| |||||||||
Book: The Judo Language 0.9 |
|
Blocks can also be a part of other compound statements that are discussed in this chapter. Blocks can also have Compound statements Event-driven statements do 'http://www.yahoo.com' as sgml { <a>: if $_.href != null { println $_.href; } <img>: println $_.src; } In this SGML statement, each SGML tag encountered is treated as an "event"; you as a programmer provides an event "handler", which is a series of statements, for each "event". If-Else StatementThe if-else statement has this syntax:
The Expr's are evaluated to boolean values; if if foo() { var tmp = 5; println 'foo() returns true.'; } else { println 'foo() returns false.'; } println tmp; In the last line, Switch StatementThe syntax for the switch statement is:
No more than one The values in the
The CASE OF number: 9 CASE OF Date: 11/20/01 12:00 AM CASE OF Java: {} CASE OF string: uvw DEFAULT: XYZ CASE OF Java: {} What happened to the value of Statements for each switch x { case 1: case 2: case 3: println 'In [1,3]'; break; case 4: case 5: case 6: println 'In [4,6]'; break; default: println 'Outside of [1,6];'; break; } Note that the
The result is: 0 is a power of 3 3 is a power of 3 9 is a power of 3 27 is a power of 3 81 is a power of 3 While and Do-While LoopsThe while and do-while statements have the following syntax:
The meaning of these two statements are self-evident. The following example tests both:
The result is: while() {} 3 2 1 0 do {} while. -1 0 1 For and Repeat LoopsJudo has three for loop statements. The generic for loop The syntax for the generic for loop is:
This form of for loop is the same as the for statement in Java or C/C++. It runs the first list of expressions sort of like initialization, then check on the boolean expression in the second place; if for init(); cond(); postproc() { do_work(); } it is equivalent to: init(); while cond() { do_work(); postproc(); } This is an example:
The for-from-to loop This statement is to loop through a series of numbers as specified. The syntax is:
The loop number can be ascending (with the
The result is: for [from 0] to 3: 0 1 2 3 for from 3 to 5: 3 4 5 for from 3 to 10 step 2: 3 5 7 9 for from 10 downto 5 step 2: 10 8 6 The for-in loop The for-in statement is to iterate through collection data structures. Collections include built-in data structures such as
The
The result is: Iterating Array: 0: 1 1: 2 2: 3 Iterating Java array: 0: 10 1: 20 2: 30 Iterating java.util.ArrayList: 0: 100 1: 200 2: 300 Iterating with range: --- for in 1 2 3 4 --- for in backward 4 3 2 1 --- for in from 1 2 3 4 --- for in to 1 1 2 --- for in from 1 to 2 2 3 --- for in from 2 downto 1 3 2 --- for in downto 1 4 3 2 The repeat statement
Break, Continue and Loop IndexThe break and continue statements
The optional IDENTIFIER is a label name for a loop to break or continue from within a nested loop. The following is an example:
The result is: 4-1 4-2 4-3 4-4 4-5 5-1 5-2 5-3 5-4 Loop index
The result is: outer loop: 0 inner loop: 0 outer loop: 0 inner loop: 1 outer loop: 0 inner loop: 2 outer loop: 0 inner loop: 3 outer loop: 1 inner loop: 0 outer loop: 1 inner loop: 1 outer loop: 1 inner loop: 2 outer loop: 1 inner loop: 3 outer loop: 2 inner loop: 0 outer loop: 2 inner loop: 1 outer loop: 2 inner loop: 2 outer loop: 2 inner loop: 3 This do file_name as lines { if loopIndex() < 5 { continue; } println $_; } The do .. as lines statement is covered later.
|
Function | ::= | function IDENTIFIER [ ( ] params [ ) ] { ( Statement )* } |
params | ::= | param ( , param )* [ , .. ] | .. | < Expr > |
param | ::= | IDENTIFIER [ = Expr ] |
The same syntax is used for methods within user-defined classes; there are some fundamental differences between functions and class methods, which will be discussed in chapter 10. Object-Oriented Programming.
The parentheses around parameters are not required; if parentheses are used, the right parenthesis must match the left one. Functions always return a value; the return
statement can return a value and exit the function. If no return
statements are called, the function code will fall out of scope and exit, returning undefined
. Functions, like any declarations in Judo, can appear anywhere, that is, you can call a function before it is declared. The following is the famous Hanoi Tower problem followed by the result of a test run.
Listing 6.9 hanoi.judo |
---|
cnt = 0; hanoiTower(4, 'A', 'B', 'C'); function hanoiTower N, src, aux, dst { if N == 0 { return; } hanoiTower(N-1, src, dst, aux); println 'step ', ++cnt :>2, ': ', src, ' => ', dst; hanoiTower(N-1, aux, src, dst); } |
The Tower of Hanoi puzzle was invented by the French mathematician Edouard Lucas in 1883. There are three pegs; initially a number of disks of different sizes are stacked on one peg; the objective is to transfer the entire tower to another peg, moving only one disk at a time and never a larger one on top of a smaller. This is a well-known recursive algorithm. In hanoi.judo
, we used a global variable, cnt
, to track the history of the transfers. The following is the result of moving an initial tower of 4 disks.
step 1: A => B step 2: A => C step 3: B => C step 4: A => B step 5: C => A step 6: C => B step 7: A => B step 8: A => C step 9: B => C step 10: B => A step 11: C => A step 12: B => C step 13: A => B step 14: A => C step 15: B => C
Function parameter names are the same as variable names. Parameters may have default values. Function calls can take any number of parameter values. If the number of passed values is less than the number of declared parameters, the missing parameters take the default values in the function declaration; if no default values specified, null
is used. If the number of passed values is more than the number of declared parameters, the extra parameters are stored in an array in the predefined local variable, $$args
.
To explicitly declare that a function takes variable number of parameters, you may end the parameter list with two dots (..
); this has no further meaning.
During function calls, parameters are pass-by-value for primitive Judo data types (including integer, number, date and time and string), and pass-by-reference for other object types.
Listing 6.10 var_params.judo |
---|
function inc x, delta=1, .. { ret = x + delta; if $$args != null { for x in $$args { ret += x; } } return ret; } println inc(2); println inc(2,2); println inc(2,2,2); function sum .. { ret = 0; for x in $$args { ret += x; } return ret; } println sum(1,2,3,4,5,6,7,8,9); function oneparam a { println '---', nl, 'The parameter: ', a; if $$args != null { println unit($$args.length, 'useless parameter'); } } oneparam('abc'); oneparam('abc', x, y, z); |
The result is:
3 4 6 45 ---- The parameter: abc ---- The parameter: abc 3 useless parameters
Judo allows you to dynamically create a parameter list in an array, and use that array as function call parameters through the {{ }}
syntax.
Listing 6.11 dyn_params.judo |
---|
function sentence subj, verb, obj, .. { print subj, ' ', verb, ' ', obj; for x in $$args { print ' ', x; } println '.'; } params = [ 'James', 'wrote', 'Judo' ]; sentence( {{params}} ); params = [ 'He', 'uses', 'Judo', 'day-in', 'and', 'day-out' ]; sentence( {{params}} ); |
In the example, the functionsentence()
prints out all its parameters separated by spaces. The first three parameters are named, and it handles variable number of parameters. When called with dynamic parameters in an array, the elements of array are taken as individual parameters and the result of execution is:
James wrote Judo. He uses Judo day-in and day-out.
A function variable is a variable that references a function. A function reference is obtained by the &
operator. They can be assigned to variables or passed as paramter values to other functions.
To call a function reference stored in a variable, you can simply invoke the function with the variable name. If the function reference is stored in an array element, use that array element. If the function reference is stored as a value for a key in an Object
, use the key name to invoke the function. The following example demonstrates all these situations.
Listing 6.15 fxn_var.judo |
---|
function foo1 a, b { return a + b; } function foo2 a, b { return a * b; } function whichFoo f, a, b { return f(a,b); } println 'whichFoo(&foo1, 2, 3) = ', whichFoo(&foo1, 2, 3); println 'whichFoo(&foo2, 2, 3) = ', whichFoo(&foo2, 2, 3); x = [ &foo1, &foo2 ]; println 'x = ', x; println 'x[0](2, 3) = ', x[0](2, 3); println 'x[1](2, 3) = ', x[1](2, 3); y = { fxn1 = &foo1, fxn2 = &foo2 }; println 'y = ', y; println 'y.fxn1(4, 6) = ', y.fxn1(4, 6); println 'y.fxn2(4, 6) = ', y.fxn2(4, 6); |
The only ambiguous situation is that, if there is a function defined with the same name as a variable that holds a function reference, the defined function will be accessed. To remedy this situation, Judo uses the ->
operator to explicitly invoke a function referenced in a variable as follows:
function foo1 a, b { return a + b; } function foo2 a, b { return a * b; } function whichFoo f, a, b { return f(a,b); } println 'whichFoo->(&foo1, 2, 3) = ', whichFoo->(&foo1, 2, 3); println 'whichFoo->(&foo2, 2, 3) = ', whichFoo->(&foo2, 2, 3);
Function variables are important in Judo. Many data structures have methods that take particular function variables to do tasks such as sorting, filtering and transformation. For instance, Array
's sort()
method can take a function reference which takes two parameters and return 1
, 0
or -1
as the result of comparison; its filter()
method can take a function reference which takes one parameter and returns true
or false
. The following example shows how to do a custom sorting on array elements.
Listing 6.13 custom_sort |
---|
a = [ '1.2', '3', '3.9', '1.10', '1.2.1', '2.3', '3' ]; a.sort( &my_comparator ); for x in al { println x; } function my_comparator(lhs, rhs) { la = lhs.csv('.'); ra = rhs.csv('.'); for i from 0 to la.size() { if la[i].int() < ra[i].int() { return -1; } if la[i].int() > ra[i].int() { return 1; } } if la.size() == ra.size() { return 0; } return la.size() > ra.size(); } |
This program prints the array list as book section numbers. The result is:
1.2 1.2.1 1.10 2.3 3 3 3.9
Another good example is the toCsv()
of the Array
object. The following code converts an array of values into comma-separated, quoted strings, which can be used in SQL's where clause as the values for the in expression:
last_names = [ 'Olajuwon', 'Yao' ]; in_expr = last_names.toCsv(',', function(x){ return "'"+x+"'"; }); exeucteQuery qry: SELECT * FROM emp WHERE last_name IN ( (* in_expr *) ) ;
The resultant SQL statement is:
SELECT * FROM emp WHERE last_name IN ( 'Olajuwon', 'Yao' )
The SQL scripting is introduced in chapter 22. JDBC (SQL) Scripting.
With function variables, functions do not always need names. Anonymous functions can be declared without names; in this case, parentheses around parameters are required, and it must be assigned to a location.
Listing 6.14 filter.judo |
---|
a = [ 'a', 'ab', 'abc', 'abcd', 'abcde', 'abcdef', 'abcdefg' ]; f = function(elem){ return elem.length() >= 5; }; a.filter(f,true); println a; |
In the filter()
call, the first parameter is a filter function. The second parameter of true
indicates the filtering is done locally; if false
, a new array is returned with the filtered elements. The filtering is for strings over 5-character long. The result is:
[abcde,abcdef,abcdefg]
Another way to make new functions is to alias Java class static methods. Aliasing Java static methods is also discussed in Alias Java Static Methods as Functions. The syntax is:
Once a Java static method is aliased to be a function, that function can be used almost like a native Judo function:
function now for java::System.currentTimeMillis(); function loadLibrary for java::System.loadLibrary(); millis = now(); loadLibrary("native.dll");
Because the function aliases are indeed Java methods, the method parameters are fixed and strongly typed. You have to pass exactly the same number of parameters, and the parameter values should be compatible with the declared parameter types, and sometimes explicit casting may be needed. See Alias Java Static Methods as Functions for more details.
Judo has a number of system functions for various purposes. They are actually the methods of an internal $$sys
object but $$sys
is not required to use them. This is called method shortcut. In addition to $$sys
, shortcut methods also exists for internal object $$con
(the default database connection). In Judo, values and objects all have methods. The mathematical functions, for instance, are methods of numeric values. System functions are those that do not belong to any objects but useful system-wide.
The system functions fall into the following categories: values and numbers, system properties and related, system controls, system standard input-output, file input-output and generic. Refer to appendix 3. Built-In System Functions for a complete listing.
Judo can catch runtime exceptions, either from the language engine or from Java. The try-catch-finally syntax has two equivalent forms:
BlockCatchFinally | ::= | { ( Statement )+ [ catch [ IDENTIFIER ] : ( Statement )+ ] [ finally : ( Statement )+ ] } |
TryCatchFinally | ::= | try Block [ catch [ IDENTIFIER ] Block ] [ finally Block ] |
In the second form, at least one of catch
and finally
clauses must appear. The following is an example:
try { xxxxx(); // doesn't exist and will fail. } catch ex { println 'Catch: ', ex; } finally { println 'Finally.'; }
The first form is compact and easy; the second form is more Java-like and elegant but verbose. The choice is totally up to your style. The block form can also be applied to bodies of functions and compound statements. Note that if-else and switch statements' blocks can not have catch
and finally
clauses, as these blocks are just syntactic blocks and not block statements.
The catch
clause can take a variable name to hold the exception object; if not specified, $_
is used, as is the case in the following example:
{ xxxxx(); // doesn't exist and will fail. catch: println 'Catch: ', $_; finally: println 'Finally.'; }
In the global scope, you can have one catch
and one finally
clauses:
xxxxx(); // doesn't exist and will fail. catch: println 'Catch: ', $_; finally: cleanup();
The exception object in the catch
clause is a built-in object. For Java exceptions, the exception object wraps the Java exception, and all the Java exception methods can be accessed. The Judo exception object has these properties:
Name | Description |
---|---|
line | the line number in the script where the exception happened. |
file | the file name of the script in which the exception happened. |
message | the message for the exception. |
name | the internal name of the exception. |
type | the internal type of the exception. |
The most frequently used properties are line
and message
.
The Throw and Resume Statements
The throw and resume statements are two exception-related statements in Judo. The throw statement throws an exception that transfers the control to the immediate catch clause, or it aborts the program. Its syntax is:
Throw | ::= | throw [ Expr ] ; |
The Expr should be evaluated to be either an exception object (including Java exception object) or a string. If a string or no value is specified, a USER_EXCEPTION
is thrown.
The resume
statement is used only during handling exception in the catch
clause. It resumes the execution after where the exception has happened. If it has no effect if it appears in non-catch
code. It takes no parameters:
Resume | ::= | resume ; |
The following test demonstrates most of the exeption handling topics, including the exception object properties, throw and resume statements, and catch
and finally
in local and global scopes.
Listing 6.15 excpt_test.judo |
---|
{ xxxxx(); // method does not exist println 'Not reached.'; catch: println '[Line ', $_.line, '] INSIDE CATCH: <', $_.name, '> ', $_.message; throw $_; finally: println 'INSIDE FINALLY.'; } throw; throw new java::Exception("This exception is pure Java."); throw "ABCDE"; catch: println '[Line ', $_.line, '] OUTSIDE CATCH: <', $_.name, '> ', $_.message; resume; |
The output is:
[Line 2] INSIDE CATCH: <METHOD_NOT_FOUND> Function xxxxx() not found. INSIDE FINALLY. [Line 2] OUTSIDE CATCH: <METHOD_NOT_FOUND> Function xxxxx() not found. [Line 12] OUTSIDE CATCH: <USER_EXCEPTION> [Line 13] OUTSIDE CATCH: <JAVA_EXCEPTION> This exception is pure Java. [Line 14] OUTSIDE CATCH: <USER_EXCEPTION> ABCDE
The catch
and finally
clauses do not create new scopes; that is, they are all in the same scope as the whole block. In the format of try { .. } catch { .. } finally { .. }
, this may not be obvious.
|