Last active
June 1, 2023 03:12
-
-
Save amcgregor/a816599dc9df860f75bd to your computer and use it in GitHub Desktop.
Clueless. A metaprogramming programming language that uses itself to define itself.
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
require io | |
x = 42 | |
x = 27 | |
io.stdout.puts(x) # Guess which value will be used? | |
# Sbheglgjb. Gur vaqragrq fpbcr vf vzzrqvngryl guebja njnl. | |
if x | |
io.stdout.puts("x is truthy") | |
io.stdout.puts("continuing...") | |
else | |
io.stdout.puts("x is falsy") | |
# Ruby has def method_missing *args; args.join ' '; end | |
# We have... | |
__barewords__ = macro('invalid..') | |
" ".join(*invalid) |
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
require io | |
require functional:function | |
require sys.internals:macro | |
require sys.internals:binop | |
message = "Hello world!" | |
io.stdout.puts(message) | |
hello = function(['name']) # This is "bare", similar to macro definition. Manually constructing a new instance. | |
io.stdout.puts("Hello", name) | |
hello("Dave") | |
# Exception behaviour minimally defined in the RPython objectspace. | |
# Macro takes a code block, compiles it with the currently known macro set, | |
# registers quoted text as new tokens (if needed) and registers the production. | |
__return__ = macro('"return" expr') | |
# Return the result of evaluating the provided expression to the calling scope. | |
ReturnException(this..parent..eval(expr)).raise | |
# The production replaces the original matched bytecode with the bytecode | |
# resulting from compilation of the macro body. | |
# Some care is taken to ensure the `this` context is sane, and for overly | |
# large macro bodies it may turn into a function call. (Need to benchmark.) | |
__raise__ = macro('"raise" expr') | |
# Raise the exception produced by evaluation of the expression provided. | |
this..parent..eval(expr).raise | |
# This registers "*" as a BINOP token associated with __mul__ method calls. | |
# This is equivalent to Python's operator.__mul__ and has no "block body" unlike macro or function. | |
__mul__ = binop('*', 'mul') | |
# Because the available binary operations are unbounded, it's lame to write | |
# all of the special assignment cases individually. So don't. | |
# The special token "_" is used to tell the BNF parser that the binop token | |
# and "=" token do not allow whitespace between them. | |
macro('name binop _ "=" expr') | |
this..parent..set(name, binop.apply(this..parent..get(name), this..parent..eval(expr))) | |
# Things get weirder when you have to implement standard flow control. | |
__break__ = macro('"break"') | |
# Exit the current loop. | |
StopIteration().raise | |
__continue__ = macro('"continue"') | |
# Exit the current iteration of a loop and continue with the next iteration. | |
ContinueIteration().raise | |
# Tired of writing "if <expr1>: return <expr1>" repeatedly? So were we! | |
__success__ = macro('"success" expr') | |
# Immediately exit the current scope, returning the result of the expression if truthy. | |
result = this..parent..eval(expr) | |
if result.asBoolean | |
ReturnException(result).raise | |
__fail__ = macro('"fail" expr') | |
# Immediately exit the current scope, returning the result of the expression if falsy. | |
result = this..parent..eval(expr) | |
if not result.asBoolean | |
ReturnException(result).raise | |
# "forever" is the only built-in loop structure; from it, all others are built. | |
__for__ = macro('"for" name "in" expr ...') | |
# Repeatedly execute a contained block once for each element provided by some iterable. | |
iterator = this..parent..eval(expr).asIterator | |
set = this..child..set | |
eval = this..parent..eval | |
block = this..child..block | |
try | |
forever | |
set(name, iterator.next) | |
try | |
eval(block) | |
allow ContinueIteration | |
allow StopIteration | |
finally | |
iterator.close | |
__conditional_for__ = macro('"for" name "in" expr1 "if" expr2...') | |
# Repeatedly execute a contained block once for each matching element provided by some iterable. | |
iterator = this..parent..eval(expr).asIterator | |
set = this..child..set | |
eval = this..parent..eval | |
block = this..child..block | |
try | |
forever | |
set(name, iterator.next) | |
try | |
if this..child..eval(expr2) | |
eval(block) | |
allow ContinueIteration | |
allow StopIteration | |
finally | |
iterator.close | |
__while__ = macro('"while" expr ...') | |
# Repeatedly execute a contained block as long as the expression holds true. | |
# The condition is evaluated prior to loop body execution. | |
eval = this..parent..eval | |
block = this..child..block | |
try | |
forever | |
if not eval(expr) | |
raise StopIteration | |
try | |
eval(block) | |
allow ContinueIteration | |
allow StopIteration |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See also: https://gist.github.com/amcgregor/016098f96a687a6738a8 (WIP docs)
Additional examples (mostly macros): https://gist.github.com/amcgregor/e4114c3f3f1b71e543fb