Skip to content

Latest commit

 

History

History
110 lines (98 loc) · 3.89 KB

File metadata and controls

110 lines (98 loc) · 3.89 KB

2.5解析返回语句

我之前说过,我们将充实我们的空荡的ParseProgram方法。现在是 时候了。我们将解析return语句。第一步,就像之前的let语句一样 它们,是在ast包中定义我们可以表示的必要结构AST中的return语句。

下面是Monkey中的返回语句:

return 5;
return 10;
return add(15);

有了let语句的经验,我们很容易发现这些语句背后的结构:

return <expression>;

返回语句仅有关键字return和表达式组成。这使得ast.ReturnStatement的定义非常简单:

// ast/ast.go
type ReturnStatement struct {
    Token token.Token // the 'return' token
    ReturnValue Expression
}

func (rs *ReturnStatement) statementNode() {}
func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal }

这个节点没有你之前看过的任何东西:它有一个用于初始token的字段和一个包含要返回的表达式的ReturnValue字段。我们现在将再次跳过表达式的解析和分号,但稍后会回到这一点。statementNode和TokenLiteral方法用于完成Node和Statement接口,看起来与*ast.LetStatement上定义的方法相同。我们接下来编写的测试看起来也与let语句的测试非常相似:

// parser/parser_test.go

func TestReturnStatement(t *testing.T) {
    input :=`
    return 5;
    return 10;
    return 993322;
    `
    l := lexer.New(input)
    p := new(l)

    program := p.ParseProgram()
    checkParserErrors(t,p)
    
    if len(program.Statements) != 3 {
t.Fatalf("program.Statements does not contain 3 statements. got=%d",
        len(program.Statements))
    }

    for _, stmt := range program.Statements {
        returnStmt, ok := stmt.(*ast.ReturnStatement)
        if !ok {
            t.Errorf("stmt not *ast.returnStatement. got=%T", stmt)
            continue
        }
        if returnStmt.TokenLiteral() != "return" {
            t.Errorf("returnStmt.TokenLiteral not 'return', got %q",
            returnStmt.TokenLiteral())
        }
    }
}

当然,一旦表达式解析到位,这些测试用例也必须扩展。但是没关系,测试不是一成不变的。 但事实上,他们失败了:

$ go test ./parser
--- FAIL: TestReturnStatements (0.00s)
    parser_test.go:77: program.Statements does not contain 3 statements. got=0
FAIL
FAIL monkey/parser 0.007s

所以让我们改变我们的ParseProgram方法以将token.RETURN标记也考虑在内使它们通过:

// parser/parser.go

func (p *Parser) parseStatement() ast.Statement {
    switch p.curToken.Type {
    case token.LET:
        return p.parseLetStatement()
    case token.RETURN:
        return p.parseReturnStatement()
    default:
        return nil
    }
}

在向你展示之前,我可以对parseReturnStatement方法进行大量模糊处理。但是,好吧,我不会,因为它很小。没什么可模糊表达的。

// parser/parser.go

func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
    stmt := &ast.ReturnStatement{Token: p.curToken}

    p.nextToken()

    // TODO: We're skipping the expressions until we
    // encounter a semicolon
    for !p.curTokenIs(token.SEMICOLON) {
        p.nextToken()
    }

    return stmt
}

我告诉过你:它很小。它仅仅做的事情就是构造了一个ast.ReturnStatement,使用当前token它作为token坐在上面。然后它通过调用nextToken()为接下来的表达式提供解析器,最后,有警察出来了。它跳过每个表达式,直到遇到分号。就是这样,我们的测试通过了:

$ go test ./parser
ok monkey/parser 0.009s

是时候再一次庆祝了!我们现在解析了Monkey语言中所有的语句。好吧:仅仅只有两个语句。let和return语句。语言的其余部分仅由表达式组成。这就是我们接下来要解析的内容。

< 2.4解析器起步:解析LET语句 > 2.6解析表达式