Statement. got=%T",
			program.Statements[0])
	}

	literal, ok := stmt.Expression.(*ast.IntegerLiteral)
	if!ok {
		t.Fatalf("exp not *ast.IntegerLiteral. got=%T", stmt.Expression)
	}
	if literal.Value!= 5 {
		t.Errorf("literal.Value not %d. got=%d", 5, literal.Value)
	}
	if literal.TokenLiteral()!= "5" {
		t.Errorf("literal.TokenLiteral not %s. got=%s", "5",
			literal.TokenLiteral())
	}
}
```
就像在标识符的测试用例中一样，我们使用一个简单的输入，将它提供给解析器，然后检查解析器没有遇到任何错误并在*ast.Program.Statements中生成正确数量的语句。然后我们添加一个断言，即第一条语句是 *ast.ExpressionStatement。最后我们期待一个格式良好的 *ast.IntegerLiteral。测试不会编译，因为 *ast.IntergerLiteral还不存在。定义它很容易：
```go
// ast/ast.go

type IntegerLiteral struct {
    Token token.Token
    Value int64
}
func (il *IntegerLiteral) expressionNode() {}
func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }
func (il *IntegerLiteral) String() string { return il.Token.Literal }
```

*ast.IntegerLiteral 实现了 ast.Expression 接口，就像 *ast.Identifier 一样，但在结构本身上与 ast.Identifier 有显着区别：Value 是一个 int64 而不是字符串。 这是将包含整数文字在源代码中表示的实际值的字段。 当我们构建 *ast.IntegerLiteral 时，我们必须将 *ast.IntegerLiteral.Token.Literal 中的字符串（类似于“5”）转换为 int64。

最好的做的方式是在解析函数中和token.INT联系起来，叫做parseIntegerLiteral:
```go
// parser/parser.go

import (
// [...]
    "strconv"
)

func (p *Parser) parseIntegerLiteral() ast.Expression {
    lit := &ast.IntegerLiteral{Token: p.curToken}

    value, err := strconv.ParseInt(p.curToken.Literal, 0, 64)
    if err!= nil {
        msg := fmt.Sprintf("could not parse %q as integer", p.curToken.Literal)
        p.errors = append(p.errors, msg)
        return nil
    }

    lit.Value = value

    return lit
}

```
像parseIdentifier方法简单。唯一不同的是调用strconv.Parselnt,它将p.curToken.Literal中的字符串转换为int64。然后int64被保存到Value字段，我们返回新构造的*ast.IntegerLiteral节点。如果这不起作用，我们会在解析器的错误字段中添加一个新错误。

但是测试还没有运行：
```go
$ go test./parser
--- FAIL: TestIntegerLiteralExpression (0.00s)
parser_test.go:162: exp not *ast.IntegerLiteral. got=<nil>
FAIL
FAIL monkey/parser 0.008s
```
我们有nil代替一个*ast.IntegerLiteral在我们的AST。原因就是parseExpression无法为 token.INT 类型的标记找到 prefixParseFn。。为了让测试通过，我们所要做的就是注册我们的 parseIntegerLiteral 方法：
```go
// parser/parser.go

func New(l *lexer.Lexer) *Parser {
// [...]
    p.prefixParseFns = make(map[token.TokenType]prefixParseFn)
    p.registerPrefix(token.IDENT, p.parseIdentifier)
    p.registerPrefix(token.INT, p.parseIntegerLiteral)

// [...]
}
```
随着ParseIntegerLiteral注册了，parseExpression现在知道如何处理token.INT token，调用 parseIntegerLiteral 并返回它的返回值，一个 *ast.IntegerLiteral。 这次测试通过了：
```go
$ go test./parser
ok monkey/parser 0.007s
```
我认为是时候说：我们顺利运行了！ 标识符和整数文字都在包里，让我们更进一步，解析前缀运算符。
## 前缀运算符
在Monkey语言中有两种前缀运算符:!和-。它们的用法与您对其他语言的期望非常相似：
```go
-5;
!foobar;
5 + -10;
```
它们遵循的使用结构：
```
<prefix operator><expression>;
```
是的，好吧。一些表达式能遵循一个前缀运算符作为一个文字。这些是有效的:
```go
!isGreaterThanZero(2);
5 + -add(5, 5);
```
这意味着前缀运算符表达式的 AST 节点必须足够灵活以
指向任何表达式作为其操作数。

但首先，这是前缀运算符或“前缀表达式”的测试用例：
```go
// parser/parser_test.go

func TestParsingPrefixExpressions(t *testing.T) {
	prefixTests := []struct {
		input    string
		operator string
		value    interface{}
	}{
		{"!5;", "!", 5},
		{"-15;", "-", 15},
		{"!foobar;", "!", "foobar"},
		{"-foobar;", "-", "foobar"},
		{"!true;", "!", true},
		{"!false;", "!", false},
	}

	for _, tt := range prefixTests {
		l := lexer.New(tt.input)
		p := New(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		if len(program.Statements)!= 1 {
			t.Fatalf("program.Statements does not contain %d statements. got=%d\n",
				1, len(program.Statements))
		}

		stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
		if!ok {
			t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T",
				program.Statements[0])
		}

		exp, ok := stmt.Expression.(*ast.PrefixExpression)
		if!ok {
			t.Fatalf("stmt is not ast.PrefixExpression. got=%T", stmt.Expression)
		}
		if exp.Operator!= tt.operator {
			t.Fatalf("exp.Operator is not '%s'. got=%s",
				tt.operator, exp.Operator)
		}
		if!testLiteralExpression(t, exp.Right, tt.value) {
			return
		}
	}
}
```
这个测试函数，再一次，有很多行:(有两个原因：手动闯进错误信息t.Errorf占用了一些空间，我们正在使用表驱动的测试方法。原因是它结尾我们节省了两个测试用例，但是重复每个案例的完整测试意味着很多行。而且由于背后逻辑的测试断言相同，