Implemented fs module.
@@ -84,10 +84,11 @@ #i.debug "[scope] " & scope.fullname
i.scope = origScope proc copystack*(i: MinInterpreter): MinStack = - var s = newSeq[MinValue](0) - for i in i.stack: - s.add i - return s + return i.stack + #var s = newSeq[MinValue](0) + #for i in i.stack: + # s.add i + #return s proc newMinInterpreter*(debugging = false): MinInterpreter = var st:MinStack = newSeq[MinValue](0)@@ -119,7 +120,6 @@ if i.currSym.filename == "":
stderr.writeLine("`$1`: Error - $2" % [i.currSym.symVal, message]) else: stderr.writeLine("$1 [$2,$3] `$4`: Error - $5" % [i.filename, $i.currSym.line, $i.currSym.column, i.currSym.symVal, message]) - #quit(100) template execute(i: In, body: stmt) {.immediate.}= let stack = i.copystack@@ -200,11 +200,6 @@ while i.parser.token != tkEof:
i.execute: val = i.parser.parseMinValue i.push val - -#proc interpretString*(i: In, s, ctxname: string) = -# i.open(newStringStream(s), ctxname) -# discard i.parser.getToken() -# i.interpret() proc unquote*(i: In, name: string, q: var MinValue) = i.createScope(name, q):
@@ -68,6 +68,9 @@
proc newSym*(s: string): MinValue = return MinValue(kind: minSymbol, symVal: s) +proc newQuotation*(): MinValue = + return MinValue(kind: minQuotation, qVal: newSeq[MinValue](0)) + # Error Helpers proc raiseInvalid*(msg: string) =@@ -85,6 +88,102 @@
proc raiseEmptyStack*() = raise MinEmptyStackError(msg: "Insufficient items on the stack") +proc filetype*(p: PathComponent): string = + case p + of pcFile: + return "file" + of pcLinkToFile: + return "filelink" + of pcDir: + return "dir" + of pcLinkToDir: + return "dirlink" + +proc unixPermissions*(s: set[FilePermission]): int = + result = 0 + for p in s: + case p: + of fpUserRead: + result += 400 + of fpUserWrite: + result += 200 + of fpUserExec: + result += 100 + of fpGroupRead: + result += 40 + of fpGroupWrite: + result += 20 + of fpGroupExec: + result += 10 + of fpOthersRead: + result += 4 + of fpOthersWrite: + result += 2 + of fpOthersExec: + result += 1 + +proc toFilePermissions*(p: BiggestInt): set[FilePermission] = + let user = ($p)[0].int + let group = ($p)[1].int + let others = ($p)[2].int + if user == 1: + result.incl fpUserExec + if user == 2: + result.incl fpUserWrite + if user == 3: + result.incl fpUserExec + result.incl fpUserWrite + if user == 4: + result.incl fpUserRead + if user == 5: + result.incl fpUserRead + result.incl fpUserExec + if user == 6: + result.incl fpUserRead + result.incl fpUserWrite + if user == 7: + result.incl fpUserRead + result.incl fpUserWrite + result.incl fpUserExec + if group == 1: + result.incl fpGroupExec + if group == 2: + result.incl fpGroupWrite + if group == 3: + result.incl fpGroupExec + result.incl fpGroupWrite + if group == 4: + result.incl fpGroupRead + if group == 5: + result.incl fpGroupRead + result.incl fpGroupExec + if group == 6: + result.incl fpGroupRead + result.incl fpGroupWrite + if group == 7: + result.incl fpGroupRead + result.incl fpGroupWrite + result.incl fpGroupExec + if others == 1: + result.incl fpOthersExec + if others == 2: + result.incl fpOthersWrite + if others == 3: + result.incl fpOthersExec + result.incl fpOthersWrite + if others == 4: + result.incl fpOthersRead + if others == 5: + result.incl fpOthersRead + result.incl fpOthersExec + if others == 6: + result.incl fpOthersRead + result.incl fpOthersWrite + if others == 7: + result.incl fpOthersRead + result.incl fpOthersWrite + result.incl fpOthersExec + proc getString*(v: MinValue): string = if v.isSymbol: return v.symVal@@ -222,7 +321,7 @@ if found:
q.qVal.delete(c) return q -proc dset*(q: var MinValue, s: MinValue, m: MinValue): MinValue = +proc dset*(q: var MinValue, s: MinValue, m: MinValue): MinValue {.discardable.}= # Assumes q is a dictionary var found = false var c = -1@@ -294,6 +393,12 @@ a = i.pop
b = i.pop if not (a.isString and b.isString or a.isNumber and b.isNumber): raiseInvalid("Two numbers or two strings are required on the stack") + +proc reqStringAndNumber*(i: var MinInterpreter, a, b: var MinValue) = + b = i.pop + a = i.pop + if not (a.isString and b.isNumber): + raiseInvalid("A string and a number are required on the stack") proc reqString*(i: var MinInterpreter, a: var MinValue) = a = i.pop
@@ -0,0 +1,64 @@
+import + strutils, + os, + times +import + ../core/types, + ../core/parser, + ../core/interpreter, + ../core/utils + +proc fs_module*(i: In) = + i.define("fs") + .symbol("mtime") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.getLastModificationTime.toSeconds.newVal + + .symbol("atime") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.getLastAccessTime.toSeconds.newVal + + .symbol("ctime") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.getCreationTime.toSeconds.newVal + + .symbol("hidden?") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.isHidden.newVal + + .symbol("fsize") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.getFileSize.newVal + + .symbol("fstats") do (i: In): + var s: MinValue + i.reqStringLike s + let fi = s.getString.getFileInfo + var info = newSeq[MinValue](0).newVal + info.qVal.add @["device".newSym, fi.id.device.newVal].newVal + info.qVal.add @["file".newSym, fi.id.file.newVal].newVal + info.qVal.add @["type".newSym, fi.kind.filetype.newVal].newVal + info.qVal.add @["size".newSym, fi.size.newVal].newVal + info.qVal.add @["permissions".newSym, fi.permissions.unixPermissions.newVal].newVal + info.qVal.add @["nlinks".newSym, fi.linkCount.newVal].newVal + info.qVal.add @["ctime".newSym, fi.creationTime.toSeconds.newVal].newVal + info.qVal.add @["atime".newSym, fi.lastAccessTime.toSeconds.newVal].newVal + info.qVal.add @["mtime".newSym, fi.lastWriteTime.toSeconds.newVal].newVal + i.push info + + .symbol("ftype") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.getFileInfo.kind.filetype.newVal + + .symbol("fperms") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.getFilePermissions.unixPermissions.newVal + + .finalize()
@@ -229,10 +229,10 @@
.symbol("dump") do (i: In): echo i.dump - .symbol("getstack") do (i: In): + .symbol("get-stack") do (i: In): i.push i.stack.newVal - .symbol("setstack") do (i: In): + .symbol("set-stack") do (i: In): var q: MinValue i.reqQuotation q i.stack = q.qVal
@@ -60,6 +60,16 @@ var key, value: MinValue
i.reqTwoStrings key, value key.strVal.putEnv value.strVal + .symbol("env?") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.existsEnv.newVal + + .symbol("which") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.findExe.newVal + .symbol("os") do (i: In): i.push hostOS.newVal@@ -106,4 +116,24 @@ var ms: MinValue
i.reqInt ms sleep ms.intVal.int + .symbol("chmod") do (i: In): + var s, perms: MinValue + i.reqStringAndNumber s, perms + s.getString.setFilePermissions(perms.intVal.toFilePermissions) + + .symbol("symlink?") do (i: In): + var s: MinValue + i.reqStringLike s + i.push s.getString.symlinkExists.newVal + + .symbol("symlink") do (i: In): + var src, dest: MinValue + i.reqTwoStrings dest, src + src.getString.createSymlink dest.getString + + .symbol("hardlink") do (i: In): + var src, dest: MinValue + i.reqTwoStrings dest, src + src.getString.createHardlink dest.getString + .finalize()
@@ -8,6 +8,7 @@ #num
#stack #sys #time +#fs ; Common sigils (bind) (.) sigil
@@ -13,7 +13,8 @@ lib/min_str,
lib/min_logic, lib/min_time, lib/min_io, - lib/min_sys + lib/min_sys, + lib/min_fs const version* = "1.0.0-dev" var REPL = false@@ -67,8 +68,8 @@ i.stack_module
i.str_module i.sys_module i.time_module + i.fs_module i.eval PRELUDE - proc minimStream(s: Stream, filename: string, debugging = false) = var i = newMinInterpreter(debugging)@@ -100,7 +101,7 @@ proc minimRepl*(i: var MinInterpreter) =
i.stdLib() var s = newStringStream("") i.open(s, "") - echo "Terminal initialized." + echo "MiNiM Shell v" & version echo "-> Type 'exit' or 'quit' to exit." var line: string while true:@@ -116,8 +117,7 @@ i.interpret()
except: warn getCurrentExceptionMsg() finally: - stdout.write "-> " - echo i.dump + echo "-> ($1)" % i.dump.strip proc minimRepl*(debugging = false) = var i = newMinInterpreter(debugging)@@ -150,9 +150,6 @@ else:
discard else: discard - -if REPL: - echo "MiNiM v"&version if s != "": minimString(s, DEBUGGING)
@@ -0,0 +1,22 @@
+@test +#test + +"fs" describe + + "TEST" "test.txt" fwrite + + ("test.txt" fsize 4 ==) assert + + ("test.txt" fperms 644 ==) assert + + ("test.txt" ftype "file" ==) assert + + ("test.txt" hidden? false ==) assert + + ("test.txt" fstats 'type dget "file" ==) assert + + + + report + clear + "test.txt" rm
@@ -47,9 +47,9 @@ "tests/testload.min" rm
(defmod 2 2 mymath %myplus 4 ==) assert - (1 2 3 4 getstack (1 2 3 4) ==) assert + (1 2 3 4 get-stack (1 2 3 4) ==) assert - ((1 2 3) setstack getstack (1 2 3) ==) assert + ((1 2 3) set-stack get-stack (1 2 3) ==) assert ((1 2) (3 4) concat (1 2 3 4) ==) assert@@ -59,7 +59,7 @@ ((1 2 3) rest (2 3) ==) assert
(2 quote (2) ==) assert - ((2 3) unquote getstack (2 3) ==) assert + ((2 3) unquote get-stack (2 3) ==) assert (4 (1 2 3) append (1 2 3 4) ==) assert@@ -100,7 +100,7 @@ (1 at)
) try "Test Message" ==) assert ( - (("test" (1 2) :)) try getstack ("test" (1 2)) ==) assert + (("test" (1 2) :)) try get-stack ("test" (1 2)) ==) assert ( (
@@ -5,9 +5,9 @@ "stack" describe
(1 id 1 ==) assert - (1 pop getstack () ==) assert + (1 pop get-stack () ==) assert - (1 dup getstack (1 1) ==) assert + (1 dup get-stack (1 1) ==) assert (3 2 (1 +) dip + 6 ==) assert
@@ -10,6 +10,8 @@ ".." cd
(&ls "\n" split "systest" contains) assert + ("PATH" env?) assert + ($PATH length 0 >) assert ("TEST" "AAA" putenv $AAA "TEST" ==) assert