Helios-Debugger.st 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. Smalltalk createPackage: 'Helios-Debugger'!
  2. (Smalltalk packageAt: 'Helios-Debugger' ifAbsent: [ self error: 'Package not created: Helios-Debugger' ]) imports: {'amber/core/Compiler-Interpreter'}!
  3. Object subclass: #HLContextInspectorDecorator
  4. slots: {#context}
  5. package: 'Helios-Debugger'!
  6. !HLContextInspectorDecorator methodsFor: 'accessing'!
  7. context
  8. ^ context
  9. ! !
  10. !HLContextInspectorDecorator methodsFor: 'evaluating'!
  11. evaluate: aString on: anEvaluator
  12. ^ self context evaluate: aString on: anEvaluator
  13. ! !
  14. !HLContextInspectorDecorator methodsFor: 'initialization'!
  15. initializeFromContext: aContext
  16. context := aContext
  17. ! !
  18. !HLContextInspectorDecorator methodsFor: 'inspecting'!
  19. inspectOn: anInspector
  20. | variables inspectedContext |
  21. inspectedContext := self context. console log: 'paso por aqui'.
  22. variables := Array streamContents: [ :stream |
  23. stream nextPutAll: inspectedContext locals associations.
  24. [ inspectedContext notNil and: [ inspectedContext isBlockContext ] ] whileTrue: [
  25. inspectedContext := inspectedContext outerContext.
  26. inspectedContext ifNotNil: [
  27. stream nextPutAll: inspectedContext locals associations ] ] ].
  28. anInspector
  29. setLabel: 'Context';
  30. setVariables: variables
  31. ! !
  32. !HLContextInspectorDecorator class methodsFor: 'instance creation'!
  33. on: aContext
  34. ^ self new
  35. initializeFromContext: aContext;
  36. yourself
  37. ! !
  38. HLFocusableWidget subclass: #HLDebugger
  39. slots: {#model. #stackListWidget. #codeWidget. #inspectorWidget}
  40. package: 'Helios-Debugger'!
  41. !HLDebugger commentStamp!
  42. I am the main widget for the Helios debugger.!
  43. !HLDebugger methodsFor: 'accessing'!
  44. cssClass
  45. ^ super cssClass, ' hl_debugger'
  46. !
  47. model
  48. ^ model ifNil: [ model := HLDebuggerModel new ]
  49. ! !
  50. !HLDebugger methodsFor: 'actions'!
  51. focus
  52. self stackListWidget focus
  53. !
  54. observeModel
  55. self model announcer
  56. on: HLDebuggerContextSelected
  57. send: #onContextSelected:
  58. to: self;
  59. on: HLDebuggerStepped
  60. send: #onDebuggerStepped:
  61. to: self;
  62. on: HLDebuggerProceeded
  63. send: #onDebuggerProceeded
  64. to: self
  65. !
  66. unregister
  67. super unregister.
  68. self inspectorWidget unregister
  69. ! !
  70. !HLDebugger methodsFor: 'initialization'!
  71. initializeFromError: anError
  72. model := HLDebuggerModel on: anError.
  73. self observeModel
  74. ! !
  75. !HLDebugger methodsFor: 'keybindings'!
  76. registerBindingsOn: aBindingGroup
  77. HLToolCommand
  78. registerConcreteClassesOn: aBindingGroup
  79. for: self model
  80. ! !
  81. !HLDebugger methodsFor: 'reactions'!
  82. onContextSelected: anAnnouncement
  83. self inspectorWidget inspect: (HLContextInspectorDecorator on: anAnnouncement context)
  84. !
  85. onDebuggerProceeded
  86. self removeTab
  87. !
  88. onDebuggerStepped: anAnnouncement
  89. self model atEnd ifTrue: [ self removeTab ].
  90. self inspectorWidget inspect: (HLContextInspectorDecorator on: anAnnouncement context).
  91. self stackListWidget refresh
  92. ! !
  93. !HLDebugger methodsFor: 'rendering'!
  94. renderContentOn: html
  95. self renderHeadOn: html.
  96. html with: (HLContainer with: (HLVerticalSplitter
  97. with: self codeWidget
  98. with: (HLHorizontalSplitter
  99. with: self stackListWidget
  100. with: self inspectorWidget)))
  101. !
  102. renderHeadOn: html
  103. html div
  104. class: 'head';
  105. with: [ html h2 with: self model error messageText ]
  106. ! !
  107. !HLDebugger methodsFor: 'widgets'!
  108. codeWidget
  109. ^ codeWidget ifNil: [ codeWidget := HLDebuggerCodeWidget new
  110. model: (HLDebuggerCodeModel new
  111. debuggerModel: self model;
  112. yourself);
  113. browserModel: self model;
  114. yourself ]
  115. !
  116. inspectorWidget
  117. ^ inspectorWidget ifNil: [
  118. inspectorWidget := HLInspectorWidget new ]
  119. !
  120. stackListWidget
  121. ^ stackListWidget ifNil: [
  122. stackListWidget := (HLStackListWidget on: self model)
  123. next: self codeWidget;
  124. yourself ]
  125. ! !
  126. !HLDebugger class methodsFor: 'accessing'!
  127. tabClass
  128. ^ 'debugger'
  129. !
  130. tabLabel
  131. ^ 'Debugger'
  132. ! !
  133. !HLDebugger class methodsFor: 'instance creation'!
  134. on: anError
  135. ^ self new
  136. initializeFromError: anError;
  137. yourself
  138. ! !
  139. HLCodeModel subclass: #HLDebuggerCodeModel
  140. slots: {#debuggerModel}
  141. package: 'Helios-Debugger'!
  142. !HLDebuggerCodeModel methodsFor: 'accessing'!
  143. debuggerModel
  144. ^ debuggerModel
  145. !
  146. debuggerModel: anObject
  147. debuggerModel := anObject
  148. ! !
  149. !HLDebuggerCodeModel methodsFor: 'actions'!
  150. doIt: aString
  151. ^ self debuggerModel evaluate: aString
  152. ! !
  153. HLBrowserCodeWidget subclass: #HLDebuggerCodeWidget
  154. slots: {}
  155. package: 'Helios-Debugger'!
  156. !HLDebuggerCodeWidget methodsFor: 'accessing'!
  157. contents: aString
  158. self clearHighlight.
  159. super contents: aString
  160. !
  161. editorOptions
  162. ^ super editorOptions
  163. at: 'gutters' put: #('CodeMirror-linenumbers' 'stops');
  164. yourself
  165. ! !
  166. !HLDebuggerCodeWidget methodsFor: 'actions'!
  167. addStopAt: anInteger
  168. editor
  169. setGutterMarker: anInteger
  170. gutter: 'stops'
  171. value: '<div class="stop"></div>' asJQuery toArray first
  172. !
  173. clearHighlight
  174. self editor clearGutter: 'stops'
  175. !
  176. highlight
  177. self browserModel nextNode ifNotNil: [ :node |
  178. self highlightNode: node ]
  179. !
  180. highlightNode: aNode
  181. | token |
  182. aNode ifNotNil: [
  183. self
  184. clearHighlight;
  185. addStopAt: aNode positionStart x - 1.
  186. self editor
  187. setSelection: #{ 'line' -> (aNode positionStart x - 1). 'ch' -> (aNode positionStart y - 1) }
  188. to: #{ 'line' -> (aNode positionEnd x - 1). 'ch' -> (aNode positionEnd y) } ]
  189. !
  190. observeBrowserModel
  191. super observeBrowserModel.
  192. self browserModel announcer
  193. on: HLDebuggerContextSelected
  194. send: #onContextSelected
  195. to: self.
  196. self browserModel announcer
  197. on: HLDebuggerStepped
  198. send: #onContextSelected
  199. to: self.
  200. self browserModel announcer
  201. on: HLDebuggerWhere
  202. send: #onContextSelected
  203. to: self
  204. ! !
  205. !HLDebuggerCodeWidget methodsFor: 'reactions'!
  206. onContextSelected
  207. self highlight
  208. ! !
  209. !HLDebuggerCodeWidget methodsFor: 'rendering'!
  210. renderOn: html
  211. super renderOn: html.
  212. self contents: self browserModel selectedMethod source
  213. ! !
  214. HLToolModel subclass: #HLDebuggerModel
  215. slots: {#rootContext. #debugger. #error}
  216. package: 'Helios-Debugger'!
  217. !HLDebuggerModel commentStamp!
  218. I am a model for debugging Amber code in Helios.
  219. My instances hold a reference to an `ASTDebugger` instance, itself referencing the current `context`. The context should be the root of the context stack.!
  220. !HLDebuggerModel methodsFor: 'accessing'!
  221. contexts
  222. | contexts context |
  223. contexts := OrderedCollection new.
  224. context := self rootContext.
  225. [ context notNil ] whileTrue: [
  226. contexts add: context.
  227. context := context outerContext ].
  228. ^ contexts
  229. !
  230. currentContext
  231. ^ self debugger context
  232. !
  233. currentContext: aContext
  234. self withChangesDo: [
  235. self selectedMethod: aContext method.
  236. self debugger context: aContext.
  237. self announcer announce: (HLDebuggerContextSelected new
  238. context: aContext;
  239. yourself) ]
  240. !
  241. debugger
  242. ^ debugger ifNil: [ debugger := ASTDebugger new ]
  243. !
  244. error
  245. ^ error
  246. !
  247. nextNode
  248. ^ self debugger node
  249. !
  250. rootContext
  251. ^ rootContext
  252. ! !
  253. !HLDebuggerModel methodsFor: 'actions'!
  254. proceed
  255. self debugger proceed.
  256. self announcer announce: HLDebuggerProceeded new
  257. !
  258. restart
  259. self debugger restart.
  260. self onStep.
  261. self announcer announce: (HLDebuggerStepped new
  262. context: self currentContext;
  263. yourself)
  264. !
  265. stepOver
  266. self debugger stepOver.
  267. self onStep.
  268. self announcer announce: (HLDebuggerStepped new
  269. context: self currentContext;
  270. yourself)
  271. !
  272. where
  273. self announcer announce: HLDebuggerWhere new
  274. ! !
  275. !HLDebuggerModel methodsFor: 'evaluating'!
  276. evaluate: aString
  277. ^ self environment
  278. evaluate: aString
  279. for: self currentContext
  280. ! !
  281. !HLDebuggerModel methodsFor: 'initialization'!
  282. initializeFromError: anError
  283. | errorContext |
  284. error := anError.
  285. errorContext := (AIContext fromMethodContext: error context).
  286. rootContext := error signalerContextFrom: errorContext.
  287. self selectedMethod: rootContext method
  288. ! !
  289. !HLDebuggerModel methodsFor: 'private'!
  290. flushInnerContexts
  291. "When stepping, the inner contexts are not relevent anymore,
  292. and can be flushed"
  293. self currentContext innerContext: nil.
  294. rootContext := self currentContext.
  295. self initializeContexts
  296. ! !
  297. !HLDebuggerModel methodsFor: 'reactions'!
  298. onStep
  299. rootContext := self currentContext.
  300. "Force a refresh of the context list and code widget"
  301. self selectedMethod: self currentContext method.
  302. self announcer announce: (HLDebuggerContextSelected new
  303. context: self currentContext;
  304. yourself)
  305. ! !
  306. !HLDebuggerModel methodsFor: 'testing'!
  307. atEnd
  308. ^ self debugger atEnd
  309. !
  310. isReferencesModel
  311. ^ true
  312. !
  313. openMethod
  314. | browser |
  315. self selectedMethod ifNil: [ ^ self ].
  316. self withChangesDo: [
  317. browser := HLBrowser openAsTab.
  318. browser openMethod: self selectedMethod ]
  319. ! !
  320. !HLDebuggerModel class methodsFor: 'instance creation'!
  321. on: anError
  322. ^ self new
  323. initializeFromError: anError;
  324. yourself
  325. ! !
  326. Object subclass: #HLErrorHandler
  327. slots: {#confirms}
  328. package: 'Helios-Debugger'!
  329. !HLErrorHandler methodsFor: 'error handling'!
  330. confirmDebugError: anError
  331. confirms ifFalse: [
  332. confirms := true.
  333. HLConfirmationWidget new
  334. confirmationString: anError messageText;
  335. cancelBlock: [ confirms := false ];
  336. actionBlock: [ confirms := false. self debugError: anError ];
  337. cancelButtonLabel: 'Abandon';
  338. confirmButtonLabel: 'Debug';
  339. show ]
  340. !
  341. debugError: anError
  342. [
  343. anError context ifNil: [ anError context: thisContext ].
  344. (HLDebugger on: anError) openAsTab ]
  345. on: Error do: [ :error | ConsoleErrorHandler new handleError: error ]
  346. !
  347. handleError: anError
  348. self confirmDebugError: anError
  349. !
  350. initialize
  351. confirms := false
  352. !
  353. onErrorHandled
  354. "when an error is handled, we need to make sure that
  355. any progress bar widget gets removed. Because HLProgressBarWidget is asynchronous,
  356. it has to be done here."
  357. HLProgressWidget default
  358. flush;
  359. remove
  360. ! !
  361. HLToolListWidget subclass: #HLStackListWidget
  362. slots: {}
  363. package: 'Helios-Debugger'!
  364. !HLStackListWidget methodsFor: 'accessing'!
  365. items
  366. ^ self model contexts
  367. !
  368. label
  369. ^ 'Call stack'
  370. ! !
  371. !HLStackListWidget methodsFor: 'actions'!
  372. observeModel
  373. super observeModel.
  374. self model announcer
  375. on: HLDebuggerStepped
  376. send: #onDebuggerStepped:
  377. to: self
  378. !
  379. proceed
  380. self model proceed
  381. !
  382. restart
  383. self model restart
  384. !
  385. selectItem: aContext
  386. self model currentContext: aContext.
  387. super selectItem: aContext
  388. !
  389. selectedItem
  390. ^ self model currentContext
  391. !
  392. stepOver
  393. self model stepOver
  394. !
  395. where
  396. self model where
  397. ! !
  398. !HLStackListWidget methodsFor: 'reactions'!
  399. onDebuggerStepped: anAnnouncement
  400. items := nil.
  401. self refresh
  402. ! !
  403. !HLStackListWidget methodsFor: 'rendering'!
  404. renderButtonsOn: html
  405. html div
  406. class: 'debugger_bar';
  407. with: [
  408. html button
  409. class: 'btn btn-default restart';
  410. with: 'Restart';
  411. onClick: [ self restart ].
  412. html button
  413. class: 'btn btn-default where';
  414. with: 'Where';
  415. onClick: [ self where ].
  416. html button
  417. class: 'btn btn-default stepOver';
  418. with: 'Step over';
  419. onClick: [ self stepOver ].
  420. html button
  421. class: 'btn btn-default proceed';
  422. with: 'Proceed';
  423. onClick: [ self proceed ] ]
  424. ! !