lib/finitio/system.rb
module Finitio
#
# A System is a collection of named Finitio types.
#
class System
def initialize(types = {}, imports = [])
@types = types
@imports = imports
end
attr_reader :types, :imports
private :imports
def add_import(system)
@imports << system
end
def add_type(type, name = nil, metadata = nil)
type = factory.type(type, name, metadata)
if @types.has_key?(type.name)
raise Error, "Duplicate type name `#{type.name}`"
end
@types[type.name] = type
end
def each_type(&bl)
@types.values.each(&bl)
end
private :each_type
def each_import(&bl)
@imports.each(&bl)
end
private :each_import
def get_type(name)
fetch(name){|_|
fetch(name.to_s){ nil }
}
end
alias :[] :get_type
def main
self['Main']
end
def fetch(name, with_imports = true, &bl)
if with_imports
@types.fetch(name) do
fetch_on_imports(name, &bl)
end
else
@types.fetch(name, &bl)
end
end
def fetch_on_imports(name, imports = @imports, &bl)
if imports.empty?
raise KeyError, %Q{key not found: "#{name}"} unless bl
bl.call(name)
else
imports.first.fetch(name, false) do
fetch_on_imports(name, imports[1..-1], &bl)
end
end
end
def factory
@factory ||= TypeFactory.new
end
TypeFactory::DSL_METHODS.each do |dsl_method|
define_method(dsl_method){|*args, &bl|
factory.public_send(dsl_method, *args, &bl)
}
end
def dress(*args, &bl)
raise Error, "No main type." unless main
main.dress(*args, &bl)
end
def parse(source)
require_relative "syntax"
Syntax.compile(source, self.dup)
end
def inspect
@types.each_pair.map{|k,v| "#{k} = #{v}" }.join("\n")
end
def dup(types = @types.dup, imports = @imports.dup)
System.new(types, imports)
end
def check_and_warn(logger = nil)
logger ||= begin
require 'logger'
Logger.new(STDERR)
end
each_type do |t|
next unless t.named?
each_import do |i|
next unless found = i.get_type(t.name)
if found == t
logger.info "Duplicate type def `#{t.name}`"
break
else
logger.warn "Type erasure `#{t.name}`"
break
end
end
end
self
end
end # class System
end # module Finitio