private Expression ParseLambda( TokenStream tokens, Token firstToken, IList <AType> argTypes, IList <Token> args, Node owner) { tokens.PopExpected("=>"); Lambda lambda = new Lambda(firstToken, owner, args, argTypes); IList <Executable> lambdaCode; if (tokens.IsNext("{")) { lambdaCode = this.parser.ExecutableParser.ParseBlock(tokens, false, lambda, false); } else { Expression lambdaBodyExpression = this.parser.ExpressionParser.ParseTernary(tokens, lambda); lambdaCode = new Executable[] { new ExpressionAsExecutable(lambdaBodyExpression, lambda) }; } if (lambdaCode.Count == 1 && lambdaCode[0] is ExpressionAsExecutable) { // If a lambda contains a single expression as its code body, then this is an implicit return statement. ExpressionAsExecutable eae = (ExpressionAsExecutable)lambdaCode[0]; lambdaCode[0] = new ReturnStatement(eae.FirstToken, eae.Expression, lambda); } lambda.Code = lambdaCode.ToArray(); return(lambda); }
private Expression ParseIncrement(TokenStream tokens, Node owner) { Expression root; if (tokens.IsNext("++") || tokens.IsNext("--")) { Token incrementToken = tokens.Pop(); root = this.ParseEntity(tokens, owner); return(new Increment(incrementToken, incrementToken, incrementToken.Value == "++", true, root, owner)); } root = this.ParseEntity(tokens, owner); if (tokens.IsNext("++") || tokens.IsNext("--")) { Token incrementToken = tokens.Pop(); return(new Increment(root.FirstToken, incrementToken, incrementToken.Value == "++", false, root, owner)); } return(root); }
internal virtual AnnotationCollection ParseAnnotations(TokenStream tokens) { AnnotationCollection annotationCollection = new AnnotationCollection(this.parser); while (tokens.IsNext("@")) { annotationCollection.Add(this.ParseAnnotation(tokens)); } annotationCollection.Validate(); return(annotationCollection); }
public void ParseFile(string filename, string code) { FileScope fileScope = new FileScope(filename, code, this.CurrentScope, this.GetNextFileId()); this.RegisterFileUsed(fileScope, code); TokenStream tokens = new TokenStream(fileScope); List <string> namespaceImportsBuilder = new List <string>(); // Implicitly import the Core library for the current locale. LocalizedAssemblyView implicitCoreImport = this.ScopeManager.GetCoreLibrary(this); namespaceImportsBuilder.Add(implicitCoreImport.Name); fileScope.Imports.Add(new ImportStatement(null, implicitCoreImport.Name, fileScope)); while (tokens.HasMore && (tokens.IsNext(this.Keywords.IMPORT) || (this.IsCSharpCompat && tokens.IsNext("using")))) { ImportStatement importStatement = this.TopLevelParser.ParseImport(tokens, fileScope); if (importStatement == null) { throw new Exception(); } namespaceImportsBuilder.Add(importStatement.ImportPath); LocalizedAssemblyView localizedAssemblyView = this.ScopeManager.GetOrImportAssembly(this, importStatement.FirstToken, importStatement.ImportPath); if (localizedAssemblyView == null) { this.unresolvedImports.Add(importStatement); } } string[] namespaceImports = namespaceImportsBuilder.ToArray(); while (tokens.HasMore) { this.CurrentScope.AddExecutable(this.TopLevelParser.Parse(tokens, null, fileScope)); } }
public void ParseInterpretedCode(string filename, string code) { FileScope fileScope = new FileScope(filename, this.CurrentScope); int fileId = this.GetNextFileId(); this.RegisterFileUsed(filename, code, fileId); Token[] tokenList = Tokenizer.Tokenize(filename, code, fileId, true); TokenStream tokens = new TokenStream(tokenList, filename); List <string> namespaceImportsBuilder = new List <string>(); // Implicitly import the Core library for the current locale. LocalizedLibraryView implicitCoreImport = this.LibraryManager.GetCoreLibrary(this); namespaceImportsBuilder.Add(implicitCoreImport.Name); fileScope.Imports.Add(new ImportStatement(null, implicitCoreImport.Name, this.CurrentLibrary, fileScope)); while (tokens.HasMore && tokens.IsNext(this.Keywords.IMPORT)) { ImportStatement importStatement = this.ExecutableParser.ParseTopLevel(tokens, null, fileScope) as ImportStatement; if (importStatement == null) { throw new Exception(); } namespaceImportsBuilder.Add(importStatement.ImportPath); LocalizedLibraryView localizedLibraryView = this.LibraryManager.GetOrImportLibrary(this, importStatement.FirstToken, importStatement.ImportPath); if (localizedLibraryView == null) { this.unresolvedImports.Add(importStatement); } } string[] namespaceImports = namespaceImportsBuilder.ToArray(); while (tokens.HasMore) { TopLevelConstruct executable = this.ExecutableParser.ParseTopLevel(tokens, null, fileScope); if (executable is ImportStatement) { throw this.GenerateParseError( ErrorMessages.ALL_IMPORTS_MUST_OCCUR_AT_BEGINNING_OF_FILE, executable.FirstToken); } this.CurrentScope.AddExecutable(executable); } }
private Executable ParseTry(TokenStream tokens, TopLevelConstruct owner) { Token tryToken = tokens.PopExpected(this.parser.Keywords.TRY); IList <Executable> tryBlock = ParserContext.ParseBlock(parser, tokens, true, owner); List <Token> catchTokens = new List <Token>(); List <string[]> exceptionTypes = new List <string[]>(); List <Token[]> exceptionTypeTokens = new List <Token[]>(); List <Token> exceptionVariables = new List <Token>(); List <Executable[]> catchBlocks = new List <Executable[]>(); Token finallyToken = null; IList <Executable> finallyBlock = null; while (tokens.IsNext(this.parser.Keywords.CATCH)) { /* * Parse patterns: * All exceptions: * 1a: catch { ... } * 1b: catch (e) { ... } * * A certain exception: * 2a: catch (ExceptionName) { ... } * 2b: catch (ExceptionName e) { ... } * * Certain exceptions: * 3a: catch (ExceptionName1 | ExceptionName2) { ... } * 3b: catch (ExceptionName1 | ExceptionName2 e) { ... } * * Non-Context-Free alert: * Note that if the exception variable does not contain a '.' character, 1b and 2a are * ambiguous at parse time. Treat them both as 1b and then if the classname resolution * fails, treat this as a variable. * * This is actually kind of bad because a typo in the classname will not be known. * e.g "catch (Excpetion) {" will compile as a variable called "Excpetion" * * End-user workarounds: * - always use a variable name OR * - always fully qualify exception types e.g. Core.Exception * Long-term plan: * - add warning support and emit warnings for: * - unused variables * - style-breaking uppercase variables. */ Token catchToken = tokens.PopExpected(this.parser.Keywords.CATCH); List <string> classNames = new List <string>(); List <Token> classTokens = new List <Token>(); Token variableToken = null; if (tokens.PopIfPresent("(")) { // This first one might actually be a variable. Assume class for now and sort it out later. // (and by "later" I mean the ResolveNames phase) Token classFirstToken = tokens.Pop(); string className = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classFirstToken); classNames.Add(className); classTokens.Add(classFirstToken); while (tokens.PopIfPresent("|")) { classFirstToken = tokens.Pop(); className = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classFirstToken); classNames.Add(className); classTokens.Add(classFirstToken); } if (!tokens.IsNext(")")) { variableToken = tokens.Pop(); this.parser.VerifyIdentifier(variableToken); } tokens.PopExpected(")"); } else { classNames.Add(null); classTokens.Add(null); } Executable[] catchBlockCode = ParserContext.ParseBlock(parser, tokens, true, owner).ToArray(); catchTokens.Add(catchToken); exceptionTypes.Add(classNames.ToArray()); exceptionTypeTokens.Add(classTokens.ToArray()); exceptionVariables.Add(variableToken); catchBlocks.Add(catchBlockCode); } if (tokens.IsNext(this.parser.Keywords.FINALLY)) { finallyToken = tokens.Pop(); finallyBlock = ParserContext.ParseBlock(parser, tokens, true, owner); } return(new TryStatement(tryToken, tryBlock, catchTokens, exceptionVariables, exceptionTypeTokens, exceptionTypes, catchBlocks, finallyToken, finallyBlock, owner)); }
private Executable ParseSwitch(TokenStream tokens, TopLevelConstruct owner) { Token switchToken = tokens.PopExpected(this.parser.Keywords.SWITCH); Expression explicitMax = null; Token explicitMaxToken = null; if (tokens.IsNext("{")) { explicitMaxToken = tokens.Pop(); explicitMax = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected("}"); } tokens.PopExpected("("); Expression condition = this.parser.ExpressionParser.Parse(tokens, owner); tokens.PopExpected(")"); tokens.PopExpected("{"); List <List <Expression> > cases = new List <List <Expression> >(); List <Token> firstTokens = new List <Token>(); List <List <Executable> > code = new List <List <Executable> >(); char state = '?'; // ? - first, O - code, A - case bool defaultEncountered = false; while (!tokens.PopIfPresent("}")) { if (tokens.IsNext(this.parser.Keywords.CASE)) { if (defaultEncountered) { throw new ParserException(tokens.Peek(), "default condition in a switch statement must be the last condition."); } Token caseToken = tokens.PopExpected(this.parser.Keywords.CASE); if (state != 'A') { cases.Add(new List <Expression>()); firstTokens.Add(caseToken); code.Add(null); state = 'A'; } cases[cases.Count - 1].Add(this.parser.ExpressionParser.Parse(tokens, owner)); tokens.PopExpected(":"); } else if (tokens.IsNext(this.parser.Keywords.DEFAULT)) { Token defaultToken = tokens.PopExpected(this.parser.Keywords.DEFAULT); if (state != 'A') { cases.Add(new List <Expression>()); firstTokens.Add(defaultToken); code.Add(null); state = 'A'; } cases[cases.Count - 1].Add(null); tokens.PopExpected(":"); defaultEncountered = true; } else { if (state != 'O') { cases.Add(null); firstTokens.Add(null); code.Add(new List <Executable>()); state = 'O'; } code[code.Count - 1].Add(this.parser.ExecutableParser.Parse(tokens, false, true, owner)); } } return(new SwitchStatement(switchToken, condition, firstTokens, cases, code, explicitMax, explicitMaxToken, owner)); }
private ClassDefinition ParseClassDefinition(TokenStream tokens, TopLevelConstruct owner, Token staticToken, Token finalToken, FileScope fileScope, AnnotationCollection classAnnotations) { Token classToken = tokens.PopExpected(this.parser.Keywords.CLASS); Token classNameToken = tokens.Pop(); this.parser.VerifyIdentifier(classNameToken); List <Token> baseClassTokens = new List <Token>(); List <string> baseClassStrings = new List <string>(); if (tokens.PopIfPresent(":")) { if (baseClassTokens.Count > 0) { tokens.PopExpected(","); } Token baseClassToken = tokens.Pop(); string baseClassName = baseClassToken.Value; this.parser.VerifyIdentifier(baseClassToken); while (tokens.PopIfPresent(".")) { Token baseClassTokenNext = tokens.Pop(); this.parser.VerifyIdentifier(baseClassTokenNext); baseClassName += "." + baseClassTokenNext.Value; } baseClassTokens.Add(baseClassToken); baseClassStrings.Add(baseClassName); } ClassDefinition cd = new ClassDefinition( classToken, classNameToken, baseClassTokens, baseClassStrings, owner, parser.CurrentLibrary, staticToken, finalToken, fileScope, classAnnotations); tokens.PopExpected("{"); List <FunctionDefinition> methods = new List <FunctionDefinition>(); List <FieldDeclaration> fields = new List <FieldDeclaration>(); ConstructorDefinition constructorDef = null; ConstructorDefinition staticConstructorDef = null; while (!tokens.PopIfPresent("}")) { AnnotationCollection annotations = this.parser.AnnotationParser.ParseAnnotations(tokens); if (tokens.IsNext(this.parser.Keywords.FUNCTION) || tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.FUNCTION)) { methods.Add(this.parser.ExecutableParser.ParseFunction(tokens, cd, fileScope, annotations)); } else if (tokens.IsNext(this.parser.Keywords.CONSTRUCTOR)) { if (constructorDef != null) { throw this.parser.GenerateParseError( ErrorMessages.CLASS_CANNOT_HAVE_MULTIPLE_CONSTRUCTORS, tokens.Pop()); } constructorDef = this.parser.ExecutableParser.ParseConstructor(tokens, cd, annotations); } else if (tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.CONSTRUCTOR)) { tokens.Pop(); // static token if (staticConstructorDef != null) { throw new ParserException(tokens.Pop(), "Multiple static constructors are not allowed."); } staticConstructorDef = this.parser.ExecutableParser.ParseConstructor(tokens, cd, annotations); } else if (tokens.IsNext(this.parser.Keywords.FIELD) || tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.FIELD)) { fields.Add(this.parser.ExecutableParser.ParseField(tokens, cd, annotations)); } else { tokens.PopExpected("}"); } TODO.CheckForUnusedAnnotations(); } cd.Methods = methods.ToArray(); cd.Constructor = constructorDef; cd.StaticConstructor = staticConstructorDef; cd.Fields = fields.ToArray(); return(cd); }
private Expression ParseEntityWithoutSuffixChain(TokenStream tokens, Node owner) { tokens.EnsureNotEof(); Token nextToken = tokens.Peek(); string next = nextToken.Value; if (next == this.parser.Keywords.NULL) { return(new NullConstant(tokens.Pop(), owner)); } if (next == this.parser.Keywords.TRUE) { return(new BooleanConstant(tokens.Pop(), true, owner)); } if (next == this.parser.Keywords.FALSE) { return(new BooleanConstant(tokens.Pop(), false, owner)); } if (next == this.parser.Keywords.THIS) { return(new ThisKeyword(tokens.Pop(), owner)); } if (next == this.parser.Keywords.BASE) { return(new BaseKeyword(tokens.Pop(), owner)); } Token peekToken = tokens.Peek(); if (next.StartsWith("'")) { return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner)); } if (next.StartsWith("\"")) { return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner)); } if (next == "@") // Raw strings (no escape sequences, a backslash is a literal backslash) { Token atToken = tokens.Pop(); Token stringToken = tokens.Pop(); char stringTokenChar = stringToken.Value[0]; if (stringTokenChar != '"' && stringTokenChar != '\'') { throw new ParserException(atToken, "Unexpected token: '@'"); } string stringValue = stringToken.Value.Substring(1, stringToken.Value.Length - 2); return(new StringConstant(atToken, stringValue, owner)); } if (next == this.parser.Keywords.NEW) { return(this.ParseInstantiate(tokens, owner)); } char firstChar = next[0]; if (nextToken.Type == TokenType.WORD) { Token varToken = tokens.Pop(); if (tokens.IsNext("=>")) { return(this.ParseLambda( tokens, varToken, new AType[] { AType.Any() }, new Token[] { varToken }, owner)); } else { return(new Variable(varToken, varToken.Value, owner)); } } if (firstChar == '[' && nextToken.File.CompilationScope.IsCrayon) { Token bracketToken = tokens.PopExpected("["); List <Expression> elements = new List <Expression>(); bool previousHasCommaOrFirst = true; while (!tokens.PopIfPresent("]")) { if (!previousHasCommaOrFirst) { tokens.PopExpected("]"); // throws appropriate error } elements.Add(Parse(tokens, owner)); previousHasCommaOrFirst = tokens.PopIfPresent(","); } return(new ListDefinition(bracketToken, elements, AType.Any(), owner, false, null)); } if (firstChar == '{' && nextToken.File.CompilationScope.IsCrayon) { Token braceToken = tokens.PopExpected("{"); List <Expression> keys = new List <Expression>(); List <Expression> values = new List <Expression>(); bool previousHasCommaOrFirst = true; while (!tokens.PopIfPresent("}")) { if (!previousHasCommaOrFirst) { tokens.PopExpected("}"); // throws appropriate error } keys.Add(Parse(tokens, owner)); tokens.PopExpected(":"); values.Add(Parse(tokens, owner)); previousHasCommaOrFirst = tokens.PopIfPresent(","); } return(new DictionaryDefinition(braceToken, AType.Any(), AType.Any(), keys, values, owner)); } if (nextToken.Type == TokenType.NUMBER) { if (next.Contains(".")) { double floatValue; if (double.TryParse(next, out floatValue)) { return(new FloatConstant(tokens.Pop(), floatValue, owner)); } throw new ParserException(nextToken, "Invalid float literal."); } return(new IntegerConstant( tokens.Pop(), IntegerConstant.ParseIntConstant(nextToken, next), owner)); } throw new ParserException(tokens.Peek(), "Encountered unexpected token: '" + tokens.PeekValue() + "'"); }
private Expression ParseEntity(TokenStream tokens, Node owner) { Expression root; Token firstToken = tokens.Peek(); AType castPrefix = firstToken.Value == "(" ? this.MaybeParseCastPrefix(tokens) : null; if (castPrefix != null) { root = this.ParseEntity(tokens, owner); return(new Cast(firstToken, castPrefix, root, owner, true)); } Token maybeOpenParen = tokens.Peek(); if (tokens.PopIfPresent("(")) { if (tokens.PopIfPresent(")")) { root = this.ParseLambda(tokens, firstToken, new AType[0], new Token[0], owner); } else { if (this.parser.CurrentScope.IsStaticallyTyped) { TokenStream.StreamState state = tokens.RecordState(); AType lambdaArgType = this.parser.TypeParser.TryParse(tokens); Token lambdaArg = null; if (lambdaArgType != null) { lambdaArg = tokens.PopIfWord(); } if (lambdaArg != null) { List <AType> lambdaArgTypes = new List <AType>() { lambdaArgType }; List <Token> lambdaArgs = new List <Token>() { lambdaArg }; while (tokens.PopIfPresent(",")) { lambdaArgTypes.Add(this.parser.TypeParser.Parse(tokens)); lambdaArgs.Add(tokens.PopWord()); } tokens.PopExpected(")"); return(this.ParseLambda(tokens, maybeOpenParen, lambdaArgTypes, lambdaArgs, owner)); } else { tokens.RestoreState(state); } } root = this.Parse(tokens, owner); if (root is Variable) { if (tokens.PopIfPresent(")")) { if (tokens.IsNext("=>")) { root = this.ParseLambda(tokens, firstToken, new AType[] { AType.Any(root.FirstToken) }, new Token[] { root.FirstToken }, owner); } } else if (tokens.IsNext(",")) { List <Token> lambdaArgs = new List <Token>() { root.FirstToken }; List <AType> lambdaArgTypes = new List <AType>() { AType.Any(root.FirstToken) }; Token comma = tokens.Peek(); while (tokens.PopIfPresent(",")) { Token nextArg = tokens.Pop(); if (nextArg.Type != TokenType.WORD) { throw new ParserException(comma, "Unexpected comma."); } lambdaArgTypes.Add(AType.Any(nextArg)); lambdaArgs.Add(nextArg); comma = tokens.Peek(); } tokens.PopExpected(")"); root = this.ParseLambda(tokens, firstToken, lambdaArgTypes, lambdaArgs, owner); } else { // This will purposely cause an unexpected token error // since it's none of the above conditions. tokens.PopExpected(")"); } } else { tokens.PopExpected(")"); } } } else { root = ParseEntityWithoutSuffixChain(tokens, owner); } bool anySuffixes = true; bool isPreviousADot = false; while (anySuffixes) { if (tokens.IsNext(".")) { isPreviousADot = true; Token dotToken = tokens.Pop(); Token fieldToken = tokens.Pop(); // HACK alert: "class" is a valid field on a class. // ParserVerifyIdentifier is invoked downstream for non-resolved fields. if (fieldToken.Value != this.parser.Keywords.CLASS) { this.parser.VerifyIdentifier(fieldToken); } root = new DotField(root, dotToken, fieldToken, owner); } else if (tokens.IsNext("[")) { Token openBracket = tokens.Pop(); List <Expression> sliceComponents = new List <Expression>(); if (tokens.IsNext(":")) { sliceComponents.Add(null); } else { sliceComponents.Add(Parse(tokens, owner)); } for (int i = 0; i < 2; ++i) { if (tokens.PopIfPresent(":")) { if (tokens.IsNext(":") || tokens.IsNext("]")) { sliceComponents.Add(null); } else { sliceComponents.Add(Parse(tokens, owner)); } } } tokens.PopExpected("]"); if (sliceComponents.Count == 1) { Expression index = sliceComponents[0]; root = new BracketIndex(root, openBracket, index, owner); } else { root = new ListSlice(root, sliceComponents, openBracket, owner); } } else if (tokens.IsNext("(")) { Token openParen = tokens.Pop(); List <Expression> args = new List <Expression>(); while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(Parse(tokens, owner)); } root = new FunctionCall(root, openParen, args, owner); } else if (tokens.IsNext(this.parser.Keywords.IS)) { Token isToken = tokens.Pop(); Token classToken = tokens.Pop(); string className = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classToken); root = new IsComparison(root, isToken, classToken, className, owner); } else if (isPreviousADot && this.parser.IsCSharpCompat && tokens.IsNext("<")) { TokenStream.StreamState s = tokens.RecordState(); Token openBracket = tokens.Pop(); AType funcType = this.parser.TypeParser.TryParse(tokens); List <AType> types = new List <AType>() { funcType }; if (funcType != null) { while (tokens.PopIfPresent(",")) { types.Add(this.parser.TypeParser.Parse(tokens)); } } if (funcType == null) { anySuffixes = false; tokens.RestoreState(s); } else if (!tokens.PopIfPresent(">") || !tokens.IsNext("(")) { anySuffixes = false; tokens.RestoreState(s); } else { // TODO(acrylic-conversion): do something with this types list. } } else { anySuffixes = false; } } return(root); }
private Expression ParseEntityWithoutSuffixChain(TokenStream tokens, TopLevelConstruct owner) { string next = tokens.PeekValue(); if (next == null) { tokens.ThrowEofException(); } if (next == this.parser.Keywords.NULL) { return(new NullConstant(tokens.Pop(), owner)); } if (next == this.parser.Keywords.TRUE) { return(new BooleanConstant(tokens.Pop(), true, owner)); } if (next == this.parser.Keywords.FALSE) { return(new BooleanConstant(tokens.Pop(), false, owner)); } Token peekToken = tokens.Peek(); if (next.StartsWith("'")) { return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner)); } if (next.StartsWith("\"")) { return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner)); } if (next == this.parser.Keywords.NEW) { return(this.ParseInstantiate(tokens, owner)); } char firstChar = next[0]; if (VARIABLE_STARTER.Contains(firstChar)) { Token varToken = tokens.Pop(); return(new Variable(varToken, varToken.Value, owner)); } if (firstChar == '[') { Token bracketToken = tokens.PopExpected("["); List <Expression> elements = new List <Expression>(); bool previousHasCommaOrFirst = true; while (!tokens.PopIfPresent("]")) { if (!previousHasCommaOrFirst) { tokens.PopExpected("]"); // throws appropriate error } elements.Add(Parse(tokens, owner)); previousHasCommaOrFirst = tokens.PopIfPresent(","); } return(new ListDefinition(bracketToken, elements, owner)); } if (firstChar == '{') { Token braceToken = tokens.PopExpected("{"); List <Expression> keys = new List <Expression>(); List <Expression> values = new List <Expression>(); bool previousHasCommaOrFirst = true; while (!tokens.PopIfPresent("}")) { if (!previousHasCommaOrFirst) { tokens.PopExpected("}"); // throws appropriate error } keys.Add(Parse(tokens, owner)); tokens.PopExpected(":"); values.Add(Parse(tokens, owner)); previousHasCommaOrFirst = tokens.PopIfPresent(","); } return(new DictionaryDefinition(braceToken, keys, values, owner)); } if (next.Length > 2 && next.Substring(0, 2) == "0x") { Token intToken = tokens.Pop(); int intValue = IntegerConstant.ParseIntConstant(intToken, intToken.Value); return(new IntegerConstant(intToken, intValue, owner)); } if (ParserContext.IsInteger(next)) { Token numberToken = tokens.Pop(); string numberValue = numberToken.Value; if (tokens.IsNext(".")) { Token decimalToken = tokens.Pop(); if (decimalToken.HasWhitespacePrefix) { throw new ParserException(decimalToken, "Decimals cannot have whitespace before them."); } Token afterDecimal = tokens.Pop(); if (afterDecimal.HasWhitespacePrefix) { throw new ParserException(afterDecimal, "Cannot have whitespace after the decimal."); } if (!ParserContext.IsInteger(afterDecimal.Value)) { throw new ParserException(afterDecimal, "Decimal must be followed by an integer."); } numberValue += "." + afterDecimal.Value; double floatValue = FloatConstant.ParseValue(numberToken, numberValue); return(new FloatConstant(numberToken, floatValue, owner)); } int intValue = IntegerConstant.ParseIntConstant(numberToken, numberToken.Value); return(new IntegerConstant(numberToken, intValue, owner)); } if (tokens.IsNext(".")) { Token dotToken = tokens.PopExpected("."); string numberValue = "0."; Token postDecimal = tokens.Pop(); if (postDecimal.HasWhitespacePrefix || !ParserContext.IsInteger(postDecimal.Value)) { throw new ParserException(dotToken, "Unexpected dot."); } numberValue += postDecimal.Value; double floatValue; if (Util.ParseDouble(numberValue, out floatValue)) { return(new FloatConstant(dotToken, floatValue, owner)); } throw new ParserException(dotToken, "Invalid float literal."); } throw new ParserException(tokens.Peek(), "Encountered unexpected token: '" + tokens.PeekValue() + "'"); }
private Expression ParseEntity(TokenStream tokens, TopLevelConstruct owner) { Expression root; if (tokens.PopIfPresent("(")) { root = this.Parse(tokens, owner); tokens.PopExpected(")"); } else { root = ParseEntityWithoutSuffixChain(tokens, owner); } bool anySuffixes = true; while (anySuffixes) { if (tokens.IsNext(".")) { Token dotToken = tokens.Pop(); Token stepToken = tokens.Pop(); // HACK alert: "class" is a valid field on a class. // ParserVerifyIdentifier is invoked downstream for non-resolved fields. if (stepToken.Value != this.parser.Keywords.CLASS) { this.parser.VerifyIdentifier(stepToken); } root = new DotStep(root, dotToken, stepToken, owner); } else if (tokens.IsNext("[")) { Token openBracket = tokens.Pop(); List <Expression> sliceComponents = new List <Expression>(); if (tokens.IsNext(":")) { sliceComponents.Add(null); } else { sliceComponents.Add(Parse(tokens, owner)); } for (int i = 0; i < 2; ++i) { if (tokens.PopIfPresent(":")) { if (tokens.IsNext(":") || tokens.IsNext("]")) { sliceComponents.Add(null); } else { sliceComponents.Add(Parse(tokens, owner)); } } } tokens.PopExpected("]"); if (sliceComponents.Count == 1) { Expression index = sliceComponents[0]; root = new BracketIndex(root, openBracket, index, owner); } else { root = new ListSlice(root, sliceComponents, openBracket, owner); } } else if (tokens.IsNext("(")) { Token openParen = tokens.Pop(); List <Expression> args = new List <Expression>(); while (!tokens.PopIfPresent(")")) { if (args.Count > 0) { tokens.PopExpected(","); } args.Add(Parse(tokens, owner)); } root = new FunctionCall(root, openParen, args, owner); } else if (tokens.IsNext(this.parser.Keywords.IS)) { Token isToken = tokens.Pop(); Token classToken = tokens.Pop(); string className = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classToken); root = new IsComparison(root, isToken, classToken, className, owner); } else { anySuffixes = false; } } return(root); }