├── .gitignore ├── Bootstrap ├── Parser_test_output1.c ├── ErrorHandler.c ├── Dict_int_string.c ├── Parser.c ├── Lexer.c └── lexer_test.c ├── examples ├── 00_Hello_World.anil ├── 00_Hello_World_generated_anil.c ├── Unique_ptr_example.c ├── UI │ ├── todos.txt │ ├── TodoAppBasic.c │ ├── TodoAppWebServer.c │ ├── TodoAppJSX.c │ ├── Todos.html │ └── IDE │ │ └── IDE.anil ├── 10_FileIO.anil ├── 07_Set.c ├── 04_Classes.anil ├── 10_FileIO.c ├── Macro_With_Variadic_Arguments.c ├── FunctionPointer_generated.c ├── 00_Hello_World_generated.c ├── 03_Dictionary.c ├── 08_Optional.anil ├── FunctionPointer.c ├── 00_Hello_World.c ├── 04_Classes.c ├── 04_Classes_generated.c ├── 04_Classes_generated_anil.c ├── 08_Optional.c ├── TestSuites │ ├── Expression_parse_tests.c │ ├── slicing.c │ ├── Return_value_tests.c │ └── slicing_generated.c ├── decorators_inside_fn_body.c ├── 04_b_Classes.c ├── decorators_inside_fn_body_generated.c ├── 01_variables.c ├── Reflection.c ├── Enumerate.c ├── 02_List.c ├── 04_b_Classes_generated.c ├── 11_Threads_And_Channels.anil ├── Enumerate_generated.c ├── Compile_Time_Constants.c ├── 01_variables_generated.c ├── 06_Vector.c ├── WebServer.c ├── 09_Functions.c ├── 08_Optional_generated.c ├── 08_Optional_generated_anil.c ├── Variables_GUI_Input_Win.c ├── 05_Strings.c ├── raylib │ ├── raylib_example.c │ └── snake.c ├── Annotations.c ├── Annotations_generated.c ├── 03_Dictionary_generated.c ├── Variables_GUI_Input_Win_generated.c ├── Macro_With_Variadic_Arguments_generated.c └── 11_Threads_And_Channels_generated_anil.c ├── Lib ├── Random.c ├── Optional.c ├── UniquePtr.c ├── Set.c ├── File.c ├── Dictionary.c ├── OrderedDict.c ├── Subprocess.c ├── JSON.c ├── raylib.c ├── Threads.c ├── List.c ├── String.c └── Vector.c ├── ErrorHandler.py ├── batch_compile.py ├── Parser.py ├── README.md └── lexer.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | .vscode/ 3 | __pycache__/ -------------------------------------------------------------------------------- /Bootstrap/Parser_test_output1.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(){ 3 | printf("Hello World!"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /examples/00_Hello_World.anil: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | function print_hello_world_in_ANIL() 4 | print("Hello World from ANIL function.\n") 5 | endfunction 6 | 7 | function main() -> int: 8 | print("Hello World.\n") 9 | print_hello_world_in_ANIL() 10 | return 0 11 | endfunction -------------------------------------------------------------------------------- /Bootstrap/ErrorHandler.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | ///*/// 4 | 5 | struct ErrorHandler { char dummy}; 6 | 7 | namespace ErrorHandler 8 | c_function RAISE_ERROR(p_error_msg : str) 9 | fprintf(stderr, p_error_msg); 10 | exit(EXIT_FAILURE); 11 | endc_function 12 | endnamespace 13 | 14 | ///*/// 15 | -------------------------------------------------------------------------------- /examples/00_Hello_World_generated_anil.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | void print_hello_world_in_ANIL(); 5 | int main(); 6 | 7 | void print_hello_world_in_ANIL() { 8 | printf("Hello World from ANIL function.\n"); 9 | } 10 | 11 | int main() { 12 | printf("Hello World.\n"); 13 | print_hello_world_in_ANIL(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /Lib/Random.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | /////////////////////////////////////////// 4 | #include 5 | #include 6 | 7 | struct Random{char dummy}; 8 | 9 | namespace Random 10 | 11 | c_function __init__() 12 | srand(time(0)); 13 | endc_function 14 | 15 | c_function randrange(upper_limit : int) -> int: 16 | return rand() % upper_limit; 17 | endc_function 18 | 19 | endnamespace 20 | ///*/// 21 | 22 | -------------------------------------------------------------------------------- /examples/Unique_ptr_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // IMPORTS // 4 | 5 | // STRUCT_DEFINATIONS // 6 | 7 | int main() { 8 | 9 | // clang-format off 10 | 11 | ///*/// main() 12 | import Vector 13 | import String 14 | 15 | import UniquePtr 16 | 17 | let i = UniquePtr{5}; 18 | let s = UniquePtr{5}; 19 | 20 | // DESTRUCTOR_CODE // 21 | ///*/// 22 | 23 | // clang-format on 24 | 25 | return 0; 26 | } -------------------------------------------------------------------------------- /examples/UI/todos.txt: -------------------------------------------------------------------------------- 1 | Complete UI Framework 2 | Implement JSX like syntax 3 | Return; statements should call all destructors. 4 | return False produces error but return false doesnt. 5 | Add Copy constructors for Vectors. See Json.c 6 | Optimize Comma in Vector Print 7 | Token.LET Rename array_name to var_name 8 | Move more stuffs to AST based parsing 9 | Add syntax highlighting to IDE. 10 | Add a edit button for constexpr lines so the dict can be edited graphically. 11 | -------------------------------------------------------------------------------- /examples/10_FileIO.anil: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | import Vector 6 | import String 7 | import File 8 | 9 | function main() -> int: 10 | print("Writing to file hello.txt:\n") 11 | let outputFile = File{"hello.txt"}; 12 | outputFile.writeline("Hello World :)") 13 | 14 | print("Reading from a file(10_FileIO.c) to a string:\n") 15 | let input_str = "" 16 | input_str.set_to_file_contents("10_FileIO.c") 17 | input_str.printLn() 18 | 19 | return 0 20 | endfunction -------------------------------------------------------------------------------- /Lib/Optional.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | struct Optional{bool _has_value, T _value}; 4 | 5 | namespace Optional 6 | 7 | function __init__() 8 | this._has_value = false 9 | endfunction 10 | 11 | function has_value() -> bool: 12 | return this._has_value 13 | endfunction 14 | 15 | function get_value() -> T: 16 | return this._value 17 | endfunction 18 | 19 | function set_value(p_value : T) 20 | this._has_value = true 21 | this._value = p_value 22 | endfunction 23 | 24 | endnamespace 25 | ///*/// 26 | 27 | -------------------------------------------------------------------------------- /examples/07_Set.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | import Vector 15 | import String 16 | import Set 17 | 18 | let s1 = "apple" 19 | let s2 = "banana" 20 | let s3 = "cherry" 21 | 22 | let s = Set{10}; 23 | s.add(s1) 24 | s.add(s1) 25 | s.add(s2) 26 | s.add(s2) 27 | s.add(s3) 28 | s.print() 29 | 30 | for str in s{ 31 | str.printLn() 32 | } 33 | 34 | // DESTRUCTOR_CODE // 35 | ///*/// 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /examples/04_Classes.anil: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Rectangle{int length, int breadth}; 5 | 6 | namespace Rectangle 7 | function __init__(l : int, b : int) 8 | this.length = l 9 | this.breadth = b 10 | endfunction 11 | 12 | function area() 13 | let area : int = 20 14 | print("Area of the rectangle is {area}.\n") 15 | endfunction 16 | endnamespace 17 | 18 | function print_param(param : int) for Rectangle 19 | print("Parameter provided to the rectangle is {param}.\n") 20 | endfunction 21 | 22 | function main() -> int: 23 | let rect = Rectangle{10, 20}; 24 | rect.area() 25 | rect.print_param(10) 26 | return 0 27 | endfunction -------------------------------------------------------------------------------- /examples/10_FileIO.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | import Vector 15 | import String 16 | import File 17 | 18 | print("Writing to file hello.txt:\n") 19 | let outputFile = File{"hello.txt"}; 20 | outputFile.writeline("Hello World :)") 21 | 22 | 23 | print("Reading from a file(10_FileIO.c) to a string:\n") 24 | let input_str = "" 25 | input_str.set_to_file_contents("10_FileIO.c") 26 | input_str.printLn() 27 | 28 | // DESTRUCTOR_CODE // 29 | ///*/// 30 | 31 | // clang-format on 32 | 33 | return 0; 34 | } -------------------------------------------------------------------------------- /examples/Macro_With_Variadic_Arguments.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | import Vector 15 | 16 | let values = Vector{8}; 17 | values.push(1) 18 | values.push(2) 19 | values.push(3) 20 | values.push(4) 21 | values.push(5) 22 | values.push(6) 23 | values.push(7) 24 | values.push(8) 25 | 26 | def push(X...): 27 | values.allocate_more(X.size) 28 | forall x: values.push_unchecked(x) 29 | enddef 30 | 31 | push 10 20 30 40 50 60 70 80 32 | 33 | // DESTRUCTOR_CODE // 34 | ///*/// 35 | 36 | return 0; 37 | } -------------------------------------------------------------------------------- /examples/FunctionPointer_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | struct Test { 8 | char dummy; 9 | }; 10 | 11 | void ANIL_function(int p); 12 | void call_func(void (*F)(int), int value); 13 | void Testcall_func(struct Test *this, void (*F)(int), int value); 14 | 15 | void Testcall_func(struct Test *this, void (*F)(int), int value) { F(value); } 16 | 17 | void ANIL_function(int p) { printf("Hello World from function.\n"); } 18 | 19 | void call_func(void (*F)(int), int value) { F(value); } 20 | 21 | int main() { 22 | 23 | call_func(ANIL_function, 5); 24 | 25 | struct Test t; 26 | Testcall_func(&t, ANIL_function, 5); 27 | 28 | return 0; 29 | } -------------------------------------------------------------------------------- /examples/00_Hello_World_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // IMPORTS // 4 | 5 | void print_hello_world_in_ANIL(); 6 | void print_hello_world_in_c(); 7 | 8 | // ^^^ The above line denotes the start of ANIL code. 9 | void print_hello_world_in_ANIL() { 10 | printf("Hello World from ANIL function.\n"); 11 | } 12 | 13 | // In ANIL, we can implement functions in C. 14 | void print_hello_world_in_c() { 15 | printf("Hello World from C function.\n"); 16 | printf("Hello World from C function.\n"); 17 | } 18 | // VVV The below line denotes the end of ANIL code. 19 | 20 | int main() { 21 | 22 | // ^^^ Every ANIL program should start with the line above. 23 | 24 | printf("Hello World.\n"); 25 | print_hello_world_in_ANIL(); 26 | print_hello_world_in_c(); 27 | 28 | return 0; 29 | } -------------------------------------------------------------------------------- /examples/03_Dictionary.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // IMPORTS // 5 | 6 | // STRUCT_DEFINATIONS // 7 | 8 | int main() { 9 | 10 | // clang-format off 11 | 12 | ///*/// main() 13 | import Dictionary 14 | 15 | // Compile time dictionary. See Compile_Time_Constants.c 16 | // Also See, Bootstrap/lexer_test.c. 17 | constexpr NUMBERS = {"ONE" : 1, "TWO" : 2} 18 | 19 | let dict = {}; 20 | // The following line is also valid, as the above syntax is shorthand for the statement below. 21 | // let dict = Dictionary{}; 22 | dict["One"] = NUMBERS["ONE"] 23 | dict["Two"] = NUMBERS["TWO"] 24 | dict["Three"] = 3 25 | 26 | dict.print() 27 | 28 | // DESTRUCTOR_CODE // 29 | ///*/// 30 | 31 | // clang-format on 32 | 33 | return 0; 34 | } -------------------------------------------------------------------------------- /examples/08_Optional.anil: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | import Optional 6 | 7 | struct Test{char dummy}; 8 | 9 | namespace Test 10 | function return_val() -> Optional: 11 | let opt = Optional{}; 12 | opt.set_value(5) 13 | return opt 14 | endfunction 15 | 16 | function return_none() -> Optional: 17 | let opt = Optional{}; 18 | return opt 19 | endfunction 20 | endnamespace 21 | 22 | function main() -> int: 23 | let test = Test{}; 24 | 25 | let optional_int = test.return_val() 26 | if optional_int.has_value(){ 27 | let val = optional_int.get_value() 28 | print("Value is {val}") 29 | } 30 | 31 | let opt = Optional{}; 32 | opt.set_value(5) 33 | 34 | return 0 35 | endfunction -------------------------------------------------------------------------------- /Lib/UniquePtr.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | 4 | struct UniquePtr{T *arr}; 5 | 6 | namespace UniquePtr 7 | 8 | c_function __init__(capacity : int) 9 | this->arr = (@TEMPLATED_DATA_TYPE@ *)malloc(capacity * sizeof(@TEMPLATED_DATA_TYPE@)); 10 | 11 | if (this->arr == NULL) { 12 | fprintf(stderr, "Memory allocation failed.\n"); 13 | exit(EXIT_FAILURE); 14 | } 15 | endc_function 16 | 17 | function __call_destructor_if_available__() 18 | // If arr has a destructor, then emit 'arr.__del__()'. 19 | // Otherwise emit nothing. 20 | // Evaluated at compile time. 21 | ~arr 22 | endfunction 23 | 24 | c_function __free__ptr() 25 | free(this->arr); 26 | endc_function 27 | 28 | function __del__() 29 | this.__call_destructor_if_available__() 30 | this.__free__ptr() 31 | endfunction 32 | endnamespace 33 | 34 | ///*/// 35 | -------------------------------------------------------------------------------- /Lib/Set.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | 4 | /////////////////////////////////////////// 5 | struct Set{Vector arr}; 6 | 7 | namespace Set 8 | 9 | function len() -> size_t: 10 | return this.arr.len() 11 | endfunction 12 | 13 | function __getitem__(index : int) -> &String: 14 | return this.arr[index] 15 | endfunction 16 | 17 | function __init__(count : int) 18 | this.arr.__init__(count) 19 | endfunction 20 | 21 | function __contains__(value : String) -> bool: 22 | return value in this.arr 23 | endfunction 24 | 25 | function add(value : String) 26 | if value not in this{ 27 | this.arr.push(value) 28 | } 29 | endfunction 30 | 31 | function print() 32 | print("[") 33 | for str in this{ 34 | str.print() 35 | print(",") 36 | } 37 | print("]\n") 38 | endfunction 39 | 40 | endnamespace 41 | ///*/// 42 | 43 | -------------------------------------------------------------------------------- /examples/FunctionPointer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | ///*/// 10 | // clang-format off 11 | 12 | function ANIL_function(p: int) 13 | print("Hello World from function.\n") 14 | endfunction 15 | 16 | function call_func(F: Fn(int) -> void, value : int) 17 | F(value); 18 | endfunction 19 | 20 | struct Test{char dummy}; 21 | 22 | namespace Test 23 | 24 | function call_func(F: Fn(int) -> void, value : int) 25 | F(value); 26 | endfunction 27 | 28 | endnamespace 29 | 30 | ///*/// 31 | // clang-format on 32 | 33 | int main() { 34 | // clang-format off 35 | 36 | ///*/// main() 37 | 38 | call_func(ANIL_function, 5) 39 | 40 | let t = Test{}; 41 | t.call_func(ANIL_function, 5) 42 | 43 | // DESTRUCTOR_CODE // 44 | ///*/// 45 | 46 | // clang-format on 47 | 48 | return 0; 49 | } -------------------------------------------------------------------------------- /examples/00_Hello_World.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // IMPORTS // 4 | 5 | // STRUCT_DEFINATIONS // 6 | 7 | ///*/// 8 | // ^^^ The above line denotes the start of ANIL code. 9 | function print_hello_world_in_ANIL() 10 | print("Hello World from ANIL function.\n") 11 | endfunction 12 | 13 | // In ANIL, we can implement functions in C. 14 | c_function print_hello_world_in_c() 15 | printf("Hello World from C function.\n"); 16 | printf("Hello World from C function.\n"); 17 | endc_function 18 | // VVV The below line denotes the end of ANIL code. 19 | ///*/// 20 | 21 | int main() { 22 | 23 | // clang-format off 24 | 25 | ///*/// main() 26 | // ^^^ Every ANIL program should start with the line above. 27 | 28 | print("Hello World.\n") 29 | print_hello_world_in_ANIL() 30 | print_hello_world_in_c() 31 | 32 | // DESTRUCTOR_CODE // 33 | ///*/// 34 | 35 | // clang-format on 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /examples/04_Classes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // IMPORTS // 5 | 6 | // STRUCT_DEFINATIONS // 7 | 8 | // clang-format off 9 | 10 | ///*/// 11 | struct Rectangle{int length, int breadth}; 12 | 13 | namespace Rectangle 14 | 15 | function __init__(l : int, b : int) 16 | this.length = l 17 | this.breadth = b 18 | endfunction 19 | 20 | function area() 21 | let area : int = 20 22 | print("Area of the rectangle is {area}.\n") 23 | endfunction 24 | 25 | endnamespace 26 | 27 | function print_param(param : int) for Rectangle 28 | print("Parameter provided to the rectangle is {param}.\n") 29 | endfunction 30 | 31 | 32 | ///*/// 33 | 34 | int main() { 35 | 36 | // clang-format off 37 | 38 | ///*/// main() 39 | 40 | let rect = Rectangle{10, 20}; 41 | rect.area() 42 | rect.print_param(10) 43 | 44 | // DESTRUCTOR_CODE // 45 | ///*/// 46 | 47 | // clang-format on 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /examples/04_Classes_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // IMPORTS // 5 | 6 | struct Rectangle { 7 | int length; 8 | int breadth; 9 | }; 10 | 11 | void Rectangle__init__(struct Rectangle *this, int l, int b); 12 | void Rectanglearea(struct Rectangle *this); 13 | 14 | void Rectangleprint_param(struct Rectangle *this, int param); 15 | 16 | void Rectangle__init__(struct Rectangle *this, int l, int b) { 17 | this->length = l; 18 | this->breadth = b; 19 | } 20 | 21 | void Rectanglearea(struct Rectangle *this) { 22 | int area = 20; 23 | printf("Area of the rectangle is %d.\n", area); 24 | } 25 | 26 | void Rectangleprint_param(struct Rectangle *this, int param) { 27 | printf("Parameter provided to the rectangle is %d.\n", param); 28 | } 29 | 30 | int main() { 31 | 32 | struct Rectangle rect; 33 | Rectangle__init__(&rect, 10, 20); 34 | Rectanglearea(&rect); 35 | Rectangleprint_param(&rect, 10); 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /examples/04_Classes_generated_anil.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | struct Rectangle { 6 | int length; 7 | int breadth; 8 | }; 9 | 10 | void Rectangle__init__(struct Rectangle *this, int l, int b); 11 | void Rectanglearea(struct Rectangle *this); 12 | 13 | void Rectangleprint_param(struct Rectangle *this, int param); 14 | int main(); 15 | 16 | void Rectangle__init__(struct Rectangle *this, int l, int b) { 17 | this->length = l; 18 | this->breadth = b; 19 | } 20 | 21 | void Rectanglearea(struct Rectangle *this) { 22 | int area = 20; 23 | printf("Area of the rectangle is %d.\n", area); 24 | } 25 | 26 | void Rectangleprint_param(struct Rectangle *this, int param) { 27 | printf("Parameter provided to the rectangle is %d.\n", param); 28 | } 29 | 30 | int main() { 31 | struct Rectangle rect; 32 | Rectangle__init__(&rect, 10, 20); 33 | Rectanglearea(&rect); 34 | Rectangleprint_param(&rect, 10); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /examples/08_Optional.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | 15 | import Optional 16 | 17 | struct Test{char dummy}; 18 | 19 | namespace Test 20 | function return_val() -> Optional: 21 | let opt = Optional{}; 22 | opt.set_value(5) 23 | return opt 24 | endfunction 25 | 26 | function return_none() -> Optional: 27 | let opt = Optional{}; 28 | return opt 29 | endfunction 30 | endnamespace 31 | 32 | let test = Test{}; 33 | 34 | let optional_int = test.return_val() 35 | if optional_int.has_value(){ 36 | let val = optional_int.get_value() 37 | print("Value is {val}") 38 | } 39 | 40 | let opt = Optional{}; 41 | opt.set_value(5) 42 | 43 | 44 | // DESTRUCTOR_CODE // 45 | ///*/// 46 | 47 | // clang-format on 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /examples/TestSuites/Expression_parse_tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | 15 | import Vector 16 | import String 17 | 18 | let p_index : int = 5 19 | 20 | let s1 = "Hello World" 21 | 22 | if s1[2] == "\\"{ 23 | s1 += "\\" 24 | } 25 | 26 | let string_to_insert = "*****" 27 | 28 | let left_part = s1.substr(0, p_index) 29 | left_part += string_to_insert + s1.substr(p_index, s1.len() - p_index) 30 | 31 | let vec = Vector{10}; 32 | 33 | vec.push(10) 34 | vec.push(20) 35 | 36 | let x : int = 69420 37 | let y : int = s1.len() 38 | let v : int = s1.len() + x + y - 100 - s1.len() + vec[0] 39 | 40 | print("The magic number is {x}.\n"); 41 | print("Expression value is is {v}.\n"); 42 | 43 | // DESTRUCTOR_CODE // 44 | ///*/// 45 | 46 | // clang-format on 47 | 48 | return 0; 49 | } -------------------------------------------------------------------------------- /examples/decorators_inside_fn_body.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // clang-format off 6 | 7 | // IMPORTS // 8 | 9 | // STRUCT_DEFINATIONS // 10 | 11 | 12 | ///*/// 13 | 14 | struct Node{int m_data}; 15 | 16 | namespace Node 17 | c_function __init__(p_data : int) 18 | this->m_data = p_data; 19 | endc_function 20 | 21 | c_function print() 22 | int data = this->m_data; 23 | 24 | @hook_begin("custom_integer_printer" "int" data) 25 | printf("%d \n", data); 26 | @hook_end 27 | endc_function 28 | endnamespace 29 | ///*/// 30 | 31 | void CustomIntPrint(int data) { 32 | printf("[CustomIntegerPrinter] Int = %d \n", data); 33 | } 34 | 35 | int main() { 36 | 37 | 38 | ///*/// main() 39 | 40 | let node = Node{10}; 41 | 42 | node.print() 43 | 44 | @apply_hook("custom_integer_printer", CustomIntPrint) 45 | node.print() 46 | 47 | // DESTRUCTOR_CODE // 48 | ///*/// 49 | 50 | // clang-format on 51 | 52 | return 0; 53 | } -------------------------------------------------------------------------------- /Lib/File.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | struct File{FILE* file_ptr}; 4 | 5 | namespace File 6 | c_function __init__(p_file_name : str) 7 | // Change mode from "w" to "wb". 8 | // This prevents the C runtime from translating '\n' to '\r\n', 9 | // which was causing double newlines while writing the content of Windows control, 10 | // because the input string from the Windows control already contained '\r\n'. 11 | this->file_ptr = fopen(p_file_name, "wb"); 12 | if(this->file_ptr == NULL) { 13 | printf("Failed to open file %s.\n", p_file_name); 14 | exit(0); 15 | } 16 | endc_function 17 | 18 | c_function write(p_content : str) 19 | fprintf(this->file_ptr, "%s", p_content); 20 | endc_function 21 | 22 | c_function writeline(p_content : str) 23 | // Write a line to the file with terminating newline. 24 | fprintf(this->file_ptr, "%s\n", p_content); 25 | endc_function 26 | 27 | c_function __del__() 28 | fclose(this->file_ptr); 29 | endc_function 30 | endnamespace 31 | ///*/// 32 | 33 | -------------------------------------------------------------------------------- /ErrorHandler.py: -------------------------------------------------------------------------------- 1 | class ErrorHandler: 2 | _instance = None 3 | 4 | def __new__(cls): 5 | if cls._instance is None: 6 | cls._instance = super().__new__(cls) 7 | cls._instance.current_line_code = "" 8 | cls._instance.source_file = "" 9 | return cls._instance 10 | 11 | def register_source_file(self, source_file: str) -> None: 12 | self.source_file = source_file 13 | 14 | def register_current_line_code(self, current_line_code: str) -> None: 15 | """ 16 | Register the line which we are currently parsing. 17 | This line is printed along with the error message. 18 | """ 19 | self.current_line_code = current_line_code 20 | 21 | def raise_error(self, error): 22 | line = self.current_line_code.strip() 23 | error_msg = ( 24 | f"Error in compiling '{self.source_file}' " 25 | f'at line "{line}" :\n' 26 | f"{error}" 27 | ) 28 | raise Exception(f"{error_msg}") 29 | -------------------------------------------------------------------------------- /examples/04_b_Classes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // IMPORTS // 5 | 6 | // STRUCT_DEFINATIONS // 7 | 8 | int main() { 9 | 10 | // clang-format off 11 | 12 | ///*/// main() 13 | 14 | struct Point {int x, int y}; 15 | let p1 = Point{20, 50}; 16 | 17 | namespace Point 18 | c_function say() 19 | // We write normal C code inside c_function. 20 | // Use this-> pointer to access member variables. 21 | printf("x : %d , y : %d \n", this->x, this->y); 22 | endc_function 23 | 24 | c_function shout() 25 | printf("Shouting Point Values, x = %d.\n", this->x); 26 | endc_function 27 | endnamespace 28 | 29 | p1.say() 30 | p1.shout() 31 | 32 | struct GenericStruct{X a, float b}; 33 | 34 | let t1 = GenericStruct{10,20}; 35 | let t2 = GenericStruct{10,20}; 36 | 37 | struct Vector{T* arr,int size,int capacity}; 38 | 39 | let vec2 = Vector{NULL, 10, 20}; 40 | let vec3 = Vector{NULL, 10, 20}; 41 | 42 | // DESTRUCTOR_CODE // 43 | ///*/// 44 | 45 | // clang-format on 46 | 47 | return 0; 48 | } -------------------------------------------------------------------------------- /examples/TestSuites/slicing.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | import Vector 15 | 16 | let a = Vector{10}; 17 | a.push("1") 18 | a.push("2") 19 | a.push("3") 20 | a.push("4") 21 | a.push("5") 22 | 23 | print("Printing in normal order(step 1): 1,2,3,4,5 \n") 24 | for a1 in a[::1]{ 25 | print("{a1} ") 26 | } 27 | 28 | print("\nPrinting in normal order(step 1) in between (2,..): 3,4,5 \n") 29 | for a1 in a[2::1]{ 30 | print("{a1} ") 31 | } 32 | 33 | print("\nPrinting in normal order(step 1) in between (2,4): 3,4 \n") 34 | for a1 in a[2:4:1]{ 35 | print("{a1} ") 36 | } 37 | 38 | print("\nPrinting in normal order(step 2): 1,3,5 \n") 39 | for a1 in a[::2]{ 40 | print("{a1} ") 41 | } 42 | 43 | print("\nPrinting in reverse order: 5,4,3,2,1 \n") 44 | for a1 in a[::-1]{ 45 | print("{a1} ") 46 | } 47 | 48 | // DESTRUCTOR_CODE // 49 | ///*/// 50 | 51 | // clang-format on 52 | 53 | return 0; 54 | } -------------------------------------------------------------------------------- /examples/decorators_inside_fn_body_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | struct Node { 8 | int m_data; 9 | }; 10 | 11 | void Node__init__(struct Node *this, int p_data); 12 | void Nodeprint(struct Node *this); 13 | 14 | void Node__init__(struct Node *this, int p_data) { this->m_data = p_data; } 15 | 16 | void Nodeprint(struct Node *this) { 17 | int data = this->m_data; 18 | 19 | //@hook_begin("custom_integer_printer" "int" data) 20 | printf("%d \n", data); 21 | //@hook_end 22 | } 23 | 24 | typedef void (*custom_integer_printer)(int); 25 | void Nodeprint_hooked_custom_integer_printer( 26 | struct Node *this, custom_integer_printer p_custom_integer_printer) { 27 | int data = this->m_data; 28 | 29 | // 30 | p_custom_integer_printer(data); 31 | } 32 | 33 | void CustomIntPrint(int data) { 34 | printf("[CustomIntegerPrinter] Int = %d \n", data); 35 | } 36 | 37 | int main() { 38 | 39 | struct Node node; 40 | Node__init__(&node, 10); 41 | 42 | Nodeprint(&node); 43 | 44 | Nodeprint_hooked_custom_integer_printer(&node, CustomIntPrint); 45 | 46 | return 0; 47 | } -------------------------------------------------------------------------------- /examples/01_variables.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | 15 | let x : int = 69420 16 | print("The magic number is {x}.\n"); 17 | 18 | // Char uses " " but the contents inside it should be of length 1. 19 | let gender : char = "M" 20 | print("The gender is {gender}. \n"); 21 | 22 | let arr = [1, 2, 3, 4, 5, 10]; 23 | for value2 in arr{ 24 | print("{value2} \n") 25 | } 26 | 27 | if 10 in arr{ 28 | print("10 is in arr. \n") 29 | } 30 | 31 | let arr2 = [1, 2, 3, 4, 5, 10]; 32 | for value3 in arr2{ 33 | print("{value3} \n") 34 | } 35 | 36 | for i in range(1..10){ 37 | print("{i}\n") 38 | } 39 | 40 | for i in range(1..10,2){ 41 | print("{i}\n") 42 | } 43 | 44 | for i in range(1..=10){ 45 | print("{i}\n") 46 | } 47 | 48 | for i in range(1..=10,2){ 49 | print("{i}\n") 50 | } 51 | 52 | for i in range(1..=10,-2){ 53 | print("{i}\n") 54 | } 55 | 56 | // DESTRUCTOR_CODE // 57 | ///*/// 58 | 59 | // clang-format on 60 | 61 | return 0; 62 | } -------------------------------------------------------------------------------- /examples/Reflection.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | import Vector 15 | import List 16 | 17 | let vector_class_members = []; 18 | let vector_class_member_functions = []; 19 | let list_instances = []; 20 | 21 | def reflection(): 22 | forall x in members_of(Vector): vector_class_members.append_str(x) 23 | forall x in member_functions_of(Vector): vector_class_member_functions.append_str(x) 24 | forall x in instances_of_class(List): list_instances.append_str(x) 25 | enddef 26 | reflection 27 | // ^^^^^^^ just writing the macro name calls the macro. 28 | print("We print the different instances of class List using Reflection as follows: \n") 29 | 30 | // 'instances_of_class' returns name of the instances in "string" form, 31 | // so, we unquote that using UNQUOTE in macro as belows. 32 | def reflective_print(): 33 | forall x in instances_of_class(List) UNQUOTE: x.print() 34 | enddef 35 | reflective_print 36 | 37 | // DESTRUCTOR_CODE // 38 | ///*/// 39 | 40 | return 0; 41 | } -------------------------------------------------------------------------------- /examples/Enumerate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct iterator { 5 | int *begin; 6 | int *end; 7 | int *curr; 8 | }; 9 | 10 | struct enumerator { 11 | int index; 12 | int val; 13 | }; 14 | 15 | typedef struct iterator Iterator; 16 | typedef struct enumerator Enumerator; 17 | 18 | bool can_iterate(Iterator iter) { return iter.curr <= iter.end; } 19 | 20 | int curr_iter_value(Iterator iter) { return *iter.curr; } 21 | 22 | int next_iter(Iterator *iter) { 23 | int val = curr_iter_value(*iter); 24 | iter->curr++; 25 | return val; 26 | } 27 | 28 | bool enumerate(Iterator *iter, Enumerator *enumerator) { 29 | if (!can_iterate(*iter)) { 30 | return false; 31 | } 32 | 33 | enumerator->index++; 34 | enumerator->val = next_iter(iter); 35 | 36 | return true; 37 | } 38 | 39 | Iterator create_iterator_from_array(int *array, int len) { 40 | Iterator it; 41 | it.begin = array; 42 | it.end = array + len - 1; 43 | it.curr = it.begin; 44 | return it; 45 | } 46 | 47 | int main() { 48 | 49 | // clang-format off 50 | 51 | ///*/// main() 52 | 53 | let arr = [ 1, 2, 3, 4, 5 ]; 54 | for index,value in enumerate arr{ 55 | print("index : {index} value : {value} \n") 56 | } 57 | 58 | ///*/// 59 | 60 | // clang-format on 61 | 62 | return 0; 63 | } -------------------------------------------------------------------------------- /examples/02_List.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | import List 15 | 16 | let test_list = [] 17 | // The following line is also valid, as the above syntax is shorthand for the statement below. 18 | // let test_list = List{}; 19 | 20 | // append is an overloaded function. 21 | // append_str() and append_int() are explicit versions, 22 | // which are called by the overloaded append functions. 23 | // test_list.append_str("Hello") 24 | // test_list.append_int(10) 25 | 26 | test_list.append("Hello") 27 | test_list.append("World") 28 | test_list.append("Puppy") 29 | 30 | test_list.append(10) 31 | test_list.append(20) 32 | test_list.append(30) 33 | test_list.append(40) 34 | test_list.append(50) 35 | 36 | let node = test_list.pop(7) 37 | 38 | test_list.print() 39 | 40 | if 10 in test_list{ 41 | print("10 is in the list.\n") 42 | } 43 | 44 | if 5 not in test_list{ 45 | print("5 is not in the list.\n") 46 | } 47 | 48 | print("Duplicating List: ") 49 | let test_list2 = [] 50 | test_list2 = test_list 51 | test_list2.print() 52 | 53 | // DESTRUCTOR_CODE // 54 | ///*/// 55 | 56 | // clang-format on 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /examples/04_b_Classes_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // IMPORTS // 5 | 6 | struct Point { 7 | int x; 8 | int y; 9 | }; 10 | 11 | struct GenericStruct_float { 12 | float a; 13 | float b; 14 | }; 15 | 16 | struct GenericStruct_int { 17 | int a; 18 | float b; 19 | }; 20 | 21 | struct Vector_int { 22 | int *arr; 23 | int size; 24 | int capacity; 25 | }; 26 | 27 | struct Vector_float { 28 | float *arr; 29 | int size; 30 | int capacity; 31 | }; 32 | 33 | void Pointsay(struct Point *this); 34 | void Pointshout(struct Point *this); 35 | 36 | void Pointsay(struct Point *this) { 37 | // We write normal C code inside c_function. 38 | // Use this-> pointer to access member variables. 39 | printf("x : %d , y : %d \n", this->x, this->y); 40 | } 41 | 42 | void Pointshout(struct Point *this) { 43 | printf("Shouting Point Values, x = %d.\n", this->x); 44 | } 45 | 46 | int main() { 47 | 48 | struct Point p1; 49 | p1.x = 20; 50 | p1.y = 50; 51 | 52 | Pointsay(&p1); 53 | Pointshout(&p1); 54 | 55 | struct GenericStruct_float t1; 56 | t1.a = 10; 57 | t1.b = 20; 58 | struct GenericStruct_int t2; 59 | t2.a = 10; 60 | t2.b = 20; 61 | 62 | struct Vector_int vec2; 63 | vec2.arr = NULL; 64 | vec2.size = 10; 65 | vec2.capacity = 20; 66 | struct Vector_float vec3; 67 | vec3.arr = NULL; 68 | vec3.size = 10; 69 | vec3.capacity = 20; 70 | 71 | return 0; 72 | } -------------------------------------------------------------------------------- /examples/11_Threads_And_Channels.anil: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | import Threads 6 | 7 | let ch = Channel{10}; 8 | 9 | function Task() 10 | while true{ 11 | let res = ch.receive_int() 12 | if res.is_ok(){ 13 | let value = res.get_value() 14 | print("Worker: Received {value} \n") 15 | } else{ 16 | print("Worker: Channel is closed and empty. Exiting. \n") 17 | break; 18 | } 19 | } 20 | endfunction 21 | 22 | c_function WorkerThread(arg : ThreadInternalVoidPointer) -> ThreadInternalVoidPointer: 23 | Task(); 24 | return NULL; 25 | endc_function 26 | 27 | function main() -> int: 28 | print("Main: Created a channel with capacity 10. \n") 29 | 30 | print("Main: Starting worker thread. \n") 31 | 32 | let channelAsVoidPointer = ch.ToThreadVoidPointer() 33 | // the above void* casting can be done by Thread itself. 34 | let worker = Thread{WorkerThread, channelAsVoidPointer}; 35 | 36 | for i in range(1..50){ 37 | print("Main: Sending {i} \n") 38 | 39 | let res = ch.send(i) 40 | 41 | if res == false{ 42 | print("Main: Failed to send data, channel is closed.\n") 43 | break; 44 | } 45 | 46 | } 47 | 48 | print("Main: All items sent. Closing channel.\n") 49 | ch.close() 50 | 51 | print("Main: Waiting for worker to finish...\n") 52 | worker.join() 53 | 54 | print("Main: Program finished successfully.\n") 55 | 56 | return 0 57 | endfunction -------------------------------------------------------------------------------- /examples/Enumerate_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct iterator { 5 | int *begin; 6 | int *end; 7 | int *curr; 8 | }; 9 | 10 | struct enumerator { 11 | int index; 12 | int val; 13 | }; 14 | 15 | typedef struct iterator Iterator; 16 | typedef struct enumerator Enumerator; 17 | 18 | bool can_iterate(Iterator iter) { return iter.curr <= iter.end; } 19 | 20 | int curr_iter_value(Iterator iter) { return *iter.curr; } 21 | 22 | int next_iter(Iterator *iter) { 23 | int val = curr_iter_value(*iter); 24 | iter->curr++; 25 | return val; 26 | } 27 | 28 | bool enumerate(Iterator *iter, Enumerator *enumerator) { 29 | if (!can_iterate(*iter)) { 30 | return false; 31 | } 32 | 33 | enumerator->index++; 34 | enumerator->val = next_iter(iter); 35 | 36 | return true; 37 | } 38 | 39 | Iterator create_iterator_from_array(int *array, int len) { 40 | Iterator it; 41 | it.begin = array; 42 | it.end = array + len - 1; 43 | it.curr = it.begin; 44 | return it; 45 | } 46 | 47 | int main() { 48 | 49 | int arr[] = {1, 2, 3, 4, 5}; 50 | unsigned int arr_array_size = 5; 51 | 52 | Iterator arr_iter = create_iterator_from_array(arr, arr_array_size); 53 | Enumerator arr_enumerator; 54 | arr_enumerator.index = -1; 55 | 56 | while (enumerate(&arr_iter, &arr_enumerator)) { 57 | int index = arr_enumerator.index; 58 | int value = arr_enumerator.val; 59 | printf("index : %d value : %d \n", index, value); 60 | } 61 | 62 | return 0; 63 | } -------------------------------------------------------------------------------- /examples/Compile_Time_Constants.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | // let color2 = Color["red"] 14 | // This will produce error below, because Color has "Red" and not "red". 15 | 16 | // Currently we Support {"String" : int} dictionary only. 17 | 18 | ///*/// main() 19 | 20 | // Compile time dictionaries. 21 | // These acts as contants, and the individual values of these constants 22 | // will be placed in code at compile time. 23 | import Vector 24 | import String 25 | 26 | constexpr Color = {"Red":255, "Green":200} 27 | constexpr Age = {"Anil":22, "Universe":10000} 28 | 29 | let color = Color["Red"] 30 | let color2 = Color["Green"] 31 | 32 | let age1 = Age["Anil"] 33 | let age2 = Age["Universe"] 34 | 35 | constexpr RGBMap = {"Red" : "225,0,0", "Green" : "0,255,0", default : "255,255,255"} 36 | 37 | let red = RGBMap["Red"] 38 | print("Red Color RGB: {red} \n") 39 | 40 | let green = RGBMap["Green"] 41 | print("Green Color RGB: {green} \n") 42 | 43 | let default_color = RGBMap["whatever"] 44 | print("Default Color RGB: {default_color} \n") 45 | 46 | let g_key = "Green" 47 | let contexpr_at_runtime_color = RGBMap[g_key] 48 | print("Green Color RGB fetched from constexpr map at runtime: {contexpr_at_runtime_color} \n") 49 | 50 | // DESTRUCTOR_CODE // 51 | ///*/// 52 | 53 | // clang-format on 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /examples/01_variables_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | int main() { 8 | 9 | int x = 69420; 10 | printf("The magic number is %d.\n", x); 11 | 12 | // Char uses " " but the contents inside it should be of length 1. 13 | char gender = 'M'; 14 | printf("The gender is %c. \n", gender); 15 | 16 | int arr[] = {1, 2, 3, 4, 5, 10}; 17 | unsigned int arr_array_size = 6; 18 | 19 | for (unsigned int i = 0; i < arr_array_size; i++) { 20 | int value2 = arr[i]; 21 | printf("%d \n", value2); 22 | } 23 | 24 | bool arr__contains__10_0 = false; 25 | for (unsigned int i = 0; i < arr_array_size; i++) { 26 | if (arr[i] == 10) { 27 | arr__contains__10_0 = true; 28 | break; 29 | } 30 | } 31 | 32 | if (arr__contains__10_0) { 33 | printf("10 is in arr. \n"); 34 | } 35 | 36 | float arr2[] = {1, 2, 3, 4, 5, 10}; 37 | unsigned int arr2_array_size = 6; 38 | 39 | for (unsigned int i = 0; i < arr2_array_size; i++) { 40 | float value3 = arr2[i]; 41 | printf("%f \n", value3); 42 | } 43 | 44 | for (size_t i = 1; i < 10; i++) { 45 | printf("%llu\n", i); 46 | } 47 | 48 | for (size_t i = 1; i < 10; i += 2) { 49 | printf("%llu\n", i); 50 | } 51 | 52 | for (size_t i = 1; i <= 10; i++) { 53 | printf("%llu\n", i); 54 | } 55 | 56 | for (size_t i = 1; i <= 10; i += 2) { 57 | printf("%llu\n", i); 58 | } 59 | 60 | for (size_t i = 10; i >= 1; i += -2) { 61 | printf("%llu\n", i); 62 | } 63 | 64 | return 0; 65 | } -------------------------------------------------------------------------------- /Bootstrap/Dict_int_string.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | // Dictionary of > 4 | // This is just for Symbol Table in preprocess_test as we dont have Dictionary as of now. 5 | struct int_str_list{int key, Vector value}; 6 | namespace int_str_list 7 | function __init__(p_key : int) 8 | this.key = p_key 9 | this.value.__init__(5) 10 | endfunction 11 | endnamespace 12 | 13 | namespace Vector 14 | function __contains__(value : T) -> bool: 15 | for pair in this{ 16 | if pair.key == value.key{ 17 | // FIXME: Incomplete implementation. 18 | return true 19 | } 20 | } 21 | return false 22 | endfunction 23 | endnamespace 24 | 25 | // Ordered Dictionary of key(int) and value(list of string). 26 | struct Dict_int_string{Vector pairs}; 27 | namespace Dict_int_string 28 | function __init__() 29 | this.pairs.__init__(5) 30 | endfunction 31 | 32 | function __contains__(p_key : int) -> bool: 33 | let found : bool = false 34 | for pair in this.pairs{ 35 | if pair.key == p_key{ 36 | found = True 37 | // no break because the pair should be destructed at the end of the scope. 38 | // break doesn't do that as of now. 39 | } 40 | } 41 | return found 42 | endfunction 43 | 44 | c_function key_exists_quit() 45 | fprintf(stderr, "Pop from empty Vector.\n"); 46 | exit(EXIT_FAILURE); 47 | endc_function 48 | 49 | function add_key(p_key : int) 50 | if p_key in this{ 51 | this.key_exists_quit() 52 | }else{ 53 | let s = int_str_list{p_key}; 54 | this.pairs.push(s) 55 | } 56 | endfunction 57 | endnamespace 58 | ///*/// 59 | 60 | 61 | -------------------------------------------------------------------------------- /examples/06_Vector.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | import Vector 15 | import String 16 | 17 | let a = Vector{10}; 18 | a.push(10) 19 | a.push(20) 20 | a.push(30) 21 | a.push(40) 22 | a.push(50) 23 | a.print() 24 | 25 | if 10 in a{ 26 | print("10 is in the vector. \n") 27 | } 28 | 29 | print("Removing index 2 item.\n") 30 | a.remove_at(2) 31 | 32 | a.print() 33 | print("\n") 34 | 35 | let b = Vector{10}; 36 | b.push(10) 37 | b.push(40) 38 | b.push(50) 39 | b.print() 40 | 41 | let string = Vector{10}; 42 | string.push("A") 43 | string.push("N") 44 | string.push("I") 45 | string.push("L") 46 | string.print() 47 | 48 | let str = "Hello" 49 | let str2 = "World" 50 | let str3 = "Honey" 51 | let str4 = "Bunny" 52 | 53 | let test = Vector{5}; 54 | // Push Strings to Vector 55 | test.push(str) 56 | test.push(str2) 57 | test.push(str3) 58 | test.push(str4) 59 | test.print() 60 | 61 | for tst in test[::-1]{ 62 | tst.print() 63 | } 64 | 65 | print("\nClearing Vector:\n") 66 | test.clear() 67 | test.print() 68 | 69 | print("\nPushing String to Vector:\n") 70 | test.push(str) 71 | test.push(str2) 72 | test.print() 73 | 74 | print("\nReplacing with the above vector[1] with str which is Hello:\n") 75 | test[1] = str 76 | test.print() 77 | 78 | // DESTRUCTOR_CODE // 79 | ///*/// 80 | 81 | // clang-format on 82 | 83 | return 0; 84 | } -------------------------------------------------------------------------------- /examples/TestSuites/Return_value_tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // IMPORTS // 5 | 6 | // STRUCT_DEFINATIONS // 7 | 8 | ///*/// 9 | import Vector 10 | import String 11 | import Optional 12 | 13 | function return_test_bool(p_str : String) -> bool: 14 | let a = "Test String" 15 | return p_str in a 16 | endfunction 17 | 18 | function return_test_struct_in_struct(p_str : String) -> bool: 19 | let z = Vector{5}; 20 | return p_str in z 21 | endfunction 22 | 23 | function return_test_equals(p_str : String, p_str2 : String) -> bool: 24 | return p_str == p_str2 25 | endfunction 26 | 27 | function return_test_equals2(p_str : String) -> bool: 28 | let a = "Test String" 29 | return p_str == a 30 | endfunction 31 | 32 | function return_test_equals3() -> bool: 33 | let a = "Test String" 34 | let b = "Test String" 35 | return a == b 36 | endfunction 37 | 38 | function return_normal_value() -> String: 39 | let a = "Test String" 40 | return a 41 | endfunction 42 | 43 | function return_test_array() -> bool: 44 | let arr = [1, 2, 3, 4, 5, 10]; 45 | 46 | if 10 in arr{ 47 | return true 48 | } 49 | 50 | return false 51 | endfunction 52 | 53 | function return_test_array2() -> bool: 54 | let value : int = 10 55 | let arr = [1, 2, 3, 4, 5, 10]; 56 | 57 | return value in arr 58 | endfunction 59 | 60 | ///*/// 61 | 62 | int main() { 63 | 64 | // clang-format off 65 | 66 | ///*/// main() 67 | 68 | print("Code Generation Tests for return expressions, Just check if the code generated is valid.") 69 | 70 | // DESTRUCTOR_CODE // 71 | ///*/// 72 | // clang-format on 73 | 74 | return 0; 75 | } -------------------------------------------------------------------------------- /examples/WebServer.c: -------------------------------------------------------------------------------- 1 | //gcc -o .\WebServer .\WebServer_generated.c -lws2_32 2 | #include 3 | 4 | // IMPORTS // 5 | 6 | // STRUCT_DEFINATIONS // 7 | 8 | ///*/// 9 | import HTTPServer 10 | 11 | function Handle404(res : Response, req : Request) 12 | const html = "

404 Page Not Found

\r\n" 13 | res.send(html, 404) 14 | endfunction 15 | 16 | @route("GET", "/about") 17 | function HandleAbout(res : Response, req : Request) 18 | const html = "

About Us Page

\r\n" 19 | res.send(html, 200) 20 | endfunction 21 | 22 | @route("GET", "/home") 23 | @route("GET", "/") 24 | function HandleHome(res : Response, req : Request) 25 | const html = "

Welcome to Home Page!

\r\n" 26 | res.send(html, 200) 27 | endfunction 28 | ///*/// 29 | 30 | int main() { 31 | 32 | // clang-format off 33 | ///*/// main() 34 | 35 | let server = HTTPServer{}; 36 | 37 | // server.register_route("GET" "/about", HandleAbout) 38 | // server.register_route("GET" "/home", HandleHome) 39 | // server.register_route("GET", "/ ", HandleHome) 40 | 41 | // Use reflection to get all functions with annotations '@route' and register those functions as routes. 42 | // This generates the code same as above. 43 | def register_routes_reflection(): 44 | forall annotated_fn_name, arg_value1, arg_value2 in annotated_functions_by_name(route) UNQUOTE: server.register_route("arg_value1", "arg_value2", annotated_fn_name) 45 | enddef 46 | register_routes_reflection 47 | 48 | server.listen(8080) 49 | 50 | // DESTRUCTOR_CODE // 51 | ///*/// 52 | 53 | // clang-format on 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /examples/09_Functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | ///*/// 10 | // clang-format off 11 | import Vector 12 | import String 13 | 14 | # Global functions. 15 | function my_first_ANIL_function() 16 | print("Hello World from function. \n") 17 | endfunction 18 | 19 | function get_format_specifier(p_type: String) -> String: 20 | let return_type_str = "d" 21 | 22 | if p_type == "char"{ 23 | return_type_str = "c" 24 | }else if p_type == "int"{ 25 | return_type_str = "d" 26 | }else if p_type == "float"{ 27 | return_type_str = "f" 28 | }else if p_type == "size_t"{ 29 | return_type_str = "llu" 30 | } 31 | 32 | return return_type_str 33 | endfunction 34 | 35 | function get_mangled_fn_name(p_struct_type: String, p_fn_name: String) -> String: 36 | let s = p_struct_type + p_fn_name 37 | return s 38 | endfunction 39 | 40 | function get_templated_mangled_fn_name(p_struct_type1: String, p_fn_name1: String, p_templated_data_type1: String) -> String: 41 | let s1 = p_struct_type1 + "_" + p_templated_data_type1 + p_fn_name1 42 | return s1 43 | endfunction 44 | 45 | ///*/// 46 | // clang-format on 47 | 48 | int main() { 49 | // clang-format off 50 | 51 | ///*/// main() 52 | let string = "Hello World from String.\n" 53 | string.print() 54 | 55 | let s5 = string 56 | 57 | my_first_ANIL_function() 58 | 59 | let class_name = "String" 60 | let fn_name = "__del__" 61 | 62 | let mangled_name = get_mangled_fn_name(class_name, fn_name) 63 | mangled_name.print() 64 | 65 | // DESTRUCTOR_CODE // 66 | ///*/// 67 | 68 | // clang-format on 69 | 70 | return 0; 71 | } -------------------------------------------------------------------------------- /examples/08_Optional_generated.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // IMPORTS // 8 | 9 | struct Test { 10 | char dummy; 11 | }; 12 | 13 | struct Optional_int { 14 | bool _has_value; 15 | int _value; 16 | }; 17 | 18 | struct Optional_int Testreturn_val(struct Test *this); 19 | struct Optional_int Testreturn_none(struct Test *this); 20 | 21 | void Optional_int__init__(struct Optional_int *this); 22 | bool Optional_inthas_value(struct Optional_int *this); 23 | int Optional_intget_value(struct Optional_int *this); 24 | void Optional_intset_value(struct Optional_int *this, int p_value); 25 | 26 | struct Optional_int Testreturn_val(struct Test *this) { 27 | struct Optional_int opt; 28 | Optional_int__init__(&opt); 29 | Optional_intset_value(&opt, 5); 30 | return opt; 31 | } 32 | 33 | struct Optional_int Testreturn_none(struct Test *this) { 34 | struct Optional_int opt; 35 | Optional_int__init__(&opt); 36 | return opt; 37 | } 38 | 39 | void Optional_int__init__(struct Optional_int *this) { 40 | this->_has_value = false; 41 | } 42 | 43 | bool Optional_inthas_value(struct Optional_int *this) { 44 | return this->_has_value; 45 | } 46 | 47 | int Optional_intget_value(struct Optional_int *this) { return this->_value; } 48 | 49 | void Optional_intset_value(struct Optional_int *this, int p_value) { 50 | this->_has_value = true; 51 | this->_value = p_value; 52 | } 53 | 54 | int main() { 55 | 56 | struct Test test; 57 | 58 | struct Optional_int optional_int = Testreturn_val(&test); 59 | 60 | if (Optional_inthas_value(&optional_int)) { 61 | int val = Optional_intget_value(&optional_int); 62 | printf("Value is %d", val); 63 | } 64 | 65 | struct Optional_int opt; 66 | Optional_int__init__(&opt); 67 | Optional_intset_value(&opt, 5); 68 | 69 | return 0; 70 | } -------------------------------------------------------------------------------- /examples/08_Optional_generated_anil.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct Test { 8 | char dummy; 9 | }; 10 | 11 | struct Optional_int { 12 | bool _has_value; 13 | int _value; 14 | }; 15 | 16 | struct Optional_int Testreturn_val(struct Test *this); 17 | struct Optional_int Testreturn_none(struct Test *this); 18 | 19 | int main(); 20 | void Optional_int__init__(struct Optional_int *this); 21 | bool Optional_inthas_value(struct Optional_int *this); 22 | int Optional_intget_value(struct Optional_int *this); 23 | void Optional_intset_value(struct Optional_int *this, int p_value); 24 | 25 | struct Optional_int Testreturn_val(struct Test *this) { 26 | struct Optional_int opt; 27 | Optional_int__init__(&opt); 28 | Optional_intset_value(&opt, 5); 29 | return opt; 30 | } 31 | 32 | struct Optional_int Testreturn_none(struct Test *this) { 33 | struct Optional_int opt; 34 | Optional_int__init__(&opt); 35 | return opt; 36 | } 37 | 38 | void Optional_int__init__(struct Optional_int *this) { 39 | this->_has_value = false; 40 | } 41 | 42 | bool Optional_inthas_value(struct Optional_int *this) { 43 | return this->_has_value; 44 | } 45 | 46 | int Optional_intget_value(struct Optional_int *this) { return this->_value; } 47 | 48 | void Optional_intset_value(struct Optional_int *this, int p_value) { 49 | this->_has_value = true; 50 | this->_value = p_value; 51 | } 52 | 53 | int main() { 54 | struct Test test; 55 | 56 | struct Optional_int optional_int = Testreturn_val(&test); 57 | 58 | if (Optional_inthas_value(&optional_int)) { 59 | int val = Optional_intget_value(&optional_int); 60 | printf("Value is %d", val); 61 | } 62 | 63 | struct Optional_int opt; 64 | Optional_int__init__(&opt); 65 | Optional_intset_value(&opt, 5); 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /batch_compile.py: -------------------------------------------------------------------------------- 1 | file_names = [ 2 | "examples\\00_Hello_World.c", 3 | "examples\\00_Hello_World.anil", 4 | "examples\\01_variables.c", 5 | "examples\\02_List.c", 6 | "examples\\03_Dictionary.c", 7 | "examples\\04_Classes.c", 8 | "examples\\04_Classes.anil", 9 | "examples\\04_b_Classes.c", 10 | "examples\\05_Strings.c", 11 | "examples\\06_Vector.c", 12 | "examples\\07_Set.c", 13 | "examples\\08_Optional.c", 14 | "examples\\08_Optional.anil", 15 | "examples\\09_Functions.c", 16 | "examples\\10_FileIO.c", 17 | "examples\\10_FileIO.anil", 18 | "examples\\11_Threads_And_Channels.anil", 19 | "examples\\Annotations.c", 20 | "examples\\Compile_Time_Constants.c", 21 | "examples\\Macro_With_Variadic_Arguments.c", 22 | "examples\\Reflection.c", 23 | "examples\\Enumerate.c", 24 | "examples\\decorators_inside_fn_body.c", 25 | "examples\\Unique_ptr_example.c", 26 | "examples\\FunctionPointer.c", 27 | "examples\\UI\\TodoAppBasic.c", 28 | "examples\\UI\\TodoAppJSX.c", 29 | "examples\\UI\\TodoAppWebServer.c", 30 | "examples\\UI\\IDE\\IDE.anil", 31 | "examples\\Variables_GUI_Input_Win.c", 32 | "examples\\WebServer.c", 33 | "examples\\TestSuites\\Expression_parse_tests.c", 34 | "examples\\TestSuites\\Return_value_tests.c", 35 | "examples\\TestSuites\\slicing.c", 36 | "examples\\raylib\\raylib_example.c", 37 | "examples\\raylib\\snake.c", 38 | "Bootstrap\\lexer_test.c", 39 | "Bootstrap\\Parser.c", 40 | "Bootstrap\\preprocess_test.c", 41 | "Bootstrap\\preprocess_test.anil", 42 | ] 43 | 44 | import subprocess 45 | 46 | for file_name in file_names: 47 | subprocess.run(["python", "preprocess_2.py", "--filename", file_name]) 48 | 49 | # for file_name in file_names: 50 | # output_file = file_name.split('.')[0] 51 | # subprocess.run(["gcc", "-Wall", "-Wextra", "-o", output_file, output_file + "_generated.c"]) -------------------------------------------------------------------------------- /examples/Variables_GUI_Input_Win.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // IMPORTS // 7 | 8 | // STRUCT_DEFINATIONS // 9 | 10 | // HWND_VARIABLE_DECLARATIONS // 11 | 12 | // Function to redirect console I/O to a console window 13 | void RedirectIOToConsole() { 14 | // Allocate a console for the current process 15 | AllocConsole(); 16 | 17 | // Redirect the STDOUT to the console 18 | FILE* fp; 19 | freopen_s(&fp, "CONOUT$", "w", stdout); 20 | freopen_s(&fp, "CONOUT$", "w", stderr); 21 | 22 | // Redirect STDIN to the console 23 | freopen_s(&fp, "CONIN$", "r", stdin); 24 | 25 | // Optional: You can set the console title if you like 26 | SetConsoleTitle(TEXT("Console Window")); 27 | } 28 | 29 | LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ 30 | switch (msg) { 31 | case WM_CREATE: 32 | // GUI_NODES_CREATION // 33 | break; 34 | 35 | case WM_COMMAND: 36 | if (LOWORD(wParam) == 1000) { // Submit Button Clicked 37 | // ASSIGN_GUI_OUTPUTS // 38 | 39 | // Close the window 40 | DestroyWindow(hwnd); 41 | } 42 | break; 43 | 44 | case WM_DESTROY: 45 | PostQuitMessage(0); 46 | break; 47 | 48 | default: 49 | return DefWindowProcW(hwnd, msg, wParam, lParam); 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow) { 56 | 57 | // clang-format off 58 | 59 | // Redirect console I/O 60 | RedirectIOToConsole(); 61 | 62 | ///*/// main() 63 | 64 |
65 | let car_age : int = 5 ## 5, 10, 15 66 | let car_mileage : int = 200 67 | let is_electric : bool = true 68 |
69 | 70 | print("Car age is {car_age} years.\n") 71 | print("Car mileage is {car_mileage} miles.\n") 72 | print("Is the car electric? {is_electric}.\n") 73 | 74 | // DESTRUCTOR_CODE // 75 | ///*/// 76 | // clang-format on 77 | 78 | return 0; 79 | } -------------------------------------------------------------------------------- /examples/05_Strings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | int main() { 10 | 11 | // clang-format off 12 | 13 | ///*/// main() 14 | import Vector 15 | import String 16 | 17 | const c_str1 = "C Style Strings\n" 18 | // Such strings are very limited in functionality and only looping as below is supported. 19 | for c in c_str1{ 20 | print("{c}") 21 | } 22 | 23 | let str = "Hello World" 24 | // The following line is also valid, as the above syntax is shorthand for the statement below. 25 | // let str = String{"Hello World"}; 26 | str.printLn() 27 | 28 | str = "Reassign" 29 | str.printLn() 30 | 31 | let str2 = "Hi \n" 32 | str2.print() 33 | 34 | let str3 = str2.strip() 35 | str3.printLn() 36 | 37 | let len = str3.len() 38 | print("Length of the string is : {len}. \n") 39 | 40 | for val in str{ 41 | print("{val} \n") 42 | } 43 | 44 | if "Wor" in str{ 45 | print("Wor is in str. \n") 46 | } 47 | 48 | if str == "Hello World"{ 49 | puts("Str is Hello World."); 50 | } 51 | 52 | str += "New message appended at the " + "end." 53 | str.printLn() 54 | 55 | str = "" 56 | 57 | let len4 = str.len() 58 | print("Length of the string is : {len4}. \n") 59 | str.printLn() 60 | 61 | let str4 = "String constructed from another string. \n" 62 | let str5 = String{str4}; 63 | str5.printLn() 64 | 65 | let str6 = "String constructed from another string 2.\n" 66 | let str7 = str6 67 | str7.printLn() 68 | 69 | let substr_str = str4.substr(0, 6); 70 | substr_str.printLn() 71 | 72 | print("Split Test: \n") 73 | let split_str = "Splitting.with.dots." 74 | split_str.printLn() 75 | let dot_split = split_str.split(".") 76 | dot_split.print() 77 | 78 | let split_str2 = "Splitting with Spaces." 79 | split_str2.printLn() 80 | let space_split = split_str2.split(" ") 81 | space_split.print() 82 | 83 | // DESTRUCTOR_CODE // 84 | 85 | ///*/// 86 | 87 | return 0; 88 | } -------------------------------------------------------------------------------- /examples/raylib/raylib_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Partial Reimplementation of 4 | // https://github.com/raysan5/raylib/blob/master/examples/shapes/shapes_basic_shapes.c 5 | 6 | // Windows Compilation: 7 | // https://github.com/raysan5/raylib/wiki/Working-on-Windows 8 | // Open C:\raylib\w64devkit\w64devkit.exe 9 | // ~ $ cd "E:\ANIL\examples\raylib" 10 | // ~ $ gcc -o raylib_example.exe raylib_example_generated.c -lraylib -lgdi32 -lwinmm 11 | // ~ $ raylib_example 12 | 13 | // IMPORTS // 14 | 15 | // STRUCT_DEFINATIONS // 16 | 17 | int main() { 18 | 19 | // clang-format off 20 | 21 | ///*/// main() 22 | 23 | import raylib 24 | 25 | let rlGOLD = rlColor{ 255, 203, 0, 255 }; 26 | let rlORANGE = rlColor{ 255, 161, 0, 255 }; 27 | let rlRED = rlColor{ 230, 41, 55, 255 }; 28 | let rlMAROON = rlColor{ 190, 33, 55, 255 }; 29 | let rlGREEN = rlColor{ 0, 228, 48, 255 }; 30 | let rlSKYBLUE = rlColor{ 102, 191, 255, 255 }; 31 | let rlDARKBLUE = rlColor{ 0, 82, 172, 255 }; 32 | let rlWHITE = rlColor{ 255, 255, 255, 255 }; 33 | let rlBLACK = rlColor{ 0, 0, 0, 255 }; 34 | let rlRAYWHITE = rlColor{ 245, 245, 245, 255 }; 35 | 36 | let screenWidth : int = 800 37 | let screenHeight : int = 600 38 | 39 | let rl = raylib{}; 40 | 41 | rl.InitWindow(screenWidth, screenHeight, "raylib basic window") 42 | rl.SetTargetFPS(60) 43 | 44 | while rl.WindowShouldOpen(){ 45 | rl.BeginDrawing() 46 | rl.ClearBackground(rlRAYWHITE) 47 | rl.DrawText("It works!", 20, 20, 20, rlRED) 48 | 49 | rl.DrawCircle(screenWidth/5, 120, 35, rlDARKBLUE) 50 | rl.DrawCircleGradient(screenWidth/5, 220, 60, rlGREEN, rlSKYBLUE) 51 | rl.DrawCircleLines(screenWidth/5, 340, 80, rlDARKBLUE) 52 | 53 | // Rectangle shapes and lines 54 | rl.DrawRectangle(screenWidth/4*2 - 60, 100, 120, 60, rlRED) 55 | rl.DrawRectangleGradientH(screenWidth/4*2 - 90, 170, 180, 130, rlMAROON, rlGOLD) 56 | rl.DrawRectangleLines(screenWidth/4*2 - 40, 320, 80, 60, rlORANGE) 57 | 58 | // NOTE: We draw all LINES based shapes together to optimize internal drawing, 59 | // this way, all LINES are rendered in a single draw pass 60 | rl.DrawLine(18, 42, screenWidth - 18, 42, rlBLACK) 61 | 62 | rl.EndDrawing() 63 | } 64 | 65 | rl.CloseWindow() 66 | 67 | // DESTRUCTOR_CODE // 68 | ///*/// 69 | // clang-format on 70 | 71 | return 0; 72 | } -------------------------------------------------------------------------------- /examples/Annotations.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef void (*fn_ptr)(); 6 | 7 | typedef struct { 8 | char *key_str; 9 | } Key; 10 | 11 | typedef struct { 12 | Key key; 13 | fn_ptr value; 14 | }KeyValuePair; 15 | 16 | typedef struct { 17 | KeyValuePair pair[45]; 18 | }KeyValuePairs; 19 | 20 | // IMPORTS // 21 | 22 | // STRUCT_DEFINATIONS // 23 | 24 | ///*/// 25 | 26 | struct FunctionDictionary{int added_values,KeyValuePairs pairs}; 27 | 28 | namespace FunctionDictionary 29 | c_function __init__() 30 | this->added_values = 0; 31 | endc_function 32 | 33 | c_function add_key_value(p_key_str : str, p_value : fn_ptr) 34 | KeyValuePair pair; 35 | pair.key.key_str = p_key_str; 36 | pair.value = p_value; 37 | this->pairs.pair[this->added_values++] = pair; 38 | endc_function 39 | 40 | c_function HandleRequest(p_str : str) { 41 | for (int i = 0; i < this->added_values; i++) { 42 | char *key = this->pairs.pair[i].key.key_str; 43 | if(strcmp(key, p_str) == 0){ 44 | fn_ptr value = this->pairs.pair[i].value; 45 | value(); 46 | return; 47 | } 48 | } 49 | printf("%s is not a valid route.\n", p_str); 50 | endc_function 51 | endnamespace 52 | 53 | @default_route("home") 54 | @route("/Home") 55 | function Home() 56 | print("Hello World\n") 57 | endfunction 58 | 59 | @route("/About") 60 | function About() 61 | print("Anil BK\n") 62 | endfunction 63 | 64 | ///*/// 65 | 66 | int main() { 67 | 68 | // clang-format off 69 | 70 | ///*/// main() 71 | 72 | let router = FunctionDictionary{}; 73 | 74 | // Add all the annotated functions using a macro. 75 | // The macro performs text replace operations so, "annotation_argument_value" in the macro below is not a string. 76 | // It will be replaced by actual value of 'annotation_argument_value'. 77 | 78 | def reflection(): 79 | forall annotated_fn_name, annotation_argument_value in annotated_functions_by_name(route) UNQUOTE: router.add_key_value("annotation_argument_value", annotated_fn_name) 80 | forall annotated_fn_name, annotation_argument_value in annotated_functions_by_name(default_route) UNQUOTE: router.add_key_value("annotation_argument_value", annotated_fn_name) 81 | enddef 82 | reflection 83 | 84 | router.HandleRequest("/Home") 85 | router.HandleRequest("/About") 86 | router.HandleRequest("/Home/1") 87 | 88 | // DESTRUCTOR_CODE // 89 | ///*/// 90 | 91 | // clang-format on 92 | 93 | return 0; 94 | } -------------------------------------------------------------------------------- /Lib/Dictionary.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define TABLE_SIZE 101 8 | 9 | unsigned int hash(char *str) { 10 | unsigned int hash = 5381; 11 | int c; 12 | while ((c = *str++)) { 13 | hash = ((hash << 5) + hash) + c; // hash * 33 + c 14 | } 15 | return hash % TABLE_SIZE; 16 | } 17 | 18 | ///*/// 19 | 20 | struct DictObject{char *key_str,T value,Self *next}; 21 | 22 | struct Dictionary{DictObject **table}; 23 | 24 | namespace Dictionary 25 | 26 | c_function __init__() 27 | this->table = (@TYPEOF(table) **)malloc(TABLE_SIZE * sizeof(@TYPEOF(table) *)); 28 | for (int i = 0; i < TABLE_SIZE; i++) { 29 | this->table[i] = NULL; 30 | } 31 | endc_function 32 | 33 | c_function __del__() 34 | for (int i = 0; i < TABLE_SIZE; i++) { 35 | @TYPEOF(table) *pair = this->table[i]; 36 | while (pair != NULL) { 37 | @TYPEOF(table) *next = pair->next; 38 | // Do not free key_str since it's not dynamically allocated 39 | free(pair); 40 | pair = next; 41 | } 42 | } 43 | free(this->table); // Free the table itself 44 | endc_function 45 | 46 | c_function __getitem__(p_key : str) -> int: 47 | unsigned int index = hash(p_key); 48 | @TYPEOF(table) *pair = this->table[index]; 49 | while (pair != NULL) { 50 | if (strcmp(pair->key_str, p_key) == 0) { 51 | return pair->value; 52 | } 53 | pair = pair->next; 54 | } 55 | return 0; 56 | endc_function 57 | 58 | c_function __setitem__(p_key_str : str, p_value : int) 59 | unsigned int index = hash(p_key_str); 60 | @TYPEOF(table) *new_pair = (@TYPEOF(table) *)malloc(sizeof(@TYPEOF(table))); 61 | new_pair->key_str = p_key_str; 62 | new_pair->value = p_value; 63 | new_pair->next = this->table[index]; 64 | this->table[index] = new_pair; 65 | endc_function 66 | 67 | c_function __contains__(p_key : str) -> bool: 68 | unsigned int index = hash(p_key); 69 | @TYPEOF(table) *pair = this->table[index]; 70 | while (pair != NULL) { 71 | if (strcmp(pair->key_str, p_key) == 0) { 72 | return true; 73 | } 74 | pair = pair->next; 75 | } 76 | return false; 77 | endc_function 78 | 79 | c_function print() 80 | printf("{\n"); 81 | for (int i = 0; i < TABLE_SIZE; i++) { 82 | @TYPEOF(table) *pair = this->table[i]; 83 | while (pair != NULL) { 84 | printf("\"%s\" : %d,\n", pair->key_str, pair->value); 85 | pair = pair->next; 86 | } 87 | } 88 | printf("}\n"); 89 | endc_function 90 | endnamespace 91 | ///*/// 92 | 93 | -------------------------------------------------------------------------------- /examples/Annotations_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef void (*fn_ptr)(); 6 | 7 | typedef struct { 8 | char *key_str; 9 | } Key; 10 | 11 | typedef struct { 12 | Key key; 13 | fn_ptr value; 14 | } KeyValuePair; 15 | 16 | typedef struct { 17 | KeyValuePair pair[45]; 18 | } KeyValuePairs; 19 | 20 | // IMPORTS // 21 | 22 | struct FunctionDictionary { 23 | int added_values; 24 | KeyValuePairs pairs; 25 | }; 26 | 27 | void FunctionDictionary__init__(struct FunctionDictionary *this); 28 | void FunctionDictionaryadd_key_value(struct FunctionDictionary *this, 29 | char *p_key_str, fn_ptr p_value); 30 | void FunctionDictionaryHandleRequest(struct FunctionDictionary *this, 31 | char *p_str); 32 | 33 | void Home(); 34 | void About(); 35 | 36 | void FunctionDictionary__init__(struct FunctionDictionary *this) { 37 | this->added_values = 0; 38 | } 39 | 40 | void FunctionDictionaryadd_key_value(struct FunctionDictionary *this, 41 | char *p_key_str, fn_ptr p_value) { 42 | KeyValuePair pair; 43 | pair.key.key_str = p_key_str; 44 | pair.value = p_value; 45 | this->pairs.pair[this->added_values++] = pair; 46 | } 47 | 48 | void FunctionDictionaryHandleRequest(struct FunctionDictionary *this, 49 | char *p_str) { 50 | for (int i = 0; i < this->added_values; i++) { 51 | char *key = this->pairs.pair[i].key.key_str; 52 | if (strcmp(key, p_str) == 0) { 53 | fn_ptr value = this->pairs.pair[i].value; 54 | value(); 55 | return; 56 | } 57 | } 58 | printf("%s is not a valid route.\n", p_str); 59 | } 60 | 61 | void Home() { printf("Hello World\n"); } 62 | 63 | void About() { printf("Anil BK\n"); } 64 | 65 | int main() { 66 | 67 | struct FunctionDictionary router; 68 | FunctionDictionary__init__(&router); 69 | 70 | // Add all the annotated functions using a macro. 71 | // The macro performs text replace operations so, "annotation_argument_value" 72 | // in the macro below is not a string. It will be replaced by actual value of 73 | // 'annotation_argument_value'. 74 | 75 | FunctionDictionaryadd_key_value(&router, "/Home", Home); 76 | FunctionDictionaryadd_key_value(&router, "/About", About); 77 | 78 | FunctionDictionaryadd_key_value(&router, "home", Home); 79 | 80 | FunctionDictionaryHandleRequest(&router, "/Home"); 81 | FunctionDictionaryHandleRequest(&router, "/About"); 82 | FunctionDictionaryHandleRequest(&router, "/Home/1"); 83 | 84 | return 0; 85 | } -------------------------------------------------------------------------------- /Lib/OrderedDict.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | 4 | struct OrderedDictObject{char *key_str, T value, Self *next}; 5 | 6 | struct OrderedDict{OrderedDictObject *nodes}; 7 | 8 | namespace OrderedDict 9 | 10 | c_function __init__() 11 | this->nodes = NULL; 12 | endc_function 13 | 14 | c_function __del__() 15 | @TYPEOF(nodes) *node = this->nodes; 16 | while (node != NULL) { 17 | @TYPEOF(nodes) *temp = node; 18 | node = node->next; 19 | free(temp); 20 | } 21 | endc_function 22 | 23 | c_function __getitem__(p_key : str) -> T: 24 | @TYPEOF(nodes) *node = this->nodes; 25 | while (node != NULL) { 26 | @TYPEOF(nodes) *temp = node; 27 | if (strcmp(node->key_str, p_key) == 0) { 28 | return node->value; 29 | } 30 | node = node->next; 31 | free(temp); 32 | } 33 | 34 | @TEMPLATED_DATA_TYPE@ item; 35 | return item; 36 | endc_function 37 | 38 | c_function __setitem__(p_key : str, p_value : T) 39 | if (!p_key || p_key[0] == '\0') { 40 | printf("OrderedDict: Key cannot be NULL or empty.\n"); 41 | exit(EXIT_FAILURE); 42 | } 43 | 44 | @TYPEOF(nodes) *node = this->nodes; 45 | if (node == NULL) { 46 | // No items in the dict yet, add the new item as the first node. 47 | @TYPEOF(nodes) *new_node = (@TYPEOF(nodes)*)malloc(sizeof(@TYPEOF(nodes))); 48 | new_node->key_str = strdup(p_key); 49 | new_node->value = p_value; 50 | new_node->next = NULL; 51 | this->nodes = new_node; 52 | } else { 53 | @TYPEOF(nodes) *prev = NULL; 54 | while (node != NULL) { 55 | if (strcmp(node->key_str, p_key) == 0) { 56 | free(node->key_str); // Free the old key string 57 | node->key_str = strdup(p_key); 58 | if (!node->key_str) { 59 | printf("OrderedDict: Memory allocation for key failed.\n"); 60 | exit(EXIT_FAILURE); 61 | return; 62 | } 63 | node->value = p_value; 64 | return; 65 | } 66 | prev = node; 67 | node = node->next; 68 | } 69 | 70 | // Add a new node since the key was not found. 71 | @TYPEOF(nodes) *new_node = (@TYPEOF(nodes)*)malloc(sizeof(@TYPEOF(nodes))); 72 | new_node->key_str = strdup(p_key); 73 | new_node->value = p_value; 74 | new_node->next = NULL; 75 | prev->next = new_node; 76 | } 77 | endc_function 78 | 79 | c_function __contains__(p_key : str) -> bool: 80 | @TYPEOF(nodes) *node = this->nodes; 81 | while (node != NULL) { 82 | if (strcmp(node->key_str, p_key) == 0) { 83 | return true; 84 | } 85 | node = node->next; 86 | } 87 | return false; 88 | endc_function 89 | 90 | function get(key : str) -> Optional: 91 | let res = Optional{}; 92 | if key in this{ 93 | let value = this[key] 94 | res.set_value(value) 95 | } 96 | return res 97 | endfunction 98 | 99 | function push(p_key : str, p_value : T) 100 | this[p_key] = p_value 101 | endfunction 102 | 103 | endnamespace 104 | ///*/// 105 | 106 | -------------------------------------------------------------------------------- /examples/UI/TodoAppBasic.c: -------------------------------------------------------------------------------- 1 | 2 | // Very Basic Version of Todo App. 3 | // Doesn't use JSX like syntax to create UI elements. 4 | // No todo saving/loading functionality. 5 | // Look TodoAppJSX.c for a more advanced version. 6 | 7 | // gcc -O2 TodoAppBasic_generated.c -o TodoAppBasic -lgdi32 -lcomctl32 -mwindows 8 | 9 | // IMPORTS // 10 | 11 | // STRUCT_DEFINATIONS // 12 | 13 | ///*/// 14 | 15 | import Vector 16 | import String 17 | import UI 18 | 19 | function AddTodo(userData: voidPtr) 20 | // 'userData' has UIElement* to the root element. 21 | // Convert it to UIWidget for easier access to UIWidget methods, 22 | // and tree traversal. 23 | let r1 = UIWidget{}; 24 | let root = r1.CreateUIWidgetFromVoidPtr(userData) 25 | 26 | let editElement = root.FindElementById("todoInput") 27 | let listElement = root.FindElementById("todoList") 28 | 29 | if editElement.isValid(){ 30 | if listElement.isValid(){ 31 | let text = editElement.GetEditText() 32 | listElement.AddItemToList(text) 33 | editElement.ClearEditText() 34 | } 35 | } 36 | endfunction 37 | 38 | ///*/// 39 | 40 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 41 | LPSTR lpCmdLine, int nCmdShow) { 42 | // clang-format off 43 | 44 | // RedirectIOToConsole(); 45 | 46 | ///*/// main() 47 | 48 | // hInstance and nCmdShow are C types above and not registered in ANIL yet, 49 | // so we use a struct to pass them. 50 | let AppConfig = WinUIAppConfig{hInstance, nCmdShow}; 51 | 52 | let App = WinUIApp{}; 53 | let result_code : int = App.Create(AppConfig, "Todo Application") 54 | if result_code == -1 { 55 | // Initialization failed 56 | return -1; 57 | } 58 | 59 | let ui = UIWidget{}; 60 | let headerLabel = ui.CreateLabel(0, 0, 100, 25, "Todo Application", "headerLabel") 61 | let todoList = ui.CreateList(0, 0, 0, 150, "todoList") 62 | let inputRow = ui.CreateHBox(0, 0, 0, 30, "inputRow") 63 | let todoInput = ui.CreateLineInput(0, 0, 0, 0, "todoInput") 64 | let addButton = ui.CreateButton(0, 0, 60, 0, "Add TODO", "addButton") 65 | 66 | let root_elem = App.GetRootWidget() 67 | root_elem.AddChild(headerLabel) 68 | root_elem.AddChild(todoList) 69 | root_elem.AddChild(inputRow) 70 | inputRow.AddChild(todoInput) 71 | inputRow.AddChild(addButton) 72 | 73 | // Create Windows Controls (HWNDs) for Children of Root. 74 | let create_status = App.CreateControls() 75 | if create_status == false { 76 | fprintf(stderr, "Failed to create HWND tree starting from child '%s'.\n", root_elem.uiElement->id); 77 | App.CleanUp() 78 | return -1 79 | } 80 | 81 | // Setup Event Handlers. 82 | // Pass the root element as userData so the handler can find other elements 83 | let payload = VoidPointer{root_elem}; 84 | addButton.SetOnClickCallback(AddTodo, payload) 85 | 86 | todoList.AddItemToList("Complete UI Framework") 87 | todoList.AddItemToList("Implement JSX like syntax") 88 | 89 | let exitCode = App.Run() 90 | 91 | // DESTRUCTOR_CODE // 92 | ///*/// 93 | // clang-format on 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /Bootstrap/Parser.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | ///*/// 10 | import Vector 11 | import String 12 | import Dictionary 13 | import List 14 | import File 15 | import Lexer 16 | 17 | struct Parser{List tokens}; 18 | 19 | namespace Parser 20 | 21 | function __init__(line : String) 22 | let lexer = Lexer{}; 23 | let tokens = lexer.get_tokens(line) 24 | 25 | this.tokens.__init__() 26 | this.tokens = tokens 27 | endfunction 28 | 29 | function has_tokens_remaining() -> bool: 30 | return this.tokens.len() > 0 31 | endfunction 32 | 33 | function current_token() -> ListObject: 34 | return this.tokens[0] 35 | endfunction 36 | 37 | function next_token() 38 | let node = this.tokens.pop(0) 39 | endfunction 40 | 41 | function get_token() -> ListObject: 42 | return this.tokens.pop(0) 43 | endfunction 44 | 45 | function check_token<>(token : int) -> bool: 46 | let node = this.current_token() 47 | return node == token 48 | endfunction 49 | 50 | function check_token<>(token : str) -> bool: 51 | let node = this.current_token() 52 | return node == token 53 | endfunction 54 | 55 | function match_token(token : int) -> bool: 56 | if this.check_token(token){ 57 | return true 58 | }else{ 59 | print("Expected token {token}.") 60 | exit(EXIT_FAILURE); 61 | } 62 | endfunction 63 | 64 | function consume_token(p_token : int) -> bool: 65 | if this.match_token(p_token){ 66 | } 67 | this.next_token() 68 | endfunction 69 | 70 | function extract_string_literal() -> String: 71 | /* 72 | Extract the string defined inside the quotes "...". 73 | And, advances the parser to the next token. 74 | It expects the following Tokens: Token.QUOTE, Actual string, Token.QUOTE. 75 | */ 76 | this.consume_token(Token["QUOTE"]) 77 | 78 | let string_tk = this.get_token() 79 | 80 | this.match_token(Token["QUOTE"]) 81 | this.next_token() 82 | 83 | let string = ""; 84 | if string_tk.is_str(){ 85 | string = string_tk.get_str() 86 | }else{ 87 | print("Expected a string literal.") 88 | exit(EXIT_FAILURE); 89 | } 90 | 91 | return string 92 | endfunction 93 | 94 | endnamespace 95 | ///*/// 96 | 97 | 98 | int main() { 99 | 100 | // clang-format off 101 | 102 | ///*/// main() 103 | 104 | let Line = "print(" + "\"Hello World!\");" 105 | 106 | let parser = Parser{Line}; 107 | 108 | let GeneratedLines = [] 109 | GeneratedLines.append("#include") 110 | GeneratedLines.append("int main(){") 111 | 112 | if parser.check_token("print"){ 113 | parser.next_token() 114 | 115 | parser.consume_token(Token["LEFT_ROUND_BRACKET"]) 116 | let actual_str = parser.extract_string_literal() 117 | parser.consume_token(Token["RIGHT_ROUND_BRACKET"]) 118 | 119 | let str_to_write = "printf(" + "\"" + actual_str + "\");" 120 | let cstr = str_to_write.c_str() 121 | GeneratedLines.append(cstr) 122 | } 123 | 124 | GeneratedLines.append("return 0;") 125 | GeneratedLines.append("}") 126 | 127 | GeneratedLines.print() 128 | 129 | let outputFile = File{"Parser_test_output1.c"}; 130 | for line in GeneratedLines{ 131 | if line.is_str(){ 132 | outputFile.writeline(line.get_str()) 133 | } 134 | } 135 | 136 | 137 | // DESTRUCTOR_CODE // 138 | ///*/// 139 | // clang-format on 140 | 141 | return 0; 142 | } -------------------------------------------------------------------------------- /Parser.py: -------------------------------------------------------------------------------- 1 | import lexer 2 | from ErrorHandler import ErrorHandler 3 | 4 | 5 | class Parser: 6 | def __init__(self, line: str) -> None: 7 | self.tokens = lexer.get_tokens(line) 8 | self.checkpoint_stack = [] 9 | 10 | def has_tokens_remaining(self) -> bool: 11 | return len(self.tokens) > 0 12 | 13 | def current_token(self): 14 | return self.tokens[0] 15 | 16 | def peek_token(self): 17 | if len(self.tokens) >= 1: 18 | return self.tokens[1] 19 | else: 20 | return None 21 | 22 | def next_token(self): 23 | _ = self.tokens.pop(0) 24 | 25 | def get_token(self): 26 | return self.tokens.pop(0) 27 | 28 | def check_token(self, token: lexer.Token, p_custom_msg=None) -> bool: 29 | if not self.has_tokens_remaining(): 30 | token_str = lexer.token_to_str(token) 31 | error_msg = ( 32 | f'Expected {token}("{token_str}"), but no more tokens remaining.' 33 | ) 34 | if p_custom_msg != None: 35 | error_msg += "\n" + p_custom_msg 36 | ErrorHandler().raise_error(error_msg) 37 | return self.current_token() == token 38 | 39 | def match_token(self, token: lexer.Token, p_custom_msg=None): 40 | if self.check_token(token, p_custom_msg): 41 | return True 42 | else: 43 | token_str = lexer.token_to_str(token) 44 | 45 | obtained_tk = self.current_token() 46 | obtained_tk_str = lexer.token_to_str(obtained_tk) 47 | if obtained_tk_str is None: 48 | obtained_tk_str = "" 49 | else: 50 | obtained_tk_str = f'("{obtained_tk_str}")' 51 | 52 | error_msg = f'Expected {token}("{token_str}") but got {obtained_tk}{obtained_tk_str}.' 53 | if p_custom_msg != None: 54 | error_msg += "\n" + p_custom_msg 55 | ErrorHandler().raise_error(error_msg) 56 | 57 | def consume_token(self, p_token: lexer.Token): 58 | """ 59 | Expects the 'p_token' token. 60 | And, advances the parser to next token. 61 | Basically, we check for 'p_token' and then goto next token. 62 | """ 63 | self.match_token(p_token) 64 | self.next_token() 65 | 66 | def extract_string_literal(self) -> str: 67 | """ 68 | Extract the string defined inside the quotes "...". 69 | And, advances the parser to the next token. 70 | It expects the following Tokens: Token.QUOTE, Actual string, Token.QUOTE. 71 | """ 72 | self.consume_token(lexer.Token.QUOTE) 73 | 74 | string = self.get_token() 75 | 76 | self.match_token(lexer.Token.QUOTE, "Quote Should be Closed.") 77 | self.next_token() 78 | 79 | return string 80 | 81 | # Checkpoint tokens. 82 | # While parsing, we consume tokens. If we find that we are parsing wrong thing(say expression), 83 | # we roll back to the point where, we need to reparse again with different kind of (expression)parser. 84 | # Since, consuming token removes the token, we create these checkpoints to recover the tokens that have been consumed. 85 | def save_checkpoint(self): 86 | self.checkpoint_stack.append(list(self.tokens)) 87 | 88 | def rollback_checkpoint(self): 89 | if self.checkpoint_stack: 90 | self.tokens.clear() 91 | self.tokens = self.checkpoint_stack.pop() 92 | 93 | def clear_checkpoint(self): 94 | self.checkpoint_stack.clear() 95 | -------------------------------------------------------------------------------- /examples/UI/TodoAppWebServer.c: -------------------------------------------------------------------------------- 1 | // Run this file and then open Todos.html in a browser to see the UI. 2 | 3 | // gcc -o .\TodoAppWebServer .\TodoAppWebServer_generated.c cJSON.c -lws2_32 4 | 5 | #include 6 | 7 | // IMPORTS // 8 | 9 | // STRUCT_DEFINATIONS // 10 | 11 | ///*/// 12 | import Vector 13 | import String 14 | import HTTPServer 15 | import JSON 16 | import File 17 | 18 | function LoadTodosFromFile() -> Vector: 19 | let str = "" 20 | let storedTodos = str.readlinesFrom("todos.txt") 21 | 22 | let todos = Vector{1}; 23 | 24 | if storedTodos.len() > 0{ 25 | // If todos.txt already exists and has some lines, then read the todos from it. 26 | for todo in storedTodos{ 27 | if todo == "" { 28 | continue; 29 | } 30 | if todo == "\n" { 31 | continue; 32 | } 33 | todos.push(todo) 34 | } 35 | } 36 | 37 | return todos 38 | endfunction 39 | 40 | function WriteTodosToFile(todos: Vector) 41 | let file = File{"todos.txt"}; 42 | 43 | for todo in todos{ 44 | file.writeline(todo) 45 | } 46 | endfunction 47 | 48 | function VectorStringToJSONString(todos: Vector) -> String: 49 | let jsonString = "[" 50 | 51 | let todo_count : int = 0 52 | for todo in todos{ 53 | jsonString += "\"" + todo + "\"" 54 | if todo_count != todos.len() - 1 { 55 | jsonString += "," 56 | } 57 | todo_count = todo_count + 1 58 | } 59 | 60 | jsonString += "]" 61 | 62 | return jsonString 63 | endfunction 64 | 65 | function Handle404(res : Response, req : Request) 66 | const html = "

404 Page Not Found

\r\n" 67 | res.send(html, 404) 68 | endfunction 69 | 70 | @route("GET", "/get_todos") 71 | function HandleGetTodos(res : Response, req : Request) 72 | let todos = LoadTodosFromFile() 73 | let jsonString = VectorStringToJSONString(todos) 74 | 75 | res.send(jsonString, 200) 76 | endfunction 77 | 78 | @routeWithValidation("OPTIONS", "/save_todos", "") 79 | @routeWithValidation("POST", "/save_todos", "application/json") 80 | function HandleSaveTodos(res : Response, request : Request) 81 | let jsonParser = JSON{}; 82 | let todos = jsonParser.ParseRequest(request) 83 | 84 | if todos.len() == 0 { 85 | fprintf(stderr, "Failed to parse JSON body for POST /save_todos\n"); 86 | res.send("{\"error\":\"Invalid JSON format\"}", 400) // Bad Request 87 | } else{ 88 | WriteTodosToFile(todos) 89 | res.send("{\"message\":\"Todos saved successfully\"}", 201) // Created 90 | } 91 | endfunction 92 | 93 | ///*/// 94 | 95 | int main() { 96 | 97 | // clang-format off 98 | ///*/// main() 99 | 100 | let server = HTTPServer{}; 101 | 102 | // Use reflection to get all functions with annotations '@route' and register those functions as routes. 103 | def register_routes_reflection(): 104 | forall annotated_fn_name, arg_value1, arg_value2 in annotated_functions_by_name(route) UNQUOTE: server.register_route("arg_value1", "arg_value2", annotated_fn_name) 105 | 106 | forall annotated_fn_name, arg_value1, arg_value2, arg_value3 in annotated_functions_by_name(routeWithValidation) UNQUOTE: server.register_route("arg_value1", "arg_value2", annotated_fn_name) 107 | forall annotated_fn_name, arg_value1, arg_value2, arg_value3 in annotated_functions_by_name(routeWithValidation) UNQUOTE: server.add_validation_rule("arg_value2", "arg_value1", "arg_value3") 108 | enddef 109 | register_routes_reflection 110 | 111 | server.listen(8080) 112 | 113 | // DESTRUCTOR_CODE // 114 | ///*/// 115 | 116 | // clang-format on 117 | 118 | return 0; 119 | } -------------------------------------------------------------------------------- /Lib/Subprocess.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | #include 4 | #include 5 | 6 | struct Subprocess{String commandLine, PROCESS_INFORMATION pi}; 7 | 8 | namespace Subprocess 9 | 10 | c_function _clear_pi() 11 | ZeroMemory(&this->pi, sizeof(this->pi)); 12 | endc_function 13 | 14 | function __init__(commandLine : str) 15 | this.commandLine.__init__(commandLine) 16 | this._clear_pi() 17 | endfunction 18 | 19 | c_function run() -> int: 20 | // Start subprocess (non-blocking) 21 | STARTUPINFOA si; 22 | ZeroMemory(&si, sizeof(si)); 23 | si.cb = sizeof(si); 24 | 25 | if (!CreateProcessA( 26 | NULL, // No module name (use command line) 27 | this->commandLine.arr, // Command line 28 | NULL, // Process handle not inheritable 29 | NULL, // Thread handle not inheritable 30 | FALSE, // Set handle inheritance to FALSE 31 | CREATE_NEW_CONSOLE, // Create in new console window 32 | NULL, // Use parent's environment block 33 | NULL, // Use parent's starting directory 34 | &si, // Pointer to STARTUPINFO structure 35 | &this->pi)) // Pointer to PROCESS_INFORMATION structure 36 | { 37 | fprintf(stderr, "CreateProcess failed (%lu).\n", GetLastError()); 38 | return -1; 39 | } 40 | 41 | // success, running in background 42 | return 0; 43 | endc_function 44 | 45 | c_function wait() -> int: 46 | if (this->pi.hProcess == NULL) { 47 | fprintf(stderr, "No process to wait for.\n"); 48 | return -1; 49 | } 50 | 51 | // Wait until child process exits 52 | WaitForSingleObject(this->pi.hProcess, INFINITE); 53 | 54 | DWORD exitCode; 55 | if (!GetExitCodeProcess(this->pi.hProcess, &exitCode)) { 56 | fprintf(stderr, "GetExitCodeProcess failed (%lu).\n", GetLastError()); 57 | exitCode = (DWORD)-1; 58 | } 59 | 60 | CloseHandle(this->pi.hProcess); 61 | CloseHandle(this->pi.hThread); 62 | 63 | this->pi.hProcess = NULL; 64 | this->pi.hThread = NULL; 65 | 66 | return (int)exitCode; 67 | endc_function 68 | 69 | c_function run_and_detach() -> int: 70 | STARTUPINFOA si; 71 | ZeroMemory(&si, sizeof(si)); 72 | si.cb = sizeof(si); 73 | 74 | // Clear any old process information before creating a new one. 75 | Subprocess_clear_pi(this); 76 | 77 | if (!CreateProcessA(NULL, // No module name (use command line) 78 | this->commandLine.arr, // Command line 79 | NULL, // Process handle not inheritable 80 | NULL, // Thread handle not inheritable 81 | FALSE, // Set handle inheritance to FALSE 82 | CREATE_NEW_CONSOLE, // Create in new console window 83 | NULL, // Use parent's environment block 84 | NULL, // Use parent's starting directory 85 | &si, // Pointer to STARTUPINFO structure 86 | &this->pi)) 87 | { 88 | fprintf(stderr, "CreateProcess failed (%lu).\n", GetLastError()); 89 | return -1; 90 | } 91 | 92 | // Immediately close the handles. The child process will continue to run. 93 | // This prevents handle leaks and detaches the child from the parent. 94 | CloseHandle(this->pi.hProcess); 95 | CloseHandle(this->pi.hThread); 96 | 97 | // Clear the PI structure again so a subsequent call to wait() will fail gracefully. 98 | Subprocess_clear_pi(this); 99 | 100 | return 0; 101 | endc_function 102 | endnamespace 103 | ///*/// 104 | -------------------------------------------------------------------------------- /examples/UI/TodoAppJSX.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // gcc -O2 TodoAppJSX_generated.c -o TodoAppJSX -lgdi32 -lcomctl32 -mwindows 8 | 9 | // IMPORTS // 10 | 11 | // STRUCT_DEFINATIONS // 12 | 13 | ///*/// 14 | import Vector 15 | import String 16 | import UI 17 | import File 18 | 19 | function SaveTodos(todoList: UIWidget) 20 | let file = File{"todos.txt"}; 21 | let todoItems = todoList.GetAllItemsInList() 22 | for todoItem in todoItems{ 23 | file.writeline(todoItem) 24 | } 25 | endfunction 26 | 27 | function LoadTodos(todoList: UIWidget) 28 | let str = "" 29 | let storedTodos = str.readlinesFrom("todos.txt") 30 | 31 | if storedTodos.len() > 0{ 32 | for todo in storedTodos{ 33 | todoList.AddItemToList(todo) 34 | } 35 | }else{ 36 | todoList.AddItemToList("Complete UI Framework") 37 | todoList.AddItemToList("Implement JSX like syntax") 38 | SaveTodos(todoList) 39 | } 40 | endfunction 41 | 42 | function CreateUIWidgetFromVoidPtr(ptr: voidPtr) -> UIWidget: 43 | // We don't have static functions in ANIL yet, so we have to do this. 44 | let w = UIWidget{}; 45 | let widget = w.CreateUIWidgetFromVoidPtr(ptr) 46 | return widget 47 | endfunction 48 | 49 | function AddTodo(userData: voidPtr) 50 | // 'userData' has UIElement* to the root element. 51 | // Convert it to UIWidget for easier access to UIWidget methods, 52 | // and tree traversal. 53 | let root = CreateUIWidgetFromVoidPtr(userData) 54 | 55 | let todoInput = root.FindElementById("todoInput") 56 | let todoList = root.FindElementById("todoList") 57 | 58 | if todoInput.isValid(){ 59 | if todoList.isValid(){ 60 | let text = todoInput.GetEditText() 61 | todoList.AddItemToList(text) 62 | todoInput.ClearEditText() 63 | SaveTodos(todoList) 64 | } 65 | } 66 | endfunction 67 | 68 | function DeleteSelectedTodo(userData: voidPtr) 69 | let root = CreateUIWidgetFromVoidPtr(userData) 70 | 71 | let todoList = root.FindElementById("todoList") 72 | 73 | if todoList.isValid(){ 74 | todoList.RemoveSelectedListItem() 75 | SaveTodos(todoList) 76 | } 77 | endfunction 78 | 79 | ///*/// 80 | 81 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 82 | LPSTR lpCmdLine, int nCmdShow) { 83 | // clang-format off 84 | 85 | // RedirectIOToConsole(); 86 | 87 | ///*/// main() 88 | 89 | // hInstance and nCmdShow are C types above and not registered in ANIL yet, 90 | // so we use a struct to pass them. 91 | let AppConfig = WinUIAppConfig{hInstance, nCmdShow}; 92 | 93 | let App = WinUIApp{}; 94 | let result_code : int = App.Create(AppConfig, "Todo Application") 95 | if result_code == -1 { 96 | // Initialization failed 97 | return -1; 98 | } 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | // Create Windows Controls (HWNDs) for Children of Root. 112 | let create_status = App.CreateControls() 113 | if create_status == false { 114 | fprintf(stderr, "Failed to create HWND tree starting from child '%s'.\n", root_elem.uiElement->id); 115 | App.CleanUp() 116 | return -1 117 | } 118 | 119 | LoadTodos(todoList) 120 | 121 | let exitCode = App.Run() 122 | 123 | // DESTRUCTOR_CODE // 124 | ///*/// 125 | // clang-format on 126 | 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /examples/03_Dictionary_generated.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #define TABLE_SIZE 101 7 | 8 | unsigned int hash(char *str) { 9 | unsigned int hash = 5381; 10 | int c; 11 | while ((c = *str++)) { 12 | hash = ((hash << 5) + hash) + c; // hash * 33 + c 13 | } 14 | return hash % TABLE_SIZE; 15 | } 16 | 17 | #include 18 | #include 19 | 20 | // IMPORTS // 21 | 22 | struct DictObject_int { 23 | char *key_str; 24 | int value; 25 | struct DictObject_int *next; 26 | }; 27 | 28 | struct Dictionary_int { 29 | struct DictObject_int **table; 30 | }; 31 | 32 | void Dictionary_int__init__(struct Dictionary_int *this); 33 | void Dictionary_int__del__(struct Dictionary_int *this); 34 | int Dictionary_int__getitem__(struct Dictionary_int *this, char *p_key); 35 | void Dictionary_int__setitem__(struct Dictionary_int *this, char *p_key_str, 36 | int p_value); 37 | bool Dictionary_int__contains__(struct Dictionary_int *this, char *p_key); 38 | void Dictionary_intprint(struct Dictionary_int *this); 39 | 40 | void Dictionary_int__init__(struct Dictionary_int *this) { 41 | this->table = (struct DictObject_int **)malloc( 42 | TABLE_SIZE * sizeof(struct DictObject_int *)); 43 | for (int i = 0; i < TABLE_SIZE; i++) { 44 | this->table[i] = NULL; 45 | } 46 | } 47 | 48 | void Dictionary_int__del__(struct Dictionary_int *this) { 49 | for (int i = 0; i < TABLE_SIZE; i++) { 50 | struct DictObject_int *pair = this->table[i]; 51 | while (pair != NULL) { 52 | struct DictObject_int *next = pair->next; 53 | // Do not free key_str since it's not dynamically allocated 54 | free(pair); 55 | pair = next; 56 | } 57 | } 58 | free(this->table); // Free the table itself 59 | } 60 | 61 | int Dictionary_int__getitem__(struct Dictionary_int *this, char *p_key) { 62 | unsigned int index = hash(p_key); 63 | struct DictObject_int *pair = this->table[index]; 64 | while (pair != NULL) { 65 | if (strcmp(pair->key_str, p_key) == 0) { 66 | return pair->value; 67 | } 68 | pair = pair->next; 69 | } 70 | return 0; 71 | } 72 | 73 | void Dictionary_int__setitem__(struct Dictionary_int *this, char *p_key_str, 74 | int p_value) { 75 | unsigned int index = hash(p_key_str); 76 | struct DictObject_int *new_pair = 77 | (struct DictObject_int *)malloc(sizeof(struct DictObject_int)); 78 | new_pair->key_str = p_key_str; 79 | new_pair->value = p_value; 80 | new_pair->next = this->table[index]; 81 | this->table[index] = new_pair; 82 | } 83 | 84 | bool Dictionary_int__contains__(struct Dictionary_int *this, char *p_key) { 85 | unsigned int index = hash(p_key); 86 | struct DictObject_int *pair = this->table[index]; 87 | while (pair != NULL) { 88 | if (strcmp(pair->key_str, p_key) == 0) { 89 | return true; 90 | } 91 | pair = pair->next; 92 | } 93 | return false; 94 | } 95 | 96 | void Dictionary_intprint(struct Dictionary_int *this) { 97 | printf("{\n"); 98 | for (int i = 0; i < TABLE_SIZE; i++) { 99 | struct DictObject_int *pair = this->table[i]; 100 | while (pair != NULL) { 101 | printf("\"%s\" : %d,\n", pair->key_str, pair->value); 102 | pair = pair->next; 103 | } 104 | } 105 | printf("}\n"); 106 | } 107 | 108 | int main() { 109 | 110 | // Compile time dictionary. See constexpr_dict.c 111 | // Also See, Bootstrap/lexer_test.c. 112 | 113 | struct Dictionary_int dict; 114 | Dictionary_int__init__(&dict); 115 | // The following line is also valid, as the above syntax is shorthand for the 116 | // statement below. let dict = Dictionary{}; 117 | Dictionary_int__setitem__(&dict, "One", 1); 118 | Dictionary_int__setitem__(&dict, "Two", 2); 119 | Dictionary_int__setitem__(&dict, "Three", 3); 120 | 121 | Dictionary_intprint(&dict); 122 | 123 | Dictionary_int__del__(&dict); 124 | 125 | return 0; 126 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Nice Intermediate Language(ANIL) 2 | ## ANIL is a statically typed programming language, inspired by Python and C++, that can be embedded within C source files. 3 | 4 | ![ss1](https://github.com/user-attachments/assets/7ed43e7e-39fd-4ff0-a8e4-a60f43983355) 5 | 6 | *Fig: ANIL functions written in C and ANIL respectively. The first function written in C is the general implementation for the `__contains__` method whereas the second function written in ANIL is template specialization for `String` class.* 7 | 8 | ## ANIL generates appropriate C code, which is then compiled using a C compiler. 9 | 10 | ![ss2](https://github.com/user-attachments/assets/38fb545a-cad5-44d6-8892-7e4d07afab95) 11 | 12 | *Fig: The generated C code from the second `__contains__` method in the first screenshot.* 13 | 14 | ## Requirements: 15 | - C compiler. 16 | - Python. 17 | - clang-format(Recommended). 18 | 19 | ## Usage 20 | 1. Open [preprocess_2.py](preprocess_2.py). 21 | 2. Uncomment one of the `source_file = "FILE_NAME*.c"` line. 22 | 3. Run 23 | ```bash 24 | python preprocess_2.py 25 | ``` 26 | Alternatively, you can specify the filename directly by running: 27 | ```bash 28 | python preprocess_2.py --filename examples\FILE_NAME*.c 29 | ``` 30 | 31 | 4. This will generate a FILE_NAME*_generated.c file. Compile the generated c file using a C compiler and execute the generated executable. 32 | 33 | ## Features: 34 | - Classes: [Example 1](examples/04_Classes.c) [Example 2](examples/04_b_Classes.c) 35 | - Templates & Function Overloading: [Example](Lib/Vector.c) 36 | - Macros: [Example](examples/Macro_With_Variadic_Arguments.c) 37 | - Compile-Time Reflection: [Example 1](examples/Reflection.c) 38 | - Annotations: [Example 1](examples/Annotations.c) [WebSever Example](examples/WebServer.c) 39 | - Standard Library: See [Lib/](Lib/). Shows mixing of C code and ANIL. 40 | - Windows UI FrameWork: See [Todo App Example](examples/UI/TodoAppBasic.c) 41 | - Windows UI App using JSX like syntax: See [Todo App JSX like Syntax Example](examples/UI/TodoAppJSX.c) 42 | - Windows Web Server: See [Todo App Web Server Example](examples/UI/TodoAppWebServer.c) 43 | - Function Pointers: See [Example](examples/FunctionPointer.c) 44 | - Threads & Channel: See [Example](examples/11_Threads_And_Channels.anil) 45 | - Dunder methods: 46 | - `__init__` : To implement constructors. 47 | - `__del__` : To implement destructors. For automatic destructor call for a struct member(if it has a destructor), use the ~ operator. Lookup `_call_destructor_for_element()` in [Vector](Lib/Vector.c) 48 | - `__getitem__` : To get an item at a specified index (e.g. `obj[index]`). 49 | - `__setitem__` : To set an item at a specified index (e.g. `obj[index] = value`). 50 | - `__reassign__` : To implement reassignment (e.g. `obj = value`). 51 | - `__add__` : To implement addition. 52 | - `__contains__` : To implement `in` operator (e.g `value in list`). 53 | - `len` : To get total number of items. It is used along with `__getitem__` to implement iterators. 54 | 55 | 56 | ### The examples in [examples/](examples/) and [Lib/](lib/) folder shows all different features of ANIL. Right now, these examples serve as documentation for the language. 57 | 58 | ## Project Structure 59 | ## Directories 60 | 61 | - **[Bootstrap](Bootstrap/)**: Implementation of the compiler in ANIL itself. Files in this directory uses all (advanced) features available in the language. 62 | 63 | - **[examples](examples/)**: Demonstrations of various language features and usage of the standard library. 64 | 65 | - **[Lib](Lib/)**: Standard Library. 66 | 67 | ## Individual Files 68 | 69 | - **[preprocess_2.py](preprocess_2.py)**: The actual compiler and code generator. 70 | 71 | - **[batch_compile.py](batch_compile.py)**: Compiles all the ANIL files one by one. Used to verify if the changes made to the compiler doesn't break existing functionality. 72 | 73 | --- 74 | 75 | > [!NOTE] 76 | > This is my first ever compiler project. 77 | > I created this compiler for the following reasons: 78 | > 1. To learn about compiler development. 79 | > 2. To build a self-compiling compiler. 80 | > 3. To implement features I find interesting and cool. 81 | -------------------------------------------------------------------------------- /Lib/JSON.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | #include 3 | #include 4 | #include 5 | #include "cJSON.h" 6 | 7 | ///*/// 8 | struct JSON{Vector parsed_strings}; 9 | 10 | namespace JSON 11 | 12 | function __init__() 13 | this.parsed_strings.__init__(1) 14 | endfunction 15 | 16 | function ParsedStringsList() -> Vector: 17 | // Duplicate the vector to avoid returning the raw pointer, 18 | // which may be freed somewhere else. 19 | let length = this.parsed_strings.len() 20 | let copy = Vector{length}; 21 | for str in this.parsed_strings{ 22 | copy.push(str) 23 | } 24 | return copy 25 | endfunction 26 | 27 | c_function Parse(json_string : str, len : int) -> bool: 28 | // Parse the JSON and store the strings in 'parsed_strings'. 29 | Vector_Stringclear(&this->parsed_strings); 30 | 31 | // 1. Input Validation 32 | if (!json_string || len <= 0) { 33 | fprintf(stderr, "JSON Error: Invalid input parameters.\n"); 34 | return false; 35 | } 36 | 37 | // 2. Create Null-Terminated Copy 38 | // cJSON_Parse requires a null-terminated string. 39 | char* temp_json_buffer = (char*)malloc(len + 1); 40 | if (!temp_json_buffer) { 41 | fprintf(stderr, "JSON Error: Failed to allocate memory for JSON buffer.\n"); 42 | return false; 43 | } 44 | 45 | memcpy(temp_json_buffer, json_string, len); 46 | temp_json_buffer[len] = '\0'; 47 | 48 | // 3. Parse JSON 49 | cJSON *root = cJSON_Parse(temp_json_buffer); 50 | 51 | // 4. Free Temporary Buffer (no longer needed after parsing) 52 | free(temp_json_buffer); 53 | temp_json_buffer = NULL; // Avoid dangling pointer use 54 | 55 | // 5. Check for Parse Errors 56 | if (root == NULL) { 57 | const char *error_ptr = cJSON_GetErrorPtr(); // Get error location if available 58 | if (error_ptr != NULL) { 59 | fprintf(stderr, "JSON Error: JSON parsing failed near: %s\n", error_ptr); 60 | } else { 61 | fprintf(stderr, "JSON Error: JSON parsing failed (unknown location).\n"); 62 | } 63 | // root is already NULL, nothing to delete 64 | return false; 65 | } 66 | 67 | // 6. Validate Root Type (must be an array) 68 | if (!cJSON_IsArray(root)) { 69 | fprintf(stderr, "JSON Error: Root JSON element is not an array.\n"); 70 | cJSON_Delete(root); // Free the parsed JSON structure 71 | return false; 72 | } 73 | 74 | // 7. Iterate Through JSON Array 75 | int array_size = cJSON_GetArraySize(root); 76 | bool success = true; // Assume success initially 77 | 78 | for (int i = 0; i < array_size; i++) { 79 | cJSON *item = cJSON_GetArrayItem(root, i); 80 | 81 | // 8. Validate Item Type (must be a string) 82 | if (cJSON_IsString(item) && (item->valuestring != NULL)) { 83 | // 9. Create a String object and add it to the vector 84 | struct String todo_str; 85 | String__init__OVDstr(&todo_str, item->valuestring); 86 | Vector_Stringpush(&this->parsed_strings, todo_str); 87 | String__del__(&todo_str); 88 | } else { 89 | // Handle items that are not strings (e.g., numbers, null, objects) 90 | fprintf(stderr, "JSON Warning: Item at index %d is not a string. Skipping.\n", i); 91 | // Depending on requirements, we might want to set success = false here 92 | // success = false; 93 | // break; // Or stop processing immediately on invalid item 94 | } 95 | } // End of loop 96 | 97 | // 10. Cleanup cJSON object 98 | cJSON_Delete(root); 99 | 100 | // Return true if parsing and iteration were generally successful 101 | return success; 102 | endc_function 103 | 104 | function ParseRequest(request : Request) -> Vector: 105 | if request.HasAValidBody(){ 106 | let body_start = request.GetBodyStart(); 107 | let body_len = request.GetContentLength(); 108 | 109 | if this.Parse(body_start, body_len){ 110 | // Sucessful Parse. 111 | return this.ParsedStringsList() 112 | } 113 | } 114 | 115 | let empty_result = Vector{1}; 116 | return empty_result 117 | endfunction 118 | 119 | endnamespace 120 | ///*/// 121 | -------------------------------------------------------------------------------- /examples/UI/Todos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Simple TODO App 8 | 60 | 61 | 62 | 63 |

TODO List

64 | 65 |
66 | 67 | 68 |
69 | 70 |
71 | 72 |
    73 | 74 | 75 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /examples/UI/IDE/IDE.anil: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | import Vector 8 | import String 9 | import UI 10 | import File 11 | import Subprocess 12 | 13 | function CreateUIWidgetFromVoidPtr(ptr: voidPtr) -> UIWidget: 14 | let w = UIWidget{}; 15 | let widget = w.CreateUIWidgetFromVoidPtr(ptr) 16 | return widget 17 | endfunction 18 | 19 | function PythonPreprocess() 20 | let subprocess = Subprocess{"python E:\\ANIL\\preprocess_2.py --filename E:\\ANIL\\examples\\UI\\IDE\\out.anil --no-clang-format"}; 21 | let result = subprocess.run() 22 | if result == 0{ 23 | print("Python preprocessing started...\n") 24 | let exit_code = subprocess.wait() 25 | if exit_code == 0{ 26 | print("Preprocessing succeeded.\n") 27 | } else { 28 | print("Preprocessing failed with exit code: {exit_code}") 29 | } 30 | } else { 31 | print("Failed to start Preprocessing process.\n") 32 | } 33 | endfunction 34 | 35 | function GetBuildType(userData: voidPtr) -> String: 36 | let root = CreateUIWidgetFromVoidPtr(userData) 37 | 38 | let build_type = "Console" 39 | 40 | let build_type_select = root.FindElementById("buildType") 41 | if build_type_select.isValid(){ 42 | build_type = build_type_select.GetSelectedValue() 43 | } 44 | 45 | return build_type 46 | endfunction 47 | 48 | function GCCCompile(userData: voidPtr) 49 | let build_type = GetBuildType(userData) 50 | 51 | constexpr COMPILE_FLAGS = {"Win32" : "-mwindows -lgdi32 -lcomctl32", "Raylib" : "-lraylib -lopengl32 -lgdi32 -lwinmm -lshell32 -luser32 -lkernel32", default : ""} 52 | let compile_flags = COMPILE_FLAGS[build_type] 53 | 54 | let gcc_compile_command = "gcc -O2 E:\\ANIL\\examples\\UI\\IDE\\out_generated_anil.c -o out" 55 | gcc_compile_command += " " + compile_flags 56 | 57 | print("GCC Compile Command: {gcc_compile_command}\n") 58 | 59 | let subprocess = Subprocess{gcc_compile_command}; 60 | let result = subprocess.run() 61 | if result == 0{ 62 | print("Compilation started...\n") 63 | let exit_code = subprocess.wait() 64 | if exit_code == 0{ 65 | print("Compilation succeeded.\n") 66 | } else { 67 | print("Compilation failed with exit code: {exit_code}") 68 | } 69 | } else { 70 | print("Failed to start compilation process.\n") 71 | } 72 | endfunction 73 | 74 | function Compile(userData: voidPtr) 75 | let root = CreateUIWidgetFromVoidPtr(userData) 76 | 77 | PythonPreprocess() 78 | GCCCompile(userData) 79 | endfunction 80 | 81 | function Execute(userData: voidPtr) 82 | let root = CreateUIWidgetFromVoidPtr(userData) 83 | 84 | let subprocess = Subprocess{"out"}; 85 | let result = subprocess.run_and_detach() 86 | if result == 0{ 87 | print("Launched application out.exe.\n") 88 | } else { 89 | print("Failed to Launch application out.exe.\n") 90 | } 91 | endfunction 92 | 93 | function Load(userData: voidPtr) 94 | let root = CreateUIWidgetFromVoidPtr(userData) 95 | 96 | let editor = root.FindElementById("filePickerButton") 97 | if editor.isValid(){ 98 | let fileName = editor.getFilePath() 99 | 100 | let fileContents = "" 101 | fileContents.set_to_file_contents(fileName) 102 | 103 | let codeEditor = root.FindElementById("codeEditor") 104 | if codeEditor.isValid(){ 105 | codeEditor.SetEditText(fileContents) 106 | } 107 | } 108 | endfunction 109 | 110 | function OpenFileAndLoadToEditor(userData: voidPtr) 111 | let root = CreateUIWidgetFromVoidPtr(userData) 112 | 113 | let editor = root.FindElementById("codeEditor") 114 | if editor.isValid(){ 115 | let fileContents = editor.OpenFilePickerAndReadContents() 116 | editor.SetEditText(fileContents) 117 | } 118 | endfunction 119 | 120 | function SaveEditorContentsToFile(userData: voidPtr) 121 | let root = CreateUIWidgetFromVoidPtr(userData) 122 | 123 | let editor = root.FindElementById("codeEditor") 124 | if editor.isValid(){ 125 | let fileContents = editor.GetEditText() 126 | 127 | let outputFile = File{"out.anil"}; 128 | outputFile.write(fileContents) 129 | } 130 | endfunction 131 | 132 | function WinMain(hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nCmdShow: int) -> int: 133 | let AppConfig = WinUIAppConfig{hInstance, nCmdShow}; 134 | 135 | let App = WinUIApp{}; 136 | let result_code : int = App.Create(AppConfig, "ANIL IDE") 137 | 138 | if result_code == -1 { 139 | // Initialization failed 140 | return -1; 141 | } 142 | 143 | App.ShowConsoleWindow() 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | // Create Windows Controls (HWNDs) for Children of Root. 160 | let create_status = App.CreateControls() 161 | if create_status == false { 162 | fprintf(stderr, "Failed to create HWND tree starting from child '%s'.\n", root_elem.uiElement->id); 163 | App.CleanUp() 164 | return -1 165 | } 166 | 167 | let exitCode = App.Run() 168 | 169 | return 0 170 | endfunction -------------------------------------------------------------------------------- /examples/Variables_GUI_Input_Win_generated.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // IMPORTS // 7 | 8 | HWND hSubmitButton, hcar_ageLabel, hcar_ageDropdown, hcar_mileageLabel, 9 | hcar_mileageInput, his_electricCheckboxLabel, his_electricCheckbox; 10 | struct Form1Output { 11 | int car_age; 12 | int car_mileage; 13 | bool is_electric; 14 | } Form1Output; 15 | 16 | // Function to redirect console I/O to a console window 17 | void RedirectIOToConsole() { 18 | // Allocate a console for the current process 19 | AllocConsole(); 20 | 21 | // Redirect the STDOUT to the console 22 | FILE *fp; 23 | freopen_s(&fp, "CONOUT$", "w", stdout); 24 | freopen_s(&fp, "CONOUT$", "w", stderr); 25 | 26 | // Redirect STDIN to the console 27 | freopen_s(&fp, "CONIN$", "r", stdin); 28 | 29 | // Optional: You can set the console title if you like 30 | SetConsoleTitle(TEXT("Console Window")); 31 | } 32 | 33 | LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, 34 | LPARAM lParam) { 35 | switch (msg) { 36 | case WM_CREATE: 37 | // car_age Label 38 | hcar_ageLabel = CreateWindowW(L"Static", L"car_age:", WS_VISIBLE | WS_CHILD, 39 | 10, 10, 100, 25, hwnd, NULL, NULL, NULL); 40 | // car_age Input (with Dropdown field) 41 | hcar_ageDropdown = CreateWindowW( 42 | L"Combobox", NULL, WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST, 10 + 100, 43 | 10, 200, 100, hwnd, NULL, NULL, NULL); 44 | // Add integer values to the dropdown 45 | SendMessageW(hcar_ageDropdown, CB_ADDSTRING, 0, (LPARAM)L"5"); 46 | SendMessageW(hcar_ageDropdown, CB_ADDSTRING, 0, (LPARAM)L"10"); 47 | SendMessageW(hcar_ageDropdown, CB_ADDSTRING, 0, (LPARAM)L"15"); 48 | // Set default value for integer dropdown (index 0) 49 | SendMessageW(hcar_ageDropdown, CB_SETCURSEL, (WPARAM)0, 0); 50 | // car_mileage Label 51 | hcar_mileageLabel = 52 | CreateWindowW(L"Static", L"car_mileage:", WS_VISIBLE | WS_CHILD, 10, 50, 53 | 100, 25, hwnd, NULL, NULL, NULL); 54 | // car_mileage Input (Number field) 55 | hcar_mileageInput = CreateWindowW( 56 | L"Edit", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_NUMBER, 10 + 100, 57 | 50, 200, 25, hwnd, NULL, NULL, NULL); 58 | // Set default value for car_mileage Input 59 | SetWindowTextW(hcar_mileageInput, L"200"); 60 | // is_electric Checkbox Label(To the Left) 61 | his_electricCheckboxLabel = 62 | CreateWindowW(L"Static", L"is_electric:", WS_VISIBLE | WS_CHILD, 10, 90, 63 | 100, 25, hwnd, NULL, NULL, NULL); 64 | // is_electric Checkbox(To the Right) 65 | his_electricCheckbox = 66 | CreateWindowW(L"Button", L"", WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX, 67 | 10 + 100, 90, 200, 25, hwnd, NULL, NULL, NULL); 68 | // Set default value for is_electric Checkbox to checked 69 | SendMessage(his_electricCheckbox, BM_SETCHECK, BST_CHECKED, 0); 70 | hSubmitButton = 71 | CreateWindowW(L"Button", L"Submit", WS_VISIBLE | WS_CHILD, 10, 130, 100, 72 | 25, hwnd, (HMENU)1000, NULL, NULL); 73 | break; 74 | 75 | case WM_COMMAND: 76 | if (LOWORD(wParam) == 1000) { // Submit Button Clicked 77 | 78 | // Get the selected index from the dropdown 79 | int car_age_tmp_index = 80 | (int)SendMessageW(hcar_ageDropdown, CB_GETCURSEL, 0, 0); 81 | 82 | if (car_age_tmp_index != CB_ERR) { 83 | wchar_t car_age_tmp_buffer[256]; // Buffer to store the text from the 84 | // selected item 85 | // Get the text of the selected item 86 | SendMessageW(hcar_ageDropdown, CB_GETLBTEXT, (WPARAM)car_age_tmp_index, 87 | (LPARAM)car_age_tmp_buffer); 88 | 89 | Form1Output.car_age = 90 | _wtoi(car_age_tmp_buffer); // Convert the wide string to an integer 91 | } 92 | 93 | wchar_t car_mileage_tmp_buffer[256]; 94 | GetWindowTextW(hcar_mileageInput, car_mileage_tmp_buffer, 256); 95 | Form1Output.car_mileage = _wtoi(car_mileage_tmp_buffer); 96 | 97 | Form1Output.is_electric = 98 | SendMessage(his_electricCheckbox, BM_GETCHECK, 0, 0) == BST_CHECKED; 99 | // Close the window 100 | DestroyWindow(hwnd); 101 | } 102 | break; 103 | 104 | case WM_DESTROY: 105 | PostQuitMessage(0); 106 | break; 107 | 108 | default: 109 | return DefWindowProcW(hwnd, msg, wParam, lParam); 110 | } 111 | 112 | return 0; 113 | } 114 | 115 | int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, 116 | int ncmdshow) { 117 | 118 | // Redirect console I/O 119 | RedirectIOToConsole(); 120 | 121 | int car_age = 5; 122 | int car_mileage = 200; 123 | bool is_electric = true; 124 | 125 | WNDCLASSW wc = {0}; 126 | wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); 127 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 128 | wc.hInstance = hInst; 129 | wc.lpszClassName = L"FormWindow"; 130 | wc.lpfnWndProc = WindowProcedure; 131 | 132 | if (!RegisterClassW(&wc)) { 133 | return -1; 134 | } 135 | 136 | CreateWindowW(L"FormWindow", L"Form", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 137 | // 100, 100, 400, 230, NULL, NULL, NULL, NULL); 138 | 100, 100, 400, 600, NULL, NULL, NULL, NULL); 139 | 140 | MSG msg = {0}; 141 | while (GetMessage(&msg, NULL, 0, 0)) { 142 | TranslateMessage(&msg); 143 | DispatchMessage(&msg); 144 | } 145 | 146 | car_age = Form1Output.car_age; 147 | car_mileage = Form1Output.car_mileage; 148 | is_electric = Form1Output.is_electric; 149 | 150 | printf("Car age is %d years.\n", car_age); 151 | printf("Car mileage is %d miles.\n", car_mileage); 152 | printf("Is the car electric? %d.\n", is_electric); 153 | 154 | return 0; 155 | } -------------------------------------------------------------------------------- /Lib/raylib.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | 4 | // This provides bindings for raylib.h. 5 | // https://github.com/raysan5/raylib/blob/master/LICENSE 6 | 7 | #include "raylib.h" 8 | 9 | typedef unsigned char u8; 10 | 11 | struct rlColor{Color color}; 12 | namespace rlColor 13 | c_function __init__(r : u8, g : u8, b : u8, a : u8) 14 | this->color = (Color){r, g, b, a}; 15 | endc_function 16 | endnamespace 17 | 18 | struct rlVector2{Vector2 vector2}; 19 | namespace rlVector2 20 | c_function __init__<>(x : float, y : float) 21 | this->vector2 = (Vector2){x, y}; 22 | endc_function 23 | 24 | c_function __init__<>(x : int, y : int) 25 | this->vector2 = (Vector2){(float)x, (float)y}; 26 | endc_function 27 | 28 | c_function __add__(p_vec : rlVector2) 29 | this->vector2.x = this->vector2.x + p_vec.vector2.x; 30 | this->vector2.y = this->vector2.y + p_vec.vector2.y; 31 | endc_function 32 | 33 | c_function __reassign__(p_vec : rlVector2) 34 | this->vector2 = p_vec.vector2; 35 | endc_function 36 | 37 | c_function __eq__(p_vector : rlVector2) -> bool: 38 | return this->vector2.x == p_vector.vector2.x && this->vector2.y == p_vector.vector2.y; 39 | endc_function 40 | 41 | c_function get_x() -> float: 42 | return this->vector2.x; 43 | endc_function 44 | 45 | c_function get_y() -> float: 46 | return this->vector2.y; 47 | endc_function 48 | 49 | c_function get_x_int() -> int: 50 | return (int)this->vector2.x; 51 | endc_function 52 | 53 | c_function get_y_int() -> int: 54 | return (int)this->vector2.y; 55 | endc_function 56 | 57 | c_function set_int(x : int, y : int) 58 | this->vector2.x = (float)x; 59 | this->vector2.y = (float)y; 60 | endc_function 61 | 62 | c_function translate_i(v : rlVector2) 63 | this->vector2.x = (int)this->vector2.x + (int)v.vector2.x; 64 | this->vector2.y = (int)this->vector2.y + (int)v.vector2.y; 65 | endc_function 66 | endnamespace 67 | 68 | struct raylib{char dummy}; 69 | namespace raylib 70 | c_function InitWindow(screenWidth : int, screenHeight : int, title : str) 71 | InitWindow(screenWidth, screenHeight, title); 72 | endc_function 73 | 74 | c_function WindowShouldOpen() -> bool: 75 | return !WindowShouldClose(); 76 | endc_function 77 | 78 | c_function CloseWindow() 79 | CloseWindow(); 80 | endc_function 81 | 82 | c_function ClearBackground(color : rlColor) 83 | ClearBackground(color.color); 84 | endc_function 85 | 86 | c_function BeginDrawing() 87 | BeginDrawing(); 88 | endc_function 89 | 90 | c_function EndDrawing() 91 | EndDrawing(); 92 | endc_function 93 | 94 | c_function SetTargetFPS(fps : int) 95 | SetTargetFPS(fps); 96 | endc_function 97 | 98 | c_function IsKeyPressed(key : int) -> bool: 99 | return IsKeyPressed(key); 100 | endc_function 101 | 102 | c_function DrawLine(startPosX : int, startPosY : int, endPosX : int, endPosY : int, color : rlColor) 103 | DrawLine(startPosX, startPosY, endPosX, endPosY, color.color); 104 | endc_function 105 | 106 | c_function DrawLineV(startPos : rlVector2, endPos : rlVector2, color : rlColor) 107 | DrawLineV(startPos.vector2, endPos.vector2, color.color); 108 | endc_function 109 | 110 | c_function DrawCircle(centerX : int, centerY : int, radius : float, color : rlColor) 111 | DrawCircle(centerX, centerY, radius, color.color); 112 | endc_function 113 | 114 | c_function DrawCircleGradient(centerX : int, centerY : int, radius : float, color1 : rlColor, color2 : rlColor) 115 | DrawCircleGradient(centerX, centerY, radius, color1.color, color2.color); 116 | endc_function 117 | 118 | c_function DrawCircleLines(centerX : int, centerY : int, radius : float, color : rlColor) 119 | DrawCircleLines(centerX, centerY, radius, color.color); 120 | endc_function 121 | 122 | c_function DrawRectangle(posX : int, posY : int, width : int, height : int, color : rlColor) 123 | DrawRectangle(posX, posY, width, height, color.color); 124 | endc_function 125 | 126 | c_function DrawRectangleV(position : rlVector2, size : rlVector2, color : rlColor) 127 | DrawRectangleV(position.vector2, size.vector2, color.color); 128 | endc_function 129 | 130 | c_function DrawRectangleGradientV(posX : int, posY : int, width : int, height : int, color1 : rlColor, color2 : rlColor) 131 | DrawRectangleGradientV(posX, posY, width, height, color1.color, color2.color); 132 | endc_function 133 | 134 | c_function DrawRectangleGradientH(posX : int, posY : int, width : int, height : int, color1 : rlColor, color2 : rlColor) 135 | DrawRectangleGradientH(posX, posY, width, height, color1.color, color2.color); 136 | endc_function 137 | 138 | c_function DrawRectangleLines(posX : int, posY : int, width : int, height : int, color : rlColor) 139 | DrawRectangleLines(posX, posY, width, height, color.color); 140 | endc_function 141 | 142 | c_function DrawTriangle(v1 : rlVector2, v2 : rlVector2, v3 : rlVector2, color : rlColor) 143 | DrawTriangle(v1.vector2, v2.vector2, v3.vector2, color.color); 144 | endc_function 145 | 146 | c_function DrawTriangleLines(v1 : rlVector2, v2 : rlVector2, v3 : rlVector2, color : rlColor) 147 | DrawTriangleLines(v1.vector2, v2.vector2, v3.vector2, color.color); 148 | endc_function 149 | 150 | c_function DrawPoly(center : rlVector2, sides : int, radius : float, rotation : float, color : rlColor) 151 | DrawPoly(center.vector2, sides, radius, rotation, color.color); 152 | endc_function 153 | 154 | c_function DrawPolyLines(center : rlVector2, sides : int, radius : float, rotation : float, color : rlColor) 155 | DrawPolyLines(center.vector2, sides, radius, rotation, color.color); 156 | endc_function 157 | 158 | c_function DrawPolyLinesEx(center : rlVector2, sides : int, radius : float, rotation : float, lineThick : float, color : rlColor) 159 | DrawPolyLinesEx(center.vector2, sides, radius, rotation, lineThick, color.color); 160 | endc_function 161 | 162 | c_function DrawText(text : str, x : int, y : int, font_size : int, color : rlColor) 163 | DrawText(text, x, y, font_size, color.color); 164 | endc_function 165 | endnamespace 166 | ///*/// 167 | -------------------------------------------------------------------------------- /Lib/Threads.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | void** buffer; 9 | size_t capacity; 10 | size_t size; 11 | size_t head; 12 | size_t tail; 13 | bool is_closed; 14 | pthread_mutex_t mutex; 15 | pthread_cond_t can_send; 16 | pthread_cond_t can_receive; 17 | } ChannelInternal; 18 | 19 | typedef struct { 20 | void* data; 21 | bool ok; 22 | } ChannelResultInternal; 23 | 24 | typedef void* ThreadInternalVoidPointer; 25 | 26 | ///*/// 27 | 28 | struct Channel {ChannelInternal channel}; 29 | 30 | struct ChannelResult{ChannelResultInternal result}; 31 | 32 | namespace ChannelResult 33 | 34 | c_function is_ok() -> bool: 35 | return this->result.ok; 36 | endc_function 37 | 38 | endnamespace 39 | 40 | struct IntChannelResult{int value, bool ok}; 41 | 42 | namespace IntChannelResult 43 | c_function is_ok() -> bool: 44 | return this->ok; 45 | endc_function 46 | 47 | c_function get_value() -> int: 48 | return this->value; 49 | endc_function 50 | endnamespace 51 | 52 | namespace Channel 53 | 54 | c_function __init__(capacity : int) 55 | if (capacity <= 0) { 56 | fprintf(stderr, "Error: Channel capacity must be positive.\n"); 57 | exit(-1); 58 | } 59 | 60 | ChannelInternal *ch = &this->channel; 61 | 62 | ch->buffer = (void **)malloc(capacity * sizeof(void *)); 63 | if (!ch->buffer) { 64 | fprintf(stderr, "Error: Memory allocation failed for Channel buffer.\n"); 65 | exit(-1); 66 | } 67 | 68 | ch->capacity = capacity; 69 | ch->size = 0; 70 | ch->head = 0; 71 | ch->tail = 0; 72 | ch->is_closed = false; 73 | 74 | pthread_mutex_init(&ch->mutex, NULL); 75 | pthread_cond_init(&ch->can_send, NULL); 76 | pthread_cond_init(&ch->can_receive, NULL); 77 | endc_function 78 | 79 | c_function ToThreadVoidPointer() -> ThreadInternalVoidPointer: 80 | ThreadInternalVoidPointer ptr = (ThreadInternalVoidPointer)this; 81 | return ptr; 82 | endc_function 83 | 84 | c_function send_ptr(data : ThreadInternalVoidPointer) -> bool: 85 | ChannelInternal* ch = &this->channel; 86 | pthread_mutex_lock(&ch->mutex); 87 | 88 | while (ch->size == ch->capacity) { 89 | if (ch->is_closed) { 90 | pthread_mutex_unlock(&ch->mutex); 91 | return false; 92 | } 93 | pthread_cond_wait(&ch->can_send, &ch->mutex); 94 | } 95 | 96 | if (ch->is_closed) { 97 | pthread_mutex_unlock(&ch->mutex); 98 | return false; 99 | } 100 | 101 | ch->buffer[ch->tail] = data; 102 | ch->tail = (ch->tail + 1) % ch->capacity; 103 | ch->size++; 104 | 105 | pthread_cond_signal(&ch->can_receive); 106 | pthread_mutex_unlock(&ch->mutex); 107 | 108 | return true; 109 | endc_function 110 | 111 | c_function send(data : int) -> bool: 112 | int *value = (int*)malloc(sizeof(int)); 113 | if (!value) { 114 | fprintf(stderr, "Error: Threads::send() Memory allocation failed for sending data.\n"); 115 | return false; 116 | } 117 | *value = data; 118 | return Channelsend_ptr(this, (ThreadInternalVoidPointer)value); 119 | endc_function 120 | 121 | c_function receive() -> ChannelResult: 122 | ChannelInternal* ch = &this->channel; 123 | pthread_mutex_lock(&ch->mutex); 124 | while (ch->size == 0) { 125 | if (ch->is_closed) { 126 | pthread_mutex_unlock(&ch->mutex); 127 | ChannelResultInternal result = {NULL, false}; 128 | struct ChannelResult res; 129 | res.result = result; 130 | return res; 131 | } 132 | pthread_cond_wait(&ch->can_receive, &ch->mutex); 133 | } 134 | 135 | void* data = ch->buffer[ch->head]; 136 | ch->head = (ch->head + 1) % ch->capacity; 137 | ch->size--; 138 | pthread_cond_signal(&ch->can_send); 139 | pthread_mutex_unlock(&ch->mutex); 140 | 141 | ChannelResultInternal result = {data, true}; 142 | struct ChannelResult res; 143 | res.result = result; 144 | return res; 145 | endc_function 146 | 147 | c_function receive_int() -> IntChannelResult: 148 | ChannelInternal* ch = &this->channel; 149 | pthread_mutex_lock(&ch->mutex); 150 | while (ch->size == 0) { 151 | if (ch->is_closed) { 152 | pthread_mutex_unlock(&ch->mutex); 153 | struct IntChannelResult res = {0, false}; 154 | return res; 155 | } 156 | pthread_cond_wait(&ch->can_receive, &ch->mutex); 157 | } 158 | 159 | int* data = (int*)ch->buffer[ch->head]; 160 | ch->head = (ch->head + 1) % ch->capacity; 161 | ch->size--; 162 | pthread_cond_signal(&ch->can_send); 163 | pthread_mutex_unlock(&ch->mutex); 164 | 165 | struct IntChannelResult res = {*data, true}; 166 | free(data); 167 | return res; 168 | endc_function 169 | 170 | c_function close() 171 | ChannelInternal* ch = &this->channel; 172 | pthread_mutex_lock(&ch->mutex); 173 | if (ch->is_closed) { 174 | pthread_mutex_unlock(&ch->mutex); 175 | return; 176 | } 177 | 178 | ch->is_closed = true; 179 | pthread_cond_broadcast(&ch->can_receive); 180 | pthread_cond_broadcast(&ch->can_send); 181 | pthread_mutex_unlock(&ch->mutex); 182 | endc_function 183 | 184 | c_function __del__() 185 | ChannelInternal *ch = &this->channel; 186 | 187 | pthread_mutex_lock(&ch->mutex); 188 | 189 | for (size_t i = 0; i < ch->size; i++) { 190 | size_t index = (ch->head + i) % ch->capacity; 191 | free(ch->buffer[index]); 192 | } 193 | 194 | free(ch->buffer); 195 | ch->buffer = NULL; 196 | ch->size = 0; 197 | ch->capacity = 0; 198 | ch->head = 0; 199 | ch->tail = 0; 200 | ch->is_closed = true; 201 | 202 | pthread_mutex_unlock(&ch->mutex); 203 | 204 | pthread_mutex_destroy(&ch->mutex); 205 | pthread_cond_destroy(&ch->can_send); 206 | pthread_cond_destroy(&ch->can_receive); 207 | endc_function 208 | 209 | endnamespace 210 | 211 | struct Thread{pthread_t id, bool joined}; 212 | 213 | namespace Thread 214 | 215 | c_function __init__(start_routine: Fn(ThreadInternalVoidPointer) -> ThreadInternalVoidPointer, arg : ThreadInternalVoidPointer) 216 | if (pthread_create(&this->id, NULL, start_routine, arg) != 0) { 217 | fprintf(stderr, "Error: Failed to create thread.\n"); 218 | exit(-1); 219 | } 220 | this->joined = false; 221 | endc_function 222 | 223 | c_function join() 224 | pthread_join(this->id, NULL); 225 | this->joined = true; 226 | endc_function 227 | 228 | c_function __del__() 229 | if (!this->joined) { 230 | fprintf(stderr, "Warning: Thread was not joined before deletion.\n"); 231 | pthread_detach(this->id); 232 | } 233 | endc_function 234 | endnamespace 235 | ///*/// 236 | 237 | -------------------------------------------------------------------------------- /examples/raylib/snake.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // https://github.com/raysan5/raylib/wiki/Working-on-Windows 5 | // Open C:\raylib\w64devkit\w64devkit.exe 6 | // ~ $ cd "E:\ANIL\examples\raylib" 7 | // ~ $ gcc -o snake.exe snake_generated.c -lraylib -lgdi32 -lwinmm 8 | // ~ $ snake 9 | 10 | // IMPORTS // 11 | 12 | // STRUCT_DEFINATIONS // 13 | 14 | ///*/// 15 | import raylib 16 | import Random 17 | 18 | struct Food{rlVector2 position}; 19 | namespace Food 20 | function __init__(p_position : rlVector2) 21 | this.position = p_position 22 | endfunction 23 | endnamespace 24 | 25 | struct Snake{rlVector2 position, rlVector2 speed, Vector body}; 26 | namespace Snake 27 | function __init__(p_position : rlVector2, p_speed : rlVector2) 28 | this.position = p_position 29 | this.speed = p_speed 30 | this.body.__init__(10) 31 | endfunction 32 | 33 | function is_touching_itself() -> bool: 34 | let body_ref = this.body 35 | 36 | for body_pos in body_ref[1:]{ 37 | if this.position == body_pos{ 38 | return true 39 | } 40 | } 41 | return false 42 | endfunction 43 | 44 | function ate_food(p_food : Food) -> bool: 45 | return this.position == p_food.position 46 | endfunction 47 | 48 | function move_body() 49 | for i in range(1..=this.body.len()-1,-1){ 50 | let left_pos = this.body[i - 1] 51 | this.body[i] = left_pos 52 | } 53 | endfunction 54 | 55 | function is_out_of_bounds(GRID_WIDTH : int, GRID_HEIGHT : int) -> bool: 56 | if this.position.get_x_int() < 0{ 57 | return true 58 | } else if this.position.get_x_int() >= GRID_WIDTH{ 59 | return true 60 | } else if this.position.get_y_int() < 0{ 61 | return true 62 | } else if this.position.get_y_int() >= GRID_HEIGHT{ 63 | return true 64 | } 65 | return false 66 | endfunction 67 | endnamespace 68 | 69 | function new_food_spawn(snake : Snake, grid_width : int, grid_height : int) -> rlVector2: 70 | let rng = Random{}; 71 | 72 | while true { 73 | let new_x = rng.randrange(grid_width) 74 | let new_y = rng.randrange(grid_height) 75 | let new_pos = rlVector2{new_x, new_y}; 76 | 77 | if new_pos not in snake.body{ 78 | return new_pos 79 | } 80 | } 81 | 82 | // Infinite loop above or should never reach here. 83 | let res = rlVector2{0, 0}; 84 | return res; 85 | endfunction 86 | ///*/// 87 | 88 | int main() { 89 | 90 | // clang-format off 91 | 92 | ///*/// main() 93 | import Vector 94 | import String 95 | 96 | let rlRED = rlColor{ 230, 41, 55, 255 }; 97 | let rlGREEN = rlColor{ 0, 228, 48, 255 }; 98 | let rlRAYWHITE = rlColor{ 245, 245, 245, 255 }; 99 | let rlBLACK = rlColor{ 0, 0, 0, 255 }; 100 | 101 | let rlKEY_UP : int = 265 102 | let rlKEY_DOWN : int = 264 103 | let rlKEY_RIGHT : int = 262 104 | let rlKEY_LEFT : int = 263 105 | let rlKEY_R : int = 82 106 | 107 | let CELL_SIZE : int = 20 108 | let GRID_WIDTH : int = 25 109 | let GRID_HEIGHT : int = 25 110 | 111 | let w_x : int = GRID_WIDTH * CELL_SIZE 112 | let w_y : int = GRID_HEIGHT * CELL_SIZE 113 | 114 | let mid_x : int = GRID_WIDTH / 2 115 | let mid_y : int = GRID_HEIGHT / 2 116 | 117 | let pos = rlVector2{mid_x, mid_y}; 118 | let speed = rlVector2{1, 0}; 119 | 120 | let snake = Snake{pos, speed}; 121 | snake.body.push(pos) 122 | 123 | let new_food_pos = new_food_spawn(snake, GRID_WIDTH, GRID_HEIGHT) 124 | let food = Food{new_food_pos}; 125 | 126 | let gameOver : bool = false 127 | 128 | let score : int = 0 129 | let scoreText = "Score: 0 " 130 | // ^^^^^^^^^ These spaces act as a buffer where sprintf 131 | // can write the score digits. 132 | 133 | let rl = raylib{}; 134 | rl.InitWindow(w_x, w_y, "Snake Game") 135 | rl.SetTargetFPS(10) 136 | 137 | while rl.WindowShouldOpen(){ 138 | rl.BeginDrawing() 139 | 140 | if gameOver{ 141 | rl.ClearBackground(rlRAYWHITE) 142 | rl.DrawText("Game Over! Press R to Restart", 100, 200, 20, rlRED) 143 | if rl.IsKeyPressed(rlKEY_R){ 144 | gameOver = False 145 | 146 | snake.speed.set_int(1, 0) 147 | snake.position.set_int(mid_x, mid_y) 148 | 149 | snake.body.clear() 150 | snake.body.push(snake.position) 151 | 152 | food.position = new_food_spawn(snake, GRID_WIDTH, GRID_HEIGHT) 153 | 154 | score = 0 155 | let score_ptr = scoreText.c_str() 156 | sprintf(score_ptr, "Score: %d", score); 157 | } 158 | }else{ 159 | rl.ClearBackground(rlBLACK) 160 | 161 | // Update game. 162 | if rl.IsKeyPressed(rlKEY_UP){ 163 | if snake.speed.get_y() == 0{ 164 | snake.speed.set_int(0, -1) 165 | } 166 | } 167 | if rl.IsKeyPressed(rlKEY_DOWN){ 168 | if snake.speed.get_y() == 0{ 169 | snake.speed.set_int(0, 1) 170 | } 171 | } 172 | if rl.IsKeyPressed(rlKEY_LEFT){ 173 | if snake.speed.get_x() == 0{ 174 | snake.speed.set_int(-1, 0) 175 | } 176 | } 177 | if rl.IsKeyPressed(rlKEY_RIGHT){ 178 | if snake.speed.get_x() == 0{ 179 | snake.speed.set_int(1, 0) 180 | } 181 | } 182 | 183 | snake.move_body() 184 | 185 | // Update head position. 186 | snake.position.translate_i(snake.speed) 187 | snake.body[0] = snake.position 188 | 189 | // Check for wall collisions. 190 | if snake.is_out_of_bounds(GRID_WIDTH, GRID_HEIGHT){ 191 | gameOver = True 192 | } 193 | 194 | if snake.is_touching_itself(){ 195 | gameOver = True 196 | } 197 | 198 | if snake.ate_food(food){ 199 | let last_pos = snake.body[-1] 200 | last_pos += snake.speed 201 | 202 | snake.body.push(last_pos) 203 | 204 | food.position = new_food_spawn(snake, GRID_WIDTH, GRID_HEIGHT) 205 | 206 | score = score + 1 207 | let score_ptr = scoreText.c_str() 208 | sprintf(score_ptr, "Score: %d", score); 209 | } 210 | 211 | // Draw food. 212 | let fx : int = food.position.get_x_int() * CELL_SIZE 213 | let fy : int = food.position.get_y_int() * CELL_SIZE 214 | 215 | rl.DrawRectangle(fx, fy, CELL_SIZE, CELL_SIZE, rlRED) 216 | 217 | // Draw snake 218 | for body in snake.body{ 219 | let x : int = body.get_x_int() * CELL_SIZE 220 | let y : int = body.get_y_int() * CELL_SIZE 221 | 222 | rl.DrawRectangle(x, y, CELL_SIZE, CELL_SIZE, rlGREEN) 223 | } 224 | } 225 | 226 | rl.DrawText(scoreText, 10, 20, 20, rlRED) 227 | 228 | rl.EndDrawing() 229 | } 230 | 231 | rl.CloseWindow() 232 | 233 | // DESTRUCTOR_CODE // 234 | ///*/// 235 | // clang-format on 236 | 237 | return 0; 238 | } -------------------------------------------------------------------------------- /Bootstrap/Lexer.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | #include 3 | #include 4 | #include 5 | 6 | void CustomPrint(int data) { 7 | // printf("This is a custom print wrapper. [%d]\n", data); 8 | 9 | // The macro is in str, val pair because it is in this format in TOKEN_MAP 10 | // below. 11 | // clang-format off 12 | 13 | #define token_case(str, val) \ 14 | case val: msg = str; break \ 15 | 16 | char *msg; 17 | 18 | switch (data) { 19 | token_case("LET", 0); 20 | token_case("EQUALS", 1); 21 | token_case("LEFT_SQUARE_BRACKET", 2); 22 | token_case("RIGHT_SQUARE_BRACKET", 3); 23 | token_case("SEMICOLON", 4); 24 | token_case("COMMA", 5); 25 | token_case("PERCENT", 6); 26 | token_case("LEFT_CURLY", 7); 27 | token_case("RIGHT_CURLY", 8); 28 | token_case("STRUCT", 9); 29 | token_case("MATCH", 10); 30 | token_case("FOR", 11); 31 | token_case("IF", 12); 32 | token_case("IN", 13); 33 | token_case("OPTION", 14); 34 | token_case("SMALLER_THAN", 15); 35 | token_case("GREATER_THAN", 16); 36 | token_case("ENUMERATE", 17); 37 | token_case("QUOTE", 18); 38 | token_case("PLUS", 19); 39 | token_case("LEFT_ROUND_BRACKET", 21); 40 | token_case("RIGHT_ROUND_BRACKET", 22); 41 | token_case("COLON", 23); 42 | token_case("DOT", 24); 43 | token_case("ASTERISK", 25); 44 | token_case("MINUS", 26); 45 | token_case("DEF", 27); 46 | token_case("c_function", 28); 47 | token_case("ENDDEF", 29); 48 | token_case("ENDFN", 30); 49 | token_case("ELSE", 31); 50 | token_case("TRUE", 32); 51 | token_case("FALSE", 33); 52 | token_case("CONSTEXPR", 34); 53 | token_case("HASH", 35); 54 | token_case("INCLUDE", 36); 55 | token_case("AT", 37); 56 | token_case("APPLY_HOOK", 38); 57 | token_case("HOOK_BEGIN", 39); 58 | token_case("HOOK_END", 40); 59 | token_case("EXCLAMATION", 41); 60 | default: { 61 | msg = "UNDEFINED: "; 62 | break; 63 | } 64 | } 65 | 66 | // clang-format on 67 | printf("Token : %s", msg); 68 | 69 | #undef token_case 70 | } 71 | 72 | ///*/// 73 | 74 | import Vector 75 | import String 76 | import Dictionary 77 | import List 78 | 79 | constexpr Token = {"LET" : 0, "EQUALS" : 1, "LEFT_SQUARE_BRACKET" : 2, "RIGHT_SQUARE_BRACKET" : 3, "SEMICOLON" : 4, "COMMA" : 5, "PERCENT" : 6, "LEFT_CURLY" : 7, "RIGHT_CURLY" : 8, "STRUCT" : 9, "MATCH" : 10, "FOR" : 11, "IF" : 12, "IN" : 13, "OPTION" : 14, "SMALLER_THAN" : 15, "GREATER_THAN" : 16, "ENUMERATE" : 17, "QUOTE" : 18, "PLUS" : 19, "LEFT_ROUND_BRACKET" : 21, "RIGHT_ROUND_BRACKET" : 22, "COLON" : 23, "DOT" : 24, "ASTERISK" : 25, "MINUS" : 26, "DEF" : 27, "CFUNCTION" : 28, "ENDDEF" : 29, "ENDFN" : 30, "ELSE" : 31, "TRUE" : 32, "FALSE" : 33, "CONSTEXPR" : 34, "HASH" : 35, "INCLUDE" : 36, "AT" : 37, "APPLY_HOOK" : 38, "HOOK_BEGIN" : 39, "HOOK_END" : 40, "EXCLAMATION" : 41} 80 | 81 | struct Lexer{int dummy}; 82 | 83 | namespace Lexer 84 | 85 | function get_tokens(p_line : String) -> List: 86 | let CHARACTER_TOKENS = {}; 87 | CHARACTER_TOKENS["="] = Token["EQUALS"] 88 | CHARACTER_TOKENS["["] = Token["LEFT_SQUARE_BRACKET"] 89 | CHARACTER_TOKENS["]"] = Token["RIGHT_SQUARE_BRACKET"] 90 | CHARACTER_TOKENS[";"] = Token["SEMICOLON"] 91 | CHARACTER_TOKENS[","] = Token["COMMA"] 92 | CHARACTER_TOKENS["%"] = Token["PERCENT"] 93 | CHARACTER_TOKENS["{"] = Token["LEFT_CURLY"] 94 | CHARACTER_TOKENS["}"] = Token["RIGHT_CURLY"] 95 | CHARACTER_TOKENS["<"] = Token["SMALLER_THAN"] 96 | CHARACTER_TOKENS[">"] = Token["GREATER_THAN"] 97 | CHARACTER_TOKENS["\""] = Token["QUOTE"] 98 | CHARACTER_TOKENS["+"] = Token["PLUS"] 99 | CHARACTER_TOKENS["("] = Token["LEFT_ROUND_BRACKET"] 100 | CHARACTER_TOKENS[")"] = Token["RIGHT_ROUND_BRACKET"] 101 | CHARACTER_TOKENS[":"] = Token["COLON"] 102 | CHARACTER_TOKENS["."] = Token["DOT"] 103 | CHARACTER_TOKENS["*"] = Token["ASTERISK"] 104 | CHARACTER_TOKENS["-"] = Token["MINUS"] 105 | CHARACTER_TOKENS["#"] = Token["HASH"] 106 | CHARACTER_TOKENS["@"] = Token["AT"] 107 | CHARACTER_TOKENS["!"] = Token["EXCLAMATION"] 108 | 109 | let KEYWORD_TOKENS = {}; 110 | KEYWORD_TOKENS["let"] = Token["LET"] 111 | KEYWORD_TOKENS["struct"] = Token["STRUCT"] 112 | KEYWORD_TOKENS["match"] = Token["MATCH"] 113 | KEYWORD_TOKENS["for"] = Token["FOR"] 114 | KEYWORD_TOKENS["if"] = Token["IF"] 115 | KEYWORD_TOKENS["in"] = Token["IN"] 116 | KEYWORD_TOKENS["Option"] = Token["OPTION"] 117 | KEYWORD_TOKENS["enumerate"] = Token["ENUMERATE"] 118 | KEYWORD_TOKENS["def"] = Token["DEF"] 119 | KEYWORD_TOKENS["c_function"] = Token["CFUNCTION"] 120 | KEYWORD_TOKENS["enddef"] = Token["ENDDEF"] 121 | KEYWORD_TOKENS["endfunc"] = Token["ENDFN"] 122 | KEYWORD_TOKENS["else"] = Token["ELSE"] 123 | KEYWORD_TOKENS["True"] = Token["TRUE"] 124 | KEYWORD_TOKENS["False"] = Token["FALSE"] 125 | KEYWORD_TOKENS["constexpr"] = Token["CONSTEXPR"] 126 | KEYWORD_TOKENS["include"] = Token["INCLUDE"] 127 | KEYWORD_TOKENS["apply_hook"] = Token["APPLY_HOOK"] 128 | KEYWORD_TOKENS["hook_begin"] = Token["HOOK_BEGIN"] 129 | KEYWORD_TOKENS["hook_end"] = Token["HOOK_END"] 130 | 131 | let line = p_line.strip() 132 | let length = line.len() 133 | 134 | let token = "" 135 | 136 | let tokens = []; 137 | 138 | let inside_string = False 139 | let escape_back_slash = False 140 | 141 | def add_token_raw(p_token): 142 | tokens.append_str(p_token) 143 | enddef 144 | 145 | def add_token(p_token): 146 | if p_token in KEYWORD_TOKENS{ 147 | tokens.append(KEYWORD_TOKENS[p_token]) 148 | }else if p_token in CHARACTER_TOKENS{ 149 | tokens.append(CHARACTER_TOKENS[p_token]) 150 | }else{ 151 | add_token_raw p_token 152 | } 153 | enddef 154 | 155 | line.printLn() 156 | 157 | for Char in line{ 158 | #print("{Char}") 159 | 160 | if escape_back_slash{ 161 | if Char == "\""{ 162 | token += Char 163 | escape_back_slash = False 164 | }else if Char == "\\"{ 165 | token += "\\\\" 166 | escape_back_slash = False 167 | }else{ 168 | token += Char 169 | escape_back_slash = False 170 | } 171 | }else if Char == "\""{ 172 | if inside_string{ 173 | # End of string. 174 | inside_string = False 175 | 176 | // Single character tokens like = are tokenized by add_token(), 177 | // so we use the following method. 178 | // "=" the inner equals to shouldn't be tokenized. 179 | add_token_raw token 180 | 181 | token = "" 182 | }else{ 183 | # Start of string. 184 | inside_string = True 185 | } 186 | tokens.append(Token["QUOTE"]) 187 | } else if inside_string{ 188 | if Char == "\\"{ 189 | escape_back_slash = True 190 | continue; 191 | } 192 | 193 | token += Char 194 | } else if Char == " "{ 195 | if token == ""{ 196 | continue; 197 | } 198 | 199 | add_token token 200 | token = "" 201 | }else{ 202 | if Char in CHARACTER_TOKENS{ 203 | if token != ""{ 204 | add_token token 205 | } 206 | tokens.append(CHARACTER_TOKENS[Char]) 207 | token = "" 208 | continue; 209 | } 210 | 211 | if token in CHARACTER_TOKENS{ 212 | tokens.append(CHARACTER_TOKENS[token]) 213 | token = "" 214 | continue; 215 | } 216 | 217 | token += Char 218 | } 219 | 220 | 221 | } 222 | 223 | # Process the last token. 224 | if token != ""{ 225 | add_token token 226 | } 227 | 228 | return tokens 229 | endfunction 230 | 231 | endnamespace 232 | ///*/// 233 | -------------------------------------------------------------------------------- /lexer.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Token(Enum): 5 | LET = 0 6 | EQUALS = 1 7 | LEFT_SQUARE_BRACKET = 2 8 | RIGHT_SQUARE_BRACKET = 3 9 | SEMICOLON = 4 10 | COMMA = 5 11 | PERCENT = 6 12 | LEFT_CURLY = 7 13 | RIGHT_CURLY = 8 14 | STRUCT = 9 15 | MATCH = 10 16 | FOR = 11 17 | IF = 12 18 | IN = 13 19 | OPTION = 14 20 | SMALLER_THAN = 15 21 | GREATER_THAN = 16 22 | ENUMERATE = 17 23 | QUOTE = 18 24 | PLUS = 19 25 | LEFT_ROUND_BRACKET = 21 26 | RIGHT_ROUND_BRACKET = 22 27 | COLON = 23 28 | DOT = 24 29 | ASTERISK = 25 30 | MINUS = 26 31 | DEF = 27 32 | ENDDEF = 28 33 | CFUNCTION = 29 34 | ENDCFUNCTION = 30 35 | ELSE = 31 36 | TRUE = 32 37 | FALSE = 33 38 | CONSTEXPR = 34 39 | HASH = 35 40 | INCLUDE = 36 41 | AT = 37 42 | APPLY_HOOK = 38 43 | HOOK_BEGIN = 39 44 | HOOK_END = 40 45 | EXCLAMATION = 41 46 | FUNCTION = 42 47 | ENDFUNCTION = 43 48 | RETURN = 44 49 | NAMESPACE = 45 50 | ENDNAMESPACE = 46 51 | FRONT_SLASH = 47 52 | AMPERSAND = 48 53 | CONST = 49 54 | WHILE = 50 55 | NOT = 51 56 | TILDE = 52 57 | 58 | 59 | CHARACTER_TOKENS = { 60 | "=": Token.EQUALS, 61 | "[": Token.LEFT_SQUARE_BRACKET, 62 | "]": Token.RIGHT_SQUARE_BRACKET, 63 | ";": Token.SEMICOLON, 64 | ",": Token.COMMA, 65 | "%": Token.PERCENT, 66 | "{": Token.LEFT_CURLY, 67 | "}": Token.RIGHT_CURLY, 68 | "<": Token.SMALLER_THAN, 69 | ">": Token.GREATER_THAN, 70 | '"': Token.QUOTE, 71 | "+": Token.PLUS, 72 | "(": Token.LEFT_ROUND_BRACKET, 73 | ")": Token.RIGHT_ROUND_BRACKET, 74 | ":": Token.COLON, 75 | ".": Token.DOT, 76 | "*": Token.ASTERISK, 77 | "-": Token.MINUS, 78 | "#": Token.HASH, 79 | "@": Token.AT, 80 | "!": Token.EXCLAMATION, 81 | "/": Token.FRONT_SLASH, 82 | "&": Token.AMPERSAND, 83 | "~": Token.TILDE, 84 | } 85 | 86 | 87 | KEYWORD_TOKENS = { 88 | "let": Token.LET, 89 | "const": Token.CONST, 90 | "struct": Token.STRUCT, 91 | "match": Token.MATCH, 92 | "for": Token.FOR, 93 | "while": Token.WHILE, 94 | "if": Token.IF, 95 | "in": Token.IN, 96 | "Option": Token.OPTION, 97 | "enumerate": Token.ENUMERATE, 98 | "def": Token.DEF, 99 | "c_function": Token.CFUNCTION, 100 | "endc_function": Token.ENDCFUNCTION, 101 | "enddef": Token.ENDDEF, 102 | "else": Token.ELSE, 103 | "not": Token.NOT, 104 | "True": Token.TRUE, 105 | "False": Token.FALSE, 106 | "constexpr": Token.CONSTEXPR, 107 | "include": Token.INCLUDE, 108 | "apply_hook": Token.APPLY_HOOK, 109 | "hook_begin": Token.HOOK_BEGIN, 110 | "hook_end": Token.HOOK_END, 111 | "function": Token.FUNCTION, 112 | "endfunction": Token.ENDFUNCTION, 113 | "return": Token.RETURN, 114 | "namespace": Token.NAMESPACE, 115 | "endnamespace": Token.ENDNAMESPACE, 116 | } 117 | 118 | 119 | def token_to_str(token): 120 | """Return the corresponding key from a Token value in either CHARACTER_TOKENS or KEYWORD_TOKENS.""" 121 | for key, tok in CHARACTER_TOKENS.items(): 122 | if tok == token: 123 | return key 124 | 125 | for key, tok in KEYWORD_TOKENS.items(): 126 | if tok == token: 127 | return key 128 | 129 | return None 130 | 131 | 132 | def get_escaped_length(line): 133 | """ 134 | Returns the length of the string considering escape sequences. 135 | Escape sequences are counted as 1 character each, not their literal representations. 136 | """ 137 | 138 | """ 139 | Escape sequences such as \n are not encoded as a single character '\n', but as two independent 140 | characters '\','n' because when we output the string, the '\n' will be converted to a new line and, 141 | an extra line will be added to the generated output file. We don't want this. 142 | That's why we have this representation. 143 | However, the actual length of the string should be the escaped length. 144 | """ 145 | 146 | length = 0 147 | i = 0 148 | while i < len(line): 149 | if line[i] == '\\' and i + 1 < len(line): 150 | # If an escape sequence is detected, we just count the escape character and the next one 151 | length += 1 152 | i += 2 # Skip the next character as it's part of the escape sequence 153 | else: 154 | length += 1 155 | i += 1 156 | return length 157 | 158 | 159 | def get_tokens(line): 160 | line = line.strip("\n") 161 | length = len(line) 162 | 163 | token = "" 164 | tokens = [] 165 | 166 | inside_string = False 167 | 168 | def add_token_raw(p_token): 169 | tokens.append(p_token) 170 | 171 | def add_token(p_token): 172 | if p_token in KEYWORD_TOKENS.keys(): 173 | tokens.append(KEYWORD_TOKENS[p_token]) 174 | elif p_token in CHARACTER_TOKENS.keys(): 175 | tokens.append(CHARACTER_TOKENS[p_token]) 176 | else: 177 | # "=" the inner equals to shouldn't be tokenized. 178 | add_token_raw(p_token) 179 | 180 | escape_back_slash = False 181 | 182 | for i in range(length): 183 | char = line[i] 184 | 185 | if escape_back_slash: 186 | if char == '"': 187 | token += char 188 | escape_back_slash = False 189 | elif char == "\\": 190 | token += "\\\\" 191 | escape_back_slash = False 192 | else: 193 | token += "\\" 194 | token += char 195 | escape_back_slash = False 196 | elif char == '"': 197 | if inside_string: 198 | # End of string. 199 | inside_string = False 200 | 201 | # Single character tokens like = are tokenized by add_token(), 202 | # so we use the following method. 203 | # "=" the inner equals to shouldn't be tokenized. 204 | add_token_raw(token) 205 | 206 | token = "" 207 | else: 208 | # Start of string. 209 | inside_string = True 210 | tokens.append(Token.QUOTE) 211 | elif inside_string: 212 | # \" 213 | if char == "\\": 214 | escape_back_slash = True 215 | continue 216 | 217 | token += char 218 | elif char == " " or char == "\t": 219 | if token == "": 220 | continue 221 | add_token(token) 222 | token = "" 223 | else: 224 | if char in CHARACTER_TOKENS: 225 | if token != "": 226 | add_token(token) 227 | tokens.append(CHARACTER_TOKENS[char]) 228 | token = "" 229 | continue 230 | 231 | if token in CHARACTER_TOKENS: 232 | tokens.append(CHARACTER_TOKENS[token]) 233 | token = "" 234 | continue 235 | token += char 236 | 237 | # Process the last token. 238 | if token != "": 239 | add_token(token) 240 | 241 | # print(tokens) 242 | return tokens 243 | 244 | 245 | if __name__ == "__main__": 246 | 247 | line = '"="' 248 | tk = get_tokens(line) 249 | 250 | line = '" String Str " " {{ ] } t{10, 20}; ' 251 | tk = get_tokens(line) 252 | print(tk) 253 | 254 | line = " let arr = [ 1, 2, 3, 4 , 5 ]; } let" 255 | tk = get_tokens(line) 256 | print(tk) 257 | 258 | # let p1 = Point{10, 20}; 259 | line = "let p1 = Point {10, 20};" 260 | tk = get_tokens(line) 261 | print(tk) 262 | 263 | line = "\tlet p1" 264 | tk = get_tokens(line) 265 | print(tk) 266 | -------------------------------------------------------------------------------- /Bootstrap/lexer_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // IMPORTS // 6 | 7 | // STRUCT_DEFINATIONS // 8 | 9 | void CustomPrint(int data) { 10 | // printf("This is a custom print wrapper. [%d]\n", data); 11 | 12 | // The macro is in str, val pair because it is in this format in TOKEN_MAP 13 | // below. 14 | // clang-format off 15 | 16 | #define token_case(str, val) \ 17 | case val: msg = str; break \ 18 | 19 | char *msg; 20 | 21 | switch (data) { 22 | token_case("LET", 0); 23 | token_case("EQUALS", 1); 24 | token_case("LEFT_SQUARE_BRACKET", 2); 25 | token_case("RIGHT_SQUARE_BRACKET", 3); 26 | token_case("SEMICOLON", 4); 27 | token_case("COMMA", 5); 28 | token_case("PERCENT", 6); 29 | token_case("LEFT_CURLY", 7); 30 | token_case("RIGHT_CURLY", 8); 31 | token_case("STRUCT", 9); 32 | token_case("MATCH", 10); 33 | token_case("FOR", 11); 34 | token_case("IF", 12); 35 | token_case("IN", 13); 36 | token_case("OPTION", 14); 37 | token_case("SMALLER_THAN", 15); 38 | token_case("GREATER_THAN", 16); 39 | token_case("ENUMERATE", 17); 40 | token_case("QUOTE", 18); 41 | token_case("PLUS", 19); 42 | token_case("LEFT_ROUND_BRACKET", 21); 43 | token_case("RIGHT_ROUND_BRACKET", 22); 44 | token_case("COLON", 23); 45 | token_case("DOT", 24); 46 | token_case("ASTERISK", 25); 47 | token_case("MINUS", 26); 48 | token_case("DEF", 27); 49 | token_case("c_function", 28); 50 | token_case("ENDDEF", 29); 51 | token_case("ENDFN", 30); 52 | token_case("ELSE", 31); 53 | token_case("TRUE", 32); 54 | token_case("FALSE", 33); 55 | token_case("CONSTEXPR", 34); 56 | token_case("HASH", 35); 57 | token_case("INCLUDE", 36); 58 | token_case("AT", 37); 59 | token_case("APPLY_HOOK", 38); 60 | token_case("HOOK_BEGIN", 39); 61 | token_case("HOOK_END", 40); 62 | token_case("EXCLAMATION", 41); 63 | default: { 64 | msg = "UNDEFINED: "; 65 | break; 66 | } 67 | } 68 | 69 | // clang-format on 70 | printf("Token : %s", msg); 71 | 72 | #undef token_case 73 | } 74 | 75 | ///*/// 76 | import Vector 77 | import String 78 | import Dictionary 79 | import List 80 | 81 | struct Lexer{int dummy}; 82 | 83 | namespace Lexer 84 | 85 | function get_tokens() -> List: 86 | constexpr Token = {"LET" : 0, "EQUALS" : 1, "LEFT_SQUARE_BRACKET" : 2, "RIGHT_SQUARE_BRACKET" : 3, "SEMICOLON" : 4, "COMMA" : 5, "PERCENT" : 6, "LEFT_CURLY" : 7, "RIGHT_CURLY" : 8, "STRUCT" : 9, "MATCH" : 10, "FOR" : 11, "IF" : 12, "IN" : 13, "OPTION" : 14, "SMALLER_THAN" : 15, "GREATER_THAN" : 16, "ENUMERATE" : 17, "QUOTE" : 18, "PLUS" : 19, "LEFT_ROUND_BRACKET" : 21, "RIGHT_ROUND_BRACKET" : 22, "COLON" : 23, "DOT" : 24, "ASTERISK" : 25, "MINUS" : 26, "DEF" : 27, "CFUNCTION" : 28, "ENDDEF" : 29, "ENDFN" : 30, "ELSE" : 31, "TRUE" : 32, "FALSE" : 33, "CONSTEXPR" : 34, "HASH" : 35, "INCLUDE" : 36, "AT" : 37, "APPLY_HOOK" : 38, "HOOK_BEGIN" : 39, "HOOK_END" : 40, "EXCLAMATION" : 41} 87 | 88 | let CHARACTER_TOKENS = {}; 89 | CHARACTER_TOKENS["="] = Token["EQUALS"] 90 | CHARACTER_TOKENS["["] = Token["LEFT_SQUARE_BRACKET"] 91 | CHARACTER_TOKENS["]"] = Token["RIGHT_SQUARE_BRACKET"] 92 | CHARACTER_TOKENS[";"] = Token["SEMICOLON"] 93 | CHARACTER_TOKENS[","] = Token["COMMA"] 94 | CHARACTER_TOKENS["%"] = Token["PERCENT"] 95 | CHARACTER_TOKENS["{"] = Token["LEFT_CURLY"] 96 | CHARACTER_TOKENS["}"] = Token["RIGHT_CURLY"] 97 | CHARACTER_TOKENS["<"] = Token["SMALLER_THAN"] 98 | CHARACTER_TOKENS[">"] = Token["GREATER_THAN"] 99 | CHARACTER_TOKENS["\""] = Token["QUOTE"] 100 | CHARACTER_TOKENS["+"] = Token["PLUS"] 101 | CHARACTER_TOKENS["("] = Token["LEFT_ROUND_BRACKET"] 102 | CHARACTER_TOKENS[")"] = Token["RIGHT_ROUND_BRACKET"] 103 | CHARACTER_TOKENS[":"] = Token["COLON"] 104 | CHARACTER_TOKENS["."] = Token["DOT"] 105 | CHARACTER_TOKENS["*"] = Token["ASTERISK"] 106 | CHARACTER_TOKENS["-"] = Token["MINUS"] 107 | CHARACTER_TOKENS["#"] = Token["HASH"] 108 | CHARACTER_TOKENS["@"] = Token["AT"] 109 | CHARACTER_TOKENS["!"] = Token["EXCLAMATION"] 110 | 111 | let KEYWORD_TOKENS = {}; 112 | KEYWORD_TOKENS["let"] = Token["LET"] 113 | KEYWORD_TOKENS["struct"] = Token["STRUCT"] 114 | KEYWORD_TOKENS["match"] = Token["MATCH"] 115 | KEYWORD_TOKENS["for"] = Token["FOR"] 116 | KEYWORD_TOKENS["if"] = Token["IF"] 117 | KEYWORD_TOKENS["in"] = Token["IN"] 118 | KEYWORD_TOKENS["Option"] = Token["OPTION"] 119 | KEYWORD_TOKENS["enumerate"] = Token["ENUMERATE"] 120 | KEYWORD_TOKENS["def"] = Token["DEF"] 121 | KEYWORD_TOKENS["c_function"] = Token["CFUNCTION"] 122 | KEYWORD_TOKENS["enddef"] = Token["ENDDEF"] 123 | KEYWORD_TOKENS["endfunc"] = Token["ENDFN"] 124 | KEYWORD_TOKENS["else"] = Token["ELSE"] 125 | KEYWORD_TOKENS["True"] = Token["TRUE"] 126 | KEYWORD_TOKENS["False"] = Token["FALSE"] 127 | KEYWORD_TOKENS["constexpr"] = Token["CONSTEXPR"] 128 | KEYWORD_TOKENS["include"] = Token["INCLUDE"] 129 | KEYWORD_TOKENS["apply_hook"] = Token["APPLY_HOOK"] 130 | KEYWORD_TOKENS["hook_begin"] = Token["HOOK_BEGIN"] 131 | KEYWORD_TOKENS["hook_end"] = Token["HOOK_END"] 132 | 133 | let line_org = " let arr = [ 1, 2, 3, 4 , 5 ]; } let" 134 | let line = line_org.strip() 135 | let length = line.len() 136 | 137 | let token = "" 138 | 139 | let tokens = []; 140 | 141 | let inside_string = False 142 | let escape_back_slash = False 143 | 144 | def add_token_raw(p_token): 145 | tokens.append_str(p_token) 146 | enddef 147 | 148 | def add_token(p_token): 149 | if p_token in KEYWORD_TOKENS{ 150 | tokens.append(KEYWORD_TOKENS[p_token]) 151 | }else if p_token in CHARACTER_TOKENS{ 152 | tokens.append(CHARACTER_TOKENS[p_token]) 153 | }else{ 154 | add_token_raw p_token 155 | } 156 | enddef 157 | 158 | line.printLn() 159 | 160 | for Char in line{ 161 | #print("{Char}") 162 | 163 | if escape_back_slash{ 164 | if Char == "\""{ 165 | token += Char 166 | escape_back_slash = False 167 | }else if Char == "\\"{ 168 | token += "\\\\" 169 | escape_back_slash = False 170 | }else{ 171 | token += Char 172 | escape_back_slash = False 173 | } 174 | }else if Char == "\""{ 175 | if inside_string{ 176 | # End of string. 177 | inside_string = False 178 | 179 | // Single character tokens like = are tokenized by add_token(), 180 | // so we use the following method. 181 | // "=" the inner equals to shouldn't be tokenized. 182 | add_token_raw token 183 | 184 | token = "" 185 | }else{ 186 | # Start of string. 187 | inside_string = True 188 | } 189 | tokens.append(Token["QUOTE"]) 190 | } else if inside_string{ 191 | if Char == "\\"{ 192 | escape_back_slash = True 193 | continue; 194 | } 195 | 196 | token += Char 197 | } else if Char == " "{ 198 | if token == ""{ 199 | continue; 200 | } 201 | 202 | add_token token 203 | token = "" 204 | }else{ 205 | if Char in CHARACTER_TOKENS{ 206 | if token != ""{ 207 | add_token token 208 | } 209 | tokens.append(CHARACTER_TOKENS[Char]) 210 | token = "" 211 | continue; 212 | } 213 | 214 | if token in CHARACTER_TOKENS{ 215 | tokens.append(CHARACTER_TOKENS[token]) 216 | token = "" 217 | continue; 218 | } 219 | 220 | token += Char 221 | } 222 | 223 | 224 | } 225 | 226 | # Process the last token. 227 | if token != ""{ 228 | add_token token 229 | } 230 | 231 | return tokens 232 | endfunction 233 | 234 | endnamespace 235 | ///*/// 236 | 237 | 238 | int main() { 239 | 240 | // clang-format off 241 | 242 | ///*/// main() 243 | 244 | let lexer = Lexer{}; 245 | let tokens = lexer.get_tokens(); 246 | 247 | @apply_hook("custom_integer_printer", CustomPrint) 248 | tokens.print() 249 | 250 | // DESTRUCTOR_CODE // 251 | ///*/// 252 | // clang-format on 253 | 254 | return 0; 255 | } -------------------------------------------------------------------------------- /Lib/List.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | #include 3 | #include 4 | 5 | typedef struct Variant{ 6 | enum { 7 | INT, 8 | STRING 9 | } data_type; 10 | 11 | union { 12 | int int_data; 13 | char *str_data; 14 | } data; 15 | } Variant; 16 | 17 | typedef struct Variant Variant; 18 | typedef struct ListObject *ListObjectptr; 19 | 20 | ///*/// 21 | struct ListObject{Variant data, Self* next}; 22 | 23 | namespace ListObject 24 | 25 | c_function __init__<>(p_value : int) 26 | this->data.data.int_data = p_value; 27 | this->data.data_type = INT; 28 | this->next = NULL; 29 | endc_function 30 | 31 | c_function __init__<>(p_value : str) 32 | this->data.data.str_data = strdup(p_value); 33 | this->data.data_type = STRING; 34 | this->next = NULL; 35 | endc_function 36 | 37 | c_function is_int() -> bool: 38 | return this->data.data_type == INT; 39 | endc_function 40 | 41 | c_function get_int() -> int: 42 | return this->data.data.int_data; 43 | endc_function 44 | 45 | c_function is_str() -> bool: 46 | return this->data.data_type == STRING; 47 | endc_function 48 | 49 | c_function get_str() -> str: 50 | return this->data.data.str_data; 51 | endc_function 52 | 53 | c_function _clear_str() 54 | free(this->data.data.str_data); 55 | endc_function 56 | 57 | function __del__() 58 | if this.is_str(){ 59 | this._clear_str() 60 | } 61 | endfunction 62 | 63 | c_function _duplicate() -> ListObject: 64 | // Perform a deep copy. 65 | struct ListObject copy = *this; 66 | if (this->data.data_type == STRING) { 67 | copy.data.data.str_data = strdup(this->data.data.str_data); 68 | } 69 | return copy; 70 | endc_function 71 | 72 | function __eq__<>(p_value : int) -> bool: 73 | if this.is_int(){ 74 | return this.get_int() == p_value 75 | }else{ 76 | return false 77 | } 78 | endfunction 79 | 80 | function __eq__<>(p_value : str) -> bool: 81 | if this.is_str(){ 82 | return this.get_str() == p_value 83 | }else{ 84 | return false 85 | } 86 | endfunction 87 | endnamespace 88 | 89 | struct List{ListObject *head, ListObject *tail, int size}; 90 | 91 | namespace List 92 | 93 | c_function len() -> int: 94 | return this->size; 95 | endc_function 96 | 97 | c_function __init__() 98 | this->head = NULL; 99 | this->tail = NULL; 100 | this->size = 0; 101 | endc_function 102 | 103 | c_function __del__() 104 | struct ListObject *current = this->head; 105 | while (current != NULL) { 106 | struct ListObject *temp = current; 107 | current = current->next; 108 | 109 | ListObject__del__(temp); 110 | free(temp); 111 | } 112 | this->head = NULL; 113 | this->tail = NULL; 114 | this->size = 0; 115 | endc_function 116 | 117 | c_function __getitem__(index : int) -> ListObject: 118 | if (index < 0){ 119 | index += this->size; 120 | } 121 | 122 | if (index < 0 || index >= this->size) { 123 | printf("Index %d out of bounds(max : %d).\n", index, this->size - 1); 124 | exit(EXIT_FAILURE); 125 | } 126 | 127 | struct ListObject *current = this->head; 128 | for (int i = 0; i < index; i++) { 129 | current = current->next; 130 | } 131 | 132 | // Duplicate contents of node and return it. 133 | // If we return a reference, then the calling function will call destructor, 134 | // which will free the str_data causing free() errors later. 135 | return ListObject_duplicate(current); 136 | endc_function 137 | 138 | c_function pop(index : int) -> ListObject: 139 | if (this->size == 0) { 140 | printf("List is empty. Can't pop element.\n"); 141 | exit(EXIT_FAILURE); 142 | } 143 | 144 | if (index < 0 || index >= this->size) { 145 | printf("Index %d out of bounds(max : %d).\n", index, this->size - 1); 146 | exit(EXIT_FAILURE); 147 | } 148 | 149 | struct ListObject *current = this->head; 150 | struct ListObject *previous = NULL; 151 | 152 | for (int i = 0; i < index; i++) { 153 | previous = current; 154 | current = current->next; 155 | } 156 | 157 | if (previous == NULL) { 158 | // Popping the head. 159 | this->head = current->next; 160 | if (this->head == NULL) { 161 | // The list is now empty. 162 | this->tail = NULL; 163 | } 164 | } else { 165 | previous->next = current->next; 166 | if (current->next == NULL) { 167 | // Popping the tail. 168 | this->tail = previous; 169 | } 170 | } 171 | 172 | this->size--; 173 | 174 | struct ListObject popped_node = *current; 175 | // Don't free current->data.str_data even though current data_type is String. 176 | // After copying the *pointer above, popped_node now owns current->data.str_data. 177 | // This avoids duplicating current->data.str_data into popped_node. 178 | free(current); 179 | return popped_node; 180 | endc_function 181 | 182 | c_function __contains__<>(p_value : int) -> bool: 183 | struct ListObject *current = this->head; 184 | while (current != NULL) { 185 | if (current->data.data_type == INT) { 186 | int data = current->data.data.int_data; 187 | 188 | if (data == p_value){ 189 | return true; 190 | } 191 | 192 | } 193 | current = current->next; 194 | } 195 | return false; 196 | endc_function 197 | 198 | c_function __contains__<>(p_value : str) -> bool: 199 | struct ListObject *current = this->head; 200 | while (current != NULL) { 201 | if (current->data.data_type == STRING) { 202 | char* data = current->data.data.str_data; 203 | 204 | if (strcmp(data,p_value) == 0){ 205 | return true; 206 | } 207 | 208 | } 209 | current = current->next; 210 | } 211 | return false; 212 | endc_function 213 | 214 | c_function print() 215 | struct ListObject *current = this->head; 216 | printf("["); 217 | while (current != NULL) { 218 | if (current->data.data_type == STRING) { 219 | printf("\"%s\"", current->data.data.str_data); 220 | } else { 221 | int data = current->data.data.int_data; 222 | 223 | @hook_begin("custom_integer_printer" "int" data) 224 | printf("%d", data); 225 | @hook_end 226 | 227 | } 228 | 229 | current = current->next; 230 | if(current != NULL){ 231 | printf(", "); 232 | } 233 | } 234 | printf("]\n"); 235 | endc_function 236 | 237 | c_function _insert_end(new_node : ListObjectptr) { 238 | this->size++; 239 | if (this->head == NULL) { 240 | this->head = new_node; 241 | this->tail = new_node; 242 | return; 243 | } 244 | 245 | this->tail->next = new_node; 246 | this->tail = new_node; 247 | endc_function 248 | 249 | c_function create_int_node(p_value : int) -> ListObjectptr: 250 | struct ListObject *new_node = (struct ListObject *)malloc(sizeof(struct ListObject)); 251 | if(new_node == NULL){ 252 | printf("List : Failed to allocate a new node of type int for value %d.", p_value); 253 | exit(EXIT_FAILURE); 254 | } 255 | ListObject__init__OVDint(new_node, p_value); 256 | return new_node; 257 | endc_function 258 | 259 | c_function create_string_node(p_value : str) -> ListObjectptr: 260 | struct ListObject *new_node = (struct ListObject *)malloc(sizeof(struct ListObject)); 261 | if(new_node == NULL){ 262 | printf("List : Failed to allocate a new node of type char*."); 263 | exit(EXIT_FAILURE); 264 | } 265 | ListObject__init__OVDstr(new_node, p_value); 266 | return new_node; 267 | endc_function 268 | 269 | function append_int(p_value : int) 270 | let int_node = this.create_int_node(p_value) 271 | this._insert_end(int_node) 272 | endfunction 273 | 274 | function append_str(p_value : str) 275 | let str_node = this.create_string_node(p_value) 276 | this._insert_end(str_node) 277 | endfunction 278 | 279 | function append<>(p_value : int) 280 | this.append_int(p_value) 281 | endfunction 282 | 283 | function append<>(p_value : str) 284 | this.append_str(p_value) 285 | endfunction 286 | 287 | function append<>(p_value : ListObject) 288 | if p_value.is_int(){ 289 | this.append_int(p_value.get_int()) 290 | }else if p_value.is_str(){ 291 | this.append_str(p_value.get_str()) 292 | } 293 | endfunction 294 | 295 | function __reassign__(p_list: List) 296 | for item in p_list{ 297 | this.append(item) 298 | } 299 | endfunction 300 | 301 | endnamespace 302 | 303 | ///*/// 304 | 305 | 306 | -------------------------------------------------------------------------------- /examples/Macro_With_Variadic_Arguments_generated.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | /////////////////////////////////////////// 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // IMPORTS // 11 | 12 | struct Vector_int { 13 | int *arr; 14 | int size; 15 | int capacity; 16 | }; 17 | 18 | size_t Vector_intlen(struct Vector_int *this); 19 | void Vector_int__init__(struct Vector_int *this, int capacity); 20 | void Vector_int_call_destructor_for_element(struct Vector_int *this, int index); 21 | void Vector_int_call_destructor_for_all_elements(struct Vector_int *this); 22 | void Vector_int_reset(struct Vector_int *this); 23 | void Vector_int__del__(struct Vector_int *this); 24 | int Vector_int__getitem__(struct Vector_int *this, int index); 25 | void Vector_int_set_ith_item(struct Vector_int *this, int index, int value); 26 | void Vector_intpush_unchecked(struct Vector_int *this, int value); 27 | void Vector_intvalidate_index(struct Vector_int *this, int index); 28 | void Vector_int_set(struct Vector_int *this, int index, int value); 29 | void Vector_int__setitem__(struct Vector_int *this, int index, int value); 30 | void Vector_intallocate_more(struct Vector_int *this, int n); 31 | void Vector_int_grow_if_required(struct Vector_int *this); 32 | void Vector_int_push(struct Vector_int *this, int value); 33 | void Vector_intpush(struct Vector_int *this, int value); 34 | int Vector_intpop(struct Vector_int *this); 35 | void Vector_int_shift_left_from(struct Vector_int *this, int index); 36 | void Vector_intremove_at(struct Vector_int *this, int index); 37 | void Vector_int_clear(struct Vector_int *this); 38 | void Vector_intclear(struct Vector_int *this); 39 | bool Vector_int__contains__(struct Vector_int *this, int value); 40 | void Vector_intprint(struct Vector_int *this); 41 | 42 | size_t Vector_intlen(struct Vector_int *this) { return this->size; } 43 | 44 | void Vector_int__init__(struct Vector_int *this, int capacity) { 45 | // if we want to use instanced template type in fn body, we use following 46 | // syntax. 47 | // @ TEMPLATED_DATA_TYPE @ 48 | this->arr = (int *)malloc(capacity * sizeof(int)); 49 | 50 | if (this->arr == NULL) { 51 | fprintf(stderr, "Memory allocation failed.\n"); 52 | exit(EXIT_FAILURE); 53 | } 54 | this->size = 0; 55 | this->capacity = capacity; 56 | } 57 | 58 | void Vector_int_call_destructor_for_element(struct Vector_int *this, 59 | int index) { 60 | // If element at 'index' has a destructor, then emit a destructor call. 61 | // Otherwise emit nothing. 62 | // Evaluated at compile time. 63 | } 64 | 65 | void Vector_int_call_destructor_for_all_elements(struct Vector_int *this) { 66 | for (size_t i = 0; i < Vector_intlen(this); i++) { 67 | Vector_int_call_destructor_for_element(this, i); 68 | } 69 | } 70 | 71 | void Vector_int_reset(struct Vector_int *this) { 72 | free(this->arr); 73 | this->arr = NULL; 74 | this->size = 0; 75 | this->capacity = 0; 76 | } 77 | 78 | void Vector_int__del__(struct Vector_int *this) { 79 | Vector_int_call_destructor_for_all_elements(this); 80 | Vector_int_reset(this); 81 | } 82 | 83 | int Vector_int__getitem__(struct Vector_int *this, int index) { 84 | if (index < 0) { 85 | index += this->size; 86 | } 87 | return *(this->arr + index); 88 | } 89 | 90 | void Vector_int_set_ith_item(struct Vector_int *this, int index, int value) { 91 | // NOTE: We assume that the index is valid. 92 | this->arr[index] = value; 93 | } 94 | 95 | void Vector_intpush_unchecked(struct Vector_int *this, int value) { 96 | this->arr[this->size++] = value; 97 | } 98 | 99 | void Vector_intvalidate_index(struct Vector_int *this, int index) { 100 | if (index < 0 || index >= this->size) { 101 | fprintf(stderr, "Index out of bounds: index = %d, size = %d.\n", index, 102 | this->size); 103 | exit(EXIT_FAILURE); 104 | } 105 | } 106 | 107 | void Vector_int_set(struct Vector_int *this, int index, int value) { 108 | 109 | if (index < 0) { 110 | index = index + this->size; 111 | } 112 | Vector_intvalidate_index(this, index); 113 | Vector_int_call_destructor_for_element(this, index); 114 | Vector_int_set_ith_item(this, index, value); 115 | } 116 | 117 | void Vector_int__setitem__(struct Vector_int *this, int index, int value) { 118 | Vector_int_set(this, index, value); 119 | } 120 | 121 | void Vector_intallocate_more(struct Vector_int *this, int n) { 122 | if (n <= 0) { 123 | // Prevent unnecessary reallocation or negative increments. 124 | return; 125 | } 126 | 127 | size_t new_capacity = this->capacity + n; 128 | int *new_arr = (int *)realloc(this->arr, new_capacity * sizeof(int)); 129 | 130 | if (!new_arr) { 131 | fprintf(stderr, "Vector<>::allocate_more(): Memory reallocation failed.\n"); 132 | exit(EXIT_FAILURE); 133 | } 134 | 135 | this->arr = new_arr; 136 | this->capacity = new_capacity; 137 | } 138 | 139 | void Vector_int_grow_if_required(struct Vector_int *this) { 140 | 141 | if (this->size >= this->capacity) { 142 | 143 | if (this->capacity > 0) { 144 | Vector_intallocate_more(this, this->capacity); 145 | } else { 146 | // Avoid 0 capacity. 147 | Vector_intallocate_more(this, 1); 148 | } 149 | } 150 | } 151 | 152 | void Vector_int_push(struct Vector_int *this, int value) { 153 | Vector_int_grow_if_required(this); 154 | Vector_intpush_unchecked(this, value); 155 | } 156 | 157 | void Vector_intpush(struct Vector_int *this, int value) { 158 | Vector_int_push(this, value); 159 | } 160 | 161 | int Vector_intpop(struct Vector_int *this) { 162 | if (this->size == 0) { 163 | fprintf(stderr, "Pop from empty Vector.\n"); 164 | exit(EXIT_FAILURE); 165 | } 166 | return this->arr[--this->size]; 167 | } 168 | 169 | void Vector_int_shift_left_from(struct Vector_int *this, int index) { 170 | // NOTE: The index is assumed to be valid(i.e not negative and within bounds). 171 | for (int i = index; i < this->size - 1; i++) { 172 | this->arr[i] = this->arr[i + 1]; 173 | } 174 | } 175 | 176 | void Vector_intremove_at(struct Vector_int *this, int index) { 177 | 178 | if (index < 0) { 179 | index = index + this->size; 180 | } 181 | Vector_intvalidate_index(this, index); 182 | Vector_int_call_destructor_for_element(this, index); 183 | Vector_int_shift_left_from(this, index); 184 | this->size -= 1; 185 | } 186 | 187 | void Vector_int_clear(struct Vector_int *this) { 188 | free(this->arr); 189 | 190 | this->capacity = 1; 191 | this->arr = (int *)malloc(this->capacity * sizeof(int)); 192 | 193 | if (this->arr == NULL) { 194 | fprintf(stderr, "Vector<>::_clear(): Memory allocation failed.\n"); 195 | exit(EXIT_FAILURE); 196 | } 197 | 198 | this->size = 0; 199 | } 200 | 201 | void Vector_intclear(struct Vector_int *this) { 202 | Vector_int_call_destructor_for_all_elements(this); 203 | Vector_int_clear(this); 204 | } 205 | 206 | bool Vector_int__contains__(struct Vector_int *this, int value) { 207 | // This function is an overloaded function. 208 | // Here <> in function defination means the base overload. 209 | for (size_t i = 0; i < this->size; ++i) { 210 | if (this->arr[i] == value) { 211 | return true; 212 | } 213 | } 214 | return false; 215 | } 216 | 217 | void Vector_intprint(struct Vector_int *this) { 218 | printf("Vector (size = %d, capacity = %d) : [", this->size, 219 | this->capacity); 220 | for (size_t i = 0; i < this->size; ++i) { 221 | printf("%d", this->arr[i]); 222 | if (i < this->size - 1) { 223 | printf(", "); 224 | } 225 | } 226 | printf("]\n"); 227 | } 228 | 229 | int main() { 230 | 231 | struct Vector_int values; 232 | Vector_int__init__(&values, 8); 233 | Vector_intpush(&values, 1); 234 | Vector_intpush(&values, 2); 235 | Vector_intpush(&values, 3); 236 | Vector_intpush(&values, 4); 237 | Vector_intpush(&values, 5); 238 | Vector_intpush(&values, 6); 239 | Vector_intpush(&values, 7); 240 | Vector_intpush(&values, 8); 241 | 242 | Vector_intallocate_more(&values, 8); 243 | Vector_intpush_unchecked(&values, 10); 244 | Vector_intpush_unchecked(&values, 20); 245 | Vector_intpush_unchecked(&values, 30); 246 | Vector_intpush_unchecked(&values, 40); 247 | Vector_intpush_unchecked(&values, 50); 248 | Vector_intpush_unchecked(&values, 60); 249 | Vector_intpush_unchecked(&values, 70); 250 | Vector_intpush_unchecked(&values, 80); 251 | 252 | Vector_int__del__(&values); 253 | 254 | return 0; 255 | } -------------------------------------------------------------------------------- /Lib/String.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct String{char* arr, int length, int capacity, bool is_constexpr}; 10 | 11 | namespace String 12 | function c_str() -> str: 13 | return this.arr 14 | endfunction 15 | 16 | function len() -> size_t: 17 | return this.length 18 | endfunction 19 | 20 | c_function __getitem__(index: int) -> char: 21 | return *(this->arr + index); 22 | endc_function 23 | 24 | c_function length_of_charptr(p_string:str) -> size_t: 25 | // This should be some kind of static method. 26 | return strlen(p_string); 27 | endc_function 28 | 29 | c_function __init__from_charptr(text: str, p_text_length: int) 30 | // p_text_length : Length of the string without the null terminator. 31 | this->arr = (char *)malloc((p_text_length + 1) * sizeof(char)); 32 | 33 | if (this->arr == NULL) { 34 | fprintf(stderr, "Memory allocation failed.\n"); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | strncpy(this->arr, text, p_text_length); 39 | this->arr[p_text_length] = '\0'; 40 | 41 | this->length = p_text_length; 42 | this->capacity = p_text_length + 1; 43 | this->is_constexpr = false; 44 | endc_function 45 | 46 | c_function init__STATIC__(text: str, p_text_length: int) 47 | // WARNING: Only the compiler should write a call to this function. 48 | // The compiler uses this initialization function to create a temporary String object 49 | // when a string literal is passed to a function that expects a String object. 50 | this->arr = text; 51 | this->length = p_text_length; 52 | this->capacity = p_text_length + 1; 53 | this->is_constexpr = true; 54 | endc_function 55 | 56 | function __init__<>(text: str) 57 | let p_text_length = this.length_of_charptr(text) 58 | this.__init__from_charptr(text, p_text_length) 59 | endfunction 60 | 61 | function __init__<>(text: str, p_text_length: int) 62 | this.__init__from_charptr(text, p_text_length) 63 | endfunction 64 | 65 | function __init__<>(text: String) 66 | let p_text_length = text.len() 67 | this.__init__from_charptr(text, p_text_length); 68 | endfunction 69 | 70 | c_function clear() 71 | this->arr = (char *)realloc(this->arr, sizeof(char)); 72 | this->arr[0] = '\0'; 73 | this->length = 0; 74 | this->capacity = 1; 75 | endc_function 76 | 77 | c_function _allocate_more(n: int) 78 | if (n <= 0) { 79 | // Prevent unnecessary reallocation or negative increments. 80 | return; 81 | } 82 | 83 | size_t new_capacity = this->capacity + n + 1; 84 | 85 | char *new_arr = (char *)realloc(this->arr, new_capacity * sizeof(char)); 86 | if (!new_arr) { 87 | fprintf(stderr, "Memory reallocation failed.\n"); 88 | exit(EXIT_FAILURE); 89 | } else{ 90 | this->arr = new_arr; 91 | this->capacity = new_capacity; 92 | } 93 | endc_function 94 | 95 | c_function print() 96 | printf("%s", this->arr); 97 | endc_function 98 | 99 | c_function printLn() 100 | printf("%s\n", this->arr); 101 | endc_function 102 | 103 | c_function __del__() 104 | if (!this->is_constexpr){ 105 | free(this->arr); 106 | } 107 | endc_function 108 | 109 | c_function startswith(prefix: str) -> bool: 110 | return strncmp(this->arr, prefix, strlen(prefix)) == 0; 111 | endc_function 112 | 113 | c_function substr(start : int, length : int) -> String: 114 | struct String text; 115 | String__init__from_charptr(&text, &this->arr[start], length); 116 | return text; 117 | endc_function 118 | 119 | c_function strip() -> String: 120 | char *begin = this->arr; 121 | char *end = begin + Stringlen(this) - 1; 122 | 123 | // Remove leading whitespaces. 124 | while (isspace(*begin)) { 125 | begin++; 126 | } 127 | 128 | // Remove trailing whitespaces. 129 | while (end > begin && isspace(*end)) { 130 | end--; 131 | } 132 | 133 | // Length of the substring between 'begin' and 'end' inclusive. 134 | int new_length = end - begin + 1; 135 | 136 | struct String text; 137 | String__init__from_charptr(&text, begin, new_length); 138 | return text; 139 | endc_function 140 | 141 | function split(delimeter: char) -> Vector: 142 | // NOTE : Because of this function, before import String, we require import Vector. 143 | let split_result = Vector{2}; 144 | 145 | let index : int = 0 146 | let segment_start : int = 0 147 | 148 | for character in this{ 149 | if character == delimeter { 150 | if segment_start < index { 151 | let segment = this.substr(segment_start, index - segment_start) 152 | split_result.push(segment) 153 | } 154 | segment_start = index + 1 155 | } 156 | index = index + 1 157 | } 158 | 159 | if segment_start < this.len() { 160 | let remaining_segment = this.substr(segment_start, this.len() - segment_start) 161 | split_result.push(remaining_segment) 162 | } 163 | 164 | return split_result 165 | endfunction 166 | 167 | c_function __contains__(substring: str) -> bool: 168 | return strstr(this->arr, substring) != NULL; 169 | endc_function 170 | 171 | c_function __eq__(pstring: str) -> bool: 172 | return strcmp(this->arr, pstring) == 0; 173 | endc_function 174 | 175 | c_function __add__(pstring: str) 176 | size_t new_length = this->length + strlen(pstring) + 1; 177 | 178 | if(new_length > this->capacity){ 179 | size_t new_capacity; 180 | if(this->capacity == 0){ 181 | new_capacity = new_length * 2; 182 | }else{ 183 | new_capacity = this->capacity; 184 | while(new_capacity <= new_length){ 185 | new_capacity *= 2; 186 | } 187 | } 188 | this->arr = (char *)realloc(this->arr, new_capacity * sizeof(char)); 189 | this->capacity = new_capacity; 190 | } 191 | 192 | if (this->arr == NULL) { 193 | fprintf(stderr, "Memory Re-Allocation Error.\n"); 194 | exit(EXIT_FAILURE); 195 | } 196 | 197 | strcat(this->arr, pstring); 198 | this->length = new_length; 199 | endc_function 200 | 201 | c_function reassign_internal(pstring: str, p_text_length: int) 202 | if (this->arr != NULL) { 203 | free(this->arr); 204 | } 205 | 206 | String__init__from_charptr(this, pstring, p_text_length); 207 | endc_function 208 | 209 | function __reassign__<>(pstring: String) 210 | let src = pstring.c_str() 211 | let p_text_length = pstring.len() 212 | this.reassign_internal(src, p_text_length) 213 | endfunction 214 | 215 | function __reassign__<>(pstring: str) 216 | let p_text_length = this.length_of_charptr(pstring) 217 | this.reassign_internal(pstring, p_text_length) 218 | endfunction 219 | 220 | c_function set_to_file_contents(pfilename: str) 221 | if(this->is_constexpr){ 222 | // Probably not necessary, as constexpr strings are compiler generated, but just in case. 223 | fprintf(stderr, "Error: Attempt to modify a constexpr String object.\n"); 224 | exit(EXIT_FAILURE); 225 | } 226 | 227 | // Use fopen in binary read mode ("rb") to prevent newline translation. 228 | FILE *ptr = fopen(pfilename, "rb"); 229 | if (ptr == NULL) { 230 | fprintf(stderr, "File \"%s\" couldn't be opened.\n", pfilename); 231 | Stringclear(this); 232 | return; 233 | } 234 | 235 | fseek(ptr, 0, SEEK_END); 236 | long fileSize = ftell(ptr); 237 | if (fileSize < 0) { 238 | fprintf(stderr, "Failed to get file size"); 239 | fclose(ptr); 240 | Stringclear(this); 241 | return; 242 | } 243 | 244 | fseek(ptr, 0, SEEK_SET); 245 | 246 | int buffer_capacity = fileSize + 1; 247 | char *buffer = (char *)malloc(buffer_capacity); 248 | if (buffer == NULL) { 249 | fprintf(stderr, "Memory allocation failed for file content.\n"); 250 | fclose(ptr); 251 | Stringclear(this); 252 | return; 253 | } 254 | 255 | size_t bytesRead = fread(buffer, 1, fileSize, ptr); 256 | fclose(ptr); 257 | 258 | if (bytesRead != (size_t)fileSize) { 259 | fprintf(stderr, "Error reading file \"%s\". Expected %ld bytes, got %zu.\n", 260 | pfilename, fileSize, bytesRead); 261 | free(buffer); 262 | Stringclear(this); 263 | return; 264 | } 265 | 266 | buffer[fileSize] = '\0'; 267 | 268 | if (this->arr != NULL){ 269 | free(this->arr); 270 | } 271 | 272 | // Take ownership of the buffer. 273 | // The buffer should not be freed after this point. 274 | this->arr = buffer; 275 | this->length = fileSize; 276 | this->capacity = buffer_capacity; 277 | endc_function 278 | 279 | function readlinesFrom(pfilename: str) -> Vector: 280 | this.set_to_file_contents(pfilename) 281 | let result = this.split("\n") 282 | return result 283 | endfunction 284 | 285 | endnamespace 286 | 287 | ///*/// 288 | 289 | -------------------------------------------------------------------------------- /Lib/Vector.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | ///*/// 3 | 4 | #include 5 | 6 | /////////////////////////////////////////// 7 | struct Vector{T* arr,int size,int capacity}; 8 | 9 | namespace Vector 10 | function len() -> size_t: 11 | return this.size 12 | endfunction 13 | 14 | c_function __init__(capacity : int) 15 | // if we want to use instanced template type in fn body, we use following syntax. 16 | // @ TEMPLATED_DATA_TYPE @ 17 | this->arr = (@TEMPLATED_DATA_TYPE@ *)malloc(capacity * sizeof(@TEMPLATED_DATA_TYPE@)); 18 | 19 | if (this->arr == NULL) { 20 | fprintf(stderr, "Memory allocation failed.\n"); 21 | exit(EXIT_FAILURE); 22 | } 23 | this->size = 0; 24 | this->capacity = capacity; 25 | endc_function 26 | 27 | function _call_destructor_for_element(index : int) 28 | // If element at 'index' has a destructor, then emit a destructor call. 29 | // Otherwise emit nothing. 30 | // Evaluated at compile time. 31 | ~arr[index] 32 | endfunction 33 | 34 | function _call_destructor_for_all_elements() 35 | for i in range(0..this.len()){ 36 | this._call_destructor_for_element(i) 37 | } 38 | endfunction 39 | 40 | c_function _reset() 41 | free(this->arr); 42 | this->arr = NULL; 43 | this->size = 0; 44 | this->capacity = 0; 45 | endc_function 46 | 47 | function __del__() 48 | this._call_destructor_for_all_elements() 49 | this._reset() 50 | endfunction 51 | 52 | c_function<> __getitem__(index : int) -> T: 53 | if (index < 0){index += this->size;} 54 | return *(this->arr + index); 55 | endc_function 56 | 57 | c_function __getitem__(index : int) -> &T: 58 | if (index < 0){index += this->size;} 59 | // Vector Specialization: 60 | // Returns &T ie &String, which means the return type is reference type. 61 | // So, the returned String isn't freed by the destructor. 62 | // for x in Vector{} 63 | // x calls __getitem__() and is a String. Typically x should be freed at the end of the loop. 64 | // Since __getitem__() is a reference return type, it isn't freed. 65 | return *(this->arr + index); 66 | endc_function 67 | 68 | c_function _set_ith_item(index : int, value : T) 69 | // NOTE: We assume that the index is valid. 70 | this->arr[index] = value; 71 | endc_function 72 | 73 | c_function push_unchecked(value : T) 74 | this->arr[this->size++] = value; 75 | endc_function 76 | 77 | c_function validate_index(index : int) 78 | if (index < 0 || index >= this->size) { 79 | fprintf(stderr, "Index out of bounds: index = %d, size = %d.\n", index, this->size); 80 | exit(EXIT_FAILURE); 81 | } 82 | endc_function 83 | 84 | function _copy_string(s : String) -> String: 85 | let string_copy = s 86 | return string_copy 87 | endfunction 88 | 89 | function _set(index : int, value : T) 90 | if index < 0 { 91 | index = index + this.size 92 | } 93 | this.validate_index(index) 94 | this._call_destructor_for_element(index) 95 | this._set_ith_item(index, value) 96 | endfunction 97 | 98 | function<> __setitem__(index : int, value : T) 99 | this._set(index, value) 100 | endfunction 101 | 102 | function __setitem__(index : int, value : T) 103 | // Vector Specialization: 104 | // Duplicate a string object, to prevent dangling pointers, 105 | // as when a string moves out of a scope, it is freed. 106 | this._set(index, this._copy_string(value)) 107 | endfunction 108 | 109 | c_function allocate_more(n : int) 110 | if (n <= 0) { 111 | // Prevent unnecessary reallocation or negative increments. 112 | return; 113 | } 114 | 115 | size_t new_capacity = this->capacity + n; 116 | @TEMPLATED_DATA_TYPE@ *new_arr = (@TEMPLATED_DATA_TYPE@ *)realloc(this->arr, new_capacity * sizeof(@TEMPLATED_DATA_TYPE@)); 117 | 118 | if (!new_arr) { 119 | fprintf(stderr, "Vector<>::allocate_more(): Memory reallocation failed.\n"); 120 | exit(EXIT_FAILURE); 121 | } 122 | 123 | this->arr = new_arr; 124 | this->capacity = new_capacity; 125 | endc_function 126 | 127 | function _grow_if_required() 128 | if this.size >= this.capacity { 129 | if this.capacity > 0 { 130 | this.allocate_more(this.capacity) 131 | } else { 132 | // Avoid 0 capacity. 133 | this.allocate_more(1) 134 | } 135 | } 136 | endfunction 137 | 138 | function _push(value : T) 139 | this._grow_if_required() 140 | this.push_unchecked(value) 141 | endfunction 142 | 143 | function<> push(value : T) 144 | this._push(value) 145 | endfunction 146 | 147 | function push(value : T) 148 | // Vector Specialization: 149 | // Duplicate a string object, to prevent dangling pointers, 150 | // as when a string moves out of a scope, it is freed. 151 | this._push(this._copy_string(value)) 152 | endfunction 153 | 154 | c_function pop() -> T: 155 | if (this->size == 0) { 156 | fprintf(stderr, "Pop from empty Vector.\n"); 157 | exit(EXIT_FAILURE); 158 | } 159 | return this->arr[--this->size]; 160 | endc_function 161 | 162 | c_function _shift_left_from(index : int) 163 | // NOTE: The index is assumed to be valid(i.e not negative and within bounds). 164 | for (int i = index; i < this->size - 1; i++) { 165 | this->arr[i] = this->arr[i + 1]; 166 | } 167 | endc_function 168 | 169 | function remove_at(index : int) 170 | if index < 0 { 171 | index = index + this.size 172 | } 173 | this.validate_index(index) 174 | this._call_destructor_for_element(index) 175 | this._shift_left_from(index) 176 | this.size -= 1 177 | endfunction 178 | 179 | c_function _clear() 180 | free(this->arr); 181 | 182 | this->capacity = 1; 183 | this->arr = (@TEMPLATED_DATA_TYPE@ *)malloc(this->capacity * sizeof(@TEMPLATED_DATA_TYPE@ )); 184 | 185 | if (this->arr == NULL) { 186 | fprintf(stderr, "Vector<>::_clear(): Memory allocation failed.\n"); 187 | exit(EXIT_FAILURE); 188 | } 189 | 190 | this->size = 0; 191 | endc_function 192 | 193 | function clear() 194 | this._call_destructor_for_all_elements() 195 | this._clear() 196 | endfunction 197 | 198 | c_function<> __contains__(value : T) -> bool: 199 | // This function is an overloaded function. 200 | // Here <> in function defination means the base overload. 201 | for (size_t i = 0; i < this->size; ++i) { 202 | if(this->arr[i] == value){ 203 | return true; 204 | } 205 | } 206 | return false; 207 | endc_function 208 | 209 | function __contains__(value : T) -> bool: 210 | for string in this{ 211 | if string.len() == value.len(){ 212 | if string == value{ 213 | return true 214 | } 215 | } 216 | } 217 | return false 218 | endfunction 219 | 220 | function __contains__(value : T) -> bool: 221 | for vec in this{ 222 | if vec == value{ 223 | return true 224 | } 225 | } 226 | return false 227 | endfunction 228 | 229 | def pushn(X...) for Vector: 230 | self.allocate_more(X.size) 231 | forall x: self.push_unchecked(x) 232 | enddef 233 | 234 | c_function<> print() 235 | // Default overload. 236 | printf("Dynamic Array (size = %d, capacity = %d) : [ ]", this->size, this->capacity); 237 | // @TEMPLATED_DATA_TYPE@ will be replaced by the actual templated data type. 238 | printf("Unknown Format Specifier for type @TEMPLATED_DATA_TYPE@.\n"); 239 | endc_function 240 | 241 | c_function print() 242 | printf("Vector (size = %d, capacity = %d) : [", this->size, this->capacity); 243 | for (size_t i = 0; i < this->size; ++i) { 244 | printf("%d",this->arr[i]); 245 | if (i < this->size - 1) { 246 | printf(", "); 247 | } 248 | } 249 | printf("]\n"); 250 | endc_function 251 | 252 | c_function print() 253 | printf("Vector (size = %d, capacity = %d) : [", this->size, this->capacity); 254 | for (size_t i = 0; i < this->size; ++i) { 255 | printf("%f",this->arr[i]); 256 | if (i < this->size - 1) { 257 | printf(", "); 258 | } 259 | } 260 | printf("]\n"); 261 | endc_function 262 | 263 | c_function print() 264 | printf("Vector (size = %d, capacity = %d) : [", this->size, this->capacity); 265 | for (size_t i = 0; i < this->size; ++i) { 266 | printf("\'%c\'",this->arr[i]); 267 | if (i < this->size - 1) { 268 | printf(", "); 269 | } 270 | } 271 | printf("]\n"); 272 | endc_function 273 | 274 | c_function print() 275 | printf("Vector (size = %d, capacity = %d) : [", this->size, this->capacity); 276 | for (size_t i = 0; i < this->size; ++i) { 277 | printf("\"%s\"",this->arr[i].arr); 278 | if (i < this->size - 1) { 279 | printf(", "); 280 | } 281 | } 282 | printf("]\n"); 283 | endc_function 284 | endnamespace 285 | ///*/// 286 | 287 | -------------------------------------------------------------------------------- /examples/11_Threads_And_Channels_generated_anil.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | void **buffer; 8 | size_t capacity; 9 | size_t size; 10 | size_t head; 11 | size_t tail; 12 | bool is_closed; 13 | pthread_mutex_t mutex; 14 | pthread_cond_t can_send; 15 | pthread_cond_t can_receive; 16 | } ChannelInternal; 17 | 18 | typedef struct { 19 | void *data; 20 | bool ok; 21 | } ChannelResultInternal; 22 | 23 | typedef void *ThreadInternalVoidPointer; 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | struct Channel { 30 | ChannelInternal channel; 31 | }; 32 | 33 | struct ChannelResult { 34 | ChannelResultInternal result; 35 | }; 36 | 37 | struct IntChannelResult { 38 | int value; 39 | bool ok; 40 | }; 41 | 42 | struct Thread { 43 | pthread_t id; 44 | bool joined; 45 | }; 46 | 47 | bool ChannelResultis_ok(struct ChannelResult *this); 48 | bool IntChannelResultis_ok(struct IntChannelResult *this); 49 | int IntChannelResultget_value(struct IntChannelResult *this); 50 | void Channel__init__(struct Channel *this, int capacity); 51 | ThreadInternalVoidPointer ChannelToThreadVoidPointer(struct Channel *this); 52 | bool Channelsend_ptr(struct Channel *this, ThreadInternalVoidPointer data); 53 | bool Channelsend(struct Channel *this, int data); 54 | struct ChannelResult Channelreceive(struct Channel *this); 55 | struct IntChannelResult Channelreceive_int(struct Channel *this); 56 | void Channelclose(struct Channel *this); 57 | void Channel__del__(struct Channel *this); 58 | void Thread__init__( 59 | struct Thread *this, 60 | ThreadInternalVoidPointer (*start_routine)(ThreadInternalVoidPointer), 61 | ThreadInternalVoidPointer arg); 62 | void Threadjoin(struct Thread *this); 63 | void Thread__del__(struct Thread *this); 64 | void Task(); 65 | ThreadInternalVoidPointer WorkerThread(ThreadInternalVoidPointer arg); 66 | int main(); 67 | 68 | bool ChannelResultis_ok(struct ChannelResult *this) { return this->result.ok; } 69 | 70 | bool IntChannelResultis_ok(struct IntChannelResult *this) { return this->ok; } 71 | 72 | int IntChannelResultget_value(struct IntChannelResult *this) { 73 | return this->value; 74 | } 75 | 76 | void Channel__init__(struct Channel *this, int capacity) { 77 | if (capacity <= 0) { 78 | fprintf(stderr, "Error: Channel capacity must be positive.\n"); 79 | exit(-1); 80 | } 81 | 82 | ChannelInternal *ch = &this->channel; 83 | 84 | ch->buffer = (void **)malloc(capacity * sizeof(void *)); 85 | if (!ch->buffer) { 86 | fprintf(stderr, "Error: Memory allocation failed for Channel buffer.\n"); 87 | exit(-1); 88 | } 89 | 90 | ch->capacity = capacity; 91 | ch->size = 0; 92 | ch->head = 0; 93 | ch->tail = 0; 94 | ch->is_closed = false; 95 | 96 | pthread_mutex_init(&ch->mutex, NULL); 97 | pthread_cond_init(&ch->can_send, NULL); 98 | pthread_cond_init(&ch->can_receive, NULL); 99 | } 100 | 101 | ThreadInternalVoidPointer ChannelToThreadVoidPointer(struct Channel *this) { 102 | ThreadInternalVoidPointer ptr = (ThreadInternalVoidPointer)this; 103 | return ptr; 104 | } 105 | 106 | bool Channelsend_ptr(struct Channel *this, ThreadInternalVoidPointer data) { 107 | ChannelInternal *ch = &this->channel; 108 | pthread_mutex_lock(&ch->mutex); 109 | 110 | while (ch->size == ch->capacity) { 111 | if (ch->is_closed) { 112 | pthread_mutex_unlock(&ch->mutex); 113 | return false; 114 | } 115 | pthread_cond_wait(&ch->can_send, &ch->mutex); 116 | } 117 | 118 | if (ch->is_closed) { 119 | pthread_mutex_unlock(&ch->mutex); 120 | return false; 121 | } 122 | 123 | ch->buffer[ch->tail] = data; 124 | ch->tail = (ch->tail + 1) % ch->capacity; 125 | ch->size++; 126 | 127 | pthread_cond_signal(&ch->can_receive); 128 | pthread_mutex_unlock(&ch->mutex); 129 | 130 | return true; 131 | } 132 | 133 | bool Channelsend(struct Channel *this, int data) { 134 | int *value = (int *)malloc(sizeof(int)); 135 | if (!value) { 136 | fprintf( 137 | stderr, 138 | "Error: Threads::send() Memory allocation failed for sending data.\n"); 139 | return false; 140 | } 141 | *value = data; 142 | return Channelsend_ptr(this, (ThreadInternalVoidPointer)value); 143 | } 144 | 145 | struct ChannelResult Channelreceive(struct Channel *this) { 146 | ChannelInternal *ch = &this->channel; 147 | pthread_mutex_lock(&ch->mutex); 148 | while (ch->size == 0) { 149 | if (ch->is_closed) { 150 | pthread_mutex_unlock(&ch->mutex); 151 | ChannelResultInternal result = {NULL, false}; 152 | struct ChannelResult res; 153 | res.result = result; 154 | return res; 155 | } 156 | pthread_cond_wait(&ch->can_receive, &ch->mutex); 157 | } 158 | 159 | void *data = ch->buffer[ch->head]; 160 | ch->head = (ch->head + 1) % ch->capacity; 161 | ch->size--; 162 | pthread_cond_signal(&ch->can_send); 163 | pthread_mutex_unlock(&ch->mutex); 164 | 165 | ChannelResultInternal result = {data, true}; 166 | struct ChannelResult res; 167 | res.result = result; 168 | return res; 169 | } 170 | 171 | struct IntChannelResult Channelreceive_int(struct Channel *this) { 172 | ChannelInternal *ch = &this->channel; 173 | pthread_mutex_lock(&ch->mutex); 174 | while (ch->size == 0) { 175 | if (ch->is_closed) { 176 | pthread_mutex_unlock(&ch->mutex); 177 | struct IntChannelResult res = {0, false}; 178 | return res; 179 | } 180 | pthread_cond_wait(&ch->can_receive, &ch->mutex); 181 | } 182 | 183 | int *data = (int *)ch->buffer[ch->head]; 184 | ch->head = (ch->head + 1) % ch->capacity; 185 | ch->size--; 186 | pthread_cond_signal(&ch->can_send); 187 | pthread_mutex_unlock(&ch->mutex); 188 | 189 | struct IntChannelResult res = {*data, true}; 190 | free(data); 191 | return res; 192 | } 193 | 194 | void Channelclose(struct Channel *this) { 195 | ChannelInternal *ch = &this->channel; 196 | pthread_mutex_lock(&ch->mutex); 197 | if (ch->is_closed) { 198 | pthread_mutex_unlock(&ch->mutex); 199 | return; 200 | } 201 | 202 | ch->is_closed = true; 203 | pthread_cond_broadcast(&ch->can_receive); 204 | pthread_cond_broadcast(&ch->can_send); 205 | pthread_mutex_unlock(&ch->mutex); 206 | } 207 | 208 | void Channel__del__(struct Channel *this) { 209 | ChannelInternal *ch = &this->channel; 210 | 211 | pthread_mutex_lock(&ch->mutex); 212 | 213 | for (size_t i = 0; i < ch->size; i++) { 214 | size_t index = (ch->head + i) % ch->capacity; 215 | free(ch->buffer[index]); 216 | } 217 | 218 | free(ch->buffer); 219 | ch->buffer = NULL; 220 | ch->size = 0; 221 | ch->capacity = 0; 222 | ch->head = 0; 223 | ch->tail = 0; 224 | ch->is_closed = true; 225 | 226 | pthread_mutex_unlock(&ch->mutex); 227 | 228 | pthread_mutex_destroy(&ch->mutex); 229 | pthread_cond_destroy(&ch->can_send); 230 | pthread_cond_destroy(&ch->can_receive); 231 | } 232 | 233 | void Thread__init__( 234 | struct Thread *this, 235 | ThreadInternalVoidPointer (*start_routine)(ThreadInternalVoidPointer), 236 | ThreadInternalVoidPointer arg) { 237 | if (pthread_create(&this->id, NULL, start_routine, arg) != 0) { 238 | fprintf(stderr, "Error: Failed to create thread.\n"); 239 | exit(-1); 240 | } 241 | this->joined = false; 242 | } 243 | 244 | void Threadjoin(struct Thread *this) { 245 | pthread_join(this->id, NULL); 246 | this->joined = true; 247 | } 248 | 249 | void Thread__del__(struct Thread *this) { 250 | if (!this->joined) { 251 | fprintf(stderr, "Warning: Thread was not joined before deletion.\n"); 252 | pthread_detach(this->id); 253 | } 254 | } 255 | 256 | struct Channel ch; 257 | 258 | void Task() { 259 | 260 | while (true) { 261 | struct IntChannelResult res = Channelreceive_int(&ch); 262 | 263 | if (IntChannelResultis_ok(&res)) { 264 | int value = IntChannelResultget_value(&res); 265 | printf("Worker: Received %d \n", value); 266 | } else { 267 | printf("Worker: Channel is closed and empty. Exiting. \n"); 268 | break; 269 | } 270 | } 271 | } 272 | 273 | ThreadInternalVoidPointer WorkerThread(ThreadInternalVoidPointer arg) { 274 | Task(); 275 | return NULL; 276 | } 277 | 278 | int main() { 279 | // Global Variables Initialization. 280 | Channel__init__(&ch, 10); 281 | 282 | printf("Main: Created a channel with capacity 10. \n"); 283 | 284 | printf("Main: Starting worker thread. \n"); 285 | 286 | ThreadInternalVoidPointer channelAsVoidPointer = 287 | ChannelToThreadVoidPointer(&ch); 288 | // the above void* casting can be done by Thread itself. 289 | struct Thread worker; 290 | Thread__init__(&worker, WorkerThread, channelAsVoidPointer); 291 | 292 | for (size_t i = 1; i < 50; i++) { 293 | printf("Main: Sending %llu \n", i); 294 | 295 | bool res = Channelsend(&ch, i); 296 | 297 | if (res == false) { 298 | printf("Main: Failed to send data, channel is closed.\n"); 299 | break; 300 | } 301 | } 302 | 303 | printf("Main: All items sent. Closing channel.\n"); 304 | Channelclose(&ch); 305 | 306 | printf("Main: Waiting for worker to finish...\n"); 307 | Threadjoin(&worker); 308 | 309 | printf("Main: Program finished successfully.\n"); 310 | 311 | Thread__del__(&worker); 312 | 313 | Channel__del__(&ch); 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /examples/TestSuites/slicing_generated.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | /////////////////////////////////////////// 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // IMPORTS // 11 | 12 | struct Vector_char { 13 | char *arr; 14 | int size; 15 | int capacity; 16 | }; 17 | 18 | size_t Vector_charlen(struct Vector_char *this); 19 | void Vector_char__init__(struct Vector_char *this, int capacity); 20 | void Vector_char_call_destructor_for_element(struct Vector_char *this, 21 | int index); 22 | void Vector_char_call_destructor_for_all_elements(struct Vector_char *this); 23 | void Vector_char_reset(struct Vector_char *this); 24 | void Vector_char__del__(struct Vector_char *this); 25 | char Vector_char__getitem__(struct Vector_char *this, int index); 26 | void Vector_char_set_ith_item(struct Vector_char *this, int index, char value); 27 | void Vector_charpush_unchecked(struct Vector_char *this, char value); 28 | void Vector_charvalidate_index(struct Vector_char *this, int index); 29 | void Vector_char_set(struct Vector_char *this, int index, char value); 30 | void Vector_char__setitem__(struct Vector_char *this, int index, char value); 31 | void Vector_charallocate_more(struct Vector_char *this, int n); 32 | void Vector_char_grow_if_required(struct Vector_char *this); 33 | void Vector_char_push(struct Vector_char *this, char value); 34 | void Vector_charpush(struct Vector_char *this, char value); 35 | char Vector_charpop(struct Vector_char *this); 36 | void Vector_char_shift_left_from(struct Vector_char *this, int index); 37 | void Vector_charremove_at(struct Vector_char *this, int index); 38 | void Vector_char_clear(struct Vector_char *this); 39 | void Vector_charclear(struct Vector_char *this); 40 | bool Vector_char__contains__(struct Vector_char *this, char value); 41 | void Vector_charprint(struct Vector_char *this); 42 | 43 | size_t Vector_charlen(struct Vector_char *this) { return this->size; } 44 | 45 | void Vector_char__init__(struct Vector_char *this, int capacity) { 46 | // if we want to use instanced template type in fn body, we use following 47 | // syntax. 48 | // @ TEMPLATED_DATA_TYPE @ 49 | this->arr = (char *)malloc(capacity * sizeof(char)); 50 | 51 | if (this->arr == NULL) { 52 | fprintf(stderr, "Memory allocation failed.\n"); 53 | exit(EXIT_FAILURE); 54 | } 55 | this->size = 0; 56 | this->capacity = capacity; 57 | } 58 | 59 | void Vector_char_call_destructor_for_element(struct Vector_char *this, 60 | int index) { 61 | // If element at 'index' has a destructor, then emit a destructor call. 62 | // Otherwise emit nothing. 63 | // Evaluated at compile time. 64 | } 65 | 66 | void Vector_char_call_destructor_for_all_elements(struct Vector_char *this) { 67 | for (size_t i = 0; i < Vector_charlen(this); i++) { 68 | Vector_char_call_destructor_for_element(this, i); 69 | } 70 | } 71 | 72 | void Vector_char_reset(struct Vector_char *this) { 73 | free(this->arr); 74 | this->arr = NULL; 75 | this->size = 0; 76 | this->capacity = 0; 77 | } 78 | 79 | void Vector_char__del__(struct Vector_char *this) { 80 | Vector_char_call_destructor_for_all_elements(this); 81 | Vector_char_reset(this); 82 | } 83 | 84 | char Vector_char__getitem__(struct Vector_char *this, int index) { 85 | if (index < 0) { 86 | index += this->size; 87 | } 88 | return *(this->arr + index); 89 | } 90 | 91 | void Vector_char_set_ith_item(struct Vector_char *this, int index, char value) { 92 | // NOTE: We assume that the index is valid. 93 | this->arr[index] = value; 94 | } 95 | 96 | void Vector_charpush_unchecked(struct Vector_char *this, char value) { 97 | this->arr[this->size++] = value; 98 | } 99 | 100 | void Vector_charvalidate_index(struct Vector_char *this, int index) { 101 | if (index < 0 || index >= this->size) { 102 | fprintf(stderr, "Index out of bounds: index = %d, size = %d.\n", index, 103 | this->size); 104 | exit(EXIT_FAILURE); 105 | } 106 | } 107 | 108 | void Vector_char_set(struct Vector_char *this, int index, char value) { 109 | 110 | if (index < 0) { 111 | index = index + this->size; 112 | } 113 | Vector_charvalidate_index(this, index); 114 | Vector_char_call_destructor_for_element(this, index); 115 | Vector_char_set_ith_item(this, index, value); 116 | } 117 | 118 | void Vector_char__setitem__(struct Vector_char *this, int index, char value) { 119 | Vector_char_set(this, index, value); 120 | } 121 | 122 | void Vector_charallocate_more(struct Vector_char *this, int n) { 123 | if (n <= 0) { 124 | // Prevent unnecessary reallocation or negative increments. 125 | return; 126 | } 127 | 128 | size_t new_capacity = this->capacity + n; 129 | char *new_arr = (char *)realloc(this->arr, new_capacity * sizeof(char)); 130 | 131 | if (!new_arr) { 132 | fprintf(stderr, "Vector<>::allocate_more(): Memory reallocation failed.\n"); 133 | exit(EXIT_FAILURE); 134 | } 135 | 136 | this->arr = new_arr; 137 | this->capacity = new_capacity; 138 | } 139 | 140 | void Vector_char_grow_if_required(struct Vector_char *this) { 141 | 142 | if (this->size >= this->capacity) { 143 | 144 | if (this->capacity > 0) { 145 | Vector_charallocate_more(this, this->capacity); 146 | } else { 147 | // Avoid 0 capacity. 148 | Vector_charallocate_more(this, 1); 149 | } 150 | } 151 | } 152 | 153 | void Vector_char_push(struct Vector_char *this, char value) { 154 | Vector_char_grow_if_required(this); 155 | Vector_charpush_unchecked(this, value); 156 | } 157 | 158 | void Vector_charpush(struct Vector_char *this, char value) { 159 | Vector_char_push(this, value); 160 | } 161 | 162 | char Vector_charpop(struct Vector_char *this) { 163 | if (this->size == 0) { 164 | fprintf(stderr, "Pop from empty Vector.\n"); 165 | exit(EXIT_FAILURE); 166 | } 167 | return this->arr[--this->size]; 168 | } 169 | 170 | void Vector_char_shift_left_from(struct Vector_char *this, int index) { 171 | // NOTE: The index is assumed to be valid(i.e not negative and within bounds). 172 | for (int i = index; i < this->size - 1; i++) { 173 | this->arr[i] = this->arr[i + 1]; 174 | } 175 | } 176 | 177 | void Vector_charremove_at(struct Vector_char *this, int index) { 178 | 179 | if (index < 0) { 180 | index = index + this->size; 181 | } 182 | Vector_charvalidate_index(this, index); 183 | Vector_char_call_destructor_for_element(this, index); 184 | Vector_char_shift_left_from(this, index); 185 | this->size -= 1; 186 | } 187 | 188 | void Vector_char_clear(struct Vector_char *this) { 189 | free(this->arr); 190 | 191 | this->capacity = 1; 192 | this->arr = (char *)malloc(this->capacity * sizeof(char)); 193 | 194 | if (this->arr == NULL) { 195 | fprintf(stderr, "Vector<>::_clear(): Memory allocation failed.\n"); 196 | exit(EXIT_FAILURE); 197 | } 198 | 199 | this->size = 0; 200 | } 201 | 202 | void Vector_charclear(struct Vector_char *this) { 203 | Vector_char_call_destructor_for_all_elements(this); 204 | Vector_char_clear(this); 205 | } 206 | 207 | bool Vector_char__contains__(struct Vector_char *this, char value) { 208 | // This function is an overloaded function. 209 | // Here <> in function defination means the base overload. 210 | for (size_t i = 0; i < this->size; ++i) { 211 | if (this->arr[i] == value) { 212 | return true; 213 | } 214 | } 215 | return false; 216 | } 217 | 218 | void Vector_charprint(struct Vector_char *this) { 219 | printf("Vector (size = %d, capacity = %d) : [", this->size, 220 | this->capacity); 221 | for (size_t i = 0; i < this->size; ++i) { 222 | printf("\'%c\'", this->arr[i]); 223 | if (i < this->size - 1) { 224 | printf(", "); 225 | } 226 | } 227 | printf("]\n"); 228 | } 229 | 230 | int main() { 231 | 232 | struct Vector_char a; 233 | Vector_char__init__(&a, 10); 234 | Vector_charpush(&a, '1'); 235 | Vector_charpush(&a, '2'); 236 | Vector_charpush(&a, '3'); 237 | Vector_charpush(&a, '4'); 238 | Vector_charpush(&a, '5'); 239 | 240 | printf("Printing in normal order(step 1): 1,2,3,4,5 \n"); 241 | size_t tmp_len_0 = Vector_charlen(&a); 242 | for (size_t i = 0; i < tmp_len_0; i++) { 243 | char a1 = Vector_char__getitem__(&a, i); 244 | printf("%c ", a1); 245 | } 246 | 247 | printf("\nPrinting in normal order(step 1) in between (2,..): 3,4,5 \n"); 248 | size_t tmp_len_1 = Vector_charlen(&a); 249 | for (size_t i = 2; i < tmp_len_1; i++) { 250 | char a1 = Vector_char__getitem__(&a, i); 251 | printf("%c ", a1); 252 | } 253 | 254 | printf("\nPrinting in normal order(step 1) in between (2,4): 3,4 \n"); 255 | int tmp_len_2 = 4; 256 | for (size_t i = 2; i < tmp_len_2; i++) { 257 | char a1 = Vector_char__getitem__(&a, i); 258 | printf("%c ", a1); 259 | } 260 | 261 | printf("\nPrinting in normal order(step 2): 1,3,5 \n"); 262 | size_t tmp_len_3 = Vector_charlen(&a); 263 | for (size_t i = 0; i < tmp_len_3; i += 2) { 264 | char a1 = Vector_char__getitem__(&a, i); 265 | printf("%c ", a1); 266 | } 267 | 268 | printf("\nPrinting in reverse order: 5,4,3,2,1 \n"); 269 | size_t tmp_len_4 = Vector_charlen(&a); 270 | tmp_len_4 -= 1; 271 | for (size_t i = tmp_len_4; i != (size_t)-1; i += -1) { 272 | char a1 = Vector_char__getitem__(&a, i); 273 | printf("%c ", a1); 274 | } 275 | 276 | Vector_char__del__(&a); 277 | 278 | return 0; 279 | } --------------------------------------------------------------------------------