183 Commits e756476b01 ... 36684d4d53

Tác giả SHA1 Thông báo Ngày
  Herby Vojčík 36684d4d53 Working on 0.28.2 5 năm trước cách đây
  Herby Vojčík e0c32490a4 Recompile (while version set to 0.28.1) 5 năm trước cách đây
  Herby Vojčík 72d8567d34 Release version 0.28.1 5 năm trước cách đây
  Herby Vojčík 83a6034f16 Get back `imports:` variables in unknown check. 5 năm trước cách đây
  Herby Vojčík 4b5b537df7 scaffolding: Bump version to 0.28.0. 5 năm trước cách đây
  Herby Vojčík bde20c397a scaffolding: Bump Amber to 0.28. 5 năm trước cách đây
  Herby Vojčík 435fa9f543 Working on 0.28.1 5 năm trước cách đây
  Herby Vojčík 55060f8cdc Recompile (while version set to 0.28.0) 5 năm trước cách đây
  Herby Vojčík 4338d0e248 Release version 0.28.0 5 năm trước cách đây
  Herby Vojčík 56b65fad11 Type-checked Strings comparison. 5 năm trước cách đây
  Herby Vojčík 813b6ce449 CHANGELOG: Typechecked binops. 5 năm trước cách đây
  Herby Vojčík a1a162a6f6 Type-checked Number bit arithmetics. 5 năm trước cách đây
  Herby Vojčík c1b1debd9c Type-checked Number arithmetics and comparison. 5 năm trước cách đây
  Herby Vojčík c1903660ca Small fix. 5 năm trước cách đây
  Herby Vojčík e5943e560e String >> #, with better type checks. 5 năm trước cách đây
  Herby Vojčík 2a99226198 Working on 0.27.2 5 năm trước cách đây
  Herby Vojčík dab304ad7e Recompile (while version set to 0.27.1) 5 năm trước cách đây
  Herby Vojčík 9f7a9e14ab Release version 0.27.1 5 năm trước cách đây
  Herby Vojčík 88a582a95f Formatting. 5 năm trước cách đây
  Herby Vojčík 45b172b8c1 A few Number methods. 5 năm trước cách đây
  Herby Vojčík c056a985df Fix #1249. 5 năm trước cách đây
  Herby Vojčík 4b008b99b1 Fixed AssociativeCollection >> =. 5 năm trước cách đây
  Herby Vojčík be4b221828 Typo. 5 năm trước cách đây
  Herby Vojčík 5bb87d7b22 Proper comma tests in Collection hierarchy. 5 năm trước cách đây
  Herby Vojčík ad4c13a323 scaffolding: Bump version to 0.27.0. 5 năm trước cách đây
  Herby Vojčík da78652491 scaffolding: Bump Amber, helios & legacy for 0.27 5 năm trước cách đây
  Herby Vojčík b1cb8dfe9d Working on 0.27.1 5 năm trước cách đây
  Herby Vojčík d6ec838e28 Recompile (while version set to 0.27.0) 5 năm trước cách đây
  Herby Vojčík 2216167ce5 Release version 0.27.0 5 năm trước cách đây
  Herby Vojčík fe8c0c74e9 inspectOn: now sets list of associations 5 năm trước cách đây
  Herby Vojčík 27ad12c807 Proper place for inspectOn: methods. 5 năm trước cách đây
  Herby Vojčík 52f0eacf9d scaffolding: Bump version to 0.26.0. 5 năm trước cách đây
  Herby Vojčík a8ba8885ef scaffolding: Bump amber. 5 năm trước cách đây
  Herby Vojčík b56731c2a4 Working on 0.26.1 5 năm trước cách đây
  Herby Vojčík bd4586f3e0 Recompile (while version set to 0.26.0) 5 năm trước cách đây
  Herby Vojčík b71f306f94 Release version 0.26.0 5 năm trước cách đây
  Herby Vojčík 4319bf36be Docs for upcoming 0.26. 5 năm trước cách đây
  Herby Vojčík 07c088720e Kernel does not setup whole thisContext chain. 5 năm trước cách đây
  Herby Vojčík 35a78741f1 Error handling out of kernel. 5 năm trước cách đây
  Herby Vojčík 7488f770b9 scaffolding: Bump version to 0.25.1. 5 năm trước cách đây
  Herby Vojčík ec9861557b scaffolding: Bump amber and IDEs. 5 năm trước cách đây
  Herby Vojčík 4dcd38e6ff Working on 0.25.5 5 năm trước cách đây
  Herby Vojčík 31e6daa1a3 Recompile (while version set to 0.25.4) 5 năm trước cách đây
  Herby Vojčík 43ca62a154 Release version 0.25.4 5 năm trước cách đây
  Herby Vojčík 06daecf756 DebugTestContext. TestCase >> debugCase. 5 năm trước cách đây
  Herby Vojčík 95573bde49 Working on 0.25.4 5 năm trước cách đây
  Herby Vojčík 93d2a4a1f8 Recompile (while version set to 0.25.3) 5 năm trước cách đây
  Herby Vojčík 81118e6461 Release version 0.25.3 5 năm trước cách đây
  Herby Vojčík eefaf5b455 kernel: Fix nasty error. 5 năm trước cách đây
  Herby Vojčík 356e4e9645 Working on 0.25.3 5 năm trước cách đây
  Herby Vojčík 29c75d26a7 Recompile (while version set to 0.25.2) 5 năm trước cách đây
  Herby Vojčík 7adf2b5295 Release version 0.25.2 5 năm trước cách đây
  Herby Vojčík 43f3ca08b5 kernel: Different thisContext setup. 5 năm trước cách đây
  Herby Vojčík cd255750ed Working on 0.25.2 5 năm trước cách đây
  Herby Vojčík 96707285e2 Recompile (while version set to 0.25.1) 5 năm trước cách đây
  Herby Vojčík b0363f9a53 Release version 0.25.1 5 năm trước cách đây
  Herby Vojčík d7fd0daa25 CHANGELOG: 0.25.1 5 năm trước cách đây
  Herby Vojčík 40d349b2af Collection >> #shortenedPrintString. 5 năm trước cách đây
  Herby Vojčík 6e4527c9ab Collection >> #copyEmpty 5 năm trước cách đây
  Herby Vojčík 56651b7ae5 CHANGELOG: Subclassing JS. 5 năm trước cách đây
  Herby Vojčík e81744b7c5 Date of release. 5 năm trước cách đây
  Herby Vojčík 94d91489e3 scaffolding: First one for Amber 0.25. 5 năm trước cách đây
  Herby Vojčík c8fbd8e80d Working on 0.25.1 5 năm trước cách đây
  Herby Vojčík b2846784ec Recompile (while version set to 0.25.0) 5 năm trước cách đây
  Herby Vojčík 9ebf8f372b Release version 0.25.0 5 năm trước cách đây
  Herby Vojčík 9c5afb93d8 Recompile. 5 năm trước cách đây
  Herby Vojčík eafbf84248 Different cr/lf sanitizing of source code. 5 năm trước cách đây
  Herby Vojčík e343e92bea Bump dependencies for 0.25 release. 5 năm trước cách đây
  Herby Vojčík cabb6e24c6 Now <jsOverride:args:> works in interpreter. 5 năm trước cách đây
  Herby Vojčík bb191d4827 Fix tests so they actually are interpreted/dbgd. 5 năm trước cách đây
  Herby Vojčík 1d76f230e7 In <jsOverride:args:>, args can be permutated. 5 năm trước cách đây
  Herby Vojčík 5490c0ad03 Typo in method name. 5 năm trước cách đây
  Herby Vojčík 3de75162c3 N-adic jsOverride:args: works. 5 năm trước cách đây
  Herby Vojčík 0d39981bc4 kernel: Remove attachment of removed method. 5 năm trước cách đây
  Herby Vojčík 91656d575e Fix. :-/ 5 năm trước cách đây
  Herby Vojčík 34d99ac6b3 Array >> allIn:. 5 năm trước cách đây
  Herby Vojčík 37473d1701 Niladic jsOverride: works in interpreter. 5 năm trước cách đây
  Herby Vojčík b0540240c2 Move jsOverride: marking to AST. 5 năm trước cách đây
  Herby Vojčík 5da271da4d API-CHANGES: #instVarNamed:[put:]. 5 năm trước cách đây
  Herby Vojčík 667465d036 Add instVarNamed:[put:]. 5 năm trước cách đây
  Herby Vojčík 6ffe4ecbd8 Optimization. 5 năm trước cách đây
  Herby Vojčík 4d1656fb1b Not all inlined sends need aliased receiver. 5 năm trước cách đây
  Herby Vojčík e465818812 Refactor inlined send arguments guarding. 5 năm trước cách đây
  Herby Vojčík b516aa0afb More reworking in aliasing. 5 năm trước cách đây
  Herby Vojčík fe2cc466af Remove visitOrAlias:. 5 năm trước cách đây
  Herby Vojčík f6a76689c1 Split different aliasing needs. 5 năm trước cách đây
  Herby Vojčík 6b27fc46f3 Setting: no point for value ivar. 5 năm trước cách đây
  Herby Vojčík 938c10d485 Move TPragmator to Compiler-Core. 5 năm trước cách đây
  Herby Vojčík a78d925fda Bump sdk to version 0.12.2. 5 năm trước cách đây
  Herby Vojčík d9a8a3310c Move to use @ambers/amdefine. 5 năm trước cách đây
  Herby Vojčík a1e3134d30 Niladic #jsOverride: pragma - super sends. 5 năm trước cách đây
  Herby Vojčík 41fecf304b Bump scaffolding to 0.24.9. 5 năm trước cách đây
  Herby Vojčík f3d4386d4a gitignore: comment the items 5 năm trước cách đây
  Herby Vojčík 65b5afa98f Small fix. 5 năm trước cách đây
  Herby Vojčík 9ce6b38e9d Method attachments: no need for IIFE. 5 năm trước cách đây
  Herby Vojčík ef446ad94d Bump scaffolding to 0.24.8. 5 năm trước cách đây
  Herby Vojčík b32fa374c4 README: Restructure library section. 5 năm trước cách đây
  Herby Vojčík ea7cd2d4e6 README: Contribution section formatting. 5 năm trước cách đây
  Herby Vojčík 08512c7ab9 README: Contribution needs amber tooling. 5 năm trước cách đây
  Herby Vojčík d21478e460 Bump scaffolding to 0.24.7. 5 năm trước cách đây
  Herby Vojčík dfe1fd4398 Comment the IDE dialog. 5 năm trước cách đây
  Herby Vojčík 3980aaf7c4 Bump scaffolding to 0.24.6. 5 năm trước cách đây
  Herby Vojčík 264bc5758a Gruntfile.js: less cbRequireAndPromiseMain. 5 năm trước cách đây
  Herby Vojčík dea2172465 Revert to state of 0.24.4. 5 năm trước cách đây
  Herby Vojčík 09c46ed043 Bump scaffolding to 0.24.5. 5 năm trước cách đây
  Herby Vojčík 9a1e4bc2cd Simplify Gruntfile.js. 5 năm trước cách đây
  Herby Vojčík 179b189839 Revert "Revert "Flatter loader code."" 5 năm trước cách đây
  Herby Vojčík 2e11d4e754 Make the.js contains promise polyfill. 5 năm trước cách đây
  Herby Vojčík 70fa5c4a67 Bump scaffolding to 0.24.4. 5 năm trước cách đây
  Herby Vojčík 511324bc05 Revert "Flatter loader code." 5 năm trước cách đây
  Herby Vojčík 0dc1d8efb3 Scaffolding: deps in alphabetical order. 5 năm trước cách đây
  Herby Vojčík b918f86dbc Bump scaffolding to 0.24.3. 5 năm trước cách đây
  Herby Vojčík 49e9ecaafe New silk. 5 năm trước cách đây
  Herby Vojčík f3257a8806 Next version will be minor bump. 5 năm trước cách đây
  Herby Vojčík 9c0962739b Squash compiler-related changes. 5 năm trước cách đây
  Herby Vojčík 38acbc5019 AstEarlyPragmator => AstSemanticPragmator. 5 năm trước cách đây
  Herby Vojčík 16ee1e6f21 TIRInlinedVisitor. Compiler-IR clear of inlining. 5 năm trước cách đây
  Herby Vojčík 1e1f4d32b9 Put implicit `^ self` to method sequence. 5 năm trước cách đây
  Herby Vojčík ebf2869dd3 IRMethod manages some of aliasing logistics. 5 năm trước cách đây
  Herby Vojčík e8c2030575 IRAliasFactory instance in IRMethod. 5 năm trước cách đây
  Herby Vojčík 5f22e11744 Use ArgVar for what essentially is an arg var. 5 năm trước cách đây
  Herby Vojčík c50db69cf5 Performance optimization. 5 năm trước cách đây
  Herby Vojčík 9e68ecec3e Remove $receiver. 5 năm trước cách đây
  Herby Vojčík 2fca1b456c API-CHANGES: Cleanup of #isFoo in ast nodes. 5 năm trước cách đây
  Herby Vojčík 6d96c99a65 Clean scope var tests & test-only #isFoo methods. 5 năm trước cách đây
  Herby Vojčík 684fb9b77d AST Interpreter: Double dispatch read/write vars. 5 năm trước cách đây
  Herby Vojčík 1fb2a0813d Move #evaluate:for: into Interpreter package. 5 năm trước cách đây
  Herby Vojčík f385aeefb3 Change #isAssignable default to false. 5 năm trước cách đây
  Herby Vojčík 8361bd4b81 ScopeVar / ExpressionNode deprecate #isImmutable. 5 năm trước cách đây
  Herby Vojčík a9b97168d2 ScopeVar / ExpressionNode subtree #isIdempotent. 5 năm trước cách đây
  Herby Vojčík 6b1cbb2e43 ScopeVar and children #isAssignable. 5 năm trước cách đây
  Herby Vojčík e25f7b9973 Make externally known variables unassignable. 5 năm trước cách đây
  Herby Vojčík 973f0466dd Tests for (semantic) invalid assignment. 5 năm trước cách đây
  Herby Vojčík 0e90ec29eb Remove ivar that is in superclass. 5 năm trước cách đây
  Herby Vojčík 7824aee093 Typos. 5 năm trước cách đây
  Herby Vojčík 34df6b90a2 AstGenerator; different #ast:forClass:protocol:. 5 năm trước cách đây
  Herby Vojčík 32474db5e2 Refactor: use #enterNode. 5 năm trước cách đây
  Herby Vojčík 1f96af67dd Compiler: VariableNode changes. 5 năm trước cách đây
  Herby Vojčík fe2304fa41 Compiler: ExpressionNode, group expression nodes. 5 năm trước cách đây
  Herby Vojčík e80743e00f Compiler: Explictly mark "side-effect" sends. 5 năm trước cách đây
  Herby Vojčík 72cf503117 Use TSingleDagChild et. al in Compiler-AST. 5 năm trước cách đây
  Herby Vojčík 74e213d4a1 Fix DagSink (no nodes slot), add traits. 5 năm trước cách đây
  Herby Vojčík 54d03fd37c Remove message never sent. 5 năm trước cách đây
  Herby Vojčík 26736be9eb Remove isFooNode messages never sent. 5 năm trước cách đây
  Herby Vojčík 30ff55811d Compiler: less aliasing. 5 năm trước cách đây
  Herby Vojčík eba01a8328 Compile debug augmentation differently. 5 năm trước cách đây
  Herby Vojčík d19dae7e44 Compiler: Different aliasing of assignment and cascade. 5 năm trước cách đây
  Herby Vojčík a01417ca15 Compiler: Move #requiresSmalltalkContext to IR package. 5 năm trước cách đây
  Herby Vojčík 9843784ffe Use #anySatisfy:. 5 năm trước cách đây
  Herby Vojčík 780bd792dc Remove ivar that was never used. 5 năm trước cách đây
  Herby Vojčík 9a0af62f29 Compiler: No aliasing of sequence members. 5 năm trước cách đây
  Herby Vojčík d5006790bd Remove message never sent. 5 năm trước cách đây
  Herby Vojčík 0864daf565 Remove test-only #isJSStatementNode. 5 năm trước cách đây
  Herby Vojčík b42bf2dcd0 Add Teachable to SUnit package. 5 năm trước cách đây
  Herby Vojčík 8715ddbe23 CHANGELOG: $nil. 5 năm trước cách đây
  Herby Vojčík ba64716de3 Performance optimizations. 5 năm trước cách đây
  Herby Vojčík 752127ddfe Formatting. 5 năm trước cách đây
  Herby Vojčík 25dc722d47 parser: Inline sequences. 5 năm trước cách đây
  Herby Vojčík 8177ea7ac4 ScopeVar asReceiver as extension method. 5 năm trước cách đây
  Herby Vojčík a73dbbd68a Memoize dictionary of receiver names. 5 năm trước cách đây
  Herby Vojčík 3f59afc322 Compile nil receiver as `$nil`. 5 năm trước cách đây
  Herby Vojčík d97910b6ec Pseudovars including nil, true, false actually parsed as such. 5 năm trước cách đây
  Herby Vojčík 89aeddb62d Fix glitch in lookupContextForLocal:ifNone:. 5 năm trước cách đây
  Herby Vojčík dbc29ce2b5 Compiler: cleaner super receiver handling. 5 năm trước cách đây
  Herby Vojčík 9de7736644 Compiler: redesign receiver boxing. 5 năm trước cách đây
  Herby Vojčík 25f05d294d DRY 5 năm trước cách đây
  Herby Vojčík 01ae5c0265 Optimize some uses of #and:. 5 năm trước cách đây
  Herby Vojčík a512c9d830 Refactor: Put responsibility where it's due. 5 năm trước cách đây
  Herby Vojčík 10e50375bf Refactor: Put responsibility where it's due. 5 năm trước cách đây
  Herby Vojčík 75feddedce Remove message never sent. 5 năm trước cách đây
  Herby Vojčík eab0e5857a Remove ivar that was never used. 5 năm trước cách đây
  Herby Vojčík 908203de93 Simplify #validateAssigment. 5 năm trước cách đây
  Herby Vojčík 9a35214ee6 UnknownVar => ExternallyKnownVar 5 năm trước cách đây
  Herby Vojčík 89bdb83fec Refactor: Put responsibility where it's due. 5 năm trước cách đây
  Herby Vojčík 976ee5a571 Actually check for existence of a variable. 5 năm trước cách đây
  Herby Vojčík a3d5721c6d SemanticAnalyzer >> isVariableKnown:inPackage: 5 năm trước cách đây
  Herby Vojčík 24d2c49031 Cosmetics. 5 năm trước cách đây
  Herby Vojčík 0148d48c5e Remove ivar that was never read. 5 năm trước cách đây
  Herby Vojčík 56a8f25284 aScope bindingFor: is never used with a string. 5 năm trước cách đây
  Herby Vojčík 3669389473 API-CHANGES: Removal of shouldBeInlined. 5 năm trước cách đây
  Herby Vojčík 89602991e0 API-CHANGES: SeqColl >> copyWithFirst:. 5 năm trước cách đây
  Herby Vojčík 0f51004ae5 Optimizations. Cleaning. 5 năm trước cách đây
  Herby Vojčík ff4307218e SequenceableCollection >> copyWithFirst:. 5 năm trước cách đây
64 tập tin đã thay đổi với 10209 bổ sung7143 xóa
  1. 77 2
      CHANGELOG
  2. 992 927
      cli/dist/amber-cli.js
  3. 255 253
      cli/src/AmberCli.js
  4. 7 7
      cli/src/AmberCli.st
  5. 1 1
      grunt-init-project/package.json
  6. 3 5
      grunt-init-project/root/Gruntfile.js
  7. 8 15
      grunt-init-project/root/README.md
  8. 3 0
      grunt-init-project/root/gitignore-file
  9. 14 10
      grunt-init-project/root/index.html
  10. 5 5
      grunt-init-project/template.js
  11. 54 3
      lang/API-CHANGES.txt
  12. 21 15
      lang/base/junk-drawer.js
  13. 20 30
      lang/base/kernel-runtime.js
  14. 183 247
      lang/base/parser.js
  15. 15 21
      lang/base/parser.pegjs
  16. 1 1
      lang/package.json
  17. 333 529
      lang/src/Compiler-AST.js
  18. 277 309
      lang/src/Compiler-AST.st
  19. 256 201
      lang/src/Compiler-Core.js
  20. 66 52
      lang/src/Compiler-Core.st
  21. 307 346
      lang/src/Compiler-IR.js
  22. 248 180
      lang/src/Compiler-IR.st
  23. 272 340
      lang/src/Compiler-Inlining.js
  24. 56 34
      lang/src/Compiler-Inlining.st
  25. 292 227
      lang/src/Compiler-Interpreter.js
  26. 137 40
      lang/src/Compiler-Interpreter.st
  27. 414 315
      lang/src/Compiler-Semantic.js
  28. 176 141
      lang/src/Compiler-Semantic.st
  29. 1371 422
      lang/src/Compiler-Tests.js
  30. 370 50
      lang/src/Compiler-Tests.st
  31. 42 43
      lang/src/Kernel-Announcements.js
  32. 263 261
      lang/src/Kernel-Classes.js
  33. 10 9
      lang/src/Kernel-Classes.st
  34. 325 191
      lang/src/Kernel-Collections.js
  35. 107 16
      lang/src/Kernel-Collections.st
  36. 158 30
      lang/src/Kernel-Dag.js
  37. 40 2
      lang/src/Kernel-Dag.st
  38. 17 21
      lang/src/Kernel-Exceptions.js
  39. 0 95
      lang/src/Kernel-Helpers.js
  40. 0 21
      lang/src/Kernel-Helpers.st
  41. 253 257
      lang/src/Kernel-Infrastructure.js
  42. 17 7
      lang/src/Kernel-Infrastructure.st
  43. 246 192
      lang/src/Kernel-Methods.js
  44. 9 5
      lang/src/Kernel-Methods.st
  45. 517 116
      lang/src/Kernel-Objects.js
  46. 192 22
      lang/src/Kernel-Objects.st
  47. 13 15
      lang/src/Kernel-Promises.js
  48. 7 9
      lang/src/Kernel-Promises.st
  49. 317 278
      lang/src/Kernel-Tests.js
  50. 45 20
      lang/src/Kernel-Tests.st
  51. 56 8
      lang/src/Platform-Browser.js
  52. 8 0
      lang/src/Platform-Browser.st
  53. 2 6
      lang/src/Platform-DOM-Tests.js
  54. 6 8
      lang/src/Platform-DOM.js
  55. 322 263
      lang/src/Platform-ImportExport.js
  56. 4 5
      lang/src/Platform-Node.js
  57. 261 201
      lang/src/Platform-Services.js
  58. 48 57
      lang/src/Platform-Services.st
  59. 92 86
      lang/src/SUnit-Tests.js
  60. 421 86
      lang/src/SUnit.js
  61. 100 1
      lang/src/SUnit.st
  62. 74 81
      sdk/lib/NodeTestRunner.js
  63. 1 1
      sdk/lib/helpers.js
  64. 2 2
      sdk/package.json

+ 77 - 2
CHANGELOG

@@ -1,11 +1,86 @@
-? ??? 2019 - Release 0.24.1
+20 Apr 2020 - Release 0.28.0
 ===================================
 ===================================
 
 
+* Fixing bugs related to lack of typechecking binary operations.
+  * String >> , now only accepts strings and character arrays.
+  * String comparisons return false for non-strings.
+  * Number arithmetics and bit manipulations only accept numbers.
+  * Number comparisons return false for non-numbers.
+
+Commits: https://lolg.it/amber/amber/commits/0.28.0
+
+
+19 Apr 2020 - Release 0.27.1
+===================================
+
+* Fixes.
+
+Commits: https://lolg.it/amber/amber/commits/0.27.1
+
+
+14 Apr 2020 - Release 0.27.0
+===================================
+
+* Inspectors protocol is changed.
+  * The inspectOn: now sets list of associations in setVariables:.
+    * Breaking for objects acting as inspectors that assume Dictionary.
+    * Both IDEs were updated to assoc-list first, with backward compat.
+    * Inspecting big (~10k) collections is drastically faster.
+
+Commits: https://lolg.it/amber/amber/commits/0.27.0
+
+
+13 Apr 2020 - Release 0.26.0
+===================================
+
+* Kernel simplification in context and error handling.
+  * Kernel no longer handles errors.
+    * BrowserPlatform installs unhandled exception / promise handlers.
+    * Develop on modern browsers (production should not be harmed).
+  * Kernel no longer sets up thisContext chain.
+    * MethodContext takes care of the lazy initialization.
+
+Commits: https://lolg.it/amber/amber/commits/0.26.0
+
+
+12 Apr 2020 - Release 0.25.3
+===================================
+
+* Fix error handling broken by errors happening in Promises.
+
+Commits: https://lolg.it/amber/amber/commits/0.25.3
+
+
+11 Apr 2020 - Release 0.25.2
+===================================
+
+* Changed thisContext hydrating in kernel
+  * Set up so better stack traces are shown in debugger, esp. for async
+  * Can be breaking for code that depends on old hydration (unlikely).
+
+Commits: https://lolg.it/amber/amber/commits/0.25.2
+
+
+9 Apr 2020 - Release 0.25.1
+===================================
+
+* Quick release to shorten inspector labels for big collections.
+
+Commits: https://lolg.it/amber/amber/commits/0.25.1
+
+
+8 Apr 2020 - Release 0.25.0
+===================================
+
+* Teachable class (in SUnit package).
 * $core.removeClass returns removed class.
 * $core.removeClass returns removed class.
+* Subclassing JS classes, <jsOverride:(args:)> pragma.
+* Both 'nil' and '$nil' compiled in method code.
+  * '$nil' used as receiver, 'nil' used to pass a value.
 * Cleaned error-handling code.
 * Cleaned error-handling code.
 * More Set fixes.
 * More Set fixes.
 
 
-Commits: https://lolg.it/amber/amber/commits/0.24.1
+Commits: https://lolg.it/amber/amber/commits/0.25.0
 
 
 
 
 4 Jun 2019 - Release 0.24.0
 4 Jun 2019 - Release 0.24.0

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 992 - 927
cli/dist/amber-cli.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 255 - 253
cli/src/AmberCli.js


+ 7 - 7
cli/src/AmberCli.st

@@ -38,7 +38,7 @@ handleArguments: args
 
 
 	selector := self selectorForCommandLineSwitch: (args first).
 	selector := self selectorForCommandLineSwitch: (args first).
 	args remove: args first.
 	args remove: args first.
-	self perform: selector  withArguments: (Array with: args)
+	self perform: selector  withArguments: { args }
 !
 !
 
 
 selectorForCommandLineSwitch: aSwitch
 selectorForCommandLineSwitch: aSwitch
@@ -328,7 +328,7 @@ handlePUTRequest: aRequest respondTo: aResponse
 	stream on: 'error' do: [:error |
 	stream on: 'error' do: [:error |
 		console warn: 'Error creating WriteStream for file ', file.
 		console warn: 'Error creating WriteStream for file ', file.
 		console warn: '    Did you forget to create the necessary directory in your project (often /src)?'.
 		console warn: '    Did you forget to create the necessary directory in your project (often /src)?'.
-		console warn: '    The exact error is: ', error.
+		console warn: '    The exact error is: ', error asString.
 		self respondNotCreatedTo: aResponse].
 		self respondNotCreatedTo: aResponse].
 
 
 	stream on: 'close' do: [
 	stream on: 'close' do: [
@@ -437,7 +437,7 @@ start
 	self checkDirectoryLayout.
 	self checkDirectoryLayout.
 	(http createServer: [:request :response |
 	(http createServer: [:request :response |
 	      self handleRequest: request respondTo: response])
 	      self handleRequest: request respondTo: response])
-	      on: 'error' do: [:error | console log: 'Error starting server: ', error];
+	      on: 'error' do: [:error | console log: 'Error starting server: ', error asString];
 	      on: 'listening' do: [console log: 'Starting file server on http://', self host, ':', self port asString];
 	      on: 'listening' do: [console log: 'Starting file server on http://', self host, ':', self port asString];
 	      listen: self port host: self host.
 	      listen: self port host: self host.
 !
 !
@@ -939,8 +939,8 @@ createServerWithArguments: options
 
 
 	(options size even) ifFalse: [
 	(options size even) ifFalse: [
 		console log: 'Using default parameters.'.
 		console log: 'Using default parameters.'.
-		console log: 'Wrong commandline options or not enough arguments for: ' , options.
-		console log: 'Use any of the following ones: ', switches.
+		console log: 'Wrong commandline options or not enough arguments for: ' , (' ' join: options).
+		console log: 'Use any of the following ones: ', (',' join: switches).
 		^server].
 		^server].
 
 
 	popFront := [:args |
 	popFront := [:args |
@@ -954,10 +954,10 @@ createServerWithArguments: options
 
 
 		(switches includes: optionName) ifTrue: [
 		(switches includes: optionName) ifTrue: [
 			optionName := self selectorForCommandLineSwitch: optionName.
 			optionName := self selectorForCommandLineSwitch: optionName.
-			server perform: optionName withArguments: (Array with: optionValue)]
+			server perform: optionName withArguments: { optionValue } ]
 			ifFalse: [
 			ifFalse: [
 				console log: optionName, ' is not a valid commandline option'.
 				console log: optionName, ' is not a valid commandline option'.
-				console log: 'Use any of the following ones: ', switches ]].
+				console log: 'Use any of the following ones: ', (',' join: switches) ]].
 	^ server.
 	^ server.
 !
 !
 
 

+ 1 - 1
grunt-init-project/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@ambers/grunt-init-amber-project",
   "name": "@ambers/grunt-init-amber-project",
-  "version": "0.24.2",
+  "version": "0.28.0",
   "description": "grunt-init template for amber project",
   "description": "grunt-init template for amber project",
   "main": "template.js",
   "main": "template.js",
   "scripts": {
   "scripts": {

+ 3 - 5
grunt-init-project/root/Gruntfile.js

@@ -118,8 +118,7 @@ module.exports = function (grunt) {
                 options: {
                 options: {
                     rawText: {
                     rawText: {
                         "helios/index": "",
                         "helios/index": "",
-                        "app": mkDefine(["app/promise"], lambdaExports),
-                        "app/promise": mkDefine(["require"], cbRequireAndPromiseMain),
+                        "app": mkDefine(["app/main"], lambdaExports),
                         "app/main": mkDefine(["lambda", "amber/core/Platform-Node"], function (amber) {
                         "app/main": mkDefine(["lambda", "amber/core/Platform-Node"], function (amber) {
                             return amber.initialize().then(function () {
                             return amber.initialize().then(function () {
                                 return amber;
                                 return amber;
@@ -142,12 +141,11 @@ module.exports = function (grunt) {
                 options: {
                 options: {
                     rawText: {
                     rawText: {
                         "jquery": "/* do not load in node test runner */",
                         "jquery": "/* do not load in node test runner */",
-                        "app/main": mkDefine(["testing", "amber/core/Platform-Node", "amber_devkit/NodeTestRunner"], function (amber) {
+                        "app": mkDefine(["testing", "amber/core/Platform-Node", "amber_devkit/NodeTestRunner"], function (amber) {
                             amber.initialize().then(function () {
                             amber.initialize().then(function () {
                                 amber.globals.NodeTestRunner._main();
                                 amber.globals.NodeTestRunner._main();
                             });
                             });
-                        }),
-                        "app": mkDefine(["require"], cbRequireAndPromiseMain)
+                        })
                     },
                     },
                     paths: {"amber_devkit": helpers.libPath},
                     paths: {"amber_devkit": helpers.libPath},
                     pragmas: {
                     pragmas: {

+ 8 - 15
grunt-init-project/root/README.md

@@ -2,17 +2,14 @@
 
 
 {%= description %}
 {%= description %}
 
 
-## Getting Started
+## Use {%= name %} library in your project
 
 
-Install Amber and create an Amber project,
-as shown in [Amber Instructions](https://lolg.it/amber/amber#prerequisities).
-
-## Use {%= name %} as a library in a client project
+**DELETE THIS PARAGRAPH, IF {%= name %} IS A LIBRARY. DELETE WHOLE THIS SECTION IF {%= name %} IS AN APP, NOT A LIBRARY.**
 
 
-If not already present, create a client project
-in an empty directory with `amber init`.
+If not already done, install Amber and create an Amber project with `amber init`,
+as shown in [Amber Instructions](https://lolg.it/amber/amber#prerequisities).
 
 
-In a client project, run
+In a project, run
 
 
 ```sh
 ```sh
 npm install {%= name %} --save
 npm install {%= name %} --save
@@ -27,12 +24,8 @@ save the change and commit the package. Reload.
 
 
 ## Contributing
 ## Contributing
 
 
-To bring project alive (for example after `git clone`):
+  1. Have amber cli tooling installed. If you don't, see first box in these [instructions](https://lolg.it/amber/amber#getting-amber-and-setting-up-an-initial-project).
 
 
-```sh
-npm run init
-```
+  1. Fork and/or clone the project, then bring it alive by: `npm run init`.
 
 
-Developing the project (after brought alive):
- 
-Start server with `amber serve` and go to `http://localhost:4000/` in your browser and follow the instructions
+  1. Developing the project: Start server with `amber serve` and go to `http://localhost:4000/` in your browser. Overlay with buttons to open IDE should appear shortly.

+ 3 - 0
grunt-init-project/root/gitignore-file

@@ -1,7 +1,10 @@
+#Dependencies defined in `package.json` got via `npm install`
 /node_modules/
 /node_modules/
 
 
+#Generated when running tests from cli via `npm test` / `grunt test`
 /test_runner.js
 /test_runner.js
 
 
+#Generated when `grunt devel`, `grunt deploy` or `grunt deploy:lambda`
 /config.js
 /config.js
 /the.js
 /the.js
 /lambda/the.js
 /lambda/the.js

+ 14 - 10
grunt-init-project/root/index.html

@@ -25,17 +25,21 @@
 <!-- EXAMPLE APP END -->
 <!-- EXAMPLE APP END -->
 <script type='text/javascript'>
 <script type='text/javascript'>
     var global = typeof global === "undefined" ? window : global || window;
     var global = typeof global === "undefined" ? window : global || window;
-    new Promise(function (resolve, reject) {
-        require(['app'], resolve, reject);
-    }).then(function (amber) {
-        return amber.initialize({
-            //used for all new packages in IDE
-            'transport.defaultAmdNamespace': "{%= namespace %}"
-        }).then(function () {
-            require(["amber-ide-starter-dialog"], function (dlg) {
-                dlg.start();
+    require(['app'], function (amberPromise) {
+        amberPromise.then(function (amber) {
+            amber.initialize({
+                //used for all new packages in IDE
+                'transport.defaultAmdNamespace': "{%= namespace %}"
+            }).then(function () {
+                // This shows IDE dialog in development mode (module is present).
+                // This silently fails in deploy mode (module is missing).
+                // Thus, no need to have different page for deploy, leading to less bugs.
+                require(["amber-ide-starter-dialog"], function (dlg) {
+                    dlg.start();
+                });
+                // Start the app itself.
+                amber.globals.{%= name %}._start();
             });
             });
-            amber.globals.{%= name %}._start();
         });
         });
     });
     });
 </script>
 </script>

+ 5 - 5
grunt-init-project/template.js

@@ -118,16 +118,16 @@ exports.template = function (grunt, init, done) {
         props.dependencies = {
         props.dependencies = {
             "@ambers/contrib-jquery": "^0.6.0",
             "@ambers/contrib-jquery": "^0.6.0",
             "@ambers/contrib-web": "^0.8.2",
             "@ambers/contrib-web": "^0.8.2",
-            "@ambers/lang": "^0.24.0",
             "@ambers/domite": "^0.9.0",
             "@ambers/domite": "^0.9.0",
-            "es6-promise": "^4.2.6",
-            "@ambers/silk": "^0.5.1"
+            "@ambers/lang": "^0.28.0",
+            "@ambers/silk": "^0.6.0",
+            "es6-promise": "^4.2.6"
         };
         };
         props.devDependencies = {
         props.devDependencies = {
+            "@ambers/contrib-legacy": "^0.10.1",
+            "@ambers/helios": "^0.12.2",
             "@ambers/ide-starter-modal": "^0.2.0",
             "@ambers/ide-starter-modal": "^0.2.0",
             "@ambers/sdk": "^0.12.1",
             "@ambers/sdk": "^0.12.1",
-            "@ambers/contrib-legacy": "^0.8.6",
-            "@ambers/helios": "^0.11.6",
             "grunt": "^1.0.3",
             "grunt": "^1.0.3",
             "grunt-contrib-clean": "^1.1.0",
             "grunt-contrib-clean": "^1.1.0",
             "grunt-contrib-requirejs": "^1.0.0",
             "grunt-contrib-requirejs": "^1.0.0",

+ 54 - 3
lang/API-CHANGES.txt

@@ -1,18 +1,68 @@
-0.24.1:
+0.27.1:
+
++ Number >>
+  + isFinite
+  + isNaN
++ Number class >>
+  + negativeInfinity
+  + positiveInfinity
+
+
+0.27.0:
+
++ JSObjectProxy class >>
+  + associationsOfProxy:
+
+
+0.26.0:
+
+* Deprecate $core.seamless.
+
++ MethodContext >>
+  + hydrated
+
+
+0.25.4:
+
+* Add class DebugTestContext.
+
++ TestCase >>
+  + debugCase
+
+
+0.25.1:
+
++ Collection >>
+  + copyEmpty
+  + shortenedPrintString
+
+
+0.25.0:
 
 
 * Deprecate Behavior >> javascriptConstructor(:)
 * Deprecate Behavior >> javascriptConstructor(:)
+* Deprecate ProtoObject >> instVarAt:(put:)
+* Lots of changes in Compiler.
+* Added Teachable class.
 
 
++ Array >>
+  + allIn:
 + Behavior >>
 + Behavior >>
   + alternateConstructorViaSelector:
   + alternateConstructorViaSelector:
   + applySuperConstructorOn:withArguments:
   + applySuperConstructorOn:withArguments:
   + beJavaScriptSubclassOf:
   + beJavaScriptSubclassOf:
   + javaScriptConstructor
   + javaScriptConstructor
   + javaScriptConstructor:
   + javaScriptConstructor:
+  + superPrototype
 + BlockClosure >>
 + BlockClosure >>
   + tryIfTrue:catch:
   + tryIfTrue:catch:
++ ProtoObject >>
+  + instVarNamed:
+  + instVarNamed:put:
++ SequenceableCollection >>
+  + copyWithFirst:
 + SmalltalkImage >>
 + SmalltalkImage >>
-  + do:on:do:
   + isError:
   + isError:
+  + try:ifTrue:catch:
 + amber/boot api >>
 + amber/boot api >>
   + detachClass(klass)
   + detachClass(klass)
 + amber/helpers exports >>
 + amber/helpers exports >>
@@ -24,9 +74,10 @@
 - JavaScriptError >>
 - JavaScriptError >>
   - shouldBeStubbed
   - shouldBeStubbed
   - wrap
   - wrap
-- MethodContext
+- MethodContext >>
   - stubHere
   - stubHere
   - stubToAtMost:
   - stubToAtMost:
+
 - amber/boot api >>
 - amber/boot api >>
   - addElement(arraySet, el)
   - addElement(arraySet, el)
   - removeElement(arraySet, el)
   - removeElement(arraySet, el)

+ 21 - 15
lang/base/junk-drawer.js

@@ -27,24 +27,30 @@ define(function () {
         if (obj[name] == null) installMethodOfJsObject(obj, name, noop);
         if (obj[name] == null) installMethodOfJsObject(obj, name, noop);
     }
     }
 
 
+    var table = {
+        ':': '_',
+        '&': '_and',
+        '|': '_or',
+        '+': '_plus',
+        '-': '_minus',
+        '*': '_star',
+        '/': '_slash',
+        '\\': '_backslash',
+        '~': '_tild',
+        '%': '_percent',
+        '>': '_gt',
+        '<': '_lt',
+        '=': '_eq',
+        ',': '_comma',
+        '@': '_at'
+    };
+
     /* Convert a Smalltalk selector into a JS selector */
     /* Convert a Smalltalk selector into a JS selector */
     function st2js (string) {
     function st2js (string) {
         return '_' + string
         return '_' + string
-            .replace(/:/g, '_')
-            .replace(/[\&]/g, '_and')
-            .replace(/[\|]/g, '_or')
-            .replace(/[+]/g, '_plus')
-            .replace(/-/g, '_minus')
-            .replace(/[*]/g, '_star')
-            .replace(/[\/]/g, '_slash')
-            .replace(/[\\]/g, '_backslash')
-            .replace(/[\~]/g, '_tild')
-            .replace(/%/g, '_percent')
-            .replace(/>/g, '_gt')
-            .replace(/</g, '_lt')
-            .replace(/=/g, '_eq')
-            .replace(/,/g, '_comma')
-            .replace(/[@]/g, '_at');
+            .replace(/[:&|+\-*/\\~%><=,@]/g, function (ch) {
+                return table[ch];
+            });
     };
     };
 
 
     function js2st (selector) {
     function js2st (selector) {

+ 20 - 30
lang/base/kernel-runtime.js

@@ -10,7 +10,7 @@ define(['./junk-drawer'], function ($goodies) {
     var deleteKeysFrom = $goodies.deleteKeysFrom;
     var deleteKeysFrom = $goodies.deleteKeysFrom;
     var extendWithMethods = $goodies.extendWithMethods;
     var extendWithMethods = $goodies.extendWithMethods;
 
 
-    function installMethodOfJsObjectEx (obj, name, fn) {
+    function uninstallMethodOfJsObjectEx (obj, name) {
         var attachments;
         var attachments;
         var old = Object.getOwnPropertyDescriptor(obj, name);
         var old = Object.getOwnPropertyDescriptor(obj, name);
         if (old != null && (old = old.value) != null) {
         if (old != null && (old = old.value) != null) {
@@ -19,7 +19,12 @@ define(['./junk-drawer'], function ($goodies) {
                 deleteKeysFrom(Object.keys(attachments), obj);
                 deleteKeysFrom(Object.keys(attachments), obj);
             }
             }
         }
         }
-        attachments = fn.a$atx;
+        delete obj[name];
+    }
+
+    function installMethodOfJsObjectEx (obj, name, fn) {
+        uninstallMethodOfJsObjectEx(obj, name);
+        var attachments = fn.a$atx;
         if (attachments != null) {
         if (attachments != null) {
             extendWithMethods(obj, attachments);
             extendWithMethods(obj, attachments);
         }
         }
@@ -253,7 +258,7 @@ define(['./junk-drawer'], function ($goodies) {
             };
             };
 
 
             emit.behaviorMethodRemoved = function (method, klass) {
             emit.behaviorMethodRemoved = function (method, klass) {
-                delete klass.fn.prototype[method.jsSelector];
+                uninstallMethodOfJsObjectEx(klass.fn.prototype, method.jsSelector);
                 propagateMethodChange(klass, method, null);
                 propagateMethodChange(klass, method, null);
             };
             };
 
 
@@ -350,35 +355,22 @@ define(['./junk-drawer'], function ($goodies) {
 
 
             var thisContext = null;
             var thisContext = null;
 
 
-            /*
-             Runs worker function so that error handler is not set up
-             if there isn't one. This is accomplished by unconditional
-             wrapping inside a context of a simulated `nil seamlessDoIt` call,
-             which then stops error handler setup (see st.withContext above).
-             The effect is, $core.seamless(fn)'s exceptions are not
-             handed into ST error handler and caller should process them.
-             */
-            st.seamless = function (worker) {
-                var oldContext = thisContext;
-                thisContext = new SmalltalkMethodContext(thisContext, function (ctx) {
-                    ctx.fill(null, "seamlessDoIt", {}, globals.UndefinedObject);
-                });
-                var result = worker(thisContext);
-                thisContext = oldContext;
-                return result;
-            };
-
-            function resultWithErrorHandling (worker) {
+            function resultWithNoErrorHandling (worker) {
                 try {
                 try {
                     return worker(thisContext);
                     return worker(thisContext);
-                } catch (error) {
-                    globals.ErrorHandler._handleError_(error);
+                } finally {
                     thisContext = null;
                     thisContext = null;
-                    // Rethrow the error in any case.
-                    throw error;
                 }
                 }
             }
             }
 
 
+            // TODO deprecated, remove
+            st.seamless = function (worker) {
+                return worker();
+                // return st.withContext(worker, new SmalltalkMethodContext(thisContext, function (ctx) {
+                //     ctx.fill(null, "seamlessDoIt", {}, globals.UndefinedObject);
+                // }));
+            };
+
             /*
             /*
              Standard way to run within context.
              Standard way to run within context.
              Sets up error handler if entering first ST context in a stack.
              Sets up error handler if entering first ST context in a stack.
@@ -386,7 +378,7 @@ define(['./junk-drawer'], function ($goodies) {
             st.withContext = function (worker, setup) {
             st.withContext = function (worker, setup) {
                 var oldContext = thisContext;
                 var oldContext = thisContext;
                 thisContext = new SmalltalkMethodContext(thisContext, setup);
                 thisContext = new SmalltalkMethodContext(thisContext, setup);
-                var result = oldContext == null ? resultWithErrorHandling(worker) : worker(thisContext);
+                var result = oldContext == null ? resultWithNoErrorHandling(worker) : worker(thisContext);
                 thisContext = oldContext;
                 thisContext = oldContext;
                 return result;
                 return result;
             };
             };
@@ -395,9 +387,7 @@ define(['./junk-drawer'], function ($goodies) {
 
 
             st.getThisContext = function () {
             st.getThisContext = function () {
                 if (!thisContext) return null;
                 if (!thisContext) return null;
-                for (var frame = thisContext; frame; frame = frame.homeContext) {
-                    frame.setup(frame);
-                }
+                thisContext.setup(thisContext);
                 return thisContext;
                 return thisContext;
             };
             };
         }
         }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 183 - 247
lang/base/parser.js


+ 15 - 21
lang/base/parser.pegjs

@@ -4,6 +4,10 @@
 	function newNode(nodeClass) {
 	function newNode(nodeClass) {
 		return nodeClass._new()._location_(location())._source_(text());
 		return nodeClass._new()._location_(location())._source_(text());
 	}
 	}
+
+	function newSequenceNode(nodeClass, temps, statements) {
+		return newNode(nodeClass)._temps_(temps || [])._dagChildren_(statements || []);
+	}
 }
 }
 
 
 start = method
 start = method
@@ -93,7 +97,7 @@ runtimeLiteral = dynamicDictionary / dynamicArray / block
 literal = runtimeLiteral / parseTimeLiteral
 literal = runtimeLiteral / parseTimeLiteral
 
 
 variable = identifier:identifier {
 variable = identifier:identifier {
-	return newNode($globals.VariableNode)._value_(identifier);
+	return newNode($globals.VariableNode)._identifier_(identifier);
 }
 }
 
 
 reference = variable
 reference = variable
@@ -153,9 +157,9 @@ assignment = variable:variable ws ':=' ws expression:expression {
 }
 }
 
 
 ret = '^' ws expression:expression {
 ret = '^' ws expression:expression {
-	return newNode($globals.ReturnNode)._dagChildren_([expression]);
+	return newNode($globals.ReturnNode)._expression_(expression);
 }
 }
-  
+
 temps = '|' vars:(ws variable:identifier {return variable;})* ws '|' {
 temps = '|' vars:(ws variable:identifier {return variable;})* ws '|' {
 	return vars;
 	return vars;
 }
 }
@@ -178,23 +182,13 @@ wsStatements =
 	} /
 	} /
 	expressions:wsExpressions? {return expressions || [];}
 	expressions:wsExpressions? {return expressions || [];}
 
 
-wsSequenceWs = aPragmas:wsPragmas? ws temps:temps? zPragmas:wsPragmas? statements:wsStatements? maybeDotsWs {
-	return [newNode($globals.SequenceNode)
-		._temps_(temps || [])
-		._dagChildren_(statements || []), (aPragmas || []).concat(zPragmas || [])];
-}
-
-wsBlockSequenceWs = ws temps:temps? statements:wsStatements? maybeDotsWs {
-	return newNode($globals.BlockSequenceNode)
-		._temps_(temps || [])
-		._dagChildren_(statements || []);
-}
-
-block = '[' params:wsBlockParamList? sequence:wsBlockSequenceWs ']' {
-	return newNode($globals.BlockNode)._parameters_(params || [])._dagChildren_([sequence]);
+block = '[' params:wsBlockParamList? ws temps:temps? statements:wsStatements? maybeDotsWs ']' {
+	return newNode($globals.BlockNode)
+		._parameters_(params || [])
+		._sequenceNode_(newSequenceNode($globals.BlockSequenceNode, temps, statements));
 }
 }
 
 
-operand = literal / reference / subexpression
+operand = reference / literal / subexpression
 
 
 wsUnaryMessage = ws selector:unarySelector !':' {
 wsUnaryMessage = ws selector:unarySelector !':' {
 	return newNode($globals.SendNode)._selector_(selector);
 	return newNode($globals.SendNode)._selector_(selector);
@@ -247,12 +241,12 @@ cascade =
 
 
 method =
 method =
 	pattern:(wsKeywordPattern / wsBinaryPattern / wsUnaryPattern)
 	pattern:(wsKeywordPattern / wsBinaryPattern / wsUnaryPattern)
-	sequence:wsSequenceWs {
+	aPragmas:wsPragmas? ws temps:temps? zPragmas:wsPragmas? statements:wsStatements? maybeDotsWs {
 		return newNode($globals.MethodNode)
 		return newNode($globals.MethodNode)
 			._selector_(pattern[0])
 			._selector_(pattern[0])
 			._arguments_(pattern[1])
 			._arguments_(pattern[1])
-			._pragmas_(sequence[1])
-			._dagChildren_([sequence[0]]);
+			._pragmas_((aPragmas || []).concat(zPragmas || []))
+			._sequenceNode_(newSequenceNode($globals.SequenceNode, temps, statements));
 	}
 	}
 
 
 associationSend =
 associationSend =

+ 1 - 1
lang/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@ambers/lang",
   "name": "@ambers/lang",
-  "version": "0.25.0-pre",
+  "version": "0.28.2-pre",
   "description": "An implementation of the Smalltalk language that runs on top of the JS runtime.",
   "description": "An implementation of the Smalltalk language that runs on top of the JS runtime.",
   "homepage": "http://amber-lang.net",
   "homepage": "http://amber-lang.net",
   "keywords": [
   "keywords": [

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 333 - 529
lang/src/Compiler-AST.js


+ 277 - 309
lang/src/Compiler-AST.st

@@ -1,6 +1,6 @@
 Smalltalk createPackage: 'Compiler-AST'!
 Smalltalk createPackage: 'Compiler-AST'!
 DagParentNode subclass: #ASTNode
 DagParentNode subclass: #ASTNode
-	slots: {#parent. #position. #source. #shouldBeAliased}
+	slots: {#parent. #position. #source}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
 !ASTNode commentStamp!
 !ASTNode commentStamp!
 I am the abstract root class of the abstract syntax tree.
 I am the abstract root class of the abstract syntax tree.
@@ -15,10 +15,6 @@ location: aLocation
 	self position: aLocation start line @ aLocation start column
 	self position: aLocation start line @ aLocation start column
 !
 !
 
 
-method
-	^ self parent ifNotNil: [ :node | node method ]
-!
-
 navigationNodeAt: aPoint ifAbsent: aBlock
 navigationNodeAt: aPoint ifAbsent: aBlock
 	"Answer the navigation node in the receiver's tree at aPoint 
 	"Answer the navigation node in the receiver's tree at aPoint 
 	or nil if no navigation node was found.
 	or nil if no navigation node was found.
@@ -64,14 +60,6 @@ positionStart
 	^ self position
 	^ self position
 !
 !
 
 
-shouldBeAliased
-	^ shouldBeAliased ifNil: [ false ]
-!
-
-shouldBeAliased: aBoolean
-	shouldBeAliased := aBoolean
-!
-
 size
 size
 	^ self source size
 	^ self source size
 !
 !
@@ -84,19 +72,6 @@ source: aString
 	source := aString
 	source := aString
 ! !
 ! !
 
 
-!ASTNode methodsFor: 'building'!
-
-withTail: aCollection
-	^ aCollection inject: self into: [
-		:receiver :send | SendNode new
-			position: send position;
-			source: send source;
-			receiver: receiver;
-			selector: send selector;
-			arguments: send arguments;
-			yourself ]
-! !
-
 !ASTNode methodsFor: 'testing'!
 !ASTNode methodsFor: 'testing'!
 
 
 inPosition: aPoint
 inPosition: aPoint
@@ -104,73 +79,61 @@ inPosition: aPoint
 		self positionEnd >= aPoint ])
 		self positionEnd >= aPoint ])
 !
 !
 
 
-isAssignmentNode
-	^ false
-!
-
-isBlockNode
+isNavigationNode
+	"Answer true if the node can be navigated to"
+	
 	^ false
 	^ false
 !
 !
 
 
-isBlockSequenceNode
+isReturnNode
 	^ false
 	^ false
-!
+! !
 
 
-isCascadeNode
-	^ false
-!
+ASTNode subclass: #ExpressionNode
+	slots: {#shouldBeAliased}
+	package: 'Compiler-AST'!
+!ExpressionNode commentStamp!
+I am the abstract root class for expression nodes.!
 
 
-isImmutable
-	^ false
-!
+!ExpressionNode methodsFor: 'accessing'!
 
 
-isJSStatementNode
-	^ false
+shouldBeAliased
+	^ shouldBeAliased ifNil: [ false ]
 !
 !
 
 
-isNavigationNode
-	"Answer true if the node can be navigated to"
-	
-	^ false
-!
+shouldBeAliased: aBoolean
+	shouldBeAliased := aBoolean
+! !
 
 
-isReturnNode
-	^ false
-!
+!ExpressionNode methodsFor: 'building'!
 
 
-isSendNode
-	^ false
-!
+withTail: aCollection
+	^ aCollection inject: self into: [
+		:receiver :send | SendNode new
+			position: send position;
+			source: send source;
+			receiver: receiver;
+			selector: send selector;
+			arguments: send arguments;
+			yourself ]
+! !
 
 
-isSequenceNode
-	^ false
-!
+!ExpressionNode methodsFor: 'testing'!
 
 
-isSuper
+isIdempotent
 	^ false
 	^ false
 !
 !
 
 
-isValueNode
-	^ false
+isImmutable
+	self deprecatedAPI: 'Use #isIdempotent instead.'.
+	^ self isIdempotent
 !
 !
 
 
-isVariableNode
+isSuper
 	^ false
 	^ false
-!
-
-requiresSmalltalkContext
-	"Answer true if the receiver requires a smalltalk context.
-	Only send nodes require a context.
-	
-	If no node requires a context, the method will be compiled without one.
-	See `IRJSTranslator` and `JSStream` for context creation"
-	
-	^ (self dagChildren 
-		detect: [ :each | each requiresSmalltalkContext ]
-		ifNone: [ nil ]) notNil
 ! !
 ! !
 
 
-ASTNode subclass: #AssignmentNode
+ExpressionNode subclass: #AssignmentNode
 	slots: {#left. #right}
 	slots: {#left. #right}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
 !AssignmentNode commentStamp!
 !AssignmentNode commentStamp!
@@ -179,7 +142,7 @@ I represent an assignment node.!
 !AssignmentNode methodsFor: 'accessing'!
 !AssignmentNode methodsFor: 'accessing'!
 
 
 dagChildren
 dagChildren
-	^ Array with: self left with: self right
+	^ { self left. self right }
 !
 !
 
 
 left
 left
@@ -198,26 +161,24 @@ right: aNode
 	right := aNode
 	right := aNode
 ! !
 ! !
 
 
-!AssignmentNode methodsFor: 'testing'!
-
-isAssignmentNode
-	^ true
-! !
-
 !AssignmentNode methodsFor: 'visiting'!
 !AssignmentNode methodsFor: 'visiting'!
 
 
 acceptDagVisitor: aVisitor
 acceptDagVisitor: aVisitor
 	^ aVisitor visitAssignmentNode: self
 	^ aVisitor visitAssignmentNode: self
 ! !
 ! !
 
 
-ASTNode subclass: #BlockNode
-	slots: {#parameters. #scope}
+ExpressionNode subclass: #BlockNode
+	slots: {#parameters. #scope. #sequenceNode}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
 !BlockNode commentStamp!
 !BlockNode commentStamp!
 I represent an block closure node.!
 I represent an block closure node.!
 
 
 !BlockNode methodsFor: 'accessing'!
 !BlockNode methodsFor: 'accessing'!
 
 
+dagChild
+	^ self sequenceNode
+!
+
 parameters
 parameters
 	^ parameters ifNil: [ parameters := Array new ]
 	^ parameters ifNil: [ parameters := Array new ]
 !
 !
@@ -232,12 +193,14 @@ scope
 
 
 scope: aLexicalScope
 scope: aLexicalScope
 	scope := aLexicalScope
 	scope := aLexicalScope
-! !
+!
 
 
-!BlockNode methodsFor: 'testing'!
+sequenceNode
+	^ sequenceNode
+!
 
 
-isBlockNode
-	^ true
+sequenceNode: anObject
+	sequenceNode := anObject
 ! !
 ! !
 
 
 !BlockNode methodsFor: 'visiting'!
 !BlockNode methodsFor: 'visiting'!
@@ -246,7 +209,7 @@ acceptDagVisitor: aVisitor
 	^ aVisitor visitBlockNode: self
 	^ aVisitor visitBlockNode: self
 ! !
 ! !
 
 
-ASTNode subclass: #CascadeNode
+ExpressionNode subclass: #CascadeNode
 	slots: {#receiver}
 	slots: {#receiver}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
 !CascadeNode commentStamp!
 !CascadeNode commentStamp!
@@ -262,19 +225,13 @@ receiver: aNode
 	receiver := aNode
 	receiver := aNode
 ! !
 ! !
 
 
-!CascadeNode methodsFor: 'testing'!
-
-isCascadeNode
-	^ true
-! !
-
 !CascadeNode methodsFor: 'visiting'!
 !CascadeNode methodsFor: 'visiting'!
 
 
 acceptDagVisitor: aVisitor
 acceptDagVisitor: aVisitor
 	^ aVisitor visitCascadeNode: self
 	^ aVisitor visitCascadeNode: self
 ! !
 ! !
 
 
-ASTNode subclass: #DynamicArrayNode
+ExpressionNode subclass: #DynamicArrayNode
 	slots: {}
 	slots: {}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
 !DynamicArrayNode commentStamp!
 !DynamicArrayNode commentStamp!
@@ -286,7 +243,7 @@ acceptDagVisitor: aVisitor
 	^ aVisitor visitDynamicArrayNode: self
 	^ aVisitor visitDynamicArrayNode: self
 ! !
 ! !
 
 
-ASTNode subclass: #DynamicDictionaryNode
+ExpressionNode subclass: #DynamicDictionaryNode
 	slots: {}
 	slots: {}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
 !DynamicDictionaryNode commentStamp!
 !DynamicDictionaryNode commentStamp!
@@ -298,76 +255,70 @@ acceptDagVisitor: aVisitor
 	^ aVisitor visitDynamicDictionaryNode: self
 	^ aVisitor visitDynamicDictionaryNode: self
 ! !
 ! !
 
 
-ASTNode subclass: #JSStatementNode
-	slots: {}
+ExpressionNode subclass: #SendNode
+	slots: {#selector. #arguments. #receiver. #index. #javaScriptSelector. #argumentSwitcher. #isSideEffect}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
-!JSStatementNode commentStamp!
-I represent an JavaScript statement node.!
+!SendNode commentStamp!
+I represent an message send node.!
 
 
-!JSStatementNode methodsFor: 'testing'!
+!SendNode methodsFor: 'accessing'!
 
 
-isJSStatementNode
-	^ true
+argumentSwitcher
+	^ argumentSwitcher
 !
 !
 
 
-requiresSmalltalkContext
-	^ true
-! !
-
-!JSStatementNode methodsFor: 'visiting'!
-
-acceptDagVisitor: aVisitor
-	^ aVisitor visitJSStatementNode: self
-! !
-
-ASTNode subclass: #MethodNode
-	slots: {#selector. #arguments. #pragmas. #scope. #classReferences. #sendIndexes}
-	package: 'Compiler-AST'!
-!MethodNode commentStamp!
-I represent an method node.
-
-A method node must be the root and only method node of a valid AST.!
-
-!MethodNode methodsFor: 'accessing'!
+argumentSwitcher: aJSFunction
+	argumentSwitcher := aJSFunction
+!
 
 
 arguments
 arguments
-	^ arguments ifNil: [ #() ]
+	^ arguments ifNil: [ arguments := #() ]
 !
 !
 
 
 arguments: aCollection
 arguments: aCollection
 	arguments := aCollection
 	arguments := aCollection
 !
 !
 
 
-classReferences
-	^ classReferences
+beSideEffect
+	isSideEffect := true
 !
 !
 
 
-classReferences: aCollection
-	classReferences := aCollection
+dagChildren
+	self receiver ifNil: [ ^ self arguments copy ].
+	
+	^ self arguments copyWithFirst: self receiver
 !
 !
 
 
-messageSends
-	^ self sendIndexes keys
+index
+	^ index
 !
 !
 
 
-method
-	^ self
+index: anInteger
+	index := anInteger
 !
 !
 
 
-pragmas
-	^ pragmas ifNil: [ #() ]
+isSideEffect
+	^ isSideEffect ifNil: [ false ]
 !
 !
 
 
-pragmas: aCollection
-	pragmas := aCollection
+javaScriptSelector
+	^ javaScriptSelector
 !
 !
 
 
-scope
-	^ scope
+javaScriptSelector: aString
+	javaScriptSelector := aString
 !
 !
 
 
-scope: aMethodScope
-	scope := aMethodScope
+navigationLink
+	^ self selector
+!
+
+receiver
+	^ receiver
+!
+
+receiver: aNode
+	receiver := aNode
 !
 !
 
 
 selector
 selector
@@ -378,292 +329,301 @@ selector: aString
 	selector := aString
 	selector := aString
 !
 !
 
 
-sendIndexes
-	^ sendIndexes
-!
+superSend
+	^ self receiver ifNil: [ false ] ifNotNil: [ :recv | recv isSuper ]
+! !
 
 
-sendIndexes: aDictionary
-	sendIndexes := aDictionary
-!
+!SendNode methodsFor: 'testing'!
 
 
-sequenceNode
-	self dagChildren do: [ :each |
-		each isSequenceNode ifTrue: [ ^ each ] ].
-		
-	^ nil
+isNavigationNode
+	^ true
 ! !
 ! !
 
 
-!MethodNode methodsFor: 'visiting'!
+!SendNode methodsFor: 'visiting'!
 
 
 acceptDagVisitor: aVisitor
 acceptDagVisitor: aVisitor
-	^ aVisitor visitMethodNode: self
+	^ aVisitor visitSendNode: self
 ! !
 ! !
 
 
-ASTNode subclass: #ReturnNode
-	slots: {#scope}
+ExpressionNode subclass: #ValueNode
+	slots: {#value}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
-!ReturnNode commentStamp!
-I represent an return node. At the AST level, there is not difference between a local return or non-local return.!
+!ValueNode commentStamp!
+I represent a value node.!
 
 
-!ReturnNode methodsFor: 'accessing'!
+!ValueNode methodsFor: 'accessing'!
 
 
-scope
-	^ scope
+value
+	^ value
 !
 !
 
 
-scope: aLexicalScope
-	scope := aLexicalScope
+value: anObject
+	value := anObject
 ! !
 ! !
 
 
-!ReturnNode methodsFor: 'testing'!
-
-isReturnNode
-	^ true
-!
+!ValueNode methodsFor: 'testing'!
 
 
-nonLocalReturn
-	^ self scope isMethodScope not
+isIdempotent
+	^ self value isImmutable
 ! !
 ! !
 
 
-!ReturnNode methodsFor: 'visiting'!
+!ValueNode methodsFor: 'visiting'!
 
 
 acceptDagVisitor: aVisitor
 acceptDagVisitor: aVisitor
-	^ aVisitor visitReturnNode: self
+	^ aVisitor visitValueNode: self
 ! !
 ! !
 
 
-ASTNode subclass: #SendNode
-	slots: {#selector. #arguments. #receiver. #index. #shouldBeInlined}
+ExpressionNode subclass: #VariableNode
+	slots: {#identifier. #assigned. #binding}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
-!SendNode commentStamp!
-I represent an message send node.!
+!VariableNode commentStamp!
+I represent an variable node.!
 
 
-!SendNode methodsFor: 'accessing'!
+!VariableNode methodsFor: 'accessing'!
 
 
-arguments
-	^ arguments ifNil: [ arguments := #() ]
+alias
+	^ self binding alias
 !
 !
 
 
-arguments: aCollection
-	arguments := aCollection
+assigned
+	^ assigned ifNil: [ false ]
 !
 !
 
 
-dagChildren
-	self receiver ifNil: [ ^ self arguments copy ].
-	
-	^ (Array with: self receiver)
-		addAll: self arguments;
-		yourself
+assigned: aBoolean
+	assigned := aBoolean
 !
 !
 
 
-index
-	^ index
+binding
+	^ binding
 !
 !
 
 
-index: anInteger
-	index := anInteger
+binding: aScopeVar
+	binding := aScopeVar
 !
 !
 
 
-navigationLink
-	^ self selector
+identifier
+	^ identifier
 !
 !
 
 
-receiver
-	^ receiver
+identifier: anObject
+	identifier := anObject
 !
 !
 
 
-receiver: aNode
-	receiver := aNode
+navigationLink
+	^ self identifier
 !
 !
 
 
-selector
-	^ selector
+value
+	self deprecatedAPI: 'Use #identifier instead.'.
+	^ self identifier
 !
 !
 
 
-selector: aString
-	selector := aString
-!
+value: anObject
+	self deprecatedAPI: 'Use #identifier: instead.'.
+	self identifier: anObject
+! !
 
 
-shouldBeInlined
-	^ shouldBeInlined ifNil: [ false ]
-!
+!VariableNode methodsFor: 'testing'!
 
 
-shouldBeInlined: aBoolean
-	shouldBeInlined := aBoolean
+isAssignable
+	^ self binding isAssignable
 !
 !
 
 
-superSend
-	^ self receiver notNil and: [ self receiver isSuper ]
-! !
+isIdempotent
+	^ self binding isIdempotent
+!
 
 
-!SendNode methodsFor: 'testing'!
+isImmutable
+	self deprecatedAPI: 'Use #isIdempotent / #isAssignable not instead.'.
+	^ self isIdempotent "to be consistent with super"
+!
 
 
 isNavigationNode
 isNavigationNode
 	^ true
 	^ true
 !
 !
 
 
-isSendNode
-	^ true
-!
+isSuper
+	^ self binding isSuper
+! !
 
 
-requiresSmalltalkContext
-	^ true
+!VariableNode methodsFor: 'visiting'!
+
+acceptDagVisitor: aVisitor
+	^ aVisitor visitVariableNode: self
 ! !
 ! !
 
 
-!SendNode methodsFor: 'visiting'!
+ASTNode subclass: #JSStatementNode
+	slots: {}
+	package: 'Compiler-AST'!
+!JSStatementNode commentStamp!
+I represent an JavaScript statement node.!
+
+!JSStatementNode methodsFor: 'visiting'!
 
 
 acceptDagVisitor: aVisitor
 acceptDagVisitor: aVisitor
-	^ aVisitor visitSendNode: self
+	^ aVisitor visitJSStatementNode: self
 ! !
 ! !
 
 
-ASTNode subclass: #SequenceNode
-	slots: {#temps. #scope}
+ASTNode subclass: #MethodNode
+	slots: {#selector. #arguments. #pragmas. #scope. #classReferences. #sendIndexes. #sequenceNode}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
-!SequenceNode commentStamp!
-I represent an sequence node. A sequence represent a set of instructions inside the same scope (the method scope or a block scope).!
+!MethodNode commentStamp!
+I represent an method node.
 
 
-!SequenceNode methodsFor: 'accessing'!
+A method node must be the root and only method node of a valid AST.!
 
 
-scope
-	^ scope
-!
+!MethodNode methodsFor: 'accessing'!
 
 
-scope: aLexicalScope
-	scope := aLexicalScope
+arguments
+	^ arguments ifNil: [ #() ]
 !
 !
 
 
-temps
-	^ temps ifNil: [ #() ]
+arguments: aCollection
+	arguments := aCollection
 !
 !
 
 
-temps: aCollection
-	temps := aCollection
-! !
-
-!SequenceNode methodsFor: 'testing'!
-
-isSequenceNode
-	^ true
-! !
+classReferences
+	^ classReferences
+!
 
 
-!SequenceNode methodsFor: 'visiting'!
+classReferences: aCollection
+	classReferences := aCollection
+!
 
 
-acceptDagVisitor: aVisitor
-	^ aVisitor visitSequenceNode: self
-! !
+dagChild
+	^ self sequenceNode
+!
 
 
-SequenceNode subclass: #BlockSequenceNode
-	slots: {}
-	package: 'Compiler-AST'!
-!BlockSequenceNode commentStamp!
-I represent an special sequence node for block scopes.!
+messageSends
+	^ self sendIndexes keys
+!
 
 
-!BlockSequenceNode methodsFor: 'testing'!
+method
+	^ self
+!
 
 
-isBlockSequenceNode
-	^ true
-! !
+pragmas
+	^ pragmas ifNil: [ #() ]
+!
 
 
-!BlockSequenceNode methodsFor: 'visiting'!
+pragmas: aCollection
+	pragmas := aCollection
+!
 
 
-acceptDagVisitor: aVisitor
-	^ aVisitor visitBlockSequenceNode: self
-! !
+scope
+	^ scope
+!
 
 
-ASTNode subclass: #ValueNode
-	slots: {#value}
-	package: 'Compiler-AST'!
-!ValueNode commentStamp!
-I represent a value node.!
+scope: aMethodScope
+	scope := aMethodScope
+!
 
 
-!ValueNode methodsFor: 'accessing'!
+selector
+	^ selector
+!
 
 
-value
-	^ value
+selector: aString
+	selector := aString
 !
 !
 
 
-value: anObject
-	value := anObject
-! !
+sendIndexes
+	^ sendIndexes
+!
 
 
-!ValueNode methodsFor: 'testing'!
+sendIndexes: aDictionary
+	sendIndexes := aDictionary
+!
 
 
-isImmutable
-	^ self value isImmutable
+sequenceNode
+	^ sequenceNode
 !
 !
 
 
-isValueNode
-	^ true
+sequenceNode: aSequenceNode
+	sequenceNode := aSequenceNode
 ! !
 ! !
 
 
-!ValueNode methodsFor: 'visiting'!
+!MethodNode methodsFor: 'visiting'!
 
 
 acceptDagVisitor: aVisitor
 acceptDagVisitor: aVisitor
-	^ aVisitor visitValueNode: self
+	^ aVisitor visitMethodNode: self
 ! !
 ! !
 
 
-ValueNode subclass: #VariableNode
-	slots: {#assigned. #binding}
+ASTNode subclass: #ReturnNode
+	slots: {#scope. #expression}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
-!VariableNode commentStamp!
-I represent an variable node.!
+!ReturnNode commentStamp!
+I represent an return node. At the AST level, there is not difference between a local return or non-local return.!
 
 
-!VariableNode methodsFor: 'accessing'!
+!ReturnNode methodsFor: 'accessing'!
 
 
-alias
-	^ self binding alias
+dagChild
+	^ self expression
 !
 !
 
 
-assigned
-	^ assigned ifNil: [ false ]
+expression
+	^ expression ifNil: [ nodes first ]
 !
 !
 
 
-assigned: aBoolean
-	assigned := aBoolean
+expression: anObject
+	expression := anObject
 !
 !
 
 
-beAssigned
-	self binding validateAssignment.
-	assigned := true
+scope
+	^ scope
 !
 !
 
 
-binding
-	^ binding
-!
+scope: aLexicalScope
+	scope := aLexicalScope
+! !
 
 
-binding: aScopeVar
-	binding := aScopeVar
+!ReturnNode methodsFor: 'testing'!
+
+isReturnNode
+	^ true
 !
 !
 
 
-navigationLink
-	^ self value
+nonLocalReturn
+	^ self scope isMethodScope not
 ! !
 ! !
 
 
-!VariableNode methodsFor: 'testing'!
+!ReturnNode methodsFor: 'visiting'!
 
 
-isArgument
-	^ self binding isArgVar
-!
+acceptDagVisitor: aVisitor
+	^ aVisitor visitReturnNode: self
+! !
 
 
-isImmutable
-	^ self binding isImmutable
-!
+ASTNode subclass: #SequenceNode
+	slots: {#temps}
+	package: 'Compiler-AST'!
+!SequenceNode commentStamp!
+I represent an sequence node. A sequence represent a set of instructions inside the same scope (the method scope or a block scope).!
 
 
-isNavigationNode
-	^ true
-!
+!SequenceNode methodsFor: 'accessing'!
 
 
-isSuper
-	^ self binding isSuper
+temps
+	^ temps ifNil: [ #() ]
 !
 !
 
 
-isVariableNode
-	^ true
+temps: aCollection
+	temps := aCollection
 ! !
 ! !
 
 
-!VariableNode methodsFor: 'visiting'!
+!SequenceNode methodsFor: 'visiting'!
 
 
 acceptDagVisitor: aVisitor
 acceptDagVisitor: aVisitor
-	^ aVisitor visitVariableNode: self
+	^ aVisitor visitSequenceNode: self
+! !
+
+SequenceNode subclass: #BlockSequenceNode
+	slots: {}
+	package: 'Compiler-AST'!
+!BlockSequenceNode commentStamp!
+I represent an special sequence node for block scopes.!
+
+!BlockSequenceNode methodsFor: 'visiting'!
+
+acceptDagVisitor: aVisitor
+	^ aVisitor visitBlockSequenceNode: self
 ! !
 ! !
 
 
 Object subclass: #AstPragmator
 Object subclass: #AstPragmator
@@ -701,11 +661,11 @@ value: aMethodNode
 	^ aMethodNode
 	^ aMethodNode
 ! !
 ! !
 
 
-AstPragmator subclass: #AstEarlyPragmator
+AstPragmator subclass: #AstSemanticPragmator
 	slots: {}
 	slots: {}
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!
 
 
-!AstEarlyPragmator methodsFor: 'pragmas'!
+!AstSemanticPragmator methodsFor: 'pragmas'!
 
 
 inlineJS: aString
 inlineJS: aString
 	self methodNode sequenceNode dagChildren ifNotEmpty: [
 	self methodNode sequenceNode dagChildren ifNotEmpty: [
@@ -802,6 +762,14 @@ visitVariableNode: aNode
 	^ self visitDagNode: aNode
 	^ self visitDagNode: aNode
 ! !
 ! !
 
 
+AssignmentNode setTraitComposition: {TDerivedDagChildren} asTraitComposition!
+BlockNode setTraitComposition: {TSingleDagChild} asTraitComposition!
+SendNode setTraitComposition: {TDerivedDagChildren} asTraitComposition!
+ValueNode setTraitComposition: {TDagSink} asTraitComposition!
+VariableNode setTraitComposition: {TDagSink} asTraitComposition!
+JSStatementNode setTraitComposition: {TDagSink} asTraitComposition!
+MethodNode setTraitComposition: {TSingleDagChild} asTraitComposition!
+ReturnNode setTraitComposition: {TSingleDagChild} asTraitComposition!
 AstPragmator setTraitComposition: {TPragmator} asTraitComposition!
 AstPragmator setTraitComposition: {TPragmator} asTraitComposition!
 ! !
 ! !
 
 

+ 256 - 201
lang/src/Compiler-Core.js

@@ -157,9 +157,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.source;
 $1=$self.source;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return "";
 return "";
 } else {
 } else {
 return $1;
 return $1;
@@ -248,18 +248,44 @@ $globals.AbstractCodeGenerator);
 
 
 
 
 
 
-$core.addClass("CodeGenerator", $globals.AbstractCodeGenerator, ["transformersDictionary"], "Compiler-Core");
+$core.addClass("AstGenerator", $globals.AbstractCodeGenerator, ["transformersDictionary"], "Compiler-Core");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
-$globals.CodeGenerator.comment="I am a basic code generator. I generate a valid JavaScript output, but no not perform any inlining.\x0aSee `InliningCodeGenerator` for an optimized JavaScript code generation.";
+$globals.AstGenerator.comment="I am a very basic code generator.\x0aI generate semantically augmented abstract syntax tree,\x0aSome initial pragmas (eg. #inlineJS:) are applied to transform the tree.";
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
-selector: "earlyAstPragmator",
+selector: "semanticAnalyzer",
+protocol: "compiling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "semanticAnalyzer\x0a\x09^ (SemanticAnalyzer on: self currentClass)\x0a\x09\x09thePackage: self currentPackage;\x0a\x09\x09yourself",
+referencedClasses: ["SemanticAnalyzer"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["thePackage:", "on:", "currentClass", "currentPackage", "yourself"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=$recv($globals.SemanticAnalyzer)._on_($self._currentClass());
+$recv($1)._thePackage_($self._currentPackage());
+return $recv($1)._yourself();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"semanticAnalyzer",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.AstGenerator);
+
+$core.addMethod(
+$core.method({
+selector: "semanticAstPragmator",
 protocol: "compiling",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
 args: [],
-source: "earlyAstPragmator\x0a\x09^ AstEarlyPragmator new",
-referencedClasses: ["AstEarlyPragmator"],
+source: "semanticAstPragmator\x0a\x09^ AstSemanticPragmator new",
+referencedClasses: ["AstSemanticPragmator"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
 messageSends: ["new"]
 messageSends: ["new"]
@@ -268,13 +294,56 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv($globals.AstEarlyPragmator)._new();
+return $recv($globals.AstSemanticPragmator)._new();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"earlyAstPragmator",{})});
+}, function($ctx1) {$ctx1.fill(self,"semanticAstPragmator",{})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }; }),
 }; }),
-$globals.CodeGenerator);
+$globals.AstGenerator);
 
 
+$core.addMethod(
+$core.method({
+selector: "transformersDictionary",
+protocol: "compiling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "transformersDictionary\x0a\x09^ transformersDictionary ifNil: [ transformersDictionary := Dictionary new\x0a\x09\x09at: '2000-semantic' put: self semanticAnalyzer;\x0a\x09\x09at: '2500-semanticPragmas' put: self semanticAstPragmator;\x0a\x09\x09yourself ]",
+referencedClasses: ["Dictionary"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["ifNil:", "at:put:", "new", "semanticAnalyzer", "semanticAstPragmator", "yourself"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1,$2;
+$1=$self.transformersDictionary;
+if($1 == null || $1.a$nil){
+$2=$recv($globals.Dictionary)._new();
+[$recv($2)._at_put_("2000-semantic",$self._semanticAnalyzer())
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["at:put:"]=1
+//>>excludeEnd("ctx");
+][0];
+$recv($2)._at_put_("2500-semanticPragmas",$self._semanticAstPragmator());
+$self.transformersDictionary=$recv($2)._yourself();
+return $self.transformersDictionary;
+} else {
+return $1;
+}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"transformersDictionary",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.AstGenerator);
+
+
+
+$core.addClass("CodeGenerator", $globals.AstGenerator, [], "Compiler-Core");
+//>>excludeStart("ide", pragmas.excludeIdeData);
+$globals.CodeGenerator.comment="I am a basic code generator. I generate a valid JavaScript output, but do not perform any inlining.\x0aSee `InliningCodeGenerator` for an optimized JavaScript code generation.";
+//>>excludeEnd("ide");
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "irTranslator",
 selector: "irTranslator",
@@ -342,69 +411,45 @@ return $recv($globals.IRLatePragmator)._new();
 }; }),
 }; }),
 $globals.CodeGenerator);
 $globals.CodeGenerator);
 
 
-$core.addMethod(
-$core.method({
-selector: "semanticAnalyzer",
-protocol: "compiling",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "semanticAnalyzer\x0a\x09^ (SemanticAnalyzer on: self currentClass)\x0a\x09\x09thePackage: self currentPackage;\x0a\x09\x09yourself",
-referencedClasses: ["SemanticAnalyzer"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["thePackage:", "on:", "currentClass", "currentPackage", "yourself"]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1;
-$1=$recv($globals.SemanticAnalyzer)._on_($self._currentClass());
-$recv($1)._thePackage_($self._currentPackage());
-return $recv($1)._yourself();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"semanticAnalyzer",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.CodeGenerator);
-
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "transformersDictionary",
 selector: "transformersDictionary",
 protocol: "compiling",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
 args: [],
-source: "transformersDictionary\x0a\x09^ transformersDictionary ifNil: [ transformersDictionary := Dictionary new\x0a\x09\x09at: '1000-earlyPragmas' put: self earlyAstPragmator;\x0a\x09\x09at: '2000-semantic' put: self semanticAnalyzer;\x0a\x09\x09at: '5000-astToIr' put: self translator;\x0a\x09\x09at: '8000-irToJs' put: self irTranslator;\x0a\x09\x09at: '9000-latePragmas' put: self lateIRPragmator;\x0a\x09\x09yourself ]",
-referencedClasses: ["Dictionary"],
+source: "transformersDictionary\x0a\x09^ transformersDictionary ifNil: [ transformersDictionary := super transformersDictionary\x0a\x09\x09at: '5000-astToIr' put: self translator;\x0a\x09\x09at: '7000-irLatePragmas' put: self lateIRPragmator;\x0a\x09\x09at: '8000-irToJs' put: self irTranslator;\x0a\x09\x09yourself ]",
+referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["ifNil:", "at:put:", "new", "earlyAstPragmator", "semanticAnalyzer", "translator", "irTranslator", "lateIRPragmator", "yourself"]
+messageSends: ["ifNil:", "at:put:", "transformersDictionary", "translator", "lateIRPragmator", "irTranslator", "yourself"]
 }, function ($methodClass){ return function (){
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
+var $1,$2;
 $1=$self.transformersDictionary;
 $1=$self.transformersDictionary;
-if(($receiver = $1) == null || $receiver.a$nil){
-$2=$recv($globals.Dictionary)._new();
-$recv($2)._at_put_("1000-earlyPragmas",$self._earlyAstPragmator());
+if($1 == null || $1.a$nil){
+$2=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+$ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($2)._at_put_("2000-semantic",$self._semanticAnalyzer());
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._transformersDictionary.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=2;
+,$ctx1.supercall = false
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($2)._at_put_("5000-astToIr",$self._translator());
+][0];
+[$recv($2)._at_put_("5000-astToIr",$self._translator())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=3;
+,$ctx1.sendIdx["at:put:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($2)._at_put_("8000-irToJs",$self._irTranslator());
+][0];
+[$recv($2)._at_put_("7000-irLatePragmas",$self._lateIRPragmator())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=4;
+,$ctx1.sendIdx["at:put:"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($2)._at_put_("9000-latePragmas",$self._lateIRPragmator());
+][0];
+$recv($2)._at_put_("8000-irToJs",$self._irTranslator());
 $self.transformersDictionary=$recv($2)._yourself();
 $self.transformersDictionary=$recv($2)._yourself();
 return $self.transformersDictionary;
 return $self.transformersDictionary;
 } else {
 } else {
@@ -455,28 +500,19 @@ selector: "ast:forClass:protocol:",
 protocol: "compiling",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString", "aClass", "anotherString"],
 args: ["aString", "aClass", "anotherString"],
-source: "ast: aString forClass: aClass protocol: anotherString\x0a\x09self\x0a\x09\x09start: aString forClass: aClass protocol: anotherString;\x0a\x09\x09transformerAt: '2500-astCheckpoint' put: [ :x | ^x ];\x0a\x09\x09compileNode: (self parse: aString);\x0a\x09\x09error: 'AST transformation failed.'",
-referencedClasses: [],
+source: "ast: aString forClass: aClass protocol: anotherString\x0a\x09^ self\x0a\x09\x09codeGeneratorClass: AstGenerator;\x0a\x09\x09start: aString forClass: aClass protocol: anotherString;\x0a\x09\x09compileNode: (self parse: aString)",
+referencedClasses: ["AstGenerator"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["start:forClass:protocol:", "transformerAt:put:", "compileNode:", "parse:", "error:"]
+messageSends: ["codeGeneratorClass:", "start:forClass:protocol:", "compileNode:", "parse:"]
 }, function ($methodClass){ return function (aString,aClass,anotherString){
 }, function ($methodClass){ return function (aString,aClass,anotherString){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $early={};
-try {
+$self._codeGeneratorClass_($globals.AstGenerator);
 $self._start_forClass_protocol_(aString,aClass,anotherString);
 $self._start_forClass_protocol_(aString,aClass,anotherString);
-$self._transformerAt_put_("2500-astCheckpoint",(function(x){
-throw $early=[x];
-
-}));
-$self._compileNode_($self._parse_(aString));
-$self._error_("AST transformation failed.");
-return self;
-}
-catch(e) {if(e===$early)return e[0]; throw e}
+return $self._compileNode_($self._parse_(aString));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"ast:forClass:protocol:",{aString:aString,aClass:aClass,anotherString:anotherString})});
 }, function($ctx1) {$ctx1.fill(self,"ast:forClass:protocol:",{aString:aString,aClass:aClass,anotherString:anotherString})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -578,9 +614,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.codeGeneratorClass;
 $1=$self.codeGeneratorClass;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $globals.InliningCodeGenerator;
 return $globals.InliningCodeGenerator;
 } else {
 } else {
 return $1;
 return $1;
@@ -616,33 +652,30 @@ selector: "compile:forClass:protocol:",
 protocol: "compiling",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString", "aClass", "anotherString"],
 args: ["aString", "aClass", "anotherString"],
-source: "compile: aString forClass: aClass protocol: anotherString\x0a\x09| compilationResult result pragmas closureFactory |\x0a\x09compilationResult := self\x0a\x09\x09start: aString forClass: aClass protocol: anotherString;\x0a\x09\x09compileNode: (self parse: aString).\x0a\x09closureFactory := self\x0a\x09\x09eval: (self wrappedSourceOf: compilationResult)\x0a\x09\x09forPackage: self currentPackage.\x0a\x09result := Smalltalk core method: #{\x0a\x09\x09#selector -> compilationResult selector.\x0a\x09\x09#protocol -> anotherString.\x0a\x09\x09#source -> aString.\x0a\x09\x09#messageSends -> compilationResult messageSends asArray.\x0a\x09\x09#args -> compilationResult arguments.\x0a\x09\x09#referencedClasses -> compilationResult classReferences asArray.\x0a\x09} withFactory: closureFactory.\x0a\x09result pragmas: compilationResult pragmas.\x0a\x09^ result",
+source: "compile: aString forClass: aClass protocol: anotherString\x0a\x09| sanitizedSource compilationResult result pragmas closureFactory |\x0a\x09sanitizedSource := aString crlfSanitized.\x0a\x09compilationResult := self\x0a\x09\x09start: sanitizedSource forClass: aClass protocol: anotherString;\x0a\x09\x09compileNode: (self parse: sanitizedSource).\x0a\x09closureFactory := self\x0a\x09\x09eval: (self wrappedSourceOf: compilationResult)\x0a\x09\x09forPackage: self currentPackage.\x0a\x09result := Smalltalk core method: #{\x0a\x09\x09#selector -> compilationResult selector.\x0a\x09\x09#protocol -> anotherString.\x0a\x09\x09#source -> sanitizedSource.\x0a\x09\x09#messageSends -> compilationResult messageSends asArray.\x0a\x09\x09#args -> compilationResult arguments.\x0a\x09\x09#referencedClasses -> compilationResult classReferences asArray.\x0a\x09} withFactory: closureFactory.\x0a\x09result pragmas: compilationResult pragmas.\x0a\x09^ result",
 referencedClasses: ["Smalltalk"],
 referencedClasses: ["Smalltalk"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["start:forClass:protocol:", "compileNode:", "parse:", "eval:forPackage:", "wrappedSourceOf:", "currentPackage", "method:withFactory:", "core", "selector", "asArray", "messageSends", "arguments", "classReferences", "pragmas:", "pragmas"]
+messageSends: ["crlfSanitized", "start:forClass:protocol:", "compileNode:", "parse:", "eval:forPackage:", "wrappedSourceOf:", "currentPackage", "method:withFactory:", "core", "selector", "asArray", "messageSends", "arguments", "classReferences", "pragmas:", "pragmas"]
 }, function ($methodClass){ return function (aString,aClass,anotherString){
 }, function ($methodClass){ return function (aString,aClass,anotherString){
 var self=this,$self=this;
 var self=this,$self=this;
-var compilationResult,result,pragmas,closureFactory;
+var sanitizedSource,compilationResult,result,pragmas,closureFactory;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$3,$4,$2;
-$self._start_forClass_protocol_(aString,aClass,anotherString);
-compilationResult=$self._compileNode_($self._parse_(aString));
+sanitizedSource=$recv(aString)._crlfSanitized();
+$self._start_forClass_protocol_(sanitizedSource,aClass,anotherString);
+compilationResult=$self._compileNode_($self._parse_(sanitizedSource));
 closureFactory=$self._eval_forPackage_($self._wrappedSourceOf_(compilationResult),$self._currentPackage());
 closureFactory=$self._eval_forPackage_($self._wrappedSourceOf_(compilationResult),$self._currentPackage());
-$1=$recv($globals.Smalltalk)._core();
-$3=$recv(compilationResult)._selector();
-$4=$recv($recv(compilationResult)._messageSends())._asArray();
+result=$recv($recv($globals.Smalltalk)._core())._method_withFactory_($globals.HashedCollection._newFromPairs_(["selector",$recv(compilationResult)._selector(),"protocol",anotherString,"source",sanitizedSource,"messageSends",[$recv($recv(compilationResult)._messageSends())._asArray()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["asArray"]=1;
+,$ctx1.sendIdx["asArray"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$globals.HashedCollection._newFromPairs_(["selector",$3,"protocol",anotherString,"source",aString,"messageSends",$4,"args",$recv(compilationResult)._arguments(),"referencedClasses",$recv($recv(compilationResult)._classReferences())._asArray()]);
-result=$recv($1)._method_withFactory_($2,closureFactory);
+][0],"args",$recv(compilationResult)._arguments(),"referencedClasses",$recv($recv(compilationResult)._classReferences())._asArray()]),closureFactory);
 $recv(result)._pragmas_($recv(compilationResult)._pragmas());
 $recv(result)._pragmas_($recv(compilationResult)._pragmas());
 return result;
 return result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"compile:forClass:protocol:",{aString:aString,aClass:aClass,anotherString:anotherString,compilationResult:compilationResult,result:result,pragmas:pragmas,closureFactory:closureFactory})});
+}, function($ctx1) {$ctx1.fill(self,"compile:forClass:protocol:",{aString:aString,aClass:aClass,anotherString:anotherString,sanitizedSource:sanitizedSource,compilationResult:compilationResult,result:result,pragmas:pragmas,closureFactory:closureFactory})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }; }),
 }; }),
 $globals.Compiler);
 $globals.Compiler);
@@ -774,12 +807,12 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $receiver;
-if(($receiver = aPackage) == null || $receiver.a$nil){
-return $self._eval_(aString);
+if(aPackage == null || aPackage.a$nil){
+return [$self._eval_(aString)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["eval:"]=1;
+,$ctx1.sendIdx["eval:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 } else {
 } else {
 return $recv(aPackage)._eval_(aString);
 return $recv(aPackage)._eval_(aString);
 }
 }
@@ -829,13 +862,11 @@ var result,method;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2;
-$1=$self._sourceForExpression_(aString);
-$2=$recv(anObject)._class();
+method=$self._install_forClass_protocol_($self._sourceForExpression_(aString),[$recv(anObject)._class()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["class"]=1;
+,$ctx1.sendIdx["class"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-method=$self._install_forClass_protocol_($1,$2,"**xxxDoIt");
+][0],"**xxxDoIt");
 result=$recv(anObject)._xxxDoIt();
 result=$recv(anObject)._xxxDoIt();
 $recv($recv(anObject)._class())._removeCompiledMethod_(method);
 $recv($recv(anObject)._class())._removeCompiledMethod_(method);
 return result;
 return result;
@@ -919,50 +950,53 @@ selector: "parseError:parsing:",
 protocol: "error handling",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anException", "aString"],
 args: ["anException", "aString"],
-source: "parseError: anException parsing: aString\x0a\x09(anException basicAt: 'location')\x0a\x09\x09ifNil: [ ^ anException pass ]\x0a\x09\x09ifNotNil: [ :loc |\x0a\x09\x09\x09^ ParseError new \x0a\x09\x09\x09\x09messageText: \x0a\x09\x09\x09\x09\x09'Parse error on line ', loc start line ,\x0a\x09\x09\x09\x09\x09' column ' , loc start column ,\x0a\x09\x09\x09\x09\x09' : Unexpected character ', (anException basicAt: 'found');\x0a\x09\x09\x09\x09yourself ]",
+source: "parseError: anException parsing: aString\x0a\x09(anException basicAt: 'location')\x0a\x09\x09ifNil: [ ^ anException pass ]\x0a\x09\x09ifNotNil: [ :loc |\x0a\x09\x09\x09^ ParseError new \x0a\x09\x09\x09\x09messageText: \x0a\x09\x09\x09\x09\x09'Parse error on line ', loc start line asString,\x0a\x09\x09\x09\x09\x09' column ' , loc start column asString,\x0a\x09\x09\x09\x09\x09' : Unexpected character ', (anException basicAt: 'found');\x0a\x09\x09\x09\x09yourself ]",
 referencedClasses: ["ParseError"],
 referencedClasses: ["ParseError"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["ifNil:ifNotNil:", "basicAt:", "pass", "messageText:", "new", ",", "line", "start", "column", "yourself"]
+messageSends: ["ifNil:ifNotNil:", "basicAt:", "pass", "messageText:", "new", ",", "asString", "line", "start", "column", "yourself"]
 }, function ($methodClass){ return function (anException,aString){
 }, function ($methodClass){ return function (anException,aString){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$9,$8,$7,$6,$5,$4,$3,$receiver;
-$1=$recv(anException)._basicAt_("location");
+var $1,$2;
+$1=[$recv(anException)._basicAt_("location")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["basicAt:"]=1;
+,$ctx1.sendIdx["basicAt:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 return $recv(anException)._pass();
 return $recv(anException)._pass();
 } else {
 } else {
 var loc;
 var loc;
-loc=$receiver;
+loc=$1;
 $2=$recv($globals.ParseError)._new();
 $2=$recv($globals.ParseError)._new();
-$9=$recv(loc)._start();
+$recv($2)._messageText_([$recv([$recv([$recv([$recv("Parse error on line ".__comma([$recv($recv([$recv(loc)._start()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["start"]=1
+//>>excludeEnd("ctx");
+][0])._line())._asString()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["start"]=1;
+,$ctx1.sendIdx["asString"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$8=$recv($9)._line();
-$7="Parse error on line ".__comma($8);
-$6=$recv($7).__comma(" column ");
+][0])).__comma(" column ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=4;
+,$ctx1.sendIdx[","]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$5=$recv($6).__comma($recv($recv(loc)._start())._column());
+][0]).__comma($recv($recv($recv(loc)._start())._column())._asString())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=3;
+,$ctx1.sendIdx[","]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$4=$recv($5).__comma(" : Unexpected character ");
+][0]).__comma(" : Unexpected character ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=2;
+,$ctx1.sendIdx[","]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$3=$recv($4).__comma($recv(anException)._basicAt_("found"));
+][0]).__comma($recv(anException)._basicAt_("found"))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($2)._messageText_($3);
+][0]);
 return $recv($2)._yourself();
 return $recv($2)._yourself();
 }
 }
 return self;
 return self;
@@ -1011,7 +1045,6 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 $recv(aClass)._includingPossibleMetaDo_((function(eachSide){
 $recv(aClass)._includingPossibleMetaDo_((function(eachSide){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
@@ -1020,8 +1053,7 @@ return $recv($recv($recv(eachSide)._methodDictionary())._values())._do_displayin
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($recv(each)._origin()).__eq(eachSide);
-if($core.assert($1)){
+if($core.assert($recv($recv(each)._origin()).__eq(eachSide))){
 return $self._install_forClass_protocol_($recv(each)._source(),eachSide,$recv(each)._protocol());
 return $self._install_forClass_protocol_($recv(each)._source(),eachSide,$recv(each)._protocol());
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1087,12 +1119,11 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv("xxxDoIt ^ [ ".__comma(aString)).__comma(" ] value");
+return [$recv("xxxDoIt ^ [ ".__comma(aString)).__comma(" ] value")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $1;
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"sourceForExpression:",{aString:aString})});
 }, function($ctx1) {$ctx1.fill(self,"sourceForExpression:",{aString:aString})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -1116,18 +1147,18 @@ var package_;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $2,$1;
+var $1;
 package_=$recv(aClass)._packageOfProtocol_(anotherString);
 package_=$recv(aClass)._packageOfProtocol_(anotherString);
-$self._currentPackage_(package_);
+[$self._currentPackage_(package_)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["currentPackage:"]=1;
+,$ctx1.sendIdx["currentPackage:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$recv($self._codeGeneratorClass())._new();
-$recv($2)._source_(aString);
-$recv($2)._currentClass_(aClass);
-$recv($2)._currentPackage_(package_);
-$1=$recv($2)._yourself();
-$self._codeGenerator_($1);
+][0];
+$1=$recv($self._codeGeneratorClass())._new();
+$recv($1)._source_(aString);
+$recv($1)._currentClass_(aClass);
+$recv($1)._currentPackage_(package_);
+$self._codeGenerator_($recv($1)._yourself());
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"start:forClass:protocol:",{aString:aString,aClass:aClass,anotherString:anotherString,package_:package_})});
 }, function($ctx1) {$ctx1.fill(self,"start:forClass:protocol:",{aString:aString,aClass:aClass,anotherString:anotherString,package_:package_})});
@@ -1165,7 +1196,7 @@ selector: "wrappedSourceOf:",
 protocol: "private",
 protocol: "private",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRMethod"],
 args: ["anIRMethod"],
-source: "wrappedSourceOf: anIRMethod\x0a\x09anIRMethod attachments\x0a\x09\x09ifEmpty: [ ^\x0a\x09\x09\x09'(function ($methodClass){ return ',\x0a\x09\x09\x09anIRMethod compiledSource,\x0a\x09\x09\x09'; })' ]\x0a\x09\x09ifNotEmpty: [ :attachments | ^ \x0a\x09\x09\x09'(function ($methodClass){ return (function(method){Object.defineProperty(method,\x22a$atx\x22,{enumerable:false,configurable:true,writable:true,value:',\x0a\x09\x09\x09attachments asJavaScriptSource,\x0a\x09\x09\x09'});return method})(',\x0a\x09\x09\x09anIRMethod compiledSource,\x0a\x09\x09\x09'); })' ]",
+source: "wrappedSourceOf: anIRMethod\x0a\x09^ anIRMethod attachments\x0a\x09\x09ifEmpty: [\x0a\x09\x09\x09'(function ($methodClass){ return ',\x0a\x09\x09\x09anIRMethod compiledSource,\x0a\x09\x09\x09'; })' ]\x0a\x09\x09ifNotEmpty: [ :attachments |\x0a\x09\x09\x09'(function ($methodClass){ return Object.defineProperty(',\x0a\x09\x09\x09anIRMethod compiledSource,\x0a\x09\x09\x09',\x22a$atx\x22,{enumerable:false,configurable:true,writable:true,value:',\x0a\x09\x09\x09attachments asJavaScriptSource,\x0a\x09\x09\x09'}); })' ]",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
@@ -1175,26 +1206,23 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $3,$2,$1,$6,$5,$4;
-var $early={};
-try {
-$recv($recv(anIRMethod)._attachments())._ifEmpty_ifNotEmpty_((function(){
+return $recv($recv(anIRMethod)._attachments())._ifEmpty_ifNotEmpty_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$3=$recv(anIRMethod)._compiledSource();
+return [$recv(["(function ($methodClass){ return ".__comma([$recv(anIRMethod)._compiledSource()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["compiledSource"]=1;
+,$ctx2.sendIdx["compiledSource"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2="(function ($methodClass){ return ".__comma($3);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=2;
+,$ctx2.sendIdx[","]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($2).__comma("; })");
+][0]).__comma("; })")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=1;
+,$ctx2.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-throw $early=[$1];
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -1202,26 +1230,23 @@ throw $early=[$1];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$6=$recv("(function ($methodClass){ return (function(method){Object.defineProperty(method,\x22a$atx\x22,{enumerable:false,configurable:true,writable:true,value:".__comma($recv(attachments)._asJavaScriptSource())).__comma("});return method})(");
+return [$recv([$recv([$recv("(function ($methodClass){ return Object.defineProperty(".__comma($recv(anIRMethod)._compiledSource())).__comma(",\x22a$atx\x22,{enumerable:false,configurable:true,writable:true,value:")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=5;
+,$ctx2.sendIdx[","]=5
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$5=$recv($6).__comma($recv(anIRMethod)._compiledSource());
+][0]).__comma($recv(attachments)._asJavaScriptSource())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=4;
+,$ctx2.sendIdx[","]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$4=$recv($5).__comma("); })");
+][0]).__comma("}); })")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=3;
+,$ctx2.sendIdx[","]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-throw $early=[$4];
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({attachments:attachments},$ctx1,2)});
 }, function($ctx2) {$ctx2.fillBlock({attachments:attachments},$ctx1,2)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }));
 }));
-return self;
-}
-catch(e) {if(e===$early)return e[0]; throw e}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"wrappedSourceOf:",{anIRMethod:anIRMethod})});
 }, function($ctx1) {$ctx1.fill(self,"wrappedSourceOf:",{anIRMethod:anIRMethod})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -1389,57 +1414,6 @@ $core.addClass("Evaluator", $globals.Object, [], "Compiler-Core");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.Evaluator.comment="I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.";
 $globals.Evaluator.comment="I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.";
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
-$core.addMethod(
-$core.method({
-selector: "evaluate:context:",
-protocol: "evaluating",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aString", "aContext"],
-source: "evaluate: aString context: aContext\x0a\x09\x22Similar to #evaluate:for:, with the following differences:\x0a\x09- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`\x0a\x09- instead of evaluating against a receiver, evaluate in the context of `aContext`\x22\x0a\x0a\x09| compiler ast |\x0a\x09\x0a\x09compiler := Compiler new.\x0a\x09[ ast := compiler parseExpression: aString ] \x0a\x09\x09on: Error \x0a\x09\x09do: [ :ex | ^ Terminal alert: ex messageText ].\x0a\x09\x09\x0a\x09(AISemanticAnalyzer on: aContext receiver class)\x0a\x09\x09context: aContext;\x0a\x09\x09visit: ast.\x0a\x0a\x09^ aContext evaluateNode: ast",
-referencedClasses: ["Compiler", "Error", "Terminal", "AISemanticAnalyzer"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["new", "on:do:", "parseExpression:", "alert:", "messageText", "context:", "on:", "class", "receiver", "visit:", "evaluateNode:"]
-}, function ($methodClass){ return function (aString,aContext){
-var self=this,$self=this;
-var compiler,ast;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1;
-var $early={};
-try {
-compiler=$recv($globals.Compiler)._new();
-$recv((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-ast=$recv(compiler)._parseExpression_(aString);
-return ast;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}))._on_do_($globals.Error,(function(ex){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-throw $early=[$recv($globals.Terminal)._alert_($recv(ex)._messageText())];
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
-$1=$recv($globals.AISemanticAnalyzer)._on_($recv($recv(aContext)._receiver())._class());
-$recv($1)._context_(aContext);
-$recv($1)._visit_(ast);
-return $recv(aContext)._evaluateNode_(ast);
-}
-catch(e) {if(e===$early)return e[0]; throw e}
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"evaluate:context:",{aString:aString,aContext:aContext,compiler:compiler,ast:ast})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.Evaluator);
-
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "evaluate:for:",
 selector: "evaluate:for:",
@@ -1539,6 +1513,89 @@ $core.addClass("ParseError", $globals.Error, [], "Compiler-Core");
 $globals.ParseError.comment="Instance of ParseError are signaled on any parsing error.\x0aSee `Compiler >> #parse:`";
 $globals.ParseError.comment="Instance of ParseError are signaled on any parsing error.\x0aSee `Compiler >> #parse:`";
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 
 
+
+$core.addTrait("TPragmator", "Compiler-Core");
+$core.addMethod(
+$core.method({
+selector: "canProcessPragma:",
+protocol: "pragma processing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aMessage"],
+source: "canProcessPragma: aMessage\x0a\x09^ self class includesSelector: aMessage selector",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["includesSelector:", "class", "selector"]
+}, function ($methodClass){ return function (aMessage){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($self._class())._includesSelector_($recv(aMessage)._selector());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"canProcessPragma:",{aMessage:aMessage})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TPragmator);
+
+$core.addMethod(
+$core.method({
+selector: "processPragma:",
+protocol: "pragma processing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aMessage"],
+source: "processPragma: aMessage\x0a\x09(self canProcessPragma: aMessage) ifTrue: [\x0a\x09\x09^ aMessage sendTo: self ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["ifTrue:", "canProcessPragma:", "sendTo:"]
+}, function ($methodClass){ return function (aMessage){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+if($core.assert($self._canProcessPragma_(aMessage))){
+return $recv(aMessage)._sendTo_(self);
+}
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"processPragma:",{aMessage:aMessage})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TPragmator);
+
+$core.addMethod(
+$core.method({
+selector: "processPragmas:",
+protocol: "pragma processing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aCollection"],
+source: "processPragmas: aCollection\x0a\x09aCollection do: [ :each | self processPragma: each ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["do:", "processPragma:"]
+}, function ($methodClass){ return function (aCollection){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv(aCollection)._do_((function(each){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._processPragma_(each);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"processPragmas:",{aCollection:aCollection})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TPragmator);
+
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "asVariableName",
 selector: "asVariableName",
@@ -1555,9 +1612,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($recv($globals.Smalltalk)._reservedWords())._includes_(self);
-if($core.assert($1)){
+if($core.assert($recv($recv($globals.Smalltalk)._reservedWords())._includes_(self))){
 return $self.__comma("_");
 return $self.__comma("_");
 } else {
 } else {
 return self;
 return self;

+ 66 - 52
lang/src/Compiler-Core.st

@@ -54,19 +54,42 @@ transformersDictionary
 	self subclassResponsibility
 	self subclassResponsibility
 ! !
 ! !
 
 
-AbstractCodeGenerator subclass: #CodeGenerator
+AbstractCodeGenerator subclass: #AstGenerator
 	slots: {#transformersDictionary}
 	slots: {#transformersDictionary}
 	package: 'Compiler-Core'!
 	package: 'Compiler-Core'!
+!AstGenerator commentStamp!
+I am a very basic code generator.
+I generate semantically augmented abstract syntax tree,
+Some initial pragmas (eg. #inlineJS:) are applied to transform the tree.!
+
+!AstGenerator methodsFor: 'compiling'!
+
+semanticAnalyzer
+	^ (SemanticAnalyzer on: self currentClass)
+		thePackage: self currentPackage;
+		yourself
+!
+
+semanticAstPragmator
+	^ AstSemanticPragmator new
+!
+
+transformersDictionary
+	^ transformersDictionary ifNil: [ transformersDictionary := Dictionary new
+		at: '2000-semantic' put: self semanticAnalyzer;
+		at: '2500-semanticPragmas' put: self semanticAstPragmator;
+		yourself ]
+! !
+
+AstGenerator subclass: #CodeGenerator
+	slots: {}
+	package: 'Compiler-Core'!
 !CodeGenerator commentStamp!
 !CodeGenerator commentStamp!
-I am a basic code generator. I generate a valid JavaScript output, but no not perform any inlining.
+I am a basic code generator. I generate a valid JavaScript output, but do not perform any inlining.
 See `InliningCodeGenerator` for an optimized JavaScript code generation.!
 See `InliningCodeGenerator` for an optimized JavaScript code generation.!
 
 
 !CodeGenerator methodsFor: 'compiling'!
 !CodeGenerator methodsFor: 'compiling'!
 
 
-earlyAstPragmator
-	^ AstEarlyPragmator new
-!
-
 irTranslator
 irTranslator
 	^ self irTranslatorClass new
 	^ self irTranslatorClass new
 		currentClass: self currentClass;
 		currentClass: self currentClass;
@@ -81,19 +104,11 @@ lateIRPragmator
 	^ IRLatePragmator new
 	^ IRLatePragmator new
 !
 !
 
 
-semanticAnalyzer
-	^ (SemanticAnalyzer on: self currentClass)
-		thePackage: self currentPackage;
-		yourself
-!
-
 transformersDictionary
 transformersDictionary
-	^ transformersDictionary ifNil: [ transformersDictionary := Dictionary new
-		at: '1000-earlyPragmas' put: self earlyAstPragmator;
-		at: '2000-semantic' put: self semanticAnalyzer;
+	^ transformersDictionary ifNil: [ transformersDictionary := super transformersDictionary
 		at: '5000-astToIr' put: self translator;
 		at: '5000-astToIr' put: self translator;
+		at: '7000-irLatePragmas' put: self lateIRPragmator;
 		at: '8000-irToJs' put: self irTranslator;
 		at: '8000-irToJs' put: self irTranslator;
-		at: '9000-latePragmas' put: self lateIRPragmator;
 		yourself ]
 		yourself ]
 !
 !
 
 
@@ -146,25 +161,25 @@ currentPackage: anObject
 !Compiler methodsFor: 'compiling'!
 !Compiler methodsFor: 'compiling'!
 
 
 ast: aString forClass: aClass protocol: anotherString
 ast: aString forClass: aClass protocol: anotherString
-	self
+	^ self
+		codeGeneratorClass: AstGenerator;
 		start: aString forClass: aClass protocol: anotherString;
 		start: aString forClass: aClass protocol: anotherString;
-		transformerAt: '2500-astCheckpoint' put: [ :x | ^x ];
-		compileNode: (self parse: aString);
-		error: 'AST transformation failed.'
+		compileNode: (self parse: aString)
 !
 !
 
 
 compile: aString forClass: aClass protocol: anotherString
 compile: aString forClass: aClass protocol: anotherString
-	| compilationResult result pragmas closureFactory |
+	| sanitizedSource compilationResult result pragmas closureFactory |
+	sanitizedSource := aString crlfSanitized.
 	compilationResult := self
 	compilationResult := self
-		start: aString forClass: aClass protocol: anotherString;
-		compileNode: (self parse: aString).
+		start: sanitizedSource forClass: aClass protocol: anotherString;
+		compileNode: (self parse: sanitizedSource).
 	closureFactory := self
 	closureFactory := self
 		eval: (self wrappedSourceOf: compilationResult)
 		eval: (self wrappedSourceOf: compilationResult)
 		forPackage: self currentPackage.
 		forPackage: self currentPackage.
 	result := Smalltalk core method: #{
 	result := Smalltalk core method: #{
 		#selector -> compilationResult selector.
 		#selector -> compilationResult selector.
 		#protocol -> anotherString.
 		#protocol -> anotherString.
-		#source -> aString.
+		#source -> sanitizedSource.
 		#messageSends -> compilationResult messageSends asArray.
 		#messageSends -> compilationResult messageSends asArray.
 		#args -> compilationResult arguments.
 		#args -> compilationResult arguments.
 		#referencedClasses -> compilationResult classReferences asArray.
 		#referencedClasses -> compilationResult classReferences asArray.
@@ -276,8 +291,8 @@ parseError: anException parsing: aString
 		ifNotNil: [ :loc |
 		ifNotNil: [ :loc |
 			^ ParseError new 
 			^ ParseError new 
 				messageText: 
 				messageText: 
-					'Parse error on line ', loc start line ,
-					' column ' , loc start column ,
+					'Parse error on line ', loc start line asString,
+					' column ' , loc start column asString,
 					' : Unexpected character ', (anException basicAt: 'found');
 					' : Unexpected character ', (anException basicAt: 'found');
 				yourself ]
 				yourself ]
 ! !
 ! !
@@ -289,17 +304,17 @@ basicParse: aString
 !
 !
 
 
 wrappedSourceOf: anIRMethod
 wrappedSourceOf: anIRMethod
-	anIRMethod attachments
-		ifEmpty: [ ^
+	^ anIRMethod attachments
+		ifEmpty: [
 			'(function ($methodClass){ return ',
 			'(function ($methodClass){ return ',
 			anIRMethod compiledSource,
 			anIRMethod compiledSource,
 			'; })' ]
 			'; })' ]
-		ifNotEmpty: [ :attachments | ^ 
-			'(function ($methodClass){ return (function(method){Object.defineProperty(method,"a$atx",{enumerable:false,configurable:true,writable:true,value:',
-			attachments asJavaScriptSource,
-			'});return method})(',
+		ifNotEmpty: [ :attachments |
+			'(function ($methodClass){ return Object.defineProperty(',
 			anIRMethod compiledSource,
 			anIRMethod compiledSource,
-			'); })' ]
+			',"a$atx",{enumerable:false,configurable:true,writable:true,value:',
+			attachments asJavaScriptSource,
+			'}); })' ]
 ! !
 ! !
 
 
 !Compiler class methodsFor: 'compiling'!
 !Compiler class methodsFor: 'compiling'!
@@ -350,25 +365,6 @@ I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
 
 
 !Evaluator methodsFor: 'evaluating'!
 !Evaluator methodsFor: 'evaluating'!
 
 
-evaluate: aString context: aContext
-	"Similar to #evaluate:for:, with the following differences:
-	- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
-	- instead of evaluating against a receiver, evaluate in the context of `aContext`"
-
-	| compiler ast |
-	
-	compiler := Compiler new.
-	[ ast := compiler parseExpression: aString ] 
-		on: Error 
-		do: [ :ex | ^ Terminal alert: ex messageText ].
-		
-	(AISemanticAnalyzer on: aContext receiver class)
-		context: aContext;
-		visit: ast.
-
-	^ aContext evaluateNode: ast
-!
-
 evaluate: aString for: anObject
 evaluate: aString for: anObject
 	^ anObject evaluate: aString on: self
 	^ anObject evaluate: aString on: self
 !
 !
@@ -397,6 +393,24 @@ Error subclass: #ParseError
 Instance of ParseError are signaled on any parsing error.
 Instance of ParseError are signaled on any parsing error.
 See `Compiler >> #parse:`!
 See `Compiler >> #parse:`!
 
 
+Trait named: #TPragmator
+	package: 'Compiler-Core'!
+
+!TPragmator methodsFor: 'pragma processing'!
+
+canProcessPragma: aMessage
+	^ self class includesSelector: aMessage selector
+!
+
+processPragma: aMessage
+	(self canProcessPragma: aMessage) ifTrue: [
+		^ aMessage sendTo: self ]
+!
+
+processPragmas: aCollection
+	aCollection do: [ :each | self processPragma: each ]
+! !
+
 !String methodsFor: '*Compiler-Core'!
 !String methodsFor: '*Compiler-Core'!
 
 
 asVariableName
 asVariableName

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 307 - 346
lang/src/Compiler-IR.js


+ 248 - 180
lang/src/Compiler-IR.st

@@ -1,6 +1,6 @@
 Smalltalk createPackage: 'Compiler-IR'!
 Smalltalk createPackage: 'Compiler-IR'!
 NodeVisitor subclass: #IRASTTranslator
 NodeVisitor subclass: #IRASTTranslator
-	slots: {#source. #theClass. #method. #sequence. #nextAlias}
+	slots: {#source. #theClass. #method. #sequence}
 	package: 'Compiler-IR'!
 	package: 'Compiler-IR'!
 !IRASTTranslator commentStamp!
 !IRASTTranslator commentStamp!
 I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.!
 I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.!
@@ -15,12 +15,6 @@ method: anIRMethod
 	method := anIRMethod
 	method := anIRMethod
 !
 !
 
 
-nextAlias
-	nextAlias ifNil: [ nextAlias := 0 ].
-	nextAlias := nextAlias + 1.
-	^ nextAlias asString
-!
-
 sequence
 sequence
 	^ sequence
 	^ sequence
 !
 !
@@ -63,23 +57,15 @@ addToSequence: anInstruction
 	^ anInstruction
 	^ anInstruction
 !
 !
 
 
-alias: aNode
-	| variable |
-
-	aNode isImmutable ifTrue: [ ^ self visit: aNode ].
+alias: anExpressionNode
+	| assignment |
 
 
-	variable := IRVariable new
-		variable: (AliasVar new name: '$', self nextAlias);
-		yourself.
-
-	self addToSequence: (IRAssignment new
-		add: variable;
-		add: (self visit: aNode);
-		yourself).
+	anExpressionNode isIdempotent ifTrue: [ ^ self visit: anExpressionNode ].
 
 
-	self method internalVariables add: variable.
+	assignment := self method newAliasingOf: (self visit: anExpressionNode).
+	self addToSequence: assignment.
 
 
-	^ variable
+	^ assignment left
 !
 !
 
 
 aliasTemporally: aCollection
 aliasTemporally: aCollection
@@ -89,20 +75,22 @@ aliasTemporally: aCollection
 	The tree is iterated twice. First we get the aliasing dependency,
 	The tree is iterated twice. First we get the aliasing dependency,
 	then the aliasing itself is done"
 	then the aliasing itself is done"
 
 
-	| threshold result |
-	threshold := 0.
-	
-	aCollection withIndexDo: [ :each :i |
-		each subtreeNeedsAliasing
-			ifTrue: [ threshold := i ] ].
-
-	result := OrderedCollection new.
-	aCollection withIndexDo: [ :each :i |
-		result add: (i <= threshold
-			ifTrue: [ self alias: each ]
-			ifFalse: [ self visit: each ]) ].
+	| threshold shouldAlias |
+	shouldAlias := false.
+	threshold := aCollection reversed
+		detect: [ :each |
+			shouldAlias ifTrue: [ true ] ifFalse: [
+				each shouldBeAliased ifTrue: [ true ] ifFalse: [
+					(each hasOpeningStatements ifTrue: [ true ] ifFalse: [ each subtreeNeedsAliasing ]) ifTrue: [ shouldAlias := true ].
+					false ] ] ]
+		ifNone: [ nil ].
+	threshold ifNil: [ ^ self visitAll: aCollection ].
 
 
-	^ result
+	shouldAlias := true.
+	^ aCollection collect: [ :each |
+		shouldAlias
+			ifTrue: [ each == threshold ifTrue: [ shouldAlias := false ]. self alias: each ]
+			ifFalse: [ self visit: each ] ]
 !
 !
 
 
 visitAssignmentNode: aNode
 visitAssignmentNode: aNode
@@ -128,7 +116,7 @@ visitBlockNode: aNode
 			name: each name;
 			name: each name;
 			scope: aNode scope;
 			scope: aNode scope;
 			yourself) ].
 			yourself) ].
-	aNode dagChildren do: [ :each | closure add: (self visit: each) ].
+	closure add: (self visit: aNode sequenceNode).
 	^ closure
 	^ closure
 !
 !
 
 
@@ -138,16 +126,16 @@ visitBlockSequenceNode: aNode
 		do: [
 		do: [
 			aNode dagChildren ifNotEmpty: [
 			aNode dagChildren ifNotEmpty: [
 				aNode dagChildren allButLast do: [ :each |
 				aNode dagChildren allButLast do: [ :each |
-					self addToSequence: (self visitOrAlias: each) ].
+					self addToSequence: (self visit: each) ].
 				aNode dagChildren last isReturnNode
 				aNode dagChildren last isReturnNode
-					ifFalse: [ self addToSequence: (IRBlockReturn new add: (self visitOrAlias: aNode dagChildren last); yourself) ]
-					ifTrue: [ self addToSequence: (self visitOrAlias: aNode dagChildren last) ] ]]
+					ifFalse: [ self addToSequence: (IRBlockReturn new add: (self visit: aNode dagChildren last); yourself) ]
+					ifTrue: [ self addToSequence: (self visit: aNode dagChildren last) ] ]]
 !
 !
 
 
 visitCascadeNode: aNode
 visitCascadeNode: aNode
 	| receiver |
 	| receiver |
 	receiver := aNode receiver.
 	receiver := aNode receiver.
-	receiver isImmutable ifFalse: [
+	receiver isIdempotent ifFalse: [
 		| alias |
 		| alias |
 		alias := self alias: receiver.
 		alias := self alias: receiver.
 		receiver := VariableNode new binding: alias variable ].
 		receiver := VariableNode new binding: alias variable ].
@@ -156,7 +144,7 @@ visitCascadeNode: aNode
 	aNode dagChildren allButLast do: [ :each |
 	aNode dagChildren allButLast do: [ :each |
 		self addToSequence: (self visit: each) ].
 		self addToSequence: (self visit: each) ].
 
 
-	^ self visitOrAlias: aNode dagChildren last
+	^ self visit: aNode dagChildren last
 !
 !
 
 
 visitDynamicArrayNode: aNode
 visitDynamicArrayNode: aNode
@@ -180,9 +168,10 @@ visitJSStatementNode: aNode
 !
 !
 
 
 visitMethodNode: aNode
 visitMethodNode: aNode
+	| irSequence |
 
 
 	self method: (IRMethod new
 	self method: (IRMethod new
-		source: self source crlfSanitized;
+		source: self source;
 		pragmas: (aNode pragmas collect: [ :each |
 		pragmas: (aNode pragmas collect: [ :each |
 			Message
 			Message
 				selector: each selector
 				selector: each selector
@@ -203,34 +192,25 @@ visitMethodNode: aNode
 			scope: aNode scope;
 			scope: aNode scope;
 			yourself) ].
 			yourself) ].
 
 
-	self method dagChildren addAll: (self visitAllChildren: aNode).
+	self method add: (irSequence := self visit: aNode sequenceNode).
 
 
-	aNode scope hasLocalReturn ifFalse: [self method
+	aNode scope hasLocalReturn ifFalse: [ irSequence
 		add: (IRReturn new
 		add: (IRReturn new
 			add: (IRVariable new
 			add: (IRVariable new
 				variable: (aNode scope pseudoVars at: 'self');
 				variable: (aNode scope pseudoVars at: 'self');
 				yourself);
 				yourself);
-			yourself);
-		add: (IRVerbatim new source: ';', String lf; yourself) ].
+			yourself) ].
 
 
 	^ self method
 	^ self method
 !
 !
 
 
-visitOrAlias: aNode
-	^ aNode shouldBeAliased
-		ifTrue: [ self alias: aNode ]
-		ifFalse: [ self visit: aNode ]
-!
-
 visitReturnNode: aNode
 visitReturnNode: aNode
-	| return |
-	return := aNode nonLocalReturn
+	^ (aNode nonLocalReturn
 		ifTrue: [ IRNonLocalReturn new ]
 		ifTrue: [ IRNonLocalReturn new ]
-		ifFalse: [ IRReturn new ].
-	return scope: aNode scope.
-	aNode dagChildren do: [ :each |
-		return add: (self visitOrAlias: each) ].
-	^ return
+		ifFalse: [ IRReturn new ])
+		scope: aNode scope;
+		add: (self visit: aNode expression);
+		yourself
 !
 !
 
 
 visitSendNode: aNode
 visitSendNode: aNode
@@ -238,6 +218,8 @@ visitSendNode: aNode
 	send := IRSend new.
 	send := IRSend new.
 	send
 	send
 		selector: aNode selector;
 		selector: aNode selector;
+		javaScriptSelector: aNode javaScriptSelector;
+		argumentSwitcher: aNode argumentSwitcher;
 		index: aNode index.
 		index: aNode index.
 	
 	
 	(self aliasTemporally: aNode dagChildren) do: [ :each | send add: each ].
 	(self aliasTemporally: aNode dagChildren) do: [ :each | send add: each ].
@@ -249,7 +231,7 @@ visitSequenceNode: aNode
 	^ self
 	^ self
 		withSequence: IRSequence new
 		withSequence: IRSequence new
 		do: [ aNode dagChildren do: [ :each |
 		do: [ aNode dagChildren do: [ :each |
-			self addToSequence: (self visitOrAlias: each) ] ]
+			self addToSequence: (self visit: each) ] ]
 !
 !
 
 
 visitValueNode: aNode
 visitValueNode: aNode
@@ -264,6 +246,26 @@ visitVariableNode: aNode
 		yourself
 		yourself
 ! !
 ! !
 
 
+Object subclass: #IRAliasFactory
+	slots: {#counter}
+	package: 'Compiler-IR'!
+
+!IRAliasFactory methodsFor: 'accessing'!
+
+next
+	counter := counter + 1.
+	^ AliasVar new
+		name: '$', counter asString;
+		yourself
+! !
+
+!IRAliasFactory methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	counter := 0
+! !
+
 DagParentNode subclass: #IRInstruction
 DagParentNode subclass: #IRInstruction
 	slots: {#parent}
 	slots: {#parent}
 	package: 'Compiler-IR'!
 	package: 'Compiler-IR'!
@@ -311,6 +313,14 @@ replaceWith: anIRInstruction
 	self parent replace: self with: anIRInstruction
 	self parent replace: self with: anIRInstruction
 ! !
 ! !
 
 
+!IRInstruction methodsFor: 'converting'!
+
+asReceiver
+	"Return customized form to act as receiver.
+	Return self to use standard $recv(...) boxing."
+	^ nil
+! !
+
 !IRInstruction methodsFor: 'testing'!
 !IRInstruction methodsFor: 'testing'!
 
 
 isClosure
 isClosure
@@ -325,10 +335,6 @@ isMethod
 	^ false
 	^ false
 !
 !
 
 
-isSelf
-	^ false
-!
-
 isSend
 isSend
 	^ false
 	^ false
 !
 !
@@ -350,7 +356,8 @@ isVariable
 !
 !
 
 
 needsBoxingAsReceiver
 needsBoxingAsReceiver
-	^ true
+	self deprecatedAPI: 'Use asReceiver isNil instead.'.
+	^ self asReceiver isNil
 !
 !
 
 
 yieldsValue
 yieldsValue
@@ -434,9 +441,7 @@ arguments: aCollection
 !
 !
 
 
 locals
 locals
-	^ self arguments copy
-		addAll: (self tempDeclarations collect: [ :each | each name ]);
-		yourself
+	^ self arguments, (self tempDeclarations collect: [ :each | each name ])
 !
 !
 
 
 requiresSmalltalkContext
 requiresSmalltalkContext
@@ -480,13 +485,17 @@ acceptDagVisitor: aVisitor
 ! !
 ! !
 
 
 IRClosureInstruction subclass: #IRMethod
 IRClosureInstruction subclass: #IRMethod
-	slots: {#theClass. #source. #compiledSource. #attachments. #selector. #pragmas. #classReferences. #sendIndexes. #internalVariables}
+	slots: {#theClass. #source. #compiledSource. #attachments. #selector. #pragmas. #classReferences. #sendIndexes. #internalVariables. #aliasFactory}
 	package: 'Compiler-IR'!
 	package: 'Compiler-IR'!
 !IRMethod commentStamp!
 !IRMethod commentStamp!
 I am a method instruction!
 I am a method instruction!
 
 
 !IRMethod methodsFor: 'accessing'!
 !IRMethod methodsFor: 'accessing'!
 
 
+aliasFactory
+	^ aliasFactory ifNil: [ aliasFactory := IRAliasFactory new ]
+!
+
 attachments
 attachments
 	^ attachments ifNil: [ attachments := #{} ]
 	^ attachments ifNil: [ attachments := #{} ]
 !
 !
@@ -519,6 +528,21 @@ method
 	^ self
 	^ self
 !
 !
 
 
+newAliasingOf: anIRInstruction
+	| variable |
+
+	variable := IRVariable new
+		variable: self aliasFactory next;
+		yourself.
+
+	self internalVariables add: variable.
+
+	^ IRAssignment new
+		add: variable;
+		add: anIRInstruction;
+		yourself
+!
+
 pragmas
 pragmas
 	^ pragmas
 	^ pragmas
 !
 !
@@ -653,13 +677,21 @@ acceptDagVisitor: aVisitor
 ! !
 ! !
 
 
 IRInstruction subclass: #IRSend
 IRInstruction subclass: #IRSend
-	slots: {#selector. #javaScriptSelector. #index}
+	slots: {#selector. #javaScriptSelector. #argumentSwitcher. #index}
 	package: 'Compiler-IR'!
 	package: 'Compiler-IR'!
 !IRSend commentStamp!
 !IRSend commentStamp!
 I am a message send instruction.!
 I am a message send instruction.!
 
 
 !IRSend methodsFor: 'accessing'!
 !IRSend methodsFor: 'accessing'!
 
 
+argumentSwitcher
+	^ argumentSwitcher
+!
+
+argumentSwitcher: aJSFunction
+	argumentSwitcher := aJSFunction
+!
+
 arguments
 arguments
 	^ self dagChildren allButFirst
 	^ self dagChildren allButFirst
 !
 !
@@ -746,10 +778,10 @@ value: aString
 	value := aString
 	value := aString
 ! !
 ! !
 
 
-!IRValue methodsFor: 'testing'!
+!IRValue methodsFor: 'converting'!
 
 
-needsBoxingAsReceiver
-	^ false
+asReceiver
+	^ self
 ! !
 ! !
 
 
 !IRValue methodsFor: 'visiting'!
 !IRValue methodsFor: 'visiting'!
@@ -774,11 +806,17 @@ variable: aScopeVariable
 	variable := aScopeVariable
 	variable := aScopeVariable
 ! !
 ! !
 
 
-!IRVariable methodsFor: 'testing'!
+!IRVariable methodsFor: 'converting'!
 
 
-isSelf
-	^ self variable isSelf
-!
+asReceiver
+	self variable asReceiver
+		ifNil: [ ^ super asReceiver ]
+		ifNotNil: [ :receiverVar |
+			self variable == receiverVar ifTrue: [ ^ self ].
+			^ self copy variable: receiverVar; yourself ]
+! !
+
+!IRVariable methodsFor: 'testing'!
 
 
 isSuper
 isSuper
 	^ self variable isSuper
 	^ self variable isSuper
@@ -786,10 +824,6 @@ isSuper
 
 
 isVariable
 isVariable
 	^ true
 	^ true
-!
-
-needsBoxingAsReceiver
-	^ self variable isPseudoVar not
 ! !
 ! !
 
 
 !IRVariable methodsFor: 'visiting'!
 !IRVariable methodsFor: 'visiting'!
@@ -847,11 +881,28 @@ IRPragmator subclass: #IRLatePragmator
 !IRLatePragmator methodsFor: 'pragmas'!
 !IRLatePragmator methodsFor: 'pragmas'!
 
 
 jsOverride: aString
 jsOverride: aString
+	self irMethod arguments ifNotEmpty: [
+		CompilerError signal: 'Must use <jsOverride:> in unary method.' ].
 	self irMethod attachments
 	self irMethod attachments
 		at: aString
 		at: aString
 		put: (NativeFunction
 		put: (NativeFunction
 			constructorNamed: #Function
 			constructorNamed: #Function
 			value: 'return this.', irMethod selector asJavaScriptMethodName, '()')
 			value: 'return this.', irMethod selector asJavaScriptMethodName, '()')
+!
+
+jsOverride: aString args: aCollection
+	| myArgs |
+	myArgs := self irMethod arguments.
+	myArgs size = aCollection size ifFalse: [
+		CompilerError signal: 'Should have ', self irMethod arguments size asString, ' args in <jsOverride:args:>.' ].
+	myArgs asSet = aCollection asSet ifFalse: [
+		CompilerError signal: 'Argument mismatch in <jsOverride:args:>.' ].
+	self irMethod attachments
+		at: aString
+		put: (NativeFunction
+			constructorNamed: #Function
+			value: (',' join: aCollection)
+			value: 'return this.', irMethod selector asJavaScriptMethodName, '(', (',' join: myArgs), ')')
 ! !
 ! !
 
 
 ParentFakingPathDagVisitor subclass: #IRVisitor
 ParentFakingPathDagVisitor subclass: #IRVisitor
@@ -888,14 +939,6 @@ visitIRDynamicDictionary: anIRDynamicDictionary
 	^ self visitDagNode: anIRDynamicDictionary
 	^ self visitDagNode: anIRDynamicDictionary
 !
 !
 
 
-visitIRInlinedClosure: anIRInlinedClosure
-	^ self visitIRClosure: anIRInlinedClosure
-!
-
-visitIRInlinedSequence: anIRInlinedSequence
-	^ self visitIRSequence: anIRInlinedSequence
-!
-
 visitIRMethod: anIRMethod
 visitIRMethod: anIRMethod
 	^ self visitDagNode: anIRMethod
 	^ self visitDagNode: anIRMethod
 !
 !
@@ -1031,15 +1074,25 @@ visitIRReturn: anIRReturn
 !
 !
 
 
 visitIRSend: anIRSend
 visitIRSend: anIRSend
-	| sends superclass |
-	sends := (anIRSend method sendIndexes at: anIRSend selector) size.
+	| prefixes suffixes workBlock |
+	prefixes := #().
+	suffixes := #().
+	workBlock := [ self visitSend: anIRSend ].
 	
 	
-	anIRSend receiver isSuper
-		ifTrue: [ self visitSuperSend: anIRSend ]
-		ifFalse: [ self visitSend: anIRSend ].
-		
-	anIRSend index < sends
-		ifTrue: [ self stream nextPutSendIndexFor: anIRSend ]
+	anIRSend index < (anIRSend method sendIndexes at: anIRSend selector) size ifTrue: [
+		suffixes add:
+			anIRSend scope alias,
+			'.sendIdx[',
+			anIRSend selector asJavaScriptSource,
+			']=',
+			anIRSend index asString ].
+	
+	anIRSend receiver isSuper ifTrue: [
+		prefixes add: anIRSend scope alias, '.supercall = true'.
+		suffixes add: anIRSend scope alias, '.supercall = false'.
+		workBlock := [ self visitSuperSend: anIRSend ] ].
+
+	self stream nextPutBefore: prefixes after: suffixes with: workBlock
 !
 !
 
 
 visitIRSequence: anIRSequence
 visitIRSequence: anIRSequence
@@ -1074,19 +1127,12 @@ visitInstructionList: anArray enclosedBetween: aString and: anotherString
 !
 !
 
 
 visitReceiver: anIRInstruction
 visitReceiver: anIRInstruction
-	| instr |
-
-	anIRInstruction isSelf
-		ifTrue: [ instr := anIRInstruction copy
-			variable: (anIRInstruction variable copy name: '$self'; yourself);
-			yourself ]
-		ifFalse: [ instr := anIRInstruction ].
-	
-	instr needsBoxingAsReceiver ifFalse: [ ^ self visit: instr ].
-	
-	self stream nextPutAll: '$recv('.
-	self visit: instr.
-	self stream nextPutAll: ')'
+	anIRInstruction asReceiver
+		ifNotNil: [ :instr | self visit: instr ]
+		ifNil: [
+			self stream nextPutAll: '$recv('.
+			self visit: anIRInstruction.
+			self stream nextPutAll: ')' ]
 !
 !
 
 
 visitSend: anIRSend
 visitSend: anIRSend
@@ -1098,13 +1144,29 @@ visitSend: anIRSend
 !
 !
 
 
 visitSuperSend: anIRSend
 visitSuperSend: anIRSend
-	self stream nextPutSupercallFor: anIRSend with: [
-		self stream
-			nextPutAll: anIRSend receiver variable lookupAsJavaScriptSource, '.';
-			nextPutAll: anIRSend javaScriptSelector, '.call'.
-		self
-			visitInstructionList: {anIRSend receiver}, anIRSend arguments
-			enclosedBetween: '(' and: ')' ]
+	self stream
+		nextPutAll: anIRSend receiver variable lookupAsJavaScriptSource, '.';
+		nextPutAll: anIRSend javaScriptSelector.
+	anIRSend arguments
+		ifEmpty: [
+			self stream nextPutAll: '.call('.
+			self visitReceiver: anIRSend receiver.
+			self stream nextPutAll: ')' ]
+		ifNotEmpty: [
+			anIRSend argumentSwitcher
+				ifNil: [
+					self stream nextPutAll: '.call('.
+					self visitReceiver: anIRSend receiver.
+					self
+						visitInstructionList: anIRSend arguments
+						enclosedBetween: ',' and: ')' ]
+				ifNotNil: [ :switcher |
+					self stream nextPutAll: '.apply('.
+					self visitReceiver: anIRSend receiver.
+					self
+						visitInstructionList: anIRSend arguments
+						enclosedBetween: ',(', switcher asJavaScriptSource, ')('
+						and: '))' ] ]
 ! !
 ! !
 
 
 Object subclass: #JSStream
 Object subclass: #JSStream
@@ -1152,6 +1214,29 @@ nextPutAssignLhs: aBlock rhs: anotherBlock
 	anotherBlock value
 	anotherBlock value
 !
 !
 
 
+nextPutBefore: prefixCollection after: suffixCollection with: aBlock
+	suffixCollection isEmpty
+		ifTrue: [ self nextPutBefore: prefixCollection with: aBlock ]
+		ifFalse: [
+			self
+				nextPutAll: '['; nextPutBefore: prefixCollection with: aBlock; lf;
+				nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);'; lf.
+			suffixCollection do: [ :each | self nextPutAll: ','; nextPutAll: each ].
+			self
+				lf;
+				nextPutAll: '//>>excludeEnd("ctx");'; lf;
+				nextPutAll: '][0]' ]
+!
+
+nextPutBefore: aCollection with: aBlock
+	aCollection isEmpty ifTrue: [ aBlock value ] ifFalse: [
+		self nextPutAll: '('; lf; nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);'; lf.
+		aCollection do: [ :each | self nextPutAll: each; nextPutAll: ',' ].
+		self lf; nextPutAll: '//>>excludeEnd("ctx");'; lf.
+		aBlock value.
+		self nextPutAll: ')' ]
+!
+
 nextPutBlockContextFor: anIRClosure during: aBlock
 nextPutBlockContextFor: anIRClosure during: aBlock
 	anIRClosure requiresSmalltalkContext ifFalse: [ ^ aBlock value ].
 	anIRClosure requiresSmalltalkContext ifFalse: [ ^ aBlock value ].
 	self
 	self
@@ -1280,19 +1365,6 @@ nextPutReturnWith: aBlock
 	aBlock value
 	aBlock value
 !
 !
 
 
-nextPutSendIndexFor: anIRSend
-	self 
-		nextPutAll: ';'; lf;
-		nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);'; lf;
-		nextPutAll: anIRSend scope alias;
-		nextPutAll: '.sendIdx[';
-		nextPutAll: anIRSend selector asJavaScriptSource;
-		nextPutAll: ']=';
-		nextPutAll: anIRSend index asString;
-		nextPutAll: ';'; lf;
-		nextPutAll: '//>>excludeEnd("ctx")'
-!
-
 nextPutStatementWith: aBlock
 nextPutStatementWith: aBlock
 	self omitSemicolon: false.
 	self omitSemicolon: false.
 	aBlock value.
 	aBlock value.
@@ -1301,20 +1373,6 @@ nextPutStatementWith: aBlock
 	stream lf
 	stream lf
 !
 !
 
 
-nextPutSupercallFor: anIRSend with: aBlock
-	self
-		nextPutAll: '('; lf;
-		nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);'; lf;
-		nextPutAll: anIRSend scope alias, '.supercall = true,'; lf;
-		nextPutAll: '//>>excludeEnd("ctx");'; lf.
-	aBlock value.
-	self
-		nextPutAll: ');'; lf;
-		nextPutAll: '//>>excludeStart("ctx", pragmas.excludeDebugContexts);'; lf;
-		nextPutAll: anIRSend scope alias, '.supercall = false;'; lf;
-		nextPutAll: '//>>excludeEnd("ctx");'
-!
-
 nextPutVars: aCollection
 nextPutVars: aCollection
 	aCollection ifNotEmpty: [
 	aCollection ifNotEmpty: [
 		stream nextPutAll: 'var '.
 		stream nextPutAll: 'var '.
@@ -1329,63 +1387,73 @@ IRPragmator setTraitComposition: {TPragmator} asTraitComposition!
 
 
 !ASTNode methodsFor: '*Compiler-IR'!
 !ASTNode methodsFor: '*Compiler-IR'!
 
 
-isReferenced
-	"Answer true if the receiver is referenced by other nodes.
-	Do not take sequences or assignments into account"
+requiresSmalltalkContext
+	"Answer true if the receiver requires a smalltalk context.
+	Only send nodes require a context.
 	
 	
-	self parent isSequenceNode ifTrue: [ ^ false ].
-	self parent isAssignmentNode ifTrue: [ ^ false ].
-	self parent isCascadeNode ifTrue: [ ^ self parent isReferenced ].
+	If no node requires a context, the method will be compiled without one.
+	See `IRJSTranslator` and `JSStream` for context creation"
 	
 	
-	^ true
-!
-
-subtreeNeedsAliasing
-	^ self shouldBeAliased or: [
-		self dagChildren anySatisfy: [ :each | each subtreeNeedsAliasing ] ]
+	^ self dagChildren anySatisfy: [ :each | each requiresSmalltalkContext ]
 ! !
 ! !
 
 
 !AssignmentNode methodsFor: '*Compiler-IR'!
 !AssignmentNode methodsFor: '*Compiler-IR'!
 
 
-shouldBeAliased
-	^ super shouldBeAliased or: [ self isReferenced ]
-! !
-
-!BlockClosure methodsFor: '*Compiler-IR'!
-
-appendToInstruction: anIRInstruction
-	anIRInstruction appendBlock: self
+hasOpeningStatements
+	^ true
 ! !
 ! !
 
 
 !BlockNode methodsFor: '*Compiler-IR'!
 !BlockNode methodsFor: '*Compiler-IR'!
 
 
 subtreeNeedsAliasing
 subtreeNeedsAliasing
-	^ self shouldBeAliased
+	^ false
 ! !
 ! !
 
 
 !CascadeNode methodsFor: '*Compiler-IR'!
 !CascadeNode methodsFor: '*Compiler-IR'!
 
 
-subtreeNeedsAliasing
-	^ self parent isSequenceNode not
+hasOpeningStatements
+	^ true
 ! !
 ! !
 
 
-!SendNode methodsFor: '*Compiler-IR'!
+!ExpressionNode methodsFor: '*Compiler-IR'!
 
 
-shouldBeAliased
-	"Because we keep track of send indexes, some send nodes need additional care for aliasing. 
-	See IRJSVisitor >> visitIRSend:"
-	
-	| sends |
-	
-	sends := (self method sendIndexes at: self selector) size.
-	
-	^ (super shouldBeAliased or: [
-		self isReferenced and: [
-			self index < sends or: [
-				self superSend ] ] ])
+hasOpeningStatements
+	^ false
 !
 !
 
 
 subtreeNeedsAliasing
 subtreeNeedsAliasing
-	^ self shouldBeInlined or: [ super subtreeNeedsAliasing ]
+	^ self dagChildren anySatisfy: [ :each |
+		each shouldBeAliased ifTrue: [ true ] ifFalse: [
+			each hasOpeningStatements ifTrue: [ true ] ifFalse: [
+				each subtreeNeedsAliasing ] ] ]
+! !
+
+!JSStatementNode methodsFor: '*Compiler-IR'!
+
+requiresSmalltalkContext
+	^ true
+! !
+
+!PseudoVar methodsFor: '*Compiler-IR'!
+
+asReceiver
+	^ self class receiverNames
+		at: self name
+		ifPresent: [ :newName | self copy name: newName; yourself ]
+		ifAbsent: [ self ]
+! !
+
+!ScopeVar methodsFor: '*Compiler-IR'!
+
+asReceiver
+	"Return customized copy to use as receiver,
+	or self if suffices."
+	^ nil
+! !
+
+!SendNode methodsFor: '*Compiler-IR'!
+
+requiresSmalltalkContext
+	^ true
 ! !
 ! !
 
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 272 - 340
lang/src/Compiler-Inlining.js


+ 56 - 34
lang/src/Compiler-Inlining.st

@@ -9,9 +9,10 @@ visitSendNode: aNode
 
 
 	aNode superSend ifFalse: [ 
 	aNode superSend ifFalse: [ 
 		(IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [
 		(IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [
-			aNode shouldBeInlined: true.
+			aNode shouldBeAliased: true.
 			aNode receiver ifNotNil: [ :receiver |
 			aNode receiver ifNotNil: [ :receiver |
-				receiver shouldBeAliased: true ] ] ].
+				(IRSendInliner inlinedSelectorsNeedingIdempotentReceiver includes: aNode selector) ifTrue: [
+					receiver shouldBeAliased: true ] ] ] ].
 
 
 	^ super visitSendNode: aNode
 	^ super visitSendNode: aNode
 ! !
 ! !
@@ -79,22 +80,6 @@ IRInlinedSend subclass: #IRInlinedIfNilIfNotNil
 !IRInlinedIfNilIfNotNil commentStamp!
 !IRInlinedIfNilIfNotNil commentStamp!
 I represent an inlined `#ifNil:ifNotNil:` message send instruction.!
 I represent an inlined `#ifNil:ifNotNil:` message send instruction.!
 
 
-!IRInlinedIfNilIfNotNil methodsFor: 'accessing'!
-
-internalVariables
-	^ Array with: self receiverInternalVariable
-!
-
-receiverInternalVariable
-	^ IRVariable new
-		variable: (AliasVar new name: self receiverInternalVariableName);
-		yourself.
-!
-
-receiverInternalVariableName
-	^ '$receiver'
-! !
-
 !IRInlinedIfNilIfNotNil methodsFor: 'visiting'!
 !IRInlinedIfNilIfNotNil methodsFor: 'visiting'!
 
 
 acceptDagVisitor: aVisitor
 acceptDagVisitor: aVisitor
@@ -262,11 +247,10 @@ visitIRInlinedIfFalse: anIRInlinedIfFalse
 visitIRInlinedIfNilIfNotNil: anIRInlinedIfNilIfNotNil
 visitIRInlinedIfNilIfNotNil: anIRInlinedIfNilIfNotNil
 	self stream
 	self stream
 		nextPutIf: [
 		nextPutIf: [
-			| recvVarName |
-			recvVarName := anIRInlinedIfNilIfNotNil receiverInternalVariableName.
-			self stream nextPutAll: '(', recvVarName, ' = '.
 			self visit: anIRInlinedIfNilIfNotNil dagChildren first.
 			self visit: anIRInlinedIfNilIfNotNil dagChildren first.
-			self stream nextPutAll: ') == null || ', recvVarName, '.a$nil' ]
+			self stream nextPutAll: ' == null || '.
+			self visit: anIRInlinedIfNilIfNotNil dagChildren first.
+			self stream nextPutAll: '.a$nil' ]
 		then: [ self visit: anIRInlinedIfNilIfNotNil dagChildren second ]
 		then: [ self visit: anIRInlinedIfNilIfNotNil dagChildren second ]
 		else: [ self visit: anIRInlinedIfNilIfNotNil dagChildren third ]
 		else: [ self visit: anIRInlinedIfNilIfNotNil dagChildren third ]
 !
 !
@@ -332,14 +316,18 @@ inlinedSequence
 !IRSendInliner methodsFor: 'inlining'!
 !IRSendInliner methodsFor: 'inlining'!
 
 
 ifFalse: anIRInstruction
 ifFalse: anIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
 	^ self inlinedSend: IRInlinedIfFalse new withBlock: anIRInstruction
 	^ self inlinedSend: IRInlinedIfFalse new withBlock: anIRInstruction
 !
 !
 
 
 ifFalse: anIRInstruction ifTrue: anotherIRInstruction
 ifFalse: anIRInstruction ifTrue: anotherIRInstruction
-	^ self perform: #ifTrue:ifFalse: withArguments: { anotherIRInstruction. anIRInstruction }
+	self mustBeNiladicClosure: anIRInstruction.
+	self mustBeNiladicClosure: anotherIRInstruction.
+	^ self inlinedSend: IRInlinedIfTrueIfFalse new withBlock: anotherIRInstruction withBlock: anIRInstruction
 !
 !
 
 
 ifNil: anIRInstruction
 ifNil: anIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
 	^ self
 	^ self
 		inlinedSend: IRInlinedIfNilIfNotNil new
 		inlinedSend: IRInlinedIfNilIfNotNil new
 		withBlock: anIRInstruction
 		withBlock: anIRInstruction
@@ -352,10 +340,13 @@ ifNil: anIRInstruction
 !
 !
 
 
 ifNil: anIRInstruction ifNotNil: anotherIRInstruction
 ifNil: anIRInstruction ifNotNil: anotherIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
+	self mustBeNiladicOrUnaryClosure: anotherIRInstruction.
 	^ self inlinedSend: IRInlinedIfNilIfNotNil new withBlock: anIRInstruction withBlock: anotherIRInstruction
 	^ self inlinedSend: IRInlinedIfNilIfNotNil new withBlock: anIRInstruction withBlock: anotherIRInstruction
 !
 !
 
 
 ifNotNil: anIRInstruction
 ifNotNil: anIRInstruction
+	self mustBeNiladicOrUnaryClosure: anIRInstruction.
 	^ self
 	^ self
 		inlinedSend: IRInlinedIfNilIfNotNil new
 		inlinedSend: IRInlinedIfNilIfNotNil new
 		withBlock: (IRClosure new
 		withBlock: (IRClosure new
@@ -368,14 +359,19 @@ ifNotNil: anIRInstruction
 !
 !
 
 
 ifNotNil: anIRInstruction ifNil: anotherIRInstruction
 ifNotNil: anIRInstruction ifNil: anotherIRInstruction
+	self mustBeNiladicOrUnaryClosure: anIRInstruction.
+	self mustBeNiladicClosure: anotherIRInstruction.
 	^ self inlinedSend: IRInlinedIfNilIfNotNil new withBlock: anotherIRInstruction withBlock: anIRInstruction
 	^ self inlinedSend: IRInlinedIfNilIfNotNil new withBlock: anotherIRInstruction withBlock: anIRInstruction
 !
 !
 
 
 ifTrue: anIRInstruction
 ifTrue: anIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
 	^ self inlinedSend: IRInlinedIfTrue new withBlock: anIRInstruction
 	^ self inlinedSend: IRInlinedIfTrue new withBlock: anIRInstruction
 !
 !
 
 
 ifTrue: anIRInstruction ifFalse: anotherIRInstruction
 ifTrue: anIRInstruction ifFalse: anotherIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
+	self mustBeNiladicClosure: anotherIRInstruction.
 	^ self inlinedSend: IRInlinedIfTrueIfFalse new withBlock: anIRInstruction withBlock: anotherIRInstruction
 	^ self inlinedSend: IRInlinedIfTrueIfFalse new withBlock: anIRInstruction withBlock: anotherIRInstruction
 !
 !
 
 
@@ -398,8 +394,8 @@ inlineClosure: anIRClosure
 	anIRClosure arguments do: [ :each |
 	anIRClosure arguments do: [ :each |
 		inlinedClosure add: (IRTempDeclaration new name: each; yourself).
 		inlinedClosure add: (IRTempDeclaration new name: each; yourself).
 		sequence add: (IRAssignment new
 		sequence add: (IRAssignment new
-			add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: each; yourself));
-			add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: '$receiver'; yourself));
+			add: (IRVariable new variable: (ArgVar new scope: inlinedClosure scope; name: each; yourself));
+			add: self send receiver;
 			yourself) ].
 			yourself) ].
 			
 			
 	"To ensure the correct order of the closure instructions: first the temps then the sequence"
 	"To ensure the correct order of the closure instructions: first the temps then the sequence"
@@ -425,15 +421,14 @@ inlineSend: anIRSend
 !
 !
 
 
 inlinedClosure: closure wrapFinalValueIn: aBlock
 inlinedClosure: closure wrapFinalValueIn: aBlock
-	| sequence statements final |
+	| sequence final |
 
 
 	sequence := closure sequence.
 	sequence := closure sequence.
-	statements := sequence dagChildren.
 	
 	
 	sequence dagChildren ifEmpty: [ sequence add: (IRVariable new
 	sequence dagChildren ifEmpty: [ sequence add: (IRVariable new
 		variable: (closure scope pseudoVars at: 'nil');
 		variable: (closure scope pseudoVars at: 'nil');
 		yourself) ].
 		yourself) ].
-	final := statements last.
+	final := sequence dagChildren last.
 	final yieldsValue ifTrue: [ sequence replace: final with: (aBlock value: final) ].
 	final yieldsValue ifTrue: [ sequence replace: final with: (aBlock value: final) ].
 
 
 	^ closure
 	^ closure
@@ -449,9 +444,6 @@ inlineSend: anIRSend andReplace: anIRInstruction
 inlinedSend: inlinedSend withBlock: anIRInstruction
 inlinedSend: inlinedSend withBlock: anIRInstruction
 	| inlinedClosure |
 	| inlinedClosure |
 
 
-	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
-	anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
-
 	inlinedClosure := self translator visit: (self inlineClosure: anIRInstruction).
 	inlinedClosure := self translator visit: (self inlineClosure: anIRInstruction).
 
 
 	inlinedSend
 	inlinedSend
@@ -468,9 +460,6 @@ inlinedSend: inlinedSend withBlock: anIRInstruction
 inlinedSend: inlinedSend withBlock: anIRInstruction withBlock: anotherIRInstruction
 inlinedSend: inlinedSend withBlock: anIRInstruction withBlock: anotherIRInstruction
 	| inlinedClosure1 inlinedClosure2 |
 	| inlinedClosure1 inlinedClosure2 |
 
 
-	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
-	anotherIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
-
 	inlinedClosure1 := self translator visit: (self inlineClosure: anIRInstruction).
 	inlinedClosure1 := self translator visit: (self inlineClosure: anIRInstruction).
 	inlinedClosure2 := self translator visit: (self inlineClosure: anotherIRInstruction).
 	inlinedClosure2 := self translator visit: (self inlineClosure: anotherIRInstruction).
 
 
@@ -486,12 +475,28 @@ inlinedSend: inlinedSend withBlock: anIRInstruction withBlock: anotherIRInstruct
 	^ inlinedSend
 	^ inlinedSend
 ! !
 ! !
 
 
+!IRSendInliner methodsFor: 'testing'!
+
+mustBeNiladicClosure: anIRInstruction
+	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
+	anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ]
+!
+
+mustBeNiladicOrUnaryClosure: anIRInstruction
+	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
+	anIRInstruction arguments size <= 1 ifFalse: [ self inliningError: 'Inlined block should have at most one argument' ]
+! !
+
 !IRSendInliner class methodsFor: 'accessing'!
 !IRSendInliner class methodsFor: 'accessing'!
 
 
 inlinedSelectors
 inlinedSelectors
 	^ #('ifTrue:' 'ifFalse:' 'ifTrue:ifFalse:' 'ifFalse:ifTrue:' 'ifNil:' 'ifNotNil:' 'ifNil:ifNotNil:' 'ifNotNil:ifNil:')
 	^ #('ifTrue:' 'ifFalse:' 'ifTrue:ifFalse:' 'ifFalse:ifTrue:' 'ifNil:' 'ifNotNil:' 'ifNil:ifNotNil:' 'ifNotNil:ifNil:')
 !
 !
 
 
+inlinedSelectorsNeedingIdempotentReceiver
+	^ #('ifNil:' 'ifNotNil:' 'ifNil:ifNotNil:' 'ifNotNil:ifNil:')
+!
+
 shouldInline: anIRSend
 shouldInline: anIRSend
 	(self inlinedSelectors includes: anIRSend selector) ifFalse: [ ^ false ].
 	(self inlinedSelectors includes: anIRSend selector) ifFalse: [ ^ false ].
 	anIRSend receiver isSuper ifTrue: [ ^ false ].
 	anIRSend receiver isSuper ifTrue: [ ^ false ].
@@ -619,6 +624,23 @@ SemanticError subclass: #InliningError
 !InliningError commentStamp!
 !InliningError commentStamp!
 Instances of InliningError are signaled when using an `InliningCodeGenerator`in a `Compiler`.!
 Instances of InliningError are signaled when using an `InliningCodeGenerator`in a `Compiler`.!
 
 
+Trait named: #TIRInlinedVisitor
+	package: 'Compiler-Inlining'!
+
+!TIRInlinedVisitor methodsFor: 'visiting'!
+
+visitIRInlinedClosure: anIRInlinedClosure
+	^ self visitIRClosure: anIRInlinedClosure
+!
+
+visitIRInlinedSequence: anIRInlinedSequence
+	^ self visitIRSequence: anIRInlinedSequence
+! !
+
+IRInliner setTraitComposition: {TIRInlinedVisitor} asTraitComposition!
+IRInliningJSTranslator setTraitComposition: {TIRInlinedVisitor} asTraitComposition!
+! !
+
 !IRBlockReturn methodsFor: '*Compiler-Inlining'!
 !IRBlockReturn methodsFor: '*Compiler-Inlining'!
 
 
 asInlinedBlockResult
 asInlinedBlockResult

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 292 - 227
lang/src/Compiler-Interpreter.js


+ 137 - 40
lang/src/Compiler-Interpreter.st

@@ -60,7 +60,7 @@ valueWithPossibleArguments: aCollection
 	context := outerContext newInnerContext.
 	context := outerContext newInnerContext.
 
 
 	"Interpret a copy of the sequence node to avoid creating a new AIBlockClosure"
 	"Interpret a copy of the sequence node to avoid creating a new AIBlockClosure"
-	sequenceNode := node dagChildren first copy
+	sequenceNode := node sequenceNode copy
 		parent: nil;
 		parent: nil;
 		yourself.
 		yourself.
 		
 		
@@ -372,7 +372,7 @@ lookupContextForLocal: aString ifNone: aBlock
 			self outerContext 
 			self outerContext 
 				ifNil: aBlock
 				ifNil: aBlock
 				ifNotNil: [ :context | 
 				ifNotNil: [ :context | 
-					context lookupContextForLocal: aString ] ]
+					context lookupContextForLocal: aString ifNone: aBlock ] ]
 ! !
 ! !
 
 
 !AIContext methodsFor: 'testing'!
 !AIContext methodsFor: 'testing'!
@@ -409,7 +409,7 @@ context: anAIContext
 
 
 visitVariableNode: aNode
 visitVariableNode: aNode
 	self context 
 	self context 
-		localAt: aNode value 
+		localAt: aNode identifier 
 		ifAbsent: [ ^ super visitVariableNode: aNode ].
 		ifAbsent: [ ^ super visitVariableNode: aNode ].
 
 
 	aNode binding: ASTContextVar new
 	aNode binding: ASTContextVar new
@@ -656,13 +656,12 @@ interpret
 !
 !
 
 
 next
 next
-	| nd nextNode |
+	| nd parent |
 	nd := self node.
 	nd := self node.
-	nextNode := nd parent ifNotNil: [ :parent |
-		(parent nextSiblingNode: nd)
-			ifNil: [ parent ]
-			ifNotNil: [ :sibling | (ASTEnterNode on: self) visit: sibling ] ].
-	self node: nextNode
+	parent := nd parent.
+	(parent ifNotNil: [ parent nextSiblingNode: nd ])
+		ifNil: [ self node: parent ]
+		ifNotNil: [ :sibling | self node: sibling; enterNode ]
 !
 !
 
 
 proceed
 proceed
@@ -702,9 +701,7 @@ stepOver
 !ASTInterpreter methodsFor: 'private'!
 !ASTInterpreter methodsFor: 'private'!
 
 
 assign: aNode to: anObject
 assign: aNode to: anObject
-	aNode binding isInstanceVar
-		ifTrue: [ self context receiver instVarAt: aNode value put: anObject ]
-		ifFalse: [ self context localAt: aNode value put: anObject ]
+	aNode binding inContext: self context put: anObject
 !
 !
 
 
 eval: aString
 eval: aString
@@ -739,13 +736,37 @@ messageNotUnderstood: aMessage receiver: anObject
 		signal
 		signal
 !
 !
 
 
-sendMessage: aMessage to: anObject superSend: aBoolean
-	| method |
+sendJavaScript: aString superMessage: aMessage switcher: aJSFunction to: anObject
+	| methodBlock parent |
 	
 	
-	aBoolean ifFalse: [ ^ aMessage sendTo: anObject ].
-	anObject class superclass ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
+	parent := self context method methodClass superPrototype.
+	parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
 	
 	
-	method := (self context method methodClass superclass lookupSelector: aMessage selector)
+	methodBlock := (parent at: aString)
+		ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
+		
+	^ methodBlock applyTo: anObject arguments: (aJSFunction applyTo: nil arguments: aMessage arguments)
+!
+
+sendJavaScript: aString superMessage: aMessage to: anObject
+	| methodBlock parent |
+	
+	parent := self context method methodClass superPrototype.
+	parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
+	
+	methodBlock := (parent at: aString)
+		ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
+		
+	^ methodBlock applyTo: anObject arguments: aMessage arguments
+!
+
+sendSuperMessage: aMessage to: anObject
+	| method parent |
+	
+	parent := self context method methodClass superclass.
+	parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
+	
+	method := (parent lookupSelector: aMessage selector)
 		ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
 		ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
 		
 		
 	^ method sendTo: anObject arguments: aMessage arguments
 	^ method sendTo: anObject arguments: aMessage arguments
@@ -875,11 +896,16 @@ visitSendNode: aNode
 		messageFromSendNode: aNode
 		messageFromSendNode: aNode
 		arguments: args reversed.
 		arguments: args reversed.
 	
 	
-	result := self sendMessage: message to: receiver superSend: aNode superSend.
+	result := aNode superSend
+		ifFalse: [ message sendTo: receiver ]
+		ifTrue: [ aNode receiver binding isJavaScriptSuper
+			ifFalse: [ self sendSuperMessage: message to: receiver ]
+			ifTrue: [ aNode argumentSwitcher
+				ifNil: [ self sendJavaScript: aNode javaScriptSelector superMessage: message to: receiver ]
+				ifNotNil: [ :switcher | self sendJavaScript: aNode javaScriptSelector superMessage: message switcher: switcher to: receiver ] ] ].
 	
 	
 	"For cascade sends, push the reciever if the send is not the last one"
 	"For cascade sends, push the reciever if the send is not the last one"
-	(aNode isCascadeSendNode and: [ aNode isLastChild not ])
-		ifFalse: [ self pop; push: result ]
+	aNode isSideEffect ifFalse: [ self pop; push: result ]
 !
 !
 
 
 visitValueNode: aNode
 visitValueNode: aNode
@@ -887,19 +913,7 @@ visitValueNode: aNode
 !
 !
 
 
 visitVariableNode: aNode
 visitVariableNode: aNode
-	aNode binding isUnknownVar ifTrue: [
-		^ self push: (Platform globals at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].
-		
-	self push: (aNode binding isInstanceVar
-		ifTrue: [ self context receiver instVarAt: aNode value ]
-		ifFalse: [ self context 
-			localAt: (aNode binding isSuper ifTrue: [ 'self' ] ifFalse: [ aNode value ])
-			ifAbsent: [
-				aNode value isCapitalized
-					ifTrue: [
-						Smalltalk globals 
-							at: aNode value 
-							ifAbsent: [ Platform globals at: aNode value ] ] ] ])
+	self push: (aNode binding inContext: self context)
 ! !
 ! !
 
 
 Error subclass: #ASTInterpreterError
 Error subclass: #ASTInterpreterError
@@ -972,10 +986,6 @@ AIContext setTraitComposition: {TMethodContext} asTraitComposition!
 
 
 !ASTNode methodsFor: '*Compiler-Interpreter'!
 !ASTNode methodsFor: '*Compiler-Interpreter'!
 
 
-isLastChild
-	^ self parent dagChildren last = self
-!
-
 isSteppingNode
 isSteppingNode
 	^ false
 	^ false
 !
 !
@@ -988,6 +998,12 @@ nextSiblingNode: aNode
 		ifAbsent: [ nil ]
 		ifAbsent: [ nil ]
 ! !
 ! !
 
 
+!AliasVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	self error: 'Alias variable is internal, it should never appear in normal variable context.'
+! !
+
 !AssignmentNode methodsFor: '*Compiler-Interpreter'!
 !AssignmentNode methodsFor: '*Compiler-Interpreter'!
 
 
 isSteppingNode
 isSteppingNode
@@ -1008,6 +1024,14 @@ nextSiblingNode: aNode
 	^ nil
 	^ nil
 ! !
 ! !
 
 
+!ClassRefVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ Smalltalk globals 
+		at: self name 
+		ifAbsent: [ Platform globals at: self name ]
+! !
+
 !DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
 !DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
 
 
 isSteppingNode
 isSteppingNode
@@ -1020,19 +1044,92 @@ isSteppingNode
 	^ true
 	^ true
 ! !
 ! !
 
 
+!Evaluator methodsFor: '*Compiler-Interpreter'!
+
+evaluate: aString context: aContext
+	"Similar to #evaluate:for:, with the following differences:
+	- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
+	- instead of evaluating against a receiver, evaluate in the context of `aContext`"
+
+	| compiler ast |
+	
+	compiler := Compiler new.
+	[ ast := compiler parseExpression: aString ] 
+		on: Error 
+		do: [ :ex | ^ Terminal alert: ex messageText ].
+		
+	(AISemanticAnalyzer on: aContext receiver class)
+		context: aContext;
+		visit: ast.
+
+	^ aContext evaluateNode: ast
+! !
+
+!ExternallyKnownVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ Platform globals at: self name ifAbsent: [ self error: 'Unknown variable' ]
+! !
+
+!InstanceVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ aContext receiver instVarNamed: self name
+!
+
+inContext: aContext put: anObject
+	aContext receiver instVarNamed: self name put: anObject
+! !
+
 !JSStatementNode methodsFor: '*Compiler-Interpreter'!
 !JSStatementNode methodsFor: '*Compiler-Interpreter'!
 
 
 isSteppingNode
 isSteppingNode
 	^ true
 	^ true
 ! !
 ! !
 
 
-!SendNode methodsFor: '*Compiler-Interpreter'!
+!JavaScriptSuperVar methodsFor: '*Compiler-Interpreter'!
+
+isJavaScriptSuper
+	^ true
+! !
+
+!PseudoVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ #{'nil'->nil. 'true'->true. 'false'->false}
+		at: self name
+		ifAbsent: [ super inContext: aContext ]
+! !
 
 
-isCascadeSendNode
-	^ self parent isCascadeNode
+!ScopeVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ aContext localAt: self name
 !
 !
 
 
+inContext: aContext put: anObject
+	self error: 'Non-assignable variables should not be changed.'
+! !
+
+!SendNode methodsFor: '*Compiler-Interpreter'!
+
 isSteppingNode
 isSteppingNode
 	^ true
 	^ true
 ! !
 ! !
 
 
+!SuperVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ aContext localAt: 'self'
+!
+
+isJavaScriptSuper
+	^ false
+! !
+
+!TempVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext put: anObject
+	aContext localAt: self name put: anObject
+! !
+

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 414 - 315
lang/src/Compiler-Semantic.js


+ 176 - 141
lang/src/Compiler-Semantic.st

@@ -1,4 +1,75 @@
 Smalltalk createPackage: 'Compiler-Semantic'!
 Smalltalk createPackage: 'Compiler-Semantic'!
+NodeVisitor subclass: #JSSuperSendVisitor
+	slots: {#selector. #arguments. #property. #args}
+	package: 'Compiler-Semantic'!
+
+!JSSuperSendVisitor methodsFor: 'accessing'!
+
+args
+	^ args
+!
+
+args: aCollection
+	args := aCollection
+!
+
+arguments
+	^ arguments
+!
+
+arguments: aCollection
+	arguments := aCollection
+!
+
+property
+	^ property
+!
+
+property: anObject
+	property := anObject
+!
+
+selector
+	^ selector
+!
+
+selector: anObject
+	selector := anObject
+!
+
+switcherFrom: aCollection to: anotherCollection
+	^ NativeFunction
+		constructorNamed: #Function
+		value: (',' join: aCollection)
+		value: 'return [', (',' join: anotherCollection), ']'
+!
+
+visitMethodNode: aNode
+	self selector: aNode selector.
+	self arguments: aNode arguments.
+	^ super visitMethodNode: aNode
+!
+
+visitSendNode: aNode
+	| receiver |
+	receiver := aNode receiver.
+	receiver isSuper ifTrue: [
+		aNode selector = self selector ifTrue: [
+			| old |
+			old := receiver binding.
+			receiver binding: (
+				JavaScriptSuperVar new
+					scope: old scope;
+					name: old name;
+					yourself ).
+			self args ifNotNil: [ :myArgs |
+				myArgs = self arguments ifFalse: [
+					aNode argumentSwitcher:
+						(self switcherFrom: self arguments to: myArgs) ] ].
+			aNode javaScriptSelector: self property ] ].
+	^ super visitSendNode: aNode
+! !
+
 Object subclass: #LexicalScope
 Object subclass: #LexicalScope
 	slots: {#node. #instruction. #temps. #args. #outerScope. #blockIndex}
 	slots: {#node. #instruction. #temps. #args. #outerScope. #blockIndex}
 	package: 'Compiler-Semantic'!
 	package: 'Compiler-Semantic'!
@@ -23,10 +94,10 @@ args
 	^ args ifNil: [ args := Dictionary new ]
 	^ args ifNil: [ args := Dictionary new ]
 !
 !
 
 
-bindingFor: aStringOrNode
-	^ self pseudoVars at: aStringOrNode value ifAbsent: [
-		self args at: aStringOrNode value ifAbsent: [
-			self temps at: aStringOrNode value ifAbsent: [ nil ]]]
+bindingFor: aString
+	^ self pseudoVars at: aString ifAbsent: [
+		self args at: aString ifAbsent: [
+			self temps at: aString ifAbsent: [ nil ]]]
 !
 !
 
 
 blockIndex
 blockIndex
@@ -45,12 +116,12 @@ instruction: anIRInstruction
 	instruction := anIRInstruction
 	instruction := anIRInstruction
 !
 !
 
 
-lookupVariable: aNode
+lookupVariable: aString
 	| lookup |
 	| lookup |
-	lookup := (self bindingFor: aNode).
+	lookup := (self bindingFor: aString).
 	lookup ifNil: [
 	lookup ifNil: [
 		lookup := self outerScope ifNotNil: [
 		lookup := self outerScope ifNotNil: [
-			(self outerScope lookupVariable: aNode) ]].
+			(self outerScope lookupVariable: aString) ]].
 	^ lookup
 	^ lookup
 !
 !
 
 
@@ -115,8 +186,7 @@ isBlockScope
 !
 !
 
 
 isInlined
 isInlined
-	^ self instruction notNil and: [
-		self instruction isInlined ]
+	^ self instruction ifNil: [ false ] ifNotNil: [ :instr | instr isInlined ]
 !
 !
 
 
 isMethodScope
 isMethodScope
@@ -124,7 +194,7 @@ isMethodScope
 ! !
 ! !
 
 
 LexicalScope subclass: #MethodLexicalScope
 LexicalScope subclass: #MethodLexicalScope
-	slots: {#iVars. #pseudoVars. #unknownVariables. #localReturn. #nonLocalReturns}
+	slots: {#iVars. #pseudoVars. #localReturn. #nonLocalReturns}
 	package: 'Compiler-Semantic'!
 	package: 'Compiler-Semantic'!
 !MethodLexicalScope commentStamp!
 !MethodLexicalScope commentStamp!
 I represent a method scope.!
 I represent a method scope.!
@@ -135,9 +205,9 @@ allVariableNames
 	^ super allVariableNames, self iVars keys
 	^ super allVariableNames, self iVars keys
 !
 !
 
 
-bindingFor: aNode
-	^ (super bindingFor: aNode) ifNil: [
-		self iVars at: aNode value ifAbsent: [ nil ]]
+bindingFor: aString
+	^ (super bindingFor: aString) ifNil: [
+		self iVars at: aString ifAbsent: [ nil ]]
 !
 !
 
 
 iVars
 iVars
@@ -168,10 +238,6 @@ pseudoVars
 				scope: self methodScope;
 				scope: self methodScope;
 				yourself) ] ].
 				yourself) ] ].
 	^ pseudoVars
 	^ pseudoVars
-!
-
-unknownVariables
-	^ unknownVariables ifNil: [ unknownVariables := OrderedCollection new ]
 ! !
 ! !
 
 
 !MethodLexicalScope methodsFor: 'adding'!
 !MethodLexicalScope methodsFor: 'adding'!
@@ -238,47 +304,21 @@ scope: aScope
 
 
 !ScopeVar methodsFor: 'testing'!
 !ScopeVar methodsFor: 'testing'!
 
 
-isArgVar
+isAssignable
 	^ false
 	^ false
 !
 !
 
 
-isClassRefVar
+isIdempotent
 	^ false
 	^ false
 !
 !
 
 
 isImmutable
 isImmutable
-	^ false
-!
-
-isInstanceVar
-	^ false
-!
-
-isPseudoVar
-	^ false
-!
-
-isSelf
-	^ false
+	self deprecatedAPI: 'Use #isIdempotent / #isAssignable not instead.'.
+	^ self isIdempotent
 !
 !
 
 
 isSuper
 isSuper
 	^ false
 	^ false
-!
-
-isTempVar
-	^ false
-!
-
-isUnknownVar
-	^ false
-!
-
-validateAssignment
-	(self isArgVar or: [ self isPseudoVar ]) ifTrue: [
-		InvalidAssignmentError new
-			variableName: self name;
-			signal]
 ! !
 ! !
 
 
 !ScopeVar class methodsFor: 'instance creation'!
 !ScopeVar class methodsFor: 'instance creation'!
@@ -290,24 +330,18 @@ on: aString
 ! !
 ! !
 
 
 ScopeVar subclass: #AliasVar
 ScopeVar subclass: #AliasVar
-	slots: {#node}
+	slots: {}
 	package: 'Compiler-Semantic'!
 	package: 'Compiler-Semantic'!
 !AliasVar commentStamp!
 !AliasVar commentStamp!
 I am an internally defined variable by the compiler!
 I am an internally defined variable by the compiler!
 
 
-!AliasVar methodsFor: 'accessing'!
+!AliasVar methodsFor: 'testing'!
 
 
-node
-	^ node
+isAssignable
+	self error: 'Alias variable is internal, it should never appear in normal variable context.'
 !
 !
 
 
-node: aNode
-	node := aNode
-! !
-
-!AliasVar methodsFor: 'testing'!
-
-isImmutable
+isIdempotent
 	^ true
 	^ true
 ! !
 ! !
 
 
@@ -319,11 +353,7 @@ I am an argument of a method or block.!
 
 
 !ArgVar methodsFor: 'testing'!
 !ArgVar methodsFor: 'testing'!
 
 
-isArgVar
-	^ true
-!
-
-isImmutable
+isIdempotent
 	^ true
 	^ true
 ! !
 ! !
 
 
@@ -339,15 +369,11 @@ alias
 	^ '$globals.', self name
 	^ '$globals.', self name
 ! !
 ! !
 
 
-!ClassRefVar methodsFor: 'testing'!
-
-isClassRefVar
-	^ true
-!
-
-isImmutable
-	^ true
-! !
+ScopeVar subclass: #ExternallyKnownVar
+	slots: {}
+	package: 'Compiler-Semantic'!
+!ExternallyKnownVar commentStamp!
+I am a variable known externally (not in method scope).!
 
 
 ScopeVar subclass: #InstanceVar
 ScopeVar subclass: #InstanceVar
 	slots: {}
 	slots: {}
@@ -361,7 +387,7 @@ alias
 	^ '$self.', self name
 	^ '$self.', self name
 !
 !
 
 
-isInstanceVar
+isAssignable
 	^ true
 	^ true
 ! !
 ! !
 
 
@@ -381,19 +407,11 @@ alias
 
 
 !PseudoVar methodsFor: 'testing'!
 !PseudoVar methodsFor: 'testing'!
 
 
-isImmutable
+isIdempotent
 	^ true
 	^ true
-!
-
-isPseudoVar
-	^ true
-!
-
-isSelf
-	^ name = 'self'
 ! !
 ! !
 
 
-PseudoVar class slots: {#dictionary}!
+PseudoVar class slots: {#dictionary. #receiverNames}!
 
 
 !PseudoVar class methodsFor: 'accessing'!
 !PseudoVar class methodsFor: 'accessing'!
 
 
@@ -406,6 +424,14 @@ dictionary
 		at: #true put: PseudoVar;
 		at: #true put: PseudoVar;
 		at: #thisContext put: ThisContextVar;
 		at: #thisContext put: ThisContextVar;
 		yourself ]
 		yourself ]
+!
+
+receiverNames
+	^ receiverNames ifNil: [ receiverNames := Dictionary new
+		at: #self put: '$self';
+		at: #super put: '$self';
+		at: #nil put: '$nil';
+		yourself ]
 ! !
 ! !
 
 
 PseudoVar subclass: #SuperVar
 PseudoVar subclass: #SuperVar
@@ -416,10 +442,6 @@ I am a 'super' pseudo variable.!
 
 
 !SuperVar methodsFor: 'accessing'!
 !SuperVar methodsFor: 'accessing'!
 
 
-alias
-	^ '$self'
-!
-
 lookupAsJavaScriptSource
 lookupAsJavaScriptSource
 	^ '($methodClass.superclass||$boot.nilAsClass).fn.prototype'
 	^ '($methodClass.superclass||$boot.nilAsClass).fn.prototype'
 ! !
 ! !
@@ -430,6 +452,16 @@ isSuper
 	^ true
 	^ true
 ! !
 ! !
 
 
+SuperVar subclass: #JavaScriptSuperVar
+	slots: {}
+	package: 'Compiler-Semantic'!
+
+!JavaScriptSuperVar methodsFor: 'accessing'!
+
+lookupAsJavaScriptSource
+	^ 'Object.getPrototypeOf($methodClass.fn.prototype)'
+! !
+
 PseudoVar subclass: #ThisContextVar
 PseudoVar subclass: #ThisContextVar
 	slots: {}
 	slots: {}
 	package: 'Compiler-Semantic'!
 	package: 'Compiler-Semantic'!
@@ -450,19 +482,7 @@ I am an temporary variable of a method or block.!
 
 
 !TempVar methodsFor: 'testing'!
 !TempVar methodsFor: 'testing'!
 
 
-isTempVar
-	^ true
-! !
-
-ScopeVar subclass: #UnknownVar
-	slots: {}
-	package: 'Compiler-Semantic'!
-!UnknownVar commentStamp!
-I am an unknown variable. Amber uses unknown variables as JavaScript globals!
-
-!UnknownVar methodsFor: 'testing'!
-
-isUnknownVar
+isAssignable
 	^ true
 	^ true
 ! !
 ! !
 
 
@@ -500,32 +520,22 @@ thePackage: aPackage
 
 
 !SemanticAnalyzer methodsFor: 'error handling'!
 !SemanticAnalyzer methodsFor: 'error handling'!
 
 
+errorInvalidAssignment: aString
+	InvalidAssignmentError new
+		variableName: aString;
+		signal
+!
+
 errorShadowingVariable: aString
 errorShadowingVariable: aString
 	ShadowingVariableError new
 	ShadowingVariableError new
 		variableName: aString;
 		variableName: aString;
 		signal
 		signal
 !
 !
 
 
-errorUnknownVariable: aNode
-	"Throw an error if the variable is undeclared in the global JS scope (i.e. window).
-	We allow all variables listed by Smalltalk>>#globalJsVariables.
-	This list includes: `window`, `document`,  `process` and `global`
-	for nodejs and browser environments.
-	
-	This is only to make sure compilation works on both browser-based and nodejs environments.
-	The ideal solution would be to use a pragma instead"
-
-	| identifier |
-	identifier := aNode value.
-	
-	((Smalltalk globalJsVariables includes: identifier) not
-		and: [ self isVariableUndefined: identifier inPackage: self thePackage ])
-			ifTrue: [
-				UnknownVariableError new
-					variableName: aNode value;
-					signal ]
-			ifFalse: [
-				currentScope methodScope unknownVariables add: aNode value ]
+errorUnknownVariable: aString
+	UnknownVariableError new
+		variableName: aString;
+		signal
 ! !
 ! !
 
 
 !SemanticAnalyzer methodsFor: 'factory'!
 !SemanticAnalyzer methodsFor: 'factory'!
@@ -546,6 +556,26 @@ newScopeOfClass: aLexicalScopeClass
 
 
 !SemanticAnalyzer methodsFor: 'private'!
 !SemanticAnalyzer methodsFor: 'private'!
 
 
+bindUnscopedVariable: aString
+	aString isCapitalized ifTrue: [ "Capital letter variables might be globals."
+		self classReferences add: aString.
+		^ ClassRefVar new name: aString; yourself ].
+
+	"Throw an error if the variable is undeclared in the global JS scope (i.e. window).
+	We allow all variables listed by Smalltalk>>#globalJsVariables.
+	This list includes: `window`, `document`,  `process` and `global`
+	for nodejs and browser environments.
+	
+	This is only to make sure compilation works on both browser-based and nodejs environments.
+	The ideal solution would be to use a pragma instead"
+
+	((Smalltalk globalJsVariables includes: aString)
+		or: [ self isVariableKnown: aString inPackage: self thePackage ]) ifTrue: [
+			^ ExternallyKnownVar new name: aString; yourself ].
+
+	self errorUnknownVariable: aString
+!
+
 nextBlockIndex
 nextBlockIndex
 	blockIndex ifNil: [ blockIndex := 0 ].
 	blockIndex ifNil: [ blockIndex := 0 ].
 	
 	
@@ -574,21 +604,24 @@ validateVariableScope: aString
 
 
 !SemanticAnalyzer methodsFor: 'testing'!
 !SemanticAnalyzer methodsFor: 'testing'!
 
 
-isVariableUndefined: aString inPackage: aPackage
+isVariableKnown: aString inPackage: aPackage
 	aPackage ifNotNil: [
 	aPackage ifNotNil: [
 		| packageKnownVars |
 		| packageKnownVars |
-		packageKnownVars := (aPackage imports
-			reject: #isString)
-			collect: #key.
-		(packageKnownVars includes: aString) ifTrue: [ ^ false ]].
-	^ Compiler eval: 'typeof ', aString, ' === "undefined"'
+		packageKnownVars := (aPackage imports reject: #isString) collect: #key.
+		(packageKnownVars includes: aString) ifTrue: [ ^ true ] ].
+	^ Compiler new
+		eval: 'typeof(', aString, ')!!== "undefined"||(function(){try{return(', aString, ',true)}catch(_){return false}})()'
+		forPackage: aPackage
 ! !
 ! !
 
 
 !SemanticAnalyzer methodsFor: 'visiting'!
 !SemanticAnalyzer methodsFor: 'visiting'!
 
 
 visitAssignmentNode: aNode
 visitAssignmentNode: aNode
+	| lhs |
 	super visitAssignmentNode: aNode.
 	super visitAssignmentNode: aNode.
-	aNode left beAssigned
+	lhs := aNode left.
+	lhs isAssignable ifFalse: [ self errorInvalidAssignment: lhs identifier ].
+	lhs assigned: true
 !
 !
 
 
 visitBlockNode: aNode
 visitBlockNode: aNode
@@ -607,6 +640,7 @@ visitBlockNode: aNode
 
 
 visitCascadeNode: aNode
 visitCascadeNode: aNode
 	aNode receiver: aNode dagChildren first receiver.
 	aNode receiver: aNode dagChildren first receiver.
+	aNode dagChildren allButLast do: [ :each | each beSideEffect ].
 	super visitCascadeNode: aNode
 	super visitCascadeNode: aNode
 !
 !
 
 
@@ -659,21 +693,10 @@ visitSequenceNode: aNode
 
 
 visitVariableNode: aNode
 visitVariableNode: aNode
 	"Bind a ScopeVar to aNode by doing a lookup in the current scope.
 	"Bind a ScopeVar to aNode by doing a lookup in the current scope.
-	If no ScopeVar is found, bind a UnknowVar and throw an error."
+	If no var is found in scope, represent an externally known variable or throw an error."
 
 
-	| binding |
-	binding := currentScope lookupVariable: aNode.
-	
-	binding ifNil: [
-		aNode value isCapitalized
-			ifTrue: [ "Capital letter variables might be globals."
-				binding := ClassRefVar new name: aNode value; yourself.
-				self classReferences add: aNode value]
-			ifFalse: [
-				self errorUnknownVariable: aNode.
-				binding := UnknownVar new name: aNode value; yourself ] ].
-		
-	aNode binding: binding.
+	aNode binding:
+		((currentScope lookupVariable: aNode identifier) ifNil: [ self bindUnscopedVariable: aNode identifier ])
 ! !
 ! !
 
 
 !SemanticAnalyzer class methodsFor: 'instance creation'!
 !SemanticAnalyzer class methodsFor: 'instance creation'!
@@ -755,3 +778,15 @@ variableName: aString
 	variableName := aString
 	variableName := aString
 ! !
 ! !
 
 
+!AstSemanticPragmator methodsFor: '*Compiler-Semantic'!
+
+jsOverride: aString
+	(JSSuperSendVisitor new property: aString; yourself)
+		visit: self methodNode
+!
+
+jsOverride: aString args: aCollection
+	(JSSuperSendVisitor new property: aString; args: aCollection; yourself)
+		visit: self methodNode
+! !
+

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1371 - 422
lang/src/Compiler-Tests.js


+ 370 - 50
lang/src/Compiler-Tests.st

@@ -1,10 +1,14 @@
 Smalltalk createPackage: 'Compiler-Tests'!
 Smalltalk createPackage: 'Compiler-Tests'!
 TestCase subclass: #ASTMethodRunningTest
 TestCase subclass: #ASTMethodRunningTest
-	slots: {#receiver}
+	slots: {#receiver. #arguments}
 	package: 'Compiler-Tests'!
 	package: 'Compiler-Tests'!
 
 
 !ASTMethodRunningTest methodsFor: 'accessing'!
 !ASTMethodRunningTest methodsFor: 'accessing'!
 
 
+arguments
+	^ arguments
+!
+
 receiver
 receiver
 	^ receiver
 	^ receiver
 ! !
 ! !
@@ -12,6 +16,7 @@ receiver
 !ASTMethodRunningTest methodsFor: 'initialization'!
 !ASTMethodRunningTest methodsFor: 'initialization'!
 
 
 setUp
 setUp
+	arguments := #().
 	receiver := DoIt new
 	receiver := DoIt new
 ! !
 ! !
 
 
@@ -45,6 +50,14 @@ ASTMethodRunningTest subclass: #AbstractCompilerTest
 
 
 !AbstractCompilerTest methodsFor: 'tests'!
 !AbstractCompilerTest methodsFor: 'tests'!
 
 
+testAfterInliningNonLocalBlockReturnIndexSend
+	self should: 'foo [ ^ true ifTrue: [ self class ] ] value. self class' return: DoIt.
+!
+
+testAfterInliningNonLocalBlockReturnSuperSend
+	self should: 'foo [ ^ true ifTrue: [ super class ] ] value' return: DoIt.
+!
+
 testAssignment
 testAssignment
 	self should: 'foo | a | a := true ifTrue: [ 1 ]. ^ a' return: 1.
 	self should: 'foo | a | a := true ifTrue: [ 1 ]. ^ a' return: 1.
 	self should: 'foo | a | a := false ifTrue: [ 1 ]. ^ a' return: nil.
 	self should: 'foo | a | a := false ifTrue: [ 1 ]. ^ a' return: nil.
@@ -455,6 +468,135 @@ AbstractCompilerTest subclass: #InliningCodeGeneratorTest
 	slots: {}
 	slots: {}
 	package: 'Compiler-Tests'!
 	package: 'Compiler-Tests'!
 
 
+ASTMethodRunningTest subclass: #AbstractJavaScriptGatewayTest
+	slots: {#theClass}
+	package: 'Compiler-Tests'!
+
+!AbstractJavaScriptGatewayTest methodsFor: 'accessing'!
+
+theClass
+	^ theClass
+! !
+
+!AbstractJavaScriptGatewayTest methodsFor: 'running'!
+
+jsConstructor
+	<inlineJS: '
+		var ctr = function () {};
+		ctr.prototype.foo = function (a,b) {return a+","+b};
+		return ctr;
+	'>
+! !
+
+!AbstractJavaScriptGatewayTest methodsFor: 'tests'!
+
+testDyadicSuperDifferentNames
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.
+	arguments := #(4 true).
+	self
+		should: 'bar: anObject baz: anotherObject
+			<jsOverride: #foo args: #(anObject anotherObject)>
+			^ super bar: anObject baz: anotherObject'
+		return: '4,true'
+!
+
+testDyadicSuperDifferentNamesNested
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.
+	arguments := #(4 true).
+	self
+		should: 'bar: anObject baz: anotherObject
+			<jsOverride: #foo args: #(anObject anotherObject)>
+			^ [ super bar: anObject baz: anotherObject ] value'
+		return: '4,true'
+!
+
+testDyadicSuperDifferentNamesPermutated
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.
+	arguments := #(4 true).
+	self
+		should: 'bar: anObject baz: anotherObject
+			<jsOverride: #foo args: #(anotherObject anObject)>
+			^ super bar: anObject baz: anotherObject'
+		return: 'true,4'
+!
+
+testMonadicSuperDifferentNames
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.
+	arguments := #(4).
+	self
+		should: 'bar: anObject <jsOverride: #foo args: #(anObject)> ^ super bar: anObject'
+		return: '4,undefined'
+!
+
+testNiladicSuper
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	self
+		should: 'foo <jsOverride: #foo> ^ super foo'
+		receiver: (ObjectMock2 new foo: 'should be shadowed'; yourself)
+		return: 'undefined,undefined'
+!
+
+testNiladicSuperDifferentNames
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	self
+		should: 'bar <jsOverride: #foo> ^ super bar'
+		receiver: (ObjectMock2 new foo: 'should be shadowed'; yourself)
+		return: 'undefined,undefined'
+!
+
+testNiladicSuperNested
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	self
+		should: 'foo <jsOverride: #foo> ^ [ super foo ] value'
+		receiver: (ObjectMock2 new foo: 'should be shadowed'; yourself)
+		return: 'undefined,undefined'
+!
+
+testTriadicSuperDifferentNamesPermutated
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.
+	arguments := #(4 true 'hello').
+	self
+		should: 'bar: anObject baz: anotherObject moo: yao
+			<jsOverride: #foo args: #(yao anObject anotherObject)>
+			^ super bar: anObject baz: anotherObject moo: yao'
+		return: 'hello,4'
+! !
+
+!AbstractJavaScriptGatewayTest class methodsFor: 'testing'!
+
+isAbstract
+	^ self name = AbstractJavaScriptGatewayTest name
+! !
+
+AbstractJavaScriptGatewayTest subclass: #DebuggedJSGTest
+	slots: {}
+	package: 'Compiler-Tests'!
+
+AbstractJavaScriptGatewayTest subclass: #InlinedJSGTest
+	slots: {}
+	package: 'Compiler-Tests'!
+
+AbstractJavaScriptGatewayTest subclass: #InterpretedJSGTest
+	slots: {}
+	package: 'Compiler-Tests'!
+
+AbstractJavaScriptGatewayTest subclass: #PlainJSGTest
+	slots: {}
+	package: 'Compiler-Tests'!
+
 TestCase subclass: #ASTPCNodeVisitorTest
 TestCase subclass: #ASTPCNodeVisitorTest
 	slots: {}
 	slots: {}
 	package: 'Compiler-Tests'!
 	package: 'Compiler-Tests'!
@@ -472,17 +614,26 @@ astPCNodeVisitorForSelector: aString
 		selector: aString;
 		selector: aString;
 		index: 0;
 		index: 0;
 		yourself
 		yourself
+!
+
+newTeachableVisitor
+	| result |
+	result := Teachable new
+		whenSend: #visit: evaluate: [ :one | one acceptDagVisitor: result ];
+		acceptSend: #visitDagNode:.
+	^ result
 ! !
 ! !
 
 
 !ASTPCNodeVisitorTest methodsFor: 'tests'!
 !ASTPCNodeVisitorTest methodsFor: 'tests'!
 
 
 testJSStatementNode
 testJSStatementNode
-	| ast visitor |
+	| ast result |
 	
 	
 	ast := self parse: 'foo <inlineJS: ''consolee.log(1)''>' forClass: Object.
 	ast := self parse: 'foo <inlineJS: ''consolee.log(1)''>' forClass: Object.
-	self assert: (self astPCNodeVisitor
-		visit: ast;
-		currentNode) isJSStatementNode
+	result := self astPCNodeVisitor visit: ast; currentNode.
+	self
+		assert: ((self newTeachableVisitor whenSend: #visitJSStatementNode: return: 'JS'; yourself) visit: result)
+		equals: 'JS'
 !
 !
 
 
 testMessageSend
 testMessageSend
@@ -563,19 +714,134 @@ receiver
 
 
 !AbstractCodeGeneratorInstallTest methodsFor: 'testing'!
 !AbstractCodeGeneratorInstallTest methodsFor: 'testing'!
 
 
-shouldntInstall: aString
+shouldntInstall: aString andRaise: anErrorClass
 	| method |
 	| method |
 
 
 	[ self
 	[ self
 		should: [ method := self install: aString forClass: receiver class ]
 		should: [ method := self install: aString forClass: receiver class ]
-		raise: ParseError ]
+		raise: anErrorClass ]
 	ensure: [ method ifNotNil: [ receiver class removeCompiledMethod: method ] ]
 	ensure: [ method ifNotNil: [ receiver class removeCompiledMethod: method ] ]
 ! !
 ! !
 
 
 !AbstractCodeGeneratorInstallTest methodsFor: 'tests'!
 !AbstractCodeGeneratorInstallTest methodsFor: 'tests'!
 
 
+testDyadicJSOverrideArgMismatch
+	receiver := ObjectMock new.
+	self
+		shouldntInstall: 'quux: aNumber foo: anotherNumber
+		<jsOverride: #mux args: #(anInteger anotherNumber)>
+		^ (foo := foo * aNumber + anotherNumber)'
+		andRaise: CompilerError.
+	self
+		shouldntInstall: 'quux: aNumber foo: anotherNumber
+		<jsOverride: #mux args: #(aNumber anotherInteger)>
+		^ (foo := foo * aNumber + anotherNumber)'
+		andRaise: CompilerError.
+	self
+		shouldntInstall: 'quux: aNumber foo: anotherNumber
+		<jsOverride: #mux args: #(anotherNumber anInteger)>
+		^ (foo := foo * aNumber + anotherNumber)'
+		andRaise: CompilerError
+!
+
+testDyadicJSOverrideDifferentNames
+	receiver := ObjectMock new.
+	receiver foo: 4.
+	self while: 'quux: anInteger foo: anotherInteger
+		<jsOverride: #mux args: #(anInteger anotherInteger)>
+		^ (foo := foo * anInteger + anotherInteger)' should: [
+		self should: [ receiver mux ] raise: MessageNotUnderstood.
+		self should: [ receiver mux: 2 and: -1 ] raise: MessageNotUnderstood.
+		self assert: (receiver basicPerform: #mux withArguments: #(2 -2)) equals: 6.
+		self assert: (receiver quux: 1 foo: 4) equals: 10.
+		self should: [ receiver basicPerform: #quux ] raise: Error.
+		self assert: receiver foo equals: 10 ]
+!
+
+testDyadicJSOverrideDifferentNamesPermutated
+	receiver := ObjectMock new.
+	receiver foo: 4.
+	self while: 'quux: anInteger foo: anotherInteger
+		<jsOverride: #mux args: #(anotherInteger anInteger)>
+		^ (foo := foo * anInteger + anotherInteger)' should: [
+		self should: [ receiver mux ] raise: MessageNotUnderstood.
+		self should: [ receiver mux: 2 and: -1 ] raise: MessageNotUnderstood.
+		self assert: (receiver basicPerform: #mux withArguments: #(-2 2)) equals: 6.
+		self assert: (receiver quux: 1 foo: 4) equals: 10.
+		self should: [ receiver basicPerform: #quux ] raise: Error.
+		self assert: receiver foo equals: 10 ]
+!
+
+testDyadicJSOverrideInOneArg
+	receiver := ObjectMock new.
+	self
+		shouldntInstall: 'quux: anInteger
+		<jsOverride: #mux args: #(anInteger anotherInteger)>
+		^ (foo := foo + anInteger)'
+		andRaise: CompilerError.
+	self
+		shouldntInstall: 'quux: anInteger
+		<jsOverride: #mux args: #(anotherInteger anInteger)>
+		^ (foo := foo + anInteger)'
+		andRaise: CompilerError
+!
+
+testDyadicJSOverrideInUnary
+	receiver := ObjectMock new.
+	self
+		shouldntInstall: 'quux <jsOverride: #mux args: #(anInteger anotherInteger)> ^ (foo := foo + 3)'
+		andRaise: CompilerError
+!
+
+testDyadicJSOverrideRepeatedArgs
+	receiver := ObjectMock new.
+	self
+		shouldntInstall: 'quux: anInteger
+		<jsOverride: #mux args: #(anInteger anInteger)>
+		^ (foo := foo + anInteger)'
+		andRaise: CompilerError.
+	self
+		shouldntInstall: 'quux: anInteger foo: anotherInteger
+		<jsOverride: #mux args: #(anInteger anInteger)>
+		^ (foo := foo * anInteger + anotherInteger)'
+		andRaise: CompilerError
+!
+
+testInvalidAssignment
+	self shouldntInstall: 'foo:a a:=1' andRaise: InvalidAssignmentError.
+	self shouldntInstall: 'foo false:=1' andRaise: InvalidAssignmentError.
+	self shouldntInstall: 'foo console:=1' andRaise: InvalidAssignmentError.
+	self shouldntInstall: 'foo Number:=1' andRaise: InvalidAssignmentError
+!
+
 testMistypedPragmaJSStatement
 testMistypedPragmaJSStatement
-	self shouldntInstall: 'foo < inlineJS: ''return ''foo'''' >'
+	self shouldntInstall: 'foo < inlineJS: ''return ''foo'''' >' andRaise: ParseError
+!
+
+testMonadicJSOverrideArgMismatch
+	receiver := ObjectMock new.
+	self
+		shouldntInstall: 'quux: aNumber <jsOverride: #mux args: #(anInteger)> ^ (foo := foo + aNumber)'
+		andRaise: CompilerError
+!
+
+testMonadicJSOverrideDifferentNames
+	receiver := ObjectMock new.
+	receiver foo: 4.
+	self while: 'quux: anInteger <jsOverride: #mux args: #(anInteger)> ^ (foo := foo + anInteger)' should: [
+		self should: [ receiver mux ] raise: MessageNotUnderstood.
+		self should: [ receiver mux: 2 ] raise: MessageNotUnderstood.
+		self assert: (receiver basicPerform: #mux withArguments: #(2)) equals: 6.
+		self assert: (receiver quux: 4) equals: 10.
+		self should: [ receiver basicPerform: #quux ] raise: Error.
+		self assert: receiver foo equals: 10 ]
+!
+
+testMonadicJSOverrideInUnary
+	receiver := ObjectMock new.
+	self
+		shouldntInstall: 'quux <jsOverride: #mux args: #(anInteger)> ^ (foo := foo + 3)'
+		andRaise: CompilerError
 !
 !
 
 
 testNiladicJSOverride
 testNiladicJSOverride
@@ -599,8 +865,29 @@ testNiladicJSOverrideDifferentNames
 		self assert: receiver foo equals: 10 ]
 		self assert: receiver foo equals: 10 ]
 !
 !
 
 
+testNiladicJSOverrideInOneArg
+	receiver := ObjectMock new.
+	self
+		shouldntInstall: 'quux: anInteger <jsOverride: #mux> ^ (foo := foo + anInteger)'
+		andRaise: CompilerError
+!
+
 testPragmaInBlock
 testPragmaInBlock
-	self shouldntInstall: 'foo ^ [ < fooBar > 4 ] value'
+	self shouldntInstall: 'foo ^ [ < fooBar > 4 ] value' andRaise: ParseError
+!
+
+testTriadicJSOverrideDifferentNamesPermutated
+	receiver := ObjectMock new.
+	receiver foo: 4.
+	self while: 'quux: anInteger foo: anotherInteger bar: yaInt
+		<jsOverride: #mux args: #(yaInt anInteger anotherInteger)>
+		^ (foo := foo * anInteger + anotherInteger - yaInt)' should: [
+		self should: [ receiver mux ] raise: MessageNotUnderstood.
+		self should: [ receiver mux: 2 and: -1 and: 0 ] raise: MessageNotUnderstood.
+		self assert: (receiver basicPerform: #mux withArguments: #(5 2 3)) equals: 6.
+		self assert: (receiver quux: 1 foo: 4 bar: 20) equals: -10.
+		self should: [ receiver basicPerform: #quux ] raise: Error.
+		self assert: receiver foo equals: -10 ]
 ! !
 ! !
 
 
 !AbstractCodeGeneratorInstallTest class methodsFor: 'testing'!
 !AbstractCodeGeneratorInstallTest class methodsFor: 'testing'!
@@ -624,52 +911,78 @@ TestCase subclass: #ScopeVarTest
 !ScopeVarTest methodsFor: 'tests'!
 !ScopeVarTest methodsFor: 'tests'!
 
 
 testClassRefVar
 testClassRefVar
-	| node |
+	| node binding |
 	node := VariableNode new
 	node := VariableNode new
-		value: 'Object';
+		identifier: 'Object';
 		yourself.
 		yourself.
 	SemanticAnalyzer new 
 	SemanticAnalyzer new 
 		pushScope: MethodLexicalScope new;
 		pushScope: MethodLexicalScope new;
 		visit: node.
 		visit: node.
-	self assert: node binding isClassRefVar
+	binding := node binding.
+	self deny: binding isAssignable.
+	self deny: binding isIdempotent.
+	self assert: (binding alias includesSubString: 'Object').
+	self assert: (binding alias ~= 'Object')
 !
 !
 
 
-testInstanceVar
-	| node scope |
+testExternallyKnownVar
+	| node binding |
 	node := VariableNode new
 	node := VariableNode new
-		value: 'bzzz';
+		identifier: 'console';
 		yourself.
 		yourself.
-	scope := MethodLexicalScope new.
-	scope addIVar: 'bzzz'.
-	self assert: (scope bindingFor: node) isInstanceVar
+	SemanticAnalyzer new 
+		pushScope: MethodLexicalScope new;
+		visit: node.
+	binding := node binding.
+	self deny: binding isAssignable.
+	self deny: binding isIdempotent.
+	self assert: binding alias equals: 'console'
 !
 !
 
 
-testPseudoVar
-	| node pseudoVars |
-	pseudoVars := #('self' 'super' 'true' 'false' 'nil').
-	pseudoVars do: [:each |
-		node := VariableNode new
-		value: each;
+testExternallyUnknownVar
+	| node |
+	node := VariableNode new
+		identifier: 'bzzz';
 		yourself.
 		yourself.
-		self assert: (MethodLexicalScope new bindingFor: node) isPseudoVar]
+	self 
+		should: [
+			SemanticAnalyzer new 
+			pushScope: MethodLexicalScope new;
+			visit: node ]
+		raise: UnknownVariableError
+!
+
+testInstanceVar
+	| binding |
+	binding := MethodLexicalScope new
+		addIVar: 'bzzz';
+		bindingFor: 'bzzz'.
+	self assert: binding isAssignable.
+	self deny: binding isIdempotent.
+	self assert: (binding alias includesSubString: 'bzzz').
+	self assert: (binding alias ~= 'bzzz')
+!
+
+testPseudoVar
+	#('self' 'super' 'true' 'false' 'nil' 'thisContext') do: [ :each |
+		| binding |
+		binding := MethodLexicalScope new bindingFor: each.
+		self deny: binding isAssignable.
+		self assert: binding isIdempotent ]
 !
 !
 
 
 testTempVar
 testTempVar
-	| node scope |
-	node := VariableNode new
-		value: 'bzzz';
-		yourself.
-	scope := MethodLexicalScope new.
-	scope addTemp: 'bzzz'.
-	self assert: (scope bindingFor: node) isTempVar
+	| binding |
+	binding := MethodLexicalScope new
+		addTemp: 'bzzz';
+		bindingFor: 'bzzz'.
+	self assert: binding isAssignable.
+	self deny: binding isIdempotent.
+	self assert: binding alias equals: 'bzzz'
 !
 !
 
 
 testUnknownVar
 testUnknownVar
-	| node |
-	node := VariableNode new
-		value: 'bzzz';
-		yourself.
-	self assert: (MethodLexicalScope new bindingFor: node) isNil
+	self assert: (MethodLexicalScope new bindingFor: 'bzzz') isNil
 ! !
 ! !
 
 
 TestCase subclass: #SemanticAnalyzerTest
 TestCase subclass: #SemanticAnalyzerTest
@@ -719,7 +1032,7 @@ testScope
 	ast := Smalltalk parse: src.
 	ast := Smalltalk parse: src.
 	analyzer visit: ast.
 	analyzer visit: ast.
 
 
-	self deny: ast dagChildren first dagChildren last scope == ast scope.
+	self deny: ast sequenceNode dagChildren last scope == ast scope.
 !
 !
 
 
 testScope2
 testScope2
@@ -729,7 +1042,7 @@ testScope2
 	ast := Smalltalk parse: src.
 	ast := Smalltalk parse: src.
 	analyzer visit: ast.
 	analyzer visit: ast.
 
 
-	self deny: ast dagChildren first dagChildren last dagChildren first dagChildren first scope == ast scope.
+	self deny: ast sequenceNode dagChildren last sequenceNode dagChildren first scope == ast scope.
 !
 !
 
 
 testScopeLevel
 testScopeLevel
@@ -740,7 +1053,7 @@ testScopeLevel
 	analyzer visit: ast.
 	analyzer visit: ast.
 
 
 	self assert: ast scope scopeLevel equals: 1.
 	self assert: ast scope scopeLevel equals: 1.
-	self assert: ast dagChildren first dagChildren last dagChildren first dagChildren first scope scopeLevel equals: 3
+	self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first scope scopeLevel equals: 3
 !
 !
 
 
 testUnknownVariables
 testUnknownVariables
@@ -804,12 +1117,14 @@ testVariablesLookup
 	analyzer visit: ast.
 	analyzer visit: ast.
 
 
 	"Binding for `a` in the message send"
 	"Binding for `a` in the message send"
-	self assert: ast dagChildren first dagChildren first receiver binding isTempVar.
-	self assert: ast dagChildren first dagChildren first receiver binding scope == ast scope.
+	self assert: ast sequenceNode dagChildren first receiver binding isAssignable.
+	self assert: ast sequenceNode dagChildren first receiver binding alias equals: 'a'.
+	self assert: ast sequenceNode dagChildren first receiver binding scope == ast scope.
 
 
 	"Binding for `b`"
 	"Binding for `b`"
-	self assert: ast dagChildren first dagChildren last dagChildren first dagChildren first left binding isTempVar.
-	self assert: ast dagChildren first dagChildren last dagChildren first dagChildren first left binding scope == ast dagChildren first dagChildren last scope.
+	self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding isAssignable.
+	self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding alias equals: 'b'.
+	self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding scope == ast sequenceNode dagChildren last scope.
 ! !
 ! !
 
 
 SemanticAnalyzerTest subclass: #AISemanticAnalyzerTest
 SemanticAnalyzerTest subclass: #AISemanticAnalyzerTest
@@ -916,7 +1231,7 @@ while: aString inClass: aClass should: aBlock
 		while: aString
 		while: aString
 		inClass: aClass
 		inClass: aClass
 		should: [ :method | aBlock value: [
 		should: [ :method | aBlock value: [
-			self receiver perform: method selector ] ]
+			self receiver perform: method selector withArguments: self arguments ] ]
 ! !
 ! !
 
 
 Trait named: #TCTInlined
 Trait named: #TCTInlined
@@ -943,7 +1258,7 @@ interpret: aString forClass: aClass receiver: anObject withArguments: aDictionar
 	^ ctx interpreter proceed; result
 	^ ctx interpreter proceed; result
 !
 !
 
 
-prepareContextFor: aString class: aClass receiver: anObject withArguments: aDictionary
+prepareContextFor: aString class: aClass receiver: anObject withArguments: anArray
 	"The food is a methodNode. Interpret the sequenceNode only"
 	"The food is a methodNode. Interpret the sequenceNode only"
 	
 	
 	| ctx ast |
 	| ctx ast |
@@ -960,9 +1275,9 @@ prepareContextFor: aString class: aClass receiver: anObject withArguments: aDict
 	ast sequenceNode ifNotNil: [ :sequence |
 	ast sequenceNode ifNotNil: [ :sequence |
 		sequence temps do: [ :each |
 		sequence temps do: [ :each |
 			ctx defineLocal: each ] ].
 			ctx defineLocal: each ] ].
-		
-	aDictionary keysAndValuesDo: [ :key :value |
-		ctx localAt: key put: value ].
+
+	ast arguments with: anArray do: [ :key :value |
+		ctx defineLocal: key; localAt: key put: value ].
 	
 	
 	ctx interpreter
 	ctx interpreter
 		context: ctx;
 		context: ctx;
@@ -983,7 +1298,7 @@ while: aString inClass: aClass should: aBlock
 				interpret: aString
 				interpret: aString
 				forClass: aClass
 				forClass: aClass
 				receiver: self receiver
 				receiver: self receiver
-				withArguments: #{} ] ]
+				withArguments: self arguments ] ]
 ! !
 ! !
 
 
 Trait named: #TCTNonInlined
 Trait named: #TCTNonInlined
@@ -1002,6 +1317,11 @@ ASTDebuggerTest setTraitComposition: {TCTNonInlined. TCTDebugged} asTraitComposi
 ASTInterpreterTest setTraitComposition: {TCTNonInlined. TCTInterpreted} asTraitComposition!
 ASTInterpreterTest setTraitComposition: {TCTNonInlined. TCTInterpreted} asTraitComposition!
 CodeGeneratorTest setTraitComposition: {TCTNonInlined. TCTExecuted} asTraitComposition!
 CodeGeneratorTest setTraitComposition: {TCTNonInlined. TCTExecuted} asTraitComposition!
 InliningCodeGeneratorTest setTraitComposition: {TCTInlined. TCTExecuted} asTraitComposition!
 InliningCodeGeneratorTest setTraitComposition: {TCTInlined. TCTExecuted} asTraitComposition!
+AbstractJavaScriptGatewayTest setTraitComposition: {TClassBuildingTest} asTraitComposition!
+DebuggedJSGTest setTraitComposition: {TCTNonInlined. TCTDebugged} asTraitComposition!
+InlinedJSGTest setTraitComposition: {TCTInlined. TCTExecuted} asTraitComposition!
+InterpretedJSGTest setTraitComposition: {TCTNonInlined. TCTInterpreted} asTraitComposition!
+PlainJSGTest setTraitComposition: {TCTNonInlined. TCTExecuted} asTraitComposition!
 ASTPCNodeVisitorTest setTraitComposition: {TASTParsingTest} asTraitComposition!
 ASTPCNodeVisitorTest setTraitComposition: {TASTParsingTest} asTraitComposition!
 ASTPositionTest setTraitComposition: {TASTParsingTest} asTraitComposition!
 ASTPositionTest setTraitComposition: {TASTParsingTest} asTraitComposition!
 AbstractCodeGeneratorInstallTest setTraitComposition: {TASTCompilingTest} asTraitComposition!
 AbstractCodeGeneratorInstallTest setTraitComposition: {TASTCompilingTest} asTraitComposition!

+ 42 - 43
lang/src/Kernel-Announcements.js

@@ -66,9 +66,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._handlesAnnouncement_(anAnnouncement);
-if($core.assert($1)){
+if($core.assert($self._handlesAnnouncement_(anAnnouncement))){
 $recv($self._valuable())._value_(anAnnouncement);
 $recv($self._valuable())._value_(anAnnouncement);
 }
 }
 return self;
 return self;
@@ -341,14 +339,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $self.subscriptions=$recv($globals.OrderedCollection)._new();
 $self.subscriptions=$recv($globals.OrderedCollection)._new();
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -397,27 +396,27 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$3,$5,$6,$4,$2;
+var $1,$2,$3;
 $1=$self.subscriptions;
 $1=$self.subscriptions;
-$3=$recv($globals.AnnouncementSubscription)._new();
+$2=[$recv($globals.AnnouncementSubscription)._new()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["new"]=1;
+,$ctx1.sendIdx["new"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$5=$recv($globals.AnnouncementValuable)._new();
-$recv($5)._valuable_(aBlock);
-$recv($5)._receiver_(aReceiver);
-$6=$recv($5)._yourself();
+][0];
+$3=$recv($globals.AnnouncementValuable)._new();
+$recv($3)._valuable_(aBlock);
+$recv($3)._receiver_(aReceiver);
+[$recv($2)._valuable_([$recv($3)._yourself()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["yourself"]=1;
+,$ctx1.sendIdx["yourself"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$4=$6;
-$recv($3)._valuable_($4);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["valuable:"]=1;
+,$ctx1.sendIdx["valuable:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($3)._announcementClass_(aClass);
-$2=$recv($3)._yourself();
-$recv($1)._add_($2);
+][0];
+$recv($2)._announcementClass_(aClass);
+$recv($1)._add_($recv($2)._yourself());
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"on:do:for:",{aClass:aClass,aBlock:aBlock,aReceiver:aReceiver})});
 }, function($ctx1) {$ctx1.fill(self,"on:do:for:",{aClass:aClass,aBlock:aBlock,aReceiver:aReceiver})});
@@ -480,24 +479,23 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$3,$5,$6,$4,$2;
+var $1,$2,$3;
 $1=$self.subscriptions;
 $1=$self.subscriptions;
-$3=$recv($globals.AnnouncementSubscription)._new();
+$2=[$recv($globals.AnnouncementSubscription)._new()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["new"]=1;
+,$ctx1.sendIdx["new"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$5=$recv($globals.MessageSend)._new();
-$recv($5)._receiver_(anObject);
-$recv($5)._selector_(aSelector);
-$6=$recv($5)._yourself();
+][0];
+$3=$recv($globals.MessageSend)._new();
+$recv($3)._receiver_(anObject);
+$recv($3)._selector_(aSelector);
+$recv($2)._valuable_([$recv($3)._yourself()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["yourself"]=1;
+,$ctx1.sendIdx["yourself"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$4=$6;
-$recv($3)._valuable_($4);
-$recv($3)._announcementClass_(aClass);
-$2=$recv($3)._yourself();
-$recv($1)._add_($2);
+][0]);
+$recv($2)._announcementClass_(aClass);
+$recv($1)._add_($recv($2)._yourself());
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"on:send:to:",{aClass:aClass,aSelector:aSelector,anObject:anObject})});
 }, function($ctx1) {$ctx1.fill(self,"on:send:to:",{aClass:aClass,aSelector:aSelector,anObject:anObject})});
@@ -561,17 +559,18 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.current;
 $1=$self.current;
-if(($receiver = $1) == null || $receiver.a$nil){
-$self.current=(
+if($1 == null || $1.a$nil){
+$self.current=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 return $self.current;
 return $self.current;
 } else {
 } else {
 return $1;
 return $1;
@@ -1018,13 +1017,13 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self._theClass();
 $1=$self._theClass();
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $1;
 return $1;
 } else {
 } else {
 var class_;
 var class_;
-class_=$receiver;
+class_=$1;
 return $recv(class_)._packageOfProtocol_($self._protocol());
 return $recv(class_)._packageOfProtocol_($self._protocol());
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 263 - 261
lang/src/Kernel-Classes.js


+ 10 - 9
lang/src/Kernel-Classes.st

@@ -39,9 +39,7 @@ allSuperclasses
 	
 	
 	self superclass ifNil: [ ^ #() ].
 	self superclass ifNil: [ ^ #() ].
 	
 	
-	^ (OrderedCollection with: self superclass)
-		addAll: self superclass allSuperclasses;
-		yourself
+	^ self superclass allSuperclasses copyWithFirst: self superclass
 !
 !
 
 
 applySuperConstructorOn: anObject withArguments: anArray
 applySuperConstructorOn: anObject withArguments: anArray
@@ -119,6 +117,10 @@ subclasses
 	self subclassResponsibility
 	self subclassResponsibility
 !
 !
 
 
+superPrototype
+	<inlineJS: 'return Object.getPrototypeOf($self.fn.prototype)'>
+!
+
 superclass
 superclass
 	^ superclass
 	^ superclass
 !
 !
@@ -132,7 +134,7 @@ theNonMetaClass
 !
 !
 
 
 withAllSubclasses
 withAllSubclasses
-	^ (Array with: self) addAll: self allSubclasses; yourself
+	^ self allSubclasses copyWithFirst: self
 ! !
 ! !
 
 
 !Behavior methodsFor: 'enumerating'!
 !Behavior methodsFor: 'enumerating'!
@@ -173,7 +175,7 @@ makeJavaScriptConstructorSubclassOf: javaScriptClass
 
 
 canUnderstand: aSelector
 canUnderstand: aSelector
 	^ (self includesSelector: aSelector asString) or: [
 	^ (self includesSelector: aSelector asString) or: [
-		self superclass notNil and: [ self superclass canUnderstand: aSelector ]]
+		self superclass ifNil: [ false ] ifNotNil: [ :superClass | superClass canUnderstand: aSelector ]]
 !
 !
 
 
 includesBehavior: aClass
 includesBehavior: aClass
@@ -182,10 +184,9 @@ includesBehavior: aClass
 !
 !
 
 
 inheritsFrom: aClass
 inheritsFrom: aClass
-	self superclass ifNil: [ ^ false ].
-
-	^ aClass == self superclass or: [ 
-		self superclass inheritsFrom: aClass ]
+	^ self superclass
+		ifNil: [ false ]
+		ifNotNil: [ :superClass | superClass includesBehavior: aClass ]
 !
 !
 
 
 isBehavior
 isBehavior

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 325 - 191
lang/src/Kernel-Collections.js


+ 107 - 16
lang/src/Kernel-Collections.st

@@ -229,6 +229,10 @@ asSet
 		yourself
 		yourself
 !
 !
 
 
+copyEmpty
+	^ self class new
+!
+
 copyWith: anObject
 copyWith: anObject
 	^ self copy add: anObject; yourself
 	^ self copy add: anObject; yourself
 !
 !
@@ -370,6 +374,14 @@ errorNotFound
 	self error: 'Object is not in the collection'
 	self error: 'Object is not in the collection'
 ! !
 ! !
 
 
+!Collection methodsFor: 'printing'!
+
+shortenedPrintString
+	^ self size <= 1
+		ifTrue: [ self printString ]
+		ifFalse: [ (self copyEmpty copyWith: self anyOne) printString, ' ... ', (self size - 1) asString, ' more items' ]
+! !
+
 !Collection methodsFor: 'streaming'!
 !Collection methodsFor: 'streaming'!
 
 
 putOn: aStream
 putOn: aStream
@@ -542,10 +554,16 @@ removeKey: aKey ifAbsent: aBlock
 
 
 !AssociativeCollection methodsFor: 'comparing'!
 !AssociativeCollection methodsFor: 'comparing'!
 
 
-= anAssocitativeCollection
-	self class = anAssocitativeCollection class ifFalse: [ ^ false ].
-	self size = anAssocitativeCollection size ifFalse: [ ^ false ].
-	^ self associations = anAssocitativeCollection associations
+= anAssociativeCollection
+	| comparisons |
+	self class = anAssociativeCollection class ifFalse: [ ^ false ].
+	self size = anAssociativeCollection size ifFalse: [ ^ false ].
+	comparisons := OrderedCollection new.
+	(self associations allSatisfy: [ :each |
+		anAssociativeCollection at: each key
+			ifPresent: [ :otherValue | comparisons add: { each value. otherValue }. true ]
+			ifAbsent: [ false ] ]) ifFalse: [ ^ false ].
+	^ comparisons allSatisfy: [ :each | each first = each second ]
 ! !
 ! !
 
 
 !AssociativeCollection methodsFor: 'converting'!
 !AssociativeCollection methodsFor: 'converting'!
@@ -654,6 +672,12 @@ printOn: aStream
 		do: [ :each | each printOn: aStream ]
 		do: [ :each | each printOn: aStream ]
 		separatedBy: [ aStream nextPutAll: ' , ' ].
 		separatedBy: [ aStream nextPutAll: ' , ' ].
 	aStream nextPutAll: ')'
 	aStream nextPutAll: ')'
+!
+
+shortenedPrintString
+	^ self size <= 1
+		ifTrue: [ self printString ]
+		ifFalse: [ | key | key := self keys anyOne. (self copyEmpty at: key put: (self at: key); yourself) printString, ' ... ', (self size - 1) asString, ' more items' ]
 ! !
 ! !
 
 
 !AssociativeCollection methodsFor: 'testing'!
 !AssociativeCollection methodsFor: 'testing'!
@@ -974,6 +998,10 @@ reversed
 
 
 copyFrom: anIndex to: anotherIndex
 copyFrom: anIndex to: anotherIndex
 	self subclassResponsibility
 	self subclassResponsibility
+!
+
+copyWithFirst: anObject
+	^ (self class with: anObject) addAll: self; yourself
 ! !
 ! !
 
 
 !SequenceableCollection methodsFor: 'enumerating'!
 !SequenceableCollection methodsFor: 'enumerating'!
@@ -1109,6 +1137,18 @@ reversed
 
 
 !Array methodsFor: 'copying'!
 !Array methodsFor: 'copying'!
 
 
+appendToString: aString
+<inlineJS: '
+	for (var i = 0, l = $self.length; i < l; ++i) {
+		var el = $self[i];
+		if ((typeof el === "string") || $recv(el)._isString()) {
+			if (el.length === 1) { aString += el; continue; }
+		}
+		$self._error_("Not a character.");
+	}
+	return aString'>
+!
+
 copyFrom: anIndex to: anotherIndex
 copyFrom: anIndex to: anotherIndex
 <inlineJS: '
 <inlineJS: '
 	if (anIndex >= 1 && anotherIndex <= self.length) {
 	if (anIndex >= 1 && anotherIndex <= self.length) {
@@ -1127,6 +1167,12 @@ shallowCopy
 
 
 !Array methodsFor: 'enumerating'!
 !Array methodsFor: 'enumerating'!
 
 
+allIn: aBlock
+	^ aBlock valueWithPossibleArguments:
+		"collect to match #in: behaviour"
+		(self collect: [ :each | each in: [ :x | x ] ])
+!
+
 collect: aBlock
 collect: aBlock
 	"Optimized version"
 	"Optimized version"
 	
 	
@@ -1263,32 +1309,59 @@ remove: anObject ifAbsent: aBlock
 !String methodsFor: 'comparing'!
 !String methodsFor: 'comparing'!
 
 
 < aString
 < aString
-	<inlineJS: 'return String(self) < aString._asString()'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) < aString :
+	$recv(aString)._isStringLessThanSelf_(String(self))'>
 !
 !
 
 
 <= aString
 <= aString
-	<inlineJS: 'return String(self) <= aString._asString()'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) <= aString :
+	$recv(aString)._isStringLessThanOrEqualToSelf_(String(self))'>
 !
 !
 
 
 = aString
 = aString
-<inlineJS:
-	'return aString !!= null && String(self) === (typeof aString === "string" ? aString : aString.valueOf())'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) === aString :
+	$recv(aString)._isStringEqualToSelf_(String(self))'>
 !
 !
 
 
 == aString
 == aString
-<inlineJS: '
-	if (typeof aString === "string") return String(self) === aString;
-	else if (aString !!= null && typeof aString === "object") return String(self) === aString.valueOf();
-	else return false;
-'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) === aString :
+	$recv(aString)._isStringEqualToSelf_(String(self))'>
 !
 !
 
 
 > aString
 > aString
-	<inlineJS: 'return String(self) > aString._asString()'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) > aString :
+	$recv(aString)._isStringGreaterThanSelf_(String(self))'>
 !
 !
 
 
 >= aString
 >= aString
-	<inlineJS: 'return String(self) >= aString._asString()'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) >= aString :
+	$recv(aString)._isStringGreaterThanOrEqualSelf_(String(self))'>
+!
+
+isStringEqualToSelf: aString
+	<inlineJS: 'return aString === String(self)'>
+!
+
+isStringGreaterThanOrEqualToSelf: aString
+	<inlineJS: 'return aString >= self'>
+!
+
+isStringGreaterThanSelf: aString
+	<inlineJS: 'return aString > self'>
+!
+
+isStringLessThanOrEqualToSelf: aString
+	<inlineJS: 'return aString <= self'>
+!
+
+isStringLessThanSelf: aString
+	<inlineJS: 'return aString < self'>
 ! !
 ! !
 
 
 !String methodsFor: 'converting'!
 !String methodsFor: 'converting'!
@@ -1381,13 +1454,25 @@ uriEncoded
 !String methodsFor: 'copying'!
 !String methodsFor: 'copying'!
 
 
 , aString
 , aString
-	<inlineJS: 'return String(self) + aString'>
+	<inlineJS: 'return typeof aString === "string" ?
+		String(self) + aString :
+		$recv(aString)._appendToString_(String(self))'>
+!
+
+appendToString: aString
+	<inlineJS: 'return aString + self'>
 !
 !
 
 
 copyFrom: anIndex to: anotherIndex
 copyFrom: anIndex to: anotherIndex
 	<inlineJS: 'return self.substring(anIndex - 1, anotherIndex)'>
 	<inlineJS: 'return self.substring(anIndex - 1, anotherIndex)'>
 !
 !
 
 
+copyWithFirst: anObject
+	(anObject isString and: [ anObject size = 1 ]) "character is one-char string in JS"
+		ifFalse: [ self error: 'Cannot put ', anObject class name, ' in a String' ].
+	^ anObject, self
+!
+
 deepCopy
 deepCopy
 	^ self shallowCopy
 	^ self shallowCopy
 !
 !
@@ -1428,6 +1513,12 @@ printOn: aStream
 		nextPutAll: ''''
 		nextPutAll: ''''
 !
 !
 
 
+shortenedPrintString
+	^ self printString size > 30
+		ifTrue: [ (self printString copyFrom: 1 to: 30), '...''' ]
+		ifFalse: [ self printString ]
+!
+
 symbolPrintString
 symbolPrintString
 	^ String streamContents: [ :str | self asSymbolPrintOn: str ]
 	^ String streamContents: [ :str | self asSymbolPrintOn: str ]
 ! !
 ! !

+ 158 - 30
lang/src/Kernel-Dag.js

@@ -149,16 +149,15 @@ var newChildren,oldChildren;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2;
+var $1;
 oldChildren=$recv(aNode)._dagChildren();
 oldChildren=$recv(aNode)._dagChildren();
 newChildren=$self._visitAllChildren_(aNode);
 newChildren=$self._visitAllChildren_(aNode);
-$1=$recv(oldChildren).__eq(newChildren);
-if($core.assert($1)){
+if($core.assert($recv(oldChildren).__eq(newChildren))){
 return aNode;
 return aNode;
 } else {
 } else {
-$2=$recv(aNode)._copy();
-$recv($2)._dagChildren_(newChildren);
-return $recv($2)._yourself();
+$1=$recv(aNode)._copy();
+$recv($1)._dagChildren_(newChildren);
+return $recv($1)._yourself();
 }
 }
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -213,14 +212,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $self.path=[];
 $self.path=[];
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -271,14 +271,15 @@ $recv((function(){
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 $self.path=$recv($self.path).__comma([aNode]);
 $self.path=$recv($self.path).__comma([aNode]);
-result=(
+result=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx2.supercall = true,
 $ctx2.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._visit_.call($self,aNode));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._visit_.call($self,aNode))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx2.supercall = false
+//>>excludeEnd("ctx");
+][0];
 return result;
 return result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
@@ -312,17 +313,16 @@ var newNode;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-newNode=(
+newNode=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._visitDagNodeVariantRedux_.call($self,aNode));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._visitDagNodeVariantRedux_.call($self,aNode))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-$1=$recv(aNode).__eq_eq(newNode);
-if(!$core.assert($1)){
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
+if(!$core.assert($recv(aNode).__eq_eq(newNode))){
 $recv($self.path)._at_put_($recv($self.path)._size(),newNode);
 $recv($self.path)._at_put_($recv($self.path)._size(),newNode);
 }
 }
 return newNode;
 return newNode;
@@ -378,12 +378,11 @@ var allNodes;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._dagChildren();
+allNodes=$recv([$self._dagChildren()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["dagChildren"]=1;
+,$ctx1.sendIdx["dagChildren"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-allNodes=$recv($1)._asSet();
+][0])._asSet();
 $recv($self._dagChildren())._do_((function(each){
 $recv($self._dagChildren())._do_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
@@ -512,9 +511,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.nodes;
 $1=$self.nodes;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $self.nodes=$recv($globals.Array)._new();
 $self.nodes=$recv($globals.Array)._new();
 return $self.nodes;
 return $self.nodes;
 } else {
 } else {
@@ -547,10 +546,13 @@ $globals.DagParentNode);
 
 
 
 
 
 
-$core.addClass("DagSink", $globals.DagNode, ["nodes"], "Kernel-Dag");
+$core.addClass("DagSink", $globals.DagNode, [], "Kernel-Dag");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.DagSink.comment="I am `DagNode` with no direct successors.\x0a\x0aSending `dagChildren:` with empty collection is legal.";
 $globals.DagSink.comment="I am `DagNode` with no direct successors.\x0a\x0aSending `dagChildren:` with empty collection is legal.";
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
+
+
+$core.addTrait("TDagSink", "Kernel-Dag");
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "dagChildren",
 selector: "dagChildren",
@@ -567,7 +569,7 @@ var self=this,$self=this;
 return [];
 return [];
 
 
 }; }),
 }; }),
-$globals.DagSink);
+$globals.TDagSink);
 
 
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
@@ -599,8 +601,134 @@ return self;
 }, function($ctx1) {$ctx1.fill(self,"dagChildren:",{aCollection:aCollection})});
 }, function($ctx1) {$ctx1.fill(self,"dagChildren:",{aCollection:aCollection})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }; }),
 }; }),
-$globals.DagSink);
+$globals.TDagSink);
+
+
+$core.addTrait("TDerivedDagChildren", "Kernel-Dag");
+$core.addMethod(
+$core.method({
+selector: "addDagChild:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aDagNode"],
+source: "addDagChild: aDagNode\x0a\x09self error: 'Cannot add child for a TDerivedChildren.'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["error:"]
+}, function ($methodClass){ return function (aDagNode){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._error_("Cannot add child for a TDerivedChildren.");
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"addDagChild:",{aDagNode:aDagNode})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TDerivedDagChildren);
+
+$core.addMethod(
+$core.method({
+selector: "dagChildren",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "dagChildren\x0a\x09self subclassResponsibility",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["subclassResponsibility"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._subclassResponsibility();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"dagChildren",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TDerivedDagChildren);
+
+$core.addMethod(
+$core.method({
+selector: "dagChildren:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aCollection"],
+source: "dagChildren: aCollection\x0a\x09self error: 'Cannot set children of a TDerivedChildren.'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["error:"]
+}, function ($methodClass){ return function (aCollection){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._error_("Cannot set children of a TDerivedChildren.");
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"dagChildren:",{aCollection:aCollection})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TDerivedDagChildren);
+
+
+$core.addTrait("TSingleDagChild", "Kernel-Dag");
+$core.addMethod(
+$core.method({
+selector: "dagChild",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "dagChild\x0a\x09self subclassResponsibility",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["subclassResponsibility"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._subclassResponsibility();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"dagChild",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TSingleDagChild);
+
+$core.addMethod(
+$core.method({
+selector: "dagChildren",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "dagChildren\x0a\x09^ { self dagChild }",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["dagChild"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return [$self._dagChild()];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"dagChildren",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TSingleDagChild);
 
 
+$core.setTraitComposition([{trait: $globals.TDerivedDagChildren}], $globals.TDagSink);
+$core.setTraitComposition([{trait: $globals.TDerivedDagChildren}], $globals.TSingleDagChild);
+$core.setTraitComposition([{trait: $globals.TDagSink}], $globals.DagSink);
 
 
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({

+ 40 - 2
lang/src/Kernel-Dag.st

@@ -164,14 +164,17 @@ dagChildren: aCollection
 ! !
 ! !
 
 
 DagNode subclass: #DagSink
 DagNode subclass: #DagSink
-	slots: {#nodes}
+	slots: {}
 	package: 'Kernel-Dag'!
 	package: 'Kernel-Dag'!
 !DagSink commentStamp!
 !DagSink commentStamp!
 I am `DagNode` with no direct successors.
 I am `DagNode` with no direct successors.
 
 
 Sending `dagChildren:` with empty collection is legal.!
 Sending `dagChildren:` with empty collection is legal.!
 
 
-!DagSink methodsFor: 'accessing'!
+Trait named: #TDagSink
+	package: 'Kernel-Dag'!
+
+!TDagSink methodsFor: 'accessing'!
 
 
 dagChildren
 dagChildren
 	^ #()
 	^ #()
@@ -181,6 +184,41 @@ dagChildren: aCollection
 	aCollection ifNotEmpty: [ self error: 'A DagSink cannot have children.' ]
 	aCollection ifNotEmpty: [ self error: 'A DagSink cannot have children.' ]
 ! !
 ! !
 
 
+Trait named: #TDerivedDagChildren
+	package: 'Kernel-Dag'!
+
+!TDerivedDagChildren methodsFor: 'accessing'!
+
+addDagChild: aDagNode
+	self error: 'Cannot add child for a TDerivedChildren.'
+!
+
+dagChildren
+	self subclassResponsibility
+!
+
+dagChildren: aCollection
+	self error: 'Cannot set children of a TDerivedChildren.'
+! !
+
+Trait named: #TSingleDagChild
+	package: 'Kernel-Dag'!
+
+!TSingleDagChild methodsFor: 'accessing'!
+
+dagChild
+	self subclassResponsibility
+!
+
+dagChildren
+	^ { self dagChild }
+! !
+
+TDagSink setTraitComposition: {TDerivedDagChildren} asTraitComposition!
+TSingleDagChild setTraitComposition: {TDerivedDagChildren} asTraitComposition!
+DagSink setTraitComposition: {TDagSink} asTraitComposition!
+! !
+
 !Object methodsFor: '*Kernel-Dag'!
 !Object methodsFor: '*Kernel-Dag'!
 
 
 isDagNode
 isDagNode

+ 17 - 21
lang/src/Kernel-Exceptions.js

@@ -366,20 +366,19 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $3,$2,$1;
 return $recv(aContext)._findContextSuchThat_((function(one){
 return $recv(aContext)._findContextSuchThat_((function(one){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$3=$recv(one)._receiver();
+return $recv($recv([$recv([$recv(one)._receiver()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["receiver"]=1;
+,$ctx2.sendIdx["receiver"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$recv($3).__eq_eq(self);
+][0]).__eq_eq(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["=="]=1;
+,$ctx2.sendIdx["=="]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($2)._or_((function(){
+][0])._or_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -387,8 +386,7 @@ return $recv($recv(one)._receiver()).__eq_eq($self._class());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
-return $recv($1)._not();
+})))._not();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({one:one},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({one:one},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -526,20 +524,19 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $3,$2,$1;
 return $recv(aContext)._findContextSuchThat_((function(one){
 return $recv(aContext)._findContextSuchThat_((function(one){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$3=$recv(one)._receiver();
+return $recv([$recv([$recv([$recv(one)._receiver()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["receiver"]=1;
+,$ctx2.sendIdx["receiver"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$recv($3).__eq_eq(self);
+][0]).__eq_eq(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["=="]=1;
+,$ctx2.sendIdx["=="]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($2)._or_((function(){
+][0])._or_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -555,11 +552,11 @@ return $recv($recv($recv(one)._method())._selector()).__eq("halt");
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["or:"]=1;
+,$ctx2.sendIdx["or:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv($1)._not();
+][0])._not();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({one:one},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({one:one},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -749,12 +746,11 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($recv($recv($self._receiver())._asString()).__comma(" does not understand #")).__comma($recv($self._message())._selector());
+return [$recv($recv($recv($self._receiver())._asString()).__comma(" does not understand #")).__comma($recv($self._message())._selector())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $1;
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"messageText",{})});
 }, function($ctx1) {$ctx1.fill(self,"messageText",{})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");

+ 0 - 95
lang/src/Kernel-Helpers.js

@@ -189,101 +189,6 @@ return false;
 $globals.TIsInGroup);
 $globals.TIsInGroup);
 
 
 
 
-$core.addTrait("TPragmator", "Kernel-Helpers");
-$core.addMethod(
-$core.method({
-selector: "canProcessPragma:",
-protocol: "pragma processing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aMessage"],
-source: "canProcessPragma: aMessage\x0a\x09| selector |\x0a\x09selector := aMessage selector.\x0a\x09^ (self respondsTo: selector) and: [\x0a\x09\x09(self class superclass canUnderstand: selector) not]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["selector", "and:", "respondsTo:", "not", "canUnderstand:", "superclass", "class"]
-}, function ($methodClass){ return function (aMessage){
-var self=this,$self=this;
-var selector;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-selector=$recv(aMessage)._selector();
-return $recv($self._respondsTo_(selector))._and_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($recv($recv($self._class())._superclass())._canUnderstand_(selector))._not();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"canProcessPragma:",{aMessage:aMessage,selector:selector})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.TPragmator);
-
-$core.addMethod(
-$core.method({
-selector: "processPragma:",
-protocol: "pragma processing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aMessage"],
-source: "processPragma: aMessage\x0a\x09(self canProcessPragma: aMessage) ifTrue: [\x0a\x09\x09^ aMessage sendTo: self ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["ifTrue:", "canProcessPragma:", "sendTo:"]
-}, function ($methodClass){ return function (aMessage){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1;
-$1=$self._canProcessPragma_(aMessage);
-if($core.assert($1)){
-return $recv(aMessage)._sendTo_(self);
-}
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"processPragma:",{aMessage:aMessage})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.TPragmator);
-
-$core.addMethod(
-$core.method({
-selector: "processPragmas:",
-protocol: "pragma processing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aCollection"],
-source: "processPragmas: aCollection\x0a\x09aCollection do: [ :each | self processPragma: each ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["do:", "processPragma:"]
-}, function ($methodClass){ return function (aCollection){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-$recv(aCollection)._do_((function(each){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $self._processPragma_(each);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"processPragmas:",{aCollection:aCollection})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.TPragmator);
-
-
 $core.addTrait("TSubclassable", "Kernel-Helpers");
 $core.addTrait("TSubclassable", "Kernel-Helpers");
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({

+ 0 - 21
lang/src/Kernel-Helpers.st

@@ -50,27 +50,6 @@ isSymbol
 	^ false
 	^ false
 ! !
 ! !
 
 
-Trait named: #TPragmator
-	package: 'Kernel-Helpers'!
-
-!TPragmator methodsFor: 'pragma processing'!
-
-canProcessPragma: aMessage
-	| selector |
-	selector := aMessage selector.
-	^ (self respondsTo: selector) and: [
-		(self class superclass canUnderstand: selector) not]
-!
-
-processPragma: aMessage
-	(self canProcessPragma: aMessage) ifTrue: [
-		^ aMessage sendTo: self ]
-!
-
-processPragmas: aCollection
-	aCollection do: [ :each | self processPragma: each ]
-! !
-
 Trait named: #TSubclassable
 Trait named: #TSubclassable
 	package: 'Kernel-Helpers'!
 	package: 'Kernel-Helpers'!
 
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 253 - 257
lang/src/Kernel-Infrastructure.js


+ 17 - 7
lang/src/Kernel-Infrastructure.st

@@ -209,6 +209,16 @@ addObjectVariablesTo: aDictionary ofProxy: aProxy
 	'>
 	'>
 !
 !
 
 
+associationsOfProxy: aProxy
+	<inlineJS: '
+		var jsObject = aProxy.jsObject, result = [];
+		for(var i in jsObject) {
+			result.push(i.__minus_gt(jsObject[i]));
+		}
+		return result;
+	'>
+!
+
 compareJSObjectOfProxy: aProxy withProxy: anotherProxy
 compareJSObjectOfProxy: aProxy withProxy: anotherProxy
 <inlineJS: '
 <inlineJS: '
 	var anotherJSObject = anotherProxy.a$cls ? anotherProxy.jsObject : anotherProxy;
 	var anotherJSObject = anotherProxy.a$cls ? anotherProxy.jsObject : anotherProxy;
@@ -712,7 +722,7 @@ initialize
 ! !
 ! !
 
 
 Object subclass: #Setting
 Object subclass: #Setting
-	slots: {#key. #value. #defaultValue}
+	slots: {#key. #defaultValue}
 	package: 'Kernel-Infrastructure'!
 	package: 'Kernel-Infrastructure'!
 !Setting commentStamp!
 !Setting commentStamp!
 I represent a setting **stored** at `Smalltalk settings`. 
 I represent a setting **stored** at `Smalltalk settings`. 
@@ -868,7 +878,7 @@ settings
 version
 version
 	"Answer the version string of Amber"
 	"Answer the version string of Amber"
 	
 	
-	^ '0.25.0-pre'
+	^ '0.28.2-pre'
 ! !
 ! !
 
 
 !SmalltalkImage methodsFor: 'accessing amd'!
 !SmalltalkImage methodsFor: 'accessing amd'!
@@ -916,16 +926,16 @@ asSmalltalkException: anObject
 		ifFalse: [ JavaScriptException on: anObject ]
 		ifFalse: [ JavaScriptException on: anObject ]
 !
 !
 
 
-do: actionBlock on: anErrorClass do: aBlock
-	"All exceptions thrown in the Smalltalk stack are cought.
-	Convert all JS exceptions to JavaScriptException instances."
+try: actionBlock ifTrue: aBlock catch: anotherBlock
+	"Similar to BlockClosure >> tryifTrue:catch:, but
+	converts all JS exceptions to JavaScriptException instances."
 	
 	
 	| smalltalkError |
 	| smalltalkError |
 	^ actionBlock
 	^ actionBlock
 		tryIfTrue: [ :error |
 		tryIfTrue: [ :error |
 			smalltalkError := self asSmalltalkException: error.
 			smalltalkError := self asSmalltalkException: error.
-			smalltalkError isKindOf: anErrorClass ]
-		catch: [ aBlock value: smalltalkError ]
+			aBlock value: smalltalkError ]
+		catch: [ anotherBlock value: smalltalkError ]
 ! !
 ! !
 
 
 !SmalltalkImage methodsFor: 'globals'!
 !SmalltalkImage methodsFor: 'globals'!

+ 246 - 192
lang/src/Kernel-Methods.js

@@ -345,17 +345,25 @@ selector: "on:do:",
 protocol: "error handling",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anErrorClass", "aBlock"],
 args: ["anErrorClass", "aBlock"],
-source: "on: anErrorClass do: aBlock\x0a\x09^ Smalltalk do: self on: anErrorClass do: aBlock",
+source: "on: anErrorClass do: aBlock\x0a\x09^ Smalltalk try: self ifTrue: [ :err | err isKindOf: anErrorClass ] catch: aBlock",
 referencedClasses: ["Smalltalk"],
 referencedClasses: ["Smalltalk"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["do:on:do:"]
+messageSends: ["try:ifTrue:catch:", "isKindOf:"]
 }, function ($methodClass){ return function (anErrorClass,aBlock){
 }, function ($methodClass){ return function (anErrorClass,aBlock){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv($globals.Smalltalk)._do_on_do_(self,anErrorClass,aBlock);
+return $recv($globals.Smalltalk)._try_ifTrue_catch_(self,(function(err){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(err)._isKindOf_(anErrorClass);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({err:err},$ctx1,1)});
+//>>excludeEnd("ctx");
+}),aBlock);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{anErrorClass:anErrorClass,aBlock:aBlock})});
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{anErrorClass:anErrorClass,aBlock:aBlock})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -835,9 +843,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.args;
 $1=$self.args;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return [];
 return [];
 } else {
 } else {
 return $1;
 return $1;
@@ -888,93 +896,99 @@ var result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $2,$1,$4,$6,$7,$5,$3,$10,$9,$12,$11,$8,$14,$16,$15,$13,$17,$receiver;
-result=$recv(aClass)._name();
+var $1,$2,$3,$4,$5,$6;
+result=[$recv(aClass)._name()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["name"]=1;
+,$ctx1.sendIdx["name"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$self._methodClass();
+][0];
+if(!$core.assert([$recv([$self._methodClass()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["methodClass"]=1;
+,$ctx1.sendIdx["methodClass"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($2).__eq(aClass);
+][0]).__eq(aClass)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["="]=1;
+,$ctx1.sendIdx["="]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(!$core.assert($1)){
-$4=$recv(result).__comma(" (");
+][0])){
+$1=[$recv(result).__comma(" (")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=3;
+,$ctx1.sendIdx[","]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$6=$self._methodClass();
+][0];
+$2=[$self._methodClass()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["methodClass"]=2;
+,$ctx1.sendIdx["methodClass"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(($receiver = $6) == null || $receiver.a$nil){
-$5="nil";
+][0];
+if($2 == null || $2.a$nil){
+$3="nil";
 } else {
 } else {
-$7=$self._methodClass();
+$3=[$recv([$self._methodClass()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["methodClass"]=3;
+,$ctx1.sendIdx["methodClass"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$5=$recv($7)._name();
+][0])._name()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["name"]=2;
+,$ctx1.sendIdx["name"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 }
 }
-$3=$recv($4).__comma($5);
+result=[$recv([$recv($1).__comma($3)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=2;
+,$ctx1.sendIdx[","]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-result=$recv($3).__comma(")");
+][0]).__comma(")")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 result;
 result;
 }
 }
-$10=$self._origin();
+if(!$core.assert($recv([$recv([$self._origin()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["origin"]=1;
+,$ctx1.sendIdx["origin"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$9=$recv($10).__eq(aClass);
+][0]).__eq(aClass)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["="]=2;
+,$ctx1.sendIdx["="]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$12=$self._origin();
+][0]).__or($recv([$self._origin()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["origin"]=2;
+,$ctx1.sendIdx["origin"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$11=$recv($12).__eq($self._methodClass());
-$8=$recv($9).__or($11);
-if(!$core.assert($8)){
-$14=$recv(result).__comma(" /");
+][0]).__eq($self._methodClass())))){
+$4=[$recv(result).__comma(" /")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=6;
+,$ctx1.sendIdx[","]=6
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$16=$self._origin();
+][0];
+$5=[$self._origin()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["origin"]=3;
+,$ctx1.sendIdx["origin"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(($receiver = $16) == null || $receiver.a$nil){
-$15="nil";
+][0];
+if($5 == null || $5.a$nil){
+$6="nil";
 } else {
 } else {
-$15=$recv($self._origin())._name();
+$6=$recv($self._origin())._name();
 }
 }
-$13=$recv($14).__comma($15);
+result=[$recv([$recv($4).__comma($6)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=5;
+,$ctx1.sendIdx[","]=5
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-result=$recv($13).__comma("/");
+][0]).__comma("/")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=4;
+,$ctx1.sendIdx[","]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 result;
 result;
 }
 }
-$17=$recv($recv(result).__comma(" >> ")).__comma($recv($self._selector())._symbolPrintString());
+return [$recv($recv(result).__comma(" >> ")).__comma($recv($self._selector())._symbolPrintString())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=7;
+,$ctx1.sendIdx[","]=7
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $17;
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"asStringForClass:",{aClass:aClass,result:result})});
 }, function($ctx1) {$ctx1.fill(self,"asStringForClass:",{aClass:aClass,result:result})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -997,9 +1011,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.pragmas;
 $1=$self.pragmas;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return [];
 return [];
 } else {
 } else {
 return $1;
 return $1;
@@ -1164,15 +1178,13 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 var $early={};
 var $early={};
 try {
 try {
 $recv($self._methodClass())._allSubclassesDo_((function(each){
 $recv($self._methodClass())._allSubclassesDo_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv(each)._includesSelector_($self.selector);
-if($core.assert($1)){
+if($core.assert($recv(each)._includesSelector_($self.selector))){
 throw $early=[true];
 throw $early=[true];
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1205,20 +1217,21 @@ var superclass;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
-$1=$self._methodClass();
+var $1;
+superclass=[$recv([$self._methodClass()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["methodClass"]=1;
+,$ctx1.sendIdx["methodClass"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-superclass=$recv($1)._superclass();
+][0])._superclass()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["superclass"]=1;
+,$ctx1.sendIdx["superclass"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=superclass;
-if(($receiver = $2) == null || $receiver.a$nil){
+][0];
+$1=superclass;
+if($1 == null || $1.a$nil){
 return false;
 return false;
 } else {
 } else {
-$2;
+$1;
 }
 }
 return $recv($recv($recv($self._methodClass())._superclass())._lookupSelector_($self._selector()))._notNil();
 return $recv($recv($recv($self._methodClass())._superclass())._lookupSelector_($self._selector()))._notNil();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1297,13 +1310,13 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self._origin();
 $1=$self._origin();
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $1;
 return $1;
 } else {
 } else {
 var class_;
 var class_;
-class_=$receiver;
+class_=$1;
 return $recv(class_)._packageOfProtocol_($self._protocol());
 return $recv(class_)._packageOfProtocol_($self._protocol());
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1391,9 +1404,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.protocol;
 $1=$self.protocol;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $self._defaultProtocol();
 return $self._defaultProtocol();
 } else {
 } else {
 return $1;
 return $1;
@@ -1421,26 +1434,25 @@ var oldProtocol;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$4,$3,$5,$receiver;
+var $1,$2,$3,$4;
 oldProtocol=$self._protocol();
 oldProtocol=$self._protocol();
 $self.protocol=aString;
 $self.protocol=aString;
 $1=oldProtocol;
 $1=oldProtocol;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $1;
 $1;
 } else {
 } else {
 $2=$recv($globals.SystemAnnouncer)._current();
 $2=$recv($globals.SystemAnnouncer)._current();
-$4=$recv($globals.MethodMoved)._new();
-$recv($4)._method_(self);
-$recv($4)._oldProtocol_(oldProtocol);
-$3=$recv($4)._yourself();
-$recv($2)._announce_($3);
+$3=$recv($globals.MethodMoved)._new();
+$recv($3)._method_(self);
+$recv($3)._oldProtocol_(oldProtocol);
+$recv($2)._announce_($recv($3)._yourself());
 }
 }
-$5=$self._origin();
-if(($receiver = $5) == null || $receiver.a$nil){
-$5;
+$4=$self._origin();
+if($4 == null || $4.a$nil){
+$4;
 } else {
 } else {
 var origin;
 var origin;
-origin=$receiver;
+origin=$4;
 $recv($recv(origin)._organization())._addElement_(aString);
 $recv($recv(origin)._organization())._addElement_(aString);
 $recv(origin)._removeProtocolIfEmpty_(oldProtocol);
 $recv(origin)._removeProtocolIfEmpty_(oldProtocol);
 }
 }
@@ -1545,9 +1557,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.source;
 $1=$self.source;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return "";
 return "";
 } else {
 } else {
 return $1;
 return $1;
@@ -1647,9 +1659,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($self.poolSize).__lt($self._maxPoolSize());
-if($core.assert($1)){
+if($core.assert($recv($self.poolSize).__lt($self._maxPoolSize()))){
 $self._addWorker();
 $self._addWorker();
 }
 }
 $recv($self.queue)._nextPut_(aBlock);
 $recv($self.queue)._nextPut_(aBlock);
@@ -1676,14 +1686,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $self.poolSize=(0);
 $self.poolSize=(0);
 $self.queue=$recv($globals.Queue)._new();
 $self.queue=$recv($globals.Queue)._new();
 $self.worker=$self._makeWorker();
 $self.worker=$self._makeWorker();
@@ -1711,7 +1722,6 @@ var sentinel;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 sentinel=$recv($globals.Object)._new();
 sentinel=$recv($globals.Object)._new();
 return (function(){
 return (function(){
 var block;
 var block;
@@ -1723,8 +1733,7 @@ block=$recv($self.queue)._nextIfAbsent_((function(){
 return sentinel;
 return sentinel;
 
 
 }));
 }));
-$1=$recv(block).__eq_eq(sentinel);
-if(!$core.assert($1)){
+if(!$core.assert($recv(block).__eq_eq(sentinel))){
 return $recv((function(){
 return $recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 return $core.withContext(function($ctx3) {
@@ -1769,9 +1778,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.maxPoolSize;
 $1=$self.maxPoolSize;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $self._defaultMaxPoolSize();
 return $self._defaultMaxPoolSize();
 } else {
 } else {
 return $1;
 return $1;
@@ -1819,9 +1828,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.default;
 $1=$self.default;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $self.default=$self._new();
 $self.default=$self._new();
 return $self.default;
 return $self.default;
 } else {
 } else {
@@ -1928,22 +1937,25 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._printOn_.call($self,aStream));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._printOn_.call($self,aStream))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-$recv(aStream)._nextPutAll_("(");
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
+[$recv(aStream)._nextPutAll_("(")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nextPutAll:"]=1;
+,$ctx1.sendIdx["nextPutAll:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(aStream)._nextPutAll_($self._selector());
+][0];
+[$recv(aStream)._nextPutAll_($self._selector())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nextPutAll:"]=2;
+,$ctx1.sendIdx["nextPutAll:"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $recv(aStream)._nextPutAll_(")");
 $recv(aStream)._nextPutAll_(")");
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2131,14 +2143,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $self.message=$recv($globals.Message)._new();
 $self.message=$recv($globals.Message)._new();
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2163,30 +2176,35 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._printOn_.call($self,aStream));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._printOn_.call($self,aStream))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-$recv(aStream)._nextPutAll_("(");
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
+[$recv(aStream)._nextPutAll_("(")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nextPutAll:"]=1;
+,$ctx1.sendIdx["nextPutAll:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(aStream)._nextPutAll_($self._receiver());
+][0];
+[$recv(aStream)._nextPutAll_($self._receiver())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nextPutAll:"]=2;
+,$ctx1.sendIdx["nextPutAll:"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(aStream)._nextPutAll_(" >> ");
+][0];
+[$recv(aStream)._nextPutAll_(" >> ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nextPutAll:"]=3;
+,$ctx1.sendIdx["nextPutAll:"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(aStream)._nextPutAll_($self._selector());
+][0];
+[$recv(aStream)._nextPutAll_($self._selector())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nextPutAll:"]=4;
+,$ctx1.sendIdx["nextPutAll:"]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $recv(aStream)._nextPutAll_(")");
 $recv(aStream)._nextPutAll_(")");
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2452,15 +2470,52 @@ selector: "home",
 protocol: "accessing",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
 args: [],
-source: "home\x0a\x09^ homeContext",
+source: "home\x0a\x09^ homeContext ifNotNil: [ :c | c hydrated ]",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: []
+messageSends: ["ifNotNil:", "hydrated"]
 }, function ($methodClass){ return function (){
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 var self=this,$self=this;
-return $self.homeContext;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=$self.homeContext;
+if($1 == null || $1.a$nil){
+return $1;
+} else {
+var c;
+c=$1;
+return $recv(c)._hydrated();
+}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"home",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.MethodContext);
 
 
+$core.addMethod(
+$core.method({
+selector: "hydrated",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "hydrated\x0a\x09<inlineJS: 'if (!$self.selector && !$self.outerContext) $self.setup(self); return self;'>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [["inlineJS:", ["if (!$self.selector && !$self.outerContext) $self.setup(self); return self;"]]],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+if (!$self.selector && !$self.outerContext) $self.setup(self); return self;;
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"hydrated",{})});
+//>>excludeEnd("ctx");
 }; }),
 }; }),
 $globals.MethodContext);
 $globals.MethodContext);
 
 
@@ -2480,9 +2535,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.index;
 $1=$self.index;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return (0);
 return (0);
 } else {
 } else {
 return $1;
 return $1;
@@ -2517,22 +2572,24 @@ selector: "outerContext",
 protocol: "accessing",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
 args: [],
-source: "outerContext\x0a\x09^ outerContext ifNil: [ self home ]",
+source: "outerContext\x0a\x09^ outerContext ifNil: [ self home ] ifNotNil: [ :c | c hydrated ]",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["ifNil:", "home"]
+messageSends: ["ifNil:ifNotNil:", "home", "hydrated"]
 }, function ($methodClass){ return function (){
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.outerContext;
 $1=$self.outerContext;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $self._home();
 return $self._home();
 } else {
 } else {
-return $1;
+var c;
+c=$1;
+return $recv(c)._hydrated();
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"outerContext",{})});
 }, function($ctx1) {$ctx1.fill(self,"outerContext",{})});
@@ -2556,9 +2613,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.selector;
 $1=$self.selector;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $1;
 return $1;
 } else {
 } else {
 return $recv($recv($globals.Smalltalk)._core())._js2st_($self.selector);
 return $recv($recv($globals.Smalltalk)._core())._js2st_($self.selector);
@@ -2677,10 +2734,10 @@ selector: "constructorNamed:value:value:",
 protocol: "instance creation",
 protocol: "instance creation",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString", "anObject", "anObject2"],
 args: ["aString", "anObject", "anObject2"],
-source: "constructorNamed: aString value: anObject value: anObject2\x0a\x09<inlineJS: '\x0a\x09\x09var nativeFunc=$globals.Platform._globals[aString];\x0a\x09\x09return new nativeFunc(anObject,anObject2);\x0a\x09'>",
+source: "constructorNamed: aString value: anObject value: anObject2\x0a\x09<inlineJS: '\x0a\x09\x09var nativeFunc=$globals.Platform._globals()[aString];\x0a\x09\x09return new nativeFunc(anObject,anObject2);\x0a\x09'>",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
-pragmas: [["inlineJS:", ["\x0a\x09\x09var nativeFunc=$globals.Platform._globals[aString];\x0a\x09\x09return new nativeFunc(anObject,anObject2);\x0a\x09"]]],
+pragmas: [["inlineJS:", ["\x0a\x09\x09var nativeFunc=$globals.Platform._globals()[aString];\x0a\x09\x09return new nativeFunc(anObject,anObject2);\x0a\x09"]]],
 messageSends: []
 messageSends: []
 }, function ($methodClass){ return function (aString,anObject,anObject2){
 }, function ($methodClass){ return function (aString,anObject,anObject2){
 var self=this,$self=this;
 var self=this,$self=this;
@@ -2688,7 +2745,7 @@ var self=this,$self=this;
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 
 
-		var nativeFunc=$globals.Platform._globals[aString];
+		var nativeFunc=$globals.Platform._globals()[aString];
 		return new nativeFunc(anObject,anObject2);
 		return new nativeFunc(anObject,anObject2);
 	;
 	;
 return self;
 return self;
@@ -2704,10 +2761,10 @@ selector: "constructorNamed:value:value:value:",
 protocol: "instance creation",
 protocol: "instance creation",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString", "anObject", "anObject2", "anObject3"],
 args: ["aString", "anObject", "anObject2", "anObject3"],
-source: "constructorNamed: aString value: anObject value: anObject2 value: anObject3\x0a\x09<inlineJS: '\x0a\x09\x09var nativeFunc=$globals.Platform._globals[aString];\x0a\x09\x09return new nativeFunc(anObject,anObject2, anObject3);\x0a\x09'>",
+source: "constructorNamed: aString value: anObject value: anObject2 value: anObject3\x0a\x09<inlineJS: '\x0a\x09\x09var nativeFunc=$globals.Platform._globals()[aString];\x0a\x09\x09return new nativeFunc(anObject,anObject2, anObject3);\x0a\x09'>",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
-pragmas: [["inlineJS:", ["\x0a\x09\x09var nativeFunc=$globals.Platform._globals[aString];\x0a\x09\x09return new nativeFunc(anObject,anObject2, anObject3);\x0a\x09"]]],
+pragmas: [["inlineJS:", ["\x0a\x09\x09var nativeFunc=$globals.Platform._globals()[aString];\x0a\x09\x09return new nativeFunc(anObject,anObject2, anObject3);\x0a\x09"]]],
 messageSends: []
 messageSends: []
 }, function ($methodClass){ return function (aString,anObject,anObject2,anObject3){
 }, function ($methodClass){ return function (aString,anObject,anObject2,anObject3){
 var self=this,$self=this;
 var self=this,$self=this;
@@ -2715,7 +2772,7 @@ var self=this,$self=this;
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 
 
-		var nativeFunc=$globals.Platform._globals[aString];
+		var nativeFunc=$globals.Platform._globals()[aString];
 		return new nativeFunc(anObject,anObject2, anObject3);
 		return new nativeFunc(anObject,anObject2, anObject3);
 	;
 	;
 return self;
 return self;
@@ -3289,24 +3346,24 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$3,$receiver;
-$1=$self._isBlockContext();
-if($core.assert($1)){
-$2="a block (in ".__comma($recv($self._methodContext())._asString());
+var $1;
+if($core.assert($self._isBlockContext())){
+return [$recv(["a block (in ".__comma($recv($self._methodContext())._asString())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=2;
+,$ctx1.sendIdx[","]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv($2).__comma(")");
+][0]).__comma(")")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 } else {
 } else {
-$3=$self._method();
-if(($receiver = $3) == null || $receiver.a$nil){
+$1=$self._method();
+if($1 == null || $1.a$nil){
 return "missing method ".__comma($recv($self._selector())._symbolPrintString());
 return "missing method ".__comma($recv($self._selector())._symbolPrintString());
 } else {
 } else {
 var method;
 var method;
-method=$receiver;
+method=$1;
 return $recv(method)._asStringForClass_($recv($self._receiver())._class());
 return $recv(method)._asStringForClass_($recv($self._receiver())._class());
 }
 }
 }
 }
@@ -3357,7 +3414,6 @@ var context;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 var $early={};
 var $early={};
 try {
 try {
 context=self;
 context=self;
@@ -3373,8 +3429,7 @@ return $recv(context)._isNil();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv(testBlock)._value_(context);
-if($core.assert($1)){
+if($core.assert($recv(testBlock)._value_(context))){
 throw $early=[context];
 throw $early=[context];
 }
 }
 context=$recv(context)._outerContext();
 context=$recv(context)._outerContext();
@@ -3504,45 +3559,44 @@ var method,lookupClass,receiverClass,supercall;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$3,$2,$4,$6,$5,$7,$8,$receiver;
-$1=$self._methodContext();
+var $1,$2;
+$1=[$self._methodContext()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["methodContext"]=1;
+,$ctx1.sendIdx["methodContext"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 return nil;
 return nil;
 } else {
 } else {
 $1;
 $1;
 }
 }
-$3=$self._methodContext();
+receiverClass=$recv($recv([$self._methodContext()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["methodContext"]=2;
+,$ctx1.sendIdx["methodContext"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$recv($3)._receiver();
-receiverClass=$recv($2)._class();
-$4=receiverClass;
-$6=$self._methodContext();
+][0])._receiver())._class();
+method=[$recv(receiverClass)._lookupSelector_([$recv([$self._methodContext()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["methodContext"]=3;
+,$ctx1.sendIdx["methodContext"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$5=$recv($6)._selector();
+][0])._selector()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["selector"]=1;
+,$ctx1.sendIdx["selector"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-method=$recv($4)._lookupSelector_($5);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["lookupSelector:"]=1;
+,$ctx1.sendIdx["lookupSelector:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$7=$self._outerContext();
-if(($receiver = $7) == null || $receiver.a$nil){
+][0];
+$2=$self._outerContext();
+if($2 == null || $2.a$nil){
 supercall=false;
 supercall=false;
 } else {
 } else {
 var outer;
 var outer;
-outer=$receiver;
+outer=$2;
 supercall=$recv(outer)._supercall();
 supercall=$recv(outer)._supercall();
 }
 }
-$8=supercall;
-if($core.assert($8)){
+if($core.assert(supercall)){
 return $recv($recv($recv(method)._methodClass())._superclass())._lookupSelector_($recv($self._methodContext())._selector());
 return $recv($recv($recv(method)._methodClass())._superclass())._lookupSelector_($recv($self._methodContext())._selector());
 } else {
 } else {
 return method;
 return method;
@@ -3569,17 +3623,16 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
-$1=$self._isBlockContext();
-if(!$core.assert($1)){
+var $1;
+if(!$core.assert($self._isBlockContext())){
 return self;
 return self;
 }
 }
-$2=$self._outerContext();
-if(($receiver = $2) == null || $receiver.a$nil){
-return $2;
+$1=$self._outerContext();
+if($1 == null || $1.a$nil){
+return $1;
 } else {
 } else {
 var outer;
 var outer;
-outer=$receiver;
+outer=$1;
 return $recv(outer)._methodContext();
 return $recv(outer)._methodContext();
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -3628,22 +3681,25 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._printOn_.call($self,aStream));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._printOn_.call($self,aStream))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-$recv(aStream)._nextPutAll_("(");
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
+[$recv(aStream)._nextPutAll_("(")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nextPutAll:"]=1;
+,$ctx1.sendIdx["nextPutAll:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(aStream)._nextPutAll_($self._asString());
+][0];
+[$recv(aStream)._nextPutAll_($self._asString())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nextPutAll:"]=2;
+,$ctx1.sendIdx["nextPutAll:"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $recv(aStream)._nextPutAll_(")");
 $recv(aStream)._nextPutAll_(")");
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -3668,21 +3724,19 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $2,$1;
-$1=$recv($self._isBlockContext())._and_((function(){
+if($core.assert($recv($self._isBlockContext())._and_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$self._outerContext();
+return $recv([$self._outerContext()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["outerContext"]=1;
+,$ctx2.sendIdx["outerContext"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv($2)._notNil();
+][0])._notNil();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
-if($core.assert($1)){
+})))){
 return $recv($self._outerContext())._receiver();
 return $recv($self._outerContext())._receiver();
 } else {
 } else {
 return $self._basicReceiver();
 return $self._basicReceiver();

+ 9 - 5
lang/src/Kernel-Methods.st

@@ -103,7 +103,7 @@ provided
 !BlockClosure methodsFor: 'error handling'!
 !BlockClosure methodsFor: 'error handling'!
 
 
 on: anErrorClass do: aBlock
 on: anErrorClass do: aBlock
-	^ Smalltalk do: self on: anErrorClass do: aBlock
+	^ Smalltalk try: self ifTrue: [ :err | err isKindOf: anErrorClass ] catch: aBlock
 !
 !
 
 
 tryCatch: aBlock
 tryCatch: aBlock
@@ -648,7 +648,11 @@ evaluatedSelector
 !
 !
 
 
 home
 home
-	^ homeContext
+	^ homeContext ifNotNil: [ :c | c hydrated ]
+!
+
+hydrated
+	<inlineJS: 'if (!!$self.selector && !!$self.outerContext) $self.setup(self); return self;'>
 !
 !
 
 
 index
 index
@@ -660,7 +664,7 @@ locals
 !
 !
 
 
 outerContext
 outerContext
-	^ outerContext ifNil: [ self home ]
+	^ outerContext ifNil: [ self home ] ifNotNil: [ :c | c hydrated ]
 !
 !
 
 
 selector
 selector
@@ -779,14 +783,14 @@ constructorNamed: aString value: anObject
 
 
 constructorNamed: aString value: anObject value: anObject2
 constructorNamed: aString value: anObject value: anObject2
 	<inlineJS: '
 	<inlineJS: '
-		var nativeFunc=$globals.Platform._globals[aString];
+		var nativeFunc=$globals.Platform._globals()[aString];
 		return new nativeFunc(anObject,anObject2);
 		return new nativeFunc(anObject,anObject2);
 	'>
 	'>
 !
 !
 
 
 constructorNamed: aString value: anObject value: anObject2 value: anObject3
 constructorNamed: aString value: anObject value: anObject2 value: anObject3
 	<inlineJS: '
 	<inlineJS: '
-		var nativeFunc=$globals.Platform._globals[aString];
+		var nativeFunc=$globals.Platform._globals()[aString];
 		return new nativeFunc(anObject,anObject2, anObject3);
 		return new nativeFunc(anObject,anObject2, anObject3);
 	'>
 	'>
 !
 !

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 517 - 116
lang/src/Kernel-Objects.js


+ 192 - 22
lang/src/Kernel-Objects.st

@@ -24,11 +24,11 @@ identityHash
 	'>
 	'>
 !
 !
 
 
-instVarAt: aString
+instVarNamed: aString
 	<inlineJS: 'return $self[aString]'>
 	<inlineJS: 'return $self[aString]'>
 !
 !
 
 
-instVarAt: aString put: anObject
+instVarNamed: aString put: anObject
 	<inlineJS: '$self[aString] = anObject'>
 	<inlineJS: '$self[aString] = anObject'>
 !
 !
 
 
@@ -208,8 +208,28 @@ basicDelete: aString
 	<inlineJS: 'delete self[aString]; return aString'>
 	<inlineJS: 'delete self[aString]; return aString'>
 !
 !
 
 
+divideBySelfToNumber: aNumber
+	self error: 'I am not a number.'
+!
+
+divisionRemainderBySelfToNumber: aNumber
+	self error: 'I am not a number.'
+!
+
+minusSelfToNumber: aNumber
+	self error: 'I am not a number.'
+!
+
+plusSelfToNumber: aNumber
+	self error: 'I am not a number.'
+!
+
 size
 size
 	self error: 'Object not indexable'
 	self error: 'Object not indexable'
+!
+
+timesSelfToNumber: aNumber
+	self error: 'I am not a number.'
 ! !
 ! !
 
 
 !Object methodsFor: 'browsing'!
 !Object methodsFor: 'browsing'!
@@ -218,12 +238,58 @@ browse
 	Finder findClass: self class
 	Finder findClass: self class
 ! !
 ! !
 
 
+!Object methodsFor: 'comparing'!
+
+isNumberEqualToSelf: aNumber
+	^ false
+!
+
+isNumberGreaterThanOrEqualToSelf: aNumber
+	^ false
+!
+
+isNumberGreaterThanSelf: aNumber
+	^ false
+!
+
+isNumberLessThanOrEqualToSelf: aNumber
+	^ false
+!
+
+isNumberLessThanSelf: aNumber
+	^ false
+!
+
+isStringEqualToSelf: aString
+	^ false
+!
+
+isStringGreaterThanOrEqualToSelf: aString
+	^ false
+!
+
+isStringGreaterThanSelf: aString
+	^ false
+!
+
+isStringLessThanOrEqualToSelf: aString
+	^ false
+!
+
+isStringLessThanSelf: aString
+	^ false
+! !
+
 !Object methodsFor: 'converting'!
 !Object methodsFor: 'converting'!
 
 
 -> anObject
 -> anObject
 	^ Association key: self value: anObject
 	^ Association key: self value: anObject
 !
 !
 
 
+andSelfToNumber: aNumber
+	self error: 'I am not a number.'
+!
+
 asJSONString
 asJSONString
 	^ JSON stringify: self asJavaScriptObject
 	^ JSON stringify: self asJavaScriptObject
 !
 !
@@ -232,16 +298,28 @@ asJavaScriptObject
 	| variables |
 	| variables |
 	variables := HashedCollection new.
 	variables := HashedCollection new.
 	self class allInstanceVariableNames do: [ :each |
 	self class allInstanceVariableNames do: [ :each |
-		variables at: each put: (self instVarAt: each) asJavaScriptObject ].
+		variables at: each put: (self instVarNamed: each) asJavaScriptObject ].
 	^ variables
 	^ variables
 !
 !
 
 
 asJavaScriptSource
 asJavaScriptSource
 	^ self asString
 	^ self asString
+!
+
+orSelfToNumber: aNumber
+	self error: 'I am not a number.'
+!
+
+xorSelfToNumber: aNumber
+	self error: 'I am not a number.'
 ! !
 ! !
 
 
 !Object methodsFor: 'copying'!
 !Object methodsFor: 'copying'!
 
 
+appendToString: aString
+	self error: 'Cannot add self to a string.'
+!
+
 copy
 copy
 	^ self shallowCopy postCopy
 	^ self shallowCopy postCopy
 !
 !
@@ -727,19 +805,27 @@ My instances can also be used to evaluate a block a fixed number of times:
 !Number methodsFor: 'arithmetic'!
 !Number methodsFor: 'arithmetic'!
 
 
 * aNumber
 * aNumber
-	<inlineJS: 'return self * aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self * aNumber :
+		$recv(aNumber)._timesSelfToNumber_(self)'>
 !
 !
 
 
 + aNumber
 + aNumber
-	<inlineJS: 'return self + aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self + aNumber :
+		$recv(aNumber)._plusSelfToNumber_(self)'>
 !
 !
 
 
 - aNumber
 - aNumber
-	<inlineJS: 'return self - aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self - aNumber :
+		$recv(aNumber)._minusSelfToNumber_(self)'>
 !
 !
 
 
 / aNumber
 / aNumber
-	<inlineJS: 'return self / aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self / aNumber :
+		$recv(aNumber)._divideBySelfToNumber_(self)'>
 !
 !
 
 
 // aNumber
 // aNumber
@@ -747,13 +833,23 @@ My instances can also be used to evaluate a block a fixed number of times:
 !
 !
 
 
 \\ aNumber
 \\ aNumber
-	<inlineJS: 'return self % aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self % aNumber :
+		$recv(aNumber)._divisionRemainderBySelfToNumber_(self)'>
 !
 !
 
 
 abs
 abs
 	<inlineJS: 'return Math.abs(self);'>
 	<inlineJS: 'return Math.abs(self);'>
 !
 !
 
 
+divideBySelfToNumber: aNumber
+	<inlineJS: 'return aNumber / self'>
+!
+
+divisionRemainderBySelfToNumber: aNumber
+	<inlineJS: 'return aNumber % self'>
+!
+
 max: aNumber
 max: aNumber
 	<inlineJS: 'return Math.max(self, aNumber);'>
 	<inlineJS: 'return Math.max(self, aNumber);'>
 !
 !
@@ -766,46 +862,88 @@ min: aMin max: aMax
 	^ (self min: aMin) max: aMax
 	^ (self min: aMin) max: aMax
 !
 !
 
 
+minusSelfToNumber: aNumber
+	<inlineJS: 'return aNumber - self'>
+!
+
 negated
 negated
 	^ 0 - self
 	^ 0 - self
+!
+
+plusSelfToNumber: aNumber
+	<inlineJS: 'return aNumber + self'>
+!
+
+timesSelfToNumber: aNumber
+	<inlineJS: 'return aNumber * self'>
 ! !
 ! !
 
 
 !Number methodsFor: 'comparing'!
 !Number methodsFor: 'comparing'!
 
 
 < aNumber
 < aNumber
-	<inlineJS: 'return self < aNumber'>
+<inlineJS: 'return typeof aNumber === "number" ?
+	Number(self) < aNumber :
+	$recv(aNumber)._isNumberLessThanSelf_(self)'>
 !
 !
 
 
 <= aNumber
 <= aNumber
-	<inlineJS: 'return self <= aNumber'>
+<inlineJS: 'return typeof aNumber === "number" ?
+	Number(self) <= aNumber :
+	$recv(aNumber)._isNumberLessThanOrEqualToSelf_(self)'>
 !
 !
 
 
 == aNumber
 == aNumber
-<inlineJS: '
-	if (typeof aNumber === "number") return Number(self) === aNumber;
-	else if (aNumber !!= null && typeof aNumber === "object") return Number(self) === aNumber.valueOf();
-	else return false;
-'>
+<inlineJS: 'return typeof aNumber === "number" ?
+	Number(self) === aNumber :
+	$recv(aNumber)._isNumberEqualToSelf_(self)'>
 !
 !
 
 
 > aNumber
 > aNumber
-	<inlineJS: 'return self > aNumber'>
+<inlineJS: 'return typeof aNumber === "number" ?
+	Number(self) > aNumber :
+	$recv(aNumber)._isNumberGreaterThanSelf_(self)'>
 !
 !
 
 
 >= aNumber
 >= aNumber
-	<inlineJS: 'return self >= aNumber'>
+<inlineJS: 'return typeof aNumber === "number" ?
+	Number(self) >= aNumber :
+	$recv(aNumber)._isNumberGreaterThanOrEqualToSelf_(self)'>
+!
+
+isNumberEqualToSelf: aNumber
+	<inlineJS: 'return aNumber === Number(self)'>
+!
+
+isNumberGreaterThanOrEqualToSelf: aNumber
+	<inlineJS: 'return aNumber >= self'>
+!
+
+isNumberGreaterThanSelf: aNumber
+	<inlineJS: 'return aNumber > self'>
+!
+
+isNumberLessThanOrEqualToSelf: aNumber
+	<inlineJS: 'return aNumber <= self'>
+!
+
+isNumberLessThanSelf: aNumber
+	<inlineJS: 'return aNumber < self'>
 ! !
 ! !
 
 
 !Number methodsFor: 'converting'!
 !Number methodsFor: 'converting'!
 
 
 & aNumber
 & aNumber
-	<inlineJS: 'return self & aNumber'>
+	^ self bitAnd: aNumber
 !
 !
 
 
 @ aNumber
 @ aNumber
 	^ Point x: self y: aNumber
 	^ Point x: self y: aNumber
 !
 !
 
 
+andSelfToNumber: aNumber
+	<inlineJS: 'return aNumber & self'>
+!
+
 asJavaScriptObject
 asJavaScriptObject
 	^ self
 	^ self
 !
 !
@@ -831,7 +969,9 @@ atRandom
 !
 !
 
 
 bitAnd: aNumber
 bitAnd: aNumber
-	<inlineJS: 'return self & aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self & aNumber :
+		$recv(aNumber)._andSelfToNumber_(self)'>
 !
 !
 
 
 bitNot
 bitNot
@@ -839,11 +979,15 @@ bitNot
 !
 !
 
 
 bitOr: aNumber
 bitOr: aNumber
-	<inlineJS: 'return self | aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self | aNumber :
+		$recv(aNumber)._orSelfToNumber_(self)'>
 !
 !
 
 
 bitXor: aNumber
 bitXor: aNumber
-	<inlineJS: 'return self ^ aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self ^ aNumber :
+		$recv(aNumber)._xorSelfToNumber_(self)'>
 !
 !
 
 
 ceiling
 ceiling
@@ -858,6 +1002,10 @@ floor
 	<inlineJS: 'return Math.floor(self);'>
 	<inlineJS: 'return Math.floor(self);'>
 !
 !
 
 
+orSelfToNumber: aNumber
+	<inlineJS: 'return aNumber | self'>
+!
+
 printStringBase: aBase
 printStringBase: aBase
 	<inlineJS: 'return self.toString(aBase)'>
 	<inlineJS: 'return self.toString(aBase)'>
 !
 !
@@ -911,8 +1059,12 @@ truncated
 	'>
 	'>
 !
 !
 
 
+xorSelfToNumber: aNumber
+	<inlineJS: 'return aNumber ^ self'>
+!
+
 | aNumber
 | aNumber
-	<inlineJS: 'return self | aNumber'>
+	^ self bitOr: aNumber
 ! !
 ! !
 
 
 !Number methodsFor: 'copying'!
 !Number methodsFor: 'copying'!
@@ -1048,10 +1200,20 @@ even
 	^ 0 = (self \\ 2)
 	^ 0 = (self \\ 2)
 !
 !
 
 
+isFinite
+	"Answer whether the receiver is finite"
+	<inlineJS: 'return Number.isFinite(self)'>
+!
+
 isImmutable
 isImmutable
 	^ true
 	^ true
 !
 !
 
 
+isNaN
+	"Answer whether the receiver is IEEE-754 not-a-number"
+	<inlineJS: 'return Number.isNaN(self)'>
+!
+
 isNumber
 isNumber
 	^ true
 	^ true
 !
 !
@@ -1092,10 +1254,18 @@ e
 	<inlineJS: 'return Math.E;'>
 	<inlineJS: 'return Math.E;'>
 !
 !
 
 
+negativeInfinity
+	<inlineJS: 'return Number.NEGATIVE_INFINITY'>
+!
+
 pi
 pi
 	<inlineJS: 'return Math.PI'>
 	<inlineJS: 'return Math.PI'>
 !
 !
 
 
+positiveInfinity
+	<inlineJS: 'return Number.POSITIVE_INFINITY'>
+!
+
 radiansPerDegree
 radiansPerDegree
 	^ (self pi) / 180
 	^ (self pi) / 180
 ! !
 ! !

+ 13 - 15
lang/src/Kernel-Promises.js

@@ -184,19 +184,17 @@ selector: "catch:",
 protocol: "promises",
 protocol: "promises",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock"],
 args: ["aBlock"],
-source: "catch: aBlock\x0a<inlineJS: 'return self.then(null, function (err) {return $core.seamless(function () {\x0a    return aBlock._value_(err);\x0a})})'>",
+source: "catch: aBlock\x0a<inlineJS: 'return self.then(null, function (err) { return aBlock._value_(err); })'>",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
-pragmas: [["inlineJS:", ["return self.then(null, function (err) {return $core.seamless(function () {\x0a    return aBlock._value_(err);\x0a})})"]]],
+pragmas: [["inlineJS:", ["return self.then(null, function (err) { return aBlock._value_(err); })"]]],
 messageSends: []
 messageSends: []
 }, function ($methodClass){ return function (aBlock){
 }, function ($methodClass){ return function (aBlock){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return self.then(null, function (err) {return $core.seamless(function () {
-    return aBlock._value_(err);
-})});
+return self.then(null, function (err) { return aBlock._value_(err); });
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"catch:",{aBlock:aBlock})});
 }, function($ctx1) {$ctx1.fill(self,"catch:",{aBlock:aBlock})});
@@ -210,20 +208,20 @@ selector: "on:do:",
 protocol: "promises",
 protocol: "promises",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aClass", "aBlock"],
 args: ["aClass", "aBlock"],
-source: "on: aClass do: aBlock\x0a<inlineJS: 'return self.then(null, function (err) {return $core.seamless(function () {\x0a    if (err._isKindOf_(aClass)) return aBlock._value_(err);\x0a    else throw err;\x0a})})'>",
+source: "on: aClass do: aBlock\x0a<inlineJS: 'return self.then(null, function (err) {\x0a    if (err._isKindOf_(aClass)) return aBlock._value_(err);\x0a    else throw err;\x0a})'>",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
-pragmas: [["inlineJS:", ["return self.then(null, function (err) {return $core.seamless(function () {\x0a    if (err._isKindOf_(aClass)) return aBlock._value_(err);\x0a    else throw err;\x0a})})"]]],
+pragmas: [["inlineJS:", ["return self.then(null, function (err) {\x0a    if (err._isKindOf_(aClass)) return aBlock._value_(err);\x0a    else throw err;\x0a})"]]],
 messageSends: []
 messageSends: []
 }, function ($methodClass){ return function (aClass,aBlock){
 }, function ($methodClass){ return function (aClass,aBlock){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return self.then(null, function (err) {return $core.seamless(function () {
+return self.then(null, function (err) {
     if (err._isKindOf_(aClass)) return aBlock._value_(err);
     if (err._isKindOf_(aClass)) return aBlock._value_(err);
     else throw err;
     else throw err;
-})});
+});
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{aClass:aClass,aBlock:aBlock})});
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{aClass:aClass,aBlock:aBlock})});
@@ -260,10 +258,10 @@ selector: "then:",
 protocol: "promises",
 protocol: "promises",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlockOrArray"],
 args: ["aBlockOrArray"],
-source: "then: aBlockOrArray\x0a\x22Accepts a block or array of blocks.\x0aEach of blocks in the array or the singleton one is\x0aused in .then call to a promise, to accept a result\x0aand transform it to the result for the next one.\x0aIn case a block has more than one argument\x0aand result is an array, first n-1 elements of the array\x0aare put into additional arguments beyond the first.\x0aThe first argument always contains the result as-is.\x22\x0a<inlineJS: '\x0avar array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];\x0areturn array.reduce(function (soFar, aBlock) {\x0a    return soFar.then(typeof aBlock === \x22function\x22 && aBlock.length > 1 ?\x0a        function (result) {return $core.seamless(function () {\x0a            if (Array.isArray(result)) {\x0a                return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));\x0a            } else {\x0a                return aBlock._value_(result);\x0a            }\x0a        })} :\x0a        function (result) {return $core.seamless(function () {\x0a            return aBlock._value_(result);\x0a        })}\x0a    );\x0a}, self)'>",
+source: "then: aBlockOrArray\x0a\x22Accepts a block or array of blocks.\x0aEach of blocks in the array or the singleton one is\x0aused in .then call to a promise, to accept a result\x0aand transform it to the result for the next one.\x0aIn case a block has more than one argument\x0aand result is an array, first n-1 elements of the array\x0aare put into additional arguments beyond the first.\x0aThe first argument always contains the result as-is.\x22\x0a<inlineJS: '\x0avar array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];\x0areturn array.reduce(function (soFar, aBlock) {\x0a    return soFar.then(typeof aBlock === \x22function\x22 && aBlock.length > 1 ?\x0a       function (result) {\x0a            if (Array.isArray(result)) {\x0a                return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));\x0a            } else {\x0a                return aBlock._value_(result);\x0a            }\x0a        } :\x0a        function (result) {\x0a            return aBlock._value_(result);\x0a        }\x0a    );\x0a}, self)'>",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
-pragmas: [["inlineJS:", ["\x0avar array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];\x0areturn array.reduce(function (soFar, aBlock) {\x0a    return soFar.then(typeof aBlock === \x22function\x22 && aBlock.length > 1 ?\x0a        function (result) {return $core.seamless(function () {\x0a            if (Array.isArray(result)) {\x0a                return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));\x0a            } else {\x0a                return aBlock._value_(result);\x0a            }\x0a        })} :\x0a        function (result) {return $core.seamless(function () {\x0a            return aBlock._value_(result);\x0a        })}\x0a    );\x0a}, self)"]]],
+pragmas: [["inlineJS:", ["\x0avar array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];\x0areturn array.reduce(function (soFar, aBlock) {\x0a    return soFar.then(typeof aBlock === \x22function\x22 && aBlock.length > 1 ?\x0a       function (result) {\x0a            if (Array.isArray(result)) {\x0a                return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));\x0a            } else {\x0a                return aBlock._value_(result);\x0a            }\x0a        } :\x0a        function (result) {\x0a            return aBlock._value_(result);\x0a        }\x0a    );\x0a}, self)"]]],
 messageSends: []
 messageSends: []
 }, function ($methodClass){ return function (aBlockOrArray){
 }, function ($methodClass){ return function (aBlockOrArray){
 var self=this,$self=this;
 var self=this,$self=this;
@@ -274,16 +272,16 @@ return $core.withContext(function($ctx1) {
 var array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];
 var array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];
 return array.reduce(function (soFar, aBlock) {
 return array.reduce(function (soFar, aBlock) {
     return soFar.then(typeof aBlock === "function" && aBlock.length > 1 ?
     return soFar.then(typeof aBlock === "function" && aBlock.length > 1 ?
-        function (result) {return $core.seamless(function () {
+       function (result) {
             if (Array.isArray(result)) {
             if (Array.isArray(result)) {
                 return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));
                 return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));
             } else {
             } else {
                 return aBlock._value_(result);
                 return aBlock._value_(result);
             }
             }
-        })} :
-        function (result) {return $core.seamless(function () {
+        } :
+        function (result) {
             return aBlock._value_(result);
             return aBlock._value_(result);
-        })}
+        }
     );
     );
 }, self);
 }, self);
 return self;
 return self;

+ 7 - 9
lang/src/Kernel-Promises.st

@@ -57,16 +57,14 @@ Trait named: #TThenable
 !TThenable methodsFor: 'promises'!
 !TThenable methodsFor: 'promises'!
 
 
 catch: aBlock
 catch: aBlock
-<inlineJS: 'return self.then(null, function (err) {return $core.seamless(function () {
-    return aBlock._value_(err);
-})})'>
+<inlineJS: 'return self.then(null, function (err) { return aBlock._value_(err); })'>
 !
 !
 
 
 on: aClass do: aBlock
 on: aClass do: aBlock
-<inlineJS: 'return self.then(null, function (err) {return $core.seamless(function () {
+<inlineJS: 'return self.then(null, function (err) {
     if (err._isKindOf_(aClass)) return aBlock._value_(err);
     if (err._isKindOf_(aClass)) return aBlock._value_(err);
     else throw err;
     else throw err;
-})})'>
+})'>
 !
 !
 
 
 on: aClass do: aBlock catch: anotherBlock
 on: aClass do: aBlock catch: anotherBlock
@@ -86,16 +84,16 @@ The first argument always contains the result as-is."
 var array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];
 var array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];
 return array.reduce(function (soFar, aBlock) {
 return array.reduce(function (soFar, aBlock) {
     return soFar.then(typeof aBlock === "function" && aBlock.length > 1 ?
     return soFar.then(typeof aBlock === "function" && aBlock.length > 1 ?
-        function (result) {return $core.seamless(function () {
+       function (result) {
             if (Array.isArray(result)) {
             if (Array.isArray(result)) {
                 return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));
                 return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));
             } else {
             } else {
                 return aBlock._value_(result);
                 return aBlock._value_(result);
             }
             }
-        })} :
-        function (result) {return $core.seamless(function () {
+        } :
+        function (result) {
             return aBlock._value_(result);
             return aBlock._value_(result);
-        })}
+        }
     );
     );
 }, self)'>
 }, self)'>
 !
 !

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 317 - 278
lang/src/Kernel-Tests.js


+ 45 - 20
lang/src/Kernel-Tests.st

@@ -590,6 +590,22 @@ testMethodAttachmentsAreRemoved
 	self assert: (ObjectMock2 new basicAt: #b) equals: nil
 	self assert: (ObjectMock2 new basicAt: #b) equals: nil
 !
 !
 
 
+testMethodAttachmentsAreRemoved2
+	| instance theMethod anObject |
+	theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.
+	anObject := #{#foo -> 'oof'}.
+	theMethod := Compiler new
+		compile: 'bar' forClass: ObjectMock2 protocol: '**test'.
+	self
+		augmentMethodInstantiationOf: theMethod
+		withAttachments: #{#a -> 42. #b -> anObject}.
+	ObjectMock2 addCompiledMethod: theMethod.
+	ObjectMock2 new bar.
+	ObjectMock2 removeCompiledMethod: theMethod.
+	self assert: (ObjectMock2 new basicAt: #a) equals: nil.
+	self assert: (ObjectMock2 new basicAt: #b) equals: nil
+!
+
 testMethodAttachmentsAreReplaced
 testMethodAttachmentsAreReplaced
 	| instance theMethod anObject |
 	| instance theMethod anObject |
 	theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.
 	theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.
@@ -780,8 +796,7 @@ testComma
 	self assert: self collection, self collectionClass new equals: self collection.
 	self assert: self collection, self collectionClass new equals: self collection.
 	self assert: self collectionClass new, self collection equals: self collection.
 	self assert: self collectionClass new, self collection equals: self collection.
 	self assert: self collectionClass new, self collectionClass new equals: self collectionClass new.
 	self assert: self collectionClass new, self collectionClass new equals: self collectionClass new.
-	self assert: self collection, self sampleNewValueAsCollection equals: self collectionWithNewValue.
-	self assertSameContents: self sampleNewValueAsCollection, self collection as: self collectionWithNewValue
+	self assert: self collection, self sampleNewValueAsCollection equals: self collectionWithNewValue
 !
 !
 
 
 testCopy
 testCopy
@@ -794,6 +809,12 @@ testCopy
 	self deny: self collection copy = self collectionWithNewValue
 	self deny: self collection copy = self collectionWithNewValue
 !
 !
 
 
+testCopyEmpty
+	self assert: self collectionClass new copyEmpty equals: self collectionClass new.
+	self assert: self collection copyEmpty equals: self collectionClass new.
+	self assert: self collectionWithNewValue copyEmpty equals: self collectionClass new
+!
+
 testCopySeparates
 testCopySeparates
 	| original copy |
 	| original copy |
 	original := self collection.
 	original := self collection.
@@ -980,13 +1001,6 @@ testAsHashedCollection
 self assert: ( self collectionClass new asHashedCollection isMemberOf: HashedCollection ).
 self assert: ( self collectionClass new asHashedCollection isMemberOf: HashedCollection ).
 !
 !
 
 
-testComma
-	super testComma.
-	self assert: self collection, self collection equals: self collection.
-	self assert: self collection, self collectionWithNewValue equals: self collectionWithNewValue.
-	self assert: self collectionWithNewValue, self collection equals: self collectionWithNewValue
-!
-
 testFrom
 testFrom
 "Accept a collection of associations."
 "Accept a collection of associations."
 | associations |
 | associations |
@@ -1048,6 +1062,13 @@ testRemoveKeyIfAbsent
 		equals: self collection
 		equals: self collection
 !
 !
 
 
+testUnorderedComma
+	self assert: self collection, self collection equals: self collection.
+	self assert: self sampleNewValueAsCollection, self collection equals: self collectionWithNewValue.
+	self assert: self collection, self collectionWithNewValue equals: self collectionWithNewValue.
+	self assert: self collectionWithNewValue, self collection equals: self collectionWithNewValue
+!
+
 testValues
 testValues
 	self assert:self collectionClass new values isEmpty.
 	self assert:self collectionClass new values isEmpty.
 	self assertSameContents:self collection values as: self collectionValues.
 	self assertSameContents:self collection values as: self collectionValues.
@@ -1327,6 +1348,10 @@ testLastN
 	self should: [ self collection last: 33 ] raise: Error
 	self should: [ self collection last: 33 ] raise: Error
 !
 !
 
 
+testOrderedComma
+	self assertSameContents: self sampleNewValueAsCollection, self collection as: self collectionWithNewValue
+!
+
 testSecond
 testSecond
 	self assert: (self collection second) equals: (self collection at: 2)
 	self assert: (self collection second) equals: (self collection at: 2)
 !
 !
@@ -1775,13 +1800,6 @@ testCollect
 	self assert: (#(5 6 8) asSet collect: [ :x | x \\ 3 ]) equals: #(0 2) asSet
 	self assert: (#(5 6 8) asSet collect: [ :x | x \\ 3 ]) equals: #(0 2) asSet
 !
 !
 
 
-testComma
-	super testComma.
-	self assert: self collection, self collection equals: self collection.
-	self assert: self collection, self collectionWithNewValue equals: self collectionWithNewValue.
-	self assert: self collectionWithNewValue, self collection equals: self collectionWithNewValue
-!
-
 testComparing
 testComparing
 	self assert: #(0 2) asSet equals: #(0 2) asSet.
 	self assert: #(0 2) asSet equals: #(0 2) asSet.
 	self assert: #(2 0) asSet equals: #(0 2) asSet.
 	self assert: #(2 0) asSet equals: #(0 2) asSet.
@@ -1842,6 +1860,13 @@ testUnicity
 	self assert: set size equals: 2.
 	self assert: set size equals: 2.
 
 
 	self assert: set asArray equals: #(21 'hello')
 	self assert: set asArray equals: #(21 'hello')
+!
+
+testUnorderedComma
+	self assert: self collection, self collection equals: self collection.
+	self assert: self sampleNewValueAsCollection, self collection equals: self collectionWithNewValue.
+	self assert: self collection, self collectionWithNewValue equals: self collectionWithNewValue.
+	self assert: self collectionWithNewValue, self collection equals: self collectionWithNewValue
 ! !
 ! !
 
 
 !SetTest class methodsFor: 'fixture'!
 !SetTest class methodsFor: 'fixture'!
@@ -2644,11 +2669,11 @@ testIfNil
 testInstVars
 testInstVars
 	| o |
 	| o |
 	o := ObjectMock new.
 	o := ObjectMock new.
-	self assert: (o instVarAt: #foo) equals: nil.
+	self assert: (o instVarNamed: #foo) equals: nil.
 
 
-	o instVarAt: #foo put: 1.
-	self assert: (o instVarAt: #foo) equals: 1.
-	self assert: (o instVarAt: 'foo') equals: 1
+	o instVarNamed: #foo put: 1.
+	self assert: (o instVarNamed: #foo) equals: 1.
+	self assert: (o instVarNamed: 'foo') equals: 1
 !
 !
 
 
 testNilUndefined
 testNilUndefined

+ 56 - 8
lang/src/Platform-Browser.js

@@ -108,6 +108,57 @@ return window;
 }; }),
 }; }),
 $globals.BrowserPlatform);
 $globals.BrowserPlatform);
 
 
+$core.addMethod(
+$core.method({
+selector: "initialize",
+protocol: "public API",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "initialize\x0a\x09window\x0a\x09\x09addEventListener: 'error'\x0a\x09\x09do: [ :event | ErrorHandler handleError: event error ];\x0a\x09\x09addEventListener: 'unhandledrejection'\x0a\x09\x09do: [ :event | ErrorHandler handleError: event reason ]",
+referencedClasses: ["ErrorHandler"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["addEventListener:do:", "handleError:", "error", "reason"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=window;
+[$recv($1)._addEventListener_do_("error",(function(event){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return [$recv($globals.ErrorHandler)._handleError_($recv(event)._error())
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["handleError:"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({event:event},$ctx1,1)});
+//>>excludeEnd("ctx");
+}))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["addEventListener:do:"]=1
+//>>excludeEnd("ctx");
+][0];
+$recv($1)._addEventListener_do_("unhandledrejection",(function(event){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv($globals.ErrorHandler)._handleError_($recv(event)._reason());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({event:event},$ctx1,2)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"initialize",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.BrowserPlatform);
+
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "newXhr",
 selector: "newXhr",
@@ -124,8 +175,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $receiver;
-if(($receiver = $globals.XMLHttpRequest) == null || $receiver.a$nil){
+var $1;
+$1=$globals.XMLHttpRequest;
+if($1 == null || $1.a$nil){
 $self._error_("XMLHttpRequest not available.");
 $self._error_("XMLHttpRequest not available.");
 } else {
 } else {
 return $recv($globals.NativeFunction)._constructorOf_($globals.XMLHttpRequest);
 return $recv($globals.NativeFunction)._constructorOf_($globals.XMLHttpRequest);
@@ -154,9 +206,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._isFeasible();
-if($core.assert($1)){
+if($core.assert($self._isFeasible())){
 $recv($globals.Platform)._registerIfNone_($self._new());
 $recv($globals.Platform)._registerIfNone_($self._new());
 }
 }
 return self;
 return self;
@@ -304,9 +354,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._isFeasible();
-if($core.assert($1)){
+if($core.assert($self._isFeasible())){
 $recv($globals.Terminal)._registerIfNone_($self._new());
 $recv($globals.Terminal)._registerIfNone_($self._new());
 }
 }
 return self;
 return self;

+ 8 - 0
lang/src/Platform-Browser.st

@@ -26,6 +26,14 @@ fetchUrl: aString options: anObject
 		ifAbsent: [ Promise signal: 'fetch not available.' ]
 		ifAbsent: [ Promise signal: 'fetch not available.' ]
 !
 !
 
 
+initialize
+	window
+		addEventListener: 'error'
+		do: [ :event | ErrorHandler handleError: event error ];
+		addEventListener: 'unhandledrejection'
+		do: [ :event | ErrorHandler handleError: event reason ]
+!
+
 newXhr
 newXhr
 	XMLHttpRequest
 	XMLHttpRequest
 		ifNotNil: [ ^ NativeFunction constructorOf: XMLHttpRequest ]
 		ifNotNil: [ ^ NativeFunction constructorOf: XMLHttpRequest ]

+ 2 - 6
lang/src/Platform-DOM-Tests.js

@@ -21,9 +21,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($globals.PlatformDom)._isFeasible();
-if($core.assert($1)){
+if($core.assert($recv($globals.PlatformDom)._isFeasible())){
 $self._assert_equals_("&copy;"._htmlTextContent(),"©");
 $self._assert_equals_("&copy;"._htmlTextContent(),"©");
 }
 }
 return self;
 return self;
@@ -49,9 +47,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($globals.PlatformDom)._isFeasible();
-if($core.assert($1)){
+if($core.assert($recv($globals.PlatformDom)._isFeasible())){
 $self._shouldnt_raise_((function(){
 $self._shouldnt_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {

+ 6 - 8
lang/src/Platform-DOM.js

@@ -165,20 +165,18 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2;
-$1=$recv($globals.PlatformDom)._isDomNode_($self.jsObject);
-if($core.assert($1)){
+if($core.assert($recv($globals.PlatformDom)._isDomNode_($self.jsObject))){
 return $self.jsObject;
 return $self.jsObject;
 } else {
 } else {
-$2=(
+return [(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._asDomNode.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._asDomNode.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-return $2;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 }
 }
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 322 - 263
lang/src/Platform-ImportExport.js


+ 4 - 5
lang/src/Platform-Node.js

@@ -124,8 +124,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $receiver;
-if(($receiver = $globals.XMLHttpRequest) == null || $receiver.a$nil){
+var $1;
+$1=$globals.XMLHttpRequest;
+if($1 == null || $1.a$nil){
 $self._error_("XMLHttpRequest not available.");
 $self._error_("XMLHttpRequest not available.");
 } else {
 } else {
 return $recv($globals.XMLHttpRequest)._new();
 return $recv($globals.XMLHttpRequest)._new();
@@ -154,9 +155,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._isFeasible();
-if($core.assert($1)){
+if($core.assert($self._isFeasible())){
 $recv($globals.Platform)._registerIfNone_($self._new());
 $recv($globals.Platform)._registerIfNone_($self._new());
 }
 }
 return self;
 return self;

+ 261 - 201
lang/src/Platform-Services.js

@@ -24,12 +24,13 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
-$1=$recv(anError)._context();
+var $1;
+$1=[$recv(anError)._context()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["context"]=1;
+,$ctx1.sendIdx["context"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 $1;
 $1;
 } else {
 } else {
 $self._logErrorContext_($recv(anError)._context());
 $self._logErrorContext_($recv(anError)._context());
@@ -82,12 +83,13 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
-$1=$recv(aContext)._home();
+var $1;
+$1=[$recv(aContext)._home()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["home"]=1;
+,$ctx1.sendIdx["home"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 $1;
 $1;
 } else {
 } else {
 $self._logContext_($recv(aContext)._home());
 $self._logContext_($recv(aContext)._home());
@@ -140,15 +142,16 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
-if(($receiver = aContext) == null || $receiver.a$nil){
+var $1;
+if(aContext == null || aContext.a$nil){
 aContext;
 aContext;
 } else {
 } else {
-$1=$recv(aContext)._home();
+$1=[$recv(aContext)._home()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["home"]=1;
+,$ctx1.sendIdx["home"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 $1;
 $1;
 } else {
 } else {
 $self._logContext_($recv(aContext)._home());
 $self._logContext_($recv(aContext)._home());
@@ -317,23 +320,19 @@ var newInstVars;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$3,$4,$5;
 newInstVars=$recv($recv(aClass)._instanceVariableNames())._copyWith_(aString);
 newInstVars=$recv($recv(aClass)._instanceVariableNames())._copyWith_(aString);
-$1=$recv(aClass)._isMetaclass();
-if($core.assert($1)){
-$2=$self._classBuilder();
+if($core.assert($recv(aClass)._isMetaclass())){
+$recv([$self._classBuilder()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["classBuilder"]=1;
+,$ctx1.sendIdx["classBuilder"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($2)._class_slots_(aClass,newInstVars);
+][0])._class_slots_(aClass,newInstVars);
 } else {
 } else {
-$3=$self._classBuilder();
-$4=$recv(aClass)._superclass();
-$5=$recv(aClass)._name();
+$recv($self._classBuilder())._addSubclassOf_named_instanceVariableNames_package_($recv(aClass)._superclass(),[$recv(aClass)._name()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["name"]=1;
+,$ctx1.sendIdx["name"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($3)._addSubclassOf_named_instanceVariableNames_package_($4,$5,newInstVars,$recv($recv(aClass)._package())._name());
+][0],newInstVars,$recv($recv(aClass)._package())._name());
 }
 }
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -444,13 +443,14 @@ var protocols;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 protocols=$recv(aClass)._protocols();
 protocols=$recv(aClass)._protocols();
-$1=$recv(aClass)._superclass();
+$1=[$recv(aClass)._superclass()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["superclass"]=1;
+,$ctx1.sendIdx["superclass"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 $1;
 $1;
 } else {
 } else {
 $recv(protocols)._addAll_($self._availableProtocolsFor_($recv(aClass)._superclass()));
 $recv(protocols)._addAll_($self._availableProtocolsFor_($recv(aClass)._superclass()));
@@ -501,9 +501,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$recv($recv($globals.Smalltalk)._globals())._at_($recv(aString)._asSymbol());
 $1=$recv($recv($globals.Smalltalk)._globals())._at_($recv(aString)._asSymbol());
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $self._error_("Invalid class name");
 return $self._error_("Invalid class name");
 } else {
 } else {
 return $1;
 return $1;
@@ -664,16 +664,16 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
+var $1;
 $1=$recv($recv($globals.Smalltalk)._globals())._at_(aClassName);
 $1=$recv($recv($globals.Smalltalk)._globals())._at_(aClassName);
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $1;
 $1;
 } else {
 } else {
-$2=$recv("A class named ".__comma(aClassName)).__comma(" already exists");
+$self._error_([$recv("A class named ".__comma(aClassName)).__comma(" already exists")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._error_($2);
+][0]);
 }
 }
 $recv($recv($globals.ClassBuilder)._new())._copyClass_named_(aClass,aClassName);
 $recv($recv($globals.ClassBuilder)._new())._copyClass_named_(aClass,aClassName);
 return self;
 return self;
@@ -735,17 +735,17 @@ selector: "evaluate:on:do:",
 protocol: "error handling",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock", "anErrorClass", "exceptionBlock"],
 args: ["aBlock", "anErrorClass", "exceptionBlock"],
-source: "evaluate: aBlock on: anErrorClass do: exceptionBlock\x0a\x09\x22Evaluate a block and catch exceptions happening on the environment stack\x22\x0a\x09\x0a\x09^ Smalltalk do: aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock",
-referencedClasses: ["Smalltalk"],
+source: "evaluate: aBlock on: anErrorClass do: exceptionBlock\x0a\x09\x22Evaluate a block and catch exceptions happening on the environment stack\x22\x0a\x09\x0a\x09^ aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock",
+referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["do:on:do:", "classNamed:", "name"]
+messageSends: ["on:do:", "classNamed:", "name"]
 }, function ($methodClass){ return function (aBlock,anErrorClass,exceptionBlock){
 }, function ($methodClass){ return function (aBlock,anErrorClass,exceptionBlock){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv($globals.Smalltalk)._do_on_do_(aBlock,$self._classNamed_($recv(anErrorClass)._name()),exceptionBlock);
+return $recv(aBlock)._on_do_($self._classNamed_($recv(anErrorClass)._name()),exceptionBlock);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"evaluate:on:do:",{aBlock:aBlock,anErrorClass:anErrorClass,exceptionBlock:exceptionBlock})});
 }, function($ctx1) {$ctx1.fill(self,"evaluate:on:do:",{aBlock:aBlock,anErrorClass:anErrorClass,exceptionBlock:exceptionBlock})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -793,16 +793,15 @@ var package_;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
+var $1;
 package_=$recv($globals.Package)._named_(aPackageName);
 package_=$recv($globals.Package)._named_(aPackageName);
 $1=package_;
 $1=package_;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $self._error_("Invalid package name");
 $self._error_("Invalid package name");
 } else {
 } else {
 $1;
 $1;
 }
 }
-$2=$recv(package_).__eq_eq($recv(aClass)._package());
-if($core.assert($2)){
+if($core.assert($recv(package_).__eq_eq($recv(aClass)._package()))){
 return self;
 return self;
 }
 }
 $recv(aClass)._package_(package_);
 $recv(aClass)._package_(package_);
@@ -831,23 +830,19 @@ var destinationClass;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $2,$3,$1,$5,$4;
 destinationClass=$self._classNamed_(aClassName);
 destinationClass=$self._classNamed_(aClassName);
-$2=destinationClass;
-$3=$recv(aMethod)._origin();
+if($core.assert($recv(destinationClass).__eq_eq([$recv(aMethod)._origin()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["origin"]=1;
+,$ctx1.sendIdx["origin"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($2).__eq_eq($3);
-if($core.assert($1)){
+][0]))){
 return self;
 return self;
 }
 }
-$5=$recv(aMethod)._origin();
+if($core.assert($recv([$recv(aMethod)._origin()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["origin"]=2;
+,$ctx1.sendIdx["origin"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$4=$recv($5)._isMetaclass();
-if($core.assert($4)){
+][0])._isMetaclass())){
 destinationClass=$recv(destinationClass)._theMetaClass();
 destinationClass=$recv(destinationClass)._theMetaClass();
 destinationClass;
 destinationClass;
 }
 }
@@ -1124,16 +1119,16 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
+var $1;
 $1=$recv($recv($globals.Smalltalk)._globals())._at_(aClassName);
 $1=$recv($recv($globals.Smalltalk)._globals())._at_(aClassName);
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $1;
 $1;
 } else {
 } else {
-$2=$recv("A class named ".__comma(aClassName)).__comma(" already exists");
+$self._error_([$recv("A class named ".__comma(aClassName)).__comma(" already exists")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._error_($2);
+][0]);
 }
 }
 $recv($recv($globals.ClassBuilder)._new())._renameClass_to_(aClass,aClassName);
 $recv($recv($globals.ClassBuilder)._new())._renameClass_to_(aClass,aClassName);
 return self;
 return self;
@@ -1386,9 +1381,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self._current();
 $1=$self._current();
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $self._register_(anObject);
 $self._register_(anObject);
 } else {
 } else {
 $1;
 $1;
@@ -1423,10 +1418,10 @@ var smalltalkError;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 smalltalkError=$recv($globals.Smalltalk)._asSmalltalkException_(anError);
 smalltalkError=$recv($globals.Smalltalk)._asSmalltalkException_(anError);
 $1=$recv(smalltalkError)._context();
 $1=$recv(smalltalkError)._context();
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $recv(smalltalkError)._context_($core.getThisContext());
 $recv(smalltalkError)._context_($core.getThisContext());
 } else {
 } else {
 $1;
 $1;
@@ -1455,9 +1450,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv(anError)._wasHandled();
-if(!$core.assert($1)){
+if(!$core.assert($recv(anError)._wasHandled())){
 $recv($self._current())._handleError_(anError);
 $recv($self._current())._handleError_(anError);
 $recv(anError)._beHandled();
 $recv(anError)._beHandled();
 }
 }
@@ -1959,36 +1952,37 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anInspector"],
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#keys' put: self keys.\x0a\x09self keysAndValuesDo: [ :key :value |\x0a\x09\x09variables at: key put: value ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-referencedClasses: ["Dictionary"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Array streamContents: [ :stream |\x0a\x09\x09stream\x0a\x09\x09\x09nextPut: '#self' -> self;\x0a\x09\x09\x09nextPut: '#keys' -> self keys;\x0a\x09\x09\x09nextPutAll: self associations ].\x0a\x09anInspector\x0a\x09\x09setLabel: self shortenedPrintString;\x0a\x09\x09setVariables: variables",
+referencedClasses: ["Array"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["new", "at:put:", "keys", "keysAndValuesDo:", "setLabel:", "printString", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "keys", "nextPutAll:", "associations", "setLabel:", "shortenedPrintString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var self=this,$self=this;
 var variables;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+variables=$recv($globals.Array)._streamContents_((function(stream){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#keys",$self._keys());
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=2;
+,$ctx2.sendIdx["->"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._keysAndValuesDo_((function(key,value){
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+,$ctx2.sendIdx["nextPut:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv(variables)._at_put_(key,value);
+][0];
+$recv(stream)._nextPut_("#keys".__minus_gt($self._keys()));
+return $recv(stream)._nextPutAll_($self._associations());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1,1)});
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }));
 }));
-$recv(anInspector)._setLabel_($self._printString());
+$recv(anInspector)._setLabel_($self._shortenedPrintString());
 $recv(anInspector)._setVariables_(variables);
 $recv(anInspector)._setVariables_(variables);
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2003,32 +1997,48 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anInspector"],
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09self withIndexDo: [ :each :i |\x0a\x09\x09variables at: i put: each ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-referencedClasses: ["Dictionary"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Array streamContents: [ :stream |\x0a\x09\x09| i |\x0a\x09\x09stream nextPut: '#self' -> self.\x0a\x09\x09i := 1.\x0a\x09\x09self do: [ :each |\x0a\x09\x09\x09stream nextPut: i -> each.\x0a\x09\x09\x09i := i + 1 ] ].\x0a\x09anInspector\x0a\x09\x09setLabel: self shortenedPrintString;\x0a\x09\x09setVariables: variables",
+referencedClasses: ["Array"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["new", "at:put:", "withIndexDo:", "setLabel:", "printString", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "do:", "+", "setLabel:", "shortenedPrintString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var self=this,$self=this;
 var variables;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+variables=$recv($globals.Array)._streamContents_((function(stream){
+var i;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._withIndexDo_((function(each,i){
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+,$ctx2.sendIdx["->"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv(variables)._at_put_(i,each);
+][0])
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["nextPut:"]=1
+//>>excludeEnd("ctx");
+][0];
+i=(1);
+return $self._do_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({each:each,i:i},$ctx1,1)});
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+$recv(stream)._nextPut_($recv(i).__minus_gt(each));
+i=$recv(i).__plus((1));
+return i;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({each:each},$ctx2,2)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }));
 }));
-$recv(anInspector)._setLabel_($self._printString());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({stream:stream,i:i},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+$recv(anInspector)._setLabel_($self._shortenedPrintString());
 $recv(anInspector)._setVariables_(variables);
 $recv(anInspector)._setVariables_(variables);
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2043,47 +2053,89 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anInspector"],
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#year' put: self year.\x0a\x09variables at: '#month' put: self month.\x0a\x09variables at: '#day' put: self day.\x0a\x09variables at: '#hours' put: self hours.\x0a\x09variables at: '#minutes' put: self minutes.\x0a\x09variables at: '#seconds' put: self seconds.\x0a\x09variables at: '#milliseconds' put: self milliseconds.\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-referencedClasses: ["Dictionary"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Array streamContents: [ :stream |\x0a\x09\x09stream\x0a\x09\x09\x09nextPut: '#self' -> self;\x0a\x09\x09\x09nextPut: '#year' -> self year;\x0a\x09\x09\x09nextPut: '#month' -> self month;\x0a\x09\x09\x09nextPut: '#day' -> self day;\x0a\x09\x09\x09nextPut: '#hours' -> self hours;\x0a\x09\x09\x09nextPut: '#minutes' -> self minutes;\x0a\x09\x09\x09nextPut: '#seconds' -> self seconds;\x0a\x09\x09\x09nextPut: '#milliseconds' -> self milliseconds ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+referencedClasses: ["Array"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["new", "at:put:", "year", "month", "day", "hours", "minutes", "seconds", "milliseconds", "setLabel:", "printString", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "year", "month", "day", "hours", "minutes", "seconds", "milliseconds", "setLabel:", "printString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var self=this,$self=this;
 var variables;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+variables=$recv($globals.Array)._streamContents_((function(stream){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["->"]=1
+//>>excludeEnd("ctx");
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+,$ctx2.sendIdx["nextPut:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#year",$self._year());
+][0];
+[$recv(stream)._nextPut_(["#year".__minus_gt($self._year())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=2;
+,$ctx2.sendIdx["->"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#month",$self._month());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=3;
+,$ctx2.sendIdx["nextPut:"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#day",$self._day());
+][0];
+[$recv(stream)._nextPut_(["#month".__minus_gt($self._month())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=4;
+,$ctx2.sendIdx["->"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#hours",$self._hours());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=5;
+,$ctx2.sendIdx["nextPut:"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#minutes",$self._minutes());
+][0];
+[$recv(stream)._nextPut_(["#day".__minus_gt($self._day())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=6;
+,$ctx2.sendIdx["->"]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#seconds",$self._seconds());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=7;
+,$ctx2.sendIdx["nextPut:"]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#milliseconds",$self._milliseconds());
+][0];
+[$recv(stream)._nextPut_(["#hours".__minus_gt($self._hours())
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["->"]=5
+//>>excludeEnd("ctx");
+][0])
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["nextPut:"]=5
+//>>excludeEnd("ctx");
+][0];
+[$recv(stream)._nextPut_(["#minutes".__minus_gt($self._minutes())
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["->"]=6
+//>>excludeEnd("ctx");
+][0])
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["nextPut:"]=6
+//>>excludeEnd("ctx");
+][0];
+[$recv(stream)._nextPut_(["#seconds".__minus_gt($self._seconds())
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["->"]=7
+//>>excludeEnd("ctx");
+][0])
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["nextPut:"]=7
+//>>excludeEnd("ctx");
+][0];
+return $recv(stream)._nextPut_("#milliseconds".__minus_gt($self._milliseconds()));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
 $recv(anInspector)._setLabel_($self._printString());
 $recv(anInspector)._setLabel_($self._printString());
 $recv(anInspector)._setVariables_(variables);
 $recv(anInspector)._setVariables_(variables);
 return self;
 return self;
@@ -2099,21 +2151,28 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anInspector"],
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self jsObject.\x0a\x09anInspector setLabel: self printString.\x0a\x09JSObjectProxy addObjectVariablesTo: variables ofProxy: self.\x0a\x09anInspector setVariables: variables",
-referencedClasses: ["Dictionary", "JSObjectProxy"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Array streamContents: [ :stream |\x0a\x09\x09stream\x0a\x09\x09\x09nextPut: '#self' -> self jsObject;\x0a\x09\x09\x09nextPutAll: (JSObjectProxy associationsOfProxy: self) ].\x0a\x09anInspector setLabel: self printString.\x0a\x09anInspector setVariables: variables",
+referencedClasses: ["Array", "JSObjectProxy"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["new", "at:put:", "jsObject", "setLabel:", "printString", "addObjectVariablesTo:ofProxy:", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "jsObject", "nextPutAll:", "associationsOfProxy:", "setLabel:", "printString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var self=this,$self=this;
 var variables;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",$self._jsObject());
+variables=$recv($globals.Array)._streamContents_((function(stream){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$recv(stream)._nextPut_("#self".__minus_gt($self._jsObject()));
+return $recv(stream)._nextPutAll_($recv($globals.JSObjectProxy)._associationsOfProxy_(self));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
 $recv(anInspector)._setLabel_($self._printString());
 $recv(anInspector)._setLabel_($self._printString());
-$recv($globals.JSObjectProxy)._addObjectVariablesTo_ofProxy_(variables,self);
 $recv(anInspector)._setVariables_(variables);
 $recv(anInspector)._setVariables_(variables);
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2128,29 +2187,41 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anInspector"],
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09self class allInstanceVariableNames do: [ :each |\x0a\x09\x09variables at: each put: (self instVarAt: each) ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-referencedClasses: ["Dictionary"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Array streamContents: [ :stream |\x0a\x09\x09stream nextPut: '#self' -> self.\x0a\x09\x09self class allInstanceVariableNames do: [ :each |\x0a\x09\x09\x09stream nextPut: each -> (self instVarNamed: each) ] ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+referencedClasses: ["Array"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["new", "at:put:", "do:", "allInstanceVariableNames", "class", "instVarAt:", "setLabel:", "printString", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "do:", "allInstanceVariableNames", "class", "instVarNamed:", "setLabel:", "printString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var self=this,$self=this;
 var variables;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+variables=$recv($globals.Array)._streamContents_((function(stream){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($recv($self._class())._allInstanceVariableNames())._do_((function(each){
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+,$ctx2.sendIdx["->"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv(variables)._at_put_(each,$self._instVarAt_(each));
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)});
+,$ctx2.sendIdx["nextPut:"]=1
+//>>excludeEnd("ctx");
+][0];
+return $recv($recv($self._class())._allInstanceVariableNames())._do_((function(each){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(stream)._nextPut_($recv(each).__minus_gt($self._instVarNamed_(each)));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({each:each},$ctx2,2)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }));
 }));
 $recv(anInspector)._setLabel_($self._printString());
 $recv(anInspector)._setLabel_($self._printString());
@@ -2192,42 +2263,51 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anInspector"],
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables i |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09i := 1.\x0a\x09self do: [ :each |\x0a\x09\x09variables at: i put: each.\x0a\x09\x09i := i + 1 ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-referencedClasses: ["Dictionary"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Array streamContents: [ :stream |\x0a\x09\x09stream nextPut: '#self' -> self.\x0a\x09\x09self withIndexDo: [ :each :i |\x0a\x09\x09\x09stream nextPut: i -> each ] ].\x0a\x09anInspector\x0a\x09\x09setLabel: self shortenedPrintString;\x0a\x09\x09setVariables: variables",
+referencedClasses: ["Array"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["new", "at:put:", "do:", "+", "setLabel:", "printString", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "withIndexDo:", "setLabel:", "shortenedPrintString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var self=this,$self=this;
-var variables,i;
+var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+variables=$recv($globals.Array)._streamContents_((function(stream){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-i=(1);
-$self._do_((function(each){
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+,$ctx2.sendIdx["->"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_(i,each);
-i=$recv(i).__plus((1));
-return i;
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)});
+,$ctx2.sendIdx["nextPut:"]=1
+//>>excludeEnd("ctx");
+][0];
+return $self._withIndexDo_((function(each,i){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(stream)._nextPut_($recv(i).__minus_gt(each));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({each:each,i:i},$ctx2,2)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }));
 }));
-$recv(anInspector)._setLabel_($self._printString());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+$recv(anInspector)._setLabel_($self._shortenedPrintString());
 $recv(anInspector)._setVariables_(variables);
 $recv(anInspector)._setVariables_(variables);
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables,i:i})});
+}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }; }),
 }; }),
-$globals.Set);
+$globals.SequenceableCollection);
 
 
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
@@ -2235,97 +2315,77 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anInspector"],
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| label |\x0a\x09super inspectOn: anInspector.\x0a\x09self printString size > 30\x0a\x09\x09ifTrue: [ label := (self printString copyFrom: 1 to: 30), '...''' ]\x0a\x09\x09ifFalse: [ label := self printString ].\x0a\x09anInspector setLabel: label",
-referencedClasses: [],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Array streamContents: [ :stream |\x0a\x09\x09stream\x0a\x09\x09\x09nextPut: '#self' -> self;\x0a\x09\x09\x09nextPut: '#home' -> self home;\x0a\x09\x09\x09nextPut: '#receiver' -> self receiver;\x0a\x09\x09\x09nextPut: '#selector' -> self selector;\x0a\x09\x09\x09nextPut: '#locals' -> self locals.\x0a\x09self class instanceVariableNames do: [ :each |\x0a\x09\x09stream nextPut: each -> (self instVarNamed: each) ] ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+referencedClasses: ["Array"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["inspectOn:", "ifTrue:ifFalse:", ">", "size", "printString", ",", "copyFrom:to:", "setLabel:"]
+messageSends: ["streamContents:", "nextPut:", "->", "home", "receiver", "selector", "locals", "do:", "instanceVariableNames", "class", "instVarNamed:", "setLabel:", "printString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var self=this,$self=this;
-var label;
+var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $3,$2,$1,$5,$4;
-(
+variables=$recv($globals.Array)._streamContents_((function(stream){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = true,
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._inspectOn_.call($self,anInspector));
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-$3=$self._printString();
+,$ctx2.sendIdx["->"]=1
+//>>excludeEnd("ctx");
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["printString"]=1;
+,$ctx2.sendIdx["nextPut:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$recv($3)._size();
-$1=$recv($2).__gt((30));
-if($core.assert($1)){
-$5=$self._printString();
+][0];
+[$recv(stream)._nextPut_(["#home".__minus_gt($self._home())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["printString"]=2;
+,$ctx2.sendIdx["->"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$4=$recv($5)._copyFrom_to_((1),(30));
-label=$recv($4).__comma("...'");
-label;
-} else {
-label=$self._printString();
-label;
-}
-$recv(anInspector)._setLabel_(label);
-return self;
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,label:label})});
+,$ctx2.sendIdx["nextPut:"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}; }),
-$globals.String);
-
-$core.addMethod(
-$core.method({
-selector: "inspectOn:",
-protocol: "*Platform-Services",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#home' put: self home.\x0a\x09variables at: '#receiver' put: self receiver.\x0a\x09variables at: '#selector' put: self selector.\x0a\x09variables at: '#locals' put: self locals.\x0a\x09self class instanceVariableNames do: [ :each |\x0a\x09\x09variables at: each put: (self instVarAt: each) ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-referencedClasses: ["Dictionary"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["new", "at:put:", "home", "receiver", "selector", "locals", "do:", "instanceVariableNames", "class", "instVarAt:", "setLabel:", "printString", "setVariables:"]
-}, function ($methodClass){ return function (anInspector){
-var self=this,$self=this;
-var variables;
+][0];
+[$recv(stream)._nextPut_(["#receiver".__minus_gt($self._receiver())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
+,$ctx2.sendIdx["->"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+,$ctx2.sendIdx["nextPut:"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#home",$self._home());
+][0];
+[$recv(stream)._nextPut_(["#selector".__minus_gt($self._selector())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=2;
+,$ctx2.sendIdx["->"]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#receiver",$self._receiver());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=3;
+,$ctx2.sendIdx["nextPut:"]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#selector",$self._selector());
+][0];
+[$recv(stream)._nextPut_(["#locals".__minus_gt($self._locals())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=4;
+,$ctx2.sendIdx["->"]=5
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#locals",$self._locals());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=5;
+,$ctx2.sendIdx["nextPut:"]=5
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($recv($self._class())._instanceVariableNames())._do_((function(each){
+][0];
+return $recv($recv($self._class())._instanceVariableNames())._do_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv(variables)._at_put_(each,$self._instVarAt_(each));
+return $recv(stream)._nextPut_($recv(each).__minus_gt($self._instVarNamed_(each)));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)});
+}, function($ctx3) {$ctx3.fillBlock({each:each},$ctx2,2)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }));
 }));
 $recv(anInspector)._setLabel_($self._printString());
 $recv(anInspector)._setLabel_($self._printString());

+ 48 - 57
lang/src/Platform-Services.st

@@ -257,7 +257,7 @@ compileMethod: sourceCode for: class protocol: protocol
 evaluate: aBlock on: anErrorClass do: exceptionBlock
 evaluate: aBlock on: anErrorClass do: exceptionBlock
 	"Evaluate a block and catch exceptions happening on the environment stack"
 	"Evaluate a block and catch exceptions happening on the environment stack"
 	
 	
-	^ Smalltalk do: aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock
+	^ aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock
 ! !
 ! !
 
 
 !Environment methodsFor: 'evaluating'!
 !Environment methodsFor: 'evaluating'!
@@ -534,13 +534,13 @@ show: anObject
 
 
 inspectOn: anInspector
 inspectOn: anInspector
 	| variables |
 	| variables |
-	variables := Dictionary new.
-	variables at: '#self' put: self.
-	variables at: '#keys' put: self keys.
-	self keysAndValuesDo: [ :key :value |
-		variables at: key put: value ].
+	variables := Array streamContents: [ :stream |
+		stream
+			nextPut: '#self' -> self;
+			nextPut: '#keys' -> self keys;
+			nextPutAll: self associations ].
 	anInspector
 	anInspector
-		setLabel: self printString;
+		setLabel: self shortenedPrintString;
 		setVariables: variables
 		setVariables: variables
 ! !
 ! !
 
 
@@ -548,12 +548,15 @@ inspectOn: anInspector
 
 
 inspectOn: anInspector
 inspectOn: anInspector
 	| variables |
 	| variables |
-	variables := Dictionary new.
-	variables at: '#self' put: self.
-	self withIndexDo: [ :each :i |
-		variables at: i put: each ].
+	variables := Array streamContents: [ :stream |
+		| i |
+		stream nextPut: '#self' -> self.
+		i := 1.
+		self do: [ :each |
+			stream nextPut: i -> each.
+			i := i + 1 ] ].
 	anInspector
 	anInspector
-		setLabel: self printString;
+		setLabel: self shortenedPrintString;
 		setVariables: variables
 		setVariables: variables
 ! !
 ! !
 
 
@@ -561,15 +564,16 @@ inspectOn: anInspector
 
 
 inspectOn: anInspector
 inspectOn: anInspector
 	| variables |
 	| variables |
-	variables := Dictionary new.
-	variables at: '#self' put: self.
-	variables at: '#year' put: self year.
-	variables at: '#month' put: self month.
-	variables at: '#day' put: self day.
-	variables at: '#hours' put: self hours.
-	variables at: '#minutes' put: self minutes.
-	variables at: '#seconds' put: self seconds.
-	variables at: '#milliseconds' put: self milliseconds.
+	variables := Array streamContents: [ :stream |
+		stream
+			nextPut: '#self' -> self;
+			nextPut: '#year' -> self year;
+			nextPut: '#month' -> self month;
+			nextPut: '#day' -> self day;
+			nextPut: '#hours' -> self hours;
+			nextPut: '#minutes' -> self minutes;
+			nextPut: '#seconds' -> self seconds;
+			nextPut: '#milliseconds' -> self milliseconds ].
 	anInspector
 	anInspector
 		setLabel: self printString;
 		setLabel: self printString;
 		setVariables: variables
 		setVariables: variables
@@ -579,10 +583,11 @@ inspectOn: anInspector
 
 
 inspectOn: anInspector
 inspectOn: anInspector
 	| variables |
 	| variables |
-	variables := Dictionary new.
-	variables at: '#self' put: self jsObject.
+	variables := Array streamContents: [ :stream |
+		stream
+			nextPut: '#self' -> self jsObject;
+			nextPutAll: (JSObjectProxy associationsOfProxy: self) ].
 	anInspector setLabel: self printString.
 	anInspector setLabel: self printString.
-	JSObjectProxy addObjectVariablesTo: variables ofProxy: self.
 	anInspector setVariables: variables
 	anInspector setVariables: variables
 ! !
 ! !
 
 
@@ -590,10 +595,10 @@ inspectOn: anInspector
 
 
 inspectOn: anInspector
 inspectOn: anInspector
 	| variables |
 	| variables |
-	variables := Dictionary new.
-	variables at: '#self' put: self.
-	self class allInstanceVariableNames do: [ :each |
-		variables at: each put: (self instVarAt: each) ].
+	variables := Array streamContents: [ :stream |
+		stream nextPut: '#self' -> self.
+		self class allInstanceVariableNames do: [ :each |
+			stream nextPut: each -> (self instVarNamed: each) ] ].
 	anInspector
 	anInspector
 		setLabel: self printString;
 		setLabel: self printString;
 		setVariables: variables
 		setVariables: variables
@@ -606,46 +611,32 @@ do: aBlock displayingProgress: aString
 		do: aBlock 
 		do: aBlock 
 		on: self 
 		on: self 
 		displaying: aString
 		displaying: aString
-! !
-
-!Set methodsFor: '*Platform-Services'!
+!
 
 
 inspectOn: anInspector
 inspectOn: anInspector
-	| variables i |
-	variables := Dictionary new.
-	variables at: '#self' put: self.
-	i := 1.
-	self do: [ :each |
-		variables at: i put: each.
-		i := i + 1 ].
+	| variables |
+	variables := Array streamContents: [ :stream |
+		stream nextPut: '#self' -> self.
+		self withIndexDo: [ :each :i |
+			stream nextPut: i -> each ] ].
 	anInspector
 	anInspector
-		setLabel: self printString;
+		setLabel: self shortenedPrintString;
 		setVariables: variables
 		setVariables: variables
 ! !
 ! !
 
 
-!String methodsFor: '*Platform-Services'!
-
-inspectOn: anInspector
-	| label |
-	super inspectOn: anInspector.
-	self printString size > 30
-		ifTrue: [ label := (self printString copyFrom: 1 to: 30), '...''' ]
-		ifFalse: [ label := self printString ].
-	anInspector setLabel: label
-! !
-
 !TMethodContext methodsFor: '*Platform-Services'!
 !TMethodContext methodsFor: '*Platform-Services'!
 
 
 inspectOn: anInspector
 inspectOn: anInspector
 	| variables |
 	| variables |
-	variables := Dictionary new.
-	variables at: '#self' put: self.
-	variables at: '#home' put: self home.
-	variables at: '#receiver' put: self receiver.
-	variables at: '#selector' put: self selector.
-	variables at: '#locals' put: self locals.
+	variables := Array streamContents: [ :stream |
+		stream
+			nextPut: '#self' -> self;
+			nextPut: '#home' -> self home;
+			nextPut: '#receiver' -> self receiver;
+			nextPut: '#selector' -> self selector;
+			nextPut: '#locals' -> self locals.
 	self class instanceVariableNames do: [ :each |
 	self class instanceVariableNames do: [ :each |
-		variables at: each put: (self instVarAt: each) ].
+		stream nextPut: each -> (self instVarNamed: each) ] ].
 	anInspector
 	anInspector
 		setLabel: self printString;
 		setLabel: self printString;
 		setVariables: variables
 		setVariables: variables

+ 92 - 86
lang/src/SUnit-Tests.js

@@ -99,7 +99,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._should_raise_((function(){
+[$self._should_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -107,10 +107,11 @@ return $recv($self.empty)._at_((5));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}),$globals.Error);
+}),$globals.Error)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["should:raise:"]=1;
+,$ctx1.sendIdx["should:raise:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self._should_raise_((function(){
 $self._should_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
@@ -143,15 +144,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($self.full)._includes_((5));
+[$self._assert_([$recv($self.full)._includes_((5))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["includes:"]=1;
+,$ctx1.sendIdx["includes:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._assert_($1);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["assert:"]=1;
+,$ctx1.sendIdx["assert:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self._assert_($recv($self.full)._includes_("abc"));
 $self._assert_($recv($self.full)._includes_("abc"));
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -176,23 +177,24 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2;
-$1=$recv($self.empty)._occurrencesOf_((0));
+[$self._assert_equals_([$recv($self.empty)._occurrencesOf_((0))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["occurrencesOf:"]=1;
+,$ctx1.sendIdx["occurrencesOf:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._assert_equals_($1,(0));
+][0],(0))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["assert:equals:"]=1;
+,$ctx1.sendIdx["assert:equals:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$recv($self.full)._occurrencesOf_((5));
+][0];
+[$self._assert_equals_([$recv($self.full)._occurrencesOf_((5))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["occurrencesOf:"]=2;
+,$ctx1.sendIdx["occurrencesOf:"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._assert_equals_($2,(1));
+][0],(1))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["assert:equals:"]=2;
+,$ctx1.sendIdx["assert:equals:"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $recv($self.full)._add_((5));
 $recv($self.full)._add_((5));
 $self._assert_equals_($recv($self.full)._occurrencesOf_((5)),(1));
 $self._assert_equals_($recv($self.full)._occurrencesOf_((5)),(1));
 return self;
 return self;
@@ -218,13 +220,12 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 $recv($self.full)._remove_((5));
 $recv($self.full)._remove_((5));
-$1=$recv($self.full)._includes_("abc");
+$self._assert_([$recv($self.full)._includes_("abc")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["includes:"]=1;
+,$ctx1.sendIdx["includes:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._assert_($1);
+][0]);
 $self._deny_($recv($self.full)._includes_((5)));
 $self._deny_($recv($self.full)._includes_((5)));
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -356,12 +357,12 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$self._timeout_((100));
+[$self._timeout_((100))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["timeout:"]=1;
+,$ctx1.sendIdx["timeout:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$self._async_((function(){
+][0];
+[$recv([$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -378,14 +379,15 @@ return $self._finished();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["async:"]=1;
+,$ctx1.sendIdx["async:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($1)._valueWithTimeout_((20));
+][0])._valueWithTimeout_((20))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["valueWithTimeout:"]=1;
+,$ctx1.sendIdx["valueWithTimeout:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"fakeMultipleTimeoutFailing",{})});
 }, function($ctx1) {$ctx1.fill(self,"fakeMultipleTimeoutFailing",{})});
@@ -409,12 +411,12 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$self._timeout_((20));
+[$self._timeout_((20))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["timeout:"]=1;
+,$ctx1.sendIdx["timeout:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$self._async_((function(){
+][0];
+[$recv([$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -431,14 +433,15 @@ return $self._finished();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["async:"]=1;
+,$ctx1.sendIdx["async:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($1)._valueWithTimeout_((10));
+][0])._valueWithTimeout_((10))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["valueWithTimeout:"]=1;
+,$ctx1.sendIdx["valueWithTimeout:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"fakeMultipleTimeoutPassing",{})});
 }, function($ctx1) {$ctx1.fill(self,"fakeMultipleTimeoutPassing",{})});
@@ -570,7 +573,6 @@ var suite,runner,result,assertBlock;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$3,$4;
 suite=["fakeError", "fakeErrorFailingInTearDown", "fakeFailure", "testPass"]._collect_((function(each){
 suite=["fakeError", "fakeErrorFailingInTearDown", "fakeFailure", "testPass"]._collect_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
@@ -582,26 +584,28 @@ return $recv($self._class())._selector_(each);
 }));
 }));
 runner=$recv($globals.TestSuiteRunner)._on_(suite);
 runner=$recv($globals.TestSuiteRunner)._on_(suite);
 $self._timeout_((200));
 $self._timeout_((200));
-result=$recv(runner)._result();
+result=[$recv(runner)._result()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["result"]=1;
+,$ctx1.sendIdx["result"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 assertBlock=$self._async_((function(){
 assertBlock=$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$self._selectorSetOf_($recv(result)._errors());
+[$self._assert_equals_([$self._selectorSetOf_($recv(result)._errors())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["selectorSetOf:"]=1;
+,$ctx2.sendIdx["selectorSetOf:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=["fakeError"]._asSet();
+][0],[["fakeError"]._asSet()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["asSet"]=1;
+,$ctx2.sendIdx["asSet"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._assert_equals_($1,$2);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["assert:equals:"]=1;
+,$ctx2.sendIdx["assert:equals:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self._assert_equals_($self._selectorSetOf_($recv(result)._failures()),["fakeErrorFailingInTearDown", "fakeFailure"]._asSet());
 $self._assert_equals_($self._selectorSetOf_($recv(result)._failures()),["fakeErrorFailingInTearDown", "fakeFailure"]._asSet());
 return $self._finished();
 return $self._finished();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -612,10 +616,8 @@ $recv($recv(runner)._announcer())._on_do_($globals.ResultAnnouncement,(function(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$3=$recv($recv(ann)._result()).__eq_eq(result);
-if($core.assert($3)){
-$4=$recv($recv(result)._runs()).__eq($recv(result)._total());
-return $recv($4)._ifTrue_(assertBlock);
+if($core.assert($recv($recv(ann)._result()).__eq_eq(result))){
+return $recv($recv($recv(result)._runs()).__eq($recv(result)._total()))._ifTrue_(assertBlock);
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1,3)});
 }, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1,3)});
@@ -649,12 +651,13 @@ $self._should_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $self._async_((function(){
+return [$self._async_((function(){
 
 
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["async:"]=1;
+,$ctx2.sendIdx["async:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -699,10 +702,11 @@ $self._should_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $self._finished();
+return [$self._finished()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["finished"]=1;
+,$ctx2.sendIdx["finished"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -740,21 +744,21 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2;
-$1=$self._isAsync();
+[$self._deny_([$self._isAsync()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["isAsync"]=1;
+,$ctx1.sendIdx["isAsync"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._deny_($1);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["deny:"]=1;
+,$ctx1.sendIdx["deny:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self._timeout_((0));
 $self._timeout_((0));
-$2=$self._isAsync();
+$self._assert_([$self._isAsync()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["isAsync"]=2;
+,$ctx1.sendIdx["isAsync"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._assert_($2);
+][0]);
 $self._finished();
 $self._finished();
 $self._deny_($self._isAsync());
 $self._deny_($self._isAsync());
 return self;
 return self;
@@ -818,7 +822,6 @@ var suite,runner,result,assertBlock;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2,$3;
 suite=["fakeTimeout", "fakeMultipleTimeoutFailing", "fakeMultipleTimeoutPassing", "testPass"]._collect_((function(each){
 suite=["fakeTimeout", "fakeMultipleTimeoutFailing", "fakeMultipleTimeoutPassing", "testPass"]._collect_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
@@ -830,22 +833,24 @@ return $recv($self._class())._selector_(each);
 }));
 }));
 runner=$recv($globals.TestSuiteRunner)._on_(suite);
 runner=$recv($globals.TestSuiteRunner)._on_(suite);
 $self._timeout_((200));
 $self._timeout_((200));
-result=$recv(runner)._result();
+result=[$recv(runner)._result()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["result"]=1;
+,$ctx1.sendIdx["result"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 assertBlock=$self._async_((function(){
 assertBlock=$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$self._selectorSetOf_($recv(result)._errors());
+[$self._assert_equals_([$self._selectorSetOf_($recv(result)._errors())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["selectorSetOf:"]=1;
+,$ctx2.sendIdx["selectorSetOf:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._assert_equals_($1,$recv($globals.Set)._new());
+][0],$recv($globals.Set)._new())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["assert:equals:"]=1;
+,$ctx2.sendIdx["assert:equals:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self._assert_equals_($self._selectorSetOf_($recv(result)._failures()),["fakeMultipleTimeoutFailing", "fakeTimeout"]._asSet());
 $self._assert_equals_($self._selectorSetOf_($recv(result)._failures()),["fakeMultipleTimeoutFailing", "fakeTimeout"]._asSet());
 return $self._finished();
 return $self._finished();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -856,10 +861,8 @@ $recv($recv(runner)._announcer())._on_do_($globals.ResultAnnouncement,(function(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$recv($recv(ann)._result()).__eq_eq(result);
-if($core.assert($2)){
-$3=$recv($recv(result)._runs()).__eq($recv(result)._total());
-return $recv($3)._ifTrue_(assertBlock);
+if($core.assert($recv($recv(ann)._result()).__eq_eq(result))){
+return $recv($recv($recv(result)._runs()).__eq($recv(result)._total()))._ifTrue_(assertBlock);
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1,3)});
 }, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1,3)});
@@ -890,38 +893,41 @@ var x;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 $self.flag="bad";
 $self.flag="bad";
 $self._timeout_((10));
 $self._timeout_((10));
 x=(0);
 x=(0);
-$1=$self._async_((function(){
+$self.flag=[$recv([$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._finished();
+[$self._finished()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["finished"]=1;
+,$ctx2.sendIdx["finished"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self.flag="ok";
 $self.flag="ok";
-x=$recv(x).__plus((1));
+x=[$recv(x).__plus((1))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["+"]=1;
+,$ctx2.sendIdx["+"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $self._assert_equals_(x,(1));
+][0];
+return [$self._assert_equals_(x,(1))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["assert:equals:"]=1;
+,$ctx2.sendIdx["assert:equals:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["async:"]=1;
+,$ctx1.sendIdx["async:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self.flag=$recv($1)._valueWithTimeout_((0));
+][0])._valueWithTimeout_((0))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["valueWithTimeout:"]=1;
+,$ctx1.sendIdx["valueWithTimeout:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self.flag=$recv($self._async_((function(){
 $self.flag=$recv($self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {

+ 421 - 86
lang/src/SUnit.js

@@ -47,6 +47,215 @@ $globals.ResultAnnouncement);
 
 
 
 
 
 
+$core.addClass("Teachable", $globals.Object, ["learnings"], "SUnit");
+//>>excludeStart("ide", pragmas.excludeIdeData);
+$globals.Teachable.comment="An object you can teach how to behave. Have a look at the \x0aclass side for an example.\x0a\x0aFor more infos have a look at: http://lists.squeakfoundation.org/pipermail/squeak-dev/2002-April/038170.html";
+//>>excludeEnd("ide");
+$core.addMethod(
+$core.method({
+selector: "acceptSend:",
+protocol: "teaching",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aSymbol"],
+source: "acceptSend: aSymbol\x0a\x0a\x09self whenSend: aSymbol return: self",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["whenSend:return:"]
+}, function ($methodClass){ return function (aSymbol){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._whenSend_return_(aSymbol,self);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"acceptSend:",{aSymbol:aSymbol})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Teachable);
+
+$core.addMethod(
+$core.method({
+selector: "doesNotUnderstand:",
+protocol: "private",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aMessage"],
+source: "doesNotUnderstand: aMessage\x0a\x0a\x09| learning |\x0a\x09learning := self learnings \x0a\x09\x09at: aMessage selector \x0a\x09\x09ifAbsent:[ ^super doesNotUnderstand: aMessage ].\x0a\x09^ learning class == Association\x0a\x09\x09ifTrue: [learning value]\x0a\x09\x09ifFalse: [learning valueWithPossibleArguments: aMessage arguments]",
+referencedClasses: ["Association"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["at:ifAbsent:", "learnings", "selector", "doesNotUnderstand:", "ifTrue:ifFalse:", "==", "class", "value", "valueWithPossibleArguments:", "arguments"]
+}, function ($methodClass){ return function (aMessage){
+var self=this,$self=this;
+var learning;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $early={};
+try {
+learning=$recv($self._learnings())._at_ifAbsent_($recv(aMessage)._selector(),(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+throw $early=[[(
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.supercall = true,
+//>>excludeEnd("ctx");
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._doesNotUnderstand_.call($self,aMessage))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.supercall = false
+//>>excludeEnd("ctx");
+][0]];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+if($core.assert($recv($recv(learning)._class()).__eq_eq($globals.Association))){
+return $recv(learning)._value();
+} else {
+return $recv(learning)._valueWithPossibleArguments_($recv(aMessage)._arguments());
+}
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"doesNotUnderstand:",{aMessage:aMessage,learning:learning})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Teachable);
+
+$core.addMethod(
+$core.method({
+selector: "learnings",
+protocol: "private",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "learnings\x0a\x0a\x09learnings isNil ifTrue: [learnings := Dictionary new].\x0a\x09^learnings",
+referencedClasses: ["Dictionary"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["ifTrue:", "isNil", "new"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+if($core.assert($recv($self.learnings)._isNil())){
+$self.learnings=$recv($globals.Dictionary)._new();
+$self.learnings;
+}
+return $self.learnings;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"learnings",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Teachable);
+
+$core.addMethod(
+$core.method({
+selector: "whenSend:evaluate:",
+protocol: "teaching",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aSymbol", "aBlock"],
+source: "whenSend: aSymbol evaluate: aBlock\x0a\x0a\x09self learnings at: aSymbol put: aBlock",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["at:put:", "learnings"]
+}, function ($methodClass){ return function (aSymbol,aBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv($self._learnings())._at_put_(aSymbol,aBlock);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"whenSend:evaluate:",{aSymbol:aSymbol,aBlock:aBlock})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Teachable);
+
+$core.addMethod(
+$core.method({
+selector: "whenSend:return:",
+protocol: "teaching",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aSymbol", "anObject"],
+source: "whenSend: aSymbol return: anObject\x0a\x0a\x09self learnings at: aSymbol put: (#return -> anObject)",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["at:put:", "learnings", "->"]
+}, function ($methodClass){ return function (aSymbol,anObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv($self._learnings())._at_put_(aSymbol,"return".__minus_gt(anObject));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"whenSend:return:",{aSymbol:aSymbol,anObject:anObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Teachable);
+
+
+$core.addMethod(
+$core.method({
+selector: "example",
+protocol: "examples",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "example\x0a\x09| teachable |\x0a\x09teachable := self new.\x0a\x09teachable \x0a\x09\x09whenSend: #help return: 'ok';\x0a\x09\x09whenSend: #doit evaluate: [1 inspect];\x0a\x09\x09acceptSend: #noDebugger;\x0a\x09\x09whenSend: #negate: evaluate: [:num | num negated].\x0a\x09teachable help.\x0a\x09teachable doit.\x0a\x09teachable noDebugger.\x0a\x09teachable negate: 120",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["new", "whenSend:return:", "whenSend:evaluate:", "inspect", "acceptSend:", "negated", "help", "doit", "noDebugger", "negate:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+var teachable;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+teachable=$self._new();
+$1=teachable;
+$recv($1)._whenSend_return_("help","ok");
+[$recv($1)._whenSend_evaluate_("doit",(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return (1)._inspect();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["whenSend:evaluate:"]=1
+//>>excludeEnd("ctx");
+][0];
+$recv($1)._acceptSend_("noDebugger");
+$recv($1)._whenSend_evaluate_("negate:",(function(num){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(num)._negated();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({num:num},$ctx1,2)});
+//>>excludeEnd("ctx");
+}));
+$recv(teachable)._help();
+$recv(teachable)._doit();
+$recv(teachable)._noDebugger();
+$recv(teachable)._negate_((120));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"example",{teachable:teachable})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Teachable.a$cls);
+
+
 $core.addClass("TestCase", $globals.Object, ["testSelector", "asyncTimeout", "context"], "SUnit");
 $core.addClass("TestCase", $globals.Object, ["testSelector", "asyncTimeout", "context"], "SUnit");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.TestCase.comment="I am an implementation of the command pattern to run a test.\x0a\x0a## API\x0a\x0aMy instances are created with the class method `#selector:`,\x0apassing the symbol that names the method to be executed when the test case runs.\x0a\x0aWhen you discover a new fixture, subclass `TestCase` and create a `#test...` method for the first test.\x0aAs that method develops and more `#test...` methods are added, you will find yourself refactoring temps\x0ainto instance variables for the objects in the fixture and overriding `#setUp` to initialize these variables.\x0aAs required, override `#tearDown` to nil references, release objects and deallocate.";
 $globals.TestCase.comment="I am an implementation of the command pattern to run a test.\x0a\x0a## API\x0a\x0aMy instances are created with the class method `#selector:`,\x0apassing the symbol that names the method to be executed when the test case runs.\x0a\x0aWhen you discover a new fixture, subclass `TestCase` and create a `#test...` method for the first test.\x0aAs that method develops and more `#test...` methods are added, you will find yourself refactoring temps\x0ainto instance variables for the objects in the fixture and overriding `#setUp` to initialize these variables.\x0aAs required, override `#tearDown` to nil references, release objects and deallocate.";
@@ -117,22 +326,19 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$5,$4,$3,$2;
-$1=$recv(actual).__eq(expected);
-$5=$recv(expected)._printString();
+return $self._assert_description_($recv(actual).__eq(expected),[$recv([$recv("Expected: ".__comma([$recv(expected)._printString()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["printString"]=1;
+,$ctx1.sendIdx["printString"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$4="Expected: ".__comma($5);
-$3=$recv($4).__comma(" but was: ");
+][0])).__comma(" but was: ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=2;
+,$ctx1.sendIdx[","]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$2=$recv($3).__comma($recv(actual)._printString());
+][0]).__comma($recv(actual)._printString())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $self._assert_description_($1,$2);
+][0]);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"assert:equals:",{actual:actual,expected:expected})});
 }, function($ctx1) {$ctx1.fill(self,"assert:equals:",{actual:actual,expected:expected})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -156,15 +362,13 @@ var c;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 $self._errorIfNotAsync_("#async");
 $self._errorIfNotAsync_("#async");
 c=$self.context;
 c=$self.context;
 return (function(){
 return (function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$self._isAsync();
-if($core.assert($1)){
+if($core.assert($self._isAsync())){
 return $recv(c)._execute_(aBlock);
 return $recv(c)._execute_(aBlock);
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -196,6 +400,30 @@ return self;
 }; }),
 }; }),
 $globals.TestCase);
 $globals.TestCase);
 
 
+$core.addMethod(
+$core.method({
+selector: "debugCase",
+protocol: "running",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "debugCase\x0a\x09\x22Runs a test case in isolated context, debugging all errors.\x22\x0a\x0a\x09(DebugTestContext testCase: self) start",
+referencedClasses: ["DebugTestContext"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["start", "testCase:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv($recv($globals.DebugTestContext)._testCase_(self))._start();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"debugCase",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TestCase);
+
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "deny:",
 selector: "deny:",
@@ -236,9 +464,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._isAsync();
-if(!$core.assert($1)){
+if(!$core.assert($self._isAsync())){
 $self._error_($recv(aString).__comma(" used without prior #timeout:"));
 $self._error_($recv(aString).__comma(" used without prior #timeout:"));
 }
 }
 return self;
 return self;
@@ -557,9 +783,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.asyncTimeout;
 $1=$self.asyncTimeout;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $1;
 $1;
 } else {
 } else {
 $recv($self.asyncTimeout)._clearTimeout();
 $recv($self.asyncTimeout)._clearTimeout();
@@ -588,24 +814,22 @@ selector: "allTestSelectors",
 protocol: "accessing",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
 args: [],
-source: "allTestSelectors\x0a\x09| selectors |\x0a\x09selectors := self testSelectors.\x0a\x09self shouldInheritSelectors ifTrue: [\x0a\x09\x09selectors addAll: self superclass allTestSelectors ].\x0a\x09^ selectors",
+source: "allTestSelectors\x0a\x09| selectors |\x0a\x09selectors := self testSelectors.\x0a\x09self shouldInheritSelectors ifTrue: [\x0a\x09\x09selectors addAll: self superclass allTestSelectors ].\x0a\x09^ selectors asSet",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["testSelectors", "ifTrue:", "shouldInheritSelectors", "addAll:", "allTestSelectors", "superclass"]
+messageSends: ["testSelectors", "ifTrue:", "shouldInheritSelectors", "addAll:", "allTestSelectors", "superclass", "asSet"]
 }, function ($methodClass){ return function (){
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 var self=this,$self=this;
 var selectors;
 var selectors;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 selectors=$self._testSelectors();
 selectors=$self._testSelectors();
-$1=$self._shouldInheritSelectors();
-if($core.assert($1)){
+if($core.assert($self._shouldInheritSelectors())){
 $recv(selectors)._addAll_($recv($self._superclass())._allTestSelectors());
 $recv(selectors)._addAll_($recv($self._superclass())._allTestSelectors());
 }
 }
-return selectors;
+return $recv(selectors)._asSet();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"allTestSelectors",{selectors:selectors})});
 }, function($ctx1) {$ctx1.fill(self,"allTestSelectors",{selectors:selectors})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -677,12 +901,11 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._name();
+return $recv([$self._name()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["name"]=1;
+,$ctx1.sendIdx["name"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv($1).__eq($recv($globals.TestCase)._name());
+][0]).__eq($recv($globals.TestCase)._name());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"isAbstract",{})});
 }, function($ctx1) {$ctx1.fill(self,"isAbstract",{})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -832,11 +1055,11 @@ var failed;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2;
-$recv($self.testCase)._context_(self);
+[$recv($self.testCase)._context_(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["context:"]=1;
+,$ctx1.sendIdx["context:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $recv((function(){
 $recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
@@ -853,23 +1076,22 @@ return failed;
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 $recv($self.testCase)._context_(nil);
 $recv($self.testCase)._context_(nil);
-$1=$recv(failed)._and_((function(){
+if($core.assert($recv(failed)._and_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv($self.testCase)._isAsync();
+return [$recv($self.testCase)._isAsync()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx3.sendIdx["isAsync"]=1;
+,$ctx3.sendIdx["isAsync"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)});
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
-if($core.assert($1)){
+})))){
 $recv($self.testCase)._finished();
 $recv($self.testCase)._finished();
 }
 }
-$2=$recv($self.testCase)._isAsync();
-if(!$core.assert($2)){
+if(!$core.assert($recv($self.testCase)._isAsync())){
 return $recv($self.testCase)._tearDown();
 return $recv($self.testCase)._tearDown();
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -963,6 +1185,119 @@ return $recv($1)._yourself();
 $globals.TestContext.a$cls);
 $globals.TestContext.a$cls);
 
 
 
 
+$core.addClass("DebugTestContext", $globals.TestContext, ["finished", "result"], "SUnit");
+//>>excludeStart("ide", pragmas.excludeIdeData);
+$globals.DebugTestContext.comment="I add error debugging to `TestContext`.\x0a\x0aErrors are caught and explicitly passed to `ErrorHandler`.\x0aI am used in `TestCase >> debugCase`.";
+//>>excludeEnd("ide");
+$core.addMethod(
+$core.method({
+selector: "execute:",
+protocol: "running",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aBlock"],
+source: "execute: aBlock\x0a\x09self withErrorDebugging: [ super execute: aBlock ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["withErrorDebugging:", "execute:"]
+}, function ($methodClass){ return function (aBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._withErrorDebugging_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return [(
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.supercall = true,
+//>>excludeEnd("ctx");
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._execute_.call($self,aBlock))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.supercall = false
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"execute:",{aBlock:aBlock})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.DebugTestContext);
+
+$core.addMethod(
+$core.method({
+selector: "withErrorDebugging:",
+protocol: "private",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aBlock"],
+source: "withErrorDebugging: aBlock\x0a\x09aBlock\x0a\x09\x09on: Error\x0a\x09\x09do: [ :ex | ErrorHandler handleError: ex ]",
+referencedClasses: ["Error", "ErrorHandler"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["on:do:", "handleError:"]
+}, function ($methodClass){ return function (aBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv(aBlock)._on_do_($globals.Error,(function(ex){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv($globals.ErrorHandler)._handleError_(ex);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"withErrorDebugging:",{aBlock:aBlock})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.DebugTestContext);
+
+
+$core.addMethod(
+$core.method({
+selector: "testCase:result:finished:",
+protocol: "instance creation",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aTestCase", "aTestResult", "aBlock"],
+source: "testCase: aTestCase result: aTestResult finished: aBlock\x0a\x09^ (super testCase: aTestCase)\x0a\x09\x09result: aTestResult;\x0a\x09\x09finished: aBlock;\x0a\x09\x09yourself",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["result:", "testCase:", "finished:", "yourself"]
+}, function ($methodClass){ return function (aTestCase,aTestResult,aBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=[(
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = true,
+//>>excludeEnd("ctx");
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._testCase_.call($self,aTestCase))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
+$recv($1)._result_(aTestResult);
+$recv($1)._finished_(aBlock);
+return $recv($1)._yourself();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testCase:result:finished:",{aTestCase:aTestCase,aTestResult:aTestResult,aBlock:aBlock})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.DebugTestContext.a$cls);
+
+
 $core.addClass("ReportingTestContext", $globals.TestContext, ["finished", "result"], "SUnit");
 $core.addClass("ReportingTestContext", $globals.TestContext, ["finished", "result"], "SUnit");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.ReportingTestContext.comment="I add `TestResult` reporting to `TestContext`.\x0a\x0aErrors are caught and save into a `TestResult`,\x0aWhen test case is finished (which can be later for async tests), a callback block is executed; this is used by a `TestSuiteRunner`.";
 $globals.ReportingTestContext.comment="I add `TestResult` reporting to `TestContext`.\x0a\x0aErrors are caught and save into a `TestResult`,\x0aWhen test case is finished (which can be later for async tests), a callback block is executed; this is used by a `TestSuiteRunner`.";
@@ -983,7 +1318,6 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 $recv((function(){
 $recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
@@ -992,14 +1326,15 @@ return $self._withErrorReporting_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return (
+return [(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx3.supercall = true,
 $ctx3.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._execute_.call($self,aBlock));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._execute_.call($self,aBlock))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx3.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx3.supercall = false
+//>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -1011,8 +1346,7 @@ $ctx3.supercall = false;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($self.testCase)._isAsync();
-if(!$core.assert($1)){
+if(!$core.assert($recv($self.testCase)._isAsync())){
 $recv($self.result)._increaseRuns();
 $recv($self.result)._increaseRuns();
 return $recv($self.finished)._value();
 return $recv($self.finished)._value();
 }
 }
@@ -1081,7 +1415,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv((function(){
+[$recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -1105,10 +1439,11 @@ return $recv($self.result)._addError_($self.testCase);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,3)});
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,3)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["on:do:"]=1;
+,$ctx1.sendIdx["on:do:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"withErrorReporting:",{aBlock:aBlock})});
 }, function($ctx1) {$ctx1.fill(self,"withErrorReporting:",{aBlock:aBlock})});
@@ -1134,14 +1469,15 @@ var self=this,$self=this;
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 var $1;
 var $1;
-$1=(
+$1=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._testCase_.call($self,aTestCase));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._testCase_.call($self,aTestCase))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $recv($1)._result_(aTestResult);
 $recv($1)._result_(aTestResult);
 $recv($1)._finished_(aBlock);
 $recv($1)._finished_(aBlock);
 return $recv($1)._yourself();
 return $recv($1)._yourself();
@@ -1286,20 +1622,22 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $self.timestamp=$recv($globals.Date)._now();
 $self.timestamp=$recv($globals.Date)._now();
 $self.runs=(0);
 $self.runs=(0);
-$self.errors=$recv($globals.Array)._new();
+$self.errors=[$recv($globals.Array)._new()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["new"]=1;
+,$ctx1.sendIdx["new"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self.failures=$recv($globals.Array)._new();
 $self.failures=$recv($globals.Array)._new();
 $self.total=(0);
 $self.total=(0);
 return self;
 return self;
@@ -1325,13 +1663,11 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $2,$1;
-$2=$self._runs();
+if(!$core.assert($recv([$self._runs()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["runs"]=1;
+,$ctx1.sendIdx["runs"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($2).__eq_eq($self._total());
-if(!$core.assert($1)){
+][0]).__eq_eq($self._total()))){
 return $recv(aBlock)._value_($recv($self._runs()).__plus((1)));
 return $recv(aBlock)._value_($recv($self._runs()).__plus((1)));
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1356,7 +1692,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv((function(){
+[$recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -1389,10 +1725,11 @@ return $self._addError_(aTestCase);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,4)});
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,4)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["on:do:"]=1;
+,$ctx1.sendIdx["on:do:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"runCase:",{aTestCase:aTestCase})});
 }, function($ctx1) {$ctx1.fill(self,"runCase:",{aTestCase:aTestCase})});
@@ -1434,8 +1771,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($self._errors())._ifNotEmpty_ifEmpty_((function(){
+return [$recv($self._errors())._ifNotEmpty_ifEmpty_((function(){
 return "error";
 return "error";
 
 
 }),(function(){
 }),(function(){
@@ -1452,11 +1788,11 @@ return "success";
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=1;
+,$ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $1;
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"status",{})});
 }, function($ctx1) {$ctx1.fill(self,"status",{})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -1589,19 +1925,20 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-$self.announcer=$recv($globals.Announcer)._new();
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
+$self.announcer=[$recv($globals.Announcer)._new()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["new"]=1;
+,$ctx1.sendIdx["new"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 $self.result=$recv($globals.TestResult)._new();
 $self.result=$recv($globals.TestResult)._new();
 $self.runNextTest=(function(){
 $self.runNextTest=(function(){
 var runs;
 var runs;
@@ -1609,8 +1946,7 @@ var runs;
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 runs=$recv($self.result)._runs();
 runs=$recv($self.result)._runs();
-$1=$recv(runs).__lt($recv($self.result)._total());
-if($core.assert($1)){
+if($core.assert($recv(runs).__lt($recv($self.result)._total()))){
 return $recv($self._contextOf_($recv(runs).__plus((1))))._start();
 return $recv($self._contextOf_($recv(runs).__plus((1))))._start();
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1752,16 +2088,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=(
+return $recv([(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-return $recv($1)._suite_(aCollection);
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0])._suite_(aCollection);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"on:",{aCollection:aCollection})});
 }, function($ctx1) {$ctx1.fill(self,"on:",{aCollection:aCollection})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");

+ 100 - 1
lang/src/SUnit.st

@@ -17,6 +17,67 @@ result: aTestResult
 	result := aTestResult
 	result := aTestResult
 ! !
 ! !
 
 
+Object subclass: #Teachable
+	slots: {#learnings}
+	package: 'SUnit'!
+!Teachable commentStamp!
+An object you can teach how to behave. Have a look at the 
+class side for an example.
+
+For more infos have a look at: http://lists.squeakfoundation.org/pipermail/squeak-dev/2002-April/038170.html!
+
+!Teachable methodsFor: 'private'!
+
+doesNotUnderstand: aMessage
+
+	| learning |
+	learning := self learnings 
+		at: aMessage selector 
+		ifAbsent:[ ^super doesNotUnderstand: aMessage ].
+	^ learning class == Association
+		ifTrue: [learning value]
+		ifFalse: [learning valueWithPossibleArguments: aMessage arguments]
+!
+
+learnings
+
+	learnings isNil ifTrue: [learnings := Dictionary new].
+	^learnings
+! !
+
+!Teachable methodsFor: 'teaching'!
+
+acceptSend: aSymbol
+
+	self whenSend: aSymbol return: self
+!
+
+whenSend: aSymbol evaluate: aBlock
+
+	self learnings at: aSymbol put: aBlock
+!
+
+whenSend: aSymbol return: anObject
+
+	self learnings at: aSymbol put: (#return -> anObject)
+! !
+
+!Teachable class methodsFor: 'examples'!
+
+example
+	| teachable |
+	teachable := self new.
+	teachable 
+		whenSend: #help return: 'ok';
+		whenSend: #doit evaluate: [1 inspect];
+		acceptSend: #noDebugger;
+		whenSend: #negate: evaluate: [:num | num negated].
+	teachable help.
+	teachable doit.
+	teachable noDebugger.
+	teachable negate: 120
+! !
+
 Object subclass: #TestCase
 Object subclass: #TestCase
 	slots: {#testSelector. #asyncTimeout. #context}
 	slots: {#testSelector. #asyncTimeout. #context}
 	package: 'SUnit'!
 	package: 'SUnit'!
@@ -91,6 +152,12 @@ signalFailure: aString
 
 
 !TestCase methodsFor: 'running'!
 !TestCase methodsFor: 'running'!
 
 
+debugCase
+	"Runs a test case in isolated context, debugging all errors."
+
+	(DebugTestContext testCase: self) start
+!
+
 performTest
 performTest
 	asyncTimeout := nil.
 	asyncTimeout := nil.
 	self perform: self selector
 	self perform: self selector
@@ -153,7 +220,7 @@ allTestSelectors
 	selectors := self testSelectors.
 	selectors := self testSelectors.
 	self shouldInheritSelectors ifTrue: [
 	self shouldInheritSelectors ifTrue: [
 		selectors addAll: self superclass allTestSelectors ].
 		selectors addAll: self superclass allTestSelectors ].
-	^ selectors
+	^ selectors asSet
 !
 !
 
 
 buildSuite
 buildSuite
@@ -244,6 +311,38 @@ testCase: aTestCase
 		yourself
 		yourself
 ! !
 ! !
 
 
+TestContext subclass: #DebugTestContext
+	slots: {#finished. #result}
+	package: 'SUnit'!
+!DebugTestContext commentStamp!
+I add error debugging to `TestContext`.
+
+Errors are caught and explicitly passed to `ErrorHandler`.
+I am used in `TestCase >> debugCase`.!
+
+!DebugTestContext methodsFor: 'private'!
+
+withErrorDebugging: aBlock
+	aBlock
+		on: Error
+		do: [ :ex | ErrorHandler handleError: ex ]
+! !
+
+!DebugTestContext methodsFor: 'running'!
+
+execute: aBlock
+	self withErrorDebugging: [ super execute: aBlock ]
+! !
+
+!DebugTestContext class methodsFor: 'instance creation'!
+
+testCase: aTestCase result: aTestResult finished: aBlock
+	^ (super testCase: aTestCase)
+		result: aTestResult;
+		finished: aBlock;
+		yourself
+! !
+
 TestContext subclass: #ReportingTestContext
 TestContext subclass: #ReportingTestContext
 	slots: {#finished. #result}
 	slots: {#finished. #result}
 	package: 'SUnit'!
 	package: 'SUnit'!

+ 74 - 81
sdk/lib/NodeTestRunner.js

@@ -47,7 +47,6 @@ var suite,worker;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $2,$1,$3,$9,$8,$12,$11,$10,$7,$6,$15,$14,$13,$5,$4,$17,$16,$19,$18,$26,$25,$24,$23,$22,$28,$27,$21,$20,$30,$29,$32,$31,$39,$38,$37,$36,$35,$34,$33;
 suite=$recv($globals.OrderedCollection)._new();
 suite=$recv($globals.OrderedCollection)._new();
 $recv($recv($recv($globals.TestCase)._allSubclasses())._select_((function(each){
 $recv($recv($recv($globals.TestCase)._allSubclasses())._select_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -73,153 +72,147 @@ var result;
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 result=$recv(ann)._result();
 result=$recv(ann)._result();
-$2=$recv(result)._runs();
+if($core.assert($recv([$recv(result)._runs()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["runs"]=1;
+,$ctx2.sendIdx["runs"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($2).__eq($recv(result)._total());
-if($core.assert($1)){
-$3=console;
-$9=$recv($recv(result)._runs())._asString();
+][0]).__eq($recv(result)._total()))){
+$recv(console)._log_([$recv([$recv([$recv([$recv([$recv([$recv($recv(result)._runs())._asString()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["asString"]=1;
+,$ctx2.sendIdx["asString"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$8=$recv($9).__comma(" tests run, ");
+][0]).__comma(" tests run, ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=5;
+,$ctx2.sendIdx[","]=5
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$12=$recv(result)._failures();
+][0]).__comma([$recv([$recv([$recv(result)._failures()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["failures"]=1;
+,$ctx2.sendIdx["failures"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$11=$recv($12)._size();
+][0])._size()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["size"]=1;
+,$ctx2.sendIdx["size"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$10=$recv($11)._asString();
+][0])._asString()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["asString"]=2;
+,$ctx2.sendIdx["asString"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$7=$recv($8).__comma($10);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=4;
+,$ctx2.sendIdx[","]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$6=$recv($7).__comma(" failures, ");
+][0]).__comma(" failures, ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=3;
+,$ctx2.sendIdx[","]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$15=$recv(result)._errors();
+][0]).__comma($recv($recv([$recv(result)._errors()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["errors"]=1;
+,$ctx2.sendIdx["errors"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$14=$recv($15)._size();
-$13=$recv($14)._asString();
-$5=$recv($6).__comma($13);
+][0])._size())._asString())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=2;
+,$ctx2.sendIdx[","]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$4=$recv($5).__comma(" errors.");
+][0]).__comma(" errors.")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=1;
+,$ctx2.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($3)._log_($4);
-$17=$recv(result)._failures();
+][0]);
+if(!$core.assert([$recv([$recv(result)._failures()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["failures"]=2;
+,$ctx2.sendIdx["failures"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$16=$recv($17)._isEmpty();
+][0])._isEmpty()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["isEmpty"]=1;
+,$ctx2.sendIdx["isEmpty"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-if(!$core.assert($16)){
-$19=$recv(result)._failures();
+][0])){
+[$recv([$recv([$recv(result)._failures()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["failures"]=3;
+,$ctx2.sendIdx["failures"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$18=$recv($19)._first();
+][0])._first()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["first"]=1;
+,$ctx2.sendIdx["first"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($18)._runCase();
+][0])._runCase()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["runCase"]=1;
+,$ctx2.sendIdx["runCase"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$26=$recv(result)._failures();
+][0];
+[$self._throw_([$recv([$recv([$recv([$recv([$recv([$recv([$recv(result)._failures()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["failures"]=4;
+,$ctx2.sendIdx["failures"]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$25=$recv($26)._first();
+][0])._first()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["first"]=2;
+,$ctx2.sendIdx["first"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$24=$recv($25)._class();
+][0])._class()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["class"]=1;
+,$ctx2.sendIdx["class"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$23=$recv($24)._name();
+][0])._name()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["name"]=1;
+,$ctx2.sendIdx["name"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$22=$recv($23).__comma(" >> ");
+][0]).__comma(" >> ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=8;
+,$ctx2.sendIdx[","]=8
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$28=$recv($recv(result)._failures())._first();
+][0]).__comma([$recv([$recv($recv(result)._failures())._first()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["first"]=3;
+,$ctx2.sendIdx["first"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$27=$recv($28)._selector();
+][0])._selector()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["selector"]=1;
+,$ctx2.sendIdx["selector"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$21=$recv($22).__comma($27);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=7;
+,$ctx2.sendIdx[","]=7
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$20=$recv($21).__comma(" is failing!");
+][0]).__comma(" is failing!")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=6;
+,$ctx2.sendIdx[","]=6
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$self._throw_($20);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["throw:"]=1;
+,$ctx2.sendIdx["throw:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
+][0];
 }
 }
-$30=$recv(result)._errors();
+if(!$core.assert($recv([$recv(result)._errors()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["errors"]=2;
+,$ctx2.sendIdx["errors"]=2
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$29=$recv($30)._isEmpty();
-if(!$core.assert($29)){
-$32=$recv(result)._errors();
+][0])._isEmpty())){
+$recv([$recv([$recv(result)._errors()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["errors"]=3;
+,$ctx2.sendIdx["errors"]=3
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$31=$recv($32)._first();
+][0])._first()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["first"]=4;
+,$ctx2.sendIdx["first"]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$recv($31)._runCase();
-$39=$recv(result)._errors();
+][0])._runCase();
+return $self._throw_([$recv([$recv($recv($recv($recv([$recv([$recv(result)._errors()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["errors"]=4;
+,$ctx2.sendIdx["errors"]=4
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$38=$recv($39)._first();
+][0])._first()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["first"]=5;
+,$ctx2.sendIdx["first"]=5
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$37=$recv($38)._class();
-$36=$recv($37)._name();
-$35=$recv($36).__comma(" >> ");
-$34=$recv($35).__comma($recv($recv($recv(result)._errors())._first())._selector());
+][0])._class())._name()).__comma(" >> ")).__comma($recv($recv($recv(result)._errors())._first())._selector())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=10;
+,$ctx2.sendIdx[","]=10
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$33=$recv($34).__comma(" has errors!");
+][0]).__comma(" has errors!")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=9;
+,$ctx2.sendIdx[","]=9
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $self._throw_($33);
+][0]);
 }
 }
 }
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);

+ 1 - 1
sdk/lib/helpers.js

@@ -7,7 +7,7 @@ function nodeWrapper() {
         "require = requirejs;\n",
         "require = requirejs;\n",
         end: "});\n" +
         end: "});\n" +
         "}((" +
         "}((" +
-        require("amdefine") +
+        require("@ambers/amdefine") +
         "(module)), require));"
         "(module)), require));"
     };
     };
 }
 }

+ 2 - 2
sdk/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@ambers/sdk",
   "name": "@ambers/sdk",
-  "version": "0.12.1",
+  "version": "0.12.2",
   "description": "Development goodies for Amber Smalltalk",
   "description": "Development goodies for Amber Smalltalk",
   "scripts": {
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
     "test": "echo \"Error: no test specified\" && exit 1"
@@ -20,8 +20,8 @@
     "url": "https://lolg.it/amber/amber/issues?labels=in+devkit"
     "url": "https://lolg.it/amber/amber/issues?labels=in+devkit"
   },
   },
   "dependencies": {
   "dependencies": {
+    "@ambers/amdefine": "^1.0.2",
     "amd-config-builder": "^0.3.0",
     "amd-config-builder": "^0.3.0",
-    "amdefine": ">=0.1.1",
     "requirejs": "^2.1.19",
     "requirejs": "^2.1.19",
     "requirejs-text": "^2.0.12"
     "requirejs-text": "^2.0.12"
   }
   }

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác