Refactor and bugfix for integer division

Took 54 minutes
This commit is contained in:
ayrton 2023-11-21 21:39:04 -07:00
parent 561a9a5efa
commit fb36aef06e
6 changed files with 67 additions and 51 deletions

View file

@ -55,10 +55,30 @@ class AstGenerator:
self.int_op_options, self.int_op_cutoffs, self.int_op_numline = ( self.int_op_options, self.int_op_cutoffs, self.int_op_numline = (
self.get_numberlines('expression-weights', self.get_numberlines('expression-weights',
['brackets', 'arithmetic', 'unary'], ['brackets', 'arithmetic', 'unary'],
[[], [], ['negation']])) [[], [], ['not']]))
self.int_unary = ['negation', 'noop'] self.int_unary = ['negation', 'noop']
pass self.bool_op_options, self.bool_op_cutoffs, self.bool_op_numline = (
self.get_numberlines('expression-weights',
['comparison', 'logical', 'brackets', 'unary'],
[['less-than-or-equal', 'greater-than-or-equal', 'less-than', 'greater-than'], [], [], ['noop', 'negation']]))
self.bool_unary = ['not']
self.float_op_options, self.float_op_cutoffs, self.float_op_numline = (
self.get_numberlines('expression-weights',
['brackets', 'arithmetic', 'unary'],
[[], [], ['not']]))
self.float_unary = ['negation', 'noop']
self.char_op_options, self.char_op_cutoffs, self.char_op_numline = (
self.get_numberlines('expression-weights',
['brackets', 'comparison'],
[[], ['less-than', 'greater-than', 'less-than-or-equal', 'greater-than-or-equal']]))
self.comp_op_options, self.comp_op_cutoffs, self.comp_op_numline = (
self.get_numberlines('expression-weights',
['brackets', 'comparison'],
[[], []]))
def get_numberlines(self, settings_section: str, subsettings: list[str], excluded_values: list[list[str or None]]): def get_numberlines(self, settings_section: str, subsettings: list[str], excluded_values: list[list[str or None]]):
assert len(subsettings) == len(excluded_values) assert len(subsettings) == len(excluded_values)
@ -242,49 +262,42 @@ class AstGenerator:
break break
break break
def generate_int_real_expr(self): def generate_int_expr(self):
# Number line self._generate_expression([GAZ_INT_KEY],
number_line = 100 self.int_op_numline,
cutoffs = [10, 30, 50, 80, 100] self.int_op_cutoffs,
options = { #TODO add brackets self.int_op_options,
0: "addition", self.int_unary)
1: "subtraction",
2: "multiplication",
3: "division",
4: "modulo",
5: "power",
6: "negation",
7: "noop",
8: "equality",
9: "inequality",
10: "less-than",
11: "greater-than",
12: "less-than-or-equal",
13: "greater-than-or-equal",
}
unary = ["negation", "noop"] def generate_float_expr(self):
self._generate_expression([GAZ_FLOAT_KEY, GAZ_INT_KEY],
self._generate_expression([GAZ_INT_KEY, GAZ_FLOAT_KEY], self.int_op_numline, self.int_op_cutoffs, self.float_op_numline,
self.int_op_options, self.int_unary) self.float_op_cutoffs,
self.float_op_options,
self.float_unary)
def generate_bool_expr(self): def generate_bool_expr(self):
# Number line self._generate_expression([GAZ_BOOL_KEY],
number_line = 100 self.bool_op_numline,
cutoffs = [10, 30, 50, 80, 100] self.bool_op_cutoffs,
options = { #TODO add brackets # TODO cannot guarantee correctness of comparison since booleans may appear self.bool_op_options,
0: "equality", self.bool_unary)
1: "and",
2: "or",
3: "xor",
4: "not",
}
unary = ["not"] def generate_char_expr(self):
self._generate_expression([GAZ_CHAR_KEY],
self.char_op_numline,
self.char_op_cutoffs,
self.char_op_options)
self._generate_expression([GAZ_BOOL_KEY], number_line, cutoffs, options, unary) def generate_comp_expr(self):
self._generate_expression([GAZ_BOOL_KEY],
self.comp_op_numline,
self.comp_op_cutoffs,
self.comp_op_options,
comparison=True)
def _generate_expression(self, expr_type: list[str], number_line, cutoffs, options, unary=None): def _generate_expression(self, expr_type: list[str], number_line,
cutoffs, options, unary=None, comparison: bool = False):
if unary is None: if unary is None:
unary = [] unary = []
@ -293,7 +306,7 @@ class AstGenerator:
if self.current_nesting_depth > self.settings['generation-options']['max-nesting-depth'] or random.random() < \ if self.current_nesting_depth > self.settings['generation-options']['max-nesting-depth'] or random.random() < \
self.settings['block-termination-probability']: self.settings['block-termination-probability']:
self.generate_literal(random.choice(expr_type)) # TODO add the reals self.generate_literal(random.choice(expr_type))
self.current_nesting_depth -= 1 self.current_nesting_depth -= 1
return return
@ -511,11 +524,11 @@ class AstGenerator:
def generate_expression(self, expr_type: str): def generate_expression(self, expr_type: str):
if expr_type == GAZ_INT_KEY or expr_type == GAZ_FLOAT_KEY: if expr_type == GAZ_INT_KEY or expr_type == GAZ_FLOAT_KEY:
self.generate_int_real_expr() self.generate_int_expr()
elif expr_type == GAZ_BOOL_KEY: elif expr_type == GAZ_BOOL_KEY:
self.generate_bool_expr() self.generate_bool_expr()
elif expr_type == ANY_TYPE: # TODO implement the choice of any type elif expr_type == ANY_TYPE: # TODO implement the choice of any type
self.generate_int_real_expr() self.generate_int_expr()
else: else:
raise NotImplementedError(f"Expression type {expr_type} not implemented") raise NotImplementedError(f"Expression type {expr_type} not implemented")

