Skip to content
Branch: master
Go to file

Latest commit


Failed to load latest commit information.
Latest commit message
Commit time
lupe @ 70bb9de

Up Language Specification



Everything is an object. Every object is also a function. Every statement is a call to a function. Every function returns a value or fails. Every value is typed.


The type of the message indicates the actions on the receiver. Types of messages:

  • type ** datatype ** literal value ** function/closure
  • metadata **
  • parameters

Each statement results in the filling of a slot in the block. The slot's resulting type determines how the slot affects the block.

Slots can be:

  • type ** provides casts
  • variable **
  • function **


Execution proceeds based on the context of the block.

Default block execution:

{ o r o r p,p,p o r p,r p,r p }


All literals are typed as expected.


Type Literals

Types are simply objects like everything else.


"Calling" a type can be thought of like a cast in other languages:

int "5"

But objects can define messages that do other things:

a int "abcd" = { int = { self.length } }


1 is sent to a

a 1

Reassign a with 2

a = 2

If a


Where a.value() is defined on any as

value: self = n

If, on the other hand, a was already defined to be a function or, more generally, a type, like

a { s int }


a 1

would become


Context is assigned left to right, By default, execution occurs right to left but can be altered by the context.

a b c

  1. a sets context within it's parent's context, in this case, Root
  2. b sets context within a's context
  3. c sets context within b's context
  4. c executes.
  5. The result of c is sent to b.
  6. b executes.
  7. The result of b is sent to a.
  8. a executes.
  9. The result of a is "returned".

Any operation with two or more parameters can be represented as infix

a b,c

Can also be written, with default infix:

c a b

or if a specifies which parameter can be moved left

b a c

Binary arithmetic operators are specified as b a c


`1 + 2

  • 1,2`

`1 + 2 + 3 + 4

  • 1,2 + 3 + 4
  • (+ 1,2),3 + 4
  • (+ (+ 1,2),3),4`


+ 1,2,3,4

Infix operators must specify precedence. Precedence is specified using 100 as highest and 0 as lowest. e.g. *,/ are 50 +,- are 25

`1 + 2 * 3 + 4

  • 1,(* 2,3) + 4
  • (+ 1,(* 2,3)),4`


+ 1,(* 2,3),4


Everything returns a value.

Send a the int message.

a int

Send int the message 4. Since int is a type, what it does with its message is to cast it to its type. So int is redundant.

a int 4

is the same as

a 4

Where int is defined as

int number 32

Where number is internally

number { [size](little_endian 32) // big endian array of little endian 32-bit values. scale little_endian 64 sign little_endian 2 }

Where little_endian is internally

little_endian [size]bit


Everything is a type. The only primitives are bit, little_endian, and big_endian and can only be used internally.

t is of type int:

t int

t is a structure with two ints, i and j:

t { i int j int }

Obtain an initialized structure of type t:

t 1,2 // returns a t where t.i is 1 and t.j is 2.


There's nothing really different between types and functions except that there are executable statements, not just variable definitions.

f { i,j int i+j*j }

The result of the function execution is, by default, the result of the last statement executed or explicitly returned.

Executing the function f:

f 1,2 // returns 5

f // returns 0

f 1 // returns 1

f j=2 // returns 4

How the above works:

  • {} produces a closure type.
  • During compilation, all uninitialized variables are presented as parameters to the closure.


Up Language




No releases published
You can’t perform that action at this time.