-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathexamples.lua
185 lines (143 loc) · 4.31 KB
/
examples.lua
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
--[[============================================================
--=
--= Examples for Dumb Lua Parser
--=
--= 1 - Find globals
--= 2 - Detect variable shadowing
--= 3 - Replace calls to a function
--= 4 - Construct an AST (the painful way)
--=
--=-------------------------------------------------------------
--=
--= Dumb Lua Parser - Lua parsing library
--= by Marcus 'ReFreezed' Thunström
--=
--============================================================]]
local parser = require("dumbParser")
io.stdout:setvbuf("no")
io.stderr:setvbuf("no")
--
-- 1 - Find globals
--
local ast = parser.parse(
[[
local x = math.floor(1.5) -- 'math' is a global.
y = "foo" -- 'y' is a global.
]],
"dummyFilePath.lua"
)
parser.updateReferences(ast)
print("Globals:")
-- Note that parser.findGlobalReferences() could be used instead of this.
parser.traverseTree(ast, function(node)
if node.type == "identifier" and not node.declaration then
print(parser.formatMessage(node, "Found global '%s'.", node.name))
end
end)
print("\n\n")
--
-- 2 - Detect variable shadowing
--
local ast = parser.parse[[
local function foo(x, x)
for x = x-1, x+1 do
local x = "foo"
end
local x = x
end
]]
parser.updateReferences(ast)
print("Shadows:")
-- Note that findShadows() doesn't detect shadowing of globals.
for _, shadows in ipairs(parser.findShadows(ast)) do
for i, ident in ipairs(shadows) do
-- The first item in 'shadows' is the identifier shadowing the rest.
local message = (i == 1) and "This identifier is shadowing others:" or "Shadowed #"..i-1
print(parser.formatMessage(ident, message))
end
end
print("\n\n")
--
-- 3 - Replace calls to a function
--
--
-- Here we change calls to assert() into 'if' statements:
--
-- -- From this.
-- assert(foo)
--
-- -- Into this.
-- if not (foo) then
-- error("Assertion failed: foo")
-- end
--
local ast = parser.parse[[
local function calculate(x)
assert(type(x) == "number")
-- ...
end
local function doThing(foo)
assert(foo ~= "bar")
-- ...
end
]]
parser.traverseTree(ast, function(node, parent, container, key)
if node.type == "call" and node.callee.type == "identifier" and node.callee.name == "assert" then
-- We assume the parent is a block, i.e. that the call is a complete statement.
local oldCall = node
local oldCondition = oldCall.arguments[1]
-- Create the 'if' statement and the new condition.
local ifNode = parser.newNode("if")
ifNode.bodyTrue = parser.newNode("block")
local condition = parser.newNode("unary", "not")
condition.expression = oldCondition
ifNode.condition = condition
-- Create the error() call.
local message = "Assertion failed: " .. parser.toLua(oldCondition)
local errorCall = parser.newNode("call")
errorCall.callee = parser.newNode("identifier", "error")
errorCall.arguments[1] = parser.newNode("literal", message)
ifNode.bodyTrue.statements[1] = errorCall
-- Replace the node.
container[key] = ifNode
-- Prevent traversal down through the old call.
return "ignorechildren"
end
end)
print("Transformed code:")
print(parser.toLua(ast, true))
print("\n\n")
--
-- 4 - Construct an AST (the painful way)
--
--[[ This is the program we will create:
function _G.double(n)
return 2 * n
end
local x = double(5)
]]
local new = parser.newNode
local block = new("block")
local assignment = new("assignment")
assignment.targets[1] = new("lookup")
assignment.targets[1].object = new("identifier", "_G")
assignment.targets[1].member = new("literal", "double")
table.insert(block.statements, assignment)
local func = new("function")
func.parameters[1] = new("identifier", "n")
func.body = new("block")
assignment.values[1] = func
local ret = new("return")
ret.values[1] = new("binary", "*")
ret.values[1].left = new("literal", 2)
ret.values[1].right = new("identifier", "n")
table.insert(func.body.statements, ret)
local decl = new("declaration")
decl.names[1] = new("identifier", "x")
decl.values[1] = new("call")
decl.values[1].callee = new("identifier", "double")
decl.values[1].arguments[1] = new("literal", 5)
table.insert(block.statements, decl)
print("Constructed code:")
print(parser.toLua(block, true))
print("\n\n")