module Dhallish
Public Class Methods
create_ctx(dhallcode, basedir=Dir.pwd)
click to toggle source
# File lib/dhallish.rb, line 53 def create_ctx(dhallcode, basedir=Dir.pwd) empty_ctx = empty_context(basedir) ctx, type = evaluate(dhallcode, empty_ctx) if type != Types::Record.new({}) or ctx["<#TYPES#>"].nil? or ctx["<#VALS#>"].nil? raise DhallError, "return type of dhallcode supplied to `create_ctx` did not return a context (but something of type `#{type}`). use `???`" end ctx end
empty_context(basedir=Dir.pwd)
click to toggle source
# File lib/dhallish.rb, line 20 def empty_context(basedir=Dir.pwd) ctx = { "<#TYPES#>" => Context.new, "<#VALS#>" => Context.new } ctx["<#TYPES#>"]["<#DIR#>"] = basedir fill_context(ctx["<#VALS#>"], ctx["<#TYPES#>"]) ctx end
evaluate(dhallcode, ctx=nil, expected_type=nil)
click to toggle source
# File lib/dhallish.rb, line 28 def evaluate(dhallcode, ctx=nil, expected_type=nil) if ctx.nil?; ctx = empty_context() end rawast = @@parser.parse dhallcode if rawast.nil? raise DhallError, "#{@@parser.failure_reason} (line/column: #{@@parser.failure_line}:#{@@parser.failure_column})" end ast = rawast.to_node type = ast.compute_type ctx["<#TYPES#>"] res = ast.evaluate ctx["<#VALS#>"] if !expected_type.nil? if !(type == expected_type) raise DhallError, "expression return type missmatch: expected `#{expected_type}`, got: `#{type}`" else res end else [res, type] end end
fill_context(globalctx, types)
click to toggle source
# File lib/stdlib.rb, line 24 def fill_context(globalctx, types) # Types: globalctx["Natural"] = Types::Natural globalctx["Integer"] = Types::Integer globalctx["Double"] = Types::Double globalctx["Bool"] = Types::Bool globalctx["Text"] = Types::Text globalctx["Type"] = Types::Type.new types["Natural"] = Types::Type.new(Types::Natural) types["Integer"] = Types::Type.new(Types::Integer) types["Double"] = Types::Type.new(Types::Double) types["Bool"] = Types::Type.new(Types::Bool) types["Text"] = Types::Type.new(Types::Text) types["Type"] = Types::Type.new(Types::Type.new) # Shows: globalctx["Natural/show"] = BuiltinFunction.new { |arg| arg.to_s } types["Natural/show"] = Types::Function.new(Types::Natural, Types::Text) globalctx["Integer/show"] = BuiltinFunction.new { |arg| arg.to_s } types["Integer/show"] = Types::Function.new(Types::Integer, Types::Text) globalctx["Double/show"] = BuiltinFunction.new { |arg| arg.to_s } types["Double/show"] = Types::Function.new(Types::Double, Types::Text) globalctx["Text/show"] = BuiltinFunction.new { |arg| arg } types["Text/show"] = Types::Function.new(Types::Text, Types::Text) # Casts: natToInt = BuiltinFunction.new { |arg| arg } globalctx["Natural/toInteger"] = natToInt types["Natural/toInteger"] = Types::Function.new(Types::Natural, Types::Integer) natToDou = BuiltinFunction.new { |arg| arg.to_f } globalctx["Natural/toDouble"] = natToDou types["Natural/toDouble"] = Types::Function.new(Types::Natural, Types::Double) intToNat = BuiltinFunction.new { |arg| arg.abs } globalctx["Integer/toNatural"] = intToNat types["Integer/toNatural"] = Types::Function.new(Types::Integer, Types::Natural) intToDou = BuiltinFunction.new { |arg| arg.to_f } globalctx["Integer/toDouble"] = intToDou types["Integer/toDouble"] = Types::Function.new(Types::Integer, Types::Double) douToNat = BuiltinFunction.new { |arg| arg.round.abs } globalctx["Double/toNatural"] = douToNat types["Double/toNatural"] = Types::Function.new(Types::Double, Types::Natural) douToInt = BuiltinFunction.new { |arg| arg.round } globalctx["Double/toInteger"] = douToInt types["Double/toInteger"] = Types::Function.new(Types::Double, Types::Integer) # Lists: globalctx["List"] = BuiltinFunction.new { |a| Types::List.new(a) } types["List"] = make_fn_type([:list_a], Types::Type.new(Types::List.new(Types::Unresolved.new(:list_a)))) list_length_type = make_fn_type([:list_len_a], Types::List.new(Types::Unresolved.new(:list_len_a)), Types::Natural) globalctx["List/length"] = BuiltinFunction.new{ |a| BuiltinFunction.new { |list| list.length } } types["List/length"] = list_length_type list_fold_type = make_fn_type( [:list_fold_a], Types::List.new(Types::Unresolved.new(:list_fold_a)), [:list_fold_b], make_fn_type(:list_fold_a, :list_fold_b, :list_fold_b), :list_fold_b, :list_fold_b) globalctx["List/fold"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| BuiltinFunction.new { |b| BuiltinFunction.new { |f| BuiltinFunction.new { |x| acc = x list.reverse_each { |elm| acc = f.call(elm).call(acc) } acc } } } } } types["List/fold"] = list_fold_type list_head_type = make_fn_type( [:list_head_a], Types::List.new(Types::Unresolved.new(:list_head_a)), Types::Optional.new(Types::Unresolved.new(:list_head_a))) globalctx["List/head"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| list.first } } types["List/head"] = list_head_type list_last_type = make_fn_type( [:list_last_a], Types::List.new(Types::Unresolved.new(:list_last_a)), Types::Optional.new(Types::Unresolved.new(:list_last_a))) globalctx["List/last"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| list.last } } types["List/last"] = list_last_type list_tail_type = make_fn_type( [:list_tail_a], Types::List.new(Types::Unresolved.new(:list_tail_a)), Types::List.new(Types::Unresolved.new(:list_tail_a))) globalctx["List/tail"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| if list.empty? [] else list[1..list.length] end } } types["List/tail"] = list_tail_type types["List/reverse"] = make_fn_type( [:list_reverse_a], Types::List.new(Types::Unresolved.new(:list_reverse_a)), Types::List.new(Types::Unresolved.new(:list_reverse_a))) globalctx["List/reverse"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| list.reverse } } types["List/build"] = make_fn_type( [:list_build_a], make_fn_type( [:list_build_b], make_fn_type(:list_build_a, :list_build_b, :list_build_b), :list_build_b, :list_build_b), Types::List.new(Types::Unresolved.new(:list_build_a))) globalctx["List/build"] = BuiltinFunction.new { |a| BuiltinFunction.new { |f| cons = BuiltinFunction.new { |x| BuiltinFunction.new { |list| [x] + list } } f.call(Types::List.new(a)).call(cons).call([]) } } types["List/indexed"] = make_fn_type( [:list_indexed_a], Types::List.new(Types::Unresolved.new(:list_indexed_a)), Types::List.new(Types::Record.new({ "index" => Types::Natural, "value" => Types::Unresolved.new(:list_indexed_a)}))) globalctx["List/indexed"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| list.map.with_index { |val, idx| { "index" => idx, "value" => val } } } } # Optionals: globalctx["Optional"] = BuiltinFunction.new { |a| Types::Optional.new(a) } types["Optional"] = make_fn_type([:opt_a], Types::Type.new(Types::Optional.new(Types::Unresolved.new(:opt_a)))) optional_fold_type = make_fn_type( [:opt_fold_a], Types::Optional.new(Types::Unresolved.new(:opt_fold_a)), [:opt_fold_b], make_fn_type(:opt_fold_a, :opt_fold_b), :opt_fold_b, :opt_fold_b) globalctx["Optional/fold"] = BuiltinFunction.new { |a| BuiltinFunction.new { |opt| BuiltinFunction.new { |b| BuiltinFunction.new { |f| BuiltinFunction.new { |x| if opt.nil? x else f.call(opt) end } } } } } types["Optional/fold"] = optional_fold_type types["Optional/build"] = make_fn_type( [:opt_build_a], make_fn_type([:opt_build_b], make_fn_type(:opt_build_a, :opt_build_b), :opt_build_b, :opt_build_b), Types::Optional.new(Types::Unresolved.new(:opt_build_a))) globalctx["Optional/build"] = BuiltinFunction.new { |a| BuiltinFunction.new { |f| just = BuiltinFunction.new { |x| x } f.call(Types::Optional.new(a)).call(just).call(nil) } } # Naturals: natural_fold_type = make_fn_type( Types::Natural, [:nat_fold_a], make_fn_type(:nat_fold_a, :nat_fold_a), :nat_fold_a, :nat_fold_a) globalctx["Natural/fold"] = BuiltinFunction.new { |n| BuiltinFunction.new { |a| BuiltinFunction.new { |succ| BuiltinFunction.new { |zero| res = zero n.times { res = succ.call(res) } res } } } } types["Natural/fold"] = natural_fold_type types["Natural/even"] = make_fn_type(Types::Natural, Types::Bool) globalctx["Natural/even"] = BuiltinFunction.new { |n| n % 2 == 0 } types["Natural/odd"] = make_fn_type(Types::Natural, Types::Bool) globalctx["Natural/odd"] = BuiltinFunction.new { |n| n % 2 == 1 } types["Natural/isZero"] = make_fn_type(Types::Natural, Types::Bool) globalctx["Natural/isZero"] = BuiltinFunction.new { |n| n == 0 } globalctx["Natural/build"] = BuiltinFunction.new { |f| zero = 0 succ = BuiltinFunction.new { |n| n + 1 } f.call(Types::Natural).call(succ).call(zero) } types["Natural/build"] = make_fn_type(make_fn_type([:nat_build_a], make_fn_type(:nat_build_a, :nat_build_a), :nat_build_a, :nat_build_a), Types::Natural) end
make_fn_type(*args, rettype)
click to toggle source
Utility function to create dhallish function types: Use [:name] to introduce a new unresolved type and write :name to use it. Look at `fill_context` for examples.
# File lib/stdlib.rb, line 9 def make_fn_type(*args, rettype) if Types::not_a_type?(rettype); rettype = Types::Unresolved.new(rettype) end args.reverse.reduce(rettype) { |rettype, arg| argtype = arg name = nil if arg.is_a? Array name = arg[0] argtype = Types::Type.new(Types::Unresolved.new(name)) end if Types::not_a_type?(argtype); argtype = Types::Unresolved.new(argtype) end Types::Function.new(argtype, rettype, name) } end
mergeRecordTypes(a, b)
click to toggle source
# File lib/types.rb, line 388 def mergeRecordTypes(a, b) assert("records expected") { a.is_a? Types::Record and b.is_a? Types::Record } merged = a.types.clone b.types.each { |key, type| if merged.key? key if type.is_a? Types::Record and merged[key].is_a? Types::Record merged[key] = mergeRecordTypes(merged[key], type) else raise DhallError, "key `#{key}` apeares in left and right side of `//\\\\` with different types" end else merged[key] = type end } Types::Record.new merged end
mergeRecordTypesPrefereRight(a, b)
click to toggle source
# File lib/types.rb, line 426 def mergeRecordTypesPrefereRight(a, b) assert("expecting records for `//`") { a.is_a? Types::Record and b.is_a? Types::Record } mergedTypes = a.types.clone b.types.each { |key, type| mergedTypes[key] = type } Types::Record.new(mergedTypes) end
mergeRecordsPrefereRight(a, b)
click to toggle source
# File lib/types.rb, line 434 def mergeRecordsPrefereRight(a, b) mergedVals = a.clone b.each { |key, val| mergedVals[key] = val } mergedVals end
mergeRecordsRecursively(a, b)
click to toggle source
TODO: .val weg!
# File lib/types.rb, line 409 def mergeRecordsRecursively(a, b) merged = a.clone b.each { |key, val| if merged.key? key if val.is_a? Hash and merged[key].is_a? Hash merged[key] = mergeRecordsRecursively(merged[key], val) else raise DhallError, "key `#{key}` apeares in left and right side of `/\\` (should not happen becouse of static type checks)" end else merged[key] = val end } merged end
to_json(dhallval)
click to toggle source
# File lib/types.rb, line 292 def to_json(dhallval) case dhallval when Integer dhallval.to_s when Float dhallval.to_s when String "\"#{escape_str(dhallval)}\"" when TrueClass "true" when FalseClass "false" when Array "[#{ dhallval.map{ |val| to_json(val) }.join(", ") }]" when Hash "{#{ dhallval.map{ |key, val| "\"#{escape_str(key)}\": #{ to_json(val) }" }.join(", ") }}" when nil "null" else if Types::is_a_type? dhallval "\"#{dhallval.to_s}\"" else "\"<#{escape_str(dhallval.class.to_s)}##{dhallval.hash.abs.to_s(16)}>\"" end end end
Public Instance Methods
create_ctx_from_file(dhallfile, basedir=nil)
click to toggle source
# File lib/dhallish.rb, line 63 def create_ctx_from_file(dhallfile, basedir=nil) if basedir.nil?; basedir = File.dirname(dhallfile) end file = File.open(dhallfile) res = create_ctx(file.read, basedir) file.close res end
Private Instance Methods
create_ctx(dhallcode, basedir=Dir.pwd)
click to toggle source
# File lib/dhallish.rb, line 53 def create_ctx(dhallcode, basedir=Dir.pwd) empty_ctx = empty_context(basedir) ctx, type = evaluate(dhallcode, empty_ctx) if type != Types::Record.new({}) or ctx["<#TYPES#>"].nil? or ctx["<#VALS#>"].nil? raise DhallError, "return type of dhallcode supplied to `create_ctx` did not return a context (but something of type `#{type}`). use `???`" end ctx end
empty_context(basedir=Dir.pwd)
click to toggle source
# File lib/dhallish.rb, line 20 def empty_context(basedir=Dir.pwd) ctx = { "<#TYPES#>" => Context.new, "<#VALS#>" => Context.new } ctx["<#TYPES#>"]["<#DIR#>"] = basedir fill_context(ctx["<#VALS#>"], ctx["<#TYPES#>"]) ctx end
evaluate(dhallcode, ctx=nil, expected_type=nil)
click to toggle source
# File lib/dhallish.rb, line 28 def evaluate(dhallcode, ctx=nil, expected_type=nil) if ctx.nil?; ctx = empty_context() end rawast = @@parser.parse dhallcode if rawast.nil? raise DhallError, "#{@@parser.failure_reason} (line/column: #{@@parser.failure_line}:#{@@parser.failure_column})" end ast = rawast.to_node type = ast.compute_type ctx["<#TYPES#>"] res = ast.evaluate ctx["<#VALS#>"] if !expected_type.nil? if !(type == expected_type) raise DhallError, "expression return type missmatch: expected `#{expected_type}`, got: `#{type}`" else res end else [res, type] end end
fill_context(globalctx, types)
click to toggle source
# File lib/stdlib.rb, line 24 def fill_context(globalctx, types) # Types: globalctx["Natural"] = Types::Natural globalctx["Integer"] = Types::Integer globalctx["Double"] = Types::Double globalctx["Bool"] = Types::Bool globalctx["Text"] = Types::Text globalctx["Type"] = Types::Type.new types["Natural"] = Types::Type.new(Types::Natural) types["Integer"] = Types::Type.new(Types::Integer) types["Double"] = Types::Type.new(Types::Double) types["Bool"] = Types::Type.new(Types::Bool) types["Text"] = Types::Type.new(Types::Text) types["Type"] = Types::Type.new(Types::Type.new) # Shows: globalctx["Natural/show"] = BuiltinFunction.new { |arg| arg.to_s } types["Natural/show"] = Types::Function.new(Types::Natural, Types::Text) globalctx["Integer/show"] = BuiltinFunction.new { |arg| arg.to_s } types["Integer/show"] = Types::Function.new(Types::Integer, Types::Text) globalctx["Double/show"] = BuiltinFunction.new { |arg| arg.to_s } types["Double/show"] = Types::Function.new(Types::Double, Types::Text) globalctx["Text/show"] = BuiltinFunction.new { |arg| arg } types["Text/show"] = Types::Function.new(Types::Text, Types::Text) # Casts: natToInt = BuiltinFunction.new { |arg| arg } globalctx["Natural/toInteger"] = natToInt types["Natural/toInteger"] = Types::Function.new(Types::Natural, Types::Integer) natToDou = BuiltinFunction.new { |arg| arg.to_f } globalctx["Natural/toDouble"] = natToDou types["Natural/toDouble"] = Types::Function.new(Types::Natural, Types::Double) intToNat = BuiltinFunction.new { |arg| arg.abs } globalctx["Integer/toNatural"] = intToNat types["Integer/toNatural"] = Types::Function.new(Types::Integer, Types::Natural) intToDou = BuiltinFunction.new { |arg| arg.to_f } globalctx["Integer/toDouble"] = intToDou types["Integer/toDouble"] = Types::Function.new(Types::Integer, Types::Double) douToNat = BuiltinFunction.new { |arg| arg.round.abs } globalctx["Double/toNatural"] = douToNat types["Double/toNatural"] = Types::Function.new(Types::Double, Types::Natural) douToInt = BuiltinFunction.new { |arg| arg.round } globalctx["Double/toInteger"] = douToInt types["Double/toInteger"] = Types::Function.new(Types::Double, Types::Integer) # Lists: globalctx["List"] = BuiltinFunction.new { |a| Types::List.new(a) } types["List"] = make_fn_type([:list_a], Types::Type.new(Types::List.new(Types::Unresolved.new(:list_a)))) list_length_type = make_fn_type([:list_len_a], Types::List.new(Types::Unresolved.new(:list_len_a)), Types::Natural) globalctx["List/length"] = BuiltinFunction.new{ |a| BuiltinFunction.new { |list| list.length } } types["List/length"] = list_length_type list_fold_type = make_fn_type( [:list_fold_a], Types::List.new(Types::Unresolved.new(:list_fold_a)), [:list_fold_b], make_fn_type(:list_fold_a, :list_fold_b, :list_fold_b), :list_fold_b, :list_fold_b) globalctx["List/fold"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| BuiltinFunction.new { |b| BuiltinFunction.new { |f| BuiltinFunction.new { |x| acc = x list.reverse_each { |elm| acc = f.call(elm).call(acc) } acc } } } } } types["List/fold"] = list_fold_type list_head_type = make_fn_type( [:list_head_a], Types::List.new(Types::Unresolved.new(:list_head_a)), Types::Optional.new(Types::Unresolved.new(:list_head_a))) globalctx["List/head"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| list.first } } types["List/head"] = list_head_type list_last_type = make_fn_type( [:list_last_a], Types::List.new(Types::Unresolved.new(:list_last_a)), Types::Optional.new(Types::Unresolved.new(:list_last_a))) globalctx["List/last"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| list.last } } types["List/last"] = list_last_type list_tail_type = make_fn_type( [:list_tail_a], Types::List.new(Types::Unresolved.new(:list_tail_a)), Types::List.new(Types::Unresolved.new(:list_tail_a))) globalctx["List/tail"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| if list.empty? [] else list[1..list.length] end } } types["List/tail"] = list_tail_type types["List/reverse"] = make_fn_type( [:list_reverse_a], Types::List.new(Types::Unresolved.new(:list_reverse_a)), Types::List.new(Types::Unresolved.new(:list_reverse_a))) globalctx["List/reverse"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| list.reverse } } types["List/build"] = make_fn_type( [:list_build_a], make_fn_type( [:list_build_b], make_fn_type(:list_build_a, :list_build_b, :list_build_b), :list_build_b, :list_build_b), Types::List.new(Types::Unresolved.new(:list_build_a))) globalctx["List/build"] = BuiltinFunction.new { |a| BuiltinFunction.new { |f| cons = BuiltinFunction.new { |x| BuiltinFunction.new { |list| [x] + list } } f.call(Types::List.new(a)).call(cons).call([]) } } types["List/indexed"] = make_fn_type( [:list_indexed_a], Types::List.new(Types::Unresolved.new(:list_indexed_a)), Types::List.new(Types::Record.new({ "index" => Types::Natural, "value" => Types::Unresolved.new(:list_indexed_a)}))) globalctx["List/indexed"] = BuiltinFunction.new { |a| BuiltinFunction.new { |list| list.map.with_index { |val, idx| { "index" => idx, "value" => val } } } } # Optionals: globalctx["Optional"] = BuiltinFunction.new { |a| Types::Optional.new(a) } types["Optional"] = make_fn_type([:opt_a], Types::Type.new(Types::Optional.new(Types::Unresolved.new(:opt_a)))) optional_fold_type = make_fn_type( [:opt_fold_a], Types::Optional.new(Types::Unresolved.new(:opt_fold_a)), [:opt_fold_b], make_fn_type(:opt_fold_a, :opt_fold_b), :opt_fold_b, :opt_fold_b) globalctx["Optional/fold"] = BuiltinFunction.new { |a| BuiltinFunction.new { |opt| BuiltinFunction.new { |b| BuiltinFunction.new { |f| BuiltinFunction.new { |x| if opt.nil? x else f.call(opt) end } } } } } types["Optional/fold"] = optional_fold_type types["Optional/build"] = make_fn_type( [:opt_build_a], make_fn_type([:opt_build_b], make_fn_type(:opt_build_a, :opt_build_b), :opt_build_b, :opt_build_b), Types::Optional.new(Types::Unresolved.new(:opt_build_a))) globalctx["Optional/build"] = BuiltinFunction.new { |a| BuiltinFunction.new { |f| just = BuiltinFunction.new { |x| x } f.call(Types::Optional.new(a)).call(just).call(nil) } } # Naturals: natural_fold_type = make_fn_type( Types::Natural, [:nat_fold_a], make_fn_type(:nat_fold_a, :nat_fold_a), :nat_fold_a, :nat_fold_a) globalctx["Natural/fold"] = BuiltinFunction.new { |n| BuiltinFunction.new { |a| BuiltinFunction.new { |succ| BuiltinFunction.new { |zero| res = zero n.times { res = succ.call(res) } res } } } } types["Natural/fold"] = natural_fold_type types["Natural/even"] = make_fn_type(Types::Natural, Types::Bool) globalctx["Natural/even"] = BuiltinFunction.new { |n| n % 2 == 0 } types["Natural/odd"] = make_fn_type(Types::Natural, Types::Bool) globalctx["Natural/odd"] = BuiltinFunction.new { |n| n % 2 == 1 } types["Natural/isZero"] = make_fn_type(Types::Natural, Types::Bool) globalctx["Natural/isZero"] = BuiltinFunction.new { |n| n == 0 } globalctx["Natural/build"] = BuiltinFunction.new { |f| zero = 0 succ = BuiltinFunction.new { |n| n + 1 } f.call(Types::Natural).call(succ).call(zero) } types["Natural/build"] = make_fn_type(make_fn_type([:nat_build_a], make_fn_type(:nat_build_a, :nat_build_a), :nat_build_a, :nat_build_a), Types::Natural) end
make_fn_type(*args, rettype)
click to toggle source
Utility function to create dhallish function types: Use [:name] to introduce a new unresolved type and write :name to use it. Look at `fill_context` for examples.
# File lib/stdlib.rb, line 9 def make_fn_type(*args, rettype) if Types::not_a_type?(rettype); rettype = Types::Unresolved.new(rettype) end args.reverse.reduce(rettype) { |rettype, arg| argtype = arg name = nil if arg.is_a? Array name = arg[0] argtype = Types::Type.new(Types::Unresolved.new(name)) end if Types::not_a_type?(argtype); argtype = Types::Unresolved.new(argtype) end Types::Function.new(argtype, rettype, name) } end
mergeRecordTypes(a, b)
click to toggle source
# File lib/types.rb, line 388 def mergeRecordTypes(a, b) assert("records expected") { a.is_a? Types::Record and b.is_a? Types::Record } merged = a.types.clone b.types.each { |key, type| if merged.key? key if type.is_a? Types::Record and merged[key].is_a? Types::Record merged[key] = mergeRecordTypes(merged[key], type) else raise DhallError, "key `#{key}` apeares in left and right side of `//\\\\` with different types" end else merged[key] = type end } Types::Record.new merged end
mergeRecordTypesPrefereRight(a, b)
click to toggle source
# File lib/types.rb, line 426 def mergeRecordTypesPrefereRight(a, b) assert("expecting records for `//`") { a.is_a? Types::Record and b.is_a? Types::Record } mergedTypes = a.types.clone b.types.each { |key, type| mergedTypes[key] = type } Types::Record.new(mergedTypes) end
mergeRecordsPrefereRight(a, b)
click to toggle source
# File lib/types.rb, line 434 def mergeRecordsPrefereRight(a, b) mergedVals = a.clone b.each { |key, val| mergedVals[key] = val } mergedVals end
mergeRecordsRecursively(a, b)
click to toggle source
TODO: .val weg!
# File lib/types.rb, line 409 def mergeRecordsRecursively(a, b) merged = a.clone b.each { |key, val| if merged.key? key if val.is_a? Hash and merged[key].is_a? Hash merged[key] = mergeRecordsRecursively(merged[key], val) else raise DhallError, "key `#{key}` apeares in left and right side of `/\\` (should not happen becouse of static type checks)" end else merged[key] = val end } merged end
to_json(dhallval)
click to toggle source
# File lib/types.rb, line 292 def to_json(dhallval) case dhallval when Integer dhallval.to_s when Float dhallval.to_s when String "\"#{escape_str(dhallval)}\"" when TrueClass "true" when FalseClass "false" when Array "[#{ dhallval.map{ |val| to_json(val) }.join(", ") }]" when Hash "{#{ dhallval.map{ |key, val| "\"#{escape_str(key)}\": #{ to_json(val) }" }.join(", ") }}" when nil "null" else if Types::is_a_type? dhallval "\"#{dhallval.to_s}\"" else "\"<#{escape_str(dhallval.class.to_s)}##{dhallval.hash.abs.to_s(16)}>\"" end end end