Skip to content

Commit 1a15665

Browse files
errors +59 patterns; +28 JSON / stdlib tests
Errors: parser specific-token expectations (RParen / RBrace / RBracket / Semicolon / Comma / Colon / Equal / LBrace / LParen / LBracket / Identifier / Arrow), empty-* runtime cases, arr_get / dict_set type-mismatch specifics, non-callable / non-iterable errors, string-index OOB, regex-no-match, network IO (unreachable, SSL handshake, HTTP 404/500/401/403), JSON key error, format not-supported (YAML/TOML/XML), SQL syntax / locked db, OMC version mismatch, missing return, unreachable code, math edge errors (shift overflow, invalid base, not-a-multiple), 19 introspection- builtin arity entries. Tests: 14 JSON (int/string/array/dict/nested parse, stringify roundtrips, bool/null/float), 14 stdlib (SHA-256 known values + length + determinism, SHA-512 length, base64 hi/empty/roundtrip, now_unix sanity, now_iso format, format_time epoch, parse_time roundtrip). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b63b739 commit 1a15665

3 files changed

Lines changed: 227 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# More JSON tests.
2+
3+
fn assert_eq(actual, expected, msg) {
4+
if actual != expected {
5+
test_record_failure(msg + ": expected " + to_string(expected) + " got " + to_string(actual));
6+
}
7+
}
8+
9+
fn assert_true(cond, msg) { if !cond { test_record_failure(msg); } }
10+
11+
fn test_json_parse_int() {
12+
h v = json_parse("42");
13+
assert_eq(v, 42, "parses int");
14+
}
15+
16+
fn test_json_parse_string() {
17+
h v = json_parse("\"hi\"");
18+
assert_eq(v, "hi", "parses string");
19+
}
20+
21+
fn test_json_parse_array_ints() {
22+
h v = json_parse("[1, 2, 3]");
23+
assert_eq(arr_len(v), 3, "3 elements");
24+
assert_eq(arr_get(v, 0), 1, "first");
25+
}
26+
27+
fn test_json_parse_array_mixed_types() {
28+
h v = json_parse("[1, \"x\", true, null]");
29+
assert_eq(arr_len(v), 4, "4 elements");
30+
}
31+
32+
fn test_json_parse_dict() {
33+
h v = json_parse("{\"a\": 1, \"b\": 2}");
34+
assert_eq(dict_get(v, "a"), 1, "a=1");
35+
assert_eq(dict_get(v, "b"), 2, "b=2");
36+
}
37+
38+
fn test_json_parse_nested() {
39+
h v = json_parse("{\"outer\": {\"inner\": 42}}");
40+
h o = dict_get(v, "outer");
41+
assert_eq(dict_get(o, "inner"), 42, "nested");
42+
}
43+
44+
fn test_json_stringify_int() {
45+
assert_eq(json_stringify(42), "42", "int → 42");
46+
}
47+
48+
fn test_json_stringify_string() {
49+
assert_eq(json_stringify("hi"), "\"hi\"", "string quoted");
50+
}
51+
52+
fn test_json_stringify_array() {
53+
assert_eq(json_stringify([1, 2, 3]), "[1,2,3]", "array");
54+
}
55+
56+
fn test_json_roundtrip_int() {
57+
h v = json_parse(json_stringify(42));
58+
assert_eq(v, 42, "roundtrip int");
59+
}
60+
61+
fn test_json_roundtrip_dict() {
62+
h d = dict_new();
63+
dict_set(d, "k", 1);
64+
h v = json_parse(json_stringify(d));
65+
assert_eq(dict_get(v, "k"), 1, "roundtrip dict");
66+
}
67+
68+
fn test_json_parse_bool() {
69+
assert_eq(json_parse("true"), true, "true");
70+
assert_eq(json_parse("false"), false, "false");
71+
}
72+
73+
fn test_json_parse_null() {
74+
h v = json_parse("null");
75+
assert_true(v == null, "null parses");
76+
}
77+
78+
fn test_json_parse_float() {
79+
h v = json_parse("3.14");
80+
assert_true(v > 3.0, ">3");
81+
assert_true(v < 4.0, "<4");
82+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# More stdlib tests.
2+
3+
fn assert_eq(actual, expected, msg) {
4+
if actual != expected {
5+
test_record_failure(msg + ": expected " + to_string(expected) + " got " + to_string(actual));
6+
}
7+
}
8+
9+
fn assert_true(cond, msg) { if !cond { test_record_failure(msg); } }
10+
11+
# SHA-256
12+
fn test_sha256_empty() {
13+
assert_eq(sha256(""),
14+
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
15+
"sha256 of empty");
16+
}
17+
18+
fn test_sha256_hello() {
19+
assert_eq(sha256("hello"),
20+
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
21+
"sha256 of hello");
22+
}
23+
24+
fn test_sha256_length() {
25+
assert_eq(str_len(sha256("anything")), 64, "64 hex chars");
26+
}
27+
28+
fn test_sha256_deterministic() {
29+
assert_eq(sha256("x"), sha256("x"), "deterministic");
30+
}
31+
32+
# SHA-512
33+
fn test_sha512_length() {
34+
assert_eq(str_len(sha512("x")), 128, "128 hex chars");
35+
}
36+
37+
fn test_sha512_deterministic() {
38+
assert_eq(sha512("x"), sha512("x"), "deterministic");
39+
}
40+
41+
# Base64
42+
fn test_base64_encode_hi() {
43+
assert_eq(base64_encode("hi"), "aGk=", "hi → aGk=");
44+
}
45+
46+
fn test_base64_decode_hi() {
47+
assert_eq(base64_decode("aGk="), "hi", "aGk= → hi");
48+
}
49+
50+
fn test_base64_roundtrip() {
51+
h orig = "hello world 12345";
52+
h encoded = base64_encode(orig);
53+
h back = base64_decode(encoded);
54+
assert_eq(back, orig, "roundtrip");
55+
}
56+
57+
fn test_base64_empty() {
58+
assert_eq(base64_encode(""), "", "empty encode");
59+
assert_eq(base64_decode(""), "", "empty decode");
60+
}
61+
62+
# Datetime
63+
fn test_now_unix_recent() {
64+
h now = now_unix();
65+
# Should be > 2023 (1.7e9) and < year 2603 (2e10).
66+
assert_true(now > 1700000000, "post-2023");
67+
assert_true(now < 20000000000, "pre-2603");
68+
}
69+
70+
fn test_now_iso_format() {
71+
h s = now_iso();
72+
assert_true(str_len(s) > 18, "ISO non-trivial");
73+
assert_true(re_match("^[0-9]{4}-[0-9]{2}-[0-9]{2}", s) == 1, "YYYY-MM-DD start");
74+
}
75+
76+
fn test_format_time_epoch() {
77+
assert_eq(format_time(0, "%Y-%m-%d"), "1970-01-01", "epoch date");
78+
assert_eq(format_time(0, "%H:%M:%S"), "00:00:00", "epoch time");
79+
}
80+
81+
fn test_parse_time_roundtrip() {
82+
h s = "2023-06-15 10:30:00";
83+
h ts = parse_time(s, "%Y-%m-%d %H:%M:%S");
84+
h back = format_time(ts, "%Y-%m-%d %H:%M:%S");
85+
assert_eq(back, s, "roundtrip");
86+
}

omnimcode-core/src/errors.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,65 @@ pub const ERROR_PATTERNS: &[ErrorPattern] = &[
11201120
ErrorPattern { pattern: "omc_code_complexity: parse error", category: "parser", explanation: "`omc_code_complexity` couldn't parse its input.", typical_cause: "Source is malformed OMC.", fix: "Test the source standalone via `omc --check file.omc` first." },
11211121
ErrorPattern { pattern: "omc_code_diff: parse error", category: "parser", explanation: "`omc_code_diff` couldn't parse its input.", typical_cause: "Source is malformed OMC.", fix: "Test the source standalone via `omc --check file.omc` first." },
11221122
ErrorPattern { pattern: "omc_code_metrics: parse error", category: "parser", explanation: "`omc_code_metrics` couldn't parse its input.", typical_cause: "Source is malformed OMC.", fix: "Test the source standalone via `omc --check file.omc` first." },
1123+
ErrorPattern { pattern: "Expected RParen,", category: "parser", explanation: "Parser expected a closing paren ')' at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra closing paren ')'." },
1124+
ErrorPattern { pattern: "Expected RBrace,", category: "parser", explanation: "Parser expected a closing brace '}' at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra closing brace '}'." },
1125+
ErrorPattern { pattern: "Expected RBracket,", category: "parser", explanation: "Parser expected a closing bracket ']' at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra closing bracket ']'." },
1126+
ErrorPattern { pattern: "Expected Semicolon,", category: "parser", explanation: "Parser expected a ';' terminator at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra ';' terminator." },
1127+
ErrorPattern { pattern: "Expected Comma,", category: "parser", explanation: "Parser expected a ',' separator at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra ',' separator." },
1128+
ErrorPattern { pattern: "Expected Colon,", category: "parser", explanation: "Parser expected a ':' separator at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra ':' separator." },
1129+
ErrorPattern { pattern: "Expected Equal,", category: "parser", explanation: "Parser expected a '=' for assignment at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra '=' for assignment." },
1130+
ErrorPattern { pattern: "Expected LBrace,", category: "parser", explanation: "Parser expected a block-opening '{' at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra block-opening '{'." },
1131+
ErrorPattern { pattern: "Expected LParen,", category: "parser", explanation: "Parser expected a '(' for call/grouping at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra '(' for call/grouping." },
1132+
ErrorPattern { pattern: "Expected LBracket,", category: "parser", explanation: "Parser expected a '[' for index/array at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra '[' for index/array." },
1133+
ErrorPattern { pattern: "Expected Identifier,", category: "parser", explanation: "Parser expected a identifier name at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra identifier name." },
1134+
ErrorPattern { pattern: "Expected Arrow,", category: "parser", explanation: "Parser expected a '=>' for match arm at this position.", typical_cause: "Misplaced or missing punctuation, or unbalanced delimiter earlier in source.", fix: "Check surrounding source for missing/extra '=>' for match arm." },
1135+
ErrorPattern { pattern: "empty array", category: "runtime", explanation: "Operation called on an empty array.", typical_cause: "Edge case not guarded.", fix: "Check size/length before invoking." },
1136+
ErrorPattern { pattern: "empty matrix", category: "runtime", explanation: "Operation called on an empty matrix.", typical_cause: "Edge case not guarded.", fix: "Check size/length before invoking." },
1137+
ErrorPattern { pattern: "empty string", category: "runtime", explanation: "Operation called on an empty string.", typical_cause: "Edge case not guarded.", fix: "Check size/length before invoking." },
1138+
ErrorPattern { pattern: "empty dict", category: "runtime", explanation: "Operation called on an empty dict.", typical_cause: "Edge case not guarded.", fix: "Check size/length before invoking." },
1139+
ErrorPattern { pattern: "arr_get: first argument must be an array", category: "arrays", explanation: "Tried to index a non-array value.", typical_cause: "Confused dict with array, or passed scalar.", fix: "Use type_of(value) first; dict_get for dicts; cast or wrap as needed." },
1140+
ErrorPattern { pattern: "dict_set: first argument must be a dict_variable", category: "dicts", explanation: "dict_set's first arg must be a bound dict variable, not an expression.", typical_cause: "Calling dict_set on a sub-expression that returns a dict.", fix: "Bind the dict to a variable first: `h d = expr(); dict_set(d, ...);`." },
1141+
ErrorPattern { pattern: "Cannot call non-function value", category: "runtime", explanation: "Tried to invoke a value that isn't callable.", typical_cause: "Variable shadows a builtin / wrong type passed where function expected.", fix: "Check `type_of(value)` is 'function'." },
1142+
ErrorPattern { pattern: "Cannot iterate non-array", category: "runtime", explanation: "for-in needs an array.", typical_cause: "Passed scalar/dict to for-in.", fix: "Use dict_items / dict_keys for dicts, or wrap scalar in [value]." },
1143+
ErrorPattern { pattern: "string index out of bounds", category: "strings", explanation: "str_slice/str_get past end of string.", typical_cause: "Computed wrong slice.", fix: "Check str_len first; clamp indices to [0, len]." },
1144+
ErrorPattern { pattern: "regex not found", category: "regex", explanation: "Pattern produced no match where one was required.", typical_cause: "Source doesn't contain the pattern.", fix: "Use re_match for a yes/no check before extracting groups." },
1145+
ErrorPattern { pattern: "network unreachable", category: "io", explanation: "Could not reach destination.", typical_cause: "DNS/firewall/no internet.", fix: "Verify URL/host; check network connectivity." },
1146+
ErrorPattern { pattern: "ssl handshake failed", category: "io", explanation: "TLS negotiation failed.", typical_cause: "Certificate mismatch or stale TLS.", fix: "Verify HTTPS URL; update CA bundle." },
1147+
ErrorPattern { pattern: "http 404", category: "io", explanation: "HTTP request returned 404 Not Found.", typical_cause: "Wrong URL or resource removed.", fix: "Verify path; consider redirect handling." },
1148+
ErrorPattern { pattern: "http 500", category: "io", explanation: "Server returned 500 Internal Server Error.", typical_cause: "Upstream service failure.", fix: "Retry with backoff; inspect server logs." },
1149+
ErrorPattern { pattern: "http 401", category: "io", explanation: "HTTP 401 Unauthorized.", typical_cause: "Missing/expired auth token.", fix: "Refresh credentials and include auth header." },
1150+
ErrorPattern { pattern: "http 403", category: "io", explanation: "HTTP 403 Forbidden.", typical_cause: "Auth ok but resource access denied.", fix: "Check ACLs / permissions." },
1151+
ErrorPattern { pattern: "json key error", category: "json", explanation: "Required key missing in parsed JSON.", typical_cause: "Schema mismatch.", fix: "Verify the source / use dict_get_or with a default." },
1152+
ErrorPattern { pattern: "yaml not supported", category: "stdlib", explanation: "OMC doesn't ship YAML; use JSON instead.", typical_cause: "Trying to load .yaml.", fix: "Convert YAML to JSON externally or use omc-yaml package if available." },
1153+
ErrorPattern { pattern: "toml not supported", category: "stdlib", explanation: "OMC doesn't ship TOML.", typical_cause: "Looking for tomllib.", fix: "Use JSON or write a small parser." },
1154+
ErrorPattern { pattern: "xml not supported", category: "stdlib", explanation: "OMC doesn't ship XML parsing.", typical_cause: "Trying to parse XML.", fix: "Use JSON; XML requires an external library." },
1155+
ErrorPattern { pattern: "sql syntax error", category: "stdlib", explanation: "SQLite couldn't parse the query.", typical_cause: "Typo or wrong dialect.", fix: "Test the query in sqlite3 CLI first." },
1156+
ErrorPattern { pattern: "sqlite locked", category: "io", explanation: "Database file is locked by another writer.", typical_cause: "Concurrent access.", fix: "Use WAL mode or coordinate writers." },
1157+
ErrorPattern { pattern: "OMC version mismatch", category: "runtime", explanation: "Bytecode/serialised form from a different OMC version.", typical_cause: "Cached file is stale.", fix: "Clear cache, regenerate from source." },
1158+
ErrorPattern { pattern: "missing return", category: "runtime", explanation: "Function exited without an explicit return.", typical_cause: "Code path forgot a return.", fix: "Add explicit return; OMC defaults to null but may be ambiguous." },
1159+
ErrorPattern { pattern: "unreachable code", category: "runtime", explanation: "Statements after an unconditional return/throw/break.", typical_cause: "Dead code.", fix: "Remove the unreachable code or fix the control flow." },
1160+
ErrorPattern { pattern: "omc_help requires", category: "introspection", explanation: "`omc_help` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_help\")` for the signature." },
1161+
ErrorPattern { pattern: "omc_explain_error requires", category: "introspection", explanation: "`omc_explain_error` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_explain_error\")` for the signature." },
1162+
ErrorPattern { pattern: "omc_code_canonical requires", category: "introspection", explanation: "`omc_code_canonical` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_code_canonical\")` for the signature." },
1163+
ErrorPattern { pattern: "omc_code_equivalent requires", category: "introspection", explanation: "`omc_code_equivalent` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_code_equivalent\")` for the signature." },
1164+
ErrorPattern { pattern: "omc_code_summary requires", category: "introspection", explanation: "`omc_code_summary` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_code_summary\")` for the signature." },
1165+
ErrorPattern { pattern: "omc_code_diff requires", category: "introspection", explanation: "`omc_code_diff` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_code_diff\")` for the signature." },
1166+
ErrorPattern { pattern: "omc_code_metrics requires", category: "introspection", explanation: "`omc_code_metrics` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_code_metrics\")` for the signature." },
1167+
ErrorPattern { pattern: "omc_remember requires", category: "introspection", explanation: "`omc_remember` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_remember\")` for the signature." },
1168+
ErrorPattern { pattern: "omc_recall_matches requires", category: "introspection", explanation: "`omc_recall_matches` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_recall_matches\")` for the signature." },
1169+
ErrorPattern { pattern: "omc_token_encode requires", category: "introspection", explanation: "`omc_token_encode` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_token_encode\")` for the signature." },
1170+
ErrorPattern { pattern: "omc_token_decode requires", category: "introspection", explanation: "`omc_token_decode` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_token_decode\")` for the signature." },
1171+
ErrorPattern { pattern: "omc_cheatsheet requires", category: "introspection", explanation: "`omc_cheatsheet` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_cheatsheet\")` for the signature." },
1172+
ErrorPattern { pattern: "omc_change_report requires", category: "introspection", explanation: "`omc_change_report` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_change_report\")` for the signature." },
1173+
ErrorPattern { pattern: "omc_id requires", category: "introspection", explanation: "`omc_id` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_id\")` for the signature." },
1174+
ErrorPattern { pattern: "omc_bootstrap_pack requires", category: "introspection", explanation: "`omc_bootstrap_pack` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_bootstrap_pack\")` for the signature." },
1175+
ErrorPattern { pattern: "omc_python_translation requires", category: "introspection", explanation: "`omc_python_translation` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_python_translation\")` for the signature." },
1176+
ErrorPattern { pattern: "omc_builtin_index_markdown requires", category: "introspection", explanation: "`omc_builtin_index_markdown` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_builtin_index_markdown\")` for the signature." },
1177+
ErrorPattern { pattern: "omc_search_builtins requires", category: "introspection", explanation: "`omc_search_builtins` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_search_builtins\")` for the signature." },
1178+
ErrorPattern { pattern: "omc_completion_hint requires", category: "introspection", explanation: "`omc_completion_hint` arity mismatch.", typical_cause: "Wrong arg count.", fix: "Run `omc_help(\"omc_completion_hint\")` for the signature." },
1179+
ErrorPattern { pattern: "overflow shift", category: "math", explanation: "Shift exceeded i64 width.", typical_cause: "Shift count out of range.", fix: "Mask shift count to 0..63 via & 63." },
1180+
ErrorPattern { pattern: "invalid base", category: "math", explanation: "parse_int with base outside 2..36.", typical_cause: "Wrong base.", fix: "Use base in [2, 36]." },
1181+
ErrorPattern { pattern: "not a multiple", category: "math", explanation: "Requires divisibility but input isn't a multiple.", typical_cause: "Bad input.", fix: "Use modular arithmetic or pad input." },
11231182
];
11241183

11251184
/// Best-matching pattern for an error message. Returns None if no

0 commit comments

Comments
 (0)