easycoder 241218.1__tar.gz → 241231.1__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 (81) hide show
  1. {easycoder-241218.1 → easycoder-241231.1}/PKG-INFO +11 -3
  2. {easycoder-241218.1 → easycoder-241231.1}/README.md +10 -2
  3. easycoder-241231.1/easycoder/README.md +6 -0
  4. {easycoder-241218.1 → easycoder-241231.1}/easycoder/__init__.py +2 -2
  5. easycoder-241231.1/easycoder/ec.py +10 -0
  6. {easycoder-241218.1 → easycoder-241231.1}/easycoder/ec_classes.py +3 -0
  7. {easycoder-241218.1 → easycoder-241231.1}/easycoder/ec_compiler.py +7 -6
  8. {easycoder-241218.1 → easycoder-241231.1}/easycoder/ec_core.py +29 -4
  9. easycoder-241231.1/easycoder/ec_graphics.py +429 -0
  10. {easycoder-241218.1 → easycoder-241231.1}/easycoder/ec_handler.py +1 -0
  11. {easycoder-241218.1 → easycoder-241231.1}/easycoder/ec_program.py +72 -58
  12. easycoder-241231.1/easycoder/ec_renderer.py +245 -0
  13. easycoder-241231.1/easycoder/ec_screenspec.py +77 -0
  14. {easycoder-241218.1 → easycoder-241231.1}/easycoder/ec_value.py +10 -10
  15. easycoder-241231.1/json/graphics-demo.json +74 -0
  16. easycoder-241231.1/scripts/README.md +16 -0
  17. easycoder-241231.1/scripts/graphics-demo.ecg +102 -0
  18. easycoder-241231.1/scripts/wave.ecg +118 -0
  19. easycoder-241218.1/easycoder/ec_graphics.py +0 -376
  20. easycoder-241218.1/easycoder/ec_renderer.py +0 -335
  21. easycoder-241218.1/json/graphics-demo.json +0 -60
  22. easycoder-241218.1/scripts/graphics-demo.ecs +0 -71
  23. {easycoder-241218.1 → easycoder-241231.1}/LICENSE +0 -0
  24. {easycoder-241218.1 → easycoder-241231.1}/doc/README.md +0 -0
  25. {easycoder-241218.1 → easycoder-241231.1}/doc/core/add.md +0 -0
  26. {easycoder-241218.1 → easycoder-241231.1}/doc/core/append.md +0 -0
  27. {easycoder-241218.1 → easycoder-241231.1}/doc/core/assert.md +0 -0
  28. {easycoder-241218.1 → easycoder-241231.1}/doc/core/begin.md +0 -0
  29. {easycoder-241218.1 → easycoder-241231.1}/doc/core/clear.md +0 -0
  30. {easycoder-241218.1 → easycoder-241231.1}/doc/core/close.md +0 -0
  31. {easycoder-241218.1 → easycoder-241231.1}/doc/core/create.md +0 -0
  32. {easycoder-241218.1 → easycoder-241231.1}/doc/core/debug.md +0 -0
  33. {easycoder-241218.1 → easycoder-241231.1}/doc/core/decrement.md +0 -0
  34. {easycoder-241218.1 → easycoder-241231.1}/doc/core/delete.md +0 -0
  35. {easycoder-241218.1 → easycoder-241231.1}/doc/core/divide.md +0 -0
  36. {easycoder-241218.1 → easycoder-241231.1}/doc/core/exit.md +0 -0
  37. {easycoder-241218.1 → easycoder-241231.1}/doc/core/file.md +0 -0
  38. {easycoder-241218.1 → easycoder-241231.1}/doc/core/fork.md +0 -0
  39. {easycoder-241218.1 → easycoder-241231.1}/doc/core/get.md +0 -0
  40. {easycoder-241218.1 → easycoder-241231.1}/doc/core/go.md +0 -0
  41. {easycoder-241218.1 → easycoder-241231.1}/doc/core/gosub.md +0 -0
  42. {easycoder-241218.1 → easycoder-241231.1}/doc/core/if.md +0 -0
  43. {easycoder-241218.1 → easycoder-241231.1}/doc/core/import.md +0 -0
  44. {easycoder-241218.1 → easycoder-241231.1}/doc/core/increment.md +0 -0
  45. {easycoder-241218.1 → easycoder-241231.1}/doc/core/index.md +0 -0
  46. {easycoder-241218.1 → easycoder-241231.1}/doc/core/init.md +0 -0
  47. {easycoder-241218.1 → easycoder-241231.1}/doc/core/input.md +0 -0
  48. {easycoder-241218.1 → easycoder-241231.1}/doc/core/multiply.md +0 -0
  49. {easycoder-241218.1 → easycoder-241231.1}/doc/core/open.md +0 -0
  50. {easycoder-241218.1 → easycoder-241231.1}/doc/core/pop.md +0 -0
  51. {easycoder-241218.1 → easycoder-241231.1}/doc/core/post.md +0 -0
  52. {easycoder-241218.1 → easycoder-241231.1}/doc/core/print.md +0 -0
  53. {easycoder-241218.1 → easycoder-241231.1}/doc/core/push.md +0 -0
  54. {easycoder-241218.1 → easycoder-241231.1}/doc/core/put.md +0 -0
  55. {easycoder-241218.1 → easycoder-241231.1}/doc/core/read.md +0 -0
  56. {easycoder-241218.1 → easycoder-241231.1}/doc/core/replace.md +0 -0
  57. {easycoder-241218.1 → easycoder-241231.1}/doc/core/return.md +0 -0
  58. {easycoder-241218.1 → easycoder-241231.1}/doc/core/script.md +0 -0
  59. {easycoder-241218.1 → easycoder-241231.1}/doc/core/set.md +0 -0
  60. {easycoder-241218.1 → easycoder-241231.1}/doc/core/split.md +0 -0
  61. {easycoder-241218.1 → easycoder-241231.1}/doc/core/stack.md +0 -0
  62. {easycoder-241218.1 → easycoder-241231.1}/doc/core/stop.md +0 -0
  63. {easycoder-241218.1 → easycoder-241231.1}/doc/core/system.md +0 -0
  64. {easycoder-241218.1 → easycoder-241231.1}/doc/core/take.md +0 -0
  65. {easycoder-241218.1 → easycoder-241231.1}/doc/core/toggle.md +0 -0
  66. {easycoder-241218.1 → easycoder-241231.1}/doc/core/truncate.md +0 -0
  67. {easycoder-241218.1 → easycoder-241231.1}/doc/core/variable.md +0 -0
  68. {easycoder-241218.1 → easycoder-241231.1}/doc/core/wait.md +0 -0
  69. {easycoder-241218.1 → easycoder-241231.1}/doc/core/while.md +0 -0
  70. {easycoder-241218.1 → easycoder-241231.1}/doc/core/write.md +0 -0
  71. {easycoder-241218.1 → easycoder-241231.1}/easycoder/ec_condition.py +0 -0
  72. {easycoder-241218.1 → easycoder-241231.1}/easycoder/ec_timestamp.py +0 -0
  73. {easycoder-241218.1 → easycoder-241231.1}/images/Semoigo Dawn.jpg +0 -0
  74. {easycoder-241218.1 → easycoder-241231.1}/plugins/ec_p100.py +0 -0
  75. {easycoder-241218.1 → easycoder-241231.1}/plugins/example.py +0 -0
  76. {easycoder-241218.1 → easycoder-241231.1}/pyproject.toml +0 -0
  77. {easycoder-241218.1 → easycoder-241231.1}/scripts/benchmark.ecs +0 -0
  78. {easycoder-241218.1 → easycoder-241231.1}/scripts/fizzbuzz.ecs +0 -0
  79. {easycoder-241218.1 → easycoder-241231.1}/scripts/hello.ecs +0 -0
  80. {easycoder-241218.1 → easycoder-241231.1}/scripts/points.ecs +0 -0
  81. {easycoder-241218.1 → easycoder-241231.1}/scripts/tests.ecs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: easycoder
