示例#1
0
        public static bool TryParseNode(Genero4glParser parser, out ModuleNode defNode)
        {
            defNode = new ModuleNode();
            if (!string.IsNullOrWhiteSpace(parser.Filename))
            {
                defNode.ProgramName = Path.GetFileName(Path.GetDirectoryName(parser.Filename));
            }

            NodesProcessed processed = NodesProcessed.None;

            while (!parser.PeekToken(TokenKind.EndOfFile))
            {
                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                CompilerOptionsNode compOptionsNode;
                if (CompilerOptionsNode.TryParseNode(parser, out compOptionsNode) && compOptionsNode != null)
                {
                    if (processed == NodesProcessed.None)
                    {
                        defNode.Children.Add(compOptionsNode.StartIndex, compOptionsNode);
                    }
                    else
                    {
                        parser.ReportSyntaxError("Compiler options statement found in incorrect position.");
                    }
                }
                if (processed == NodesProcessed.None)
                {
                    processed = NodesProcessed.CompilerOption;
                }

                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                ImportModuleNode importNode;
                if (ImportModuleNode.TryParseNode(parser, out importNode) && importNode != null)
                {
                    if (processed == NodesProcessed.CompilerOption)
                    {
                        if (!defNode.Children.ContainsKey(importNode.StartIndex))
                        {
                            defNode.Children.Add(importNode.StartIndex, importNode);
                            if (!string.IsNullOrWhiteSpace(importNode.ImportName))
                            {
                                if (importNode.ImportType == ImportModuleType.C)
                                {
                                    defNode.CExtensionImports.Add(importNode.ImportName);
                                }
                                else if (importNode.ImportType == ImportModuleType.Java)
                                {
                                    defNode.JavaImports.Add(importNode.ImportName);
                                }
                                else
                                {
                                    defNode.FglImports.Add(importNode.ImportName);
                                }
                            }
                        }
                        continue;
                    }
                    else
                    {
                        parser.ReportSyntaxError("Import statement found in incorrect position.");
                    }
                }
                if (processed == NodesProcessed.CompilerOption)
                {
                    processed = NodesProcessed.Imports;
                }

                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                SchemaSpecificationNode schemaNode;
                if (SchemaSpecificationNode.TryParseDefine(parser, out schemaNode) && schemaNode != null)
                {
                    if (processed == NodesProcessed.Imports)
                    {
                        if (!defNode.Children.ContainsKey(schemaNode.StartIndex))
                        {
                            defNode.Children.Add(schemaNode.StartIndex, schemaNode);
                        }
                    }
                    else
                    {
                        parser.ReportSyntaxError("Schema statement found in incorrect position.");
                    }
                }
                if (processed == NodesProcessed.Imports)
                {
                    processed = NodesProcessed.SchemaSpec;
                }

                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                GlobalsNode globalNode;
                if (GlobalsNode.TryParseNode(parser, out globalNode) && globalNode != null)
                {
                    if (processed == NodesProcessed.SchemaSpec || processed == NodesProcessed.MemberDefinitions)
                    {
                        defNode.Children.Add(globalNode.StartIndex, globalNode);
                        foreach (var cGlobKVP in globalNode.Constants)
                        {
                            if (!defNode.GlobalConstants.ContainsKey(cGlobKVP.Key))
                            {
                                defNode.GlobalConstants.Add(cGlobKVP);
                            }
                            else
                            {
                                parser.ReportSyntaxError(cGlobKVP.Value.LocationIndex, cGlobKVP.Value.LocationIndex + cGlobKVP.Value.Name.Length, string.Format("Global constant {0} defined more than once.", cGlobKVP.Key), Severity.Error);
                            }
                        }
                        foreach (var tGlobKVP in globalNode.Types)
                        {
                            if (!defNode.GlobalTypes.ContainsKey(tGlobKVP.Key))
                            {
                                defNode.GlobalTypes.Add(tGlobKVP);
                            }
                            else
                            {
                                parser.ReportSyntaxError(tGlobKVP.Value.LocationIndex, tGlobKVP.Value.LocationIndex + tGlobKVP.Value.Name.Length, string.Format("Global type {0} defined more than once.", tGlobKVP.Key), Severity.Error);
                            }
                        }
                        foreach (var vGlobKVP in globalNode.Variables)
                        {
                            if (!defNode.GlobalVariables.ContainsKey(vGlobKVP.Key))
                            {
                                defNode.GlobalVariables.Add(vGlobKVP);
                            }
                            else
                            {
                                parser.ReportSyntaxError(vGlobKVP.Value.LocationIndex, vGlobKVP.Value.LocationIndex + vGlobKVP.Value.Name.Length, string.Format("Global variable {0} defined more than once.", vGlobKVP.Key), Severity.Error);
                            }
                        }
                        continue;
                    }
                    else
                    {
                        parser.ReportSyntaxError("Globals statement found in incorrect position.");
                    }
                }
                if (processed == NodesProcessed.SchemaSpec)
                {
                    processed = NodesProcessed.MemberDefinitions;
                }

                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                bool                     matchedBreakSequence = false;
                ConstantDefNode          constNode;
                List <List <TokenKind> > breakSequences = new List <List <TokenKind> >()
                {
                    new List <TokenKind> {
                        TokenKind.GlobalsKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.PublicKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.PrivateKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.ConstantKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.DefineKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.TypeKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.FunctionKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.MainKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.ReportKeyword
                    }
                };
                if (ConstantDefNode.TryParseNode(parser, out constNode, out matchedBreakSequence, breakSequences) && constNode != null)
                {
                    if (processed == NodesProcessed.SchemaSpec || processed == NodesProcessed.MemberDefinitions)
                    {
                        defNode.Children.Add(constNode.StartIndex, constNode);
                        foreach (var def in constNode.GetDefinitions())
                        {
                            def.Scope = "module 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("Module constant {0} defined more than once.", def.Name), Severity.Error);
                            }
                        }
                        continue;
                    }
                    else
                    {
                        parser.ReportSyntaxError("Constant definition found in incorrect position.");
                    }
                }
                if (processed == NodesProcessed.SchemaSpec)
                {
                    processed = NodesProcessed.MemberDefinitions;
                }

                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                TypeDefNode typeNode;
                if (TypeDefNode.TryParseNode(parser, out typeNode, out matchedBreakSequence, breakSequences) && typeNode != null)
                {
                    if (processed == NodesProcessed.SchemaSpec || processed == NodesProcessed.MemberDefinitions)
                    {
                        if (!defNode.Children.ContainsKey(typeNode.StartIndex))
                        {
                            defNode.Children.Add(typeNode.StartIndex, typeNode);
                        }
                        foreach (var def in typeNode.GetDefinitions())
                        {
                            def.Scope = "module 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("Module type {0} defined more than once.", def.Name), Severity.Error);
                            }
                        }
                        continue;
                    }
                    else
                    {
                        parser.ReportSyntaxError("Type definition found in incorrect position.");
                    }
                }
                if (processed == NodesProcessed.SchemaSpec)
                {
                    processed = NodesProcessed.MemberDefinitions;
                }

                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                DefineNode defineNode;
                if (DefineNode.TryParseDefine(parser, out defineNode, out matchedBreakSequence, breakSequences) && defineNode != null)
                {
                    if (processed == NodesProcessed.SchemaSpec || processed == NodesProcessed.MemberDefinitions)
                    {
                        defNode.Children.Add(defineNode.StartIndex, defineNode);
                        foreach (var def in defineNode.GetDefinitions())
                        {
                            foreach (var vardef in def.VariableDefinitions)
                            {
                                vardef.Scope = "module variable";
                                vardef.SetIsPublic(defineNode.AccessModifier == AccessModifier.Public);
                                if (!defNode.Variables.ContainsKey(vardef.Name))
                                {
                                    defNode.Variables.Add(vardef.Name, vardef);
                                }
                                else
                                {
                                    parser.ReportSyntaxError(vardef.LocationIndex, vardef.LocationIndex + vardef.Name.Length, string.Format("Module variable {0} defined more than once.", vardef.Name), Severity.Error);
                                }
                            }
                        }
                        continue;
                    }
                    else
                    {
                        parser.ReportSyntaxError("Variable definition found in incorrect position.");
                    }
                }
                if (processed == NodesProcessed.SchemaSpec)
                {
                    processed = NodesProcessed.MemberDefinitions;
                }

                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                MainBlockNode mainBlock;
                if (MainBlockNode.TryParseNode(parser, out mainBlock, defNode) && mainBlock != null)
                {
                    if (processed == NodesProcessed.MemberDefinitions)
                    {
                        defNode.Children.Add(mainBlock.StartIndex, mainBlock);
                        defNode.Functions.Add(mainBlock.Name, mainBlock);
                        foreach (var cursor in mainBlock.Children.Values.Where(x => x is PrepareStatement || x is DeclareStatement))
                        {
                            IAnalysisResult curRes = cursor as IAnalysisResult;
                            if (!defNode.Cursors.ContainsKey(curRes.Name))
                            {
                                defNode.Cursors.Add(curRes.Name, curRes);
                            }
                        }
                    }
                    else
                    {
                        parser.ReportSyntaxError("Main block found in incorrect position.");
                    }
                }
                if (processed == NodesProcessed.MemberDefinitions)
                {
                    processed = NodesProcessed.Main;
                }

                if (CheckForPreprocessorNode(parser, defNode))
                {
                    continue;
                }

                FunctionBlockNode      funcNode;
                ReportBlockNode        repNode;
                DeclarativeDialogBlock dialogNode;
                int dummy;
                if (FunctionBlockNode.TryParseNode(parser, out funcNode, out dummy, defNode) && funcNode != null)
                {
                    defNode.Children.Add(funcNode.StartIndex, funcNode);
                    funcNode.Scope = "function";

                    if (string.IsNullOrWhiteSpace(funcNode.Name))
                    {
                        parser.ReportSyntaxError(funcNode.LocationIndex, funcNode.LocationIndex, "Invalid function definition found.");
                    }
                    else if (!defNode.Functions.ContainsKey(funcNode.Name))
                    {
                        defNode.Functions.Add(funcNode.Name, funcNode);
                    }
                    else
                    {
                        parser.ReportSyntaxError(funcNode.LocationIndex, funcNode.LocationIndex + funcNode.Name.Length, string.Format("Function {0} defined more than once.", funcNode.Name), Severity.Error);
                    }
                }
                else if (ReportBlockNode.TryParseNode(parser, out repNode, defNode) && repNode != null)
                {
                    defNode.Children.Add(repNode.StartIndex, repNode);

                    repNode.Scope = "report";
                    if (string.IsNullOrWhiteSpace(repNode.Name))
                    {
                        parser.ReportSyntaxError(repNode.LocationIndex, repNode.LocationIndex, "Invalid report definition found.");
                    }
                    else if (!defNode.Functions.ContainsKey(repNode.Name))
                    {
                        defNode.Functions.Add(repNode.Name, repNode);
                    }
                    else
                    {
                        parser.ReportSyntaxError(repNode.LocationIndex, repNode.LocationIndex + repNode.Name.Length, string.Format("Report {0} defined more than once.", repNode.Name), Severity.Error);
                    }
                }
                else if (DeclarativeDialogBlock.TryParseNode(parser, out dialogNode, defNode) && dialogNode != null)
                {
                    defNode.Children.Add(dialogNode.StartIndex, dialogNode);
                    dialogNode.Scope = "dialog";
                    if (string.IsNullOrWhiteSpace(dialogNode.Name))
                    {
                        parser.ReportSyntaxError(dialogNode.LocationIndex, dialogNode.LocationIndex, "Invalid declarative dialog definition found.");
                    }
                    else if (!defNode.Functions.ContainsKey(dialogNode.Name))
                    {
                        defNode.Functions.Add(dialogNode.Name, dialogNode);
                    }
                    else
                    {
                        parser.ReportSyntaxError(dialogNode.LocationIndex, dialogNode.LocationIndex + dialogNode.Name.Length, string.Format("Declarative dialog {0} defined more than once.", dialogNode.Name), Severity.Error);
                    }
                }
                else
                {
                    parser.NextToken();
                }
            }

            if (defNode.Children.Count > 0)
            {
                defNode.StartIndex = defNode.Children[defNode.Children.Keys[0]].StartIndex;
                defNode.EndIndex   = defNode.Children[defNode.Children.Keys[defNode.Children.Count - 1]].EndIndex;
                defNode.IsComplete = true;
            }

            return(true);
        }
