Skip to content

Commit

Permalink
added get_path to atypes
Browse files Browse the repository at this point in the history
  • Loading branch information
cnvogelg committed Dec 15, 2024
1 parent dcf4b7f commit d17e4a9
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 66 deletions.
13 changes: 13 additions & 0 deletions amitools/vamos/astructs/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def __init__(self, mem, addr, **kwargs):

def get(self, index):
"""Return n-th element in array"""
if type(index) is str:
index = int(index)
entry_addr = self._get_entry_addr(index)
cls_type = self._element_type.get_alias_type()
return cls_type(self._mem, entry_addr)
Expand All @@ -34,6 +36,17 @@ def _get_entry_addr(self, index):
def __getitem__(self, key):
return self.get(key)

def get_path(self, path):
if len(path) == 0:
return self
# allow and index '[num]'
arg = self._get_path_arg(path)
if arg:
index = int(arg)
sub_obj = self.get(index)
sub_path = self._skip_path_arg(path, arg)
return sub_obj.get_path(sub_path)


class ArrayIter:
def __init__(self, array):
Expand Down
10 changes: 10 additions & 0 deletions amitools/vamos/astructs/astruct.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,3 +401,13 @@ def __setattr__(self, field_name, val):
"Field {} is read-only in {}".format(field_name, self)
)
super().__setattr__(field_name, val)

