Walls of Flesh programming language
Find a file
2023-12-23 22:34:02 +01:00
crates prep... 2023-12-23 22:34:02 +01:00
.gitignore add simple lexer 2023-05-19 00:46:12 +02:00
Cargo.lock prep... 2023-12-23 22:34:02 +01:00
Cargo.toml typesys: implement formatting 2023-06-18 19:48:44 +02:00
README.md remove tag+match, introduce return 2023-05-23 16:43:34 +02:00
TYPES.md types: +more explanation of problems/necessities 2023-06-18 17:31:05 +02:00

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 root
  • cfe 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;
    };
  };
};