Bladeren bron

Overloaded `free`; 3 dotted ellipsis

Ginger Bill 8 jaren geleden
bovenliggende
commit
e86c990b75
12 gewijzigde bestanden met toevoegingen van 111 en 48 verwijderingen
  1. 8 4
      code/demo.odin
  2. 1 2
      code/punity.odin
  3. 1 1
      core/_preload.odin
  4. 15 15
      core/fmt.odin
  5. 2 2
      core/mem.odin
  6. 1 1
      core/os_windows.odin
  7. 28 6
      src/check_expr.c
  8. 5 3
      src/checker.c
  9. 3 7
      src/gb/gb.h
  10. 31 0
      src/ir.c
  11. 12 5
      src/parser.c
  12. 4 2
      src/tokenizer.c

+ 8 - 4
code/demo.odin

@@ -72,6 +72,12 @@ syntax :: proc() {
 	// `odin build_dll demo.odin`
 
 
+	// New vector syntax
+	v: [vector 3]f32;
+	v[0] = 123;
+	v.x  = 123; // valid for all vectors with count 1 to 4
+
+
 	// Next part
 	prefixes();
 }
@@ -189,14 +195,14 @@ loops :: proc() {
 	for i in 0..<123 { // 123 exclusive
 	}
 
-	for i in 0..122 { // 122 inclusive
+	for i in 0...122 { // 122 inclusive
 	}
 
 	for val, idx in 12..<16 {
 		fmt.println(val, idx);
 	}
 
-	primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19};
+	primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
 
 	for p in primes {
 		fmt.println(p);
@@ -224,8 +230,6 @@ loops :: proc() {
 		}
 	}
 
-
-
 	procedure_overloading();
 }
 

+ 1 - 2
code/punity.odin

@@ -398,8 +398,7 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
 	ShowWindow(win32_window, SW_SHOW);
 
 	window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
-	assert(window_buffer.data != nil);
-	defer free(window_buffer.data);
+	defer free(window_buffer);
 
 
 	for i := 0; i < window_buffer.count; i += 1 {

+ 1 - 1
core/_preload.odin

@@ -164,7 +164,7 @@ alloc_align :: proc(size, alignment: int) -> rawptr #inline {
 	return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
 }
 
