예제 #1
0
        public static bool CheckForPreprocessorNode(Genero4glParser parser, AstNode4gl node)
        {
            PreprocessorNode preNode;

            if (PreprocessorNode.TryParseNode(parser, out preNode) && node != null)
            {
                // TODO: determine context of the preprocessor via containingNode
                if (preNode.Type == PreprocessorType.Include && !string.IsNullOrWhiteSpace(preNode.IncludeFile))
                {
                    if (node.IncludeFiles.ContainsKey(preNode.IncludeFile))
                    {
                        node.IncludeFiles[preNode.IncludeFile].Add(preNode);
                    }
                    else
                    {
                        node.IncludeFiles.Add(preNode.IncludeFile, new List <PreprocessorNode>()
                        {
                            preNode
                        });
                    }
                }
                return(true);
            }
            return(false);
        }
예제 #2
0
        public static bool TryParseNode(Genero4glParser parser, out OtherwiseStatement node,
                                        IModuleResult containingModule,
                                        List <Func <PrepareStatement, bool> > prepStatementBinders,
                                        Func <ReturnStatement, ParserResult> returnStatementBinder   = null,
                                        Action <IAnalysisResult, int, int> limitedScopeVariableAdder = null,
                                        List <TokenKind> validExitKeywords = null,
                                        IEnumerable <ContextStatementFactory> contextStatementFactories = null,
                                        ExpressionParsingOptions expressionOptions = null,
                                        HashSet <TokenKind> endKeywords            = null)
        {
            node = null;
            bool result = false;

            if (parser.PeekToken(TokenKind.OtherwiseKeyword))
            {
                result = true;
                node   = new OtherwiseStatement();
                parser.NextToken();
                node.StartIndex   = parser.Token.Span.Start;
                node.DecoratorEnd = parser.Token.Span.End;
                prepStatementBinders.Insert(0, node.BindPrepareCursorFromIdentifier);
                while (!parser.PeekToken(TokenKind.EndOfFile) &&
                       !parser.PeekToken(TokenKind.WhenKeyword) &&
                       !parser.PeekToken(TokenKind.OtherwiseKeyword) &&
                       !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.CaseKeyword, 2)))
                {
                    FglStatement statement;
                    if (parser.StatementFactory.TryParseNode(parser, out statement, containingModule, prepStatementBinders, returnStatementBinder,
                                                             limitedScopeVariableAdder, false, validExitKeywords, contextStatementFactories, expressionOptions) &&
                        statement != null)
                    {
                        AstNode4gl stmtNode = statement as AstNode4gl;
                        node.Children.Add(stmtNode.StartIndex, stmtNode);

                        if (statement is ExitStatement &&
                            (statement as ExitStatement).ExitType != TokenKind.CaseKeyword)
                        {
                            if (validExitKeywords != null && !validExitKeywords.Contains((statement as ExitStatement).ExitType))
                            {
                                parser.ReportSyntaxError("Invalid exit statement for case statement block detected.");
                            }
                        }
                    }
                    else if (parser.PeekToken(TokenKind.EndKeyword) && endKeywords != null && endKeywords.Contains(parser.PeekToken(2).Kind))
                    {
                        break;
                    }
                    else
                    {
                        parser.NextToken();
                    }
                }
                prepStatementBinders.RemoveAt(0);

                node.EndIndex = parser.Token.Span.End;
            }

            return(result);
        }
예제 #3
0
        public FunctionBlockNode GetContainingFunction(int index, bool returnNextIfOutside)
        {
            AstNode4gl containingNode = null;
            List <int> keys           = null;
            int        searchIndex    = -1;
            int        key            = -1;

            if (_body.Children.Count > 0)
            {
                // do a binary search to determine what node we're in
                keys        = _body.Children.Select(x => x.Key).ToList();
                searchIndex = keys.BinarySearch(index);
                if (searchIndex < 0)
                {
                    searchIndex = ~searchIndex;
                    if (searchIndex > 0)
                    {
                        searchIndex--;
                    }
                }

                key = keys[searchIndex];

                // TODO: need to handle multiple results of the same name
                containingNode = Body.Children[key] as AstNode4gl;

                if (returnNextIfOutside && containingNode != null && containingNode.EndIndex < index)
                {
                    // need to go to the next function
                    searchIndex++;
                    if (keys.Count > searchIndex)
                    {
                        key            = keys[searchIndex];
                        containingNode = Body.Children[key] as AstNode4gl;
                    }
                    else
                    {
                        containingNode = null;
                    }
                }
            }

            if (containingNode != null &&
                containingNode is FunctionBlockNode)
            {
                return(containingNode as FunctionBlockNode);
            }
            return(null);
        }
