# 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_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 } 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 if n != null { if n.file != null { file = n.file } line = n.line } 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 } ck_err(cat, e, `{what} wants {ck_a(to)} and this is {ck_a(from)}`) }