]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/level/script.c
(#477) Replace all instances of malloc with nth_alloc
[nothing.git] / src / game / level / script.c
index 641e6fb95e623d755b7c190c65deb40a86907617..568337b0cb387b4990525d23a536eedcc8732789 100644 (file)
 #include <assert.h>
 
+#include "ebisp/gc.h"
+#include "ebisp/interpreter.h"
+#include "ebisp/parser.h"
+#include "ebisp/scope.h"
 #include "script.h"
+#include "str.h"
+#include "system/error.h"
 #include "system/line_stream.h"
+#include "system/lt.h"
+#include "system/nth_alloc.h"
+#include "ui/console.h"
 
-/* TODO(#457): script entity clashes with script/ subpackage */
-/* TODO: script entity is not implemented */
+struct Script
+{
+    Lt *lt;
+    Gc *gc;
+    struct Scope scope;
+};
 
-Script *create_script_from_line_stream(LineStream *line_stream)
+Script *create_script_from_line_stream(LineStream *line_stream, Level *level)
 {
     assert(line_stream);
-    return NULL;
+
+    Lt *lt = create_lt();
+    if (lt == NULL) {
+        return NULL;
+    }
+
+    Script *script = PUSH_LT(lt, nth_alloc(sizeof(Script)), free);
+    if (script == NULL) {
+        throw_error(ERROR_TYPE_LIBC);
+        RETURN_LT(lt, NULL);
+    }
+    script->lt = lt;
+
+    script->gc = PUSH_LT(lt, create_gc(), destroy_gc);
+    if (script->gc == NULL) {
+        RETURN_LT(lt, NULL);
+    }
+
+    script->scope = create_scope(script->gc);
+
+    size_t n = 0;
+    sscanf(line_stream_next(line_stream), "%lu", &n);
+
+    char *source_code = NULL;
+    for (size_t i = 0; i < n; ++i) {
+        /* TODO(#466): maybe source_code should be constantly replaced in the Lt */
+        source_code = string_append(
+            source_code,
+            line_stream_next(line_stream));
+    }
+    PUSH_LT(lt, source_code, free);
+
+    set_scope_value(
+        script->gc,
+        &script->scope,
+        SYMBOL(script->gc, "rect-apply-force"),
+        NATIVE(script->gc, rect_apply_force, level));
+
+    struct ParseResult parse_result =
+        read_all_exprs_from_string(
+            script->gc,
+            source_code);
+    if (parse_result.is_error) {
+        fprintf(stderr, "Parsing error: %s\n", parse_result.error_message);
+        RETURN_LT(lt, NULL);
+    }
+
+    struct EvalResult eval_result = eval(
+        script->gc,
+        &script->scope,
+        CONS(script->gc,
+             SYMBOL(script->gc, "begin"),
+             parse_result.expr));
+    if (eval_result.is_error) {
+        print_expr_as_sexpr(stderr, eval_result.expr);
+        fprintf(stderr, "\n");
+        RETURN_LT(lt, NULL);
+    }
+
+    gc_collect(script->gc, script->scope.expr);
+
+    free(RELEASE_LT(lt, source_code));
+
+    return script;
 }
 
 void destroy_script(Script *script)
 {
     assert(script);
+    RETURN_LT0(script->lt);
+}
+
+int script_eval(Script *script, const char *source_code)
+{
+    assert(script);
+    assert(source_code);
+
+    struct ParseResult parse_result = read_expr_from_string(
+        script->gc,
+        source_code);
+    if (parse_result.is_error) {
+        fprintf(stderr, "Parsing error: %s\n", parse_result.error_message);
+        return -1;
+    }
+
+    struct EvalResult eval_result = eval(
+        script->gc,
+        &script->scope,
+        parse_result.expr);
+    if (eval_result.is_error) {
+        fprintf(stderr, "Evaluation error: ");
+        print_expr_as_sexpr(stderr, eval_result.expr);
+        fprintf(stderr, "\n");
+        return -1;
+    }
+
+    gc_collect(script->gc, script->scope.expr);
+
+    return 0;
+}
+
+bool script_has_scope_value(const Script *script, const char *name)
+{
+    return !nil_p(
+        get_scope_value(
+            &script->scope,
+            SYMBOL(script->gc, name)));
 }