~singpolyma/dhall-ruby

1026a6408714727835e512e7cf12d2ec882ddd9e — Stephen Paul Weber 4 years ago c979c0c
Fix rubocop except for parser metrics
M lib/dhall/ast.rb => lib/dhall/ast.rb +19 -9
@@ 660,11 660,8 @@ module Dhall

		def fetch(k, default=nil)
			if (type = alternatives.fetch(k))
				Function.new(
					var:  k,
					type: type,
					body: Union.from(self, k, Variable[k])
				).normalize
				body = Union.from(self, k, Variable[k])
				Function.new(var: k, type: type, body: body).normalize
			else
				Union.from(self, k, nil)
			end


@@ 856,14 853,13 @@ module Dhall

		def self.for(*chunks)
			fixed =
				chunks
				([""] + chunks)
				.flat_map { |c| ["", c, ""] }
				.map { |c| c.is_a?(Expression) ? c : Text.new(value: c.to_s) }
				.chunk { |x| x.is_a?(Text) }.flat_map do |(is_text, group)|
					is_text ? group.reduce(&:<<) : group
				end

			return Text.new(value: "") if fixed.empty?
			fixed.length == 1 ? fixed.first : new(chunks: fixed)
		end



@@ 884,7 880,7 @@ module Dhall
			def initialize(protocol=:nocheck, data=nil)
				super(
					protocol: protocol,
					data: data
					data:     data
				)
			end



@@ 934,7 930,7 @@ module Dhall
					hash.fetch(:headers),
					authority,
					*path,
					query,
					query
				)
			end



@@ 1055,6 1051,12 @@ module Dhall
				"v"  => "\v"
			}.freeze

			def self.decode(var)
				var.gsub(/\\[\"\\abfnrtv]/) do |escape|
					ESCAPES.fetch(escape[1])
				end
			end

			def initialize(var)
				@var = var
			end


@@ 1184,6 1186,14 @@ module Dhall
			body Expression
		end)

		def self.for(lets:, body:)
			if lets.length == 1
				LetIn.new(let: lets.first, body: body)
			else
				new(lets: lets, body: body)
			end
		end

		def unflatten
			lets.reverse.reduce(body) do |inside, let|
				letin = LetIn.new(let: let, body: inside)

M lib/dhall/binary.rb => lib/dhall/binary.rb +4 -14
@@ 145,9 145,9 @@ module Dhall

	class UnionType
		def self.decode(record)
			new(alternatives: Hash[record.map { |k, v|
			new(alternatives: Hash[record.map do |k, v|
				[k, v.nil? ? v : Dhall.decode(v)]
			}])
			end])
		end
	end



@@ 187,13 187,7 @@ module Dhall
	class Import
		def self.decode(integrity_check, import_type, path_type, *parts)
			parts[0] = Dhall.decode(parts[0]) if path_type < 2 && !parts[0].nil?
			if PATH_TYPES[path_type] == EnvironmentVariable
				parts = parts.map do |part|
					part.gsub(/\\[\"\\abfnrtv]/) do |escape|
						EnvironmentVariable::ESCAPES.fetch(escape[1])
					end
				end
			end
			parts[0] = EnvironmentVariable.decode(parts[0]) if path_type == 5

			new(
				IntegrityCheck.new(*integrity_check),


@@ 214,11 208,7 @@ module Dhall
				)
			end

			if lets.length == 1
				LetIn.new(let: lets.first, body: body)
			else
				new(lets: lets, body: body)
			end
			self.for(lets: lets, body: body)
		end
	end


M lib/dhall/normalize.rb => lib/dhall/normalize.rb +11 -13
@@ 6,16 6,18 @@ require "dhall/util"

module Dhall
	module ExpressionVisitor
		ExpressionHash = Util::HashOf.new(
			ValueSemantics::Anything,
			ValueSemantics::Either.new([Expression, nil])
		)

		def self.new(&block)
			Visitor.new(
				Expression                                             => block,
				Util::ArrayOf.new(Expression)                          => lambda do |x|
				Expression                    => block,
				Util::ArrayOf.new(Expression) => lambda do |x|
					x.map(&block)
				end,
				Util::HashOf.new(
					ValueSemantics::Anything,
					ValueSemantics::Either.new([Expression, nil])
				) => lambda do |x|
				ExpressionHash                => lambda do |x|
					Hash[x.map { |k, v| [k, v.nil? ? v : block[v]] }]
				end
			)


@@ 266,13 268,9 @@ module Dhall
		def normalize
			normalized = super
			if normalized.record.is_a?(Record) && normalized.input.is_a?(Union)
				if normalized.input.value.nil?
					normalized.record.fetch(normalized.input.tag)
				else
					normalized.record.fetch(normalized.input.tag).call(
						normalized.input.value
					)
				end
				fetched = normalized.record.fetch(normalized.input.tag)
				value = normalized.input.value
				value.nil? ? fetched : fetched.call(value)
			else
				normalized
			end

M lib/dhall/parser.rb => lib/dhall/parser.rb +15 -21
@@ 113,12 113,9 @@ module Dhall
						Float::NAN
					else
						float = string.to_f
						if float.nan? || float.infinite?
							raise Citrus::ParseError, input
						end
						raise Citrus::ParseError, input if float.nan? || float.infinite?
						float
					end
				)
					end)
			end
		end



@@ 128,9 125,9 @@ module Dhall
					*captures(:double_quote_chunk)
					.map(&:value)
					.chunk { |s| s.is_a?(String) }
					.flat_map { |(is_string, group)|
					.flat_map do |(is_string, group)|
						is_string ? group.join : group
					}
					end
				)
			end
		end


