1
0

183 کامیت‌ها e756476b01 ... 36684d4d53

نویسنده SHA1 پیام تاریخ
  Herby Vojčík 36684d4d53 Working on 0.28.2 5 سال پیش
  Herby Vojčík e0c32490a4 Recompile (while version set to 0.28.1) 5 سال پیش
  Herby Vojčík 72d8567d34 Release version 0.28.1 5 سال پیش
  Herby Vojčík 83a6034f16 Get back `imports:` variables in unknown check. 5 سال پیش
  Herby Vojčík 4b5b537df7 scaffolding: Bump version to 0.28.0. 5 سال پیش
  Herby Vojčík bde20c397a scaffolding: Bump Amber to 0.28. 5 سال پیش
  Herby Vojčík 435fa9f543 Working on 0.28.1 5 سال پیش
  Herby Vojčík 55060f8cdc Recompile (while version set to 0.28.0) 5 سال پیش
  Herby Vojčík 4338d0e248 Release version 0.28.0 5 سال پیش
  Herby Vojčík 56b65fad11 Type-checked Strings comparison. 5 سال پیش
  Herby Vojčík 813b6ce449 CHANGELOG: Typechecked binops. 5 سال پیش
  Herby Vojčík a1a162a6f6 Type-checked Number bit arithmetics. 5 سال پیش
  Herby Vojčík c1b1debd9c Type-checked Number arithmetics and comparison. 5 سال پیش
  Herby Vojčík c1903660ca Small fix. 5 سال پیش
  Herby Vojčík e5943e560e String >> #, with better type checks. 5 سال پیش
  Herby Vojčík 2a99226198 Working on 0.27.2 5 سال پیش
  Herby Vojčík dab304ad7e Recompile (while version set to 0.27.1) 5 سال پیش
  Herby Vojčík 9f7a9e14ab Release version 0.27.1 5 سال پیش
  Herby Vojčík 88a582a95f Formatting. 5 سال پیش
  Herby Vojčík 45b172b8c1 A few Number methods. 5 سال پیش
  Herby Vojčík c056a985df Fix #1249. 5 سال پیش
  Herby Vojčík 4b008b99b1 Fixed AssociativeCollection >> =. 5 سال پیش
  Herby Vojčík be4b221828 Typo. 5 سال پیش
  Herby Vojčík 5bb87d7b22 Proper comma tests in Collection hierarchy. 5 سال پیش
  Herby Vojčík ad4c13a323 scaffolding: Bump version to 0.27.0. 5 سال پیش
  Herby Vojčík da78652491 scaffolding: Bump Amber, helios & legacy for 0.27 5 سال پیش
  Herby Vojčík b1cb8dfe9d Working on 0.27.1 5 سال پیش
  Herby Vojčík d6ec838e28 Recompile (while version set to 0.27.0) 5 سال پیش
  Herby Vojčík 2216167ce5 Release version 0.27.0 5 سال پیش
  Herby Vojčík fe8c0c74e9 inspectOn: now sets list of associations 5 سال پیش
  Herby Vojčík 27ad12c807 Proper place for inspectOn: methods. 5 سال پیش
  Herby Vojčík 52f0eacf9d scaffolding: Bump version to 0.26.0. 5 سال پیش
  Herby Vojčík a8ba8885ef scaffolding: Bump amber. 5 سال پیش
  Herby Vojčík b56731c2a4 Working on 0.26.1 5 سال پیش
  Herby Vojčík bd4586f3e0 Recompile (while version set to 0.26.0) 5 سال پیش
  Herby Vojčík b71f306f94 Release version 0.26.0 5 سال پیش
  Herby Vojčík 4319bf36be Docs for upcoming 0.26. 5 سال پیش
  Herby Vojčík 07c088720e Kernel does not setup whole thisContext chain. 5 سال پیش
  Herby Vojčík 35a78741f1 Error handling out of kernel. 5 سال پیش
  Herby Vojčík 7488f770b9 scaffolding: Bump version to 0.25.1. 5 سال پیش
  Herby Vojčík ec9861557b scaffolding: Bump amber and IDEs. 5 سال پیش
  Herby Vojčík 4dcd38e6ff Working on 0.25.5 5 سال پیش
  Herby Vojčík 31e6daa1a3 Recompile (while version set to 0.25.4) 5 سال پیش
  Herby Vojčík 43ca62a154 Release version 0.25.4 5 سال پیش
  Herby Vojčík 06daecf756 DebugTestContext. TestCase >> debugCase. 5 سال پیش
  Herby Vojčík 95573bde49 Working on 0.25.4 5 سال پیش
  Herby Vojčík 93d2a4a1f8 Recompile (while version set to 0.25.3) 5 سال پیش
  Herby Vojčík 81118e6461 Release version 0.25.3 5 سال پیش
  Herby Vojčík eefaf5b455 kernel: Fix nasty error. 5 سال پیش
  Herby Vojčík 356e4e9645 Working on 0.25.3 5 سال پیش
  Herby Vojčík 29c75d26a7 Recompile (while version set to 0.25.2) 5 سال پیش
  Herby Vojčík 7adf2b5295 Release version 0.25.2 5 سال پیش
  Herby Vojčík 43f3ca08b5 kernel: Different thisContext setup. 5 سال پیش
  Herby Vojčík cd255750ed Working on 0.25.2 5 سال پیش
  Herby Vojčík 96707285e2 Recompile (while version set to 0.25.1) 5 سال پیش
  Herby Vojčík b0363f9a53 Release version 0.25.1 5 سال پیش
  Herby Vojčík d7fd0daa25 CHANGELOG: 0.25.1 5 سال پیش
  Herby Vojčík 40d349b2af Collection >> #shortenedPrintString. 5 سال پیش
  Herby Vojčík 6e4527c9ab Collection >> #copyEmpty 5 سال پیش
  Herby Vojčík 56651b7ae5 CHANGELOG: Subclassing JS. 5 سال پیش
  Herby Vojčík e81744b7c5 Date of release. 5 سال پیش
  Herby Vojčík 94d91489e3 scaffolding: First one for Amber 0.25. 5 سال پیش
  Herby Vojčík c8fbd8e80d Working on 0.25.1 5 سال پیش
  Herby Vojčík b2846784ec Recompile (while version set to 0.25.0) 5 سال پیش
  Herby Vojčík 9ebf8f372b Release version 0.25.0 5 سال پیش
  Herby Vojčík 9c5afb93d8 Recompile. 5 سال پیش
  Herby Vojčík eafbf84248 Different cr/lf sanitizing of source code. 5 سال پیش
  Herby Vojčík e343e92bea Bump dependencies for 0.25 release. 5 سال پیش
  Herby Vojčík cabb6e24c6 Now <jsOverride:args:> works in interpreter. 5 سال پیش
  Herby Vojčík bb191d4827 Fix tests so they actually are interpreted/dbgd. 5 سال پیش
  Herby Vojčík 1d76f230e7 In <jsOverride:args:>, args can be permutated. 5 سال پیش
  Herby Vojčík 5490c0ad03 Typo in method name. 5 سال پیش
  Herby Vojčík 3de75162c3 N-adic jsOverride:args: works. 5 سال پیش
  Herby Vojčík 0d39981bc4 kernel: Remove attachment of removed method. 5 سال پیش
  Herby Vojčík 91656d575e Fix. :-/ 5 سال پیش
  Herby Vojčík 34d99ac6b3 Array >> allIn:. 5 سال پیش
  Herby Vojčík 37473d1701 Niladic jsOverride: works in interpreter. 5 سال پیش
  Herby Vojčík b0540240c2 Move jsOverride: marking to AST. 5 سال پیش
  Herby Vojčík 5da271da4d API-CHANGES: #instVarNamed:[put:]. 5 سال پیش
  Herby Vojčík 667465d036 Add instVarNamed:[put:]. 5 سال پیش
  Herby Vojčík 6ffe4ecbd8 Optimization. 5 سال پیش
  Herby Vojčík 4d1656fb1b Not all inlined sends need aliased receiver. 5 سال پیش
  Herby Vojčík e465818812 Refactor inlined send arguments guarding. 5 سال پیش
  Herby Vojčík b516aa0afb More reworking in aliasing. 5 سال پیش
  Herby Vojčík fe2cc466af Remove visitOrAlias:. 5 سال پیش
  Herby Vojčík f6a76689c1 Split different aliasing needs. 5 سال پیش
  Herby Vojčík 6b27fc46f3 Setting: no point for value ivar. 5 سال پیش
  Herby Vojčík 938c10d485 Move TPragmator to Compiler-Core. 5 سال پیش
  Herby Vojčík a78d925fda Bump sdk to version 0.12.2. 5 سال پیش
  Herby Vojčík d9a8a3310c Move to use @ambers/amdefine. 5 سال پیش
  Herby Vojčík a1e3134d30 Niladic #jsOverride: pragma - super sends. 5 سال پیش
  Herby Vojčík 41fecf304b Bump scaffolding to 0.24.9. 5 سال پیش
  Herby Vojčík f3d4386d4a gitignore: comment the items 5 سال پیش
  Herby Vojčík 65b5afa98f Small fix. 5 سال پیش
  Herby Vojčík 9ce6b38e9d Method attachments: no need for IIFE. 5 سال پیش
  Herby Vojčík ef446ad94d Bump scaffolding to 0.24.8. 5 سال پیش
  Herby Vojčík b32fa374c4 README: Restructure library section. 5 سال پیش
  Herby Vojčík ea7cd2d4e6 README: Contribution section formatting. 5 سال پیش
  Herby Vojčík 08512c7ab9 README: Contribution needs amber tooling. 5 سال پیش
  Herby Vojčík d21478e460 Bump scaffolding to 0.24.7. 5 سال پیش
  Herby Vojčík dfe1fd4398 Comment the IDE dialog. 5 سال پیش
  Herby Vojčík 3980aaf7c4 Bump scaffolding to 0.24.6. 5 سال پیش
  Herby Vojčík 264bc5758a Gruntfile.js: less cbRequireAndPromiseMain. 5 سال پیش
  Herby Vojčík dea2172465 Revert to state of 0.24.4. 5 سال پیش
  Herby Vojčík 09c46ed043 Bump scaffolding to 0.24.5. 5 سال پیش
  Herby Vojčík 9a1e4bc2cd Simplify Gruntfile.js. 5 سال پیش
  Herby Vojčík 179b189839 Revert "Revert "Flatter loader code."" 5 سال پیش
  Herby Vojčík 2e11d4e754 Make the.js contains promise polyfill. 5 سال پیش
  Herby Vojčík 70fa5c4a67 Bump scaffolding to 0.24.4. 5 سال پیش
  Herby Vojčík 511324bc05 Revert "Flatter loader code." 5 سال پیش
  Herby Vojčík 0dc1d8efb3 Scaffolding: deps in alphabetical order. 5 سال پیش
  Herby Vojčík b918f86dbc Bump scaffolding to 0.24.3. 5 سال پیش
  Herby Vojčík 49e9ecaafe New silk. 5 سال پیش
  Herby Vojčík f3257a8806 Next version will be minor bump. 5 سال پیش
  Herby Vojčík 9c0962739b Squash compiler-related changes. 5 سال پیش
  Herby Vojčík 38acbc5019 AstEarlyPragmator => AstSemanticPragmator. 5 سال پیش
  Herby Vojčík 16ee1e6f21 TIRInlinedVisitor. Compiler-IR clear of inlining. 5 سال پیش
  Herby Vojčík 1e1f4d32b9 Put implicit `^ self` to method sequence. 5 سال پیش
  Herby Vojčík ebf2869dd3 IRMethod manages some of aliasing logistics. 5 سال پیش
  Herby Vojčík e8c2030575 IRAliasFactory instance in IRMethod. 5 سال پیش
  Herby Vojčík 5f22e11744 Use ArgVar for what essentially is an arg var. 5 سال پیش
  Herby Vojčík c50db69cf5 Performance optimization. 5 سال پیش
  Herby Vojčík 9e68ecec3e Remove $receiver. 5 سال پیش
  Herby Vojčík 2fca1b456c API-CHANGES: Cleanup of #isFoo in ast nodes. 5 سال پیش
  Herby Vojčík 6d96c99a65 Clean scope var tests & test-only #isFoo methods. 5 سال پیش
  Herby Vojčík 684fb9b77d AST Interpreter: Double dispatch read/write vars. 5 سال پیش
  Herby Vojčík 1fb2a0813d Move #evaluate:for: into Interpreter package. 5 سال پیش
  Herby Vojčík f385aeefb3 Change #isAssignable default to false. 5 سال پیش
  Herby Vojčík 8361bd4b81 ScopeVar / ExpressionNode deprecate #isImmutable. 5 سال پیش
  Herby Vojčík a9b97168d2 ScopeVar / ExpressionNode subtree #isIdempotent. 5 سال پیش
  Herby Vojčík 6b1cbb2e43 ScopeVar and children #isAssignable. 5 سال پیش
  Herby Vojčík e25f7b9973 Make externally known variables unassignable. 5 سال پیش
  Herby Vojčík 973f0466dd Tests for (semantic) invalid assignment. 5 سال پیش
  Herby Vojčík 0e90ec29eb Remove ivar that is in superclass. 5 سال پیش
  Herby Vojčík 7824aee093 Typos. 5 سال پیش
  Herby Vojčík 34df6b90a2 AstGenerator; different #ast:forClass:protocol:. 5 سال پیش
  Herby Vojčík 32474db5e2 Refactor: use #enterNode. 5 سال پیش
  Herby Vojčík 1f96af67dd Compiler: VariableNode changes. 5 سال پیش
  Herby Vojčík fe2304fa41 Compiler: ExpressionNode, group expression nodes. 5 سال پیش
  Herby Vojčík e80743e00f Compiler: Explictly mark "side-effect" sends. 5 سال پیش
  Herby Vojčík 72cf503117 Use TSingleDagChild et. al in Compiler-AST. 5 سال پیش
  Herby Vojčík 74e213d4a1 Fix DagSink (no nodes slot), add traits. 5 سال پیش
  Herby Vojčík 54d03fd37c Remove message never sent. 5 سال پیش
  Herby Vojčík 26736be9eb Remove isFooNode messages never sent. 5 سال پیش
  Herby Vojčík 30ff55811d Compiler: less aliasing. 5 سال پیش
  Herby Vojčík eba01a8328 Compile debug augmentation differently. 5 سال پیش
  Herby Vojčík d19dae7e44 Compiler: Different aliasing of assignment and cascade. 5 سال پیش
  Herby Vojčík a01417ca15 Compiler: Move #requiresSmalltalkContext to IR package. 5 سال پیش
  Herby Vojčík 9843784ffe Use #anySatisfy:. 5 سال پیش
  Herby Vojčík 780bd792dc Remove ivar that was never used. 5 سال پیش
  Herby Vojčík 9a0af62f29 Compiler: No aliasing of sequence members. 5 سال پیش
  Herby Vojčík d5006790bd Remove message never sent. 5 سال پیش
  Herby Vojčík 0864daf565 Remove test-only #isJSStatementNode. 5 سال پیش
  Herby Vojčík b42bf2dcd0 Add Teachable to SUnit package. 5 سال پیش
  Herby Vojčík 8715ddbe23 CHANGELOG: $nil. 5 سال پیش
  Herby Vojčík ba64716de3 Performance optimizations. 5 سال پیش
  Herby Vojčík 752127ddfe Formatting. 5 سال پیش
  Herby Vojčík 25dc722d47 parser: Inline sequences. 5 سال پیش
  Herby Vojčík 8177ea7ac4 ScopeVar asReceiver as extension method. 5 سال پیش
  Herby Vojčík a73dbbd68a Memoize dictionary of receiver names. 5 سال پیش
  Herby Vojčík 3f59afc322 Compile nil receiver as `$nil`. 5 سال پیش
  Herby Vojčík d97910b6ec Pseudovars including nil, true, false actually parsed as such. 5 سال پیش
  Herby Vojčík 89aeddb62d Fix glitch in lookupContextForLocal:ifNone:. 5 سال پیش
  Herby Vojčík dbc29ce2b5 Compiler: cleaner super receiver handling. 5 سال پیش
  Herby Vojčík 9de7736644 Compiler: redesign receiver boxing. 5 سال پیش
  Herby Vojčík 25f05d294d DRY 5 سال پیش
  Herby Vojčík 01ae5c0265 Optimize some uses of #and:. 5 سال پیش
  Herby Vojčík a512c9d830 Refactor: Put responsibility where it's due. 5 سال پیش
  Herby Vojčík 10e50375bf Refactor: Put responsibility where it's due. 5 سال پیش
  Herby Vojčík 75feddedce Remove message never sent. 5 سال پیش
  Herby Vojčík eab0e5857a Remove ivar that was never used. 5 سال پیش
  Herby Vojčík 908203de93 Simplify #validateAssigment. 5 سال پیش
  Herby Vojčík 9a35214ee6 UnknownVar => ExternallyKnownVar 5 سال پیش
  Herby Vojčík 89bdb83fec Refactor: Put responsibility where it's due. 5 سال پیش
  Herby Vojčík 976ee5a571 Actually check for existence of a variable. 5 سال پیش
  Herby Vojčík a3d5721c6d SemanticAnalyzer >> isVariableKnown:inPackage: 5 سال پیش
  Herby Vojčík 24d2c49031 Cosmetics. 5 سال پیش
  Herby Vojčík 0148d48c5e Remove ivar that was never read. 5 سال پیش
  Herby Vojčík 56a8f25284 aScope bindingFor: is never used with a string. 5 سال پیش
  Herby Vojčík 3669389473 API-CHANGES: Removal of shouldBeInlined. 5 سال پیش
  Herby Vojčík 89602991e0 API-CHANGES: SeqColl >> copyWithFirst:. 5 سال پیش
  Herby Vojčík 0f51004ae5 Optimizations. Cleaning. 5 سال پیش
  Herby Vojčík ff4307218e SequenceableCollection >> copyWithFirst:. 5 سال پیش
