#pragma once #include "nasal_err.h" #include "nasal_opcode.h" #include "nasal_ast.h" #include "ast_visitor.h" #include "symbol_finder.h" #include "nasal_parse.h" #include "nasal_import.h" #include "natives/builtin.h" #include "natives/coroutine.h" #include "natives/bits_lib.h" #include "natives/math_lib.h" #include "natives/fg_props.h" #include "natives/io_lib.h" #include "natives/json_lib.h" #include "natives/dylib_lib.h" #include "natives/regex_lib.h" #include "natives/unix_lib.h" #include "natives/subprocess.h" #include <iomanip> #include <list> #include <stack> #include <unordered_map> #include <unordered_set> #ifdef _MSC_VER #pragma warning (disable:4244) #pragma warning (disable:4267) #endif namespace nasal { class codegen { private: error err; // repl output flag, will generate op_repl to output stack top value if true bool flag_need_repl_output = false; // limit mode flag bool flag_limited_mode = false; // under limited mode, unsafe system api will be banned const std::unordered_set<std::string> unsafe_system_api = { // builtin "__system", "__input", "__terminal_size", // io "__fout", "__open", "__write", "__stat" // bits "__fld", "__sfld", "__setfld", "__buf", // fg "__logprint", // dylib "__dlopen", "__dlclose", "__dlcallv", "__dlcall", // unix "__chdir", "__environ", "__getcwd", "__getenv", // subprocess "__subprocess_create", "__subprocess_active", "__subprocess_terminate" }; // file mapper for file -> index std::unordered_map<std::string, usize> file_map; void init_file_map(const std::vector<std::string>&); // used for generate pop in return expression std::vector<u32> in_foreach_loop_level; // constant numbers and strings std::unordered_map<f64, u64> const_number_map; std::unordered_map<std::string, u64> const_string_map; std::vector<f64> const_number_table; std::vector<std::string> const_string_table; // native functions std::vector<nasal_builtin_table> native_function; std::unordered_map<std::string, usize> native_function_mapper; void load_native_function_table(nasal_builtin_table*); void init_native_function(); // generated opcodes std::vector<opcode> code; // used to store jmp operands index, to fill the jump address back std::list<std::vector<u64>> continue_ptr; std::list<std::vector<u64>> break_ptr; // symbol table // global : max VM_STACK_DEPTH-1 values std::unordered_map<std::string, u64> global; // nasal namespace // stores all global symbols of each file std::unordered_map<std::string, std::unordered_set<std::string>> nasal_namespace; // local : max 32768 upvalues 65536 values // but in fact local scope also has less than VM_STACK_DEPTH value std::list<std::unordered_map<std::string, u64>> local; void check_id_exist(identifier*); void die(const std::string& info, expr* node) { err.err("code", node->get_location(), info); } void regist_number(const f64); void regist_string(const std::string&); void find_symbol(code_block*); void regist_symbol(const std::string&); i64 local_symbol_find(const std::string&); i64 global_symbol_find(const std::string&); i64 upvalue_symbol_find(const std::string&); void emit(u8, u64, const span&); void number_gen(number_literal*); void string_gen(string_literal*); void bool_gen(bool_literal*); void vector_gen(vector_expr*); void hash_gen(hash_expr*); void func_gen(function*); 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*); void mcall_identifier(identifier*); void mcall_vec(call_vector*); void mcall_hash(call_hash*); void multi_def(definition_expr*); void single_def(definition_expr*); void definition_gen(definition_expr*); void assignment_expression(assignment_expr*); void gen_assignment_equal_statement(assignment_expr*); void replace_left_assignment_with_load(const span&); void assignment_statement(assignment_expr*); void multi_assign_gen(multi_assign*); void cond_gen(condition_expr*); void loop_gen(expr*); void load_continue_break(u64, u64); void while_gen(while_expr*); void for_gen(for_expr*); void forei_gen(forei_expr*); void statement_generation(expr*); void or_gen(binary_operator*); void and_gen(binary_operator*); void unary_gen(unary_operator*); void binary_gen(binary_operator*); void null_chain_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*); public: const auto& strs() const {return const_string_table;} const auto& nums() const {return const_number_table;} const auto& natives() const {return native_function;} const auto& codes() const {return code;} const auto& globals() const {return global;} public: codegen() = default; const error& compile(parse&, linker&, bool, bool); void print(std::ostream&); void symbol_dump(std::ostream&) const; }; }