Skip to content

Advanced Tutorial

Luis Albizo edited this page Sep 13, 2020 · 15 revisions

Introduction

Strings

In wardscript there is no string data type, but with the help of nodes and bytes you can build one, even so there is a way for the interpreter to do this for you; with a syntactic sugar, just write the string you want between double quotes: "string". This will result in a node with a byte and another node referencing to the next char.

s := "My String";
? s is a node 
    The structure is:
        { $char := 77, $next := { $char := 121, $next := ... } }
    It is a linked list where $char is the byte value for the
    character and $next is another linked list or nil for
    the end of the string, like the following:
        77->121->32->83->116->114->105->110->103->nil
?
print(s);
? if the function print takes a node it wil treat it like a
string and will print character by character. 
the output will be "My String" (whitout end of line) ?

Lists

Another syntactic sugar on wardscript serves for creating linked list in an easy way.

my_list := [1, 2, 4, 8, 16];
? This generates a node with the folowing structure:
    { $root := { $data := 1, $next := { $data := 2, next := ... } } }
    as we see, the linked list is on the $root member which can be nil if the list is empty ( [] ),
    the $data member contains the value of the element and the member $next is the reference to the next node.

    root->(1->2->4->8->16->nil)
?

Lambdas

A lambda expression or an 'anonymous function' is a reduced syntaxis to create a function, a lambda just need a list of arguments and an expression, it automaticaly returns the result of that expresion.

$1 := func { x, y : x + y },
$2 := func { f, x : func { y : f(x, y) } };

Reduce operator

The reduce operator is unique to wardscript, is not an arithmetic operator. The function of this operator is to eval and reduce some expression, this is useful when is more appropiate to eval an expression just once. Internally the interpreter evaluate the expression and saves the result in the ast instead of just using it. An example is:

f := func x, y: x:
    x := x + y;
end,
f' := func x, y: x:
    x := #(x + y);
end;

? Non-reducing ?
present(f(2,4)); ? output: 6 ?
present(f(2,5)); ? output: 7 ?
? Reducing ?
present(f'(2,4)); ? output: 6 ?
present(f'(2,5)); ? output: 6 ?

Closures and the nonlocal keyword

See closures on wikipedia to understand what a closure is, in abstract a closure is the context (scope) where a function is created, so the function will have some memory about the variables that existed in the moment when the function was created.

Check the next example:

f := func x: g:
    g := func y: y:
        y := x + y;
    end;
end;

add8 := f(8);
present(add8(10)); ? output: 18 ?

this works correctly even when the context where f was called the variable x was not declared, this is a closure.

In this case the nonlocal keyword were not needed because wardscript by default searchs in the higher scopes recursively when a name is required and is not declared in the current scope, but if we assign x inside g then we need a way to start searching from the higher scope, that is why exists the nonlocal keyword

f := func x: g:
    g := func y: y:
        x := nil;
        y := nonlocal x + y;
    end;
end,

f' := func x: g:
    g := func x: x:
        x := nonlocal x + x;
    end;
end;
? f and f' do the same ?

this works exactly like the last example, the first way to use the nonlocal keyword is prefixing it to a name, then the name becomes nonlocal and search the variable starting from the higher scope, this way: nonlocal name.

Nonlocal assignments

The second way to use the nonlocal keyword is by prefixing it to a list of assignments, if we made a nonlocal assignment then the names have to exist in the higher scopes.

generator := func start: g:
    g := func step: start:
        nonlocal start := start + step;
    end;
end;

$g := generator(0);
present($g(8)); ? output: 8 ?
present($g(8)); ? output: 16 ?

Clone this wiki locally