Phase 3: Var system — var-get, var-set, var?, alter-var-root, find-var, alter-meta!, reset-meta!
- types.janet: find-var (ctx-based var resolution), alter-meta!, reset-meta! - evaluator.janet: 10 new special-form dispatch arms for var ops - core.janet: 6 new Clojure-level wrappers in core-bindings - core-meta: add var-aware branch (was struct-only) - core-binding macro: use array-map instead of hash-map (PHM incompatibility) - 8 new tests (17: var system, 18: var metadata) — all pass - 317 total tests, 0 failures
This commit is contained in:
parent
ad895945a0
commit
8e86c7c2ec
8 changed files with 177 additions and 51 deletions
|
|
@ -1,38 +1,16 @@
|
|||
{
|
||||
"jolt-dev": {
|
||||
"created_by": "agent",
|
||||
"use_count": 29,
|
||||
"view_count": 44,
|
||||
"patch_count": 34,
|
||||
"last_used_at": "2026-06-02T20:32:00.407408+00:00",
|
||||
"last_viewed_at": "2026-06-02T21:03:17.891717+00:00",
|
||||
"last_patched_at": "2026-06-02T20:33:05.356194+00:00",
|
||||
"use_count": 30,
|
||||
"view_count": 45,
|
||||
"patch_count": 37,
|
||||
"last_used_at": "2026-06-02T22:24:09.648320+00:00",
|
||||
"last_viewed_at": "2026-06-02T22:24:09.636430+00:00",
|
||||
"last_patched_at": "2026-06-02T22:24:40.254179+00:00",
|
||||
"created_at": "2026-06-01T21:26:06.614465+00:00",
|
||||
"state": "active",
|
||||
"pinned": false
|
||||
},
|
||||
"jolt-compiler": {
|
||||
"created_by": "agent",
|
||||
"use_count": 3,
|
||||
"view_count": 7,
|
||||
"patch_count": 6,
|
||||
"last_used_at": "2026-06-02T21:40:37.747767+00:00",
|
||||
"last_viewed_at": "2026-06-02T21:40:37.739522+00:00",
|
||||
"last_patched_at": "2026-06-02T21:40:55.723354+00:00",
|
||||
"created_at": "2026-06-02T17:54:38.690279+00:00",
|
||||
"state": "active",
|
||||
"pinned": false
|
||||
},
|
||||
"jpm-build": {
|
||||
"created_by": "agent",
|
||||
"use_count": 0,
|
||||
"view_count": 15,
|
||||
"patch_count": 0,
|
||||
"last_viewed_at": "2026-06-02T21:03:17.897587+00:00",
|
||||
"created_at": "2026-06-01T20:56:39.144222+00:00",
|
||||
"state": "active",
|
||||
"pinned": false
|
||||
},
|
||||
"jolt-bootstrap": {
|
||||
"created_by": "agent",
|
||||
"use_count": 9,
|
||||
|
|
@ -44,5 +22,27 @@
|
|||
"created_at": "2026-06-01T21:49:51.101718+00:00",
|
||||
"state": "active",
|
||||
"pinned": false
|
||||
},
|
||||
"jolt-compiler": {
|
||||
"created_by": "agent",
|
||||
"use_count": 4,
|
||||
"view_count": 8,
|
||||
"patch_count": 6,
|
||||
"last_used_at": "2026-06-02T22:24:09.679583+00:00",
|
||||
"last_viewed_at": "2026-06-02T22:24:09.655249+00:00",
|
||||
"last_patched_at": "2026-06-02T21:40:55.723354+00:00",
|
||||
"created_at": "2026-06-02T17:54:38.690279+00:00",
|
||||
"state": "active",
|
||||
"pinned": false
|
||||
},
|
||||
"jpm-build": {
|
||||
"created_by": "agent",
|
||||
"use_count": 0,
|
||||
"view_count": 15,
|
||||
"patch_count": 0,
|
||||
"last_viewed_at": "2026-06-02T21:03:17.897587+00:00",
|
||||
"created_at": "2026-06-01T20:56:39.144222+00:00",
|
||||
"state": "active",
|
||||
"pinned": false
|
||||
}
|
||||
}
|
||||
|
|
@ -12,8 +12,25 @@ cd /Users/yogthos/src/jolt
|
|||
jpm build # produces build/jolt
|
||||
jpm test # runs all tests
|
||||
janet test/foo.janet # run a single test file from project root
|
||||
janet -k file.janet # check parse without executing (useful for syntax validation)
|
||||
```
|
||||
|
||||
## Python3 batch edits
|
||||
|
||||
When the `edit` tool is blocked by syntax checker false positives on complex multi-line replacements, use `python3` for batch text edits:
|
||||
|
||||
```bash
|
||||
python3 << 'PYEOF'
|
||||
with open('src/jolt/core.janet') as f:
|
||||
content = f.read()
|
||||
content = content.replace('old text', 'new text')
|
||||
with open('src/jolt/core.janet', 'w') as f:
|
||||
f.write(content)
|
||||
PYEOF
|
||||
```
|
||||
|
||||
Always run `janet -k file.janet` after to verify syntax.
|
||||
|
||||
## Compiler Development
|
||||
|
||||
See `jolt-compiler` skill for the Clojure→Janet source-to-source compiler workflow.
|
||||
|
|
@ -113,15 +130,33 @@ The match arm receives `ctx`, `bindings`, and `form` (the full list). Use `(in f
|
|||
|
||||
## Persistent Data Structures
|
||||
|
||||
Located in:
|
||||
- `src/jolt/clojure/lang/persistent_vector.clj`
|
||||
- `src/jolt/clojure/lang/persistent_hash_map.clj`
|
||||
### PersistentVector
|
||||
Located in `src/jolt/clojure/lang/persistent_vector.clj`.
|
||||
Loaded at init time by `load-persistent-structures` in `api.janet`.
|
||||
32-way branching trie with tail optimization.
|
||||
|
||||
Loaded at init time by `load-persistent-structures` in `api.janet`. Use `{:mutable? true}` to skip and use Janet-native types.
|
||||
### PersistentHashMap
|
||||
Located in `src/jolt/phm.janet` — Janet module, NOT a .clj file.
|
||||
Imported via `(use ./phm)` in `src/jolt/core.janet`.
|
||||
Bucket-based (8 buckets), each bucket is a flat `[k v k v ...]` array.
|
||||
PHM is a table with magic type tag: `:jolt/deftype` = `"jolt.lang.persistent-hash-map.PersistentHashMap"`.
|
||||
Key fields: `:cnt` (entry count), `:buckets` (array of arrays), `:_meta`.
|
||||
|
||||
### Implementation detail
|
||||
Simple array-based implementation (node-assoc/node-find/find-key-index), NOT HAMT bit-trie.
|
||||
HAMT failed because Janet uses 64-bit doubles and bit operations require 32-bit signed ints.
|
||||
API: `phm-get`, `phm-assoc`, `phm-dissoc`, `phm-contains?`, `phm-entries`, `phm-to-struct`.
|
||||
`phm-to-struct` converts PHM back to Janet struct for compatibility with `keys`, `deep=`, etc.
|
||||
|
||||
**Design decision**: PHM lives in a separate Janet module rather than embedded in core.janet, to avoid forward-reference issues (core-map? calls phm? which wasn't yet defined when core-map? was being compiled).
|
||||
|
||||
**16 core functions updated** with PHM-aware branches: core-map?, core-hash-map, core-get, core-count, core-keys, core-vals, core-contains?, core-empty?, core-seq, core-conj, core-assoc, core-dissoc, core-merge, core-merge-with, core-into, core-=.
|
||||
|
||||
### Working with PHM in core functions
|
||||
- Check `(phm? coll)` FIRST, before generic struct/table checks
|
||||
- Use `phm-get` not `(m key)` — PHM is a table but keys aren't direct properties
|
||||
- Use `phm-to-struct` when you need Janet-native operations (deep=, keys, etc.)
|
||||
- PHM equality: `core-=` converts both sides to structs via `phm-to-struct`, then uses `deep=`
|
||||
|
||||
### Loading persistent structures
|
||||
Use `{:mutable? true}` in `init` to skip persistent types and use Janet-native structs.
|
||||
|
||||
## Janet Gotchas
|
||||
|
||||
|
|
@ -129,6 +164,8 @@ HAMT failed because Janet uses 64-bit doubles and bit operations require 32-bit
|
|||
- `deftype` creates tables, not structs. `struct?` returns false.
|
||||
- `(get child :key)` DOES follow table prototype chain — resolved and confirmed working.
|
||||
- Janet LSP produces many false positives on `.janet` files — safe to ignore.
|
||||
- `break` can't be used inside `let` blocks — `break` returns from the innermost loop, and a `let` has no loop. Use `(var found nil)` pattern + `(while ... (if cond (do (set found val) (break))))` then check `found` after loop.
|
||||
- Duplicate function definitions in the same file cause hard-to-diagnose "unknown symbol" errors. Always grep for the fn name before adding.
|
||||
|
||||
## Symbol representation
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue