public void BooleanAND() { AST root = new AST(new Token(Token.TokenType.OPERATOR, "&&")); AST lhs = new AST(new Token(Token.TokenType.NUMBER, "1")); AST rhs = new AST(new Token(Token.TokenType.NUMBER, "0")); root.addChild(lhs); root.addChild(rhs); ExpressionEvaluator e = new ExpressionEvaluator(root); Assert.AreEqual(0, e.getValue()); }
public void BooleanGREATEROREQUALS2() { AST root = new AST(new Token(Token.TokenType.OPERATOR, ">=")); AST lhs = new AST(new Token(Token.TokenType.NUMBER, "4")); AST rhs = new AST(new Token(Token.TokenType.NUMBER, "3")); root.addChild(lhs); root.addChild(rhs); ExpressionEvaluator e = new ExpressionEvaluator(root); Assert.AreEqual(1, e.getValue()); }
private AST createParameterDefinition(string typeName, string variableName) { AST parameter = new AST(new Token(Token.TokenType.PARAMETER, "<PARAMETER>")); AST declaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<PARAMETER_DECLARATION>"), ReturnValue.getReturnValueTypeFromString(typeName), variableName); AST assigment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), variableName); parameter.addChild(declaration); parameter.addChild(assigment); return parameter; }
private void defineFunction(FunctionDefinition f) { if (externalFunctions.ContainsKey(f.functionName)) { throw new Error("There is already a function called '" + f.functionName + "'", Error.ErrorType.UNDEFINED, 0, 0); } AST parameterList = new AST(new Token(Token.TokenType.NODE_GROUP, "<PARAMETER_LIST>")); for (int i = 0; i < f.parameterTypes.Length; ++i) { parameterList.addChild(createParameterDefinition(f.parameterTypes[i], f.parameterNames[i])); } AST functionNode = createFunctionDefinitionNode(f.returnType, f.functionName, parameterList); m_builtInFunctions.Add(functionNode); externalFunctions.Add(f.functionName, f.callback); }
private ExternalFunctionCreator AddExternalFunctions(FunctionDefinition[] functionDefinitions, AST ast) { List <FunctionDefinition> allFunctionDefinitions = new List <FunctionDefinition>(); allFunctionDefinitions.AddRange(builtInFunctions); allFunctionDefinitions.AddRange(functionDefinitions); // HasFunction requires a reference to the SprakRunner FunctionDocumentation functionDoc_HasFunction = new FunctionDocumentation("Check if a function exists on the object", new string[] { "The name of the function" }); allFunctionDefinitions.Add(new FunctionDefinition("bool", "HasFunction", new string[] { "string" }, new string[] { "functionName" }, new ExternalFunctionCreator.OnFunctionCall(API_hasFunction), functionDoc_HasFunction)); ExternalFunctionCreator externalFunctionCreator = new ExternalFunctionCreator(allFunctionDefinitions.ToArray()); AST functionList = ast.getChild(1); foreach (AST externalFunction in externalFunctionCreator.FunctionASTs) { functionList.addChild(externalFunction); } return(externalFunctionCreator); }
private AST booleanExpression() { #if WRITE_DEBUG_INFO Console.WriteLine("boolean expression"); #endif AST lhs = comparisonExpression(); if ( lookAhead(1).getTokenString() == "&&" || lookAhead(1).getTokenString() == "||" ) { Token operatorToken = match(Token.TokenType.OPERATOR); //Console.WriteLine ("Matched operator token " + operatorToken.getTokenString() + " at line " + operatorToken.LineNr + " and pos " + operatorToken.LinePosition); AST rhs = booleanExpression(); checkLeftHandSide(lhs, operatorToken); checkRightHandSide(rhs, operatorToken); AST booleanExpressionTree = new AST(operatorToken); booleanExpressionTree.addChild(lhs); booleanExpressionTree.addChild(rhs); return booleanExpressionTree; } else { return lhs; } }
private AST loop() { #if WRITE_DEBUG_INFO Console.WriteLine("loop"); #endif AST loopBlockStatements = new AST(new Token(Token.TokenType.STATEMENT_LIST, "<LOOP_BLOCK_STATEMENTS>")); AST_LoopNode loopTree = new AST_LoopNode(match(Token.TokenType.LOOP)); bool isForeachLoop = false; if(lookAheadType(1) != Token.TokenType.NEW_LINE) { #if WRITE_DEBUG_INFO Console.WriteLine("foreach loop!"); #endif isForeachLoop = true; // __index__ AST_VariableDeclaration loopIndexDeclaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.NUMBER, "__index__"); loopBlockStatements.addChild(loopIndexDeclaration); AST_Assignment loopIndexAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__index__"); loopIndexAssignment.addChild(new AST(new TokenWithValue(Token.TokenType.NUMBER, "-1", new ReturnValue(-1.0f)))); loopBlockStatements.addChild(loopIndexAssignment); // match //match(Token.TokenType.PARANTHESIS_LEFT); AST arrayExpression = expression(); //match(Token.TokenType.PARANTHESIS_RIGHT); // __array__ (is a copy of the array to loop over) AST_VariableDeclaration loopArrayDeclaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.ARRAY, "__array__"); loopBlockStatements.addChild(loopArrayDeclaration); AST_Assignment loopArrayAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__array__"); if(arrayExpression != null) { loopArrayAssignment.addChild(arrayExpression); } else { throw new Error("Can't understand array expression in loop", Error.ErrorType.SYNTAX, loopArrayAssignment.getToken().LineNr, loopArrayAssignment.getToken().LinePosition); } loopBlockStatements.addChild(loopArrayAssignment); // __indexes__ (holds all the indexes in the array, since it works like a SortedDictionary) // __indexes = getIndexes(__array__) AST_VariableDeclaration indexesDeclaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.ARRAY, "__indexes__"); loopBlockStatements.addChild(indexesDeclaration); AST_FunctionCall getArrayIndexes = new AST_FunctionCall(new Token(Token.TokenType.FUNCTION_CALL, "getIndexes")); AST argumentList = new AST(new Token(Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); argumentList.addChild(new Token(Token.TokenType.NAME, "__array__")); getArrayIndexes.addChild(argumentList); AST_Assignment indexesAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__indexes__"); indexesAssignment.addChild(getArrayIndexes); loopBlockStatements.addChild(indexesAssignment); } else { #if WRITE_DEBUG_INFO Console.WriteLine("infinite loop!"); #endif } /* * loopParentTree * __index__-declaration * __array__-declaration & assigment * loop tree * loop body * foreach stuff * rest of statements * goto beginning of loop * * */ allowLineBreak(); AST loopBody = statementList(false); loopBody.addChild(new AST(new Token(Token.TokenType.GOTO_BEGINNING_OF_LOOP, "<GOTO_BEGINNING_OF_LOOP>"))); allowLineBreak(); match(Token.TokenType.BLOCK_END); if(isForeachLoop) { loopBody.addChildFirst(foreachStuff()); } loopTree.addChild(loopBody); loopBlockStatements.addChild(loopTree); AST_LoopBlockNode loopBlock = new AST_LoopBlockNode(new Token(Token.TokenType.LOOP_BLOCK, "<LOOP_BLOCK>")); loopBlock.addChild(loopBlockStatements); return loopBlock; }
private AST ifThenElse() { #if WRITE_DEBUG_INFO Console.WriteLine("if block"); #endif AST ifThenElseTree; AST trueChild; AST falseChild = null; AST expr; try { Token ifToken = match(Token.TokenType.IF); expr = expression(); // child 0 if (expr == null) { throw new Error("The if statement is missing an expression after the 'if'", Error.ErrorType.SYNTAX, ifToken.LineNr, ifToken.LinePosition); } if(lookAheadType(1) == Token.TokenType.NEW_LINE) { match(Token.TokenType.NEW_LINE); } else { throw new Error("Found assignment (=) in if statement. Use == instead?", Error.ErrorType.SYNTAX, ifToken.LineNr, ifToken.LinePosition); } trueChild = statementList(false); // child 1 if ((lookAheadType(1) == Token.TokenType.ELSE) && (lookAheadType(2) == Token.TokenType.IF)) { #if WRITE_DEBUG_INFO Console.WriteLine("if else block"); #endif match(Token.TokenType.ELSE); var ifElseBranch = statement(); // ifThenElse(); // have to put it into a statement list to make scopes work falseChild = new AST(new Token(Token.TokenType.STATEMENT_LIST, "<STATEMENT_LIST>")); if(ifElseBranch != null) { falseChild.addChild(ifElseBranch); } #if WRITE_DEBUG_INFO Console.WriteLine("Popping out from ifElse branch"); #endif } else if (lookAheadType(1) == Token.TokenType.ELSE) { #if WRITE_DEBUG_INFO Console.WriteLine("else block"); #endif match(Token.TokenType.ELSE); if(lookAhead(1).getTokenType() == Token.TokenType.NEW_LINE) { match(Token.TokenType.NEW_LINE); } else { throw new Error("The else statement is missing a line break after it", Error.ErrorType.SYNTAX, ifToken.LineNr, ifToken.LinePosition); } falseChild = statementList(false); // child 2 if(lookAhead(1).getTokenType() == Token.TokenType.BLOCK_END) { match(Token.TokenType.BLOCK_END); } else { throw new Error("The if statement is missing a following 'end'", Error.ErrorType.SYNTAX, ifToken.LineNr, ifToken.LinePosition); } } else { #if WRITE_DEBUG_INFO Console.WriteLine("no else block"); #endif if(lookAhead(1).getTokenType() == Token.TokenType.BLOCK_END) { match(Token.TokenType.BLOCK_END); } else { throw new Error("The if statement is missing a following 'end'", Error.ErrorType.SYNTAX, ifToken.LineNr, ifToken.LinePosition); } } } catch(Error e) { // The error caught here will probably be from the match() function. // Since that means we're missing some part of the if-statement we can give a better // error message by throwing a new one. throw e; // new Error("Something is wrong with the IF-statement", Error.ErrorType.SYNTAX, e.getLineNr(), e.getLinePosition()); } ifThenElseTree = new AST_IfNode(new Token(Token.TokenType.IF, "if", lookAhead(1).LineNr, lookAhead(1).LinePosition)); ifThenElseTree.addChild (expr); ifThenElseTree.addChild(trueChild); if (falseChild != null) { ifThenElseTree.addChild(falseChild); } return ifThenElseTree; }
private AST fromMinToMaxArrayCreation() { #if WRITE_DEBUG_INFO Console.WriteLine("fromMinToMaxArrayCreation"); #endif try { Token fromToken = match(Token.TokenType.FROM); AST minValue = expression(); if(minValue == null) { throw new Error("Missing expression after 'from'", Error.ErrorType.SYNTAX, fromToken.LineNr, fromToken.LinePosition + 5 ); } match(Token.TokenType.TO); AST maxValue = expression(); if(maxValue == null) { throw new Error("Missing expression after 'to'", Error.ErrorType.SYNTAX, fromToken.LineNr, fromToken.LinePosition + 3 ); } AST_FunctionCall callRangeFunction = new AST_FunctionCall(new Token(Token.TokenType.FUNCTION_CALL, "Range")); AST argumentList = new AST(new Token(Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); argumentList.addChild(minValue); argumentList.addChild(maxValue); callRangeFunction.addChild(argumentList); return callRangeFunction; } catch(Error e) { m_errorHandler.errorOccured(e); return null; } }
private AST dotNotationExpression() { #if WRITE_DEBUG_INFO Console.WriteLine("dot notation expression"); #endif AST lhs = parenthesisExpression(); if ( lookAhead(1).getTokenType() == Token.TokenType.DOT) { match (Token.TokenType.DOT); #if WRITE_DEBUG_INFO Console.WriteLine("It's a dot notation expression!!! for example: object.f(a, b)"); #endif Token nameToken = match(Token.TokenType.NAME); AST functionCallTree = new AST_FunctionCall(new Token(Token.TokenType.FUNCTION_CALL, "RemoteFunctionCall", nameToken.LineNr, nameToken.LinePosition)); // These are the argument sent through the remote function call AST innerArgumentList = FunctionArgumentList (); // The call to RemoteFunctionCall always takes three args: <id>, <functionName> & <args> AST argumentList = new AST (new Token (Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); // <ID> argumentList.addChild (lhs); // use whatever is on the left side of the dot in the function (method rather) call (.) //Console.WriteLine ("Method call ID: "); //(new ASTPainter()).PaintAST(lhs); // <FunctionName> Token functionNameToken = new TokenWithValue ( Token.TokenType.QUOTED_STRING, nameToken.getTokenString (), nameToken.LineNr, nameToken.LinePosition, nameToken.getTokenString()); argumentList.addChild (new AST(functionNameToken)); // <args> AST_ArrayEndSignal argsArray = new AST_ArrayEndSignal(new Token(Token.TokenType.ARRAY_END_SIGNAL, "<ARRAY>")); //Console.WriteLine ("Inner args:"); foreach (var child in innerArgumentList.getChildren()) { //Console.WriteLine (child.getTokenString ()); argsArray.addChild (child); } argsArray.ArraySize = innerArgumentList.getChildren().Count; // DAMNIT DON'T FORGET THIS ONE argumentList.addChild (argsArray); // send the arguments as an array to RemoteFunctionCall functionCallTree.addChild(argumentList); return functionCallTree; } else { return lhs; } }
private AST parameter() { #if WRITE_DEBUG_INFO Console.WriteLine("parameter"); #endif AST parameterTree = new AST(new Token(Token.TokenType.PARAMETER, "<PARAMETER>", lookAhead(1).LineNr, lookAhead(1).LinePosition)); AST type = null; if(lookAheadType(1) == Token.TokenType.BUILT_IN_TYPE_NAME) { type = new AST(match(Token.TokenType.BUILT_IN_TYPE_NAME)); } else { type = new AST(new Token(Token.TokenType.BUILT_IN_TYPE_NAME, "var")); } AST name = new AST(match(Token.TokenType.NAME)); AST declaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<PARAMETER_DECLARATION>"), ExternalFunctionCreator.GetReturnTypeFromString(type.getTokenString()), name.getTokenString()); AST assigment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), name.getTokenString()); parameterTree.addChild(declaration); parameterTree.addChild(assigment); return parameterTree; }
private AST negativeExpression() { #if WRITE_DEBUG_INFO Console.WriteLine("negative expression"); #endif match(Token.TokenType.OPERATOR); // the minus sign AST negativeExpressionTree = new AST(new Token(Token.TokenType.OPERATOR, "*")); AST minusSign = new AST(new TokenWithValue(Token.TokenType.NUMBER, "-1", lookAhead(1).LineNr, lookAhead(1).LinePosition, -1.0f)); AST expressionTree = parenthesisExpression(); //operand(); negativeExpressionTree.addChild(minusSign); negativeExpressionTree.addChild(expressionTree); return negativeExpressionTree; }
private AST notStatement() { var notAST = new AST(match(Token.TokenType.NOT)); var expr = expression(); notAST.addChild(expr); return notAST; }
private AST functionCall() { #if WRITE_DEBUG_INFO Console.WriteLine("function call"); #endif Token nameToken = match(Token.TokenType.NAME); AST functionCallTree = new AST_FunctionCall(new Token(Token.TokenType.FUNCTION_CALL, nameToken.getTokenString(), nameToken.LineNr, nameToken.LinePosition)); match(Token.TokenType.PARANTHESIS_LEFT); functionCallTree.getToken().LineNr = nameToken.LineNr; functionCallTree.getToken().LinePosition = nameToken.LinePosition; AST argumentList = new AST(new Token(Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); if (lookAheadType(1) != Token.TokenType.PARANTHESIS_RIGHT) { while (true) { AST expressionTree = expression(); if (expressionTree != null) { argumentList.addChild(expressionTree); // add arguments as subtrees } else { throw new Error("Something is wrong with the argument list", Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); } if (lookAheadType(1) == Token.TokenType.COMMA) { match(Token.TokenType.COMMA); continue; } else { // Is something wrong? if (lookAheadType(1) == Token.TokenType.NEW_LINE || lookAheadType(1) == Token.TokenType.EOF) { throw new Error("Ending parenthesis is missing in function call" , Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); } else if (lookAheadType(1) == Token.TokenType.NAME || lookAheadType(1) == Token.TokenType.QUOTED_STRING || lookAheadType(1) == Token.TokenType.NUMBER) { throw new Error("A comma is missing in argument list" , Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); } break; } } } match(Token.TokenType.PARANTHESIS_RIGHT); functionCallTree.addChild(argumentList); return(functionCallTree); }
private AST loop() { #if WRITE_DEBUG_INFO Console.WriteLine("loop"); #endif AST loopBlockStatements = new AST(new Token(Token.TokenType.STATEMENT_LIST, "<LOOP_BLOCK_STATEMENTS>")); AST_LoopNode loopTree = new AST_LoopNode(match(Token.TokenType.LOOP)); bool isForeachLoop = false; if (lookAheadType(1) != Token.TokenType.NEW_LINE) { #if WRITE_DEBUG_INFO Console.WriteLine("foreach loop!"); #endif isForeachLoop = true; // __index__ AST_VariableDeclaration loopIndexDeclaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.NUMBER, "__index__"); loopBlockStatements.addChild(loopIndexDeclaration); AST_Assignment loopIndexAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__index__"); loopIndexAssignment.addChild(new AST(new TokenWithValue(Token.TokenType.NUMBER, "-1", new ReturnValue(-1.0f)))); loopBlockStatements.addChild(loopIndexAssignment); // match //match(Token.TokenType.PARANTHESIS_LEFT); AST arrayExpression = expression(); //match(Token.TokenType.PARANTHESIS_RIGHT); // __array__ (is a copy of the array to loop over) AST_VariableDeclaration loopArrayDeclaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.ARRAY, "__array__"); loopBlockStatements.addChild(loopArrayDeclaration); AST_Assignment loopArrayAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__array__"); if (arrayExpression != null) { loopArrayAssignment.addChild(arrayExpression); } else { throw new Error("Can't understand array expression in loop", Error.ErrorType.SYNTAX, loopArrayAssignment.getToken().LineNr, loopArrayAssignment.getToken().LinePosition); } loopBlockStatements.addChild(loopArrayAssignment); // __indexes__ (holds all the indexes in the array, since it works like a SortedDictionary) // __indexes = getIndexes(__array__) AST_VariableDeclaration indexesDeclaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.ARRAY, "__indexes__"); loopBlockStatements.addChild(indexesDeclaration); AST_FunctionCall getArrayIndexes = new AST_FunctionCall(new Token(Token.TokenType.FUNCTION_CALL, "getIndexes")); AST argumentList = new AST(new Token(Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); argumentList.addChild(new Token(Token.TokenType.NAME, "__array__")); getArrayIndexes.addChild(argumentList); AST_Assignment indexesAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__indexes__"); indexesAssignment.addChild(getArrayIndexes); loopBlockStatements.addChild(indexesAssignment); } else { #if WRITE_DEBUG_INFO Console.WriteLine("infinite loop!"); #endif } /* * loopParentTree * __index__-declaration * __array__-declaration & assigment * loop tree * loop body * foreach stuff * rest of statements * goto beginning of loop * * */ allowLineBreak(); AST loopBody = statementList(false); loopBody.addChild(new AST(new Token(Token.TokenType.GOTO_BEGINNING_OF_LOOP, "<GOTO_BEGINNING_OF_LOOP>"))); allowLineBreak(); match(Token.TokenType.BLOCK_END); if (isForeachLoop) { loopBody.addChildFirst(foreachStuff()); } loopTree.addChild(loopBody); loopBlockStatements.addChild(loopTree); AST_LoopBlockNode loopBlock = new AST_LoopBlockNode(new Token(Token.TokenType.LOOP_BLOCK, "<LOOP_BLOCK>")); loopBlock.addChild(loopBlockStatements); return(loopBlock); }
private AST comparisonExpression() { #if WRITE_DEBUG_INFO Console.WriteLine("comparison expression"); #endif AST lhs = plusOrMinusExpression(); if ( lookAhead(1).getTokenString() == "<" || lookAhead(1).getTokenString() == ">" || lookAhead(1).getTokenString() == "<=" || lookAhead(1).getTokenString() == ">=" || lookAhead(1).getTokenString() == "!=" || lookAhead(1).getTokenString() == "==" ) { Token operatorToken = match(Token.TokenType.OPERATOR); AST rhs = plusOrMinusExpression(); checkLeftHandSide(lhs, operatorToken); checkRightHandSide(rhs, operatorToken); AST comparisonExpressionTree = new AST(operatorToken); comparisonExpressionTree.addChild(lhs); comparisonExpressionTree.addChild(rhs); return comparisonExpressionTree; } else { return lhs; } }
private AST declarationAndAssignment() { #if WRITE_DEBUG_INFO Console.WriteLine("declaration and assignment"); #endif AST_VariableDeclaration declarationTree = declaration(); Token assignmentToken = match(Token.TokenType.ASSIGNMENT); AST expressionTree = expression(); if(expressionTree != null) { AST_Assignment assignmentTree = new AST_Assignment(assignmentToken, declarationTree.Name); assignmentTree.addChild(expressionTree); AST declarationAndAssignmentTree = new AST(new Token(Token.TokenType.STATEMENT_LIST, "<DECLARATION_AND_ASSIGNMENT>", declarationTree.getToken().LineNr, declarationTree.getToken().LinePosition)); declarationAndAssignmentTree.addChild(declarationTree); declarationAndAssignmentTree.addChild(assignmentTree); return declarationAndAssignmentTree; } else { throw new Error("The expression after = makes no sense", Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); } }
private AST parameterList() { #if WRITE_DEBUG_INFO Console.WriteLine("parameter list"); #endif AST parameterListTree = new AST(new Token(Token.TokenType.NODE_GROUP, "<PARAMETER_LIST>", lookAhead(1).LineNr, lookAhead(1).LinePosition)); if (lookAheadType(1) != Token.TokenType.PARANTHESIS_RIGHT) { while(true) { AST parameterTree = parameter(); parameterListTree.addChild(parameterTree); if (lookAheadType(1) == Token.TokenType.COMMA) { match(Token.TokenType.COMMA); continue; } else { break; } } } return parameterListTree; }
private AST foreachStuff(string pLoopVariableName) { AST statementList = new AST(new Token(Token.TokenType.STATEMENT_LIST, "<FOREACH_STATEMENTS>")); // increase __index__ AST incrementNode = new AST(new Token(Token.TokenType.OPERATOR, "+")); incrementNode.addChild(new AST(new Token(Token.TokenType.NAME, "__index__"))); incrementNode.addChild(new AST(new TokenWithValue(Token.TokenType.NUMBER, "1", 1.0f))); AST_Assignment assignmentNode = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__index__"); assignmentNode.addChild(incrementNode); statementList.addChild(assignmentNode); // if(__index__ >= count(__indexes__)) { break } AST_FunctionCall lengthOfArray = new AST_FunctionCall(new Token(Token.TokenType.FUNCTION_CALL, "Count")); AST argumentList = new AST(new Token(Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); argumentList.addChild(new Token(Token.TokenType.NAME, "__indexes__")); lengthOfArray.addChild(argumentList); AST breakStatement = new AST_IfNode(new Token(Token.TokenType.IF, "IF")); AST operatorTree = new AST(new Token(Token.TokenType.OPERATOR, ">=")); operatorTree.addChild(new Token(Token.TokenType.NAME, "__index__")); operatorTree.addChild(lengthOfArray); breakStatement.addChild(operatorTree); breakStatement.addChild(new Token(Token.TokenType.BREAK, "break")); statementList.addChild(breakStatement); // Loop variable AST_VariableDeclaration declarationTree = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.UNKNOWN_TYPE, pLoopVariableName); statementList.addChild(declarationTree); AST arrayIndexLookup = new AST(new Token(Token.TokenType.ARRAY_LOOKUP, "__indexes__")); arrayIndexLookup.addChild(new AST(new Token(Token.TokenType.NAME, "__index__"))); AST arrayValueLookup = new AST(new Token(Token.TokenType.ARRAY_LOOKUP, "__array__")); arrayValueLookup.addChild(arrayIndexLookup); AST_Assignment assignmentTree = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), pLoopVariableName); assignmentTree.addChild(arrayValueLookup); statementList.addChild(assignmentTree); return statementList; }
private AST parenthesisExpression() { #if WRITE_DEBUG_INFO Console.WriteLine("parenthesis expression"); #endif AST lhs; if (lookAheadType(1) == Token.TokenType.PARANTHESIS_LEFT) { #if WRITE_DEBUG_INFO Console.WriteLine("paranthesis left"); #endif match(Token.TokenType.PARANTHESIS_LEFT); lhs = expression(); #if WRITE_DEBUG_INFO Console.WriteLine("paranthesis right"); #endif match(Token.TokenType.PARANTHESIS_RIGHT); } else { return operand(); } if (lookAheadType(1) == Token.TokenType.OPERATOR) { // two parenthesis expressions with an operator between them Token operatorToken = match(Token.TokenType.OPERATOR); AST rightParenthesisTree = expression(); AST duoParenthesisTree = new AST(operatorToken); duoParenthesisTree.addChild(lhs); duoParenthesisTree.addChild(rightParenthesisTree); return duoParenthesisTree; } else { return lhs; } }
AST FunctionArgumentList() { match (Token.TokenType.PARANTHESIS_LEFT); AST argumentList = new AST (new Token (Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); if (lookAheadType (1) != Token.TokenType.PARANTHESIS_RIGHT) { while (true) { AST expressionTree = expression (); if (expressionTree != null) { argumentList.addChild (expressionTree); // add arguments as subtrees } else { throw new Error ("Something is wrong with the argument list", Error.ErrorType.SYNTAX, lookAhead (1).LineNr, lookAhead (1).LinePosition); } if (lookAheadType (1) == Token.TokenType.COMMA) { match (Token.TokenType.COMMA); continue; } else { // Is something wrong? if (lookAheadType (1) == Token.TokenType.NEW_LINE || lookAheadType (1) == Token.TokenType.EOF) { throw new Error ("Ending parenthesis is missing in function call", Error.ErrorType.SYNTAX, lookAhead (1).LineNr, lookAhead (1).LinePosition); } else if (lookAheadType (1) == Token.TokenType.NAME || lookAheadType (1) == Token.TokenType.QUOTED_STRING || lookAheadType (1) == Token.TokenType.NUMBER) { //throw new Error("A comma is missing in argument list", Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); // allow missing commas in function call continue; } break; } } } match (Token.TokenType.PARANTHESIS_RIGHT); return argumentList; }
private AST plusOrMinusExpression() { #if WRITE_DEBUG_INFO Console.WriteLine("plus or minus expression"); #endif AST lhs = multiplicationExpression(); if ( lookAhead(1).getTokenString() == "+" || lookAhead(1).getTokenString() == "-" ) { Token operatorToken = match(Token.TokenType.OPERATOR); AST rhs = plusOrMinusExpression(); checkLeftHandSide(lhs, operatorToken); checkRightHandSide(rhs, operatorToken); AST plusMinusExpressionTree = new AST(operatorToken); plusMinusExpressionTree.addChild(lhs); plusMinusExpressionTree.addChild(rhs); return plusMinusExpressionTree; } else { return lhs; } }
private AST loop() { #if WRITE_DEBUG_INFO Console.WriteLine("loop"); #endif AST loopBlockStatements = new AST(new Token(Token.TokenType.STATEMENT_LIST, "<LOOP_BLOCK_STATEMENTS>")); AST_LoopNode loopTree = new AST_LoopNode(match(Token.TokenType.LOOP)); string loopVariableName = "@"; // default name if no name is specified directly after 'loop' keyword bool isForeachLoop = false; if(lookAheadType(1) != Token.TokenType.NEW_LINE) { #if WRITE_DEBUG_INFO Console.WriteLine("foreach loop!"); #endif isForeachLoop = true; // __index__ AST_VariableDeclaration loopIndexDeclaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.NUMBER, "__index__"); loopBlockStatements.addChild(loopIndexDeclaration); AST_Assignment loopIndexAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__index__"); loopIndexAssignment.addChild(new AST(new TokenWithValue(Token.TokenType.NUMBER, "-1", -1.0f))); loopBlockStatements.addChild(loopIndexAssignment); Token savePoint = lookAhead(1); // will backtrack from here if matching loopVariable + loopRangeExpression fails //Console.WriteLine("Created save point at token " + savePoint); Token loopVariable = null; AST loopRangeExpression = null; // what the loop will loop through if ((lookAheadType (1) == Token.TokenType.NAME && lookAheadType(2) == Token.TokenType.IN) || (lookAheadType (1) == Token.TokenType.NAME && lookAheadType(2) == Token.TokenType.FROM)) { loopVariable = match (Token.TokenType.NAME); if(lookAheadType(1) == Token.TokenType.IN) { match (Token.TokenType.IN); } else if(lookAheadType(1) == Token.TokenType.FROM) { // proceed } try { //Console.WriteLine ("Found a potential loop variable " + loopVariable.getTokenString() + ", trying to match loop range expression with a loop variable"); loopRangeExpression = expression(); if(loopRangeExpression == null) { //Console.WriteLine ("null! Failed to match statement after loop variable, will backtrack and assume this loop does not use a loop variable"); backtrackToToken (savePoint); } else { loopVariableName = loopVariable.getTokenString(); //Console.WriteLine("Success, loop variable is called: " + loopVariableName); } } catch(Error e) { //Console.WriteLine ("Failed to match statement after loop variable, will backtrack and assume this loop does not use a loop variable"); backtrackToToken (savePoint); } } if (loopRangeExpression == null) { //Console.WriteLine ("There is no loop variable, trying to match a bare loop range expression"); loopRangeExpression = expression(); } if (loopRangeExpression == null) { throw new Error ("Failed to match the expression after 'loop'", Error.ErrorType.SYNTAX, loopTree.getToken ().LineNr, loopTree.getToken ().LinePosition); } //Console.WriteLine ("Loop range/array expression: "); //(new ASTPainter ()).PaintAST (loopRangeExpression); // __array__ (is a copy of the array to loop over) AST_VariableDeclaration loopArrayDeclaration = new AST_VariableDeclaration( new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.UNKNOWN_TYPE, "__array__"); loopBlockStatements.addChild(loopArrayDeclaration); AST_Assignment loopArrayAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__array__"); if(loopRangeExpression != null) { loopArrayAssignment.addChild(loopRangeExpression); } else { throw new Error("Can't understand array expression in loop", Error.ErrorType.SYNTAX, loopArrayAssignment.getToken().LineNr, loopArrayAssignment.getToken().LinePosition); } loopBlockStatements.addChild(loopArrayAssignment); // __indexes__ (holds all the indexes in the array, since it works like a SortedDictionary) // __indexes = getIndexes(__array__) AST_VariableDeclaration indexesDeclaration = new AST_VariableDeclaration( new Token(Token.TokenType.VAR_DECLARATION, "<VAR_DECL>"), ReturnValueType.UNKNOWN_TYPE, "__indexes__"); loopBlockStatements.addChild(indexesDeclaration); AST_FunctionCall getArrayIndexes = new AST_FunctionCall(new Token(Token.TokenType.FUNCTION_CALL, "GetIndexes")); AST argumentList = new AST(new Token(Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); argumentList.addChild(new Token(Token.TokenType.NAME, "__array__")); getArrayIndexes.addChild(argumentList); AST_Assignment indexesAssignment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), "__indexes__"); indexesAssignment.addChild(getArrayIndexes); loopBlockStatements.addChild(indexesAssignment); } else { #if WRITE_DEBUG_INFO Console.WriteLine("infinite loop!"); #endif } /* * loopParentTree * __index__-declaration * __array__-declaration & assigment * loop tree * loop body * foreach stuff * rest of statements * goto beginning of loop * * */ allowLineBreak(); AST loopBody = statementList(false); loopBody.addChild(new AST(new Token(Token.TokenType.GOTO_BEGINNING_OF_LOOP, "<GOTO_BEGINNING_OF_LOOP>"))); allowLineBreak(); match(Token.TokenType.BLOCK_END); if(isForeachLoop) { loopBody.addChildFirst(foreachStuff(loopVariableName)); } loopTree.addChild(loopBody); loopBlockStatements.addChild(loopTree); AST_LoopBlockNode loopBlock = new AST_LoopBlockNode(new Token(Token.TokenType.LOOP_BLOCK, "<LOOP_BLOCK>")); loopBlock.addChild(loopBlockStatements); return loopBlock; }
private AST returnFromFunction() { #if WRITE_DEBUG_INFO Console.WriteLine("return from function"); #endif AST returnTree = new AST(match(Token.TokenType.RETURN)); AST returnExpression = expression(); if(returnExpression != null) { returnTree.addChild(returnExpression); } //else { // throw new Error("No expression in return statement", Error.ErrorType.SYNTAX, // lookAhead(1).LineNr, lookAhead(1).LinePosition); //} return returnTree; }
void AddLocalVariables(AST ast, VariableDefinition[] variableDefinitions) { AST nodeForDefiningGlobalVariables = ast.getChild(0).getChild(0); if(variableDefinitions == null) { return; } foreach(VariableDefinition vd in variableDefinitions) { Token token = new Token(Token.TokenType.VAR_DECLARATION,"<VAR_DECL>", ast.getToken().LineNr, ast.getToken().LinePosition); AST_VariableDeclaration declarationTree = new AST_VariableDeclaration(token, vd.initValue.getReturnValueType(), vd.variableName); if(vd.initValue != null) { AST assignmentTree = CreateAssignmentTreeFromInitValue(vd.variableName, vd.initValue); AST declarationAndAssignmentTree = new AST(new Token(Token.TokenType.STATEMENT_LIST, "<DECLARATION_AND_ASSIGNMENT>", declarationTree.getToken().LineNr, declarationTree.getToken().LinePosition)); declarationAndAssignmentTree.addChild(declarationTree); declarationAndAssignmentTree.addChild(assignmentTree); nodeForDefiningGlobalVariables.addChild(declarationAndAssignmentTree); } else { nodeForDefiningGlobalVariables.addChild(declarationTree); } } }
private AST statementList(bool isInMainScope) { #if WRITE_DEBUG_INFO Console.WriteLine("statement list"); #endif AST statementListTree = new AST(new Token(Token.TokenType.STATEMENT_LIST, "<STATEMENT_LIST>")); while (lookAheadType(1) != Token.TokenType.EOF && lookAheadType(1) != Token.TokenType.ELSE) { if(lookAheadType(1) == Token.TokenType.BLOCK_END) { if(isInMainScope) { m_errorHandler.errorOccured("Found the word 'end' where it makes no sense", Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); } break; } AST statementTree = statement(); if(statementTree != null) { statementListTree.addChild(statementTree); } else { #if WRITE_DEBUG_INFO Console.WriteLine("null statement"); #endif } } return statementListTree; }
private AST arrayLookup() { AST arrayName = new AST(match(Token.TokenType.NAME)); AST arrayLookupNode = new AST(new Token(Token.TokenType.ARRAY_LOOKUP, arrayName.getTokenString())); match(Token.TokenType.BRACKET_LEFT); AST arrayIndex = expression(); match(Token.TokenType.BRACKET_RIGHT); arrayLookupNode.addChild(arrayIndex); return arrayLookupNode; }
private AST functionCall() { #if WRITE_DEBUG_INFO Console.WriteLine("function call"); #endif Token nameToken = match(Token.TokenType.NAME); AST functionCallTree = new AST_FunctionCall(new Token(Token.TokenType.FUNCTION_CALL, nameToken.getTokenString(), nameToken.LineNr, nameToken.LinePosition)); match(Token.TokenType.PARANTHESIS_LEFT); functionCallTree.getToken().LineNr = nameToken.LineNr; functionCallTree.getToken().LinePosition = nameToken.LinePosition; AST argumentList = new AST(new Token(Token.TokenType.NODE_GROUP, "<ARGUMENT_LIST>")); if (lookAheadType(1) != Token.TokenType.PARANTHESIS_RIGHT) { while(true) { AST expressionTree = expression(); if(expressionTree != null) { argumentList.addChild(expressionTree); // add arguments as subtrees } else { throw new Error("Something is wrong with the argument list", Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); } if (lookAheadType(1) == Token.TokenType.COMMA) { match(Token.TokenType.COMMA); continue; } else { // Is something wrong? if( lookAheadType(1) == Token.TokenType.NEW_LINE || lookAheadType(1) == Token.TokenType.EOF ) { throw new Error("Ending parenthesis is missing in function call" , Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); } else if( lookAheadType(1) == Token.TokenType.NAME || lookAheadType(1) == Token.TokenType.QUOTED_STRING || lookAheadType(1) == Token.TokenType.NUMBER ) { throw new Error("A comma is missing in argument list" , Error.ErrorType.SYNTAX, lookAhead(1).LineNr, lookAhead(1).LinePosition); } break; } } } match(Token.TokenType.PARANTHESIS_RIGHT); functionCallTree.addChild(argumentList); return functionCallTree; }