예제 #4
0
        public Genero4glAst(AstNode4gl body, int[] lineLocations, GeneroLanguageVersion langVersion = GeneroLanguageVersion.None, IProjectEntry projEntry = null, string filename = null)
            : base(body, lineLocations, langVersion, projEntry, filename)
        {
            InitializeBuiltins();
            InitializeImportedPackages();   // for this instance
            InitializePackages();

            if (body is ModuleNode)
            {
                foreach (var import in (body as ModuleNode).CExtensionImports)
                {
                    if (_importedPackages.ContainsKey(import))
                    {
                        _importedPackages[import] = true;
                    }
                }
            }
        }
예제 #5
0
        public static bool TryParseNode(Genero4glParser parser, out IfBlockContentsNode node,
                                        IModuleResult containingModule,
                                        List <Func <PrepareStatement, bool> > prepStatementBinders,
                                        Func <ReturnStatement, ParserResult> returnStatementBinder   = null,
                                        Action <IAnalysisResult, int, int> limitedScopeVariableAdder = null,
                                        List <TokenKind> validExitKeywords = null,
                                        IEnumerable <ContextStatementFactory> contextStatementFactories = null,
                                        ExpressionParsingOptions expressionOptions = null,
                                        HashSet <TokenKind> endKeywords            = null)
        {
            node            = new IfBlockContentsNode();
            node.StartIndex = parser.Token.Span.Start;
            prepStatementBinders.Insert(0, node.BindPrepareCursorFromIdentifier);
            while (!parser.PeekToken(TokenKind.EndOfFile) &&
                   !parser.PeekToken(TokenKind.ElseKeyword) &&
                   !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.IfKeyword, 2)))
            {
                FglStatement statement;
                if (parser.StatementFactory.TryParseNode(parser, out statement, containingModule, prepStatementBinders,
                                                         returnStatementBinder, limitedScopeVariableAdder, false, validExitKeywords,
                                                         contextStatementFactories, expressionOptions, endKeywords))
                {
                    AstNode4gl stmtNode = statement as AstNode4gl;
                    if (stmtNode != null && !node.Children.ContainsKey(stmtNode.StartIndex))
                    {
                        node.Children.Add(stmtNode.StartIndex, stmtNode);
                    }
                }
                else if (parser.PeekToken(TokenKind.EndKeyword) && endKeywords != null && endKeywords.Contains(parser.PeekToken(2).Kind))
                {
                    break;
                }
                else
                {
                    parser.NextToken();
                }
            }
            prepStatementBinders.RemoveAt(0);
            node.EndIndex = parser.Token.Span.End;

            return(true);
        }
