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:
parent
6070d69d00
commit
19df7e84a1
|
@ -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 → "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "**=" | "//=" | "="
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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}:
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue