示例#1
0
        public static bool TryParseNode(IParser parser, out VariableDefinitionNode defNode, Action <VariableDef> binder = null, bool reportSyntaxError = true, bool allowShorthandDefinition = true)
        {
            defNode = null;
            bool result         = false;
            uint peekaheadCount = 1;
            List <Tuple <string, int> > identifiers = new List <Tuple <string, int> >();

            var tok     = parser.PeekTokenWithSpan(peekaheadCount);
            var tokInfo = Tokenizer.GetTokenInfo(tok.Token);

            while (tokInfo.Category == TokenCategory.Identifier || tokInfo.Category == TokenCategory.Keyword)
            {
                identifiers.Add(new Tuple <string, int>(tok.Token.Value.ToString(), tok.Span.Start));
                peekaheadCount++;
                if (!parser.PeekToken(TokenKind.Comma, peekaheadCount) || !allowShorthandDefinition)
                {
                    break;
                }
                peekaheadCount++;
                tok     = parser.PeekTokenWithSpan(peekaheadCount);
                tokInfo = Tokenizer.GetTokenInfo(tok.Token);
            }

            if (identifiers.Count > 0)
            {
                result              = true;
                defNode             = new VariableDefinitionNode();
                defNode.StartIndex  = parser.Token.Span.Start;
                defNode.Location    = parser.TokenLocation;
                defNode.Identifiers = new List <Tuple <string, int> >(identifiers);
                while (peekaheadCount > 1)
                {
                    parser.NextToken();
                    peekaheadCount--;
                }

                TypeReference typeRef;
                if (TypeReference.TryParseNode(parser, out typeRef) && typeRef != null)
                {
                    defNode.EndIndex = typeRef.EndIndex;
                    defNode.Children.Add(typeRef.StartIndex, typeRef);
                    if (defNode.Children.Last().Value.IsComplete)
                    {
                        defNode.IsComplete = true;
                    }
                }
                else
                {
                    if (reportSyntaxError)
                    {
                        parser.ReportSyntaxError("No type defined for variable(s).");
                    }
                    result = false;
                }

                if (typeRef != null)
                {
                    foreach (var ident in defNode.Identifiers)
                    {
                        var varDef = new VariableDef(ident.Item1, typeRef, ident.Item2, false, (defNode.Location != null ? defNode.Location.FilePath : null));
                        defNode.VariableDefinitions.Add(varDef);
                        if (binder != null)
                        {
                            binder(varDef);
                        }
                    }
                }
            }

            return(result);
        }
示例#2
0
        public static bool TryParseDefine(IParser parser, out DefineNode defNode, out bool matchedBreakSequence, List <List <TokenKind> > breakSequences = null, Action <VariableDef> binder = 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.DefineKeyword, lookAheadBy))
            {
                result  = true;
                defNode = new DefineNode();
                if (accMod.HasValue)
                {
                    parser.NextToken();
                    defNode.AccessModifier = accMod.Value;
                }
                else
                {
                    defNode.AccessModifier = AccessModifier.Public;
                }

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

                if (parser.PeekToken(TokenCategory.Keyword) || parser.PeekToken(TokenCategory.Identifier))
                {
                    bool tryAgain = true;
                    do
                    {
                        VariableDefinitionNode varDef;
                        if (VariableDefinitionNode.TryParseNode(parser, out varDef, binder) && varDef != null)
                        {
                            defNode.Children.Add(varDef.StartIndex, varDef);
                        }
                        else
                        {
                            tryAgain = false;
                        }

                        if (tryAgain)
                        {
                            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 (tryAgain)
                            {
                                if (parser.PeekToken(TokenKind.Comma))
                                {
                                    parser.NextToken();
                                    continue;
                                }
                                else
                                {
                                    tryAgain = false;
                                }
                            }
                        }
                    }while (tryAgain);

                    if (defNode.Children.Count > 0)
                    {
                        defNode.EndIndex = parser.Token.Span.End;
                        if (defNode.Children.All(x => x.Value.IsComplete))
                        {
                            defNode.IsComplete = true;
                        }
                    }
                    else
                    {
                        parser.ReportSyntaxError("Nothing defined in define block");
                    }
                }
                else
                {
                    parser.ReportSyntaxError("Invalid token following define.");
                }
            }

            return(result);
        }
示例#3
0
        public static bool TryParseNode(IParser parser, out FunctionTypeReference defNode, bool isPublic)
        {
            defNode = null;
            bool result = false;

            if (parser.PeekToken(TokenKind.FunctionKeyword))
            {
                result               = true;
                defNode              = new FunctionTypeReference();
                defNode.Arguments    = new Dictionary <string, TypeReference>();
                defNode.Returns      = new List <TypeReference>();
                defNode._orderedArgs = new List <string>();
                defNode._isPublic    = isPublic;
                parser.NextToken();
                defNode.StartIndex      = parser.Token.Span.Start;
                defNode._location       = parser.TokenLocation;
                defNode._typeNameString = defNode.Name;

                // TODO: not sure if a function name is allowable...
                if (parser.PeekToken(TokenKind.LeftParenthesis))
                {
                    parser.NextToken();
                    while (parser.PeekToken(TokenCategory.Keyword) || parser.PeekToken(TokenCategory.Identifier))
                    {
                        VariableDefinitionNode varDefNode = null;
                        if (VariableDefinitionNode.TryParseNode(parser, out varDefNode, null, false, false))
                        {
                            // There should only be one vardef since we're not allowing compact definition
                            foreach (var vardef in varDefNode.VariableDefinitions)
                            {
                                defNode.Arguments.Add(vardef.Name, vardef.Type);
                                defNode._orderedArgs.Add(vardef.Name);
                            }
                        }
                        else
                        {
                            parser.ReportSyntaxError("Failed getting argument type.");
                        }
                        if (parser.PeekToken(TokenKind.Comma))
                        {
                            parser.NextToken();
                        }
                    }

                    if (parser.PeekToken(TokenKind.RightParenthesis))
                    {
                        parser.NextToken();
                        ReturnsStatement returnsStatement;
                        if (ReturnsStatement.TryParseNode(parser, out returnsStatement))
                        {
                            foreach (var ret in returnsStatement.ReturnTypes)
                            {
                                defNode.Returns.Add(ret);
                            }
                        }
                    }
                    else
                    {
                        parser.ReportSyntaxError("Missing right paren in function type signature.");
                    }
                }
                else
                {
                    parser.ReportSyntaxError("A function name cannot exist in a function type specifier");
                }
            }

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