├── .gitattributes ├── .gitignore ├── README.md ├── examples ├── design.curly ├── e.curly ├── eval.curly └── primes.curly ├── makefile ├── src ├── compiler │ ├── backends │ │ └── llvm │ │ │ ├── codegen.c │ │ │ ├── codegen.h │ │ │ ├── environment.c │ │ │ ├── environment.h │ │ │ ├── functions.c │ │ │ ├── functions.h │ │ │ ├── llvm_types.c │ │ │ └── llvm_types.h │ └── frontend │ │ ├── correctness │ │ ├── check.c │ │ ├── check.h │ │ ├── check_helper.h │ │ ├── scope.c │ │ ├── scope.h │ │ ├── type_generators.c │ │ ├── type_generators.h │ │ ├── types.c │ │ └── types.h │ │ ├── ir │ │ ├── generate_ir.c │ │ └── generate_ir.h │ │ └── parse │ │ ├── ast.c │ │ ├── ast.h │ │ ├── lexer.c │ │ ├── lexer.h │ │ ├── parser.c │ │ └── parser.h ├── main.c └── utils │ ├── hashes.c │ ├── hashes.h │ ├── hashmap.c │ ├── hashmap.h │ ├── list.c │ └── list.h └── tests ├── compile-tests ├── assign.curly ├── infix.curly └── with.curly ├── correctness-tests └── types.curly └── parsing-tests ├── for.curly ├── func-apply.curly ├── if.curly ├── test.curly ├── values.txt └── where.curly /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Miscellaneous 55 | .DS_Store 56 | .vscode/ 57 | curly 58 | tags 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Curly 2 | IMPORTANT NOTICE: This repo is now archived. For the current implementation of the language, please see https://github.com/jenra-uwu/curly-lang. 3 | 4 | Curly is a functional programming language that focuses on iterators. Some of its main implementation features include lazy evaluation, list comprehensions, and quantifiers. 5 | 6 | ## Example 7 |
 8 | primes = n in (from 2) where
 9 |     for all p in (range 2 n)
