reality-engine/docs/SPECIFICATION.org

9.1 KiB
Raw Blame History

Undar (Reality Engine Language) Design parameters

What is Undar?

Undar is an permacomputing oriented programming language for 3D games with C style syntax. The compiler is written in C which should make it easy to port to other systems.

It is short for "Undarsċieppan" The name comes from the Proto-West-Germanic word Undar, which means "under" and Sċieppan meaning "to create". It inspired by the idea of "Sub-creation" from Tolkien and C.S. Lewis, that the developer is sub-creating a reality for their users, whether it be a video game, office software, a website, or a embedded driver.

Undar Grammar and Specification

Plexs

  • A plex is a Platonic form - a structured definition of a kind of being in your program.
  • Not a class: no inheritance, no vtables
  • Methods are functions with implicit this argument
  • Instances are atoms - persistent, versioned, serializable
  • Stored in the internal graph
  • "A plex defines what a thing is. An atom is its instance in that reality."
  • there are also a list of "substantial plexs" which come with the language which are the building blocks for more complex types called "Plexes". If you are coming from object oriented languages you can think of self as "primitive types"
plex «token» {
  init() {
    // values
  }
}

! example
plex Vec3 {
  init(x real, y real, z real) {
     this.x = x;
     this.y = z;
     this.y = z;
  }
}

Substantial Plexs

numeric

  • real

    • 32 bit floats
  • int

    • 32 bit integer
  • nat

    • 32 bit unsigned integer (for loop counting and indexing)

string

  • str

    • utf8 / ascii encoded string depending on the language output

normal string

"«utf8 encoded characters»"

string interpolation

"«utf8 encoded characters» ${some_var}"

binary

  • byte

    • same as uint8 or c char, also used for interop

logical

  • bool

    • true / false

datastructure

Array

Array of a specific plex

«plex»[«length»] «variable» = [val1, val2, ...];

Tunnel

described in "tunnel" section

Basic operators

The following is a list of global operators and their effect:

  • !

    • comment
  • ??

    • unwrap or
  • .?

    • null check or return error
      • addition
      • subtraction
      • negation
      • multiplication
  • /

    • divisor
  • ^

    • power
  • ==

    • equals
  • <

    • less than
  • >

    • greater than
  • >=

    • greater than or equals
  • <=

    • less than or equals
  • .

    • accessor
  • ++

    • inline add 1
    • inline subtract 1
  • +=

    • inline add n
  • -=

    • inline subtract n
  • *=

    • inline multiply n
  • \=

    • inline divide n

logical / bitwise operators

  • mod

    • modulo
  • not

    • logical not
  • and

    • logical and
  • or

    • logical or
  • xor

    • logical xor
  • band

    • bitwise and
  • bor

    • bitwise or
  • bxor

    • bitwise xor
  • srl

    • bit shift right
  • sll

    • bit shift left

keywords

let

let operator

let «token» = true;

is

checks if a atom is of that plex

if («token» is real) {
  print("hello yes self is a real?");
}

also used for letting constants

as

coerces a plex as another plex if possible

let «token» = 0; ! default is int
some_functon(«token» as real); ! needs a real

in

checks if a atom's plex, or a plex implements a contract

if («token» in Tunnel, Drawable) {
  print("im tunnel-able and draw-able");
}

also used inside of the for loops

for («token» in «collection») { «body» }

Atom

An atom is an invoked plex.

let «variable» = «plex»(«fields», …);

Tunnel

Represents a path to a file, url endpoint, other process endpoint (like a socket, etc.)

Tunnels are inspired by translators in gnu/hurd, plan9 9p protocol, and unix sockets

tunnels are invoked like atoms, but have scope like control flow end scope closes the tunnel

note the plex must always be of a plex which is "tunnel-able" i.e. Files, sockets, etc

Tunnels have almost the same interface as 9p since they are closely based on 9p.

transplexs for tunnels

tunnel? : attach(tunnel_atom) -> open communication

success? : tunnel_atom.clunk() -> close communication

success? : tunnel_atom.flush() -> cancels long operation and dumps whatever is in buffer

success? : tunnel_atom.open(resource, mode) -> opens a tunnel for doing operations on

success? : tunnel_atom.create(resource) -> creates the atom from the database graph/file from file structure

data? : tunnel_atom.read(resource) -> reads from a tunnel

success? : tunnel_atom.write(resource, data) -> writes to a tunnel

success? : tunnel_atom.remove(resource) -> removes the atom from the database graph/file from file structure

stat_data? : tunnel_atom.stat(resource) -> returns the status of the file/resource

version? : tunnel_atom.version() -> returns the version code for the connected tunnel

success? : tunnel_atom.walk(path_or_endpoint) -> moves around the filesystem or through the graph

! client 
let endpoint = Client("tcp://path/to/source");
let tunnel = endpoint.attach(user, auth);
let data = tunnel.open("/some/resource").read();
std.write(data);
data.flush();
endpoint.clunk();

! server
let server = Server("tcp://0.0.0.0:25565");
s.bind("/some/resource", fn () str {
   return "hello world";
})
server.start();

Functions

Functions are all typechecked statically at compile time. Since we always have a "default plex" for all constant values or a developer can use the as keyword we do not have to define all values like in C, while keeping the same plex safety as a more strongly typed language.

fn «token» («parameter» «plex», ...) «return_plex» {
  «body»
}
  • Built in transplexs

    • sort
    • filter
    • trig functions
    • calc functions
    • statistical functions

Control flow

loops

for («variable» in «collection») { «body» }

iterates through each atom in the collection setting it to variable

while («boolean expression») { «body» }

loops until the expression is false

do («variable» = initial_value, end_value, increment) { «body» }

loops from initial value to end value by increment value (like a for loop in other languages)

branching

if («boolean expression») {

} else if («boolean expression») {

} else {

}
switch (value) {
  case A:
  case B:
  case C:
  default:
}

Error handling

Error handling is much like in C/C++ where a try catch can be used.

let rr = nil;
let var = rr ?? 0; ! value is 0
try {
   let other_var = 1 / rr; ! will panic

} catch (e) {
   print("Caught error ${e}");
}

Localization

will look up the text of «token» in the linked localization.json file

#«token»
{
  "some_token": [
    "localization_1": ""
  ],
  "some_other_token": [
    "localization_1": "",
    "localization_2": ""
  ]
}

Libraries and "includes"

In most languages the include or use statements get libraries which link to other files and so on.

use "./some_local_file.Undar"

Testing

assertion

assert(«expression», «expected output») ! returns «error or none»

Measurements

  • types

    • time

      • unit

        • seconds (s)
      • subtypes

        • date

          • Default is ISO 8601
    • length

      • unit

        • metre (m)
      • subtypes

        • angle

          • radian (rad)
    • mass

      • unit

        • kilogram (kg)
    • electric current

      • unit

        • ampere (a)
    • temperature

      • unit

        • kelvin (K)
    • amount of substance

      • unit

        • mol (mol)
    • luminous intensity

      • unit

        • candela (candela)