Pārlūkot izejas kodu

bindings & The environment -- add environment

runningwater 3 gadi atpakaļ
vecāks
revīzija
877ea3a776
4 mainītis faili ar 47 papildinājumiem un 21 dzēšanām
  1. 23 19
      evaluator/evaluator.go
  2. 2 1
      evaluator/evaluator_test.go
  3. 19 0
      object/environment.go
  4. 3 1
      repl/repl.go

+ 23 - 19
evaluator/evaluator.go

@@ -12,14 +12,14 @@ var (
 	FALSE = &object.Boolean{Value: false}
 )
 
-func Eval(node ast.Node) object.Object {
+func Eval(node ast.Node, env *object.Environment) object.Object {
 	switch node := node.(type) {
 	// Statements
 	case *ast.Program:
-		return evalProgram(node)
+		return evalProgram(node, env)
 
 	case *ast.ExpressionStatement:
-		return Eval(node.Expression)
+		return Eval(node.Expression, env)
 
 	// Expression
 	case *ast.IntegerLiteral:
@@ -27,33 +27,37 @@ func Eval(node ast.Node) object.Object {
 	case *ast.Boolean:
 		return nativeBooleanObject(node.Value)
 	case *ast.PrefixExpression:
-		right := Eval(node.Right)
+		right := Eval(node.Right, env)
 		if isError(right) {
 			return right
 		}
 		return evalPrefixExpression(node.Operator, right)
 	case *ast.InfixExpression:
-		left := Eval(node.Left)
+		left := Eval(node.Left, env)
 		if isError(left) {
 			return left
 		}
-		right := Eval(node.Right)
+		right := Eval(node.Right, env)
 		if isError(right) {
 			return right
 		}
 		return evalInfixExpression(node.Operator, left, right)
-
 	case *ast.BlockStatement:
-		return evalBlockStatements(node)
+		return evalBlockStatements(node, env)
 	case *ast.IfExpression:
-		return evalIfExpression(node)
-
+		return evalIfExpression(node, env)
 	case *ast.ReturnStatement:
-		val := Eval(node.ReturnValue)
+		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
+		}
+		// Huh? Now what?
 	}
 
 	return nil
@@ -62,11 +66,11 @@ func Eval(node ast.Node) object.Object {
 func newError(format string, a ...interface{}) *object.Error {
 	return &object.Error{Msg: fmt.Sprintf(format, a...)}
 }
-func evalProgram(node *ast.Program) object.Object {
+func evalProgram(node *ast.Program, env *object.Environment) object.Object {
 	var result object.Object
 
 	for _, stmt := range node.Statements {
-		result = Eval(stmt)
+		result = Eval(stmt, env)
 		// skip return 后面的语句
 		switch result := result.(type) {
 		case *object.ReturnValue:
@@ -111,24 +115,24 @@ func evalInfixExpression(operator string, left object.Object, right object.Objec
 		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
 	}
 }
-func evalIfExpression(node *ast.IfExpression) object.Object {
-	condition := Eval(node.Condition)
+func evalIfExpression(node *ast.IfExpression, env *object.Environment) object.Object {
+	condition := Eval(node.Condition, env)
 	if isError(condition) {
 		return condition
 	}
 	if isTruthy(condition) {
-		return Eval(node.Consequence)
+		return Eval(node.Consequence, env)
 	} else if node.Alternative != nil {
-		return Eval(node.Alternative)
+		return Eval(node.Alternative, env)
 	} else {
 		return NULL
 	}
 }
-func evalBlockStatements(block *ast.BlockStatement) object.Object {
+func evalBlockStatements(block *ast.BlockStatement, env *object.Environment) object.Object {
 	var result object.Object
 
 	for _, stmt := range block.Statements {
-		result = Eval(stmt)
+		result = Eval(stmt, env)
 
 		if result != nil {
 			rt := result.Type()

+ 2 - 1
evaluator/evaluator_test.go

@@ -232,6 +232,7 @@ func testEval(input string) object.Object {
 	l := lexer.New(input)
 	p := parser.New(l)
 	program := p.ParseProgram()
+	env := object.NewEnvironment()
 
-	return Eval(program)
+	return Eval(program, env)
 }

+ 19 - 0
object/environment.go

@@ -0,0 +1,19 @@
+package object
+
+func NewEnvironment() *Environment {
+	s := make(map[string]Object)
+	return &Environment{store: s}
+}
+
+type Environment struct {
+	store map[string]Object
+}
+
+func (e *Environment) Get(name string) (Object, bool) {
+	obj, ok := e.store[name]
+	return obj, ok
+}
+func (e *Environment) Set(name string, val Object) Object {
+	e.store[name] = val
+	return val
+}

+ 3 - 1
repl/repl.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github/runnignwater/monkey/evaluator"
 	"github/runnignwater/monkey/lexer"
+	"github/runnignwater/monkey/object"
 	"github/runnignwater/monkey/parser"
 	"io"
 	"log"
@@ -21,6 +22,7 @@ const PROMPT = ">>> "
 
 func Start(in io.Reader, out io.Writer) {
 	scanner := bufio.NewScanner(in)
+	env := object.NewEnvironment()
 
 	for {
 		fmt.Printf(PROMPT)
@@ -38,7 +40,7 @@ func Start(in io.Reader, out io.Writer) {
 			continue
 		}
 
-		evaluated := evaluator.Eval(program)
+		evaluated := evaluator.Eval(program, env)
 		if evaluated != nil {
 			if _, err := io.WriteString(out, evaluated.Inspect()); err != nil {
 				panic(err)