import strformat type NdType* = enum ndNil, ndBool, ndFloat, ndString, ndFunct, type NdValue* = object case ndType*: NdType: of ndNil: discard of ndBool: boolValue*: bool of ndFloat: floatValue*: float64 of ndString: stringValue*: string of ndFunct: placeholder*: string entryII*: int # entry instruction index NatReturn* = object ok*: bool msg*: string # KON VALUE HELPERS, MUST BE DEFINED FOR EVERY KONVALUE proc `$`*(val: NdValue): string = case val.ndType: of ndFloat: return $val.floatValue of ndBool: return $val.boolValue of ndNil: return "nil" of ndString: return val.stringValue of ndFunct: return &"Function object: {val.entryII}" proc isFalsey*(val: NdValue): bool = val.ndType in {ndNil} or (val.ndType == ndBool and not val.boolValue) template isTruthy*(val: NdValue): bool = not isFalsey(val) proc equal*(val, right: NdValue): bool = if val.ndType != right.ndType: false else: case val.ndType: of ndFloat: val.floatValue == right.floatValue of ndBool: val.boolValue == right.boolValue of ndNil: true of ndString: val.stringValue == right.stringValue of ndFunct: val.entryII == right.entryII # NIM VALUE TO KON VALUE WRAPPERS proc toNdValue*(val: float): NdValue = NdValue(ndType: ndFloat, floatValue: val) proc toNdValue*(val: bool): NdValue = NdValue(ndType: ndBool, boolValue: val) proc toNdValue*(val: string): NdValue = NdValue(ndType: ndString, stringValue: val) proc newNdFunction*(ii: int): NdValue = NdValue(ndType: ndFunct, entryII: ii) proc toNdValue*: NdValue = NdValue(ndType: ndNil) # NatReturn misc proc natError*(msg: string): NatReturn {.inline.} = NatReturn(ok: false, msg: msg) const natOk* = NatReturn(ok: true) # OPERATIONS # NOTE: these operations can return ktTypeError with a message if types are invalid proc negate*(val: var NdValue): NatReturn {.inline.} = if (val.ndType != ndFloat): return natError("Operand must be a number.") else: val.floatValue = -val.floatValue return natOk proc add*(val: var NdValue, right: NdValue): NatReturn {.inline.} = if val.ndType == ndFloat and right.ndType == ndFloat: val.floatValue += right.floatValue elif val.ndType == ndString and right.ndType == ndString: val.stringValue &= right.stringValue else: return natError(&"Attempt to add types {val.ndType} and {right.ndType}.") return natOk proc subtract*(val: var NdValue, right: NdValue): NatReturn {.inline.} = if val.ndType == ndFloat and right.ndType == ndFloat: val.floatValue -= right.floatValue else: return natError(&"Attempt to subtract types {val.ndType} and {right.ndType}.") return natOk proc multiply*(val: var NdValue, right: NdValue): NatReturn {.inline.} = if val.ndType == ndFloat and right.ndType == ndFloat: val.floatValue *= right.floatValue else: return natError(&"Attempt to multiply types {val.ndType} and {right.ndType}.") return natOk proc divide*(val: var NdValue, right: NdValue): NatReturn {.inline.} = if val.ndType == ndFloat and right.ndType == ndFloat: val.floatValue /= right.floatValue else: return natError(&"Attempt to divide types {val.ndType} and {right.ndType}.") return natOk proc less*(val: var NdValue, right: NdValue): NatReturn {.inline.} = if val.ndType == ndFloat and right.ndType == ndFloat: val = toNdValue(val.floatValue < right.floatValue) else: return natError(&"Attempt to compare types {val.ndType} and {right.ndType}.") return natOk proc greater*(val: var NdValue, right: NdValue): NatReturn {.inline.} = if val.ndType == ndFloat and right.ndType == ndFloat: val = toNdValue(val.floatValue > right.floatValue) else: return natError(&"Attempt to compare types {val.ndType} and {right.ndType}.") return natOk