Changed how structs/unions are parsed so that recovery becomes more robust. Allow for more complex error data. Fixed recursive structs/unions. Corrected prefix precedence rules. Begin work on checking initializer constant-ness. Fixed error on failed arithmetic promotion. Added checks on constant overflow of sub/add/mult. Allow "current_module_name::x" to refer to globals. Added many tests.

This commit is contained in:
Christoffer Lerno
2020-07-23 17:59:42 +02:00
parent f45d6ef84b
commit ed01616f1e
49 changed files with 1289 additions and 314 deletions

View File

@@ -68,11 +68,11 @@ class Issues:
print('"' + parts[3] + '"')
if len(self.errors) > 0:
self.set_failed()
print("Expected errors that never occured:")
print("Expected errors that never occurred:")
num = 1
for key, value in self.errors.items():
pos = key.split(":", 2)
print(str(num) + ". " + pos[0] + " line: " + pos[1] + " expected: " + value)
print(str(num) + ". " + pos[0] + " line: " + pos[1] + " expected: \"" + value + "\"")
num += 1
def compile(self, args):
@@ -80,7 +80,7 @@ class Issues:
code = subprocess.run(path + 'c3c ' + args, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if code.returncode != 0 and code.returncode != 1:
self.set_failed()
print("Error: " + code.stderr)
print("Error (" + str(code.returncode) + "): " + code.stderr)
self.has_errors = True
return
self.parse_result(code.stderr.splitlines(keepends=False))

View File

@@ -10,4 +10,5 @@ module comments;
func void test()
{
return;
}
}

View File

@@ -1,11 +0,0 @@
enum EnumTestOverflow
{
VALUE = 0x80000000, // #error: does not fit into 'int'
}
enum EnumTestErrorType : float // #error: must be an integer type not 'float'
{
VALUE_BOOM
}

View File

@@ -1,19 +0,0 @@
enum EnumWithErrorWithMissingName : int (int) // #error: function parameter must be named
{
TEST
}
enum EnumWithErrorData : int (int // #error: end of the parameter list
{
TEST
}
error TheError
{
union // #error: A type name was expected here
{
int a;
int b;
}
}

View File

@@ -1,9 +1,12 @@
module foo;
error TooBig // #error: Error type may not exceed pointer
error TheError
{
usize a;
char b;
}
union // #error: A type name was expected here
{
int a;
int b;
}
}

View File

@@ -5,5 +5,16 @@ error TheError
int a;
}
error TheError2
{
byte a;
byte b;
}
error TheError3
{
void *a;
}
error OtherError;

View File

@@ -0,0 +1,5 @@
error TooBig // #error: Error type may not exceed pointer
{
usize a;
char b;
}

View File

@@ -35,4 +35,15 @@ func void testDiv(int a, int b)
a = a / b;
a /= b;
a /= 1;
}
func void testAssignment()
{
char x = -3 - 5;
char c = -128;
}
func byte test22()
{
return 100;
}

View File

@@ -0,0 +1,129 @@
func void test1()
{
double x = 2.3 +% 2; // #error: only valid for integer addition
}
func void test2()
{
double x = 0;
int y = x +% 4; // #error: only valid for integer addition
}
func void test3()
{
double x = 2.3 -% 2; // #error: only valid for integer subtraction
}
func void test4()
{
double x = 0;
int y = x -% 4; // #error: only valid for integer subtraction
}
func void test5()
{
double x = 2.3 *% 2; // #error: try * instead
}
func void test6()
{
double x = 0;
int y = x *% 4; // #error: try * instead
}
func void test7()
{
double x = 1.2 / 0; // #error: division by zero is not allowed
}
func void test8()
{
int y = 0 / 0; // #error: division by zero is not allowed
}
func void test9()
{
int y = 0;
int x = y / 0; // #error: division by zero is not allowed
}
func void test10()
{
10 = 20; // #error: Expression is not assignable
}
func void test11()
{
'10' = '20'; // #error: Expression is not assignable
}
func void test12()
{
true = false; // #error: Expression is not assignable
}
func void test13()
{
"a" = "b"; // #error: Expression is not assignable
}
func void test14()
{
1.2 = 1.3; // #error: Expression is not assignable
}
func void test15()
{
nil = nil; // #error: Expression is not assignable
}
func void test16()
{
int a = 0;
uint b = 2;
ushort c = 3;
a = a + c;
int c = a + b; // #error: Cannot add 'int' to 'uint'
}
func void test17()
{
byte a = 100 + 300; // #error: '300' does not fit in type 'byte'
}
func void test18()
{
byte b = 100 + 156; // #error: Cannot fit '256' into type 'byte'
}
func void test19()
{
char b = (-40) - 126; // #error: Cannot fit '-166' into type 'char'
}
func void test20()
{
char d = ((-128 - 10) + 10) - 2; // #error: Cannot fit '-130' into type 'char'
char c = 100 * 100; // #error: Cannot fit '10000' into type 'char'
char e = (-138 + 30);
char f = -138 + 30; // #error: '-138' does not fit in type 'char'
char g = -(128);
check(128); // #error: '128' does not fit in type 'char'
}
func void check(char x) {}
func void test21()
{
int a = 0;
int b = 2;
a++ = b++; // #error: Expression is not assignable
}
func byte test22()
{
return 300; // #error: '300' does not fit in type 'byte'
}

