diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 5d9e132..b795a97 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -339,6 +339,8 @@ void codegen::call_gen(call_expr* node) { call_vector_gen(reinterpret_cast(i)); break; case expr_type::ast_callf: call_func_gen(reinterpret_cast(i)); break; + case expr_type::ast_nullaccess: + null_access_gen(reinterpret_cast(i)); break; default: break; } } @@ -382,6 +384,24 @@ void codegen::call_hash_gen(call_hash* node) { emit(op_callh, const_string_map.at(node->get_field()), node->get_location()); } +void codegen::null_access_gen(null_access* node) { + regist_string(node->get_field()); + + emit(op_dup, 0, node->get_location()); + emit(op_pnil, 0, node->get_location()); + emit(op_eq, 0, node->get_location()); + + const auto jmp_false_point = code.size(); + emit(op_jf, 0, node->get_location()); + + const auto jmp_direct_point = code.size(); + emit(op_jmp, 0, node->get_location()); + + code[jmp_false_point].num = code.size(); + emit(op_callh, const_string_map.at(node->get_field()), node->get_location()); + code[jmp_direct_point].num = code.size(); +} + void codegen::call_vector_gen(call_vector* node) { // maybe this place can use callv-const if ast's first child is ast_num if (node->get_slices().size()==1 && @@ -455,6 +475,8 @@ void codegen::mcall(expr* node) { call_vector_gen(reinterpret_cast(tmp)); break; case expr_type::ast_callf: call_func_gen(reinterpret_cast(tmp)); break; + case expr_type::ast_nullaccess: + null_access_gen(reinterpret_cast(tmp)); break; default: break; } } @@ -467,6 +489,8 @@ void codegen::mcall(expr* node) { mcall_vec(reinterpret_cast(tmp)); break; case expr_type::ast_callf: die("bad left-value: function call", tmp->get_location()); break; + case expr_type::ast_nullaccess: + die("bad left-value: null access test", tmp->get_location()); break; default: die("bad left-value: unknown call", tmp->get_location()); break; } diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index abc42c9..ffa2ab7 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -123,6 +123,7 @@ private: void call_gen(call_expr*); void call_identifier(identifier*); void call_hash_gen(call_hash*); + void null_access_gen(null_access*); void call_vector_gen(call_vector*); void call_func_gen(call_function*); void mcall(expr*); diff --git a/src/nasal_dbg.h b/src/nasal_dbg.h index 61b03fc..132c570 100644 --- a/src/nasal_dbg.h +++ b/src/nasal_dbg.h @@ -43,49 +43,93 @@ class dbg: public vm { private: typedef void (dbg::*nasal_vm_func)(); const nasal_vm_func operand_function[op_ret + 1] = { - nullptr, &dbg::o_repl, - &dbg::o_intl, &dbg::o_loadg, - &dbg::o_loadl, &dbg::o_loadu, - &dbg::o_pnum, &dbg::o_pnil, - &dbg::o_pstr, &dbg::o_newv, - &dbg::o_newh, &dbg::o_newf, - &dbg::o_happ, &dbg::o_para, - &dbg::o_deft, &dbg::o_dyn, - &dbg::o_lnot, &dbg::o_usub, - &dbg::o_bnot, &dbg::o_btor, - &dbg::o_btxor, &dbg::o_btand, - &dbg::o_add, &dbg::o_sub, - &dbg::o_mul, &dbg::o_div, - &dbg::o_lnk, &dbg::o_addc, - &dbg::o_subc, &dbg::o_mulc, - &dbg::o_divc, &dbg::o_lnkc, - &dbg::o_addeq, &dbg::o_subeq, - &dbg::o_muleq, &dbg::o_diveq, - &dbg::o_lnkeq, &dbg::o_bandeq, - &dbg::o_boreq, &dbg::o_bxoreq, - &dbg::o_addeqc, &dbg::o_subeqc, - &dbg::o_muleqc, &dbg::o_diveqc, - &dbg::o_lnkeqc, &dbg::o_addecp, - &dbg::o_subecp, &dbg::o_mulecp, - &dbg::o_divecp, &dbg::o_lnkecp, - &dbg::o_meq, &dbg::o_eq, - &dbg::o_neq, &dbg::o_less, - &dbg::o_leq, &dbg::o_grt, - &dbg::o_geq, &dbg::o_lessc, - &dbg::o_leqc, &dbg::o_grtc, - &dbg::o_geqc, &dbg::o_pop, - &dbg::o_jmp, &dbg::o_jt, - &dbg::o_jf, &dbg::o_cnt, - &dbg::o_findex, &dbg::o_feach, - &dbg::o_callg, &dbg::o_calll, - &dbg::o_upval, &dbg::o_callv, - &dbg::o_callvi, &dbg::o_callh, - &dbg::o_callfv, &dbg::o_callfh, - &dbg::o_callb, &dbg::o_slcbeg, - &dbg::o_slcend, &dbg::o_slc, - &dbg::o_slc2, &dbg::o_mcallg, - &dbg::o_mcalll, &dbg::o_mupval, - &dbg::o_mcallv, &dbg::o_mcallh, + nullptr, + &dbg::o_repl, + &dbg::o_intl, + &dbg::o_loadg, + &dbg::o_loadl, + &dbg::o_loadu, + &dbg::o_dup, + &dbg::o_pnum, + &dbg::o_pnil, + &dbg::o_pstr, + &dbg::o_newv, + &dbg::o_newh, + &dbg::o_newf, + &dbg::o_happ, + &dbg::o_para, + &dbg::o_deft, + &dbg::o_dyn, + &dbg::o_lnot, + &dbg::o_usub, + &dbg::o_bnot, + &dbg::o_btor, + &dbg::o_btxor, + &dbg::o_btand, + &dbg::o_add, + &dbg::o_sub, + &dbg::o_mul, + &dbg::o_div, + &dbg::o_lnk, + &dbg::o_addc, + &dbg::o_subc, + &dbg::o_mulc, + &dbg::o_divc, + &dbg::o_lnkc, + &dbg::o_addeq, + &dbg::o_subeq, + &dbg::o_muleq, + &dbg::o_diveq, + &dbg::o_lnkeq, + &dbg::o_bandeq, + &dbg::o_boreq, + &dbg::o_bxoreq, + &dbg::o_addeqc, + &dbg::o_subeqc, + &dbg::o_muleqc, + &dbg::o_diveqc, + &dbg::o_lnkeqc, + &dbg::o_addecp, + &dbg::o_subecp, + &dbg::o_mulecp, + &dbg::o_divecp, + &dbg::o_lnkecp, + &dbg::o_meq, + &dbg::o_eq, + &dbg::o_neq, + &dbg::o_less, + &dbg::o_leq, + &dbg::o_grt, + &dbg::o_geq, + &dbg::o_lessc, + &dbg::o_leqc, + &dbg::o_grtc, + &dbg::o_geqc, + &dbg::o_pop, + &dbg::o_jmp, + &dbg::o_jt, + &dbg::o_jf, + &dbg::o_cnt, + &dbg::o_findex, + &dbg::o_feach, + &dbg::o_callg, + &dbg::o_calll, + &dbg::o_upval, + &dbg::o_callv, + &dbg::o_callvi, + &dbg::o_callh, + &dbg::o_callfv, + &dbg::o_callfh, + &dbg::o_callb, + &dbg::o_slcbeg, + &dbg::o_slcend, + &dbg::o_slc, + &dbg::o_slc2, + &dbg::o_mcallg, + &dbg::o_mcalll, + &dbg::o_mupval, + &dbg::o_mcallv, + &dbg::o_mcallh, &dbg::o_ret }; diff --git a/src/nasal_opcode.cpp b/src/nasal_opcode.cpp index b8ed77d..c3bc7ad 100644 --- a/src/nasal_opcode.cpp +++ b/src/nasal_opcode.cpp @@ -4,28 +4,94 @@ namespace nasal { const char* oprand_name_table[] = { - "exit ", "repl ", "intl ", "loadg ", - "loadl ", "loadu ", "pnum ", "pnil ", - "pstr ", "newv ", "newh ", "newf ", - "happ ", "para ", "def ", "dyn ", - "lnot ", "usub ", "bitnot", "bitor ", - "bitxor", "bitand", "add ", "sub ", - "mult ", "div ", "lnk ", "addc ", - "subc ", "multc ", "divc ", "lnkc ", - "addeq ", "subeq ", "muleq ", "diveq ", - "lnkeq ", "bandeq", "boreq ", "bxoreq", - "addeqc", "subeqc", "muleqc", "diveqc", - "lnkeqc", "addecp", "subecp", "mulecp", - "divecp", "lnkecp", "meq ", "eq ", - "neq ", "less ", "leq ", "grt ", - "geq ", "lessc ", "leqc ", "grtc ", - "geqc ", "pop ", "jmp ", "jt ", - "jf ", "cnt ", "findx ", "feach ", - "callg ", "calll ", "upval ", "callv ", - "callvi", "callh ", "callfv", "callfh", - "callb ", "slcbeg", "slcend", "slice ", - "slice2", "mcallg", "mcalll", "mupval", - "mcallv", "mcallh", "ret " + "exit ", + "repl ", + "intl ", + "loadg ", + "loadl ", + "loadu ", + "dup ", + "pnum ", + "pnil ", + "pstr ", + "newv ", + "newh ", + "newf ", + "happ ", + "para ", + "def ", + "dyn ", + "lnot ", + "usub ", + "bitnot", + "bitor ", + "bitxor", + "bitand", + "add ", + "sub ", + "mult ", + "div ", + "lnk ", + "addc ", + "subc ", + "multc ", + "divc ", + "lnkc ", + "addeq ", + "subeq ", + "muleq ", + "diveq ", + "lnkeq ", + "bandeq", + "boreq ", + "bxoreq", + "addeqc", + "subeqc", + "muleqc", + "diveqc", + "lnkeqc", + "addecp", + "subecp", + "mulecp", + "divecp", + "lnkecp", + "meq ", + "eq ", + "neq ", + "less ", + "leq ", + "grt ", + "geq ", + "lessc ", + "leqc ", + "grtc ", + "geqc ", + "pop ", + "jmp ", + "jt ", + "jf ", + "cnt ", + "findx ", + "feach ", + "callg ", + "calll ", + "upval ", + "callv ", + "callvi", + "callh ", + "callfv", + "callfh", + "callb ", + "slcbeg", + "slcend", + "slice ", + "slice2", + "mcallg", + "mcalll", + "mupval", + "mcallv", + "mcallh", + "ret " }; void codestream::set(const f64* number_list, diff --git a/src/nasal_opcode.h b/src/nasal_opcode.h index 55e81c8..8d3e06a 100644 --- a/src/nasal_opcode.h +++ b/src/nasal_opcode.h @@ -14,6 +14,7 @@ enum op_code_type: u8 { op_loadg, // load global value op_loadl, // load local value op_loadu, // load upvalue + op_dup, // copy value on stack top op_pnum, // push constant number to the stack op_pnil, // push constant nil to the stack op_pstr, // push constant std::string to the stack diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 9515c1a..a5e2a46 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -429,28 +429,94 @@ void vm::run(const codegen& gen, #ifndef _MSC_VER // using labels as values/computed goto const void* oprs[] = { - &&vmexit, &&repl, &&intl, &&loadg, - &&loadl, &&loadu, &&pnum, &&pnil, - &&pstr, &&newv, &&newh, &&newf, - &&happ, &¶, &&deft, &&dyn, - &&lnot, &&usub, &&bnot, &&btor, - &&btxor, &&btand, &&add, &&sub, - &&mul, &&div, &&lnk, &&addc, - &&subc, &&mulc, &&divc, &&lnkc, - &&addeq, &&subeq, &&muleq, &&diveq, - &&lnkeq, &&bandeq, &&boreq, &&bxoreq, - &&addeqc, &&subeqc, &&muleqc, &&diveqc, - &&lnkeqc, &&addecp, &&subecp, &&mulecp, - &&divecp, &&lnkecp, &&meq, &&eq, - &&neq, &&less, &&leq, &&grt, - &&geq, &&lessc, &&leqc, &&grtc, - &&geqc, &&pop, &&jmp, &&jt, - &&jf, &&cnt, &&findex, &&feach, - &&callg, &&calll, &&upval, &&callv, - &&callvi, &&callh, &&callfv, &&callfh, - &&callb, &&slcbeg, &&slcend, &&slc, - &&slc2, &&mcallg, &&mcalll, &&mupval, - &&mcallv, &&mcallh, &&ret + &&vmexit, + &&repl, + &&intl, + &&loadg, + &&loadl, + &&loadu, + &&dup, + &&pnum, + &&pnil, + &&pstr, + &&newv, + &&newh, + &&newf, + &&happ, + &¶, + &&deft, + &&dyn, + &&lnot, + &&usub, + &&bnot, + &&btor, + &&btxor, + &&btand, + &&add, + &&sub, + &&mul, + &&div, + &&lnk, + &&addc, + &&subc, + &&mulc, + &&divc, + &&lnkc, + &&addeq, + &&subeq, + &&muleq, + &&diveq, + &&lnkeq, + &&bandeq, + &&boreq, + &&bxoreq, + &&addeqc, + &&subeqc, + &&muleqc, + &&diveqc, + &&lnkeqc, + &&addecp, + &&subecp, + &&mulecp, + &&divecp, + &&lnkecp, + &&meq, + &&eq, + &&neq, + &&less, + &&leq, + &&grt, + &&geq, + &&lessc, + &&leqc, + &&grtc, + &&geqc, + &&pop, + &&jmp, + &&jt, + &&jf, + &&cnt, + &&findex, + &&feach, + &&callg, + &&calll, + &&upval, + &&callv, + &&callvi, + &&callh, + &&callfv, + &&callfh, + &&callb, + &&slcbeg, + &&slcend, + &&slc, + &&slc2, + &&mcallg, + &&mcalll, + &&mupval, + &&mcallv, + &&mcallh, + &&ret }; std::vector code; for(const auto& i : gen.codes()) { @@ -462,49 +528,93 @@ void vm::run(const codegen& gen, #else typedef void (vm::*nafunc)(); const nafunc oprs[] = { - nullptr, &vm::o_repl, - &vm::o_intl, &vm::o_loadg, - &vm::o_loadl, &vm::o_loadu, - &vm::o_pnum, &vm::o_pnil, - &vm::o_pstr, &vm::o_newv, - &vm::o_newh, &vm::o_newf, - &vm::o_happ, &vm::o_para, - &vm::o_deft, &vm::o_dyn, - &vm::o_lnot, &vm::o_usub, - &vm::o_bnot, &vm::o_btor, - &vm::o_btxor, &vm::o_btand, - &vm::o_add, &vm::o_sub, - &vm::o_mul, &vm::o_div, - &vm::o_lnk, &vm::o_addc, - &vm::o_subc, &vm::o_mulc, - &vm::o_divc, &vm::o_lnkc, - &vm::o_addeq, &vm::o_subeq, - &vm::o_muleq, &vm::o_diveq, - &vm::o_lnkeq, &vm::o_bandeq, - &vm::o_boreq, &vm::o_bxoreq, - &vm::o_addeqc, &vm::o_subeqc, - &vm::o_muleqc, &vm::o_diveqc, - &vm::o_lnkeqc, &vm::o_addecp, - &vm::o_subecp, &vm::o_mulecp, - &vm::o_divecp, &vm::o_lnkecp, - &vm::o_meq, &vm::o_eq, - &vm::o_neq, &vm::o_less, - &vm::o_leq, &vm::o_grt, - &vm::o_geq, &vm::o_lessc, - &vm::o_leqc, &vm::o_grtc, - &vm::o_geqc, &vm::o_pop, - &vm::o_jmp, &vm::o_jt, - &vm::o_jf, &vm::o_cnt, - &vm::o_findex, &vm::o_feach, - &vm::o_callg, &vm::o_calll, - &vm::o_upval, &vm::o_callv, - &vm::o_callvi, &vm::o_callh, - &vm::o_callfv, &vm::o_callfh, - &vm::o_callb, &vm::o_slcbeg, - &vm::o_slcend, &vm::o_slc, - &vm::o_slc2, &vm::o_mcallg, - &vm::o_mcalll, &vm::o_mupval, - &vm::o_mcallv, &vm::o_mcallh, + nullptr, + &vm::o_repl, + &vm::o_intl, + &vm::o_loadg, + &vm::o_loadl, + &vm::o_loadu, + &vm::o_dup, + &vm::o_pnum, + &vm::o_pnil, + &vm::o_pstr, + &vm::o_newv, + &vm::o_newh, + &vm::o_newf, + &vm::o_happ, + &vm::o_para, + &vm::o_deft, + &vm::o_dyn, + &vm::o_lnot, + &vm::o_usub, + &vm::o_bnot, + &vm::o_btor, + &vm::o_btxor, + &vm::o_btand, + &vm::o_add, + &vm::o_sub, + &vm::o_mul, + &vm::o_div, + &vm::o_lnk, + &vm::o_addc, + &vm::o_subc, + &vm::o_mulc, + &vm::o_divc, + &vm::o_lnkc, + &vm::o_addeq, + &vm::o_subeq, + &vm::o_muleq, + &vm::o_diveq, + &vm::o_lnkeq, + &vm::o_bandeq, + &vm::o_boreq, + &vm::o_bxoreq, + &vm::o_addeqc, + &vm::o_subeqc, + &vm::o_muleqc, + &vm::o_diveqc, + &vm::o_lnkeqc, + &vm::o_addecp, + &vm::o_subecp, + &vm::o_mulecp, + &vm::o_divecp, + &vm::o_lnkecp, + &vm::o_meq, + &vm::o_eq, + &vm::o_neq, + &vm::o_less, + &vm::o_leq, + &vm::o_grt, + &vm::o_geq, + &vm::o_lessc, + &vm::o_leqc, + &vm::o_grtc, + &vm::o_geqc, + &vm::o_pop, + &vm::o_jmp, + &vm::o_jt, + &vm::o_jf, + &vm::o_cnt, + &vm::o_findex, + &vm::o_feach, + &vm::o_callg, + &vm::o_calll, + &vm::o_upval, + &vm::o_callv, + &vm::o_callvi, + &vm::o_callh, + &vm::o_callfv, + &vm::o_callfh, + &vm::o_callb, + &vm::o_slcbeg, + &vm::o_slcend, + &vm::o_slc, + &vm::o_slc2, + &vm::o_mcallg, + &vm::o_mcalll, + &vm::o_mupval, + &vm::o_mcallv, + &vm::o_mcallh, &vm::o_ret }; std::vector code; @@ -551,6 +661,7 @@ intl: exec_nodie(o_intl ); // -0 loadg: exec_nodie(o_loadg ); // -1 loadl: exec_nodie(o_loadl ); // -1 loadu: exec_nodie(o_loadu ); // -1 +dup: exec_check(o_dup ); // +1 pnum: exec_check(o_pnum ); // +1 pnil: exec_check(o_pnil ); // +1 pstr: exec_check(o_pstr ); // +1 diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 8ed1109..f253075 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -93,6 +93,7 @@ protected: inline void o_loadg(); inline void o_loadl(); inline void o_loadu(); + inline void o_dup(); inline void o_pnum(); inline void o_pnil(); inline void o_pstr(); @@ -248,6 +249,11 @@ inline void vm::o_loadu() { .upval()[imm[ctx.pc]&0xffff] = (ctx.top--)[0]; } +inline void vm::o_dup() { + ctx.top[1] = ctx.top[0]; + ++ctx.top; +} + inline void vm::o_pnum() { (++ctx.top)[0] = var::num(const_number[imm[ctx.pc]]); } diff --git a/test/scalar.nas b/test/scalar.nas index ca8b959..5a085de 100644 --- a/test/scalar.nas +++ b/test/scalar.nas @@ -273,4 +273,10 @@ func() { var b = nil; var c = nil; println(a??b??c??"a??b??c?? -> should print this text"); + + var a = {b: 2}; + println(a?.b); # should be 2 + + var a = nil; + println(a?.b); # should be nil }();