Archived
iteration-1: the compiler stops adjudicating #164
@@ -1517,6 +1517,16 @@ fn cg_stmt(stmt: Map<String, Any>, indent: String, declared: [String]) -> [Strin
|
|||||||
if str_eq(ltype, "Int") {
|
if str_eq(ltype, "Int") {
|
||||||
add_int_name(name)
|
add_int_name(name)
|
||||||
}
|
}
|
||||||
|
// UNANNOTATED let: take the type from what the initialiser RETURNS.
|
||||||
|
// Without this, `let a = str_len(s)` loses the Int and a later `a + b`
|
||||||
|
// lowers to el_str_concat on two integers -- silently, with no error,
|
||||||
|
// producing a program that prints nothing where it should print 7.
|
||||||
|
// Verified present in the pre-change compiler too, so this is a repair
|
||||||
|
// rather than a regression. The return types were already needed for
|
||||||
|
// dispatch; they were just never consulted here.
|
||||||
|
if str_eq(ltype, "") {
|
||||||
|
if is_int_expr(val) { add_int_name(name) }
|
||||||
|
}
|
||||||
// Same as params: Bool is an int in the value model. Without this a
|
// Same as params: Bool is an int in the value model. Without this a
|
||||||
// `let ok: Bool = ...` compared to another Bool lowered to str_eq.
|
// `let ok: Bool = ...` compared to another Bool lowered to str_eq.
|
||||||
if str_eq(ltype, "Bool") {
|
if str_eq(ltype, "Bool") {
|
||||||
@@ -1943,48 +1953,10 @@ fn is_duration_name(name: String) -> Bool {
|
|||||||
// string-concat on `+` when one side is a Call. New builtins must be added
|
// string-concat on `+` when one side is a Call. New builtins must be added
|
||||||
// here when they return Int and may participate in arithmetic.
|
// here when they return Int and may participate in arithmetic.
|
||||||
fn is_int_call(call_expr: Map<String, Any>) -> Bool {
|
fn is_int_call(call_expr: Map<String, Any>) -> Bool {
|
||||||
let func = call_expr["func"]
|
call_returns(call_expr, "Int")
|
||||||
let fk: String = func["expr"]
|
|
||||||
if !str_eq(fk, "Ident") { return false }
|
|
||||||
let name: String = func["name"]
|
|
||||||
if str_eq(name, "str_len") { return true }
|
|
||||||
if str_eq(name, "str_index_of") { return true }
|
|
||||||
if str_eq(name, "str_to_int") { return true }
|
|
||||||
if str_eq(name, "str_char_code") { return true }
|
|
||||||
if str_eq(name, "str_count") { return true }
|
|
||||||
if str_eq(name, "str_count_chars") { return true }
|
|
||||||
if str_eq(name, "str_count_bytes") { return true }
|
|
||||||
if str_eq(name, "str_count_lines") { return true }
|
|
||||||
if str_eq(name, "str_count_words") { return true }
|
|
||||||
if str_eq(name, "str_count_letters") { return true }
|
|
||||||
if str_eq(name, "str_count_digits") { return true }
|
|
||||||
if str_eq(name, "str_last_index_of") { return true }
|
|
||||||
if str_eq(name, "str_find_chars") { return true }
|
|
||||||
if str_eq(name, "native_list_len") { return true }
|
|
||||||
if str_eq(name, "el_list_len") { return true }
|
|
||||||
if str_eq(name, "len") { return true }
|
|
||||||
if str_eq(name, "json_get_int") { return true }
|
|
||||||
if str_eq(name, "json_array_len") { return true }
|
|
||||||
if str_eq(name, "engram_node_count") { return true }
|
|
||||||
if str_eq(name, "engram_edge_count") { return true }
|
|
||||||
if str_eq(name, "time_now") { return true }
|
|
||||||
if str_eq(name, "time_now_utc") { return true }
|
|
||||||
if str_eq(name, "time_diff") { return true }
|
|
||||||
if str_eq(name, "time_add") { return true }
|
|
||||||
if str_eq(name, "time_from_parts") { return true }
|
|
||||||
if str_eq(name, "el_abs") { return true }
|
|
||||||
if str_eq(name, "el_max") { return true }
|
|
||||||
if str_eq(name, "el_min") { return true }
|
|
||||||
if str_eq(name, "float_to_int") { return true }
|
|
||||||
if str_eq(name, "unix_timestamp") { return true }
|
|
||||||
if str_eq(name, "instant_to_unix_seconds") { return true }
|
|
||||||
if str_eq(name, "instant_to_unix_millis") { return true }
|
|
||||||
if str_eq(name, "duration_to_seconds") { return true }
|
|
||||||
if str_eq(name, "duration_to_millis") { return true }
|
|
||||||
if str_eq(name, "duration_to_nanos") { return true }
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Known runtime builtins that return Float. Parallel to is_int_call — lets a
|
// Known runtime builtins that return Float. Parallel to is_int_call — lets a
|
||||||
// Call participate in float arithmetic (and get inferred into __float_names on
|
// Call participate in float arithmetic (and get inferred into __float_names on
|
||||||
// an unannotated `let`). New Float-returning builtins must be added here.
|
// an unannotated `let`). New Float-returning builtins must be added here.
|
||||||
|
|||||||
@@ -924,3 +924,22 @@ test "compiler-no-longer-emits-prohibition-errors" {
|
|||||||
let out: String = compile_capture(src)
|
let out: String = compile_capture(src)
|
||||||
assert !str_contains(out, "boundary violation"), "the emitter does not adjudicate"
|
assert !str_contains(out, "boundary violation"), "the emitter does not adjudicate"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Int return types drive + dispatch ────────────────────────────────────────
|
||||||
|
//
|
||||||
|
// El has one type, so `a + b` must be dispatched from what the operands ARE.
|
||||||
|
// The 35 Int-returning builtins moved to signatures.rel; the dispatch stayed,
|
||||||
|
// because choosing between arithmetic and concatenation is emission.
|
||||||
|
|
||||||
|
test "int-returning-builtin-drives-arithmetic-dispatch" {
|
||||||
|
let src: String = "fn main() { let a = str_len(\"hello\") let b = str_len(\"hi\") let c = a + b println(int_to_str(c)) }"
|
||||||
|
let out: String = compile_capture(src)
|
||||||
|
assert str_contains(out, "(a + b)"), "Int + Int is arithmetic"
|
||||||
|
assert !str_contains(out, "el_str_concat(a, b)"), "and NOT concatenation"
|
||||||
|
}
|
||||||
|
|
||||||
|
test "string-plus-string-still-concatenates" {
|
||||||
|
let src: String = "fn main() { let s = \"a\" + \"b\" println(s) }"
|
||||||
|
let out: String = compile_capture(src)
|
||||||
|
assert str_contains(out, "el_str_concat"), "String + String still concatenates"
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,3 +31,43 @@ el_duration_sub returns Duration
|
|||||||
el_duration_scale returns Duration
|
el_duration_scale returns Duration
|
||||||
el_duration_div returns Duration
|
el_duration_div returns Duration
|
||||||
ttl_cache_age returns Duration
|
ttl_cache_age returns Duration
|
||||||
|
|
||||||
|
# Int-returning builtins. Previously 35 hardcoded names in is_int_call().
|
||||||
|
# These decide whether `a + b` is arithmetic or concatenation, so the
|
||||||
|
# compiler reads them at emission time -- dispatch, not adjudication.
|
||||||
|
|
||||||
|
str_len returns Int
|
||||||
|
str_index_of returns Int
|
||||||
|
str_to_int returns Int
|
||||||
|
str_char_code returns Int
|
||||||
|
str_count returns Int
|
||||||
|
str_count_chars returns Int
|
||||||
|
str_count_bytes returns Int
|
||||||
|
str_count_lines returns Int
|
||||||
|
str_count_words returns Int
|
||||||
|
str_count_letters returns Int
|
||||||
|
str_count_digits returns Int
|
||||||
|
str_last_index_of returns Int
|
||||||
|
str_find_chars returns Int
|
||||||
|
native_list_len returns Int
|
||||||
|
el_list_len returns Int
|
||||||
|
len returns Int
|
||||||
|
json_get_int returns Int
|
||||||
|
json_array_len returns Int
|
||||||
|
engram_node_count returns Int
|
||||||
|
engram_edge_count returns Int
|
||||||
|
time_now returns Int
|
||||||
|
time_now_utc returns Int
|
||||||
|
time_diff returns Int
|
||||||
|
time_add returns Int
|
||||||
|
time_from_parts returns Int
|
||||||
|
el_abs returns Int
|
||||||
|
el_max returns Int
|
||||||
|
el_min returns Int
|
||||||
|
float_to_int returns Int
|
||||||
|
unix_timestamp returns Int
|
||||||
|
instant_to_unix_seconds returns Int
|
||||||
|
instant_to_unix_millis returns Int
|
||||||
|
duration_to_seconds returns Int
|
||||||
|
duration_to_millis returns Int
|
||||||
|
duration_to_nanos returns Int
|
||||||
|
|||||||
Reference in New Issue
Block a user