all repos — min @ f3faad8ddc662888d06bf30fb64cce10e324abb3

A small but practical concatenative programming language.

Added new min tasks.
h3rald h3rald@h3rald.com
Sat, 05 Dec 2020 01:57:53 +0100
commit

f3faad8ddc662888d06bf30fb64cce10e324abb3

parent

037c8b03ae22ba05be805df610ed24af98203b39

7 files changed, 357 insertions(+), 293 deletions(-)

jump to
M core/utils.nimcore/utils.nim

@@ -1,272 +1,282 @@

-import - strutils, - critbits, - json -import - ../packages/nim-sgregex/sgregex, - parser, - value, - scope, - interpreter - -proc reverse[T](xs: openarray[T]): seq[T] = - result = newSeq[T](xs.len) - for i, x in xs: - result[result.len-i-1] = x - -# Library methods - -proc define*(i: In): ref MinScope {.extern:"min_exported_symbol_$1".}= - var scope = newScopeRef(i.scope, minNativeScope) - scope.parent = i.scope - return scope - -proc symbol*(scope: ref MinScope, sym: string, p: MinOperatorProc) {.extern:"min_exported_symbol_$1".}= - scope.symbols[sym] = MinOperator(prc: p, kind: minProcOp, sealed: true) - -proc symbol*(scope: ref MinScope, sym: string, v: MinValue) {.extern:"min_exported_symbol_$1_2".}= - scope.symbols[sym] = MinOperator(val: v, kind: minValOp, sealed: true) - -proc sigil*(scope: ref MinScope, sym: string, p: MinOperatorProc) {.extern:"min_exported_symbol_$1".}= - scope.sigils[sym] = MinOperator(prc: p, kind: minProcOp, sealed: true) - -proc sigil*(scope: ref MinScope, sym: string, v: MinValue) {.extern:"min_exported_symbol_$1_2".}= - scope.sigils[sym] = MinOperator(val: v, kind: minValOp, sealed: true) - -proc finalize*(scope: ref MinScope, name: string = "") {.extern:"min_exported_symbol_$1".}= - var mdl = newDict(scope) - mdl.scope = scope - mdl.objType = "module" - let op = proc(i: In) {.closure.} = - i.evaluating = true - i.push mdl - i.evaluating = false - if name != "": - scope.previous.symbols[name] = MinOperator(kind: minProcOp, prc: op) - -# Dictionary Methods - -proc `%`*(i: In, a: MinValue): JsonNode {.extern:"min_exported_symbol_percent_2".} - -proc dget*(i: In, q: MinValue, s: MinValue): MinValue {.extern:"min_exported_symbol_$1".}= - if not q.isDictionary: - raiseInvalid("Value is not a dictionary") - if q.dVal[s.getString].kind == minProcOp: - raiseInvalid("Key '$1' is set to a native value that cannot be retrieved." % [s.getString]) - result = q.dVal[s.getString].val - -proc dget*(i: In, q: MinValue, s: string): MinValue {.extern:"min_exported_symbol_$1_2".}= - if not q.isDictionary: - raiseInvalid("Value is not a dictionary") - if q.dVal[s].kind == minProcOp: - raiseInvalid("Key $1 is set to a native value that cannot be retrieved." % [s]) - result = q.dVal[s].val - -proc dhas*(q: MinValue, s: MinValue): bool {.extern:"min_exported_symbol_$1".}= - if not q.isDictionary: - raiseInvalid("Value is not a dictionary") - return q.dVal.contains(s.getString) - -proc dhas*(q: MinValue, s: string): bool {.extern:"min_exported_symbol_$1_2".}= - if not q.isDictionary: - raiseInvalid("Value is not a dictionary") - return q.dVal.contains(s) - -proc ddel*(i: In, p: var MinValue, s: MinValue): MinValue {.discardable, extern:"min_exported_symbol_$1".} = - if not p.isDictionary: - raiseInvalid("Value is not a dictionary") - excl(p.scope.symbols, s.getString) - return p - -proc ddel*(i: In, p: var MinValue, s: string): MinValue {.discardable, extern:"min_exported_symbol_$1_2".} = - if not p.isDictionary: - raiseInvalid("Value is not a dictionary") - excl(p.scope.symbols, s) - return p - -proc dset*(i: In, p: var MinValue, s: MinValue, m: MinValue): MinValue {.discardable, extern:"min_exported_symbol_$1".}= - if not p.isDictionary: - raiseInvalid("Value is not a dictionary") - var q = m - p.scope.symbols[s.getString] = MinOperator(kind: minValOp, val: q, sealed: false) - return p - -proc dset*(i: In, p: var MinValue, s: string, m: MinValue): MinValue {.discardable, extern:"min_exported_symbol_$1_2".}= - if not p.isDictionary: - raiseInvalid("Value is not a dictionary") - var q = m - p.scope.symbols[s] = MinOperator(kind: minValOp, val: q, sealed: false) - return p - -proc keys*(i: In, q: MinValue): MinValue {.extern:"min_exported_symbol_$1".}= - # Assumes q is a dictionary - var r = newSeq[MinValue](0) - for i in q.dVal.keys: - r.add newVal(i) - return r.newVal - -proc values*(i: In, q: MinValue): MinValue {.extern:"min_exported_symbol_$1".}= - # Assumes q is a dictionary - var r = newSeq[MinValue](0) - for item in q.dVal.values: - if item.kind == minProcOp: - raiseInvalid("Dictionary contains native values that cannot be accessed.") - r.add item.val - return r.newVal - -# JSON interop - -proc `%`*(i: In, a: MinValue): JsonNode {.extern:"min_exported_symbol_percent_2".}= - case a.kind: - of minBool: - return %a.boolVal - of minSymbol: - return %(";sym:$1" % [a.getstring]) - of minString: - return %a.strVal - of minInt: - return %a.intVal - of minFloat: - return %a.floatVal - of minQuotation: - result = newJArray() - for it in a.qVal: - result.add(i%it) - of minDictionary: - result = newJObject() - for it in a.dVal.pairs: - result[it.key] = i%i.dget(a, it.key) - -proc fromJson*(i: In, json: JsonNode): MinValue {.extern:"min_exported_symbol_$1".}= - case json.kind: - of JNull: - result = newSeq[MinValue](0).newVal - of JBool: - result = json.getBool.newVal - of JInt: - result = json.getBiggestInt.newVal - of JFloat: - result = json.getFloat.newVal - of JString: - let s = json.getStr - if s.match("^;sym:"): - result = sgregex.replace(s, "^;sym:", "").newSym - else: - result = json.getStr.newVal - of JObject: - var res = newDict(i.scope) - for key, value in json.pairs: - var first = $key[0] - var rest = "" - if key.len > 1: - rest = key[1..key.len-1] - first = sgregex.replace(first, "[^a-zA-Z0-9_]", "_") - rest = sgregex.replace(rest, "[^a-zA-Z0-9/!?+*._-]", "_") - discard i.dset(res, first&rest, i.fromJson(value)) - return res - of JArray: - var res = newSeq[MinValue](0) - for value in json.items: - res.add i.fromJson(value) - return res.newVal - -# Validators - -proc validate(value: MinValue, t: string): bool {.extern:"min_exported_symbol_$1".}= - case t: - of "bool": - return value.isBool - of "int": - return value.isInt - of "num": - return value.isNumber - of "quot": - return value.isQuotation - of "dict": - return value.isDictionary - of "'sym": - return value.isStringLike - of "sym": - return value.isSymbol - of "float": - return value.isFloat - of "string": - return value.isString - of "a": - return true - else: - var split = t.split(":") - # Typed dictionaries - if split[0] == "dict": - if value.isTypedDictionary(split[1]): - return true - return false - -proc expect*(i: var MinInterpreter, elements: varargs[string]): seq[MinValue] {.extern:"min_exported_symbol_$1".}= - let stack = elements.reverse.join(" ") - let sym = i.currSym.getString - var valid = newSeq[string](0) - result = newSeq[MinValue](0) - let message = proc(invalid: string): string = - result = "Symbol: $1 - Incorrect values found on the stack:\n" % sym - result &= "- expected: " & stack & " $1\n" % sym - var other = "" - if valid.len > 0: - other = valid.reverse.join(" ") & " " - result &= "- got: " & invalid & " " & other & sym - for element in elements: - let value = i.pop - result.add value - var split = element.split("|") - if split.len > 1: - var res = false - for t in split: - if validate(value, t): - res = true - break - if not res: - raiseInvalid(message(value.typeName)) - elif not validate(value, element): - raiseInvalid(message(value.typeName)) - valid.add element - -proc reqQuotationOfQuotations*(i: var MinInterpreter, a: var MinValue) {.extern:"min_exported_symbol_$1".}= - a = i.pop - if not a.isQuotation: - raiseInvalid("A quotation is required on the stack") - for s in a.qVal: - if not s.isQuotation: - raiseInvalid("A quotation of quotations is required on the stack") - -proc reqQuotationOfNumbers*(i: var MinInterpreter, a: var MinValue) {.extern:"min_exported_symbol_$1".}= - a = i.pop - if not a.isQuotation: - raiseInvalid("A quotation is required on the stack") - for s in a.qVal: - if not s.isNumber: - raiseInvalid("A quotation of numbers is required on the stack") - -proc reqQuotationOfSymbols*(i: var MinInterpreter, a: var MinValue) {.extern:"min_exported_symbol_$1".}= - a = i.pop - if not a.isQuotation: - raiseInvalid("A quotation is required on the stack") - for s in a.qVal: - if not s.isSymbol: - raiseInvalid("A quotation of symbols is required on the stack") - -proc reqTwoNumbersOrStrings*(i: var MinInterpreter, a, b: var MinValue) {.extern:"min_exported_symbol_$1".}= - 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 reqStringOrQuotation*(i: var MinInterpreter, a: var MinValue) {.extern:"min_exported_symbol_$1".}= - a = i.pop - if not a.isQuotation and not a.isString: - raiseInvalid("A quotation or a string is required on the stack") - -proc reqTwoQuotationsOrStrings*(i: var MinInterpreter, a, b: var MinValue) {.extern:"min_exported_symbol_$1".}= - a = i.pop - b = i.pop - if not (a.isQuotation and b.isQuotation or a.isString and b.isString): - raiseInvalid("Two quotations or two strings are required on the stack") +import + strutils, + critbits, + json +import + ../packages/nim-sgregex/sgregex, + parser, + value, + scope, + interpreter + +proc reverse[T](xs: openarray[T]): seq[T] = + result = newSeq[T](xs.len) + for i, x in xs: + result[result.len-i-1] = x + +# Library methods + +proc define*(i: In): ref MinScope {.extern:"min_exported_symbol_$1".}= + var scope = newScopeRef(i.scope, minNativeScope) + scope.parent = i.scope + return scope + +proc symbol*(scope: ref MinScope, sym: string, p: MinOperatorProc) {.extern:"min_exported_symbol_$1".}= + scope.symbols[sym] = MinOperator(prc: p, kind: minProcOp, sealed: true) + +proc symbol*(scope: ref MinScope, sym: string, v: MinValue) {.extern:"min_exported_symbol_$1_2".}= + scope.symbols[sym] = MinOperator(val: v, kind: minValOp, sealed: true) + +proc sigil*(scope: ref MinScope, sym: string, p: MinOperatorProc) {.extern:"min_exported_symbol_$1".}= + scope.sigils[sym] = MinOperator(prc: p, kind: minProcOp, sealed: true) + +proc sigil*(scope: ref MinScope, sym: string, v: MinValue) {.extern:"min_exported_symbol_$1_2".}= + scope.sigils[sym] = MinOperator(val: v, kind: minValOp, sealed: true) + +proc finalize*(scope: ref MinScope, name: string = "") {.extern:"min_exported_symbol_$1".}= + var mdl = newDict(scope) + mdl.scope = scope + mdl.objType = "module" + let op = proc(i: In) {.closure.} = + i.evaluating = true + i.push mdl + i.evaluating = false + if name != "": + scope.previous.symbols[name] = MinOperator(kind: minProcOp, prc: op) + +# Dictionary Methods + +proc `%`*(i: In, a: MinValue): JsonNode {.extern:"min_exported_symbol_percent_2".} + +proc dget*(i: In, q: MinValue, s: MinValue): MinValue {.extern:"min_exported_symbol_$1".}= + if not q.isDictionary: + raiseInvalid("Value is not a dictionary") + if q.dVal[s.getString].kind == minProcOp: + raiseInvalid("Key '$1' is set to a native value that cannot be retrieved." % [s.getString]) + result = q.dVal[s.getString].val + +proc dget*(i: In, q: MinValue, s: string): MinValue {.extern:"min_exported_symbol_$1_2".}= + if not q.isDictionary: + raiseInvalid("Value is not a dictionary") + if q.dVal[s].kind == minProcOp: + raiseInvalid("Key $1 is set to a native value that cannot be retrieved." % [s]) + result = q.dVal[s].val + +proc dhas*(q: MinValue, s: MinValue): bool {.extern:"min_exported_symbol_$1".}= + if not q.isDictionary: + raiseInvalid("Value is not a dictionary") + return q.dVal.contains(s.getString) + +proc dhas*(q: MinValue, s: string): bool {.extern:"min_exported_symbol_$1_2".}= + if not q.isDictionary: + raiseInvalid("Value is not a dictionary") + return q.dVal.contains(s) + +proc ddel*(i: In, p: var MinValue, s: MinValue): MinValue {.discardable, extern:"min_exported_symbol_$1".} = + if not p.isDictionary: + raiseInvalid("Value is not a dictionary") + excl(p.scope.symbols, s.getString) + return p + +proc ddel*(i: In, p: var MinValue, s: string): MinValue {.discardable, extern:"min_exported_symbol_$1_2".} = + if not p.isDictionary: + raiseInvalid("Value is not a dictionary") + excl(p.scope.symbols, s) + return p + +proc dset*(i: In, p: var MinValue, s: MinValue, m: MinValue): MinValue {.discardable, extern:"min_exported_symbol_$1".}= + if not p.isDictionary: + raiseInvalid("Value is not a dictionary") + var q = m + p.scope.symbols[s.getString] = MinOperator(kind: minValOp, val: q, sealed: false) + return p + +proc dset*(i: In, p: var MinValue, s: string, m: MinValue): MinValue {.discardable, extern:"min_exported_symbol_$1_2".}= + if not p.isDictionary: + raiseInvalid("Value is not a dictionary") + var q = m + p.scope.symbols[s] = MinOperator(kind: minValOp, val: q, sealed: false) + return p + +proc keys*(i: In, q: MinValue): MinValue {.extern:"min_exported_symbol_$1".}= + # Assumes q is a dictionary + var r = newSeq[MinValue](0) + for i in q.dVal.keys: + r.add newVal(i) + return r.newVal + +proc values*(i: In, q: MinValue): MinValue {.extern:"min_exported_symbol_$1".}= + # Assumes q is a dictionary + var r = newSeq[MinValue](0) + for item in q.dVal.values: + if item.kind == minProcOp: + raiseInvalid("Dictionary contains native values that cannot be accessed.") + r.add item.val + return r.newVal + +proc pairs*(i: In, q: MinValue): MinValue {.extern:"min_exported_symbol_$1".}= + # Assumes q is a dictionary + var r = newSeq[MinValue](0) + for key, value in q.dVal.pairs: + if value.kind == minProcOp: + raiseInvalid("Dictionary contains native values that cannot be accessed.") + r.add key.newVal + r.add value.val + return r.newVal + +# JSON interop + +proc `%`*(i: In, a: MinValue): JsonNode {.extern:"min_exported_symbol_percent_2".}= + case a.kind: + of minBool: + return %a.boolVal + of minSymbol: + return %(";sym:$1" % [a.getstring]) + of minString: + return %a.strVal + of minInt: + return %a.intVal + of minFloat: + return %a.floatVal + of minQuotation: + result = newJArray() + for it in a.qVal: + result.add(i%it) + of minDictionary: + result = newJObject() + for it in a.dVal.pairs: + result[it.key] = i%i.dget(a, it.key) + +proc fromJson*(i: In, json: JsonNode): MinValue {.extern:"min_exported_symbol_$1".}= + case json.kind: + of JNull: + result = newSeq[MinValue](0).newVal + of JBool: + result = json.getBool.newVal + of JInt: + result = json.getBiggestInt.newVal + of JFloat: + result = json.getFloat.newVal + of JString: + let s = json.getStr + if s.match("^;sym:"): + result = sgregex.replace(s, "^;sym:", "").newSym + else: + result = json.getStr.newVal + of JObject: + var res = newDict(i.scope) + for key, value in json.pairs: + var first = $key[0] + var rest = "" + if key.len > 1: + rest = key[1..key.len-1] + first = sgregex.replace(first, "[^a-zA-Z0-9_]", "_") + rest = sgregex.replace(rest, "[^a-zA-Z0-9/!?+*._-]", "_") + discard i.dset(res, first&rest, i.fromJson(value)) + return res + of JArray: + var res = newSeq[MinValue](0) + for value in json.items: + res.add i.fromJson(value) + return res.newVal + +# Validators + +proc validate(value: MinValue, t: string): bool {.extern:"min_exported_symbol_$1".}= + case t: + of "bool": + return value.isBool + of "int": + return value.isInt + of "num": + return value.isNumber + of "quot": + return value.isQuotation + of "dict": + return value.isDictionary + of "'sym": + return value.isStringLike + of "sym": + return value.isSymbol + of "float": + return value.isFloat + of "string": + return value.isString + of "a": + return true + else: + var split = t.split(":") + # Typed dictionaries + if split[0] == "dict": + if value.isTypedDictionary(split[1]): + return true + return false + +proc expect*(i: var MinInterpreter, elements: varargs[string]): seq[MinValue] {.extern:"min_exported_symbol_$1".}= + let stack = elements.reverse.join(" ") + let sym = i.currSym.getString + var valid = newSeq[string](0) + result = newSeq[MinValue](0) + let message = proc(invalid: string): string = + result = "Symbol: $1 - Incorrect values found on the stack:\n" % sym + result &= "- expected: " & stack & " $1\n" % sym + var other = "" + if valid.len > 0: + other = valid.reverse.join(" ") & " " + result &= "- got: " & invalid & " " & other & sym + for element in elements: + let value = i.pop + result.add value + var split = element.split("|") + if split.len > 1: + var res = false + for t in split: + if validate(value, t): + res = true + break + if not res: + raiseInvalid(message(value.typeName)) + elif not validate(value, element): + raiseInvalid(message(value.typeName)) + valid.add element + +proc reqQuotationOfQuotations*(i: var MinInterpreter, a: var MinValue) {.extern:"min_exported_symbol_$1".}= + a = i.pop + if not a.isQuotation: + raiseInvalid("A quotation is required on the stack") + for s in a.qVal: + if not s.isQuotation: + raiseInvalid("A quotation of quotations is required on the stack") + +proc reqQuotationOfNumbers*(i: var MinInterpreter, a: var MinValue) {.extern:"min_exported_symbol_$1".}= + a = i.pop + if not a.isQuotation: + raiseInvalid("A quotation is required on the stack") + for s in a.qVal: + if not s.isNumber: + raiseInvalid("A quotation of numbers is required on the stack") + +proc reqQuotationOfSymbols*(i: var MinInterpreter, a: var MinValue) {.extern:"min_exported_symbol_$1".}= + a = i.pop + if not a.isQuotation: + raiseInvalid("A quotation is required on the stack") + for s in a.qVal: + if not s.isSymbol: + raiseInvalid("A quotation of symbols is required on the stack") + +proc reqTwoNumbersOrStrings*(i: var MinInterpreter, a, b: var MinValue) {.extern:"min_exported_symbol_$1".}= + 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 reqStringOrQuotation*(i: var MinInterpreter, a: var MinValue) {.extern:"min_exported_symbol_$1".}= + a = i.pop + if not a.isQuotation and not a.isString: + raiseInvalid("A quotation or a string is required on the stack") + +proc reqTwoQuotationsOrStrings*(i: var MinInterpreter, a, b: var MinValue) {.extern:"min_exported_symbol_$1".}= + a = i.pop + b = i.pop + if not (a.isQuotation and b.isQuotation or a.isString and b.isString): + raiseInvalid("Two quotations or two strings are required on the stack")
M lib/min_dict.nimlib/min_dict.nim

