wiki:Doc/panc/dml/functions

Functions

Table of Contents

  1. Calling Functions
  2. User-Defined Functions
  3. Built-In Functions
    1. base64_decode( arg:string ) : string
    2. base64_encode( arg:string ) : string
    3. clone( arg:element ) : element
    4. create( name:string, ... ) : nlist
    5. debug( arg:string ) : string
    6. delete( arg:variable ) : undef
    7. error( msg:string )
    8. escape( arg:string ) : string
    9. exists( arg:variable ) : boolean
    10. exists( path:string ) : boolean
    11. exists( template:string ) : boolean
    12. first( arg:resource, key:identifier, value:identifier ) : boolean
    13. format( format_string:string, arg:property, ... ) : string
    14. hash( ... ) : nlist
    15. if_exists( template_name:string ) : string | undef
    16. index ( sub:string, arg:string, [ start:long ] ) : long
    17. index ( sub:property, arg:list, [ start:long ] ) : long
    18. index ( sub:property, arg:nlist, [ start:long ] ) : string
    19. index ( sub:nlist, arg:list, [ start:long ] ) : long
    20. index ( sub:nlist, arg:nlist, [ start:long ] ) : string
    21. is_boolean( arg:element ) : boolean
    22. is_defined( arg:element ) : boolean
    23. is_double( arg:element ) : boolean
    24. is_hash( arg:element ) : boolean
    25. is_list( arg:element ) : boolean
    26. is_long( arg:element ) : boolean
    27. is_nlist( arg:element ) : boolean
    28. is_null( arg:element ) : boolean
    29. is_number( arg:element ) : boolean
    30. is_property( arg:element ) : boolean
    31. is_resource( arg:element ) : boolean
    32. is_string( arg:element ) : boolean
    33. key( arg:nlist, index:long ) : string
    34. length( arg:string ) : long
    35. length( arg:resource ) : long
    36. list( ... ) : list
    37. match( arg:string, regexp:string ) : boolean
    38. matches( arg:string, regexp:string ) : list
    39. merge( ... ) : resource
    40. next( arg:resource, key:identifier, value:identifier ) : boolean
    41. nlist( ... ) : nlist
    42. return( arg:element ) : element
    43. splice ( arg:string, start:long, length:long, [ new:string ] ) : string
    44. splice ( arg:list, start:long, length:long, [ new:list] ) : list
    45. substr ( arg:string, start:long, [ length:long ] ) : string
    46. to_boolean( arg:property ) : boolean
    47. to_double( arg:property ) : double
    48. to_long( arg:property ) : long
    49. to_string( arg:property ) : string
    50. traceback( arg:string ) : string
    51. unescape( arg:string ) : string
    52. value( path:string ) : element

Calling Functions

Within a Data Manipulation Language (DML) block, user-defined and built-in functions may be called. The pan language uses a typical syntax for calling a function:

identifier(arg1, arg2, ...);

where 'identifier' is a valid pan identifier and the arguments are passed to the function as a comma-separated list. The arguments may be expressions, in which case those expressions will be completely evaluated before calling the function.

All functions return a value, although it might be 'undef'.

User-Defined Functions

The pan language permits user-defined functions. These functions are essentially a DML block bound to an identifier. Only one DML block may be assigned to a given identifier. Attempts to redefine an existing function will cause the execution to be aborted. The syntax for defining a function is:

function identifier = DML;

where identifier is a valid pan identifier and DML is the block to bind to this identifier.

When the function is called, the DML will have the variables 'ARGC' and 'ARGV' defined. (The deprecated names 'argc' and 'argv' will also be defined.) The variable 'ARGC' contains the number of arguments passed to the function; 'ARGV' is a list containing the values of the arguments.

Note that ARGV is a standard pan list. Consequently, passing null values (intended to delete elements) to functions can have non-obvious effects. For example, the call:

f(null);

will result is an empty ARGV list because the null value deletes the nonexistent element ARGV[0].

The pan language does no automatic checking of the number or types of arguments. The DML block that defines the function must make all of these checks explicitly and use the error() function to emit an informative message in case of an error.

Recursive calls to a function are permitted. However, the call depth is limited (by an option when the compiler is invoked) to avoid infinite recursion. Typically, the maximum is a small number like 10.

The following example defines a function that checks if the number of arguments is even and are all numbers:

function even_numbers = {

  if (ARGC%2 != 0) {
    error('number of arguments must be even'); 
  };

  foreach (k, v, ARGV) {
    if (! is_number(v)) {
      error('non-numeric argument found');
    };
  };

};

Built-In Functions

base64_decode( arg:string ) : string

This function decodes the given string that must be Base64 (defined in RFC 2045) encoded.

