Integrate marking labels/slots
This commit is contained in:
parent
2557ff1e4f
commit
3ee2f8ece9
3 changed files with 76 additions and 37 deletions
|
@ -25,6 +25,7 @@ from shutil import copy2 as copyfile
|
|||
import stat
|
||||
import sys
|
||||
import typing as t
|
||||
import os
|
||||
|
||||
from .util import *
|
||||
|
||||
|
@ -350,7 +351,7 @@ def img_info(p: Path) -> ImgInfo:
|
|||
|
||||
def is_readonly(src: Path) -> bool:
|
||||
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 False
|
||||
|
@ -364,8 +365,11 @@ def main():
|
|||
if is_readonly(src):
|
||||
print(f" warning: {src} is read-only, unable to remove")
|
||||
else:
|
||||
src.unlink()
|
||||
print(" unlink: ok")
|
||||
try:
|
||||
src.unlink()
|
||||
print(" unlink: ok")
|
||||
except PermissionError:
|
||||
print(" unlink: fail")
|
||||
|
||||
def _copy(src, target):
|
||||
print(f" rename: {target}")
|
||||
|
@ -398,8 +402,7 @@ def main():
|
|||
continue
|
||||
|
||||
elif ext in ["thm", "lrv", "ico", "sav"] or src.name.startswith("._"):
|
||||
if opts.destructive:
|
||||
src.unlink()
|
||||
_delete(src)
|
||||
continue
|
||||
|
||||
elif ext in KNOWN_IMG_TYPES:
|
||||
|
@ -437,11 +440,7 @@ def main():
|
|||
elif checksum_path_blocks(src) == checksum_path_blocks(target):
|
||||
print(f" ok: {target}")
|
||||
# src != target && id(src) == id(target); delete src
|
||||
if opts.destructive:
|
||||
if is_readonly(src):
|
||||
print(f" warning: {src} is read-only, unable to remove")
|
||||
else:
|
||||
src.unlink()
|
||||
_delete(src)
|
||||
|
||||
else:
|
||||
# src != target && id(src) != id(target); replace target with src?
|
||||
|
|
|
@ -15,10 +15,39 @@ def gensym(prefix = None) -> isa.Label:
|
|||
class FuncBuilder(object):
|
||||
def __init__(self) -> None:
|
||||
self._opcodes = []
|
||||
self._slots = {}
|
||||
self._stack = 0
|
||||
self._straightline = True
|
||||
|
||||
def _write(self, 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 flatten(o):
|
||||
|
@ -30,6 +59,7 @@ class FuncBuilder(object):
|
|||
|
||||
if isinstance(op, (isa.Opcode, isa.Label)):
|
||||
self._opcodes.append(op)
|
||||
|
||||
else:
|
||||
for e in op:
|
||||
self.write(e)
|
||||
|
@ -37,6 +67,26 @@ class FuncBuilder(object):
|
|||
def make_label(self, prefix: Optional[str] = ""):
|
||||
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]:
|
||||
"""Assemble the written body into fully resolved opcodes."""
|
||||
|
||||
|
@ -64,6 +114,9 @@ class FuncBuilder(object):
|
|||
case isa.ATEST(isa.Label(_) as l):
|
||||
assembled.append(isa.ATEST(labels[l]))
|
||||
|
||||
case isa.SLOT(isa.Label(_) as l):
|
||||
assembled.append(isa.SLOT(self._slots[l]))
|
||||
|
||||
case o:
|
||||
assembled.append(o)
|
||||
|
||||
|
@ -75,30 +128,3 @@ def assemble(builder_cls=FuncBuilder, /, **opcodes: List[isa.Opcode]) -> List[is
|
|||
for o in opcodes:
|
||||
builder.write(o)
|
||||
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
|
||||
|
|
|
@ -46,3 +46,17 @@ def test_self_label(builder: FuncBuilder):
|
|||
isa.DROP(0),
|
||||
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),
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue