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); }
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); }
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); }
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); }