From 084d1f5c4d91ae14d289c0abe9b5f84268b514b1 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 12 Mar 2019 19:04:59 -0500 Subject: [PATCH] Try on generic visitor --- lib/dhall/ast.rb | 26 ++++---------------------- lib/dhall/normalize.rb | 28 +++++++++++++++++++++++++--- lib/dhall/util.rb | 9 ++++++++- lib/dhall/visitor.rb | 23 +++++++++++++++++++++++ 4 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 lib/dhall/visitor.rb diff --git a/lib/dhall/ast.rb b/lib/dhall/ast.rb index 326f9df..a0c14ab 100644 --- a/lib/dhall/ast.rb +++ b/lib/dhall/ast.rb @@ -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) diff --git a/lib/dhall/normalize.rb b/lib/dhall/normalize.rb index bb811fb..6e9452f 100644 --- a/lib/dhall/normalize.rb +++ b/lib/dhall/normalize.rb @@ -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 diff --git a/lib/dhall/util.rb b/lib/dhall/util.rb index 40a2470..affb3cc 100644 --- a/lib/dhall/util.rb +++ b/lib/dhall/util.rb @@ -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 diff --git a/lib/dhall/visitor.rb b/lib/dhall/visitor.rb new file mode 100644 index 0000000..6688cad --- /dev/null +++ b/lib/dhall/visitor.rb @@ -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 -- 2.34.5