-free :: proc(ptr: rawptr) #inline {
+free_ptr :: proc(ptr: rawptr) #inline {
 	__check_context();
 	a := context.allocator;
 	if ptr != nil {

+ 15 - 15
core/fmt.odin

@@ -58,38 +58,38 @@ Fmt_Info :: struct {
 
 
 
-fprint :: proc(fd: os.Handle, args: ..any) -> int {
+fprint :: proc(fd: os.Handle, args: ...any) -> int {
 	data: [DEFAULT_BUFFER_SIZE]byte;
 	buf := Buffer{data[:], 0};
-	bprint(^buf, ..args);
+	bprint(^buf, ...args);
 	os.write(fd, buf.data[:buf.length]);
 	return buf.length;
 }
 
-fprintln :: proc(fd: os.Handle, args: ..any) -> int {
+fprintln :: proc(fd: os.Handle, args: ...any) -> int {
 	data: [DEFAULT_BUFFER_SIZE]byte;
 	buf := Buffer{data[:], 0};
-	bprintln(^buf, ..args);
+	bprintln(^buf, ...args);
 	os.write(fd, buf.data[:buf.length]);
 	return buf.length;
 }
-fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
+fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int {
 	data: [DEFAULT_BUFFER_SIZE]byte;
 	buf := Buffer{data[:], 0};
-	bprintf(^buf, fmt, ..args);
+	bprintf(^buf, fmt, ...args);
 	os.write(fd, buf.data[:buf.length]);
 	return buf.length;
 }
 
 
-print :: proc(args: ..any) -> int {
-	return fprint(os.stdout, ..args);
+print :: proc(args: ...any) -> int {
+	return fprint(os.stdout, ...args);
 }
-println :: proc(args: ..any) -> int {
-	return fprintln(os.stdout, ..args);
+println :: proc(args: ...any) -> int {
+	return fprintln(os.stdout, ...args);
 }
-printf :: proc(fmt: string, args: ..any) -> int {
-	return fprintf(os.stdout, fmt, ..args);
+printf :: proc(fmt: string, args: ...any) -> int {
+	return fprintf(os.stdout, fmt, ...args);
 }
 
 
@@ -225,7 +225,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 }
 
 
-bprint :: proc(buf: ^Buffer, args: ..any) -> int {
+bprint :: proc(buf: ^Buffer, args: ...any) -> int {
 	fi: Fmt_Info;
 	fi.buf = buf;
 
@@ -241,7 +241,7 @@ bprint :: proc(buf: ^Buffer, args: ..any) -> int {
 	return buf.length;
 }
 
-bprintln :: proc(buf: ^Buffer, args: ..any) -> int {
+bprintln :: proc(buf: ^Buffer, args: ...any) -> int {
 	fi: Fmt_Info;
 	fi.buf = buf;
 
@@ -888,7 +888,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
 }
 
 
-bprintf :: proc(b: ^Buffer, fmt: string, args: ..any) -> int {
+bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
 	fi := Fmt_Info{};
 	end := fmt.count;
 	arg_index := 0;

+ 2 - 2
core/mem.odin

@@ -123,8 +123,8 @@ init_arena_from_context :: proc(using a: ^Arena, size: int) {
 free_arena :: proc(using a: ^Arena) {
 	if backing.procedure != nil {
 		push_allocator backing {
-			free(memory.data);
-			memory = memory[0:0];
+			free(memory);
+			memory = nil;
 			offset = 0;
 		}
 	}

+ 1 - 1
core/os_windows.odin

@@ -235,7 +235,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
 
 		win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
 		if single_read_length <= 0 {
-			free(data.data);
+			free(data);
 			return nil, false;
 		}
 

+ 28 - 6
src/check_expr.c

@@ -1519,12 +1519,7 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
 			return;
 		}
 
-		bool is_value =
-			o->mode == Addressing_Variable ||
-			o->mode == Addressing_Value ||
-			o->mode == Addressing_Constant;
-
-		if (!is_value || is_type_untyped(t)) {
+		if (!is_operand_value(*o) || is_type_untyped(t)) {
 			if (ast_node_expect(node, AstNode_UnaryExpr)) {
 				ast_node(ue, UnaryExpr, node);
 				gbString str = expr_to_string(ue->expr);
@@ -2536,6 +2531,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 		// TODO(bill): This is the rule I need?
 		if (sel.indirect || operand->mode != Addressing_Value) {
 			operand->mode = Addressing_Variable;
+		} else {
+			operand->mode = Addressing_Value;
 		}
 		break;
 	case Entity_TypeName:
@@ -2645,6 +2642,31 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		operand->type = make_type_slice(c->allocator, type);
 	} break;
 
+	case BuiltinProc_free: {
+		// free :: proc(^Type)
+		// free :: proc([]Type)
+		// free :: proc(string)
+		Type *type = operand->type;
+		bool ok = false;
+		if (is_type_pointer(type)) {
+			ok = true;
+		} else if (is_type_slice(type)) {
+			ok = true;
+		} else if (is_type_string(type)) {
+			ok = true;
+		}
+
+		if (!ok) {
+			gbString type_str = type_to_string(type);
+			error_node(operand->expr, "You can only free pointers, slices, and strings, got `%s`", type_str);
+			gb_string_free(type_str);
+			return false;
+		}
+
+
+		operand->mode = Addressing_NoValue;
+	} break;
+
 	case BuiltinProc_size_of: {
 		// size_of :: proc(Type) -> untyped int
 		Type *type = check_type(c, ce->args.e[0]);

+ 5 - 3
src/checker.c

@@ -5,8 +5,8 @@ typedef enum AddressingMode {
 	Addressing_Invalid,
 
 	Addressing_NoValue,
-	Addressing_Value,    // R-value
-	Addressing_Variable, // L-value
+	Addressing_Value,
+	Addressing_Variable,
 	Addressing_Constant,
 	Addressing_Type,
 	Addressing_Builtin,
@@ -123,6 +123,7 @@ typedef enum BuiltinProcId {
 
 	BuiltinProc_new,
 	BuiltinProc_new_slice,
+	BuiltinProc_free,
 
 	BuiltinProc_size_of,
 	BuiltinProc_size_of_val,
@@ -165,7 +166,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 	{STR_LIT(""),                 0, false, Expr_Stmt},
 
 	{STR_LIT("new"),              1, false, Expr_Expr},
-	{STR_LIT("new_slice"),        2, false,  Expr_Expr},
+	{STR_LIT("new_slice"),        2, false, Expr_Expr},
+	{STR_LIT("free"),             1, false, Expr_Stmt},
 
 	{STR_LIT("size_of"),          1, false, Expr_Expr},
 	{STR_LIT("size_of_val"),      1, false, Expr_Expr},

+ 3 - 7
src/gb/gb.h

@@ -4819,14 +4819,10 @@ GB_ALLOCATOR_PROC(gb_heap_allocator_proc) {
 #else
 	// TODO(bill): *nix version that's decent
 	case gbAllocation_Alloc: {
-		gbAllocationHeader *header;
-		isize total_size = size + alignment + gb_size_of(gbAllocationHeader);
-		ptr = malloc(total_size);
-		header = cast(gbAllocationHeader *)ptr;
-		ptr = gb_align_forward(header+1, alignment);
-		gb_allocation_header_fill(header, ptr, size);
-		if (flags & gbAllocatorFlag_ClearToZero)
+		ptr = aligned_alloc(alignment, size);
+		if (flags & gbAllocatorFlag_ClearToZero) {
 			gb_zero_size(ptr, size);
+		}
 	} break;
 
 	case gbAllocation_Free: {

+ 31 - 0
src/ir.c

@@ -2909,6 +2909,37 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					return ir_emit_load(proc, slice);
 				} break;
 
+				case BuiltinProc_free: {
+					ir_emit_comment(proc, str_lit("free"));
+
+					gbAllocator allocator = proc->module->allocator;
+
+					AstNode *node = ce->args.e[0];
+					TypeAndValue tav = *type_and_value_of_expression(proc->module->info, node);
+					Type *type = base_type(tav.type);
+					irValue *val = ir_build_expr(proc, node);
+					irValue *ptr = NULL;
+					if (is_type_pointer(type)) {
+						ptr = val;
+					} else if (is_type_slice(type)) {
+						ptr = ir_slice_elem(proc, val);
+					} else if (is_type_string(type)) {
+						ptr = ir_string_elem(proc, val);
+					} else {
+						GB_PANIC("Invalid type to `free`");
+					}
+
+					if (ptr == NULL) {
+						return NULL;
+					}
+
+					ptr = ir_emit_conv(proc, ptr, t_rawptr);
+
+					irValue **args = gb_alloc_array(allocator, irValue *, 1);
+					args[0] = ptr;
+					return ir_emit_global_call(proc, "free_ptr", args, 1);
+				} break;
+
 				case BuiltinProc_assert: {
 					ir_emit_comment(proc, str_lit("assert"));
 					irValue *cond = ir_build_expr(proc, ce->args.e[0]);

+ 12 - 5
src/parser.c

@@ -149,7 +149,7 @@ AST_NODE_KIND(_ExprBegin,  "",  i32) \
 	AST_NODE_KIND(DemaybeExpr,  "demaybe expression",     struct { Token op; AstNode *expr; }) \
 	AST_NODE_KIND(SliceExpr, "slice expression", struct { \
 		AstNode *expr; \
-		Token open, close; \
+		Token open, close, interval; \
 		AstNode *low, *high; \
 	}) \
 	AST_NODE_KIND(CallExpr,     "call expression", struct { \
@@ -716,11 +716,12 @@ AstNode *make_index_expr(AstFile *f, AstNode *expr, AstNode *index, Token open,
 }
 
 
-AstNode *make_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, AstNode *low, AstNode *high) {
+AstNode *make_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, Token interval, AstNode *low, AstNode *high) {
 	AstNode *result = make_node(f, AstNode_SliceExpr);
 	result->SliceExpr.expr = expr;
 	result->SliceExpr.open = open;
 	result->SliceExpr.close = close;
+	result->SliceExpr.interval = interval;
 	result->SliceExpr.low = low;
 	result->SliceExpr.high = high;
 	return result;
@@ -1970,19 +1971,25 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
 			if (lhs) {
 				// TODO(bill): Handle this
 			}
-			Token open, close;
+			Token open = {0}, close = {0}, interval = {0};
 			AstNode *indices[2] = {0};
 
 			f->expr_level++;
 			open = expect_token(f, Token_OpenBracket);
 
+			// if (f->curr_token.kind != Token_Ellipsis &&
+			    // f->curr_token.kind != Token_HalfOpenRange) {
 			if (f->curr_token.kind != Token_Colon) {
 				indices[0] = parse_expr(f, false);
 			}
 			bool is_index = true;
 
-			if (allow_token(f, Token_Colon)) {
+			// if (f->curr_token.kind == Token_Ellipsis ||
+			    // f->curr_token.kind == Token_HalfOpenRange) {
+			if (f->curr_token.kind == Token_Colon) {
 				is_index = false;
+				interval = f->curr_token;
+				next_token(f);
 				if (f->curr_token.kind != Token_CloseBracket &&
 				    f->curr_token.kind != Token_EOF) {
 					indices[1] = parse_expr(f, false);
@@ -1995,7 +2002,7 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
 			if (is_index) {
 				operand = make_index_expr(f, operand, indices[0], open, close);
 			} else {
-				operand = make_slice_expr(f, operand, open, close, indices[0], indices[1]);
+				operand = make_slice_expr(f, operand, open, close, interval, indices[0], indices[1]);
 			}
 		} break;
 

+ 4 - 2
src/tokenizer.c

@@ -75,7 +75,7 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
 	TOKEN_KIND(Token_Semicolon,     ";"), \
 	TOKEN_KIND(Token_Period,        "."), \
 	TOKEN_KIND(Token_Comma,         ","), \
-	TOKEN_KIND(Token_Ellipsis,      ".."), \
+	TOKEN_KIND(Token_Ellipsis,      "..."), \
 	TOKEN_KIND(Token_HalfOpenRange, "..<"), \
 TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
 \
@@ -847,10 +847,12 @@ Token tokenizer_get_token(Tokenizer *t) {
 			token.kind = Token_Period; // Default
 			if (t->curr_rune == '.') { // Could be an ellipsis
 				advance_to_next_rune(t);
-				token.kind = Token_Ellipsis;
 				if (t->curr_rune == '<') {
 					advance_to_next_rune(t);
 					token.kind = Token_HalfOpenRange;
+				} else if (t->curr_rune == '.') {
+					advance_to_next_rune(t);
+					token.kind = Token_Ellipsis;
 				}
 			}
 			break;