The XDCscript Language

From RTSC-Pedia

Jump to: navigation, search
revision tip
—— LANDSCAPE orientation
[printable version]  [offline version]offline version generated on 18-Nov-2017 00:11 UTC 

The XDCscript Language

XDCscript overview

Contents

Introduction

XDCscripts, such as configuration scripts, are written in the JavaScript language. This document does not provide details on the syntax of the JavaScript language. However, several concepts are important when using JavaScript within XDCscripts. This section provides an overview of such concepts. See "JavaScript and Java References" below for JavaScript reference sources.

JavaScript language overview

JavaScript syntax, operators, and flow-control statements are similar to those in the C language. It includes if, else, switch, break, for, while, do, and return statements which behave almost identically to their C counter-parts. As a result, C programmers can easily read and modify most JavaScript scripts.

JavaScript is a loosely-typed language. Variables in JavaScript are more flexible than variables in C or Java. Variables do not need to be explicitly declared, and the same variable can store different data types at different points within a script. These types are number, string, Boolean value, array, object, function (which is actually an object itself), and null. Operators automatically convert values between data types as necessary.

Variables can be local to a function or global to the entire JavaScript environment. Variable and object names may not contain spaces or punctuation other than "_" or "$". In addition, variable and object names can include numbers but must not begin with a number.

JavaScript does not have pointers and does not deal with memory addresses.

Common misconceptions about JavaScript

