Language Structure

[ LiB ]

Language Structure

As I mentioned, executions of Lua are broken down into units called chunks . Chunks are simply sequences of statements, and are basically equivalent to program blocks. Lua handles a chunk just like any language handles a function, so chunks can hold local variables and return values.

Chunks may be stored in a file or in a string inside the host program. When a chunk is executed, first it is precompiled into byte-code for the Lua virtual machine, and then the compiled code is executed by an interpreter for the virtual machine. Lua has no declarations, so a chunk may be as simple and short as a single statement:

 chunk ::={single statement} 

Or it can be big and complex:

 Chunk ::={         event_buffer = nil,         last_update_ticks = 0,         begin_time = 0,         elapsed_ticks = 0,         frames = 0,         update_period = 33         active = 1,         screen = nil,         background = nil,         new_actors = {},         actors = {},         add_actor = function(self, a)                 assert(a)                 tinsert(self.new_actors, a)         end } 

Punctuation

Lua uses C- and Pascal-like punctuation. This takes a bit of getting used to, especially when you're just coming from Python. While Python uses spaces and tabs to keep statements separated, Lua utilizes brackets, quotes, parentheses, squiggly lines, and other deliminators, and spaces and tabs are pretty much ignored, which can be confusing at first. A good practice is to use the interpreter often; because the interpreter expects code to be properly bracketed off, it

NOTE

I talked a bit about Pascal in earlier chapters when discussing the history of computer languages. As you may recall, Pascal is a high-level struc tured programming language, which forces design with a very regimented structure.

will complain immediately if you return a line of Lua that's missing something. For example, see Figure 6.2, in which our friendly interpreter reminds me that I left off the second " in the string assignment.
Figure 6.2. The Lua interpreter complains that I've left off something important

graphic/06fig02.gif


Statements in C are normally ended in a semicolon. In Lua this is optional, but you will still see it commonly done:

 a=1 b=2 --equivalent to a=1; b=2; --equivalent to a=1;b=2; 

Language Types

Lua is a dynamically typed language, so variables themselves do not have types; only the values of the variables have types. The basic types in Lua are shown in Table 6.2:

Variables created in Lua are visible within the blocks in which they are created and are considered global unless the area is specifically defined as local using the local keyword. After a code block is executed, local variables are destroyed .

Booleans

In Lua, all values different from false or nil are considered true . This means that only nil and Boolean false are considered false for the purposes of statement execution; everything else is considered true . As of Version 5.0, Lua has a built-in Boolean recognition of true and false .

Try running the following lines in the Lua interpreter:

Table 6.2. Built-in Data Types

Name

Data Held

Boolean

Either false or true

function

Function stored as a variable

nil

Value nil

number

Real numbers (double precision floating point)

string

Character string

table

Associative array (i.e., dictionary / hash )

thread

Independent threads of execution

userdata

C pointers stored as variable


 x = true print (x) print (not x) 

You will see that the interpreter is smart enough to know that if something is not true , then it must be false . You can use Lua to test Boolean validity by using two equal signs to represent "is equal to," like so:

 print (0==100) print (1 ==1) 

Note that in Lua, true and false are not numerical values (0 and 1) like in some languages.

Functions

A really wonderful feature of Lua is that you can assign functions to variables. In fact, when you define a function in Lua, you are basically assigning the text body of the function to a given variable. Functions are declared by using the function keyword, with the general syntax being:

 function name(args) does_something end 

where name is the name of the new function, args is any arguments the function takes, does_something represents what the function actually does, and end tells Lua the function is over.

For example, here is a quick function that prints a statement to the screen:

 function Myfunction() print("What's your function?") end 

After creating a function, you can call it at will:

 Myfunction() 

You can also print the value of the function's memory address using print :

 print (Myfunction) 

When you run this last line in the interpreter, you can see that Lua notices that it's dealing with a function as well as returning its memory address.

Functions can take arguments as well, like in this example that takes an argument and assigns it to X :

 function Myfunction(X) print(X) end 

When you call this function with Myfunction(1) , the interpreter prints out what is assigned to X in this case a 1. You could also assign the function a string with Myfunction("hello") . If no argument is passed to the function, Lua automatically assigns nil to the argument, and in the case of Myfunction() , the interpreter prints nil .

Since functions can be stored as variables in Lua, they can then be passed as arguments to other functions or they can be returned. This makes them fairly powerful creatures in Lua-land.

Nil

Nil values mean that a variable has no value. You can set values to nil to delete them:

 x = nil 

and you can test to see whether a variable exists by checking to see if its value is nil :

 print (x==nil) 

Nil is the equivalent of no value, so if a variable is assigned nil , it ceases to exist.

Numbers

Lua supports the standard add ( + ), subtract ( - ), multiply ( * ), and divide ( / ) operators. These can be fun to play with after firing up the lua.exe and using the print statement:

 print (1+1) print (5*5) print (10/9) 

If you run these lines in the interpreter, you will notice that Lua automatically brings in floating point numbers and gives you 1.11111111 as an answer to the third chunk. Lua doesn't bother with rounding off like many other languages do. All numbers in Lua are "real" numbers stored in floating point format.

You can assign numbers to variables by using the = sign:

 X=100 print (x) 

Lua also supports multiple assignments:

 x, y = 2, 4 print (x,y) x,y = y,x print (x,y) 

NOTE

The act of setting the value of a variable is called an assignment .

Lua supports the standard arithmetic relational operators, including

+

-

*

/

^

==

~=

<

>

<=

>=

These should be pretty familiar to you by now. Lua also understands logical and , or , and not . Logical not inverts a logical expression:

 not true = false 

while logical and and or can be used and combined to form the logical statements programmers often need:

 true or false x = true and y = true 

NOTE

CAUTION

Lua does exhibit some strange behavior when ordering precedence in an equation. This behavior shows up when running through equations from left to right and right to left. Normally, Lua figures out the left side of the equals sign first, but the order in which multiple assignments are performed is actually undefined. For instance, if the same values or tables occur twice within an assignment list, then Lua may perform the equation from right to left. The order precedence may also be changed in future versions of Lua. This can be a hassle, but it simply means that you should always use separate assignment statements when possible.

An important topic for numbers and running equations is operator precedence, which is illustrated in Table 6.3.

Table 6.3. Lua Operator Precedence

Precedence

Operator

1.(highest)

^(exponentiation)

2.

not - (unary)

3.

* /

4.

+ -

5.

..(string concatenation)

6.( lowest )

< > <= >= ~= ==


Lua has an additional library that interfaces with the common C Math library functions. The library is available for access by Lua with a luaopen_math function and include a number of fun math tricks that should look familiar to C users and Math whizzes. The functions are listed in Table 6.4.

Table 6.4. Additional Math Lua Library Functions

Function

Use

math.abs

Absolute value

math.acos

Arc cosine

math.asin

Arc sine

math.atan

Arc tangent

math.atan2

As atan but uses signs of the arguments to compute quadrant of the return value

math.ceil

Ceiling, returns smallest integer no less than given argument

math.cos

Cosine

math.exp

Exponent

math.floor

Returns largest integer no greater than given argument

math.frexp

Turns argument number into mantissa and exponent

math.ldexp

Returns X*(2^exp)

math.log

Logarithm

math.log10

Base-10 logarithm

math.mod

Splits given into integer and fraction parts

math.pi

Pi (3.14)

math.pow

Power, the base raised to exp power

math.sin

Sine

math.sqrt

Square root

math.tan

Tangent

math.random

Random number

math.randomseed

Seed number for random


These functions all follow a similar pattern when used. Let's say I wanted the value of pi. I'd do this:

 MyPy = (math.pi) print (MyPy) 

If I needed to find the tangent of a given number, I'd do this:

 MyTan = (math.tan(10)) print (MyTan) 

Strings

Lua supports strings as text variable types. You can assign strings just like you would numbers, but you must be sure to include the quotes and parentheses, like so:

 myself = ("me") print (myself) 

