Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add children roSGNode containers #192

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
3 changes: 2 additions & 1 deletion src/adapters/DebugProtocolAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,8 @@ describe('DebugProtocolAdapter', function() {
container?.children.map(x => x.evaluateName)
).to.eql([
'person["name"]',
'person["age"]'
'person["age"]',
'2'
]);
//the top level object should be an AA
expect(container.type).to.eql(VariableType.AssociativeArray);
Expand Down
35 changes: 31 additions & 4 deletions src/adapters/DebugProtocolAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,33 @@ export class DebugProtocolAdapter {
//this is the top-level container, so there are no parent keys to this entry
undefined
);
if (container?.value?.startsWith('roSGNode')) {
let nodeChildren = <EvaluateContainer>{
name: '[[children]]',
type: 'roArray',
highLevelType: 'array',
keyType: KeyType.integer,
presentationHint: 'virtual',
evaluateName: `${expression}.getChildren(-1, 0)`,
children: []
};
container.children.push(nodeChildren);
}
if (container.elementCount > 0 || container.type === 'Array') {
let nodeCount = <EvaluateContainer>{
name: '[[count]]',
Christian-Holbrook marked this conversation as resolved.
Show resolved Hide resolved
evaluateName: container.elementCount.toString(),
type: 'number',
highLevelType: undefined,
keyType: undefined,
presentationHint: 'virtual',
value: container.elementCount.toString(),
elementCount: undefined,
children: []
};
container.children.push(nodeCount);
}

return container;
}
}
Expand Down Expand Up @@ -636,7 +663,7 @@ export class DebugProtocolAdapter {
* @param name the name of this variable. For example, `alpha.beta.charlie`, this value would be `charlie`. For local vars, this is the root variable name (i.e. `alpha`)
* @param parentEvaluateName the string used to derive the parent, _excluding_ this variable's name (i.e. `alpha.beta` or `alpha[0]`)
*/
private createEvaluateContainer(variable: Variable, name: string, parentEvaluateName: string) {
private createEvaluateContainer(variable: Variable, name: string | number, parentEvaluateName: string) {
let value;
let variableType = variable.type;
if (variable.value === null) {
Expand All @@ -658,15 +685,15 @@ export class DebugProtocolAdapter {
//build full evaluate name for this var. (i.e. `alpha["beta"]` + ["charlie"]` === `alpha["beta"]["charlie"]`)
let evaluateName: string;
if (!parentEvaluateName?.trim()) {
evaluateName = name;
evaluateName = name?.toString();
} else if (typeof name === 'string') {
evaluateName = `${parentEvaluateName}["${name}"]`;
} else if (typeof name === 'number') {
evaluateName = `${parentEvaluateName}[${name}]`;
}

let container: EvaluateContainer = {
name: name ?? '',
name: name?.toString() ?? '',
evaluateName: evaluateName ?? '',
type: variableType ?? '',
value: value ?? null,
Expand All @@ -685,7 +712,7 @@ export class DebugProtocolAdapter {
const childVariable = variable.children[i];
const childContainer = this.createEvaluateContainer(
childVariable,
container.keyType === KeyType.integer ? i.toString() : childVariable.name,
container.keyType === KeyType.integer ? i : childVariable.name,
container.evaluateName
);
container.children.push(childContainer);
Expand Down
55 changes: 31 additions & 24 deletions src/debugSession/BrightScriptDebugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,8 @@ export class BrightScriptDebugSession extends BaseDebugSession {
const vars = await (this.rokuAdapter as TelnetAdapter).getScopeVariables();

for (const varName of vars) {
let result = await this.rokuAdapter.getVariable(varName, -1);
let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: varName, frameId: -1 }, util.getVariablePath(varName));
let result = await this.rokuAdapter.getVariable(evalArgs.expression, -1);
let tempVar = this.getVariableFromResult(result, -1);
childVariables.push(tempVar);
}
Expand All @@ -1117,7 +1118,8 @@ export class BrightScriptDebugSession extends BaseDebugSession {
logger.log('variable', v);
//query for child vars if we haven't done it yet.
if (v.childVariables.length === 0) {
let result = await this.rokuAdapter.getVariable(v.evaluateName, v.frameId);
let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: v.evaluateName, frameId: v.frameId }, util.getVariablePath(v.evaluateName));
let result = await this.rokuAdapter.getVariable(evalArgs.expression, v.frameId);
let tempVar = this.getVariableFromResult(result, v.frameId);
tempVar.frameId = v.frameId;
v.childVariables = tempVar.childVariables;
Expand Down Expand Up @@ -1195,41 +1197,26 @@ export class BrightScriptDebugSession extends BaseDebugSession {

//is at debugger prompt
} else {
let variablePath = util.getVariablePath(args.expression);
if (!variablePath && util.isAssignableExpression(args.expression)) {
let varIndex = this.getNextVarIndex(args.frameId);
let arrayVarName = this.tempVarPrefix + 'eval';
if (varIndex === 0) {
const response = await this.rokuAdapter.evaluate(`${arrayVarName} = []`, args.frameId);
console.log(response);
}
let statement = `${arrayVarName}[${varIndex}] = ${args.expression}`;
args.expression = `${arrayVarName}[${varIndex}]`;
let commandResults = await this.rokuAdapter.evaluate(statement, args.frameId);
if (commandResults.type === 'error') {
throw new Error(commandResults.message);
}
variablePath = [arrayVarName, varIndex.toString()];
}
let { evalArgs, variablePath } = await this.evaluateExpressionToTempVar(args, util.getVariablePath(args.expression));

//if we found a variable path (e.g. ['a', 'b', 'c']) then do a variable lookup because it's faster and more widely supported than `evaluate`
if (variablePath) {
let refId = this.getEvaluateRefId(args.expression, args.frameId);
let refId = this.getEvaluateRefId(evalArgs.expression, evalArgs.frameId);
let v: AugmentedVariable;
//if we already looked this item up, return it
if (this.variables[refId]) {
v = this.variables[refId];
} else {
let result = await this.rokuAdapter.getVariable(args.expression, args.frameId);
let result = await this.rokuAdapter.getVariable(evalArgs.expression, evalArgs.frameId);
if (!result) {
throw new Error('Error: unable to evaluate expression');
}

v = this.getVariableFromResult(result, args.frameId);
v = this.getVariableFromResult(result, evalArgs.frameId);
//TODO - testing something, remove later
// eslint-disable-next-line camelcase
v.request_seq = response.request_seq;
v.frameId = args.frameId;
v.frameId = evalArgs.frameId;
}
response.body = {
result: v.value,
Expand All @@ -1241,13 +1228,13 @@ export class BrightScriptDebugSession extends BaseDebugSession {

//run an `evaluate` call
} else {
let commandResults = await this.rokuAdapter.evaluate(args.expression, args.frameId);
let commandResults = await this.rokuAdapter.evaluate(evalArgs.expression, evalArgs.frameId);

commandResults.message = util.trimDebugPrompt(commandResults.message);
if (args.context !== 'watch') {
//clear variable cache since this action could have side-effects
this.clearState();
this.sendInvalidatedEvent(null, args.frameId);
this.sendInvalidatedEvent(null, evalArgs.frameId);
}
//if the adapter captured output (probably only telnet), print it to the vscode debug console
if (typeof commandResults.message === 'string') {
Expand Down Expand Up @@ -1278,6 +1265,26 @@ export class BrightScriptDebugSession extends BaseDebugSession {
deferred.resolve();
}

private async evaluateExpressionToTempVar(args: DebugProtocol.EvaluateArguments, variablePath: string[]): Promise< { evalArgs: DebugProtocol.EvaluateArguments; variablePath: string[] } > {
let returnVal = { evalArgs: args, variablePath };
if (!variablePath && util.isAssignableExpression(args.expression)) {
let varIndex = this.getNextVarIndex(args.frameId);
let arrayVarName = this.tempVarPrefix + 'eval';
if (varIndex === 0) {
const response = await this.rokuAdapter.evaluate(`${arrayVarName} = []`, args.frameId);
console.log(response);
}
let statement = `${arrayVarName}[${varIndex}] = ${args.expression}`;
returnVal.evalArgs.expression = `${arrayVarName}[${varIndex}]`;
let commandResults = await this.rokuAdapter.evaluate(statement, args.frameId);
if (commandResults.type === 'error') {
throw new Error(commandResults.message);
}
returnVal.variablePath = [arrayVarName, varIndex.toString()];
}
return returnVal;
}

/**
* Called when the host stops debugging
* @param response
Expand Down