]> git.lizzy.rs Git - metalua.git/blobdiff - src/samples/typecheck.mlua
fix CRLF
[metalua.git] / src / samples / typecheck.mlua
index 631f6725c580bd4f2f9baf3ec29e373e58afb861..e9d6b7583c9f2bb14531403b2b612bd15c4891cf 100644 (file)
--- 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
+-- static partial checkings for Lua.
+--
+-- This program checks some metalua or plain lua source code for most common
+-- mistakes. Its design focuses on the ability to check plain lua code: there is
+-- no need to load any extension in the module.
+--
+-- The current checkings include:
+--
+-- * Listing all free variables, and make sure they are declared.
+-- * For free vars known as modules, check that indexings in them are also
+--   declared.
+-- * When the type of something is known, do some basic type checkings. These
+--   checkings are by no means exhaustive; however, when a parameter function
+--   is constant or statically declared, it's checked.
+
+
+
+--[[
+Type grammar:
+
+t ::=
+| t and t
+| t or  t
+| function (t, ...) return t, ... end
+| { (k=t)... }
+| table(t, t)
+| string
+| number
+| integer
+| boolean
+| userdata
+| nil
+| multi(t, ...)
+| _
+
+--]]
+
+
+match function get_type
+| `Number{...} -> return +{number}
+| `String{...} -> return +{string}
+| `True|`False -> return +{boolean}
+| `Nil         -> return +{nil}
+| `Dots        -> return +{_}
+| `Stat{_,v}   -> return get_type(v)
+| `Paren{t}    -> return get_one_type(t)
+| `Call{f, ...} -> 
+   local ftype = get_type(f)
+   match ftype with
+   | `Function{ _, {`Return{result}} } -> return get_type(result)
+   | `Function{ _, {`Return{...} == results} } ->
+      local r2 = +{ multi() }
+      for r in ivalues(results) table.insert(r2, get_type(r)) end
+      return r2
+   | `And{...} -> return +{_} -- not implemented
+   | `Or{ a, b } -> match get_one_type(a), get_one_type(b) with
+     | `Function{...}==f1, `Function{...}==f2 ->
+       return `Op{ 'or', get_type(`Call{f1}), get_type(`Call{f2})}
+     | `Function{...}==f, _ | _, `Function{...}==f ->
+       return get_type(`Call{f})
+   | _ -> return +{_}
+   end
+| `Invoke{o, m, ... } ==  x -> return get_type(`Call{`Index{o, m}})
+| `Op{...}==o -> return get_op_type(o)
+| `Table{...}==t ->
+   local r = `Table{ }
+   for x in ivalues(t) do
+      match x with
+      | `Pair{ `String{...}==k, v } -> table.insert(r, `Pair{k, get_one_type(v)})
+      | t -> table.insert(r, get_one_type(t))
+      end
+   end
+   return r
+| `Function{...}==f ->
+| `Id{v} ->
+| `Index{t, k} -> match get_one_type(t), get_one_type(k) with
+   | `Call{`Id 'table', tk, tv }, _ -> return tv
+   | `Table{...}==tt, `Id 'string' ->
+
+
+
+local types_rt = require 'extension.types'
+
+
+
+
+function check_function(f, term)
+   match get_type(term) with
+   | `Function{ params, {`Return{...} == results}}, args ->
+   | `And{ a, b }, args ->
+      check_function(a, args)
+      check_function(b, args)
+   | `Or{ a, b }, args ->
+      if not pcall(check_function, a, args) then check_function(b, args) end
+   | `Id '_' -> -- pass
+   | _ -> error ("Call to a non-function")
+   end
+end
+
+function check_index(a, b, term)
+   match get_type(term) with
+   | `Table{}
+
+match function cfg.id.up
+| `Call{ f, ... } == x -> check_function (f, x)
+| `Index{ a, b }  == x -> check_index (a, b, x)
+end   
+
+
+-- List free vars
 cfg.id.
\ No newline at end of file