From ce0ba21b97de4965b90cdd3dc8ff098ea6007c20 Mon Sep 17 00:00:00 2001 From: jirimosinger <99467904+jirimosinger@users.noreply.github.com> Date: Wed, 13 Apr 2022 09:32:07 +0200 Subject: [PATCH] fix: Empty arrays now behave similarly to other subscripted variables in the macro tracer --- clients/vscode-hlasmplugin/CHANGELOG.md | 9 +- .../src/debugging/set_symbol_variable.cpp | 7 +- parser_library/test/common_testing.h | 29 ++ .../test/debugging/debugger_test.cpp | 11 +- .../test/processing/ca_instr_test.cpp | 260 ++++++------------ 5 files changed, 126 insertions(+), 190 deletions(-) diff --git a/clients/vscode-hlasmplugin/CHANGELOG.md b/clients/vscode-hlasmplugin/CHANGELOG.md index 296fd5052..d339156fa 100644 --- a/clients/vscode-hlasmplugin/CHANGELOG.md +++ b/clients/vscode-hlasmplugin/CHANGELOG.md @@ -13,6 +13,7 @@ - Improve detection of HLASM files - Reaching ACTR limit now only generates warnings - Parsing of negative numbers in machine expressions +- Empty arrays now behave similarly to other subscripted variables in macro tracer ## [1.1.0](https://github.com/eclipse/che-che4z-lsp-for-hlasm/compare/1.0.0...1.1.0) (2022-03-29) @@ -38,7 +39,7 @@ #### Fixed - Highlighting now fully works with themes, not just categories dark, light and contrast. -- Incorrect module layout generated when data defintion operands have different alignments +- Incorrect module layout generated when data definition operands have different alignments - Data definition grammar is too greedy - Readme update @@ -75,7 +76,7 @@ - Infinite loop during lookahead processing when model statement is located in copybook - DOT operator in string concatenation is optional - AINSERT operand length validation -- HLASM Listing highligting of lines with trimmed whitespace +- HLASM Listing highlighting of lines with trimmed whitespace - Macro tracer: step over sometimes stops inside a macro or a copy file ## [0.14.0](https://github.com/eclipse/che-che4z-lsp-for-hlasm/compare/0.13.0...0.14.0) (2021-08-18) @@ -94,9 +95,9 @@ - Improved OPSYN processing - Language server crashes while evaluating conditional assembly statements - Allow self-reference in previously undefined array variables -- Tolerate '+' in modifiers in data defintions +- Tolerate '+' in modifiers in data definitions - Empty TITLE argument must be tolerated -- Statements skipped by conditinal assembly emmiting errors in macros and copy files +- Statements skipped by conditional assembly emitting errors in macros and copy files - Location counter in machine instruction sometimes evaluating incorrectly - WASM variant of the language server not working with the V8 JavaScript machine version 9 or later - Improve language server stability diff --git a/parser_library/src/debugging/set_symbol_variable.cpp b/parser_library/src/debugging/set_symbol_variable.cpp index 8962a7eec..6de6e273e 100644 --- a/parser_library/src/debugging/set_symbol_variable.cpp +++ b/parser_library/src/debugging/set_symbol_variable.cpp @@ -81,7 +81,12 @@ std::string set_symbol_variable::get_string_array_value() const array_value.append("("); auto keys = set_symbol_.keys(); - assert(!keys.empty()); + + if (keys.empty()) + { + array_value.append(")"); + return array_value; + } for (const auto& key : keys) { diff --git a/parser_library/test/common_testing.h b/parser_library/test/common_testing.h index 9148cd2ba..e6ec5f5a5 100644 --- a/parser_library/test/common_testing.h +++ b/parser_library/test/common_testing.h @@ -126,6 +126,35 @@ std::optional> get_var_vector(hlasm_context& ctx, std::string nam return result; } +template +std::optional> get_var_vector_map(hlasm_context& ctx, std::string name) +{ + auto var = ctx.get_var_sym(ctx.ids().find(name)); + if (!var) + return std::nullopt; + + if (var->var_kind != context::variable_kind::SET_VAR_KIND) + return std::nullopt; + auto var_ = var->access_set_symbol_base(); + if (var_->type != object_traits::type_enum || var_->is_scalar) + return std::nullopt; + + auto symbol = var_->template access_set_symbol(); + if (!symbol) + return std::nullopt; + + auto keys = symbol->keys(); + + std::unordered_map result; + result.reserve(keys.size()); + for (size_t i = 0; i < keys.size(); ++i) + { + result.emplace(keys[i], symbol->get_value(keys[i])); + } + + return result; +} + inline bool matches_message_codes(const std::vector& d, std::initializer_list m) { std::vector codes; diff --git a/parser_library/test/debugging/debugger_test.cpp b/parser_library/test/debugging/debugger_test.cpp index 26c801c7c..819d63d3a 100644 --- a/parser_library/test/debugging/debugger_test.cpp +++ b/parser_library/test/debugging/debugger_test.cpp @@ -774,7 +774,7 @@ TEST(debugger, positional_parameters) d.disconnect(); } -TEST(debugger, var_symbol_array) +TEST(debugger, arrays) { using list = std::unordered_map>; @@ -782,7 +782,8 @@ TEST(debugger, var_symbol_array) &VAR(30) SETA 1,456,48,7 &BOOL(15) SETB 0,1,0 &STR(6) SETC 'a','b' - LR 1,1 + GBLC &ARR(10) + END )"; @@ -823,6 +824,10 @@ TEST(debugger, var_symbol_array) list { { "6", std::make_shared("a") }, { "7", std::make_shared("b") } })); EXPECT_TRUE(check_step(d, exp_frames, exp_frame_vars)); + step_over_by(1, d, m, exp_frames, 5); + exp_frame_vars[0].globals.emplace("&ARR", test_var_value("()", list {})); + EXPECT_TRUE(check_step(d, exp_frames, exp_frame_vars)); + d.disconnect(); } @@ -923,4 +928,4 @@ TEST(debugger, breakpoints_set_get) ASSERT_EQ(bps.size(), 1); EXPECT_EQ(bp.line, bps.begin()->line); -} +} \ No newline at end of file diff --git a/parser_library/test/processing/ca_instr_test.cpp b/parser_library/test/processing/ca_instr_test.cpp index 7e779aabe..d78b0b1e9 100644 --- a/parser_library/test/processing/ca_instr_test.cpp +++ b/parser_library/test/processing/ca_instr_test.cpp @@ -20,10 +20,8 @@ using namespace hlasm_plugin::parser_library; using namespace hlasm_plugin::parser_library::context; using namespace hlasm_plugin::parser_library::semantics; -// tests for -// variable substitution for model statements -// concatenation of multiple substitutions -// CA instructions +// Tests for variable substitution for model statements concatenation of multiple substitutions CA instructions +// Some inputs are deliberately not written in uppercase to also verify case-insensitivity TEST(var_subs, gbl_instr_only) { @@ -31,11 +29,7 @@ TEST(var_subs, gbl_instr_only) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - - auto it = ctx.ids().find("var"); - - ASSERT_TRUE(ctx.get_var_sym(it)); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var"), 0); } TEST(var_subs, lcl_instr_only) @@ -44,11 +38,7 @@ TEST(var_subs, lcl_instr_only) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - - auto it = ctx.ids().find("var"); - - ASSERT_TRUE(ctx.get_var_sym(it)); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var"), 0); } TEST(var_subs, gbl_instr_more) @@ -57,15 +47,9 @@ TEST(var_subs, gbl_instr_more) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - - auto it = ctx.ids().find("var"); - auto it2 = ctx.ids().find("var2"); - auto it3 = ctx.ids().find("var3"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - ASSERT_TRUE(ctx.get_var_sym(it2)); - ASSERT_TRUE(ctx.get_var_sym(it3)); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var"), 0); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), 0); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var3"), 0); } TEST(var_subs, lcl_instr_more) @@ -74,15 +58,22 @@ TEST(var_subs, lcl_instr_more) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var"), 0); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), 0); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var3"), 0); +} - auto it = ctx.ids().find("var"); - auto it2 = ctx.ids().find("var2"); - auto it3 = ctx.ids().find("var3"); +TEST(var_subs, big_arrays) +{ + std::string input = R"( + lclc &larr(100000000) + gblc &garr(100000000) +)"; + analyzer a(input); + a.analyze(); - ASSERT_TRUE(ctx.get_var_sym(it)); - ASSERT_TRUE(ctx.get_var_sym(it2)); - ASSERT_TRUE(ctx.get_var_sym(it3)); + EXPECT_EQ(get_var_vector(a.hlasm_ctx(), "larr")->size(), 0); + EXPECT_EQ(get_var_vector(a.hlasm_ctx(), "garr")->size(), 0); } TEST(var_subs, set_to_var) @@ -91,15 +82,7 @@ TEST(var_subs, set_to_var) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - - auto it = ctx.ids().find("var"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - - diagnostic_op_consumer_container diags; - int tmp = get_var_sym_value(ctx, it, std::vector {}, {}, diags).access_a(); - EXPECT_EQ(tmp, 3); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var"), 3); } TEST(var_subs, set_to_var_idx) @@ -108,160 +91,105 @@ TEST(var_subs, set_to_var_idx) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - diagnostic_op_consumer_container diags; - - auto it = ctx.ids().find("var"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - std::vector subscript1; - subscript1.push_back(2); - int tmp = get_var_sym_value(ctx, it, std::move(subscript1), {}, diags).access_a(); - EXPECT_EQ(tmp, 3); + std::unordered_map expected = { { 1, 3 } }; + EXPECT_EQ(get_var_vector_map(a.hlasm_ctx(), "var"), expected); } TEST(var_subs, set_to_var_idx_many) { std::string input("&var(2) seta 3,4,5"); - std::string input_s1("2"); - std::string input_s2("3"); - std::string input_s3("4"); - analyzer s1(input_s1); - analyzer s2(input_s2); - analyzer s3(input_s3); - analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - diagnostic_op_consumer_container diags; - - auto it = ctx.ids().find("var"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - - int tmp; - std::vector subscript1; - subscript1.push_back(2); - tmp = get_var_sym_value(ctx, it, std::move(subscript1), {}, diags).access_a(); - EXPECT_EQ(tmp, 3); - std::vector subscript2; - subscript2.push_back(3); - tmp = get_var_sym_value(ctx, it, std::move(subscript2), {}, diags).access_a(); - EXPECT_EQ(tmp, 4); - std::vector subscript3; - subscript3.push_back(4); - tmp = get_var_sym_value(ctx, it, std::move(subscript3), {}, diags).access_a(); - EXPECT_EQ(tmp, 5); + std::unordered_map expected = { { 1, 3 }, { 2, 4 }, { 3, 5 } }; + EXPECT_EQ(get_var_vector_map(a.hlasm_ctx(), "var"), expected); } TEST(var_subs, var_sym_reset) { - std::string input("&var setc 'avc' \n&var setc 'XXX'"); + std::string input = R"( +&var setc 'avc' +&var setc 'XXX' +)"; analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - diagnostic_op_consumer_container diags; - - auto it = ctx.ids().find("var"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - - std::string tmp = get_var_sym_value(ctx, it, std::vector {}, {}, diags).access_c(); - EXPECT_EQ(tmp, "XXX"); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var"), "XXX"); } TEST(var_subs, created_set_sym) { - std::string input("&var setc 'avc' \n&var2 setb 0 \n&(ab&var.cd&var2) seta 11"); + std::string input = R"( +&var setc 'avc' +&var2 setb 0 +&(ab&var.cd&var2) seta 11 +)"; analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - diagnostic_op_consumer_container diags; - - auto it = ctx.ids().find("abavccd0"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - - auto tmp = get_var_sym_value(ctx, it, std::vector {}, {}, diags).access_a(); - EXPECT_EQ(tmp, 11); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "abavccd0"), 11); } TEST(var_subs, instruction_substitution_space_at_end) { - std::string input("&var setc 'LR ' \n &var 1,1"); + std::string input = R"( +&var setc 'lr ' + &var 1,1 +)"; analyzer a(input); a.analyze(); - - a.collect_diags(); - ASSERT_EQ(a.diags().size(), (size_t)0); + EXPECT_EQ(a.diags().size(), (size_t)0); } TEST(var_subs, instruction_substitution_space_in_middle) { - std::string input("&var setc 'LR 1,1' \n &var "); + std::string input = R"( +&var setc 'lr 1,1' + &var +)"; analyzer a(input); a.analyze(); - - a.collect_diags(); - ASSERT_EQ(a.diags().size(), (size_t)1); + EXPECT_TRUE(matches_message_codes(a.diags(), { "E075" })); } TEST(var_concatenation, concatenated_string_dot_last) { - std::string input("&var setc 'avc' \n&var2 setc '&var.'"); + std::string input = R"( +&var setc 'avc' +&var2 setc '&var.' +)"; analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - diagnostic_op_consumer_container diags; - - auto it = ctx.ids().find("var2"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - - auto tmp = get_var_sym_value(ctx, it, std::vector {}, {}, diags).access_c(); - EXPECT_EQ(tmp, "avc"); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), "avc"); } TEST(var_concatenation, concatenated_string_dot) { - std::string input("&var setc 'avc' \n&var2 setc '&var.-get'"); + std::string input = R"( +&var setc 'avc' +&var2 setc '&var.-get' +)"; analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - diagnostic_op_consumer_container diags; - - auto it = ctx.ids().find("var2"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - - auto tmp = get_var_sym_value(ctx, it, std::vector {}, {}, diags).access_c(); - EXPECT_EQ(tmp, "avc-get"); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), "avc-get"); } TEST(var_concatenation, concatenated_string_double_dot) { - std::string input("&var setc 'avc' \n&var2 setc '&var..'"); + std::string input = R"( +&var setc 'avc' +&var2 setc '&var..' +)"; analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - diagnostic_op_consumer_container diags; - - auto it = ctx.ids().find("var2"); - - ASSERT_TRUE(ctx.get_var_sym(it)); - - auto tmp = get_var_sym_value(ctx, it, std::vector {}, {}, diags).access_c(); - EXPECT_EQ(tmp, "avc."); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), "avc."); } TEST(AGO, extended) @@ -278,15 +206,9 @@ TEST(AGO, extended) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - - auto it1 = ctx.ids().add("var1"); - auto it2 = ctx.ids().add("var2"); - auto it3 = ctx.ids().add("var3"); - - EXPECT_FALSE(ctx.get_var_sym(it1)); - EXPECT_TRUE(ctx.get_var_sym(it2)); - EXPECT_TRUE(ctx.get_var_sym(it3)); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var1"), std::nullopt); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), false); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var3"), false); } TEST(AGO, extended_fail) @@ -303,15 +225,9 @@ TEST(AGO, extended_fail) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - - auto it1 = ctx.ids().add("var1"); - auto it2 = ctx.ids().add("var2"); - auto it3 = ctx.ids().add("var3"); - - EXPECT_TRUE(ctx.get_var_sym(it1)); - EXPECT_TRUE(ctx.get_var_sym(it2)); - EXPECT_TRUE(ctx.get_var_sym(it3)); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var1"), false); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), false); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var3"), false); } TEST(AIF, extended) @@ -328,15 +244,9 @@ TEST(AIF, extended) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - - auto it1 = ctx.ids().add("var1"); - auto it2 = ctx.ids().add("var2"); - auto it3 = ctx.ids().add("var3"); - - EXPECT_FALSE(ctx.get_var_sym(it1)); - EXPECT_TRUE(ctx.get_var_sym(it2)); - EXPECT_TRUE(ctx.get_var_sym(it3)); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var1"), std::nullopt); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), false); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var3"), false); } TEST(AIF, extended_fail) @@ -353,15 +263,9 @@ TEST(AIF, extended_fail) analyzer a(input); a.analyze(); - auto& ctx = a.hlasm_ctx(); - - auto it1 = ctx.ids().add("var1"); - auto it2 = ctx.ids().add("var2"); - auto it3 = ctx.ids().add("var3"); - - EXPECT_TRUE(ctx.get_var_sym(it1)); - EXPECT_TRUE(ctx.get_var_sym(it2)); - EXPECT_TRUE(ctx.get_var_sym(it3)); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var1"), false); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var2"), false); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "var3"), false); } TEST(ACTR, exceeded) @@ -373,7 +277,6 @@ TEST(ACTR, exceeded) )"); analyzer a(input); a.analyze(); - a.collect_diags(); EXPECT_TRUE(matches_message_codes(a.diags(), { "E056" })); @@ -389,7 +292,6 @@ TEST(ACTR, infinite_ACTR) )"); analyzer a(input, analyzer_options(asm_option { .statement_count_limit = 10000 })); a.analyze(); - a.collect_diags(); EXPECT_TRUE(matches_message_codes(a.diags(), { "W063", "E077" })); @@ -406,7 +308,6 @@ TEST(ACTR, negative) )"); analyzer a(input); a.analyze(); - a.collect_diags(); EXPECT_TRUE(matches_message_codes(a.diags(), { "E056" })); @@ -433,7 +334,6 @@ TEST(MHELP, SYSNDX_limit) )"; analyzer a(input); a.analyze(); - a.collect_diags(); EXPECT_TRUE(matches_message_codes(a.diags(), { "E072" })); @@ -452,7 +352,6 @@ ABC EQU 1 )"; analyzer a(input); a.analyze(); - a.collect_diags(); EXPECT_TRUE(matches_message_codes(a.diags(), { "E021", "E020", "E020", "CE012", "E010" })); @@ -474,7 +373,6 @@ ABC EQU 1 )"; analyzer a(input); a.analyze(); - a.collect_diags(); EXPECT_TRUE(a.diags().empty()); @@ -495,10 +393,9 @@ TEST(SET, conversions_valid) )"); analyzer a(input); a.analyze(); - a.collect_diags(); - ASSERT_EQ(a.diags().size(), (size_t)0); + EXPECT_EQ(a.diags().size(), (size_t)0); } TEST(SET, conversions_invalid) @@ -516,10 +413,10 @@ TEST(SET, conversions_invalid) )"); analyzer a(input); a.analyze(); - a.collect_diags(); - ASSERT_EQ(a.diags().size(), (size_t)8); + EXPECT_TRUE( + matches_message_codes(a.diags(), { "CE004", "CE004", "CE004", "CE004", "CE004", "CE004", "CE017", "CE017" })); } TEST(CA_instructions, undefined_relocatable) @@ -536,10 +433,9 @@ B EQU 1 )"); analyzer a(input); a.analyze(); - a.collect_diags(); - ASSERT_EQ(a.diags().size(), (size_t)3); + EXPECT_TRUE(matches_message_codes(a.diags(), { "CE012", "CE012", "CE012" })); } TEST(var_subs, defined_by_self_ref)