Ejemplo n.º 1
0
        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);
        }