If you've used JavaScript before, you have probably added scripts to a web page. It's important to clear up misconceptions some programmers may have about JavaScript when used outside the context of web pages:

  • JavaScript is a general-purpose, cross-platform programming language. While it was developed for use in web-browsers, it has a number of features that make it useful for application configuration. It is easy to learn and use, the syntax is similar to C, it is object oriented, and it is widely documented.
  • JavaScript is standardized. The language is also called ECMAScript, and the ECMA-262 standard defines the language (see http://www.ecma.ch/ecma1/STAND/ECMA-262.HTM). The basic syntax and semantics of the language are stable and standardized.
  • When you use JavaScript in a web page, the objects you use are defined by the Document Object Model (DOM). These objects include window, document, form, and image. The DOM is not part of the JavaScript standard; nor is the DOM part of XDCscript.
  • Other object models can be defined for use with JavaScript. Instead of the DOM, XDCscript often runs in the context of an "object model" containing one or more global objects; for example, configuration scripts are run in a context in which the global variable Program is defined.
  • JavaScript is not a part of Java. These are two different languages that have similar names for historical marketing reasons. However, XDCscript does allow scripts to call arbitrary Java functions, including any method provided by the the standard Java Runtime Environment.
  • For security reasons within web browsers, JavaScript does not provide built-in support for file services. However, by virtue of providing access to the Java Runtime Environment, XDCscript has full access to a complete (and standard) set of file-system services.
  • RTSC Modules run JavaScript only on the host PC, UNIX, or Linux machine. JavaScript code is not run on the embedded target (yet).

The print() method

The print() method is an extension to JavaScript that sends the result of the expression passed to the method to stdout. When running the a script via xs at the command line, for example, the print() statement is displayed in the command shell's window.

In this example, if obj is an array, these statements print a list of the objects in the array.

 
 
 
for (var i = 0; i < obj.length; i++) {
    print("obj[" + i + "] = " + obj[i]);
}

The following statements display the names of all public properties of the object obj and their values.

 
 
 
for (var p in obj) {
    print("obj." + p + " = " + obj[p]);
}

The java object

For security reasons, the JavaScript language does not provide any built-in file services. In a web browser, the lack of file services prevents most forms of file access on your computer. XDCscript, however, builds atop the Rhino JavaScript interpreter and this interpreter provides unrestricted to any Java class via LiveConnect. As a result, all of the classes in the standard Java Runtime Environment, such as the java.io classes, can be used from XDCscript.

File manipulation with Java

Calls to the java.io classes from a script look just like JavaScript function calls. For example, these statements display the path to a file if it exists:

 
 
 
 
var file = new java.io.File(fileName);
if (file.exists()) {
    print(file.getPath());
}

Reading files

Reading files.  It's even possible to read and write files. For example, it is possible to display the contents of a file with the following few lines:

 
 
 
 
 
var line;
var file = new java.io.BufferedReader(new java.io.FileReader("/etc/motd"));
while ((line = file.readLine()) != null) {
    print(line);
}

Writing files

Writing files.  The next example illustrates how to create a new file, named "foo.txt", and write to it.

 
 
 
var file = new java.io.FileWriter("foo.txt");
file.write("this is a test");
file.flush();

Deleting files

Deleting files.  The java.io.File class also allows you to delete files via a delete() method. However, since delete is a JavaScript keyword it is not possible to directly call this method. Fortunately, because all JavaScript objects are associative arrays, any method or property of an object can be accessed using "array notation".

 
 
 
var file = new java.io.File("tmp.dat");
file.delete();     /* WRONG: this will cause a JavaScript parser error */
file["delete"]();  /* RIGHT: same as above but avoids conflict with 'delete' keyword */
Copying files

Copying files.  There are times when you may need to copy a file. Rather than loop over each line of the input file, Java provides a method that can transfer the entire contents of a file into another.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function copy(src, dst)
{
    /* open input and output channels */
    var ins = new java.io.FileInputStream(src);
    var outs = new java.io.FileOutputStream(dst, true);
    var inc = ins.getChannel();
    var outc = outs.getChannel();
 
    inc.transferTo(0, inc.size(), outc);    /* transfer entire src to dst */
 
    /* close all streams and channels */
    inc.close();
    outc.close();
    ins.close();
    outs.close();
}

For documentation of the java.io package, see the Java 2 SDK documentation. In particular, see the reference documentation for the java.io package classes File, FileReader, BufferedReader, FileWriter, and BufferedWriter.

JavaScript versus Java strings

The Rhino JavaScript interpreter does its best to enable seamless use of underlying Java classes and objects. Unfortunately, this integration sometimes causes confusion when manipulating strings; both Java and JavaScript define a number of methods that operate on strings and not all of them are the same.

As a result, there are some situations where you must explicitly convert strings returned by Java methods into JavaScript strings. Fortunately, this is simple: either cast the Java string to a JavaScript string using JavaScript's String object or simply append an empty string to the Java string (Rhino automatically converts the Java string to a JavaScript to allow the concatenation).

 
 
 
 
 
 
 
 
 
 
 
/* cwd is a Java string */
var cwd = (new java.io.File("foo/bar")).getName();
 
/* the following will print "true" because cwd ends with "bar" */
print(cwd.endsWith("bar"));  
 
/* convert cwd to a JavaScript string */
cwd = "" + cwd; /* could also convert via "cwd = String(cwd)" */
 
/* the following triggers a "TypeError": endsWith() isn't a JavaScript string method */
print(cwd.endsWith("bar"));

XDCscript operators

XDCscript inherits all JavaScript operators and adds some XDCscript-specific ones, mainly to help with the type-checked assignments, which is one of the main differences between JavaScript and XDCscript.

The XDCscript pointer variables expect expressions of pointer types, with an additional requirement for function pointer variables that the signature of the function assigned to a variable must match the signature of the variable's type. In most cases, the assigned values are typed variables specified in XDCspec files, and their types are readily available and can be checked for compatibility with the pointer variables. However, XDCscript pointer variables must also accept references to C functions and variables that do not have their representation in XDCscript. In such cases, C function and variable names are supplied as parameters to the operators $externPtr, $externFxn and $externModFxn, which then convert these names to assignment compatible values for XDCscript pointer variables.

For example, a module pkg.Mod could define a config parameter callbackFxn of the function pointer type Void (Int, Int).

Mod.xdc
 
 
 
 
 
module Mod {
    typedef Void (*FxnType)(Int, Int); 
    config FxnType callbackFxn;
    ...
}

Using the operator $externFxn, one can assign the function myFxn to callbackFxn without myFxn being declared in any XDCspec file.

app.cfg
 
 
var Mod = xdc.useModule('pkg.Mod');
Mod.callbackFxn = $externFxn("myFxn");

The user's code must then contain a function myFxn with the signature as defined for FxnType.

While these operators are available in any object model, they are mainly intended to be used in the configuration object model, in which a C file is being generated at the end of configuration. The generated C file contains declarations and definitions of objects of pointer types based on the values assigned to them during the configuration. For the given example, a simplified version of the generated code shows the definition of callbackFxn.

 
FxnType pkg_Mod_callbackFxn = (FxnType)myFxn;

The operator $addr is used when a numeric value is assigned to a pointer variable. The purpose of having this operator, as opposed to allowing a simple number assignment, is to prevent accidental assignments. For example, a module pkg.Mod could define a config parameter arr of the type Int *.

Mod.xdc
 
 
 
 
module Mod {
    config Int *arr;
    ...
}

The address 0x1000 can be assigned to arr using $addr.

app.cfg
 
 
var Mod = xdc.useModule('pkg.Mod');
Mod.arr = $addr(0x1000);
$externPtr(<symbol name>)

$externPtr(<symbol name>). This operator produces a value that can only be assigned to a variable of a data pointer type. The generated C file contains a declaration extern void * for a name passed to the operator. The user's code must contain a symbol with that name of any pointer type.

$externFxn<symbol name>)