예제 #6
0
        public static bool TryParseNode(Genero4glParser parser, out ForeachStatement node,
                                        IModuleResult containingModule,
                                        List <Func <PrepareStatement, bool> > prepStatementBinders,
                                        Func <ReturnStatement, ParserResult> returnStatementBinder   = null,
                                        Action <IAnalysisResult, int, int> limitedScopeVariableAdder = null,
                                        List <TokenKind> validExitKeywords = null,
                                        IEnumerable <ContextStatementFactory> contextStatementFactories = null,
                                        HashSet <TokenKind> endKeywords = null)
        {
            node = null;
            bool result = false;

            if (parser.PeekToken(TokenKind.ForeachKeyword))
            {
                result = true;
                node   = new ForeachStatement();
                parser.NextToken();
                node.StartIndex = parser.Token.Span.Start;
                node.InputVars  = new List <FglNameExpression>();
                node.OutputVars = new List <FglNameExpression>();

                FglNameExpression cid;
                if (FglNameExpression.TryParseNode(parser, out cid))
                {
                    node.CursorId = cid;
                }
                else
                {
                    parser.ReportSyntaxError("Invalid declared cursor id found in foreach statement.");
                }

                HashSet <TokenKind> inVarMods = new HashSet <TokenKind> {
                    TokenKind.InKeyword, TokenKind.OutKeyword, TokenKind.InOutKeyword
                };
                if (parser.PeekToken(TokenKind.UsingKeyword))
                {
                    parser.NextToken();
                    FglNameExpression inVar;
                    while (FglNameExpression.TryParseNode(parser, out inVar, TokenKind.Comma))
                    {
                        node.InputVars.Add(inVar);
                        if (inVarMods.Contains(parser.PeekToken().Kind))
                        {
                            parser.NextToken();
                        }
                        if (parser.PeekToken(TokenKind.Comma))
                        {
                            parser.NextToken();
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                if (parser.PeekToken(TokenKind.IntoKeyword))
                {
                    parser.NextToken();
                    FglNameExpression outVar;
                    while (FglNameExpression.TryParseNode(parser, out outVar, TokenKind.Comma))
                    {
                        node.InputVars.Add(outVar);
                        if (parser.PeekToken(TokenKind.Comma))
                        {
                            parser.NextToken();
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                node.DecoratorEnd = parser.Token.Span.End;

                if (parser.PeekToken(TokenKind.WithKeyword))
                {
                    parser.NextToken();
                    if (parser.PeekToken(TokenKind.ReoptimizationKeyword))
                    {
                        parser.NextToken();
                    }
                    else
                    {
                        parser.ReportSyntaxError("Expecting keyword \"reoptimization\" in open statement.");
                    }
                }

                List <TokenKind> validExits = new List <TokenKind>();
                if (validExitKeywords != null)
                {
                    validExits.AddRange(validExitKeywords);
                }
                validExits.Add(TokenKind.ForeachKeyword);

                HashSet <TokenKind> newEndKeywords = new HashSet <TokenKind>();
                if (endKeywords != null)
                {
                    newEndKeywords.AddRange(endKeywords);
                }
                newEndKeywords.Add(TokenKind.ForeachKeyword);

                prepStatementBinders.Insert(0, node.BindPrepareCursorFromIdentifier);
                while (!parser.PeekToken(TokenKind.EndOfFile) &&
                       !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.ForeachKeyword, 2)))
                {
                    FglStatement statement;
                    if (parser.StatementFactory.TryParseNode(parser, out statement, containingModule, prepStatementBinders,
                                                             returnStatementBinder, limitedScopeVariableAdder, false, validExits,
                                                             contextStatementFactories, null, newEndKeywords) && statement != null)
                    {
                        AstNode4gl stmtNode = statement as AstNode4gl;
                        node.Children.Add(stmtNode.StartIndex, stmtNode);

                        if (statement is ExitStatement &&
                            (statement as ExitStatement).ExitType != TokenKind.ForeachKeyword)
                        {
                            if (validExitKeywords == null || !validExitKeywords.Contains((statement as ExitStatement).ExitType))
                            {
                                parser.ReportSyntaxError("Invalid exit statement for for loop detected.");
                            }
                        }

                        if (statement is ContinueStatement &&
                            (statement as ContinueStatement).ContinueType != TokenKind.ForeachKeyword)
                        {
                            if (validExitKeywords == null || !validExitKeywords.Contains((statement as ContinueStatement).ContinueType))
                            {
                                parser.ReportSyntaxError("Invalid continue statement for for loop detected.");
                            }
                        }
                    }
                    else if (parser.PeekToken(TokenKind.EndKeyword) && endKeywords != null && endKeywords.Contains(parser.PeekToken(2).Kind))
                    {
                        break;
                    }
                    else
                    {
                        parser.NextToken();
                    }
                }
                prepStatementBinders.RemoveAt(0);

                if (!(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.ForeachKeyword, 2)))
                {
                    parser.ReportSyntaxError("A foreach statement must be terminated with \"end foreach\".");
                }
                else
                {
                    parser.NextToken(); // advance to the 'end' token
                    parser.NextToken(); // advance to the 'foreach' token
                    node.EndIndex = parser.Token.Span.End;
                }
            }

            return(result);
        }
예제 #7
0
        public static bool TryParseNode(Genero4glParser parser, out FunctionBlockNode defNode, out int bufferPosition,
                                        IModuleResult containingModule, bool abbreviatedParse = false, bool advanceOnEnd = true)
        {
            bufferPosition = 0;
            defNode        = null;
            bool           result      = false;
            AccessModifier?accMod      = null;
            string         accModToken = null;

            if (parser.PeekToken(TokenKind.PublicKeyword))
            {
                accMod      = AccessModifier.Public;
                accModToken = parser.PeekToken().Value.ToString();
            }
            else if (parser.PeekToken(TokenKind.PrivateKeyword))
            {
                accMod      = AccessModifier.Private;
                accModToken = parser.PeekToken().Value.ToString();
            }

            uint lookAheadBy = (uint)(accMod.HasValue ? 2 : 1);

            if (parser.PeekToken(TokenKind.FunctionKeyword, lookAheadBy))
            {
                result  = true;
                defNode = new FunctionBlockNode();
                if (accMod.HasValue)
                {
                    parser.NextToken();
                    defNode.AccessModifier = accMod.Value;
                    defNode.StartIndex     = parser.Token.Span.Start;
                }
                else
                {
                    defNode.AccessModifier = AccessModifier.Public;
                }

                parser.NextToken(); // move past the Function keyword
                if (!accMod.HasValue)
                {
                    defNode.StartIndex = parser.Token.Span.Start;
                }

                // get the name
                if (parser.PeekToken(TokenCategory.Keyword) || parser.PeekToken(TokenCategory.Identifier))
                {
                    parser.NextToken();
                    defNode.Name          = parser.Token.Token.Value.ToString();
                    defNode.LocationIndex = parser.Token.Span.Start;
                    defNode.DecoratorEnd  = parser.Token.Span.End;
                }
                else
                {
                    parser.ReportSyntaxError("A function must have a name.");
                }

                if (!parser.PeekToken(TokenKind.LeftParenthesis))
                {
                    parser.ReportSyntaxError("A function must specify zero or more parameters in the form: ([param1][,...])");
                }
                else
                {
                    parser.NextToken();
                }

                bool paramsParsed = false;
                if (parser.LanguageVersion >= GeneroLanguageVersion.V310)
                {
                    while (parser.PeekToken(TokenCategory.Keyword) || parser.PeekToken(TokenCategory.Identifier))
                    {
                        var    paramName = parser.PeekTokenWithSpan();
                        string errMsg;
                        if (!defNode.AddArgument(paramName, out errMsg))
                        {
                            parser.ReportSyntaxError(errMsg);
                        }
                        // try parsing the parameters as variable definitions
                        VariableDefinitionNode varDefNode = null;
                        if (VariableDefinitionNode.TryParseNode(parser, out varDefNode, defNode.BindArgument, false, false))
                        {
                            defNode.Children.Add(varDefNode.StartIndex, varDefNode);
                            foreach (var vardef in varDefNode.VariableDefinitions)
                            {
                                vardef.Scope = "local variable";
                                if (!defNode.Variables.ContainsKey(vardef.Name))
                                {
                                    defNode.Variables.Add(vardef.Name, vardef);
                                }
                                else
                                {
                                    parser.ReportSyntaxError(vardef.LocationIndex, vardef.LocationIndex + vardef.Name.Length, string.Format("Variable {0} defined more than once.", vardef.Name), Severity.Error);
                                }
                            }
                            paramsParsed = true;
                        }
                        if (parser.PeekToken(TokenKind.Comma))
                        {
                            parser.NextToken();
                        }
                    }
                }

                if (!paramsParsed)
                {
                    // get the parameters
                    while (parser.PeekToken(TokenCategory.Keyword) || parser.PeekToken(TokenCategory.Identifier))
                    {
                        parser.NextToken();
                        string errMsg;
                        if (!defNode.AddArgument(parser.Token, out errMsg))
                        {
                            parser.ReportSyntaxError(errMsg);
                        }
                        if (parser.PeekToken(TokenKind.Comma))
                        {
                            parser.NextToken();
                        }

                        // TODO: probably need to handle "end" "function" case...won't right now
                    }
                }

                if (!parser.PeekToken(TokenKind.RightParenthesis))
                {
                    parser.ReportSyntaxError("A function must specify zero or more parameters in the form: ([param1][,...])");
                }
                else
                {
                    parser.NextToken();
                }

                if (parser.LanguageVersion >= GeneroLanguageVersion.V310)
                {
                    ReturnsStatement returnsStatement;
                    if (ReturnsStatement.TryParseNode(parser, out returnsStatement))
                    {
                        defNode._explicitReturns = new List <TypeReference>();
                        foreach (var ret in returnsStatement.ReturnTypes)
                        {
                            defNode._explicitReturns.Add(ret);
                        }
                    }
                }

                List <List <TokenKind> > breakSequences =
                    new List <List <TokenKind> >(Genero4glAst.ValidStatementKeywords
                                                 .Where(x => x != TokenKind.EndKeyword && x != TokenKind.FunctionKeyword)
                                                 .Select(x => new List <TokenKind> {
                    x
                }))
                {
                    new List <TokenKind> {
                        TokenKind.EndKeyword, TokenKind.FunctionKeyword
                    }
                };
                List <TokenKind> validExits = new List <TokenKind> {
                    TokenKind.ProgramKeyword
                };
                HashSet <TokenKind> endKeywords = new HashSet <TokenKind> {
                    TokenKind.FunctionKeyword
                };
                // try to parse one or more declaration statements
                while (!parser.PeekToken(TokenKind.EndOfFile) &&
                       !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.FunctionKeyword, 2)))
                {
                    DefineNode      defineNode;
                    TypeDefNode     typeNode;
                    ConstantDefNode constNode;
                    bool            matchedBreakSequence = false;
                    switch (parser.PeekToken().Kind)
                    {
                    case TokenKind.TypeKeyword:
                    {
                        if (TypeDefNode.TryParseNode(parser, out typeNode, out matchedBreakSequence, breakSequences) && typeNode != null)
                        {
                            defNode.Children.Add(typeNode.StartIndex, typeNode);
                            foreach (var def in typeNode.GetDefinitions())
                            {
                                def.Scope = "local type";
                                if (!defNode.Types.ContainsKey(def.Name))
                                {
                                    defNode.Types.Add(def.Name, def);
                                }
                                else
                                {
                                    parser.ReportSyntaxError(def.LocationIndex, def.LocationIndex + def.Name.Length, string.Format("Type {0} defined more than once.", def.Name), Severity.Error);
                                }
                            }
                        }
                        break;
                    }

                    case TokenKind.ConstantKeyword:
                    {
                        if (ConstantDefNode.TryParseNode(parser, out constNode, out matchedBreakSequence, breakSequences) && constNode != null)
                        {
                            defNode.Children.Add(constNode.StartIndex, constNode);
                            foreach (var def in constNode.GetDefinitions())
                            {
                                def.Scope = "local constant";
                                if (!defNode.Constants.ContainsKey(def.Name))
                                {
                                    defNode.Constants.Add(def.Name, def);
                                }
                                else
                                {
                                    parser.ReportSyntaxError(def.LocationIndex, def.LocationIndex + def.Name.Length, string.Format("Constant {0} defined more than once.", def.Name), Severity.Error);
                                }
                            }
                        }
                        break;
                    }

                    case TokenKind.DefineKeyword:
                    {
                        if (DefineNode.TryParseDefine(parser, out defineNode, out matchedBreakSequence, breakSequences, defNode.BindArgument) && defineNode != null)
                        {
                            defNode.Children.Add(defineNode.StartIndex, defineNode);
                            foreach (var def in defineNode.GetDefinitions())
                            {
                                foreach (var vardef in def.VariableDefinitions)
                                {
                                    vardef.Scope = "local variable";
                                    if (!defNode.Variables.ContainsKey(vardef.Name))
                                    {
                                        defNode.Variables.Add(vardef.Name, vardef);
                                    }
                                    else
                                    {
                                        parser.ReportSyntaxError(vardef.LocationIndex, vardef.LocationIndex + vardef.Name.Length, string.Format("Variable {0} defined more than once.", vardef.Name), Severity.Error);
                                    }
                                }
                            }
                        }
                        break;
                    }

                    default:
                    {
                        FglStatement statement;
                        List <Func <PrepareStatement, bool> > prepBinders = new List <Func <PrepareStatement, bool> >();
                        prepBinders.Add(defNode.BindPrepareCursorFromIdentifier);
                        if (parser.StatementFactory.TryParseNode(parser, out statement, containingModule,
                                                                 prepBinders, defNode.StoreReturnStatement, defNode.AddLimitedScopeVariable,
                                                                 abbreviatedParse, validExits, null, null, endKeywords))
                        {
                            AstNode4gl stmtNode = statement as AstNode4gl;
                            if (stmtNode != null && !defNode.Children.ContainsKey(stmtNode.StartIndex))
                            {
                                defNode.Children.Add(stmtNode.StartIndex, stmtNode);
                            }

                            continue;
                        }
                        break;
                    }
                    }

                    if (parser.PeekToken(TokenKind.EndOfFile) ||
                        (parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.FunctionKeyword, 2)))
                    {
                        break;
                    }

                    // if a break sequence was matched, we don't want to advance the token
                    if (!matchedBreakSequence)
                    {
                        // TODO: not sure whether to break or keep going...for right now, let's keep going until we hit the end keyword
                        parser.NextToken();
                    }
                }

                if (!parser.PeekToken(TokenKind.EndOfFile))
                {
                    parser.NextToken();
                    if (parser.PeekToken(TokenKind.FunctionKeyword))
                    {
                        var tokSpan = parser.PeekTokenWithSpan();
                        bufferPosition = tokSpan.BufferPosition + tokSpan.Span.Length;
                        if (advanceOnEnd)
                        {
                            parser.NextToken();
                        }
                        defNode.EndIndex   = parser.Token.Span.End;
                        defNode.IsComplete = true;
                    }
                    else
                    {
                        parser.ReportSyntaxError(parser.Token.Span.Start, parser.Token.Span.End, "Invalid end of function definition.");
                    }
                }
                else
                {
                    parser.ReportSyntaxError("Unexpected end of function definition");
                }
            }
            return(result);
        }
