diff --git a/clients/vscode-hlasmplugin/CHANGELOG.md b/clients/vscode-hlasmplugin/CHANGELOG.md index 300a44dd8..1806ece9e 100644 --- a/clients/vscode-hlasmplugin/CHANGELOG.md +++ b/clients/vscode-hlasmplugin/CHANGELOG.md @@ -5,6 +5,9 @@ #### Added - USING and DROP support +#### Fixed +- Behavior of currently supported subscripted system variables corrected + ## [1.0.0](https://github.com/eclipse/che-che4z-lsp-for-hlasm/compare/0.15.1...1.0.0) (2022-01-31) #### Added diff --git a/parser_library/src/compiler_options.h b/parser_library/src/compiler_options.h index 1bc65109e..0c5e9adcd 100644 --- a/parser_library/src/compiler_options.h +++ b/parser_library/src/compiler_options.h @@ -27,6 +27,9 @@ struct asm_option static const std::string system_id_default; std::string system_id = system_id_default; + + static const unsigned int sysopt_rent_default = 0; + unsigned int sysopt_rent = sysopt_rent_default; }; } // namespace hlasm_plugin::parser_library #endif diff --git a/parser_library/src/context/hlasm_context.cpp b/parser_library/src/context/hlasm_context.cpp index a67879475..caf5d020a 100644 --- a/parser_library/src/context/hlasm_context.cpp +++ b/parser_library/src/context/hlasm_context.cpp @@ -57,85 +57,105 @@ hlasm_context::instruction_storage hlasm_context::init_instruction_map(id_storag return instr_map; } +namespace { +macro_data_ptr create_macro_data(std::string value) +{ + return std::make_unique(std::move(value)); +} + +macro_data_ptr create_macro_data(std::vector value) +{ + std::vector data; + for (auto& single_data : value) + { + data.push_back(std::make_unique(std::move(single_data))); + } + + return std::make_unique(std::move(data)); +} + +template +std::pair create_system_variable( + id_storage& ids, std::string name, DATA mac_data, bool is_global) +{ + auto id = ids.add(std::move(name)); + + auto var = std::make_shared(id, create_macro_data(std::move(mac_data)), is_global); + + return { id, std::move(var) }; +} + +} // namespace + void hlasm_context::add_system_vars_to_scope(code_scope& scope) { if (scope.is_in_macro()) { { - auto SYSECT = ids().add("SYSECT"); - - auto val_sect = std::make_shared>(SYSECT, true, false); auto sect_name = ord_ctx.current_section() ? ord_ctx.current_section()->name : id_storage::empty_id; - val_sect->set_value(*sect_name); - scope.variables.insert({ SYSECT, val_sect }); + + scope.system_variables.insert( + create_system_variable(ids(), "SYSECT", *sect_name, false)); } { - auto SYSNDX = ids().add("SYSNDX"); - - auto val_ndx = std::make_shared>(SYSNDX, true, false); - std::string value = std::to_string(SYSNDX_); if (auto value_len = value.size(); value_len < 4) value.insert(0, 4 - value_len, '0'); - val_ndx->set_value(std::move(value)); - scope.variables.insert({ SYSNDX, val_ndx }); + scope.system_variables.insert( + create_system_variable(ids(), "SYSNDX", std::move(value), false)); } { - auto SYSSTYP = ids().add("SYSSTYP"); + std::string value = ""; - auto val_styp = std::make_shared>(SYSSTYP, true, false); if (ord_ctx.current_section()) { switch (ord_ctx.current_section()->kind) { case context::section_kind::COMMON: - val_styp->set_value("COM"); + value = "COM"; break; case context::section_kind::DUMMY: - val_styp->set_value("DSECT"); + value = "DSECT"; break; case context::section_kind::READONLY: - val_styp->set_value("RSECT"); + value = "RSECT"; break; case context::section_kind::EXECUTABLE: - val_styp->set_value("CSECT"); + value = "CSECT"; break; default: break; } } - scope.variables.insert({ SYSSTYP, val_styp }); + + scope.system_variables.insert( + create_system_variable(ids(), "SYSSTYP", std::move(value), false)); } { - auto SYSLOC = ids().add("SYSLOC"); - - auto var = std::make_shared>(SYSLOC, true, false); + std::string location_counter_name = ""; if (ord_ctx.current_section()) { - var->set_value(*ord_ctx.current_section()->current_location_counter().name); + location_counter_name = *ord_ctx.current_section()->current_location_counter().name; } - scope.variables.insert({ SYSLOC, var }); + + scope.system_variables.insert( + create_system_variable(ids(), "SYSLOC", std::move(location_counter_name), false)); } { - auto SYSNEST = ids().add("SYSNEST"); - - auto var = std::make_shared>(SYSNEST, true, false); + std::string value = std::to_string(scope_stack_.size() - 1); - var->set_value((context::A_t)scope_stack_.size() - 1); - - scope.variables.insert({ SYSNEST, var }); + scope.system_variables.insert( + create_system_variable(ids(), "SYSNEST", std::move(value), false)); } { - auto SYSMAC = ids().add("SYSMAC"); - - std::vector data; + std::vector data; for (auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) { @@ -144,117 +164,106 @@ void hlasm_context::add_system_vars_to_scope(code_scope& scope) tmp = *it->this_macro->id; else tmp = "OPEN CODE"; - data.push_back(std::make_unique(std::move(tmp))); + data.push_back(std::move(tmp)); } - macro_data_ptr mac_data = std::make_unique(std::move(data)); - - sys_sym_ptr var = std::make_shared(SYSMAC, std::move(mac_data), false); - - scope.system_variables.insert({ SYSMAC, std::move(var) }); + scope.system_variables.insert( + create_system_variable(ids(), "SYSMAC", std::move(data), false)); } } } -void hlasm_context::add_global_system_vars(code_scope& scope) +void hlasm_context::add_global_system_var_to_scope(id_storage& ids, const std::string& name, code_scope& scope) const { - auto SYSDATC = ids().add("SYSDATC"); - auto SYSDATE = ids().add("SYSDATE"); - auto SYSTIME = ids().add("SYSTIME"); - auto SYSPARM = ids().add("SYSPARM"); - auto SYSOPT_RENT = ids().add("SYSOPT_RENT"); - auto SYSTEM_ID = ids().add("SYSTEM_ID"); + auto id = ids.add(name); - if (!is_in_macro()) - { - auto datc = std::make_shared>(SYSDATC, true, true); - auto date = std::make_shared>(SYSDATE, true, true); - auto time = std::make_shared>(SYSTIME, true, true); + auto glob = globals_.find(id); - auto tmp_now = std::time(0); - auto now = std::localtime(&tmp_now); + sys_sym_ptr temp = std::dynamic_pointer_cast(glob->second); - std::string datc_val; - std::string date_val; - datc_val.reserve(8); - date_val.reserve(8); - auto year = std::to_string(now->tm_year + 1900); - datc_val.append(year); + scope.system_variables.try_emplace(glob->second->id, temp); +} - if (now->tm_mon + 1 < 10) +void hlasm_context::add_global_system_vars(code_scope& scope) +{ + if (!is_in_macro()) + { { - datc_val.push_back('0'); - date_val.push_back('0'); - } + auto tmp_now = std::time(0); + auto now = std::localtime(&tmp_now); - datc_val.append(std::to_string(now->tm_mon + 1)); + std::string datc_val; + std::string date_val; + datc_val.reserve(8); + date_val.reserve(8); + auto year = std::to_string(now->tm_year + 1900); + datc_val.append(year); - date_val.append(std::to_string(now->tm_mon + 1)); - date_val.push_back('/'); + if (now->tm_mon + 1 < 10) + { + datc_val.push_back('0'); + date_val.push_back('0'); + } - if (now->tm_mday < 10) - { - datc_val.push_back('0'); - date_val.push_back('0'); - } + datc_val.append(std::to_string(now->tm_mon + 1)); - datc_val.append(std::to_string(now->tm_mday)); + date_val.append(std::to_string(now->tm_mon + 1)); + date_val.push_back('/'); - date_val.append(std::to_string(now->tm_mday)); - date_val.push_back('/'); + if (now->tm_mday < 10) + { + datc_val.push_back('0'); + date_val.push_back('0'); + } - datc->set_value(std::move(datc_val)); + datc_val.append(std::to_string(now->tm_mday)); - date_val.append(year.c_str() + 2); - date->set_value(std::move(date_val)); + date_val.append(std::to_string(now->tm_mday)); + date_val.push_back('/'); + date_val.append(year.c_str() + 2); - globals_.insert({ SYSDATC, datc }); - globals_.insert({ SYSDATE, date }); + { + globals_.insert(create_system_variable(ids(), "SYSDATC", std::move(datc_val), true)); + } - std::string time_val; - if (now->tm_hour < 10) - time_val.push_back('0'); - time_val.append(std::to_string(now->tm_hour)); - time_val.push_back(':'); - if (now->tm_min < 10) - time_val.push_back('0'); - time_val.append(std::to_string(now->tm_min)); + { + globals_.insert(create_system_variable(ids(), "SYSDATE", std::move(date_val), true)); + } - time->set_value(std::move(time_val)); - globals_.insert({ SYSTIME, time }); + { + std::string value; + if (now->tm_hour < 10) + value.push_back('0'); + value.append(std::to_string(now->tm_hour)); + value.push_back(':'); + if (now->tm_min < 10) + value.push_back('0'); + value.append(std::to_string(now->tm_min)); + + globals_.insert(create_system_variable(ids(), "SYSTIME", std::move(value), true)); + } + } { - auto val = std::make_shared>(SYSPARM, true, true); - - val->set_value(asm_options_.sysparm); - - globals_.insert({ SYSPARM, std::move(val) }); + globals_.insert(create_system_variable(ids(), "SYSPARM", asm_options_.sysparm, true)); } + { - auto val = std::make_shared>(SYSOPT_RENT, true, true); - globals_.insert({ SYSOPT_RENT, std::move(val) }); + globals_.insert(create_system_variable( + ids(), "SYSOPT_RENT", std::to_string(asm_options_.sysopt_rent), true)); } - { - auto val = std::make_shared>(SYSTEM_ID, true, true); - - val->set_value(asm_options_.system_id); - globals_.insert({ SYSTEM_ID, std::move(val) }); + { + globals_.insert(create_system_variable(ids(), "SYSTEM_ID", asm_options_.system_id, true)); } } - auto glob = globals_.find(SYSDATC); - scope.variables.insert({ glob->second->id, glob->second }); - glob = globals_.find(SYSDATE); - scope.variables.insert({ glob->second->id, glob->second }); - glob = globals_.find(SYSTIME); - scope.variables.insert({ glob->second->id, glob->second }); - glob = globals_.find(SYSPARM); - scope.variables.insert({ glob->second->id, glob->second }); - glob = globals_.find(SYSOPT_RENT); - scope.variables.insert({ glob->second->id, glob->second }); - glob = globals_.find(SYSTEM_ID); - scope.variables.insert({ glob->second->id, glob->second }); + add_global_system_var_to_scope(ids(), "SYSDATC", scope); + add_global_system_var_to_scope(ids(), "SYSDATE", scope); + add_global_system_var_to_scope(ids(), "SYSTIME", scope); + add_global_system_var_to_scope(ids(), "SYSPARM", scope); + add_global_system_var_to_scope(ids(), "SYSOPT_RENT", scope); + add_global_system_var_to_scope(ids(), "SYSTEM_ID", scope); } bool hlasm_context::is_opcode(id_index symbol) const @@ -458,7 +467,7 @@ std::vector hlasm_context::whole_copy_stack() const void hlasm_context::fill_metrics_files() { metrics.files = visited_files_.size(); } -const code_scope::set_sym_storage& hlasm_context::globals() const { return globals_; } +const hlasm_context::global_variable_storage& hlasm_context::globals() const { return globals_; } var_sym_ptr hlasm_context::get_var_sym(id_index name) const { diff --git a/parser_library/src/context/hlasm_context.h b/parser_library/src/context/hlasm_context.h index 51bfbf13c..3ff066e63 100644 --- a/parser_library/src/context/hlasm_context.h +++ b/parser_library/src/context/hlasm_context.h @@ -47,9 +47,11 @@ class hlasm_context using copy_member_storage = std::unordered_map; using instruction_storage = std::unordered_map; using opcode_map = std::unordered_map; + using global_variable_storage = std::unordered_map; // storage of global variables - code_scope::set_sym_storage globals_; + global_variable_storage globals_; + // storage of defined macros macro_storage macros_; // storage of copy members @@ -88,6 +90,8 @@ class hlasm_context size_t m_ainsert_id = 0; bool m_end_reached = false; + void add_global_system_var_to_scope(id_storage& ids, const std::string& name, code_scope& scope) const; + void add_system_vars_to_scope(code_scope& scope); void add_global_system_vars(code_scope& scope); @@ -161,7 +165,7 @@ class hlasm_context void fill_metrics_files(); // return map of global set vars - const code_scope::set_sym_storage& globals() const; + const global_variable_storage& globals() const; // return variable symbol in current scope // returns empty shared_ptr if there is none in the current scope @@ -245,14 +249,17 @@ class hlasm_context if (auto glob = globals_.find(id); glob != globals_.end()) { - scope->variables.insert({ id, glob->second }); - return glob->second; + set_sym_ptr var = std::dynamic_pointer_cast>(glob->second); + assert(var); + + scope->variables.try_emplace(id, var); + return var; } auto val = std::make_shared>(id, is_scalar, true); - globals_.insert({ id, val }); - scope->variables.insert({ id, val }); + globals_.try_emplace(id, val); + scope->variables.try_emplace(id, val); return val; } @@ -270,7 +277,7 @@ class hlasm_context set_sym_ptr val(std::make_shared>(id, is_scalar, false)); - scope->variables.insert({ id, val }); + scope->variables.try_emplace(id, val); return val; } diff --git a/parser_library/src/context/macro.cpp b/parser_library/src/context/macro.cpp index 5491c5b07..fe842780a 100644 --- a/parser_library/src/context/macro.cpp +++ b/parser_library/src/context/macro.cpp @@ -149,7 +149,7 @@ macro_invo_ptr macro_definition::call( } named_cpy.emplace(syslist_name, - std::make_unique( + std::make_unique( syslist_name, std::make_unique(std::move(syslist)), false)); return std::make_shared( diff --git a/parser_library/src/context/variables/macro_param.cpp b/parser_library/src/context/variables/macro_param.cpp index f86563f71..cffee9c21 100644 --- a/parser_library/src/context/variables/macro_param.cpp +++ b/parser_library/src/context/variables/macro_param.cpp @@ -49,7 +49,7 @@ const C_t& macro_param_base::get_value(const std::vector& offset) const return tmp->get_value(); } -const C_t& macro_param_base::get_value(size_t idx) const { return real_data()->get_ith(idx - 1)->get_value(); } +const C_t& macro_param_base::get_value(size_t idx) const { return real_data()->get_ith(idx)->get_value(); } const C_t& macro_param_base::get_value() const { return real_data()->get_value(); } diff --git a/parser_library/src/context/variables/system_variable.cpp b/parser_library/src/context/variables/system_variable.cpp index a7d7c5a5d..b9bfea1b4 100644 --- a/parser_library/src/context/variables/system_variable.cpp +++ b/parser_library/src/context/variables/system_variable.cpp @@ -24,20 +24,21 @@ system_variable::system_variable(id_index name, macro_data_ptr value, bool is_gl const C_t& system_variable::get_value(const std::vector& offset) const { return get_data(offset)->get_value(); } -const C_t& system_variable::get_value(size_t idx) const { return macro_param_base::get_value(idx + 1); } +const C_t& system_variable::get_value(size_t idx) const { return macro_param_base::get_value(idx); } const C_t& system_variable::get_value() const { return macro_param_base::get_value(0); } const macro_param_data_component* system_variable::get_data(const std::vector& offset) const { - const macro_param_data_component* tmp = data_.get(); - - for (size_t i = 0; i < offset.size(); ++i) + for (auto subscript : offset) { - tmp = tmp->get_ith(offset[i] - (i == 0 ? 0 : 1)); + if (1 != subscript) + { + return macro_param_data_component::dummy.get(); + } } - return tmp; + return data_->get_ith(0); } A_t system_variable::number(std::vector offset) const @@ -54,7 +55,7 @@ A_t system_variable::number(std::vector offset) const A_t system_variable::count(std::vector offset) const { if (offset.empty()) - return (A_t)data_->get_ith(1)->get_value().size(); + return (A_t)data_->get_ith(0)->get_value().size(); const macro_param_data_component* tmp = real_data(); for (size_t i = 0; i < offset.size(); ++i) @@ -86,9 +87,9 @@ const C_t& system_variable_sysmac::get_value(const std::vector& offset) return get_data({ 0 })->get_value(); } -const C_t& system_variable_sysmac::get_value(size_t idx) const { return get_data({ idx })->get_value(); } +const C_t& system_variable_sysmac::get_value(size_t idx) const { return system_variable::get_value(idx); } -const C_t& system_variable_sysmac::get_value() const { return get_data({ 0 })->get_value(); } +const C_t& system_variable_sysmac::get_value() const { return system_variable::get_value(); } const macro_param_data_component* system_variable_sysmac::get_data(const std::vector& offset) const { @@ -97,5 +98,24 @@ const macro_param_data_component* system_variable_sysmac::get_data(const std::ve if (!offset.empty()) tmp = tmp->get_ith(offset.back()); // what the original seems to do + return tmp; +} + +const macro_param_data_component* system_variable_syslist::get_data(const std::vector& offset) const +{ + const macro_param_data_component* tmp = real_data(); + + if (offset.empty()) + { + tmp = tmp->get_ith(1); + } + else + { + for (size_t i = 0; i < offset.size(); ++i) + { + tmp = tmp->get_ith(offset[i] - (i == 0 ? 0 : 1)); + } + } + return tmp; } \ No newline at end of file diff --git a/parser_library/src/context/variables/system_variable.h b/parser_library/src/context/variables/system_variable.h index 90d1839b1..3a4dda5f7 100644 --- a/parser_library/src/context/variables/system_variable.h +++ b/parser_library/src/context/variables/system_variable.h @@ -64,6 +64,16 @@ class system_variable_sysmac final : public system_variable const macro_param_data_component* get_data(const std::vector& offset) const override; }; +// SYSLIST extras +class system_variable_syslist final : public system_variable +{ +public: + using system_variable::system_variable; + + // SYSLIST special behavior + const macro_param_data_component* get_data(const std::vector& offset) const override; +}; + } // namespace hlasm_plugin::parser_library::context #endif diff --git a/parser_library/src/diagnostic.cpp b/parser_library/src/diagnostic.cpp index 7ee3f2739..c89069df4 100644 --- a/parser_library/src/diagnostic.cpp +++ b/parser_library/src/diagnostic.cpp @@ -2059,6 +2059,27 @@ diagnostic_op diagnostic_op::error_E073(const range& range) diagnostic_severity::error, "E073", "Illegal START instruction - CSECT already exists.", range); } +diagnostic_op diagnostic_op::error_E074(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "E074", "NULL operation code has been generated.", range); +} + +diagnostic_op diagnostic_op::error_E075(std::string_view message, const range& range) +{ + return diagnostic_op(diagnostic_severity::error, + "E075", + concat("The name field ", + message, + " contains unexpected characters. Valid characters are A-Z, 0-9, $, #, @ and _"), + range); +} + +diagnostic_op diagnostic_op::error_E076(const range& range) +{ + return diagnostic_op( + diagnostic_severity::error, "E076", "SYSLIST must be subscripted; using default subscript is 1", range); +} + diagnostic_op diagnostic_op::warning_W010(std::string_view message, const range& range) { return diagnostic_op(diagnostic_severity::warning, "W010", concat(message, " not expected"), range); diff --git a/parser_library/src/diagnostic.h b/parser_library/src/diagnostic.h index 8ef505ca0..340664622 100644 --- a/parser_library/src/diagnostic.h +++ b/parser_library/src/diagnostic.h @@ -590,6 +590,12 @@ struct diagnostic_op static diagnostic_op error_E073(const range& range); + static diagnostic_op error_E074(const range& range); + + static diagnostic_op error_E075(std::string_view message, const range& range); + + static diagnostic_op error_E076(const range& range); + static diagnostic_op warning_W010(std::string_view message, const range& range); static diagnostic_op warning_W011(const range& range); diff --git a/parser_library/src/processing/context_manager.cpp b/parser_library/src/processing/context_manager.cpp index 29dad6847..5b3a04e02 100644 --- a/parser_library/src/processing/context_manager.cpp +++ b/parser_library/src/processing/context_manager.cpp @@ -31,7 +31,7 @@ context_manager::context_manager(const expressions::evaluation_context* eval_ctx {} context::SET_t context_manager::get_var_sym_value( - context::id_index name, const std::vector& subscript, range symbol_range) const + context::id_index name, const std::vector& subscript, const range& symbol_range) const { auto var = hlasm_ctx.get_var_sym(name); @@ -87,7 +87,7 @@ context::SET_t context_manager::get_var_sym_value( return context::SET_t(); } -context::id_index context_manager::get_symbol_name(const std::string& symbol, range symbol_range) const +context::id_index context_manager::get_symbol_name(const std::string& symbol, const range& symbol_range) const { auto [valid, id] = hlasm_ctx.try_get_symbol_name(symbol); if (!valid) @@ -96,7 +96,7 @@ context::id_index context_manager::get_symbol_name(const std::string& symbol, ra } bool context_manager::test_symbol_for_read( - const context::var_sym_ptr& var, const std::vector& subscript, range symbol_range) const + const context::var_sym_ptr& var, const std::vector& subscript, const range& symbol_range) const { if (!var) { @@ -106,37 +106,106 @@ bool context_manager::test_symbol_for_read( if (auto set_sym = var->access_set_symbol_base()) { - if (subscript.size() > 1) - { - add_diagnostic( - diagnostic_op::error_E020("variable symbol subscript", symbol_range)); // error - too many operands - return false; - } + return test_set_symbol_for_read(set_sym, subscript, symbol_range); + } + else if (auto mac_par = var->access_macro_param_base()) + { + return test_macro_param_for_read(mac_par, subscript, symbol_range); + } - if ((set_sym->is_scalar && subscript.size() == 1) || (!set_sym->is_scalar && subscript.size() == 0)) - { - add_diagnostic( - diagnostic_op::error_E013("subscript error", symbol_range)); // error - inconsistent format of subcript - return false; - } + return true; +} - if (!set_sym->is_scalar && (subscript.front() < 1)) +bool context_manager::test_set_symbol_for_read(const context::set_symbol_base* set_sym, + const std::vector& subscript, + const range& symbol_range) const +{ + if (subscript.size() > 1) + { + add_diagnostic( + diagnostic_op::error_E020("variable symbol subscript", symbol_range)); // error - too many operands + return false; + } + + if ((set_sym->is_scalar && subscript.size() == 1) || (!set_sym->is_scalar && subscript.empty())) + { + add_diagnostic( + diagnostic_op::error_E013("subscript error", symbol_range)); // error - inconsistent format of subcript + return false; + } + + if (!set_sym->is_scalar && (subscript.front() < 1)) + { + add_diagnostic(diagnostic_op::error_E012( + "subscript value has to be 1 or more", symbol_range)); // error - subscript is less than 1 + return false; + } + + return true; +} + +bool context_manager::test_macro_param_for_read(const context::macro_param_base* mac_par, + const std::vector& subscript, + const range& symbol_range) const +{ + if (dynamic_cast(mac_par)) + { + return test_syslist_for_read(subscript, symbol_range); + } + else if (dynamic_cast(mac_par)) + { + return true; + } + else + { + return test_general_system_variable_for_read(subscript, symbol_range); + } +} + +bool context_manager::test_syslist_for_read(const std::vector& subscript, const range& symbol_range) const +{ + if (subscript.empty()) + { + add_diagnostic(diagnostic_op::error_E076(symbol_range)); // error - SYSLIST is not subscripted + } + + for (size_t i = 0; i < subscript.size(); ++i) + { + if (subscript[i] < 1) { + // if subscript = 0, ok + if (i == 0 && subscript[i] == 0) + continue; + add_diagnostic(diagnostic_op::error_E012( "subscript value has to be 1 or more", symbol_range)); // error - subscript is less than 1 return false; } } - else if (auto mac_par = var->access_macro_param_base()) + + return true; +} + +bool context_manager::test_general_system_variable_for_read( + const std::vector& subscript, const range& symbol_range) const +{ + if (subscript.empty()) { - for (size_t i = 0; i < subscript.size(); ++i) + return true; + } + + if (0 == subscript[0]) + { + add_diagnostic(diagnostic_op::error_E012( + "subscript value has to be 1 or more", symbol_range)); // error - subscript is less than 1 + return false; + } + else if (1 == subscript[0]) + { + for (size_t i = 1; i < subscript.size(); ++i) { - if (subscript[i] < 1) + if (0 == subscript[i]) { - // if syslist and subscript = 0, ok - if (i == 0 && subscript[i] == 0 && dynamic_cast(mac_par)) - continue; - add_diagnostic(diagnostic_op::error_E012( "subscript value has to be 1 or more", symbol_range)); // error - subscript is less than 1 return false; diff --git a/parser_library/src/processing/context_manager.h b/parser_library/src/processing/context_manager.h index 7d0b67460..25e1950b4 100644 --- a/parser_library/src/processing/context_manager.h +++ b/parser_library/src/processing/context_manager.h @@ -38,17 +38,30 @@ class context_manager : public diagnosable_ctx explicit context_manager(const expressions::evaluation_context* eval_ctx); context::SET_t get_var_sym_value( - context::id_index name, const std::vector& subscript, range symbol_range) const; + context::id_index name, const std::vector& subscript, const range& symbol_range) const; - context::id_index get_symbol_name(const std::string& symbol, range symbol_range) const; + context::id_index get_symbol_name(const std::string& symbol, const range& symbol_range) const; bool test_symbol_for_read( - const context::var_sym_ptr& var, const std::vector& subscript, range symbol_range) const; + const context::var_sym_ptr& var, const std::vector& subscript, const range& symbol_range) const; void collect_diags() const override; private: void add_diagnostic(diagnostic_s diagnostic) const override; + + bool test_set_symbol_for_read(const context::set_symbol_base* set_sym, + const std::vector& subscript, + const range& symbol_range) const; + + bool test_macro_param_for_read(const context::macro_param_base* mac_par, + const std::vector& subscript, + const range& symbol_range) const; + + bool test_syslist_for_read(const std::vector& subscript, const range& symbol_range) const; + + bool test_general_system_variable_for_read( + const std::vector& subscript, const range& symbol_range) const; }; } // namespace hlasm_plugin::parser_library::processing diff --git a/parser_library/src/processing/statement_processors/ordinary_processor.cpp b/parser_library/src/processing/statement_processors/ordinary_processor.cpp index 058c7edee..abb4dd91f 100644 --- a/parser_library/src/processing/statement_processors/ordinary_processor.cpp +++ b/parser_library/src/processing/statement_processors/ordinary_processor.cpp @@ -14,6 +14,7 @@ #include "ordinary_processor.h" +#include #include #include "checking/instruction_checker.h" @@ -319,7 +320,19 @@ context::id_index ordinary_processor::resolve_instruction( ; tmp.erase(0U, i); - if (tmp.find(' ') != std::string::npos) + static const std::regex regex(R"([ \$_#@a-zA-Z0-9]*)"); + + if (tmp.empty()) + { + add_diagnostic(diagnostic_op::error_E074(instruction_range)); + return context::id_storage::empty_id; + } + else if (!std::regex_match(tmp, regex)) + { + add_diagnostic(diagnostic_op::error_E075(tmp, instruction_range)); + return context::id_storage::empty_id; + } + else if (tmp.find(' ') != std::string::npos) { add_diagnostic(diagnostic_op::error_E067(instruction_range)); return context::id_storage::empty_id; diff --git a/parser_library/test/CMakeLists.txt b/parser_library/test/CMakeLists.txt index cd0b01b14..eb3730f40 100644 --- a/parser_library/test/CMakeLists.txt +++ b/parser_library/test/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(library_test PRIVATE common_testing.h diagnosable_ctx_test.cpp diagnostics_check_test.cpp + diagnostics_sysvar_test.cpp gtest_stringers.h message_consumer_mock.h metrics_test.cpp diff --git a/parser_library/test/context/CMakeLists.txt b/parser_library/test/context/CMakeLists.txt index f09deaca2..c10003e5f 100644 --- a/parser_library/test/context/CMakeLists.txt +++ b/parser_library/test/context/CMakeLists.txt @@ -18,6 +18,7 @@ target_sources(library_test PRIVATE literals_test.cpp macro_test.cpp ord_sym_test.cpp + system_variable_test.cpp using_test.cpp ) diff --git a/parser_library/test/context/context_test.cpp b/parser_library/test/context/context_test.cpp index be551cc4d..1ddc26819 100644 --- a/parser_library/test/context/context_test.cpp +++ b/parser_library/test/context/context_test.cpp @@ -76,7 +76,23 @@ TEST(context, create_global_var) ASSERT_TRUE(glob == found); - ASSERT_TRUE(glob == ctx.globals().find(idx)->second); + ASSERT_TRUE(ctx.globals().find(idx) != ctx.globals().end()); + EXPECT_TRUE(glob.get() == ctx.globals().find(idx)->second->access_set_symbol_base()); + EXPECT_TRUE(glob == ctx.globals().find(idx)->second); +} + +TEST(context, find_global_system_var) +{ + hlasm_context ctx; + + + auto idx = ctx.ids().find("SYSDATC"); + + auto scope_var_ptr = ctx.get_var_sym(idx); + + + EXPECT_TRUE(scope_var_ptr); + EXPECT_TRUE(ctx.globals().find(idx) != ctx.globals().end()); } TEST(context, create_local_var) diff --git a/parser_library/test/context/macro_test.cpp b/parser_library/test/context/macro_test.cpp index aec45878a..00db40959 100644 --- a/parser_library/test/context/macro_test.cpp +++ b/parser_library/test/context/macro_test.cpp @@ -483,7 +483,7 @@ TEST(macro, arguments_concatenation) ASSERT_NE(it, a.hlasm_ctx().globals().end()); - EXPECT_EQ(it->second->access_set_symbol()->get_value(), "(B-C)+(A-D)"); + EXPECT_EQ(it->second->access_set_symbol_base()->access_set_symbol()->get_value(), "(B-C)+(A-D)"); EXPECT_EQ(a.diags().size(), (size_t)0); EXPECT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0); @@ -514,8 +514,8 @@ TEST(macro, arguments_continuation) ASSERT_NE(Q, a.hlasm_ctx().globals().end()); ASSERT_NE(W, a.hlasm_ctx().globals().end()); - EXPECT_EQ(Q->second->access_set_symbol()->get_value(), "X"); - EXPECT_EQ(W->second->access_set_symbol()->get_value(), "Y"); + EXPECT_EQ(Q->second->access_set_symbol_base()->access_set_symbol()->get_value(), "X"); + EXPECT_EQ(W->second->access_set_symbol_base()->access_set_symbol()->get_value(), "Y"); EXPECT_EQ(a.diags().size(), (size_t)0); EXPECT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0); diff --git a/parser_library/test/context/system_variable_test.cpp b/parser_library/test/context/system_variable_test.cpp new file mode 100644 index 000000000..77f063d2d --- /dev/null +++ b/parser_library/test/context/system_variable_test.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2022 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#include "gtest/gtest.h" + +#include "../common_testing.h" + +namespace { + +std::vector subscripts_default = { "", "(1)", "(1,1)", "(1,1,1)", "(2)", "(2,2)", "(3)" }; +std::vector subscripts_sysmac = { "", "(0)", "(1)", "(1,1)", "(1,1,1)", "(2)", "(2,2)", "(3)" }; +std::vector subscripts_syslist = { "", + "(0)", + "(1)", + "(1,0)", + "(1,1)", + "(1,1,1)", + "(2)", + "(2,0)", + "(2,2)", + "(3)", + "(3,1)", + "(3,1,1)", + "(3,2)", + "(3,3)", + "(3,4)", + "(3,4,1)", + "(3,5)", + "(3,5,1)", + "(3,5,1,1)", + "(3,5,1,2)", + "(3,5,2)", + "(3,5,2,1)", + "(3,5,2,1)", + "(4)", + "(5)", + "(5,0)", + "(5,1)", + "(7)", + "(7,0)", + "(7,1)", + "(7,1,2)", + "(7,2)", + "(10)", + "(14)", + "(20)" }; + +struct system_variable_params +{ + std::string input; + std::vector exp_results; + + static system_variable_params create_input(std::string system_variable, + std::vector expected_results, + std::vector& subscripts = subscripts_default) + { + assert(subscripts.size() == expected_results.size()); + + system_variable_params params; + params.input = R"( + MACRO + MAC +)"; + + for (size_t i = 0; i < subscripts.size(); ++i) + { + params.input += R"( GBLC A)" + std::to_string(i) + R"( +)"; + } + + for (size_t i = 0; i < subscripts.size(); ++i) + { + params.input += R"(&A)" + std::to_string(i) + R"( SETC '&)" + system_variable + subscripts[i] + R"(' +)"; + } + + params.input += R"( + MEND + +TEST CSECT +)"; + + for (size_t i = 0; i < subscripts.size(); ++i) + { + params.input += R"( GBLC A)" + std::to_string(i) + R"( +)"; + } + + params.input += R"( +NNN MAC WW,XX,(A,,B,,(AA,,BB,CC,,DD),8,,()),,YY,,(),,,ZZ +)"; + + params.exp_results = std::move(expected_results); + + return params; + } +}; + +class system_variable_standard_behavior_fixture : public ::testing::TestWithParam +{}; + +} // namespace + +INSTANTIATE_TEST_SUITE_P(system_variable, + system_variable_standard_behavior_fixture, + ::testing::Values(system_variable_params::create_input("SYSECT", { "TEST", "TEST", "TEST", "TEST", "", "", "" }), + system_variable_params::create_input("SYSLOC", { "TEST", "TEST", "TEST", "TEST", "", "", "" }), + system_variable_params::create_input( + "SYSMAC", { "MAC", "MAC", "OPEN CODE", "OPEN CODE", "OPEN CODE", "", "", "" }, subscripts_sysmac), + system_variable_params::create_input("SYSNDX", { "0001", "0001", "0001", "0001", "", "", "" }), + system_variable_params::create_input("SYSNEST", { "1", "1", "1", "1", "", "", "" }), + system_variable_params::create_input("SYSOPT_RENT", { "0", "0", "0", "0", "", "", "" }), + system_variable_params::create_input("SYSPARM", { "PAR", "PAR", "PAR", "PAR", "", "", "" }), + system_variable_params::create_input("SYSSTYP", { "CSECT", "CSECT", "CSECT", "CSECT", "", "", "" }), + system_variable_params::create_input( + "SYSTEM_ID", { "z/OS 02.04.00", "z/OS 02.04.00", "z/OS 02.04.00", "z/OS 02.04.00", "", "", "" }), + system_variable_params::create_input("SYSLIST", + { "WW", + "NNN", + "WW", + "", + "WW", + "WW", + "XX", + "", + "", + "(A,,B,,(AA,,BB,CC,,DD),8,,())", + "A", + "A", + "", + "B", + "", + "", + "(AA,,BB,CC,,DD)", + "AA", + "AA", + "", + "", + "", + "", + "", + "YY", + "", + "YY", + "()", + "", + "", + "", + "", + "ZZ", + "", + "" }, + subscripts_syslist))); + +TEST_P(system_variable_standard_behavior_fixture, standard_behavior) +{ + std::string input(GetParam().input); + std::vector exp_behavior(GetParam().exp_results); + + analyzer a(input, analyzer_options { asm_option { "PAR" } }); + a.analyze(); + a.collect_diags(); + + for (size_t i = 0; i < exp_behavior.size(); ++i) + { + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "A" + std::to_string(i)), exp_behavior[i]) + << "for i = " << i; + } +} diff --git a/parser_library/test/debugging/debugger_test.cpp b/parser_library/test/debugging/debugger_test.cpp index d139780ee..4b40601bb 100644 --- a/parser_library/test/debugging/debugger_test.cpp +++ b/parser_library/test/debugging/debugger_test.cpp @@ -131,25 +131,9 @@ class test_var_value if (ignore_) return true; - if (!children_.empty()) + if (has_children(var) && !check_children(d, var)) { - auto child_vars = var.variable_reference; - if (!child_vars) - return false; - auto actual_children = d.variables(child_vars); - if (actual_children.size() != children_.size()) - return false; - for (auto actual_ch : actual_children) - { - std::string actual_ch_name(actual_ch.name); - auto found = children_.find(actual_ch_name); - if (found == children_.end()) - return false; - if (found->first != actual_ch_name) - return false; - if (!found->second->check(d, actual_ch)) - return false; - } + return false; } if (data_) @@ -158,6 +142,31 @@ class test_var_value return var.value.size() == 0; } + bool has_children(const hlasm_plugin::parser_library::variable& var) const { return var.variable_reference; } + + bool check_children(debugger& d, const hlasm_plugin::parser_library::variable& var) const + { + auto child_vars = var.variable_reference; + if (!child_vars) + return false; + auto actual_children = d.variables(child_vars); + if (actual_children.size() != children_.size()) + return false; + for (auto actual_ch : actual_children) + { + std::string actual_ch_name(actual_ch.name); + auto found = children_.find(actual_ch_name); + if (found == children_.end()) + return false; + if (found->first != actual_ch_name) + return false; + if (!found->second->check(d, actual_ch)) + return false; + } + + return true; + } + private: std::unordered_map> children_; std::optional data_; @@ -349,7 +358,7 @@ TEST(debugger, test) // macro locals { "&SYSLIST", - test_var_value("(10,13)", + test_var_value("13", list { { "0", std::make_shared("10") }, { "1", std::make_shared("13") }, diff --git a/parser_library/test/diagnostics_sysvar_test.cpp b/parser_library/test/diagnostics_sysvar_test.cpp new file mode 100644 index 000000000..d617b9da7 --- /dev/null +++ b/parser_library/test/diagnostics_sysvar_test.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2022 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#include "gtest/gtest.h" + +#include "common_testing.h" + +namespace { + +struct diagnostics_sysvar_params +{ + std::string input; + + static diagnostics_sysvar_params create_input(std::string system_variable, std::string subscript) + { + diagnostics_sysvar_params result; + + result.input = + R"( + MACRO + MAC + &)" + system_variable + + subscript + R"( + MEND + +TEST CSECT +NNN MAC WW,XX,(A,,B,,(AA,,BB,CC,,DD),8,,()),,YY,,(),,,ZZ +)"; + + return result; + } +}; + +class diagnostics_sysvar_invalid_opcode_fixture : public ::testing::TestWithParam +{}; + +class diagnostics_sysvar_null_opcode_invalid_subscript_fixture + : public ::testing::TestWithParam +{}; + +class diagnostics_sysvar_null_opcode_fixture : public ::testing::TestWithParam +{}; + +class diagnostics_sysvar_bad_symbol_fixture : public ::testing::TestWithParam +{}; + +class diagnostics_sysvar_non_alpha_char_fixture : public ::testing::TestWithParam +{}; + +class diagnostics_sysvar_unsubscripted_syslist_invalid_opcode_fixture + : public ::testing::TestWithParam +{}; + +class diagnostics_sysvar_too_many_nested_macro_calls_fixture + : public ::testing::TestWithParam +{}; + +} // namespace + +INSTANTIATE_TEST_SUITE_P(diagnostics_sysvar, + diagnostics_sysvar_invalid_opcode_fixture, + ::testing::Values(diagnostics_sysvar_params::create_input("SYSDATC", ""), + diagnostics_sysvar_params::create_input("SYSDATC", "(1)"), + diagnostics_sysvar_params::create_input("SYSDATC", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSDATC", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSECT", ""), + diagnostics_sysvar_params::create_input("SYSECT", "(1)"), + diagnostics_sysvar_params::create_input("SYSECT", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSECT", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(0)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(1)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(2)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSLOC", ""), + diagnostics_sysvar_params::create_input("SYSLOC", "(1)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSNDX", ""), + diagnostics_sysvar_params::create_input("SYSNDX", "(1)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSNEST", ""), + diagnostics_sysvar_params::create_input("SYSNEST", "(1)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", ""), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(1)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(1,1,1)"))); + +INSTANTIATE_TEST_SUITE_P(diagnostics_sysvar, + diagnostics_sysvar_null_opcode_invalid_subscript_fixture, + ::testing::Values(diagnostics_sysvar_params::create_input("SYSDATC", "(0)"), + diagnostics_sysvar_params::create_input("SYSDATC", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSDATC", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(0)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSECT", "(0)"), + diagnostics_sysvar_params::create_input("SYSECT", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSECT", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(0)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(0)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(0)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(0)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(0)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSSTYP", "(0)"), + diagnostics_sysvar_params::create_input("SYSSTYP", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSSTYP", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(0)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(0)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(1,1,0)") + + )); + +INSTANTIATE_TEST_SUITE_P(diagnostics_sysvar, + diagnostics_sysvar_null_opcode_fixture, + ::testing::Values(diagnostics_sysvar_params::create_input("SYSDATC", "(2)"), + diagnostics_sysvar_params::create_input("SYSDATC", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSDATC", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSDATC", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(2)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSECT", "(2)"), + diagnostics_sysvar_params::create_input("SYSECT", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSECT", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSECT", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(2)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSLOC", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(0,2)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(1,2)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(2)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(2,2)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(2)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSNDX", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(2)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSNEST", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(2)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSOPT_RENT", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSPARM", ""), + diagnostics_sysvar_params::create_input("SYSPARM", "(1)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(2)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSPARM", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSSTYP", "(2)"), + diagnostics_sysvar_params::create_input("SYSSTYP", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSSTYP", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSSTYP", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(2)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(2,2,2)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(2)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(2,0)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(2,1)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(2,2,2)"))); + +INSTANTIATE_TEST_SUITE_P(diagnostics_sysvar, + diagnostics_sysvar_bad_symbol_fixture, + ::testing::Values(diagnostics_sysvar_params::create_input("SYSMAC", "(0,1)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(0,0,1)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(1)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(2,1)"))); + +INSTANTIATE_TEST_SUITE_P(diagnostics_sysvar, + diagnostics_sysvar_non_alpha_char_fixture, + ::testing::Values(diagnostics_sysvar_params::create_input("SYSDATE", ""), + diagnostics_sysvar_params::create_input("SYSDATE", "(1)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSDATE", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSLIST", "(7)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", ""), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(1)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSTEM_ID", "(1,1,1)"), + diagnostics_sysvar_params::create_input("SYSTIME", ""), + diagnostics_sysvar_params::create_input("SYSTIME", "(1)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(1,1)"), + diagnostics_sysvar_params::create_input("SYSTIME", "(1,1,1)"))); + +INSTANTIATE_TEST_SUITE_P(diagnostics_sysvar, + diagnostics_sysvar_unsubscripted_syslist_invalid_opcode_fixture, + ::testing::Values(diagnostics_sysvar_params::create_input("SYSLIST", ""))); + +INSTANTIATE_TEST_SUITE_P(diagnostics_sysvar, + diagnostics_sysvar_too_many_nested_macro_calls_fixture, + ::testing::Values(diagnostics_sysvar_params::create_input("SYSMAC", ""), + diagnostics_sysvar_params::create_input("SYSMAC", "(0)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(1,0)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(1,1,0)"), + diagnostics_sysvar_params::create_input("SYSMAC", "(2,0)"))); + +TEST_P(diagnostics_sysvar_invalid_opcode_fixture, invalid_opcode) +{ + std::string input(GetParam().input); + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "E049" })); +} + +TEST_P(diagnostics_sysvar_null_opcode_invalid_subscript_fixture, null_opcode_invalid_subscript) +{ + std::string input(GetParam().input); + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "E012", "E074" })); +} + +TEST_P(diagnostics_sysvar_null_opcode_fixture, null_opcode) +{ + std::string input(GetParam().input); + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "E074" })); +} + +TEST_P(diagnostics_sysvar_bad_symbol_fixture, bad_symbol) +{ + std::string input(GetParam().input); + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "E067" })); +} + +TEST_P(diagnostics_sysvar_non_alpha_char_fixture, non_alpha_char) +{ + std::string input(GetParam().input); + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "E075" })); +} + +TEST_P(diagnostics_sysvar_unsubscripted_syslist_invalid_opcode_fixture, unsubscripted_syslist) +{ + std::string input(GetParam().input); + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "E049", "E076" })); +} + +TEST_P(diagnostics_sysvar_too_many_nested_macro_calls_fixture, too_many_macro_calls) +{ + std::string input(GetParam().input); + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "E055" })); +}