Integrate marking labels/slots

This commit is contained in:
Reid 'arrdem' McKenzie 2022-08-09 10:05:26 -06:00
parent 99f456e0ee
commit a79644aa23
3 changed files with 76 additions and 37 deletions

View file

@ -25,6 +25,7 @@ from shutil import copy2 as copyfile
import stat import stat
import sys import sys
import typing as t import typing as t
import os
from .util import * from .util import *
@ -350,7 +351,7 @@ def img_info(p: Path) -> ImgInfo:
def is_readonly(src: Path) -> bool: def is_readonly(src: Path) -> bool:
statinfo = os.stat(src, dir_fd=None, follow_symlinks=True) statinfo = os.stat(src, dir_fd=None, follow_symlinks=True)
if statinfo.st_flags & stat.UF_IMMUTABLE: if getattr(statinfo, 'st_flags', 0) & stat.UF_IMMUTABLE:
return True return True
return False return False
@ -364,8 +365,11 @@ def main():
if is_readonly(src): if is_readonly(src):
print(f" warning: {src} is read-only, unable to remove") print(f" warning: {src} is read-only, unable to remove")
else: else:
try:
src.unlink() src.unlink()
print(" unlink: ok") print(" unlink: ok")
except PermissionError:
print(" unlink: fail")
def _copy(src, target): def _copy(src, target):
print(f" rename: {target}") print(f" rename: {target}")
@ -398,8 +402,7 @@ def main():
continue continue
elif ext in ["thm", "lrv", "ico", "sav"] or src.name.startswith("._"): elif ext in ["thm", "lrv", "ico", "sav"] or src.name.startswith("._"):
if opts.destructive: _delete(src)
src.unlink()
continue continue
elif ext in KNOWN_IMG_TYPES: elif ext in KNOWN_IMG_TYPES:
@ -437,11 +440,7 @@ def main():
elif checksum_path_blocks(src) == checksum_path_blocks(target): elif checksum_path_blocks(src) == checksum_path_blocks(target):
print(f" ok: {target}") print(f" ok: {target}")
# src != target && id(src) == id(target); delete src # src != target && id(src) == id(target); delete src
if opts.destructive: _delete(src)
if is_readonly(src):
print(f" warning: {src} is read-only, unable to remove")
else:
src.unlink()
else: else:
# src != target && id(src) != id(target); replace target with src? # src != target && id(src) != id(target); replace target with src?

View file

@ -15,10 +15,39 @@ def gensym(prefix = None) -> isa.Label:
class FuncBuilder(object): class FuncBuilder(object):
def __init__(self) -> None: def __init__(self) -> None:
self._opcodes = [] self._opcodes = []
self._slots = {}
self._stack = 0
self._straightline = True
def _write(self, op): def _write(self, op):
self._opcodes.append(op) self._opcodes.append(op)
# Bookkeeping for statically analyzing the stack
if not self._straightline:
return
match op:
case isa.Label(_):
# Labels abort
self._straightline = False
case isa.GOTO(_) | isa.ATEST(_):
# Control ops abort
self._straightline = False
case isa.DROP(n):
self._stack -= n
case isa.DUP(n):
self._stack += n
case isa.ROT(_):
pass
case _:
self._stack -= getattr(op, 'nargs', 0)
self._stack += 1
def write(self, op: Union[isa.Opcode, isa.Label, Sequence[isa.Opcode]]): def write(self, op: Union[isa.Opcode, isa.Label, Sequence[isa.Opcode]]):
def flatten(o): def flatten(o):
@ -30,6 +59,7 @@ class FuncBuilder(object):
if isinstance(op, (isa.Opcode, isa.Label)): if isinstance(op, (isa.Opcode, isa.Label)):
self._opcodes.append(op) self._opcodes.append(op)
else: else:
for e in op: for e in op:
self.write(e) self.write(e)
@ -37,6 +67,26 @@ class FuncBuilder(object):
def make_label(self, prefix: Optional[str] = ""): def make_label(self, prefix: Optional[str] = ""):
return gensym(prefix) return gensym(prefix)
def mark_label(self, prefix: Optional[str] = ""):
l = self.make_label(prefix=prefix)
self.write(l)
return l
def mark_slot(self, target: Optional[int] = None, prefix: Optional[str] = ""):
if target is not None:
s = gensym(prefix)
self._slots[s] = target
return s
elif self._straightline:
s = gensym(prefix)
self._slots[s] = self._stack
return s
else:
raise Exception("Can't automatically generate slots after control flow (label/goto), provide `target=`.")
def build(self) -> List[isa.Opcode]: def build(self) -> List[isa.Opcode]:
"""Assemble the written body into fully resolved opcodes.""" """Assemble the written body into fully resolved opcodes."""
@ -64,6 +114,9 @@ class FuncBuilder(object):
case isa.ATEST(isa.Label(_) as l): case isa.ATEST(isa.Label(_) as l):
assembled.append(isa.ATEST(labels[l])) assembled.append(isa.ATEST(labels[l]))
case isa.SLOT(isa.Label(_) as l):
assembled.append(isa.SLOT(self._slots[l]))
case o: case o:
assembled.append(o) assembled.append(o)
@ -75,30 +128,3 @@ def assemble(builder_cls=FuncBuilder, /, **opcodes: List[isa.Opcode]) -> List[is
for o in opcodes: for o in opcodes:
builder.write(o) builder.write(o)
return builder.build() return builder.build()
class LocalBuilder(FuncBuilder):
def __init__(self):
super().__init__()
self._stack = 0
self._labels = {}
def _write(self, op):
super()._write(op)
match op:
case isa.DROP(n):
self._stack -= n
case isa.DUP(n):
self._stack += n
case isa.ROT(_):
pass
case _:
self._stack -= getattr(op, 'nargs', 0)
self._stack += 1
def write_local(self, label: isa.Label):
pass
def get_local(self, label: isa.Label):
pass

View file

@ -46,3 +46,17 @@ def test_self_label(builder: FuncBuilder):
isa.DROP(0), isa.DROP(0),
isa.GOTO(1), isa.GOTO(1),
] ]
def test_local_label(builder: FuncBuilder):
s0 = builder.mark_slot()
builder.write(isa.SLOT(s0))
s999 = builder.mark_slot(target=999)
builder.write(isa.SLOT(s999))
instrs = builder.build()
assert instrs == [
isa.SLOT(0),
isa.SLOT(999),
]