@@ -50,6 +50,10 @@ local default_whitelist = Set({
5050 " true" ,
5151 " false"
5252})
53+ local default_stages = {
54+ globals = true ,
55+ unused = true
56+ }
5357local LinterBlock
5458do
5559 local _class_0
6569 end
6670 end ,
6771 lint_check_unused = function (self )
72+ if not (self .stages .unused ) then
73+ return
74+ end
6875 if not (self .lint_unused_names and next (self .lint_unused_names )) then
6976 return
7077 end
141148 _base_0 .__index = _base_0
142149 setmetatable (_base_0 , _parent_0 .__base )
143150 _class_0 = setmetatable ({
144- __init = function (self , whitelist_globals , ...)
151+ __init = function (self , whitelist_globals , stages , ...)
145152 if whitelist_globals == nil then
146153 whitelist_globals = default_whitelist
147154 end
155+ if stages == nil then
156+ stages = default_stages
157+ end
148158 _class_0 .__parent .__init (self , ... )
149159 self .get_root_block = function ()
150160 return self
151161 end
162+ self .stages = stages
152163 self .lint_errors = { }
153164 local vc = self .value_compilers
154165 self .value_compilers = setmetatable ({
155166 ref = function (block , val )
156167 local name = val [2 ]
157- if not (block :has_name (name ) or whitelist_globals [name ] or name :match (" %." )) then
158- insert (self .lint_errors , {
159- " accessing global `" .. tostring (name ) .. " `" ,
160- val [- 1 ]
161- })
168+ if self .stages .globals then
169+ if not (block :has_name (name ) or whitelist_globals [name ] or name :match (" %." )) then
170+ insert (self .lint_errors , {
171+ " accessing global `" .. tostring (name ) .. " `" ,
172+ val [- 1 ]
173+ })
174+ end
175+ end
176+ if self .stages .unused then
177+ block :lint_mark_used (name )
162178 end
163- block :lint_mark_used (name )
164179 return vc .ref (block , val )
165180 end
166181 }, {
169184 local sc = self .statement_compilers
170185 self .statement_compilers = setmetatable ({
171186 assign = function (block , node )
172- local names = node [2 ]
173- for _index_0 = 1 , # names do
174- local _continue_0 = false
175- repeat
176- local name = names [_index_0 ]
177- if type (name ) == " table" and name [1 ] == " temp_name" then
178- _continue_0 = true
179- break
180- end
181- local real_name , is_local = block :extract_assign_name (name )
182- if not (is_local or real_name and not block :has_name (real_name , true )) then
183- _continue_0 = true
184- break
185- end
186- if real_name == " _" then
187+ if self .stages .unused then
188+ local names = node [2 ]
189+ for _index_0 = 1 , # names do
190+ local _continue_0 = false
191+ repeat
192+ local name = names [_index_0 ]
193+ if type (name ) == " table" and name [1 ] == " temp_name" then
194+ _continue_0 = true
195+ break
196+ end
197+ local real_name , is_local = block :extract_assign_name (name )
198+ if not (is_local or real_name and not block :has_name (real_name , true )) then
199+ _continue_0 = true
200+ break
201+ end
202+ if real_name == " _" then
203+ _continue_0 = true
204+ break
205+ end
206+ block .lint_unused_names = block .lint_unused_names or { }
207+ block .lint_unused_names [real_name ] = node [- 1 ] or 0
187208 _continue_0 = true
209+ until true
210+ if not _continue_0 then
188211 break
189212 end
190- block .lint_unused_names = block .lint_unused_names or { }
191- block .lint_unused_names [real_name ] = node [- 1 ] or 0
192- _continue_0 = true
193- until true
194- if not _continue_0 then
195- break
196213 end
197214 end
198215 return sc .assign (block , node )
@@ -270,14 +287,18 @@ format_lint = function(errors, code, header)
270287end
271288local whitelist_for_file
272289do
273- local lint_config
274- whitelist_for_file = function (fname )
275- if not (lint_config ) then
276- lint_config = { }
290+ local loaded_configs = { }
291+ whitelist_for_file = function (fname , config_module )
292+ if config_module == nil then
293+ config_module = " lint_config"
294+ end
295+ if not (loaded_configs [config_module ]) then
296+ loaded_configs [config_module ] = { }
277297 pcall (function ()
278- lint_config = require (" lint_config " )
298+ loaded_configs [ config_module ] = require (config_module )
279299 end )
280300 end
301+ local lint_config = loaded_configs [config_module ]
281302 if not (lint_config .whitelist_globals ) then
282303 return default_whitelist
283304 end
295316 })
296317 end
297318end
319+ local normalize_stages
320+ normalize_stages = function (stages )
321+ if not (stages ) then
322+ return default_stages
323+ end
324+ if stages .globals ~= nil or stages .unused ~= nil then
325+ return stages
326+ end
327+ local out = { }
328+ for _index_0 = 1 , # stages do
329+ local stage = stages [_index_0 ]
330+ out [stage ] = true
331+ end
332+ return out
333+ end
298334local lint_code
299- lint_code = function (code , name , whitelist_globals )
335+ lint_code = function (code , name , opts )
300336 if name == nil then
301337 name = " string input"
302338 end
339+ if opts == nil then
340+ opts = { }
341+ end
303342 local parse = require (" moonscript.parse" )
304343 local tree , err = parse .string (code )
305344 if not (tree ) then
306345 return nil , err
307346 end
308- local scope = LinterBlock (whitelist_globals )
347+ local whitelist_globals = opts .whitelist_globals or default_whitelist
348+ local stages = normalize_stages (opts .stages )
349+ local scope = LinterBlock (whitelist_globals , stages )
309350 scope :stms (tree )
310351 scope :lint_check_unused ()
311352 return format_lint (scope .lint_errors , code , name )
312353end
313354local lint_file
314- lint_file = function (fname )
355+ lint_file = function (fname , opts )
356+ if opts == nil then
357+ opts = { }
358+ end
315359 local f , err = io.open (fname )
316360 if not (f ) then
317361 return nil , err
318362 end
319- return lint_code (f :read (" *a" ), fname , whitelist_for_file (fname ))
363+ local config_module = opts .config_module or " lint_config"
364+ return lint_code (f :read (" *a" ), fname , {
365+ whitelist_globals = whitelist_for_file (fname , config_module ),
366+ stages = opts .stages
367+ })
320368end
321369return {
322370 lint_code = lint_code ,
0 commit comments