diff --git a/ast_generator/ast_generator.py b/ast_generator/ast_generator.py index 31c4480..0fc6cb5 100644 --- a/ast_generator/ast_generator.py +++ b/ast_generator/ast_generator.py @@ -73,6 +73,15 @@ class AstGenerator: self.comp_op_options, self.comp_op_cutoffs, self.comp_op_numline = ( get_numberlines('expression-weights', ['brackets', 'comparison'], [[], []], self.settings)) + self.type_options, self.type_cutoffs, self.type_numline = ( + get_numberlines('type-weights', ['composite', 'atomic'], [[], []], self.settings)) + + self.atomic_type_options, self.atomic_type_cutoffs, self.atomic_type_numline = ( + get_numberlines('type-weights', ['atomic-types'], [[]], self.settings)) + + self.composite_type_options, self.composite_type_cutoffs, self.composite_type_numline = ( + get_numberlines('type-weights', ['composite-types'], [[]], self.settings)) + def _init_names(self): names = get_english_words_set(['web2'], alpha=True) possible_names = filter(lambda x: self.settings['properties']['id-length']['max'] <= len(x) <= @@ -575,6 +584,8 @@ class AstGenerator: self.generate_comp_expr() elif expr_type == GAZ_CHAR_KEY: self.generate_char_expr() + elif expr_type == GAZ_FLOAT_KEY: + self.generate_float_expr() elif expr_type == ANY_TYPE: # TODO implement the choice of any type ty = self.get_type(GAZ_RHS_TAG) self.generate_expression(ty) @@ -703,32 +714,53 @@ class AstGenerator: name = ''.join(random.choices(string.ascii_letters, k=length)) return name else: - if name_type == GAZ_VAR_TAG: - choice = random.choice(self.variable_names) - self.variable_names.remove(choice) + try: + if name_type == GAZ_VAR_TAG: + choice = random.choice(self.variable_names) + self.variable_names.remove(choice) + return choice + else: + choice = random.choice(self.routine_names) + self.routine_names.remove(choice) + return choice + except IndexError: # if we run out of variable names + length = random.randint(self.settings['properties']['id-length']['min'], + self.settings['properties']['id-length']['max']) + name = ''.join(random.choices(string.ascii_letters, k=length)) + return name + + def get_type(self, tag) -> str: # TODO Add support for composite types + """ + @brief get a random type from the list of possible types + + @param tag: + @return: a type as a string + """ + comp_atom = self.get_choice(self.type_options, self.type_numline, self.type_cutoffs) + choice = "" + if comp_atom == GAZ_ATOMIC_TYPE_KEY: + choice = self.get_choice(self.atomic_type_options, self.atomic_type_numline, self.atomic_type_cutoffs) + elif comp_atom == GAZ_COMPOSITE_TYPE_KEY: + choice = self.get_choice(self.composite_type_options, self.composite_type_numline, self.composite_type_cutoffs) + else: + raise NotImplementedError(f"Unimplemented generator for type: {comp_atom}") + + if tag not in [GAZ_PROCEDURE_TAG]: + if choice != GAZ_VOID_TYPE: return choice else: - choice = random.choice(self.routine_names) - self.routine_names.remove(choice) - return choice + return self.get_type(tag) + else: + return choice - def get_type(self, tag): # TODO Add support for composite types - return 'int' # TODO Add support for all types - if tag in [GAZ_PROCEDURE_TAG, GAZ_FUNCTION_TAG, GAZ_VAR_TAG]: - cutoffs = [] - values = [] - types = [] - for key, value in self.settings["type-weights"]["value-types"].items(): - if key == GAZ_VOID_TYPE and tag != GAZ_PROCEDURE_TAG: - continue - cutoffs.append(value + sum(cutoffs)) - values.append(value) - types.append(key) - - res = random.randint(0, sum(values)) - for i in range(len(cutoffs)): - if res < cutoffs[i]: - return types[i] + def get_choice(self, options, numline, cutoffs): + res = random.randint(0, numline - 1) + for i in range(len(cutoffs)): + if res < cutoffs[i]: + try: + return options[i] + except Exception as e: + raise ValueError(str(e) + "Internal Error, please report the stack trace to me") ### LOOP HELPERS ### @@ -848,7 +880,7 @@ class AstGenerator: if cutoffs[i] < a < cutoffs[i + 1]: try: options[i]() - except KeyError: + except KeyError: # if the key is not in the options (due to exclusion) continue except ValueError: break diff --git a/config.yaml b/config.yaml index 65cb2cf..f51ce79 100644 --- a/config.yaml +++ b/config.yaml @@ -9,7 +9,7 @@ generation-options: max-globals: 5 # maximum number of global variables properties: max-range-length: 5 # maximum length of ranges, vectors and tuples, (AxA matrices can exist) - use-english-words: True # use english words instead of random names (this may limit the maximum number of names) + use-english-words: True # use english words instead of random names (if we run out, we switch to random) id-length: # length of identifiers min: 1 max: 5 @@ -68,12 +68,12 @@ statement-weights: # set to 0 for any statements y in-stream: 5 type-weights: - value-types: - integer: 50 - real: 50 - boolean: 50 - character: 50 - void: 10 + atomic-types: + int: 50 # TODO change these to the gaz types + float: 50 + bool: 50 + char: 50 + void: 0 # TODO add support for void composite-types: vector: 20 tuple: 5 diff --git a/constants.py b/constants.py index 3522105..5c969d5 100644 --- a/constants.py +++ b/constants.py @@ -47,6 +47,12 @@ GAZ_STRING_KEY = "string" GAZ_CHAR_KEY = "char" GAZ_BRACKET_TAG = "brackets" GAZ_BREAK_TAG = "break" +GAZ_ATOMIC_TYPE_KEY = "atomic" +GAZ_COMPOSITE_TYPE_KEY = "composite" +GAZ_COMPOSITE_KEY = "composite" +GAZ_VECTOR_KEY = "vector" +GAZ_TUPLE_KEY = "tuple" +GAZ_MATRIX_KEY = "matrix" class NoneTagException(Exception):