l43_peg 0.0.2 → 0.1.1
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 +4 -4
- data/LICENSE +235 -201
- data/README.md +74 -2
- data/lib/l43/match_data_extenstion.rb +6 -0
- data/lib/l43/open_object.rb +38 -0
- data/lib/l43/require_helper.rb +8 -0
- data/lib/l43_peg/cache.rb +9 -0
- data/lib/l43_peg/combinators/many.rb +38 -0
- data/lib/l43_peg/combinators/seq.rb +29 -0
- data/lib/l43_peg/combinators.rb +51 -0
- data/lib/l43_peg/failure.rb +9 -0
- data/lib/l43_peg/helper.rb +13 -0
- data/lib/l43_peg/input.rb +48 -0
- data/lib/l43_peg/mappers.rb +21 -0
- data/lib/l43_peg/parser.rb +19 -0
- data/lib/l43_peg/parsers/char_parser.rb +36 -0
- data/lib/l43_peg/parsers/end_parser.rb +27 -0
- data/lib/l43_peg/parsers/failure_parser.rb +21 -0
- data/lib/l43_peg/parsers/int_parser.rb +26 -0
- data/lib/l43_peg/parsers/rgx_parser.rb +45 -0
- data/lib/l43_peg/parsers/token_parser.rb +32 -0
- data/lib/l43_peg/parsers/tokens_parser.rb +61 -0
- data/lib/l43_peg/parsers/verb_parser.rb +23 -0
- data/lib/l43_peg/parsers.rb +19 -0
- data/lib/l43_peg/success.rb +30 -0
- data/lib/l43_peg/tokens.rb +46 -0
- data/lib/l43_peg.rb +6 -3
- metadata +25 -2
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43
|
4
|
+
module OpenObject
|
5
|
+
def attributes(*atts, **defaults)
|
6
|
+
attr_reader(*atts)
|
7
|
+
attr_reader(*defaults.keys)
|
8
|
+
|
9
|
+
define_method :== do |other|
|
10
|
+
other&.to_h == to_h
|
11
|
+
end
|
12
|
+
|
13
|
+
define_method :initialize do |**kwds|
|
14
|
+
missing = atts - kwds.keys
|
15
|
+
raise ArgumentError, "missing required keyword parameters: #{missing.inspect}" unless missing.empty?
|
16
|
+
spurious = kwds.keys - atts - defaults.keys
|
17
|
+
raise ArgumentError, "spurious keyword parameters: #{spurious.inspect}" unless spurious.empty?
|
18
|
+
|
19
|
+
values = defaults.merge(kwds)
|
20
|
+
values.each do |key, value|
|
21
|
+
instance_variable_set("@#{key}", value)
|
22
|
+
end
|
23
|
+
_init if respond_to?(:_init)
|
24
|
+
end
|
25
|
+
|
26
|
+
define_method :to_h do |*|
|
27
|
+
first = atts.inject Hash.new do |h, attribute|
|
28
|
+
h.update(attribute => send(attribute))
|
29
|
+
end
|
30
|
+
defaults.keys.inject first do |h, attribute|
|
31
|
+
h.update(attribute => send(attribute))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
alias_method :deconstruct_keys, :to_h
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../helper"
|
4
|
+
module L43Peg
|
5
|
+
module Combinators
|
6
|
+
module Many extend self
|
7
|
+
|
8
|
+
include L43Peg::Helper
|
9
|
+
def many(input:, cache:, name:, parser:, min:, max:)
|
10
|
+
curr_input = input
|
11
|
+
curr_cache = cache
|
12
|
+
count = 0
|
13
|
+
ast = []
|
14
|
+
|
15
|
+
loop do
|
16
|
+
if max && count == max
|
17
|
+
return succeed_parser(ast, curr_input, cache: curr_cache)
|
18
|
+
end
|
19
|
+
case parser.(curr_input, cache: curr_cache)
|
20
|
+
in L43Peg::Success => success
|
21
|
+
ast.push(success.ast)
|
22
|
+
curr_input = success.rest
|
23
|
+
curr_cache = success.cache
|
24
|
+
count += 1
|
25
|
+
in L43Peg::Failure
|
26
|
+
if count < min
|
27
|
+
return fail_parser("many #{name} should match at least #{min} times but did only #{count} times")
|
28
|
+
end
|
29
|
+
return succeed_parser(ast, curr_input, cache: curr_cache)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../helper"
|
4
|
+
module L43Peg
|
5
|
+
module Combinators
|
6
|
+
module Seq extend self
|
7
|
+
|
8
|
+
include L43Peg::Helper
|
9
|
+
def seq(input:, cache:, name:, parsers:)
|
10
|
+
curr_input = input
|
11
|
+
curr_cache = cache
|
12
|
+
ast = []
|
13
|
+
parsers.each do |parser|
|
14
|
+
case parser.(curr_input, cache: curr_cache)
|
15
|
+
in L43Peg::Failure => failure
|
16
|
+
return L43Peg::Failure.new(reason: "#{failure.reason} in (#{name})", position: failure.position, input:)
|
17
|
+
in L43Peg::Success => success
|
18
|
+
ast.push(success.ast)
|
19
|
+
curr_input = success.rest
|
20
|
+
curr_cache = success.cache
|
21
|
+
end
|
22
|
+
end
|
23
|
+
succeed_parser(ast, curr_input, cache: curr_cache)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
require_relative 'mappers'
|
5
|
+
require_relative 'parser'
|
6
|
+
require_relative 'parsers'
|
7
|
+
require_subdir('combinators') {}
|
8
|
+
|
9
|
+
module L43Peg
|
10
|
+
module Combinators extend self
|
11
|
+
|
12
|
+
include L43Peg::Helper
|
13
|
+
include L43Peg::Mappers
|
14
|
+
include L43Peg::Parsers
|
15
|
+
|
16
|
+
def args_parser(definitions, name: nil, &block)
|
17
|
+
parser = tokens_parser(definitions, &block)
|
18
|
+
name = name || "args_parser(#{definitions.inspect})"
|
19
|
+
inner = many(parser)
|
20
|
+
map(inner, name:, fn: join_maps)
|
21
|
+
end
|
22
|
+
|
23
|
+
def many(parser, name: nil, min: 0, max: nil)
|
24
|
+
Parser.new(name || "many(#{parser.name})") {|input, cache, name1=nil| Many.many(input:, cache:, name: name1 || name, parser:, min:, max:)}
|
25
|
+
end
|
26
|
+
|
27
|
+
def map(parser, name: nil, fn: nil, &mapper)
|
28
|
+
raise ArgumentError, "must not provide keyword parameyer fn and a block" if fn && mapper
|
29
|
+
mapper = fn || mapper
|
30
|
+
raise ArgumentError, "must provide keyword parameyer fn or a block" unless mapper
|
31
|
+
Parser.new(name || "map(#{parser.name})") {|input, cache, name=nil| _map(input:, cache:, name:, parser:, mapper:)}
|
32
|
+
end
|
33
|
+
|
34
|
+
def seq(*parsers, name: nil)
|
35
|
+
name ||= "seq(#{parsers.map(&:name).join(", ")})"
|
36
|
+
Parser.new(name) {|input, cache, _name=nil| Seq.seq(input:, cache:, name:, parsers:)}
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def _map(input:, cache:, name:, parser:, mapper:)
|
42
|
+
case parser.(input, cache:)
|
43
|
+
in L43Peg::Failure => failure
|
44
|
+
failure
|
45
|
+
in L43Peg::Success => success
|
46
|
+
success.map(&mapper)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
module Helper
|
5
|
+
def fail_parser(reason)
|
6
|
+
L43Peg::Failure.new(reason:)
|
7
|
+
end
|
8
|
+
def succeed_parser(ast, input, cache: nil)
|
9
|
+
L43Peg::Success.new(ast:, rest: input, cache: cache || input.cache)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
class Input
|
5
|
+
extend L43::OpenObject
|
6
|
+
|
7
|
+
attributes col: 1, input: "", lnb: 1, context: {}
|
8
|
+
|
9
|
+
def drop(by=nil)
|
10
|
+
case by
|
11
|
+
when nil
|
12
|
+
_drop_by_n(1)
|
13
|
+
when String
|
14
|
+
_drop_by_n(by.length)
|
15
|
+
else
|
16
|
+
_drop_by_n(by)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def empty? = input.empty?
|
21
|
+
|
22
|
+
def position = [@col, @lnb]
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def _drop_by_n(n)
|
27
|
+
return self if input.empty?
|
28
|
+
_split(n) => col, lnb, head, tail
|
29
|
+
self.class.new(input: tail, context:, col:, lnb:)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Very inefficent but sufficent for my use cases so far
|
33
|
+
# and convenient for regex parsers
|
34
|
+
def _split(n)
|
35
|
+
head = input.slice(0...n)
|
36
|
+
lines = head.count("\n")
|
37
|
+
tail = input.slice(n..-1) || ''
|
38
|
+
new_col =
|
39
|
+
if lines.zero?
|
40
|
+
col + n
|
41
|
+
else
|
42
|
+
1 + head.sub(%r{\A.*\n}m, "").length
|
43
|
+
end
|
44
|
+
[new_col, lnb + lines, head, tail]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
module Mappers
|
5
|
+
|
6
|
+
def join_and_to_i
|
7
|
+
-> list do
|
8
|
+
list.join.to_i
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def join_maps
|
13
|
+
-> maps do
|
14
|
+
maps.reduce Hash.new do |map, entry|
|
15
|
+
map.merge(entry) { |*args| args.drop(1).flatten }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
class Parser
|
5
|
+
|
6
|
+
attr_reader :fn, :name
|
7
|
+
|
8
|
+
def call(input, cache: L43Peg::Cache.new) = fn.(input, cache, name)
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def initialize(name, &fn)
|
13
|
+
@name = name
|
14
|
+
@fn = fn
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
module Parsers
|
5
|
+
class CharParser < L43Peg::Parser
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def initialize(charset=nil)
|
10
|
+
charset = _mk_set(charset)
|
11
|
+
super("char_parser(#{charset})") do |input, cache, name|
|
12
|
+
if input.input.empty?
|
13
|
+
L43Peg::Failure.new(cache:, input:, parsed_by: self, reason: "cannot parse at end of input #{name}")
|
14
|
+
elsif charset.nil? || charset.member?(input.input[0])
|
15
|
+
L43Peg::Success.new(ast: input.input[0], cache:, rest: input.drop, position: input.position)
|
16
|
+
else
|
17
|
+
L43Peg::Failure.new(cache:, input:, parsed_by: self, reason: "char #{input.input[0].inspect}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def _mk_set(charset)
|
23
|
+
return unless charset
|
24
|
+
case charset
|
25
|
+
when String
|
26
|
+
Set.new(charset.split(""))
|
27
|
+
when Set
|
28
|
+
charset
|
29
|
+
else
|
30
|
+
Set.new(charset)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../parsers'
|
4
|
+
|
5
|
+
module L43Peg
|
6
|
+
module Parsers
|
7
|
+
class EndParser < L43Peg::Parser
|
8
|
+
|
9
|
+
def self.instance
|
10
|
+
@__instance__ ||= new
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super('end_parser') do |input, cache, _name=nil|
|
17
|
+
if input.input.empty?
|
18
|
+
L43Peg::Success.new(cache:, rest: input, position: input.position)
|
19
|
+
else
|
20
|
+
L43Peg::Failure.new(cache:, input:, parsed_by: self, reason: "not at end of input")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
module Parsers
|
5
|
+
class FailureParser < L43Peg::Parser
|
6
|
+
|
7
|
+
def self.instance
|
8
|
+
@__instance__ ||= new
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
super('failure_parser') do |input, cache, _name=nil|
|
15
|
+
L43Peg::Failure.new(cache:, input:, parsed_by: self, reason: "this parser always fails")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../parsers'
|
4
|
+
|
5
|
+
module L43Peg
|
6
|
+
module Parsers
|
7
|
+
class IntParser < L43Peg::Parser
|
8
|
+
extend L43Peg::Combinators
|
9
|
+
extend L43Peg::Mappers
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def instance
|
13
|
+
@__instance__ ||= _mk_int_parser
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def _mk_int_parser
|
19
|
+
map(seq(many(Parsers.char_parser("+-"), max: 1), many(Parsers.char_parser("0".."9"), min: 1), name: "int_parser"), &join_and_to_i)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
module Parsers
|
5
|
+
class RgxParser < L43Peg::Parser
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def initialize(rgx, name: nil, **options)
|
10
|
+
name = name || "rgx_parser(#{rgx.inspect})"
|
11
|
+
rgx = _mk_rgx(rgx)
|
12
|
+
super(name) do |input, cache, _name|
|
13
|
+
case rgx.match(input.input)
|
14
|
+
in MatchData => md
|
15
|
+
ast = _from_match(md, options)
|
16
|
+
L43Peg::Success.new(ast:, cache:, rest: input.drop(md[0]), position: input.position)
|
17
|
+
else
|
18
|
+
L43Peg::Failure.new(cache:, input:, parsed_by: self, reason: "input does not match #{rgx.inspect} (in #{name})")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def _from_match(md, options)
|
24
|
+
case options[:capture]
|
25
|
+
in NilClass
|
26
|
+
md[1] || md[0]
|
27
|
+
in Integer => n
|
28
|
+
md[n]
|
29
|
+
in :all
|
30
|
+
md.to_a
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def _mk_rgx(rgx)
|
35
|
+
case rgx
|
36
|
+
when String
|
37
|
+
Regexp.compile("\\A#{rgx}")
|
38
|
+
else
|
39
|
+
rgx
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
module Parsers
|
5
|
+
class TokenParser < L43Peg::Parser
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def initialize(token_spec, name: nil, **options)
|
10
|
+
_check_arg!(token_spec)
|
11
|
+
name = name || "token_parser(#{token_spec.inspect})"
|
12
|
+
super(name) do |tokens, cache, _name|
|
13
|
+
if result = tokens.match(token_spec, options[:capture])
|
14
|
+
L43Peg::Success.new(ast: result, cache:, rest: tokens.drop(1), position: tokens.position)
|
15
|
+
else
|
16
|
+
reason = "token #{tokens.head.inspect} does not match #{token_spec.inspect} (in #{name})"
|
17
|
+
L43Peg::Failure.new(cache:, input: tokens, parsed_by: self, reason:)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def _check_arg!(token_spec)
|
23
|
+
case token_spec
|
24
|
+
when Regexp, String
|
25
|
+
else
|
26
|
+
raise ArgumentError, "#{token_spec.inspect} must be a regular expression or a string"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
module Parsers
|
5
|
+
class TokensParser < L43Peg::Parser
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def initialize(map, name: nil, &blk)
|
10
|
+
map = _check_arg!(map)
|
11
|
+
name = name || "tokens_parser(#{map.inspect})"
|
12
|
+
super(name) do |tokens, cache, _name|
|
13
|
+
case _find_matching(map, tokens)
|
14
|
+
in [token, success]
|
15
|
+
_succeed(tokens:, token:, success:, &blk)
|
16
|
+
else
|
17
|
+
reason = "no token matches (in #{name})"
|
18
|
+
L43Peg::Failure.new(cache:, input: tokens, parsed_by: self, reason:)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def _check_arg!(map)
|
25
|
+
case map
|
26
|
+
when Hash
|
27
|
+
_mk_tokens(map)
|
28
|
+
else
|
29
|
+
raise ArgumentError, "#{map.inspect} must be a regular expression or a string"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def _find_matching(map, tokens)
|
34
|
+
map.each do |token, token_parser|
|
35
|
+
case token_parser.(tokens)
|
36
|
+
in L43Peg::Success => success
|
37
|
+
return [token, success]
|
38
|
+
else
|
39
|
+
end
|
40
|
+
end
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def _mk_tokens(map)
|
45
|
+
map.map do |token, spec|
|
46
|
+
[token, TokenParser.new(Regexp.compile(spec), capture: 1)]
|
47
|
+
end.to_h
|
48
|
+
end
|
49
|
+
|
50
|
+
def _succeed(success:, token:, tokens:, &blk)
|
51
|
+
result = if blk
|
52
|
+
blk.(success.ast)
|
53
|
+
else
|
54
|
+
success.ast
|
55
|
+
end
|
56
|
+
L43Peg::Success.new(ast: {token => result}, cache: success.cache, rest: success.rest, position: tokens.position)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
module Parsers
|
5
|
+
class VerbParser < L43Peg::Parser
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def initialize(verb, name: nil)
|
10
|
+
name = name || "verb_parser(#{verb.inspect})"
|
11
|
+
super(name) do |input, cache, _name|
|
12
|
+
if input.input.start_with?(verb)
|
13
|
+
L43Peg::Success.new(ast: verb, cache:, rest: input.drop(verb), position: input.position)
|
14
|
+
else
|
15
|
+
L43Peg::Failure.new(cache:, input:, parsed_by: self, reason: "input does not start with #{verb.inspect} (in #{name})")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'combinators'
|
4
|
+
require_subdir {}
|
5
|
+
|
6
|
+
module L43Peg
|
7
|
+
module Parsers extend self
|
8
|
+
def args_parser(args, name: nil) = L43Peg::Parsers::ArgsParser.new(args, name:)
|
9
|
+
def char_parser(charset = nil) = L43Peg::Parsers::CharParser.new(charset)
|
10
|
+
def end_parser = L43Peg::Parsers::EndParser.instance
|
11
|
+
def failure_parser = L43Peg::Parsers::FailureParser.instance
|
12
|
+
def int_parser = L43Peg::Parsers::IntParser.instance
|
13
|
+
def rgx_parser(rgx, name: nil, **o) = L43Peg::Parsers::RgxParser.new(rgx, name:, **o)
|
14
|
+
def token_parser(spc, name: nil, **o) = L43Peg::Parsers::TokenParser.new(spc, name:, **o)
|
15
|
+
def tokens_parser(map, name: nil, &b) = L43Peg::Parsers::TokensParser.new(map, name:, &b)
|
16
|
+
def verb_parser(verb, name: nil) = L43Peg::Parsers::VerbParser.new(verb, name:)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
class Success
|
5
|
+
def _init
|
6
|
+
return if @position
|
7
|
+
@position = _position
|
8
|
+
end
|
9
|
+
extend L43::OpenObject
|
10
|
+
|
11
|
+
attributes ast: nil, cache: nil, position: nil, rest: nil
|
12
|
+
|
13
|
+
def map(&mapper)
|
14
|
+
self.class.new(ast: mapper.(ast), cache:, position:, rest:)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
|
20
|
+
def _position
|
21
|
+
case @rest
|
22
|
+
when Tokens
|
23
|
+
1
|
24
|
+
else
|
25
|
+
[1, 1]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module L43Peg
|
4
|
+
class Tokens
|
5
|
+
extend L43::OpenObject
|
6
|
+
|
7
|
+
attributes tnb: 1, tokens: [], context: {}
|
8
|
+
|
9
|
+
def drop(by=nil)
|
10
|
+
by = by || 1
|
11
|
+
return self if empty?
|
12
|
+
self.class.new(tokens: input.drop(by), context:, tnb: tnb + by)
|
13
|
+
end
|
14
|
+
|
15
|
+
def empty? = tokens.empty?
|
16
|
+
def head = tokens.first
|
17
|
+
def input = tokens
|
18
|
+
|
19
|
+
def match(str_or_rgx, option)
|
20
|
+
return if empty?
|
21
|
+
|
22
|
+
case str_or_rgx
|
23
|
+
when String
|
24
|
+
head == str_or_rgx && head
|
25
|
+
when Regexp
|
26
|
+
_match_rgx(str_or_rgx, option || 0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def position = tnb
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def _match_rgx(rgx, option)
|
35
|
+
md = rgx.match(head)
|
36
|
+
return unless md
|
37
|
+
|
38
|
+
if option == :all
|
39
|
+
md.to_a
|
40
|
+
else
|
41
|
+
md[option]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
# SPDX-License-Identifier: Apache-2.0
|
data/lib/l43_peg.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'l43/require_helper'
|
4
|
+
require_relative 'l43/open_object'
|
5
|
+
require_subdir {}
|
6
|
+
|
3
7
|
module L43Peg
|
4
|
-
VERSION = "0.
|
5
|
-
|
8
|
+
VERSION = "0.1.1"
|
6
9
|
end
|
7
|
-
# SPDX-License-Identifier:
|
10
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|