aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--grammar.ebnf6
-rw-r--r--src/analyzer.c27
-rw-r--r--src/codegen.c36
-rw-r--r--src/parser.c45
-rw-r--r--src/parser.h8
5 files changed, 101 insertions, 21 deletions
diff --git a/grammar.ebnf b/grammar.ebnf
index ed4260e..b16a85b 100644
--- a/grammar.ebnf
+++ b/grammar.ebnf
@@ -34,6 +34,7 @@ prototype
statement
= declaration
| assignment
+ | funcall
| 'return', [expression], ';'
;
@@ -43,6 +44,11 @@ expression
| unop, expression
| expression, binop, expression
| '(', expression, ')'
+ | funcall
+ ;
+
+funcall
+ = expression '(' ')'
;
unop
diff --git a/src/analyzer.c b/src/analyzer.c
index f40d12b..3683a68 100644
--- a/src/analyzer.c
+++ b/src/analyzer.c
@@ -355,6 +355,8 @@ analyzestmt(struct azctx *ctx, idx_t i)
ctx->types[i] = ctx->fnret;
return ni;
}
+ case ASTCALLSTMT:
+ return analyzeexpr(ctx, i + 1);
default:
__builtin_unreachable();
}
@@ -499,6 +501,14 @@ analyzeexpr(struct azctx *ctx, idx_t i)
}
case ASTFN:
return analyzefn(ctx, i);
+ case ASTFUNCALL: {
+ /* TODO: Support function arguments */
+ assert(ctx->ast.kids[i].rhs == AST_EMPTY);
+ idx_t ni, lhs = ctx->ast.kids[i].lhs;
+ ni = analyzeexpr(ctx, lhs);
+ ctx->types[i] = ctx->types[lhs]->ret;
+ return ni;
+ }
default:
__builtin_unreachable();
}
@@ -595,6 +605,9 @@ constfoldexpr(struct azctx *ctx, type_t *T, idx_t i)
struct azctx nctx;
switch (ctx->ast.kinds[i]) {
+ case ASTFUNCALL:
+ /* TODO: Constfold funcall params */
+ break;
case ASTFN:
return constfoldblk(ctx, ctx->ast.kids[i].rhs);
case ASTNUMLIT: {
@@ -910,16 +923,18 @@ typecompat(type_t *lhs, type_t *rhs)
if (lhs == rhs)
return true;
- /* Boolean types are only compatible with boolean types */
- if (lhs->kind == TYPE_BOOL || rhs->kind == TYPE_BOOL)
- return lhs->kind == TYPE_BOOL && rhs->kind == TYPE_BOOL;
+ if (lhs->kind != rhs->kind)
+ return false;
/* Function types are compatible if they have the same parameter- and
return types */
- if (lhs->kind == TYPE_FN && rhs->kind == TYPE_FN)
+ /* TODO: Compare the actual parameter types */
+ if (lhs->kind == TYPE_FN)
return lhs->paramcnt == rhs->paramcnt && lhs->ret == rhs->ret;
- if (lhs->kind == TYPE_FN || rhs->kind == TYPE_FN)
- return false;
+
+ /* Boolean types are only compatible with boolean types */
+ if (lhs->kind == TYPE_BOOL)
+ return true;
/* At this point we only have numeric types left */
diff --git a/src/codegen.c b/src/codegen.c
index 252ac29..3c8196d 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -146,6 +146,10 @@ static idx_t codegendecl(struct cgctx ctx, idx_t);
idx_t
codegentypedexpr(struct cgctx ctx, idx_t i, type_t *T, LLVMValueRef *outv)
{
+ /* To avoid spamming NULL checks everywhere */
+ if (T == NULL || outv == NULL)
+ goto callstmt;
+
if (T->kind == TYPE_NUM && TESTBIT(ctx.cnst, i) && !T->isfloat) {
char buf[40 /* The max value of a u128 is length 39 */];
mpz_get_str(buf, 10, mpq_numref(ctx.folds[i].q));
@@ -194,7 +198,8 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t *T, LLVMValueRef *outv)
mpf_clear(x);
return fwdnode(ctx.ast, i);
} else if (T->kind == TYPE_BOOL && TESTBIT(ctx.cnst, i)) {
- *outv = LLVMConstInt(type2llvm(ctx, ctx.types[i]), ctx.folds[i].b, false);
+ *outv = LLVMConstInt(type2llvm(ctx, ctx.types[i]), ctx.folds[i].b,
+ false);
return fwdnode(ctx.ast, i);
}
@@ -280,6 +285,19 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t *T, LLVMValueRef *outv)
*outv = LLVMBuildICmp(ctx.bob, bo.pred, vl, vr, bo.name);
return ni;
}
+callstmt:
+ case ASTFUNCALL: {
+ idx_t lhs = ctx.ast.kids[i].lhs;
+ assert(ctx.ast.kinds[lhs] == ASTIDENT);
+ strview_t sv = ctx.toks.strs[ctx.ast.lexemes[lhs]];
+ symval_t *sym = symtab_get_from_scopes(ctx, sv);
+ LLVMTypeRef ft = LLVMGlobalGetValueType(sym->v);
+ LLVMValueRef call = LLVMBuildCall2(ctx.bob, ft, sym->v, NULL, 0,
+ outv == NULL ? "" : "call");
+ if (outv != NULL)
+ *outv = call;
+ return fwdnode(ctx.ast, i);
+ }
default:
__builtin_unreachable();
}
@@ -314,6 +332,8 @@ codegenstmt(struct cgctx ctx, idx_t i)
(void)LLVMBuildRet(ctx.bob, v);
return i;
}
+ case ASTCALLSTMT:
+ return codegentypedexpr(ctx, i + 1, NULL, NULL);
default:
__builtin_unreachable();
}
@@ -356,7 +376,7 @@ codegenalloca(struct cgctx ctx, idx_t i)
}
idx_t
-codegenfunc(struct cgctx ctx, idx_t i, strview_t sv)
+codegenfunc(struct cgctx ctx, idx_t i, strview_t sv, LLVMValueRef *outv)
{
size_t namesz = ctx.namespace.len + sv.len + 1;
char *name = arena_new(ctx.a, char, namesz + 1);
@@ -374,11 +394,14 @@ codegenfunc(struct cgctx ctx, idx_t i, strview_t sv)
idx_t proto = ctx.ast.kids[i].lhs;
idx_t blk = ctx.ast.kids[i].rhs;
+ while (ctx.scps[ctx.scpi].i != ctx.ast.kids[blk].lhs)
+ ctx.scpi++;
+
snapshot_t snap = arena_snapshot_create(*ctx.a);
for (idx_t i = ctx.ast.kids[blk].lhs; i <= ctx.ast.kids[blk].rhs;
i = fwdnode(ctx.ast, i))
{
- if (ctx.ast.kinds[i] == ASTCDECL && ctx.ast.kids[i].rhs != AST_EMPTY
+ if (ctx.ast.kinds[i] == ASTCDECL
&& ctx.ast.kinds[ctx.ast.kids[i].rhs] == ASTFN)
{
(void)codegendecl(ctx, i);
@@ -404,6 +427,7 @@ codegenfunc(struct cgctx ctx, idx_t i, strview_t sv)
if (ctx.ast.kids[proto].rhs == AST_EMPTY)
LLVMBuildRetVoid(ctx.bob);
+ *outv = ctx.func;
return i;
}
@@ -411,6 +435,7 @@ idx_t
codegendecl(struct cgctx ctx, idx_t i)
{
pair_t p = ctx.ast.kids[i];
+ strview_t sv = ctx.toks.strs[ctx.ast.lexemes[i]];
if (ctx.ast.kinds[i] == ASTCDECL) {
/* Constants are purely a compiler concept; they aren’t generated
@@ -421,7 +446,8 @@ codegendecl(struct cgctx ctx, idx_t i)
if (ctx.ast.kinds[p.rhs] != ASTFN || ctx.func != NULL)
return fwdnode(ctx.ast, i);
- return codegenfunc(ctx, p.rhs, ctx.toks.strs[ctx.ast.lexemes[i]]);
+ symval_t *sym = symtab_insert(&ctx.scps[ctx.scpi].map, sv, NULL);
+ return codegenfunc(ctx, p.rhs, ctx.toks.strs[ctx.ast.lexemes[i]], &sym->v);
}
assert(ctx.ast.kinds[i] == ASTDECL);
@@ -431,7 +457,6 @@ codegendecl(struct cgctx ctx, idx_t i)
return fwdnode(ctx.ast, i);
if (ctx.aux.buf[p.lhs].decl.isstatic) {
- strview_t sv = ctx.toks.strs[ctx.ast.lexemes[i]];
/* TODO: Namespace the name */
char *name = tmpalloc(ctx.s, sv.len + 1, 1);
LLVMTypeRef t = type2llvm(ctx, ctx.types[i]);
@@ -452,7 +477,6 @@ codegendecl(struct cgctx ctx, idx_t i)
/* Non-static, non-undef, mutable */
LLVMValueRef var, val;
- strview_t sv = ctx.toks.strs[ctx.ast.lexemes[i]];
var = symtab_insert(&ctx.scps[ctx.scpi].map, sv, NULL)->v;
if (p.rhs == AST_EMPTY) {
val = LLVMConstNull(type2llvm(ctx, ctx.types[i]));
diff --git a/src/parser.c b/src/parser.c
index 49067e2..6a4db5e 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -85,6 +85,12 @@ fwdnode(ast_t ast, idx_t i)
case ASTUNNEG:
i = ast.kids[i].rhs;
break;
+ case ASTCALLSTMT:
+ i = ast.kids[i + 1].lhs;
+ break;
+ case ASTFUNCALL:
+ i = ast.kids[i].lhs;
+ break;
case ASTIDENT:
case ASTNUMLIT:
case ASTTYPE:
@@ -279,6 +285,20 @@ parseexpratom(ast_t *ast, lexemes_t toks)
default:
err("parser: Invalid expression leaf");
}
+
+ if (toks.kinds[toksidx] == '(') {
+ toksidx++;
+ if (toks.kinds[toksidx++] != ')')
+ err("parser: Expected closing parenthesis");
+
+ idx_t j = astalloc(ast);
+ ast->kinds[j] = ast->kinds[i];
+ ast->kids[j] = ast->kids[i];
+ ast->lexemes[j] = ast->lexemes[i];
+ ast->kinds[i] = ASTFUNCALL;
+ ast->kids[i] = (pair_t){j, AST_EMPTY};
+ }
+
return i;
}
@@ -369,15 +389,22 @@ parsestmt(ast_t *ast, aux_t *aux, lexemes_t toks)
} else /* assignment */ {
idx_t lhs, rhs;
i = astalloc(ast);
- lhs = parseexpratom(ast, toks);
- if (toks.kinds[toksidx++] != LEXEQ)
- err("parser: Expected equals");
- rhs = parseexpr(ast, toks, 0);
- if (toks.kinds[toksidx++] != LEXSEMI)
- err("parser: Expected semicolon");
- ast->kinds[i] = ASTASIGN;
- ast->kids[i].lhs = lhs;
- ast->kids[i].rhs = rhs;
+ lhs = parseexpr(ast, toks, 0);
+
+ if (ast->kinds[lhs] != ASTFUNCALL || toks.kinds[toksidx + 1] == LEXEQ) {
+ if (toks.kinds[toksidx++] != LEXEQ)
+ err("parser: Expected equals");
+ rhs = parseexpr(ast, toks, 0);
+ if (toks.kinds[toksidx++] != LEXSEMI)
+ err("parser: Expected semicolon");
+ ast->kinds[i] = ASTASIGN;
+ ast->kids[i].lhs = lhs;
+ ast->kids[i].rhs = rhs;
+ } else {
+ if (toks.kinds[toksidx++] != LEXSEMI)
+ err("parser: Expected semicolon");
+ ast->kinds[i] = ASTCALLSTMT;
+ }
}
return i;
diff --git a/src/parser.h b/src/parser.h
index 31be1c8..5d5c53b 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -61,6 +61,14 @@ enum {
‘~rhs’ */
ASTUNCMPL,
+ /* Function call
+ ‘lhs(a, …)’; aux[rhs].funcall */
+ ASTFUNCALL,
+
+ /* A dummy node to deal with quirks of how the parser is setup. The
+ node directly after this is an ASTFUNCALL. */
+ ASTCALLSTMT,
+
/* NOTE: Ensure that the enumerations defined above this comment do
not exceed 37 — the value of ‘%’ — or they will conflict with the
definitions below. */