selfhost/cmd/wcc: drop snake_case from 119 cross-cutting identifiers
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
// The cgen routines in selfhost/cmd/wcc/cgen.ww write directly to
|
// The cgen routines in selfhost/cmd/wcc/cgen.ww write directly to
|
||||||
// fd 1 via os.write(1, ...). For -o, we open the output file and
|
// fd 1 via os.write(1, ...). For -o, we open the output file and
|
||||||
// dup2 it onto fd 1 before invoking cg_file. This is the same trick
|
// dup2 it onto fd 1 before invoking cgfile. This is the same trick
|
||||||
// the bootstrap uses with shell redirection, just in-process.
|
// the bootstrap uses with shell redirection, just in-process.
|
||||||
|
|
||||||
use os;
|
use os;
|
||||||
@@ -123,8 +123,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
let f: *node = parsefile(&ps);
|
let f: *node = parsefile(&ps);
|
||||||
|
|
||||||
let cg: cgen;
|
let cg: cgen;
|
||||||
cgen_init(&cg, ar);
|
cgeninit(&cg, ar);
|
||||||
cg_file(&cg, f);
|
cgfile(&cg, f);
|
||||||
|
|
||||||
if (l.errs > 0) { return 1; };
|
if (l.errs > 0) { return 1; };
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -32,56 +32,56 @@ type checker = struct {
|
|||||||
verbose: i32, // when non-zero, log each unresolved name
|
verbose: i32, // when non-zero, log each unresolved name
|
||||||
};
|
};
|
||||||
|
|
||||||
// seed_primitives — install the built-in type names so `i32`, `str`,
|
// seedprimitives — install the built-in type names so `i32`, `str`,
|
||||||
// etc. can be looked up like ordinary symbols.
|
// etc. can be looked up like ordinary symbols.
|
||||||
fn seed_primitives(c: *checker) void = {
|
fn seedprimitives(c: *checker) void = {
|
||||||
scope_define(c.top, "void", SK_TYPE, c.tc.ty_void, nil);
|
scopedefine(c.top, "void", SK_TYPE, c.tc.ty_void, nil);
|
||||||
scope_define(c.top, "bool", SK_TYPE, c.tc.ty_bool, nil);
|
scopedefine(c.top, "bool", SK_TYPE, c.tc.ty_bool, nil);
|
||||||
scope_define(c.top, "rune", SK_TYPE, c.tc.ty_rune, nil);
|
scopedefine(c.top, "rune", SK_TYPE, c.tc.ty_rune, nil);
|
||||||
scope_define(c.top, "i8", SK_TYPE, c.tc.ty_i8, nil);
|
scopedefine(c.top, "i8", SK_TYPE, c.tc.ty_i8, nil);
|
||||||
scope_define(c.top, "i16", SK_TYPE, c.tc.ty_i16, nil);
|
scopedefine(c.top, "i16", SK_TYPE, c.tc.ty_i16, nil);
|
||||||
scope_define(c.top, "i32", SK_TYPE, c.tc.ty_i32, nil);
|
scopedefine(c.top, "i32", SK_TYPE, c.tc.ty_i32, nil);
|
||||||
scope_define(c.top, "i64", SK_TYPE, c.tc.ty_i64, nil);
|
scopedefine(c.top, "i64", SK_TYPE, c.tc.ty_i64, nil);
|
||||||
scope_define(c.top, "u8", SK_TYPE, c.tc.ty_u8, nil);
|
scopedefine(c.top, "u8", SK_TYPE, c.tc.ty_u8, nil);
|
||||||
scope_define(c.top, "u16", SK_TYPE, c.tc.ty_u16, nil);
|
scopedefine(c.top, "u16", SK_TYPE, c.tc.ty_u16, nil);
|
||||||
scope_define(c.top, "u32", SK_TYPE, c.tc.ty_u32, nil);
|
scopedefine(c.top, "u32", SK_TYPE, c.tc.ty_u32, nil);
|
||||||
scope_define(c.top, "u64", SK_TYPE, c.tc.ty_u64, nil);
|
scopedefine(c.top, "u64", SK_TYPE, c.tc.ty_u64, nil);
|
||||||
scope_define(c.top, "int", SK_TYPE, c.tc.ty_int, nil);
|
scopedefine(c.top, "int", SK_TYPE, c.tc.ty_int, nil);
|
||||||
scope_define(c.top, "uint", SK_TYPE, c.tc.ty_uint, nil);
|
scopedefine(c.top, "uint", SK_TYPE, c.tc.ty_uint, nil);
|
||||||
scope_define(c.top, "uintptr", SK_TYPE, c.tc.ty_uintptr, nil);
|
scopedefine(c.top, "uintptr", SK_TYPE, c.tc.ty_uintptr, nil);
|
||||||
scope_define(c.top, "f32", SK_TYPE, c.tc.ty_f32, nil);
|
scopedefine(c.top, "f32", SK_TYPE, c.tc.ty_f32, nil);
|
||||||
scope_define(c.top, "f64", SK_TYPE, c.tc.ty_f64, nil);
|
scopedefine(c.top, "f64", SK_TYPE, c.tc.ty_f64, nil);
|
||||||
scope_define(c.top, "str", SK_TYPE, c.tc.ty_str, nil);
|
scopedefine(c.top, "str", SK_TYPE, c.tc.ty_str, nil);
|
||||||
// `nil`, `true`, `false` are keywords — handled at the lex/parser
|
// `nil`, `true`, `false` are keywords — handled at the lex/parser
|
||||||
// level, no symbol needed.
|
// level, no symbol needed.
|
||||||
// `len`, `alloc`, `free` are pseudo-builtins; scope_define them so
|
// `len`, `alloc`, `free` are pseudo-builtins; scopedefine them so
|
||||||
// their use sites resolve. The actual semantics live in cgen.
|
// their use sites resolve. The actual semantics live in cgen.
|
||||||
scope_define(c.top, "len", SK_FN, nil, nil);
|
scopedefine(c.top, "len", SK_FN, nil, nil);
|
||||||
scope_define(c.top, "alloc", SK_FN, nil, nil);
|
scopedefine(c.top, "alloc", SK_FN, nil, nil);
|
||||||
scope_define(c.top, "free", SK_FN, nil, nil);
|
scopedefine(c.top, "free", SK_FN, nil, nil);
|
||||||
};
|
};
|
||||||
|
|
||||||
// install_decl — install the top-level decl's name into the top scope.
|
// installdecl — install the top-level decl's name into the top scope.
|
||||||
// We don't compute its type yet (that's the resolve pass) — just bind
|
// We don't compute its type yet (that's the resolve pass) — just bind
|
||||||
// the name so forward references resolve.
|
// the name so forward references resolve.
|
||||||
fn install_decl(c: *checker, d: *node) void = {
|
fn installdecl(c: *checker, d: *node) void = {
|
||||||
if (d == nil) { return; };
|
if (d == nil) { return; };
|
||||||
let k: i32 = d.kind;
|
let k: i32 = d.kind;
|
||||||
let nm: str = d.str;
|
let nm: str = d.str;
|
||||||
if (k == N_USE) { scope_define(c.top, nm, SK_USE, nil, d); return; };
|
if (k == N_USE) { scopedefine(c.top, nm, SK_USE, nil, d); return; };
|
||||||
if (k == N_DEF) { scope_define(c.top, nm, SK_DEF, nil, d); return; };
|
if (k == N_DEF) { scopedefine(c.top, nm, SK_DEF, nil, d); return; };
|
||||||
if (k == N_TYPEDECL) { scope_define(c.top, nm, SK_TYPE, nil, d); return; };
|
if (k == N_TYPEDECL) { scopedefine(c.top, nm, SK_TYPE, nil, d); return; };
|
||||||
if (k == N_FNDECL) { scope_define(c.top, nm, SK_FN, nil, d); return; };
|
if (k == N_FNDECL) { scopedefine(c.top, nm, SK_FN, nil, d); return; };
|
||||||
if (k == N_LET) { scope_define(c.top, nm, SK_VAR, nil, d); return; };
|
if (k == N_LET) { scopedefine(c.top, nm, SK_VAR, nil, d); return; };
|
||||||
};
|
};
|
||||||
|
|
||||||
// resolve_walk — recursive AST walk that, for every N_IDENT and
|
// resolvewalk — recursive AST walk that, for every N_IDENT and
|
||||||
// N_TNAME seen, looks up the name and bumps the resolved/unresolved
|
// N_TNAME seen, looks up the name and bumps the resolved/unresolved
|
||||||
// counters. Local lets are installed in the current scope as soon as
|
// counters. Local lets are installed in the current scope as soon as
|
||||||
// their init/type expressions have been walked (forward use of a let
|
// their init/type expressions have been walked (forward use of a let
|
||||||
// before its declaration would resolve to nothing — same semantics as
|
// before its declaration would resolve to nothing — same semantics as
|
||||||
// the C checker's collect-then-resolve flow within a function).
|
// the C checker's collect-then-resolve flow within a function).
|
||||||
fn resolve_walk(c: *checker, n: *node) void = {
|
fn resolvewalk(c: *checker, n: *node) void = {
|
||||||
if (n == nil) { return; };
|
if (n == nil) { return; };
|
||||||
let k: i32 = n.kind;
|
let k: i32 = n.kind;
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ fn resolve_walk(c: *checker, n: *node) void = {
|
|||||||
if (k == N_IDENT) {
|
if (k == N_IDENT) {
|
||||||
let nm: str = n.str;
|
let nm: str = n.str;
|
||||||
if (nm.len > 0) {
|
if (nm.len > 0) {
|
||||||
let s: *sym = scope_lookup(c.cur, nm);
|
let s: *sym = scopelookup(c.cur, nm);
|
||||||
if (s == nil) {
|
if (s == nil) {
|
||||||
c.nunresolved += 1;
|
c.nunresolved += 1;
|
||||||
if (c.verbose != 0) {
|
if (c.verbose != 0) {
|
||||||
@@ -106,7 +106,7 @@ fn resolve_walk(c: *checker, n: *node) void = {
|
|||||||
if (k == N_TNAME) {
|
if (k == N_TNAME) {
|
||||||
let nm: str = n.str;
|
let nm: str = n.str;
|
||||||
if (nm.len > 0) {
|
if (nm.len > 0) {
|
||||||
let s: *sym = scope_lookup(c.cur, nm);
|
let s: *sym = scopelookup(c.cur, nm);
|
||||||
if (s == nil) {
|
if (s == nil) {
|
||||||
c.nunresolved += 1;
|
c.nunresolved += 1;
|
||||||
if (c.verbose != 0) {
|
if (c.verbose != 0) {
|
||||||
@@ -121,89 +121,89 @@ fn resolve_walk(c: *checker, n: *node) void = {
|
|||||||
// `match (e) { case let v: T => stmt; ... }` — the binding `v`
|
// `match (e) { case let v: T => stmt; ... }` — the binding `v`
|
||||||
// is declared by the case arm and visible inside its body.
|
// is declared by the case arm and visible inside its body.
|
||||||
if (k == N_MCASE) {
|
if (k == N_MCASE) {
|
||||||
if (n.lhs != nil) { resolve_walk(c, n.lhs); };
|
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||||
let nm: str = n.str;
|
let nm: str = n.str;
|
||||||
if (nm.len > 0) {
|
if (nm.len > 0) {
|
||||||
scope_define(c.cur, nm, SK_VAR, nil, n);
|
scopedefine(c.cur, nm, SK_VAR, nil, n);
|
||||||
};
|
};
|
||||||
if (n.body != nil) { resolve_walk(c, n.body); };
|
if (n.body != nil) { resolvewalk(c, n.body); };
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (k == N_DOT) {
|
if (k == N_DOT) {
|
||||||
// Walk only the base; the .field name is a member, not a
|
// Walk only the base; the .field name is a member, not a
|
||||||
// free identifier.
|
// free identifier.
|
||||||
if (n.lhs != nil) { resolve_walk(c, n.lhs); };
|
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (k == N_FIELD) {
|
if (k == N_FIELD) {
|
||||||
if (n.lhs != nil) { resolve_walk(c, n.lhs); };
|
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (k == N_TFIELD) {
|
if (k == N_TFIELD) {
|
||||||
if (n.lhs != nil) { resolve_walk(c, n.lhs); };
|
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Walk children (mirroring ast.ww's printer descent order).
|
// Walk children (mirroring ast.ww's printer descent order).
|
||||||
if (n.attr != nil) { resolve_walk(c, n.attr); };
|
if (n.attr != nil) { resolvewalk(c, n.attr); };
|
||||||
if (n.lhs != nil) { resolve_walk(c, n.lhs); };
|
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||||
if (n.rhs != nil) { resolve_walk(c, n.rhs); };
|
if (n.rhs != nil) { resolvewalk(c, n.rhs); };
|
||||||
if (n.cond != nil) { resolve_walk(c, n.cond); };
|
if (n.cond != nil) { resolvewalk(c, n.cond); };
|
||||||
if (n.body != nil) { resolve_walk(c, n.body); };
|
if (n.body != nil) { resolvewalk(c, n.body); };
|
||||||
if (n.els != nil) { resolve_walk(c, n.els); };
|
if (n.els != nil) { resolvewalk(c, n.els); };
|
||||||
if (n.list != nil) {
|
if (n.list != nil) {
|
||||||
let m: *node = n.list;
|
let m: *node = n.list;
|
||||||
for (m != nil) {
|
for (m != nil) {
|
||||||
resolve_walk(c, m);
|
resolvewalk(c, m);
|
||||||
m = m.next;
|
m = m.next;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// After walking children: a local `let X: T = init;` registers
|
// After walking children: a local `let X: T = init;` registers
|
||||||
// `X` so subsequent statements can resolve it. Top-level lets
|
// `X` so subsequent statements can resolve it. Top-level lets
|
||||||
// are installed in install_decl, so this duplicate install at
|
// are installed in installdecl, so this duplicate install at
|
||||||
// the file scope just no-ops (scope_define returns nil on dup).
|
// the file scope just no-ops (scopedefine returns nil on dup).
|
||||||
if (k == N_LET) {
|
if (k == N_LET) {
|
||||||
let nm: str = n.str;
|
let nm: str = n.str;
|
||||||
if (nm.len > 0) {
|
if (nm.len > 0) {
|
||||||
scope_define(c.cur, nm, SK_VAR, nil, n);
|
scopedefine(c.cur, nm, SK_VAR, nil, n);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// install_param — when entering a fn body, define its params in a
|
// install_param — when entering a fn body, define its params in a
|
||||||
// fresh local scope.
|
// fresh local scope.
|
||||||
fn install_params(c: *checker, params: *node) void = {
|
fn installparams(c: *checker, params: *node) void = {
|
||||||
let p: *node = params;
|
let p: *node = params;
|
||||||
for (p != nil) {
|
for (p != nil) {
|
||||||
if (p.kind == N_PARAM) {
|
if (p.kind == N_PARAM) {
|
||||||
let nm: str = p.str;
|
let nm: str = p.str;
|
||||||
if (nm.len > 0) {
|
if (nm.len > 0) {
|
||||||
scope_define(c.cur, nm, SK_PARAM, nil, p);
|
scopedefine(c.cur, nm, SK_PARAM, nil, p);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
p = p.next;
|
p = p.next;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// resolve_fnbody — open a child scope for the fn, install its params,
|
// resolvefnbody — open a child scope for the fn, install its params,
|
||||||
// then walk the body. Local lets installed by walk_stmt (a future
|
// then walk the body. Local lets installed by walk_stmt (a future
|
||||||
// extension); for the current pass we just resolve-walk without
|
// extension); for the current pass we just resolve-walk without
|
||||||
// per-statement scopes.
|
// per-statement scopes.
|
||||||
fn resolve_fnbody(c: *checker, fnnode: *node) void = {
|
fn resolvefnbody(c: *checker, fnnode: *node) void = {
|
||||||
let outer: *scope = c.cur;
|
let outer: *scope = c.cur;
|
||||||
c.cur = newscope(c.a, c.cur);
|
c.cur = newscope(c.a, c.cur);
|
||||||
install_params(c, fnnode.list);
|
installparams(c, fnnode.list);
|
||||||
if (fnnode.body != nil) {
|
if (fnnode.body != nil) {
|
||||||
resolve_walk(c, fnnode.body);
|
resolvewalk(c, fnnode.body);
|
||||||
};
|
};
|
||||||
c.cur = outer;
|
c.cur = outer;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn check_init(c: *checker, a: *arena, tc: *tctx) void = {
|
export fn checkinit(c: *checker, a: *arena, tc: *tctx) void = {
|
||||||
c.a = a;
|
c.a = a;
|
||||||
c.tc = tc;
|
c.tc = tc;
|
||||||
c.top = newscope(a, nil);
|
c.top = newscope(a, nil);
|
||||||
@@ -212,17 +212,17 @@ export fn check_init(c: *checker, a: *arena, tc: *tctx) void = {
|
|||||||
c.nunresolved = 0;
|
c.nunresolved = 0;
|
||||||
c.errs = 0;
|
c.errs = 0;
|
||||||
c.verbose = 0;
|
c.verbose = 0;
|
||||||
seed_primitives(c);
|
seedprimitives(c);
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn check_file(c: *checker, file: *node) void = {
|
export fn checkfile(c: *checker, file: *node) void = {
|
||||||
if (file == nil) { return; };
|
if (file == nil) { return; };
|
||||||
if (file.kind != N_FILE) { return; };
|
if (file.kind != N_FILE) { return; };
|
||||||
|
|
||||||
// Pass 1: install all top-level names.
|
// Pass 1: install all top-level names.
|
||||||
let d: *node = file.list;
|
let d: *node = file.list;
|
||||||
for (d != nil) {
|
for (d != nil) {
|
||||||
install_decl(c, d);
|
installdecl(c, d);
|
||||||
d = d.next;
|
d = d.next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -231,16 +231,16 @@ export fn check_file(c: *checker, file: *node) void = {
|
|||||||
for (d != nil) {
|
for (d != nil) {
|
||||||
let k: i32 = d.kind;
|
let k: i32 = d.kind;
|
||||||
if (k == N_FNDECL) {
|
if (k == N_FNDECL) {
|
||||||
if (d.lhs != nil) { resolve_walk(c, d.lhs); }; // return type
|
if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type
|
||||||
resolve_fnbody(c, d);
|
resolvefnbody(c, d);
|
||||||
} else { if (k == N_DEF) {
|
} else { if (k == N_DEF) {
|
||||||
if (d.lhs != nil) { resolve_walk(c, d.lhs); };
|
if (d.lhs != nil) { resolvewalk(c, d.lhs); };
|
||||||
if (d.rhs != nil) { resolve_walk(c, d.rhs); };
|
if (d.rhs != nil) { resolvewalk(c, d.rhs); };
|
||||||
} else { if (k == N_TYPEDECL) {
|
} else { if (k == N_TYPEDECL) {
|
||||||
if (d.lhs != nil) { resolve_walk(c, d.lhs); };
|
if (d.lhs != nil) { resolvewalk(c, d.lhs); };
|
||||||
} else { if (k == N_LET) {
|
} else { if (k == N_LET) {
|
||||||
if (d.lhs != nil) { resolve_walk(c, d.lhs); };
|
if (d.lhs != nil) { resolvewalk(c, d.lhs); };
|
||||||
if (d.rhs != nil) { resolve_walk(c, d.rhs); };
|
if (d.rhs != nil) { resolvewalk(c, d.rhs); };
|
||||||
};};};};
|
};};};};
|
||||||
d = d.next;
|
d = d.next;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -64,14 +64,14 @@ fn lget(l: *lex) i32 = {
|
|||||||
return c;
|
return c;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn cur_pos(l: *lex, out: *pos) void = {
|
fn curpos(l: *lex, out: *pos) void = {
|
||||||
out.file = l.file;
|
out.file = l.file;
|
||||||
out.line = l.line;
|
out.line = l.line;
|
||||||
out.col = l.col;
|
out.col = l.col;
|
||||||
};
|
};
|
||||||
|
|
||||||
// putuint — write `v` (signed, but always non-negative here) to fd 2
|
// putuint — write `v` (signed, but always non-negative here) to fd 2
|
||||||
// in decimal. Standalone so err_at doesn't drag in fmt and create a
|
// in decimal. Standalone so errat doesn't drag in fmt and create a
|
||||||
// dependency cycle with strconv.
|
// dependency cycle with strconv.
|
||||||
fn putuint(fd: i32, v: i32) void = {
|
fn putuint(fd: i32, v: i32) void = {
|
||||||
let tmp: [16]u8;
|
let tmp: [16]u8;
|
||||||
@@ -89,7 +89,7 @@ fn putuint(fd: i32, v: i32) void = {
|
|||||||
os.write(fd, buf.ptr, m: u64);
|
os.write(fd, buf.ptr, m: u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn err_at(l: *lex, p: *pos, msg: str) void = {
|
fn errat(l: *lex, p: *pos, msg: str) void = {
|
||||||
let pf: str = p.file;
|
let pf: str = p.file;
|
||||||
os.write(2, pf.ptr, pf.len: u64);
|
os.write(2, pf.ptr, pf.len: u64);
|
||||||
os.write(2, ":".ptr, 1u64);
|
os.write(2, ":".ptr, 1u64);
|
||||||
@@ -128,8 +128,8 @@ fn skipws(l: *lex) bool = {
|
|||||||
let x: i32 = lget(l);
|
let x: i32 = lget(l);
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
let cp: pos;
|
let cp: pos;
|
||||||
cur_pos(l, &cp);
|
curpos(l, &cp);
|
||||||
err_at(l, &cp, "unterminated /* comment");
|
errat(l, &cp, "unterminated /* comment");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if (prev == 42) {
|
if (prev == 42) {
|
||||||
@@ -200,13 +200,13 @@ fn escape(l: *lex, out: *i32) bool = {
|
|||||||
if (hi < 0) { return false; };
|
if (hi < 0) { return false; };
|
||||||
if (lo < 0) { return false; };
|
if (lo < 0) { return false; };
|
||||||
if (!ascii.ishex(hi: u8)) {
|
if (!ascii.ishex(hi: u8)) {
|
||||||
let cp: pos; cur_pos(l, &cp);
|
let cp: pos; curpos(l, &cp);
|
||||||
err_at(l, &cp, "bad \\x escape");
|
errat(l, &cp, "bad \\x escape");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if (!ascii.ishex(lo: u8)) {
|
if (!ascii.ishex(lo: u8)) {
|
||||||
let cp: pos; cur_pos(l, &cp);
|
let cp: pos; curpos(l, &cp);
|
||||||
err_at(l, &cp, "bad \\x escape");
|
errat(l, &cp, "bad \\x escape");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let h: i32 = ascii.digitval(hi: u8);
|
let h: i32 = ascii.digitval(hi: u8);
|
||||||
@@ -214,13 +214,13 @@ fn escape(l: *lex, out: *i32) bool = {
|
|||||||
*out = (h << 4) | lv;
|
*out = (h << 4) | lv;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
let cp: pos; cur_pos(l, &cp);
|
let cp: pos; curpos(l, &cp);
|
||||||
err_at(l, &cp, "bad escape");
|
errat(l, &cp, "bad escape");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// scan_decimal_run — consume a run of decimal digits and underscores.
|
// scandecimalrun — consume a run of decimal digits and underscores.
|
||||||
fn scan_decimal_run(l: *lex) void = {
|
fn scandecimalrun(l: *lex) void = {
|
||||||
for (true) {
|
for (true) {
|
||||||
let c: i32 = lpeek(l, 0u64);
|
let c: i32 = lpeek(l, 0u64);
|
||||||
if (c < 0) { break; };
|
if (c < 0) { break; };
|
||||||
@@ -231,7 +231,7 @@ fn scan_decimal_run(l: *lex) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn scan_hex_run(l: *lex) void = {
|
fn scanhexrun(l: *lex) void = {
|
||||||
for (true) {
|
for (true) {
|
||||||
let c: i32 = lpeek(l, 0u64);
|
let c: i32 = lpeek(l, 0u64);
|
||||||
if (c < 0) { break; };
|
if (c < 0) { break; };
|
||||||
@@ -242,7 +242,7 @@ fn scan_hex_run(l: *lex) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn scan_bin_run(l: *lex) void = {
|
fn scanbinrun(l: *lex) void = {
|
||||||
for (true) {
|
for (true) {
|
||||||
let c: i32 = lpeek(l, 0u64);
|
let c: i32 = lpeek(l, 0u64);
|
||||||
if (c == 48) { lget(l); continue; };
|
if (c == 48) { lget(l); continue; };
|
||||||
@@ -252,7 +252,7 @@ fn scan_bin_run(l: *lex) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn scan_oct_run(l: *lex) void = {
|
fn scanoctrun(l: *lex) void = {
|
||||||
for (true) {
|
for (true) {
|
||||||
let c: i32 = lpeek(l, 0u64);
|
let c: i32 = lpeek(l, 0u64);
|
||||||
if (c < 48) { break; };
|
if (c < 48) { break; };
|
||||||
@@ -263,8 +263,8 @@ fn scan_oct_run(l: *lex) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// scan_exp — consume the [eE][+-]?[0-9]+ tail of a float, if present.
|
// scanexp — consume the [eE][+-]?[0-9]+ tail of a float, if present.
|
||||||
fn scan_exp(l: *lex) void = {
|
fn scanexp(l: *lex) void = {
|
||||||
let e: i32 = lpeek(l, 0u64);
|
let e: i32 = lpeek(l, 0u64);
|
||||||
if (e != 101) { if (e != 69) { return; }; }; // 'e' or 'E'
|
if (e != 101) { if (e != 69) { return; }; }; // 'e' or 'E'
|
||||||
lget(l);
|
lget(l);
|
||||||
@@ -293,41 +293,41 @@ fn lexnum(l: *lex, start: *pos, out: *tok) void = {
|
|||||||
|
|
||||||
if (c0 == 48) { // '0'
|
if (c0 == 48) { // '0'
|
||||||
if (c1 == 120) { // 'x'
|
if (c1 == 120) { // 'x'
|
||||||
lget(l); lget(l); base = 16; scan_hex_run(l);
|
lget(l); lget(l); base = 16; scanhexrun(l);
|
||||||
} else { if (c1 == 88) { // 'X'
|
} else { if (c1 == 88) { // 'X'
|
||||||
lget(l); lget(l); base = 16; scan_hex_run(l);
|
lget(l); lget(l); base = 16; scanhexrun(l);
|
||||||
} else { if (c1 == 98) { // 'b'
|
} else { if (c1 == 98) { // 'b'
|
||||||
lget(l); lget(l); base = 2; scan_bin_run(l);
|
lget(l); lget(l); base = 2; scanbinrun(l);
|
||||||
} else { if (c1 == 66) { // 'B'
|
} else { if (c1 == 66) { // 'B'
|
||||||
lget(l); lget(l); base = 2; scan_bin_run(l);
|
lget(l); lget(l); base = 2; scanbinrun(l);
|
||||||
} else { if (c1 == 111) { // 'o'
|
} else { if (c1 == 111) { // 'o'
|
||||||
lget(l); lget(l); base = 8; scan_oct_run(l);
|
lget(l); lget(l); base = 8; scanoctrun(l);
|
||||||
} else { if (c1 == 79) { // 'O'
|
} else { if (c1 == 79) { // 'O'
|
||||||
lget(l); lget(l); base = 8; scan_oct_run(l);
|
lget(l); lget(l); base = 8; scanoctrun(l);
|
||||||
} else {
|
} else {
|
||||||
scan_decimal_run(l);
|
scandecimalrun(l);
|
||||||
if (lpeek(l, 0u64) == 46) {
|
if (lpeek(l, 0u64) == 46) {
|
||||||
let after: i32 = lpeek(l, 1u64);
|
let after: i32 = lpeek(l, 1u64);
|
||||||
if (after >= 48) {
|
if (after >= 48) {
|
||||||
if (after <= 57) {
|
if (after <= 57) {
|
||||||
isfloat = true;
|
isfloat = true;
|
||||||
lget(l);
|
lget(l);
|
||||||
scan_decimal_run(l);
|
scandecimalrun(l);
|
||||||
scan_exp(l);
|
scanexp(l);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};};};};};};
|
};};};};};};
|
||||||
} else {
|
} else {
|
||||||
scan_decimal_run(l);
|
scandecimalrun(l);
|
||||||
if (lpeek(l, 0u64) == 46) {
|
if (lpeek(l, 0u64) == 46) {
|
||||||
let after: i32 = lpeek(l, 1u64);
|
let after: i32 = lpeek(l, 1u64);
|
||||||
if (after >= 48) {
|
if (after >= 48) {
|
||||||
if (after <= 57) {
|
if (after <= 57) {
|
||||||
isfloat = true;
|
isfloat = true;
|
||||||
lget(l);
|
lget(l);
|
||||||
scan_decimal_run(l);
|
scandecimalrun(l);
|
||||||
scan_exp(l);
|
scanexp(l);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -352,7 +352,7 @@ fn lexnum(l: *lex, start: *pos, out: *tok) void = {
|
|||||||
let ok: bool = false;
|
let ok: bool = false;
|
||||||
out.uval = parseint(digs, dn, base, &ok);
|
out.uval = parseint(digs, dn, base, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
err_at(l, start, "bad integer literal");
|
errat(l, start, "bad integer literal");
|
||||||
out.kind = TK_ERR;
|
out.kind = TK_ERR;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -432,7 +432,7 @@ fn lexstr(l: *lex, start: *pos, out: *tok) void = {
|
|||||||
for (true) {
|
for (true) {
|
||||||
let c: i32 = lpeek(l, 0u64);
|
let c: i32 = lpeek(l, 0u64);
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
err_at(l, start, "unterminated string");
|
errat(l, start, "unterminated string");
|
||||||
out.kind = TK_ERR;
|
out.kind = TK_ERR;
|
||||||
out.file = start.file;
|
out.file = start.file;
|
||||||
out.line = start.line;
|
out.line = start.line;
|
||||||
@@ -477,7 +477,7 @@ fn lexstr(l: *lex, start: *pos, out: *tok) void = {
|
|||||||
fn lexrune(l: *lex, start: *pos, out: *tok) void = {
|
fn lexrune(l: *lex, start: *pos, out: *tok) void = {
|
||||||
let c: i32 = lpeek(l, 0u64);
|
let c: i32 = lpeek(l, 0u64);
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
err_at(l, start, "unterminated rune");
|
errat(l, start, "unterminated rune");
|
||||||
out.kind = TK_ERR;
|
out.kind = TK_ERR;
|
||||||
out.file = start.file;
|
out.file = start.file;
|
||||||
out.line = start.line;
|
out.line = start.line;
|
||||||
@@ -493,7 +493,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = {
|
|||||||
ch = lget(l);
|
ch = lget(l);
|
||||||
};
|
};
|
||||||
if (lpeek(l, 0u64) != 39) {
|
if (lpeek(l, 0u64) != 39) {
|
||||||
err_at(l, start, "rune literal missing closing '");
|
errat(l, start, "rune literal missing closing '");
|
||||||
out.kind = TK_ERR;
|
out.kind = TK_ERR;
|
||||||
out.file = start.file;
|
out.file = start.file;
|
||||||
out.line = start.line;
|
out.line = start.line;
|
||||||
@@ -509,16 +509,16 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = {
|
|||||||
out.uval = ch: u64;
|
out.uval = ch: u64;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn emit_simple(start: *pos, k: i32, out: *tok) void = {
|
fn emitsimple(start: *pos, k: i32, out: *tok) void = {
|
||||||
out.kind = k;
|
out.kind = k;
|
||||||
out.file = start.file;
|
out.file = start.file;
|
||||||
out.line = start.line;
|
out.line = start.line;
|
||||||
out.col = start.col;
|
out.col = start.col;
|
||||||
};
|
};
|
||||||
|
|
||||||
// set_pos_from — copy file/line/col from a *pos into a tok. Used by
|
// setposfrom — copy file/line/col from a *pos into a tok. Used by
|
||||||
// the err-token path where we already have a pos.
|
// the err-token path where we already have a pos.
|
||||||
fn set_pos_from(out: *tok, p: *pos) void = {
|
fn setposfrom(out: *tok, p: *pos) void = {
|
||||||
out.file = p.file;
|
out.file = p.file;
|
||||||
out.line = p.line;
|
out.line = p.line;
|
||||||
out.col = p.col;
|
out.col = p.col;
|
||||||
@@ -541,11 +541,11 @@ export fn lexnext(l: *lex, out: *tok) void = {
|
|||||||
out.tsuffix = empty;
|
out.tsuffix = empty;
|
||||||
|
|
||||||
if (!skipws(l)) {
|
if (!skipws(l)) {
|
||||||
let p: pos; cur_pos(l, &p);
|
let p: pos; curpos(l, &p);
|
||||||
emit_simple(&p, TK_EOF, out);
|
emitsimple(&p, TK_EOF, out);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let start: pos; cur_pos(l, &start);
|
let start: pos; curpos(l, &start);
|
||||||
let c: i32 = lpeek(l, 0u64);
|
let c: i32 = lpeek(l, 0u64);
|
||||||
|
|
||||||
if (c >= 0) {
|
if (c >= 0) {
|
||||||
@@ -558,98 +558,98 @@ export fn lexnext(l: *lex, out: *tok) void = {
|
|||||||
|
|
||||||
lget(l);
|
lget(l);
|
||||||
|
|
||||||
if (c == 40) { emit_simple(&start, TK_LPAREN, out); return; };
|
if (c == 40) { emitsimple(&start, TK_LPAREN, out); return; };
|
||||||
if (c == 41) { emit_simple(&start, TK_RPAREN, out); return; };
|
if (c == 41) { emitsimple(&start, TK_RPAREN, out); return; };
|
||||||
if (c == 123) { emit_simple(&start, TK_LBRACE, out); return; };
|
if (c == 123) { emitsimple(&start, TK_LBRACE, out); return; };
|
||||||
if (c == 125) { emit_simple(&start, TK_RBRACE, out); return; };
|
if (c == 125) { emitsimple(&start, TK_RBRACE, out); return; };
|
||||||
if (c == 91) { emit_simple(&start, TK_LBRACK, out); return; };
|
if (c == 91) { emitsimple(&start, TK_LBRACK, out); return; };
|
||||||
if (c == 93) { emit_simple(&start, TK_RBRACK, out); return; };
|
if (c == 93) { emitsimple(&start, TK_RBRACK, out); return; };
|
||||||
if (c == 44) { emit_simple(&start, TK_COMMA, out); return; };
|
if (c == 44) { emitsimple(&start, TK_COMMA, out); return; };
|
||||||
if (c == 59) { emit_simple(&start, TK_SEMI, out); return; };
|
if (c == 59) { emitsimple(&start, TK_SEMI, out); return; };
|
||||||
if (c == 58) { emit_simple(&start, TK_COLON, out); return; };
|
if (c == 58) { emitsimple(&start, TK_COLON, out); return; };
|
||||||
if (c == 64) { emit_simple(&start, TK_AT, out); return; };
|
if (c == 64) { emitsimple(&start, TK_AT, out); return; };
|
||||||
if (c == 63) { emit_simple(&start, TK_QUESTION, out); return; };
|
if (c == 63) { emitsimple(&start, TK_QUESTION, out); return; };
|
||||||
if (c == 126) { emit_simple(&start, TK_TILDE, out); return; };
|
if (c == 126) { emitsimple(&start, TK_TILDE, out); return; };
|
||||||
|
|
||||||
if (c == 46) { // '.'
|
if (c == 46) { // '.'
|
||||||
if (lpeek(l, 0u64) == 46) {
|
if (lpeek(l, 0u64) == 46) {
|
||||||
if (lpeek(l, 1u64) == 46) {
|
if (lpeek(l, 1u64) == 46) {
|
||||||
lget(l); lget(l);
|
lget(l); lget(l);
|
||||||
emit_simple(&start, TK_ELLIPSIS, out); return;
|
emitsimple(&start, TK_ELLIPSIS, out); return;
|
||||||
};
|
};
|
||||||
lget(l);
|
lget(l);
|
||||||
emit_simple(&start, TK_DOTDOT, out); return;
|
emitsimple(&start, TK_DOTDOT, out); return;
|
||||||
};
|
};
|
||||||
emit_simple(&start, TK_DOT, out); return;
|
emitsimple(&start, TK_DOT, out); return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (c == 43) {
|
if (c == 43) {
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_PLUSEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_PLUSEQ, out); return; };
|
||||||
emit_simple(&start, TK_PLUS, out); return;
|
emitsimple(&start, TK_PLUS, out); return;
|
||||||
};
|
};
|
||||||
if (c == 45) {
|
if (c == 45) {
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_MINUSEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_MINUSEQ, out); return; };
|
||||||
if (lpeek(l, 0u64) == 62) { lget(l); emit_simple(&start, TK_ARROW, out); return; };
|
if (lpeek(l, 0u64) == 62) { lget(l); emitsimple(&start, TK_ARROW, out); return; };
|
||||||
emit_simple(&start, TK_MINUS, out); return;
|
emitsimple(&start, TK_MINUS, out); return;
|
||||||
};
|
};
|
||||||
if (c == 42) {
|
if (c == 42) {
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_STAREQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_STAREQ, out); return; };
|
||||||
emit_simple(&start, TK_STAR, out); return;
|
emitsimple(&start, TK_STAR, out); return;
|
||||||
};
|
};
|
||||||
if (c == 47) {
|
if (c == 47) {
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_SLASHEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_SLASHEQ, out); return; };
|
||||||
emit_simple(&start, TK_SLASH, out); return;
|
emitsimple(&start, TK_SLASH, out); return;
|
||||||
};
|
};
|
||||||
if (c == 37) {
|
if (c == 37) {
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_PERCENTEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_PERCENTEQ, out); return; };
|
||||||
emit_simple(&start, TK_PERCENT, out); return;
|
emitsimple(&start, TK_PERCENT, out); return;
|
||||||
};
|
};
|
||||||
if (c == 38) {
|
if (c == 38) {
|
||||||
if (lpeek(l, 0u64) == 38) { lget(l); emit_simple(&start, TK_AND, out); return; };
|
if (lpeek(l, 0u64) == 38) { lget(l); emitsimple(&start, TK_AND, out); return; };
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_AMPEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_AMPEQ, out); return; };
|
||||||
emit_simple(&start, TK_AMP, out); return;
|
emitsimple(&start, TK_AMP, out); return;
|
||||||
};
|
};
|
||||||
if (c == 124) {
|
if (c == 124) {
|
||||||
if (lpeek(l, 0u64) == 124) { lget(l); emit_simple(&start, TK_OR, out); return; };
|
if (lpeek(l, 0u64) == 124) { lget(l); emitsimple(&start, TK_OR, out); return; };
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_PIPEEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_PIPEEQ, out); return; };
|
||||||
emit_simple(&start, TK_PIPE, out); return;
|
emitsimple(&start, TK_PIPE, out); return;
|
||||||
};
|
};
|
||||||
if (c == 94) {
|
if (c == 94) {
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_CARETEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_CARETEQ, out); return; };
|
||||||
emit_simple(&start, TK_CARET, out); return;
|
emitsimple(&start, TK_CARET, out); return;
|
||||||
};
|
};
|
||||||
if (c == 61) {
|
if (c == 61) {
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_EQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_EQ, out); return; };
|
||||||
if (lpeek(l, 0u64) == 62) { lget(l); emit_simple(&start, TK_FATARROW, out); return; };
|
if (lpeek(l, 0u64) == 62) { lget(l); emitsimple(&start, TK_FATARROW, out); return; };
|
||||||
emit_simple(&start, TK_ASSIGN, out); return;
|
emitsimple(&start, TK_ASSIGN, out); return;
|
||||||
};
|
};
|
||||||
if (c == 33) {
|
if (c == 33) {
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_NEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_NEQ, out); return; };
|
||||||
emit_simple(&start, TK_NOT, out); return;
|
emitsimple(&start, TK_NOT, out); return;
|
||||||
};
|
};
|
||||||
if (c == 60) {
|
if (c == 60) {
|
||||||
if (lpeek(l, 0u64) == 60) {
|
if (lpeek(l, 0u64) == 60) {
|
||||||
lget(l);
|
lget(l);
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_LSHIFTEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_LSHIFTEQ, out); return; };
|
||||||
emit_simple(&start, TK_LSHIFT, out); return;
|
emitsimple(&start, TK_LSHIFT, out); return;
|
||||||
};
|
};
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_LE, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_LE, out); return; };
|
||||||
if (lpeek(l, 0u64) == 45) { lget(l); emit_simple(&start, TK_LARROW, out); return; };
|
if (lpeek(l, 0u64) == 45) { lget(l); emitsimple(&start, TK_LARROW, out); return; };
|
||||||
emit_simple(&start, TK_LT, out); return;
|
emitsimple(&start, TK_LT, out); return;
|
||||||
};
|
};
|
||||||
if (c == 62) {
|
if (c == 62) {
|
||||||
if (lpeek(l, 0u64) == 62) {
|
if (lpeek(l, 0u64) == 62) {
|
||||||
lget(l);
|
lget(l);
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_RSHIFTEQ, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_RSHIFTEQ, out); return; };
|
||||||
emit_simple(&start, TK_RSHIFT, out); return;
|
emitsimple(&start, TK_RSHIFT, out); return;
|
||||||
};
|
};
|
||||||
if (lpeek(l, 0u64) == 61) { lget(l); emit_simple(&start, TK_GE, out); return; };
|
if (lpeek(l, 0u64) == 61) { lget(l); emitsimple(&start, TK_GE, out); return; };
|
||||||
emit_simple(&start, TK_GT, out); return;
|
emitsimple(&start, TK_GT, out); return;
|
||||||
};
|
};
|
||||||
|
|
||||||
err_at(l, &start, "unexpected character");
|
errat(l, &start, "unexpected character");
|
||||||
out.kind = TK_ERR;
|
out.kind = TK_ERR;
|
||||||
set_pos_from(out, &start);
|
setposfrom(out, &start);
|
||||||
let one: [1]u8;
|
let one: [1]u8;
|
||||||
one[0] = c: u8;
|
one[0] = c: u8;
|
||||||
out.text = astrndup(l.a, one.ptr, 1u64);
|
out.text = astrndup(l.a, one.ptr, 1u64);
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ export fn parserinit(p: *parser, a: *arena, l: *lex) void = {
|
|||||||
|
|
||||||
fn advance(p: *parser) void = { refill(p); };
|
fn advance(p: *parser) void = { refill(p); };
|
||||||
|
|
||||||
fn accept_tok(p: *parser, k: i32) bool = {
|
fn accepttok(p: *parser, k: i32) bool = {
|
||||||
if (p.cur_kind == k) { advance(p); return true; };
|
if (p.cur_kind == k) { advance(p); return true; };
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn err_msg(p: *parser, msg: str) void = {
|
fn errmsg(p: *parser, msg: str) void = {
|
||||||
let pre: str = "parse: ";
|
let pre: str = "parse: ";
|
||||||
os.write(2, pre.ptr, pre.len: u64);
|
os.write(2, pre.ptr, pre.len: u64);
|
||||||
os.write(2, msg.ptr, msg.len: u64);
|
os.write(2, msg.ptr, msg.len: u64);
|
||||||
@@ -69,9 +69,9 @@ fn err_msg(p: *parser, msg: str) void = {
|
|||||||
p.errs += 1;
|
p.errs += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn expect_tok(p: *parser, k: i32, what: str) bool = {
|
fn expecttok(p: *parser, k: i32, what: str) bool = {
|
||||||
if (p.cur_kind == k) { advance(p); return true; };
|
if (p.cur_kind == k) { advance(p); return true; };
|
||||||
err_msg(p, what);
|
errmsg(p, what);
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ fn expect_tok(p: *parser, k: i32, what: str) bool = {
|
|||||||
// Returns the empty str on error (and advances to make progress).
|
// Returns the empty str on error (and advances to make progress).
|
||||||
fn expectident(p: *parser, into: *str) bool = {
|
fn expectident(p: *parser, into: *str) bool = {
|
||||||
if (p.cur_kind != TK_IDENT) {
|
if (p.cur_kind != TK_IDENT) {
|
||||||
err_msg(p, "expected identifier");
|
errmsg(p, "expected identifier");
|
||||||
advance(p);
|
advance(p);
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -116,14 +116,14 @@ fn parsetype(p: *parser) *node = {
|
|||||||
};
|
};
|
||||||
let n: *node = newnode(p.a, N_TARRAY, pf, pl, pc);
|
let n: *node = newnode(p.a, N_TARRAY, pf, pl, pc);
|
||||||
n.rhs = parseexpr(p);
|
n.rhs = parseexpr(p);
|
||||||
expect_tok(p, TK_RBRACK, "expected ']' in array type");
|
expecttok(p, TK_RBRACK, "expected ']' in array type");
|
||||||
n.lhs = parsetype(p);
|
n.lhs = parsetype(p);
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (p.cur_kind == TK_STRUCT) {
|
if (p.cur_kind == TK_STRUCT) {
|
||||||
advance(p);
|
advance(p);
|
||||||
expect_tok(p, TK_LBRACE, "expected '{' after struct");
|
expecttok(p, TK_LBRACE, "expected '{' after struct");
|
||||||
let n: *node = newnode(p.a, N_TSTRUCT, pf, pl, pc);
|
let n: *node = newnode(p.a, N_TSTRUCT, pf, pl, pc);
|
||||||
let fhead: *node = nil;
|
let fhead: *node = nil;
|
||||||
let ftail: *node = nil;
|
let ftail: *node = nil;
|
||||||
@@ -136,13 +136,13 @@ fn parsetype(p: *parser) *node = {
|
|||||||
let fid: str;
|
let fid: str;
|
||||||
expectident(p, &fid);
|
expectident(p, &fid);
|
||||||
f.str = fid;
|
f.str = fid;
|
||||||
expect_tok(p, TK_COLON, "expected ':' in field");
|
expecttok(p, TK_COLON, "expected ':' in field");
|
||||||
f.lhs = parsetype(p);
|
f.lhs = parsetype(p);
|
||||||
if (fhead == nil) { fhead = f; ftail = f; }
|
if (fhead == nil) { fhead = f; ftail = f; }
|
||||||
else { ftail.next = f; ftail = f; };
|
else { ftail.next = f; ftail = f; };
|
||||||
if (!accept_tok(p, TK_COMMA)) { break; };
|
if (!accepttok(p, TK_COMMA)) { break; };
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RBRACE, "expected '}' after struct fields");
|
expecttok(p, TK_RBRACE, "expected '}' after struct fields");
|
||||||
n.list = fhead;
|
n.list = fhead;
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
@@ -160,7 +160,7 @@ fn parsetype(p: *parser) *node = {
|
|||||||
// (T) or (T, T, ...) or (T | T | ...)
|
// (T) or (T, T, ...) or (T | T | ...)
|
||||||
advance(p);
|
advance(p);
|
||||||
let first: *node = parsetype(p);
|
let first: *node = parsetype(p);
|
||||||
if (accept_tok(p, TK_PIPE)) {
|
if (accepttok(p, TK_PIPE)) {
|
||||||
let n: *node = newnode(p.a, N_TTAGGED, pf, pl, pc);
|
let n: *node = newnode(p.a, N_TTAGGED, pf, pl, pc);
|
||||||
let head: *node = first;
|
let head: *node = first;
|
||||||
let tail: *node = first;
|
let tail: *node = first;
|
||||||
@@ -168,14 +168,14 @@ fn parsetype(p: *parser) *node = {
|
|||||||
let e: *node = parsetype(p);
|
let e: *node = parsetype(p);
|
||||||
tail.next = e;
|
tail.next = e;
|
||||||
tail = e;
|
tail = e;
|
||||||
if (!accept_tok(p, TK_PIPE)) { break; };
|
if (!accepttok(p, TK_PIPE)) { break; };
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' in tagged-union type");
|
expecttok(p, TK_RPAREN, "expected ')' in tagged-union type");
|
||||||
n.list = head;
|
n.list = head;
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
if (!accept_tok(p, TK_COMMA)) {
|
if (!accepttok(p, TK_COMMA)) {
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' after parenthesised type");
|
expecttok(p, TK_RPAREN, "expected ')' after parenthesised type");
|
||||||
return first;
|
return first;
|
||||||
};
|
};
|
||||||
let n: *node = newnode(p.a, N_TTUPLE, pf, pl, pc);
|
let n: *node = newnode(p.a, N_TTUPLE, pf, pl, pc);
|
||||||
@@ -185,28 +185,28 @@ fn parsetype(p: *parser) *node = {
|
|||||||
let e: *node = parsetype(p);
|
let e: *node = parsetype(p);
|
||||||
tail.next = e;
|
tail.next = e;
|
||||||
tail = e;
|
tail = e;
|
||||||
if (!accept_tok(p, TK_COMMA)) { break; };
|
if (!accepttok(p, TK_COMMA)) { break; };
|
||||||
if (p.cur_kind == TK_RPAREN) { break; };
|
if (p.cur_kind == TK_RPAREN) { break; };
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' in tuple type");
|
expecttok(p, TK_RPAREN, "expected ')' in tuple type");
|
||||||
n.list = head;
|
n.list = head;
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (p.cur_kind == TK_FN) {
|
if (p.cur_kind == TK_FN) {
|
||||||
advance(p);
|
advance(p);
|
||||||
expect_tok(p, TK_LPAREN, "expected '(' after fn in type");
|
expecttok(p, TK_LPAREN, "expected '(' after fn in type");
|
||||||
let n: *node = newnode(p.a, N_TFN, pf, pl, pc);
|
let n: *node = newnode(p.a, N_TFN, pf, pl, pc);
|
||||||
// Anonymous-or-named params: parseparams handles named only;
|
// Anonymous-or-named params: parseparams handles named only;
|
||||||
// for fn-type expressions the C parser allows IDENT-less
|
// for fn-type expressions the C parser allows IDENT-less
|
||||||
// (anonymous) params. Stub: only named params for now.
|
// (anonymous) params. Stub: only named params for now.
|
||||||
n.list = parseparams(p);
|
n.list = parseparams(p);
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' after fn type params");
|
expecttok(p, TK_RPAREN, "expected ')' after fn type params");
|
||||||
n.lhs = parsetype(p);
|
n.lhs = parsetype(p);
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
err_msg(p, "expected type");
|
errmsg(p, "expected type");
|
||||||
advance(p);
|
advance(p);
|
||||||
return newnode(p.a, N_TNAME, pf, pl, pc);
|
return newnode(p.a, N_TNAME, pf, pl, pc);
|
||||||
};
|
};
|
||||||
@@ -298,7 +298,7 @@ fn parseprimary(p: *parser) *node = {
|
|||||||
advance(p);
|
advance(p);
|
||||||
let e: *node = parseexpr(p);
|
let e: *node = parseexpr(p);
|
||||||
// Tuple literal: (a, b, ...)
|
// Tuple literal: (a, b, ...)
|
||||||
if (accept_tok(p, TK_COMMA)) {
|
if (accepttok(p, TK_COMMA)) {
|
||||||
let t: *node = newnode(p.a, N_TUPLE, pf, pl, pc);
|
let t: *node = newnode(p.a, N_TUPLE, pf, pl, pc);
|
||||||
t.list = e;
|
t.list = e;
|
||||||
let tail: *node = e;
|
let tail: *node = e;
|
||||||
@@ -307,12 +307,12 @@ fn parseprimary(p: *parser) *node = {
|
|||||||
let en: *node = parseexpr(p);
|
let en: *node = parseexpr(p);
|
||||||
tail.next = en;
|
tail.next = en;
|
||||||
tail = en;
|
tail = en;
|
||||||
if (!accept_tok(p, TK_COMMA)) { break; };
|
if (!accepttok(p, TK_COMMA)) { break; };
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' in tuple");
|
expecttok(p, TK_RPAREN, "expected ')' in tuple");
|
||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RPAREN, "expected ')'");
|
expecttok(p, TK_RPAREN, "expected ')'");
|
||||||
return e;
|
return e;
|
||||||
};
|
};
|
||||||
if (p.cur_kind == TK_IDENT) {
|
if (p.cur_kind == TK_IDENT) {
|
||||||
@@ -338,16 +338,16 @@ fn parseprimary(p: *parser) *node = {
|
|||||||
let fpc: i32 = p.cur_col;
|
let fpc: i32 = p.cur_col;
|
||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
expect_tok(p, TK_ASSIGN, "expected '=' in struct lit field");
|
expecttok(p, TK_ASSIGN, "expected '=' in struct lit field");
|
||||||
let v: *node = parseexpr(p);
|
let v: *node = parseexpr(p);
|
||||||
let f: *node = newnode(p.a, N_FIELD, fpf, fpl, fpc);
|
let f: *node = newnode(p.a, N_FIELD, fpf, fpl, fpc);
|
||||||
f.str = id;
|
f.str = id;
|
||||||
f.lhs = v;
|
f.lhs = v;
|
||||||
if (head == nil) { head = f; tail = f; }
|
if (head == nil) { head = f; tail = f; }
|
||||||
else { tail.next = f; tail = f; };
|
else { tail.next = f; tail = f; };
|
||||||
if (!accept_tok(p, TK_COMMA)) { break; };
|
if (!accepttok(p, TK_COMMA)) { break; };
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RBRACE, "expected '}' after struct literal");
|
expecttok(p, TK_RBRACE, "expected '}' after struct literal");
|
||||||
s.list = head;
|
s.list = head;
|
||||||
return s;
|
return s;
|
||||||
};
|
};
|
||||||
@@ -356,11 +356,11 @@ fn parseprimary(p: *parser) *node = {
|
|||||||
if (p.cur_kind == TK_MATCH) {
|
if (p.cur_kind == TK_MATCH) {
|
||||||
// match (e) { case let v: T => stmt; case T => stmt; case => stmt; };
|
// match (e) { case let v: T => stmt; case T => stmt; case => stmt; };
|
||||||
advance(p);
|
advance(p);
|
||||||
expect_tok(p, TK_LPAREN, "expected '(' after match");
|
expecttok(p, TK_LPAREN, "expected '(' after match");
|
||||||
let m: *node = newnode(p.a, N_MATCH, pf, pl, pc);
|
let m: *node = newnode(p.a, N_MATCH, pf, pl, pc);
|
||||||
m.lhs = parseexpr(p);
|
m.lhs = parseexpr(p);
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' after match scrutinee");
|
expecttok(p, TK_RPAREN, "expected ')' after match scrutinee");
|
||||||
expect_tok(p, TK_LBRACE, "expected '{' to open match body");
|
expecttok(p, TK_LBRACE, "expected '{' to open match body");
|
||||||
let head: *node = nil;
|
let head: *node = nil;
|
||||||
let tail: *node = nil;
|
let tail: *node = nil;
|
||||||
for (p.cur_kind == TK_CASE) {
|
for (p.cur_kind == TK_CASE) {
|
||||||
@@ -374,21 +374,21 @@ fn parseprimary(p: *parser) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
mc.str = id;
|
mc.str = id;
|
||||||
expect_tok(p, TK_COLON, "expected ':' after match binding");
|
expecttok(p, TK_COLON, "expected ':' after match binding");
|
||||||
mc.lhs = parsetype(p);
|
mc.lhs = parsetype(p);
|
||||||
} else { if (p.cur_kind != TK_FATARROW) {
|
} else { if (p.cur_kind != TK_FATARROW) {
|
||||||
mc.lhs = parsetype(p);
|
mc.lhs = parsetype(p);
|
||||||
};};
|
};};
|
||||||
expect_tok(p, TK_FATARROW, "expected '=>' in match arm");
|
expecttok(p, TK_FATARROW, "expected '=>' in match arm");
|
||||||
mc.body = parsestmt(p);
|
mc.body = parsestmt(p);
|
||||||
if (head == nil) { head = mc; tail = mc; }
|
if (head == nil) { head = mc; tail = mc; }
|
||||||
else { tail.next = mc; tail = mc; };
|
else { tail.next = mc; tail = mc; };
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RBRACE, "expected '}' after match body");
|
expecttok(p, TK_RBRACE, "expected '}' after match body");
|
||||||
m.list = head;
|
m.list = head;
|
||||||
return m;
|
return m;
|
||||||
};
|
};
|
||||||
err_msg(p, "expected expression");
|
errmsg(p, "expected expression");
|
||||||
advance(p);
|
advance(p);
|
||||||
return newnode(p.a, N_NONE, pf, pl, pc);
|
return newnode(p.a, N_NONE, pf, pl, pc);
|
||||||
};
|
};
|
||||||
@@ -402,7 +402,7 @@ fn parsearglist(p: *parser, close_kind: i32, head_out: **node) void = {
|
|||||||
let e: *node = parseexpr(p);
|
let e: *node = parseexpr(p);
|
||||||
if (head == nil) { head = e; tail = e; }
|
if (head == nil) { head = e; tail = e; }
|
||||||
else { tail.next = e; tail = e; };
|
else { tail.next = e; tail = e; };
|
||||||
if (!accept_tok(p, TK_COMMA)) { break; };
|
if (!accepttok(p, TK_COMMA)) { break; };
|
||||||
if (p.cur_kind == close_kind) { break; };
|
if (p.cur_kind == close_kind) { break; };
|
||||||
};
|
};
|
||||||
*head_out = head;
|
*head_out = head;
|
||||||
@@ -421,7 +421,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
|
|||||||
let arghead: *node = nil;
|
let arghead: *node = nil;
|
||||||
parsearglist(p, TK_RPAREN, &arghead);
|
parsearglist(p, TK_RPAREN, &arghead);
|
||||||
n.list = arghead;
|
n.list = arghead;
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' after args");
|
expecttok(p, TK_RPAREN, "expected ')' after args");
|
||||||
cur = n;
|
cur = n;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -435,7 +435,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
|
|||||||
if (p.cur_kind != TK_RBRACK) {
|
if (p.cur_kind != TK_RBRACK) {
|
||||||
n.cond = parseexpr(p);
|
n.cond = parseexpr(p);
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RBRACK, "expected ']' in slice");
|
expecttok(p, TK_RBRACK, "expected ']' in slice");
|
||||||
cur = n;
|
cur = n;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -453,14 +453,14 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
|
|||||||
if (p.cur_kind != TK_RBRACK) {
|
if (p.cur_kind != TK_RBRACK) {
|
||||||
n.cond = parseexpr(p);
|
n.cond = parseexpr(p);
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RBRACK, "expected ']' in slice");
|
expecttok(p, TK_RBRACK, "expected ']' in slice");
|
||||||
cur = n;
|
cur = n;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let n: *node = newnode(p.a, N_INDEX, pf, pl, pc);
|
let n: *node = newnode(p.a, N_INDEX, pf, pl, pc);
|
||||||
n.lhs = cur;
|
n.lhs = cur;
|
||||||
n.rhs = e;
|
n.rhs = e;
|
||||||
expect_tok(p, TK_RBRACK, "expected ']' after index");
|
expecttok(p, TK_RBRACK, "expected ']' after index");
|
||||||
cur = n;
|
cur = n;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -581,7 +581,7 @@ fn parseexpr(p: *parser) *node = {
|
|||||||
// (single-cond C-style), expr-stmt, defer, break, continue. Switch
|
// (single-cond C-style), expr-stmt, defer, break, continue. Switch
|
||||||
// and match arms are not yet wired; tuple-let / multi-let neither.
|
// and match arms are not yet wired; tuple-let / multi-let neither.
|
||||||
|
|
||||||
fn parselet_local(p: *parser) *node = {
|
fn parseletlocal(p: *parser) *node = {
|
||||||
let pf: str = p.cur_file;
|
let pf: str = p.cur_file;
|
||||||
let pl: i32 = p.cur_line;
|
let pl: i32 = p.cur_line;
|
||||||
let pc: i32 = p.cur_col;
|
let pc: i32 = p.cur_col;
|
||||||
@@ -590,13 +590,13 @@ fn parselet_local(p: *parser) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
n.str = id;
|
n.str = id;
|
||||||
if (accept_tok(p, TK_COLON)) {
|
if (accepttok(p, TK_COLON)) {
|
||||||
n.lhs = parsetype(p);
|
n.lhs = parsetype(p);
|
||||||
};
|
};
|
||||||
if (accept_tok(p, TK_ASSIGN)) {
|
if (accepttok(p, TK_ASSIGN)) {
|
||||||
n.rhs = parseexpr(p);
|
n.rhs = parseexpr(p);
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after let");
|
expecttok(p, TK_SEMI, "expected ';' after let");
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -604,7 +604,7 @@ fn parseblock(p: *parser) *node = {
|
|||||||
let pf: str = p.cur_file;
|
let pf: str = p.cur_file;
|
||||||
let pl: i32 = p.cur_line;
|
let pl: i32 = p.cur_line;
|
||||||
let pc: i32 = p.cur_col;
|
let pc: i32 = p.cur_col;
|
||||||
expect_tok(p, TK_LBRACE, "expected '{' to open block");
|
expecttok(p, TK_LBRACE, "expected '{' to open block");
|
||||||
let blk: *node = newnode(p.a, N_BLOCK, pf, pl, pc);
|
let blk: *node = newnode(p.a, N_BLOCK, pf, pl, pc);
|
||||||
let head: *node = nil;
|
let head: *node = nil;
|
||||||
let tail: *node = nil;
|
let tail: *node = nil;
|
||||||
@@ -616,7 +616,7 @@ fn parseblock(p: *parser) *node = {
|
|||||||
else { tail.next = s; tail = s; };
|
else { tail.next = s; tail = s; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RBRACE, "expected '}' to close block");
|
expecttok(p, TK_RBRACE, "expected '}' to close block");
|
||||||
blk.list = head;
|
blk.list = head;
|
||||||
return blk;
|
return blk;
|
||||||
};
|
};
|
||||||
@@ -626,12 +626,12 @@ fn parseif(p: *parser) *node = {
|
|||||||
let pl: i32 = p.cur_line;
|
let pl: i32 = p.cur_line;
|
||||||
let pc: i32 = p.cur_col;
|
let pc: i32 = p.cur_col;
|
||||||
advance(p); // past `if`
|
advance(p); // past `if`
|
||||||
expect_tok(p, TK_LPAREN, "expected '(' after if");
|
expecttok(p, TK_LPAREN, "expected '(' after if");
|
||||||
let n: *node = newnode(p.a, N_IF, pf, pl, pc);
|
let n: *node = newnode(p.a, N_IF, pf, pl, pc);
|
||||||
n.cond = parseexpr(p);
|
n.cond = parseexpr(p);
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' after if condition");
|
expecttok(p, TK_RPAREN, "expected ')' after if condition");
|
||||||
n.body = parseblock(p);
|
n.body = parseblock(p);
|
||||||
if (accept_tok(p, TK_ELSE)) {
|
if (accepttok(p, TK_ELSE)) {
|
||||||
if (p.cur_kind == TK_IF) {
|
if (p.cur_kind == TK_IF) {
|
||||||
n.els = parseif(p);
|
n.els = parseif(p);
|
||||||
} else {
|
} else {
|
||||||
@@ -646,7 +646,7 @@ fn parsefor(p: *parser) *node = {
|
|||||||
let pl: i32 = p.cur_line;
|
let pl: i32 = p.cur_line;
|
||||||
let pc: i32 = p.cur_col;
|
let pc: i32 = p.cur_col;
|
||||||
advance(p); // past `for`
|
advance(p); // past `for`
|
||||||
expect_tok(p, TK_LPAREN, "expected '(' after for");
|
expecttok(p, TK_LPAREN, "expected '(' after for");
|
||||||
let n: *node = newnode(p.a, N_FOR, pf, pl, pc);
|
let n: *node = newnode(p.a, N_FOR, pf, pl, pc);
|
||||||
// Three forms (matching C parser):
|
// Three forms (matching C parser):
|
||||||
// for (cond) — only cond
|
// for (cond) — only cond
|
||||||
@@ -657,14 +657,14 @@ fn parsefor(p: *parser) *node = {
|
|||||||
// ';' it was cond. If we see two ';' total after init, post is
|
// ';' it was cond. If we see two ';' total after init, post is
|
||||||
// next. Simpler: peek for `let` to decide init form.
|
// next. Simpler: peek for `let` to decide init form.
|
||||||
if (p.cur_kind == TK_LET) {
|
if (p.cur_kind == TK_LET) {
|
||||||
n.lhs = parselet_local(p); // init (consumes its own ';')
|
n.lhs = parseletlocal(p); // init (consumes its own ';')
|
||||||
n.cond = parseexpr(p);
|
n.cond = parseexpr(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after for cond");
|
expecttok(p, TK_SEMI, "expected ';' after for cond");
|
||||||
n.rhs = parseexpr(p);
|
n.rhs = parseexpr(p);
|
||||||
} else {
|
} else {
|
||||||
// Parse one expr. If next is ';', it's a 3-clause without init.
|
// Parse one expr. If next is ';', it's a 3-clause without init.
|
||||||
let first: *node = parseexpr(p);
|
let first: *node = parseexpr(p);
|
||||||
if (accept_tok(p, TK_SEMI)) {
|
if (accepttok(p, TK_SEMI)) {
|
||||||
// cond ; post
|
// cond ; post
|
||||||
n.cond = first;
|
n.cond = first;
|
||||||
n.rhs = parseexpr(p);
|
n.rhs = parseexpr(p);
|
||||||
@@ -673,7 +673,7 @@ fn parsefor(p: *parser) *node = {
|
|||||||
n.cond = first;
|
n.cond = first;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' after for");
|
expecttok(p, TK_RPAREN, "expected ')' after for");
|
||||||
n.body = parseblock(p);
|
n.body = parseblock(p);
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
@@ -689,18 +689,18 @@ fn parsestmt(p: *parser) *node = {
|
|||||||
|
|
||||||
if (p.cur_kind == TK_LBRACE) {
|
if (p.cur_kind == TK_LBRACE) {
|
||||||
let b: *node = parseblock(p);
|
let b: *node = parseblock(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after block");
|
expecttok(p, TK_SEMI, "expected ';' after block");
|
||||||
return b;
|
return b;
|
||||||
};
|
};
|
||||||
if (p.cur_kind == TK_LET) { return parselet_local(p); };
|
if (p.cur_kind == TK_LET) { return parseletlocal(p); };
|
||||||
if (p.cur_kind == TK_IF) {
|
if (p.cur_kind == TK_IF) {
|
||||||
let n: *node = parseif(p);
|
let n: *node = parseif(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after if");
|
expecttok(p, TK_SEMI, "expected ';' after if");
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
if (p.cur_kind == TK_FOR) {
|
if (p.cur_kind == TK_FOR) {
|
||||||
let n: *node = parsefor(p);
|
let n: *node = parsefor(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after for");
|
expecttok(p, TK_SEMI, "expected ';' after for");
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
if (p.cur_kind == TK_RETURN) {
|
if (p.cur_kind == TK_RETURN) {
|
||||||
@@ -714,7 +714,7 @@ fn parsestmt(p: *parser) *node = {
|
|||||||
let t: *node = newnode(p.a, N_TUPLE, pf, pl, pc);
|
let t: *node = newnode(p.a, N_TUPLE, pf, pl, pc);
|
||||||
t.list = first;
|
t.list = first;
|
||||||
let tail: *node = first;
|
let tail: *node = first;
|
||||||
for (accept_tok(p, TK_COMMA)) {
|
for (accepttok(p, TK_COMMA)) {
|
||||||
let e: *node = parseexpr(p);
|
let e: *node = parseexpr(p);
|
||||||
tail.next = e;
|
tail.next = e;
|
||||||
tail = e;
|
tail = e;
|
||||||
@@ -724,24 +724,24 @@ fn parsestmt(p: *parser) *node = {
|
|||||||
n.lhs = first;
|
n.lhs = first;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after return");
|
expecttok(p, TK_SEMI, "expected ';' after return");
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
if (p.cur_kind == TK_DEFER) {
|
if (p.cur_kind == TK_DEFER) {
|
||||||
advance(p);
|
advance(p);
|
||||||
let n: *node = newnode(p.a, N_DEFER, pf, pl, pc);
|
let n: *node = newnode(p.a, N_DEFER, pf, pl, pc);
|
||||||
n.lhs = parseexpr(p);
|
n.lhs = parseexpr(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after defer");
|
expecttok(p, TK_SEMI, "expected ';' after defer");
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
if (p.cur_kind == TK_BREAK) {
|
if (p.cur_kind == TK_BREAK) {
|
||||||
advance(p);
|
advance(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after break");
|
expecttok(p, TK_SEMI, "expected ';' after break");
|
||||||
return newnode(p.a, N_BREAK, pf, pl, pc);
|
return newnode(p.a, N_BREAK, pf, pl, pc);
|
||||||
};
|
};
|
||||||
if (p.cur_kind == TK_CONTINUE) {
|
if (p.cur_kind == TK_CONTINUE) {
|
||||||
advance(p);
|
advance(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after continue");
|
expecttok(p, TK_SEMI, "expected ';' after continue");
|
||||||
return newnode(p.a, N_CONTINUE, pf, pl, pc);
|
return newnode(p.a, N_CONTINUE, pf, pl, pc);
|
||||||
};
|
};
|
||||||
// expression statement, or tuple-destructure multi-assign:
|
// expression statement, or tuple-destructure multi-assign:
|
||||||
@@ -761,15 +761,15 @@ fn parsestmt(p: *parser) *node = {
|
|||||||
tail.next = lv;
|
tail.next = lv;
|
||||||
tail = lv;
|
tail = lv;
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_ASSIGN, "expected '=' after multi-assign lvalues");
|
expecttok(p, TK_ASSIGN, "expected '=' after multi-assign lvalues");
|
||||||
m.rhs = parseexpr(p);
|
m.rhs = parseexpr(p);
|
||||||
m.list = head;
|
m.list = head;
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after multi-assign");
|
expecttok(p, TK_SEMI, "expected ';' after multi-assign");
|
||||||
return m;
|
return m;
|
||||||
};
|
};
|
||||||
let n: *node = newnode(p.a, N_EXPRSTMT, pf, pl, pc);
|
let n: *node = newnode(p.a, N_EXPRSTMT, pf, pl, pc);
|
||||||
n.lhs = e;
|
n.lhs = e;
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after expression statement");
|
expecttok(p, TK_SEMI, "expected ';' after expression statement");
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -784,7 +784,7 @@ fn parseuse(p: *parser) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
n.str = id;
|
n.str = id;
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after use");
|
expecttok(p, TK_SEMI, "expected ';' after use");
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -797,11 +797,11 @@ fn parsedef(p: *parser, exported: i32) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
n.str = id;
|
n.str = id;
|
||||||
expect_tok(p, TK_COLON, "expected ':' in def");
|
expecttok(p, TK_COLON, "expected ':' in def");
|
||||||
n.lhs = parsetype(p);
|
n.lhs = parsetype(p);
|
||||||
expect_tok(p, TK_ASSIGN, "expected '=' in def");
|
expecttok(p, TK_ASSIGN, "expected '=' in def");
|
||||||
n.rhs = parseexpr(p);
|
n.rhs = parseexpr(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after def");
|
expecttok(p, TK_SEMI, "expected ';' after def");
|
||||||
n.exported = exported;
|
n.exported = exported;
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
@@ -815,13 +815,13 @@ fn parselet(p: *parser, exported: i32) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
n.str = id;
|
n.str = id;
|
||||||
if (accept_tok(p, TK_COLON)) {
|
if (accepttok(p, TK_COLON)) {
|
||||||
n.lhs = parsetype(p);
|
n.lhs = parsetype(p);
|
||||||
};
|
};
|
||||||
if (accept_tok(p, TK_ASSIGN)) {
|
if (accepttok(p, TK_ASSIGN)) {
|
||||||
n.rhs = parseexpr(p);
|
n.rhs = parseexpr(p);
|
||||||
};
|
};
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after let");
|
expecttok(p, TK_SEMI, "expected ';' after let");
|
||||||
n.exported = exported;
|
n.exported = exported;
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
@@ -838,11 +838,11 @@ fn parseattrs(p: *parser) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
a.str = id;
|
a.str = id;
|
||||||
expect_tok(p, TK_LPAREN, "expected '(' after attribute name");
|
expecttok(p, TK_LPAREN, "expected '(' after attribute name");
|
||||||
let arghead: *node = nil;
|
let arghead: *node = nil;
|
||||||
parsearglist(p, TK_RPAREN, &arghead);
|
parsearglist(p, TK_RPAREN, &arghead);
|
||||||
a.list = arghead;
|
a.list = arghead;
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' after attribute args");
|
expecttok(p, TK_RPAREN, "expected ')' after attribute args");
|
||||||
if (head == nil) { head = a; tail = a; }
|
if (head == nil) { head = a; tail = a; }
|
||||||
else { tail.next = a; tail = a; };
|
else { tail.next = a; tail = a; };
|
||||||
};
|
};
|
||||||
@@ -863,11 +863,11 @@ fn parseparams(p: *parser) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
n.str = id;
|
n.str = id;
|
||||||
expect_tok(p, TK_COLON, "expected ':' in parameter");
|
expecttok(p, TK_COLON, "expected ':' in parameter");
|
||||||
n.lhs = parsetype(p);
|
n.lhs = parsetype(p);
|
||||||
if (head == nil) { head = n; tail = n; }
|
if (head == nil) { head = n; tail = n; }
|
||||||
else { tail.next = n; tail = n; };
|
else { tail.next = n; tail = n; };
|
||||||
if (!accept_tok(p, TK_COMMA)) { break; };
|
if (!accepttok(p, TK_COMMA)) { break; };
|
||||||
if (p.cur_kind == TK_RPAREN) { break; };
|
if (p.cur_kind == TK_RPAREN) { break; };
|
||||||
};
|
};
|
||||||
return head;
|
return head;
|
||||||
@@ -882,20 +882,20 @@ fn parsefn(p: *parser, exported: i32, attrs: *node) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
n.str = id;
|
n.str = id;
|
||||||
expect_tok(p, TK_LPAREN, "expected '(' after fn name");
|
expecttok(p, TK_LPAREN, "expected '(' after fn name");
|
||||||
n.list = parseparams(p);
|
n.list = parseparams(p);
|
||||||
expect_tok(p, TK_RPAREN, "expected ')' after params");
|
expecttok(p, TK_RPAREN, "expected ')' after params");
|
||||||
if (p.cur_kind != TK_ASSIGN) {
|
if (p.cur_kind != TK_ASSIGN) {
|
||||||
if (p.cur_kind != TK_SEMI) {
|
if (p.cur_kind != TK_SEMI) {
|
||||||
n.lhs = parsetype(p);
|
n.lhs = parsetype(p);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (accept_tok(p, TK_ASSIGN)) {
|
if (accepttok(p, TK_ASSIGN)) {
|
||||||
n.body = parseblock(p);
|
n.body = parseblock(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after fn body");
|
expecttok(p, TK_SEMI, "expected ';' after fn body");
|
||||||
} else {
|
} else {
|
||||||
// Body-less fn: FFI declaration (`fn name(args) ret;`).
|
// Body-less fn: FFI declaration (`fn name(args) ret;`).
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after fn header");
|
expecttok(p, TK_SEMI, "expected ';' after fn header");
|
||||||
};
|
};
|
||||||
n.exported = exported;
|
n.exported = exported;
|
||||||
n.attr = attrs;
|
n.attr = attrs;
|
||||||
@@ -911,9 +911,9 @@ fn parsetypedecl(p: *parser, exported: i32) *node = {
|
|||||||
let id: str;
|
let id: str;
|
||||||
expectident(p, &id);
|
expectident(p, &id);
|
||||||
n.str = id;
|
n.str = id;
|
||||||
expect_tok(p, TK_ASSIGN, "expected '=' in type decl");
|
expecttok(p, TK_ASSIGN, "expected '=' in type decl");
|
||||||
n.lhs = parsetype(p);
|
n.lhs = parsetype(p);
|
||||||
expect_tok(p, TK_SEMI, "expected ';' after type decl");
|
expecttok(p, TK_SEMI, "expected ';' after type decl");
|
||||||
n.exported = exported;
|
n.exported = exported;
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export fn streq(a: str, b: str) bool = {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn scope_lookup_local(s: *scope, name: str) *sym = {
|
export fn scopelookuplocal(s: *scope, name: str) *sym = {
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
let h: u64 = hashstr(name);
|
let h: u64 = hashstr(name);
|
||||||
let bi: i32 = (h % (s.nbuckets: u64)): i32;
|
let bi: i32 = (h % (s.nbuckets: u64)): i32;
|
||||||
@@ -86,17 +86,17 @@ export fn scope_lookup_local(s: *scope, name: str) *sym = {
|
|||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn scope_lookup(s: *scope, name: str) *sym = {
|
export fn scopelookup(s: *scope, name: str) *sym = {
|
||||||
for (s != nil) {
|
for (s != nil) {
|
||||||
let r: *sym = scope_lookup_local(s, name);
|
let r: *sym = scopelookuplocal(s, name);
|
||||||
if (r != nil) { return r; };
|
if (r != nil) { return r; };
|
||||||
s = s.parent;
|
s = s.parent;
|
||||||
};
|
};
|
||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn scope_define(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = {
|
export fn scopedefine(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = {
|
||||||
if (scope_lookup_local(s, name) != nil) { return nil; };
|
if (scopelookuplocal(s, name) != nil) { return nil; };
|
||||||
let sy: *sym = amalloc(s.a, 80u64): *sym;
|
let sy: *sym = amalloc(s.a, 80u64): *sym;
|
||||||
sy.name = name;
|
sy.name = name;
|
||||||
sy.skind = k;
|
sy.skind = k;
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ type tok = struct {
|
|||||||
|
|
||||||
// ---- keyword lookup ---------------------------------------------------
|
// ---- keyword lookup ---------------------------------------------------
|
||||||
|
|
||||||
fn streq_n(a: *u8, b: str, n: i32) bool = {
|
fn streqn(a: *u8, b: str, n: i32) bool = {
|
||||||
if (b.len != n) { return false; };
|
if (b.len != n) { return false; };
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < n) {
|
for (i < n) {
|
||||||
@@ -148,30 +148,30 @@ fn streq_n(a: *u8, b: str, n: i32) bool = {
|
|||||||
// or TK_NONE if it's an ordinary identifier. Linear search over a
|
// or TK_NONE if it's an ordinary identifier. Linear search over a
|
||||||
// small alphabetised list, matching cmd/wcc/tok.c.
|
// small alphabetised list, matching cmd/wcc/tok.c.
|
||||||
export fn kwlookup(p: *u8, n: i32) i32 = {
|
export fn kwlookup(p: *u8, n: i32) i32 = {
|
||||||
if (streq_n(p, "as", n)) { return TK_AS; };
|
if (streqn(p, "as", n)) { return TK_AS; };
|
||||||
if (streq_n(p, "break", n)) { return TK_BREAK; };
|
if (streqn(p, "break", n)) { return TK_BREAK; };
|
||||||
if (streq_n(p, "case", n)) { return TK_CASE; };
|
if (streqn(p, "case", n)) { return TK_CASE; };
|
||||||
if (streq_n(p, "chan", n)) { return TK_CHAN; };
|
if (streqn(p, "chan", n)) { return TK_CHAN; };
|
||||||
if (streq_n(p, "continue", n)) { return TK_CONTINUE; };
|
if (streqn(p, "continue", n)) { return TK_CONTINUE; };
|
||||||
if (streq_n(p, "def", n)) { return TK_DEF; };
|
if (streqn(p, "def", n)) { return TK_DEF; };
|
||||||
if (streq_n(p, "defer", n)) { return TK_DEFER; };
|
if (streqn(p, "defer", n)) { return TK_DEFER; };
|
||||||
if (streq_n(p, "else", n)) { return TK_ELSE; };
|
if (streqn(p, "else", n)) { return TK_ELSE; };
|
||||||
if (streq_n(p, "export", n)) { return TK_EXPORT; };
|
if (streqn(p, "export", n)) { return TK_EXPORT; };
|
||||||
if (streq_n(p, "false", n)) { return TK_FALSE; };
|
if (streqn(p, "false", n)) { return TK_FALSE; };
|
||||||
if (streq_n(p, "fn", n)) { return TK_FN; };
|
if (streqn(p, "fn", n)) { return TK_FN; };
|
||||||
if (streq_n(p, "for", n)) { return TK_FOR; };
|
if (streqn(p, "for", n)) { return TK_FOR; };
|
||||||
if (streq_n(p, "if", n)) { return TK_IF; };
|
if (streqn(p, "if", n)) { return TK_IF; };
|
||||||
if (streq_n(p, "let", n)) { return TK_LET; };
|
if (streqn(p, "let", n)) { return TK_LET; };
|
||||||
if (streq_n(p, "match", n)) { return TK_MATCH; };
|
if (streqn(p, "match", n)) { return TK_MATCH; };
|
||||||
if (streq_n(p, "nil", n)) { return TK_NIL; };
|
if (streqn(p, "nil", n)) { return TK_NIL; };
|
||||||
if (streq_n(p, "proc", n)) { return TK_PROC; };
|
if (streqn(p, "proc", n)) { return TK_PROC; };
|
||||||
if (streq_n(p, "return", n)) { return TK_RETURN; };
|
if (streqn(p, "return", n)) { return TK_RETURN; };
|
||||||
if (streq_n(p, "static", n)) { return TK_STATIC; };
|
if (streqn(p, "static", n)) { return TK_STATIC; };
|
||||||
if (streq_n(p, "struct", n)) { return TK_STRUCT; };
|
if (streqn(p, "struct", n)) { return TK_STRUCT; };
|
||||||
if (streq_n(p, "switch", n)) { return TK_SWITCH; };
|
if (streqn(p, "switch", n)) { return TK_SWITCH; };
|
||||||
if (streq_n(p, "true", n)) { return TK_TRUE; };
|
if (streqn(p, "true", n)) { return TK_TRUE; };
|
||||||
if (streq_n(p, "type", n)) { return TK_TYPE; };
|
if (streqn(p, "type", n)) { return TK_TYPE; };
|
||||||
if (streq_n(p, "use", n)) { return TK_USE; };
|
if (streqn(p, "use", n)) { return TK_USE; };
|
||||||
return TK_NONE;
|
return TK_NONE;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -278,13 +278,13 @@ export fn tokname(k: i32) str = {
|
|||||||
// fputq mirrors cmd/wcc/tok.c:fputq — quote the string with C-style
|
// fputq mirrors cmd/wcc/tok.c:fputq — quote the string with C-style
|
||||||
// escapes for \, ", \n, \t, \r and \xNN for other non-printables.
|
// escapes for \, ", \n, \t, \r and \xNN for other non-printables.
|
||||||
|
|
||||||
fn fputc_byte(fd: i32, b: u8) void = {
|
fn fputcbyte(fd: i32, b: u8) void = {
|
||||||
let buf: [1]u8;
|
let buf: [1]u8;
|
||||||
buf[0] = b;
|
buf[0] = b;
|
||||||
os.write(fd, buf.ptr, 1u64);
|
os.write(fd, buf.ptr, 1u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn fputs_str(fd: i32, s: str) void = {
|
fn fputsstr(fd: i32, s: str) void = {
|
||||||
os.write(fd, s.ptr, s.len: u64);
|
os.write(fd, s.ptr, s.len: u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -303,24 +303,24 @@ fn fputhex2(fd: i32, b: u8) void = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn fputq(fd: i32, p: *u8, n: i32) void = {
|
fn fputq(fd: i32, p: *u8, n: i32) void = {
|
||||||
fputc_byte(fd, 34u8); // '"'
|
fputcbyte(fd, 34u8); // '"'
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < n) {
|
for (i < n) {
|
||||||
let c: u8 = p[i];
|
let c: u8 = p[i];
|
||||||
if (c == 92u8) { // '\\'
|
if (c == 92u8) { // '\\'
|
||||||
fputs_str(fd, "\\\\");
|
fputsstr(fd, "\\\\");
|
||||||
} else {
|
} else {
|
||||||
if (c == 34u8) { // '"'
|
if (c == 34u8) { // '"'
|
||||||
fputs_str(fd, "\\\"");
|
fputsstr(fd, "\\\"");
|
||||||
} else {
|
} else {
|
||||||
if (c == 10u8) { // '\n'
|
if (c == 10u8) { // '\n'
|
||||||
fputs_str(fd, "\\n");
|
fputsstr(fd, "\\n");
|
||||||
} else {
|
} else {
|
||||||
if (c == 9u8) { // '\t'
|
if (c == 9u8) { // '\t'
|
||||||
fputs_str(fd, "\\t");
|
fputsstr(fd, "\\t");
|
||||||
} else {
|
} else {
|
||||||
if (c == 13u8) { // '\r'
|
if (c == 13u8) { // '\r'
|
||||||
fputs_str(fd, "\\r");
|
fputsstr(fd, "\\r");
|
||||||
} else {
|
} else {
|
||||||
if (c < 32u8) {
|
if (c < 32u8) {
|
||||||
fputhex2(fd, c);
|
fputhex2(fd, c);
|
||||||
@@ -328,7 +328,7 @@ fn fputq(fd: i32, p: *u8, n: i32) void = {
|
|||||||
if (c == 127u8) {
|
if (c == 127u8) {
|
||||||
fputhex2(fd, c);
|
fputhex2(fd, c);
|
||||||
} else {
|
} else {
|
||||||
fputc_byte(fd, c);
|
fputcbyte(fd, c);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -338,7 +338,7 @@ fn fputq(fd: i32, p: *u8, n: i32) void = {
|
|||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
fputc_byte(fd, 34u8);
|
fputcbyte(fd, 34u8);
|
||||||
};
|
};
|
||||||
|
|
||||||
// tokprint — write one token line to fd. Format must match
|
// tokprint — write one token line to fd. Format must match
|
||||||
@@ -354,35 +354,35 @@ export fn tokprint(fd: i32, t: *tok) void = {
|
|||||||
let tfile: str = t.file;
|
let tfile: str = t.file;
|
||||||
let ttext: str = t.text;
|
let ttext: str = t.text;
|
||||||
if (tfile.len > 0) {
|
if (tfile.len > 0) {
|
||||||
fputs_str(fd, tfile);
|
fputsstr(fd, tfile);
|
||||||
} else {
|
} else {
|
||||||
fputs_str(fd, "<none>");
|
fputsstr(fd, "<none>");
|
||||||
};
|
};
|
||||||
fputc_byte(fd, 58u8); // ':'
|
fputcbyte(fd, 58u8); // ':'
|
||||||
let buf: [32]u8;
|
let buf: [32]u8;
|
||||||
let n: i32 = strconv.i64toa(buf[0:32], t.line: i64);
|
let n: i32 = strconv.i64toa(buf[0:32], t.line: i64);
|
||||||
os.write(fd, buf.ptr, n: u64);
|
os.write(fd, buf.ptr, n: u64);
|
||||||
fputc_byte(fd, 58u8);
|
fputcbyte(fd, 58u8);
|
||||||
n = strconv.i64toa(buf[0:32], t.col: i64);
|
n = strconv.i64toa(buf[0:32], t.col: i64);
|
||||||
os.write(fd, buf.ptr, n: u64);
|
os.write(fd, buf.ptr, n: u64);
|
||||||
fputc_byte(fd, 32u8); // ' '
|
fputcbyte(fd, 32u8); // ' '
|
||||||
fputs_str(fd, tokname(t.kind));
|
fputsstr(fd, tokname(t.kind));
|
||||||
|
|
||||||
if (t.kind == TK_IDENT) {
|
if (t.kind == TK_IDENT) {
|
||||||
fputc_byte(fd, 32u8);
|
fputcbyte(fd, 32u8);
|
||||||
fputq(fd, ttext.ptr, ttext.len);
|
fputq(fd, ttext.ptr, ttext.len);
|
||||||
} else { if (t.kind == TK_STR) {
|
} else { if (t.kind == TK_STR) {
|
||||||
fputc_byte(fd, 32u8);
|
fputcbyte(fd, 32u8);
|
||||||
fputq(fd, ttext.ptr, ttext.len);
|
fputq(fd, ttext.ptr, ttext.len);
|
||||||
} else { if (t.kind == TK_ERR) {
|
} else { if (t.kind == TK_ERR) {
|
||||||
fputc_byte(fd, 32u8);
|
fputcbyte(fd, 32u8);
|
||||||
fputq(fd, ttext.ptr, ttext.len);
|
fputq(fd, ttext.ptr, ttext.len);
|
||||||
} else { if (t.kind == TK_INT) {
|
} else { if (t.kind == TK_INT) {
|
||||||
fputc_byte(fd, 32u8);
|
fputcbyte(fd, 32u8);
|
||||||
n = strconv.u64toa(buf[0:32], t.uval);
|
n = strconv.u64toa(buf[0:32], t.uval);
|
||||||
os.write(fd, buf.ptr, n: u64);
|
os.write(fd, buf.ptr, n: u64);
|
||||||
} else { if (t.kind == TK_RUNE) {
|
} else { if (t.kind == TK_RUNE) {
|
||||||
fputc_byte(fd, 32u8);
|
fputcbyte(fd, 32u8);
|
||||||
n = strconv.u64toa(buf[0:32], t.uval);
|
n = strconv.u64toa(buf[0:32], t.uval);
|
||||||
os.write(fd, buf.ptr, n: u64);
|
os.write(fd, buf.ptr, n: u64);
|
||||||
};};};};};
|
};};};};};
|
||||||
@@ -390,5 +390,5 @@ export fn tokprint(fd: i32, t: *tok) void = {
|
|||||||
// won't byte-match across implementations. Diff fixtures must
|
// won't byte-match across implementations. Diff fixtures must
|
||||||
// be float-free until we implement a stable float formatter.
|
// be float-free until we implement a stable float formatter.
|
||||||
|
|
||||||
fputc_byte(fd, 10u8); // '\n'
|
fputcbyte(fd, 10u8); // '\n'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ export fn typesinit(c: *tctx, a: *arena) void = {
|
|||||||
c.ty_untyped_nil = prim(a, TY_UNTYPED_NIL, "untyped_nil", 0u64, 1u64);
|
c.ty_untyped_nil = prim(a, TY_UNTYPED_NIL, "untyped_nil", 0u64, 1u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_ptr(a: *arena, sub: *tinfo) *tinfo = {
|
export fn typeptr(a: *arena, sub: *tinfo) *tinfo = {
|
||||||
let t: *tinfo = newtype(a, TY_PTR);
|
let t: *tinfo = newtype(a, TY_PTR);
|
||||||
t.sub = sub;
|
t.sub = sub;
|
||||||
t.size = 8u64;
|
t.size = 8u64;
|
||||||
@@ -161,7 +161,7 @@ export fn type_ptr(a: *arena, sub: *tinfo) *tinfo = {
|
|||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_slice(a: *arena, sub: *tinfo) *tinfo = {
|
export fn typeslice(a: *arena, sub: *tinfo) *tinfo = {
|
||||||
let t: *tinfo = newtype(a, TY_SLICE);
|
let t: *tinfo = newtype(a, TY_SLICE);
|
||||||
t.sub = sub;
|
t.sub = sub;
|
||||||
t.size = 24u64;
|
t.size = 24u64;
|
||||||
@@ -169,7 +169,7 @@ export fn type_slice(a: *arena, sub: *tinfo) *tinfo = {
|
|||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_array(a: *arena, sub: *tinfo, n: u64) *tinfo = {
|
export fn typearray(a: *arena, sub: *tinfo, n: u64) *tinfo = {
|
||||||
let t: *tinfo = newtype(a, TY_ARRAY);
|
let t: *tinfo = newtype(a, TY_ARRAY);
|
||||||
t.sub = sub;
|
t.sub = sub;
|
||||||
t.alen = n;
|
t.alen = n;
|
||||||
@@ -182,7 +182,7 @@ export fn type_array(a: *arena, sub: *tinfo, n: u64) *tinfo = {
|
|||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_chan(a: *arena, sub: *tinfo) *tinfo = {
|
export fn typechan(a: *arena, sub: *tinfo) *tinfo = {
|
||||||
let t: *tinfo = newtype(a, TY_CHAN);
|
let t: *tinfo = newtype(a, TY_CHAN);
|
||||||
t.sub = sub;
|
t.sub = sub;
|
||||||
t.size = 8u64;
|
t.size = 8u64;
|
||||||
@@ -190,7 +190,7 @@ export fn type_chan(a: *arena, sub: *tinfo) *tinfo = {
|
|||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_named(a: *arena, name: str, under: *tinfo) *tinfo = {
|
export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = {
|
||||||
let t: *tinfo = newtype(a, TY_NAMED);
|
let t: *tinfo = newtype(a, TY_NAMED);
|
||||||
t.name = name;
|
t.name = name;
|
||||||
t.under = under;
|
t.under = under;
|
||||||
@@ -203,7 +203,7 @@ export fn type_named(a: *arena, name: str, under: *tinfo) *tinfo = {
|
|||||||
|
|
||||||
// ---- predicates -------------------------------------------------------
|
// ---- predicates -------------------------------------------------------
|
||||||
|
|
||||||
export fn type_isint(t: *tinfo) bool = {
|
export fn typeisint(t: *tinfo) bool = {
|
||||||
if (t == nil) { return false; };
|
if (t == nil) { return false; };
|
||||||
let k: i32 = t.kind;
|
let k: i32 = t.kind;
|
||||||
if (k == TY_I8) { return true; };
|
if (k == TY_I8) { return true; };
|
||||||
@@ -220,26 +220,26 @@ export fn type_isint(t: *tinfo) bool = {
|
|||||||
if (k == TY_RUNE){ return true; };
|
if (k == TY_RUNE){ return true; };
|
||||||
if (k == TY_UNTYPED_INT) { return true; };
|
if (k == TY_UNTYPED_INT) { return true; };
|
||||||
if (k == TY_UNTYPED_RUNE) { return true; };
|
if (k == TY_UNTYPED_RUNE) { return true; };
|
||||||
if (k == TY_NAMED) { return type_isint(t.under); };
|
if (k == TY_NAMED) { return typeisint(t.under); };
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_isfloat(t: *tinfo) bool = {
|
export fn typeisfloat(t: *tinfo) bool = {
|
||||||
if (t == nil) { return false; };
|
if (t == nil) { return false; };
|
||||||
let k: i32 = t.kind;
|
let k: i32 = t.kind;
|
||||||
if (k == TY_F32) { return true; };
|
if (k == TY_F32) { return true; };
|
||||||
if (k == TY_F64) { return true; };
|
if (k == TY_F64) { return true; };
|
||||||
if (k == TY_UNTYPED_FLOAT) { return true; };
|
if (k == TY_UNTYPED_FLOAT) { return true; };
|
||||||
if (k == TY_NAMED) { return type_isfloat(t.under); };
|
if (k == TY_NAMED) { return typeisfloat(t.under); };
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_isnum(t: *tinfo) bool = {
|
export fn typeisnum(t: *tinfo) bool = {
|
||||||
if (type_isint(t)) { return true; };
|
if (typeisint(t)) { return true; };
|
||||||
return type_isfloat(t);
|
return typeisfloat(t);
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_isunsigned(t: *tinfo) bool = {
|
export fn typeisunsigned(t: *tinfo) bool = {
|
||||||
if (t == nil) { return false; };
|
if (t == nil) { return false; };
|
||||||
let k: i32 = t.kind;
|
let k: i32 = t.kind;
|
||||||
if (k == TY_U8) { return true; };
|
if (k == TY_U8) { return true; };
|
||||||
@@ -248,11 +248,11 @@ export fn type_isunsigned(t: *tinfo) bool = {
|
|||||||
if (k == TY_U64) { return true; };
|
if (k == TY_U64) { return true; };
|
||||||
if (k == TY_UINT){ return true; };
|
if (k == TY_UINT){ return true; };
|
||||||
if (k == TY_UINTPTR) { return true; };
|
if (k == TY_UINTPTR) { return true; };
|
||||||
if (k == TY_NAMED) { return type_isunsigned(t.under); };
|
if (k == TY_NAMED) { return typeisunsigned(t.under); };
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn type_isuntyped(t: *tinfo) bool = {
|
export fn typeisuntyped(t: *tinfo) bool = {
|
||||||
if (t == nil) { return false; };
|
if (t == nil) { return false; };
|
||||||
let k: i32 = t.kind;
|
let k: i32 = t.kind;
|
||||||
if (k == TY_UNTYPED_INT) { return true; };
|
if (k == TY_UNTYPED_INT) { return true; };
|
||||||
@@ -264,29 +264,29 @@ export fn type_isuntyped(t: *tinfo) bool = {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// type_eq — structural equality. Named types compare nominally.
|
// typeeq — structural equality. Named types compare nominally.
|
||||||
export fn type_eq(a: *tinfo, b: *tinfo) bool = {
|
export fn typeeq(a: *tinfo, b: *tinfo) bool = {
|
||||||
if (a == b) { return true; };
|
if (a == b) { return true; };
|
||||||
if (a == nil) { return false; };
|
if (a == nil) { return false; };
|
||||||
if (b == nil) { return false; };
|
if (b == nil) { return false; };
|
||||||
if (a.kind != b.kind) { return false; };
|
if (a.kind != b.kind) { return false; };
|
||||||
let k: i32 = a.kind;
|
let k: i32 = a.kind;
|
||||||
if (k == TY_PTR) { return type_eq(a.sub, b.sub); };
|
if (k == TY_PTR) { return typeeq(a.sub, b.sub); };
|
||||||
if (k == TY_SLICE) { return type_eq(a.sub, b.sub); };
|
if (k == TY_SLICE) { return typeeq(a.sub, b.sub); };
|
||||||
if (k == TY_CHAN) { return type_eq(a.sub, b.sub); };
|
if (k == TY_CHAN) { return typeeq(a.sub, b.sub); };
|
||||||
if (k == TY_ARRAY) {
|
if (k == TY_ARRAY) {
|
||||||
if (a.alen != b.alen) { return false; };
|
if (a.alen != b.alen) { return false; };
|
||||||
return type_eq(a.sub, b.sub);
|
return typeeq(a.sub, b.sub);
|
||||||
};
|
};
|
||||||
if (k == TY_FN) {
|
if (k == TY_FN) {
|
||||||
if (a.variadic != b.variadic) { return false; };
|
if (a.variadic != b.variadic) { return false; };
|
||||||
if (!type_eq(a.ret, b.ret)) { return false; };
|
if (!typeeq(a.ret, b.ret)) { return false; };
|
||||||
let pa: *tparam = a.params;
|
let pa: *tparam = a.params;
|
||||||
let pb: *tparam = b.params;
|
let pb: *tparam = b.params;
|
||||||
for (true) {
|
for (true) {
|
||||||
if (pa == nil) { if (pb == nil) { return true; }; return false; };
|
if (pa == nil) { if (pb == nil) { return true; }; return false; };
|
||||||
if (pb == nil) { return false; };
|
if (pb == nil) { return false; };
|
||||||
if (!type_eq(pa.type_, pb.type_)) { return false; };
|
if (!typeeq(pa.type_, pb.type_)) { return false; };
|
||||||
pa = pa.tnext;
|
pa = pa.tnext;
|
||||||
pb = pb.tnext;
|
pb = pb.tnext;
|
||||||
};
|
};
|
||||||
@@ -306,7 +306,7 @@ export fn type_eq(a: *tinfo, b: *tinfo) bool = {
|
|||||||
if (na[i] != nb[i]) { return false; };
|
if (na[i] != nb[i]) { return false; };
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
if (!type_eq(fa.type_, fb.type_)) { return false; };
|
if (!typeeq(fa.type_, fb.type_)) { return false; };
|
||||||
fa = fa.tnext;
|
fa = fa.tnext;
|
||||||
fb = fb.tnext;
|
fb = fb.tnext;
|
||||||
};
|
};
|
||||||
@@ -319,7 +319,7 @@ export fn type_eq(a: *tinfo, b: *tinfo) bool = {
|
|||||||
for (true) {
|
for (true) {
|
||||||
if (pa == nil) { if (pb == nil) { return true; }; return false; };
|
if (pa == nil) { if (pb == nil) { return true; }; return false; };
|
||||||
if (pb == nil) { return false; };
|
if (pb == nil) { return false; };
|
||||||
if (!type_eq(pa.type_, pb.type_)) { return false; };
|
if (!typeeq(pa.type_, pb.type_)) { return false; };
|
||||||
pa = pa.tnext;
|
pa = pa.tnext;
|
||||||
pb = pb.tnext;
|
pb = pb.tnext;
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -125,10 +125,10 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
let tc: tctx;
|
let tc: tctx;
|
||||||
typesinit(&tc, a);
|
typesinit(&tc, a);
|
||||||
let ck: checker;
|
let ck: checker;
|
||||||
check_init(&ck, a, &tc);
|
checkinit(&ck, a, &tc);
|
||||||
// Quiet by default; flip to 1 when debugging missing names.
|
// Quiet by default; flip to 1 when debugging missing names.
|
||||||
ck.verbose = 0;
|
ck.verbose = 0;
|
||||||
check_file(&ck, f);
|
checkfile(&ck, f);
|
||||||
// (close out the if-else chain — we'll close all braces below)
|
// (close out the if-else chain — we'll close all braces below)
|
||||||
// "<file>: <resolved>/<resolved+unresolved> resolved"
|
// "<file>: <resolved>/<resolved+unresolved> resolved"
|
||||||
os.write(1, argstr(path).ptr, argstrlen(path): u64);
|
os.write(1, argstr(path).ptr, argstrlen(path): u64);
|
||||||
@@ -147,8 +147,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
parserinit(&ps, a, &l);
|
parserinit(&ps, a, &l);
|
||||||
let f: *node = parsefile(&ps);
|
let f: *node = parsefile(&ps);
|
||||||
let cg: cgen;
|
let cg: cgen;
|
||||||
cgen_init(&cg, a);
|
cgeninit(&cg, a);
|
||||||
cg_file(&cg, f);
|
cgfile(&cg, f);
|
||||||
};};};};
|
};};};};
|
||||||
|
|
||||||
if (l.errs > 0) { return 1; };
|
if (l.errs > 0) { return 1; };
|
||||||
|
|||||||
@@ -16,28 +16,28 @@ export fn main() i32 = {
|
|||||||
if (s == nil) { return 2; };
|
if (s == nil) { return 2; };
|
||||||
|
|
||||||
let n1: str = "foo";
|
let n1: str = "foo";
|
||||||
let r1: *sym = scope_define(s, n1, SK_VAR, nil, nil);
|
let r1: *sym = scopedefine(s, n1, SK_VAR, nil, nil);
|
||||||
if (r1 == nil) { return 3; };
|
if (r1 == nil) { return 3; };
|
||||||
|
|
||||||
let n2: str = "bar";
|
let n2: str = "bar";
|
||||||
let r2: *sym = scope_define(s, n2, SK_TYPE, nil, nil);
|
let r2: *sym = scopedefine(s, n2, SK_TYPE, nil, nil);
|
||||||
if (r2 == nil) { return 4; };
|
if (r2 == nil) { return 4; };
|
||||||
|
|
||||||
// Duplicate define in same scope must fail.
|
// Duplicate define in same scope must fail.
|
||||||
let r3: *sym = scope_define(s, n1, SK_VAR, nil, nil);
|
let r3: *sym = scopedefine(s, n1, SK_VAR, nil, nil);
|
||||||
if (r3 != nil) { return 5; };
|
if (r3 != nil) { return 5; };
|
||||||
|
|
||||||
let l1: *sym = scope_lookup(s, n1);
|
let l1: *sym = scopelookup(s, n1);
|
||||||
if (l1 == nil) { return 6; };
|
if (l1 == nil) { return 6; };
|
||||||
if (l1.skind != SK_VAR) { return 7; };
|
if (l1.skind != SK_VAR) { return 7; };
|
||||||
|
|
||||||
let l2: *sym = scope_lookup(s, n2);
|
let l2: *sym = scopelookup(s, n2);
|
||||||
if (l2 == nil) { return 8; };
|
if (l2 == nil) { return 8; };
|
||||||
if (l2.skind != SK_TYPE) { return 9; };
|
if (l2.skind != SK_TYPE) { return 9; };
|
||||||
|
|
||||||
// Not-found lookup returns nil.
|
// Not-found lookup returns nil.
|
||||||
let n3: str = "baz";
|
let n3: str = "baz";
|
||||||
let l3: *sym = scope_lookup(s, n3);
|
let l3: *sym = scopelookup(s, n3);
|
||||||
if (l3 != nil) { return 10; };
|
if (l3 != nil) { return 10; };
|
||||||
|
|
||||||
freearena(a);
|
freearena(a);
|
||||||
|
|||||||
Reference in New Issue
Block a user