# check_env.ludic — L4: the checker's scopes and its errors. A scope is a mark in one list of # (name, type) pairs; a lookup walks it from the end, so an inner name hides an outer one. var ck_names: []pointer = new []pointer var ck_tys: []pointer = new []pointer var ck_ret: pointer = "void" # the result type of the function being checked var ck_fn_node: Node = null # the function being checked (27.1: a machine's own may set its field) var ck_mem_node: Node = null # the member expression ck_member typed last, and its base's type var ck_mem_base: pointer = null var ck_errors: int = 0 var ck_report: int = -1 # LUDIC_CHECK_REPORT=1: list every mix-up by category, fail nothing var ck_top: int = 0 # the scope stack's height; the lists only grow function ck_bind(name: pointer, ty: pointer) -> void { var t = ty if (t == "null") or t == null { t = "?" } if ck_top < len(ck_names) { ck_names[ck_top] = name ck_tys[ck_top] = t } else { push(ck_names, name) push(ck_tys, t) } ck_top += 1 ck_set_ro(false) } function ck_mark() -> int { return ck_top } function ck_pop(m: int) -> void { ck_top = m } function ck_local(name: pointer) -> int { var i = ck_top - 1 while i >= 0 { if ck_names[i] == name { return i } i -= 1 } return -1 } function ck_reporting() -> bool { if ck_report < 0 { ck_report = 0 if getenv("LUDIC_CHECK_REPORT") != null { ck_report = 1 } } return ck_report == 1 } # every mix-up is reported, not only the first: a type change shows everything it breaks at once function ck_err(cat: pointer, n: Node, msg: pointer) -> void { var file: pointer = "" var line = 0 var col = 0 if n != null { if n.file != null { file = n.file } line = n.line col = n.col } if g_diag_json and not ck_reporting() { diag_add(file, line, col, "error", msg) ck_errors += 1 return } var m = `{file}:{itoa(line)}: error: {msg}\n` if ck_reporting() { m = `check[{cat}]: {file}:{itoa(line)}: {msg}\n` } file_write(file_stderr(), m, len(m)) ck_errors += 1 } # a value given where a type is wanted: `what` says where ("argument 2 of f", "x") function ck_give(to: pointer, from: pointer, e: Node, what: pointer) -> void { # a literal past 2^31 - 1 given to an int would lose its value: say so, rather than wrap it if e != null and e.kind == E_INT and e.s != null and ((to == "int") or (to == "byte") or (to == "fixed")) { ck_err("literal", e, `{what} wants {ck_a(to)} and {e.s} does not fit one; it is a long`) return } let cat = ck_mismatch(to, from, e) if cat == null { return } if (cat == "slice-pointer") { ck_err(cat, e, `{what} wants a pointer and this is {ck_a(from)}: take the slice itself, or data_of(xs) in unsafe code`) return } if (cat == "pointer-slice") { ck_err(cat, e, `{what} wants {ck_a(to)} and this is a pointer: a slice is made with words(n), floats(n) or new, not from an address`) return } if (cat == "key") and ck_is_key(to) { ck_err(cat, e, `{what} wants a Key and this is {ck_a(from)}: a key is written k"module.purpose" (kn"..." for a plural)`) return } if (cat == "key") { ck_err(cat, e, `{what} wants {ck_a(to)} and this is a Key: text is made from a key (tr(key)), never the key itself`) return } ck_err(cat, e, `{what} wants {ck_a(to)} and this is {ck_a(from)}`) }