3
- Version: 241218.1
3
+ Version: 241231.1
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>
@@ -60,9 +60,17 @@ Here in the repository is a folder called `scripts` containing some sample scrip
60
60
  `fizzbuzz.ecs` is a simple programming challenge often given at job interviews
61
61
 
62
62
  ## Graphical programmming
63
- **_EasyCoder_** is currently being extended to include a graphical programming environment. A single demo script `graphics-demo.ecs` is included in the `scripts` directory. To run it, first install the Python graphics library if it's not already present on your system. On Linux this is done with `sudo apt install python3-tk`. On Windows it's `pip install tk`. Then give the command `easycoder -g scripts/graphics-demo.ecs`.
63
+ **_EasyCoder_** includes a graphical programming environment that is in the early stages of development. A couple of demo scripts are included in the `scripts` directory. To run them, first install the Python `kivy` graphics library if it's not already present on your system. This is done with `pip install kivy`. Then run a script using `easycoder {scriptname}.ecg`.
64
64
 
65
- As development progresses this demo script will be extended to include new features as they are added. **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
65
+ Graphical scripts look much like any other script but their file names must use the extension `.ecg` to signal to **_EasyCoder_** that it needs to load the graphics module. This allows the **_EasyCoder_** application to be used wherever Python is installed, in either a command-line or a graphical environment (but graphics will of course not be available in the former).
66
+
67
+ A couple of demo scripts are included in the `scripts` directory:
68
+
69
+ `graphics-demo.ecg` shows some of the elements that can be created, and demonstrates a variety of the graphical features of the language such as detecting when elements are clicked.
70
+
71
+ `wave.ecg` is a "Mexican Wave" simulation.
72
+
73
+ **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
66
74
 
