easycoder 251215.2__tar.gz → 251215.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of easycoder might be problematic. Click here for more details.

Files changed (210) hide show
  1. {easycoder-251215.2 → easycoder-251215.3}/PKG-INFO +1 -1
  2. easycoder-251215.3/SYNTAX_REFACTORING.md +235 -0
  3. {easycoder-251215.2 → easycoder-251215.3}/easycoder/__init__.py +1 -1
  4. {easycoder-251215.2 → easycoder-251215.3}/easycoder/debugger/ec_debug.py +61 -4
  5. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_core.py +12 -1
  6. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_value.py +33 -22
  7. {easycoder-251215.2 → easycoder-251215.3}/test.py +1 -1
  8. {easycoder-251215.2 → easycoder-251215.3}/.github/copilot-instructions.md +0 -0
  9. {easycoder-251215.2 → easycoder-251215.3}/.gitignore +0 -0
  10. {easycoder-251215.2 → easycoder-251215.3}/.vscode/EXTENSION_GUIDE.md +0 -0
  11. {easycoder-251215.2 → easycoder-251215.3}/.vscode/PYTHON_SETUP.md +0 -0
  12. {easycoder-251215.2 → easycoder-251215.3}/.vscode/easycoder/README.md +0 -0
  13. {easycoder-251215.2 → easycoder-251215.3}/.vscode/easycoder/language-configuration.json +0 -0
  14. {easycoder-251215.2 → easycoder-251215.3}/.vscode/easycoder/package.json +0 -0
  15. {easycoder-251215.2 → easycoder-251215.3}/.vscode/easycoder/snippets/easycoder.json +0 -0
  16. {easycoder-251215.2 → easycoder-251215.3}/.vscode/easycoder/syntaxes/easycoder.tmLanguage.json +0 -0
  17. {easycoder-251215.2 → easycoder-251215.3}/.vscode/settings.json +0 -0
  18. {easycoder-251215.2 → easycoder-251215.3}/CONTRIBUTING.md +0 -0
  19. {easycoder-251215.2 → easycoder-251215.3}/LICENSE +0 -0
  20. {easycoder-251215.2 → easycoder-251215.3}/README.md +0 -0
  21. {easycoder-251215.2 → easycoder-251215.3}/backdrop.jpg +0 -0
  22. {easycoder-251215.2 → easycoder-251215.3}/basic.py +0 -0
  23. {easycoder-251215.2 → easycoder-251215.3}/doc/README.md +0 -0
  24. {easycoder-251215.2 → easycoder-251215.3}/doc/core/README.md +0 -0
  25. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/boolean.md +0 -0
  26. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/empty.md +0 -0
  27. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/ends.md +0 -0
  28. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/even.md +0 -0
  29. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/exists.md +0 -0
  30. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/greater.md +0 -0
  31. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/hasProperty.md +0 -0
  32. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/includes.md +0 -0
  33. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/is.md +0 -0
  34. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/less.md +0 -0
  35. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/list.md +0 -0
  36. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/none.md +0 -0
  37. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/not.md +0 -0
  38. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/numeric.md +0 -0
  39. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/object.md +0 -0
  40. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/odd.md +0 -0
  41. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/starts.md +0 -0
  42. {easycoder-251215.2 → easycoder-251215.3}/doc/core/conditions/string.md +0 -0
  43. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/add.md +0 -0
  44. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/append.md +0 -0
  45. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/assert.md +0 -0
  46. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/begin.md +0 -0
  47. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/clear.md +0 -0
  48. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/close.md +0 -0
  49. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/create.md +0 -0
  50. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/debug.md +0 -0
  51. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/decrement.md +0 -0
  52. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/delete.md +0 -0
  53. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/divide.md +0 -0
  54. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/download.md +0 -0
  55. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/exit.md +0 -0
  56. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/file.md +0 -0
  57. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/fork.md +0 -0
  58. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/get.md +0 -0
  59. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/go.md +0 -0
  60. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/gosub.md +0 -0
  61. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/if.md +0 -0
  62. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/import.md +0 -0
  63. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/increment.md +0 -0
  64. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/index.md +0 -0
  65. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/init.md +0 -0
  66. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/input.md +0 -0
  67. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/load.md +0 -0
  68. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/lock.md +0 -0
  69. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/log.md +0 -0
  70. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/module.md +0 -0
  71. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/multiply.md +0 -0
  72. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/negate.md +0 -0
  73. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/on.md +0 -0
  74. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/open.md +0 -0
  75. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/pass.md +0 -0
  76. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/pop.md +0 -0
  77. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/post.md +0 -0
  78. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/print.md +0 -0
  79. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/push.md +0 -0
  80. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/put.md +0 -0
  81. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/read.md +0 -0
  82. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/release.md +0 -0
  83. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/replace.md +0 -0
  84. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/return.md +0 -0
  85. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/run.md +0 -0
  86. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/save.md +0 -0
  87. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/script.md +0 -0
  88. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/send.md +0 -0
  89. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/set.md +0 -0
  90. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/shuffle.md +0 -0
  91. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/split.md +0 -0
  92. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/stack.md +0 -0
  93. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/stop.md +0 -0
  94. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/system.md +0 -0
  95. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/take.md +0 -0
  96. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/toggle.md +0 -0
  97. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/trim.md +0 -0
  98. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/truncate.md +0 -0
  99. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/unlock.md +0 -0
  100. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/use.md +0 -0
  101. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/variable.md +0 -0
  102. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/wait.md +0 -0
  103. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/while.md +0 -0
  104. {easycoder-251215.2 → easycoder-251215.3}/doc/core/keywords/write.md +0 -0
  105. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/arg.md +0 -0
  106. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/args.md +0 -0
  107. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/cos.md +0 -0
  108. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/datime.md +0 -0
  109. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/decode.md +0 -0
  110. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/element.md +0 -0
  111. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/elements.md +0 -0
  112. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/empty.md +0 -0
  113. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/encode.md +0 -0
  114. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/error.md +0 -0
  115. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/files.md +0 -0
  116. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/float.md +0 -0
  117. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/from.md +0 -0
  118. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/hash.md +0 -0
  119. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/index.md +0 -0
  120. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/integer.md +0 -0
  121. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/json.md +0 -0
  122. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/keys.md +0 -0
  123. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/left.md +0 -0
  124. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/length.md +0 -0
  125. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/lowercase.md +0 -0
  126. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/memory.md +0 -0
  127. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/modification.md +0 -0
  128. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/modulo.md +0 -0
  129. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/newline.md +0 -0
  130. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/now.md +0 -0
  131. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/position.md +0 -0
  132. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/property.md +0 -0
  133. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/random.md +0 -0
  134. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/right.md +0 -0
  135. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/sin.md +0 -0
  136. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/stringify.md +0 -0
  137. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/tab.md +0 -0
  138. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/tan.md +0 -0
  139. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/timestamp.md +0 -0
  140. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/today.md +0 -0
  141. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/trim.md +0 -0
  142. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/type.md +0 -0
  143. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/uppercase.md +0 -0
  144. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/value.md +0 -0
  145. {easycoder-251215.2 → easycoder-251215.3}/doc/core/values/weekday.md +0 -0
  146. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/README.md +0 -0
  147. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/add.md +0 -0
  148. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/attach.md +0 -0
  149. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/center.md +0 -0
  150. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/checkbox.md +0 -0
  151. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/clear.md +0 -0
  152. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/close.md +0 -0
  153. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/combobox.md +0 -0
  154. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/create.md +0 -0
  155. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/dialog.md +0 -0
  156. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/disable.md +0 -0
  157. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/enable.md +0 -0
  158. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/group.md +0 -0
  159. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/hide.md +0 -0
  160. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/label.md +0 -0
  161. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/layout.md +0 -0
  162. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/lineinput.md +0 -0
  163. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/listbox.md +0 -0
  164. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/messagebox.md +0 -0
  165. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/move.md +0 -0
  166. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/multiline.md +0 -0
  167. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/on.md +0 -0
  168. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/pushbutton.md +0 -0
  169. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/remove.md +0 -0
  170. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/select.md +0 -0
  171. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/set.md +0 -0
  172. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/keywords/window.md +0 -0
  173. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/values/attribute.md +0 -0
  174. {easycoder-251215.2 → easycoder-251215.3}/doc/graphics/values/window.md +0 -0
  175. {easycoder-251215.2 → easycoder-251215.3}/easycoder/debugger/__init__.py +0 -0
  176. {easycoder-251215.2 → easycoder-251215.3}/easycoder/debugger/ec_dbg_value_display copy.py +0 -0
  177. {easycoder-251215.2 → easycoder-251215.3}/easycoder/debugger/ec_dbg_value_display.py +0 -0
  178. {easycoder-251215.2 → easycoder-251215.3}/easycoder/debugger/ec_dbg_watch_list copy.py +0 -0
  179. {easycoder-251215.2 → easycoder-251215.3}/easycoder/debugger/ec_dbg_watchlist.py +0 -0
  180. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_border.py +0 -0
  181. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_classes.py +0 -0
  182. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_compiler.py +0 -0
  183. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_condition.py +0 -0
  184. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_gclasses.py +0 -0
  185. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_graphics.py +0 -0
  186. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_handler.py +0 -0
  187. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_keyboard.py +0 -0
  188. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_program.py +0 -0
  189. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_psutil.py +0 -0
  190. {easycoder-251215.2 → easycoder-251215.3}/easycoder/ec_timestamp.py +0 -0
  191. {easycoder-251215.2 → easycoder-251215.3}/easycoder/icons/close.png +0 -0
  192. {easycoder-251215.2 → easycoder-251215.3}/easycoder/icons/exit.png +0 -0
  193. {easycoder-251215.2 → easycoder-251215.3}/easycoder/icons/run.png +0 -0
  194. {easycoder-251215.2 → easycoder-251215.3}/easycoder/icons/step.png +0 -0
  195. {easycoder-251215.2 → easycoder-251215.3}/easycoder/icons/stop.png +0 -0
  196. {easycoder-251215.2 → easycoder-251215.3}/easycoder/icons/tick.png +0 -0
  197. {easycoder-251215.2 → easycoder-251215.3}/images/Semoigo Dawn.jpg +0 -0
  198. {easycoder-251215.2 → easycoder-251215.3}/json/graphics-demo.json +0 -0
  199. {easycoder-251215.2 → easycoder-251215.3}/plugins/ec_p100.py +0 -0
  200. {easycoder-251215.2 → easycoder-251215.3}/plugins/points.py +0 -0
  201. {easycoder-251215.2 → easycoder-251215.3}/plugins/sql.py +0 -0
  202. {easycoder-251215.2 → easycoder-251215.3}/pyproject.toml +0 -0
  203. {easycoder-251215.2 → easycoder-251215.3}/testdbg.py +0 -0
  204. {easycoder-251215.2 → easycoder-251215.3}/testg.py +0 -0
  205. {easycoder-251215.2 → easycoder-251215.3}/testrbr.py +0 -0
  206. {easycoder-251215.2 → easycoder-251215.3}/testrc.py +0 -0
  207. {easycoder-251215.2 → easycoder-251215.3}/tests/ec_keyboard.py +0 -0
  208. {easycoder-251215.2 → easycoder-251215.3}/tests/update_vscode_extension.py +0 -0
  209. {easycoder-251215.2 → easycoder-251215.3}/testsql.py +0 -0
  210. {easycoder-251215.2 → easycoder-251215.3}/testui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easycoder
