mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-20 21:35:19 +00:00
Remove enum for favour of Go-style enumerations
This commit is contained in:
@@ -29,8 +29,8 @@ const (
|
||||
EB;
|
||||
);
|
||||
|
||||
|
||||
proc main() {
|
||||
fmt.println(X, Y, Z);
|
||||
fmt.println(A, B, C);
|
||||
fmt.println(KB, MB, GB, TB, PB, EB);
|
||||
var x = 123;
|
||||
fmt.println(x);
|
||||
}
|
||||
|
||||
@@ -70,11 +70,6 @@ type Type_Info union {
|
||||
Struct Type_Info_Record;
|
||||
Union Type_Info_Record;
|
||||
Raw_Union Type_Info_Record;
|
||||
Enum struct #ordered {
|
||||
base ^Type_Info;
|
||||
values []i64;
|
||||
names []string;
|
||||
};
|
||||
};
|
||||
|
||||
proc type_info_base(info ^Type_Info) -> ^Type_Info {
|
||||
@@ -113,12 +108,13 @@ proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
|
||||
|
||||
|
||||
|
||||
type Allocator_Mode enum {
|
||||
ALLOC,
|
||||
FREE,
|
||||
FREE_ALL,
|
||||
RESIZE,
|
||||
}
|
||||
type Allocator_Mode int;
|
||||
const (
|
||||
ALLOCATOR_ALLOC Allocator_Mode = iota;
|
||||
ALLOCATOR_FREE;
|
||||
ALLOCATOR_FREE_ALL;
|
||||
ALLOCATOR_RESIZE;
|
||||
);
|
||||
type Allocator_Proc proc(allocator_data rawptr, mode Allocator_Mode,
|
||||
size, alignment int,
|
||||
old_memory rawptr, old_size int, flags u64) -> rawptr;
|
||||
@@ -162,20 +158,20 @@ proc alloc(size int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNM
|
||||
proc alloc_align(size, alignment int) -> rawptr #inline {
|
||||
__check_context();
|
||||
var a = context.allocator;
|
||||
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
|
||||
return a.procedure(a.data, ALLOCATOR_ALLOC, size, alignment, nil, 0, 0);
|
||||
}
|
||||
|
||||
proc free(ptr rawptr) #inline {
|
||||
__check_context();
|
||||
var a = context.allocator;
|
||||
if ptr != nil {
|
||||
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
|
||||
a.procedure(a.data, ALLOCATOR_FREE, 0, 0, ptr, 0, 0);
|
||||
}
|
||||
}
|
||||
proc free_all() #inline {
|
||||
__check_context();
|
||||
var a = context.allocator;
|
||||
a.procedure(a.data, Allocator_Mode.FREE_ALL, 0, 0, nil, 0, 0);
|
||||
a.procedure(a.data, ALLOCATOR_FREE_ALL, 0, 0, nil, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +179,7 @@ proc resize (ptr rawptr, old_size, new_size int) -> rawptr #inline { return
|
||||
proc resize_align(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inline {
|
||||
__check_context();
|
||||
var a = context.allocator;
|
||||
return a.procedure(a.data, Allocator_Mode.RESIZE, new_size, alignment, ptr, old_size, 0);
|
||||
return a.procedure(a.data, ALLOCATOR_RESIZE, new_size, alignment, ptr, old_size, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -216,10 +212,9 @@ proc default_resize_align(old_memory rawptr, old_size, new_size, alignment int)
|
||||
proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
||||
size, alignment int,
|
||||
old_memory rawptr, old_size int, flags u64) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
when false {
|
||||
match mode {
|
||||
case ALLOC:
|
||||
case ALLOCATOR_ALLOC:
|
||||
var total_size = size + alignment + size_of(mem.AllocationHeader);
|
||||
var ptr = os.heap_alloc(total_size);
|
||||
var header = ptr as ^mem.AllocationHeader;
|
||||
@@ -227,14 +222,14 @@ proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
||||
mem.allocation_header_fill(header, ptr, size);
|
||||
return mem.zero(ptr, size);
|
||||
|
||||
case FREE:
|
||||
case ALLOCATOR_FREE:
|
||||
os.heap_free(mem.allocation_header(old_memory));
|
||||
return nil;
|
||||
|
||||
case FREE_ALL:
|
||||
case ALLOCATOR_FREE_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
|
||||
case RESIZE:
|
||||
case ALLOCATOR_RESIZE:
|
||||
var total_size = size + alignment + size_of(mem.AllocationHeader);
|
||||
var ptr = os.heap_resize(mem.allocation_header(old_memory), total_size);
|
||||
var header = ptr as ^mem.AllocationHeader;
|
||||
@@ -244,17 +239,17 @@ proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
||||
}
|
||||
} else {
|
||||
match mode {
|
||||
case ALLOC:
|
||||
case ALLOCATOR_ALLOC:
|
||||
return os.heap_alloc(size);
|
||||
|
||||
case FREE:
|
||||
case ALLOCATOR_FREE:
|
||||
os.heap_free(old_memory);
|
||||
return nil;
|
||||
|
||||
case FREE_ALL:
|
||||
case ALLOCATOR_FREE_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
|
||||
case RESIZE:
|
||||
case ALLOCATOR_RESIZE:
|
||||
return os.heap_resize(old_memory, size);
|
||||
}
|
||||
}
|
||||
@@ -332,17 +327,4 @@ proc __substring_expr_error(file string, line, column int, low, high int) {
|
||||
__debug_trap();
|
||||
}
|
||||
|
||||
proc __enum_to_string(info ^Type_Info, value i64) -> string {
|
||||
match type ti : type_info_base(info) {
|
||||
case Type_Info.Enum:
|
||||
// TODO(bill): Search faster than linearly
|
||||
for var i = 0; i < ti.values.count; i++ {
|
||||
if ti.values[i] == value {
|
||||
return ti.names[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -290,11 +290,6 @@ proc bprint_type(buf ^[]byte, ti ^Type_Info) {
|
||||
bprint_type(buf, info.fields[i].type_info);
|
||||
}
|
||||
bprint_string(buf, "}");
|
||||
|
||||
case Enum:
|
||||
bprint_string(buf, "enum ");
|
||||
bprint_type(buf, info.base);
|
||||
bprint_string(buf, "{}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,21 +387,6 @@ proc bprint_any(buf ^[]byte, arg any) {
|
||||
bprint_string(buf, "nil");
|
||||
}
|
||||
|
||||
case Enum:
|
||||
var value i64 = 0;
|
||||
|
||||
match type i : make_any(info.base, arg.data) {
|
||||
case i8: value = i as i64;
|
||||
case i16: value = i as i64;
|
||||
case i32: value = i as i64;
|
||||
case i64: value = i as i64;
|
||||
case u8: value = i as i64;
|
||||
case u16: value = i as i64;
|
||||
case u32: value = i as i64;
|
||||
case u64: value = i as i64;
|
||||
}
|
||||
bprint_string(buf, __enum_to_string(arg.type_info, value));
|
||||
|
||||
case Array:
|
||||
bprintf(buf, "[%]%{", info.count, info.elem);
|
||||
defer bprint_string(buf, "}");
|
||||
|
||||
@@ -162,9 +162,8 @@ proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
||||
old_memory rawptr, old_size int, flags u64) -> rawptr {
|
||||
var arena = allocator_data as ^Arena;
|
||||
|
||||
using Allocator_Mode;
|
||||
match mode {
|
||||
case ALLOC:
|
||||
case ALLOCATOR_ALLOC:
|
||||
var total_size = size + alignment;
|
||||
|
||||
if arena.memory.count + total_size > arena.memory.capacity {
|
||||
@@ -178,14 +177,14 @@ proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
||||
arena.memory.count += total_size;
|
||||
return zero(ptr, size);
|
||||
|
||||
case FREE:
|
||||
case ALLOCATOR_FREE:
|
||||
// NOTE(bill): Free all at once
|
||||
// Use Arena_Temp_Memory if you want to free a block
|
||||
|
||||
case FREE_ALL:
|
||||
case ALLOCATOR_FREE_ALL:
|
||||
arena.memory.count = 0;
|
||||
|
||||
case RESIZE:
|
||||
case ALLOCATOR_RESIZE:
|
||||
return default_resize_align(old_memory, old_size, size, alignment);
|
||||
}
|
||||
|
||||
@@ -263,8 +262,6 @@ proc align_of_type_info(type_info ^Type_Info) -> int {
|
||||
return info.align;
|
||||
case Raw_Union:
|
||||
return info.align;
|
||||
case Enum:
|
||||
return align_of_type_info(info.base);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -339,8 +336,6 @@ proc size_of_type_info(type_info ^Type_Info) -> int {
|
||||
return info.size;
|
||||
case Raw_Union:
|
||||
return info.size;
|
||||
case Enum:
|
||||
return size_of_type_info(info.base);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -83,23 +83,24 @@ proc last_write_time_by_name(name string) -> File_Time {
|
||||
|
||||
|
||||
|
||||
const (
|
||||
FILE_STANDARD_INPUT = iota;
|
||||
FILE_STANDARD_OUTPUT;
|
||||
FILE_STANDARD_ERROR;
|
||||
|
||||
type File_Standard enum {
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
ERROR,
|
||||
}
|
||||
FILE_STANDARD_COUNT;
|
||||
);
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
var __std_files = [File_Standard.count]File{
|
||||
var __std_files = [FILE_STANDARD_COUNT]File{
|
||||
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE) transmute File_Handle },
|
||||
{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) transmute File_Handle },
|
||||
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE) transmute File_Handle },
|
||||
};
|
||||
|
||||
var stdin = ^__std_files[File_Standard.INPUT];
|
||||
var stdout = ^__std_files[File_Standard.OUTPUT];
|
||||
var stderr = ^__std_files[File_Standard.ERROR];
|
||||
var stdin = ^__std_files[FILE_STANDARD_INPUT];
|
||||
var stdout = ^__std_files[FILE_STANDARD_OUTPUT];
|
||||
var stderr = ^__std_files[FILE_STANDARD_ERROR];
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -369,157 +369,158 @@ proc is_key_down(key Key_Code) -> bool {
|
||||
return GetAsyncKeyState(key as i32) < 0;
|
||||
}
|
||||
|
||||
type Key_Code enum i32 {
|
||||
LBUTTON = 0x01,
|
||||
RBUTTON = 0x02,
|
||||
CANCEL = 0x03,
|
||||
MBUTTON = 0x04,
|
||||
type Key_Code i32;
|
||||
const (
|
||||
KEY_LBUTTON Key_Code = 0x01;
|
||||
KEY_RBUTTON = 0x02;
|
||||
KEY_CANCEL = 0x03;
|
||||
KEY_MBUTTON = 0x04;
|
||||
|
||||
BACK = 0x08,
|
||||
TAB = 0x09,
|
||||
KEY_BACK = 0x08;
|
||||
KEY_TAB = 0x09;
|
||||
|
||||
CLEAR = 0x0C,
|
||||
RETURN = 0x0D,
|
||||
KEY_CLEAR = 0x0C;
|
||||
KEY_RETURN = 0x0D;
|
||||
|
||||
SHIFT = 0x10,
|
||||
CONTROL = 0x11,
|
||||
MENU = 0x12,
|
||||
PAUSE = 0x13,
|
||||
CAPITAL = 0x14,
|
||||
KEY_SHIFT = 0x10;
|
||||
KEY_CONTROL = 0x11;
|
||||
KEY_MENU = 0x12;
|
||||
KEY_PAUSE = 0x13;
|
||||
KEY_CAPITAL = 0x14;
|
||||
|
||||
KANA = 0x15,
|
||||
HANGEUL = 0x15,
|
||||
HANGUL = 0x15,
|
||||
JUNJA = 0x17,
|
||||
FINAL = 0x18,
|
||||
HANJA = 0x19,
|
||||
KANJI = 0x19,
|
||||
KEY_KANA = 0x15;
|
||||
KEY_HANGEUL = 0x15;
|
||||
KEY_HANGUL = 0x15;
|
||||
KEY_JUNJA = 0x17;
|
||||
KEY_FINAL = 0x18;
|
||||
KEY_HANJA = 0x19;
|
||||
KEY_KANJI = 0x19;
|
||||
|
||||
ESCAPE = 0x1B,
|
||||
KEY_ESCAPE = 0x1B;
|
||||
|
||||
CONVERT = 0x1C,
|
||||
NONCONVERT = 0x1D,
|
||||
ACCEPT = 0x1E,
|
||||
MODECHANGE = 0x1F,
|
||||
KEY_CONVERT = 0x1C;
|
||||
KEY_NONCONVERT = 0x1D;
|
||||
KEY_ACCEPT = 0x1E;
|
||||
KEY_MODECHANGE = 0x1F;
|
||||
|
||||
SPACE = 0x20,
|
||||
PRIOR = 0x21,
|
||||
NEXT = 0x22,
|
||||
END = 0x23,
|
||||
HOME = 0x24,
|
||||
LEFT = 0x25,
|
||||
UP = 0x26,
|
||||
RIGHT = 0x27,
|
||||
DOWN = 0x28,
|
||||
SELECT = 0x29,
|
||||
PRINT = 0x2A,
|
||||
EXECUTE = 0x2B,
|
||||
SNAPSHOT = 0x2C,
|
||||
INSERT = 0x2D,
|
||||
DELETE = 0x2E,
|
||||
HELP = 0x2F,
|
||||
KEY_SPACE = 0x20;
|
||||
KEY_PRIOR = 0x21;
|
||||
KEY_NEXT = 0x22;
|
||||
KEY_END = 0x23;
|
||||
KEY_HOME = 0x24;
|
||||
KEY_LEFT = 0x25;
|
||||
KEY_UP = 0x26;
|
||||
KEY_RIGHT = 0x27;
|
||||
KEY_DOWN = 0x28;
|
||||
KEY_SELECT = 0x29;
|
||||
KEY_PRINT = 0x2A;
|
||||
KEY_EXECUTE = 0x2B;
|
||||
KEY_SNAPSHOT = 0x2C;
|
||||
KEY_INSERT = 0x2D;
|
||||
KEY_DELETE = 0x2E;
|
||||
KEY_HELP = 0x2F;
|
||||
|
||||
NUM0 = '0',
|
||||
NUM1 = '1',
|
||||
NUM2 = '2',
|
||||
NUM3 = '3',
|
||||
NUM4 = '4',
|
||||
NUM5 = '5',
|
||||
NUM6 = '6',
|
||||
NUM7 = '7',
|
||||
NUM8 = '8',
|
||||
NUM9 = '9',
|
||||
KEY_NUM0 = '0';
|
||||
KEY_NUM1 = '1';
|
||||
KEY_NUM2 = '2';
|
||||
KEY_NUM3 = '3';
|
||||
KEY_NUM4 = '4';
|
||||
KEY_NUM5 = '5';
|
||||
KEY_NUM6 = '6';
|
||||
KEY_NUM7 = '7';
|
||||
KEY_NUM8 = '8';
|
||||
KEY_NUM9 = '9';
|
||||
|
||||
A = 'A',
|
||||
B = 'B',
|
||||
C = 'C',
|
||||
D = 'D',
|
||||
E = 'E',
|
||||
F = 'F',
|
||||
G = 'G',
|
||||
H = 'H',
|
||||
I = 'I',
|
||||
J = 'J',
|
||||
K = 'K',
|
||||
L = 'L',
|
||||
M = 'M',
|
||||
N = 'N',
|
||||
O = 'O',
|
||||
P = 'P',
|
||||
Q = 'Q',
|
||||
R = 'R',
|
||||
S = 'S',
|
||||
T = 'T',
|
||||
U = 'U',
|
||||
V = 'V',
|
||||
W = 'W',
|
||||
X = 'X',
|
||||
Y = 'Y',
|
||||
Z = 'Z',
|
||||
KEY_A = 'A';
|
||||
KEY_B = 'B';
|
||||
KEY_C = 'C';
|
||||
KEY_D = 'D';
|
||||
KEY_E = 'E';
|
||||
KEY_F = 'F';
|
||||
KEY_G = 'G';
|
||||
KEY_H = 'H';
|
||||
KEY_I = 'I';
|
||||
KEY_J = 'J';
|
||||
KEY_K = 'K';
|
||||
KEY_L = 'L';
|
||||
KEY_M = 'M';
|
||||
KEY_N = 'N';
|
||||
KEY_O = 'O';
|
||||
KEY_P = 'P';
|
||||
KEY_Q = 'Q';
|
||||
KEY_R = 'R';
|
||||
KEY_S = 'S';
|
||||
KEY_T = 'T';
|
||||
KEY_U = 'U';
|
||||
KEY_V = 'V';
|
||||
KEY_W = 'W';
|
||||
KEY_X = 'X';
|
||||
KEY_Y = 'Y';
|
||||
KEY_Z = 'Z';
|
||||
|
||||
LWIN = 0x5B,
|
||||
RWIN = 0x5C,
|
||||
APPS = 0x5D,
|
||||
KEY_LWIN = 0x5B;
|
||||
KEY_RWIN = 0x5C;
|
||||
KEY_APPS = 0x5D;
|
||||
|
||||
NUMPAD0 = 0x60,
|
||||
NUMPAD1 = 0x61,
|
||||
NUMPAD2 = 0x62,
|
||||
NUMPAD3 = 0x63,
|
||||
NUMPAD4 = 0x64,
|
||||
NUMPAD5 = 0x65,
|
||||
NUMPAD6 = 0x66,
|
||||
NUMPAD7 = 0x67,
|
||||
NUMPAD8 = 0x68,
|
||||
NUMPAD9 = 0x69,
|
||||
MULTIPLY = 0x6A,
|
||||
ADD = 0x6B,
|
||||
SEPARATOR = 0x6C,
|
||||
SUBTRACT = 0x6D,
|
||||
DECIMAL = 0x6E,
|
||||
DIVIDE = 0x6F,
|
||||
F1 = 0x70,
|
||||
F2 = 0x71,
|
||||
F3 = 0x72,
|
||||
F4 = 0x73,
|
||||
F5 = 0x74,
|
||||
F6 = 0x75,
|
||||
F7 = 0x76,
|
||||
F8 = 0x77,
|
||||
F9 = 0x78,
|
||||
F10 = 0x79,
|
||||
F11 = 0x7A,
|
||||
F12 = 0x7B,
|
||||
F13 = 0x7C,
|
||||
F14 = 0x7D,
|
||||
F15 = 0x7E,
|
||||
F16 = 0x7F,
|
||||
F17 = 0x80,
|
||||
F18 = 0x81,
|
||||
F19 = 0x82,
|
||||
F20 = 0x83,
|
||||
F21 = 0x84,
|
||||
F22 = 0x85,
|
||||
F23 = 0x86,
|
||||
F24 = 0x87,
|
||||
KEY_NUMPAD0 = 0x60;
|
||||
KEY_NUMPAD1 = 0x61;
|
||||
KEY_NUMPAD2 = 0x62;
|
||||
KEY_NUMPAD3 = 0x63;
|
||||
KEY_NUMPAD4 = 0x64;
|
||||
KEY_NUMPAD5 = 0x65;
|
||||
KEY_NUMPAD6 = 0x66;
|
||||
KEY_NUMPAD7 = 0x67;
|
||||
KEY_NUMPAD8 = 0x68;
|
||||
KEY_NUMPAD9 = 0x69;
|
||||
KEY_MULTIPLY = 0x6A;
|
||||
KEY_ADD = 0x6B;
|
||||
KEY_SEPARATOR = 0x6C;
|
||||
KEY_SUBTRACT = 0x6D;
|
||||
KEY_DECIMAL = 0x6E;
|
||||
KEY_DIVIDE = 0x6F;
|
||||
KEY_F1 = 0x70;
|
||||
KEY_F2 = 0x71;
|
||||
KEY_F3 = 0x72;
|
||||
KEY_F4 = 0x73;
|
||||
KEY_F5 = 0x74;
|
||||
KEY_F6 = 0x75;
|
||||
KEY_F7 = 0x76;
|
||||
KEY_F8 = 0x77;
|
||||
KEY_F9 = 0x78;
|
||||
KEY_F10 = 0x79;
|
||||
KEY_F11 = 0x7A;
|
||||
KEY_F12 = 0x7B;
|
||||
KEY_F13 = 0x7C;
|
||||
KEY_F14 = 0x7D;
|
||||
KEY_F15 = 0x7E;
|
||||
KEY_F16 = 0x7F;
|
||||
KEY_F17 = 0x80;
|
||||
KEY_F18 = 0x81;
|
||||
KEY_F19 = 0x82;
|
||||
KEY_F20 = 0x83;
|
||||
KEY_F21 = 0x84;
|
||||
KEY_F22 = 0x85;
|
||||
KEY_F23 = 0x86;
|
||||
KEY_F24 = 0x87;
|
||||
|
||||
NUMLOCK = 0x90,
|
||||
SCROLL = 0x91,
|
||||
KEY_NUMLOCK = 0x90;
|
||||
KEY_SCROLL = 0x91;
|
||||
|
||||
LSHIFT = 0xA0,
|
||||
RSHIFT = 0xA1,
|
||||
LCONTROL = 0xA2,
|
||||
RCONTROL = 0xA3,
|
||||
LMENU = 0xA4,
|
||||
RMENU = 0xA5,
|
||||
PROCESSKEY = 0xE5,
|
||||
ATTN = 0xF6,
|
||||
CRSEL = 0xF7,
|
||||
EXSEL = 0xF8,
|
||||
EREOF = 0xF9,
|
||||
PLAY = 0xFA,
|
||||
ZOOM = 0xFB,
|
||||
NONAME = 0xFC,
|
||||
PA1 = 0xFD,
|
||||
OEM_CLEAR = 0xFE,
|
||||
}
|
||||
KEY_LSHIFT = 0xA0;
|
||||
KEY_RSHIFT = 0xA1;
|
||||
KEY_LCONTROL = 0xA2;
|
||||
KEY_RCONTROL = 0xA3;
|
||||
KEY_LMENU = 0xA4;
|
||||
KEY_RMENU = 0xA5;
|
||||
KEY_PROCESSKEY = 0xE5;
|
||||
KEY_ATTN = 0xF6;
|
||||
KEY_CRSEL = 0xF7;
|
||||
KEY_EXSEL = 0xF8;
|
||||
KEY_EREOF = 0xF9;
|
||||
KEY_PLAY = 0xFA;
|
||||
KEY_ZOOM = 0xFB;
|
||||
KEY_NONAME = 0xFC;
|
||||
KEY_PA1 = 0xFD;
|
||||
KEY_OEM_CLEAR = 0xFE;
|
||||
);
|
||||
|
||||
|
||||
@@ -127,8 +127,6 @@ typedef enum BuiltinProcId {
|
||||
BuiltinProc_abs,
|
||||
BuiltinProc_clamp,
|
||||
|
||||
BuiltinProc_enum_to_string,
|
||||
|
||||
BuiltinProc_Count,
|
||||
} BuiltinProcId;
|
||||
typedef struct BuiltinProc {
|
||||
@@ -171,8 +169,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
{STR_LIT("max"), 2, false, Expr_Expr},
|
||||
{STR_LIT("abs"), 1, false, Expr_Expr},
|
||||
{STR_LIT("clamp"), 3, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("enum_to_string"), 1, false, Expr_Expr},
|
||||
};
|
||||
|
||||
typedef enum ImplicitValueId {
|
||||
@@ -681,7 +677,9 @@ void add_untyped(CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode m
|
||||
}
|
||||
|
||||
void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value) {
|
||||
GB_ASSERT(expression != NULL);
|
||||
if (expression == NULL) {
|
||||
return;
|
||||
}
|
||||
if (mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
@@ -864,10 +862,6 @@ void add_type_info_type(Checker *c, Type *t) {
|
||||
|
||||
case Type_Record: {
|
||||
switch (bt->Record.kind) {
|
||||
case TypeRecord_Enum:
|
||||
add_type_info_type(c, bt->Record.enum_base);
|
||||
break;
|
||||
|
||||
case TypeRecord_Union:
|
||||
add_type_info_type(c, t_int);
|
||||
/* fallthrough */
|
||||
@@ -1012,7 +1006,7 @@ void init_preload(Checker *c) {
|
||||
t_type_info_member = type_info_member_entity->type;
|
||||
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
|
||||
|
||||
if (record->field_count != 18) {
|
||||
if (record->field_count != 17) {
|
||||
compiler_error("Invalid `Type_Info` layout");
|
||||
}
|
||||
t_type_info_named = record->fields[ 1]->type;
|
||||
@@ -1031,7 +1025,6 @@ void init_preload(Checker *c) {
|
||||
t_type_info_struct = record->fields[14]->type;
|
||||
t_type_info_union = record->fields[15]->type;
|
||||
t_type_info_raw_union = record->fields[16]->type;
|
||||
t_type_info_enum = record->fields[17]->type;
|
||||
}
|
||||
|
||||
if (t_allocator == NULL) {
|
||||
@@ -1253,78 +1246,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
|
||||
DelayedDecl di = {parent_scope, decl};
|
||||
array_add(&c->delayed_foreign_libraries, di);
|
||||
case_end;
|
||||
case_ast_node(vd, VarDecl, decl);
|
||||
if (!parent_scope->is_file) {
|
||||
// NOTE(bill): Within a procedure, variables must be in order
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE(bill): You need to store the entity information here unline a constant declaration
|
||||
isize entity_count = vd->names.count;
|
||||
isize entity_index = 0;
|
||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||
DeclInfo *di = NULL;
|
||||
if (vd->values.count > 0) {
|
||||
di = make_declaration_info(heap_allocator(), parent_scope);
|
||||
di->entities = entities;
|
||||
di->entity_count = entity_count;
|
||||
di->type_expr = vd->type;
|
||||
di->init_expr = vd->values.e[0];
|
||||
}
|
||||
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names.e[i];
|
||||
AstNode *value = NULL;
|
||||
if (i < vd->values.count) {
|
||||
value = vd->values.e[i];
|
||||
}
|
||||
if (name->kind != AstNode_Ident) {
|
||||
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
|
||||
continue;
|
||||
}
|
||||
Entity *e = make_entity_variable(c->allocator, parent_scope, name->Ident, NULL);
|
||||
e->identifier = name;
|
||||
entities[entity_index++] = e;
|
||||
|
||||
DeclInfo *d = di;
|
||||
if (d == NULL) {
|
||||
AstNode *init_expr = value;
|
||||
d = make_declaration_info(heap_allocator(), e->scope);
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init_expr;
|
||||
d->var_decl_tags = vd->tags;
|
||||
}
|
||||
|
||||
add_entity_and_decl_info(c, name, e, d);
|
||||
}
|
||||
case_end;
|
||||
case_ast_node(cd, ConstDecl, decl);
|
||||
for_array(i, cd->values) {
|
||||
AstNode *name = cd->names.e[i];
|
||||
AstNode *value = unparen_expr(cd->values.e[i]);
|
||||
if (name->kind != AstNode_Ident) {
|
||||
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
|
||||
continue;
|
||||
}
|
||||
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
Entity *e = make_entity_constant(c->allocator, parent_scope, name->Ident, NULL, v);
|
||||
e->identifier = name;
|
||||
DeclInfo *di = make_declaration_info(c->allocator, e->scope);
|
||||
di->type_expr = cd->type;
|
||||
di->init_expr = value;
|
||||
add_entity_and_decl_info(c, name, e, di);
|
||||
}
|
||||
|
||||
isize lhs_count = cd->names.count;
|
||||
isize rhs_count = cd->values.count;
|
||||
|
||||
if (rhs_count == 0 && cd->type == NULL) {
|
||||
error_node(decl, "Missing type or initial expression");
|
||||
} else if (lhs_count < rhs_count) {
|
||||
error_node(decl, "Extra initial expression");
|
||||
}
|
||||
case_end;
|
||||
case_ast_node(td, TypeDecl, decl);
|
||||
if (td->name->kind != AstNode_Ident) {
|
||||
error_node(td->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[td->name->kind]));
|
||||
|
||||
@@ -98,15 +98,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
|
||||
|
||||
void check_var_decl_node(Checker *c, AstNode *node) {
|
||||
ast_node(vd, VarDecl, node);
|
||||
isize entity_count = vd->names.count;
|
||||
void check_var_spec_node(Checker *c, AstNodeValueSpec *vs) {
|
||||
GB_ASSERT(vs->keyword == Token_var);
|
||||
isize entity_count = vs->names.count;
|
||||
isize entity_index = 0;
|
||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names.e[i];
|
||||
for_array(i, vs->names) {
|
||||
AstNode *name = vs->names.e[i];
|
||||
Entity *entity = NULL;
|
||||
if (name->kind == AstNode_Ident) {
|
||||
Token token = name->Ident;
|
||||
@@ -137,8 +136,8 @@ void check_var_decl_node(Checker *c, AstNode *node) {
|
||||
}
|
||||
|
||||
Type *init_type = NULL;
|
||||
if (vd->type) {
|
||||
init_type = check_type_extra(c, vd->type, NULL);
|
||||
if (vs->type) {
|
||||
init_type = check_type_extra(c, vs->type, NULL);
|
||||
if (init_type == NULL) {
|
||||
init_type = t_invalid;
|
||||
}
|
||||
@@ -157,11 +156,12 @@ void check_var_decl_node(Checker *c, AstNode *node) {
|
||||
e->type = init_type;
|
||||
}
|
||||
|
||||
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
|
||||
|
||||
for_array(i, vd->names) {
|
||||
check_init_variables(c, entities, entity_count, vs->values, str_lit("variable declaration"));
|
||||
|
||||
for_array(i, vs->names) {
|
||||
if (entities[i] != NULL) {
|
||||
add_entity(c, c->context.scope, vd->names.e[i], entities[i]);
|
||||
add_entity(c, c->context.scope, vs->names.e[i], entities[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ struct Entity {
|
||||
ExactValue value;
|
||||
} Constant;
|
||||
struct {
|
||||
b32 is_let;
|
||||
i32 field_index;
|
||||
i32 field_src_index;
|
||||
} Variable;
|
||||
|
||||
@@ -131,76 +131,6 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
case_ast_node(cd, ConstDecl, node);
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
|
||||
isize entity_count = cd->names.count;
|
||||
isize entity_index = 0;
|
||||
Entity **entities = gb_alloc_array(c->tmp_allocator, Entity *, entity_count);
|
||||
|
||||
for_array(i, cd->values) {
|
||||
AstNode *name = cd->names.e[i];
|
||||
AstNode *value = unparen_expr(cd->values.e[i]);
|
||||
if (name->kind != AstNode_Ident) {
|
||||
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
|
||||
entities[entity_index++] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v);
|
||||
e->identifier = name;
|
||||
entities[entity_index++] = e;
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = cd->type;
|
||||
d->init_expr = value;
|
||||
add_entity_and_decl_info(c, name, e, d);
|
||||
|
||||
DelayedEntity delay = {name, e, d};
|
||||
array_add(delayed_entities, delay);
|
||||
}
|
||||
|
||||
isize lhs_count = cd->names.count;
|
||||
isize rhs_count = cd->values.count;
|
||||
|
||||
// TODO(bill): Better error messages or is this good enough?
|
||||
if (rhs_count == 0 && cd->type == NULL) {
|
||||
error_node(node, "Missing type or initial expression");
|
||||
} else if (lhs_count < rhs_count) {
|
||||
error_node(node, "Extra initial expression");
|
||||
}
|
||||
|
||||
if (dof != NULL) {
|
||||
// NOTE(bill): Within a record
|
||||
for_array(i, cd->names) {
|
||||
Entity *e = entities[i];
|
||||
if (e == NULL) {
|
||||
continue;
|
||||
}
|
||||
AstNode *name = cd->names.e[i];
|
||||
if (name->kind != AstNode_Ident) {
|
||||
continue;
|
||||
}
|
||||
Token name_token = name->Ident;
|
||||
if (str_eq(name_token.string, str_lit("_"))) {
|
||||
dof->other_fields[dof->other_field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_entity_get(dof->entity_map, key) != NULL) {
|
||||
// TODO(bill): Scope checking already checks the declaration
|
||||
error(name_token, "`%.*s` is already declared in this record", LIT(name_token.string));
|
||||
} else {
|
||||
map_entity_set(dof->entity_map, key, e);
|
||||
dof->other_fields[dof->other_field_index++] = e;
|
||||
}
|
||||
add_entity(c, c->context.scope, name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
case_end;
|
||||
|
||||
#if 0
|
||||
case_ast_node(pd, ProcDecl, node);
|
||||
if (!ast_node_expect(pd->name, AstNode_Ident)) {
|
||||
@@ -362,9 +292,6 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
|
||||
}
|
||||
|
||||
if (are_types_identical(dst, src) && (!is_type_named(dst) || !is_type_named(src))) {
|
||||
if (is_type_enum(dst) && is_type_enum(src)) {
|
||||
return are_types_identical(s, type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -794,127 +721,6 @@ GB_COMPARE_PROC(cmp_enum_order) {
|
||||
return i < j ? -1 : i > j;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) {
|
||||
GB_ASSERT(node->kind == AstNode_EnumType);
|
||||
GB_ASSERT(is_type_enum(enum_type));
|
||||
ast_node(et, EnumType, node);
|
||||
|
||||
Type *base_type = t_int;
|
||||
if (et->base_type != NULL) {
|
||||
base_type = check_type(c, et->base_type);
|
||||
}
|
||||
|
||||
if (base_type == NULL || !is_type_integer(base_type)) {
|
||||
error(et->token, "Base type for enumeration must be an integer");
|
||||
return;
|
||||
} else
|
||||
if (base_type == NULL) {
|
||||
base_type = t_int;
|
||||
}
|
||||
enum_type->Record.enum_base = base_type;
|
||||
|
||||
Entity **fields = gb_alloc_array(c->allocator, Entity *, et->fields.count);
|
||||
isize field_index = 0;
|
||||
ExactValue iota = make_exact_value_integer(-1);
|
||||
i64 min_value = 0;
|
||||
i64 max_value = 0;
|
||||
|
||||
Type *constant_type = enum_type;
|
||||
if (named_type != NULL) {
|
||||
constant_type = named_type;
|
||||
}
|
||||
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
|
||||
MapEntity entity_map = {0};
|
||||
map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count));
|
||||
|
||||
Entity *blank_entity = make_entity_constant(c->allocator, c->context.scope, blank_token, constant_type, make_exact_value_integer(0));;
|
||||
|
||||
for_array(i, et->fields) {
|
||||
AstNode *field = et->fields.e[i];
|
||||
|
||||
if (!ast_node_expect(field, AstNode_FieldValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ast_node(f, FieldValue, field);
|
||||
Token name_token = f->field->Ident;
|
||||
|
||||
if (str_eq(name_token.string, str_lit("count"))) {
|
||||
error(name_token, "`count` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
} else if (str_eq(name_token.string, str_lit("min_value"))) {
|
||||
error(name_token, "`min_value` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
} else if (str_eq(name_token.string, str_lit("max_value"))) {
|
||||
error(name_token, "`max_value` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
}
|
||||
|
||||
Operand o = {0};
|
||||
if (f->value != NULL) {
|
||||
check_expr(c, &o, f->value);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
error_node(f->value, "Enumeration value must be a constant integer %d");
|
||||
o.mode = Addressing_Invalid;
|
||||
}
|
||||
if (o.mode != Addressing_Invalid) {
|
||||
check_assignment(c, &o, constant_type, str_lit("enumeration"));
|
||||
}
|
||||
if (o.mode != Addressing_Invalid) {
|
||||
iota = o.value;
|
||||
} else {
|
||||
iota = exact_binary_operator_value(Token_Add, iota, make_exact_value_integer(1));
|
||||
}
|
||||
} else {
|
||||
iota = exact_binary_operator_value(Token_Add, iota, make_exact_value_integer(1));
|
||||
}
|
||||
|
||||
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, name_token, constant_type, iota);
|
||||
if (min_value > iota.value_integer) {
|
||||
min_value = iota.value_integer;
|
||||
}
|
||||
if (max_value < iota.value_integer) {
|
||||
max_value = iota.value_integer;
|
||||
}
|
||||
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_entity_get(&entity_map, key)) {
|
||||
// TODO(bill): Scope checking already checks the declaration
|
||||
error(name_token, "`%.*s` is already declared in this enumeration", LIT(name_token.string));
|
||||
} else {
|
||||
map_entity_set(&entity_map, key, e);
|
||||
add_entity(c, c->context.scope, NULL, e);
|
||||
fields[field_index++] = e;
|
||||
}
|
||||
add_entity_use(c, f->field, e);
|
||||
}
|
||||
|
||||
GB_ASSERT(field_index <= et->fields.count);
|
||||
|
||||
gb_sort_array(fields, field_index, cmp_enum_order);
|
||||
|
||||
enum_type->Record.enum_values = fields;
|
||||
enum_type->Record.enum_value_count = field_index;
|
||||
|
||||
enum_type->Record.enum_count = make_entity_constant(c->allocator, NULL,
|
||||
make_token_ident(str_lit("count")), t_int, make_exact_value_integer(enum_type->Record.enum_value_count));
|
||||
enum_type->Record.min_value = make_entity_constant(c->allocator, NULL,
|
||||
make_token_ident(str_lit("min_value")), constant_type, make_exact_value_integer(min_value));
|
||||
enum_type->Record.max_value = make_entity_constant(c->allocator, NULL,
|
||||
make_token_ident(str_lit("max_value")), constant_type, make_exact_value_integer(max_value));
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) {
|
||||
if (params.count == 0) {
|
||||
return NULL;
|
||||
@@ -1165,6 +971,11 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
||||
Type *type = NULL;
|
||||
gbString err_str = NULL;
|
||||
|
||||
if (e == NULL) {
|
||||
type = t_invalid;
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch (e->kind) {
|
||||
case_ast_node(i, Ident, e);
|
||||
Operand o = {0};
|
||||
@@ -1291,16 +1102,6 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
||||
goto end;
|
||||
case_end;
|
||||
|
||||
case_ast_node(et, EnumType, e);
|
||||
type = make_type_enum(c->allocator);
|
||||
set_base_type(named_type, type);
|
||||
check_open_scope(c, e);
|
||||
check_enum_type(c, type, named_type, e);
|
||||
check_close_scope(c);
|
||||
type->Record.node = e;
|
||||
goto end;
|
||||
case_end;
|
||||
|
||||
case_ast_node(pt, ProcType, e);
|
||||
type = alloc_type(c->allocator, Type_Proc);
|
||||
set_base_type(named_type, type);
|
||||
@@ -1357,7 +1158,7 @@ end:
|
||||
|
||||
bool check_unary_op(Checker *c, Operand *o, Token op) {
|
||||
// TODO(bill): Handle errors correctly
|
||||
Type *type = base_type(get_enum_base_type(base_vector_type(o->type)));
|
||||
Type *type = base_type(base_vector_type(o->type));
|
||||
gbString str = NULL;
|
||||
switch (op.kind) {
|
||||
case Token_Add:
|
||||
@@ -1393,7 +1194,7 @@ bool check_unary_op(Checker *c, Operand *o, Token op) {
|
||||
|
||||
bool check_binary_op(Checker *c, Operand *o, Token op) {
|
||||
// TODO(bill): Handle errors correctly
|
||||
Type *type = base_type(get_enum_base_type(base_vector_type(o->type)));
|
||||
Type *type = base_type(base_vector_type(o->type));
|
||||
switch (op.kind) {
|
||||
case Token_Sub:
|
||||
case Token_SubEq:
|
||||
@@ -1470,8 +1271,6 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exa
|
||||
return true;
|
||||
}
|
||||
|
||||
type = get_enum_base_type(type);
|
||||
|
||||
if (is_type_boolean(type)) {
|
||||
return in_value.kind == ExactValue_Bool;
|
||||
} else if (is_type_string(type)) {
|
||||
@@ -1554,8 +1353,8 @@ void check_is_expressible(Checker *c, Operand *o, Type *type) {
|
||||
if (!check_value_is_expressible(c, o->value, type, &o->value)) {
|
||||
gbString a = expr_to_string(o->expr);
|
||||
gbString b = type_to_string(type);
|
||||
if (is_type_numeric(get_enum_base_type(o->type)) && is_type_numeric(get_enum_base_type(type))) {
|
||||
if (!is_type_integer(get_enum_base_type(o->type)) && is_type_integer(get_enum_base_type(type))) {
|
||||
if (is_type_numeric(o->type) && is_type_numeric(type)) {
|
||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||
error_node(o->expr, "`%s` truncated to `%s`", a, b);
|
||||
} else {
|
||||
error_node(o->expr, "`%s = %lld` overflows `%s`", a, o->value.value_integer, b);
|
||||
@@ -1859,8 +1658,6 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
if (are_types_identical(xb, yb)) {
|
||||
return true;
|
||||
}
|
||||
xb = get_enum_base_type(x);
|
||||
yb = get_enum_base_type(y);
|
||||
|
||||
|
||||
// Cast between booleans and integers
|
||||
@@ -2460,7 +2257,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
|
||||
return;
|
||||
}
|
||||
|
||||
Type *t = get_enum_base_type(base_type(target_type));
|
||||
Type *t = base_type(target_type);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
@@ -2531,7 +2328,7 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_type_integer(get_enum_base_type(operand.type))) {
|
||||
if (!is_type_integer(operand.type)) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error_node(operand.expr, "Index `%s` must be an integer", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
@@ -3598,44 +3395,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case BuiltinProc_enum_to_string: {
|
||||
Type *type = base_type(operand->type);
|
||||
if (!is_type_enum(type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
gb_string_free(type_str);
|
||||
error_node(call,
|
||||
"Expected an enum to `enum_to_string`, got `%s`",
|
||||
type_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
ExactValue value = make_exact_value_string(str_lit(""));
|
||||
if (operand->value.kind == ExactValue_Integer) {
|
||||
i64 index = operand->value.value_integer;
|
||||
for (isize i = 0; i < type->Record.enum_value_count; i++) {
|
||||
Entity *f = type->Record.enum_values[i];
|
||||
if (f->kind == Entity_Constant && f->Constant.value.kind == ExactValue_Integer) {
|
||||
i64 fv = f->Constant.value.value_integer;
|
||||
if (index == fv) {
|
||||
value = make_exact_value_string(f->token.string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operand->value = value;
|
||||
operand->type = t_string;
|
||||
return true;
|
||||
}
|
||||
|
||||
add_type_info_type(c, operand->type);
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = t_string;
|
||||
} break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -279,6 +279,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
c->context.stmt_state_flags = prev_stmt_state_flags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct TypeAndToken {
|
||||
Type *type;
|
||||
Token token;
|
||||
@@ -907,19 +909,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
switch (e->kind) {
|
||||
case Entity_TypeName: {
|
||||
Type *t = base_type(e->type);
|
||||
if (is_type_enum(t)) {
|
||||
for (isize i = 0; i < t->Record.enum_value_count; i++) {
|
||||
Entity *f = t->Record.enum_values[i];
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||
gb_string_free(expr_str);
|
||||
return;
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
} else if (is_type_union(t)) {
|
||||
if (is_type_union(t)) {
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Entity *f = t->Record.fields[i];
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
@@ -931,6 +921,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
} else {
|
||||
error(us->token, "`using` can be only applied to `union` type entities");
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1008,40 +1000,52 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(vd, VarDecl, us->node);
|
||||
if (vd->names.count > 1 && vd->type != NULL) {
|
||||
error(us->token, "`using` can only be applied to one variable of the same type");
|
||||
}
|
||||
check_var_decl_node(c, us->node);
|
||||
case_ast_node(gd, GenericDecl, us->node);
|
||||
for_array(spec_index, gd->specs) {
|
||||
AstNode *spec = gd->specs.e[spec_index];
|
||||
switch (spec->kind) {
|
||||
case_ast_node(vs, ValueSpec, spec);
|
||||
if (vs->keyword != Token_var) {
|
||||
error_node(spec, "`using` can only be applied to a variable declaration");
|
||||
return;
|
||||
}
|
||||
|
||||
for_array(name_index, vd->names) {
|
||||
AstNode *item = vd->names.e[name_index];
|
||||
ast_node(i, Ident, item);
|
||||
String name = i->string;
|
||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
GB_ASSERT(found != NULL);
|
||||
for_array(i, (*found)->elements.entries) {
|
||||
Entity *f = (*found)->elements.entries.e[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != NULL) {
|
||||
error(us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
return;
|
||||
if (vs->names.count > 1 && vs->type != NULL) {
|
||||
error(us->token, "`using` can only be applied to one variable of the same type");
|
||||
}
|
||||
|
||||
check_var_spec_node(c, vs);
|
||||
|
||||
for_array(name_index, vs->names) {
|
||||
AstNode *item = vs->names.e[name_index];
|
||||
ast_node(i, Ident, item);
|
||||
String name = i->string;
|
||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
GB_ASSERT(found != NULL);
|
||||
for_array(i, (*found)->elements.entries) {
|
||||
Entity *f = (*found)->elements.entries.e[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != NULL) {
|
||||
error(us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
|
||||
return;
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
|
||||
|
||||
default:
|
||||
error(us->token, "Invalid AST: Using Statement");
|
||||
break;
|
||||
@@ -1068,12 +1072,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case_ast_node(vd, VarDecl, node);
|
||||
check_var_decl_node(c, node);
|
||||
case_end;
|
||||
|
||||
case_ast_node(gd, GenericDecl, node);
|
||||
for_array(spec_index, gd->specs) {
|
||||
AstNode *spec = gd->specs.e[spec_index];
|
||||
@@ -1136,6 +1134,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
if (e->type == NULL)
|
||||
e->type = init_type;
|
||||
}
|
||||
check_arity_match(c, vs, NULL);
|
||||
|
||||
check_init_variables(c, entities, entity_count, vs->values, str_lit("variable declaration"));
|
||||
|
||||
@@ -1158,10 +1157,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(cd, ConstDecl, node);
|
||||
// NOTE(bill): Handled elsewhere
|
||||
case_end;
|
||||
|
||||
case_ast_node(td, TypeDecl, node);
|
||||
// NOTE(bill): Handled elsewhere
|
||||
case_end;
|
||||
|
||||
@@ -62,7 +62,6 @@ typedef enum TypeRecordKind {
|
||||
TypeRecord_Invalid,
|
||||
|
||||
TypeRecord_Struct,
|
||||
TypeRecord_Enum,
|
||||
TypeRecord_RawUnion,
|
||||
TypeRecord_Union, // Tagged
|
||||
|
||||
@@ -78,23 +77,11 @@ typedef struct TypeRecord {
|
||||
i32 field_count; // == offset_count is struct
|
||||
AstNode *node;
|
||||
|
||||
union { // NOTE(bill): Reduce size_of Type
|
||||
struct { // enum only
|
||||
Type * enum_base; // Default is `int`
|
||||
Entity * enum_count;
|
||||
Entity * min_value;
|
||||
Entity * max_value;
|
||||
Entity **enum_values;
|
||||
i32 enum_value_count;
|
||||
};
|
||||
struct { // struct only
|
||||
i64 * struct_offsets;
|
||||
bool struct_are_offsets_set;
|
||||
bool struct_is_packed;
|
||||
bool struct_is_ordered;
|
||||
Entity **fields_in_src_order; // Entity_Variable
|
||||
};
|
||||
};
|
||||
i64 * struct_offsets;
|
||||
bool struct_are_offsets_set;
|
||||
bool struct_is_packed;
|
||||
bool struct_is_ordered;
|
||||
Entity **fields_in_src_order; // Entity_Variable
|
||||
} TypeRecord;
|
||||
|
||||
#define TYPE_KINDS \
|
||||
@@ -282,7 +269,6 @@ gb_global Type *t_type_info_tuple = NULL;
|
||||
gb_global Type *t_type_info_struct = NULL;
|
||||
gb_global Type *t_type_info_union = NULL;
|
||||
gb_global Type *t_type_info_raw_union = NULL;
|
||||
gb_global Type *t_type_info_enum = NULL;
|
||||
|
||||
gb_global Type *t_allocator = NULL;
|
||||
gb_global Type *t_allocator_ptr = NULL;
|
||||
@@ -380,11 +366,6 @@ Type *make_type_raw_union(gbAllocator a) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_enum(gbAllocator a) {
|
||||
Type *t = alloc_type(a, Type_Record);
|
||||
t->Record.kind = TypeRecord_Enum;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -437,15 +418,6 @@ Type *type_deref(Type *t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *get_enum_base_type(Type *t) {
|
||||
Type *bt = base_type(t);
|
||||
if (bt->kind == Type_Record && bt->Record.kind == TypeRecord_Enum) {
|
||||
GB_ASSERT(bt->Record.enum_base != NULL);
|
||||
return bt->Record.enum_base;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
bool is_type_named(Type *t) {
|
||||
if (t->kind == Type_Basic) {
|
||||
return true;
|
||||
@@ -508,7 +480,7 @@ bool is_type_untyped(Type *t) {
|
||||
return false;
|
||||
}
|
||||
bool is_type_ordered(Type *t) {
|
||||
t = base_type(get_enum_base_type(t));
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Ordered) != 0;
|
||||
}
|
||||
@@ -522,9 +494,6 @@ bool is_type_constant_type(Type *t) {
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
|
||||
}
|
||||
if (t->kind == Type_Record) {
|
||||
return t->Record.kind == TypeRecord_Enum;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_float(Type *t) {
|
||||
@@ -615,10 +584,6 @@ Type *base_vector_type(Type *t) {
|
||||
}
|
||||
|
||||
|
||||
bool is_type_enum(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Enum);
|
||||
}
|
||||
bool is_type_struct(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct);
|
||||
@@ -656,20 +621,13 @@ bool type_has_nil(Type *t) {
|
||||
|
||||
case Type_Tuple:
|
||||
return false;
|
||||
|
||||
case Type_Record:
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Enum:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool is_type_comparable(Type *t) {
|
||||
t = base_type(get_enum_base_type(t));
|
||||
t = base_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
return t->kind != Basic_UntypedNil;
|
||||
@@ -682,8 +640,6 @@ bool is_type_comparable(Type *t) {
|
||||
if (!is_type_comparable(t->Record.fields[i]->type))
|
||||
return false;
|
||||
}
|
||||
} else if (is_type_enum(t)) {
|
||||
return is_type_comparable(t->Record.enum_base);
|
||||
}
|
||||
return false;
|
||||
} break;
|
||||
@@ -753,10 +709,6 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeRecord_Enum:
|
||||
// NOTE(bill): Each enum is unique
|
||||
return x == y;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -981,33 +933,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_enum(type)) {
|
||||
for (isize i = 0; i < type->Record.enum_value_count; i++) {
|
||||
Entity *f = type->Record.enum_values[i];
|
||||
GB_ASSERT(f->kind != Entity_Variable);
|
||||
String str = f->token.string;
|
||||
|
||||
if (str_eq(field_name, str)) {
|
||||
sel.entity = f;
|
||||
selection_add_index(&sel, i);
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
|
||||
if (str_eq(field_name, str_lit("count"))) {
|
||||
sel.entity = type->Record.enum_count;
|
||||
return sel;
|
||||
} else if (str_eq(field_name, str_lit("min_value"))) {
|
||||
sel.entity = type->Record.min_value;
|
||||
return sel;
|
||||
} else if (str_eq(field_name, str_lit("max_value"))) {
|
||||
sel.entity = type->Record.max_value;
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!is_type_enum(type) && !is_type_union(type)) {
|
||||
} else if (!is_type_union(type)) {
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
|
||||
@@ -1247,8 +1173,6 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
}
|
||||
return max;
|
||||
} break;
|
||||
case TypeRecord_Enum:
|
||||
return type_align_of_internal(s, allocator, t->Record.enum_base, path);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@@ -1437,10 +1361,6 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
// TODO(bill): Is this how it should work?
|
||||
return align_formula(max, align);
|
||||
} break;
|
||||
|
||||
case TypeRecord_Enum: {
|
||||
return type_size_of_internal(s, allocator, t->Record.enum_base, path);
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@@ -1591,11 +1511,6 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
}
|
||||
str = gb_string_appendc(str, "}");
|
||||
break;
|
||||
|
||||
case TypeRecord_Enum:
|
||||
str = gb_string_appendc(str, "enum ");
|
||||
str = write_type_to_string(str, type->Record.enum_base);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
51
src/parser.c
51
src/parser.c
@@ -241,21 +241,6 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
||||
u64 tags; \
|
||||
bool is_using; \
|
||||
}) \
|
||||
AST_NODE_KIND(VarDecl, "variable declaration", struct { \
|
||||
u64 tags; \
|
||||
bool is_using; \
|
||||
AstNodeArray names; \
|
||||
AstNode * type; \
|
||||
AstNodeArray values; \
|
||||
AstNode * note; \
|
||||
}) \
|
||||
AST_NODE_KIND(ConstDecl, "constant declaration", struct { \
|
||||
u64 tags; \
|
||||
AstNodeArray names; \
|
||||
AstNode * type; \
|
||||
AstNodeArray values; \
|
||||
AstNode * note; \
|
||||
}) \
|
||||
AST_NODE_KIND(TypeDecl, "type declaration", struct { \
|
||||
Token token; \
|
||||
AstNode *name; \
|
||||
@@ -480,10 +465,6 @@ Token ast_node_token(AstNode *node) {
|
||||
return node->BadDecl.begin;
|
||||
case AstNode_GenericDecl:
|
||||
return node->GenericDecl.token;
|
||||
case AstNode_VarDecl:
|
||||
return ast_node_token(node->VarDecl.names.e[0]);
|
||||
case AstNode_ConstDecl:
|
||||
return ast_node_token(node->ConstDecl.names.e[0]);
|
||||
case AstNode_ProcDecl:
|
||||
return ast_node_token(node->ProcDecl.name);
|
||||
case AstNode_TypeDecl:
|
||||
@@ -917,22 +898,6 @@ AstNode *make_bad_decl(AstFile *f, Token begin, Token end) {
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_var_decl(AstFile *f, AstNodeArray names, AstNode *type, AstNodeArray values) {
|
||||
AstNode *result = make_node(f, AstNode_VarDecl);
|
||||
result->VarDecl.names = names;
|
||||
result->VarDecl.type = type;
|
||||
result->VarDecl.values = values;
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_const_decl(AstFile *f, AstNodeArray names, AstNode *type, AstNodeArray values) {
|
||||
AstNode *result = make_node(f, AstNode_ConstDecl);
|
||||
result->ConstDecl.names = names;
|
||||
result->ConstDecl.type = type;
|
||||
result->ConstDecl.values = values;
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_parameter(AstFile *f, AstNodeArray names, AstNode *type, bool is_using) {
|
||||
AstNode *result = make_node(f, AstNode_Parameter);
|
||||
result->Parameter.names = names;
|
||||
@@ -2814,8 +2779,8 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
valid = true;
|
||||
}
|
||||
} break;
|
||||
case AstNode_VarDecl:
|
||||
valid = true;
|
||||
case AstNode_GenericDecl:
|
||||
valid = node->GenericDecl.token.kind == Token_var;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2952,9 +2917,8 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return s;
|
||||
} else if (str_eq(tag, str_lit("thread_local"))) {
|
||||
AstNode *decl = parse_simple_stmt(f);
|
||||
if (decl->kind != AstNode_VarDecl &&
|
||||
(decl->kind == AstNode_GenericDecl &&
|
||||
decl->GenericDecl.token.kind != Token_var)) {
|
||||
if (decl->kind == AstNode_GenericDecl &&
|
||||
decl->GenericDecl.token.kind != Token_var) {
|
||||
syntax_error(token, "#thread_local may only be applied to variable declarations");
|
||||
return make_bad_decl(f, token, ast_node_token(decl));
|
||||
}
|
||||
@@ -2962,11 +2926,8 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
syntax_error(token, "#thread_local is only allowed at the file scope");
|
||||
return make_bad_decl(f, token, ast_node_token(decl));
|
||||
}
|
||||
if (decl->kind == AstNode_VarDecl) {
|
||||
decl->VarDecl.tags |= VarDeclTag_thread_local;
|
||||
} else if (decl->kind == AstNode_GenericDecl) {
|
||||
decl->GenericDecl.tags |= VarDeclTag_thread_local;
|
||||
}
|
||||
GB_ASSERT(decl->kind == AstNode_GenericDecl);
|
||||
decl->GenericDecl.tags |= VarDeclTag_thread_local;
|
||||
return decl;
|
||||
} else if (str_eq(tag, str_lit("bounds_check"))) {
|
||||
s = parse_stmt(f);
|
||||
|
||||
149
src/ssa.c
149
src/ssa.c
@@ -1919,8 +1919,8 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Type *src = base_type(get_enum_base_type(src_type));
|
||||
Type *dst = base_type(get_enum_base_type(t));
|
||||
Type *src = base_type(src_type);
|
||||
Type *dst = base_type(t);
|
||||
|
||||
if (value->kind == ssaValue_Constant) {
|
||||
if (is_type_any(dst)) {
|
||||
@@ -2172,7 +2172,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
}
|
||||
|
||||
bool ssa_is_type_aggregate(Type *t) {
|
||||
t = base_type(get_enum_base_type(t));
|
||||
t = base_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
switch (t->Basic.kind) {
|
||||
@@ -3088,19 +3088,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
x = ssa_emit_select(proc, cond, max, x);
|
||||
return x;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_enum_to_string: {
|
||||
ssa_emit_comment(proc, str_lit("enum_to_string"));
|
||||
ssaValue *x = ssa_build_expr(proc, ce->args.e[0]);
|
||||
Type *t = ssa_type(x);
|
||||
ssaValue *ti = ssa_type_info(proc, t);
|
||||
|
||||
|
||||
ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 2);
|
||||
args[0] = ti;
|
||||
args[1] = ssa_emit_conv(proc, x, t_i64);
|
||||
return ssa_emit_global_call(proc, "__enum_to_string", args, 2);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3849,8 +3836,7 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
|
||||
|
||||
case_ast_node(us, UsingStmt, node);
|
||||
AstNode *decl = unparen_expr(us->node);
|
||||
if (decl->kind == AstNode_VarDecl &&
|
||||
decl->kind == AstNode_GenericDecl) {
|
||||
if (decl->kind == AstNode_GenericDecl) {
|
||||
ssa_build_stmt(proc, decl);
|
||||
}
|
||||
case_end;
|
||||
@@ -3928,61 +3914,6 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(vd, VarDecl, node);
|
||||
ssaModule *m = proc->module;
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
|
||||
|
||||
if (vd->values.count == 0) { // declared and zero-initialized
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names.e[i];
|
||||
if (!ssa_is_blank_ident(name)) {
|
||||
ssa_add_local_for_identifier(proc, name, true);
|
||||
}
|
||||
}
|
||||
} else { // Tuple(s)
|
||||
Array(ssaAddr) lvals;
|
||||
ssaValueArray inits;
|
||||
array_init_reserve(&lvals, m->tmp_allocator, vd->names.count);
|
||||
array_init_reserve(&inits, m->tmp_allocator, vd->names.count);
|
||||
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names.e[i];
|
||||
ssaAddr lval = ssa_make_addr(NULL, NULL);
|
||||
if (!ssa_is_blank_ident(name)) {
|
||||
ssa_add_local_for_identifier(proc, name, false);
|
||||
lval = ssa_build_addr(proc, name);
|
||||
}
|
||||
|
||||
array_add(&lvals, lval);
|
||||
}
|
||||
|
||||
for_array(i, vd->values) {
|
||||
ssaValue *init = ssa_build_expr(proc, vd->values.e[i]);
|
||||
Type *t = ssa_type(init);
|
||||
if (t->kind == Type_Tuple) {
|
||||
for (isize i = 0; i < t->Tuple.variable_count; i++) {
|
||||
Entity *e = t->Tuple.variables[i];
|
||||
ssaValue *v = ssa_emit_struct_ev(proc, init, i);
|
||||
array_add(&inits, v);
|
||||
}
|
||||
} else {
|
||||
array_add(&inits, init);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for_array(i, inits) {
|
||||
if (lvals.e[i].addr == NULL) {
|
||||
continue;
|
||||
}
|
||||
ssaValue *v = ssa_emit_conv(proc, inits.e[i], ssa_addr_type(lvals.e[i]));
|
||||
ssa_addr_store(proc, lvals.e[i], v);
|
||||
}
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, node);
|
||||
if (pd->body != NULL) {
|
||||
CheckerInfo *info = proc->module->info;
|
||||
@@ -5472,78 +5403,6 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
ssa_emit_store(proc, len, field_count);
|
||||
ssa_emit_store(proc, cap, field_count);
|
||||
} break;
|
||||
case TypeRecord_Enum: {
|
||||
tag = ssa_add_local_generated(proc, t_type_info_enum);
|
||||
Type *enum_base = t->Record.enum_base;
|
||||
if (enum_base == NULL) {
|
||||
enum_base = t_int;
|
||||
}
|
||||
ssaValue *base = ssa_emit_struct_ep(proc, tag, 0);
|
||||
ssa_emit_store(proc, base, ssa_get_type_info_ptr(proc, type_info_data, enum_base));
|
||||
|
||||
if (t->Record.enum_value_count > 0) {
|
||||
Entity **fields = t->Record.enum_values;
|
||||
isize count = t->Record.enum_value_count;
|
||||
ssaValue *value_array = NULL;
|
||||
ssaValue *name_array = NULL;
|
||||
|
||||
{
|
||||
Token token = {Token_Ident};
|
||||
i32 id = cast(i32)entry_index;
|
||||
char name_base[] = "__$enum_values";
|
||||
isize name_len = gb_size_of(name_base) + 10;
|
||||
token.string.text = gb_alloc_array(a, u8, name_len);
|
||||
token.string.len = gb_snprintf(cast(char *)token.string.text, name_len,
|
||||
"%s-%d", name_base, id)-1;
|
||||
Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_i64, count));
|
||||
value_array = ssa_make_value_global(a, e, NULL);
|
||||
value_array->Global.is_private = true;
|
||||
ssa_module_add_value(m, e, value_array);
|
||||
map_ssa_value_set(&m->members, hash_string(token.string), value_array);
|
||||
}
|
||||
{
|
||||
Token token = {Token_Ident};
|
||||
i32 id = cast(i32)entry_index;
|
||||
char name_base[] = "__$enum_names";
|
||||
isize name_len = gb_size_of(name_base) + 10;
|
||||
token.string.text = gb_alloc_array(a, u8, name_len);
|
||||
token.string.len = gb_snprintf(cast(char *)token.string.text, name_len,
|
||||
"%s-%d", name_base, id)-1;
|
||||
Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_string, count));
|
||||
name_array = ssa_make_value_global(a, e, NULL);
|
||||
name_array->Global.is_private = true;
|
||||
ssa_module_add_value(m, e, name_array);
|
||||
map_ssa_value_set(&m->members, hash_string(token.string), name_array);
|
||||
}
|
||||
|
||||
for (isize i = 0; i < count; i++) {
|
||||
ssaValue *value_gep = ssa_emit_array_epi(proc, value_array, i);
|
||||
ssaValue *name_gep = ssa_emit_array_epi(proc, name_array, i);
|
||||
|
||||
ssa_emit_store(proc, value_gep, ssa_make_const_i64(a, fields[i]->Constant.value.value_integer));
|
||||
ssa_emit_store(proc, name_gep, ssa_make_const_string(a, fields[i]->token.string));
|
||||
}
|
||||
|
||||
ssaValue *v_count = ssa_make_const_int(a, count);
|
||||
|
||||
|
||||
ssaValue *values = ssa_emit_struct_ep(proc, tag, 1);
|
||||
ssaValue *names = ssa_emit_struct_ep(proc, tag, 2);
|
||||
ssaValue *value_slice = ssa_add_local_generated(proc, type_deref(t_i64_slice_ptr));
|
||||
ssaValue *name_slice = ssa_add_local_generated(proc, type_deref(t_string_slice_ptr));
|
||||
|
||||
ssa_emit_store(proc, ssa_emit_struct_ep(proc, value_slice, 0), ssa_array_elem(proc, value_array));
|
||||
ssa_emit_store(proc, ssa_emit_struct_ep(proc, value_slice, 1), v_count);
|
||||
ssa_emit_store(proc, ssa_emit_struct_ep(proc, value_slice, 2), v_count);
|
||||
|
||||
ssa_emit_store(proc, ssa_emit_struct_ep(proc, name_slice, 0), ssa_array_elem(proc, name_array));
|
||||
ssa_emit_store(proc, ssa_emit_struct_ep(proc, name_slice, 1), v_count);
|
||||
ssa_emit_store(proc, ssa_emit_struct_ep(proc, name_slice, 2), v_count);
|
||||
|
||||
ssa_emit_store(proc, values, ssa_emit_load(proc, value_slice));
|
||||
ssa_emit_store(proc, names, ssa_emit_load(proc, name_slice));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
@@ -225,9 +225,6 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
|
||||
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
||||
ssa_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
|
||||
} break;
|
||||
case TypeRecord_Enum:
|
||||
ssa_print_type(f, m, t->Record.enum_base);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user