162 lines
4.4 KiB
Plaintext
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;
|
|
};
|
|
|