Implemented comparison operators.
h3rald h3rald@h3rald.com
Sun, 23 Nov 2014 19:38:17 +0100
4 files changed,
175 insertions(+),
32 deletions(-)
M
interpreter.nim
→
interpreter.nim
@@ -26,7 +26,7 @@ const ERRORS: array [TMinError, string] = [
"A system error occurred", "A parsing error occurred", "A generic error occurred", - "The stack is empty", + "Insufficient items on the stack", "Quotation not found on the stack", "Symbol undefined", "Incorrect items on the stack",@@ -44,7 +44,6 @@ return i
proc error*(i: TMinInterpreter, status: TMinError, message = "") = var msg = if message == "": ERRORS[status] else: message - var start = "" if i.filename != "": stderr.writeln("$1[$2,$3] `$4`: Error - $5" %[i.filename, $i.currSym.line, $i.currSym.last, i.currSym.symVal, msg]) else:
M
parser.nim
→
parser.nim
@@ -334,11 +334,13 @@ inc(my.bufpos)
result = tkBracketRi of '\0': result = tkEof - else: + else: + result = parseSymbol(my) case my.a of "true": result = tkTrue of "false": result = tkFalse - else: result = parseSymbol(my) + else: + discard my.token = result@@ -354,7 +356,7 @@ my.kind = eMinError
my.err = errEofExpected of stateStart: case tk - of tkString, tkInt, tkFloat: + of tkString, tkInt, tkFloat, tkTrue, tkFalse: my.state[i] = stateEof # expect EOF next! my.kind = TMinEventKind(ord(tk)) of tkBracketLe:@@ -367,7 +369,7 @@ my.kind = eMinError
my.err = errEofExpected of stateQuotation: case tk - of tkString, tkInt, tkFloat: + of tkString, tkInt, tkFloat, tkTrue, tkFalse: my.kind = TMinEventKind(ord(tk)) of tkBracketLe: my.state.add(stateQuotation)@@ -380,7 +382,7 @@ my.kind = eMinError
my.err = errBracketRiExpected of stateExpectValue: case tk - of tkString, tkInt, tkFloat: + of tkString, tkInt, tkFloat, tkTrue, tkFalse: my.kind = TMinEventKind(ord(tk)) of tkBracketLe: my.state.add(stateQuotation)@@ -448,3 +450,33 @@
proc print*(a: TMinValue) = stdout.write($a) +proc `==`*(a: TMinValue, b: TMinValue): bool = + if a.kind == minInt and b.kind == minInt: + return a.intVal == b.intVal + elif a.kind == minInt and b.kind == minFloat: + return a.intVal.float == b.intVal.float + elif a.kind == minFloat and b.kind == minFloat: + return a.floatVal == b.floatVal + elif a.kind == minFloat and b.kind == minInt: + return a.floatVal == b.intVal.float + elif a.kind == b.kind: + if a.kind == minString: + return a.strVal == b.strVal + elif a.kind == minBool: + return a.boolVal == b.boolVal + elif a.kind == minQuotation: + if a.qVal.len == b.qVal.len: + var c = 0 + for item in a.qVal: + if item == b.qVal[c]: + c.inc + else: + return false + return true + else: + return false + else: + return false + + +
M
primitives.nim
→
primitives.nim
@@ -1,6 +1,9 @@
import tables, strutils import parser, interpreter, utils +minsym "exit": + quit(0) + # Common stack operations minsym "i":@@ -65,10 +68,10 @@ var q1 = i.pop
var q2 = i.pop if q1.isString and q2.isString: let s = q2.strVal & q1.strVal - i.push newString(s) + i.push newVal(s) elif q1.isQuotation and q2.isQuotation: let q = q2.qVal & q1.qVal - i.push newQuotation(q) + i.push newVal(q) else: i.error(errIncorrect, "Two quotations or two strings is required on the stack")@@ -77,16 +80,16 @@ var q = i.pop
if q.isQuotation: i.push q.qVal[0] elif q.isString: - i.push newString($q.strVal[0]) + i.push newVal($q.strVal[0]) else: i.error(errIncorrect, "A quotation or a string is required on the stack") minsym "rest": var q = i.pop if q.isQuotation: - i.push newQuotation(q.qVal[1..q.qVal.len-1]) + i.push newVal(q.qVal[1..q.qVal.len-1]) elif q.isString: - i.push newString(q.strVal[1..q.strVal.len-1]) + i.push newVal(q.strVal[1..q.strVal.len-1]) else: i.error(errIncorrect, "A quotation or a string is required on the stack")@@ -97,16 +100,16 @@ let a = i.pop
let b = i.pop if a.isInt: if b.isInt: - i.push newInt(a.intVal + b.intVal) + i.push newVal(a.intVal + b.intVal) elif b.isFloat: - i.push newFloat(a.intVal.float + b.floatVal) + i.push newVal(a.intVal.float + b.floatVal) else: i.error(errTwoNumbersRequired) elif a.isFloat: if b.isFloat: - i.push newFloat(a.floatVal + b.floatVal) + i.push newVal(a.floatVal + b.floatVal) elif b.isInt: - i.push newFloat(a.floatVal + b.intVal.float) + i.push newVal(a.floatVal + b.intVal.float) else: i.error(errTwoNumbersRequired)@@ -115,16 +118,16 @@ let a = i.pop
let b = i.pop if a.isInt: if b.isInt: - i.push newInt(b.intVal - a.intVal) + i.push newVal(b.intVal - a.intVal) elif b.isFloat: - i.push newFloat(b.floatVal - a.intVal.float) + i.push newVal(b.floatVal - a.intVal.float) else: i.error(errTwoNumbersRequired) elif a.isFloat: if b.isFloat: - i.push newFloat(b.floatVal - a.floatVal) + i.push newVal(b.floatVal - a.floatVal) elif b.isInt: - i.push newFloat(b.intVal.float - a.floatVal) + i.push newVal(b.intVal.float - a.floatVal) else: i.error(errTwoNumbersRequired)@@ -133,16 +136,16 @@ let a = i.pop
let b = i.pop if a.isInt: if b.isInt: - i.push newInt(a.intVal * b.intVal) + i.push newVal(a.intVal * b.intVal) elif b.isFloat: - i.push newFloat(a.intVal.float * b.floatVal) + i.push newVal(a.intVal.float * b.floatVal) else: i.error(errTwoNumbersRequired) elif a.isFloat: if b.isFloat: - i.push newFloat(a.floatVal * b.floatVal) + i.push newVal(a.floatVal * b.floatVal) elif b.isInt: - i.push newFloat(a.floatVal * b.intVal.float) + i.push newVal(a.floatVal * b.intVal.float) else: i.error(errTwoNumbersRequired)@@ -153,16 +156,16 @@ if b.isInt and b.intVal == 0:
i.error errDivisionByZero if a.isInt: if b.isInt: - i.push newFloat(b.intVal / a.intVal) + i.push newVal(b.intVal / a.intVal) elif b.isFloat: - i.push newFloat(b.floatVal / a.intVal.float) + i.push newVal(b.floatVal / a.intVal.float) else: i.error(errTwoNumbersRequired) elif a.isFloat: if b.isFloat: - i.push newFloat(b.floatVal / a.floatVal) + i.push newVal(b.floatVal / a.floatVal) elif b.isInt: - i.push newFloat(b.intVal.float / a.floatVal) + i.push newVal(b.intVal.float / a.floatVal) else: i.error(errTwoNumbersRequired)@@ -183,6 +186,106 @@ i.error(errIncorrect, "The top quotation must contain only one symbol value")
else: i.error(errIncorrect, "Two quotations or two strings is required on the stack") +# Comparison operators + +minsym ">": + let n2 = i.pop + let n1 = i.pop + if n1.isNumber and n2.isNumber: + if n1.isInt and n2.isInt: + i.push newVal(n1.intVal > n2.intVal) + elif n1.isInt and n2.isFloat: + i.push newVal(n1.intVal.float > n2.floatVal) + 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: + i.push newVal(n1.strVal > n2.strVal) + else: + i.error(errIncorrect, "Two numbers or two strings are required on the stack") + +minsym ">=": + let n2 = i.pop + let n1 = i.pop + if n1.isNumber and n2.isNumber: + if n1.isInt and n2.isInt: + i.push newVal(n1.intVal >= n2.intVal) + elif n1.isInt and n2.isFloat: + i.push newVal(n1.intVal.float >= n2.floatVal) + 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: + i.push newVal(n1.strVal >= n2.strVal) + else: + i.error(errIncorrect, "Two numbers or two strings are required on the stack") + +minsym "<": + let n1 = i.pop + let n2 = i.pop + if n1.isNumber and n2.isNumber: + if n1.isInt and n2.isInt: + i.push newVal(n1.intVal > n2.intVal) + elif n1.isInt and n2.isFloat: + i.push newVal(n1.intVal.float > n2.floatVal) + 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: + i.push newVal(n1.strVal > n2.strVal) + else: + i.error(errIncorrect, "Two numbers or two strings are required on the stack") + +minsym "<=": + let n1 = i.pop + let n2 = i.pop + if n1.isNumber and n2.isNumber: + if n1.isInt and n2.isInt: + i.push newVal(n1.intVal >= n2.intVal) + elif n1.isInt and n2.isFloat: + i.push newVal(n1.intVal.float >= n2.floatVal) + 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: + i.push newVal(n1.strVal >= n2.strVal) + else: + i.error(errIncorrect, "Two numbers or two strings are required on the stack") + +minsym "==": + 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") + +minsym "!=": + 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") + +minsym "not": + 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") + +minalias "quit", "exit" minalias "&", "concat" minalias "%", "print" minalias ":", "def" +minalias "eq", "==" +minalias "noteq", "!=" +minalias "gt", ">" +minalias "lt", "<" +minalias "gte", ">=" +minalias "lte", "<="
M
utils.nim
→
utils.nim
@@ -23,14 +23,23 @@
proc isInt*(s: TMinValue): bool = return s.kind == minInt -proc newString*(s: string): TMinValue = +proc isNumber*(s: TMinValue): bool = + return s.kind == minInt or s.kind == minFloat + +proc isBool*(s: TMinValue): bool = + return s.kind == minBool + +proc newVal*(s: string): TMinValue = return TMinValue(kind: minString, strVal: s) -proc newQuotation*(q: seq[TMinValue]): TMinValue = +proc newVal*(q: seq[TMinValue]): TMinValue = return TMinValue(kind: minQuotation, qVal: q) -proc newInt*(s: int): TMinValue = +proc newVal*(s: int): TMinValue = return TMinValue(kind: minInt, intVal: s) -proc newFloat*(s: float): TMinValue = +proc newVal*(s: float): TMinValue = return TMinValue(kind: minFloat, floatVal: s) + +proc newVal*(s: bool): TMinValue = + return TMinValue(kind: minBool, boolVal: s)