Lingo Scripting Basics

Computer languages tend to be simpler and more rigid than human languages, but like any other language Lingo has a set of rules that control the structure (syntax) of your Lingo program. Just as languages have grammar, Lingo’s syntactical rules restrict the spelling, vocabulary, and punctuation so that Director can understand your instructions.

Tip

A syntax error or script error usually indicates a typographical error or the incorrect use of a Lingo statement.

Lingo’s built-in keywords (or reserved words) make up Lingo’s vocabulary and are the building blocks of any Lingo program. We’ll see later how these keywords form the skeleton of your Director program, just as any language’s words are the basis for sentences and paragraphs. It is crucial that you recognize which items in a Lingo script are built-in keywords versus those that are specified arbitrarily by the programmer. Refer to Chapter 18, Lingo Keyword and Command Summary, for a complete list of all Lingo keywords. The PrettyScript Xtra (http://rampages.onramp.net/~joker/tools/) is a $20 U.S. shareware tool that colorizes some items in your Lingo scripts to make them easier to recognize. The ScriptOMatic Lite Xtra, is available under XtrasScriptOMatic➤Lite, colorizes a broader range of items, but it is crippled almost to the point of being useless. The full version is promised imminently from g/matter (http://www.gmatter.com/products/scriptomatic/) at press time.

Handlers and Scripts

A handler is a series of Lingo statements that tell Director to perform some useful function. Handlers are typed into script cast members in the Script window. (“Script” is also used loosely to refer to a handler within a script. “Code” is used both as a noun to indicate your Lingo scripts and as a verb, meaning “to program” or “to write Lingo scripts.”)

The scripts in a Director movie control the action, just as real-life actors follow a script. There are several types of scripts (castmember scripts, movie scripts, sprite scripts, parent scripts, and Behaviors), which are covered in detail in the "Lingo Scripts and Handler Types" section of Chapter 2.

Hello World

As required by the International Programmers’ Treaty of 1969, we’ll start with an example that displays “Hello World.” Open up a movie script cast member using Cmd-Shift-U (Macintosh) or Ctrl-Shift-U (Windows).

Enter Example 1-1 exactly as shown into the movie script window.

Example 1-1. Hello World

on helloWorld
  alert "Hello World"
end

The keyword on identifies the beginning of our handler, which we arbitrarily chose to name helloWorld. The keyword end signifies the end of our handler.

Tip

The examples beginning with the word on are handlers that must be typed into a script, not the Message window.

With minor exceptions, your Lingo code for each handler goes between the on handlerName and end commands (see "Where Commands Go“).

Handler names must be one word, but they are case-insensitive, so you can use capitalization to make them easier to read. Name your handlers descriptively so that you can remember what they do, and as a rule you should avoid naming them the same as existing Lingo commands (see Table 18-1).

A handler name must start with an alphanumeric character, not a digit, but it can contain digits, decimal points, and underscores. Only the first 260 characters of the name are significant.

Movie script cast members are simply repositories for our handlers and are not used in the Score (see Chapter 2 for details on score scripts).

Entering a handler into a script (as shown above) defines or declares the handler and is referred to as a handler definition. Defining (declaring) a handler makes it available for future use, but the handler doesn’t execute until something tells Director to run it for you.

Close the Script window to compile it (that is, to prepare it to run). When the handler is run (called), Lingo will execute each line (that is, each command) in the order in which it appears in the handler. There is only one command in our helloWorld handler; the built-in alert command displays the specified text in an alert dialog box.

The Message window provides an area for printing messages from Lingo and testing Lingo scripts (see Chapter 3, Lingo Coding and Debugging Tips). A handler stored in a movie script can be executed (called) by typing its name in the Message window (or by using its name in another handler).

Open the Message window using Cmd-M (Macintosh) or Ctrl-M (Windows). In the Message window, type the name of the handler to test (helloWorld without any spaces). Do not precede the name with the word on, which is used only to declare a handler, not to run it.

helloWorld

Tip

Always press the RETURN key (Macintosh) or the ENTER key (Windows) at the end of the line to initiate the command. Example code shown flush left should be typed into the Message window, as opposed to handler definitions that are entered in the Script window.

Congratulations, you are now a Lingo programmer! After accepting your diploma, please step to the right. If your script didn’t work, make sure you typed everything correctly and that you entered the script in a movie Script window (not a score script, castmember script, field, or text cast member). Choose ControlRecompile All Scripts. If it still fails, hang your head in shame, or see Chapter 3 and Chapter 4.

Calling All Scripts

Typing helloWorld in the Message window calls (locates and runs) the handler of the same name. Reopen the script, and change both the name of the handler in the script and the name you type in the Message window to something new. If the names don’t match, what happens? Did you remember to recompile the script by closing its window? Set the Using Message Window Recompiles Scripts option under PreferencesGeneral to ensure that the latest version of a handler is executed. See "Compiling Scripts" later in this chapter.

Note above that "Hello World" is automatically incorporated by the alert command into the alert dialog. You can change the displayed text by specifying any string (series of characters) in place of "Hello World" (don’t forget the quotes). The specified string is said to be an argument to the alert command, and it is used to customize the dialog. See "Commands and Functions" and "Parameters and Arguments" later in this chapter for complete details on using arguments with built-in Lingo commands and custom handlers.

Previously we created an arbitrarily named custom handler and called it from the Message window by using its name.

Tip

You can add more handlers after the end of the helloWorld handler in the movie script used above, or you can press the “+” button in the Script window to create a second movie script. (You can have a virtually unlimited number of movie scripts).

Naturally, the user will not be typing anything in the Message window. When the user clicks the mouse button or presses a key Director tries to run handlers named on mouseDown, on mouseUp, on keyDown, and so on. In practice, you’ll create event handlers with these reserved names to respond to user events. If you name the handlers incorrectly, they will never be executed. See the "Events" section in Chapter 2, and Chapter 9 for more details.

Nested Handler Calls

Just as we can call a handler from the Message window, one handler can call another simply by using its name. As each handler completes its work, control returns to the calling handler. You can picture a hierarchy of nested handler calls as an outline that periodically is indented further, then returns to the previous level. Suppose we define several handlers (some of which call other handlers) in a movie script as shown in Example 1-2.

Tip

The put command prints a message in the Message window and is used throughout the book to peek inside Lingo. The && and & operators are used to assemble long strings (see Chapter 7, Strings). Lingo lines starting with two hyphens (“—”) are comments for the reader’s benefit (see "Comments,” later in this chapter).

Example 1-2. Nested Handler Calls

Nested Handler Calls

We can then test it from the Message window.

handlerA
-- "I'm in handlerA"
-- "I'm in handlerB"
-- "I'm in handlerD"
-- "I'm back in handlerB"
-- "I'm back in handlerA"
-- "I'm in handlerC"
-- "I'm back in handlerA one last time"

Tip

The series of Lingo handlers that are currently “pending” is known as the call stack. The call stack is always shown in the upper left pane of the Debugger window (see Figure 3-1).

Note that handlerA calls handlerB, which then calls handlerD. Control then passes back through handlerB and back to handlerA. Finally, handlerA calls handlerC, and control is then returned to handlerA. Conceptually, this can be pictured as:

handlerA
  handlerB
    handlerD
  handlerC

Note that the order of execution within a handler is determined by order of the Lingo commands, but the order in which the four handlers are typed into the movie script is irrelevant. Execution begins at our so-called entry point (in this case handlerA, which was called from the Message window), and Lingo takes detours into each called handler before it returns control to the calling handler. Note that handlerE is never called and therefore never executed, even though it has been defined in the same script with our other handlers.

Recursion

Each time a handler is called, a copy of it is created temporarily. The copy comes into existence when the handler is called and disappears when the handler completes. You can call a handler hundreds of times, and each occurrence will be independent of the other occurrences. A handler that calls itself, as shown in Example 1-3, is called a recursive function, and this technique is called Recursion.

Warning

If we call our recursive function from the Message window, Director will run out of memory. (Save your work before testing this as it may crash your machine.)

Example 1-3. A Recursive Function

on recurseTest
  recurseTest
  put "End of recurseTest reached"
end recurseTest

If you are using recursion, it is probably an accident. As a general rule, you should avoid it. It is like a reflection repeated infinitely between two mirrors; in the extreme case it will crash Director. See Example 6-9 in Chapter 6, Lists, Example 8-16 in Chapter 8, Math (and Gambling), and Example 14-5 in Chapter 14, External Files, for proper uses of recursion.

Even if we call recurseTest only once, it calls itself repeatedly so that Director keeps going “down” an extra level and never comes back up for air. Director will run out of memory before the put “End of recurseTest reached” command is ever reached. Note that each time recurseTest is called, it spawns another copy of itself. Conceptually, this can be pictured as follows:

recurseTest
  recurseTest
    recurseTest
      recurseTest
        (ad infinitum until Director runs out of memory)

Note that it is perfectly acceptable for one handler to call another repeatedly, as is often done using a repeat loop (see "Repeat Loops" later in this chapter).

Example 1-4. Calling a Function Non-recursively

on testIt
  repeat with i = 1 to 100
    someHandler
  end repeat
end

on someHandler
  put "I am inside someHandler"
end

Typing testIt in the Message window will print out "I am inside someHandler" 100 times with no ill effects because each time someHandler completes, control is returned to the top level (in this case, the testIt handler).

Entering and Compiling Scripts

There is no magic to entering Lingo scripts. Scripts are typed in script cast members (or attached to non-script cast members) via the Script window. Script cast members appear in the Cast window along with your other assets (bitmaps, fields, and so on). The Script and Message windows include buttons to access pop-up menus of Lingo commands (both alphabetical and by category). You can use these to insert commands into your scripts or to remind you of the correct syntax. Refer to Chapter 2 of this book and to Chapter 2, Script Basics, of Macromedia’s Learning Lingo manual for details on creating scripts and entering your Lingo.

Where Commands Go

All your Lingo code goes between a handler’s on handlerName and end statements.

The exceptions to the rule are:

  • Each handler should be separate from other handlers. Handler declarations are not “nested” the way that if...then statements can be. Do not start a new handler before end'ing the first one, as described under "Common Handler Declaration Errors" later in this chapter.

  • Comments can be placed both inside and outside handlers.

  • Property variables must be declared outside any handler.

  • Global variables can be declared both inside and outside handlers. Global variables declared within a handler apply only to that handler. Global variables declared outside a handler apply to all handlers in the script following the declaration.

Each Lingo command occupies its own line (although there are some multiline Lingo statements, discussed under "Multiline Code Structures" later in this chapter). Each line of Lingo is separated using a carriage return—that is, using the Return key (Macintosh) or Enter key (Windows) on the main keyboard, not the one on the keypad.

You can enter long lines of Lingo code in your script without line breaks; Director will wrap them automatically. To improve readability (as with many examples in this book), long lines of Lingo code can be continued onto the next line using the Lingo continuation character ¬, as shown in the example that follows. This special character is created using Option-Return (Macintosh) or Alt-Enter (Windows).

-- Here is a long line of Lingo broken onto two lines
set the member of sprite (the currentSpriteNum) = ¬
   member "Hilighted Button"

You can break long lines of Lingo onto more than two lines using an ¬ character at the end of each line (except the last) of the long command. Do not break the long lines (that is, do not use the ¬ character) within quoted strings (see Chapter 7, Strings). Do not put anything, even a space, on the same line after a continuation character.

Director ignores leading spaces and automatically indents your Lingo code according to its own rules. For example, all lines within a handler between the on and end statements are indented at least two spaces. Use the same font and type size throughout the script to make the code more legible and indentation problems obvious. Colorized or formatted text can slow the Script window’s response, especially for longer scripts. A single script cast member is limited to 32,000 characters, but you can use as many script cast members as required.

Warning

Use the Tab key to automatically indent your Lingo code. If the indentation is wrong, you may have omitted necessary keywords or used them in the wrong order. Refer to "Lingo’s Skeletal Structure" later in this chapter.

The Lingo code you enter is simply text (although you should enter it in a script cast member, not in a text or field cast member). Before it can be run, Director must compile your Lingo code into a machine-readable format. (This is analogous to a player piano, which cannot read sheet music but can play a song if is transcribed onto a paper roll.)

When Director compiles a script, it checks that the syntax conforms to the accepted rules and does its best to parse (understand) the structure of your Lingo. Compilation is analogous to spellchecking and grammar checking in a word processor. It merely checks that your Lingo code has a recognizable structure and acceptable keywords. It does not attempt to actually run your Lingo code.

It would be counter-productive for Director to attempt to compile your scripts as you type them. Use ControlRecompile All Scripts to compile your scripts when you finish typing (see "Compiling Scripts" in Chapter 2).

If Director’s compiler fails, it displays a script error (a syntax error) that identifies the offending portion of the Lingo, but it may merely reflect a problem that lies elsewhere. You would then correct the Lingo and recompile. If successful, it creates a hidden compiled version of your Lingo script that runs more quickly than it would if Director had to reinterpret your human-readable script every time it runs.

If compilation succeeds, your code is not necessarily error-free and may still cause a so-called runtime error when Director attempts to run it. (In this context runtime refers to when the script is executed, as opposed to when it is compiled. This should not be confused with authoring time (in Director) vs. runtime (in a Projector). Refer to Chapter 3 for more details.

Handler Scope

Handlers are stored in script cast members (excepting those attached directly to other member types); the multiple types of script cast members are explained in great detail in Chapter 2. The script cast member’s type (movie script, score script, or parent script) affects the scope of all the handlers declared within it (that is, which other scripts can “see” these handlers and from where they are accessible). We were able to test the example handlers above from the Message window because they were entered in movie scripts. (A movie script is a script cast member whose type is set to Movie in the script cast member’s info window). Handlers in movie scripts can be “seen” from the Message window or any other script in the same Director movie (even from scripts in other linked castLibs) because they have universal scope.

Had we entered the example handlers in score scripts, attempting to use them from the Message window would result in a "Handler not defined" error because the scope of score scripts is more limited.

If two handlers in the same script cast member have the same name, Director will complain. Neither should you use two handlers with the same name in two different movie scripts because the first handler found will intercept all function calls using that name, and the second handler will always be ignored.

Tip

Place any handlers that you use in multiple Director movies or multiple Director projects into movie scripts in an external cast library that you can link into your project. Use unique names, perhaps starting with a prefix such as "lib,” that are unlikely to conflict with other handlers in a given movie.

Avoid naming your handlers the same as existing Lingo commands (see Table 18-1). A custom handler (stored in a movie script) that has the same name as a built-in Lingo command will intercept (and override) any calls to that Lingo command. If accidental, such an error can be extraordinarily hard to debug.

Contrary to movie scripts, it is very common to use handlers of the same name in score scripts. (Again, these are explained in detail in Chapter 2.) The important point is that the handlers in score scripts have a different scope (accessibility) than handlers in movie scripts. For example, most sprite scripts (one type of score script) will contain on mouseUp handlers, and most frame scripts (another type of score script) will contain on exitFrame handlers. The same handler name can be used in multiple score scripts because they do not have universal scope as do handlers in movie scripts. Director automatically calls only those handlers that are attached to the current frame or the sprite on which the user clicked. Other on mouseUp and on exitFrame handlers located in other score scripts won’t interfere. Refer to Chapter 9 for more details. Likewise, Lingo calls an on keyDown handler only if it is attached to the field sprite that has keyboard focus (see Chapter 10).

Example 1-5 demonstrates the different scope of a handler depending on the script type in which it exists.

If the following two handlers coexist in the same score script cast member, handlerA can call handlerB (or vice-versa).

Example 1-5. Handler Scope

on handlerA
  handlerB
end

on handlerB
  put "I am doing something, so please stop hovering."
end

If the two handlers existed in two separate score scripts, however, they would not “see” each other and therefore could not call each other. On the other hand, if handlerA was in a score script, but handlerB was in a movie script, handlerA could call handlerB, but not vice-versa. Furthermore, if handlerB is in a movie script, it can be called from other handlers in other scripts of any type. Therefore, you should place one copy of your general-purpose utility handlers in a movie script rather than replicating it in multiple score scripts.

Tip

Handlers in movie scripts can be called from anywhere at any time and are usually custom handlers named arbitrarily by the programmer. Handlers in score scripts are generally named to respond to predefined events (such as mouseUp) and are called by Director in response to those events.

This example offers a simplified picture of the universe. In actuality, any handler in any script can be called from anywhere if you refer to the script explicitly. You usually refer only to the handler name and let Director decide in which script to find the handler. This is covered in Chapter 2, along with details on the way that handlers in multiple scripts are sometimes called in succession.

See "Special Treatment of the First Argument Passed" later in this chapter for details on how the first argument to a function affects which scripts are searched for a matching handler.

Commands and Functions

A command tells Director to do something, such as play a sound, but usually does not return any result. Built-in Lingo keywords are referred to as commands, but you can create custom handlers that are used just like the built-in commands, essentially extending Director’s command set. (The word command is also used loosely in many contexts, including to indicate a menu choice.)

The general format of a command is:

commandName arg1, arg2, arg3, ...

where the arguments (arg1, arg2, arg3, ...) are inputs used by the command, and may be optional or mandatory, and vary in number and type depending on the command. For example, the alert command shown previously expected a single string argument. The puppetSprite command expects two arguments (an integer and a Boolean value), as in:

puppetSprite 17, TRUE

A command that returns a result is called a function (the terms, though, are often used interchangeably). The result may be a number, a string, or any other data type. The general format of a function is

set variableName = functionName (arg1, arg2, arg3, ...)

or put functionName (arg1, arg2, arg3, ...) into variableName

where again the arguments (arg1, arg2, arg3, ...) may be optional or mandatory and may vary in number and type depending on the function.

For example, the power() function requires two arguments and raises the first argument to the power specified by the second argument. You wouldn’t ordinarily compute a value and discard the result; you would either print it out in the Message window or store it in a variable (a container for data). Below, the result of the calculation is stored in a variable that is arbitrarily named myValue (see "Variable Storage Classes and Data Types" later in this chapter for details on variables).

set myValue = power (10, 2)

If you don’t store the result in a variable, the function still returns a result that can be used in other expressions (see Chapter 5, Data Types and Expressions). This prints the result in the Message window instead of storing it in a variable:

put power (10, 2)
-- 100.0000

This uses the result of the calculation to decide whether to print a message:

if power (10, 2) > 50 then put "That's a big number."

In some cases, Director issues a "Command not defined" error if you use a function by itself rather than as part of a larger expression:

power (10, 2)  -- This causes an error

Either use put power (10, 2) to print the result of the function call in the Message window or assign the result to a variable, as shown earlier.

If a function does not require any arguments, you must still include the parentheses to obtain the result, such as:

put browserName()
-- "Mac HD:Netscape Navigator Folder:Netscape Navigator"

See "Return Values and Exiting Handlers" later in this chapter for details on returning values from custom handlers.

Lingo allows nested function calls, in which the result of one function is used as an argument to another function, such as:

if (random(max(x, y)) > 5) then ...

In such a case, the result of max(x, y) is used as an argument to the random() function. The preceding code is just shorthand notation for:

set myValue = max(x, y)
if (random(myValue) > 5) then ...

Return Values and Exiting Handlers

This section is next in the logical progression of the chapter, but it will not make sense unless you understand concepts explained later. You can skim it now and revisit it after reading the rest of the chapter. As alluded to earlier, a handler often performs a calculation and returns the result to the calling routine. A handler or Lingo command that returns a value is called a function. Most functions require some inputs on which to operate (see "Parameters and Arguments" for details). For example, the built-in Lingo function max() returns the maximum value from the list of items you send it:

put max (6, 9, 12)
-- 12

You might write your own custom function that returns TRUE or FALSE based on whether the input is a valid digit between 0 and 9, as shown in Example 1-6.

Example 1-6. Returning a Value from a Function

on isDigit someChar
  if "0123456789" contains string (someChar) then
    return TRUE
  else
    return FALSE
  end if
end isDigit

In this case, the result (1) signifies the Boolean value TRUE:

put isDigit (5)
-- 1

Warning

The parentheses surrounding the arguments are mandatory when calling a function that returns a value. Even if the function does not require any parameters, you must still include the parentheses to obtain a result.

If the parentheses are omitted, Lingo would treat isDigit as if it were a variable name (see "Variables and Properties" later in this chapter) rather than a function name. In the following case, isDigit is mistaken for a VOID (valueless) variable, and the put statement prints the values VOID and 5 instead of the desired result of the function call.

put isDigit 5
VOID 5

Note the use of parentheses following rollover():

put rollOver()   -- rollOver() is treated as a function call
-- 7
put rollOver     -- rollOver is treated as a variable name
-- VOID

Leaving the Current Handler

Ordinarily a handler terminates when the last statement in it is reached (the end statement). Control then returns to whatever called the handler (either another handler or Director itself). In that case, no value is returned to the calling handler, and any calculated result would be lost unless it were stored in a global or property variable. The return and result commands obtain return values from a handler. The abort and exit commands terminate a handler prematurely. (They differ from next repeat and exit repeat, which affect program flow but do not exit the handler). The quit, halt, restart, shutDown, go, play, play done, and pass commands may also affect the order of Lingo execution.

return

The return command exits the current handler and returns control to the calling routine, along with an optional value of any data type. Any statements following the return are not executed, which makes return convenient for exiting a handler once a particular condition is met or task is completed.

Example 1-7 returns as soon as it finds a sound cast member in the primary castLib. It returns zero (0) if no sound cast member is found. The other details are not important at this point.

Example 1-7. Returning Prematurely from a Function

on findFirstSound
 -- Loop through the cast
 repeat with n = 1 to the number of members
  -- Look for a sound castmember
    if the type of member n = #sound then
         -- Return the number of the sound
         -- and we're out of here!
      return n
    end if
  end repeat

     -- If no sound  was found, return 0
  return 0
end findFirstSound

Test it in the Message window:

put findFirstSound()
-- 72

Warning

The above technique is best used with small handlers. Avoid using multiple return statements to exit a large handler from many different points. It makes the code harder to understand and maintain. Storing the eventual return value in a variable and returning it at the end of the handler is often clearer.

You can use return without a value, in which case it is identical to exit, and the caller receives VOID as the returned value. Note that the return command is distinguished by context from the RETURN constant (which indicates the carriage return character).

the result

The result retrieves the result of the last function call, even if it was never stored in a variable when it was returned by the last function call.

set x = isDigit (5)
put x
-- 1
isDigit (5)
put the result
-- 1

Some commands, such as preLoad and preLoadMember, do not return a value, but set the result.

preLoadMember 1, 5
put the result
-- 5
abort

Abort aborts the call stack (that is, the current Lingo handler and any handlers that called it) without executing any of the remaining Lingo statements in any of those handlers. By contrast, exit exits only the current handler. Abort is useful when you want to stop the current action in response to some drastic change. For example, if the user presses the Escape key, you may abort what you are doing:

on getUserInfo
  -- Abort if the user hits ESCAPE (ASCII code 27)
  if the key = numToChar (27) then
    abort
  end if
end getUserInfo

Abort does not quit Director (see halt or quit), nor does it abort asynchronous operations in progress (see cancelIdleLoad, netAbort). Abort aborts only Lingo execution; it does not affect the Score’s playback head (see the pause command).

exit

Exit (not to be confused with exit repeat) causes Lingo to exit the current handler. It exits “up” only one level to the calling handler, as opposed to aborting the entire call stack (see "Nested Function Calls" earlier in this chapter). Exit is often used to exit the current handler if some condition is not met:

on playVideo
  if not (the quickTimePresent) then
    alert "You can't play video without QuickTime."
    exit
  end if
        -- Remaining statements are run only
        -- if QuickTime is installed.
end playVideo

When using exit, no return value is sent. Use return instead to return a value to the calling handler.

quit, halt, restart, and shutDown

Quit and halt immediately quit a Projector and are generally used only in a script attached to a Quit button or at the end of a presentation. During development, halt stops the movie without quitting Director. See Chapter 8, Projectors and the Run-time Environment, in Director in a Nutshell for details on these and other commands, including restart and shutDown.

go

The playback head moves semi-independently remaining of Lingo commands. If you use the go command to move the playback head, commands in the handler are still executed before jumping to the new frame.

                    on exitFrame
  go frame 50
  put "This will be printed before jumping to frame 50"
end
play and play done

The play command works differently than the go command. Commands following the play command are executed, but not until a play done command returns control back to the original script. Commands following play done are never reached. Test this using a frame script of the form:

on exitFrame
  play frame 50
  put "This will be printed second, not first"
end

In frame 50, use this frame script to complete the test:

                    on exitFrame
  put "This will be printed first"
  play done
  put "This line won't ever be reached or printed"
end
pass

The pass command aborts the call stack (see the abort command). Commands following the pass command are never executed. Control immediately jumps to the next script that handles the event being passed (see Chapter 2). For example:

on mouseUp
  pass
  put "This line won't ever be reached or printed"
end

Dynamic Script Creation

This section is next in the logical progression of the chapter but is fairly advanced—and irrelevant for most users. You can skim it or even ignore it altogether without significant regret. You can create new Lingo dynamically at runtime (that is, while Director or even a Projector is running). Using the do command or by setting the scriptText of member property, you can actually create new Lingo from within Lingo! You can dynamically evaluate a string as if it is a Lingo statement using the value() function. Most programming languages don’t allow this, and you will rarely use this feature. The following examples are for illustration only and do not necessarily depict likely uses.

Do Statements

The do command can compile and execute a string on the fly as if it were a Lingo statement. Although it should not be used haphazardly, it can perform some interesting tricks. Most notably, you can use it to execute an arbitrary command stored in a text file or a field cast member. You can create a pseudo-Message window for debugging Projectors by do‘ing the text entered in a field cast member:

do "beep"
do the text of field "someFieldCastMember"

You cannot use do to declare global variables without a trick. The following will not work:

do "global gSomeGlobal"
do "set gSomeGlobal = 5"

To declare a global with a do statement, use:

do "global gSomeGlobal" & RETURN & "set gSomeGlobal = 5"

To make use of a global within a do statement, declare the global inside the current handler. So-called “global globals” declared outside the currrent handler are not recognized during a do statement. The following example is illustrative only and would never be required in reality:

on setGlobal
  global gSomeGlobal
  do "set gSomeGlobal = 7"
end

Value Statements

The value() function can be used to convert a string into an integer or a float, as is useful when converting string data from a file or user input into a number.

set userEntry = value (field "Age in Years")

Value() can also evaluate a string or symbol as if it is a variable name:

set someVar = "Oh happy days!"
put value ("someVar")
-- "Oh happy days!"
put value (string(#someVar))
-- "Oh happy days!"

Setting the ScriptText at Runtime

The scriptText of member property contains the Lingo code from a script cast member. The human-readable form of the scriptText is stripped when creating Projectors and protecting DIR files (creating DXR files), leaving only the hidden internal compiled version. Even from a Projector, you can create a script dynamically, as shown in Example 1-8.

Example 1-8. Creating Scripts at Runtime

-- Set up a string variable containing the text:
on createscript
  set dynaScript = "on newHandler" & RETURN ¬
                     "global gMyGlobal" & RETURN ¬
                     "set gMyGlobal to 52" & RETURN & "end"
-- Create a new movie script cast member, and fill it in.
  set newMovieScriptCastMember = new(#script)
  set the scriptType of newMovieScriptCastMember = #movie
  set the scriptText of newMovieScriptCastMember = dynaScript
end
-- Now you can run it
createscript
newHandler
-- If desired, you can then delete the cast member
erase newMovieScriptCastMember

Get Lingo in a Nutshell now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.