----------------------------------------------------------------------
-- TODO: hygiene wrt type()
+-- TODO: cfg.ntmp isn't reset as often as it could. I'm not even sure
+-- the corresponding locals are declared.
module ('spmatch', package.seeall)
id_pattern_element_builder (pattern, term, cfg)
elseif "Op" == pattern.tag and "div" == pattern[1] then
regexp_pattern_element_builder (pattern, term, cfg)
+ elseif "Op" == pattern.tag and "eq" == pattern[1] then
+ eq_pattern_element_builder (pattern, term, cfg)
elseif "Table" == pattern.tag then
table_pattern_element_builder (pattern, term, cfg)
else
end
end
+function eq_pattern_element_builder (pattern, term, cfg)
+ local _, pat1, pat2 = unpack (pattern)
+ local ntmp_save = cfg.ntmp
+ pattern_element_builder (pat1, term, cfg)
+ cfg.ntmp = ntmp_save
+ pattern_element_builder (pat2, term, cfg)
+end
+
-- pattern :: `Op{ 'div', string, list{`Id string} or `Id{ string }}
-- term :: expr
function regexp_pattern_element_builder (pattern, term, cfg)
local v2 = next_tmpvar(cfg)
acc_assign (v2, `Index{ term, key }, cfg)
pattern_element_builder (sub_pattern, v2, cfg)
+ -- TODO: restore ntmp?
end
end
if not seen_dots then -- Check arity
--- /dev/null
+-- static partial checkings for Lua.\r
+--\r
+-- This program checks some metalua or plain lua source code for most common\r
+-- mistakes. Its design focuses on the ability to check plain lua code: there is\r
+-- no need to load any extension in the module.\r
+--\r
+-- The current checkings include:\r
+--\r
+-- * Listing all free variables, and make sure they are declared.\r
+-- * For free vars known as modules, check that indexings in them are also\r
+-- declared.\r
+-- * When the type of something is known, do some basic type checkings. These\r
+-- checkings are by no means exhaustive; however, when a parameter function\r
+-- is constant or statically declared, it's checked.\r
+\r
+\r
+\r
+--[[\r
+Type grammar:\r
+\r
+t ::=\r
+| t and t\r
+| t or t\r
+| function (t, ...) return t, ... end\r
+| { (k=t)... }\r
+| table(t, t)\r
+| string\r
+| number\r
+| integer\r
+| boolean\r
+| userdata\r
+| nil\r
+| multi(t, ...)\r
+| _\r
+\r
+--]]\r
+\r
+\r
+match function get_type\r
+| `Number{...} -> return +{number}\r
+| `String{...} -> return +{string}\r
+| `True|`False -> return +{boolean}\r
+| `Nil -> return +{nil}\r
+| `Dots -> return +{_}\r
+| `Stat{_,v} -> return get_type(v)\r
+| `Paren{t} -> return get_one_type(t)\r
+| `Call{f, ...} -> \r
+ local ftype = get_type(f)\r
+ match ftype with\r
+ | `Function{ _, {`Return{result}} } -> return get_type(result)\r
+ | `Function{ _, {`Return{...} == results} } ->\r
+ local r2 = +{ multi() }\r
+ for r in ivalues(results) table.insert(r2, get_type(r)) end\r
+ return r2\r
+ | `And{...} -> return +{_} -- not implemented\r
+ | `Or{ a, b } -> match get_one_type(a), get_one_type(b) with\r
+ | `Function{...}==f1, `Function{...}==f2 ->\r
+ return `Op{ 'or', get_type(`Call{f1}), get_type(`Call{f2})}\r
+ | `Function{...}==f, _ | _, `Function{...}==f ->\r
+ return get_type(`Call{f})\r
+ | _ -> return +{_}\r
+ end\r
+| `Invoke{o, m, ... } == x -> return get_type(`Call{`Index{o, m}})\r
+| `Op{...}==o -> return get_op_type(o)\r
+| `Table{...}==t ->\r
+ local r = `Table{ }\r
+ for x in ivalues(t) do\r
+ match x with\r
+ | `Pair{ `String{...}==k, v } -> table.insert(r, `Pair{k, get_one_type(v)})\r
+ | t -> table.insert(r, get_one_type(t))\r
+ end\r
+ end\r
+ return r\r
+| `Function{...}==f ->\r
+| `Id{v} ->\r
+| `Index{t, k} -> match get_one_type(t), get_one_type(k) with\r
+ | `Call{`Id 'table', tk, tv }, _ -> return tv\r
+ | `Table{...}==tt, `Id 'string' ->\r
+\r
+\r
+\r
+local types_rt = require 'extension.types'\r
+\r
+\r
+\r
+\r
+function check_function(f, term)\r
+ match get_type(term) with\r
+ | `Function{ params, {`Return{...} == results}}, args ->\r
+ | `And{ a, b }, args ->\r
+ check_function(a, args)\r
+ check_function(b, args)\r
+ | `Or{ a, b }, args ->\r
+ if not pcall(check_function, a, args) then check_function(b, args) end\r
+ | `Id '_' -> -- pass\r
+ | _ -> error ("Call to a non-function")\r
+ end\r
+end\r
+\r
+function check_index(a, b, term)\r
+ match get_type(term) with\r
+ | `Table{}\r
+\r
+match function cfg.id.up\r
+| `Call{ f, ... } == x -> check_function (f, x)\r
+| `Index{ a, b } == x -> check_index (a, b, x)\r
+end \r
+\r
+\r
+-- List free vars\r
+cfg.id.
\ No newline at end of file