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:
+22
-7
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user