changeset 98:8498c1faba07

built-ins: Improve let built-in and implement ybuiltin_translate()
author Lewin Bormann <lbo@spheniscida.de>
date Mon, 26 Aug 2019 17:01:40 +0200
parents 3b468dad363f
children 7b041326c9f7
files src/built-ins.c src/built-ins.h src/built-ins_test.c
diffstat 3 files changed, 45 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/built-ins.c	Mon Aug 26 17:01:14 2019 +0200
+++ b/src/built-ins.c	Mon Aug 26 17:01:40 2019 +0200
@@ -63,6 +63,16 @@
     return YBUILTIN_UNDEF;
 }
 
+bool ybuiltin_translate(yexpr_t* expr) {
+    if (expr->typ != YEXPR_REF) return false;
+    if (yref_type(&expr->value.ref) != YREF_SYM) return false;
+    YBUILTIN_TYPE bi = ybuiltin_id(&expr->value.ref.ref.sym);
+    if (bi == YBUILTIN_UNDEF) return false;
+    yexpr_destroy(expr);
+    yexpr_set_builtin(expr, bi);
+    return true;
+}
+
 static void nothing(void){};
 
 /// Expects a list expression starting with built-in "let" on the stack. It is not modified.
@@ -70,7 +80,7 @@
 /// Returns an UNDEF expression by default, or an EXCEPTION if something went
 /// wrong.
 yexpr_t ybuiltin_fn_let(yeval_state_t* state) {
-    yexpr_t let, *ref, *val;
+    yexpr_t let, *ref;
     size_t counter = 0;
     yvec_t* letlist = &let.value.list;
 
@@ -83,13 +93,11 @@
         goto badexprfail;
 
     ref = YVEC_AT(letlist, counter++, yexpr_t);
-    // TODO evaluate all expressions and assign last
-    val = YVEC_AT(letlist, counter++, yexpr_t);
-    if (ref->typ != YEXPR_REF || val->typ == YEXPR_UNDEF) goto typefail;
+    if (ref->typ != YEXPR_REF) goto typefail;
 
     yvalue_t newvalue = {
         .typ = YVALUE_EXPR,
-        .value.expr = yeval(state, val, /* in_place= */ false)};
+        .value.expr = yeval_list_return_last(state, letlist, 2)};
     yvalue_set(ref->value.ref, &newvalue);
     return yexpr_new();
 
@@ -105,15 +113,11 @@
 
 typefail:
     nothing();
-    yexpr_t args = yexpr_new();
-    yexpr_init_or_extend(&args, *ref);
-    yexpr_init_or_extend(&args, *val);
     yexpr_t exc = ybuiltin_type_error(
         YBUILTIN_LET,
         ystr_new(
-            "type mismatch: want (reference, value), received something else"),
-        &args);
-    yexpr_destroy(&args);
+            "type mismatch: want (let reference [exprs...] expr), received something else"),
+        &let);
     return exc;
 }
 
--- a/src/built-ins.h	Mon Aug 26 17:01:14 2019 +0200
+++ b/src/built-ins.h	Mon Aug 26 17:01:40 2019 +0200
@@ -19,6 +19,11 @@
 const char* ybuiltin_name(YBUILTIN_TYPE t);
 
 /**
+ * @brief If possible, make an ID (in a parse tree) into a built-in reference.
+ */
+bool ybuiltin_translate(yexpr_t* expr);
+
+/**
  * @brief Run a built-in function. The caller assumes ownership of the returned value.
  */
 yexpr_t ybuiltin_run(YBUILTIN_TYPE t, yeval_state_t* state);
--- a/src/built-ins_test.c	Mon Aug 26 17:01:14 2019 +0200
+++ b/src/built-ins_test.c	Mon Aug 26 17:01:40 2019 +0200
@@ -4,6 +4,28 @@
 #include <src/parse.h>
 #include <src/value.h>
 
+void test_builtin_translate(void) {
+    yexpr_t expr = yexpr_new();
+
+    yexpr_set_atom(&expr, yatom_get_or_add("atom"));
+    assert(!ybuiltin_translate(&expr));
+    assert(YEXPR_ATOM == expr.typ);
+
+    yexpr_set_ref(&expr, yref_new());
+    assert(!ybuiltin_translate(&expr));
+    assert(YEXPR_REF == expr.typ);
+
+    yexpr_set_ref(&expr, yref_new_c("my-ref"));
+    assert(!ybuiltin_translate(&expr));
+    assert(YEXPR_REF == expr.typ);
+    yexpr_destroy(&expr);
+
+    yexpr_set_ref(&expr, yref_new_c("let"));
+    assert(ybuiltin_translate(&expr));
+    assert(YEXPR_BUILTIN == expr.typ);
+    assert(YBUILTIN_LET == expr.value.builtin);
+}
+
 void test_builtin_let(void) {
     yexpr_t ref_expr = yexpr_new();
     yexpr_t let_expr = yexpr_new();
@@ -71,7 +93,7 @@
 
 void test_builtin_let_parsed(void) {
     ystr_t input = ystr_new("(let my-var (1 2 3))"), error = ystr_new(NULL);
-    yexpr_t program, *let_expr;
+    yexpr_t program = yexpr_new(), *let_expr;
     assert(yparse_str(&input, &program, &error));
     let_expr = YVEC_AT(&program.value.list, 0, yexpr_t);
 
@@ -94,6 +116,7 @@
     assert(YVEC_AT(&stored->value.expr.value.list, 1, yexpr_t)->value.n == 2);
 
     yexpr_destroy(&result);
+    yexpr_destroy(&program);
     yref_destroy(&my_var_ref);
     yvec_destroy(&state.call_stack);
     ystr_destroy(&input);
@@ -101,6 +124,7 @@
 }
 
 int main(void) {
+    test_builtin_translate();
     test_builtin_let();
     test_builtin_let_parsed();
     return 0;