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 extends ParserRuleContext>... 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 extends ParserRuleContext> parent,
+ protected static boolean hasAncestor(ParserRuleContext context, Class extends ParserRuleContext> parent,
Class extends ParserRuleContext>... stops) {
return getAncestor(context, parent, stops) != null;
}
@@ -263,7 +143,7 @@ protected final boolean hasAncestor(ParserRuleContext context, Class extends P
* @param 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;
}
}