Fix pcb stackup handling

This commit is contained in:
jaseg 2023-06-21 13:37:38 +02:00
parent dd8507d202
commit 467e482bf4
2 changed files with 119 additions and 4 deletions

View file

@ -33,12 +33,12 @@ class PageSettings:
page_format: str = 'A4'
width: float = None
height: float = None
portrait: bool = False
portrait: Flag() = False
@sexp_type('layers')
class LayerSettings:
index: int = None
index: int = 0
canonical_name: str = None
layer_type: AtomChoice(Atom.jumper, Atom.mixed, Atom.power, Atom.signal, Atom.user) = Atom.signal
custom_name: str = None
@ -206,7 +206,7 @@ class Board:
generator: Named(Atom) = Atom.gerbonara
general: GeneralSection = field(default_factory=GeneralSection)
page: PageSettings = field(default_factory=PageSettings)
layers: Named(Array(LayerSettings)) = field(default_factory=list)
layers: Named(Array(Untagged(LayerSettings))) = field(default_factory=list)
setup: BoardSetup = field(default_factory=BoardSetup)
properties: List(Property) = field(default_factory=list)
nets: List(Net) = field(default_factory=list)
@ -245,7 +245,10 @@ class Board:
def write(self, filename=None):
with open(filename or self.original_filename, 'w') as f:
f.write(build_sexp(sexp(self)))
f.write(self.serialize())
def serialize(self):
return build_sexp(sexp(type(self), self)[0])
@classmethod
def open(kls, pcb_file, *args, **kwargs):

View file

@ -191,6 +191,118 @@ class Array(WrapperType):
yield from sexp(self.next_type, e)
class Untagged(WrapperType):
def __map__(self, value, parent=None):
value, = value
return self.next_type.__map__([self.next_type.name_atom, *value], parent=parent)
def __sexp__(self, value):
for inner in sexp(self.next_type, value):
_tag, *rest = inner
yield rest
class List(WrapperType):
def __bind_field__(self, field):
self.attr = field.name
def __map__(self, value, parent):
l = getattr(parent, self.attr, [])
mapped = map_sexp(self.next_type, value, parent=parent)
l.append(mapped)
setattr(parent, self.attr, l)
def __sexp__(self, value):
for elem in value:
yield from sexp(self.next_type, elem)
class _SexpTemplate:
@staticmethod
def __atoms__(kls):
return [kls.name_atom]
@staticmethod
def __map__(kls, value, *args, parent=None, **kwargs):
positional = iter(kls.positional)
inst = kls(*args, **kwargs)
for v in value[1:]: # skip key
if isinstance(v, Atom) and v in kls.keys:
name, etype = kls.keys[v]
mapped = map_sexp(etype, [v], parent=inst)
if mapped is not None:
setattr(inst, name, mapped)
elif isinstance(v, list):
name, etype = kls.keys[v[0]]
mapped = map_sexp(etype, v, parent=inst)
if mapped is not None:
setattr(inst, name, mapped)
else:
try:
pos_key = next(positional)
setattr(inst, pos_key.name, v)
except StopIteration:
raise TypeError(f'Unhandled positional argument {v!r} while parsing {kls}')
getattr(inst, '__after_parse__', lambda x: None)(parent)
return inst
@staticmethod
def __sexp__(kls, value):
getattr(value, '__before_sexp__', lambda: None)()
out = [kls.name_atom]
for f in fields(kls):
if f.type is SEXP_END:
break
out += sexp(f.type, getattr(value, f.name))
yield out
@staticmethod
def parse(kls, data, *args, **kwargs):
return kls.__map__(parse_sexp(data), *args, **kwargs)
@staticmethod
def sexp(self):
return next(self.__sexp__(self))
def sexp_type(name=None):
def register(cls):
cls = dataclass(cls)
cls.name_atom = Atom(name) if name is not None else None
for key in '__sexp__', '__map__', '__atoms__', 'parse':
if not hasattr(cls, key):
setattr(cls, key, classmethod(getattr(_SexpTemplate, key)))
if not hasattr(cls, 'sexp'):
setattr(cls, 'sexp', getattr(_SexpTemplate, 'sexp'))
cls.positional = []
cls.keys = {}
for f in fields(cls):
f_type = f.type
if f_type is SEXP_END:
break
if hasattr(f_type, '__bind_field__'):
f_type.__bind_field__(f)
atoms = getattr(f_type, '__atoms__', lambda: [])
atoms = list(atoms())
for atom in atoms:
cls.keys[atom] = (f.name, f_type)
if not atoms:
cls.positional.append(f)
return cls
return register
class List(WrapperType):
def __bind_field__(self, field):
self.attr = field.name