You cannot use operators like + to concatenate strings, but Lua does allow you to concatenate strings using two periods, like in the following:

 myself = ("me") print ("Hello to "..myself) 

Besides double quotes, you can also set up strings using single quotes or double square brackets, as in the following:

 --this myself = ("me") --is equivalent to this myself = ('me') --is equivalent to this myself = ([[me]]) 

Lua supports these various methods so that you can place quotes within strings without using nasty escape sequences:

 Mystring = ([["quote"]]) print (Mystring) 

But Lua does support the standard C-type escape sequences when using strings. These sequences are listed in Table 6.5.

Table 6.5. Lua Escape Sequences

Sequence

Translates to

\a

System beep

\b

Backspace, deletes the last character typed

\f

Form feed

\n

Newline

\r

Carriage return

\t

Horizontal tab

\v

Vertical tab

\\

Backslash

\"

Double quote

\'

Single quote


It is important to note that when indexing a string in Lua, the first character is at position 1 (not at 0, as with C).

Brackets have further uses when you're creating strings. For instance, they can be used to place strings on several lines of code, as shown in Figure 6.3.

Figure 6.3. Using brackets to input a string over multiple lines

graphic/06fig03.gif


Lua comes packaged with additional library string functions. These are not necessary to import Lua but are very helpful if you are working on an application with heavy string handling. These functions are listed in Table 6.6; the library is opened with the luaopen_string function.

Table 6.6. Lua's String-Handling Library

Function

Purpose

string.byte ()

Returns the internal numerical code of the character

string.char ()

Returns a string of given length and internal numerical codes

string.dump ()

Returns binary representation for a given function

string.find ()

Uses pattern matching to find the first match of a given string

string.len ()

Returns a string's length

string.lower ()

Returns a copy of a given string in all lowercase letters

string.rep ()

Returns a string concatenated to specifications given

string.sub ()

Returns a substring of the given string

string.upper ()

Returns a copy of a given string in all uppercase letters

string.format ()

Returns a formatted version of a given string using C's printf style of arguments and rules

string.gfind ()

Used to iterate over strings to match pattern

string.gsub ()

Returns a copy of a given string after running given arguments over the specific string


The string library also has built-in functions for pattern matching, allowing Lua to search through long strings or tables, match up patterns, and return them (called capturing ). These controls are normally preceded by modulus ; they are outlined in Table 6.7.

Table 6.7. Common Pattern-Matching Controls

Symbol

Pattern

.

All characters

%a

All letters

%c

All control characters

%d

All digits

%l

All lowercase letters

%p

All punctuation characters

%s

All space characters

%u

All uppercase letters

%w

All alphanumeric characters

%x

All hexadecimal digits

%z

Character with representation 0


Using these functions to find patterns and matches is relatively straightforward using string.find . For instance, here is a Lua chunk that searches for the letter "o" in the given string:

 MySearch = string.find('word', 'o') print (MySearch) 

When this chunk is run in the Lua interpreter, you are given the location of o in the string, which is the second character location, right after 'w' which is first.

Let's say that you wanted to find four-letter words that begin with s in a given string. You can use period ( . ) as a wildcard:

 Mystring = 'Blah blah blah blah sand blah' Mystring2 = (string.find(Mystring, 's...')) print (Mystring2) 

This chunk will find the word sand in the string at the 21st character location after the first four Blahs.

Tables

Tables are the main data structure in Lua. Let me repeat that, because it's important: Tables are the main data structure in Lua . Instead of lists or tuples or dictionaries, Lua utilizes tables as its primary data holder. Tables are Lua's general-purpose data type and are capable of storing groups of objects, numbers, strings, or even other tables. Tables are created using curly brackets, like so:

 Mytable = {} 

If you were to print out Mytable (using print (MyTable) ), you would get a funny number, something like 0032bb99. This is the unique identifier and memory address that Lua has assigned to Mytable .

Tables are used everywhere in Lua. They are the basic building block to creating all of the important programming constructs like queues, linked lists, and arrays. Tables can also function more like hashes and dictionaries than arrays and lists. You can add hash-like objects to a table by assigning a key/value pair, like so:

 Mytable = {Mynumber = 1, Myword = "Ikes!" } 

You can then refer to the table with the familiar

 print (Mytable.Mynumber) print (Mytable.Myword) 

Tables can also be used in an array/list-type way. You do this by creating a comma-separated list of objects when creating the table. You can then access the table like an array, using brackets and numeric references, like so:

 Mytable = { 1,2,3,4,5,6,7,8,9,0 } print (Mytable[1]) 

Notice, when you run this chunk in the interpreter, that the array/table starts at 1, not 0. The 0 value is actually assigned nil , or no value.

You can mix a dictionary-type table and array-type table together, making tables pretty versatile little buggers. Tables can also contain other tables:

 Mytable = { table1= {a = 1, b = 2}, table2={c = 3, d = 4}} 

Additional ways to manipulate tables are possible using the additional library functions listed in Table 6.8.

Table 6.8. Table Functions

Function

Purpose

table.concat ()

Returns concatenated tables

table.foreach ()

Used to execute a given function over all elements of a table

table.foreachi ()

Executes given function over numerical indices (only) of table

table.getn ()

Returns the size of the table

table. sort ()

Sorts tables elements in a given order

table.insert ()

Inserts element at a given position, shifting all other elements

table.remove ()

Removes element from given position, shifting elements down

table.setn ()

Updates the size of a table


These functions all work in a similar way. For instance, you can use table.getn and table.insert to update a table entry, like so:

 Mytablelength = table.getn(Mytable) --Inserts 22 into the end of the table table.insert(Mytable, 22) 

You can insert elements at a chosen point in the list using table.insert :

 table.insert(Mytable, 10,100) 

You can print out the contents of the table using table.foreachi :

 table.foreachi(Mytable, print) 

Even though you can treat a table as an array, keep in mind that it is still table. You can store whatever you want:

 Mytable[5] = "Hey, a string!" 

So, if you were printing out a dictionary version of the table

 Mytable = {Mynumber = 1, Myword = "Ikes!" } 

you would use the foreach function to print out each key/value pair:

 table.foreach(Mytable, print) 

The next function can also be used to iterate over a table. next takes a table and an index and gives back the next key/value pair from the table:

 next(Mytable,"key") 

Tables are also objects in Lua in the sense that they have state, independent identity, a life cycle, and operations that can be called upon them. The Lua programming model also has ways of implementing traditional OOP in the form of inheritance, polymorphism, classes, and late binding with tables.

People considered tables in Lua so impressive that in the latest version metatables were added as well. Every table and userdata object in Lua may now also have a metatable, which is an ordinary Lua table that further defines behavior. The commands lua_getmetatable and lua_setmetatable allow you to manipulate the metatables of a given object.

Weak tables were also added with Lua 5.0, which are tables whose elements are weak references. Unlike regular references weak references are ignored by Lua's garbage collector.. Since weak tables do not prevent garbage collection, they are useful for determining when other objects have been collected by the GC and for caching objects without impeding garbage collection.

Threads

Threads allow programs to do multiple things at once. In a multi-threading model, each task runs in a thread that is separate from other threads. There are many ways to implement multi-threading, and Lua's way is a bit unique. Lua uses a "cooperative multi-threading ," using coroutines that aren't actually operating-system threads but are instead just blocks of code that can be created and run in tandem.

To create a coroutine, you first must have a function that the coroutine runs:

 function Myfunction() print ("do something") coroutine.yield() end 

You then create a coroutine using coroutine.create :

 Mythread = coroutine.create(Myfucntion) 

Once you have established a coroutine, you can check its status with coroutine.status :

 Mystatus = coroutine.status(Mythread) print(Mystatus) 

When run in the interpreter, this code will show that Mythread is suspended . To start or resume a coroutine, use coroutine.resume . In this example, the interpreter will print do something , and then Mythread will exit by yielding.

Yielding is key to coroutines. Coroutines must be able to yield system resources and pass control to the next thread that needs it. The coroutine.yield is similar to the return function, and it exits the current thread and frees up any resources.

