// // Parse a strong type alias from a token stream. // // Presently there is no associated data, although it would // probably be desirable to store the base type so that the // IntelliSense tips for the alias can show it. // internal static ParsedObject <StrongAlias> Parse(ParseSession parser) { if (!parser.CheckToken(0, "type")) { return(null); } var nametoken = parser.PeekToken(1); if (nametoken == null) { return(null); } if (!parser.CheckToken(2, ":")) { return(null); } parser.ConsumeTokens(4); var aliastype = new StrongAlias { }; return(new ParsedObject <StrongAlias> { Name = nametoken, Object = aliastype }); }
internal static Variable Parse(ParseSession parser, int starttoken, out int consumedtokens, Origins origin) { consumedtokens = starttoken; if (parser.CheckToken(starttoken + 1, ".")) { return(null); } var basetypename = parser.PeekToken(starttoken); int totaltokens = starttoken + 1; if (parser.CheckToken(totaltokens, "<")) { ++totaltokens; if (!parser.ParseTemplateArguments(totaltokens, basetypename, out totaltokens)) { return(null); } } var varname = parser.PeekToken(totaltokens); if (!parser.CheckToken(totaltokens + 1, "=")) { return(null); } var type = TypeSignatureInstantiated.Construct(parser, starttoken, totaltokens); var variable = new Variable { Name = varname, Origin = origin, Type = type }; totaltokens += 2; Expression.Parse(parser, totaltokens, out totaltokens); while (parser.CheckToken(totaltokens, ",")) { ++totaltokens; Expression.Parse(parser, totaltokens, out totaltokens); } consumedtokens = totaltokens; return(variable); }
// // Helper routine for parsing an assignment statement. // // Returns true if an assignment was seen in the token stream, false // otherwise. A false return does not indicate a syntax error. Also // passes back the index of the next unexamined token. // // Assignments can have associated operations, such as "a += b". // They can also be "chained" as in "a = b = c". However these two // features may not be used in conjunction with one another. // internal static bool ParseAssignment(ParseSession parser, int starttoken, out int consumedtokens) { consumedtokens = starttoken; int totaltokens = starttoken; ++totaltokens; while (parser.CheckToken(totaltokens, ".")) { totaltokens += 2; } if (!parser.CheckToken(totaltokens, "=") && !parser.CheckToken(totaltokens, "+=") && !parser.CheckToken(totaltokens, "-=")) { return(false); } var assignmenttoken = parser.PeekToken(totaltokens); ++totaltokens; bool haschain = true; while (haschain) { while (parser.CheckToken(totaltokens + 1, ".")) { totaltokens += 2; } if (parser.CheckToken(totaltokens + 1, "=")) { if (assignmenttoken.Text != "=") { throw new SyntaxError("Chained assignments must all use the = assignment operator.", parser.PeekToken(totaltokens + 1)); } ++totaltokens; } else { haschain = false; } } var expr = Expression.Parse(parser, totaltokens, out totaltokens); if (expr == null) { return(false); } consumedtokens = totaltokens; return(true); }
internal static ParsedObject <SumType> Parse(ParseSession parser) { int totaltokens = 0; if (!parser.CheckToken(0, "type")) { return(null); } Token sumtypename = parser.PeekToken(1); if (sumtypename == null || string.IsNullOrEmpty(sumtypename.Text)) { return(null); } if (parser.CheckToken(2, "<")) { if (!parser.ParseTemplateParameters(3, sumtypename, out totaltokens)) { return(null); } if (!parser.CheckToken(totaltokens, ":")) { return(null); } } else if (!parser.CheckToken(2, ":")) { return(null); } else if (!parser.CheckToken(4, "|")) { return(null); } else { totaltokens = 2; } do { ++totaltokens; if (parser.CheckToken(totaltokens + 1, "<")) { var token = parser.PeekToken(totaltokens); if (token == null) { return(null); } if (!parser.ParseTemplateArguments(totaltokens + 2, token, out totaltokens)) { return(null); } } else { ++totaltokens; } } while (parser.CheckToken(totaltokens, "|")); // Success! Consume everything and return the constructed result parser.ConsumeTokens(totaltokens); var sumtype = new SumType { }; return(new ParsedObject <SumType> { Name = sumtypename, Object = sumtype }); }
// // Helper routine for parsing a code entity from a token stream. // // This terminology is mostly legacy from an older implementation of Epoch. // An entity is really just a branch/flow-control construct such as a loop // or an if/else statement. Typically there is an expression which controls // execution and an associated code block. // internal static bool ParseEntity(ParseSession parser, LexicalScope parentscope, int starttoken, out int consumedtokens) { consumedtokens = starttoken; int totaltokens = starttoken; if (parser.CheckToken(totaltokens, "if")) { if (!parser.CheckToken(totaltokens + 1, "(")) { return(false); } totaltokens += 2; var expr = Expression.Parse(parser, totaltokens, out totaltokens); if (expr == null) { throw new SyntaxError("if() statement must be supplied with a valid Boolean-typed expression", parser.ReversePeekToken()); } while (parser.CheckToken(totaltokens, ")")) { ++totaltokens; } if (!parser.CheckToken(totaltokens, "{")) { throw new SyntaxError("if() statement must be followed by a code block surrounded in braces { }", parser.PeekToken(totaltokens)); } ++totaltokens; LexicalScope.Parse(parser, parentscope, totaltokens, out totaltokens); while (parser.CheckToken(totaltokens, "elseif")) { totaltokens += 2; var condexpr = Expression.Parse(parser, totaltokens, out totaltokens); if (condexpr == null) { throw new SyntaxError("elseif() statement must be supplied with a valid Boolean-typed expression", parser.ReversePeekToken()); } while (parser.CheckToken(totaltokens, ")")) { ++totaltokens; } if (!parser.CheckToken(totaltokens, "{")) { throw new SyntaxError("elseif() statement must be followed by a code block surrounded in braces { }", parser.PeekToken(totaltokens)); } ++totaltokens; LexicalScope.Parse(parser, parentscope, totaltokens, out totaltokens); } if (parser.CheckToken(totaltokens, "else")) { ++totaltokens; if (!parser.CheckToken(totaltokens, "{")) { throw new SyntaxError("else statement must be followed by a code block surrounded in braces { }", parser.PeekToken(totaltokens)); } ++totaltokens; LexicalScope.Parse(parser, parentscope, totaltokens, out totaltokens); } consumedtokens = totaltokens; return(true); } else if (parser.CheckToken(totaltokens, "while")) { if (!parser.CheckToken(totaltokens + 1, "(")) { throw new SyntaxError("while() statement must be supplied with a valid Boolean-typed expression", parser.ReversePeekToken()); } totaltokens += 2; while (parser.CheckToken(totaltokens, ")")) { ++totaltokens; } var expr = Expression.Parse(parser, totaltokens, out totaltokens); ++totaltokens; if (!parser.CheckToken(totaltokens, "{")) { throw new SyntaxError("while() statement must be followed by a code block surrounded in braces { }", parser.PeekToken(totaltokens)); } ++totaltokens; LexicalScope.Parse(parser, parentscope, totaltokens, out totaltokens); consumedtokens = totaltokens; return(true); } return(false); }
// // Helper function to extract an operator from a token stream. // // Returns true if successful, false if no valid operator was // detected. Does not directly consume tokens; assume exactly // one token can be popped if true is returned. // // Note that this function will return false if a terminating // token (closing parens, etc.) is seen; this should not be // taken to indicate a syntax error. // private static bool ParseExpressionOperator(ParseSession parser, int starttoken) { var token = parser.PeekToken(starttoken); if (token == null) { return(false); } string op = token.Text; if (op == ")") { return(false); } if (op == ",") { return(false); } if (op == "") { return(false); } if (op.Length > 2) { return(false); } if (op == ".") { return(true); } else if (op == "+") { return(true); } else if (op == "-") { return(true); } else if (op == "*") { return(true); } else if (op == "/") { return(true); } else if (op == "==") { return(true); } else if (op == "!=") { return(true); } else if (op == ";") { return(true); } else if (op == ">") { return(true); } else if (op == "<") { return(true); } else if (op == "&") { return(true); } else if (op == "&&") { return(true); } return(false); }
// // Helper function to extract an expression term from a token stream. // // Returns true if a term was found, and passes out the index of the // next token to examine. No tokens should be popped if this helper // returns false. // // Note that in cases where a terminating token is present, such as // a closing parenthesis or a comma, this will return false; however // this does not indicate a syntax error. // private static bool ParseExpressionTerm(ParseSession parser, bool atstart, int starttoken, out int consumedtokens, out bool matchedstatement) { matchedstatement = false; int totaltokens = starttoken; consumedtokens = totaltokens; if (parser.PeekToken(totaltokens) == null) { return(false); } if (parser.CheckToken(totaltokens, ")")) { return(false); } if (parser.CheckToken(totaltokens, ",")) { return(false); } if (parser.CheckToken(totaltokens, "(")) { ++totaltokens; if (Parse(parser, totaltokens, out totaltokens) != null) { ++totaltokens; consumedtokens = totaltokens; return(true); } return(false); } if (parser.CheckToken(totaltokens, "!")) { ++totaltokens; var ret = ParseExpressionTerm(parser, atstart, totaltokens, out totaltokens, out matchedstatement); if (matchedstatement && parser.CheckToken(totaltokens, ")")) { ++totaltokens; } consumedtokens = totaltokens; return(ret); } // The following check is a tiny optimization. Instead of trying to parse // a statement first and then eventually giving up, we first try checking // for common literals. This makes code with literals parse a fractional, // almost insignificant amount faster. It's actually a relic from the way // the compiler implements this logic. Maybe it makes sense to remove it, // and aim for simplicity over ideal efficiency. Profiling data is so far // insufficient to decide for sure, so this stays in the interim. if (parser.CheckToken(totaltokens, "false") || parser.CheckToken(totaltokens, "true") || parser.CheckToken(totaltokens, "0") || parser.CheckToken(totaltokens, "0.0")) { ++totaltokens; } else if (parser.ParsePreopStatement(totaltokens, out totaltokens)) { consumedtokens = totaltokens; return(true); } else if (parser.ParseStatement(totaltokens, out totaltokens)) { matchedstatement = true; consumedtokens = totaltokens; return(true); } else { ++totaltokens; } consumedtokens = totaltokens; return(true); }