commit 95ed9bfdc82db27442570086da1a85b4a4e656b9
parent 5a62b83bf91cab34389b7ab0e981c1804bc2ff54
Author: Juan F. Meleiro <juan@juanmeleiro.mat.br>
Date: Thu, 9 May 2024 12:57:30 +0200
Add a partial implementation of a language for commanding gardeners
Diffstat:
9 files changed, 311 insertions(+), 3 deletions(-)
diff --git a/coding/gardener.c b/coding/gardener.c
@@ -48,6 +48,12 @@ get_cur_tree(gardener *g)
return g->result;
}
+symbol
+get_cur_constructor(gardener *g)
+{
+ return get_head(get_cur_tree(g));
+}
+
schema*
get_cur_schema(gardener *g)
{
@@ -149,6 +155,7 @@ start(gardener* g, symbol c)
{
ensure(g, is_empty(g->stack), START_ON_NONEMPTY_STACK);
ensure(g, (g->result == NULL), OP_AFTER_RESULT);
+ ensure(g, is_constructor(g->top, c), START_WITH_INVALID_CONSTRUCTOR);
frame *f = new_frame();
f->tree = new_node(c);
@@ -175,7 +182,10 @@ show(FILE *f, gardener *g)
{
schema *s = get_cur_schema(g);
tree *cur = get_cur_tree(g);
- if (cur == NULL) return;
+ if (cur == NULL) {
+ fprintf(f, "schema %s\n", get_name(get_top(g)));
+ return;
+ }
symbol head = get_head(cur);
fprintf(f, "schema %s\n", repr(get_name(s)));
diff --git a/coding/gardener.h b/coding/gardener.h
@@ -4,6 +4,7 @@
typedef enum {
OK,
+ START_WITH_INVALID_CONSTRUCTOR,
SUB_INVALID_KEY,
START_ON_NONEMPTY_STACK,
SUB_WITH_INVALID_CONSTRUCTOR,
@@ -14,6 +15,9 @@ typedef enum {
typedef struct gardener gardener;
+schema *get_cur_schema(gardener*);
+symbol get_cur_constructor(gardener*);
+
gardener* new_gardener(schema*);
gardener_status get_error(gardener*);
tree* result(gardener*);
diff --git a/coding/interpreter.c b/coding/interpreter.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+
+#include "model.h"
+#include "zen.h"
+#include "tokenizer.h"
+
+int
+main(size_t argc, char **argv)
+{
+ garden *g = new_garden(schema(context));
+ FILE *src;
+
+ if (argc > 1) {
+ src = fopen(argv[1], "r");
+ if (!src) {
+ fprintf(stderr, "No such file: %s\n", argv[1]);
+ return 1;
+ }
+ } else {
+ src = stdin;
+ }
+
+ tokenizer *t = new_tokenizer(src);
+
+ while (!eos(t))
+ instruct(g, next_token(t));
+ display_garden(stdout, g);
+
+ return 0;
+}
diff --git a/coding/interpreter.do b/coding/interpreter.do
@@ -0,0 +1,5 @@
+deps=$(grep '^#include ".*\.h"' interpreter.c | sed 's/#include "\(.*\).h"/\1.o/')
+redo-ifchange $deps
+src=$(ag -L '^main\(' | grep '\.c$' | sed 's/\.c/.o/')
+echo cc $src interpreter.c -o $1 >&2
+cc $src interpreter.c -o $3
diff --git a/coding/model.c b/coding/model.c
@@ -23,11 +23,16 @@ start_schema(context)
mark_as_leaf (it, I("attitude"), I("name") );
assign_subschema (it, I("attitude"), I("vars"), schema(vars) );
assign_subschema (it, I("attitude"), I("pressupositions"), schema(term_list) );
+ assign_subschema (it, I("attitude"), I("precontext"), schema(context) );
add_constructor (it, I("assumption") );
mark_as_leaf (it, I("assumption"), I("name") );
assign_subschema (it, I("assumption"), I("judgment"), schema(term) );
assign_subschema (it, I("assumption"), I("proof"), schema(proof) );
+ assign_subschema (it, I("assumption"), I("precontext"), schema(context) );
+ assign_subschema (it, I("assumption"), I("subcontext"), schema(context) );
+
+ add_constructor (it, I("being") );
end_schema(context);
start_schema(term)
diff --git a/coding/model.test.c b/coding/model.test.c
@@ -125,8 +125,8 @@ test_use(void)
done (g ); assert(get_error(g) == OK);
done (g ); assert(get_error(g) == OK);
- show(stdout, g);
- display_tree(stdout, result(g));
+ // show(stdout, g);
+ // display_tree(stdout, result(g));
}
int
diff --git a/coding/zen.c b/coding/zen.c
@@ -0,0 +1,161 @@
+#include "zen.h"
+#include "schema.h"
+#include "gardener.h"
+
+typedef enum {
+ OP_START,
+ OP_FILL,
+ OP_NOOP
+} op_type;
+
+struct garden {
+ gardener *gardener;
+ garden_status status;
+ op_type next;
+ symbol a;
+ symbol b;
+};
+
+char*
+next_symbol_meaning(garden_status s, op_type next)
+{
+ if (s == ERROR) return "enlightenment";
+ if (s == WAITING_FOR_OP) return "operation";
+
+ switch (next) {
+ case OP_NOOP:
+ return "nothing";
+ case OP_FILL:
+ if (s == WAITING_FOR_B)
+ return "key";
+ else
+ return "value";
+ case OP_START:
+ return "constructor";
+ }
+}
+
+void
+display_garden(FILE *f, garden *g)
+{
+ show(f, g->gardener);
+ fprintf(f, "\nWaiting for %s.\n",
+ next_symbol_meaning(g->status, g->next));
+}
+
+garden*
+new_garden(schema* s)
+{
+ garden *g = malloc(sizeof(garden));
+ g->gardener = new_gardener(s);
+ g->status = WAITING_FOR_OP;
+ return g;
+}
+
+garden_status
+get_status(garden *g)
+{
+ return g->status;
+}
+
+op_type
+symbol_to_op(symbol s)
+{
+ if (s == intern("start"))
+ return OP_START;
+ else if (s == intern("fill"))
+ return OP_FILL;
+ else
+ return OP_NOOP;
+}
+
+garden_status
+next_status_for_op(op_type op)
+{
+ switch (op) {
+ case OP_NOOP:
+ return ERROR;
+ case OP_START:
+ return WAITING_FOR_A;
+ case OP_FILL:
+ return WAITING_FOR_B;
+ }
+}
+
+void
+end_op(garden *g)
+{
+ if (get_error(g->gardener) != OK)
+ g->status = ERROR;
+ else
+ g->status = WAITING_FOR_OP;
+}
+
+void
+exec_op(garden *g)
+{
+ switch (g->next) {
+
+ case OP_START:
+ start(g->gardener, g->a);
+ end_op(g);
+ break;
+
+ case OP_FILL:
+ fill(g->gardener, g->b, g->a);
+ end_op(g);
+ break;
+
+ case OP_NOOP:
+ g->status = ERROR;
+ break;
+ }
+}
+
+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)) {
+ g->status = WAITING_FOR_A;
+ } else {
+ g->status = ERROR;
+ }
+ }
+}
+
+void
+instruct(garden *g, symbol s)
+{
+ (void)s;
+ switch (g->status) {
+
+ case WAITING_FOR_OP:
+ g->next = symbol_to_op(s);
+ g->status = next_status_for_op(g->next);
+ break;
+
+ case WAITING_FOR_A:
+ g->a = s;
+ exec_op(g);
+ break;
+
+ case WAITING_FOR_B:
+ g->b = s;
+ check_b(g);
+ break;
+
+ case ERROR:
+ break;
+
+ }
+}
diff --git a/coding/zen.h b/coding/zen.h
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include "schema.h"
+
+typedef enum {
+ WAITING_FOR_OP,
+ WAITING_FOR_A,
+ WAITING_FOR_B,
+ ERROR
+} garden_status;
+
+typedef struct garden garden;
+
+garden *new_garden(schema*);
+void instruct(garden*, symbol);
+garden_status get_status(garden*);
+void display_garden(FILE*, garden*);
diff --git a/coding/zen.test.c b/coding/zen.test.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <assert.h>
+
+#include "zen.h"
+#include "symbol.h"
+#include "schema.h"
+
+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);
+}
+
+void
+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);
+}
+
+void
+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);
+}
+
+void
+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);
+}
+
+/* PICK-UP: tests to implement all gardener ops through instruct */
+
+int
+main()
+{
+ test_start();
+ test_invalid_constructor_start_fail();
+ test_invalid_key_fail();
+ test_valid_key_success();
+ return 0;
+}