Browse Source

Implement call expressions

gingerBill 2 years ago
parent
commit
4654b41c3e
4 changed files with 201 additions and 6 deletions
  1. 11 0
      src/array.cpp
  2. 6 3
      src/tilde.hpp
  3. 1 1
      src/tilde_const.cpp
  4. 183 2
      src/tilde_proc.cpp

+ 11 - 0
src/array.cpp

@@ -168,6 +168,17 @@ gb_internal gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi)
 	}
 	return out;
 }
+template <typename T>
+gb_internal gb_inline Slice<T> slice(Array<T> const &array, isize lo, isize hi) {
+	GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
+	Slice<T> out = {};
+	isize len = hi-lo;
+	if (len > 0) {
+		out.data = array.data+lo;
+		out.count = len;
+	}
+	return out;
+}
 
 
 template <typename T>

+ 6 - 3
src/tilde.hpp

@@ -42,8 +42,9 @@ struct cgValue {
 	cgValueKind kind;
 	Type *      type;
 	union {
-		TB_Symbol *symbol;
-		TB_Node *  node;
+		// NOTE: any value in this union must be a pointer
+		TB_Symbol *   symbol;
+		TB_Node *     node;
 		cgValueMulti *multi;
 	};
 };
@@ -308,4 +309,6 @@ gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgV
 gb_internal bool    cg_emit_goto(cgProcedure *p, TB_Node *control_region);
 
 
-gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name);
+gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name);
+
+gb_internal isize cg_append_tuple_values(cgProcedure *p, Array<cgValue> *dst_values, cgValue src_value);

+ 1 - 1
src/tilde_const.cpp

@@ -126,7 +126,7 @@ gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Ty
 
 	if (global == nullptr) {
 		global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE);
-		tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_global, type_size_of(type), type_align_of(type), 2);
+		tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(type), type_align_of(type), 2);
 	}
 
 	tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)str_global);

+ 183 - 2
src/tilde_proc.cpp

@@ -355,7 +355,7 @@ gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr) {
 	return res;
 }
 
-gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice<cgValue> args) {
+gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice<cgValue> const &args) {
 	if (value.kind == cgValue_Symbol) {
 		value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type);
 	}
@@ -540,6 +540,43 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice<cgValue>
 	return cg_value_multi(multi, pt->results);
 }
 
+
+gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const &param_value, TokenPos const &pos) {
+	switch (param_value.kind) {
+	case ParameterValue_Constant:
+		if (is_type_constant_type(parameter_type)) {
+			auto res = cg_const_value(p, parameter_type, param_value.value);
+			return res;
+		} else {
+			ExactValue ev = param_value.value;
+			cgValue arg = {};
+			Type *type = type_of_expr(param_value.original_ast_expr);
+			if (type != nullptr) {
+				arg = cg_const_value(p, type, ev);
+			} else {
+				arg = cg_const_value(p, parameter_type, param_value.value);
+			}
+			return cg_emit_conv(p, arg, parameter_type);
+		}
+
+	case ParameterValue_Nil:
+		return cg_const_nil(p, parameter_type);
+	case ParameterValue_Location:
+		{
+			String proc_name = {};
+			if (p->entity != nullptr) {
+				proc_name = p->entity->token.string;
+			}
+			GB_PANIC("TODO(bill): cg_emit_source_code_location_as_global");
+			// return cg_emit_source_code_location_as_global(p, proc_name, pos);
+			break;
+		}
+	case ParameterValue_Value:
+		return cg_build_expr(p, param_value.ast_value);
+	}
+	return cg_const_nil(p, parameter_type);
+}
+
 gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
 	ast_node(ce, CallExpr, expr);
 
@@ -611,7 +648,151 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
 		value = cg_emit_load(p, value);
 	}
 	GB_ASSERT(value.kind == cgValue_Value);
+	GB_ASSERT(value.node != nullptr);
 	GB_ASSERT(is_type_proc(value.type));
 
