8.7 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 «type_token» {
! values
}
Substantial Types
numeric
bit (or unsigned units)
u8
- unsigned 8 bit integer (uint8_t)
u16
- unsigned 16 bit integer (uint16_t)
u32
- unsigned 32 bit integer (uint32_t)
u64
- unsigned 64 bit integer (uint64_t)
integer (signed)
i8
- signed 8 bit integer (int8_t)
i16
- signed 16 bit integer (int16_t)
i32
- signed 32 bit integer (int32_t)
i64
- signed 64 bit integer (int64_t)
real
f32
- 32 bit floating point (float)
f64
- 64 bit floating point (double)
string
str
- utf8 / ascii encoded string depending on the language output
normal string
"«utf8 encoded characters»"
multiline literal string (also used for string interpolation like in JS)
`«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.
set error to %"something borked";
set some_var to error ?? 0;
set some_var to error ?? panic(error);
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->«type»
set «variable» to [val1, val2, ...] as «type»[];
! or as a map
set «variable» to {key1: val1, key2: val2, ...} as «type»->«type»;
tunnel
described in "tunnel" section
Basic operators
The following is a list of global operators and their effect:
!
- comment
!!
- block comment (looks for another !! to close)
??
- 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
..
- expander
- (1..10) is the same as writing (1,2,3,4,5,6,7,8,9,10)
++
- inline add 1
--
- inline subtract 1
+=
- inline add n
-=
- inline subtract n
*=
- inline multiply n
\=
- inline divide n
**=
- inline power n
logical / bitwise operators
eq
- equal to
ne
- not equals to
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
to
set operator
set «token» to 0;
is
checks if a object is of that type
if («token» is i32) {
stdout.print("hello yes self is i32?");
}
also used for setting constants
const purple is Color(255, 255, 0);
as
coerces a type as another type if possible
set «token» to 0; ! default is i32
some_functon_that_needs_a_i8(«token» as i8);
in
checks if a object's type, or a type impls another type
if («token» in Tunnel) {
stdout.print("im tunnel-able");
}
also used inside of the for loops
for («token» in «collection») { «body» }
Object
An object is an invoked type.
set «variable» to «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
set endpoint to 9p(endpoint_str);
set tunnel to endpoint.attach(user, auth);
set data to tunnel.open("\some\resource").read();
stdout.write(data);
data.flush();
endpoint.clunk();
in "terminal mode" the default tunnel is stdout
in "web mode" the default tunnels are log, info, trace, warn, error, but note these are all special tunnels which only accept write commands
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» («type» «parameter», ...) «return_type» {
«instructions»
}
- 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
loop { «body» } until(«boolean expression»);
always loops first and then until the expression is false
branching
match «token» {
'a' -> actionA
'x' -> actionX
'y'..'z' -> {
actionY
actionZ
}
_ -> actionNoMatch
}
exceptions
take a look at error's, but you can panic on an error like self:
panic(#"error message");
panic(#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://code.example.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
- date
- unit
- length
- unit
- metre (m)
- subtypes
- angle
- radian (rad)
- angle
- unit
- mass
- unit
- kilogram (kg)
- unit
- electric current
- unit
- ampere (a)
- unit
- temperature
- unit
- kelvin (K)
- unit
- amount of substance
- unit
- mol (mol)
- unit
- luminous intensity
- unit
- candela (candela)
- unit
- time