Selaa lähdekoodia

Begin work on builtin procedures

gingerBill 2 vuotta sitten
vanhempi
commit
eec3b3009f
7 muutettua tiedostoa jossa 637 lisäystä ja 9 poistoa
  1. 1 0
      src/checker.cpp
  2. 1 0
      src/tilde.cpp
  3. 6 1
      src/tilde.hpp
  4. 147 0
      src/tilde_builtin.cpp
  5. 479 7
      src/tilde_expr.cpp
  6. 2 1
      src/tilde_proc.cpp
  7. 1 0
      src/types.cpp

+ 1 - 0
src/checker.cpp

@@ -1114,6 +1114,7 @@ gb_internal void init_universal(void) {
 
 
 	t_u8_ptr       = alloc_type_pointer(t_u8);
+	t_u8_multi_ptr = alloc_type_multi_pointer(t_u8);
 	t_int_ptr      = alloc_type_pointer(t_int);
 	t_i64_ptr      = alloc_type_pointer(t_i64);
 	t_f64_ptr      = alloc_type_pointer(t_f64);

+ 1 - 0
src/tilde.cpp

@@ -669,6 +669,7 @@ gb_internal String cg_get_entity_name(cgModule *m, Entity *e) {
 #include "tilde_const.cpp"
 #include "tilde_debug.cpp"
 #include "tilde_expr.cpp"
+#include "tilde_builtin.cpp"
 #include "tilde_proc.cpp"
 #include "tilde_stmt.cpp"
 

+ 6 - 1
src/tilde.hpp

@@ -272,6 +272,7 @@ gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws);
 
 gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr);
 gb_internal cgAddr  cg_build_addr(cgProcedure *p, Ast *expr);
+gb_internal cgValue cg_build_addr_ptr(cgProcedure *p, Ast *expr);
 
 gb_internal Type *  cg_addr_type(cgAddr const &addr);
 gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr);
@@ -311,4 +312,8 @@ 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 isize cg_append_tuple_values(cgProcedure *p, Array<cgValue> *dst_values, cgValue src_value);
+gb_internal isize cg_append_tuple_values(cgProcedure *p, Array<cgValue> *dst_values, cgValue src_value);
+
+
+gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value);
+gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &x);

+ 147 - 0
src/tilde_builtin.cpp

