aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cffc.hff2
-rw-r--r--src/option.hff4
-rw-r--r--src/parse.cff81
3 files changed, 82 insertions, 5 deletions
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,
}});
}
)