1 -- static partial checkings for Lua.
\r
3 -- This program checks some metalua or plain lua source code for most common
\r
4 -- mistakes. Its design focuses on the ability to check plain lua code: there is
\r
5 -- no need to load any extension in the module.
\r
7 -- The current checkings include:
\r
9 -- * Listing all free variables, and make sure they are declared.
\r
10 -- * For free vars known as modules, check that indexings in them are also
\r
12 -- * When the type of something is known, do some basic type checkings. These
\r
13 -- checkings are by no means exhaustive; however, when a parameter function
\r
14 -- is constant or statically declared, it's checked.
\r
24 | function (t, ...) return t, ... end
\r
39 match function get_type
\r
40 | `Number{...} -> return +{number}
\r
41 | `String{...} -> return +{string}
\r
42 | `True|`False -> return +{boolean}
\r
43 | `Nil -> return +{nil}
\r
44 | `Dots -> return +{_}
\r
45 | `Stat{_,v} -> return get_type(v)
\r
46 | `Paren{t} -> return get_one_type(t)
\r
48 local ftype = get_type(f)
\r
50 | `Function{ _, {`Return{result}} } -> return get_type(result)
\r
51 | `Function{ _, {`Return{...} == results} } ->
\r
52 local r2 = +{ multi() }
\r
53 for r in ivalues(results) table.insert(r2, get_type(r)) end
\r
55 | `And{...} -> return +{_} -- not implemented
\r
56 | `Or{ a, b } -> match get_one_type(a), get_one_type(b) with
\r
57 | `Function{...}==f1, `Function{...}==f2 ->
\r
58 return `Op{ 'or', get_type(`Call{f1}), get_type(`Call{f2})}
\r
59 | `Function{...}==f, _ | _, `Function{...}==f ->
\r
60 return get_type(`Call{f})
\r
63 | `Invoke{o, m, ... } == x -> return get_type(`Call{`Index{o, m}})
\r
64 | `Op{...}==o -> return get_op_type(o)
\r
67 for x in ivalues(t) do
\r
69 | `Pair{ `String{...}==k, v } -> table.insert(r, `Pair{k, get_one_type(v)})
\r
70 | t -> table.insert(r, get_one_type(t))
\r
74 | `Function{...}==f ->
\r
76 | `Index{t, k} -> match get_one_type(t), get_one_type(k) with
\r
77 | `Call{`Id 'table', tk, tv }, _ -> return tv
\r
78 | `Table{...}==tt, `Id 'string' ->
\r
82 local types_rt = require 'extension.types'
\r
87 function check_function(f, term)
\r
88 match get_type(term) with
\r
89 | `Function{ params, {`Return{...} == results}}, args ->
\r
90 | `And{ a, b }, args ->
\r
91 check_function(a, args)
\r
92 check_function(b, args)
\r
93 | `Or{ a, b }, args ->
\r
94 if not pcall(check_function, a, args) then check_function(b, args) end
\r
95 | `Id '_' -> -- pass
\r
96 | _ -> error ("Call to a non-function")
\r
100 function check_index(a, b, term)
\r
101 match get_type(term) with
\r
104 match function cfg.id.up
\r
105 | `Call{ f, ... } == x -> check_function (f, x)
\r
106 | `Index{ a, b } == x -> check_index (a, b, x)
\r