505 lines
20 KiB
Python
505 lines
20 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
import re, copy
|
||
|
|
|
||
|
|
class Pointer:
|
||
|
|
def __init__(s, v=None): s.val = v
|
||
|
|
|
||
|
|
class NanoClass:
|
||
|
|
def __init__(s, n, p, m, c, d): s.name, s.props, s.methods, s.constructor, s.destructor = n, p, m, c, d
|
||
|
|
|
||
|
|
class NanoObject:
|
||
|
|
def __init__(s, c, p): s._class, s._props = c, p
|
||
|
|
|
||
|
|
class Runtime:
|
||
|
|
def __init__(s):
|
||
|
|
s.classes, s.globals, s.locals_stack = {}, {}, [{}]
|
||
|
|
s.return_value, s.returning = None, False
|
||
|
|
|
||
|
|
@property
|
||
|
|
def locals(s): return s.locals_stack[-1]
|
||
|
|
def push_scope(s): s.locals_stack.append({})
|
||
|
|
def pop_scope(s): len(s.locals_stack) > 1 and s.locals_stack.pop()
|
||
|
|
|
||
|
|
def get_var(s, n):
|
||
|
|
if n in s.locals: return s.locals[n]
|
||
|
|
return s.globals.get(n)
|
||
|
|
|
||
|
|
def set_var(s, n, v):
|
||
|
|
for sc in reversed(s.locals_stack):
|
||
|
|
if n in sc: sc[n] = v; return
|
||
|
|
if n in s.globals: s.globals[n] = v
|
||
|
|
else: s.locals[n] = v
|
||
|
|
|
||
|
|
def set_local(s, n, v):
|
||
|
|
s.locals[n] = v
|
||
|
|
|
||
|
|
def tokenize(s, c):
|
||
|
|
c = re.sub(r'//[^\n]*', '', re.sub(r'/\*.*?\*/', '', c, flags=re.DOTALL))
|
||
|
|
toks, pats = [], [
|
||
|
|
(r'\"[^\"]*\"', 'S'), (r"\'[^\']*\'", 'S'), (r'\d+\.?\d*', 'N'),
|
||
|
|
(r'class\b', 'CL'), (r'new\b', 'NW'), (r'if\b', 'IF'), (r'else\b', 'EL'),
|
||
|
|
(r'while\b', 'WH'), (r'for\b', 'FR'), (r'return\b', 'RT'),
|
||
|
|
(r'null\b', 'NU'), (r'true\b', 'TR'), (r'false\b', 'FA'),
|
||
|
|
(r'\*\*', 'DS'), (r'\|\|', 'OR'), (r'&&', 'AN'), (r'==', 'EQ'), (r'!=', 'NE'),
|
||
|
|
(r'<=', 'LE'), (r'>=', 'GE'), (r'\+=', 'PE'), (r'-=', 'ME'), (r'\*=', 'UE'),
|
||
|
|
(r'/=', 'DE'), (r'\+\+', 'IC'), (r'--', 'DC'),
|
||
|
|
(r'[a-zA-Z_][a-zA-Z0-9_]*', 'I'), (r'[{}()\[\];,.<>+\-*/%=!&|:~]', 'Y'), (r'\s+', None)]
|
||
|
|
i = 0
|
||
|
|
while i < len(c):
|
||
|
|
for p, t in pats:
|
||
|
|
m = re.match(p, c[i:])
|
||
|
|
if m:
|
||
|
|
t and toks.append((t, m.group()))
|
||
|
|
i += len(m.group()); break
|
||
|
|
else: i += 1
|
||
|
|
return toks
|
||
|
|
|
||
|
|
def parse_block(s, t, st):
|
||
|
|
if st >= len(t) or t[st] != ('Y', '{'): return [], st
|
||
|
|
d, i, b = 1, st + 1, []
|
||
|
|
while i < len(t) and d > 0:
|
||
|
|
if t[i] == ('Y', '{'): d += 1
|
||
|
|
elif t[i] == ('Y', '}'): d -= 1
|
||
|
|
d > 0 and b.append(t[i]); i += 1
|
||
|
|
return b, i
|
||
|
|
|
||
|
|
def parse_expr(s, t, st, es=None):
|
||
|
|
es = es or [';', ',', ')', '}', ']']
|
||
|
|
e, d, i = [], 0, st
|
||
|
|
while i < len(t):
|
||
|
|
x = t[i]
|
||
|
|
if d == 0 and x[0] == 'Y' and x[1] in es: break
|
||
|
|
if x[0] == 'Y' and x[1] in '([{': d += 1
|
||
|
|
elif x[0] == 'Y' and x[1] in ')]}': d -= 1
|
||
|
|
e.append(x); i += 1
|
||
|
|
return e, i
|
||
|
|
|
||
|
|
def to_num(s, v):
|
||
|
|
if v is None: return 0
|
||
|
|
if isinstance(v, (int, float)): return v
|
||
|
|
try: return int(v)
|
||
|
|
except:
|
||
|
|
try: return float(v)
|
||
|
|
except: return 0
|
||
|
|
|
||
|
|
def is_truthy(s, v):
|
||
|
|
if v is None: return False
|
||
|
|
if isinstance(v, (int, float)): return v != 0
|
||
|
|
if isinstance(v, (str, list)): return len(v) > 0
|
||
|
|
return True
|
||
|
|
|
||
|
|
def eval_expr(s, t):
|
||
|
|
if not t: return None
|
||
|
|
if len(t) == 1:
|
||
|
|
x = t[0]
|
||
|
|
if x[0] == 'N': return float(x[1]) if '.' in x[1] else int(x[1])
|
||
|
|
if x[0] == 'S': return x[1][1:-1]
|
||
|
|
if x[0] == 'NU': return None
|
||
|
|
if x[0] == 'TR': return 1
|
||
|
|
if x[0] == 'FA': return 0
|
||
|
|
if x[0] == 'I': return s.get_var(x[1])
|
||
|
|
if t[0] == ('NW', 'new'): return s.eval_new(t[1:])
|
||
|
|
if t[0] == ('Y', '*') and len(t) > 1:
|
||
|
|
v = s.eval_expr(t[1:])
|
||
|
|
return v.val if isinstance(v, Pointer) else v
|
||
|
|
if t[0] == ('Y', '&') and len(t) > 1 and t[1][0] == 'I':
|
||
|
|
return Pointer(s.get_var(t[1][1]))
|
||
|
|
if t[0] == ('Y', '{'): return s.eval_array(t)
|
||
|
|
for i, x in enumerate(t):
|
||
|
|
if x == ('OR', '||'):
|
||
|
|
l = s.eval_expr(t[:i])
|
||
|
|
return l if s.is_truthy(l) else s.eval_expr(t[i+1:])
|
||
|
|
for i, x in enumerate(t):
|
||
|
|
if x == ('AN', '&&'):
|
||
|
|
l = s.eval_expr(t[:i])
|
||
|
|
return 0 if not s.is_truthy(l) else (1 if s.is_truthy(s.eval_expr(t[i+1:])) else 0)
|
||
|
|
for op in [('EQ', '=='), ('NE', '!=')]:
|
||
|
|
d = 0
|
||
|
|
for i, x in enumerate(t):
|
||
|
|
if x[0] == 'Y' and x[1] in '([{': d += 1
|
||
|
|
elif x[0] == 'Y' and x[1] in ')]}': d -= 1
|
||
|
|
if d == 0 and x == op:
|
||
|
|
l, r = s.eval_expr(t[:i]), s.eval_expr(t[i+1:])
|
||
|
|
return 1 if (l == r if op[1] == '==' else l != r) else 0
|
||
|
|
for op in [('LE', '<='), ('GE', '>='), ('Y', '<'), ('Y', '>')]:
|
||
|
|
d = 0
|
||
|
|
for i, x in enumerate(t):
|
||
|
|
if x[0] == 'Y' and x[1] in '([{': d += 1
|
||
|
|
elif x[0] == 'Y' and x[1] in ')]}': d -= 1
|
||
|
|
if d == 0 and x == op:
|
||
|
|
l, r = s.to_num(s.eval_expr(t[:i])), s.to_num(s.eval_expr(t[i+1:]))
|
||
|
|
if op[1] == '<': return 1 if l < r else 0
|
||
|
|
if op[1] == '>': return 1 if l > r else 0
|
||
|
|
if op[1] == '<=': return 1 if l <= r else 0
|
||
|
|
if op[1] == '>=': return 1 if l >= r else 0
|
||
|
|
d = 0
|
||
|
|
for i in range(len(t) - 1, -1, -1):
|
||
|
|
x = t[i]
|
||
|
|
if x[0] == 'Y' and x[1] in ')]}': d += 1
|
||
|
|
elif x[0] == 'Y' and x[1] in '([{': d -= 1
|
||
|
|
if d == 0:
|
||
|
|
if x == ('Y', '+') and i > 0:
|
||
|
|
l, r = s.eval_expr(t[:i]), s.eval_expr(t[i+1:])
|
||
|
|
if isinstance(l, str) or isinstance(r, str):
|
||
|
|
return str(l if l is not None else '') + str(r if r is not None else '')
|
||
|
|
return s.to_num(l) + s.to_num(r)
|
||
|
|
if x == ('Y', '-') and i > 0:
|
||
|
|
return s.to_num(s.eval_expr(t[:i])) - s.to_num(s.eval_expr(t[i+1:]))
|
||
|
|
d = 0
|
||
|
|
for i in range(len(t) - 1, -1, -1):
|
||
|
|
x = t[i]
|
||
|
|
if x[0] == 'Y' and x[1] in ')]}': d += 1
|
||
|
|
elif x[0] == 'Y' and x[1] in '([{': d -= 1
|
||
|
|
if d == 0:
|
||
|
|
if x == ('Y', '*') and i > 0:
|
||
|
|
return s.to_num(s.eval_expr(t[:i])) * s.to_num(s.eval_expr(t[i+1:]))
|
||
|
|
if x == ('Y', '/') and i > 0:
|
||
|
|
r = s.to_num(s.eval_expr(t[i+1:]))
|
||
|
|
return s.to_num(s.eval_expr(t[:i])) / r if r else 0
|
||
|
|
if x == ('Y', '%') and i > 0:
|
||
|
|
r = s.to_num(s.eval_expr(t[i+1:]))
|
||
|
|
return s.to_num(s.eval_expr(t[:i])) % r if r else 0
|
||
|
|
if t[0] == ('Y', '('):
|
||
|
|
d, i = 1, 1
|
||
|
|
while i < len(t) and d > 0:
|
||
|
|
if t[i] == ('Y', '('): d += 1
|
||
|
|
elif t[i] == ('Y', ')'): d -= 1
|
||
|
|
i += 1
|
||
|
|
return s.eval_expr(t[1:i-1])
|
||
|
|
if len(t) >= 2 and t[0][0] == 'I':
|
||
|
|
if t[1] == ('Y', '('): return s.eval_call(t)
|
||
|
|
if t[1] == ('Y', '.'): return s.eval_member(t)
|
||
|
|
if t[1] == ('Y', '['): return s.eval_index(t)
|
||
|
|
return None
|
||
|
|
|
||
|
|
def eval_array(s, t):
|
||
|
|
if not t or t[0] != ('Y', '{'): return []
|
||
|
|
items, i = [], 1
|
||
|
|
while i < len(t) and t[i] != ('Y', '}'):
|
||
|
|
e, i = s.parse_expr(t, i, [',', '}'])
|
||
|
|
e and items.append(s.eval_expr(e))
|
||
|
|
i < len(t) and t[i] == ('Y', ',') and (i := i + 1)
|
||
|
|
return items
|
||
|
|
|
||
|
|
def eval_new(s, t):
|
||
|
|
if not t or t[0][0] != 'I': return None
|
||
|
|
c = s.classes.get(t[0][1])
|
||
|
|
if not c: return None
|
||
|
|
o = NanoObject(c, copy.deepcopy(c.props))
|
||
|
|
a = s.parse_args(t, 1) if len(t) > 1 and t[1] == ('Y', '(') else []
|
||
|
|
c.constructor and s.call_method(o, c.constructor, a)
|
||
|
|
return o
|
||
|
|
|
||
|
|
def parse_args(s, t, st):
|
||
|
|
if st >= len(t) or t[st] != ('Y', '('): return []
|
||
|
|
a, i, d = [], st + 1, 1
|
||
|
|
while i < len(t) and d > 0:
|
||
|
|
if t[i] == ('Y', ')'):
|
||
|
|
d -= 1
|
||
|
|
if d == 0: break
|
||
|
|
i += 1; continue
|
||
|
|
if t[i] == ('Y', '('): d += 1
|
||
|
|
e, i = s.parse_expr(t, i, [',', ')'])
|
||
|
|
e and a.append(s.eval_expr(e))
|
||
|
|
i < len(t) and t[i] == ('Y', ',') and (i := i + 1)
|
||
|
|
return a
|
||
|
|
|
||
|
|
def eval_call(s, t):
|
||
|
|
n, a = t[0][1], s.parse_args(t, 1)
|
||
|
|
if n == 'print': print(*a); return
|
||
|
|
if n == 'len': return len(a[0]) if a and a[0] else 0
|
||
|
|
if n == 'str': return str(a[0]) if a and a[0] is not None else ''
|
||
|
|
if n == 'int':
|
||
|
|
if not a or a[0] is None: return 0
|
||
|
|
try: return int(float(a[0]))
|
||
|
|
except: return 0
|
||
|
|
if n == 'bool': return 1 if a and s.is_truthy(a[0]) else 0
|
||
|
|
if n == 'typeof':
|
||
|
|
if not a: return 'null'
|
||
|
|
v = a[0]
|
||
|
|
if v is None: return 'null'
|
||
|
|
if isinstance(v, int): return 'int'
|
||
|
|
if isinstance(v, float): return 'float'
|
||
|
|
if isinstance(v, str): return 'str'
|
||
|
|
if isinstance(v, list): return 'array'
|
||
|
|
if isinstance(v, NanoObject): return v._class.name
|
||
|
|
return 'unknown'
|
||
|
|
f = s.get_var(n)
|
||
|
|
if f and isinstance(f, tuple) and len(f) == 2: return s.call_func(f[0], f[1], a)
|
||
|
|
return None
|
||
|
|
|
||
|
|
def call_func(s, ps, bd, ar):
|
||
|
|
s.push_scope()
|
||
|
|
rp, va, vk = [], None, None
|
||
|
|
for p in ps:
|
||
|
|
if p.startswith('**'): vk = p[2:]
|
||
|
|
elif p.startswith('*'): va = p[1:]
|
||
|
|
else: rp.append(p)
|
||
|
|
for i, p in enumerate(rp):
|
||
|
|
if '=' in p:
|
||
|
|
pn, df = p.split('=', 1)
|
||
|
|
s.set_local(pn.strip(), ar[i] if i < len(ar) else s.eval_expr(s.tokenize(df.strip())))
|
||
|
|
else: s.set_local(p.strip(), ar[i] if i < len(ar) else None)
|
||
|
|
va and s.set_local(va, list(ar[len(rp):]))
|
||
|
|
vk and s.set_local(vk, {})
|
||
|
|
s.returning, s.return_value = False, None
|
||
|
|
s.execute_block(bd)
|
||
|
|
r = s.return_value
|
||
|
|
s.returning, s.return_value = False, None
|
||
|
|
s.pop_scope()
|
||
|
|
return r
|
||
|
|
|
||
|
|
def eval_member(s, t):
|
||
|
|
o, i = s.get_var(t[0][1]), 2
|
||
|
|
while i < len(t):
|
||
|
|
if t[i] == ('Y', '['):
|
||
|
|
e, j = s.parse_expr(t, i + 1, [']'])
|
||
|
|
idx = s.eval_expr(e)
|
||
|
|
if isinstance(o, (list, str)):
|
||
|
|
idx = int(idx) if idx is not None else 0
|
||
|
|
o = o[idx] if 0 <= idx < len(o) else None
|
||
|
|
elif isinstance(o, dict):
|
||
|
|
o = o.get(idx)
|
||
|
|
i = j + 1
|
||
|
|
continue
|
||
|
|
if t[i][0] != 'I': break
|
||
|
|
m = t[i][1]; i += 1
|
||
|
|
if i < len(t) and t[i] == ('Y', '('):
|
||
|
|
a = s.parse_args(t, i)
|
||
|
|
o = s.call_obj_method(o, m, a)
|
||
|
|
d = 1; i += 1
|
||
|
|
while i < len(t) and d > 0:
|
||
|
|
if t[i] == ('Y', '('): d += 1
|
||
|
|
elif t[i] == ('Y', ')'): d -= 1
|
||
|
|
i += 1
|
||
|
|
else:
|
||
|
|
if isinstance(o, NanoObject): o = o._props.get(m)
|
||
|
|
elif isinstance(o, dict): o = o.get(m)
|
||
|
|
elif isinstance(o, str) and m == 'length': o = len(o)
|
||
|
|
elif isinstance(o, list) and m == 'length': o = len(o)
|
||
|
|
if i < len(t) and t[i] == ('Y', '.'): i += 1
|
||
|
|
elif i < len(t) and t[i] == ('Y', '['): pass
|
||
|
|
else: break
|
||
|
|
return o
|
||
|
|
|
||
|
|
def call_obj_method(s, o, m, a):
|
||
|
|
if isinstance(o, str):
|
||
|
|
if m == 'substr': return o[int(a[0]) if a else 0:(int(a[0]) if a else 0)+(int(a[1]) if len(a)>1 else len(o))]
|
||
|
|
if m == 'split': return o.split(a[0] if a else ' ')
|
||
|
|
if m == 'count': return o.count(a[0] if a else '')
|
||
|
|
if m == 'indexOf': return o.find(a[0] if a else '')
|
||
|
|
if m == 'toUpper': return o.upper()
|
||
|
|
if m == 'toLower': return o.lower()
|
||
|
|
if m == 'trim': return o.strip()
|
||
|
|
if m == 'replace': return o.replace(a[0] if a else '', a[1] if len(a)>1 else '')
|
||
|
|
if isinstance(o, list):
|
||
|
|
if m == 'push': o.append(a[0] if a else None); return len(o)
|
||
|
|
if m == 'pop': return o.pop() if o else None
|
||
|
|
if m == 'join': return (str(a[0]) if a else '').join(str(x) for x in o)
|
||
|
|
if m == 'indexOf':
|
||
|
|
try: return o.index(a[0] if a else None)
|
||
|
|
except: return -1
|
||
|
|
if m == 'slice': return o[int(a[0]) if a else 0:int(a[1]) if len(a)>1 else len(o)]
|
||
|
|
if isinstance(o, NanoObject) and m in o._class.methods:
|
||
|
|
return s.call_method(o, o._class.methods[m], a)
|
||
|
|
return None
|
||
|
|
|
||
|
|
def call_method(s, o, md, ar):
|
||
|
|
ps, bd = md
|
||
|
|
s.push_scope()
|
||
|
|
rp, va, vk = [], None, None
|
||
|
|
for p in ps:
|
||
|
|
if p.startswith('**'): vk = p[2:]
|
||
|
|
elif p.startswith('*'): va = p[1:]
|
||
|
|
else: rp.append(p)
|
||
|
|
if rp and rp[0].strip() == 'this': s.set_local('this', o); rp = rp[1:]
|
||
|
|
for i, p in enumerate(rp):
|
||
|
|
if '=' in p:
|
||
|
|
pn, df = p.split('=', 1)
|
||
|
|
s.set_local(pn.strip(), ar[i] if i < len(ar) else s.eval_expr(s.tokenize(df.strip())))
|
||
|
|
else: s.set_local(p.strip(), ar[i] if i < len(ar) else None)
|
||
|
|
va and s.set_local(va, list(ar[len(rp):]))
|
||
|
|
vk and s.set_local(vk, {})
|
||
|
|
s.returning, s.return_value = False, None
|
||
|
|
s.execute_block(bd)
|
||
|
|
r = s.return_value
|
||
|
|
s.returning, s.return_value = False, None
|
||
|
|
s.pop_scope()
|
||
|
|
return r
|
||
|
|
|
||
|
|
def eval_index(s, t):
|
||
|
|
o = s.get_var(t[0][1])
|
||
|
|
i = 1
|
||
|
|
while i < len(t) and t[i] == ('Y', '['):
|
||
|
|
e, j = s.parse_expr(t, i + 1, [']'])
|
||
|
|
idx = s.eval_expr(e)
|
||
|
|
if isinstance(o, (list, str)):
|
||
|
|
idx = int(idx) if idx is not None else 0
|
||
|
|
o = o[idx] if 0 <= idx < len(o) else None
|
||
|
|
elif isinstance(o, dict):
|
||
|
|
o = o.get(idx)
|
||
|
|
else:
|
||
|
|
return None
|
||
|
|
i = j + 1
|
||
|
|
return o
|
||
|
|
|
||
|
|
def execute(s, c): s.execute_tokens(s.tokenize(c))
|
||
|
|
|
||
|
|
def execute_tokens(s, t):
|
||
|
|
i = 0
|
||
|
|
while i < len(t):
|
||
|
|
if s.returning: return s.return_value
|
||
|
|
if t[i] == ('CL', 'class'): i = s.parse_class(t, i)
|
||
|
|
elif t[i] == ('IF', 'if'): i = s.execute_if(t, i)
|
||
|
|
elif t[i] == ('WH', 'while'): i = s.execute_while(t, i)
|
||
|
|
elif t[i] == ('FR', 'for'): i = s.execute_for(t, i)
|
||
|
|
elif t[i] == ('RT', 'return'):
|
||
|
|
e, i = s.parse_expr(t, i + 1, [';'])
|
||
|
|
s.return_value, s.returning = s.eval_expr(e), True
|
||
|
|
return s.return_value
|
||
|
|
else:
|
||
|
|
st, i = s.parse_expr(t, i, [';'])
|
||
|
|
st and s.execute_stmt(st)
|
||
|
|
i < len(t) and t[i] == ('Y', ';') and (i := i + 1)
|
||
|
|
return None
|
||
|
|
|
||
|
|
def execute_block(s, t): return s.execute_tokens(t)
|
||
|
|
|
||
|
|
def parse_class(s, t, st):
|
||
|
|
n = t[st + 1][1]
|
||
|
|
bd, i = s.parse_block(t, st + 2)
|
||
|
|
ps, ms, ct, dt, j = {}, {}, None, None, 0
|
||
|
|
while j < len(bd):
|
||
|
|
if bd[j] == ('Y', '~') and j + 1 < len(bd):
|
||
|
|
j += 1
|
||
|
|
if bd[j][0] == 'I' and bd[j][1] == n:
|
||
|
|
j += 1
|
||
|
|
pm, j = s.parse_params(bd, j)
|
||
|
|
mb, j = s.parse_block(bd, j)
|
||
|
|
dt = (pm, mb)
|
||
|
|
elif bd[j][0] == 'I':
|
||
|
|
pn = bd[j][1]; j += 1
|
||
|
|
if j < len(bd) and bd[j] == ('Y', '('):
|
||
|
|
pm, j = s.parse_params(bd, j)
|
||
|
|
mb, j = s.parse_block(bd, j)
|
||
|
|
if pn == n: ct = (pm, mb)
|
||
|
|
else: ms[pn] = (pm, mb)
|
||
|
|
elif j < len(bd) and bd[j] == ('Y', '='):
|
||
|
|
j += 1
|
||
|
|
e, j = s.parse_expr(bd, j, [';'])
|
||
|
|
ps[pn] = s.eval_expr(e)
|
||
|
|
j < len(bd) and bd[j] == ('Y', ';') and (j := j + 1)
|
||
|
|
else:
|
||
|
|
ps[pn] = None
|
||
|
|
j < len(bd) and bd[j] == ('Y', ';') and (j := j + 1)
|
||
|
|
else: j += 1
|
||
|
|
s.classes[n] = NanoClass(n, ps, ms, ct, dt)
|
||
|
|
return i
|
||
|
|
|
||
|
|
def parse_params(s, t, st):
|
||
|
|
if st >= len(t) or t[st] != ('Y', '('): return [], st
|
||
|
|
ps, i, c, d = [], st + 1, '', 0
|
||
|
|
while i < len(t):
|
||
|
|
x = t[i]
|
||
|
|
if x == ('Y', '('): d += 1; c += x[1]
|
||
|
|
elif x == ('Y', ')'):
|
||
|
|
if d == 0: c.strip() and ps.append(c.strip()); i += 1; break
|
||
|
|
d -= 1; c += x[1]
|
||
|
|
elif x == ('Y', ',') and d == 0: c.strip() and ps.append(c.strip()); c = ''
|
||
|
|
else: c += x[1]
|
||
|
|
i += 1
|
||
|
|
return ps, i
|
||
|
|
|
||
|
|
def execute_if(s, t, st):
|
||
|
|
i = st + 1
|
||
|
|
if i >= len(t) or t[i] != ('Y', '('): return i
|
||
|
|
cd, i = s.parse_expr(t, i + 1, [')']); i += 1
|
||
|
|
bd, i = s.parse_block(t, i)
|
||
|
|
eb = []
|
||
|
|
if i < len(t) and t[i] == ('EL', 'else'):
|
||
|
|
i += 1
|
||
|
|
if i < len(t) and t[i] == ('IF', 'if'):
|
||
|
|
return s.execute_if(t, i) if not s.is_truthy(s.eval_expr(cd)) else i
|
||
|
|
eb, i = s.parse_block(t, i)
|
||
|
|
if s.is_truthy(s.eval_expr(cd)): s.execute_block(bd)
|
||
|
|
elif eb: s.execute_block(eb)
|
||
|
|
return i
|
||
|
|
|
||
|
|
def execute_while(s, t, st):
|
||
|
|
i = st + 1
|
||
|
|
if i >= len(t) or t[i] != ('Y', '('): return i
|
||
|
|
cd, ce = s.parse_expr(t, i + 1, [')'])
|
||
|
|
bd, i = s.parse_block(t, ce + 1)
|
||
|
|
while s.is_truthy(s.eval_expr(cd)):
|
||
|
|
s.execute_block(bd)
|
||
|
|
if s.returning: break
|
||
|
|
return i
|
||
|
|
|
||
|
|
def execute_for(s, t, st):
|
||
|
|
i = st + 1
|
||
|
|
if i >= len(t) or t[i] != ('Y', '('): return i
|
||
|
|
it, i = s.parse_expr(t, i + 1, [';'])
|
||
|
|
it and s.execute_stmt(it); i += 1
|
||
|
|
cd, i = s.parse_expr(t, i, [';']); i += 1
|
||
|
|
up, i = s.parse_expr(t, i, [')']); i += 1
|
||
|
|
bd, i = s.parse_block(t, i)
|
||
|
|
while s.is_truthy(s.eval_expr(cd)):
|
||
|
|
s.execute_block(bd)
|
||
|
|
if s.returning: break
|
||
|
|
up and s.execute_stmt(up)
|
||
|
|
return i
|
||
|
|
|
||
|
|
def execute_stmt(s, t):
|
||
|
|
if not t: return
|
||
|
|
for i, x in enumerate(t):
|
||
|
|
if x == ('PE', '+='):
|
||
|
|
tg, vl = t[:i], s.eval_expr(t[i+1:])
|
||
|
|
cr = s.eval_expr(tg)
|
||
|
|
nv = str(cr if cr is not None else '') + str(vl if vl is not None else '') if isinstance(cr, str) or isinstance(vl, str) else s.to_num(cr) + s.to_num(vl)
|
||
|
|
s.assign(tg, nv); return
|
||
|
|
if x == ('ME', '-='): s.assign(t[:i], s.to_num(s.eval_expr(t[:i])) - s.to_num(s.eval_expr(t[i+1:]))); return
|
||
|
|
if x == ('UE', '*='): s.assign(t[:i], s.to_num(s.eval_expr(t[:i])) * s.to_num(s.eval_expr(t[i+1:]))); return
|
||
|
|
if x == ('DE', '/='):
|
||
|
|
r = s.to_num(s.eval_expr(t[i+1:]))
|
||
|
|
s.assign(t[:i], s.to_num(s.eval_expr(t[:i])) / r if r else 0); return
|
||
|
|
if x == ('Y', '='): s.assign(t[:i], s.eval_expr(t[i+1:])); return
|
||
|
|
for i, x in enumerate(t):
|
||
|
|
if x == ('IC', '++'): tg = t[:i] if i > 0 else t[i+1:]; s.assign(tg, s.to_num(s.eval_expr(tg)) + 1); return
|
||
|
|
if x == ('DC', '--'): tg = t[:i] if i > 0 else t[i+1:]; s.assign(tg, s.to_num(s.eval_expr(tg)) - 1); return
|
||
|
|
s.eval_expr(t)
|
||
|
|
|
||
|
|
def assign(s, tg, v):
|
||
|
|
if not tg: return
|
||
|
|
if len(tg) == 1 and tg[0][0] == 'I': s.set_var(tg[0][1], v); return
|
||
|
|
if len(tg) >= 3 and tg[1] == ('Y', '.'):
|
||
|
|
o, i = s.get_var(tg[0][1]), 2
|
||
|
|
while i < len(tg) - 2:
|
||
|
|
m = tg[i][1]
|
||
|
|
if isinstance(o, NanoObject): o = o._props.get(m)
|
||
|
|
elif isinstance(o, dict): o = o.get(m)
|
||
|
|
i += 2
|
||
|
|
m = tg[i][1]
|
||
|
|
if isinstance(o, NanoObject): o._props[m] = v
|
||
|
|
elif isinstance(o, dict): o[m] = v
|
||
|
|
return
|
||
|
|
if len(tg) >= 3 and tg[1] == ('Y', '['):
|
||
|
|
o = s.get_var(tg[0][1])
|
||
|
|
e, _ = s.parse_expr(tg, 2, [']'])
|
||
|
|
idx = s.eval_expr(e)
|
||
|
|
if isinstance(o, list):
|
||
|
|
idx = int(idx) if idx is not None else 0
|
||
|
|
while len(o) <= idx: o.append(None)
|
||
|
|
o[idx] = v
|
||
|
|
elif isinstance(o, dict): o[idx] = v
|
||
|
|
return
|
||
|
|
if tg[0] == ('Y', '*'):
|
||
|
|
p = s.eval_expr(tg[1:])
|
||
|
|
isinstance(p, Pointer) and setattr(p, 'val', v)
|
||
|
|
|
||
|
|
def run_file(fn):
|
||
|
|
with open(fn) as f: Runtime().execute(f.read())
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
import sys
|
||
|
|
len(sys.argv) > 1 and run_file(sys.argv[1]) or print("Usage: python nano.py <filename>")
|