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 sensitive set 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 equal
  • and 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 and lea 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, view lib.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 as PutString 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.