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