'/test' = '[' + base64_decode("aGVsbG8gd29ybGQ=") + ']'; 
# will be the string '[hello world]' 

base64_encode( arg:string ) : string

This function encodes the given string into its Base64 (defined in RFC 2045) form.

clone( arg:element ) : element

This function returns a clone (copy) of the given argument.

create( name:string, ... ) : nlist

This function returns the named list which is the result of the execution of the structure template identified by the given name; the optional extra parameters must be pairs of key and value and will add or modify the result accordingly (a bit like with nlist).

# description of a CD mount entry (but the device is unknown) 
structure template mount_cdrom; 
"device" = undef; 
"path" = "/mnt/cdrom"; 
"type" = "iso9660"; 
"options" = list("noauto", "owner", "ro"); 
# our first mount entry is the CD coming from hdc 
"/system/mounts/0" = create("mount_cdrom", "device", "hdc"); 
# this is exactly equivalent to the following two lines 
"/system/mounts/0" = create("mount_cdrom"); 
"/system/mounts/0/device" = "hdc"; 

debug( arg:string ) : string

This function prints the given message on stdout when debugging is enabled with the DEBUG USER flag. The function returns the message.

# print the value of x if it is positive 
if (x > 0) debug("x is positive: " + to_string(x)); 

delete( arg:variable ) : undef

This function deletes the element identified by the ”variable expression” (i.e. variable name with optional subscript such as foo or foo[123] or foo[123][”abc”]).

# the following will put the list ("a", "c") at path "/x" 
"/x" = { 
  x = list("a", "b", "c"); 
  delete(x[1]); 
  return(x); 
}; 

error( msg:string )

This function prints the given message on stderr and aborts the compilation.

# user function requiring one long argument 
function foo = { 

  if (argc != 1) error("foo(): wrong number of arguments: " + to_string(argc)); 

  if (!is_long(argv[0])) error("foo(): argument is not a long"); 

# normal processing... 
}; 

escape( arg:string ) : string

This function escape non alphanumeric characters in the given string so that it can be used inside paths, for instance as an named list key.

"/test" = escape("1+1"); 
# will be the string "1_2b1" 

exists( arg:variable ) : boolean

This function checks if the ”variable expression” (see delete function) corresponds to an existing element. Note that this function processes its argument in a non-standard way. The function only checks to see if the element identified by the variable expression exists. It does not check the actual value of the element. Consequently, this function will return true for any element including 'null' and 'undef' values.

exists( path:string ) : boolean

This function checks if the path corresponds to an existing element; the path must be an absolute or external path. Note that if the argument is a variable expression it will be interpreted as a call to exists( arg:variable) and will not read the value of the variable. For example, the following DML code:

v = '/some/absolute/path';
r = exists(v);

always gives the value 'true' to the variable r. If you want to test the path, do something like the following instead:

v = '/some/absolute/path';
r = exists(v+'');

Here the value r will depend on whether the path '/some/absolute/path' actually exists.

exists( template:string ) : boolean

This function checks if the given template exists. Any string not starting with a slash is considered a template name.

first( arg:resource, key:identifier, value:identifier ) : boolean

This function resets the iterator associated with arg so that it points to its first child element; if there is one (i.e. if the resource is not empty), sets the variable key to the ”key” of this element (i.e. a long if arg is a list or a string if it is a nlist) and the variable value to the child element itself and return true; if key or value is undef, don’t assign it; if there is no such child element, simply return false.

# compute the sum of the elements inside numlist 
numlist = list(1, 2, 4, 8); 
sum = 0; 
ok = first(numlist, k, v); 
while (ok) { 
  sum = sum + v; 
  ok = next(numlist, k, v); 
}; 
# sum will be 15 

# put the list of all the keys of table inside keys 
table = nlist("a", 1, "b", 2, "c", 3); 
keys = list(); 
ok = first(table, k, v); 
  while (ok) { 
  keys[length(keys)] = k;
  ok = next(table, k, v);
}; 
# keys will be ("a", "b", "c") 

format( format_string:string, arg:property, ... ) : string

This function will created a formatted string from the given arguments. This is implemented via the java format syntax; see the java.util.Formatter description for complete details of the syntax. (Available in version 8 and later.)

hash( ... ) : nlist

This is a synonym for the nlist function.

if_exists( template_name:string ) : string | undef

This function checks if the template named template exists on the current load path. If it does, the function returns the template name; if not, it returns undef.

This can be used to conditionally include a template only if it exists:

include {if_exists('my/conditional/template')};

This function should be used with caution as this brings in dependencies based on the state of the file system and may cause dependency checking to be inaccurate.

index ( sub:string, arg:string, [ start:long ] ) : long