@@ -0,0 +1,147 @@
+gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value) {
+	Type *t = base_type(value.type);
+
+	switch (t->kind) {
+	case Type_Basic:
+		switch (t->Basic.kind) {
+		case Basic_string:
+			{
+				GB_ASSERT(value.kind == cgValue_Addr);
+				cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type));
+				cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1);
+				return cg_emit_load(p, len_ptr);
+			}
+		case Basic_cstring:
+			break;
+		}
+		break;
+	case Type_Array:
+		return cg_const_int(p, t_int, t->Array.count);
+	case Type_EnumeratedArray:
+		return cg_const_int(p, t_int, t->EnumeratedArray.count);
+	case Type_Slice:
+		{
+			GB_ASSERT(value.kind == cgValue_Addr);
+			cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type));
+			cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1);
+			return cg_emit_load(p, len_ptr);
+		}
+	case Type_DynamicArray:
+		{
+			GB_ASSERT(value.kind == cgValue_Addr);
+			cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type));
+			cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1);
+			return cg_emit_load(p, len_ptr);
+		}
+	case Type_Map:
+		{
+			GB_ASSERT(value.kind == cgValue_Addr);
+			cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type));
+			cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1);
+			return cg_emit_conv(p, cg_emit_load(p, len_ptr), t_int);
+		}
+	case Type_Struct:
+		GB_ASSERT(is_type_soa_struct(t));
+		break;
+	case Type_RelativeSlice:
+		break;
+	}
+
+	GB_PANIC("TODO(bill): cg_builtin_len %s", type_to_string(t));
+	return {};
+}
+
+gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &value) {
+	Type *t = base_type(value.type);
+	cgValue res = {};
+	switch (t->kind) {
+	case Type_Slice:
+		{
+			GB_ASSERT(value.kind == cgValue_Addr);
+			cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type));
+			cgValue data_ptr = cg_emit_struct_ep(p, ptr, 0);
+			res = cg_emit_load(p, data_ptr);
+		}
+		break;
+	case Type_DynamicArray:
+		{
+			GB_ASSERT(value.kind == cgValue_Addr);
+			cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type));
+			cgValue data_ptr = cg_emit_struct_ep(p, ptr, 0);
+			res = cg_emit_load(p, data_ptr);
+		}
+		break;
+	case Type_Basic:
+		if (t->Basic.kind == Basic_string) {
+			GB_ASSERT(value.kind == cgValue_Addr);
+			cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type));
+			cgValue data_ptr = cg_emit_struct_ep(p, ptr, 0);
+			res = cg_emit_load(p, data_ptr);
+		} else if (t->Basic.kind == Basic_cstring) {
+			res = cg_emit_conv(p, value, t_u8_multi_ptr);
+		}
+		break;
+	case Type_Pointer:
+	case Type_MultiPointer:
+		GB_PANIC("TODO(bill) %s", type_to_string(value.type));
+		// res = cg_emit_conv(p, value, tv.type);
+		break;
+	}
+	GB_ASSERT(res.node != nullptr);
+	return res;
+}
+
+gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) {
+	ast_node(ce, CallExpr, expr);
+
+	if (BuiltinProc__simd_begin < id && id < BuiltinProc__simd_end) {
+		GB_PANIC("TODO(bill): cg_build_builtin_simd_proc");
+		// return cg_build_builtin_simd_proc(p, expr, tv, id);
+	}
+
+	String builtin_name = builtin_procs[id].name;
+
+	switch (id) {
+	case BuiltinProc_DIRECTIVE: {
+		ast_node(bd, BasicDirective, ce->proc);
+		String name = bd->name.string;
+		GB_ASSERT(name == "location");
+		String procedure = p->entity->token.string;
+		TokenPos pos = ast_token(ce->proc).pos;
+		if (ce->args.count > 0) {
+			Ast *ident = unselector_expr(ce->args[0]);
+			GB_ASSERT(ident->kind == Ast_Ident);
+			Entity *e = entity_of_node(ident);
+			GB_ASSERT(e != nullptr);
+
+			if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) {
+				procedure = e->parent_proc_decl->entity->token.string;
+			} else {
+				procedure = str_lit("");
+			}
+			pos = e->token.pos;
+
+		}
+		GB_PANIC("TODO(bill): cg_emit_source_code_location_as_global");
+		// return cg_emit_source_code_location_as_global(p, procedure, pos);
+	} break;
+
+	case BuiltinProc_len: {
+		cgValue v = cg_build_expr(p, ce->args[0]);
+		Type *t = base_type(v.type);
+		if (is_type_pointer(t)) {
+			// IMPORTANT TODO(bill): Should there be a nil pointer check?
+			v = cg_emit_load(p, v);
+			t = type_deref(t);
+		}
+		return cg_builtin_len(p, v);
+	}
+
+
+	}
+
+
+	GB_PANIC("TODO(bill): builtin procs %d %.*s", id, LIT(builtin_name));
+	return {};
+}
+

+ 479 - 7
src/tilde_expr.cpp

