feat: 80/80 unit tests, real-world examples (FizzBuzz, WordFreq)

- Emitter: def registry (definedGlobals) for symbol emit distinction
- Emitter: cond emits return statements
- Emitter: reduce wraps named functions in closure adapter
- Emitter: clojure.string/* function mappings (split, lower-case, etc.)
- Emitter: statement detection for echo cljRepr wrapping
- Runtime: cljGet supports default value (3 args)
- Runtime: cljStrSplit supports regex patterns via re module
- Examples: fizzbuzz.clj and wordfreq.clj both compile and run correctly
- Tests: emit symbol / emit mangled symbol now pass (80/80)
- Compliance: 233/233 (100%) maintained
This commit is contained in:
2026-05-11 10:08:46 +03:00
parent 4afef5a264
commit 456636700c
6 changed files with 169 additions and 43 deletions
+22 -7
View File
@@ -1,6 +1,6 @@
import cljnim_pvec
import cljnim_pmap
import strutils, sequtils, hashes, algorithm, os, osproc, locks, math, random
import strutils, sequtils, hashes, algorithm, os, osproc, locks, math, random, re
type
CljKind* = enum
@@ -1338,10 +1338,6 @@ proc cljGet*(m: CljVal, key: CljVal): CljVal =
else: cljNil()
else: cljNil()
proc cljGet*(args: seq[CljVal]): CljVal =
if args.len < 2: return cljNil()
cljGet(args[0], args[1])
proc cljGetDefault*(m: CljVal, key: CljVal, default: CljVal): CljVal =
if m.isNil: return default
case m.kind
@@ -1351,6 +1347,13 @@ proc cljGetDefault*(m: CljVal, key: CljVal, default: CljVal): CljVal =
else: default
else: default
proc cljGet*(args: seq[CljVal]): CljVal =
if args.len < 2: return cljNil()
if args.len >= 3:
cljGetDefault(args[0], args[1], args[2])
else:
cljGet(args[0], args[1])
proc cljExInfo*(msg: CljVal, data: CljVal): CljVal =
var ex = newException(ExInfo, cljStr(msg))
ex.exData = data
@@ -1663,10 +1666,22 @@ proc cljStrJoin*(args: seq[CljVal]): CljVal =
proc cljStrSplit*(s: CljVal, sep: CljVal): CljVal =
if s.kind != ckString: raise newException(CatchableError, "split requires a string")
let parts = s.strVal.split(cljStr(sep))
let sepStr = cljStr(sep)
var parts: seq[string]
# Check if pattern looks like regex (contains special chars)
if sepStr.contains(re"[\\^$.*+?{}()\[\]|]"):
try:
let regex = re(sepStr)
parts = s.strVal.split(regex)
except CatchableError:
# Fallback to string split if regex is invalid
parts = s.strVal.split(sepStr)
else:
parts = s.strVal.split(sepStr)
var items: seq[CljVal] = @[]
for p in parts:
items.add(cljString(p))
if p.len > 0: # Skip empty strings from split
items.add(cljString(p))
cljList(items)
proc cljStrReplace*(s: CljVal, match: CljVal, replacement: CljVal): CljVal =