search

Class myphysicslab.lab.util.Terminal

Provided By

Executes scripts and provides a command line user interface with separate text fields for input and output. Executes EasyScript or JavaScript. The JavaScript is a safe subset to prevent malicious scripts and work in strict mode. Allows use of "short names" to replace full name space pathnames of classes.

After the command is executed the result is converted to text and displayed in the output text field. The output is not displayed if the result is undefined or the command ends with a semi-colon.

See also Customizing myPhysicsLab Software.

Getting Help

Type help in the Terminal input text area and press return to see the help message. Several useful Terminal commands are shown. The help message also specifies whether the code was simple-compiled or advance-compiled.

Perhaps the most useful command is vars which shows the list of variables that are available.

Two Types of Scripts

Terminal can execute two types of scripts:

  1. JavaScript: a safe subset of JavaScript, where you can use short-names that are run thru #expand.

  2. EasyScript: a very simple scripting language for setting Parameter values. See myphysicslab.lab.util.EasyScriptParser for syntax details.

These two types of script can be intermixed in a single command as long as they are separated with a semicolon. For example, here are both types of scripts in one command:

DAMPING=0.1;GRAVITY=9.8;ANGLE=2.5;bob.fillStyle='red'

The first three commands are EasyScript commands that set Parameter values; the last is a JavaScript command.

In most applications the EasyScriptParser is available in the variable easyScript and you can use it to execute EasyScript within JavaScript. Examples:

easyScript.parse('angle')+0.1

easyScript.parse('angle='+Math.PI/2);

Safe Subset of JavaScript

To prevent malicious scripts from being executed, only a safe subset of JavaScript is allowed. See the book JavaScript: The Definitive Guide by Flanagan, section 11.1.2 'Subsets for Security'. JavaScript commands are executed via the JavaScript eval function under strict mode.

We prohibit access to most global variables including the window object which defines global variables. We prohibit usage of the JavaScript eval function and access to certain methods and properties of Terminal.

Square-brackets are only allowed when they contain a list of numbers. This is to prevent accessing prohibited properties by manipulating strings, for example the following is not allowed:

terminal['white'+'List_']

Arrays of objects other than numbers can be made using new Array(). Array access can be done using the built-in functions UtilityCore.get and UtilityCore.set.

Short Names

To allow for shorter scripts, we define a variety of regular expressions which convert short names to their proper long expanded form.

Most class names will have their equivalent short-name defined. For example you can type

new DoubleRect(0,0,1,1)

instead of

new myphysicslab.lab.util.DoubleRect(0,0,1,1)

Applications will typically make their key objects available as short-names. So instead of app.sim you can just type sim.

These short-names are implemented by defining a set of regular expression replacements which are applied to the Terminal input string before it is executed.

The methods #addRegex and #expand are how short-names are defined and used. Regular expressions are registered with Terminal using addRegex. Then whenever a command is evaluated it is first expanded to the long form using expand.

Terminal.stdRegex defines a standard set of regular expressions for expanding myPhysicsLab class names (like DoubleRect) and for expanding a few function shortcuts like methodsOf, propertiesOf and prettyPrint. An application can add more shortcuts via #addRegex.

To see the post-expansion names in the Terminal output, use #setVerbose.

The Result Variable

The result of the last Terminal command is stored in a variable named result. Here is an example Terminal session:

> 2+2
4
> result*2
8
> result*2
16

Note that #eval has an argument called output which if set to false prevents result from being updated.

Semi-colons End A Comment

Scripts are processed by splitting them into smaller scripts delimited by a semi-colon. Only semi-colons at the 'top level' of the script have this effect. Semi-colons within brackets or inside of a quoted string are ignored for command splitting.

An unusual result of this policy is that a semi-colon will end a comment. Here we enter // this is a comment; 2+2 which looks like a single comment, but it is interpreted as two separate scripts.

> // this is a comment;
> 2+2
4

URL Query Script

