138 lines
4.0 KiB
Nim
138 lines
4.0 KiB
Nim
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||
|
# SPDX-License-Identifier: Unlicense
|
||
|
|
||
|
import std/[sequtils, tables]
|
||
|
|
||
|
import spryvm/spryvm
|
||
|
|
||
|
import preserves, preserves/parse
|
||
|
|
||
|
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 pkBigInteger: discard
|
||
|
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 str = StringVal(evalArg(spry)).value
|
||
|
PreservesNode(preserve: parsePreserves(str))
|
||
|
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]
|