64فایلهای تغییر یافته به همراه10209 افزوده شده و 7143 حذف شده
  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.
+* 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.
 * 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

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 992 - 927
cli/dist/amber-cli.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 255 - 253
cli/src/AmberCli.js


+ 7 - 7
cli/src/AmberCli.st

@@ -38,7 +38,7 @@ handleArguments: args
 
 	selector := self selectorForCommandLineSwitch: (args first).
 	args remove: args first.
-	self perform: selector  withArguments: (Array with: args)
+	self perform: selector  withArguments: { args }
 !
 
 selectorForCommandLineSwitch: aSwitch
@@ -328,7 +328,7 @@ handlePUTRequest: aRequest respondTo: aResponse
 	stream on: 'error' do: [:error |
 		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: '    The exact error is: ', error.
+		console warn: '    The exact error is: ', error asString.
 		self respondNotCreatedTo: aResponse].
 
 	stream on: 'close' do: [
@@ -437,7 +437,7 @@ start
 	self checkDirectoryLayout.
 	(http createServer: [:request :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];
 	      listen: self port host: self host.
 !
@@ -939,8 +939,8 @@ createServerWithArguments: options
 
 	(options size even) ifFalse: [
 		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].
 
 	popFront := [:args |
@@ -954,10 +954,10 @@ createServerWithArguments: options
 
 		(switches includes: optionName) ifTrue: [
 			optionName := self selectorForCommandLineSwitch: optionName.
-			server perform: optionName withArguments: (Array with: optionValue)]
+			server perform: optionName withArguments: { optionValue } ]
 			ifFalse: [
 				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.
 !
 

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

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

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

@@ -118,8 +118,7 @@ module.exports = function (grunt) {
                 options: {
                     rawText: {
                         "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) {
                             return amber.initialize().then(function () {
                                 return amber;
@@ -142,12 +141,11 @@ module.exports = function (grunt) {
                 options: {
                     rawText: {
                         "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.globals.NodeTestRunner._main();
                             });
-                        }),
-                        "app": mkDefine(["require"], cbRequireAndPromiseMain)
+                        })
                     },
                     paths: {"amber_devkit": helpers.libPath},
                     pragmas: {

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

@@ -2,17 +2,14 @@
 
 {%= 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
 npm install {%= name %} --save
@@ -27,12 +24,8 @@ save the change and commit the package. Reload.
 
 ## 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/
 
+#Generated when running tests from cli via `npm test` / `grunt test`
 /test_runner.js
 
+#Generated when `grunt devel`, `grunt deploy` or `grunt deploy:lambda`
 /config.js
 /the.js
 /lambda/the.js

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

@@ -25,17 +25,21 @@
 <!-- EXAMPLE APP END -->
 <script type='text/javascript'>
     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>

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

@@ -118,16 +118,16 @@ exports.template = function (grunt, init, done) {
         props.dependencies = {
             "@ambers/contrib-jquery": "^0.6.0",
             "@ambers/contrib-web": "^0.8.2",
-            "@ambers/lang": "^0.24.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 = {
+            "@ambers/contrib-legacy": "^0.10.1",
+            "@ambers/helios": "^0.12.2",
             "@ambers/ide-starter-modal": "^0.2.0",
             "@ambers/sdk": "^0.12.1",
-            "@ambers/contrib-legacy": "^0.8.6",
-            "@ambers/helios": "^0.11.6",
             "grunt": "^1.0.3",
             "grunt-contrib-clean": "^1.1.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 ProtoObject >> instVarAt:(put:)
+* Lots of changes in Compiler.
+* Added Teachable class.
 
++ Array >>
+  + allIn:
 + Behavior >>
   + alternateConstructorViaSelector:
   + applySuperConstructorOn:withArguments:
   + beJavaScriptSubclassOf:
   + javaScriptConstructor
   + javaScriptConstructor:
+  + superPrototype
 + BlockClosure >>
   + tryIfTrue:catch:
++ ProtoObject >>
+  + instVarNamed:
+  + instVarNamed:put:
++ SequenceableCollection >>
+  + copyWithFirst:
 + SmalltalkImage >>
-  + do:on:do:
   + isError:
+  + try:ifTrue:catch:
 + amber/boot api >>
   + detachClass(klass)
 + amber/helpers exports >>
@@ -24,9 +74,10 @@
 - JavaScriptError >>
   - shouldBeStubbed
   - wrap
-- MethodContext
+- MethodContext >>
   - stubHere
   - stubToAtMost:
+
 - amber/boot api >>
   - addElement(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);
     }
 
+    var table = {
+        ':': '_',
+        '&': '_and',
+        '|': '_or',
+        '+': '_plus',
+        '-': '_minus',
+        '*': '_star',
+        '/': '_slash',
+        '\\': '_backslash',
+        '~': '_tild',
+        '%': '_percent',
+        '>': '_gt',
+        '<': '_lt',
+        '=': '_eq',
+        ',': '_comma',
+        '@': '_at'
+    };
+
     /* Convert a Smalltalk selector into a JS selector */
     function st2js (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) {

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

@@ -10,7 +10,7 @@ define(['./junk-drawer'], function ($goodies) {
     var deleteKeysFrom = $goodies.deleteKeysFrom;
     var extendWithMethods = $goodies.extendWithMethods;
 
-    function installMethodOfJsObjectEx (obj, name, fn) {
+    function uninstallMethodOfJsObjectEx (obj, name) {
         var attachments;
         var old = Object.getOwnPropertyDescriptor(obj, name);
         if (old != null && (old = old.value) != null) {
@@ -19,7 +19,12 @@ define(['./junk-drawer'], function ($goodies) {
                 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) {
             extendWithMethods(obj, attachments);
         }
@@ -253,7 +258,7 @@ define(['./junk-drawer'], function ($goodies) {
             };
 
             emit.behaviorMethodRemoved = function (method, klass) {
-                delete klass.fn.prototype[method.jsSelector];
+                uninstallMethodOfJsObjectEx(klass.fn.prototype, method.jsSelector);
                 propagateMethodChange(klass, method, null);
             };
 
@@ -350,35 +355,22 @@ define(['./junk-drawer'], function ($goodies) {
 
             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 {
                     return worker(thisContext);
-                } catch (error) {
-                    globals.ErrorHandler._handleError_(error);
+                } finally {
                     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.
              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) {
                 var oldContext = thisContext;
                 thisContext = new SmalltalkMethodContext(thisContext, setup);
-                var result = oldContext == null ? resultWithErrorHandling(worker) : worker(thisContext);
+                var result = oldContext == null ? resultWithNoErrorHandling(worker) : worker(thisContext);
                 thisContext = oldContext;
                 return result;
             };
@@ -395,9 +387,7 @@ define(['./junk-drawer'], function ($goodies) {
 
             st.getThisContext = function () {
                 if (!thisContext) return null;
-                for (var frame = thisContext; frame; frame = frame.homeContext) {
-                    frame.setup(frame);
-                }
+                thisContext.setup(thisContext);
                 return thisContext;
             };
         }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 183 - 247
lang/base/parser.js


+ 15 - 21
lang/base/parser.pegjs

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

+ 1 - 1
lang/package.json

@@ -1,6 +1,6 @@
 {
   "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.",
   "homepage": "http://amber-lang.net",
   "keywords": [

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 333 - 529
lang/src/Compiler-AST.js


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

@@ -1,6 +1,6 @@
 Smalltalk createPackage: 'Compiler-AST'!
 DagParentNode subclass: #ASTNode
-	slots: {#parent. #position. #source. #shouldBeAliased}
+	slots: {#parent. #position. #source}
 	package: 'Compiler-AST'!
 !ASTNode commentStamp!
 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
 !
 
-method
-	^ self parent ifNotNil: [ :node | node method ]
-!
-
 navigationNodeAt: aPoint ifAbsent: aBlock
 	"Answer the navigation node in the receiver's tree at aPoint 
 	or nil if no navigation node was found.
@@ -64,14 +60,6 @@ positionStart
 	^ self position
 !
 
-shouldBeAliased
-	^ shouldBeAliased ifNil: [ false ]
-!
-
-shouldBeAliased: aBoolean
-	shouldBeAliased := aBoolean
-!
-
 size
 	^ self source size
 !
@@ -84,19 +72,6 @@ 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'!
 
 inPosition: aPoint
@@ -104,73 +79,61 @@ inPosition: aPoint
 		self positionEnd >= aPoint ])
 !
 
-isAssignmentNode
-	^ false
-!
-
-isBlockNode
+isNavigationNode
+	"Answer true if the node can be navigated to"
+	
 	^ false
 !
 
-isBlockSequenceNode
+isReturnNode
 	^ 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
 !
 
-isValueNode
-	^ false
+isImmutable
+	self deprecatedAPI: 'Use #isIdempotent instead.'.
+	^ self isIdempotent
 !
 
-isVariableNode
+isSuper
 	^ 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}
 	package: 'Compiler-AST'!
 !AssignmentNode commentStamp!
@@ -179,7 +142,7 @@ I represent an assignment node.!
 !AssignmentNode methodsFor: 'accessing'!
 
 dagChildren
-	^ Array with: self left with: self right
+	^ { self left. self right }
 !
 
 left
@@ -198,26 +161,24 @@ right: aNode
 	right := aNode
 ! !
 
-!AssignmentNode methodsFor: 'testing'!
-
-isAssignmentNode
-	^ true
-! !
-
 !AssignmentNode methodsFor: 'visiting'!
 
 acceptDagVisitor: aVisitor
 	^ aVisitor visitAssignmentNode: self
 ! !
 
-ASTNode subclass: #BlockNode
-	slots: {#parameters. #scope}
+ExpressionNode subclass: #BlockNode
+	slots: {#parameters. #scope. #sequenceNode}
 	package: 'Compiler-AST'!
 !BlockNode commentStamp!
 I represent an block closure node.!
 
 !BlockNode methodsFor: 'accessing'!
 
+dagChild
+	^ self sequenceNode
+!
+
 parameters
 	^ parameters ifNil: [ parameters := Array new ]
 !
@@ -232,12 +193,14 @@ scope
 
 scope: aLexicalScope
 	scope := aLexicalScope
-! !
+!
 
-!BlockNode methodsFor: 'testing'!
+sequenceNode
+	^ sequenceNode
+!
 
-isBlockNode
-	^ true
+sequenceNode: anObject
+	sequenceNode := anObject
 ! !
 
 !BlockNode methodsFor: 'visiting'!
@@ -246,7 +209,7 @@ acceptDagVisitor: aVisitor
 	^ aVisitor visitBlockNode: self
 ! !
 
-ASTNode subclass: #CascadeNode
+ExpressionNode subclass: #CascadeNode
 	slots: {#receiver}
 	package: 'Compiler-AST'!
 !CascadeNode commentStamp!
@@ -262,19 +225,13 @@ receiver: aNode
 	receiver := aNode
 ! !
 
-!CascadeNode methodsFor: 'testing'!
-
-isCascadeNode
-	^ true
-! !
-
 !CascadeNode methodsFor: 'visiting'!
 
 acceptDagVisitor: aVisitor
 	^ aVisitor visitCascadeNode: self
 ! !
 
-ASTNode subclass: #DynamicArrayNode
+ExpressionNode subclass: #DynamicArrayNode
 	slots: {}
 	package: 'Compiler-AST'!
 !DynamicArrayNode commentStamp!
@@ -286,7 +243,7 @@ acceptDagVisitor: aVisitor
 	^ aVisitor visitDynamicArrayNode: self
 ! !
 
-ASTNode subclass: #DynamicDictionaryNode
+ExpressionNode subclass: #DynamicDictionaryNode
 	slots: {}
 	package: 'Compiler-AST'!
 !DynamicDictionaryNode commentStamp!
@@ -298,76 +255,70 @@ acceptDagVisitor: aVisitor
 	^ aVisitor visitDynamicDictionaryNode: self
 ! !
 
-ASTNode subclass: #JSStatementNode
-	slots: {}
+ExpressionNode subclass: #SendNode
+	slots: {#selector. #arguments. #receiver. #index. #javaScriptSelector. #argumentSwitcher. #isSideEffect}
 	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 ifNil: [ #() ]
+	^ arguments ifNil: [ arguments := #() ]
 !
 
 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
@@ -378,292 +329,301 @@ 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
-	^ aVisitor visitMethodNode: self
+	^ aVisitor visitSendNode: self
 ! !
 
-ASTNode subclass: #ReturnNode
-	slots: {#scope}
+ExpressionNode subclass: #ValueNode
+	slots: {#value}
 	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
-	^ 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'!
-!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
 	^ 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
-	^ 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'!
-!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
-	^ aVisitor visitValueNode: self
+	^ aVisitor visitMethodNode: self
 ! !
 
-ValueNode subclass: #VariableNode
-	slots: {#assigned. #binding}
+ASTNode subclass: #ReturnNode
+	slots: {#scope. #expression}
 	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
-	^ 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
@@ -701,11 +661,11 @@ value: aMethodNode
 	^ aMethodNode
 ! !
 
-AstPragmator subclass: #AstEarlyPragmator
+AstPragmator subclass: #AstSemanticPragmator
 	slots: {}
 	package: 'Compiler-AST'!
 
-!AstEarlyPragmator methodsFor: 'pragmas'!
+!AstSemanticPragmator methodsFor: 'pragmas'!
 
 inlineJS: aString
 	self methodNode sequenceNode dagChildren ifNotEmpty: [
@@ -802,6 +762,14 @@ visitVariableNode: 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!
 ! !
 

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

@@ -157,9 +157,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.source;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return "";
 } else {
 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);
-$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");
 $core.addMethod(
 $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",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "earlyAstPragmator\x0a\x09^ AstEarlyPragmator new",
-referencedClasses: ["AstEarlyPragmator"],
+source: "semanticAstPragmator\x0a\x09^ AstSemanticPragmator new",
+referencedClasses: ["AstSemanticPragmator"],
 //>>excludeEnd("ide");
 pragmas: [],
 messageSends: ["new"]
@@ -268,13 +294,56 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $recv($globals.AstEarlyPragmator)._new();
+return $recv($globals.AstSemanticPragmator)._new();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"earlyAstPragmator",{})});
+}, function($ctx1) {$ctx1.fill(self,"semanticAstPragmator",{})});
 //>>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.method({
 selector: "irTranslator",
@@ -342,69 +411,45 @@ return $recv($globals.IRLatePragmator)._new();
 }; }),
 $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.method({
 selector: "transformersDictionary",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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");
 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 (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
+var $1,$2;
 $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);
-$ctx1.sendIdx["at:put:"]=1;
+$ctx1.supercall = true,
 //>>excludeEnd("ctx");
-$recv($2)._at_put_("2000-semantic",$self._semanticAnalyzer());
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._transformersDictionary.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=2;
+,$ctx1.supercall = false
 //>>excludeEnd("ctx");
-$recv($2)._at_put_("5000-astToIr",$self._translator());
+][0];
+[$recv($2)._at_put_("5000-astToIr",$self._translator())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=3;
+,$ctx1.sendIdx["at:put:"]=1
 //>>excludeEnd("ctx");
-$recv($2)._at_put_("8000-irToJs",$self._irTranslator());
+][0];
+[$recv($2)._at_put_("7000-irLatePragmas",$self._lateIRPragmator())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=4;
+,$ctx1.sendIdx["at:put:"]=2
 //>>excludeEnd("ctx");
-$recv($2)._at_put_("9000-latePragmas",$self._lateIRPragmator());
+][0];
+$recv($2)._at_put_("8000-irToJs",$self._irTranslator());
 $self.transformersDictionary=$recv($2)._yourself();
 return $self.transformersDictionary;
 } else {
@@ -455,28 +500,19 @@ selector: "ast:forClass:protocol:",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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");
 pragmas: [],
-messageSends: ["start:forClass:protocol:", "transformerAt:put:", "compileNode:", "parse:", "error:"]
+messageSends: ["codeGeneratorClass:", "start:forClass:protocol:", "compileNode:", "parse:"]
 }, function ($methodClass){ return function (aString,aClass,anotherString){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $early={};
-try {
+$self._codeGeneratorClass_($globals.AstGenerator);
 $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);
 }, function($ctx1) {$ctx1.fill(self,"ast:forClass:protocol:",{aString:aString,aClass:aClass,anotherString:anotherString})});
 //>>excludeEnd("ctx");
@@ -578,9 +614,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.codeGeneratorClass;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $globals.InliningCodeGenerator;
 } else {
 return $1;
@@ -616,33 +652,30 @@ selector: "compile:forClass:protocol:",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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"],
 //>>excludeEnd("ide");
 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){
 var self=this,$self=this;
-var compilationResult,result,pragmas,closureFactory;
+var sanitizedSource,compilationResult,result,pragmas,closureFactory;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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());
-$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);
-$ctx1.sendIdx["asArray"]=1;
+,$ctx1.sendIdx["asArray"]=1
 //>>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());
 return result;
 //>>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");
 }; }),
 $globals.Compiler);
@@ -774,12 +807,12 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
-$ctx1.sendIdx["eval:"]=1;
+,$ctx1.sendIdx["eval:"]=1
 //>>excludeEnd("ctx");
+][0];
 } else {
 return $recv(aPackage)._eval_(aString);
 }
@@ -829,13 +862,11 @@ var result,method;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
-$ctx1.sendIdx["class"]=1;
+,$ctx1.sendIdx["class"]=1
 //>>excludeEnd("ctx");
-method=$self._install_forClass_protocol_($1,$2,"**xxxDoIt");
+][0],"**xxxDoIt");
 result=$recv(anObject)._xxxDoIt();
 $recv($recv(anObject)._class())._removeCompiledMethod_(method);
 return result;
@@ -919,50 +950,53 @@ selector: "parseError:parsing:",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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"],
 //>>excludeEnd("ide");
 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){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
-$ctx1.sendIdx["basicAt:"]=1;
+,$ctx1.sendIdx["basicAt:"]=1
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 return $recv(anException)._pass();
 } else {
 var loc;
-loc=$receiver;
+loc=$1;
 $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);
-$ctx1.sendIdx["start"]=1;
+,$ctx1.sendIdx["asString"]=1
 //>>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);
-$ctx1.sendIdx[","]=4;
+,$ctx1.sendIdx[","]=4
 //>>excludeEnd("ctx");
-$5=$recv($6).__comma($recv($recv(loc)._start())._column());
+][0]).__comma($recv($recv($recv(loc)._start())._column())._asString())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=3;
+,$ctx1.sendIdx[","]=3
 //>>excludeEnd("ctx");
-$4=$recv($5).__comma(" : Unexpected character ");
+][0]).__comma(" : Unexpected character ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=2;
+,$ctx1.sendIdx[","]=2
 //>>excludeEnd("ctx");
-$3=$recv($4).__comma($recv(anException)._basicAt_("found"));
+][0]).__comma($recv(anException)._basicAt_("found"))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
-$recv($2)._messageText_($3);
+][0]);
 return $recv($2)._yourself();
 }
 return self;
@@ -1011,7 +1045,6 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
 $recv(aClass)._includingPossibleMetaDo_((function(eachSide){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -1020,8 +1053,7 @@ return $recv($recv($recv(eachSide)._methodDictionary())._values())._do_displayin
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 //>>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());
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1087,12 +1119,11 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv("xxxDoIt ^ [ ".__comma(aString)).__comma(" ] value");
+return [$recv("xxxDoIt ^ [ ".__comma(aString)).__comma(" ] value")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
-return $1;
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"sourceForExpression:",{aString:aString})});
 //>>excludeEnd("ctx");
@@ -1116,18 +1147,18 @@ var package_;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$1;
+var $1;
 package_=$recv(aClass)._packageOfProtocol_(anotherString);
-$self._currentPackage_(package_);
+[$self._currentPackage_(package_)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["currentPackage:"]=1;
+,$ctx1.sendIdx["currentPackage:"]=1
 //>>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;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"start:forClass:protocol:",{aString:aString,aClass:aClass,anotherString:anotherString,package_:package_})});
@@ -1165,7 +1196,7 @@ selector: "wrappedSourceOf:",
 protocol: "private",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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: [],
 //>>excludeEnd("ide");
 pragmas: [],
@@ -1175,26 +1206,23 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$3=$recv(anIRMethod)._compiledSource();
+return [$recv(["(function ($methodClass){ return ".__comma([$recv(anIRMethod)._compiledSource()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["compiledSource"]=1;
+,$ctx2.sendIdx["compiledSource"]=1
 //>>excludeEnd("ctx");
-$2="(function ($methodClass){ return ".__comma($3);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=2;
+,$ctx2.sendIdx[","]=2
 //>>excludeEnd("ctx");
-$1=$recv($2).__comma("; })");
+][0]).__comma("; })")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=1;
+,$ctx2.sendIdx[","]=1
 //>>excludeEnd("ctx");
-throw $early=[$1];
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
@@ -1202,26 +1230,23 @@ throw $early=[$1];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>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);
-$ctx2.sendIdx[","]=5;
+,$ctx2.sendIdx[","]=5
 //>>excludeEnd("ctx");
-$5=$recv($6).__comma($recv(anIRMethod)._compiledSource());
+][0]).__comma($recv(attachments)._asJavaScriptSource())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=4;
+,$ctx2.sendIdx[","]=4
 //>>excludeEnd("ctx");
-$4=$recv($5).__comma("); })");
+][0]).__comma("}); })")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx[","]=3;
+,$ctx2.sendIdx[","]=3
 //>>excludeEnd("ctx");
-throw $early=[$4];
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({attachments:attachments},$ctx1,2)});
 //>>excludeEnd("ctx");
 }));
