diff options
| author | 2022-08-16 09:19:33 +0200 | |
|---|---|---|
| committer | 2022-08-16 09:19:33 +0200 | |
| commit | 1ca77f60626666fba792db407dd11ea9b597d9cf (patch) | |
| tree | 0e5ea52e457474899ad5f0076bbe658e67626925 /src/parse.cff | |
| parent | 04c7892134d49f3b295a51cc741affe9f02e374d (diff) | |
binary operators and more stuff
Diffstat (limited to 'src/parse.cff')
| -rw-r--r-- | src/parse.cff | 187 |
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 { |