public SyntaxNode SyntaxBlock(SyntaxNode node, int token_count, IdentifierNode scope) { if (node.children == null) { node.children = new List <SyntaxNode>(); } node.scope = scope; while (syntax_index < token_count) { //Logger.WriteLogLine("w" + tokenLineNumbers[syntax_index] + ", " + syntax_index + ": " + tokens[syntax_index] + " " + node.value + " " + node.type); bool bReturnAfterAdding = false; SyntaxNode child = new SyntaxNode(); child.tokenindex = syntax_index; ChildSyntaxPlacement placement = ChildSyntaxPlacement.Normal; if (tokenTypes[syntax_index] == TokenType.Name) { // can be type if (CompilerConstants.Types.Contains(tokens[syntax_index])) { if (node.type == SyntaxType.BaseDeclaration || node.type == SyntaxType.ArgDeclaration || node.type == SyntaxType.FuncDeclaration || node.type == SyntaxType.VarDeclaration) { child.type = SyntaxType.Type; child.value = CompilerConstants.Types.ToList().IndexOf(tokens[syntax_index]); // FIXME THIS IS SLOW } else { if (node.type == SyntaxType.Root) { child.type = SyntaxType.BaseDeclaration; } else if (node.type == SyntaxType.ParensBlock) { child.type = SyntaxType.ArgDeclaration; } else { // no func declarations outside of root scope child.type = SyntaxType.VarDeclaration; } child = SyntaxBlock(child, token_count, scope); } } else if (CompilerConstants.FlowControl.Contains(tokens[syntax_index])) { child.type = SyntaxType.FlowControl; child.value = CompilerConstants.FlowControl.ToList().IndexOf(tokens[syntax_index]); // FIXME THIS IS SLOW if (node.type == SyntaxType.BaseDeclaration || node.type == SyntaxType.VarDeclaration || node.type == SyntaxType.FuncDeclaration || node.type == SyntaxType.ArgDeclaration) { SyntaxError("error in declaration, reserved flow control keyword `" + tokens[syntax_index] + "` can't be used in declaration"); } syntax_index++; child = SyntaxBlock(child, token_count, scope.AddNewChild(syntax_index - 1)); } else { if (node.type == SyntaxType.BaseDeclaration || node.type == SyntaxType.VarDeclaration || node.type == SyntaxType.FuncDeclaration || node.type == SyntaxType.ArgDeclaration) { if (scope.IsInScope(tokens[syntax_index])) { SyntaxError("Identifier `" + tokens[syntax_index] + "` already declared in this scope, can't redeclare/shadow!"); } else { child.type = SyntaxType.Identifier; scope.identifierDict.Add(tokens[syntax_index], 0); } } else if (node.type == SyntaxType.Block) { child.type = SyntaxType.Statement; child = SyntaxBlock(child, token_count, scope); } else { child.type = SyntaxType.Identifier; } } } // name else if (tokenTypes[syntax_index] == TokenType.Symbol) { switch (tokens[syntax_index]) { case "*": case "+": case "-": case "/": case "%": case "<": case ">": case "==": case "<=": case ">=": if (node.type == SyntaxType.BaseDeclaration || node.type == SyntaxType.VarDeclaration || node.type == SyntaxType.FuncDeclaration || node.type == SyntaxType.ArgDeclaration) { SyntaxError("unexpected binary operator `" + tokens[syntax_index] + "` in declaration"); } else if (node.type == SyntaxType.Block) { SyntaxError("unexpected binary operator `" + tokens[syntax_index] + "` without statement (you probably don't have anything it goes with ?)"); } child.type = SyntaxType.BinaryOperator; child.operator_precedence = CompilerConstants.OperatorPrecedence[tokens[syntax_index]]; /* * if (node.type == SyntaxType.RightHandSide && child.operator_precedence < node.operator_precedence) * { * return node; * } * * placement = ChildSyntaxPlacement.BinaryOperatorPlacement; */ break; case ",": if (node.type == SyntaxType.BaseDeclaration || node.type == SyntaxType.VarDeclaration || node.type == SyntaxType.FuncDeclaration) { SyntaxError("unexpected separator `" + tokens[syntax_index] + "` in declaration"); } // FIXME || node.type == SyntaxType.ArgDeclaration child.type = SyntaxType.Comma; break; case ";": if (node.type == SyntaxType.FuncDeclaration || node.type == SyntaxType.ArgDeclaration) { SyntaxError("unexpected `;` ender in function declaration"); } else if (node.type == SyntaxType.Assignment) { return(node); } else if (node.type == SyntaxType.BaseDeclaration || node.type == SyntaxType.VarDeclaration || node.type == SyntaxType.Statement) //|| node.type == SyntaxType.RightHandSide) { if (node.type == SyntaxType.BaseDeclaration) { node.type = SyntaxType.VarDeclaration; } //syntax_index++; return(node); } child.type = SyntaxType.Semicolon; break; case "=": if (node.type == SyntaxType.Assignment) { SyntaxError("multiple `=` assignments unsupported"); } else if (node.type == SyntaxType.FuncDeclaration || node.type == SyntaxType.ArgDeclaration) // TODO - support default arguments { SyntaxError("unexpected assignment `=` in function declaration"); } else if (node.type == SyntaxType.BaseDeclaration) { node.type = SyntaxType.VarDeclaration; } child.type = SyntaxType.Assignment; syntax_index++; child = SyntaxBlock(child, token_count, scope); if (node.type == SyntaxType.VarDeclaration || node.type == SyntaxType.Statement) { node.children.Add(child); return(node); } break; case "{": if (node.type == SyntaxType.VarDeclaration || node.type == SyntaxType.Assignment || node.type == SyntaxType.ArgDeclaration || node.type == SyntaxType.Statement) { SyntaxError("unexpected `{` in declaration/assignment/statement (did you forget a `;`?)"); } if (node.type == SyntaxType.BaseDeclaration) { node.type = SyntaxType.FuncDeclaration; } child.type = SyntaxType.Block; /*if (node.children.Count != 0 * && node.children[node.children.Count-1].type == SyntaxType.Statement)*/ /* * if(node.type == SyntaxType.FlowControl || node.type == SyntaxType.FuncDeclaration) ||{ ||placement = ChildSyntaxPlacement.ChildOfPrevious; ||} */ syntax_index++; child = SyntaxBlock(child, token_count, scope.AddNewChild(syntax_index - 1)); if (node.type == SyntaxType.FlowControl || node.type == SyntaxType.FuncDeclaration) { bReturnAfterAdding = true; } break; case "(": if (node.type == SyntaxType.ArgDeclaration) { SyntaxError("unexpected `(` in function argument declaration"); } else if (node.type == SyntaxType.BaseDeclaration) { node.type = SyntaxType.FuncDeclaration; } child.type = SyntaxType.ParensBlock; placement = ChildSyntaxPlacement.ChildOfPrevious; syntax_index++; child = SyntaxBlock(child, token_count, scope); break; case "[": child.type = SyntaxType.SquareBlock; placement = ChildSyntaxPlacement.ChildOfPrevious; syntax_index++; child = SyntaxBlock(child, token_count, scope); break; case "}": // end block if (node.type != SyntaxType.Block) { if (node.type == SyntaxType.ParensBlock) { SyntaxError("couldn't find matching closed ')' for open '(' due to unexpected '}' "); } else if (node.type == SyntaxType.SquareBlock) { SyntaxError("couldn't find matching closed ']' for open '[' due to unexpected '}' "); } else if (node.type == SyntaxType.BaseDeclaration || node.type == SyntaxType.VarDeclaration || node.type == SyntaxType.FuncDeclaration || node.type == SyntaxType.ArgDeclaration || node.type == SyntaxType.Assignment) { SyntaxError("unexpected `}` in declaration or assignment (did you forget a `;` maybe?)"); } else { SyntaxError("unexpected closing '}' with no matching '{'"); } } return(node); case ")": // end parensblock if (node.type != SyntaxType.ParensBlock) //&& node.type != SyntaxType.RightHandSide) { if (node.type == SyntaxType.Block) { SyntaxError("couldn't find matching closed '}' for open '{' due to unexpected ')' "); } else if (node.type == SyntaxType.SquareBlock) { SyntaxError("couldn't find matching closed ']' for open '[' due to unexpected ')' "); } else { SyntaxError("unexpected closing ')' with no matching '('"); } } return(node); case "]": // end squareblock if (node.type != SyntaxType.SquareBlock) { if (node.type == SyntaxType.Block) { SyntaxError("couldn't find matching closed '}' for open '{' due to unexpected ']' "); } else if (node.type == SyntaxType.ParensBlock) { SyntaxError("couldn't find matching closed ')' for open '(' due to unexpected ']' "); } else { SyntaxError("unexpected closing ']' with no matching '['"); } } return(node); default: // TODO - might be error? child.type = SyntaxType.Symbol; break; } } // symbol else if (tokenTypes[syntax_index] == TokenType.IntLiteral) { // FIXME error in wrong contexts child.type = SyntaxType.IntLiteral; if (!int.TryParse(tokens[syntax_index], NumberStyles.Integer, CultureInfo.InvariantCulture, out child.value)) { SyntaxError("failure to parse integer!"); } } else if (tokenTypes[syntax_index] == TokenType.HexLiteral) { // FIXME error in wrong contexts child.type = SyntaxType.IntLiteral; if (!int.TryParse(tokens[syntax_index], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out child.value)) { SyntaxError("failure to parse hex integer!"); } } else if (tokenTypes[syntax_index] == TokenType.FloatLiteral) { // FIXME error in wrong contexts child.type = SyntaxType.FloatLiteral; if (!float.TryParse(tokens[syntax_index], NumberStyles.Number, CultureInfo.InvariantCulture, out child.floatvalue)) { SyntaxError("failure to parse float!"); } } else if (tokenTypes[syntax_index] == TokenType.StringLiteral) { // FIXME error in wrong contexts child.type = SyntaxType.StringLiteral; child.value = vm.StringToTableIndex(tokens[syntax_index]); //return node; } // string if (child.scope == null) { child.scope = scope; } switch (placement) { case ChildSyntaxPlacement.ChildOfPrevious: if (node.children.Count == 0) { node.children.Add(child); } else { SyntaxNode prev = node.children[node.children.Count - 1]; if (prev.children == null) { prev.children = new List <SyntaxNode>(); } prev.children.Add(child); node.children[node.children.Count - 1] = prev; } break; /* * case ChildSyntaxPlacement.BinaryOperatorPlacement: * { * if (node.children.Count <= 0) * { * SyntaxError("binary operator `" + tokens[syntax_index] + "` with no lefthand side!"); * } * SyntaxNode lhs = new SyntaxNode(); * lhs.children = node.children; * lhs.tokenindex = node.children[0].tokenindex; * lhs.type = SyntaxType.LeftHandSide; * lhs.operator_precedence = child.operator_precedence; * child.children = new List<SyntaxNode>(); * * SyntaxNode rhs = new SyntaxNode(); * rhs.type = SyntaxType.RightHandSide; * * syntax_index++; * rhs.tokenindex = syntax_index; * rhs.operator_precedence = child.operator_precedence; * rhs = SyntaxBlock(rhs, token_count, scope); * * child.children.Add(lhs); * child.children.Add(rhs); * * node.children = new List<SyntaxNode>(); * node.children.Add(child); * return node; * } */ //break; case ChildSyntaxPlacement.Normal: default: node.children.Add(child); break; } // switch placement if (bReturnAfterAdding) { return(node); } syntax_index++; } // while if (node.type == SyntaxType.Block) { SyntaxError("couldn't find matching close '}' for open '{' due to unexpected EOF ", true, node.tokenindex); } else if (node.type == SyntaxType.ParensBlock) { SyntaxError("couldn't find matching close ')' for open '(' due to unexpected EOF ", true, node.tokenindex); } else if (node.type == SyntaxType.SquareBlock) { SyntaxError("couldn't find matching close ']' for open '[' due to unexpected EOF ", true, node.tokenindex); } return(node); }