]> git.lizzy.rs Git - nothing.git/blobdiff - src/script/scope.c
TODO(#391)
[nothing.git] / src / script / scope.c
index f7c8d375fa79e01c2bbe08d991545a072b77c209..2a7f8a32f981418ff209a93485d5101cd32102ea 100644 (file)
@@ -1,43 +1,69 @@
+#include <assert.h>
 #include "./scope.h"
 
-struct Expr empty_scope(void)
+static struct Expr get_scope_value_impl(struct Expr scope, struct Expr name)
 {
-    return CONS(NIL, NIL);
+    if (cons_p(scope)) {
+        struct Expr value = assoc(name, scope.cons->car);
+        return nil_p(value) ? get_scope_value_impl(scope.cons->cdr, name) : value;
+    }
+
+    return scope;
 }
 
-struct Expr get_scope_value(struct Expr scope, struct Expr name)
+struct Expr get_scope_value(const struct Scope *scope, struct Expr name)
 {
-    switch (scope.type) {
-    case EXPR_CONS: {
-        struct Expr value = assoc(name, scope.cons->car);
-        return nil_p(value) ? get_scope_value(scope.cons->cdr, name) : value;
-    } break;
+    return get_scope_value_impl(scope->expr, name);
+}
 
-    default:
-        return scope;
+static struct Expr set_scope_value_impl(Gc *gc, struct Expr scope, struct Expr name, struct Expr value)
+{
+    if (cons_p(scope)) {
+        if (!nil_p(assoc(name, scope.cons->car)) || nil_p(scope.cons->cdr)) {
+            return CONS(gc,
+                        CONS(gc, CONS(gc, name, value), scope.cons->car),
+                        scope.cons->cdr);
+        } else {
+            return CONS(gc,
+                        scope.cons->car,
+                        set_scope_value_impl(gc, scope.cons->cdr, name, value));
+        }
+    } else {
+        return CONS(gc,
+                    CONS(gc, CONS(gc, name, value), NIL(gc)),
+                    scope);
     }
 }
 
-struct Expr set_scope_value(struct Expr scope, struct Expr name, struct Expr value)
+void set_scope_value(Gc *gc, struct Scope *scope, struct Expr name, struct Expr value)
 {
-    (void) name;
-    (void) value;
-
-    /* TODO(#312): set_scope_value is not implemented */
-
-    return scope;
+    scope->expr = set_scope_value_impl(gc, scope->expr, name, value);
 }
 
-struct Expr push_scope_frame(struct Expr scope)
+void push_scope_frame(Gc *gc, struct Scope *scope, struct Expr vars, struct Expr args)
 {
-    return CONS(empty_scope(), scope);
+    assert(gc);
+    assert(scope);
+
+    struct Expr frame = NIL(gc);
+
+    while(!nil_p(vars) && !nil_p(args)) {
+        frame = CONS(gc,
+                     CONS(gc, vars.cons->car, args.cons->car),
+                     frame);
+        vars = vars.cons->cdr;
+        args = args.cons->cdr;
+    }
+
+    scope->expr = CONS(gc, frame, scope->expr);
 }
 
-struct Expr pop_scope_frame(struct Expr scope)
+void pop_scope_frame(Gc *gc, struct Scope *scope)
 {
-    if (scope.type == EXPR_CONS) {
-        return scope.cons->cdr;
-    } else {
-        return scope;
+    assert(gc);
+    assert(scope);
+
+    if (!nil_p(scope->expr)) {
+        scope->expr = scope->expr.cons->cdr;
     }
 }