@@ -45,6 +45,11 @@ def.symbol("dvalues") do (i: In):

let vals = i.expect("dict") let d = vals[0] i.push i.values(d) + + def.symbol("dpairs") do (i: In): + let vals = i.expect("dict") + let d = vals[0] + i.push i.pairs(d) def.symbol("ddup") do (i: In): let vals = i.expect("dict")
M lib/min_lang.nimlib/min_lang.nim

@@ -82,7 +82,7 @@ let lines = s.strVal.split("\n")

for line in lines: let pair = line.split(":") i.dset(dict, pair[0].strip, pair[1].strip.newVal) - i.push(dict) + i.push(dict) except: raiseInvalid("Invalid/unsupported YAML object (only dictionaries with string values are supported)")
M run.minrun.min

@@ -5,12 +5,15 @@ (args size 2 <) ("No task specified" error 1 exit) when

args 1 get ":" split =taskspec taskspec 0 get :task -"" :subtask +"default" :subtask (taskspec size 1 >) (taskspec 1 get @subtask) when "./tasks/$#.min" (task) =% :task-file (task-file exists? not) ("Task '$1' does not exist" (task) =% error 2 exit) when +; Load task module +task-file load + ; Execute task -task-file load+"$#-tasks" (task) =% eval subtask ^
M tasks/build.mintasks/build.min

