private Expression ParsePrimaryExpression() { int start, end, globalStart; Expression ret; // lambda handling List<Parameter> parameters = new List<Parameter>(); Parameter param; bool startBody = false; switch (PeekToken().Kind) { case TokenKind.Name: NameToken nameToken = (NameToken)NextToken(); globalStart = GetStart(); if (_sink != null) _sink.StartName(GetSourceSpan(), nameToken.Name); ret = new NameExpression(nameToken.Name); ret.SetLoc(_globalParent, GetStart(), GetEnd()); if (MaybeEat(TokenKind.Arrow)) { param = new Parameter(nameToken.Name); param.SetLoc(_globalParent, ret.IndexSpan); parameters.Add(param); startBody = true; goto lambda; } return ret; case TokenKind.Constant: ConstantValueToken constantToken = (ConstantValueToken)NextToken(); start = GetStart(); object cv = constantToken.Value; if (cv == null) { ret = new ConstantExpression(null); } else if (cv is bool) { ret = new ConstantExpression((bool)cv); } else if (cv is string) { ret = new ConstantExpression((string)cv); } else if (cv is int) { ret = new ConstantExpression((int)cv); } else if (cv is Uninitialized) { ret = new ConstantExpression(Uninitialized.Instance); } else if (cv is double) { ret = new ConstantExpression((double)cv); } else if (cv is BigInteger) { ret = new ConstantExpression((BigInteger)cv); } else { throw Assert.Unreachable; } ret.SetLoc(_globalParent, GetStart(), GetEnd()); return ret; case TokenKind.LeftParenthesis: NextToken(); start = GetStart(); globalStart = GetStart(); if (PeekToken().Kind == TokenKind.Name) // may be lambda: (a = 2) => a; { NameToken nt = (NameToken)NextToken(); if (PeekToken().Kind == TokenKind.RightParenthesis) { end = GetEnd(); start = GetStart(); NextToken(); if (MaybeEat(TokenKind.Arrow)) { param = new Parameter(nt.Name); param.SetLoc(_globalParent, GetStart(), end); parameters.Add(param); startBody = true; goto lambda; } else { ret = new NameExpression(nt.Name); ret.SetLoc(_globalParent, start, end); ret = new ParenthesisExpression(ret); ret.SetLoc(_globalParent, globalStart, GetEnd()); return ret; } } else if (PeekToken().Kind == TokenKind.Assign) { end = GetEnd(); start = GetStart(); NextToken(); var left = new NameExpression(nt.Name); left.SetLoc(_globalParent, start, end); var right = ParseExpression(); if (PeekToken().Kind == TokenKind.RightParenthesis) { end = GetEnd(); NextToken(); if (MaybeEat(TokenKind.Arrow)) { param = new Parameter(nt.Name, right); param.SetLoc(_globalParent, left.StartIndex, right.EndIndex); parameters.Add(param); startBody = true; goto lambda; } else { ret = new AssignExpression(TokenKind.Assign, left, right); ret.SetLoc(_globalParent, start, end); ret = new ParenthesisExpression(ret); ret.SetLoc(_globalParent, globalStart, GetEnd()); return ret; } } else if (PeekToken().Kind == TokenKind.Comma) { param = new Parameter(nt.Name, right); param.SetLoc(_globalParent, start, GetEnd()); parameters.Add(param); goto lambda; } else { throw Assert.Unreachable; } } else if (PeekToken().Kind == TokenKind.Comma) { param = new Parameter(nt.Name); param.SetLoc(_globalParent, GetStart(), GetEnd()); parameters.Add(param); goto lambda; } else { throw Assert.Unreachable; } } else if (PeekToken(TokenKind.RightParenthesis)) { goto lambda; } else // not NameToken nor RightParen { ret = new ParenthesisExpression(ParseExpression()); Eat(TokenKind.RightParenthesis); ret.SetLoc(_globalParent, globalStart, GetEnd()); return ret; } lambda: // parse the rest of the lambda if (!startBody) { while (MaybeEat(TokenKind.Comma)) { NameToken nt = (NameToken)NextToken(TokenKind.Name); start = GetStart(); Expression defaultVal = MaybeEat(TokenKind.Assign) ? ParseExpression() : null; param = new Parameter(nt.Name, defaultVal); param.SetLoc(_globalParent, start, GetEnd()); parameters.Add(param); } Eat(TokenKind.RightParenthesis); Eat(TokenKind.Arrow); } return ParseLambdaBody(globalStart, parameters.ToArray()); case TokenKind.LeftBracket: return ParseArrayLiteral(); default: return null; // syntax error } }
// arg: ( identifier ':' )? expression private Arg ParseArg() { Arg ret; int start = GetStart(); Expression value = ParseExpression(); if (value is NameExpression) { string name = ((NameExpression)value).Name; int end = GetEnd(); if (MaybeEat(TokenKind.Colon)) { value = ParseExpression(); ret = new Arg(name, value); ret.SetLoc(_globalParent, start, GetEnd()); return ret; } else if (MaybeEat(TokenKind.Arrow)) { var param = new Parameter(name); param.SetLoc(_globalParent, start, end); ret = new Arg(ParseLambdaBody(start, param)); ret.SetLoc(_globalParent, start, GetEnd()); return ret; } } ret = new Arg(value); ret.SetLoc(_globalParent, value.IndexSpan); return ret; }
private Statement ParseFunctionStatement() { Eat(TokenKind.KeywordFunction); var start = GetStart(); var globalStart = start; var name = (NameToken)NextToken(TokenKind.Name); List<Parameter> parameters = new List<Parameter>(); Eat(TokenKind.LeftParenthesis); int lStart = GetStart(), lEnd = GetEnd(); int grouping = _tokenizer.GroupingLevel; if (!MaybeEat(TokenKind.RightParenthesis)) { do { NameToken nt = (NameToken)NextToken(TokenKind.Name); start = GetStart(); Expression defaultVal = MaybeEat(TokenKind.Assign) ? ParseExpression() : null; var param = new Parameter(nt.Name, defaultVal); param.SetLoc(_globalParent, start, GetEnd()); parameters.Add(param); } while (MaybeEat(TokenKind.Comma)); Eat(TokenKind.RightParenthesis); } int rStart = GetStart(), rEnd = GetEnd(); var inFinally = _inFinally; var inLoop = _inLoop; var return_ = _return; var isGenerator = _isGenerator; var isAsync = _isAsync; _inLoop = false; _inFinally = false; _return = false; _isGenerator = false; var ret = new FunctionDefinition(name.Name, parameters.ToArray()); PushFunction(ret); var body = ParseBlock(); FunctionDefinition ret2 = PopFunction(); Debug.Assert(ret == ret2); _inLoop = inLoop; _inFinally = inFinally; _return = return_; _isGenerator = isGenerator; _isAsync = isAsync; ret.Body = body; if(_sink != null) _sink.MatchPair( new SourceSpan(_tokenizer.IndexToLocation(lStart), _tokenizer.IndexToLocation(lEnd)), new SourceSpan(_tokenizer.IndexToLocation(rStart), _tokenizer.IndexToLocation(rEnd)), grouping ); ret.SetLoc(_globalParent, globalStart, GetEnd()); return ret; }