-return self;
-}
-catch(e) {if(e===$early)return e[0]; throw e}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"wrappedSourceOf:",{anIRMethod:anIRMethod})});
 //>>excludeEnd("ctx");
@@ -1389,57 +1414,6 @@ $core.addClass("Evaluator", $globals.Object, [], "Compiler-Core");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.Evaluator.comment="I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.";
 //>>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.method({
 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:`";
 //>>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.method({
 selector: "asVariableName",
@@ -1555,9 +1612,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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("_");
 } else {
 return self;

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

@@ -54,19 +54,42 @@ transformersDictionary
 	self subclassResponsibility
 ! !
 
-AbstractCodeGenerator subclass: #CodeGenerator
+AbstractCodeGenerator subclass: #AstGenerator
 	slots: {#transformersDictionary}
 	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!
-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.!
 
 !CodeGenerator methodsFor: 'compiling'!
 
-earlyAstPragmator
-	^ AstEarlyPragmator new
-!
-
 irTranslator
 	^ self irTranslatorClass new
 		currentClass: self currentClass;
@@ -81,19 +104,11 @@ lateIRPragmator
 	^ IRLatePragmator new
 !
 
-semanticAnalyzer
-	^ (SemanticAnalyzer on: self currentClass)
-		thePackage: self currentPackage;
-		yourself
-!
-
 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: '7000-irLatePragmas' put: self lateIRPragmator;
 		at: '8000-irToJs' put: self irTranslator;
-		at: '9000-latePragmas' put: self lateIRPragmator;
 		yourself ]
 !
 
@@ -146,25 +161,25 @@ currentPackage: anObject
 !Compiler methodsFor: 'compiling'!
 
 ast: aString forClass: aClass protocol: anotherString
-	self
+	^ self
+		codeGeneratorClass: AstGenerator;
 		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
-	| compilationResult result pragmas closureFactory |
+	| sanitizedSource compilationResult result pragmas closureFactory |
+	sanitizedSource := aString crlfSanitized.
 	compilationResult := self
-		start: aString forClass: aClass protocol: anotherString;
-		compileNode: (self parse: aString).
+		start: sanitizedSource forClass: aClass protocol: anotherString;
+		compileNode: (self parse: sanitizedSource).
 	closureFactory := self
 		eval: (self wrappedSourceOf: compilationResult)
 		forPackage: self currentPackage.
 	result := Smalltalk core method: #{
 		#selector -> compilationResult selector.
 		#protocol -> anotherString.
-		#source -> aString.
+		#source -> sanitizedSource.
 		#messageSends -> compilationResult messageSends asArray.
 		#args -> compilationResult arguments.
 		#referencedClasses -> compilationResult classReferences asArray.
@@ -276,8 +291,8 @@ parseError: anException parsing: aString
 		ifNotNil: [ :loc |
 			^ ParseError new 
 				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');
 				yourself ]
 ! !
@@ -289,17 +304,17 @@ basicParse: aString
 !
 
 wrappedSourceOf: anIRMethod
-	anIRMethod attachments
-		ifEmpty: [ ^
+	^ anIRMethod attachments
+		ifEmpty: [
 			'(function ($methodClass){ return ',
 			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,
-			'); })' ]
+			',"a$atx",{enumerable:false,configurable:true,writable:true,value:',
+			attachments asJavaScriptSource,
+			'}); })' ]
 ! !
 
 !Compiler class methodsFor: 'compiling'!
@@ -350,25 +365,6 @@ I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
 
 !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
 	^ anObject evaluate: aString on: self
 !
@@ -397,6 +393,24 @@ Error subclass: #ParseError
 Instance of ParseError are signaled on any parsing error.
 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'!
 
 asVariableName

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 307 - 346
lang/src/Compiler-IR.js


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

@@ -1,6 +1,6 @@
 Smalltalk createPackage: 'Compiler-IR'!
 NodeVisitor subclass: #IRASTTranslator
-	slots: {#source. #theClass. #method. #sequence. #nextAlias}
+	slots: {#source. #theClass. #method. #sequence}
 	package: 'Compiler-IR'!
 !IRASTTranslator commentStamp!
 I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.!
@@ -15,12 +15,6 @@ method: anIRMethod
 	method := anIRMethod
 !
 
-nextAlias
-	nextAlias ifNil: [ nextAlias := 0 ].
-	nextAlias := nextAlias + 1.
-	^ nextAlias asString
-!
-
 sequence
 	^ sequence
 !
@@ -63,23 +57,15 @@ addToSequence: 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
@@ -89,20 +75,22 @@ aliasTemporally: aCollection
 	The tree is iterated twice. First we get the aliasing dependency,
 	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
@@ -128,7 +116,7 @@ visitBlockNode: aNode
 			name: each name;
 			scope: aNode scope;
 			yourself) ].
-	aNode dagChildren do: [ :each | closure add: (self visit: each) ].
+	closure add: (self visit: aNode sequenceNode).
 	^ closure
 !
 
@@ -138,16 +126,16 @@ visitBlockSequenceNode: aNode
 		do: [
 			aNode dagChildren ifNotEmpty: [
 				aNode dagChildren allButLast do: [ :each |
-					self addToSequence: (self visitOrAlias: each) ].
+					self addToSequence: (self visit: each) ].
 				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
 	| receiver |
 	receiver := aNode receiver.
-	receiver isImmutable ifFalse: [
+	receiver isIdempotent ifFalse: [
 		| alias |
 		alias := self alias: receiver.
 		receiver := VariableNode new binding: alias variable ].
@@ -156,7 +144,7 @@ visitCascadeNode: aNode
 	aNode dagChildren allButLast do: [ :each |
 		self addToSequence: (self visit: each) ].
 
-	^ self visitOrAlias: aNode dagChildren last
+	^ self visit: aNode dagChildren last
 !
 
 visitDynamicArrayNode: aNode
@@ -180,9 +168,10 @@ visitJSStatementNode: aNode
 !
 
 visitMethodNode: aNode
+	| irSequence |
 
 	self method: (IRMethod new
-		source: self source crlfSanitized;
+		source: self source;
 		pragmas: (aNode pragmas collect: [ :each |
 			Message
 				selector: each selector
@@ -203,34 +192,25 @@ visitMethodNode: aNode
 			scope: aNode scope;
 			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: (IRVariable new
 				variable: (aNode scope pseudoVars at: 'self');
 				yourself);
-			yourself);
-		add: (IRVerbatim new source: ';', String lf; yourself) ].
+			yourself) ].
 
 	^ self method
 !
 
-visitOrAlias: aNode
-	^ aNode shouldBeAliased
-		ifTrue: [ self alias: aNode ]
-		ifFalse: [ self visit: aNode ]
-!
-
 visitReturnNode: aNode
-	| return |
-	return := aNode nonLocalReturn
+	^ (aNode nonLocalReturn
 		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
@@ -238,6 +218,8 @@ visitSendNode: aNode
 	send := IRSend new.
 	send
 		selector: aNode selector;
+		javaScriptSelector: aNode javaScriptSelector;
+		argumentSwitcher: aNode argumentSwitcher;
 		index: aNode index.
 	
 	(self aliasTemporally: aNode dagChildren) do: [ :each | send add: each ].
@@ -249,7 +231,7 @@ visitSequenceNode: aNode
 	^ self
 		withSequence: IRSequence new
 		do: [ aNode dagChildren do: [ :each |
-			self addToSequence: (self visitOrAlias: each) ] ]
+			self addToSequence: (self visit: each) ] ]
 !
 
 visitValueNode: aNode
@@ -264,6 +246,26 @@ visitVariableNode: aNode
 		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
 	slots: {#parent}
 	package: 'Compiler-IR'!
@@ -311,6 +313,14 @@ replaceWith: 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'!
 
 isClosure
@@ -325,10 +335,6 @@ isMethod
 	^ false
 !
 
-isSelf
-	^ false
-!
-
 isSend
 	^ false
 !
@@ -350,7 +356,8 @@ isVariable
 !
 
 needsBoxingAsReceiver
-	^ true
+	self deprecatedAPI: 'Use asReceiver isNil instead.'.
+	^ self asReceiver isNil
 !
 
 yieldsValue
@@ -434,9 +441,7 @@ arguments: aCollection
 !
 
 locals
-	^ self arguments copy
-		addAll: (self tempDeclarations collect: [ :each | each name ]);
-		yourself
+	^ self arguments, (self tempDeclarations collect: [ :each | each name ])
 !
 
 requiresSmalltalkContext
@@ -480,13 +485,17 @@ acceptDagVisitor: aVisitor
 ! !
 
 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'!
 !IRMethod commentStamp!
 I am a method instruction!
 
 !IRMethod methodsFor: 'accessing'!
 
+aliasFactory
+	^ aliasFactory ifNil: [ aliasFactory := IRAliasFactory new ]
+!
+
 attachments
 	^ attachments ifNil: [ attachments := #{} ]
 !
@@ -519,6 +528,21 @@ method
 	^ 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
 !
@@ -653,13 +677,21 @@ acceptDagVisitor: aVisitor
 ! !
 
 IRInstruction subclass: #IRSend
-	slots: {#selector. #javaScriptSelector. #index}
+	slots: {#selector. #javaScriptSelector. #argumentSwitcher. #index}
 	package: 'Compiler-IR'!
 !IRSend commentStamp!
 I am a message send instruction.!
 
 !IRSend methodsFor: 'accessing'!
 
+argumentSwitcher
+	^ argumentSwitcher
+!
+
+argumentSwitcher: aJSFunction
+	argumentSwitcher := aJSFunction
+!
+
 arguments
 	^ self dagChildren allButFirst
 !
@@ -746,10 +778,10 @@ value: aString
 	value := aString
 ! !
 
-!IRValue methodsFor: 'testing'!
+!IRValue methodsFor: 'converting'!
 
-needsBoxingAsReceiver
-	^ false
+asReceiver
+	^ self
 ! !
 
 !IRValue methodsFor: 'visiting'!
@@ -774,11 +806,17 @@ 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
 	^ self variable isSuper
@@ -786,10 +824,6 @@ isSuper
 
 isVariable
 	^ true
-!
-
-needsBoxingAsReceiver
-	^ self variable isPseudoVar not
 ! !
 
 !IRVariable methodsFor: 'visiting'!
@@ -847,11 +881,28 @@ IRPragmator subclass: #IRLatePragmator
 !IRLatePragmator methodsFor: 'pragmas'!
 
 jsOverride: aString
+	self irMethod arguments ifNotEmpty: [
+		CompilerError signal: 'Must use <jsOverride:> in unary method.' ].
 	self irMethod attachments
 		at: aString
 		put: (NativeFunction
 			constructorNamed: #Function
 			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
@@ -888,14 +939,6 @@ visitIRDynamicDictionary: anIRDynamicDictionary
 	^ self visitDagNode: anIRDynamicDictionary
 !
 
-visitIRInlinedClosure: anIRInlinedClosure
-	^ self visitIRClosure: anIRInlinedClosure
-!
-
-visitIRInlinedSequence: anIRInlinedSequence
-	^ self visitIRSequence: anIRInlinedSequence
-!
-
 visitIRMethod: anIRMethod
 	^ self visitDagNode: anIRMethod
 !
@@ -1031,15 +1074,25 @@ visitIRReturn: anIRReturn
 !
 
 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
@@ -1074,19 +1127,12 @@ visitInstructionList: anArray enclosedBetween: aString and: anotherString
 !
 
 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
@@ -1098,13 +1144,29 @@ visitSend: 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
@@ -1152,6 +1214,29 @@ nextPutAssignLhs: aBlock rhs: anotherBlock
 	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
 	anIRClosure requiresSmalltalkContext ifFalse: [ ^ aBlock value ].
 	self
@@ -1280,19 +1365,6 @@ nextPutReturnWith: aBlock
 	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
 	self omitSemicolon: false.
 	aBlock value.
@@ -1301,20 +1373,6 @@ nextPutStatementWith: aBlock
 	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
 	aCollection ifNotEmpty: [
 		stream nextPutAll: 'var '.
@@ -1329,63 +1387,73 @@ IRPragmator setTraitComposition: {TPragmator} asTraitComposition!
 
 !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'!
 
-shouldBeAliased
-	^ super shouldBeAliased or: [ self isReferenced ]
-! !
-
-!BlockClosure methodsFor: '*Compiler-IR'!
-
-appendToInstruction: anIRInstruction
-	anIRInstruction appendBlock: self
+hasOpeningStatements
+	^ true
 ! !
 
 !BlockNode methodsFor: '*Compiler-IR'!
 
 subtreeNeedsAliasing
-	^ self shouldBeAliased
+	^ false
 ! !
 
 !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
-	^ 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
 ! !
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 272 - 340
lang/src/Compiler-Inlining.js


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

@@ -9,9 +9,10 @@ visitSendNode: aNode
 
 	aNode superSend ifFalse: [ 
 		(IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [
-			aNode shouldBeInlined: true.
+			aNode shouldBeAliased: true.
 			aNode receiver ifNotNil: [ :receiver |
-				receiver shouldBeAliased: true ] ] ].
+				(IRSendInliner inlinedSelectorsNeedingIdempotentReceiver includes: aNode selector) ifTrue: [
+					receiver shouldBeAliased: true ] ] ] ].
 
 	^ super visitSendNode: aNode
 ! !
@@ -79,22 +80,6 @@ IRInlinedSend subclass: #IRInlinedIfNilIfNotNil
 !IRInlinedIfNilIfNotNil commentStamp!
 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'!
 
 acceptDagVisitor: aVisitor
@@ -262,11 +247,10 @@ visitIRInlinedIfFalse: anIRInlinedIfFalse
 visitIRInlinedIfNilIfNotNil: anIRInlinedIfNilIfNotNil
 	self stream
 		nextPutIf: [
-			| recvVarName |
-			recvVarName := anIRInlinedIfNilIfNotNil receiverInternalVariableName.
-			self stream nextPutAll: '(', recvVarName, ' = '.
 			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 ]
 		else: [ self visit: anIRInlinedIfNilIfNotNil dagChildren third ]
 !
@@ -332,14 +316,18 @@ inlinedSequence
 !IRSendInliner methodsFor: 'inlining'!
 
 ifFalse: anIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
 	^ self inlinedSend: IRInlinedIfFalse new withBlock: anIRInstruction
 !
 
 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
+	self mustBeNiladicClosure: anIRInstruction.
 	^ self
 		inlinedSend: IRInlinedIfNilIfNotNil new
 		withBlock: anIRInstruction
@@ -352,10 +340,13 @@ ifNil: anIRInstruction
 !
 
 ifNil: anIRInstruction ifNotNil: anotherIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
+	self mustBeNiladicOrUnaryClosure: anotherIRInstruction.
 	^ self inlinedSend: IRInlinedIfNilIfNotNil new withBlock: anIRInstruction withBlock: anotherIRInstruction
 !
 
 ifNotNil: anIRInstruction
+	self mustBeNiladicOrUnaryClosure: anIRInstruction.
 	^ self
 		inlinedSend: IRInlinedIfNilIfNotNil new
 		withBlock: (IRClosure new
@@ -368,14 +359,19 @@ ifNotNil: anIRInstruction
 !
 
 ifNotNil: anIRInstruction ifNil: anotherIRInstruction
+	self mustBeNiladicOrUnaryClosure: anIRInstruction.
+	self mustBeNiladicClosure: anotherIRInstruction.
 	^ self inlinedSend: IRInlinedIfNilIfNotNil new withBlock: anotherIRInstruction withBlock: anIRInstruction
 !
 
 ifTrue: anIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
 	^ self inlinedSend: IRInlinedIfTrue new withBlock: anIRInstruction
 !
 
 ifTrue: anIRInstruction ifFalse: anotherIRInstruction
+	self mustBeNiladicClosure: anIRInstruction.
+	self mustBeNiladicClosure: anotherIRInstruction.
 	^ self inlinedSend: IRInlinedIfTrueIfFalse new withBlock: anIRInstruction withBlock: anotherIRInstruction
 !
 
@@ -398,8 +394,8 @@ inlineClosure: anIRClosure
 	anIRClosure arguments do: [ :each |
 		inlinedClosure add: (IRTempDeclaration new name: each; yourself).
 		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) ].
 			
 	"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
-	| sequence statements final |
+	| sequence final |
 
 	sequence := closure sequence.
-	statements := sequence dagChildren.
 	
 	sequence dagChildren ifEmpty: [ sequence add: (IRVariable new
 		variable: (closure scope pseudoVars at: 'nil');
 		yourself) ].
-	final := statements last.
+	final := sequence dagChildren last.
 	final yieldsValue ifTrue: [ sequence replace: final with: (aBlock value: final) ].
 
 	^ closure
@@ -449,9 +444,6 @@ inlineSend: anIRSend andReplace: anIRInstruction
 inlinedSend: inlinedSend withBlock: anIRInstruction
 	| 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).
 
 	inlinedSend
@@ -468,9 +460,6 @@ inlinedSend: inlinedSend withBlock: anIRInstruction
 inlinedSend: inlinedSend withBlock: anIRInstruction withBlock: anotherIRInstruction
 	| 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).
 	inlinedClosure2 := self translator visit: (self inlineClosure: anotherIRInstruction).
 
@@ -486,12 +475,28 @@ inlinedSend: inlinedSend withBlock: anIRInstruction withBlock: anotherIRInstruct
 	^ 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'!
 
 inlinedSelectors
 	^ #('ifTrue:' 'ifFalse:' 'ifTrue:ifFalse:' 'ifFalse:ifTrue:' 'ifNil:' 'ifNotNil:' 'ifNil:ifNotNil:' 'ifNotNil:ifNil:')
 !
 
+inlinedSelectorsNeedingIdempotentReceiver
+	^ #('ifNil:' 'ifNotNil:' 'ifNil:ifNotNil:' 'ifNotNil:ifNil:')
+!
+
 shouldInline: anIRSend
 	(self inlinedSelectors includes: anIRSend selector) ifFalse: [ ^ false ].
 	anIRSend receiver isSuper ifTrue: [ ^ false ].
@@ -619,6 +624,23 @@ SemanticError subclass: #InliningError
 !InliningError commentStamp!
 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'!
 
 asInlinedBlockResult

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 292 - 227
lang/src/Compiler-Interpreter.js


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

@@ -60,7 +60,7 @@ valueWithPossibleArguments: aCollection
 	context := outerContext newInnerContext.
 
 	"Interpret a copy of the sequence node to avoid creating a new AIBlockClosure"
-	sequenceNode := node dagChildren first copy
+	sequenceNode := node sequenceNode copy
 		parent: nil;
 		yourself.
 		
@@ -372,7 +372,7 @@ lookupContextForLocal: aString ifNone: aBlock
 			self outerContext 
 				ifNil: aBlock
 				ifNotNil: [ :context | 
-					context lookupContextForLocal: aString ] ]
+					context lookupContextForLocal: aString ifNone: aBlock ] ]
 ! !
 
 !AIContext methodsFor: 'testing'!
@@ -409,7 +409,7 @@ context: anAIContext
 
 visitVariableNode: aNode
 	self context 
-		localAt: aNode value 
+		localAt: aNode identifier 
 		ifAbsent: [ ^ super visitVariableNode: aNode ].
 
 	aNode binding: ASTContextVar new
@@ -656,13 +656,12 @@ interpret
 !
 
 next
-	| nd nextNode |
+	| nd parent |
 	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
@@ -702,9 +701,7 @@ stepOver
 !ASTInterpreter methodsFor: 'private'!
 
 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
@@ -739,13 +736,37 @@ messageNotUnderstood: aMessage receiver: anObject
 		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 ].
 		
 	^ method sendTo: anObject arguments: aMessage arguments
@@ -875,11 +896,16 @@ visitSendNode: aNode
 		messageFromSendNode: aNode
 		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"
-	(aNode isCascadeSendNode and: [ aNode isLastChild not ])
-		ifFalse: [ self pop; push: result ]
+	aNode isSideEffect ifFalse: [ self pop; push: result ]
 !
 
 visitValueNode: aNode
@@ -887,19 +913,7 @@ visitValueNode: 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
@@ -972,10 +986,6 @@ AIContext setTraitComposition: {TMethodContext} asTraitComposition!
 
 !ASTNode methodsFor: '*Compiler-Interpreter'!
 
-isLastChild
-	^ self parent dagChildren last = self
-!
-
 isSteppingNode
 	^ false
 !
@@ -988,6 +998,12 @@ nextSiblingNode: aNode
 		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'!
 
 isSteppingNode
@@ -1008,6 +1024,14 @@ nextSiblingNode: aNode
 	^ nil
 ! !
 
+!ClassRefVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ Smalltalk globals 
+		at: self name 
+		ifAbsent: [ Platform globals at: self name ]
+! !
+
 !DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
 
 isSteppingNode
@@ -1020,19 +1044,92 @@ isSteppingNode
 	^ 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'!
 
 isSteppingNode
 	^ 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
 	^ 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
+! !
+

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 414 - 315
lang/src/Compiler-Semantic.js


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

@@ -1,4 +1,75 @@
 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
 	slots: {#node. #instruction. #temps. #args. #outerScope. #blockIndex}
 	package: 'Compiler-Semantic'!
@@ -23,10 +94,10 @@ args
 	^ 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
@@ -45,12 +116,12 @@ instruction: anIRInstruction
 	instruction := anIRInstruction
 !
 
-lookupVariable: aNode
+lookupVariable: aString
 	| lookup |
-	lookup := (self bindingFor: aNode).
+	lookup := (self bindingFor: aString).
 	lookup ifNil: [
 		lookup := self outerScope ifNotNil: [
-			(self outerScope lookupVariable: aNode) ]].
+			(self outerScope lookupVariable: aString) ]].
 	^ lookup
 !
 
@@ -115,8 +186,7 @@ isBlockScope
 !
 
 isInlined
-	^ self instruction notNil and: [
-		self instruction isInlined ]
+	^ self instruction ifNil: [ false ] ifNotNil: [ :instr | instr isInlined ]
 !
 
 isMethodScope
@@ -124,7 +194,7 @@ isMethodScope
 ! !
 
 LexicalScope subclass: #MethodLexicalScope
-	slots: {#iVars. #pseudoVars. #unknownVariables. #localReturn. #nonLocalReturns}
+	slots: {#iVars. #pseudoVars. #localReturn. #nonLocalReturns}
 	package: 'Compiler-Semantic'!
 !MethodLexicalScope commentStamp!
 I represent a method scope.!
@@ -135,9 +205,9 @@ allVariableNames
 	^ 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
@@ -168,10 +238,6 @@ pseudoVars
 				scope: self methodScope;
 				yourself) ] ].
 	^ pseudoVars
-!
-
-unknownVariables
-	^ unknownVariables ifNil: [ unknownVariables := OrderedCollection new ]
 ! !
 
 !MethodLexicalScope methodsFor: 'adding'!
@@ -238,47 +304,21 @@ scope: aScope
 
 !ScopeVar methodsFor: 'testing'!
 
-isArgVar
+isAssignable
 	^ false
 !
 
-isClassRefVar
+isIdempotent
 	^ false
 !
 
 isImmutable
-	^ false
-!
-
-isInstanceVar
-	^ false
-!
-
-isPseudoVar
-	^ false
-!
-
-isSelf
-	^ false
+	self deprecatedAPI: 'Use #isIdempotent / #isAssignable not instead.'.
+	^ self isIdempotent
 !
 
 isSuper
 	^ false
-!
-
-isTempVar
-	^ false
-!
-
-isUnknownVar
-	^ false
-!
-
-validateAssignment
-	(self isArgVar or: [ self isPseudoVar ]) ifTrue: [
-		InvalidAssignmentError new
-			variableName: self name;
-			signal]
 ! !
 
 !ScopeVar class methodsFor: 'instance creation'!
@@ -290,24 +330,18 @@ on: aString
 ! !
 
 ScopeVar subclass: #AliasVar
-	slots: {#node}
+	slots: {}
 	package: 'Compiler-Semantic'!
 !AliasVar commentStamp!
 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
 ! !
 
@@ -319,11 +353,7 @@ I am an argument of a method or block.!
 
 !ArgVar methodsFor: 'testing'!
 
-isArgVar
-	^ true
-!
-
-isImmutable
+isIdempotent
 	^ true
 ! !
 
@@ -339,15 +369,11 @@ alias
 	^ '$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
 	slots: {}
@@ -361,7 +387,7 @@ alias
 	^ '$self.', self name
 !
 
-isInstanceVar
+isAssignable
 	^ true
 ! !
 
@@ -381,19 +407,11 @@ alias
 
 !PseudoVar methodsFor: 'testing'!
 
-isImmutable
+isIdempotent
 	^ true
-!
-
-isPseudoVar
-	^ true
-!
-
-isSelf
-	^ name = 'self'
 ! !
 
-PseudoVar class slots: {#dictionary}!
+PseudoVar class slots: {#dictionary. #receiverNames}!
 
 !PseudoVar class methodsFor: 'accessing'!
 
@@ -406,6 +424,14 @@ dictionary
 		at: #true put: PseudoVar;
 		at: #thisContext put: ThisContextVar;
 		yourself ]
+!
+
+receiverNames
+	^ receiverNames ifNil: [ receiverNames := Dictionary new
+		at: #self put: '$self';
+		at: #super put: '$self';
+		at: #nil put: '$nil';
+		yourself ]
 ! !
 
 PseudoVar subclass: #SuperVar
@@ -416,10 +442,6 @@ I am a 'super' pseudo variable.!
 
 !SuperVar methodsFor: 'accessing'!
 
-alias
-	^ '$self'
-!
-
 lookupAsJavaScriptSource
 	^ '($methodClass.superclass||$boot.nilAsClass).fn.prototype'
 ! !
@@ -430,6 +452,16 @@ isSuper
 	^ true
 ! !
 
+SuperVar subclass: #JavaScriptSuperVar
+	slots: {}
+	package: 'Compiler-Semantic'!
+
+!JavaScriptSuperVar methodsFor: 'accessing'!
+
+lookupAsJavaScriptSource
+	^ 'Object.getPrototypeOf($methodClass.fn.prototype)'
+! !
+
 PseudoVar subclass: #ThisContextVar
 	slots: {}
 	package: 'Compiler-Semantic'!
@@ -450,19 +482,7 @@ I am an temporary variable of a method or block.!
 
 !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
 ! !
 
@@ -500,32 +520,22 @@ thePackage: aPackage
 
 !SemanticAnalyzer methodsFor: 'error handling'!
 
+errorInvalidAssignment: aString
+	InvalidAssignmentError new
+		variableName: aString;
+		signal
+!
+
 errorShadowingVariable: aString
 	ShadowingVariableError new
 		variableName: aString;
 		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'!
@@ -546,6 +556,26 @@ newScopeOfClass: aLexicalScopeClass
 
 !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
 	blockIndex ifNil: [ blockIndex := 0 ].
 	
@@ -574,21 +604,24 @@ validateVariableScope: aString
 
 !SemanticAnalyzer methodsFor: 'testing'!
 
-isVariableUndefined: aString inPackage: aPackage
+isVariableKnown: aString inPackage: aPackage
 	aPackage ifNotNil: [
 		| 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'!
 
 visitAssignmentNode: aNode
+	| lhs |
 	super visitAssignmentNode: aNode.
-	aNode left beAssigned
+	lhs := aNode left.
+	lhs isAssignable ifFalse: [ self errorInvalidAssignment: lhs identifier ].
+	lhs assigned: true
 !
 
 visitBlockNode: aNode
@@ -607,6 +640,7 @@ visitBlockNode: aNode
 
 visitCascadeNode: aNode
 	aNode receiver: aNode dagChildren first receiver.
+	aNode dagChildren allButLast do: [ :each | each beSideEffect ].
 	super visitCascadeNode: aNode
 !
 
@@ -659,21 +693,10 @@ visitSequenceNode: aNode
 
 visitVariableNode: aNode
 	"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'!
@@ -755,3 +778,15 @@ 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
+! !
+

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1371 - 422
lang/src/Compiler-Tests.js


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

@@ -1,10 +1,14 @@
 Smalltalk createPackage: 'Compiler-Tests'!
 TestCase subclass: #ASTMethodRunningTest
-	slots: {#receiver}
+	slots: {#receiver. #arguments}
 	package: 'Compiler-Tests'!
 
 !ASTMethodRunningTest methodsFor: 'accessing'!
 
+arguments
+	^ arguments
+!
+
 receiver
 	^ receiver
 ! !
@@ -12,6 +16,7 @@ receiver
 !ASTMethodRunningTest methodsFor: 'initialization'!
 
 setUp
+	arguments := #().
 	receiver := DoIt new
 ! !
 
@@ -45,6 +50,14 @@ ASTMethodRunningTest subclass: #AbstractCompilerTest
 
 !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
 	self should: 'foo | a | a := true ifTrue: [ 1 ]. ^ a' return: 1.
 	self should: 'foo | a | a := false ifTrue: [ 1 ]. ^ a' return: nil.
@@ -455,6 +468,135 @@ AbstractCompilerTest subclass: #InliningCodeGeneratorTest
 	slots: {}
 	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
 	slots: {}
 	package: 'Compiler-Tests'!
@@ -472,17 +614,26 @@ astPCNodeVisitorForSelector: aString
 		selector: aString;
 		index: 0;
 		yourself
+!
+
+newTeachableVisitor
+	| result |
+	result := Teachable new
+		whenSend: #visit: evaluate: [ :one | one acceptDagVisitor: result ];
+		acceptSend: #visitDagNode:.
+	^ result
 ! !
 
 !ASTPCNodeVisitorTest methodsFor: 'tests'!
 
 testJSStatementNode
-	| ast visitor |
+	| ast result |
 	
 	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
@@ -563,19 +714,134 @@ receiver
 
 !AbstractCodeGeneratorInstallTest methodsFor: 'testing'!
 
-shouldntInstall: aString
+shouldntInstall: aString andRaise: anErrorClass
 	| method |
 
 	[ self
 		should: [ method := self install: aString forClass: receiver class ]
-		raise: ParseError ]
+		raise: anErrorClass ]
 	ensure: [ method ifNotNil: [ receiver class removeCompiledMethod: method ] ]
 ! !
 
 !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
-	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
@@ -599,8 +865,29 @@ testNiladicJSOverrideDifferentNames
 		self assert: receiver foo equals: 10 ]
 !
 
+testNiladicJSOverrideInOneArg
+	receiver := ObjectMock new.
+	self
+		shouldntInstall: 'quux: anInteger <jsOverride: #mux> ^ (foo := foo + anInteger)'
+		andRaise: CompilerError
+!
+
 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'!
@@ -624,52 +911,78 @@ TestCase subclass: #ScopeVarTest
 !ScopeVarTest methodsFor: 'tests'!
 
 testClassRefVar
-	| node |
+	| node binding |
 	node := VariableNode new
-		value: 'Object';
+		identifier: 'Object';
 		yourself.
 	SemanticAnalyzer new 
 		pushScope: MethodLexicalScope new;
 		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
-		value: 'bzzz';
+		identifier: 'console';
 		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.
-		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
-	| 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
-	| node |
-	node := VariableNode new
-		value: 'bzzz';
-		yourself.
-	self assert: (MethodLexicalScope new bindingFor: node) isNil
+	self assert: (MethodLexicalScope new bindingFor: 'bzzz') isNil
 ! !
 
 TestCase subclass: #SemanticAnalyzerTest
@@ -719,7 +1032,7 @@ testScope
 	ast := Smalltalk parse: src.
 	analyzer visit: ast.
 
-	self deny: ast dagChildren first dagChildren last scope == ast scope.
+	self deny: ast sequenceNode dagChildren last scope == ast scope.
 !
 
 testScope2
@@ -729,7 +1042,7 @@ testScope2
 	ast := Smalltalk parse: src.
 	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
@@ -740,7 +1053,7 @@ testScopeLevel
 	analyzer visit: ast.
 
 	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
@@ -804,12 +1117,14 @@ testVariablesLookup
 	analyzer visit: ast.
 
 	"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`"
