Skip to content

Commit

Permalink
added support for %<n>
Browse files Browse the repository at this point in the history
  • Loading branch information
uuk0 committed May 11, 2023
1 parent 21e5412 commit f0f3d48
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 33 deletions.
2 changes: 1 addition & 1 deletion ASSEMBLY.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Expressions can be added as certain parameters to instructions to use instead of
- $\<local name>: local variable
- §\<name>: access a variable from an outer scope
- &\<name>: access to a macro parameter
- %: top of stack (in most cases the default when not provided)
- %\[\<n>]: top of stack, or the n-th item from TOS
- \<access>\[\<index or expression>]: value by \[] operator
- \<access>(\<... args>): call to the attribute; not allowed in CALL opcode source and STORE opcode source
- '\' for discarding the result of an expression (only when STORING)
Expand Down
7 changes: 7 additions & 0 deletions bytecodemanipulation/MutableFunction.py
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,13 @@ def assemble_fast(self, instructions: typing.List[Instruction]):
if not (0 <= arg <= 255 and 0 <= instruction.opcode <= 255):
print("error", instruction)

print("----")

for ins in instructions:
print(repr(ins))

print("----")

self.__raw_code += bytes([instruction.opcode, arg])

def get_raw_code(self):
Expand Down
2 changes: 1 addition & 1 deletion bytecodemanipulation/assembler/AbstractBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ class AbstractAccessExpression(AbstractSourceExpression, ABC):

