Skip to content

Commit

Permalink
handle with setq special form in evaluator (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
JunNishimura committed Jul 25, 2024
1 parent 53304e2 commit 61bc6d6
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 8 deletions.
47 changes: 46 additions & 1 deletion evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ func evalValueList(consCell *ast.ConsCell, env *object.Environment) []object.Obj
if isError(car) {
return []object.Object{car}
}
list = append(list, car)
if symbol, ok := car.(*object.Symbol); ok {
list = append(list, symbol.Value)
} else {
list = append(list, car)
}

// move to the next cons cell or return the list if the cdr is nil
switch cdr := consCell.Cdr().(type) {
Expand Down Expand Up @@ -232,6 +236,8 @@ func evalSpecialForm(sexp *ast.ConsCell, env *object.Environment) object.Object
return evalBackquote(sexp, env)
case "if":
return evalIf(sexp, env)
case "setq":
return evalSetq(sexp, env)
}

return newError("unknown special form: %s", spForm.Value)
Expand Down Expand Up @@ -428,3 +434,42 @@ func isTruthy(obj object.Object) bool {
return true
}
}

func evalSetq(consCell *ast.ConsCell, env *object.Environment) object.Object {
spForm, ok := consCell.Car().(*ast.SpecialForm)
if !ok {
return newError("expect special form, got %T", consCell.Car())
}
if spForm.Token.Type != token.SETQ {
return newError("expect special form setq, got %s", spForm.Token.Type)
}

cdr, ok := consCell.Cdr().(*ast.ConsCell)
if !ok {
return newError("not defined name of symbol")
}

symbolName, ok := cdr.Car().(*ast.Symbol)
if !ok {
return newError("expect symbol, got %T", cdr.Car())
}

cddr, ok := cdr.Cdr().(*ast.ConsCell)
if !ok {
return newError("not defined value of symbol")
}

value := Eval(cddr.Car(), env)
if isError(value) {
return value
}

symbol := &object.Symbol{
Name: symbolName.Value,
Value: value,
}

env.Set(symbolName.Value, symbol)

return symbol
}
46 changes: 39 additions & 7 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,30 @@ func testEval(input string) object.Object {

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 ok {
if result.Value != expected {
t.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
return false
}
return true
}
if result.Value != expected {
t.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
return false

symbol, ok := obj.(*object.Symbol)
if ok {
integer, ok := symbol.Value.(*object.Integer)
if !ok {
t.Errorf("object is not Integer. got=%T (%+v)", result.Value, result.Value)
return false
}
if integer.Value != expected {
t.Errorf("object has wrong value. got=%d, want=%d", integer.Value, expected)
return false
}
return true
}
return true

t.Errorf("object is not Integer. got=%T (%+v)", obj, obj)
return false
}

func TestEvalIntegerExpression(t *testing.T) {
Expand Down Expand Up @@ -201,3 +216,20 @@ func TestIfExpression(t *testing.T) {
}
}
}

func TestSetqExpression(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"(setq x 10) x", 10},
{"(setq x 10) (setq x 20) x", 20},
{"(setq x 10) (setq y 20) (+ x y)", 30},
{"(setq x (+ 1 1)) x", 2},
}

for _, tt := range tests {
evaluated := testEval(tt.input)
testIntegerObject(t, evaluated, tt.expected)
}
}

0 comments on commit 61bc6d6

Please sign in to comment.