A Terminal script can be embedded into a URL query string which will be executed when the page is loaded. This provides a convenient way to share a customized simulation with someone else.

The script follows a question mark in the URL, so it is called a 'query script' or 'query URL'. Here is an example:

http://www.myphysicslab.com/PendulumApp_en.html?DRIVE_AMPLITUDE=0;
DAMPING=0.1;GRAVITY=9.8;ANGLE=2.5;ANGLE_VELOCITY=0;DRAW_MODE=lines

The URL Query Script is executed at startup by calling #parseURL or #parseURLorRecall. Most myPhysicsLab applications do this.

Because of percent-encoding we must substitute in the URL:

  • %20 for space
  • %22 for double-quote

See this character encoding chart to learn which other characters must be percent-encoded.

Session History

A session history feature recalls previous input lines; these are accessed using the up/down arrow keys. Command-K clears the output area.

This feature is only for the convenience of the Terminal user, and has no relation to the command storage feature.

Script Storage

To allow storage in HTML5 Local Storage of commands and later re-use, there are methods #remember, #recall, and #forget. This allows users to customize a simulation by remembering a specific script.

Most applications call {@parseURLorRecall} when starting, therefore whenever the page loads, the remembered script will be executed (unless there is a URL script which would take priority).

If no script is explicitly supplied to remember(), then the commands in the Terminal output window are saved, as returned by the method #commands. A user can edit the contents of the Terminal output window to change what is remembered. Commands are any line in the output text area that start with '> '.

The #remember command saves a script specific for the current page and browser. If you load the page under a different browser, or for a different locale (which is a different page), there will be a different stored script.

The z Object

Strict mode prevents adding global variables when using the JavaScript eval command. To allow making variables that persist between commands, Terminal provides an object named z where properties can be added:

> z.a = 1
1
> z.a
1

This z object is a property of Terminal; z is initially an object with no properties. We define a 'short name' regular expression so that referring to z is replaced by terminal.z when the command is executed.

Declaring a Variable

To hide the usage of the z object, Terminal interprets the var keyword in a special way.

When Terminal sees the var keyword at the start of a command, it changes the script to use the z object and defines a short-name. For example the command

var foo = 3;

will become

z.foo = 3;

and thereafter every reference to foo will be changed to z.foo in later commands.

The terminal Variable

Some features require that the name terminal is defined and resolves to the Terminal object. These features include the z variable, the result variable, and the usage of the var keyword.

In most apps this is accomplished by using #addRegex like this:

terminal.addRegex('terminal', myName);

where myName is the global name of the app, which is usually just 'app'. The purpose of the regex is to replace the word terminal with app.terminal which is a valid JavaScript reference.

(In unit tests of Terminal, we temporarily define a global variable named terminal.)

Advanced-compile is the Enemy of JavaScript

When using Advanced Compile only EasyScript can be executed in Terminal, not JavaScript code.

Advanced compilation causes all class and method names to be minified to one or two character names, so scripts based on non-minified names will not work. Also, unused code is eliminated, so desired features might be missing.

However, names that are exported can be used in HTML scripts under advanced-compile. For example, we export the eval method in myphysicslab.sims.layout.AbstractApp so that EasyScript can be executed via app.eval() even under advanced-compile. See Exporting Symbols.

JavaScript code is disabled under advanced-compile due to security considerations. The 'safe subset' strategy used here depends on detecting names in the script such as window, eval, myEval, whiteList_, etc. Because advanced-compile renames many of these, we are no longer able to detect their usage. For example, an attacker could figure out what the myEval function was renamed to, and enter a script that would call that function; this would not be detected by the 'safe subset' checking which is looking for myEval, not for whatever that method got renamed to.

new Terminal( term_input, term_output )

Parameters
term_inputHTMLInputElement

A textarea where user types input to evaluate

term_outputHTMLInputElement

A textarea where results are shown

Instance Methods

Instance Properties

Static Functions

Static Properties

Type Definitions