@@ -179,7 +179,7 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type)
 	TB_DataType dt = cg_data_type(type);
 	switch (value.kind) {
 	case cgValue_Value:
-		GB_ASSERT(!TB_IS_VOID_TYPE(dt));
+		GB_ASSERT_MSG(!TB_IS_VOID_TYPE(dt), "%s", type_to_string(type));
 		value.type = type;
 		if (value.node->dt.raw != dt.raw) {
 			value.node = tb_inst_bitcast(p->func, value.node, dt);
@@ -1959,6 +1959,255 @@ gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) {
 }
 
 
+gb_internal cgValue cg_find_ident(cgProcedure *p, Entity *e, Ast *expr) {
+	cgAddr *found_addr = map_get(&p->variable_map, e);
+	if (found_addr) {
+		return cg_addr_load(p, *found_addr);
+	}
+
+	cgValue *found = nullptr;
+	rw_mutex_shared_lock(&p->module->values_mutex);
+	found = map_get(&p->module->values, e);
+	rw_mutex_shared_unlock(&p->module->values_mutex);
+
+	if (found) {
+
+		auto v = *found;
+		// NOTE(bill): This is because pointers are already pointers in LLVM
+		if (is_type_proc(v.type)) {
+			return v;
+		}
+		return cg_emit_load(p, v);
+	} else if (e != nullptr && e->kind == Entity_Variable) {
+		return cg_addr_load(p, cg_build_addr(p, expr));
+	}
+
+	if (e->kind == Entity_Procedure) {
+		return cg_find_procedure_value_from_entity(p->module, e);
+	}
+
+	String pkg = {};
+	if (e->pkg) {
+		pkg = e->pkg->name;
+	}
+	gb_printf_err("Error in: %s\n", token_pos_to_string(ast_token(expr).pos));
+	GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr);
+	return {};
+}
+
+gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) {
+	ast_node(ue, UnaryExpr, expr);
+	auto tv = type_and_value_of_expr(expr);
+
+
+	Ast *ue_expr = unparen_expr(ue->expr);
+	if (ue_expr->kind == Ast_IndexExpr && tv.mode == Addressing_OptionalOkPtr && is_type_tuple(tv.type)) {
+		GB_PANIC("TODO(bill): &m[k]");
+		// Type *tuple = tv.type;
+
+		// Type *map_type = type_of_expr(ue_expr->IndexExpr.expr);
+		// Type *ot = base_type(map_type);
+		// Type *t = base_type(type_deref(ot));
+		// bool deref = t != ot;
+		// GB_ASSERT(t->kind == Type_Map);
+		// ast_node(ie, IndexExpr, ue_expr);
+
+		// lbValue map_val = lb_build_addr_ptr(p, ie->expr);
+		// if (deref) {
+		// 	map_val = lb_emit_load(p, map_val);
+		// }
+
+		// lbValue key = lb_build_expr(p, ie->index);
+		// key = lb_emit_conv(p, key, t->Map.key);
+
+		// lbAddr addr = lb_addr_map(map_val, key, t, alloc_type_pointer(t->Map.value));
+		// lbValue ptr = lb_addr_get_ptr(p, addr);
+
+		// lbValue ok = lb_emit_comp_against_nil(p, Token_NotEq, ptr);
+		// ok = lb_emit_conv(p, ok, tuple->Tuple.variables[1]->type);
+
+		// lbAddr res = lb_add_local_generated(p, tuple, false);
+		// lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0);
+		// lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1);
+		// lb_emit_store(p, gep0, ptr);
+		// lb_emit_store(p, gep1, ok);
+		// return lb_addr_load(p, res);
+
+	} else if (is_type_soa_pointer(tv.type)) {
+		GB_PANIC("TODO(bill): &soa[i]");
+		// ast_node(ie, IndexExpr, ue_expr);
+		// lbValue addr = lb_build_addr_ptr(p, ie->expr);
+		// lbValue index = lb_build_expr(p, ie->index);
+
+		// if (!build_context.no_bounds_check) {
+		// 	// TODO(bill): soa bounds checking
+		// }
+
+		// return lb_make_soa_pointer(p, tv.type, addr, index);
+	} else if (ue_expr->kind == Ast_CompoundLit) {
+		cgValue v = cg_build_expr(p, ue->expr);
+
+		Type *type = v.type;
+		cgAddr addr = {};
+		// if (p->is_startup) {
+			// addr = cg_add_global_generated(p->module, type, v);
+		// } else {
+			addr = cg_add_local(p, type, nullptr, false);
+		// }
+		cg_addr_store(p, addr, v);
+		return addr.addr;
+
+	} else if (ue_expr->kind == Ast_TypeAssertion) {
+		GB_PANIC("TODO(bill): &v.(T)");
+		// if (is_type_tuple(tv.type)) {
+		// 	Type *tuple = tv.type;
+		// 	Type *ptr_type = tuple->Tuple.variables[0]->type;
+		// 	Type *ok_type = tuple->Tuple.variables[1]->type;
+
+		// 	ast_node(ta, TypeAssertion, ue_expr);
+		// 	TokenPos pos = ast_token(expr).pos;
+		// 	Type *type = type_of_expr(ue_expr);
+		// 	GB_ASSERT(!is_type_tuple(type));
+
+		// 	lbValue e = lb_build_expr(p, ta->expr);
+		// 	Type *t = type_deref(e.type);
+		// 	if (is_type_union(t)) {
+		// 		lbValue v = e;
+		// 		if (!is_type_pointer(v.type)) {
+		// 			v = lb_address_from_load_or_generate_local(p, v);
+		// 		}
+		// 		Type *src_type = type_deref(v.type);
+		// 		Type *dst_type = type;
+
+		// 		lbValue src_tag = {};
+		// 		lbValue dst_tag = {};
+		// 		if (is_type_union_maybe_pointer(src_type)) {
+		// 			src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v);
+		// 			dst_tag = lb_const_bool(p->module, t_bool, true);
+		// 		} else {
+		// 			src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v));
+		// 			dst_tag = lb_const_union_tag(p->module, src_type, dst_type);
+		// 		}
+
+		// 		lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
+
+		// 		lbValue data_ptr = lb_emit_conv(p, v, ptr_type);
+		// 		lbAddr res = lb_add_local_generated(p, tuple, true);
+		// 		lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0);
+		// 		lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1);
+		// 		lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type)));
+		// 		lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type));
+		// 		return lb_addr_load(p, res);
+		// 	} else if (is_type_any(t)) {
+		// 		lbValue v = e;
+		// 		if (is_type_pointer(v.type)) {
+		// 			v = lb_emit_load(p, v);
+		// 		}
+
+		// 		lbValue data_ptr = lb_emit_conv(p, lb_emit_struct_ev(p, v, 0), ptr_type);
+		// 		lbValue any_id = lb_emit_struct_ev(p, v, 1);
+		// 		lbValue id = lb_typeid(p->module, type);
+
+		// 		lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id);
+
+		// 		lbAddr res = lb_add_local_generated(p, tuple, false);
+		// 		lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0);
+		// 		lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1);
+		// 		lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type)));
+		// 		lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type));
+		// 		return lb_addr_load(p, res);
+		// 	} else {
+		// 		GB_PANIC("TODO(bill): type assertion %s", type_to_string(type));
+		// 	}
+
+		// } else {
+		// 	GB_ASSERT(is_type_pointer(tv.type));
+
+		// 	ast_node(ta, TypeAssertion, ue_expr);
+		// 	TokenPos pos = ast_token(expr).pos;
+		// 	Type *type = type_of_expr(ue_expr);
+		// 	GB_ASSERT(!is_type_tuple(type));
+
+		// 	lbValue e = lb_build_expr(p, ta->expr);
+		// 	Type *t = type_deref(e.type);
+		// 	if (is_type_union(t)) {
+		// 		lbValue v = e;
+		// 		if (!is_type_pointer(v.type)) {
+		// 			v = lb_address_from_load_or_generate_local(p, v);
+		// 		}
+		// 		Type *src_type = type_deref(v.type);
+		// 		Type *dst_type = type;
+
+
+		// 		if ((p->state_flags & StateFlag_no_type_assert) == 0) {
+		// 			lbValue src_tag = {};
+		// 			lbValue dst_tag = {};
+		// 			if (is_type_union_maybe_pointer(src_type)) {
+		// 				src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v);
+		// 				dst_tag = lb_const_bool(p->module, t_bool, true);
+		// 			} else {
+		// 				src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v));
+		// 				dst_tag = lb_const_union_tag(p->module, src_type, dst_type);
+		// 			}
+
+
+		// 			isize arg_count = 6;
+		// 			if (build_context.no_rtti) {
+		// 				arg_count = 4;
+		// 			}
+
+		// 			lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
+		// 			auto args = array_make<lbValue>(permanent_allocator(), arg_count);
+		// 			args[0] = ok;
+
+		// 			args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
+		// 			args[2] = lb_const_int(p->module, t_i32, pos.line);
+		// 			args[3] = lb_const_int(p->module, t_i32, pos.column);
+
+		// 			if (!build_context.no_rtti) {
+		// 				args[4] = lb_typeid(p->module, src_type);
+		// 				args[5] = lb_typeid(p->module, dst_type);
+		// 			}
+		// 			lb_emit_runtime_call(p, "type_assertion_check", args);
+		// 		}
+
+		// 		lbValue data_ptr = v;
+		// 		return lb_emit_conv(p, data_ptr, tv.type);
+		// 	} else if (is_type_any(t)) {
+		// 		lbValue v = e;
+		// 		if (is_type_pointer(v.type)) {
+		// 			v = lb_emit_load(p, v);
+		// 		}
+		// 		lbValue data_ptr = lb_emit_struct_ev(p, v, 0);
+		// 		if ((p->state_flags & StateFlag_no_type_assert) == 0) {
+		// 			GB_ASSERT(!build_context.no_rtti);
+
+		// 			lbValue any_id = lb_emit_struct_ev(p, v, 1);
+
+		// 			lbValue id = lb_typeid(p->module, type);
+		// 			lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id);
+		// 			auto args = array_make<lbValue>(permanent_allocator(), 6);
+		// 			args[0] = ok;
+
+		// 			args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
+		// 			args[2] = lb_const_int(p->module, t_i32, pos.line);
+		// 			args[3] = lb_const_int(p->module, t_i32, pos.column);
+
+		// 			args[4] = any_id;
+		// 			args[5] = id;
+		// 			lb_emit_runtime_call(p, "type_assertion_check", args);
+		// 		}
+
+		// 		return lb_emit_conv(p, data_ptr, tv.type);
+		// 	} else {
+		// 		GB_PANIC("TODO(bill): type assertion %s", type_to_string(type));
+		// 	}
+		// }
+	}
+
+	return cg_build_addr_ptr(p, ue->expr);
+}
+
 
 gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 	expr = unparen_expr(expr);
