si-debug
Version:
GDB, LLDB & Mago-MI Debugger support for SuperIDE
259 lines (241 loc) • 7.27 kB
text/typescript
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 errorRegex = /^\<.+?\>/;
const referenceStringRegex = /^(0x[0-9a-fA-F]+\s*)"/;
const referenceRegex = /^0x[0-9a-fA-F]+/;
const cppReferenceRegex = /^@0x[0-9a-fA-F]+/;
const nullpointerRegex = /^0x0+\b/;
const charRegex = /^(\d+) ['"]/;
const numberRegex = /^\d+(\.\d+)?/;
const pointerCombineChar = ".";
export function isExpandable(value: string): number {
let match;
value = value.trim();
if (value.length == 0) return 0;
else if (value.startsWith("{...}")) return 2; // lldb string/array
else if (value[0] == '{') return 1; // object
else if (value.startsWith("true")) return 0;
else if (value.startsWith("false")) return 0;
else if (match = nullpointerRegex.exec(value)) return 0;
else if (match = referenceStringRegex.exec(value)) return 0;
else if (match = referenceRegex.exec(value)) return 2; // reference
else if (match = charRegex.exec(value)) return 0;
else if (match = numberRegex.exec(value)) return 0;
else if (match = variableRegex.exec(value)) return 0;
else if (match = errorRegex.exec(value)) return 0;
else return 0;
}
export function expandValue(variableCreate: Function, value: string, root: string = "", extra: any = undefined): any {
const parseCString = () => {
value = value.trim();
if (value[0] != '"' && value[0] != '\'')
return "";
let stringEnd = 1;
let inString = true;
const charStr = value[0];
let remaining = value.substring(1);
let escaped = false;
while (inString) {
if (escaped)
escaped = false;
else if (remaining[0] == '\\')
escaped = true;
else if (remaining[0] == charStr)
inString = false;
remaining = remaining.substring(1);
stringEnd++;
}
const str = value.substring(0, stringEnd).trim();
value = value.substring(stringEnd).trim();
return str;
};
const stack = [root];
let parseValue, parseCommaResult, parseCommaValue, parseResult, createValue;
let variable = "";
const getNamespace = (variable) => {
let namespace = "";
let prefix = "";
stack.push(variable);
stack.forEach(name => {
prefix = "";
if (name != "") {
if (name.startsWith("["))
namespace = namespace + name;
else {
if (namespace) {
while (name.startsWith("*")) {
prefix += "*";
name = name.substring(1);
}
namespace = namespace + pointerCombineChar + name;
} else
namespace = name;
}
}
});
stack.pop();
return prefix + namespace;
};
const parseTupleOrList = () => {
value = value.trim();
if (value[0] != '{')
return undefined;
const oldContent = value;
value = value.substring(1).trim();
if (value[0] == '}') {
value = value.substring(1).trim();
return [];
}
if (value.startsWith("...")) {
value = value.substring(3).trim();
if (value[0] == '}') {
value = value.substring(1).trim();
return <any> "<...>";
}
}
const eqPos = value.indexOf("=");
const newValPos1 = value.indexOf("{");
const newValPos2 = value.indexOf(",");
let newValPos = newValPos1;
if (newValPos2 != -1 && newValPos2 < newValPos1)
newValPos = newValPos2;
if (newValPos != -1 && eqPos > newValPos || eqPos == -1) { // is value list
const values = [];
stack.push("[0]");
let val = parseValue();
stack.pop();
values.push(createValue("[0]", val));
const remaining = value;
let i = 0;
for (;;) {
stack.push("[" + (++i) + "]");
if (!(val = parseCommaValue())) {
stack.pop();
break;
}
stack.pop();
values.push(createValue("[" + i + "]", val));
}
value = value.substring(1).trim(); // }
return values;
}
let result = parseResult(true);
if (result) {
const results = [];
results.push(result);
while (result = parseCommaResult(true))
results.push(result);
value = value.substring(1).trim(); // }
return results;
}
return undefined;
};
const parsePrimitive = () => {
let primitive: any;
let match;
value = value.trim();
if (value.length == 0)
primitive = undefined;
else if (value.startsWith("true")) {
primitive = "true";
value = value.substring(4).trim();
} else if (value.startsWith("false")) {
primitive = "false";
value = value.substring(5).trim();
} else if (match = nullpointerRegex.exec(value)) {
primitive = "<nullptr>";
value = value.substring(match[0].length).trim();
} else if (match = referenceStringRegex.exec(value)) {
value = value.substring(match[1].length).trim();
primitive = parseCString();
} else if (match = referenceRegex.exec(value)) {
primitive = "*" + match[0];
value = value.substring(match[0].length).trim();
} else if (match = cppReferenceRegex.exec(value)) {
primitive = match[0];
value = value.substring(match[0].length).trim();
} else if (match = charRegex.exec(value)) {
primitive = match[1];
value = value.substring(match[0].length - 1);
primitive += " " + parseCString();
} else if (match = numberRegex.exec(value)) {
primitive = match[0];
value = value.substring(match[0].length).trim();
} else if (match = variableRegex.exec(value)) {
primitive = match[0];
value = value.substring(match[0].length).trim();
} else if (match = errorRegex.exec(value)) {
primitive = match[0];
value = value.substring(match[0].length).trim();
} else {
primitive = value;
}
return primitive;
};
parseValue = () => {
value = value.trim();
if (value[0] == '"')
return parseCString();
else if (value[0] == '{')
return parseTupleOrList();
else
return parsePrimitive();
};
parseResult = (pushToStack: boolean = false) => {
value = value.trim();
const variableMatch = resultRegex.exec(value);
if (!variableMatch)
return undefined;
value = value.substring(variableMatch[0].length).trim();
const name = variable = variableMatch[1];
if (pushToStack)
stack.push(variable);
const val = parseValue();
if (pushToStack)
stack.pop();
return createValue(name, val);
};
createValue = (name, val) => {
let ref = 0;
if (typeof val == "object") {
ref = variableCreate(val);
val = "Object";
} else if (typeof val == "string" && val.startsWith("*0x")) {
if (extra && MINode.valueOf(extra, "arg") == "1") {
ref = variableCreate(getNamespace("*(" + name), { arg: true });
val = "<args>";
} else {
ref = variableCreate(getNamespace("*" + name));
val = "Object@" + val;
}
} else if (typeof val == "string" && val.startsWith("@0x")) {
ref = variableCreate(getNamespace("*&" + name.substr));
val = "Ref" + val;
} else if (typeof val == "string" && val.startsWith("<...>")) {
ref = variableCreate(getNamespace(name));
val = "...";
}
return {
name: name,
value: val,
variablesReference: ref
};
};
parseCommaValue = () => {
value = value.trim();
if (value[0] != ',')
return undefined;
value = value.substring(1).trim();
return parseValue();
};
parseCommaResult = (pushToStack: boolean = false) => {
value = value.trim();
if (value[0] != ',')
return undefined;
value = value.substring(1).trim();
return parseResult(pushToStack);
};
value = value.trim();
return parseValue();
}