class Steep::Typing
def self.summary(node)
def self.summary(node) src = node.loc.expression.source.split(/\n/).first line = node.loc.first_line col = node.loc.column "#{line}:#{col}:#{src}" end
def add_error(error)
def add_error(error) errors << error end
def add_typing(node, type)
def add_typing(node, type) typing[node.__id__] = type nodes[node.__id__] = node if should_update @last_update += 1 @should_update = false end type end
def dump(io)
def dump(io) io.puts "Typing: " nodes.each_value do |node| io.puts " #{Typing.summary(node)} => #{type_of(node: node).inspect}" end io.puts "Errors: " errors.each do |error| io.puts " #{Typing.summary(error.node)} => #{error.inspect}" end end
def each_typing
def each_typing nodes.each do |id, node| yield node, typing[id] end end
def has_type?(node)
def has_type?(node) typing.key?(node.__id__) end
def initialize(parent: nil, parent_last_update: parent&.last_update)
def initialize(parent: nil, parent_last_update: parent&.last_update) @parent = parent @parent_last_update = parent_last_update @last_update = parent&.last_update || 0 @should_update = false @errors = [] @nodes = {} @var_typing = {} @typing = {} end
def new_child
def new_child child = self.class.new(parent: self) @should_update = true if block_given? yield child else child end end
def save!
def save! raise "Unexpected save!" unless parent raise "Parent modified since new_child" unless parent.last_update == parent_last_update each_typing do |node, type| parent.add_typing(node, type) end errors.each do |error| parent.add_error error end end
def type_of(node:)
def type_of(node:) type = typing[node.__id__] if type type else if parent parent.type_of(node: node) else raise "Unknown node for typing: #{node.inspect}" end end end