67
75
  ## EasyCoder programming reference
68
76
 
@@ -49,9 +49,17 @@ Here in the repository is a folder called `scripts` containing some sample scrip
49
49
  `fizzbuzz.ecs` is a simple programming challenge often given at job interviews
50
50
 
51
51
  ## Graphical programmming
52
- **_EasyCoder_** is currently being extended to include a graphical programming environment. A single demo script `graphics-demo.ecs` is included in the `scripts` directory. To run it, first install the Python graphics library if it's not already present on your system. On Linux this is done with `sudo apt install python3-tk`. On Windows it's `pip install tk`. Then give the command `easycoder -g scripts/graphics-demo.ecs`.
52
+ **_EasyCoder_** includes a graphical programming environment that is in the early stages of development. A couple of demo scripts are included in the `scripts` directory. To run them, first install the Python `kivy` graphics library if it's not already present on your system. This is done with `pip install kivy`. Then run a script using `easycoder {scriptname}.ecg`.
53
53
 
54
- As development progresses this demo script will be extended to include new features as they are added. **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
54
+ Graphical scripts look much like any other script but their file names must use the extension `.ecg` to signal to **_EasyCoder_** that it needs to load the graphics module. This allows the **_EasyCoder_** application to be used wherever Python is installed, in either a command-line or a graphical environment (but graphics will of course not be available in the former).
55
+
56
+ A couple of demo scripts are included in the `scripts` directory:
57
+
58
+ `graphics-demo.ecg` shows some of the elements that can be created, and demonstrates a variety of the graphical features of the language such as detecting when elements are clicked.
59
+
60
+ `wave.ecg` is a "Mexican Wave" simulation.
61
+
62
+ **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
55
63
 
56
64
  ## EasyCoder programming reference
57
65
 
@@ -0,0 +1,6 @@
1
+ # EasyCode source code
2
+ These are the Python files that comprise **_EasyCoder_**.
3
+
4
+ **_EasyCoder_** has a small number of third-party dependencies. A minor one is `pytz`, which handles timezones. The biggest one by far is `kivy`, a comprehensive Python graphics library.
5
+
6
+ If an **_EasyCoder_** script filename ends with `.ecs` it's a command-line script. If it ends with `.ecg` it's a script for a graphical application and will cause `kivy` to be imported. Obviously this will only work on a GUI-based system, whereas command-line scripts will run anywhere there is Python.
@@ -1,5 +1,6 @@
1
1
  '''EasyCoder for Python'''
2
2
 
3
+ from .ec import Main
3
4
  from .ec_classes import *
4
5
  from .ec_compiler import *
5
6
  from .ec_condition import *
@@ -8,6 +9,5 @@ from .ec_handler import *
8
9
  from .ec_program import *
9
10
  from .ec_timestamp import *
10
11
  from .ec_value import *
