diff options
-rw-r--r-- | src/ee/kicad/__init__.py | 2 | ||||
-rw-r--r-- | src/ee/kicad/pcb/__init__.py | 128 | ||||
-rw-r--r-- | src/ee/kicad/sexpr/__init__.py (renamed from src/ee/kicad/_parse_kicad_pcb.py) | 51 | ||||
-rw-r--r-- | test/kicad_pcb/parser-1.kicad_pcb | 2 | ||||
-rw-r--r-- | test/test_parse_pcb.py | 15 | ||||
-rw-r--r-- | test/test_parse_sexpr.py (renamed from test/test_parse_kicad_pcb.py) | 4 |
6 files changed, 160 insertions, 42 deletions
diff --git a/src/ee/kicad/__init__.py b/src/ee/kicad/__init__.py index efc20a2..8d5acd1 100644 --- a/src/ee/kicad/__init__.py +++ b/src/ee/kicad/__init__.py @@ -4,12 +4,10 @@ from ee import EeException from ee.kicad.read_schematic import read_schematic, read_schematics from ee.kicad.to_bom import to_bom, to_bom_xml from .model import * -from ._parse_kicad_pcb import parse_kicad_pcb __all__ = [ "Component", "ComponentField", - "parse_kicad_pcb", "Position", "read_schematic", "read_schematics", diff --git a/src/ee/kicad/pcb/__init__.py b/src/ee/kicad/pcb/__init__.py new file mode 100644 index 0000000..bfd352f --- /dev/null +++ b/src/ee/kicad/pcb/__init__.py @@ -0,0 +1,128 @@ +from .. import sexpr + +def auto_str(cls): + def __str__(self): + return str({k: [str(x) for x in v] if isinstance(v, list) else str(v) for k, v in vars(self).items()}) + + cls.__str__ = __str__ + return cls + +@auto_str +class KicadPcb(object): + def __init__(self, **kwargs): + for k, v in kwargs.items(): + setattr(self, k, v) + +@auto_str +class General(object): + def __init__(self, **kwargs): + for k, v in kwargs.items(): + setattr(self, k, v) + +@auto_str +class Module(object): + def __init__(self, **kwargs): + for k, v in kwargs.items(): + setattr(self, k, v) + +def parse(path): + count = 0 + p = sexpr.parse(path) + p = sexpr.logging_parser(p) + (event, token) = next(p) + assert event == sexpr.EVENT_LPAREN + + (event, token) = next(p) + assert event == sexpr.EVENT_TEXT and token == "kicad_pcb" + + idx = 0 + def _consume(): + nonlocal idx + idx = idx + 1 +# print("consume: idx={}".format(idx)) + (event, token) = next(p) +# print("consume: event={}".format(event)) + while event != sexpr.EVENT_RPAREN: + if event == sexpr.EVENT_LPAREN: + _consume() + elif event == sexpr.EVENT_TEXT: + pass + (event, token) = next(p) +# print("consume: event={}".format(event)) +# print("consume: done".format()) + idx = idx - 1 + + def _parse_kicad_pcb(): + modules = [] + args = {"modules": modules} + + (event, token) = next(p) + while event == sexpr.EVENT_LPAREN: + (event, token) = next(p) + if token == "version": + args[token] = _parse_text(rparen = True) + elif token == "general": + args[token] = _parse_general() + elif token == "module": + modules.append(_parse_module()) + else: + _consume() + (event, token) = next(p) + + return KicadPcb(**args) + + def _parse_text(optional = False, rparen = False): + (event, token) = next(p) + if not optional: + assert event == sexpr.EVENT_TEXT + else: + assert event == sexpr.EVENT_TEXT or event == sexpr.EVENT_RPAREN + if event == sexpr.EVENT_RPAREN: + return None + text = token + if rparen: + (event, token) = next(p) + assert event == sexpr.EVENT_RPAREN + return text + + def _parse_general(): + args = {} + + (event, token) = next(p) + while event == sexpr.EVENT_LPAREN: + (event, token) = next(p) + if token == "no_connects": + args[token] =_parse_text(rparen = True) + elif token == "area": + args[token] = (_parse_text(), _parse_text(), _parse_text(), _parse_text(rparen = True)) + elif token == "thickness": + args[token] = _parse_text(rparen = True) + else: + _consume() + (event, token) = next(p) + return General(**args) + + def _parse_module(): + args = {} + + args["footprint"] = _parse_text() + + (event, token) = next(p) + while event == sexpr.EVENT_LPAREN: + (event, token) = next(p) + if token == "layer": + args[token] = _parse_text(rparen = True) + elif token == "at": + x = _parse_text() + y = _parse_text() + rot = _parse_text(optional = True, rparen = True) + args[token] = (x, y, rot or 0) + else: + _consume() + (event, token) = next(p) + return Module(**args) + + kicad_pcb = _parse_kicad_pcb() +# (event, token) = next(p) +# assert event == sexpr.EVENT_END + return kicad_pcb diff --git a/src/ee/kicad/_parse_kicad_pcb.py b/src/ee/kicad/sexpr/__init__.py index 5ea4d1b..a8604dc 100644 --- a/src/ee/kicad/_parse_kicad_pcb.py +++ b/src/ee/kicad/sexpr/__init__.py @@ -17,7 +17,15 @@ def state_to_str(s): return "EVENT_TEXT" return "UNKNOWN STATE" -def parse_kicad_pcb(path): +def logging_parser(parser): + for (event, token) in parser: + if token: + print("SEXPR: event={}, token={}".format(state_to_str(event), token or "")) + else: + print("SEXPR: event={}".format(state_to_str(event))) + yield (event, token) + +def parse(path): class state(object): def __init__(self): self.f = open(path, "r")#, 128 * 1024) @@ -37,32 +45,17 @@ def parse_kicad_pcb(path): # TODO: count lines and characters if self.buffer: c = self.buffer[0] - while c == '\n': - del self.buffer[0] - c = self.buffer[0] - return c - - c = self.f.read(1024) - if not c: + del self.buffer[0] return c - self.buffer.extend(c) - return self._read_c() - -# if self.buffer: -# c = self.buffer[0] -# del self.buffer[0] -# return c -# -# c = self.f.read(1) -# while c and c == '\n': -# c = self.f.read(1) -# return c + c = self.f.read(1) + while c and c == '\n': + c = self.f.read(1) + return c def _unread(self, s): for c in s: self.buffer.append(c) -# print("unreading: '{}', buffer={}".format(s, str(self.buffer))) def _read_token(self): s = "" @@ -101,13 +94,11 @@ def parse_kicad_pcb(path): def next(self): s = self.state -# print("next: current state={}, buffer={}".format(self.state_to_str(s), self.buffer)) self._text = None if s == EVENT_END: raise Exception("Invalid state, state=END") token = self._read_token() -# print("token={}".format(token)) if token is None: self.state = EVENT_END @@ -130,17 +121,3 @@ def parse_kicad_pcb(path): while event != EVENT_END: yield (event, token) (event, token) = s.next() - -#indent = 0 -#for (event_type, text) in parse_kicad_pcb("alpha.kicad_pcb"): -# if event_type == EVENT_LPAREN: -# prefix = " " * indent -# indent = indent + 1 -# print(prefix + "(") -# elif event_type == EVENT_RPAREN: -# indent = indent - 1 -# prefix = " " * indent -# print(prefix + ")") -# elif event_type == EVENT_TEXT: -# prefix = " " * indent -# print("{}{}".format(prefix, text)) diff --git a/test/kicad_pcb/parser-1.kicad_pcb b/test/kicad_pcb/parser-1.kicad_pcb index b8efabc..9aa6ab4 100644 --- a/test/kicad_pcb/parser-1.kicad_pcb +++ b/test/kicad_pcb/parser-1.kicad_pcb @@ -2,7 +2,7 @@ (general (links 5) - (no_connects 0) + (no_connects 1) (area 139.649999 101.549999 152.450001 109.270001) (thickness 1.6) (drawings 5) diff --git a/test/test_parse_pcb.py b/test/test_parse_pcb.py new file mode 100644 index 0000000..9592b92 --- /dev/null +++ b/test/test_parse_pcb.py @@ -0,0 +1,15 @@ +import pytest +import os.path +import ee.kicad.pcb + +basedir = os.path.dirname(os.path.abspath(__file__)) + +def test_parsing(): + path = os.path.join(basedir, "kicad_pcb/parser-1.kicad_pcb") + count = 0 + kicad_pcb = ee.kicad.pcb.parse(path) + modules = kicad_pcb.modules + del kicad_pcb.modules + print(str(kicad_pcb)) + for m in modules: + print(m) diff --git a/test/test_parse_kicad_pcb.py b/test/test_parse_sexpr.py index 25c1957..4a97507 100644 --- a/test/test_parse_kicad_pcb.py +++ b/test/test_parse_sexpr.py @@ -1,12 +1,12 @@ import pytest import os.path -from ee.kicad import parse_kicad_pcb +import ee.kicad.sexpr as sexpr basedir = os.path.dirname(os.path.abspath(__file__)) def test_parsing(): path = os.path.join(basedir, "kicad_pcb/parser-1.kicad_pcb") count = 0 - for (event, token) in parse_kicad_pcb(path): + for (event, token) in sexpr.parse(path): count = count + 1 assert count == 3657 |