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;
}