private static CSharpType[] MaybeParseOutOneOfThoseInlineTypeSpecificationsForFunctionInvocations(TokenStream tokens) { int state = tokens.CurrentState; if (!tokens.PopIfPresent("<")) { return(null); } List <CSharpType> types = new List <CSharpType>(); CSharpType type = CSharpType.TryParse(tokens); if (type == null) { tokens.RestoreState(state); return(null); } types.Add(type); while (tokens.PopIfPresent(",")) { type = CSharpType.TryParse(tokens); if (type == null) { tokens.RestoreState(state); return(null); } types.Add(type); } if (tokens.PopIfPresent(">") && tokens.IsNext("(")) { return(types.ToArray()); } tokens.RestoreState(state); return(null); }
public static TopLevelEntity ParseClassMember( ClassLikeDefinition classDef, Token className, ParserContext context, TokenStream tokens) { Token firstToken = tokens.Peek(); Dictionary <string, Token> modifiers = ParseModifiers(context, tokens); if (tokens.IsNext("enum")) { return(ParseEnumDefinition(context, classDef, firstToken, modifiers, tokens)); } if (tokens.IsNext("class")) { return(ParseClass(context, classDef, firstToken, modifiers, tokens)); } if (tokens.IsNext("const")) { return(ParseConstDefinition(context, classDef, firstToken, modifiers, tokens)); } CSharpType type = CSharpType.TryParse(tokens); if (tokens.IsNext("(") && type.SimpleTypeName == className.Value) { return(ParseClassConstructor(context, classDef, firstToken, modifiers, type, tokens)); } Token memberName = tokens.PopWord(); if (tokens.IsNext(";") || tokens.IsNext("=")) { return(ParseClassField(context, classDef, firstToken, modifiers, type, memberName, tokens)); } if (tokens.IsNext("[") && memberName.Value == "this") { return(ParseIndexProperty(context, classDef, firstToken, modifiers, type, tokens)); } if (tokens.IsNext("{")) { return(ParseClassProperty(context, classDef, firstToken, modifiers, type, memberName, tokens)); } if (tokens.IsNext("(")) { return(ParseClassMethod(classDef, context, firstToken, modifiers, type, memberName, tokens)); } throw new ParserException(tokens.Peek(), "Not implemented"); }
private static Expression ParseAtom(ParserContext context, TokenStream tokens, TopLevelEntity parent) { string next = tokens.PeekValue(); switch (next) { case "true": case "false": Token booleanToken = tokens.Pop(); return(new BooleanConstant(booleanToken, booleanToken.Value == "true", parent)); case "null": Token nullToken = tokens.Pop(); return(new NullConstant(nullToken, parent)); case "new": Token newToken = tokens.Pop(); CSharpType className = CSharpType.TryParse(tokens); if (className == null) { throw new ParserException(newToken, "'new' keyword must be followed by a className"); } if (!tokens.IsNext("(")) { // could be a new array of which there are two ways to define it... if (className.IsArray && tokens.IsNext("{")) { List <Expression> arrayItems = new List <Expression>(); tokens.PopExpected("{"); bool nextAllowed = true; while (!tokens.PopIfPresent("}")) { if (!nextAllowed) { tokens.PopExpected("}"); } arrayItems.Add(ExpressionParser.Parse(context, tokens, parent)); nextAllowed = tokens.PopIfPresent(","); } return(new ArrayInitialization(newToken, className.Generics[0], null, arrayItems, parent)); } if (tokens.IsNext("[")) { // a new array with specified length tokens.PopExpected("["); Expression arrayLength = ExpressionParser.Parse(context, tokens, parent); tokens.PopExpected("]"); return(new ArrayInitialization(newToken, className, arrayLength, null, parent)); } // if this isn't an array construction, then give a reasonable error message... tokens.PopExpected("("); } return(new ConstructorInvocationFragment(newToken, className, parent)); case "@": // raw string Token rawStringAt = tokens.Pop(); Token stringValue = tokens.Pop(); string stringValueActual = stringValue.Value; if (stringValueActual[0] != '"') { throw new ParserException(stringValue, "Expected a string value"); } return(new StringConstant(rawStringAt, stringValueActual.Substring(1, stringValueActual.Length - 2), parent)); default: break; } Token token = tokens.Pop(); char c = next[0]; if (c == '"' || c == '\'') { string stringValue = StringUtil.ConvertStringTokenToValue(token); if (c == '"') { return(new StringConstant(token, stringValue, parent)); } else { return(new CharConstant(token, stringValue, parent)); } } if (c == '0' && next.Length > 2 && next[1] == 'x') { string hex = next.Substring(2); int parsedValue = 0; for (int i = 0; i < hex.Length; ++i) { c = hex[i]; if (c >= '0' && c <= '9') { parsedValue = parsedValue * 16 + (c - '0'); } else if (c >= 'a' && c <= 'f') { parsedValue = parsedValue * 16 + (10 + c - 'a'); } else if (c >= 'A' && c <= 'F') { parsedValue = parsedValue * 16 + (10 + c - 'A'); } else { throw new ParserException(token, "Invalid hexidecimal value: '" + hex + "'"); } } return(new IntegerConstant(token, parsedValue, parent)); } if (c == '.' && next.Length > 1) { double value; if (!double.TryParse(next, out value)) { throw new ParserException(token, "Invalid double constant: '" + next + "'"); } return(new DoubleConstant(token, value, parent)); } if (c >= '0' && c <= '9') { if (next.Contains('.')) { if (next.EndsWith("f") || next.EndsWith("F")) { throw new NotImplementedException(); } double floatValue; if (!double.TryParse(next, out floatValue)) { throw new ParserException(token, "Invalid number: '" + next + "'"); } return(new DoubleConstant(token, floatValue, parent)); } else { if (next.EndsWith("f") || next.EndsWith("F")) { throw new NotImplementedException(); } int intValue; if (!int.TryParse(next, out intValue)) { throw new ParserException(token, "Invalid number: '" + next + "'"); } return(new IntegerConstant(token, intValue, parent)); } } if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') { if (tokens.IsNext("=>")) { List <Token> args = new List <Token>() { token }; Token arrowToken = tokens.Pop(); Executable[] lambdaBody; if (tokens.IsNext("{")) { lambdaBody = ExecutableParser.ParseCodeBlock(context, tokens, parent, true); } else { Expression lambdaBodyExpr = Parse(context, tokens, parent); lambdaBody = new Executable[] { new ReturnStatement(lambdaBodyExpr.FirstToken, lambdaBodyExpr, parent), }; } return(new Lambda(token, args, arrowToken, lambdaBody, parent)); } return(new Variable(token, parent)); } throw new ParserException(token, "Unexpected token: '" + token.Value + "'"); }
// this function is called after the first ( is popped off the token stream. // It is destructive to the token stream. private static ParenthesisSituation IdentifyParenthesisSituationImpl(TokenStream tokens) { int state = tokens.CurrentState; // if any of these cause an EOF exception, it's a legit EOF exception. // The }'s alone for any body of code that an expression can appear in would be enough padding // to avoid non-legit errors. Token t1 = tokens.Pop(); Token t2 = tokens.Pop(); Token t3 = tokens.Pop(); if (!t1.IsIdentifier) { return(ParenthesisSituation.WRAPPED_EXPRESSION); } if (t2.Value == ",") { return(ParenthesisSituation.LAMBDA_ARG); } if (t2.Value == ")" && t3.Value == "=>") { return(ParenthesisSituation.LAMBDA_ARG); } if (t2.Value == ")") { switch (t1.Value) { case "string": case "int": case "float": case "double": case "bool": case "object": case "byte": case "char": case "long": return(ParenthesisSituation.CAST); } } tokens.RestoreState(state); CSharpType type = CSharpType.TryParse(tokens); if (type == null || !tokens.IsNext(")")) { return(ParenthesisSituation.WRAPPED_EXPRESSION); } if (type.Generics.Length > 0) { return(ParenthesisSituation.CAST); } if (!tokens.PopIfPresent(")")) { return(ParenthesisSituation.WRAPPED_EXPRESSION); } if (!tokens.HasMore) { return(ParenthesisSituation.WRAPPED_EXPRESSION); } // At this point you have a sequence words and dots in parentheses. Token next = tokens.Peek(); if (next.IsIdentifier || next.IsNumber) { return(ParenthesisSituation.CAST); } char c = next.Value[0]; if (c == '(') { return(ParenthesisSituation.CAST); } if (c == '@') { return(ParenthesisSituation.CAST); } if (c == '.') { return(ParenthesisSituation.WRAPPED_EXPRESSION); } if (c == '!') { return(ParenthesisSituation.CAST); } return(ParenthesisSituation.WRAPPED_EXPRESSION); }
public static Executable Parse(ParserContext context, TokenStream tokens, TopLevelEntity parent, bool enableSemicolon) { switch (tokens.PeekValue()) { case "for": return(ParseForLoop(context, tokens, parent)); case "foreach": return(ParseForEachLoop(context, tokens, parent)); case "if": return(ParseIfStatement(context, tokens, parent)); case "while": return(ParseWhileLoop(context, tokens, parent)); case "do": return(ParseDoWhileLoop(context, tokens, parent)); case "switch": return(ParseSwitchStatement(context, tokens, parent)); case "throw": return(ParseThrowStatement(context, tokens, parent)); case "return": return(ParseReturnStatement(context, tokens, parent)); case "using": return(ParseUsingStatement(context, tokens, parent)); case "try": return(ParseTryStatement(context, tokens, parent)); default: break; } // check for variable declaration int state = tokens.CurrentState; CSharpType variableDeclarationType = CSharpType.TryParse(tokens); if (variableDeclarationType != null) { Token variableName = tokens.PopWordIfPresent(); if (variableName != null && (tokens.IsNext(";") || tokens.IsNext("=") || tokens.IsNext(","))) { // This is a variable declaration. Executable varDecl = ParseVariableDeclaration(context, tokens, variableDeclarationType, variableName, parent); if (enableSemicolon) { tokens.PopExpected(";"); } return(varDecl); } tokens.RestoreState(state); } Expression expr = ExpressionParser.Parse(context, tokens, parent); Executable exec; string nextToken = tokens.PeekValue(); switch (nextToken) { case "=": case "+=": case "-=": case "*=": case "/=": case "%=": case "|=": case "&=": case "^=": case "<<=": case ">>=": Token assignmentOpToken = tokens.Pop(); Expression assignmentValue = ExpressionParser.Parse(context, tokens, parent); exec = new AssignmentStatement(expr.FirstToken, expr, assignmentOpToken, assignmentValue, parent); break; default: exec = new ExpressionAsExecutable(expr, parent); break; } if (enableSemicolon) { tokens.PopExpected(";"); } return(exec); }