l43_simple_peg 0.1.0.pre.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/peg/class_methods.rb +69 -0
- data/lib/peg/combinators/choice.rb +26 -0
- data/lib/peg/combinators/list.rb +57 -0
- data/lib/peg/combinators/many.rb +33 -0
- data/lib/peg/combinators/seq.rb +29 -0
- data/lib/peg/combinators.rb +12 -0
- data/lib/peg/helpers.rb +19 -0
- data/lib/peg/parsers/time_parser/time_helper.rb +96 -0
- data/lib/peg/parsers/time_parser.rb +100 -0
- data/lib/peg/result.rb +32 -0
- data/lib/peg/set.rb +8 -0
- data/lib/peg/version.rb +7 -0
- data/lib/peg.rb +94 -0
- metadata +67 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 23eaccca5eeb68df26e134c6f18f27b1d5507a629bc710c1a1a21ba22e2958ab
|
|
4
|
+
data.tar.gz: 0f3c03a9c45fbd0eb55df8fd8448106cb5ce26a215b8031352fdb7d069e21629
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0ce27fab43a70fea75c7e257418e600690f182a0e903104beeb35397097b1c2d633059b2548608bf7d23acf0d11211c666d20142e6a044df38f89a46ae195b49
|
|
7
|
+
data.tar.gz: 9dc045b2b19bfc1265e6576554c5d44574405d9666a39729f5d8da1374f732a2b4e0a8d0d1ecf72ed3062094d739db9cf3a4ebfae08f5204a5a0ec077764af92
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'combinators'
|
|
4
|
+
class Peg
|
|
5
|
+
module ClassMethods
|
|
6
|
+
|
|
7
|
+
PredefinedSymbols = {
|
|
8
|
+
dot: "\\.",
|
|
9
|
+
ws: ["\\s", :ignore],
|
|
10
|
+
wss: ["\\s*", :ignore],
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
def choice(*pegs, name: nil, &blk) = Combinators::Choice.new(*pegs, name:, &blk)
|
|
14
|
+
|
|
15
|
+
def ignore(peg, name: nil)
|
|
16
|
+
parser = Peg(peg)
|
|
17
|
+
name ||= "ignored(#{parser.name})"
|
|
18
|
+
parser.ignore
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def list(ele_peg, sep_peg, min: 1, name: nil, &blk) = Combinators::List.new(ele_peg, sep_peg, min:, name:, &blk)
|
|
22
|
+
|
|
23
|
+
def from_sym(sym, name: nil, &blk)
|
|
24
|
+
regex = PredefinedSymbols.fetch(sym) do
|
|
25
|
+
return posix(sym, name:, &blk)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
predefined_name = name || "predefined(#{sym})"
|
|
29
|
+
case regex
|
|
30
|
+
in rgx, :ignore
|
|
31
|
+
rgx(rgx, name: predefined_name, &blk).ignore
|
|
32
|
+
else
|
|
33
|
+
rgx(regex, name: predefined_name, &blk)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def posix(desc, name: nil, &blk)
|
|
38
|
+
name ||= "posix(#{desc.inspect})"
|
|
39
|
+
peg = if desc.to_s.end_with?("s")
|
|
40
|
+
rgx("[[:#{desc.to_s[0...-1]}:]]+", name:)
|
|
41
|
+
else
|
|
42
|
+
rgx("[[:#{desc.to_s}:]]", name:)
|
|
43
|
+
end
|
|
44
|
+
return peg unless blk
|
|
45
|
+
peg.map(&blk)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def rgx(source, name: nil)
|
|
49
|
+
name ||= "rgx(#{source.inspect})"
|
|
50
|
+
regexp = Regexp.compile("\\A#{source}")
|
|
51
|
+
new(name:) do |input|
|
|
52
|
+
if regexp.match(input) in MatchData => md
|
|
53
|
+
[md.match(0), input[md.match_length(0)..]]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def seq(*parsers, name: nil) = Combinators::Seq.new(*parsers, name:)
|
|
59
|
+
|
|
60
|
+
def set(chars, name: nil)
|
|
61
|
+
name ||= "Set(#{chars})"
|
|
62
|
+
rgx("[#{chars}]", name:)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
extend ClassMethods
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
69
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Peg
|
|
4
|
+
module Combinators
|
|
5
|
+
class Choice < Peg
|
|
6
|
+
attr_reader :name, :fn, :pegs
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
def initialize(*pegs, name: nil)
|
|
10
|
+
@pegs = pegs.map { Peg(it) }
|
|
11
|
+
@name = name || pegs.map(&:name).join(" & ")
|
|
12
|
+
@fn = ->(input) { _parse(input) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def _parse(input)
|
|
16
|
+
pegs.each do |peg|
|
|
17
|
+
if peg.(input) in [_, _] => result
|
|
18
|
+
return result
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Peg
|
|
4
|
+
module Combinators
|
|
5
|
+
class List < Peg
|
|
6
|
+
attr_reader :ele_peg, :fn, :min, :name, :sep_peg
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
def initialize(ele_peg, sep_peg, name: nil, min: 1, &blk)
|
|
10
|
+
@ele_peg = Peg(ele_peg, &blk)
|
|
11
|
+
@sep_peg = Peg(sep_peg)
|
|
12
|
+
@min = min
|
|
13
|
+
|
|
14
|
+
@name = name || "list(#{@ele_peg.name}, #{@sep_peg.name})"
|
|
15
|
+
@fn = ->(input) { _parse(input) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def _parse(input)
|
|
19
|
+
ast = []
|
|
20
|
+
count = min
|
|
21
|
+
|
|
22
|
+
if ele_peg.(input) in ele, input
|
|
23
|
+
ast << ele
|
|
24
|
+
count -= 1
|
|
25
|
+
else
|
|
26
|
+
return nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
_parse_tail(ast, count: min - 1, input:)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def _parse_tail(ast, count:, input:)
|
|
33
|
+
loop do
|
|
34
|
+
if sep_peg.(input) in _, rest
|
|
35
|
+
if ele_peg.(rest) in ele, input
|
|
36
|
+
count -= 1
|
|
37
|
+
ast << ele
|
|
38
|
+
else
|
|
39
|
+
if count.positive?
|
|
40
|
+
return nil
|
|
41
|
+
else
|
|
42
|
+
return [ast, input]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
if count.positive?
|
|
47
|
+
return nil
|
|
48
|
+
else
|
|
49
|
+
return [ast, input]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Peg
|
|
4
|
+
module Combinators
|
|
5
|
+
class Many < Peg
|
|
6
|
+
attr_reader :fn, :min, :name, :peg
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
def initialize(peg, name: nil, min: 1)
|
|
10
|
+
@peg = peg
|
|
11
|
+
@min = min
|
|
12
|
+
@name = name || "many(#{peg.name}, min: #{min})"
|
|
13
|
+
@fn = ->(input) { _parse(input) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def _parse(input)
|
|
17
|
+
count = min
|
|
18
|
+
ast = []
|
|
19
|
+
loop do
|
|
20
|
+
case peg.(input)
|
|
21
|
+
in partial_ast, input
|
|
22
|
+
count -= 1
|
|
23
|
+
ast << partial_ast
|
|
24
|
+
else
|
|
25
|
+
return if count.positive?
|
|
26
|
+
return [ast, input]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Peg
|
|
4
|
+
module Combinators
|
|
5
|
+
class Seq < Peg
|
|
6
|
+
attr_reader :name, :fn, :pegs
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
def initialize(*pegs, name: nil)
|
|
10
|
+
@pegs = pegs.map { Peg(it) }
|
|
11
|
+
@name = name || @pegs.map(&:name).join(" & ")
|
|
12
|
+
@fn = ->(input) { _parse(input) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def _parse(input)
|
|
16
|
+
pegs.inject([[], input]) do |(ast, inp), peg|
|
|
17
|
+
# p(inp:, peg: peg.name, ast:)
|
|
18
|
+
if peg.(inp) in [partial, inp]
|
|
19
|
+
# p(partial:, inp:)
|
|
20
|
+
peg.ignore? ? [ast, inp] : [[*ast, partial], inp]
|
|
21
|
+
else
|
|
22
|
+
return nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'combinators/choice'
|
|
4
|
+
require_relative 'combinators/list'
|
|
5
|
+
require_relative 'combinators/many'
|
|
6
|
+
require_relative 'combinators/seq'
|
|
7
|
+
class Peg
|
|
8
|
+
module Combinators
|
|
9
|
+
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/peg/helpers.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'class_methods'
|
|
4
|
+
class Peg
|
|
5
|
+
module Helpers extend self
|
|
6
|
+
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def Peg(peg, name: nil)
|
|
11
|
+
name ||= "Peg(#{peg.inspect})"
|
|
12
|
+
case peg
|
|
13
|
+
when String
|
|
14
|
+
Peg.rgx(peg, name:)
|
|
15
|
+
when Symbol
|
|
16
|
+
Peg::Helpers.from_symbol
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Time
|
|
4
|
+
def deconstruct(*)
|
|
5
|
+
[year, month, day, hour, min, seconds]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def deconstruct_keys(*)
|
|
9
|
+
{
|
|
10
|
+
year:,
|
|
11
|
+
month:,
|
|
12
|
+
day:,
|
|
13
|
+
hour:,
|
|
14
|
+
min:,
|
|
15
|
+
seconds:,
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def seconds
|
|
20
|
+
s = to_f
|
|
21
|
+
s = sec + (s - s.floor)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Peg
|
|
26
|
+
module Parsers
|
|
27
|
+
module TimeParser
|
|
28
|
+
module TimeHelper extend self
|
|
29
|
+
Units = {
|
|
30
|
+
"s" => 1,
|
|
31
|
+
"m" => 60,
|
|
32
|
+
"h" => 3600,
|
|
33
|
+
"d" => 86400,
|
|
34
|
+
"w" => 604800,
|
|
35
|
+
}
|
|
36
|
+
def add_units(units)
|
|
37
|
+
units => sign, [*pairs]
|
|
38
|
+
sign = sign == "-" ? -1 : 1
|
|
39
|
+
sign * _add_pairs(pairs)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def complete_datetime(parts)
|
|
43
|
+
Time.now => {**} => now
|
|
44
|
+
case parts
|
|
45
|
+
in :date, date
|
|
46
|
+
_complete_date(date, now)
|
|
47
|
+
in :time, time
|
|
48
|
+
_complete_time(time, now)
|
|
49
|
+
in [:date, date], [[:time, time]]
|
|
50
|
+
_complete_datetime(date, time, now)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
def _add_pairs(pairs)
|
|
56
|
+
pairs.inject(0) do |result, (amount, unit)|
|
|
57
|
+
result + amount.to_i * Units.fetch(unit)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def _complete_date(date, now)
|
|
62
|
+
case date
|
|
63
|
+
in 0, d
|
|
64
|
+
[now.year, now.month, d, now.hour, now.min, now.seconds]
|
|
65
|
+
in m, d
|
|
66
|
+
[now.year, m, d, now.hour, now.min, now.seconds]
|
|
67
|
+
in y, m, d
|
|
68
|
+
[now.year/100 * 100 + y, m, d, now.hour, now.min, now.seconds]
|
|
69
|
+
else
|
|
70
|
+
raise ArgumentError, "need a pair or triplet, got: #{date.inspect}"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def _complete_datetime(date, time, now)
|
|
75
|
+
date_triplet = _complete_date(date, now)[0..2]
|
|
76
|
+
time_triplet = _complete_time(time, now)[3..]
|
|
77
|
+
date_triplet + time_triplet
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def _complete_time(time, now)
|
|
81
|
+
case time
|
|
82
|
+
in 0, s
|
|
83
|
+
[now.year, now.month, now.day, now.hour, now.min, s]
|
|
84
|
+
in m, s
|
|
85
|
+
[now.year, now.month, now.day, now.hour, m, s]
|
|
86
|
+
in h, m, s
|
|
87
|
+
[now.year, now.month, now.day, h, m, s]
|
|
88
|
+
else
|
|
89
|
+
raise ArgumentError, "need a pair or triplet, got: #{time.inspect}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'peg'
|
|
4
|
+
require_relative 'time_parser/time_helper'
|
|
5
|
+
class Peg
|
|
6
|
+
module Parsers
|
|
7
|
+
module TimeParser extend self
|
|
8
|
+
|
|
9
|
+
def datetime_parser = @__datetime_parser__ ||= _datetime_parser
|
|
10
|
+
|
|
11
|
+
def time_parser = @__time_parser__ ||= _time_parser
|
|
12
|
+
|
|
13
|
+
def timestamp_parser = @__timestamp_parser__ ||= _timestamp_parser
|
|
14
|
+
def timestamp_float_parser = @__timestamp_float_parser__ ||= _timestamp_float_parser
|
|
15
|
+
def timestamp_int_parser = @__timestamp_int_parser__ ||= _timestamp_int_parser
|
|
16
|
+
|
|
17
|
+
def offset_parser = @__offset_parser__ ||= _offset_parser
|
|
18
|
+
def offset_in_seconds_parser = @__offset_in_seconds_parser__ ||= _offset_in_seconds_parser
|
|
19
|
+
def offset_in_float_seconds_parser = @__offset_in_float_seconds_parser__ ||= _offset_in_float_seconds_parser
|
|
20
|
+
def offset_in_int_seconds_parser = @__offset_in_int_seconds_parser__ ||= _offset_in_int_seconds_parser
|
|
21
|
+
def offset_with_units_parser = @__offset_with_units_parser__ ||= _offset_with_units_parser
|
|
22
|
+
|
|
23
|
+
def only_date_parser = @__only_date_parser__ ||= _only_date_parser
|
|
24
|
+
def only_time_parser = @__only_time_parser__ ||= _only_time_parser
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def _datetime_parser
|
|
29
|
+
Peg.choice(
|
|
30
|
+
Peg.seq(only_date_parser, Peg.seq(Peg.ignore("T"), only_time_parser)),
|
|
31
|
+
only_date_parser,
|
|
32
|
+
only_time_parser,
|
|
33
|
+
).map{ [:datetime, TimeHelper.complete_datetime(it)] }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def _offset_in_float_seconds_parser
|
|
37
|
+
Peg.seq(Peg.set("+-"), :digits, "\\.", :digits, name: "offset in float seconds parser")
|
|
38
|
+
.joined.map(&:to_f)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def _offset_in_int_seconds_parser
|
|
42
|
+
Peg.seq(Peg.set("+-"), :digits, name: "offset in int seconds parser")
|
|
43
|
+
.joined.map(&:to_i)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def _offset_in_seconds_parser
|
|
47
|
+
offset_in_float_seconds_parser.or(offset_in_int_seconds_parser)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def _offset_parser
|
|
51
|
+
Peg.choice(
|
|
52
|
+
offset_with_units_parser,
|
|
53
|
+
offset_in_seconds_parser,
|
|
54
|
+
name: "offset parser"
|
|
55
|
+
).map { [:offset, it] }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def _offset_with_units_parser
|
|
59
|
+
Peg.seq(Peg.set("-+").optional, _time_unit_parser).map { TimeHelper.add_units(it) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def _only_date_parser
|
|
63
|
+
Peg.list(:digits, "-", min: 2, &:to_i).map { [:date, it] }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def _only_time_parser
|
|
67
|
+
Peg.list(:digits, ":", min: 2, &:to_i).map { [:time, it] }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def _time_parser
|
|
71
|
+
Peg.choice(
|
|
72
|
+
offset_parser,
|
|
73
|
+
datetime_parser,
|
|
74
|
+
timestamp_parser
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def _time_unit_parser
|
|
79
|
+
unit_parser = Peg.seq(:digits, Peg.set(TimeHelper::Units.keys.join))
|
|
80
|
+
unit_parser.many
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def _timestamp_parser
|
|
84
|
+
Peg.choice(
|
|
85
|
+
timestamp_float_parser,
|
|
86
|
+
timestamp_int_parser
|
|
87
|
+
).map { [:timestamp, it] }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def _timestamp_float_parser
|
|
91
|
+
Peg.seq(:digits, :dot, :digits).joined.map(&:to_f)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def _timestamp_int_parser
|
|
95
|
+
Peg.seq(:digits).joined.map(&:to_i)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/peg/result.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Peg
|
|
4
|
+
class Result
|
|
5
|
+
attr_reader :ast, :name, :rest
|
|
6
|
+
|
|
7
|
+
def deconstruct(*) = [ast, rest]
|
|
8
|
+
|
|
9
|
+
def deconstruct_keys(*) = {
|
|
10
|
+
ast:,
|
|
11
|
+
name:,
|
|
12
|
+
rest:,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def ==(other)
|
|
16
|
+
self.class === other && ast == other.ast && rest == other.rest
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def len = match.length
|
|
20
|
+
|
|
21
|
+
def ignore? = @ignore
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
def initialize(ast, rest, name: nil)
|
|
25
|
+
@ast = ast
|
|
26
|
+
@rest = rest
|
|
27
|
+
@name = name
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/peg/set.rb
ADDED
data/lib/peg/version.rb
ADDED
data/lib/peg.rb
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'peg/class_methods'
|
|
4
|
+
require_relative 'peg/result'
|
|
5
|
+
class Peg
|
|
6
|
+
attr_reader :fn, :name
|
|
7
|
+
|
|
8
|
+
def call(input)
|
|
9
|
+
fn.(input).tap do |result|
|
|
10
|
+
# $stderr.puts(input) if $debug # :nocov:
|
|
11
|
+
# $stderr.puts({name:, result:}.inspect) if $debug # :nocov:
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ignore
|
|
16
|
+
@ignore = true
|
|
17
|
+
self
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def ignore? = @ignore
|
|
21
|
+
|
|
22
|
+
def joined(joiner: "", name: nil)
|
|
23
|
+
name ||= "joined(#{self.name})"
|
|
24
|
+
Peg.new(name:) do |input|
|
|
25
|
+
case fn.(input)
|
|
26
|
+
in ast, rest
|
|
27
|
+
[ast.join(joiner), rest]
|
|
28
|
+
else
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def many(name: nil, min: 1)
|
|
35
|
+
name ||= "many(#{self.name}, min: #{min})"
|
|
36
|
+
Combinators::Many.new(self, name:, min:)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def map(name: nil, &mapper)
|
|
40
|
+
name ||= "map(#{self.name})"
|
|
41
|
+
Peg.new(name:) do |input|
|
|
42
|
+
case fn.(input)
|
|
43
|
+
in ast, rest
|
|
44
|
+
[mapper.(ast), rest]
|
|
45
|
+
else
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def or(peg, name: nil, &blk) = Combinators::Choice.new(self, peg, name:, &blk)
|
|
52
|
+
|
|
53
|
+
def parse(input)
|
|
54
|
+
case self.(input)
|
|
55
|
+
in ast, rest
|
|
56
|
+
Result.new(ast, rest, name:)
|
|
57
|
+
else
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def optional(name: nil)
|
|
63
|
+
name ||= "optional(#{self.name})"
|
|
64
|
+
self.class.new(name:) do |input|
|
|
65
|
+
if fn.(input) in [_, _] => result
|
|
66
|
+
result
|
|
67
|
+
else
|
|
68
|
+
[nil, input]
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
def initialize(name: nil, &fn)
|
|
75
|
+
@name = name
|
|
76
|
+
@fn = fn
|
|
77
|
+
@ignore = false
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def Peg(peg, name: nil, &blk)
|
|
82
|
+
name ||= "Peg(#{peg.inspect})"
|
|
83
|
+
case peg
|
|
84
|
+
when String
|
|
85
|
+
Peg.rgx(peg, name:, &blk)
|
|
86
|
+
when Symbol
|
|
87
|
+
Peg.from_sym(peg, name:, &blk)
|
|
88
|
+
when Peg
|
|
89
|
+
peg
|
|
90
|
+
else
|
|
91
|
+
raise ArgumentError, "unexpected arg: #{peg.inspect}, need a String, Symbol or Peg instance"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
metadata
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: l43_simple_peg
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0.pre.pre
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Robert Dober
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-09-28 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ostruct
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.6.3
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.6.3
|
|
26
|
+
description: 'peg
|
|
27
|
+
|
|
28
|
+
'
|
|
29
|
+
email: robert.dober@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- lib/peg.rb
|
|
35
|
+
- lib/peg/class_methods.rb
|
|
36
|
+
- lib/peg/combinators.rb
|
|
37
|
+
- lib/peg/combinators/choice.rb
|
|
38
|
+
- lib/peg/combinators/list.rb
|
|
39
|
+
- lib/peg/combinators/many.rb
|
|
40
|
+
- lib/peg/combinators/seq.rb
|
|
41
|
+
- lib/peg/helpers.rb
|
|
42
|
+
- lib/peg/parsers/time_parser.rb
|
|
43
|
+
- lib/peg/parsers/time_parser/time_helper.rb
|
|
44
|
+
- lib/peg/result.rb
|
|
45
|
+
- lib/peg/set.rb
|
|
46
|
+
- lib/peg/version.rb
|
|
47
|
+
licenses:
|
|
48
|
+
- AGPL-3.0-or-later
|
|
49
|
+
metadata: {}
|
|
50
|
+
rdoc_options: []
|
|
51
|
+
require_paths:
|
|
52
|
+
- lib
|
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: 4.0.2
|
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '0'
|
|
63
|
+
requirements: []
|
|
64
|
+
rubygems_version: 4.0.19
|
|
65
|
+
specification_version: 4
|
|
66
|
+
summary: peg
|
|
67
|
+
test_files: []
|