Statement ParseStatement(Scope scope) { int startP = reader.p; int startLine = reader.Peek().Line; Statement stat = null; // print(tok.Peek().Print()) if (reader.ConsumeKeyword("if")) { //setup IfStmt _if = new IfStmt(); //clauses do { int sP = reader.p; Expression nodeCond = ParseExpr(scope); if (!reader.ConsumeKeyword("then")) error("'then' expected"); List<Statement> nodeBody = ParseStatementList(scope); List<Token> range = new List<Token>(); range.Add(reader.tokens[sP - 1]); range.AddRange(reader.Range(sP, reader.p)); _if.Clauses.Add(new ElseIfStmt(scope) { Condition = nodeCond, Body = nodeBody, ScannedTokens = range }); } while (reader.ConsumeKeyword("elseif")); // else clause if (reader.ConsumeKeyword("else")) { int sP = reader.p; List<Statement> nodeBody = ParseStatementList(scope); List<Token> range = new List<Token>(); range.Add(reader.tokens[sP - 1]); range.AddRange(reader.Range(sP, reader.p)); _if.Clauses.Add(new ElseStmt(scope) { Body = nodeBody, ScannedTokens = range }); } // end if (!reader.ConsumeKeyword("end")) error("'end' expected"); stat = _if; } else if (reader.ConsumeKeyword("while")) { WhileStatement w = new WhileStatement(scope); // condition Expression nodeCond = ParseExpr(scope); // do if (!reader.ConsumeKeyword("do")) error("'do' expected"); // body List<Statement> body = ParseStatementList(scope); //end if (!reader.ConsumeKeyword("end")) error("'end' expected"); // return w.Condition = nodeCond; w.Body = body; stat = w; } else if (reader.ConsumeKeyword("do")) { // do block List<Statement> b = ParseStatementList(scope); if (!reader.ConsumeKeyword("end")) error("'end' expected"); stat = new DoStatement(scope) { Body = b }; } else if (reader.ConsumeKeyword("for")) { //for block if (!reader.Is(TokenType.Ident)) error("<ident> expected"); Token baseVarName = reader.Get(); if (reader.ConsumeSymbol('=')) { //numeric for NumericForStatement forL = new NumericForStatement(scope); Variable forVar = new Variable() { Name = baseVarName.Data }; forL.Scope.AddLocal(forVar); Expression startEx = ParseExpr(scope); if (!reader.ConsumeSymbol(',')) error("',' expected"); Expression endEx = ParseExpr(scope); Expression stepEx = null; if (reader.ConsumeSymbol(',')) { stepEx = ParseExpr(scope); } if (!reader.ConsumeKeyword("do")) error("'do' expected"); List<Statement> body = ParseStatementList(forL.Scope); if (!reader.ConsumeKeyword("end")) error("'end' expected"); forL.Variable = forVar; forL.Start = startEx; forL.End = endEx; forL.Step = stepEx; forL.Body = body; stat = forL; } else { // generic for GenericForStatement forL = new GenericForStatement(scope); List<Variable> varList = new List<Variable> { forL.Scope.CreateLocal(baseVarName.Data) }; while (reader.ConsumeSymbol(',')) { if (!reader.Is(TokenType.Ident)) error("for variable expected"); varList.Add(forL.Scope.CreateLocal(reader.Get().Data)); } if (!reader.ConsumeKeyword("in")) error("'in' expected"); List<Expression> generators = new List<Expression>(); Expression first = ParseExpr(scope); generators.Add(first); while (reader.ConsumeSymbol(',')) { Expression gen = ParseExpr(scope); generators.Add(gen); } if (!reader.ConsumeKeyword("do")) error("'do' expected"); List<Statement> body = ParseStatementList(forL.Scope); if (!reader.ConsumeKeyword("end")) error("'end' expected"); forL.VariableList = varList; forL.Generators = generators; forL.Body = body; stat = forL; } } else if (reader.ConsumeKeyword("repeat")) { List<Statement> body = ParseStatementList(scope); if (!reader.ConsumeKeyword("until")) error("'until' expected"); Expression cond = ParseExpr(scope); RepeatStatement r = new RepeatStatement(scope); r.Condition = cond; r.Body = body; stat = r; } else if (reader.ConsumeKeyword("function")) { if (!reader.Is(TokenType.Ident)) error("function name expected"); Expression name = ParseSuffixedExpr(scope, true); // true: only dots and colons FunctionStatement func = ParseFunctionArgsAndBody(scope); func.IsLocal = false; func.Name = name; stat = func; } else if (reader.ConsumeKeyword("local")) { if (reader.Is(TokenType.Ident)) { List<string> varList = new List<string> { reader.Get().Data }; while (reader.ConsumeSymbol(',')) { if (!reader.Is(TokenType.Ident)) error("local variable name expected"); varList.Add(reader.Get().Data); } List<Expression> initList = new List<Expression>(); if (reader.ConsumeSymbol('=')) { do { Expression ex = ParseExpr(scope); initList.Add(ex); } while (reader.ConsumeSymbol(',')); } //now patch var list //we can't do this before getting the init list, because the init list does not //have the locals themselves in scope. List<Expression> newVarList = new List<Expression>(); for (int i = 0; i < varList.Count; i++) { Variable x = scope.CreateLocal(varList[i]); newVarList.Add(new VariableExpression { Var = x }); } AssignmentStatement l = new AssignmentStatement(); l.Lhs = newVarList; l.Rhs = initList; l.IsLocal = true; stat = l; } else if (reader.ConsumeKeyword("function")) { if (!reader.Is(TokenType.Ident)) error("Function name expected"); string name = reader.Get().Data; Variable localVar = scope.CreateLocal(name); FunctionStatement func = ParseFunctionArgsAndBody(scope); func.Name = new VariableExpression { Var = localVar }; func.IsLocal = true; stat = func; } else error("local variable or function definition expected"); } #if !VANILLA_LUA else if (reader.ConsumeSymbol("::")) { if (!reader.Is(TokenType.Ident)) error("label name expected"); string label = reader.Get().Data; if (!reader.ConsumeSymbol("::")) error("'::' expected"); LabelStatement l = new LabelStatement(); l.Label = label; stat = l; } #endif else if (reader.ConsumeKeyword("return")) { List<Expression> exprList = new List<Expression>(); if (!reader.IsKeyword("end") && !reader.IsEof()) { Expression firstEx = ParseExpr(scope); exprList.Add(firstEx); while (reader.ConsumeSymbol(',')) { Expression ex = ParseExpr(scope); exprList.Add(ex); } } ReturnStatement r = new ReturnStatement(); r.Arguments = exprList; stat = r; } else if (reader.ConsumeKeyword("break")) { stat = new BreakStatement(); } else if (reader.ConsumeKeyword("continue")) { stat = new ContinueStatement(); } #if !VANILLA_LUA else if (reader.ConsumeKeyword("goto")) { if (!reader.Is(TokenType.Ident)) error("label expected"); string label = reader.Get().Data; GotoStatement g = new GotoStatement(); g.Label = label; stat = g; } else if (reader.ConsumeKeyword("using")) { // using <a, b = 1, x()> do <statements> end UsingStatement us = new UsingStatement(scope); us.Scope = new Scope(scope); List<Expression> lhs = new List<Expression> { ParseExpr(us.Scope) }; while (reader.ConsumeSymbol(',')) { lhs.Add(ParseSuffixedExpr(us.Scope, true)); } // equals if (!reader.ConsumeSymbol('=')) error("'=' expected"); //rhs List<Expression> rhs = new List<Expression>(); rhs.Add(ParseExpr(us.Scope)); while (reader.ConsumeSymbol(',')) { rhs.Add(ParseExpr(scope)); } AssignmentStatement a = new AssignmentStatement(); a.Lhs = lhs; a.Rhs = rhs; a.IsLocal = true; if (!reader.ConsumeKeyword("do")) error("'do' expected"); List<Statement> block = ParseStatementList(us.Scope); if (!reader.ConsumeKeyword("end")) error("'end' expected"); us.Vars = a; us.Body = block; stat = us; } #endif else { // statementParseExpr Expression suffixed = ParseSuffixedExpr(scope); // assignment or call? if (reader.IsSymbol(',') || reader.IsSymbol('=')) { // check that it was not parenthesized, making it not an lvalue if (suffixed.ParenCount > 0) error("Can not assign to parenthesized expression, it is not an lvalue"); // more processing needed List<Expression> lhs = new List<Expression> { suffixed }; while (reader.ConsumeSymbol(',')) { lhs.Add(ParseSuffixedExpr(scope)); } // equals if (!reader.ConsumeSymbol('=')) error("'=' expected"); //rhs List<Expression> rhs = new List<Expression>(); rhs.Add(ParseExpr(scope)); while (reader.ConsumeSymbol(',')) { rhs.Add(ParseExpr(scope)); } AssignmentStatement a = new AssignmentStatement(); a.Lhs = lhs; a.Rhs = rhs; stat = a; } #if !VANILLA_LUA else if (isAugmentedAssignment(reader.Peek())) { AugmentedAssignmentStatement aas = new AugmentedAssignmentStatement(); Expression left = suffixed; Expression right = null; string augmentedOp = reader.Get().Data; right = ParseExpr(scope); BinOpExpr nRight = new BinOpExpr(); nRight.Lhs = left; nRight.Op = augmentedOp.Substring(0, augmentedOp.Length - 1); // strip the '=' nRight.Rhs = right; aas.Lhs = new List<Expression> { left }; aas.Rhs = new List<Expression> { nRight }; stat = aas; } #endif else if (suffixed is CallExpr || suffixed is TableCallExpr || suffixed is StringCallExpr) { //it's a call statement CallStatement c = new CallStatement(); c.Expression = suffixed; stat = c; } else error("assignment statement expected"); } stat.ScannedTokens = reader.Range(startP, reader.p); if (reader.Peek().Data == ";" && reader.Peek().Type == TokenType.Symbol) { stat.HasSemicolon = true; stat.SemicolonToken = reader.Get(); } if (stat.Scope == null) stat.Scope = scope; stat.LineNumber = startLine; return stat; }
Expression ParseSubExpr(Scope scope, int level) { // base item, possibly with unop prefix Expression exp = null; if (isUnOp(reader.Peek().Data) && (reader.Peek().Type == TokenType.Symbol || reader.Peek().Type == TokenType.Keyword)) { string op = reader.Get().Data; exp = ParseSubExpr(scope, unopprio); exp = new UnOpExpr { Rhs = exp, Op = op }; } else exp = ParseSimpleExpr(scope); if (exp is InlineFunctionExpression) return exp; // inline functions cannot have any extra parts // next items in chain while (true) { priority_ prio = getpriority(reader.Peek().Data); if (prio != null && prio.l > level) { string op = reader.Get().Data; Expression rhs = ParseSubExpr(scope, prio.r); BinOpExpr binOpExpr = new BinOpExpr(); binOpExpr.Lhs = exp; binOpExpr.Op = op; binOpExpr.Rhs = rhs; exp = binOpExpr; } else break; } return exp; }