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