diff --git a/bin/dhallish b/bin/dhallish index 9fda29ea8ef7c4b189e866d770efdbf33133e57e..8f0fc718653ffca4f92c638f318aa0fd0d92d5ec 100755 --- a/bin/dhallish +++ b/bin/dhallish @@ -1,6 +1,7 @@ #!/usr/bin/env ruby -require File.expand_path("../lib/dhallish.rb", File.dirname(__FILE__)) +this_file = File.readlink(__FILE__) +require File.expand_path("../lib/dhallish.rb", File.dirname(this_file)) require 'json' pretty_json = false diff --git a/lib/DhallishGrammar.treetop b/lib/DhallishGrammar.treetop index 703588a01b816e47ff7a511122fc222d2252a243..760adfaa59c26896c33016d460d613bb5447b91e 100644 --- a/lib/DhallishGrammar.treetop +++ b/lib/DhallishGrammar.treetop @@ -338,13 +338,13 @@ grammar DhallishGrammar end rule record_merge_expression - exp:application_expression tail:(space? op:("//\\\\" / "/\\" / "//") space? exp:application_expression)* + exp:application_expression tail:(space? op:("//\\\\" / "⩓" / "/\\" / "∧" / "//" / "⫽") space? exp:application_expression)* { def to_node(ctx) tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - if node.op.text_value == "//\\\\" + if node.op.text_value == "//\\\\" or node.op.text_value == "⩓" Dhallish::Ast::RecordTypeRecursiveMergeNode.new tree, node.exp.to_node(ctx) - elsif node.op.text_value == "/\\" + elsif node.op.text_value == "/\\" or node.op.text_value == "∧" Dhallish::Ast::RecordRecursiveMergeNode.new tree, node.exp.to_node(ctx) else Dhallish::Ast::RecordNonRecursiveMergeNode.new tree, node.exp.to_node(ctx) diff --git a/lib/ast.rb b/lib/ast.rb index 1e1a59ba4b919f691c86407be96a1c4d861511be..39817011a9e12568504b68fce7ce2cf41623fbfe 100644 --- a/lib/ast.rb +++ b/lib/ast.rb @@ -169,7 +169,8 @@ module Dhallish type_type = annot_type_expr.compute_type(new_ctx) assert ("not a type after type annotation") { type_type.is_a? Types::Type } annot_type = type_type.metadata - assert ("Actual type of #{name}'s value (#{act_type}) doesn't match annotated type (#{annot_type})") { annot_type == act_type } + unification = Types::unification(annot_type, act_type) + assert ("Actual type of #{name}'s value (#{act_type}) doesn't match annotated type (#{annot_type})") { !unification.nil? } end new_ctx[name] = act_type diff --git a/lib/stdlib.rb b/lib/stdlib.rb index b15335dcc69dbbfae1b090951dbd9d62e0d03847..351c6b4faac851d0fb3069798c09fd366ddbaebf 100644 --- a/lib/stdlib.rb +++ b/lib/stdlib.rb @@ -142,6 +142,43 @@ module Dhallish } types["List/tail"] = list_tail_type + types["List/reverse"] = make_fn_type( + [Types::Type.new(Types::Unresolved.new(:a)), :a], + Types::List.new(Types::Unresolved.new(:a)), + Types::List.new(Types::Unresolved.new(:a))) + globalctx["List/reverse"] = BuiltinFunction.new { |a| + BuiltinFunction.new { |list| list.reverse } + } + + types["List/build"] = make_fn_type( + [Types::Type.new(Types::Unresolved.new(:a)), :a], + make_fn_type( + [Types::Type.new(Types::Unresolved.new(:b)), :b], + make_fn_type(:a, :b, :b), :b, :b), + Types::List.new(Types::Unresolved.new(: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( + [Types::Type.new(Types::Unresolved.new(:a)), :a], + Types::List.new(Types::Unresolved.new(:a)), + Types::List.new(Types::Record.new({ + "index" => Types::Natural, + "value" => Types::Unresolved.new(: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) @@ -171,6 +208,19 @@ module Dhallish } types["Optional/fold"] = optional_fold_type + types["Optional/build"] = make_fn_type( + [Types::Type.new(Types::Unresolved.new(:a)), :a], + make_fn_type([Types::Type.new(Types::Unresolved.new(:b)), :b], + make_fn_type(:a, :b), :b, :b), + Types::Optional.new(Types::Unresolved.new(: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,