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)