✨ change intg to repl output operand
This commit is contained in:
parent
7a10392bea
commit
d69dd0b03f
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, &¶, &&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
|
||||
|
|
|
@ -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() {
|
||||
|
|
15
src/repl.cpp
15
src/repl.cpp
|
@ -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();
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# utils.nas
|
||||
# 2023 by ValKmjolnir
|
||||
|
||||
var times_trigger = func(times, count) {
|
||||
return math.mod(times, count)==0;
|
||||
}
|
Loading…
Reference in New Issue