11
- from .ec_graphics import *
12
12
 
13
- __version__ = "241218.1"
13
+ __version__ = "241231.1"
@@ -0,0 +1,10 @@
1
+ import sys
2
+ from .ec_program import Program
3
+
4
+ # This is the program launcher
5
+ def Main():
6
+ print(f'Args: {sys.argv}')
7
+ if (len(sys.argv) > 1):
8
+ Program(sys.argv[1:]).start()
9
+ else:
10
+ print('Syntax: easycoder <scriptname>')
@@ -52,3 +52,6 @@ class Token:
52
52
 
53
53
  class Condition():
54
54
  negate = False
55
+
56
+ class Object():
57
+ pass
@@ -16,6 +16,7 @@ class Compiler:
16
16
  self.warnings = []
17
17
  self.program.compiler = self
18
18
  self.addCommand = self.program.add
19
+ self.compileConstant = self.value.compileConstant
19
20
 
20
21
  def getPC(self):
21
22
  return len(self.program.code)
@@ -44,6 +45,11 @@ class Compiler:
44
45
  except:
45
46
  return None
46
47
 
48
+ # Get a constant
49
+ def getConstant(self, token):
50
+ self.index += 1
51
+ return self.compileConstant(token)
52
+
47
53
  # Get a value
48
54
  def getValue(self):
49
55
  return self.value.compileValue()
@@ -53,11 +59,6 @@ class Compiler:
53
59
  self.index += 1
54
60
  return self.value.compileValue()
55
61
 
56
- # Get a constant
57
- def getConstant(self, token):
58
- self.index += 1
59
- return self.value.compileConstant(token)
60
-
61
62
  # Get a condition
62
63
  def getCondition(self):
63
64
  return self.condition.compileCondition()
@@ -101,7 +102,7 @@ class Compiler:
101
102
 
102
103
  def showWarnings(self):
103
104
  for warning in self.warnings:
104
- print(f'Warning: Line {self.getLino() + 1}: {warning}')
105
+ print(f'Warning at line {self.getLino() + 1} from {warning}')
105
106
 
106
107
  def getSymbolRecord(self):
107
108
  token = self.getToken()
@@ -696,6 +696,29 @@ class Core(Handler):
696
696
  self.putSymbolValue(target, value)
697
697
  return self.nextPC()
698
698
 
699
+ # Negate a variable
700
+ def k_negate(self, command):
701
+ if self.nextIsSymbol():
702
+ symbolRecord = self.getSymbolRecord()
703
+ if symbolRecord['valueHolder']:
704
+ command['target'] = self.getToken()
705
+ self.add(command)
706
+ return True
707
+ self.warning(f'Core.negate: Variable "{symbolRecord["name"]}" does not hold a value')
708
+ return False
709
+
710
+ def r_negate(self, command):
711
+ symbolRecord = self.getVariable(command['target'])
712
+ if not symbolRecord['valueHolder']:
713
+ RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
714
+ return None
715
+ value = self.getSymbolValue(symbolRecord)
716
+ if value == None:
717
+ RuntimeError(self.program, f'{symbolRecord["name"]} has not been initialised')
718
+ value['content'] *= -1
719
+ self.putSymbolValue(symbolRecord, value)
720
+ return self.nextPC()
721
+
699
722
  # Define an object variable
700
723
  def k_object(self, command):
701
724
  return self.compileVariable(command)
@@ -724,8 +747,10 @@ class Core(Handler):
724
747
  FatalError(self.program.compiler, 'Unknown file open mode {self.getToken()}')
725
748
  return False
726
749
  command['mode'] = mode
727
- self.add(command)
728
- return True
750
+ else:
751
+ command['mode'] = 'r'
752
+ self.add(command)
753
+ return True
729
754
  else:
730
755
  FatalError(self.compiler, f'Variable "{self.getToken()}" is not a file')
731
756
  else:
@@ -974,7 +999,7 @@ class Core(Handler):
974
999
  content = self.getSymbolValue(templateRecord)['content']
975
1000
  original = self.getRuntimeValue(command['original'])
976
1001
  replacement = self.getRuntimeValue(command['replacement'])
977
- content = content.replace(original, replacement)
1002
+ content = content.replace(original, str(replacement))
978
1003
  value = {}
