• 《用Go语言自制解释器》之第3章 求值


    第3章 求值

    3.1 为符号赋予含义

    let num = 5;
    if(num) {
    	return a;
    } else {
    	return b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    len one = fn() {
    	printLine("one");
    	return 1;
    };
    
    len two = fn() {
    	printLine("two");
    	return 2;
    };
    
    add(one(), two());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.2 求值策略

    解释器不会生成可执行文件,编译器会。
    树遍历解释器,遍历AST,访问每个节点并执行该节点的语义,实时进行。

    3.3 树遍历解释器

    直接解释AST,无预处理和编译步骤。
    eval函数,对AST求值。

    3.4 表示对象

    eval函数返回内容添加定义,表示AST值或AST求值时内存中生成的值。

    3.4.1 对象系统的基础

    // object/object.go
    package object
    
    type ObjectType string
    
    type Object interface {
    	Type() ObjectType
    	Inspect() string
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.4.2 整数

    // object/object.go
    package object
    
    import "fmt"
    
    const (
    	INTEGER_OBJ = "INTEGER"
    )
    
    type Integer struct {
    	Value int64
    }
    func (i *Integer) Type() ObjectType { return INTEGER_OBJ }
    func (i *Integer) Inspect() string  { return fmt.Sprintf("%d", i.Value) }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.4.3 布尔值

    // object/object.go
    const (
    	BOOLEAN_OBJ = "BOOLEAN"
    )
    
    type Boolean struct {
    	Value bool
    }
    func (b *Boolean) Type() ObjectType { return BOOLEAN_OBJ }
    func (b *Boolean) Inspect() string  { return fmt.Sprintf("%t", b.Value) }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.4.4 空值

    null表示缺失值的值。

    // object/object.go
    const (
    	NULL_OBJ  = "NULL"
    )
    
    type Null struct{}
    func (n *Null) Type() ObjectType { return NULL_OBJ }
    func (n *Null) Inspect() string  { return "null" }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.5 求值表达式

    func Eval(node ast.Node) object.Object
    
    • 1

    3.5.1 整数字面量

    // evaluator/evaluator.go
    package evaluator
    
    import (
    	"monkey/ast"
    	"monkey/object"
    )
    
    func Eval(node ast.Node) object.Object {
    	switch node := node.(type) {
    	case *ast.Program:
    		return evalStatements(node.Statements)
    		
    	case *ast.ExpressionStatement:
    		return Eval(node.Expression)
    		
    	case *ast.IntegerLiteral:
    		return &object.Integer{Value: node.Value}
    	}
    
    	return nil
    }
    
    func evalStatements(stmts []ast.Statement) object.Object {
    	var result object.Object
    	
    	for _, statement := range stmts {
    		result = Eval(statement)
    	}
    	return result
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    3.5.2 完成REPL

    Read-Evaluate-Print Loop

    // repl/repl.go
    package repl
    
    import (
    	"monkey/evaluator"
    )
    
    func Start(in io.Reader, out io.Writer) {
    	scanner := bufio.NewScanner(in)
    
    	for {
    		fmt.Fprintf(out, PROMPT)
    		scanned := scanner.Scan()
    		if !scanned {
    			return
    		}
    
    		line := scanner.Text()
    		l := lexer.New(line)
    		
    		p := parser.New(l)
    		program := p.ParseProgram()
    		if len(p.Errors()) != 0 {
    			printParserErrors(out, p.Errors())
    			continue
    		}
    		
    		if evaluated := evaluator.Eval(program); evaluated != nil {	
    			io.WriteString(out, evaluated.Inspect() + "\n")
    		}
    
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    3.5.3 布尔字面量

    // evaluator/evaluator.go
    package evaluator
    
    var (
    	TRUE  = &object.Boolean{Value: true}
    	FALSE = &object.Boolean{Value: false}
    )
    
    func Eval(node ast.Node) object.Object {
    	switch node := node.(type) {
    	case *ast.Program:
    		return evalStatements(node.Statements)
    		
    	case *ast.ExpressionStatement:
    		return Eval(node.Expression)
    		
    	case *ast.IntegerLiteral:
    		return &object.Integer{Value: node.Value}
    		
    	case *ast.Boolean:
    		return nativeBoolToBooleanObject(node.Value)
    	}
    
    	return nil
    }
    
    func nativeBoolToBooleanObject(input bool) *object.Boolean {
    	if input {
    		return TRUE
    	}
    	return FALSE
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3.5.4 空值

    // evaluator/evaluator.go
    package evaluator
    
    var (
    	NULL  = &object.Null{}
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.5.5 前缀表达式

    // evaluator/evaluator.go
    
    func Eval(node ast.Node) object.Object {
    	switch node := node.(type) {
    	case *ast.PrefixExpression:
    		return nativeBoolToBooleanObject(node.Value)
    	}
    
    	return nil
    }
    
    func evalPrefixExpression(operator string, right object.Object) object.Object {
    	switch operator {
    	case "!":
    		return evalBangOperatorExpression(right)
    	case "-":
    		return evalMinusPrefixOperatorExpression(right)
    	default:
    		return NULL
    	}
    }
    
    func evalBangOperatorExpression(right object.Object) object.Object {
    	switch right {
    	case TRUE:
    		return FALSE
    	case FALSE:
    		return TRUE
    	case NULL:
    		return TRUE
    	default:
    		return FALSE
    	}
    }
    
    func evalMinusPrefixOperatorExpression(right object.Object) object.Object {
    	if right.Type() != object.INTEGER_OBJ {
    		return NULL
    	}
    
    	value := right.(*object.Integer).Value
    	return &object.Integer{Value: -value}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    3.5.6 中缀表达式

    // evaluator/evaluator.go
    
    func Eval(node ast.Node) object.Object {
    	switch node := node.(type) {
    	case *ast.InfixExpression:
    		left := Eval(node.Left)
    		right := Eval(node.Right)
    		return evalInfixExpression(node.Token.Literal, left, right)
    	}
    
    	return nil
    }
    
    func evalInfixExpression(
    	operator string,
    	left, right object.Object,
    ) object.Object {
    	switch {
    	case left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ:
    		return evalIntegerInfixExpression(operator, left, right)
    	case operator == "==":
    		return nativeBoolToBooleanObject(left == right)
    	case operator == "!=":
    		return nativeBoolToBooleanObject(left != right)
    	default:
    		return NULL
    	}
    }
    
    func evalIntegerInfixExpression(
    	operator string,
    	left, right object.Object,
    ) object.Object {
    	leftVal := left.(*object.Integer).Value
    	rightVal := right.(*object.Integer).Value
    
    	switch operator {
    	case "+":
    		return &object.Integer{Value: leftVal + rightVal}
    	case "-":
    		return &object.Integer{Value: leftVal - rightVal}
    	case "*":
    		return &object.Integer{Value: leftVal * rightVal}
    	case "/":
    		return &object.Integer{Value: leftVal / rightVal}	
    	case "<":
    		return nativeBoolToBooleanObject(leftVal < rightVal)
    	case ">":
    		return nativeBoolToBooleanObject(leftVal > rightVal)
    	case "==":
    		return nativeBoolToBooleanObject(leftVal == rightVal)
    	case "!=":
    		return nativeBoolToBooleanObject(leftVal != rightVal)	
    	default:
    		return NULL
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    3.6 条件语句

    // evaluator/evaluator.go
    
    func Eval(node ast.Node) object.Object {
    	switch node := node.(type) {
    	case *ast.BlockStatement:
    		return evalStatements(node.Statements)
    		
    	case *ast.IfExpression:
    		return evalIfExpression(node)
    	}
    
    	return nil
    }
    
    func evalIfExpression(ie *ast.IfExpression) object.Object {
    	condition := Eval(ie.Condition)
    	
    	if isTruthy(condition) {
    		return Eval(ie.Consequence)
    	} else if ie.Alternative != nil {
    		return Eval(ie.Alternative)
    	} else {
    		return NULL
    	}
    }
    
    func isTruthy(obj object.Object) bool {
    	switch obj {
    	case NULL:
    		return false
    	case TRUE:
    		return true
    	case FALSE:
    		return false
    	default:
    		return true
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    3.7 return语句

    5*5*5return 10;
    9*9*9;
    
    • 1
    • 2
    • 3
    // object/object.go
    
    const (
    	RETURN_VALUE_OBJ = "RETURN_VALUE"
    )
    
    type ReturnValue struct {
    	Value Object
    }
    func (rv *ReturnValue) Type() ObjectType { return RETURN_VALUE_OBJ }
    func (rv *ReturnValue) Inspect() string  { return rv.Value.Inspect() }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    // evaluator/evaluator.go
    
    func Eval(node ast.Node) object.Object {
    	switch node := node.(type) {
    	case *ast.Program:
    		return evalProgram(node)
    
    	case *ast.BlockStatement:
    		return evalBlockStatement(node)
    		
    	case *ast.ReturnStatement:
    		val := Eval(node.ReturnValue)
    		return &object.ReturnValue{Value: val}
    
    	case *ast.IfExpression:
    		return evalIfExpression(node)
    	}
    
    	return nil
    }
    
    func evalProgram(program *ast.Program) object.Object {
    	var result object.Object
    
    	for _, statement := range program.Statements {
    		result = Eval(statement)
    
    		switch result := result.(type) {
    		case *object.ReturnValue:
    			return result.Value
    		}
    	}
    
    	return result
    }
    
    func evalBlockStatement(block *ast.BlockStatement) object.Object {
    	var result object.Object
    
    	for _, statement := range block.Statements {
    		result = Eval(statement)
    
    		if result != nil && result.Type() == object.RETURN_VALUE_OBJ {
    			return result
    		}
    	}
    
    	return result
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    3.8 错误处理

    // object/object.go
    
    const (
    	ERROR_OBJ = "ERROR"
    )
    
    type Error struct {
    	Message string
    }
    func (e *Error) Type() ObjectType { return ERROR_OBJ }
    func (e *Error) Inspect() string  { return "ERROR: " + e.Message }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    // evaluator/evaluator.go
    import "fmt"
    
    func newError(format string, a ...interface{}) *object.Error {
    	return &object.Error{Message: fmt.Sprintf(format, a...)}
    }
    
    func evalPrefixExpression(operator string, right object.Object) object.Object {
    	switch operator {
    	default:
    		return newError("unknown operator: %s%s", operator, right.Type())
    	}
    }
    
    func evalMinusPrefixOperatorExpression(right object.Object) object.Object {
    	if right.Type() != object.INTEGER_OBJ {
    		return newError("unknown operator: -%s", right.Type())
    	}
    }
    
    func evalInfixExpression(
    	operator string,
    	left, right object.Object,
    ) object.Object {
    	switch {
    	case left.Type() != right.Type():
    		return newError("type mismatch: %s %s %s",
    			left.Type(), operator, right.Type())
    	default:
    		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
    	}
    }
    
    func evalIntegerInfixExpression(
    	operator string,
    	left, right object.Object,
    ) object.Object {
    	leftVal := left.(*object.Integer).Value
    	rightVal := right.(*object.Integer).Value
    
    	switch operator {
    	default:
    		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
    	}
    }
    
    func evalProgram(program *ast.Program) object.Object {
    	var result object.Object
    
    	for _, statement := range program.Statements {
    		result = Eval(statement)
    
    		switch result := result.(type) {
    		case *object.ReturnValue:
    			return result.Value
    		case *object.Error:
    			return result
    		}
    	}
    
    	return result
    }
    
    func evalBlockStatement(block *ast.BlockStatement) object.Object {
    	var result object.Object
    
    	for _, statement := range block.Statements {
    		result = Eval(statement)
    
    		if result != nil {
    			rt := result.Type() 
    			if rt == object.RETURN_VALUE_OBJ || rt == object.ERROR_OBJ {
    				return result
    			}
    		}
    	}
    
    	return result
    }
    
    func isError(obj object.Object) bool {
    	if obj != nil {
    		return obj.Type() == object.ERROR_OBJ
    	}
    	return false
    }
    
    func Eval(node ast.Node) object.Object {
    	switch node := node.(type) {
    	case *ast.PrefixExpression:
    		right := Eval(node.Right)
    		if isError(right) {
    			return right
    		}
    		return evalPrefixExpression(node.Token.Literal, right)
    		
    	case *ast.InfixExpression:
    		left := Eval(node.Left)
    		if isError(left) {
    			return left
    		}
    		right := Eval(node.Right)
    		if isError(right) {
    			return right
    		}
    		return evalInfixExpression(node.Token.Literal, left, right)
    		
    	case *ast.ReturnStatement:
    		val := Eval(node.ReturnValue)
    		if isError(val) {
    			return val
    		}
    		return &object.ReturnValue{Value: val}
    	}
    
    	return nil
    }
    
    func evalIfExpression(ie *ast.IfExpression) object.Object {
    	condition := Eval(ie.Condition)
    	if isError(condition) {
    		return condition
    	}
    	
    	if isTruthy(condition) {
    		return Eval(ie.Consequence)
    	} else if ie.Alternative != nil {
    		return Eval(ie.Alternative)
    	} else {
    		return NULL
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132

    3.9 绑定与环境

    // evaluator/evaluator.go
    func Eval(node ast.Node, env *object.Environment) object.Object {
    	switch node := node.(type) {
    	// Statements
    	case *ast.Program:
    		return evalProgram(node, env)
    
    	case *ast.BlockStatement:
    		return evalBlockStatement(node, env)
    		
    	case *ast.ExpressionStatement:
    		return Eval(node.Expression, env)
    		
    	case *ast.ReturnStatement:
    		val := Eval(node.ReturnValue, env)
    		if isError(val) {
    			return val
    		}
    		return &object.ReturnValue{Value: val}
    		
    	case *ast.LetStatement:
    		val := Eval(node.Value, env)
    		if isError(val) {
    			return val
    		}
    		env.Set(node.Name.Token.Literal, val)
    
    	// Expressions
    	case *ast.IntegerLiteral:
    		return &object.Integer{Value: node.Value}
    	
    	case *ast.Boolean:
    		return nativeBoolToBooleanObject(node.Value)
    		
    	case *ast.PrefixExpression:
    		right := Eval(node.Right, env)
    		if isError(right) {
    			return right
    		}
    		return evalPrefixExpression(node.Token.Literal, right)
    		
    	case *ast.InfixExpression:
    		left := Eval(node.Left, env)
    		if isError(left) {
    			return left
    		}
    		right := Eval(node.Right, env)
    		if isError(right) {
    			return right
    		}
    		return evalInfixExpression(node.Token.Literal, left, right)
    		
    	case *ast.IfExpression:
    		return evalIfExpression(node, env)
    
    	case *ast.Identifier:
    		return evalIdentifier(node, env)
    	}	
    	return nil
    }
    
    func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object {
    	val, ok := env.Get(node.Token.Literal)
    	if !ok {
    		return newError("identifier not found: " + node.Token.Literal)
    	}
    
    	return val
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    环境是一个将字符串与对象相关联的哈希映射。

    // object/environment.go
    package object
    
    type Environment struct {
    	store map[string]Object
    	outer *Environment
    }
    
    func (e *Environment) Get(name string) (Object, bool) {
    	obj, ok := e.store[name]
    	if !ok && e.outer != nil {
    		obj, ok = e.outer.Get(name)
    	}
    	return obj, ok
    }
    
    func (e *Environment) Set(name string, val Object) Object {
    	e.store[name] = val
    	return val
    }
    
    func NewEnvironment() *Environment {
    	s := make(map[string]Object)
    	return &Environment{store: s, outer: nil}
    }
    
    func NewEnclosedEnvironment(outer *Environment) *Environment {
    	env := NewEnvironment()
    	env.outer = outer
    	return env
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    // repl/repl.go
    
    func Start(in io.Reader, out io.Writer) {
    	scanner := bufio.NewScanner(in)
    	env := object.NewEnvironment()
    	
    	for {
    		fmt.Fprintf(out, PROMPT)
    		scanned := scanner.Scan()
    		if !scanned {
    			return
    		}
    
    		line := scanner.Text()
    		l := lexer.New(line)
    		
    		p := parser.New(l)
    		program := p.ParseProgram()
    		if len(p.Errors()) != 0 {
    			printParserErrors(out, p.Errors())
    			continue
    		}
    
    		if evaluated := evaluator.Eval(program, env); evaluated != nil {	
    			io.WriteString(out, evaluated.Inspect() + "\n")
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3.10 函数和函数调用

    对象系统内部表示函数

    // object/object.go
    import (
    	"bytes"
    	"fmt"
    	"monkey/ast"
    	"strings"
    )
    
    const (
    	FUNCTION_OBJ = "FUNCTION"
    )
    
    type Function struct {
    	Parameters []*ast.Identifier
    	Body       *ast.BlockStatement
    	Env        *Environment
    }
    func (f *Function) Type() ObjectType { return FUNCTION_OBJ }
    func (f *Function) Inspect() string {
    	var out bytes.Buffer
    
    	params := []string{}
    	for _, p := range f.Parameters {
    		params = append(params, p.String())
    	}
    
    	out.WriteString("fn")
    	out.WriteString("(")
    	out.WriteString(strings.Join(params, ", "))
    	out.WriteString(") ")
    	out.WriteString(f.Body.String())
    	out.WriteString("\n")
    
    	return out.String()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    对象系统内部表示调用函数

    // object/object.go
    
    func Eval(node ast.Node, env *object.Environment) object.Object {
    	switch node := node.(type) {
    	case *ast.FunctionLiteral:
    		params := node.Parameters
    		body := node.Body
    		return &object.Function{Parameters: params, Env: env, Body: body}
    
    	case *ast.CallExpression:
    		function := Eval(node.Function, env) //解析函数字面量或函数标识符
    		if isError(function) {
    			return function
    		}
    
    		args := evalExpressions(node.Arguments, env)
    		if len(args) == 1 && isError(args[0]) {
    			return args[0]
    		}
    
    		return applyFunction(function, args)
    	}
    
    	return nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    3.11 垃圾处理

    let counter = fn(x) {
    	if(x>10) {
    		return true;
    	} else {
    		let foobar = 9999;
    		counter(x+1);
    	}
    };
    counter(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用Go的垃圾回收(GC)。

    3.12 完整工程

    monkey/token/token.go

    package token
    
    type TokenType string
    
    const (
    	ILLEGAL = "ILLEGAL"
    	EOF     = "EOF"
    
    	// 标识符+字面量
    	IDENT = "IDENT" // add, foobar, x, y, ...
    	INT   = "INT"   // 1343456
    
    	// 运算符
    	ASSIGN   = "="
    	PLUS     = "+"
    	MINUS    = "-"
    	BANG     = "!"
    	ASTERISK = "*"
    	SLASH    = "/"
    
    	LT = "<"
    	GT = ">"
    
    	EQ     = "=="
    	NOT_EQ = "!="
    
    	// 分隔符
    	COMMA     = ","
    	SEMICOLON = ";"
    
    	LPAREN = "("
    	RPAREN = ")"
    	LBRACE = "{"
    	RBRACE = "}"
    
    	// 关键字
    	FUNCTION = "FUNCTION"
    	LET      = "LET"
    	TRUE     = "TRUE"
    	FALSE    = "FALSE"
    	IF       = "IF"
    	ELSE     = "ELSE"
    	RETURN   = "RETURN"
    )
    
    type Token struct {
    	Type    TokenType
    	Literal string
    }
    
    var keywords = map[string]TokenType{
    	"fn":     FUNCTION,
    	"let":    LET,
    	"true":   TRUE,
    	"false":  FALSE,
    	"if":     IF,
    	"else":   ELSE,
    	"return": RETURN,
    }
    
    func LookupIdent(ident string) TokenType {
    	if tok, ok := keywords[ident]; ok {
    		return tok
    	}
    	return IDENT
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    monkey/lexer/lexer.go

    package lexer
    
    import "monkey/token"
    
    type Lexer struct {
    	input        string
    	position     int  // 当前字符位置
    	readPosition int  // 下一个字符位置
    	ch           byte // 当前字符
    }
    
    func New(input string) *Lexer {
    	l := &Lexer{input: input}
    	l.readChar()
    	return l
    }
    
    func (l *Lexer) readChar() {
    	if l.readPosition >= len(l.input) {
    		l.ch = 0
    	} else {
    		l.ch = l.input[l.readPosition]
    	}
    	l.position = l.readPosition
    	l.readPosition += 1
    }
    
    func (l *Lexer) peekChar() byte {
    	if l.readPosition >= len(l.input) {
    		return 0
    	} else {
    		return l.input[l.readPosition]
    	}
    }
    
    func (l *Lexer) skipWhitespace() {
    	for l.ch == ' ' || l.ch == '\t' || l.ch == '\n' || l.ch == '\r' {
    		l.readChar()
    	}
    }
    
    func newToken(tokenType token.TokenType, ch byte) token.Token {
    	return token.Token{Type: tokenType, Literal: string(ch)}
    }
    
    func isLetter(ch byte) bool {
    	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_'
    }
    
    func isDigit(ch byte) bool {
    	return '0' <= ch && ch <= '9'
    }
    
    func (l *Lexer) readIdentifier() string {
    	position := l.position
    	for isLetter(l.ch) {
    		l.readChar()
    	}
    	return l.input[position:l.position]
    }
    
    func (l *Lexer) readNumber() string {
    	position := l.position
    	for isDigit(l.ch) {
    		l.readChar()
    	}
    	return l.input[position:l.position]
    }
    
    func (l *Lexer) NextToken() token.Token {
    	var tok token.Token
    
    	l.skipWhitespace()
    
    	switch l.ch {
    	case '=':
    		if l.peekChar() == '=' {
    			ch := l.ch
    			l.readChar()
    			literal := string(ch) + string(l.ch)
    			tok = token.Token{Type: token.EQ, Literal: literal}
    		} else {
    			tok = newToken(token.ASSIGN, l.ch)
    		}
    	case '+':
    		tok = newToken(token.PLUS, l.ch)
    	case '-':
    		tok = newToken(token.MINUS, l.ch)
    	case '!':
    		if l.peekChar() == '=' {
    			ch := l.ch
    			l.readChar()
    			literal := string(ch) + string(l.ch)
    			tok = token.Token{Type: token.NOT_EQ, Literal: literal}
    		} else {
    			tok = newToken(token.BANG, l.ch)
    		}
    	case '/':
    		tok = newToken(token.SLASH, l.ch)
    	case '*':
    		tok = newToken(token.ASTERISK, l.ch)
    	case '<':
    		tok = newToken(token.LT, l.ch)
    	case '>':
    		tok = newToken(token.GT, l.ch)
    	case ';':
    		tok = newToken(token.SEMICOLON, l.ch)
    	case ',':
    		tok = newToken(token.COMMA, l.ch)
    	case '{':
    		tok = newToken(token.LBRACE, l.ch)
    	case '}':
    		tok = newToken(token.RBRACE, l.ch)
    	case '(':
    		tok = newToken(token.LPAREN, l.ch)
    	case ')':
    		tok = newToken(token.RPAREN, l.ch)
    	case 0:
    		tok.Literal = ""
    		tok.Type = token.EOF
    	default:
    		if isLetter(l.ch) {
    			tok.Literal = l.readIdentifier()
    			tok.Type = token.LookupIdent(tok.Literal)
    			return tok
    		} else if isDigit(l.ch) {
    			tok.Type = token.INT
    			tok.Literal = l.readNumber()
    			return tok
    		} else {
    			tok = newToken(token.ILLEGAL, l.ch)
    		}
    	}
    
    	l.readChar()
    	return tok
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137

    monkey/lexer/lexer_test.go

    package lexer
    
    import (
    	"testing"
    	"monkey/token"
    )
    
    func TestNextToken(t *testing.T) {
    	input := `let five = 5;
    let ten = 10;
    
    let add = fn(x, y) {
      x + y;
    };
    
    let result = add(five, ten);
    !-/*5;
    5 < 10 > 5;
    
    if (5 < 10) {
    	return true;
    } else {
    	return false;
    }
    
    10 == 10;
    10 != 9;
    `
    
    	tests := []struct {
    		expectedType    token.TokenType
    		expectedLiteral string
    	}{
    		{token.LET, "let"},
    		{token.IDENT, "five"},
    		{token.ASSIGN, "="},
    		{token.INT, "5"},
    		{token.SEMICOLON, ";"},
    		{token.LET, "let"},
    		{token.IDENT, "ten"},
    		{token.ASSIGN, "="},
    		{token.INT, "10"},
    		{token.SEMICOLON, ";"},
    		{token.LET, "let"},
    		{token.IDENT, "add"},
    		{token.ASSIGN, "="},
    		{token.FUNCTION, "fn"},
    		{token.LPAREN, "("},
    		{token.IDENT, "x"},
    		{token.COMMA, ","},
    		{token.IDENT, "y"},
    		{token.RPAREN, ")"},
    		{token.LBRACE, "{"},
    		{token.IDENT, "x"},
    		{token.PLUS, "+"},
    		{token.IDENT, "y"},
    		{token.SEMICOLON, ";"},
    		{token.RBRACE, "}"},
    		{token.SEMICOLON, ";"},
    		{token.LET, "let"},
    		{token.IDENT, "result"},
    		{token.ASSIGN, "="},
    		{token.IDENT, "add"},
    		{token.LPAREN, "("},
    		{token.IDENT, "five"},
    		{token.COMMA, ","},
    		{token.IDENT, "ten"},
    		{token.RPAREN, ")"},
    		{token.SEMICOLON, ";"},
    		{token.BANG, "!"},
    		{token.MINUS, "-"},
    		{token.SLASH, "/"},
    		{token.ASTERISK, "*"},
    		{token.INT, "5"},
    		{token.SEMICOLON, ";"},
    		{token.INT, "5"},
    		{token.LT, "<"},
    		{token.INT, "10"},
    		{token.GT, ">"},
    		{token.INT, "5"},
    		{token.SEMICOLON, ";"},
    		{token.IF, "if"},
    		{token.LPAREN, "("},
    		{token.INT, "5"},
    		{token.LT, "<"},
    		{token.INT, "10"},
    		{token.RPAREN, ")"},
    		{token.LBRACE, "{"},
    		{token.RETURN, "return"},
    		{token.TRUE, "true"},
    		{token.SEMICOLON, ";"},
    		{token.RBRACE, "}"},
    		{token.ELSE, "else"},
    		{token.LBRACE, "{"},
    		{token.RETURN, "return"},
    		{token.FALSE, "false"},
    		{token.SEMICOLON, ";"},
    		{token.RBRACE, "}"},
    		{token.INT, "10"},
    		{token.EQ, "=="},
    		{token.INT, "10"},
    		{token.SEMICOLON, ";"},
    		{token.INT, "10"},
    		{token.NOT_EQ, "!="},
    		{token.INT, "9"},
    		{token.SEMICOLON, ";"},
    		{token.EOF, ""},
    	}
    
    	l := New(input)
    
    	for i, tt := range tests {
    		tok := l.NextToken()
    
    		if tok.Type != tt.expectedType {
    			t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q",
    				i, tt.expectedType, tok.Type)
    		}
    
    		if tok.Literal != tt.expectedLiteral {
    			t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q",
    				i, tt.expectedLiteral, tok.Literal)
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

    monkey/ast/ast.go

    package ast
    
    import (
    	"bytes"
    	"monkey/token"
    	"strings"
    )
    
    // 基础节点接口
    type Node interface {
    	String() string
    }
    
    // 语句
    type Statement interface {
    	Node
    }
    
    // 表达式
    type Expression interface {
    	Node
    }
    
    // 程序
    type Program struct {
    	Statements []Statement
    }
    func (p *Program) String() string {
    	var out bytes.Buffer
    
    	for _, s := range p.Statements {
    		out.WriteString(s.String())
    	}
    
    	return out.String()
    }
    
    // let语句
    type LetStatement struct {
    	Name  *Identifier 	// 标识符
    	Value Expression	// 右侧表达式
    }
    func (ls *LetStatement) String() string {
    	var out bytes.Buffer
    
    	out.WriteString("let ")
    	out.WriteString(ls.Name.String())
    	out.WriteString(" = ")
    	out.WriteString(ls.Value.String())
    	out.WriteString(";")
    	out.WriteString("\n")
    
    	return out.String()
    }
    
    // return语句
    type ReturnStatement struct {
    	ReturnValue Expression	//return右边表达式
    }
    func (rs *ReturnStatement) String() string {
    	var out bytes.Buffer
    
    	out.WriteString("return ")
    	out.WriteString(rs.ReturnValue.String())
    	out.WriteString(";")
    	out.WriteString("\n")
    
    	return out.String()
    }
    
    // expression语句
    type ExpressionStatement struct {
    	Expression Expression
    }
    func (es *ExpressionStatement) String() string {
    	return es.Expression.String() + ";" + "\n"
    }
    
    // block语句
    type BlockStatement struct {
    	Statements []Statement
    }
    func (bs *BlockStatement) String() string {
    	var out bytes.Buffer
    
    	out.WriteString("{")
    	out.WriteString("\n")
    	for _, s := range bs.Statements {
    		out.WriteString("\t" + s.String())
    	}
    	out.WriteString("}")
    
    	return out.String()
    }
    
    // 标识符
    type Identifier struct {
    	Token token.Token // 词法单元
    }
    func (i *Identifier) String() string { return i.Token.Literal }
    
    // 布尔字面量
    type Boolean struct {
    	Token token.Token
    	Value bool
    }
    func (b *Boolean) String() string { return b.Token.Literal }
    
    // 整数字面量
    type IntegerLiteral struct {
    	Token token.Token
    	Value int64
    }
    func (il *IntegerLiteral) String() string { return il.Token.Literal }
    
    // 前缀表达式
    type PrefixExpression struct {
    	Token    token.Token // The prefix token, e.g. !
    	Right    Expression
    }
    func (pe *PrefixExpression) String() string {
    	var out bytes.Buffer
    
    	out.WriteString("(")
    	out.WriteString(pe.Token.Literal)
    	out.WriteString(pe.Right.String())
    	out.WriteString(")")
    
    	return out.String()
    }
    
    // 中缀表达式
    type InfixExpression struct {
    	Token    token.Token // The operator token, e.g. +
    	Left     Expression
    	Right    Expression
    }
    func (ie *InfixExpression) String() string {
    	var out bytes.Buffer
    
    	out.WriteString("(")
    	out.WriteString(ie.Left.String())
    	out.WriteString(" " + ie.Token.Literal + " ")
    	out.WriteString(ie.Right.String())
    	out.WriteString(")")
    
    	return out.String()
    }
    
    // if表达式
    type IfExpression struct {
    	Condition   Expression
    	Consequence *BlockStatement
    	Alternative *BlockStatement
    }
    func (ie *IfExpression) String() string {
    	var out bytes.Buffer
    
    	out.WriteString("if")
    	out.WriteString(ie.Condition.String())
    	out.WriteString(" ")
    	out.WriteString(ie.Consequence.String())
    
    	if ie.Alternative != nil {
    		out.WriteString(" else ")
    		out.WriteString(ie.Alternative.String())
    	}
    
    	return out.String()
    }
    
    // 函数字面量
    type FunctionLiteral struct {
    	Parameters []*Identifier
    	Body       *BlockStatement
    }
    func (fl *FunctionLiteral) String() string {
    	var out bytes.Buffer
    
    	params := []string{}
    	for _, p := range fl.Parameters {
    		params = append(params, p.String())
    	}
    
    	out.WriteString("fn")
    	out.WriteString("(")
    	out.WriteString(strings.Join(params, ", "))
    	out.WriteString(") ")
    	out.WriteString(fl.Body.String())
    
    	return out.String()
    }
    
    // 调用表达式
    type CallExpression struct {
    	Function  Expression  // 标识符或函数字面量
    	Arguments []Expression
    }
    func (ce *CallExpression) String() string {
    	var out bytes.Buffer
    
    	args := []string{}
    	for _, a := range ce.Arguments {
    		args = append(args, a.String())
    	}
    
    	out.WriteString(ce.Function.String())
    	out.WriteString("(")
    	out.WriteString(strings.Join(args, ", "))
    	out.WriteString(")")
    
    	return out.String()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213

    monkey/ast/ast_test.go

    package ast
    
    import (
    	"monkey/token"
    	"testing"
    )
    
    func TestString(t *testing.T) {
    	program := &Program{
    		Statements: []Statement{
    			&LetStatement{
    				Name: &Identifier{Token: token.Token{Type: token.IDENT, Literal: "myVar"}},
    				Value: &Identifier{Token: token.Token{Type: token.IDENT, Literal: "anotherVar"}},
    			},
    		},
    	}
    
    	if program.String() != "let myVar = anotherVar;\n" {
    		t.Errorf("program.String() wrong. got=%q", program.String())
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    monkey/parser/parser.go

    package parser
    
    import (
    	"fmt"
    	"monkey/ast"
    	"monkey/lexer"
    	"monkey/token"
    	"strconv"
    )
    
    //运算符优先级
    const (
    	_ int = iota
    	LOWEST
    	EQUALS      // == !=
    	LESSGREATER // > or <
    	SUM         // + -
    	PRODUCT     // * /
    	PREFIX      // -X or !X
    	CALL        // myFunction(X)
    )
    
    //词法单元运算符优先级
    //用于中缀表达式
    var precedences = map[token.TokenType]int{
    	token.EQ:       EQUALS, // ==
    	token.NOT_EQ:   EQUALS,	// !=
    	token.LT:       LESSGREATER,	// <
    	token.GT:       LESSGREATER,	// >
    	token.PLUS:     SUM,	// +
    	token.MINUS:    SUM,	// -
    	token.SLASH:    PRODUCT,// /
    	token.ASTERISK: PRODUCT,// *
    	token.LPAREN:   CALL,	// (
    }
    
    type (
    	prefixParseFn func() ast.Expression	//前缀解析函数
    	infixParseFn  func(ast.Expression) ast.Expression	//中缀解析函数
    )
    
    type Parser struct {
    	l      *lexer.Lexer
    	errors []string
    
    	curToken  token.Token
    	peekToken token.Token
    
    	prefixParseFns map[token.TokenType]prefixParseFn
    	infixParseFns  map[token.TokenType]infixParseFn
    }
    
    func New(l *lexer.Lexer) *Parser {
    	p := &Parser{
    		l:      l,
    		errors: []string{},
    	}
    
    	//注册前缀解析函数
    	p.prefixParseFns = make(map[token.TokenType]prefixParseFn)
    	p.registerPrefix(token.IDENT, p.parseIdentifier)
    	p.registerPrefix(token.INT, p.parseIntegerLiteral)
    	p.registerPrefix(token.BANG, p.parsePrefixExpression)	// !
    	p.registerPrefix(token.MINUS, p.parsePrefixExpression)	// -
    	p.registerPrefix(token.TRUE, p.parseBoolean)
    	p.registerPrefix(token.FALSE, p.parseBoolean)
    	p.registerPrefix(token.LPAREN, p.parseGroupedExpression)// (,分组表达式(1 + 2) * 3
    	p.registerPrefix(token.IF, p.parseIfExpression)
    	p.registerPrefix(token.FUNCTION, p.parseFunctionLiteral)// fn
    
    	//注册中缀解析函数
    	p.infixParseFns = make(map[token.TokenType]infixParseFn)
    	p.registerInfix(token.PLUS, p.parseInfixExpression)
    	p.registerInfix(token.MINUS, p.parseInfixExpression)
    	p.registerInfix(token.SLASH, p.parseInfixExpression)	// /	
    	p.registerInfix(token.ASTERISK, p.parseInfixExpression)	// *
    	p.registerInfix(token.EQ, p.parseInfixExpression)
    	p.registerInfix(token.NOT_EQ, p.parseInfixExpression)
    	p.registerInfix(token.LT, p.parseInfixExpression)
    	p.registerInfix(token.GT, p.parseInfixExpression)
    
    	p.registerInfix(token.LPAREN, p.parseCallExpression)	// (,函数调用表达式add(2, 3)
    
    	// 读取当前词法单元和下一个词法单元
    	p.nextToken()
    	p.nextToken()
    
    	return p
    }
    
    func (p *Parser) nextToken() {
    	p.curToken = p.peekToken
    	p.peekToken = p.l.NextToken()
    }
    
    func (p *Parser) curTokenIs(t token.TokenType) bool {
    	return p.curToken.Type == t
    }
    
    func (p *Parser) peekTokenIs(t token.TokenType) bool {
    	return p.peekToken.Type == t
    }
    
    // 判断下一个词法单元是否是期望的词法单元,是则跳过当前词法单元
    func (p *Parser) expectPeek(t token.TokenType) bool {
    	if p.peekTokenIs(t) {
    		p.nextToken()
    		return true
    	} else {
    		p.peekError(t)
    		return false
    	}
    }
    
    func (p *Parser) Errors() []string {
    	return p.errors
    }
    
    func (p *Parser) peekError(t token.TokenType) {
    	msg := fmt.Sprintf("expected next token to be %s, got %s instead",
    		t, p.peekToken.Type)
    	p.errors = append(p.errors, msg)
    }
    
    // 解析到词法单元未注册前缀解析函数时,记录错误
    func (p *Parser) noPrefixParseFnError(t token.TokenType) {
    	msg := fmt.Sprintf("no prefix parse function for %s found", t)
    	p.errors = append(p.errors, msg)
    }
    
    // 遍历语句解析程序
    func (p *Parser) ParseProgram() *ast.Program {
    	program := &ast.Program{}
    	program.Statements = []ast.Statement{}
    
    	for !p.curTokenIs(token.EOF) {
    		stmt := p.parseStatement()
    		if stmt != nil {
    			program.Statements = append(program.Statements, stmt)
    		}
    		p.nextToken()
    	}
    
    	return program
    }
    
    // 解析语句
    func (p *Parser) parseStatement() ast.Statement {
    	switch p.curToken.Type {
    	case token.SEMICOLON:	//空语句;
    		return nil
    	case token.LET:			//let语句
    		return p.parseLetStatement()
    	case token.RETURN:		//return语句
    		return p.parseReturnStatement()
    	default:				//expression语句
    		return p.parseExpressionStatement()
    	}
    }
    
    // 解析let语句(末尾可以无分号;)
    func (p *Parser) parseLetStatement() *ast.LetStatement {
    	stmt := &ast.LetStatement{}
    
    	if !p.expectPeek(token.IDENT) {
    		return nil
    	}
    
    	stmt.Name = &ast.Identifier{Token: p.curToken}
    
    	if !p.expectPeek(token.ASSIGN) {
    		return nil
    	}
    
    	p.nextToken()
    
    	stmt.Value = p.parseExpression(LOWEST)
    
    	if p.peekTokenIs(token.SEMICOLON) {	//下一个词法单元为分号;,则跳过当前词法单元
    		p.nextToken()
    	}
    
    	return stmt
    }
    
    // 解析return语句(末尾可以无分号;)
    func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
    	stmt := &ast.ReturnStatement{}
    
    	p.nextToken()
    
    	stmt.ReturnValue = p.parseExpression(LOWEST)
    
    	if p.peekTokenIs(token.SEMICOLON) {
    		p.nextToken()
    	}
    
    	return stmt
    }
    
    // 解析expression语句(末尾可以无分号;)
    func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement {
    	//defer untrace(trace("parseExpressionStatement"))
    	
    	stmt := &ast.ExpressionStatement{}
    
    	stmt.Expression = p.parseExpression(LOWEST)
    
    	if p.peekTokenIs(token.SEMICOLON) {
    		p.nextToken()
    	}
    
    	return stmt
    }
    
    // 解析表达式
    func (p *Parser) parseExpression(precedence int) ast.Expression {
    	//defer untrace(trace("parseExpression"))
    	
    	prefix := p.prefixParseFns[p.curToken.Type]
    	if prefix == nil {
    		p.noPrefixParseFnError(p.curToken.Type)
    		return nil
    	}
    	leftExp := prefix()	//调用前缀解析函数
    
    	// 下一个词法单元不是表达式末尾分号;,并且传入运算符优先级小于下一个运算符优先级时
    	// 递归调用parseExpression,生成AST
    	for !p.peekTokenIs(token.SEMICOLON) && precedence < p.peekPrecedence() {
    		infix := p.infixParseFns[p.peekToken.Type]
    		if infix == nil {
    			return leftExp
    		}
    
    		p.nextToken()
    
    		leftExp = infix(leftExp)	//调用中缀解析函数,leftExp作为参数传入
    	}
    
    	return leftExp
    }
    
    func (p *Parser) peekPrecedence() int {
    	if p, ok := precedences[p.peekToken.Type]; ok {
    		return p
    	}
    
    	return LOWEST
    }
    
    func (p *Parser) curPrecedence() int {
    	if p, ok := precedences[p.curToken.Type]; ok {
    		return p
    	}
    
    	return LOWEST
    }
    
    // 解析标识符
    func (p *Parser) parseIdentifier() ast.Expression {
    	//defer untrace(trace("parseIdentifier"))
    	
    	return &ast.Identifier{Token: p.curToken}
    }
    
    // 解析整形字面量
    func (p *Parser) parseIntegerLiteral() ast.Expression {
    	//defer untrace(trace("parseIntegerLiteral"))
    	
    	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
    }
    
    // 解析前缀表达式
    func (p *Parser) parsePrefixExpression() ast.Expression {
    	//defer untrace(trace("parsePrefixExpression"))
    	
    	expression := &ast.PrefixExpression{
    		Token:    p.curToken,
    	}
    
    	p.nextToken()
    
    	// 传入极高运算符优先级PREFIX
    	// 确保前缀表达式(Token expression)完整解析
    	expression.Right = p.parseExpression(PREFIX)
    
    	return expression
    }
    
    // 解析中缀表达式,传入左侧表达式
    func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression {
    	//defer untrace(trace("parseInfixExpression"))
    	
    	expression := &ast.InfixExpression{
    		Token:    p.curToken,
    		Left:     left,
    	}
    
    	precedence := p.curPrecedence()
    	p.nextToken()
    	expression.Right = p.parseExpression(precedence)
    
    	return expression
    }
    
    func (p *Parser) parseBoolean() ast.Expression {
    	return &ast.Boolean{Token: p.curToken, Value: p.curTokenIs(token.TRUE)}
    }
    
    // 解析分组表达式
    func (p *Parser) parseGroupedExpression() ast.Expression {
    	p.nextToken()
    
    	exp := p.parseExpression(LOWEST)
    
    	if !p.expectPeek(token.RPAREN) {
    		return nil
    	}
    
    	return exp
    }
    
    // 解析if表达式
    func (p *Parser) parseIfExpression() ast.Expression {
    	expression := &ast.IfExpression{}
    
    	if !p.expectPeek(token.LPAREN) {
    		return nil
    	}
    
    	p.nextToken()
    	expression.Condition = p.parseExpression(LOWEST)
    
    	if !p.expectPeek(token.RPAREN) {
    		return nil
    	}
    
    	if !p.expectPeek(token.LBRACE) {
    		return nil
    	}
    
    	expression.Consequence = p.parseBlockStatement()
    
    	if p.peekTokenIs(token.ELSE) {
    		p.nextToken()
    
    		if !p.expectPeek(token.LBRACE) {
    			return nil
    		}
    
    		expression.Alternative = p.parseBlockStatement()
    	}
    
    	return expression
    }
    
    // 解析block语句
    func (p *Parser) parseBlockStatement() *ast.BlockStatement {
    	block := &ast.BlockStatement{}
    	block.Statements = []ast.Statement{}
    
    	p.nextToken()
    
    	for !p.curTokenIs(token.RBRACE) && !p.curTokenIs(token.EOF) {
    		stmt := p.parseStatement()
    		if stmt != nil {
    			block.Statements = append(block.Statements, stmt)
    		}
    		p.nextToken()
    	}
    
    	return block
    }
    
    // 解析函数字面量表达式
    // fn() {}
    func (p *Parser) parseFunctionLiteral() ast.Expression {
    	lit := &ast.FunctionLiteral{}
    
    	if !p.expectPeek(token.LPAREN) {
    		return nil
    	}
    
    	lit.Parameters = p.parseFunctionParameters()
    
    	if !p.expectPeek(token.LBRACE) {
    		return nil
    	}
    
    	lit.Body = p.parseBlockStatement()
    
    	return lit
    }
    
    // 解析函数字面量表达式,内部参数标识符a, b, c等
    // fn(a, b, c) {}
    func (p *Parser) parseFunctionParameters() []*ast.Identifier {
    	identifiers := []*ast.Identifier{}
    
    	if p.peekTokenIs(token.RPAREN) {
    		p.nextToken()
    		return identifiers
    	}
    
    	p.nextToken()
    
    	ident := &ast.Identifier{Token: p.curToken}
    	identifiers = append(identifiers, ident)
    
    	for p.peekTokenIs(token.COMMA) {
    		p.nextToken()
    		p.nextToken()
    		ident := &ast.Identifier{Token: p.curToken}
    		identifiers = append(identifiers, ident)
    	}
    
    	if !p.expectPeek(token.RPAREN) {
    		return nil
    	}
    
    	return identifiers
    }
    
    // 解析调用函数表达式
    // add(2, 3)
    func (p *Parser) parseCallExpression(function ast.Expression) ast.Expression {
    	exp := &ast.CallExpression{Function: function}
    	exp.Arguments = p.parseCallArguments()
    	return exp
    }
    
    // 解析调用函数表达式,传入实际参数表达式
    // add(2+3, minute(5, 3))
    func (p *Parser) parseCallArguments() []ast.Expression {
    	args := []ast.Expression{}
    
    	if p.peekTokenIs(token.RPAREN) {
    		p.nextToken()
    		return args
    	}
    
    	p.nextToken()
    	args = append(args, p.parseExpression(LOWEST))
    
    	for p.peekTokenIs(token.COMMA) {
    		p.nextToken()
    		p.nextToken()
    		args = append(args, p.parseExpression(LOWEST))
    	}
    
    	if !p.expectPeek(token.RPAREN) {
    		return nil
    	}
    
    	return args
    }
    
    func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) {
    	p.prefixParseFns[tokenType] = fn
    }
    
    func (p *Parser) registerInfix(tokenType token.TokenType, fn infixParseFn) {
    	p.infixParseFns[tokenType] = fn
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475

    monkey/parser/parser_test.go

    package parser
    
    import (
    	"fmt"
    	"monkey/ast"
    	"monkey/lexer"
    	"testing"
    )
    
    func checkParserErrors(t *testing.T, p *Parser) {
    	errors := p.Errors()
    	if len(errors) == 0 {
    		return
    	}
    
    	t.Errorf("parser has %d errors", len(errors))
    	for _, msg := range errors {
    		t.Errorf("parser error: %q", msg)
    	}
    	t.FailNow()
    }
    
    func testLetStatement(t *testing.T, s ast.Statement, name string) bool {
    	letStmt, ok := s.(*ast.LetStatement)
    	if !ok {
    		t.Errorf("s not *ast.LetStatement. got=%T", s)
    		return false
    	}
    
    	if letStmt.Name.String() != name {
    		t.Errorf("letStmt.Name.String() not '%s'. got=%s", name, letStmt.Name.String())
    		return false
    	}
    
    	if letStmt.Name.Token.Literal != name {
    		t.Errorf("letStmt.Name.Token.Literal not '%s'. got=%s", name, letStmt.Name.Token.Literal)
    		return false
    	}
    
    	return true
    }
    
    func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool {
    	integ, ok := il.(*ast.IntegerLiteral)
    	if !ok {
    		t.Errorf("il not *ast.IntegerLiteral. got=%T", il)
    		return false
    	}
    
    	if integ.Value != value {
    		t.Errorf("integ.Value not %d. got=%d", value, integ.Value)
    		return false
    	}
    
    	if integ.String() != fmt.Sprintf("%d", value) {
    		t.Errorf("integ.String() not %d. got=%s", value, integ.String())
    		return false
    	}
    
    	return true
    }
    
    func testBooleanLiteral(t *testing.T, exp ast.Expression, value bool) bool {
    	bo, ok := exp.(*ast.Boolean)
    	if !ok {
    		t.Errorf("exp not *ast.Boolean. got=%T", exp)
    		return false
    	}
    
    	if bo.Value != value {
    		t.Errorf("bo.Value not %t. got=%t", value, bo.Value)
    		return false
    	}
    
    	if bo.String() != fmt.Sprintf("%t", value) {
    		t.Errorf("bo.String() not %t. got=%s", value, bo.String())
    		return false
    	}
    
    	return true
    }
    
    func testIdentifier(t *testing.T, exp ast.Expression, value string) bool {
    	ident, ok := exp.(*ast.Identifier)
    	if !ok {
    		t.Errorf("exp not *ast.Identifier. got=%T", exp)
    		return false
    	}
    
    	if ident.String() != value {
    		t.Errorf("ident.String() not %s. got=%s", value,
    			ident.String())
    		return false
    	}
    
    	return true
    }
    
    func testLiteralExpression(
    	t *testing.T,
    	exp ast.Expression,
    	expected interface{},
    ) bool {
    	switch v := expected.(type) {
    	case int:
    		return testIntegerLiteral(t, exp, int64(v))
    	case int64:
    		return testIntegerLiteral(t, exp, v)
    	case string:
    		return testIdentifier(t, exp, v)
    	case bool:
    		return testBooleanLiteral(t, exp, v)
    	}
    	t.Errorf("type of exp not handled. got=%T", exp)
    	return false
    }
    
    func testInfixExpression(t *testing.T, exp ast.Expression, left interface{},
    	operator string, right interface{}) bool {
    
    	opExp, ok := exp.(*ast.InfixExpression)
    	if !ok {
    		t.Errorf("exp is not ast.InfixExpression. got=%T(%s)", exp, exp)
    		return false
    	}
    
    	if !testLiteralExpression(t, opExp.Left, left) {
    		return false
    	}
    
    	if opExp.Token.Literal != operator {
    		t.Errorf("exp.Token.Literal is not '%s'. got=%q", operator, opExp.Token.Literal)
    		return false
    	}
    
    	if !testLiteralExpression(t, opExp.Right, right) {
    		return false
    	}
    
    	return true
    }
    
    func TestLetStatements(t *testing.T) {
    	tests := []struct {
    		input              string
    		expectedIdentifier string
    		expectedValue      interface{}
    	}{
    		{"let x = 5;", "x", 5},
    		{"let y = true;", "y", true},
    		{"let foobar = y;", "foobar", "y"},
    	}
    
    	for _, tt := range tests {
    		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 1 statements. got=%d",
    				len(program.Statements))
    		}
    
    		stmt := program.Statements[0]
    		if !testLetStatement(t, stmt, tt.expectedIdentifier) {
    			return
    		}
    
    		val := stmt.(*ast.LetStatement).Value
    		if !testLiteralExpression(t, val, tt.expectedValue) {
    			return
    		}
    	}
    }
    
    func TestReturnStatements(t *testing.T) {
    	tests := []struct {
    		input         string
    		expectedValue interface{}
    	}{
    		{"return 5;", 5},
    		{"return true;", true},
    		{"return foobar;", "foobar"},
    	}
    
    	for _, tt := range tests {
    		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 1 statements. got=%d",
    				len(program.Statements))
    		}
    
    		stmt := program.Statements[0]
    		returnStmt, ok := stmt.(*ast.ReturnStatement)
    		if !ok {
    			t.Fatalf("stmt not *ast.ReturnStatement. got=%T", stmt)
    		}
    		
    		if testLiteralExpression(t, returnStmt.ReturnValue, tt.expectedValue) {
    			return
    		}
    	}
    }
    
    func TestIdentifierExpression(t *testing.T) {
    	input := "foobar;"
    
    	l := lexer.New(input)
    	p := New(l)
    	program := p.ParseProgram()
    	checkParserErrors(t, p)
    
    	if len(program.Statements) != 1 {
    		t.Fatalf("program has not enough statements. got=%d",
    			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])
    	}
    
    	ident, ok := stmt.Expression.(*ast.Identifier)
    	if !ok {
    		t.Fatalf("exp not *ast.Identifier. got=%T", stmt.Expression)
    	}
    
    	if ident.String() != "foobar" {
    		t.Errorf("ident.String() not %s. got=%s", "foobar",
    			ident.String())
    	}
    }
    
    func TestIntegerLiteralExpression(t *testing.T) {
    	input := "5;"
    
    	l := lexer.New(input)
    	p := New(l)
    	program := p.ParseProgram()
    	checkParserErrors(t, p)
    
    	if len(program.Statements) != 1 {
    		t.Fatalf("program has not enough statements. got=%d",
    			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])
    	}
    
    	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.String() != "5" {
    		t.Errorf("literal.String() not %s. got=%s", "5",
    			literal.String())
    	}
    }
    
    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.Token.Literal != tt.operator {
    			t.Fatalf("exp.Token.Literal is not '%s'. got=%s",
    				tt.operator, exp.Token.Literal)
    		}
    		if !testLiteralExpression(t, exp.Right, tt.value) {
    			return
    		}
    	}
    }
    
    func TestParsingInfixExpressions(t *testing.T) {
    	infixTests := []struct {
    		input      string
    		leftValue  interface{}
    		operator   string
    		rightValue interface{}
    	}{
    		{"5 + 5;", 5, "+", 5},
    		{"5 - 5;", 5, "-", 5},
    		{"5 * 5;", 5, "*", 5},
    		{"5 / 5;", 5, "/", 5},
    		{"5 > 5;", 5, ">", 5},
    		{"5 < 5;", 5, "<", 5},
    		{"5 == 5;", 5, "==", 5},
    		{"5 != 5;", 5, "!=", 5},
    		{"foobar + barfoo;", "foobar", "+", "barfoo"},
    		{"foobar - barfoo;", "foobar", "-", "barfoo"},
    		{"foobar * barfoo;", "foobar", "*", "barfoo"},
    		{"foobar / barfoo;", "foobar", "/", "barfoo"},
    		{"foobar > barfoo;", "foobar", ">", "barfoo"},
    		{"foobar < barfoo;", "foobar", "<", "barfoo"},
    		{"foobar == barfoo;", "foobar", "==", "barfoo"},
    		{"foobar != barfoo;", "foobar", "!=", "barfoo"},
    		{"true == true", true, "==", true},
    		{"true != false", true, "!=", false},
    		{"false == false", false, "==", false},
    	}
    
    	for _, tt := range infixTests {
    		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])
    		}
    
    		if !testInfixExpression(t, stmt.Expression, tt.leftValue,
    			tt.operator, tt.rightValue) {
    			return
    		}
    	}
    }
    
    func TestOperatorPrecedenceParsing(t *testing.T) {
    	tests := []struct {
    		input    string
    		expected string
    	}{
    		{
    			"-a * b",
    			"((-a) * b);\n",
    		},
    		{
    			"!-a",
    			"(!(-a));\n",
    		},
    		{
    			"a + b + c",
    			"((a + b) + c);\n",
    		},
    		{
    			"a + b - c",
    			"((a + b) - c);\n",
    		},
    		{
    			"a * b * c",
    			"((a * b) * c);\n",
    		},
    		{
    			"a * b / c",
    			"((a * b) / c);\n",
    		},
    		{
    			"a + b / c",
    			"(a + (b / c));\n",
    		},
    		{
    			"a + b * c + d / e - f",
    			"(((a + (b * c)) + (d / e)) - f);\n",
    		},
    		{
    			"3 + 4; -5 * 5",
    			"(3 + 4);\n((-5) * 5);\n",
    		},
    		{
    			"5 > 4 == 3 < 4",
    			"((5 > 4) == (3 < 4));\n",
    		},
    		{
    			"5 < 4 != 3 > 4",
    			"((5 < 4) != (3 > 4));\n",
    		},
    		{
    			"3 + 4 * 5 == 3 * 1 + 4 * 5",
    			"((3 + (4 * 5)) == ((3 * 1) + (4 * 5)));\n",
    		},
    		{
    			"true",
    			"true;\n",
    		},
    		{
    			"false",
    			"false;\n",
    		},
    		{
    			"3 > 5 == false",
    			"((3 > 5) == false);\n",
    		},
    		{
    			"3 < 5 == true",
    			"((3 < 5) == true);\n",
    		},
    		{
    			"1 + (2 + 3) + 4",
    			"((1 + (2 + 3)) + 4);\n",
    		},
    		{
    			"(5 + 5) * 2",
    			"((5 + 5) * 2);\n",
    		},
    		{
    			"2 / (5 + 5)",
    			"(2 / (5 + 5));\n",
    		},
    		{
    			"(5 + 5) * 2 * (5 + 5)",
    			"(((5 + 5) * 2) * (5 + 5));\n",
    		},
    		{
    			"-(5 + 5)",
    			"(-(5 + 5));\n",
    		},
    		{
    			"!(true == true)",
    			"(!(true == true));\n",
    		},
    		{
    			"a + add(b * c) + d",
    			"((a + add((b * c))) + d);\n",
    		},
    		{
    			"add(a, b, 1, 2 * 3, 4 + 5, add(6, 7 * 8))",
    			"add(a, b, 1, (2 * 3), (4 + 5), add(6, (7 * 8)));\n",
    		},
    		{
    			"add(a + b + c * d / f + g)",
    			"add((((a + b) + ((c * d) / f)) + g));\n",
    		},
    	}
    
    	for _, tt := range tests {
    		l := lexer.New(tt.input)
    		p := New(l)
    		program := p.ParseProgram()
    		checkParserErrors(t, p)
    
    		actual := program.String()
    		if actual != tt.expected {
    			t.Errorf("expected=%q, got=%q", tt.expected, actual)
    		}
    	}
    }
    
    func TestBooleanExpression(t *testing.T) {
    	tests := []struct {
    		input           string
    		expectedBoolean bool
    	}{
    		{"true;", true},
    		{"false;", false},
    	}
    
    	for _, tt := range tests {
    		l := lexer.New(tt.input)
    		p := New(l)
    		program := p.ParseProgram()
    		checkParserErrors(t, p)
    
    		if len(program.Statements) != 1 {
    			t.Fatalf("program has not enough statements. got=%d",
    				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])
    		}
    
    		boolean, ok := stmt.Expression.(*ast.Boolean)
    		if !ok {
    			t.Fatalf("exp not *ast.Boolean. got=%T", stmt.Expression)
    		}
    		if boolean.Value != tt.expectedBoolean {
    			t.Errorf("boolean.Value not %t. got=%t", tt.expectedBoolean,
    				boolean.Value)
    		}
    	}
    }
    
    func TestIfExpression(t *testing.T) {
    	input := `if (x < y) { x }`
    
    	l := lexer.New(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.IfExpression)
    	if !ok {
    		t.Fatalf("stmt.Expression is not ast.IfExpression. got=%T",
    			stmt.Expression)
    	}
    
    	if !testInfixExpression(t, exp.Condition, "x", "<", "y") {
    		return
    	}
    
    	if len(exp.Consequence.Statements) != 1 {
    		t.Errorf("consequence is not 1 statements. got=%d\n",
    			len(exp.Consequence.Statements))
    	}
    
    	consequence, ok := exp.Consequence.Statements[0].(*ast.ExpressionStatement)
    	if !ok {
    		t.Fatalf("Statements[0] is not ast.ExpressionStatement. got=%T",
    			exp.Consequence.Statements[0])
    	}
    
    	if !testIdentifier(t, consequence.Expression, "x") {
    		return
    	}
    
    	if exp.Alternative != nil {
    		t.Errorf("exp.Alternative.Statements was not nil. got=%+v", exp.Alternative)
    	}
    }
    
    func TestIfElseExpression(t *testing.T) {
    	input := `if (x < y) { x } else { y }`
    
    	l := lexer.New(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.IfExpression)
    	if !ok {
    		t.Fatalf("stmt.Expression is not ast.IfExpression. got=%T", stmt.Expression)
    	}
    
    	if !testInfixExpression(t, exp.Condition, "x", "<", "y") {
    		return
    	}
    
    	if len(exp.Consequence.Statements) != 1 {
    		t.Errorf("consequence is not 1 statements. got=%d\n",
    			len(exp.Consequence.Statements))
    	}
    
    	consequence, ok := exp.Consequence.Statements[0].(*ast.ExpressionStatement)
    	if !ok {
    		t.Fatalf("Statements[0] is not ast.ExpressionStatement. got=%T",
    			exp.Consequence.Statements[0])
    	}
    
    	if !testIdentifier(t, consequence.Expression, "x") {
    		return
    	}
    
    	if len(exp.Alternative.Statements) != 1 {
    		t.Errorf("exp.Alternative.Statements does not contain 1 statements. got=%d\n",
    			len(exp.Alternative.Statements))
    	}
    
    	alternative, ok := exp.Alternative.Statements[0].(*ast.ExpressionStatement)
    	if !ok {
    		t.Fatalf("Statements[0] is not ast.ExpressionStatement. got=%T",
    			exp.Alternative.Statements[0])
    	}
    
    	if !testIdentifier(t, alternative.Expression, "y") {
    		return
    	}
    }
    
    func TestFunctionLiteralParsing(t *testing.T) {
    	input := `fn(x, y) { x + y; }`
    
    	l := lexer.New(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])
    	}
    
    	function, ok := stmt.Expression.(*ast.FunctionLiteral)
    	if !ok {
    		t.Fatalf("stmt.Expression is not ast.FunctionLiteral. got=%T",
    			stmt.Expression)
    	}
    
    	if len(function.Parameters) != 2 {
    		t.Fatalf("function literal parameters wrong. want 2, got=%d\n",
    			len(function.Parameters))
    	}
    
    	testLiteralExpression(t, function.Parameters[0], "x")
    	testLiteralExpression(t, function.Parameters[1], "y")
    
    	if len(function.Body.Statements) != 1 {
    		t.Fatalf("function.Body.Statements has not 1 statements. got=%d\n",
    			len(function.Body.Statements))
    	}
    
    	bodyStmt, ok := function.Body.Statements[0].(*ast.ExpressionStatement)
    	if !ok {
    		t.Fatalf("function body stmt is not ast.ExpressionStatement. got=%T",
    			function.Body.Statements[0])
    	}
    
    	testInfixExpression(t, bodyStmt.Expression, "x", "+", "y")
    }
    
    func TestFunctionParameterParsing(t *testing.T) {
    	tests := []struct {
    		input          string
    		expectedParams []string
    	}{
    		{input: "fn() {};", expectedParams: []string{}},
    		{input: "fn(x) {};", expectedParams: []string{"x"}},
    		{input: "fn(x, y, z) {};", expectedParams: []string{"x", "y", "z"}},
    	}
    
    	for _, tt := range tests {
    		l := lexer.New(tt.input)
    		p := New(l)
    		program := p.ParseProgram()
    		checkParserErrors(t, p)
    
    		stmt := program.Statements[0].(*ast.ExpressionStatement)
    		function := stmt.Expression.(*ast.FunctionLiteral)
    
    		if len(function.Parameters) != len(tt.expectedParams) {
    			t.Errorf("length parameters wrong. want %d, got=%d\n",
    				len(tt.expectedParams), len(function.Parameters))
    		}
    
    		for i, ident := range tt.expectedParams {
    			testLiteralExpression(t, function.Parameters[i], ident)
    		}
    	}
    }
    
    func TestCallExpressionParsing(t *testing.T) {
    	input := "add(1, 2 * 3, 4 + 5);"
    
    	l := lexer.New(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("stmt is not ast.ExpressionStatement. got=%T",
    			program.Statements[0])
    	}
    
    	exp, ok := stmt.Expression.(*ast.CallExpression)
    	if !ok {
    		t.Fatalf("stmt.Expression is not ast.CallExpression. got=%T",
    			stmt.Expression)
    	}
    
    	if !testIdentifier(t, exp.Function, "add") {
    		return
    	}
    
    	if len(exp.Arguments) != 3 {
    		t.Fatalf("wrong length of arguments. got=%d", len(exp.Arguments))
    	}
    
    	testLiteralExpression(t, exp.Arguments[0], 1)
    	testInfixExpression(t, exp.Arguments[1], 2, "*", 3)
    	testInfixExpression(t, exp.Arguments[2], 4, "+", 5)
    }
    
    func TestCallExpressionParameterParsing(t *testing.T) {
    	tests := []struct {
    		input         string
    		expectedIdent string
    		expectedArgs  []string
    	}{
    		{
    			input:         "add();",
    			expectedIdent: "add",
    			expectedArgs:  []string{},
    		},
    		{
    			input:         "add(1);",
    			expectedIdent: "add",
    			expectedArgs:  []string{"1"},
    		},
    		{
    			input:         "add(1, 2 * 3, 4 + 5);",
    			expectedIdent: "add",
    			expectedArgs:  []string{"1", "(2 * 3)", "(4 + 5)"},
    		},
    	}
    
    	for _, tt := range tests {
    		l := lexer.New(tt.input)
    		p := New(l)
    		program := p.ParseProgram()
    		checkParserErrors(t, p)
    
    		stmt := program.Statements[0].(*ast.ExpressionStatement)
    		exp, ok := stmt.Expression.(*ast.CallExpression)
    		if !ok {
    			t.Fatalf("stmt.Expression is not ast.CallExpression. got=%T",
    				stmt.Expression)
    		}
    
    		if !testIdentifier(t, exp.Function, tt.expectedIdent) {
    			return
    		}
    
    		if len(exp.Arguments) != len(tt.expectedArgs) {
    			t.Fatalf("wrong number of arguments. want=%d, got=%d",
    				len(tt.expectedArgs), len(exp.Arguments))
    		}
    
    		for i, arg := range tt.expectedArgs {
    			if exp.Arguments[i].String() != arg {
    				t.Errorf("argument %d wrong. want=%q, got=%q", i,
    					arg, exp.Arguments[i].String())
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769
    • 770
    • 771
    • 772
    • 773
    • 774
    • 775
    • 776
    • 777
    • 778
    • 779
    • 780
    • 781
    • 782
    • 783
    • 784
    • 785
    • 786
    • 787
    • 788
    • 789
    • 790
    • 791
    • 792
    • 793
    • 794
    • 795
    • 796
    • 797
    • 798
    • 799
    • 800
    • 801

    monkey/parser/parser_tracing.go

    package parser
    
    import (
    	"fmt"
    	"strings"
    )
    
    const traceIdentPlaceholder string = "\t"
    
    var traceLevel int = 0
    
    func identLevel() string {
    	return strings.Repeat(traceIdentPlaceholder, traceLevel-1)
    }
    
    func tracePrint(fs string) {
    	fmt.Printf("%s%s\n", identLevel(), fs)
    }
    
    func incIdent() { traceLevel += 1 }
    func decIdent() { traceLevel -= 1 }
    
    func trace(msg string) string {
    	incIdent()
    	tracePrint("BEGIN " + msg)
    	return msg
    }
    
    func untrace(msg string) {
    	tracePrint("END " + msg)
    	decIdent()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    monkey/object/object.go

    package object
    
    import (
    	"bytes"
    	"fmt"
    	"monkey/ast"
    	"strings"
    )
    
    const (
    	NULL_OBJ  = "NULL"
    	ERROR_OBJ = "ERROR"
    
    	INTEGER_OBJ = "INTEGER"
    	BOOLEAN_OBJ = "BOOLEAN"
    
    	RETURN_VALUE_OBJ = "RETURN_VALUE"
    
    	FUNCTION_OBJ = "FUNCTION"
    )
    
    type ObjectType string
    
    type Object interface {
    	Type() ObjectType
    	Inspect() string
    }
    
    type Integer struct {
    	Value int64
    }
    func (i *Integer) Type() ObjectType { return INTEGER_OBJ }
    func (i *Integer) Inspect() string  { return fmt.Sprintf("%d", i.Value) }
    
    type Boolean struct {
    	Value bool
    }
    func (b *Boolean) Type() ObjectType { return BOOLEAN_OBJ }
    func (b *Boolean) Inspect() string  { return fmt.Sprintf("%t", b.Value) }
    
    type Null struct{}
    func (n *Null) Type() ObjectType { return NULL_OBJ }
    func (n *Null) Inspect() string  { return "null" }
    
    type ReturnValue struct {
    	Value Object
    }
    func (rv *ReturnValue) Type() ObjectType { return RETURN_VALUE_OBJ }
    func (rv *ReturnValue) Inspect() string  { return rv.Value.Inspect() }
    
    type Error struct {
    	Message string
    }
    func (e *Error) Type() ObjectType { return ERROR_OBJ }
    func (e *Error) Inspect() string  { return "ERROR: " + e.Message }
    
    type Function struct {
    	Parameters []*ast.Identifier
    	Body       *ast.BlockStatement
    	Env        *Environment
    }
    func (f *Function) Type() ObjectType { return FUNCTION_OBJ }
    func (f *Function) Inspect() string {
    	var out bytes.Buffer
    
    	params := []string{}
    	for _, p := range f.Parameters {
    		params = append(params, p.String())
    	}
    
    	out.WriteString("fn")
    	out.WriteString("(")
    	out.WriteString(strings.Join(params, ", "))
    	out.WriteString(") ")
    	out.WriteString(f.Body.String())
    	out.WriteString("\n")
    
    	return out.String()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    monkey/object/environment.go

    package object
    
    type Environment struct {
    	store map[string]Object
    	outer *Environment
    }
    
    func (e *Environment) Get(name string) (Object, bool) {
    	obj, ok := e.store[name]
    	if !ok && e.outer != nil {
    		obj, ok = e.outer.Get(name)
    	}
    	return obj, ok
    }
    
    func (e *Environment) Set(name string, val Object) Object {
    	e.store[name] = val
    	return val
    }
    
    func NewEnvironment() *Environment {
    	s := make(map[string]Object)
    	return &Environment{store: s, outer: nil}
    }
    
    func NewEnclosedEnvironment(outer *Environment) *Environment {
    	env := NewEnvironment()
    	env.outer = outer
    	return env
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    monkey/evaluator/evaluator.go

    package evaluator
    
    import (
    	"fmt"
    	"monkey/ast"
    	"monkey/object"
    )
    
    var (
    	NULL  = &object.Null{}
    	TRUE  = &object.Boolean{Value: true}
    	FALSE = &object.Boolean{Value: false}
    )
    
    func Eval(node ast.Node, env *object.Environment) object.Object {
    	switch node := node.(type) {
    	// 语句
    	case *ast.Program:
    		return evalProgram(node, env)
    
    	case *ast.BlockStatement:
    		return evalBlockStatement(node, env)
    		
    	case *ast.ExpressionStatement:
    		return Eval(node.Expression, env)
    		
    	case *ast.ReturnStatement:
    		val := Eval(node.ReturnValue, env)
    		if isError(val) {
    			return val
    		}
    		return &object.ReturnValue{Value: val}
    		
    	case *ast.LetStatement:
    		val := Eval(node.Value, env)
    		if isError(val) {
    			return val
    		}
    		env.Set(node.Name.Token.Literal, val)
    
    	// 表达式
    	case *ast.IntegerLiteral:
    		return &object.Integer{Value: node.Value}
    	
    	case *ast.Boolean:
    		return nativeBoolToBooleanObject(node.Value)
    		
    	case *ast.PrefixExpression:
    		right := Eval(node.Right, env)
    		if isError(right) {
    			return right
    		}
    		return evalPrefixExpression(node.Token.Literal, right)
    		
    	case *ast.InfixExpression:
    		left := Eval(node.Left, env)
    		if isError(left) {
    			return left
    		}
    		right := Eval(node.Right, env)
    		if isError(right) {
    			return right
    		}
    		return evalInfixExpression(node.Token.Literal, left, right)
    		
    	case *ast.IfExpression:
    		return evalIfExpression(node, env)
    
    	case *ast.Identifier:
    		return evalIdentifier(node, env)
    		
    	case *ast.FunctionLiteral:
    		params := node.Parameters
    		body := node.Body
    		return &object.Function{Parameters: params, Env: env, Body: body}
    
    	case *ast.CallExpression:
    		function := Eval(node.Function, env)	//得到object.Function对象
    		if isError(function) {
    			return function
    		}
    		
    		args := evalExpressions(node.Arguments, env)	//函数实参expression,生成object
    		if len(args) == 1 && isError(args[0]) {
    			return args[0]
    		}
    
    		return applyFunction(function, args)
    	}	
    	return nil
    }
    
    func evalProgram(program *ast.Program, env *object.Environment) object.Object {
    	var result object.Object
    
    	for _, statement := range program.Statements { //遍历语句
    		result = Eval(statement, env)
    
    		switch result := result.(type) {
    		case *object.ReturnValue: //return语句
    			return result.Value
    		case *object.Error:	//错误语句
    			return result
    		}
    	}
    
    	return result
    }
    
    func evalBlockStatement(block *ast.BlockStatement, env *object.Environment) object.Object {
    	var result object.Object
    
    	for _, statement := range block.Statements {
    		result = Eval(statement, env)
    
    		if result != nil {
    			rt := result.Type() 
    			if rt == object.RETURN_VALUE_OBJ || rt == object.ERROR_OBJ { //return对象或者error对象
    				return result
    			}
    		}
    	}
    
    	return result
    }
    
    func evalPrefixExpression(operator string, right object.Object) object.Object {
    	switch operator {
    	case "!":
    		return evalBangOperatorExpression(right)
    	case "-":
    		return evalMinusPrefixOperatorExpression(right)
    	default:
    		return newError("unknown operator: %s%s", operator, right.Type())
    	}
    }
    
    func evalBangOperatorExpression(right object.Object) object.Object {
    	switch right {
    	case TRUE:
    		return FALSE
    	case FALSE:
    		return TRUE
    	case NULL:
    		return TRUE
    	default:
    		return FALSE
    	}
    }
    
    func evalMinusPrefixOperatorExpression(right object.Object) object.Object {
    	if right.Type() != object.INTEGER_OBJ {
    		return newError("unknown operator: -%s", right.Type())
    	}
    
    	value := right.(*object.Integer).Value
    	return &object.Integer{Value: -value}
    }
    
    func evalInfixExpression(
    	operator string,
    	left, right object.Object,
    ) object.Object {
    	switch {
    	case left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ:
    		return evalIntegerInfixExpression(operator, left, right)
    	case operator == "==":
    		return nativeBoolToBooleanObject(left == right)
    	case operator == "!=":
    		return nativeBoolToBooleanObject(left != right)
    	case left.Type() != right.Type():
    		return newError("type mismatch: %s %s %s",
    			left.Type(), operator, right.Type())
    	default:
    		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
    	}
    }
    
    func evalIfExpression(ie *ast.IfExpression, env *object.Environment) object.Object {
    	condition := Eval(ie.Condition, env)
    	if isError(condition) {
    		return condition
    	}
    	
    	if isTruthy(condition) {
    		return Eval(ie.Consequence, env)
    	} else if ie.Alternative != nil {
    		return Eval(ie.Alternative, env)
    	} else {
    		return NULL
    	}
    }
    
    func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object {
    	val, ok := env.Get(node.Token.Literal)
    	if !ok {
    		return newError("identifier not found: " + node.Token.Literal)
    	}
    
    	return val
    }
    
    func evalIntegerInfixExpression(
    	operator string,
    	left, right object.Object,
    ) object.Object {
    	leftVal := left.(*object.Integer).Value
    	rightVal := right.(*object.Integer).Value
    
    	switch operator {
    	case "+":
    		return &object.Integer{Value: leftVal + rightVal}
    	case "-":
    		return &object.Integer{Value: leftVal - rightVal}
    	case "*":
    		return &object.Integer{Value: leftVal * rightVal}
    	case "/":
    		return &object.Integer{Value: leftVal / rightVal}	
    	case "<":
    		return nativeBoolToBooleanObject(leftVal < rightVal)
    	case ">":
    		return nativeBoolToBooleanObject(leftVal > rightVal)
    	case "==":
    		return nativeBoolToBooleanObject(leftVal == rightVal)
    	case "!=":
    		return nativeBoolToBooleanObject(leftVal != rightVal)	
    	default:
    		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
    	}
    }
    
    func nativeBoolToBooleanObject(input bool) *object.Boolean {
    	if input {
    		return TRUE
    	}
    	return FALSE
    }
    
    func isTruthy(obj object.Object) bool {
    	switch obj {
    	case NULL:
    		return false
    	case TRUE:
    		return true
    	case FALSE:
    		return false
    	default:
    		return true
    	}
    }
    
    func newError(format string, a ...interface{}) *object.Error {
    	return &object.Error{Message: fmt.Sprintf(format, a...)}
    }
    
    func isError(obj object.Object) bool {
    	if obj != nil {
    		return obj.Type() == object.ERROR_OBJ
    	}
    	return false
    }
    
    // 解析实参表达式
    func evalExpressions(exps []ast.Expression, env *object.Environment) []object.Object {
    	var result []object.Object
    
    	for _, e := range exps {
    		evaluated := Eval(e, env)
    		if isError(evaluated) {
    			return []object.Object{evaluated}
    		}
    		result = append(result, evaluated)
    	}
    
    	return result
    }
    
    // 应用实参对象,计算函数值
    func applyFunction(fn object.Object, args []object.Object) object.Object {
    	function, ok := fn.(*object.Function)
    	if !ok {
    		return newError("not a function: %s", fn.Type())
    	}
    
    	extendedEnv := extendFunctionEnv(function, args)
    	evaluated := Eval(function.Body, extendedEnv)
    	return unwrapReturnValue(evaluated)
    }
    
    // 扩展函数对象中环境变量
    // 传入实参对象,关联函数定义中的标识符参数
    func extendFunctionEnv(fn *object.Function, args []object.Object) *object.Environment {
    	env := object.NewEnclosedEnvironment(fn.Env)
    
    	for paramIdx, param := range fn.Parameters {
    		env.Set(param.Token.Literal, args[paramIdx])
    	}
    
    	return env
    }
    
    func unwrapReturnValue(obj object.Object) object.Object {
    	if returnValue, ok := obj.(*object.ReturnValue); ok {
    		return returnValue.Value
    	}
    
    	return obj
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308

    monkey/evaluator/evaluator_test.go

    package evaluator
    
    import (
    	"monkey/lexer"
    	"monkey/object"
    	"monkey/parser"
    	"testing"
    )
    
    func testEval(input string) object.Object {
    	l := lexer.New(input)
    	p := parser.New(l)
    	program := p.ParseProgram()
    	env := object.NewEnvironment()
    
    	return Eval(program, env)
    }
    
    func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
    	result, ok := obj.(*object.Integer)
    	if !ok {
    		t.Errorf("object is not Integer. got=%T (%+v)", obj, obj)
    		return false
    	}
    	if result.Value != expected {
    		t.Errorf("object has wrong value. got=%d, want=%d",
    			result.Value, expected)
    		return false
    	}
    
    	return true
    }
    
    func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
    	result, ok := obj.(*object.Boolean)
    	if !ok {
    		t.Errorf("object is not Boolean. got=%T (%+v)", obj, obj)
    		return false
    	}
    	if result.Value != expected {
    		t.Errorf("object has wrong value. got=%t, want=%t",
    			result.Value, expected)
    		return false
    	}
    	return true
    }
    
    func testNullObject(t *testing.T, obj object.Object) bool {
    	if obj != NULL {
    		t.Errorf("object is not NULL. got=%T (%+v)", obj, obj)
    		return false
    	}
    	return true
    }
    
    func TestEvalIntegerExpression(t *testing.T) {
    	tests := []struct {
    		input    string
    		expected int64
    	}{
    		{"5", 5},
    		{"10", 10},
    		{"-5", -5},
    		{"-10", -10},
    		{"5 + 5 + 5 + 5 - 10", 10},
    		{"2 * 2 * 2 * 2 * 2", 32},
    		{"-50 + 100 + -50", 0},
    		{"5 * 2 + 10", 20},
    		{"5 + 2 * 10", 25},
    		{"20 + 2 * -10", 0},
    		{"50 / 2 * 2 + 10", 60},
    		{"2 * (5 + 10)", 30},
    		{"3 * 3 * 3 + 10", 37},
    		{"3 * (3 * 3) + 10", 37},
    		{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
    	}
    
    	for _, tt := range tests {
    		evaluated := testEval(tt.input)
    		testIntegerObject(t, evaluated, tt.expected)
    	}
    }
    
    func TestEvalBooleanExpression(t *testing.T) {
    	tests := []struct {
    		input    string
    		expected bool
    	}{
    		{"true", true},
    		{"false", false},
    		{"1 < 2", true},
    		{"1 > 2", false},
    		{"1 < 1", false},
    		{"1 > 1", false},
    		{"1 == 1", true},
    		{"1 != 1", false},
    		{"1 == 2", false},
    		{"1 != 2", true},
    		{"true == true", true},
    		{"false == false", true},
    		{"true == false", false},
    		{"true != false", true},
    		{"false != true", true},
    		{"(1 < 2) == true", true},
    		{"(1 < 2) == false", false},
    		{"(1 > 2) == true", false},
    		{"(1 > 2) == false", true},
    	}
    
    	for _, tt := range tests {
    		evaluated := testEval(tt.input)
    		testBooleanObject(t, evaluated, tt.expected)
    	}
    }
    
    func TestBangOperator(t *testing.T) {
    	tests := []struct {
    		input    string
    		expected bool
    	}{
    		{"!true", false},
    		{"!false", true},
    		{"!5", false},
    		{"!!true", true},
    		{"!!false", false},
    		{"!!5", true},
    	}
    
    	for _, tt := range tests {
    		evaluated := testEval(tt.input)
    		testBooleanObject(t, evaluated, tt.expected)
    	}
    }
    
    func TestIfElseExpressions(t *testing.T) {
    	tests := []struct {
    		input    string
    		expected interface{}
    	}{
    		{"if (true) { 10 }", 10},
    		{"if (false) { 10 }", nil},
    		{"if (1) { 10 }", 10},
    		{"if (1 < 2) { 10 }", 10},
    		{"if (1 > 2) { 10 }", nil},
    		{"if (1 > 2) { 10 } else { 20 }", 20},
    		{"if (1 < 2) { 10 } else { 20 }", 10},
    	}
    
    	for _, tt := range tests {
    		evaluated := testEval(tt.input)
    		integer, ok := tt.expected.(int)
    		if ok {
    			testIntegerObject(t, evaluated, int64(integer))
    		} else {
    			testNullObject(t, evaluated)
    		}
    	}
    }
    
    func TestReturnStatements(t *testing.T) {
    	tests := []struct {
    		input    string
    		expected int64
    	}{
    		{"return 10;", 10},
    		{"return 10; 9;", 10},
    		{"return 2 * 5; 9;", 10},
    		{"9; return 2 * 5; 9;", 10},
    		{"if (10 > 1) { return 10; }", 10},		
    		{`if (10 > 1) {
    	if (10 > 1) {
    		return 10;
    	}
    	return 1;
    }`, 10},
    		{`let f = fn(x) {
    	return x;
    	x + 10;
    }; f(10);`, 10},
    		{`let f = fn(x) {
       let result = x + 10;
       return result;
       return 10;
    }; f(10);`, 20},
    	}
    
    	for _, tt := range tests {
    		evaluated := testEval(tt.input)
    		testIntegerObject(t, evaluated, tt.expected)
    	}
    }
    
    func TestErrorHandling(t *testing.T) {
    	tests := []struct {
    		input           string
    		expectedMessage string
    	}{
    		{
    			"5 + true;",
    			"type mismatch: INTEGER + BOOLEAN",
    		},		
    		{
    			"5 + true; 5;",
    			"type mismatch: INTEGER + BOOLEAN",
    		},
    		{
    			"-true",
    			"unknown operator: -BOOLEAN",
    		},
    		{
    			"true + false;",
    			"unknown operator: BOOLEAN + BOOLEAN",
    		},		
    		{
    			"true + false + true + false;",
    			"unknown operator: BOOLEAN + BOOLEAN",
    		},
    		{
    			"5; true + false; 5",
    			"unknown operator: BOOLEAN + BOOLEAN",
    		},		
    		{
    			"if (10 > 1) { true + false; }",
    			"unknown operator: BOOLEAN + BOOLEAN",
    		},	
    		{`if (10 > 1) {
    	if (10 > 1) {
    		return true + false;
    	}
    	return 1;
    }`, "unknown operator: BOOLEAN + BOOLEAN",
    		},	
    		{
    			"foobar",
    			"identifier not found: foobar",
    		},	
    	}
    
    	for _, tt := range tests {
    		evaluated := testEval(tt.input)
    
    		errObj, ok := evaluated.(*object.Error)
    		if !ok {
    			t.Errorf("no error object returned. got=%T(%+v)",
    				evaluated, evaluated)
    			continue
    		}
    
    		if errObj.Message != tt.expectedMessage {
    			t.Errorf("wrong error message. expected=%q, got=%q",
    				tt.expectedMessage, errObj.Message)
    		}
    	}
    }
    
    func TestLetStatements(t *testing.T) {
    	tests := []struct {
    		input    string
    		expected int64
    	}{
    		{"let a = 5; a;", 5},
    		{"let a = 5 * 5; a;", 25},
    		{"let a = 5; let b = a; b;", 5},
    		{"let a = 5; let b = a; let c = a + b + 5; c;", 15},
    	}
    
    	for _, tt := range tests {
    		testIntegerObject(t, testEval(tt.input), tt.expected)
    	}
    }
    
    func TestFunctionObject(t *testing.T) {
    	input := "fn(x) { x + 2; };"
    
    	evaluated := testEval(input)
    	fn, ok := evaluated.(*object.Function)
    	if !ok {
    		t.Fatalf("object is not Function. got=%T (%+v)", evaluated, evaluated)
    	}
    
    	if len(fn.Parameters) != 1 {
    		t.Fatalf("function has wrong parameters. Parameters=%+v",
    			fn.Parameters)
    	}
    
    	if fn.Parameters[0].String() != "x" {
    		t.Fatalf("parameter is not 'x'. got=%q", fn.Parameters[0])
    	}
    
    	expectedBody := "{\n\t(x + 2);\n}"
    
    	if fn.Body.String() != expectedBody {
    		t.Fatalf("body is not %q. got=%q", expectedBody, fn.Body.String())
    	}
    }
    
    func TestFunctionApplication(t *testing.T) {
    	tests := []struct {
    		input    string
    		expected int64
    	}{
    		{"let identity = fn(x) { x; }; identity(5);", 5},
    		{"let identity = fn(x) { return x; }; identity(5);", 5},
    		{"let double = fn(x) { x * 2; }; double(5);", 10},
    		{"let add = fn(x, y) { x + y; }; add(5, 5);", 10},
    		{"let add = fn(x, y) { x + y; }; add(5 + 5, add(5, 5));", 20},
    		{"fn(x) { x; }(5)", 5},
    	}
    
    	for _, tt := range tests {
    		testIntegerObject(t, testEval(tt.input), tt.expected)
    	}
    }
    
    func TestEnclosingEnvironments(t *testing.T) {
    	input := `
    let first = 10;
    let second = 10;
    let third = 10;
    
    let ourFunction = fn(first) {
      let second = 20;
    
      first + second + third;
    };
    
    ourFunction(20) + first + second;`
    
    	testIntegerObject(t, testEval(input), 70)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330

    monkey/repl/repl.go

    package repl
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"monkey/lexer"
    	"monkey/parser"
    	"monkey/evaluator"
    	"monkey/object"
    )
    
    const PROMPT = ">>"
    
    func Start(in io.Reader, out io.Writer) {
    	scanner := bufio.NewScanner(in)
    	env := object.NewEnvironment()
    	
    	for {
    		fmt.Fprintf(out, PROMPT)
    		scanned := scanner.Scan()
    		if !scanned {
    			return
    		}
    
    		line := scanner.Text()
    		l := lexer.New(line)
    		
    		p := parser.New(l)
    		program := p.ParseProgram()
    		if len(p.Errors()) != 0 {
    			printParserErrors(out, p.Errors())
    			continue
    		}
    
    		if evaluated := evaluator.Eval(program, env); evaluated != nil {	
    			io.WriteString(out, evaluated.Inspect() + "\n")
    		}
    	}
    }
    
    const MONKEY_FACE = `            __,__
       .--.  .-"     "-.  .--.
      / .. \/  .-. .-.  \/ .. \
     | |  '|  /   Y   \  |'  | |
     | \   \  \ 0 | 0 /  /   / |
      \ '- ,\.-"""""""-./, -' /
       ''-' /_   ^ ^   _\ '-''
           |  \._   _./  |
           \   \ '~' /   /
            '._ '-=-' _.'
               '-----'
    `
    
    func printParserErrors(out io.Writer, errors []string) {
    	io.WriteString(out, MONKEY_FACE)
    	io.WriteString(out, "Woops! We ran into some monkey business here!\n")
    	io.WriteString(out, "parser errors:\n")
    	for _, msg := range errors {
    		io.WriteString(out, "\t" + msg + "\n")
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    monkey/main.go

    package main
    
    import (
    	"fmt"
    	"monkey/repl"
    	"os"
    	"os/user"
    )
    
    func main() {
    	user, err := user.Current()
    	if err != nil {
    		panic(err)
    	}
    	fmt.Printf("Hello %s! This is the Monkey programming language!\n", user.Username)
    	fmt.Printf("Feel free to type in commands\n")
    	repl.Start(os.Stdin, os.Stdout)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    monkey/run.txt

    cd monkey
    
    go mod init monkey
    
    go test .\lexer -count=1
    
    go test .\ast -count=1
    
    go test .\parser -count=1
    
    go test .\evaluator -count=1
    
    go run main.go
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    acwing算法提高之图论--无向图的双连通分量
    美发店微信小程序怎么制作
    一文了解 Java 中的构造器
    C++模板元编程详细教程(之一)
    请问Java语言是否支持音频和视频播放、串口通信、截屏、录屏、底层协议等功能?
    【图像处理笔记3】Gabor Filter的手动和调包实现
    黑客(网络安全)技术自学30天
    SpringSecurity中注解讲解
    SpringCloudAlibaba 微服务讲解(三)Nacos Discovery-服务治理
    警惕AI换脸技术:近期诈骗事件揭示的惊人真相
  • 原文地址:https://blog.csdn.net/oqqyx1234567/article/details/126577227