fixes to run stdlib tests and tutorial tests. No unexpected exits on these tests (without output checkings). + remove som e leftovers from stdlib closure coding + bug fixes

This commit is contained in:
ProgramSnail 2025-04-12 17:09:02 +03:00
parent 467eeb0eef
commit 4d7afdeae0
10 changed files with 84 additions and 51 deletions

View file

@ -28,5 +28,4 @@ for test in regression/dep_test*.lama; do
echo "done"
done
rm *.bc
rm *.o

View file

@ -54,15 +54,17 @@ enum BUILTIN : uint {
//
BUILTIN_LkindOf, // 39
BUILTIN_LcompareTags, // 40
BUILTIN_Ls__Infix_58, // 41
//
#define BUILTIN_NAME(name) BUILTIN_##name,
FORALL_BINOP_FUNC(BUILTIN_NAME)
#undef BUILTIN_NAME
//
BUILTIN_Barray, // 41+14 // can't be run with run_stdlib_func
BUILTIN_NONE, // 42+14
BUILTIN_Barray, // 42+14 // can't be run with run_stdlib_func
BUILTIN_NONE, // 43+14
};
enum BUILTIN id_by_builtin(const char *name);
bool is_builtin_with_ret(enum BUILTIN id);
void run_stdlib_func(enum BUILTIN id, size_t args_count);

View file

@ -19,9 +19,7 @@
DEF(CMD_BINOP_AND, &&) \
DEF(CMD_BINOP_OR, ||)
// NOTE: includes additional ':' operator
#define FORALL_BINOP_FUNC(DEF) \
DEF(Ls__Infix_58) \
DEF(Ls__Infix_3333) \
DEF(Ls__Infix_3838) \
DEF(Ls__Infix_6161) \

View file

@ -25,7 +25,7 @@ aint LkindOf(void *p);
aint LcompareTags(void *p, void *q);
// Functional synonym for built-in operator ":";
void *Ls__Infix_58(void *p, void *q);
void *Ls__Infix_58(void **args);
// Functional synonym for built-in operator "!!";
aint Ls__Infix_3333(void *p, void *q);

View file

@ -16,9 +16,9 @@ for test in ../regression/*.lama; do
test_path="${test%.*}"
test_file="${test_path##*/}"
echo $test_path: $test_file
# cat $test_file.input | ./byterun.exe -p $test_file.bc > test.bc.code
# cat $test_file.input | ./byterun.exe -p $test_file.bc
# cat $test_file.input | ./byterun.exe -vi $test_file.bc
# cat $test_path.input | ./byterun.exe -p $test_file.bc > test.bc.code
# cat $test_path.input | ./byterun.exe -p $test_file.bc
# cat $test_path.input | ./byterun.exe -vi $test_file.bc
cat $test_path.input | ./byterun.exe -vi $test_file.bc > test.log
sed '1d;s/^..//' $test_path.t > test_orig.log
diff test.log test_orig.log

View file

@ -69,13 +69,13 @@ void set_argc_argv(int argc, char **argv) {
#endif
s_push(Bstring((aint *)&argv[argc - i - 1]));
}
s_push(Barray((aint *)s_peek(), argc));
void *argv_elem = s_pop();
void *args_array = Barray((aint *)s_peek(), BOX(argc));
s_popn(argc);
s_push(argv_elem);
s_push(args_array);
*var_by_category(VAR_GLOBAL, 0) = args_array; // NOTE: implementation detail, stdlib/test26.lama
#ifdef DEBUG_VERSION
print_stack(s);
print_stack(&s);
printf("- state init done\n");
#endif
}
@ -468,6 +468,13 @@ void run_main(Bytefile* bf, int argc, char **argv) {
size_t builtin_id = ip_read_int(&s.ip);
size_t args_count = ip_read_int(&s.ip); // args count
call_builtin(builtin_id, args_count);
if (s.is_closure_call) {
// NOTE: all functions have returned value, some values undefined
// if (is_builtin_with_ret(builtin_id)) {
s_swap_tops();
// }
s_pop();
}
s.ip = s.call_ip; // TODO: check
break;
}