def __init__(
self,
name: "MacroExpandedIdentifier | str",
name: "IIdentifierAccessor | str",
token: AbstractToken | typing.List[AbstractToken] = None,
):
self.name = name
Expand Down
40 changes: 32 additions & 8 deletions bytecodemanipulation/assembler/Parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,13 @@ def try_consume_access_to_value(

elif start_token.text == "%" and allow_tos:
self.consume(SpecialToken("%"), err_arg=scope)
expr = TopOfStackAccessExpression()

offset = self.try_consume(IntegerToken)

if offset is not None:
return TopOfStackAccessExpression(start_token, int(offset.text))

expr = TopOfStackAccessExpression(start_token)

elif start_token.text == "~":
self.consume(SpecialToken("~"), err_arg=scope)
Expand All @@ -388,10 +394,23 @@ def try_consume_access_to_value(
and "OP" in self.INSTRUCTIONS
and AbstractOpAssembly.IMPLEMENTATION is not None
):
self.consume(start_token)
self.consume(SpecialToken("("), err_arg=scope)
self.consume(start_token, err_arg=scope)

if not (opening := self.try_consume(SpecialToken("("))):
raise throw_positioned_syntax_error(
scope,
self[-1:1],
"expected '(' after OP when used in expressions",
)

expr = AbstractOpAssembly.IMPLEMENTATION.consume(self, scope)
self.consume(SpecialToken(")"), err_arg=scope)

if not self.try_consume(SpecialToken(")")):
raise throw_positioned_syntax_error(
scope,
[opening, self[0]],
"expected ')' after operation",
)

else:
return
Expand Down Expand Up @@ -430,13 +449,14 @@ def try_consume_access_to_value(
)

elif self.try_consume(SpecialToken(".")):
if self.try_consume(SpecialToken("(")):
if opening_bracket := self.try_consume(SpecialToken("(")):
if not (
index := self.try_consume_access_to_value(
allow_primitives=True,
allow_tos=allow_tos,
allow_op=allow_op,
scope=scope,
allow_calls=allow_calls,
)
):
raise throw_positioned_syntax_error(
Expand All @@ -454,15 +474,19 @@ def try_consume_access_to_value(

if not self.try_consume(SpecialToken(")")):
raise throw_positioned_syntax_error(
scope, self.try_inspect() or self[-1], "expected ')'"
scope,
[opening_bracket, self.try_inspect()],
"expected ')'",
)

expr = DynamicAttributeAccessExpression(expr, index)

elif self.try_consume(SpecialToken("!")):
name = self.try_consume(IdentifierToken)
name = self.parse_identifier_like(scope)
expr = StaticAttributeAccessExpression(expr, name)

else:
name = self.try_consume(IdentifierToken)
name = self.parse_identifier_like(scope)
expr = AttributeAccessExpression(expr, name)

elif self.try_inspect() == SpecialToken("(") and allow_calls:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,48 @@
from bytecodemanipulation.assembler.util.tokenizer import IdentifierToken
from bytecodemanipulation.MutableFunction import Instruction
from bytecodemanipulation.MutableFunction import MutableFunction
from bytecodemanipulation.assembler.AbstractBase import IIdentifierAccessor, StaticIdentifier


class AttributeAccessExpression(AbstractAccessExpression):
def __init__(
self, root: AbstractAccessExpression, name_token: IdentifierToken | str
self, root: AbstractAccessExpression, name: IIdentifierAccessor | str
):
self.root = root
self.name_token = (
name_token
if isinstance(name_token, IdentifierToken)
else IdentifierToken(name_token)
self.name = (
name
if not isinstance(name, str)
else StaticIdentifier(name)
)

def __eq__(self, other):
return (
type(self) == type(other)
and self.root == other.root
and self.name_token == other.name_token
and self.name == other.name
)

def __repr__(self):
return f"{self.root}.{self.name_token.text}"
return f"{self.root}.{self.name(None)}"

def copy(self) -> "AttributeAccessExpression":
return AttributeAccessExpression(self.root.copy(), self.name_token)
return AttributeAccessExpression(self.root.copy(), self.name)

def emit_bytecodes(
self, function: MutableFunction, scope: ParsingScope
) -> typing.List[Instruction]:
return self.root.emit_bytecodes(function, scope) + [
Instruction.create_with_token(
self.name_token, function, -1, "LOAD_ATTR", self.name_token.text
Instruction(
function, -1, "LOAD_ATTR", self.name(scope)
)
]

def emit_store_bytecodes(
self, function: MutableFunction, scope: ParsingScope
) -> typing.List[Instruction]:
return self.root.emit_bytecodes(function, scope) + [
Instruction.create_with_token(
self.name_token, function, -1, "STORE_ATTR", self.name_token.text
Instruction(
function, -1, "STORE_ATTR", self.name(scope)
)
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,45 @@
from bytecodemanipulation.assembler.util.tokenizer import IdentifierToken
from bytecodemanipulation.MutableFunction import Instruction
from bytecodemanipulation.MutableFunction import MutableFunction
from bytecodemanipulation.assembler.AbstractBase import IIdentifierAccessor, StaticIdentifier


class StaticAttributeAccessExpression(AbstractAccessExpression):
IS_STATIC = True

def __init__(
self, root: AbstractAccessExpression, name_token: IdentifierToken | str
self, root: AbstractAccessExpression, name: typing.Union["IIdentifierAccessor", str],
):
self.root = root
self.name_token = (
name_token
if isinstance(name_token, IdentifierToken)
else IdentifierToken(name_token)
self.name = (
name
if not isinstance(name, str)
else StaticIdentifier(name)
)

def __eq__(self, other):
return (
type(self) == type(other)
and self.root == other.root
and self.name_token == other.name_token
and self.name == other.name
)

def __repr__(self):
return f"{self.root}.!{self.name_token.text}"
return f"{self.root}.!{self.name(None)}"

def copy(self) -> "StaticAttributeAccessExpression":
return StaticAttributeAccessExpression(self.root.copy(), self.name_token)
return StaticAttributeAccessExpression(self.root.copy(), self.name)

def emit_bytecodes(
self, function: MutableFunction, scope: ParsingScope
) -> typing.List[Instruction]:
return self.root.emit_bytecodes(function, scope) + [
Instruction.create_with_token(
self.name_token,
self.name(scope),
function,
-1,
"STATIC_ATTRIBUTE_ACCESS",
self.name_token.text,
self.name(scope),
)
]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import typing

from bytecodemanipulation.Opcodes import Opcodes

from bytecodemanipulation.assembler.AbstractBase import AbstractAccessExpression
from bytecodemanipulation.assembler.AbstractBase import ParsingScope
from bytecodemanipulation.MutableFunction import Instruction
Expand All @@ -9,8 +11,9 @@
class TopOfStackAccessExpression(AbstractAccessExpression):
PREFIX = "%"

def __init__(self, token=None):
def __init__(self, token=None, offset=0):
self.token = token
self.offset = offset

def __eq__(self, other):
return type(self) == type(other)
Expand All @@ -24,9 +27,22 @@ def copy(self) -> "AbstractAccessExpression":
def emit_bytecodes(
self, function: MutableFunction, scope: ParsingScope
) -> typing.List[Instruction]:
if self.offset != 0:
return [
Instruction(function, -1, Opcodes.ROT_N, arg=self.offset)
for _ in range(self.offset - 1)
] + [
Instruction(function, -1, Opcodes.DUP_TOP),
Instruction(function, -1, Opcodes.ROT_TWO),
Instruction(function, -1, Opcodes.ROT_N, arg=self.offset),
]

return []

def emit_store_bytecodes(
self, function: MutableFunction, scope: ParsingScope
) -> typing.List[Instruction]:
if self.offset != 0:
raise NotImplementedError("%<n> as store target")

return []

0 comments on commit f0f3d48

Please sign in to comment.