mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-04 01:34:39 +00:00
expr as type; {N}bool is still causing problems
This commit is contained in:
@@ -2,7 +2,7 @@ putchar :: proc(c: i32) -> i32 #foreign
|
||||
|
||||
print_string :: proc(s: string) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
putchar(cast(i32)s[i]);
|
||||
putchar(s[i] as i32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,15 @@ byte_reverse :: proc(b: []byte) {
|
||||
|
||||
encode_rune :: proc(r : rune) -> ([4]byte, int) {
|
||||
buf : [4]byte;
|
||||
i := cast(u32)r;
|
||||
i := r as u32;
|
||||
mask : byte : 0x3f;
|
||||
if i <= 1<<7-1 {
|
||||
buf[0] = cast(byte)r;
|
||||
buf[0] = r as byte;
|
||||
return buf, 1;
|
||||
}
|
||||
if i <= 1<<11-1 {
|
||||
buf[0] = 0xc0 | cast(byte)(r>>6);
|
||||
buf[1] = 0x80 | cast(byte)(r)&mask;
|
||||
buf[0] = (0xc0 | r>>6) as byte;
|
||||
buf[1] = (0x80 | r) as byte & mask;
|
||||
return buf, 2;
|
||||
}
|
||||
|
||||
@@ -34,22 +34,22 @@ encode_rune :: proc(r : rune) -> ([4]byte, int) {
|
||||
}
|
||||
|
||||
if i <= 1<<16-1 {
|
||||
buf[0] = 0xe0 | cast(byte)(r>>12);
|
||||
buf[1] = 0x80 | cast(byte)(r>>6)&mask;
|
||||
buf[2] = 0x80 | cast(byte)(r)&mask;
|
||||
buf[0] = (0xe0 | r>>12) as byte ;
|
||||
buf[1] = (0x80 | r>>6) as byte & mask;
|
||||
buf[2] = (0x80 | r) as byte & mask;
|
||||
return buf, 3;
|
||||
}
|
||||
|
||||
buf[0] = 0xf0 | cast(byte)(r>>18);
|
||||
buf[1] = 0x80 | cast(byte)(r>>12)&mask;
|
||||
buf[2] = 0x80 | cast(byte)(r>>6)&mask;
|
||||
buf[3] = 0x80 | cast(byte)(r)&mask;
|
||||
buf[0] = (0xf0 | r>>18) as byte;
|
||||
buf[1] = (0x80 | r>>12) as byte & mask;
|
||||
buf[2] = (0x80 | r>>6) as byte & mask;
|
||||
buf[3] = (0x80 | r) as byte & mask;
|
||||
return buf, 4;
|
||||
}
|
||||
|
||||
print_rune :: proc(r : rune) {
|
||||
buf, n := encode_rune(r);
|
||||
str := cast(string)buf[:n];
|
||||
str := buf[:n] as string;
|
||||
print_string(str);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ print_int :: proc(i : int) {
|
||||
print_int_base :: proc(i, base : int) {
|
||||
NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
|
||||
|
||||
buf: [21]byte;
|
||||
buf: [65]byte;
|
||||
len := 0;
|
||||
negative := false;
|
||||
if i < 0 {
|
||||
@@ -82,5 +82,57 @@ print_int_base :: proc(i, base : int) {
|
||||
}
|
||||
|
||||
byte_reverse(buf[:len]);
|
||||
print_string(cast(string)buf[:len]);
|
||||
print_string(buf[:len] as string);
|
||||
}
|
||||
|
||||
print_uint :: proc(i : uint) {
|
||||
print_uint_base(i, 10);
|
||||
}
|
||||
print_uint_base :: proc(i, base : uint) {
|
||||
NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
|
||||
|
||||
buf: [65]byte;
|
||||
len := 0;
|
||||
negative := false;
|
||||
if i < 0 {
|
||||
negative = true;
|
||||
i = -i;
|
||||
}
|
||||
if i == 0 {
|
||||
buf[len] = '0';
|
||||
len++;
|
||||
}
|
||||
for i > 0 {
|
||||
buf[len] = NUM_TO_CHAR_TABLE[i % base];
|
||||
len++;
|
||||
i /= base;
|
||||
}
|
||||
|
||||
if negative {
|
||||
buf[len] = '-';
|
||||
len++;
|
||||
}
|
||||
|
||||
byte_reverse(buf[:len]);
|
||||
print_string(buf[:len] as string);
|
||||
}
|
||||
|
||||
|
||||
// f64
|
||||
|
||||
|
||||
print_f64 :: proc(f : f64) {
|
||||
buf: [128]byte;
|
||||
|
||||
if f == 0 {
|
||||
value : u64;
|
||||
|
||||
} else {
|
||||
if f < 0 {
|
||||
print_rune('-');
|
||||
}
|
||||
print_rune('0');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
427
examples/main.ll
427
examples/main.ll
@@ -4,142 +4,62 @@
|
||||
|
||||
declare void @llvm.memmove.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1)
|
||||
|
||||
%main.Vec2 = type <2 x float>
|
||||
define void @exec(i64 ()* %p) {
|
||||
"entry - 0":
|
||||
%0 = alloca i64 ()*, align 8 ; p
|
||||
store i64 ()* zeroinitializer, i64 ()** %0
|
||||
store i64 ()* %p, i64 ()** %0
|
||||
%1 = load i64 ()*, i64 ()** %0
|
||||
%2 = call i64 %1()
|
||||
call void @print_int(i64 %2)
|
||||
call void @print_rune(i32 10)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @main() {
|
||||
"entry - 0":
|
||||
%0 = alloca i64, align 8 ; i
|
||||
store i64 zeroinitializer, i64* %0
|
||||
store i64 123, i64* %0
|
||||
%1 = load i64, i64* %0
|
||||
call void @print_int(i64 %1)
|
||||
call void @print_rune(i32 128149)
|
||||
call void @print_rune(i32 10)
|
||||
%2 = alloca %main.Vec2, align 2 ; v
|
||||
store %main.Vec2 zeroinitializer, %main.Vec2* %2
|
||||
%3 = alloca %main.Vec2, align 2
|
||||
store %main.Vec2 zeroinitializer, %main.Vec2* %3
|
||||
%4 = getelementptr inbounds %main.Vec2, %main.Vec2* %3, i64 0, i32 0
|
||||
store float 0x3ff0000000000000, float* %4
|
||||
%5 = getelementptr inbounds %main.Vec2, %main.Vec2* %3, i64 0, i32 1
|
||||
store float 0x4000000000000000, float* %5
|
||||
%6 = load %main.Vec2, %main.Vec2* %3
|
||||
store %main.Vec2 %6, %main.Vec2* %2
|
||||
%7 = alloca [4 x i64], align 8 ; a
|
||||
store [4 x i64] zeroinitializer, [4 x i64]* %7
|
||||
%8 = alloca [4 x i64], align 8
|
||||
store [4 x i64] zeroinitializer, [4 x i64]* %8
|
||||
%9 = load i64, i64* %0
|
||||
%10 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 0
|
||||
store i64 %9, i64* %10
|
||||
%11 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 1
|
||||
store i64 2, i64* %11
|
||||
%12 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 2
|
||||
store i64 3, i64* %12
|
||||
%13 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 3
|
||||
store i64 7, i64* %13
|
||||
%14 = load [4 x i64], [4 x i64]* %8
|
||||
store [4 x i64] %14, [4 x i64]* %7
|
||||
%15 = alloca [4 x i64], align 8 ; e
|
||||
store [4 x i64] zeroinitializer, [4 x i64]* %15
|
||||
%16 = alloca [4 x i64], align 8
|
||||
store [4 x i64] zeroinitializer, [4 x i64]* %16
|
||||
%17 = load i64, i64* %0
|
||||
%18 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 0
|
||||
store i64 %17, i64* %18
|
||||
%19 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 1
|
||||
store i64 2, i64* %19
|
||||
%20 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 2
|
||||
store i64 3, i64* %20
|
||||
%21 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 3
|
||||
store i64 7, i64* %21
|
||||
%22 = load [4 x i64], [4 x i64]* %16
|
||||
store [4 x i64] %22, [4 x i64]* %15
|
||||
%23 = alloca {i64*, i64, i64}, align 8 ; s
|
||||
store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %23
|
||||
%24 = alloca {i64*, i64, i64}, align 8
|
||||
store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %24
|
||||
%25 = alloca [4 x i64], align 8
|
||||
store [4 x i64] zeroinitializer, [4 x i64]* %25
|
||||
%26 = load i64, i64* %0
|
||||
%27 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 0
|
||||
store i64 %26, i64* %27
|
||||
%28 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 1
|
||||
store i64 2, i64* %28
|
||||
%29 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 2
|
||||
store i64 3, i64* %29
|
||||
%30 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 3
|
||||
store i64 7, i64* %30
|
||||
%31 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 0
|
||||
%32 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 0
|
||||
store i64* %31, i64** %32
|
||||
%33 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 1
|
||||
store i64 4, i64* %33
|
||||
%34 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 2
|
||||
store i64 4, i64* %34
|
||||
%35 = load {i64*, i64, i64}, {i64*, i64, i64}* %24
|
||||
store {i64*, i64, i64} %35, {i64*, i64, i64}* %23
|
||||
%36 = alloca i64, align 8 ; i
|
||||
store i64 zeroinitializer, i64* %36
|
||||
store i64 0, i64* %36
|
||||
br label %"for.loop - 2"
|
||||
|
||||
"for.body - 1":
|
||||
%37 = getelementptr inbounds [4 x i64], [4 x i64]* %7, i64 0, i64 0
|
||||
%38 = load i64, i64* %36
|
||||
%39 = getelementptr i64, i64* %37, i64 %38
|
||||
%40 = load i64, i64* %39
|
||||
call void @print_int(i64 %40)
|
||||
%41 = getelementptr inbounds [2 x i8], [2 x i8]* @.str0, i64 0, i64 0
|
||||
%42 = alloca %.string, align 8
|
||||
store %.string zeroinitializer, %.string* %42
|
||||
%43 = getelementptr inbounds %.string, %.string* %42, i64 0, i32 0
|
||||
%44 = getelementptr inbounds %.string, %.string* %42, i64 0, i32 1
|
||||
store i8* %41, i8** %43
|
||||
store i64 2, i64* %44
|
||||
%45 = load %.string, %.string* %42
|
||||
call void @print_string(%.string %45)
|
||||
br label %"for.post - 3"
|
||||
|
||||
"for.loop - 2":
|
||||
%46 = load i64, i64* %36
|
||||
%47 = icmp slt i64 %46, 4
|
||||
br i1 %47, label %"for.body - 1", label %"for.done - 4"
|
||||
|
||||
"for.post - 3":
|
||||
%48 = load i64, i64* %36
|
||||
%49 = add i64 %48, 1
|
||||
store i64 %49, i64* %36
|
||||
br label %"for.loop - 2"
|
||||
|
||||
"for.done - 4":
|
||||
call void @print_rune(i32 10)
|
||||
call void @exec(i64 ()* @main$0)
|
||||
%0 = alloca <8 x float>, align 4 ; a
|
||||
store <8 x float> zeroinitializer, <8 x float>* %0
|
||||
%1 = alloca <8 x float>, align 4 ; b
|
||||
store <8 x float> zeroinitializer, <8 x float>* %1
|
||||
%2 = alloca <8 x float>, align 4
|
||||
store <8 x float> zeroinitializer, <8 x float>* %2
|
||||
%3 = load <8 x float>, <8 x float>* %2
|
||||
%4 = insertelement <8 x float> %3, float 0x3ff0000000000000, i64 0
|
||||
%5 = insertelement <8 x float> %4, float 0x4000000000000000, i64 1
|
||||
%6 = insertelement <8 x float> %5, float 0x4008000000000000, i64 2
|
||||
%7 = insertelement <8 x float> %6, float 0x4010000000000000, i64 3
|
||||
%8 = alloca <8 x float>, align 4
|
||||
store <8 x float> zeroinitializer, <8 x float>* %8
|
||||
%9 = load <8 x float>, <8 x float>* %8
|
||||
%10 = insertelement <8 x float> %9, float 0x3ff0000000000000, i64 0
|
||||
%11 = insertelement <8 x float> %10, float 0x4000000000000000, i64 1
|
||||
%12 = insertelement <8 x float> %11, float 0x4008000000000000, i64 2
|
||||
%13 = insertelement <8 x float> %12, float 0x4010000000000000, i64 3
|
||||
store <8 x float> %7, <8 x float>* %0
|
||||
store <8 x float> %13, <8 x float>* %1
|
||||
%14 = alloca <8 x i1>, align 1 ; c
|
||||
store <8 x i1> zeroinitializer, <8 x i1>* %14
|
||||
%15 = load <8 x float>, <8 x float>* %0
|
||||
%16 = load <8 x float>, <8 x float>* %1
|
||||
%17 = fcmp oeq <8 x float> %15, %16
|
||||
store <8 x i1> %17, <8 x i1>* %14
|
||||
%18 = alloca <32 x i1>, align 1 ; x
|
||||
store <32 x i1> zeroinitializer, <32 x i1>* %18
|
||||
%19 = alloca <32 x i1>, align 1
|
||||
store <32 x i1> zeroinitializer, <32 x i1>* %19
|
||||
%20 = load <32 x i1>, <32 x i1>* %19
|
||||
%21 = insertelement <32 x i1> %20, i1 true, i64 0
|
||||
%22 = insertelement <32 x i1> %21, i1 false, i64 1
|
||||
%23 = insertelement <32 x i1> %22, i1 true, i64 2
|
||||
store <32 x i1> %23, <32 x i1>* %18
|
||||
%24 = alloca i32, align 4 ; d
|
||||
store i32 zeroinitializer, i32* %24
|
||||
%25 = alloca i32*, align 8
|
||||
store i32* zeroinitializer, i32** %25
|
||||
%26 = getelementptr inbounds <32 x i1>, <32 x i1>* %18, i64 0, i32 0
|
||||
%27 = getelementptr i1, i1* %26, i64 0
|
||||
%28 = getelementptr inbounds i1, i1* %27
|
||||
%29 = bitcast i1* %28 to i32*
|
||||
store i32* %29, i32** %25
|
||||
%30 = load i32*, i32** %25
|
||||
%31 = getelementptr i32, i32* %30
|
||||
%32 = load i32, i32* %31
|
||||
store i32 %32, i32* %24
|
||||
%33 = load i32, i32* %24
|
||||
%34 = zext i32 %33 to i64
|
||||
call void @print_int_base(i64 %34, i64 2)
|
||||
ret void
|
||||
}
|
||||
|
||||
define i64 @main$0() {
|
||||
"entry - 0":
|
||||
%0 = alloca i64, align 8 ; i
|
||||
store i64 zeroinitializer, i64* %0
|
||||
store i64 1337, i64* %0
|
||||
call void @print_rune(i32 128149)
|
||||
call void @print_rune(i32 10)
|
||||
%1 = load i64, i64* %0
|
||||
ret i64 %1
|
||||
}
|
||||
|
||||
declare i32 @putchar(i32 %c) ; foreign procedure
|
||||
|
||||
define void @print_string(%.string %s) {
|
||||
@@ -281,15 +201,15 @@ define {[4 x i8], i64} @encode_rune(i32 %r) {
|
||||
%18 = getelementptr i8, i8* %17, i64 0
|
||||
%19 = load i32, i32* %0
|
||||
%20 = lshr i32 %19, 6
|
||||
%21 = trunc i32 %20 to i8
|
||||
%22 = or i8 192, %21
|
||||
%21 = or i32 192, %20
|
||||
%22 = trunc i32 %21 to i8
|
||||
store i8 %22, i8* %18
|
||||
%23 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
|
||||
%24 = getelementptr i8, i8* %23, i64 1
|
||||
%25 = load i32, i32* %0
|
||||
%26 = trunc i32 %25 to i8
|
||||
%27 = and i8 %26, 63
|
||||
%28 = or i8 128, %27
|
||||
%26 = or i32 128, %25
|
||||
%27 = trunc i32 %26 to i8
|
||||
%28 = and i8 %27, 63
|
||||
store i8 %28, i8* %24
|
||||
%29 = alloca {[4 x i8], i64}, align 8
|
||||
store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %29
|
||||
@@ -330,23 +250,23 @@ define {[4 x i8], i64} @encode_rune(i32 %r) {
|
||||
%43 = getelementptr i8, i8* %42, i64 0
|
||||
%44 = load i32, i32* %0
|
||||
%45 = lshr i32 %44, 12
|
||||
%46 = trunc i32 %45 to i8
|
||||
%47 = or i8 224, %46
|
||||
%46 = or i32 224, %45
|
||||
%47 = trunc i32 %46 to i8
|
||||
store i8 %47, i8* %43
|
||||
%48 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
|
||||
%49 = getelementptr i8, i8* %48, i64 1
|
||||
%50 = load i32, i32* %0
|
||||
%51 = lshr i32 %50, 6
|
||||
%52 = trunc i32 %51 to i8
|
||||
%53 = and i8 %52, 63
|
||||
%54 = or i8 128, %53
|
||||
%52 = or i32 128, %51
|
||||
%53 = trunc i32 %52 to i8
|
||||
%54 = and i8 %53, 63
|
||||
store i8 %54, i8* %49
|
||||
%55 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
|
||||
%56 = getelementptr i8, i8* %55, i64 2
|
||||
%57 = load i32, i32* %0
|
||||
%58 = trunc i32 %57 to i8
|
||||
%59 = and i8 %58, 63
|
||||
%60 = or i8 128, %59
|
||||
%58 = or i32 128, %57
|
||||
%59 = trunc i32 %58 to i8
|
||||
%60 = and i8 %59, 63
|
||||
store i8 %60, i8* %56
|
||||
%61 = alloca {[4 x i8], i64}, align 8
|
||||
store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %61
|
||||
@@ -363,31 +283,31 @@ define {[4 x i8], i64} @encode_rune(i32 %r) {
|
||||
%67 = getelementptr i8, i8* %66, i64 0
|
||||
%68 = load i32, i32* %0
|
||||
%69 = lshr i32 %68, 18
|
||||
%70 = trunc i32 %69 to i8
|
||||
%71 = or i8 240, %70
|
||||
%70 = or i32 240, %69
|
||||
%71 = trunc i32 %70 to i8
|
||||
store i8 %71, i8* %67
|
||||
%72 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
|
||||
%73 = getelementptr i8, i8* %72, i64 1
|
||||
%74 = load i32, i32* %0
|
||||
%75 = lshr i32 %74, 12
|
||||
%76 = trunc i32 %75 to i8
|
||||
%77 = and i8 %76, 63
|
||||
%78 = or i8 128, %77
|
||||
%76 = or i32 128, %75
|
||||
%77 = trunc i32 %76 to i8
|
||||
%78 = and i8 %77, 63
|
||||
store i8 %78, i8* %73
|
||||
%79 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
|
||||
%80 = getelementptr i8, i8* %79, i64 2
|
||||
%81 = load i32, i32* %0
|
||||
%82 = lshr i32 %81, 6
|
||||
%83 = trunc i32 %82 to i8
|
||||
%84 = and i8 %83, 63
|
||||
%85 = or i8 128, %84
|
||||
%83 = or i32 128, %82
|
||||
%84 = trunc i32 %83 to i8
|
||||
%85 = and i8 %84, 63
|
||||
store i8 %85, i8* %80
|
||||
%86 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
|
||||
%87 = getelementptr i8, i8* %86, i64 3
|
||||
%88 = load i32, i32* %0
|
||||
%89 = trunc i32 %88 to i8
|
||||
%90 = and i8 %89, 63
|
||||
%91 = or i8 128, %90
|
||||
%89 = or i32 128, %88
|
||||
%90 = trunc i32 %89 to i8
|
||||
%91 = and i8 %90, 63
|
||||
store i8 %91, i8* %87
|
||||
%92 = alloca {[4 x i8], i64}, align 8
|
||||
store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %92
|
||||
@@ -469,8 +389,8 @@ define void @print_int_base(i64 %i, i64 %base) {
|
||||
%1 = alloca i64, align 8 ; base
|
||||
store i64 zeroinitializer, i64* %1
|
||||
store i64 %base, i64* %1
|
||||
%2 = alloca [21 x i8], align 1 ; buf
|
||||
store [21 x i8] zeroinitializer, [21 x i8]* %2
|
||||
%2 = alloca [65 x i8], align 1 ; buf
|
||||
store [65 x i8] zeroinitializer, [65 x i8]* %2
|
||||
%3 = alloca i64, align 8 ; len
|
||||
store i64 zeroinitializer, i64* %3
|
||||
store i64 0, i64* %3
|
||||
@@ -494,7 +414,7 @@ define void @print_int_base(i64 %i, i64 %base) {
|
||||
br i1 %10, label %"if.then - 3", label %"if.done - 4"
|
||||
|
||||
"if.then - 3":
|
||||
%11 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
|
||||
%11 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%12 = load i64, i64* %3
|
||||
%13 = getelementptr i8, i8* %11, i64 %12
|
||||
store i8 48, i8* %13
|
||||
@@ -507,10 +427,10 @@ define void @print_int_base(i64 %i, i64 %base) {
|
||||
br label %"for.loop - 6"
|
||||
|
||||
"for.body - 5":
|
||||
%16 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
|
||||
%16 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%17 = load i64, i64* %3
|
||||
%18 = getelementptr i8, i8* %16, i64 %17
|
||||
%19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str1, i64 0, i64 0
|
||||
%19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str0, i64 0, i64 0
|
||||
%20 = load i64, i64* %1
|
||||
%21 = load i64, i64* %0
|
||||
%22 = srem i64 %21, %20
|
||||
@@ -536,7 +456,7 @@ define void @print_int_base(i64 %i, i64 %base) {
|
||||
br i1 %32, label %"if.then - 8", label %"if.done - 9"
|
||||
|
||||
"if.then - 8":
|
||||
%33 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
|
||||
%33 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%34 = load i64, i64* %3
|
||||
%35 = getelementptr i8, i8* %33, i64 %34
|
||||
store i8 45, i8* %35
|
||||
@@ -548,8 +468,8 @@ define void @print_int_base(i64 %i, i64 %base) {
|
||||
"if.done - 9":
|
||||
%38 = load i64, i64* %3
|
||||
%39 = sub i64 %38, 0
|
||||
%40 = sub i64 21, 0
|
||||
%41 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
|
||||
%40 = sub i64 65, 0
|
||||
%41 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%42 = getelementptr i8, i8* %41, i64 0
|
||||
%43 = alloca {i8*, i64, i64}, align 8
|
||||
store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %43
|
||||
@@ -563,8 +483,8 @@ define void @print_int_base(i64 %i, i64 %base) {
|
||||
call void @byte_reverse({i8*, i64, i64} %47)
|
||||
%48 = load i64, i64* %3
|
||||
%49 = sub i64 %48, 0
|
||||
%50 = sub i64 21, 0
|
||||
%51 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
|
||||
%50 = sub i64 65, 0
|
||||
%51 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%52 = getelementptr i8, i8* %51, i64 0
|
||||
%53 = alloca {i8*, i64, i64}, align 8
|
||||
store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %53
|
||||
@@ -593,5 +513,180 @@ define void @print_int_base(i64 %i, i64 %base) {
|
||||
ret void
|
||||
}
|
||||
|
||||
@.str0 = global [2 x i8] c"\2C\20"
|
||||
define void @print_uint(i64 %i) {
|
||||
"entry - 0":
|
||||
%0 = alloca i64, align 8 ; i
|
||||
store i64 zeroinitializer, i64* %0
|
||||
store i64 %i, i64* %0
|
||||
%1 = load i64, i64* %0
|
||||
call void @print_uint_base(i64 %1, i64 10)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @print_uint_base(i64 %i, i64 %base) {
|
||||
"entry - 0":
|
||||
%0 = alloca i64, align 8 ; i
|
||||
store i64 zeroinitializer, i64* %0
|
||||
store i64 %i, i64* %0
|
||||
%1 = alloca i64, align 8 ; base
|
||||
store i64 zeroinitializer, i64* %1
|
||||
store i64 %base, i64* %1
|
||||
%2 = alloca [65 x i8], align 1 ; buf
|
||||
store [65 x i8] zeroinitializer, [65 x i8]* %2
|
||||
%3 = alloca i64, align 8 ; len
|
||||
store i64 zeroinitializer, i64* %3
|
||||
store i64 0, i64* %3
|
||||
%4 = alloca i1, align 1 ; negative
|
||||
store i1 zeroinitializer, i1* %4
|
||||
store i1 false, i1* %4
|
||||
%5 = load i64, i64* %0
|
||||
%6 = icmp ult i64 %5, 0
|
||||
br i1 %6, label %"if.then - 1", label %"if.done - 2"
|
||||
|
||||
"if.then - 1":
|
||||
store i1 true, i1* %4
|
||||
%7 = load i64, i64* %0
|
||||
%8 = sub i64 0, %7
|
||||
store i64 %8, i64* %0
|
||||
br label %"if.done - 2"
|
||||
|
||||
"if.done - 2":
|
||||
%9 = load i64, i64* %0
|
||||
%10 = icmp eq i64 %9, 0
|
||||
br i1 %10, label %"if.then - 3", label %"if.done - 4"
|
||||
|
||||
"if.then - 3":
|
||||
%11 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%12 = load i64, i64* %3
|
||||
%13 = getelementptr i8, i8* %11, i64 %12
|
||||
store i8 48, i8* %13
|
||||
%14 = load i64, i64* %3
|
||||
%15 = add i64 %14, 1
|
||||
store i64 %15, i64* %3
|
||||
br label %"if.done - 4"
|
||||
|
||||
"if.done - 4":
|
||||
br label %"for.loop - 6"
|
||||
|
||||
"for.body - 5":
|
||||
%16 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%17 = load i64, i64* %3
|
||||
%18 = getelementptr i8, i8* %16, i64 %17
|
||||
%19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str1, i64 0, i64 0
|
||||
%20 = load i64, i64* %1
|
||||
%21 = load i64, i64* %0
|
||||
%22 = urem i64 %21, %20
|
||||
%23 = getelementptr i8, i8* %19, i64 %22
|
||||
%24 = load i8, i8* %23
|
||||
store i8 %24, i8* %18
|
||||
%25 = load i64, i64* %3
|
||||
%26 = add i64 %25, 1
|
||||
store i64 %26, i64* %3
|
||||
%27 = load i64, i64* %1
|
||||
%28 = load i64, i64* %0
|
||||
%29 = udiv i64 %28, %27
|
||||
store i64 %29, i64* %0
|
||||
br label %"for.loop - 6"
|
||||
|
||||
"for.loop - 6":
|
||||
%30 = load i64, i64* %0
|
||||
%31 = icmp ugt i64 %30, 0
|
||||
br i1 %31, label %"for.body - 5", label %"for.done - 7"
|
||||
|
||||
"for.done - 7":
|
||||
%32 = load i1, i1* %4
|
||||
br i1 %32, label %"if.then - 8", label %"if.done - 9"
|
||||
|
||||
"if.then - 8":
|
||||
%33 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%34 = load i64, i64* %3
|
||||
%35 = getelementptr i8, i8* %33, i64 %34
|
||||
store i8 45, i8* %35
|
||||
%36 = load i64, i64* %3
|
||||
%37 = add i64 %36, 1
|
||||
store i64 %37, i64* %3
|
||||
br label %"if.done - 9"
|
||||
|
||||
"if.done - 9":
|
||||
%38 = load i64, i64* %3
|
||||
%39 = sub i64 %38, 0
|
||||
%40 = sub i64 65, 0
|
||||
%41 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%42 = getelementptr i8, i8* %41, i64 0
|
||||
%43 = alloca {i8*, i64, i64}, align 8
|
||||
store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %43
|
||||
%44 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %43, i64 0, i32 0
|
||||
store i8* %42, i8** %44
|
||||
%45 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %43, i64 0, i32 1
|
||||
store i64 %39, i64* %45
|
||||
%46 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %43, i64 0, i32 2
|
||||
store i64 %40, i64* %46
|
||||
%47 = load {i8*, i64, i64}, {i8*, i64, i64}* %43
|
||||
call void @byte_reverse({i8*, i64, i64} %47)
|
||||
%48 = load i64, i64* %3
|
||||
%49 = sub i64 %48, 0
|
||||
%50 = sub i64 65, 0
|
||||
%51 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
|
||||
%52 = getelementptr i8, i8* %51, i64 0
|
||||
%53 = alloca {i8*, i64, i64}, align 8
|
||||
store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %53
|
||||
%54 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %53, i64 0, i32 0
|
||||
store i8* %52, i8** %54
|
||||
%55 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %53, i64 0, i32 1
|
||||
store i64 %49, i64* %55
|
||||
%56 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %53, i64 0, i32 2
|
||||
store i64 %50, i64* %56
|
||||
%57 = load {i8*, i64, i64}, {i8*, i64, i64}* %53
|
||||
%58 = alloca {i8*, i64, i64}, align 8
|
||||
store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %58
|
||||
store {i8*, i64, i64} %57, {i8*, i64, i64}* %58
|
||||
%59 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %58, i64 0, i32 0
|
||||
%60 = load i8*, i8** %59
|
||||
%61 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %58, i64 0, i32 1
|
||||
%62 = load i64, i64* %61
|
||||
%63 = alloca %.string, align 8
|
||||
store %.string zeroinitializer, %.string* %63
|
||||
%64 = getelementptr inbounds %.string, %.string* %63, i64 0, i32 0
|
||||
%65 = getelementptr inbounds %.string, %.string* %63, i64 0, i32 1
|
||||
store i8* %60, i8** %64
|
||||
store i64 %62, i64* %65
|
||||
%66 = load %.string, %.string* %63
|
||||
call void @print_string(%.string %66)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @print_f64(double %f) {
|
||||
"entry - 0":
|
||||
%0 = alloca double, align 8 ; f
|
||||
store double zeroinitializer, double* %0
|
||||
store double %f, double* %0
|
||||
%1 = alloca [128 x i8], align 1 ; buf
|
||||
store [128 x i8] zeroinitializer, [128 x i8]* %1
|
||||
%2 = load double, double* %0
|
||||
%3 = fcmp oeq double %2, 0x0000000000000000
|
||||
br i1 %3, label %"if.then - 1", label %"if.else - 2"
|
||||
|
||||
"if.then - 1":
|
||||
%4 = alloca i64, align 8 ; value
|
||||
store i64 zeroinitializer, i64* %4
|
||||
br label %"if.done - 5"
|
||||
|
||||
"if.else - 2":
|
||||
%5 = load double, double* %0
|
||||
%6 = fcmp olt double %5, 0x0000000000000000
|
||||
br i1 %6, label %"if.then - 3", label %"if.done - 4"
|
||||
|
||||
"if.then - 3":
|
||||
call void @print_rune(i32 45)
|
||||
br label %"if.done - 4"
|
||||
|
||||
"if.done - 4":
|
||||
call void @print_rune(i32 48)
|
||||
br label %"if.done - 5"
|
||||
|
||||
"if.done - 5":
|
||||
ret void
|
||||
}
|
||||
|
||||
@.str0 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$"
|
||||
@.str1 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$"
|
||||
|
||||
@@ -2,53 +2,48 @@ import "basic"
|
||||
|
||||
TWO_HEARTS :: '💕';
|
||||
|
||||
|
||||
exec :: proc(p : proc() -> int) {
|
||||
print_int(p());
|
||||
print_rune('\n');
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
i := 123;
|
||||
print_int(i);
|
||||
print_rune(TWO_HEARTS);
|
||||
print_rune('\n');
|
||||
a, b := {8}f32{1, 2, 3, 4}, {8}f32{1, 2, 3, 4};
|
||||
c := a == b;
|
||||
x := {32}bool{true, false, true};
|
||||
d := ((^x[0]) as ^u32)^;
|
||||
print_int_base(d as int, 2);
|
||||
// print_string("\n");
|
||||
// print_int(x[0] as int);
|
||||
// print_int(x[1] as int);
|
||||
// print_int(x[2] as int);
|
||||
// print_string("\n");
|
||||
|
||||
type Vec2: {2}f32;
|
||||
// for i := 0; false && i < len(x); i++ {
|
||||
// v := x[i];
|
||||
// print_int(v);
|
||||
// print_string("\n");
|
||||
// }
|
||||
|
||||
v := Vec2{1, 2};
|
||||
a := [4] int{i, 2, 3, 7};
|
||||
e := [..]int{i, 2, 3, 7};
|
||||
s := [] int{i, 2, 3, 7};
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
print_int(a[i]);
|
||||
print_string(", ");
|
||||
}
|
||||
print_rune('\n');
|
||||
|
||||
exec(proc() -> int {
|
||||
i : int = 1337;
|
||||
print_rune('💕');
|
||||
print_rune('\n');
|
||||
return i;
|
||||
});
|
||||
// for i := 0; i < len(c); i++ {
|
||||
// if i > 0 {
|
||||
// print_string("\n");
|
||||
// }
|
||||
// print_int(a[i] as int);
|
||||
// print_string(" == ");
|
||||
// print_int(b[i] as int);
|
||||
// print_string(" => ");
|
||||
// print_int(c[i] as int);
|
||||
// }
|
||||
// print_rune('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
if false {
|
||||
print_string("Chinese - 你好世界\n");
|
||||
print_string("Dutch - Hello wereld\n");
|
||||
print_string("English - Hello world\n");
|
||||
print_string("French - Bonjour monde\n");
|
||||
print_string("German - Hallo Welt\n");
|
||||
print_string("Greek - γειά σου κόσμος\n");
|
||||
print_string("Italian - Ciao mondo\n");
|
||||
print_string("Japanese - こんにちは世界\n");
|
||||
print_string("Korean - 여보세요 세계\n");
|
||||
print_string("Portuguese - Olá mundo\n");
|
||||
print_string("Russian - Здравствулте мир\n");
|
||||
print_string("Spanish - Hola mundo\n");
|
||||
}
|
||||
"Chinese - 你好世界\n"
|
||||
"Dutch - Hello wereld\n"
|
||||
"English - Hello world\n"
|
||||
"French - Bonjour monde\n"
|
||||
"German - Hallo Welt\n"
|
||||
"Greek - γειά σου κόσμος\n"
|
||||
"Italian - Ciao mondo\n"
|
||||
"Japanese - こんにちは世界\n"
|
||||
"Korean - 여보세요 세계\n"
|
||||
"Portuguese - Olá mundo\n"
|
||||
"Russian - Здравствулте мир\n"
|
||||
"Spanish - Hola mundo\n"
|
||||
*/
|
||||
|
||||
|
||||
@@ -384,11 +384,9 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
|
||||
Type *elem = check_type(c, vt->elem);
|
||||
Type *be = get_base_type(elem);
|
||||
i64 count = check_array_count(c, vt->count);
|
||||
if (!is_type_vector(be) &&
|
||||
!(is_type_boolean(be) || is_type_numeric(be))) {
|
||||
if (!is_type_boolean(be) && !is_type_numeric(be)) {
|
||||
err_str = type_to_string(elem);
|
||||
error(&c->error_collector, ast_node_token(vt->elem), "Vector element type must be a boolean, numerical, or vector. Got `%s`", err_str);
|
||||
} else {
|
||||
error(&c->error_collector, ast_node_token(vt->elem), "Vector element type must be numerical or a boolean. Got `%s`", err_str);
|
||||
}
|
||||
type = make_type_vector(c->allocator, elem, count);
|
||||
set_base_type(named_type, type);
|
||||
@@ -433,7 +431,7 @@ end:
|
||||
|
||||
b32 check_unary_op(Checker *c, Operand *o, Token op) {
|
||||
// TODO(bill): Handle errors correctly
|
||||
Type *type = get_base_type(base_vector_type(o->type));
|
||||
Type *type = get_base_type(base_vector_type(get_base_type(o->type)));
|
||||
gbString str = NULL;
|
||||
defer (gb_string_free(str));
|
||||
switch (op.kind) {
|
||||
@@ -702,13 +700,11 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
||||
update_expr_type(c, y->expr, default_type(y->type), true);
|
||||
}
|
||||
|
||||
if (is_type_vector(x->type)) {
|
||||
Type *vec_bool = NULL;
|
||||
do {
|
||||
} while (is_type_vector(x->type->vector.elem));
|
||||
if (is_type_vector(get_base_type(y->type))) {
|
||||
x->type = make_type_vector(c->allocator, t_bool, get_base_type(y->type)->vector.count);
|
||||
} else {
|
||||
x->type = t_untyped_bool;
|
||||
}
|
||||
x->type = t_untyped_bool;
|
||||
|
||||
}
|
||||
|
||||
void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
|
||||
@@ -805,6 +801,101 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
|
||||
x->mode = Addressing_Value;
|
||||
}
|
||||
|
||||
b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
if (check_is_assignable_to(c, operand, y))
|
||||
return true;
|
||||
|
||||
Type *x = operand->type;
|
||||
Type *xb = get_base_type(x);
|
||||
Type *yb = get_base_type(y);
|
||||
if (are_types_identical(xb, yb))
|
||||
return true;
|
||||
|
||||
|
||||
// Cast between booleans and integers
|
||||
if (is_type_boolean(x) || is_type_integer(x)) {
|
||||
if (is_type_boolean(y) || is_type_integer(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast between numbers
|
||||
if (is_type_integer(x) || is_type_float(x)) {
|
||||
if (is_type_integer(y) || is_type_float(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast between pointers
|
||||
if (is_type_pointer(x)) {
|
||||
if (is_type_pointer(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// untyped integers -> pointers
|
||||
if (is_type_untyped(xb) && is_type_integer(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// (u)int <-> pointer
|
||||
if (is_type_pointer(xb) || is_type_int_or_uint(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
if (is_type_pointer(xb)) {
|
||||
if (is_type_pointer(yb) || is_type_int_or_uint(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// []byte/[]u8 <-> string
|
||||
if (is_type_u8_slice(xb) && is_type_string(yb)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_string(xb) && is_type_u8_slice(yb)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_cast_expr(Checker *c, Operand *operand, Type *type) {
|
||||
b32 is_const_expr = operand->mode == Addressing_Constant;
|
||||
b32 can_convert = false;
|
||||
|
||||
if (is_const_expr && is_type_constant_type(type)) {
|
||||
Type *t = get_base_type(type);
|
||||
if (t->kind == Type_Basic) {
|
||||
if (check_value_is_expressible(c, operand->value, t, &operand->value)) {
|
||||
can_convert = true;
|
||||
}
|
||||
}
|
||||
} else if (check_castable_to(c, operand, type)) {
|
||||
operand->mode = Addressing_Value;
|
||||
can_convert = true;
|
||||
}
|
||||
|
||||
if (!can_convert) {
|
||||
gbString expr_str = expr_to_string(operand->expr);
|
||||
gbString type_str = type_to_string(type);
|
||||
defer (gb_string_free(expr_str));
|
||||
defer (gb_string_free(type_str));
|
||||
error(&c->error_collector, ast_node_token(operand->expr), "Cannot cast `%s` to `%s`", expr_str, type_str);
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_untyped(operand->type)) {
|
||||
Type *final_type = type;
|
||||
if (is_const_expr && !is_type_constant_type(type)) {
|
||||
final_type = default_type(operand->type);
|
||||
}
|
||||
update_expr_type(c, operand->expr, final_type, true);
|
||||
}
|
||||
|
||||
operand->type = type;
|
||||
}
|
||||
|
||||
|
||||
void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
GB_ASSERT(node->kind == AstNode_BinaryExpr);
|
||||
Operand y_ = {}, *y = &y_;
|
||||
@@ -813,6 +904,15 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
|
||||
ast_node(be, BinaryExpr, node);
|
||||
|
||||
if (be->op.kind == Token_as) {
|
||||
check_expr(c, x, be->left);
|
||||
Type *cast_type = check_type(c, be->right);
|
||||
if (x->mode == Addressing_Invalid)
|
||||
return;
|
||||
check_cast_expr(c, x, cast_type);
|
||||
return;
|
||||
}
|
||||
|
||||
check_expr(c, x, be->left);
|
||||
check_expr(c, y, be->right);
|
||||
if (x->mode == Addressing_Invalid) {
|
||||
@@ -890,7 +990,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
}
|
||||
|
||||
if (x->mode == Addressing_Constant &&
|
||||
y->mode == Addressing_Constant) {
|
||||
y->mode == Addressing_Constant) {
|
||||
ExactValue a = x->value;
|
||||
ExactValue b = y->value;
|
||||
|
||||
@@ -943,7 +1043,18 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) {
|
||||
found->type = get_base_type(type);
|
||||
map_set(&c->info.untyped, key, *found);
|
||||
} else {
|
||||
ExpressionInfo old = *found;
|
||||
map_remove(&c->info.untyped, key);
|
||||
|
||||
if (old.is_lhs && !is_type_integer(type)) {
|
||||
gbString expr_str = expr_to_string(e);
|
||||
gbString type_str = type_to_string(type);
|
||||
defer (gb_string_free(expr_str));
|
||||
defer (gb_string_free(type_str));
|
||||
error(&c->error_collector, ast_node_token(e), "Shifted operand %s must be an integer, got %s", expr_str, type_str);
|
||||
return;
|
||||
}
|
||||
|
||||
add_type_and_value(&c->info, e, found->mode, type, found->value);
|
||||
}
|
||||
}
|
||||
@@ -1349,6 +1460,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
value = make_exact_value_integer(t->array.count);
|
||||
break;
|
||||
|
||||
case Type_Vector:
|
||||
mode = Addressing_Constant;
|
||||
value = make_exact_value_integer(t->vector.count);
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
mode = Addressing_Value;
|
||||
break;
|
||||
@@ -1600,85 +1716,6 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
||||
return Expression_Statement;
|
||||
}
|
||||
|
||||
b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
if (check_is_assignable_to(c, operand, y))
|
||||
return true;
|
||||
|
||||
Type *x = operand->type;
|
||||
Type *xb = get_base_type(x);
|
||||
Type *yb = get_base_type(y);
|
||||
if (are_types_identical(xb, yb))
|
||||
return true;
|
||||
|
||||
// Cast between numbers
|
||||
if (is_type_integer(x) || is_type_float(x)) {
|
||||
if (is_type_integer(y) || is_type_float(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast between pointers
|
||||
if (is_type_pointer(x)) {
|
||||
if (is_type_pointer(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// untyped integers -> pointers
|
||||
if (is_type_untyped(xb) && is_type_integer(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// (u)int <-> pointer
|
||||
if (is_type_pointer(xb) || is_type_int_or_uint(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
if (is_type_pointer(xb)) {
|
||||
if (is_type_pointer(yb) || is_type_int_or_uint(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// []byte/[]u8 <-> string
|
||||
if (is_type_u8_slice(xb) && is_type_string(yb)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_string(xb) && is_type_u8_slice(yb)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_cast_expr(Checker *c, Operand *operand, Type *type) {
|
||||
b32 is_const_expr = operand->mode == Addressing_Constant;
|
||||
b32 can_convert = false;
|
||||
|
||||
if (is_const_expr && is_type_constant_type(type)) {
|
||||
Type *t = get_base_type(type);
|
||||
if (t->kind == Type_Basic) {
|
||||
if (check_value_is_expressible(c, operand->value, t, &operand->value)) {
|
||||
can_convert = true;
|
||||
}
|
||||
}
|
||||
} else if (check_castable_to(c, operand, type)) {
|
||||
operand->mode = Addressing_Value;
|
||||
can_convert = true;
|
||||
}
|
||||
|
||||
if (!can_convert) {
|
||||
gbString expr_str = expr_to_string(operand->expr);
|
||||
gbString type_str = type_to_string(type);
|
||||
defer (gb_string_free(expr_str));
|
||||
defer (gb_string_free(type_str));
|
||||
error(&c->error_collector, ast_node_token(operand->expr), "Cannot cast `%s` to `%s`", expr_str, type_str);
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
operand->type = type;
|
||||
}
|
||||
|
||||
void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
|
||||
check_expr_base(c, o, e, t);
|
||||
check_not_tuple(c, o);
|
||||
@@ -1924,6 +1961,15 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
o->type = t->array.elem;
|
||||
break;
|
||||
|
||||
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:
|
||||
valid = true;
|
||||
o->type = t->slice.elem;
|
||||
@@ -2039,15 +2085,6 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(ce, CastExpr, node);
|
||||
Type *cast_type = check_type(c, ce->type);
|
||||
check_expr_or_type(c, o, ce->expr);
|
||||
if (o->mode != Addressing_Invalid)
|
||||
check_cast_expr(c, o, cast_type);
|
||||
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(ce, CallExpr, node);
|
||||
return check_call_expr(c, o, node);
|
||||
case_end;
|
||||
@@ -2287,13 +2324,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
str = gb_string_appendc(str, "]");
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, CastExpr, node);
|
||||
str = gb_string_appendc(str, "cast(");
|
||||
str = write_expr_to_string(str, ce->type);
|
||||
str = gb_string_appendc(str, ")");
|
||||
str = write_expr_to_string(str, ce->expr);
|
||||
case_end;
|
||||
|
||||
case_ast_node(e, Ellipsis, node);
|
||||
str = gb_string_appendc(str, "..");
|
||||
case_end;
|
||||
|
||||
@@ -39,11 +39,12 @@ enum BasicFlag : u32 {
|
||||
BasicFlag_Float = GB_BIT(3),
|
||||
BasicFlag_Pointer = GB_BIT(4),
|
||||
BasicFlag_String = GB_BIT(5),
|
||||
BasicFlag_Untyped = GB_BIT(6),
|
||||
BasicFlag_Rune = GB_BIT(6),
|
||||
BasicFlag_Untyped = GB_BIT(7),
|
||||
|
||||
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float,
|
||||
BasicFlag_Ordered = BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer,
|
||||
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer,
|
||||
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_Pointer | BasicFlag_String | BasicFlag_Rune,
|
||||
};
|
||||
|
||||
struct BasicType {
|
||||
@@ -130,10 +131,11 @@ struct Type {
|
||||
|
||||
Type *get_base_type(Type *t) {
|
||||
while (t->kind == Type_Named || t->kind == Type_Alias) {
|
||||
if (t->kind == Type_Named)
|
||||
if (t->kind == Type_Named) {
|
||||
t = t->named.base;
|
||||
else
|
||||
} else {
|
||||
t = t->alias.base;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
@@ -381,8 +383,8 @@ b32 is_type_vector(Type *t) {
|
||||
return t->kind == Type_Vector;
|
||||
}
|
||||
Type *base_vector_type(Type *t) {
|
||||
while (is_type_vector(t)) {
|
||||
t = t->vector.elem;
|
||||
if (is_type_vector(t)) {
|
||||
return t->vector.elem;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
@@ -520,7 +522,7 @@ struct BaseTypeSizes {
|
||||
// TODO(bill): Change
|
||||
gb_global i64 basic_type_sizes[] = {
|
||||
0, // Basic_Invalid
|
||||
1, // Basic_bool // TODO(bill): What size should this be? And should I have different booleans?
|
||||
1, // Basic_bool
|
||||
1, // Basic_i8
|
||||
2, // Basic_i16
|
||||
4, // Basic_i32
|
||||
@@ -531,13 +533,10 @@ gb_global i64 basic_type_sizes[] = {
|
||||
4, // Basic_u32
|
||||
8, // Basic_u64
|
||||
16, // Basic_u128
|
||||
2, // Basic_f16
|
||||
4, // Basic_f32
|
||||
8, // Basic_f64
|
||||
16, // Basic_f128
|
||||
};
|
||||
|
||||
|
||||
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
|
||||
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
|
||||
i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i64 index);
|
||||
@@ -635,11 +634,18 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
i64 count = t->vector.count;
|
||||
if (count == 0)
|
||||
return 0;
|
||||
count = next_pow2(count);
|
||||
i64 align = type_align_of(s, allocator, t->vector.elem);
|
||||
i64 size = type_size_of(s, allocator, t->vector.elem);
|
||||
i64 alignment = align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
// i64 align = type_align_of(s, allocator, t->vector.elem);
|
||||
i64 bit_size = 8*type_size_of(s, allocator, t->vector.elem);
|
||||
if (is_type_boolean(t->vector.elem)) {
|
||||
bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
||||
// Silly LLVM spec
|
||||
}
|
||||
i64 total_size_in_bits = bit_size * count;
|
||||
i64 total_size = (total_size_in_bits+7)/8;
|
||||
return total_size;
|
||||
|
||||
// i64 alignment = align_formula(size, align);
|
||||
// return alignment*(count-1) + size;
|
||||
} break;
|
||||
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ void ssa_gen_code(ssaGen *s) {
|
||||
ssa_build_proc(v, NULL);
|
||||
}
|
||||
|
||||
// m->layout = make_string("e-p:64:64:64");
|
||||
// m->layout = make_string("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
|
||||
|
||||
ssa_print_llvm_ir(&s->output_file, &s->module);
|
||||
}
|
||||
|
||||
@@ -393,10 +393,10 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
||||
|
||||
case ssaInstr_BinaryOp: {
|
||||
auto *bo = &value->instr.binary_op;
|
||||
Type *type = ssa_value_type(bo->left);
|
||||
Type *type = get_base_type(ssa_value_type(bo->left));
|
||||
Type *elem_type = type;
|
||||
while (elem_type->kind == Type_Vector) {
|
||||
elem_type = elem_type->vector.elem;
|
||||
elem_type = get_base_type(elem_type->vector.elem);
|
||||
}
|
||||
|
||||
ssa_fprintf(f, "%%%d = ", value->id);
|
||||
@@ -535,13 +535,37 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
||||
vol_str = "true";
|
||||
}
|
||||
ssa_fprintf(f, ", i32 %d, i1 %s)\n", instr->copy_memory.align, vol_str);
|
||||
} break;
|
||||
|
||||
|
||||
case ssaInstr_InsertElement: {
|
||||
auto *ie = &instr->insert_element;
|
||||
Type *vt = ssa_value_type(ie->vector);
|
||||
ssa_fprintf(f, "%%%d = insertelement ", value->id);
|
||||
|
||||
ssa_print_type(f, m->sizes, vt);
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_value(f, m, ie->vector, vt);
|
||||
ssa_fprintf(f, ", ");
|
||||
|
||||
ssa_print_type(f, m->sizes, ssa_value_type(ie->elem));
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_value(f, m, ie->elem, ssa_value_type(ie->elem));
|
||||
ssa_fprintf(f, ", ");
|
||||
|
||||
ssa_print_type(f, m->sizes, ssa_value_type(ie->index));
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_value(f, m, ie->index, ssa_value_type(ie->index));
|
||||
|
||||
ssa_fprintf(f, "\n");
|
||||
|
||||
} break;
|
||||
|
||||
default:
|
||||
|
||||
default: {
|
||||
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
||||
ssa_fprintf(f, "; <unknown instr> %d\n", instr->kind);
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,7 +637,7 @@ void ssa_print_type_name(gbFile *f, ssaModule *m, ssaValue *v) {
|
||||
|
||||
void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
||||
if (m->layout.len > 0) {
|
||||
ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout));
|
||||
ssa_fprintf(f, "target datalayout = \"%.*s\"\n", LIT(m->layout));
|
||||
}
|
||||
|
||||
ssa_print_encoded_local(f, make_string(".string"));
|
||||
|
||||
@@ -69,6 +69,9 @@ struct ssaProcedure {
|
||||
SSA_INSTR_KIND(BinaryOp), \
|
||||
SSA_INSTR_KIND(Call), \
|
||||
SSA_INSTR_KIND(CopyMemory), \
|
||||
SSA_INSTR_KIND(ExtractElement), \
|
||||
SSA_INSTR_KIND(InsertElement), \
|
||||
SSA_INSTR_KIND(ShuffleVector), \
|
||||
SSA_INSTR_KIND(Count),
|
||||
|
||||
enum ssaInstrKind {
|
||||
@@ -178,6 +181,16 @@ struct ssaInstr {
|
||||
i32 align;
|
||||
b32 is_volatile;
|
||||
} copy_memory;
|
||||
|
||||
struct {
|
||||
ssaValue *vector;
|
||||
ssaValue *index;
|
||||
} extract_element;
|
||||
struct {
|
||||
ssaValue *vector;
|
||||
ssaValue *elem;
|
||||
ssaValue *index;
|
||||
} insert_element;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -236,36 +249,16 @@ gb_global ssaValue *v_two32 = NULL;
|
||||
gb_global ssaValue *v_false = NULL;
|
||||
gb_global ssaValue *v_true = NULL;
|
||||
|
||||
enum ssaLvalueKind {
|
||||
ssaLvalue_Blank,
|
||||
ssaLvalue_Address,
|
||||
|
||||
ssaLvalue_Count,
|
||||
};
|
||||
|
||||
struct ssaLvalue {
|
||||
ssaLvalueKind kind;
|
||||
union {
|
||||
struct {} blank;
|
||||
struct {
|
||||
ssaValue *value;
|
||||
AstNode *expr;
|
||||
} address;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ssaLvalue ssa_make_lvalue_address(ssaValue *value, AstNode *expr) {
|
||||
ssaLvalue lval = {ssaLvalue_Address};
|
||||
lval.address.value = value;
|
||||
lval.address.expr = expr;
|
||||
return lval;
|
||||
ssaValue *address;
|
||||
AstNode *expr;};
|
||||
ssaLvalue ssa_make_lvalue(ssaValue *address, AstNode *expr) {
|
||||
ssaLvalue v = {address, expr};
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ssa_module_init(ssaModule *m, Checker *c) {
|
||||
isize token_count = c->parser->total_token_count;
|
||||
isize arena_size = 3 * token_count * gb_size_of(ssaValue);
|
||||
@@ -323,6 +316,13 @@ Type *ssa_instr_type(ssaInstr *instr) {
|
||||
}
|
||||
case ssaInstr_CopyMemory:
|
||||
return t_int;
|
||||
|
||||
case ssaInstr_ExtractElement: {
|
||||
Type *vt = ssa_value_type(instr->extract_element.vector);
|
||||
return base_vector_type(get_base_type(vt));
|
||||
} break;
|
||||
case ssaInstr_InsertElement:
|
||||
return ssa_value_type(instr->insert_element.vector);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -477,8 +477,8 @@ ssaValue *ssa_make_instr_load(ssaProcedure *p, ssaValue *address) {
|
||||
}
|
||||
|
||||
ssaValue *ssa_make_instr_get_element_ptr(ssaProcedure *p, ssaValue *address,
|
||||
ssaValue *index0, ssaValue *index1, isize index_count,
|
||||
b32 inbounds) {
|
||||
ssaValue *index0, ssaValue *index1, isize index_count,
|
||||
b32 inbounds) {
|
||||
ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_GetElementPtr);
|
||||
ssaInstr *i = &v->instr;
|
||||
i->get_element_ptr.address = address;
|
||||
@@ -598,6 +598,34 @@ ssaValue *ssa_make_instr_conv(ssaProcedure *p, ssaConvKind kind, ssaValue *value
|
||||
return v;
|
||||
}
|
||||
|
||||
ssaValue *ssa_make_instr_extract_element(ssaProcedure *p, ssaValue *vector, ssaValue *index) {
|
||||
ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_ExtractElement);
|
||||
v->instr.extract_element.vector = vector;
|
||||
v->instr.extract_element.index = index;
|
||||
if (p->curr_block) {
|
||||
gb_array_append(p->curr_block->values, v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
ssaValue *ssa_make_instr_insert_element(ssaProcedure *p, ssaValue *vector, ssaValue *elem, ssaValue *index) {
|
||||
ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_InsertElement);
|
||||
v->instr.insert_element.vector = vector;
|
||||
v->instr.insert_element.elem = elem;
|
||||
v->instr.insert_element.index = index;
|
||||
if (p->curr_block) {
|
||||
gb_array_append(p->curr_block->values, v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -714,36 +742,23 @@ ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) {
|
||||
|
||||
|
||||
ssaValue *ssa_lvalue_store(ssaLvalue lval, ssaProcedure *p, ssaValue *value) {
|
||||
switch (lval.kind) {
|
||||
case ssaLvalue_Address:
|
||||
return ssa_emit_store(p, lval.address.value, value);
|
||||
if (lval.address != NULL) {
|
||||
return ssa_emit_store(p, lval.address, value);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssaValue *ssa_lvalue_load(ssaLvalue lval, ssaProcedure *p) {
|
||||
switch (lval.kind) {
|
||||
case ssaLvalue_Address:
|
||||
return ssa_emit_load(p, lval.address.value);
|
||||
if (lval.address != NULL) {
|
||||
return ssa_emit_load(p, lval.address);
|
||||
}
|
||||
GB_PANIC("Illegal lvalue load");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ssaValue *ssa_lvalue_address(ssaLvalue lval, ssaProcedure *p) {
|
||||
switch (lval.kind) {
|
||||
case ssaLvalue_Address:
|
||||
return lval.address.value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Type *ssa_lvalue_type(ssaLvalue lval) {
|
||||
switch (lval.kind) {
|
||||
case ssaLvalue_Address:
|
||||
// return type_deref(ssa_value_type(lval.address.value));
|
||||
return ssa_value_type(lval.address.value);
|
||||
if (lval.address != NULL) {
|
||||
return type_deref(ssa_value_type(lval.address));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -921,7 +936,11 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *
|
||||
}
|
||||
|
||||
ssaValue *v = ssa_make_instr_binary_op(proc, op, left, right);
|
||||
ssa_value_set_type(v, t_bool);
|
||||
Type *result = t_bool;
|
||||
if (is_type_vector(a)) {
|
||||
result = make_type_vector(proc->module->allocator, t_bool, a->vector.count);
|
||||
}
|
||||
ssa_value_set_type(v, result);
|
||||
return ssa_emit(proc, v);
|
||||
}
|
||||
|
||||
@@ -935,6 +954,15 @@ ssaValue *ssa_emit_ptr_offset(ssaProcedure *proc, ssaValue *ptr, ssaValue *offse
|
||||
return ssa_emit(proc, gep);
|
||||
}
|
||||
|
||||
ssaValue *ssa_emit_zero_gep(ssaProcedure *proc, ssaValue *s) {
|
||||
ssaValue *gep = NULL;
|
||||
// NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32
|
||||
gep = ssa_make_instr_get_element_ptr(proc, s, NULL, NULL, 0, true);
|
||||
gep->instr.get_element_ptr.elem_type = ssa_value_type(s);
|
||||
gep->instr.get_element_ptr.result_type = ssa_value_type(s);
|
||||
return ssa_emit(proc, gep);
|
||||
}
|
||||
|
||||
ssaValue *ssa_emit_struct_gep(ssaProcedure *proc, ssaValue *s, ssaValue *index, Type *result_type) {
|
||||
ssaValue *gep = NULL;
|
||||
// NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32
|
||||
@@ -1139,14 +1167,17 @@ ssaValue *ssa_emit_string(ssaProcedure *proc, ssaValue *elem, ssaValue *len) {
|
||||
|
||||
ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
Type *src_type = ssa_value_type(value);
|
||||
if (are_types_identical(t, src_type))
|
||||
if (are_types_identical(t, src_type)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Type *src = get_base_type(src_type);
|
||||
Type *dst = get_base_type(t);
|
||||
if (are_types_identical(t, src_type))
|
||||
return value;
|
||||
|
||||
|
||||
|
||||
if (value->kind == ssaValue_Constant) {
|
||||
if (dst->kind == Type_Basic) {
|
||||
ExactValue ev = value->constant.value;
|
||||
@@ -1163,21 +1194,34 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
|
||||
// integer -> integer
|
||||
if (is_type_integer(src) && is_type_integer(dst)) {
|
||||
i64 sz = basic_type_sizes[src->basic.kind];
|
||||
i64 dz = basic_type_sizes[dst->basic.kind];
|
||||
ssaConvKind kind = ssaConv_trunc;
|
||||
if (dz >= sz) {
|
||||
kind = ssaConv_zext;
|
||||
}
|
||||
|
||||
GB_ASSERT(src->kind == Type_Basic &&
|
||||
dst->kind == Type_Basic);
|
||||
i64 sz = type_size_of(proc->module->sizes, proc->module->allocator, src);
|
||||
i64 dz = type_size_of(proc->module->sizes, proc->module->allocator, dst);
|
||||
if (sz == dz) {
|
||||
// NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment
|
||||
return value;
|
||||
}
|
||||
|
||||
ssaConvKind kind = ssaConv_trunc;
|
||||
if (dz >= sz) {
|
||||
kind = ssaConv_zext;
|
||||
}
|
||||
return ssa_emit(proc, ssa_make_instr_conv(proc, kind, value, src, dst));
|
||||
}
|
||||
|
||||
// boolean -> integer
|
||||
if (is_type_boolean(src) && is_type_integer(dst)) {
|
||||
return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_zext, value, src, dst));
|
||||
}
|
||||
|
||||
// integer -> boolean
|
||||
if (is_type_integer(src) && is_type_boolean(dst)) {
|
||||
Token op = {Token_NotEq};
|
||||
return ssa_emit_comp(proc, op, value, v_zero);
|
||||
}
|
||||
|
||||
|
||||
// float -> float
|
||||
if (is_type_float(src) && is_type_float(dst)) {
|
||||
i64 sz = basic_type_sizes[src->basic.kind];
|
||||
@@ -1238,6 +1282,9 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
}
|
||||
|
||||
|
||||
gb_printf("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
|
||||
|
||||
|
||||
GB_PANIC("Invalid type conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t));
|
||||
|
||||
return NULL;
|
||||
@@ -1285,8 +1332,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
case_ast_node(ue, UnaryExpr, expr);
|
||||
switch (ue->op.kind) {
|
||||
case Token_Pointer: {
|
||||
ssaLvalue lval = ssa_build_addr(proc, ue->expr);
|
||||
return ssa_lvalue_address(lval, proc);
|
||||
ssaValue *v = ssa_emit_zero_gep(proc, ssa_build_addr(proc, ue->expr).address);
|
||||
ssa_value_set_type(v, type_of_expr(proc->module->info, expr));
|
||||
return v;
|
||||
}
|
||||
case Token_Add:
|
||||
return ssa_build_expr(proc, ue->expr);
|
||||
@@ -1341,6 +1389,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
return ssa_emit_conv(proc, cmp, default_type(tv->type));
|
||||
} break;
|
||||
|
||||
case Token_as:
|
||||
return ssa_emit_conv(proc, ssa_build_expr(proc, be->left), tv->type);
|
||||
|
||||
default:
|
||||
GB_PANIC("Invalid binary expression");
|
||||
break;
|
||||
@@ -1404,7 +1455,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
}
|
||||
|
||||
} break;
|
||||
case Type_Vector:
|
||||
case Type_Array: {
|
||||
isize index = 0;
|
||||
for (AstNode *elem = cl->elem_list;
|
||||
@@ -1422,6 +1472,25 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Type_Vector: {
|
||||
isize index = 0;
|
||||
ssaValue *result = ssa_emit_load(proc, v);
|
||||
for (AstNode *elem = cl->elem_list;
|
||||
elem != NULL;
|
||||
elem = elem->next) {
|
||||
ssaValue *field_expr = ssa_build_expr(proc, elem);
|
||||
Type *t = ssa_value_type(field_expr);
|
||||
if (t->kind != Type_Tuple) {
|
||||
ssaValue *ev = ssa_emit_conv(proc, field_expr, et);
|
||||
ssaValue *i = ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(index));
|
||||
result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i));
|
||||
index++;
|
||||
} else {
|
||||
GB_PANIC("TODO(bill): tuples in vector literals");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} break;
|
||||
case Type_Slice: {
|
||||
i64 count = cl->elem_count;
|
||||
ssaValue *array = ssa_add_local_generated(proc, make_type_array(proc->module->allocator, et, count));
|
||||
@@ -1457,10 +1526,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
return ssa_emit_load(proc, v);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, CastExpr, expr);
|
||||
return ssa_emit_conv(proc, ssa_build_expr(proc, ce->expr), tv->type);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, CallExpr, expr);
|
||||
AstNode *p = unparen_expr(ce->proc);
|
||||
if (p->kind == AstNode_Ident) {
|
||||
@@ -1471,7 +1536,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
case BuiltinProc_len: {
|
||||
// len :: proc(Type) -> int
|
||||
// NOTE(bill): len of an array is a constant expression
|
||||
ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, ce->arg_list), proc);
|
||||
ssaValue *v = ssa_build_addr(proc, ce->arg_list).address;
|
||||
Type *t = get_base_type(ssa_value_type(v));
|
||||
if (t == t_string)
|
||||
return ssa_string_len(proc, v);
|
||||
@@ -1481,7 +1546,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
case BuiltinProc_cap: {
|
||||
// cap :: proc(Type) -> int
|
||||
// NOTE(bill): cap of an array is a constant expression
|
||||
ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, ce->arg_list), proc);
|
||||
ssaValue *v = ssa_build_addr(proc, ce->arg_list).address;
|
||||
Type *t = get_base_type(ssa_value_type(v));
|
||||
return ssa_slice_cap(proc, v);
|
||||
} break;
|
||||
@@ -1489,8 +1554,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
// copy :: proc(dst, src: []Type) -> int
|
||||
AstNode *dst_node = ce->arg_list;
|
||||
AstNode *src_node = ce->arg_list->next;
|
||||
ssaValue *dst_slice = ssa_lvalue_address(ssa_build_addr(proc, dst_node), proc);
|
||||
ssaValue *src_slice = ssa_lvalue_address(ssa_build_addr(proc, src_node), proc);
|
||||
ssaValue *dst_slice = ssa_build_addr(proc, dst_node).address;
|
||||
ssaValue *src_slice = ssa_build_addr(proc, src_node).address;
|
||||
Type *slice_type = get_base_type(ssa_value_type(dst_slice));
|
||||
GB_ASSERT(slice_type->kind == Type_Slice);
|
||||
Type *elem_type = slice_type->slice.elem;
|
||||
@@ -1564,11 +1629,21 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
case_end;
|
||||
|
||||
case_ast_node(se, SliceExpr, expr);
|
||||
return ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, expr), proc));
|
||||
return ssa_emit_load(proc, ssa_build_addr(proc, expr).address);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ie, IndexExpr, expr);
|
||||
return ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, expr), proc));
|
||||
Type *type = type_of_expr(proc->module->info, ie->expr);
|
||||
type = get_base_type(type);
|
||||
if (is_type_vector(type)) {
|
||||
GB_PANIC("HERE\n");
|
||||
// NOTE(bill): For vectors, use ExtractElement
|
||||
ssaValue *vector = ssa_emit_load(proc, ssa_build_addr(proc, ie->expr).address);
|
||||
ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
|
||||
return ssa_emit(proc, ssa_make_instr_extract_element(proc, vector, index));
|
||||
} else {
|
||||
return ssa_emit_load(proc, ssa_build_addr(proc, expr).address);
|
||||
}
|
||||
case_end;
|
||||
}
|
||||
|
||||
@@ -1608,7 +1683,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
switch (expr->kind) {
|
||||
case_ast_node(i, Ident, expr);
|
||||
if (ssa_is_blank_ident(expr)) {
|
||||
ssaLvalue val = {ssaLvalue_Blank};
|
||||
ssaLvalue val = {};
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -1616,7 +1691,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
ssaValue *v = NULL;
|
||||
ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
|
||||
if (found) v = *found;
|
||||
return ssa_make_lvalue_address(v, expr);
|
||||
return ssa_make_lvalue(v, expr);
|
||||
case_end;
|
||||
|
||||
case_ast_node(pe, ParenExpr, expr);
|
||||
@@ -1630,7 +1705,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
Entity *entity = lookup_field(type, unparen_expr(se->selector), &field_index);
|
||||
GB_ASSERT(entity != NULL);
|
||||
|
||||
ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc);
|
||||
ssaValue *e = ssa_build_addr(proc, se->expr).address;
|
||||
|
||||
if (type->kind == Type_Pointer) {
|
||||
// NOTE(bill): Allow x^.y and x.y to be the same
|
||||
@@ -1639,7 +1714,37 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
|
||||
ssaValue *v = ssa_emit_struct_gep(proc, e, field_index, entity->type);
|
||||
return ssa_make_lvalue_address(v, expr);
|
||||
return ssa_make_lvalue(v, expr);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ue, UnaryExpr, expr);
|
||||
switch (ue->op.kind) {
|
||||
case Token_Pointer: {
|
||||
ssaLvalue lval = ssa_build_addr(proc, ue->expr);
|
||||
// ssaValue *v = ssa_emit_zero_gep(proc, lval.address);
|
||||
// Type *t = ssa_value_type(lval.address);
|
||||
// ssa_value_set_type(lval.address, make_type_pointer(proc->module->allocator, t));
|
||||
// return ssa_make_lvalue(v, expr);
|
||||
return lval;
|
||||
}
|
||||
default:
|
||||
GB_PANIC("Invalid unary expression for ssa_build_addr");
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(be, BinaryExpr, expr);
|
||||
switch (be->op.kind) {
|
||||
case Token_as: {
|
||||
// NOTE(bill): Needed for dereference of pointer conversion
|
||||
Type *type = type_of_expr(proc->module->info, expr);
|
||||
ssaValue *v = ssa_add_local_generated(proc, type);
|
||||
ssa_emit_store(proc, v, ssa_emit_conv(proc, ssa_build_expr(proc, be->left), type));
|
||||
return ssa_make_lvalue(v, expr);
|
||||
}
|
||||
default:
|
||||
GB_PANIC("Invalid binary expression for ssa_build_addr: %.*s\n", LIT(be->op.string));
|
||||
break;
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(ie, IndexExpr, expr);
|
||||
@@ -1648,34 +1753,39 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
ssaValue *elem = NULL;
|
||||
switch (t->kind) {
|
||||
case Type_Array: {
|
||||
ssaValue *array = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
|
||||
ssaValue *array = ssa_build_addr(proc, ie->expr).address;
|
||||
elem = ssa_array_elem(proc, array);
|
||||
} break;
|
||||
case Type_Slice: {
|
||||
ssaValue *slice = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
|
||||
ssaValue *slice = ssa_build_addr(proc, ie->expr).address;
|
||||
elem = ssa_slice_elem(proc, slice);
|
||||
} break;
|
||||
case Type_Vector: {
|
||||
ssaValue *vector = ssa_build_addr(proc, ie->expr).address;
|
||||
Type *t_ptr = make_type_pointer(proc->module->allocator, t->vector.elem);
|
||||
elem = ssa_emit_struct_gep(proc, vector, v_zero32, t_ptr);
|
||||
} break;
|
||||
case Type_Basic: { // Basic_string
|
||||
TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(ie->expr));
|
||||
if (tv->mode == Addressing_Constant) {
|
||||
ssaValue *array = ssa_add_global_string_array(proc, tv->value);
|
||||
elem = ssa_array_elem(proc, array);
|
||||
} else {
|
||||
ssaLvalue lval = ssa_build_addr(proc, ie->expr);
|
||||
ssaValue *str = ssa_lvalue_address(lval, proc);
|
||||
elem = ssa_string_elem(proc, str);
|
||||
elem = ssa_string_elem(proc, ssa_build_addr(proc, ie->expr).address);
|
||||
}
|
||||
} break;
|
||||
case Type_Pointer: {
|
||||
elem = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc));
|
||||
elem = ssa_emit_load(proc, ssa_build_addr(proc, ie->expr).address);
|
||||
} break;
|
||||
}
|
||||
|
||||
ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
|
||||
v = ssa_emit_ptr_offset(proc, elem, index);
|
||||
|
||||
ssa_value_set_type(v, type_deref(ssa_value_type(v)));
|
||||
return ssa_make_lvalue_address(v, expr);
|
||||
Type *lval_type = type_deref(ssa_value_type(v));
|
||||
// gb_printf("%s\n", type_to_string(lval_type));
|
||||
ssa_value_set_type(v, lval_type);
|
||||
return ssa_make_lvalue(v, expr);
|
||||
case_end;
|
||||
|
||||
case_ast_node(se, SliceExpr, expr);
|
||||
@@ -1691,13 +1801,13 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
switch (type->kind) {
|
||||
case Type_Slice:
|
||||
case Type_Array: {
|
||||
ssaValue *base = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc);
|
||||
return ssa_make_lvalue_address(ssa_emit_slice(proc, type, base, low, high, max), expr);
|
||||
ssaValue *base = ssa_build_addr(proc, se->expr).address;
|
||||
return ssa_make_lvalue(ssa_emit_slice(proc, type, base, low, high, max), expr);
|
||||
} break;
|
||||
case Type_Basic: {
|
||||
// NOTE(bill): max is not needed
|
||||
ssaValue *base = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc);
|
||||
return ssa_make_lvalue_address(ssa_emit_substring(proc, base, low, high), expr);
|
||||
ssaValue *base = ssa_build_addr(proc, se->expr).address;
|
||||
return ssa_make_lvalue(ssa_emit_substring(proc, base, low, high), expr);
|
||||
} break;
|
||||
}
|
||||
|
||||
@@ -1705,21 +1815,21 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(de, DerefExpr, expr);
|
||||
ssaValue *e = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc));
|
||||
ssaValue *e = ssa_emit_load(proc, ssa_build_addr(proc, de->expr).address);
|
||||
ssaValue *gep = ssa_make_instr_get_element_ptr(proc, e, NULL, NULL, 0, false);
|
||||
Type *t = type_deref(get_base_type(ssa_value_type(e)));
|
||||
gep->instr.get_element_ptr.result_type = t;
|
||||
gep->instr.get_element_ptr.elem_type = t;
|
||||
ssaValue *v = ssa_emit(proc, gep);
|
||||
return ssa_make_lvalue_address(v, expr);
|
||||
return ssa_make_lvalue(v, expr);
|
||||
case_end;
|
||||
}
|
||||
|
||||
GB_PANIC("Unexpected address expression\n"
|
||||
"\tAstNode: %.*s\n", LIT(ast_node_strings[expr->kind]));
|
||||
|
||||
ssaLvalue blank = {ssaLvalue_Blank};
|
||||
return blank;
|
||||
|
||||
return ssa_make_lvalue(NULL, NULL);
|
||||
}
|
||||
|
||||
void ssa_build_assign_op(ssaProcedure *proc, ssaLvalue lhs, ssaValue *value, Token op) {
|
||||
@@ -1787,11 +1897,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
defer (gb_array_free(inits));
|
||||
|
||||
for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
|
||||
ssaLvalue lval = {ssaLvalue_Blank};
|
||||
ssaLvalue lval = ssa_make_lvalue(NULL, NULL);
|
||||
if (!ssa_is_blank_ident(name)) {
|
||||
ssa_add_local_for_identifier(proc, name);
|
||||
lval = ssa_build_addr(proc, name);
|
||||
GB_ASSERT(lval.address.value != NULL);
|
||||
GB_ASSERT(lval.address != NULL);
|
||||
}
|
||||
|
||||
gb_array_append(lvals, lval);
|
||||
@@ -1804,8 +1914,8 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
|
||||
|
||||
gb_for_array(i, inits) {
|
||||
if (lvals[i].kind != ssaLvalue_Blank) {
|
||||
ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_lvalue_type(lvals[i]));
|
||||
if (lvals[i].address != NULL) {
|
||||
ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_value_type(lvals[i].address));
|
||||
ssa_lvalue_store(lvals[i], proc, v);
|
||||
}
|
||||
}
|
||||
@@ -1825,7 +1935,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
defer (gb_array_free(inits));
|
||||
|
||||
for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
|
||||
ssaLvalue lval = {ssaLvalue_Blank};
|
||||
ssaLvalue lval = ssa_make_lvalue(NULL, NULL);
|
||||
if (!ssa_is_blank_ident(name)) {
|
||||
ssa_add_local_for_identifier(proc, name);
|
||||
lval = ssa_build_addr(proc, name);
|
||||
@@ -1850,7 +1960,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
|
||||
|
||||
gb_for_array(i, inits) {
|
||||
ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_lvalue_type(lvals[i]));
|
||||
ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_value_type(lvals[i].address));
|
||||
ssa_lvalue_store(lvals[i], proc, v);
|
||||
}
|
||||
}
|
||||
|
||||
141
src/parser.cpp
141
src/parser.cpp
@@ -96,7 +96,6 @@ AST_NODE_KIND(_ExprBegin, struct{}) \
|
||||
AST_NODE_KIND(ParenExpr, struct { AstNode *expr; Token open, close; }) \
|
||||
AST_NODE_KIND(SelectorExpr, struct { Token token; AstNode *expr, *selector; }) \
|
||||
AST_NODE_KIND(IndexExpr, struct { AstNode *expr, *index; Token open, close; }) \
|
||||
AST_NODE_KIND(CastExpr, struct { Token token; AstNode *type, *expr; }) \
|
||||
AST_NODE_KIND(DerefExpr, struct { Token op; AstNode *expr; }) \
|
||||
AST_NODE_KIND(CallExpr, struct { \
|
||||
AstNode *proc, *arg_list; \
|
||||
@@ -296,8 +295,6 @@ Token ast_node_token(AstNode *node) {
|
||||
return node->SliceExpr.open;
|
||||
case AstNode_Ellipsis:
|
||||
return node->Ellipsis.token;
|
||||
case AstNode_CastExpr:
|
||||
return node->CastExpr.token;
|
||||
case AstNode_DerefExpr:
|
||||
return node->DerefExpr.op;
|
||||
case AstNode_BadStmt:
|
||||
@@ -537,15 +534,6 @@ gb_inline AstNode *make_slice_expr(AstFile *f, AstNode *expr, Token open, Token
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_inline AstNode *make_cast_expr(AstFile *f, Token token, AstNode *type, AstNode *expr) {
|
||||
AstNode *result = make_node(f, AstNode_CastExpr);
|
||||
result->CastExpr.token = token;
|
||||
result->CastExpr.type = type;
|
||||
result->CastExpr.expr = expr;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
gb_inline AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) {
|
||||
AstNode *result = make_node(f, AstNode_DerefExpr);
|
||||
result->DerefExpr.expr = expr;
|
||||
@@ -858,6 +846,7 @@ gb_internal void add_ast_entity(AstFile *f, AstScope *scope, AstNode *declaratio
|
||||
|
||||
|
||||
void fix_advance_to_next_stmt(AstFile *f) {
|
||||
// TODO(bill): fix_advance_to_next_stmt
|
||||
#if 0
|
||||
for (;;) {
|
||||
Token t = f->cursor[0];
|
||||
@@ -1209,17 +1198,6 @@ AstNode *parse_unary_expr(AstFile *f, b32 lhs) {
|
||||
operand = parse_unary_expr(f, false);
|
||||
return make_unary_expr(f, op, operand);
|
||||
} break;
|
||||
|
||||
case Token_cast: {
|
||||
AstNode *type, *operand;
|
||||
Token token = f->cursor[0];
|
||||
next_token(f);
|
||||
expect_token(f, Token_OpenParen);
|
||||
type = parse_type(f);
|
||||
expect_token(f, Token_CloseParen);
|
||||
operand = parse_unary_expr(f, false);
|
||||
return make_cast_expr(f, token, type, operand);
|
||||
} break;
|
||||
}
|
||||
|
||||
return parse_atom_expr(f, lhs);
|
||||
@@ -1234,15 +1212,25 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) {
|
||||
i32 op_prec = token_precedence(op);
|
||||
if (op_prec != prec)
|
||||
break;
|
||||
expect_operator(f); // NOTE(bill): error checks too
|
||||
if (op.kind != Token_as) {
|
||||
expect_operator(f); // NOTE(bill): error checks too
|
||||
}
|
||||
if (lhs) {
|
||||
// TODO(bill): error checking
|
||||
lhs = false;
|
||||
}
|
||||
right = parse_binary_expr(f, false, prec+1);
|
||||
if (!right)
|
||||
ast_file_err(f, op, "Expected expression on the right hand side of the binary operator");
|
||||
|
||||
if (op.kind == Token_as) {
|
||||
next_token(f);
|
||||
right = parse_type(f);
|
||||
} else {
|
||||
right = parse_binary_expr(f, false, prec+1);
|
||||
if (!right) {
|
||||
ast_file_err(f, op, "Expected expression on the right hand side of the binary operator");
|
||||
}
|
||||
}
|
||||
expression = make_binary_expr(f, op, expression, right);
|
||||
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
@@ -1731,12 +1719,8 @@ AstNode *parse_if_stmt(AstFile *f) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
f->expr_level = prev_level;
|
||||
|
||||
|
||||
|
||||
|
||||
if (cond == NULL) {
|
||||
ast_file_err(f, f->cursor[0], "Expected condition for if statement");
|
||||
}
|
||||
@@ -1846,56 +1830,51 @@ AstNode *parse_defer_stmt(AstFile *f) {
|
||||
return make_defer_stmt(f, token, statement);
|
||||
}
|
||||
|
||||
AstNode *parse_type_decl(AstFile *f) {
|
||||
Token token = expect_token(f, Token_type);
|
||||
AstNode *name = parse_identifier(f);
|
||||
expect_token(f, Token_Colon);
|
||||
AstNode *type = parse_type(f);
|
||||
|
||||
AstNode *type_decl = make_type_decl(f, token, name, type);
|
||||
|
||||
if (type->kind != AstNode_StructType &&
|
||||
type->kind != AstNode_ProcType)
|
||||
expect_token(f, Token_Semicolon);
|
||||
|
||||
return type_decl;
|
||||
}
|
||||
|
||||
AstNode *parse_alias_decl(AstFile *f) {
|
||||
Token token = expect_token(f, Token_alias);
|
||||
AstNode *name = parse_identifier(f);
|
||||
expect_token(f, Token_Colon);
|
||||
AstNode *type = parse_type(f);
|
||||
|
||||
AstNode *alias_decl = make_alias_decl(f, token, name, type);
|
||||
|
||||
if (type->kind != AstNode_StructType &&
|
||||
type->kind != AstNode_ProcType)
|
||||
expect_token(f, Token_Semicolon);
|
||||
|
||||
return alias_decl;
|
||||
}
|
||||
|
||||
AstNode *parse_import_decl(AstFile *f) {
|
||||
Token token = expect_token(f, Token_import);
|
||||
Token filepath = expect_token(f, Token_String);
|
||||
if (f->curr_scope == f->file_scope) {
|
||||
return make_import_decl(f, token, filepath);
|
||||
}
|
||||
ast_file_err(f, token, "You cannot `import` within a procedure. This must be done at the file scope.");
|
||||
return make_bad_decl(f, token, filepath);
|
||||
}
|
||||
|
||||
AstNode *parse_stmt(AstFile *f) {
|
||||
AstNode *s = NULL;
|
||||
Token token = f->cursor[0];
|
||||
switch (token.kind) {
|
||||
case Token_type:
|
||||
return parse_type_decl(f);
|
||||
case Token_alias:
|
||||
return parse_alias_decl(f);
|
||||
case Token_import:
|
||||
return parse_import_decl(f);
|
||||
case Token_type: {
|
||||
Token token = expect_token(f, Token_type);
|
||||
AstNode *name = parse_identifier(f);
|
||||
expect_token(f, Token_Colon);
|
||||
AstNode *type = parse_type(f);
|
||||
|
||||
AstNode *type_decl = make_type_decl(f, token, name, type);
|
||||
|
||||
if (type->kind != AstNode_StructType &&
|
||||
type->kind != AstNode_ProcType) {
|
||||
expect_token(f, Token_Semicolon);
|
||||
}
|
||||
|
||||
return type_decl;
|
||||
} break;
|
||||
|
||||
case Token_alias: {
|
||||
Token token = expect_token(f, Token_alias);
|
||||
AstNode *name = parse_identifier(f);
|
||||
expect_token(f, Token_Colon);
|
||||
AstNode *type = parse_type(f);
|
||||
|
||||
AstNode *alias_decl = make_alias_decl(f, token, name, type);
|
||||
|
||||
if (type->kind != AstNode_StructType &&
|
||||
type->kind != AstNode_ProcType) {
|
||||
expect_token(f, Token_Semicolon);
|
||||
}
|
||||
|
||||
return alias_decl;
|
||||
} break;
|
||||
|
||||
case Token_import: {
|
||||
Token token = expect_token(f, Token_import);
|
||||
Token filepath = expect_token(f, Token_String);
|
||||
if (f->curr_scope == f->file_scope) {
|
||||
return make_import_decl(f, token, filepath);
|
||||
}
|
||||
ast_file_err(f, token, "You cannot `import` within a procedure. This must be done at the file scope.");
|
||||
return make_bad_decl(f, token, filepath);
|
||||
} break;
|
||||
|
||||
// Operands
|
||||
case Token_Identifier:
|
||||
@@ -1910,10 +1889,8 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
case Token_Xor:
|
||||
case Token_Not:
|
||||
s = parse_simple_stmt(f);
|
||||
if (s->kind != AstNode_ProcDecl &&
|
||||
!allow_token(f, Token_Semicolon) &&
|
||||
f->cursor[0].kind == Token_CloseBrace) {
|
||||
// TODO(bill): Cleanup semicolon handling in parser
|
||||
if (s->kind != AstNode_ProcDecl && !allow_token(f, Token_Semicolon)) {
|
||||
// CLEANUP(bill): Semicolon handling in parser
|
||||
ast_file_err(f, f->cursor[0],
|
||||
"Expected `;` after statement, got `%.*s`",
|
||||
LIT(token_strings[f->cursor[0].kind]));
|
||||
@@ -1946,8 +1923,6 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
s = make_empty_stmt(f, token);
|
||||
next_token(f);
|
||||
return s;
|
||||
|
||||
|
||||
}
|
||||
|
||||
ast_file_err(f, token,
|
||||
|
||||
@@ -70,12 +70,6 @@ void print_ast(AstNode *node, isize indent) {
|
||||
print_ast(node->IndexExpr.expr, indent+1);
|
||||
print_ast(node->IndexExpr.index, indent+1);
|
||||
break;
|
||||
case AstNode_CastExpr:
|
||||
print_indent(indent);
|
||||
gb_printf("(cast)\n");
|
||||
print_ast(node->CastExpr.type, indent+1);
|
||||
print_ast(node->CastExpr.expr, indent+1);
|
||||
break;
|
||||
case AstNode_DerefExpr:
|
||||
print_indent(indent);
|
||||
gb_printf("(deref)\n");
|
||||
|
||||
@@ -54,6 +54,7 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
||||
TOKEN_KIND(Token_AndNot, "&~"), \
|
||||
TOKEN_KIND(Token_Shl, "<<"), \
|
||||
TOKEN_KIND(Token_Shr, ">>"), \
|
||||
TOKEN_KIND(Token_as, "as"), \
|
||||
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||
TOKEN_KIND(Token_AddEq, "+="), \
|
||||
TOKEN_KIND(Token_SubEq, "-="), \
|
||||
@@ -71,6 +72,7 @@ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||
TOKEN_KIND(Token_Decrement, "--"), \
|
||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||
\
|
||||
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
||||
TOKEN_KIND(Token_CmpOr, "||"), \
|
||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||
@@ -113,7 +115,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_defer, "defer"), \
|
||||
TOKEN_KIND(Token_return, "return"), \
|
||||
TOKEN_KIND(Token_import, "import"), \
|
||||
TOKEN_KIND(Token_cast, "cast"), \
|
||||
TOKEN_KIND(Token_struct, "struct"), \
|
||||
TOKEN_KIND(Token_union, "union"), \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
@@ -199,9 +200,10 @@ gb_no_inline void warning(Token token, char *fmt, ...) {
|
||||
|
||||
i32 token_precedence(Token t) {
|
||||
switch (t.kind) {
|
||||
case Token_CmpOr: return 1;
|
||||
case Token_CmpAnd: return 2;
|
||||
|
||||
case Token_CmpOr:
|
||||
return 1;
|
||||
case Token_CmpAnd:
|
||||
return 2;
|
||||
case Token_CmpEq:
|
||||
case Token_NotEq:
|
||||
case Token_Lt:
|
||||
@@ -209,13 +211,11 @@ i32 token_precedence(Token t) {
|
||||
case Token_LtEq:
|
||||
case Token_GtEq:
|
||||
return 3;
|
||||
|
||||
case Token_Add:
|
||||
case Token_Sub:
|
||||
case Token_Or:
|
||||
case Token_Xor:
|
||||
return 4;
|
||||
|
||||
case Token_Mul:
|
||||
case Token_Quo:
|
||||
case Token_Mod:
|
||||
@@ -224,6 +224,8 @@ i32 token_precedence(Token t) {
|
||||
case Token_Shl:
|
||||
case Token_Shr:
|
||||
return 5;
|
||||
case Token_as:
|
||||
return 6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -641,10 +643,14 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
|
||||
// NOTE(bill): ALL identifiers are > 1
|
||||
if (token.string.len > 1) {
|
||||
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
||||
if (are_strings_equal(token.string, token_strings[k])) {
|
||||
token.kind = cast(TokenKind)k;
|
||||
break;
|
||||
if (are_strings_equal(token.string, token_strings[Token_as])) {
|
||||
token.kind = Token_as;
|
||||
} else {
|
||||
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
||||
if (are_strings_equal(token.string, token_strings[k])) {
|
||||
token.kind = cast(TokenKind)k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user