10 |         n % p != 0
11 | 
12 | 13 | ## Build 14 | Just type in the following: 15 | ```bash 16 | git clone https://github.com/jenra-uwu/curly-lang && cd curly-lang && make 17 | ``` 18 | This project depends on `libedit-dev`/`libedit-devel`/`readline` (for Linux and macOS respectively) and `llvm`, which can each be installed using your favourite package manager (`apt`/`pacman`/`yum` for Linux and Homebrew/MacPorts for macOS). 19 | 20 | Note: On Fedora, you also need to install `llvm-devel`. 21 | 22 | Note: This repo has been tested on macOS, Ubuntu, and Fedora as of now, but will not build on Windows. Windows support is coming soon. 23 | 24 | ## Progress 25 | The parser is done, and the type checker is mostly done. Current effort is focused on the LLVM backend. Everything is highly experimental. Be cautious: code may be explosive. 26 | -------------------------------------------------------------------------------- /examples/design.curly: -------------------------------------------------------------------------------- 1 | # statically type - types are inferred 2 | # a variable must remain the same type through its lifetime 3 | 4 | variable = expression # assignment 5 | head..tail = expression # getting the head and tail of an iterable 6 | 7 | with var1 = expression, # create a scope in which var[123] are used 8 | var2 = expression, # these are the only way to define variables in functions, loops, and conditions 9 | var3 = expression, 10 | f var1 var2 var3 11 | 12 | function arg1: type1 arg2: type2 = expression # function 13 | # a function can only have one signature type1 -> type2 -> return_type 14 | 15 | function arg1 (function arg2 arg3) # function application 16 | function arg1 # partial application 17 | function (*list) # currying 18 | 19 | if condition then expression else expression # if else expression 20 | 21 | debug expression # can place anywhere, prints out a message like this if debug is enabled: 22 | # (db) expression evaluated to value on file.curly:lino:charno 23 | 24 | range a b # numbers in [a, b) as a generator 25 | list.i.j.k # get the kth element of the jth element of the ith element of list 26 | dict.a # get the value of key a in dict 27 | list.(range a b) # get the sublist of list with indices in the range 28 | x in set # check if x is in set 29 | 30 | # list compehensions are generated lazily 31 | for i in iter f i # creates a list 32 | with acc = value, for i in iter acc = f acc i # folds iterable into a single value 33 | # pass - does not return a value 34 | # stop - halts a loop 35 | # true, false, and, or, xor 36 | 37 | # quantifiers 38 | for all i in iter f i # checks that all elements of the iterable follow some predicate 39 | for some i in iter f i # checks that some element of the iterable follows some predicate 40 | 41 | # filtering 42 | x in iter where f x # lazy list / generator 43 | 44 | "string owo" # a string 45 | "" expression # expression as a string / concatenation 46 | 47 | # type names: int, float, string, list, set, dict, gen, type, func 48 | 49 | # example: fibonacci 50 | fib 0 = 1 51 | fib 1 = 1 52 | fib n: Int = (fib n - 1) + (fib n - 2) 53 | 54 | ExType = type isFloat: bool & (num: int | num: float) 55 | 56 | instance: ExType = { 57 | isFloat = false, 58 | num = 42 59 | } 60 | 61 | instance.isFloat # false 62 | instance.0 # false 63 | instance.num # 42 64 | instance.1 # 42 65 | 66 | # types: & - intersection type; * - product type; | - union type; >> - function type; *type - generator of type; [type] - list of type 67 | Complex = type rect: (x: Float & y: Float) | polar: (r: Float & theta: Float) 68 | Pair = type Int * Int 69 | Tree = type T => leaf: T | branch: (Tree T * Tree T) 70 | 71 | z1: Complex = {r = 1, theta = 2} 72 | p: Pair = {5, 4} 73 | t1: (Tree Bool) = { 74 | branch = { 75 | leaf = true, leaf = false 76 | }, leaf = false 77 | } 78 | 79 | z2: Complex = {1, 2} 80 | t2: (Tree Bool) = {{true, false}, false} 81 | -------------------------------------------------------------------------------- /examples/e.curly: -------------------------------------------------------------------------------- 1 | factorials = with acc = 1, 2 | for i in (from 0) 3 | acc = ( 4 | if i == 0 5 | then 1 6 | else i 7 | ) * acc 8 | 9 | e = with acc = 0, 10 | for n in factorials 11 | acc = 1 / n + acc 12 | -------------------------------------------------------------------------------- /examples/eval.curly: -------------------------------------------------------------------------------- 1 | BinOp = enum Mul | Div | Add | Sub 2 | 3 | Expr = type value: Int 4 | | bin: (op: BinOp * Expr * Expr) 5 | 6 | eval: Expr -> Int 7 | eval n: Expr.value = n 8 | eval bin: Expr.bin = match bin.op 9 | to Mul => eval bin.1 * eval bin.2 10 | to Div => eval bin.1 / eval bin.2 11 | to Add => eval bin.1 + eval bin.2 12 | to Sub => eval bin.1 - eval bin.2 13 | -------------------------------------------------------------------------------- /examples/primes.curly: -------------------------------------------------------------------------------- 1 | primes = n in (from 2) where 2 | for all p in (range 2 n) 3 | p % n != 0 4 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## Curly 3 | ## makefile 4 | ## 5 | ## jenra 6 | ## March 3 2020 7 | ## 8 | 9 | CC = gcc 10 | CPPC = g++ 11 | CFLAGS = -Wall -O0 -ggdb3 $(shell llvm-config --cflags) 12 | CPPFLAGS = $(shell llvm-config --cxxflags --ldflags --libs all) 13 | ifeq ($(shell uname), Darwin) 14 | CPPFLAGS += -lm -lz -lcurses -lxml2 15 | else 16 | CPPFLAGS += $(shell llvm-config --system-libs) 17 | endif 18 | LIBS = -ledit 19 | 20 | CODE = src/ 21 | 22 | all: *.o 23 | $(CPPC) $(CPPFLAGS) $(LIBS) -o curly *.o 24 | 25 | debug: *.o 26 | $(CC) $(CFLAGS) $(LDFLAGS) -o curly *.o $(LIBS) 27 | 28 | *.o: main compiler utils 29 | 30 | main: $(CODE)*.c 31 | $(CC) $(CFLAGS) -c $? 32 | 33 | compiler: frontend backends 34 | 35 | frontend: $(CODE)compiler/frontend/*/*.c 36 | $(CC) $(CFLAGS) -c $? 37 | 38 | backends: $(CODE)compiler/backends/*/*.c 39 | $(CC) $(CFLAGS) -c $? 40 | 41 | utils: $(CODE)utils/*.c 42 | $(CC) $(CFLAGS) -c $? 43 | 44 | clean: 45 | -rm *.o 46 | -------------------------------------------------------------------------------- /src/compiler/backends/llvm/codegen.c: -------------------------------------------------------------------------------- 1 | // 2 | // Curly 3 | // codegen.c: Implements code generation to LLVM IR. 4 | // 5 | // Created by jenra. 6 | // Created on September 7 2020. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "../../../utils/list.h" 13 | #include "codegen.h" 14 | #include "functions.h" 15 | #include "llvm_types.h" 16 | 17 | // build_expression(ir_sexpr_t*, LLVMBuilderRef, llvm_codegen_env_t*) -> LLVMValueRef 18 | // Builds an expression to LLVM IR. 19 | LLVMValueRef build_expression(ir_sexpr_t* sexpr, LLVMBuilderRef builder, llvm_codegen_env_t* env); 20 | 21 | // build_assignment(ir_sexpr_t*, LLVMBuilderRef, llvm_codegen_env_t*) -> LLVMValueRef 22 | // Builds an assignment to LLVM IR. 23 | LLVMValueRef build_assignment(ir_sexpr_t* sexpr, LLVMBuilderRef builder, llvm_codegen_env_t* env); 24 | 25 | // build_infix(ir_sexpr_t*, LLVMBuilderRef, llvm_codegen_env_t*) -> LLVMValueRef 26 | // Builds an infix expression to LLVM IR. 27 | LLVMValueRef build_infix(ir_sexpr_t* sexpr, LLVMBuilderRef builder, llvm_codegen_env_t* env) 28 | { 29 | // Build the operands 30 | LLVMValueRef left = build_expression(sexpr->infix.left, builder, env); 31 | LLVMValueRef right = build_expression(sexpr->infix.right, builder, env); 32 | 33 | // Cast ints to floats if necessary 34 | type_t* ltype = sexpr->infix.left->type; 35 | type_t* rtype = sexpr->infix.right->type; 36 | if (ltype->type_type == IR_TYPES_PRIMITIVE && rtype->type_type == IR_TYPES_PRIMITIVE) 37 | { 38 | if (!strcmp(ltype->type_name, "Int") && !strcmp(rtype->type_name, "Float")) 39 | left = LLVMBuildSIToFP(builder, left, LLVMDoubleType(), ""); 40 | else if (!strcmp(ltype->type_name, "Float") && !strcmp(rtype->type_name, "Int")) 41 | right = LLVMBuildSIToFP(builder, right, LLVMDoubleType(), ""); 42 | } 43 | 44 | // Build the operator 45 | switch(sexpr->infix.op) 46 | { 47 | case IR_BINOPS_MUL: 48 | if (sexpr->type->type_type == IR_TYPES_PRIMITIVE && !strcmp(sexpr->type->type_name, "Int")) 49 | return LLVMBuildMul(builder, left, right, ""); 50 | else return LLVMBuildFMul(builder, left, right, ""); 51 | case IR_BINOPS_DIV: 52 | if (sexpr->type->type_type == IR_TYPES_PRIMITIVE && !strcmp(sexpr->type->type_name, "Int")) 53 | return LLVMBuildSDiv(builder, left, right, ""); 54 | else return LLVMBuildFDiv(builder, left, right, ""); 55 | case IR_BINOPS_MOD: 56 | return LLVMBuildSRem(builder, left, right, ""); 57 | case IR_BINOPS_ADD: 58 | if (sexpr->type->type_type == IR_TYPES_PRIMITIVE && !strcmp(sexpr->type->type_name, "Int")) 59 | return LLVMBuildAdd(builder, left, right, ""); 60 | else return LLVMBuildFAdd(builder, left, right, ""); 61 | case IR_BINOPS_SUB: 62 | if (sexpr->type->type_type == IR_TYPES_PRIMITIVE && !strcmp(sexpr->type->type_name, "Int")) 63 | return LLVMBuildSub(builder, left, right, ""); 64 | else return LLVMBuildFSub(builder, left, right, ""); 65 | case IR_BINOPS_BSL: 66 | return LLVMBuildShl(builder, left, right, ""); 67 | case IR_BINOPS_BSR: 68 | return LLVMBuildLShr(builder, left, right, ""); 69 | case IR_BINOPS_BITAND: 70 | return LLVMBuildAnd(builder, left, right, ""); 71 | case IR_BINOPS_BITOR: 72 | return LLVMBuildOr(builder, left, right, ""); 73 | case IR_BINOPS_BITXOR: 74 | case IR_BINOPS_BOOLXOR: 75 | return LLVMBuildXor(builder, left, right, ""); 76 | case IR_BINOPS_CMPLT: 77 | if (ltype->type_type == IR_TYPES_PRIMITIVE && !strcmp(ltype->type_name, "Int") 78 | && rtype->type_type == IR_TYPES_PRIMITIVE && !strcmp(rtype->type_name, "Int")) 79 | return LLVMBuildICmp(builder, LLVMIntSLT, left, right, ""); 80 | else return LLVMBuildFCmp(builder, LLVMRealOLT, left, right, ""); 81 | case IR_BINOPS_CMPLTE: 82 | if (ltype->type_type == IR_TYPES_PRIMITIVE && !strcmp(ltype->type_name, "Int") 83 | && rtype->type_type == IR_TYPES_PRIMITIVE && !strcmp(rtype->type_name, "Int")) 84 | return LLVMBuildICmp(builder, LLVMIntSLE, left, right, ""); 85 | else return LLVMBuildFCmp(builder, LLVMRealOLE, left, right, ""); 86 | case IR_BINOPS_CMPGT: 87 | if (ltype->type_type == IR_TYPES_PRIMITIVE && !strcmp(ltype->type_name, "Int") 88 | && rtype->type_type == IR_TYPES_PRIMITIVE && !strcmp(rtype->type_name, "Int")) 89 | return LLVMBuildICmp(builder, LLVMIntSGT, left, right, ""); 90 | else return LLVMBuildFCmp(builder, LLVMRealOGT, left, right, ""); 91 | case IR_BINOPS_CMPGTE: 92 | if (ltype->type_type == IR_TYPES_PRIMITIVE && !strcmp(ltype->type_name, "Int") 93 | && rtype->type_type == IR_TYPES_PRIMITIVE && !strcmp(rtype->type_name, "Int")) 94 | return LLVMBuildICmp(builder, LLVMIntSGE, left, right, ""); 95 | else return LLVMBuildFCmp(builder, LLVMRealOGE, left, right, ""); 96 | case IR_BINOPS_CMPEQ: 97 | if (ltype->type_type == IR_TYPES_PRIMITIVE && !strcmp(ltype->type_name, "Int") 98 | && rtype->type_type == IR_TYPES_PRIMITIVE && !strcmp(rtype->type_name, "Int")) 99 | return LLVMBuildICmp(builder, LLVMIntEQ, left, right, ""); 100 | else return LLVMBuildFCmp(builder, LLVMRealOEQ, left, right, ""); 101 | case IR_BINOPS_CMPNEQ: 102 | if (ltype->type_type == IR_TYPES_PRIMITIVE && !strcmp(ltype->type_name, "Int") 103 | && rtype->type_type == IR_TYPES_PRIMITIVE && !strcmp(rtype->type_name, "Int")) 104 | return LLVMBuildICmp(builder, LLVMIntNE, left, right, ""); 105 | else return LLVMBuildFCmp(builder, LLVMRealONE, left, right, ""); 106 | default: 107 | return NULL; 108 | } 109 | } 110 | 111 | // build_expression(ir_sexpr_t*, LLVMBuilderRef, llvm_codegen_env_t*) -> LLVMValueRef 112 | // Builds an expression to LLVM IR. 113 | LLVMValueRef build_expression(ir_sexpr_t* sexpr, LLVMBuilderRef builder, llvm_codegen_env_t* env) 114 | { 115 | switch (sexpr->tag) 116 | { 117 | case CURLY_IR_TAGS_INT: 118 | return LLVMConstInt(LLVMInt64Type(), sexpr->i64, false); 119 | case CURLY_IR_TAGS_FLOAT: 120 | return LLVMConstReal(LLVMDoubleType(), sexpr->f64); 121 | case CURLY_IR_TAGS_BOOL: 122 | return LLVMConstInt(LLVMInt1Type(), sexpr->i1, false); 123 | case CURLY_IR_TAGS_SYMBOL: 124 | { 125 | // Get local 126 | LLVMValueRef local = lookup_llvm_local(env, sexpr->symbol); 127 | if (local != NULL) 128 | // { 129 | // // Local is definitely not a thunk 130 | // uint64_t param_index = lookup_llvm_param(env, sexpr->symbol); 131 | // if (param_index >= 64) 132 | return local; 133 | 134 | // // Local is a parameter that has not been checked for thunkiness 135 | // LLVMValueRef thunk_bitmap_ptr = LLVMGetParam(env->current_func, 0); 136 | // LLVMValueRef thunk_bitmap = LLVMBuildLoad2(builder, LLVMInt64Type(), thunk_bitmap_ptr, "thunk.bitmap.deref"); 137 | // LLVMValueRef arg_ptr = local; 138 | // LLVMTypeRef arg_type = LLVMGetElementType(LLVMTypeOf(arg_ptr)); 139 | // uint64_t mask = ((uint64_t) 1) << param_index; 140 | // LLVMValueRef cond_pre = LLVMBuildAnd(builder, thunk_bitmap, LLVMConstInt(LLVMInt64Type(), mask, false), ""); 141 | // LLVMValueRef cond = LLVMBuildIsNotNull(builder, cond_pre, ""); 142 | 143 | // // Create the blocks 144 | // LLVMBasicBlockRef thunk_unwrap = LLVMAppendBasicBlock(env->current_func, "thunk.unwrap"); 145 | // LLVMMoveBasicBlockAfter(thunk_unwrap, env->current_block); 146 | // LLVMBasicBlockRef load_arg = LLVMAppendBasicBlock(env->current_func, "thunk.load"); 147 | // LLVMMoveBasicBlockAfter(load_arg, thunk_unwrap); 148 | // LLVMBasicBlockRef post_thunk = LLVMAppendBasicBlock(env->current_func, "thunk.post"); 149 | // LLVMMoveBasicBlockAfter(post_thunk, load_arg); 150 | 151 | // // Load the argument 152 | // LLVMBuildCondBr(builder, cond, load_arg, thunk_unwrap); 153 | // LLVMPositionBuilderAtEnd(builder, load_arg); 154 | // LLVMValueRef loaded_arg = LLVMBuildLoad2(builder, arg_type, arg_ptr, "loaded"); 155 | // LLVMBuildBr(builder, post_thunk); 156 | 157 | // // Unwrap the thunk 158 | // LLVMPositionBuilderAtEnd(builder, thunk_unwrap); 159 | // LLVMTypeRef func_type = LLVMFunctionType(arg_type, (LLVMTypeRef[]) {}, 0, false); 160 | // LLVMValueRef thunk = LLVMBuildBitCast(builder, arg_ptr, LLVMPointerType(func_type, 0), "thunk"); 161 | // LLVMValueRef evaled = LLVMBuildCall2(builder, func_type, thunk, (LLVMValueRef[]) {}, 0, "evaled"); 162 | // LLVMBuildStore(builder, evaled, arg_ptr); 163 | // LLVMBuildBr(builder, post_thunk); 164 | 165 | // // Build phi instruction 166 | // LLVMValueRef phi_vals[] = {loaded_arg, evaled}; 167 | // LLVMBasicBlockRef phi_blocks[] = {load_arg, thunk_unwrap}; 168 | // LLVMPositionBuilderAtEnd(builder, post_thunk); 169 | // LLVMValueRef phi = LLVMBuildPhi(builder, arg_type, ""); 170 | // LLVMAddIncoming(phi, phi_vals, phi_blocks, 2); 171 | // env->current_block = post_thunk; 172 | 173 | // // Save the evaluated thunk for future usage 174 | // set_llvm_param(env, sexpr->symbol, phi, 255); 175 | // return phi; 176 | // } 177 | 178 | // Get global 179 | LLVMValueRef global = LLVMGetNamedGlobal(env->header_mod, sexpr->symbol); 180 | return LLVMBuildLoad(builder, global, ""); 181 | } 182 | case CURLY_IR_TAGS_INFIX: 183 | switch (sexpr->infix.op) 184 | { 185 | case IR_BINOPS_BOOLAND: 186 | { 187 | // Build the left operand 188 | LLVMValueRef left = build_expression(sexpr->infix.left, builder, env); 189 | 190 | // Create basic blocks to jump to 191 | LLVMBasicBlockRef from = env->current_block; 192 | LLVMBasicBlockRef right_block = LLVMAppendBasicBlock(env->current_func, "and.rhs"); 193 | LLVMMoveBasicBlockAfter(right_block, from); 194 | LLVMBasicBlockRef post_and = LLVMAppendBasicBlock(env->current_func, "and.post"); 195 | LLVMMoveBasicBlockAfter(post_and, right_block); 196 | 197 | // Build the branch and right operand 198 | LLVMBuildCondBr(builder, left, right_block, post_and); 199 | LLVMPositionBuilderAtEnd(builder, right_block); 200 | env->local = push_llvm_scope(env->local); 201 | env->current_block = right_block; 202 | LLVMValueRef right = build_expression(sexpr->infix.right, builder, env); 203 | right_block = env->current_block; 204 | env->local = pop_llvm_scope(env->local); 205 | 206 | // Build phi 207 | LLVMBuildBr(builder, post_and); 208 | LLVMPositionBuilderAtEnd(builder, post_and); 209 | env->current_block = post_and; 210 | LLVMValueRef phi = LLVMBuildPhi(builder, LLVMInt1Type(), ""); 211 | LLVMValueRef incoming_values[] = {left, right}; 212 | LLVMBasicBlockRef incoming_blocks[] = {from, right_block}; 213 | LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); 214 | return phi; 215 | } 216 | 217 | case IR_BINOPS_BOOLOR: 218 | { 219 | // Build the left operand 220 | LLVMValueRef left = build_expression(sexpr->infix.left, builder, env); 221 | 222 | // Create basic blocks to jump to 223 | LLVMBasicBlockRef from = env->current_block; 224 | LLVMBasicBlockRef right_block = LLVMAppendBasicBlock(env->current_func, "or.rhs"); 225 | LLVMMoveBasicBlockAfter(right_block, from); 226 | LLVMBasicBlockRef post_or = LLVMAppendBasicBlock(env->current_func, "or.post"); 227 | LLVMMoveBasicBlockAfter(post_or, right_block); 228 | 229 | // Build the branch and right operand 230 | LLVMBuildCondBr(builder, left, post_or, right_block); 231 | LLVMPositionBuilderAtEnd(builder, right_block); 232 | env->current_block = right_block; 233 | env->local = push_llvm_scope(env->local); 234 | LLVMValueRef right = build_expression(sexpr->infix.right, builder, env); 235 | right_block = env->current_block; 236 | env->local = pop_llvm_scope(env->local); 237 | 238 | // Build phi 239 | LLVMBuildBr(builder, post_or); 240 | LLVMPositionBuilderAtEnd(builder, post_or); 241 | env->current_block = post_or; 242 | LLVMValueRef phi = LLVMBuildPhi(builder, LLVMInt1Type(), ""); 243 | LLVMValueRef incoming_values[] = {left, right}; 244 | LLVMBasicBlockRef incoming_blocks[] = {from, right_block}; 245 | LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); 246 | return phi; 247 | } 248 | 249 | default: 250 | return build_infix(sexpr, builder, env); 251 | } 252 | case CURLY_IR_TAGS_PREFIX: 253 | switch (sexpr->prefix.op) 254 | { 255 | case IR_BINOPS_NEG: 256 | { 257 | LLVMValueRef operand = build_expression(sexpr->prefix.operand, builder, env); 258 | if (sexpr->prefix.operand->type->type_type == IR_TYPES_PRIMITIVE && !strcmp(sexpr->prefix.operand->type->type_name, "Int")) 259 | return LLVMBuildNeg(builder, operand, ""); 260 | else return LLVMBuildFNeg(builder, operand, ""); 261 | } 262 | default: 263 | puts("Unsupported prefix operator!"); 264 | return NULL; 265 | } 266 | case CURLY_IR_TAGS_LOCAL_SCOPE: 267 | // Push local scope 268 | env->local = push_llvm_scope(env->local); 269 | 270 | // Build all the assignments 271 | for (size_t i = 0; i < sexpr->local_scope.assign_count; i++) 272 | { 273 | if (sexpr->local_scope.assigns[i]->tag == CURLY_IR_TAGS_ASSIGN) 274 | build_assignment(sexpr->local_scope.assigns[i], builder, env); 275 | } 276 | 277 | // Build the scope 278 | LLVMValueRef value = build_expression(sexpr->local_scope.value, builder, env); 279 | 280 | // Pop local scope 281 | env->local = pop_llvm_scope(env->local); 282 | return value; 283 | case CURLY_IR_TAGS_IF: 284 | { 285 | // Build condition 286 | LLVMValueRef cond = build_expression(sexpr->if_expr.cond, builder, env); 287 | 288 | // Create basic blocks to jump to 289 | LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(env->current_func, "if.then"); 290 | LLVMMoveBasicBlockAfter(then_block, env->current_block); 291 | LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(env->current_func, "if.else"); 292 | LLVMMoveBasicBlockAfter(else_block, then_block); 293 | LLVMBasicBlockRef post_if = LLVMAppendBasicBlock(env->current_func, "if.post"); 294 | LLVMMoveBasicBlockAfter(post_if, else_block); 295 | 296 | // Build the branch and then body 297 | LLVMBuildCondBr(builder, cond, then_block, else_block); 298 | LLVMPositionBuilderAtEnd(builder, then_block); 299 | env->current_block = then_block; 300 | env->local = push_llvm_scope(env->local); 301 | LLVMValueRef then_val = build_expression(sexpr->if_expr.then, builder, env); 302 | then_block = env->current_block; 303 | env->local = pop_llvm_scope(env->local); 304 | 305 | // Build the branch and else body 306 | LLVMBuildBr(builder, post_if); 307 | LLVMPositionBuilderAtEnd(builder, else_block); 308 | env->current_block = else_block; 309 | env->local = push_llvm_scope(env->local); 310 | LLVMValueRef else_val = build_expression(sexpr->if_expr.elsy, builder, env); 311 | else_block = env->current_block; 312 | env->local = pop_llvm_scope(env->local); 313 | 314 | // Build phi 315 | LLVMBuildBr(builder, post_if); 316 | LLVMPositionBuilderAtEnd(builder, post_if); 317 | env->current_block = post_if; 318 | LLVMValueRef phi = LLVMBuildPhi(builder, LLVMTypeOf(then_val), ""); 319 | LLVMValueRef incoming_values[] = {then_val, else_val}; 320 | LLVMBasicBlockRef incoming_blocks[] = {then_block, else_block}; 321 | LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); 322 | return phi; 323 | } 324 | default: 325 | puts("Unsupported S expression!"); 326 | return NULL; 327 | } 328 | } 329 | 330 | // llvm_save_value(llvm_codegen_env_t*, char*, LLVMValueRef, LLVMBuilderRef) -> LLVMValueRef 331 | // Saves a value as a global value, or a local if a local scope is present. 332 | LLVMValueRef llvm_save_value(llvm_codegen_env_t* env, char* name, LLVMValueRef value, LLVMBuilderRef builder) 333 | { 334 | // Set the global variable 335 | if (env->local == NULL) 336 | { 337 | // Get expression and global 338 | LLVMValueRef global = LLVMGetNamedGlobal(env->header_mod, name); 339 | size_t length = 0; 340 | 341 | // Create missing global 342 | if (global == NULL) 343 | { 344 | global = LLVMAddGlobal(env->header_mod, LLVMTypeOf(value), name); 345 | if (!strcmp(LLVMGetModuleIdentifier(env->header_mod, &length), "repl-header")) 346 | LLVMSetLinkage(global, LLVMExternalWeakLinkage); 347 | else 348 | { 349 | LLVMSetLinkage(global, LLVMCommonLinkage); 350 | LLVMSetInitializer(global, LLVMConstInt(LLVMInt64Type(), 0, false)); 351 | } 352 | } 353 | 354 | // Build store instruction 355 | LLVMBuildStore(builder, value, global); 356 | return value; 357 | } else 358 | { 359 | map_add(env->local->variables, name, value); 360 | return value; 361 | } 362 | } 363 | 364 | // build_assignment(ir_sexpr_t*, LLVMBuilderRef, llvm_codegen_env_t*) -> LLVMValueRef 365 | // Builds an assignment to LLVM IR. 366 | LLVMValueRef build_assignment(ir_sexpr_t* sexpr, LLVMBuilderRef builder, llvm_codegen_env_t* env) 367 | { 368 | LLVMValueRef value = build_expression(sexpr->assign.value, builder, env); 369 | return llvm_save_value(env, sexpr->assign.name, value, builder); 370 | 371 | // // var = expr and var: type = expr 372 | // char* name = NULL; 373 | // if (ast->children[0]->value.type == LEX_TYPE_SYMBOL && ast->children[0]->children_count == 0) 374 | // name = ast->children[0]->value.value; 375 | // else if (ast->children[0]->value.type == LEX_TYPE_COLON) 376 | // name = ast->children[0]->children[0]->value.value; 377 | 378 | // // New variable (typed or untyped) 379 | // if (name != NULL) 380 | // { 381 | // LLVMValueRef value = build_expression(ast->children[1], builder, env); 382 | // llvm_save_value(env, name, value, builder); 383 | 384 | // // Functions 385 | // } else if (ast->children[0]->value.type == LEX_TYPE_SYMBOL && ast->children[0]->children_count > 0) 386 | // { 387 | // // Create the function 388 | // LLVMTypeRef func_app_type = LLVMGetTypeByName(env->header_mod, "func.app.type"); 389 | // LLVMTypeRef func_app_ptr_type = LLVMPointerType(func_app_type, 0); 390 | // LLVMTypeRef func_type = LLVMFunctionType(func_app_ptr_type, (LLVMTypeRef[]) {func_app_ptr_type}, 1, false); 391 | // char* func_name = malloc(strlen(ast->children[0]->value.value) + 6); 392 | // func_name[0] = '\0'; 393 | // strcat(func_name, ast->children[0]->value.value); 394 | // strcat(func_name, ".func"); 395 | // LLVMValueRef func = LLVMAddFunction(env->header_mod, func_name, func_type); 396 | // free(func_name); 397 | 398 | // // Save state and move builder to the start of the function 399 | // LLVMBasicBlockRef last_block = env->current_block; 400 | // LLVMValueRef last_func = env->current_func; 401 | // LLVMBasicBlockRef entry = LLVMAppendBasicBlock(func, "entry"); 402 | // env->current_func = func; 403 | // env->current_block = entry; 404 | // LLVMPositionBuilderAtEnd(builder, entry); 405 | 406 | // // Check for argument count 407 | // LLVMValueRef app_arg = LLVMGetParam(func, 0); 408 | // LLVMSetValueName2(app_arg, ".app", 4); 409 | // LLVMValueRef argc_ptr = LLVMBuildStructGEP2(builder, func_app_type, app_arg, 2, "argc-ptr"); 410 | // LLVMValueRef argc = LLVMBuildLoad2(builder, LLVMInt8Type(), argc_ptr, "argc"); 411 | // uint8_t arity = ast->children[0]->children_count; 412 | // LLVMValueRef arity_val = LLVMConstInt(LLVMInt8Type(), arity, false); 413 | // LLVMValueRef cond = LLVMBuildICmp(builder, LLVMIntULT, argc, arity_val, ""); 414 | 415 | // // Build branch 416 | // LLVMBasicBlockRef ret = LLVMAppendBasicBlock(func, "return"); 417 | // LLVMBasicBlockRef cont = LLVMAppendBasicBlock(func, "continue"); 418 | // LLVMBuildCondBr(builder, cond, ret, cont); 419 | 420 | // // Return from the function 421 | // LLVMPositionBuilderAtEnd(builder, ret); 422 | // LLVMBuildRet(builder, app_arg); 423 | 424 | // // Build arguments 425 | // LLVMPositionBuilderAtEnd(builder, cont); 426 | // LLVMValueRef args = LLVMBuildStructGEP2(builder, func_app_type, app_arg, 4, "args"); 427 | // env->local = push_llvm_scope(env->local); 428 | // env->current_block = cont; 429 | // for (uint8_t i = 0; i < arity; i++) 430 | // { 431 | // LLVMValueRef arg = LLVMBuildGEP2(builder, func_app_type, args, (LLVMValueRef[]) {LLVMConstInt(LLVMInt8Type(), i, false)}, 1, ""); 432 | // if (ast->children[0]->children[i]->type->type_type != IR_TYPES_FUNC) 433 | // { 434 | // arg = LLVMBuildStructGEP2(builder, func_app_type, arg, 0, ""); 435 | // arg = LLVMBuildBitCast(builder, arg, LLVMPointerType(internal_type_to_llvm(env, ast->children[0]->children[i]), 0), ""); 436 | // } 437 | // char* arg_name = ast->children[0]->children[i]->children[0]->value.value; 438 | // LLVMSetValueName2(arg, arg_name, strlen(arg_name)); 439 | // set_llvm_param(env, arg_name, arg, i); 440 | // } 441 | 442 | // // Create the function 443 | // LLVMValueRef ret_val = build_expression(ast->children[1], builder, env); 444 | 445 | // // Return from function 446 | // LLVMBuildRet(builder, ret_val); 447 | // env->current_func = last_func; 448 | // env->current_block = last_block; 449 | // LLVMPositionBuilderAtEnd(builder, env->current_block); 450 | // env->local = pop_llvm_scope(env->local); 451 | 452 | // // Build a function application structure 453 | // LLVMValueRef func_alloca = LLVMBuildAlloca(builder, func_app_type, ""); 454 | // LLVMValueRef ref_count = LLVMBuildStructGEP(builder, func_alloca, 0, ".ref.count"); 455 | // LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 1, false), ref_count); 456 | // LLVMValueRef func_ptr = LLVMBuildStructGEP(builder, func_alloca, 1, ".func"); 457 | // LLVMBuildStore(builder, func, func_ptr); 458 | // LLVMValueRef count_ptr = LLVMBuildStructGEP(builder, func_alloca, 2, ".arg.count"); 459 | // LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 0, false), count_ptr); 460 | // LLVMValueRef thunk_bitmap_ptr = LLVMBuildStructGEP(builder, func_alloca, 3, ".thunk.bitmap"); 461 | // LLVMBuildStore(builder, LLVMConstInt(LLVMInt64Type(), 0, false), thunk_bitmap_ptr); 462 | // LLVMValueRef args_ptr_ptr = LLVMBuildStructGEP(builder, func_alloca, 4, ".args"); 463 | // LLVMBuildStore(builder, LLVMConstInt(LLVMInt64Type(), 0, false), args_ptr_ptr); 464 | 465 | // // Save the function application 466 | // LLVMValueRef func_val = LLVMBuildLoad2(builder, func_app_type, func_alloca, ""); 467 | // llvm_save_value(env, ast->children[0]->value.value, func_val, builder); 468 | // // del_hashmap(closed_locals); 469 | // return func_val; 470 | // } 471 | 472 | // return NULL; 473 | } 474 | 475 | // generate_code(curly_ir_t, llvm_codegen_env_t*) -> llvm_codegen_env_t* 476 | // Generates llvm ir code from an ast. 477 | llvm_codegen_env_t* generate_code(curly_ir_t ir, llvm_codegen_env_t* env) 478 | { 479 | LLVMContextRef context; 480 | bool repl_mode = env != NULL; 481 | if (!repl_mode) 482 | { 483 | // Create the main module 484 | context = LLVMContextCreate(); 485 | LLVMModuleRef main_mod = LLVMModuleCreateWithNameInContext("file", context); 486 | env = create_llvm_codegen_environment(main_mod); 487 | env->body_mod = main_mod; 488 | } else 489 | { 490 | // Create the executed module for repl 491 | context = LLVMGetModuleContext(env->header_mod); 492 | env->body_mod = LLVMModuleCreateWithNameInContext("stdin", context); 493 | 494 | // Create the repl variable 495 | LLVMValueRef repl_last = LLVMGetNamedGlobal(env->header_mod, "repl.last"); 496 | if (repl_last != NULL) LLVMDeleteGlobal(repl_last); 497 | LLVMTypeRef repl_last_type = internal_type_to_llvm(env, ir.expr[ir.expr_count - 1]->type); 498 | repl_last = LLVMAddGlobal(env->header_mod, repl_last_type, "repl.last"); 499 | LLVMSetLinkage(repl_last, LLVMExternalWeakLinkage); 500 | } 501 | 502 | // Create the main function 503 | LLVMTypeRef main_type = LLVMFunctionType(LLVMVoidType(), (LLVMTypeRef[]) {}, 0, false); 504 | env->main_func = LLVMAddFunction(env->body_mod, "main", main_type); 505 | env->current_func = env->main_func; 506 | 507 | // Create the entry basic block 508 | env->current_block = LLVMAppendBasicBlock(env->current_func, "entry"); 509 | LLVMBuilderRef builder = LLVMCreateBuilderInContext(context); 510 | LLVMPositionBuilderAtEnd(builder, env->current_block); 511 | 512 | // Iterate over every element of the topmost parent and build 513 | LLVMValueRef value = NULL; 514 | for (size_t i = 0; i < ir.expr_count; i++) 515 | { 516 | if (ir.expr[i]->tag == CURLY_IR_TAGS_ASSIGN) 517 | value = build_assignment(ir.expr[i], builder, env); 518 | else if (ir.expr[i]->tag != CURLY_IR_TAGS_DECLARE) 519 | value = build_expression(ir.expr[i], builder, env); 520 | } 521 | 522 | // If in repl mode, save the last value 523 | if (repl_mode) 524 | LLVMBuildStore(builder, value, LLVMGetNamedGlobal(env->header_mod, "repl.last")); 525 | 526 | // Create a return instruction 527 | LLVMBuildRetVoid(builder); 528 | LLVMDisposeBuilder(builder); 529 | return env; 530 | } 531 | -------------------------------------------------------------------------------- /src/compiler/backends/llvm/codegen.h: -------------------------------------------------------------------------------- 1 | // 2 | // Curly 3 | // codegen.h: Header file for codegen.c. 4 | // 5 | // Created by jenra. 6 | // Created on September 7 2020. 7 | // 8 | 9 | #ifndef LLVM_CODEGEN_H 10 | #define LLVM_CODEGEN_H 11 | 12 | #include 13 | 14 | #include "environment.h" 15 | #include "../../frontend/ir/generate_ir.h" 16 | 17 | // generate_code(curly_ir_t, llvm_codegen_env_t*) -> llvm_codegen_env_t* 18 | // Generates llvm ir code from an ast. 19 | llvm_codegen_env_t* generate_code(curly_ir_t ir, llvm_codegen_env_t* env); 20 | 21 | #endif /* LLVM_CODEGEN_H */ 22 | -------------------------------------------------------------------------------- /src/compiler/backends/llvm/environment.c: -------------------------------------------------------------------------------- 1 | // 2 | // llvm 3 | // environment.c: Creates an environment for LLVM IR codegen. 4 | // 5 | // Created by jenra. 6 | // Created on September 29 2020. 7 | // 8 | 9 | #include "environment.h" 10 | 11 | // push_llvm_scope(llvm_scope_t*) -> llvm_scope_t* 12 | // Pushes an LLVM scope onto the stack of scopes. 13 | llvm_scope_t* push_llvm_scope(llvm_scope_t* parent) 14 | { 15 | llvm_scope_t* scope = malloc(sizeof(llvm_scope_t)); 16 | scope->parent = parent; 17 | scope->variables = init_hashmap(); 18 | scope->parameters = init_hashmap(); 19 | return scope; 20 | } 21 | 22 | // pop_llvm_scope(llvm_scope_t*) -> llvm_scope_t* 23 | // Pops an LLVM scope onto the stack of scopes. 24 | llvm_scope_t* pop_llvm_scope(llvm_scope_t* scope) 25 | { 26 | llvm_scope_t* parent = scope->parent; 27 | del_hashmap(scope->variables); 28 | del_hashmap(scope->parameters); 29 | free(scope); 30 | return parent; 31 | } 32 | 33 | // create_llvm_codegen_environment(LLVMModuleRef) -> llvm_codegen_env_t* 34 | // Creates an LLVM codegen environment. 35 | llvm_codegen_env_t* create_llvm_codegen_environment(LLVMModuleRef header_mod) 36 | { 37 | llvm_codegen_env_t* env = malloc(sizeof(llvm_codegen_env_t)); 38 | env->local = NULL; 39 | env->header_mod = header_mod; 40 | env->body_mod = NULL; 41 | env->main_func = NULL; 42 | env->current_func = NULL; 43 | env->current_block = NULL; 44 | 45 | // Create necessary types 46 | if (LLVMGetTypeByName(header_mod, "func.app.type") == NULL) 47 | { 48 | // Function application structure 49 | // typedef struct s_func_app 50 | // { 51 | // union 52 | // { 53 | // int32_t reference_count; 54 | // int64_t i64; 55 | // double f64; 56 | // }; 57 | // 58 | // void* func; 59 | // int8_t count; 60 | // int64_t thunk_bitmap; 61 | // struct s_func_app* args; 62 | // } func_app_t; 63 | LLVMContextRef context = LLVMGetModuleContext(header_mod); 64 | LLVMTypeRef func_app = LLVMStructCreateNamed(context, "func.app.type"); 65 | LLVMTypeRef func_app_body[] = {LLVMInt32Type(), LLVMPointerType(LLVMInt64Type(), 0), LLVMInt8Type(), LLVMInt8Type(), LLVMInt64Type(), LLVMPointerType(func_app, 0)}; 66 | LLVMStructSetBody(func_app, func_app_body, 6, false); 67 | } 68 | return env; 69 | } 70 | 71 | // set_llvm_local(llvm_codegen_env_t*, char*, LLVMValueRef) -> void 72 | // Sets a local to the scope. 73 | void set_llvm_local(llvm_codegen_env_t* env, char* local, LLVMValueRef value) 74 | { 75 | if (env->local != NULL) 76 | map_add(env->local->variables, local, value); 77 | } 78 | 79 | // set_llvm_param(llvm_codegen_env_t*, char*, LLVMValueRef) -> void 80 | // Sets a parameter to the scope. 81 | void set_llvm_param(llvm_codegen_env_t* env, char* local, LLVMValueRef value, uint8_t param_index) 82 | { 83 | if (env->local != NULL) 84 | { 85 | map_add(env->local->variables, local, value); 86 | map_add(env->local->parameters, local, (void*) (uint64_t) param_index); 87 | } 88 | } 89 | 90 | // lookup_llvm_local(llvm_codegen_env_t*, char*) -> LLVMValueRef 91 | // Looks up a local and returns its LLVMValueRef if available. 92 | LLVMValueRef lookup_llvm_local(llvm_codegen_env_t* env, char* local) 93 | { 94 | // Get most local scope 95 | llvm_scope_t* scope = env->local; 96 | 97 | // Iterate over all scopes in the linked list 98 | while (scope != NULL) 99 | { 100 | // Get the value 101 | LLVMValueRef value = map_get(scope->variables, local); 102 | if (value != NULL) 103 | return value; 104 | 105 | // Parent scope 106 | scope = scope->parent; 107 | } 108 | 109 | // Local not found 110 | return NULL; 111 | } 112 | 113 | // lookup_llvm_param(llvm_codegen_env_t*, char*) -> uint64_t 114 | // Looks up a parameter and returns its parameter index if available. 115 | uint64_t lookup_llvm_param(llvm_codegen_env_t* env, char* local) 116 | { 117 | // Get most local scope 118 | llvm_scope_t* scope = env->local; 119 | 120 | // Iterate over all scopes in the linked list 121 | while (scope != NULL) 122 | { 123 | // Get the parameter index 124 | if (map_contains(scope->parameters, local)) 125 | return (uint64_t) map_get(scope->parameters, local); 126 | 127 | // Parent scope 128 | scope = scope->parent; 129 | } 130 | 131 | // Parameter not found 132 | return (uint64_t) -1; 133 | } 134 | 135 | // empty_llvm_codegen_environment(llvm_codegen_env_t*) -> void 136 | // Emptys an LLVM codegen environment for reuse. 137 | void empty_llvm_codegen_environment(llvm_codegen_env_t* env) 138 | { 139 | while (env->local != NULL) 140 | { 141 | env->local = pop_llvm_scope(env->local); 142 | } 143 | env->body_mod = NULL; 144 | env->main_func = NULL; 145 | env->current_func = NULL; 146 | env->current_block = NULL; 147 | } 148 | 149 | // clean_llvm_codegen_environment(llvm_codegen_env_t) 150 | // Cleans an LLVM codegen environment. 151 | void clean_llvm_codegen_environment(llvm_codegen_env_t* env) 152 | { 153 | if (env->header_mod != NULL && env->header_mod != env->body_mod) 154 | LLVMDisposeModule(env->header_mod); 155 | while (env->local != NULL) 156 | { 157 | env->local = pop_llvm_scope(env->local); 158 | } 159 | free(env); 160 | } 161 | -------------------------------------------------------------------------------- /src/compiler/backends/llvm/environment.h: -------------------------------------------------------------------------------- 1 | // 2 | // llvm 3 | // environment.h: Header file for environment.c. 4 | // 5 | // Created by jenra. 6 | // Created on September 29 2020. 7 | // 8 | 9 | #ifndef LLVM_ENVIRONMENT_H 10 | #define LLVM_ENVIRONMENT_H 11 | 12 | #include "llvm-c/Core.h" 13 | 14 | #include "../../../utils/hashmap.h" 15 | 16 | // Represents a scope 17 | typedef struct s_llvm_scope 18 | { 19 | hashmap_t* variables; 20 | 21 | hashmap_t* parameters; 22 | 23 | struct s_llvm_scope* parent; 24 | } llvm_scope_t; 25 | 26 | typedef struct 27 | { 28 | llvm_scope_t* local; 29 | 30 | LLVMModuleRef header_mod; 31 | 32 | LLVMModuleRef body_mod; 33 | 34 | LLVMValueRef main_func; 35 | 36 | LLVMValueRef current_func; 37 | 38 | LLVMBasicBlockRef current_block; 39 | } llvm_codegen_env_t; 40 | 41 | // push_llvm_scope(llvm_scope_t*) -> llvm_scope_t* 42 | // Pushes an LLVM scope onto the stack of scopes. 43 | llvm_scope_t* push_llvm_scope(llvm_scope_t* parent); 44 | 45 | // pop_llvm_scope(llvm_scope_t*) -> llvm_scope_t* 46 | // Pops an LLVM scope onto the stack of scopes. 47 | llvm_scope_t* pop_llvm_scope(llvm_scope_t* scope); 48 | 49 | // create_llvm_codegen_environment(LLVMModuleRef) -> llvm_codegen_env_t* 50 | // Creates an LLVM codegen environment. 51 | llvm_codegen_env_t* create_llvm_codegen_environment(LLVMModuleRef header_mod); 52 | 53 | // set_llvm_local(llvm_codegen_env_t*, char*, LLVMValueRef) -> void 54 | // Sets a local to the scope. 55 | void set_llvm_local(llvm_codegen_env_t* env, char* local, LLVMValueRef value); 56 | 57 | // set_llvm_param(llvm_codegen_env_t*, char*, LLVMValueRef) -> void 58 | // Sets a parameter to the scope. 59 | void set_llvm_param(llvm_codegen_env_t* env, char* local, LLVMValueRef value, uint8_t param_index); 60 | 61 | // lookup_llvm_local(llvm_codegen_env_t*, char*) -> LLVMValueRef 62 | // Looks up a local and returns its LLVMValueRef if available. 63 | LLVMValueRef lookup_llvm_local(llvm_codegen_env_t* env, char* local); 64 | 65 | // lookup_llvm_param(llvm_codegen_env_t*, char*) -> uint64_t 66 | // Looks up a parameter and returns its parameter index if available. 67 | uint64_t lookup_llvm_param(llvm_codegen_env_t* env, char* local); 68 | 69 | // empty_llvm_codegen_environment(llvm_codegen_env_t*) -> void 70 | // Emptys an LLVM codegen environment for reuse. 71 | void empty_llvm_codegen_environment(llvm_codegen_env_t* env); 72 | 73 | // clean_llvm_codegen_environment(llvm_codegen_env_t) 74 | // Cleans an LLVM codegen environment. 75 | void clean_llvm_codegen_environment(llvm_codegen_env_t* env); 76 | 77 | #endif /* LLVM_ENVIRONMENT_H */ 78 | -------------------------------------------------------------------------------- /src/compiler/backends/llvm/functions.c: -------------------------------------------------------------------------------- 1 | // 2 | // llvm 3 | // functions.c: Implements helper functions for creating functions. 4 | // 5 | // Created by jenra. 6 | // Created on October 2 2020. 7 | // 8 | 9 | #include 10 | 11 | #include "functions.h" 12 | 13 | // find_llvm_closure_locals(llvm_codegen_env_t*, ast_t*, hashmap_t*) -> void 14 | // Finds all locals the function closes over and adds them to the hash of closed locals. 15 | void find_llvm_closure_locals(llvm_codegen_env_t* env, ast_t* body, hashmap_t* closed_locals) 16 | { 17 | if (body->value.tag == LEX_TAG_OPERAND) 18 | { 19 | // Local is closed from above scope 20 | LLVMValueRef value = lookup_llvm_local(env, body->value.value); 21 | if (body->value.type == LEX_TYPE_SYMBOL && value != NULL) 22 | map_add(closed_locals, body->value.value, value); 23 | } else if (!strcmp(body->value.value, "with")) 24 | { 25 | // Create a new scope 26 | env->local = push_llvm_scope(env->local); 27 | 28 | // Push variables 29 | for (size_t i = 0; i < body->children_count - 1; i++) 30 | { 31 | // Get name 32 | char* name = NULL; 33 | ast_t* ast = body->children[i]; 34 | if (ast->children[0]->value.type == LEX_TYPE_SYMBOL) 35 | name = ast->children[0]->value.value; 36 | else if (ast->children[0]->value.type == LEX_TYPE_COLON) 37 | name = ast->children[0]->children[0]->value.value; 38 | 39 | // Set local 40 | set_llvm_local(env, name, NULL); 41 | 42 | // Set arguments if applicable 43 | if (ast->children[0]->value.type == LEX_TYPE_SYMBOL && ast->children[0]->children_count != 0) 44 | { 45 | for (size_t i = 0; i < ast->children[0]->children_count; i++) 46 | { 47 | ast_t* arg = ast->children[0]->children[i]; 48 | if (arg->value.type == LEX_TYPE_COLON) 49 | { 50 | set_llvm_local(env, arg->children[0]->value.value, NULL); 51 | } 52 | } 53 | } 54 | 55 | // Check value of the assignment 56 | if (ast->value.type == LEX_TYPE_ASSIGN) 57 | find_llvm_closure_locals(env, ast->children[1], closed_locals); 58 | } 59 | 60 | // Check value of scope 61 | find_llvm_closure_locals(env, body->children[body->children_count - 1], closed_locals); 62 | 63 | // Pop scope 64 | env->local = pop_llvm_scope(env->local); 65 | } else 66 | { 67 | // Find locals closed over in child nodes 68 | for (size_t i = 0; i < body->children_count; i++) 69 | { 70 | find_llvm_closure_locals(env, body->children[i], closed_locals); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/compiler/backends/llvm/functions.h: -------------------------------------------------------------------------------- 1 | // 2 | // llvm 3 | // functions.h: Header file for functions.c. 4 | // 5 | // Created by jenra. 6 | // Created on October 2 2020. 7 | // 8 | 9 | #ifndef LLVM_FUNCTIONS_H 10 | #define LLVM_FUNCTIONS_H 11 | 12 | #include 13 | 14 | #include "../../frontend/parse/ast.h" 15 | #include "../../../utils/hashmap.h" 16 | #include "environment.h" 17 | 18 | // find_llvm_closure_locals(llvm_codegen_env_t*, ast_t*, hashmap_t*) -> void 19 | // Finds all locals the function closes over and adds them to the hash of closed locals. 20 | void find_llvm_closure_locals(llvm_codegen_env_t* env, ast_t* body, hashmap_t* closed_locals); 21 | 22 | #endif /* LLVM_FUNCTIONS_H */ 23 | -------------------------------------------------------------------------------- /src/compiler/backends/llvm/llvm_types.c: -------------------------------------------------------------------------------- 1 | // 2 | // llvm 3 | // llvm_types.c: Defines a function for converting internal types to LLVM IR types. 4 | // 5 | // Created by jenra. 6 | // Created on September 29 2020. 7 | // 8 | 9 | #include 10 | 11 | #include "llvm_types.h" 12 | 13 | // internal_type_to_llvm(llvm_codegen_env_t*, type_t*) -> LLVMTypeRef 14 | // Converts an internal type into an LLVM IR type. 15 | LLVMTypeRef internal_type_to_llvm(llvm_codegen_env_t* env, type_t* type) 16 | { 17 | if (type->type_type == IR_TYPES_PRIMITIVE && !strcmp(type->type_name, "Int")) 18 | return LLVMInt64Type(); 19 | else if (type->type_type == IR_TYPES_PRIMITIVE && !strcmp(type->type_name, "Float")) 20 | return LLVMDoubleType(); 21 | else if (type->type_type == IR_TYPES_PRIMITIVE && !strcmp(type->type_name, "Bool")) 22 | return LLVMInt1Type(); 23 | else if (type->type_type == IR_TYPES_FUNC) 24 | return LLVMGetTypeByName(env->header_mod, "func.app.type"); 25 | else return LLVMVoidType(); 26 | } 27 | -------------------------------------------------------------------------------- /src/compiler/backends/llvm/llvm_types.h: -------------------------------------------------------------------------------- 1 | // 2 | // llvm 3 | // llvm_types.h: Header file for llvm_types.c. 4 | // 5 | // Created by jenra. 6 | // Created on September 29 2020. 7 | // 8 | 9 | #ifndef LLVM_TYPES_H 10 | #define LLVM_TYPES_H 11 | 12 | #include 13 | 14 | #include "../../frontend/parse/ast.h" 15 | #include "environment.h" 16 | 17 | // internal_type_to_llvm(llvm_codegen_env_t*, type_t*) -> LLVMTypeRef 18 | // Converts an internal type into an LLVM IR type. 19 | LLVMTypeRef internal_type_to_llvm(llvm_codegen_env_t* env, type_t* type); 20 | 21 | #endif /* LLVM_TYPES_H */ 22 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/check.c: -------------------------------------------------------------------------------- 1 | // 2 | // correctness 3 | // check.c: Checks if an ast is semantically valid. 4 | // 5 | // Created by jenra. 6 | // Created on August 29 2020. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "../../../utils/list.h" 13 | #include "check.h" 14 | #include "type_generators.h" 15 | 16 | // check_correctness_helper(ast_t*, ir_scope_t* /*, bool, bool*/) -> void 17 | // Helper function for check_correctness. 18 | bool check_correctness_helper(ir_sexpr_t* sexpr, ir_scope_t* scope /*, bool get_real_type, bool disable_new_vars*/) 19 | { 20 | // Match the sum type 21 | switch (sexpr->tag) 22 | { 23 | case CURLY_IR_TAGS_INT: 24 | sexpr->type = scope_lookup_type(scope, "Int"); 25 | return true; 26 | case CURLY_IR_TAGS_FLOAT: 27 | sexpr->type = scope_lookup_type(scope, "Float"); 28 | return true; 29 | case CURLY_IR_TAGS_BOOL: 30 | sexpr->type = scope_lookup_type(scope, "Bool"); 31 | return true; 32 | case CURLY_IR_TAGS_SYMBOL: 33 | // Get type from variable list 34 | sexpr->type = scope_lookup_var_type(scope, sexpr->symbol); 35 | 36 | // If variable isn't found, report an error 37 | if (sexpr->type == NULL) 38 | printf("Undeclared variable %s found at %i:%i\n", sexpr->symbol, sexpr->lino, sexpr->charpos); 39 | return sexpr->type != NULL; 40 | 41 | case CURLY_IR_TAGS_ASSIGN: 42 | // Check value 43 | if (!check_correctness_helper(sexpr->assign.value, scope)) 44 | return false; 45 | 46 | // Check type doesn't change on reassignment 47 | type_t* type = map_get(scope->var_types, sexpr->assign.name); 48 | if (type != NULL && !type_subtype(type, sexpr->assign.value->type)) 49 | { 50 | printf("Assigning incompatible type to %s found at %i:%i\n", sexpr->assign.name, sexpr->lino, sexpr->charpos); 51 | return false; 52 | } else sexpr->type = type; 53 | 54 | // Assert the type is empty or matches 55 | if (sexpr->type == NULL) 56 | sexpr->type = sexpr->assign.value->type; 57 | else if (!type_subtype(sexpr->type, sexpr->assign.value->type)) 58 | { 59 | printf("Assigning incompatible type to %s found at %i:%i\n", sexpr->assign.name, sexpr->lino, sexpr->charpos); 60 | return false; 61 | } 62 | 63 | // Add the value and return 64 | map_add(scope->var_types, sexpr->assign.name, sexpr->type); 65 | map_add(scope->var_vals, sexpr->assign.name, sexpr->assign.value); 66 | return true; 67 | 68 | case CURLY_IR_TAGS_DECLARE: 69 | map_add(scope->var_types, sexpr->declare.name, sexpr->type); 70 | return true; 71 | 72 | case CURLY_IR_TAGS_LOCAL_SCOPE: 73 | // Create a new scope 74 | scope = push_scope(scope); 75 | 76 | // Deal with assignments 77 | for (size_t i = 0; i < sexpr->local_scope.assign_count; i++) 78 | { 79 | if (!check_correctness_helper(sexpr->local_scope.assigns[i], scope)) 80 | return false; 81 | } 82 | 83 | // Deal with the expression 84 | if (!check_correctness_helper(sexpr->local_scope.value, scope)) 85 | return false; 86 | 87 | // Pop scope and set the type 88 | scope = pop_scope(scope); 89 | sexpr->type = sexpr->local_scope.value->type; 90 | return true; 91 | 92 | case CURLY_IR_TAGS_IF: 93 | // Check that the condition is a boolean 94 | if (!check_correctness_helper(sexpr->if_expr.cond, scope)) 95 | return false; 96 | if (!types_equal(sexpr->if_expr.cond->type, scope_lookup_type(scope, "Bool"))) 97 | { 98 | printf("Nonboolean condition found at %i:%i\n", sexpr->if_expr.cond->lino, sexpr->if_expr.cond->charpos); 99 | return false; 100 | } 101 | 102 | // Check the then clause 103 | if (!check_correctness_helper(sexpr->if_expr.then, scope)) 104 | return false; 105 | sexpr->type = sexpr->if_expr.then->type; 106 | 107 | // Check the else clause 108 | if (!check_correctness_helper(sexpr->if_expr.elsy, scope)) 109 | return false; 110 | 111 | // Else clause should have the same type as the body 112 | if (!types_equal(sexpr->type, sexpr->if_expr.elsy->type)) 113 | { 114 | printf("If statement with different types for bodies at %i:%i\n", sexpr->lino, sexpr->charpos); 115 | return false; 116 | } 117 | 118 | // Return successfully 119 | return true; 120 | 121 | case CURLY_IR_TAGS_INFIX: 122 | switch (sexpr->infix.op) 123 | { 124 | case IR_BINOPS_CMPIN: 125 | // Check the operands 126 | if (!check_correctness_helper(sexpr->infix.right, scope)) 127 | return false; 128 | 129 | // Assert that the second operand is an iterator 130 | if (sexpr->infix.right->type->type_type != IR_TYPES_LIST && sexpr->infix.right->type->type_type != IR_TYPES_GENERATOR) 131 | { 132 | printf("Noniterator used in in expression found at %i:%i\n", sexpr->infix.right->lino, sexpr->infix.right->charpos); 133 | return false; 134 | } 135 | 136 | // Assert the type makes sense 137 | if (!types_equal(sexpr->infix.left->type, sexpr->infix.right->type->field_types[0])) 138 | { 139 | printf("Mismatched types found at %i:%i", sexpr->lino, sexpr->charpos); 140 | return false; 141 | } 142 | sexpr->type = scope_lookup_type(scope, "Bool"); 143 | return true; 144 | 145 | case IR_BINOPS_CMPEQ: 146 | case IR_BINOPS_CMPNEQ: 147 | case IR_BINOPS_CMPGT: 148 | case IR_BINOPS_CMPGTE: 149 | case IR_BINOPS_CMPLT: 150 | case IR_BINOPS_CMPLTE: 151 | // Check the operands 152 | if (!check_correctness_helper(sexpr->infix.left, scope)) 153 | return false; 154 | if (!check_correctness_helper(sexpr->infix.right, scope)) 155 | return false; 156 | 157 | // Set the type of the s expression to bool and return success 158 | sexpr->type = scope_lookup_type(scope, "Bool"); 159 | return true; 160 | 161 | case IR_BINOPS_BOOLAND: 162 | case IR_BINOPS_BOOLOR: 163 | case IR_BINOPS_BOOLXOR: 164 | { 165 | // Check the operands 166 | if (!check_correctness_helper(sexpr->infix.left, scope)) 167 | return false; 168 | if (!check_correctness_helper(sexpr->infix.right, scope)) 169 | return false; 170 | 171 | // Assert that both operands are booleans 172 | type_t* boolean = scope_lookup_type(scope, "Bool"); 173 | if (!types_equal(sexpr->infix.left->type, boolean)) 174 | { 175 | printf("Nonboolean used for logical expression found at %i:%i\n", sexpr->infix.left->lino, sexpr->infix.left->charpos); 176 | return false; 177 | } else if (!types_equal(sexpr->infix.right->type, boolean)) 178 | { 179 | printf("Nonboolean used for logical expression found at %i:%i\n", sexpr->infix.right->lino, sexpr->infix.right->charpos); 180 | return false; 181 | } 182 | 183 | // Set the type and return success 184 | sexpr->type = boolean; 185 | return true; 186 | } 187 | 188 | default: 189 | // Check the operands 190 | if (!check_correctness_helper(sexpr->infix.left, scope)) 191 | return false; 192 | if (!check_correctness_helper(sexpr->infix.right, scope)) 193 | return false; 194 | 195 | // Find the type of the resulting infix expression 196 | sexpr->type = scope_lookup_infix(scope, sexpr->infix.op, sexpr->infix.left->type, sexpr->infix.right->type); 197 | if (sexpr->type == NULL) 198 | { 199 | printf("Undefined infix operator found at %i:%i\n", sexpr->lino, sexpr->charpos); 200 | return false; 201 | } 202 | return true; 203 | } 204 | 205 | case CURLY_IR_TAGS_PREFIX: 206 | switch (sexpr->prefix.op) 207 | { 208 | case IR_BINOPS_SPAN: 209 | // Check the child node 210 | if (!check_correctness_helper(sexpr->prefix.operand, scope)) 211 | return false; 212 | 213 | // Assert the type is a list or generator 214 | if (sexpr->prefix.operand->type->type_type != IR_TYPES_PRODUCT) 215 | { 216 | printf("Curry on invalid operand found at %i:%i\n", sexpr->lino, sexpr->charpos); 217 | return false; 218 | } 219 | 220 | // Create the type and return success 221 | sexpr->type = init_type(IR_TYPES_CURRY, NULL, sexpr->prefix.operand->type->field_count); 222 | for (size_t i = 0; i < sexpr->type->field_count; i++) 223 | { 224 | sexpr->type->field_types[i] = sexpr->prefix.operand->type->field_types[i]; 225 | } 226 | return true; 227 | case IR_BINOPS_NEG: 228 | // Check the operand 229 | if (!check_correctness_helper(sexpr->prefix.operand, scope)) 230 | return false; 231 | 232 | // Find the type of the resulting prefix expression 233 | sexpr->type = scope_lookup_prefix(scope, sexpr->prefix.operand->type); 234 | if (sexpr->type == NULL) 235 | { 236 | printf("Negative sign on invalid operand found at %i:%i\n", sexpr->lino, sexpr->charpos); 237 | return false; 238 | } 239 | return true; 240 | default: 241 | printf("Unsupported prefix operator found at %i:%i\n", sexpr->lino, sexpr->charpos); 242 | return false; 243 | } 244 | 245 | default: 246 | printf("Unsupported s expression found at %i:%i\n", sexpr->lino, sexpr->charpos); 247 | return false; 248 | } 249 | } 250 | 251 | // check_correctness(curly_ir_t, ir_scope_t*) -> void 252 | // Checks the correctness of IR. 253 | bool check_correctness(curly_ir_t ir, ir_scope_t* scope) 254 | { 255 | // Create global scope 256 | bool temp_scope = scope == NULL; 257 | if (temp_scope) 258 | scope = push_scope(NULL); 259 | create_primatives(scope); 260 | 261 | // Iterate over every root S expression 262 | for (size_t i = 0; i < ir.expr_count; i++) 263 | { 264 | // Check the S expression 265 | if (!check_correctness_helper(ir.expr[i], scope)) 266 | { 267 | // Pop scopes if failed 268 | while (scope->parent != NULL) 269 | { 270 | scope = pop_scope(scope); 271 | } 272 | if (temp_scope) 273 | pop_scope(scope); 274 | return false; 275 | } 276 | } 277 | 278 | // Pop scopes and return success 279 | if (temp_scope) 280 | pop_scope(scope); 281 | return true; 282 | } 283 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/check.h: -------------------------------------------------------------------------------- 1 | // 2 | // correctness 3 | // check.h: Header file for check.c. 4 | // 5 | // Created by jenra. 6 | // Created on August 29 2020. 7 | // 8 | 9 | #ifndef CHECK_H 10 | #define CHECK_H 11 | 12 | #include "../ir/generate_ir.h" 13 | #include "scope.h" 14 | 15 | // check_correctness(curly_ir_t, ir_scope_t*) -> void 16 | // Checks the correctness of IR. 17 | bool check_correctness(curly_ir_t ir, ir_scope_t* scope); 18 | 19 | #endif /* CHECK_H */ 20 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/check_helper.h: -------------------------------------------------------------------------------- 1 | // 2 | // correctness 3 | // check_helper.h: Header file for check.c. 4 | // 5 | // Created by jenra. 6 | // Created on September 5 2020. 7 | // 8 | 9 | #ifndef CHECK_HELPER_H 10 | #define CHECK_HELPER_H 11 | 12 | #include "scope.h" 13 | #include "types.h" 14 | 15 | // check_correctness_helper(ast_t*, ir_scope_t*, bool, bool) -> void 16 | // Helper function for check_correctness. 17 | bool check_correctness_helper(ast_t* ast, ir_scope_t* scope, bool get_real_type, bool disable_new_vars); 18 | 19 | #endif /* CHECK_HELPER_H */ 20 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/scope.c: -------------------------------------------------------------------------------- 1 | // 2 | // correctness 3 | // scope.c: Implements a scope system. 4 | // 5 | // Created by jenra. 6 | // Created on August 29 2020. 7 | // 8 | 9 | #include "scope.h" 10 | 11 | // push_scope(ir_scope_t*) -> ir_scope_t* 12 | // Initialises a scope and pushes it onto the stack of scopes. 13 | ir_scope_t* push_scope(ir_scope_t* parent) 14 | { 15 | ir_scope_t* scope = malloc(sizeof(ir_scope_t)); 16 | scope->var_types = init_hashmap(); 17 | scope->var_vals = init_hashmap(); 18 | scope->types = init_hashmap(); 19 | 20 | for (int i = 0; i < INFIX_OP_COUNT; i++) 21 | { 22 | scope->infix_ops[i] = NULL; 23 | } 24 | 25 | scope->parent = parent; 26 | return scope; 27 | } 28 | 29 | // add_prefix_op(ir_scope_t*, type_t*, type_t*) -> void 30 | // Adds a new prefix operator to the scope. 31 | void add_prefix_op(ir_scope_t* scope, type_t* operand, type_t* out) 32 | { 33 | // Create the type 34 | type_t* type = init_type(IR_TYPES_FUNC, NULL, 2); 35 | type->field_types[0] = operand; 36 | type->field_types[1] = out; 37 | 38 | // Create the prefix operator 39 | ir_infix_type_t* prefix = malloc(sizeof(ir_infix_type_t)); 40 | prefix->type = type; 41 | prefix->next = NULL; 42 | 43 | // Append the new operator 44 | if (scope->infix_ops[0] == NULL) 45 | scope->infix_ops[0] = prefix; 46 | else 47 | { 48 | // Find the last element in the linked list 49 | ir_infix_type_t* head = scope->infix_ops[0]; 50 | while (head->next != NULL) 51 | { 52 | head = head->next; 53 | } 54 | head->next = prefix; 55 | } 56 | } 57 | 58 | // add_infix_op(ir_scope_t*, ir_binops_t, type_t*, type_t*, type_t*) -> void 59 | // Adds an infix operation to the scope. 60 | void add_infix_op(ir_scope_t* scope, ir_binops_t op, type_t* left, type_t* right, type_t* out) 61 | { 62 | // Create the type 63 | type_t* type = init_type(IR_TYPES_FUNC, NULL, 3); 64 | type->field_types[0] = left; 65 | type->field_types[1] = right; 66 | type->field_types[2] = out; 67 | 68 | // Create the infix operator 69 | ir_infix_type_t* infix = malloc(sizeof(ir_infix_type_t)); 70 | infix->type = type; 71 | infix->next = NULL; 72 | 73 | // Append the new operator 74 | if (scope->infix_ops[op] == NULL) 75 | scope->infix_ops[op] = infix; 76 | else 77 | { 78 | // Find the last element in the linked list 79 | ir_infix_type_t* head = scope->infix_ops[op]; 80 | while (head->next != NULL) 81 | { 82 | head = head->next; 83 | } 84 | head->next = infix; 85 | } 86 | } 87 | 88 | // scope_lookup_prefix(ir_scope_t*, type_t*) -> type_t* 89 | // Looks up a prefix operator based on the argument type and returns the result type. 90 | type_t* scope_lookup_prefix(ir_scope_t* scope, type_t* operand) 91 | { 92 | // Iterate over the scopes 93 | ir_scope_t* top = scope; 94 | while (top != NULL) 95 | { 96 | // Search for the prefix operator 97 | ir_infix_type_t* current = top->infix_ops[0]; 98 | while (current != NULL) 99 | { 100 | if (type_subtype(current->type->field_types[0], operand)) 101 | return current->type->field_types[1]; 102 | current = current->next; 103 | } 104 | 105 | // Get parent scope 106 | top = top->parent; 107 | } 108 | 109 | // No operator found 110 | return NULL; 111 | } 112 | 113 | // scope_lookup_infix(ir_scope_t*, ir_binops_t, type_t*, type_t*) -> type_t* 114 | // Looks up an infix operator based on the argument types and returns the result type. 115 | type_t* scope_lookup_infix(ir_scope_t* scope, ir_binops_t op, type_t* left, type_t* right) 116 | { 117 | // Iterate over the scopes 118 | ir_scope_t* top = scope; 119 | while (top != NULL) 120 | { 121 | // Search for the infix operator in topmost scope 122 | ir_infix_type_t* current = top->infix_ops[op]; 123 | while (current != NULL) 124 | { 125 | if (type_subtype(current->type->field_types[0], left) && type_subtype(current->type->field_types[1], right)) 126 | return current->type->field_types[2]; 127 | current = current->next; 128 | } 129 | 130 | // Get parent scope 131 | top = top->parent; 132 | } 133 | 134 | // No operator found 135 | return NULL; 136 | } 137 | 138 | // scope_lookup_var_type(ir_scope_t*, char*) -> type_t* 139 | // Looks up the type of a variable in the scope. 140 | type_t* scope_lookup_var_type(ir_scope_t* scope, char* name) 141 | { 142 | // Iterate over every scope 143 | while (scope != NULL) 144 | { 145 | // Get the type in the current scope 146 | type_t* type = map_get(scope->var_types, name); 147 | 148 | // Return the type if found 149 | if (type != NULL) 150 | return type; 151 | 152 | // Get parent scope 153 | scope = scope->parent; 154 | } 155 | 156 | // No type was found 157 | return NULL; 158 | } 159 | 160 | // scope_lookup_var_val(ir_scope_t*, char*) -> ir_sexpr_t* 161 | // Looks up the value of a variable in the scope. 162 | ir_sexpr_t* scope_lookup_var_val(ir_scope_t* scope, char* name) 163 | { 164 | // Iterate over every scope 165 | while (scope != NULL) 166 | { 167 | // Get the S expression in the current scope 168 | ir_sexpr_t* sexpr = map_get(scope->var_vals, name); 169 | 170 | // Return the S expression if found 171 | if (sexpr != NULL) 172 | return sexpr; 173 | 174 | // Get parent scope 175 | scope = scope->parent; 176 | } 177 | 178 | // No S expression was found 179 | return NULL; 180 | } 181 | 182 | // scope_lookup_type(ir_scope_t*, char*) -> type_t* 183 | // Looks up a type in the scope. 184 | type_t* scope_lookup_type(ir_scope_t* scope, char* name) 185 | { 186 | // Iterate over every scope 187 | while (scope != NULL) 188 | { 189 | // Get the type in the current scope 190 | type_t* type = map_get(scope->types, name); 191 | 192 | // Return the type if found 193 | if (type != NULL) 194 | return type; 195 | 196 | // Get parent scope 197 | scope = scope->parent; 198 | } 199 | 200 | // No type was found 201 | return NULL; 202 | } 203 | 204 | // pop_scope(ir_scope_t* scope) 205 | // Deletes a scope and returns its parent. 206 | ir_scope_t* pop_scope(ir_scope_t* scope) 207 | { 208 | del_hashmap(scope->var_types); 209 | del_hashmap(scope->var_vals); 210 | del_hashmap(scope->types); 211 | 212 | for (int i = 0; i < INFIX_OP_COUNT; i++) 213 | { 214 | ir_infix_type_t* head = scope->infix_ops[i]; 215 | while (head != NULL) 216 | { 217 | ir_infix_type_t* next = head->next; 218 | free(head); 219 | head = next; 220 | } 221 | } 222 | 223 | ir_scope_t* parent = scope->parent; 224 | free(scope); 225 | return parent; 226 | } 227 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/scope.h: -------------------------------------------------------------------------------- 1 | // 2 | // correctness 3 | // scope.h: Header file for scope.c. 4 | // 5 | // Created by jenra. 6 | // Created on August 29 2020. 7 | // 8 | 9 | #ifndef SCOPE_H 10 | #define SCOPE_H 11 | 12 | #include "../../../utils/hashmap.h" 13 | #include "../ir/generate_ir.h" 14 | #include "types.h" 15 | 16 | #define INFIX_OP_COUNT 11 17 | 18 | // Represents an infix operator's type 19 | typedef struct s_ir_infix_type 20 | { 21 | // The type of the infix value 22 | type_t* type; 23 | 24 | // The next infix type in the linked list. 25 | struct s_ir_infix_type* next; 26 | } ir_infix_type_t; 27 | 28 | // Represents a scope. 29 | typedef struct s_ir_scope 30 | { 31 | // A hashmap of all variable names mapped to their types in the current scope. 32 | hashmap_t* var_types; 33 | 34 | // A hashmap of all variable names mapped to their values in the current scope. 35 | hashmap_t* var_vals; 36 | 37 | // A hashmap of all the types mapped by their names in the current scope. 38 | hashmap_t* types; 39 | 40 | // The infix operations defined for the current scope. 41 | ir_infix_type_t* infix_ops[INFIX_OP_COUNT]; 42 | 43 | // The parent scope. 44 | struct s_ir_scope* parent; 45 | } ir_scope_t; 46 | 47 | // push_scope(ir_scope_t*) -> ir_scope_t* 48 | // Initialises a scope and pushes it onto the stack of scopes. 49 | ir_scope_t* push_scope(ir_scope_t* parent); 50 | 51 | // add_prefix_op(ir_scope_t*, type_t*, type_t*) -> void 52 | // Adds a new prefix operator to the scope. 53 | void add_prefix_op(ir_scope_t* scope, type_t* operand, type_t* out); 54 | 55 | // add_infix_op(ir_scope_t*, ir_binops_t, type_t*, type_t*, type_t*) -> void 56 | // Adds an infix operation to the scope. 57 | void add_infix_op(ir_scope_t* scope, ir_binops_t op, type_t* left, type_t* right, type_t* out); 58 | 59 | // scope_lookup_prefix(ir_scope_t*, type_t*) -> type_t* 60 | // Looks up a prefix operator based on the argument type and returns the result type. 61 | type_t* scope_lookup_prefix(ir_scope_t* scope, type_t* operand); 62 | 63 | // scope_lookup_infix(ir_scope_t*, ir_binops_t, type_t*, type_t*) -> type_t* 64 | // Looks up an infix operator based on the argument types and returns the result type. 65 | type_t* scope_lookup_infix(ir_scope_t* scope, ir_binops_t op, type_t* left, type_t* right); 66 | 67 | // scope_lookup_var_type(ir_scope_t*, char*) -> type_t* 68 | // Looks up the type of a variable in the scope. 69 | type_t* scope_lookup_var_type(ir_scope_t* scope, char* name); 70 | 71 | // scope_lookup_var_val(ir_scope_t*, char*) -> ir_sexpr_t* 72 | // Looks up the value of a variable in the scope. 73 | ir_sexpr_t* scope_lookup_var_val(ir_scope_t* scope, char* name); 74 | 75 | // scope_lookup_type(ir_scope_t*, char*) -> type_t* 76 | // Looks up a type in the scope. 77 | type_t* scope_lookup_type(ir_scope_t* scope, char* name); 78 | 79 | // pop_scope(ir_scope_t* scope) 80 | // Deletes a scope and returns its parent. 81 | ir_scope_t* pop_scope(ir_scope_t* scope); 82 | 83 | #endif /* SCOPE_H */ 84 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/type_generators.c: -------------------------------------------------------------------------------- 1 | // 2 | // correctness 3 | // type_generators.c: Provides functions for generating types. 4 | // 5 | // Created by jenra. 6 | // Created on September 5 2020. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "../../../utils/list.h" 13 | #include "type_generators.h" 14 | 15 | // generate_type(ast_t*, ir_scope_t*, ast_t*, type_t*) -> type_t* 16 | // Generates a type from an infix expression. 17 | // TODO: parametric types (both recursive and nonrecursive) 18 | type_t* generate_type(ast_t* ast, ir_scope_t* scope, ast_t* self, type_t* head) 19 | { 20 | // types: 21 | // & - intersection type 22 | // * - product type 23 | // | - union type 24 | // -> - function type 25 | // *type - generator of type 26 | // [type] - list of type 27 | 28 | // If the ast is the same as the type name then its equal 29 | if (asts_equal(ast, self)) 30 | return head; 31 | 32 | // Type symbols 33 | else if (ast->value.type == LEX_TYPE_SYMBOL) 34 | { 35 | type_t* type = scope_lookup_type(scope, ast->value.value); 36 | if (type == NULL) 37 | { 38 | printf("Undeclared type %s found at %i:%i\n", ast->value.value, ast->value.lino, ast->value.charpos); 39 | return NULL; 40 | } 41 | return type; 42 | 43 | // Functions 44 | } else if (ast->value.type == LEX_TYPE_SYMBOL) 45 | { 46 | printf("Functions are unsupported right now\n"); 47 | return NULL; 48 | 49 | // Field declarations (field: type) 50 | } else if (!strcmp(ast->value.value, ":")) 51 | { 52 | // Assert that the left hand side is a symbol 53 | ast_t* field_name = ast->children[0]; 54 | if (field_name->value.type != LEX_TYPE_SYMBOL) 55 | { 56 | printf("Used %s as field name at %i:%i\n", field_name->value.value, field_name->value.lino, field_name->value.charpos); 57 | return NULL; 58 | } 59 | 60 | // Get the type of the right hand side 61 | type_t* type = init_type(IR_TYPES_PRODUCT, NULL, 1); 62 | if (head == NULL) head = type; 63 | ast_t* field_type = ast->children[1]; 64 | type_t* subtype = generate_type(field_type, scope, self, head); 65 | 66 | // Create a new type 67 | type->field_names[0] = strdup(field_name->value.value); 68 | type->field_types[0] = subtype; 69 | ast->type = scope_lookup_type(scope, "Type"); 70 | return type; 71 | 72 | // Generator types 73 | } else if (!strcmp(ast->value.value, "*") && ast->children_count == 1) 74 | { 75 | // Create generator type 76 | type_t* type = init_type(IR_TYPES_GENERATOR, NULL, 1); 77 | if (head == NULL) head = type; 78 | type_t* subtype = generate_type(ast->children[0], scope, self, head); 79 | if (subtype == NULL) return NULL; 80 | type->field_types[0] = subtype; 81 | return type; 82 | 83 | // Product types 84 | } else if (!strcmp(ast->value.value, "*")) 85 | { 86 | // List of types (reverse order) 87 | type_t** types = NULL; 88 | size_t size = 0; 89 | size_t count = 0; 90 | type_t* type = init_type(IR_TYPES_PRODUCT, NULL, 0); 91 | if (head == NULL) head = type; 92 | 93 | do 94 | { 95 | // Get type and append it to the list of types 96 | ast->type = scope_lookup_type(scope, "Type"); 97 | type_t* type = generate_type(ast->children[1], scope, self, head); 98 | if (type == NULL) return NULL; 99 | list_append_element(types, size, count, type_t*, type); 100 | 101 | // Get the next ast and continue if it's also a product 102 | ast = ast->children[0]; 103 | } while (!strcmp(ast->value.value, "*")); 104 | 105 | // Get the last ast's type and append it to the list of types 106 | type_t* subtype = generate_type(ast, scope, self, head); 107 | if (subtype == NULL) return NULL; 108 | list_append_element(types, size, count, type_t*, subtype); 109 | 110 | // Create a new product type and add the subtypes 111 | type->field_count = count; 112 | type->field_names = calloc(count, sizeof(char*)); 113 | type->field_types = calloc(count, sizeof(type_t*)); 114 | for (size_t i = 0; i < count; i++) 115 | { 116 | type->field_types[i] = types[count - i - 1]; 117 | } 118 | return type; 119 | 120 | // Union types 121 | } else if (!strcmp(ast->value.value, "|")) 122 | { 123 | // List of field types and names (reverse order) 124 | type_t** types = NULL; 125 | char** names = NULL; 126 | size_t t_size = 0; 127 | size_t n_size = 0; 128 | size_t count = 0; 129 | type_t* type = init_type(IR_TYPES_UNION, NULL, 0); 130 | if (head == NULL) head = type; 131 | 132 | do 133 | { 134 | // Get type and append it to the list of types 135 | ast->type = scope_lookup_type(scope, "Type"); 136 | type_t* type = generate_type(ast->children[1], scope, self, head); 137 | if (type == NULL) return NULL; 138 | if (type->field_count == 1 && type->type_type == IR_TYPES_PRODUCT) 139 | { 140 | list_append_element(types, t_size, count, type_t*, type->field_types[0]); 141 | count--; 142 | list_append_element(names, n_size, count, char*, type->field_names[0]); 143 | } else 144 | { 145 | list_append_element(types, t_size, count, type_t*, type); 146 | count--; 147 | list_append_element(names, n_size, count, char*, NULL); 148 | } 149 | 150 | // Get the next ast and continue if it's also a product 151 | ast = ast->children[0]; 152 | } while (!strcmp(ast->value.value, "|")); 153 | 154 | // Get the last ast's type and append it to the list of types 155 | type_t* subtype = generate_type(ast, scope, self, head); 156 | if (subtype == NULL) return NULL; 157 | if (subtype->field_count == 1 && subtype->type_type == IR_TYPES_PRODUCT) 158 | { 159 | list_append_element(types, t_size, count, type_t*, subtype->field_types[0]); 160 | count--; 161 | list_append_element(names, n_size, count, char*, subtype->field_names[0]); 162 | } else 163 | { 164 | list_append_element(types, t_size, count, type_t*, subtype); 165 | count--; 166 | list_append_element(names, n_size, count, char*, NULL); 167 | } 168 | 169 | // Create a new union type and add the subtypes 170 | type->field_count = count; 171 | type->field_names = calloc(count, sizeof(char*)); 172 | type->field_types = calloc(count, sizeof(type_t*)); 173 | for (size_t i = 0; i < count; i++) 174 | { 175 | type->field_types[i] = types[count - i - 1]; 176 | type->field_names[i] = names[count - i - 1]; 177 | } 178 | return type; 179 | 180 | // Intersection types 181 | } else if (!strcmp(ast->value.value, "&")) 182 | { 183 | // List of field types and names (reverse order) 184 | type_t** types = NULL; 185 | char** names = NULL; 186 | size_t t_size = 0; 187 | size_t n_size = 0; 188 | size_t count = 0; 189 | type_t* type = init_type(IR_TYPES_PRODUCT, NULL, 0); 190 | if (head == NULL) head = type; 191 | 192 | do 193 | { 194 | // Get type 195 | ast->type = scope_lookup_type(scope, "Type"); 196 | type_t* type = generate_type(ast->children[1], scope, self, head); 197 | if (type == NULL) return NULL; 198 | 199 | // If it's a primitive make an error (cannot intersect primatives) 200 | if (type->type_type == IR_TYPES_PRIMITIVE) 201 | { 202 | printf("Intersection of primitive %s found at %i:%i\n", ast->value.value, ast->value.lino, ast->value.charpos); 203 | return NULL; 204 | } 205 | 206 | // Copy over the fields 207 | for (size_t i = 0; i < type->field_count; i++) 208 | { 209 | list_append_element(names, n_size, count, type_t*, type->field_names[i]); 210 | count--; 211 | list_append_element(types, t_size, count, type_t*, type->field_types[i]); 212 | } 213 | 214 | // Get the next ast and continue if it's also a product 215 | ast = ast->children[0]; 216 | } while (!strcmp(ast->value.value, "&")); 217 | 218 | // Get the last ast's type and append it to the list of types 219 | type_t* subtype = generate_type(ast, scope, self, head); 220 | if (subtype == NULL) return NULL; 221 | 222 | // If it's a primitive make an error (cannot intersect primatives) 223 | if (subtype->type_type == IR_TYPES_PRIMITIVE) 224 | { 225 | printf("Intersection of primitive %s found at %i:%i\n", ast->value.value, ast->value.lino, ast->value.charpos); 226 | return NULL; 227 | } 228 | 229 | // Copy over the fields 230 | for (size_t i = 0; i < subtype->field_count; i++) 231 | { 232 | list_append_element(names, n_size, count, type_t*, subtype->field_names[i]); 233 | count--; 234 | list_append_element(types, t_size, count, type_t*, subtype->field_types[i]); 235 | } 236 | 237 | // Create a new intersection type and add the subtypes 238 | type->field_count = count; 239 | type->field_names = calloc(count, sizeof(char*)); 240 | type->field_types = calloc(count, sizeof(type_t*)); 241 | for (size_t i = 0; i < count; i++) 242 | { 243 | type->field_types[i] = types[count - i - 1]; 244 | type->field_names[i] = names[count - i - 1]; 245 | } 246 | return type; 247 | 248 | // Function types 249 | } else if (ast->value.type == LEX_TYPE_RIGHT_ARROW) 250 | { 251 | // Fill argument and return type 252 | type_t* type = init_type(IR_TYPES_FUNC, NULL, 2); 253 | if (head == NULL) head = type; 254 | type->field_types[0] = generate_type(ast->children[0], scope, self, head); 255 | if (type->field_types[0] == NULL) return NULL; 256 | type->field_types[1] = generate_type(ast->children[1], scope, self, head); 257 | if (type->field_types[1] == NULL) return NULL; 258 | return type; 259 | 260 | // List types 261 | } else if (!strcmp(ast->value.value, "[") && ast->children_count == 1) 262 | { 263 | // Create list type 264 | type_t* type = init_type(IR_TYPES_LIST, NULL, 1); 265 | if (head == NULL) head = type; 266 | type_t* subtype = generate_type(ast->children[0], scope, self, head); 267 | if (subtype == NULL) return NULL; 268 | type->field_types[0] = subtype; 269 | return type; 270 | 271 | // Error on anything else 272 | } else 273 | { 274 | printf("Invalid type found at %i:%i\n", ast->value.lino, ast->value.charpos); 275 | return NULL; 276 | } 277 | } 278 | 279 | // generate_enum(ast_t*, ir_scope_t*, type_t*) -> type_t* 280 | // Generates an enum type from a given ast. 281 | type_t* generate_enum(ast_t* ast, ir_scope_t* scope, type_t* head) 282 | { 283 | // Enum values 284 | if (ast->value.type == LEX_TYPE_SYMBOL && ast->children_count == 0) 285 | { 286 | // Create the enum 287 | type_t* enumy = init_type(IR_TYPES_ENUMERATION, ast->value.value, 0); // ast->children_count); 288 | ast->type = enumy; 289 | 290 | map_add(scope->var_types, ast->value.value, head); 291 | map_add(scope->var_vals, ast->value.value, ast); 292 | 293 | return enumy; 294 | 295 | // Unions 296 | } else if (!strcmp(ast->value.value, "|")) 297 | { 298 | // List of field types (reverse order) 299 | type_t** enums = NULL; 300 | size_t size = 0; 301 | size_t count = 0; 302 | type_t* enumy = init_type(IR_TYPES_UNION, NULL, 0); 303 | if (head == NULL) head = enumy; 304 | 305 | do 306 | { 307 | // Get enum and append it to the list of enums 308 | ast->type = scope_lookup_type(scope, "Enum"); 309 | type_t* enumy = generate_enum(ast->children[1], scope, head); 310 | if (enumy == NULL) return NULL; 311 | list_append_element(enums, size, count, type_t*, enumy); 312 | 313 | // Get the next ast and continue if it's also a product 314 | ast = ast->children[0]; 315 | } while (!strcmp(ast->value.value, "|")); 316 | 317 | // Get the last ast's enum and append it to the list of enums 318 | type_t* subenum = generate_enum(ast, scope, head); 319 | if (subenum == NULL) return NULL; 320 | list_append_element(enums, size, count, type_t*, subenum); 321 | 322 | // Create a new enum type and add the subtypes 323 | enumy->field_count = count; 324 | enumy->field_names = calloc(count, sizeof(char*)); 325 | enumy->field_types = calloc(count, sizeof(type_t*)); 326 | for (size_t i = 0; i < count; i++) 327 | { 328 | enumy->field_types[i] = enums[count - i - 1]; 329 | } 330 | return enumy; 331 | 332 | // Error on anything else 333 | } else 334 | { 335 | printf("Invalid enum found at %i:%i\n", ast->value.lino, ast->value.charpos); 336 | return NULL; 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/type_generators.h: -------------------------------------------------------------------------------- 1 | // 2 | // correctness 3 | // type_generators.h: Header file for type_generators.c. 4 | // 5 | // Created by jenra. 6 | // Created on September 5 2020. 7 | // 8 | 9 | #ifndef TYPE_GENERATORS_H 10 | #define TYPE_GENERATORS_H 11 | 12 | #include "scope.h" 13 | #include "types.h" 14 | 15 | // generate_type(ast_t*, ir_scope_t*, ast_t*, type_t*) -> type_t* 16 | // Generates a type from an infix expression. 17 | type_t* generate_type(ast_t* ast, ir_scope_t* scope, ast_t* self, type_t* head); 18 | 19 | // generate_enum(ast_t*, ir_scope_t*, type_t*) -> type_t* 20 | // Generates an enum type from a given ast. 21 | type_t* generate_enum(ast_t* ast, ir_scope_t* scope, type_t* head); 22 | 23 | #endif /* TYPE_GENERATORS_H */ 24 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/types.c: -------------------------------------------------------------------------------- 1 | // 2 | // ir-codegen 3 | // types.c: Implements different functions for comparing, combining, and representing types in curly. 4 | // 5 | // Created by jenra. 6 | // Created on August 29 2020. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "scope.h" 13 | #include "types.h" 14 | 15 | static type_t* type_linked_list_head = NULL; 16 | 17 | // create_primatives(ir_scope_t*) -> void 18 | // Creates the builtin primative types. 19 | void create_primatives(ir_scope_t* scope) 20 | { 21 | // Primatives must be the first types created 22 | if (type_linked_list_head != NULL) 23 | return; 24 | 25 | // Create primatives 26 | type_t* _int = init_type(IR_TYPES_PRIMITIVE, "Int", 0); 27 | type_t* _float = init_type(IR_TYPES_PRIMITIVE, "Float", 0); 28 | init_type(IR_TYPES_PRIMITIVE, "String", 0); 29 | init_type(IR_TYPES_PRIMITIVE, "Bool", 0); 30 | //init_type(IR_TYPES_PRIMITIVE, "Dict", 0); 31 | init_type(IR_TYPES_PRIMITIVE, "Enum", 0); 32 | 33 | // Add to scope 34 | type_t* head = type_linked_list_head; 35 | while (head != NULL) 36 | { 37 | map_add(scope->types, head->type_name, head); 38 | head = head->next; 39 | } 40 | 41 | // Define default arithmetic infix operations 42 | add_infix_op(scope, IR_BINOPS_MUL, _int, _int, _int); 43 | add_infix_op(scope, IR_BINOPS_MUL, _float, _int, _float); 44 | add_infix_op(scope, IR_BINOPS_MUL, _int, _float, _float); 45 | add_infix_op(scope, IR_BINOPS_MUL, _float, _float, _float); 46 | add_infix_op(scope, IR_BINOPS_DIV, _int, _int, _int); 47 | add_infix_op(scope, IR_BINOPS_DIV, _float, _int, _float); 48 | add_infix_op(scope, IR_BINOPS_DIV, _int, _float, _float); 49 | add_infix_op(scope, IR_BINOPS_DIV, _float, _float, _float); 50 | add_infix_op(scope, IR_BINOPS_MOD, _int, _int, _int); 51 | add_infix_op(scope, IR_BINOPS_ADD, _int, _int, _int); 52 | add_infix_op(scope, IR_BINOPS_ADD, _float, _int, _float); 53 | add_infix_op(scope, IR_BINOPS_ADD, _int, _float, _float); 54 | add_infix_op(scope, IR_BINOPS_ADD, _float, _float, _float); 55 | add_infix_op(scope, IR_BINOPS_SUB, _int, _int, _int); 56 | add_infix_op(scope, IR_BINOPS_SUB, _float, _int, _float); 57 | add_infix_op(scope, IR_BINOPS_SUB, _int, _float, _float); 58 | add_infix_op(scope, IR_BINOPS_SUB, _float, _float, _float); 59 | add_infix_op(scope, IR_BINOPS_BSL, _int, _int, _int); 60 | add_infix_op(scope, IR_BINOPS_BSR, _int, _int, _int); 61 | add_infix_op(scope, IR_BINOPS_BITAND, _int, _int, _int); 62 | add_infix_op(scope, IR_BINOPS_BITOR, _int, _int, _int); 63 | add_infix_op(scope, IR_BINOPS_BITXOR, _int, _int, _int); 64 | 65 | // Define default prefix operations 66 | add_prefix_op(scope, _int, _int); 67 | add_prefix_op(scope, _float, _float); 68 | } 69 | 70 | // init_type(ir_type_types_t, char*, size_t, type_t) -> type_t* 71 | // Initialises a new type. 72 | type_t* init_type(ir_type_types_t type_type, char* name, size_t field_count) 73 | { 74 | type_t* type = malloc(sizeof(type_t)); 75 | type->printing = false; 76 | type->name_carry = NULL; 77 | type->type_type = type_type; 78 | type->type_name = name != NULL ? strdup(name) : NULL; 79 | type->field_types = calloc(field_count, sizeof(type_t*)); 80 | type->field_names = calloc(field_count, sizeof(char*)); 81 | type->field_count = field_count; 82 | 83 | // Add to linked list 84 | type->next = type_linked_list_head; 85 | type_linked_list_head = type; 86 | return type; 87 | } 88 | 89 | // type_subtype(type_t*, type_t*) -> bool 90 | // Returns true if the second type is a valid type under the first type. 91 | bool type_subtype(type_t* super, type_t* sub) 92 | { 93 | if (super == NULL || sub == NULL) 94 | return super == sub; 95 | 96 | // Empty lists are valid subtypes of populated lists 97 | if (super->type_type == IR_TYPES_LIST && sub->type_type == IR_TYPES_LIST && sub->field_count == 0) 98 | return true; 99 | 100 | // Nonunion types must be the same type of type and have the same number of fields 101 | else if (super->type_type != IR_TYPES_UNION && (super->type_type != sub->type_type || super->field_count != sub->field_count)) 102 | return false; 103 | 104 | // Every type is equal to itself 105 | else if (super == sub) 106 | return true; 107 | 108 | // Check the contents of the type 109 | switch (super->type_type) 110 | { 111 | case IR_TYPES_PRIMITIVE: 112 | case IR_TYPES_ENUMERATION: 113 | // Primatives and enums check if they have the same name and number of subtypes 114 | return !strcmp(super->type_name, sub->type_name); 115 | case IR_TYPES_UNION: 116 | // Union types check its subtypes against the passed subtype 117 | for (size_t i = 0; i < super->field_count; i++) 118 | { 119 | bool equal = type_subtype(super->field_types[i], sub); 120 | if (equal) 121 | return true; 122 | } 123 | return false; 124 | case IR_TYPES_PRODUCT: 125 | case IR_TYPES_LIST: 126 | case IR_TYPES_GENERATOR: 127 | case IR_TYPES_FUNC: 128 | case IR_TYPES_CURRY: 129 | // Compound types are equal if their field types are the same 130 | for (size_t i = 0; i < super->field_count; i++) 131 | { 132 | bool equal = (super->field_names[i] != NULL && sub->field_names[i] != NULL ? !strcmp(super->field_names[i], sub->field_names[i]) : true) && type_subtype(super->field_types[i], sub->field_types[i]); 133 | if (!equal) return false; 134 | } 135 | 136 | return true; 137 | default: 138 | return false; 139 | } 140 | } 141 | 142 | // types_equal(type_t*, type_t*) -> bool 143 | // Returns whether the two types are equal or not. 144 | bool types_equal(type_t* t1, type_t* t2) 145 | { 146 | if (t1 == NULL || t2 == NULL) 147 | return t1 == t2; 148 | 149 | // Types must be the same type of type and have the same number of fields 150 | if (t1->type_type != t2->type_type || t1->field_count != t2->field_count) 151 | return false; 152 | 153 | // Every type is equal to itself 154 | else if (t1 == t2) 155 | return true; 156 | 157 | // Check the contents of the type 158 | switch (t1->type_type) 159 | { 160 | case IR_TYPES_PRIMITIVE: 161 | case IR_TYPES_ENUMERATION: 162 | // Primatives and enums are equal if they have the same name 163 | return !strcmp(t1->type_name, t2->type_name); 164 | case IR_TYPES_PRODUCT: 165 | case IR_TYPES_UNION: 166 | case IR_TYPES_LIST: 167 | case IR_TYPES_GENERATOR: 168 | case IR_TYPES_FUNC: 169 | case IR_TYPES_CURRY: 170 | // Compound types are equal if their field types are the same 171 | for (size_t i = 0; i < t1->field_count; i++) 172 | { 173 | bool equal = types_equal(t1->field_types[i], t2->field_types[i]); 174 | if (!equal) return false; 175 | } 176 | return true; 177 | default: 178 | return false; 179 | } 180 | } 181 | 182 | // print_type_helper(type_t*, int) -> void 183 | // Helps to print out a type's internal structure. 184 | void print_type_helper(type_t* type, char* name, int level) 185 | { 186 | // Print indentation 187 | for (int i = 0; i < level; i++) 188 | { 189 | putc('\t', stdout); 190 | } 191 | if (level > 0) printf("| "); 192 | 193 | if (type == NULL) 194 | { 195 | puts("null"); 196 | return; 197 | } 198 | 199 | // Print out the field name if applicable 200 | if (name != NULL) 201 | printf("%s: ", name); 202 | 203 | // Print out the type of the type 204 | switch (type->type_type) 205 | { 206 | case IR_TYPES_PRIMITIVE: 207 | printf("prim"); 208 | break; 209 | case IR_TYPES_ENUMERATION: 210 | printf("enum"); 211 | break; 212 | case IR_TYPES_PRODUCT: 213 | printf("prod"); 214 | break; 215 | case IR_TYPES_UNION: 216 | printf("union"); 217 | break; 218 | case IR_TYPES_LIST: 219 | printf("list"); 220 | break; 221 | case IR_TYPES_GENERATOR: 222 | printf("gen"); 223 | break; 224 | case IR_TYPES_FUNC: 225 | printf("func"); 226 | break; 227 | default: 228 | printf("type"); 229 | break; 230 | } 231 | 232 | // Print out the type name if applicable 233 | if (type->type_name != NULL) 234 | printf(" %s", type->type_name); 235 | puts(""); 236 | 237 | // If the type is currently being printed out, stop printing it a second time 238 | if (type->printing) 239 | { 240 | // Print indentation 241 | for (int i = 0; i < level + 1; i++) 242 | { 243 | putc('\t', stdout); 244 | } 245 | puts("| ..."); 246 | return; 247 | } else type->printing = true; 248 | 249 | // Print out children 250 | for (int i = 0; i < type->field_count; i++) 251 | { 252 | print_type_helper(type->field_types[i], type->field_names[i], level + 1); 253 | } 254 | 255 | // Set printing to false 256 | type->printing = false; 257 | } 258 | 259 | // print_type(type_t*) -> void 260 | // Prints out a type. 261 | void print_type(type_t* type) { print_type_helper(type, NULL, 0); } 262 | 263 | // clean_types(void) -> void 264 | // Frees every type created. 265 | void clean_types() 266 | { 267 | // Iterate over every 268 | while (type_linked_list_head != NULL) 269 | { 270 | // Free fields 271 | free(type_linked_list_head->type_name); 272 | free(type_linked_list_head->field_types); 273 | free(type_linked_list_head->field_names); 274 | 275 | // Free head pointer 276 | type_t* tail = type_linked_list_head->next; 277 | free(type_linked_list_head); 278 | type_linked_list_head = tail; 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /src/compiler/frontend/correctness/types.h: -------------------------------------------------------------------------------- 1 | // 2 | // ir-codegen 3 | // types.h: Header file for types.c. 4 | // 5 | // Created by jenra. 6 | // Created on August 29 2020. 7 | // 8 | 9 | #ifndef TYPES_H 10 | #define TYPES_H 11 | 12 | #include 13 | #include 14 | 15 | #include "../../../utils/hashmap.h" 16 | 17 | // Represents the types of types. 18 | typedef enum 19 | { 20 | IR_TYPES_PRIMITIVE, 21 | IR_TYPES_ENUMERATION, 22 | IR_TYPES_PRODUCT, 23 | IR_TYPES_UNION, 24 | IR_TYPES_LIST, 25 | IR_TYPES_GENERATOR, 26 | IR_TYPES_FUNC, 27 | IR_TYPES_CURRY 28 | } ir_type_types_t; 29 | 30 | // Represents a curly type in the intermediate representation. 31 | typedef struct s_type 32 | { 33 | // If the type is currently being printed 34 | bool printing; 35 | 36 | // Carries the name from this type node to its parent. 37 | char* name_carry; 38 | 39 | // The type of type 40 | ir_type_types_t type_type; 41 | 42 | // The name of the type 43 | char* type_name; 44 | 45 | // Array of field names (names can be null) 46 | char** field_names; 47 | struct s_type** field_types; 48 | size_t field_count; 49 | 50 | // Linked list of types 51 | struct s_type* next; 52 | } type_t; 53 | 54 | typedef struct s_ir_scope ir_scope_t; 55 | 56 | // create_primatives(ir_scope_t*) -> void 57 | // Creates the builtin primative types. 58 | void create_primatives(ir_scope_t* scope); 59 | 60 | // init_type(ir_type_types_t, char*, size_t) -> type_t* 61 | // Initialises a new type. 62 | type_t* init_type(ir_type_types_t type_type, char* name, size_t field_count); 63 | 64 | // type_subtype(type_t*, type_t*) -> bool 65 | // Returns true if the second type is a valid type under the first type. 66 | bool type_subtype(type_t* super, type_t* sub); 67 | 68 | // types_equal(type_t*, type_t*) -> bool 69 | // Returns whether the two types are equal or not. 70 | bool types_equal(type_t* t1, type_t* t2); 71 | 72 | // print_type(type_t*) -> void 73 | // Prints out a type. 74 | void print_type(type_t* type); 75 | 76 | // clean_types(void) -> void 77 | // Frees every type created. 78 | void clean_types(); 79 | 80 | #endif /* TYPES_H */ 81 | -------------------------------------------------------------------------------- /src/compiler/frontend/ir/generate_ir.c: -------------------------------------------------------------------------------- 1 | // 2 | // ir 3 | // generate_ir.c: Converts the abstract syntax tree into an intermediate representation used by the backends. 4 | // 5 | // Created by jenra. 6 | // Created on October 12 2020. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "../../../utils/list.h" 13 | #include "../correctness/type_generators.h" 14 | #include "generate_ir.h" 15 | 16 | // convert_ast_node(curly_ir_t*, ast_t*, ir_scope_t*) -> ir_sexpr_t* 17 | // Converts an ast node into an S expression. 18 | ir_sexpr_t* convert_ast_node(curly_ir_t* root, ast_t* ast, ir_scope_t* scope) 19 | { 20 | ir_sexpr_t* sexpr = malloc(sizeof(ir_sexpr_t)); 21 | sexpr->type = NULL; 22 | sexpr->lino = ast->value.lino; 23 | sexpr->charpos = ast->value.charpos; 24 | sexpr->pos = ast->value.pos; 25 | 26 | // Operands 27 | if (ast->value.tag == LEX_TAG_OPERAND) 28 | { 29 | switch (ast->value.type) 30 | { 31 | case LEX_TYPE_INT: 32 | sexpr->tag = CURLY_IR_TAGS_INT; 33 | sexpr->i64 = atoll(ast->value.value); 34 | break; 35 | case LEX_TYPE_FLOAT: 36 | sexpr->tag = CURLY_IR_TAGS_FLOAT; 37 | sexpr->f64 = atof(ast->value.value); 38 | break; 39 | case LEX_TYPE_BOOL: 40 | sexpr->tag = CURLY_IR_TAGS_BOOL; 41 | sexpr->i1 = !strcmp(ast->value.value, "true"); 42 | break; 43 | case LEX_TYPE_SYMBOL: 44 | sexpr->tag = CURLY_IR_TAGS_SYMBOL; 45 | sexpr->symbol = strdup(ast->value.value); 46 | break; 47 | default: 48 | puts("Unimplemented operand!"); 49 | break; 50 | } 51 | 52 | // Infix operators 53 | } else if (ast->value.tag == LEX_TAG_INFIX_OPERATOR) 54 | { 55 | sexpr->tag = CURLY_IR_TAGS_INFIX; 56 | sexpr->infix.left = convert_ast_node(root, ast->children[0], scope); 57 | sexpr->infix.right = convert_ast_node(root, ast->children[1], scope); 58 | sexpr->infix.op = !strcmp(ast->value.value, "*") ? IR_BINOPS_MUL 59 | : !strcmp(ast->value.value, "/") ? IR_BINOPS_DIV 60 | : !strcmp(ast->value.value, "%") ? IR_BINOPS_MOD 61 | : !strcmp(ast->value.value, "+") ? IR_BINOPS_ADD 62 | : !strcmp(ast->value.value, "-") ? IR_BINOPS_SUB 63 | : !strcmp(ast->value.value, "<<") ? IR_BINOPS_BSL 64 | : !strcmp(ast->value.value, ">>") ? IR_BINOPS_BSR 65 | : !strcmp(ast->value.value, "&") ? IR_BINOPS_BITAND 66 | : !strcmp(ast->value.value, "|") ? IR_BINOPS_BITOR 67 | : !strcmp(ast->value.value, "^") ? IR_BINOPS_BITXOR 68 | : !strcmp(ast->value.value, "<") ? IR_BINOPS_CMPLT 69 | : !strcmp(ast->value.value, ">") ? IR_BINOPS_CMPGT 70 | : !strcmp(ast->value.value, "<=") ? IR_BINOPS_CMPLTE 71 | : !strcmp(ast->value.value, ">=") ? IR_BINOPS_CMPGTE 72 | : !strcmp(ast->value.value, "==") ? IR_BINOPS_CMPEQ 73 | : !strcmp(ast->value.value, "!=") ? IR_BINOPS_CMPNEQ 74 | : !strcmp(ast->value.value, "and") ? IR_BINOPS_BOOLAND 75 | : !strcmp(ast->value.value, "or") ? IR_BINOPS_BOOLOR 76 | : !strcmp(ast->value.value, "xor") ? IR_BINOPS_BOOLXOR 77 | : -1; 78 | 79 | // Prefix operators 80 | } else if (!strcmp(ast->value.value, "*") || !strcmp(ast->value.value, "-")) 81 | { 82 | sexpr->tag = CURLY_IR_TAGS_PREFIX; 83 | sexpr->prefix.operand = convert_ast_node(root, ast->children[0], scope); 84 | sexpr->prefix.op = !strcmp(ast->value.value, "*") ? IR_BINOPS_SPAN 85 | : !strcmp(ast->value.value, "-") ? IR_BINOPS_NEG 86 | : -1; 87 | 88 | // Assignments 89 | } else if (ast->value.type == LEX_TYPE_ASSIGN) 90 | { 91 | sexpr->tag = CURLY_IR_TAGS_ASSIGN; 92 | char* name = NULL; 93 | ast_t* head = ast->children[0]; 94 | 95 | if (head->value.type == LEX_TYPE_SYMBOL && head->children_count == 0) 96 | name = head->value.value; 97 | else if (head->value.type == LEX_TYPE_COLON) 98 | { 99 | name = head->children[0]->value.value; 100 | 101 | sexpr->type = generate_type(head->children[1], scope, NULL, NULL); 102 | 103 | // Functions 104 | } else if (head->value.type == LEX_TYPE_SYMBOL) 105 | { 106 | // Get the name of the function 107 | name = head->value.value; 108 | 109 | // Create function 110 | ir_sexpr_func_t* func = malloc(sizeof(ir_sexpr_func_t)); 111 | func->arg_count = head->children_count; 112 | func->args = calloc(func->arg_count, sizeof(ir_sexpr_func_arg_t)); 113 | for (size_t i = 0; i < func->arg_count; i++) 114 | { 115 | func->args[i].name = strdup(head->children[i]->children[0]->value.value); 116 | func->args[i].type = generate_type(head->children[i]->children[1], scope, NULL, NULL); 117 | } 118 | 119 | // Generate body and add function 120 | func->body = convert_ast_node(root, ast->children[1], scope); 121 | list_append_element(root->funcs, root->func_size, root->func_count, ir_sexpr_func_arg_t, func); 122 | 123 | // Create wrapper s expression 124 | ir_sexpr_t* value = malloc(sizeof(ir_sexpr_t)); 125 | value->tag = CURLY_IR_TAGS_FUNC; 126 | value->func_id = root->func_count - 1; 127 | value->type = NULL; // generate_function_type(func, scope) 128 | value->lino = ast->children[1]->value.lino; 129 | value->charpos = ast->children[1]->value.charpos; 130 | value->pos = ast->children[1]->value.pos; 131 | 132 | // Create assignment 133 | sexpr->assign.name = strdup(name); 134 | sexpr->assign.value = value; 135 | return sexpr; 136 | 137 | // TODO attributes, and head/tail 138 | } else puts("Unsupported assignment!"); 139 | 140 | sexpr->assign.name = strdup(name); 141 | sexpr->assign.value = convert_ast_node(root, ast->children[1], scope); 142 | 143 | // Declarations 144 | } else if (ast->value.type == LEX_TYPE_COLON) 145 | { 146 | sexpr->tag = CURLY_IR_TAGS_DECLARE; 147 | sexpr->declare.name = strdup(ast->children[0]->value.value); 148 | 149 | sexpr->type = generate_type(ast->children[1], scope, NULL, NULL); 150 | 151 | // With expressions 152 | } else if (!strcmp(ast->value.value, "with")) 153 | { 154 | sexpr->tag = CURLY_IR_TAGS_LOCAL_SCOPE; 155 | sexpr->local_scope.assign_count = ast->children_count - 1; 156 | sexpr->local_scope.assigns = calloc(sexpr->local_scope.assign_count, sizeof(ir_sexpr_t)); 157 | 158 | for (size_t i = 0; i < sexpr->local_scope.assign_count; i++) 159 | { 160 | sexpr->local_scope.assigns[i] = convert_ast_node(root, ast->children[i], scope); 161 | } 162 | 163 | sexpr->local_scope.value = convert_ast_node(root, ast->children[ast->children_count - 1], scope); 164 | 165 | // If expressions 166 | } else if (!strcmp(ast->value.value, "if")) 167 | { 168 | sexpr->tag = CURLY_IR_TAGS_IF; 169 | sexpr->if_expr.cond = convert_ast_node(root, ast->children[0], scope); 170 | sexpr->if_expr.then = convert_ast_node(root, ast->children[1], scope); 171 | sexpr->if_expr.elsy = convert_ast_node(root, ast->children[2], scope); 172 | 173 | // Unsupported syntax 174 | } else 175 | { 176 | puts("Unsupported syntax!"); 177 | return NULL; 178 | } 179 | 180 | return sexpr; 181 | } 182 | 183 | // init_ir(curly_ir_t*) -> void 184 | // Initialises an ir structure. 185 | void init_ir(curly_ir_t* ir) 186 | { 187 | ir->funcs = NULL; 188 | ir->func_count = 0; 189 | ir->func_size = 0; 190 | ir->expr = NULL; 191 | ir->expr_count = 0; 192 | } 193 | 194 | // convert_ast_to_ir(ast_t*, ir_scope_t*, curly_ir_t*) -> void 195 | // Converts a given ast root to IR. 196 | void convert_ast_to_ir(ast_t* ast, ir_scope_t* scope, curly_ir_t* ir) 197 | { 198 | ir->expr_count = ast->children_count; 199 | ir->expr = calloc(ir->expr_count, sizeof(ir_sexpr_t*)); 200 | 201 | for (size_t i = 0; i < ir->expr_count; i++) 202 | { 203 | ir->expr[i] = convert_ast_node(ir, ast->children[i], scope); 204 | } 205 | } 206 | 207 | // print_ir_sexpr(ir_sexpr_t*, int, bool) -> void 208 | // Prints out an IR S expression to stdout. 209 | void print_ir_sexpr(ir_sexpr_t* sexpr, int indent, bool newline) 210 | { 211 | // Indent and print parenthesis 212 | if (newline) 213 | { 214 | for (int i = 0; i < indent; i++) 215 | printf(" "); 216 | newline = false; 217 | } 218 | printf("("); 219 | 220 | // Ad hoc match expression for printing 221 | switch (sexpr->tag) 222 | { 223 | case CURLY_IR_TAGS_INT: 224 | printf("%li: Int", sexpr->i64); 225 | break; 226 | case CURLY_IR_TAGS_FLOAT: 227 | printf("%.05f: Float", sexpr->f64); 228 | break; 229 | case CURLY_IR_TAGS_BOOL: 230 | printf("%s: Bool", sexpr->i1 ? "true" : "false"); 231 | break; 232 | case CURLY_IR_TAGS_SYMBOL: 233 | printf("%s: %s", sexpr->symbol, sexpr->type != NULL ? sexpr->type->type_name : "(null)"); 234 | break; 235 | case CURLY_IR_TAGS_INFIX: 236 | printf("call(2) "); 237 | switch (sexpr->infix.op) 238 | { 239 | case IR_BINOPS_MUL: 240 | printf("*"); 241 | break; 242 | case IR_BINOPS_DIV: 243 | printf("/"); 244 | break; 245 | case IR_BINOPS_MOD: 246 | printf("%%"); 247 | break; 248 | case IR_BINOPS_ADD: 249 | printf("+"); 250 | break; 251 | case IR_BINOPS_SUB: 252 | printf("-"); 253 | break; 254 | case IR_BINOPS_BSL: 255 | printf("<<"); 256 | break; 257 | case IR_BINOPS_BSR: 258 | printf(">>"); 259 | break; 260 | case IR_BINOPS_BITAND: 261 | printf("&"); 262 | break; 263 | case IR_BINOPS_BITOR: 264 | printf("|"); 265 | break; 266 | case IR_BINOPS_BITXOR: 267 | printf("^"); 268 | break; 269 | case IR_BINOPS_CMPEQ: 270 | printf("=="); 271 | break; 272 | case IR_BINOPS_CMPNEQ: 273 | printf("!="); 274 | break; 275 | case IR_BINOPS_CMPLT: 276 | printf("<"); 277 | break; 278 | case IR_BINOPS_CMPLTE: 279 | printf("<="); 280 | break; 281 | case IR_BINOPS_CMPGT: 282 | printf(">"); 283 | break; 284 | case IR_BINOPS_CMPGTE: 285 | printf(">="); 286 | break; 287 | case IR_BINOPS_CMPIN: 288 | printf("in"); 289 | break; 290 | case IR_BINOPS_BOOLAND: 291 | printf("and"); 292 | break; 293 | case IR_BINOPS_BOOLOR: 294 | printf("or"); 295 | break; 296 | case IR_BINOPS_BOOLXOR: 297 | printf("xor"); 298 | break; 299 | default: 300 | printf("???"); 301 | break; 302 | } 303 | printf(" "); 304 | print_ir_sexpr(sexpr->infix.left, indent, false); 305 | printf(" "); 306 | print_ir_sexpr(sexpr->infix.right, indent, false); 307 | break; 308 | case CURLY_IR_TAGS_PREFIX: 309 | printf("call(1) "); 310 | switch (sexpr->prefix.op) 311 | { 312 | case IR_BINOPS_SPAN: 313 | printf("*"); 314 | break; 315 | case IR_BINOPS_NEG: 316 | printf("-"); 317 | break; 318 | default: 319 | printf("???"); 320 | break; 321 | } 322 | printf(" "); 323 | print_ir_sexpr(sexpr->prefix.operand, indent, false); 324 | break; 325 | case CURLY_IR_TAGS_ASSIGN: 326 | printf("set %s\n", sexpr->assign.name); 327 | print_ir_sexpr(sexpr->assign.value, indent + 1, true); 328 | puts(""); 329 | newline = true; 330 | break; 331 | case CURLY_IR_TAGS_DECLARE: 332 | printf("declare %s: %s", sexpr->declare.name, sexpr->type != NULL ? sexpr->type->type_name : "(null)"); 333 | break; 334 | case CURLY_IR_TAGS_LOCAL_SCOPE: 335 | puts("scope"); 336 | for (size_t i = 0; i < sexpr->local_scope.assign_count; i++) 337 | { 338 | print_ir_sexpr(sexpr->local_scope.assigns[i], indent + 1, true); 339 | puts(""); 340 | } 341 | print_ir_sexpr(sexpr->local_scope.value, indent + 1, true); 342 | puts(""); 343 | newline = true; 344 | break; 345 | case CURLY_IR_TAGS_IF: 346 | printf("if "); 347 | print_ir_sexpr(sexpr->if_expr.cond, indent, false); 348 | puts(""); 349 | print_ir_sexpr(sexpr->if_expr.then, indent + 1, true); 350 | puts(""); 351 | print_ir_sexpr(sexpr->if_expr.elsy, indent + 1, true); 352 | puts(""); 353 | newline = true; 354 | break; 355 | case CURLY_IR_TAGS_FUNC: 356 | printf("func-ref %li: (func)", sexpr->func_id); 357 | break; 358 | default: 359 | printf("???"); 360 | } 361 | 362 | // Indent and print parenthesis 363 | if (newline) 364 | for (int i = 0; i < indent; i++) 365 | printf(" "); 366 | printf(")"); 367 | } 368 | 369 | // print_ir(curly_ir_t) -> void 370 | // Prints out IR to stdout. 371 | void print_ir(curly_ir_t ir) 372 | { 373 | // Function parenthesis 374 | if (ir.func_count > 0) 375 | puts("("); 376 | 377 | // Print out functions 378 | for (size_t i = 0; i < ir.func_count; i++) 379 | { 380 | printf(" (\\"); 381 | 382 | for (size_t j = 0; j < ir.funcs[i]->arg_count; j++) 383 | { 384 | printf(" %s: type", ir.funcs[i]->args[j].name); 385 | } 386 | puts("."); 387 | 388 | print_ir_sexpr(ir.funcs[i]->body, 2, true); 389 | 390 | puts("\n )"); 391 | } 392 | 393 | // Function parenthesis 394 | if (ir.func_count > 0) 395 | puts(")"); 396 | 397 | // Print out expressions 398 | for (size_t i = 0; i < ir.expr_count; i++) 399 | { 400 | print_ir_sexpr(ir.expr[i], 0, true); 401 | puts(""); 402 | } 403 | } 404 | 405 | // clean_ir_sexpr(ir_sexpr_t*) -> void 406 | // Cleans up an IR S expression. 407 | void clean_ir_sexpr(ir_sexpr_t* sexpr) 408 | { 409 | switch (sexpr->tag) 410 | { 411 | case CURLY_IR_TAGS_SYMBOL: 412 | free(sexpr->symbol); 413 | break; 414 | case CURLY_IR_TAGS_INFIX: 415 | clean_ir_sexpr(sexpr->infix.left); 416 | clean_ir_sexpr(sexpr->infix.right); 417 | break; 418 | case CURLY_IR_TAGS_PREFIX: 419 | clean_ir_sexpr(sexpr->prefix.operand); 420 | break; 421 | case CURLY_IR_TAGS_ASSIGN: 422 | free(sexpr->assign.name); 423 | clean_ir_sexpr(sexpr->assign.value); 424 | break; 425 | case CURLY_IR_TAGS_DECLARE: 426 | free(sexpr->declare.name); 427 | break; 428 | case CURLY_IR_TAGS_LOCAL_SCOPE: 429 | for (size_t i = 0; i < sexpr->local_scope.assign_count; i++) 430 | { 431 | clean_ir_sexpr(sexpr->local_scope.assigns[i]); 432 | } 433 | free(sexpr->local_scope.assigns); 434 | clean_ir_sexpr(sexpr->local_scope.value); 435 | break; 436 | case CURLY_IR_TAGS_IF: 437 | clean_ir_sexpr(sexpr->if_expr.cond); 438 | clean_ir_sexpr(sexpr->if_expr.then); 439 | clean_ir_sexpr(sexpr->if_expr.elsy); 440 | break; 441 | default: 442 | break; 443 | } 444 | 445 | free(sexpr); 446 | } 447 | 448 | // clean_ir(curly_ir_t*) -> void 449 | // Cleans up Curly IR. 450 | void clean_ir(curly_ir_t* ir) 451 | { 452 | for (size_t i = 0; i < ir->expr_count; i++) 453 | { 454 | clean_ir_sexpr(ir->expr[i]); 455 | } 456 | 457 | free(ir->expr); 458 | ir->expr = NULL; 459 | ir->expr_count = 0; 460 | } 461 | 462 | // clean_functions(curly_ir_t*) -> void 463 | // Cleans up a list of functions. 464 | void clean_functions(curly_ir_t* ir) 465 | { 466 | for (size_t i = 0; i < ir->func_count; i++) 467 | { 468 | for (size_t j = 0; j < ir->funcs[i]->arg_count; j++) 469 | { 470 | free(ir->funcs[i]->args[j].name); 471 | } 472 | free(ir->funcs[i]->args); 473 | clean_ir_sexpr(ir->funcs[i]->body); 474 | free(ir->funcs[i]); 475 | } 476 | free(ir->funcs); 477 | ir->funcs = NULL; 478 | ir->func_count = 0; 479 | ir->func_size = 0; 480 | } 481 | -------------------------------------------------------------------------------- /src/compiler/frontend/ir/generate_ir.h: -------------------------------------------------------------------------------- 1 | // 2 | // ir 3 | // generate_ir.h: Header file for generate_ir.c. 4 | // 5 | // Created by jenra. 6 | // Created on October 12 2020. 7 | // 8 | 9 | #ifndef GENERATE_IR_H 10 | #define GENERATE_IR_H 11 | 12 | #include 13 | 14 | #include "../correctness/types.h" 15 | #include "../parse/ast.h" 16 | 17 | // Represents the tag of an IR S expression. 18 | typedef enum 19 | { 20 | CURLY_IR_TAGS_INT, 21 | CURLY_IR_TAGS_FLOAT, 22 | CURLY_IR_TAGS_BOOL, 23 | CURLY_IR_TAGS_FUNC, 24 | CURLY_IR_TAGS_SYMBOL, 25 | CURLY_IR_TAGS_INFIX, 26 | CURLY_IR_TAGS_PREFIX, 27 | CURLY_IR_TAGS_ASSIGN, 28 | CURLY_IR_TAGS_DECLARE, 29 | CURLY_IR_TAGS_LOCAL_SCOPE, 30 | CURLY_IR_TAGS_IF 31 | } ir_types_t; 32 | 33 | // Represents an infix operation. 34 | typedef enum 35 | { 36 | IR_BINOPS_NEG, 37 | IR_BINOPS_MUL, 38 | IR_BINOPS_DIV, 39 | IR_BINOPS_MOD, 40 | IR_BINOPS_ADD, 41 | IR_BINOPS_SUB, 42 | IR_BINOPS_BSL, 43 | IR_BINOPS_BSR, 44 | IR_BINOPS_BITAND, 45 | IR_BINOPS_BITOR, 46 | IR_BINOPS_BITXOR, 47 | IR_BINOPS_CMPEQ, 48 | IR_BINOPS_CMPNEQ, 49 | IR_BINOPS_CMPLT, 50 | IR_BINOPS_CMPLTE, 51 | IR_BINOPS_CMPGT, 52 | IR_BINOPS_CMPGTE, 53 | IR_BINOPS_CMPIN, 54 | IR_BINOPS_BOOLAND, 55 | IR_BINOPS_BOOLOR, 56 | IR_BINOPS_BOOLXOR, 57 | IR_BINOPS_SPAN 58 | } ir_binops_t; 59 | 60 | typedef struct s_ir_sexpr ir_sexpr_t; 61 | 62 | // Function argument 63 | typedef struct 64 | { 65 | type_t* type; 66 | char* name; 67 | } ir_sexpr_func_arg_t; 68 | 69 | // A function 70 | typedef struct 71 | { 72 | ir_sexpr_func_arg_t* args; 73 | size_t arg_count; 74 | 75 | ir_sexpr_t* body; 76 | } ir_sexpr_func_t; 77 | 78 | // An S expression in IR code. 79 | typedef struct s_ir_sexpr 80 | { 81 | // The type of the expression. 82 | type_t* type; 83 | 84 | // The position in the string the expression was found at. 85 | size_t pos; 86 | int lino; 87 | int charpos; 88 | 89 | // The tag for the tagged union. 90 | ir_types_t tag; 91 | 92 | // The value of the expression. 93 | union 94 | { 95 | int64_t i64; 96 | double f64; 97 | bool i1; 98 | char* symbol; 99 | 100 | // Infix expressions. 101 | struct 102 | { 103 | ir_binops_t op; 104 | struct s_ir_sexpr* left; 105 | struct s_ir_sexpr* right; 106 | } infix; 107 | 108 | // Prefix expressions. 109 | struct 110 | { 111 | ir_binops_t op; 112 | struct s_ir_sexpr* operand; 113 | } prefix; 114 | 115 | // Assignments. 116 | struct 117 | { 118 | char* name; 119 | struct s_ir_sexpr* value; 120 | } assign; 121 | 122 | // Declarations. 123 | struct 124 | { 125 | char* name; 126 | } declare; 127 | 128 | // Local scopes. 129 | struct 130 | { 131 | struct s_ir_sexpr** assigns; 132 | size_t assign_count; 133 | 134 | struct s_ir_sexpr* value; 135 | } local_scope; 136 | 137 | // If expressions. 138 | struct 139 | { 140 | struct s_ir_sexpr* cond; 141 | struct s_ir_sexpr* then; 142 | struct s_ir_sexpr* elsy; 143 | } if_expr; 144 | 145 | // Functions 146 | size_t func_id; 147 | }; 148 | } ir_sexpr_t; 149 | 150 | // Represents the IR. 151 | typedef struct 152 | { 153 | // The map of all functions. 154 | ir_sexpr_func_t** funcs; 155 | size_t func_count; 156 | size_t func_size; 157 | 158 | // The list of all expressions. 159 | ir_sexpr_t** expr; 160 | size_t expr_count; 161 | } curly_ir_t; 162 | 163 | // init_ir(curly_ir_t*) -> void 164 | // Initialises an ir structure. 165 | void init_ir(curly_ir_t* ir); 166 | 167 | // convert_ast_to_ir(ast_t*, ir_scope_t*, curly_ir_t*) -> void 168 | // Converts a given ast root to IR. 169 | void convert_ast_to_ir(ast_t* ast, ir_scope_t* scope, curly_ir_t* ir); 170 | 171 | // print_ir(curly_ir_t) -> void 172 | // Prints out IR to stdout. 173 | void print_ir(curly_ir_t ir); 174 | 175 | // clean_ir(curly_ir_t*) -> void 176 | // Cleans up Curly IR. 177 | void clean_ir(curly_ir_t* ir); 178 | 179 | // clean_functions(curly_ir_t*) -> void 180 | // Cleans up a list of functions. 181 | void clean_functions(curly_ir_t* ir); 182 | 183 | #endif /* GENERATE_IR_H */ 184 | -------------------------------------------------------------------------------- /src/compiler/frontend/parse/ast.c: -------------------------------------------------------------------------------- 1 | // 2 | // parse 3 | // ast.c: Implements an abstract syntax tree. 4 | // 5 | // Created by jenra. 6 | // Created on August 27 2020. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "ast.h" 13 | 14 | // init_ast(token_t) -> ast_t* 15 | // Initialises an ast. 16 | ast_t* init_ast(token_t token) 17 | { 18 | ast_t* ast = malloc(sizeof(ast_t)); 19 | ast->value = token; 20 | ast->value.value = token.value != NULL ? strdup(token.value) : NULL; 21 | ast->children = NULL; 22 | ast->children_count = 0; 23 | ast->children_size = 0; 24 | return ast; 25 | } 26 | 27 | // asts_equal(ast_t*, ast_t*) -> bool 28 | // Returns whether or not the two given ast nodes are equal. 29 | bool asts_equal(ast_t* a1, ast_t* a2) 30 | { 31 | // The ast nodes are equal if they're both null or the same object 32 | if (a1 == NULL || a2 == NULL) 33 | return a1 == a2; 34 | else if (a1 == a2) 35 | return true; 36 | 37 | // Check the token 38 | else if (a1->value.type != a2->value.type || a1->value.tag != a2->value.tag || strcmp(a1->value.value, a2->value.value)) 39 | return false; 40 | 41 | // The two ast nodes must have the same number of children to be equal 42 | else if (a1->children_count != a2->children_count) 43 | return false; 44 | 45 | // Check that the child nodes are equal 46 | for (size_t i = 0; i < a1->children_count; i++) 47 | { 48 | bool equal = asts_equal(a1->children[i], a2->children[i]); 49 | if (!equal) return false; 50 | } 51 | 52 | // The ast nodes are equal 53 | return true; 54 | } 55 | 56 | // print_ast_helper(ast_t*, int) -> void 57 | // Helps to print an ast node. 58 | void print_ast_helper(ast_t* ast, int level) 59 | { 60 | if (ast == NULL) 61 | return; 62 | 63 | // Tab out the ast node 64 | for (int i = 0; i < level; i++) 65 | { 66 | putc('\t', stdout); 67 | } 68 | if (level > 0) 69 | printf("| "); 70 | 71 | // Print out the token 72 | printf("%s (%i:%i/%i)\n", ast->value.value, ast->value.lino, ast->value.charpos, ast->value.type); 73 | 74 | // Print out children if there are any 75 | for (size_t i = 0; i < ast->children_count; i++) 76 | { 77 | print_ast_helper(ast->children[i], level + 1); 78 | } 79 | } 80 | 81 | // print_ast(ast_t*) -> void 82 | // Prints an ast. 83 | void print_ast(ast_t* ast) { print_ast_helper(ast, 0); } 84 | 85 | // clean_ast(ast_t*) -> void 86 | // Deletes an ast. 87 | void clean_ast(ast_t* ast) 88 | { 89 | // Don't do anything if the ast node is null 90 | if (ast == NULL) 91 | return; 92 | 93 | // Delete the children 94 | for (size_t i = 0; i < ast->children_count; i++) 95 | { 96 | clean_ast(ast->children[i]); 97 | } 98 | 99 | // Delete the fields 100 | free(ast->value.value); 101 | free(ast->children); 102 | free(ast); 103 | } 104 | 105 | // clean_parse_result(parse_result_t) -> void 106 | // Deletes a parse result's data. 107 | void clean_parse_result(parse_result_t result) 108 | { 109 | if (result.succ) 110 | // Delete ast node 111 | clean_ast(result.ast); 112 | else if (result.error != NULL) 113 | { 114 | // Free error fields 115 | free(result.error->expected); 116 | free(result.error->value.value); 117 | free(result.error); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/compiler/frontend/parse/ast.h: -------------------------------------------------------------------------------- 1 | // 2 | // parse 3 | // ast.h: Header file for ast.c. 4 | // 5 | // Created by jenra. 6 | // Created on August 27 2020. 7 | // 8 | 9 | #ifndef AST_H 10 | #define AST_H 11 | 12 | #include 13 | 14 | #include "lexer.h" 15 | 16 | #include "../correctness/types.h" 17 | 18 | // Represents a parsing error. 19 | typedef struct 20 | { 21 | // Whether the error should force parsing to halt or not. 22 | bool fatal; 23 | 24 | // The token that caused the error. 25 | token_t value; 26 | 27 | // The error message. 28 | char* expected; 29 | } error_t; 30 | 31 | // Represents an abstract syntax tree node. 32 | typedef struct s_ast 33 | { 34 | type_t* type; 35 | 36 | // The token the ast node represents. 37 | token_t value; 38 | 39 | // The list of children of the ast node. 40 | struct s_ast** children; 41 | size_t children_count; 42 | size_t children_size; 43 | } ast_t; 44 | 45 | // Represents the result of parsing a string. 46 | typedef struct 47 | { 48 | // Whether the parse was successful or failed. 49 | bool succ; 50 | 51 | // The value of the parsing result. 52 | union 53 | { 54 | ast_t* ast; 55 | error_t* error; 56 | }; 57 | } parse_result_t; 58 | 59 | // init_ast(token_t) -> ast_t* 60 | // Initialises an ast. 61 | ast_t* init_ast(token_t token); 62 | 63 | // asts_equal(ast_t*, ast_t*) -> bool 64 | // Returns whether or not the two given ast nodes are equal. 65 | bool asts_equal(ast_t* a1, ast_t* a2); 66 | 67 | // print_ast(ast_t*) -> void 68 | // Prints an ast. 69 | void print_ast(ast_t* ast); 70 | 71 | // clean_ast(ast_t*) -> void 72 | // Deletes an ast. 73 | void clean_ast(ast_t* ast); 74 | 75 | // clean_parse_result(parse_result_t) -> void 76 | // Deletes a parse result's data. 77 | void clean_parse_result(parse_result_t result); 78 | 79 | #endif /* AST_H */ 80 | -------------------------------------------------------------------------------- /src/compiler/frontend/parse/lexer.c: -------------------------------------------------------------------------------- 1 | // 2 | // parse 3 | // lexer.c: Implements the lexer for the language. 4 | // 5 | // Created by jenra. 6 | // Created on July 27 2020. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "lexer.h" 13 | #include "../../../utils/list.h" 14 | 15 | // init_lexer(lexer_t*, char*) -> void 16 | // Initialises a lexer. 17 | void init_lexer(lexer_t* lex, char* string) 18 | { 19 | lex->string = strdup(string); 20 | lex->pos = 0; 21 | lex->lino = 1; 22 | lex->charpos = 0; 23 | lex->size = 16; 24 | lex->tokens = calloc(lex->size, sizeof(token_t)); 25 | lex->count = 0; 26 | lex->token_pos = 0; 27 | } 28 | 29 | // lex_type_string(lex_type_t) -> char* 30 | // Converts a lex_type_t into a string. 31 | char* lex_type_string(lex_type_t type) 32 | { 33 | switch (type) 34 | { 35 | case LEX_TYPE_NONE: 36 | return "none"; 37 | case LEX_TYPE_EOF: 38 | return "EOF"; 39 | case LEX_TYPE_INT: 40 | return "int"; 41 | case LEX_TYPE_FLOAT: 42 | return "float"; 43 | case LEX_TYPE_LGROUP: 44 | return "left grouping"; 45 | case LEX_TYPE_RGROUP: 46 | return "right grouping"; 47 | case LEX_TYPE_COLON: 48 | return "':'"; 49 | case LEX_TYPE_NEWLINE: 50 | return "newline"; 51 | case LEX_TYPE_COMMA: 52 | return "','"; 53 | case LEX_TYPE_SYMBOL: 54 | return "symbol"; 55 | case LEX_TYPE_BOOL: 56 | return "'true' or 'false'"; 57 | case LEX_TYPE_KEYWORD: 58 | return "keyword"; 59 | case LEX_TYPE_ASSIGN: 60 | return "'='"; 61 | case LEX_TYPE_COMPARE: 62 | return "comparison operator"; 63 | case LEX_TYPE_DOT: 64 | return "'.'"; 65 | case LEX_TYPE_RANGE: 66 | return "'..'"; 67 | case LEX_TYPE_MULDIV: 68 | return "'*' or '/'"; 69 | case LEX_TYPE_ADDSUB: 70 | return "'+' or '-'"; 71 | case LEX_TYPE_BITSHIFT: 72 | return "'>>' or '<<'"; 73 | case LEX_TYPE_AND: 74 | return "'and'"; 75 | case LEX_TYPE_OR: 76 | return "'or'"; 77 | case LEX_TYPE_XOR: 78 | return "'xor'"; 79 | case LEX_TYPE_AMP: 80 | return "'&'"; 81 | case LEX_TYPE_BAR: 82 | return "'|'"; 83 | case LEX_TYPE_CARET: 84 | return "'^'"; 85 | case LEX_TYPE_STRING: 86 | return "string"; 87 | case LEX_TYPE_APPLICATION: 88 | return "application"; 89 | case LEX_TYPE_RIGHT_ARROW: 90 | return "->"; 91 | case LEX_TYPE_THICC_ARROW: 92 | return "=>"; 93 | default: 94 | return "type"; 95 | } 96 | } 97 | 98 | // lex_skip_whitespace(lexer_t*) -> void 99 | // Skips whitespace before a token. 100 | void lex_skip_whitespace(lexer_t* lex) 101 | { 102 | char c; 103 | bool comment = false; 104 | 105 | while (true) 106 | { 107 | // Get the next character 108 | c = lex->string[lex->pos]; 109 | if (c == '\0') break; 110 | 111 | // Check for newline 112 | if (c == '\\' && lex->string[lex->pos + 1] == '\n') 113 | { 114 | lex->pos += 2; 115 | lex->charpos = 0; 116 | lex->lino++; 117 | comment = false; 118 | 119 | // Check for comments ending 120 | } else if (comment && lex->string[lex->pos] == '\n') 121 | { 122 | comment = false; 123 | break; 124 | 125 | // Check for whitespace 126 | } else if (comment || c == ' ' || c == '\t' || c == '\r' || c == '#') 127 | { 128 | lex->pos++; 129 | lex->charpos++; 130 | comment = comment || c == '#'; 131 | 132 | // Everything else should not be skipped 133 | } else break; 134 | } 135 | } 136 | 137 | // lex_next(lexer_t*) -> token_t* 138 | // Consumes the next token in the string. 139 | token_t* lex_next(lexer_t* lex) 140 | { 141 | // Return the next token in the list if it was previously generated 142 | if (lex->token_pos < lex->count) 143 | return lex->tokens + lex->token_pos++; 144 | 145 | // Skip whitespace 146 | lex_skip_whitespace(lex); 147 | 148 | // Set up 149 | size_t i = lex->pos; 150 | token_t token; 151 | char c; 152 | bool iter = true; 153 | 154 | // Initialise the token 155 | token.type = LEX_TYPE_NONE; 156 | token.tag = LEX_TAG_NONE; 157 | token.value = NULL; 158 | token.pos = lex->pos; 159 | token.lino = lex->lino; 160 | token.charpos = lex->charpos; 161 | 162 | // Iterate over the string 163 | while (iter) 164 | { 165 | c = lex->string[i]; 166 | 167 | switch (token.type) 168 | { 169 | case LEX_TYPE_NONE: 170 | // Break if a token type has not been assigned 171 | if (i != lex->pos) 172 | iter = false; 173 | 174 | // Determine the type of the token 175 | else if (c == '\0') 176 | { 177 | token.type = LEX_TYPE_EOF; 178 | iter = false; 179 | } else if ('0' <= c && c <= '9') 180 | { 181 | token.type = LEX_TYPE_INT; 182 | token.tag = LEX_TAG_OPERAND; 183 | } else if (c == '(' || c == '[' || c == '{') 184 | { 185 | token.type = LEX_TYPE_LGROUP; 186 | token.tag = LEX_TAG_OPERATOR; 187 | } else if (c == ')' || c == ']' || c == '}') 188 | { 189 | token.type = LEX_TYPE_RGROUP; 190 | token.tag = LEX_TAG_OPERATOR; 191 | } else if (c == ':') 192 | { 193 | token.type = LEX_TYPE_COLON; 194 | token.tag = LEX_TAG_OPERATOR; 195 | } else if (c == '\n') 196 | { 197 | token.type = LEX_TYPE_NEWLINE; 198 | } else if (c == ',') 199 | { 200 | token.type = LEX_TYPE_COMMA; 201 | token.tag = LEX_TAG_OPERATOR; 202 | } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_' || c == '@' || c == '$') 203 | { 204 | token.type = LEX_TYPE_SYMBOL; 205 | token.tag = LEX_TAG_OPERAND; 206 | } else if (c == '=') 207 | { 208 | token.type = LEX_TYPE_ASSIGN; 209 | token.tag = LEX_TAG_OPERATOR; 210 | } else if (c == '<' || c == '>' || c == '!') 211 | { 212 | token.type = LEX_TYPE_COMPARE; 213 | token.tag = LEX_TAG_INFIX_OPERATOR; 214 | } else if (c == '.') 215 | { 216 | token.type = LEX_TYPE_DOT; 217 | token.tag = LEX_TAG_INFIX_OPERATOR; 218 | } else if (c == '*' || c == '/' || c == '%') 219 | { 220 | token.type = LEX_TYPE_MULDIV; 221 | token.tag = LEX_TAG_INFIX_OPERATOR; 222 | } else if (c == '+' || c == '-') 223 | { 224 | token.type = LEX_TYPE_ADDSUB; 225 | token.tag = LEX_TAG_INFIX_OPERATOR; 226 | } else if (c == '"') 227 | { 228 | token.type = LEX_TYPE_STRING; 229 | token.tag = LEX_TAG_OPERAND; 230 | } else if (c == '&') 231 | { 232 | token.type = LEX_TYPE_AMP; 233 | token.tag = LEX_TAG_INFIX_OPERATOR; 234 | } else if (c == '|') 235 | { 236 | token.type = LEX_TYPE_BAR; 237 | token.tag = LEX_TAG_INFIX_OPERATOR; 238 | } else if (c == '^') 239 | { 240 | token.type = LEX_TYPE_CARET; 241 | token.tag = LEX_TAG_INFIX_OPERATOR; 242 | } 243 | break; 244 | case LEX_TYPE_INT: 245 | // Turn ints into floats if necessary 246 | if (c == '.') 247 | token.type = LEX_TYPE_FLOAT; 248 | 249 | // Assert all characters in the token are digits 250 | else if (!('0' <= c && c <= '9')) 251 | iter = false; 252 | break; 253 | case LEX_TYPE_FLOAT: 254 | // Assert the float does not end with a dot 255 | if (lex->string[i - 1] == '.' && !('0' <= c && c <= '9')) 256 | { 257 | token.type = LEX_TYPE_NONE; 258 | token.tag = LEX_TAG_NONE; 259 | } 260 | 261 | // Assert all characters after the . in the token are digits 262 | else if (!('0' <= c && c <= '9')) 263 | iter = false; 264 | break; 265 | case LEX_TYPE_SYMBOL: 266 | // Assert only valid characters are in the symbol 267 | if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '\'')) 268 | iter = false; 269 | break; 270 | case LEX_TYPE_ASSIGN: 271 | // If there's another equal sign, then it's == (equal to) 272 | if (c == '=') 273 | { 274 | token.type = LEX_TYPE_COMPARE; 275 | token.tag = LEX_TAG_INFIX_OPERATOR; 276 | 277 | // Thicc arrows 278 | } else if (c == '>') 279 | { 280 | token.type = LEX_TYPE_THICC_ARROW; 281 | } else iter = false; 282 | break; 283 | case LEX_TYPE_COMPARE: 284 | // << and >> are operators 285 | if ((c == '<' || c == '>') && lex->string[i - 1] == c) 286 | token.type = LEX_TYPE_BITSHIFT; 287 | // != is a comparison operator 288 | else if (lex->string[i - 1] == '!' && c != '=') 289 | token.type = LEX_TYPE_NONE; 290 | // <= and >= are comparison operators 291 | else if ((lex->string[i - 1] != '<' && lex->string[i - 1] != '>' && lex->string[i - 1] != '!') || c != '=') 292 | iter = false; 293 | break; 294 | case LEX_TYPE_DOT: 295 | // .. is the range operator 296 | if (c == '.') 297 | { 298 | token.type = LEX_TYPE_RANGE; 299 | token.tag = LEX_TAG_OPERATOR; 300 | } else iter = false; 301 | break; 302 | case LEX_TYPE_STRING: 303 | // Strings end at an unescaped quotation mark 304 | if (lex->string[i - 1] != '\\' && c == '"') 305 | { 306 | iter = false; 307 | i++; 308 | // Strings that never end are an error 309 | } else if (c == '\0') 310 | { 311 | token.type = LEX_TYPE_NONE; 312 | token.tag = LEX_TAG_NONE; 313 | iter = false; 314 | } 315 | break; 316 | case LEX_TYPE_NEWLINE: 317 | // Append all newlines to the token 318 | lex_skip_whitespace(lex); 319 | i = lex->pos; 320 | if (lex->string[i] != '\n') 321 | iter = false; 322 | else 323 | { 324 | lex->lino++; 325 | lex->charpos = -1; 326 | lex->pos++; 327 | } 328 | break; 329 | case LEX_TYPE_ADDSUB: 330 | // Right arrows 331 | if (lex->string[i - 1] == '-' && c == '>') 332 | { 333 | token.type = LEX_TYPE_RIGHT_ARROW; 334 | token.tag = LEX_TAG_OPERATOR; 335 | } else iter = false; 336 | break; 337 | 338 | // These token types are only one character long 339 | case LEX_TYPE_LGROUP: 340 | case LEX_TYPE_RGROUP: 341 | case LEX_TYPE_COLON: 342 | case LEX_TYPE_COMMA: 343 | case LEX_TYPE_RANGE: 344 | case LEX_TYPE_MULDIV: 345 | case LEX_TYPE_BITSHIFT: 346 | default: 347 | iter = false; 348 | break; 349 | } 350 | 351 | // Increment appropriate variables if iterating 352 | if (iter) 353 | { 354 | i++; 355 | lex->charpos++; 356 | } 357 | } 358 | 359 | // Copy the value of the token into the token 360 | size_t length = i - lex->pos; 361 | token.value = calloc(length + 1, 1); 362 | strncpy(token.value, lex->string + lex->pos, length); 363 | lex->pos = i; 364 | 365 | // If the token is a symbol, check if the symbol is actually a keyword 366 | if (token.type == LEX_TYPE_SYMBOL) 367 | { 368 | if (!strcmp(token.value, "with") 369 | || !strcmp(token.value, "for") 370 | || !strcmp(token.value, "some") 371 | || !strcmp(token.value, "all") 372 | || !strcmp(token.value, "if") 373 | || !strcmp(token.value, "then") 374 | || !strcmp(token.value, "else") 375 | || !strcmp(token.value, "where") 376 | || !strcmp(token.value, "pass") 377 | || !strcmp(token.value, "stop") 378 | || !strcmp(token.value, "type") 379 | || !strcmp(token.value, "enum") 380 | || !strcmp(token.value, "class") 381 | || !strcmp(token.value, "match") 382 | || !strcmp(token.value, "to")) 383 | { 384 | token.type = LEX_TYPE_KEYWORD; 385 | token.tag = LEX_TAG_OPERATOR; 386 | } else if (!strcmp(token.value, "true") 387 | || !strcmp(token.value, "false")) 388 | { 389 | token.type = LEX_TYPE_BOOL; 390 | } else if (!strcmp(token.value, "in")) 391 | { 392 | // in is treated as an infix operator on the same level as comparing operators 393 | token.type = LEX_TYPE_COMPARE; 394 | token.tag = LEX_TAG_INFIX_OPERATOR; 395 | } else if (!strcmp(token.value, "and")) 396 | { 397 | token.type = LEX_TYPE_AND; 398 | token.tag = LEX_TAG_INFIX_OPERATOR; 399 | } else if (!strcmp(token.value, "or")) 400 | { 401 | token.type = LEX_TYPE_OR; 402 | token.tag = LEX_TAG_INFIX_OPERATOR; 403 | } else if (!strcmp(token.value, "xor")) 404 | { 405 | token.type = LEX_TYPE_XOR; 406 | token.tag = LEX_TAG_INFIX_OPERATOR; 407 | } 408 | } 409 | 410 | // Append the token to the list of tokens 411 | list_append_element(lex->tokens, lex->size, lex->count, token_t, token); 412 | lex->token_pos++; 413 | 414 | // Return a pointer to the token 415 | return lex->tokens + lex->count - 1; 416 | } 417 | 418 | // cleanup_lexer(lexer_t*) -> void 419 | // Frees memory associated with the lexer. 420 | void cleanup_lexer(lexer_t* lex) 421 | { 422 | free(lex->string); 423 | 424 | for (size_t i = 0; i < lex->count; i++) 425 | { 426 | free(lex->tokens[i].value); 427 | } 428 | 429 | free(lex->tokens); 430 | } 431 | -------------------------------------------------------------------------------- /src/compiler/frontend/parse/lexer.h: -------------------------------------------------------------------------------- 1 | // 2 | // parse 3 | // lexer.h: Header file for lexer.c. 4 | // 5 | // Created by jenra. 6 | // Created on July 27 2020. 7 | // 8 | 9 | #ifndef LEXER_H 10 | #define LEXER_H 11 | 12 | #include 13 | 14 | typedef enum 15 | { 16 | LEX_TAG_NONE, 17 | LEX_TAG_OPERAND, 18 | LEX_TAG_OPERATOR, 19 | LEX_TAG_INFIX_OPERATOR 20 | } lex_tag_t; 21 | 22 | typedef enum 23 | { 24 | LEX_TYPE_NONE, 25 | LEX_TYPE_EOF, 26 | LEX_TYPE_INT, 27 | LEX_TYPE_FLOAT, 28 | LEX_TYPE_LGROUP, 29 | LEX_TYPE_RGROUP, 30 | LEX_TYPE_COLON, 31 | LEX_TYPE_NEWLINE, 32 | LEX_TYPE_COMMA, 33 | LEX_TYPE_SYMBOL, 34 | LEX_TYPE_KEYWORD, 35 | LEX_TYPE_BOOL, 36 | LEX_TYPE_ASSIGN, 37 | LEX_TYPE_COMPARE, 38 | LEX_TYPE_DOT, 39 | LEX_TYPE_RANGE, 40 | LEX_TYPE_MULDIV, 41 | LEX_TYPE_ADDSUB, 42 | LEX_TYPE_BITSHIFT, 43 | LEX_TYPE_AND, 44 | LEX_TYPE_OR, 45 | LEX_TYPE_XOR, 46 | LEX_TYPE_AMP, 47 | LEX_TYPE_BAR, 48 | LEX_TYPE_CARET, 49 | LEX_TYPE_STRING, 50 | LEX_TYPE_APPLICATION, 51 | LEX_TYPE_RIGHT_ARROW, 52 | LEX_TYPE_THICC_ARROW 53 | } lex_type_t; 54 | 55 | // Represents a token. 56 | typedef struct 57 | { 58 | // The type of the token/ 59 | lex_type_t type; 60 | 61 | // The tag of the token; ie, whether it's an operand, operator, grouping symbol, et cetera. 62 | lex_tag_t tag; 63 | 64 | // The value of the token. 65 | char* value; 66 | 67 | // The position the token was found. 68 | size_t pos; 69 | int lino; 70 | int charpos; 71 | } token_t; 72 | 73 | // Represents the current state of the lexer. 74 | typedef struct 75 | { 76 | // The string being parsed. 77 | char* string; 78 | 79 | // The current position of the lexer. 80 | size_t pos; 81 | int lino; 82 | int charpos; 83 | 84 | // The list of tokens already parsed. 85 | token_t* tokens; 86 | size_t count; 87 | size_t size; 88 | 89 | // The current position in the list of tokens. 90 | size_t token_pos; 91 | } lexer_t; 92 | 93 | // init_lexer(lexer_t*, char*) -> void 94 | // Initialises a lexer. 95 | void init_lexer(lexer_t* lex, char* string); 96 | 97 | // lex_type_string(lex_type_t) -> char* 98 | // Converts a lex_type_t into a string. 99 | char* lex_type_string(lex_type_t type); 100 | 101 | // lex_next(lexer_t*) -> token_t* 102 | // Consumes the next token in the string. 103 | token_t* lex_next(lexer_t* lex); 104 | 105 | // cleanup_lexer(lexer_t*) -> void 106 | // Frees memory associated with the lexer. 107 | void cleanup_lexer(lexer_t* lex); 108 | 109 | #endif /* LEXER_H */ 110 | -------------------------------------------------------------------------------- /src/compiler/frontend/parse/parser.c: -------------------------------------------------------------------------------- 1 | // 2 | // parse 3 | // parser.c: Implements the parser for curly. 4 | // 5 | // Created by jenra. 6 | // Created on August 28 2020. 7 | // 8 | 9 | #include 10 | 11 | #include "../../../utils/list.h" 12 | #include "parser.h" 13 | 14 | // succ_result(ast_t*) -> parse_result_t 15 | // Returns a parse result containing the ast node. 16 | parse_result_t succ_result(ast_t* ast) 17 | { 18 | parse_result_t res; 19 | res.succ = true; 20 | res.ast = ast; 21 | return res; 22 | } 23 | 24 | // err_result(bool, token_t, char*) -> parse_result_t 25 | // Returns a parse result containing an error. 26 | parse_result_t err_result(bool fatal, token_t token, char* expected) 27 | { 28 | error_t* err = malloc(sizeof(error_t)); 29 | err->fatal = fatal; 30 | err->value = token; 31 | err->value.value = token.value != NULL ? strdup(token.value) : NULL; 32 | err->expected = strdup(expected); 33 | 34 | parse_result_t res; 35 | res.succ = false; 36 | res.error = err; 37 | return res; 38 | } 39 | 40 | // consume_string(lexer_t*, char*, bool) -> parse_result_t 41 | // Consumes a string from the lexer. 42 | parse_result_t consume_string(lexer_t* lex, char* string, bool fatal) 43 | { 44 | // Next token 45 | token_t* token = lex_next(lex); 46 | 47 | // Check if the token matches the string 48 | if (!strcmp(token->value, string)) 49 | return succ_result(init_ast(*token)); 50 | 51 | // Check for a lexer error 52 | else if (token->type == LEX_TYPE_NONE) 53 | return err_result(true, *token, string); 54 | 55 | // Return an error 56 | else return err_result(fatal, *token, string); 57 | } 58 | 59 | // consume_type(lexer_t*, lex_type_t, bool) -> parse_result_t 60 | // Consumes a type from the lexer. 61 | parse_result_t consume_type(lexer_t* lex, lex_type_t type, bool fatal) 62 | { 63 | // Next token 64 | token_t* token = lex_next(lex); 65 | 66 | // Check if the token matches the type 67 | if (token->type == type) 68 | return succ_result(init_ast(*token)); 69 | 70 | // Check for a lexer error 71 | else if (token->type == LEX_TYPE_NONE) 72 | return err_result(true, *token, lex_type_string(type)); 73 | 74 | // Return an error 75 | else return err_result(fatal, *token, lex_type_string(type)); 76 | } 77 | 78 | // consume_tag(lexer_t*, lex_tag_t, bool) -> parse_result_t 79 | // Consumes a tag from the lexer. 80 | parse_result_t consume_tag(lexer_t* lex, lex_tag_t tag, bool fatal) 81 | { 82 | // Next token 83 | token_t* token = lex_next(lex); 84 | 85 | // Check if the token matches the tag 86 | if (token->tag == tag) 87 | return succ_result(init_ast(*token)); 88 | 89 | // Check for a lexer error 90 | else if (token->type == LEX_TYPE_NONE) 91 | return err_result(true, *token, tag == LEX_TAG_OPERAND ? "operand" : "tag"); 92 | 93 | // Return an error 94 | else return err_result(fatal, *token, tag == LEX_TAG_OPERAND ? "operand" : "tag"); 95 | } 96 | 97 | #define push_lexer(lex) size_t prev_token_pos = lex->token_pos 98 | #define repush_lexer(lex) prev_token_pos = lex->token_pos 99 | 100 | // consume(parse_result_t, bool, string|type|tag, lexer_t*, ?, parse_result_t, bool) -> void 101 | // Consumes a token from the lexer. 102 | #define consume(res, required, type, lex, arg, built, fatal_) \ 103 | parse_result_t res = consume_##type(lex, arg, fatal_); \ 104 | if (!res.succ) \ 105 | { \ 106 | (lex)->token_pos = prev_token_pos; \ 107 | if (res.error->fatal || (required)) \ 108 | { \ 109 | clean_parse_result(built); \ 110 | return res; \ 111 | } \ 112 | } 113 | 114 | // call(parse_result_t, bool, func, lexer_t*, parse_result_t) -> void 115 | // Calls a function and crashes if a fatal error occurs. 116 | #define call(res, required, func, lex, built, fatal_) \ 117 | parse_result_t res = func(lex); \ 118 | if (!res.succ) \ 119 | { \ 120 | (lex)->token_pos = prev_token_pos; \ 121 | if (fatal_) \ 122 | res.error->fatal = fatal_; \ 123 | if (res.error->fatal || (required)) \ 124 | { \ 125 | clean_parse_result(built); \ 126 | return res; \ 127 | } \ 128 | } 129 | 130 | // expression: 'pass' | 'stop' | with_expr | if_expr | for_loop | xor 131 | parse_result_t expression(lexer_t* lex); 132 | 133 | // statement: assignment | expression 134 | parse_result_t statement(lexer_t* lex); 135 | 136 | // list_expr: '[' (for_loop | where_expr | (expression (',' expression?)*)?) ']' 137 | parse_result_t list_expr(lexer_t* lex) 138 | { 139 | // Push lexer 140 | push_lexer(lex); 141 | 142 | // Consume left bracket 143 | consume(lbrack, true, string, lex, "[", (parse_result_t) {false}, false); 144 | lbrack.ast->children_size = 1; 145 | lbrack.ast->children = calloc(1, sizeof(ast_t*)); 146 | 147 | // Consume a newline 148 | repush_lexer(lex); 149 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, lbrack, false); 150 | clean_parse_result(newline); 151 | repush_lexer(lex); 152 | 153 | // Try to collect items for the list 154 | call(expr, false, expression, lex, lbrack, false); 155 | if (expr.succ) 156 | { 157 | // Collect items 158 | list_append_element(lbrack.ast->children, lbrack.ast->children_size, lbrack.ast->children_count, ast_t*, expr.ast); 159 | while (true) 160 | { 161 | // Push lexer 162 | push_lexer(lex); 163 | 164 | // Consume comma 165 | consume(comma, false, type, lex, LEX_TYPE_COMMA, lbrack, false); 166 | clean_parse_result(comma); 167 | if (!comma.succ) break; 168 | repush_lexer(lex); 169 | 170 | // Consume a newline 171 | repush_lexer(lex); 172 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, lbrack, false); 173 | clean_parse_result(newline); 174 | 175 | // Consume item 176 | call(expr, false, expression, lex, lbrack, false); 177 | if (expr.succ) 178 | list_append_element(lbrack.ast->children, lbrack.ast->children_size, lbrack.ast->children_count, ast_t*, expr.ast); 179 | else clean_parse_result(expr); 180 | } 181 | } 182 | 183 | // Consume a newline 184 | repush_lexer(lex); 185 | consume(newline2, false, type, lex, LEX_TYPE_NEWLINE, lbrack, false); 186 | clean_parse_result(newline2); 187 | 188 | // Consume right bracket 189 | consume(rbrack, true, string, lex, "]", lbrack, true); 190 | clean_parse_result(rbrack); 191 | return lbrack; 192 | } 193 | 194 | // dict_item: (symbol '=')? expression 195 | parse_result_t dict_item(lexer_t* lex) 196 | { 197 | // Push the lexer 198 | push_lexer(lex); 199 | 200 | // Consume a symbol 201 | consume(symbol, false, type, lex, LEX_TYPE_SYMBOL, (parse_result_t) {false}, false); 202 | 203 | // Consume an equal sign and create the tree 204 | consume(assign, false, type, lex, LEX_TYPE_ASSIGN, symbol, false); 205 | 206 | if (symbol.succ && assign.succ) 207 | { 208 | assign.ast->children_size = 2; 209 | assign.ast->children = calloc(2, sizeof(ast_t*)); 210 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, symbol.ast); 211 | } else if (assign.succ) 212 | { 213 | clean_parse_result(assign); 214 | return symbol; 215 | } else 216 | { 217 | clean_parse_result(symbol); 218 | clean_parse_result(assign); 219 | assign.ast = NULL; 220 | } 221 | 222 | // Consume an expression 223 | call(expr, true, expression, lex, assign, true); 224 | if (!assign.succ) 225 | return expr; 226 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, expr.ast); 227 | return assign; 228 | } 229 | 230 | // dict_expr: '{' (dict_item (',' dict_item?)*)? '}' 231 | parse_result_t dict_expr(lexer_t* lex) 232 | { 233 | // Push the lexer 234 | push_lexer(lex); 235 | 236 | // Consume curly brace 237 | consume(lcurly, true, string, lex, "{", (parse_result_t) {false}, false); 238 | 239 | // Consume a newline 240 | repush_lexer(lex); 241 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, lcurly, false); 242 | clean_parse_result(newline); 243 | 244 | // Try to collect items for the dictionary 245 | call(item, false, dict_item, lex, lcurly, false); 246 | if (item.succ) 247 | { 248 | // Collect items 249 | list_append_element(lcurly.ast->children, lcurly.ast->children_size, lcurly.ast->children_count, ast_t*, item.ast); 250 | while (true) 251 | { 252 | // Push lexer 253 | push_lexer(lex); 254 | 255 | // Consume comma 256 | consume(comma, false, type, lex, LEX_TYPE_COMMA, lcurly, false); 257 | clean_parse_result(comma); 258 | if (!comma.succ) break; 259 | repush_lexer(lex); 260 | 261 | // Consume a newline 262 | repush_lexer(lex); 263 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, lcurly, false); 264 | clean_parse_result(newline); 265 | 266 | // Consume item 267 | call(item, false, dict_item, lex, lcurly, false); 268 | if (item.succ) 269 | list_append_element(lcurly.ast->children, lcurly.ast->children_size, lcurly.ast->children_count, ast_t*, item.ast); 270 | else clean_parse_result(item); 271 | } 272 | } else clean_parse_result(item); 273 | 274 | // Consume a newline 275 | repush_lexer(lex); 276 | consume(newline2, false, type, lex, LEX_TYPE_NEWLINE, lcurly, false); 277 | clean_parse_result(newline2); 278 | 279 | // Consume right curly brace 280 | consume(rcurly, true, string, lex, "}", lcurly, true); 281 | clean_parse_result(rcurly); 282 | return lcurly; 283 | } 284 | 285 | // value: operand | '(' expression ')' | list_expr | dict_expr 286 | parse_result_t value(lexer_t* lex) 287 | { 288 | // Push the lexer 289 | push_lexer(lex); 290 | 291 | // Consume an operand 292 | consume(res, false, tag, lex, LEX_TAG_OPERAND, (parse_result_t) {false}, false); 293 | 294 | // Return the operand if successful 295 | if (res.succ) 296 | return res; 297 | else clean_parse_result(res); 298 | 299 | // Try to consume a list 300 | call(list, false, list_expr, lex, (parse_result_t) {false}, false); 301 | if (list.succ) 302 | return list; 303 | else clean_parse_result(list); 304 | 305 | // Try to consume a dictionary 306 | call(dict, false, dict_expr, lex, (parse_result_t) {false}, false); 307 | if (dict.succ) 308 | return dict; 309 | else clean_parse_result(dict); 310 | 311 | // Consume a parenthesised expression 312 | consume(lparen, true, string, lex, "(", (parse_result_t) {false}, false); 313 | clean_parse_result(lparen); 314 | 315 | // Consume a newline 316 | repush_lexer(lex); 317 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, (parse_result_t) {false}, false); 318 | clean_parse_result(newline); 319 | 320 | // Consume expression 321 | call(expr, true, expression, lex, (parse_result_t) {false}, true); 322 | 323 | // Consume a newline 324 | repush_lexer(lex); 325 | consume(newline2, false, type, lex, LEX_TYPE_NEWLINE, expr, false); 326 | clean_parse_result(newline2); 327 | 328 | consume(rparen, true, string, lex, ")", expr, true); 329 | clean_parse_result(rparen); 330 | return expr; 331 | } 332 | 333 | #define infix_parser(name, subparser, type, operator, left_assoc) \ 334 | parse_result_t name(lexer_t* lex) \ 335 | { \ 336 | /* Push the lexer */ \ 337 | push_lexer(lex); \ 338 | \ 339 | /* Get left operand */ \ 340 | call(top, true, subparser, lex, (parse_result_t) {false}, false); \ 341 | parse_result_t right_acc = top; \ 342 | parse_result_t right_operand = top; \ 343 | \ 344 | while (true) \ 345 | { \ 346 | /* Push the lexer */ \ 347 | push_lexer(lex); \ 348 | \ 349 | /* Get operator */ \ 350 | consume(op, false, type, lex, operator, top, false); \ 351 | if (!op.succ) { clean_parse_result(op); break; } \ 352 | \ 353 | if (left_assoc) \ 354 | { \ 355 | /* Add left operand to the operator ast node */ \ 356 | op.ast->children_size = 2; \ 357 | op.ast->children = calloc(2, sizeof(ast_t*)); \ 358 | list_append_element(op.ast->children, op.ast->children_size, op.ast->children_count, ast_t*, top.ast); \ 359 | top = op; \ 360 | } else \ 361 | { \ 362 | /* Add operator to right operand */ \ 363 | op.ast->children_size = 2; \ 364 | op.ast->children = calloc(2, sizeof(ast_t*)); \ 365 | list_append_element(op.ast->children, op.ast->children_size, op.ast->children_count, ast_t*, right_operand.ast); \ 366 | if (right_operand.ast == top.ast) \ 367 | { \ 368 | top = op; \ 369 | right_acc = top; \ 370 | right_operand.ast = top.ast->children[1]; \ 371 | } \ 372 | right_acc.ast->children[1] = op.ast; \ 373 | right_acc = op; \ 374 | } \ 375 | \ 376 | /* Get right operand */ \ 377 | call(right, true, subparser, lex, top, true); \ 378 | list_append_element(op.ast->children, op.ast->children_size, op.ast->children_count, ast_t*, right.ast); \ 379 | right_operand = right; \ 380 | } \ 381 | \ 382 | /* Return the parsed expression */ \ 383 | return top; \ 384 | } 385 | 386 | // attribute: prefix ('.' prefix)* 387 | infix_parser(attribute, value, type, LEX_TYPE_DOT, true) 388 | 389 | // application: attribute+ 390 | parse_result_t application(lexer_t* lex) 391 | { 392 | // Push the lexer 393 | push_lexer(lex); 394 | 395 | // Consume the function 396 | call(func, true, attribute, lex, (parse_result_t) {false}, false); 397 | 398 | // Consume any arguments if necessary 399 | while (true) 400 | { 401 | // Push lexer 402 | push_lexer(lex); 403 | 404 | // Get argument 405 | call(arg, false, attribute, lex, func, false); 406 | if (!arg.succ) 407 | { 408 | clean_parse_result(arg); 409 | break; 410 | } 411 | 412 | // Construct tree 413 | ast_t* app = init_ast((token_t) {LEX_TYPE_APPLICATION, LEX_TAG_OPERATOR, strdup("app"), func.ast->value.pos, func.ast->value.lino, func.ast->value.charpos}); 414 | app->children_size = 2; 415 | app->children = calloc(2, sizeof(ast_t*)); 416 | list_append_element(app->children, app->children_size, app->children_count, ast_t*, func.ast); 417 | list_append_element(app->children, app->children_size, app->children_count, ast_t*, arg.ast); 418 | func.ast = app; 419 | } 420 | 421 | return func; 422 | } 423 | 424 | // prefix: ('*' | '-')? application 425 | parse_result_t prefix(lexer_t* lex) 426 | { 427 | // Push the lexer 428 | push_lexer(lex); 429 | 430 | // Try to consume curry operator 431 | consume(curry, false, string, lex, "*", (parse_result_t) {false}, false); 432 | if (curry.succ) 433 | { 434 | // Append a value to the curry operator 435 | call(app, true, application, lex, curry, true); 436 | curry.ast->children_size = 1; 437 | curry.ast->children = calloc(1, sizeof(ast_t*)); 438 | list_append_element(curry.ast->children, curry.ast->children_size, curry.ast->children_count, ast_t*, app.ast); 439 | curry.ast->value.tag = LEX_TAG_OPERATOR; 440 | return curry; 441 | } 442 | 443 | // Try to consume negative operator 444 | clean_parse_result(curry); 445 | consume(negative, false, string, lex, "-", (parse_result_t) {false}, false); 446 | if (negative.succ) 447 | { 448 | // Append a value to the curry operator 449 | call(app, true, application, lex, negative, true); 450 | negative.ast->children_size = 1; 451 | negative.ast->children = calloc(1, sizeof(ast_t*)); 452 | list_append_element(negative.ast->children, negative.ast->children_size, negative.ast->children_count, ast_t*, app.ast); 453 | negative.ast->value.tag = LEX_TAG_OPERATOR; 454 | return negative; 455 | } 456 | 457 | // Return the regular application if no prefix was found 458 | clean_parse_result(negative); 459 | return application(lex); 460 | } 461 | 462 | // muldiv: prefix (('*'|'/'|'%') prefix)* 463 | infix_parser(muldiv, prefix, type, LEX_TYPE_MULDIV, true) 464 | 465 | // addsub: muldiv (('+'|'-') muldiv)* 466 | infix_parser(addsub, muldiv, type, LEX_TYPE_ADDSUB, true) 467 | 468 | // bitshift: addsub (('<<'|'>>') addsub)* 469 | infix_parser(bitshift, addsub, type, LEX_TYPE_BITSHIFT, true) 470 | 471 | // bitand: bitshift (('&') bitshift)* 472 | infix_parser(bitand, bitshift, type, LEX_TYPE_AMP, true) 473 | 474 | // bitor: bitand (('|') bitand)* 475 | infix_parser(bitor, bitand, type, LEX_TYPE_BAR, true) 476 | 477 | // bitxor: bitor (('^') bitor)* 478 | infix_parser(bitxor, bitor, type, LEX_TYPE_CARET, true) 479 | 480 | // compare: bitxor (/[=!]=|[><]=?|in/ bitxor)* 481 | infix_parser(compare, bitxor, type, LEX_TYPE_COMPARE, true) 482 | 483 | // and: compare (('and') compare)* 484 | infix_parser(and, compare, type, LEX_TYPE_AND, true) 485 | 486 | // or: and (('or') and)* 487 | infix_parser(or, and, type, LEX_TYPE_OR, true) 488 | 489 | // xor: or (('xor') or)* 490 | infix_parser(xor, or, type, LEX_TYPE_XOR, true) 491 | 492 | // assignment: symbol '..' symbol '=' expression 493 | // | symbol ':' type_func ('=' expression)? 494 | // | symbol ('.' value)+ '=' expression 495 | // | symbol (operand | symbol ':' (symbol | type_func))* '=' expression 496 | // | symbol '=' 'type' type_func 497 | // | symbol '=' 'enum' enum_parser 498 | // | symbol '=' 'class' class 499 | // | symbol '=' expression 500 | parse_result_t assignment(lexer_t* lex); 501 | 502 | // with_expr: 'with' (assignment ',')+ expression 503 | parse_result_t with_expr(lexer_t* lex) 504 | { 505 | // Push the lexer 506 | push_lexer(lex); 507 | 508 | // Consume with keyword 509 | consume(with, true, string, lex, "with", (parse_result_t) {false}, false); 510 | 511 | // Consume one assignment and add it to the with keyword ast node 512 | call(assign, true, assignment, lex, with, true); 513 | list_append_element(with.ast->children, with.ast->children_size, with.ast->children_count, ast_t*, assign.ast); 514 | 515 | // Consume a comma 516 | consume(comma, true, type, lex, LEX_TYPE_COMMA, with, true); 517 | clean_parse_result(comma); 518 | 519 | // Consume a newline 520 | repush_lexer(lex); 521 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, with, false); 522 | clean_parse_result(newline); 523 | 524 | while (true) 525 | { 526 | push_lexer(lex); 527 | 528 | // Consume an assignment and add it to the with keyword ast node if found 529 | call(assign, false, assignment, lex, with, false); 530 | if (!assign.succ) 531 | { 532 | clean_parse_result(assign); 533 | break; 534 | } 535 | list_append_element(with.ast->children, with.ast->children_size, with.ast->children_count, ast_t*, assign.ast); 536 | 537 | // Consume a comma 538 | consume(comma, true, type, lex, LEX_TYPE_COMMA, with, true); 539 | clean_parse_result(comma); 540 | 541 | // Consume a newline 542 | repush_lexer(lex); 543 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, with, false); 544 | clean_parse_result(newline); 545 | } 546 | 547 | // Get an expression 548 | call(expr, true, expression, lex, with, true); 549 | list_append_element(with.ast->children, with.ast->children_size, with.ast->children_count, ast_t*, expr.ast); 550 | return with; 551 | } 552 | 553 | // match: 'match' expression 'to' value '=>' bitxor ('or' value '=>' bitxor)* ('else' bitxor)? 554 | parse_result_t match(lexer_t* lex) 555 | { 556 | // Push the lexer 557 | push_lexer(lex); 558 | 559 | // Consume the initial expression and form the tree 560 | consume(match, true, string, lex, "match", (parse_result_t) {false}, false); 561 | call(expr, true, expression, lex, match, true); 562 | list_append_element(match.ast->children, match.ast->children_size, match.ast->children_count, ast_t*, expr.ast); 563 | 564 | // Consume to 565 | repush_lexer(lex); 566 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, match, false); 567 | clean_parse_result(newline); 568 | consume(to, true, string, lex, "to", match, true); 569 | repush_lexer(lex); 570 | consume(newline1, false, type, lex, LEX_TYPE_NEWLINE, match, false); 571 | clean_parse_result(newline1); 572 | 573 | // Consume first match 574 | call(val, true, value, lex, match, true); 575 | list_append_element(match.ast->children, match.ast->children_size, match.ast->children_count, ast_t*, val.ast); 576 | consume(arrow, true, type, lex, LEX_TYPE_THICC_ARROW, match, true); 577 | 578 | // Form tree for arrow 579 | arrow.ast->children_size = 2; 580 | arrow.ast->children = calloc(2, sizeof(ast_t*)); 581 | list_append_element(arrow.ast->children, arrow.ast->children_size, arrow.ast->children_count, ast_t*, val.ast); 582 | match.ast->children[match.ast->children_count - 1] = arrow.ast; 583 | 584 | // Consume first expression 585 | call(expr1, true, expression, lex, match, true); 586 | list_append_element(arrow.ast->children, arrow.ast->children_size, arrow.ast->children_count, ast_t*, expr1.ast); 587 | 588 | // Consume more matches 589 | while (true) 590 | { 591 | // Push lexer 592 | push_lexer(lex); 593 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, match, false); 594 | repush_lexer(lex); 595 | 596 | // Consume to 597 | consume(or, false, string, lex, "to", match, false); 598 | clean_parse_result(or); 599 | if (!or.succ) break; 600 | 601 | // Consume match 602 | call(val, true, value, lex, match, true); 603 | list_append_element(match.ast->children, match.ast->children_size, match.ast->children_count, ast_t*, val.ast); 604 | consume(arrow, true, type, lex, LEX_TYPE_THICC_ARROW, match, true); 605 | 606 | // Form tree for arrow 607 | arrow.ast->children_size = 2; 608 | arrow.ast->children = calloc(2, sizeof(ast_t*)); 609 | list_append_element(arrow.ast->children, arrow.ast->children_size, arrow.ast->children_count, ast_t*, val.ast); 610 | match.ast->children[match.ast->children_count - 1] = arrow.ast; 611 | 612 | // Consume expression 613 | call(expr, true, expression, lex, match, true); 614 | list_append_element(arrow.ast->children, arrow.ast->children_size, arrow.ast->children_count, ast_t*, expr.ast); 615 | } 616 | 617 | // Consume else 618 | repush_lexer(lex); 619 | consume(newline2, false, type, lex, LEX_TYPE_NEWLINE, match, false); 620 | consume(elsey, false, string, lex, "else", match, false); 621 | if (elsey.succ) 622 | { 623 | // Form tree for else 624 | elsey.ast->children_size = 1; 625 | elsey.ast->children = calloc(1, sizeof(ast_t*)); 626 | list_append_element(match.ast->children, match.ast->children_size, match.ast->children_count, ast_t*, elsey.ast); 627 | 628 | // Consume expression 629 | call(expr, true, expression, lex, match, true); 630 | list_append_element(elsey.ast->children, elsey.ast->children_size, elsey.ast->children_count, ast_t*, expr.ast); 631 | } else clean_parse_result(elsey); 632 | return match; 633 | } 634 | 635 | // if_expr: 'if' expression 'then' expression ('else' expression)? 636 | parse_result_t if_expr(lexer_t* lex) 637 | { 638 | // Push the lexer 639 | push_lexer(lex); 640 | 641 | // Consume an if condition and form the tree 642 | consume(iffy, true, string, lex, "if", (parse_result_t) {false}, false); 643 | call(cond, true, expression, lex, iffy, true); 644 | iffy.ast->children_size = 3; 645 | iffy.ast->children = calloc(3, sizeof(ast_t*)); 646 | list_append_element(iffy.ast->children, iffy.ast->children_size, iffy.ast->children_count, ast_t*, cond.ast); 647 | 648 | // Consume a newline 649 | repush_lexer(lex); 650 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, iffy, false); 651 | clean_parse_result(newline); 652 | 653 | // Consume then 654 | consume(then, true, string, lex, "then", iffy, true); 655 | clean_parse_result(then); 656 | 657 | // Consume a newline 658 | repush_lexer(lex); 659 | consume(newline2, false, type, lex, LEX_TYPE_NEWLINE, iffy, false); 660 | clean_parse_result(newline2); 661 | 662 | // Consume body 663 | call(body, true, statement, lex, iffy, true); 664 | list_append_element(iffy.ast->children, iffy.ast->children_size, iffy.ast->children_count, ast_t*, body.ast); 665 | 666 | // Consume a newline 667 | repush_lexer(lex); 668 | consume(newline3, false, type, lex, LEX_TYPE_NEWLINE, iffy, false); 669 | clean_parse_result(newline3); 670 | 671 | // Consume else 672 | consume(elsy, true, string, lex, "else", iffy, true); 673 | clean_parse_result(elsy); 674 | 675 | // Consume a newline 676 | repush_lexer(lex); 677 | consume(newline4, false, type, lex, LEX_TYPE_NEWLINE, iffy, false); 678 | clean_parse_result(newline4); 679 | 680 | // Consume else body 681 | call(else_body, true, statement, lex, iffy, true); 682 | list_append_element(iffy.ast->children, iffy.ast->children_size, iffy.ast->children_count, ast_t*, else_body.ast); 683 | return iffy; 684 | } 685 | 686 | // type_func: type_parameterised ('|' type_parameterised)* 687 | parse_result_t type_func(lexer_t* lex); 688 | 689 | // type_typed: symbol ':' type_func 690 | parse_result_t type_typed(lexer_t* lex) 691 | { 692 | // Push the lexer 693 | push_lexer(lex); 694 | 695 | // Consume the symbol 696 | consume(symbol, true, type, lex, LEX_TYPE_SYMBOL, (parse_result_t) {false}, false); 697 | 698 | // Consume a colon 699 | consume(colon, true, type, lex, LEX_TYPE_COLON, symbol, false); 700 | 701 | // Create tree 702 | colon.ast->children_size = 2; 703 | colon.ast->children = calloc(2, sizeof(ast_t*)); 704 | list_append_element(colon.ast->children, colon.ast->children_size, colon.ast->children_count, ast_t*, symbol.ast); 705 | 706 | // Colon must be followed by a type 707 | repush_lexer(lex); 708 | consume(type_sym, false, type, lex, LEX_TYPE_SYMBOL, colon, false); 709 | if (type_sym.succ) 710 | { 711 | list_append_element(colon.ast->children, colon.ast->children_size, colon.ast->children_count, ast_t*, type_sym.ast); 712 | return colon; 713 | } else clean_parse_result(type_sym); 714 | 715 | consume(lparen, true, string, lex, "(", colon, true); 716 | clean_parse_result(lparen); 717 | call(type, true, type_func, lex, colon, true); 718 | list_append_element(colon.ast->children, colon.ast->children_size, colon.ast->children_count, ast_t*, type.ast); 719 | consume(rparen, true, string, lex, ")", colon, true); 720 | clean_parse_result(rparen); 721 | return colon; 722 | } 723 | 724 | // type_paren: '(' type_func ')' 725 | parse_result_t type_paren(lexer_t* lex) 726 | { 727 | // Push the lexer 728 | push_lexer(lex); 729 | 730 | // Consume parenthesised type 731 | consume(lparen, true, string, lex, "(", (parse_result_t) {false}, false); 732 | clean_parse_result(lparen); 733 | call(subtype, true, type_func, lex, (parse_result_t) {false}, true); 734 | consume(rparen, true, string, lex, ")", subtype, true); 735 | clean_parse_result(rparen); 736 | return subtype; 737 | } 738 | 739 | // type_application: symbol (symbol | type_paren)* 740 | parse_result_t type_application(lexer_t* lex) 741 | { 742 | // Push the lexer 743 | push_lexer(lex); 744 | 745 | // Consume the type 746 | consume(type, true, type, lex, LEX_TYPE_SYMBOL, (parse_result_t) {false}, false); 747 | 748 | // Consume any arguments if necessary 749 | while (true) 750 | { 751 | // Push lexer 752 | push_lexer(lex); 753 | 754 | // Get argument 755 | consume(arg, false, type, lex, LEX_TYPE_SYMBOL, type, false); 756 | if (!arg.succ) 757 | { 758 | clean_parse_result(arg); 759 | 760 | // Get parenthesised type 761 | call(paren, false, type_paren, lex, type, false); 762 | if (paren.succ) 763 | arg = paren; 764 | else 765 | { 766 | clean_parse_result(paren); 767 | break; 768 | } 769 | } 770 | 771 | // Construct tree 772 | list_append_element(type.ast->children, type.ast->children_size, type.ast->children_count, ast_t*, arg.ast); 773 | } 774 | 775 | return type; 776 | } 777 | 778 | // type_intersect_arg: typed_type | type_application 779 | parse_result_t type_intersect_arg(lexer_t* lex) 780 | { 781 | // Push lexer 782 | push_lexer(lex); 783 | 784 | // Try to consume a typed result 785 | call(typed, false, type_typed, lex, (parse_result_t) {false}, false); 786 | if (typed.succ) 787 | return typed; 788 | else clean_parse_result(typed); 789 | 790 | // Consume a type application 791 | call(app, false, type_application, lex, (parse_result_t) {false}, false); 792 | if (app.succ) 793 | return app; 794 | else clean_parse_result(app); 795 | 796 | // Consume a parenthesised type 797 | call(subtype, false, type_paren, lex, (parse_result_t) {false}, false); 798 | return subtype; 799 | } 800 | 801 | // type_intersection: type_intersect_arg ('&' type_intersect_arg)* 802 | parse_result_t type_intersection(lexer_t* lex) 803 | { 804 | // Push the lexer 805 | push_lexer(lex); 806 | 807 | // Consume first argument 808 | call(arg, true, type_intersect_arg, lex, (parse_result_t) {false}, false); 809 | parse_result_t top = arg; 810 | bool second = true; 811 | 812 | // Consume the rest of the arguments 813 | while (true) 814 | { 815 | push_lexer(lex); 816 | 817 | // Consume the operator 818 | consume(op, false, type, lex, LEX_TYPE_AMP, top, false); 819 | if (!op.succ) 820 | { 821 | clean_parse_result(op); 822 | break; 823 | } else if (second) 824 | { 825 | list_append_element(op.ast->children, op.ast->children_size, op.ast->children_count, ast_t*, top.ast); 826 | top = op; 827 | second = false; 828 | } else clean_parse_result(op); 829 | 830 | // Consume a new item 831 | call(arg, true, type_intersect_arg, lex, (parse_result_t) {false}, false); 832 | list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, arg.ast); 833 | } 834 | 835 | return top; 836 | } 837 | 838 | // type_product: type_intersection ('*' type_intersection)* 839 | parse_result_t type_product(lexer_t* lex) 840 | { 841 | // Push the lexer 842 | push_lexer(lex); 843 | 844 | // Consume first argument 845 | call(arg, true, type_intersection, lex, (parse_result_t) {false}, false); 846 | parse_result_t top = arg; 847 | bool second = true; 848 | 849 | // Consume the rest of the arguments 850 | while (true) 851 | { 852 | push_lexer(lex); 853 | 854 | // Consume the operator 855 | consume(op, false, string, lex, "*", top, false); 856 | if (!op.succ) 857 | { 858 | clean_parse_result(op); 859 | break; 860 | } else if (second) 861 | { 862 | list_append_element(op.ast->children, op.ast->children_size, op.ast->children_count, ast_t*, top.ast); 863 | top = op; 864 | second = false; 865 | } else clean_parse_result(op); 866 | 867 | // Consume a new item 868 | call(arg, true, type_intersection, lex, (parse_result_t) {false}, false); 869 | list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, arg.ast); 870 | } 871 | 872 | return top; 873 | } 874 | 875 | // type_union: type_product ('|' type_product)* 876 | parse_result_t type_union(lexer_t* lex) 877 | { 878 | // Push the lexer 879 | push_lexer(lex); 880 | 881 | // Consume first argument 882 | call(arg, true, type_product, lex, (parse_result_t) {false}, false); 883 | parse_result_t top = arg; 884 | bool second = true; 885 | 886 | // Consume the rest of the arguments 887 | while (true) 888 | { 889 | push_lexer(lex); 890 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, top, false); 891 | 892 | // Consume the operator 893 | consume(op, false, type, lex, LEX_TYPE_BAR, top, false); 894 | if (!op.succ) 895 | { 896 | clean_parse_result(op); 897 | break; 898 | } else if (second) 899 | { 900 | list_append_element(op.ast->children, op.ast->children_size, op.ast->children_count, ast_t*, top.ast); 901 | top = op; 902 | second = false; 903 | } else clean_parse_result(op); 904 | 905 | // Consume a new item 906 | call(arg, true, type_product, lex, (parse_result_t) {false}, false); 907 | list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, arg.ast); 908 | } 909 | 910 | return top; 911 | } 912 | 913 | // type_parameterised: type_union ('=>' type_union)* 914 | parse_result_t type_parameterised(lexer_t* lex) 915 | { 916 | // Push the lexer 917 | push_lexer(lex); 918 | 919 | // Consume parameters 920 | parse_result_t top = {false}; 921 | bool first = true; 922 | while (true) 923 | { 924 | push_lexer(lex); 925 | 926 | // Consume parameter 927 | consume(param, false, type, lex, LEX_TYPE_SYMBOL, top, false); 928 | if (param.succ && first) 929 | top = param; 930 | else if (!param.succ) 931 | { 932 | clean_parse_result(param); 933 | break; 934 | } else if (!first) 935 | list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, param.ast); 936 | 937 | // Consume the operator 938 | consume(op, false, type, lex, LEX_TYPE_THICC_ARROW, top, false); 939 | if (!op.succ) 940 | { 941 | clean_parse_result(op); 942 | if (!first) 943 | top.ast->children[--top.ast->children_count] = NULL; 944 | break; 945 | } else if (first) 946 | { 947 | list_append_element(op.ast->children, op.ast->children_size, op.ast->children_count, ast_t*, top.ast); 948 | top = op; 949 | first = false; 950 | } else clean_parse_result(op); 951 | } 952 | 953 | // Consume type 954 | call(arg, true, type_union, lex, top, false); 955 | if (first) 956 | top = arg; 957 | else list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, arg.ast); 958 | return top; 959 | } 960 | 961 | // type_func: type_parameterised ('->' type_parameterised)* 962 | infix_parser(type_func, type_parameterised, type, LEX_TYPE_RIGHT_ARROW, false) 963 | 964 | // enum_parser: 'enum' symbol ('|' symbol)* 965 | parse_result_t enum_parser(lexer_t* lex) 966 | { 967 | // Push the lexer 968 | push_lexer(lex); 969 | 970 | // Consume enum keyword 971 | consume(top, true, string, lex, "enum", (parse_result_t) {false}, false); 972 | 973 | // Consume first symbol 974 | consume(item, true, type, lex, LEX_TYPE_SYMBOL, top, true); 975 | list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, item.ast); 976 | 977 | // Consume the rest of the symbols 978 | while (true) 979 | { 980 | push_lexer(lex); 981 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, top, false); 982 | 983 | // Consume a bar 984 | consume(bar, false, type, lex, LEX_TYPE_BAR, top, false); 985 | clean_parse_result(bar); 986 | if (!bar.succ) break; 987 | 988 | // Consume a new item 989 | consume(item, true, type, lex, LEX_TYPE_SYMBOL, top, true); 990 | list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, item.ast); 991 | } 992 | 993 | return top; 994 | } 995 | 996 | // class: 'class' symbol* 'where' ('true' | class_comp ('and' class_comp)*) 997 | parse_result_t class(lexer_t* lex) 998 | { 999 | // Push the lexer 1000 | push_lexer(lex); 1001 | 1002 | // Consume class keyword 1003 | consume(top, true, string, lex, "class", (parse_result_t) {false}, false); 1004 | 1005 | // Consume type class name 1006 | consume(symbol, true, type, lex, LEX_TYPE_SYMBOL, top, true); 1007 | list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, symbol.ast); 1008 | 1009 | // Consume parameters to type class 1010 | while (true) 1011 | { 1012 | push_lexer(lex); 1013 | consume(arg, false, type, lex, LEX_TYPE_SYMBOL, top, false); 1014 | if (!arg.succ) 1015 | { 1016 | clean_parse_result(arg); 1017 | break; 1018 | } 1019 | 1020 | // Add parameter to symbol 1021 | list_append_element(symbol.ast->children, symbol.ast->children_size, symbol.ast->children_count, ast_t*, arg.ast); 1022 | } 1023 | 1024 | // Consume where 1025 | consume(where, true, string, lex, "where", top, true); 1026 | clean_parse_result(where); 1027 | 1028 | // Consume true 1029 | // TODO: More type class stuff 1030 | consume(truthy, true, string, lex, "true", top, true); 1031 | list_append_element(top.ast->children, top.ast->children_size, top.ast->children_count, ast_t*, truthy.ast); 1032 | return top; 1033 | } 1034 | 1035 | // assignment: symbol '..' symbol '=' expression 1036 | // | symbol ':' type_func ('=' expression)? 1037 | // | symbol ('.' value)+ '=' expression 1038 | // | symbol (operand | symbol ':' (symbol | type_func))* '=' expression 1039 | // | symbol '=' 'type' type_func 1040 | // | symbol '=' 'enum' enum_parser 1041 | // | symbol '=' 'class' class 1042 | // | symbol '=' expression 1043 | parse_result_t assignment(lexer_t* lex) 1044 | { 1045 | // Push the lexer 1046 | push_lexer(lex); 1047 | 1048 | // Consume a symbol (there must be at least one for an assignment) 1049 | consume(symbol, true, type, lex, LEX_TYPE_SYMBOL, (parse_result_t) {false}, false); 1050 | repush_lexer(lex); 1051 | 1052 | // Try to consume a range operator 1053 | consume(range, false, type, lex, LEX_TYPE_RANGE, symbol, false); 1054 | if (range.succ) 1055 | { 1056 | // Add the head to the range operator ast node 1057 | range.ast->children_size = 2; 1058 | range.ast->children = calloc(2, sizeof(ast_t*)); 1059 | list_append_element(range.ast->children, range.ast->children_size, range.ast->children_count, ast_t*, symbol.ast); 1060 | 1061 | // Consume another symbol and add it as the tail to the range operator ast node 1062 | consume(tail, true, type, lex, LEX_TYPE_SYMBOL, range, true); 1063 | list_append_element(range.ast->children, range.ast->children_size, range.ast->children_count, ast_t*, tail.ast); 1064 | 1065 | // Consume equal sign 1066 | consume(assign, true, type, lex, LEX_TYPE_ASSIGN, range, true); 1067 | assign.ast->children_size = 2; 1068 | assign.ast->children = calloc(2, sizeof(ast_t*)); 1069 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, range.ast); 1070 | 1071 | // Get expression 1072 | call(expr, true, expression, lex, assign, true); 1073 | 1074 | // Add the expression to the assignment operator ast node 1075 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, expr.ast); 1076 | return assign; 1077 | } 1078 | 1079 | // Try to consume a colon 1080 | clean_parse_result(range); 1081 | consume(colon, false, type, lex, LEX_TYPE_COLON, symbol, false); 1082 | if (colon.succ) 1083 | { 1084 | // Add the variable name to the type operator ast node 1085 | colon.ast->children_size = 2; 1086 | colon.ast->children = calloc(2, sizeof(ast_t*)); 1087 | list_append_element(colon.ast->children, colon.ast->children_size, colon.ast->children_count, ast_t*, symbol.ast); 1088 | 1089 | // Consume the type 1090 | call(type, true, type_func, lex, colon, true); 1091 | list_append_element(colon.ast->children, colon.ast->children_size, colon.ast->children_count, ast_t*, type.ast); 1092 | push_lexer(lex); 1093 | 1094 | // Consume equal sign (it's optional) 1095 | consume(assign, false, type, lex, LEX_TYPE_ASSIGN, colon, false); 1096 | if (!assign.succ) 1097 | { 1098 | clean_parse_result(assign); 1099 | return colon; 1100 | } 1101 | 1102 | // Create the tree 1103 | assign.ast->children_size = 2; 1104 | assign.ast->children = calloc(2, sizeof(ast_t*)); 1105 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, colon.ast); 1106 | 1107 | // Get expression 1108 | call(expr, true, expression, lex, assign, true); 1109 | 1110 | // Add the expression to the assignment operator ast node 1111 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, expr.ast); 1112 | return assign; 1113 | } 1114 | 1115 | // Try to consume a dot 1116 | clean_parse_result(colon); 1117 | consume(dot, false, type, lex, LEX_TYPE_DOT, symbol, false); 1118 | if (dot.succ) 1119 | { 1120 | // Add the parent name to the type operator ast node 1121 | list_append_element(dot.ast->children, dot.ast->children_size, dot.ast->children_count, ast_t*, symbol.ast); 1122 | 1123 | // Consume a value 1124 | call(val, true, value, lex, dot, true); 1125 | list_append_element(dot.ast->children, dot.ast->children_size, dot.ast->children_count, ast_t*, val.ast); 1126 | 1127 | while (true) 1128 | { 1129 | // Push the lexer 1130 | push_lexer(lex); 1131 | 1132 | // Consume a dot 1133 | consume(dot2, false, type, lex, LEX_TYPE_DOT, dot, false); 1134 | clean_parse_result(dot2); 1135 | if (!dot2.succ) break; 1136 | 1137 | // Consume a value 1138 | call(val, true, value, lex, dot, true); 1139 | list_append_element(dot.ast->children, dot.ast->children_size, dot.ast->children_count, ast_t*, val.ast); 1140 | } 1141 | 1142 | // Consume equal sign 1143 | consume(assign, true, type, lex, LEX_TYPE_ASSIGN, dot, false); 1144 | assign.ast->children_size = 2; 1145 | assign.ast->children = calloc(2, sizeof(ast_t*)); 1146 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, dot.ast); 1147 | 1148 | // Get expression 1149 | call(expr, true, expression, lex, assign, true); 1150 | 1151 | // Add the expression to the assignment operator ast node 1152 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, expr.ast); 1153 | return assign; 1154 | } 1155 | 1156 | // Try to consume arguments 1157 | clean_parse_result(dot); 1158 | while (true) 1159 | { 1160 | // Push the lexer 1161 | push_lexer(lex); 1162 | 1163 | // Consume an operand and add it to the symbol ast node 1164 | consume(arg, false, tag, lex, LEX_TAG_OPERAND, symbol, false); 1165 | if (!arg.succ) 1166 | { 1167 | clean_parse_result(arg); 1168 | break; 1169 | } 1170 | list_append_element(symbol.ast->children, symbol.ast->children_size, symbol.ast->children_count, ast_t*, arg.ast); 1171 | 1172 | // If a symbol was absorbed, attach a type 1173 | if (arg.ast->value.type == LEX_TYPE_SYMBOL) 1174 | { 1175 | // Consume a colon if able 1176 | push_lexer(lex); 1177 | consume(colon, false, type, lex, LEX_TYPE_COLON, symbol, false); 1178 | if (!colon.succ) 1179 | { 1180 | clean_parse_result(colon); 1181 | continue; 1182 | } 1183 | 1184 | // Add the symbol node to the colon 1185 | colon.ast->children_size = 2; 1186 | colon.ast->children = calloc(2, sizeof(ast_t*)); 1187 | list_append_element(colon.ast->children, colon.ast->children_size, colon.ast->children_count, ast_t*, symbol.ast->children[symbol.ast->children_count - 1]); 1188 | symbol.ast->children[symbol.ast->children_count - 1] = colon.ast; 1189 | 1190 | // Consume the type and add it to the colon ast node 1191 | repush_lexer(lex); 1192 | consume(lparen, false, string, lex, "(", symbol, false); 1193 | clean_parse_result(lparen); 1194 | if (lparen.succ) 1195 | { 1196 | call(type, true, type_func, lex, symbol, true); 1197 | consume(rparen, true, string, lex, ")", symbol, true); 1198 | list_append_element(colon.ast->children, colon.ast->children_size, colon.ast->children_count, ast_t*, type.ast); 1199 | } else 1200 | { 1201 | consume(type, true, type, lex, LEX_TYPE_SYMBOL, symbol, true); 1202 | list_append_element(colon.ast->children, colon.ast->children_size, colon.ast->children_count, ast_t*, type.ast); 1203 | 1204 | // Consume attribute if applicable 1205 | push_lexer(lex); 1206 | consume(dot, false, type, lex, LEX_TYPE_DOT, symbol, false); 1207 | if (dot.succ) 1208 | { 1209 | dot.ast->children_count = 2; 1210 | dot.ast->children = calloc(2, sizeof(ast_t*)); 1211 | list_append_element(dot.ast->children, dot.ast->children_size, dot.ast->children_count, ast_t*, type.ast); 1212 | colon.ast->children[1] = dot.ast; 1213 | consume(attr, true, type, lex, LEX_TYPE_SYMBOL, symbol, true); 1214 | list_append_element(dot.ast->children, dot.ast->children_size, dot.ast->children_count, ast_t*, attr.ast); 1215 | } else clean_parse_result(dot); 1216 | } 1217 | } 1218 | } 1219 | 1220 | // Consume equal sign 1221 | consume(assign, true, type, lex, LEX_TYPE_ASSIGN, symbol, false); 1222 | repush_lexer(lex); 1223 | assign.ast->children_size = 2; 1224 | assign.ast->children = calloc(2, sizeof(ast_t*)); 1225 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, symbol.ast); 1226 | 1227 | if (symbol.ast->children_count == 0) 1228 | { 1229 | // Try to consume type keyword 1230 | consume(type_keyword, false, string, lex, "type", assign, false); 1231 | if (type_keyword.succ) 1232 | { 1233 | // Get the type 1234 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, type_keyword.ast); 1235 | call(type, true, type_func, lex, assign, true); 1236 | 1237 | // Build the tree 1238 | type_keyword.ast->children = calloc(1, sizeof(ast_t*)); 1239 | list_append_element(type_keyword.ast->children, type_keyword.ast->children_size, type_keyword.ast->children_count, ast_t*, type.ast); 1240 | return assign; 1241 | } else clean_parse_result(type_keyword); 1242 | 1243 | // Try to consume enum 1244 | call(enumy, false, enum_parser, lex, assign, false); 1245 | if (enumy.succ) 1246 | { 1247 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, enumy.ast); 1248 | return assign; 1249 | } else clean_parse_result(enumy); 1250 | 1251 | // Try to consume class 1252 | call(classy, false, class, lex, assign, false); 1253 | if (classy.succ) 1254 | { 1255 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, classy.ast); 1256 | return assign; 1257 | } else clean_parse_result(classy); 1258 | } 1259 | 1260 | // Get expression 1261 | call(expr, true, expression, lex, assign, true); 1262 | 1263 | // Add the expression to the assignment operator ast node 1264 | list_append_element(assign.ast->children, assign.ast->children_size, assign.ast->children_count, ast_t*, expr.ast); 1265 | return assign; 1266 | } 1267 | 1268 | 1269 | // for_loop: 'for' symbol 'in' expression expression 1270 | parse_result_t for_loop(lexer_t* lex) 1271 | { 1272 | // Push the lexer 1273 | push_lexer(lex); 1274 | 1275 | // Consume for 1276 | consume(fory, true, string, lex, "for", (parse_result_t) {false}, false); 1277 | 1278 | { 1279 | // Push the lexer 1280 | push_lexer(lex); 1281 | 1282 | // Check for a quantifier 1283 | consume(all, false, string, lex, "all", fory, false); 1284 | if (all.succ) 1285 | list_append_element(fory.ast->children, fory.ast->children_size, fory.ast->children_count, ast_t*, all.ast); 1286 | else 1287 | { 1288 | // stan loona 1289 | clean_parse_result(all); 1290 | consume(some, false, string, lex, "some", fory, false); 1291 | if (some.succ) 1292 | list_append_element(fory.ast->children, fory.ast->children_size, fory.ast->children_count, ast_t*, some.ast); 1293 | } 1294 | } 1295 | 1296 | // Consume the variable name 1297 | consume(symbol, true, type, lex, LEX_TYPE_SYMBOL, fory, true); 1298 | list_append_element(fory.ast->children, fory.ast->children_size, fory.ast->children_count, ast_t*, symbol.ast); 1299 | 1300 | // Consume the iterator 1301 | consume(in, true, string, lex, "in", fory, true); 1302 | clean_parse_result(in); 1303 | call(iter, true, value, lex, fory, true); 1304 | list_append_element(fory.ast->children, fory.ast->children_size, fory.ast->children_count, ast_t*, iter.ast); 1305 | 1306 | // Consume a newline 1307 | repush_lexer(lex); 1308 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, fory, false); 1309 | clean_parse_result(newline); 1310 | 1311 | // Consume the body 1312 | call(body, true, statement, lex, fory, true); 1313 | list_append_element(fory.ast->children, fory.ast->children_size, fory.ast->children_count, ast_t*, body.ast); 1314 | return fory; 1315 | } 1316 | 1317 | // where_expr: symbol 'in' expression 'where' expression 1318 | parse_result_t where_expr(lexer_t* lex) 1319 | { 1320 | // Push the lexer 1321 | push_lexer(lex); 1322 | 1323 | // Consume a symbol 1324 | consume(symbol, true, type, lex, LEX_TYPE_SYMBOL, (parse_result_t) {false}, false); 1325 | 1326 | // Consume the in operator and form the tree 1327 | consume(in, true, string, lex, "in", symbol, false); 1328 | in.ast->children_size = 2; 1329 | in.ast->children = calloc(2, sizeof(ast_t*)); 1330 | list_append_element(in.ast->children, in.ast->children_size, in.ast->children_count, ast_t*, symbol.ast); 1331 | 1332 | // Consume the iterator 1333 | call(iter, true, expression, lex, in, false); 1334 | list_append_element(in.ast->children, in.ast->children_size, in.ast->children_count, ast_t*, iter.ast); 1335 | 1336 | // Consume the where operator and form the tree 1337 | consume(where, true, string, lex, "where", in, false); 1338 | where.ast->children_size = 2; 1339 | where.ast->children = calloc(2, sizeof(ast_t*)); 1340 | list_append_element(where.ast->children, where.ast->children_size, where.ast->children_count, ast_t*, in.ast); 1341 | 1342 | // Consume a newline 1343 | repush_lexer(lex); 1344 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, where, false); 1345 | clean_parse_result(newline); 1346 | 1347 | // Consume the predicate 1348 | call(pred, true, expression, lex, in, true); 1349 | list_append_element(where.ast->children, where.ast->children_size, where.ast->children_count, ast_t*, pred.ast); 1350 | return where; 1351 | } 1352 | 1353 | // expression: 'pass' | 'stop' | with_expr | if_expr | for_loop | xor 1354 | parse_result_t expression(lexer_t* lex) 1355 | { 1356 | // Push the lexer 1357 | push_lexer(lex); 1358 | 1359 | // Consume pass 1360 | consume(pass, false, string, lex, "pass", (parse_result_t) {false}, false); 1361 | if (pass.succ) 1362 | return pass; 1363 | 1364 | // Consume stop 1365 | clean_parse_result(pass); 1366 | consume(stop, false, string, lex, "stop", (parse_result_t) {false}, false); 1367 | if (stop.succ) 1368 | return stop; 1369 | 1370 | // Call where expression 1371 | clean_parse_result(stop); 1372 | call(where, false, where_expr, lex, (parse_result_t) {false}, false); 1373 | if (where.succ) 1374 | return where; 1375 | 1376 | // Call with expression if where expression is not applicable 1377 | clean_parse_result(where); 1378 | call(with, false, with_expr, lex, (parse_result_t) {false}, false); 1379 | if (with.succ) 1380 | return with; 1381 | 1382 | // Call if expression if with expression is not applicable 1383 | clean_parse_result(with); 1384 | call(iffy, false, if_expr, lex, (parse_result_t) {false}, false); 1385 | if (iffy.succ) 1386 | return iffy; 1387 | 1388 | // Call for loop if if expression is not applicable 1389 | clean_parse_result(iffy); 1390 | call(fory, false, for_loop, lex, (parse_result_t) {false}, false); 1391 | if (fory.succ) 1392 | return fory; 1393 | 1394 | // Call pattern matching if for loop is not applicable 1395 | clean_parse_result(fory); 1396 | call(matchy, false, match, lex, (parse_result_t) {false}, false); 1397 | if (matchy.succ) 1398 | return matchy; 1399 | 1400 | // Call xor if pattern matching is not applicable 1401 | clean_parse_result(matchy); 1402 | return xor(lex); 1403 | } 1404 | 1405 | // statement: assignment | expression 1406 | parse_result_t statement(lexer_t* lex) 1407 | { 1408 | // Push the lexer 1409 | push_lexer(lex); 1410 | 1411 | // Call assignment 1412 | call(assign, false, assignment, lex, (parse_result_t) {false}, false); 1413 | if (assign.succ) 1414 | return assign; 1415 | 1416 | // Call expression if assignment is not applicable 1417 | clean_parse_result(assign); 1418 | call(expr, false, expression, lex, (parse_result_t) {false}, false); 1419 | return expr; 1420 | } 1421 | 1422 | // lang_parser(lexer_t*) -> parse_result_t 1423 | // Parses the curly language. 1424 | // lang_parser: statement* 1425 | parse_result_t lang_parser(lexer_t* lex) 1426 | { 1427 | // Push the lexer 1428 | push_lexer(lex); 1429 | parse_result_t result = succ_result(init_ast((token_t) {0, 0, NULL, 0, 0, 0})); 1430 | 1431 | while (true) 1432 | { 1433 | // Push the lexer 1434 | push_lexer(lex); 1435 | 1436 | // Consume one statement 1437 | call(state, false, statement, lex, result, false); 1438 | if (!state.succ) 1439 | clean_parse_result(state); 1440 | else list_append_element(result.ast->children, result.ast->children_size, result.ast->children_count, ast_t*, state.ast); 1441 | 1442 | // Consume a newline 1443 | repush_lexer(lex); 1444 | consume(newline, false, type, lex, LEX_TYPE_NEWLINE, result, false); 1445 | if (!newline.succ) 1446 | { 1447 | clean_parse_result(newline); 1448 | break; 1449 | } 1450 | } 1451 | 1452 | // Assert that the end of file has been reached 1453 | consume(eof, true, type, lex, LEX_TYPE_EOF, result, true); 1454 | clean_parse_result(eof); 1455 | return result; 1456 | } 1457 | 1458 | #undef infix_parser 1459 | #undef repush_lexer 1460 | #undef push_lexer 1461 | #undef call 1462 | #undef consume 1463 | -------------------------------------------------------------------------------- /src/compiler/frontend/parse/parser.h: -------------------------------------------------------------------------------- 1 | // 2 | // parse 3 | // parser.h: Header file for parser.c. 4 | // 5 | // Created by jenra. 6 | // Created on August 28 2020. 7 | // 8 | 9 | #ifndef PARSER_H 10 | #define PARSER_H 11 | 12 | #include "ast.h" 13 | #include "lexer.h" 14 | 15 | // lang_parser(lexer_t*) -> parse_result_t 16 | // Parses the curly language. 17 | // lang_parser: statement* 18 | parse_result_t lang_parser(lexer_t* lex); 19 | 20 | #endif /* PARSER_H */ 21 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // Curly 3 | // main.c: Runs the command line interface. 4 | // 5 | // jenra 6 | // July 27 2020 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "compiler/backends/llvm/codegen.h" 17 | #include "compiler/frontend/correctness/check.h" 18 | #include "compiler/frontend/ir/generate_ir.h" 19 | #include "compiler/frontend/parse/lexer.h" 20 | #include "compiler/frontend/parse/parser.h" 21 | #include "utils/list.h" 22 | 23 | // count_groupings(char*, int) -> int 24 | // Counts the number of unmatched grouping symbols and returns the result. 25 | int count_groupings(char* string, int p) 26 | { 27 | // Iterate over the string 28 | for (size_t i = 0; i < strlen(string); i++) 29 | { 30 | char c = string[i]; 31 | 32 | // Increment if a left grouping symbol is found 33 | if (c == '(' || c == '[' || c == '{') 34 | p++; 35 | 36 | // Decrement if a right grouping symbol is found 37 | else if (c == ')' || c == ']' || c == '}') 38 | { 39 | p--; 40 | 41 | // Excessive right grouping symbols is an irrecoverable error 42 | if (p < 0) 43 | return p; 44 | } 45 | } 46 | return p; 47 | } 48 | 49 | typedef union 50 | { 51 | int64_t i64; 52 | double f64; 53 | bool i1; 54 | struct 55 | { 56 | int32_t reference_count; 57 | void* func; 58 | int8_t count; 59 | int8_t arity; 60 | int64_t thunk_bitmap; 61 | int64_t* args; 62 | } func_app; 63 | } repl_value_t; 64 | 65 | int main(int argc, char** argv) 66 | { 67 | switch (argc) 68 | { 69 | case 1: 70 | { 71 | // Set up 72 | puts("Curly REPL"); 73 | ir_scope_t* scope = push_scope(NULL); 74 | create_primatives(scope); 75 | lexer_t lex; 76 | parse_result_t res; 77 | curly_ir_t ir; 78 | init_ir(&ir); 79 | LLVMContextRef context = LLVMContextCreate(); 80 | llvm_codegen_env_t* env = create_llvm_codegen_environment(LLVMModuleCreateWithNameInContext("repl-header", context)); 81 | size_t globals_size = 0; 82 | size_t globals_count = 0; 83 | repl_value_t* global_vals = calloc(globals_size, sizeof(repl_value_t)); 84 | repl_value_t last_repl_val = {0}; 85 | 86 | // Init JIT 87 | LLVMInitializeNativeTarget(); 88 | LLVMInitializeNativeAsmPrinter(); 89 | LLVMLinkInMCJIT(); 90 | 91 | while (true) 92 | { 93 | // Get user input 94 | char* input = readline(">>> "); 95 | if (input == NULL || !strcmp(input, ":q") || !strcmp(input, ":quit")) 96 | { 97 | if (input == NULL) puts(""); 98 | free(input); 99 | break; 100 | } 101 | add_history(input); 102 | 103 | // Get next few lines if necessary 104 | char c; 105 | int p = count_groupings(input, 0); 106 | while ((c = input[strlen(input) - 1]) == '\\' || c == ',' || p > 0) 107 | { 108 | // Read next line 109 | char* next_line = readline("... "); 110 | if (input == NULL || !strcmp(next_line, "")) 111 | { 112 | if (input == NULL) puts(""); 113 | free(input); 114 | break; 115 | } 116 | add_history(next_line); 117 | p = count_groupings(next_line, p); 118 | 119 | // Concatenate 120 | char* buffer = calloc(strlen(input) + strlen(next_line) + 2, 1); 121 | strcat(buffer, input); 122 | strcat(buffer, "\n"); 123 | strcat(buffer, next_line); 124 | free(input); 125 | free(next_line); 126 | input = buffer; 127 | } 128 | 129 | // Init lexer 130 | init_lexer(&lex, input); 131 | free(input); 132 | 133 | // Print out tokens 134 | // token_t* token; 135 | // while ((token = lex_next(&lex))->type != LEX_TYPE_EOF) 136 | // { 137 | // printf("%s (%i:%i/%i)\n", token->value, token->lino, token->charpos, token->type); 138 | // } 139 | // lex.token_pos = 0; 140 | 141 | // Parse 142 | res = lang_parser(&lex); 143 | 144 | if (res.succ) 145 | { 146 | // Skip if no children 147 | if (res.ast->children_count == 0) 148 | continue; 149 | 150 | // Print 151 | print_ast(res.ast); 152 | 153 | // Generate IR code 154 | convert_ast_to_ir(res.ast, scope, &ir); 155 | print_ir(ir); 156 | 157 | // Type check 158 | // Build the LLVM IR if it's correct code 159 | if (check_correctness(ir, scope)) 160 | { 161 | print_ir(ir); 162 | 163 | generate_code(ir, env); 164 | char* modstr = LLVMPrintModuleToString(env->header_mod); 165 | printf("%s\n", modstr); 166 | free(modstr); 167 | modstr = LLVMPrintModuleToString(env->body_mod); 168 | printf("%s\n", modstr); 169 | free(modstr); 170 | 171 | // Create the execution engine 172 | char* error = NULL; 173 | LLVMExecutionEngineRef engine = NULL; 174 | if (LLVMCreateExecutionEngineForModule(&engine, env->body_mod, &error) || error != NULL) 175 | { 176 | fprintf(stderr, "engine error: %s\n", error); 177 | free(error); 178 | LLVMDisposeExecutionEngine(engine); 179 | return -1; 180 | } 181 | 182 | // Set global mappings 183 | LLVMValueRef global = LLVMGetFirstGlobal(env->header_mod); 184 | size_t i = 0; 185 | while (global != NULL) 186 | { 187 | size_t length = 0; 188 | if (strcmp(LLVMGetValueName2(global, &length), "repl.last")) 189 | { 190 | if (i < globals_count) 191 | list_append_element(global_vals, globals_size, globals_count, repl_value_t, (repl_value_t) {0}); 192 | LLVMAddGlobalMapping(engine, global, global_vals + i++); 193 | 194 | // The repl value global has its own special global value 195 | } else LLVMAddGlobalMapping(engine, global, &last_repl_val); 196 | 197 | global = LLVMGetNextGlobal(global); 198 | } 199 | 200 | // Run the code 201 | LLVMAddModule(engine, env->header_mod); 202 | LLVMDisposeGenericValue(LLVMRunFunction(engine, env->main_func, 0, (LLVMGenericValueRef[]) {})); 203 | 204 | // Print the result 205 | type_t* ret_type = ir.expr[ir.expr_count - 1]->type; 206 | printf(" = "); 207 | if (ret_type->type_type == IR_TYPES_PRIMITIVE && !strcmp(ret_type->type_name, "Int")) 208 | printf("%li", last_repl_val.i64); 209 | else if (ret_type->type_type == IR_TYPES_PRIMITIVE && !strcmp(ret_type->type_name, "Float")) 210 | printf("%.5f", last_repl_val.f64); 211 | else if (ret_type->type_type == IR_TYPES_PRIMITIVE && !strcmp(ret_type->type_name, "Bool")) 212 | printf("%s", last_repl_val.i1 ? "true" : "false"); 213 | else if (ret_type->type_type == IR_TYPES_FUNC) 214 | printf("(%i) %p: %i/%i args, bitmap = %li, args => %p", last_repl_val.func_app.reference_count, last_repl_val.func_app.func, last_repl_val.func_app.count, last_repl_val.func_app.arity, last_repl_val.func_app.thunk_bitmap, last_repl_val.func_app.args); 215 | else printf("unknown value"); 216 | puts(""); 217 | 218 | // Clean up 219 | LLVMRemoveModule(engine, env->header_mod, &env->header_mod, &error); 220 | empty_llvm_codegen_environment(env); 221 | LLVMDisposeExecutionEngine(engine); 222 | } else printf("Check failed\n"); 223 | 224 | clean_ir(&ir); 225 | } else 226 | { 227 | // Print out parsing error 228 | puts("an error occured"); 229 | printf("Expected %s, got '%s'\n", res.error->expected, res.error->value.value); 230 | printf(" (%i:%i)\n", res.error->value.lino, res.error->value.charpos); 231 | } 232 | 233 | // Clean up 234 | cleanup_lexer(&lex); 235 | clean_parse_result(res); 236 | } 237 | 238 | // Final clean up 239 | clean_functions(&ir); 240 | clean_types(); 241 | pop_scope(scope); 242 | free(global_vals); 243 | clean_llvm_codegen_environment(env); 244 | LLVMContextDispose(context); 245 | puts("Leaving Curly REPL"); 246 | return 0; 247 | } 248 | case 2: 249 | { 250 | // Set up 251 | FILE* file = fopen(argv[1], "r"); 252 | size_t size = 128; 253 | char* string = malloc(size + 1); 254 | string[0] = '\0'; 255 | 256 | // Read file 257 | while (!feof(file)) 258 | { 259 | size_t max = size - strlen(string); 260 | fgets(string + strlen(string), max < 64 ? max : 64, file); 261 | if (strlen(string) + 1 >= size) 262 | string = realloc(string, (size <<= 1) + 1); 263 | } 264 | 265 | // Close file 266 | fclose(file); 267 | 268 | // Init lexer 269 | lexer_t lex; 270 | init_lexer(&lex, string); 271 | free(string); 272 | 273 | // Print out tokens 274 | // token_t* token; 275 | // while ((token = lex_next(&lex))->type != LEX_TYPE_EOF) 276 | // { 277 | // printf("%s (%i:%i/%i)\n", token->value, token->lino, token->charpos, token->type); 278 | // } 279 | // lex.token_pos = 0; 280 | 281 | // Parse 282 | parse_result_t res = lang_parser(&lex); 283 | 284 | if (res.succ) 285 | { 286 | print_ast(res.ast); 287 | 288 | // Generate IR code 289 | ir_scope_t* scope = push_scope(NULL); 290 | curly_ir_t ir; 291 | init_ir(&ir); 292 | convert_ast_to_ir(res.ast, scope, &ir); 293 | print_ir(ir); 294 | 295 | // Type check 296 | if (check_correctness(ir, NULL)) 297 | { 298 | // Build the LLVM IR 299 | llvm_codegen_env_t* env = generate_code(ir, NULL); 300 | char* string = LLVMPrintModuleToString(env->body_mod); 301 | printf("%s", string); 302 | free(string); 303 | 304 | // Init JIT 305 | LLVMInitializeNativeTarget(); 306 | LLVMInitializeNativeAsmPrinter(); 307 | LLVMLinkInMCJIT(); 308 | 309 | // Create the execution engine 310 | char* error = NULL; 311 | LLVMExecutionEngineRef engine = NULL; 312 | if (LLVMCreateJITCompilerForModule(&engine, env->body_mod, 0, &error) || error != NULL) 313 | { 314 | fprintf(stderr, "engine error: %s\n", error); 315 | free(error); 316 | LLVMDisposeExecutionEngine(engine); 317 | return -1; 318 | } 319 | 320 | // Run the code 321 | LLVMDisposeGenericValue(LLVMRunFunction(engine, env->main_func, 0, (LLVMGenericValueRef[]) {})); 322 | 323 | // Clean up 324 | LLVMDisposeExecutionEngine(engine); 325 | clean_llvm_codegen_environment(env); 326 | } else printf("Check failed\n"); 327 | 328 | clean_functions(&ir); 329 | clean_ir(&ir); 330 | pop_scope(scope); 331 | } else 332 | { 333 | // Print out parsing error 334 | puts("an error occured"); 335 | printf("Expected %s, got '%s'\n", res.error->expected, res.error->value.value); 336 | printf(" (%i:%i)\n", res.error->value.lino, res.error->value.charpos); 337 | } 338 | 339 | // Clean up 340 | cleanup_lexer(&lex); 341 | clean_parse_result(res); 342 | clean_types(); 343 | return 0; 344 | } 345 | default: 346 | // Display usage message 347 | puts("usage: curly [filename]"); 348 | return -1; 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/utils/hashes.c: -------------------------------------------------------------------------------- 1 | // 2 | // hashes.c 3 | // 4 | // Created by jenra on 9/1/17. 5 | // 6 | 7 | #include "hashes.h" 8 | 9 | // one_at_a_time_hash(void*, size_t) -> size_t 10 | // One at a time hash algorithm; developed by Bob Jenkins. 11 | // 12 | // This is the default hashing algorithm used. 13 | size_t one_at_a_time_hash(void* key, size_t length) 14 | { 15 | unsigned char* p = key; 16 | size_t hash = 0; 17 | for (size_t i = 0; i < length; i++) 18 | { 19 | hash += p[i]; 20 | hash += hash << 10; 21 | hash ^= hash >> 6; 22 | } 23 | hash += hash << 3; 24 | hash ^= hash >> 11; 25 | hash += hash << 15; 26 | return hash; 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/hashes.h: -------------------------------------------------------------------------------- 1 | // 2 | // hashes.h 3 | // 4 | // Created by jenra on 9/1/17. 5 | // 6 | 7 | #ifndef HASHES_H 8 | #define HASHES_H 9 | 10 | #include 11 | 12 | // The default hashing algorithm used. 13 | #define hashing_function one_at_a_time_hash 14 | 15 | // one_at_a_time_hash(void*, size_t) -> size_t 16 | // One at a time hash algorithm, developed by Bob Jenkins. 17 | // 18 | // This is the default hashing algorithm used. 19 | size_t one_at_a_time_hash(void* key, size_t length); 20 | 21 | #endif /* HASHES_H */ 22 | -------------------------------------------------------------------------------- /src/utils/hashmap.c: -------------------------------------------------------------------------------- 1 | // 2 | // hashmap.c 3 | // 4 | // Created by jenra on 9/1/17. 5 | // 6 | 7 | #include 8 | 9 | #include "hashes.h" 10 | #include "hashmap.h" 11 | #include "list.h" 12 | 13 | // The maximum number of collisions in a hashmap before a resize occurs. 14 | #define HASHMAP_MAX_COLLISIONS 5 // TODO: Adjust. 15 | 16 | // init_hash_bucket(char*, size_t, void*) -> hash_bucket* 17 | // Initialises a hashmap bucket. 18 | hash_bucket* init_hash_bucket(char* key, size_t key_length, void* value) 19 | { 20 | hash_bucket* bucket = malloc(sizeof(hash_bucket)); 21 | bucket->key = strndup(key, key_length); 22 | bucket->key_length = key_length; 23 | bucket->value = value; 24 | bucket->next = NULL; 25 | bucket->last = bucket; 26 | return bucket; 27 | } 28 | 29 | // del_hash_bucket(hash_bucket*) -> hash_bucket* 30 | // Deletes a hashmap bucket, returning the next bucket with the same hash value. Note that values are not freed, since a hashmap does not know what type the value is and if it needs a special method to free it correctly, or even if the value is still needed! 31 | hash_bucket* del_hash_bucket(hash_bucket* bucket) 32 | { 33 | free(bucket->key); 34 | hash_bucket* next = bucket->next; 35 | free(bucket); 36 | return next; 37 | } 38 | 39 | // init_hashmap() -> hashmap_t* 40 | // Initialises a hashmap. 41 | hashmap_t* init_hashmap() 42 | { 43 | hashmap_t* map = malloc(sizeof(hashmap_t)); 44 | map->buckets = calloc(16, sizeof(hash_bucket*)); 45 | map->item_count = 0; 46 | map->bucket_count = 0; 47 | map->collision_count = 0; 48 | map->buckets_size = 16; 49 | map->function = hashing_function; 50 | map->resizing = false; 51 | return map; 52 | } 53 | 54 | // map_resize(hashmap_t*, bool) -> void 55 | // Resizes a hashmap and rehashes all the children. 56 | void map_resize(hashmap_t* map, bool grow) 57 | { 58 | map->resizing = true; 59 | hash_bucket* all_buckets = NULL; 60 | for (size_t i = 0; i < map->buckets_size; i++) 61 | { 62 | hash_bucket* current = map->buckets[i]; 63 | if (all_buckets == NULL) 64 | all_buckets = current; 65 | else 66 | { 67 | all_buckets->last->next = current; 68 | all_buckets->last = current->last; 69 | } 70 | } 71 | if (grow) 72 | map->buckets_size = map->buckets_size << 1; 73 | else 74 | map->buckets_size = map->buckets_size >> 1; 75 | map->buckets = realloc(map->buckets, map->buckets_size * sizeof(hash_bucket*)); 76 | 77 | // I didn't want to deal with repeating such a large block of code, so here is a malloc-heavy and free-heavy loop. 78 | while (all_buckets != NULL) 79 | { 80 | map_addn(map, all_buckets->key, all_buckets->key_length, all_buckets->value); 81 | all_buckets = del_hash_bucket(all_buckets); 82 | } 83 | map->resizing = false; 84 | } 85 | 86 | // map_add(hashmap_t*, char*, void*) -> void 87 | // Adds an element to a hashmap. 88 | void map_add(hashmap_t* map, char* key, void* value) 89 | { 90 | map_addn(map, key, strlen(key), value); 91 | } 92 | 93 | // map_addn(hashmap_t*, char*, size_t, void*) -> void 94 | // Adds an element to a hashmap. 95 | void map_addn(hashmap_t* map, char* key, size_t key_length, void* value) 96 | { 97 | if (key == NULL) 98 | return; 99 | 100 | if (!map->resizing && map->collision_count > HASHMAP_MAX_COLLISIONS) 101 | map_resize(map, true); 102 | size_t index = map->function(key, key_length) & (map->buckets_size - 1); 103 | if (map->buckets[index] == NULL) 104 | { 105 | map->buckets[index] = init_hash_bucket(key, key_length, value); 106 | map->bucket_count++; 107 | map->item_count++; 108 | } else 109 | { 110 | hash_bucket* first = map->buckets[index]; 111 | hash_bucket* current = first; 112 | while (true) 113 | { 114 | if (key_length == current->key_length && !strncmp(key, current->key, key_length)) 115 | { 116 | current->value = value; 117 | break; 118 | } else if (current->next == NULL) 119 | { 120 | current->next = init_hash_bucket(key, key_length, value); 121 | first->last = current->next; 122 | map->item_count++; 123 | map->collision_count++; 124 | break; 125 | } 126 | current = current->next; 127 | } 128 | } 129 | } 130 | 131 | // map_contains(hashmap_t*, char*) -> bool 132 | // Returns true if the hashmap contains a given key. 133 | bool map_contains(hashmap_t* map, char* key) 134 | { 135 | return map_containsn(map, key, strlen(key)); 136 | } 137 | 138 | // map_containsn(hashmap_t*, char*, size_t) -> bool 139 | // Returns true if the hashmap contains a given key. 140 | bool map_containsn(hashmap_t* map, char* key, size_t key_length) 141 | { 142 | if (key == NULL) 143 | return false; 144 | 145 | size_t index = map->function(key, key_length) & (map->buckets_size - 1); 146 | hash_bucket* current = map->buckets[index]; 147 | while (current != NULL) 148 | { 149 | if (key_length == current->key_length && !strncmp(key, current->key, key_length)) 150 | { 151 | return true; 152 | } 153 | current = current->next; 154 | } 155 | return false; 156 | } 157 | 158 | // map_keys(hashmap_t*, size_t*, size_t*) -> char** 159 | // Returns a list of keys in the hashmap, updating the length and size parameters accordingly. 160 | char** map_keys(hashmap_t* map, size_t* length, size_t* size) 161 | { 162 | // Set up 163 | size_t _length = 0; 164 | size_t _size = 0; 165 | char** keys = NULL; 166 | 167 | // Iterate over the buckets 168 | for (size_t i = 0; i < map->buckets_size; i++) 169 | { 170 | // Get every bucket in the bucket linked list for the current hash 171 | hash_bucket* current = map->buckets[i]; 172 | while (current != NULL) 173 | { 174 | list_append_element(keys, _size, _length, char*, current->key); 175 | current = current->next; 176 | } 177 | } 178 | 179 | // Update length and size 180 | if (length != NULL) 181 | { 182 | *length = _length; 183 | } 184 | if (size != NULL) 185 | { 186 | *size = _size; 187 | } 188 | return keys; 189 | } 190 | 191 | // map_get(hashmap_t*, char*) -> void* 192 | // Returns the value associated with the given key or NULL if it does not exist. 193 | void* map_get(hashmap_t* map, char* key) 194 | { 195 | return map_getn(map, key, strlen(key)); 196 | } 197 | 198 | // map_getn(hashmap_t*, char*, size_t) -> void* 199 | // Returns the value associated with the given key or NULL if it does not exist. 200 | void* map_getn(hashmap_t* map, char* key, size_t key_length) 201 | { 202 | if (key == NULL) 203 | return NULL; 204 | 205 | size_t index = map->function(key, key_length) & (map->buckets_size - 1); 206 | hash_bucket* current = map->buckets[index]; 207 | while (current != NULL) 208 | { 209 | if (key_length == current->key_length && !strncmp(key, current->key, key_length)) 210 | { 211 | return current->value; 212 | } 213 | current = current->next; 214 | } 215 | return NULL; 216 | } 217 | 218 | // map_remove(hashmap_t*, char*) -> void 219 | // Removes a key from a hashmap. 220 | void map_remove(hashmap_t* map, char* key) 221 | { 222 | map_removen(map, key, strlen(key)); 223 | } 224 | 225 | // map_removen(hashmap_t*, char*, size_t) -> void 226 | // Removes a key from a hashmap. 227 | void map_removen(hashmap_t* map, char* key, size_t key_length) 228 | { 229 | if (key == NULL) 230 | return; 231 | 232 | if (!map->resizing && map->item_count < map->buckets_size >> 5) // 16 seems like a good absolute minimum 233 | map_resize(map, false); 234 | size_t index = map->function(key, key_length) & (map->buckets_size - 1); 235 | hash_bucket* first = map->buckets[index]; 236 | hash_bucket* current = first; 237 | hash_bucket* previous = NULL; 238 | while (current != NULL) 239 | { 240 | if (key_length == current->key_length && !strncmp(key, current->key, key_length)) 241 | { 242 | if (current != first) 243 | { 244 | if (current->next == NULL) 245 | first->last = previous; 246 | previous->next = del_hash_bucket(current); 247 | } 248 | else 249 | { 250 | hash_bucket* last = first->last; 251 | first = del_hash_bucket(current); 252 | if (first != NULL) 253 | first->last = last; 254 | map->buckets[index] = first; 255 | } 256 | break; 257 | } 258 | previous = current; 259 | current = current->next; 260 | } 261 | } 262 | 263 | // del_hashmap(hashmap_t*) -> void 264 | // Deletes a hashmap. 265 | void del_hashmap(hashmap_t* map) 266 | { 267 | for (size_t i = 0; i < map->buckets_size; i++) 268 | { 269 | hash_bucket* current = map->buckets[i]; 270 | while (current != NULL) 271 | current = del_hash_bucket(current); 272 | } 273 | free(map->buckets); 274 | free(map); 275 | } 276 | -------------------------------------------------------------------------------- /src/utils/hashmap.h: -------------------------------------------------------------------------------- 1 | // 2 | // hashmap.h 3 | // 4 | // Created by jenra on 9/1/17. 5 | // 6 | 7 | #ifndef HASHMAP_H 8 | #define HASHMAP_H 9 | 10 | #include 11 | #include 12 | 13 | // (void*, size_t) -> size_t 14 | // Represents a hash function. 15 | typedef size_t (*hash_func)(void*, size_t); 16 | 17 | // Represents a bucket in a hashmap. 18 | typedef struct hash_bucket 19 | { 20 | // The key the bucket represents (used to resolve collisions). 21 | char* key; 22 | 23 | // The length of the key. 24 | size_t key_length; 25 | 26 | // The value the bucket holds. 27 | void* value; 28 | 29 | // The next bucket in the linked list of buckets with equivelent hash values. 30 | struct hash_bucket* next; 31 | 32 | // The last bucket in the linked list of buckets with equivelent hash values. 33 | struct hash_bucket* last; 34 | } hash_bucket; 35 | 36 | // Represents a hashmap. 37 | typedef struct hashmap_t 38 | { 39 | // The list of buckets. 40 | hash_bucket** buckets; 41 | 42 | // The number of items in the bucket list. (Includes collisions.) 43 | size_t item_count; 44 | 45 | // The number of buckets in the bucket list. (Does not include collisions.) 46 | size_t bucket_count; 47 | 48 | // The number of collisions in the bucket list. 49 | size_t collision_count; 50 | 51 | // The size of the bucket list. 52 | size_t buckets_size; 53 | 54 | // If the hashmap is currently being resized. 55 | bool resizing; 56 | 57 | // The hashing function used. 58 | hash_func function; 59 | } hashmap_t; 60 | 61 | // init_hashmap() -> hashmap_t* 62 | // Initialises a hashmap. 63 | hashmap_t* init_hashmap(void); 64 | 65 | // map_resize(hashmap_t*, bool) -> void 66 | // Resizes a hashmap and rehashes all the children. 67 | void map_resize(hashmap_t* map, bool grow); 68 | 69 | // map_add(hashmap_t*, char*, void*) -> void 70 | // Adds an element to a hashmap. 71 | void map_add(hashmap_t* map, char* key, void* value); 72 | 73 | // map_addn(hashmap_t*, char*, size_t, void*) -> void 74 | // Adds an element to a hashmap. 75 | void map_addn(hashmap_t* map, char* key, size_t key_length, void* value); 76 | 77 | // map_contains(hashmap_t*, char*) -> bool 78 | // Returns true if the hashmap contains a given key. 79 | bool map_contains(hashmap_t* map, char* key); 80 | 81 | // map_containsn(hashmap_t*, char*, size_t) -> bool 82 | // Returns true if the hashmap contains a given key. 83 | bool map_containsn(hashmap_t* map, char* key, size_t key_length); 84 | 85 | // map_keys(hashmap_t*, size_t*, size_t*) -> char** 86 | // Returns a list of keys in the hashmap, updating the length and size parameters accordingly. 87 | char** map_keys(hashmap_t* map, size_t* length, size_t* size); 88 | 89 | // map_get(hashmap_t*, char*) -> void* 90 | // Returns the value associated with the given key or NULL if it does not exist. 91 | void* map_get(hashmap_t* map, char* key); 92 | 93 | // map_getn(hashmap_t*, char*, size_t) -> void* 94 | // Returns the value associated with the given key or NULL if it does not exist. 95 | void* map_getn(hashmap_t* map, char* key, size_t key_length); 96 | 97 | // map_remove(hashmap_t*, char*) -> void 98 | // Removes a key from a hashmap. 99 | void map_remove(hashmap_t* map, char* key); 100 | 101 | // map_removen(hashmap_t*, char*, size_t) -> void 102 | // Removes a key from a hashmap. 103 | void map_removen(hashmap_t* map, char* key, size_t key_length); 104 | 105 | // del_hashmap(hashmap_t*) -> void 106 | // Deletes a hashmap. 107 | void del_hashmap(hashmap_t* map); 108 | 109 | #endif /* HASHMAP_H */ 110 | -------------------------------------------------------------------------------- /src/utils/list.c: -------------------------------------------------------------------------------- 1 | // 2 | // utils 3 | // list.c: Implements various util functions relating to lists. 4 | // 5 | // Created by jenra. 6 | // Created on July 27 2020. 7 | // 8 | 9 | #include "list.h" 10 | -------------------------------------------------------------------------------- /src/utils/list.h: -------------------------------------------------------------------------------- 1 | // 2 | // utils 3 | // list.h: Header file for list.c. 4 | // 5 | // Created by jenra. 6 | // Created on July 27 2020. 7 | // 8 | 9 | #ifndef UTILS_LIST_H 10 | #define UTILS_LIST_H 11 | 12 | #include 13 | 14 | #define list_append_element(list, size, count, type, element) \ 15 | do \ 16 | { \ 17 | if ((size) == 0) \ 18 | (list) = calloc(((size) = 8), sizeof(type)); \ 19 | else if ((size) <= (count)) \ 20 | (list) = realloc(list, ((size) <<= 1) * sizeof(type)); \ 21 | (list)[(count)++] = (element); \ 22 | } while (0) 23 | 24 | #endif /* UTILS_LIST_H */ 25 | -------------------------------------------------------------------------------- /tests/compile-tests/assign.curly: -------------------------------------------------------------------------------- 1 | x=2 2 | x=5 3 | y=x+4 4 | z=6*y 5 | z 6 | a: Int 7 | with a: Int, 8 | a = 2, 9 | a 10 | -------------------------------------------------------------------------------- /tests/compile-tests/infix.curly: -------------------------------------------------------------------------------- 1 | 1 2 | 1.0 3 | 1+2 4 | 4*5-3 5 | 4*(5-3) 6 | 3.14159*2.71828/6 7 | 1.0+1.0/(2*2)+1.0/(3*3)+1.0/(4*4)+1.0/(5*5)+1.0/(6*6) 8 | -------------------------------------------------------------------------------- /tests/compile-tests/with.curly: -------------------------------------------------------------------------------- 1 | a=with a = 10, 2 | b = 20, 3 | a + b 4 | 5 | w = with a = 30, 6 | b = 40, 7 | a + b 8 | a+w 9 | -------------------------------------------------------------------------------- /tests/correctness-tests/types.curly: -------------------------------------------------------------------------------- 1 | # types: 2 | # & - intersection type 3 | # * - product type 4 | # | - union type 5 | # >> - function type 6 | # *type - generator of type 7 | # [type] - list of type 8 | 9 | # n: (a:Int & b:Bool) = {2, false} # succeeds 10 | # y: Int = 0 # succeeds 11 | # y = 2 # succeeds 12 | # t: Type = int # succeeds 13 | # l = [1,2,3] # succeeds 14 | # l2 = ["a", "b", 3] # fails 15 | # y = "" # fails 16 | # y: String = "" # fails 17 | # x: String = x # fails 18 | # y # succeeds 19 | # z # fails 20 | 21 | # Pair = type T => T * T 22 | # p: Pair Int = {5, 4} 23 | 24 | # Comp = type rect: (x: Float & y: Float) | polar: (r: Float & theta: Float) 25 | # z1: Comp = {r = 1.0, theta = 2.0} 26 | # z2: Comp = {1.0, 2.0} 27 | 28 | Tree = type T => leaf: T | branch: (Tree T * Tree T) 29 | # t1: Tree Bool = { 30 | # branch = { 31 | # leaf = true, leaf = false 32 | # }, leaf = false 33 | # } 34 | # t2: Tree Bool = {{true, false}, false} 35 | # test: Bool = t2.branch.0 36 | # test: Tree Bool = false 37 | # test2: List (Tree Bool) = [test, {false, true}] 38 | 39 | # trees: List (Tree Bool) = [Tree {false, true}, Tree false] 40 | 41 | # func arg0: Int arg1: String = arg0 42 | 43 | # y: Bool = for all i in [1,2,3] i = true 44 | # y: Int = if true then 0 else false 45 | 46 | # x: *Int = x in [1,2,3] where x < 3 and x != 1 47 | 48 | # func a:Int b:String c:Float = 0 49 | # func (*{0, "", 0.0}) 50 | 51 | # x..xs = [1,2,3] 52 | # None: Enum = Nothing 53 | # Maybe: (Type >> Type) 54 | # Maybe T: Type = just: T | none: None 55 | 56 | # x test:Int = 2 57 | 58 | # Test: Enum = A | B 59 | # t1: Test = A 60 | # t2: Test = B 61 | 62 | # inp A = 0 63 | # inp B = 1 64 | # func a: Int b: Int c: Int d: Int e: Int f: Int g: Int = 0 65 | # func 1 2 3 4 5 6 7 66 | # "" 1 2 func A [1,2,3] 67 | # [1,2,3]."" 68 | 69 | # Linked: Type >> Type 70 | # Linked T: Type = T * (Maybe (Linked T)) 71 | # iterate: (Linked Int) >> *Int 72 | # iterate l: (Linked Int) = gen l.0 (*(iterate l.1)) 73 | -------------------------------------------------------------------------------- /tests/parsing-tests/for.curly: -------------------------------------------------------------------------------- 1 | sum = ( # create a generator 2 | with acc = 0, # acc (accumulator) starts at 0 3 | for i in (range 1 101 (-2)) # iterate over the range 100, 98, 96, ..., 4, 2 4 | acc = i + acc # sum the values up 5 | ) 6 | -------------------------------------------------------------------------------- /tests/parsing-tests/func-apply.curly: -------------------------------------------------------------------------------- 1 | add_vars x:t1 y:t2 z:t3 = x + y + z 2 | add_vars 4 2 5 3 | 4 | a b c d # comment 5 | s (n s z) # more comments 6 | x y z a \ 7 | f g y \ 8 | b e # even more comments 9 | o r # one last comment 10 | 11 | # this is a comment 12 | -------------------------------------------------------------------------------- /tests/parsing-tests/if.curly: -------------------------------------------------------------------------------- 1 | # I know you know how if statements work 2 | # I'm just testing comments 3 | if x <= 2 or x in myList # condition 4 | then y = "less than" # on true 5 | else z = "greater than" # on false 6 | 7 | 8 | "here is 9 | a multiline 10 | string 11 | with a \" 12 | quotation mark" 13 | -------------------------------------------------------------------------------- /tests/parsing-tests/test.curly: -------------------------------------------------------------------------------- 1 | # assignments 2 | a = 0 3 | b: int = 1 4 | x..xs = [ 5 | 1,2,3 6 | ] 7 | add 0 y: int = y 8 | add x: int y: int = 1 + (add x - 1 y) 9 | 10 | # with expressions 11 | with a = 2, a 12 | with a = 2, b = 3, add a b 13 | 14 | # if statements 15 | if true then x = 2 16 | x = if x >= 3 then 3 else x 17 | 18 | # for loops 19 | for i in iter i 20 | with acc = 0, 21 | for i in iter 22 | acc = acc + i 23 | [for i in iter i] 24 | for all i in iter f i 25 | for some i in iter f i 26 | 27 | # where expressions 28 | [x in iter where f x] 29 | 30 | # lists 31 | [ 32 | 1,2,3, 33 | 4,5 34 | ] 35 | [[[3,1,4], [1,5,9]], [[2,6,5],[3,5,8]]] 36 | 37 | # structures 38 | {a, b=2, {c=3}} 39 | 40 | # function application 41 | a b c (d e f) g (*h) i (-j) 42 | "three strings" " " "concated" 43 | -------------------------------------------------------------------------------- /tests/parsing-tests/values.txt: -------------------------------------------------------------------------------- 1 | 420 -69 2 | 4.3 -5.4 6e+3 7e-2 0.23E3 0.2e5 3 | 'a' 'b' '\x45' '\xAF' '\x2a' 4 | _ _a this_is_a_test f f' f'' f''' 5 | -------------------------------------------------------------------------------- /tests/parsing-tests/where.curly: -------------------------------------------------------------------------------- 1 | [ 2 | a in iter where 3 | a >= 2 4 | ] 5 | --------------------------------------------------------------------------------