168 lines
3.6 KiB
Python
168 lines
3.6 KiB
Python
import dataclasses
|
|
from dataclasses import dataclass
|
|
import json
|
|
|
|
|
|
"""
|
|
Types that must be supported:
|
|
* int
|
|
* float
|
|
* string
|
|
* bool
|
|
* list
|
|
"""
|
|
|
|
|
|
@dataclass
|
|
class Element:
|
|
pass
|
|
|
|
|
|
@dataclass
|
|
class Variable(Element):
|
|
text: str
|
|
value: str
|
|
description: str
|
|
|
|
|
|
@dataclass
|
|
class IntVariable(Variable):
|
|
value: int
|
|
|
|
|
|
@dataclass
|
|
class FloatVariable(Variable):
|
|
value: float
|
|
|
|
|
|
@dataclass
|
|
class StringVariable(Variable):
|
|
value: str
|
|
|
|
|
|
@dataclass
|
|
class BoolVariable(Variable):
|
|
value: bool
|
|
|
|
|
|
@dataclass
|
|
class Section(Element):
|
|
text: str
|
|
elements: list[Element]
|
|
|
|
|
|
@dataclass
|
|
class CustomizerData:
|
|
elements: list[Element]
|
|
|
|
@staticmethod
|
|
def flatten(data):
|
|
"""
|
|
Return a list of parameters
|
|
"""
|
|
elems = {}
|
|
for elem in data.elements:
|
|
if isinstance(elem, Section):
|
|
for param in elem.elements:
|
|
elems[param.text] = param.value
|
|
else:
|
|
elems[elem.text] = elem.value
|
|
return elems
|
|
|
|
|
|
class EnhancedJSONEncoder(json.JSONEncoder):
|
|
def default(self, o):
|
|
if dataclasses.is_dataclass(o):
|
|
return dataclasses.asdict(o)
|
|
return super().default(o)
|
|
|
|
|
|
class CustomizerProfileEncoder(json.JSONEncoder):
|
|
def default(self, o):
|
|
if isinstance(o, CustomizerData):
|
|
return CustomizerData.flatten(o)
|
|
return super().default(o)
|
|
|
|
|
|
def parse_type(value):
|
|
# Parse type
|
|
if ((value[0] == "\"" or value[0] == "'")
|
|
and (value[-1] == "\"" or value[-1] == "'")):
|
|
value = value.strip("\"").strip("'")
|
|
|
|
elif value == "true" or value == "false":
|
|
value = bool(value)
|
|
|
|
elif value[0] == "[" and value[-1] == "]":
|
|
value = value[1:-2].split(",")
|
|
for index in range(len(value)):
|
|
value[index] = parse_type(value[index])
|
|
|
|
elif len(value.split(".")):
|
|
value = float(value)
|
|
|
|
else:
|
|
value = int(value)
|
|
|
|
return value
|
|
|
|
|
|
def parse(file):
|
|
with open(file) as scad_file:
|
|
section = None
|
|
all_elems = []
|
|
elems = []
|
|
description = None
|
|
for line in scad_file.readlines():
|
|
line = line.strip()
|
|
|
|
# Checking for section title
|
|
if line[0:2] == "/*":
|
|
(middle, end) = line[2:].strip().split("*/")
|
|
middle = middle.strip()
|
|
|
|
if section is None:
|
|
all_elems.extend(elems)
|
|
else:
|
|
all_elems.append(Section(section, elems))
|
|
|
|
section = middle
|
|
elems = []
|
|
|
|
# Checking for comment
|
|
elif line[0:2] == "//":
|
|
description = line[2:].strip()
|
|
|
|
# Checking for text
|
|
elif len(line.strip()) > 0 and len(line.split("=")) == 2:
|
|
(name, value) = line.split("=")
|
|
name = name.strip()
|
|
value = value.split(";")[0].strip()
|
|
|
|
try:
|
|
value = parse_type(value)
|
|
except ValueError as e:
|
|
print(f"Error parsing a value: {e}")
|
|
print("Stopping parsing")
|
|
break
|
|
|
|
elems.append(
|
|
Variable(
|
|
name,
|
|
value,
|
|
"" if description is None else description
|
|
)
|
|
)
|
|
description = None
|
|
|
|
elif len(line) == 0:
|
|
pass
|
|
|
|
else:
|
|
break
|
|
|
|
all_elems.append(Section(section, elems))
|
|
|
|
data = CustomizerData(all_elems)
|
|
return data
|