aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-06-26 23:50:37 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-06-26 23:53:08 +0200
commitc0895afd99c8befd0d89580bfaa71bb532ba9c7f (patch)
tree97ea69dccef8cf5e994c265f723ff9c5d6940ad8
parent101db2a43b1b3bb4c1c9c120cd5722f17a5f262d (diff)
Support unary plus and minus
-rw-r--r--README20
-rw-r--r--src/analyzer.c20
-rw-r--r--src/codegen.c24
-rw-r--r--src/parser.c15
-rw-r--r--src/parser.h10
5 files changed, 78 insertions, 11 deletions
diff --git a/README b/README
index a770ac8..8895385 100644
--- a/README
+++ b/README
@@ -117,7 +117,7 @@ The build script also accepts some subcommands. They are as follows:
different integer types which may have the same size (i.e. int and
int64)
- pub MyFunc :: () {
+ pub my_func :: () {
x: int = 69;
y: i64 = x; /* Compile-time error */
}
@@ -128,10 +128,24 @@ The build script also accepts some subcommands. They are as follows:
/* Recall that constants (including functions!) can be declared
in any order. This lets us define Inner *after* it gets
called by the assignment to ‘x’. */
- Outer :: () {
+ outer :: () {
x := Inner(5);
- Inner :: (x: int) int {
+ inner :: (x: int) int {
return x;
}
}
+
+8. No increment/decrement operators. The following functions both
+ return 42 as the return values are parsed as (+ (+ 42)) and
+ (- (- 42)) respectively.
+
+ x := 42;
+
+ returns_42 :: () int {
+ return ++x;
+ }
+
+ returns_42′ :: () int {
+ return --x;
+ }
diff --git a/src/analyzer.c b/src/analyzer.c
index 6e6df9d..c74e89f 100644
--- a/src/analyzer.c
+++ b/src/analyzer.c
@@ -309,6 +309,16 @@ analyzeexpr(struct azctx ctx, scope_t *scps, type_t *types, ast_t ast,
err("analyzer: Unknown symbol ‘%.*s’", SV_PRI_ARGS(sv));
}
+ case ASTUNNEG: {
+ idx_t ni, rhs;
+ rhs = ast.kids[i].rhs;
+ ni = analyzeexpr(ctx, scps, types, ast, aux, toks, rhs);
+ type_t t = types[rhs];
+ if (t.kind != TYPE_NUM || !t.issigned)
+ err("analyzer: Unary negation is reserved for signed numeric types");
+ types[i] = t;
+ return ni;
+ }
case ASTFN:
return analyzefn(ctx, scps, types, ast, aux, toks, i);
default:
@@ -476,6 +486,16 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
}
}
}
+ case ASTUNNEG: {
+ idx_t rhs = ast.kids[i].rhs;
+ idx_t ni = constfoldexpr(ctx, folds, scps, types, ast, toks, rhs);
+ mpq_t *x = folds + rhs;
+ if (MPQ_IS_INIT(*x)) {
+ MPQCPY(folds[i], *x);
+ mpq_neg(folds[i], folds[i]);
+ }
+ return ni;
+ }
case ASTFN:
return constfoldblk(ctx, folds, scps, types, ast, toks,
ast.kids[i].rhs);
diff --git a/src/codegen.c b/src/codegen.c
index a9b1430..9e9e329 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -211,13 +211,23 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv)
return fwdnode(ctx.ast, i);
}
- assert(ctx.ast.kinds[i] == ASTIDENT);
-
- strview_t sv = ctx.toks.strs[ctx.ast.lexemes[i]];
- LLVMTypeRef t = type2llvm(ctx, ctx.types[i]);
- LLVMValueRef ptrval = symtab_insert(&ctx.scps[ctx.scpi].map, sv, NULL)->v;
- *outv = LLVMBuildLoad2(ctx.bob, t, ptrval, "loadtmp");
- return fwdnode(ctx.ast, i);
+ switch (ctx.ast.kinds[i]) {
+ case ASTIDENT: {
+ strview_t sv = ctx.toks.strs[ctx.ast.lexemes[i]];
+ LLVMTypeRef t = type2llvm(ctx, ctx.types[i]);
+ LLVMValueRef ptrval = symtab_insert(&ctx.scps[ctx.scpi].map, sv, NULL)->v;
+ *outv = LLVMBuildLoad2(ctx.bob, t, ptrval, "loadtmp");
+ return fwdnode(ctx.ast, i);
+ }
+ case ASTUNNEG: {
+ LLVMValueRef v;
+ idx_t ni = codegentypedexpr(ctx, ctx.ast.kids[i].rhs, ctx.types[i], &v);
+ *outv = LLVMBuildNeg(ctx.bob, v, "negtmp");
+ return ni;
+ }
+ default:
+ __builtin_unreachable();
+ }
}
idx_t
diff --git a/src/parser.c b/src/parser.c
index fa1c720..cb8aa8f 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -61,6 +61,7 @@ fwdnode(ast_t ast, idx_t i)
case ASTBINSUB:
case ASTCDECL:
case ASTFN:
+ case ASTUNNEG:
i = ast.kids[i].rhs;
break;
case ASTIDENT:
@@ -219,6 +220,13 @@ parseexpr(ast_t *ast, aux_t *aux, lexemes_t toks)
{
(void)aux;
idx_t i = astalloc(ast);
+
+ /* Unary plus is kind of a fake syntactic construct. We just pretend
+ like it doesn’t exist, but allow it in the syntax to be consistent
+ with unary negation. */
+ while (toks.kinds[toksidx] == LEXPLUS)
+ toksidx++;
+
ast->lexemes[i] = toksidx;
switch (toks.kinds[toksidx]) {
@@ -230,6 +238,13 @@ parseexpr(ast_t *ast, aux_t *aux, lexemes_t toks)
toksidx++;
ast->kinds[i] = ASTIDENT;
break;
+ case LEXMINUS: {
+ toksidx++;
+ ast->kinds[i] = ASTUNNEG;
+ idx_t rhs = parseexpr(ast, aux, toks);
+ ast->kids[i].rhs = rhs;
+ break;
+ }
default:
err("parser: Expected expression");
}
diff --git a/src/parser.h b/src/parser.h
index d8991c0..055350a 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -50,11 +50,19 @@ enum {
‘return rhs’ */
ASTRET,
+ /* Unary negation
+ ‘-rhs’ */
+ ASTUNNEG,
+
+ /* NOTE: Ensure that the enumerations defined above this comment do
+ not exceed 37 — the value of ‘%’ — or they will conflict with the
+ definitions below. */
+
/* Binary add
‘lhs + rhs’ */
ASTBINADD = '+',
- /* Binary sub
+ /* Binary subtraction
‘lhs - rhs’ */
ASTBINSUB = '-',