aboutsummaryrefslogtreecommitdiff
path: root/evaluator/quote_unquote.go
diff options
context:
space:
mode:
Diffstat (limited to 'evaluator/quote_unquote.go')
-rw-r--r--evaluator/quote_unquote.go68
1 files changed, 68 insertions, 0 deletions
diff --git a/evaluator/quote_unquote.go b/evaluator/quote_unquote.go
new file mode 100644
index 0000000..d3521f9
--- /dev/null
+++ b/evaluator/quote_unquote.go
@@ -0,0 +1,68 @@
+package evaluator
+
+import (
+ "fmt"
+ "monkey/ast"
+ "monkey/object"
+ "monkey/token"
+)
+
+func quote(node ast.Node, env *object.Environment) object.Object {
+ node = evalUnquoteCalls(node, env)
+ return &object.Quote{Node: node}
+}
+
+func evalUnquoteCalls(quoted ast.Node, env *object.Environment) ast.Node {
+ return ast.Modify(quoted, func(node ast.Node) ast.Node {
+ if !isUnquoteCall(node) {
+ return node
+ }
+
+ call, ok := node.(*ast.CallExpression)
+ if !ok {
+ return node
+ }
+
+ if len(call.Arguments) != 1 {
+ return node
+ }
+
+ unquoted := Eval(call.Arguments[0], env)
+ return convertObjectToASTNode(unquoted)
+ })
+}
+
+func isUnquoteCall(node ast.Node) bool {
+ callExpression, ok := node.(*ast.CallExpression)
+ if !ok {
+ return false
+ }
+
+ return callExpression.Function.TokenLiteral() == "unquote"
+}
+
+func convertObjectToASTNode(obj object.Object) ast.Node {
+ switch obj := obj.(type) {
+ case *object.Integer:
+ t := token.Token{
+ Type: token.INT,
+ Literal: fmt.Sprintf("%d", obj.Value),
+ }
+ return &ast.IntegerLiteral{Token: t, Value: obj.Value}
+
+ case *object.Boolean:
+ var t token.Token
+ if obj.Value {
+ t = token.Token{Type: token.TRUE, Literal: "true"}
+ } else {
+ t = token.Token{Type: token.FALSE, Literal: "false"}
+ }
+ return &ast.Boolean{Token: t, Value: obj.Value}
+
+ case *object.Quote:
+ return obj.Node
+
+ default:
+ return nil
+ }
+}