Lua Documentation Notes
I wanted to learn more about Lua so that I can make some custom Pandoc writers. The current Pandoc output does not mesh with my design system.
References
I only read Part 1 - The Language of this book. I think I can figure out everything else about Lua that I need to know from here.
Getting Started
Each piece of code that Lua executes, such as a file in interactive mode, is a chunk. A chunk is simply a sequence of statements. A semicolon may optionally follow any statement. Use semicolons to separate two or more statements on the same line (although not required). Lua is a data-description language.
The dofile function can be used to execute files from the lua interactive mode.
lua -- file lib1.lua function norm(x,y) local n2 = x^2 + y^2 return math.sqrt(n2)
```bash
dofile("lib1.lua")
```
Global variables do not need declaration. You simply assign a value to a global variable to create it. It is not an error to access a non-initialized variable; you just get the special value nil as the result. To delete a global variable, assign nil to it.
Identifiers (variable names) can be any string of letters, digits, and underscores, not beginning with a digit. Avoid underscores followed by one or more uppercase letters. and, end, in, repeat, while, break, false, local, return, do, for, nil, then, else, function, not, true, elseif, if, or, and until are reserved keywords.
A comments starts anywhere with a double hyphen -- and runs until the end of the line. Lua also offers block comments, which start with --[[ and run until the corresponding ]].
Types and Values
Lua is a dynamically typed language. There are no type definitions in the language; each value carries its own type. There are eight basic values in Lua: nil, boolean, string, userdata, function, thread, and table. The type function gives the type name of a given value.
Nil is a type with a single value, nil, whose main property is to be different from any other value. Lua uses nil as a kind of non-value, to represent the absence of a useful value.
The boolean type has two values false and true, which represent the traditional boolean values. However, they do not hold a monopoly of condition values: In Lua, any value may represent a condition. Conditionals (such as ones in control structures) consider false and nil as false and anything else as true (0 and '' are considered true in Lua).
The number type represents real (double-precision floating point) numbers. Lua has no integer type, as it does not need it.
There is a widespread misconception about floating-point arithmetic errors and some people fear that even a simple increment can go weird with floating-point numbers. The fact is that, when you use a double to represent an integer, there is no rounding error at all (unless the number is greater than 100,000,000,000,000). Specifically, a Lua number can represent any long integer without rounding problems. Moreover, most modern CPUs do floating-point arithmetic as fast as (or even faster than) integer arithmetic.
Strings have the usual meaning: a sequence of characters. Strings are immutable in Lua. All objects in Lua are subject to automatic memory management.
We can delimit literal strings also by matching double square brackets [[...]]. This form ignores the first character of the string when this character is a newline. This form is especially convenient for writing strings that contain program pieces; for instance,
lua page = [[ <HTML> <HEAD> <TITLE>An HTML Page</TITLE> </HEAD> <BODY> <A HREF="http://www.lua.org">Lua</A> [[a text between double brackets]] </BODY> </HTML> ]] Lua provides automatic conversion between numbers and strings at run time. Any operation applied to a string tries to convert the string to a number. "10"+"2" = 12. The .. us the string concatenation operator in Lua. Comparison between strings and non-strings are false because they are different things. To convert a number to a string, you can use the function tostring.
The table type implements associative arrays. An associative array is an array that can be indexed not only with numbers, but also with strings or any other value of the language, except nil. Tables have no fixed size; you can add as many elements as you want to a table dynamically. Tables are the main (in fact the only)data structuring mechanism in Lua, and a powerful one. We use table to represent ordinary arrays, symbol tables, sets, records, queues, and other data structures, in a simple, unifrom, and efficient way. Lua uses tables to represent packages as well. When we write io.read, we mean "the read entry from the io package". For Lua, that means "index the table io using the string "read" as the key". Tables in Lua are objects. Each table may store values with different types of indices and it grows as it need sto accommodate new entries.
- To represent records, you use the field name as an index.
- To represent a conventional array, you simply use a table with integer keys
Functions are first-class values in Lua. That means that functions can be stored in variables, passed as arguments to other functions, and returned as results. Lua can call functions written in Lua and functions written in C. All the standard library in Lua is written in C.
The userdata type allows arbitrary C data to be stored in Lua variables. It has no predefined operations in Lua, except assignment and equality test. Userdata are used to represent new types created by an application program or a library written in C.
Expressions
Expression denote values. Expressions in Lua include the numerical constants and string literals, variables, unary and binary operations, and function calls.
Lua supports the usual arithmetic operations (not modulus). Lua supports all the usual binary operators (not qual is written as ~=). In comparison, Lua will say that two different types are not equal. Lua compares tables, userdata, and functions by reference, that is, two such values are only considered equal if they are the very same object.
The logical operators are and, or, and not. Like control structures, all logical operators consider false and nil as false and anything else as true. The operator and returns its first argument if it is false; otherwise, it returns its second argument. The operator or returns ts first argument if it is not false; otherwise, it returns its second argument. Both and and or use short-cut evaluation, that is, they evaluate their second operator only when necessary. The ternary operation in Lua can be done:(a and b) or c which is equal to a ? b : c in C.
Constructors are expressions that create and initialize tables. They are a distinctive feature of Lua and one of its most useful and versatile mechanisms. The simplest constructor is the empty constructor, {}, which creates an empty table. COnstructors also initialized arrays (also called sequences or lists):
lua days = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"} print(days[1]) -- Sunday (arrays 1-indexed like this)
You can use any kind of expression for the value of each element in an array. To initialize a table to be used as a record, Lua offers the following syntax:
lua w = {x=0, y=0, label="console"} x = {sin(0), sin(1), sin(2)} w[1] = "another field" x.f = w print(w["x"]) --> 0 print(w[1]) --> another field print(x.f[1]) --> another field w.x = nil -- remove field "x"
You can mix record-style and line-style initialization in the same constructor:
lua polyline = {color="blue", thickness=2, npoints=4, {x=0, y=0}, {x=-10, y=0}, {x=-10, y=1}, {x=0, y=1} }
Statements
Lua supports an almost conventional set of statements, similar to those in C or Pascal. Assignment is the basic means of changing the value of a variable or a table field. Lua allows multiple assignment, where a list of values is assigned to a list of variables in one step. Both lists have their elements separated by commas:
lua a, b = 10, 2*x
Besides global variables, Lua supports local variables. Local variables are created with the local statement:
lua j = 10 -- global local i = 1 -- local
Unlike global variables, local variables have their scope limited to the block where they are declared. A block is the body of a control structure, the body of a function, or a chunk.
It is good programming style to use local variables whenever possible. Local variables help you avoid cluttering the global environment with unnecessary names. Moreover, the access to local variables is faster than to global ones.
Lua handles local variable declarations as statements. As such, you can write local declarations anywhere you can write a statement. A common idiom in Lua is:
lua -- Creates a local variable, foo, and initializes it with the value of the global variable foo local foo = foo
Lua provides a small and conventional set of control structures, with if for conditional and while, repeat, and for for iteration. All control structures have an explicit terminator: end terminates the if, for and while structures, and until terminates the repeat structure. An if statement tests its condition and executes its then-part or its else-part accordingly.
lua -- print the first non-empty line -- The body is always executed at least once repeat line = io.read() until line ~= "" print(line) The for statement has two variants: the numeric for and the generic for. A numeric for has the following syntax:
lua for var=exp1,exp2,exp3 do something end That loop will execute someting for each value of var from exp1 to exp2, using exp3 as the step increment var. The step is optional. All three expressions in the for loop are executed once and only once before the loop starts.
The generic for loop allows you to traverse all values returned by an iterator function.
The break and return statements allow us to jump out from an inner block. You can use the break statement to finish a loop. A return statement returns occasional results from a function or simply finishes a function. There is an implicit return at the end of the function, so you do not need to use one if your function ends without returning a value.
Functions
Functions are the main mechanism for abstraction of statements and expressions in Lua. Functions can both carry out a specific task (what is sometimes called a procedure or subroutine in other languages) or compute and return values. In both cases, we write a list of arguments enclosed in parentheses. If the function call has no arguments, we must write an empty list () to indicate the call. There is a special case to this rule: If the function has one single argument and this argument is either a literal string or a table constructor, then the parentheses are optional.
Lua also offers a special syntax for object oriented calls, the colon operator. An expression o:foo(x) is just another way to write o.foo(o,x).
Functions in Lua can return multiple results.
lua function maximum (a) local mi = 1 -- maximum index local m = a[mi] -- maximum value for i,val in ipairs(a) do if val > m then mi = i m = val end end return m, mi end
Lua always adjusts the number of results from a function to the circumstances of the call. We we call a function as a statement, Lua discards all of its results. When we call as an expression, Lua keeps only the first result. We get all results only when teh call is the last (or the only) expression in a list of expressions. The print function may receive a variable number of arguments.
A special function with multiple returns is unpack. It receives an array and returns as results all elements from the array, starting from index 1:
lua print(unpack{10,20,30}) --> 10 20 30 a,b = unpack{10,20,30} -- a=10, b=20, 30 is discarded
An important use for unpack is in a generic call mechanism. A generic call mechanism allows you to call any function, with any arguments, dynamically.
Some functions in Lua receive a variable number of arguments. For instance, we have already called print with one, two, and more arguments. The three dots ... in the function below indicate that the function has a variable number of arguments. When this function is called, all its arguments are collected in a single table, which the function accesses as a hidden parameter named arg. Besides those arguments, the arg table has an extra field, n with the actual number of arguments collected.
lua function print (...) for i,v in ipairs(arg) do printResult = printResult .. tostring(v) .. "\t" end printResult = printResult .. "\n" end A function can have a fixed parameter plus a variable number of extra arguments:
lua function select (n, ...) return arg[n] end The parameter passing mechanism is positional: When we call a function, arguments match parameters by their positions. The first arguments gives the value to the first parameter, and so on. Sometimes, it is useful to specify teh arguments byu name. You can do this with tables.
More About Functions
A function is a value with the same rights as conventional values like numbers and strings. Functions can be stored in variables (both global and local) and in tables, can be passed as arguments, and can be returned by other functions. Functions have lexical scoping - can access the variables of their enclosing functions. Functions, like other values, are anonymous and do not have names.
Iterators and the Generic for
Am iterator is any construction that allows you to iterate over the elements of a collection. In Lua, we typically represent iterators by functions: Each time we all that function it returns a "next" element from the collection. Any iterator needs to keep some state between successive calls, so that it knows where it is and how to proceed from there. Closures provide an excellent mechanism for that task. Iterator for a list:
lua function list_iter (t) local i = 0 local n = table.getn(t) return function () i = i + 1 if i <= n then return t[i] end end end t = {10, 20, 30} iter = list_iter(t) -- creates the iterator while true do local element = iter() -- calls the iterator if element == nil then break end print(element) end
Compilation, Execution, and Errors
Although Lua is an interpreted language, Lua always precompiles source code to an intermediate form before running it. The presence of a compilation phase may sound out of place in an interpreted language like Lua. However, the distinguishing feature of interpreted languages is not that they are not compiled, but that any compiler is part of the language runtime and that, therefore, it is possible (and easy) to execute code generated on the fly.
Lua offers a higher-level function to load and run libraries, called require. Roughly, require does the same job as dofile, but with two important differences. First, require searches for the file; second, require controls whether a file has already been run to avoid duplicating the work. Because of these features, require is the preferred function in Lua for loading libraries.
Because it is easy to interface Lua with C, it is also easy to write packages for Lua in C. Unlike packages written in Lua, however, C packages need to be loaded and linked with an application before use.
Any unexpected condition that Lua encounters raises an error. Errors occur when you try to add values that are not numbers, to call values that are not functions, to index values that are not tables, and so on. You can explicitly raise an error calling the error function; its argument is the error message.
lua if not n then error("invalid input") end --[[ Some combination of `if not ... then error end` is so common that Lua has a built-in function just for that job, called `assert`. The `assert` function checks whether its first argument is not false and simply returns that argument; if the argument is false, `assert` raises an error. ]] n = assert(io.read("*number"), "invalid input")
If you need to handle errors in Lua, you should use the pcall function (protected call) to encapsulate your code. Suppose you want to run a piece of Lua code and catch any error raised while running that code. Your first step is to encapsulate that piece of code in a function. Then you call the function with pcall. You can call pcall with an anonymous function.
Couroutines
A coroutine is similar to a thread (in the sense of multithreading): a line of execution, with its own stack, its local variables, and its own instruction pointer, but sharing global variables and mostly anything else with other coroutines. The amin difference between threads andd coroutines is that, conceptually (or literally, in a multiprocessor machine), a program with threads runs several threads concurrently. Coroutines, on the other hand, are collaborative: A program with coroutines is, at any given time, running inly one of its coroutines and the running coroutine only suspends its execution when it explicitly requests to be suspended.
Tables in Lua are not a data structure; they are the data structure. All structures that other languages offer - arrays, records, lists, queues, sets - are represented with tables in Lua.
<aside>
Element
<details>
Element
Comments
You have to be logged in to add a comment
User Comments