Spry interpreter
This commit is contained in:
parent
8ae2353cab
commit
340ce658d3
|
@ -6,7 +6,7 @@ description = "Sets of named blobs"
|
|||
license = "AGPLv3"
|
||||
srcDir = "src"
|
||||
|
||||
requires "nim >= 0.18.0", "base58", "cbor >= 0.5.1", "siphash", "nimcrypto"
|
||||
requires "nim >= 0.18.0", "base58", "cbor >= 0.5.1", "siphash", "nimcrypto", "spryvm"
|
||||
|
||||
bin = @["blobset"]
|
||||
skipFiles = @["blobset.nim"]
|
||||
|
|
113
src/blobset.nim
113
src/blobset.nim
|
@ -5,6 +5,19 @@ import std/nre, std/os, std/strutils, std/tables, std/parseopt, std/streams, std
|
|||
import cbor
|
||||
import ./blobsets, ./blobsets/filestores
|
||||
|
||||
# Basic Spry
|
||||
import spryvm/spryvm
|
||||
|
||||
# Spry extra modules, as much as possible!
|
||||
import spryvm/sprycore, spryvm/spryextend, spryvm/sprymath, spryvm/spryos, spryvm/spryio,
|
||||
spryvm/spryoo, spryvm/sprystring, spryvm/sprymodules, spryvm/spryreflect, spryvm/sprymemfile,
|
||||
spryvm/spryblock,
|
||||
./blobsets/spryblobs
|
||||
|
||||
import os, strutils
|
||||
when defined(readLine):
|
||||
import rdstdin, linenoise
|
||||
|
||||
#when defined(genode):
|
||||
# import dagfsclient
|
||||
|
||||
|
@ -676,6 +689,90 @@ proc replMain() =
|
|||
outStream.write "\n"
|
||||
flush outStream
|
||||
|
||||
const Prompt = ">>> "
|
||||
|
||||
proc getLine(prompt: string): string =
|
||||
# Using line editing
|
||||
when defined(readLine):
|
||||
result = readLineFromStdin(prompt)
|
||||
else:
|
||||
# Primitive fallback
|
||||
stdout.write(prompt)
|
||||
result = stdin.readline()
|
||||
|
||||
proc spryMain() =
|
||||
let spry = newInterpreter()
|
||||
spry.addCore()
|
||||
spry.addExtend()
|
||||
spry.addMath()
|
||||
spry.addOS()
|
||||
spry.addIO()
|
||||
spry.addOO()
|
||||
spry.addString()
|
||||
spry.addModules()
|
||||
spry.addReflect()
|
||||
spry.addMemfile()
|
||||
spry.addBlock()
|
||||
spry.addBlobSets()
|
||||
var
|
||||
lines, stashed, fileLines = newSeq[string]()
|
||||
suspended: bool = true
|
||||
|
||||
echo "Welcome to interactive Spry!"
|
||||
echo "An empty line will evaluate previous lines, so hit enter twice."
|
||||
# We collect lines until an empty line is entered, easy way to enter
|
||||
# multiline code.
|
||||
|
||||
while true:
|
||||
var line: string
|
||||
if suspended:
|
||||
line = getLine(Prompt)
|
||||
else:
|
||||
if fileLines.len == 0:
|
||||
quit 0
|
||||
# Read a line, eh, would be nice with removeFirst or popFirst...
|
||||
line = fileLines[0]
|
||||
fileLines.delete(0)
|
||||
# Logic for pausing
|
||||
if line.strip() == "# pause":
|
||||
var enter = getLine(" <enter = eval, s = suspend>")
|
||||
if enter.strip() == "s":
|
||||
stdout.write(" <suspended, c = continue>\n")
|
||||
stashed = lines
|
||||
lines = newSeq[string]()
|
||||
suspended = true
|
||||
continue
|
||||
else:
|
||||
stdout.write(line & "\n")
|
||||
|
||||
# Logic to start the script again
|
||||
if suspended and line.strip() == "c":
|
||||
lines = stashed
|
||||
suspended = false
|
||||
continue
|
||||
|
||||
# Finally time to eval
|
||||
if line.strip().len() == 0:
|
||||
let code = lines.join("\n")
|
||||
lines = newSeq[string]()
|
||||
try:
|
||||
# Let the interpreter eval the code. We need to eval whatever we
|
||||
# get (ispry acting as a func). The surrounding block is just because we only
|
||||
# want to pass one Node.
|
||||
var result = spry.evalRoot("[" & code & "]")
|
||||
#discard spry.setBinding(newEvalWord("@"), result)
|
||||
var output = $result
|
||||
# Print any result
|
||||
if output.isNil:
|
||||
output = if suspended: "nil" else: ""
|
||||
stdout.write(output & "\n")
|
||||
except:
|
||||
echo "Oops, sorry about that: " & getCurrentExceptionMsg() & "\n"
|
||||
echo getStackTrace()
|
||||
else:
|
||||
lines.add(line)
|
||||
|
||||
|
||||
proc main() =
|
||||
var cmd = ""
|
||||
for kind, key, val in getopt():
|
||||
|
@ -683,15 +780,11 @@ proc main() =
|
|||
cmd = key
|
||||
break
|
||||
case normalize(cmd)
|
||||
of "":
|
||||
quit("no subcommand specified")
|
||||
of "repl":
|
||||
replMain()
|
||||
of "dump":
|
||||
dumpMain()
|
||||
of "ingest":
|
||||
ingestMain()
|
||||
else:
|
||||
quit("no such subcommand ")
|
||||
of "": quit("no subcommand specified")
|
||||
of "repl": replMain()
|
||||
of "dump": dumpMain()
|
||||
of "ingest": ingestMain()
|
||||
of "spry": spryMain()
|
||||
else: quit("no such subcommand ")
|
||||
|
||||
main()
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
import spryvm/spryvm
|
||||
import ../blobsets, ./filestores
|
||||
import std/strutils, std/tables, std/os
|
||||
|
||||
type BlobIdSpryNode* = ref object of Value
|
||||
id*: BlobId
|
||||
|
||||
type BlobSetSpryNode* = ref object of Value
|
||||
set*: BlobSet
|
||||
|
||||
method eval*(self: BlobIdSpryNode|BlobSetSpryNode; spry: Interpreter): Node = self
|
||||
|
||||
method `$`*(self: BlobIdSpryNode): string = $self.id
|
||||
|
||||
method `$`*(self: BlobSetSpryNode): string = "<BlobSet>"
|
||||
|
||||
type BlobStoreNode* = ref object of Value
|
||||
## Object for store interface and caches
|
||||
store: BlobStore
|
||||
blobs: Table[string, tuple[id: BlobId, size: BiggestInt]]
|
||||
sets: Table[string, BlobSet]
|
||||
|
||||
proc insertPath(store: BlobStore; bs: BlobSet; kind: PathComponent; path: string): BlobSet =
|
||||
result = bs
|
||||
try:
|
||||
case kind
|
||||
of pcFile, pcLinkToFile:
|
||||
var path = normalizedPath path
|
||||
let (id, size) = store.ingestFile(path)
|
||||
path.removePrefix(getCurrentDir())
|
||||
path.removePrefix("/")
|
||||
result = result.insert(path, id, size)
|
||||
writeLine(stdout, id, align($size, 11), " ", path)
|
||||
of pcDir, pcLinkToDir:
|
||||
for kind, subPath in path.walkDir:
|
||||
result = store.insertPath(result, kind, subPath)
|
||||
except:
|
||||
let e = getCurrentException()
|
||||
writeLine(stderr, "failed to ingest '", path, "', ", e.msg)
|
||||
|
||||
proc getSet(env: BlobStoreNode; path: string): BlobSet =
|
||||
result = env.sets.getOrDefault(path)
|
||||
if result.isNil:
|
||||
result = newBlobSet()
|
||||
result = env.store.insertPath(result, path.getFileInfo.kind, path)
|
||||
if not result.isEmpty:
|
||||
env.sets[path] = result
|
||||
|
||||
proc ingestBlobs(env: BlobStoreNode; path: string): BlobSetSpryNode =
|
||||
let bs = env.getSet(path)
|
||||
BlobSetSpryNode(set: bs)
|
||||
|
||||
# Spry Blobset module
|
||||
proc addBlobSets*(spry: Interpreter) =
|
||||
|
||||
nimMeth "ingestBlobs":
|
||||
var env = BlobStoreNode(evalArgInfix(spry))
|
||||
let path = StringVal(evalArg(spry)).value
|
||||
result = ingestBlobs(env, path)
|
||||
|
||||
nimFunc "newBlobStore":
|
||||
let path = StringVal(evalArg(spry)).value
|
||||
BlobStoreNode(
|
||||
store: newNullStore(),
|
||||
blobs: initTable[string, tuple[id: BlobId, size: BiggestInt]](),
|
||||
sets: initTable[string, BlobSet]())
|
||||
|
||||
nimFunc "toBlobId":
|
||||
let str = StringVal(evalArg(spry)).value
|
||||
BlobIdSpryNode(id: str.toBlobId)
|
Loading…
Reference in New Issue