This function searches for the given substring inside the given string and returns its position from the beginning of the string or -1 if not found; if the third argument is given, starts only from that position.

"/s1" = index("foo", "abcfoodefoobar"); # 3 
"/s2" = index("f0o", "abcfoodefoobar"); # -1 
"/s3" = index("foo", "abcfoodefoobar", 4); # 8 

index ( sub:property, arg:list, [ start:long ] ) : long

This function searches for the given property inside the given list of properties and returns its position or -1 if not found; if the third argument is given, starts only from that position; it is an error if sub and arg’s children are not of the same type.

# search in a list of strings 
"/l1" = index("foo", list("Foo", "FOO", "foo", "bar")); 
# will be 2 
# search in a list of longs 
"/l2" = index(1, list(3, 1, 4, 1, 6), 2); 
# will be 3 

index ( sub:property, arg:nlist, [ start:long ] ) : string

This function searches for the given property inside the given named list of properties and returns its name or the empty string if not found; if the third argument is given, skips that many matching children; it is an error if sub and arg’s children are not of the same type.

# simple color table 
"/table" = nlist("red", 0xf00, "green", 0x0f0, "blue", 0x00f); 
"/name1" = index(0x0f0, value("/table")); 
# will be the string "green" 
"/name2" = index(0x0f0, value("/table"), 1); 
# will be the string ""

index ( sub:nlist, arg:list, [ start:long ] ) : long

This function searches for the given named list inside the given list of named lists and returns its position or -1 if not found; the comparison is done by comparing all the children of sub, these children must all be properties; if the third argument is given, starts only from that position; it is an error if sub and arg’s children are not of the same type or if their common children don’t have the same type.

# search a record in a list of records 
"/l1" = index(nlist("key", "foo"), list(nlist("key", "bar", "val", 101), 
nlist("key", "foo", "val", 102))); 
# will be 1 (i.e. the second nlist) 

index ( sub:nlist, arg:nlist, [ start:long ] ) : string

This function searches for the given named list inside the given named list of named lists and returns its name or the empty string if not found; if the third argument is given, skips that many matching children; it is an error if sub and arg’s children are not of the same type or if their common children don’t have the same type.

is_boolean( arg:element ) : boolean

This function checks if the given argument is a boolean.

is_defined( arg:element ) : boolean

This function checks if the given argument is defined (i.e. is anything but undef or null).

is_double( arg:element ) : boolean

This function checks if the given argument is a double.

is_hash( arg:element ) : boolean

This function checks if the given argument is a nlist. Synonym for the is_nlist function.

is_list( arg:element ) : boolean

This function checks if the given argument is a list.

is_long( arg:element ) : boolean

This function checks if the given argument is a long.

is_nlist( arg:element ) : boolean

This function checks if the given argument is a nlist.

is_null( arg:element ) : boolean

This function checks if the given argument has a null value (i.e. is anything but null).

is_number( arg:element ) : boolean

Returns true if the argument is either a long or double property.

is_property( arg:element ) : boolean

This function checks if the given argument is a property.

is_resource( arg:element ) : boolean

This function checks if the given argument is a resource.

is_string( arg:element ) : boolean

This function checks if the given argument is a string.

key( arg:nlist, index:long ) : string

This function returns the name of the child identified by its index, this can be used to iterate through all the children of a named list. The index of a particular key is determined by the lexical ordering of all keys in the nlist, with 0 being the first index.

"/table" = nlist("red", 0xf00, "green", 0x0f0, "blue", 0x00f); 

"/keys" = { 

  tbl = value("/table"); 
  res = ""; 
  len = length(tbl); 
  idx = 0; 
  while (idx < len) { 
    res = res + key(tbl, idx) + " "; 
    idx = idx + 1; 
  }; 

  if (length(res) > 0) splice(res, -1, 1); 
  return(res); 
}; 
# /keys will be the string "blue green red " 

length( arg:string ) : long

This function returns the length of the given string.

length( arg:resource ) : long

This function returns the number of children of the given resource.

list( ... ) : list

This function returns a list made of its arguments.

# the list of mount entries is empty 
"/system/mounts = list(); 
# we define two DNS servers 
"/system/dns/servers" = list("137.138.16.5", "137.138.17.5"); 
# this machine has only one CPU 
"/hardware/cpus" = list(create("cpu_intel_p3_850")); 

match( arg:string, regexp:string ) : boolean

This function checks if the given string matches the regular expression.

# device_t is a string that can only be "disk", "cd" or "net" 
type device_t = string with match(self, ’ˆ(disk|cd|net)$’); 

matches( arg:string, regexp:string ) : list

This function matches the given string against the regular expression and returns the list of captured substrings, the first one being the complete matched string (i.e. $& in Perl).

