mirror of
https://github.com/ProgramSnail/Lama.git
synced 2025-12-13 10:18:47 +00:00
256 lines
5.7 KiB
C
256 lines
5.7 KiB
C
|
|
#pragma once
|
||
|
|
|
||
|
|
#include "../../runtime/runtime.h"
|
||
|
|
#include "types.h"
|
||
|
|
|
||
|
|
#include <cstdlib>
|
||
|
|
|
||
|
|
// TODO: use gc
|
||
|
|
|
||
|
|
// ------ general ------
|
||
|
|
|
||
|
|
// TODO: use gc
|
||
|
|
inline void free_var_ptr(union VarT *var);
|
||
|
|
|
||
|
|
inline void free_var(union VarT var) {
|
||
|
|
switch (dh_type(var.nil.data_header)) {
|
||
|
|
case NIL_T:
|
||
|
|
break;
|
||
|
|
case INT_T:
|
||
|
|
break;
|
||
|
|
case CONST_STR_T:
|
||
|
|
break;
|
||
|
|
case STR_T:
|
||
|
|
free(var.str.value);
|
||
|
|
break;
|
||
|
|
case LIST_T:
|
||
|
|
if (var.list.value != NULL) {
|
||
|
|
free_var_ptr(to_var(var.list.value));
|
||
|
|
}
|
||
|
|
if (var.list.next != NULL) {
|
||
|
|
free_var_ptr(to_var(var.list.next));
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case ARRAY_T:
|
||
|
|
// dh param is size
|
||
|
|
for (size_t i = 0; i < dh_param(var.array.data_header); ++i) {
|
||
|
|
free_var_ptr(to_var(var.array.values[i]));
|
||
|
|
}
|
||
|
|
free(var.array.values);
|
||
|
|
break;
|
||
|
|
case SEXP_T:
|
||
|
|
// tag is const string, no need to free
|
||
|
|
if (var.sexp.next != NULL) {
|
||
|
|
free(var.sexp.next);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FUN_T:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TODO: use gc
|
||
|
|
inline void free_var_ptr(union VarT *var) {
|
||
|
|
free_var(*var);
|
||
|
|
free((void *)var);
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
|
||
|
|
inline NilT clear_var() { return NilT{.data_header = NIL_T}; }
|
||
|
|
|
||
|
|
// usually not required, because frame is located on shared stack
|
||
|
|
inline struct Frame clear_frame() {
|
||
|
|
struct Frame frame = {
|
||
|
|
.ret_ip = NULL,
|
||
|
|
.rp = NULL,
|
||
|
|
.ret = NULL,
|
||
|
|
.params = NULL,
|
||
|
|
.locals = NULL,
|
||
|
|
.end = NULL,
|
||
|
|
};
|
||
|
|
return frame;
|
||
|
|
}
|
||
|
|
|
||
|
|
// TODO: not required ??
|
||
|
|
// inline struct Var deep_copy_var(struct Var var) {
|
||
|
|
// switch (var.type) {
|
||
|
|
// case INT_T:
|
||
|
|
// break;
|
||
|
|
// case CONST_STR_T:
|
||
|
|
// break;
|
||
|
|
// case STR_T: {
|
||
|
|
// char *old_str = var.value.str_v;
|
||
|
|
// var.value.str_v = calloc(var.size + 1, sizeof(char));
|
||
|
|
// strcpy(var.value.str_v, old_str);
|
||
|
|
// break;
|
||
|
|
// }
|
||
|
|
// case LIST_T:
|
||
|
|
// if (var.value.list_v.elem != NULL) {
|
||
|
|
// struct Var *old_elem = var.value.list_v.elem;
|
||
|
|
// var.value.list_v.elem = calloc(1, sizeof(struct Var));
|
||
|
|
// *var.value.list_v.elem = deep_copy_var(*old_elem);
|
||
|
|
// }
|
||
|
|
// if (var.value.list_v.next != NULL) {
|
||
|
|
// struct Var *old_next = var.value.list_v.next;
|
||
|
|
// var.value.list_v.next = calloc(1, sizeof(struct Var));
|
||
|
|
// *var.value.list_v.next = deep_copy_var(*old_next);
|
||
|
|
// }
|
||
|
|
// break;
|
||
|
|
// case ARRAY_T: {
|
||
|
|
// struct Var *old_array = var.value.array_v;
|
||
|
|
// var.value.array_v = calloc(var.size, sizeof(char));
|
||
|
|
// for (size_t i = 0; i < var.size; ++i) {
|
||
|
|
// var.value.array_v[i] = deep_copy_var(*(old_array + i));
|
||
|
|
// }
|
||
|
|
// break;
|
||
|
|
// }
|
||
|
|
// case FUN_T:
|
||
|
|
// break;
|
||
|
|
// case NIL_T:
|
||
|
|
// break;
|
||
|
|
// }
|
||
|
|
|
||
|
|
// return var;
|
||
|
|
// }
|
||
|
|
|
||
|
|
// ------ put on stack ---
|
||
|
|
|
||
|
|
inline void s_put_var(struct State *s, struct NilT *val) { // any var
|
||
|
|
*s->vp = val;
|
||
|
|
++s->vp;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void s_put_nil(struct State *s) {
|
||
|
|
struct NilT *var = alloc();
|
||
|
|
var->data_header = NIL_T; // no param
|
||
|
|
s_put_var(s, var);
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void s_putn_nil(struct State *s, size_t n) {
|
||
|
|
for (size_t i = 0; i < n; ++i) {
|
||
|
|
s_put_nil(s);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void s_put_i(struct State *s, int val) {
|
||
|
|
struct IntT *var = alloc();
|
||
|
|
var->data_header = INT_T; // no param
|
||
|
|
var->value = val;
|
||
|
|
s_put_var(s, (NilT *)var);
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void s_put_const_str(struct State *s,
|
||
|
|
const char *val) { // memory controlled externally
|
||
|
|
struct ConstStrT *var = alloc();
|
||
|
|
var->data_header = CONST_STR_T; // no param
|
||
|
|
var->value = val;
|
||
|
|
s_put_var(s, (NilT *)var);
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void s_put_str(struct State *s, char *val) { // memory controlled by var
|
||
|
|
struct StrT *var = alloc();
|
||
|
|
var->data_header = STR_T; // no param
|
||
|
|
var->value = val;
|
||
|
|
s_put_var(s, (NilT *)var);
|
||
|
|
}
|
||
|
|
|
||
|
|
// TODO
|
||
|
|
inline void s_put_array(struct State *s, int sz) { // memory controlled by var
|
||
|
|
struct Var var = {
|
||
|
|
.type = ARRAY_T,
|
||
|
|
.value.array_v = calloc(sz, sizeof(struct Var)),
|
||
|
|
.size = sz,
|
||
|
|
};
|
||
|
|
s_put_var(s, var);
|
||
|
|
|
||
|
|
// fill array with nils ?
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void s_put_list(struct State *s,
|
||
|
|
struct NilT *first_elem) { // memory controlled by var
|
||
|
|
struct ListT *var;
|
||
|
|
var->data_header = LIST_T; // no param
|
||
|
|
var->value = first_elem;
|
||
|
|
var->next = NULL;
|
||
|
|
|
||
|
|
s_put_var(s, (NilT *)var);
|
||
|
|
|
||
|
|
*first_elem = clear_var();
|
||
|
|
}
|
||
|
|
|
||
|
|
// ------ take from stack ------
|
||
|
|
|
||
|
|
inline union VarT *s_take_var(struct State *s) {
|
||
|
|
if (s->vp == s->fp->end) {
|
||
|
|
failure("take: no var");
|
||
|
|
}
|
||
|
|
--s->vp;
|
||
|
|
|
||
|
|
union VarT *ret = *s->vp;
|
||
|
|
*s->vp = NULL; // clear top var
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline int s_take_i(struct State *s) {
|
||
|
|
union VarT *v = s_take_var(s);
|
||
|
|
if (dh_type(v->nil.data_header) != INT_T) {
|
||
|
|
failure("take int: not int");
|
||
|
|
}
|
||
|
|
return v->int_t.value;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void s_drop_var(struct State *s) {
|
||
|
|
if (s->vp == s->fp->end) {
|
||
|
|
failure("drop: no var");
|
||
|
|
}
|
||
|
|
--s->vp;
|
||
|
|
free_var_ptr(*s->vp);
|
||
|
|
*s->vp = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void s_dropn_var(struct State *s, size_t n) {
|
||
|
|
for (size_t i = 0; i < n; ++i) {
|
||
|
|
s_drop_var(s);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ------ functions ------
|
||
|
|
|
||
|
|
// TODO
|
||
|
|
inline void s_exit_f(struct State *s) {
|
||
|
|
if (s->fp == (void *)s->stack) {
|
||
|
|
failure("exit: no func");
|
||
|
|
}
|
||
|
|
--s->fp;
|
||
|
|
s_dropn_var(s, s->vp - s->fp->locals);
|
||
|
|
// drop local var stack and locals // TODO: check +-1
|
||
|
|
union VarT *ret = *s->vp;
|
||
|
|
--s->vp;
|
||
|
|
s_dropn_var(s, s->vp - s->fp->params);
|
||
|
|
// drop params // TODO: check +-1
|
||
|
|
s_put_var(s, ret);
|
||
|
|
s->ip = s->fp->rp;
|
||
|
|
|
||
|
|
// *s->fp = clear_frame(); // clear top frame
|
||
|
|
}
|
||
|
|
|
||
|
|
// TODO
|
||
|
|
inline void s_enter_f(struct State *s, char *func_ip, size_t params_sz,
|
||
|
|
size_t locals_sz) {
|
||
|
|
struct Frame frame = {
|
||
|
|
.rp = s->ip, // ??
|
||
|
|
.ret = s->vp,
|
||
|
|
.params = s->vp - params_sz, // TODO: check +-1
|
||
|
|
.locals = s->vp + 1,
|
||
|
|
.end = s->vp + locals_sz + 1, // ??
|
||
|
|
};
|
||
|
|
|
||
|
|
// TODO:
|
||
|
|
s_put_nil(s); // ret
|
||
|
|
s_putn_nil(s, locals_sz); // locals
|
||
|
|
s->ip = func_ip;
|
||
|
|
(*s->fp) = frame;
|
||
|
|
++s->fp;
|
||
|
|
}
|