easypy-lang 2.0.0__py3-none-any.whl → 2.0.2__py3-none-any.whl
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.
- easypy_lang/modules_real.py +9 -0
- easypy_lang/transpiler.py +129 -12
- {easypy_lang-2.0.0.dist-info → easypy_lang-2.0.2.dist-info}/METADATA +15 -3
- easypy_lang-2.0.2.dist-info/RECORD +12 -0
- {easypy_lang-2.0.0.dist-info → easypy_lang-2.0.2.dist-info}/WHEEL +1 -1
- easypy_lang-2.0.0.dist-info/RECORD +0 -12
- {easypy_lang-2.0.0.dist-info → easypy_lang-2.0.2.dist-info}/entry_points.txt +0 -0
- {easypy_lang-2.0.0.dist-info → easypy_lang-2.0.2.dist-info}/top_level.txt +0 -0
easypy_lang/modules_real.py
CHANGED
|
@@ -9,6 +9,15 @@ import time
|
|
|
9
9
|
import json
|
|
10
10
|
import threading
|
|
11
11
|
|
|
12
|
+
# Global Aliases for Easypy -> Python compatibility
|
|
13
|
+
true = True
|
|
14
|
+
false = False
|
|
15
|
+
null = None
|
|
16
|
+
|
|
17
|
+
# Built-in String Helpers
|
|
18
|
+
def upper(s): return str(s).upper()
|
|
19
|
+
def lower(s): return str(s).lower()
|
|
20
|
+
|
|
12
21
|
# ==================== GUI (Tkinter) ====================
|
|
13
22
|
class _GUIImpl:
|
|
14
23
|
def __init__(self):
|
easypy_lang/transpiler.py
CHANGED
|
@@ -8,6 +8,7 @@ import re
|
|
|
8
8
|
class EasypyTranspiler:
|
|
9
9
|
def __init__(self):
|
|
10
10
|
self.indent_level = 0
|
|
11
|
+
self.context_stack = [] # Stack to track [class, func, other]
|
|
11
12
|
self.in_block = False
|
|
12
13
|
self.source_map = {} # Maps generated python line -> original ep line
|
|
13
14
|
|
|
@@ -154,16 +155,82 @@ class EasypyTranspiler:
|
|
|
154
155
|
|
|
155
156
|
return "".join(normalized)
|
|
156
157
|
|
|
158
|
+
def _clean_expression(self, text):
|
|
159
|
+
"""Helper to convert C-style syntax to Python"""
|
|
160
|
+
# Operators
|
|
161
|
+
text = text.replace("===", "==")
|
|
162
|
+
text = text.replace("&&", " and ")
|
|
163
|
+
text = text.replace("||", " or ")
|
|
164
|
+
|
|
165
|
+
# '!' but not '!='
|
|
166
|
+
# Only replace if preceded by start-of-line, space, '(', '[', or '='
|
|
167
|
+
# This prevents replacing '!' inside strings like "Hello!"
|
|
168
|
+
text = re.sub(r'(?:^|(?<=[=\s(\[]))!(?!=)', 'not ', text)
|
|
169
|
+
|
|
170
|
+
# 'true'/'false'/'null' are handled by modules_real.py aliases at runtime,
|
|
171
|
+
# but replacing them here can be safer for some edge cases.
|
|
172
|
+
# But let's stick to the aliases to avoid accidental string replacement.
|
|
173
|
+
|
|
174
|
+
return text
|
|
175
|
+
|
|
176
|
+
def _preprocess_line(self, line):
|
|
177
|
+
"""Handle 'Advanced' syntax: --->, if =, implicit f-strings"""
|
|
178
|
+
|
|
179
|
+
# 1. implicit f-strings for print/log
|
|
180
|
+
# Detect if {var} pattern exists inside quotes
|
|
181
|
+
if ('print(' in line or 'log ' in line) and '{' in line and '}' in line:
|
|
182
|
+
# Simple heuristic: inject 'f' before quotes
|
|
183
|
+
# Handle double quotes
|
|
184
|
+
line = re.sub(r'print\(\s*"', 'print(f"', line)
|
|
185
|
+
line = re.sub(r'log\s+"', 'log f"', line)
|
|
186
|
+
# Handle single quotes
|
|
187
|
+
line = re.sub(r"print\(\s*'", "print(f'", line)
|
|
188
|
+
line = re.sub(r"log\s+'", "log f'", line)
|
|
189
|
+
|
|
190
|
+
# 2. Syntax Sugar: Arrow
|
|
191
|
+
if "--->" in line:
|
|
192
|
+
line = line.replace("--->", ":")
|
|
193
|
+
|
|
194
|
+
# 3. Syntax Sugar: if =, else if =, else =
|
|
195
|
+
line = re.sub(r'^(\s*)if\s*=\s*', r'\1if ', line)
|
|
196
|
+
line = re.sub(r'^(\s*)else\s*if\s*=\s*', r'\1elif ', line)
|
|
197
|
+
# Fix: else = statement needs a colon for inline usage
|
|
198
|
+
line = re.sub(r'^(\s*)else\s*=\s*', r'\1else: ', line)
|
|
199
|
+
|
|
200
|
+
# 4. Handle "else if" without equals
|
|
201
|
+
line = line.replace("else if", "elif")
|
|
202
|
+
|
|
203
|
+
# 5. Loop syntax conversion (loop N times)
|
|
204
|
+
# Supports both "loop 3 times:" and "loop 3 times {"
|
|
205
|
+
# We replace the start with pythonic loop
|
|
206
|
+
loop_match = re.match(r'^(\s*)loop\s+(\d+)\s+times', line)
|
|
207
|
+
if loop_match:
|
|
208
|
+
indent = loop_match.group(1)
|
|
209
|
+
count = loop_match.group(2)
|
|
210
|
+
# Replace 'loop N times' with 'for _ in range(N)'
|
|
211
|
+
# We leave the suffix (colon or brace) for the next step
|
|
212
|
+
line = re.sub(r'loop\s+\d+\s+times', f'for _ in range({count})', line, count=1)
|
|
213
|
+
|
|
214
|
+
return line
|
|
215
|
+
|
|
157
216
|
def _process_line(self, raw_line):
|
|
158
217
|
# Indentation handling (Closing Brace)
|
|
159
218
|
# Handle cases like "}" or "} else {" or "}}"
|
|
219
|
+
closing_braces = ""
|
|
160
220
|
while raw_line.startswith("}"):
|
|
221
|
+
ctx = self.context_stack[-1] if self.context_stack else 'block'
|
|
222
|
+
if ctx == 'dict':
|
|
223
|
+
closing_braces += "}"
|
|
224
|
+
|
|
161
225
|
self.indent_level -= 1
|
|
162
226
|
if self.indent_level < 0: self.indent_level = 0
|
|
227
|
+
if self.context_stack: self.context_stack.pop()
|
|
163
228
|
raw_line = raw_line[1:].strip()
|
|
164
229
|
|
|
165
|
-
# If line was just "}", it is now empty.
|
|
230
|
+
# If line was just "}", it is now empty.
|
|
166
231
|
if not raw_line:
|
|
232
|
+
if closing_braces:
|
|
233
|
+
return f"{' ' * self.indent_level}{closing_braces}"
|
|
167
234
|
return None
|
|
168
235
|
|
|
169
236
|
# Prepare current indentation string
|
|
@@ -173,6 +240,13 @@ class EasypyTranspiler:
|
|
|
173
240
|
if raw_line.startswith('#') or raw_line.startswith('//'):
|
|
174
241
|
return f"{indent}#{raw_line}"
|
|
175
242
|
|
|
243
|
+
# === PREPROCESSOR ===
|
|
244
|
+
# Handle "Advanced" syntax (Arrow, if=, etc)
|
|
245
|
+
raw_line = self._preprocess_line(raw_line)
|
|
246
|
+
|
|
247
|
+
# Apply basic expression cleanup (&& -> and)
|
|
248
|
+
raw_line = self._clean_expression(raw_line)
|
|
249
|
+
|
|
176
250
|
# === TRANSLATION RULES ===
|
|
177
251
|
|
|
178
252
|
# 1. Imports
|
|
@@ -212,19 +286,34 @@ class EasypyTranspiler:
|
|
|
212
286
|
# 3. Functions
|
|
213
287
|
if raw_line.startswith("func ") and raw_line.endswith("{"):
|
|
214
288
|
defn = raw_line[5:-1].strip()
|
|
289
|
+
|
|
290
|
+
# Auto-inject 'self' if inside a class
|
|
291
|
+
if self.context_stack and self.context_stack[-1] == 'class':
|
|
292
|
+
parts = defn.split("(", 1)
|
|
293
|
+
name = parts[0]
|
|
294
|
+
args = parts[1][:-1] if len(parts) > 1 else ""
|
|
295
|
+
|
|
296
|
+
if args.strip():
|
|
297
|
+
defn = f"{name}(self, {args})"
|
|
298
|
+
else:
|
|
299
|
+
defn = f"{name}(self)"
|
|
300
|
+
|
|
215
301
|
self.indent_level += 1
|
|
302
|
+
self.context_stack.append('func')
|
|
216
303
|
return f"{indent}def {defn}:"
|
|
217
304
|
|
|
218
305
|
# 3b. Async Functions
|
|
219
306
|
if raw_line.startswith("async func ") and raw_line.endswith("{"):
|
|
220
307
|
defn = raw_line[11:-1].strip()
|
|
221
308
|
self.indent_level += 1
|
|
309
|
+
self.context_stack.append('func')
|
|
222
310
|
return f"{indent}async def {defn}:"
|
|
223
311
|
|
|
224
312
|
# 4. Classes
|
|
225
313
|
if raw_line.startswith("class ") and raw_line.endswith("{"):
|
|
226
314
|
defn = raw_line[6:-1].strip()
|
|
227
315
|
self.indent_level += 1
|
|
316
|
+
self.context_stack.append('class')
|
|
228
317
|
return f"{indent}class {defn}:"
|
|
229
318
|
|
|
230
319
|
# 5. Logic
|
|
@@ -232,40 +321,68 @@ class EasypyTranspiler:
|
|
|
232
321
|
condition = raw_line[2:-1].strip()
|
|
233
322
|
# Handle if(x) vs if x
|
|
234
323
|
if condition.startswith("(") and condition.endswith(")"): condition = condition
|
|
324
|
+
condition = self._clean_expression(condition)
|
|
235
325
|
self.indent_level += 1
|
|
326
|
+
self.context_stack.append('block')
|
|
236
327
|
return f"{indent}if {condition}:"
|
|
237
328
|
|
|
238
329
|
if raw_line.startswith("elif") and raw_line.endswith("{"):
|
|
239
330
|
condition = raw_line[4:-1].strip()
|
|
331
|
+
condition = self._clean_expression(condition)
|
|
240
332
|
self.indent_level += 1
|
|
333
|
+
self.context_stack.append('block')
|
|
241
334
|
return f"{indent}elif {condition}:"
|
|
242
335
|
|
|
243
336
|
if raw_line.startswith("else") and raw_line.endswith("{"):
|
|
244
337
|
self.indent_level += 1
|
|
338
|
+
self.context_stack.append('block')
|
|
245
339
|
return f"{indent}else:"
|
|
246
340
|
|
|
247
341
|
# 6. Loops
|
|
248
|
-
|
|
249
|
-
if
|
|
250
|
-
count = loop_match.group(1)
|
|
342
|
+
# (Handled by preprocessor now, but we keep this for block context tracking if needed)
|
|
343
|
+
if raw_line.startswith("for ") and " range(" in raw_line and (raw_line.endswith("{") or raw_line.endswith(":")):
|
|
251
344
|
self.indent_level += 1
|
|
252
|
-
|
|
345
|
+
self.context_stack.append('block')
|
|
346
|
+
# If it ends with {, strip it for python
|
|
347
|
+
if raw_line.endswith("{"):
|
|
348
|
+
return f"{indent}{raw_line[:-1].strip()}:"
|
|
349
|
+
return f"{indent}{raw_line}"
|
|
253
350
|
|
|
254
|
-
if raw_line.startswith("while") and raw_line.endswith("{"):
|
|
255
|
-
|
|
351
|
+
if raw_line.startswith("while") and (raw_line.endswith("{") or raw_line.endswith(":")):
|
|
352
|
+
clean_line = raw_line[:-1].strip() if raw_line.endswith("{") else raw_line[:-1].strip()
|
|
256
353
|
self.indent_level += 1
|
|
257
|
-
|
|
354
|
+
self.context_stack.append('block')
|
|
355
|
+
return f"{indent}{clean_line}:"
|
|
258
356
|
|
|
259
|
-
if raw_line.startswith("for ") and raw_line.endswith("{"):
|
|
260
|
-
|
|
357
|
+
if raw_line.startswith("for ") and (raw_line.endswith("{") or raw_line.endswith(":")):
|
|
358
|
+
clean_line = raw_line[:-1].strip() if raw_line.endswith("{") else raw_line[:-1].strip()
|
|
261
359
|
self.indent_level += 1
|
|
262
|
-
|
|
360
|
+
self.context_stack.append('block')
|
|
361
|
+
return f"{indent}{clean_line}:"
|
|
263
362
|
|
|
264
363
|
# 7. Generic Block
|
|
265
364
|
if raw_line.endswith("{"):
|
|
266
365
|
clean_line = raw_line[:-1].strip()
|
|
366
|
+
clean_line = self._clean_expression(clean_line)
|
|
367
|
+
|
|
368
|
+
# CRITICAL FIX: Detect Dictionary vs Code Block
|
|
369
|
+
# If it is an assignment (x = {), keep the brace, do strict Python dict open.
|
|
370
|
+
# Regex checks for "var =" or "word =" pattern at end of line
|
|
371
|
+
# But NOT "if x == {" (comparison)
|
|
372
|
+
# Simple heuristic: If it has "=" and not " if " or " while ", it's likely data.
|
|
373
|
+
is_assignment = re.search(r'[^=!<>]=[^=]', clean_line) or clean_line.endswith("=")
|
|
374
|
+
|
|
267
375
|
self.indent_level += 1
|
|
268
|
-
|
|
376
|
+
if is_assignment:
|
|
377
|
+
# It's a dict! Keep the brace.
|
|
378
|
+
self.context_stack.append('dict')
|
|
379
|
+
return f"{indent}{clean_line} {{"
|
|
380
|
+
else:
|
|
381
|
+
# It's a code block! Use colon.
|
|
382
|
+
self.context_stack.append('block')
|
|
383
|
+
return f"{indent}{clean_line}:"
|
|
269
384
|
|
|
270
385
|
# 8. Standard Line
|
|
386
|
+
# Apply cleanup to standard lines too (assignments, expressions)
|
|
387
|
+
# raw_line = self._clean_expression(raw_line) # Already done in preprocess
|
|
271
388
|
return f"{indent}{raw_line}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: easypy-lang
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: A simple, powerful language for AI, ML, and apps - No coding experience needed!
|
|
5
5
|
Home-page: https://github.com/VadikGoel/easypy-lang
|
|
6
6
|
Author: Vadik Goel
|
|
@@ -41,12 +41,24 @@ Whether you want to build websites, analyze data, or create AI chatbots, Easypy
|
|
|
41
41
|
|
|
42
42
|
## 📦 Installation
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
### Option 1: Install via Pip (Recommended)
|
|
45
|
+
Simply install the package via pip:
|
|
45
46
|
|
|
46
47
|
```bash
|
|
47
48
|
pip install easypy-lang
|
|
48
49
|
```
|
|
49
50
|
|
|
51
|
+
### Option 2: Run via Docker (No Install Needed)
|
|
52
|
+
Don't want to install Python? Run Easypy directly in a container:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Pull the image
|
|
56
|
+
docker pull vadikgoel/easypy-lang
|
|
57
|
+
|
|
58
|
+
# Run interactive mode
|
|
59
|
+
docker run -it vadikgoel/easypy-lang
|
|
60
|
+
```
|
|
61
|
+
|
|
50
62
|
## ✨ Features
|
|
51
63
|
|
|
52
64
|
- **English-like Syntax**: Write code that reads like a story.
|
|
@@ -80,7 +92,7 @@ easypy hello.easy
|
|
|
80
92
|
|
|
81
93
|
## 📚 Documentation
|
|
82
94
|
|
|
83
|
-
For full documentation, tutorials, and the interactive playground, please check the `docs/` folder included in the repository or visit our [
|
|
95
|
+
For full documentation, tutorials, and the interactive playground, please check the `docs/` folder included in the repository or visit our [Documentation](https://vadikgoel.github.io/easypy-lang/).
|
|
84
96
|
|
|
85
97
|
## 🤝 Contributing
|
|
86
98
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
easypy_lang/__init__.py,sha256=8RyTILsaMBOfR1mgK9hRKOvYz8lkwAUdX9HQILNR5LU,218
|
|
2
|
+
easypy_lang/cli.py,sha256=THGJ23wEK4sG0R-fSVGesNa0wsYp0-WIj4NK_-uWBBA,15490
|
|
3
|
+
easypy_lang/engine.py,sha256=mEvSKb_gcGvlb4iBtrQFFc6Pns73-Gb3HiGKWqLLTes,26608
|
|
4
|
+
easypy_lang/epi.py,sha256=W3FQtq__GujGofQDwBAqsbPGS-1bCyFSnriqnaP_V4A,1683
|
|
5
|
+
easypy_lang/modules.py,sha256=uuyrx7_GY8V64rgBPrLTksjUAB3q0V_PI3aGZySVGwQ,14403
|
|
6
|
+
easypy_lang/modules_real.py,sha256=IcZMcVafF3aozmPZYp5YXPoIJzh6oV-BX-28G6TDAQA,3588
|
|
7
|
+
easypy_lang/transpiler.py,sha256=0WJYN5PxML0y2yg7TUjDswKJ7-vvcKirxR_0Jwjj8UY,16393
|
|
8
|
+
easypy_lang-2.0.2.dist-info/METADATA,sha256=hfNPY9gCQe5aJyZe8X-IdCi7Uk8-ZBzI-DSRMPlANuM,3180
|
|
9
|
+
easypy_lang-2.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
+
easypy_lang-2.0.2.dist-info/entry_points.txt,sha256=mKKDQahcErG53etDO_npP9h4Oxvw4s7buWdl9R6BMX4,76
|
|
11
|
+
easypy_lang-2.0.2.dist-info/top_level.txt,sha256=MEflM_hPiCkdi0AemcYPHUMvUOoFQhNylmfb92x_FZw,12
|
|
12
|
+
easypy_lang-2.0.2.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
easypy_lang/__init__.py,sha256=8RyTILsaMBOfR1mgK9hRKOvYz8lkwAUdX9HQILNR5LU,218
|
|
2
|
-
easypy_lang/cli.py,sha256=THGJ23wEK4sG0R-fSVGesNa0wsYp0-WIj4NK_-uWBBA,15490
|
|
3
|
-
easypy_lang/engine.py,sha256=mEvSKb_gcGvlb4iBtrQFFc6Pns73-Gb3HiGKWqLLTes,26608
|
|
4
|
-
easypy_lang/epi.py,sha256=W3FQtq__GujGofQDwBAqsbPGS-1bCyFSnriqnaP_V4A,1683
|
|
5
|
-
easypy_lang/modules.py,sha256=uuyrx7_GY8V64rgBPrLTksjUAB3q0V_PI3aGZySVGwQ,14403
|
|
6
|
-
easypy_lang/modules_real.py,sha256=Zchg6xmTUoThHl45Ae1qLQPaPtXvYTSovG8LxbBvVM8,3389
|
|
7
|
-
easypy_lang/transpiler.py,sha256=3V1p7sNi3zH3-2a1gXbP9HytfEx0CrtGWJB9IyPc4kA,10813
|
|
8
|
-
easypy_lang-2.0.0.dist-info/METADATA,sha256=d_mFxZwyDUVCEqFpNApMBNmBu0sUPRR6RYVSZxlXjPc,2903
|
|
9
|
-
easypy_lang-2.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
10
|
-
easypy_lang-2.0.0.dist-info/entry_points.txt,sha256=mKKDQahcErG53etDO_npP9h4Oxvw4s7buWdl9R6BMX4,76
|
|
11
|
-
easypy_lang-2.0.0.dist-info/top_level.txt,sha256=MEflM_hPiCkdi0AemcYPHUMvUOoFQhNylmfb92x_FZw,12
|
|
12
|
-
easypy_lang-2.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|