-	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
@@ -916,7 +1231,7 @@ while: aString inClass: aClass should: aBlock
 		while: aString
 		inClass: aClass
 		should: [ :method | aBlock value: [
-			self receiver perform: method selector ] ]
+			self receiver perform: method selector withArguments: self arguments ] ]
 ! !
 
 Trait named: #TCTInlined
@@ -943,7 +1258,7 @@ interpret: aString forClass: aClass receiver: anObject withArguments: aDictionar
 	^ 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"
 	
 	| ctx ast |
@@ -960,9 +1275,9 @@ prepareContextFor: aString class: aClass receiver: anObject withArguments: aDict
 	ast sequenceNode ifNotNil: [ :sequence |
 		sequence temps do: [ :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
 		context: ctx;
@@ -983,7 +1298,7 @@ while: aString inClass: aClass should: aBlock
 				interpret: aString
 				forClass: aClass
 				receiver: self receiver
-				withArguments: #{} ] ]
+				withArguments: self arguments ] ]
 ! !
 
 Trait named: #TCTNonInlined
@@ -1002,6 +1317,11 @@ ASTDebuggerTest setTraitComposition: {TCTNonInlined. TCTDebugged} asTraitComposi
 ASTInterpreterTest setTraitComposition: {TCTNonInlined. TCTInterpreted} asTraitComposition!
 CodeGeneratorTest setTraitComposition: {TCTNonInlined. 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!
 ASTPositionTest setTraitComposition: {TASTParsingTest} 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);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._handlesAnnouncement_(anAnnouncement);
