module Emfrp::Typing
Public Instance Methods
additional_typing(top, definition)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 15 def additional_typing(top, definition) typing_syntax(top, definition) check_unbound_exp_type(definition, []) end
assoc(top, key, s)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 109 def assoc(top, key, s) top[:dict][key][s[:name][:desc]].get end
check_unbound_exp_type(syntax, allow_types)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 223 def check_unbound_exp_type(syntax, allow_types) case syntax when FuncDef allow_types = [syntax[:typing]] + syntax[:params].map{|x| x[:typing]} check_unbound_exp_type(syntax.values, allow_types) when TValue check_unbound_exp_type(syntax.values, [syntax[:typing]]) when NodeDef check_unbound_exp_type(syntax.values, []) when DataDef check_unbound_exp_type(syntax.values, []) when Syntax if syntax.has_key?(:typing) && syntax[:typing].has_var? syntax[:typing].typevars.each do |t| unless allow_types.any?{|at| at.include?(t)} raise TypeDetermineError.new(:undetermined, syntax[:typing], syntax) end end end check_unbound_exp_type(syntax.values, allow_types) when Array syntax.map{|e| check_unbound_exp_type(e, allow_types)} else # do nothing end end
clone_utypes(*utypes)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 203 def clone_utypes(*utypes) tbl = {} utypes.map{|t| t.clone_utype(tbl)} end
find_pattern_by_ref_name(pattern, name)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 208 def find_pattern_by_ref_name(pattern, name) if pattern[:ref] && pattern[:ref] == name pattern elsif pattern.is_a?(ValuePattern) pattern[:args].each do |p| if res = find_pattern_by_ref_name(p, name) return res end end return nil else return nil end end
get_var_typing(top, name, binder)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 158 def get_var_typing(top, name, binder) case binder when DataDef typing_syntax(top, binder) binder[:typing] when NodeDef param = binder[:params].find{|x| x[:as] == name} param[:typing] when FuncDef param = binder[:params].find{|x| x[:name] == name} param[:typing] when Case pattern = find_pattern_by_ref_name(binder[:pattern], name) raise "Assertion error: pattern-match-var #{name[:desc]} is not found" unless pattern pattern[:typing] else raise "Assertion error: unexpected binder type #{binder.class}" end end
try_unify(expected_utype, real_utype, place, *factors)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 250 def try_unify(expected_utype, real_utype, place, *factors) real_utype.unify(expected_utype) rescue UnionType::UnifyError => err raise TypeMatchingError.new(:unify, expected_utype, real_utype, place, *factors) end
typing(top, s=top)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 9 def typing(top, s=top) typing_syntax(top, s) typing_node(top) check_unbound_exp_type(s, []) end
typing_exp(top, e)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 114 def typing_exp(top, e) case e when FuncCall f = assoc(top, :func_space, e) typing_syntax(top, f) return_type, *arg_types = clone_utypes(f[:typing], *f[:params].map{|x| x[:typing]}) e[:args].zip(arg_types).each do |a, t| try_unify(t, typing_exp(top, a), "argument of function `#{f[:name][:desc]}'", a) end return e[:typing] = return_type when ValueConst tvalue = assoc(top, :const_space, e) typing_syntax(top, tvalue) return_type, *arg_types = clone_utypes(tvalue[:typing], *tvalue[:params].map{|x| x[:typing]}) e[:args].zip(arg_types).each do |a, t| try_unify(t, typing_exp(top, a), "argument of value-constructor `#{tvalue[:name][:desc]}'", a) end return e[:typing] = return_type when MatchExp pattern_type = UnionType.new return_type = UnionType.new e[:cases].each do |c| try_unify(pattern_type, typing_pattern(top, c[:pattern]), "pattern of MatchExp", c[:pattern]) try_unify(return_type, typing_exp(top, c[:exp]), "body-expression of MatchExp", c[:exp]) end try_unify(pattern_type, typing_exp(top, e[:exp]), "left-exp of MatchExp", e[:exp]) return e[:typing] = return_type when LiteralIntegral return e[:typing] = UnionType.new("Int", []) when LiteralFloating return e[:typing] = UnionType.new("Double", []) when LiteralChar return e[:typing] = UnionType.new("Char", []) when VarRef return e[:typing] = get_var_typing(top, e[:name], e[:binder].get) when SkipExp return e[:typing] = UnionType.new when ParenthExp return e[:typing] = typing_exp(top, e[:exp]) else raise "Assertion error: unexpected exp type #{e.class}" end end
typing_node(top)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 20 def typing_node(top) # typing Inputs top[:inputs].each do |i| i[:typing] = UnionType.from_type(i[:type]) if i[:init_exp] init_exp_type = typing_exp(top, i[:init_exp]) try_unify(i[:typing], init_exp_type, "init-exp for input `#{i[:name][:desc]}`", i[:init_exp]) end end # typing Nodes top[:nodes].each do |n| n[:typing] = UnionType.new n[:params].each do |x| x[:typing] = UnionType.new end if n[:init_exp] init_exp_type = typing_exp(top, n[:init_exp]) try_unify(n[:typing], init_exp_type, "init-exp for node `#{n[:name][:desc]}`", n[:init_exp]) end body_exp_type = typing_exp(top, n[:exp]) try_unify(n[:typing], body_exp_type, "body-exp for node `#{n[:name][:desc]}`", n[:exp]) if n[:type] try_unify(UnionType.from_type(n[:type]), n[:typing], "type-annotation for node `#{n[:name][:desc]}'", n) end end # unify Outputs and Nodes top[:outputs].each do |x| if x[:type] x[:typing] = UnionType.from_type(x[:type]) else x[:typing] = UnionType.new end node = assoc(top, :node_space, x) try_unify(node[:typing], x[:typing], "output `#{x[:name][:desc]}'", x) end # unify Node-params and Nodes top[:nodes].each do |n| n[:params].each do |param| node = assoc(top, :node_space, param) s = "parameter `#{param[:name][:desc]}' for node `#{n[:name][:desc]}'" try_unify(node[:typing], param[:typing], s, param) end end end
typing_pattern(top, pattern)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 178 def typing_pattern(top, pattern) case pattern when AnyPattern pattern[:typing] = UnionType.new when ValuePattern tvalue = assoc(top, :const_space, pattern) typing_syntax(top, tvalue) return_type, *etypes = clone_utypes(tvalue[:typing], *tvalue[:params].map{|x| x[:typing]}) rtypes = pattern[:args].map{|a| typing_pattern(top, a)} pattern[:args].each_with_index do |a, i| try_unify(etypes[i], rtypes[i], "arg for pattern `#{pattern[:name][:desc]}'", a) end pattern[:typing] = return_type when IntegralPattern pattern[:typing] = UnionType.new("Int", []) else raise "Assertion error: unexpected pattern type #{pattern.class}" end if pattern[:type] s = "type annotation for pattern" try_unify(UnionType.from_type(pattern[:type]), pattern[:typing], s, pattern) end return pattern[:typing] end
typing_syntax(top, s)
click to toggle source
# File lib/emfrp/typing/typing.rb, line 65 def typing_syntax(top, s) if s.is_a?(Syntax) return if s.has_key?(:typing) if s.has_key?(:typing_lock) raise CompileError.new("`#{s[:name][:desc]}' is defined recursively:\n", s) end s[:typing_lock] = true end case s when FuncDef tbl = {} s[:params].each do |x| x[:typing] = x[:type] ? UnionType.from_type(x[:type], tbl) : UnionType.new end s[:typing] = typing_exp(top, s[:exp]) if s[:type] str = "type-annotation for func `#{s[:name][:desc]}'" try_unify(UnionType.from_type(s[:type], tbl), s[:typing], str, s) end when DataDef s[:typing] = typing_exp(top, s[:exp]) if s[:type] str = "type-annotation for data `#{s[:name][:desc]}'" try_unify(UnionType.from_type(s[:type], tbl), s[:typing], str, s) end when PrimFuncDef s[:params].each do |x| x[:typing] = UnionType.from_type(x[:type]) end s[:typing] = UnionType.from_type(s[:type]) when TValue tbl = {} s[:params].each do |x| x[:typing] = UnionType.from_type(x[:type], tbl) end s[:typing] = UnionType.from_type(s[:type_def].get[:type], tbl) when Syntax typing_syntax(top, s.values) when Array s.each{|x| typing_syntax(top, x)} end s.delete(:typing_lock) if s.is_a?(Syntax) end