Grammaire complète

Référence syntaxique condensée du langage, dans l'esprit de l'annexe « The Complete Syntax of Lua » du manuel de référence Lua : toute la grammaire, sans réexpliquer la sémantique déjà décrite dans les autres pages de cette section. Si une règle vous semble obscure, la page thématique correspondante (liée depuis index.md) en donne le sens et des exemples.

Notation

Chunk et blocs

chunk ::= block

block ::= {stat} [retstat]

Un script constitue à lui seul un chunk : il est toujours variadique (... y est utilisable, voir Variables), même s'il n'est pas défini comme une fonction explicite.

Instructions

stat ::=  ';' |
     varlist '=' explist |
     functioncall |
     label |
     break | continue |
     goto Name |
     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 attnamelist ['=' explist]

attnamelist ::= Name attrib {',' Name attrib}

attrib ::= ['<' Name '>']

retstat ::= return [explist] [';']

label ::= '::' Name '::'

retstat ne peut apparaître qu'en dernière position d'un block (rien ne suit un return, à l'exception d'un ; optionnel) — voir Structures de contrôle.

attrib est accepté syntaxiquement pour tout nom, mais seuls <const> et <close> sont reconnus par le parseur — voir Variables ; tout autre nom reste rejeté avec une erreur de syntaxe.

funcname ::= Name {'.' Name} [':' Name]

varlist ::= var {',' var}

var ::=  Name | prefixexp '[' exp ']' | prefixexp '.' Name

namelist ::= Name {',' Name}

explist ::= exp {',' exp}

Au niveau d'une instruction, varlist '=' explist et functioncall partagent le même préfixe : le parseur lit d'abord un prefixexp (Name ou '(' exp ')', avec ses suffixes ./[...]/:/appel éventuels), puis choisit entre affectation et appel selon ce qui suit — (f)() est donc une instruction valide au même titre qu'une sous-expression, comme en Lua. Une instruction ne peut en revanche pas être une expression parenthésée sans suffixe ((1 + 2) seul, ni appel ni affectation), ni une affectation à une expression parenthésée sans suffixe ((t) = 5 — (t).x = 5 reste valide).

Expressions

exp ::=  primary | functiondef | binary | unary

primary ::=  nil | false | true | Numeral | LiteralString | '...' |
     prefixexp | tableconstructor

prefixexp ::= var | functioncall | '(' exp ')'

functioncall ::=  prefixexp args | prefixexp ':' Name args

args ::=  '(' [explist] ')' | tableconstructor | LiteralString

functiondef ::= function funcbody

funcbody ::= '(' [parlist] ')' block end

parlist ::= namelist [',' '...'] | '...'

function t:m(...) ... end (voir Fonctions) désucre en une funcbody dont le premier paramètre implicite est self ; ce paramètre n'apparaît pas dans parlist tel qu'écrit par l'auteur du script.

tableconstructor ::= '{' [fieldlist] '}'

fieldlist ::= field {fieldsep field} [fieldsep]

field ::= '[' exp ']' '=' exp | Name '=' exp | exp

fieldsep ::= ',' | ';'

Opérateurs

binary ::= exp binop exp

unary ::= unop exp

binop ::=  '+' | '-' | '*' | '/' | '//' | '^' | '%' |
     '&' | '~' | '|' | '>>' | '<<' | '..' |
     '<' | '<=' | '>' | '>=' | '==' | '~=' |
     and | or

unop ::= '-' | not | '#' | '~' | '+'

Précédence, associativité et sémantique de chaque opérateur : voir Expressions et opérateurs. Le + unaire est syntaxiquement accepté (unop) mais purement décoratif : le parseur l'ignore sans produire de nœud — voir Expressions.

Point d'attention : ambiguïté classique avec une instruction commençant par (

prefixexp inclut '(' exp ')' (ci-dessus) aussi bien en position d'expression qu'en position d'instruction : (f)(), (t.x).y, (g()).hello() sont tous valides, y compris comme instruction autonome ((f)() seule sur sa ligne).

Cela réintroduit l'ambiguïté classique de Lua : l'absence de point-virgule n'étant pas une fin d'instruction, deux instructions consécutives où la seconde commence par ( peuvent fusionner en une seule si la première se termine par une expression :

local g = f
(g)()   -- lu comme f(g)(), PAS comme deux instructions distinctes

Ajoutez un ; explicite avant une instruction commençant par ( si l'instruction précédente se termine par une expression, pour lever l'ambiguïté :

local g = f;
(g)()   -- deux instructions distinctes, sans ambiguïté