Golang でプログラミング言語を作る__Part15

Tuyoshi Akiyama
Aug 22, 2017 · 5 min read

前回はif文のevaluatorを実装しました。今回は、return文のを作っていきます。

ここでのreturnの機能は他のプログラミング言語同様に、一連のStatementsの解釈を止めさせ、その止まる前までの処理(evaluation)を行います。

Statements内のreturn以降は、処理されません。


まずは、オブジェクトにreturn文の定義を行います。以前行った、他の値タイプの定義内容と同様になります。

object.ReturnValue は値(Value)をwrapするものになります。ここでのreturn文の値は他のObjectタイプである必要があります。

return文のオブジェクトを作ったら、次はテストを作成します。

evaluator/evaluator_test.go

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) {
if (10 > 1) {
return 10;
}
return 1;
}
`,
10,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testIntegerObject(t, evaluated, tt.expected)
}
}

上のテストケース(return文)を通るevaluatorは次のものになります。

func Eval(node ast.Node, env *object.Environment) object.Object {
switch node := node.(type) {
// [...]
case *ast.Program:
return evalProgram(node, env)
case *ast.ReturnStatement:
val := Eval(node.ReturnValue, env)
if isError(val) {
return val
}
return &object.ReturnValue{Value: val}
case *ast.BlockStatement:
return evalBlockStatement(node, env)
// [...]
}
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 result.Value
case *object.Error:
return result
}
}
return result
}

ast.Programノード(一連のStatements)は、各Statementを返す evalProgram 関数に渡されます。

return文のオブジェクトが渡された時、そのオブジェクトの値を返します。

この evalProgram 関数では、return文はその値だけを返され、return文のオブジェクトは返されません。

また、”{}”ブロックステートメントタイプのASTノードの場合は、次の evalBlockStatement に処理が移ります。

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 result
}
}
}
return result
}

ここでは、明示的に返り値をwrapしないで、各オブジェクトのTypeのみをチェックします。

それがreturn文のオブジェクトならば、そのオブジェクトそのものを Eval 関数に渡されます。そして、 object.ReturnValue が返されます。

これによって、ソースの処理(evaluation)を通っていく過程でreturn文があった時に、その時点で処理が終わるようになります。

以上の処理を書き終えたら、テストを走らせpassすることを確認します。

これでreturn文のevaluation実装が終わりました。

次は、エラーハンドリングの実装を行っていきます。

)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade