all repos — min @ 1a59e1ca38cb85f90117996bb530e5abf8b63e54

A small but practical concatenative programming language.

refactor(validation) Implemented all the most common validators.
h3rald h3rald@h3rald.com
Sat, 11 Jun 2016 21:56:38 +0200
commit

1a59e1ca38cb85f90117996bb530e5abf8b63e54

parent

b154ead9ac4d63e4a3e954c85016154e1066294b

6 files changed, 167 insertions(+), 169 deletions(-)

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

@@ -91,16 +91,51 @@ shallowCopy varname, value

# Validators +proc reqBool*(i: var MinInterpreter, a: var MinValue) = + a = i.pop + if not a.isBool: + raise MinInvalidError(msg: "A bool value is required on the stack") + +proc reqTwoBools*(i: var MinInterpreter, a, b: var MinValue) = + a = i.pop + b = i.pop + if not a.isBool or not b.isBool: + raise MinInvalidError(msg: "Two bool values are required on the stack") + proc reqInt*(i: var MinInterpreter, a: var MinValue) = a = i.pop if not a.isInt: raise MinInvalidError(msg: "An integer is required on the stack") +proc reqTwoInts*(i: var MinInterpreter, a, b: var MinValue) = + a = i.pop + b = i.pop + if not a.isInt or not b.isInt: + raise MinInvalidError(msg: "Two integers are required on the stack") + proc reqQuotation*(i: var MinInterpreter, a: var MinValue) = a = i.pop if not a.isQuotation: raise MinInvalidError(msg: "A quotation is required on the stack") +proc reqIntAndQuotation*(i: var MinInterpreter, a, b: var MinValue) = + a = i.pop + b = i.pop + if not (a.isInt and b.isQuotation): + raise MinInvalidError(msg: "An integer and a quotation are required on the stack") + +proc reqTwoNumbers*(i: var MinInterpreter, a, b: var MinValue) = + a = i.pop + b = i.pop + if not (a.isNumber and b.isNumber): + raise MinInvalidError(msg: "Two numbers are required on the stack") + +proc reqTwoNumbersOrStrings*(i: var MinInterpreter, a, b: var MinValue) = + a = i.pop + b = i.pop + if not (a.isString and b.isString or a.isNumber and b.isNumber): + raise MinInvalidError(msg: "Two numbers or two strings are required on the stack") + proc reqString*(i: var MinInterpreter, a: var MinValue) = a = i.pop if not a.isString:

@@ -111,6 +146,11 @@ a = i.pop

if not a.isQuotation and not a.isString: raise MinInvalidError(msg: "A quotation or a string is required on the stack") +proc reqStringOrSymbol*(i: var MinInterpreter, a: var MinValue) = + a = i.pop + if not a.isStringLike: + raise MinInvalidError(msg: "A symbol or a string is required on the stack") + proc reqTwoStrings*(i: var MinInterpreter, a, b: var MinValue) = a = i.pop b = i.pop

@@ -129,6 +169,12 @@ a = i.pop

b = i.pop if not a.isQuotation or not b.isQuotation: raise MinInvalidError(msg: "Two quotations are required on the stack") + +proc reqTwoQuotationsOrStrings*(i: var MinInterpreter, a, b: var MinValue) = + a = i.pop + b = i.pop + if not (a.isQuotation and b.isQuotation or a.isString and b.isString): + raise MinInvalidError(msg: "Two quotations or two strings are required on the stack") proc reqThreeQuotations*(i: var MinInterpreter, a, b, c: var MinValue) = a = i.pop

@@ -144,3 +190,9 @@ c = i.pop

d = i.pop if not a.isQuotation or not b.isQuotation or not c.isQuotation or not d.isQuotation: raise MinInvalidError(msg: "Four quotations are required on the stack") + +proc reqTwoSimilarTypesNonSymbol*(i: var MinInterpreter, a, b: var MinValue) = + a = i.pop + b = i.pop + if not ((a.kind == a.kind or (a.isNumber and a.isNumber)) and not a.isSymbol): + raise MinInvalidError(msg: "Two non-symbol values of similar type are required on the stack")
M lib/io.nimlib/io.nim

@@ -27,32 +27,19 @@

.symbol("fread") do (i: In): var a: MinValue i.reqString a - if a.strVal.fileExists: - try: - i.push newVal(a.strVal.readFile) - except: - i.error errRuntime, getCurrentExceptionMsg() - else: - i.error errRuntime, "File '$1' not found" % [a.strVal] + i.push newVal(a.strVal.readFile) .symbol("fwrite") do (i: In): var a, b: MinValue i.reqTwoStrings a, b - try: - a.strVal.writeFile(b.strVal) - except: - i.error errRuntime, getCurrentExceptionMsg() + a.strVal.writeFile(b.strVal) .symbol("fappend") do (i: In): var a, b: MinValue i.reqTwoStrings a, b - try: - var f:File - discard f.open(a.strVal, fmAppend) - f.write(b.strVal) - f.close() - except: - i.error errRuntime, getCurrentExceptionMsg() - + var f:File + discard f.open(a.strVal, fmAppend) + f.write(b.strVal) + f.close() .finalize()
M lib/lang.nimlib/lang.nim

@@ -50,8 +50,7 @@ symbol = q2.strVal

elif q2.isQuotation and q2.qVal.len == 1 and q2.qVal[0].kind == minSymbol: symbol = q2.qVal[0].symVal else: - i.error errIncorrect, "The top quotation must contain only one symbol value" - return + raise MinInvalidError(msg:"The top quotation must contain only one symbol value") i.debug "[define] " & symbol & " = " & $q1 i.scope.symbols[symbol] = proc(i: In) = i.push q1.qVal

@@ -67,21 +66,19 @@ symbol = q2.getString

elif q2.isQuotation and q2.qVal.len == 1 and q2.qVal[0].kind == minSymbol: symbol = q2.qVal[0].symVal else: - i.error errIncorrect, "The top quotation must contain only one symbol value" - return + raise MinInvalidError(msg:"The top quotation must contain only one symbol value") i.debug "[bind] " & symbol & " = " & $q1 let res = i.scope.setSymbol(symbol) do (i: In): i.push q1.qVal if not res: - i.error errRuntime, "Attempting to bind undefined symbol: " & symbol + raise MinUndefinedError(msg:"Attempting to bind undefined symbol: " & symbol) .symbol("delete") do (i: In): - var sym = i.pop - if not sym.isStringLike: - i.error errIncorrect, "A string or a symbol are required on the stack" + var sym: MinValue + i.reqStringOrSymbol sym let res = i.scope.delSymbol(sym.getString) if not res: - i.error errRuntime, "Attempting to delete undefined symbol: " & sym.getString + raise MinUndefinedError(msg:"Attempting to delete undefined symbol: " & sym.getString) .symbol("scope") do (i: In): var code: MinValue

@@ -117,16 +114,15 @@ if q1.qVal.len == 1 and q1.qVal[0].kind == minSymbol:

var symbol = q1.qVal[0].symVal if symbol.len == 1: if i.scope.getSigil(symbol).isNotNil: - i.error errSystem, "Sigil '$1' already exists" % [symbol] - return + raise MinRuntimeError(msg:"Sigil '$1' already exists" % [symbol]) i.scope.sigils[symbol] = proc(i: In) = i.evaluating = true i.push q2.qVal i.evaluating = false else: - i.error errIncorrect, "A sigil can only have one character" + raise MinInvalidError(msg:"A sigil can only have one character") else: - i.error errIncorrect, "The top quotation must contain only one symbol value" + raise MinInvalidError(msg:"The top quotation must contain only one symbol value") .symbol("eval") do (i: In): var s: MinValue

@@ -147,25 +143,21 @@ i.reqTwoQuotations symbols, target

let vals = symbols.qVal var q: MinValue if vals.len == 0: - i.error errIncorrect, "No symbol to call" - return + raise MinRuntimeError(msg:"No symbol to call") let origScope = i.scope i.scope = target.scope for c in 0..vals.len-1: if not vals[c].isStringLike: - i.error(errIncorrect, "Quotation must contain only symbols or strings") - return + raise MinInvalidError(msg:"Quotation must contain only symbols or strings") let symbol = vals[c].getString let qProc = i.scope.getSymbol(symbol) if qProc.isNil: - i.error(errUndefined, "Symbol '$1' not found in scope '$2'" % [symbol, i.scope.fullname]) - return + raise MinUndefinedError(msg:"Symbol '$1' not found in scope '$2'" % [symbol, i.scope.fullname]) qProc(i) if vals.len > 1 and c < vals.len-1: q = i.pop if not q.isQuotation: - i.error(errIncorrect, "Unable to evaluate symbol '$1'" % [symbol]) - return + raise MinRuntimeError(msg:"Unable to evaluate symbol '$1'" % [symbol]) i.scope = q.scope i.scope = origScope

@@ -180,14 +172,13 @@

.symbol("raise") do (i: In): var err: MinValue i.reqQuotation err - raise MinRuntimeError(msg: "($1) $2" % [err.qVal[0].getString, err.qVal[1].getString], qVal: err.qVal) + raise MinRuntimeError(msg:"($1) $2" % [err.qVal[0].getString, err.qVal[1].getString], qVal: err.qVal) .symbol("try") do (i: In): var prog: MinValue i.reqQuotation prog if prog.qVal.len < 2: - i.error errIncorrect, "Quotation must contain at least two elements" - return + raise MinInvalidError(msg:"Quotation must contain at least two elements") var code = prog.qVal[0] var catch = prog.qVal[1] var final: MinValue

@@ -196,8 +187,7 @@ if prog.qVal.len > 2:

final = prog.qVal[2] hasFinally = true if (not code.isQuotation or not catch.isQuotation) or (hasFinally and not final.isQuotation): - i.error errIncorrect, "Quotation must contain at least two quotations" - return + raise MinInvalidError(msg:"Quotation must contain at least two quotations") i.unsafe = true try: i.unquote("<try-code>", code)

@@ -253,17 +243,14 @@

# Operations on quotations or strings .symbol("concat") do (i: In): - var q1 = i.pop - var q2 = i.pop + var q1, q2: MinValue + i.reqTwoQuotationsOrStrings q1, q2 if q1.isString and q2.isString: let s = q2.strVal & q1.strVal i.push newVal(s) - elif q1.isQuotation and q2.isQuotation: + else: let q = q2.qVal & q1.qVal i.push newVal(q) - else: - i.error(errIncorrect, "Two quotations or two strings are required on the stack") - return .symbol("first") do (i: In): var q: MinValue

@@ -305,13 +292,9 @@ q.qVal = @[v] & q.qVal

i.push q .symbol("at") do (i: In): - var index = i.pop - var q = i.pop - if index.isInt and q.isQuotation: - i.push q.qVal[index.intVal] - else: - i.error errIncorrect, "An integer and a quotation are required on the stack" - return + var index, q: MinValue + i.reqIntAndQuotation index, q + i.push q.qVal[index.intVal] .symbol("size") do (i: In): var q: MinValue

@@ -338,14 +321,10 @@ i.apply("swap")

i.apply("append") .symbol("times") do (i: In): - let t = i.pop - var prog = i.pop - if t.isInt and prog.isQuotation: - for c in 1..t.intVal: - i.unquote("<times-quotation>", prog) - else: - i.error errIncorrect, "An integer and a quotation are required on the stack" - return + var t, prog: MinValue + i.reqIntAndQuotation t, prog + for c in 1..t.intVal: + i.unquote("<times-quotation>", prog) .symbol("ifte") do (i: In): var fpath, tpath, check: MinValue
M lib/logic.nimlib/logic.nim

@@ -10,8 +10,8 @@

define("logic") .symbol(">") do (i: In): - let n2 = i.pop - let n1 = i.pop + var n2, n1: MinValue + i.reqTwoNumbersOrStrings n2, n1 if n1.isNumber and n2.isNumber: if n1.isInt and n2.isInt: i.push newVal(n1.intVal > n2.intVal)

@@ -21,14 +21,12 @@ elif n1.isFloat and n2.isFloat:

i.push newVal(n1.floatVal > n2.floatVal) elif n1.isFloat and n2.isInt: i.push newVal(n1.floatVal > n2.intVal.float) - elif n1.isString and n2.isString: + else: i.push newVal(n1.strVal > n2.strVal) - else: - i.error(errIncorrect, "Two numbers or two strings are required on the stack") .symbol(">=") do (i: In): - let n2 = i.pop - let n1 = i.pop + var n2, n1: MinValue + i.reqTwoNumbersOrStrings n2, n1 if n1.isNumber and n2.isNumber: if n1.isInt and n2.isInt: i.push newVal(n1.intVal >= n2.intVal)

@@ -38,14 +36,12 @@ elif n1.isFloat and n2.isFloat:

i.push newVal(n1.floatVal >= n2.floatVal) elif n1.isFloat and n2.isInt: i.push newVal(n1.floatVal >= n2.intVal.float) - elif n1.isString and n2.isString: + else: i.push newVal(n1.strVal >= n2.strVal) - else: - i.error(errIncorrect, "Two numbers or two strings are required on the stack") .symbol("<") do (i: In): - let n1 = i.pop - let n2 = i.pop + var n2, n1: MinValue + i.reqTwoNumbersOrStrings n1, n2 if n1.isNumber and n2.isNumber: if n1.isInt and n2.isInt: i.push newVal(n1.intVal > n2.intVal)

@@ -55,14 +51,12 @@ elif n1.isFloat and n2.isFloat:

i.push newVal(n1.floatVal > n2.floatVal) elif n1.isFloat and n2.isInt: i.push newVal(n1.floatVal > n2.intVal.float) - elif n1.isString and n2.isString: + else: i.push newVal(n1.strVal > n2.strVal) - else: - i.error(errIncorrect, "Two numbers or two strings are required on the stack") .symbol("<=") do (i: In): - let n1 = i.pop - let n2 = i.pop + var n2, n1: MinValue + i.reqTwoNumbersOrStrings n1, n2 if n1.isNumber and n2.isNumber: if n1.isInt and n2.isInt: i.push newVal(n1.intVal >= n2.intVal)

@@ -72,59 +66,40 @@ elif n1.isFloat and n2.isFloat:

i.push newVal(n1.floatVal >= n2.floatVal) elif n1.isFloat and n2.isInt: i.push newVal(n1.floatVal >= n2.intVal.float) - elif n1.isString and n2.isString: + else: i.push newVal(n1.strVal >= n2.strVal) - else: - i.error(errIncorrect, "Two numbers or two strings are required on the stack") .symbol("==") do (i: In): - let n2 = i.pop - let n1 = i.pop - if (n1.kind == n2.kind or (n1.isNumber and n2.isNumber)) and not n1.isSymbol: - i.push newVal(n1 == n2) - else: - i.error(errIncorrect, "Two non-symbol values of similar type are required") + var n1, n2: MinValue + i.reqTwoSimilarTypesNonSymbol n2, n1 + i.push newVal(n1 == n2) .symbol("!=") do (i: In): - let n2 = i.pop - let n1 = i.pop - if (n1.kind == n2.kind or (n1.isNumber and n2.isNumber)) and not n1.isSymbol: - i.push newVal(not (n1 == n2)) - else: - i.error(errIncorrect, "Two non-symbol values of similar type are required") + var n1, n2: MinValue + i.reqTwoSimilarTypesNonSymbol n2, n1 + i.push newVal(not (n1 == n2)) # Boolean Logic .symbol("not") do (i: In): - let b = i.pop - if b.isBool: - i.push newVal(not b.boolVal) - else: - i.error(errIncorrect, "A bool value is required on the stack") + var b: MinValue + i.reqBool b + i.push newVal(not b.boolVal) .symbol("and") do (i: In): - let a = i.pop - let b = i.pop - if a.isBool and b.isBool: - i.push newVal(a.boolVal and b.boolVal) - else: - i.error(errIncorrect, "Two bool values are required on the stack") + var a, b: MinValue + i.reqTwoBools a, b + i.push newVal(a.boolVal and b.boolVal) .symbol("or") do (i: In): - let a = i.pop - let b = i.pop - if a.isBool and b.isBool: - i.push newVal(a.boolVal or b.boolVal) - else: - i.error(errIncorrect, "Two bool values are required on the stack") + var a, b: MinValue + i.reqTwoBools a, b + i.push newVal(a.boolVal or b.boolVal) .symbol("xor") do (i: In): - let a = i.pop - let b = i.pop - if a.isBool and b.isBool: - i.push newVal(a.boolVal xor b.boolVal) - else: - i.error(errIncorrect, "Two bool values are required on the stack") + var a, b: MinValue + i.reqTwoBools a, b + i.push newVal(a.boolVal xor b.boolVal) .symbol("string?") do (i: In): if i.peek.kind == minString:
M lib/num.nimlib/num.nim

@@ -10,91 +10,69 @@

