rearranged Python part
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# Build and distribution artifacts
|
||||
build/
|
||||
dist/
|
||||
*.egg-info/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Dynamically copied files at build time
|
||||
README.md
|
||||
clyx/*.clx
|
||||
@@ -0,0 +1 @@
|
||||
from .clyx import Clyx, repl, main
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python3
|
||||
# Clyx programming language interpreter, reference core implementation
|
||||
# Created by Luxferre in 2026, released into the public domain
|
||||
|
||||
import os, sys, math
|
||||
from random import randrange
|
||||
|
||||
# T-DeckARD compatible socket/input initialization
|
||||
try: import socket
|
||||
except: from deck.net import init_socket; from deck.input import input; socket = init_socket()
|
||||
|
||||
scriptdir = __file__.replace('\\', '/').rsplit('/', 1)[0] if ('/' in __file__ or '\\' in __file__) else '.'
|
||||
def _fpath(p1, p2):
|
||||
try: open(p1).close(); return p1
|
||||
except: return p2
|
||||
libpath = _fpath(f'{scriptdir}/lib.clx', f'{scriptdir}/../../lib.clx')
|
||||
replpath = _fpath(f'{scriptdir}/clyx_repl.clx', f'{scriptdir}/../../clyx_repl.clx')
|
||||
|
||||
|
||||
class Sock:
|
||||
def __init__(self, s): self.s = s
|
||||
def write(self, d): return self.s.write(d) if hasattr(self.s, 'write') else self.send(d.encode('utf-8') if isinstance(d, str) else d)
|
||||
def send(self, d): return self.s.send(d) if hasattr(self.s, 'send') else getattr(self.s, 'write', lambda *a: 0)(d)
|
||||
def recv(self, n):
|
||||
if hasattr(self.s, 'recv'): return self.s.recv(n)
|
||||
b = bytearray(n); return bytes(b[:self.s.recv_into(b)]) if hasattr(self.s, 'recv_into') else getattr(self.s, 'read', lambda *a: b'')(n)
|
||||
def readline(self):
|
||||
if hasattr(self.s, 'readline'): return self.s.readline()
|
||||
res = b''
|
||||
while not res.endswith(b'\n'):
|
||||
c = self.recv(1)
|
||||
if not c: break
|
||||
res += c
|
||||
return res.decode('utf-8')
|
||||
def close(self): return self.s.close()
|
||||
def flush(self):
|
||||
try: getattr(self.s, 'flush', lambda: None)()
|
||||
except: pass
|
||||
|
||||
class Clyx:
|
||||
def __init__(self, libfname = None, in_str=None, out_num=None, out_char=None):
|
||||
def default_in():
|
||||
try: return input()
|
||||
except: return 'exit'
|
||||
self._in_str, self._out_num, self._out_char = in_str or default_in, out_num or (lambda v: (sys.stdout.write(str(v)+'\n'), getattr(sys.stdout, 'flush', lambda: None)())), out_char or (lambda v: (sys.stdout.write(chr(int(v))), getattr(sys.stdout, 'flush', lambda: None)()))
|
||||
self._stack, self._tokens, self._token_streams = [], [], []
|
||||
self._words = {
|
||||
'dup': lambda: self._stack.append(self._stack[-1]), 'drop': lambda: self._stack.pop(), 'swap': lambda: self._stack.extend([self._stack.pop(), self._stack.pop()]), 'i': lambda: self._eval(self._stack.pop()),
|
||||
'cond': lambda: (lambda c, t, f: self._exec_quot(t if c else f))(self._stack.pop(), self._stack.pop(), self._stack.pop()), 'cons': lambda: (lambda q: self._stack.append([self._stack.pop()] + q))(self._stack.pop()),
|
||||
'uncons': lambda: (lambda q: (lambda l: self._stack.extend([l, 0] if not l else [l[1:], l[0], 1]))(list(map(ord, q)) if isinstance(q, str) else q))(self._stack.pop()), 'qpop': lambda: (lambda q: self._stack.extend([q[:-1], q[-1]]))(self._stack.pop()),
|
||||
'qlen': lambda: (lambda v: self._stack.append(len(v) if isinstance(v, list) else 0))(self._stack.pop()), 'qget': lambda: (lambda i,v: self._stack.append(v[i] if isinstance(v, list) else None))(self._stack.pop(), self._stack.pop()),
|
||||
'qset': self._cmd_qset, 'slen': lambda: (lambda v: self._stack.append(len(v) if isinstance(v, str) else 0))(self._stack.pop()),
|
||||
'+': lambda: self._stack.append(self._stack.pop() + self._stack.pop()), '*': lambda: self._stack.append(self._stack.pop() * self._stack.pop()), '-': lambda: (lambda y: self._stack.append(self._stack.pop() - y))(self._stack.pop()), '/': lambda: (lambda y: self._stack.append(self._stack.pop() / y))(self._stack.pop()),
|
||||
'divmod': lambda: (lambda y: (lambda x: self._stack.extend(divmod(x, y)))(self._stack.pop()))(self._stack.pop()), 'shl': lambda: (lambda f, x: self._stack.append(x << f if f >= 0 else x >> -f))(self._stack.pop(), self._stack.pop()), '^': lambda: (lambda y: self._stack.append(self._stack.pop() ** y))(self._stack.pop()),
|
||||
'0=': lambda: self._stack.append(1 if self._stack.pop() == 0 else 0), '0<': lambda: self._stack.append(1 if self._stack.pop() < 0 else 0), 'nand': lambda: self._stack.append(~(self._stack.pop() & self._stack.pop())), 'defw': self._cmd_defw, 'type': lambda: self._stack.append(2 if isinstance(self._stack[-1], list) else (1 if isinstance(self._stack[-1], str) else 0)),
|
||||
'next': lambda: self._stack.append(self._pop_caller_token()), '.': lambda: self._out_num(self._stack.pop()), 'emit': lambda: self._out_char(self._stack.pop()),
|
||||
'fopen': lambda: (lambda m, f: self._stack.append(type('FD0', (), {'readline': lambda s: self._in_str() + '\n', 'read': lambda s: self._in_str(), 'fileno': lambda s: 0})() if f in (0, '0') else open(f, m)))(self._stack.pop(), self._stack.pop()),
|
||||
'nopen': lambda: (lambda p, h: (lambda s: (lambda addr: (s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if hasattr(s, 'setsockopt') else None, s.bind(addr) if h == '0.0.0.0' else s.connect(addr), s.listen(1) if h == '0.0.0.0' else None, self._stack.append(s if h == '0.0.0.0' else Sock(getattr(s, 'makefile', lambda *a: s)('rw'))))[3])(socket.getaddrinfo(h, int(p))[0][-1] if hasattr(socket, 'getaddrinfo') else (h, int(p))))(socket.socket()))(self._stack.pop(), self._stack.pop()),
|
||||
'write': lambda: (lambda d, fd: (self._stack.append(fd.write(d)), self._flush(fd)))(self._stack.pop(), self._stack.pop()),
|
||||
'read': lambda: (lambda fd: self._stack.append((lambda c: Sock(getattr(c, 'makefile', lambda *a: c)('rw')))(fd.accept()[0]) if hasattr(fd, 'accept') else (lambda r: r.rstrip(b'\r\n' if isinstance(r, bytes) else '\r\n'))(fd.readline() if (fd is sys.stdin or fd.__class__.__name__ in ('FD0', 'Sock')) else fd.read())))(self._stack.pop()),
|
||||
'close': lambda: (lambda fd: fd.close() if not (fd in (sys.stdin, sys.stdout, sys.stderr) or fd.__class__.__name__ == 'FD0') else None)(self._stack.pop()),
|
||||
'delf': lambda: os.remove(self._stack.pop()), 'maked': lambda: os.mkdir(self._stack.pop()), 'listd': lambda: self._stack.append(os.listdir(self._stack.pop())), 'deld': lambda: os.rmdir(self._stack.pop()),
|
||||
'rand': lambda: self._stack.append(randrange(int(self._stack.pop()))), '.s': lambda: self._out_num(repr(self._stack)), 'dip': lambda: (lambda q, y: (self._exec_quot(q), self._stack.append(y)))(self._stack.pop(), self._stack.pop()),
|
||||
'loop': lambda: (lambda body, cond: self._exec_loop(cond, body))(self._stack.pop(), self._stack.pop()),
|
||||
'chr': lambda: self._stack.append(chr(int(self._stack.pop()))), 'asc': lambda: self._stack.append(ord(self._stack.pop())),
|
||||
'sin': lambda: self._stack.append(math.sin(float(self._stack.pop()))), 'cos': lambda: self._stack.append(math.cos(float(self._stack.pop()))), 'atan': lambda: self._stack.append(math.atan(float(self._stack.pop()))),
|
||||
'exp': lambda: self._stack.append(math.exp(float(self._stack.pop()))), 'log': lambda: self._stack.append(math.log(float(self._stack.pop())))
|
||||
}
|
||||
self.run('"::" [ next defw ] defw :: readf [ "r" fopen dup read swap close ] :: src [ readf i ]')
|
||||
self.run(f'"{libpath}" src' if libfname is None else (libfname + ' src'))
|
||||
|
||||
def _cmd_qset(self): i, v, x = self._stack.pop(), self._stack.pop(), self._stack.pop(); (v.pop(int(i)), v.insert(int(i), x)) if isinstance(v, list) else None; self._stack.append(v if isinstance(v, list) else None)
|
||||
def _exec_loop(self, c, b):
|
||||
while (self._exec_quot(c), self._stack.pop())[1]: self._exec_quot(b)
|
||||
_pop_caller_token = lambda self: (lambda t: (t.pop(0) if t[0] != '[' else self._parse_quot((t.pop(0), t)[1])) if t else None)(self._token_streams[-1] if self._token_streams else self._tokens)
|
||||
def _cmd_defw(self): t = self._token_streams[-1] if self._token_streams else self._tokens; val = self._pop_caller_token() if (t and (t[0] == '[' or isinstance(t[0], list))) else self._stack.pop(); self._words[self._stack.pop()] = val
|
||||
|
||||
def _tokenize(self, code):
|
||||
tokens = []
|
||||
for l in code.replace('\\\\', '\x01').replace('\\"', '\x02').split('\n'):
|
||||
for i, p in enumerate(l.split('"')):
|
||||
if i % 2: tokens.append('"' + p.replace('\x02', '"').replace('\x01', '\\') + '"')
|
||||
elif tokens.extend(p.split('#')[0].replace('[', ' [ ').replace(']', ' ] ').split()) or '#' in p: break
|
||||
return tokens
|
||||
|
||||
_next_token = lambda self: self._tokens.pop(0) if self._tokens else None
|
||||
|
||||
def _parse_quot(self, tokens=None):
|
||||
tokens, quot = self._tokens if tokens is None else tokens, []
|
||||
try:
|
||||
while True:
|
||||
t = tokens.pop(0)
|
||||
if t == ']': return quot
|
||||
quot.append(self._parse_quot(tokens) if t == '[' else self._norm_token(t))
|
||||
except IndexError: raise SyntaxError('Syntax error: unbalanced brackets')
|
||||
|
||||
def _norm_token(self, t):
|
||||
try: return float(t.strip()) if ('.' in t and t != '.') else int(t.strip())
|
||||
except: return t[1:-1].replace('\\\\', '\x01').replace('\\n', '\n').replace('\\t', '\t').replace('\\r', '\r').replace('\\s', ' ').replace('\\b', '\b').replace('\\f', '\f').replace('\\"', '"').replace('\x01', '\\') if (t.startswith('"') and t.endswith('"')) else t
|
||||
_flush = lambda self, fd: getattr(fd, 'flush', lambda: None)()
|
||||
|
||||
def _exec_quot(self, q):
|
||||
self._token_streams.append(self._tokens); self._tokens = list(q)
|
||||
while self._tokens:
|
||||
t = self._next_token()
|
||||
if isinstance(t, list): self._stack.append(t)
|
||||
elif t == '[': self._stack.append(self._parse_quot(self._tokens))
|
||||
else:
|
||||
t = self._norm_token(t) if isinstance(t, str) else t
|
||||
v = self._words.get(t) if isinstance(t, str) else None
|
||||
if callable(v): v()
|
||||
elif isinstance(v, list): self._exec_quot(v)
|
||||
elif v is not None: self._stack.append(v)
|
||||
else: self._stack.append(t)
|
||||
self._tokens = self._token_streams.pop()
|
||||
|
||||
def _eval(self, q):
|
||||
try: self._exec_quot(self._tokenize(q) if isinstance(q, str) else q)
|
||||
except Exception as e: sys.stderr.write(f'Error: {e}\n')
|
||||
run = lambda self, code: self._exec_quot(self._tokenize(code))
|
||||
|
||||
def clyx(f):
|
||||
try: Clyx().run(open(f).read())
|
||||
except Exception as e: (sys.stderr.write(f'Error executing {f}: {e}\n'), sys.exit(1))
|
||||
|
||||
repl = lambda: clyx(replpath)
|
||||
def main(): clyx(sys.argv[1] if len(sys.argv) > 1 else replpath)
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
@@ -0,0 +1,25 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=61.0.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "clyx"
|
||||
version = "0.1.0"
|
||||
description = "Clyx programming language interpreter"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.7"
|
||||
license = { text = "Public Domain" }
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: Public Domain",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
clyx = "clyx:main"
|
||||
|
||||
[tool.setuptools]
|
||||
packages = ["clyx"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
clyx = ["*.clx"]
|
||||
@@ -0,0 +1,19 @@
|
||||
import os
|
||||
import shutil
|
||||
from setuptools import setup
|
||||
|
||||
pkg_dir = os.path.join(os.path.dirname(__file__), "clyx")
|
||||
parent_dir = os.path.join(os.path.dirname(__file__), "..")
|
||||
|
||||
for fname in ["lib.clx", "clyx_repl.clx"]:
|
||||
src = os.path.join(parent_dir, fname)
|
||||
dst = os.path.join(pkg_dir, fname)
|
||||
if os.path.exists(src):
|
||||
shutil.copy(src, dst)
|
||||
|
||||
readme_src = os.path.join(parent_dir, "README.md")
|
||||
readme_dst = os.path.join(os.path.dirname(__file__), "README.md")
|
||||
if os.path.exists(readme_src):
|
||||
shutil.copy(readme_src, readme_dst)
|
||||
|
||||
setup()
|
||||
Reference in New Issue
Block a user