feat(solo/stdlib): string-keyed Map/dict builtins#49
Merged
Conversation
Add map_new/map_set/map_get/map_has/map_keys/map_remove/map_len to the Solo runtime stdlib, backed by the existing Value::Record(HashMap<String, Value>) representation. Previously Record was only reachable through static, syntax-level field identifiers (eval_field), so tooling had no way to use dynamic / computed string keys for config tables, lookup tables, or JSON-shaped data. Mutation builtins (map_set, map_remove) follow the same immutable convention as `push`: they clone and return a fresh Record. map_keys returns keys sorted for deterministic tooling output. Registered in register_stdlib() and stdlib_functions(); checker uses the existing Ty::Unknown fallback, consistent with the fs_*/format/env_args builtins. Adds examples/map.my and an integration regression test. Highest-leverage Phase-2 gap and the natural representation substrate for the follow-up json_parse/json_stringify work (#47). Refs #45 Refs #46 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The status table conflated "Solo dialect Complete" (true: lexer/parser/ checker/interpreter/REPL) with the runtime stdlib (still Phase 2). Split the row, add an explicit "runtime standard library | In Progress" row, and a NOTE pointing at the GitHub Phase-2 tracker as live status so the table cannot drift into a lie. Refs #45 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 18, 2026
hyperpolymath
added a commit
that referenced
this pull request
May 18, 2026
Adds json_parse(s)->Value and json_stringify(v)->String, backed by serde_json (promoted to a non-optional dependency of my-lang; serde derive stays behind the `serde` feature). Mapping pairs with the Map builtins (#46): object<->Record, array<->Array, integral number->Int else Float, null<->Unit. Object keys serialize sorted (serde_json's default BTreeMap), matching map_keys' deterministic ordering. Also fixes a prerequisite latent bug: the lexer stored raw string-literal slices and escape sequences were never decoded anywhere, so `"a\"b"` yielded the four chars a \ " b and json_parse("{\"k\":1}") — issue #45's own repro — was unparseable. parse_string_literal now decodes the standard escapes (\" \\ \/ \n \t \r \0, \uXXXX / \u{...}); unknown escapes pass through leniently so no previously-valid program breaks. Adds examples/json.my and integration regression tests for both the JSON round-trip (deterministic sorted keys) and string-escape decoding. Rebased onto main after #49 (Map) landed; coexists with map_* builtins. Refs #45 Refs #47 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 18, 2026
) Adds json_parse(s)->Value and json_stringify(v)->String, backed by serde_json (promoted to a non-optional dependency of my-lang; serde derive stays behind the `serde` feature). Mapping pairs with the Map builtins (#46): object<->Record, array<->Array, integral number->Int else Float, null<->Unit. Object keys serialize sorted (serde_json's default BTreeMap), matching map_keys' deterministic ordering. Also fixes a prerequisite latent bug: the lexer stored raw string-literal slices and escape sequences were never decoded anywhere, so `"a\"b"` yielded the four chars a \ " b and json_parse("{\"k\":1}") — issue #45's own repro — was unparseable. parse_string_literal now decodes the standard escapes (\" \\ \/ \n \t \r \0, \uXXXX / \u{...}); unknown escapes pass through leniently so no previously-valid program breaks. Adds examples/json.my and integration regression tests for both the JSON round-trip (deterministic sorted keys) and string-escape decoding. Rebased onto main after #49 (Map) landed; coexists with map_* builtins. Refs #45 Refs #47 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 18, 2026
time() only yields a Unix timestamp float; tooling that stamps generated artifacts (changelogs, scaffolds) needs a calendar date. date_today() returns the current UTC date as an ISO `YYYY-MM-DD` string. Civil date derived from SystemTime epoch seconds via Howard Hinnant's civil_from_days algorithm (public domain) — no date-crate dependency, correct for all Gregorian dates. Verified: produces 2026-05-18 today. Adds examples/date.my and an integration test asserting format/shape and a sane range (exact value depends on the wall clock). Rebased onto main after #49 (Map) and #53 (JSON) landed; coexists with the map_* / json_* builtins. Refs #45 Refs #48 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 18, 2026
time() only yields a Unix timestamp float; tooling that stamps generated artifacts (changelogs, scaffolds) needs a calendar date. date_today() returns the current UTC date as an ISO `YYYY-MM-DD` string. Civil date derived from SystemTime epoch seconds via Howard Hinnant's civil_from_days algorithm (public domain) — no date-crate dependency, correct for all Gregorian dates. Verified: produces 2026-05-18 today. Adds examples/date.my and an integration test asserting format/shape and a sane range (exact value depends on the wall clock). Rebased onto main after #49 (Map) and #53 (JSON) landed; coexists with the map_* / json_* builtins. Refs #45 Refs #48 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 18, 2026
🔍 Hypatia Security ScanFindings: 35 issues detected
View findings[
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "unwrap_or(0) with dangerous default (1 occurrences, CWE-754)",
"type": "unwrap_dangerous_default",
"file": "/home/runner/work/my-lang/my-lang/_exploratory/me-scaffolding/crates/parser/src/lib.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "critical"
},
{
"reason": "expect() in hot path (80 occurrences, CWE-754)",
"type": "expect_in_hot_path",
"file": "/home/runner/work/my-lang/my-lang/_exploratory/me-scaffolding/crates/parser/src/lib.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "unwrap() without prior check -- DoS via panic (1 occurrences, CWE-754)",
"type": "unwrap_without_check",
"file": "/home/runner/work/my-lang/my-lang/my-ssg/src/generator.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "expect() in hot path (5 occurrences, CWE-754)",
"type": "expect_in_hot_path",
"file": "/home/runner/work/my-lang/my-lang/crates/my-mir/src/lib.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "unwrap() without prior check -- DoS via panic (26 occurrences, CWE-754)",
"type": "unwrap_without_check",
"file": "/home/runner/work/my-lang/my-lang/crates/my-fmt/src/lib.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "unwrap() without prior check -- DoS via panic (1 occurrences, CWE-754)",
"type": "unwrap_without_check",
"file": "/home/runner/work/my-lang/my-lang/crates/my-hir/src/lib.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "unwrap() without prior check -- DoS via panic (3 occurrences, CWE-754)",
"type": "unwrap_without_check",
"file": "/home/runner/work/my-lang/my-lang/crates/my-llvm/src/lib.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Implements the highest-leverage remaining Solo Phase-2 stdlib gap: string-keyed maps.
Adds 7 builtins backed by the existing
Value::Record(HashMap<String, Value>)representation (no newValuevariant, no checker type-table change — same approach as the already-landedfs_*/format/env_argsbuiltins):map_new()-> Recordmap_set(m, k, v)-> Recordmap_get(m, k)-> valueFieldNotFound) if absentmap_has(m, k)-> Boolmap_keys(m)-> Array<String>map_remove(m, k)-> Recordmap_len(m)-> IntMutation builtins follow the same immutable convention as
push(clone + return new).Why
Value::Recordwas only reachable through static, syntax-level field identifiers (eval_field). Tooling needs dynamic / computed string keys for config tables, lookup tables, and JSON-shaped data. This is also the natural object substrate for the follow-upjson_parse/json_stringifywork (#47), per the tracker's suggested order (Map → JSON → date).Validation
examples/map.myruns and produces exactly its documented expected output.test_eval_map_builtins(exercises new/set/overwrite/get/remove/len + immutability of the source map).rustfmt-clean. (Pre-existing fmt drift elsewhere instdlib.rsleft untouched — out of scope.)Scope notes
vscode-extension/package-lock.json(pre-existing untracked file) deliberately not included.Refs #45
Refs #46
🤖 Generated with Claude Code