예제 #8
0
        public static bool TryParseNode(Genero4glParser parser, out WhileStatement node,
                                        IModuleResult containingModule,
                                        List <Func <PrepareStatement, bool> > prepStatementBinders,
                                        Func <ReturnStatement, ParserResult> returnStatementBinder   = null,
                                        Action <IAnalysisResult, int, int> limitedScopeVariableAdder = null,
                                        List <TokenKind> validExitKeywords = null,
                                        IEnumerable <ContextStatementFactory> contextStatementFactories = null,
                                        ExpressionParsingOptions expressionOptions = null,
                                        HashSet <TokenKind> endKeywords            = null)
        {
            node = null;
            bool result = false;

            if (parser.PeekToken(TokenKind.WhileKeyword))
            {
                result = true;
                node   = new WhileStatement();
                parser.NextToken();
                node.StartIndex = parser.Token.Span.Start;

                ExpressionNode conditionExpr;
                if (!FglExpressionNode.TryGetExpressionNode(parser, out conditionExpr, Genero4glAst.ValidStatementKeywords.ToList(), expressionOptions))
                {
                    parser.ReportSyntaxError("A while statement must have a condition expression.");
                }
                else
                {
                    node.ConditionExpression = conditionExpr;
                }

                node.DecoratorEnd = parser.Token.Span.End;

                List <TokenKind> validExits = new List <TokenKind>();
                if (validExitKeywords != null)
                {
                    validExits.AddRange(validExitKeywords);
                }
                validExits.Add(TokenKind.WhileKeyword);

                HashSet <TokenKind> newEndKeywords = new HashSet <TokenKind>();
                if (endKeywords != null)
                {
                    newEndKeywords.AddRange(endKeywords);
                }
                newEndKeywords.Add(TokenKind.WhileKeyword);
                prepStatementBinders.Insert(0, node.BindPrepareCursorFromIdentifier);

                while (!parser.PeekToken(TokenKind.EndOfFile) &&
                       !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.WhileKeyword, 2)))
                {
                    FglStatement statement;
                    if (parser.StatementFactory.TryParseNode(parser, out statement, containingModule, prepStatementBinders,
                                                             returnStatementBinder, limitedScopeVariableAdder, false, validExits,
                                                             contextStatementFactories, expressionOptions, newEndKeywords) && statement != null)
                    {
                        AstNode4gl stmtNode = statement as AstNode4gl;
                        node.Children.Add(stmtNode.StartIndex, stmtNode);

                        if (statement is ExitStatement &&
                            (statement as ExitStatement).ExitType != TokenKind.WhileKeyword)
                        {
                            if (validExitKeywords == null || !validExitKeywords.Contains((statement as ExitStatement).ExitType))
                            {
                                parser.ReportSyntaxError("Invalid exit statement for while loop detected.");
                            }
                        }

                        if (statement is ContinueStatement &&
                            (statement as ContinueStatement).ContinueType != TokenKind.WhileKeyword)
                        {
                            if (validExitKeywords == null || !validExitKeywords.Contains((statement as ContinueStatement).ContinueType))
                            {
                                parser.ReportSyntaxError("Invalid continue statement for while loop detected.");
                            }
                        }
                    }
                    else if (parser.PeekToken(TokenKind.EndKeyword) && endKeywords != null && endKeywords.Contains(parser.PeekToken(2).Kind))
                    {
                        break;
                    }
                    else
                    {
                        parser.NextToken();
                    }
                }
                prepStatementBinders.RemoveAt(0);

                if (!(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.WhileKeyword, 2)))
                {
                    parser.ReportSyntaxError("A while statement must be terminated with \"end while\".");
                }
                else
                {
                    parser.NextToken(); // advance to the 'end' token
                    parser.NextToken(); // advance to the 'while' token
                    node.EndIndex = parser.Token.Span.End;
                }
            }

            return(result);
        }
