/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.utils.java.parser.javadoc; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocBasicType; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocBlock; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocField; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocFragment; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocMethod; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocName; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocNamedType; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocSimpleName; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocText; import com.asakusafw.utils.java.internal.parser.javadoc.ir.IrDocType; import com.asakusafw.utils.java.internal.parser.javadoc.ir.JavadocTokenKind; /** * An abstract super class of Java documentation comment block parsers. */ public abstract class JavadocBlockParser extends JavadocBaseParser { private static final Set<JavadocTokenKind> S_FOLLOW; static { Set<JavadocTokenKind> set = EnumSet.noneOf(JavadocTokenKind.class); set.add(JavadocTokenKind.WHITE_SPACES); set.add(JavadocTokenKind.LINE_BREAK); set.add(JavadocTokenKind.EOF); S_FOLLOW = Collections.unmodifiableSet(set); } /** * Creates a new instance without any inline block parsers. */ protected JavadocBlockParser() { this(Collections.emptyList()); } /** * Creates a new instance with inline block parsers. * @param blockParsers the inline block parsers * @throws IllegalArgumentException if the parameter is {@code null} */ protected JavadocBlockParser(List<? extends JavadocBlockParser> blockParsers) { super(blockParsers); } /** * Returns whether this parser can accept the block with target tag name. * If the target is an synopsis block, the tag name will be {@code null}. * @param tag the target tag name (without <code>"@"</code>), or {@code null} for synopsis blocks * @return {@code true} if this parser can accept the target block, otherwise {@code false} */ public abstract boolean canAccept(String tag); /** * Parses a block. * The scanner will provides contents of the target block (without its block tag). * @param tag the target tag name (without <code>"@"</code>), or {@code null} for synopsis blocks * @param scanner the scanner for providing block contents * @return the parsed block * @throws JavadocParseException if error occurred while parsing the target block * @throws IllegalArgumentException if {@code scanner} is {@code null} */ public abstract IrDocBlock parse(String tag, JavadocScanner scanner) throws JavadocParseException; /** * Creates a new block from its tag and fragments. * @param tag the tag name, or {@code null} for synopsis blocks * @param fragments the fragments * @return the created block * @throws IllegalArgumentException if {@code fragments} is {@code null} */ public IrDocBlock newBlock(String tag, List<? extends IrDocFragment> fragments) { if (fragments == null) { throw new IllegalArgumentException("fragments"); //$NON-NLS-1$ } IrDocBlock block = new IrDocBlock(); block.setTag(tag); block.setFragments(fragments); return block; } /** * Consumes all tokens from the scanner, and converts them to a list of {@link IrDocFragment}s. * @param scanner the target scanner * @return the converted fragments * @throws JavadocParseException if error was occurred while converting tokens * @throws IllegalArgumentException if the parameter is {@code null} */ public List<IrDocFragment> fetchRestFragments(JavadocScanner scanner) throws JavadocParseException { int index = scanner.getIndex(); try { ArrayList<IrDocFragment> fragments = new ArrayList<>(); while (true) { JavadocTokenKind la = scanner.lookahead(0).getKind(); if (la == JavadocTokenKind.LINE_BREAK) { int count = JavadocScannerUtil.countUntilNextPrintable(scanner, 0); scanner.consume(count); } else if (la == JavadocTokenKind.LEFT_BRACE) { JavadocBlockInfo info = JavadocBlockParserUtil.fetchBlockInfo(scanner); IrDocBlock inline = parseBlock(info); fragments.add(inline); } else if (la == JavadocTokenKind.EOF) { break; } else { IrDocText text = JavadocBlockParserUtil.fetchText(scanner, false, false); fragments.add(text); } } fragments.trimToSize(); return fragments; } catch (JavadocParseException e) { scanner.seek(index); throw e; } } /** * Consumes tokens from the scanner and returns the corresponded simple name. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocSimpleName fetchSimpleName(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchSimpleName(scanner, S_FOLLOW); } /** * Consumes tokens from the scanner and returns the corresponded (simple or qualified) name. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocName fetchName(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchName(scanner, S_FOLLOW); } /** * Consumes tokens from the scanner and returns the corresponded basic type. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocBasicType fetchBasicType(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchBasicType(scanner, S_FOLLOW); } /** * Consumes tokens from the scanner and returns the corresponded primitive type. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocBasicType fetchPrimitiveType(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchPrimitiveType(scanner, S_FOLLOW); } /** * Consumes tokens from the scanner and returns the corresponded named type. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocNamedType fetchNamedType(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchNamedType(scanner, S_FOLLOW); } /** * Consumes tokens from the scanner and returns the corresponded type. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocType fetchType(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchType(scanner, S_FOLLOW); } /** * Consumes tokens from the scanner and returns the corresponded field. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocField fetchField(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchField(scanner, S_FOLLOW); } /** * Consumes tokens from the scanner and returns the corresponded method or constructor. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocMethod fetchMethod(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchMethod(scanner, S_FOLLOW); } /** * Consumes tokens from the scanner and returns the corresponded link target. * The link target means one of type, field, method, or constructor. * This will ignore successive while space tokens, and tokens are removed from the scanner only if this operation * was successfully completed. * @param scanner the target scanner * @return the analyzed element if this operation was successfully completed, otherwise {@code null} * @throws IllegalArgumentException if the parameter is {@code null} */ public IrDocFragment fetchLinkTarget(JavadocScanner scanner) { return JavadocBlockParserUtil.fetchLinkTarget(scanner, S_FOLLOW); } }