diff options
| author | 2022-08-17 07:38:48 +0200 | |
|---|---|---|
| committer | 2022-08-17 07:38:48 +0200 | |
| commit | 585e51cac05cbb4fbc54ae3381bea4f41320ff5d (patch) | |
| tree | bc456bc650f5828e6058131ece28e726509b9caa | |
| parent | c50a02ec703c7c1c5f6823c8cbd07a424d604792 (diff) | |
let
| -rw-r--r-- | bootstrap/parse.c | 4 | ||||
| -rw-r--r-- | examples/hello-world.cff | 3 | ||||
| -rw-r--r-- | src/cffc.hff | 2 | ||||
| -rw-r--r-- | src/option.hff | 4 | ||||
| -rw-r--r-- | src/parse.cff | 81 |
5 files changed, 87 insertions, 7 deletions
diff --git a/bootstrap/parse.c b/bootstrap/parse.c index c76445f..efcf0b2 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -875,7 +875,7 @@ islvalue(const struct expr *ex) { return 1; if (ex->t == Eprefix && ex->unop.op == '*') return 1; - if (ex->t == Eindex || ex->t == Eget) + if (ex->t == Eindex || ex->t == Eget || ex->t == Eeutag) return 1; if (ex->t == Eini) return 1; @@ -1444,7 +1444,7 @@ pexpostfix(struct parser *P) { if ((exptr = ty->t == TYptr)) ty = ty->child; - if (ty->t == TYstruct || ty->t == TYunion) { + if (ty->t == TYstruct || ty->t == TYunion || ty->t == TYeunion) { struct decl *decl = findaggdecl(unconstify(ty), fnam); if (!decl) fatal(P, tok.span, "%t has no such method `%s'", ty, fnam); diff --git a/examples/hello-world.cff b/examples/hello-world.cff index a976450..29a1c03 100644 --- a/examples/hello-world.cff +++ b/examples/hello-world.cff @@ -2,6 +2,9 @@ extern fn printf(fmt *const u8, ...) int; extern fn cos(x f32) f32; extern fn main(argc int, argv *const *const u8) int { + let x = argv, + z = 3; + let foo = x + z; printf("hello world\n"); } diff --git a/src/cffc.hff b/src/cffc.hff index ff9d3eb..bc49f29 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -133,6 +133,7 @@ struct Stmt { u enum union { Block [#]Stmt, Expr Expr, + Decl *Decl, } } @@ -147,6 +148,7 @@ struct Fn { struct Var { ty *const Type, ini Option<Expr>, + fwd bool, fnid int, } diff --git a/src/option.hff b/src/option.hff index ef32725..f0eddfc 100644 --- a/src/option.hff +++ b/src/option.hff @@ -1,4 +1,8 @@ enum union Option<T> { None, Some T, + + fn empty(self Option) bool { + return self.#tag == :None; + } } diff --git a/src/parse.cff b/src/parse.cff index 0479b0a..db161d7 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -302,7 +302,7 @@ fn lex(P *Parser) Tok { return tok; } } - if isalpha(c) or c == '_' or c == '$' { + if isalpha(c) or c == '_' or c == '$' or c > 0x7F { let s [120]u8; if readtilsep(P, s[0::], #f) < 0 { fatal(P, tok.loc, "identifier too long"); @@ -595,6 +595,18 @@ fn parsetype(P *Parser) *const Type { // Expressions Parsing // ///////////////////////// +fn typematchestarg(targ *const Type, ty *const Type) bool { + if typeof2(targ, ty) == #null { + return #f; + } + if targ->is(:Ptr) or ty->is(:Ptr) { + if !targ.u.Ptr.konst and ty.u.Ptr.konst { + return #f; + } + } + return #t; +} + fn exprdup(alloc *Allocator, ex Expr) *Expr { return memcpy(alloc->alloc(sizeof(ex)), &ex, sizeof(ex)); } @@ -988,17 +1000,31 @@ fn parseexpr(P *Parser) Expr { typedef DeclYielder *fn(*Decl, *void) void; typedef StmtYielder *fn(Stmt, *void) void; - fn parseblock(P *Parser) [#]Stmt; +fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, DeclYielder, *void) void; + +fn pstlet(P *Parser, yield StmtYielder, yarg *void) void { + struct Arg { + P *Parser, + yield StmtYielder, + yarg *void, + } + fn varyield(decl *Decl, arg *void) void { + let a *Arg = arg; + a.yield({ decl.loc, :Decl(decl) }, a.yarg); + } + parsevardecl(P, #{toplevel?} #f, #{extern?} #f, #{let?} #t, &varyield, &Arg { P, yield, yarg }); +} + fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { let tok Tok = {}; switch { case lexmatch(P, &tok, '{'); - yield({ + return yield({ tok.loc, .u: :Block(parseblock(P)) }, yarg); case lexmatch(P, &tok, :kw_let); - // pstlet(P, yield, yarg); + return pstlet(P, yield, yarg); case else; let ex = parseexpr(P); lexexpect(P, ';'); @@ -1030,6 +1056,51 @@ fn parseblock(P *Parser) [#]Stmt { // Decls Parsing // /////////////////// +fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYielder, yarg *void) void { + let tok Tok #?; + do { + let konst = lexmatch(P, #null, :kw_const), + tok = lexexpect(P, :ident), + name = tok.u.ident, + ini Option<Expr> #?, + ty *const Type = #null, + fwd = #f; + + if lexmatch(P, #null, '=') { + ini = :Some(parseexpr(P)); + ty = unconstify(ini.Some.ty); + } else { + ty = parsetype(P); + + if lexmatch(P, #null, '=') { + ini = :Some(parseexpr(P)); + } else if lexmatch(P, #null, '#?') { + ini = :None; + } else { + fwd = #t; + } + } + + if !ini->empty() and !typematchestarg(ty, ini.Some.ty) { + err(P, ini.Some.loc, "incompatible initializer (%t, expected %t)", ini.Some.ty, ty); + } + if konst { + ty = constify(ty); + } + + let decl Decl = { name, tok.loc, externp, :Let { ty, ini, fwd, 0 } }; + if !letp { + decl.u.#tag = :Static; + } + yield(putdecl(P, decl), yarg); + + if !lexmatch(P, &tok, ',') { + lexexpects(P, ';', "`,' or `;'"); + break; + } + } while !lexmatch(P, &tok, ';'); +} + fn parsefn(P *Parser, decl *Decl, externp bool, name *const u8) void { decl.name = name; decl.u = :Fn {}; @@ -1075,7 +1146,7 @@ fn parsefn(P *Parser, decl *Decl, externp bool, name *const u8) void { foreach(name, i, Fn.paramnames, if name { putdecl(P, { name, tok.loc, .u: :Let { - Fn.ty.u.Fn.params[i], :None, Fn.id, + Fn.ty.u.Fn.params[i], :None, #f, Fn.id, }}); } ) |