This repository was archived by the owner on Nov 20, 2020. It is now read-only.
forked from fab13n/metalua
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtypecheck.mlua
More file actions
106 lines (93 loc) · 2.9 KB
/
typecheck.mlua
File metadata and controls
106 lines (93 loc) · 2.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
-- 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.