l43_peg 0.0.2 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|