142 lines
4.0 KiB
Nim
142 lines
4.0 KiB
Nim
import strformat
|
|
import types/ndstring
|
|
|
|
type
|
|
NdType* = enum
|
|
ntNil, ntBool, ntFloat, ntString,
|
|
ntFunct,
|
|
|
|
type
|
|
NdValue* = object
|
|
case ndType*: NdType:
|
|
of ntNil:
|
|
discard
|
|
of ntBool:
|
|
boolValue*: bool
|
|
of ntFloat:
|
|
floatValue*: float64
|
|
of ntString:
|
|
stringValue*: NdString
|
|
of ntFunct:
|
|
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 ntFloat:
|
|
return $val.floatValue
|
|
of ntBool:
|
|
return $val.boolValue
|
|
of ntNil:
|
|
return "nil"
|
|
of ntString:
|
|
return $val.stringValue
|
|
of ntFunct:
|
|
return &"Function object: {val.entryII}"
|
|
|
|
proc isFalsey*(val: NdValue): bool =
|
|
val.ndType in {ntNil} or (val.ndType == ntBool 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 ntFloat:
|
|
val.floatValue == right.floatValue
|
|
of ntBool:
|
|
val.boolValue == right.boolValue
|
|
of ntNil:
|
|
true
|
|
of ntString:
|
|
# TODO this was meant for nim strings, not ndStrings, FIXME!
|
|
val.stringValue == right.stringValue
|
|
of ntFunct:
|
|
val.entryII == right.entryII
|
|
|
|
# NIM VALUE TO KON VALUE WRAPPERS
|
|
|
|
proc toNdValue*(val: float): NdValue =
|
|
NdValue(ndType: ntFloat, floatValue: val)
|
|
|
|
proc toNdValue*(val: bool): NdValue =
|
|
NdValue(ndType: ntBool, boolValue: val)
|
|
|
|
proc toNdValue*(val: string): NdValue =
|
|
NdValue(ndType: ntString, stringValue: val.newString())
|
|
|
|
proc newNdFunction*(ii: int): NdValue =
|
|
NdValue(ndType: ntFunct, entryII: ii)
|
|
|
|
proc toNdValue*: NdValue =
|
|
NdValue(ndType: ntNil)
|
|
|
|
# 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 != ntFloat):
|
|
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 == ntFloat and right.ndType == ntFloat:
|
|
val.floatValue += right.floatValue
|
|
elif val.ndType == ntString and right.ndType == ntString:
|
|
val.stringValue = 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 == ntFloat and right.ndType == ntFloat:
|
|
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 == ntFloat and right.ndType == ntFloat:
|
|
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 == ntFloat and right.ndType == ntFloat:
|
|
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 == ntFloat and right.ndType == ntFloat:
|
|
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 == ntFloat and right.ndType == ntFloat:
|
|
val = toNdValue(val.floatValue > right.floatValue)
|
|
else:
|
|
return natError(&"Attempt to compare types {val.ndType} and {right.ndType}.")
|
|
return natOk
|