@@ 152,9 149,9 @@ module Dhall
				if first&.string == "\\" && matches[1].string =~ /\Au\h+\Z/i
					[matches[1].string[1..-1]].pack("H*").force_encoding("UTF-16BE")
				elsif first&.string == "\\"
					ESCAPES.fetch(matches[1].string) do
					ESCAPES.fetch(matches[1].string) {
						raise "Invalid escape: #{string}"
					end.encode("UTF-16BE")
					}.encode("UTF-16BE")
				elsif first&.string == "${"
					matches[1].value
				else


@@ 187,7 184,7 @@ module Dhall
			def value
				if matches.length == 2
					[ESCAPES.fetch(first.string, first.string), matches[1].value]
				elsif matches.length == 0
				elsif matches.empty?
					[]
				else
					[


@@ 359,14 356,14 @@ module Dhall
				if keys.length == 1
					capture(keys.first).value
				elsif captures.key?(:let)
					lets = first.matches.map { |let_match|
					lets = first.matches.map do |let_match|
						exprs = let_match.captures(:expression)
						Let.new(
							var:    let_match.capture(:nonreserved_label).value,
							assign: exprs.last.value,
							type:   exprs.length > 1 ? exprs.first.value : nil,
							type:   exprs.length > 1 ? exprs.first.value : nil
						)
					}
					end

					if lets.length == 1
						LetIn.new(let: lets.first, body: matches.last.value)


@@ 394,7 391,7 @@ module Dhall
					If.new(
						predicate: captures(:expression)[0].value,
						then:      captures(:expression)[1].value,
						else:      captures(:expression)[2].value,
						else:      captures(:expression)[2].value
					)
				elsif captures.key?(:merge)
					Merge.new(


@@ 438,7 435,7 @@ module Dhall
		module Http
			SCHEME = {
				"http"  => Dhall::Import::Http,
				"https" => Dhall::Import::Https,
				"https" => Dhall::Import::Https
			}.freeze

			def self.escape(s)


@@ 452,10 449,7 @@ module Dhall
						capture(:import_hashed).value(Dhall::Import::Expression)
					end,
					http.capture(:authority).value,
					*http.capture(:path).captures(:path_component).map { |c|
						# https://github.com/dhall-lang/dhall-lang/issues/456
						c.value # (Http.method(:escape))
					},
					*http.capture(:path).captures(:path_component).map(&:value),
					http.capture(:query)&.value
				)
			end


@@ 484,9 478,9 @@ module Dhall

			def value
				if first&.string == "\\"
					ESCAPES.fetch(matches[1].string) do
					ESCAPES.fetch(matches[1].string) {
						raise "Invalid escape: #{string}"
					end.encode("UTF-16BE")
					}.encode("UTF-16BE")
				else
					string
				end

M scripts/generate_citrus_parser.rb => scripts/generate_citrus_parser.rb +45 -26
@@ 1,22 1,33 @@
# frozen_string_literal: true

require "abnf"

require "dhall/parser"
require "dhall/util"

class RegexpTree::CharClass
	def encode_elt(e)
		case e
		when 0x09; '\t'
		when 0x0a; '\n'
		when 0x0d; '\r'
		when 0x0c; '\f'
		when 0x0b; '\v'
		when 0x07; '\a'
		when 0x1b; '\e'
		when 0x21, 0x22, 0x25, 0x26, 0x27, 0x2c, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x2f, 0x30..0x39, 0x40, 0x41..0x5a, 0x5f, 0x60, 0x61..0x7a, 0x7e
			sprintf("%c", e)
		else
			sprintf("\\u{%02x}", e)
class RegexpTree
	class CharClass
		MAP = {
			0x09 => '\t',
			0x0a => '\n',
			0x0d => '\r',
			0x0c => '\f',
			0x0b => '\v',
			0x07 => '\a',
			0x1b => '\e'
		}.freeze

		def encode_elt(e)
			MAP.fetch(e) do
				case e
				when 0x21, 0x22, 0x25, 0x26, 0x27, 0x2c, 0x3a, 0x3b, 0x3c,
					  0x3d, 0x3e, 0x2f, 0x30..0x39, 0x40, 0x41..0x5a, 0x5f,
					  0x60, 0x61..0x7a, 0x7e
					"%c" % e
				else
					"\\u{%02x}" % e
				end
			end
		end
	end
end


@@ 37,7 48,7 @@ class Sequence
	end

	def to_s
		@seq.join(' ')
		@seq.join(" ")
	end
end



@@ 98,37 109,44 @@ class RuleFormatter
		formatted.is_a?(Terminal) ? formatted : "(#{formatted})"
	end

	# rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
	# rubocop:disable Metrics/MethodLength,Metrics/PerceivedComplexity
	def format_rule(name, rule)
		if name == :"simple-label"
			return "keyword simple_label_next_char+ | !keyword (simple_label_first_char simple_label_next_char*)"
			return "keyword simple_label_next_char+ | " \
			       "!keyword (simple_label_first_char simple_label_next_char*)"
		end

		if name == :"nonreserved-label"
			return "reserved_identifier simple_label_next_char+ | !reserved_identifier label"
			return "reserved_identifier simple_label_next_char+ | " \
			       "!reserved_identifier label"
		end

		case rule
		when ABNF::Term
			Terminal.new(@abnf.regexp(name))
		when ABNF::Var
			rule.name.to_s.gsub(/-/, '_')
			rule.name.to_s.tr("-", "_")
		when ABNF::Seq
			if rule.elts.empty?
				'""'
			else
				rule.elts.map(&method(:format_anon_rule)).chunk { |x| x.is_a?(Terminal) }.flat_map { |(terminal, chunk)|
					terminal ? chunk.reduce(:+) : Sequence.new(chunk)
				}.join(' ')
				rule
					.elts.map(&method(:format_anon_rule))
					.chunk { |x| x.is_a?(Terminal) }
					.flat_map { |(terminal, chunk)|
						terminal ? chunk.reduce(:+) : Sequence.new(chunk)
					}.join(" ")
			end
		when ABNF::Alt
			rule.elts.map(&method(:format_anon_rule)).join(' | ')
			rule.elts.map(&method(:format_anon_rule)).join(" | ")
		when ABNF::Rep
			base = format_anon_rule(rule.elt)
			if rule.min == 0 && rule.max.nil?
			if rule.min.zero? && rule.max.nil?
				"#{base}*"
			elsif rule.min == 1 && rule.max.nil?
				"#{base}+"
			elsif rule.min == 0 && rule.max == 1
			elsif rule.min.zero? && rule.max == 1
				"#{base}?"
			else
				"#{base} #{rule.min}*#{rule.max}"


@@ 136,8 154,9 @@ class RuleFormatter
		else
			raise "Unknown rule type: #{rule.inspect}"
		end

	end
	# rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity
	# rubocop:enable Metrics/MethodLength,Metrics/PerceivedComplexity
end

puts "grammar Dhall::Parser::CitrusParser"


@@ 147,7 166,7 @@ abnf = ABNF.parse(STDIN.read)
formatter = RuleFormatter.new(abnf)
abnf.each do |name, rule|
	next if name.to_s.start_with?("____")
	puts "rule #{name.to_s.gsub(/-/, '_')}"
	puts "rule #{name.to_s.tr("-", "_")}"
	print "\t(#{formatter.format_rule(name, rule)})"
	extension = name.to_s.split(/-/).map(&:capitalize).join
	if Dhall::Parser.const_defined?(extension)