$externFxn<symbol name>). This operator produces a value that can only be assigned to a variable of a function pointer type. The generated C file contains a function declaration extern void <symbol name>(). The user's code must contain a function whose signature corresponds to this declaration.

$externModFxn<symbol name>)

$externModFxn<symbol name>). This operator produces a value that can only be assigned to a variable of a function pointer type. However, the generated C file does not contain any additional function declaration. This operator can be used for functions that are declared as instance functions in XDCspec files, and as such cannot be referenced as XDCscript objects. The user's code does not have to define such functions because they will be defined automatically.

$addr(<numeric literal>)

$addr(<numeric literal>). This operator produces a value that can only assign values to a variable of a pointer type. The generated C files assigns the numeric value to the C representation of the pointer variable.

The environment and arguments objects

The Rhino interpreter also defines two other global objects, environment and arguments, that make it possible to create highly reusable scripts.

The environment object

The environment object.  This object is a hash table that maps strings naming Java Runtime Environment (JRE) system properties to their values.

% xs -i
 
 
 
js> print(environment["user.dir"])
/home/dr
js>

Don't confuse values defined in the environment[] with command shell environment variables. JRE properties, while similar to shell environment variables, are not the same as the environment variables passed to processes by the host operating system. If you need to access command line environment variables, you should use the java.lang.System.getenv() method.

% xs -i
 
 
 
js> print(java.lang.System.getenv("USER"))
dr
js>

In addition to the properties provided by the JRE, the xs command adds the following properties to the Java environment.

xdc.path
the full package path
xdc.rootDir
the full path to the XDCtools installation directory
xdc.scriptName
the name of the script passed on the xs command line. If a module or a package is specified on the command line rather than a script file, environment["xdc.scriptName"] is set to the name of the module containing the code to run. For example, the commands "xs xdc.tools.cdoc" and "xs -m xdc.tools.cdoc.Main" both run the main() method defined in the module xdc.tools.cdoc.Main and in both cases environment["xdc.scriptName"] is equal to "xdc.tools.cdoc.Main".

Finally, it is possible to add new name value pairs to environment via the -D command line option of the xs command.

% xs -Dfoo=bar -i
 
 
 
js> print(environment["foo"])
bar
js>

For a complete list of properties provided by the JRE see the Java reference documentation for the java.lang.System.getProperties() method. To see the list of properties provided in your environment, you can use the JavaScript ability to loop over the elements of a hash table and display them using the print() method described above.

% xs -i
 
 
 
 
 
js> for (var p in environment) print('environment["' + p + '"] = ' + environment[p])
environment["java.runtime.name"] = Java(TM) 2 Runtime Environment, Standard Edition
environment["user.dir"] = /home/dr
   :
js>
The arguments object

The arguments object.  When scripts are run via the xs command, all arguments passed after the name of the script (or package containing a Main.xs script) are passed to the script in the arguments array. This arguments object is an ordinary JavaScript array of strings, one element per argument passed on the command line.

% xs -f args.xs this is 'a test'
 
 
 
arguments[0] = this
arguments[1] = is
arguments[2] = a test
args.xs
 
 
 
for (var i = 0; i < arguments.length; i++) {
    print('arguments[' + i + '] = ' + arguments[i]);
}

The xdc object