View File

@@ -0,0 +1,5 @@
func void test1()
{
int* p;
*p = 10;
}

View File

@@ -0,0 +1,33 @@
// #skip
// TODO string str = "hello";
char* str2 = "hello";
char[] str3 = "hello";
func void test2()
{
int[2] a = { 1, 2 };
int[2] b = 30; // #error: Cannot implicitly cast 'compint' to 'int[2]'
int[2] c = a;
}
int[2] a1 = { 1, 2 };
int[2] a2 = 30; // #error: Cannot implicitly cast 'compint' to 'int[2]'
int[2] a3 = a1;
// i8[] a; // @error{definition of variable with array type needs an explicit size or an initializer}
char ca = 0;
char cb = 1;
char cc = 127;
char cd = -128;
char ce = 128; // #error: '128' does not fit
char cf = -129; // #error: '-129' does not fit
char cg = 70000; // #error: '70000' does not fit
char ch = -70000; // #error: '-70000' does not fit

View File

@@ -0,0 +1,73 @@
// #skip
i32[+] a;
a += 10;
public func i32 main() {
a += 20; // @error{cannot add values to incremental array in function scope}
return 0;
}
const i32[+] A;
A += 10;
A += 20;
A += 30;
i32[+] b;
func void test1() {
i32[+] d; // @error{incremental arrays not allowed in function scope}
}
i32[+] c;
func void test2()
{
b += 10; // @error{cannot add values to incremental array in function scope}
}
i32[+] a = {} // @error{incremental array cannot have initializer}
i32 g;
i8[2] h = { 1, 2 }
g += 10; // @error{'a' is not an incremental array}
xyz += 20; // @error{module test has no symbol b}
h += 30; // @error{'d' is not an incremental array}
test2 += 20; // @error{'main' is not an incremental array}
i32[+] i;
i += xyz; // @error{use of undeclared identifier c}
a += test2; // @error{invalid type conversion from 'i32 ()' to 'i32'}
i32[+] k;
k += 1;
k += 2;
k += 3;
public func void test3()
{
i32 c = a; // @error{invalid type conversion from 'i32[3]' to 'i32'}
}
struct Point
{
int x;
int y;
}
Point[+] points;
points += { 10, 11 }
points += { 20, main } // @error{invalid type conversion from 'i32 ()' to 'i32'}
points += { 30, 31 }

View File

@@ -0,0 +1,17 @@
// #skip
type State enum u8 {
A,
B,
}
State += 10; // @error{expected identifier after incremental enum}
type State enum u8 {
A,
B,
}
State += C;
State += D;

View File

@@ -0,0 +1,31 @@
/*
public func int main()
{
for (;;) {}
return 0;
}
public func int test1()
{
for (int x = 0;;)
{
}
return 0;
}
public func int test2()
{
for (int x = 0; 1 ;)
{
}
return 0;
}
public func int test3()
{
for (; 1 ;2)
{
}
return 0;
}
*/

View File

@@ -0,0 +1,7 @@
func void foo() {}
public func int main()
{
for (; foo() ; ) {} // #error: Cannot implicitly cast 'void' to 'bool'
return 0;
}

View File

@@ -0,0 +1,24 @@
public func int main()
{
do FOO:
{
while FOO: (1) // #error: would shadow a previous declaration
{
return 1;
}
}
return 0;
}
func void test1()
{
do FOO:
{
while (1)
{
break BAR; // #error: Cannot find a labelled statement with the name 'BAR'
}
}
}

View File

