preserves-nim/src/preserves/sprypreserves.nim

155 lines
4.4 KiB
Nim

# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[sequtils, tables]
import spryvm/spryvm
import preserves
type
PreservesNode* = ref object of Value
preserve: Preserve[void]
EmbeddedNode* = ref object of PreservesNode
ByteStringNode* = ref object of StringVal
RecordNode* = ref object of Blok
SetNode = ref object of PreservesNode
method eval*(self: PreservesNode; spry: Interpreter): Node =
self
method `$`*(self: PreservesNode): string =
$self.preserve
method typeName*(self: PreservesNode): string =
"preserves-value"
method typeName*(self: EmbeddedNode): string =
"preserves-embedded-value"
method typeName*(self: ByteStringNode): string =
"preserves-bytestring"
method typeName*(self: RecordNode): string =
"preserves-record"
method typeName*(self: SetNode): string =
"preserves-set"
proc toSpry(pr: Preserve[void], spry: Interpreter): Node =
if pr.embedded:
result = EmbeddedNode(preserve: pr)
# TODO: need to be able to manipulate these
else:
case pr.kind
of pkBoolean:
result = boolVal(pr.bool, spry)
of pkFloat:
result = newValue(pr.float)
of pkDouble:
result = newValue(pr.double)
of pkSignedInteger:
result = newValue(int pr.int)
of pkString:
result = newValue(pr.string)
of pkByteString:
result = ByteStringNode(value: cast[string](pr.bytes))
of pkSymbol:
result =
if pr.symbol == "null": newNilVal()
else: newLitWord(spry, pr.symbol)
of pkRecord:
var comp = RecordNode()
proc f(pr: Preserve[void]): Node = toSpry(pr, spry)
comp.nodes = map(pr.record, f)
result = comp
of pkSequence:
var blk = newBlok()
for e in pr.sequence: blk.add toSpry(e, spry)
result = blk
of pkSet:
result = SetNode(preserve: pr)
of pkDictionary:
var map = newMap()
for (key, val) in pr.dict.items:
map[toSpry(key, spry)] = toSpry(val, spry)
result = map
of pkEmbedded:
result = EmbeddedNode(preserve: pr)
proc toPreserveHook*(node: Node; E: typedesc): Preserve[E] =
if node of PreservesNode:
result = PreservesNode(node).preserve
elif node of RecordNode:
result = Preserve[E](kind: pkRecord)
var comp = RecordNode(node)
proc f(child: Node): Preserve[void] = toPreserve(child, void)
result.record = map(comp.nodes, f)
elif node of ByteStringNode:
result = toPreserve(cast[seq[byte]](ByteStringNode(node).value), E)
elif node of Blok:
var blk = Blok(node)
result = initSequence[E](blk.nodes.len)
for i, child in blk.nodes: result.sequence[i] = toPreserve(child, E)
elif node of Map:
result = initDictionary[E]()
for key, val in Map(node).bindings:
result[toPreserve(key, E)] = toPreserve(val, E)
elif node of StringVal:
result = toPreserve(StringVal(node).value, E)
elif node of LitWord:
result = toSymbol(LitWord(node).word, E)
elif node of IntVal:
result = toPreserve(IntVal(node).value, E)
elif node of FloatVal:
result = toPreserve(FloatVal(node).value, E)
elif node of BoolVal:
result = toPreserve(BoolVal(node).value, E)
else: # node of NilVal:
result = toSymbol("null", E)
when isMainModule:
var
node: Node
pr = toPreserveHook(node, void)
proc addPreserves*(spry: Interpreter) =
nimFunc("parsePreserves"):
let node = evalArg(spry)
if node of StringVal:
let str = StringVal(node).value
result = PreservesNode(preserve: parsePreserves(str))
nimFunc("decodePreserves"):
let node = evalArg(spry)
if node of StringVal:
let str = StringVal(node).value
result = PreservesNode(preserve: decodePreserves(cast[seq[byte]](str)))
nimMeth("encodePreserves"):
let node = evalArgInfix(spry)
if node of PreservesNode:
var bin = encode PreservesNode(node).preserve
result = newValue(cast[string](bin))
nimFunc("fromPreserves"):
let node = evalArg(spry)
if node of PreservesNode:
let pr = PreservesNode(node).preserve
return toSpry(pr, spry)
nimMeth("toPreserves"):
let node = evalArgInfix(spry)
PreservesNode(preserve: node.toPreserve)
nimMeth("arity"):
let node = evalArgInfix(spry)
if node of RecordNode:
return newValue(pred SeqComposite(node).nodes.len)
nimMeth("label"):
let node = evalArgInfix(spry)
if node of RecordNode:
let rec = RecordNode(node)
return rec.nodes[rec.nodes.high]