-if($core.assert($1)){
+if($core.assert($self._handlesAnnouncement_(anAnnouncement))){
 $recv($self._valuable())._value_(anAnnouncement);
 }
 return self;
@@ -341,14 +339,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $self.subscriptions=$recv($globals.OrderedCollection)._new();
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -397,27 +396,27 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$3,$5,$6,$4,$2;
+var $1,$2,$3;
 $1=$self.subscriptions;
-$3=$recv($globals.AnnouncementSubscription)._new();
+$2=[$recv($globals.AnnouncementSubscription)._new()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["new"]=1;
+,$ctx1.sendIdx["new"]=1
 //>>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);
-$ctx1.sendIdx["yourself"]=1;
+,$ctx1.sendIdx["yourself"]=1
 //>>excludeEnd("ctx");
-$4=$6;
-$recv($3)._valuable_($4);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["valuable:"]=1;
+,$ctx1.sendIdx["valuable:"]=1
 //>>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;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, 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);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$3,$5,$6,$4,$2;
+var $1,$2,$3;
 $1=$self.subscriptions;
-$3=$recv($globals.AnnouncementSubscription)._new();
+$2=[$recv($globals.AnnouncementSubscription)._new()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["new"]=1;
+,$ctx1.sendIdx["new"]=1
 //>>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);
-$ctx1.sendIdx["yourself"]=1;
+,$ctx1.sendIdx["yourself"]=1
 //>>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;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, 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);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.current;
-if(($receiver = $1) == null || $receiver.a$nil){
-$self.current=(
+if($1 == null || $1.a$nil){
+$self.current=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 return $self.current;
 } else {
 return $1;
@@ -1018,13 +1017,13 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self._theClass();
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 return $1;
 } else {
 var class_;
-class_=$receiver;
+class_=$1;
 return $recv(class_)._packageOfProtocol_($self._protocol());
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 263 - 261
lang/src/Kernel-Classes.js


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

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

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 325 - 191
lang/src/Kernel-Collections.js


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

@@ -229,6 +229,10 @@ asSet
 		yourself
 !
 
+copyEmpty
+	^ self class new
+!
+
 copyWith: anObject
 	^ self copy add: anObject; yourself
 !
@@ -370,6 +374,14 @@ errorNotFound
 	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'!
 
 putOn: aStream
@@ -542,10 +554,16 @@ removeKey: aKey ifAbsent: aBlock
 
 !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'!
@@ -654,6 +672,12 @@ printOn: aStream
 		do: [ :each | each printOn: aStream ]
 		separatedBy: [ 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'!
@@ -974,6 +998,10 @@ reversed
 
 copyFrom: anIndex to: anotherIndex
 	self subclassResponsibility
+!
+
+copyWithFirst: anObject
+	^ (self class with: anObject) addAll: self; yourself
 ! !
 
 !SequenceableCollection methodsFor: 'enumerating'!
@@ -1109,6 +1137,18 @@ reversed
 
 !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
 <inlineJS: '
 	if (anIndex >= 1 && anotherIndex <= self.length) {
@@ -1127,6 +1167,12 @@ shallowCopy
 
 !Array methodsFor: 'enumerating'!
 
+allIn: aBlock
+	^ aBlock valueWithPossibleArguments:
+		"collect to match #in: behaviour"
+		(self collect: [ :each | each in: [ :x | x ] ])
+!
+
 collect: aBlock
 	"Optimized version"
 	
@@ -1263,32 +1309,59 @@ remove: anObject ifAbsent: aBlock
 !String methodsFor: 'comparing'!
 
 < aString
-	<inlineJS: 'return String(self) < aString._asString()'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) < aString :
+	$recv(aString)._isStringLessThanSelf_(String(self))'>
 !
 
 <= aString
-	<inlineJS: 'return String(self) <= aString._asString()'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) <= aString :
+	$recv(aString)._isStringLessThanOrEqualToSelf_(String(self))'>
 !
 
 = 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
-<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
-	<inlineJS: 'return String(self) > aString._asString()'>
+<inlineJS: 'return typeof aString === "string" ?
+	String(self) > aString :
+	$recv(aString)._isStringGreaterThanSelf_(String(self))'>
 !
 
 >= 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'!
@@ -1381,13 +1454,25 @@ uriEncoded
 !String methodsFor: 'copying'!
 
 , 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
 	<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
 	^ self shallowCopy
 !
@@ -1428,6 +1513,12 @@ printOn: aStream
 		nextPutAll: ''''
 !
 
+shortenedPrintString
+	^ self printString size > 30
+		ifTrue: [ (self printString copyFrom: 1 to: 30), '...''' ]
+		ifFalse: [ self printString ]
+!
+
 symbolPrintString
 	^ String streamContents: [ :str | self asSymbolPrintOn: str ]
 ! !

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

@@ -149,16 +149,15 @@ var newChildren,oldChildren;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2;
+var $1;
 oldChildren=$recv(aNode)._dagChildren();
 newChildren=$self._visitAllChildren_(aNode);
-$1=$recv(oldChildren).__eq(newChildren);
-if($core.assert($1)){
+if($core.assert($recv(oldChildren).__eq(newChildren))){
 return aNode;
 } 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;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -213,14 +212,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $self.path=[];
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -271,14 +271,15 @@ $recv((function(){
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 $self.path=$recv($self.path).__comma([aNode]);
-result=(
+result=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx2.supercall = true,
 //>>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);
-$ctx2.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx2.supercall = false
+//>>excludeEnd("ctx");
+][0];
 return result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
@@ -312,17 +313,16 @@ var newNode;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-newNode=(
+newNode=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>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);
-$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);
 }
 return newNode;
@@ -378,12 +378,11 @@ var allNodes;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._dagChildren();
+allNodes=$recv([$self._dagChildren()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["dagChildren"]=1;
+,$ctx1.sendIdx["dagChildren"]=1
 //>>excludeEnd("ctx");
-allNodes=$recv($1)._asSet();
+][0])._asSet();
 $recv($self._dagChildren())._do_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -512,9 +511,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.nodes;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $self.nodes=$recv($globals.Array)._new();
 return $self.nodes;
 } 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);
 $globals.DagSink.comment="I am `DagNode` with no direct successors.\x0a\x0aSending `dagChildren:` with empty collection is legal.";
 //>>excludeEnd("ide");
+
+
+$core.addTrait("TDagSink", "Kernel-Dag");
 $core.addMethod(
 $core.method({
 selector: "dagChildren",
@@ -567,7 +569,7 @@ var self=this,$self=this;
 return [];
 
 }; }),
-$globals.DagSink);
+$globals.TDagSink);
 
 $core.addMethod(
 $core.method({
@@ -599,8 +601,134 @@ return self;
 }, function($ctx1) {$ctx1.fill(self,"dagChildren:",{aCollection:aCollection})});
 //>>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.method({

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

@@ -164,14 +164,17 @@ dagChildren: aCollection
 ! !
 
 DagNode subclass: #DagSink
-	slots: {#nodes}
+	slots: {}
 	package: 'Kernel-Dag'!
 !DagSink commentStamp!
 I am `DagNode` with no direct successors.
 
 Sending `dagChildren:` with empty collection is legal.!
 
-!DagSink methodsFor: 'accessing'!
+Trait named: #TDagSink
+	package: 'Kernel-Dag'!
+
+!TDagSink methodsFor: 'accessing'!
 
 dagChildren
 	^ #()
@@ -181,6 +184,41 @@ dagChildren: aCollection
 	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'!
 
 isDagNode

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

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

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

@@ -189,101 +189,6 @@ return false;
 $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.addMethod(
 $core.method({

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

@@ -50,27 +50,6 @@ isSymbol
 	^ 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
 	package: 'Kernel-Helpers'!
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 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
 <inlineJS: '
 	var anotherJSObject = anotherProxy.a$cls ? anotherProxy.jsObject : anotherProxy;
@@ -712,7 +722,7 @@ initialize
 ! !
 
 Object subclass: #Setting
-	slots: {#key. #value. #defaultValue}
+	slots: {#key. #defaultValue}
 	package: 'Kernel-Infrastructure'!
 !Setting commentStamp!
 I represent a setting **stored** at `Smalltalk settings`. 
@@ -868,7 +878,7 @@ settings
 version
 	"Answer the version string of Amber"
 	
-	^ '0.25.0-pre'
+	^ '0.28.2-pre'
 ! !
 
 !SmalltalkImage methodsFor: 'accessing amd'!
@@ -916,16 +926,16 @@ asSmalltalkException: 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 |
 	^ actionBlock
 		tryIfTrue: [ :error |
 			smalltalkError := self asSmalltalkException: error.
-			smalltalkError isKindOf: anErrorClass ]
-		catch: [ aBlock value: smalltalkError ]
+			aBlock value: smalltalkError ]
+		catch: [ anotherBlock value: smalltalkError ]
 ! !
 
 !SmalltalkImage methodsFor: 'globals'!

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

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

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

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

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 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]'>
 !
 
-instVarAt: aString put: anObject
+instVarNamed: aString put: anObject
 	<inlineJS: '$self[aString] = anObject'>
 !
 
@@ -208,8 +208,28 @@ basicDelete: 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
 	self error: 'Object not indexable'
+!
+
+timesSelfToNumber: aNumber
+	self error: 'I am not a number.'
 ! !
 
 !Object methodsFor: 'browsing'!
@@ -218,12 +238,58 @@ browse
 	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'!
 
 -> anObject
 	^ Association key: self value: anObject
 !
 
+andSelfToNumber: aNumber
+	self error: 'I am not a number.'
+!
+
 asJSONString
 	^ JSON stringify: self asJavaScriptObject
 !
@@ -232,16 +298,28 @@ asJavaScriptObject
 	| variables |
 	variables := HashedCollection new.
 	self class allInstanceVariableNames do: [ :each |
-		variables at: each put: (self instVarAt: each) asJavaScriptObject ].
+		variables at: each put: (self instVarNamed: each) asJavaScriptObject ].
 	^ variables
 !
 
 asJavaScriptSource
 	^ self asString
+!
+
+orSelfToNumber: aNumber
+	self error: 'I am not a number.'
+!
+
+xorSelfToNumber: aNumber
+	self error: 'I am not a number.'
 ! !
 
 !Object methodsFor: 'copying'!
 
+appendToString: aString
+	self error: 'Cannot add self to a string.'
+!
+
 copy
 	^ 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'!
 
 * aNumber
-	<inlineJS: 'return self * aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self * aNumber :
+		$recv(aNumber)._timesSelfToNumber_(self)'>
 !
 
 + aNumber
-	<inlineJS: 'return self + aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self + aNumber :
+		$recv(aNumber)._plusSelfToNumber_(self)'>
 !
 
 - aNumber
-	<inlineJS: 'return self - aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self - aNumber :
+		$recv(aNumber)._minusSelfToNumber_(self)'>
 !
 
 / aNumber
-	<inlineJS: 'return self / aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self / aNumber :
+		$recv(aNumber)._divideBySelfToNumber_(self)'>
 !
 
 // aNumber
@@ -747,13 +833,23 @@ My instances can also be used to evaluate a block a fixed number of times:
 !
 
 \\ aNumber
-	<inlineJS: 'return self % aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self % aNumber :
+		$recv(aNumber)._divisionRemainderBySelfToNumber_(self)'>
 !
 
 abs
 	<inlineJS: 'return Math.abs(self);'>
 !
 
+divideBySelfToNumber: aNumber
+	<inlineJS: 'return aNumber / self'>
+!
+
+divisionRemainderBySelfToNumber: aNumber
+	<inlineJS: 'return aNumber % self'>
+!
+
 max: aNumber
 	<inlineJS: 'return Math.max(self, aNumber);'>
 !
@@ -766,46 +862,88 @@ min: aMin max: aMax
 	^ (self min: aMin) max: aMax
 !
 
+minusSelfToNumber: aNumber
+	<inlineJS: 'return aNumber - self'>
+!
+
 negated
 	^ 0 - self
+!
+
+plusSelfToNumber: aNumber
+	<inlineJS: 'return aNumber + self'>
+!
+
+timesSelfToNumber: aNumber
+	<inlineJS: 'return aNumber * self'>
 ! !
 
 !Number methodsFor: 'comparing'!
 
 < aNumber
-	<inlineJS: 'return self < aNumber'>
+<inlineJS: 'return typeof aNumber === "number" ?
+	Number(self) < aNumber :
+	$recv(aNumber)._isNumberLessThanSelf_(self)'>
 !
 
 <= aNumber
-	<inlineJS: 'return self <= aNumber'>
+<inlineJS: 'return typeof aNumber === "number" ?
+	Number(self) <= aNumber :
+	$recv(aNumber)._isNumberLessThanOrEqualToSelf_(self)'>
 !
 
 == 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
-	<inlineJS: 'return self > aNumber'>
+<inlineJS: 'return typeof aNumber === "number" ?
+	Number(self) > aNumber :
+	$recv(aNumber)._isNumberGreaterThanSelf_(self)'>
 !
 
 >= 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'!
 
 & aNumber
-	<inlineJS: 'return self & aNumber'>
+	^ self bitAnd: aNumber
 !
 
 @ aNumber
 	^ Point x: self y: aNumber
 !
 
+andSelfToNumber: aNumber
+	<inlineJS: 'return aNumber & self'>
+!
+
 asJavaScriptObject
 	^ self
 !
@@ -831,7 +969,9 @@ atRandom
 !
 
 bitAnd: aNumber
-	<inlineJS: 'return self & aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self & aNumber :
+		$recv(aNumber)._andSelfToNumber_(self)'>
 !
 
 bitNot
@@ -839,11 +979,15 @@ bitNot
 !
 
 bitOr: aNumber
-	<inlineJS: 'return self | aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self | aNumber :
+		$recv(aNumber)._orSelfToNumber_(self)'>
 !
 
 bitXor: aNumber
-	<inlineJS: 'return self ^ aNumber'>
+	<inlineJS: 'return typeof aNumber === "number" ?
+		self ^ aNumber :
+		$recv(aNumber)._xorSelfToNumber_(self)'>
 !
 
 ceiling
@@ -858,6 +1002,10 @@ floor
 	<inlineJS: 'return Math.floor(self);'>
 !
 
+orSelfToNumber: aNumber
+	<inlineJS: 'return aNumber | self'>
+!
+
 printStringBase: aBase
 	<inlineJS: 'return self.toString(aBase)'>
 !
@@ -911,8 +1059,12 @@ truncated
 	'>
 !
 
+xorSelfToNumber: aNumber
+	<inlineJS: 'return aNumber ^ self'>
+!
+
 | aNumber
-	<inlineJS: 'return self | aNumber'>
+	^ self bitOr: aNumber
 ! !
 
 !Number methodsFor: 'copying'!
@@ -1048,10 +1200,20 @@ even
 	^ 0 = (self \\ 2)
 !
 
+isFinite
+	"Answer whether the receiver is finite"
+	<inlineJS: 'return Number.isFinite(self)'>
+!
+
 isImmutable
 	^ true
 !
 
+isNaN
+	"Answer whether the receiver is IEEE-754 not-a-number"
+	<inlineJS: 'return Number.isNaN(self)'>
+!
+
 isNumber
 	^ true
 !
@@ -1092,10 +1254,18 @@ e
 	<inlineJS: 'return Math.E;'>
 !
 
+negativeInfinity
+	<inlineJS: 'return Number.NEGATIVE_INFINITY'>
+!
+
 pi
 	<inlineJS: 'return Math.PI'>
 !
 
+positiveInfinity
+	<inlineJS: 'return Number.POSITIVE_INFINITY'>
+!
+
 radiansPerDegree
 	^ (self pi) / 180
 ! !

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

@@ -184,19 +184,17 @@ selector: "catch:",
 protocol: "promises",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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: [],
 //>>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: []
 }, function ($methodClass){ return function (aBlock){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"catch:",{aBlock:aBlock})});
@@ -210,20 +208,20 @@ selector: "on:do:",
 protocol: "promises",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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: [],
 //>>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: []
 }, function ($methodClass){ return function (aClass,aBlock){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
     else throw err;
-})});
+});
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{aClass:aClass,aBlock:aBlock})});
@@ -260,10 +258,10 @@ selector: "then:",
 protocol: "promises",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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: [],
 //>>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: []
 }, function ($methodClass){ return function (aBlockOrArray){
 var self=this,$self=this;
@@ -274,16 +272,16 @@ return $core.withContext(function($ctx1) {
 var array = Array.isArray(aBlockOrArray) ? aBlockOrArray : [aBlockOrArray];
 return array.reduce(function (soFar, aBlock) {
     return soFar.then(typeof aBlock === "function" && aBlock.length > 1 ?
-        function (result) {return $core.seamless(function () {
+       function (result) {
             if (Array.isArray(result)) {
                 return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));
             } else {
                 return aBlock._value_(result);
             }
-        })} :
-        function (result) {return $core.seamless(function () {
+        } :
+        function (result) {
             return aBlock._value_(result);
-        })}
+        }
     );
 }, self);
 return self;

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

@@ -57,16 +57,14 @@ Trait named: #TThenable
 !TThenable methodsFor: 'promises'!
 
 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
-<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);
     else throw err;
-})})'>
+})'>
 !
 
 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];
 return array.reduce(function (soFar, aBlock) {
     return soFar.then(typeof aBlock === "function" && aBlock.length > 1 ?
-        function (result) {return $core.seamless(function () {
+       function (result) {
             if (Array.isArray(result)) {
                 return aBlock._valueWithPossibleArguments_([result].concat(result.slice(0, aBlock.length-1)));
             } else {
                 return aBlock._value_(result);
             }
-        })} :
-        function (result) {return $core.seamless(function () {
+        } :
+        function (result) {
             return aBlock._value_(result);
-        })}
+        }
     );
 }, self)'>
 !

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 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
 !
 
