Last active
February 14, 2024 11:41
-
-
Save Nourz1234/361b006efbab7379cf87ef1981649ca8 to your computer and use it in GitHub Desktop.
Introducing new features into python! block scopes using curly braces, commas (instead of semicolons), multiline lambdas/anonymous functions, anonymous classes, "This" and "Base" keywords instead of "self" and "super", code minification, more commas, non-indentation sensitive code and more!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from madness import * | |
main = Function(lambda: { | |
# anonymous classes! | |
# notice the use of the magical keyword "This" | |
Person := Class(Object) ( | |
"Person", # Optional class name | |
__init__ = lambda name, age: { | |
This.set( | |
name = name, | |
age = age, | |
), | |
}, | |
say_hi = lambda: { | |
print(f"Hi, my name is {This.name}!") | |
}, | |
__str__ = lambda: { | |
Return(f"{type(This).__name__} - Name: {This.name} - Age: {This.age}"), | |
}, | |
), | |
person := Person(name="Jeff", age=20), | |
person.say_hi(), | |
print(person), | |
}) | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from madness import * | |
main = Function(lambda: { | |
# inheritance: | |
# notice the use of the magical keyword "Base" | |
A := Class() ( | |
foo = lambda x: { | |
print("A"), | |
Return(x / 2), | |
}, | |
), | |
B := Class(A) ( | |
foo = lambda x: { | |
print("B"), | |
Return(Base.foo(x) + 1), | |
}, | |
), | |
C := Class(B) ( | |
foo = lambda x: { | |
print("C"), | |
Return(Base.foo(x) * 2), | |
}, | |
), | |
c := C(), | |
print(c.foo(2)), | |
}) | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ast | |
import importlib | |
import importlib.util | |
import inspect | |
import sys | |
from importlib.abc import SourceLoader | |
from importlib.machinery import FileFinder | |
def make_everything_nonlocal( | |
node: ast.Module | ast.FunctionDef | ast.ClassDef, | |
incl_globals=False, | |
_globals: list[str] = [], | |
_nonlocals: list[str] = [], | |
) -> ast.Module | ast.FunctionDef | ast.ClassDef: | |
st = ScopeTransformer(node) | |
node = st.process_scope() | |
globals = _globals.copy() | |
nonlocals = _nonlocals.copy() | |
if isinstance(node, ast.Module): | |
if incl_globals: | |
globals = list(set(globals + st.locales)) | |
elif isinstance(node, ast.ClassDef): | |
pass | |
else: | |
nonlocals = list(set(nonlocals + st.locales)) | |
for func_def in st.func_defs: | |
if globals: | |
func_def.body.insert(0, ast.Global(names=globals)) | |
if nonlocals: | |
func_def.body.insert(0, ast.Nonlocal(names=nonlocals)) | |
# print(f"func: {func_def.name} globals: {globals} nonlocals: {nonlocals}") | |
func_def = make_everything_nonlocal( | |
func_def, incl_globals, _globals=globals, _nonlocals=nonlocals | |
) | |
for class_def in st.class_defs: | |
class_def = make_everything_nonlocal( | |
class_def, incl_globals, _globals=globals, _nonlocals=nonlocals | |
) | |
return node | |
class ScopeTransformer(ast.NodeTransformer): | |
""" | |
gets a list of functions and classes and variable names | |
that are direct children of the current scope. | |
lambdas get converted to function defs. | |
""" | |
def __init__(self, scope: ast.Module | ast.FunctionDef | ast.ClassDef) -> None: | |
super().__init__() | |
self._lambdas: list[ast.FunctionDef] = [] | |
self.func_defs: list[ast.FunctionDef] = [] | |
self.class_defs: list[ast.ClassDef] = [] | |
self.locales: list[str] = [] | |
self.scope = scope | |
def process_scope(self): | |
scope = self.visit(self.scope) | |
scope.body[0:0] = self._lambdas | |
return scope | |
def visit_ClassDef(self, node: ast.ClassDef): | |
if self.scope == node: | |
return self.generic_visit(node) | |
self.class_defs.append(node) | |
self.locales.append(node.name) | |
return node | |
def visit_FunctionDef(self, node: ast.FunctionDef): | |
if self.scope == node: | |
return self.generic_visit(node) | |
self.func_defs.append(node) | |
self.locales.append(node.name) | |
return node | |
def visit_Lambda(self, node: ast.Lambda): | |
func_def = self.lambda_to_func(node) | |
self._lambdas.append(func_def) | |
self.func_defs.append(func_def) | |
return ast.Name(id=func_def.name, ctx=ast.Load()) | |
def visit_NamedExpr(self, node: ast.NamedExpr): | |
self.locales.append(node.target.id) | |
return self.generic_visit(node) | |
def visit_Assign(self, node: ast.Assign): | |
nv = NameVisitor() | |
for target in node.targets: | |
nv.visit(target) | |
self.locales.extend(nv.names) | |
return self.generic_visit(node) | |
@staticmethod | |
def lambda_to_func(node: ast.Lambda) -> ast.FunctionDef: | |
return ast.FunctionDef( | |
name=ScopeTransformer.generate_unique_name(), | |
args=node.args, | |
body=[ast.Return(value=node.body)], | |
decorator_list=[], | |
) | |
_counter = 0 | |
@staticmethod | |
def generate_unique_name() -> str: | |
""" | |
attempting to generate names that wont conflict with any naming style | |
but knowing devs, someone out there uses numbers prefixed with triple underscores as variable names. | |
""" | |
ScopeTransformer._counter += 1 | |
return f"___{ScopeTransformer._counter}" | |
class NameVisitor(ast.NodeVisitor): | |
def __init__(self) -> None: | |
super().__init__() | |
self.names: list[str] = [] | |
def visit_Name(self, node: ast.Name): | |
self.names.append(node.id) | |
class WhileFixer(ast.NodeTransformer): | |
def visit_Call(self, node: ast.Call): | |
if isinstance(node.func, ast.Name): | |
if node.func.id == "While" and len(node.args) == 1: | |
node.args = [ | |
ast.Lambda( | |
args=ast.arguments( | |
posonlyargs=[], | |
args=[], | |
kwonlyargs=[], | |
kw_defaults=[], | |
defaults=[], | |
), | |
body=node.args[0], | |
) | |
] | |
return self.generic_visit(node) | |
class InitCallRemover(ast.NodeTransformer): | |
def visit_Call(self, node: ast.Call): | |
if isinstance(node.func, ast.Name): | |
if node.func.id == init_experimental_stuff.__name__: | |
return ast.Constant(value=0) | |
return node | |
class ExperimentalStuffLoader(SourceLoader): | |
def __init__(self, fullname, path): | |
self.fullname = fullname | |
self.path = path | |
def get_filename(self, fullname): | |
return self.path | |
def get_data(self, filename): | |
with open(filename) as f: | |
data = f.read() | |
return data | |
@staticmethod | |
def source_to_code(data: str, path: str = "<string>"): | |
tree: ast.Module = ast.parse(data) | |
tree = InitCallRemover().visit(tree) | |
tree = WhileFixer().visit(tree) | |
tree = make_everything_nonlocal(tree) | |
tree = ast.fix_missing_locations(tree) | |
return compile(tree, path, "exec", dont_inherit=True) | |
def init_experimental_stuff(): | |
# install the loader | |
loader_details = ExperimentalStuffLoader, [".py"] | |
sys.path_hooks.insert(0, FileFinder.path_hook(loader_details)) | |
sys.path_importer_cache.clear() | |
importlib.invalidate_caches() | |
# import the calling file | |
frame_info = inspect.stack()[1] | |
filename = frame_info.filename | |
mod_name = frame_info.frame.f_globals["__name__"] | |
if mod_name != "__main__": | |
raise Exception("Must call from __main__") | |
spec = importlib.util.spec_from_loader( | |
mod_name, ExperimentalStuffLoader(mod_name, filename) | |
) | |
module = importlib.util.module_from_spec(spec) | |
sys.modules[mod_name] = module | |
spec.loader.exec_module(module) | |
# using '__builtins__' instead of directly calling 'quit' | |
# so that the IDE does not complain about unreachable code | |
__builtins__["quit"]() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from experimental_stuff import init_experimental_stuff | |
from madness import * | |
# should be at the very top, even before other imports! | |
init_experimental_stuff() | |
# what this line does is: | |
# 1- Make all variables nonlocal | |
# 2- Wrap anything passed to "While" in a lambda | |
# don't ask how it works, it's magic! | |
main = Function(lambda: { | |
counter := 0, | |
While(counter < 3) (lambda: { | |
print(counter), | |
counter := counter + 1, | |
}), | |
print(counter), | |
foo(), | |
}) | |
# works with normal functions and methods as well. | |
def foo(): | |
var = "foo" | |
def bar(): | |
var += "bar" | |
def baz(): | |
var += "baz" | |
baz() | |
bar() | |
print(var) | |
main() | |
# Li0uLi0uIC4uIC0gLyAuLiAuLi4gLyAtLS0gLS4gLi0uLiAtLi0tIC8gLS0uIC0tLSAtLS0gLS4uIC0uIC4gLi4uIC4uLiAvIC4tLSAuLi4uIC4uIC0uLS4gLi4uLiAvIC0tLiAuLiAuLi4tIC4gLi4uIC8gLiAtLi4tIC0gLi0uIC4tIC4uLiAuLS4uLS4= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from random import randint | |
from madness import * | |
main = Function (lambda: { | |
number := randint(1, 10), | |
print("Guess a number between 1 and 10"), | |
While (True) (lambda: { | |
# since we can't mutate non-local vars | |
# we create an object and mutate its properties instead | |
guess := Object(), | |
guess.set(value = input("Your guess: ")), | |
Try (lambda: { | |
guess.set(value = int(guess.value)), | |
}) | |
.Except(ValueError) (lambda err: { | |
print("Not a valid number."), | |
Continue(), | |
}), | |
If (guess.value < 1 or guess.value > 10) (lambda: { | |
print("Number must be between 1 and 10."), | |
Continue(), | |
}), | |
If (guess.value == number) (lambda: { | |
print("Correct!"), | |
Break(), | |
}) | |
.Else (lambda: { | |
print(f"Incorrect."), | |
}), | |
}), | |
}) | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from madness import * | |
(is_even:=Function(lambda x:{negative:=True if x < 0 else False,vars:=Object(),vars.set(even=True),vars.set(y=0),While(True)(lambda:{If(vars.y == x)(lambda:{Return(vars.even),}),vars.set(y=vars.y+(-1 if negative else 1)),vars.set(even=not vars.even),}),}),main:=Function (lambda:{number:=input("Input a number: "),If(is_even(int(number)))(lambda:{print("Number is even!"),}).Else (lambda:{print("Number is odd!"),}),}),main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from madness import * | |
is_even = Function (lambda x: { | |
negative := True if x < 0 else False, | |
vars := Object(), | |
vars.set(even = True), | |
vars.set(y = 0), | |
While (True) (lambda: { | |
If (vars.y == x) (lambda: { | |
Return(vars.even), | |
}), | |
vars.set(y = vars.y + (-1 if negative else 1)), | |
vars.set(even = not vars.even), | |
}), | |
}) | |
main = Function (lambda: { | |
# don't input large numbers, your pc will burn! | |
number := input("Input a number: "), | |
If (is_even(int(number))) (lambda: { | |
print("Number is even!"), | |
}) | |
.Else (lambda: { | |
print("Number is odd!"), | |
}), | |
}) | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Any, Callable, Generic, Iterable, Optional, Type, TypeVar | |
T = TypeVar("T") | |
# just so the IDE doesn't complain about undefined variables | |
This = None | |
Base = None | |
class Object: | |
def set(self, **kwargs): | |
self.__dict__.update(**kwargs) | |
class If: | |
def __init__(self, condition: bool, /): | |
self.condition = condition | |
self.done = False | |
def __call__(self, func: Callable[[], None], /): | |
if not self.done and self.condition: | |
func() | |
self.done = True | |
return self | |
def Elif(self, condition: bool, /): | |
self.condition = condition | |
return self | |
def Else(self, func: Callable[[], None], /): | |
if not self.done: | |
func() | |
class For(Generic[T]): | |
def __init__(self, iter: Iterable[T], /): | |
self.iter = iter | |
def __call__(self, func: Callable[[T], None], /): | |
for item in self.iter: | |
try: | |
func(item) | |
except Continue: | |
continue | |
except Break: | |
break | |
class While: | |
def __init__(self, condition: bool | Callable[[], bool], /): | |
if isinstance(condition, Callable): | |
self.condition = condition | |
else: | |
self.condition = lambda: condition | |
def __call__(self, func: Callable[[], None], /): | |
while self.condition(): | |
try: | |
func() | |
except Continue: | |
continue | |
except Break: | |
break | |
class Try: | |
def __init__(self, func: Callable[[], None], /): | |
self.err = None | |
try: | |
func() | |
except Exception as err: | |
self.err = err | |
def Except(self, exception: Type[T] = Exception, /, *exceptions): | |
def _handler(func: Callable[[T], None]): | |
if self.err and isinstance(self.err, (exception,) + exceptions): | |
func(self.err) | |
return self | |
return _handler | |
class With: | |
def __init__(self, ctx_mgr, /, *ctx_mgrs): | |
self.ctx_mgrs = (ctx_mgr,) + ctx_mgrs | |
def __call__(self, func): | |
self._With(*self.ctx_mgrs, ctx_items=[], func=func) | |
def _With(self, ctx_mgr, /, *ctx_mgrs, ctx_items: list, func): | |
with ctx_mgr as ctx_item: | |
ctx_items.append(ctx_item) | |
if ctx_mgrs: | |
self._With(*ctx_mgrs, ctx_items=ctx_items, func=func) | |
else: | |
func(*ctx_items) | |
class Function: | |
def __init__(self, func): | |
self.func = func | |
def __call__(self, *args, **kwargs): | |
try: | |
self.func(*args, **kwargs) | |
return None | |
except Return as err: | |
return err.value | |
class ClassType(type): | |
def __setattr__(cls, name, value): | |
if isinstance(value, Callable): | |
value = cls._wrap_method(value) | |
return super().__setattr__(name, value) | |
def _wrap_method(cls, method): | |
def wrapped(self, *args, **kwargs): | |
method.__globals__["This"] = self | |
method.__globals__["Base"] = super(cls, self) | |
try: | |
method(*args, **kwargs) | |
return None | |
except Return as err: | |
return err.value | |
return wrapped | |
class Class: | |
def __init__(self, *bases): | |
self.bases = bases | |
def __call__(self, name="<class>", /, **members): | |
cls = ClassType(name, self.bases, {}) | |
for key, val in members.items(): | |
setattr(cls, key, val) | |
return cls | |
class FlowException(Exception): | |
def __init__(self): | |
raise self | |
class Return(FlowException): | |
def __init__(self, value: Any = None, /): | |
self.value = value | |
super().__init__() | |
class Continue(FlowException): | |
pass | |
class Break(FlowException): | |
pass | |
class Raise: | |
def __init__(self, exception: Optional[Exception] = None, /): | |
if exception is None: | |
raise | |
else: | |
raise exception |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from madness import * | |
main = Function(lambda: { | |
With (open("./foo.txt", "w")) (lambda file: { | |
file.write("bar"), | |
}), | |
With (open("./foo.txt", "r")) (lambda file: { | |
print(f"file content: {file.read()}"), | |
}), | |
}) | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from madness import * | |
# "unexpected indent"? what is that? | |
do_stuff = Function (lambda: { | |
x := 10, | |
y := 20, | |
z := 30, | |
xyz := x + y + z, | |
Return(xyz), | |
}) | |
print(do_stuff()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment