Lua - Murray State Information Systemscampus.murraystate.edu/academic/faculty/wlyle/415/201… ·...
Click here to load reader
Transcript of Lua - Murray State Information Systemscampus.murraystate.edu/academic/faculty/wlyle/415/201… ·...
Lua
CSC 415
John Imboden
10/27/2011
A Short History of Lua
Lua was developed as a lightweight embeddable scripting language for the purpose of a
small in house project for PETROBRAS (a Brazilian oil company) for a data entry program. It
was designed by a committee consisting of Roberto Lerusalimschy, Luiz Henrique de Figueiredo, and
Waldemar Celes. Lua is a modified mixture of two other languages created by the same people called
Sol, and DEL. Something of importance to note is the fact that Lua was "raised" following a bottom up
design. This sets it apart from many of the larger languages that are created using a top down
design and thus it is highly specialized in its functionality. Unfortunately an issue with
something designed to be small is that it may quickly outgrow its initial purpose as its user base
grows, since each user has his/her own individual needs. "In December 1996, the magazine Dr.
Dobb's featured an article about Lua."[1] This is the start of a major exposure for the language.
Soon after the language was used in a LucasArts game called "Grim Fandango" that was
released in 1997. Now in 2011 there are several game companies that use Lua in their productions,
including Blizzard and BioWare. Even though Lua is known mostly for its uses in game programming it is
not limited to just that realm of game development. "Its uses range from adventure games to web-
servers to telephony-network testing to Ethernet switches."[1]
Names, Bindings, and Scopes
"Names (also called identifiers) in Lua can be any string of letters, digits, and
underscores, not beginning with a digit. This coincides with the definition of names in most
languages. "[4] Lua also contains several keywords that are reserved and cannot be used as
identifiers, these are very similar to most other language's reserved words.[see appendix a for a
list of reserved words] "Since extension languages are not for writing large pieces of software,
mechanisms for supporting programming-in-the-large, like static type checking and information
hiding, are not essential."[2] This means that all variables in Lua are global unless explicitly
declared as local. Thanks to Lua's built in garbage collection feature it throws away unused
variables so as to lower as much memory usage as possible. " Lua is a lexically scoped language.
The scope of variables begins at the first statement after their declaration and lasts until the
end of the innermost block that includes the declaration."[4] "Lua is a case-sensitive language:
and is a reserved word, but "And" and "AND" are two different, valid names. As a convention,
names starting with an underscore followed by uppercase letters (such as _VERSION) are
reserved for internal global variables used by Lua."[4]
Data Types
"Lua is a dynamically typed language. This means that values have types but variables
don't, so there are no type or variable declarations. Internally, each value has a tag that
identifies its type; the tag can be queried at run time with the built-in function type. "[3] Upon
seeing this I had to do a double take. The idea of not having variable types seems kind of alien.
It feels as though the writability of the language might suffer when it is time to write
expressions and not having a way of making sure that floats are not being added to strings
seems to be an issue. "Lua provides automatic conversion between string and number values at
run time. Any arithmetic operation applied to a string tries to convert this string to a number,
following the usual conversion rules. Conversely, whenever a number is used where a string is
expected, the number is converted to a string, in a reasonable format."[4] " Lua provides the
types nil, string, number, user data, function, and table. nil is the type of the value nil; its main
property is that it is different from any other value."[2] Nil is a great asset to Lua since it was
originally developed as a data entry language using nil for variables that have not been assigned
an actual value. With the release of Lua 5.0 two new types were introduced, boolean and
thread.[3] The creators of Lua were reluctant to add boolean values because the language
already supported it through the nil values being false and any other value being true for the
purpose of keeping the language as small as possible; however there were occasions where
table values needed an explicit false and since nil is more of an initial value it led to errors.[3]
Expressions and Assignment Statements
Expressions in Lua are pretty conventional, they resemble statements in Pascal and C
and include assignments, control structures, function calls, and variable declarations.[4] The
mathematical operators are also standard and include binary + (addition), - (subtraction), *
(multiplication), / (division), % (modulo), ^ (exponentiation) and unary - (negation).[4] The
relational operators are also pretty standard but are implemented slightly differently since
unlike many languages the variables do not have types the language must first compare the
operand types before any values can be compared.[4] The relational operators in Lua are
== ~= < > <= >=.[4] The conversion rules used with different types do not come into
effect with relational operators so when two operands of different types are compared it will
always equate to false, therefore the relational expression 5>"4" will be false even though the
value 5 is obviously more than 4 based on the fact that one is of type number and the other is
of type string.[4] " Lua supports multiple assignment; for example, x, y = y, x swaps the values of
x and y. Likewise, functions can return multiple values."[2]
Statement-Level Control Structures
Lua supports all conventional control structures including If, elseif, For, While, and
Repeat.[4] There are two types of for loops supported by Lua. The first type of for loop is the
standard numeric for loop that starts at some initial value and increments until a target value is
reached. The other type is known as a generic for loop and it increments over functions called
iterators and will run the iterator function that will produce a new value on each iteration until
the value produced by the function is nil.[4] [see apendix b for an example of these for loops]
"To avoid dangling elses, control structures like ifs and whiles finish with an explicit end.
Comments follow the Ada convention, starting with "--" and run until the end of the line." [2]
Subprograms
Lua supports subprograms only in the form of functions. These functions may be native
to Lua or C. "Being an extension language, Lua has no notion of a "main" program: it only works
embedded in a host client, called the embedding program or simply the host. This host program
can invoke functions to execute a piece of Lua code, can write and read Lua variables, and can
register C functions to be called by Lua code."[4]
Abstract Data Types and Encapsulation Constructs
"The type userdata is provided to allow arbitrary C data to be stored in Lua variables.
This type corresponds to a block of raw memory and has no pre-defined operations in Lua,
except assignment and identity test. However, by using metatables, the programmer can define
operations for userdata values (see §2.8). Userdata values cannot be created or modified in
Lua, only through the C API. This guarantees the integrity of data owned by the host
program."[4] The ability of Lua to read and manipulate data in C is one of the most important
features in defining it as an extensible language. Oddly enough, the Userdata type has not
undergone any changes since the first implementation of Lua.[3]
Support for Object-Oriented Programming
Originally Lua was not meant to be an Object Oriented language but its ability to
become one developed over time as more features were added to accommodate its growing
user base and the addition of a fallback meta-mechanism allowing several new kinds of
inheritance between different objects.[1] "Because functions are first-class values, table fields
can refer to functions. This is a step toward object-oriented programming, and one made easier
by simpler syntax for defining and calling methods."[2] Objects in Lua are defined as a table,
userdata, a thread, or a function, and as such they may all call on one another lending to the
over object oriented nature of the Language[4]
Concurrency
At its creation Lua had no true built in form of concurrency as it had no concept of
threads. A thesis by Eleftherios Chatzimparmpas about how to achieve concurrency in Lua and
other interpreted scripting languages shed some light on to how to force concurrency when
necessary, and is included in the bibliography for extra reading.[5] This is no longer true as of
the release of Lua 5.0 and the addition of the thread data type.[2] The concurrency provided by
the thread data type is still not a "true" concurrency in the sense as it does not make use of
multiple processors working on different instructions. The form of concurrency supported is a
co routine that represents its own thread of execution. These co routines are also called
collaborative multithreading.[4] " Unlike threads in multithread systems, however, a coroutine
only suspends its execution by explicitly calling a yield function."[4]
Exception Handling and Event Handling
Because Lua is an embedded extension language, all Lua actions start from C code in the
host program calling a function from the Lua library. Whenever an error occurs during Lua
compilation or execution, control returns to C, which can take appropriate measures (such as
printing an error message).[4] One of the issues with this is that when the error is thrown and
the control is returned back to the host language that language may react in unfavorable ways
such as aborting. Lua's defense against this is through it's use of fallbacks. "Fallbacks are used
for handling situations that are not strictly error conditions, such as accessing an absent field in
a table and signaling garbage collection. Lua provides default fallback handlers, but you can set
your own handlers by calling the built-in function setfallback with two arguments: a string
identifying the fallback condition (see Table 1), and the function to be called whenever the
condition occurs. setfallback returns the old fallback function, so you can chain fallback
handlers if necessary."[2] In this sense the fallbacks work much like try catch blocks in C.
Other Issues of Lua
Lua can lead to memory issues as the programmer has no direct control over releasing
memory back to the system due to Lua’s garbage collection system. It allows for less time being
spent trying to manage memory but problems still arise from poorly constructed data
structures or code that simply generates too much garbage to clean up with the built in garbage
collection.[6]
Evaluation
Readability – Reading code written in Lua is not terribly difficult, or so I have
found. I think the biggest issue is the horrid use of the <type>.<function> lines used repeatedly.
One thing improving readability is the color coding of commands. Reserved words show up in
dark blue, types and their functions show up in pink and constant string text shows up in a light
blue.
Writability – Because Lua is based on C its writability is quite good. It is
designed to be used in conjunction with C++ and its syntax is very similar to lessen the learning
curve as much as possible. The garbage collection functionality provided by Lua also helps quite
a bit by removing altogether the effort required to manually manage memory.
Reliability – The common consensus that I can find is that Lua is not very good
as a standalone language. It is missing data types and other common functions that most
programmers are used to using as well as having no true support for pointers. My response to
this is that Lua was never designed to be a standalone language and doing so is like using a
wrench for a hammer, you can do it but don’t be surprised when the result is ugly…
D. Cost – Lua is free and open source, Lua’s only cost is the time spent
learning the language, which in theory should not be too long or difficult as it is based on C so
most programmers should already have some form of basic knowledge. “Lua is free software: it
may be used for any purpose, including commercial purposes, at absolutely no cost. No
paperwork, no royalties, no GNU-like "copyleft" restrictions, either.”[7]
Bibliography and References
[1]http://www.lua.org/history.html (Reprint from Proceedings of V Brazilian Symposium on
Programming Languages (2001))
[2] http://www.lua.org/ddj.html (Reprint from Dr. Dobb's Journal 21 #12 (Dec 1996) 26–33.
Copyright © 1996 Miller Freeman, Inc.)
[3] http://www.lua.org/doc/hopl.pdf (The Evolution of Lua, by Roberto Ierusalimschy, Luiz
Henrique de Figueiredo, Waldemar Celes)
[4] http://www.lua.org/manual/5.1/manual.html (Lua 5.1 Reference Manual by R.
Ierusalimschy, L. H. de Figueiredo, W. Celes Lua.org, August 2006 ISBN 85-903798-3-3)
[5]http://web.it.kth.se/~johanmon/theses/eleftherios.pdf
[6]http://bitsquid.blogspot.com/2011/08/fixing-memory-issues-in-lua.html
[7] http://www.lua.org/license.html
All appendices are directly taken from the Lua version 5.1 manual located at lua.org and is freely available under the terms of the Lua license.
Appendix "a" List of reserved words in Lua
and break do else elseif
end false for function if
in local nil not or
repeat return then true until while
Appendix "b" For Loops
A numeric for loop like
for v = e1, e2, e3 do block end
is equivalent to the code:
do
local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
if not (var and limit and step) then error() end
while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
local v = var
block
var = var + step
end
end
A generic for statement like
for var_1, ···, var_n in explist do block end
is equivalent to the code:
do
local f, s, var = explist
while true do
local var_1, ···, var_n = f(s, var)
var = var_1
if var == nil then break end
block
end
end
Appendix "c" A list of Functions in Lua
Index
Lua functions
_G_VERSION
assertcollectgarbagedofileerrorgetfenvgetmetatableipairsloadloadfileloadstringmodulenextpairspcallprintrawequalrawgetrawset
file:closefile:flushfile:linesfile:readfile:seekfile:setvbuffile:write
io.closeio.flushio.inputio.linesio.openio.outputio.popenio.readio.stderrio.stdinio.stdoutio.tmpfileio.type
C API
lua_Alloclua_CFunctionlua_Debuglua_Hooklua_Integerlua_Numberlua_Readerlua_Statelua_Writer
lua_atpaniclua_calllua_checkstacklua_closelua_concatlua_cpcalllua_createtablelua_dumplua_equallua_errorlua_gc
auxiliary library
luaL_BufferluaL_Reg
luaL_addcharluaL_addlstringluaL_addsizeluaL_addstringluaL_addvalueluaL_argcheckluaL_argerrorluaL_buffinitluaL_callmetaluaL_checkanyluaL_checkintluaL_checkintegerluaL_checklongluaL_checklstringluaL_checknumberluaL_checkoptionluaL_checkstackluaL_checkstring
requireselectsetfenvsetmetatabletonumbertostringtypeunpackxpcall
coroutine.createcoroutine.resumecoroutine.runningcoroutine.statuscoroutine.wrapcoroutine.yield
debug.debugdebug.getfenvdebug.gethookdebug.getinfodebug.getlocaldebug.getmetatabledebug.getregistrydebug.getupvaluedebug.setfenvdebug.sethookdebug.setlocaldebug.setmetatabledebug.setupvaluedebug.traceback
io.write
math.absmath.acosmath.asinmath.atanmath.atan2math.ceilmath.cosmath.coshmath.degmath.expmath.floormath.fmodmath.frexpmath.hugemath.ldexpmath.logmath.log10math.maxmath.minmath.modfmath.pimath.powmath.radmath.randommath.randomseedmath.sinmath.sinhmath.sqrtmath.tanmath.tanh
os.clockos.dateos.difftimeos.executeos.exitos.getenv
lua_getallocflua_getfenvlua_getfieldlua_getgloballua_gethooklua_gethookcountlua_gethookmasklua_getinfolua_getlocallua_getmetatablelua_getstacklua_gettablelua_gettoplua_getupvaluelua_insertlua_isbooleanlua_iscfunctionlua_isfunctionlua_islightuserdatalua_isnillua_isnonelua_isnoneornillua_isnumberlua_isstringlua_istablelua_isthreadlua_isuserdatalua_lessthanlua_loadlua_newstatelua_newtablelua_newthreadlua_newuserdatalua_nextlua_objlenlua_pcalllua_poplua_pushboolean
luaL_checktypeluaL_checkudataluaL_dofileluaL_dostringluaL_errorluaL_getmetafieldluaL_getmetatableluaL_gsubluaL_loadbufferluaL_loadfileluaL_loadstringluaL_newmetatableluaL_newstateluaL_openlibsluaL_optintluaL_optintegerluaL_optlongluaL_optlstringluaL_optnumberluaL_optstringluaL_prepbufferluaL_pushresultluaL_refluaL_registerluaL_typenameluaL_typerrorluaL_unrefluaL_where
os.removeos.renameos.setlocaleos.timeos.tmpname
package.cpathpackage.loadedpackage.loaderspackage.loadlibpackage.pathpackage.preloadpackage.seeall
string.bytestring.charstring.dumpstring.findstring.formatstring.gmatchstring.gsubstring.lenstring.lowerstring.matchstring.repstring.reversestring.substring.upper
table.concattable.inserttable.maxntable.removetable.sort
lua_pushcclosurelua_pushcfunctionlua_pushfstringlua_pushintegerlua_pushlightuserdatalua_pushliterallua_pushlstringlua_pushnillua_pushnumberlua_pushstringlua_pushthreadlua_pushvaluelua_pushvfstringlua_rawequallua_rawgetlua_rawgetilua_rawsetlua_rawsetilua_registerlua_removelua_replacelua_resumelua_setallocflua_setfenvlua_setfieldlua_setgloballua_sethooklua_setlocallua_setmetatablelua_settablelua_settoplua_setupvaluelua_statuslua_tobooleanlua_tocfunctionlua_tointegerlua_tolstringlua_tonumber
lua_topointerlua_tostringlua_tothreadlua_touserdatalua_typelua_typenamelua_upvalueindexlua_xmovelua_yield
Appendix "d" A full syntax of Lua
Here is the complete syntax of Lua in extended BNF. (It does not describe operator precedences.)
chunk ::= {stat [`;´]} [laststat [`;´]]
block ::= chunk
stat ::= varlist `=´ explist |
functioncall |
do block end |
while exp do block end |
repeat block until exp |
if exp then block {elseif exp then block} [else block] end |
for Name `=´ exp `,´ exp [`,´ exp] do block end |
for namelist in explist do block end |
function funcname funcbody |
local function Name funcbody |
local namelist [`=´ explist]
laststat ::= return [explist] | break
funcname ::= Name {`.´ Name} [`:´ Name]
varlist ::= var {`,´ var}
var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name
namelist ::= Name {`,´ Name}
explist ::= {exp `,´} exp
exp ::= nil | false | true | Number | String | `...´ | function |
prefixexp | tableconstructor | exp binop exp | unop exp
prefixexp ::= var | functioncall | `(´ exp `)´
functioncall ::= prefixexp args | prefixexp `:´ Name args
args ::= `(´ [explist] `)´ | tableconstructor | String
function ::= function funcbody
funcbody ::= `(´ [parlist] `)´ block end
parlist ::= namelist [`,´ `...´] | `...´
tableconstructor ::= `{´ [fieldlist] `}´
fieldlist ::= field {fieldsep field} [fieldsep]
field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
fieldsep ::= `,´ | `;´
binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ |
`<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ |
and | or
unop ::= `-´ | not | `#´
Appendix "e" Lua Interpreter written in C++
#include <stdio.h> #include "lua.h" /* lua header file */ #include "lualib.h" /* extra libraries (optional) */
int main (int argc, char *argv[]) { char line[BUFSIZ]; iolib_open(); /* opens I/O library (optional) */ strlib_open(); /* opens string lib (optional) */ mathlib_open(); /* opens math lib (optional) */ while (gets(line) != 0) lua_dostring(line); }Appendix "f" Sample Lua Programs (freely available from http://www.lua.org/cgi-bin/demo)
Hello World.
-- hello.lua
-- the first program in every language
io.write("Hello world, from ",_VERSION,"!\n")
Output
Hello world, from Lua 5.1!
Sieve of Eratosthenes
-- sieve.lua
-- the sieve of Eratosthenes programmed with coroutines
-- typical usage: lua -e N=1000 sieve.lua | column
-- generate all the numbers from 2 to n
function gen (n)
return coroutine.wrap(function ()
for i=2,n do coroutine.yield(i) end
end)
end
-- filter the numbers generated by `g', removing multiples of `p'
function filter (p, g)
return coroutine.wrap(function ()
while 1 do
local n = g()
if n == nil then return end
if math.mod(n, p) ~= 0 then coroutine.yield(n) end
end
end)
end
N=N or 1000 -- from command line
x = gen(N) -- generate primes up to N
while 1 do
local n = x() -- pick a number until done
if n == nil then break end
print(n) -- must be a prime number
x = filter(n, x) -- now remove its multiples
end
Output
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727
733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997
(note, these numbers would normally be on separate lines but in order to save paper they are printed all as one line.)