# SPDX-FileCopyrightText: ☭ Emery Hemingway # SPDX-License-Identifier: Unlicense import std/critbits, min, preserves const recordType* = "preserves-record" setType* = "preserves-set" proc toMin*(i: In; pr: sink Value): MinValue = case pr.kind of pkBoolean: result = pr.bool.newVal of pkFloat: result = pr.float.newVal of pkRegister: result = pr.register.newVal of pkBigInt: raiseAssert "big integers not supported by Min bindings" of pkString: result = pr.string.newVal of pkByteString: result = newDict(i.scope) result.objType = "preserves-bytestring" i.dset(result, "bytes", cast[string](pr.bytes).newVal) of pkSymbol: result = pr.symbol.string.newSym of pkRecord: result = newDict(i.scope) result.objType = recordType var fields = newSeq[MinValue](pr.record.len.pred) for j, _ in fields: fields[j] = i.toMin pr.record[j].move result = i.dset(result, "fields", fields.newVal) result = i.dset(result, "label", i.toMin pr.record[pr.record.high].move) of pkSequence: var entries = newSeq[MinValue](pr.sequence.len) for j, _ in pr.sequence: entries[j] = i.toMin pr.sequence[j].move result = entries.newVal of pkSet: result = newDict(i.scope) result.objType = setType var set = newSeq[MinValue](pr.set.len) for j, _ in pr.set: set[j] = i.toMin pr.set[j].move i.dset(result, "set", set.newVal) of pkDictionary: result = newDict(i.scope) for (k, v) in pr.dict.mitems: i.dset(result, i.toMin k.move, i.toMin v.move) of pkEmbedded: result = newDict(i.scope) result.objType = "preserves-embedded" result.obj = pr.embeddedRef[].addr proc toPreserves*(i: In; val: MinValue): Value = case val.kind of minInt: result = val.intVal.toPreserves of minFloat: result = val.floatVal.toPreserves of minQuotation: result = initSequence val.qVal.len for j, v in val.qVal: result.sequence[j] = i.toPreserves v of minCommand: discard of minDictionary: case val.objType of recordType: let fields = i.dget(val, "fields") result = initRecord( i.toPreserves i.dget(val, "label"), fields.qVal.len, ) for j, f in fields.qVal: result.record[j] = i.toPreserves f of setType: result = initSet() for e in i.dget(val, "set").qVal: result.incl i.toPreserves e else: result = initDictionary() for k, v in val.dVal.pairs: result[toSymbol k] = i.toPreserves v.val of minString: result = val.strVal.toPreserves of minSymbol: result = val.symVal.Symbol.toPreserves of minNull: result = initRecord"null" of minBool: result = val.boolVal.toPreserves proc preserves_module*(i: In) = let def = i.define() def.symbol("to-record") do (i: In): let vals = i.expect("a", "quot") var dict = i.scope.newDict dict.objType = recordType dict = i.dset(dict, "label", vals[0]) dict = i.dset(dict, "fields", vals[1]) i.push dict def.symbol("to-set") do (i: In): let vals = i.expect("quot") var dict = i.scope.newDict dict.objType = setType dict = i.dset(dict, "set", vals[0]) i.push dict def.symbol("from-preserves") do (i: In): let vals = i.expect("str") let s = vals[0].getString() try: var pr: Value if s[0].ord < 0x20: pr = decodePreserves s else: pr = parsePreserves s i.push(i.toMin pr) except CatchableError as err: raiseInvalid(err.msg) def.symbol("to-text") do (i: In): let vals = i.expect("a") var pr = i.toPreserves vals[0] i.push ($pr).newVal def.symbol("to-binary") do (i: In): let vals = i.expect("a") var pr = i.toPreserves vals[0] i.push cast[string](pr.encode).newVal def.finalize("preserves")