├── .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 |
--------------------------------------------------------------------------------