~singpolyma/dhall-ruby

d58516b09fcc8540593c723f9c99339216940966 — Stephen Paul Weber 5 years ago 3f26cd0
Record projection by expression / type
5 files changed, 62 insertions(+), 1 deletions(-)

M lib/dhall/ast.rb
M lib/dhall/binary.rb
M lib/dhall/normalize.rb
M lib/dhall/parser.rb
M lib/dhall/typecheck.rb
M lib/dhall/ast.rb => lib/dhall/ast.rb +11 -0
@@ 810,6 810,17 @@ module Dhall
		end
	end

	class RecordProjectionByExpression < Expression
		include(ValueSemantics.for_attributes do
			record Expression
			selector Expression
		end)

		def as_json
			[10, record.as_json, [selector.as_json]]
		end
	end

	class EmptyRecordProjection < Expression
		include(ValueSemantics.for_attributes do
			record Expression

M lib/dhall/binary.rb => lib/dhall/binary.rb +9 -1
@@ 144,7 144,15 @@ module Dhall

	class RecordProjection
		def self.decode(record, *selectors)
			self.for(Dhall.decode(record), selectors)
			record = Dhall.decode(record)
			if selectors.length == 1 && selectors[0].is_a?(Array)
				RecordProjectionByExpression.new(
					record:   record,
					selector: Dhall.decode(selectors[0][0])
				)
			else
				self.for(record, selectors)
			end
		end
	end


M lib/dhall/normalize.rb => lib/dhall/normalize.rb +12 -0
@@ 320,6 320,18 @@ module Dhall
		end
	end

	class RecordProjectionByExpression
		def normalize
			sel = selector.normalize

			if sel.is_a?(RecordType)
				RecordProjection.for(record, sel.keys).normalize
			else
				with(record: record.normalize, selector: sel)
			end
		end
	end

	class EmptyRecordProjection
		def normalize
			EmptyRecord.new

M lib/dhall/parser.rb => lib/dhall/parser.rb +2 -0
@@ 146,6 146,8 @@ module Dhall
				selectors.reduce(record) do |rec, sels|
					if sels.is_a?(Array)
						RecordProjection.for(rec, sels)
					elsif sels.is_a?(Dhall::Expression)
						RecordProjectionByExpression.new(record: rec, selector: sels)
					else
						RecordSelection.new(record: rec, selector: sels)
					end

M lib/dhall/typecheck.rb => lib/dhall/typecheck.rb +28 -0
@@ 604,6 604,34 @@ module Dhall
			end
		end

		class RecordProjectionByExpression
			TypeChecker.register self, Dhall::RecordProjectionByExpression

			def initialize(projection)
				@selector = projection.selector.normalize
				@projection = projection
			end

			def annotate(context)
				TypeChecker.assert @selector, Dhall::RecordType,
				                   "RecordProjectionByExpression on #{@selector.class}"

				projection = Dhall::RecordProjection.for(
					@projection.record,
					@selector.keys
				)

				TypeChecker.assert_type projection, @selector.normalize,
				                        "Type doesn't match #{@selector}",
				                        context: context

				Dhall::TypeAnnotation.new(
					value: @projection,
					type:  @selector
				)
			end
		end

		class Enum
			TypeChecker.register self, Dhall::Enum