aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/parse.h12
-rw-r--r--src/parse.c96
2 files changed, 101 insertions, 7 deletions
diff --git a/include/parse.h b/include/parse.h
index d3cee83..8cc4985 100644
--- a/include/parse.h
+++ b/include/parse.h
@@ -49,6 +49,7 @@ struct ast_const_global {
struct ast_path {
const char **segments;
+ int len, cap;
};
struct ast_import {
@@ -71,14 +72,11 @@ struct ast_toplevel {
} decl;
};
-struct ast_subunit {
- struct ast_import *imports;
- struct ast_toplevel tops[];
-};
-
struct ast_unit {
- struct ast_subunit *root;
- struct ast_subunit imports[];
+ struct ast_import *imports;
+ struct ast_toplevel *tops;
+ int impsz, implen;
+ int topsz, toplen;
};
void parse(struct lexer *lexer, struct ast_unit *ast);
diff --git a/src/parse.c b/src/parse.c
index 406752d..a047424 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1 +1,97 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdnoreturn.h>
#include "parse.h"
+#include "util.h"
+
+static noreturn void
+error(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "\n");
+ exit(EXIT_PARSE);
+}
+
+static void
+append(struct ast_path *path, const char *name)
+{
+ if (path->len >= path->cap) {
+ path->cap *= 2;
+ size_t sz = sizeof(const char *) * path->cap;
+ path->segments = must_realloc(path->segments, sz);
+ }
+
+ path->segments[path->len++] = name;
+}
+
+static bool
+parse_path(struct lexer *lexer, struct ast_path *out)
+{
+ struct token name;
+
+ if (lex(lexer, &name) != T_NAME) {
+ error("syntax error: expected path");
+ }
+
+ out->segments = must_calloc(1, sizeof(const char *));
+ out->segments[0] = name.info.str;
+ out->len = 1;
+ out->cap = 1;
+
+ while (match(lexer, T_MODDELIM)) {
+ if (lex(lexer, &name) != T_NAME) {
+ error("syntax error: expected name");
+ }
+ append(out, name.info.str);
+ }
+
+ return true;
+}
+
+static bool
+parse_import(struct lexer *lexer, struct ast_import *out)
+{
+ if (!match(lexer, T_IMPORT)) {
+ return false;
+ }
+
+ if (!parse_path(lexer, &out->path)) {
+ error("syntax error: expected import path");
+ }
+
+ struct token token;
+ if (lex(lexer, &token) == T_NAME) {
+ out->name = token.info.str;
+ } else {
+ unlex(lexer, &token);
+ out->name = out->path.segments[out->path.len - 1];
+ }
+
+ if (!match(lexer, T_SEMICOLON)) {
+ error("syntax error: expected semicolon");
+ }
+
+ return true;
+}
+
+void
+parse(struct lexer *lexer, struct ast_unit *ast)
+{
+ ast->imports = must_calloc(1, sizeof(struct ast_import));
+ ast->impsz = 1;
+ ast->implen = 0;
+
+ struct ast_import import;
+ while (parse_import(lexer, &import)) {
+ if (ast->implen >= ast->impsz) {
+ ast->impsz *= 2;
+ size_t sz = sizeof(struct ast_import) * ast->impsz;
+ ast->imports = must_realloc(ast->imports, sz);
+ }
+ ast->imports[ast->implen++] = import;
+ }
+}