zongors-universe-machine/docs/SPECIFICATION.org

9.4 KiB

ZTL (Zongors Transpiler Language) Design parameters

What is ztl?

ztl is an language transpiler with C/Lua style syntax. The transpiler bootstrap is written in Lua which should make it easy to port to other systems. ztl also can "run" standalone inside of a lua vm for debugging purposes, it could be used for small scripting tasks or the like.

ZTL Grammar and Specification

Types

  • there are also a list of "substantial types" which come with the language which are the building blocks for more complex types. If you are coming from object oriented languages you can think of self as "primitive types"
type «token» {
  init() {
    // values
  }
}

Basic Types

numeric

  • byte

    • unsigned 8 bit integer (uint8_t)
  • number

    • 64 bit floating point (double)

string

  • str

    • utf8 / ascii encoded string depending on the language output

normal string

"«utf8 encoded characters»"

string interpolation

"«utf8 encoded characters» ${some_var}"

logical

bool

true / false

Also follows the style boolean 'c' rules of nonzero / zero, but the compiler will make fun of you

error

error is a type which describes an error that occurred, it is similar to the Go programming language and is returned as a monad like the maybe monad above and is unwrapped in a similar way. You could also think of it as every variable being able to have "the type" and also "error" as a possible value.

let rr = err("something borked");
let var = rr ?? 0; // value is 0
let other_var = rr ?? panic(rr); // will panic

datastructure

Much like Lua, zwl only has tables. Lua's tables are amazing and very unique. Why have five different datastructures to do things when you can just have one that does everything?

Types that can be indexes are numbers and strings (no objects);

table

syntax (yes I was nice and kept the syntax the same as most C like langs)

// array same as a map of int to «type»
let «variable» = [val1, val2, ...];

// or as a map
let «variable» = {key1: val1, key2: val2, ...};

tunnel

described in "tunnel" section

Basic operators

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

  • //

    • comment
  • ??

    • unwrap or
  • +

    • addition
  • -

    • subtraction
    • negation
  • *

    • multiplication
  • /

    • divisor
  • **

    • power
  • ==

    • equals
  • <

    • less than
  • >

    • greater than
  • >=

    • greater than or equals
  • <=

    • less than or equals
  • |>

    • curry a function into another function (like haskell shove)
  • .

    • accessor
  • ++

    • inline add 1
  • --

    • inline subtract 1
  • +=

    • inline add n
  • -=

    • inline subtract n
  • *=

    • inline multiply n
  • \=

    • inline divide n
  • **=

    • inline power n

logical / bitwise operators

  • mod

    • modulo
  • 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» = 0;

is

checks if a object is of that type

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

also used for letting constants

as

coerces a type as another type if possible

let «token» = 0; // default is i32
some_functon(«token» as i8); // needs an i8

in

checks if a object's type, or a type impls another type

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

also used inside of the for loops

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

Object

An object is an invoked type.

let «variable» = «type»(«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 objects, but have scope like control flow end scope closes the tunnel

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

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

transtypes for tunnels

tunnel? : attach(tunnel_object) -> open communication

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

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

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

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

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

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

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

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

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

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

let endpoint = Tunnel("protocol://path/to/source");
let tunnel = endpoint.attach(user, auth);
let data = tunnel.open("/some/resource").read();
std.write(data); //print(data);
data.flush();
endpoint.clunk();

Functions

Functions are all typechecked statically at compile time. Since we always have a "default type" 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 type safety as a more strongly typed language.

fn «token» («parameter» «type», ...) «return_type» {
  «body»
}
  • Built in transtypes

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

Control flow

loops

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

iterates through each object in the collection setting it to token

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

loops until the expression is false

loop { «body» }

loops infinitely until break or return

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

loops from initial value to end value by increment value

branching

if («boolean expression») {

} else if («boolean expression») {

} else {

}

exceptions

take a look at error's, but you can panic on an error like self:

panic(err("error message"));
panic(err(3));
panic(«some_error_token»);

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. Self quickly gets confusing and so requires package managers and installers, etc. The other way to do self would be to just specifically "name" the paths using a tunnel and import it. You can even use localization tokens to create config files. Since everything is lazily compiled jit anyways it (in theory) doesn't hurt pertypeance much

use "https://git.alfrescocavern.com/some_library/some_file.ztl"
use "./some_local_file.ztl"

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)