commit - 871eec082d922a94977ef7f38b63e6678ffc92c5
commit + f9cd3e06af84c7a1ce4408cda517310d99e5a23e
blob - c05a341d1b5e223431a9baa834770897fcb445cb
blob + d3adcb028212b28d8438a72bb0af388cec6883bd
--- script.c
+++ script.c
static struct value vstack[STACK_HEIGHT];
static int stackh;
+static struct envs envs = TAILQ_HEAD_INITIALIZER(envs);
+
static struct value v_false = {.type = V_NUM, .v = {.num = 0}};
static struct value v_true = {.type = V_NUM, .v = {.num = 1}};
+static inline void
+popv(struct value *v)
+{
+ if (stackh == 0)
+ errx(1, "can't pop the stack: underflow");
+ memcpy(v, &vstack[--stackh], sizeof(*v));
+
+#if DEBUG
+ printf("popping "); pp_val(v); printf("\n");
+#endif
+}
+
+static inline void
+pushv(struct value *v)
+{
+ if (stackh == STACK_HEIGHT)
+ errx(1, "can't push the stack: overflow");
+
+#if DEBUG
+ printf("pushing "); pp_val(v); printf("\n");
+#endif
+
+ memcpy(&vstack[stackh++], v, sizeof(*v));
+}
+
+static inline void
+pushbool(int n)
+{
+ pushv(n ? &v_true : &v_false);
+}
+
static inline struct opstack *
pushstack(struct opstacks *stack)
{
ops->counter++;
}
-void
+static inline void
+pushenv(void)
+{
+ struct env *e;
+
+ e = xcalloc(1, sizeof(*e));
+ TAILQ_INSERT_HEAD(&envs, e, entry);
+}
+
+static inline struct env *
+currentenv(void)
+{
+ assert(!TAILQ_EMPTY(&envs));
+ return TAILQ_FIRST(&envs);
+}
+
+static void
+popenv(void)
+{
+ struct env *e;
+ struct binding *b, *tb;
+
+ e = currentenv();
+ TAILQ_REMOVE(&envs, e, entry);
+
+ TAILQ_FOREACH_SAFE(b, &e->bindings, entry, tb) {
+ free(b->name);
+ switch (b->val.type) {
+ case V_SYM:
+ case V_STR:
+ free(b->val.v.str);
+ break;
+ }
+ free(b);
+ }
+
+ free(e);
+}
+
+static inline int
+setvar(char *sym, struct op *op)
+{
+ struct binding *b;
+ struct env *e;
+ int ret;
+
+ if ((ret = eval(op)) != EVAL_OK)
+ return ret;
+
+ b = xcalloc(1, sizeof(*b));
+ b->name = sym;
+ popv(&b->val);
+
+ e = TAILQ_FIRST(&envs);
+ TAILQ_INSERT_HEAD(&e->bindings, b, entry);
+
+ return EVAL_OK;
+}
+
+static inline int
+getvar(const char *sym, struct value *v)
+{
+ struct env *e;
+ struct binding *b;
+
+ TAILQ_FOREACH(e, &envs, entry) {
+ TAILQ_FOREACH(b, &e->bindings, entry) {
+ if (!strcmp(sym, b->name)) {
+ memcpy(v, &b->val, sizeof(*v));
+ return EVAL_OK;
+ }
+ }
+ }
+
+ fprintf(stderr, "unbound variable %s\n", sym);
+ return EVAL_ERR;
+}
+
+int
global_set(char *sym, struct op *op)
{
- assert(op->type == OP_LITERAL);
+ struct binding *b;
+ struct env *e;
+
+ /* TODO: check for duplicates */
+
+ if (op->type != OP_LITERAL)
+ return 0;
+
+ b = xcalloc(1, sizeof(*b));
+ b->name = sym;
+ memcpy(&b->val, &op->v.literal, sizeof(b->val));
+
+ e = TAILQ_LAST(&envs, envs);
+ TAILQ_INSERT_HEAD(&e->bindings, b, entry);
+
+ return 1;
}
struct op *
op = op->next;
}
}
-
-static inline void
-popv(struct value *v)
-{
- if (stackh == 0)
- errx(1, "can't pop the stack: underflow");
- memcpy(v, &vstack[--stackh], sizeof(*v));
-#if DEBUG
- printf("popping "); pp_val(v); printf("\n");
-#endif
-}
-
-static inline void
-pushv(struct value *v)
-{
- if (stackh == STACK_HEIGHT)
- errx(1, "can't push the stack: overflow");
-
-#if DEBUG
- printf("pushing "); pp_val(v); printf("\n");
-#endif
-
- memcpy(&vstack[stackh++], v, sizeof(*v));
-}
-
-static inline void
-pushbool(int n)
-{
- pushv(n ? &v_true : &v_false);
-}
-
int
eval(struct op *op)
{
switch (op->type) {
case OP_ASSIGN:
- printf("TODO: assignment\n");
+ ret = setvar(op->v.assign.name, op->v.assign.expr);
+ if (ret != EVAL_OK)
+ return ret;
break;
case OP_ASSERT:
break;
case OP_FUNCALL:
- /* TODO: arity check! */
+ /* assume airity matches */
+ pushenv();
+
+ proc = op->v.funcall.proc;
for (i = 0; i < op->v.funcall.argc; ++i) {
t = &op->v.funcall.argv[i];
- if ((ret = eval(t)) != EVAL_OK)
+ if ((ret = setvar(proc->args[i], t)) != EVAL_OK)
return ret;
}
- proc = op->v.funcall.proc;
if (proc->nativefn != NULL)
proc->nativefn(i);
else if ((ret = eval(proc->body)) != EVAL_OK)
return ret;
+
+ popenv();
break;
case OP_LITERAL:
break;
case OP_VAR:
- printf("TODO: load variable\n");
+ if ((ret = getvar(op->v.var, &a)) != EVAL_OK)
+ return ret;
+ pushv(&a);
break;
case OP_CAST:
int
main(int argc, char **argv)
{
+ struct env *e;
struct test *t;
int i, passed = 0, failed = 0, skipped = 0;
log_init(1, LOG_DAEMON);
log_setverbose(1);
+ /* prepare the global env */
+ pushenv();
+
add_builtin_proc("dummy", builtin_dummy);
for (i = 1; i < argc; ++i)
printf("failed %d\n", failed);
printf("skipped %d\n", skipped);
+ popenv();
+
return failed != 0;
}
blob - 7ffb5c8f3b19f814fd697398a1862a7feaff2bfc
blob + 3c3af1629dee81f6acfee368cc87bb847f40a8c1
--- script.h
+++ script.h
} v;
};
+TAILQ_HEAD(bindings, binding);
+struct binding {
+ char *name;
+ struct value val;
+ TAILQ_ENTRY(binding) entry;
+};
+
+TAILQ_HEAD(envs, env);
+struct env {
+ TAILQ_ENTRY(env) entry;
+ struct bindings bindings;
+};
+
TAILQ_HEAD(opstacks, opstack);
struct opstack {
TAILQ_ENTRY(opstack) entry;
EVAL_SKIP,
};
-void global_set(char *, struct op *);
+int global_set(char *, struct op *);
struct op *newop(int);
void free_op(struct op *);