Files
ww/lib/ww/parse/decl.ww

162 lines
4.4 KiB
Plaintext

// lib/ww/parse/decl.ww — declaration parsing, split out of parse.ww.
use os;
use mem;
use tok;
fn parseuse(p: *parser) *node = {
let pf: str = p.curfile;
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
advance(p); // past `use`
let n: *node = newnode(p.a, nkind.N_USE, pf, pl, pc);
let id: str;
expectident(p, &id);
n.str = id;
expecttok(p, tkind.TK_SEMI, "expected ';' after use");
return n;
};
fn parsedef(p: *parser, exported: i32) *node = {
let pf: str = p.curfile;
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
advance(p); // past `def`
let n: *node = newnode(p.a, nkind.N_DEF, pf, pl, pc);
n.module = p.l.module;
let id: str;
expectident(p, &id);
n.str = id;
expecttok(p, tkind.TK_COLON, "expected ':' in def");
n.lhs = parsetype(p);
expecttok(p, tkind.TK_ASSIGN, "expected '=' in def");
n.rhs = parseexpr(p);
expecttok(p, tkind.TK_SEMI, "expected ';' after def");
n.exported = exported;
return n;
};
fn parselet(p: *parser, exported: i32) *node = {
let pf: str = p.curfile;
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
// Accept `let` or `const`. Const-bound bindings are marked via
// n.op = tkind.TK_CONST so the checker can reject reassignment.
let is_const: i32 = 0;
if (p.curkind == tkind.TK_CONST) { is_const = 1; };
advance(p);
let n: *node = newnode(p.a, nkind.N_LET, pf, pl, pc);
n.module = p.l.module;
let id: str;
expectbindname(p, &id);
n.str = id;
if (accepttok(p, tkind.TK_COLON)) {
n.lhs = parsetype(p);
};
if (accepttok(p, tkind.TK_ASSIGN)) {
n.rhs = parseexpr(p);
};
expecttok(p, tkind.TK_SEMI, "expected ';' after let");
n.exported = exported;
if (is_const != 0) { n.op = tkind.TK_CONST; };
return n;
};
fn parseattrs(p: *parser) *node = {
let head: *node = nil;
let tail: *node = nil;
for (p.curkind == tkind.TK_AT) {
let pf: str = p.curfile;
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
advance(p);
let a: *node = newnode(p.a, nkind.N_ATTR, pf, pl, pc);
let id: str;
expectident(p, &id);
a.str = id;
// `@name(args...)` for FFI-style attrs; `@name` for marker-
// only attrs like @test (no parens).
if (accepttok(p, tkind.TK_LPAREN)) {
let arghead: *node = nil;
parsearglist(p, tkind.TK_RPAREN, &arghead);
a.list = arghead;
expecttok(p, tkind.TK_RPAREN, "expected ')' after attribute args");
};
if (head == nil) { head = a; tail = a; }
else { tail.next = a; tail = a; };
};
return head;
};
fn parseparams(p: *parser) *node = {
if (p.curkind == tkind.TK_RPAREN) { return nil; };
let head: *node = nil;
let tail: *node = nil;
for (true) {
let pf: str = p.curfile;
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
let n: *node = newnode(p.a, nkind.N_PARAM, pf, pl, pc);
// Param form: (IDENT|'_') ':' type. Anonymous-type-only params
// (used in fn type expressions) aren't yet wired here.
let id: str;
expectbindname(p, &id);
n.str = id;
expecttok(p, tkind.TK_COLON, "expected ':' in parameter");
n.lhs = parsetype(p);
if (head == nil) { head = n; tail = n; }
else { tail.next = n; tail = n; };
if (!accepttok(p, tkind.TK_COMMA)) { break; };
if (p.curkind == tkind.TK_RPAREN) { break; };
};
return head;
};
fn parsefn(p: *parser, exported: i32, attrs: *node) *node = {
let pf: str = p.curfile;
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
advance(p); // past `fn`
let n: *node = newnode(p.a, nkind.N_FNDECL, pf, pl, pc);
n.module = p.l.module;
let id: str;
expectident(p, &id);
n.str = id;
expecttok(p, tkind.TK_LPAREN, "expected '(' after fn name");
n.list = parseparams(p);
expecttok(p, tkind.TK_RPAREN, "expected ')' after params");
if (p.curkind != tkind.TK_ASSIGN) {
if (p.curkind != tkind.TK_SEMI) {
n.lhs = parsetype(p);
};
};
if (accepttok(p, tkind.TK_ASSIGN)) {
n.body = parseblock(p);
expecttok(p, tkind.TK_SEMI, "expected ';' after fn body");
} else {
// Body-less fn: FFI declaration (`fn name(args) ret;`).
expecttok(p, tkind.TK_SEMI, "expected ';' after fn header");
};
n.exported = exported;
n.attr = attrs;
return n;
};
fn parsetypedecl(p: *parser, exported: i32) *node = {
let pf: str = p.curfile;
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
advance(p); // past `type`
let n: *node = newnode(p.a, nkind.N_TYPEDECL, pf, pl, pc);
n.module = p.l.module;
let id: str;
expectident(p, &id);
n.str = id;
expecttok(p, tkind.TK_ASSIGN, "expected '=' in type decl");
n.lhs = parsetype(p);
expecttok(p, tkind.TK_SEMI, "expected ';' after type decl");
n.exported = exported;
return n;
};