# IPv4 address in dotted number notation 
type ipv4 = string with { 
  result = matches(self, ’ˆ(\d+)\.(\d+)\.(\d+)\.(\d+)$’); 
  if (length(result) == 0) 
  return("bad string"); 
  i = 1; 
  while (i <= 4) { 
    x = to_long(result[i]); 
    if (x > 255) return("chunk " + to_string(i) + " too big: " + result[i]); 
    i = i + 1; 
  };
  return(true); 
}; 

merge( ... ) : resource

This function returns the resource which is the merge of its arguments which must be of the same type: either all lists or all named lists; if several named lists have children of the same name, an error occurs.

"/x" = list("a", "b", "c"); 
"/y" = list("d", "e"); 
"/z" = merge (value("/x"), value("/y")); 
# /z will contain the list "a", "b", "c", "d", "e" 

next( arg:resource, key:identifier, value:identifier ) : boolean

This function increments the iterator associated with arg so that it points to the next child element and then behaves like first.

nlist( ... ) : nlist

This function returns a named list made of its arguments which must be pairs of key (i.e. child’s name, a string) and value (i.e. child’s value, an element).

# hda1 is our root filesystem 
"/system/mounts/0" = nlist("type", "ext2", "path", "/", "device", "hda1"); 
# hda2 is our /var filesystem 
"/system/mounts/1" = nlist( 
"type", "ext2", 
"path", "/var", 
"device", "hda2", 
); 

return( arg:element ) : element

This function interrupts the processing of the current DML block and returns from it with the given value, this is often used in user defined functions.

function facto = { 
  if (argv[0] < 2) return(1); 
  return(argv[0] * facto(argv[0] - 1)); 
}; 

splice ( arg:string, start:long, length:long, [ new:string ] ) : string

This function deletes the substring identified by start and length (see substr’s documentation for de- tails) and, if a fourth argument is given, replaces it with new.

"/s1" = splice("abcde", 2, 0, "12"); # ab12cde 
"/s2" = splice("abcde", -2, 1); # abce 
"/s3" = splice("abcde", 2, 2, "XXX"); # abXXXe 

splice ( arg:list, start:long, length:long, [ new:list] ) : list

This function deletes the children of the given list identified by start and length (see substr’s docu- mentation for details) and, if a fourth argument is given, replaces them with the contents of new.

"/l1" = splice(list("a","b","c","d","e"), 2, 0, list(1,2)); 
# will be the list "a", "b", 1, 2, "c", "d", "e" 
"/l2" = splice(list("a","b","c","d","e"), -2, 1); 
# will be the list "a", "b", "c", "e" 
"/l3" = splice(list("a","b","c","d","e"), 2, 2, list("XXX")); 
# will be the list "a", "b", "XXX", "e" 

substr ( arg:string, start:long, [ length:long ] ) : string

This function returns the part of the given string characterised by its start position (starting from 0) and its length (if omitted, returns everything to the end of the string); if start is negative, starts that far from the end of the string; if length is negative, leaves that many characters off the end of the string.

"/s1" = substr("abcdef", 2); # cdef 
"/s2" = substr("abcdef", 1, 1); # b 
"/s3" = substr("abcdef", 1, -1); # bcde 
"/s4" = substr("abcdef", -4); # cdef 
"/s5" = substr("abcdef", -4, 1); # c 
"/s6" = substr("abcdef", -4, -1); # cde 

to_boolean( arg:property ) : boolean

This function converts the given property into a boolean; 0 and the empty strings are considered as false, everything else as true.

to_double( arg:property ) : double

This function converts the given property into a double; it is an error if the given string does not represent a double.

to_long( arg:property ) : long

This function converts the given property into a long; it is an error if the given string does not represent a long; if the argument is a double, it will be rounded to the nearest long.

to_string( arg:property ) : string

This function converts the given property into a string.

traceback( arg:string ) : string

Prints the argument and a traceback from the current execution point to the standard error. Value returned is the argument. This will throw an evaluation error (along with a traceback) if the argument is not a string.

unescape( arg:string ) : string

This function replace escaped characters in the given string to get back the original string, this is the inverse of the escape function.

value( path:string ) : element

This function returns the element identified by its path (which can be an external path), an error occurs if there is no such element.

"/x" = 100; 
"/y" = 2 * value("/x"); 
# /y will be 200 
# we add one DNS server to the current list 
# (we need to use list() because merge() requires lists) 
"/system/dns/servers" = merge(value("/system/dns/servers"), list("137.138.16.5")); 
# the RAM of this machine is the same as the machine foo 
"/hardware/memory/size" = value("//foo/hardware/memory/size"); 
Last modified 16 years ago Last modified on Apr 21, 2008, 2:14:18 PM