-	return cg_emit_call(p, value, {});
+	TEMPORARY_ALLOCATOR_GUARD();
+
+	Type *proc_type_ = base_type(value.type);
+	GB_ASSERT(proc_type_->kind == Type_Proc);
+	TypeProc *pt = &proc_type_->Proc;
+
+	GB_ASSERT(ce->split_args != nullptr);
+
+	auto args = array_make<cgValue>(temporary_allocator(), 0, pt->param_count);
+
+	bool vari_expand = (ce->ellipsis.pos.line != 0);
+	bool is_c_vararg = pt->c_vararg;
+
+	for_array(i, ce->split_args->positional) {
+		Entity *e = pt->params->Tuple.variables[i];
+		if (e->kind == Entity_TypeName) {
+			continue;
+		} else if (e->kind == Entity_Constant) {
+			continue;
+		}
+
+		GB_ASSERT(e->kind == Entity_Variable);
+
+		if (pt->variadic && pt->variadic_index == i) {
+			cgValue variadic_args = cg_const_nil(p, e->type);
+			auto variadic = slice(ce->split_args->positional, pt->variadic_index, ce->split_args->positional.count);
+			if (variadic.count != 0) {
+				// variadic call argument generation
+				Type *slice_type = e->type;
+				GB_ASSERT(slice_type->kind == Type_Slice);
+
+				if (is_c_vararg) {
+					GB_ASSERT(!vari_expand);
+
+					Type *elem_type = slice_type->Slice.elem;
+
+					for (Ast *var_arg : variadic) {
+						cgValue arg = cg_build_expr(p, var_arg);
+						if (is_type_any(elem_type)) {
+							array_add(&args, cg_emit_conv(p, arg, default_type(arg.type)));
+						} else {
+							array_add(&args, cg_emit_conv(p, arg, elem_type));
+						}
+					}
+					break;
+				} else if (vari_expand) {
+					GB_ASSERT(variadic.count == 1);
+					variadic_args = cg_build_expr(p, variadic[0]);
+					variadic_args = cg_emit_conv(p, variadic_args, slice_type);
+				} else {
+					Type *elem_type = slice_type->Slice.elem;
+
+					auto var_args = array_make<cgValue>(temporary_allocator(), 0, variadic.count);
+					for (Ast *var_arg : variadic) {
+						cgValue v = cg_build_expr(p, var_arg);
+						cg_append_tuple_values(p, &var_args, v);
+					}
+					isize slice_len = var_args.count;
+					if (slice_len > 0) {
+						cgAddr slice = cg_add_local(p, slice_type, nullptr, true);
+						cgAddr base_array = cg_add_local(p, alloc_type_array(elem_type, slice_len), nullptr, true);
+
+						for (isize i = 0; i < var_args.count; i++) {
+							cgValue addr = cg_emit_array_epi(p, base_array.addr, cast(i32)i);
+							cgValue var_arg = var_args[i];
+							var_arg = cg_emit_conv(p, var_arg, elem_type);
+							cg_emit_store(p, addr, var_arg);
+						}
+
+						cgValue base_elem = cg_emit_array_epi(p, base_array.addr, 0);
+						cgValue len = cg_const_int(p, t_int, slice_len);
+						GB_PANIC("TODO(bill): cg_fill_slice");
+						// cg_fill_slice(p, slice, base_elem, len);
+
+						variadic_args = cg_addr_load(p, slice);
+					}
+				}
+			}
+			array_add(&args, variadic_args);
+
+			break;
+		} else {
+			cgValue value = cg_build_expr(p, ce->split_args->positional[i]);
+			cg_append_tuple_values(p, &args, value);
+		}
+	}
+
+	if (!is_c_vararg) {
+		array_resize(&args, pt->param_count);
+	}
+
+	for (Ast *arg : ce->split_args->named) {
+		ast_node(fv, FieldValue, arg);
+		GB_ASSERT(fv->field->kind == Ast_Ident);
+		String name = fv->field->Ident.token.string;
+		gb_unused(name);
+		isize param_index = lookup_procedure_parameter(pt, name);
+		GB_ASSERT(param_index >= 0);
+
+		cgValue value = cg_build_expr(p, fv->value);
+		GB_ASSERT(!is_type_tuple(value.type));
+		args[param_index] = value;
+	}
+
+	TokenPos pos = ast_token(ce->proc).pos;
+
+
+	if (pt->params != nullptr)  {
+		isize min_count = pt->params->Tuple.variables.count;
+		if (is_c_vararg) {
+			min_count -= 1;
+		}
+		GB_ASSERT(args.count >= min_count);
+		for_array(arg_index, pt->params->Tuple.variables) {
+			Entity *e = pt->params->Tuple.variables[arg_index];
+			if (pt->variadic && arg_index == pt->variadic_index) {
+				if (!is_c_vararg && args[arg_index].node == nullptr) {
+					args[arg_index] = cg_const_nil(p, e->type);
+				}
+				continue;
+			}
+
+			cgValue arg = args[arg_index];
+			if (arg.node == nullptr) {
+				switch (e->kind) {
+				case Entity_TypeName:
+				case Entity_Constant:
+					break;
+				case Entity_Variable:
+					args[arg_index] = cg_handle_param_value(p, e->type, e->Variable.param_value, pos);
+					break;
+				default:
+					GB_PANIC("Unknown entity kind %.*s\n", LIT(entity_strings[e->kind]));
+				}
+			} else {
+				args[arg_index] = cg_emit_conv(p, arg, e->type);
+			}
+		}
+	}
+
+	isize final_count = is_c_vararg ? args.count : pt->param_count;
+	auto call_args = slice(args, 0, final_count);
+
+	return cg_emit_call(p, value, call_args);
 }