If you run the Mystatus code a second time:

 Mystatus = coroutine.status(Mythread) print(Mystatus) 

the status will show that the thread has already run by reporting dead .

Userdata

Userdata is used to represent C values in Lua. There are two types of userdata: full userdata and light userdata. Full userdata represents a block of memory and is considered to be an object. A light userdata represents a pointer.

Identifiers

Identifiers in Lua can be made up of letters, numbers, and underscores, but they cannot begin with a digit. Lua is case-sensitive, so the strings HELLO and hello are considered different strings. There are a handful of reserved words that Lua keeps for itself and cannot be used as identifiers; these are as follows :

and

break

do

else

elseif

end

false

for

function

if

in

local

nil

not

or

repeat

return

then

true

until

while

A standard convention in Lua is that internal variables begin with an underscore and a capital letter, like Myvariable.

Control Structures

Control structures in Lua are similar to those in Lua's syntactical parents C and Pascal. if , while , and repeat commands are very common. The traditional if statement looks like the following in Lua:

 if true then block {elseif true then block} [else block] end 

An example of an if statement that prints whether x is less than 10 would be:

 x=1 if x<10 then print ("x is less than 10")end 

You can add a second else statement in case x is greater than 10:

 if x<10 then print ("x is less than 10")else print ("x is greater than 10")end 

Loops

One extremely common looping statement is the while loop, which looks syntactically like the following:

 while true do block end 

A second common looping construct is the repeat loop:

 repeat block until true 

Here is a sample Lua while loop that prints out a series of numbers:

 x = 1 while x<10 do print (x) x=x+1 end 

The sample is just as easy to implement using repeat :

 x=1 repeat print (x) x=x+1 until x==10 

The for loop, however, is what holds a special place in the programmer's heart. Lua has two versions of the for loop. The first one is used with numbers:

 for variable = var, var, var do block end 

Like in a typical for loop, all three expressions aren't necessary:

 for X=1, 10 do print(X) end 

This loop prints X as it iterates through the loop 10 times.

The second version of for is used for traversing a table, and it is capable of iterating through each key/value pair of a given table:

 for variable {, var} in explist do block end 