In addition to the global objects added by Rhino to the JavaScript environment, XDCscript has an additional global object named xdc. This object servers as a "container" for a collection of methods and state common to all of XDCscript. This section summarizes some of the more commonly used methods. For a complete list of methods available see XDCscript Language Reference.

Methods for loading other files

XDCscript can load another script file. When a script file is loaded, any statements that are outside any function are executed. The functions and variables defined in the loaded script are available to the script that loaded the file.

On Windows-based hosts, directory paths specified in JavaScript statements can use either "\\" or "/" as a directory separator. However, UNIX-based hosts require you to use "/" to separate directory names within a file name. To ensure portability, you should always use "/" to separate directory names.

XDCscript provides the following methods for finding and loading files contained in packages:

  • xdc.loadCapsule() - An extension to JavaScript that runs JavaScript statements in any file and returns an object containing the variable and functions defined within the file.
  • xdc.findFile() - The method used to locate files based on either a package path relative name, an absolute path name or a current working directory relative name.
  • xdc.loadXML() - An extension to JavaScript that parses the specified XML file and returns an E4X object representing the contents of the file.

Suppose you find that you have some common code in a number of different configuration scripts. You can factor out and parameterize this common code by placing it in a separate script file, say bios_utils.xs, and place it in a package, say common.scripts, that appears on your package path. Now any script that would otherwise duplicate the code contained in bios_utils.xs can simply load it via xdc.loadCapsule().

 
 
var bios_utils = xdc.loadCapsule("common/scripts/bios_utils.xs");
bios_utils.doSomethingUseful();

Suppose you adopt a convention that every package has contains contains a file named version.txt containing package version information. The script below uses xdc.findFile() to locate the version.txt file in the package named my.pkg and prints its contents.

 
 
 
 
 
 
 
 
 
/* locate my.pkg's version.txt file */
var path = xdc.findFile("my/pkg/version.txt");
 
/* print its contents */
var file = new java.io.BufferedReader(new java.io.FileReader(path));
var line;
while ((line = file.readLine()) != null) {
    print(line);
}

Finally, the next example illustrates how to use xdc.loadXML() and E4X to display all of a package's external references. Every package contains a ./package subdirectory with several XML files that describe the package. One file, package.rel.xml, contained in all released packages contains a list of all external references. The example below displays this list for the xdc.runtime package. Note that like xdc.loadCapsule(), xdc.loadXML() searches the package path.

 
 
 
 
 
 
 
 
 
/* load the xdc.runtime package's release XML file */
var ext = xdc.loadXML("xdc/runtime/package/package.rel.xml");
 
/* use E4X extensions to get and display information from this file */
var references = ext.references["package"];
print("package " + ext["package"].@name + " references the following packages:");
for (var i in references) {
    print("    " + references[i].@name + " [" + references[i].@version + "]");
}

Methods for generating other files

While it is relatively easy to use the ability to write files (shown above) to create any text file, it is sometimes easier to use and maintain a "template" that is used to create a new file. For example, suppose you need to generate a C file whose contents are almost always the same except for a few computed data tables. Using a template allows you to easily adjust the output rather than wading through long sequences of 'file.write(" \n");' statements.

The XDCscript provides a few methods to simplify the generation of files based on templates.

  • var tplt = xdc.loadTemplate(template)
    read template into memory and return an object that can be used to "expand" the template into an output stream or into a new file.
  • tplt.genFile(fileName, thisObj, args, clobber)
    generate output to fileName, which is created if necessary. Unless clobber is true, an existing file is overwritten only when its content has truly changed.
  • tplt.genStream(outStream, thisObj, args)
    generate output to outStream, an instance of class java.io.PrintStream. All three parameters are passed to the underlying template generation function.

Template files contain lines of text that genFile() and genStream() automatically output when invoked. Templates also contain lines of XDCscript that are executed during expansion and can reference any object in the current environment – with $out, this, and $args bound to parameters of genStream().

The syntax of templates is quite simple. Lines that begin with the '%' character are treated as XDCscript and are not output. Line that don't begin with '%' are simply output without change unless they contain tokens within between back quotes (`...`). In this case the characters between the back quotes are evaluated as XDCscript expression and the resulting value replaces the expression in the output line.

The following examples summarize the statements that can appear in templates.

text`script expression`text …
A line of text to be output at this point. All expressions between `s are replaced with their (textual) value in the current context.
% script …
A single line of script to be executed at this point during expansion.
%%{
   stmt …
   stmt …
%%}
Multiple lines of script to be evaluated at this point during expansion. Variable and functions defined in such a block can be used in other lines, blocks, or expressions.

Example (generating copyrights from a template).  The following script and template illustrate many of the capabilities of templates.

gen.xs
 
 
 
var template = xdc.loadTemplate("copyright.xdt");
template.genStream(java.lang.System.out, this, 
    ["TI", arguments]);
copyright.xdt
 
 
 
 
 
 
 
 
 
 
 
 
%%{
    var NAME = $args[0];
    var CTRB = $args[1];
    var DATE = new Date().getFullYear();
%%}
/*  Copyright `DATE` by `NAME`.
 *  All rights reserved. Property of `NAME`.
 *  Contributions from:
%for (var i = 0; i < CTRB.length; i++) {
 *      `CTRB[i]`
%}
 */

Running this script produces the following output.

xs -f gen.xs bob carol ted alice
 
 
 
 
 
 
 
 
/*  Copyright 2008 by TI.
 *  All rights reserved. Property of TI.
 *  Contributions from:
 *      bob
 *      carol
 *      ted
 *      alice
 */

Running scripts

TODO:   move to beginning or remove reference to xs above

In addition to using JavaScript and the extensions described above for configuration and build scripts, XDCtools provides a command line utility, xs, that allows you to run arbitrary scripts. This allows you to easily experiment with XDCscript and create powerful utilities that don't require any additional tools. For example, it is possible to use the xs command to start an interactive session that allows you to repeatedly enter XDCscript statements and see their results.

% xs -i
 
 
 
 
 
 
js> print("hello");
hello
js> "this.is.a.test".replace(/\./g, '/')
this/is/a/test
js> quit
%

It is also quite easy to create and run arbitrary scripts. For example, we can encapsulate the E4X example above to create a reusable script that displays any package's external references.

refs.xs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function main(args) {
    /* convert package name to release XML file name */
    var file = args[0].replace(/\./g, '/') + "/package/package.rel.xml";
    print("loading " + file + " ...");
 
    /* load the specified package's release XML file */
    var ext = xdc.loadXML(file);
 
    /* use E4X extensions to get and display information from this file */
    var references = ext.references["package"];
    print("package " + ext["package"].@name + " references the following packages:");
    for (var i in references) {
        print("    " + references[i].@name + " [" + references[i].@version + "]");
    }
}

This script can be run using the -c option of the xs command.

% xs -c refs.xs xdc.runtime
 
 
 
 
 
 
 
 
 
 
 
 
 
    loading xdc/runtime/package/package.rel.xml ...
    package xdc.runtime references the following packages:
        xdc.utils.tconf [1, 0, 0, 0]
        xdc.services.global [1, 0, 0]
        xdc.services.spec [1, 0, 0, 0]
        xdc.corevers [16, 0, 1, 0]
        xdc.bld [1, 0, 0, 0]
        xdc.services.intern.cmd [1, 0, 0, 0]
        xdc.services.intern.xsr [1, 0, 0]
        xdc [1, 1, 0, 0]
        xdc.shelf [1, 0, 0, 0]
        xdc.services.intern.gen [1, 0, 0, 0]
%

For more information about running XDCscript, see the xs Command Reference and for help debugging scripts see XDCscript Debugging.

JavaScript and Java references

This document does not provide details on the syntax of the JavaScript language or on the Java packages that can be used. For reference information, we recommend the following sources:

See also

Command - xs XDCscript interpreter
 
XDCscript Debugging Overview of script debugging techniques
XDCscript - xdc.traceEnable Enable debug trace output
 
XDCscript - xdc.loadCapsule Load specified capsule
XDCscript - xdc.findFile Find file (or directory) along the package path
XDCscript - xdc.loadXML Load an XML file
 
XDCscript - xdc.loadTemplate Create a template object from a template file

[printable version]  [offline version]offline version generated on 18-Nov-2017 00:11 UTC 
Copyright © 2008 The Eclipse Foundation. All Rights Reserved
Personal tools
package reference