def get_tal_of_evaluated_node(node: ast.Node, env: en.Environment) -> en.Type: if node.node_type == ast.LITERAL: node: ast.Literal return LITERAL_TYPE_TABLE[node.lit_type] elif node.node_type == ast.STRING_LITERAL: node: ast.StringLiteralNode return en.Type("char", node.byte_length) elif node.node_type == ast.NAME_NODE: node: ast.NameNode return env.get_type_arr_len(node.name, (node.line_num, node.file)) elif node.node_type == ast.UNARY_OPERATOR: node: ast.UnaryOperator tal = get_tal_of_evaluated_node(node.value, env) if node.operation == "unpack": if len(tal.type_name) > 1 and tal.type_name[0] == "*": return en.Type(tal.type_name[1:]) else: raise lib.TypeException("Cannot unpack a non-pointer type") elif node.operation == "pack": return en.Type("*" + tal.type_name) else: return tal elif node.node_type == ast.BINARY_OPERATOR: node: ast.BinaryOperator return get_tal_of_evaluated_node(node.left, env) elif node.node_type == ast.FUNCTION_CALL: node: ast.FuncCall call_obj = node.call_obj if call_obj.node_type == ast.NAME_NODE: func_group: dict = env.get_function(call_obj.name, (node.line_num, node.file)) arg_types = [] for orig_arg in node.args.lines: tal = get_tal_of_evaluated_node(orig_arg, env) arg_types.append(tal) types_id = en.args_type_hash(arg_types) func = func_group[types_id] return func.r_tal elif node.node_type == ast.INDEXING_NODE: # array node: ast.IndexingNode # return get_tal_of_ordinary_node(node.call_obj, env) tal_co = get_tal_of_evaluated_node(node.call_obj, env) if en.is_array(tal_co): return en.Type(tal_co.type_name, *tal_co.array_lengths[1:]) elif tal_co.type_name[0] == "*": return en.Type(tal_co.type_name[1:]) else: raise lib.TypeException() elif node.node_type == ast.IN_DECREMENT_OPERATOR: node: ast.InDecrementOperator return get_tal_of_evaluated_node(node.value, env) elif node.node_type == ast.NULL_STMT: return en.Type("*void")
def eval_comparison(cmp_func, lp, l_tal: en.Type, rp, r_tal: en.Type, env) -> int: if l_tal.type_name in PRIMITIVE_TYPES and r_tal.type_name in PRIMITIVE_TYPES and not en.is_array(l_tal) and \ not en.is_array(r_tal): l_len = PRIMITIVE_TYPES[l_tal.type_name] r_len = PRIMITIVE_TYPES[r_tal.type_name] lb = mem.MEMORY.get(lp, l_len) rb = mem.MEMORY.get(rp, r_len) if l_tal.type_name == "int": if r_tal.type_name == "int": cmp = typ.int_cmp_int(lb, rb) return cmp_func(cmp) elif l_tal.type_name == "char": if r_tal.type_name == "char": cmp = typ.char_cmp_char(lb, rb) return cmp_func(cmp) elif l_tal.type_name[0] == "*": l_ptr_b = mem.MEMORY.get(lp, l_tal.total_len()) # l_ptr = typ.bytes_to_int(l_ptr_b) if r_tal.type_name[0] == "*": r_ptr_b = mem.MEMORY.get(rp, r_tal.total_len()) # r_ptr = typ.bytes_to_int(r_ptr_b) # print(l_ptr_b ,r_ptr_b) cmp = typ.int_cmp_int(l_ptr_b, r_ptr_b) return cmp_func(cmp) else: raise lib.TypeException( "Comparing pointer type '{}' to primitive type '{}'".format( en.type_to_readable(l_tal), en.type_to_readable(r_tal))) else: print(2131212321)
def eval_call(node: ast.FuncCall, env: en.Environment): func_group: dict = evaluate(node.call_obj, env) some_func = list(func_group.values())[0] if isinstance(some_func, Function): return call_function(func_group, node.args.lines, env) elif isinstance(some_func, NativeFunction): return call_native_function(some_func, node.args.lines, env) else: raise lib.TypeException("Call on a non-callable object")
def int_op_any(lv: bytes, right_ptr: int, right_tal: en.Type, op_set: dict) -> int: if right_tal.type_name in op_set: rv = mem.MEMORY.get(right_ptr, right_tal.total_len()) op_func = op_set[right_tal.type_name] res = op_func(lv, rv) return mem.MEMORY.allocate(res) elif right_tal.type_name[0] == "*": rv = mem.MEMORY.get(right_ptr, PTR_LEN) op_func = op_set["int"] res = op_func(lv, rv) return mem.MEMORY.allocate(res) else: raise lib.TypeException("Cannot operates int with {}".format( en.type_to_readable(right_tal)))
def basic_arithmetic(op_set: dict, left_ptr: int, left_tal: en.Type, right_ptr: int, right_tal: en.Type, env: en.Environment) -> int: if left_tal.type_name in op_set: left_len = left_tal.total_len() lv = mem.MEMORY.get(left_ptr, left_len) # print(right_ptr) return int_op_any(lv, right_ptr, right_tal, op_set[left_tal.type_name]) elif left_tal.type_name[0] == "*": ptr_len = mem.MEMORY.pointer_length lv = mem.MEMORY.get(left_ptr, ptr_len) return int_op_any(lv, right_ptr, right_tal, op_set["int"]) else: raise lib.TypeException("Cannot operates {}".format( en.type_to_readable(right_tal)))
def get_indexing_location_and_unit_len(node: ast.IndexingNode, env: en.Environment) -> (int, int): l_ptr = evaluate(node.call_obj, env) l_tal = get_tal_of_node_self(node, env) if en.is_array(l_tal): depth = index_node_depth(node) unit_length = l_tal.total_len() for i in range(depth): unit_length //= l_tal.array_lengths[i] elif l_tal.type_name[0] == "*": ptr_b = mem.MEMORY.get(l_ptr, PTR_LEN) l_ptr = typ.bytes_to_int(ptr_b) unit_length = mem.MEMORY.get_type_size(l_tal.type_name[1:]) else: raise lib.TypeException("Type '{}' not supporting indexing".format( en.type_to_readable(l_tal))) arg_ptr = evaluate(node.arg, env) # arg type must be int arg_b = mem.MEMORY.get(arg_ptr, mem.MEMORY.get_type_size("int")) arg_v = typ.bytes_to_int(arg_b) return l_ptr + arg_v * unit_length, unit_length
def eval_binary_operation(node: ast.BinaryOperator, env: en.Environment): if node.assignment and node.operation[:-1] in BINARY_OP_TABLE: left = evaluate(node.left, env) right = evaluate(node.right, env) ltl = get_tal_of_evaluated_node(node.left, env) rtl = get_tal_of_evaluated_node(node.right, env) op_type = BINARY_OP_TABLE[node.operation[:-1]] res = basic_arithmetic(op_type, left, ltl, right, rtl, env) mem.MEMORY.mem_copy(res, left, ltl.total_len()) return left elif node.operation in BINARY_OP_TABLE: left = evaluate(node.left, env) right = evaluate(node.right, env) ltl = get_tal_of_evaluated_node(node.left, env) rtl = get_tal_of_evaluated_node(node.right, env) # print(left, right) op_type = BINARY_OP_TABLE[node.operation] return basic_arithmetic(op_type, left, ltl, right, rtl, env) elif node.operation in COMPARE_TABLE: left = evaluate(node.left, env) right = evaluate(node.right, env) ltl = get_tal_of_evaluated_node(node.left, env) rtl = get_tal_of_evaluated_node(node.right, env) cmp = COMPARE_TABLE[node.operation] return eval_comparison(cmp, left, ltl, right, rtl, env) else: raise lib.TypeException( "Unexpected binary operator '{}', in file '{}', at line {}".format( node.operation, node.file, node.line_num))
def call_function(func_group: dict, orig_args: list, call_env: en.Environment): arg_types = [] for orig_arg in orig_args: tal = get_tal_of_evaluated_node(orig_arg, call_env) arg_types.append(tal) types_id = en.args_type_hash(arg_types) func = func_group[types_id] rtn_type = func.r_tal rtn_len = rtn_type.total_len() rtn_loc = mem.MEMORY.allocate_empty(rtn_len) scope = en.FunctionEnvironment(func.outer_scope) mem.MEMORY.push_stack() for i in range(len(orig_args)): param: ParameterPair = func.params[i] orig_arg = orig_args[i] p = evaluate(orig_arg, call_env) tal = param.tal total_len = tal.total_len() arg_ptr = mem.MEMORY.allocate_empty(total_len) scope.define_var(param.name, tal, arg_ptr) mem.MEMORY.mem_copy(p, arg_ptr, total_len) r = evaluate(func.body, scope) if rtn_len > 0 and r is None: raise lib.TypeException( "Missing return statement of a function declared to return type '{}'" .format(en.type_to_readable(rtn_type))) mem.MEMORY.mem_copy(r, rtn_loc, rtn_len) mem.MEMORY.restore_stack() return rtn_loc
def add_namespace(self, namespace): raise lib.TypeException("Sub environment does not support namespace definition")
def eval_assignment_node(node: ast.AssignmentNode, env: en.Environment): r = evaluate(node.right, env) lf = node.line_num, node.file if node.left.node_type == ast.NAME_NODE: name: str = node.left.name if node.level == ast.FUNC_DEFINE: if not isinstance(r, Function): raise lib.TypeException("Unexpected function declaration") env.define_function(name, r) else: tal = get_tal_of_evaluated_node(node.left, env) total_len = tal.total_len() rv = mem.MEMORY.get(r, total_len) current_ptr = env.get(name, lf) mem.MEMORY.set(current_ptr, rv) # env.assign(name, r, lf) elif node.left.node_type == ast.TYPE_NODE: type_node: ast.TypeNode = node.left tal = get_tal_of_defining_node(type_node.right, env) name: str = type_node.left.name total_len = tal.total_len() if total_len == 0: # array with undefined length tal = get_tal_of_evaluated_node(node.right, env) total_len = tal.total_len() ptr = mem.MEMORY.allocate_empty(total_len) if r != 0: # is not undefined mem.MEMORY.mem_copy(r, ptr, total_len) if node.level == ast.VAR: env.define_var(name, tal, ptr) elif node.level == ast.CONST: env.define_const(name, tal, ptr) elif node.left.node_type == ast.DOT: dot: ast.Dot = node.left l_ptr = evaluate(dot.left, env) l_tal = get_tal_of_evaluated_node(dot.left, env) # print(l_tal) struct: Struct = env.get_struct(l_tal.type_name) attr: ast.NameNode = dot.right pos_in_struct = struct.get_attr_pos(attr.name) attr_tal = struct.get_attr_tal(attr.name) attr_len = attr_tal.total_len() rv = mem.MEMORY.get(r, attr_len) mem.MEMORY.set(l_ptr + pos_in_struct, rv) elif node.left.node_type == ast.INDEXING_NODE: eval_setitem(node.left, r, env) elif node.left.node_type == ast.UNARY_OPERATOR: uo: ast.UnaryOperator = node.left tal = get_tal_of_evaluated_node(uo, env) total_len = tal.total_len() l_ptr = evaluate(uo, env) rv = mem.MEMORY.get(r, total_len) if uo.operation == "pack" and uo.value.node_type == ast.NAME_NODE: ri = typ.bytes_to_int(rv) env.assign(uo.value.name, ri, lf) else: mem.MEMORY.set(l_ptr, rv) else: raise lib.TypeException("Currently unimplemented")