Decode SourceDecodeIndex

class Index

A list of definitions organised for quick lookup and lexical enumeration.

Definitions

def initialize(languages = Languages.all)

Initialize an empty index.

Implementation

def initialize(languages = Languages.all)
	@languages = languages
	
	@sources = {}
	@definitions = {}
	
	# This is essentially a prefix tree:
	@trie = Trie.new
end

attr :languages

All supported languages for this index.

Signature

attribute Languages

attr :sources

All source files that have been parsed.

Signature

attribute Array(Source)

attr :definitions

All definitions which have been parsed.

Signature

attribute Array(Symbol)

attr :trie

A (prefix) trie of lexically scoped definitions.

Signature

attribute Trie

def update(paths)

Updates the index by parsing the specified files. All extracted definitions are merged into the existing index.

Signature

parameter paths Array(String)

The source file paths.

Implementation

def update(paths)
	paths.each do |path|
		if source = @languages.source_for(path)
			@sources[path] = source
			
			source.definitions do |symbol|
				# $stderr.puts "Adding #{symbol.qualified_name} to #{symbol.lexical_path.join(' -> ')}"
				
				@definitions[symbol.qualified_name] = symbol
				@trie.insert(symbol.path, symbol)
			end
		end
	end
end

def lookup(reference, relative_to: nil)

Lookup the specified reference and return matching definitions.

Signature

parameter reference Language::Reference

The reference to match.

parameter relative_to Definition

Lookup the reference relative to the scope of this definition.

Implementation

def lookup(reference, relative_to: nil)
	if reference.absolute? || relative_to.nil?
		lexical_path = []
	else
		lexical_path = relative_to.path.dup
	end
	
	path = reference.path
	
	while true
		node = @trie.lookup(lexical_path)
		
		if node.children[path.first]
			if target = node.lookup(path)
				return reference.best(target.values)
			else
				return nil
			end
		end
		
		break if lexical_path.empty?
		lexical_path.pop
	end
end