nondescript/value.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