예제 #9
0
        public static bool TryParserNode(Genero4glParser parser, out ForStatement node,
                                         IModuleResult containingModule,
                                         List <Func <PrepareStatement, bool> > prepStatementBinders,
                                         Func <ReturnStatement, ParserResult> returnStatementBinder   = null,
                                         Action <IAnalysisResult, int, int> limitedScopeVariableAdder = null,
                                         List <TokenKind> validExitKeywords = null,
                                         IEnumerable <ContextStatementFactory> contextStatementFactories = null,
                                         ExpressionParsingOptions expressionOptions = null,
                                         HashSet <TokenKind> endKeywords            = null)
        {
            node = null;
            bool result = false;

            if (parser.PeekToken(TokenKind.ForKeyword))
            {
                result = true;
                node   = new ForStatement();
                parser.NextToken();
                node.StartIndex = parser.Token.Span.Start;

                ExpressionNode counterVar;
                if (FglExpressionNode.TryGetExpressionNode(parser, out counterVar, new List <TokenKind> {
                    TokenKind.Equals
                }))
                {
                    node.CounterVariable = counterVar;
                }
                else
                {
                    parser.ReportSyntaxError("Invalid expression found in for statement");
                }

                if (parser.PeekToken(TokenKind.Equals))
                {
                    parser.NextToken();
                }
                else
                {
                    parser.ReportSyntaxError("For statement missing counter variable assignment.");
                }

                ExpressionNode startValue;
                if (FglExpressionNode.TryGetExpressionNode(parser, out startValue, new List <TokenKind> {
                    TokenKind.ToKeyword
                }))
                {
                    node.StartValueExpresison = startValue;
                }
                else
                {
                    parser.ReportSyntaxError("Invalid expression found in for statement");
                }

                if (parser.PeekToken(TokenKind.ToKeyword))
                {
                    parser.NextToken();
                }
                else
                {
                    parser.ReportSyntaxError("For statement missing \"to\" keyword.");
                }

                List <TokenKind> keywords = new List <TokenKind>(Genero4glAst.ValidStatementKeywords);
                keywords.Add(TokenKind.StepKeyword);
                ExpressionNode endValue;
                if (FglExpressionNode.TryGetExpressionNode(parser, out endValue, keywords))
                {
                    node.EndValueExpression = endValue;
                }
                else
                {
                    parser.ReportSyntaxError("Invalid expression found in for statement");
                }

                if (parser.PeekToken(TokenKind.StepKeyword))
                {
                    parser.NextToken();
                    ExpressionNode stepExpr;
                    if (FglExpressionNode.TryGetExpressionNode(parser, out stepExpr))
                    {
                        node.StepValue = stepExpr;
                    }
                    else
                    {
                        parser.ReportSyntaxError("Invalid step expression found.");
                    }
                    //bool negative = false;
                    //if (parser.PeekToken(TokenKind.Subtract))
                    //{
                    //    negative = true;
                    //    parser.NextToken();
                    //}
                    //if(parser.PeekToken(TokenCategory.NumericLiteral))
                    //{
                    //    parser.NextToken();
                    //    int temp;
                    //    if(int.TryParse(parser.Token.Token.Value.ToString(), out temp))
                    //    {
                    //        node.StepValue = temp;
                    //        if (negative)
                    //            node.StepValue = -(node.StepValue);
                    //    }
                    //    else
                    //    {
                    //        parser.ReportSyntaxError("Invalid step value found.");
                    //    }
                    //}
                    //else
                    //{
                    //    parser.ReportSyntaxError("Invalid step value found.");
                    //}
                }

                node.DecoratorEnd = parser.Token.Span.End;

                List <TokenKind> validExits = new List <TokenKind>();
                if (validExitKeywords != null)
                {
                    validExits.AddRange(validExitKeywords);
                }
                validExits.Add(TokenKind.ForKeyword);

                HashSet <TokenKind> newEndKeywords = new HashSet <TokenKind>();
                if (endKeywords != null)
                {
                    newEndKeywords.AddRange(endKeywords);
                }
                newEndKeywords.Add(TokenKind.ForKeyword);

                prepStatementBinders.Insert(0, node.BindPrepareCursorFromIdentifier);
                while (!parser.PeekToken(TokenKind.EndOfFile) &&
                       !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.ForKeyword, 2)))
                {
                    FglStatement statement;
                    if (parser.StatementFactory.TryParseNode(parser, out statement, containingModule, prepStatementBinders,
                                                             returnStatementBinder, limitedScopeVariableAdder, false, validExits,
                                                             contextStatementFactories, expressionOptions, newEndKeywords) && statement != null)
                    {
                        AstNode4gl stmtNode = statement as AstNode4gl;
                        node.Children.Add(stmtNode.StartIndex, stmtNode);

                        if (statement is ExitStatement &&
                            (statement as ExitStatement).ExitType != TokenKind.ForKeyword)
                        {
                            if (validExitKeywords == null || !validExitKeywords.Contains((statement as ExitStatement).ExitType))
                            {
                                parser.ReportSyntaxError("Invalid exit statement for for loop detected.");
                            }
                        }

                        if (statement is ContinueStatement &&
                            (statement as ContinueStatement).ContinueType != TokenKind.ForKeyword)
                        {
                            if (validExitKeywords == null || !validExitKeywords.Contains((statement as ContinueStatement).ContinueType))
                            {
                                parser.ReportSyntaxError("Invalid continue statement for for loop detected.");
                            }
                        }
                    }
                    else if (parser.PeekToken(TokenKind.EndKeyword) && endKeywords != null && endKeywords.Contains(parser.PeekToken(2).Kind))
                    {
                        break;
                    }
                    else
                    {
                        parser.NextToken();
                    }
                }
                prepStatementBinders.RemoveAt(0);

                if (!(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.ForKeyword, 2)))
                {
                    parser.ReportSyntaxError("A for statement must be terminated with \"end for\".");
                }
                else
                {
                    parser.NextToken(); // advance to the 'end' token
                    parser.NextToken(); // advance to the 'for' token
                    node.EndIndex = parser.Token.Span.End;
                }
            }

            return(result);
        }
