package scotch.compiler.analyzer; import static java.util.stream.Collectors.toList; import static scotch.compiler.syntax.definition.DefinitionEntry.entry; import static scotch.compiler.syntax.reference.DefinitionReference.rootRef; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; import java.util.Optional; import java.util.function.Supplier; import scotch.compiler.syntax.definition.Definition; import scotch.compiler.syntax.definition.DefinitionEntry; import scotch.compiler.syntax.definition.DefinitionGraph; import scotch.compiler.syntax.pattern.CaptureMatch; import scotch.compiler.syntax.pattern.DefaultPatternReducer; import scotch.compiler.syntax.pattern.PatternCase; import scotch.compiler.syntax.pattern.PatternReducer; import scotch.compiler.syntax.reference.DefinitionReference; import scotch.compiler.syntax.scope.Scope; import scotch.compiler.syntax.value.FunctionValue; import scotch.compiler.syntax.value.IsConstructor; import scotch.compiler.syntax.value.PatternMatcher; import scotch.compiler.syntax.value.Value; import scotch.symbol.Symbol; import scotch.compiler.syntax.type.VariableType; import scotch.compiler.syntax.util.SymbolGenerator; public class PatternAnalyzer implements PatternReducer { private final DefinitionGraph graph; private final List<DefinitionEntry> entries; private final Deque<Scope> scopes; private final PatternReducer patternReducer; public PatternAnalyzer(DefinitionGraph graph) { this.graph = graph; this.entries = new ArrayList<>(); this.scopes = new ArrayDeque<>(); this.patternReducer = new DefaultPatternReducer(new SymbolGeneratorShim()); } @Override public void addAssignment(CaptureMatch capture) { patternReducer.addAssignment(capture); } @Override public void addCondition(Value argument, Value value) { patternReducer.addCondition(argument, value); } @Override public void addCondition(IsConstructor constructor) { patternReducer.addCondition(constructor); } @Override public void addTaggedArgument(Value taggedArgument) { patternReducer.addTaggedArgument(taggedArgument); } @Override public void markFunction(FunctionValue function) { entries.add(entry(graph.getScope(function.getReference()), function.getDefinition())); } @Override public void beginPattern(PatternMatcher matcher) { entries.add(entry(graph.getScope(matcher.getReference()), matcher.getDefinition())); patternReducer.beginPattern(matcher); } @Override public void beginPatternCase(PatternCase patternCase) { entries.add(entry(graph.getScope(patternCase.getReference()), patternCase.getDefinition())); patternReducer.beginPatternCase(patternCase); } @Override public void endPattern() { patternReducer.endPattern(); } @Override public void endPatternCase() { patternReducer.endPatternCase(); } @Override public Value getTaggedArgument(Value argument) { return patternReducer.getTaggedArgument(argument); } public Definition keep(Definition definition) { entries.add(entry(graph.getScope(definition.getReference()), definition)); return definition; } @Override public Value reducePattern() { return patternReducer.reducePattern(); } public DefinitionGraph reducePatterns() { getDefinition(rootRef()) .orElseThrow(() -> new IllegalStateException("Root definition not found")) .reducePatterns(this); return graph .copyWith(entries) .build(); } public List<DefinitionReference> reducePatterns(List<DefinitionReference> references) { return references.stream() .map(this::getDefinition) .filter(Optional::isPresent) .map(Optional::get) .map(definition -> definition.reducePatterns(this)) .map(Definition::getReference) .collect(toList()); } public Scope scope() { return scopes.peek(); } public Definition scoped(Definition definition, Supplier<Definition> runnable) { scopes.push(graph.getScope(definition.getReference())); try { Definition result = runnable.get(); entries.add(entry(scopes.peek(), result)); return result; } finally { scopes.pop(); } } private Optional<Definition> getDefinition(DefinitionReference reference) { return graph.getDefinition(reference); } private class SymbolGeneratorShim implements SymbolGenerator { @Override public Symbol reserveSymbol() { return scope().reserveSymbol(); } @Override public Symbol reserveSymbol(List<String> nestings) { return scope().reserveSymbol(nestings); } @Override public VariableType reserveType() { return scope().reserveType(); } @Override public void startTypesAt(int counter) { throw new UnsupportedOperationException(); } } }