+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
 	| instance theMethod anObject |
 	theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.
@@ -780,8 +796,7 @@ testComma
 	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 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
@@ -794,6 +809,12 @@ testCopy
 	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
 	| original copy |
 	original := self collection.
@@ -980,13 +1001,6 @@ testAsHashedCollection
 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
 "Accept a collection of associations."
 | associations |
@@ -1048,6 +1062,13 @@ testRemoveKeyIfAbsent
 		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
 	self assert:self collectionClass new values isEmpty.
 	self assertSameContents:self collection values as: self collectionValues.
@@ -1327,6 +1348,10 @@ testLastN
 	self should: [ self collection last: 33 ] raise: Error
 !
 
+testOrderedComma
+	self assertSameContents: self sampleNewValueAsCollection, self collection as: self collectionWithNewValue
+!
+
 testSecond
 	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
 !
 
-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
 	self assert: #(0 2) 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 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'!
@@ -2644,11 +2669,11 @@ testIfNil
 testInstVars
 	| o |
 	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

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

@@ -108,6 +108,57 @@ return window;
 }; }),
 $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.method({
 selector: "newXhr",
@@ -124,8 +175,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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.");
 } else {
 return $recv($globals.NativeFunction)._constructorOf_($globals.XMLHttpRequest);
@@ -154,9 +206,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._isFeasible();
-if($core.assert($1)){
+if($core.assert($self._isFeasible())){
 $recv($globals.Platform)._registerIfNone_($self._new());
 }
 return self;
@@ -304,9 +354,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._isFeasible();
-if($core.assert($1)){
+if($core.assert($self._isFeasible())){
 $recv($globals.Terminal)._registerIfNone_($self._new());
 }
 return self;

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

@@ -26,6 +26,14 @@ fetchUrl: aString options: anObject
 		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
 	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);
 return $core.withContext(function($ctx1) {
 //>>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(),"©");
 }
 return self;
@@ -49,9 +47,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($globals.PlatformDom)._isFeasible();
-if($core.assert($1)){
+if($core.assert($recv($globals.PlatformDom)._isFeasible())){
 $self._shouldnt_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 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);
 return $core.withContext(function($ctx1) {
 //>>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;
 } else {
-$2=(
+return [(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._asDomNode.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._asDomNode.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-return $2;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 }
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 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);
 return $core.withContext(function($ctx1) {
 //>>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.");
 } else {
 return $recv($globals.XMLHttpRequest)._new();
@@ -154,9 +155,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._isFeasible();
-if($core.assert($1)){
+if($core.assert($self._isFeasible())){
 $recv($globals.Platform)._registerIfNone_($self._new());
 }
 return self;

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

@@ -24,12 +24,13 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
-$1=$recv(anError)._context();
+var $1;
+$1=[$recv(anError)._context()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["context"]=1;
+,$ctx1.sendIdx["context"]=1
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 $1;
 } else {
 $self._logErrorContext_($recv(anError)._context());
@@ -82,12 +83,13 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
-$1=$recv(aContext)._home();
+var $1;
+$1=[$recv(aContext)._home()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["home"]=1;
+,$ctx1.sendIdx["home"]=1
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 $1;
 } else {
 $self._logContext_($recv(aContext)._home());
@@ -140,15 +142,16 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
-if(($receiver = aContext) == null || $receiver.a$nil){
+var $1;
+if(aContext == null || aContext.a$nil){
 aContext;
 } else {
-$1=$recv(aContext)._home();
+$1=[$recv(aContext)._home()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["home"]=1;
+,$ctx1.sendIdx["home"]=1
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 $1;
 } else {
 $self._logContext_($recv(aContext)._home());
@@ -317,23 +320,19 @@ var newInstVars;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$3,$4,$5;
 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);
-$ctx1.sendIdx["classBuilder"]=1;
+,$ctx1.sendIdx["classBuilder"]=1
 //>>excludeEnd("ctx");
-$recv($2)._class_slots_(aClass,newInstVars);
+][0])._class_slots_(aClass,newInstVars);
 } 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);
-$ctx1.sendIdx["name"]=1;
+,$ctx1.sendIdx["name"]=1
 //>>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;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -444,13 +443,14 @@ var protocols;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 protocols=$recv(aClass)._protocols();
-$1=$recv(aClass)._superclass();
+$1=[$recv(aClass)._superclass()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["superclass"]=1;
+,$ctx1.sendIdx["superclass"]=1
 //>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
+][0];
+if($1 == null || $1.a$nil){
 $1;
 } else {
 $recv(protocols)._addAll_($self._availableProtocolsFor_($recv(aClass)._superclass()));
@@ -501,9 +501,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $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");
 } else {
 return $1;
@@ -664,16 +664,16 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
+var $1;
 $1=$recv($recv($globals.Smalltalk)._globals())._at_(aClassName);
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $1;
 } 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);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
-$self._error_($2);
+][0]);
 }
 $recv($recv($globals.ClassBuilder)._new())._copyClass_named_(aClass,aClassName);
 return self;
@@ -735,17 +735,17 @@ selector: "evaluate:on:do:",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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");
 pragmas: [],
-messageSends: ["do:on:do:", "classNamed:", "name"]
+messageSends: ["on:do:", "classNamed:", "name"]
 }, function ($methodClass){ return function (aBlock,anErrorClass,exceptionBlock){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
 }, function($ctx1) {$ctx1.fill(self,"evaluate:on:do:",{aBlock:aBlock,anErrorClass:anErrorClass,exceptionBlock:exceptionBlock})});
 //>>excludeEnd("ctx");
@@ -793,16 +793,15 @@ var package_;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
+var $1;
 package_=$recv($globals.Package)._named_(aPackageName);
 $1=package_;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $self._error_("Invalid package name");
 } else {
 $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;
 }
 $recv(aClass)._package_(package_);
@@ -831,23 +830,19 @@ var destinationClass;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$3,$1,$5,$4;
 destinationClass=$self._classNamed_(aClassName);
-$2=destinationClass;
-$3=$recv(aMethod)._origin();
+if($core.assert($recv(destinationClass).__eq_eq([$recv(aMethod)._origin()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["origin"]=1;
+,$ctx1.sendIdx["origin"]=1
 //>>excludeEnd("ctx");
-$1=$recv($2).__eq_eq($3);
-if($core.assert($1)){
+][0]))){
 return self;
 }
-$5=$recv(aMethod)._origin();
+if($core.assert($recv([$recv(aMethod)._origin()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["origin"]=2;
+,$ctx1.sendIdx["origin"]=2
 //>>excludeEnd("ctx");
-$4=$recv($5)._isMetaclass();
-if($core.assert($4)){
+][0])._isMetaclass())){
 destinationClass=$recv(destinationClass)._theMetaClass();
 destinationClass;
 }
@@ -1124,16 +1119,16 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
+var $1;
 $1=$recv($recv($globals.Smalltalk)._globals())._at_(aClassName);
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $1;
 } 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);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
-$self._error_($2);
+][0]);
 }
 $recv($recv($globals.ClassBuilder)._new())._renameClass_to_(aClass,aClassName);
 return self;
@@ -1386,9 +1381,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self._current();
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $self._register_(anObject);
 } else {
 $1;
@@ -1423,10 +1418,10 @@ var smalltalkError;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 smalltalkError=$recv($globals.Smalltalk)._asSmalltalkException_(anError);
 $1=$recv(smalltalkError)._context();
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $recv(smalltalkError)._context_($core.getThisContext());
 } else {
 $1;
@@ -1455,9 +1450,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv(anError)._wasHandled();
-if(!$core.assert($1)){
+if(!$core.assert($recv(anError)._wasHandled())){
 $recv($self._current())._handleError_(anError);
 $recv(anError)._beHandled();
 }
@@ -1959,36 +1952,37 @@ 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: '#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");
 pragmas: [],
-messageSends: ["new", "at:put:", "keys", "keysAndValuesDo:", "setLabel:", "printString", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "keys", "nextPutAll:", "associations", "setLabel:", "shortenedPrintString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+variables=$recv($globals.Array)._streamContents_((function(stream){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#keys",$self._keys());
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=2;
+,$ctx2.sendIdx["->"]=1
 //>>excludeEnd("ctx");
-$self._keysAndValuesDo_((function(key,value){
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+,$ctx2.sendIdx["nextPut:"]=1
 //>>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);
-}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1,1)});
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)});
 //>>excludeEnd("ctx");
 }));
