diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractAntlrListener.java b/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractAntlrListener.java index b8a38cd28..f4144b72e 100644 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractAntlrListener.java +++ b/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractAntlrListener.java @@ -1,6 +1,5 @@ package de.jplag.antlr; -import java.io.File; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; @@ -8,211 +7,92 @@ import java.util.function.Predicate; import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.ParseTreeListener; import org.antlr.v4.runtime.tree.TerminalNode; -import de.jplag.TokenType; -import de.jplag.semantics.VariableRegistry; - /** - * Base class for Antlr listeners. You can use the create*Mapping functions to map antlr tokens to jplag tokens. - *

- * You should create a constructor matching one of the constructors and create your mapping after calling super. + * Base class for Antlr listeners. This is a quasi-static class that is only created once per language. Use by calling + * the visit methods in the overwritten constructor. */ -@SuppressWarnings("unused") -public class AbstractAntlrListener implements ParseTreeListener { - private final List> startMappings; - private final List> endMappings; - - private final List terminalMapping; - - private final TokenCollector collector; - private final File currentFile; - - private VariableRegistry variableRegistry; +public abstract class AbstractAntlrListener { + private final List> contextVisitors; + private final List terminalVisitors; /** * New instance - * @param collector The token collector - * @param currentFile The currently processed file - * @param extractsSemantics If true, the listener will extract semantics along with every token - */ - public AbstractAntlrListener(TokenCollector collector, File currentFile, boolean extractsSemantics) { - this.collector = collector; - this.currentFile = currentFile; - - this.startMappings = new ArrayList<>(); - this.endMappings = new ArrayList<>(); - - this.terminalMapping = new ArrayList<>(); - - if (extractsSemantics) { - this.variableRegistry = new VariableRegistry(); - } - } - - /** - * Creates a new AbstractAntlrListener, that does not collect semantics information - * @param collector The collector, obtained by the parser - * @param currentFile The current file, obtained by the parser - */ - public AbstractAntlrListener(TokenCollector collector, File currentFile) { - this(collector, currentFile, false); - } - - @Override - public void visitTerminal(TerminalNode terminalNode) { - this.terminalMapping.stream().filter(mapping -> mapping.matches(terminalNode.getSymbol())) - .forEach(mapping -> mapping.createToken(terminalNode.getSymbol(), variableRegistry)); - } - - @Override - public void visitErrorNode(ErrorNode errorNode) { - // does nothing, because we do not handle error nodes right now. - } - - @Override - public void enterEveryRule(ParserRuleContext rule) { - this.startMappings.stream().filter(mapping -> mapping.matches(rule)).forEach(mapping -> mapping.createToken(rule, variableRegistry)); - } - - @Override - public void exitEveryRule(ParserRuleContext rule) { - this.endMappings.stream().filter(mapping -> mapping.matches(rule)).forEach(mapping -> mapping.createToken(rule, variableRegistry)); - } - - /** - * Creates a mapping using the start token from antlr as the location - * @param antlrType The antlr context type - * @param jplagType The Jplag token type - * @param The type of {@link ParserRuleContext} - * @return The builder for the token - */ - protected ContextTokenBuilder mapEnter(Class antlrType, TokenType jplagType) { - return this.mapEnter(antlrType, jplagType, it -> true); - } - - /** - * Creates a mapping using the start token from antlr as the location - * @param antlrType The antlr context type - * @param jplagType The Jplag token type - * @param condition The condition under which the mapping applies - * @param The type of {@link ParserRuleContext} - * @return The builder for the token */ - @SuppressWarnings("unchecked") - protected ContextTokenBuilder mapEnter(Class antlrType, TokenType jplagType, Predicate condition) { - ContextTokenBuilder builder = initTypeBuilder(antlrType, jplagType, condition, ContextTokenBuilderType.START); - this.startMappings.add((ContextTokenBuilder) builder); - return builder; + protected AbstractAntlrListener() { + contextVisitors = new ArrayList<>(); + terminalVisitors = new ArrayList<>(); } /** - * Creates a mapping using the stop token from antlr as the location - * @param antlrType The antlr context type - * @param jplagType The Jplag token type - * @param The type of {@link ParserRuleContext} - * @return The builder for the token - */ - protected ContextTokenBuilder mapExit(Class antlrType, TokenType jplagType) { - return this.mapExit(antlrType, jplagType, it -> true); - } - - /** - * Creates a mapping using the stop token from antlr as the location - * @param antlrType The antlr context type - * @param jplagType The Jplag token type - * @param condition The condition under which the mapping applies - * @param The type of {@link ParserRuleContext} - * @return The builder for the token + * Visit the given node. + * @param antlrType The antlr type of the node. + * @param condition An additional condition for the visit. + * @return A visitor for the node. + * @param The class of the node. */ @SuppressWarnings("unchecked") - protected ContextTokenBuilder mapExit(Class antlrType, TokenType jplagType, Predicate condition) { - ContextTokenBuilder builder = initTypeBuilder(antlrType, jplagType, condition, ContextTokenBuilderType.STOP); - this.endMappings.add((ContextTokenBuilder) builder); - return builder; + public ContextVisitor visit(Class antlrType, Predicate condition) { + Predicate typeCheck = rule -> rule.getClass() == antlrType; + ContextVisitor visitor = new ContextVisitor<>(typeCheck.and(condition)); + contextVisitors.add((ContextVisitor) visitor); + return visitor; } /** - * Creates a mapping using the beginning of the start token as the start location and the distance from the start to the - * stop token as the length - * @param antlrType The antlr context type - * @param jplagType The Jplag token type - * @param The type of {@link ParserRuleContext} - * @return The builder for the token + * Visit the given node. + * @param antlrType The antlr type of the node. + * @return A visitor for the node. + * @param The class of the node. */ - protected ContextTokenBuilder mapRange(Class antlrType, TokenType jplagType) { - return this.mapRange(antlrType, jplagType, it -> true); + public ContextVisitor visit(Class antlrType) { + return visit(antlrType, ignore -> true); } /** - * Creates a mapping using the beginning of the start token as the start location and the distance from the start to the - * stop token as the length - * @param antlrType The antlr context type - * @param jplagType The Jplag token type - * @param condition The condition under which the mapping applies - * @param The type of {@link ParserRuleContext} - * @return The builder for the token + * Visit the given terminal. + * @param terminalType The type of the terminal. + * @param condition An additional condition for the visit. + * @return A visitor for the node. */ - @SuppressWarnings("unchecked") - protected ContextTokenBuilder mapRange(Class antlrType, TokenType jplagType, Predicate condition) { - ContextTokenBuilder builder = initTypeBuilder(antlrType, jplagType, condition, ContextTokenBuilderType.RANGE); - this.startMappings.add((ContextTokenBuilder) builder); - return builder; + public TerminalVisitor visit(int terminalType, Predicate condition) { + Predicate typeCheck = rule -> rule.getType() == terminalType; + TerminalVisitor visitor = new TerminalVisitor(typeCheck.and(condition)); + terminalVisitors.add(visitor); + return visitor; } /** - * Creates a start mapping from antlrType to startType and a stop mapping from antlrType to stopType. - * @param antlrType The antlr token type - * @param startType The token type for the start mapping - * @param stopType The token type for the stop mapping - * @param The type of {@link ParserRuleContext} - * @return The builder for the token + * Visit the given terminal. + * @param terminalType The type of the terminal. + * @return A visitor for the node. */ - protected RangeBuilder mapEnterExit(Class antlrType, TokenType startType, TokenType stopType) { - return mapEnterExit(antlrType, startType, stopType, it -> true); + public TerminalVisitor visit(int terminalType) { + return visit(terminalType, ignore -> true); } /** - * Creates a start mapping from antlrType to startType and a stop mapping from antlrType to stopType. - * @param antlrType The antlr token type - * @param startType The token type for the start mapping - * @param stopType The token type for the stop mapping - * @param condition The condition under which the mapping applies - * @param The type of {@link ParserRuleContext} - * @return The builder for the token + * Called by {@link InternalListener#visitTerminal(TerminalNode)} as part of antlr framework. */ - protected RangeBuilder mapEnterExit(Class antlrType, TokenType startType, TokenType stopType, - Predicate condition) { - ContextTokenBuilder start = this.mapEnter(antlrType, startType, condition); - ContextTokenBuilder end = this.mapExit(antlrType, stopType, condition); - return new RangeBuilder<>(start, end); + void visitTerminal(HandlerData data) { + this.terminalVisitors.stream().filter(visitor -> visitor.matches(data.entity())).forEach(visitor -> visitor.enter(data)); } /** - * Creates a mapping for terminal tokens - * @param terminalType The type of the terminal node - * @param jplagType The jplag token type - * @return The builder for the token + * Called by {@link InternalListener#enterEveryRule(ParserRuleContext)} as part of antlr framework. */ - protected TerminalTokenBuilder mapTerminal(int terminalType, TokenType jplagType) { - return this.mapTerminal(terminalType, jplagType, it -> true); + void enterEveryRule(HandlerData data) { + this.contextVisitors.stream().filter(visitor -> visitor.matches(data.entity())).forEach(visitor -> visitor.enter(data)); } /** - * Creates a mapping for terminal tokens - * @param terminalType The type of the terminal node - * @param jplagType The jplag token type - * @param condition The condition under which the mapping applies - * @return The builder for the token + * Called by {@link InternalListener#exitEveryRule(ParserRuleContext)} as part of antlr framework. */ - protected TerminalTokenBuilder mapTerminal(int terminalType, TokenType jplagType, Predicate condition) { - TerminalTokenBuilder builder = new TerminalTokenBuilder(jplagType, token -> token.getType() == terminalType && condition.test(token), - this.collector, this.currentFile); - this.terminalMapping.add(builder); - return builder; + void exitEveryRule(HandlerData data) { + this.contextVisitors.stream().filter(visitor -> visitor.matches(data.entity())).forEach(visitor -> visitor.exit(data)); } /** @@ -224,7 +104,7 @@ protected TerminalTokenBuilder mapTerminal(int terminalType, TokenType jplagType * @return an ancestor of the specified type, or null if not found. */ @SafeVarargs - protected final T getAncestor(ParserRuleContext context, Class ancestor, + protected static T getAncestor(ParserRuleContext context, Class ancestor, Class... stops) { ParserRuleContext currentContext = context; Set> forbidden = Set.of(stops); @@ -251,7 +131,7 @@ protected final T getAncestor(ParserRuleContext co * @see #getAncestor(ParserRuleContext, Class, Class[]) */ @SafeVarargs - protected final boolean hasAncestor(ParserRuleContext context, Class parent, + protected static boolean hasAncestor(ParserRuleContext context, Class parent, Class... stops) { return getAncestor(context, parent, stops) != null; } @@ -263,7 +143,7 @@ protected final boolean hasAncestor(ParserRuleContext context, Class the type to search for. * @return the first appearance of an element of the given type in the subtree, or null if no such element exists. */ - protected final T getDescendant(ParserRuleContext context, Class descendant) { + protected static T getDescendant(ParserRuleContext context, Class descendant) { // simple iterative bfs ArrayDeque queue = new ArrayDeque<>(); queue.add(context); @@ -280,10 +160,4 @@ protected final T getDescendant(ParserRuleContext } return null; } - - private ContextTokenBuilder initTypeBuilder(Class antlrType, TokenType jplagType, Predicate condition, - ContextTokenBuilderType type) { - return new ContextTokenBuilder<>(jplagType, rule -> rule.getClass() == antlrType && condition.test(antlrType.cast(rule)), this.collector, - this.currentFile, type); - } } diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractAntlrParserAdapter.java b/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractAntlrParserAdapter.java index c5cdc478f..1644ccf7b 100644 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractAntlrParserAdapter.java +++ b/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractAntlrParserAdapter.java @@ -25,6 +25,24 @@ * @param The type of the antlr parser */ public abstract class AbstractAntlrParserAdapter extends AbstractParser { + + private final boolean extractsSemantics; + + /** + * New instance + * @param extractsSemantics If true, the listener will extract semantics along with every token + */ + protected AbstractAntlrParserAdapter(boolean extractsSemantics) { + this.extractsSemantics = extractsSemantics; + } + + /** + * New instance + */ + protected AbstractAntlrParserAdapter() { + this(false); + } + /** * Parsers the set of files * @param files The files @@ -32,33 +50,29 @@ public abstract class AbstractAntlrParserAdapter extends Abstr * @throws ParsingException If anything goes wrong */ public List parse(Set files) throws ParsingException { - TokenCollector collector = new TokenCollector(); - + TokenCollector collector = new TokenCollector(extractsSemantics); for (File file : files) { parseFile(file, collector); } - return collector.getTokens(); } private void parseFile(File file, TokenCollector collector) throws ParsingException { + collector.enterFile(file); try (Reader reader = FileUtils.openFileReader(file)) { Lexer lexer = this.createLexer(CharStreams.fromReader(reader)); CommonTokenStream tokenStream = new CommonTokenStream(lexer); T parser = this.createParser(tokenStream); - ParserRuleContext entryContext = this.getEntryContext(parser); ParseTreeWalker treeWalker = new ParseTreeWalker(); - - AbstractAntlrListener listener = this.createListener(collector, file); + InternalListener listener = new InternalListener(this.getListener(), collector); for (ParseTree child : entryContext.children) { treeWalker.walk(listener, child); } - - collector.addToken(Token.fileEnd(file)); } catch (IOException exception) { throw new ParsingException(file, exception.getMessage(), exception); } + collector.addFileEndToken(); } /** @@ -83,10 +97,7 @@ private void parseFile(File file, TokenCollector collector) throws ParsingExcept protected abstract ParserRuleContext getEntryContext(T parser); /** - * Creates the listener - * @param collector The token collector - * @param currentFile The current file - * @return The parser + * @return The listener. Should be created once statically since it never changes. */ - protected abstract AbstractAntlrListener createListener(TokenCollector collector, File currentFile); + protected abstract AbstractAntlrListener getListener(); } diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractVisitor.java b/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractVisitor.java new file mode 100644 index 000000000..cad061e19 --- /dev/null +++ b/language-antlr-utils/src/main/java/de/jplag/antlr/AbstractVisitor.java @@ -0,0 +1,122 @@ +package de.jplag.antlr; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.*; + +import org.antlr.v4.runtime.Token; + +import de.jplag.TokenType; +import de.jplag.semantics.CodeSemantics; +import de.jplag.semantics.VariableRegistry; + +/** + * The abstract visitor. + * @param The type of the visited entity. + */ +public abstract class AbstractVisitor { + private final Predicate condition; + private final List>> entryHandlers; + private TokenType entryTokenType; + private Function entrySemantics; + + /** + * @param condition The condition for the visit. + */ + AbstractVisitor(Predicate condition) { + this.condition = condition; + this.entryHandlers = new ArrayList<>(); + } + + /** + * Add an action the visitor runs upon entering the entity. + * @param handler The action, takes the entity and the variable registry as parameter. + * @return Self + */ + public AbstractVisitor onEnter(BiConsumer handler) { + entryHandlers.add(handlerData -> handler.accept(handlerData.entity(), handlerData.variableRegistry())); + return this; + } + + /** + * Add an action the visitor runs upon entering the entity. + * @param handler The action, takes the entity as parameter. + * @return Self + */ + public AbstractVisitor onEnter(Consumer handler) { + entryHandlers.add(handlerData -> handler.accept(handlerData.entity())); + return this; + } + + /** + * Tell the visitor that it should generate a token upon entering the entity. Should only be invoked once per visitor. + * @param tokenType The type of the token. + * @return Self + */ + public AbstractVisitor mapEnter(TokenType tokenType) { + entryTokenType = tokenType; + return this; + } + + /** + * Tell the visitor that it should generate a token upon entering the entity. Should only be invoked once per visitor. + * Alias for {@link #mapEnter(TokenType)}. + * @param tokenType The type of the token. + * @return Self + */ + public AbstractVisitor map(TokenType tokenType) { + mapEnter(tokenType); + return this; + } + + /** + * Tell the visitor that if it generates a token upon entering the entity, it should have semantics. + * @param semanticsSupplier A function that takes the entity and returns the semantics. + * @return Self + */ + public AbstractVisitor withSemantics(Function semanticsSupplier) { + this.entrySemantics = semanticsSupplier; + return this; + } + + /** + * Tell the visitor that if it generates a token upon entering the entity, it should have semantics. + * @param semanticsSupplier A function that returns the semantics. + * @return Self + */ + public AbstractVisitor withSemantics(Supplier semanticsSupplier) { + this.entrySemantics = ignore -> semanticsSupplier.get(); + return this; + } + + /** + * Tell the visitor that if it generates a token upon entering the entity, it should have semantics of type control. + * @return Self + */ + public AbstractVisitor withControlSemantics() { + withSemantics(CodeSemantics::createControl); + return this; + } + + /** + * @param entity The entity to check. + * @return Whether to visit the entity. + */ + boolean matches(T entity) { + return this.condition.test(entity); + } + + /** + * Enter a given entity, injecting the needed dependencies. + */ + void enter(HandlerData data) { + addToken(data, entryTokenType, entrySemantics, this::extractEnterToken); + entryHandlers.forEach(handler -> handler.accept(data)); + } + + void addToken(HandlerData data, TokenType tokenType, Function semantics, Function extractToken) { + data.collector().addToken(tokenType, semantics, data.entity(), extractToken, data.variableRegistry()); + } + + abstract Token extractEnterToken(T entity); +} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/ContextTokenBuilder.java b/language-antlr-utils/src/main/java/de/jplag/antlr/ContextTokenBuilder.java deleted file mode 100644 index c48ffc678..000000000 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/ContextTokenBuilder.java +++ /dev/null @@ -1,53 +0,0 @@ -package de.jplag.antlr; - -import java.io.File; -import java.util.function.Function; -import java.util.function.Predicate; - -import org.antlr.v4.runtime.ParserRuleContext; - -import de.jplag.TokenType; -import de.jplag.semantics.VariableScope; - -/** - * Builds tokens for {@link ParserRuleContext}s. - * @param The type of context - */ -public class ContextTokenBuilder extends TokenBuilder { - private final ContextTokenBuilderType type; - - ContextTokenBuilder(TokenType tokenType, Predicate condition, TokenCollector collector, File file, ContextTokenBuilderType type) { - super(tokenType, condition, collector, file); - this.type = type; - } - - /** - * Adds this builder as a variable to the variable registry - * @param scope The scope of the variable - * @param mutable true, if the variable is mutable - * @param nameGetter The getter for the name, from the current {@link ParserRuleContext} - * @return Self - */ - public ContextTokenBuilder addAsVariable(VariableScope scope, boolean mutable, Function nameGetter) { - addSemanticsHandler((registry, rule) -> registry.registerVariable(nameGetter.apply(rule), scope, mutable)); - return this; - } - - @Override - protected org.antlr.v4.runtime.Token getAntlrToken(T antlrContent) { - if (this.type != ContextTokenBuilderType.STOP) { - return antlrContent.getStart(); - } else { - return antlrContent.getStop(); - } - } - - @Override - protected int getLength(T antlrContent) { - if (this.type != ContextTokenBuilderType.RANGE) { - return super.getLength(antlrContent); - } else { - return antlrContent.getStop().getStopIndex() - antlrContent.getStart().getStartIndex() + 1; - } - } -} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/ContextTokenBuilderType.java b/language-antlr-utils/src/main/java/de/jplag/antlr/ContextTokenBuilderType.java deleted file mode 100644 index ab7d9231c..000000000 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/ContextTokenBuilderType.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.jplag.antlr; - -/** - * The types of context token builder. Either start, stop or range. Should only be used internally. - */ -enum ContextTokenBuilderType { - START, - STOP, - RANGE -} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/ContextVisitor.java b/language-antlr-utils/src/main/java/de/jplag/antlr/ContextVisitor.java new file mode 100644 index 000000000..92dd4ae79 --- /dev/null +++ b/language-antlr-utils/src/main/java/de/jplag/antlr/ContextVisitor.java @@ -0,0 +1,139 @@ +package de.jplag.antlr; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.*; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; + +import de.jplag.TokenType; +import de.jplag.semantics.CodeSemantics; +import de.jplag.semantics.VariableRegistry; + +/** + * The visitor for nodes, or contexts. + * @param The antlr type of the node. + */ +public class ContextVisitor extends AbstractVisitor { + private final List>> exitHandlers; + private TokenType exitToken; + private Function exitSemantics; + + ContextVisitor(Predicate condition) { + super(condition); + this.exitHandlers = new ArrayList<>(); + } + + /** + * Add an action the visitor runs upon exiting the entity. + * @param handler The action, takes the entity and the variable registry as parameter. + * @return Self + */ + public AbstractVisitor onExit(BiConsumer handler) { + exitHandlers.add(handlerData -> handler.accept(handlerData.entity(), handlerData.variableRegistry())); + return this; + } + + /** + * Add an action the visitor runs upon exiting the entity. + * @param handler The action, takes the entity as parameter. + * @return Self + */ + public AbstractVisitor onExit(Consumer handler) { + exitHandlers.add(handlerData -> handler.accept(handlerData.entity())); + return this; + } + + /** + * Tell the visitor that it should generate a token upon exiting the entity. Should only be invoked once per visitor. + * @param tokenType The type of the token. + * @return Self + */ + public ContextVisitor mapExit(TokenType tokenType) { + exitToken = tokenType; + return this; + } + + /** + * Tell the visitor that it should generate a token upon entering and one upon exiting the entity. Should only be + * invoked once per visitor. + * @param enterTokenType The type of the token generated on enter. + * @param exitTokenType The type of the token generated on exit. + * @return Self + */ + public ContextVisitor mapEnterExit(TokenType enterTokenType, TokenType exitTokenType) { + mapEnter(enterTokenType); + mapExit(exitTokenType); + return this; + } + + /** + * Tell the visitor that it should generate a token upon entering and one upon exiting the entity. Should only be + * invoked once per visitor. Alias for {@link #mapEnterExit(TokenType, TokenType)}. + * @param enterTokenType The type of the token generated on enter. + * @param exitTokenType The type of the token generated on exit. + * @return Self + */ + public ContextVisitor map(TokenType enterTokenType, TokenType exitTokenType) { + mapEnterExit(enterTokenType, exitTokenType); + return this; + } + + @Override + public ContextVisitor withSemantics(Function semantics) { + super.withSemantics(semantics); + this.exitSemantics = semantics; + return this; + } + + @Override + public ContextVisitor withSemantics(Supplier semantics) { + super.withSemantics(semantics); + this.exitSemantics = ignore -> semantics.get(); + return this; + } + + /** + * Tell the visitor that if it generates a token upon entering the entity, it should have semantics of type loop begin, + * same for the exit and loop end. + * @return Self + */ + public ContextVisitor withLoopSemantics() { + super.withSemantics(CodeSemantics::createLoopBegin); + this.exitSemantics = ignore -> CodeSemantics.createLoopEnd(); + return this; + } + + /** + * Tell the visitor that the entity represents a local scope. + * @return Self + */ + public ContextVisitor addLocalScope() { + onEnter((ignore, variableRegistry) -> variableRegistry.enterLocalScope()); + onExit((ignore, variableRegistry) -> variableRegistry.exitLocalScope()); + return this; + } + + /** + * Tell the visitor that the entity represents a class scope. + * @return Self + */ + public ContextVisitor addClassScope() { + onEnter((ignore, variableRegistry) -> variableRegistry.enterClass()); + onExit((ignore, variableRegistry) -> variableRegistry.exitClass()); + return this; + } + + /** + * Exit a given entity, injecting the needed dependencies. + */ + void exit(HandlerData data) { + addToken(data, exitToken, exitSemantics, ParserRuleContext::getStop); + exitHandlers.forEach(handler -> handler.accept(data)); + } + + Token extractEnterToken(T entity) { + return entity.getStart(); + } +} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/HandlerData.java b/language-antlr-utils/src/main/java/de/jplag/antlr/HandlerData.java new file mode 100644 index 000000000..6c1bb4095 --- /dev/null +++ b/language-antlr-utils/src/main/java/de/jplag/antlr/HandlerData.java @@ -0,0 +1,9 @@ +package de.jplag.antlr; + +import de.jplag.semantics.VariableRegistry; + +/** + * Holds the data passed to the (quasi-static) listeners. + */ +record HandlerData(T entity, VariableRegistry variableRegistry, TokenCollector collector) { +} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/InternalListener.java b/language-antlr-utils/src/main/java/de/jplag/antlr/InternalListener.java new file mode 100644 index 000000000..39178e0fb --- /dev/null +++ b/language-antlr-utils/src/main/java/de/jplag/antlr/InternalListener.java @@ -0,0 +1,48 @@ +package de.jplag.antlr; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.tree.TerminalNode; + +import de.jplag.semantics.VariableRegistry; + +/** + * Internal listener that implements pre-existing antlr methods that are called automatically. This listener is created + * for every file. + */ +class InternalListener implements ParseTreeListener { + private final AbstractAntlrListener listener; + private final TokenCollector collector; + protected final VariableRegistry variableRegistry; + + InternalListener(AbstractAntlrListener listener, TokenCollector collector) { + this.listener = listener; + this.collector = collector; + this.variableRegistry = new VariableRegistry(); + } + + @Override + public void visitTerminal(TerminalNode terminalNode) { + listener.visitTerminal(getHandlerData(terminalNode.getSymbol())); + } + + @Override + public void enterEveryRule(ParserRuleContext rule) { + listener.enterEveryRule(getHandlerData(rule)); + } + + @Override + public void exitEveryRule(ParserRuleContext rule) { + listener.exitEveryRule(getHandlerData(rule)); + } + + @Override + public void visitErrorNode(ErrorNode errorNode) { + // does nothing, because we do not handle error nodes right now. + } + + private HandlerData getHandlerData(T entity) { + return new HandlerData<>(entity, variableRegistry, collector); + } +} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/InternalListenerException.java b/language-antlr-utils/src/main/java/de/jplag/antlr/InternalListenerException.java deleted file mode 100644 index 70422ee29..000000000 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/InternalListenerException.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.jplag.antlr; - -/** - * Exception type used internally within the antlr utils. Has to be a {@link RuntimeException}, because it is thrown - * within the antlr listener methods. Should not be thrown outside the antlr utils. - */ -public class InternalListenerException extends RuntimeException { - /** - * New instance - * @param message The message of the exception - */ - public InternalListenerException(String message) { - super(message); - } -} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/RangeBuilder.java b/language-antlr-utils/src/main/java/de/jplag/antlr/RangeBuilder.java deleted file mode 100644 index ea84cf3bd..000000000 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/RangeBuilder.java +++ /dev/null @@ -1,112 +0,0 @@ -package de.jplag.antlr; - -import java.util.function.Consumer; -import java.util.function.Function; - -import org.antlr.v4.runtime.ParserRuleContext; - -import de.jplag.semantics.CodeSemantics; -import de.jplag.semantics.VariableRegistry; -import de.jplag.semantics.VariableScope; - -/** - * Builder for semantics on range mappings - * @param The type of rule - */ -@SuppressWarnings("unused") -public class RangeBuilder { - private final ContextTokenBuilder start; - private final ContextTokenBuilder end; - - /** - * New instance - * @param start The builder for the start token - * @param end The builder for the end token - */ - RangeBuilder(ContextTokenBuilder start, ContextTokenBuilder end) { - this.start = start; - this.end = end; - } - - /** - * Adds a class context to the variable registry - * @return Self - */ - public RangeBuilder addClassContext() { - this.start.addSemanticsHandler(VariableRegistry::enterClass); - this.end.addSemanticsHandler(VariableRegistry::exitClass); - return this; - } - - /** - * Adds a local scope to the variable registry - * @return Self - */ - public RangeBuilder addLocalScope() { - this.start.addSemanticsHandler(VariableRegistry::enterLocalScope); - this.end.addSemanticsHandler(VariableRegistry::exitLocalScope); - return this; - } - - /** - * Adds a semantics handler to the start token builder - * @param handler The handler - * @return Self - */ - public RangeBuilder addStartSemanticHandler(Consumer handler) { - this.start.addSemanticsHandler(handler); - return this; - } - - /** - * Adds a semantic handler to the end token builder - * @param handler The handler - * @return Self - */ - public RangeBuilder addEndSemanticHandler(Consumer handler) { - this.end.addSemanticsHandler(handler); - return this; - } - - /** - * Adds the start token as a variable when it is extracted - * @param scope The scope for the variable - * @param mutable true if the variable is mutable - * @param nameGetter The getter for the name - * @return Self - */ - public RangeBuilder addAsVariableOnStart(VariableScope scope, boolean mutable, Function nameGetter) { - this.start.addAsVariable(scope, mutable, nameGetter); - return this; - } - - /** - * Sets the given semantic for the start token - * @param semantics The semantic - * @return Self - */ - public RangeBuilder withStartSemantics(CodeSemantics semantics) { - this.start.withSemantics(semantics); - return this; - } - - /** - * Sets the given semantic for the end token - * @param semantics The semantic - * @return Self - */ - public RangeBuilder withEndSemantics(CodeSemantics semantics) { - this.end.withSemantics(semantics); - return this; - } - - /** - * Sets a control semantics for both tokens - * @return Self - */ - public RangeBuilder withControlSemantics() { - this.start.withControlSemantics(); - this.end.withControlSemantics(); - return this; - } -} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/TerminalTokenBuilder.java b/language-antlr-utils/src/main/java/de/jplag/antlr/TerminalTokenBuilder.java deleted file mode 100644 index 3f074e6ad..000000000 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/TerminalTokenBuilder.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.jplag.antlr; - -import java.io.File; -import java.util.function.Predicate; - -import org.antlr.v4.runtime.Token; - -import de.jplag.TokenType; - -/** - * Builds tokens from terminal antlr nodes - */ -public class TerminalTokenBuilder extends TokenBuilder { - /** - * New instance - * @param tokenType The token type - * @param condition The condition - * @param collector The token collector for the listener - * @param file The file the listener is for - */ - TerminalTokenBuilder(TokenType tokenType, Predicate condition, TokenCollector collector, File file) { - super(tokenType, condition, collector, file); - } - - @Override - protected Token getAntlrToken(Token antlrContent) { - return antlrContent; - } -} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/TerminalVisitor.java b/language-antlr-utils/src/main/java/de/jplag/antlr/TerminalVisitor.java new file mode 100644 index 000000000..170f5d627 --- /dev/null +++ b/language-antlr-utils/src/main/java/de/jplag/antlr/TerminalVisitor.java @@ -0,0 +1,19 @@ +package de.jplag.antlr; + +import java.util.function.Predicate; + +import org.antlr.v4.runtime.Token; + +/** + * The visitor for terminals. + */ +public class TerminalVisitor extends AbstractVisitor { + + TerminalVisitor(Predicate condition) { + super(condition); + } + + Token extractEnterToken(Token token) { + return token; + } +} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/TokenBuilder.java b/language-antlr-utils/src/main/java/de/jplag/antlr/TokenBuilder.java deleted file mode 100644 index 08e393ef7..000000000 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/TokenBuilder.java +++ /dev/null @@ -1,140 +0,0 @@ -package de.jplag.antlr; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.function.*; -import java.util.logging.Logger; - -import de.jplag.Token; -import de.jplag.TokenType; -import de.jplag.semantics.CodeSemantics; -import de.jplag.semantics.VariableRegistry; - -/** - * Handles the extraction of tokens. Contains information on the appropriate antlr types, the conditions under which the - * token should be extracted and semantics information. - * @param The antlr type being mapped - */ -public abstract class TokenBuilder { - private static final Logger logger = Logger.getLogger(TokenBuilder.class.getName()); - private static final String UNEXPECTED_SEMANTICS = "The listener %s indicates, it does not extract semantics. But the token (%s) has semantics information"; - private static final String MISSING_SEMANTICS = "Tokens should contain semantics, but none were supplied"; - - private final Predicate condition; - protected final TokenType tokenType; - - private Function semanticsSupplier = null; - private final List> semanticsHandler; - - protected final TokenCollector tokenCollector; - protected final File file; - - /** - * New instance - * @param tokenType The token type - * @param condition The condition - * @param collector The token collector for the listener - * @param file The file the listener is for - */ - TokenBuilder(TokenType tokenType, Predicate condition, TokenCollector collector, File file) { - this.condition = condition; - this.tokenType = tokenType; - this.tokenCollector = collector; - this.file = file; - - this.semanticsHandler = new ArrayList<>(); - } - - /** - * Checks if the token should be extracted for this node. - * @param value The node to check - * @return true, if the token should be extracted - */ - boolean matches(T value) { - return this.condition.test(value); - } - - /** - * Sets the given semantics for the token - * @param semantics The semantics - * @return Self - */ - public TokenBuilder withSemantics(CodeSemantics semantics) { - this.semanticsSupplier = ignore -> semantics; - return this; - } - - /** - * Uses the given function to build the token semantics from the antlr node - * @param function The function - * @return Self - */ - public TokenBuilder withSemantics(Function function) { - this.semanticsSupplier = function; - return this; - } - - /** - * Sets control semantics for the token - * @return Self - */ - public TokenBuilder withControlSemantics() { - withSemantics(CodeSemantics.createControl()); - return this; - } - - /** - * Adds a semantics handler to this builder. This can be used to perform additional operation like calling methods in - * the {@link de.jplag.semantics.VariableRegistry}. - * @param handler The handler function - * @return Self - */ - public TokenBuilder addSemanticsHandler(Consumer handler) { - this.semanticsHandler.add((semantics, rule) -> handler.accept(semantics)); - return this; - } - - /** - * Adds a semantics handler, that can perform additional operations required for semantics using the Semantics context - * objects and the antlr node. - * @param handler The handler - * @return Self - */ - public TokenBuilder addSemanticsHandler(BiConsumer handler) { - this.semanticsHandler.add(handler); - return this; - } - - void createToken(T antlrContent, VariableRegistry semantics) { - org.antlr.v4.runtime.Token antlrToken = getAntlrToken(antlrContent); - - int line = antlrToken.getLine(); - int column = antlrToken.getCharPositionInLine() + 1; - int length = getLength(antlrContent); - - Token token; - if (semantics != null) { - if (semanticsSupplier == null) { - throw new IllegalStateException(MISSING_SEMANTICS); - } - - this.semanticsHandler.forEach(it -> it.accept(semantics, antlrContent)); - token = new Token(this.tokenType, this.file, line, column, length, semanticsSupplier.apply(antlrContent)); - } else { - if (semanticsSupplier != null) { - logger.warning(() -> String.format(UNEXPECTED_SEMANTICS, this.getClass().getName(), this.tokenType.getDescription())); - } - - token = new Token(this.tokenType, this.file, line, column, length); - } - - this.tokenCollector.addToken(token); - } - - protected abstract org.antlr.v4.runtime.Token getAntlrToken(T antlrContent); - - protected int getLength(T antlrContent) { - return getAntlrToken(antlrContent).getText().length(); - } -} diff --git a/language-antlr-utils/src/main/java/de/jplag/antlr/TokenCollector.java b/language-antlr-utils/src/main/java/de/jplag/antlr/TokenCollector.java index 30ab0ce78..7a284d015 100644 --- a/language-antlr-utils/src/main/java/de/jplag/antlr/TokenCollector.java +++ b/language-antlr-utils/src/main/java/de/jplag/antlr/TokenCollector.java @@ -1,36 +1,80 @@ package de.jplag.antlr; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Function; +import java.util.logging.Logger; import de.jplag.Token; +import de.jplag.TokenType; +import de.jplag.semantics.CodeSemantics; +import de.jplag.semantics.VariableRegistry; /** * Collects the tokens during parsing. */ public class TokenCollector { + private static final Logger logger = Logger.getLogger(TokenCollector.class.getName()); private final List collected; + private final boolean extractsSemantics; + private File file; /** - * New instance + * @param extractsSemantics If semantics are extracted */ - public TokenCollector() { + TokenCollector(boolean extractsSemantics) { this.collected = new ArrayList<>(); - } - - /** - * Adds a token to the collector - * @param token The token to add - */ - public void addToken(Token token) { - this.collected.add(token); + this.extractsSemantics = extractsSemantics; } /** * @return All collected tokens */ - public List getTokens() { + List getTokens() { return Collections.unmodifiableList(this.collected); } + + void addToken(TokenType jplagType, Function semanticsSupplier, T entity, + Function extractToken, VariableRegistry variableRegistry) { + if (jplagType == null) { + if (semanticsSupplier != null) { + logger.warning("Received semantics, but no token type, so no token was generated and the semantics discarded"); + } + return; + } + org.antlr.v4.runtime.Token antlrToken = extractToken.apply(entity); + int line = antlrToken.getLine(); + int column = antlrToken.getCharPositionInLine() + 1; + int length = antlrToken.getText().length(); + Token token; + if (extractsSemantics) { + if (semanticsSupplier == null) { + throw new IllegalStateException(String.format("Expected semantics bud did not receive any for token %s", jplagType.getDescription())); + } + CodeSemantics semantics = semanticsSupplier.apply(entity); + token = new Token(jplagType, this.file, line, column, length, semantics); + variableRegistry.updateSemantics(semantics); + } else { + if (semanticsSupplier != null) { + logger.warning(() -> String.format("Received semantics for token %s despite not expecting any", jplagType.getDescription())); + } + token = new Token(jplagType, this.file, line, column, length); + } + addToken(token); + } + + void enterFile(File newFile) { + this.file = newFile; + } + + void addFileEndToken() { + addToken(extractsSemantics ? Token.semanticFileEnd(file) : Token.fileEnd(file)); + // don't need to update semantics because variable registry is new for every file + } + + private void addToken(Token token) { + this.collected.add(token); + } } diff --git a/language-antlr-utils/src/test/java/de/jplag/antlr/testLanguage/TestListener.java b/language-antlr-utils/src/test/java/de/jplag/antlr/testLanguage/TestListener.java index 49d30b023..9073ad954 100644 --- a/language-antlr-utils/src/test/java/de/jplag/antlr/testLanguage/TestListener.java +++ b/language-antlr-utils/src/test/java/de/jplag/antlr/testLanguage/TestListener.java @@ -2,34 +2,20 @@ import static de.jplag.antlr.testLanguage.TestTokenType.*; -import java.io.File; - -import de.jplag.antlr.AbstractAntlrListener; -import de.jplag.antlr.TestParser; +import de.jplag.antlr.*; import de.jplag.antlr.TestParser.*; -import de.jplag.antlr.TokenCollector; import de.jplag.semantics.CodeSemantics; import de.jplag.semantics.VariableScope; -public class TestListener extends AbstractAntlrListener { - /** - * New instance - * @param collector The token collector - * @param currentFile The currently processed file - */ - public TestListener(TokenCollector collector, File currentFile) { - super(collector, currentFile, true); - - mapEnter(VarDefContext.class, VARDEF).addAsVariable(VariableScope.FILE, false, rule -> rule.VAR_NAME().getText()) - .withSemantics(CodeSemantics.createKeep()); +class TestListener extends AbstractAntlrListener { - mapRange(CalcExpressionContext.class, ADDITION, rule -> rule.operator() != null && rule.operator().PLUS() != null).withControlSemantics(); - mapRange(OperatorContext.class, SUBTRACTION, rule -> rule.MINUS() != null).withControlSemantics(); - mapEnterExit(SubExpressionContext.class, SUB_EXPRESSION_BEGIN, SUB_EXPRESSION_END) - // .addEndSemanticHandler(registry -> registry.addAllNonLocalVariablesAsReads()) - // does not work here, because there is no class context. Is still here as an example. - .addLocalScope().withControlSemantics(); - mapTerminal(TestParser.NUMBER, NUMBER).withSemantics(CodeSemantics.createKeep()); - mapEnter(VarRefContext.class, VARREF).withSemantics(CodeSemantics.createKeep()); + TestListener() { + visit(VarDefContext.class).map(VARDEF).withSemantics(CodeSemantics::createKeep) + .onEnter((rule, variableRegistry) -> variableRegistry.registerVariable(rule.VAR_NAME().getText(), VariableScope.FILE, false)); + visit(CalcExpressionContext.class, rule -> rule.operator() != null && rule.operator().PLUS() != null).map(ADDITION).withControlSemantics(); + visit(OperatorContext.class, rule -> rule.MINUS() != null).map(SUBTRACTION).withControlSemantics(); + visit(SubExpressionContext.class).map(SUB_EXPRESSION_BEGIN, SUB_EXPRESSION_END).addLocalScope().withControlSemantics(); + visit(TestParser.NUMBER).map(NUMBER).withSemantics(CodeSemantics::createKeep); + visit(VarDefContext.class).map(VARDEF).withSemantics(CodeSemantics::createKeep); } } diff --git a/language-antlr-utils/src/test/java/de/jplag/antlr/testLanguage/TestParserAdapter.java b/language-antlr-utils/src/test/java/de/jplag/antlr/testLanguage/TestParserAdapter.java index 5b292e18d..c2873a167 100644 --- a/language-antlr-utils/src/test/java/de/jplag/antlr/testLanguage/TestParserAdapter.java +++ b/language-antlr-utils/src/test/java/de/jplag/antlr/testLanguage/TestParserAdapter.java @@ -1,7 +1,5 @@ package de.jplag.antlr.testLanguage; -import java.io.File; - import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Lexer; @@ -10,6 +8,8 @@ import de.jplag.antlr.*; public class TestParserAdapter extends AbstractAntlrParserAdapter { + private static final TestListener listener = new TestListener(); + @Override protected Lexer createLexer(CharStream input) { return new TestLexer(input); @@ -26,7 +26,7 @@ protected ParserRuleContext getEntryContext(TestParser parser) { } @Override - protected AbstractAntlrListener createListener(TokenCollector collector, File currentFile) { - return new TestListener(collector, currentFile); + protected AbstractAntlrListener getListener() { + return listener; } } diff --git a/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java b/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java index 90ef46b3b..6b2a68c49 100644 --- a/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java +++ b/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java @@ -2,10 +2,7 @@ import static de.jplag.cpp2.CPPTokenType.*; -import java.io.File; - import de.jplag.antlr.AbstractAntlrListener; -import de.jplag.antlr.TokenCollector; import de.jplag.cpp2.grammar.CPP14Parser; import de.jplag.cpp2.grammar.CPP14Parser.*; @@ -15,59 +12,53 @@ *

* Those cases are covered by {@link SimpleTypeSpecifierContext} and {@link SimpleDeclarationContext} */ -public class CPPListener extends AbstractAntlrListener { - /** - * New instance - * @param collector The token collector the token will be added to - * @param currentFile The currently processed file - */ - public CPPListener(TokenCollector collector, File currentFile) { - super(collector, currentFile); +class CPPListener extends AbstractAntlrListener { - mapEnterExit(ClassSpecifierContext.class, UNION_BEGIN, UNION_END, rule -> rule.classHead().Union() != null); - mapEnterExit(ClassSpecifierContext.class, CLASS_BEGIN, CLASS_END, - rule -> rule.classHead().classKey() != null && rule.classHead().classKey().Class() != null); - mapEnterExit(ClassSpecifierContext.class, STRUCT_BEGIN, STRUCT_END, - rule -> rule.classHead().classKey() != null && rule.classHead().classKey().Struct() != null); - mapEnterExit(EnumSpecifierContext.class, ENUM_BEGIN, ENUM_END); + CPPListener() { + visit(ClassSpecifierContext.class, rule -> rule.classHead().Union() != null).map(UNION_BEGIN, UNION_END); + visit(ClassSpecifierContext.class, rule -> rule.classHead().classKey() != null && rule.classHead().classKey().Class() != null) + .map(CLASS_BEGIN, CLASS_END); + visit(ClassSpecifierContext.class, rule -> rule.classHead().classKey() != null && rule.classHead().classKey().Struct() != null) + .map(STRUCT_BEGIN, STRUCT_END); + visit(EnumSpecifierContext.class).map(ENUM_BEGIN, ENUM_END); - mapEnterExit(FunctionDefinitionContext.class, FUNCTION_BEGIN, FUNCTION_END); + visit(FunctionDefinitionContext.class).map(FUNCTION_BEGIN, FUNCTION_END); - mapEnterExit(IterationStatementContext.class, DO_BEGIN, DO_END, rule -> rule.Do() != null); - mapEnterExit(IterationStatementContext.class, FOR_BEGIN, FOR_END, rule -> rule.For() != null); - mapEnterExit(IterationStatementContext.class, WHILE_BEGIN, WHILE_END, rule -> rule.While() != null && rule.Do() == null); + visit(IterationStatementContext.class, rule -> rule.Do() != null).map(DO_BEGIN, DO_END); + visit(IterationStatementContext.class, rule -> rule.For() != null).map(FOR_BEGIN, FOR_END); + visit(IterationStatementContext.class, rule -> rule.While() != null && rule.Do() == null).map(WHILE_BEGIN, WHILE_END); - mapEnterExit(SelectionStatementContext.class, SWITCH_BEGIN, SWITCH_END, rule -> rule.Switch() != null); - mapEnterExit(SelectionStatementContext.class, IF_BEGIN, IF_END, rule -> rule.If() != null); - mapTerminal(CPP14Parser.Else, ELSE); + visit(SelectionStatementContext.class, rule -> rule.Switch() != null).map(SWITCH_BEGIN, SWITCH_END); + visit(SelectionStatementContext.class, rule -> rule.If() != null).map(IF_BEGIN, IF_END); + visit(CPP14Parser.Else).map(ELSE); - mapEnter(LabeledStatementContext.class, CASE, rule -> rule.Case() != null); - mapEnter(LabeledStatementContext.class, DEFAULT, rule -> rule.Default() != null); + visit(LabeledStatementContext.class, rule -> rule.Case() != null).map(CASE); + visit(LabeledStatementContext.class, rule -> rule.Default() != null).map(DEFAULT); - mapEnter(TryBlockContext.class, TRY); - mapEnterExit(HandlerContext.class, CATCH_BEGIN, CATCH_END); + visit(TryBlockContext.class).map(TRY); + visit(HandlerContext.class).map(CATCH_BEGIN, CATCH_END); - mapEnter(JumpStatementContext.class, BREAK, rule -> rule.Break() != null); - mapEnter(JumpStatementContext.class, CONTINUE, rule -> rule.Continue() != null); - mapEnter(JumpStatementContext.class, GOTO, rule -> rule.Goto() != null); - mapEnter(JumpStatementContext.class, RETURN, rule -> rule.Return() != null); + visit(JumpStatementContext.class, rule -> rule.Break() != null).map(BREAK); + visit(JumpStatementContext.class, rule -> rule.Continue() != null).map(CONTINUE); + visit(JumpStatementContext.class, rule -> rule.Goto() != null).map(GOTO); + visit(JumpStatementContext.class, rule -> rule.Return() != null).map(RETURN); - mapEnter(ThrowExpressionContext.class, THROW); + visit(ThrowExpressionContext.class).map(THROW); - mapEnter(NewExpressionContext.class, NEWCLASS, rule -> rule.newInitializer() != null); - mapEnter(NewExpressionContext.class, NEWARRAY, rule -> rule.newInitializer() == null); + visit(NewExpressionContext.class, rule -> rule.newInitializer() != null).map(NEWCLASS); + visit(NewExpressionContext.class, rule -> rule.newInitializer() == null).map(NEWARRAY); - mapEnter(TemplateDeclarationContext.class, GENERIC); + visit(TemplateDeclarationContext.class).map(GENERIC); - mapEnter(AssignmentOperatorContext.class, ASSIGN); - mapEnter(BraceOrEqualInitializerContext.class, ASSIGN, rule -> rule.Assign() != null); - mapEnter(UnaryExpressionContext.class, ASSIGN, rule -> rule.PlusPlus() != null || rule.MinusMinus() != null); + visit(AssignmentOperatorContext.class).map(ASSIGN); + visit(BraceOrEqualInitializerContext.class, rule -> rule.Assign() != null).map(ASSIGN); + visit(UnaryExpressionContext.class, rule -> rule.PlusPlus() != null || rule.MinusMinus() != null).map(ASSIGN); - mapEnter(StaticAssertDeclarationContext.class, STATIC_ASSERT); - mapEnter(EnumeratorDefinitionContext.class, VARDEF); - mapEnterExit(BracedInitListContext.class, BRACED_INIT_BEGIN, BRACED_INIT_END); + visit(StaticAssertDeclarationContext.class).map(STATIC_ASSERT); + visit(EnumeratorDefinitionContext.class).map(VARDEF); + visit(BracedInitListContext.class).map(BRACED_INIT_BEGIN, BRACED_INIT_END); - mapEnter(SimpleTypeSpecifierContext.class, VARDEF, rule -> { + visit(SimpleTypeSpecifierContext.class, rule -> { if (hasAncestor(rule, MemberdeclarationContext.class, FunctionDefinitionContext.class)) { return true; } @@ -80,23 +71,23 @@ public CPPListener(TokenCollector collector, File currentFile) { } return false; - }); + }).map(VARDEF); - mapEnter(SimpleDeclarationContext.class, APPLY, rule -> { + visit(SimpleDeclarationContext.class, rule -> { if (!hasAncestor(rule, FunctionBodyContext.class)) { return false; } NoPointerDeclaratorContext noPointerDecl = getDescendant(rule, NoPointerDeclaratorContext.class); return noPointerInFunctionCallContext(noPointerDecl); - }); + }).map(APPLY); - mapEnter(InitDeclaratorContext.class, APPLY, rule -> rule.initializer() != null && rule.initializer().LeftParen() != null); - mapEnter(ParameterDeclarationContext.class, VARDEF); - mapEnter(ConditionalExpressionContext.class, QUESTIONMARK, rule -> rule.Question() != null); + visit(InitDeclaratorContext.class, rule -> rule.initializer() != null && rule.initializer().LeftParen() != null).map(APPLY); + visit(ParameterDeclarationContext.class).map(VARDEF); + visit(ConditionalExpressionContext.class, rule -> rule.Question() != null).map(QUESTIONMARK); - mapEnter(PostfixExpressionContext.class, APPLY, rule -> rule.LeftParen() != null); - mapEnter(PostfixExpressionContext.class, ASSIGN, rule -> rule.PlusPlus() != null || rule.MinusMinus() != null); + visit(PostfixExpressionContext.class, rule -> rule.LeftParen() != null).map(APPLY); + visit(PostfixExpressionContext.class, rule -> rule.PlusPlus() != null || rule.MinusMinus() != null).map(ASSIGN); } /** diff --git a/languages/cpp2/src/main/java/de/jplag/cpp2/CPPParserAdapter.java b/languages/cpp2/src/main/java/de/jplag/cpp2/CPPParserAdapter.java index fc73e2b11..c876023ee 100644 --- a/languages/cpp2/src/main/java/de/jplag/cpp2/CPPParserAdapter.java +++ b/languages/cpp2/src/main/java/de/jplag/cpp2/CPPParserAdapter.java @@ -1,7 +1,5 @@ package de.jplag.cpp2; -import java.io.File; - import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Lexer; @@ -10,7 +8,6 @@ import de.jplag.AbstractParser; import de.jplag.antlr.AbstractAntlrListener; import de.jplag.antlr.AbstractAntlrParserAdapter; -import de.jplag.antlr.TokenCollector; import de.jplag.cpp2.grammar.CPP14Lexer; import de.jplag.cpp2.grammar.CPP14Parser; @@ -18,6 +15,8 @@ * The adapter between {@link AbstractParser} and the ANTLR based parser of this language module. */ public class CPPParserAdapter extends AbstractAntlrParserAdapter { + private static final CPPListener listener = new CPPListener(); + @Override protected Lexer createLexer(CharStream input) { return new CPP14Lexer(input); @@ -34,7 +33,7 @@ protected ParserRuleContext getEntryContext(CPP14Parser parser) { } @Override - protected AbstractAntlrListener createListener(TokenCollector collector, File currentFile) { - return new CPPListener(collector, currentFile); + protected AbstractAntlrListener getListener() { + return listener; } } diff --git a/languages/kotlin/src/main/java/de/jplag/kotlin/KotlinListener.java b/languages/kotlin/src/main/java/de/jplag/kotlin/KotlinListener.java index bb308df61..19a475ffa 100644 --- a/languages/kotlin/src/main/java/de/jplag/kotlin/KotlinListener.java +++ b/languages/kotlin/src/main/java/de/jplag/kotlin/KotlinListener.java @@ -93,59 +93,55 @@ import static de.jplag.kotlin.grammar.KotlinParser.WhenExpressionContext; import static de.jplag.kotlin.grammar.KotlinParser.WhileExpressionContext; -import java.io.File; - import de.jplag.antlr.AbstractAntlrListener; -import de.jplag.antlr.TokenCollector; import de.jplag.kotlin.grammar.KotlinParser; -public class KotlinListener extends AbstractAntlrListener { - public KotlinListener(TokenCollector collector, File currentFile) { - super(collector, currentFile); +class KotlinListener extends AbstractAntlrListener { - this.mapRange(PackageHeaderContext.class, PACKAGE); - this.mapRange(ImportHeaderContext.class, IMPORT); - this.mapEnter(ClassDeclarationContext.class, CLASS_DECLARATION); - this.mapRange(ObjectDeclarationContext.class, OBJECT_DECLARATION); - this.mapRange(CompanionObjectContext.class, COMPANION_DECLARATION); - this.mapRange(TypeParameterContext.class, TYPE_PARAMETER); - this.mapRange(PrimaryConstructorContext.class, CONSTRUCTOR); - this.mapRange(ClassParameterContext.class, PROPERTY_DECLARATION); - this.mapEnterExit(ClassBodyContext.class, CLASS_BODY_BEGIN, CLASS_BODY_END); - this.mapEnterExit(EnumClassBodyContext.class, ENUM_CLASS_BODY_BEGIN, ENUM_CLASS_BODY_END); - this.mapEnter(EnumEntryContext.class, ENUM_ENTRY); - this.mapRange(SecondaryConstructorContext.class, CONSTRUCTOR); - this.mapEnter(PropertyDeclarationContext.class, PROPERTY_DECLARATION); - this.mapEnter(AnonymousInitializerContext.class, INITIALIZER); - this.mapEnterExit(InitBlockContext.class, INITIALIZER_BODY_START, INITIALIZER_BODY_END); - this.mapEnter(FunctionDeclarationContext.class, FUNCTION); - this.mapEnter(GetterContext.class, GETTER); - this.mapEnter(SetterContext.class, SETTER); - this.mapRange(FunctionValueParameterContext.class, FUNCTION_PARAMETER); - this.mapEnterExit(FunctionBodyContext.class, FUNCTION_BODY_BEGIN, FUNCTION_BODY_END); - this.mapEnterExit(FunctionLiteralContext.class, FUNCTION_LITERAL_BEGIN, FUNCTION_LITERAL_END); - this.mapEnterExit(ForExpressionContext.class, FOR_EXPRESSION_BEGIN, FOR_EXPRESSION_END); - this.mapEnterExit(IfExpressionContext.class, IF_EXPRESSION_BEGIN, IF_EXPRESSION_END); - this.mapEnterExit(WhileExpressionContext.class, WHILE_EXPRESSION_START, WHILE_EXPRESSION_END); - this.mapEnterExit(DoWhileExpressionContext.class, DO_WHILE_EXPRESSION_START, DO_WHILE_EXPRESSION_END); - this.mapEnter(TryExpressionContext.class, TRY_EXPRESSION); - this.mapEnterExit(TryBodyContext.class, TRY_BODY_START, TRY_BODY_END); - this.mapEnter(CatchStatementContext.class, CATCH); - this.mapEnterExit(CatchBodyContext.class, CATCH_BODY_START, CATCH_BODY_END); - this.mapEnter(FinallyStatementContext.class, FINALLY); - this.mapEnterExit(FinallyBodyContext.class, FINALLY_BODY_START, FINALLY_BODY_END); - this.mapEnterExit(WhenExpressionContext.class, WHEN_EXPRESSION_START, WHEN_EXPRESSION_END); - this.mapEnter(WhenConditionContext.class, WHEN_CONDITION); - this.mapEnterExit(ControlStructureBodyContext.class, CONTROL_STRUCTURE_BODY_START, CONTROL_STRUCTURE_BODY_END); - this.mapEnter(VariableDeclarationContext.class, VARIABLE_DECLARATION); - this.mapRange(ConstructorInvocationContext.class, CREATE_OBJECT); - this.mapRange(CallSuffixContext.class, FUNCTION_INVOCATION); - this.mapEnter(AssignmentOperatorContext.class, ASSIGNMENT); + KotlinListener() { + visit(PackageHeaderContext.class).map(PACKAGE); + visit(ImportHeaderContext.class).map(IMPORT); + visit(ClassDeclarationContext.class).map(CLASS_DECLARATION); + visit(ObjectDeclarationContext.class).map(OBJECT_DECLARATION); + visit(CompanionObjectContext.class).map(COMPANION_DECLARATION); + visit(TypeParameterContext.class).map(TYPE_PARAMETER); + visit(PrimaryConstructorContext.class).map(CONSTRUCTOR); + visit(ClassParameterContext.class).map(PROPERTY_DECLARATION); + visit(ClassBodyContext.class).map(CLASS_BODY_BEGIN, CLASS_BODY_END); + visit(EnumClassBodyContext.class).map(ENUM_CLASS_BODY_BEGIN, ENUM_CLASS_BODY_END); + visit(EnumEntryContext.class).map(ENUM_ENTRY); + visit(SecondaryConstructorContext.class).map(CONSTRUCTOR); + visit(PropertyDeclarationContext.class).map(PROPERTY_DECLARATION); + visit(AnonymousInitializerContext.class).map(INITIALIZER); + visit(InitBlockContext.class).map(INITIALIZER_BODY_START, INITIALIZER_BODY_END); + visit(FunctionDeclarationContext.class).map(FUNCTION); + visit(GetterContext.class).map(GETTER); + visit(SetterContext.class).map(SETTER); + visit(FunctionValueParameterContext.class).map(FUNCTION_PARAMETER); + visit(FunctionBodyContext.class).map(FUNCTION_BODY_BEGIN, FUNCTION_BODY_END); + visit(FunctionLiteralContext.class).map(FUNCTION_LITERAL_BEGIN, FUNCTION_LITERAL_END); + visit(ForExpressionContext.class).map(FOR_EXPRESSION_BEGIN, FOR_EXPRESSION_END); + visit(IfExpressionContext.class).map(IF_EXPRESSION_BEGIN, IF_EXPRESSION_END); + visit(WhileExpressionContext.class).map(WHILE_EXPRESSION_START, WHILE_EXPRESSION_END); + visit(DoWhileExpressionContext.class).map(DO_WHILE_EXPRESSION_START, DO_WHILE_EXPRESSION_END); + visit(TryExpressionContext.class).map(TRY_EXPRESSION); + visit(TryBodyContext.class).map(TRY_BODY_START, TRY_BODY_END); + visit(CatchStatementContext.class).map(CATCH); + visit(CatchBodyContext.class).map(CATCH_BODY_START, CATCH_BODY_END); + visit(FinallyStatementContext.class).map(FINALLY); + visit(FinallyBodyContext.class).map(FINALLY_BODY_START, FINALLY_BODY_END); + visit(WhenExpressionContext.class).map(WHEN_EXPRESSION_START, WHEN_EXPRESSION_END); + visit(WhenConditionContext.class).map(WHEN_CONDITION); + visit(ControlStructureBodyContext.class).map(CONTROL_STRUCTURE_BODY_START, CONTROL_STRUCTURE_BODY_END); + visit(VariableDeclarationContext.class).map(VARIABLE_DECLARATION); + visit(ConstructorInvocationContext.class).map(CREATE_OBJECT); + visit(CallSuffixContext.class).map(FUNCTION_INVOCATION); + visit(AssignmentOperatorContext.class).map(ASSIGNMENT); - this.mapTerminal(KotlinParser.THROW, THROW); - this.mapTerminal(KotlinParser.RETURN, RETURN); - this.mapTerminal(KotlinParser.CONTINUE, CONTINUE); - this.mapTerminal(KotlinParser.BREAK, BREAK); - this.mapTerminal(KotlinParser.BREAK_AT, BREAK); + visit(KotlinParser.THROW).map(THROW); + visit(KotlinParser.RETURN).map(RETURN); + visit(KotlinParser.CONTINUE).map(CONTINUE); + visit(KotlinParser.BREAK).map(BREAK); + visit(KotlinParser.BREAK_AT).map(BREAK); } } diff --git a/languages/kotlin/src/main/java/de/jplag/kotlin/KotlinParserAdapter.java b/languages/kotlin/src/main/java/de/jplag/kotlin/KotlinParserAdapter.java index 49537918d..0fed85032 100644 --- a/languages/kotlin/src/main/java/de/jplag/kotlin/KotlinParserAdapter.java +++ b/languages/kotlin/src/main/java/de/jplag/kotlin/KotlinParserAdapter.java @@ -1,16 +1,15 @@ package de.jplag.kotlin; -import java.io.File; - import org.antlr.v4.runtime.*; import de.jplag.antlr.AbstractAntlrListener; import de.jplag.antlr.AbstractAntlrParserAdapter; -import de.jplag.antlr.TokenCollector; import de.jplag.kotlin.grammar.KotlinLexer; import de.jplag.kotlin.grammar.KotlinParser; public class KotlinParserAdapter extends AbstractAntlrParserAdapter { + private static final KotlinListener listener = new KotlinListener(); + @Override protected Lexer createLexer(CharStream input) { return new KotlinLexer(input); @@ -27,7 +26,7 @@ protected ParserRuleContext getEntryContext(KotlinParser parser) { } @Override - protected AbstractAntlrListener createListener(TokenCollector collector, File currentFile) { - return new KotlinListener(collector, currentFile); + protected AbstractAntlrListener getListener() { + return listener; } } diff --git a/languages/llvmir/src/main/java/de/jplag/llvmir/LLVMIRListener.java b/languages/llvmir/src/main/java/de/jplag/llvmir/LLVMIRListener.java index ed0efc65f..24e70a9ca 100644 --- a/languages/llvmir/src/main/java/de/jplag/llvmir/LLVMIRListener.java +++ b/languages/llvmir/src/main/java/de/jplag/llvmir/LLVMIRListener.java @@ -110,133 +110,123 @@ import static de.jplag.llvmir.grammar.LLVMIRParser.ZExtExprContext; import static de.jplag.llvmir.grammar.LLVMIRParser.ZExtInstContext; -import java.io.File; - import de.jplag.antlr.AbstractAntlrListener; -import de.jplag.antlr.TokenCollector; /** * Extracts tokens from the ANTLR parse tree. The token abstraction includes nesting tokens for functions and basic * blocks and separate tokens for different elements. These include binary and bitwise instructions, memory operations, * terminator instructions, conversions, global variables, type definitions, constants, and others. */ -public class LLVMIRListener extends AbstractAntlrListener { - - /** - * New instance - * @param collector The token collector the token will be added to - * @param currentFile The currently processed file - */ - public LLVMIRListener(TokenCollector collector, File currentFile) { - super(collector, currentFile); +class LLVMIRListener extends AbstractAntlrListener { - this.mapEnter(SourceFilenameContext.class, FILENAME); - this.mapRange(ModuleAsmContext.class, ASSEMBLY); - this.mapEnter(TypeDefContext.class, TYPE_DEFINITION); - this.mapRange(GlobalDeclContext.class, GLOBAL_VARIABLE); - this.mapRange(GlobalDefContext.class, GLOBAL_VARIABLE); - this.mapRange(FuncDeclContext.class, FUNCTION_DECLARATION); - this.mapRange(FuncDefContext.class, FUNCTION_DEFINITION); - this.mapEnterExit(FuncBodyContext.class, FUNCTION_BODY_BEGIN, FUNCTION_BODY_END); - this.mapEnterExit(BasicBlockContext.class, BASIC_BLOCK_BEGIN, BASIC_BLOCK_END); - this.mapRange(RetTermContext.class, RETURN); - this.mapRange(BrTermContext.class, BRANCH); - this.mapRange(CondBrTermContext.class, CONDITIONAL_BRANCH); - this.mapRange(SwitchTermContext.class, SWITCH); - this.mapRange(IndirectBrTermContext.class, BRANCH); - this.mapRange(ResumeTermContext.class, RESUME); - this.mapRange(CatchRetTermContext.class, CATCH_RETURN); - this.mapRange(CleanupRetTermContext.class, CLEAN_UP_RETURN); - this.mapRange(InvokeTermContext.class, INVOKE); - this.mapRange(CallBrTermContext.class, CALL_BRANCH); - this.mapRange(CatchSwitchTermContext.class, CATCH_SWITCH); - this.mapRange(Case_Context.class, CASE); - this.mapRange(StructConstContext.class, STRUCTURE); - this.mapRange(ArrayConstContext.class, ARRAY); - this.mapRange(VectorConstContext.class, VECTOR); - this.mapRange(InlineAsmContext.class, ASSEMBLY); - this.mapRange(BitCastExprContext.class, BITCAST); - this.mapRange(GetElementPtrExprContext.class, GET_ELEMENT_POINTER); - this.mapEnter(AddrSpaceCastExprContext.class, CONVERSION); - this.mapEnter(IntToPtrExprContext.class, CONVERSION); - this.mapRange(ICmpExprContext.class, COMPARISON); - this.mapRange(FCmpExprContext.class, COMPARISON); - this.mapRange(SelectExprContext.class, SELECT); - this.mapEnter(TruncExprContext.class, CONVERSION); - this.mapEnter(ZExtExprContext.class, CONVERSION); - this.mapEnter(SExtExprContext.class, CONVERSION); - this.mapEnter(FpTruncExprContext.class, CONVERSION); - this.mapEnter(FpExtExprContext.class, CONVERSION); - this.mapEnter(FpToUiExprContext.class, CONVERSION); - this.mapEnter(FpToSiExprContext.class, CONVERSION); - this.mapEnter(UiToFpExprContext.class, CONVERSION); - this.mapEnter(SiToFpExprContext.class, CONVERSION); - this.mapEnter(PtrToIntExprContext.class, CONVERSION); - this.mapEnter(ExtractElementExprContext.class, EXTRACT_ELEMENT); - this.mapEnter(InsertElementExprContext.class, INSERT_ELEMENT); - this.mapEnter(ShuffleVectorExprContext.class, SHUFFLE_VECTOR); - this.mapRange(ShlExprContext.class, SHIFT); - this.mapRange(LShrExprContext.class, SHIFT); - this.mapRange(AShrExprContext.class, SHIFT); - this.mapRange(AndExprContext.class, AND); - this.mapRange(OrExprContext.class, OR); - this.mapRange(XorExprContext.class, XOR); - this.mapRange(AddExprContext.class, ADDITION); - this.mapRange(SubExprContext.class, SUBTRACTION); - this.mapRange(MulExprContext.class, MULTIPLICATION); - this.mapRange(StoreInstContext.class, STORE); - this.mapRange(FenceInstContext.class, FENCE); - this.mapRange(AddInstContext.class, ADDITION); - this.mapRange(FAddInstContext.class, ADDITION); - this.mapRange(SubInstContext.class, SUBTRACTION); - this.mapRange(FSubInstContext.class, SUBTRACTION); - this.mapRange(MulInstContext.class, MULTIPLICATION); - this.mapRange(FMulInstContext.class, MULTIPLICATION); - this.mapRange(UDivInstContext.class, DIVISION); - this.mapRange(SDivInstContext.class, DIVISION); - this.mapRange(FDivInstContext.class, DIVISION); - this.mapRange(URemInstContext.class, REMAINDER); - this.mapRange(SRemInstContext.class, REMAINDER); - this.mapRange(FRemInstContext.class, REMAINDER); - this.mapRange(ShlInstContext.class, SHIFT); - this.mapRange(LShrInstContext.class, SHIFT); - this.mapRange(AShrInstContext.class, SHIFT); - this.mapRange(AndInstContext.class, AND); - this.mapRange(OrInstContext.class, OR); - this.mapRange(XorInstContext.class, XOR); - this.mapEnter(ExtractElementInstContext.class, EXTRACT_ELEMENT); - this.mapEnter(InsertElementInstContext.class, INSERT_ELEMENT); - this.mapEnter(ShuffleVectorInstContext.class, SHUFFLE_VECTOR); - this.mapRange(ExtractValueInstContext.class, EXTRACT_VALUE); - this.mapRange(InsertValueInstContext.class, INSERT_VALUE); - this.mapRange(AllocaInstContext.class, ALLOCATION); - this.mapRange(LoadInstContext.class, LOAD); - this.mapRange(CmpXchgInstContext.class, COMPARE_EXCHANGE); - this.mapRange(AtomicRMWInstContext.class, ATOMIC_READ_MODIFY_WRITE); - this.mapRange(GetElementPtrInstContext.class, GET_ELEMENT_POINTER); - this.mapEnter(TruncInstContext.class, CONVERSION); - this.mapEnter(ZExtInstContext.class, CONVERSION); - this.mapEnter(SExtInstContext.class, CONVERSION); - this.mapEnter(FpTruncInstContext.class, CONVERSION); - this.mapEnter(FpExtInstContext.class, CONVERSION); - this.mapEnter(FpToUiInstContext.class, CONVERSION); - this.mapEnter(FpToSiInstContext.class, CONVERSION); - this.mapEnter(UiToFpInstContext.class, CONVERSION); - this.mapEnter(SiToFpInstContext.class, CONVERSION); - this.mapEnter(PtrToIntInstContext.class, CONVERSION); - this.mapEnter(IntToPtrInstContext.class, CONVERSION); - this.mapRange(BitCastInstContext.class, BITCAST); - this.mapEnter(AddrSpaceCastInstContext.class, CONVERSION); - this.mapRange(ICmpInstContext.class, COMPARISON); - this.mapRange(FCmpInstContext.class, COMPARISON); - this.mapRange(PhiInstContext.class, PHI); - this.mapRange(SelectInstContext.class, SELECT); - this.mapRange(CallInstContext.class, CALL); - this.mapRange(VaargInstContext.class, VARIABLE_ARGUMENT); - this.mapRange(LandingPadInstContext.class, LANDING_PAD); - this.mapRange(CatchPadInstContext.class, CATCH_PAD); - this.mapRange(CleanupPadInstContext.class, CLEAN_UP_PAD); - this.mapRange(ClauseContext.class, CLAUSE); - this.mapRange(AtomicOrderingContext.class, ATOMIC_ORDERING); + LLVMIRListener() { + visit(SourceFilenameContext.class).map(FILENAME); + visit(ModuleAsmContext.class).map(ASSEMBLY); + visit(TypeDefContext.class).map(TYPE_DEFINITION); + visit(GlobalDeclContext.class).map(GLOBAL_VARIABLE); + visit(GlobalDefContext.class).map(GLOBAL_VARIABLE); + visit(FuncDeclContext.class).map(FUNCTION_DECLARATION); + visit(FuncDefContext.class).map(FUNCTION_DEFINITION); + visit(FuncBodyContext.class).map(FUNCTION_BODY_BEGIN, FUNCTION_BODY_END); + visit(BasicBlockContext.class).map(BASIC_BLOCK_BEGIN, BASIC_BLOCK_END); + visit(RetTermContext.class).map(RETURN); + visit(BrTermContext.class).map(BRANCH); + visit(CondBrTermContext.class).map(CONDITIONAL_BRANCH); + visit(SwitchTermContext.class).map(SWITCH); + visit(IndirectBrTermContext.class).map(BRANCH); + visit(ResumeTermContext.class).map(RESUME); + visit(CatchRetTermContext.class).map(CATCH_RETURN); + visit(CleanupRetTermContext.class).map(CLEAN_UP_RETURN); + visit(InvokeTermContext.class).map(INVOKE); + visit(CallBrTermContext.class).map(CALL_BRANCH); + visit(CatchSwitchTermContext.class).map(CATCH_SWITCH); + visit(Case_Context.class).map(CASE); + visit(StructConstContext.class).map(STRUCTURE); + visit(ArrayConstContext.class).map(ARRAY); + visit(VectorConstContext.class).map(VECTOR); + visit(InlineAsmContext.class).map(ASSEMBLY); + visit(BitCastExprContext.class).map(BITCAST); + visit(GetElementPtrExprContext.class).map(GET_ELEMENT_POINTER); + visit(AddrSpaceCastExprContext.class).map(CONVERSION); + visit(IntToPtrExprContext.class).map(CONVERSION); + visit(ICmpExprContext.class).map(COMPARISON); + visit(FCmpExprContext.class).map(COMPARISON); + visit(SelectExprContext.class).map(SELECT); + visit(TruncExprContext.class).map(CONVERSION); + visit(ZExtExprContext.class).map(CONVERSION); + visit(SExtExprContext.class).map(CONVERSION); + visit(FpTruncExprContext.class).map(CONVERSION); + visit(FpExtExprContext.class).map(CONVERSION); + visit(FpToUiExprContext.class).map(CONVERSION); + visit(FpToSiExprContext.class).map(CONVERSION); + visit(UiToFpExprContext.class).map(CONVERSION); + visit(SiToFpExprContext.class).map(CONVERSION); + visit(PtrToIntExprContext.class).map(CONVERSION); + visit(ExtractElementExprContext.class).map(EXTRACT_ELEMENT); + visit(InsertElementExprContext.class).map(INSERT_ELEMENT); + visit(ShuffleVectorExprContext.class).map(SHUFFLE_VECTOR); + visit(ShlExprContext.class).map(SHIFT); + visit(LShrExprContext.class).map(SHIFT); + visit(AShrExprContext.class).map(SHIFT); + visit(AndExprContext.class).map(AND); + visit(OrExprContext.class).map(OR); + visit(XorExprContext.class).map(XOR); + visit(AddExprContext.class).map(ADDITION); + visit(SubExprContext.class).map(SUBTRACTION); + visit(MulExprContext.class).map(MULTIPLICATION); + visit(StoreInstContext.class).map(STORE); + visit(FenceInstContext.class).map(FENCE); + visit(AddInstContext.class).map(ADDITION); + visit(FAddInstContext.class).map(ADDITION); + visit(SubInstContext.class).map(SUBTRACTION); + visit(FSubInstContext.class).map(SUBTRACTION); + visit(MulInstContext.class).map(MULTIPLICATION); + visit(FMulInstContext.class).map(MULTIPLICATION); + visit(UDivInstContext.class).map(DIVISION); + visit(SDivInstContext.class).map(DIVISION); + visit(FDivInstContext.class).map(DIVISION); + visit(URemInstContext.class).map(REMAINDER); + visit(SRemInstContext.class).map(REMAINDER); + visit(FRemInstContext.class).map(REMAINDER); + visit(ShlInstContext.class).map(SHIFT); + visit(LShrInstContext.class).map(SHIFT); + visit(AShrInstContext.class).map(SHIFT); + visit(AndInstContext.class).map(AND); + visit(OrInstContext.class).map(OR); + visit(XorInstContext.class).map(XOR); + visit(ExtractElementInstContext.class).map(EXTRACT_ELEMENT); + visit(InsertElementInstContext.class).map(INSERT_ELEMENT); + visit(ShuffleVectorInstContext.class).map(SHUFFLE_VECTOR); + visit(ExtractValueInstContext.class).map(EXTRACT_VALUE); + visit(InsertValueInstContext.class).map(INSERT_VALUE); + visit(AllocaInstContext.class).map(ALLOCATION); + visit(LoadInstContext.class).map(LOAD); + visit(CmpXchgInstContext.class).map(COMPARE_EXCHANGE); + visit(AtomicRMWInstContext.class).map(ATOMIC_READ_MODIFY_WRITE); + visit(GetElementPtrInstContext.class).map(GET_ELEMENT_POINTER); + visit(TruncInstContext.class).map(CONVERSION); + visit(ZExtInstContext.class).map(CONVERSION); + visit(SExtInstContext.class).map(CONVERSION); + visit(FpTruncInstContext.class).map(CONVERSION); + visit(FpExtInstContext.class).map(CONVERSION); + visit(FpToUiInstContext.class).map(CONVERSION); + visit(FpToSiInstContext.class).map(CONVERSION); + visit(UiToFpInstContext.class).map(CONVERSION); + visit(SiToFpInstContext.class).map(CONVERSION); + visit(PtrToIntInstContext.class).map(CONVERSION); + visit(IntToPtrInstContext.class).map(CONVERSION); + visit(BitCastInstContext.class).map(BITCAST); + visit(AddrSpaceCastInstContext.class).map(CONVERSION); + visit(ICmpInstContext.class).map(COMPARISON); + visit(FCmpInstContext.class).map(COMPARISON); + visit(PhiInstContext.class).map(PHI); + visit(SelectInstContext.class).map(SELECT); + visit(CallInstContext.class).map(CALL); + visit(VaargInstContext.class).map(VARIABLE_ARGUMENT); + visit(LandingPadInstContext.class).map(LANDING_PAD); + visit(CatchPadInstContext.class).map(CATCH_PAD); + visit(CleanupPadInstContext.class).map(CLEAN_UP_PAD); + visit(ClauseContext.class).map(CLAUSE); + visit(AtomicOrderingContext.class).map(ATOMIC_ORDERING); } } diff --git a/languages/llvmir/src/main/java/de/jplag/llvmir/LLVMIRParserAdapter.java b/languages/llvmir/src/main/java/de/jplag/llvmir/LLVMIRParserAdapter.java index 0d96e301e..edbe94148 100644 --- a/languages/llvmir/src/main/java/de/jplag/llvmir/LLVMIRParserAdapter.java +++ b/languages/llvmir/src/main/java/de/jplag/llvmir/LLVMIRParserAdapter.java @@ -1,13 +1,10 @@ package de.jplag.llvmir; -import java.io.File; - import org.antlr.v4.runtime.*; import de.jplag.AbstractParser; import de.jplag.antlr.AbstractAntlrListener; import de.jplag.antlr.AbstractAntlrParserAdapter; -import de.jplag.antlr.TokenCollector; import de.jplag.llvmir.grammar.LLVMIRLexer; import de.jplag.llvmir.grammar.LLVMIRParser; @@ -15,6 +12,8 @@ * The adapter between {@link AbstractParser} and the ANTLR based parser of this language module. */ public class LLVMIRParserAdapter extends AbstractAntlrParserAdapter { + private static final LLVMIRListener listener = new LLVMIRListener(); + @Override protected Lexer createLexer(CharStream input) { return new LLVMIRLexer(input); @@ -31,7 +30,7 @@ protected ParserRuleContext getEntryContext(LLVMIRParser parser) { } @Override - protected AbstractAntlrListener createListener(TokenCollector collector, File currentFile) { - return new LLVMIRListener(collector, currentFile); + protected AbstractAntlrListener getListener() { + return listener; } } diff --git a/languages/typescript/src/main/java/de/jplag/typescript/TypeScriptListener.java b/languages/typescript/src/main/java/de/jplag/typescript/TypeScriptListener.java index a71b3dc84..31dc21378 100644 --- a/languages/typescript/src/main/java/de/jplag/typescript/TypeScriptListener.java +++ b/languages/typescript/src/main/java/de/jplag/typescript/TypeScriptListener.java @@ -76,76 +76,71 @@ import static de.jplag.typescript.grammar.TypeScriptParser.VariableDeclarationContext; import static de.jplag.typescript.grammar.TypeScriptParser.WhileStatementContext; -import java.io.File; - import de.jplag.antlr.AbstractAntlrListener; -import de.jplag.antlr.TokenCollector; /** * This class is responsible for mapping parsed TypeScript to the internal Token structure */ public class TypeScriptListener extends AbstractAntlrListener { - public TypeScriptListener(TokenCollector collector, File currentFile) { - super(collector, currentFile); - - this.mapRange(ImportStatementContext.class, IMPORT); - this.mapTerminal(Export, EXPORT); - this.mapEnterExit(NamespaceDeclarationContext.class, NAMESPACE_BEGIN, NAMESPACE_END); + public TypeScriptListener() { + visit(ImportStatementContext.class).map(IMPORT); + visit(Export).map(EXPORT); + visit(NamespaceDeclarationContext.class).map(NAMESPACE_BEGIN, NAMESPACE_END); - this.mapEnterExit(ClassDeclarationContext.class, CLASS_BEGIN, CLASS_END); - this.mapEnterExit(GetterSetterDeclarationExpressionContext.class, METHOD_BEGIN, METHOD_END); - this.mapRange(PropertyDeclarationExpressionContext.class, DECLARATION); - this.mapRange(PropertyDeclarationExpressionContext.class, ASSIGNMENT, it -> it.initializer() != null); - this.mapRange(PropertySetterContext.class, ASSIGNMENT); - this.mapRange(PropertySignaturContext.class, DECLARATION); + visit(ClassDeclarationContext.class).map(CLASS_BEGIN, CLASS_END); + visit(GetterSetterDeclarationExpressionContext.class).map(METHOD_BEGIN, METHOD_END); + visit(PropertyDeclarationExpressionContext.class).map(DECLARATION); + visit(PropertyDeclarationExpressionContext.class, it -> it.initializer() != null).map(ASSIGNMENT); + visit(PropertySetterContext.class).map(ASSIGNMENT); + visit(PropertySignaturContext.class).map(DECLARATION); - this.mapEnterExit(InterfaceDeclarationContext.class, INTERFACE_BEGIN, INTERFACE_END); - this.mapEnterExit(ConstructorDeclarationContext.class, CONSTRUCTOR_BEGIN, CONSTRUCTOR_END); + visit(InterfaceDeclarationContext.class).map(INTERFACE_BEGIN, INTERFACE_END); + visit(ConstructorDeclarationContext.class).map(CONSTRUCTOR_BEGIN, CONSTRUCTOR_END); - this.mapEnterExit(EnumDeclarationContext.class, ENUM_BEGIN, ENUM_END); - this.mapRange(EnumMemberContext.class, ENUM_MEMBER); + visit(EnumDeclarationContext.class).map(ENUM_BEGIN, ENUM_END); + visit(EnumMemberContext.class).map(ENUM_MEMBER); - this.mapRange(VariableDeclarationContext.class, DECLARATION); - this.mapRange(VariableDeclarationContext.class, ASSIGNMENT, it -> it.Assign() != null); + visit(VariableDeclarationContext.class).map(DECLARATION); + visit(VariableDeclarationContext.class, it -> it.Assign() != null).map(ASSIGNMENT); - this.mapEnterExit(IfStatementContext.class, IF_BEGIN, IF_END); - this.mapTerminal(Else, IF_BEGIN); + visit(IfStatementContext.class).map(IF_BEGIN, IF_END); + visit(Else).map(IF_BEGIN); - this.mapEnterExit(SwitchStatementContext.class, SWITCH_BEGIN, SWITCH_END); - this.mapRange(CaseClauseContext.class, SWITCH_CASE); - this.mapRange(DefaultClauseContext.class, SWITCH_CASE); + visit(SwitchStatementContext.class).map(SWITCH_BEGIN, SWITCH_END); + visit(CaseClauseContext.class).map(SWITCH_CASE); + visit(DefaultClauseContext.class).map(SWITCH_CASE); - this.mapEnterExit(MethodDeclarationExpressionContext.class, METHOD_BEGIN, METHOD_END); + visit(MethodDeclarationExpressionContext.class).map(METHOD_BEGIN, METHOD_END); - this.mapRange(FunctionDeclarationContext.class, DECLARATION); - this.mapRange(FunctionDeclarationContext.class, ASSIGNMENT); - this.mapEnterExit(FunctionDeclarationContext.class, METHOD_BEGIN, METHOD_END); + visit(FunctionDeclarationContext.class).map(DECLARATION); + visit(FunctionDeclarationContext.class).map(ASSIGNMENT); + visit(FunctionDeclarationContext.class).map(METHOD_BEGIN, METHOD_END); - this.mapEnterExit(ArrowFunctionDeclarationContext.class, METHOD_BEGIN, METHOD_END); - this.mapEnterExit(FunctionExpressionDeclarationContext.class, METHOD_BEGIN, METHOD_END); + visit(ArrowFunctionDeclarationContext.class).map(METHOD_BEGIN, METHOD_END); + visit(FunctionExpressionDeclarationContext.class).map(METHOD_BEGIN, METHOD_END); - this.mapEnterExit(WhileStatementContext.class, WHILE_BEGIN, WHILE_END); - this.mapEnterExit(ForStatementContext.class, FOR_BEGIN, FOR_END); - this.mapEnterExit(ForVarStatementContext.class, FOR_BEGIN, FOR_END); - this.mapEnterExit(ForInStatementContext.class, FOR_BEGIN, FOR_END); + visit(WhileStatementContext.class).map(WHILE_BEGIN, WHILE_END); + visit(ForStatementContext.class).map(FOR_BEGIN, FOR_END); + visit(ForVarStatementContext.class).map(FOR_BEGIN, FOR_END); + visit(ForInStatementContext.class).map(FOR_BEGIN, FOR_END); - this.mapRange(TryStatementContext.class, TRY_BEGIN); - this.mapEnterExit(CatchProductionContext.class, CATCH_BEGIN, CATCH_END); - this.mapEnterExit(FinallyProductionContext.class, FINALLY_BEGIN, FINALLY_END); + visit(TryStatementContext.class).map(TRY_BEGIN); + visit(CatchProductionContext.class).map(CATCH_BEGIN, CATCH_END); + visit(FinallyProductionContext.class).map(FINALLY_BEGIN, FINALLY_END); - this.mapRange(BreakStatementContext.class, BREAK); - this.mapRange(ReturnStatementContext.class, RETURN); - this.mapRange(ContinueStatementContext.class, CONTINUE); - this.mapRange(ThrowStatementContext.class, THROW); + visit(BreakStatementContext.class).map(BREAK); + visit(ReturnStatementContext.class).map(RETURN); + visit(ContinueStatementContext.class).map(CONTINUE); + visit(ThrowStatementContext.class).map(THROW); - this.mapRange(AssignmentExpressionContext.class, ASSIGNMENT); - this.mapRange(PostDecreaseExpressionContext.class, ASSIGNMENT); - this.mapRange(PreDecreaseExpressionContext.class, ASSIGNMENT); - this.mapRange(PostIncrementExpressionContext.class, ASSIGNMENT); - this.mapRange(PreIncrementExpressionContext.class, ASSIGNMENT); + visit(AssignmentExpressionContext.class).map(ASSIGNMENT); + visit(PostDecreaseExpressionContext.class).map(ASSIGNMENT); + visit(PreDecreaseExpressionContext.class).map(ASSIGNMENT); + visit(PostIncrementExpressionContext.class).map(ASSIGNMENT); + visit(PreIncrementExpressionContext.class).map(ASSIGNMENT); - this.mapRange(ArgumentsContext.class, FUNCTION_CALL); + visit(ArgumentsContext.class).map(FUNCTION_CALL); } } diff --git a/languages/typescript/src/main/java/de/jplag/typescript/TypeScriptParserAdapter.java b/languages/typescript/src/main/java/de/jplag/typescript/TypeScriptParserAdapter.java index 2f7586d1c..837512053 100644 --- a/languages/typescript/src/main/java/de/jplag/typescript/TypeScriptParserAdapter.java +++ b/languages/typescript/src/main/java/de/jplag/typescript/TypeScriptParserAdapter.java @@ -1,7 +1,5 @@ package de.jplag.typescript; -import java.io.File; - import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Lexer; @@ -9,7 +7,6 @@ import de.jplag.antlr.AbstractAntlrListener; import de.jplag.antlr.AbstractAntlrParserAdapter; -import de.jplag.antlr.TokenCollector; import de.jplag.typescript.grammar.TypeScriptLexer; import de.jplag.typescript.grammar.TypeScriptParser; @@ -17,7 +14,7 @@ * The Antlr adapter used for the TypeScript language module */ public class TypeScriptParserAdapter extends AbstractAntlrParserAdapter { - + private static final TypeScriptListener listener = new TypeScriptListener(); private final boolean useStrictDefault; /** @@ -46,7 +43,7 @@ protected ParserRuleContext getEntryContext(TypeScriptParser parser) { } @Override - protected AbstractAntlrListener createListener(TokenCollector collector, File currentFile) { - return new TypeScriptListener(collector, currentFile); + protected AbstractAntlrListener getListener() { + return listener; } }