Browse Source

using on indexable field; Auto deref for (Index|Slice)Expr

Ginger Bill 9 years ago
parent
commit
04b5d8c132
6 changed files with 193 additions and 126 deletions
  1. 5 5
      build.bat
  2. 11 53
      code/demo.odin
  3. 1 0
      src/checker/entity.cpp
  4. 94 52
      src/checker/expr.cpp
  5. 9 0
      src/checker/type.cpp
  6. 73 16
      src/codegen/ssa.cpp

+ 5 - 5
build.bat

@@ -4,7 +4,7 @@
 set exe_name=odin.exe
 
 :: Debug = 0, Release = 1
-set release_mode=1
+set release_mode=0
 
 set compiler_flags= -nologo -Oi -TP -W4 -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
 
@@ -44,10 +44,10 @@ rem pushd %build_dir%
 	del *.pdb > NUL 2> NUL
 	del *.ilk > NUL 2> NUL
 
-	rem cl %compiler_settings% "src\main.cpp" ^
-		rem /link %linker_settings% -OUT:%exe_name% ^
-	rem && odin run code/demo.odin
-	odin run code/demo.odin
+	cl %compiler_settings% "src\main.cpp" ^
+		/link %linker_settings% -OUT:%exe_name% ^
+	&& odin run code/demo.odin
+	rem odin run code/demo.odin
 
 
 	:do_not_compile_exe

+ 11 - 53
code/demo.odin

@@ -3,59 +3,17 @@
 #import "hash.odin"
 #import "mem.odin"
 
-main :: proc() {
-	{ // New Standard Library stuff
-		s := "Hello"
-		fmt.println(s,
-		            utf8.valid_string(s),
-		            hash.murmur64(s.data, s.count))
-
-		// utf8.odin
-		// hash.odin
-		//     - crc, fnv, fnva, murmur
-		// mem.odin
-		//     - Custom allocators
-		//     - Helpers
-	}
-
-	{
-		arena: mem.Arena
-		mem.init_arena_from_context(^arena, mem.megabytes(16)) // Uses default allocator
-		defer mem.free_arena(^arena)
-
-		push_allocator mem.arena_allocator(^arena) {
-			x := new(int)
-			x^ = 1337
-
-			fmt.println(x^)
-		}
-
-		/*
-			push_allocator x {
-				...
-			}
-
-			is equivalent to this:
 
-			{
-				prev_allocator := current_context().allocator
-				current_context().allocator = x
-				defer current_context().allocator = prev_allocator
-
-				...
-			}
-		*/
-
-		// You can also "push" a context
-
-		c := current_context()
-		c.allocator = mem.arena_allocator(^arena)
-
-		push_context c {
-			x := new(int)
-			x^ = 365
+A :: struct { using e: [12]int }
+Vector2 :: raw_union {
+	using _xy: struct #ordered { x, y: f32 }
+	using v: {2}f32
+	e: [2]f32
+}
 
-			fmt.println(x^)
-		}
-	}
+main :: proc() {
+	v: Vector2
+	v.x = 123
+	v[1] = 321
+	fmt.println(v)
 }

+ 1 - 0
src/checker/entity.cpp

@@ -129,6 +129,7 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
 	entity->Variable.field_index = field_index;
 	entity->Variable.is_field  = true;
 	entity->Variable.anonymous = cast(b8)is_anonymous;
+	entity->Variable.is_using = cast(b8)is_anonymous;
 	return entity;
 }
 

+ 94 - 52
src/checker/expr.cpp

@@ -224,6 +224,8 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 
 	isize other_field_index = 0;
 
+	Entity *using_index_expr = NULL;
+
 
 	// TODO(bill): Random declarations with DeclInfo
 #if 0
@@ -365,6 +367,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 				Token name_token = name->Ident;
 
 				Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, vd->is_using, cast(i32)field_index);
