private AST_Helper.Expression parseHashLiteral() { HashLiteral hashLiteral = new HashLiteral { Token = this.curToken }; while (!this.peekTokenIs(TokenHelper.TokenType.RBRACE)) { this.nextToken(); AST_Helper.Expression keyExpr = this.parseExpression(Parser_Helper.precedence.LOWEST); if (!this.expectPeek(TokenHelper.TokenType.COLON)) { return(null); } this.nextToken(); AST_Helper.Expression valueExpr = this.parseExpression(Parser_Helper.precedence.LOWEST); hashLiteral.Pairs.Add(keyExpr, valueExpr); if (!this.peekTokenIs(TokenHelper.TokenType.RBRACE) && !this.expectPeek(TokenHelper.TokenType.COMMA)) { return(null); } } if (!this.expectPeek(TokenHelper.TokenType.RBRACE)) { return(null); } return(hashLiteral); }
//this implements pratt parsing(top down recursive parsing) //DaBeaz's course implemented this with loop instead of recursion (so although top down, it is not recursive). Look in "Solution Items/stuff" folder //for snapshots showing his approach. Not only is it not recursive(he uses loops), but he has also created a func for each precendence level. //his approach is more readable than what we have here. private AST_Helper.Expression parseExpression(Parser_Helper.precedence precedence) { if (!this.prefixParseFns.ContainsKey(this.curToken.Type)) { noPrefixParseFnError(this.curToken.Type); return(null); } Parser_Helper.prefixParserFn prefixParserFn = this.prefixParseFns[this.curToken.Type]; AST_Helper.Expression leftExpr = prefixParserFn(); while (!this.peekTokenIs(TokenHelper.TokenType.SEMICOLON) && precedence < this.peekPrecedence()) { if (!this.infixParseFns.ContainsKey(this.peekToken.Type)) { return(leftExpr); } Parser_Helper.infixParseFn infixParseFn = this.infixParseFns[this.peekToken.Type]; this.nextToken(); leftExpr = infixParseFn(leftExpr);//construct a new leftExpr expression using current leftExpr and next expr as rightExpr } return(leftExpr); }
//this is called parseCallExpression in book. private AST_Helper.Expression parseFunctionCallExpression(AST_Helper.Expression function) { FunctionCallExpression functionCallExpression = new FunctionCallExpression { Token = this.curToken, Function = function }; functionCallExpression.Arguments = this.parseExpressionList(TokenHelper.TokenType.RPAREN); return(functionCallExpression); }
//note that Grouped expression does not have a corresponding AST expression node. We have associated a 'prefixFunction' with LParen //as soon we enouncter that in a expression, we read the expression starting from LParen till RParen in the usual manner. Grouped Expression //is pushed down in the AST and sits at a lower level from non-grouped epxressions thus enforcing the precedence hierarchy. //For the other way around, when we serialize AST Tree, the ToString() method takes care for adding the parenthisis as it goes traversing the tree. private AST_Helper.Expression parseGroupedExpression() { this.nextToken(); AST_Helper.Expression expression = this.parseExpression(Parser_Helper.precedence.LOWEST); if (!this.expectPeek(TokenHelper.TokenType.RPAREN)) { return(null); } return(expression); }
private AST_Helper.Expression parseInfixExpression(AST_Helper.Expression left) { InfixExpression infixExpression = new InfixExpression { Token = this.curToken, Operator = this.curToken.Literal, Left = left }; Parser_Helper.precedence precedence = this.curPrecedence();//precedence level of current token this.nextToken(); //recursice call back to parseExpression. Control arrived here from parseExpression which we are now calling back infixExpression.Right = this.parseExpression(precedence);//it is here we pass precedence using the current context return(infixExpression); }
private AST_Helper.Expression parseIndexExpression(AST_Helper.Expression leftExpr) { ArrayIndexExpression arrayIndexExpression = new ArrayIndexExpression { Token = this.curToken, Left = leftExpr }; this.nextToken(); arrayIndexExpression.Index = this.parseExpression(Parser_Helper.precedence.LOWEST); if (!this.expectPeek(TokenHelper.TokenType.RBRACKET)) { return(null); } return(arrayIndexExpression); }