130 lines
3.5 KiB
Plaintext
130 lines
3.5 KiB
Plaintext
// Compile-time diagnostics tests — verify the type checker catches errors
|
|
var fd = use('fd')
|
|
var shop = use('internal/shop')
|
|
var streamline = use('streamline')
|
|
|
|
var tmpfile = "/tmp/_cell_compile_test.cm"
|
|
|
|
function write_source(src) {
|
|
fd.slurpwrite(tmpfile, stone(blob(src)))
|
|
}
|
|
|
|
function get_diagnostics(src) {
|
|
write_source(src)
|
|
var compiled = shop.mcode_file(tmpfile)
|
|
compiled._warn = true
|
|
var optimized = streamline(compiled)
|
|
if (optimized._diagnostics == null) return []
|
|
return optimized._diagnostics
|
|
}
|
|
|
|
function has_diagnostic(diags, severity, pattern) {
|
|
var i = 0
|
|
while (i < length(diags)) {
|
|
if (diags[i].severity == severity && search(diags[i].message, pattern) != null) {
|
|
return true
|
|
}
|
|
i = i + 1
|
|
}
|
|
return false
|
|
}
|
|
|
|
function expect(diags, severity, pattern) {
|
|
if (!has_diagnostic(diags, severity, pattern)) {
|
|
return `expected ${severity} matching '${pattern}', got ${text(length(diags))} diagnostic(s)`
|
|
}
|
|
return null
|
|
}
|
|
|
|
function expect_clean(diags) {
|
|
if (length(diags) > 0) {
|
|
return `expected no diagnostics, got ${text(length(diags))}`
|
|
}
|
|
return null
|
|
}
|
|
|
|
return {
|
|
// === Store errors ===
|
|
|
|
test_store_field_on_array: function() {
|
|
var d = get_diagnostics("var a = []\na[\"x\"] = 1")
|
|
return expect(d, "error", "storing named property on array")
|
|
},
|
|
|
|
test_store_index_on_record: function() {
|
|
var d = get_diagnostics("var a = {}\na[1] = 1")
|
|
return expect(d, "error", "storing numeric index on record")
|
|
},
|
|
|
|
test_store_field_on_text: function() {
|
|
var d = get_diagnostics("var s = \"hello\"\ns.x = 1")
|
|
return expect(d, "error", "storing property on text")
|
|
},
|
|
|
|
test_store_index_on_text: function() {
|
|
var d = get_diagnostics("var s = \"hello\"\ns[0] = 1")
|
|
return expect(d, "error", "storing index on text")
|
|
},
|
|
|
|
test_push_on_text: function() {
|
|
var d = get_diagnostics("var s = \"hello\"\ns[] = 1")
|
|
return expect(d, "error", "push on text")
|
|
},
|
|
|
|
test_push_on_record: function() {
|
|
var d = get_diagnostics("var r = {}\nr[] = 1")
|
|
return expect(d, "error", "push on record")
|
|
},
|
|
|
|
// === Invoke errors ===
|
|
|
|
test_invoke_null: function() {
|
|
var d = get_diagnostics("var x = null\nx()")
|
|
return expect(d, "error", "invoking null")
|
|
},
|
|
|
|
test_invoke_number: function() {
|
|
var d = get_diagnostics("var x = 42\nx()")
|
|
return expect(d, "error", "invoking")
|
|
},
|
|
|
|
test_invoke_text: function() {
|
|
var d = get_diagnostics("var x = \"hello\"\nx()")
|
|
return expect(d, "error", "invoking")
|
|
},
|
|
|
|
// === Warnings ===
|
|
|
|
test_field_on_array_warns: function() {
|
|
var d = get_diagnostics("var a = [1, 2]\nvar x = a.name")
|
|
return expect(d, "warning", "named property access on array")
|
|
},
|
|
|
|
test_field_on_text_warns: function() {
|
|
var d = get_diagnostics("var s = \"hello\"\nvar x = s.name")
|
|
return expect(d, "warning", "named property access on text")
|
|
},
|
|
|
|
test_record_key_on_record_warns: function() {
|
|
var d = get_diagnostics("var r = {a: 1}\nvar k = {}\nvar x = r[k]")
|
|
return expect(d, "warning", "record key on record")
|
|
},
|
|
|
|
// === Clean code produces no diagnostics ===
|
|
|
|
test_clean_array_ops: function() {
|
|
var d = get_diagnostics("var a = [1, 2, 3]\nvar x = a[0]\na[1] = 5\na[] = 4")
|
|
return expect_clean(d)
|
|
},
|
|
|
|
test_clean_record_ops: function() {
|
|
var d = get_diagnostics("var r = {a: 1, b: 2}\nvar x = r.a\nr.c = 3")
|
|
return expect_clean(d)
|
|
},
|
|
|
|
test_clean_function_call: function() {
|
|
var d = get_diagnostics("function f(a, b) { return a + b }\nvar x = f(1, 2)")
|
|
return expect_clean(d)
|
|
}
|
|
}
|