-$recv(anInspector)._setLabel_($self._printString());
+$recv(anInspector)._setLabel_($self._shortenedPrintString());
 $recv(anInspector)._setVariables_(variables);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2003,32 +1997,48 @@ 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\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");
 pragmas: [],
-messageSends: ["new", "at:put:", "withIndexDo:", "setLabel:", "printString", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "do:", "+", "setLabel:", "shortenedPrintString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
-$ctx1.sendIdx["at:put:"]=1;
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$self._withIndexDo_((function(each,i){
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+,$ctx2.sendIdx["->"]=1
 //>>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);
-}, 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");
 }));
-$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);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2043,47 +2053,89 @@ 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: '#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");
 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){
 var self=this,$self=this;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
-$ctx1.sendIdx["at:put:"]=1;
+,$ctx2.sendIdx["nextPut:"]=1
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#year",$self._year());
+][0];
+[$recv(stream)._nextPut_(["#year".__minus_gt($self._year())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=2;
+,$ctx2.sendIdx["->"]=2
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#month",$self._month());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=3;
+,$ctx2.sendIdx["nextPut:"]=2
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#day",$self._day());
+][0];
+[$recv(stream)._nextPut_(["#month".__minus_gt($self._month())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=4;
+,$ctx2.sendIdx["->"]=3
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#hours",$self._hours());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=5;
+,$ctx2.sendIdx["nextPut:"]=3
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#minutes",$self._minutes());
+][0];
+[$recv(stream)._nextPut_(["#day".__minus_gt($self._day())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=6;
+,$ctx2.sendIdx["->"]=4
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#seconds",$self._seconds());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=7;
+,$ctx2.sendIdx["nextPut:"]=4
 //>>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)._setVariables_(variables);
 return self;
@@ -2099,21 +2151,28 @@ 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 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");
 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){
 var self=this,$self=this;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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($globals.JSObjectProxy)._addObjectVariablesTo_ofProxy_(variables,self);
 $recv(anInspector)._setVariables_(variables);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2128,29 +2187,41 @@ 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\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");
 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){
 var self=this,$self=this;
 var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+variables=$recv($globals.Array)._streamContents_((function(stream){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$recv($recv($self._class())._allInstanceVariableNames())._do_((function(each){
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+,$ctx2.sendIdx["->"]=1
 //>>excludeEnd("ctx");
-return $recv(variables)._at_put_(each,$self._instVarAt_(each));
+][0])
 //>>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");
 }));
 $recv(anInspector)._setLabel_($self._printString());
@@ -2192,42 +2263,51 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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");
 pragmas: [],
-messageSends: ["new", "at:put:", "do:", "+", "setLabel:", "printString", "setVariables:"]
+messageSends: ["streamContents:", "nextPut:", "->", "withIndexDo:", "setLabel:", "shortenedPrintString", "setVariables:"]
 }, function ($methodClass){ return function (anInspector){
 var self=this,$self=this;
-var variables,i;
+var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+variables=$recv($globals.Array)._streamContents_((function(stream){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-i=(1);
-$self._do_((function(each){
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+,$ctx2.sendIdx["->"]=1
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_(i,each);
-i=$recv(i).__plus((1));
-return i;
+][0])
 //>>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");
 }));
-$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);
 return self;
 //>>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");
 }; }),
-$globals.Set);
+$globals.SequenceableCollection);
 
 $core.addMethod(
 $core.method({
@@ -2235,97 +2315,77 @@ selector: "inspectOn:",
 protocol: "*Platform-Services",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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");
 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){
 var self=this,$self=this;
-var label;
+var variables;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $3,$2,$1,$5,$4;
-(
+variables=$recv($globals.Array)._streamContents_((function(stream){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = true,
+return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._inspectOn_.call($self,anInspector));
+[$recv(stream)._nextPut_(["#self".__minus_gt(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-$3=$self._printString();
+,$ctx2.sendIdx["->"]=1
+//>>excludeEnd("ctx");
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["printString"]=1;
+,$ctx2.sendIdx["nextPut:"]=1
 //>>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);
-$ctx1.sendIdx["printString"]=2;
+,$ctx2.sendIdx["->"]=2
 //>>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);
-}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,label:label})});
+,$ctx2.sendIdx["nextPut:"]=2
 //>>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);
-return $core.withContext(function($ctx1) {
+,$ctx2.sendIdx["->"]=3
 //>>excludeEnd("ctx");
-variables=$recv($globals.Dictionary)._new();
-$recv(variables)._at_put_("#self",self);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=1;
+,$ctx2.sendIdx["nextPut:"]=3
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#home",$self._home());
+][0];
+[$recv(stream)._nextPut_(["#selector".__minus_gt($self._selector())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=2;
+,$ctx2.sendIdx["->"]=4
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#receiver",$self._receiver());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=3;
+,$ctx2.sendIdx["nextPut:"]=4
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#selector",$self._selector());
+][0];
+[$recv(stream)._nextPut_(["#locals".__minus_gt($self._locals())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=4;
+,$ctx2.sendIdx["->"]=5
 //>>excludeEnd("ctx");
-$recv(variables)._at_put_("#locals",$self._locals());
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["at:put:"]=5;
+,$ctx2.sendIdx["nextPut:"]=5
 //>>excludeEnd("ctx");
-$recv($recv($self._class())._instanceVariableNames())._do_((function(each){
+][0];
+return $recv($recv($self._class())._instanceVariableNames())._do_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+return $core.withContext(function($ctx3) {
 //>>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);
-}, 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");
 }));
 $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 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'!
@@ -534,13 +534,13 @@ show: anObject
 
 inspectOn: anInspector
 	| 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
-		setLabel: self printString;
+		setLabel: self shortenedPrintString;
 		setVariables: variables
 ! !
 
@@ -548,12 +548,15 @@ inspectOn: anInspector
 
 inspectOn: anInspector
 	| 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
-		setLabel: self printString;
+		setLabel: self shortenedPrintString;
 		setVariables: variables
 ! !
 
@@ -561,15 +564,16 @@ inspectOn: anInspector
 
 inspectOn: anInspector
 	| 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
 		setLabel: self printString;
 		setVariables: variables
@@ -579,10 +583,11 @@ inspectOn: anInspector
 
 inspectOn: anInspector
 	| 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.
-	JSObjectProxy addObjectVariablesTo: variables ofProxy: self.
 	anInspector setVariables: variables
 ! !
 
@@ -590,10 +595,10 @@ inspectOn: anInspector
 
 inspectOn: anInspector
 	| 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
 		setLabel: self printString;
 		setVariables: variables
@@ -606,46 +611,32 @@ do: aBlock displayingProgress: aString
 		do: aBlock 
 		on: self 
 		displaying: aString
-! !
-
-!Set methodsFor: '*Platform-Services'!
+!
 
 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
-		setLabel: self printString;
+		setLabel: self shortenedPrintString;
 		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'!
 
 inspectOn: anInspector
 	| 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 |
-		variables at: each put: (self instVarAt: each) ].
+		stream nextPut: each -> (self instVarNamed: each) ] ].
 	anInspector
 		setLabel: self printString;
 		setVariables: variables

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

@@ -99,7 +99,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-$self._should_raise_((function(){
+[$self._should_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -107,10 +107,11 @@ return $recv($self.empty)._at_((5));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
-}),$globals.Error);
+}),$globals.Error)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["should:raise:"]=1;
+,$ctx1.sendIdx["should:raise:"]=1
 //>>excludeEnd("ctx");
+][0];
 $self._should_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -143,15 +144,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($self.full)._includes_((5));
+[$self._assert_([$recv($self.full)._includes_((5))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["includes:"]=1;
+,$ctx1.sendIdx["includes:"]=1
 //>>excludeEnd("ctx");
-$self._assert_($1);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["assert:"]=1;
+,$ctx1.sendIdx["assert:"]=1
 //>>excludeEnd("ctx");
+][0];
 $self._assert_($recv($self.full)._includes_("abc"));
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -176,23 +177,24 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2;
-$1=$recv($self.empty)._occurrencesOf_((0));
+[$self._assert_equals_([$recv($self.empty)._occurrencesOf_((0))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["occurrencesOf:"]=1;
+,$ctx1.sendIdx["occurrencesOf:"]=1
 //>>excludeEnd("ctx");
-$self._assert_equals_($1,(0));
+][0],(0))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["assert:equals:"]=1;
+,$ctx1.sendIdx["assert:equals:"]=1
 //>>excludeEnd("ctx");
-$2=$recv($self.full)._occurrencesOf_((5));
+][0];
+[$self._assert_equals_([$recv($self.full)._occurrencesOf_((5))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["occurrencesOf:"]=2;
+,$ctx1.sendIdx["occurrencesOf:"]=2
 //>>excludeEnd("ctx");
-$self._assert_equals_($2,(1));
+][0],(1))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["assert:equals:"]=2;
+,$ctx1.sendIdx["assert:equals:"]=2
 //>>excludeEnd("ctx");
+][0];
 $recv($self.full)._add_((5));
 $self._assert_equals_($recv($self.full)._occurrencesOf_((5)),(1));
 return self;
@@ -218,13 +220,12 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
 $recv($self.full)._remove_((5));
-$1=$recv($self.full)._includes_("abc");
+$self._assert_([$recv($self.full)._includes_("abc")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["includes:"]=1;
+,$ctx1.sendIdx["includes:"]=1
 //>>excludeEnd("ctx");
-$self._assert_($1);
+][0]);
 $self._deny_($recv($self.full)._includes_((5)));
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -356,12 +357,12 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$self._timeout_((100));
+[$self._timeout_((100))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["timeout:"]=1;
+,$ctx1.sendIdx["timeout:"]=1
 //>>excludeEnd("ctx");
-$1=$self._async_((function(){
+][0];
+[$recv([$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -378,14 +379,15 @@ return $self._finished();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["async:"]=1;
+,$ctx1.sendIdx["async:"]=1
 //>>excludeEnd("ctx");
-$recv($1)._valueWithTimeout_((20));
+][0])._valueWithTimeout_((20))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["valueWithTimeout:"]=1;
+,$ctx1.sendIdx["valueWithTimeout:"]=1
 //>>excludeEnd("ctx");
+][0];
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"fakeMultipleTimeoutFailing",{})});
@@ -409,12 +411,12 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$self._timeout_((20));
+[$self._timeout_((20))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["timeout:"]=1;
+,$ctx1.sendIdx["timeout:"]=1
 //>>excludeEnd("ctx");
-$1=$self._async_((function(){
+][0];
+[$recv([$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -431,14 +433,15 @@ return $self._finished();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["async:"]=1;
+,$ctx1.sendIdx["async:"]=1
 //>>excludeEnd("ctx");
-$recv($1)._valueWithTimeout_((10));
+][0])._valueWithTimeout_((10))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["valueWithTimeout:"]=1;
+,$ctx1.sendIdx["valueWithTimeout:"]=1
 //>>excludeEnd("ctx");
+][0];
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"fakeMultipleTimeoutPassing",{})});
@@ -570,7 +573,6 @@ var suite,runner,result,assertBlock;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$3,$4;
 suite=["fakeError", "fakeErrorFailingInTearDown", "fakeFailure", "testPass"]._collect_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -582,26 +584,28 @@ return $recv($self._class())._selector_(each);
 }));
 runner=$recv($globals.TestSuiteRunner)._on_(suite);
 $self._timeout_((200));
-result=$recv(runner)._result();
+result=[$recv(runner)._result()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["result"]=1;
+,$ctx1.sendIdx["result"]=1
 //>>excludeEnd("ctx");
+][0];
 assertBlock=$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$1=$self._selectorSetOf_($recv(result)._errors());
+[$self._assert_equals_([$self._selectorSetOf_($recv(result)._errors())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["selectorSetOf:"]=1;
+,$ctx2.sendIdx["selectorSetOf:"]=1
 //>>excludeEnd("ctx");
-$2=["fakeError"]._asSet();
+][0],[["fakeError"]._asSet()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["asSet"]=1;
+,$ctx2.sendIdx["asSet"]=1
 //>>excludeEnd("ctx");
-$self._assert_equals_($1,$2);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["assert:equals:"]=1;
+,$ctx2.sendIdx["assert:equals:"]=1
 //>>excludeEnd("ctx");
+][0];
 $self._assert_equals_($self._selectorSetOf_($recv(result)._failures()),["fakeErrorFailingInTearDown", "fakeFailure"]._asSet());
 return $self._finished();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -612,10 +616,8 @@ $recv($recv(runner)._announcer())._on_do_($globals.ResultAnnouncement,(function(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>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);
 }, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1,3)});
@@ -649,12 +651,13 @@ $self._should_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-return $self._async_((function(){
+return [$self._async_((function(){
 
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["async:"]=1;
+,$ctx2.sendIdx["async:"]=1
 //>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
@@ -699,10 +702,11 @@ $self._should_raise_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-return $self._finished();
+return [$self._finished()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["finished"]=1;
+,$ctx2.sendIdx["finished"]=1
 //>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
@@ -740,21 +744,21 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2;
-$1=$self._isAsync();
+[$self._deny_([$self._isAsync()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["isAsync"]=1;
+,$ctx1.sendIdx["isAsync"]=1
 //>>excludeEnd("ctx");
-$self._deny_($1);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["deny:"]=1;
+,$ctx1.sendIdx["deny:"]=1
 //>>excludeEnd("ctx");
+][0];
 $self._timeout_((0));
-$2=$self._isAsync();
+$self._assert_([$self._isAsync()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["isAsync"]=2;
+,$ctx1.sendIdx["isAsync"]=2
 //>>excludeEnd("ctx");
-$self._assert_($2);
+][0]);
 $self._finished();
 $self._deny_($self._isAsync());
 return self;
@@ -818,7 +822,6 @@ var suite,runner,result,assertBlock;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$3;
 suite=["fakeTimeout", "fakeMultipleTimeoutFailing", "fakeMultipleTimeoutPassing", "testPass"]._collect_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -830,22 +833,24 @@ return $recv($self._class())._selector_(each);
 }));
 runner=$recv($globals.TestSuiteRunner)._on_(suite);
 $self._timeout_((200));
-result=$recv(runner)._result();
+result=[$recv(runner)._result()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["result"]=1;
+,$ctx1.sendIdx["result"]=1
 //>>excludeEnd("ctx");
+][0];
 assertBlock=$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$1=$self._selectorSetOf_($recv(result)._errors());
+[$self._assert_equals_([$self._selectorSetOf_($recv(result)._errors())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["selectorSetOf:"]=1;
+,$ctx2.sendIdx["selectorSetOf:"]=1
 //>>excludeEnd("ctx");
-$self._assert_equals_($1,$recv($globals.Set)._new());
+][0],$recv($globals.Set)._new())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["assert:equals:"]=1;
+,$ctx2.sendIdx["assert:equals:"]=1
 //>>excludeEnd("ctx");
+][0];
 $self._assert_equals_($self._selectorSetOf_($recv(result)._failures()),["fakeMultipleTimeoutFailing", "fakeTimeout"]._asSet());
 return $self._finished();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -856,10 +861,8 @@ $recv($recv(runner)._announcer())._on_do_($globals.ResultAnnouncement,(function(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>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);
 }, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1,3)});
@@ -890,38 +893,41 @@ var x;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
 $self.flag="bad";
 $self._timeout_((10));
 x=(0);
-$1=$self._async_((function(){
+$self.flag=[$recv([$self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$self._finished();
+[$self._finished()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["finished"]=1;
+,$ctx2.sendIdx["finished"]=1
 //>>excludeEnd("ctx");
+][0];
 $self.flag="ok";
-x=$recv(x).__plus((1));
+x=[$recv(x).__plus((1))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["+"]=1;
+,$ctx2.sendIdx["+"]=1
 //>>excludeEnd("ctx");
-return $self._assert_equals_(x,(1));
+][0];
+return [$self._assert_equals_(x,(1))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["assert:equals:"]=1;
+,$ctx2.sendIdx["assert:equals:"]=1
 //>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["async:"]=1;
+,$ctx1.sendIdx["async:"]=1
 //>>excludeEnd("ctx");
-$self.flag=$recv($1)._valueWithTimeout_((0));
+][0])._valueWithTimeout_((0))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["valueWithTimeout:"]=1;
+,$ctx1.sendIdx["valueWithTimeout:"]=1
 //>>excludeEnd("ctx");
+][0];
 $self.flag=$recv($self._async_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 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");
 //>>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.";
@@ -117,22 +326,19 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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);
-$ctx1.sendIdx["printString"]=1;
+,$ctx1.sendIdx["printString"]=1
 //>>excludeEnd("ctx");
-$4="Expected: ".__comma($5);
-$3=$recv($4).__comma(" but was: ");
+][0])).__comma(" but was: ")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=2;
+,$ctx1.sendIdx[","]=2
 //>>excludeEnd("ctx");
-$2=$recv($3).__comma($recv(actual)._printString());
+][0]).__comma($recv(actual)._printString())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
+,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
-return $self._assert_description_($1,$2);
+][0]);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"assert:equals:",{actual:actual,expected:expected})});
 //>>excludeEnd("ctx");
@@ -156,15 +362,13 @@ var c;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
 $self._errorIfNotAsync_("#async");
 c=$self.context;
 return (function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$1=$self._isAsync();
-if($core.assert($1)){
+if($core.assert($self._isAsync())){
 return $recv(c)._execute_(aBlock);
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -196,6 +400,30 @@ return self;
 }; }),
 $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.method({
 selector: "deny:",
@@ -236,9 +464,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>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:"));
 }
 return self;
@@ -557,9 +783,9 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self.asyncTimeout;
-if(($receiver = $1) == null || $receiver.a$nil){
+if($1 == null || $1.a$nil){
 $1;
 } else {
 $recv($self.asyncTimeout)._clearTimeout();
@@ -588,24 +814,22 @@ selector: "allTestSelectors",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["testSelectors", "ifTrue:", "shouldInheritSelectors", "addAll:", "allTestSelectors", "superclass"]
+messageSends: ["testSelectors", "ifTrue:", "shouldInheritSelectors", "addAll:", "allTestSelectors", "superclass", "asSet"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 var selectors;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
 selectors=$self._testSelectors();
-$1=$self._shouldInheritSelectors();
-if($core.assert($1)){
+if($core.assert($self._shouldInheritSelectors())){
 $recv(selectors)._addAll_($recv($self._superclass())._allTestSelectors());
 }
-return selectors;
+return $recv(selectors)._asSet();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"allTestSelectors",{selectors:selectors})});
 //>>excludeEnd("ctx");
@@ -677,12 +901,11 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._name();
+return $recv([$self._name()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["name"]=1;
+,$ctx1.sendIdx["name"]=1
 //>>excludeEnd("ctx");
-return $recv($1).__eq($recv($globals.TestCase)._name());
+][0]).__eq($recv($globals.TestCase)._name());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"isAbstract",{})});
 //>>excludeEnd("ctx");
@@ -832,11 +1055,11 @@ var failed;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2;
-$recv($self.testCase)._context_(self);
+[$recv($self.testCase)._context_(self)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["context:"]=1;
+,$ctx1.sendIdx["context:"]=1
 //>>excludeEnd("ctx");
+][0];
 $recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -853,23 +1076,22 @@ return failed;
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 $recv($self.testCase)._context_(nil);
-$1=$recv(failed)._and_((function(){
+if($core.assert($recv(failed)._and_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
-return $recv($self.testCase)._isAsync();
+return [$recv($self.testCase)._isAsync()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx3.sendIdx["isAsync"]=1;
+,$ctx3.sendIdx["isAsync"]=1
 //>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)});
 //>>excludeEnd("ctx");
-}));
-if($core.assert($1)){
+})))){
 $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();
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -963,6 +1185,119 @@ return $recv($1)._yourself();
 $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");
 //>>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`.";
@@ -983,7 +1318,6 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
 $recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -992,14 +1326,15 @@ return $self._withErrorReporting_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
-return (
+return [(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx3.supercall = true,
 //>>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);
-$ctx3.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx3.supercall = false
+//>>excludeEnd("ctx");
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
 //>>excludeEnd("ctx");
@@ -1011,8 +1346,7 @@ $ctx3.supercall = false;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$1=$recv($self.testCase)._isAsync();
-if(!$core.assert($1)){
+if(!$core.assert($recv($self.testCase)._isAsync())){
 $recv($self.result)._increaseRuns();
 return $recv($self.finished)._value();
 }
@@ -1081,7 +1415,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-$recv((function(){
+[$recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -1105,10 +1439,11 @@ return $recv($self.result)._addError_($self.testCase);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,3)});
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["on:do:"]=1;
+,$ctx1.sendIdx["on:do:"]=1
 //>>excludeEnd("ctx");
+][0];
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"withErrorReporting:",{aBlock:aBlock})});
@@ -1134,14 +1469,15 @@ var self=this,$self=this;
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 var $1;
-$1=(
+$1=[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>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);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $recv($1)._result_(aTestResult);
 $recv($1)._finished_(aBlock);
 return $recv($1)._yourself();
@@ -1286,20 +1622,22 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 $self.timestamp=$recv($globals.Date)._now();
 $self.runs=(0);
-$self.errors=$recv($globals.Array)._new();
+$self.errors=[$recv($globals.Array)._new()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["new"]=1;
+,$ctx1.sendIdx["new"]=1
 //>>excludeEnd("ctx");
+][0];
 $self.failures=$recv($globals.Array)._new();
 $self.total=(0);
 return self;
@@ -1325,13 +1663,11 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$1;
-$2=$self._runs();
+if(!$core.assert($recv([$self._runs()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["runs"]=1;
+,$ctx1.sendIdx["runs"]=1
 //>>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)));
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1356,7 +1692,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-$recv((function(){
+[$recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -1389,10 +1725,11 @@ return $self._addError_(aTestCase);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,4)});
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["on:do:"]=1;
+,$ctx1.sendIdx["on:do:"]=1
 //>>excludeEnd("ctx");
+][0];
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"runCase:",{aTestCase:aTestCase})});
@@ -1434,8 +1771,7 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($self._errors())._ifNotEmpty_ifEmpty_((function(){
+return [$recv($self._errors())._ifNotEmpty_ifEmpty_((function(){
 return "error";
 
 }),(function(){
@@ -1452,11 +1788,11 @@ return "success";
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
 //>>excludeEnd("ctx");
-}));
+}))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=1;
+,$ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=1
 //>>excludeEnd("ctx");
-return $1;
+][0];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"status",{})});
 //>>excludeEnd("ctx");
@@ -1589,19 +1925,20 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-(
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._initialize.call($self))
 //>>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);
-$ctx1.sendIdx["new"]=1;
+,$ctx1.sendIdx["new"]=1
 //>>excludeEnd("ctx");
+][0];
 $self.result=$recv($globals.TestResult)._new();
 $self.runNextTest=(function(){
 var runs;
@@ -1609,8 +1946,7 @@ var runs;
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 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();
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1752,16 +2088,15 @@ var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=(
+return $recv([(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self))
 //>>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);
 }, function($ctx1) {$ctx1.fill(self,"on:",{aCollection:aCollection})});
 //>>excludeEnd("ctx");

+ 100 - 1
lang/src/SUnit.st

@@ -17,6 +17,67 @@ 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
 	slots: {#testSelector. #asyncTimeout. #context}
 	package: 'SUnit'!
@@ -91,6 +152,12 @@ signalFailure: aString
 
 !TestCase methodsFor: 'running'!
 
+debugCase
+	"Runs a test case in isolated context, debugging all errors."
+
+	(DebugTestContext testCase: self) start
+!
+
 performTest
 	asyncTimeout := nil.
 	self perform: self selector
@@ -153,7 +220,7 @@ allTestSelectors
 	selectors := self testSelectors.
 	self shouldInheritSelectors ifTrue: [
 		selectors addAll: self superclass allTestSelectors ].
-	^ selectors
+	^ selectors asSet
 !
 
 buildSuite
@@ -244,6 +311,38 @@ testCase: aTestCase
 		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
 	slots: {#finished. #result}
 	package: 'SUnit'!

+ 74 - 81
sdk/lib/NodeTestRunner.js

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

+ 1 - 1
sdk/lib/helpers.js

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

+ 2 - 2
sdk/package.json

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

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است