M lib/dhall/ast.rb => lib/dhall/ast.rb +4 -22
@@ 4,13 4,10 @@ require "uri"
require "value_semantics"
require "dhall/util"
+require "dhall/visitor"
module Dhall
class Expression
- def map_subexpressions(&block)
- with(subexpression_map(&block))
- end
-
def call(*args)
args.reduce(self) { |f, arg|
Application.new(function: f, arguments: [arg])
@@ 106,21 103,6 @@ module Dhall
Operator::RecursiveRecordTypeMerge.new(lhs: self, rhs: other)
end
end
-
- protected
-
- def subexpression_map(&block)
- to_h.each_with_object({}) do |(attr, value), h|
- case value
- when Expression
- h[attr] = block[value]
- when Util::ArrayOf.new(Expression)
- h[attr] = value.map(&block)
- when Util::HashOf.new(Expression)
- h[attr] = Hash[value.map { |k, v| [k, block[v]] }]
- end
- end
- end
end
class Application < Expression
@@ 323,7 305,7 @@ module Dhall
class RecordType < Expression
include(ValueSemantics.for_attributes do
- record Util::HashOf.new(Expression, min: 1)
+ record Util::HashOf.new(::String, Expression, min: 1)
end)
def deep_merge_type(other)
@@ 353,7 335,7 @@ module Dhall
class Record < Expression
include(ValueSemantics.for_attributes do
- record Util::HashOf.new(Expression, min: 1)
+ record Util::HashOf.new(::String, Expression, min: 1)
end)
def fetch(k, default=nil, &block)
@@ 433,7 415,7 @@ module Dhall
class UnionType < Expression
include(ValueSemantics.for_attributes do
- alternatives Util::HashOf.new(Expression)
+ alternatives Util::HashOf.new(::String, Expression)
end)
def ==(other)
M lib/dhall/normalize.rb => lib/dhall/normalize.rb +25 -3
@@ 1,19 1,39 @@
# frozen_string_literal: true
require "dhall/builtins"
+require "dhall/visitor"
+require "dhall/util"
module Dhall
+ module ExpressionVisitor
+ def self.new(&block)
+ Visitor.new(
+ Expression => block,
+ Util::ArrayOf.new(Expression) => lambda do |x|
+ x.map(&block)
+ end,
+ Util::HashOf.new(ValueSemantics::Anything, Expression) => lambda do |x|
+ Hash[x.map { |k, v| [k, block[v]] }]
+ end
+ )
+ end
+ end
+
class Expression
def normalize
- map_subexpressions(&:normalize)
+ with(ExpressionVisitor.new(&:normalize).visit(self))
end
def shift(amount, name, min_index)
- map_subexpressions { |expr| expr.shift(amount, name, min_index) }
+ with(ExpressionVisitor.new { |expr|
+ expr.shift(amount, name, min_index)
+ }.visit(self))
end
def substitute(var, with_expr)
- map_subexpressions { |expr| expr.substitute(var, with_expr) }
+ with(ExpressionVisitor.new { |expr|
+ expr.substitute(var, with_expr)
+ }.visit(self))
end
def fusion(*); end
@@ 45,6 65,8 @@ module Dhall
end
class Function
+ @@alpha_normalization = true
+
def self.disable_alpha_normalization!
@@alpha_normalization = false
end
M lib/dhall/util.rb => lib/dhall/util.rb +8 -1
@@ 15,14 15,21 @@ module Dhall
end
class HashOf
- def initialize(element_validator, min: 0, max: Float::INFINITY)
+ def initialize(
+ key_validator,
+ element_validator,
+ min: 0,
+ max: Float::INFINITY
+ )
@min = min
@max = max
+ @key_validator = key_validator
@element_validator = element_validator
end
def ===(other)
Hash === other &&
+ other.keys.all? { |x| @key_validator === x } &&
other.values.all? { |x| @element_validator === x } &&
other.size >= @min && other.size <= @max
end
A lib/dhall/visitor.rb => lib/dhall/visitor.rb +23 -0
@@ 0,0 1,23 @@
+# frozen_string_literal: true
+
+module Dhall
+ class Visitor
+ def initialize(callbacks)
+ @callbacks = callbacks
+ end
+
+ def visit(expr)
+ expr.to_h.each_with_object({}) do |(attr, value), h|
+ if (callback = callback_for(value))
+ h[attr] = callback.call(value)
+ end
+ end
+ end
+
+ protected
+
+ def callback_for(x)
+ @callbacks.find { |k, _| k === x }&.last
+ end
+ end
+end