From 1328784e5c9ab127d80cf65a9f5396c41650e59c Mon Sep 17 00:00:00 2001 From: xuhong Date: Wed, 18 Sep 2024 17:42:47 +0800 Subject: [PATCH] solve the problem of failed parsing of std containers, add test suite --- CHANGELOG.md | 1 + src/backend/gdb_expansion.ts | 27 +++++++-- src/mibase.ts | 9 ++- src/test/unit/gdb_expansion.test.ts | 88 +++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6112a983..9320aca8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Versioning]. - New `frameFilters` option for GDB that allows using custom frame filters, enabled by default ([@JacquesLucke]) - Suppress error for hover as the user may just play with the mouse ([@oltolm]). +- solve the problem of failed parsing of containers ([@henryriley0]) ## [0.27.0] - 2024-02-07 diff --git a/src/backend/gdb_expansion.ts b/src/backend/gdb_expansion.ts index 0b10e6d0..ba81fb8c 100644 --- a/src/backend/gdb_expansion.ts +++ b/src/backend/gdb_expansion.ts @@ -1,8 +1,8 @@ import { VariableObject } from "./backend"; import { MINode } from "./mi_parse"; -const resultRegex = /^([a-zA-Z_\-][a-zA-Z0-9_\-]*|\[\d+\])\s*=\s*/; -const variableRegex = /^[a-zA-Z_\-][a-zA-Z0-9_\-]*/; +const resultRegex = /^([a-zA-Z_\-][a-zA-Z0-9_\-<> :(),]*|\[\d+\])\s*=\s*/; +const variableRegex = /^[a-zA-Z_\-\'\(][a-zA-Z0-9_\-\|\>\ \\\'\)\:]*/; const errorRegex = /^\<.+?\>/; const referenceStringRegex = /^(0x[0-9a-fA-F]+\s*)"/; const referenceRegex = /^0x[0-9a-fA-F]+/; @@ -105,14 +105,18 @@ export function expandValue(variableCreate: (arg: VariableObject | string, optio const eqPos = value.indexOf("="); const newValPos1 = value.indexOf("{"); const newValPos2 = value.indexOf(","); + const newValPos3 = value.indexOf("}"); let newValPos = newValPos1; if (newValPos2 != -1 && newValPos2 < newValPos1) newValPos = newValPos2; - if (newValPos != -1 && eqPos > newValPos || eqPos == -1) { // is value list + if (newValPos != -1 && eqPos > newValPos || eqPos == -1 || eqPos > newValPos3 && newValPos2 != -1 || value.startsWith("std::")) { // is value list const values = []; stack.push("[0]"); let val = parseValue(); stack.pop(); + if(typeof val == "string" && val.endsWith('>')){ + val = val.substring(0, val.length - 2); + } values.push(createValue("[0]", val)); const remaining = value; let i = 0; @@ -191,18 +195,26 @@ export function expandValue(variableCreate: (arg: VariableObject | string, optio return parseCString(); else if (value[0] == '{') return parseTupleOrList(); + else if(value.startsWith("std::")){ + const eqPos = value.indexOf("="); + value = value.substring(eqPos + 2); + return parseValue(); + } else return parsePrimitive(); }; parseResult = (pushToStack: boolean = false) => { - value = value.trim(); - value = value.replace(/^static /, ""); + value = value.replace(/^ 1 && !name.includes("anonymous union") && !name.includes(',')){ + name = tmpName[tmpName.length - 1]; + } if (pushToStack) stack.push(variable); const val = parseValue(); @@ -231,6 +243,9 @@ export function expandValue(variableCreate: (arg: VariableObject | string, optio ref = variableCreate(getNamespace(name)); val = "..."; } + value = value.trim(); + value = value.replace(/^, /, ""); + return { name: name, value: val, diff --git a/src/mibase.ts b/src/mibase.ts index 1aa859a5..ba3fbeb5 100644 --- a/src/mibase.ts +++ b/src/mibase.ts @@ -537,7 +537,14 @@ export class MI2DebugSession extends DebugSession { // TODO: this evaluates on an (effectively) unknown thread for multithreaded programs. variable = await this.miDebugger.evalExpression(JSON.stringify(id), 0, 0); try { - let expanded = expandValue(createVariable, variable.result("value"), id, variable); + let variableValue = variable.result("value"); + const pattern = /'([^']*)' /g; + variableValue = variableValue.replace(pattern, (_: any, char: string, count: string) => { + const repeatCount = parseInt(count, 10) + 1; + const repeatedArray = Array(repeatCount).fill(char); + return `{${repeatedArray.map(item => `'${item}'`).join(', ')}}`; + }); + let expanded = expandValue(createVariable, variableValue, id, variable); if (!expanded) { this.sendErrorResponse(response, 2, `Could not expand variable`); } else { diff --git a/src/test/unit/gdb_expansion.test.ts b/src/test/unit/gdb_expansion.test.ts index 2bc5f085..a455b876 100644 --- a/src/test/unit/gdb_expansion.test.ts +++ b/src/test/unit/gdb_expansion.test.ts @@ -304,4 +304,92 @@ suite("GDB Value Expansion", () => { { name: "floatval2", value: "234.45", variablesReference: 0 } ]); }); + test("std container values", () => { + let node = `std::vector of length 4, capacity 6 = {1, 2, 3, 4}`; + let variables = expandValue(variableCreate, node); + assert.strictEqual(variables[3].value, `4`); + node = `std::deque with 7 elements = {0, 1, 2, 3, 4, 5, 6}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[6].value, `6`); + node = `std::__cxx11::list = {[0] = 6, [1] = 7, [2] = 8, [3] = 9, [4] = 10}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[4].value, `10`); + node = `std::vector of length 4, capacity 6 = {std::vector of length 3, capacity 3 = {1, 2, 3}, std::vector of length 3, capacity 3 = {4, 5, 6}, std::vector of length 3, capacity 3 = {7, 8, 9}, std::vector of length 4, capacity 4 = {1, 2, 3, 4}}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[3].variablesReference.expanded[3].value, `4`); + node = `std::deque with 3 elements = {std::deque with 2 elements = {10, 20}, std::deque with 2 elements = {30, 40}, std::deque with 7 elements = {0, 1, 2, 3, 4, 5, 6}}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[2].variablesReference.expanded[6].value, `6`); + node = `std::__cxx11::list = {[0] = std::__cxx11::list = {[0] = 11, [1] = 12}, [1] = std::__cxx11::list = {[0] = 13, [1] = 14}, [2] = std::__cxx11::list = {[0] = 6, [1] = 7, [2] = 8, [3] = 9, [4] = 10}}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[2].variablesReference.expanded[4].value, `10`); + node = `std::forward_list = {[0] = 0, [1] = 1, [2] = 2, [3] = 3}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[3].value, `3`); + node = `std::set with 5 elements = {[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[4].value, `5`); + node = `std::multiset with 6 elements = {[0] = 1, [1] = 2, [2] = 2, [3] = 2, [4] = 3, [5] = 4}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[5].value, `4`); + node = `std::map with 3 elements = {[1] = \"one\", [2] = \"two\", [3] = \"three\"}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[2].value, `"three"`); + node = `std::multimap with 3 elements = {[1] = \"one\", [2] = \"two\", [2] = \"another two\"}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[2].value, `"another two"`); + node = `std::unordered_set with 5 elements = {[0] = 5, [1] = 2, [2] = 3, [3] = 1, [4] = 4}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[4].value, `4`); + node = `std::unordered_multiset with 6 elements = {[0] = 1, [1] = 2, [2] = 2, [3] = 2, [4] = 3, [5] = 4}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[5].value, `4`); + node = `std::unordered_map with 3 elements = {[3] = \"three\", [1] = \"one\", [2] = \"two\"}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[2].value, `"two"`); + node = `std::unordered_multimap with 3 elements = {[2] = \"another two\", [2] = \"two\", [1] = \"one\"}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[2].value, `"one"`); + node = `std::stack wrapping: std::deque with 2 elements = {1, 2}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[1].value, `2`); + node = `std::queue wrapping: std::deque with 2 elements = {1, 2}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[1].value, `2`); + node = `std::priority_queue wrapping: std::vector of length 3, capacity 4 = {4, 1, 3}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[2].value, `3`); + node = `std::bitset = {[0] = 1, [2] = 1, [4] = 1, [6] = 1, [7] = 1}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[3].value, `1`); + node = `{_M_elems = {1, 2, 3}}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[0].variablesReference.expanded[2].value, `3`); + node = `std::unique_ptr = {get() = 0x5555555d7d20}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[0].name, `get()`); + assert.strictEqual(variables[0].value, `Object@*0x5555555d7d20`); + node = `std::unique_ptr = {get() = 0x5555555d7d40}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[0].name, `get()`); + assert.strictEqual(variables[0].value, `Object@*0x5555555d7d40`); + node = `std::shared_ptr (use count 1, weak count 1) = {get() = 0x5555555d7d70}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[0].name, `get()`); + assert.strictEqual(variables[0].value, `Object@*0x5555555d7d70`); + node = `{> = {static _S_alignment = 4, _M_i = 0}, }`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[0].name, `std::__atomic_base>`); + assert.strictEqual(variables[0].variablesReference.expanded[1].name, `_M_i`); + assert.strictEqual(variables[0].variablesReference.expanded[1].value, `0`); + node = `{ = {_M_mutex = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, __next = 0x0}}, __size = '\\000' , __align = 0}}, }`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[0].variablesReference.expanded[0].variablesReference.expanded[0].variablesReference.expanded[7].variablesReference.expanded[1].name, `__next`); + assert.strictEqual(variables[0].variablesReference.expanded[0].variablesReference.expanded[0].variablesReference.expanded[7].variablesReference.expanded[1].value, ``); + node = `{static icase = , static nosubs = , static optimize = , static collate = , static ECMAScript = (unknown: 16), static basic = , static extended = , static awk = , static grep = , static egrep = , _M_flags = (unknown: 16), _M_loc = {static none = 0, static ctype = 1, static numeric = 2, static collate = 4, static time = 8, static monetary = 16, static messages = 32, static all = 63, _M_impl = 0x7ffff7fa8ce0, static _S_classic = , static _S_global = , static _S_categories = , static _S_once = , static _S_twinned_facets = }, _M_automaton = std::shared_ptr >> (use count 1, weak count 0) = {get() = 0x5555555d81b0}}`; + variables = expandValue(variableCreate, node); + assert.strictEqual(variables[12].name, `_M_automaton`); + assert.strictEqual(variables[12].variablesReference.expanded[0].value, `Object@*0x5555555d81b0`); + + }); });