]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/level/script.c
(#819) Integrate LevelEditor Regions with Level
[nothing.git] / src / game / level / script.c
index c2b07cd52ce3e2bac82b7305ac56027429021671..4afe4ae6311e0b203e480b8406cbd64100e12b48 100644 (file)
@@ -1,35 +1,36 @@
-#include <assert.h>
-
+#include "system/stacktrace.h"
 #include "ebisp/gc.h"
 #include "ebisp/interpreter.h"
 #include "ebisp/parser.h"
 #include "ebisp/scope.h"
+#include "ebisp/std.h"
+#include "game/level.h"
 #include "script.h"
-#include "str.h"
-#include "system/error.h"
+#include "system/str.h"
 #include "system/line_stream.h"
+#include "system/log.h"
+#include "system/log_script.h"
 #include "system/lt.h"
+#include "system/nth_alloc.h"
 #include "ui/console.h"
+#include "broadcast.h"
 
 struct Script
 {
     Lt *lt;
     Gc *gc;
     struct Scope scope;
+    const char *source_code;
 };
 
-Script *create_script_from_line_stream(LineStream *line_stream, Level *level)
+static Script *create_script(Broadcast *broadcast, const char *source_code)
 {
-    assert(line_stream);
+    trace_assert(source_code);
 
     Lt *lt = create_lt();
-    if (lt == NULL) {
-        return NULL;
-    }
 
-    Script *script = PUSH_LT(lt, malloc(sizeof(Script)), free);
+    Script *script = PUSH_LT(lt, nth_calloc(1, sizeof(Script)), free);
     if (script == NULL) {
-        throw_error(ERROR_TYPE_LIBC);
         RETURN_LT(lt, NULL);
     }
     script->lt = lt;
@@ -40,31 +41,24 @@ Script *create_script_from_line_stream(LineStream *line_stream, Level *level)
     }
 
     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));
+    load_std_library(script->gc, &script->scope);
+    load_log_library(script->gc, &script->scope);
+    broadcast_load_library(broadcast, script->gc, &script->scope);
+
+    script->source_code = PUSH_LT(
+        lt,
+        string_duplicate(source_code, NULL),
+        free);
+    if (script->source_code == NULL) {
+        RETURN_LT(lt, NULL);
     }
-    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);
+        log_fail("Parsing error: %s\n", parse_result.error_message);
         RETURN_LT(lt, NULL);
     }
 
@@ -76,44 +70,67 @@ Script *create_script_from_line_stream(LineStream *line_stream, Level *level)
              parse_result.expr));
     if (eval_result.is_error) {
         print_expr_as_sexpr(stderr, eval_result.expr);
-        fprintf(stderr, "\n");
+        log_fail("\n");
         RETURN_LT(lt, NULL);
     }
 
     gc_collect(script->gc, script->scope.expr);
 
-    free(RELEASE_LT(lt, source_code));
-
     return script;
 }
 
+Script *create_script_from_string(Broadcast *broadcast, const char *source_code)
+{
+    return create_script(broadcast, string_duplicate(source_code, NULL));
+}
+
+Script *create_script_from_line_stream(LineStream *line_stream, Broadcast *broadcast)
+{
+    trace_assert(line_stream);
+
+    const char *line = line_stream_next(line_stream);
+    if (line == NULL) {
+        return NULL;
+    }
+
+    size_t n = 0;
+    if (sscanf(line, "%lu", &n) == EOF) {
+        return NULL;
+    }
+
+    const char *source_code = line_stream_collect_n_lines(line_stream, n);
+    if (source_code == NULL) {
+        return NULL;
+    }
+
+    return create_script(broadcast, source_code);
+}
+
 void destroy_script(Script *script)
 {
-    assert(script);
+    trace_assert(script);
     RETURN_LT0(script->lt);
 }
 
-int script_eval(Script *script, const char *source_code)
+const char *script_source_code(const Script *script)
 {
-    assert(script);
-    assert(source_code);
+    return script->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;
-    }
+int script_eval(Script *script, struct Expr expr)
+{
+    trace_assert(script);
 
     struct EvalResult eval_result = eval(
         script->gc,
         &script->scope,
-        parse_result.expr);
+        expr);
     if (eval_result.is_error) {
-        fprintf(stderr, "Evaluation error: ");
+        log_fail("Evaluation error: ");
+        /* TODO(#521): Evalation error is prepended with `[FAIL]` at the end of the message */
+        /* TODO(#486): print_expr_as_sexpr could not be easily integrated with log_fail */
         print_expr_as_sexpr(stderr, eval_result.expr);
-        fprintf(stderr, "\n");
+        log_fail("\n");
         return -1;
     }
 
@@ -129,3 +146,8 @@ bool script_has_scope_value(const Script *script, const char *name)
             &script->scope,
             SYMBOL(script->gc, name)));
 }
+
+Gc *script_gc(const Script *script)
+{
+    return script->gc;
+}