Added support for in-place operators, removed all inplace opcodes, renamed DeleteNameFast to DeleteFast and the Update* opcodes to Store*. Updated grammar accordingly

This commit is contained in:
nocturn9x 2021-12-30 16:03:29 +01:00
parent 6070d69d00
commit 19df7e84a1
7 changed files with 52 additions and 36 deletions

View File

@ -153,5 +153,5 @@ DOUBLEQUOTE → "\"";
ALPHA → "a" ... "z" | "A" ... "Z" | "_"; // Alphanumeric characters
UNICODE → 0x00 ... 0x10FFFD; // This covers the whole unicode range
DIGIT → "0" ... "9"; // Arabic digits
ASSIGNTOKENS → '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
ASSIGNTOKENS → "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "**=" | "//=" | "="
```

View File

@ -422,9 +422,8 @@ proc declareName(self: Compiler, node: ASTNode) =
self.emitByte(DeclareName)
self.emitBytes(self.identifierConstant(IdentExpr(node.name)))
else:
# Statically resolved variable here. Only creates a new StaticName entry
# so that self.identifier (and, by extension, self.getStaticIndex) emit the
# proper stack offset
# Statically resolved variable here. Only creates a new Name entry
# so that self.identifier emits the proper stack offset
if self.names.high() > 16777215:
# If someone ever hits this limit in real-world scenarios, I swear I'll
# slap myself 100 times with a sign saying "I'm dumb". Mark my words
@ -477,10 +476,10 @@ proc identifier(self: Compiler, node: IdentExpr) =
else:
let index = self.getStaticIndex(node)
if index != -1:
self.emitByte(LoadFast) # Static name resolution
self.emitByte(LoadFast) # Static name resolution, loads value at index in the stack
self.emitBytes(index.toTriple())
else:
self.emitByte(LoadName)
self.emitByte(LoadName) # Resolves by name, at runtime, in a global hashmap
self.emitBytes(self.identifierConstant(node))
@ -497,11 +496,41 @@ proc assignment(self: Compiler, node: ASTNode) =
# so we can ensure the name is a constant
self.expression(node.value)
let index = self.getStaticIndex(name)
case node.token.lexeme:
of "+=":
self.emitByte(BinaryAdd)
of "-=":
self.emitByte(BinarySubtract)
of "/=":
self.emitByte(BinaryDivide)
of "*=":
self.emitByte(BinaryMultiply)
of "**=":
self.emitByte(BinaryPow)
of "//=":
self.emitByte(BinaryFloorDiv)
of "%=":
self.emitByte(BinaryMod)
of "&=":
self.emitByte(BinaryAnd)
of "^=":
self.emitByte(BinaryXor)
of ">>=":
self.emitByte(BinaryShiftRight)
of "<<=":
self.emitByte(BinaryShiftLeft)
else:
discard
# InPlace operators just change
# what values is set to a given
# stack offset/name so we only
# need to perform the operation
# as usual and then store it
if index != -1:
self.emitByte(UpdateFast)
self.emitByte(StoreFast)
self.emitBytes(index.toTriple())
else:
self.emitByte(UpdateName)
self.emitByte(StoreName)
self.emitBytes(self.makeConstant(name))
of setItemExpr:
discard

View File

@ -57,13 +57,14 @@ const double = to_table({"**": DoubleAsterisk,
"^=": InplaceXor,
"&=": InplaceAnd,
"|=": InplaceOr,
"~=": InplaceNot,
"%=": InplaceMod,
})
# Table of all triple-character tokens
const triple = to_table({"//=": InplaceFloorDiv,
"**=": InplacePow
"**=": InplacePow,
">>=": InplaceRightShift,
"<<=": InplaceLeftShift
})

View File

@ -90,21 +90,6 @@ type
LogicalNot,
LogicalAnd,
LogicalOr,
# Binary in-place operators. Same as their non in-place counterparts
# except they operate on already existing names
InPlaceAdd,
InPlaceSubtract,
InPlaceDivide,
InPlaceFloorDiv,
InPlaceMultiply,
InPlacePow,
InPlaceMod,
InPlaceRightShift,
InPlaceLeftShift,
InPlaceXor,
InPlaceOr,
InPlaceAnd,
InPlaceNot,
# Constants/singletons
Nil,
True,
@ -120,10 +105,10 @@ type
DeclareName, # Declares a global dynamically bound name in the current scope
LoadName, # Loads a dynamically bound variable
LoadFast, # Loads a statically bound variable
UpdateName, # Updates a dynamically bound variable's value
UpdateFast, # Updates a statically bound variable's value
StoreName, # Sets/updates a dynamically bound variable's value
StoreFast, # Sets/updates a statically bound variable's value
DeleteName, # Unbinds a dynamically bound variable's name from the current scope
DeleteNameFast, # Unbinds a statically bound variable's name from the current scope
DeleteFast, # Unbinds a statically bound variable's name from the current scope
# Looping and jumping
JumpIfFalse, # Jumps to an absolute index in the bytecode if the value at the top of the stack is falsey
JumpIfTrue, # Jumps to an absolute index in the bytecode if the value at the top of the stack is truthy
@ -170,17 +155,15 @@ const simpleInstructions* = {Return, BinaryAdd, BinaryMultiply,
BinarySlice, Pop, UnaryNegate,
BinaryIs, BinaryAs, GreaterOrEqual,
LessOrEqual, BinaryOr, BinaryAnd,
UnaryNot, InPlaceAdd, InPlaceDivide,
InPlaceFloorDiv, InPlaceMod, InPlaceMultiply,
InPlaceSubtract, BinaryFloorDiv, BinaryOf, Raise,
UnaryNot, BinaryFloorDiv, BinaryOf, Raise,
ReRaise, BeginTry, FinishTry, Yield, Await}
# Constant instructions are instructions that operate on the bytecode constant table
const constantInstructions* = {LoadConstant, DeclareName, LoadName, UpdateName, DeleteName}
const constantInstructions* = {LoadConstant, DeclareName, LoadName, StoreName, DeleteName}
# Stack triple instructions operate on the stack at arbitrary offsets and pop arguments off of it in the form
# of 24 bit integers
const stackTripleInstructions* = {Call, UpdateFast, DeleteNameFast, LoadFast}
const stackTripleInstructions* = {Call, StoreFast, DeleteFast, LoadFast}
# Stack Double instructions operate on the stack at arbitrary offsets and pop arguments off of it in the form
# of 16 bit integers

View File

@ -62,8 +62,9 @@ type
LogicalAnd, LogicalOr, LogicalNot, FloorDiv, # and or not //
InplaceAdd, InplaceSub, InplaceDiv, # += -= /=
InplaceMod, InplaceMul, InplaceXor, # %= *= ^=
InplaceAnd, InplaceOr, InplaceNot, # &= |= ~=
InplaceAnd, InplaceOr, # &= |=
DoubleEqual, InplaceFloorDiv, InplacePow, # == //= **=
InplaceRightShift, InplaceLeftShift
# Miscellaneous

View File

@ -486,7 +486,9 @@ proc assignment(self: Parser): ASTNode =
## expression (including stuff like a.b = 1).
## Slice assignments are also parsed here
result = self.bitwiseOr()
if self.match(Equal):
if self.match([Equal, InplaceAdd, InplaceSub, InplaceDiv, InplaceMod,
InplacePow, InplaceMul, InplaceXor, InplaceAnd, InplaceOr,
InplaceFloorDiv, InplaceRightShift, InplaceLeftShift]):
let tok = self.peek(-1)
var value = self.expression()
if result.kind in {identExpr, sliceExpr}:

View File

@ -41,7 +41,7 @@ proc getLineEditor: LineEditor =
result.bindHistory(hist) # set default history keybindings
proc main() =
proc main =
var source: string
const filename = "test.jpl"
var tokens: seq[Token]