482 lines
9.4 KiB
Org Mode
482 lines
9.4 KiB
Org Mode
* /ZTL/ (Zongors Transpiler Language) Design parameters
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: ztl-zongors-transpiler-language-design-parameters
|
||
:END:
|
||
** What is /ztl/?
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: what-is-ztl
|
||
:END:
|
||
/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
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: ztl-grammar-and-specification
|
||
:END:
|
||
** Types
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: types
|
||
:END:
|
||
- 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"
|
||
|
||
#+begin_src ztl
|
||
type «token» {
|
||
init() {
|
||
// values
|
||
}
|
||
}
|
||
#+end_src ztl
|
||
|
||
* Basic Types
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: substantial-types
|
||
:END:
|
||
** numeric
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: numeric
|
||
:END:
|
||
- =byte=
|
||
- unsigned 8 bit integer (uint8_t)
|
||
- =number=
|
||
- 64 bit floating point (double)
|
||
|
||
** string
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: string
|
||
:END:
|
||
- =str=
|
||
- utf8 / ascii encoded string depending on the language output
|
||
|
||
normal string
|
||
|
||
="«utf8 encoded characters»"=
|
||
|
||
string interpolation
|
||
|
||
="«utf8 encoded characters» ${some_var}"=
|
||
|
||
** logical
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: logical
|
||
:END:
|
||
=bool=
|
||
|
||
=true= / =false=
|
||
|
||
Also follows the style boolean 'c' rules of nonzero / zero, but the
|
||
compiler will make fun of you
|
||
|
||
** error
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: error
|
||
:END:
|
||
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.
|
||
|
||
#+begin_src ztl
|
||
let rr = err("something borked");
|
||
let var = rr ?? 0; // value is 0
|
||
let other_var = rr ?? panic(rr); // will panic
|
||
#+end_src ztl
|
||
|
||
** datastructure
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: datastructure
|
||
:END:
|
||
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
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: table
|
||
:END:
|
||
syntax (yes I was nice and kept the syntax the same as most C like
|
||
langs)
|
||
|
||
#+begin_src ztl
|
||
// array same as a map of int to «type»
|
||
let «variable» = [val1, val2, ...];
|
||
|
||
// or as a map
|
||
let «variable» = {key1: val1, key2: val2, ...};
|
||
#+end_src ztl
|
||
|
||
*** tunnel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: tunnel
|
||
:END:
|
||
described in "tunnel" section
|
||
|
||
*** Basic operators
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: basic-operators
|
||
:END:
|
||
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
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: logical-bitwise-operators
|
||
:END:
|
||
- =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
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: keywords
|
||
:END:
|
||
|
||
=let=
|
||
|
||
let operator
|
||
|
||
#+begin_src ztl
|
||
let «token» = 0;
|
||
#+end_src ztl
|
||
|
||
=is=
|
||
|
||
checks if a object is of that type
|
||
|
||
#+begin_src ztl
|
||
if («token» is i32) {
|
||
print("hello yes self is i32?");
|
||
}
|
||
#+end_src ztl
|
||
|
||
also used for letting constants
|
||
|
||
=as=
|
||
|
||
coerces a type as another type if possible
|
||
|
||
#+begin_src ztl
|
||
let «token» = 0; // default is i32
|
||
some_functon(«token» as i8); // needs an i8
|
||
#+end_src ztl
|
||
|
||
=in=
|
||
|
||
checks if a object's type, or a type impls another type
|
||
|
||
#+begin_src ztl
|
||
if («token» in Tunnel) {
|
||
print("im tunnel-able");
|
||
}
|
||
#+end_src ztl
|
||
|
||
also used inside of the for loops
|
||
|
||
#+begin_src ztl
|
||
for («token» in «collection») { «body» }
|
||
#+end_src ztl
|
||
|
||
** Object
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: object
|
||
:END:
|
||
An object is an invoked type.
|
||
|
||
#+begin_src ztl
|
||
let «variable» = «type»(«fields», …);
|
||
#+end_src ztl
|
||
|
||
** Tunnel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: tunnel-1
|
||
:END:
|
||
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
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: transtypes-for-tunnels
|
||
:END:
|
||
=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
|
||
|
||
#+begin_src ztl
|
||
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();
|
||
#+end_src ztl
|
||
|
||
** Functions
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: functions
|
||
:END:
|
||
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.
|
||
|
||
#+begin_src ztl
|
||
fn «token» («parameter» «type», ...) «return_type» {
|
||
«body»
|
||
}
|
||
#+end_src ztl
|
||
|
||
- Built in transtypes
|
||
- sort
|
||
- filter
|
||
- trig functions
|
||
- calc functions
|
||
- statistical functions
|
||
|
||
** Control flow
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: control-flow
|
||
:END:
|
||
*** loops
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: loops
|
||
:END:
|
||
#+begin_src ztl
|
||
for («token» in «collection») { «body» }
|
||
#+end_src ztl
|
||
|
||
iterates through each object in the collection setting it to token
|
||
|
||
#+begin_src ztl
|
||
while («boolean expression») { «body» }
|
||
#+end_src ztl
|
||
|
||
loops until the expression is false
|
||
|
||
#+begin_src ztl
|
||
loop { «body» }
|
||
#+end_src ztl
|
||
|
||
loops infinitely until break or return
|
||
|
||
#+begin_src ztl
|
||
do (let «variable» = initial_value, end_value, increment) { «body» }
|
||
#+end_src ztl
|
||
|
||
loops from initial value to end value by increment value
|
||
|
||
*** branching
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: branching
|
||
:END:
|
||
#+begin_src ztl
|
||
if («boolean expression») {
|
||
|
||
} else if («boolean expression») {
|
||
|
||
} else {
|
||
|
||
}
|
||
#+end_src ztl
|
||
|
||
*** exceptions
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: exceptions
|
||
:END:
|
||
take a look at error's, but you can panic on an error like self:
|
||
|
||
#+begin_src ztl
|
||
panic(err("error message"));
|
||
panic(err(3));
|
||
panic(«some_error_token»);
|
||
#+end_src ztl
|
||
|
||
** Localization
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: localization
|
||
:END:
|
||
will look up the text of «token» in the linked localization.json file
|
||
|
||
#+begin_src ztl
|
||
#«token»
|
||
#+end_src ztl
|
||
|
||
#+begin_src json
|
||
{
|
||
"some_token": [
|
||
"localization_1": ""
|
||
],
|
||
"some_other_token": [
|
||
"localization_1": "",
|
||
"localization_2": ""
|
||
]
|
||
}
|
||
#+end_src
|
||
|
||
** Libraries and "includes"
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: libraries-and-includes
|
||
:END:
|
||
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
|
||
|
||
#+begin_src ztl
|
||
use "https://git.alfrescocavern.com/some_library/some_file.ztl"
|
||
#+end_src ztl
|
||
|
||
#+begin_src ztl
|
||
use "./some_local_file.ztl"
|
||
#+end_src ztl
|
||
|
||
** Testing
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: testing
|
||
:END:
|
||
*** assertion
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: assertion
|
||
:END:
|
||
#+begin_src ztl
|
||
assert(«expression», «expected output») //returns «error or none»
|
||
#+end_src ztl
|
||
|
||
** Measurements
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: measurements
|
||
:END:
|
||
- 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)
|