@@ -2016,9 +2265,7 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 		if (addr) {
 			return cg_addr_load(p, *addr);
 		}
-		// return cg_find_ident(p, m, e, expr);
-		GB_PANIC("TODO: cg_find_ident");
-		return {};
+		return cg_find_ident(p, e, expr);
 	case_end;
 
 	case_ast_node(i, Implicit, expr);
@@ -2151,8 +2398,7 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 
 	case_ast_node(ue, UnaryExpr, expr);
 		if (ue->op.kind == Token_And) {
-			GB_PANIC("TODO(bill): cg_build_unary_and");
-			// return cg_build_unary_and(p, expr);
+			return cg_build_unary_and(p, expr);
 		}
 		cgValue v = cg_build_expr(p, ue->expr);
 		return cg_emit_unary_arith(p, ue->op.kind, v, type);
@@ -2166,6 +2412,10 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 
 }
 
+gb_internal cgValue cg_build_addr_ptr(cgProcedure *p, Ast *expr) {
+	cgAddr addr = cg_build_addr(p, expr);
+	return cg_addr_get_ptr(p, addr);
+}
 
 gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr);
 gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr) {
@@ -2193,6 +2443,225 @@ gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr) {
 	return addr;
 }
 
+gb_internal cgAddr cg_build_addr_index_expr(cgProcedure *p, Ast *expr) {
+	ast_node(ie, IndexExpr, expr);
+
+	Type *t = base_type(type_of_expr(ie->expr));
+
+	bool deref = is_type_pointer(t);
+	t = base_type(type_deref(t));
+	if (is_type_soa_struct(t)) {
+		GB_PANIC("TODO(bill): #soa");
+		// // SOA STRUCTURES!!!!
+		// lbValue val = cg_build_addr_ptr(p, ie->expr);
+		// if (deref) {
+		// 	val = cg_emit_load(p, val);
+		// }
+
+		// cgValue index = cg_build_expr(p, ie->index);
+		// return cg_addr_soa_variable(val, index, ie->index);
+	}
+
+	if (ie->expr->tav.mode == Addressing_SoaVariable) {
+		GB_PANIC("TODO(bill): #soa");
+		// // SOA Structures for slices/dynamic arrays
+		// GB_ASSERT(is_type_pointer(type_of_expr(ie->expr)));
+
+		// lbValue field = lb_build_expr(p, ie->expr);
+		// lbValue index = lb_build_expr(p, ie->index);
+
+
+		// if (!build_context.no_bounds_check) {
+		// 	// TODO HACK(bill): Clean up this hack to get the length for bounds checking
+		// 	// GB_ASSERT(LLVMIsALoadInst(field.value));
+
+		// 	// lbValue a = {};
+		// 	// a.value = LLVMGetOperand(field.value, 0);
+		// 	// a.type = alloc_type_pointer(field.type);
+
+		// 	// irInstr *b = &a->Instr;
+		// 	// GB_ASSERT(b->kind == irInstr_StructElementPtr);
+		// 	// lbValue base_struct = b->StructElementPtr.address;
+
+		// 	// GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct))));
+		// 	// lbValue len = ir_soa_struct_len(p, base_struct);
+		// 	// lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+		// }
+		// lbValue val = lb_emit_ptr_offset(p, field, index);
+		// return lb_addr(val);
+	}
+
+	GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr));
+
+	if (is_type_map(t)) {
+		GB_PANIC("TODO(bill): map indexing");
+		// lbAddr map_addr = lb_build_addr(p, ie->expr);
+		// lbValue key = lb_build_expr(p, ie->index);
+		// key = lb_emit_conv(p, key, t->Map.key);
+
+		// Type *result_type = type_of_expr(expr);
+		// lbValue map_ptr = lb_addr_get_ptr(p, map_addr);
+		// if (is_type_pointer(type_deref(map_ptr.type))) {
+		// 	map_ptr = lb_emit_load(p, map_ptr);
+		// }
+		// return lb_addr_map(map_ptr, key, t, result_type);
+	}
+
+	switch (t->kind) {
+	case Type_Array: {
+		cgValue array = {};
+		array = cg_build_addr_ptr(p, ie->expr);
+		if (deref) {
+			array = cg_emit_load(p, array);
+		}
+		cgValue index = cg_build_expr(p, ie->index);
+		index = cg_emit_conv(p, index, t_int);
+		cgValue elem = cg_emit_array_ep(p, array, index);
+
+		auto index_tv = type_and_value_of_expr(ie->index);
+		if (index_tv.mode != Addressing_Constant) {
+			// cgValue len = cg_const_int(p->module, t_int, t->Array.count);
+			// cg_emit_bounds_check(p, ast_token(ie->index), index, len);
+		}
+		return cg_addr(elem);
+	}
+
+	case Type_EnumeratedArray: {
+		cgValue array = {};
+		array = cg_build_addr_ptr(p, ie->expr);
+		if (deref) {
+			array = cg_emit_load(p, array);
+		}
+
+		Type *index_type = t->EnumeratedArray.index;
+
+		auto index_tv = type_and_value_of_expr(ie->index);
+
+		cgValue index = {};
+		if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) {
+			if (index_tv.mode == Addressing_Constant) {
+				ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value);
+				index = cg_const_value(p, index_type, idx);
+			} else {
+				index = cg_emit_arith(p, Token_Sub,
+				                      cg_build_expr(p, ie->index),
+				                      cg_const_value(p, index_type, *t->EnumeratedArray.min_value),
+				                      index_type);
+				index = cg_emit_conv(p, index, t_int);
+			}
+		} else {
+			index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int);
+		}
+
+		cgValue elem = cg_emit_array_ep(p, array, index);
+
+		if (index_tv.mode != Addressing_Constant) {
+			// cgValue len = cg_const_int(p->module, t_int, t->EnumeratedArray.count);
+			// cg_emit_bounds_check(p, ast_token(ie->index), index, len);
+		}
+		return cg_addr(elem);
+	}
+
+	case Type_Slice: {
+		cgValue slice = {};
+		slice = cg_build_expr(p, ie->expr);
+		if (deref) {
+			slice = cg_emit_load(p, slice);
+		}
+		cgValue elem = cg_builtin_raw_data(p, slice);
+		cgValue index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int);
+		// cgValue len = cg_builtin_len(p, slice);
+		// cg_emit_bounds_check(p, ast_token(ie->index), index, len);
+		cgValue v = cg_emit_ptr_offset(p, elem, index);
+		return cg_addr(v);
+	}
+
+	case Type_MultiPointer: {
+		cgValue multi_ptr = {};
+		multi_ptr = cg_build_expr(p, ie->expr);
+		if (deref) {
+			multi_ptr = cg_emit_load(p, multi_ptr);
+		}
+		cgValue index = cg_build_expr(p, ie->index);
+		index = cg_emit_conv(p, index, t_int);
+
+		return cg_addr(cg_emit_ptr_offset(p, multi_ptr, index));
+	}
+
+	case Type_RelativeSlice: {
+		GB_PANIC("TODO(bill): relative slice");
+		// lbAddr slice_addr = {};
+		// if (deref) {
+		// 	slice_addr = lb_addr(lb_build_expr(p, ie->expr));
+		// } else {
+		// 	slice_addr = lb_build_addr(p, ie->expr);
+		// }
+		// lbValue slice = lb_addr_load(p, slice_addr);
+
+		// lbValue elem = lb_slice_elem(p, slice);
+		// lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
+		// lbValue len = lb_slice_len(p, slice);
+		// lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+		// lbValue v = lb_emit_ptr_offset(p, elem, index);
+		// return lb_addr(v);
+	}
+
+	case Type_DynamicArray: {
+		cgValue dynamic_array = {};
+		dynamic_array = cg_build_expr(p, ie->expr);
+		if (deref) {
+			dynamic_array = cg_emit_load(p, dynamic_array);
+		}
+		cgValue elem = cg_builtin_raw_data(p, dynamic_array);
+		cgValue index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int);
+		// cgValue len = cg_dynamic_array_len(p, dynamic_array);
+		// cg_emit_bounds_check(p, ast_token(ie->index), index, len);
+		cgValue v = cg_emit_ptr_offset(p, elem, index);
+		return cg_addr(v);
+	}
+
+	case Type_Matrix: {
+		GB_PANIC("TODO(bill): matrix");
+		// lbValue matrix = {};
+		// matrix = lb_build_addr_ptr(p, ie->expr);
+		// if (deref) {
+		// 	matrix = lb_emit_load(p, matrix);
+		// }
+		// lbValue index = lb_build_expr(p, ie->index);
+		// index = lb_emit_conv(p, index, t_int);
+		// lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index);
+		// elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr)));
+
+		// auto index_tv = type_and_value_of_expr(ie->index);
+		// if (index_tv.mode != Addressing_Constant) {
+		// 	lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count);
+		// 	lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+		// }
+		// return lb_addr(elem);
+	}
+
+
+	case Type_Basic: { // Basic_string
+		cgValue str;
+		cgValue elem;
+		cgValue len;
+		cgValue index;
+
+		str = cg_build_expr(p, ie->expr);
+		if (deref) {
+			str = cg_emit_load(p, str);
+		}
+		elem = cg_builtin_raw_data(p, str);
+		len = cg_builtin_len(p, str);
+
+		index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int);
+		// cg_emit_bounds_check(p, ast_token(ie->index), index, len);
+
+		return cg_addr(cg_emit_ptr_offset(p, elem, index));
+	}
+	}
+	return {};
+}
 
 gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) {
 	switch (expr->kind) {
@@ -2218,6 +2687,10 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) {
 		return cg_build_addr_from_entity(p, e, expr);
 	case_end;
 
+	case_ast_node(ie, IndexExpr, expr);
+		return cg_build_addr_index_expr(p, expr);
+	case_end;
+
 	case_ast_node(se, SliceExpr, expr);
 		return cg_build_addr_slice_expr(p, expr);
 	case_end;
@@ -2350,6 +2823,5 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) {
 	         LIT(ast_strings[expr->kind]),
 	         token_pos_to_string(token_pos));
 
-
 	return {};
 }

+ 2 - 1
src/tilde_proc.cpp

@@ -607,7 +607,8 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
 			}
 			return {};
 		}
-		GB_PANIC("TODO(bill): builtin procs %d %.*s", id, LIT(builtin_procs[id].name));
+
+		return cg_build_builtin(p, id, expr);
 	}
 
 	// NOTE(bill): Regular call

+ 1 - 0
src/types.cpp

@@ -594,6 +594,7 @@ gb_global Type *t_untyped_uninit     = &basic_types[Basic_UntypedUninit];
 
 
 gb_global Type *t_u8_ptr       = nullptr;
+gb_global Type *t_u8_multi_ptr = nullptr;
 gb_global Type *t_int_ptr      = nullptr;
 gb_global Type *t_i64_ptr      = nullptr;
 gb_global Type *t_f64_ptr      = nullptr;