aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--examples/loop.lyn6
-rw-r--r--examples/primitive.lyn5
-rw-r--r--include/lyn/ast.h89
-rw-r--r--include/lyn/lyn.h72
-rw-r--r--include/lyn/parser.h2
-rw-r--r--include/lyn/vec.h46
-rw-r--r--src/ast.c55
-rw-r--r--src/lyn.c333
-rw-r--r--src/main.c6
-rw-r--r--src/parser.y30
-rw-r--r--src/vec.c67
12 files changed, 586 insertions, 130 deletions
diff --git a/Makefile b/Makefile
index 79a05da..4819628 100644
--- a/Makefile
+++ b/Makefile
@@ -30,10 +30,6 @@ LYN_SOURCES :=
include src/source.mk
-.PHONY: check
-check: all
- $(MAKE) -C tests -k check
-
.PHONY: format
format:
find src include -iname '*.[ch]' |\
@@ -55,7 +51,6 @@ RM = rm
.PHONY: clean
clean:
$(RM) -rf $(CLEANUP)
- $(MAKE) -C tests clean
.PHONY: clean_docs
clean_docs:
diff --git a/examples/loop.lyn b/examples/loop.lyn
new file mode 100644
index 0000000..0304672
--- /dev/null
+++ b/examples/loop.lyn
@@ -0,0 +1,6 @@
+let sum 0
+for {let i 0} {< i 1000000} {set i (+ i 1)} {
+ set sum (+ sum i)
+}
+
+println sum
diff --git a/examples/primitive.lyn b/examples/primitive.lyn
new file mode 100644
index 0000000..4ebcf74
--- /dev/null
+++ b/examples/primitive.lyn
@@ -0,0 +1,5 @@
+let x 0
+println x
+
+set x 1
+println x
diff --git a/include/lyn/ast.h b/include/lyn/ast.h
index fd3b98b..ba9a0d5 100644
--- a/include/lyn/ast.h
+++ b/include/lyn/ast.h
@@ -3,102 +3,49 @@
#include <stdlib.h>
#include <string.h>
+#include <lyn/vec.h>
-enum kind {
- LYN_ID, LYN_STR, LYN_INT, LYN_FLOAT, LYN_CMD, LYN_LIST, LYN_APPLY
+enum lyn_kind {
+ LYN_ID, LYN_STR, LYN_INT, LYN_FLOAT, LYN_CMD, LYN_GROUP, LYN_APPLY
};
-struct ast {
- enum kind kind;
+struct lyn_value {
+ enum lyn_kind kind;
union {
long long i;
double d;
const char *s;
- struct ast *args;
+ struct vec args;
};
- struct ast *next;
};
-static inline struct ast *gen_id(const char *s)
+static inline struct lyn_value gen_id(const char *s)
{
- struct ast *id = calloc(1, sizeof(struct ast));
- if (!id)
- return NULL;
-
- id->kind = LYN_ID;
- id->s = strdup(s);
- return id;
+ return (struct lyn_value){.kind = LYN_ID, .s = strdup(s)};
}
-static inline struct ast *gen_str(const char *s)
+static inline struct lyn_value gen_str(const char *s)
{
- struct ast *str = calloc(1, sizeof(struct ast));
- if (!str)
- return NULL;
-
- str->kind = LYN_STR;
- str->s = strdup(s);
- return str;
+ return (struct lyn_value){.kind = LYN_STR, .s = strdup(s)};
}
-static inline struct ast *gen_int(long long i)
+static inline struct lyn_value gen_int(long long i)
{
- struct ast *integer = calloc(1, sizeof(struct ast));
- if (!integer)
- return NULL;
-
- integer->kind = LYN_INT;
- integer->i = i;
- return integer;
-}
-
-static inline struct ast *gen_float(double d)
-{
- struct ast *floating = calloc(1, sizeof(struct ast));
- if (!floating)
- return NULL;
-
- floating->kind = LYN_FLOAT;
- floating->d = d;
- return floating;
+ return (struct lyn_value){.kind = LYN_INT, .i = i};
}
-static inline struct ast *gen_apply(struct ast *cmds)
+static inline struct lyn_value gen_float(double d)
{
- struct ast *apply = calloc(1, sizeof(struct ast));
- if (!apply)
- return NULL;
-
- apply->kind = LYN_APPLY;
- apply->args = cmds;
- return apply;
+ return (struct lyn_value){.kind = LYN_FLOAT, .d = d};
}
-static inline struct ast *gen_list(struct ast *cmds)
+static inline struct lyn_value gen_list()
{
- struct ast *list = calloc(1, sizeof(struct ast));
- if (!list)
- return NULL;
-
- list->kind = LYN_LIST;
- list->args = cmds;
+ struct lyn_value list;
+ list.args = vec_create(sizeof(struct lyn_value));
return list;
}
-static inline struct ast *gen_cmd(struct ast *args)
-{
- struct ast *cmd = calloc(1, sizeof(struct ast));
- if (!cmd)
- return NULL;
-
- cmd->kind = LYN_CMD;
- cmd->args = args;
- return cmd;
-}
-
-void ast_dump(int depth, struct ast *ast);
-void ast_dump_list(int depth, struct ast *ast);
-
-struct ast *reverse_ast_list(struct ast *ast);
+void ast_dump(int depth, struct lyn_value val);
#endif /* LYN_AST_H */
diff --git a/include/lyn/lyn.h b/include/lyn/lyn.h
index 43094ca..27a2fe3 100644
--- a/include/lyn/lyn.h
+++ b/include/lyn/lyn.h
@@ -1,12 +1,84 @@
#ifndef LYN_H
#define LYN_H
+#include <lyn/parser.h>
+#include <lyn/vec.h>
+
+#define lyn_at(v, i)\
+ vect_at(struct lyn_value, v, i)
+
+struct lyn_scope {
+ struct lyn_scope *parent;
+ struct vec visible;
+};
+
struct lyn {
+ struct lyn_scope *root;
+ struct lyn_scope *cur;
+
+ struct lyn_value res;
+};
+
+typedef int (*lyn_call)(struct lyn *lyn, struct vec args);
+
+struct lyn_symbol {
+ enum lyn_symbol_kind {
+ LYN_BUILTIN_SYNTAX,
+ LYN_BUILTIN_PROC,
+ LYN_PROC,
+ LYN_SYNTAX,
+ LYN_VAR,
+ } kind;
+
+ union {
+ lyn_call call;
+ struct lyn_value value;
+ };
};
+static inline struct lyn_symbol lyn_syntax(lyn_call call)
+{
+ return (struct lyn_symbol){
+ .kind = LYN_BUILTIN_SYNTAX,
+ .call = call
+ };
+}
+
+static inline struct lyn_symbol lyn_proc(lyn_call call)
+{
+ return (struct lyn_symbol){
+ .kind = LYN_BUILTIN_PROC,
+ .call = call
+ };
+}
+
+static inline struct lyn_symbol lyn_var(struct lyn_value value)
+{
+ return (struct lyn_symbol){
+ .kind = LYN_VAR,
+ .value = value
+ };
+}
+
struct lyn lyn_create();
+int lyn_init(struct lyn *lyn);
+
+int lyn_eval(struct lyn *lyn, struct lyn_value value);
int lyn_eval_file(struct lyn *lyn, const char *fname);
int lyn_eval_str(struct lyn *lyn, const char *name, const char *str);
void lyn_destroy(struct lyn *lyn);
+int lyn_new_frame(struct lyn *lyn, lyn_call call, struct lyn_value args);
+int lyn_apply_cmd(struct lyn *lyn, struct lyn_symbol *symb, struct vec args);
+
+struct lyn_symbol *lyn_lookup_symbol(struct lyn *lyn, const char *name);
+
+int lyn_create_symbol(struct lyn *lyn, const char *name, struct lyn_symbol symb);
+int lyn_replace_symbol(struct lyn *lyn, const char *name, struct lyn_symbol symb);
+
+int lyn_create_scope(struct lyn *lyn);
+
+void lyn_return(struct lyn *lyn, struct lyn_value res);
+struct lyn_value lyn_res(struct lyn *lyn);
+
#endif /* LYN_H */
diff --git a/include/lyn/parser.h b/include/lyn/parser.h
index 81ecc49..105382e 100644
--- a/include/lyn/parser.h
+++ b/include/lyn/parser.h
@@ -23,7 +23,7 @@ struct parser {
*/
void *lexer;
- struct ast *tree;
+ struct lyn_value tree;
/** File content in memory. */
const char *buf;
diff --git a/include/lyn/vec.h b/include/lyn/vec.h
new file mode 100644
index 0000000..08a608a
--- /dev/null
+++ b/include/lyn/vec.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: copyleft-next-0.3.1 */
+
+#ifndef VEC_H
+#define VEC_H
+
+#include <stddef.h>
+
+struct vec {
+ size_t n;
+ size_t s;
+ size_t ns;
+ void *buf;
+};
+
+struct vec vec_create(size_t s);
+void vec_destroy(struct vec *v);
+void vec_reset(struct vec *v);
+
+size_t vec_len(struct vec *v);
+void *vec_at(struct vec *v, size_t i);
+void *vec_back(struct vec *v);
+void *vec_pop(struct vec *v);
+void vec_append(struct vec *v, void *n);
+
+typedef int (*vec_comp_t)(const void *, const void *);
+void vec_sort(struct vec *v, vec_comp_t comp);
+
+#define foreach_vec(iter, v) \
+ for (size_t iter = 0; iter < vec_len(&v); ++iter)
+
+#define vect_at(type, v, i) \
+ *(type *)vec_at(&v, i)
+
+#define vect_append(type, v, e) \
+ vec_append(&v, (type *)(e))
+
+#define vect_back(type, v) \
+ *(type *)vec_back(&v)
+
+#define vect_pop(type, v) \
+ *(type *)vec_pop(&v)
+
+#define vec_uninit(v) \
+ (v.buf == NULL)
+
+#endif /* VEC_H */
diff --git a/src/ast.c b/src/ast.c
index faeae6e..f99a7b8 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -1,53 +1,44 @@
#include <stdio.h>
#include <lyn/ast.h>
-struct ast *reverse_ast_list(struct ast *root)
-{
- struct ast *new_root = NULL;
- while (root) {
- struct ast *next = root->next;
- root->next = new_root;
- new_root = root;
- root = next;
- }
-
- return new_root;
-}
-
#define dump(depth, fmt, ...) \
do { \
printf("//%*s", 2 * depth, ""); \
printf(fmt,##__VA_ARGS__); \
} while (0)
-void ast_dump(int depth, struct ast *ast)
+void ast_dump(int depth, struct lyn_value val)
{
- switch (ast->kind) {
- case LYN_ID: dump(depth, "%s\n", ast->s); return;
- case LYN_STR: dump(depth, "\"%s\"\n", ast->s); return;
- case LYN_INT: dump(depth, "%lld\n", ast->i); return;
- case LYN_FLOAT: dump(depth, "%f\n", ast->d); return;
+ switch (val.kind) {
+ case LYN_ID: dump(depth, "%s\n", val.s); return;
+ case LYN_STR: dump(depth, "\"%s\"\n", val.s); return;
+ case LYN_INT: dump(depth, "%lld\n", val.i); return;
+ case LYN_FLOAT: dump(depth, "%f\n", val.d); return;
case LYN_CMD:
dump(depth, "CMD\n");
- ast_dump_list(depth + 1, ast->args);
- return;
+ foreach_vec(ci, val.args) {
+ struct lyn_value v = vect_at(struct lyn_value, val.args, ci);
+ ast_dump(depth + 1, v);
+ }
- case LYN_LIST:
- dump(depth, "LIST\n");
- ast_dump_list(depth + 1, ast->args);
return;
case LYN_APPLY:
dump(depth, "APPLY\n");
- ast_dump_list(depth + 1, ast->args);
+ foreach_vec(ai, val.args) {
+ struct lyn_value v = vect_at(struct lyn_value, val.args, ai);
+ ast_dump(depth + 1, v);
+ }
return;
- }
-}
-void ast_dump_list(int depth, struct ast *ast)
-{
- while (ast) {
- ast_dump(depth, ast);
- ast = ast->next;
+ case LYN_GROUP:
+ dump(depth, "GROUP\n");
+ foreach_vec(gi, val.args) {
+ struct lyn_value v = vect_at(struct lyn_value, val.args, gi);
+ ast_dump(depth + 1, v);
+ }
+ return;
+
+ default: abort();
}
}
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)
{
}
diff --git a/src/main.c b/src/main.c
index 85dd445..4e368f5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -9,8 +9,12 @@ int main(int argc, char *argv[])
}
struct lyn lyn = lyn_create();
+ if (lyn_init(&lyn)) {
+ lyn_destroy(&lyn);
+ return -1;
+ }
+
int ret = lyn_eval_file(&lyn, argv[1]);
lyn_destroy(&lyn);
-
return ret;
}
diff --git a/src/parser.y b/src/parser.y
index 3e0156f..742bc5f 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -29,7 +29,7 @@
%parse-param {void *scanner} {struct parser* parser}
%union {
- struct ast *ast;
+ struct lyn_value ast;
char *str;
long long integer;
double floating;
@@ -128,19 +128,19 @@ static char *strip(const char *s);
%%
arg
- : "(" cmds ")" {$$ = gen_apply($2);}
- | "{" cmds "}" {$$ = gen_list($2);}
+ : "(" cmds ")" {$$ = $2; $$.kind = LYN_APPLY;}
+ | "{" cmds "}" {$$ = $2; $$.kind = LYN_GROUP;}
| ID {$$ = gen_id($1);}
| STRING {$$ = gen_str($1);}
| INT {$$ = gen_int($1);}
| FLOAT {$$ = gen_float($1);}
rev_args
- : rev_args arg {$$ = $2; $$->next = $1;}
- | arg
+ : rev_args arg {$$ = $1; vect_append(struct lyn_value, $$.args, &$2);}
+ | arg {$$ = gen_list(); vect_append(struct lyn_value, $$.args, &$1);}
args
- : rev_args {$$ = reverse_ast_list($1);}
+ : rev_args
sep
: sep ";"
@@ -149,21 +149,21 @@ sep
| NL
cmd
- : args {$$ = gen_cmd($1);}
+ : args {$$ = $1; $$.kind = LYN_CMD;}
rev_cmds
- : rev_cmds sep cmd {$$ = $3; $$->next = $1;}
- | cmd
+ : rev_cmds sep cmd {$$ = $1; vect_append(struct lyn_value, $$.args, &$3);}
+ | cmd {$$ = gen_list(); vect_append(struct lyn_value, $$.args, &$1);}
cmds
- : rev_cmds {$$ = reverse_ast_list($1);}
- | rev_cmds sep {$$ = reverse_ast_list($1);}
- | sep rev_cmds {$$ = reverse_ast_list($2);}
- | sep rev_cmds sep {$$ = reverse_ast_list($2);}
- | {$$ = NULL;}
+ : rev_cmds
+ | rev_cmds sep
+ | sep rev_cmds {$$ = $2;}
+ | sep rev_cmds sep {$$ = $2;}
+ | {$$ = gen_list();}
input
- : cmds {parser->tree = gen_list($1);}
+ : cmds {$1.kind = LYN_GROUP; parser->tree = $1;}
%%
diff --git a/src/vec.c b/src/vec.c
new file mode 100644
index 0000000..dc7d3b1
--- /dev/null
+++ b/src/vec.c
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: copyleft-next-0.3.1 */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <lyn/vec.h>
+
+struct vec vec_create(size_t ns)
+{
+ return (struct vec) {
+ .n = 0,
+ .s = 1,
+ .ns = ns,
+ .buf = malloc(ns),
+ };
+}
+
+size_t vec_len(struct vec *v)
+{
+ return v->n;
+}
+
+void *vec_at(struct vec *v, size_t i)
+{
+ assert(i < v->n && "out of vector bounds");
+ return v->buf + i * v->ns;
+}
+
+void *vec_back(struct vec *v)
+{
+ assert(v->n);
+ return v->buf + (v->n - 1) * v->ns;
+}
+
+void *vec_pop(struct vec *v)
+{
+ assert(v->n && "attempting to pop empty vector");
+ v->n--;
+ return v->buf + v->n * v->ns;
+}
+
+void vec_append(struct vec *v, void *n)
+{
+ v->n++;
+ if (v->n >= v->s) {
+ v->s *= 2;
+ v->buf = realloc(v->buf, v->s * v->ns);
+ }
+
+ void *p = vec_at(v, v->n - 1);
+ memcpy(p, n, v->ns);
+}
+
+void vec_reset(struct vec *v)
+{
+ v->n = 0;
+}
+
+void vec_destroy(struct vec *v) {
+ free(v->buf);
+}
+
+void vec_sort(struct vec *v, vec_comp_t comp)
+{
+ qsort(v->buf, v->n, v->ns, comp);
+}