520 lines
10 KiB
Org Mode
520 lines
10 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_example
|
||
type «type_token» {
|
||
! values
|
||
}
|
||
#+end_example
|
||
|
||
* Substantial Types
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: substantial-types
|
||
:END:
|
||
** numeric
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: numeric
|
||
:END:
|
||
*** bit (or unsigned units)
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: bit-or-unsigned-units
|
||
:END:
|
||
- =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)
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: integer-signed
|
||
:END:
|
||
- =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
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: real
|
||
:END:
|
||
- =f32=
|
||
- 32 bit floating point (float)
|
||
- =f64=
|
||
- 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»"=
|
||
|
||
multiline literal string (also used for string interpolation like in JS)
|
||
=`«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_example
|
||
set error to %"something borked";
|
||
set some_var to error ?? 0;
|
||
set some_var to error ?? panic(error);
|
||
#+end_example
|
||
|
||
** 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_example
|
||
! 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»;
|
||
#+end_example
|
||
|
||
*** 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
|
||
- =!!=
|
||
- 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
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: logical-bitwise-operators
|
||
:END:
|
||
- =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
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: keywords
|
||
:END:
|
||
=to=
|
||
|
||
set operator
|
||
|
||
#+begin_example
|
||
set «token» to 0;
|
||
#+end_example
|
||
=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
|
||
|
||
#+begin_example
|
||
if («token» in Tunnel) {
|
||
stdout.print("im tunnel-able");
|
||
}
|
||
#+end_example
|
||
|
||
also used inside of the for loops
|
||
|
||
#+begin_example
|
||
for («token» in «collection») { «body» }
|
||
#+end_example
|
||
|
||
** Object
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: object
|
||
:END:
|
||
An object is an invoked type.
|
||
|
||
#+begin_example
|
||
set «variable» to «type»(«fields», …);
|
||
#+end_example
|
||
|
||
** 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_example
|
||
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();
|
||
#+end_example
|
||
|
||
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
|
||
: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_example
|
||
fn «token» («type» «parameter», ...) «return_type» {
|
||
«instructions»
|
||
}
|
||
#+end_example
|
||
|
||
- 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_example
|
||
for («token» in «collection») { «body» }
|
||
#+end_example
|
||
|
||
iterates through each object in the collection setting it to token
|
||
|
||
#+begin_example
|
||
while («boolean expression») { «body» }
|
||
#+end_example
|
||
|
||
loops until the expression is false
|
||
|
||
#+begin_example
|
||
loop { «body» }
|
||
#+end_example
|
||
|
||
loops infinitely until break or return
|
||
|
||
#+begin_example
|
||
loop { «body» } until(«boolean expression»);
|
||
#+end_example
|
||
|
||
always loops first and then until the expression is false
|
||
|
||
*** branching
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: branching
|
||
:END:
|
||
#+begin_example
|
||
match «token» {
|
||
'a' -> actionA
|
||
'x' -> actionX
|
||
'y'..'z' -> {
|
||
actionY
|
||
actionZ
|
||
}
|
||
_ -> actionNoMatch
|
||
}
|
||
#+end_example
|
||
|
||
*** exceptions
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: exceptions
|
||
:END:
|
||
take a look at error's, but you can panic on an error like self:
|
||
|
||
#+begin_example
|
||
panic(#"error message");
|
||
panic(#3);
|
||
panic(«some_error_token»);
|
||
#+end_example
|
||
|
||
** Localization
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: localization
|
||
:END:
|
||
will look up the text of «token» in the linked localization.json file
|
||
|
||
#+begin_example
|
||
$«token»
|
||
#+end_example
|
||
|
||
#+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_example
|
||
use "https://code.example.com/some_library/some_file.ztl"
|
||
#+end_example
|
||
|
||
#+begin_example
|
||
use "./some_local_file.ztl"
|
||
#+end_example
|
||
|
||
** Testing
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: testing
|
||
:END:
|
||
*** assertion
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: assertion
|
||
:END:
|
||
#+begin_example
|
||
assert(«expression», «expected output») ! returns «error or none»
|
||
#+end_example
|
||
|
||
** 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)
|