Installing ez
The compiler
Installing the compiler for ez
, ezc
is fairly simple.
First, make sure you have cargo
and zig
in your $PATH
and are on x86_64 linux. You should use zig 0.7.0
. If you are on windows, wsl should work (although it has not been tested on wsl).
Then run cargo install ezc
. This will download and compile ezc
for you. To test if it worked run ezc
in the terminal. If it says:
ERROR: I need an input file.
you have installed it correctly.
Note if you want to install without zig, run
HAS_NO_ZIG=1 cargo install ezc
.
Standard Library
To build the standard library, run git clone https://github.com/g-w1/ezc && cd ezc/lib && zig build
. If this works correctly, you should have a copy of the standard library in ezc/lib/zig-cache/lib/libstd.a
.
Testing if it worked
To test if everything is installed correctly have a file called hello_world.ez
with this contents:
External function PutStringLine(s).
Set hello_world to "Hello World!".
Set tmp to PutStringLine(hello_world).
To compile it run ezc hello_world.ez -stdlib-path path/to/stdlib.a
.
To see if it worked, the command ./a.out
should print "Hello World!"
Troubleshooting
If you have any issues with the build or install process please raise an issue on github.
Variables and Conditionals
Variables
This tutorial will cover how to program in ez by using examples. Every example will showcase a different feature of ez.
The simplest ez program that does something is this:
Set var to 42.
All this program does is set a variable called var to the number 42.
If we wanted to change var to something else after we have set it we could do this:
Set var to 42.
Change var to var * 2.
This is self explanatory, we are changing var to something else. To use the change
keyword with a variable, you must set
it first.
Note: keywords in
ez
that start a sentence are not case sensitiveset var to 42.
works.to
is case sensitive because it is in the middle of a sentence. You can think of this like English.
Numbers and characters can be used interchangeably:
Set var to 'a'.
Change var to var * 2.
In this example, at the end, var is 194, because ‘a’ is converted to it’s ASCII code. There is 0 difference between characters and numbers.
Conditionals
We can use an if
statement to control the flow of the code:
Set special_number to 0.
if special_number = 0,
change special_number to special_number + 1.
!
Take a moment to think: what is the value of special_number
at the end of this program.
The answer: 1.
The way conditionals evaluate in ez is that if the if statement guard (in this case special_number = 0) evaluates to 1 then the block is run.
Blocks look like , (code) !
. Whitespace has no impact on ez.
You can create boolean expressions using these operators:
=
equals!=
not equaland
binary and operator (it also works for booleans because math is cool)or
binary or operator (it also works for booleans because math is cool)>
greater than<
less than>=
greater than or equal<=
less than or equal
You can use these operators to create numbers:
+
add-
subtract*
multiply
Note: division is not supported because it is not safe, dividing by zero is bad.
Loops
Loops are a core part of any programming language.
Here is an example of loops in ez:
set index to 0.
loop,
if index >= 10,
break.
!
change index to index + 1.
!
You can use the break keyword to get out of loop.
You can also nest loops. You cannot set variables in loops because they would be shadowed on the next iteration of the loop. Variable shadowing is not allowed in ez.
Functions
Functions are also core to any programming language. If you are not familiar with functions they are like mini-programs that can take arguments and return results.
Here is an example of one in ez:
Function AddOne(number),
set result to number + 1.
Return result.
!
We can then call a function with an argument to get the return value:
Set six to AddOne(5). {
This calls AddOne with the `number` argument as 5.
Then the function is run with the number variable set to 5.
Finally, it returns 6.
}
In ez, comments start with {
and end with }
. Anything inside the comment is ignored.
A Return
statement immediately stops the function and returns what is after it.
Recursive functions are allowed:
Function fib(a),
if a <= 2,
return 1.
!
return fib(a - 1) + fib(a - 2).
!
set result to fib(10).
In this example, at the end, result is set to 55, which is the 10th Fibonacci number. Notice how the fib function can call itself.
Modules
Ez has a very minimal module system.
It is similar to c, except no preprocessor or .h
files.
Functions are the only thing that can be exported from .ez
files to other files.
Here is an example:
lib.ez
Export function MulByTwo(n),
return n * n.
!
main.ez
External function MulByTwo(n).
set twelve to MulByTwo(6).
To compile this into a single binary, run:
# this produces a lib.ez.o file
$ ezc lib.ez -lib
# this produces a main.ez.o file
$ ezc main.ez -nolink
# this links everything together
$ ld main.ez.o lib.ez.o -o out
For another example of this, with a Makefile, go here: https://github.com/g-w1/ezc/tree/master/tests/module.
Ez uses the systemv x86_64 so you can also import and export functions to c or any language that can use this abi in the exact same way.
For an example of interfacing with c go here: https://github.com/g-w1/ezc/tree/master/tests/cinterface
Arrays and Pointers
Arrays and pointers are two of the most advanced topics in ez. They are also experimental: there are likely to be bugs when using them.
Arrays
You can set a variable to an array in ez:
set array_of_nums to [1,2,3].
You can index an array like this:
set array_of_nums to [3,2,1].
set one to array_of_nums[1]. { We know one is 3. }
set array_of_nums[1] to 1. { Now array_of_nums is [1,2,1]. }
A string is just an array of characters, which is just an array of numbers:
set array_of_nums to "hello\n".
set array_of_nums[1] to 'm'. { array_of_nums is "mello\n"}
To find the length of an array, you can use the zeroth element of it:
set array_of_nums to "hello\n".
set len to array_of_nums[0]. { len is 6 }
Note: for technical reasons, arrays are layed out in memory with the first element being a pointer to itself (for technical reasons involving the
mov
andlea
instructions), the second element being the length of the array (not including the first 2 elements) and the rest being the array in memory
[1,2,3]
is this:pointer to itself, 3, 1, 2, 3
To see examples of interacting with this slightly different array abi, viewlib.zig
Pointers
In ez, pointers are numbers that represent a pointer to a value.
Use the @
operator to dereference a pointer:
set null to 0.
set oof to @null.
This will produce a segmentation fault; it is the classic example of dereferencing a null pointer.
Note: when setting something to an array value, or passing an array in a function, you are just using the pointer to the array.
Standard Library
There are some functions that are provided by the libstd.a
standard library.
Here they are.
PutString(string)
Takes an array and prints all the ascii characters in it to stdout.PutStringLine(string)
Same asPutString
but prints\n
after.PutNewLine()
Prints\n
to stdout.PutChar(char)
Takes a character and prints it if it is ascii.PutNum(num)
Takes a number and prints the value.PutNumHex(num)
Takes a number and prints it in hex.PutNumBin(num)
Takes a number and prints it in binary.InputLine()
Reads a line from stdin and returns an array of it.