feat: +12 tests (210/233, 90%) — fn wrapping, doseq, when-first, NaN?, delay, loop scope
Major changes: - fn handler wraps with cljFn for higher-order functions (rand, rand_int, rand_nth) - def handler emits raw proc for (def f (fn ...)) context - Local fn calls use .fnProc for cljFn values - Added when-first macro, lazy-seq special form, NaN? predicate - Added delay, rseq, listEmpty runtime functions - doseq macro uses next instead of rest, recur inside when body - loop handler pushScope/popScope for proper variable scoping - let handler: var/while/proc statement checks, block last-line discard - when handler: proper statement detection for body forms - defn/defn- allow empty body
This commit is contained in:
+26
-8
@@ -402,16 +402,20 @@ proc initMacros*() =
|
||||
innerBindings.add(name.items[j])
|
||||
innerBindings.add(cljList(@[cljSymbol("nth"), tmpGs, cljInt(j)]))
|
||||
let destructured = cljList(@[cljSymbol("let"), cljVector(innerBindings)] & body)
|
||||
let recurForm = cljList(@[cljSymbol("recur"), cljList(@[cljSymbol("next"), seqGs])])
|
||||
let loopBody = cljList(@[cljSymbol("when"), seqGs,
|
||||
cljList(@[cljSymbol("let"), cljVector(@[tmpGs, cljList(@[cljSymbol("first"), seqGs])]), destructured])])
|
||||
let recurBody = cljList(@[cljSymbol("recur"), cljList(@[cljSymbol("rest"), seqGs])])
|
||||
let loopForm = cljList(@[cljSymbol("loop"), cljVector(@[seqGs, cljList(@[cljSymbol("seq"), gs])]), loopBody, recurBody])
|
||||
result = cljList(@[cljSymbol("let"), cljVector(@[gs, coll]), loopForm])
|
||||
cljList(@[cljSymbol("let"), cljVector(@[tmpGs, cljList(@[cljSymbol("first"), seqGs])]), destructured]),
|
||||
recurForm])
|
||||
let seqColl = cljList(@[cljSymbol("seq"), coll])
|
||||
let loopForm = cljList(@[cljSymbol("loop"), cljVector(@[seqGs, seqColl]), loopBody])
|
||||
result = loopForm
|
||||
else:
|
||||
let loopBody = cljList(@[cljSymbol("when"), name] & body)
|
||||
let recurBody = cljList(@[cljSymbol("recur"), cljList(@[cljSymbol("first"), gs]), cljList(@[cljSymbol("rest"), gs])])
|
||||
let loopForm = cljList(@[cljSymbol("loop"), cljVector(@[name, cljList(@[cljSymbol("first"), gs]), gs, cljList(@[cljSymbol("rest"), gs])]), loopBody, recurBody])
|
||||
result = cljList(@[cljSymbol("let"), cljVector(@[gs, coll]), loopForm])
|
||||
# Simple binding: skip the let, pass coll directly to loop
|
||||
let seqColl = cljList(@[cljSymbol("seq"), coll])
|
||||
let recurForm = cljList(@[cljSymbol("recur"), cljList(@[cljSymbol("first"), gs]), cljList(@[cljSymbol("next"), gs])])
|
||||
let loopBody = cljList(@[cljSymbol("when"), name] & body & @[recurForm])
|
||||
let loopForm = cljList(@[cljSymbol("loop"), cljVector(@[name, cljList(@[cljSymbol("first"), seqColl]), gs, cljList(@[cljSymbol("next"), seqColl])]), loopBody])
|
||||
result = loopForm
|
||||
else:
|
||||
let name = bindings.items[0]
|
||||
let coll = bindings.items[1]
|
||||
@@ -498,6 +502,20 @@ proc initMacros*() =
|
||||
cljList(@[cljSymbol("do")] & args[1..^1])
|
||||
)
|
||||
|
||||
defineMacro("when-first", proc(args: seq[CljVal]): CljVal =
|
||||
if args.len < 2: return cljNil()
|
||||
let bindings = args[0]
|
||||
if bindings.kind != ckVector or bindings.items.len != 2:
|
||||
return cljNil()
|
||||
let bindName = bindings.items[0]
|
||||
let bindColl = bindings.items[1]
|
||||
let body = args[1..^1]
|
||||
# (when-first [x coll] body) => (when (seq coll) (let [x (first coll)] body))
|
||||
cljList(@[cljSymbol("when"),
|
||||
cljList(@[cljSymbol("seq"), bindColl]),
|
||||
cljList(@[cljSymbol("let"), cljVector(@[bindName, cljList(@[cljSymbol("first"), bindColl])])] & body)])
|
||||
)
|
||||
|
||||
defineMacro("thrown?", proc(args: seq[CljVal]): CljVal =
|
||||
if args.len == 0: return cljNil()
|
||||
let form = args[0]
|
||||
|
||||
Reference in New Issue
Block a user