hayago style += optimization for negation and binary math ops

This commit is contained in:
prod2 2022-01-27 02:03:23 +01:00
parent 5e18fd7b8d
commit 3007d51b86
3 changed files with 71 additions and 49 deletions

View File

@ -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

View File

@ -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
View File

@ -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: