crates | ||
.gitignore | ||
Cargo.lock | ||
Cargo.toml | ||
README.md | ||
TYPES.md |
Walls of Flesh (programming language / RFC)
Goals
- Massive code reuse
- Macro-like language
- Minimal syntax
Syntax
[pub] [final] name ["{" args... "}"] = [cfe] {
content;
content;
etc;
retcode
};
Attributes of Code Objects
final
prevents overwriting and basically marks a rootcfe
allows an object to access the continuation and omits the default return
Early vs late binding
On-demand created code objects might need to refer to other code objects, but do
so in a manner that does splice the referenced object immediately, instead of doing
that at the logical execution point (so logically vs lexically lookup).
An $
is used to mark a reference to the surrounding lexical scope (each additional
$
then refers to the surrounding scope of that).
To postpone the execution and resolution of an adhoc code object which isn't used
as an argument, prefix the block with '
.
Control flow builtins
cflow.if, cond = ..., then = ..., else = ...
cflow.loop § ...
return ...
(implicit when last expr in a block is not terminated via semicolon)
Modules
The language should have a module system. Code objects can be either anonymous (which don't get propagated across the stack), or namespaced (which then get propagates across the stack).
Maybe: package manager
Probably not really necessary. But there should be a way to integrate the language with existing package managers. This makes it necessary to at least be able to work with package-lock files or such. Packages (packaged module trees) would then be named "prisons of flesh".
Syntactic sugar
- If a code object only takes a single argument, the argument name can be omitted.
Examples
# 1.
final main { args env } = {
std.io.writeln § "Hello World!";
0
};
# 2.
business_in_the_front = party_in_the_back;
what_now = {
self.business_in_the_front;
}, self.party_in_the_back {
std.io.writeln § "It works";
};
# running `what_now` results in "It works" being printed.
A note about tags, variants, enum
This language doesn't have that anymore (at least for now, I might reintroduce it if it becomes necessary for performance or readabilitiy reasons or such).
It originally was designed to work like the following:
produce = { tag error, kind = "smth. bad" };
consume = {
module {
error { kind } = {
# handle the errors from produce
std.io.write § "Error occured: ";
std.io.write § $kind;
};
} : produce;
};
But it should be possible without introducing a new feature with really weird type signatures...
final lambda { body } = { module { body { env } = $$body, env = $env; } };
produce = { lambda, body { env } = { env.error, kind = "smth. bad" } };
consume = {
produce.body § module {
error { kind } = {
# handle the errors from produce
std.io.write § "Error occured: ";
std.io.write § $kind;
};
};
};