示例#2
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);
        }
示例#3
0
        public static bool TryParseNode(Genero4glParser parser, out ReportBlockNode defNode, IModuleResult containingModule)
        {
            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.ReportKeyword, lookAheadBy))
            {
                result  = true;
                defNode = new ReportBlockNode();
                if (accMod.HasValue)
                {
                    parser.NextToken();
                    defNode.AccessModifier = accMod.Value;
                }
                else
                {
                    defNode.AccessModifier = AccessModifier.Public;
                }

                parser.NextToken(); // move past the Function keyword
                defNode.StartIndex    = parser.Token.Span.Start;
                defNode.OrderVarNames = new List <FglNameExpression>();

                // 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 report must have a name.");
                }

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

                // 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 report must specify zero or more parameters in the form: ([param1][,...])");
                }
                else
                {
                    parser.NextToken();
                }

                List <List <TokenKind> > breakSequences =
                    new List <List <TokenKind> >(Genero4glAst.ValidStatementKeywords
                                                 .Where(x => x != TokenKind.EndKeyword && x != TokenKind.ReportKeyword)
                                                 .Select(x => new List <TokenKind> {
                    x
                }))
                {
                    new List <TokenKind> {
                        TokenKind.EndKeyword, TokenKind.ReportKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.OutputKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.OrderKeyword
                    },
                    new List <TokenKind> {
                        TokenKind.FormatKeyword
                    }
                };

                while (!parser.PeekToken(TokenKind.EndOfFile) &&
                       !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.ReportKeyword, 2)))
                {
                    DefineNode      defineNode;
                    TypeDefNode     typeNode;
                    ConstantDefNode constNode;
                    bool            matchedBreakSequence = false;
                    bool            inDefSection         = true;
                    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:
                        inDefSection = false;
                        break;
                    }

                    if (!inDefSection)
                    {
                        break;
                    }
                }

                if (parser.PeekToken(TokenKind.OutputKeyword))
                {
                    parser.NextToken();
                    bool           isValid = true;
                    ExpressionNode expr;
                    while (isValid)
                    {
                        if (parser.PeekToken(TokenKind.ReportKeyword))
                        {
                            parser.NextToken();
                            if (parser.PeekToken(TokenKind.ToKeyword))
                            {
                                parser.NextToken();
                                switch (parser.PeekToken().Kind)
                                {
                                case TokenKind.ScreenKeyword:
                                case TokenKind.PrinterKeyword:
                                    parser.NextToken();
                                    break;

                                case TokenKind.FileKeyword:
                                    parser.NextToken();
                                    if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                    {
                                        defNode.OutputFilename = expr;
                                    }
                                    else
                                    {
                                        parser.ReportSyntaxError("Invalid filename found in report.");
                                    }
                                    break;

                                case TokenKind.PipeKeyword:
                                    parser.NextToken();
                                    if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                    {
                                        defNode.OutputProgram = expr;
                                    }
                                    else
                                    {
                                        parser.ReportSyntaxError("Invalid program name found in report.");
                                    }
                                    if (parser.PeekToken(TokenKind.InKeyword))
                                    {
                                        parser.NextToken();
                                        if ((parser.PeekToken(TokenKind.FormKeyword) || parser.PeekToken(TokenKind.LineKeyword)) &&
                                            parser.PeekToken(TokenKind.ModeKeyword, 2))
                                        {
                                            parser.NextToken();
                                            parser.NextToken();
                                        }
                                        else
                                        {
                                            parser.ReportSyntaxError("Expected \"form mode\" or \"line mode\" in report.");
                                        }
                                    }
                                    break;

                                default:
                                    if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                    {
                                        defNode.OutputFilename = expr;
                                    }
                                    else
                                    {
                                        parser.ReportSyntaxError("Invalid filename found in report.");
                                    }
                                    break;
                                }
                            }
                            else
                            {
                                parser.ReportSyntaxError("Expected \"to\" keyword in report.");
                            }
                        }

                        switch (parser.PeekToken().Kind)
                        {
                        case TokenKind.WithKeyword:
                            parser.NextToken();
                            break;

                        case TokenKind.LeftKeyword:
                            parser.NextToken();
                            if (parser.PeekToken(TokenKind.MarginKeyword))
                            {
                                parser.NextToken();
                                if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                {
                                    defNode.MarginLeft = expr;
                                }
                                else
                                {
                                    parser.ReportSyntaxError("Invalid margin value found in report.");
                                }
                            }
                            else
                            {
                                parser.ReportSyntaxError("Expected \"margin\" keyword in report.");
                            }
                            break;

                        case TokenKind.RightKeyword:
                            parser.NextToken();
                            if (parser.PeekToken(TokenKind.MarginKeyword))
                            {
                                parser.NextToken();
                                if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                {
                                    defNode.MarginRight = expr;
                                }
                                else
                                {
                                    parser.ReportSyntaxError("Invalid margin value found in report.");
                                }
                            }
                            else
                            {
                                parser.ReportSyntaxError("Expected \"margin\" keyword in report.");
                            }
                            break;

                        case TokenKind.BottomKeyword:
                            parser.NextToken();
                            if (parser.PeekToken(TokenKind.MarginKeyword))
                            {
                                parser.NextToken();
                                if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                {
                                    defNode.MarginBottom = expr;
                                }
                                else
                                {
                                    parser.ReportSyntaxError("Invalid margin value found in report.");
                                }
                            }
                            else
                            {
                                parser.ReportSyntaxError("Expected \"margin\" keyword in report.");
                            }
                            break;

                        case TokenKind.PageKeyword:
                            parser.NextToken();
                            if (parser.PeekToken(TokenKind.LengthKeyword))
                            {
                                parser.NextToken();
                                if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                {
                                    defNode.PageLength = expr;
                                }
                                else
                                {
                                    parser.ReportSyntaxError("Invalid page length value found in report.");
                                }
                            }
                            else
                            {
                                parser.ReportSyntaxError("Expected \"length\" keyword in report.");
                            }
                            break;

                        case TokenKind.TopKeyword:
                            parser.NextToken();
                            if (parser.PeekToken(TokenKind.OfKeyword) && parser.PeekToken(TokenKind.PageKeyword, 2))
                            {
                                parser.NextToken();
                                parser.NextToken();
                                if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                {
                                    defNode.TopOfPage = expr;
                                }
                                else
                                {
                                    parser.ReportSyntaxError("Invalid top of page value found in report.");
                                }
                            }
                            else if (parser.PeekToken(TokenKind.MarginKeyword))
                            {
                                parser.NextToken();
                                if (FglExpressionNode.TryGetExpressionNode(parser, out expr))
                                {
                                    defNode.MarginTop = expr;
                                }
                                else
                                {
                                    parser.ReportSyntaxError("Invalid margin value found in report.");
                                }
                            }
                            else
                            {
                                parser.ReportSyntaxError("Invalid token found in report.");
                            }
                            break;

                        default:
                            isValid = false;
                            parser.ReportSyntaxError("Invalid token found in output section of report.");
                            break;
                        }

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

                if (parser.PeekToken(TokenKind.OrderKeyword))
                {
                    parser.NextToken();
                    if (parser.PeekToken(TokenKind.ExternalKeyword))
                    {
                        parser.NextToken();
                    }
                    if (parser.PeekToken(TokenKind.ByKeyword))
                    {
                        parser.NextToken();
                    }
                    else
                    {
                        parser.ReportSyntaxError("Expected \"by\" keyword in order section of report.");
                    }

                    // collect report variables
                    FglNameExpression varName;
                    while (FglNameExpression.TryParseNode(parser, out varName))
                    {
                        defNode.OrderVarNames.Add(varName);
                        if (parser.PeekToken(TokenKind.AscKeyword) || parser.PeekToken(TokenKind.DescKeyword))
                        {
                            parser.NextToken();
                        }
                        if (parser.PeekToken(TokenKind.Comma))
                        {
                            parser.NextToken();
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                List <TokenKind> validExits = new List <TokenKind> {
                    TokenKind.ProgramKeyword, TokenKind.ReportKeyword
                };

                ReportFormatSection rfs;
                while (ReportFormatSection.TryParseNode(parser, out rfs, containingModule, defNode, null, defNode.StoreReturnStatement,
                                                        defNode.AddLimitedScopeVariable, validExits) && rfs != null)
                {
                    defNode.Children.Add(rfs.StartIndex, rfs);
                    if (parser.PeekToken(TokenKind.EndOfFile) ||
                        (parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.ReportKeyword, 2)))
                    {
                        break;
                    }
                }

                if (!parser.PeekToken(TokenKind.EndOfFile))
                {
                    parser.NextToken();
                    if (parser.PeekToken(TokenKind.ReportKeyword))
                    {
                        parser.NextToken();
                        defNode.EndIndex   = parser.Token.Span.End;
                        defNode.IsComplete = true;
                        defNode.AddLimitedScopeVariable(Genero4glAst.PagenoVariable, defNode.StartIndex, defNode.EndIndex);
                    }
                    else
                    {
                        parser.ReportSyntaxError(parser.Token.Span.Start, parser.Token.Span.End, "Invalid end of report definition.");
                    }
                }
                else
                {
                    parser.ReportSyntaxError("Unexpected end of report definition");
                }
            }
            return(result);
        }
示例#4
0
        public static bool TryParseNode(IParser parser, out ConstantDefNode defNode, out bool matchedBreakSequence, List <List <TokenKind> > breakSequences = null)
        {
            defNode = null;
            bool result = false;

            matchedBreakSequence = 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.ConstantKeyword, lookAheadBy))
            {
                result  = true;
                defNode = new ConstantDefNode();
                if (accMod.HasValue)
                {
                    parser.NextToken();
                    defNode.AccessModifier = accMod.Value;
                }
                else
                {
                    defNode.AccessModifier = AccessModifier.Public;
                }

                parser.NextToken(); // move past the Constant keyword
                defNode.StartIndex = parser.Token.Span.Start;

                ConstantDefinitionNode constDef;
                while (true)
                {
                    if (ConstantDefinitionNode.TryParseNode(parser, out constDef, defNode.AccessModifier == AccessModifier.Public) && constDef != null)
                    {
                        defNode.Children.Add(constDef.StartIndex, constDef);
                    }
                    else
                    {
                        break;
                    }

                    if (parser.PeekToken(TokenKind.Comma))
                    {
                        parser.NextToken();
                    }

                    if (breakSequences != null)
                    {
                        bool matchedBreak = false;
                        foreach (var seq in breakSequences)
                        {
                            bool bsMatch        = true;
                            uint peekaheadCount = 1;
                            foreach (var kind in seq)
                            {
                                if (parser.PeekToken(kind, peekaheadCount))
                                {
                                    peekaheadCount++;
                                }
                                else
                                {
                                    bsMatch = false;
                                    break;
                                }
                            }
                            if (bsMatch)
                            {
                                matchedBreak = true;
                                break;
                            }
                        }

                        if (matchedBreak)
                        {
                            matchedBreakSequence = true;
                            break;
                        }
                    }
                }

                if (defNode.Children.Count > 0 &&
                    defNode.Children.All(x => x.Value.IsComplete))
                {
                    defNode.IsComplete = true;
                }
            }
            return(result);
        }
