]> git.lizzy.rs Git - metalua.git/blob - src/samples/metalint/README.TXT
Merge remote branch 'origin/master'
[metalua.git] / src / samples / metalint / README.TXT
1 Metalint 0.2 - README.TXT
2 =========================
3
4 Metalint is a utility that checks Lua and Metalua source files for global
5 variables usage. Beyond checking toplevel global variables, it also checks
6 fields in modules: for instance, it will catch typos such as taable.insert(),
7 both also table.iinsert().
8
9 Metalint works with declaration files, which list which globals are declared,
10 and what can be done with them. The syntax is:
11
12 DECL      ::= (DECL_ELEM ";"?) *
13 DECL_ELEM ::= NAME | "module" NAME DECL "end" | "free" NAME | "private" DECL_ELEM
14 NAME      ::= <identifier> | <string>
15
16 Identifiers and strings are the same as in Lua, except that the only reserved
17 keywords are "free", "module", "end" and "private". A variable name can be
18 equivalently specified as a string or as an identifier. Lua comments are allowed
19 in declaration files, short and long. Check for *.dlua files in the distribution
20 for examples.
21
22 Meaning of declaration elements:
23
24 - Standalone names declare the existence of a variable. This variable is not a
25   module, i.e. people must not extract fields from it. For instance, the
26   function ipairs() will simply be declared as: "ipairs". With this declaration, 
27   it's an error to write, for instance, "ipairs.some_field".
28
29 - Names preceded with "free" can be used as you want, including arbitrary
30   sub-indexing. This is useful for global tables not used as modules, and for
31   modules you're too lazy to fully declare. For instance, the declaration "free
32   _G" allows you to bypass all checkings, as long as you access stuff through _G
33   rather than directly (i.e. "table.iinsert" will fail, but "_G.table.iinsert"
34   will be accepted).
35
36 - modules contain field declarations. For instance, the contents of the standard
37   "os" module will be declared as "module os exit ; setlocale; date; [...]
38   execute end".
39
40 Declaration files are loaded:
41
42 - manually, by passing "-f filename", "-l libname" or "-e
43   decl_literal_expression" as options to the checking program. Options are
44   processed in order, i.e. if you load a library after a file name to check,
45   this library won't be accessible while checking the dource file.
46
47 - automatically, when a call to "require()" is found in the code.
48
49 - declaration library "base" is automatically loaded.
50
51 Declaration library files are retrieved with the same algorithm as for Lua
52 libraries, except that the pattern string is taken from environment variable
53 LUA_DPATH rather than LUA_PATH or LUA_CPATH. For instance, if
54 LUA_DPATH="./?.dlua" and a "require 'walk.id'" is found, the checker will
55 attempt to load "./walk/id.dlua". It won't fail if it can't find it, but then,
56 attempts to use globals declared by walk.id are likely to fail.
57
58 The metalua base libraries, which include Lua base libraries, can be found in
59 base.dlua. They're automatically loaded when you run metalint.
60
61 Limitations: if you try to affect custom names to modules, e.g. "local
62 wi=require 'walk.id'", the checker won't be able to check your usage of
63 subfields of "wi". Similarly, if you redefine require() or module(), or create
64 custom versions of these, metalint will be lost. Finally, computed access to
65 modules are obviously not checked, i.e. "local x, y = 'iinsert', { };
66 table[x](y, 1)" will be accepted.
67
68 Future: Metalint is intended to support richer static type checkings, including
69 function argument types. The idea is not to formally prove type soundness, but
70 to accelerate the discovery of many silly bugs when using a (possibly third
71 party) library. However, to perform interesting checks, the type declaration
72 system must support a couple of non-trivial stuff like union types and higher
73 order functions. Moreover, runtime checking code could optionally be inserted to
74 check that a function API is respected when it's called (check the types
75 extension in Metalua). Stay tuned.
76
77 Notice that metalint can easily be turned into a smarter variable localizer,
78 which would change references to module elements into local variables.
79 For instance, it would add "local _table_insert = table.insert" at the beginning
80 of the file, and change every instance of "table.insert" into a reference to the
81 local variable. This would be much more efficient than simply adding a "local
82 table=table".
83
84
85
86 Finally, to accelerate the migration of existing codebases, a decl_dump()
87 function is provided with metalint, which attempts to generate a declaration for
88 a module currently loaded in RAM. The result is not always perfect, but remains
89 a serious time saver:
90
91 ~/src/metalua/src/sandbox$ metalua
92 Metalua, interactive REPLoop.
93 (c) 2006-2008 <metalua@gmail.com>
94 M> require    "metalint"
95 M> require    "walk"
96 M> decl_dump ("walk", "decl/walk.dlua")
97 M> ^D
98 ~/src/metalua/src/sandbox$ cat decl/walk.dlua
99 module walk
100   debug;
101   module tags
102     module stat
103       Forin;
104       Do;
105       Set;
106       Fornum;
107       Invoke;
108       While;
109       Break;
110       Call;
111       Label;
112       Goto;
113       Local;
114       If;
115       Repeat;
116       Localrec;
117       Return;
118     end;
119     module expr
120       True;
121       String;
122       Index;
123       Paren;
124       Id;
125       False;
126       Invoke;
127       Function;
128       Op;
129       Number;
130       Table;
131       Dots;
132       Nil;
133       Stat;
134       Call;
135     end;
136   end;
137   expr_list;
138   binder_list;
139   guess;
140   expr;
141   block;
142   module traverse
143     expr;
144     block;
145     stat;
146     expr_list;
147   end;
148   stat;
149 end;
150
151 NEW SINCE 0.1:
152 ==============
153
154 Feature-wise, option -a replaces all references to declared fields with locals
155 and stores the compiled result in a .luac compiled file
156
157 Architecture-wise, the system now remembers where (i.e. by which require()
158 statement, if applicable) a given field has been declared. This is necessary for
159 the autolocal feature to work correctly.