View file

@ -19,15 +19,21 @@ extern "C" {
template <size_t N, typename... Args>
requires(N == 0)
void call_func(void (*f)(), Args... args) {
s_push(((void *(*)(Args...))f)(args...));
void call_func(void (*f)(), size_t n, Args... args) {
// std::cout << std::endl << "args_count=" << n << " "; // TODO FIXME TMP
std::cout << std::endl; // TODO: TMP, to work with problematic \n display
asm volatile("movq %0, %%r11"
: /* no outputs */
: "m"(n));
/*s_push(*/ ((void (*)(Args...))f)(args...); //);
s_push(0);
}
template <size_t N, typename... Args>
requires(N != 0)
void call_func(void (*f)(), Args... args) {
void call_func(void (*f)(), size_t n, Args... args) {
void *arg = s_pop();
call_func<N - 1, Args..., void *>(f, arg, args...);
call_func<N - 1, Args..., void *>(f, n, arg, args...);
// TODO: check that arg is added on the right position
}
@ -39,7 +45,7 @@ void call_anyarg_func(void (*f)(), size_t n) {
}
}
if (n == N) {
call_func<N>(f);
call_func<N>(f, n);
} else if constexpr (N > 0) {
call_anyarg_func<N - 1, false>(f, n);
}
@ -55,8 +61,6 @@ struct Offsets {
};
void rewrite_code_with_offsets(Bytefile *bytefile, const Offsets &offsets) {
// TODO: globals offsets
char *ip = bytefile->code_ptr;
while (ip - bytefile->code_ptr < bytefile->code_size) {
char *instr_ip = ip;
@ -73,6 +77,8 @@ void rewrite_code_with_offsets(Bytefile *bytefile, const Offsets &offsets) {
char *write_ip = instr_ip + 1;
switch (cmd) {
case Cmd::STRING:
case Cmd::SEXP:
case Cmd::TAG:
ip_write_int_unsafe(write_ip,
ip_read_int_unsafe(&read_ip) + offsets.strings);
break;
@ -85,16 +91,14 @@ void rewrite_code_with_offsets(Bytefile *bytefile, const Offsets &offsets) {
break;
case Cmd::CLOSURE: {
aint offset = ip_read_int_unsafe(&read_ip);
// NOTE: do not modify offset for builtin's closures
ip_write_int_unsafe(write_ip,
offset < 0 ? offset : offset + offsets.code);
ip_write_int_unsafe(write_ip, offset + offsets.code);
size_t args_count = ip_read_int_unsafe(&read_ip);
for (size_t i = 0; i < args_count; ++i) {
uint8_t arg_type = ip_read_byte_unsafe(&read_ip);
aint value = ip_read_int_unsafe(&read_ip);
if (to_var_category(arg_type) == VAR_GLOBAL) {
write_ip = read_ip;
ip_write_int_unsafe(write_ip,
ip_read_int_unsafe(&read_ip) + offsets.globals);
ip_write_int_unsafe(write_ip, value + offsets.globals);
}
}
break;
@ -173,8 +177,8 @@ void add_subst_builtin_offsets(BuiltinSubstMap &subst_map, size_t code_offset,
// NOTE: unmanaged memory allocated
std::pair<char *, size_t> gen_builtins(size_t code_offset,
BuiltinSubstMap &subst_map) {
size_t code_size =
subst_map.size() * /*size of builtin command*/ (1 + 2 * sizeof(uint32_t));
size_t code_size = subst_map.size() *
/*size of builtin command*/ (1 + 2 * sizeof(uint32_t));
char *code = (char *)malloc(code_size);
char *code_it = code;
@ -377,7 +381,6 @@ Bytefile *path_mod_load(const char *name, std::filesystem::path &&path) {
static std::vector<std::filesystem::path> search_paths;
extern "C" {
void mod_add_search_path(const char *path) { search_paths.emplace_back(path); }
Bytefile *mod_load(const char *name) {
@ -533,6 +536,7 @@ BUILTIN id_by_builtin(const char *name) {
{"LgetEnv", BUILTIN_LgetEnv},
{"Lrandom", BUILTIN_Lrandom},
{"Ltime", BUILTIN_Ltime},
{"Ls__Infix_58", BUILTIN_Ls__Infix_58},
//
{"LkindOf", BUILTIN_LkindOf},
{"LcompareTags", BUILTIN_LcompareTags},
@ -549,6 +553,27 @@ BUILTIN id_by_builtin(const char *name) {
return it == std_func.end() ? BUILTIN_NONE : it->second;
}
/* NOTE: all functions have returned value, some values undefined */
// bool is_builtin_with_ret(BUILTIN id) {
// switch (id) {
// case BUILTIN_Lassert:
// case BUILTIN_Lsprintf:
// case BUILTIN_Lprintf:
// case BUILTIN_Lfclose:
// case BUILTIN_Lfwrite:
// case BUILTIN_Lfprintf:
// case BUILTIN_Lfailure:
// return false;
// default:
// return true;
// }
// }
/* NOTE: from src/X86_64.ml: */
/* For vararg functions where we pass them in the stdlib function using va_list,
we have to unbox values to print them correctly.
For this we have special assemply functions in `printf.S`.
We additionally pass them amount of arguments to unbox using register r11. */
void run_stdlib_func(BUILTIN id, size_t args_count) {
// std::cout << "RUN BUILTIN: " << id << '\n'; // TODO: TMP
void *ret = NULL;
@ -565,10 +590,8 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
s_push(ret);
break;
case BUILTIN_Lassert:
s_popn(args_count);
std::cout << "!!> assert is not properly checked yet, skipping\n";
// NOTE: basic params: .args_count = 2, .is_vararg = true
// call_anyarg_func<20>((void (*)()) & Lassert, args_count);
call_anyarg_func<20>((void (*)()) & Lassert, args_count);
break;
case BUILTIN_Lstring:
ret = Lstring(s_nth_i(0)); // .is_args = true
@ -617,17 +640,18 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
s_push(ret);
break;
case BUILTIN_Lsprintf:
s_popn(args_count);
std::cout << "!!> printf is not properly checked yet, skipping\n";
// NOTE: basic params: .args_count = 1, .is_vararg = true
// call_anyarg_func<20>((void (*)()) & Lsprintf, args_count);
call_anyarg_func<20>((void (*)()) & Lsprintf, args_count);
break;
case BUILTIN_Lsubstring:
// std::cout << "substr\n";
s_rotate_n(3); // NOTE: is fix ?
ret = (void *)Lsubstring(s_nth_i(0)); // .is_args = true;
s_popn(3);
s_push(ret);
break;
case BUILTIN_Li__Infix_4343:
s_rotate_n(2); // NOTE: is fix ?
ret = (void *)Li__Infix_4343(s_nth_i(0)); // .is_args = true
s_popn(2);
s_push(ret);
@ -682,10 +706,8 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
s_push(ret);
break;
case BUILTIN_Lprintf:
s_popn(args_count);
std::cout << "!!> printf is not properly checked yet, skipping\n";
// NOTE: basic params: .args_count = 1, .is_vararg = true
// call_anyarg_func<20>((void (*)()) & Lprintf, args_count);
call_anyarg_func<20>((void (*)()) & Lprintf, args_count);
break;
case BUILTIN_Lfopen:
ret = (void *)Lfopen((char *)*s_nth(1), (char *)*s_nth(0));
@ -695,7 +717,7 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
case BUILTIN_Lfclose:
/*ret = (void *)*/ Lfclose((FILE *)*s_nth(0));
s_popn(1);
// s_push(ret); // NOTE: ??
s_push(0); // NOTE: UB on use
break;
case BUILTIN_Lfread:
ret = (void *)Lfread((char *)*s_nth(0));
@ -705,7 +727,7 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
case BUILTIN_Lfwrite:
/*ret = (void *)*/ Lfwrite((char *)*s_nth(1), (char *)*s_nth(0));
s_popn(2);
// s_push(ret); // NOTE: ??
s_push(0); // NOTE: UB on use
break;
case BUILTIN_Lfexists:
ret = (void *)Lfexists((char *)*s_nth(0));
@ -713,10 +735,8 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
s_push(ret);
break;
case BUILTIN_Lfprintf:
s_popn(args_count);
std::cout << "!!> printf is not properly checked yet, skipping\n";
// NOTE: basic params: .args_count = 2, .is_vararg = true
// call_anyarg_func<20>((void (*)()) & Lfprintf, args_count);
call_anyarg_func<20>((void (*)()) & Lfprintf, args_count);
break;
case BUILTIN_Lregexp:
ret = (void *)Lregexp((char *)*s_nth(0));
@ -730,9 +750,8 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
s_push(ret);
break;
case BUILTIN_Lfailure:
std::cout << "!!> failure is not properly checked yet, skipping\n";
// NOTE: basic params: .args_count = 1, .is_vararg = true
// call_anyarg_func<20>((void (*)()) & Lfailure, args_count);
call_anyarg_func<20>((void (*)()) & Lfailure, args_count);
break;
case BUILTIN_Lsystem:
ret = (void *)Lsystem((char *)*s_nth(0));
@ -763,6 +782,12 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
s_popn(2);
s_push(ret);
break;
case BUILTIN_Ls__Infix_58:
s_rotate_n(2); // NOTE: is fix ?
ret = (void *)Ls__Infix_58((void **)s_nth_i(0)); // .is_args = true
s_popn(2);
s_push(ret);
break;
#define BUILTIN_CASE(name) \
case BUILTIN_##name: \
ret = (void *)name((char *)*s_nth(1), (char *)*s_nth(0)); \
@ -784,7 +809,8 @@ void run_stdlib_func(BUILTIN id, size_t args_count) {
// // TODO: move to bytecode verifier
// if ((!func.is_vararg && func.args_count != args_count) ||
// func.args_count > args_count) {
// failure("RUNTIME ERROR: stdlib function <%u> argument count <%zu> is not
// failure("RUNTIME ERROR: stdlib function <%u> argument count <%zu> is
// not
// "
// "expected (expected is <%s%zu>)\n",
// id, func.args_count, func.is_vararg ? ">=" : "=", args_count);

View file

@ -58,7 +58,7 @@ void prepare_state(Bytefile* bf, struct State* s) {
}
void push_globals(struct State *s) {
s->bf->global_ptr = (void*)__gc_stack_top;
s->bf->global_ptr = s_peek(); // (void*)__gc_stack_top;
s_pushn_nil(s->bf->global_area_size);
#ifdef DEBUG_VERSION

View file

@ -27,10 +27,10 @@ for test in ../stdlib/regression/*.lama; do
test_path="${test%.*}"
test_file="${test_path##*/}"
echo $test_path: $test_file
# cat $test_file.input | ./byterun.exe -p $test_file.bc > test.bc.code
# cat $test_file.input | ./byterun.exe -p $test_file.bc
echo "" | ./byterun.exe -vi $test_file.bc
# echo "" | ./byterun.exe -vi $test_file.bc > test.log
echo "" | ./byterun.exe -p $test_file.bc > test.bc.code
# echo "" | ./byterun.exe -p $test_file.bc
# echo "" | ./byterun.exe -vi $test_file.bc
echo "" | ./byterun.exe -vi $test_file.bc > test.log
# sed '1d;s/^..//' $test_file.t > test_orig.log
# diff test.log test_orig.log

View file

@ -27,6 +27,7 @@ for test in ../tutorial/*.lama; do
test_file="${test_path##*/}"
echo $test_path: $test_file
echo " " | ./byterun.exe -vi $test_file.bc
echo "" | ./byterun.exe -vi $test_file.bc > test.log
rm $test_file.bc
echo "done"
done