View file

@ -228,7 +228,7 @@ class TestGeneration(unittest.TestCase):
# print("iteration: " + str(l)) # print("iteration: " + str(l))
self.ast_gen.ast = ET.Element("block") self.ast_gen.ast = ET.Element("block")
self.ast_gen.current_ast_element = self.ast_gen.ast self.ast_gen.current_ast_element = self.ast_gen.ast
self.ast_gen.generate_int_real_expr() self.ast_gen.generate_int_expr()
# self.write_ast() # self.write_ast()
if self.ast_gen.ast.find("operator") is None: if self.ast_gen.ast.find("operator") is None:

View file

@ -82,7 +82,7 @@ class GazUnparser(GeneralUnparser):
else: else:
return str(val) return str(val)
def translate_op(self, param): def translate_op(self, param, ty=None):
return to_gaz_op(param) return to_gaz_op(param)
def translate_type(self, ty): def translate_type(self, ty):

View file

@ -171,8 +171,9 @@ class GeneralUnparser:
self.unparse_node(child) self.unparse_node(child)
def unparse_operator(self, node): def unparse_operator(self, node):
ty = node.get(GAZ_TY_KEY)
self.unparse_xhs(node.find(GAZ_LHS_TAG)) self.unparse_xhs(node.find(GAZ_LHS_TAG))
self.source += " {} ".format(self.translate_op(node.get("op"))) self.source += " {} ".format(self.translate_op(node.get("op"), ty))
self.unparse_xhs(node.find(GAZ_RHS_TAG)) self.unparse_xhs(node.find(GAZ_RHS_TAG))
def unparse_return(self, node): def unparse_return(self, node):
@ -304,7 +305,7 @@ class GeneralUnparser:
def translate_value(self, val): def translate_value(self, val):
raise NotImplementedError raise NotImplementedError
def translate_op(self, param): def translate_op(self, param, ty=None):
raise NotImplementedError raise NotImplementedError
def translate_type(self, ty): def translate_type(self, ty):

View file

@ -21,15 +21,17 @@ def to_python_type(ty):
raise Exception("Unknown type: " + ty) raise Exception("Unknown type: " + ty)
def to_python_op(param): def to_python_op(param, ty):
if param == "negation" or param == "subtraction": if param == "negation" or param == "subtraction":
return "-" return "-"
elif param == "addition" or param == "noop": elif param == "addition" or param == "noop":
return "+" return "+"
elif param == "multiplication": elif param == "multiplication":
return "*" return "*"
elif param == "division": elif param == "division" and ty != GAZ_INT_KEY:
return "/" return "/"
elif param == "division" and ty == GAZ_INT_KEY:
return "//"
elif param == "modulo": elif param == "modulo":
return "%" return "%"
elif param == "power": elif param == "power":
@ -79,8 +81,8 @@ class PythonUnparser(GeneralUnparser):
def translate_value(self, val): def translate_value(self, val):
return str(val) return str(val)
def translate_op(self, param): def translate_op(self, param, ty=None):
return to_python_op(param) return to_python_op(param, ty)
def translate_type(self, ty): def translate_type(self, ty):
return to_python_type(ty) return to_python_type(ty)

View file

@ -17,7 +17,7 @@ properties:
number-of-arguments: # number of arguments to a routine number-of-arguments: # number of arguments to a routine
min: 1 min: 1
max: 10 max: 10
generate-max-int: True # if False, generate integers between [-1000, 1000] else generate-max-int: False # if False, generate integers between [-1000, 1000] else
expression-weights: # weights for expressions expression-weights: # weights for expressions
# the higher a weight, the more likely (0, 10000), 0 to exclude, 10000 for only that # the higher a weight, the more likely (0, 10000), 0 to exclude, 10000 for only that
brackets: 10 brackets: 10