From c0895afd99c8befd0d89580bfaa71bb532ba9c7f Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Wed, 26 Jun 2024 23:50:37 +0200 Subject: Support unary plus and minus --- README | 20 +++++++++++++++++--- src/analyzer.c | 20 ++++++++++++++++++++ src/codegen.c | 24 +++++++++++++++++------- src/parser.c | 15 +++++++++++++++ src/parser.h | 10 +++++++++- 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 = '-', -- cgit v1.2.3