~singpolyma/dhall-ruby

084d1f5c4d91ae14d289c0abe9b5f84268b514b1 — Stephen Paul Weber 3 years ago 3b08439
Try on generic visitor
4 files changed, 60 insertions(+), 26 deletions(-)

M lib/dhall/ast.rb
M lib/dhall/normalize.rb
M lib/dhall/util.rb
A lib/dhall/visitor.rb
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