internal void Accept(NodeEndL endl) { builder.currentLineNumber = endl.EndLine; builder.OpEndL(); }
void ASTVisitor.Accept(NodeEndL value) { Accept(value); }
private Node PrimaryExpression(bool allowPostfixInvocation = true) { if (!TokensRemain) return null; var loc = Location; Node node; switch (Current.type) { case WILDCARD: // If we aren't in a truly anon function, we ignore this if (CurrentFunction != null && CurrentFunction.fullAnon && CurrentFunction.paramNames.Count == 0) CurrentFunction.paramNames.Add(null); node = new NodeWildcard(loc); Advance(); break; case PARAM_INDEX: var index = (uint)Current.intValue; // If we aren't in a truly anon function, we ignore this if (CurrentFunction != null && CurrentFunction.fullAnon) while (CurrentFunction.paramNames.Count <= index) CurrentFunction.paramNames.Add(null); node = new NodeParamIndex(loc, index); Advance(); break; case IDENTIFIER: node = new NodeIdentifier(loc, Current.image); Advance(); break; case SYMBOL: node = new NodeSymbol(loc, Current.image); Advance(); break; case NULL: node = new NodeNull(loc); Advance(); break; case TRUE: case FALSE: node = new NodeBool(loc, Check(TRUE)); Advance(); break; case ENDL: node = new NodeEndL(loc); Advance(); break; case THIS: node = new NodeThis(loc); Advance(); break; case SELF: node = new NodeSelf(loc); Advance(); break; case INT: node = new NodeInt(loc, Current.intValue); Advance(); break; case FLOAT: node = new NodeFloat(loc, Current.floatValue); Advance(); break; case STRING: node = new NodeString(loc, Current.image); Advance(); break; case OPEN_BRACE: Advance(); if (Check(CLOSE_BRACE)) { // 0-length tuple: node = new NodeTuple(loc, new List<Node>()); node.EndLine = Current.location.line; Advance(); } else { var values = CommaExpressions(); if (values.Count != 1) { // This is a tuple :D node = new NodeTuple(loc, values); Expect(CLOSE_BRACE, "Closing brace (')') expected to end tuple expression."); node.EndLine = tokens[-1].location.line; } else { Expect(CLOSE_BRACE, "Closing brace (')') expected to surround expression."); // Just an expression, carry on: node = values[0]; } } break; case OPEN_SQUARE_BRACE: // This is a list :D Advance(); node = new NodeList(loc, (TokensRemain && Current.type != CLOSE_SQUARE_BRACE) ? CommaExpressions() : new List<Node>()); Expect(CLOSE_SQUARE_BRACE, "Closing square brace (']') expected to end list expression."); node.EndLine = tokens[-1].location.line; break; case OPEN_CURLY_BRACE: // This is a code block :D Advance(); var exprs = new List<Node>(); while (!Check(CLOSE_CURLY_BRACE)) { if (!TokensRemain) { log.Error(tokens[-1].location, "Unfinished block. A closing curly brace ('}') should be used to end blocks."); break; } var expr = Expression(); if (expr != null) exprs.Add(expr); } Expect(CLOSE_CURLY_BRACE, "Closing curly brace ('}') expected to end block."); node = new NodeBlock(loc, exprs); node.EndLine = tokens[-1].location.line; break; case TAILREC: Advance(); Expect(OPEN_BRACE, "Expected an open brace ('(') to begin the tailrec argument list."); List<Node> args; if (!Check(CLOSE_BRACE)) args = CommaExpressions(); else args = new List<Node>(); Expect(CLOSE_BRACE, "Expected a close brace (')') to end the tailrec argument list."); node = new NodeTailRec(loc, args); break; // These can't be postfix'd, so we don't allow it. case OPERATOR: var prefix = Current.image; Advance(); if (!TokensRemain) log.Error(loc, "An expression is expected after prefix operator, but the end of the file was reached."); var prefixValue = PrimaryExpression(); return new NodePrefix(loc, prefix, prefixValue); case NOT: Advance(); if (!TokensRemain) log.Error(loc, "An expression is expected after the 'not' keyword, but the end of the file was reached."); return new NodeNot(loc, Expression()); case THROW: Advance(); if (!TokensRemain) log.Error(loc, "An expression is expected after the 'throw' keyword, but the end of the file was reached."); return new NodeThrow(loc, Expression()); case YIELD: Advance(); if (!TokensRemain) log.Error(loc, "An expression is expected after the 'yield' keyword, but the end of the file was reached."); return new NodeYield(loc, Expression()); case RES: Advance(); if (!TokensRemain) log.Error(loc, "An expression is expected after the 'res' keyword, but the end of the file was reached."); return new NodeRes(loc, Expression()); case BREAK: Advance(); string bLabel = null; if (Check(IDENTIFIER) && Current.location.line == loc.line) { bLabel = Current.image; Advance(); } return new NodeBreak(loc, bLabel); case CONT: Advance(); string cLabel = null; if (Check(IDENTIFIER) && Current.location.line == loc.line) { cLabel = Current.image; Advance(); } return new NodeCont(loc, cLabel); case FN: return ParseFn(); case GEN: return ParseFn(true); case VAR: return ParseVar(); case IF: return ParseIf(); case WHILE: return ParseWhile(); case TRY: return ParseTry(); case ITER: return ParseIter(); case EACH: return ParseEach(); // And here, we don't know what they want... oops. default: log.Error(Location, "Unexpected token '{0}', skipping...", Current.ToString()); // We don't know what to do with this, let's skip and try to recover. Advance(); // Error saying we couldn't understand the token: // return a new primary expression. return PrimaryExpression(); } // TODO postfix return Postfix(node, allowPostfixInvocation); }