aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-17 07:38:48 +0200
committerlemon <lsof@mailbox.org>2022-08-17 07:38:48 +0200
commit585e51cac05cbb4fbc54ae3381bea4f41320ff5d (patch)
treebc456bc650f5828e6058131ece28e726509b9caa
parentc50a02ec703c7c1c5f6823c8cbd07a424d604792 (diff)
let
-rw-r--r--bootstrap/parse.c4
-rw-r--r--examples/hello-world.cff3
-rw-r--r--src/cffc.hff2
-rw-r--r--src/option.hff4
-rw-r--r--src/parse.cff81
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,
}});
}
)