private Tree ParseStatement() { if (curToken.type == TokenType.Keyword) { Token keyword = curToken; nextToken(); if (keyword.value == "var" || keyword.value == "global") { bool isLocal = keyword.value == "var"; string varName = curToken.value; nextToken(); Tree expression = null; if (accept(equals).valid) { expression = ParseExpression(); } Scope last = scopes[scopes.Count - 1]; if (isLocal) { last.localVariables.Add(varName, last.localCount); last.localCount++; last.maxLocalCount = Math.Max(last.localCount, last.maxLocalCount); return(new LocalAssignmentTree(last.localCount - 1, expression)); } else { last.globalVariables.Add(varName, true); return(new GlobalAssignmentTree(varName, expression)); } } else if (keyword.value == "function") { string name = expect(Token.Identifier).value; scopes[scopes.Count - 1].globalVariables.Add(name, true); CreateClosureTree funcTree = ParseFunctionDeclaration(); GlobalAssignmentTree tree = new GlobalAssignmentTree(name, funcTree); return(tree); } else if (keyword.value == "if") { IfTree tree = new IfTree(); expect(lParen); tree.condition = ParseExpression(); expect(rParen); tree.ifBody = ParseBlockOrStatement(ScopeType.If); if (accept(kElse).valid) { tree.hasElse = true; tree.elseBody = ParseBlockOrStatement(ScopeType.If); } return(tree); } else if (keyword.value == "while") { WhileTree tree = new WhileTree(); expect(lParen); tree.condition = ParseExpression(); expect(rParen); tree.body = ParseBlockOrStatement(ScopeType.While); return(tree); } else if (keyword.value == "return") { ReturnTree tree = new ReturnTree(); if (curToken.type != TokenType.Punctuation) { tree.value = ParseExpression(); } return(tree); } } else if (curToken.type == TokenType.Identifier || curToken.compare(lParen)) { Tree thing = ParseIndexOrCall(); if (thing.type == TreeType.FunctionCall) { return(thing); } else { // assignment if (thing.type == TreeType.GlobalValue) { expect(equals); Tree value = ParseExpression(); return(new GlobalAssignmentTree((thing as GlobalValueTree).name, value)); } else if (thing.type == TreeType.LocalValue) { expect(equals); Tree value = ParseExpression(); return(new LocalAssignmentTree((thing as LocalValueTree).index, value)); } else if (thing.type == TreeType.ObjectIndexValue) { expect(equals); Tree value = ParseExpression(); ObjectIndexValueTree OIVTree = thing as ObjectIndexValueTree; return(new ObjectIndexAssignmentTree(OIVTree.Object, OIVTree.Index, value)); } } } throw new SyntaxErrorException(curToken.line, "Did not expect " + curToken + " here"); }
//========== private Tree ParseIndexOrCall(Tree theObject = null) { if (theObject == null) { if (curToken.type == TokenType.Identifier) { theObject = GetVariableFromName(curToken.value); if (theObject == null) { throw new ReferenceErrorException(curToken.line, $"'{curToken.value}' is not defined"); } if (theObject.type == TreeType.LocalValue) { if ((theObject as LocalValueTree).functionId != scopes[scopes.Count - 1].functionId) { throw new SyntaxErrorException(curToken.line, "upvalues are not supported"); } } nextToken(); } else if (accept(lParen).valid) { theObject = ParseExpression(); expect(rParen); } else { throw new SyntaxErrorException(curToken.line, "Did not expect " + curToken + " here"); } } if (theObject.type == TreeType.FunctionCall) { (theObject as FunctionCallTree).isExpression = true; } if (accept(dot).valid) { //index using identifier theObject = new ObjectIndexValueTree(theObject, new StringTree(expect(Token.Identifier).value)); return(ParseIndexOrCall(theObject)); } else if (accept(lSquare).valid) { //index using expression Tree index = ParseExpression(); expect(rSquare); theObject = new ObjectIndexValueTree(theObject, index); return(ParseIndexOrCall(theObject)); } else if (accept(lParen).valid) { //function call FunctionCallTree tree = new FunctionCallTree(theObject); if (!accept(rParen).valid) { do { tree.AddArgument(ParseExpression()); } while (accept(comma).valid); expect(rParen); } return(ParseIndexOrCall(tree)); } if (theObject.type == TreeType.FunctionCall) { (theObject as FunctionCallTree).isExpression = false; } return(theObject); }