change intg to repl output operand

This commit is contained in:
ValKmjolnir 2023-10-02 00:46:12 +08:00
parent 7a10392bea
commit d69dd0b03f
10 changed files with 82 additions and 25 deletions

View File

@ -139,7 +139,7 @@ void execute(
}
// code generator gets parser's ast and import file list to generate code
gen.compile(parse, ld).chkerr();
gen.compile(parse, ld, false).chkerr();
if (cmd&VM_CODE) {
gen.print(std::cout);
}

View File

@ -79,15 +79,21 @@ void codegen::regist_str(const std::string& str) {
void codegen::find_symbol(code_block* node) {
auto finder = std::unique_ptr<symbol_finder>(new symbol_finder);
for(const auto& i : finder->do_find(node)) {
// check if symbol conflicts with native function name
if (native_function_mapper.count(i.name)) {
die("definition conflicts with native function", i.location);
die("symbol conflicts with native function", i.location);
continue;
}
// create new namespace with checking existence of location file
if (!experimental_namespace.count(i.location.file)) {
experimental_namespace[i.location.file] = {};
}
if (local.empty() && !experimental_namespace.at(i.location.file).count(i.name)) {
experimental_namespace.at(i.location.file).insert(i.name);
// if in global scope, load global symbol into this namespace
auto scope = experimental_namespace.at(i.location.file);
if (local.empty() && !scope.count(i.name)) {
scope.insert(i.name);
}
// add symbol for codegen symbol check
add_symbol(i.name);
}
}
@ -477,6 +483,10 @@ void codegen::mcall_hash(call_hash* node) {
void codegen::single_def(definition_expr* node) {
const auto& str = node->get_variable_name()->get_name();
calc_gen(node->get_value());
// only generate in repl mode and in global scope
if (need_repl_output && local.empty()) {
emit(op_repl, 0, node->get_location());
}
if (local.empty()) {
emit(op_loadg, global_symbol_find(str), node->get_location());
} else {
@ -872,6 +882,10 @@ void codegen::statement_generation(expr* node) {
case expr_type::ast_binary:
case expr_type::ast_ternary:
calc_gen(node);
// only generate in repl mode and in global scope
if (need_repl_output && local.empty()) {
emit(op_repl, 0, node->get_location());
}
emit(op_pop, 0, node->get_location());
break;
default: break;
@ -1126,16 +1140,40 @@ void codegen::calc_gen(expr* node) {
}
}
void codegen::repl_mode_info_output_gen(expr* node) {
switch(node->get_type()) {
case expr_type::ast_id: call_id((identifier*)node); break;
case expr_type::ast_nil: emit(op_pnil, 0, node->get_location()); break;
case expr_type::ast_num: num_gen((number_literal*)node); break;
case expr_type::ast_str: str_gen((string_literal*)node); break;
case expr_type::ast_bool: bool_gen((bool_literal*)node); break;
default: return;
}
// generate repl output operand
emit(op_repl, 0, node->get_location());
// pop stack
emit(op_pop, 0, node->get_location());
}
void codegen::block_gen(code_block* node) {
for(auto tmp : node->get_expressions()) {
switch(tmp->get_type()) {
case expr_type::ast_null: break;
case expr_type::ast_id:
check_id_exist((identifier*)tmp); break;
if (need_repl_output) {
repl_mode_info_output_gen(tmp);
} else {
check_id_exist((identifier*)tmp);
}
break;
case expr_type::ast_nil:
case expr_type::ast_num:
case expr_type::ast_str:
case expr_type::ast_bool: break;
case expr_type::ast_bool:
if (need_repl_output) {
repl_mode_info_output_gen(tmp);
}
break;
case expr_type::ast_cond:
cond_gen((condition_expr*)tmp); break;
case expr_type::ast_continue:
@ -1177,9 +1215,10 @@ void codegen::ret_gen(return_expr* node) {
emit(op_ret, 0, node->get_location());
}
const error& codegen::compile(parse& parse, linker& import) {
const error& codegen::compile(parse& parse, linker& import, bool repl_flag) {
init_native_function();
init_file_map(import.get_file_list());
need_repl_output = repl_flag;
in_loop_level.push_back(0);

View File

@ -34,6 +34,9 @@ class codegen {
private:
error err;
//
bool need_repl_output;
// file mapper for file -> index
std::unordered_map<std::string, usize> file_map;
void init_file_map(const std::vector<std::string>&);
@ -121,6 +124,7 @@ private:
void binary_gen(binary_operator*);
void trino_gen(ternary_operator*);
void calc_gen(expr*);
void repl_mode_info_output_gen(expr*);
void block_gen(code_block*);
void ret_gen(return_expr*);
@ -136,7 +140,7 @@ public:
public:
codegen() = default;
const error& compile(parse&, linker&);
const error& compile(parse&, linker&, bool);
void print(std::ostream&);
void symbol_dump(std::ostream&) const;
};

View File

@ -41,7 +41,7 @@ class dbg:public vm {
private:
typedef void (dbg::*nasal_vm_func)();
const nasal_vm_func operand_function[op_ret + 1] = {
nullptr, &dbg::o_intg,
nullptr, &dbg::o_repl,
&dbg::o_intl, &dbg::o_loadg,
&dbg::o_loadl, &dbg::o_loadu,
&dbg::o_pnum, &dbg::o_pnil,

View File

@ -3,7 +3,7 @@
namespace nasal {
const char* opname[] = {
"exit ", "intg ", "intl ", "loadg ",
"exit ", "repl ", "intl ", "loadg ",
"loadl ", "loadu ", "pnum ", "pnil ",
"pstr ", "newv ", "newh ", "newf ",
"happ ", "para ", "def ", "dyn ",
@ -81,7 +81,7 @@ void codestream::dump(std::ostream& out) const {
out << hex << "0x" << num << dec
<< " (" << nums[num] << ")"; break;
case op_callvi: case op_newv:
case op_callfv: case op_intg:
case op_callfv: case op_repl:
case op_intl: case op_findex:
case op_feach: case op_newf:
case op_jmp: case op_jt:

View File

@ -9,7 +9,7 @@ namespace nasal {
enum op_code_type:u8 {
op_exit, // stop the virtual machine
op_intg, // [deprecated] init global scope
op_repl, // in repl mode: print value on stack top
op_intl, // local scope size
op_loadg, // load global value
op_loadl, // load local value

View File

@ -259,7 +259,7 @@ void vm::run(
#ifndef _MSC_VER
// using labels as values/computed goto
const void* oprs[] = {
&&vmexit, &&intg, &&intl, &&loadg,
&&vmexit, &&repl, &&intl, &&loadg,
&&loadl, &&loadu, &&pnum, &&pnil,
&&pstr, &&newv, &&newh, &&newf,
&&happ, &&para, &&deft, &&dyn,
@ -292,7 +292,7 @@ void vm::run(
#else
typedef void (vm::*nafunc)();
const nafunc oprs[] = {
nullptr, &vm::o_intg,
nullptr, &vm::o_repl,
&vm::o_intl, &vm::o_loadg,
&vm::o_loadl, &vm::o_loadu,
&vm::o_pnum, &vm::o_pnil,
@ -376,7 +376,7 @@ vmexit:
goto *code[++ctx.pc];\
}
intg: exec_nodie(o_intg ); // +imm[pc] (detected at codegen)
repl: exec_nodie(o_repl ); // 0
intl: exec_nodie(o_intl ); // -0
loadg: exec_nodie(o_loadg ); // -1
loadl: exec_nodie(o_loadl ); // -1

View File

@ -41,6 +41,7 @@ protected:
/* variables for repl mode */
bool is_repl_mode = false;
bool first_exec_flag = true;
bool allow_repl_output = false;
/* vm initializing function */
void init(
@ -70,7 +71,7 @@ protected:
inline bool cond(var&);
/* vm operands */
inline void o_intg();
inline void o_repl();
inline void o_intl();
inline void o_loadg();
inline void o_loadl();
@ -180,6 +181,8 @@ public:
void set_detail_report_info(bool flag) {verbose = flag;}
/* set repl mode flag */
void set_repl_mode_flag(bool flag) {is_repl_mode = flag;}
/* set repl output flag */
void set_allow_repl_output_flag(bool flag) {allow_repl_output = flag;}
};
inline bool vm::cond(var& val) {
@ -192,9 +195,11 @@ inline bool vm::cond(var& val) {
return false;
}
inline void vm::o_intg() {
// reserved for another usage
std::cout << "[vm] do nothing\n";
inline void vm::o_repl() {
// reserved for repl mode stack top value output
if (allow_repl_output) {
std::cout << ctx.top[0] << "\n";
}
}
inline void vm::o_intl() {

View File

@ -96,22 +96,25 @@ bool repl::run() {
return false;
}
// nasal_opt->do_optimization(nasal_parser->tree());
if (nasal_codegen->compile(*nasal_parser, *nasal_linker).geterr()) {
nasal_opt->do_optimization(nasal_parser->tree());
if (nasal_codegen->compile(*nasal_parser, *nasal_linker, true).geterr()) {
return false;
}
// TODO: gc init stage in this run may cause memory leak,
// because constant strings will be generated again.
// but we could not delete old strings, they maybe still on stack.
runtime.run(*nasal_codegen, *nasal_linker, {});
return true;
}
void repl::execute() {
source = {};
// mark we are in repl mode
info::instance()->in_repl_mode = true;
std::cout << "[nasal-repl] Initializating enviroment...\n";
// run on pass for initializing basic modules, without output
run();
// allow output now
runtime.set_allow_repl_output_flag(true);
std::cout << "[nasal-repl] Initialization complete.\n\n";
std::cout << "Nasal REPL interpreter(experimental).\n";
help();

6
std/utils.nas Normal file
View File

@ -0,0 +1,6 @@
# utils.nas
# 2023 by ValKmjolnir
var times_trigger = func(times, count) {
return math.mod(times, count)==0;
}