aboutsummaryrefslogtreecommitdiff
path: root/src/lyn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lyn.c')
-rw-r--r--src/lyn.c333
1 files changed, 328 insertions, 5 deletions
diff --git a/src/lyn.c b/src/lyn.c
index 2527677..2783ba6 100644
--- a/src/lyn.c
+++ b/src/lyn.c
@@ -1,4 +1,5 @@
#include <errno.h>
+#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
@@ -6,14 +7,326 @@
#include <stdlib.h>
#include <lyn/lyn.h>
+#include <lyn/ast.h>
#include <lyn/parser.h>
#include <lyn/debug.h>
+static int builtin_let(struct lyn *lyn, struct vec args)
+{
+ assert(vec_len(&args) == 3);
+
+ struct lyn_value name = lyn_at(args, 1);
+ assert(name.kind == LYN_ID);
+
+ struct lyn_value value = lyn_at(args, 2);
+ if (lyn_eval(lyn, value))
+ return -1;
+
+ value = lyn_res(lyn);
+ assert(value.kind == LYN_INT);
+
+ return lyn_create_symbol(lyn, name.s, lyn_var(value));
+}
+
+static int builtin_set(struct lyn *lyn, struct vec args)
+{
+ assert(vec_len(&args) == 3);
+
+ struct lyn_value name = lyn_at(args, 1);
+ assert(name.kind == LYN_ID);
+
+ struct lyn_value value = lyn_at(args, 2);
+ if (lyn_eval(lyn, value))
+ return -1;
+
+ value = lyn_res(lyn);
+ assert(value.kind == LYN_INT);
+
+ return lyn_replace_symbol(lyn, name.s, lyn_var(value));
+}
+
+static int builtin_for(struct lyn *lyn, struct vec args)
+{
+ assert(vec_len(&args) == 5);
+
+ struct lyn_value init = lyn_at(args, 1);
+ struct lyn_value cond = lyn_at(args, 2);
+ struct lyn_value post = lyn_at(args, 3);
+ struct lyn_value body = lyn_at(args, 4);
+
+ if (lyn_eval(lyn, init))
+ return -1;
+
+top:
+ if (lyn_eval(lyn, cond))
+ return -1;
+
+ struct lyn_value check = lyn_res(lyn);
+ assert(check.kind == LYN_INT);
+
+ if (check.i) {
+ if (lyn_eval(lyn, body))
+ return -1;
+
+ if (lyn_eval(lyn, post))
+ return -1;
+
+ goto top;
+ }
+
+ return 0;
+}
+
+static int builtin_println(struct lyn *lyn, struct vec args)
+{
+ assert(vec_len(&args) == 2);
+
+ struct lyn_value value = lyn_at(args, 1);
+ if (lyn_eval(lyn, value))
+ return -1;
+
+ value = lyn_res(lyn);
+ assert(value.kind == LYN_INT);
+
+ printf("%lld\n", value.i);
+ return 0;
+}
+
+static int builtin_lt(struct lyn *lyn, struct vec args)
+{
+ assert(vec_len(&args) == 3);
+ struct lyn_value left = lyn_at(args, 1);
+ struct lyn_value right = lyn_at(args, 2);
+
+ if (lyn_eval(lyn, left))
+ return -1;
+
+ left = lyn_res(lyn);
+ assert(left.kind == LYN_INT);
+
+ if (lyn_eval(lyn, right))
+ return -1;
+
+ right = lyn_res(lyn);
+ assert(right.kind == LYN_INT);
+
+ lyn_return(lyn, gen_int(left.i < right.i));
+ return 0;
+}
+
+static int builtin_plus(struct lyn *lyn, struct vec args)
+{
+ assert(vec_len(&args) == 3);
+ struct lyn_value left = lyn_at(args, 1);
+ struct lyn_value right = lyn_at(args, 2);
+
+ if (lyn_eval(lyn, left))
+ return -1;
+
+ left = lyn_res(lyn);
+ assert(left.kind == LYN_INT);
+
+ if (lyn_eval(lyn, right))
+ return -1;
+
+ right = lyn_res(lyn);
+ assert(right.kind == LYN_INT);
+
+ lyn_return(lyn, gen_int(left.i + right.i));
+ return 0;
+}
+
struct lyn lyn_create()
{
return (struct lyn){};
}
+struct visible {
+ const char *name;
+ struct lyn_symbol symb;
+};
+
+int lyn_create_scope(struct lyn *lyn)
+{
+ struct lyn_scope *scope = calloc(1, sizeof(struct lyn_scope));
+ if (!scope)
+ return -1;
+
+ scope->visible = vec_create(sizeof(struct visible));
+ scope->parent = lyn->cur;
+
+ if (!lyn->root)
+ lyn->root = scope;
+
+ lyn->cur = scope;
+ return 0;
+}
+
+static struct visible *scope_find(struct lyn_scope *scope, const char *name)
+{
+ foreach_vec(vi, scope->visible) {
+ struct visible *v = vec_at(&scope->visible, vi);
+ if (strcmp(v->name, name) == 0)
+ return v;
+ }
+
+ return NULL;
+}
+
+static struct visible *scopes_find(struct lyn_scope *scope, const char *name)
+{
+ while (scope) {
+ struct visible *v = scope_find(scope, name);
+ if (v)
+ return v;
+
+ scope = scope->parent;
+ }
+
+ return NULL;
+}
+
+static int scope_add(struct lyn_scope *scope, const char *name, struct lyn_symbol symb)
+{
+ if (scope_find(scope, name)) {
+ error("%s exists in scope\n", name);
+ return -1;
+ }
+
+ struct visible v = {.name = name, .symb = symb};
+ vect_append(struct visible, scope->visible, &v);
+ return 0;
+}
+
+int lyn_create_symbol(struct lyn *lyn, const char *name, struct lyn_symbol symb)
+{
+ return scope_add(lyn->cur, name, symb);
+}
+
+struct lyn_symbol *lyn_lookup_symbol(struct lyn *lyn, const char *name)
+{
+ struct visible *v = scopes_find(lyn->cur, name);
+ if (!v)
+ return NULL;
+
+ return &v->symb;
+}
+
+int lyn_replace_symbol(struct lyn *lyn, const char *name, struct lyn_symbol symb)
+{
+ struct visible *v = scopes_find(lyn->cur, name);
+ if (!v)
+ return -1;
+
+ v->symb = symb;
+ return 0;
+}
+
+int lyn_init(struct lyn *lyn)
+{
+ if (lyn_create_scope(lyn))
+ return -1;
+
+ if (lyn_create_symbol(lyn, "let", lyn_syntax(builtin_let)))
+ return -1;
+
+ if (lyn_create_symbol(lyn, "for", lyn_syntax(builtin_for)))
+ return -1;
+
+ if (lyn_create_symbol(lyn, "set", lyn_syntax(builtin_set)))
+ return -1;
+
+ if (lyn_create_symbol(lyn, "println", lyn_proc(builtin_println)))
+ return -1;
+
+ if (lyn_create_symbol(lyn, "<", lyn_proc(builtin_lt)))
+ return -1;
+
+ if (lyn_create_symbol(lyn, "+", lyn_proc(builtin_plus)))
+ return -1;
+
+ return 0;
+}
+
+static int eval_group(struct lyn *lyn, struct lyn_value group)
+{
+ assert(group.kind == LYN_GROUP);
+ foreach_vec(gi, group.args) {
+ struct lyn_value arg = lyn_at(group.args, gi);
+ if (lyn_eval(lyn, arg))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int eval_apply(struct lyn *lyn, struct lyn_value apply)
+{
+ assert(apply.kind == LYN_APPLY);
+ foreach_vec(ai, apply.args) {
+ struct lyn_value arg = lyn_at(apply.args, ai);
+ if (lyn_eval(lyn, arg))
+ return -1;
+ }
+
+ return 0;
+}
+
+int lyn_apply_cmd(struct lyn *lyn, struct lyn_symbol *cmd, struct vec args)
+{
+ switch (cmd->kind) {
+ case LYN_BUILTIN_SYNTAX: return cmd->call(lyn, args);
+ case LYN_BUILTIN_PROC: return cmd->call(lyn, args);
+ default: abort();
+ }
+
+ return 0;
+}
+
+static int eval_cmd(struct lyn *lyn, struct lyn_value cmd)
+{
+ assert(cmd.kind == LYN_CMD);
+
+ struct lyn_value name = lyn_at(cmd.args, 0);
+
+ /* to start with */
+ struct lyn_symbol *symb = lyn_lookup_symbol(lyn, name.s);
+ assert(symb);
+
+ return lyn_apply_cmd(lyn, symb, cmd.args);
+}
+
+static int eval_int(struct lyn *lyn, struct lyn_value i)
+{
+ assert(i.kind == LYN_INT);
+ lyn_return(lyn, i);
+ return 0;
+}
+
+static int eval_id(struct lyn *lyn, struct lyn_value id)
+{
+ assert(id.kind == LYN_ID);
+ struct lyn_symbol *symb = lyn_lookup_symbol(lyn, id.s);
+ assert(symb && symb->kind == LYN_VAR);
+
+ lyn_return(lyn, symb->value);
+ return 0;
+}
+
+int lyn_eval(struct lyn *lyn, struct lyn_value value)
+{
+ switch (value.kind) {
+ case LYN_GROUP: return eval_group(lyn, value);
+ case LYN_APPLY: return eval_apply(lyn, value);
+ case LYN_CMD: return eval_cmd(lyn, value);
+ case LYN_INT: return eval_int(lyn, value);
+ case LYN_ID: return eval_id(lyn, value);
+ default: error("unhandled case in interp eval"); break;
+ }
+
+ return -1;
+}
+
int lyn_eval_str(struct lyn *lyn, const char *name, const char *str)
{
struct parser *p = create_parser();
@@ -21,15 +334,15 @@ int lyn_eval_str(struct lyn *lyn, const char *name, const char *str)
return -1;
parse(p, name, str);
- struct ast *ast = p->tree;
+ struct lyn_value ast = p->tree;
bool failed = p->failed;
destroy_parser(p);
- if (!failed) {
- ast_dump_list(0, ast);
- }
+ if (failed)
+ return -1;
- return failed;
+ ast_dump(0, ast);
+ return lyn_eval(lyn, ast);
}
/**
@@ -84,6 +397,16 @@ int lyn_eval_file(struct lyn *lyn, const char *fname)
return ret;
}
+void lyn_return(struct lyn *lyn, struct lyn_value ast)
+{
+ lyn->res = ast;
+}
+
+struct lyn_value lyn_res(struct lyn *lyn)
+{
+ return lyn->res;
+}
+
void lyn_destroy(struct lyn *lyn)
{
}