2023-11-23 13:21:43 -07:00
|
|
|
import random
|
2023-11-22 13:50:56 -07:00
|
|
|
from xml.etree import ElementTree as ET
|
|
|
|
|
|
|
|
from constants import GAZ_VAR_TAG, GAZ_ARG_TAG
|
|
|
|
|
|
|
|
|
|
|
|
class Variable:
|
|
|
|
def __init__(self, name: str, type: str, qualifier: str, value: any = None):
|
|
|
|
self.name = name
|
|
|
|
self.type = type
|
|
|
|
self.value = value
|
|
|
|
self.qualifier = qualifier
|
|
|
|
self.xml = self._build_xml()
|
|
|
|
|
|
|
|
def _build_xml(self):
|
|
|
|
args = [
|
|
|
|
('name', self.name),
|
|
|
|
('type', self.type),
|
|
|
|
('mut', self.qualifier),
|
|
|
|
]
|
|
|
|
return build_xml_element(args, name=GAZ_VAR_TAG)
|
|
|
|
|
|
|
|
|
|
|
|
class Argument:
|
|
|
|
def __init__(self, name: str, type: str):
|
|
|
|
self.name = name
|
|
|
|
self.type = type
|
|
|
|
self.xml = self._build_xml()
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.type + " " + self.name
|
|
|
|
|
|
|
|
def _build_xml(self):
|
|
|
|
args = [
|
|
|
|
('name', self.name),
|
|
|
|
('type', self.type),
|
|
|
|
]
|
|
|
|
return build_xml_element(args, name=GAZ_ARG_TAG)
|
|
|
|
|
|
|
|
|
|
|
|
class Routine:
|
|
|
|
def __init__(self, name: str, type: str, return_type: str, args: list[Argument], xml: ET.Element = None):
|
|
|
|
self.name = name
|
|
|
|
self.type = type
|
|
|
|
self.return_type = return_type
|
|
|
|
self.arguments = args
|
|
|
|
self.xml = xml
|
|
|
|
self.xml = xml
|
|
|
|
|
|
|
|
|
|
|
|
class Scope:
|
|
|
|
def __init__(self, enclosing_scope, child_scope=None, associated_xml: ET.Element = None):
|
|
|
|
self.symbols = {}
|
|
|
|
self.enclosing_scope = enclosing_scope
|
|
|
|
self.child_scope = child_scope
|
|
|
|
self.xml = associated_xml
|
|
|
|
|
|
|
|
def resolve(self, name) -> ET.Element or None:
|
|
|
|
if name in self.symbols:
|
|
|
|
return self.symbols[name]
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def append(self, name, item: Variable or Argument or Routine):
|
|
|
|
self.symbols[name] = item
|
|
|
|
|
|
|
|
def append_element(self, name, value: ET.Element):
|
|
|
|
self.symbols[name] = value
|
|
|
|
|
|
|
|
def set(self, name, value: ET.Element):
|
|
|
|
self.symbols[name] = value
|
|
|
|
|
|
|
|
def get_all_defined_mutable_vars(self) -> list[Variable]:
|
|
|
|
if self.enclosing_scope is None:
|
|
|
|
return self._get_mutable_vars()
|
|
|
|
else:
|
|
|
|
return self.enclosing_scope.get_all_defined_mutable_vars() + self._get_mutable_vars()
|
|
|
|
|
|
|
|
def _get_mutable_vars(self) -> list[Variable]:
|
|
|
|
mutable_vars = []
|
|
|
|
|
|
|
|
for name, var in self.symbols.items():
|
|
|
|
if not isinstance(var, Variable):
|
|
|
|
continue
|
|
|
|
if var.qualifier != 'const':
|
|
|
|
mutable_vars.append(self.symbols[name])
|
|
|
|
return mutable_vars
|
|
|
|
|
|
|
|
def get_top_scope(self):
|
|
|
|
if self.enclosing_scope is None:
|
|
|
|
return self
|
|
|
|
else:
|
|
|
|
return self.enclosing_scope.get_top_scope()
|
|
|
|
|
|
|
|
|
|
|
|
def build_xml_element(*keys, name):
|
|
|
|
elem = ET.Element(name)
|
|
|
|
for key in list(keys)[0]: # TODO refactor
|
|
|
|
elem.set(key[0], key[1])
|
|
|
|
return elem
|
2023-11-23 12:51:13 -07:00
|
|
|
|
|
|
|
|
|
|
|
def get_numberlines(settings_section: str, subsettings: list[str], excluded_values, settings):
|
|
|
|
assert len(subsettings) == len(excluded_values)
|
|
|
|
|
|
|
|
number_line = 0
|
|
|
|
cutoffs = []
|
|
|
|
cutoff = 0
|
|
|
|
options = {}
|
|
|
|
option = 0
|
|
|
|
|
|
|
|
valid_settings = []
|
|
|
|
|
|
|
|
for key, value in settings[settings_section].items():
|
|
|
|
if key in subsettings and key not in excluded_values: # this check needs to be done recursively
|
|
|
|
if isinstance(value, int):
|
|
|
|
t = {
|
|
|
|
key: value
|
|
|
|
}
|
|
|
|
valid_settings.append(t)
|
|
|
|
elif isinstance(value, dict):
|
|
|
|
valid_settings.append(value)
|
|
|
|
else:
|
|
|
|
raise TypeError("invalid setting type. Found " + str(value) + " instead of expected int or dict")
|
|
|
|
|
|
|
|
for v in range(len(valid_settings)):
|
|
|
|
for i in excluded_values:
|
|
|
|
for j in i:
|
|
|
|
if j in valid_settings[v]:
|
|
|
|
valid_settings[v].pop(j)
|
|
|
|
|
|
|
|
for v in valid_settings:
|
|
|
|
if isinstance(v, dict):
|
|
|
|
for key, value in v.items():
|
|
|
|
number_line += value
|
|
|
|
cutoffs.append(cutoff + value)
|
|
|
|
cutoff += value
|
|
|
|
options[option] = key
|
|
|
|
option += 1
|
|
|
|
elif isinstance(v, int):
|
|
|
|
number_line += v
|
|
|
|
cutoffs.append(cutoff + v)
|
|
|
|
cutoff += v
|
|
|
|
options[option] = v
|
|
|
|
option += 1
|
|
|
|
else:
|
|
|
|
raise TypeError("invalid setting type. Found " + str(v) + " instead of expected int")
|
|
|
|
|
2023-11-23 13:21:43 -07:00
|
|
|
return options, cutoffs, number_line
|
|
|
|
|
|
|
|
|
|
|
|
def filter_options(exclude, include, options, opts):
|
|
|
|
if include is not None and exclude is not None:
|
|
|
|
raise ValueError("Cannot specify both include and exclude")
|
|
|
|
elif include is not None and include in opts:
|
|
|
|
for i in range(len(opts)):
|
|
|
|
if opts[i] in include:
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
options.pop(opts.index(opts[i]))
|
|
|
|
elif exclude is not None and exclude in opts:
|
|
|
|
options.pop(opts.index(exclude))
|
|
|
|
elif include is None and exclude is None:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
raise ValueError("Invalid include/exclude options " + str(include) + " " + str(exclude))
|
|
|
|
|
|
|
|
|
|
|
|
def _choose_option(cutoffs, number_line, options):
|
|
|
|
op = ""
|
|
|
|
a = random.randint(0, number_line - 1)
|
|
|
|
i = 0
|
|
|
|
for i in range(len(cutoffs) - 1):
|
|
|
|
if i == 0:
|
|
|
|
if a < cutoffs[i]:
|
|
|
|
op = options[i]
|
|
|
|
break
|
|
|
|
if cutoffs[i] <= a < cutoffs[i + 1]:
|
|
|
|
op = options[i]
|
|
|
|
break
|
|
|
|
return op
|