+				e->identifier = name;
 				if (name_token.string == "_") {
 					fields[field_index++] = e;
 				} else {
@@ -386,8 +389,30 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 				Type *t = base_type(type_deref(type));
 				if (!is_type_struct(t) && !is_type_raw_union(t)) {
 					Token name_token = vd->names[0]->Ident;
-					error(name_token, "`using` on a field `%.*s` must be a type", LIT(name_token.string));
-					continue;
+					if (is_type_indexable(t)) {
+						b32 ok = true;
+						gb_for_array(emi, entity_map.entries) {
+							Entity *e = entity_map.entries[emi].value;
+							if (e->kind == Entity_Variable && e->Variable.anonymous) {
+								if (is_type_indexable(e->type)) {
+									if (e->identifier != vd->names[0]) {
+										ok = false;
+										using_index_expr = e;
+										break;
+									}
+								}
+							}
+						}
+						if (ok) {
+							using_index_expr = fields[field_index-1];
+						} else {
+							fields[field_index-1]->Variable.anonymous = false;
+							error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string));
+						}
+					} else {
+						error(name_token, "`using` on a field `%.*s` must be a `struct` or `raw_union`", LIT(name_token.string));
+						continue;
+					}
 				}
 
 				populate_using_entity_map(c, node, type, &entity_map);
@@ -3080,6 +3105,28 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
 }
 
 
+Entity *find_using_index_expr(Type *t) {
+	t = base_type(t);
+	if (t->kind != Type_Record) {
+		return NULL;
+	}
+
+	for (isize i = 0; i < t->Record.field_count; i++) {
+		Entity *f = t->Record.fields[i];
+		if (f->kind == Entity_Variable &&
+		    f->Variable.is_field && f->Variable.anonymous) {
+			if (is_type_indexable(f->type)) {
+				return f;
+			}
+			Entity *res = find_using_index_expr(f->type);
+			if (res != NULL) {
+				return res;
+			}
+		}
+	}
+	return NULL;
+}
+
 ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
 	GB_ASSERT(call->kind == AstNode_CallExpr);
 	ast_node(ce, CallExpr, call);
@@ -3428,54 +3475,58 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			goto error;
 		}
 
-		b32 valid = false;
-		i64 max_count = -1;
-		Type *t = base_type(o->type);
-		switch (t->kind) {
-		case Type_Basic:
-			if (is_type_string(t)) {
-				valid = true;
-				if (o->mode == Addressing_Constant) {
-					max_count = o->value.value_string.len;
+		Type *t = base_type(type_deref(o->type));
+
+		auto set_index_data = [](Operand *o, Type *t, i64 *max_count) -> b32 {
+			t = base_type(type_deref(t));
+
+			switch (t->kind) {
+			case Type_Basic:
+				if (is_type_string(t)) {
+					if (o->mode == Addressing_Constant) {
+						*max_count = o->value.value_string.len;
+					}
+					if (o->mode != Addressing_Variable)
+						o->mode = Addressing_Value;
+					o->type = t_u8;
+					return true;
 				}
-				if (o->mode != Addressing_Variable)
+				break;
+
+			case Type_Array:
+				*max_count = t->Array.count;
+				if (o->mode != Addressing_Variable) {
 					o->mode = Addressing_Value;
-				o->type = t_u8;
-			}
-			break;
+				}
+				o->type = t->Array.elem;
+				return true;
 
-		case Type_Array:
-			valid = true;
-			max_count = t->Array.count;
-			if (o->mode != Addressing_Variable)
-				o->mode = Addressing_Value;
-			o->type = t->Array.elem;
-			break;
+			case Type_Vector:
+				*max_count = t->Vector.count;
+				if (o->mode != Addressing_Variable) {
+					o->mode = Addressing_Value;
+				}
+				o->type = t->Vector.elem;
+				return true;
 
-		case Type_Vector:
-			valid = true;
-			max_count = t->Vector.count;
-			if (o->mode != Addressing_Variable)
-				o->mode = Addressing_Value;
-			o->type = t->Vector.elem;
-			break;
 
+			case Type_Slice:
+				o->type = t->Slice.elem;
+				o->mode = Addressing_Variable;
+				return true;
+			}
+
+			return false;
+		};
 
-		case Type_Slice:
-			valid = true;
-			o->type = t->Slice.elem;
-			o->mode = Addressing_Variable;
-			break;
+		i64 max_count = -1;
+		b32 valid = set_index_data(o, t, &max_count);
 
-		case Type_Pointer: {
-			Type *bt = base_type(t->Pointer.elem);
-			if (bt->kind == Type_Array) {
-				valid = true;
-				max_count = bt->Array.count;
-				o->mode = Addressing_Variable;
-				o->type = bt->Array.elem;
+		if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
+			Entity *found = find_using_index_expr(t);
+			if (found != NULL) {
+				valid = set_index_data(o, found->type, &max_count);
 			}
-		} break;
 		}
 
 		if (!valid) {
@@ -3506,7 +3557,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 
 		b32 valid = false;
 		i64 max_count = -1;
-		Type *t = base_type(o->type);
+		Type *t = base_type(type_deref(o->type));
 		switch (t->kind) {
 		case Type_Basic:
 			if (is_type_string(t)) {
@@ -3536,15 +3587,6 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		case Type_Slice:
 			valid = true;
 			break;
-
-		case Type_Pointer: {
-			Type *bt = base_type(t->Pointer.elem);
-			if (bt->kind == Type_Array) {
-				valid = true;
-				max_count = bt->Array.count;
-				o->type = make_type_slice(c->allocator, bt->Array.elem);
-			}
-		} break;
 		}
 
 		if (!valid) {

+ 9 - 0
src/checker/type.cpp

@@ -487,6 +487,10 @@ b32 is_type_u8(Type *t) {
 	}
 	return false;
 }
+b32 is_type_array(Type *t) {
+	t = base_type(t);
+	return t->kind == Type_Array;
+}
 b32 is_type_slice(Type *t) {
 	t = base_type(t);
 	return t->kind == Type_Slice;
@@ -546,6 +550,11 @@ b32 is_type_any(Type *t) {
 }
 
 
+b32 is_type_indexable(Type *t) {
+	return is_type_array(t) || is_type_slice(t) || is_type_vector(t) || is_type_string(t);
+}
+
+
 
 b32 is_type_comparable(Type *t) {
 	t = base_type(t);

+ 73 - 16
src/codegen/ssa.cpp

@@ -2821,9 +2821,35 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		Type *t = base_type(type_of_expr(proc->module->info, ie->expr));
 		gbAllocator a = proc->module->allocator;
 
+
+		b32 deref = is_type_pointer(t);
+		t = type_deref(t);
+
+		ssaValue *using_addr = NULL;
+		if (!is_type_indexable(t)) {
+			// Using index expression
+			Entity *using_field = find_using_index_expr(t);
+			if (using_field != NULL) {
+				Selection sel = lookup_field(a, t, using_field->token.string, false);
+				ssaValue *e = ssa_build_addr(proc, ie->expr).addr;
+				using_addr = ssa_emit_deep_field_gep(proc, t, e, sel);
+
+				t = using_field->type;
+			}
+		}
+
+
 		switch (t->kind) {
 		case Type_Vector: {
-			ssaValue *vector = ssa_build_addr(proc, ie->expr).addr;
+			ssaValue *vector = NULL;
+			if (using_addr != NULL) {
+				vector = using_addr;
+			} else {
+				vector = ssa_build_addr(proc, ie->expr).addr;
+				if (deref) {
+					vector = ssa_emit_load(proc, vector);
+				}
+			}
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
 			ssaValue *len = ssa_make_const_int(a, t->Vector.count);
 			ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len);
@@ -2831,7 +2857,15 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		} break;
 
 		case Type_Array: {
-			ssaValue *array = ssa_build_addr(proc, ie->expr).addr;
+			ssaValue *array = NULL;
+			if (using_addr != NULL) {
+				array = using_addr;
+			} else {
+				array = ssa_build_addr(proc, ie->expr).addr;
+				if (deref) {
+					array = ssa_emit_load(proc, array);
+				}
+			}
 			Type *et = make_type_pointer(proc->module->allocator, t->Array.elem);
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
 			ssaValue *elem = ssa_emit_struct_gep(proc, array, index, et);
@@ -2841,7 +2875,15 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		} break;
 
 		case Type_Slice: {
-			ssaValue *slice = ssa_build_expr(proc, ie->expr);
+			ssaValue *slice = NULL;
+			if (using_addr != NULL) {
+				slice = ssa_emit_load(proc, using_addr);
+			} else {
+				slice = ssa_build_expr(proc, ie->expr);
+				if (deref) {
+					slice = ssa_emit_load(proc, slice);
+				}
+			}
 			ssaValue *elem = ssa_slice_elem(proc, slice);
 			ssaValue *len = ssa_slice_len(proc, slice);
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
@@ -2855,12 +2897,20 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(ie->expr));
 			ssaValue *elem = NULL;
 			ssaValue *len = NULL;
-			if (tv->mode == Addressing_Constant) {
+			if (tv != NULL && tv->mode == Addressing_Constant) {
 				ssaValue *array = ssa_add_global_string_array(proc->module, tv->value.value_string);
 				elem = ssa_array_elem(proc, array);
 				len = ssa_make_const_int(a, tv->value.value_string.len);
 			} else {
-				ssaValue *str = ssa_build_expr(proc, ie->expr);
+				ssaValue *str = NULL;
+				if (using_addr != NULL) {
+					str = ssa_emit_load(proc, using_addr);
+				} else {
+					str = ssa_build_expr(proc, ie->expr);
+					if (deref) {
+						str = ssa_emit_load(proc, str);
+					}
+				}
 				elem = ssa_string_elem(proc, str);
 				len = ssa_string_len(proc, str);
 			}
@@ -2884,23 +2934,30 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		if (se->low  != NULL)    low  = ssa_build_expr(proc, se->low);
 		if (se->high != NULL)    high = ssa_build_expr(proc, se->high);
 		if (se->triple_indexed)  max  = ssa_build_expr(proc, se->max);
-		ssaAddr base = ssa_build_addr(proc, se->expr);
-		Type *type = base_type(ssa_addr_type(base));
+		ssaValue *addr = ssa_build_addr(proc, se->expr).addr;
+		ssaValue *base = ssa_emit_load(proc, addr);
+		Type *type = base_type(ssa_type(base));
+
+		if (is_type_pointer(type)) {
+			type = type_deref(type);
+			addr = base;
+			base = ssa_emit_load(proc, base);
+		}
 
 		// TODO(bill): Cleanup like mad!
 
 		switch (type->kind) {
 		case Type_Slice: {
-			Type *slice_type = ssa_addr_type(base);
+			Type *slice_type = type;
 
-			if (high == NULL) high = ssa_slice_len(proc, ssa_emit_load(proc, base.addr));
-			if (max == NULL)  max  = ssa_slice_cap(proc, ssa_emit_load(proc, base.addr));
+			if (high == NULL) high = ssa_slice_len(proc, base);
+			if (max == NULL)  max  = ssa_slice_cap(proc, base);
 			GB_ASSERT(max != NULL);
 
 			ssa_slice_bounds_check(proc, se->open, low, high, max, false);
 
 			Token op_sub = {Token_Sub};
-			ssaValue *elem = ssa_slice_elem(proc, ssa_emit_load(proc, base.addr));
+			ssaValue *elem = ssa_slice_elem(proc, base);
 			ssaValue *len  = ssa_emit_arith(proc, op_sub, high, low, t_int);
 			ssaValue *cap  = ssa_emit_arith(proc, op_sub, max,  low, t_int);
 			ssaValue *slice = ssa_add_local_generated(proc, slice_type);
@@ -2918,14 +2975,14 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		case Type_Array: {
 			Type *slice_type = make_type_slice(a, type->Array.elem);
 
-			if (high == NULL) high = ssa_array_len(proc, ssa_emit_load(proc, base.addr));
-			if (max == NULL)  max  = ssa_array_cap(proc, ssa_emit_load(proc, base.addr));
+			if (high == NULL) high = ssa_array_len(proc, base);
+			if (max == NULL)  max  = ssa_array_cap(proc, base);
 			GB_ASSERT(max != NULL);
 
 			ssa_slice_bounds_check(proc, se->open, low, high, max, false);
 
 			Token op_sub = {Token_Sub};
-			ssaValue *elem = ssa_array_elem(proc, base.addr);
+			ssaValue *elem = ssa_array_elem(proc, addr);
 			ssaValue *len  = ssa_emit_arith(proc, op_sub, high, low, t_int);
 			ssaValue *cap  = ssa_emit_arith(proc, op_sub, max,  low, t_int);
 			ssaValue *slice = ssa_add_local_generated(proc, slice_type);
@@ -2943,7 +3000,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		case Type_Basic: {
 			GB_ASSERT(type == t_string);
 			if (high == NULL) {
-				high = ssa_string_len(proc, ssa_emit_load(proc, base.addr));
+				high = ssa_string_len(proc, base);
 			}
 
 			ssa_slice_bounds_check(proc, se->open, low, high, high, true);
@@ -2952,7 +3009,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			ssaValue *elem, *len;
 			len = ssa_emit_arith(proc, op_sub, high, low, t_int);
 
-			elem = ssa_string_elem(proc, ssa_emit_load(proc, base.addr));
+			elem = ssa_string_elem(proc, base);
 			elem = ssa_emit_ptr_offset(proc, elem, low);
 
 			ssaValue *str = ssa_add_local_generated(proc, t_string);