Skip to content

Instantly share code, notes, and snippets.

/jihva.md Secret

Created December 17, 2015 04:27
Show Gist options
  • Save anonymous/799629ad2b09b8413a5c to your computer and use it in GitHub Desktop.
Save anonymous/799629ad2b09b8413a5c to your computer and use it in GitHub Desktop.

Conceptual Jihva

Macros all the way down.

Jihva is a programming language, intended to compile to JS.

Practically everything about Jihva is wrong. It is neither compiled nor interpreted. It is a stack language that uses infix notation.

Jihva is a bit like Scheme: a simple syntax, a simple interpreter, and a rich standard library.

Syntax

Everything in Jihva is represented using JSON. All objects that occur during parsing have a "kind", and most have a "val".

{ kind: "ident", val: "foo" }
{ kind: "number", val: "-3.14" }
{ kind: "block", val: [ line1, line2, line3 ] }

Syntax: Tokens

Jihva files are first parsed into a list of tokens.

"hello"       string
-3.14         number
@%            symbol
// comment
identifier

Syntax: Balanced Lines

The tokens are then parsed into "bracket-balanced lines".

e.g. the following is one balanced line, because ( holds the line open.

a b ( c
d ) f

The brackets are ( ), [ ] and { }.

Syntax: Tree

The brackets and lines form a tree.

e.g.

foo {
  bar {
    baz
  }
}

Gives the following JSON tree structure

var block3 = { kind: "block", val: [[ { kind: "ident", val: "baz" } ]] } var block2 = { kind: "block", val: [[ { kind: "ident", val: "bar" }, block3 ]] } var prog1 = [ { kind: "ident", val: "foo" }, block2 ]

Each block has two nested arrays. The first is of lines the second is is the tokens in each line.

Abstract Syntax: Modules

A module is a collection of items. That is very abstract, sorry.

mod Array {
  fn map: f {
  }
}

Here "mod Array" begins a module, and "fn map" declares an item.

You can make a new kind of item with macros, and it can have whatever syntax you want.

Abstract Syntax: void macros

void macros roughly correspond to statements. They're "void" because they don't return anything. e.g.

if x {...}
else {...}
break
continue

You can make your own, e.g.

voidmacro yield x'expr {
  ... // implement a yield statement
}

Abstract Syntax: value macros

value macros correspond to keyword operators. e.g. "typeof" in JS or "sizeof" in C. They have supreme powers over syntax, and always work in a sentence (that is, a list of tokens separated by parentheses.)

// Use:
(typeof "hello")

// Definition:
valmacro typeof x'expr {
  ... // implement a typeof macro
}

Abstract Syntax: postfix macros

If method calls could be macros, then they would be postfix macros. A postfix macro is applied at the end of a sentence.

[1, 2, 3] each |x {
  rtn x * 2
}

"each" is the macro. |x { ... } is the normal syntax for closures.

postmacro a'tight each b'expr {
  for _x in a.eval() {    // _x declares a hygienic variable, although lexical scoping means we don't really have to
    b.eval().(_x)         // we must evaluate b then apply it with .(_x)
  }
}

Abstract Syntax: the Infix Table

Jihva is a stack language, but it uses infix operators to make the proles happy.

This is done by registering operators on the infix table. A special stage then converts infix to postfix.

a + b * c + d

becomes: a b c * + d +

Infix operators are declared with

infix 1000 +      // declares an infix operator +, with precedence 1000

Abstract Syntax: Call Styles

There are 5 (yes 5!) call styles. Three are from JS, two are new for Jihva.

// JS
action(foo)       // call function action
foo.action()      // call method action
@action()         // means self.action(). self is always the lexical object, not always the function's dynamic "this"

// Native
foo action        // postfix macro
foo action()      // postfix macro, with paren arguments

Abstract Syntax: Comma Lists

For function arguments it is necessary to separate them by commas. This is a separate parsing stage:

a, b, c

becomes: { kind: "commas", val: [a, b, c] }

Abstract Syntax: =

= is the set macro.

Semantics: Runtime and Compile-time macros

Macros can either run at runtime, or compile-time.

If a line contains only compile-time macros, then the stack will be optimised out.

e.g. "dup" is a runtime macro that duplicates the top item on the stack

1 2 dup     // gives stack [1, 2, 2]

Which can be turned into an array with >array

xs = 1 2 dup ->array

// xs is [1, 2, 2]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment