package me.august.lumen.compile.parser; import me.august.lumen.compile.CompileBuildContext; import me.august.lumen.compile.codegen.BuildContext; import me.august.lumen.compile.parser.ast.expr.Expression; import me.august.lumen.compile.parser.components.*; import me.august.lumen.compile.scanner.Token; import me.august.lumen.compile.scanner.TokenSource; import me.august.lumen.compile.scanner.Type; import me.august.lumen.compile.scanner.pos.Span; import java.util.HashMap; import java.util.Map; import java.util.Stack; import static me.august.lumen.compile.scanner.Type.*; public class ExpressionParser implements TokenParser { private final static Map<Type, PrefixParser> prefixParsers = new HashMap<>(); private final static Map<Type, InfixParser> infixParsers = new HashMap<>(); private final static Map<Type, InfixParser> postfixParsers = new HashMap<>(); static { UnaryPrefixParser unaryPrefixParser = new UnaryPrefixParser(); prefixParsers.put(PLUS, unaryPrefixParser); prefixParsers.put(MIN, unaryPrefixParser); prefixParsers.put(BIT_COMP, unaryPrefixParser); prefixParsers.put(INC, unaryPrefixParser); prefixParsers.put(DEC, unaryPrefixParser); prefixParsers.put(NOT, unaryPrefixParser); prefixParsers.put(IDENTIFIER, new IdentifierParser()); prefixParsers.put(NUMBER, ComponentParsers.NUMBER_PARSER); prefixParsers.put(L_PAREN, ComponentParsers.GROUPING_PARSER); prefixParsers.put(STRING, ComponentParsers.STRING_PARSER); prefixParsers.put(TRUE, ComponentParsers.BOOLEAN_PARSER); prefixParsers.put(FALSE, ComponentParsers.BOOLEAN_PARSER); prefixParsers.put(NULL, ComponentParsers.NULL_PARSER); infixParsers.put(ASSIGN, new AssignmentParser()); // infix, prefix, and mixfix parsers AdditiveParser additiveParser = new AdditiveParser(); infixParsers.put(PLUS, additiveParser); infixParsers.put(MIN, additiveParser); MultiplicativeParser multiplicativeParser = new MultiplicativeParser(); infixParsers.put(MULT, multiplicativeParser); infixParsers.put(DIV, multiplicativeParser); infixParsers.put(REM, multiplicativeParser); infixParsers.put(QUESTION, new TernaryParser()); infixParsers.put(RESCUE_KEYWORD, new RescueParser()); EqualityParser equalityParser = new EqualityParser(); infixParsers.put(EQ, equalityParser); infixParsers.put(NE, equalityParser); RelationalParser relParser = new RelationalParser(); infixParsers.put(GT, relParser); infixParsers.put(GTE, relParser); infixParsers.put(LT, relParser); infixParsers.put(LTE, relParser); infixParsers.put(INSTANCEOF_KEYWORD, relParser); infixParsers.put(NOT_INSTANCEOF_KEYWORD, relParser); ShiftParser shiftParser = new ShiftParser(); infixParsers.put(SH_L, shiftParser); infixParsers.put(SH_R, shiftParser); infixParsers.put(U_SH_R, shiftParser); infixParsers.put(CAST_KEYWORD, new CastParser()); RangeParser rangeParser = new RangeParser(); infixParsers.put(RANGE_INCLUSIVE, rangeParser); infixParsers.put(RANGE_EXCLUSIVE, rangeParser); PostfixParser postfixParser = new PostfixParser(); postfixParsers.put(INC, postfixParser); postfixParsers.put(DEC, postfixParser); postfixParsers.put(L_BRACKET, postfixParser); } private TokenSource tokenSource; private Stack<Token> queuedTokens = new Stack<>(); private Stack<Span> spanRecorder = new Stack<>(); private BuildContext buildContext; public ExpressionParser(TokenSource tokenSource) { this.tokenSource = tokenSource; this.buildContext = new CompileBuildContext(); } public ExpressionParser(TokenSource tokenSource, BuildContext buildContext) { this.tokenSource = tokenSource; this.buildContext = buildContext; } @Override public Token consume() { Token token; if (!queuedTokens.empty()) { token = queuedTokens.pop(); } else { token = tokenSource.nextToken(); } for (Span span : spanRecorder) { if (span.getStart() < 0) { span.setStart(token.getStart()); } span.setEnd(token.getEnd()); } return token; } @Override public Token peek() { if (!queuedTokens.empty()) { return queuedTokens.get(0); } else { return queuedTokens.push(tokenSource.nextToken()); } } @Override public boolean expect(Type type) { Token token = consume(); if (token.getType() != type) { throw new RuntimeException("Expected " + type + ", found " + token.getType()); } return true; } @Override public boolean accept(Type type) { if (peek().getType() == type) { consume(); return true; } return false; } protected void startRecording() { spanRecorder.push(new Span(-1, 0)); } protected void stopRecording() { spanRecorder.pop(); } protected <T> T endRecording(T obj) { Span span = spanRecorder.pop(); buildContext.positionMap().put(obj, span); return obj; } protected <T> T keepAndEndRecording(T obj) { Span spanCopy = new Span(spanRecorder.lastElement()); buildContext.positionMap().put(obj, spanCopy); return obj; } @Override public Expression parseExpression(int predence) { startRecording(); Token token = consume(); PrefixParser prefixParser = prefixParsers.get(token.getType()); if (prefixParser == null) { throw new RuntimeException("Unexpected token: " + token); } Expression left = prefixParser.parse(this, token); keepAndEndRecording(left); while (postfixParsers.containsKey(peek().getType())) { token = consume(); left = postfixParsers.get(token.getType()).parse(this, left, token); keepAndEndRecording(left); } while (predence < getPrecedence()) { token = consume(); InfixParser infix = infixParsers.get(token.getType()); left = infix.parse(this, left, token); keepAndEndRecording(left); } stopRecording(); return left; } private int getPrecedence() { InfixParser parser = infixParsers.get(peek().getType()); if (parser != null) { return parser.getPrecedence(); } else { return 0; } } public BuildContext getBuildContext() { return buildContext; } }