Golang でプログラミング言語を作る__Part14
Aug 22, 2017 · 4 min read
前回の続きから入ります。今回はif文タイプのevaluatorを作っていきます。
if文は、conditionに合致した時(TRUEである)のみ、そのblock”{}”内の式が実行されます。なので、まずは条件分を先に解釈してTRUE/FALSEを判断していく必要があります。
ここでは、trueは、falseとnullではない全ての値としています。
では、今回もTDDで実装してきます。
evaluator/evaluator_test.go
func TestIfElseExpression(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)
}
}
}
また、 testNullObject は次のような処理になります。
if文の処理が何も返さない、つまり引数のオブジェクトがnilの時に、下の処理に移ります。
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
}このテストがfailすることを確認したら、evaluatorを実装します。
func Eval(node ast.Node, env *object.Environment) object.Object {
switch node := node.(type) {
// [...]
case *ast.BlockStatement:
return evalBlockStatement(node, env)
// [...] case *ast.IfExpression:
return evalIfExpression(node, env)
// [...]
}
また、evaluatorに渡されるASTノードがIf文タイプの値であった時に、次の evalIfExpression() 関数に渡されます。
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
}
}
isTruthy 関数は、条件式がfalseやnullならfalseを、それ以外の値全てをtrueを返すものになります。
ここで、条件に基づく実行(evaluation)する文の分岐が、行われています。
最後にテストを走らせて、passすることを確認します。
次は、return文の解釈に取り組んでいきます。
