Compare commits

58 Commits

Author SHA1 Message Date
24f93ce750 Not sure what I just fixed. 2025-10-18 10:26:39 -04:00
2fc3f1e1df Fixed some bugs and memory leaks. 2025-10-18 10:24:59 -04:00
9525535323 Got arrow syntax working. 2025-10-11 11:04:23 -04:00
0fa1c176f4 Added force & preserve operators. 2025-10-11 10:09:17 -04:00
868dcb6788 Merge branch 'types'. 2025-10-11 09:27:15 -04:00
4fb698918c Simple type checking. 2025-10-04 11:16:59 -04:00
df74d29e54 Type parsing is good enough. 2025-10-04 10:04:15 -04:00
7181b31d4b Updated readme with tail-recursive factorial. 2025-10-04 09:33:47 -04:00
7630e4b99f Cleaned up remains of recursive destroy functions.
Not needed with new GC.
2025-09-27 13:35:34 -04:00
74d5a212cd Merge branch 'types'.
Just bumping master before it lags too out of date. Should be pretty
stable at this point.
2025-09-27 13:31:30 -04:00
90fce2fce4 Added types to ast. Added new call syntax. 2025-09-27 11:06:48 -04:00
94689be83b Refactoring.
VRef -> Ref
VDef -> Def
2025-09-27 10:13:57 -04:00
cb5fa27eb3 Plans. 2025-09-12 16:38:16 -04:00
7c08e8da4d Fixed depends. 2025-09-12 16:33:45 -04:00
fdf526750d Cleaned up more fdef stuff. 2025-09-12 16:32:58 -04:00
4e5b12b5b2 Updated README.md. 2025-09-01 00:18:59 -04:00
b102a32999 Cleaned up fdef detritus. 2025-08-30 09:47:48 -04:00
518f2e9803 Changes to nomenclature.
"Kind" is how user-level types are called internally, to avoid
confusion. Kind literals in the AST have also been renamed to better
represent their function.
2025-08-29 09:56:40 -04:00
0e6bb7aa16 Cleaned up. 2025-08-28 11:12:19 -04:00
14ddf51f3c Bump version in README.md.
NOTE: changed versioning system slightly.
2025-08-27 12:30:28 -04:00
ac1d76361f Updated README.md. 2025-08-27 01:14:49 -04:00
b789193484 Recursion works.
FINALLY YESSSS 🎉🎉🎉
2025-08-27 01:10:58 -04:00
ab97f78fab Work on conditionals and equalities. 2025-08-27 00:41:48 -04:00
7c0b212ab4 Added a bit of familiar sugar to conditionals. 2025-08-26 23:50:06 -04:00
80c8038374 Added basic conditionals. 2025-08-26 23:47:15 -04:00
e3cd78e1b4 Added basic implementation of booleans. 2025-08-26 22:58:58 -04:00
b7b90f528b Created an awful hack for a clean exit on die(). 2025-08-26 18:30:08 -04:00
0ef44be808 Fixed some builtin arithmetic logic. 2025-08-26 18:24:28 -04:00
8924818ec4 Updated README.md. 2025-08-26 16:37:48 -04:00
73efa7e136 Cleaned up a bit. 2025-08-26 16:37:38 -04:00
4e8d7131d6 Merge branch 'lambda' 2025-08-26 16:26:06 -04:00
bfce18ab81 Completed lambda implementation of functions.
Hooray! 🎉
2025-08-26 16:25:20 -04:00
7b648c4bd7 Fixed negative expressions. 2025-08-26 16:17:54 -04:00
4ec5d1c075 Fixed everything.
- Cleaned up call stack
- Fixed builtin function execution
- Fixed lambda execution
- Fixed call parsing
2025-08-23 10:53:12 -04:00
5ba070ced7 Things are still in motion. Last thing worked on: call execution. 2025-07-05 11:00:11 -04:00
8256643c0b Updated example. 2025-06-30 01:24:26 -04:00
29a217928e Things are in motion. 2025-06-30 01:22:39 -04:00
482f2b4877 Big refactor to unclutter ast.h.
Moves all print functions to own file for sanity.

Also, just hit 2,000 lines; nice.
2025-06-28 12:25:10 -04:00
36fd838a8f Done with some things, saving here. 2025-06-28 12:05:07 -04:00
289243de38 Added lambda parsing. 2025-06-28 11:15:21 -04:00
67aafb3ead Updated syntax to abbreviate functions defs. 2025-06-28 10:55:15 -04:00
3b5bee0695 Added trap for GDB &c. 2025-06-18 17:21:45 -04:00
970fc39198 Cleaned up types with anonymous structs. 2025-06-14 11:22:07 -04:00
8d3e43d7dc Bump version in README.md. 2025-06-14 14:09:54 +00:00
d4293e87f3 Everything works. 2025-06-14 10:02:04 -04:00
abb8ff6b58 Finished garbage collector.
🎉
2025-06-14 09:23:49 -04:00
80122b6572 I try. 2025-05-31 19:13:26 -04:00
a4afd3b58a Fixed segfault on spacey input. 2025-05-31 18:25:11 -04:00
90c8c91410 Somethings working. 2025-05-31 18:19:04 -04:00
f5ab0e9cb0 Fixed memory leak. 2025-05-24 10:52:27 -04:00
0fb1f1d55f Began work on garbage collector. 2025-05-24 10:37:29 -04:00
1d83aa65a4 Well it mostly works now.
Fixed some memory leaks. Implemented some memory leaks.

May need to look into garbage collection in the future.
2025-05-17 11:01:20 -04:00
3f30662cde Fixed some memory bugs. 2025-05-10 10:43:36 -04:00
743d16f696 Fixed bad free on stack.
Still need to figure that one out.
2025-05-07 08:54:19 -04:00
7b99292547 Builtin functions now work with new scope. 2025-05-07 08:38:10 -04:00
4a516d8edb Updated builtin functions for scope. 2025-05-07 08:16:05 -04:00
5b0950cabb Finished linked env scope on user functions.
Doesn't work for builtin functions yet, so doesn't compile. TODO.
2025-04-26 11:04:21 -04:00
40051de9ae Fix deprecated version name.
Co-authored-by: bgiobbe-tcs <bgiobbe.tcs@gmail.com>
2025-04-26 10:58:09 -04:00
29 changed files with 1296 additions and 579 deletions

