easypy-lang 2.0.1__tar.gz → 2.0.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easypy-lang
3
- Version: 2.0.1
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
@@ -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):
@@ -155,17 +155,82 @@ class EasypyTranspiler:
155
155
 
156
156
  return "".join(normalized)
157
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
+
158
216
  def _process_line(self, raw_line):
159
217
  # Indentation handling (Closing Brace)
160
218
  # Handle cases like "}" or "} else {" or "}}"
219
+ closing_braces = ""
161
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
+
162
225
  self.indent_level -= 1
163
226
  if self.indent_level < 0: self.indent_level = 0
164
227
  if self.context_stack: self.context_stack.pop()
165
228
  raw_line = raw_line[1:].strip()
166
229
 
167
- # If line was just "}", it is now empty. Return None to skip outputting a blank/garbage line.
230
+ # If line was just "}", it is now empty.
168
231
  if not raw_line:
232
+ if closing_braces:
233
+ return f"{' ' * self.indent_level}{closing_braces}"
169
234
  return None
170
235
 
171
236
  # Prepare current indentation string
@@ -175,6 +240,13 @@ class EasypyTranspiler:
175
240
  if raw_line.startswith('#') or raw_line.startswith('//'):
176
241
  return f"{indent}#{raw_line}"
177
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
+
178
250
  # === TRANSLATION RULES ===
179
251
 
180
252
  # 1. Imports
@@ -249,12 +321,14 @@ class EasypyTranspiler:
249
321
  condition = raw_line[2:-1].strip()
250
322
  # Handle if(x) vs if x
251
323
  if condition.startswith("(") and condition.endswith(")"): condition = condition
324
+ condition = self._clean_expression(condition)
252
325
  self.indent_level += 1
253
326
  self.context_stack.append('block')
254
327
  return f"{indent}if {condition}:"
255
328
 
256
329
  if raw_line.startswith("elif") and raw_line.endswith("{"):
257
330
  condition = raw_line[4:-1].strip()
331
+ condition = self._clean_expression(condition)
258
332
  self.indent_level += 1
259
333
  self.context_stack.append('block')
260
334
  return f"{indent}elif {condition}:"
@@ -265,31 +339,50 @@ class EasypyTranspiler:
265
339
  return f"{indent}else:"
266
340
 
267
341
  # 6. Loops
268
- loop_match = re.match(r'loop (\d+) times\s*\{', raw_line)
269
- if loop_match:
270
- 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(":")):
271
344
  self.indent_level += 1
272
345
  self.context_stack.append('block')
273
- return f"{indent}for _ in range({count}):"
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}"
274
350
 
275
- if raw_line.startswith("while") and raw_line.endswith("{"):
276
- condition = raw_line[5:-1].strip()
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()
277
353
  self.indent_level += 1
278
354
  self.context_stack.append('block')
279
- return f"{indent}while {condition}:"
355
+ return f"{indent}{clean_line}:"
280
356
 
281
- if raw_line.startswith("for ") and raw_line.endswith("{"):
282
- condition = raw_line[3:-1].strip()
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()
283
359
  self.indent_level += 1
284
360
  self.context_stack.append('block')
285
- return f"{indent}for {condition}:"
361
+ return f"{indent}{clean_line}:"
286
362
 
287
363
  # 7. Generic Block
288
364
  if raw_line.endswith("{"):
289
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
+
290
375
  self.indent_level += 1
291
- self.context_stack.append('block')
292
- return f"{indent}{clean_line}:"
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}:"
293
384
 
294
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
295
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.1
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
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="easypy-lang",
8
- version="2.0.1",
8
+ version="2.0.2",
9
9
  author="Vadik Goel",
10
10
  author_email="vadikgoel1@gmail.com",
11
11
  description="A simple, powerful language for AI, ML, and apps - No coding experience needed!",
File without changes
File without changes