@@ -0,0 +1,136 @@
enum Foo
{
A, B
}
enum Bar
{
B
}
func void test_other_enum()
{
Foo f = A;
switch (f)
{
case Foo.A:
break;
case B:
break;
case Bar.B: // #error: Cannot implicitly cast 'Bar' to 'Foo'
break;
}
}
func void test_check_nums()
{
Foo f = A;
switch (f)
{
case 2:
break;
case 0:
break;
}
}
func void test_scope(int i)
{
switch (i)
{
case 1:
int a = 0;
break;
case 2:
test_scope(a + 1); // #error: Identifier 'a' could not be found
}
}
func void test_duplicate_case(int i)
{
switch (i)
{
case 1:
break;
case 2:
break;
case 1: // #error: same case value appears
break;
}
}
func void test_duplicate_case2(Foo i)
{
switch (i)
{
case A:
break;
case 2:
break;
case A: // #error: same case value appears
break;
}
}
func void test_duplicate_case3(Foo i)
{
switch (i)
{
case A:
break;
case 0: // #error: same case value appears
break;
}
}
enum Baz
{
A, B, C, D
}
func void test_missing_all_cases(Baz x)
{
switch (x) // -error: 4 enumeration values not handled in switch: A, B, C, ...
{
}
}
func void test_missing_some_cases(Baz x)
{
switch (x) // -error: 4 enumeration B, C and D not handled in switch
{
case A:
break;
}
}
func void test_missing_some_cases2(Baz x)
{
switch (x) // -error: 4 enumeration B and D not handled in switch
{
case C:
case A:
break;
}
}
func void test_missing_some_cases3(Baz x)
{
switch (x) // -error: 4 enumeration B and D not handled in switch
{
case B:
case C:
case A:
break;
}
}
func void test_missing_no_cases(Baz x)
{
switch (x)
{
default:
break;
}
}

View File

@@ -0,0 +1,70 @@
// @warnings{no-unused}
module test;
struct Aa
{
int a;
int a; // #error: Duplicate member name 'a'
}
struct Bb
{
int a;
struct a // #error: Duplicate member name 'a'
{
int b;
}
}
union Cc
{
int a;
int a; // #error: Duplicate member name 'a'
struct b
{
int c;
int c; // #error: Duplicate member name 'c'
}
}
struct Dd
{
int b;
int a;
struct
{
union
{
short a; // #error: Duplicate member name 'a'
int b; // #error: Duplicate member name 'b'
}
}
}
union Ee
{
int a;
struct
{
short a; // #error: Duplicate member name 'a'
}
}
struct Ff
{
struct
{
int a;
}
struct b
{
int a;
}
union
{
int a; // #error: Duplicate member name 'a'
}
}

View File

@@ -0,0 +1,84 @@
module test;
struct Multi
{
int a, b, c;
}
struct Point
{
int a;
struct bb
{
int b;
}
struct
{
int b;
int c;
struct
{
Point* p;
}
}
union
{
int d;
short e;
}
union uu {
int d;
ushort e;
}
}
func void tester()
{
Multi m;
m.a = 1;
Point p;
p.a = 1;
p.bb.b = 2;
p.b = 3;
p.c = 4;
p.p = nil;
p.d = 5;
p.e = 6;
p.uu.d = 7;
p.uu.e = 8;
Point *p2 = &p;
p2.bb.b = 3;
p = { a = 1, bb.b = 3, e = 2 };
}
struct Aa1
{
struct bb
{
int b;
}
struct
{
int c;
}
}
func void test_conversion_struct()
{
Aa1 a1;
int aa = a1.bb; // #error: Cannot implicitly cast 'bb' to 'int'
}
struct Struct
{
int a;
}
func void myfunc()
{
Struct s;
s.b = 10; // #error: There is no element or method 'Struct.b'
}

View File

