hayago style += optimization for negation and binary math ops
This commit is contained in:
parent
5e18fd7b8d
commit
3007d51b86
|
@ -3,13 +3,14 @@ type
|
|||
leBasic, leRdstdin
|
||||
ReadlineInterruptedException* = object of CatchableError
|
||||
|
||||
# choose debug options here
|
||||
const debugVM* = false
|
||||
# compiler debug options
|
||||
const debugScanner* = false
|
||||
const debugCompiler* = false
|
||||
const debugDumpChunk* = false
|
||||
const assertionsCompiler* = true # sanity checks in the compiler
|
||||
# vm debug options (setting any to true will slow runtime down!)
|
||||
const debugVM* = false
|
||||
const assertionsVM* = false # sanity checks in the VM, such as the stack being empty at the end
|
||||
const assertionsCompiler* = false # sanity checks in the compiler
|
||||
const profileInstructions* = false # if true, the time spent on every opcode is measured
|
||||
|
||||
# choose a line editor for the repl
|
||||
|
|
68
value.nim
68
value.nim
|
@ -4,9 +4,9 @@ type
|
|||
KonType* = enum
|
||||
ktNil, ktBool, ktFloat, ktString,
|
||||
ktFunct,
|
||||
ktTypeError,
|
||||
ktError,
|
||||
|
||||
const errorTypes = {ktTypeError}
|
||||
const errorTypes = {ktError}
|
||||
|
||||
type
|
||||
KonValue* = object
|
||||
|
@ -25,6 +25,10 @@ type
|
|||
arity*: int # number of arguments
|
||||
of errorTypes:
|
||||
message*: string
|
||||
|
||||
NatReturn* = object
|
||||
ok*: bool
|
||||
msg*: string
|
||||
|
||||
# KON VALUE HELPERS, MUST BE DEFINED FOR EVERY KONVALUE
|
||||
|
||||
|
@ -89,54 +93,64 @@ proc newKonFunction*(ii: int, arity: int): KonValue =
|
|||
proc toKonValue*: KonValue =
|
||||
KonValue(konType: ktNil)
|
||||
|
||||
proc konTypeError*(msg: string): KonValue =
|
||||
KonValue(konType: ktTypeError, message: msg)
|
||||
proc konError*(msg: string): KonValue =
|
||||
KonValue(konType: ktError, message: msg)
|
||||
|
||||
# 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: KonValue): KonValue =
|
||||
proc negate*(val: var KonValue): NatReturn =
|
||||
if (val.konType != ktFloat):
|
||||
return konTypeError("Operand must be a number.")
|
||||
return natError("Operand must be a number.")
|
||||
else:
|
||||
return toKonValue(-val.floatValue)
|
||||
val.floatValue = -val.floatValue
|
||||
return natOk
|
||||
|
||||
proc add*(val: KonValue, right: KonValue): KonValue =
|
||||
proc add*(val: var KonValue, right: KonValue): NatReturn =
|
||||
if val.konType == ktFloat and right.konType == ktFloat:
|
||||
return toKonValue(val.floatValue + right.floatValue)
|
||||
val.floatValue += right.floatValue
|
||||
elif val.konType == ktString and right.konType == ktString:
|
||||
return toKonValue(val.stringValue & right.stringValue)
|
||||
val.stringValue &= right.stringValue
|
||||
else:
|
||||
return konTypeError(&"Attempt to add types {val.konType} and {right.konType}.")
|
||||
|
||||
proc subtract*(val: KonValue, right: KonValue): KonValue =
|
||||
if val.konType == ktFloat and right.konType == ktFloat:
|
||||
return toKonValue(val.floatValue - right.floatValue)
|
||||
else:
|
||||
return konTypeError(&"Attempt to subtract types {val.konType} and {right.konType}.")
|
||||
return natError(&"Attempt to add types {val.konType} and {right.konType}.")
|
||||
return natOk
|
||||
|
||||
proc multiply*(val: KonValue, right: KonValue): KonValue =
|
||||
proc subtract*(val: var KonValue, right: KonValue): NatReturn =
|
||||
if val.konType == ktFloat and right.konType == ktFloat:
|
||||
return toKonValue(val.floatValue * right.floatValue)
|
||||
val.floatValue -= right.floatValue
|
||||
else:
|
||||
return konTypeError(&"Attempt to multiply types {val.konType} and {right.konType}.")
|
||||
return natError(&"Attempt to subtract types {val.konType} and {right.konType}.")
|
||||
return natOk
|
||||
|
||||
|
||||
proc divide*(val: KonValue, right: KonValue): KonValue =
|
||||
proc multiply*(val: var KonValue, right: KonValue): NatReturn =
|
||||
if val.konType == ktFloat and right.konType == ktFloat:
|
||||
return toKonValue(val.floatValue / right.floatValue)
|
||||
val.floatValue *= right.floatValue
|
||||
else:
|
||||
return konTypeError(&"Attempt to divide types {val.konType} and {right.konType}.")
|
||||
return natError(&"Attempt to multiply types {val.konType} and {right.konType}.")
|
||||
return natOk
|
||||
|
||||
proc divide*(val: var KonValue, right: KonValue): NatReturn =
|
||||
if val.konType == ktFloat and right.konType == ktFloat:
|
||||
val.floatValue /= right.floatValue
|
||||
else:
|
||||
return natError(&"Attempt to divide types {val.konType} and {right.konType}.")
|
||||
return natOk
|
||||
|
||||
proc `<`*(val: KonValue, right: KonValue): KonValue =
|
||||
if val.konType == ktFloat and right.konType == ktFloat:
|
||||
return toKonValue(val.floatValue < right.floatValue)
|
||||
else:
|
||||
return konTypeError(&"Attempt to compare types {val.konType} and {right.konType}.")
|
||||
|
||||
return konError(&"Attempt to compare types {val.konType} and {right.konType}.")
|
||||
|
||||
proc `>`*(val: KonValue, right: KonValue): KonValue =
|
||||
if val.konType == ktFloat and right.konType == ktFloat:
|
||||
return toKonValue(val.floatValue > right.floatValue)
|
||||
else:
|
||||
return konTypeError(&"Attempt to compare types {val.konType} and {right.konType}.")
|
||||
return konError(&"Attempt to compare types {val.konType} and {right.konType}.")
|
45
vm.nim
45
vm.nim
|
@ -39,7 +39,7 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
write stderr, &"[line: {line}] {msg}\n"
|
||||
hadError = true
|
||||
|
||||
proc peek(stack: seq[KonValue]): KonValue {.inline.} =
|
||||
template peek(stack: seq[KonValue]): KonValue =
|
||||
stack[stack.high]
|
||||
|
||||
proc pushSafe(stack: var seq[KonValue], val: KonValue): bool =
|
||||
|
@ -61,19 +61,6 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
let index = readDU8()
|
||||
chunk.constants[index]
|
||||
|
||||
proc binary(op: OpCode, left: KonValue, right: KonValue): KonValue =
|
||||
case op:
|
||||
of opAdd:
|
||||
return left.add(right)
|
||||
of opSubtract:
|
||||
return left.subtract(right)
|
||||
of opMultiply:
|
||||
return left.multiply(right)
|
||||
of opDivide:
|
||||
return left.divide(right)
|
||||
else:
|
||||
discard #unreachable
|
||||
|
||||
template frameBottom: int = frames[frames.high].stackBottom
|
||||
while true:
|
||||
{.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
|
||||
|
@ -105,13 +92,33 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
let val: KonValue = readConstant()
|
||||
stack.add(val)
|
||||
of opNegate:
|
||||
let val = stack.pop().negate
|
||||
if not stack.pushSafe(val):
|
||||
let res = stack.peek().negate
|
||||
if not res.ok:
|
||||
runtimeError(res.msg)
|
||||
break
|
||||
of opAdd, opSubtract, opMultiply, opDivide:
|
||||
of opAdd:
|
||||
let right = stack.pop()
|
||||
let left = stack.pop()
|
||||
if not stack.pushSafe(binary(ins, left, right)):
|
||||
let res = stack.peek().add(right)
|
||||
if not res.ok:
|
||||
runtimeError(res.msg)
|
||||
break
|
||||
of opSubtract:
|
||||
let right = stack.pop()
|
||||
let res = stack.peek().subtract(right)
|
||||
if not res.ok:
|
||||
runtimeError(res.msg)
|
||||
break
|
||||
of opMultiply:
|
||||
let right = stack.pop()
|
||||
let res = stack.peek().multiply(right)
|
||||
if not res.ok:
|
||||
runtimeError(res.msg)
|
||||
break
|
||||
of opDivide:
|
||||
let right = stack.pop()
|
||||
let res = stack.peek().divide(right)
|
||||
if not res.ok:
|
||||
runtimeError(res.msg)
|
||||
break
|
||||
of opReturn:
|
||||
if frames.len == 0:
|
||||
|
|
Loading…
Reference in New Issue