Skip to content

Commit

Permalink
handle with set expression in evaluator (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
JunNishimura committed Sep 28, 2024
1 parent 637936c commit 0fb3e3b
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 17 deletions.
38 changes: 22 additions & 16 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,42 @@ var (
False = &object.Boolean{Value: false}
)

func Eval(exp ast.Expression) object.Object {
func Eval(exp ast.Expression, env *object.Environment) object.Object {
switch expt := exp.(type) {
case *ast.Program:
return evalProgram(expt)
return evalProgram(expt, env)
case *ast.IntegerLiteral:
return &object.Integer{Value: expt.Value}
case *ast.Boolean:
return nativeBoolToBooleanObject(expt.Value)
case *ast.PrefixAtom:
right := Eval(expt.Right)
right := Eval(expt.Right, env)
if isError(right) {
return right
}
return evalPrefixAtom(expt.Operator, right)
case *ast.Symbol:
return evalSymbol(expt)
case *ast.CommandObject:
return evalCommandObject(expt)
return evalCommandObject(expt, env)
case *ast.IfExpression:
return evalIfExpression(expt)
return evalIfExpression(expt, env)
case *ast.SetExpression:
value := Eval(expt.Value, env)
if isError(value) {
return value
}
return env.Set(expt.Name.Value, value)
default:
return newError("unknown expression type: %T", exp)
}
}

func evalProgram(program *ast.Program) object.Object {
func evalProgram(program *ast.Program, env *object.Environment) object.Object {
var result object.Object

for _, exp := range program.Expressions {
result = Eval(exp)
result = Eval(exp, env)
}

return result
Expand Down Expand Up @@ -105,25 +111,25 @@ func evalSymbol(symbol *ast.Symbol) object.Object {
return newError("symbol not found: %s", symbol.Value)
}

func evalCommandObject(command *ast.CommandObject) object.Object {
symbol := Eval(command.Symbol)
func evalCommandObject(command *ast.CommandObject, env *object.Environment) object.Object {
symbol := Eval(command.Symbol, env)
if isError(symbol) {
return symbol
}

args := evalArgs(command.Args)
args := evalArgs(command.Args, env)
if len(args) == 1 && isError(args[0]) {
return args[0]
}

return applyFunction(symbol, args)
}

func evalArgs(args []ast.Expression) []object.Object {
func evalArgs(args []ast.Expression, env *object.Environment) []object.Object {
var result []object.Object

for _, arg := range args {
evaluated := Eval(arg)
evaluated := Eval(arg, env)
if isError(evaluated) {
return []object.Object{evaluated}
}
Expand All @@ -142,16 +148,16 @@ func applyFunction(function object.Object, args []object.Object) object.Object {
}
}

func evalIfExpression(ie *ast.IfExpression) object.Object {
condition := Eval(ie.Condition)
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)
return Eval(ie.Consequence, env)
} else if ie.Alternative != nil {
return Eval(ie.Alternative)
return Eval(ie.Alternative, env)
} else {
return False
}
Expand Down
47 changes: 46 additions & 1 deletion evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ func testEval(t *testing.T, input string) object.Object {
t.Fatalf("error: %s", err)
}

return Eval(program)
env := object.NewEnvironment()

return Eval(program, env)
}

func testIntegerObject(t *testing.T, obj object.Object, expected int64) {
Expand Down Expand Up @@ -354,3 +356,46 @@ func TestIfElseExpression(t *testing.T) {
})
}
}

func TestSetExpression(t *testing.T) {
tests := []struct {
name string
input string
expected int64
}{
{
name: "set expression",
input: `
{
"set": {
"var": "$x",
"val": 10
}
}`,
expected: 10,
},
{
name: "set expression with object",
input: `
{
"set": {
"var": "$x",
"val": {
"command": {
"symbol": "+",
"args": [1, 2]
}
}
}
}`,
expected: 3,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
evaluated := testEval(t, tt.input)
testIntegerObject(t, evaluated, tt.expected)
})
}
}

0 comments on commit 0fb3e3b

Please sign in to comment.