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