Example ufy code is denoted in this font:
printf("hello world\n");
Usage of constructs, directives, keywords and operators is denoted in the following style:
Lastly, examples sometimes yield output in your terminal. In that case, the following style is used:
Example:
// This is a comment. /* So is this. */ // /* This is a comment, but not because of the '/*'. /* // This is also a comment, but not because of the '//'. */
Back to Top | Back to Constructs | The '#doc' directive
/* ** This directive tells the interpreter to use the 'std' module, ** which is, in fact, an alias for the ** 'stdlib', 'stdio', 'string', 'net' and 'time' modules. ** The 'printf' function is in the 'stdio' module, and the '#use' ** directive below makes sure we can actually use it. */ #use std printf("Hello world\n");
Hello world
Back to Top | Back to Constructs | More on Directives
Example:
#use std while (1) { // here we are inside the block body. printf("'Round we go.\n"); }
'Round we go. 'Round we go. 'Round we go. ...
Variables declared within the body of a block, will not survive the end of a block; at that time they are removed from the stack. This is why it can be elegant to sometimes create blocks out of the blue; it will leave your variable namespace outside the block intact.
Example:
#use std var a = 3; { var a = 5 * a; printf("Inside the block, a = %a\n", a); } printf("Outside the block, a = %a\n", a);
Inside the block, a = 15 Outside the block, a = 3
Back to Top | Back to Constructs
Example:
#use std var a = 5; var b = 6 * a; printf("a = $(a)\n"); printf("b = $(b)\n"); // and so on..
a = 5 b = 30
Back to Top | Back to Constructs
Example:
function foo(a, int b) { return a + b; } foo("b = ", 3);
Back to Top | Back to Constructs
Modularization tries to raise an extra question to the programmer. Not only how to divide code into functions and classes, but also where to put them and how to reach them when needed. This can be a great boon when coding is done in teams, or when parts of the code are so good, that they will be needed for time to come or by other people unbeknownst to the original programmer.
In ufy, there are the following types of modules:
And the following possibilities to compound modules in a single namespace:
Back to Top | Back to Constructs
Creates an alias for one or more modules. Consequent usage of the alias will instead load all of the modules that it's an alias for. The <name> and <module> identifiers are subject to the module-name-constraints.
Back to Top | Back to Directives
Provides a way to document ufy code at the closing of any block. It is equivalent to the normal closing of a block with a curly brace. For example, the following code:
try { something(); #doc Here we try something } fail { telltheworld(); #doc But we might fail. }Inserts documentation into the parsetree-node at the place of this try-fail statement. That documentation can then be retrieved again by inspecting the parsetree. A tool, written in ufy, ufydoc does just that, and it sports a parser for extracting meta-data and fancy formatting from the documentation text, according to the ufydoc specification.
Back to Top | Back to Directives | Tools: ufydoc | Ufydoc Specification
Includes a file, which it may have found at its exact location, or at a location relative to the searchpath-list kept by the interpreter. When the interpreter passes over the place where the directive is specified, it will go into the included file's body instead and, on emerging from there, it will continue with the next statement.
Seemingly, this may make code specified in the included file completely out of reach. For example:
somefunction(); exit(); #include somefile.ufyThis code would seem to make the inclusion of 'somefile.ufy' to be pointless, after all, the code exits (that is, quits the interpreter) before it can even get there. This is not quite true, as the interpreter will have scanned the code before executing it and, having found the inclusion, will have loaded the code. Any functions defined in 'somefile.ufy' will be known to the interpreter. The code above is, of course, crappy code, but in fact, if 'somefunction' is defined in 'somefile.ufy', then this code will still succeed.
Back to Top | Back to Directives
Defines a module to the interpreter. A few key-value-pairs are of specific importance;
Back to Top | Back to Directives
Add one or more paths to the list of paths that the interpreter uses to find modules or files to include. Its use is primarily in the ufy configuration file; so that installed modules in exotic places can have their paths readily available to any using code.
Back to Top | Back to Directives | ufyconf
Require this module to be used for each and every sourcecode module or include file. It's really a hack to ensure that every piece of ufy source uses the '$lang' module, which has a few functions that you can't do without, as well as the standard input, output and error stream globals. Its use is primarily in the ufy configuration file.
However, you can tune your personal ufy installation in such a way, that you wouldn't ever need to '#use std', for example, by including in your configuration '#require std'. That would make all of your scripts more heavy, but probably most of your scripts one line shorter.
Back to Top | Back to Directives | ufyconf
Loads a module, and executes it. The public function- and global namespace of the module are accessible to the using script.
Back to Top | Back to Directives
Breaks out of a loop or a switch. Example:
#use std while (1) { break; exit(); } printf("Exit was never called !\n");
Exit was never called !
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Declares a class, or creates an anonymous class within an expression.
Back to Top | Back to Keywords
Or:
Creates a child-thread of execution, in which it executes a set of statements or a functioncall. Returns a queue object which can be used in the yield / fetch pair of functioncalls.
Back to Top | Back to Keywords
Continue within a loop, that is, jump to the closing bracket of the loop-body.
#use std var i=3; while (i-- > 0) { printf("i is now %a, will we make it to the end of the loop ?\n", i); continue; exit(); } printf("We made it to the end !\n");
i is now 2, will we make it to the end of the loop ? i is now 1, will we make it to the end of the loop ? i is now 0, will we make it to the end of the loop ? We made it to the end !
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Defines a destructor within a class. The destructor of a class is called when an object of the class is being destroyed. This happens when all references to the class have gone from instances on the stack, or through any instances on the stack.
Example:
#use std class foo { destructor { printf(stderr, "Object of class 'foo' is being destroyed.\n"); } } { var a = foo(); }
Object of class 'foo' is being destroyed.
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Evaluates expression 1, determines whether the loop can continue based on the outcome of expression 2, and, up completion of the execution of the body of the loop, evaluates expression 3. Example:
#use std for (i=0; i<4; i++) { printf("Your i is now $(i).\n"); }
Your i is now 0. Your i is now 1. Your i is now 2. Your i is now 3.
Back to Top | Back to Keywords
Evaluates the expression, which must yield a list as a result, and iterates through each key-value-pair of the list, assigning them to the optional identifiers given. Example:
#use std var animals = [ 'cat', 'dog', 'horse', 'last' -> 'canary' ]; foreach (n; animal; animals) { printf("Animal at number $(n) is '$(animal)'.\n"); }
Animal at number 0 is 'cat'. Animal at number 1 is 'dog'. Animal at number 2 is 'horse'. Animal at number last is 'canary'.
Back to Top | Back to Keywords
'function' S <ident> S '('
Back to Top | Back to Keywords
If evaluates the expression, and based on its outcome, it will execute the first body of code, or, when present, the second body of code. The first body of code (the 'if'-block) will be executed only when the expression evaluates to true, the second body of code (the 'else'-block) will be evaluated only in the opposite case. It's possible to chain 'if' and 'else' together to something resembling a switch statement:
if (foo == 'bar') { dosomething(); } else if (foo == 'foobar') { dosomethingelse(); } else if (foo == 'barfu') { dosomethingdifferent(); } else { dosomethingentirelydifferentstill(); }
Back to Top | Back to Keywords
Or:
Returns true when the first object is indeed of the mentioned class or one of its subclasses, or, when an object is given as its second operand, whether the first object is of the class of the second object's class or one of its subclasses.
Example:
#use std class foo { } class bar : foo { } var a = bar(); if (a isa foo) { printf("a is a foo !\n"); }
a is a foo !
Back to Top | Back to Keywords
Or:
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Back to Top | Back to Keywords
Or:
Or:
Or:
Or:
Try protects the thread execution of statements inside the first statement block against errors. When an error occurs, the code will break out of the first statement block, and start executing the code inside the 'fail' statement block, if present. If a 'succeed' statement block is present and no error occurs executing the first statement block, then that block will be executed after the thread breaks out of the first statement block naturally. Example:
#use std try { throw("throw causes an error."); } fail { printf("An error occurred: " + catch() + "\n"); } succeed { printf("You won't see this.\n"); }
An error occurred: throw causes an error.
Back to Top | Back to Keywords | Function throw | Function catch
Declares one or more variables on the stack, and optionally assigns a value to them. Example:
var a = 'foo', b, c = 'bar';
Back to Top | Back to Keywords
Is really a literal for the 'null'- or undefined value, and as such, can only be used in expressions. Example:
#use std var a = void; // which is automatic, but this is an example if (a == void) { printf("a is void.\n"); }
a is void.
Back to Top | Back to Keywords
//.. text
#use std var i=4; while (--i >= 0) { printf("i=$(i), counting down..\n"); }
i=3, counting down.. i=2, counting down.. i=1, counting down.. i=0, counting down..
Back to Top | Back to Keywords