View File

@@ -1,20 +1,20 @@
# SCL: Simple CAS Language # SCL: Simple CAS Language
Version v1.0-alpha *v0.3*
SCL aims to be a human-friendly Computer Algebra System (CAS) inspired by 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 [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 its current state, SCL can be used as a functional programming language capable
of operations and local variables. The codebase is about 1,400 lines of C, of performing simple arithmetic. The codebase is about 2,000 lines of
including a parser, interpreter, and runtime. It uses a linked environment handwritten C, including a parser, interpreter, and runtime. It uses a linked
scoping model. environment scoping model.
## Usage ## Usage
To download and run: To download and run:
```bash ```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 make release
./scl.out ./scl.out
``` ```
@@ -22,75 +22,50 @@ make release
### For Development ### For Development
```bash ```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 make all test
./scl.out ./scl.out
``` ```
If you wish to run tests, make sure to run `git clone --recurse-submodules` to 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. 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 ## Syntax
As one would expect, you can evaluate simple infix expressions: SCL's syntax will feel familiar to other functional programming languages.
```scl ```scl
> 1 + 1 > x = 3 + 3 * 3; x + 1
= 13
> f(x) x + 1
> f(1)
= 2 = 2
``` > (\(x) 2 * x)(5)
= 10
You can also define your own functions and variables: > f(g) g(2)
> f(\(x) 2 * x)
```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
= 4 = 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 ```scl
> f(x) = x^4 > fac(n) = {
> diff(f, x:sym, 2) > f(n, a) = {
= 12x^2 > 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 SCL's syntax is quite flexible. The above function could be more concisely
well: written as:
```scl ```scl
> f(x: int): int = 2x > fac(n) (n, 1) -> f(n, a) ? n == 1 a f(n - 1, a * n)
> 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.
``` ```

View File

@@ -12,33 +12,33 @@
- [x] Order of operations - [x] Order of operations
- [x] Parse function application - [x] Parse function application
- [x] Parse order of operations with parenthesis - [x] Parse order of operations with parenthesis
- [ ] Parse variable invocation - [x] Parse variable invocation
- [x] Parse variable definition - [x] Parse variable definition
- [ ] Parse types - [ ] Parse types
- [ ] Parse function definition - [x] Parse function definition
- [ ] Parse lists/arrays/vectors - [ ] Parse lists/arrays/vectors
- [x] Parse blocks - [x] Parse blocks
- [ ] Parse control flow - [ ] Parse control flow
- [ ] Parse `if` statements - [x] Parse `if` statements
- [ ] Parse `loop`s - [ ] Parse `loop`s
- [ ] Parse `for` loops - [ ] Parse `for` loops
- [ ] Parse `while` loops - [ ] Parse `while` loops
- [ ] Parse `case` statements - [ ] Parse `case` statements
- [ ] Parse `goto` statements - [ ] Parse `goto` statements
- [ ] Parse lambda function definition - [x] Parse lambda function definition
- [ ] Parse function calling with positional arguments - [ ] Parse function calling with positional arguments
- [ ] Parse variadic functions - [ ] Parse variadic functions
- [ ] Parse infix function definition - [ ] Parse infix function definition
- [ ] Executer - [ ] Executer
- [x] Exec function calls - [x] Exec function calls
- [ ] Exec variable use - [x] Exec variable use
- [ ] Exec variable definition - [x] Exec variable definition
- [ ] Exec function definition - [x] Exec function definition
- [ ] Exec symbolic variables - [ ] Exec symbolic variables
- [ ] Exec control flow statements - [ ] Exec control flow statements
- [ ] Exec variadic functions - [ ] Exec variadic functions
- [ ] Exec lambda functions - [x] Exec lambda functions
- [ ] Exec lists - [ ] Exec lists
- [ ] Exec arrays - [ ] Exec arrays
- [ ] Exec vectors - [ ] Exec vectors

11
TODO.md
View File

@@ -1,7 +1,10 @@
0. Create file to describe properties of terminology used; param, arg, var, &c. Differentiate kind literals, constructors, and kinds themselves.
1. Differenciate parameters and arguments -- params for function definitions, EXCEPTION HANDLING: exception ast type should have as data a giant enum of
arguments for function calls possible types, rather than a char* message. A description of each type could be
2. Add scope field to all ASTs, and new scope layer for those that need it. handled under the exception type and print logic. For now, executor checks
message for special exceptions e.g. exit().
Change editor to GNU Readline. Change editor to GNU Readline.
Make variables persist through lines in the editor. Make variables persist through lines in the editor.
Return syntax errors as exceptions.

View File

@@ -11,7 +11,7 @@ TEST_DIR = test
TEST_BUILD_DIR = $(BUILD_DIR)/test TEST_BUILD_DIR = $(BUILD_DIR)/test
TEST_OBJ_DIR = $(TEST_BUILD_DIR)/obj TEST_OBJ_DIR = $(TEST_BUILD_DIR)/obj
CC = clang -std=c2x CC = clang -std=c23
LINK = clang LINK = clang
CFLAGS = -Wall -DDBG -ggdb -fsanitize=leak CFLAGS = -Wall -DDBG -ggdb -fsanitize=leak
LDFLAGS = -lm LDFLAGS = -lm

25
definitions.md Normal file
View 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

View File

@@ -1,3 +1,2 @@
f(n) = 2 * n apply(f, x) f(x)
apply(\(x) x + 1, 2)
f(5)

View File

@@ -1,48 +1,3 @@
# Vectors x: Int = 3
# - Must have fixed size and type
# Lists <name> : <expression> = <expression>
# - 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">

272
src/ast.c
View File

@@ -1,30 +1,27 @@
#include <inttypes.h>
#include <stdio.h> #include <stdio.h>
#include "include/ast.h" #include "include/ast.h"
#include "include/dstr.h" #include "include/gc.h"
#include "include/scope.h" #include "include/scope.h"
#include "include/util.h" #include "include/util.h"
extern AST* root; 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_init(ASTType type, void* data) {
AST* ast = malloc(sizeof(AST)); AST* ast = gc_alloc(sizeof(AST), GC_TYPE_AST);
ast->type = type; ast->type = type;
ast->data = data; ast->data = data;
ast->scope = NULL; 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; return ast;
} }
@@ -42,47 +39,26 @@ void ast_destroy(AST* ast) {
if (!ast) return; if (!ast) return;
switch (ast->type) { switch (ast->type) {
case AST_TYPE_NUM: ast_num_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_CALL: ast_call_data_destroy(ast->data); break;
case AST_TYPE_VREF: ast_vref_data_destroy(ast->data); break; case AST_TYPE_REF: ast_ref_data_destroy(ast->data); break;
case AST_TYPE_VDEF: ast_vdef_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_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_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: default:
log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX); log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX);
} }
scope_destroy_psv(ast->scope);
free(ast); free(ast);
} }
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) { ASTNumData* ast_num_data_init(double val) {
talloc(ASTNumData, num); talloc(ASTNumData, num);
@@ -93,46 +69,72 @@ ASTNumData* ast_num_data_init(double val) {
void ast_num_data_destroy(ASTNumData* num) { free(num); } void ast_num_data_destroy(ASTNumData* num) { free(num); }
void ast_num_print(ASTNumData* data, int i) { ASTBoolData* ast_bool_data_init(int val) {
INDENT_BEGIN(i); 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)); ASTExcData* data = malloc(sizeof(ASTExcData));
data->msg = msg; data->msg = msg;
data->trace = trace; data->trace = trace;
return data; return data;
} }
void ast_exc_print(ASTExcData* data, int i) { void ast_exc_data_destroy(ASTExcData* exc) {
INDENT_BEGIN(i); // `msg` is static, and `trace` will get freed in GC.
free(exc);
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;
} }
ASTBIFData* ast_bif_data_init(AST* fn(size_t, AST**)) { ASTBIFData* ast_bif_data_init(AST* fn(size_t, AST**, Scope*)) {
return (ASTBIFData*)fn; 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); talloc(ASTCallData, call);
log_dbgf("to: %s", to); call->exp = exp;
call->to = to;
call->argc = argc; call->argc = argc;
call->argv = argv; 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) { void ast_call_data_destroy(ASTCallData* call) {
if (!call) return; 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->argv);
free(call); free(call);
} }
void ast_call_print(ASTCallData* data, int i) { // Def.
INDENT_BEGIN(i);
INDENT_TITLE("ASTCallData", data); ASTDefData* ast_def_data_init(char* name, AST* kind, AST* exp) {
INDENT_FIELD("to", "%s", data->to); talloc(ASTDefData, def);
INDENT_FIELD("argc", "%ld", data->argc);
INDENT_FIELD_LIST("argv", data->argv, data->argc, ast_print_i);
INDENT_END; def->name = name;
def->kind = kind;
def->exp = exp;
return def;
} }
ASTVDefData* ast_vdef_data_init(char* name, AST* val) { void ast_def_data_destroy(ASTDefData* vdef) {
talloc(ASTVDefData, vdef);
vdef->name = name;
vdef->val = val;
return vdef;
}
void ast_vdef_data_destroy(ASTVDefData* vdef) {
ast_destroy(vdef->val);
free(vdef->name); free(vdef->name);
free(vdef); free(vdef);
} }
void ast_vdef_print(ASTVDefData* vdef, int depth) { // Ref.
INDENT_BEGIN(depth);
INDENT_TITLE("ASTVDefData", vdef); ASTRefData* ast_ref_data_init(char* to) {
INDENT_FIELD("name", "%s", vdef->name); talloc(ASTRefData, ref);
INDENT_FIELD_EXT_NONL_START("val");
ast_print_i(vdef->val, depth + 2); // 2 because already indented.
INDENT_FIELD_NONL_END;
INDENT_END; ref->to = to;
return ref;
} }
ASTVrefData* ast_vref_data_init(char* to) { void ast_ref_data_destroy(ASTRefData* ref) {
talloc(ASTVrefData, vref); free(ref->to);
free(ref);
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;
} }
ASTBlockData* ast_block_data_init(AST** inside, size_t ln) { 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) { 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->inside);
free(block); 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* ast_arg_data_init(char* name) {
ASTArgData* arg = malloc(sizeof(ASTArgData)); ASTArgData* arg = malloc(sizeof(ASTArgData));
arg->name = name; 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_data_destroy(ASTArgData* arg) { free(arg->name); }
void ast_arg_print(ASTArgData* arg, int i) { AST* ast_find(Scope* scope, char* name) {
INDENT_BEGIN(i); while (scope) {
INDENT_TITLE("ASTArgData", arg); AST* gotten = htab_get(scope->here, name);
INDENT_FIELD("name", "%s", arg->name); if (gotten) return gotten;
INDENT_END; 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
View 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;
}

View File

@@ -1,21 +1,21 @@
#include "include/builtin.h"
#include "include/ast.h"
#include "include/exec.h"
#include "include/util.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdio.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; ASTNumData total = 0;
for (int i = 0; i < argc; i++) { 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) if (arg->type == AST_TYPE_EXC)
return ast_init( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("`sum` encountered an exception.", arg) 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( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("Sum can't sum some non-num arguments.", NULL) 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; 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) { AST* builtin_sub(size_t argc, AST** argv, Scope* parent) {
log_dbg("Got here"); if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0));
AST* first = exec_exp(*argv);
AST* first = exec_exp(*argv, parent);
if (first->type == AST_TYPE_EXC) if (first->type == AST_TYPE_EXC)
return ast_init( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("`sub` encountered an exception.", first) 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( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("Can't subtract non-num arguments.", NULL) 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; ASTNumData total = *(ASTNumData*)first->data;
for (int i = 1; i < argc; i++) { 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) if (arg->type == AST_TYPE_EXC)
return ast_init( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("`sub` encountered an exception.", arg) 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( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("Can't subtract non-num arguments.", NULL) 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; 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) { AST* builtin_mul(size_t argc, AST** argv, Scope* parent) {
log_dbg("Got here"); if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0));
AST* first = exec_exp(*argv);
AST* first = exec_exp(*argv, parent);
if (first->type == AST_TYPE_EXC) if (first->type == AST_TYPE_EXC)
return ast_init( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("`mul` encountered an expection.", first) 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( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("Can't multiply non-num arguments.", NULL) 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; ASTNumData total = *(ASTNumData*)first->data;
for (int i = 1; i < argc; i++) { 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) if (arg->type == AST_TYPE_EXC)
return ast_init( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("`mul` encountered an execption.", arg) 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( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("Can't multiply non-num arguments.", NULL) 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; 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) { AST* builtin_div(size_t argc, AST** argv, Scope* parent) {
log_dbg("Got here"); if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0));
AST* first = exec_exp(*argv);
AST* first = exec_exp(*argv, parent);
if (first->type == AST_TYPE_EXC) if (first->type == AST_TYPE_EXC)
return ast_init( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("`div` encountered an exception.", first) 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( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("Can't divide non-num arguments.", NULL) 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; ASTNumData total = *(ASTNumData*)first->data;
for (int i = 1; i < argc; i++) { 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) if (arg->type == AST_TYPE_EXC)
return ast_init( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("`div` encountered an exception.", arg) 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( return ast_init(
AST_TYPE_EXC, AST_TYPE_EXC,
ast_exc_data_init("Can't divide non-num arguments.", NULL) 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; 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.
}
} }

View File

@@ -1,9 +1,9 @@
#include <stddef.h>
#include <stdio.h> // IWYU pragma: keep. Req by util macros.
#include "include/dlist.h" #include "include/dlist.h"
#include "include/util.h" #include "include/util.h"
#include <stddef.h>
#include <stdio.h>
DList* dlist_init(void) { DList* dlist_init(void) {
DList* dlist = malloc(sizeof(DList)); DList* dlist = malloc(sizeof(DList));

View File

@@ -6,139 +6,187 @@
#include "include/builtin.h" #include "include/builtin.h"
#include "include/exec.h" #include "include/exec.h"
#include "include/htab.h" #include "include/htab.h"
#include "include/stack.h" #include "include/scope.h"
#include "include/util.h" #include "include/util.h"
AST* exec_find(char* name);
AST* exec_start(AST* ast) { AST* exec_start(AST* ast) {
log_dbg("Started execution."); log_dbg("Started execution.");
Stack* scope = stack_init(); if (!ast) return ast;
HTab* global = htab_init(); Scope* global = scope_init(NULL);
global->uses = 1;
for (int i = 0; i < BUILTIN_FNS_LN; i++) for (int i = 0; i < BUILTIN_FNS_LN; i++)
htab_ins( 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)) ast_init(AST_TYPE_BIF, ast_bif_data_init(BUILTIN_FNS[i].fn))
); );
// Push global namespace to `scope`. AST* defnum =
stack_push(scope, global); 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) { switch (ast->type) {
case AST_TYPE_BLOCK: return exec_block(ast); case AST_TYPE_BLOCK: return exec_block(ast, parent);
case AST_TYPE_CALL: return exec_call(ast); case AST_TYPE_CALL: return exec_call(ast, parent);
case AST_TYPE_NUM: return ast; case AST_TYPE_LIT_NUM:
case AST_TYPE_VREF: return exec_vref(ast); return ast_init(
case AST_TYPE_VDEF: return exec_vdef(ast); AST_TYPE_LIT_NUM, ast_num_data_init(*(ASTNumData*)ast->data)
case AST_TYPE_FDEF: return exec_fdef(ast); );
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); default: printf("what\n"); exit(1);
} }
} }
AST* exec_block(AST* ast) { AST* exec_block(AST* ast, Scope* parent) {
ASTBlockData* block = (ASTBlockData*)ast->data; ASTBlockData* block = (ASTBlockData*)ast->data;
HTab* local = htab_init(); exec_new_scope(ast, parent);
// stack_push(scope, local);
// Loop through all but last ast. // Loop through all but last ast.
for (int i = 0; i < block->ln - 1; i++) exec_exp(block->inside[i]); for (int i = 0; i < block->ln - 1; i++)
AST* last = exec_exp(block->inside[block->ln - 1]); exec_exp(block->inside[i], ast->scope);
AST* last = exec_exp(block->inside[block->ln - 1], ast->scope);
// stack_pop(scope);
htab_destroy(local);
return last; return last;
} }
AST* exec_call(AST* ast) { AST* exec_call(AST* ast, Scope* parent) {
log_dbg("Started call execution."); ASTCallData* calldata = (ASTCallData*)ast->data;
ASTCallData* data = (ASTCallData*)ast->data;
size_t argc = data->argc;
AST** argv = data->argv;
char* fname = data->to;
AST* fdef = exec_find(fname); AST* exp = exec_exp(calldata->exp, parent);
if (fdef == NULL) switch (exp->type) {
case AST_TYPE_BIF:
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( return ast_init(
AST_TYPE_EXC, ast_exc_data_init("No such function found.", NULL) AST_TYPE_EXC, ast_exc_data_init("Uncallable.", NULL)
);
}
}
AST* exec_def(AST* ast, Scope* parent) {
// Use parent's scope.
exec_inherit_scope(ast, parent);
ASTDefData* data = (ASTDefData*)ast->data;
AST* val = data->exp;
char* key = data->name;
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)
); );
switch (fdef->type) { if (kind == AST_LIT_KIND_BOOL && data->exp->type != AST_TYPE_LIT_BOOL)
case AST_TYPE_BIF: return ast_init(
ASTBIFData bifdata = fdef->data; AST_TYPE_EXC, ast_exc_data_init("Expected Bool.", NULL)
return bifdata(argc, argv); );
case AST_TYPE_FDEF: return exec_cf(fdef, argc, argv);
default: if (kind == AST_LIT_KIND_KIND && data->exp->type != AST_TYPE_LIT_KIND)
return ast_init(AST_TYPE_EXC, ast_exc_data_init("Good job!", NULL)); return ast_init(
} AST_TYPE_EXC, ast_exc_data_init("Expected Type.", NULL)
);
} }
AST* exec_cf(AST* ast, size_t argc, AST** argv) { scope_add(parent, key, val); // Add variable definition to parent scope.
ASTFDefData* fdef = (ASTFDefData*)ast->data; return exec_exp(val, parent);
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);
} }
return exec_exp(fdef->body); AST* exec_ref(AST* ast, Scope* parent) {
} // Use parent's scope.
exec_inherit_scope(ast, parent);
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;
char* key = data->name;
// htab_ins(scope->buf[scope->ln - 1], key, val);
return exec_exp(val);
}
AST* exec_vref(AST* ast) {
log_dbg("attempting to reference var"); 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) { if (found == NULL) {
// TODO: Better memory management here. // TODO: Better memory management here.
static char msg[256]; static char msg[256];
snprintf( snprintf(
msg, sizeof(msg), "Could not find value in scope for `%s`.", msg, sizeof(msg), "Could not find value in scope for `%s`.", ref->to
vref->to
); );
return ast_init(AST_TYPE_EXC, ast_exc_data_init(msg, NULL)); 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) { AST* exec_lambda(size_t argc, AST** argv, AST* exp, Scope* parent) {
ASTFDefData* fdef = (ASTFDefData*)ast->data; Scope* callscope = scope_init(parent);
AST* val = fdef->body; ASTLambdaData* lambda = (ASTLambdaData*)exp->data;
char* key = fdef->name; for (int i = 0; i < argc; i++) {
// htab_ins(scope->buf[scope->ln - 1], key, val); char* key = ((ASTArgData*)lambda->parv[i]->data)->name;
return val; // Function definitions return function body. 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); } 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++;
}

View File

@@ -1,6 +1,9 @@
#include "include/fnv1a.h" #include "include/fnv1a.h"
#include "include/util.h"
#include "include/util.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
uint64_t fnv1a_hash(char* key, size_t ln) { uint64_t fnv1a_hash(char* key, size_t ln) {
uint64_t hash = FNV1A_BASIS_64; uint64_t hash = FNV1A_BASIS_64;
@@ -10,5 +13,7 @@ uint64_t fnv1a_hash(char* key, size_t ln) {
hash *= FNV1A_PRIME_64; hash *= FNV1A_PRIME_64;
} }
log_dbgf("Hash of %s was %lu", key, hash);
return hash; return hash;
} }

54
src/gc.c Normal file
View 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);
}
}

View File

@@ -4,6 +4,7 @@
#include "../../src/include/ast.h" #include "../../src/include/ast.h"
#include "../../src/include/lexer.h" #include "../../src/include/lexer.h"
#include "../../src/include/dlist.h" #include "../../src/include/dlist.h"
#include "../../src/include/builtin.h"
int yylex(void); int yylex(void);
void yyerror(char const*); void yyerror(char const*);
@@ -14,6 +15,7 @@
%code requires { %code requires {
#include "../../src/include/ast.h" #include "../../src/include/ast.h"
#include "../../src/include/dlist.h" #include "../../src/include/dlist.h"
#include "../../src/include/builtin.h"
} }
%union { %union {
@@ -26,6 +28,12 @@
%define parse.error verbose %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 BLOCKS // Block start {.
%token BLOCKE // Block end }. %token BLOCKE // Block end }.
@@ -34,6 +42,10 @@
%token SEP // Seperator ,. %token SEP // Seperator ,.
%token EQ // Equals =. %token EQ // Equals =.
%token DEQ // Double equals ==.
%token RARROW // Right arrow ->.
%token LARROW // Left arrow <-.
%token EXPSEP // Expression seperator ;. %token EXPSEP // Expression seperator ;.
@@ -47,8 +59,19 @@
%token NL // Newline. %token NL // Newline.
%token COLON // Colon :.
%token STOP // Stop sign $.
%token FORCE // Force operator !.
%token PRESERVE // Preserve operator @.
%token BACKSLASH
%left ADD SUB %left ADD SUB
%left MUL DIV %left MUL DIV
%left RARROW
%right LARROW
%nonassoc STOP
%precedence NEG %precedence NEG
%type<ast> exp; %type<ast> exp;
@@ -63,6 +86,8 @@
%% %%
maybe_stop: %empty | STOP;
inputstart: inputstart:
exp { exp {
DList* exps = dlist_init(); DList* exps = dlist_init();
@@ -85,6 +110,7 @@ inputend:
%empty %empty
| input { | input {
root = ast_init(AST_TYPE_BLOCK, ast_block_data_init((AST**) $1->buf, $1->ln)); root = ast_init(AST_TYPE_BLOCK, ast_block_data_init((AST**) $1->buf, $1->ln));
dlist_destroypsv($1);
} }
; ;
@@ -120,83 +146,267 @@ block:
} }
; ;
exp: exp:
NUM { $$ = ast_init(AST_TYPE_NUM, ast_num_data_init($1)); } // Stop sign.
exp STOP { $$ = $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));
}
// Variable reference. // Variable reference.
| WORD { | 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 { | WORD GROUPS arg GROUPE {
size_t argc = $3->ln; size_t argc = $3->ln;
AST** argv = $3->buf; AST** argv = $3->buf;
argarr_destroypsv($3); 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 { | exp ADD exp {
AST** argv = calloc(2, sizeof(AST*)); AST** argv = calloc(2, sizeof(AST*));
argv[0] = $1; argv[0] = $1;
argv[1] = $3; argv[1] = $3;
char* to = malloc(4); $$ = ast_init(AST_TYPE_CALL,
strcpy(to, "sum"); ast_call_data_init(
$$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); 2,
argv,
ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_sum))
)
);
} }
| exp SUB exp { | exp SUB exp {
AST** argv = calloc(2, sizeof(AST*)); AST** argv = calloc(2, sizeof(AST*));
argv[0] = $1; argv[0] = $1;
argv[1] = $3; argv[1] = $3;
char* to = malloc(4); $$ = ast_init(AST_TYPE_CALL,
strcpy(to, "sub"); ast_call_data_init(
$$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); 2,
argv,
ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_sub))
)
);
} }
| exp MUL exp { | exp MUL exp {
AST** argv = calloc(2, sizeof(AST*)); AST** argv = calloc(2, sizeof(AST*));
argv[0] = $1; argv[0] = $1;
argv[1] = $3; argv[1] = $3;
char* to = malloc(4); $$ = ast_init(AST_TYPE_CALL,
strcpy(to, "mul"); ast_call_data_init(
$$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); 2,
argv,
ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_mul))
)
);
} }
| exp DIV exp { | exp DIV exp {
AST** argv = calloc(2, sizeof(AST*)); AST** argv = calloc(2, sizeof(AST*));
argv[0] = $1; argv[0] = $1;
argv[1] = $3; argv[1] = $3;
char* to = malloc(4); $$ = ast_init(AST_TYPE_CALL,
strcpy(to, "div"); ast_call_data_init(
$$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); 2,
} argv,
ast_init(AST_TYPE_BIF, ast_bif_data_init(builtin_div))
| 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));
} }
%% %%

View File

@@ -9,6 +9,8 @@
HTab* htab_init() { HTab* htab_init() {
HTab* htab = calloc(1, sizeof(HTab)); HTab* htab = calloc(1, sizeof(HTab));
log_dbgf("HTAB %p", htab);
return htab; return htab;
} }
@@ -29,7 +31,6 @@ void* htab_get(HTab* htab, char* key) {
void htab_ins(HTab* htab, char* key, void* data) { void htab_ins(HTab* htab, char* key, void* data) {
size_t i = geti(key); size_t i = geti(key);
// assert((*htab)[i] == NULL);
(*htab)[i] = data; (*htab)[i] = data;
log_dbgf("Inserted something to hash table @ index %lu", i); log_dbgf("Inserted something to hash table @ index %lu", i);
} }

View File

@@ -1,32 +1,38 @@
#ifndef AST_H #ifndef AST_H
#define AST_H #define AST_H
#include "htab.h"
#include "scope.h" #include "scope.h"
#include <stdlib.h> #include <stdlib.h>
// The type of an `AST`. // The type of an `AST`.
typedef enum { typedef enum {
// Primitive types. // Primitive type literals.
AST_TYPE_NUM, // A number (float). AST_TYPE_LIT_NUM, // A number (float) literal.
AST_TYPE_STR, // A string AST_TYPE_LIT_BOOL, // A boolean literal.
AST_TYPE_INT, // An integer. AST_TYPE_LIT_VEC, // A vector literal.
AST_TYPE_SYM, // A symbol. AST_TYPE_LIT_KIND, // A kind literal.
AST_TYPE_EXC, // Exception.
AST_TYPE_EXC_CON, // Exception constructor `Exc`.
AST_TYPE_VEC_CON, // Vectpr constructor `Vec()`.
// Collection types: // Collection types:
AST_TYPE_VEC, // A vector (fixed size, fixed type). AST_TYPE_VEC, // A vector (fixed size, fixed type).
AST_TYPE_LIST, // A list (variable size, variable 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. // Misc. types.
AST_TYPE_BIF, // Built-in function. AST_TYPE_BIF, // Built-in function.
AST_TYPE_CALL, // A function call. AST_TYPE_CALL, // A function call.
AST_TYPE_VDEF, // A variable definition. AST_TYPE_DEF, // A definition.
AST_TYPE_VREF, // A variable reference. AST_TYPE_REF, // A variable reference.
AST_TYPE_BLOCK, // A block of code (scope). AST_TYPE_LAMBDA, // An anonymous function definition.
AST_TYPE_FDEF, // A function definition. AST_TYPE_EXC, // An exception.
AST_TYPE_ARG, // A definition argument. AST_TYPE_MAX = AST_TYPE_EXC,
AST_TYPE_MAX = AST_TYPE_FDEF,
} ASTType; } ASTType;
// An Abstract Syntax Tree. // An Abstract Syntax Tree.
@@ -40,12 +46,8 @@ typedef struct {
AST* ast_init(ASTType type, void* data); AST* ast_init(ASTType type, void* data);
// Create a new `AST` with a specified scope. // Create a new `AST` with a specified scope.
AST* ast_init_scope(ASTType type, void* data, Scope* scope); AST* ast_init_scope(ASTType type, void* data, Scope* scope);
// Destroy an `AST`, recursively. // Destroy an `AST`.
void ast_destroy(AST* 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. // A number.
typedef double ASTNumData; typedef double ASTNumData;
@@ -54,67 +56,106 @@ typedef double ASTNumData;
ASTNumData* ast_num_data_init(double val); ASTNumData* ast_num_data_init(double val);
// Destroy an `ASTNumData`. // Destroy an `ASTNumData`.
void ast_num_data_destroy(ASTNumData* num); 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. // An exception.
typedef struct ASTEXCDATA { typedef struct ASTEXCDATA {
char* msg; // The exception message. const char* msg; // The exception message.
AST* trace; // The previous exception. AST* trace; // The previous exception.
} ASTExcData; } ASTExcData;
// Create a new `ASTExecData. // Create a new `ASTExecData. `msg` should be static.
ASTExcData* ast_exc_data_init(char* msg, AST* trace); ASTExcData* ast_exc_data_init(const char* msg, AST* trace);
// Destroy an `ASTExecData`. // Destroy an `ASTExecData`.
void ast_exc_data_destroy(ASTExcData* exc); 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. // 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. // 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 lambda.
// A call (to a function).
typedef struct { typedef struct {
char* to; // What the call's to. PARS; // The parameters the lambda can accept.
size_t argc; // Argument count. AST* body; // The body expression to be executed.
AST** argv; // Argument vector. } 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; } ASTCallData;
// Create a new `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`. // Destroy an `ASTCallData`.
void ast_call_data_destroy(ASTCallData* call); 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 { typedef struct {
char* name; char* name;
AST* val; AST* kind; // If NULL, assume `Any` kind.
} ASTVDefData; AST* exp;
} ASTDefData;
// Create a new `ASTVDefData`. // Create a new `ASTDefData`.
ASTVDefData* ast_vdef_data_init(char* name, AST* val); ASTDefData* ast_def_data_init(char* name, AST* kind, AST* exp);
// Destroys the `ASTVDefData`, `ASTVDefData->name`, and `ASTVDefData->val`. // Destroy an `ASTDefData`.
void ast_vdef_data_destroy(ASTVDefData* vdef); void ast_def_data_destroy(ASTDefData* vdef);
// Print an `ASTVDefData`.
void ast_vdef_print(ASTVDefData*, int depth);
// A variable reference's data. // A reference.
typedef struct { typedef struct {
char* to; // What the reference's to. char* to; // What the reference's to.
} ASTVrefData; } ASTRefData;
// Create a new `ASTVRefData`. // Create a new `ASTRefData`.
ASTVrefData* ast_vref_data_init(char* to); ASTRefData* ast_ref_data_init(char* to);
// Destroy an `ASTVRefData`. // Destroy an `ASTRefData`.
void ast_vref_data_destroy(ASTVrefData* call); void ast_ref_data_destroy(ASTRefData* call);
// Print an `ASTVRefData`.
void ast_vref_print(ASTVrefData*, int i);
// A code block. // A code block.
typedef struct { typedef struct {
@@ -126,22 +167,6 @@ typedef struct {
ASTBlockData* ast_block_data_init(AST** inside, size_t ln); ASTBlockData* ast_block_data_init(AST** inside, size_t ln);
// Destroy an `ASTBlockData`, recursively. // Destroy an `ASTBlockData`, recursively.
void ast_block_data_destroy(ASTBlockData* block); 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 { typedef struct {
char* name; // Argument name. char* name; // Argument name.
@@ -151,7 +176,18 @@ typedef struct {
ASTArgData* ast_arg_data_init(char* name); ASTArgData* ast_arg_data_init(char* name);
// Destroy an `ASTArgData`. // Destroy an `ASTArgData`.
void ast_arg_data_destroy(ASTArgData* arg); 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 #endif

49
src/include/ast_print.h Normal file
View 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

View File

@@ -2,22 +2,32 @@
#define BUILTIN_H #define BUILTIN_H
#include "ast.h" #include "ast.h"
#include <stddef.h>
// Sum some nums. // Sum some nums.
AST* builtin_sum(size_t argc, AST** argv); AST* builtin_sum(size_t argc, AST** argv, Scope* parent);
// Subtract nums. // Subtract nums.
AST* builtin_sub(size_t argc, AST** argv); AST* builtin_sub(size_t argc, AST** argv, Scope* parent);
// Multiply nums. // Multiply nums.
AST* builtin_mul(size_t argc, AST** argv); AST* builtin_mul(size_t argc, AST** argv, Scope* parent);
// Divide nums. // 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 { struct builtin_data {
char* name; char* name;
AST* (*fn)(size_t argc, AST** argv); AST* (*fn)(size_t argc, AST** argv, Scope* parent);
}; };
static struct builtin_data BUILTIN_FNS[] = { static struct builtin_data BUILTIN_FNS[] = {
@@ -25,6 +35,9 @@ static struct builtin_data BUILTIN_FNS[] = {
{ "sub", builtin_sub }, { "sub", builtin_sub },
{ "mul", builtin_mul }, { "mul", builtin_mul },
{ "div", builtin_div }, { "div", builtin_div },
{ "die", builtin_die },
{"_if", builtin_if},
{"eq", builtin_eq},
}; };
#define BUILTIN_FNS_LN (arrln(BUILTIN_FNS)) #define BUILTIN_FNS_LN (arrln(BUILTIN_FNS))

View File

@@ -2,25 +2,35 @@
#define EXEC_H #define EXEC_H
#include "ast.h" #include "ast.h"
#include "stack.h" #include "scope.h"
// Start executing at the root of the AST. Initialize the `scope`. // Start executing at the root of the AST. Initialize the `scope`.
AST* exec_start(AST* ast); AST* exec_start(AST* ast);
// Execute an expression. Delegates to the other executor functions. // 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. // Execute the expressions of a block.
AST* exec_block(AST* ast); AST* exec_block(AST* ast, Scope* parent);
// Execute a call. // Execute a call.
AST* exec_call(AST* ast); AST* exec_call(AST* ast, Scope* parent);
// Execute a custom function call. // Execute a definition.
AST* exec_cf(AST* ast, size_t argc, AST** argv); AST* exec_def(AST* ast, Scope* parent);
// Execute a variable reference. // Execute a reference.
AST* exec_vref(AST* ast); AST* exec_ref(AST* ast, Scope* parent);
// Execute a variable definition.
AST* exec_vdef(AST* ast);
// Execute a function definition. // 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. // Print the result of an execution.
void exec_print(double n); 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 #endif

32
src/include/gc.h Normal file
View 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

View File

@@ -5,15 +5,18 @@
// Represents the reverse linked tree of scope. // Represents the reverse linked tree of scope.
typedef struct SCOPE_T { typedef struct SCOPE_T {
HTab* here; HTab* here; // This scope's hash table.
struct SCOPE_T* inherit; struct SCOPE_T* inherit; // The scope to inherit from.
int uses; // How many `AST`s are linked to this scope. // TODO: REMOVE.
} Scope; } Scope;
// Create a new `Scope`. // Create a new `Scope`. Creates new empty `HTab` for current scope.
Scope* scope_init(HTab* here, Scope* inherit); Scope* scope_init(Scope* inherit);
// Destroy all linked `Scope`s this inherits from. // Destroy all linked `Scope`s this inherits from.
void scope_destroy(Scope* scope); void scope_destroy(Scope* scope);
// Destroy the current `Scope` only. // Destroy the current `Scope` only.
void scope_destroy_psv(Scope *scope); 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 #endif

View File

@@ -1,6 +1,8 @@
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
#include <signal.h>
// Most of this file is cursed printing macros for `ast_print()`. Do not attempt // Most of this file is cursed printing macros for `ast_print()`. Do not attempt
// to comprehend. // to comprehend.
@@ -10,6 +12,9 @@
// Get the length of an array. // Get the length of an array.
#define arrln(A) (sizeof(A)/sizeof(*A)) #define arrln(A) (sizeof(A)/sizeof(*A))
// Trap GDB &c.
#define TRAP() RAISE(SIGTRAP)
#ifdef DBG // Debug macros #ifdef DBG // Debug macros
// Log a message. // Log a message.

View File

@@ -3,6 +3,7 @@
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "include/dstr.h" #include "include/dstr.h"
#include "include/lexer.h" #include "include/lexer.h"
@@ -26,7 +27,7 @@ void argarr_destroy(ArgArr* argarr) {
void argarr_destroypsv(ArgArr* argarr) { free(argarr); } void argarr_destroypsv(ArgArr* argarr) { free(argarr); }
void argarr_add(ArgArr* argarr, AST* arg) { 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->sz *= 2;
argarr->buf = realloc(argarr->buf, argarr->sz); argarr->buf = realloc(argarr->buf, argarr->sz);
log_dbgf( log_dbgf(
@@ -72,7 +73,20 @@ double acc_float(int c) {
char* acc_word(int c) { char* acc_word(int c) {
Dstr* val = dstr_init(); 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)); dstr_appendch(val, *(inp - 1));
inp++; inp++;
} }
@@ -92,14 +106,27 @@ int yylex() {
// Assign & consume current character. // Assign & consume current character.
int c = *inp++; 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. // Check for NUM.
if (isdigit(c)) { if (isdigit(c)) {
yylval.fval = acc_float(c); // Set the token value. yylval.fval = acc_float(c); // Set the token value.
return NUM; return NUM;
} }
if (isalpha(c)) { if (isalpha(c) || c == '_') {
yylval.strval = acc_word(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; return WORD;
} }
@@ -115,7 +142,12 @@ int yylex() {
case ';': return EXPSEP; case ';': return EXPSEP;
case '{': return BLOCKS; case '{': return BLOCKS;
case '}': return BLOCKE; 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); default: fprintf(stderr, "Unexpected character: %c\n", c);
} }

View File

@@ -2,12 +2,11 @@
#include <string.h> #include <string.h>
#include "include/ast.h" #include "include/ast.h"
#include "include/ast_print.h"
#include "include/dstr.h" #include "include/dstr.h"
#include "include/exec.h" #include "include/exec.h"
#include "include/global.h" #include "include/gc.h"
#include "include/htab.h"
#include "include/lexer.h" #include "include/lexer.h"
#include "include/stack.h"
#include "include/util.h" #include "include/util.h"
#include "../build/grammars/grammar.tab.h" #include "../build/grammars/grammar.tab.h"
@@ -17,17 +16,16 @@ extern AST* root;
extern char* inp; extern char* inp;
extern int yyparse(); extern int yyparse();
Stack* scope;
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (argc - 1 && strlen(argv[1]) > 0 && (inp = argv[1]) && !yyparse()) { if (argc - 1 && strlen(argv[1]) > 0 && (inp = argv[1]) && !yyparse()) {
log_dbg("Parsed successfully!\n"); // log_dbg("Parsed successfully!\n");
ast_print(exec_start(root)); // ast_print(root);
HTab* global = stack_pop(scope); AST* eval = exec_start(root);
htab_destroy(global); ast_print(eval);
stack_destroy(scope); // ast_destroy(eval);
ast_destroy(root); // ast_destroy(root);
gc_hack_free();
exit(0); exit(0);
} }
@@ -56,18 +54,26 @@ int main(int argc, char** argv) {
inp = ln->buf; inp = ln->buf;
if (yyparse() == 0) { if (yyparse() == 0) {
log_dbg("Parsed successfully!\n"); log_dbg("Parsed successfully!\n");
} else printf("Parse error.\n"); } else {
printf("Parse error.\n");
dstr_destroy(ln);
continue;
}
#ifdef DBG #ifdef DBG
ast_print(root); ast_print(root);
#endif #endif
ast_print(exec_start(root)); AST* eval = exec_start(root);
HTab* global = stack_pop(scope); ast_print(eval);
htab_destroy(global); // Awful hack to exit when die() is called, until proper exception
stack_destroy(scope); // handling is implemented. TODO TODO TODO PLSFIX.
if (eval->type == AST_TYPE_EXC &&
ast_destroy(root); ((ASTExcData*)eval->data)->msg[0] == '8') {
gc_hack_free();
exit(1);
}
gc_hack_free();
} }
dstr_destroy(ln); dstr_destroy(ln);

View File

@@ -1,24 +1,37 @@
#include "include/scope.h" #include "include/scope.h"
#include "include/gc.h"
#include "include/htab.h" #include "include/htab.h"
#include "include/util.h"
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
Scope* scope_init(HTab* here, Scope* inherit) { Scope* scope_init(Scope* inherit) {
Scope* scope = malloc(sizeof(Scope)); Scope* scope = gc_alloc(sizeof(Scope), GC_TYPE_SCOPE);
scope->here = here; scope->here = htab_init();
scope->inherit = inherit; scope->inherit = inherit;
scope->uses = 0;
log_dbgf("%p: new scope, inherits from %p", scope, inherit);
return scope; return scope;
} }
void scope_destroy(Scope* scope) { void scope_destroy(Scope* scope) {
if (!scope) return;
htab_destroy(scope->here); htab_destroy(scope->here);
if (scope->inherit != NULL) scope_destroy(scope->inherit); if (scope->inherit != NULL) scope_destroy(scope->inherit);
free(scope); free(scope);
} }
void scope_destroy_psv(Scope* scope) { void scope_destroy_psv(Scope* scope) {
if (!scope) return;
log_dbgf("%p: destroying", scope);
htab_destroy(scope->here); htab_destroy(scope->here);
scope->inherit = NULL; scope->inherit = NULL;
free(scope); free(scope);
} }
inline void scope_add(Scope* scope, char* key, void* val) {
htab_ins(scope->here, key, val);
}

View File

@@ -1,5 +1,5 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h> // IWYU pragma: keep. Req by util macros.
#include <string.h> #include <string.h>
#include "include/stack.h" #include "include/stack.h"

View File

@@ -37,23 +37,8 @@ void test_ast_call() {
ast_destroy(ast); 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() { int main() {
UNITY_BEGIN(); 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
View 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`).