diff --git a/lib/cljnim_pvec.nim b/lib/cljnim_pvec.nim index 755b9b6..e65bc1e 100644 --- a/lib/cljnim_pvec.nim +++ b/lib/cljnim_pvec.nim @@ -77,17 +77,13 @@ proc pushLeaf[T](node: PVecNode[T], index: int, shift: int, val: seq[T]): PVecNo # Push a full leaf (seq of up to 32 values) into the tree at position 'index' result = copyNode(node) if shift == 0: - # Should not happen — we always push into internal nodes result = newLeafNode[T](val) else: let childIdx = (index shr shift) and BRANCHING_MASK - if childIdx >= result.children.len: - # Need to grow children array - let oldLen = result.children.len - result.children.setLen(childIdx + 1) - for i in oldLen.. result.intVal: result = args[i] + if a.intVal > result.intVal: result = a + elif a.kind == ckFloat and result.kind == ckFloat: + if isMin: + if a.floatVal < result.floatVal: result = a + else: + if a.floatVal > result.floatVal: result = a + elif a.kind == ckInt and result.kind == ckFloat: + let af = a.intVal.float64 + if isMin: + if af < result.floatVal: result = a + else: + if af > result.floatVal: result = a + elif a.kind == ckFloat and result.kind == ckInt: + let rf = result.intVal.float64 + if isMin: + if a.floatVal < rf: result = a + else: + if a.floatVal > rf: result = a proc cljAbs*(v: CljVal): CljVal = case v.kind diff --git a/src/emitter.nim b/src/emitter.nim index 4184917..8320b5e 100644 --- a/src/emitter.nim +++ b/src/emitter.nim @@ -2394,6 +2394,13 @@ proc emitProgramInternal(forms: seq[CljVal]): string = scopeStack = @[] pushScope() requiredImports = initHashSet[string]() + loopStack = @[] + loopResultVar = "" + nsAliases = @[] + libNsPrefixes = @[] + definedGlobals = initHashSet[string]() + definedFnArities = initTable[string, int]() + multiArityFns = initHashSet[string]() var headerLines: seq[string] = @[ "# Generated by Bara Lang", "import cljnim_runtime", diff --git a/src/eval.nim b/src/eval.nim index 62cbaad..e1dbe5d 100644 --- a/src/eval.nim +++ b/src/eval.nim @@ -725,9 +725,10 @@ proc evalList(items: seq[CljVal], env: Env): EvalResult = coll = args[2] else: coll = args[1] - if coll.kind in {ckList, ckVector} and coll.items.len > 0: + if coll.kind in {ckList, ckVector}: + if coll.items.len == 0: + return EvalResult(ok: false, error: "reduce of empty collection with no initial value") acc = coll.items[0] - # reduce rest var res = acc for i in 1.. 0: + while i < endVal: + items.add(cljInt(i)) + i += step + elif step < 0: + while i > endVal: + items.add(cljInt(i)) + i += step return EvalResult(ok: true, value: cljList(items)) return EvalResult(ok: false, error: "range requires integers") @@ -1132,7 +1134,8 @@ proc evalList(items: seq[CljVal], env: Env): EvalResult = let currentVal = atomRegistry[args[0].strVal] var callItems = @[fn, currentVal] if args.len > 2: - callItems.add(args[2..^1]) + for extra in args[2..^1]: + callItems.add(extra) let callRes = evalList(callItems, env) if not callRes.ok: return callRes atomRegistry[args[0].strVal] = callRes.value diff --git a/src/macros.nim b/src/macros.nim index 2470cb2..6eaa44f 100644 --- a/src/macros.nim +++ b/src/macros.nim @@ -428,8 +428,7 @@ proc initMacros*() = if whileExpr != nil: let gs = cljSymbol(gensymName("dw_")) b = @[cljList(@[cljSymbol("loop"), cljVector(@[gs, cljBool(true)]), - cljList(@[cljSymbol("when"), whileExpr] & b & @[cljList(@[cljSymbol("recur"), gs])]), - cljList(@[cljSymbol("when"), cljBool(false), cljNil()])])] + cljList(@[cljSymbol("when"), whileExpr] & b & @[cljList(@[cljSymbol("recur"), gs])])])] return cljList(@[cljSymbol("do")] & b) # Build nested doseq for multiple pairs, innermost gets the body with modifiers @@ -438,11 +437,10 @@ proc initMacros*() = inner = @[cljList(@[cljSymbol("let"), cljVector(letBinds)] & inner)] if whenExpr != nil: inner = @[cljList(@[cljSymbol("when"), whenExpr] & inner)] - if whileExpr != nil: - let gs = cljSymbol(gensymName("dw_")) - inner = @[cljList(@[cljSymbol("loop"), cljVector(@[gs, cljBool(true)]), - cljList(@[cljSymbol("when"), whileExpr] & inner & @[cljList(@[cljSymbol("recur"), gs])]), - cljList(@[cljSymbol("when"), cljBool(false), cljNil()])])] + if whileExpr != nil: + let gs = cljSymbol(gensymName("dw_")) + inner = @[cljList(@[cljSymbol("loop"), cljVector(@[gs, cljBool(true)]), + cljList(@[cljSymbol("when"), whileExpr] & inner & @[cljList(@[cljSymbol("recur"), gs])])])] proc makeLoop(name: CljVal, coll: CljVal, innerBody: seq[CljVal]): CljVal = if name.kind == ckVector: @@ -606,5 +604,9 @@ proc initMacros*() = return cljList(@[cljSymbol("do")] & body) ) +var macrosInitialized = false + proc initBuiltinMacros*() = + if macrosInitialized: return initMacros() + macrosInitialized = true diff --git a/src/reader.nim b/src/reader.nim index a4a8403..a28c74f 100644 --- a/src/reader.nim +++ b/src/reader.nim @@ -227,6 +227,20 @@ proc readAtom(s: string, i: var int): CljVal = except CatchableError: return cljSymbol(tok) + # Check for ratio literal like 1/5, -1/5, 3/4 + let slashPos = numTok.find('/') + if slashPos > 0 and slashPos < numTok.len - 1: + let numerStr = numTok[0.. 0 and (tok[j-1] == 'e' or tok[j-1] == 'E'): + if sawExp and (numTok[j] == '-' or numTok[j] == '+'): + if j > 0 and (numTok[j-1] == 'e' or numTok[j-1] == 'E'): continue isNumber = false break @@ -354,7 +368,7 @@ proc readMap(s: string, i: var int): CljVal = return cljMapFromPairs(pairs) proc readSet(s: string, i: var int): CljVal = - inc i # skip '{' after # + inc i # skip '{' after # var items: seq[CljVal] = @[] while true: skipWhitespaceAndComments(s, i) @@ -366,7 +380,7 @@ proc readSet(s: string, i: var int): CljVal = let form = readForm(s, i) if form != nil: items.add(form) - return cljList(@[cljSymbol("set"), cljVector(items)]) + return cljSet(items) proc readDispatch(s: string, i: var int): CljVal = inc i # skip '#' diff --git a/src/repl.nim b/src/repl.nim index ad76769..4da6e0e 100644 --- a/src/repl.nim +++ b/src/repl.nim @@ -528,8 +528,14 @@ proc handleClient(state: var ReplState, client: Socket) = client.send($(%*{ "status": "error", "error": { "type": "repl/unknown-op", "message": "Unknown op: " & op } }) & "\n") except EOFError: break - except: - client.send($(%*{ "status": "error", "error": { "type": "repl/protocol-error", "message": "Protocol error" } }) & "\n") + except CatchableError as e: + client.send($(%*{ "status": "error", "error": { "type": "repl/protocol-error", "message": e.msg } }) & "\n") + break + except ValueError as e: + client.send($(%*{ "status": "error", "error": { "type": "repl/parse-error", "message": e.msg } }) & "\n") + break + except OSError as e: + client.send($(%*{ "status": "error", "error": { "type": "repl/io-error", "message": e.msg } }) & "\n") break client.close()