Compare commits
	
		
			60 Commits
		
	
	
		
			c2f2658e9c
			...
			v1.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 24f93ce750 | |||
| 2fc3f1e1df | |||
| 9525535323 | |||
| 0fa1c176f4 | |||
| 868dcb6788 | |||
| 4fb698918c | |||
| df74d29e54 | |||
| 7181b31d4b | |||
| 7630e4b99f | |||
| 74d5a212cd | |||
| 90fce2fce4 | |||
| 94689be83b | |||
| cb5fa27eb3 | |||
| 7c08e8da4d | |||
| fdf526750d | |||
| 4e5b12b5b2 | |||
| b102a32999 | |||
| 518f2e9803 | |||
| 0e6bb7aa16 | |||
| 14ddf51f3c | |||
| ac1d76361f | |||
| b789193484 | |||
| ab97f78fab | |||
| 7c0b212ab4 | |||
| 80c8038374 | |||
| e3cd78e1b4 | |||
| b7b90f528b | |||
| 0ef44be808 | |||
| 8924818ec4 | |||
| 73efa7e136 | |||
| 4e8d7131d6 | |||
| bfce18ab81 | |||
| 7b648c4bd7 | |||
| 4ec5d1c075 | |||
| 5ba070ced7 | |||
| 8256643c0b | |||
| 29a217928e | |||
| 482f2b4877 | |||
| 36fd838a8f | |||
| 289243de38 | |||
| 67aafb3ead | |||
| 3b5bee0695 | |||
| 970fc39198 | |||
| 8d3e43d7dc | |||
| d4293e87f3 | |||
| abb8ff6b58 | |||
| 80122b6572 | |||
| a4afd3b58a | |||
| 90c8c91410 | |||
| f5ab0e9cb0 | |||
| 0fb1f1d55f | |||
| 1d83aa65a4 | |||
| 3f30662cde | |||
| 743d16f696 | |||
| 7b99292547 | |||
| 4a516d8edb | |||
| 5b0950cabb | |||
| 40051de9ae | |||
| 2d01b09ee9 | |||
| ff68b756ef | 
							
								
								
									
										87
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,20 +1,20 @@ | ||||
| # SCL: Simple CAS Language | ||||
|  | ||||
| Version v1.0-alpha | ||||
| *v0.3* | ||||
|  | ||||
| SCL aims to be a human-friendly Computer Algebra System (CAS) inspired by | ||||
| [maxima](https://maxima.sourceforge.io/) that feels like writing on paper. In | ||||
| its current state, SCL can be used as a basic 4-function calculator with order | ||||
| of operations and local variables. The codebase is about 1,400 lines of C, | ||||
| including a parser, interpreter, and runtime. It uses a linked environment | ||||
| scoping model. | ||||
| its current state, SCL can be used as a functional programming language capable | ||||
| of performing simple arithmetic. The codebase is about 2,000 lines of | ||||
| handwritten C, including a parser, interpreter, and runtime. It uses a linked | ||||
| environment scoping model. | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| To download and run: | ||||
|  | ||||
| ```bash | ||||
| git clone https://git.signorovitch.org/jacob/scl -b stable && cd scl | ||||
| git clone https://git.signorovitch.org/scl/scl -b stable && cd scl | ||||
| make release | ||||
| ./scl.out | ||||
| ``` | ||||
| @@ -22,75 +22,50 @@ make release | ||||
| ### For Development | ||||
|  | ||||
| ```bash | ||||
| git clone git@signorovitch.org:jacob/scl --recurse-submodules && cd scl | ||||
| git clone git@signorovitch.org:scl/scl --recurse-submodules && cd scl | ||||
| make all test | ||||
| ./scl.out | ||||
| ``` | ||||
|  | ||||
| If you wish to run tests, make sure to run `git clone --recurse-submodules` to | ||||
| include the [Unity](https://github.com/ThrowTheSwitch/Unity) test framework. | ||||
| *Note that tests are currently in poor use. I hope to amend this in the future.* | ||||
|  | ||||
| ## Syntax | ||||
|  | ||||
| As one would expect, you can evaluate simple infix expressions: | ||||
| SCL's syntax will feel familiar to other functional programming languages. | ||||
|  | ||||
| ```scl | ||||
| > 1 + 1 | ||||
| > x = 3 + 3 * 3; x + 1 | ||||
| = 13 | ||||
| > f(x) x + 1 | ||||
| > f(1) | ||||
| = 2 | ||||
| ``` | ||||
|  | ||||
| You can also define your own functions and variables: | ||||
|  | ||||
| ```scl | ||||
| > f(x) = 2x | ||||
| > n = 3 | ||||
| > f(n) | ||||
| = 6 | ||||
| ``` | ||||
|  | ||||
| As SCL uses a linked environment model for scope, arguments are passed by | ||||
| reference by default. If you would like to pass by value (i.e., a copy) you may | ||||
| use the syntax: | ||||
|  | ||||
| ```scl | ||||
| > f(x) = x = 1 | ||||
| > n = 4 | ||||
| > f($n) # Pass a copy of n. | ||||
| = 1 | ||||
| > n | ||||
| > (\(x) 2 * x)(5) | ||||
| = 10 | ||||
| > f(g) g(2) | ||||
| > f(\(x) 2 * x) | ||||
| = 4 | ||||
| > f(n) # Pass a reference to n. | ||||
| = 1 | ||||
| > n | ||||
| > 1 | ||||
| ``` | ||||
|  | ||||
| Symbolic algebra is done in the following manner: | ||||
| Here's a simple factorial function, using recursion: | ||||
|  | ||||
| ```scl | ||||
| > f(x) = x^4 | ||||
| > diff(f, x:sym, 2) | ||||
| = 12x^2 | ||||
| > fac(n) = { | ||||
| >   f(n, a) = { | ||||
| >     if n == 1 | ||||
| >       a | ||||
| >     else | ||||
| >       f(n - 1, a * n); | ||||
| >   } | ||||
| > | ||||
| >   f(n, 1); | ||||
| > } | ||||
| ``` | ||||
|  | ||||
| SCL will dynamically decide on types, but you can state them explicitly as | ||||
| well: | ||||
| SCL's syntax is quite flexible. The above function could be more concisely | ||||
| written as: | ||||
|  | ||||
| ```scl | ||||
| > f(x: int): int = 2x | ||||
| > f(3) | ||||
| = 6 | ||||
| > f(3.1) | ||||
| ! Traceback: | ||||
| ! In call to `f(x: int): int`: | ||||
| ! TypeError (58): Argument `x` must be of type `int`. | ||||
| ``` | ||||
|  | ||||
| Variables can be defined, with several attributes: | ||||
|  | ||||
| ```scl | ||||
| > a = 1             // Interpret type automatically. | ||||
| > b:int = 1         // Must be int. | ||||
| > c:const:int = 1   // Constant: value can never change. | ||||
| > x:sym             // Treated symbolicaly. | ||||
| > fac(n) (n, 1) -> f(n, a) ? n == 1 a f(n - 1, a * n) | ||||
| ``` | ||||
|   | ||||
							
								
								
									
										16
									
								
								STATUS.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								STATUS.md
									
									
									
									
									
								
							| @@ -12,33 +12,33 @@ | ||||
|   - [x] Order of operations | ||||
|   - [x] Parse function application | ||||
|   - [x] Parse order of operations with parenthesis | ||||
|   - [ ] Parse variable invocation | ||||
|   - [x] Parse variable invocation | ||||
|   - [x] Parse variable definition | ||||
|     - [ ] Parse types | ||||
|   - [ ] Parse function definition | ||||
|   - [x] Parse function definition | ||||
|   - [ ] Parse lists/arrays/vectors | ||||
|   - [x] Parse blocks | ||||
|   - [ ] Parse control flow | ||||
|     - [ ] Parse `if` statements | ||||
|     - [x] Parse `if` statements | ||||
|     - [ ] Parse `loop`s | ||||
|     - [ ] Parse `for` loops | ||||
|     - [ ] Parse `while` loops | ||||
|     - [ ] Parse `case` statements | ||||
|     - [ ] Parse `goto` statements | ||||
|   - [ ] Parse lambda function definition | ||||
|   - [x] Parse lambda function definition | ||||
|   - [ ] Parse function calling with positional arguments | ||||
|   - [ ] Parse variadic functions | ||||
|   - [ ] Parse infix function definition | ||||
|  | ||||
| - [ ] Executer | ||||
|   - [x] Exec function calls | ||||
|   - [ ] Exec variable use | ||||
|   - [ ] Exec variable definition | ||||
|   - [ ] Exec function definition | ||||
|   - [x] Exec variable use | ||||
|   - [x] Exec variable definition | ||||
|   - [x] Exec function definition | ||||
|   - [ ] Exec symbolic variables | ||||
|   - [ ] Exec control flow statements | ||||
|   - [ ] Exec variadic functions | ||||
|   - [ ] Exec lambda functions | ||||
|   - [x] Exec lambda functions | ||||
|   - [ ] Exec lists | ||||
|   - [ ] Exec arrays | ||||
|   - [ ] Exec vectors | ||||
|   | ||||
							
								
								
									
										11
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								TODO.md
									
									
									
									
									
								
							| @@ -1,7 +1,10 @@ | ||||
| 0. Create file to describe properties of terminology used; param, arg, var, &c. | ||||
| 1. Differenciate parameters and arguments -- params for function definitions, | ||||
| arguments for function calls | ||||
| 2. Add scope field to all ASTs, and new scope layer for those that need it. | ||||
| Differentiate kind literals, constructors, and kinds themselves. | ||||
| EXCEPTION HANDLING: exception ast type should have as data a giant enum of | ||||
| possible types, rather than a char* message. A description of each type could be | ||||
| handled under the exception type and print logic. For now, executor checks | ||||
| message for special exceptions e.g. exit(). | ||||
|  | ||||
| Change editor to GNU Readline. | ||||
| Make variables persist through lines in the editor. | ||||
|  | ||||
| Return syntax errors as exceptions. | ||||
|   | ||||
| @@ -11,7 +11,7 @@ TEST_DIR = test | ||||
| TEST_BUILD_DIR = $(BUILD_DIR)/test | ||||
| TEST_OBJ_DIR = $(TEST_BUILD_DIR)/obj | ||||
|  | ||||
| CC = clang -std=c2x | ||||
| CC = clang -std=c23 | ||||
| LINK = clang | ||||
| CFLAGS = -Wall -DDBG -ggdb -fsanitize=leak | ||||
| LDFLAGS = -lm | ||||
|   | ||||
							
								
								
									
										25
									
								
								definitions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								definitions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| f = \(x) 2 * x | ||||
| g = \(h) \(x) h(h(x)) | ||||
|  | ||||
| f(2) => 4 | ||||
| g(f)(2) => 8 | ||||
|  | ||||
| CALL | ||||
|  argc: 1 | ||||
|  argv: [ 2 ] | ||||
|  to: | ||||
|   CALL | ||||
|    argc: 1 | ||||
|    argv: [ | ||||
|     VREF | ||||
|      name: f | ||||
|    ] | ||||
|    to: | ||||
|     VREF | ||||
|      name: g | ||||
|  fname: NULL | ||||
|  | ||||
|  | ||||
| expression + arguments = call = expression | ||||
| expression + parameters = lambda = expression | ||||
| expression + name = variable = expression | ||||
| @@ -1,3 +1,2 @@ | ||||
| f(n) = 2 * n | ||||
|  | ||||
| f(5) | ||||
| apply(f, x) f(x) | ||||
| apply(\(x) x + 1, 2) | ||||
|   | ||||
| @@ -1,48 +1,3 @@ | ||||
| # Vectors | ||||
| # - Must have fixed size and type | ||||
| x: Int = 3 | ||||
|  | ||||
| # Lists | ||||
| # - Variable size, variable type | ||||
|  | ||||
| # Define a variable of type int: | ||||
| n: int = 3 | ||||
|  | ||||
| # Define v as a 3-dimensional vector of integers: | ||||
| v: int<3> = <4, 5, 6> | ||||
|  | ||||
| # Define l as list of length 3: | ||||
| l: [3] = [1, 2, "These can be any type at all"] | ||||
| # This would also work, as length values for lists are optional (and mutable), | ||||
| # unlike vectors: | ||||
| l: [] = [1, 2, "whatever"] | ||||
| # This is also the same, being more explicit about the any type: | ||||
| l: any[] = [1, 2, "whatever"] | ||||
| # This must be a list of integers, however: | ||||
| l: int[] = [1, 2, 3] | ||||
|  | ||||
| # Define a list of either integers or strings: | ||||
| l: union(int, str)[] = ["hello", 4, "world"] | ||||
| # union() is a complex type generator; "returns" a union of the int and str types. | ||||
|  | ||||
| # Use vectors wherever possible, as they are much faster than lists. | ||||
|  | ||||
| # Matrix | ||||
| # - Must have a fixed size and type (just like vectors) | ||||
| m: int<2, 2> = <<0, 1>, <2, 3>> | ||||
| # Can also be written as | ||||
| m: int<2, 2> = <<0, 1, 2, 3>> | ||||
| # When using this syntax, will fill remaining space with default value of type | ||||
| # to make data rectangular. E.g., to fill a 2 x 2 matrix with 0: | ||||
| m: int<2, 2> = <<>> | ||||
|  | ||||
| # To define custom data types, e.g. structs: | ||||
| typedef(Vec2, struct( a: int, b: int )) | ||||
| vector_two: Vec2 = Vec2(2, 3) | ||||
|  | ||||
| typedef(IntOrStr, union(str, int)) | ||||
| one: IntOrStr = 1 | ||||
| alsoOne: IntOrStr = "one" | ||||
|  | ||||
| # To define custom data types with type arguments: | ||||
| typedef(Vec1Of(T), T<1>) | ||||
| hello: Vec1Of(str) = <"Hello"> | ||||
| <name> : <expression> = <expression> | ||||
|   | ||||
							
								
								
									
										282
									
								
								src/ast.c
									
									
									
									
									
								
							
							
						
						
									
										282
									
								
								src/ast.c
									
									
									
									
									
								
							| @@ -1,34 +1,31 @@ | ||||
| #include <inttypes.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "include/ast.h" | ||||
| #include "include/dstr.h" | ||||
| #include "include/htab.h" | ||||
| #include "include/gc.h" | ||||
| #include "include/scope.h" | ||||
| #include "include/util.h" | ||||
|  | ||||
| extern AST* root; | ||||
|  | ||||
| static char* asttype_names[] = { | ||||
|     [AST_TYPE_CALL] = "FUNC CALL", | ||||
|     [AST_TYPE_NUM] = "NUMBER", | ||||
|     [AST_TYPE_VREF] = "VAR REFERENCE", | ||||
|     [AST_TYPE_VDEF] = "VAR DEFINITION", | ||||
|     [AST_TYPE_BLOCK] = "BLOCK", | ||||
|     [AST_TYPE_EXC] = "EXCEPTION", | ||||
|     [AST_TYPE_FDEF] = "FUNCTION DEFINITION", | ||||
|     [AST_TYPE_ARG] = "DEFINITION ARGUMENT" | ||||
| }; | ||||
|  | ||||
| AST* ast_init(ASTType type, void* data) { | ||||
|     AST* ast = malloc(sizeof(AST)); | ||||
|     AST* ast = gc_alloc(sizeof(AST), GC_TYPE_AST); | ||||
|  | ||||
|     ast->type = type; | ||||
|     ast->data = data; | ||||
|     ast->scope = NULL; | ||||
|  | ||||
|     if (ast->type > AST_TYPE_MAX) { | ||||
|         log_dbgf( | ||||
|             "Attempted to create invalid AST (%i > %i) to GC: ast:%p", | ||||
|             ast->type, AST_TYPE_MAX, ast | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     return ast; | ||||
| } | ||||
|  | ||||
| AST* ast_init_scope(ASTType type, void* data, HTab* scope) { | ||||
| AST* ast_init_scope(ASTType type, void* data, Scope* scope) { | ||||
|     AST* ast = malloc(sizeof(AST)); | ||||
|  | ||||
|     ast->type = type; | ||||
| @@ -42,45 +39,24 @@ void ast_destroy(AST* ast) { | ||||
|     if (!ast) return; | ||||
|  | ||||
|     switch (ast->type) { | ||||
|         case AST_TYPE_NUM:   ast_num_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_CALL:  ast_call_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_VREF:  ast_vref_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_VDEF:  ast_vdef_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_BLOCK: ast_block_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_FDEF:  ast_fdef_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_ARG:   ast_arg_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_LIT_NUM:  ast_num_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_LIT_BOOL: ast_bool_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_LIT_KIND: ast_kind_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_CALL:     ast_call_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_REF:      ast_ref_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_DEF:      ast_def_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_BLOCK:    ast_block_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_ARG:      ast_arg_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_BIF:      ast_bif_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_EXC:      ast_exc_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_LAMBDA:   ast_lambda_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_FORCE:    ast_force_data_destroy(ast->data); break; | ||||
|         case AST_TYPE_PRESERVE: ast_preserve_data_destroy(ast->data); break; | ||||
|         default: | ||||
|             log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX); | ||||
|     } | ||||
|  | ||||
|     free(ast); | ||||
|     htab_destroy(ast->scope); | ||||
| } | ||||
|  | ||||
| void ast_print(AST* ast) { ast_print_i(ast, 0); } | ||||
|  | ||||
| void ast_print_i(AST* ast, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("AST", ast); | ||||
|     INDENT_FIELD("type", "%s", asttype_names[ast->type]); | ||||
|     INDENT_FIELD("scope", "%p", ast->scope); | ||||
|     INDENT_FIELD_EXT_NONL_START("data"); | ||||
|     switch (ast->type) { | ||||
|         case AST_TYPE_NUM: | ||||
|             printf("%s  %lf\n", INDENT_spacing->buf, *(ASTNumData*)ast->data); | ||||
|             break; | ||||
|         case AST_TYPE_CALL:  ast_call_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_EXC:   ast_exc_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_VREF:  ast_vref_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_VDEF:  ast_vdef_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_BLOCK: ast_block_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_FDEF:  ast_fdef_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_ARG:   ast_arg_print(ast->data, i + 2); break; | ||||
|         default:             exit(1); | ||||
|     } | ||||
|     INDENT_FIELD_NONL_END; | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| ASTNumData* ast_num_data_init(double val) { | ||||
| @@ -93,46 +69,72 @@ ASTNumData* ast_num_data_init(double val) { | ||||
|  | ||||
| void ast_num_data_destroy(ASTNumData* num) { free(num); } | ||||
|  | ||||
| void ast_num_print(ASTNumData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
| ASTBoolData* ast_bool_data_init(int val) { | ||||
|     talloc(ASTBoolData, bol); | ||||
|  | ||||
|     INDENT_FIELD("data", "%lf", *data); | ||||
|     *bol = val; | ||||
|  | ||||
|     INDENT_END; | ||||
|     return bol; | ||||
| } | ||||
|  | ||||
| ASTExcData* ast_exc_data_init(char* msg, AST* trace) { | ||||
| void ast_bool_data_destroy(ASTBoolData* bol) { free(bol); } | ||||
|  | ||||
| const char* ast_lit_kind_names[AST_LIT_KIND_MAX + 2] = { | ||||
|     [AST_LIT_KIND_NUM] = "Number", | ||||
|     [AST_LIT_KIND_BOOL] = "Boolean", | ||||
|     [AST_LIT_KIND_KIND] = "Type", | ||||
| }; | ||||
|  | ||||
| ASTKindData* ast_kind_data_init(ASTKindData val) { | ||||
|     talloc(ASTKindData, kind); | ||||
|     *kind = val; | ||||
|  | ||||
|     return kind; | ||||
| } | ||||
|  | ||||
| void ast_kind_data_destroy(ASTKindData* kind) { free(kind); } | ||||
|  | ||||
| ASTExcData* ast_exc_data_init(const char* msg, AST* trace) { | ||||
|     ASTExcData* data = malloc(sizeof(ASTExcData)); | ||||
|     data->msg = msg; | ||||
|     data->trace = trace; | ||||
|     return data; | ||||
| } | ||||
|  | ||||
| void ast_exc_print(ASTExcData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("ASTExcData", data); | ||||
|     INDENT_FIELD("msg", "\"%s\"", data->msg); | ||||
|     if (data->trace == NULL) { | ||||
|         INDENT_FIELD("trace", "%p", NULL) | ||||
|     } else { | ||||
|         INDENT_FIELD_EXT_NONL_START("trace"); | ||||
|         ast_print_i(data->trace, i + 1); | ||||
|         INDENT_FIELD_NONL_END; | ||||
|     } | ||||
|     INDENT_END; | ||||
| void ast_exc_data_destroy(ASTExcData* exc) { | ||||
|     // `msg` is static, and `trace` will get freed in GC. | ||||
|     free(exc); | ||||
| } | ||||
|  | ||||
| ASTBIFData* ast_bif_data_init(AST* fn(size_t, AST**)) { | ||||
| ASTBIFData* ast_bif_data_init(AST* fn(size_t, AST**, Scope*)) { | ||||
|     return (ASTBIFData*)fn; | ||||
| } | ||||
|  | ||||
| ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv) { | ||||
| void ast_bif_data_destroy(ASTBIFData* bif) { return; } | ||||
|  | ||||
| // Lambda. | ||||
|  | ||||
| ASTLambdaData* ast_lambda_data_init(size_t parc, AST** parv, AST* body) { | ||||
|     talloc(ASTLambdaData, lambda); | ||||
|  | ||||
|     lambda->parc = parc; | ||||
|     lambda->parv = parv; | ||||
|     lambda->body = body; | ||||
|  | ||||
|     return lambda; | ||||
| } | ||||
|  | ||||
| void ast_lambda_data_destroy(ASTLambdaData* lambda) { | ||||
|     free(lambda->parv); | ||||
|     free(lambda); | ||||
| } | ||||
|  | ||||
| // Call. | ||||
|  | ||||
| ASTCallData* ast_call_data_init(size_t argc, AST** argv, AST* exp) { | ||||
|     talloc(ASTCallData, call); | ||||
|  | ||||
|     log_dbgf("to: %s", to); | ||||
|  | ||||
|     call->to = to; | ||||
|     call->exp = exp; | ||||
|     call->argc = argc; | ||||
|     call->argv = argv; | ||||
|  | ||||
| @@ -141,70 +143,40 @@ ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv) { | ||||
|  | ||||
| void ast_call_data_destroy(ASTCallData* call) { | ||||
|     if (!call) return; | ||||
|     free(call->to); | ||||
|     for (size_t i = 0; i < call->argc; i++) ast_destroy(call->argv[i]); | ||||
|     free(call->argv); | ||||
|     free(call); | ||||
| } | ||||
|  | ||||
| void ast_call_print(ASTCallData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
| // Def. | ||||
|  | ||||
|     INDENT_TITLE("ASTCallData", data); | ||||
|     INDENT_FIELD("to", "%s", data->to); | ||||
|     INDENT_FIELD("argc", "%ld", data->argc); | ||||
|     INDENT_FIELD_LIST("argv", data->argv, data->argc, ast_print_i); | ||||
| ASTDefData* ast_def_data_init(char* name, AST* kind, AST* exp) { | ||||
|     talloc(ASTDefData, def); | ||||
|  | ||||
|     INDENT_END; | ||||
|     def->name = name; | ||||
|     def->kind = kind; | ||||
|     def->exp = exp; | ||||
|  | ||||
|     return def; | ||||
| } | ||||
|  | ||||
| ASTVDefData* ast_vdef_data_init(char* name, AST* val) { | ||||
|     talloc(ASTVDefData, vdef); | ||||
|  | ||||
|     vdef->name = name; | ||||
|     vdef->val = val; | ||||
|  | ||||
|     return vdef; | ||||
| } | ||||
|  | ||||
| void ast_vdef_data_destroy(ASTVDefData* vdef) { | ||||
|     ast_destroy(vdef->val); | ||||
| void ast_def_data_destroy(ASTDefData* vdef) { | ||||
|     free(vdef->name); | ||||
|     free(vdef); | ||||
| } | ||||
|  | ||||
| void ast_vdef_print(ASTVDefData* vdef, int depth) { | ||||
|     INDENT_BEGIN(depth); | ||||
| // Ref. | ||||
|  | ||||
|     INDENT_TITLE("ASTVDefData", vdef); | ||||
|     INDENT_FIELD("name", "%s", vdef->name); | ||||
|     INDENT_FIELD_EXT_NONL_START("val"); | ||||
|     ast_print_i(vdef->val, depth + 2); // 2 because already indented. | ||||
|     INDENT_FIELD_NONL_END; | ||||
| ASTRefData* ast_ref_data_init(char* to) { | ||||
|     talloc(ASTRefData, ref); | ||||
|  | ||||
|     INDENT_END; | ||||
|     ref->to = to; | ||||
|  | ||||
|     return ref; | ||||
| } | ||||
|  | ||||
| ASTVrefData* ast_vref_data_init(char* to) { | ||||
|     talloc(ASTVrefData, vref); | ||||
|  | ||||
|     vref->to = to; | ||||
|  | ||||
|     return vref; | ||||
| } | ||||
|  | ||||
| void ast_vref_data_destroy(ASTVrefData* vref) { | ||||
|     free(vref->to); | ||||
|     free(vref); | ||||
| } | ||||
|  | ||||
| void ast_vref_print(ASTVrefData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("ASTVrefData", data); | ||||
|     INDENT_FIELD("to", "%s", data->to); | ||||
|  | ||||
|     INDENT_END; | ||||
| void ast_ref_data_destroy(ASTRefData* ref) { | ||||
|     free(ref->to); | ||||
|     free(ref); | ||||
| } | ||||
|  | ||||
| ASTBlockData* ast_block_data_init(AST** inside, size_t ln) { | ||||
| @@ -217,51 +189,10 @@ ASTBlockData* ast_block_data_init(AST** inside, size_t ln) { | ||||
| } | ||||
|  | ||||
| void ast_block_data_destroy(ASTBlockData* block) { | ||||
|     for (size_t i = 0; i < block->ln; i++) { ast_destroy(block->inside[i]); } | ||||
|  | ||||
|     free(block->inside); | ||||
|     free(block); | ||||
| } | ||||
|  | ||||
| void ast_block_print(ASTBlockData* data, int depth) { | ||||
|     INDENT_BEGIN(depth); | ||||
|  | ||||
|     INDENT_TITLE("ASTBlockData", data); | ||||
|     INDENT_FIELD("ln", "%ld", data->ln); | ||||
|     INDENT_FIELD_LIST("inside", data->inside, data->ln, ast_print_i); | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| ASTFDefData* | ||||
| ast_fdef_data_init(char* name, size_t argc, AST** argv, AST* body) { | ||||
|     ASTFDefData* fdef = malloc(sizeof(ASTFDefData)); | ||||
|  | ||||
|     fdef->name = name; | ||||
|     fdef->argc = argc; | ||||
|     fdef->argv = argv; | ||||
|     fdef->body = body; | ||||
|  | ||||
|     return fdef; | ||||
| } | ||||
|  | ||||
| void ast_fdef_data_destroy(ASTFDefData* fdef) { | ||||
|     free(fdef->name); | ||||
|     for (int i = 0; i < fdef->argc; ast_destroy(fdef->argv[i++])); | ||||
|     ast_destroy(fdef->body); | ||||
| } | ||||
|  | ||||
| void ast_fdef_print(ASTFDefData* fdef, int i) { | ||||
|     INDENT_BEGIN(i) | ||||
|     INDENT_TITLE("ASTFDefData", fdef); | ||||
|     INDENT_FIELD("name", "%s", fdef->name); | ||||
|     INDENT_FIELD("argc", "%ld", fdef->argc); | ||||
|     INDENT_FIELD_LIST("argv", fdef->argv, fdef->argc, ast_print_i); | ||||
|     INDENT_FIELD_EXT_NONL_START("body"); | ||||
|     ast_print_i(fdef->body, i + 2); | ||||
|     INDENT_FIELD_NONL_END; | ||||
| } | ||||
|  | ||||
| ASTArgData* ast_arg_data_init(char* name) { | ||||
|     ASTArgData* arg = malloc(sizeof(ASTArgData)); | ||||
|     arg->name = name; | ||||
| @@ -270,9 +201,28 @@ ASTArgData* ast_arg_data_init(char* name) { | ||||
|  | ||||
| void ast_arg_data_destroy(ASTArgData* arg) { free(arg->name); } | ||||
|  | ||||
| void ast_arg_print(ASTArgData* arg, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|     INDENT_TITLE("ASTArgData", arg); | ||||
|     INDENT_FIELD("name", "%s", arg->name); | ||||
|     INDENT_END; | ||||
| AST* ast_find(Scope* scope, char* name) { | ||||
|     while (scope) { | ||||
|         AST* gotten = htab_get(scope->here, name); | ||||
|         if (gotten) return gotten; | ||||
|         else scope = scope->inherit; | ||||
|     } | ||||
|  | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| ASTForceData* ast_force_data_init(AST* body) { | ||||
|     talloc(ASTForceData, force); | ||||
|     force->body = body; | ||||
|     return force; | ||||
| } | ||||
|  | ||||
| void ast_force_data_destroy(ASTForceData* force) { free(force); } | ||||
|  | ||||
| ASTPreserveData* ast_preserve_data_init(AST* body) { | ||||
|     talloc(ASTPreserveData, preserve); | ||||
|     preserve->body = body; | ||||
|     return preserve; | ||||
| } | ||||
|  | ||||
| void ast_preserve_data_destroy(ASTPreserveData* preserve) { free(preserve); } | ||||
|   | ||||
							
								
								
									
										199
									
								
								src/ast_print.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								src/ast_print.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| #include "include/ast_print.h" | ||||
| #include "include/ast.h" | ||||
| #include "include/builtin.h" | ||||
| #include "include/dstr.h" | ||||
| #include "include/util.h" | ||||
| #include <stdio.h> | ||||
|  | ||||
| static char* asttype_names[] = { | ||||
|     [AST_TYPE_CALL] = "CALL", | ||||
|     [AST_TYPE_LIT_NUM] = "LITERAL NUMBER", | ||||
|     [AST_TYPE_LIT_BOOL] = "LITERAL BOOLEAN", | ||||
|     [AST_TYPE_REF] = "REFERENCE", | ||||
|     [AST_TYPE_DEF] = "DEFINITION", | ||||
|     [AST_TYPE_BLOCK] = "BLOCK", | ||||
|     [AST_TYPE_EXC] = "EXCEPTION", | ||||
|     [AST_TYPE_ARG] = "DEFINITION ARGUMENT", | ||||
|     [AST_TYPE_LAMBDA] = "LAMBDA", | ||||
|     [AST_TYPE_BIF] = "BUILTIN FUNCTION", | ||||
|     [AST_TYPE_FORCE] = "FORCE", | ||||
|     [AST_TYPE_PRESERVE] = "PRESERVE" | ||||
| }; | ||||
|  | ||||
| void ast_print(AST* ast) { | ||||
|     if (!ast) return; | ||||
|     ast_print_i(ast, 0); | ||||
| } | ||||
|  | ||||
| void ast_print_i(AST* ast, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("AST", ast); | ||||
|     INDENT_FIELD("type", "%s", asttype_names[ast->type]); | ||||
|     INDENT_FIELD_EXT_NONL_START("data"); | ||||
|     switch (ast->type) { | ||||
|         case AST_TYPE_LIT_NUM: | ||||
|             printf("%s  %lf\n", INDENT_spacing->buf, *(ASTNumData*)ast->data); | ||||
|             break; | ||||
|         case AST_TYPE_LIT_BOOL: | ||||
|             printf( | ||||
|                 "%s  %s\n", INDENT_spacing->buf, | ||||
|                 *(ASTBoolData*)ast->data ? "true" : "false" | ||||
|             ); | ||||
|             break; | ||||
|         case AST_TYPE_LIT_KIND: | ||||
|             printf( | ||||
|                 "%s  %s\n", INDENT_spacing->buf, | ||||
|                 ast_lit_kind_names[*(ASTKindData*)ast->data] | ||||
|             ); | ||||
|             break; | ||||
|         case AST_TYPE_CALL:     ast_call_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_EXC:      ast_exc_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_REF:      ast_ref_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_DEF:      ast_def_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_BLOCK:    ast_block_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_ARG:      ast_arg_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_LAMBDA:   ast_lambda_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_BIF:      ast_bif_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_FORCE:    ast_force_print(ast->data, i + 2); break; | ||||
|         case AST_TYPE_PRESERVE: ast_preserve_print(ast->data, i + 2); break; | ||||
|         default:                exit(1); | ||||
|     } | ||||
|     INDENT_FIELD_NONL_END; | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_num_print(ASTNumData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_FIELD("data", "%lf", *data); | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_bool_print(ASTBoolData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_FIELD("data", "%s", *data ? "true" : "false"); | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_exc_print(ASTExcData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("ASTExcData", data); | ||||
|     INDENT_FIELD("msg", "\"%s\"", data->msg); | ||||
|     if (data->trace == NULL) { | ||||
|         INDENT_FIELD("trace", "%p", NULL) | ||||
|     } else { | ||||
|         INDENT_FIELD_EXT_NONL_START("trace"); | ||||
|         ast_print_i(data->trace, i + 1); | ||||
|         INDENT_FIELD_NONL_END; | ||||
|     } | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_call_print(ASTCallData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("ASTCallData", data); | ||||
|     INDENT_FIELD("argc", "%ld", data->argc); | ||||
|     INDENT_FIELD_LIST("argv", data->argv, data->argc, ast_print_i); | ||||
|     INDENT_FIELD_EXT_NONL_START("exp"); | ||||
|     ast_print_i(data->exp, i + 2); | ||||
|     INDENT_FIELD_NONL_END; | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
| void ast_def_print(ASTDefData* def, int depth) { | ||||
|     INDENT_BEGIN(depth); | ||||
|  | ||||
|     INDENT_TITLE("ASTDefData", def); | ||||
|     INDENT_FIELD("name", "%s", def->name); | ||||
|     if (def->kind) { | ||||
|         INDENT_FIELD_EXT_NONL_START("kind"); | ||||
|         ast_print_i(def->kind, depth + 2); | ||||
|         INDENT_FIELD_NONL_END; | ||||
|     } else INDENT_FIELD("kind", "%s", "Any"); | ||||
|  | ||||
|     INDENT_FIELD_EXT_NONL_START("exp"); | ||||
|     ast_print_i(def->exp, depth + 2); // 2 because already indented. | ||||
|     INDENT_FIELD_NONL_END; | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_ref_print(ASTRefData* data, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("ASTRefData", data); | ||||
|     INDENT_FIELD("to", "%s", data->to); | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_block_print(ASTBlockData* data, int depth) { | ||||
|     INDENT_BEGIN(depth); | ||||
|  | ||||
|     INDENT_TITLE("ASTBlockData", data); | ||||
|     INDENT_FIELD("ln", "%ld", data->ln); | ||||
|     INDENT_FIELD_LIST("inside", data->inside, data->ln, ast_print_i); | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
| void ast_arg_print(ASTArgData* arg, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|     INDENT_TITLE("ASTArgData", arg); | ||||
|     INDENT_FIELD("name", "%s", arg->name); | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_lambda_print(ASTLambdaData* lambda, int i) { | ||||
|     INDENT_BEGIN(i) | ||||
|     INDENT_TITLE("ASTLambdaData", lambda); | ||||
|     INDENT_FIELD("parc", "%ld", lambda->parc); | ||||
|     INDENT_FIELD_LIST("parv", lambda->parv, lambda->parc, ast_print_i); | ||||
|     INDENT_FIELD_EXT_NONL_START("body"); | ||||
|     ast_print_i(lambda->body, i + 2); | ||||
|     INDENT_FIELD_NONL_END; | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_bif_print(ASTBIFData* bif, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|     INDENT_TITLE("ASTBIFData", bif); | ||||
|  | ||||
|     char* name = "unknown"; | ||||
|  | ||||
|     for (int i = 0; i < BUILTIN_FNS_LN; i++) | ||||
|         if ((void*)BUILTIN_FNS[i].fn == bif) { | ||||
|             name = BUILTIN_FNS[i].name; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|     INDENT_FIELD("name", "%s", name); | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_force_print(ASTForceData* force, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("ASTForceData", force); | ||||
|     INDENT_FIELD_EXT_NONL_START("body"); | ||||
|     ast_print_i(force->body, i + 2); | ||||
|     INDENT_FIELD_NONL_END; | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
|  | ||||
| void ast_preserve_print(ASTPreserveData* preserve, int i) { | ||||
|     INDENT_BEGIN(i); | ||||
|  | ||||
|     INDENT_TITLE("ASTPreserveData", preserve); | ||||
|     INDENT_FIELD_EXT_NONL_START("body"); | ||||
|     ast_print_i(preserve->body, i + 2); | ||||
|     INDENT_FIELD_NONL_END; | ||||
|  | ||||
|     INDENT_END; | ||||
| } | ||||
							
								
								
									
										136
									
								
								src/builtin.c
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								src/builtin.c
									
									
									
									
									
								
							| @@ -1,21 +1,21 @@ | ||||
| #include "include/builtin.h" | ||||
| #include "include/ast.h" | ||||
| #include "include/exec.h" | ||||
| #include "include/util.h" | ||||
| #include <stdarg.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| AST* builtin_sum(size_t argc, AST** argv) { | ||||
| #include "include/ast.h" | ||||
| #include "include/builtin.h" | ||||
| #include "include/exec.h" | ||||
|  | ||||
| AST* builtin_sum(size_t argc, AST** argv, Scope* parent) { | ||||
|     ASTNumData total = 0; | ||||
|  | ||||
|     for (int i = 0; i < argc; i++) { | ||||
|         AST* arg = exec_exp(argv[i]); | ||||
|         AST* arg = exec_exp(argv[i], parent); | ||||
|         if (arg->type == AST_TYPE_EXC) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("`sum` encountered an exception.", arg) | ||||
|             ); | ||||
|         if (arg->type != AST_TYPE_NUM) | ||||
|         if (arg->type != AST_TYPE_LIT_NUM) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("Sum can't sum some non-num arguments.", NULL) | ||||
| @@ -24,18 +24,19 @@ AST* builtin_sum(size_t argc, AST** argv) { | ||||
|         total += *(ASTNumData*)arg->data; | ||||
|     } | ||||
|  | ||||
|     return ast_init(AST_TYPE_NUM, ast_num_data_init(total)); | ||||
|     return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(total)); | ||||
| } | ||||
|  | ||||
| AST* builtin_sub(size_t argc, AST** argv) { | ||||
|     log_dbg("Got here"); | ||||
|     AST* first = exec_exp(*argv); | ||||
| AST* builtin_sub(size_t argc, AST** argv, Scope* parent) { | ||||
|     if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0)); | ||||
|  | ||||
|     AST* first = exec_exp(*argv, parent); | ||||
|     if (first->type == AST_TYPE_EXC) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, | ||||
|             ast_exc_data_init("`sub` encountered an exception.", first) | ||||
|         ); | ||||
|     if (first->type != AST_TYPE_NUM) | ||||
|     if (first->type != AST_TYPE_LIT_NUM) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, | ||||
|             ast_exc_data_init("Can't subtract non-num arguments.", NULL) | ||||
| @@ -44,13 +45,13 @@ AST* builtin_sub(size_t argc, AST** argv) { | ||||
|     ASTNumData total = *(ASTNumData*)first->data; | ||||
|  | ||||
|     for (int i = 1; i < argc; i++) { | ||||
|         AST* arg = exec_exp(argv[i]); | ||||
|         AST* arg = exec_exp(argv[i], parent); | ||||
|         if (arg->type == AST_TYPE_EXC) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("`sub` encountered an exception.", arg) | ||||
|             ); | ||||
|         if (arg->type != AST_TYPE_NUM) | ||||
|         if (arg->type != AST_TYPE_LIT_NUM) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("Can't subtract non-num arguments.", NULL) | ||||
| @@ -59,18 +60,19 @@ AST* builtin_sub(size_t argc, AST** argv) { | ||||
|         total -= *(ASTNumData*)arg->data; | ||||
|     } | ||||
|  | ||||
|     return ast_init(AST_TYPE_NUM, ast_num_data_init(total)); | ||||
|     return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(total)); | ||||
| } | ||||
|  | ||||
| AST* builtin_mul(size_t argc, AST** argv) { | ||||
|     log_dbg("Got here"); | ||||
|     AST* first = exec_exp(*argv); | ||||
| AST* builtin_mul(size_t argc, AST** argv, Scope* parent) { | ||||
|     if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0)); | ||||
|  | ||||
|     AST* first = exec_exp(*argv, parent); | ||||
|     if (first->type == AST_TYPE_EXC) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, | ||||
|             ast_exc_data_init("`mul` encountered an expection.", first) | ||||
|         ); | ||||
|     if (first->type != AST_TYPE_NUM) | ||||
|     if (first->type != AST_TYPE_LIT_NUM) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, | ||||
|             ast_exc_data_init("Can't multiply non-num arguments.", NULL) | ||||
| @@ -79,13 +81,13 @@ AST* builtin_mul(size_t argc, AST** argv) { | ||||
|     ASTNumData total = *(ASTNumData*)first->data; | ||||
|  | ||||
|     for (int i = 1; i < argc; i++) { | ||||
|         AST* arg = exec_exp(argv[i]); | ||||
|         AST* arg = exec_exp(argv[i], parent); | ||||
|         if (arg->type == AST_TYPE_EXC) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("`mul` encountered an execption.", arg) | ||||
|             ); | ||||
|         if (arg->type != AST_TYPE_NUM) | ||||
|         if (arg->type != AST_TYPE_LIT_NUM) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("Can't multiply non-num arguments.", NULL) | ||||
| @@ -94,18 +96,19 @@ AST* builtin_mul(size_t argc, AST** argv) { | ||||
|         total *= *(ASTNumData*)arg->data; | ||||
|     } | ||||
|  | ||||
|     return ast_init(AST_TYPE_NUM, ast_num_data_init(total)); | ||||
|     return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(total)); | ||||
| } | ||||
|  | ||||
| AST* builtin_div(size_t argc, AST** argv) { | ||||
|     log_dbg("Got here"); | ||||
|     AST* first = exec_exp(*argv); | ||||
| AST* builtin_div(size_t argc, AST** argv, Scope* parent) { | ||||
|     if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0)); | ||||
|  | ||||
|     AST* first = exec_exp(*argv, parent); | ||||
|     if (first->type == AST_TYPE_EXC) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, | ||||
|             ast_exc_data_init("`div` encountered an exception.", first) | ||||
|         ); | ||||
|     if (first->type != AST_TYPE_NUM) | ||||
|     if (first->type != AST_TYPE_LIT_NUM) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, | ||||
|             ast_exc_data_init("Can't divide non-num arguments.", NULL) | ||||
| @@ -114,13 +117,13 @@ AST* builtin_div(size_t argc, AST** argv) { | ||||
|     ASTNumData total = *(ASTNumData*)first->data; | ||||
|  | ||||
|     for (int i = 1; i < argc; i++) { | ||||
|         AST* arg = exec_exp(argv[i]); | ||||
|         AST* arg = exec_exp(argv[i], parent); | ||||
|         if (arg->type == AST_TYPE_EXC) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("`div` encountered an exception.", arg) | ||||
|             ); | ||||
|         if (arg->type != AST_TYPE_NUM) | ||||
|         if (arg->type != AST_TYPE_LIT_NUM) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("Can't divide non-num arguments.", NULL) | ||||
| @@ -129,5 +132,80 @@ AST* builtin_div(size_t argc, AST** argv) { | ||||
|         total /= *(ASTNumData*)arg->data; | ||||
|     } | ||||
|  | ||||
|     return ast_init(AST_TYPE_NUM, ast_num_data_init(total)); | ||||
|     return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(total)); | ||||
| } | ||||
|  | ||||
| AST* builtin_die(size_t argc, AST** argv, Scope* parent) { | ||||
|     return ast_init(AST_TYPE_EXC, ast_exc_data_init("8", NULL)); | ||||
| } | ||||
|  | ||||
| AST* builtin_if(size_t argc, AST** argv, Scope* parent) { | ||||
|     if (argc != 3) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, | ||||
|             ast_exc_data_init("If invoked with too few args.", NULL) | ||||
|         ); | ||||
|  | ||||
|     AST* pred = exec_exp(argv[0], parent); | ||||
|     AST* body = argv[1]; | ||||
|     AST* alt = argv[2]; | ||||
|  | ||||
|     if (pred->type != AST_TYPE_LIT_BOOL) { | ||||
|         if (pred->type == AST_TYPE_EXC) { | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, ast_exc_data_init("if touched an error", pred) | ||||
|             ); | ||||
|         } else { | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, | ||||
|                 ast_exc_data_init("if works on booleans idiot", NULL) | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (*(ASTBoolData*)pred->data) return exec_exp(body, parent); | ||||
|     else return exec_exp(alt, parent); | ||||
| } | ||||
|  | ||||
| AST* builtin_eq(size_t argc, AST** argv, Scope* parent) { | ||||
|     if (argc < 1) return ast_init(AST_TYPE_EXC, ast_exc_data_init("bad", NULL)); | ||||
|     else if (argc == 1) | ||||
|         return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(1)); | ||||
|  | ||||
|     AST* first = exec_exp(argv[0], parent); | ||||
|     ASTType type = first->type; | ||||
|  | ||||
|     AST* second = exec_exp(argv[1], parent); | ||||
|     if (first->type == AST_TYPE_EXC) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, ast_exc_data_init("first was bad", first) | ||||
|         ); | ||||
|     if (second->type == AST_TYPE_EXC) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, ast_exc_data_init("second was bad", second) | ||||
|         ); | ||||
|  | ||||
|     if (second->type != type) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, | ||||
|             ast_exc_data_init("apples and oranges or something idk", NULL) | ||||
|         ); | ||||
|  | ||||
|     // Later when I put together an anctual type system I'll have this | ||||
|     // delegated to each type. For now this works. | ||||
|  | ||||
|     switch (type) { | ||||
|         case AST_TYPE_LIT_NUM: | ||||
|             if (*(ASTNumData*)first->data == *(ASTNumData*)second->data) | ||||
|                 return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(1)); | ||||
|             else return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(0)); | ||||
|         case AST_TYPE_LIT_BOOL: | ||||
|             if (*(ASTNumData*)first->data == *(ASTNumData*)second->data) | ||||
|                 return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(1)); | ||||
|             else return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(0)); | ||||
|         default: | ||||
|             return ast_init( | ||||
|                 AST_TYPE_LIT_BOOL, ast_bool_data_init(0) | ||||
|             ); // Can't equate nonprimatives. I think. Maybe. | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| #include <stddef.h> | ||||
| #include <stdio.h> // IWYU pragma: keep. Req by util macros. | ||||
|  | ||||
| #include "include/dlist.h" | ||||
| #include "include/util.h" | ||||
|  | ||||
| #include <stddef.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| DList* dlist_init(void) { | ||||
|     DList* dlist = malloc(sizeof(DList)); | ||||
|  | ||||
|   | ||||
							
								
								
									
										215
									
								
								src/exec.c
									
									
									
									
									
								
							
							
						
						
									
										215
									
								
								src/exec.c
									
									
									
									
									
								
							| @@ -6,140 +6,187 @@ | ||||
| #include "include/builtin.h" | ||||
| #include "include/exec.h" | ||||
| #include "include/htab.h" | ||||
| #include "include/stack.h" | ||||
| #include "include/scope.h" | ||||
| #include "include/util.h" | ||||
|  | ||||
| extern AST* root; | ||||
|  | ||||
| AST* exec_find(char* name); | ||||
|  | ||||
| AST* exec_start(AST* ast) { | ||||
|     log_dbg("Started execution."); | ||||
|     Stack* scope = stack_init(); | ||||
|  | ||||
|     HTab* global = htab_init(); | ||||
|     if (!ast) return ast; | ||||
|  | ||||
|     Scope* global = scope_init(NULL); | ||||
|     global->uses = 1; | ||||
|  | ||||
|     for (int i = 0; i < BUILTIN_FNS_LN; i++) | ||||
|         htab_ins( | ||||
|             global, BUILTIN_FNS[i].name, | ||||
|             global->here, BUILTIN_FNS[i].name, | ||||
|             ast_init(AST_TYPE_BIF, ast_bif_data_init(BUILTIN_FNS[i].fn)) | ||||
|         ); | ||||
|  | ||||
|     // Push global namespace to `scope`. | ||||
|     stack_push(scope, global); | ||||
|     AST* defnum = | ||||
|         ast_init(AST_TYPE_LIT_KIND, ast_kind_data_init(AST_LIT_KIND_NUM)); | ||||
|     htab_ins(global->here, "Num", defnum); | ||||
|  | ||||
|     return exec_exp(ast); | ||||
|     AST* defbool = | ||||
|         ast_init(AST_TYPE_LIT_KIND, ast_kind_data_init(AST_LIT_KIND_BOOL)); | ||||
|     htab_ins(global->here, "Bool", defbool); | ||||
|  | ||||
|     AST* defkind = | ||||
|         ast_init(AST_TYPE_LIT_KIND, ast_kind_data_init(AST_LIT_KIND_KIND)); | ||||
|     htab_ins(global->here, "Type", defkind); | ||||
|  | ||||
|     log_dbg("Completed startup sequence."); | ||||
|  | ||||
|     AST* res = exec_exp(ast, global); | ||||
|  | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| AST* exec_exp(AST* ast) { | ||||
| AST* exec_exp(AST* ast, Scope* parent) { | ||||
|     switch (ast->type) { | ||||
|         case AST_TYPE_BLOCK: return exec_block(ast); | ||||
|         case AST_TYPE_CALL:  return exec_call(ast); | ||||
|         case AST_TYPE_NUM:   return ast; | ||||
|         case AST_TYPE_VREF:  return exec_vref(ast); | ||||
|         case AST_TYPE_VDEF:  return exec_vdef(ast); | ||||
|         case AST_TYPE_FDEF:  return exec_fdef(ast); | ||||
|         default:             printf("what\n"); exit(1); | ||||
|         case AST_TYPE_BLOCK: return exec_block(ast, parent); | ||||
|         case AST_TYPE_CALL:  return exec_call(ast, parent); | ||||
|         case AST_TYPE_LIT_NUM: | ||||
|             return ast_init( | ||||
|                 AST_TYPE_LIT_NUM, ast_num_data_init(*(ASTNumData*)ast->data) | ||||
|             ); | ||||
|         case AST_TYPE_LIT_BOOL: | ||||
|             return ast_init( | ||||
|                 AST_TYPE_LIT_BOOL, ast_bool_data_init(*(ASTBoolData*)ast->data) | ||||
|             ); | ||||
|         case AST_TYPE_REF:      return exec_ref(ast, parent); | ||||
|         case AST_TYPE_DEF:      return exec_def(ast, parent); | ||||
|         case AST_TYPE_BIF: | ||||
|         case AST_TYPE_LAMBDA:   return ast; | ||||
|         case AST_TYPE_FORCE:    return exec_force(ast, parent); | ||||
|         case AST_TYPE_PRESERVE: return exec_preserve(ast, parent); | ||||
|         default:                printf("what\n"); exit(1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| AST* exec_block(AST* ast) { | ||||
| AST* exec_block(AST* ast, Scope* parent) { | ||||
|     ASTBlockData* block = (ASTBlockData*)ast->data; | ||||
|  | ||||
|     HTab* local = htab_init(); | ||||
|     //stack_push(scope, local); | ||||
|     exec_new_scope(ast, parent); | ||||
|  | ||||
|     // Loop through all but last ast. | ||||
|     for (int i = 0; i < block->ln - 1; i++) exec_exp(block->inside[i]); | ||||
|     AST* last = exec_exp(block->inside[block->ln - 1]); | ||||
|  | ||||
|     //stack_pop(scope); | ||||
|     htab_destroy(local); | ||||
|     for (int i = 0; i < block->ln - 1; i++) | ||||
|         exec_exp(block->inside[i], ast->scope); | ||||
|     AST* last = exec_exp(block->inside[block->ln - 1], ast->scope); | ||||
|  | ||||
|     return last; | ||||
| } | ||||
|  | ||||
| AST* exec_call(AST* ast) { | ||||
|     log_dbg("Started call execution."); | ||||
|     ASTCallData* data = (ASTCallData*)ast->data; | ||||
|     size_t argc = data->argc; | ||||
|     AST** argv = data->argv; | ||||
|     char* fname = data->to; | ||||
| AST* exec_call(AST* ast, Scope* parent) { | ||||
|     ASTCallData* calldata = (ASTCallData*)ast->data; | ||||
|  | ||||
|     AST* fdef = exec_find(fname); | ||||
|     AST* exp = exec_exp(calldata->exp, parent); | ||||
|  | ||||
|     if (fdef == NULL) | ||||
|         return ast_init( | ||||
|             AST_TYPE_EXC, ast_exc_data_init("No such function found.", NULL) | ||||
|         ); | ||||
|  | ||||
|     switch (fdef->type) { | ||||
|     switch (exp->type) { | ||||
|         case AST_TYPE_BIF: | ||||
|             ASTBIFData bifdata = fdef->data; | ||||
|             return bifdata(argc, argv); | ||||
|         case AST_TYPE_FDEF: return exec_cf(fdef, argc, argv); | ||||
|             return ((ASTBIFData)exp->data)( | ||||
|                 calldata->argc, calldata->argv, parent | ||||
|             ); | ||||
|         case AST_TYPE_LAMBDA: | ||||
|             return exec_lambda(calldata->argc, calldata->argv, exp, parent); | ||||
|         default: | ||||
|             return ast_init(AST_TYPE_EXC, ast_exc_data_init("Good job!", NULL)); | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, ast_exc_data_init("Uncallable.", NULL) | ||||
|             ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| AST* exec_cf(AST* ast, size_t argc, AST** argv) { | ||||
|     ASTFDefData* fdef = (ASTFDefData*)ast->data; | ||||
|     for (int i = 0; i < argc; i++) { | ||||
|         char* key = ((ASTArgData*)fdef->argv[i]->data)->name; | ||||
|         AST* val = argv[i]; | ||||
|         //htab_ins(scope->buf[scope->ln - 1], key, val); | ||||
|     } | ||||
| AST* exec_def(AST* ast, Scope* parent) { | ||||
|     // Use parent's scope. | ||||
|     exec_inherit_scope(ast, parent); | ||||
|  | ||||
|     return exec_exp(fdef->body); | ||||
| } | ||||
|  | ||||
| AST* exec_find(char* name) { | ||||
|     AST* val = NULL; | ||||
|  | ||||
|     /* | ||||
|     for (int i = scope->ln - 1; i >= 0; i--) { | ||||
|         HTab* lvl = scope->buf[i]; | ||||
|         val = htab_get(lvl, name); | ||||
|         if (val != NULL) return val; | ||||
|         }*/ | ||||
|  | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| AST* exec_vdef(AST* ast) { | ||||
|     ASTVDefData* data = (ASTVDefData*)ast->data; | ||||
|     AST* val = data->val; | ||||
|     ASTDefData* data = (ASTDefData*)ast->data; | ||||
|     AST* val = data->exp; | ||||
|     char* key = data->name; | ||||
|     //htab_ins(scope->buf[scope->ln - 1], key, val); | ||||
|     return exec_exp(val); | ||||
|  | ||||
|     if (data->kind) { | ||||
|  | ||||
|         ASTKindData kind = *(ASTKindData*)exec_exp(data->kind, parent)->data == | ||||
|                            AST_LIT_KIND_NUM; | ||||
|  | ||||
|         if (kind == AST_LIT_KIND_NUM && data->exp->type != AST_TYPE_LIT_NUM) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, ast_exc_data_init("Expected Num.", NULL) | ||||
|             ); | ||||
|  | ||||
|         if (kind == AST_LIT_KIND_BOOL && data->exp->type != AST_TYPE_LIT_BOOL) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, ast_exc_data_init("Expected Bool.", NULL) | ||||
|             ); | ||||
|  | ||||
|         if (kind == AST_LIT_KIND_KIND && data->exp->type != AST_TYPE_LIT_KIND) | ||||
|             return ast_init( | ||||
|                 AST_TYPE_EXC, ast_exc_data_init("Expected Type.", NULL) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     scope_add(parent, key, val); // Add variable definition to parent scope. | ||||
|     return exec_exp(val, parent); | ||||
| } | ||||
|  | ||||
| AST* exec_vref(AST* ast) { | ||||
| AST* exec_ref(AST* ast, Scope* parent) { | ||||
|     // Use parent's scope. | ||||
|     exec_inherit_scope(ast, parent); | ||||
|     log_dbg("attempting to reference var"); | ||||
|     ASTVrefData* vref = (ASTVrefData*)ast->data; | ||||
|     ASTRefData* ref = (ASTRefData*)ast->data; | ||||
|  | ||||
|     AST* found = exec_find(vref->to); | ||||
|     AST* found = ast_find(parent, ref->to); | ||||
|  | ||||
|     if (found == NULL) { | ||||
|         // TODO: Better memory management here. | ||||
|         static char msg[256]; | ||||
|         snprintf( | ||||
|             msg, sizeof(msg), "Could not find value in scope for `%s`.", | ||||
|             vref->to | ||||
|             msg, sizeof(msg), "Could not find value in scope for `%s`.", ref->to | ||||
|         ); | ||||
|         return ast_init(AST_TYPE_EXC, ast_exc_data_init(msg, NULL)); | ||||
|     } | ||||
|  | ||||
|     return exec_exp(found); | ||||
|     // return exec_exp(found, ast->scope); | ||||
|     return found; | ||||
| } | ||||
|  | ||||
| AST* exec_fdef(AST* ast) { | ||||
|     ASTFDefData* fdef = (ASTFDefData*)ast->data; | ||||
|     AST* val = fdef->body; | ||||
|     char* key = fdef->name; | ||||
|     //htab_ins(scope->buf[scope->ln - 1], key, val); | ||||
|     return val; // Function definitions return function body. | ||||
| AST* exec_lambda(size_t argc, AST** argv, AST* exp, Scope* parent) { | ||||
|     Scope* callscope = scope_init(parent); | ||||
|     ASTLambdaData* lambda = (ASTLambdaData*)exp->data; | ||||
|     for (int i = 0; i < argc; i++) { | ||||
|         char* key = ((ASTArgData*)lambda->parv[i]->data)->name; | ||||
|         AST* val = exec_exp(argv[i], parent); | ||||
|         scope_add(callscope, key, val); | ||||
|     } | ||||
|  | ||||
|     return exec_exp(lambda->body, callscope); | ||||
| } | ||||
|  | ||||
| AST* exec_force(AST* ast, Scope* parent) { | ||||
|     AST* body = ((ASTForceData*)ast->data)->body; | ||||
|  | ||||
|     if (body->type == AST_TYPE_REF) { | ||||
|         return exec_exp(exec_ref(body, parent), parent); | ||||
|     } else return exec_exp(body, parent); | ||||
| } | ||||
|  | ||||
| AST* exec_preserve(AST* ast, Scope* parent) { | ||||
|     return ((ASTPreserveData*)ast->data)->body; | ||||
| } | ||||
|  | ||||
| void exec_print(double n) { printf("= %lf\n", n); } | ||||
|  | ||||
| inline void exec_new_scope(AST* ast, Scope* inherit) { | ||||
|     Scope* scope = scope_init(inherit); | ||||
|     ast->scope = scope; | ||||
|  | ||||
|     // Update linked status. | ||||
|     scope->uses++; | ||||
| } | ||||
|  | ||||
| inline void exec_inherit_scope(AST* ast, Scope* inherit) { | ||||
|     ast->scope = inherit; | ||||
|  | ||||
|     // Update uses. | ||||
|     inherit->uses++; | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,9 @@ | ||||
| #include "include/fnv1a.h" | ||||
| #include "include/util.h" | ||||
| #include "include/util.h" | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| uint64_t fnv1a_hash(char* key, size_t ln) { | ||||
|     uint64_t hash = FNV1A_BASIS_64; | ||||
| @@ -10,5 +13,7 @@ uint64_t fnv1a_hash(char* key, size_t ln) { | ||||
|         hash *= FNV1A_PRIME_64; | ||||
|     } | ||||
|  | ||||
|     log_dbgf("Hash of %s was %lu", key, hash); | ||||
|  | ||||
|     return hash; | ||||
| } | ||||
|   | ||||
							
								
								
									
										54
									
								
								src/gc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/gc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #include "include/gc.h" | ||||
| #include "include/ast.h" | ||||
| #include "include/scope.h" | ||||
| #include "include/util.h" | ||||
| #include <assert.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include <stddef.h> | ||||
|  | ||||
| GC* gclist = NULL; | ||||
|  | ||||
| void gc_destroy(GC* gc) { free(gc); } | ||||
|  | ||||
| void* gc_alloc(size_t sz, GCType type) { | ||||
|     assert(type <= GC_TYPE_MAX); | ||||
|  | ||||
|     void* mem = malloc(sz); | ||||
|     GC* gc = malloc(sizeof(GC)); | ||||
|  | ||||
|     gc->p = mem; | ||||
|     gc->type = type; | ||||
|     gc->marked = false; | ||||
|     gc->nxt = gclist; | ||||
|     gclist = gc; | ||||
|  | ||||
|     if (type == GC_TYPE_AST) { | ||||
|         log_dbgf("Alloc'd AST for GC: %p", mem); | ||||
|     } else if (type == GC_TYPE_SCOPE) { | ||||
|         log_dbgf("Alloc'd scope for GC: %p", mem); | ||||
|     } | ||||
|  | ||||
|     return mem; | ||||
| } | ||||
|  | ||||
| void gc_hack_free() { | ||||
|     while (gclist) { | ||||
|         GC* gc = gclist; | ||||
|         gclist = gclist->nxt; | ||||
|         switch (gc->type) { | ||||
|             case GC_TYPE_AST: | ||||
|                 if (((AST*)gc->p)->type > AST_TYPE_MAX) { | ||||
|                     log_dbgf( | ||||
|                         "Attempted to free invalid AST (%i > %i) to GC: gc:%p " | ||||
|                         "ast:%p", | ||||
|                         ((AST*)gc->p)->type, AST_TYPE_MAX, gc, gc->p | ||||
|                     ); | ||||
|                 } | ||||
|                 ast_destroy(gc->p); | ||||
|                 break; | ||||
|             case GC_TYPE_SCOPE: scope_destroy_psv(gc->p); break; | ||||
|         } | ||||
|         gc_destroy(gc); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										298
									
								
								src/grammar.y
									
									
									
									
									
								
							
							
						
						
									
										298
									
								
								src/grammar.y
									
									
									
									
									
								
							| @@ -4,6 +4,7 @@ | ||||
|     #include "../../src/include/ast.h" | ||||
|     #include "../../src/include/lexer.h" | ||||
|     #include "../../src/include/dlist.h" | ||||
|     #include "../../src/include/builtin.h" | ||||
|  | ||||
|     int yylex(void); | ||||
|     void yyerror(char const*); | ||||
| @@ -14,6 +15,7 @@ | ||||
| %code requires { | ||||
|     #include "../../src/include/ast.h" | ||||
|     #include "../../src/include/dlist.h" | ||||
|     #include "../../src/include/builtin.h" | ||||
| } | ||||
|  | ||||
| %union { | ||||
| @@ -26,6 +28,12 @@ | ||||
|  | ||||
| %define parse.error verbose | ||||
|  | ||||
| %token BOOLT // Boolean true (TRUE or T). | ||||
| %token BOOLF // Boolean false (FALSE or F). | ||||
|  | ||||
| %token IF // if or ?. | ||||
| %token ELSE // else or :. | ||||
|  | ||||
| %token BLOCKS // Block start {. | ||||
| %token BLOCKE // Block end }. | ||||
|  | ||||
| @@ -34,6 +42,10 @@ | ||||
| %token SEP // Seperator ,. | ||||
|  | ||||
| %token EQ // Equals =. | ||||
| %token DEQ // Double equals ==. | ||||
|  | ||||
| %token RARROW // Right arrow ->. | ||||
| %token LARROW // Left arrow <-. | ||||
|  | ||||
| %token EXPSEP // Expression seperator ;. | ||||
|  | ||||
| @@ -47,8 +59,19 @@ | ||||
|  | ||||
| %token NL // Newline. | ||||
|  | ||||
| %token COLON // Colon :. | ||||
| %token STOP // Stop sign $. | ||||
|  | ||||
| %token FORCE // Force operator !. | ||||
| %token PRESERVE // Preserve operator @. | ||||
|  | ||||
| %token BACKSLASH | ||||
|  | ||||
| %left ADD SUB | ||||
| %left MUL DIV | ||||
| %left RARROW | ||||
| %right LARROW | ||||
| %nonassoc STOP | ||||
| %precedence NEG | ||||
|  | ||||
| %type<ast> exp; | ||||
| @@ -63,6 +86,8 @@ | ||||
|  | ||||
| %% | ||||
|  | ||||
| maybe_stop: %empty | STOP; | ||||
|  | ||||
| inputstart: | ||||
|     exp { | ||||
|         DList* exps = dlist_init(); | ||||
| @@ -85,6 +110,7 @@ inputend: | ||||
|     %empty | ||||
|     | input { | ||||
|         root = ast_init(AST_TYPE_BLOCK, ast_block_data_init((AST**) $1->buf, $1->ln)); | ||||
|         dlist_destroypsv($1); | ||||
|     } | ||||
|     ; | ||||
|  | ||||
| @@ -120,83 +146,267 @@ block: | ||||
|     } | ||||
|     ; | ||||
|  | ||||
|  | ||||
| exp: | ||||
|     NUM { $$ = ast_init(AST_TYPE_NUM, ast_num_data_init($1)); } | ||||
|  | ||||
|     //| BLOCKS exp BLOCKE { $$ = $2; } | ||||
|  | ||||
|     | BLOCKS block BLOCKE { | ||||
|         $$ = ast_init(AST_TYPE_BLOCK, ast_block_data_init((AST**) $2->buf, $2->ln)); | ||||
|     } | ||||
|  | ||||
|     | SUB exp { | ||||
|         AST** argv = calloc(2, sizeof(AST*)); | ||||
|         argv[0] = ast_init(AST_TYPE_NUM, ast_num_data_init(-1)); | ||||
|         argv[1] = $2; | ||||
|         char* to = malloc(4); | ||||
|         strcpy(to, "mul"); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); | ||||
|     } | ||||
|  | ||||
|     | GROUPS exp GROUPE { $$ = $2; } | ||||
|  | ||||
|     // Variable definition. | ||||
|     | WORD EQ exp { | ||||
|         $$ = ast_init(AST_TYPE_VDEF, ast_vdef_data_init($1, $3)); | ||||
|     } | ||||
|     // Stop sign. | ||||
|     exp STOP { $$ = $1; } | ||||
|  | ||||
|     // Variable reference. | ||||
|     | WORD { | ||||
|         $$ = ast_init(AST_TYPE_VREF, ast_vref_data_init($1)); | ||||
|         $$ = ast_init(AST_TYPE_REF, ast_ref_data_init($1)); | ||||
|     } | ||||
|  | ||||
|     // Call (general form). | ||||
|     | exp GROUPS arg GROUPE { | ||||
|         size_t argc = $3->ln; | ||||
|         AST** argv = $3->buf; | ||||
|         argarr_destroypsv($3); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             argc, | ||||
|             argv, | ||||
|             $1 | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     // Call (general hacky form). | ||||
|     | exp GROUPS GROUPE { | ||||
|         size_t argc = 1; | ||||
|         AST** argv = NULL; | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             argc, | ||||
|             argv, | ||||
|             $1 | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     // Call (right arrow general form). | ||||
|     | GROUPS arg GROUPE RARROW exp { | ||||
|         size_t argc = $2->ln; | ||||
|         AST** argv = $2->buf; | ||||
|         argarr_destroypsv($2); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             argc, | ||||
|             argv, | ||||
|             $5 | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     | exp RARROW exp { | ||||
|         size_t argc = 1; | ||||
|         AST** argv = malloc(sizeof(AST*)); | ||||
|         argv[0] = $1; | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             argc, | ||||
|             argv, | ||||
|             $3 | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     | exp LARROW exp { | ||||
|         size_t argc = 1; | ||||
|         AST** argv = malloc(sizeof(AST*)); | ||||
|         argv[0] = $3; | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             argc, | ||||
|             argv, | ||||
|             $1 | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     // Call (convenient form). | ||||
|     | WORD GROUPS arg GROUPE { | ||||
|         size_t argc = $3->ln; | ||||
|         AST** argv = $3->buf; | ||||
|         argarr_destroypsv($3); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init($1, argc, argv)); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             argc, | ||||
|             argv, | ||||
|             ast_init(AST_TYPE_REF, ast_ref_data_init($1)) | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // Call (hacky convenient form). | ||||
|     | WORD GROUPS GROUPE { | ||||
|         size_t argc = 0; | ||||
|         AST** argv = NULL; | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             argc, | ||||
|             argv, | ||||
|             ast_init(AST_TYPE_REF, ast_ref_data_init($1)) | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     // Number. | ||||
|     | NUM { $$ = ast_init(AST_TYPE_LIT_NUM, ast_num_data_init($1)); } | ||||
|  | ||||
|     | BOOLT { $$ = ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(1)); } | ||||
|     | BOOLF { $$ = ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(0)); } | ||||
|  | ||||
|     | exp DEQ exp { | ||||
|         AST** argv = calloc(2, sizeof(AST*)); | ||||
|         argv[0] = $1; | ||||
|         argv[1] = $3; | ||||
|  | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             2, | ||||
|             argv, | ||||
|             ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_eq)) | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     | IF exp exp exp { | ||||
|         AST** argv = calloc(3, sizeof(AST*)); | ||||
|         argv[0] = $2; | ||||
|         argv[1] = $3; | ||||
|         argv[2] = $4; | ||||
|  | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             3, | ||||
|             argv, | ||||
|             ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_if)) | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     | IF exp exp ELSE exp { | ||||
|         AST** argv = calloc(3, sizeof(AST*)); | ||||
|         argv[0] = $2; | ||||
|         argv[1] = $3; | ||||
|         argv[2] = $5; | ||||
|  | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init( | ||||
|             3, | ||||
|             argv, | ||||
|             ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_if)) | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     // Function definitions. Convert to Def of Lambda. | ||||
|     | WORD GROUPS arg GROUPE exp maybe_stop { | ||||
|         size_t parc = $3->ln; | ||||
|         AST** parv = $3->buf; | ||||
|         argarr_destroypsv($3); | ||||
|         $$ = ast_init(AST_TYPE_DEF, ast_def_data_init( | ||||
|             $1, | ||||
|             NULL, | ||||
|             ast_init(AST_TYPE_LAMBDA, ast_lambda_data_init( | ||||
|                 parc, parv, $5 | ||||
|             )) | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     // Lambda definitions. | ||||
|     | BACKSLASH GROUPS arg GROUPE exp { | ||||
|         size_t parc = $3->ln; | ||||
|         AST** parv = $3->buf; | ||||
|         argarr_destroypsv($3); | ||||
|         $$ = ast_init(AST_TYPE_LAMBDA, ast_lambda_data_init(parc, parv, $5)); | ||||
|     } | ||||
|  | ||||
|     // Force operator. | ||||
|     | FORCE exp { | ||||
|         $$ = ast_init(AST_TYPE_FORCE, ast_force_data_init($2)); | ||||
|     } | ||||
|  | ||||
|     // Preserve operator. | ||||
|     | PRESERVE exp { | ||||
|         $$ = ast_init(AST_TYPE_PRESERVE, ast_preserve_data_init($2)); | ||||
|     } | ||||
|  | ||||
|     // Block. | ||||
|     | BLOCKS block BLOCKE { | ||||
|         AST** exps = (AST**) $2->buf; | ||||
|         dlist_destroypsv($2); | ||||
|         $$ = ast_init(AST_TYPE_BLOCK, ast_block_data_init((AST**) exps, $2->ln)); | ||||
|     } | ||||
|  | ||||
|     // Negative. | ||||
|     | SUB exp { | ||||
|         AST** argv = calloc(2, sizeof(AST*)); | ||||
|         argv[0] = ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(-1)); | ||||
|         argv[1] = $2; | ||||
|         $$ = ast_init(AST_TYPE_CALL, | ||||
|             ast_call_data_init( | ||||
|                 2, | ||||
|                 argv, | ||||
|                 ast_init(AST_TYPE_BIF, | ||||
|                     ast_bif_data_init(builtin_mul) | ||||
|                 ) | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     // Group. | ||||
|     | GROUPS exp GROUPE { $$ = $2; } | ||||
|  | ||||
|     // Definition with type annotation. | ||||
|     | WORD COLON exp EQ exp { | ||||
|         $$ = ast_init(AST_TYPE_DEF, ast_def_data_init($1, $3, $5)); | ||||
|     } | ||||
|  | ||||
|     // Definition with type annotation. | ||||
|     | WORD COLON WORD EQ exp { | ||||
|         $$ = ast_init(AST_TYPE_DEF, ast_def_data_init( | ||||
|             $1, | ||||
|             ast_init(AST_TYPE_REF, ast_ref_data_init($3)), | ||||
|             $5 | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     // Definition. | ||||
|     | WORD EQ exp { | ||||
|         $$ = ast_init(AST_TYPE_DEF, ast_def_data_init($1, NULL, $3)); | ||||
|     } | ||||
|  | ||||
|     | exp ADD exp { | ||||
|         AST** argv = calloc(2, sizeof(AST*)); | ||||
|         argv[0] = $1; | ||||
|         argv[1] = $3; | ||||
|         char* to = malloc(4); | ||||
|         strcpy(to, "sum"); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); | ||||
|         $$ = ast_init(AST_TYPE_CALL, | ||||
|             ast_call_data_init( | ||||
|                 2, | ||||
|                 argv, | ||||
|                 ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_sum)) | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     | exp SUB exp { | ||||
|         AST** argv = calloc(2, sizeof(AST*)); | ||||
|         argv[0] = $1; | ||||
|         argv[1] = $3; | ||||
|         char* to = malloc(4); | ||||
|         strcpy(to, "sub"); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); | ||||
|         $$ = ast_init(AST_TYPE_CALL, | ||||
|             ast_call_data_init( | ||||
|                 2, | ||||
|                 argv, | ||||
|                 ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_sub)) | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     | exp MUL exp { | ||||
|         AST** argv = calloc(2, sizeof(AST*)); | ||||
|         argv[0] = $1; | ||||
|         argv[1] = $3; | ||||
|         char* to = malloc(4); | ||||
|         strcpy(to, "mul"); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); | ||||
|         $$ = ast_init(AST_TYPE_CALL, | ||||
|             ast_call_data_init( | ||||
|                 2, | ||||
|                 argv, | ||||
|                 ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_mul)) | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     | exp DIV exp { | ||||
|         AST** argv = calloc(2, sizeof(AST*)); | ||||
|         argv[0] = $1; | ||||
|         argv[1] = $3; | ||||
|         char* to = malloc(4); | ||||
|         strcpy(to, "div"); | ||||
|         $$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); | ||||
|     } | ||||
|  | ||||
|     | WORD GROUPS arg GROUPE EQ exp { | ||||
|         size_t argc = $3->ln; | ||||
|         AST** argv = $3->buf; | ||||
|         argarr_destroypsv($3); | ||||
|         $$ = ast_init(AST_TYPE_FDEF, ast_fdef_data_init($1, argc, argv, $6)); | ||||
|         $$ = ast_init(AST_TYPE_CALL, | ||||
|             ast_call_data_init( | ||||
|                 2, | ||||
|                 argv, | ||||
|                 ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_div)) | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
| %% | ||||
|   | ||||
| @@ -9,6 +9,8 @@ | ||||
| HTab* htab_init() { | ||||
|     HTab* htab = calloc(1, sizeof(HTab)); | ||||
|  | ||||
|     log_dbgf("HTAB %p", htab); | ||||
|  | ||||
|     return htab; | ||||
| } | ||||
|  | ||||
| @@ -29,7 +31,6 @@ void* htab_get(HTab* htab, char* key) { | ||||
|  | ||||
| void htab_ins(HTab* htab, char* key, void* data) { | ||||
|     size_t i = geti(key); | ||||
|     // assert((*htab)[i] == NULL); | ||||
|     (*htab)[i] = data; | ||||
|     log_dbgf("Inserted something to hash table @ index %lu", i); | ||||
| } | ||||
|   | ||||
| @@ -1,50 +1,53 @@ | ||||
| #ifndef AST_H | ||||
| #define AST_H | ||||
|  | ||||
| #include "htab.h" | ||||
| #include "scope.h" | ||||
| #include <stdlib.h> | ||||
|  | ||||
| // The type of an `AST`. | ||||
| typedef enum { | ||||
|     // Primitive types. | ||||
|     AST_TYPE_NUM, // A number (float). | ||||
|     AST_TYPE_STR, // A string | ||||
|     AST_TYPE_INT, // An integer. | ||||
|     AST_TYPE_SYM, // A symbol. | ||||
|     AST_TYPE_EXC, // Exception. | ||||
|     // Primitive type literals. | ||||
|     AST_TYPE_LIT_NUM,  // A number (float) literal. | ||||
|     AST_TYPE_LIT_BOOL, // A boolean literal. | ||||
|     AST_TYPE_LIT_VEC,  // A vector literal. | ||||
|     AST_TYPE_LIT_KIND, // A kind literal. | ||||
|  | ||||
|     AST_TYPE_EXC_CON,  // Exception constructor `Exc`. | ||||
|     AST_TYPE_VEC_CON,  // Vectpr constructor `Vec()`. | ||||
|  | ||||
|     // Collection types: | ||||
|     AST_TYPE_VEC,  // A vector (fixed size, fixed type). | ||||
|     AST_TYPE_LIST, // A list (variable size, variable type). | ||||
|  | ||||
|     // Syntactic types: | ||||
|     AST_TYPE_FORCE, | ||||
|     AST_TYPE_PRESERVE, | ||||
|     AST_TYPE_BLOCK,  // A block of code (scope). | ||||
|     AST_TYPE_ARG,    // A definition argument. | ||||
|  | ||||
|     // Misc. types. | ||||
|     AST_TYPE_BIF,   // Built-in function. | ||||
|     AST_TYPE_CALL,  // A function call. | ||||
|     AST_TYPE_VDEF,  // A variable definition. | ||||
|     AST_TYPE_VREF,  // A variable reference. | ||||
|     AST_TYPE_BLOCK, // A block of code (scope). | ||||
|     AST_TYPE_FDEF,  // A function definition. | ||||
|     AST_TYPE_ARG,   // A definition argument. | ||||
|     AST_TYPE_MAX = AST_TYPE_FDEF, | ||||
|     AST_TYPE_BIF,    // Built-in function. | ||||
|     AST_TYPE_CALL,   // A function call. | ||||
|     AST_TYPE_DEF,   // A definition. | ||||
|     AST_TYPE_REF,   // A variable reference. | ||||
|     AST_TYPE_LAMBDA, // An anonymous function definition. | ||||
|     AST_TYPE_EXC,   // An exception. | ||||
|     AST_TYPE_MAX = AST_TYPE_EXC, | ||||
| } ASTType; | ||||
|  | ||||
| // An Abstract Syntax Tree. | ||||
| typedef struct { | ||||
|     ASTType type; // The type of the `AST`. | ||||
|     void* data;   // The data of the `AST`. | ||||
|     HTab* scope;  // The scope of the `AST`. | ||||
|     Scope* scope; // The scope of the `AST`. | ||||
| } AST; | ||||
|  | ||||
| // Create a new `AST`. | ||||
| AST* ast_init(ASTType type, void* data); | ||||
| // Create a new `AST` with a specified scope. | ||||
| AST* ast_init_scope(ASTType type, void* data, HTab* scope); | ||||
| // Destroy an `AST`, recursively. | ||||
| AST* ast_init_scope(ASTType type, void* data, Scope* scope); | ||||
| // Destroy an `AST`. | ||||
| void ast_destroy(AST* ast); | ||||
| // Print an `AST`, recursively. | ||||
| void ast_print(AST* ast); | ||||
| // Helper function to `ast_print()`, where `i` is indentation level. | ||||
| void ast_print_i(AST* ast, int i); | ||||
|  | ||||
| // A number. | ||||
| typedef double ASTNumData; | ||||
| @@ -53,67 +56,106 @@ typedef double ASTNumData; | ||||
| ASTNumData* ast_num_data_init(double val); | ||||
| // Destroy an `ASTNumData`. | ||||
| void ast_num_data_destroy(ASTNumData* num); | ||||
| // Print an `ASTNumData`. | ||||
| void ast_num_print(ASTNumData*, int i); | ||||
|  | ||||
| // A boolean. | ||||
| typedef int ASTBoolData; | ||||
|  | ||||
| // Create a new `ASTBoolData`. | ||||
| ASTBoolData* ast_bool_data_init(int val); | ||||
| // Destroy an `ASTBoolData`. | ||||
| void ast_bool_data_destroy(ASTBoolData* bol); | ||||
|  | ||||
| // A literal kind. | ||||
| typedef enum { | ||||
|     AST_LIT_KIND_BOOL, | ||||
|     AST_LIT_KIND_NUM, | ||||
|     AST_LIT_KIND_KIND, | ||||
|     AST_LIT_KIND_MAX = AST_LIT_KIND_KIND | ||||
| } ASTKindData; | ||||
|  | ||||
| extern const char* ast_lit_kind_names[AST_LIT_KIND_MAX + 2]; | ||||
|  | ||||
| // Create a new `ASTKindData`. | ||||
| ASTKindData* ast_kind_data_init(ASTKindData); | ||||
|  | ||||
| // Destroy an `ASTKindData`. | ||||
| void ast_kind_data_destroy(ASTKindData*); | ||||
|  | ||||
| // An exception. | ||||
| typedef struct ASTEXCDATA { | ||||
|     char* msg;  // The exception message. | ||||
|     AST* trace; // The previous exception. | ||||
|     const char* msg; // The exception message. | ||||
|     AST* trace;      // The previous exception. | ||||
| } ASTExcData; | ||||
| // Create a new `ASTExecData. | ||||
| ASTExcData* ast_exc_data_init(char* msg, AST* trace); | ||||
| // Create a new `ASTExecData. `msg` should be static. | ||||
| ASTExcData* ast_exc_data_init(const char* msg, AST* trace); | ||||
| // Destroy an `ASTExecData`. | ||||
| void ast_exc_data_destroy(ASTExcData* exc); | ||||
| // Print an `ASTExecData`. | ||||
| void ast_exc_print(ASTExcData*, int i); | ||||
|  | ||||
| // Argument list as anonymous struct. | ||||
| #define ARGS                                                                   \ | ||||
|     struct {                                                                   \ | ||||
|         size_t argc;                                                           \ | ||||
|         AST** argv;                                                            \ | ||||
|     } | ||||
|  | ||||
| // Parameter list as anonymous struct. | ||||
| #define PARS                                                                   \ | ||||
|     struct {                                                                   \ | ||||
|         size_t parc;                                                           \ | ||||
|         AST** parv;                                                            \ | ||||
|     } | ||||
|  | ||||
| // A built-in function. | ||||
| typedef AST* (*ASTBIFData)(size_t argc, AST** argv); | ||||
| typedef AST* (*ASTBIFData)(size_t argc, AST** argv, Scope* scope); | ||||
|  | ||||
| // Create a built-in function. | ||||
| ASTBIFData* ast_bif_data_init(AST* fn(size_t, AST**)); | ||||
| ASTBIFData* ast_bif_data_init(AST* fn(size_t, AST**, Scope*)); | ||||
| // Destroy an `ASTBIFData`. | ||||
| void ast_bif_data_destroy(ASTBIFData* bif); | ||||
|  | ||||
| // There is no `ASTBIFData` destroy function, as function pointers are immortal. | ||||
|  | ||||
| // A call (to a function). | ||||
| // A lambda. | ||||
| typedef struct { | ||||
|     char* to;    // What the call's to. | ||||
|     size_t argc; // Argument count. | ||||
|     AST** argv;  // Argument vector. | ||||
|     PARS;      // The parameters the lambda can accept. | ||||
|     AST* body; // The body expression to be executed. | ||||
| } ASTLambdaData; | ||||
|  | ||||
| // Creates a new `ASTLambdaData`. | ||||
| ASTLambdaData* ast_lambda_data_init(size_t parc, AST** parv, AST* body); | ||||
| // Destroy an `ASTLambdaData`. | ||||
| void ast_lambda_data_destroy(ASTLambdaData*); | ||||
|  | ||||
| // A call. | ||||
| typedef struct { | ||||
|     ARGS;     // The arguments the call is made with. | ||||
|     AST* exp; // The expression the call is to. | ||||
| } ASTCallData; | ||||
|  | ||||
| // Create a new `ASTCallData`. | ||||
| ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv); | ||||
| ASTCallData* ast_call_data_init(size_t argc, AST** argv, AST* exp); | ||||
| // Destroy an `ASTCallData`. | ||||
| void ast_call_data_destroy(ASTCallData* call); | ||||
| // Print an `ASTCallData`. | ||||
| void ast_call_print(ASTCallData*, int i); | ||||
|  | ||||
| // A variable definition's data. | ||||
| // A definition. Associates a name and kind with an expression. | ||||
| typedef struct { | ||||
|     char* name; | ||||
|     AST* val; | ||||
| } ASTVDefData; | ||||
|     AST* kind; // If NULL, assume `Any` kind. | ||||
|     AST* exp; | ||||
| } ASTDefData; | ||||
|  | ||||
| // Create a new `ASTVDefData`. | ||||
| ASTVDefData* ast_vdef_data_init(char* name, AST* val); | ||||
| // Destroys the `ASTVDefData`, `ASTVDefData->name`, and `ASTVDefData->val`. | ||||
| void ast_vdef_data_destroy(ASTVDefData* vdef); | ||||
| // Print an `ASTVDefData`. | ||||
| void ast_vdef_print(ASTVDefData*, int depth); | ||||
| // Create a new `ASTDefData`. | ||||
| ASTDefData* ast_def_data_init(char* name, AST* kind, AST* exp); | ||||
| // Destroy an `ASTDefData`. | ||||
| void ast_def_data_destroy(ASTDefData* vdef); | ||||
|  | ||||
| // A variable reference's data. | ||||
| // A reference. | ||||
| typedef struct { | ||||
|     char* to; // What the reference's to. | ||||
| } ASTVrefData; | ||||
| } ASTRefData; | ||||
|  | ||||
| // Create a new `ASTVRefData`. | ||||
| ASTVrefData* ast_vref_data_init(char* to); | ||||
| // Destroy an `ASTVRefData`. | ||||
| void ast_vref_data_destroy(ASTVrefData* call); | ||||
| // Print an `ASTVRefData`. | ||||
| void ast_vref_print(ASTVrefData*, int i); | ||||
| // Create a new `ASTRefData`. | ||||
| ASTRefData* ast_ref_data_init(char* to); | ||||
| // Destroy an `ASTRefData`. | ||||
| void ast_ref_data_destroy(ASTRefData* call); | ||||
|  | ||||
| // A code block. | ||||
| typedef struct { | ||||
| @@ -125,22 +167,6 @@ typedef struct { | ||||
| ASTBlockData* ast_block_data_init(AST** inside, size_t ln); | ||||
| // Destroy an `ASTBlockData`, recursively. | ||||
| void ast_block_data_destroy(ASTBlockData* block); | ||||
| // Print an `ASTBlockData`. | ||||
| void ast_block_print(ASTBlockData*, int i); | ||||
|  | ||||
| typedef struct { | ||||
|     char* name;  // Function name. | ||||
|     size_t argc; // Argument count. | ||||
|     AST** argv;  // Argument vector. | ||||
|     AST* body;   // Function body. | ||||
| } ASTFDefData; | ||||
|  | ||||
| // Create a new `ASTFDefData`. | ||||
| ASTFDefData* ast_fdef_data_init(char* name, size_t argc, AST** argv, AST* body); | ||||
| // Destroy an `ASTFDefData`. | ||||
| void ast_fdef_data_destroy(ASTFDefData* fdef); | ||||
| // Print an `ASTFDefData`. | ||||
| void ast_fdef_print(ASTFDefData* fdef, int i); | ||||
|  | ||||
| typedef struct { | ||||
|     char* name; // Argument name. | ||||
| @@ -150,7 +176,18 @@ typedef struct { | ||||
| ASTArgData* ast_arg_data_init(char* name); | ||||
| // Destroy an `ASTArgData`. | ||||
| void ast_arg_data_destroy(ASTArgData* arg); | ||||
| // Print an `ASTArgData`. | ||||
| void ast_arg_print(ASTArgData* arg, int i); | ||||
|  | ||||
| // Find the expression associated with a name in the nearest scope. | ||||
| AST* ast_find(Scope* scope, char* name); | ||||
|  | ||||
| // A force operator. | ||||
| typedef struct {AST* body;} ASTForceData; | ||||
| ASTForceData* ast_force_data_init(AST* body); | ||||
| void ast_force_data_destroy(ASTForceData* force); | ||||
|  | ||||
| // A preserve operator. | ||||
| typedef struct {AST* body;} ASTPreserveData; | ||||
| ASTPreserveData* ast_preserve_data_init(AST* body); | ||||
| void ast_preserve_data_destroy(ASTPreserveData* preserve); | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										49
									
								
								src/include/ast_print.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/include/ast_print.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| #ifndef AST_PRINT_H | ||||
| #define AST_PRINT_H | ||||
|  | ||||
| #include "ast.h" | ||||
|  | ||||
| // Print an `AST`, recursively. | ||||
| void ast_print(AST* ast); | ||||
| // Helper function to `ast_print()`, where `i` is indentation level. | ||||
| void ast_print_i(AST* ast, int i); | ||||
|  | ||||
| // Print an `ASTNumData`. | ||||
| void ast_num_print(ASTNumData*, int i); | ||||
|  | ||||
| // Print an `ASTBoolData`. | ||||
| void ast_bool_print(ASTBoolData*, int i); | ||||
|  | ||||
| // Print an `ASTKindData`. | ||||
| void ast_kind_print(ASTKindData*, int i); | ||||
|  | ||||
| // Print an `ASTExecData`. | ||||
| void ast_exc_print(ASTExcData*, int i); | ||||
|  | ||||
| // Print an `ASTCallData`. | ||||
| void ast_call_print(ASTCallData*, int i); | ||||
|  | ||||
| // Print an `ASTDefData`. | ||||
| void ast_def_print(ASTDefData*, int depth); | ||||
|  | ||||
| // Print an `ASTRefData`. | ||||
| void ast_ref_print(ASTRefData*, int i); | ||||
|  | ||||
| // Print an `ASTBlockData`. | ||||
| void ast_block_print(ASTBlockData*, int i); | ||||
|  | ||||
| // Print an `ASTArgData`. | ||||
| void ast_arg_print(ASTArgData* arg, int i); | ||||
|  | ||||
| // Print an `ASTLambdaData`. | ||||
| void ast_lambda_print(ASTLambdaData* arg, int i); | ||||
|  | ||||
| // Print an `ASTBIFData`. | ||||
| void ast_bif_print(ASTBIFData* arg, int i); | ||||
|  | ||||
| // Print an `ASTForceData`. | ||||
| void ast_force_print(ASTForceData* force, int i); | ||||
|  | ||||
| // Print an `ASTPreserveData`. | ||||
| void ast_preserve_print(ASTPreserveData* preserve, int i); | ||||
| #endif | ||||
| @@ -2,22 +2,32 @@ | ||||
| #define BUILTIN_H | ||||
|  | ||||
| #include "ast.h" | ||||
| #include <stddef.h> | ||||
|  | ||||
| // Sum some nums. | ||||
| AST* builtin_sum(size_t argc, AST** argv); | ||||
| AST* builtin_sum(size_t argc, AST** argv, Scope* parent); | ||||
|  | ||||
| // Subtract nums. | ||||
| AST* builtin_sub(size_t argc, AST** argv); | ||||
| AST* builtin_sub(size_t argc, AST** argv, Scope* parent); | ||||
|  | ||||
| // Multiply nums. | ||||
| AST* builtin_mul(size_t argc, AST** argv); | ||||
| AST* builtin_mul(size_t argc, AST** argv, Scope* parent); | ||||
|  | ||||
| // Divide nums. | ||||
| AST* builtin_div(size_t argc, AST** argv); | ||||
| AST* builtin_div(size_t argc, AST** argv, Scope* parent); | ||||
|  | ||||
| // Die. | ||||
| AST* builtin_die(size_t argc, AST** argv, Scope* parent); | ||||
|  | ||||
| // If statement. | ||||
| AST* builtin_if(size_t argc, AST** argv, Scope* parent); | ||||
|  | ||||
| // Equality. | ||||
| AST* builtin_eq(size_t argc, AST** argv, Scope* parent); | ||||
|  | ||||
| struct builtin_data { | ||||
|     char* name; | ||||
|     AST* (*fn)(size_t argc, AST** argv); | ||||
|     AST* (*fn)(size_t argc, AST** argv, Scope* parent); | ||||
| }; | ||||
|  | ||||
| static struct builtin_data BUILTIN_FNS[] = { | ||||
| @@ -25,6 +35,9 @@ static struct builtin_data BUILTIN_FNS[] = { | ||||
|     { "sub", builtin_sub }, | ||||
|     { "mul", builtin_mul }, | ||||
|     { "div", builtin_div }, | ||||
|     { "die", builtin_die }, | ||||
|     {"_if", builtin_if}, | ||||
|     {"eq", builtin_eq}, | ||||
| }; | ||||
| #define BUILTIN_FNS_LN (arrln(BUILTIN_FNS)) | ||||
|  | ||||
|   | ||||
| @@ -2,25 +2,35 @@ | ||||
| #define EXEC_H | ||||
|  | ||||
| #include "ast.h" | ||||
| #include "stack.h" | ||||
| #include "scope.h" | ||||
|  | ||||
| // Start executing at the root of the AST. Initialize the `scope`. | ||||
| AST* exec_start(AST* ast); | ||||
| // Execute an expression. Delegates to the other executor functions. | ||||
| AST* exec_exp(AST* ast); | ||||
| AST* exec_exp(AST* ast, Scope* parent); | ||||
| // Execute the expressions of a block. | ||||
| AST* exec_block(AST* ast); | ||||
| AST* exec_block(AST* ast, Scope* parent); | ||||
| // Execute a call. | ||||
| AST* exec_call(AST* ast); | ||||
| // Execute a custom function call. | ||||
| AST* exec_cf(AST* ast, size_t argc, AST** argv); | ||||
| // Execute a variable reference. | ||||
| AST* exec_vref(AST* ast); | ||||
| // Execute a variable definition. | ||||
| AST* exec_vdef(AST* ast); | ||||
| AST* exec_call(AST* ast, Scope* parent); | ||||
| // Execute a definition. | ||||
| AST* exec_def(AST* ast, Scope* parent); | ||||
| // Execute a reference. | ||||
| AST* exec_ref(AST* ast, Scope* parent); | ||||
| // Execute a function definition. | ||||
| AST* exec_fdef(AST* ast); | ||||
| AST* exec_fdef(AST* ast, Scope* parent); | ||||
| // Execute a lambda expression. | ||||
| AST* exec_lambda(size_t argc, AST** argv, AST* exp, Scope* parent); | ||||
| // Execute a force expression. | ||||
| AST* exec_force(AST* ast, Scope* parent); | ||||
| // Execute a preserve expression. | ||||
| AST* exec_preserve(AST* ast, Scope* parent); | ||||
| // Print the result of an execution. | ||||
| void exec_print(double n); | ||||
|  | ||||
| // Create a new scope and mark it as linked. Also update inherited scope. | ||||
| void exec_new_scope(AST* ast, Scope* inherit); | ||||
|  | ||||
| // Inherit from another scope and mark it as linked. | ||||
| void exec_inherit_scope(AST* ast, Scope* inherit); | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										32
									
								
								src/include/gc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/include/gc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| #ifndef GC_H | ||||
| #define GC_H | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| // The type a GC can refer to. | ||||
| typedef enum { | ||||
|     GC_TYPE_AST, | ||||
|     GC_TYPE_SCOPE, | ||||
|     GC_TYPE_MAX = GC_TYPE_SCOPE | ||||
| } GCType; | ||||
|  | ||||
| // Added to each AST and Scope; keep track of what's actually still accessible. | ||||
| typedef struct GC_STRUCT { | ||||
|     void* p;               // Pointer to the data. | ||||
|     struct GC_STRUCT* nxt; // The next GC in the linked list. | ||||
|     GCType type;           // What type of data. | ||||
|     bool marked;           // Whether the data is still accessible. | ||||
| } GC; | ||||
|  | ||||
| GC* gc_init(void* p, GCType type, GC*); | ||||
| // Does not free ->p or ->nxt. | ||||
| void gc_destroy(GC* gc); | ||||
|  | ||||
| // Allocate for an object in the heap, and keep track of it in the GC. | ||||
| void* gc_alloc(size_t sz, GCType type); | ||||
|  | ||||
| // Free everything, immediately. | ||||
| void gc_hack_free(); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										22
									
								
								src/include/scope.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/include/scope.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| #ifndef SCOPE_H | ||||
| #define SCOPE_H | ||||
|  | ||||
| #include "htab.h" | ||||
|  | ||||
| // Represents the reverse linked tree of scope. | ||||
| typedef struct SCOPE_T { | ||||
|     HTab* here; // This scope's hash table. | ||||
|     struct SCOPE_T* inherit; // The scope to inherit from. | ||||
|     int uses; // How many `AST`s are linked to this scope. // TODO: REMOVE. | ||||
| } Scope; | ||||
|  | ||||
| // Create a new `Scope`. Creates new empty `HTab` for current scope. | ||||
| Scope* scope_init(Scope* inherit); | ||||
| // Destroy all linked `Scope`s this inherits from. | ||||
| void scope_destroy(Scope* scope); | ||||
| // Destroy the current `Scope` only. | ||||
| void scope_destroy_psv(Scope *scope); | ||||
| // Insert a key/val pair into the `HTab` of a `Scope`. | ||||
| void scope_add(Scope* scope, char* key, void* val); | ||||
|  | ||||
| #endif | ||||
| @@ -1,6 +1,8 @@ | ||||
| #ifndef UTIL_H | ||||
| #define UTIL_H | ||||
|  | ||||
| #include <signal.h> | ||||
|  | ||||
| // Most of this file is cursed printing macros for `ast_print()`. Do not attempt | ||||
| // to comprehend. | ||||
|  | ||||
| @@ -10,6 +12,9 @@ | ||||
| // Get the length of an array. | ||||
| #define arrln(A) (sizeof(A)/sizeof(*A)) | ||||
|  | ||||
| // Trap GDB &c. | ||||
| #define TRAP() RAISE(SIGTRAP) | ||||
|  | ||||
| #ifdef DBG // Debug macros | ||||
|  | ||||
| // Log a message. | ||||
|   | ||||
							
								
								
									
										40
									
								
								src/lexer.c
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								src/lexer.c
									
									
									
									
									
								
							| @@ -3,6 +3,7 @@ | ||||
| #include <limits.h> | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "include/dstr.h" | ||||
| #include "include/lexer.h" | ||||
| @@ -26,7 +27,7 @@ void argarr_destroy(ArgArr* argarr) { | ||||
| void argarr_destroypsv(ArgArr* argarr) { free(argarr); } | ||||
|  | ||||
| void argarr_add(ArgArr* argarr, AST* arg) { | ||||
|     if ((argarr->ln + 1) * argarr->sz > argarr->sz) { | ||||
|     if ((argarr->ln + 1) * sizeof(AST*) > argarr->sz) { | ||||
|         argarr->sz *= 2; | ||||
|         argarr->buf = realloc(argarr->buf, argarr->sz); | ||||
|         log_dbgf( | ||||
| @@ -72,7 +73,20 @@ double acc_float(int c) { | ||||
|  | ||||
| char* acc_word(int c) { | ||||
|     Dstr* val = dstr_init(); | ||||
|     while (isalpha(*inp)) { | ||||
|     while (isalpha(*inp) || *inp == '_') { | ||||
|         dstr_appendch(val, *(inp - 1)); | ||||
|         inp++; | ||||
|     } | ||||
|     dstr_appendch(val, *(inp - 1)); | ||||
|  | ||||
|     char* ret = val->buf; | ||||
|     dstr_destroypsv(val); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| char* acc_deq(int c) { | ||||
|     Dstr* val = dstr_init(); | ||||
|     while (*inp == '=') { | ||||
|         dstr_appendch(val, *(inp - 1)); | ||||
|         inp++; | ||||
|     } | ||||
| @@ -92,14 +106,27 @@ int yylex() { | ||||
|     // Assign & consume current character. | ||||
|     int c = *inp++; | ||||
|  | ||||
|     if (c == '-' && *inp == '>' && inp++) { return RARROW; } | ||||
|     if (c == '<' && *inp == '-' && inp++) { return LARROW; } | ||||
|     if (c == '=' && *inp == '=' && inp++) { return DEQ; } | ||||
|     if (c == '=' && *inp != '=') { return EQ; } | ||||
|  | ||||
|     // Check for NUM. | ||||
|     if (isdigit(c)) { | ||||
|         yylval.fval = acc_float(c); // Set the token value. | ||||
|         return NUM; | ||||
|     } | ||||
|  | ||||
|     if (isalpha(c)) { | ||||
|     if (isalpha(c) || c == '_') { | ||||
|         yylval.strval = acc_word(c); | ||||
|  | ||||
|         if (!strcmp(yylval.strval, "TRUE") || !strcmp(yylval.strval, "T")) | ||||
|             return BOOLT; | ||||
|         if (!strcmp(yylval.strval, "FALSE") || !strcmp(yylval.strval, "F")) | ||||
|             return BOOLF; | ||||
|         if (!strcmp(yylval.strval, "if")) return IF; | ||||
|         if (!strcmp(yylval.strval, "else")) return ELSE; | ||||
|  | ||||
|         return WORD; | ||||
|     } | ||||
|  | ||||
| @@ -115,7 +142,12 @@ int yylex() { | ||||
|         case ';':  return EXPSEP; | ||||
|         case '{':  return BLOCKS; | ||||
|         case '}':  return BLOCKE; | ||||
|         case '=':  return EQ; | ||||
|         case '\\': return BACKSLASH; | ||||
|         case '?':  return IF; | ||||
|         case ':':  return COLON; | ||||
|         case '$':  return STOP; | ||||
|         case '!':  return FORCE; | ||||
|         case '@':  return PRESERVE; | ||||
|         default:   fprintf(stderr, "Unexpected character: %c\n", c); | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										42
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -2,12 +2,11 @@ | ||||
| #include <string.h> | ||||
|  | ||||
| #include "include/ast.h" | ||||
| #include "include/ast_print.h" | ||||
| #include "include/dstr.h" | ||||
| #include "include/exec.h" | ||||
| #include "include/global.h" | ||||
| #include "include/htab.h" | ||||
| #include "include/gc.h" | ||||
| #include "include/lexer.h" | ||||
| #include "include/stack.h" | ||||
| #include "include/util.h" | ||||
|  | ||||
| #include "../build/grammars/grammar.tab.h" | ||||
| @@ -17,17 +16,16 @@ extern AST* root; | ||||
| extern char* inp; | ||||
| extern int yyparse(); | ||||
|  | ||||
| Stack* scope; | ||||
|  | ||||
| int main(int argc, char** argv) { | ||||
|  | ||||
|     if (argc - 1 && strlen(argv[1]) > 0 && (inp = argv[1]) && !yyparse()) { | ||||
|         log_dbg("Parsed successfully!\n"); | ||||
|         ast_print(exec_start(root)); | ||||
|         HTab* global = stack_pop(scope); | ||||
|         htab_destroy(global); | ||||
|         stack_destroy(scope); | ||||
|         ast_destroy(root); | ||||
|         // log_dbg("Parsed successfully!\n"); | ||||
|         // ast_print(root); | ||||
|         AST* eval = exec_start(root); | ||||
|         ast_print(eval); | ||||
|         // ast_destroy(eval); | ||||
|         // ast_destroy(root); | ||||
|         gc_hack_free(); | ||||
|         exit(0); | ||||
|     } | ||||
|  | ||||
| @@ -56,18 +54,26 @@ int main(int argc, char** argv) { | ||||
|             inp = ln->buf; | ||||
|             if (yyparse() == 0) { | ||||
|                 log_dbg("Parsed successfully!\n"); | ||||
|             } else printf("Parse error.\n"); | ||||
|             } else { | ||||
|                 printf("Parse error.\n"); | ||||
|                 dstr_destroy(ln); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
| #ifdef DBG | ||||
|             ast_print(root); | ||||
| #endif | ||||
|  | ||||
|             ast_print(exec_start(root)); | ||||
|             HTab* global = stack_pop(scope); | ||||
|             htab_destroy(global); | ||||
|             stack_destroy(scope); | ||||
|  | ||||
|             ast_destroy(root); | ||||
|             AST* eval = exec_start(root); | ||||
|             ast_print(eval); | ||||
|             // Awful hack to exit when die() is called, until proper exception | ||||
|             // handling is implemented. TODO TODO TODO PLSFIX. | ||||
|             if (eval->type == AST_TYPE_EXC && | ||||
|                 ((ASTExcData*)eval->data)->msg[0] == '8') { | ||||
|                 gc_hack_free(); | ||||
|                 exit(1); | ||||
|             } | ||||
|             gc_hack_free(); | ||||
|         } | ||||
|  | ||||
|         dstr_destroy(ln); | ||||
|   | ||||
							
								
								
									
										37
									
								
								src/scope.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/scope.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| #include "include/scope.h" | ||||
| #include "include/gc.h" | ||||
| #include "include/htab.h" | ||||
| #include "include/util.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| Scope* scope_init(Scope* inherit) { | ||||
|     Scope* scope = gc_alloc(sizeof(Scope), GC_TYPE_SCOPE); | ||||
|  | ||||
|     scope->here = htab_init(); | ||||
|     scope->inherit = inherit; | ||||
|     scope->uses = 0; | ||||
|  | ||||
|     log_dbgf("%p: new scope, inherits from %p", scope, inherit); | ||||
|  | ||||
|     return scope; | ||||
| } | ||||
|  | ||||
| void scope_destroy(Scope* scope) { | ||||
|     if (!scope) return; | ||||
|     htab_destroy(scope->here); | ||||
|     if (scope->inherit != NULL) scope_destroy(scope->inherit); | ||||
|     free(scope); | ||||
| } | ||||
|  | ||||
| void scope_destroy_psv(Scope* scope) { | ||||
|     if (!scope) return; | ||||
|     log_dbgf("%p: destroying", scope); | ||||
|     htab_destroy(scope->here); | ||||
|     scope->inherit = NULL; | ||||
|     free(scope); | ||||
| } | ||||
|  | ||||
| inline void scope_add(Scope* scope, char* key, void* val) { | ||||
|     htab_ins(scope->here, key, val); | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| #include <assert.h> | ||||
| #include <stdio.h> | ||||
| #include <stdio.h> // IWYU pragma: keep. Req by util macros. | ||||
| #include <string.h> | ||||
|  | ||||
| #include "include/stack.h" | ||||
|   | ||||
 Submodule test/Unity updated: cdf1d0297e...73237c5d22
									
								
							| @@ -17,7 +17,7 @@ void test_ast_num() { | ||||
| } | ||||
|  | ||||
| void test_ast_call() { | ||||
|     AST** argv = malloc(2*sizeof(AST*)); | ||||
|     AST** argv = malloc(2 * sizeof(AST*)); | ||||
|     argv[0] = ast_init(AST_TYPE_NUM, ast_num_data_init(1.0)); | ||||
|     argv[1] = ast_init(AST_TYPE_NUM, ast_num_data_init(2.0)); | ||||
|  | ||||
| @@ -37,23 +37,8 @@ void test_ast_call() { | ||||
|     ast_destroy(ast); | ||||
| } | ||||
|  | ||||
| void test_ast_vref() { | ||||
|     char* s = malloc(2); | ||||
|     strcpy(s, "x"); | ||||
|     ASTVrefData* vref = ast_vref_data_init(s); | ||||
|     AST* ast = ast_init(AST_TYPE_VREF, vref); | ||||
|  | ||||
|     TEST_ASSERT_EQUAL(AST_TYPE_VREF, ast->type); | ||||
|     ASTVrefData data = *(ASTVrefData*)ast->data; | ||||
|     TEST_ASSERT_EQUAL_STRING("x", data.to); | ||||
|  | ||||
|     //ast_destroy(ast); | ||||
| // ast_destroy(ast); | ||||
| } | ||||
|  | ||||
| int main() { | ||||
|     UNITY_BEGIN(); | ||||
|     RUN_TEST(test_ast_num); | ||||
|     //RUN_TEST(test_ast_call); | ||||
|     //RUN_TEST(test_ast_vref); | ||||
|     return UNITY_END(); | ||||
| } | ||||
|   | ||||
							
								
								
									
										31
									
								
								type_notes.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								type_notes.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| n: Int = 3 | ||||
|  | ||||
| - 'Int': integer constructor | ||||
| - '3': integer literal | ||||
|  | ||||
| v: Vec(3, Int) = <1, 2, 3> | ||||
|  | ||||
| Point: Struct = { x: Int, y: Int } | ||||
|  | ||||
| p: Point = { .x = 1, .y = 2 } | ||||
| p.x + p.y | ||||
|  | ||||
| VecOf(n: Int, t: Type): Type = Vec(n, t) | ||||
| strings: VecOf(3, Str) = <"Hello", ",", " world."> | ||||
|  | ||||
| f(g) = g(2) | ||||
|  | ||||
| g(n: Int): Int = n * 2 | ||||
| g: Lambda(Int, Int) = \(n: Int):Int n * 2 | ||||
|  | ||||
| Int, Vec, Str | ||||
|  | ||||
| f(g: \(Int):Int ):Int = g(2) | ||||
| f(g: Lambda(Int, Int)): Int = g(2) | ||||
|  | ||||
| f: Lambda(Int, Str, Str) = \(s1: Str, s2: Str) length(s) + length(s2) | ||||
|  | ||||
| Bad: Type = if Until.time() % 2 == 0 Str Int | ||||
|  | ||||
| - Types are code. | ||||
| - All types inherit from `Type` (the type of `Type` is `Type`). | ||||
		Reference in New Issue
	
	Block a user