示例#5
0
        public static bool TryParseNode(Genero4glParser parser, out GlobalsNode defNode)
        {
            defNode = null;
            bool result = false;

            if (parser.PeekToken(TokenKind.GlobalsKeyword))
            {
                result = true;
                parser.NextToken();
                defNode            = new GlobalsNode();
                defNode.StartIndex = parser.Token.Span.Start;

                var tok = parser.PeekToken();
                if (Tokenizer.GetTokenInfo(tok).Category == TokenCategory.StringLiteral)
                {
                    parser.NextToken();
                    defNode.GlobalsFilename = parser.Token.Token.Value.ToString();
                }
                else
                {
                    List <List <TokenKind> > breakSequences = new List <List <TokenKind> >()
                    {
                        new List <TokenKind> {
                            TokenKind.EndKeyword, TokenKind.GlobalsKeyword
                        },
                        new List <TokenKind> {
                            TokenKind.ConstantKeyword
                        },
                        new List <TokenKind> {
                            TokenKind.DefineKeyword
                        },
                        new List <TokenKind> {
                            TokenKind.TypeKeyword
                        }
                    };
                    // try to parse one or more declaration statements
                    while (!parser.PeekToken(TokenKind.EndOfFile) &&
                           !(parser.PeekToken(TokenKind.EndKeyword) && parser.PeekToken(TokenKind.GlobalsKeyword, 2)))
                    {
                        DefineNode      defineNode;
                        TypeDefNode     typeNode;
                        ConstantDefNode constNode;
                        bool            matchedBreakSequence = false;
                        switch (parser.PeekToken().Kind)
                        {
                        case TokenKind.TypeKeyword:
                        {
                            var bsList = new List <List <TokenKind> >(breakSequences);
                            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 = "global type";
                                    if (!defNode.Types.ContainsKey(def.Name))
                                    {
                                        defNode.Types.Add(def.Name, def);
                                    }
                                    else
                                    {
                                        parser.ReportSyntaxError(string.Format("Global type {0} is 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 = "global constant";
                                    if (!defNode.Constants.ContainsKey(def.Name))
                                    {
                                        defNode.Constants.Add(def.Name, def);
                                    }
                                    else
                                    {
                                        parser.ReportSyntaxError(string.Format("Global constant {0} is 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 = "global 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("Global variable {0} is defined more than once.", vardef.Name), Severity.Error);
                                        }
                                    }
                                }
                            }
                            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.GlobalsKeyword))
                        {
                            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 globals definition.");
                        }
                    }
                    else
                    {
                        parser.ReportSyntaxError("Unexpected end of globals definition");
                    }
                }
            }

            return(result);
        }
示例#6
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);
        }