An example of this version of for iterating over a given table is as follows:

 Mytable = {1,2,3; word="hi, number=100000} for key,value in Mytable do print (key,value) end 

Included with this fun for is also a pairs() function for iterating key/value pairs:

 for key,value in pairs(Mytable) do print (key,value) end 

In this instance, pairs() will iterate only over the array type table entries in the table:

 for index,value in ipairs(Mytable) do print (index,value) end 

Lua uses a return statement to return values from a function or a Lua chunk. There is also a break statement that can be used to terminate the execution of a loop and skip to the next statement that follows. Both return and break must be the last statements in a given block.

Modules

Modules, packages, namespaces: all are mechanisms used by languages to organize global names and space and avoid collisions. In Lua, modules are implemented with the all-important and versatile (you guessed it) table. Identifiers become keys within tables instead of global variables. A package may look like this:

 Mypackage = {         function1 = function() dosomething{} end,         function2 = function() dosomething{} end,         function3 = function() dosomething{} end,         function4 = function() dosomething{} end, } 

Then the package can be called like this:

 call = Mypackage.function1(arguments) 

Libraries

Lua has a set of standard libraries that provide useful and common routines. These are implemented directly through the standard API but aren't necessary to the language, and so are provided as separate C libraries. There is a basic library, a library for string manipulation, one for mathematical functions, one for system facilities and I/O, one for debugging, and one for tables. The functions are declared in lualib.h and must be opened with a corresponding function, like in the following examples:

 luaopen_string luaopen_table luaopen_math luaopen_io 

A few of the libraries (math and string) were covered in the previous sections. The others will be covered here.

The Basic Library

The basic library provides much of Lua's base functionality. The commands involved are listed in Table 6.9.

The coroutine functions are actually part of a sublibrary of the basic library.

Input/Output Library

Input and output are handled by two file handles. These handles are stored in two global variables: _INPUT and _OUTPUT , the former for reading and the latter for writing. _INPUT and _OUTPUT are also equivalent to _STDIN and _STDOUT . The common I/O functions are listed in Table 6.10.

Table 6.10. Common Lua Input/Output Functions

Function

Purpose

io.close ()

Closes the given file

io.flush ()

Flushes over the default output file

io.input ()

Opens the named file in text mode and sets its handle to the default input file

io.lines ()

Opens the given file name in read mode and returns an iterator function that returns a new line from the file each time it is called

io. open ()

Opens a file in the mode specified and returns a new file handler

io.output ()

Opens named file in text mode and sets its handle to the default output file

io. tmpfile ()

Returns handle for a temporary file

io.type ()

Checks if object is a valid file handle

file:close ()

Closes file

file:flush ()

Saves any written data to file

file:read ()

Reads the file according to given formats

file:lines ()

Returns an integrator that returns a new line from the field each time it is called

file:seek ()

Sets and gets the file position

file:write ()

Writes the value of each of its arguments to the filehandle file


Table 6.9. Lua's Basic Function Library

Function

Purpose

assert ()

Issues an error when its argument is nil

collectgarbage ()

Forces a garbage collection cycle and returns the number of objects collected

coroutine.create ()

Creates a new coroutine

coroutine.resume ()

Starts or continues coroutine execution

coroutine.status ()

Returns status for a coroutine

coroutine.wrap ()

Creates a new wrapped coroutine

coroutine.yield ()

Suspends coroutine execution

dofile ()

Opens a given file and executes its contents as a Lua chunk or as precompiled chunks

error ()

Calls the error handler and then terminates the last protected function called

_G

Holds the global environment

getfenv ()

Returns current environment in use by a given function

getmetatable ()

Returns objects' __metatable field value or else nil for no metatable

gcinfo ()

Returns dynamic memory use and garbage collector threshold in kbytes

ipairs ()

Iterates over a table

loadfile ()

Loads a file as a Lua chunk

loadlib ()

Links a program to a C library

loadstring ()

Loads a string as a Lua chunk

newtag ()

Returns a new tag - equivalent to the API function lua_newtag

next ()

Allows a program to traverse all fields of a table

pairs ()

Iterates over tables

pcall ()

Calls a function in protected mode with given arguments

print ()

Receives arguments and prints their values using the strings returned by tostring

rawequal ()

Checks to see if two values are equal

rawget ()

Gets the real value of an index within a table

rawset ()

Sets the real value of an index within a table

require ()

Loads a given package

setenv ()

Sets the environment to be used by a function

setmetatable ()

Sets the metatable for a given table

tonumber ()

Tries to convert an argument to a number

tostring ()

Tries to convert an argument to a string

type ()

Returns the type of its only argument

tinsert ()

Inserts an element at a given table position

tremove ()

Removes an element from a given table

type ()

Tests the type of a value

unpack ()

Returns all elements from a given list

-VERSION

Holds the current interpreter version (i.e. Lua 5.0)

xpcall ()

Calls a function in protected mode using err as the error handler


System Facilities

There are also a few system utility functions that can be included with Lua's built-in library. They are listed in Table 6.11.

Table 6.11. Lua System Facilities

Function

Purpose

os.clock ()

Returns an approximate CPU time, in seconds, used by the program

os.date ()

Returns the date and time according to given format

os. difftime ()

Returns the seconds between two given times

os.execute ()

Passes a command to be executed by the operating system. Equivalent to C's system

os.exit ()

Calls the C function exit to terminate a program

os.getenv ()

Returns the value of a given environment variable

os.remove ()

Deletes a given file

os.rename ()

Renames a given file

os.setlocale ()

Used as an interface to the ANSI C setlocale function

os.time ()

Returns current time

os.tmpname ()

Returns a string with a filename that can be used for a temporary file


[ LiB ]


Game Programming with Pyton, Lua and Ruby
Game Programming with Pyton, Lua and Ruby
ISBN: N/A
EAN: N/A
Year: 2005
Pages: 133

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net