979
1004
  value['type'] = 'text'
980
1005
  value['numeric'] = False
@@ -1415,7 +1440,7 @@ class Core(Handler):
1415
1440
  # Compile a value in this domain
1416
1441
  def compileValue(self):
1417
1442
  value = {}
1418
- value['domain'] = 'core'
1443
+ value['domain'] = self.getName()
1419
1444
  token = self.getToken()
1420
1445
  if self.isSymbol():
1421
1446
  value['name'] = token
@@ -0,0 +1,429 @@
1
+ from .ec_classes import FatalError, RuntimeError, Object
2
+ from .ec_handler import Handler
3
+ from .ec_screenspec import ScreenSpec
4
+ from .ec_renderer import Renderer
5
+
6
+ class Graphics(Handler):
7
+
8
+ def __init__(self, compiler):
9
+ Handler.__init__(self, compiler)
10
+
11
+ def getName(self):
12
+ return 'graphics'
13
+
14
+ #############################################################################
15
+ # Keyword handlers
16
+
17
+ def k_attach(self, command):
18
+ if self.nextIsSymbol():
19
+ record = self.getSymbolRecord()
20
+ command['name'] = record['name']
21
+ if self.nextIs('to'):
22
+ value = self.nextValue()
23
+ record['id'] = value
24
+ command['id'] = value
25
+ self.add(command)
26
+ return True
27
+
28
+ def r_attach(self, command):
29
+ targetRecord = self.getVariable(command['name'])
30
+ keyword = targetRecord['keyword']
31
+ id = self.getRuntimeValue(command['id'])
32
+ element = self.ui.getElement(id)
33
+ if element == None:
34
+ FatalError(self.program.compiler, f'There is no screen element with id \'{id}\'')
35
+ return -1
36
+ if element.getType() != keyword:
37
+ FatalError(self.program.compiler, f'Mismatched element type ({element['type']} and {keyword})')
38
+ self.putSymbolValue(targetRecord, {'type': 'text', 'content': id})
39
+ return self.nextPC()
40
+
41
+ # close window
42
+ def k_close(self, command):
43
+ if (self.nextIs('window')):
44
+ self.add(command)
45
+ return True
46
+ return False
47
+
48
+ def r_close(self, command):
49
+ self.renderer.stop()
50
+ return 0
51
+
52
+ # create window/ellipse/rectangle//text/image
53
+ def k_create(self, command):
54
+ token = self.nextToken()
55
+ if (token == 'window'):
56
+ t = {}
57
+ t['type'] = 'text'
58
+ t['content'] = 'EasyCoder'
59
+ width = self.compileConstant(640)
60
+ height = self.compileConstant(480)
61
+ left = self.compileConstant(100)
62
+ top = self.compileConstant(100)
63
+ r = self.compileConstant(255)
64
+ g = self.compileConstant(255)
65
+ b = self.compileConstant(255)
66
+ while True:
67
+ token = self.peek()
68
+ if token == 'title':
69
+ self.nextToken()
70
+ t = self.nextValue()
71
+ elif token == 'at':
72
+ self.nextToken()
73
+ left = self.nextValue()
74
+ top = self.nextValue()
75
+ elif token == 'size':
76
+ self.nextToken()
77
+ width = self.nextValue()
78
+ height = self.nextValue()
79
+ elif token == 'fill':
80
+ self.nextToken()
81
+ if self.nextIs('color'):
82
+ r = self.nextValue()
83
+ g = self.nextValue()
84
+ b = self.nextValue()
85
+ else:
86
+ break
87
+ command['type'] = 'window'
88
+ command['title'] = t
89
+ command['pos'] = (left, top)
90
+ command['size'] = (width, height)
91
+ command['fill'] = (r, g, b)
92
+ self.add(command)
93
+ return True
94
+
95
+ elif self.isSymbol():
96
+ record = self.getSymbolRecord()
97
+ command['target'] = record['name']
98
+ type = record['keyword']
99
+ command['type'] = type
100
+ if type in ['ellipse', 'rectangle', 'image']:
101
+ self.getElementData(type, command)
102
+ for item in ['width', 'height', 'left', 'bottom', 'r', 'g', 'b']:
103
+ if command[item] == None:
104
+ FatalError(self.program.compiler, f'Missing property \'{item}\'')
105
+ return True
106
+ elif type == 'text':
107
+ self.getElementData(type, command)
108
+ for item in ['width', 'height', 'left', 'bottom', 'r', 'g', 'b', 'text']:
109
+ if command[item] == None:
110
+ FatalError(self.program.compiler, f'Missing property \'{item}\'')
111
+ self.add(command)
112
+ record['elementID'] = command['id']
113
+ return False
114
+
115
+ def getElementData(self, type, command):
116
+ width = None
117
+ height = None
118
+ left = None
119
+ bottom = None
120
+ r = None
121
+ g = None
122
+ b = None
123
+ text = None
124
+ source = None
125
+ id = self.nextValue()
126
+ while True:
127
+ token = self.peek()
128
+ if token == 'size':
129
+ self.nextToken()
130
+ width = self.nextValue()
131
+ height = self.nextValue()
132
+ elif token == 'at':
133
+ self.nextToken()
134
+ left = self.nextValue()
135
+ bottom = self.nextValue()
136
+ elif token == 'fill':
137
+ self.nextToken()
138
+ r = self.nextValue()
139
+ g = self.nextValue()
140
+ b = self.nextValue()
141
+ elif token == 'text':
142
+ self.nextToken()
143
+ text = self.nextValue()
144
+ elif token == 'source':
145
+ self.nextToken()
146
+ source = self.nextValue()
147
+ else:
148
+ break
149
+ command['id'] = id
150
+ command['type'] = type
151
+ if width != None:
152
+ command['width'] = width
153
+ if height != None:
154
+ command['height'] = height
155
+ if left!= None:
156
+ command['left'] = left
157
+ if bottom != None:
158
+ command['bottom'] = bottom
159
+ if r != None:
160
+ command['r'] = r
161
+ if g != None:
162
+ command['g'] = g
163
+ if b != None:
164
+ command['b'] = b
165
+ if text != None:
166
+ command['text'] = text
167
+ if source != None:
168
+ command['source'] = source
169
+
170
+ def r_create(self, command):
171
+ try:
172
+ type = command['type']
173
+ if type == 'window':
174
+ self.windowSpec = Object()
175
+ self.windowSpec.title = command['title']['content']
176
+ self.windowSpec.flush = self.program.flush
177
+ self.windowSpec.finish = self.program.finish
178
+ self.windowSpec.pos = (self.getRuntimeValue(command['pos'][0]), self.getRuntimeValue(command['pos'][1]))
179
+ self.windowSpec.size = (self.getRuntimeValue(command['size'][0]), self.getRuntimeValue(command['size'][1]))
180
+ self.windowSpec.fill = (self.getRuntimeValue(command['fill'][0])/255, self.getRuntimeValue(command['fill'][1])/255, self.getRuntimeValue(command['fill'][2])/255)
181
+ else:
182
+ element = self.ui.createWidget(self.getWidgetSpec(command))
183
+ print(element)
184
+ except Exception as e:
185
+ RuntimeError(self.program, e)
186
+ return self.nextPC()
187
+
188
+ def getWidgetSpec(self, command):
189
+ spec = Object()
190
+ spec.id = self.getRuntimeValue(command['id'])
191
+ spec.type = command['type']
192
+ spec.w = self.getRuntimeValue(command['width'])
193
+ spec.h = self.getRuntimeValue(command['height'])
194
+ spec.x = self.getRuntimeValue(command['left'])
195
+ spec.y = self.getRuntimeValue(command['bottom'])
196
+ spec.r = self.getRuntimeValue(command['r'])/255
197
+ spec.g = self.getRuntimeValue(command['g'])/255
198
+ spec.b = self.getRuntimeValue(command['b'])/255
199
+ return spec
200
+
201
+ def k_ellipse(self, command):
202
+ return self.compileVariable(command)
203
+
204
+ def r_ellipse(self, command):
205
+ return self.nextPC()
206
+
207
+ def r_getui(self, command):
208
+ self.ui = self.renderer.getUI()
209
+ return self.nextPC()
210
+
211
+ def k_image(self, command):
212
+ return self.compileVariable(command)
213
+
214
+ def r_image(self, command):
215
+ return self.nextPC()
216
+
217
+ # move an element
218
+ def k_move(self, command):
219
+ if self.nextIsSymbol():
220
+ record = self.getSymbolRecord()
221
+ type = record['keyword']
222
+ if type in ['ellipse', 'rectangle']:
223
+ command['target'] = record['id']
224
+ token = self.nextToken()
225
+ if token == 'to':
226
+ command['x'] = self.nextValue()
227
+ command['y'] = self.nextValue()
228
+ self.add(command)
229
+ return True
230
+ elif token == 'by':
231
+ command['keyword'] = 'moveBy'
232
+ command['dx'] = self.nextValue()
233
+ command['dy'] = self.nextValue()
234
+ self.add(command)
235
+ return True
236
+ return False
237
+
238
+ def r_move(self, command):
239
+ pos = (self.getRuntimeValue(command['x']), self.getRuntimeValue(command['y']))
240
+ self.ui.moveElementTo(self.getRuntimeValue(command['target']), pos)
241
+ return self.nextPC()
242
+
243
+ def r_moveBy(self, command):
244
+ dist = (self.getRuntimeValue(command['dx']), self.getRuntimeValue(command['dy']))
245
+ self.ui.moveElementBy(self.getRuntimeValue(command['target']), dist)
246
+ return self.nextPC()
247
+
248
+ def k_on(self, command):
249
+ token = self.nextToken()
250
+ if token in ['click', 'tap']:
251
+ command['type'] = 'tap'
252
+ if self.nextIsSymbol():
253
+ target = self.getSymbolRecord()
254
+ else:
255
+ FatalError(self.program.compiler, f'{self.getToken()} is not a screen element')
256
+ return False
257
+ command['target'] = target['name']
258
+ command['goto'] = self.getPC() + 2
259
+ self.add(command)
260
+ self.nextToken()
261
+ pcNext = self.getPC()
262
+ cmd = {}
263
+ cmd['domain'] = 'core'
264
+ cmd['lino'] = command['lino']
265
+ cmd['keyword'] = 'gotoPC'
266
+ cmd['goto'] = 0
267
+ cmd['debug'] = False
268
+ self.addCommand(cmd)
269
+ self.compileOne()
270
+ cmd = {}
271
+ cmd['domain'] = 'core'
272
+ cmd['lino'] = command['lino']
273
+ cmd['keyword'] = 'stop'
274
+ cmd['debug'] = False
275
+ self.addCommand(cmd)
276
+ # Fixup the link
277
+ self.getCommandAt(pcNext)['goto'] = self.getPC()
278
+ return True
279
+ return False
280
+
281
+ def r_on(self, command):
282
+ pc = command['goto']
283
+ if command['type'] == 'tap':
284
+ record = self.getVariable(command['target'])
285
+ keyword = record['keyword']
286
+ if keyword in ['ellipse', 'rectangle', 'text', 'image']:
287
+ id = record['value'][record['index']]['content']
288
+ self.ui.setOnClick(id, lambda: self.run(pc))
289
+ else:
290
+ RuntimeError(self.program, f'{record['name']} is not a clickable object')
291
+ return self.nextPC()
292
+
293
+ def k_rectangle(self, command):
294
+ return self.compileVariable(command)
295
+
296
+ def r_rectangle(self, command):
297
+ return self.nextPC()
298
+
299
+ def k_text(self, command):
300
+ return self.compileVariable(command)
301
+
302
+ def r_text(self, command):
303
+ return self.nextPC()
304
+
305
+ # render {spec}
306
+ def k_render(self, command):
307
+ command['spec'] = self.nextValue()
308
+ self.add(command)
309
+ return True
310
+
311
+ def r_render(self, command):
312
+ self.ui = self.renderer.getUI()
313
+ try:
314
+ ScreenSpec().render(self.getRuntimeValue(command['spec']), self.ui)
315
+ except Exception as e:
316
+ RuntimeError(self.program, e)
317
+ return self.nextPC()
318
+
319
+ # run graphics
320
+ def k_run(self, command):
321
+ if self.nextIs('graphics'):
322
+ self.add(command)
323
+ cmd = {}
324
+ cmd['domain'] = 'graphics'
325
+ cmd['lino'] = command['lino'] + 1
326
+ cmd['keyword'] = 'getui'
327
+ cmd['debug'] = False
328
+ self.addCommand(cmd)
329
+ return True
330
+ return False
331
+
332
+ def r_run(self, command):
333
+ self.renderer = Renderer()
334
+ self.renderer.init(self.windowSpec)
335
+ self.program.setExternalControl()
336
+ self.program.run(self.nextPC())
337
+ self.renderer.run()
338
+
339
+ # Set something
340
+ def k_set(self, command):
341
+ if self.nextIs('attribute'):
342
+ command['attribute'] = self.nextValue()
343
+ if self.nextIs('of'):
344
+ if self.nextIsSymbol():
345
+ record = self.getSymbolRecord()
346
+ if record['keyword'] in ['ellipse', 'rectangle', 'text', 'image']:
347
+ command['target'] = record['name']
348
+ if self.nextIs('to'):
349
+ command['value'] = self.nextValue()
350
+ self.addCommand(command)
351
+ return True
352
+ else:
353
+ FatalError(self.program.compiler, f'Invalid type: {record['keyword']}')
354
+ else:
355
+ FatalError(self.program.compiler, f'\'{self.getToken()}\' is not a variable')
356
+ return False
357
+
358
+ def r_set(self, command):
359
+ attribute = self.getRuntimeValue(command['attribute'])
360
+ target = self.getVariable(command['target'])
361
+ id = target['value'][target['index']]['content']
362
+ value = self.getRuntimeValue(command['value'])
363
+ self.ui.setAttribute(id, attribute, value)
364
+ return self.nextPC()
365
+
366
+ #############################################################################
367
+ # Modify a value or leave it unchanged.
368
+ def modifyValue(self, value):
369
+ return value
370
+
371
+ #############################################################################
372
+ # Compile a value in this domain
373
+ def compileValue(self):
374
+ value = {}
375
+ value['domain'] = self.getName()
376
+ if self.tokenIs('the'):
377
+ self.nextToken()
378
+ kwd = self.getToken()
379
+ value['type'] = kwd
380
+ if kwd == 'attribute':
381
+ attribute = self.nextValue()
382
+ if self.nextIs('of'):
383
+ if self.nextIsSymbol():
384
+ record = self.getSymbolRecord()
385
+ if record['keyword'] in ['ellipse', 'rectangle']:
386
+ value['attribute'] = attribute
387
+ value['target'] = record['name']
388
+ return value
389
+ elif kwd == 'window':
390
+ attribute = self.nextToken()
391
+ if attribute in ['left', 'top', 'width', 'height']:
392
+ value['attribute'] = attribute
393
+ return value
394
+ return None
395
+
396
+ #############################################################################
397
+ # Value handlers
398
+
399
+ def v_attribute(self, v):
400
+ try:
401
+ attribute = self.getRuntimeValue(v['attribute'])
402
+ target = self.getVariable(v['target'])
403
+ val = self.getSymbolValue(target)
404
+ v = self.ui.getAttribute(val['content'], attribute)
405
+ value = {}
406
+ value['type'] = 'int'
407
+ value['content'] = int(round(v))
408
+ return value
409
+ except Exception as e:
410
+ RuntimeError(self.program, e)
411
+
412
+ def v_window(self, v):
413
+ try:
414
+ attribute = v['attribute']
415
+ value = {}
416
+ value['type'] = 'int'
417
+ value['content'] = int(round(self.ui.getWindowAttribute(attribute)))
418
+ return value
419
+ except Exception as e:
420
+ RuntimeError(self.program, e)
421
+
422
+ #############################################################################
423
+ # Compile a condition
424
+ def compileCondition(self):
425
+ condition = {}
426
+ return condition
427
+
428
+ #############################################################################
429
+ # Condition handlers
@@ -25,6 +25,7 @@ class Handler:
25
25
  self.getCommandAt = compiler.getCommandAt
26
26
  self.compileOne = compiler.compileOne
27
27
  self.compileFromHere = compiler.compileFromHere
28
+ self.compileConstant = compiler.compileConstant
28
29
 
29
30
  self.code = self.program.code
30
31
  self.add = self.program.add