@@ -0,0 +1,184 @@
module test;
func void test1()
{
char a = 1;
int b = 2;
char c = b > a ? 1 : 0;
}
func void test2()
{
char a = 1;
char b = 2;
char c = a + b;
}
func void test3()
{
char a = 1;
int b = 2;
char c = a + b; // #error: Cannot implicitly cast 'int' to 'char'
}
func void test4()
{
char a = 1;
char b = 2;
int c = a + b;
}
func void test5()
{
char a = 1;
int b = 2;
int c = a + b;
}
func void test6()
{
char a = 1;
char b = 2;
char c = (b > a) ? 1 : 0 + a + b;
}
func void test7()
{
int[100] array = { };
int v = array[1];
}
typedef int as Number;
func void test8()
{
Number a = 10;
char c = a; // #error: implicitly cast 'Number' (int) to 'char'
}
func void test9()
{
const char a = 1; // TODO should be "A"
char b = a;
a = b; // #error: Expression is not assignable
}
func void test10()
{
const char a = 1;
char* b = &a; // #error: address of values
}
enum Enum : int
{
A = 127,
B,
}
func void test11()
{
int a = Enum.A;
char b = Enum.B; // #error: Cannot implicitly convert 'Enum' with underlying type of 'int' to 'char'
}
func void test12()
{
float f = 3.14;
char a = f; // #error: cast 'float' to 'char'
}
func void test13()
{
int a = 1;
char b = a; // #error: cast 'int' to 'char'
}
func void test14()
{
byte a = 1;
char b = a; // #error: cast 'byte' to 'char'
}
func void test15()
{
float f = 3.14;
char c = 1;
char* a = &f; // #error: cast 'float*' to 'char*'
char* b = &c;
}
func void test16()
{
float f = 3.14;
int i = 1;
char c = 1 ? 'c' : 'd';
char d = 1 ? 'c' : i; // #error: cast 'int' to 'char'
char e = 1 ? i : 0; // #error: cast 'int' to 'char'
int g = 1 ? i : f; // #error: cast 'float' to 'int'
int a = f ? 1 : 0;
}
func void test17()
{
int a = "test"; // #error: cast 'string' to 'int'
}
func void test18()
{
char b = 1;
int a = b;
}
func void test19()
{
uint a = 1;
int b = a; // #error: cast 'uint' to 'int'
}
/*
const i32 Num = 200;
func void test1() {
i8 a = test.Num; // @error{constant value 200 out-of-bounds for type 'i8', range [-128, 127]}
}*/
func void test21()
{
int a = 1;
uint b = a; // #error: cast 'int' to 'uint'
}
func void foo() {}
func void test22()
{
char a = foo(); // #error: cast 'void' to 'char'
short b = foo(); // #error: cast 'void' to 'short'
int c = foo(); // #error: cast 'void' to 'int'
long d = foo(); // #error: cast 'void' to 'long'
byte e = foo(); // #error: cast 'void' to 'byte'
ushort f = foo(); // #error: cast 'void' to 'ushort'
uint g = foo(); // #error: cast 'void' to 'uint'
ulong h = foo(); // #error: cast 'void' to 'ulong'
bool i = foo(); // #error: cast 'void' to 'bool'
}
int num = 10;
func void test23()
{
int a = num;
int b = test::num;
char c = test::num; // #error: cast 'int' to 'char'
}
int[2][3] b123;
func void test24()
{
int a = b123; // #error: cast 'int[2][3]' to 'int'
}

View File

@@ -0,0 +1,34 @@
enum EnumTestOverflow
{
VALUE = 0x80000000, // #error: does not fit in type 'int'
}
enum EnumTestErrorType : float // #error: must be an integer type not 'float'
{
VALUE_BOOM
}
enum EnumWithErrorType2 : int* // #error: must be an integer type not 'int*'
{
TEST
}
enum EnumTestErrorType3 : int
{
A = FOO // #error: Identifier 'FOO' could not be found
}
func int foo()
{
return 10;
}
enum State
{
A = foo(), // #error: Expected a constant expression for enum
B = "hello", // #error: Cannot implicitly cast 'string' to 'int'
C = true, // #error: Cannot implicitly cast 'bool' to 'int'
}

View File

@@ -29,3 +29,18 @@ enum EnumTestSmall : ushort
VALUE = 0xFF,
VALUE2 = 0xFFFF
}
enum EnumWithErrorData2 : int (int bar, )
{
TEST
}
enum EnumTestErrorType4
{
}
enum EnumTest5
{
B = 0,
C,
}

View File

@@ -0,0 +1,23 @@
enum EnumWithErrorWithMissingName : int (int) // #error: function parameter must be named
{
TEST
}
enum EnumWithErrorData : int (int // #error: end of the parameter list
{
TEST
}
enum EnumWithErrorData2 : int (int, int bar) // #error: function parameter must be named
{
TEST
}
enum EnumTestErrorType3 : int
{
A,
A // #error: This enum constant is declared twice
}

View File

@@ -0,0 +1,17 @@
typedef int[4] as Arr;
Arr a = { 3, 4, 5, 6 };
func void test1()
{
Arr b = { 3, 4, 5, 6 };
int c = b; // #error: cast 'Arr' (int[4]) to 'int'
int d = a; // #error: cast 'Arr' (int[4]) to 'int'
}
typedef Number1 as Number2; // #error: Recursive definition of 'Number2'
typedef Number2 as Number1;
typedef Number as Number; // #error: Recursive definition of 'Number'

View File

@@ -0,0 +1,3 @@
func1 a = 1; // #error: declaration before the variable
func void func1() {}