blob: b072f9f01254e376c3ba27b9a4b7bb6083873327 [file] [log] [blame]
-------------------------------------------------------------------------------
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
--
-- All rights reserved.
--
-- This program and the accompanying materials are made available
-- under the terms of the Eclipse Public License v1.0 which
-- accompanies this distribution, and is available at
-- http://www.eclipse.org/legal/epl-v10.html
--
-- This program and the accompanying materials are also made available
-- under the terms of the MIT public license which accompanies this
-- distribution, and is available at http://www.lua.org/license.html
--
-- Contributors:
-- Fabien Fleutot - API and implementation
--
-------------------------------------------------------------------------------
require 'metalua.walk'
require 'metalua.walk.scope'
function bindings(ast)
-- binders :: ast => name => occurences
-- unbound :: name => occurences
-- scope :: name => ast
local binders, unbound, cfg, scope = { }, { }, { scope={ } }, scope:new()
-- * id: identifier entering in scope
-- * ast: statement or expr carrying this id, on of:
-- Local, Localrec, Forin, Fornum, Function.
function cfg.binder (id, ast)
if id.tag ~= 'Id' then return end
local id_name = id[1]
-- Reference in scope, so that the binding statement can be retrieved:
scope.current[id_name] = ast
-- Init the occurences list for this identifier:
if binders[ast] then binders[ast][id_name] = { }
else binders[ast] = { [id_name] = { } } end
end
-- identifier occurence, not as a binder: reference this occurence
function cfg.Id (id)
local id_name = id[1]
-- ast which binds this id, might be nil:
local binder_ast = scope.current [id_name]
-- dict id_name => occurences, might be the list of unbound occurences:
local occur_dict = binder_ast and binders[binder_ast] or unbound
-- add an occurence of `id' in the occurences list:
local occurences = occur_dict [id_name]
if occurences then table.insert (occurences, id)
else occur_dict [id_name] = { id } end
end
--Do not choke on partial ASTs which contain `Error{} nodes
function cfg.error(x) end
function cfg.scope.down() scope:push() end
function cfg.scope.up() scope:pop() end
walk.guess (cfg, ast)
return binders, unbound
end