Compare commits
4 Commits
master
...
7c08e8da4d
Author | SHA1 | Date | |
---|---|---|---|
7c08e8da4d | |||
fdf526750d | |||
b102a32999 | |||
518f2e9803 |
39
README.md
39
README.md
@@ -1,20 +1,20 @@
|
|||||||
# SCL: Simple CAS Language
|
# SCL: Simple CAS Language
|
||||||
|
|
||||||
*v0.3*
|
Version 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 functional programming language capable
|
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
|
of performing simple arithmetic. The codebase is about 2,000 lines of C,
|
||||||
handwritten C, including a parser, interpreter, and runtime. It uses a linked
|
including a parser, interpreter, and runtime. It uses a linked environment
|
||||||
environment scoping model.
|
scoping model.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
To download and run:
|
To download and run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://git.signorovitch.org/scl/scl -b stable && cd scl
|
git clone https://git.signorovitch.org/jacob/scl -b stable && cd scl
|
||||||
make release
|
make release
|
||||||
./scl.out
|
./scl.out
|
||||||
```
|
```
|
||||||
@@ -22,25 +22,35 @@ make release
|
|||||||
### For Development
|
### For Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone git@signorovitch.org:scl/scl --recurse-submodules && cd scl
|
git clone git@signorovitch.org:jacob/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
|
||||||
|
|
||||||
SCL's syntax will feel familiar to other functional programming languages.
|
As one would expect, you can evaluate simple infix expressions:
|
||||||
|
|
||||||
```scl
|
```scl
|
||||||
> x = 3 + 3 * 3; x + 1
|
> 1 + 1
|
||||||
= 13
|
|
||||||
> f(x) x + 1
|
|
||||||
> f(1)
|
|
||||||
= 2
|
= 2
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also define your own functions and variables:
|
||||||
|
|
||||||
|
```scl
|
||||||
|
> f(x) 2 * x
|
||||||
|
> n = 3
|
||||||
|
> f(n)
|
||||||
|
= 6
|
||||||
|
```
|
||||||
|
|
||||||
|
Being a functional programming language at heart, one can of course use lambda functions:
|
||||||
|
|
||||||
|
```scl
|
||||||
> (\(x) 2 * x)(5)
|
> (\(x) 2 * x)(5)
|
||||||
= 10
|
= 10
|
||||||
> f(g) g(2)
|
> f(g) g(2)
|
||||||
@@ -48,7 +58,7 @@ SCL's syntax will feel familiar to other functional programming languages.
|
|||||||
= 4
|
= 4
|
||||||
```
|
```
|
||||||
|
|
||||||
Here's a simple factorial function, using recursion:
|
Here's a simple factorial function:
|
||||||
|
|
||||||
```scl
|
```scl
|
||||||
> factorial(n) {
|
> factorial(n) {
|
||||||
@@ -57,8 +67,7 @@ Here's a simple factorial function, using recursion:
|
|||||||
> }
|
> }
|
||||||
```
|
```
|
||||||
|
|
||||||
SCL's syntax is quite flexible. The above function could be more concisely
|
Or, using SCL's more concise syntax:
|
||||||
written as:
|
|
||||||
|
|
||||||
```scl
|
```scl
|
||||||
> factorial(n) ? n == 0 1 n * factorial(n - 1)
|
> factorial(n) ? n == 0 1 n * factorial(n - 1)
|
||||||
|
@@ -19,13 +19,13 @@
|
|||||||
- [ ] 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
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
- [ ] 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
|
||||||
|
45
src/ast.c
45
src/ast.c
@@ -39,17 +39,16 @@ 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_BOOL: ast_bool_data_destroy(ast->data); break;
|
case AST_TYPE_LIT_BOOL: ast_bool_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_VREF: ast_vref_data_destroy(ast->data); break;
|
||||||
case AST_TYPE_VDEF: ast_vdef_data_destroy(ast->data); break;
|
case AST_TYPE_VDEF: ast_vdef_data_destroy(ast->data); break;
|
||||||
case AST_TYPE_BLOCK: ast_block_data_destroy_psv(ast->data); break;
|
case AST_TYPE_BLOCK: ast_block_data_destroy_psv(ast->data); break;
|
||||||
case AST_TYPE_FDEF: ast_fdef_data_destroy_psv(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_BIF: ast_bif_data_destroy(ast->data); break;
|
case AST_TYPE_EXC: ast_exc_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_LAMBDA: ast_lambda_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);
|
||||||
}
|
}
|
||||||
@@ -182,30 +181,6 @@ void ast_block_data_destroy_psv(ASTBlockData* block) {
|
|||||||
free(block);
|
free(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
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_data_destroy_psv(ASTFDefData* fdef) {
|
|
||||||
free(fdef->name);
|
|
||||||
free(fdef->argv);
|
|
||||||
free(fdef);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
|
@@ -7,13 +7,13 @@
|
|||||||
|
|
||||||
static char* asttype_names[] = {
|
static char* asttype_names[] = {
|
||||||
[AST_TYPE_CALL] = "FUNC CALL",
|
[AST_TYPE_CALL] = "FUNC CALL",
|
||||||
[AST_TYPE_NUM] = "NUMBER",
|
[AST_TYPE_LIT_NUM] = "NUMBER",
|
||||||
[AST_TYPE_BOOL] = "BOOLEAN",
|
[AST_TYPE_LIT_BOOL] = "BOOLEAN",
|
||||||
|
[AST_TYPE_LIT_KIND] = "KIND",
|
||||||
[AST_TYPE_VREF] = "VAR REFERENCE",
|
[AST_TYPE_VREF] = "VAR REFERENCE",
|
||||||
[AST_TYPE_VDEF] = "VAR DEFINITION",
|
[AST_TYPE_VDEF] = "VAR DEFINITION",
|
||||||
[AST_TYPE_BLOCK] = "BLOCK",
|
[AST_TYPE_BLOCK] = "BLOCK",
|
||||||
[AST_TYPE_EXC] = "EXCEPTION",
|
[AST_TYPE_EXC] = "EXCEPTION",
|
||||||
[AST_TYPE_FDEF] = "FUNCTION DEFINITION",
|
|
||||||
[AST_TYPE_ARG] = "DEFINITION ARGUMENT",
|
[AST_TYPE_ARG] = "DEFINITION ARGUMENT",
|
||||||
[AST_TYPE_LAMBDA] = "LAMBDA EXPRESSION",
|
[AST_TYPE_LAMBDA] = "LAMBDA EXPRESSION",
|
||||||
[AST_TYPE_BIF] = "BUILTIN FUNCTION"
|
[AST_TYPE_BIF] = "BUILTIN FUNCTION"
|
||||||
@@ -31,10 +31,10 @@ void ast_print_i(AST* ast, int i) {
|
|||||||
INDENT_FIELD("type", "%s", asttype_names[ast->type]);
|
INDENT_FIELD("type", "%s", asttype_names[ast->type]);
|
||||||
INDENT_FIELD_EXT_NONL_START("data");
|
INDENT_FIELD_EXT_NONL_START("data");
|
||||||
switch (ast->type) {
|
switch (ast->type) {
|
||||||
case AST_TYPE_NUM:
|
case AST_TYPE_LIT_NUM:
|
||||||
printf("%s %lf\n", INDENT_spacing->buf, *(ASTNumData*)ast->data);
|
printf("%s %lf\n", INDENT_spacing->buf, *(ASTNumData*)ast->data);
|
||||||
break;
|
break;
|
||||||
case AST_TYPE_BOOL:
|
case AST_TYPE_LIT_BOOL:
|
||||||
printf(
|
printf(
|
||||||
"%s %s\n", INDENT_spacing->buf,
|
"%s %s\n", INDENT_spacing->buf,
|
||||||
*(ASTBoolData*)ast->data ? "true" : "false"
|
*(ASTBoolData*)ast->data ? "true" : "false"
|
||||||
@@ -45,7 +45,6 @@ void ast_print_i(AST* ast, int i) {
|
|||||||
case AST_TYPE_VREF: ast_vref_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_VDEF: ast_vdef_print(ast->data, i + 2); break;
|
||||||
case AST_TYPE_BLOCK: ast_block_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;
|
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_LAMBDA: ast_lambda_print(ast->data, i + 2); break;
|
||||||
case AST_TYPE_BIF: ast_bif_print(ast->data, i + 2); break;
|
case AST_TYPE_BIF: ast_bif_print(ast->data, i + 2); break;
|
||||||
@@ -128,18 +127,6 @@ void ast_block_print(ASTBlockData* data, int depth) {
|
|||||||
|
|
||||||
INDENT_END;
|
INDENT_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
INDENT_END;
|
|
||||||
}
|
|
||||||
void ast_arg_print(ASTArgData* arg, int i) {
|
void ast_arg_print(ASTArgData* arg, int i) {
|
||||||
INDENT_BEGIN(i);
|
INDENT_BEGIN(i);
|
||||||
INDENT_TITLE("ASTArgData", arg);
|
INDENT_TITLE("ASTArgData", arg);
|
||||||
|
@@ -15,7 +15,7 @@ AST* builtin_sum(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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,11 +24,11 @@ AST* builtin_sum(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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, Scope* parent) {
|
AST* builtin_sub(size_t argc, AST** argv, Scope* parent) {
|
||||||
if (argc <= 0) return ast_init(AST_TYPE_NUM, ast_num_data_init(0));
|
if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0));
|
||||||
|
|
||||||
AST* first = exec_exp(*argv, parent);
|
AST* first = exec_exp(*argv, parent);
|
||||||
if (first->type == AST_TYPE_EXC)
|
if (first->type == AST_TYPE_EXC)
|
||||||
@@ -36,7 +36,7 @@ AST* builtin_sub(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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)
|
||||||
@@ -51,7 +51,7 @@ AST* builtin_sub(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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)
|
||||||
@@ -60,11 +60,11 @@ AST* builtin_sub(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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, Scope* parent) {
|
AST* builtin_mul(size_t argc, AST** argv, Scope* parent) {
|
||||||
if (argc <= 0) return ast_init(AST_TYPE_NUM, ast_num_data_init(0));
|
if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0));
|
||||||
|
|
||||||
AST* first = exec_exp(*argv, parent);
|
AST* first = exec_exp(*argv, parent);
|
||||||
if (first->type == AST_TYPE_EXC)
|
if (first->type == AST_TYPE_EXC)
|
||||||
@@ -72,7 +72,7 @@ AST* builtin_mul(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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)
|
||||||
@@ -87,7 +87,7 @@ AST* builtin_mul(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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)
|
||||||
@@ -96,11 +96,11 @@ AST* builtin_mul(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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, Scope* parent) {
|
AST* builtin_div(size_t argc, AST** argv, Scope* parent) {
|
||||||
if (argc <= 0) return ast_init(AST_TYPE_NUM, ast_num_data_init(0));
|
if (argc <= 0) return ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(0));
|
||||||
|
|
||||||
AST* first = exec_exp(*argv, parent);
|
AST* first = exec_exp(*argv, parent);
|
||||||
if (first->type == AST_TYPE_EXC)
|
if (first->type == AST_TYPE_EXC)
|
||||||
@@ -108,7 +108,7 @@ AST* builtin_div(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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)
|
||||||
@@ -123,7 +123,7 @@ AST* builtin_div(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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)
|
||||||
@@ -132,7 +132,7 @@ AST* builtin_div(size_t argc, AST** argv, Scope* parent) {
|
|||||||
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) {
|
AST* builtin_die(size_t argc, AST** argv, Scope* parent) {
|
||||||
@@ -150,7 +150,7 @@ AST* builtin_if(size_t argc, AST** argv, Scope* parent) {
|
|||||||
AST* body = argv[1];
|
AST* body = argv[1];
|
||||||
AST* alt = argv[2];
|
AST* alt = argv[2];
|
||||||
|
|
||||||
if (pred->type != AST_TYPE_BOOL) {
|
if (pred->type != AST_TYPE_LIT_BOOL) {
|
||||||
if (pred->type == AST_TYPE_EXC) {
|
if (pred->type == AST_TYPE_EXC) {
|
||||||
return ast_init(
|
return ast_init(
|
||||||
AST_TYPE_EXC, ast_exc_data_init("if touched an error", pred)
|
AST_TYPE_EXC, ast_exc_data_init("if touched an error", pred)
|
||||||
@@ -169,7 +169,8 @@ AST* builtin_if(size_t argc, AST** argv, Scope* parent) {
|
|||||||
|
|
||||||
AST* builtin_eq(size_t argc, AST** argv, Scope* 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));
|
if (argc < 1) return ast_init(AST_TYPE_EXC, ast_exc_data_init("bad", NULL));
|
||||||
else if (argc == 1) return ast_init(AST_TYPE_BOOL, ast_bool_data_init(1));
|
else if (argc == 1)
|
||||||
|
return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(1));
|
||||||
|
|
||||||
AST* first = exec_exp(argv[0], parent);
|
AST* first = exec_exp(argv[0], parent);
|
||||||
ASTType type = first->type;
|
ASTType type = first->type;
|
||||||
@@ -194,17 +195,17 @@ AST* builtin_eq(size_t argc, AST** argv, Scope* parent) {
|
|||||||
// delegated to each type. For now this works.
|
// delegated to each type. For now this works.
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AST_TYPE_NUM:
|
case AST_TYPE_LIT_NUM:
|
||||||
if (*(ASTNumData*)first->data == *(ASTNumData*)second->data)
|
if (*(ASTNumData*)first->data == *(ASTNumData*)second->data)
|
||||||
return ast_init(AST_TYPE_BOOL, ast_bool_data_init(1));
|
return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(1));
|
||||||
else return ast_init(AST_TYPE_BOOL, ast_bool_data_init(0));
|
else return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(0));
|
||||||
case AST_TYPE_BOOL:
|
case AST_TYPE_LIT_BOOL:
|
||||||
if (*(ASTNumData*)first->data == *(ASTNumData*)second->data)
|
if (*(ASTNumData*)first->data == *(ASTNumData*)second->data)
|
||||||
return ast_init(AST_TYPE_BOOL, ast_bool_data_init(1));
|
return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(1));
|
||||||
else return ast_init(AST_TYPE_BOOL, ast_bool_data_init(0));
|
else return ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(0));
|
||||||
default:
|
default:
|
||||||
return ast_init(
|
return ast_init(
|
||||||
AST_TYPE_BOOL, ast_bool_data_init(0)
|
AST_TYPE_LIT_BOOL, ast_bool_data_init(0)
|
||||||
); // Can't equate nonprimatives. I think. Maybe.
|
); // Can't equate nonprimatives. I think. Maybe.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
src/exec.c
23
src/exec.c
@@ -34,17 +34,16 @@ AST* exec_exp(AST* ast, Scope* parent) {
|
|||||||
switch (ast->type) {
|
switch (ast->type) {
|
||||||
case AST_TYPE_BLOCK: return exec_block(ast, parent);
|
case AST_TYPE_BLOCK: return exec_block(ast, parent);
|
||||||
case AST_TYPE_CALL: return exec_call(ast, parent);
|
case AST_TYPE_CALL: return exec_call(ast, parent);
|
||||||
case AST_TYPE_NUM:
|
case AST_TYPE_LIT_NUM:
|
||||||
return ast_init(
|
return ast_init(
|
||||||
AST_TYPE_NUM, ast_num_data_init(*(ASTNumData*)ast->data)
|
AST_TYPE_LIT_NUM, ast_num_data_init(*(ASTNumData*)ast->data)
|
||||||
);
|
);
|
||||||
case AST_TYPE_BOOL:
|
case AST_TYPE_LIT_BOOL:
|
||||||
return ast_init(
|
return ast_init(
|
||||||
AST_TYPE_BOOL, ast_bool_data_init(*(ASTBoolData*)ast->data)
|
AST_TYPE_LIT_BOOL, ast_bool_data_init(*(ASTBoolData*)ast->data)
|
||||||
);
|
);
|
||||||
case AST_TYPE_VREF: return exec_vref(ast, parent);
|
case AST_TYPE_VREF: return exec_vref(ast, parent);
|
||||||
case AST_TYPE_VDEF: return exec_vdef(ast, parent);
|
case AST_TYPE_VDEF: return exec_vdef(ast, parent);
|
||||||
case AST_TYPE_FDEF: return exec_fdef(ast, parent);
|
|
||||||
case AST_TYPE_BIF:
|
case AST_TYPE_BIF:
|
||||||
case AST_TYPE_LAMBDA: return ast;
|
case AST_TYPE_LAMBDA: return ast;
|
||||||
default: printf("what\n"); exit(1);
|
default: printf("what\n"); exit(1);
|
||||||
@@ -71,8 +70,9 @@ AST* exec_call(AST* ast, Scope* parent) {
|
|||||||
|
|
||||||
switch (exp->type) {
|
switch (exp->type) {
|
||||||
case AST_TYPE_BIF:
|
case AST_TYPE_BIF:
|
||||||
ASTBIFData bifdata = exp->data;
|
return ((ASTBIFData) exp->data)(
|
||||||
return bifdata(calldata->argc, calldata->argv, parent);
|
calldata->argc, calldata->argv, parent
|
||||||
|
);
|
||||||
case AST_TYPE_LAMBDA:
|
case AST_TYPE_LAMBDA:
|
||||||
return exec_lambda(calldata->argc, calldata->argv, exp, parent);
|
return exec_lambda(calldata->argc, calldata->argv, exp, parent);
|
||||||
default:
|
default:
|
||||||
@@ -115,15 +115,6 @@ AST* exec_vref(AST* ast, Scope* parent) {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST* exec_fdef(AST* ast, Scope* parent) {
|
|
||||||
ast->scope = scope_init(parent);
|
|
||||||
ASTFDefData* fdef = (ASTFDefData*)ast->data;
|
|
||||||
AST* val = ast;
|
|
||||||
char* key = fdef->name;
|
|
||||||
scope_add(parent, key, val);
|
|
||||||
return fdef->body; // Function definitions return function body.
|
|
||||||
}
|
|
||||||
|
|
||||||
AST* exec_lambda(size_t argc, AST** argv, AST* exp, Scope* parent) {
|
AST* exec_lambda(size_t argc, AST** argv, AST* exp, Scope* parent) {
|
||||||
Scope* callscope = scope_init(parent);
|
Scope* callscope = scope_init(parent);
|
||||||
ASTLambdaData* lambda = (ASTLambdaData*)exp->data;
|
ASTLambdaData* lambda = (ASTLambdaData*)exp->data;
|
||||||
|
@@ -134,10 +134,10 @@ block:
|
|||||||
|
|
||||||
exp:
|
exp:
|
||||||
// Number.
|
// Number.
|
||||||
NUM { $$ = ast_init(AST_TYPE_NUM, ast_num_data_init($1)); }
|
NUM { $$ = ast_init(AST_TYPE_LIT_NUM, ast_num_data_init($1)); }
|
||||||
|
|
||||||
| BOOLT { $$ = ast_init(AST_TYPE_BOOL, ast_bool_data_init(1)); }
|
| BOOLT { $$ = ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(1)); }
|
||||||
| BOOLF { $$ = ast_init(AST_TYPE_BOOL, ast_bool_data_init(0)); }
|
| BOOLF { $$ = ast_init(AST_TYPE_LIT_BOOL, ast_bool_data_init(0)); }
|
||||||
|
|
||||||
| exp DEQ exp {
|
| exp DEQ exp {
|
||||||
AST** argv = calloc(2, sizeof(AST*));
|
AST** argv = calloc(2, sizeof(AST*));
|
||||||
@@ -245,7 +245,7 @@ exp:
|
|||||||
// Negative.
|
// Negative.
|
||||||
| SUB exp {
|
| SUB exp {
|
||||||
AST** argv = calloc(2, sizeof(AST*));
|
AST** argv = calloc(2, sizeof(AST*));
|
||||||
argv[0] = ast_init(AST_TYPE_NUM, ast_num_data_init(-1));
|
argv[0] = ast_init(AST_TYPE_LIT_NUM, ast_num_data_init(-1));
|
||||||
argv[1] = $2;
|
argv[1] = $2;
|
||||||
$$ = ast_init(AST_TYPE_CALL,
|
$$ = ast_init(AST_TYPE_CALL,
|
||||||
ast_call_data_init(
|
ast_call_data_init(
|
||||||
|
@@ -6,11 +6,12 @@
|
|||||||
|
|
||||||
// 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_LIT_KIND, // A kind literal.
|
||||||
|
|
||||||
AST_TYPE_INT, // An integer.
|
AST_TYPE_INT, // An integer.
|
||||||
AST_TYPE_BOOL, // A boolean.
|
|
||||||
AST_TYPE_SYM, // A symbol.
|
AST_TYPE_SYM, // A symbol.
|
||||||
AST_TYPE_EXC, // Exception.
|
AST_TYPE_EXC, // Exception.
|
||||||
|
|
||||||
@@ -24,7 +25,6 @@ typedef enum {
|
|||||||
AST_TYPE_VDEF, // A variable definition.
|
AST_TYPE_VDEF, // A variable definition.
|
||||||
AST_TYPE_VREF, // A variable reference.
|
AST_TYPE_VREF, // A variable reference.
|
||||||
AST_TYPE_BLOCK, // A block of code (scope).
|
AST_TYPE_BLOCK, // A block of code (scope).
|
||||||
AST_TYPE_FDEF, // A function definition.
|
|
||||||
AST_TYPE_LAMBDA, // An anonymous function definition.
|
AST_TYPE_LAMBDA, // An anonymous function definition.
|
||||||
AST_TYPE_ARG, // A definition argument.
|
AST_TYPE_ARG, // A definition argument.
|
||||||
AST_TYPE_MAX = AST_TYPE_ARG,
|
AST_TYPE_MAX = AST_TYPE_ARG,
|
||||||
@@ -60,6 +60,12 @@ ASTBoolData* ast_bool_data_init(int val);
|
|||||||
// Destroy an `ASTBoolData`.
|
// Destroy an `ASTBoolData`.
|
||||||
void ast_bool_data_destroy(ASTBoolData* bol);
|
void ast_bool_data_destroy(ASTBoolData* bol);
|
||||||
|
|
||||||
|
// A kind.
|
||||||
|
typedef struct {
|
||||||
|
char* name;
|
||||||
|
|
||||||
|
} ASTKindData;
|
||||||
|
|
||||||
// An exception.
|
// An exception.
|
||||||
typedef struct ASTEXCDATA {
|
typedef struct ASTEXCDATA {
|
||||||
const char* msg; // The exception message.
|
const char* msg; // The exception message.
|
||||||
@@ -148,19 +154,6 @@ void ast_block_data_destroy(ASTBlockData* block);
|
|||||||
// Destroy an `ASTBlockData`.
|
// Destroy an `ASTBlockData`.
|
||||||
void ast_block_data_destroy_psv(ASTBlockData* block);
|
void ast_block_data_destroy_psv(ASTBlockData* block);
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char* name; // Function name.
|
|
||||||
ARGS; // Function args.
|
|
||||||
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`, recursively.
|
|
||||||
void ast_fdef_data_destroy(ASTFDefData* fdef);
|
|
||||||
// Destroy an `ASTFDefData`.
|
|
||||||
void ast_fdef_data_destroy_psv(ASTFDefData* fdef);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* name; // Argument name.
|
char* name; // Argument name.
|
||||||
} ASTArgData;
|
} ASTArgData;
|
||||||
|
@@ -29,9 +29,6 @@ void ast_vref_print(ASTVrefData*, int i);
|
|||||||
// Print an `ASTBlockData`.
|
// Print an `ASTBlockData`.
|
||||||
void ast_block_print(ASTBlockData*, int i);
|
void ast_block_print(ASTBlockData*, int i);
|
||||||
|
|
||||||
// Print an `ASTFDefData`.
|
|
||||||
void ast_fdef_print(ASTFDefData* fdef, int i);
|
|
||||||
|
|
||||||
// Print an `ASTArgData`.
|
// Print an `ASTArgData`.
|
||||||
void ast_arg_print(ASTArgData* arg, int i);
|
void ast_arg_print(ASTArgData* arg, int i);
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
#define GC_H
|
#define GC_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
// The type a GC can refer to.
|
// The type a GC can refer to.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@@ -1,21 +0,0 @@
|
|||||||
Primitive Types
|
|
||||||
- num
|
|
||||||
- bool
|
|
||||||
- str
|
|
||||||
|
|
||||||
```
|
|
||||||
fact(x) = ? (x <= 1) 1 : f(x-1) * x
|
|
||||||
> lambda
|
|
||||||
fact(5) == 120
|
|
||||||
> True
|
|
||||||
```
|
|
||||||
|
|
||||||
Ordered collections.
|
|
||||||
| Name | Homogeneous | Fixed Size | Unique |
|
|
||||||
|---|---|---|---|
|
|
||||||
| Collection | No | No | No |
|
|
||||||
| List | Yes | No | No |
|
|
||||||
| Array | Yes | Yes | No |
|
|
||||||
| Group | No | Yes | No |
|
|
||||||
| Set | Yes | No | Yes |
|
|
||||||
| Perm | Yes | Yes | Yes |
|
|
Reference in New Issue
Block a user