Skip to content

Commit c82b8f2

Browse files
robertsipkartakacs
authored andcommitted
Support the scope and variables requests (#30)
Retrieve the list of variables at the current scope and show them under the variables pane. IoT.js-VSCode-DCO-1.0-Signed-off-by: Robert Sipka [email protected]
1 parent 77c23f7 commit c82b8f2

File tree

3 files changed

+248
-6
lines changed

3 files changed

+248
-6
lines changed

src/IotjsDebugger.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
'use strict';
1818

1919
import {
20-
DebugSession, InitializedEvent, OutputEvent, Thread, Source,
20+
DebugSession, Handles, InitializedEvent, OutputEvent, Thread, Scope, Source,
2121
StoppedEvent, StackFrame, TerminatedEvent, Event, ErrorDestination
2222
} from 'vscode-debugadapter';
2323
import { DebugProtocol } from 'vscode-debugprotocol';
@@ -30,7 +30,7 @@ import { IAttachRequestArguments, ILaunchRequestArguments, SourceSendingOptions,
3030
import { JerryDebuggerClient, JerryDebuggerOptions } from './JerryDebuggerClient';
3131
import {
3232
JerryDebugProtocolDelegate, JerryDebugProtocolHandler, JerryMessageScriptParsed, JerryEvalResult,
33-
JerryMessageExceptionHit, JerryMessageBreakpointHit, JerryBacktraceResult
33+
JerryMessageExceptionHit, JerryMessageBreakpointHit, JerryBacktraceResult, JerryScopeVariable, JerryScopeChain
3434
} from './JerryProtocolHandler';
3535
import { EVAL_RESULT_SUBTYPE, CLIENT as CLIENT_PACKAGE } from './JerryProtocolConstants';
3636
import { Breakpoint } from './JerryBreakpoints';
@@ -48,6 +48,7 @@ class IotjsDebugSession extends DebugSession {
4848
private _debuggerClient: JerryDebuggerClient;
4949
private _protocolhandler: JerryDebugProtocolHandler;
5050
private _sourceSendingOptions: SourceSendingOptions;
51+
private _variableHandles = new Handles<string>();
5152

5253
public constructor() {
5354
super();
@@ -451,6 +452,55 @@ class IotjsDebugSession extends DebugSession {
451452
}
452453
}
453454

455+
456+
protected async scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments
457+
): Promise<void> {
458+
try {
459+
const scopesArray: Array<JerryScopeChain> = await this._protocolhandler.requestScopes();
460+
const scopes = new Array<Scope>();
461+
462+
for (const scope of scopesArray) {
463+
scopes.push(new Scope(scope.name,
464+
this._variableHandles.create(scope.variablesReference.toString()),
465+
scope.expensive));
466+
}
467+
468+
response.body = {
469+
scopes: scopes
470+
};
471+
472+
this.sendResponse(response);
473+
} catch (error) {
474+
this.log(error.message, LOG_LEVEL.ERROR);
475+
this.sendErrorResponse(response, 0, (<Error>error).message);
476+
}
477+
}
478+
479+
protected async variablesRequest(response: DebugProtocol.VariablesResponse,
480+
args: DebugProtocol.VariablesArguments
481+
): Promise<void> {
482+
try {
483+
const variables = new Array<DebugProtocol.Variable>();
484+
const id = this._variableHandles.get(args.variablesReference);
485+
const scopeVariables: Array<JerryScopeVariable> = await this._protocolhandler.requestVariables(Number(id));
486+
487+
for (const variable of scopeVariables) {
488+
variables.push({name: variable.name,
489+
type: variable.type,
490+
value: variable.value,
491+
variablesReference: 0});
492+
}
493+
494+
response.body = {
495+
variables: variables
496+
};
497+
this.sendResponse(response);
498+
} catch (error) {
499+
this.log(error.message, LOG_LEVEL.ERROR);
500+
this.sendErrorResponse(response, 0, (<Error>error).message);
501+
}
502+
}
503+
454504
protected customRequest(command: string, response: DebugProtocol.Response, args: any): void {
455505
switch (command) {
456506
case 'sendSource': {

src/JerryProtocolConstants.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
'use strict';
1818

1919
// Expected JerryScript debugger protocol version.
20-
export const JERRY_DEBUGGER_VERSION = 6;
20+
export const JERRY_DEBUGGER_VERSION = 7;
2121

2222
// Packages sent from the server to the client.
2323
export enum SERVER {
@@ -47,7 +47,11 @@ export enum SERVER {
4747
JERRY_DEBUGGER_EVAL_RESULT_END = 24,
4848
JERRY_DEBUGGER_WAIT_FOR_SOURCE = 25,
4949
JERRY_DEBUGGER_OUTPUT_RESULT = 26,
50-
JERRY_DEBUGGER_OUTPUT_RESULT_END = 27
50+
JERRY_DEBUGGER_OUTPUT_RESULT_END = 27,
51+
JERRY_DEBUGGER_SCOPE_CHAIN = 28,
52+
JERRY_DEBUGGER_SCOPE_CHAIN_END = 29,
53+
JERRY_DEBUGGER_SCOPE_VARIABLES = 30,
54+
JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31
5155
}
5256

5357
// Subtypes of eval.
@@ -91,5 +95,29 @@ export enum CLIENT {
9195
JERRY_DEBUGGER_FINISH = 15,
9296
JERRY_DEBUGGER_GET_BACKTRACE = 16,
9397
JERRY_DEBUGGER_EVAL = 17,
94-
JERRY_DEBUGGER_EVAL_PART = 18
98+
JERRY_DEBUGGER_EVAL_PART = 18,
99+
JERRY_DEBUGGER_GET_SCOPE_CHAIN = 19,
100+
JERRY_DEBUGGER_GET_SCOPE_VARIABLES = 20
101+
}
102+
103+
// Types of scope chain.
104+
export enum JERRY_DEBUGGER_SCOPE_TYPE {
105+
JERRY_DEBUGGER_SCOPE_WITH = 1,
106+
JERRY_DEBUGGER_SCOPE_LOCAL = 2,
107+
JERRY_DEBUGGER_SCOPE_CLOSURE = 3,
108+
JERRY_DEBUGGER_SCOPE_GLOBAL = 4,
109+
JERRY_DEBUGGER_SCOPE_NON_CLOSURE = 5
110+
}
111+
112+
// Type of scope variables.
113+
export enum JERRY_DEBUGGER_SCOPE_VARIABLES {
114+
JERRY_DEBUGGER_VALUE_NONE = 1,
115+
JERRY_DEBUGGER_VALUE_UNDEFINED = 2,
116+
JERRY_DEBUGGER_VALUE_NULL = 3,
117+
JERRY_DEBUGGER_VALUE_BOOLEAN = 4,
118+
JERRY_DEBUGGER_VALUE_NUMBER = 5,
119+
JERRY_DEBUGGER_VALUE_STRING = 6,
120+
JERRY_DEBUGGER_VALUE_FUNCTION = 7,
121+
JERRY_DEBUGGER_VALUE_ARRAY = 8,
122+
JERRY_DEBUGGER_VALUE_OBJECT = 9
95123
}

src/JerryProtocolHandler.ts

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ class PendingRequest {
123123
}
124124
}
125125

126+
export interface JerryScopeChain {
127+
name: string;
128+
variablesReference: number;
129+
expensive: boolean;
130+
}
131+
132+
export interface JerryScopeVariable {
133+
name: string;
134+
type: string;
135+
value: string;
136+
}
137+
126138
// abstracts away the details of the protocol
127139
export class JerryDebugProtocolHandler {
128140
public debuggerClient?: JerryDebuggerClient;
@@ -149,6 +161,8 @@ export class JerryDebugProtocolHandler {
149161
private functions: FunctionMap = {};
150162
private newFunctions: FunctionMap = {};
151163
private backtraceData: JerryBacktraceResult = {totalFrames : 0, backtrace: []};
164+
private scopeMessage?: Array<number> = [];
165+
private scopeVariableMessage?: string = '';
152166

153167
private nextScriptID: number = 1;
154168
private exceptionData?: Uint8Array;
@@ -197,7 +211,11 @@ export class JerryDebugProtocolHandler {
197211
[SP.SERVER.JERRY_DEBUGGER_BACKTRACE_END]: this.onBacktrace,
198212
[SP.SERVER.JERRY_DEBUGGER_EVAL_RESULT]: this.onEvalResult,
199213
[SP.SERVER.JERRY_DEBUGGER_EVAL_RESULT_END]: this.onEvalResult,
200-
[SP.SERVER.JERRY_DEBUGGER_WAIT_FOR_SOURCE]: this.onWaitForSource
214+
[SP.SERVER.JERRY_DEBUGGER_WAIT_FOR_SOURCE]: this.onWaitForSource,
215+
[SP.SERVER.JERRY_DEBUGGER_SCOPE_CHAIN]: this.onScopeChain,
216+
[SP.SERVER.JERRY_DEBUGGER_SCOPE_CHAIN_END]: this.onScopeChainEnd,
217+
[SP.SERVER.JERRY_DEBUGGER_SCOPE_VARIABLES]: this.onScopeVariables,
218+
[SP.SERVER.JERRY_DEBUGGER_SCOPE_VARIABLES_END]: this.onScopeVariablesEnd
201219
};
202220

203221
this.requestQueue = [];
@@ -586,6 +604,132 @@ export class JerryDebugProtocolHandler {
586604
return this.backtraceData;
587605
}
588606

607+
public onScopeChain(data: Uint8Array): void {
608+
this.logPacket('ScopeChain');
609+
610+
for (let i = 1; i < data.byteLength; i++) {
611+
this.scopeMessage.push(data[i]);
612+
}
613+
}
614+
615+
public onScopeChainEnd(data: Uint8Array): Array<JerryScopeChain> {
616+
this.logPacket('ScopeChainEnd');
617+
618+
for (let i = 1; i < data.byteLength; i++) {
619+
this.scopeMessage.push(data[i]);
620+
}
621+
622+
const scopes: Array<JerryScopeChain> = [];
623+
for (let i = 0; i < this.scopeMessage.length; i++) {
624+
switch (this.scopeMessage[i]) {
625+
case SP.JERRY_DEBUGGER_SCOPE_TYPE.JERRY_DEBUGGER_SCOPE_WITH: {
626+
scopes.push({name: 'with', variablesReference: i, expensive: true});
627+
break;
628+
}
629+
case SP.JERRY_DEBUGGER_SCOPE_TYPE.JERRY_DEBUGGER_SCOPE_LOCAL: {
630+
scopes.push({name: 'local', variablesReference: i, expensive: true});
631+
break;
632+
}
633+
case SP.JERRY_DEBUGGER_SCOPE_TYPE.JERRY_DEBUGGER_SCOPE_CLOSURE: {
634+
scopes.push({name: 'closure', variablesReference: i, expensive: true});
635+
break;
636+
}
637+
case SP.JERRY_DEBUGGER_SCOPE_TYPE.JERRY_DEBUGGER_SCOPE_GLOBAL: {
638+
scopes.push({name: 'global', variablesReference: i, expensive: true});
639+
break;
640+
}
641+
case SP.JERRY_DEBUGGER_SCOPE_TYPE.JERRY_DEBUGGER_SCOPE_NON_CLOSURE: {
642+
scopes.push({name: 'catch', variablesReference: i, expensive: true});
643+
break;
644+
}
645+
default: {
646+
throw new Error('Invalid scope chain type!');
647+
}
648+
}
649+
}
650+
this.scopeMessage = [];
651+
652+
return scopes;
653+
}
654+
655+
public onScopeVariables(data: Uint8Array): void {
656+
this.logPacket('ScopeVariables');
657+
for (let i = 1; i < data.byteLength; i++) {
658+
this.scopeVariableMessage += String.fromCharCode(data[i]);
659+
}
660+
}
661+
662+
public onScopeVariablesEnd(data: Uint8Array): Array<JerryScopeVariable> {
663+
this.logPacket('ScopeVariablesEnd');
664+
665+
for (let i = 1; i < data.byteLength; i++) {
666+
this.scopeVariableMessage += String.fromCharCode(data[i]);
667+
}
668+
669+
let buff_pos = 0;
670+
const scopeVariablesArray: Array<JerryScopeVariable> = [];
671+
672+
while (buff_pos < this.scopeVariableMessage.length) {
673+
let scopeVariable: JerryScopeVariable = {name: '', type: '', value: ''};
674+
675+
// Process name.
676+
const name_length = this.scopeVariableMessage[buff_pos++].charCodeAt(0);
677+
scopeVariable.name = this.scopeVariableMessage.substring(buff_pos, buff_pos + name_length);
678+
679+
buff_pos += name_length;
680+
681+
// Process type
682+
const value_type: SP.JERRY_DEBUGGER_SCOPE_VARIABLES = this.scopeVariableMessage[buff_pos++].charCodeAt(0);
683+
const value_length = this.scopeVariableMessage[buff_pos++].charCodeAt(0);
684+
685+
scopeVariable.value = this.scopeVariableMessage.substring(buff_pos, buff_pos + value_length);
686+
buff_pos += value_length;
687+
688+
switch (value_type) {
689+
case (SP.JERRY_DEBUGGER_SCOPE_VARIABLES.JERRY_DEBUGGER_VALUE_UNDEFINED): {
690+
scopeVariable.type = 'undefined';
691+
break;
692+
}
693+
case (SP.JERRY_DEBUGGER_SCOPE_VARIABLES.JERRY_DEBUGGER_VALUE_NULL): {
694+
scopeVariable.type = 'Null';
695+
break;
696+
}
697+
case (SP.JERRY_DEBUGGER_SCOPE_VARIABLES.JERRY_DEBUGGER_VALUE_BOOLEAN): {
698+
scopeVariable.type = 'Boolean';
699+
break;
700+
}
701+
case (SP.JERRY_DEBUGGER_SCOPE_VARIABLES.JERRY_DEBUGGER_VALUE_NUMBER): {
702+
scopeVariable.type = 'Number';
703+
break;
704+
}
705+
case (SP.JERRY_DEBUGGER_SCOPE_VARIABLES.JERRY_DEBUGGER_VALUE_STRING): {
706+
scopeVariable.type = 'String';
707+
break;
708+
}
709+
case (SP.JERRY_DEBUGGER_SCOPE_VARIABLES.JERRY_DEBUGGER_VALUE_FUNCTION): {
710+
scopeVariable.type = 'Function';
711+
break;
712+
}
713+
case (SP.JERRY_DEBUGGER_SCOPE_VARIABLES.JERRY_DEBUGGER_VALUE_ARRAY): {
714+
scopeVariable.type = 'Array';
715+
scopeVariable.value = '[' + scopeVariable.value + ']';
716+
break;
717+
}
718+
case (SP.JERRY_DEBUGGER_SCOPE_VARIABLES.JERRY_DEBUGGER_VALUE_OBJECT): {
719+
scopeVariable.type = 'Object';
720+
break;
721+
}
722+
default: {
723+
throw new Error('Invalid scope variable type!');
724+
}
725+
}
726+
scopeVariablesArray.push(scopeVariable);
727+
}
728+
this.scopeVariableMessage = '';
729+
730+
return scopeVariablesArray;
731+
}
732+
589733
public onEvalResult(data: Uint8Array): JerryEvalResult {
590734
this.logPacket('Eval Result');
591735

@@ -776,6 +920,26 @@ export class JerryDebugProtocolHandler {
776920
1]));
777921
}
778922

923+
public requestScopes(): Promise<any> {
924+
if (!this.lastBreakpointHit) {
925+
return Promise.reject(new Error('scope chain not allowed while app running'));
926+
}
927+
928+
return this.sendRequest(encodeMessage(this.byteConfig, 'B',
929+
[SP.CLIENT.JERRY_DEBUGGER_GET_SCOPE_CHAIN]));
930+
}
931+
932+
public requestVariables(level?: number): Promise<any> {
933+
if (!this.lastBreakpointHit) {
934+
return Promise.reject(new Error('scope variables not allowed while app running'));
935+
}
936+
937+
return this.sendRequest(encodeMessage(this.byteConfig, 'BI',
938+
[SP.CLIENT.JERRY_DEBUGGER_GET_SCOPE_VARIABLES,
939+
level]));
940+
941+
}
942+
779943
logPacket(description: string, ignorable: boolean = false) {
780944
// certain packets are ignored while evals are pending
781945
const ignored = (ignorable && this.evalsPending) ? 'Ignored: ' : '';

0 commit comments

Comments
 (0)