define("num") .symbol("+") do (i: In): - let a = i.pop - let b = i.pop + var a, b: MinValue + i.reqTwoNumbers a, b if a.isInt: if b.isInt: i.push newVal(a.intVal + b.intVal) - elif b.isFloat: + else: i.push newVal(a.intVal.float + b.floatVal) - else: - i.error(errTwoNumbersRequired) - elif a.isFloat: + else: if b.isFloat: i.push newVal(a.floatVal + b.floatVal) - elif b.isInt: + else: i.push newVal(a.floatVal + b.intVal.float) - else: - i.error(errTwoNumbersRequired) .symbol("-") do (i: In): - let a = i.pop - let b = i.pop + var a, b: MinValue + i.reqTwoNumbers a, b if a.isInt: if b.isInt: i.push newVal(b.intVal - a.intVal) - elif b.isFloat: + else: i.push newVal(b.floatVal - a.intVal.float) - else: - i.error(errTwoNumbersRequired) - elif a.isFloat: + else: if b.isFloat: i.push newVal(b.floatVal - a.floatVal) - elif b.isInt: - i.push newVal(b.intVal.float - a.floatVal) else: - i.error(errTwoNumbersRequired) + i.push newVal(b.intVal.float - a.floatVal) .symbol("*") do (i: In): - let a = i.pop - let b = i.pop + var a, b: MinValue + i.reqTwoNumbers a, b if a.isInt: if b.isInt: i.push newVal(a.intVal * b.intVal) - elif b.isFloat: + else: i.push newVal(a.intVal.float * b.floatVal) - else: - i.error(errTwoNumbersRequired) - elif a.isFloat: + else: if b.isFloat: i.push newVal(a.floatVal * b.floatVal) - elif b.isInt: + else: i.push newVal(a.floatVal * b.intVal.float) - else: - i.error(errTwoNumbersRequired) .symbol("/") do (i: In): - let a = i.pop - let b = i.pop + var a, b: MinValue + i.reqTwoNumbers a, b if a.isInt: if b.isInt: i.push newVal(b.intVal / a.intVal) - elif b.isFloat: + else: i.push newVal(b.floatVal / a.intVal.float) - else: - i.error(errTwoNumbersRequired) - elif a.isFloat: + else: if b.isFloat: i.push newVal(b.floatVal / a.floatVal) - elif b.isInt: - i.push newVal(b.intVal.float / a.floatVal) else: - i.error(errTwoNumbersRequired) + i.push newVal(b.intVal.float / a.floatVal) .symbol("div") do (i: In): - let b = i.pop - let a = i.pop - if a.isInt and b.isInt: - i.push(newVal(a.intVal div b.intVal)) - else: - i.error errIncorrect, "Two integers are required on the stack" + var a, b: MinValue + i.reqTwoInts b, a + i.push(newVal(a.intVal div b.intVal)) .symbol("mod") do (i: In): - let b = i.pop - let a = i.pop - if a.isInt and b.isInt: - i.push(newVal(a.intVal mod b.intVal)) - else: - i.error errIncorrect, "Two integers are required on the stack" + var a, b: MinValue + i.reqTwoInts b, a + i.push(newVal(a.intVal mod b.intVal)) .finalize()
A minim.nim.cfg

@@ -0,0 +1,27 @@

+define:release +threads:on + +# https://gist.github.com/Drakulix/9881160 +amd64.windows.gcc.path = "/usr/local/mingw/bin" +amd64.windows.gcc.exe = "x86_64-w64-mingw32-gcc" +amd64.windows.gcc.linkerexe = "x86_64-w64-mingw32-gcc" + +# https://gist.github.com/Drakulix/9881160 +i386.windows.gcc.path = "/usr/local/mingw/bin" +i386.windows.gcc.exe = "i686-w64-mingw32-gcc" +i386.windows.gcc.linkerexe = "i686-w64-mingw32-gcc" + +# http://crossgcc.rts-software.org/doku.php?id=compiling_for_linux +i386.linux.gcc.path = "/usr/local/gcc-4.8.1-for-linux32/bin" +i386.linux.gcc.exe = "i586-pc-linux-gcc" +i386.linux.gcc.linkerexe = "i586-pc-linux-gcc" + +# http://crossgcc.rts-software.org/doku.php?id=compiling_for_linux +amd64.linux.gcc.path = "/usr/local/gcc-4.8.1-for-linux64/bin" +amd64.linux.gcc.exe = "x86_64-pc-linux-gcc" +amd64.linux.gcc.linkerexe = "x86_64-pc-linux-gcc" + +# http://www.jaredwolff.com/toolchains/ +arm.linux.gcc.path = "/usr/local/arm-none-linux-gnueabi/bin" +arm.linux.gcc.exe = "arm-none-linux-gnueabi-gcc" +arm.linux.gcc.linkerexe = "arm-none-linux-gnueabi-gcc"