def get_path(self, path):
if len(path) == 0:
return self
field = self._get_next_path_field(path)
if field:
sub_obj = self.get(field)
if sub_obj is not None:
sub_path = self._skip_path_field(path, field)
return sub_obj.get_path(sub_path)
57 changes: 57 additions & 0 deletions amitools/vamos/astructs/typebase.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ def __init__(
if reg:
assert cpu

def clone(self, cls):
"""clone type into a new class"""
kw_args = {"alloc": self._cpu, "mem_obj": self._mem_obj}
return cls(self._mem, self._addr, **kw_args)

def __eq__(self, other):
if type(other) is int:
return self._addr == other
Expand All @@ -71,6 +76,10 @@ def __eq__(self, other):
else:
return NotImplemented

def __bool__(self):
# type objects are always true, so "if obj" works reliably
return True

def get_addr(self):
"""if type is bound to memory then return address otherwise None."""
return self._addr
Expand All @@ -94,6 +103,54 @@ def get_base_offset(self):
"""if type is embedded in a sub structure then return its global offset"""
return self._base_offset

def get_path(self, path):
"""find object along the given path"""
# by default the path has to be empty
assert len(path) == 0
return self

def _get_next_path_field(self, path):
"""split next field from path
return field
"""
# arguments in field are surrounded in '[' and ']'
pos = path.find("[")
if pos != -1:
path = path[:pos]
# fields are separated by '.'
pos = path.find(".")
if pos != -1:
path = path[:pos]
return path

def _skip_path_field(self, path, field):
n = len(field)
if path == field:
return ""
if path[n] == ".":
return path[n + 1 :]
else:
return path[n:]

def _get_path_arg(self, path):
"""return arg or None"""
if len(path) == 0:
return path
if path[0] == "[":
pos = path.find("]")
if pos != -1:
return path[1:pos]
else:
# error: no closing bracket
return None
else:
return None

def _skip_path_arg(self, path, arg):
# skip '[...].'
return path[len(arg) + 3 :]

def __getattr__(self, key):
if key == "addr":
return self._addr
Expand Down
3 changes: 0 additions & 3 deletions amitools/vamos/libtypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,3 @@
# dos
from .lock import FileLock, FileHandle
from .process import CLI, Process, PathList

# type promotion
from .promote import promote_type
23 changes: 21 additions & 2 deletions amitools/vamos/libtypes/list_.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@


class ListIter(object):
def __init__(self, alist, start_node=None):
def __init__(self, alist, start_node=None, promote=False):
self.alist = alist
self.mem = self.alist._mem
self.promote = promote
if start_node is None:
self.node = alist._head.succ.ref
else:
Expand All @@ -21,7 +22,10 @@ def __next__(self):
raise StopIteration()
res = self.node
self.node = succ
return res
if self.promote:
return res.promote_type()
else:
return res


class ListBase:
Expand Down Expand Up @@ -114,6 +118,9 @@ def __init__(self, mem, addr, **kwargs):
self._head = Node(mem, self.addr)
self._tail = Node(mem, self.addr + 4)

def __iter__(self):
return ListIter(self, promote=True)

def __str__(self):
return "[List:@%06x,h=%06x,t=%06x,tp=%06x,%s]" % (
self.addr,
Expand All @@ -123,6 +130,18 @@ def __str__(self):
self.type,
)

def get_path(self, path):
# allow to search list via arg
if len(path) == 0:
return self
# arg?
arg = self._get_path_arg(path)
if arg:
sub_obj = self.find_name(arg)
if sub_obj:
sub_path = self._skip_path_arg(path, arg)
return sub_obj.get_path(sub_path)

# ----- list ops -----

def new_list(self, lt):
Expand Down
21 changes: 20 additions & 1 deletion amitools/vamos/libtypes/node.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
from amitools.vamos.libstructs import NodeStruct, MinNodeStruct
from amitools.vamos.libstructs import NodeStruct, NodeType, MinNodeStruct, LibraryStruct
from amitools.vamos.astructs import AmigaClassDef
from amitools.vamos.libtypes.process import Process
from amitools.vamos.libtypes.task import Task


node_map = {
NodeType.NT_TASK: Task,
NodeType.NT_PROCESS: Process,
NodeType.NT_DEVICE: LibraryStruct,
NodeType.NT_LIBRARY: LibraryStruct,
}


class NodeBase:
Expand Down Expand Up @@ -43,6 +53,15 @@ def __str__(self):

# ----- node ops -----

def promote_type(self):
"""convert objects according to Amiga rules"""
node_type = self.type.get()
if node_type in node_map:
node_cls = node_map[node_type]
return self.clone(node_cls)
else:
return self

def find_name(self, name):
"""find name after this node"""
succ = self.succ.ref
Expand Down
33 changes: 0 additions & 33 deletions amitools/vamos/libtypes/promote.py

This file was deleted.

9 changes: 9 additions & 0 deletions amitools/vamos/libtypes/task.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from amitools.vamos.libstructs import TaskStruct, NodeType, TaskState
from amitools.vamos.astructs import AmigaClassDef
from amitools.vamos.libtypes.process import Process


@AmigaClassDef
Expand All @@ -12,3 +13,11 @@ def new_task(self, pri=0, flags=0, nt=NodeType.NT_TASK):
self.flags.val = flags
self.state.val = TaskState.TS_INVALID
self.mem_entry.new_list(NodeType.NT_MEMORY)

def promote_type(self):
"""promote task to process if type is set accordingly"""
node_type = self.node.type.get()
if node_type == NodeType.NT_PROCESS:
return self.clone(Process)
else:
return self
29 changes: 26 additions & 3 deletions amitools/vamos/tools/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .tool import Tool
from amitools.vamos.astructs import TypeDumper
from amitools.vamos.libstructs import ExecLibraryStruct
from amitools.vamos.libtypes import List, MinList
from amitools.vamos.machine.mock import MockMemory, MultiMockMemory, DummyMockMemory
from amitools.state import ASFFile, ASFParser
import amitools.rom
Expand All @@ -25,7 +26,10 @@ def add_args(self, arg_parser):
# show
parser = sub.add_parser("show", help="show data structures in RAM")
parser.add_argument("file", help="UAE state file (.uss)")
parser.add_argument("-r", "--rom", nargs="+", help="rom files", default=[])
parser.add_argument("what", nargs="?", help="what to show")
parser.add_argument(
"-r", "--rom", action="append", help="rom files", default=[]
)

def run(self, args):
type_cmd = args.type_cmd
Expand Down Expand Up @@ -104,8 +108,27 @@ def show_cmd(self, args):
mem.add(m)
mem.add(DummyMockMemory())

# dump exec library
# get exec library
exec_base = mem.r32(4)
exec_lib = ExecLibraryStruct(mem, exec_base)

# find sub object
obj = exec_lib
if args.what:
obj = obj.get_path(args.what)
if obj is None:
print(f"can't resolve path '{args.what}'")
return 1

dumper = TypeDumper()
dumper.dump_obj(exec_lib)
if type(obj) in (List, MinList):
# dump list
if len(obj) == 0:
print("Empty list")
else:
for elem in obj:
dumper.dump_obj(elem)
else:
# dump object
dumper.dump_obj(obj)
return 0
4 changes: 4 additions & 0 deletions test/unit/astructs_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ def astructs_array_test():
a[0].val = 23
assert a[0].val == 23
assert a.get(0).val == 23
# path
assert a.get_path("") is a
assert a.get_path("[0]") == a.get(0)
assert a.get_path("[9]") == a.get(9)


def astructs_array_iter_test():
Expand Down
7 changes: 7 additions & 0 deletions test/unit/astructs_astruct.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ def astructs_astruct_base_inst_test():
# try to assign field directly -> forbidden!
with pytest.raises(AttributeError):
ms.ms_Word = 42
# path test
assert ms.get_path("") is ms
assert ms.get_path("ms_Word") is ms.get_path("ms_Word")


def astructs_astruct_base_inst_reg_test():
Expand Down Expand Up @@ -206,6 +209,10 @@ def astructs_astruct_sub_struct_inst_test():
# find sub field
field = ss.ss_My2.ms_Pad
assert ss.sfields.find_sub_field_by_def(SubStruct.sdef.ss_My2.ms_Pad) == field
# path test
assert ss.get_path("") is ss
assert ss.get_path("ss_My") is ms
assert ss.get_path("ss_My.ms_Word") is ms.get("ms_Word")


def astructs_astruct_baddr_test():
Expand Down
20 changes: 18 additions & 2 deletions test/unit/libtypes_list.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from amitools.vamos.machine.mock import MockMemory
from amitools.vamos.mem import MemoryAlloc
from amitools.vamos.libtypes import List, MinList, Node, MinNode
from amitools.vamos.libtypes import List, MinList, Node, MinNode, Task, Process
from amitools.vamos.libstructs import ListStruct, MinListStruct, NodeType


Expand Down Expand Up @@ -167,8 +167,9 @@ def libtypes_list_iter_at_test():
assert [a for a in l.iter_at(n2)] == [n2]


def add_node(alist, addr, name):
def add_node(alist, addr, name, type=NodeType.NT_UNKNOWN):
n = Node(alist.mem, addr)
n.type.set(type)
addr += n.get_size()
name_addr = addr
alist.mem.w_cstr(addr, name)
Expand Down Expand Up @@ -198,6 +199,21 @@ def libtypes_list_find_name_test():
n = l.find_name("hello")
assert n == n1
assert n.find_name("hello") == n3
# get path
assert l.get_path("") is l
assert l.get_path("[world]") == n2
assert l.get_path("[world].type") == n2.get("type")


def libtypes_list_find_name_promote_test():
l = new_list()
addr = 0x60
n1, addr = add_node(l, addr, "hello", type=NodeType.NT_TASK)
n2, addr = add_node(l, addr, "world", type=NodeType.NT_PROCESS)
task = l.find_name("hello")
assert type(task) is Task
proc = l.find_name("world")
assert type(proc) is Process


def libtypes_list_alloc_test():
Expand Down
Loading

0 comments on commit d17e4a9

Please sign in to comment.