def generate_type_struct(program, function, old_type): # Do we take an existing struct with the type we want? reuse_struct = probs_helper.random_value(probs.reuse_struct_prob) structs = [s for s in program.structs if s.has_type(old_type)] existing_structs = len(structs) if reuse_struct and existing_structs > 0: selected = probs_helper.random_value( probs_helper.compute_equal_prob(range(existing_structs))) # An existing struct is taken return structs[selected] # Do we add a new field to an existing struct to create the expected one? reuse_struct = probs_helper.random_value( probs.enhance_existing_struct_prob) existing_structs = len(program.structs) if reuse_struct and existing_structs > 0: if isinstance( old_type, ast.Struct) or (isinstance(old_type, ast.Array) and isinstance(old_type.type, ast.Struct)): # Take the least referenced struct. They are ordered by the number of references and the min is selected. # E.g.: # struct0 -> struct1 -> array(struct2) -> struct3 # La struct3 has a reference depth of 3 # strunc4 # La struct4 has a reference depth of 0 # struct5 -> struct6 # La struct6 has a reference depth of 1 struct_t = min(program.structs, key=lambda s: max( len(path) for path in ast.reference_paths_to_struct( s, program.structs))) else: selected = probs_helper.random_value( probs_helper.compute_equal_prob(range(existing_structs))) struct_t = program.structs[selected] if not struct_t.check_circular_reference(old_type): # An existing struct is taken if not struct_t.has_type(old_type): struct_t.add_field( ast.name_struct_field(old_type, len(struct_t.fields)), old_type) return struct_t # A new struct is created with that particular field struct_name = "struct" + str(len(program.structs)) struct_t = ast.Struct(struct_name, [ast.name_struct_field(old_type, 0), old_type]) program.structs.append(struct_t) return struct_t
def generate_lvalue(program, function, exp_type, exp_depth_prob): exp_depth = probs_helper.random_value(exp_depth_prob or probs.exp_depth_prob) if exp_depth == 0: return generate_basic_lvalue(program, function, exp_type) lower_exp_depth_prob = probs_helper.compute_equal_prob(range(0, exp_depth)) operators = ast.get_operators(exp_type, "lvalue") if len(operators) == 0: return generate_basic_lvalue(program, function, exp_type) operator, _ = probs_helper.random_value(operators) if operator == "[]": return generate_expression_arity_2( program, function, exp_type, operator, default_generator_1=generate_lvalue, generator_1_depth_prob=lower_exp_depth_prob, default_generator_2=generate_expression, generator_2_depth_prob=None) return generate_expression_arity_1( program, function, exp_type, operator, default_generator_1=generate_lvalue, generator_1_depth_prob=lower_exp_depth_prob)
def generate_function(program, function, return_type): # Do we take an existing function? if isinstance(return_type, ast.Void): reuse = probs_helper.random_value(probs.reuse_proc_prob) else: reuse = probs_helper.random_value(probs.reuse_func_prob) functions = program.get_functions_by_return_type(return_type) # avoid recursion by default if reuse and len(functions): selected = probs_helper.random_value( probs_helper.compute_equal_prob(range(len(functions)))) if functions[selected].name != function.name: # An existing function is taken return functions[selected] # A new one is created param_types = generate_function_param_types(program, function) func_name = "func" + str(len(program.functions)) new_function = ast.Function(func_name, return_type, param_types) program.functions.append(new_function) # Generates the statements in the function number_statements = probs_helper.random_value(probs.number_stmts_func_prob) for i in range(number_statements): new_function.stmts.append(generate_stmt_func(program, new_function)) if not isinstance(return_type, ast.Void): new_function.stmts.append( generate_stmt_return(program, new_function, None)) return new_function
def generate_expression_arity_3(program, function, exp_type, operator, default_generator_1, generator_1_depth_prob, default_generator_2, generator_2_depth_prob, default_generator_3, generator_3_depth_prob, **kwargs): # Infer types and select one pair types_pairs = type_inference.infer_operands_type(program, function, 3, operator, exp_type) sub_exp_1_type, sub_exp_2_type, sub_exp_2_type = probs_helper.random_value( probs_helper.compute_equal_prob(types_pairs)) sub_exp_1 = default_generator_1(program, function, sub_exp_1_type, exp_depth_prob=generator_1_depth_prob) sub_exp_2 = default_generator_2(program, function, sub_exp_2_type, exp_depth_prob=generator_2_depth_prob) sub_exp_3 = default_generator_3(program, function, sub_exp_2_type, exp_depth_prob=generator_3_depth_prob) return ast.TernaryExpression(sub_exp_1, sub_exp_2, sub_exp_3, operator, exp_type)
def generate_stmt_augmented_assignment(program, function): # Get type augmented_assignment_type_cls = probs_helper.random_value( probs.augmented_assignment_types_prob) augmented_assignment_type = generate_type( program, function, new_type_cls=augmented_assignment_type_cls, old_type_obj=None) # Generate left part left_exp = generate_lvalue(program, function, augmented_assignment_type, None) # Get operator operators = ast.get_operators(augmented_assignment_type, "assignment") if not operators: operator = "=" else: operator, _ = probs_helper.random_value(operators) # Generate right part right_types = type_inference.infer_operands_type( program, function, 1, operator, augmented_assignment_type) right_type = probs_helper.random_value( probs_helper.compute_equal_prob(right_types)) right_exp = generate_expression(program, function, right_type, None) # Compose all return ast.Assignment(left_exp, operator, right_exp, augmented_assignment_type)
def generate_expression_arity_1(program, function, exp_type, operator, default_generator_1, generator_1_depth_prob, **kwargs): # Infer types and select one sub_exp_1_types = type_inference.infer_operands_type( program, function, 1, operator, exp_type) sub_exp_1_type = probs_helper.random_value( probs_helper.compute_equal_prob(sub_exp_1_types)) if operator in ["++", "--"]: return generate_expression_incdec(program, function, sub_exp_1_type, operator) if operator == "&": sub_exp_1 = generate_lvalue(program, function, sub_exp_1_type, None) return ast.UnaryExpression(operator, sub_exp_1, exp_type, post_op=False) if operator in [".", "->"]: sub_exp_1 = default_generator_1(program, function, sub_exp_1_type, exp_depth_prob=generator_1_depth_prob) if operator == ".": # Type -> Struct field = sub_exp_1_type.get_field_by_type(exp_type) return ast.StructAccessExpression(operator, sub_exp_1, field, exp_type) if operator == "->": # Type -> Pointer(Struct) field = sub_exp_1_type.type.get_field_by_type(exp_type) return ast.StructAccessExpression(operator, sub_exp_1, field, exp_type) raise AssertionError("Unknown operator") if operator == '()': sub_exp_1 = default_generator_1(program, function, sub_exp_1_type, exp_depth_prob=generator_1_depth_prob) return ast.CastExpression(sub_exp_1, exp_type) # Otherwise sub_exp_1 = default_generator_1(program, function, sub_exp_1_type, generator_1_depth_prob) return ast.UnaryExpression(operator, sub_exp_1, exp_type, post_op=False)
def generate_local_var(program, function, c_type): if c_type.name not in function.local_vars.keys(): # Creates the local vars empty list for that type function.local_vars[c_type.name] = [] create_new_local_var = probs_helper.random_value(probs.new_local_var_prob) number_of_vars = len(function.local_vars[c_type.name]) if not create_new_local_var and number_of_vars > 0: selected = probs_helper.random_value( probs_helper.compute_equal_prob(range(number_of_vars))) # An existing local variable is taken return ast.local_variable(c_type, selected + 1) # A new local variable must be created literal = generate_literal(program, function, c_type, from_declaration=True) function.local_vars[c_type.name].append((c_type, literal)) return ast.local_variable(c_type, len(function.local_vars[c_type.name]))
def generate_expression(program, function, exp_type, exp_depth_prob): # Check implicit promotion if probs_helper.random_value(probs.implicit_promotion_bool): try: new_type_cls = probs_helper.random_value( probs.promotions_prob[exp_type.__class__]) exp_type = new_type_cls() except KeyError: pass exp_depth = probs_helper.random_value(exp_depth_prob or probs.exp_depth_prob) if exp_depth == 0: return generate_basic_exp(program, function, exp_type) lower_exp_depth_prob = probs_helper.compute_equal_prob(range(0, exp_depth)) isCall = probs_helper.random_value(probs.call_prob) if not isCall: operators = ast.get_operators(exp_type, "normal") if len(operators) == 0: return generate_basic_exp(program, function, exp_type) operator, arity = probs_helper.random_value(operators) func_name = "generate_expression_arity_{}".format(arity) kwargs = { "default_generator_1": generate_expression, "generator_1_depth_prob": lower_exp_depth_prob, "default_generator_2": generate_expression, "generator_2_depth_prob": lower_exp_depth_prob, "default_generator_3": generate_expression, "generator_3_depth_prob": lower_exp_depth_prob, } return globals()[func_name](program, function, exp_type, operator, **kwargs) else: return generate_expression_invocation(program, function, exp_type, lower_exp_depth_prob)
def generate_stmt_incdec(program, function): stmt_type = generate_type(program, function, new_type_cls=None, old_type_obj=None) # Check if operators are enabled in expressions operators = [k[0] for k in ast.get_operators(stmt_type, "normal").keys()] stmt_operators = [] if '++' in operators: stmt_operators.append("++") if '--' in operators: stmt_operators.append("--") if not stmt_operators: return generate_stmt_assignment(program, function) # Create the statement operator = probs_helper.random_value( probs_helper.compute_equal_prob(stmt_operators)) return generate_expression_incdec(program, function, stmt_type, operator)
def generate_expression_invocation(program, function, return_type, exp_depth_prob): # generates the function (if necessary) invoked_func = generate_function(program, function, return_type) # generates the arguments params = [] expression_depth = probs_helper.random_value(exp_depth_prob) lower_exp_depth_prob = {0: 1} if exp_depth_prob == 0 \ else probs_helper.compute_equal_prob(range(0, expression_depth + 1)) for name, arg_type in invoked_func.param_types: params.append( generate_expression(program, function, arg_type, lower_exp_depth_prob)) # Count invocation program.invocation_as_expr[invoked_func.name] += 1 # generates the invocation return ast.Invocation(invoked_func.name, params, return_type, False)
def generate_expression_arity_2(program, function, exp_type, operator, default_generator_1, generator_1_depth_prob, default_generator_2, generator_2_depth_prob, **kwargs): # Infer types and select one pair types_pairs = type_inference.infer_operands_type(program, function, 2, operator, exp_type) sub_exp_1_type, sub_exp_2_type = probs_helper.random_value( probs_helper.compute_equal_prob(types_pairs)) # Generate the expressions sub_exp_1 = default_generator_1(program, function, sub_exp_1_type, exp_depth_prob=generator_1_depth_prob) sub_exp_2 = default_generator_2(program, function, sub_exp_2_type, exp_depth_prob=generator_2_depth_prob) if operator == "[]": return ast.ArrayAccessExpression(sub_exp_1, sub_exp_2, exp_type) return ast.BinaryExpression(sub_exp_1, operator, sub_exp_2, exp_type)
def _process_json_probs_entry(prob_name: str, prob_dictionary: dict, result: dict) -> None: """Takes one entry of the json probability specification file, process it and adds the correct representation to result""" from core import probs if not probs.does_this_probability_exist(prob_name): print(f"Unknown probability '{prob_name}'.", file=sys.stderr) # probability name is not in probs module elif "__prob_distribution__" not in prob_dictionary.keys(): # 1) fixed probability set by the user result[prob_name] = {_eval_str(key): content for (key, content) in prob_dictionary.items()} elif prob_dictionary["__prob_distribution__"] == "equal_prob": # 2) equal probability for a set of values if "__values__" not in prob_dictionary.keys(): print(f"Equal probability distribution requires a __values__ entry.", file=sys.stderr) else: values = set() for value_str in prob_dictionary["__values__"]: values.add(_eval_str(value_str)) result[prob_name] = probs_helper.compute_equal_prob(values) elif prob_dictionary["__prob_distribution__"] in ["proportional_prob", "inverse_proportional_prob"]: # 3) (inverse and direct) proportional probability for a set of values that do not sum 0 if "__values__" not in prob_dictionary.keys(): print(f"Proportional probability distribution requires a __values__ entry.", file=sys.stderr) else: # keys of the dict must be evaluated (e.g., "3" -> 3, "ast.Int" -> ast.Int) values_dict = {_eval_str(key): content for (key, content) in prob_dictionary["__values__"].items()} if prob_name == "proportional_prob": # direct proportional result[prob_name] = probs_helper.compute_proportional_prob(values_dict) else: # inverse proportional result[prob_name] = probs_helper.compute_inverse_proportional_prob(values_dict) elif prob_dictionary["__prob_distribution__"] == "normal_prob": # 5) normal probability, given a mean and standard deviation if not {"__mean__", "__stdev__"}.issubset(prob_dictionary.keys()): print(f"Normal probability distribution requires __mean__ and __stdev__ entries.", file=sys.stderr) else: result[prob_name] = probs_helper.compute_normal_prob(prob_dictionary["__mean__"], prob_dictionary["__stdev__"]) else: print(f"Unknown probability distribution '{prob_dictionary['__prob_distribution__']}'.", file=sys.stderr)
def generate_expression_incdec(program, function, exp_type, operator): assert operator in ["++", "--"] sub_exp_1 = generate_lvalue(program, function, exp_type, None) post_op = probs_helper.random_value( probs_helper.compute_equal_prob([True, False])) return ast.UnaryExpression(operator, sub_exp_1, exp_type, post_op)
ast.UnsignedShortInt, ast.SignedInt, ast.UnsignedInt, ast.SignedLongInt, ast.UnsignedLongInt, ast.SignedLongLongInt, ast.UnsignedLongLongInt, ast.Float, ast.Double, ast.LongDouble, } all_types = set(primitive_types).union({ast.Pointer, ast.Struct, ast.Array}) doc['primitive_types_prob'] = "probabilities among primitive types (default: equal probability for all the types)" primitive_types_prob = probs_helper.compute_equal_prob(primitive_types) doc['assignment_types_prob'] = "assignment type (default: equal probability for all the types)" assignment_types_prob = probs_helper.compute_equal_prob( set(primitive_types).union({ast.Pointer, ast.Struct})) doc['augmented_assignment_types_prob'] = "augmented assignment type (+=, -=, *=...) " \ "(default: equal probability for primitive types)" augmented_assignment_types_prob = probs_helper.compute_equal_prob( primitive_types) doc['all_types_prob'] = "type probability when any type may occur in a syntax construction " \ "(default: equal probability for any type)" all_types_prob = probs_helper.compute_equal_prob(all_types) doc['array_size'] = "size of the arrays to be created (default: 1-10)"