Skip to content
Snippets Groups Projects
gdb_expansion.ts 8.47 KiB
Newer Older
import { MINode } from "./mi_parse";
const resultRegex = /^([0-9a-zA-Z_\-][a-zA-Z0-9_\-\/]*|\[\d+\])\s*=\s*/;  // Dubner added \/ so that a COBOL 'A of B 'could be represented 'A/b'
const variableRegex = /^[0-9a-zA-Z_\-][a-zA-Z0-9_\-\/]*/;  			   // Dubner added \/ so that a COBOL 'A of B' could be represented 'A/b'
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;
}

function GetImmediateGroupValue(str:string) : string {
		var retval:string = "";
		const find_me:string = "{_groupvalue=\"";
		var nfound:number = str.indexOf(find_me);
		if( nfound == 0 ) {
			nfound += find_me.length;
			while( nfound < str.length && str[nfound] != '"' ) {
				retval += str[nfound];
				nfound += 1;
			}
		}
		return retval;
	};

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.substr(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.substr(1);
			stringEnd++;
		}
		const str = value.substr(0, stringEnd).trim();
		value = value.substr(stringEnd).trim();
		return str;
	};

	const stack = [root];
	const stack_of_groupvalues = [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.substr(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.substr(1).trim();
		if (value[0] == '}') {
			value = value.substr(1).trim();
			return [];
		}
		if (value.startsWith("...")) {
			value = value.substr(3).trim();
			if (value[0] == '}') {
				value = value.substr(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;
			while (true) {
				stack.push("[" + (++i) + "]");
				if (!(val = parseCommaValue())) {
					stack.pop();
				values.push(createValue("[" + i + "]", val));
			}
			value = value.substr(1).trim(); // }
			return values;
		}

		let result = parseResult(true);
		if (result) {
			// Dubner added this _groupvalue hack.  It is a pseudo-variable that
			// doesn't appear in the locals list, but rather replaces the word
			// 'Group' in a heirarchical variable listing.  This code prevents
			// it from appearing as a variable in the list
			}
			while (result = parseCommaResult(true)){
				if(result["name"] != "_groupvalue"){
					results.push(result);
				}
			}
			value = value.substr(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.substr(4).trim();
		} else if (value.startsWith("false")) {
			primitive = "false";
			value = value.substr(5).trim();
		} else if (match = nullpointerRegex.exec(value)) {
			primitive = "<nullptr>";
			value = value.substr(match[0].length).trim();
		} else if (match = referenceStringRegex.exec(value)) {
			value = value.substr(match[1].length).trim();
			primitive = parseCString();
		} else if (match = referenceRegex.exec(value)) {
			primitive = "*" + match[0];
			value = value.substr(match[0].length).trim();
		} else if (match = cppReferenceRegex.exec(value)) {
			primitive = match[0];
			value = value.substr(match[0].length).trim();
		} else if (match = charRegex.exec(value)) {
			primitive = match[1];
			value = value.substr(match[0].length - 1);
			primitive += " " + parseCString();
		} else if (match = numberRegex.exec(value)) {
			primitive = match[0];
			value = value.substr(match[0].length).trim();
		} else if (match = variableRegex.exec(value)) {
			primitive = match[0];
			value = value.substr(match[0].length).trim();
		} else if (match = errorRegex.exec(value)) {
			primitive = match[0];
			value = value.substr(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.substr(variableMatch[0].length).trim();
		const name = variable = variableMatch[1];
			var groupvalue:string = GetImmediateGroupValue(value);
			stack_of_groupvalues.push(groupvalue);
		}
		}
		var retval = createValue(name, val);
		if (pushToStack){
			stack_of_groupvalues.pop();
		}
		return retval
	};

	createValue = (name, val) => {
		let ref = 0;
		if (typeof val == "object") {
			ref = variableCreate(val);
			//val = "Objecttt";		// This is the original code
			val = stack_of_groupvalues[stack_of_groupvalues.length-1];

		} 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.substr(1).trim();
		return parseValue();
	};

	parseCommaResult = (pushToStack: boolean = false) => {
		value = value.trim();
		if (value[0] != ',')
			return undefined;
		value = value.substr(1).trim();
		return parseResult(pushToStack);
	};


	value = value.trim();
	return parseValue();
}