commit 7d12dd1a564c85f780c8aed3b463b7e3bf46ab25
parent 95ed9bfdc82db27442570086da1a85b4a4e656b9
Author: Juan F. Meleiro <juan@juanmeleiro.mat.br>
Date: Thu, 9 May 2024 15:18:07 +0200
Finish implementing zen commands
Diffstat:
6 files changed, 181 insertions(+), 36 deletions(-)
diff --git a/coding/default.o.do b/coding/default.o.do
@@ -1,4 +1,4 @@
src=$(basename "$1" .o).c
redo-ifchange $src
echo cc -g -c $src -o "$1" >&2
-cc -g -c $src -o "$3"
-\ No newline at end of file
+cc -g -Wall -Wextra -fmax-errors=1 -g -c $src -o "$3"
+\ No newline at end of file
diff --git a/coding/default.test.do b/coding/default.test.do
@@ -1,6 +1,6 @@
deps=$(grep '^#include ".*"$' $1.c | sed 's/#include "\(.*\)\.h"/\1.o/')
redo-ifchange "$1.o"
redo-ifchange $deps
-src=$(ls *.o | grep -v .test.o)
+src=$(ls *.h | sed 's/\.h$/\.o/')
echo cc -o "$1" $src "$1.o" >&2
-cc -o "$3" $src "$1.o"
+cc -o "$3" -g -Wall -Wextra -fmax-errors=1 $src "$1.o"
diff --git a/coding/gardener.c b/coding/gardener.c
@@ -183,7 +183,7 @@ show(FILE *f, gardener *g)
schema *s = get_cur_schema(g);
tree *cur = get_cur_tree(g);
if (cur == NULL) {
- fprintf(f, "schema %s\n", get_name(get_top(g)));
+ fprintf(f, "schema %s\n", repr(get_name(get_top(g))));
return;
}
symbol head = get_head(cur);
diff --git a/coding/model.test.c b/coding/model.test.c
@@ -123,9 +123,7 @@ test_use(void)
sub (g, I("cdr"), I("nil") ); assert(get_error(g) == OK);
done (g ); assert(get_error(g) == OK);
done (g ); assert(get_error(g) == OK);
- done (g ); assert(get_error(g) == OK);
- // show(stdout, g);
// display_tree(stdout, result(g));
}
diff --git a/coding/zen.c b/coding/zen.c
@@ -5,6 +5,9 @@
typedef enum {
OP_START,
OP_FILL,
+ OP_DONE,
+ OP_SUB,
+ OP_SUP,
OP_NOOP
} op_type;
@@ -32,7 +35,20 @@ next_symbol_meaning(garden_status s, op_type next)
return "value";
case OP_START:
return "constructor";
+ case OP_DONE:
+ return "enlightenment";
+ case OP_SUB:
+ if (s == WAITING_FOR_B)
+ return "key";
+ else
+ return "constructor";
+ case OP_SUP:
+ if (s == WAITING_FOR_B)
+ return "constructor";
+ else
+ return "key";
}
+ return "enlightenment";
}
void
@@ -65,6 +81,12 @@ symbol_to_op(symbol s)
return OP_START;
else if (s == intern("fill"))
return OP_FILL;
+ else if (s == intern("done"))
+ return OP_DONE;
+ else if (s == intern("sub"))
+ return OP_SUB;
+ else if (s == intern("sup"))
+ return OP_SUP;
else
return OP_NOOP;
}
@@ -79,7 +101,14 @@ next_status_for_op(op_type op)
return WAITING_FOR_A;
case OP_FILL:
return WAITING_FOR_B;
+ case OP_DONE:
+ return WAITING_FOR_OP;
+ case OP_SUB:
+ return WAITING_FOR_B;
+ case OP_SUP:
+ return WAITING_FOR_B;
}
+ return ERROR;
}
void
@@ -109,6 +138,21 @@ exec_op(garden *g)
case OP_NOOP:
g->status = ERROR;
break;
+
+ case OP_DONE:
+ done(g->gardener);
+ end_op(g);
+ break;
+
+ case OP_SUB:
+ sub(g->gardener, g->b, g->a);
+ end_op(g);
+ break;
+
+ case OP_SUP:
+ sup(g->gardener, g->b, g->a);
+ end_op(g);
+ break;
}
}
@@ -116,23 +160,68 @@ void
check_b(garden *g)
{
switch (g->next) {
+
case OP_START:
g->status = ERROR;
break;
+
case OP_NOOP:
g->status = ERROR;
break;
+
case OP_FILL:
if (has_key(get_cur_schema(g->gardener),
get_cur_constructor(g->gardener),
+ g->b) &&
+ takes_leaf(get_cur_schema(g->gardener),
+ get_cur_constructor(g->gardener),
+ g->b)) {
+ g->status = WAITING_FOR_A;
+ } else {
+ g->status = ERROR;
+ }
+ break;
+
+ case OP_DONE:
+ g->status = ERROR;
+ break;
+
+ case OP_SUB:
+ if (has_key(get_cur_schema(g->gardener),
+ get_cur_constructor(g->gardener),
g->b)) {
g->status = WAITING_FOR_A;
} else {
g->status = ERROR;
}
+ break;
+
+ case OP_SUP:
+ if (is_constructor(get_cur_schema(g->gardener),
+ g->b)) {
+ g->status = WAITING_FOR_A;
+ } else {
+ g->status = ERROR;
+ }
}
}
+bool
+takes_args(op_type op)
+{
+ switch (op) {
+ case OP_FILL:
+ case OP_SUB:
+ case OP_SUP:
+ case OP_START:
+ return true;
+ case OP_NOOP:
+ case OP_DONE:
+ /* FALLTHROUGH */
+ }
+ return false;
+}
+
void
instruct(garden *g, symbol s)
{
@@ -141,7 +230,11 @@ instruct(garden *g, symbol s)
case WAITING_FOR_OP:
g->next = symbol_to_op(s);
- g->status = next_status_for_op(g->next);
+ if (takes_args(g->next)) {
+ g->status = next_status_for_op(g->next);
+ } else {
+ exec_op(g);
+ }
break;
case WAITING_FOR_A:
diff --git a/coding/zen.test.c b/coding/zen.test.c
@@ -5,14 +5,15 @@
#include "symbol.h"
#include "schema.h"
+#define ts(g,c,e) do {instruct(g, intern(c)); assert(get_status(g) == e);} while(0);
+
void
test_start()
{
schema *s = new_schema(intern("a"));
garden *g = new_garden(s);
assert(get_status(g) == WAITING_FOR_OP);
- instruct(g, intern("start"));
- assert(get_status(g) == WAITING_FOR_A);
+ ts(g, "start", WAITING_FOR_A);
}
void
@@ -20,11 +21,8 @@ test_invalid_constructor_start_fail()
{
schema *s = new_schema(intern("a"));
garden *g = new_garden(s);
- assert(get_status(g) == WAITING_FOR_OP);
- instruct(g, intern("start"));
- assert(get_status(g) == WAITING_FOR_A);
- instruct(g, intern("anything"));
- assert(get_status(g) == ERROR);
+ ts(g, "start", WAITING_FOR_A );
+ ts(g, "anything", ERROR );
}
void
@@ -33,15 +31,11 @@ test_invalid_key_fail()
schema *s = new_schema(intern("a"));
add_constructor(s, intern("c"));
garden *g = new_garden(s);
- assert(get_status(g) == WAITING_FOR_OP);
- instruct(g, intern("start"));
- assert(get_status(g) == WAITING_FOR_A);
- instruct(g, intern("c"));
- assert(get_status(g) == WAITING_FOR_OP);
- instruct(g, intern("fill"));
- assert(get_status(g) == WAITING_FOR_B);
- instruct(g, intern("anything"));
- assert(get_status(g) == ERROR);
+
+ ts(g, "start", WAITING_FOR_A);
+ ts(g, "c", WAITING_FOR_OP);
+ ts(g, "fill", WAITING_FOR_B);
+ ts(g, "anything", ERROR);
}
void
@@ -50,21 +44,77 @@ test_valid_key_success()
schema *s = new_schema(intern("a"));
add_constructor(s, intern("c"));
mark_as_leaf(s, intern("c"), intern("k"));
+
garden *g = new_garden(s);
- assert(get_status(g) == WAITING_FOR_OP);
- instruct(g, intern("start"));
- assert(get_status(g) == WAITING_FOR_A);
- instruct(g, intern("c"));
- assert(get_status(g) == WAITING_FOR_OP);
- instruct(g, intern("fill"));
- assert(get_status(g) == WAITING_FOR_B);
- instruct(g, intern("k"));
- assert(get_status(g) == WAITING_FOR_A);
- instruct(g, intern("anything"));
- assert(get_status(g) == WAITING_FOR_OP);
+ ts(g, "start", WAITING_FOR_A);
+ ts(g, "c", WAITING_FOR_OP);
+ ts(g, "fill", WAITING_FOR_B);
+ ts(g, "k", WAITING_FOR_A);
+ ts(g, "anything", WAITING_FOR_OP);
+ ts(g, "done", WAITING_FOR_OP);
}
-/* PICK-UP: tests to implement all gardener ops through instruct */
+void
+test_sub_success()
+{
+ schema *s = new_schema(intern("a"));
+ add_constructor(s, intern("c"));
+ schema *t = new_schema(intern("b"));
+ add_constructor(t, intern("d"));
+ assign_subschema(s, intern("c"), intern("k"), t);
+
+ garden *g = new_garden(s);
+
+ ts(g, "start", WAITING_FOR_A );
+ ts(g, "c", WAITING_FOR_OP );
+ ts(g, "sub", WAITING_FOR_B );
+ ts(g, "k", WAITING_FOR_A );
+ ts(g, "d", WAITING_FOR_OP );
+ ts(g, "done", WAITING_FOR_OP );
+ ts(g, "done", WAITING_FOR_OP );
+}
+
+void
+test_sub_invalid_constructor_fail()
+{
+ schema *s = new_schema(intern("a"));
+ add_constructor(s, intern("c"));
+ garden *g = new_garden(s);
+
+ ts(g, "start", WAITING_FOR_A );
+ ts(g, "c", WAITING_FOR_OP );
+ ts(g, "sub", WAITING_FOR_B );
+ ts(g, "k", ERROR );
+}
+
+void
+test_sup_invalid_constructor_fail()
+{
+ schema *s = new_schema(intern("a"));
+ add_constructor(s, intern("c"));
+ garden *g = new_garden(s);
+
+ ts(g, "start", WAITING_FOR_A);
+ ts(g, "c", WAITING_FOR_OP);
+ ts(g, "sup", WAITING_FOR_B);
+ ts(g, "d", ERROR);
+}
+
+void
+test_sup_success()
+{
+ schema *s = new_schema(intern("a"));
+ add_constructor(s, intern("c"));
+ add_constructor(s, intern("nil"));
+ assign_subschema(s, intern("c"), intern("k"), s);
+ garden *g = new_garden(s);
+
+ ts(g, "start", WAITING_FOR_A);
+ ts(g, "nil", WAITING_FOR_OP);
+ ts(g, "sup", WAITING_FOR_B);
+ ts(g, "c", WAITING_FOR_A);
+ ts(g, "k", WAITING_FOR_OP);
+}
int
main()
@@ -73,5 +123,9 @@ main()
test_invalid_constructor_start_fail();
test_invalid_key_fail();
test_valid_key_success();
+ test_sub_invalid_constructor_fail();
+ test_sub_success();
+ test_sup_invalid_constructor_fail();
+ test_sup_success();
return 0;
}