aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-06-22 08:24:53 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-06-22 08:24:53 +0200
commit9e127d92246d6577792122b013088466e3688da1 (patch)
treeedb73aa03739bf37626aae3038586a80d3b1aa50
parentf75e2f8b54ea9d77e94aca6e387556981a7795d3 (diff)
Store decl info in auxilliary data
-rw-r--r--src/analyzer.c95
-rw-r--r--src/analyzer.h4
-rw-r--r--src/codegen.c59
-rw-r--r--src/main.c6
-rw-r--r--src/parser.c80
-rw-r--r--src/parser.h32
-rw-r--r--src/primitives.gperf2
7 files changed, 163 insertions, 115 deletions
diff --git a/src/analyzer.c b/src/analyzer.c
index 798b34c..e8d4c51 100644
--- a/src/analyzer.c
+++ b/src/analyzer.c
@@ -56,7 +56,7 @@ struct cfctx {
idx_t_ si;
};
-static void analyzeast(struct scope *, struct type *, struct ast,
+static void analyzeast(struct scope *, struct type *, struct ast, struct aux,
struct lexemes, arena *)
__attribute__((nonnull));
static void constfold(mpq_t *, struct scope *, struct type *, struct ast,
@@ -65,22 +65,27 @@ static void constfold(mpq_t *, struct scope *, struct type *, struct ast,
/* Perform a pass over the entire AST and return an array of symbol
tables, one for each scope in the program */
-static struct scope *gensymtabs(struct ast, struct lexemes, arena *)
+static struct scope *gensymtabs(struct ast, struct aux, struct lexemes, arena *)
__attribute__((returns_nonnull, nonnull));
/* Find all the unordered symbols in the scope delimited by the inclusive
indicies BEG and END in the AST, and accumulate them into a symbol
table appended to the symbol table list. UP is the index of the
previous scopes symbol table in the symbol table list. */
-static void find_unordered_syms(struct scopes *, struct ast, struct lexemes,
- idx_t_ up, idx_t_ beg, idx_t_ end, arena *)
+static void find_unordered_syms(struct scopes *, struct ast, struct aux,
+ struct lexemes, idx_t_ up, idx_t_ beg,
+ idx_t_ end, arena *)
__attribute__((nonnull));
typedef idx_t_ analyzer(struct azctx, struct scope *, struct type *, struct ast,
- struct lexemes, idx_t_)
+ struct aux, struct lexemes, idx_t_)
+ __attribute__((nonnull));
+typedef idx_t_ constfolder(struct cfctx, mpq_t *, struct scope *, struct type *,
+ struct ast, struct lexemes, idx_t_)
__attribute__((nonnull));
static analyzer analyzeblk, analyzedecl, analyzeexpr, analyzefn, analyzestmt;
+static constfolder constfoldblk, constfolddecl, constfoldexpr, constfoldstmt;
static const struct type *typegrab(struct ast, struct lexemes, idx_t_)
__attribute__((returns_nonnull));
@@ -98,14 +103,14 @@ const struct type *typelookup(const uchar *, size_t)
__attribute__((nonnull));
void
-analyzeprog(struct ast ast, struct lexemes toks, arena *a, struct type **types,
- struct scope **scps, mpq_t **folds)
+analyzeprog(struct ast ast, struct aux aux, struct lexemes toks, arena *a,
+ struct type **types, struct scope **scps, mpq_t **folds)
{
*types = bufalloc(NULL, ast.len, sizeof(**types));
memset(*types, 0, ast.len * sizeof(**types));
- *scps = gensymtabs(ast, toks, a);
- analyzeast(*scps, *types, ast, toks, a);
+ *scps = gensymtabs(ast, aux, toks, a);
+ analyzeast(*scps, *types, ast, aux, toks, a);
*folds = bufalloc(NULL, ast.len, sizeof(**folds));
memset(*folds, 0, ast.len * sizeof(**folds));
@@ -113,17 +118,18 @@ analyzeprog(struct ast ast, struct lexemes toks, arena *a, struct type **types,
}
struct scope *
-gensymtabs(struct ast ast, struct lexemes toks, arena *a)
+gensymtabs(struct ast ast, struct aux aux, struct lexemes toks, arena *a)
{
struct scopes scps = {.cap = 32};
scps.buf = bufalloc(NULL, scps.cap, sizeof(*scps.buf));
- find_unordered_syms(&scps, ast, toks, 0, 0, ast.len - 1, a);
+ find_unordered_syms(&scps, ast, aux, toks, 0, 0, ast.len - 1, a);
return scps.buf;
}
void
-find_unordered_syms(struct scopes *scps, struct ast ast, struct lexemes toks,
- idx_t_ up, idx_t_ beg, idx_t_ end, arena *a)
+find_unordered_syms(struct scopes *scps, struct ast ast, struct aux aux,
+ struct lexemes toks, idx_t_ up, idx_t_ beg, idx_t_ end,
+ arena *a)
{
if (scps->len == scps->cap) {
scps->cap *= 2;
@@ -138,10 +144,11 @@ find_unordered_syms(struct scopes *scps, struct ast ast, struct lexemes toks,
};
for (idx_t_ i = beg; likely(i <= end); i++) {
- bool globl_var = ast.kinds[i] <= _AST_DECLS_END && beg == 0;
- bool const_var = (ast.kinds[i] | 1) == ASTPCDECL;
+ bool isstatic = ast.kinds[i] <= _AST_DECLS_END
+ && aux.buf[ast.kids[i].lhs].decl.isstatic;
+ bool isconst = ast.kinds[i] == ASTCDECL;
- if (globl_var || const_var) {
+ if (isstatic || isconst) {
struct strview sv = toks.strs[ast.lexemes[i]];
idx_t_ *p = symtab_insert(&scp->map, sv, a);
if (*p != 0) {
@@ -151,7 +158,7 @@ find_unordered_syms(struct scopes *scps, struct ast ast, struct lexemes toks,
*p = i;
} else if (ast.kinds[i] == ASTBLK) {
struct pair p = ast.kids[i];
- find_unordered_syms(scps, ast, toks, beg, p.lhs, p.rhs, a);
+ find_unordered_syms(scps, ast, aux, toks, beg, p.lhs, p.rhs, a);
i = p.rhs;
}
}
@@ -169,21 +176,21 @@ typegrab(struct ast ast, struct lexemes toks, idx_t_ i)
void
analyzeast(struct scope *scps, struct type *types, struct ast ast,
- struct lexemes toks, arena *a)
+ struct aux aux, struct lexemes toks, arena *a)
{
struct azctx ctx = {.a = a};
for (idx_t_ i = 0; likely(i < ast.len); i = fwdnode(ast, i)) {
assert(ast.kinds[i] <= _AST_DECLS_END);
- analyzedecl(ctx, scps, types, ast, toks, i);
+ analyzedecl(ctx, scps, types, ast, aux, toks, i);
}
}
idx_t_
analyzedecl(struct azctx ctx, struct scope *scps, struct type *types,
- struct ast ast, struct lexemes toks, idx_t_ i)
+ struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i)
{
struct strview sv = toks.strs[ast.lexemes[i]];
- if (ctx.si > 0 && (ast.kinds[i] | 1) == ASTPDECL) {
+ if (ctx.si > 0 && ast.kinds[i] == ASTDECL) {
idx_t_ *ip = symtab_insert(&scps[ctx.si].map, sv, ctx.a);
if (*ip == 0)
*ip = i;
@@ -199,15 +206,17 @@ analyzedecl(struct azctx ctx, struct scope *scps, struct type *types,
struct type ltype, rtype;
ltype.kind = TYPE_UNSET;
- assert(p.lhs != AST_EMPTY || p.rhs != AST_EMPTY);
+ idx_t_ typeidx = aux.buf[p.lhs].decl.type;
+
+ assert(typeidx != AST_EMPTY || p.rhs != AST_EMPTY);
idx_t_ ni;
- if (p.lhs != AST_EMPTY)
- ltype = *typegrab(ast, toks, p.lhs);
+ if (typeidx != AST_EMPTY)
+ ltype = *typegrab(ast, toks, typeidx);
if (p.rhs != AST_EMPTY) {
ctx.decl = sv;
- ni = analyzeexpr(ctx, scps, types, ast, toks, p.rhs);
+ ni = analyzeexpr(ctx, scps, types, ast, aux, toks, p.rhs);
rtype = types[p.rhs];
} else
ni = fwdnode(ast, i);
@@ -223,12 +232,12 @@ analyzedecl(struct azctx ctx, struct scope *scps, struct type *types,
idx_t_
analyzestmt(struct azctx ctx, struct scope *scps, struct type *types,
- struct ast ast, struct lexemes toks, idx_t_ i)
+ struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i)
{
switch (ast.kinds[i]) {
case ASTDECL:
case ASTCDECL:
- return analyzedecl(ctx, scps, types, ast, toks, i);
+ return analyzedecl(ctx, scps, types, ast, aux, toks, i);
case ASTRET: {
idx_t_ expr = ast.kids[i].rhs;
if (expr == AST_EMPTY) {
@@ -238,7 +247,8 @@ analyzestmt(struct azctx ctx, struct scope *scps, struct type *types,
} else if (ctx.fnret.kind == TYPE_UNSET)
err("analyzer: Function has no return value");
- idx_t_ ni = analyzeexpr(ctx, scps, types, ast, toks, ast.kids[i].rhs);
+ idx_t_ ni = analyzeexpr(ctx, scps, types, ast, aux, toks,
+ ast.kids[i].rhs);
if (!typecompat(ctx.fnret, types[ast.kids[i].rhs]))
err("analyzer: Return type mismatch");
return ni;
@@ -250,7 +260,7 @@ analyzestmt(struct azctx ctx, struct scope *scps, struct type *types,
idx_t_
analyzeexpr(struct azctx ctx, struct scope *scps, struct type *types,
- struct ast ast, struct lexemes toks, idx_t_ i)
+ struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i)
{
switch (ast.kinds[i]) {
case ASTNUMLIT:
@@ -277,7 +287,7 @@ analyzeexpr(struct azctx ctx, struct scope *scps, struct type *types,
switch (types[*ip].kind) {
case TYPE_UNSET:
ctx.si = lvl;
- analyzedecl(ctx, scps, types, ast, toks, *ip);
+ analyzedecl(ctx, scps, types, ast, aux, toks, *ip);
break;
case TYPE_CHECKING:
err("analyzer: Circular definition of ‘%.*s’", SV_PRI_ARGS(sv));
@@ -291,7 +301,7 @@ analyzeexpr(struct azctx ctx, struct scope *scps, struct type *types,
err("analyzer: Unknown symbol ‘%.*s’", SV_PRI_ARGS(sv));
}
case ASTFN:
- return analyzefn(ctx, scps, types, ast, toks, i);
+ return analyzefn(ctx, scps, types, ast, aux, toks, i);
default:
__builtin_unreachable();
}
@@ -299,7 +309,7 @@ analyzeexpr(struct azctx ctx, struct scope *scps, struct type *types,
idx_t_
analyzefn(struct azctx ctx, struct scope *scps, struct type *types,
- struct ast ast, struct lexemes toks, idx_t_ i)
+ struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i)
{
struct type t = {.kind = TYPE_FN};
struct pair p = ast.kids[i];
@@ -312,12 +322,12 @@ analyzefn(struct azctx ctx, struct scope *scps, struct type *types,
} else
ctx.fnret.kind = TYPE_UNSET;
types[i] = t;
- return analyzeblk(ctx, scps, types, ast, toks, p.rhs);
+ return analyzeblk(ctx, scps, types, ast, aux, toks, p.rhs);
}
idx_t_
analyzeblk(struct azctx ctx, struct scope *scps, struct type *types,
- struct ast ast, struct lexemes toks, idx_t_ i)
+ struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i)
{
struct pair p = ast.kids[i];
@@ -330,7 +340,7 @@ analyzeblk(struct azctx ctx, struct scope *scps, struct type *types,
for (i = p.lhs; i <= p.rhs;) {
if (chkrets && returns(ast, i))
hasret = true;
- i = analyzestmt(ctx, scps, types, ast, toks, i);
+ i = analyzestmt(ctx, scps, types, ast, aux, toks, i);
}
if (chkrets && !hasret)
err("analyzer: Function doesn’t return on all paths");
@@ -338,13 +348,6 @@ analyzeblk(struct azctx ctx, struct scope *scps, struct type *types,
return i;
}
-static idx_t_
-constfolddecl(struct cfctx ctx, mpq_t *folds, struct scope *scps,
- struct type *types, struct ast ast, struct lexemes toks, idx_t_ i);
-static idx_t_
-constfoldexpr(struct cfctx ctx, mpq_t *folds, struct scope *scps,
- struct type *types, struct ast ast, struct lexemes toks, idx_t_ i);
-
idx_t_
constfoldstmt(struct cfctx ctx, mpq_t *folds, struct scope *scps,
struct type *types, struct ast ast, struct lexemes toks, idx_t_ i)
@@ -352,8 +355,6 @@ constfoldstmt(struct cfctx ctx, mpq_t *folds, struct scope *scps,
switch (ast.kinds[i]) {
case ASTDECL:
case ASTCDECL:
- case ASTPCDECL:
- case ASTPDECL:
return constfolddecl(ctx, folds, scps, types, ast, toks, i);
case ASTRET:
return constfoldexpr(ctx, folds, scps, types, ast, toks,
@@ -425,10 +426,8 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, struct scope *scps,
} else {
switch (ast.kinds[*ip]) {
case ASTDECL:
- case ASTPDECL:
break;
- case ASTCDECL:
- case ASTPCDECL: {
+ case ASTCDECL: {
idx_t_ expr = ast.kids[*ip].rhs;
assert(expr != AST_EMPTY);
#if DEBUG
@@ -493,9 +492,7 @@ returns(struct ast ast, idx_t_ i)
{
switch (ast.kinds[i]) {
case ASTDECL:
- case ASTPDECL:
case ASTCDECL:
- case ASTPCDECL:
return false;
case ASTRET:
return true;
diff --git a/src/analyzer.h b/src/analyzer.h
index ec6089c..ceb4899 100644
--- a/src/analyzer.h
+++ b/src/analyzer.h
@@ -56,8 +56,8 @@ struct type {
};
};
-void analyzeprog(struct ast, struct lexemes, arena *, struct type **,
- struct scope **, mpq_t **)
+void analyzeprog(struct ast, struct aux, struct lexemes, arena *,
+ struct type **, struct scope **, mpq_t **)
__attribute__((nonnull));
#endif /* !ORYX_ANALYZER_H */
diff --git a/src/codegen.c b/src/codegen.c
index 5b883b5..bbe7d5f 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -42,10 +42,7 @@ void
codegen(const char *file, mpq_t *folds, struct scope *scps, struct type *types,
struct ast ast, struct lexemes toks)
{
- (void)types;
(void)scps;
- (void)ast;
- (void)toks;
char *triple = LLVMGetDefaultTargetTriple();
struct cgctx ctx;
@@ -75,19 +72,40 @@ codegen(const char *file, mpq_t *folds, struct scope *scps, struct type *types,
}
idx_t_
+codegenfunc(struct cgctx ctx, mpq_t *folds, struct type *types, struct ast ast,
+ struct lexemes toks, idx_t_ i, const char *name)
+{
+ LLVMTypeRef ret = type2llvm(ctx, types[ast.kids[i].rhs]);
+ LLVMTypeRef ft = LLVMFunctionType(ret, NULL, 0, false);
+ LLVMValueRef fn = LLVMAddFunction(ctx.mod, name, ft);
+ LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fn, "entry");
+
+ struct pair p = ast.kids[i];
+ // for (i = p.lhs; i <= p.rhs; i = codegenstmt(ctx, folds, types, ast, toks, i))
+ // ;
+ return fwdnode(ast, p.rhs);
+}
+
+idx_t_
codegendecl(struct cgctx ctx, mpq_t *folds, struct type *types, struct ast ast,
struct lexemes toks, idx_t_ i)
{
/* Constants are purely a compiler concept; they aren’t generated
into anything */
- if ((ast.kinds[i] | 1) == ASTPCDECL)
+ if (ast.kinds[i] == ASTCDECL)
return fwdnode(ast, i);
struct pair p = ast.kids[i];
- switch (ast.kinds[p.rhs]) {
- case ASTFN:
- err("%s():%d: TODO", __func__, __LINE__);
- default: {
+ if (ast.kinds[p.rhs] == ASTFN) {
+ struct strview sv = toks.strs[ast.lexemes[i]];
+ /* TODO: Namespace the name */
+ /* TODO: Temporary allocator */
+ char *name = bufalloc(NULL, sv.len + 1, 1);
+ svtocstr(name, sv);
+ i = codegenfunc(ctx, folds, types, ast, toks, p.rhs, name);
+ free(name);
+ return i;
+ } else if (!types[i].isfloat) {
struct strview sv = toks.strs[ast.lexemes[i]];
/* TODO: Namespace the name */
/* TODO: Temporary allocator */
@@ -96,7 +114,13 @@ codegendecl(struct cgctx ctx, mpq_t *folds, struct type *types, struct ast ast,
LLVMValueRef globl = LLVMAddGlobal(ctx.mod, t, svtocstr(name, sv));
free(name);
- /* TODO: Assert that the fold is an integer */
+#if DEBUG /* Assert that the fold is an integer */
+ mpz_t den;
+ mpq_canonicalize(folds[p.rhs]);
+ mpq_get_den(den, folds[p.rhs]);
+ assert(mpz_cmp_si(den, 1) == 0);
+ mpz_clear(den);
+#endif
/* The max value of a u128 is length 39 */
char buf[40];
@@ -106,8 +130,8 @@ codegendecl(struct cgctx ctx, mpq_t *folds, struct type *types, struct ast ast,
LLVMSetLinkage(globl, LLVMInternalLinkage);
return fwdnode(ast, i);
- }
- }
+ } else /* && types[i].isfloat */
+ err("%s():%d: TODO", __func__, __LINE__);
}
void
@@ -126,9 +150,16 @@ type2llvm(struct cgctx ctx, struct type t)
case TYPE_FN:
err("codegen: %s: Not implemented for function types", __func__);
case TYPE_NUM:
- /* TODO: Floats */
- if (t.isfloat)
- err("codegen: %s: Not implemented for floats", __func__);
+ if (t.isfloat) {
+ switch (t.size) {
+ case 2: return LLVMHalfTypeInContext(ctx.ctx);
+ case 4: return LLVMFloatTypeInContext(ctx.ctx);
+ case 0:
+ case 8: return LLVMDoubleTypeInContext(ctx.ctx);
+ case 16: return LLVMFP128TypeInContext(ctx.ctx);
+ default: __builtin_unreachable();
+ }
+ }
/* TODO: Arbitrary precision */
if (t.size == 0)
return LLVMInt64TypeInContext(ctx.ctx);
diff --git a/src/main.c b/src/main.c
index 5bd30fe..86e8e54 100644
--- a/src/main.c
+++ b/src/main.c
@@ -31,12 +31,13 @@ main(int argc, char **argv)
arena a = NULL;
mpq_t *folds;
+ struct aux aux;
struct type *types;
struct scope *scps;
struct lexemes toks = lexstring(src, srclen);
- struct ast ast = parsetoks(toks);
- analyzeprog(ast, toks, &a, &types, &scps, &folds);
+ struct ast ast = parsetoks(toks, &aux);
+ analyzeprog(ast, aux, toks, &a, &types, &scps, &folds);
codegen(argv[1], folds, scps, types, ast, toks);
#if DEBUG
@@ -51,6 +52,7 @@ main(int argc, char **argv)
free(types);
lexemes_free(toks);
ast_free(ast);
+ aux_free(aux);
arena_free(&a);
#endif
return EXIT_SUCCESS;
diff --git a/src/parser.c b/src/parser.c
index 5d9bf9c..3f8195c 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -14,15 +14,17 @@
#if DEBUG
# define AST_DFLT_CAP (8)
+# define AUX_DFLT_CAP (8)
#else
# define AST_DFLT_CAP (2048)
+# define AUX_DFLT_CAP (128)
#endif
#define SIZE_WDTH (sizeof(size_t) * CHAR_BIT)
-typedef idx_t_ parsefn(struct ast *, struct lexemes)
+typedef idx_t_ parsefn(struct ast *, struct aux *, struct lexemes)
__attribute__((nonnull));
static parsefn parseblk, parseexpr, parsefunc, parseproto, parsestmt, parsetype;
-static idx_t_ parsedecl(struct ast *, struct lexemes, bool)
+static idx_t_ parsedecl(struct ast *, struct aux *, struct lexemes, bool)
__attribute__((nonnull));
static struct ast mkast(void);
@@ -42,7 +44,6 @@ fwdnode(struct ast ast, idx_t_ i)
i = ast.kids[i].lhs == AST_EMPTY ? i + 1 : ast.kids[i].rhs;
break;
case ASTDECL:
- case ASTPDECL:
i = ast.kids[i].rhs == AST_EMPTY ? ast.kids[i].lhs
: ast.kids[i].rhs;
break;
@@ -54,7 +55,6 @@ fwdnode(struct ast ast, idx_t_ i)
case ASTBINADD:
case ASTBINSUB:
case ASTCDECL:
- case ASTPCDECL:
case ASTFN:
i = ast.kids[i].rhs;
break;
@@ -72,12 +72,13 @@ fwdnode(struct ast ast, idx_t_ i)
}
struct ast
-parsetoks(struct lexemes toks)
+parsetoks(struct lexemes toks, struct aux *aux)
{
struct ast ast = mkast();
+ aux->buf = bufalloc(NULL, aux->cap = AUX_DFLT_CAP, sizeof(*aux->buf));
for (;;) {
- (void)parsedecl(&ast, toks, true);
+ (void)parsedecl(&ast, aux, toks, true);
if (toks.kinds[toksidx] == LEXEOF)
break;
}
@@ -86,7 +87,7 @@ parsetoks(struct lexemes toks)
}
idx_t_
-parseblk(struct ast *ast, struct lexemes toks)
+parseblk(struct ast *ast, struct aux *aux, struct lexemes toks)
{
idx_t_ i = astalloc(ast);
ast->lexemes[i] = toksidx;
@@ -98,12 +99,12 @@ parseblk(struct ast *ast, struct lexemes toks)
err("parser: Expected left brace");
if (toks.kinds[toksidx] != LEXRBRACE) {
- idx_t_ stmt = parsestmt(ast, toks);
+ idx_t_ stmt = parsestmt(ast, aux, toks);
ast->kids[i].lhs = ast->kids[i].rhs = stmt;
}
while (toks.kinds[toksidx] != LEXRBRACE) {
- idx_t_ stmt = parsestmt(ast, toks);
+ idx_t_ stmt = parsestmt(ast, aux, toks);
ast->kids[i].rhs = stmt;
}
@@ -112,18 +113,23 @@ parseblk(struct ast *ast, struct lexemes toks)
}
idx_t_
-parsedecl(struct ast *ast, struct lexemes toks, bool toplvl)
+parsedecl(struct ast *ast, struct aux *aux, struct lexemes toks, bool toplvl)
{
- idx_t_ i = astalloc(ast);
+ idx_t_ i = astalloc(ast), j = aux->len++;
+
+ if (aux->len > aux->cap) {
+ aux->cap *= 2;
+ aux->buf = bufalloc(aux->buf, aux->cap, sizeof(*aux->buf));
+ }
- bool pub;
+ aux->buf[j].decl.isstatic = toplvl;
if (toplvl && toks.kinds[toksidx] == LEXIDENT
&& strview_eq(SV("pub"), toks.strs[toksidx]))
{
- pub = true;
+ aux->buf[j].decl.ispub = true;
ast->lexemes[i] = ++toksidx;
} else {
- pub = false;
+ aux->buf[j].decl.ispub = false;
ast->lexemes[i] = toksidx;
}
@@ -132,32 +138,33 @@ parsedecl(struct ast *ast, struct lexemes toks, bool toplvl)
if (toks.kinds[toksidx++] != LEXCOLON)
err("parser: Expected colon");
- idx_t_ lhs = toks.kinds[toksidx] == LEXIDENT ? parsetype(ast, toks)
- : AST_EMPTY;
- ast->kids[i].lhs = lhs;
+ aux->buf[j].decl.type = toks.kinds[toksidx] == LEXIDENT
+ ? parsetype(ast, aux, toks)
+ : AST_EMPTY;
+ ast->kids[i].lhs = j;
switch (toks.kinds[toksidx++]) {
case LEXSEMI:
- if (ast->kids[i].lhs == AST_EMPTY)
+ if (aux->buf[j].decl.type == AST_EMPTY)
err("parser: No type provided in non-assigning declaration");
- ast->kinds[i] = ASTDECL + pub;
+ ast->kinds[i] = ASTDECL;
ast->kids[i].rhs = AST_EMPTY;
return i;
case LEXCOLON:
- ast->kinds[i] = ASTCDECL + pub;
+ ast->kinds[i] = ASTCDECL;
break;
case LEXEQ:
- ast->kinds[i] = ASTDECL + pub;
+ ast->kinds[i] = ASTDECL;
break;
default:
err("parser: Expected colon, equals, or semicolon");
}
bool func = toks.kinds[toksidx] == LEXLPAR;
- if (func && ast->kinds[i] - pub == ASTDECL)
+ if (func && ast->kinds[i] == ASTDECL)
err("Cannot assign function to mutable variable");
- idx_t_ rhs = (func ? parsefunc : parseexpr)(ast, toks);
+ idx_t_ rhs = (func ? parsefunc : parseexpr)(ast, aux, toks);
ast->kids[i].rhs = rhs;
if (!func && toks.kinds[toksidx++] != LEXSEMI)
err("parser: Expected semicolon");
@@ -166,7 +173,7 @@ parsedecl(struct ast *ast, struct lexemes toks, bool toplvl)
}
idx_t_
-parsefunc(struct ast *ast, struct lexemes toks)
+parsefunc(struct ast *ast, struct aux *aux, struct lexemes toks)
{
idx_t_ i = astalloc(ast);
ast->lexemes[i] = toksidx;
@@ -174,8 +181,8 @@ parsefunc(struct ast *ast, struct lexemes toks)
assert(toks.kinds[toksidx] == LEXLPAR);
ast->kinds[i] = ASTFN;
- idx_t_ lhs = parseproto(ast, toks);
- idx_t_ rhs = parseblk(ast, toks);
+ idx_t_ lhs = parseproto(ast, aux, toks);
+ idx_t_ rhs = parseblk(ast, aux, toks);
ast->kids[i].lhs = lhs;
ast->kids[i].rhs = rhs;
@@ -183,8 +190,9 @@ parsefunc(struct ast *ast, struct lexemes toks)
}
idx_t_
-parseexpr(struct ast *ast, struct lexemes toks)
+parseexpr(struct ast *ast, struct aux *aux, struct lexemes toks)
{
+ (void)aux;
idx_t_ i = astalloc(ast);
ast->lexemes[i] = toksidx;
@@ -205,7 +213,7 @@ parseexpr(struct ast *ast, struct lexemes toks)
}
idx_t_
-parseproto(struct ast *ast, struct lexemes toks)
+parseproto(struct ast *ast, struct aux *aux, struct lexemes toks)
{
idx_t_ i = astalloc(ast);
ast->lexemes[i] = toksidx;
@@ -217,14 +225,14 @@ parseproto(struct ast *ast, struct lexemes toks)
if (toks.kinds[toksidx++] != LEXRPAR)
err("parser: Expected right parenthesis");
- idx_t_ rhs = toks.kinds[toksidx] == LEXIDENT ? parsetype(ast, toks)
+ idx_t_ rhs = toks.kinds[toksidx] == LEXIDENT ? parsetype(ast, aux, toks)
: AST_EMPTY;
ast->kids[i].rhs = rhs;
return i;
}
idx_t_
-parsestmt(struct ast *ast, struct lexemes toks)
+parsestmt(struct ast *ast, struct aux *aux, struct lexemes toks)
{
idx_t_ i;
@@ -237,22 +245,24 @@ parsestmt(struct ast *ast, struct lexemes toks)
ast->lexemes[i] = toksidx++;
ast->kinds[i] = ASTRET;
- idx_t_ rhs = toks.kinds[toksidx] != LEXSEMI ? parseexpr(ast, toks)
+ idx_t_ rhs = toks.kinds[toksidx] != LEXSEMI ? parseexpr(ast, aux, toks)
: AST_EMPTY;
ast->kids[i].rhs = rhs;
if (toks.kinds[toksidx++] != LEXSEMI)
err("parser: Expected semicolon");
- } else if (toks.kinds[toksidx + 1] == LEXCOLON)
- i = parsedecl(ast, toks, false);
- else
+ } else if (toks.kinds[toksidx + 1] == LEXCOLON) {
+ i = parsedecl(ast, aux, toks, false);
+ } else {
err("parser: Invalid statement");
+ }
return i;
}
idx_t_
-parsetype(struct ast *ast, struct lexemes toks)
+parsetype(struct ast *ast, struct aux *aux, struct lexemes toks)
{
+ (void)aux;
idx_t_ i = astalloc(ast);
ast->kinds[i] = ASTTYPE;
ast->lexemes[i] = toksidx;
diff --git a/src/parser.h b/src/parser.h
index 1b91498..b4ce8c4 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -16,22 +16,14 @@ enum {
public by if the LSB is set. */
/* Variable declaration, lhs and rhs may be unused
- ‘x: lhs = rhs’ */
+ ‘x := rhs’; aux[lhs].decl */
ASTDECL,
- /* Public variable declaration, lhs and rhs may be unused
- ‘pub x: lhs = rhs’ */
- ASTPDECL,
-
/* Constant declaration, lhs may be unused
- ‘x: lhs : rhs’ */
+ ‘x :: rhs’; aux[lhs].decl */
ASTCDECL,
- /* Public constant declaration, lhs may be unused
- ‘pub x: lhs : rhs’ */
- ASTPCDECL,
-
- _AST_DECLS_END = ASTPCDECL,
+ _AST_DECLS_END = ASTCDECL,
/* Function prototype
‘(a: b, c: d) rhs’; aux[lhs].fnproto */
@@ -76,6 +68,17 @@ static_assert(_AST_LAST_ENT - 1 <= (ast_kind_t_)-1,
#define AST_EMPTY ((idx_t_)-1)
#define AST_SOA_BLKSZ (sizeof(ast_kind_t_) + sizeof(idx_t_) * 3)
+struct aux {
+ union {
+ struct {
+ idx_t_ type;
+ bool ispub;
+ bool isstatic;
+ } decl;
+ } *buf;
+ size_t len, cap;
+};
+
struct ast {
ast_kind_t_ *kinds;
idx_t_ *lexemes;
@@ -86,9 +89,12 @@ struct ast {
};
#define ast_free(x) free((x).kinds)
+#define aux_free(x) free((x).buf)
-/* Parse the tokens in TOKS into an abstract syntax tree */
-struct ast parsetoks(struct lexemes toks);
+/* Parse the tokens in TOKS into an abstract syntax tree, and store
+ auxilliary information in AUX */
+struct ast parsetoks(struct lexemes toks, struct aux *aux)
+ __attribute__((nonnull));
/* Starting from the node at indent I in AST, return the index of the next node
in AST that is of the same nest-depth as I */
diff --git a/src/primitives.gperf b/src/primitives.gperf
index 230413f..ca9b8c2 100644
--- a/src/primitives.gperf
+++ b/src/primitives.gperf
@@ -29,8 +29,10 @@ u64, { TYPE_NUM, {.size = 8, .issigned=false, .isfloat=false} }
u128, { TYPE_NUM, {.size = 16, .issigned=false, .isfloat=false} }
uint, { TYPE_NUM, {.size = 8, .issigned=false, .isfloat=false} }
rune, { TYPE_NUM ,{.size = 4, .issigned=true, .isfloat=false} }
+f16, { TYPE_NUM, {.size = 2, .issigned=true, .isfloat=true } }
f32, { TYPE_NUM, {.size = 4, .issigned=true, .isfloat=true } }
f64, { TYPE_NUM, {.size = 8, .issigned=true, .isfloat=true } }
+f128, { TYPE_NUM, {.size = 16, .issigned=true, .isfloat=true } }
%%
const struct type *
typelookup(const uchar *p, size_t len)