aboutsummaryrefslogtreecommitdiff
path: root/src/parse.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.cff')
-rw-r--r--src/parse.cff226
1 files changed, 154 insertions, 72 deletions
diff --git a/src/parse.cff b/src/parse.cff
index 760c0f9..e731d47 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -81,7 +81,7 @@ fn issep(c u8) bool {
case '(', ')', '[', ']', '{', '}', '.', ',',
';', '?', '+', '-', '*', '/', '&', '|',
'^', '~', '=', '\'', '"', '<', '>', ':',
- '@', '#', '\\', '`';
+ '@', '#', '\\', '`', '%', '!';
return #t;
}
return #f;
@@ -100,7 +100,7 @@ fn ishsep(c u8) bool {
}
fn readtilsep(P *Parser, buf [#]u8, dot bool) int {
- let i = 0,
+ let i = 0z,
c u8 #?;
while (!issep(c = chrpeek(P))) or (dot and c == '.') {
chr(P);
@@ -114,7 +114,7 @@ fn readtilsep(P *Parser, buf [#]u8, dot bool) int {
}
fn readtilhsep(P *Parser, buf [#]u8, dot bool) int {
- let i = 0,
+ let i = 0z,
c u8 #?,
pred = &ishsep;
while (!pred(c = chrpeek(P))) or (dot and c == '.') {
@@ -151,8 +151,8 @@ extern static keyword2str [NUM_KEYWORDS]*const u8 = {
};
fn str2keyword(s *const u8) int {
- let i = 0zs,
- j = keyword2str.#len - 1;
+ let i isize = 0,
+ j isize = keyword2str.#len - 1;
while i <= j {
let k = (j + i) / 2;
let cmp = strcmp(keyword2str[k], s);
@@ -452,7 +452,9 @@ fn lex(P *Parser) Tok {
if delim == '"' {
tok.t = :str;
+ str->push('\0');
tok.u.str = str->move(P.alloc);
+ tok.u.str = tok.u.str[0::tok.u.str.#len - 1];
} else {
tok.t = :chr;
if str.len == 0 {
@@ -627,6 +629,18 @@ fn putdecl(P *Parser, eloc Loc, decl Decl) *Decl {
return d;
}
+fn putdecl_alloc(P *Parser, alloc *Allocator, eloc Loc, decl Decl) *Decl {
+ if envfind(primenv, decl.name) {
+ fatal(P, eloc, "cannot shadow primitive `%s'", decl.name);
+ }
+ let d0 *const Decl;
+ let d = envput_alloc(P.curenv, alloc, decl, &d0);
+ if d == #null {
+ fatal(P, eloc, "attempt to redefine `%s' (previously defined at %l)", decl.name, d0.loc);
+ }
+ return d;
+}
+
///////////////////
// Types Parsing //
///////////////////
@@ -669,8 +683,8 @@ fn parseenum(P *Parser, name *const u8, lax bool) *const Type {
}
}
let intty *const Type = intty ?? (
- max < 1u64 << ((g_targ.intsize * 8) - 1) ? ty_int
- : max < 1u64 << 31 ? ty_i32
+ max < 1i64 << ((g_targ.intsize * 8) - 1) ? ty_int
+ : max < 1i64 << 31 ? ty_i32
: ty_i64);
static id int = 0;
return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }});
@@ -716,10 +730,10 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c
if !lexmatch(P, &tok, ';') {
agg.fwd = #f;
lexexpect(P, '{');
- let size = 0, align = 1;
+ let size = 0z, align = 1z;
let flds Vec<AggField> = {};
let havedecls = #f;
- let f0align = -1i64;
+ let f0align = -1zs;
while !lexmatch(P, &tok, '}') {
if isdecltokt(lexpeek(P).t) {
havedecls = #t;
@@ -895,7 +909,7 @@ fn parseexpandtepl(P *Parser, tepl *Tepl) *const Type {
#'search
for cache = tepl.cache; cache; cache = cache.next {
- for let i = 0; i < nparam; ++i {
+ for let i = 0z; i < nparam; ++i {
let arg = &tpargs[i];
switch cache.args[i] {
case Ty ty;
@@ -1102,7 +1116,7 @@ fn parseaggini(P *Parser, loc Loc, ty *const Type) Expr {
let tok Tok #?;
let flds Vec<*const AggField> = {};
let exs Vec<Expr> = {};
- let iota = 0;
+ let iota = 0u64;
while !lexmatch(P, &tok, '}') {
let fld *AggField #?;
let ex Expr #?;
@@ -1299,49 +1313,32 @@ fn parseexpandmacro(P *Parser, loc Loc, mac *Macro) void {
}
-fn parseblock0(P *Parser) [#]Stmt;
+fn parseblock0(P *Parser) Block;
fn pexprimary(P *Parser) Expr {
let tok Tok = lex(P);
let ex Expr #?;
- switch tok.t {
- case :int, :chr;
- ex = { tok.loc, tok.ty, .u: :IntLit { tok.u.int }};
-
- case :flo;
- ex = { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) };
- case :bool;
- ex = { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) };
-
- case :null;
- ex = { tok.loc, ty_voidptr, .u: :NullLit };
-
- case :str;
- let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8);
- ex = { tok.loc, ty, .u: :StrLit(tok.u.str) };
-
- case :ident;
- let ident = tok.u.ident;
- let decl = finddecl(P, ident);
- let fakedecl Decl = {};
+ let fakedecl Decl #?;
+ fn resolvedecl(P *Parser, tok Tok, decl *Decl, ex *Expr) void {
+ let fakedecl Decl #?;
if decl == #null {
fatal(P, tok.loc, "%qT is not defined", tok);
}
while #t {
switch decl.u {
case Fn f;
- ex = { tok.loc, f.ty, .u: :Symbol(decl) };
+ *ex = { tok.loc, f.ty, .u: :Symbol(decl) };
case Let var;
- ex = { tok.loc, var.ty, .u: :Symbol(decl) };
+ *ex = { tok.loc, var.ty, .u: :Symbol(decl) };
case Static var;
- ex = { tok.loc, var.ty, .u: :Symbol(decl) };
+ *ex = { tok.loc, var.ty, .u: :Symbol(decl) };
case Def dex;
dex.loc = tok.loc;
- ex = dex;
+ *ex = dex;
case Macro *mac;
parseexpandmacro(P, tok.loc, mac);
- ex = parseexpr(P);
+ *ex = parseexpr(P);
case Ty ty;
if (tok = lexpeek(P)).t != ':' and tok.t != '{' {
lexexpects(P, ':', "`:' or `{' after type name");
@@ -1356,9 +1353,10 @@ fn pexprimary(P *Parser) Expr {
continue;
} else if !ty->is(:Agg) and !ty->is(:Enum) {
fatal(P, tok.loc, "type is not aggregate or enum");
- } else {
+ } else {;
P.targty = ty;
- return parseexpr(P);
+ *ex = parseexpr(P);
+ return;
}
case Tepl *tepl;
fakedecl = { .u: :Ty(parseexpandtepl(P, tepl)) };
@@ -1367,6 +1365,34 @@ fn pexprimary(P *Parser) Expr {
}
break;
}
+ }
+
+ switch tok.t {
+ case :int, :chr;
+ ex = { tok.loc, tok.ty, .u: :IntLit { tok.u.int }};
+
+ case :flo;
+ ex = { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) };
+
+ case :bool;
+ ex = { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) };
+
+ case :null;
+ ex = { tok.loc, ty_voidptr, .u: :NullLit };
+
+ case :str;
+ let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8);
+ ex = { tok.loc, ty, .u: :StrLit(tok.u.str) };
+
+ case :ident;
+ let ident = tok.u.ident;
+ let decl = finddecl(P, ident);
+ resolvedecl(P, tok, decl, &ex);
+
+ case :typearg;
+ fakedecl = { .u: :Ty(tok.ty) };
+ resolvedecl(P, tok, &fakedecl, &ex);
+
case :kw_sizeof;
let ty *const Type #?;
if lexmatch(P, &tok, '(') {
@@ -1418,7 +1444,8 @@ fn pexprimary(P *Parser) Expr {
case '(';
if lexmatch(P, &tok, :kw_do) {
- let st = parseblock0(P);
+ let block = parseblock0(P);
+ let st = block.sts;
lexexpect(P, ')');
if st.#len == 0 or st[st.#len - 1].u.#tag != :Expr {
ex = { tok.loc, ty_void, :Stmt(st) };
@@ -1840,7 +1867,11 @@ fn pexcmp(P *Parser) Expr {
fatal(P, tok.loc, "invalid non-numeric operands %t and %t to relational operator %qT",
ex.ty, rhs.ty, tok);
}
- if ty->is(:Int) and ty != ty_int and ex.ty.u.Int.sgn != rhs.ty.u.Int.sgn {
+ fn ispositiveintlit(ex Expr) bool {
+ return ex.u.#tag == :IntLit and ex.u.IntLit.i >- 0;
+ }
+ if ty->is(:Int) and ty != ty_int and ex.ty.u.Int.sgn != rhs.ty.u.Int.sgn
+ and !(ispositiveintlit(ex) or ispositiveintlit(rhs)) {
warn(P, tok.loc, "comparing integers of different signedness (%t and %t)", ex.ty, rhs.ty);
}
}
@@ -1889,13 +1920,16 @@ fn pexlog(P *Parser) Expr {
fn pexcond(P *Parser) Expr {
let tok Tok = {};
+ let targty = P.targty;
let ex = pexlog(P);
if (lexmatch(P, &tok, '?')) {
+ P.targty = targty;
let ex2 = parseexpr(P);
if !ex.ty->is(:Bool) and !ex.ty->is(:Ptr) {
fatal(P, ex.loc, "invalid test operand to conditional operator (%t)", ex.ty);
}
lexexpect(P, ':');
+ P.targty = targty;
let ex3 = pexcond(P);
let ty = typeof2(ex2.ty, ex3.ty);
if ty == #null {
@@ -1971,7 +2005,7 @@ fn stmtdup(alloc *Allocator, st Stmt) *Stmt {
}
typedef StmtYielder *fn(Stmt, *void) void;
-fn parseblock(P *Parser) [#]Stmt;
+fn parseblock(P *Parser) Block;
fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, DeclYielder, *void) void;
fn pstlet(P *Parser, yield StmtYielder, yarg *void) void {
@@ -1998,7 +2032,7 @@ fn pstif(P *Parser, loc Loc) Stmt {
if lexmatch(P, &tok, :kw_else) {
if lexmatch(P, &tok, :kw_if) {
let f = stmtdup(P.alloc, pstif(P, tok.loc));
- return { loc, :If { test, t, f[0::1] }};
+ return { loc, :If { test, t, { f[0::1] } }};
} else {
lexexpect(P, '{');
let f = parseblock(P);
@@ -2008,7 +2042,7 @@ fn pstif(P *Parser, loc Loc) Stmt {
return { loc, :If { test, t }};
}
-fn pstreturn(P *Parser, loc Loc) Stmt {
+fn pstreturn(P *Parser, loc Loc, deferage int) Stmt {
if P.curfn == #null {
fatal(P, loc, "return outside function");
}
@@ -2017,7 +2051,7 @@ fn pstreturn(P *Parser, loc Loc) Stmt {
if retty != ty_void {
err(P, loc, "return with no value in function returning %t", retty);
}
- return { loc, :Return{} };
+ return { loc, :Return{ :None, deferage} };
} else {
P.targty = retty;
let ex = parseexpr(P);
@@ -2026,7 +2060,7 @@ fn pstreturn(P *Parser, loc Loc) Stmt {
err(P, ex.loc, "incompatible type in return statement (%t, expected %t)",
ex.ty, retty);
}
- return { loc, :Return(:Some(ex)) };
+ return { loc, :Return{:Some(ex), deferage} };
}
}
@@ -2036,7 +2070,7 @@ fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt {
err(P, test.loc, "while condition must be bool or pointer (%t)", test.ty);
}
lexexpect(P, '{');
- let body [#]Stmt #?;
+ let body Block #?;
with_tmpchange(P.curloop, ++P.loopid) {
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
@@ -2050,8 +2084,29 @@ fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt {
return { loc, :While { test, body, P.loopid }};
}
+fn pstdowhile(P *Parser, loc Loc, label *const u8) Stmt {
+ lexexpect(P, '{');
+ let body Block #?;
+ with_tmpchange(P.curloop, ++P.loopid) {
+ let env = mkenv(P.curenv, P.alloc);
+ defer envfree(env);
+ pushenv(P, env);
+ if label {
+ putdecl(P, loc, { label, loc, .u: :Label(P.loopid) });
+ }
+ body = parseblock(P);
+ popenv(P);
+ }
+ lexexpect(P, :kw_while);
+ let test = parseexpr(P);
+ if !test.ty->is(:Bool) and !test.ty->is(:Ptr) {
+ err(P, test.loc, "do-while condition must be bool or pointer (%t)", test.ty);
+ }
+ return { loc, :DoWhile { test, body, P.loopid }};
+}
+
fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
- let ini [#]Stmt = {};
+ let ini Block = {};
let test Expr #?;
let next = Option<Expr>:None;
let tok Tok #?;
@@ -2062,12 +2117,12 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
sts->push(st);
}
pstlet(P, &yieldlet, &sts);
- ini = sts->move(P.alloc);
+ ini = { sts->move(P.alloc) };
} else if lexmatch(P, #null, ';') {
// pass
} else {
let ex = parseexpr(P);
- ini = stmtdup(P.alloc, { ex.loc, :Expr(ex) })[0::1];
+ ini = { stmtdup(P.alloc, { ex.loc, :Expr(ex) })[0::1] };
lexexpect(P, ';');
}
@@ -2085,7 +2140,7 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
next = :Some(parseexpr(P));
lexexpect(P, '{');
}
- let body [#]Stmt #?;
+ let body Block #?;
let id = ++P.loopid;
with_tmpchange(P.curloop, id) {
let env = mkenv(P.curenv, P.alloc);
@@ -2103,7 +2158,7 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt {
let tok Tok #?;
let cs Vec<ISwitchCase> = {};
- let f [#]Stmt = {};
+ let f Block = {};
let elsep = #f;
while !lexmatch(P, &tok, '}') {
lexexpect(P, :kw_case);
@@ -2140,7 +2195,7 @@ fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt {
fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt {
let cs Vec<EUSwitchCase> = {};
let tok Tok #?;
- let f [#]Stmt = {};
+ let f Block = {};
let elsep = #f;
while !lexmatch(P, &tok, '}') {
@@ -2196,7 +2251,7 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt {
fn pstcswitch(P *Parser, loc Loc) Stmt {
let cs Vec<CSwitchCase> = {};
let tok Tok #?;
- let f [#]Stmt = {};
+ let f Block = {};
let elsep = #f;
while !lexmatch(P, &tok, '}') {
@@ -2237,6 +2292,7 @@ fn pstswitch(P *Parser, loc Loc) Stmt {
}
fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
+ static deferage int = {};
let tok Tok = {};
switch {
case lexmatch(P, &tok, '{');
@@ -2251,7 +2307,7 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
return yield(pstif(P, tok.loc), yarg);
case lexmatch(P, &tok, :kw_return);
- return yield(pstreturn(P, tok.loc), yarg);
+ return yield(pstreturn(P, tok.loc, deferage), yarg);
case lexmatch(P, &tok, :label);
let label = tok.u.ident;
@@ -2260,6 +2316,8 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
return yield(pstwhile(P, tok.loc, label), yarg);
case lexmatch(P, &tok, :kw_for);
return yield(pstfor(P, tok.loc, label), yarg);
+ case lexmatch(P, &tok, :kw_do);
+ return yield(pstdowhile(P, tok.loc, label), yarg);
case else
fatal(P, tok.loc, "label can only precede looping statement");
}
@@ -2270,6 +2328,10 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
case lexmatch(P, &tok, :kw_for);
return yield(pstfor(P, tok.loc, #null), yarg);
+ case lexmatch(P, &tok, :kw_do);
+ return yield(pstdowhile(P, tok.loc, #null), yarg);
+
+
case lexmatch(P, &tok, :kw_break) or lexmatch(P, &tok, :kw_continue);
if P.curloop == 0 {
err(P, tok.loc, "%s outside loop", tok.t == :kw_break ? "break" : "continue");
@@ -2287,6 +2349,20 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
lexexpect(P, ';');
return yield({ tok.loc, tok.t == :kw_break ? :Break(loop) : :Continue(loop) }, yarg);
+ case lexmatch(P, &tok, :kw_defer);
+ if P.curblock == #null {
+ fatal(P, tok.loc, "defer outside function");
+ }
+ let ex = parseexpr(P);
+ lexexpect(P, ';');
+ let defr *Defers = anew(P.alloc, Defers);
+ defr.age = deferage++;
+ defr.ex = ex;
+ defr.blockid = P.curblock.id;
+ defr.next = P.curblock.defers;
+ P.curblock.defers = defr;
+ return;
+
case lexmatch(P, &tok, :kw_switch);
return yield(pstswitch(P, tok.loc), yarg);
@@ -2317,25 +2393,30 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
}
}
-fn parseblock0(P *Parser) [#]Stmt {
+fn parseblock0(P *Parser) Block {
+ static id int = 1;
+ let block Block = { .id: id++, .defers: P.curblock ? P.curblock.defers : #null };
let sts Vec<Stmt> = {};
let tok Tok = {};
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
pushenv(P, env);
- while (tok = lexpeek(P)).t != '}' and tok.t != :kw_case and tok.t != ')' {
- if lexmatch(P, #null, ';') { continue; }
- fn pushstmt(st Stmt, arg *void) void {
- let sts *Vec<Stmt> = arg;
- sts->push(st);
+ with_tmpchange(P.curblock, &block) {
+ while (tok = lexpeek(P)).t != '}' and tok.t != :kw_case and tok.t != ')' {
+ if lexmatch(P, #null, ';') { continue; }
+ fn pushstmt(st Stmt, arg *void) void {
+ let sts *Vec<Stmt> = arg;
+ sts->push(st);
+ }
+ parsestmts(P, &pushstmt, &sts);
}
- parsestmts(P, &pushstmt, &sts);
}
popenv(P);
- return sts->move(P.alloc);
+ block.sts = sts->move(P.alloc);
+ return block;
}
-fn parseblock(P *Parser) [#]Stmt {
+fn parseblock(P *Parser) Block {
let b = parseblock0(P);
lexexpect(P, '}');
return b;
@@ -2429,7 +2510,8 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
}});
static id int = 0;
Fn.id = ++id;
- let decl = putdecl(P, loc, decl);
+ // TODO tlalloc necessary for templates. but it leaks some memory
+ let decl = putdecl_alloc(P, P.tlalloc, loc, decl);
decl.toplevel = toplevel;
if !lexmatch(P, #null, '{') {
@@ -2443,7 +2525,6 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
let varid = P.varid, loopid = P.loopid;
P.varid = 0;
P.loopid = 0;
- with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }) {
with_tmpchange(P.curfn, Fn) {
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
@@ -2455,12 +2536,13 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
}});
}
}
- Fn.body = :Some(parseblock(P));
- popenv(P);
- // ir_genfn(P.irctx, Fn);
- llvm_genfn(externp, name, Fn);
- (as(*Arena)P.alloc.a)->destroy();
- }
+ with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }) {
+ Fn.body = :Some(parseblock(P));
+ popenv(P);
+ // ir_genfn(P.irctx, Fn);
+ llvm_genfn(externp, name, Fn);
+ (as(*Arena)P.alloc.a)->destroy();
+ }
}
if toplevel {
llvm_addfn(decl);