예제 #10
0
        public static bool TryParseNode(Genero4glParser parser, out MainBlockNode defNode, IModuleResult containingModule)
        {
            defNode = null;
            bool result = false;

            if (parser.PeekToken(TokenKind.MainKeyword))
            {
                result  = true;
                defNode = new MainBlockNode();
                parser.NextToken();
                defNode.Name           = parser.Token.Token.Value.ToString();
                defNode.StartIndex     = parser.Token.Span.Start;
                defNode.DecoratorEnd   = defNode.StartIndex + 4;
                defNode.AccessModifier = AccessModifier.Private;

                List <List <TokenKind> > breakSequences =
                    new List <List <TokenKind> >(Genero4glAst.ValidStatementKeywords
                                                 .Where(x => x != TokenKind.EndKeyword && x != TokenKind.MainKeyword)
                                                 .Select(x => new List <TokenKind> {
                    x
                }))
                {
                    new List <TokenKind> {
                        TokenKind.EndKeyword, TokenKind.MainKeyword
                    }
                };
                List <TokenKind> validExits = new List <TokenKind> {
                    TokenKind.ProgramKeyword
                };
                HashSet <TokenKind> endKeywords = new HashSet <TokenKind> {
                    TokenKind.MainKeyword
                };
                bool fglStatement = false;
                // try to parse one or more declaration statements
                while (!parser.PeekToken(TokenKind.EndOfFile) &&
                       !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.MainKeyword, 2)))
                {
                    fglStatement = false;
                    DefineNode      defineNode;
                    TypeDefNode     typeNode;
                    ConstantDefNode constNode;
                    bool            matchedBreakSequence = false;
                    switch (parser.PeekToken().Kind)
                    {
                    case TokenKind.TypeKeyword:
                    {
                        if (TypeDefNode.TryParseNode(parser, out typeNode, out matchedBreakSequence, breakSequences) && typeNode != null)
                        {
                            defNode.Children.Add(typeNode.StartIndex, typeNode);
                            foreach (var def in typeNode.GetDefinitions())
                            {
                                def.Scope = "local type";
                                if (!defNode.Types.ContainsKey(def.Name))
                                {
                                    defNode.Types.Add(def.Name, def);
                                }
                                else
                                {
                                    parser.ReportSyntaxError(def.LocationIndex, def.LocationIndex + def.Name.Length, string.Format("Type {0} defined more than once.", def.Name), Severity.Error);
                                }
                            }
                        }
                        break;
                    }

                    case TokenKind.ConstantKeyword:
                    {
                        if (ConstantDefNode.TryParseNode(parser, out constNode, out matchedBreakSequence, breakSequences) && constNode != null)
                        {
                            defNode.Children.Add(constNode.StartIndex, constNode);
                            foreach (var def in constNode.GetDefinitions())
                            {
                                def.Scope = "local constant";
                                if (!defNode.Constants.ContainsKey(def.Name))
                                {
                                    defNode.Constants.Add(def.Name, def);
                                }
                                else
                                {
                                    parser.ReportSyntaxError(def.LocationIndex, def.LocationIndex + def.Name.Length, string.Format("Constant {0} defined more than once.", def.Name), Severity.Error);
                                }
                            }
                        }
                        break;
                    }

                    case TokenKind.DefineKeyword:
                    {
                        if (DefineNode.TryParseDefine(parser, out defineNode, out matchedBreakSequence, breakSequences) && defineNode != null)
                        {
                            defNode.Children.Add(defineNode.StartIndex, defineNode);
                            foreach (var def in defineNode.GetDefinitions())
                            {
                                foreach (var vardef in def.VariableDefinitions)
                                {
                                    vardef.Scope = "local variable";
                                    if (!defNode.Variables.ContainsKey(vardef.Name))
                                    {
                                        defNode.Variables.Add(vardef.Name, vardef);
                                    }
                                    else
                                    {
                                        parser.ReportSyntaxError(vardef.LocationIndex, vardef.LocationIndex + vardef.Name.Length, string.Format("Variable {0} defined more than once.", vardef.Name), Severity.Error);
                                    }
                                }
                            }
                        }
                        break;
                    }

                    default:
                    {
                        FglStatement statement;
                        List <Func <PrepareStatement, bool> > prepBinders = new List <Func <PrepareStatement, bool> >();
                        prepBinders.Add(defNode.BindPrepareCursorFromIdentifier);
                        if (parser.StatementFactory.TryParseNode(parser, out statement, containingModule, prepBinders,
                                                                 defNode.StoreReturnStatement, defNode.AddLimitedScopeVariable, false, validExits, null, null, endKeywords) && statement != null)
                        {
                            AstNode4gl stmtNode = statement as AstNode4gl;
                            defNode.Children.Add(stmtNode.StartIndex, stmtNode);
                            fglStatement = true;
                        }
                        break;
                    }
                    }

                    if (parser.PeekToken(TokenKind.EndOfFile) ||
                        (parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.MainKeyword, 2)))
                    {
                        break;
                    }

                    // if a break sequence was matched, we don't want to advance the token
                    if (!matchedBreakSequence && !fglStatement)
                    {
                        // TODO: not sure whether to break or keep going...for right now, let's keep going until we hit the end keyword
                        parser.NextToken();
                    }
                }

                if (!parser.PeekToken(TokenKind.EndOfFile))
                {
                    parser.NextToken();
                    if (parser.PeekToken(TokenKind.MainKeyword))
                    {
                        parser.NextToken();
                        defNode.EndIndex   = parser.Token.Span.End;
                        defNode.IsComplete = true;
                    }
                    else
                    {
                        parser.ReportSyntaxError(parser.Token.Span.Start, parser.Token.Span.End, "Invalid end of main definition.");
                    }
                }
                else
                {
                    parser.ReportSyntaxError("Unexpected end of main definition");
                }
            }

            return(result);
        }