aboutsummaryrefslogtreecommitdiff
path: root/src/parse.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.cff')
-rw-r--r--src/parse.cff187
1 files changed, 164 insertions, 23 deletions
diff --git a/src/parse.cff b/src/parse.cff
index 87ca850..b67cea9 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -1,6 +1,7 @@
import "mem.hff";
import "util.hff";
import "vec.hff";
+import "map.hff";
import "cffc.hff";
///////////
@@ -37,7 +38,7 @@ fn chrpeek(P *Parser) int {
if c == EOF {
P.eof = #t;
}
- P.peekchr = :Some c;
+ P.peekchr = :Some(c);
return c;
}
@@ -226,7 +227,7 @@ fn readnumber(s *const u8) Option<Tok> {
case else; return :None;
}
- return :Some tok;
+ return :Some(tok);
} else {
tok.t = :int;
tok.u.uint = acc;
@@ -272,7 +273,7 @@ fn readnumber(s *const u8) Option<Tok> {
case else; return :None;
}
- return :Some tok;
+ return :Some(tok);
}
}
@@ -504,7 +505,7 @@ fn lexpeek(P *Parser) Tok {
case Some t; return t;
}
let tok = lex(P);
- P.peektok = :Some tok;
+ P.peektok = :Some(tok);
return tok;
}
@@ -549,7 +550,10 @@ fn finddecl(P *Parser, name *const u8) *Decl {
}
fn putdecl(P *Parser, decl Decl) *Decl {
- assert(primenv != #null, "primenv");
+ if primenv == #null {
+ primenv = mkenv(#null, P.alloc);
+ putprimtypes(primenv);
+ }
if envfind(primenv, decl.name) {
fatal(P, decl.loc, "cannot shadow primitive `%s'", decl.name);
}
@@ -613,14 +617,14 @@ fn pexprimary(P *Parser) Expr {
case :int, :chr;
return { tok.loc, tok.ty, .u: :IntLit { tok.u.int }};
case :flo;
- return { tok.loc, tok.ty, .u: :FloLit tok.u.flo };
+ return { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) };
case :bool;
- return { tok.loc, ty_bool, .u: :BoolLit tok.u.bool };
+ return { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) };
case :null;
return { tok.loc, ty_voidptr, .u: :NullLit };
case :str;
let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8);
- return { tok.loc, ty, .u: :StrLit tok.u.str };
+ return { tok.loc, ty, .u: :StrLit(tok.u.str) };
case :ident;
let ident = tok.u.ident;
let decl = finddecl(P, ident);
@@ -629,11 +633,11 @@ fn pexprimary(P *Parser) Expr {
}
switch decl.u {
case Fn f;
- return { tok.loc, f.ty, .u: :Symbol decl };
+ return { tok.loc, f.ty, .u: :Symbol(decl) };
case Let var;
- return { tok.loc, var.ty, .u: :Symbol decl };
+ return { tok.loc, var.ty, .u: :Symbol(decl) };
case Static var;
- return { tok.loc, var.ty, .u: :Symbol decl };
+ return { tok.loc, var.ty, .u: :Symbol(decl) };
}
case '(';
let ex = parseexpr(P);
@@ -709,10 +713,11 @@ fn pexbitarith(P *Parser) Expr {
let rhs = pexprefix(P);
let ty = typeof2(ex.ty, rhs.ty);
switch {
- case ty == #null
- and (tokt == '+' or tokt == '-')
+ case ty == #null and tokt == '+'
and ((ex.ty->is(:Int) and rhs.ty->is(:Ptr)) or (rhs.ty->is(:Int) and ex.ty->is(:Ptr)));
ty = ex.ty->is(:Ptr) ? ex.ty : rhs.ty;
+ case ty == #null and tokt == '-' and rhs.ty->is(:Int) and ex.ty->is(:Ptr);
+ ty = ex.ty->is(:Ptr) ? ex.ty : rhs.ty;
case ty == #null;
fatal(P, tok.loc, "invalid operands %t and %t to binary operator %k", ex.ty, rhs.ty, tokt);
case tokt == '-' and ex.ty->is(:Ptr) and rhs.ty->is(:Ptr);
@@ -728,17 +733,94 @@ fn pexbitarith(P *Parser) Expr {
}
fn pexcmp(P *Parser) Expr {
+ fn matchcmpop(P *Parser, tokp *Tok) bool {
+ let tok = lexpeek(P);
+ if tokp {
+ *tokp = tok;
+ }
+ switch tok.t {
+ case '==', '<=', '>=', '<', '>', '!=';
+ lex(P);
+ return #t;
+ }
+ return #f;
+ }
+
let ex = pexbitarith(P);
+ let tok Tok = {};
+ if matchcmpop(P, &tok) {
+ let rhs = pexbitarith(P);
+ if typeof2(ex.ty, rhs.ty) == #null {
+ fatal(P, tok.loc, "incompatible operands %t and %t to binary operator %qT",
+ ex.ty, rhs.ty, tok);
+ }
+ if tok.t != '==' and tok.t != '!=' and !isnumtype(typeof2(ex.ty, rhs.ty)) {
+ fatal(P, tok.loc, "invalid non-numeric operands %t and %t to relational operator %qT",
+ ex.ty, rhs.ty, tok);
+ }
+ ex = {
+ tok.loc, ty_bool, .u: :BinOp {
+ tok.t, exprdup(P.alloc, ex), exprdup(P.alloc, rhs)
+ }
+ };
+ }
return ex;
}
fn pexlog(P *Parser) Expr {
let ex = pexcmp(P);
+ let tok Tok = lexpeek(P);
+ let tokt = lexpeek(P).t;
+ if tokt != :kw_and and tokt != :kw_or and tokt != '??' {
+ return ex;
+ }
+ while lexmatch(P, &tok, tokt) {
+ let rhs = pexcmp(P);
+ if tokt == '??' {
+ let ty = typeof2(ex.ty, rhs.ty);
+ if !ex.ty->is(:Ptr) or !rhs.ty->is(:Ptr) or ty == #null {
+ fatal(P, tok.loc, "invalid operands %t and %t to binary operator %k",
+ ex.ty, rhs.ty, tok.t);
+ }
+ ex = {
+ tok.loc, ty, .u: :BinOp { '??', exprdup(P.alloc, ex), exprdup(P.alloc, rhs) }
+ };
+ } else {
+ if !ex.ty->is(:Bool) or !rhs.ty->is(:Bool) {
+ fatal(P, tok.loc, "invalid operands %t and %t to binary operator %k",
+ ex.ty, rhs.ty, tok.t);
+ }
+ ex = {
+ tok.loc, ty_bool, .u: :BinOp {
+ tokt == :kw_and ? 'and' : 'or' , exprdup(P.alloc, ex), exprdup(P.alloc, rhs)
+ }
+ };
+ }
+ }
return ex;
}
fn pexcond(P *Parser) Expr {
+ let tok Tok = {};
let ex = pexlog(P);
+ if (lexmatch(P, &tok, '?')) {
+ 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, ':');
+ let ex3 = pexcond(P);
+ let ty = typeof2(ex2.ty, ex3.ty);
+ if ty == #null {
+ fatal(P, tok.loc, "conditional operator branches have incompatible types %t and %t",
+ ex2.ty, ex3.ty);
+ }
+ ex = {
+ tok.loc, ty, .u: :Cond {
+ exprdup(P.alloc, ex), exprdup(P.alloc, ex2), exprdup(P.alloc, ex3)
+ }
+ };
+ }
return ex;
}
@@ -804,7 +886,7 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
case else;
let ex = parseexpr(P);
lexexpect(P, ';');
- return yield({ tok.loc, .u: :Expr ex }, yarg);
+ return yield({ tok.loc, .u: :Expr(ex) }, yarg);
}
}
@@ -881,14 +963,57 @@ fn parsefn(P *Parser, decl *Decl, externp bool, name *const u8) void {
}});
}
)
- Fn.body = :Some parseblock(P);
+ Fn.body = :Some(parseblock(P));
P.curenv = envparent(env);
envfree(env);
(as(*Arena)P.alloc.a)->destroy();
);
}
-fn parsedecls(P *Parser, yield DeclYielder, yarg *void) void {
+fn doimport(P *Parser, path *const u8) [#]Decl {
+ struct Entry {
+ decls [#]Decl,
+ wip bool,
+ }
+ static seen Map<*const u8, Entry, struct {
+ fn hash(s *const u8) u32 { return fnv1a_s(FNV1A_INI, s); }
+ fn eq(a *const u8, b *const u8) bool { return streq(a, b); }
+ }> = {};
+
+ fn getbasedir(path *const u8) *const u8 {
+ static res [PATH_MAX]u8 = {};
+ let i isize #?;
+ for i = strlen(path); i > 0 and path[i] != '/'; --i { }
+ if i == 0 {
+ return ".";
+ }
+ memcpy(res, path, i);
+ res[i] = 0;
+ return res;
+ }
+ let basedir = getbasedir(P.curfile);
+ let path2 [PATH_MAX]u8 #?;
+ let _rpath [PATH_MAX]u8 #?;
+ snprintf(path2, sizeof(path2) - 1, "%s/%s", basedir, path);
+ let rpath *const u8 = realpath(path2, _rpath);
+ if rpath == #null {
+ fatal(P, P.tokloc, "import %qs: %s", path, strerror(c_errno()));
+ }
+ let d0 = seen->get(rpath);
+ if d0 != #null {
+ return d0.decls;
+ }
+ rpath = strcpy(malloc(strlen(rpath) + 1), rpath);
+ let P2 Parser #?;
+ parser_init(&P2, rpath);
+ P2.is_header = #t;
+ let e = seen->put(rpath, { {}, #t });
+ let decls = parse(&P2);
+ *e = { decls, #f };
+ return decls;
+}
+
+fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void {
let tok = Tok { .loc: P.tokloc },
decl = Decl {},
externp = #f,
@@ -896,6 +1021,9 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void) void {
if lexmatch(P, &tok, :kw_extern) {
externp = #t;
+ if (tok = lexpeek(P)).t != :kw_fn and tok.t != :kw_static {
+ err(P, tok.loc, "expected `fn' or `static' after `extern'");
+ }
}
switch {
@@ -904,26 +1032,39 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void) void {
parsefn(P, &decl, externp, name);
decl.loc = tok.loc;
decl.externp = externp;
+ case lexmatch(P, &tok, :kw_import);
+ let path = (tok = lexexpects(P, :str, "import path")).u.str.#ptr;
+ let decls = doimport(P, path);
+ foreach(decl, _, decls,
+ let decl = putdecl(P, decl);
+ if yield {
+ yield(decl, yarg);
+ }
+ )
+ lexexpect(P, ';');
+ return;
case else;
fatal(P, tok.loc, "expected declaration (near %qT)", tok);
}
-
- yield(putdecl(P, decl), yarg);
+
+ if yield {
+ yield(putdecl(P, decl), yarg);
+ }
}
extern fn parse(P *Parser) [#]Decl {
let aralloc = Arena {};
let alloc = Allocator { &aralloc, &Arena:allocf, #null };
- let decls Vec<*Decl> = {};
+ let decls Vec<Decl> = {};
P.alloc = &alloc;
P.curenv = mkenv(#null, P.alloc);
while !P.eof {
fn yield(decl *Decl, arg *void) void {
- let decls *Vec<*Decl> = arg;
- decls->push(decl);
+ let decls *Vec<Decl> = arg;
+ decls->push(*decl);
}
- parsedecls(P, &yield, &decls);
+ parsedecls(P, &yield, &decls, #{toplevel} #t);
if lexmatch(P, #null, :eof) {
break;
}
@@ -931,7 +1072,7 @@ extern fn parse(P *Parser) [#]Decl {
envfree(P.curenv);
aralloc->destroy();
- decls->clear();
+ return decls.dat[0::decls.len];
}
extern fn parser_init(P *Parser, path *const u8) void {