Skip to content

Instantly share code, notes, and snippets.

@creationix
Last active November 8, 2019 13:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save creationix/b10caa8741774dde4921cfb2287f3d96 to your computer and use it in GitHub Desktop.
Save creationix/b10caa8741774dde4921cfb2287f3d96 to your computer and use it in GitHub Desktop.

AST driven development

Visually described as textual code when needed, but aimed as graphical code for mobile touch or spatial 3d environments.

Expressions

If-Else

The first expression type matches traditional if..else or a ? : b.

if [condition] then [action]
elif [condition] then [action]
else [action]

It's basically a list of condition expressions and action expressions that are tested in order with an optional default action.

For example, the following JS expression:

x == 10 
    ? "ten"
    : x == 20
      ? "twenty"
      : "other"

Could be encoded in the AST as follows:

(if 
  (equal x 10) "ten"
  (equal x 20) "twenty"
               "other"
)

Match-With

This replaces switch in C family languages, but makes it more flexible by allowing any expression.

match [condition-with-expression]
  with [expression] then [action]
  with [expression] then [action]
  default [action]

For example, the following JS:

let value;
switch (age) {
    case 10: value = "young"; break;
    case 20: value = "still young"; break;
    default: value = "alive"; break;
}

Could be done with the following AST:

(match (equal age)
  10 "young"
  20 "stil young"
     "alive"
)

But the partially applied expression is arbitrary.

Not sure this is a good idea, we'll let it simmer...

Maths

We'll have the basic math binary operations like +, -, /, * and %. Include bitwise operators |, &, ^, ~, etc. And logical operators &&, ||, !, etc.

But building up large expressions with these is a pain, it's too many blocks!

Visual Editing

Consider the following JS expression:

((a * b) / 2 + c * c) % 13

It's rather terse and fairly quick to type on a keyboard.

Block AST

But look how noisy it is when drawn in AST blocks! Writing expressions this way is tedious, and worse, hard to see at a glance. The disgram requires scrolling in this document or panning in AR devices.

┏━━━━━━━━━┓
┃ MODULUS ┃
┡━━━━━━━━━┹────────────────────────╮
│ ┏━━━━━┓                          │
│ ┃ ADD ┃                          │
│ ┡━━━━━┹────────────────────────╮ │
│ │ ┏━━━━━━━━┓                   │ │
│ │ ┃ DIVIDE ┃                   │ │
│ │ ┡━━━━━━━━┹─────────────────╮ │ │
│ │ │ ┏━━━━━━━━━━┓             │ │ │
│ │ │ ┃ MULTIPLY ┃             │ │ │
│ │ │ ┡━━━━━━━━━━┹───────────╮ │ │ │
│ │ │ │ ┏━━━━━━━━━━━━━━┱───╮ │ │ │ │
│ │ │ │ ┃ GET VARIABLE ┃ a │ │ │ │ │
│ │ │ │ ┗━━━━━━━━━━━━━━┹───╯ │ │ │ │
│ │ │ │ ┏━━━━━━━━━━━━━━┱───╮ │ │ │ │
│ │ │ │ ┃ GET VARIABLE ┃ b │ │ │ │ │
│ │ │ │ ┗━━━━━━━━━━━━━━┹───╯ │ │ │ │
│ │ │ ╰──────────────────────╯ │ │ │
│ │ │ ┏━━━━━━━━━┱───╮          │ │ │
│ │ │ ┃ INTEGER ┃ 2 │          │ │ │
│ │ │ ┗━━━━━━━━━┹───╯          │ │ │
│ │ ╰──────────────────────────╯ │ │
│ │ ┏━━━━━━━━━━┓                 │ │
│ │ ┃ MULTIPLY ┃                 │ │
│ │ ┡━━━━━━━━━━┹───────────╮     │ │
│ │ │ ┏━━━━━━━━━━━━━━┱───╮ │     │ │
│ │ │ ┃ GET VARIABLE ┃ c │ │     │ │
│ │ │ ┗━━━━━━━━━━━━━━┹───╯ │     │ │
│ │ │ ┏━━━━━━━━━━━━━━┱───╮ │     │ │
│ │ │ ┃ GET VARIABLE ┃ c │ │     │ │
│ │ │ ┗━━━━━━━━━━━━━━┹───╯ │     │ │
│ │ ╰──────────────────────╯     │ │
│ ╰──────────────────────────────╯ │
╰──────────────────────────────────╯

We can help some with higher abstractions like average and square, be they built-ins or user defined functions/operators.

The multiply and divide above can be abstracted to:

┏━━━━━━━━━┓
┃ AVERAGE ┃
┡━━━━━━━━━┹────────────╮
│ ┏━━━━━━━━━━━━━━┱───╮ │
│ ┃ GET VARIABLE ┃ a │ │
│ ┗━━━━━━━━━━━━━━┹───╯ │
│ ┏━━━━━━━━━━━━━━┱───╮ │
│ ┃ GET VARIABLE ┃ b │ │
│ ┗━━━━━━━━━━━━━━┹───╯ │
╰──────────────────────╯

Flowing AST

What if instead of AST blocks like this, the code was visually closer to the textual representation, but not be quite free-form text?

Let's review the JS version, but use our average and square functions:

// Include all parentheses, even optional ones for visualization.
(((avg(a, b) + sqr(c))) % 13)

We get a hint from the parentheses about the structure. What if the editor drew lines for us, but it was still in linear format? Also simple things like variables could be represented as simple cells using color or font to denote the type.

╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
│ ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮   ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮  │
│ │ ┏━━━━━━━━━┱───┬───╮ ┏┷━━━┷┓ ┏━━━━━━━━┱───╮ │ ┏┷━━━━┱────╮
│ │ ┃ AVERAGE ┃ a │ b │ ┃ ADD ┃ ┃ SQUARE ┃ c │ │ ┃ MOD ┃ 13 │
│ │ ┗━━━━━━━━━┹───┴───╯ ┗┯━━━┯┛ ┗━━━━━━━━┹───╯ │ ┗┯━━━━┹────╯
│ ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯   ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯  │
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯

But the JS version normally has less parens, can we mirror that?

(avg(a, b) + sqr(c)) % 13

This isn't too bad right?

╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
│ ┏━━━━━━━━━┱───┬───╮ ┏━━━━━┓ ┏━━━━━━━━┱───╮ ┏┷━━━━┱────╮
│ ┃ AVERAGE ┃ a │ b ┝━┫ ADD ┣━┫ SQUARE ┃ c │ ┃ MOD ┃ 13 │
│ ┗━━━━━━━━━┹───┴───╯ ┗━━━━━┛ ┗━━━━━━━━┹───╯ ┗┯━━━━┹────╯
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯

Let's try this style without the abstraction functions.

((a + b) / 2 + c * c) % 13
╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
│ ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮   ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮  │
│ │ ╭───┲━━━━━┱───╮ ┏━━━━━┱───╮ ┏┷━━━┷┓ ╭───┲━━━━━┱───╮ │ ┏┷━━━━┱────╮
│ │ │ a ┃ ADD ┃ b ┝━┫ DIV ┃ 2 │ ┃ ADD ┃ │ c ┃ MUL ┃ c │ │ ┃ MOD ┃ 13 │
│ │ ╰───┺━━━━━┹───╯ ┗━━━━━┹───╯ ┗┯━━━┯┛ ╰───┺━━━━━┹───╯ │ ┗┯━━━━┹────╯
│ ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯   ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯  │
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment