The XDCscript Language
XDCscript overview
Contents[hide] |
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 below for JavaScript reference sources.
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.
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:
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]); } |
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.
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. 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. 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. 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. 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.
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")); |
The Rhino interpreter also defines two other global objects, environment and arguments, that make it possible to create highly reusable scripts.
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.
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. 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.
|
|
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.
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:
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 + "]"); } |
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.
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.
Example (generating copyrights from a template). The following script and template illustrate many of the capabilities of templates.
|
|
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 */ |
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.
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:
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 along the package path |
XDCscript - xdc.loadXML | Load an XML file |
XDCscript - xdc.loadTemplate | Create a template object from a template file |
聯(lián)系客服