@@ -1,25 +1,54 @@

#!/usr/bin/env min -; Define subtasks -{} :subtasks -subtasks +"min.yml" fread from-yaml :config + +; Helpers +( + :prog (prog which "" ==) ("$# is not available" (prog) =% error 1 exit) when +) :required +( + :target-os + "nim" required + "Building - $# (x64)" (target-os) =% notice + "nim c -d:release --cpu:amd64 --os:$# min" (target-os) =% ! + {} + target-os %os + config /version %version + pack +) :cz +( + :vdata + "min" :exe + (vdata /os "windows" ==) ("min.exe" @exe) when + "min_v$version:_$os:_x64.zip" :fn + fn vdata dpairs % ":" "" replace @fn + "Compressing: $#" (fn) =% notice + (exe) => fn zip +) :pack + + +; Define module +{} +( + os cz +) %default +( + "linux" cz +) %linux ( - ("nim" which "" ==) ("Nim is not available" error 1 exit) when - "nim c -d:release min" ! -) %native + "macosx" cz +) %macosx ( - ("hastyscribe" which "" ==) ("HastyScribe is not available" error 2 exit) when - "hastyscribe Min_DeveloperGuide.md --field/version=$#" (version) =% ! + "windows" cz +) %windows +( + "hastyscribe" required + "Building - guide" notice + "hastyscribe Min_DeveloperGuide.md --field/version=$#" (version) =% ! ) %guide ( - ("hastysite" which "" ==) ("HastySite is not available" error 3 exit) when - "cd site && hastysite build && cd .." ! + "hastysite" required + "Building - site" notice + "cd site && hastysite build && cd .." ! ) %site -@subtasks - -(subtasks subtask dhas?) - ; Check if subtask exists, otherwise do a native build - (subtasks subtask dget ->) - ; Execute subtask - (subtasks /native ->) -if ++build-tasks
A tasks/clean.min

@@ -0,0 +1,6 @@

+{} +( + "Cleaning up build files" notice + . ls ("\.(html|zip)$" match filter) rm +) %default ++clean-tasks
A tasks/release.min

@@ -0,0 +1,11 @@

+"build" load + +{} +( + build-tasks ^guide + build-tasks ^site + build-tasks ^windows + build-tasks ^linux + build-tasks ^default +) %default ++release-tasks