DecodeSourceDecodeIndex

class Index

Represents a list of definitions organised for quick lookup and lexical enumeration.

Definitions

def self.for(*paths, languages: Languages.all)

Create and populate an index from the given paths.

Signature

parameter paths Array(String)

The paths to index (files, directories, or glob patterns).

parameter languages Languages

The languages to support in this index.

returns Index

A new index populated with definitions from the given paths.

Implementation

def self.for(*paths, languages: Languages.all)
	# Resolve all paths to actual files:
	resolved_paths = paths.flat_map do |path|
		if File.directory?(path)
			Dir.glob(File.join(path, "**/*"))
		elsif File.file?(path)
			[path]
		else
			# Handle glob patterns or non-existent paths:
			Dir.glob(path)
		end
	end
	
	resolved_paths.sort!
	resolved_paths.uniq!
	
	# Create and populate the index:
	index = new(languages)
	index.update(resolved_paths)
	
	return index
end

def initialize(languages = Languages.all)

Initialize an empty index.

Signature

parameter languages Languages

The languages to support in this index.

Implementation

def initialize(languages = Languages.all)
	# Initialize with supported languages:
	@languages = languages
	
	# Initialize storage for sources and definitions:
	@sources = {}
	@definitions = {}
	
	# Create a prefix tree for efficient lookups:
	@trie = Trie.new
end

def inspect

Generate a string representation of this index.

Signature

returns String

A formatted string showing the number of definitions.

Implementation

def inspect
	"#<#{self.class} #{@definitions.size} definition(s)>"
end

alias to_s inspect

Generate a string representation of the index.

attr :languages

All supported languages for this index.

Signature

attribute Languages

The languages this index can parse.

attr :sources

All source files that have been parsed.

Signature

attribute Hash(String, Source)

A mapping of file paths to source objects.

attr :definitions

All definitions which have been parsed.

Signature

attribute Hash(String, Definition)

A mapping of qualified names to definitions.

attr :trie

A (prefix) trie of lexically scoped definitions.

Signature

attribute Trie

The trie structure for efficient lookups.

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 to parse and index.

Implementation

def update(paths)
	paths.each do |path|
		if source = @languages.source_for(path)
			# Store the source file:
			@sources[path] = source
			
			# Extract and index all definitions:
			source.definitions do |symbol|
				# $stderr.puts "Adding #{symbol.qualified_name} to #{symbol.lexical_path.join(' -> ')}"
				
				# Add to definitions lookup:
				@definitions[symbol.qualified_name] = symbol
				
				# Add to trie for hierarchical lookup:
				@trie.insert(symbol.full_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.

returns Definition | Nil

The best matching definition, or nil if not found.

Implementation

def lookup(reference, relative_to: nil)
	if reference.absolute? || relative_to.nil?
		# Start from root scope:
		lexical_path = []
	else
		# Start from the given definition's scope:
		lexical_path = relative_to.full_path.dup
	end
	
	path = reference.path
	
	while true
		# Get the current scope node:
		node = @trie.lookup(lexical_path)
		
		if node.children[path.first]
			if target = node.lookup(path)
				# Return the best matching definition:
				return reference.best(target.values)
			else
				return nil
			end
		end
		
		# Move up one scope level:
		break if lexical_path.empty?
		lexical_path.pop
	end
end