Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #13

Merged
merged 3 commits into from
Jul 21, 2024
Merged

Dev #13

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ BasedOnStyle: LLVM

AccessModifierOffset: -4
BreakBeforeBraces: Linux
ColumnLimit: 80
ColumnLimit: 0
IndentCaseLabels: true
IndentWidth: 4
SpaceBeforeCaseColon: false
Expand Down
34 changes: 21 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
> Some features will not work for a while (builtin functions, metamethods, C API).
> Pretty much everything is subject to change.
> See the [roadmap](#roadmap) to get an idea of where things are going.
> As far as the syntax examples go, just keep in mind that type inference is only implemented for function templates right now, so structure/enumerator/container literals will look pretty verbose.
> It should be possible to use a similar technique to infer these types.

An unobtrusive scripting language

Expand Down Expand Up @@ -67,8 +65,8 @@ let v = ['a', 'b', 'c']
let m = [1: 1, 2: 2]
let F = some_other_function

let b = 1 as bool // int -> bool
let i = 2 + 3.4 as int // float -> int
let b = 1 as bool
let i = 2 + 3.4 as int

struct Object {
value: int
Expand Down Expand Up @@ -99,6 +97,11 @@ fn fib(n: int) -> int {
return fib(n - 2) + fib(n - 1)
}
fib(10)

// use closure syntax to capture variables
let run_fib = || -> int {
return fib(5)
}
```

### Structures
Expand Down Expand Up @@ -147,7 +150,7 @@ break
continue

// Numeric 'for' loop:
for i in 0, 10, 2 { // start, end[, step]
for i = 0, 10, 2 { // start, end[, step]

}

Expand Down Expand Up @@ -184,7 +187,7 @@ Variables with generic types must be treated generically, that is, they can only
This allows each template to be type checked a single time, rather than once for each unique instantiation, and makes it easier to generate meaningful error messages.
```
fn map<A, B>(f: fn(A) -> B, vec: [A]) -> [B] {
let result: [B] = []
let result = []
for a in vec {
result.push(f(a))
}
Expand Down Expand Up @@ -235,16 +238,16 @@ let c = triplet.2
```
let empty: [int] = []

// infer T = string
let empty = []
empty.push('a')
empty.push('a')

let vec = [
[[1, 2, 3], [0]],
[[4, 5, 6], [1]],
[[7, 8, 9], [2]],
]

// infer T = int
let vec = [1, 2, 3]
assert(vec[:1] == [1])
assert(vec[1:-1] == [2])
Expand All @@ -255,10 +258,10 @@ assert(vec[-1:] == [3])
```
let empty: [int: string] = [:]

// infer K = int, V = string
let empty = [:]
empty[0] = 'abc'

// infer K = int, V = string
let map = [1: 'a', 2: 'b']
map[3] = 42
map.erase(1)
Expand Down Expand Up @@ -298,25 +301,30 @@ assert(status != 0)
|1 |`=` |Assignment |Right |

## Roadmap
+ [x] static typing
+ [x] static, string typing
+ [x] special-cased builtin containers (`[T]` and `[K: V]`)
+ [ ] type inference for ADT templates (including builtin containers)
+ [x] type inference for `struct` templates and builtin containers
+ [ ] methods using `impl` blocks
+ [ ] module system and `import` keyword
+ [ ] type inference for `enum` templates
+ [ ] pattern matching (`switch` construct)
+ [ ] pattern matching (`if let`, `let` bindings)
+ [ ] constness (`var` vs `let`)
+ [ ] split `string` into `str` and `String`, where `str` is a byte array and `String` is always valid UTF-8
+ [x] sum types/discriminated unions (`enum`)
+ [x] product types (tuple)
+ [ ] compiler optimization passes
+ [ ] custom garbage collector (using Boehm GC for now)
+ [ ] methods
+ [ ] metamethods
+ [ ] generic constraints/bounds
+ [ ] associated types on `struct`s (`A::B`)
+ [ ] existential types

## Known problems
+ The C API has pretty much 0 type safety
+ Compiler will allow functions that don't return a value in all code paths
+ Likely requires a CFG and some data flow analysis: it would be very difficult to get right otherwise
+ It isn't possible to create an empty vector or map of a given type without creating a temporary: `let vec: [int] = []`
+ It isn't possible to create an empty vector or map of a specific known type without creating a temporary: `let vec: [int] = []`
+ Could use Swift syntax, or something similar:
```
let empty_vec = [int]()
Expand Down
183 changes: 63 additions & 120 deletions src/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,83 +93,6 @@ void paw_close(paw_Env *P)
P->alloc(P->ud, P, sizeof *P, 0);
}

paw_Bool paw_is_bool(paw_Env *P, int index)
{
return paw_type(P, index) == PAW_TBOOL;
}

paw_Bool paw_is_int(paw_Env *P, int index)
{
return paw_type(P, index) == PAW_TINT;
}

paw_Bool paw_is_float(paw_Env *P, int index)
{
return paw_type(P, index) == PAW_TFLOAT;
}

paw_Bool paw_is_string(paw_Env *P, int index)
{
return paw_type(P, index) == PAW_TSTRING;
}

paw_Bool paw_is_function(paw_Env *P, int index)
{
return paw_type(P, index) == PAW_TFUNCTION;
}

paw_Bool paw_is_tuple(paw_Env *P, int index)
{
return paw_type(P, index) == PAW_TTUPLE;
}

paw_Bool paw_is_struct(paw_Env *P, int index)
{
return paw_type(P, index) == PAW_TSTRUCT;
}

paw_Bool paw_is_foreign(paw_Env *P, int index)
{
return paw_type(P, index) == PAW_TFOREIGN;
}

int paw_type(paw_Env *P, int index)
{
const Value v = *access(P, index);
return 0;
// switch (v_type(v)) {
// case VNULL:
// return PAW_NULL;
// case VTRUE:
// case VFALSE:
// return PAW_TBOOL;
// case VCLOSURE:
// case VMETHOD:
// case VNATIVE:
// return PAW_TFUNCTION;
// case VSTRING:
// return PAW_TSTRING;
// case VARRAY:
// return PAW_TARRAY;
// case VMAP:
// return PAW_TMAP;
// case VSTRUCT:
// return PAW_TSTRUCT;
// case VBIGINT:
// case VNUMBER:
// return PAW_TINT;
// case VFOREIGN:
// return PAW_TFOREIGN;
// default:
// return PAW_TFLOAT;
// }
}

const char *paw_typename(paw_Env *P, int index)
{
return api_typename(paw_type(P, index));
}

void paw_push_value(paw_Env *P, int index)
{
const Value v = *access(P, index);
Expand All @@ -183,11 +106,20 @@ void paw_push_unit(paw_Env *P, int n)
}
}

void paw_push_boolean(paw_Env *P, paw_Bool b) { pawC_pushb(P, b); }
void paw_push_boolean(paw_Env *P, paw_Bool b)
{
pawC_pushb(P, b);
}

void paw_push_float(paw_Env *P, paw_Float f) { pawC_pushf(P, f); }
void paw_push_float(paw_Env *P, paw_Float f)
{
pawC_pushf(P, f);
}

void paw_push_int(paw_Env *P, paw_Int i) { pawC_pushi(P, i); }
void paw_push_int(paw_Env *P, paw_Int i)
{
pawC_pushi(P, i);
}

void paw_push_native(paw_Env *P, paw_Function fn, int n)
{
Expand Down Expand Up @@ -234,9 +166,15 @@ const char *paw_push_fstring(paw_Env *P, const char *fmt, ...)
return s;
}

paw_Bool paw_bool(paw_Env *P, int index) { return v_true(*access(P, index)); }
paw_Bool paw_bool(paw_Env *P, int index)
{
return v_true(*access(P, index));
}

paw_Int paw_int(paw_Env *P, int index) { return v_int(*access(P, index)); }
paw_Int paw_int(paw_Env *P, int index)
{
return v_int(*access(P, index));
}

paw_Float paw_float(paw_Env *P, int index)
{
Expand Down Expand Up @@ -360,7 +298,10 @@ int paw_call(paw_Env *P, int argc)
return status;
}

int paw_get_count(paw_Env *P) { return P->top.p - P->cf->base.p; }
int paw_get_count(paw_Env *P)
{
return P->top.p - P->cf->base.p;
}

static int upvalue_index(int nup, int index)
{
Expand All @@ -372,35 +313,33 @@ static int upvalue_index(int nup, int index)
return index;
}

// void paw_get_upvalue(paw_Env *P, int ifn, int index)
//{
// Value *pv = pawC_push0(P);
// const Value fn = *access(P, ifn);
// switch (v_type(fn)) {
// case VNATIVE: {
// Native *f = v_native(fn);
// *pv = f->up[upvalue_index(f->nup, index)];
// break;
// }
// case VCLOSURE: {
// Closure *f = v_closure(fn);
// UpValue *u = f->up[upvalue_index(f->nup, index)];
// *pv = *u->p.p;
// break;
// }
// default:
// pawR_error(P, PAW_ETYPE, "'%s' has no upvalues",
// api_typename(api_type(fn)));
// }
// }
//
// void paw_get_global(paw_Env *P, const char *name)
//{
// if (!paw_check_global(P, name)) {
// pawR_error(P, PAW_ENAME, "global '%s' does not exist", name);
// }
// }
//
void paw_get_upvalue(paw_Env *P, int ifn, int index)
{
Value *pv = pawC_push0(P);
const Value fn = *access(P, ifn);
switch (v_object(fn)->gc_kind) {
case VNATIVE: {
Native *f = v_native(fn);
*pv = f->up[upvalue_index(f->nup, index)];
break;
}
case VCLOSURE: {
Closure *f = v_closure(fn);
UpValue *u = f->up[upvalue_index(f->nup, index)];
*pv = *u->p.p;
break;
}
default:
pawR_error(P, PAW_ETYPE, "type has no upvalues");
}
}

void paw_get_global(paw_Env *P, int index)
{
GlobalVar *var = pawE_get_global(P, index);
pawC_pushv(P, var->value);
}

// paw_Bool paw_check_global(paw_Env *P, const char *name)
//{
// paw_push_string(P, name);
Expand Down Expand Up @@ -499,6 +438,8 @@ static int upvalue_index(int nup, int index)
//
void paw_set_global(paw_Env *P, const char *name)
{
paw_unused(P);
paw_unused(name);
// paw_push_string(P, name);
// paw_rotate(P, -2, 1); // Swap
//
Expand Down Expand Up @@ -531,6 +472,8 @@ void paw_set_global(paw_Env *P, const char *name)
//
void paw_create_array(paw_Env *P, int n)
{
paw_unused(P);
paw_unused(n);
// pawR_literal_array(P, n);
}
//
Expand Down Expand Up @@ -615,13 +558,13 @@ void paw_shift(paw_Env *P, int n)
paw_pop(P, n);
}

// void paw_call_global(paw_Env *P, const char *name, int argc)
//{
// paw_get_global(P, name);
// paw_insert(P, -argc - 2);
// paw_call(P, argc);
// }
//
void paw_call_global(paw_Env *P, int index, int argc)
{
paw_get_global(P, index);
paw_insert(P, -argc - 2);
paw_call(P, argc);
}

// void paw_call_attr(paw_Env *P, int index, const char *name, int argc)
//{
// paw_push_value(P, index);
Expand All @@ -644,6 +587,6 @@ void paw_raw_equals(paw_Env *P)
{
const Value x = P->top.p[-2];
const Value y = P->top.p[-1];
// paw_push_boolean(P, pawV_equal(x, y));
paw_push_boolean(P, x.u == y.u);
paw_shift(P, 2);
}
Loading
Loading