3
- Version: 251215.2
3
+ Version: 251215.3
4
4
  Summary: Rapid scripting in English
5
5
  Keywords: compiler,scripting,prototyping,programming,coding,python,low code,hypertalk,computer language,learn to code
6
6
  Author-email: Graham Trott <gtanyware@gmail.com>
@@ -0,0 +1,235 @@
1
+ # EasyCoder Syntax Refactoring & Standardization Plan
2
+
3
+ ## Goals
4
+ 1. **Consistency**: Establish canonical patterns for all keywords (verbs, prepositions, optional tokens).
5
+ 2. **Readability**: Improve English-like flow while maintaining unambiguity for parsing.
6
+ 3. **Plugin-safety**: Ensure core handlers gracefully yield to plugins; syntactic "noise" (articles, prepositions) serves as **disambiguation anchors** to avoid collisions.
7
+ 4. **Extensibility**: Define clear patterns so new keywords/aliases follow consistent rules without risking collision or ambiguity.
8
+ 5. **LSP-ready**: Minimize syntax variations to simplify future language server implementation.
9
+
10
+ ---
11
+
12
+ ## Critical Constraint: Plugin Safety & Syntactic Disambiguation
13
+
14
+ EasyCoder's strength is its extensibility via plugins. The core module must:
15
+ 1. **Recognize graceful fallback**: If a keyword isn't in core, don't error—let plugins try.
16
+ 2. **Use syntactic anchors**: Articles ("the", "a") and prepositions ("into", "to", "of") act as **delimiters** that signal intent and reduce false positives.
17
+ 3. **Avoid ambiguous forms**: Bare word sequences (e.g., `cat A B`) risk collision with plugin keywords or future core additions.
18
+ 4. **Reserve barebones patterns for plugin use**: A plugin might claim `cat` as a standalone verb; forcing core to use `the cat of A and B` leaves room.
19
+
20
+ ### Example: Why Syntactic Noise Matters
21
+ - **Without noise**: `cat A B` could be confused with a plugin command `cat {file} {destination}` (imagine a file ops plugin).
22
+ - **With noise**: `the cat of A and B` is unambiguous—only a core/plugin string concatenation, never a file operation.
23
+ - **Human language parallel**: English uses "of", "the", "to" to disambiguate homonyms ("fly paper" vs. "the fly of paper" have different meanings).
24
+
25
+ ### Implication for Proposed Enhancements
26
+ - **`set X to Y`**: Safe (full form with preposition; unlikely plugin conflict).
27
+ - **`the cat of A and B`**: Safer than `cat A B` (article + preposition reduces collision risk).
28
+ - **Optional `to` in `fork to Label`**: Safe (fork is reserved; "to" is optional precisely because fork can't collide).
29
+ - **Bare `cat A B`**: Risky (a plugin might claim `cat` as a verb; disambiguate with `the cat of A and B` in core).
30
+
31
+ ---
32
+
33
+ ## Current Syntax Patterns (Observations)
34
+
35
+ ### Variable Declaration & Assignment
36
+ **Current forms:**
37
+ - `put {value} into {variable}` (core)
38
+ - `set {variable} to {value}` (proposed enhancement)
39
+
40
+ **Pattern**: `{verb} {object} {preposition} {target}`
41
+ - Verbs: `put`, `set` (and aliases like `assign`, `store`)
42
+ - Prepositions: `into`, `to`
43
+ - Should support both naturally without doubling parser complexity.
44
+
45
+ ### Arithmetic Operations
46
+ **Current forms:**
47
+ - `add {value} to {variable}`
48
+ - `add {value1} to {value2} giving {variable}` (in-place vs. result)
49
+
50
+ **Pattern**: `{verb} {value} {preposition} {target} [giving {variable}]`
51
+ - Optional `giving` clause changes semantics (in-place vs. result).
52
+ - Supports multiple value forms (literals, variables, expressions).
53
+
54
+ ### String Concatenation
55
+ **Current forms:**
56
+ - `{variable} cat {value}` (infix concatenation operator)
57
+
58
+ **Proposed enhancement (plugin-safe):**
59
+ - Core should use: `the cat of {value1} and {value2}` (functional style with articles/prepositions)
60
+ - Infix `A cat B` is syntactic sugar—risky if plugins claim `cat` as a standalone verb.
61
+
62
+ **Pattern**:
63
+ - **Core canonical**: `the cat of A and B` (disambiguated with article + preposition).
64
+ - **Infix sugar**: Can be allowed as syntactic convenience *only if parser clearly marks it as restricted to core*.
65
+ - **Plugin designers**: Should avoid `cat` as a standalone keyword; if needed, use a qualified form (e.g., `file cat`, `binary cat`).
66
+
67
+ ### Control Flow (Optional Prepositions)
68
+ **Current forms:**
69
+ - `fork to {label}`
70
+ - `go to {label}`
71
+ - `gosub to {label}` (optional "to")
72
+
73
+ **Pattern**: `{verb} [to] {target}`
74
+ - Many keywords should accept optional "to" without requiring it.
75
+ - Parser should use `skip('to')` liberally.
76
+
77
+ ### Array/List Operations
78
+ **Current forms:**
79
+ - `append {value} to {array}`
80
+ - Element access: `element {N} of {array}` or `{array}[{N}]`
81
+
82
+ **Pattern**: Preposition consistency (e.g., all use "to" for targets, all use "of" for containment).
83
+
84
+ ---
85
+
86
+ ## Proposed Refactoring (Phase 1)
87
+
88
+ ### 1. Assignment/Setting Verbs (Plugin-Safe)
89
+ **Canonical:** Both `put … into …` and `set … to …` should compile to the same operation.
90
+ - **Why safe**: Both use full prepositions ("into", "to"), reducing plugin collision risk.
91
+ - **Handler change**: In `k_set` (new), parse both forms and normalize to internal representation.
92
+ - **Documentation**: Update docs to show both as equivalent.
93
+ - **Example**:
94
+ ```
95
+ put 0 into Counter ! existing core form
96
+ set Counter to 0 ! new equivalent form
97
+ ```
98
+
99
+ ### 2. String Concatenation (Plugin-Safe Enhancement)
100
+ **Canonical for core**: Use `the cat of A and B` (full form with article + preposition).
101
+ - **Why safer**: The article ("the") + preposition ("of") + conjunction ("and") create a syntactic "fence" that prevents collision with plugin `cat` verbs.
102
+ - **Existing infix `A cat B`**: May be retained as documented sugar *within core only*, with clear warnings in plugin docs.
103
+ - **Handler change**: Extend value parsing to recognize both forms; prefer full form in examples and documentation.
104
+ - **Documentation**: Show full form as canonical, infix as optional shorthand with plugin-collision caveats.
105
+ - **Example**:
106
+ ```
107
+ ! Canonical (plugin-safe):
108
+ set Message to the cat of Prefix and Suffix
109
+
110
+ ! Shorthand (use with caution if plugins define 'cat'):
111
+ set Message to Prefix cat Suffix
112
+ ```
113
+
114
+ ### 3. Optional "to" in Core-Reserved Keywords (Plugin-Safe)
115
+ **Canonical**: Keywords like `fork`, `go`, `gosub`—which are core-reserved—accept optional "to".
116
+ - **Why safe**: These keywords are reserved in core, so no plugin can claim them; optional "to" adds convenience without ambiguity.
117
+ - **Handler pattern**: Use `skip('to')` before parsing the target.
118
+ - **Apply to**: `fork`, `go`, `gosub`, `goto`, and similar core-only verbs.
119
+ - **Example**:
120
+ ```
121
+ fork RunTask ! without "to"
122
+ fork to RunTask ! with "to" (both compile identically)
123
+ ```
124
+
125
+ ### 4. Articles in Value Expressions (Selective, Plugin-Safe)
126
+ **Canonical**: Use articles and prepositions in value operations to disambiguate.
127
+ - **Full forms (preferred)**: `the cat of A and B`, `the element 0 of Array`, `the property Name of Object`.
128
+ - **Shortened forms (use only if unambiguous)**: Avoid bare patterns (e.g., `element 0 Array`) unless clearly reserved.
129
+ - **Parser helper**: Add a `skipArticles()` method for optional "the", "a" in safe contexts.
130
+ - **Use sparingly**: Only where grammar and plugin isolation permit.
131
+ - **Example**:
132
+ ```
133
+ ! Preferred (plugin-safe):
134
+ the element 0 of Array
135
+ the index of X in Array
136
+ the property Name of Object
137
+ ```
138
+
139
+ ### 5. Method/Function Names & Built-in Operations (Plugin-Aware Registry)
140
+ **Goal**: Inventory all operations that act on values during compilation, with plugin-collision awareness.
141
+ - **Current examples**: `cat`, `element N of`, `index of`, `property of`, `length of`.
142
+ - **Action**: Maintain a registry (e.g., `doc/core/values/operations.md`) with:
143
+ - **Reserved stems**: Words/phrases claimed by core (e.g., `cat`, `element`, `property`).
144
+ - **Safe forms**: Full forms with articles/prepositions (e.g., `the cat of`, `the element 0 of`).
145
+ - **Plugin notes**: Which forms are off-limits to avoid collision.
146
+ - **Pattern**: All value operations should use article + preposition patterns (e.g., `the X of Y and Z`) to maximize plugin room.
147
+
148
+ ---
149
+
150
+ ## Implementation Strategy (Plugin-Safe Approach)
151
+
152
+ ### Phase 1: Core Syntax Consolidation (Immediate, Plugin-Safe)
153
+ 1. **Add `set … to …` support** in `ec_core.py` (mirror existing `put … into …` logic).
154
+ 2. **Document dual syntax** in keyword docs (both forms equivalent and plugin-safe).
155
+ 3. **Enhance string concatenation**: Support `the cat of A and B` as canonical form; document `A cat B` as shorthand with plugin-collision warnings.
156
+ 4. **Add `skipArticles()` helper** to compiler for optional "the", "a" in disambiguated contexts.
157
+ 5. **Update core-reserved keywords** (`fork`, `go`, `gosub`) to use `skip('to')` for optional "to".
158
+ 6. **Document plugin implications**: Add section to plugin dev guide warning about reserved stems.
159
+ 7. **Test with existing scripts**: Ensure no regressions; validate new forms compile correctly.
160
+
161
+ ### Phase 2: Plugin-Aware Registry (Next)
162
+ 1. **Create `doc/core/values/operations.md`**: Inventory value-time operations with plugin notes.
163
+ - `the cat of A and B` (concatenation) — reserved in core; plugins should avoid `cat` as verb.
164
+ - `the element N of {array}` (indexing) — reserved; plugins should use qualified forms.
165
+ - `the index of X in {array}` (search) — reserved.
166
+ - `the property Name of {object}` (object access) — reserved.
167
+ - `the length of {value}` (length) — reserved.
168
+ 2. **Define reserved stems**: List keywords/stems core claims (e.g., `put`, `set`, `fork`, `cat`, `element`).
169
+ 3. **Plugin guidelines**: Recommend plugins use qualified forms (e.g., `file cat` instead of bare `cat`).
170
+
171
+ ### Phase 3: Extension Pattern Documentation (Follow-up)
172
+ 1. **Create `PLUGIN_PATTERNS.md`**: Extension-safe patterns for plugin developers.
173
+ - **Avoid bare verbs** unless they can't conflict with core.
174
+ - **Prefer qualified forms** (e.g., `{plugin} {verb}` or `{verb} via {plugin}`).
175
+ - **Use articles/prepositions** to disambiguate (e.g., `the X of Y` vs. `X Y`).
176
+ 2. **Reserved stems list**: Core publishes which words are off-limits.
177
+ 3. **Example walkthrough**: Show how to add a plugin keyword safely (avoids collision with existing/future core).
178
+ 4. **Linting rules**: Define what makes a plugin keyword "safe" (no conflict with reserved stems; clear syntax boundary).
179
+
180
+ ### Phase 4: LSP Validation (Post-Refactoring)
181
+ 1. **LSP server reads registries**: Consults reserved-stems and core operations lists.
182
+ 2. **Completion hints**: Only suggest keywords that don't collide with loaded plugins.
183
+ 3. **Diagnostics**: Warn if a plugin keyword conflicts with reserved stems; suggest alternatives.
184
+
185
+ ---
186
+
187
+ ## Key Compiler Methods to Leverage
188
+
189
+ From `ec_compiler.py` and `ec_handler.py`:
190
+ - **`skip(token)`**: Consume optional token without failing (use liberally for optional "to", "the", etc.).
191
+ - **`nextToken()`, `peek()`**: Standard lookahead.
192
+ - **`nextValue()`**: Parse complex value expressions recursively (extend to recognize full forms like `the cat of`).
193
+ - **`getSymbolRecord()`**: Retrieve variable/label metadata.
194
+ - **`nextIs(value)`, `tokenIs(value)`**: Conditional parsing.
195
+
196
+ **New helper to add**:
197
+ - **`skipArticles()`**: Consume "the", "a", "an" if present; return success regardless (optional articles).
198
+ - **`skipPrepositions(words)`**: Consume optional prepositions from a list (e.g., `skip(['to', 'into'])` for assignment).
199
+
200
+ ---
201
+
202
+ ## Design Principles Summary
203
+
204
+ 1. **Use articles + prepositions as syntactic anchors**: Reduces plugin-collision risk.
205
+ 2. **Reserve only what's necessary**: Don't claim bare verbs unless core truly owns them.
206
+ 3. **Document reserved stems**: Plugins know what to avoid.
207
+ 4. **Prefer full forms in canonical examples**: Encourages plugin-safe code.
208
+ 5. **Allow shortcuts for core-reserved keywords**: Since core owns them, optional tokens are safe.
209
+ 6. **Fail gracefully**: If core doesn't recognize a keyword, pass it to plugins without error.
210
+
211
+ ---
212
+
213
+ ## Expected Outcomes
214
+
215
+ After Phase 1–2:
216
+ - ✅ New keywords follow plugin-safe patterns (verbs with prepositions, articles as disambiguators).
217
+ - ✅ Core reserves stems and documents them; plugins know what to avoid.
218
+ - ✅ Synonymous forms (e.g., `put`/`set`, full `the cat of` / shorthand `A cat B`) are transparent and documented.
219
+ - ✅ Parser code is consistent, defensive, and extensible.
220
+ - ✅ Documentation clearly shows all supported syntax forms and plugin implications.
221
+ - ✅ LSP server can use pattern + registry to provide collision-aware completion and diagnostics.
222
+ - ✅ Plugin developers have clear guidance on safe naming and syntax patterns.
223
+
224
+ ---
225
+
226
+ ## Next Steps
227
+
228
+ 1. **Review plugin-safety constraints**: Do these principles align with your plugin architecture?
229
+ 2. **Prioritize Phase 1**: Start with `set`/`put`, full `the cat of` form, optional `to` for core-reserved keywords.
230
+ 3. **Draft reserved-stems list**: Document what core claims (e.g., `cat`, `element`, `index`, `property`, `length`).
231
+ 4. **Implement & test**: I can code Phase 1 changes and validate with existing scripts + new test cases.
232
+ 5. **Refine iteratively**: Gather plugin feedback and adjust reserved stems as needed.
233
+
234
+
235
+
@@ -14,4 +14,4 @@ from .ec_psutil import *
14
14
  from .ec_timestamp import *
15
15
  from .ec_value import *
16
16
 
17
- __version__ = "251215.2"
17
+ __version__ = "251215.3"
@@ -418,6 +418,8 @@ class Debugger(QMainWindow):
418
418
  self.setWindowFlags(self.windowFlags() & ~Qt.WindowType.WindowCloseButtonHint)
419
419
  self.stopped = True
420
420
  self.skip_next_breakpoint = False # Flag to skip breakpoint check on resume
421
+ self.saved_queue = [] # Save queue state when stopped to preserve forked threads
422
+ self._highlighted: set[int] = set()
421
423
 
422
424
  # try to load saved geometry from ~/.ecdebug.conf
423
425
  cfg_path = os.path.join(os.path.expanduser("~"), ".ecdebug.conf")
@@ -794,7 +796,7 @@ class Debugger(QMainWindow):
794
796
  ###########################################################################
795
797
  # Set the background color of one line of the script
796
798
  def setBackground(self, lino, color):
797
- # Set the background color of the given line
799
+ # Set the background color of the given line and track highlighted lines
798
800
  if lino < 0 or lino >= len(self.scriptLines):
799
801
  return
800
802
  lineSpec = self.scriptLines[lino]
@@ -803,8 +805,16 @@ class Debugger(QMainWindow):
803
805
  return
804
806
  if color == 'none':
805
807
  panel.setStyleSheet("")
808
+ self._highlighted.discard(lino)
806
809
  else:
807
810
  panel.setStyleSheet(f"background-color: {color};")
811
+ self._highlighted.add(lino)
812
+
813
+ def _clearHighlights(self):
814
+ # Remove highlighting from all previously highlighted lines
815
+ for lino in list(self._highlighted):
816
+ self.setBackground(lino, 'none')
817
+ self._highlighted.clear()
808
818
 
809
819
  ###########################################################################
810
820
  # Here before each instruction is run
@@ -842,12 +852,15 @@ class Debugger(QMainWindow):
842
852
  self.stopped = True
843
853
  should_halt = True
844
854
 
845
- # If halting, update the UI
855
+ # If halting, update the UI and save queue state
846
856
  if should_halt:
847
857
  self.scrollTo(lino)
858
+ self._clearHighlights()
848
859
  self.setBackground(lino, 'LightYellow')
849
860
  # Refresh variable values when halted
850
861
  self.refreshVariables()
862
+ # Save the current queue state to preserve forked threads
863
+ self._saveQueueState()
851
864
 
852
865
  return should_halt
853
866
 
@@ -859,6 +872,28 @@ class Debugger(QMainWindow):
859
872
  except Exception as ex:
860
873
  print(f"Error refreshing variables: {ex}")
861
874
 
875
+ def _saveQueueState(self):
876
+ """Save the current global queue state (preserves forked threads)"""
877
+ try:
878
+ # Import the module to access the global queue
879
+ from easycoder import ec_program
880
+ # Save a copy of the queue
881
+ self.saved_queue = list(ec_program.queue)
882
+ except Exception as ex:
883
+ print(f"Error saving queue state: {ex}")
884
+
885
+ def _restoreQueueState(self):
886
+ """Restore the saved queue state (resume all forked threads)"""
887
+ try:
888
+ # Import here to avoid circular dependency
889
+ from easycoder import ec_program
890
+ # Restore the queue from saved state
891
+ if self.saved_queue:
892
+ ec_program.queue.clear()
893
+ ec_program.queue.extend(self.saved_queue)
894
+ except Exception as ex:
895
+ print(f"Error restoring queue state: {ex}")
896
+
862
897
  def doRun(self):
863
898
  """Resume free-running execution from current PC"""
864
899
  command = self.program.code[self.pc]
@@ -874,8 +909,13 @@ class Debugger(QMainWindow):
874
909
  # Skip the breakpoint check for the current instruction (the one we're resuming from)
875
910
  self.skip_next_breakpoint = True
876
911
 
877
- # Resume execution at current PC
912
+ # Restore the saved queue state to resume all forked threads
913
+ self._restoreQueueState()
914
+
915
+ # Enqueue the current thread, then flush immediately
878
916
  self.program.run(self.pc)
917
+ from easycoder.ec_program import flush
918
+ flush()
879
919
 
880
920
  def doStep(self):
881
921
  """Execute one instruction and halt again"""
@@ -891,10 +931,27 @@ class Debugger(QMainWindow):
891
931
  # Skip the breakpoint check for the current instruction (the one we're stepping from)
892
932
  self.skip_next_breakpoint = True
893
933
 
894
- # Execute the current instruction
934
+ # Restore the saved queue state to resume all forked threads
935
+ self._restoreQueueState()
936
+
937
+ # Enqueue the current thread, then flush a single cycle
895
938
  self.program.run(self.pc)
939
+ from easycoder.ec_program import flush
940
+ flush()
896
941
 
897
942
  def doStop(self):
943
+ try:
944
+ lino = self.program.code[self.pc].get('lino', 0) + 1
945
+ print(f"Stopped by user at line {lino}")
946
+ except Exception:
947
+ print("Stopped by user")
948
+ # Clear all previous highlights and mark the current line
949
+ try:
950
+ self._clearHighlights()
951
+ current_lino = self.program.code[self.pc].get('lino', 0)
952
+ self.setBackground(current_lino, 'LightYellow')
953
+ except Exception:
954
+ pass
898
955
  self.stopped = True
899
956
 
900
957
  def doClose(self):
@@ -1310,6 +1310,7 @@ class Core(Handler):
1310
1310
 
1311
1311
  # Set a value
1312
1312
  # set {variable}
1313
+ # set {variable} to {value}
1313
1314
  # set {ssh} host {host} user {user} password {password}
1314
1315
  # set the elements of {variable} to {value}
1315
1316
  # set element/property of {variable} to {value}
@@ -1341,7 +1342,11 @@ class Core(Handler):
1341
1342
  self.add(command)
1342
1343
  return True
1343
1344
  elif isinstance(self.getObject(record), ECVariable):
1344
- command['type'] = 'set'
1345
+ if self.peek() == 'to':
1346
+ command['type'] = 'setValue'
1347
+ self.nextToken()
1348
+ command['value'] = self.nextValue()
1349
+ else: command['type'] = 'set'
1345
1350
  self.add(command)
1346
1351
  return True
1347
1352
  return False
@@ -1410,6 +1415,12 @@ class Core(Handler):
1410
1415
  target = self.getVariable(command['target'])
1411
1416
  self.putSymbolValue(target, ECValue(domain=self.getName(), type='boolean', content=True))
1412
1417
  return self.nextPC()
1418
+
1419
+ elif cmdType == 'setValue':
1420
+ value = self.evaluate(command['value'])
1421
+ target = self.getVariable(command['target'])
1422
+ self.putSymbolValue(target, value)
1423
+ return self.nextPC()
1413
1424
 
1414
1425
  elif cmdType == 'elements':
1415
1426
  record = self.getVariable(command['name'])
@@ -11,6 +11,7 @@ class Value:
11
11
  self.getToken = compiler.getToken
12
12
  self.nextToken = compiler.nextToken
13
13
  self.peek = compiler.peek
14
+ self.skip = compiler.skip
14
15
  self.tokenIs = compiler.tokenIs
15
16
 
16
17
  def getItem(self):
@@ -53,34 +54,44 @@ class Value:
53
54
  # self.compiler.warning(f'I don\'t understand \'{token}\'')
54
55
  return None
55
56
 
56
- # Compile a value
57
- def compileValue(self):
58
- token = self.getToken()
59
- item = self.getItem()
60
- if item == None:
61
- self.compiler.warning(f'ec_value.compileValue: Cannot get the value of "{token}"')
62
- return None
63
- if item.getType() == 'symbol':
64
- object = self.compiler.getSymbolRecord(item.getContent())['object']
65
- if not object.hasRuntimeValue(): return None
66
-
57
+ # Get something starting following 'the'
58
+ def getTheSomething(self):
59
+ self.nextToken() # consume 'the'
67
60
  value = ECValue()
68
- if self.peek() == 'cat':
69
- items = None
70
- if value.getType() == 'cat': items = value.getContent()
71
- else:
72
- value.setType('cat')
73
- items = [item]
74
- value.setContent(items)
75
- while self.peek() == 'cat':
76
- v = self.nextToken()
77
- v= self.nextToken()
61
+ if self.getToken() == 'cat':
62
+ self.nextToken() # consume 'cat'
63
+ self.skip('of')
64
+ self.nextToken()
65
+ item = self.getItem()
66
+ value.setType('cat')
67
+ items = [item]
68
+ while self.peek() in ['cat', 'and']:
69
+ self.nextToken()
70
+ self.nextToken()
78
71
  element = self.getItem()
79
72
  if element != None:
80
73
  items.append(element) # pyright: ignore[reportOptionalMemberAccess]
81
74
  value.setContent(items)
75
+ return value
76
+
77
+ # Compile a value
78
+ def compileValue(self):
79
+ token = self.getToken()
80
+ if token == 'the': value = self.getTheSomething()
82
81
  else:
83
- value = item
82
+ item = self.getItem()
83
+ if item == None:
84
+ self.compiler.warning(f'ec_value.compileValue: Cannot get the value of "{token}"')
85
+ return None
86
+ if item.getType() == 'symbol':
87
+ object = self.compiler.getSymbolRecord(item.getContent())['object']
88
+ if not object.hasRuntimeValue(): return None
89
+
90
+ value = ECValue()
91
+ if self.peek() == 'cat':
92
+ value = self.getTheSomething()
93
+ else:
94
+ value = item
84
95
 
85
96
  # See if any domain has something to add to the value
86
97
  for domain in self.compiler.program.getDomains():
@@ -4,4 +4,4 @@ import os
4
4
  from easycoder import Program
5
5
 
6
6
  os.chdir('/home/graham/dev/easycoder/easycoder-py/tests')
7
- Program('debug tests-dbg.ecs').start()
7
+ Program('debug test.ecs').start()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes