l43_rmap 0.1.1 → 0.1.2
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/lib/l43_rmap/cli/color.rb +2 -0
- data/lib/l43_rmap/cli/help.rb +1 -0
- data/lib/l43_rmap/cli.rb +2 -1
- data/lib/l43_rmap/functions/predefined/str.rb +70 -0
- data/lib/l43_rmap/functions/predefined.rb +7 -8
- data/lib/l43_rmap/functions.rb +22 -4
- data/lib/l43_rmap/parsing/rgx_parsers.rb +1 -1
- data/lib/l43_rmap/predefined_patterns.rb +1 -0
- data/lib/l43_rmap/runtime.rb +28 -6
- data/lib/l43_rmap/version.rb +1 -1
- metadata +3 -13
- data/lib/peg.backup/all.rb +0 -12
- data/lib/peg.backup/combinators/implementation.rb +0 -144
- data/lib/peg.backup/combinators.rb +0 -82
- data/lib/peg.backup/parser/input.rb +0 -36
- data/lib/peg.backup/parser.rb +0 -46
- data/lib/peg.backup/parsers/advanced_parsers.rb +0 -26
- data/lib/peg.backup/parsers/base_parsers.rb +0 -124
- data/lib/peg.backup/parsers/common_parsers.rb +0 -60
- data/lib/peg.backup/parsers/true_set.rb +0 -10
- data/lib/peg.backup/parsers.rb +0 -14
- data/lib/peg.backup/result.rb +0 -78
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b95afae624f3dd5ce13c2761678d547694c5a9e11a80ea7ca23fb8cf94604b53
|
|
4
|
+
data.tar.gz: d813c9e6dc4186232cdacf3412d14c869cc40ec055a9f240e9a0774bed781fd8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7d2d9ac1512236a1a3d8f393284392e43bebaf58423842d61cff0f9ccc5b32b59457531d4791c6af26f0868abf02669e590812300f632c99be028852eb8cb73
|
|
7
|
+
data.tar.gz: 03d07b9bf563eb0ddb6a4cf2545cc66aba27a0d478745761756190d15f338275f62ac3b1533429092e2b8461855b6627a107525dcd89077857d727d5889d2627
|
data/lib/l43_rmap/cli/color.rb
CHANGED
|
@@ -4,10 +4,12 @@ module L43Rmap
|
|
|
4
4
|
class Cli
|
|
5
5
|
module Color
|
|
6
6
|
def arg(name) = [:bold, :blue, "<#{name}>", :reset]
|
|
7
|
+
def arg1(name) = [:bold, :blue, name, :reset]
|
|
7
8
|
|
|
8
9
|
def kwd(name) = [" kwd ", :bold, :cyan, name, ":", :reset]
|
|
9
10
|
|
|
10
11
|
def named(field) = [2, :bold, :blue, "%", field, :reset]
|
|
12
|
+
|
|
11
13
|
def puterr(*chunks)
|
|
12
14
|
putcol(:red, :bold, "ERROR: ", :white, *chunks)
|
|
13
15
|
false
|
data/lib/l43_rmap/cli/help.rb
CHANGED
|
@@ -65,6 +65,7 @@ module L43Rmap
|
|
|
65
65
|
putcol
|
|
66
66
|
putcol(:bold, :blue, "predefined patterns", :white, " are the following:")
|
|
67
67
|
putcol
|
|
68
|
+
putcol(4, :bold, :magenta, "ignore_ws", :white, " same as ", arg1("(unless (m '\\A\\s*\\z') %)"))
|
|
68
69
|
putcol(4, :bold, :magenta, "mv_to_ms", :white, " same as ", :bold, :blue, "mv % %m-(lpad %n 0 4).(ext)")
|
|
69
70
|
putcol(4, :bold, :magenta, "mv_to_mse", :white, " same as ", :bold, :blue, "mv (se) %m-(lpad %n 0 4).(ext)")
|
|
70
71
|
:helped
|
data/lib/l43_rmap/cli.rb
CHANGED
|
@@ -50,6 +50,7 @@ module L43Rmap
|
|
|
50
50
|
.flag(:help_pattern, desc: ["Describe ", :bold, :blue, "pattern"], stop: true)
|
|
51
51
|
.flag(:help_predefined, desc: ["Describe ", :bold, :blue, "predefined patterns"], stop: true)
|
|
52
52
|
.flag(:help_sexp, desc: ["Describe ", :bold, :blue, "s-expressions"], stop: true)
|
|
53
|
+
.flag(:randomize, :r, desc: ["Does not write to the ", arg1("output stream"), " immideately but into a buffer, the buffer is then randomized before being printed to ", arg1("output stream")])
|
|
53
54
|
.section("Options")
|
|
54
55
|
.keyword(:input, :i, desc: ["file to read from, defaults to ", :bold, :cyan, '$stdin'], default: $stdin)
|
|
55
56
|
.keyword(:output, :o, desc: ["file to write to, defaults to ", :bold, :cyan, '$stdout'], default: $stdout)
|
|
@@ -62,7 +63,7 @@ module L43Rmap
|
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def _run
|
|
65
|
-
runtime.run(kwds.input, kwds.output)
|
|
66
|
+
runtime.run(kwds.input, kwds.output, randomize: kwds.randomize)
|
|
66
67
|
:ok
|
|
67
68
|
end
|
|
68
69
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module L43Rmap
|
|
4
|
+
module Functions
|
|
5
|
+
module Predefined
|
|
6
|
+
module Str extend self
|
|
7
|
+
|
|
8
|
+
def gsub(rt, subject, pattern, replacement=nil)
|
|
9
|
+
return _gsub(subject, pattern, replacement) if replacement
|
|
10
|
+
|
|
11
|
+
_gsub(rt.line, subject, pattern)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def lpad(_rt, subject, filler, length)
|
|
15
|
+
subject.to_s.rjust(length.to_i, filler.to_s)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def match(rt, rgx, subject=nil)
|
|
19
|
+
subject ||= rt.line
|
|
20
|
+
r = Regexp.compile(rgx)
|
|
21
|
+
r.match(subject)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def sub(rt, subject, pattern, replacement=nil)
|
|
25
|
+
return _sub(subject, pattern, replacement) if replacement
|
|
26
|
+
|
|
27
|
+
_sub(rt.line, subject, pattern)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def _gsub(subject, pattern, replacement)
|
|
33
|
+
rgx = _mk_rgx(pattern)
|
|
34
|
+
subject&.gsub(rgx, replacement)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def _mk_posix(pattern)
|
|
38
|
+
case pattern
|
|
39
|
+
in *klass, "*"
|
|
40
|
+
Regexp.compile("[[:#{klass.join}:]]*")
|
|
41
|
+
in *klass, "+"
|
|
42
|
+
Regexp.compile("[[:#{klass.join}:]]+")
|
|
43
|
+
in *klass, "?"
|
|
44
|
+
Regexp.compile("[[:#{klass.join}:]]?")
|
|
45
|
+
else
|
|
46
|
+
Regexp.compile("[[:#{pattern.join}:]]")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def _mk_rgx(pattern)
|
|
51
|
+
case pattern
|
|
52
|
+
when Symbol
|
|
53
|
+
_mk_posix(pattern.to_s.grapheme_clusters)
|
|
54
|
+
when String
|
|
55
|
+
Regexp.compile(pattern)
|
|
56
|
+
else
|
|
57
|
+
raise ArgumentError, "pattern must be a String or Symbol, but was #{pattern.inspect}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def _sub(subject, pattern, replacement)
|
|
62
|
+
rgx = _mk_rgx(pattern)
|
|
63
|
+
subject&.sub(rgx, replacement)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../evaluator/evaluations'
|
|
4
4
|
require_relative 'predefined/shell'
|
|
5
|
+
require_relative 'predefined/str'
|
|
5
6
|
|
|
6
7
|
module L43Rmap
|
|
7
8
|
module Functions
|
|
@@ -38,14 +39,12 @@ module L43Rmap
|
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
r = Regexp.compile(rgx)
|
|
48
|
-
r.match(subject)
|
|
42
|
+
def unless_fn(_rt, cond, false_branch, true_branch=nil)
|
|
43
|
+
if cond
|
|
44
|
+
true_branch
|
|
45
|
+
else
|
|
46
|
+
false_branch
|
|
47
|
+
end
|
|
49
48
|
end
|
|
50
49
|
end
|
|
51
50
|
|
data/lib/l43_rmap/functions.rb
CHANGED
|
@@ -35,11 +35,23 @@ module L43Rmap
|
|
|
35
35
|
|
|
36
36
|
# Names only available inside of S-Expressions
|
|
37
37
|
DefinedFunctions = {
|
|
38
|
+
# Logic
|
|
39
|
+
"if" => Function.new("if") { |*args| Predefined.if_fn(*args) },
|
|
40
|
+
"unless" => Function.new("unless") { |*args| Predefined.unless_fn(*args) },
|
|
41
|
+
|
|
42
|
+
# File
|
|
38
43
|
"ext" => Function.new("ext") { |*args| Predefined.file_extension(*args) },
|
|
44
|
+
|
|
45
|
+
# Int
|
|
39
46
|
"inc" => Function.new("inc") { |*args| Predefined.inc(*args) },
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
47
|
+
|
|
48
|
+
# Str
|
|
49
|
+
"lpad" => Function.new("lpad") { |*args| Predefined::Str.lpad(*args) },
|
|
50
|
+
"gsub" => Function.new("gsub") { |*args| Predefined::Str.gsub(*args) },
|
|
51
|
+
"m" => Function.new("match") { |*args| Predefined::Str.match(*args) },
|
|
52
|
+
"sub" => Function.new("sub") { |*args| Predefined::Str.sub(*args) },
|
|
53
|
+
|
|
54
|
+
# Shell
|
|
43
55
|
"se" => Function.new("se") { |*args| Predefined::Shell.se(*args) },
|
|
44
56
|
}
|
|
45
57
|
|
|
@@ -57,10 +69,16 @@ module L43Rmap
|
|
|
57
69
|
Function.new("fallback to #{name}") do |rt, rcv, *args|
|
|
58
70
|
rcv.send(name, *args)
|
|
59
71
|
rescue NoMethodError
|
|
60
|
-
|
|
72
|
+
try_sending(name, rcv, *args)
|
|
61
73
|
end
|
|
62
74
|
end
|
|
63
75
|
end
|
|
76
|
+
|
|
77
|
+
def try_sending(name, rcv, *args)
|
|
78
|
+
rcv.to_i.send(name, *args)
|
|
79
|
+
rescue NoMethodError
|
|
80
|
+
rcv.to_s.send(name, *args)
|
|
81
|
+
end
|
|
64
82
|
end
|
|
65
83
|
end
|
|
66
84
|
end
|
data/lib/l43_rmap/runtime.rb
CHANGED
|
@@ -5,19 +5,20 @@ require_relative 'runtime/line_time'
|
|
|
5
5
|
|
|
6
6
|
module L43Rmap
|
|
7
7
|
class Runtime
|
|
8
|
-
attr_reader :chunks, :current, :input_stream, :output_stream, :rand, :terminated, :time
|
|
8
|
+
# attr_reader :chunks, :current, :input_stream, :output_stream, :rand, :randomize, :terminated, :time
|
|
9
|
+
attr_reader :chunks, :current, :input_stream, :output_stream, :randomize, :terminated, :time
|
|
9
10
|
|
|
10
11
|
DefaultDecRandomMax = 10_000
|
|
11
12
|
|
|
12
|
-
def run(input, output)
|
|
13
|
+
def run(input, output, randomize: false)
|
|
13
14
|
@output_stream = make_output_stream(output)
|
|
14
15
|
@input_stream = make_input_stream(input)
|
|
15
|
-
# @rand = SecureRandom.random_number
|
|
16
16
|
@time = Time.now
|
|
17
|
-
|
|
17
|
+
@randomize = randomize
|
|
18
18
|
|
|
19
19
|
execute!
|
|
20
20
|
rescue EOFError
|
|
21
|
+
maybe_output_buffer
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def random_hex = @__randomhex__ ||= SecureRandom.hex
|
|
@@ -52,8 +53,7 @@ module L43Rmap
|
|
|
52
53
|
in :terminate | :term
|
|
53
54
|
break
|
|
54
55
|
in Array
|
|
55
|
-
|
|
56
|
-
output_stream << "\n"
|
|
56
|
+
push_line(result.join)
|
|
57
57
|
else
|
|
58
58
|
raise "BAD RETURN FROM LineTime: #{result.inspect}"
|
|
59
59
|
end
|
|
@@ -73,6 +73,28 @@ module L43Rmap
|
|
|
73
73
|
return stream unless String === stream
|
|
74
74
|
File.open(stream, 'w')
|
|
75
75
|
end
|
|
76
|
+
|
|
77
|
+
def maybe_output_buffer
|
|
78
|
+
return unless randomize
|
|
79
|
+
|
|
80
|
+
output_buffer
|
|
81
|
+
.sort_by { rand }
|
|
82
|
+
.each do
|
|
83
|
+
output_stream << it
|
|
84
|
+
output_stream << "\n"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def output_buffer = @__output_buffer__ ||= []
|
|
89
|
+
|
|
90
|
+
def push_line(line)
|
|
91
|
+
if randomize
|
|
92
|
+
output_buffer << line
|
|
93
|
+
else
|
|
94
|
+
output_stream << line
|
|
95
|
+
output_stream << "\n"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
76
98
|
end
|
|
77
99
|
end
|
|
78
100
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/l43_rmap/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: l43_rmap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Dober
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-06-
|
|
10
|
+
date: 2026-06-06 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ostruct
|
|
@@ -91,6 +91,7 @@ files:
|
|
|
91
91
|
- lib/l43_rmap/functions.rb
|
|
92
92
|
- lib/l43_rmap/functions/predefined.rb
|
|
93
93
|
- lib/l43_rmap/functions/predefined/shell.rb
|
|
94
|
+
- lib/l43_rmap/functions/predefined/str.rb
|
|
94
95
|
- lib/l43_rmap/parsing/chunk_parser.rb
|
|
95
96
|
- lib/l43_rmap/parsing/input.rb
|
|
96
97
|
- lib/l43_rmap/parsing/parse_state.rb
|
|
@@ -100,17 +101,6 @@ files:
|
|
|
100
101
|
- lib/l43_rmap/runtime.rb
|
|
101
102
|
- lib/l43_rmap/runtime/line_time.rb
|
|
102
103
|
- lib/l43_rmap/version.rb
|
|
103
|
-
- lib/peg.backup/all.rb
|
|
104
|
-
- lib/peg.backup/combinators.rb
|
|
105
|
-
- lib/peg.backup/combinators/implementation.rb
|
|
106
|
-
- lib/peg.backup/parser.rb
|
|
107
|
-
- lib/peg.backup/parser/input.rb
|
|
108
|
-
- lib/peg.backup/parsers.rb
|
|
109
|
-
- lib/peg.backup/parsers/advanced_parsers.rb
|
|
110
|
-
- lib/peg.backup/parsers/base_parsers.rb
|
|
111
|
-
- lib/peg.backup/parsers/common_parsers.rb
|
|
112
|
-
- lib/peg.backup/parsers/true_set.rb
|
|
113
|
-
- lib/peg.backup/result.rb
|
|
114
104
|
homepage: https://codeberg.org/lab419/rmap
|
|
115
105
|
licenses:
|
|
116
106
|
- AGPL-3.0-or-later
|
data/lib/peg.backup/all.rb
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../../enumerable'
|
|
4
|
-
module Peg
|
|
5
|
-
class InfiniteLoop < Exception; end
|
|
6
|
-
|
|
7
|
-
module Combinators
|
|
8
|
-
module Implementation
|
|
9
|
-
|
|
10
|
-
def _debug(parser, name: nil)
|
|
11
|
-
Parser.new(parser.name) do |input, _name|
|
|
12
|
-
puts "debugging #{name || parser.name}: #{input.inspect}"
|
|
13
|
-
result = Parser.parse(parser, input)
|
|
14
|
-
puts "debugging #{name || parser.name}: #{result}"
|
|
15
|
-
result
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def _lookahead(parsers, name:)
|
|
20
|
-
parser = _select(parsers)
|
|
21
|
-
Parser.new(name || "lookahead(#{parser.name})") do |input, name|
|
|
22
|
-
case Parser.parse(parser, input)
|
|
23
|
-
in {ok: true}
|
|
24
|
-
{ok: true, ast: nil, input:}
|
|
25
|
-
in error
|
|
26
|
-
error
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# def _map(parser, name, mapper)
|
|
32
|
-
# name ||= "map(#{parser.name})"
|
|
33
|
-
# Parser.new(name) do |input, _name|
|
|
34
|
-
# case Parser.parse(parser, input)
|
|
35
|
-
# in {ok: true, ast: ast, input: new_input}
|
|
36
|
-
# {ok: true, ast: mapper.(ast), input: new_input}
|
|
37
|
-
# in error
|
|
38
|
-
# error
|
|
39
|
-
# end
|
|
40
|
-
# end
|
|
41
|
-
# end
|
|
42
|
-
|
|
43
|
-
def _map_result(parser, name, mapper)
|
|
44
|
-
Parser.new(name) do |input, name|
|
|
45
|
-
result = Parser.parse(parser, input)
|
|
46
|
-
# require "debug"; binding.break
|
|
47
|
-
mapper.(result)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def _many(parser, max:, min:, name:)
|
|
52
|
-
Parser.new(name) do |input, _name|
|
|
53
|
-
total_ast = []
|
|
54
|
-
original_input = input
|
|
55
|
-
current_input = input
|
|
56
|
-
match_count = 0
|
|
57
|
-
loop do
|
|
58
|
-
if current_input.empty?
|
|
59
|
-
break Result.ok(ast: total_ast, input:) if match_count >= min
|
|
60
|
-
break Result.nok(error: "many #{name} did not succeed the required #{min} times, but only #{match_count}", input: original_input, name:)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
case Parser.parse(parser, current_input)
|
|
64
|
-
in {ok: true, ast:, input:}
|
|
65
|
-
raise InfiniteLoop, "must not parse zero width inside many in parser: #{parser.name}" if input.pos == current_input.pos
|
|
66
|
-
current_input = input
|
|
67
|
-
total_ast = [*total_ast, ast]
|
|
68
|
-
match_count += 1
|
|
69
|
-
break Result.ok(ast: total_ast, input:) if max && match_count >= max
|
|
70
|
-
else
|
|
71
|
-
break Result.ok(ast: total_ast, input:) if match_count >= min
|
|
72
|
-
break Result.nok(error: "many #{name} did not succeed the required #{min} times, but only #{match_count}", input: original_input, name:)
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def _satisfy(parser, name:, &satisfier)
|
|
79
|
-
Parser.new(name || "satisfy(#{parser.name})") do |input, name|
|
|
80
|
-
original_input = input
|
|
81
|
-
case Parser.parse(parser, input)
|
|
82
|
-
in {ok: false} => error
|
|
83
|
-
error
|
|
84
|
-
in {ok: true, ast:, input:} => result
|
|
85
|
-
ok = satisfier.(ast)
|
|
86
|
-
if ok == true
|
|
87
|
-
result
|
|
88
|
-
elsif ok
|
|
89
|
-
{ok: true, ast: ok, input:}
|
|
90
|
-
else
|
|
91
|
-
{ok: false, input: original_input, error: "satisfier #{name} failed", name: name}
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def _select(*parsers, name: nil)
|
|
98
|
-
parsers = parsers.flatten
|
|
99
|
-
raise ArgumentError, "all parsers must be instances of Parser" unless parsers.all? { Parser === it }
|
|
100
|
-
Parser.new(name || "select #{parsers.map(&:name).join(", ")}") do |input, name|
|
|
101
|
-
result = {ok: false, error: "No parser matched in select named #{name}", input:}
|
|
102
|
-
parsers.each do |parser|
|
|
103
|
-
# case p(Parser.parse(parser, input))
|
|
104
|
-
this_result = Parser.parse(parser, input)
|
|
105
|
-
# require "debug"; binding.break
|
|
106
|
-
case this_result
|
|
107
|
-
in {ok: true} => result
|
|
108
|
-
break result
|
|
109
|
-
in _
|
|
110
|
-
nil
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
result
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def _sequence(parsers, name)
|
|
118
|
-
name ||= "seq(#{parsers.map(&:name).join(", ")})"
|
|
119
|
-
Parser.new(name) do |input, _name|
|
|
120
|
-
original_input = input
|
|
121
|
-
result = parsers.reduce_while [input, []] do |(input, ast), parser|
|
|
122
|
-
# require "debug"; binding.break
|
|
123
|
-
parsed = Parser.parse(parser, input)
|
|
124
|
-
# p parsed
|
|
125
|
-
case parsed
|
|
126
|
-
in {ok: true, ast: ast_node, input:}
|
|
127
|
-
cont_reduce([input, [*ast, ast_node]])
|
|
128
|
-
in {ok: false, error:}
|
|
129
|
-
halt_reduce(Result.nok(input: original_input, error:, name: name))
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
case result
|
|
134
|
-
in {ok: false} => error
|
|
135
|
-
error
|
|
136
|
-
in [input, ast]
|
|
137
|
-
Result.ok(ast:, input:)
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'parser'
|
|
4
|
-
require_relative 'combinators/implementation'
|
|
5
|
-
module Peg
|
|
6
|
-
module Combinators extend self
|
|
7
|
-
include Implementation
|
|
8
|
-
|
|
9
|
-
def lookahead(*parsers, name: nil)
|
|
10
|
-
parsers = make_parsers(*parsers)
|
|
11
|
-
_lookahead(parsers, name:)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def many(*parsers, max: nil, min: 0, name: nil)
|
|
15
|
-
name ||= "many(#{parsers.map(&:name).join(", ")})"
|
|
16
|
-
case parsers
|
|
17
|
-
in []
|
|
18
|
-
raise ArgumentError, "missing parser"
|
|
19
|
-
in [parser]
|
|
20
|
-
_many(parser, max:, min:, name:)
|
|
21
|
-
in _
|
|
22
|
-
many(select(*parsers), max:, min:, name:)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def map(parser, name: nil, &mapper)
|
|
27
|
-
raise ArgumentError, "missing mapper function" unless mapper
|
|
28
|
-
raise ArgumentError, "mapper function must have arity 1" unless mapper.arity == 1
|
|
29
|
-
name ||= "map(#{parser.name})"
|
|
30
|
-
Parser.new(name) do |input|
|
|
31
|
-
Parser.parse(parser, input).map(&mapper)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
alias_method :_map, :map
|
|
35
|
-
|
|
36
|
-
def map_result(parser, name: nil, &mapper)
|
|
37
|
-
raise ArgumentError, "missing mapper function" unless mapper
|
|
38
|
-
raise ArgumentError, "mapper function must have arity 1" unless mapper.arity == 1
|
|
39
|
-
_map_result(parser, name || "map_result(#{parser.name})", mapper)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def maybe(parser, name: nil)
|
|
43
|
-
Parser.new(name || "maybe(#{parser.name})") do |input, name|
|
|
44
|
-
case Parser.parse(parser, input)
|
|
45
|
-
in {ok: false}
|
|
46
|
-
{ok: true, ast: nil, input:}
|
|
47
|
-
in success
|
|
48
|
-
success
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def satisfy(parser, name: nil, &satisfier)
|
|
54
|
-
raise ArgumentError, "missing satisfier block" unless satisfier
|
|
55
|
-
parser = make_parser(parser)
|
|
56
|
-
_satisfy(parser, name, satisfier)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def select(*parsers, name: nil)
|
|
60
|
-
case parsers
|
|
61
|
-
in []
|
|
62
|
-
raise ArgumentError, "missing parser in select"
|
|
63
|
-
in [parser]
|
|
64
|
-
raise ArgumentError, "one parser in a selection is a NOP, remove the select call"
|
|
65
|
-
in _
|
|
66
|
-
_select(*make_parsers(parsers), name)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def sequence(*parsers, name: nil)
|
|
71
|
-
case parsers
|
|
72
|
-
in []
|
|
73
|
-
raise ArgumentError, "missing parser"
|
|
74
|
-
in [parser]
|
|
75
|
-
raise ArgumentError, "one parser in a sequence is a NOP, remove the sequence call"
|
|
76
|
-
in _
|
|
77
|
-
_sequence(make_parsers(parsers), name)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Peg
|
|
4
|
-
class Parser
|
|
5
|
-
class Input
|
|
6
|
-
attr_reader :content, :pos
|
|
7
|
-
|
|
8
|
-
def advance(by=1)
|
|
9
|
-
self.class.new(content.drop(by), pos+by)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def empty? = content.empty?
|
|
13
|
-
|
|
14
|
-
def show(count)
|
|
15
|
-
raise ArgumentError, "count must be an integer > 5" unless Integer === count && count > 5
|
|
16
|
-
return content.join("") if content.length < count
|
|
17
|
-
|
|
18
|
-
"#{content.take(count-3).join}..."
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def ==(other)
|
|
22
|
-
self.class === other &&
|
|
23
|
-
other.content == content &&
|
|
24
|
-
other.pos == pos
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
def initialize(content, pos=1)
|
|
29
|
-
@content = content
|
|
30
|
-
@pos = pos
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/peg.backup/parser.rb
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'combinators/implementation'
|
|
4
|
-
require_relative 'parser/input'
|
|
5
|
-
require_relative 'parsers'
|
|
6
|
-
require_relative 'result'
|
|
7
|
-
|
|
8
|
-
module Peg
|
|
9
|
-
class Parser
|
|
10
|
-
include Peg::Combinators::Implementation
|
|
11
|
-
|
|
12
|
-
attr_reader :parse_fn, :name
|
|
13
|
-
|
|
14
|
-
def self.parse(parser, input)
|
|
15
|
-
raise ArgumentError, "parser must be an instance of #{self}" unless self === parser
|
|
16
|
-
case input
|
|
17
|
-
when String
|
|
18
|
-
parser.parse_fn.(Peg::Parser::Input.new(input.grapheme_clusters))
|
|
19
|
-
when Peg::Parser::Input
|
|
20
|
-
parser.parse_fn.(input)
|
|
21
|
-
else
|
|
22
|
-
raise ArgumentError, "input must be a string or instance of Input" unless self.class === parser
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def and(*parsers, name: nil) = _sequence([self, *parsers], name)
|
|
27
|
-
|
|
28
|
-
def debug(name: nil) = _debug(self, name:)
|
|
29
|
-
|
|
30
|
-
def many(name: nil, max: nil, min: 0) = _many(self, name:, max:, min:)
|
|
31
|
-
def map(name: nil, &blk) = Peg::Combinators.map(self, name:, &blk)
|
|
32
|
-
|
|
33
|
-
def or(*parsers, name: nil) = _select(self, *parsers, name:)
|
|
34
|
-
|
|
35
|
-
def satisfy(name: nil, &satisfier) = _satisfy(self, name:, &satisfier)
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
def initialize(name, &blk)
|
|
39
|
-
raise ArgumentError, "blk must be provided as a parse function" unless blk
|
|
40
|
-
@name = name
|
|
41
|
-
@parse_fn = blk
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../combinators'
|
|
4
|
-
require_relative '../parsers'
|
|
5
|
-
module Peg
|
|
6
|
-
module Parsers
|
|
7
|
-
module AdvancedParsers
|
|
8
|
-
include Peg::Combinators
|
|
9
|
-
include Peg::Parsers
|
|
10
|
-
|
|
11
|
-
def list_parser(element_parser:, seperator_parser:, name: "list parser")
|
|
12
|
-
sequence(
|
|
13
|
-
element_parser,
|
|
14
|
-
many(
|
|
15
|
-
sequence(
|
|
16
|
-
seperator_parser, element_parser
|
|
17
|
-
)
|
|
18
|
-
.map { it[1] }
|
|
19
|
-
)
|
|
20
|
-
)
|
|
21
|
-
.map { it.flatten.compact }
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'true_set'
|
|
4
|
-
module Peg
|
|
5
|
-
module Parsers
|
|
6
|
-
module BaseParsers
|
|
7
|
-
|
|
8
|
-
# Parses a character which is a member of any of the `char_classes`
|
|
9
|
-
def char_class_parser(*char_classes, name: nil)
|
|
10
|
-
case char_classes
|
|
11
|
-
in [char_class]
|
|
12
|
-
_1_char_class_parser(char_class, name:)
|
|
13
|
-
else
|
|
14
|
-
_char_classes_parser(*char_classes, name:)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def char_parser(set=nil, name: nil, negate: false)
|
|
19
|
-
set = mk_set(set)
|
|
20
|
-
name ||= "char_parser(#{set.inspect})"
|
|
21
|
-
Parser.new(name) do |input|
|
|
22
|
-
case input.content
|
|
23
|
-
in []
|
|
24
|
-
Result.nok(error: "unexpected end of input", input:, name:)
|
|
25
|
-
in [h, *]
|
|
26
|
-
if set.member?(h) && !negate || !set.member?(h) && negate
|
|
27
|
-
Result.ok(ast: h, input: input.advance)
|
|
28
|
-
else
|
|
29
|
-
Result.nok(input:, error: "#{h} is not member of the required set #{set}", name:)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def end_parser(name: nil)
|
|
36
|
-
name ||= "end_parser"
|
|
37
|
-
Parser.new(name) do |input|
|
|
38
|
-
case input.content
|
|
39
|
-
in []
|
|
40
|
-
Result.ok(ast: nil, input:)
|
|
41
|
-
in _
|
|
42
|
-
Result.nok(input: input, error: "not at end of input", name:)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def make_parser(parser)
|
|
48
|
-
case parser
|
|
49
|
-
when String
|
|
50
|
-
char_parser(parser)
|
|
51
|
-
else
|
|
52
|
-
parser
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def make_parsers(*parsers)
|
|
57
|
-
parsers
|
|
58
|
-
.flatten
|
|
59
|
-
.map { make_parser it }
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
def _1_char_class_parser(char_class, name:)
|
|
65
|
-
rgx = Regexp.compile("[[:#{char_class}:]]")
|
|
66
|
-
name ||= "char_class_parser(:#{char_class})"
|
|
67
|
-
Parser.new(name) do |input|
|
|
68
|
-
case input.content
|
|
69
|
-
in []
|
|
70
|
-
Result.nok(error: "unexpected end of input", input:, name:)
|
|
71
|
-
in [h, *]
|
|
72
|
-
if rgx.match?(h)
|
|
73
|
-
Result.ok(ast: h, input: input.advance)
|
|
74
|
-
else
|
|
75
|
-
Result.nok(input:, name:, error: "#{h} does not match the char class: :#{char_class}")
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def _char_classes_parser(*char_classes, name:)
|
|
82
|
-
rgx = Regexp.compile("[#{_compile_char_classes(char_classes)}]")
|
|
83
|
-
name ||= "char_class_parser(#{char_classes.inspect})"
|
|
84
|
-
Parser.new(name) do |input|
|
|
85
|
-
case input.content
|
|
86
|
-
in []
|
|
87
|
-
Result.nok(error: "unexpected end of input", input:, name:)
|
|
88
|
-
in [h, *]
|
|
89
|
-
if rgx.match?(h)
|
|
90
|
-
Result.ok(ast: h, input: input.advance)
|
|
91
|
-
else
|
|
92
|
-
Result.nok(input:, name:, error: "#{h} does not match the char class: :#{char_classes}")
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def _compile_char_class(char_class)
|
|
99
|
-
case char_class
|
|
100
|
-
when Symbol
|
|
101
|
-
"[:#{char_class}:]"
|
|
102
|
-
when String
|
|
103
|
-
"[#{char_class}]"
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def _compile_char_classes(char_classes)
|
|
108
|
-
"[" +
|
|
109
|
-
char_classes
|
|
110
|
-
.map { _compile_char_class it }
|
|
111
|
-
.join + "]"
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def mk_set(set)
|
|
115
|
-
if set
|
|
116
|
-
Set.new(set.grapheme_clusters)
|
|
117
|
-
else
|
|
118
|
-
TrueSet
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../combinators'
|
|
4
|
-
module Peg
|
|
5
|
-
module Parsers
|
|
6
|
-
module CommonParsers
|
|
7
|
-
include Peg::Combinators
|
|
8
|
-
|
|
9
|
-
def id_parser(name: nil, lead_class: :alpha, inner_class: [:alnum, "_"] )
|
|
10
|
-
sequence(char_class_parser(*Array(lead_class)),
|
|
11
|
-
many(char_class_parser(*Array(inner_class)), name:),
|
|
12
|
-
name:
|
|
13
|
-
).map {
|
|
14
|
-
it.flatten.join.to_sym
|
|
15
|
-
}
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# Just parses any string starting with either a `+` or `-` sign followed by at least one
|
|
20
|
-
# _decimal digit_.
|
|
21
|
-
#
|
|
22
|
-
# **N.B.** that leading zeroes are parsed (and therefore ignored) and will not parse
|
|
23
|
-
# it as a hexadecimal or octal number
|
|
24
|
-
def int_parser(name=nil)
|
|
25
|
-
parser = sequence(
|
|
26
|
-
maybe(char_parser("+-")),
|
|
27
|
-
many(char_class_parser(:digit), min: 1),
|
|
28
|
-
name: name || "int_parser")
|
|
29
|
-
map_result(parser) { _make_int(it) }
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def literal_set(set, name: nil, lead_class: :alpha, inner_class: [:alnum, "_"])
|
|
33
|
-
id_parser(name:, lead_class:, inner_class:)
|
|
34
|
-
.satisfy { set.member? it }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def ws_parser(name=nil)
|
|
38
|
-
map(
|
|
39
|
-
many(
|
|
40
|
-
char_class_parser(:space),
|
|
41
|
-
min: 1,
|
|
42
|
-
name: "ws_parser"
|
|
43
|
-
)
|
|
44
|
-
) {|_| nil}
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
private
|
|
48
|
-
|
|
49
|
-
def _make_int(result)
|
|
50
|
-
case result
|
|
51
|
-
in {ok: true, ast:}
|
|
52
|
-
result.merge(ast: ast.join.to_i)
|
|
53
|
-
in {input:}
|
|
54
|
-
result.merge(error: "Not an integer at #{input.show(10).inspect} in int_parser")
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/peg.backup/parsers.rb
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "parsers/base_parsers"
|
|
4
|
-
require_relative "parsers/common_parsers"
|
|
5
|
-
module Peg
|
|
6
|
-
module Parsers
|
|
7
|
-
extend BaseParsers
|
|
8
|
-
include BaseParsers
|
|
9
|
-
|
|
10
|
-
extend CommonParsers
|
|
11
|
-
include CommonParsers
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/peg.backup/result.rb
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Peg
|
|
4
|
-
class Result
|
|
5
|
-
class IllegalState < RuntimeError
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
attr_reader :ast, :error, :input, :ok
|
|
9
|
-
|
|
10
|
-
def self.ok(ast:, input:) = new(ok: true, ast:, input:)
|
|
11
|
-
|
|
12
|
-
def self.nok(input:, error:, name: nil)
|
|
13
|
-
error = error + " in parser: #{name}" if name
|
|
14
|
-
new(ok: false, input:, error:)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def deconstruct_keys(*, **) = to_h
|
|
18
|
-
|
|
19
|
-
def map(&blk)
|
|
20
|
-
return self unless ok
|
|
21
|
-
self.class.ok(ast: blk.(ast), input:)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def merge(ast: nil, error: nil, input: nil)
|
|
25
|
-
@ast = ast if ast
|
|
26
|
-
@error = error if error
|
|
27
|
-
@input = input if input
|
|
28
|
-
self
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def or(input:, error:, name: nil) = self.class.nok(input:, error:, name:)
|
|
32
|
-
|
|
33
|
-
def reduce(values, &blk)
|
|
34
|
-
result = self
|
|
35
|
-
values.each do |ele|
|
|
36
|
-
result = blk.(result, ele)
|
|
37
|
-
break result unless result.ok
|
|
38
|
-
end
|
|
39
|
-
result
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def to_h = {ast:, error:, input:, ok:}
|
|
43
|
-
|
|
44
|
-
def to_s = inspect
|
|
45
|
-
|
|
46
|
-
def update(&updater)
|
|
47
|
-
raise IllegalState, "must not update an error result" unless ok
|
|
48
|
-
map(&updater)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def update_or(input:, error:, name: nil, &updater)
|
|
52
|
-
return map(&updater) if ok
|
|
53
|
-
|
|
54
|
-
self.class.nok(input:, error:, name:)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def while(input: nil, error: nil, name: nil, &blk)
|
|
58
|
-
result = self
|
|
59
|
-
count = 0
|
|
60
|
-
loop do
|
|
61
|
-
return input ? self.class.nok(input:, error:, name:) : result unless result.ok
|
|
62
|
-
result = blk.(self, count)
|
|
63
|
-
count += 1
|
|
64
|
-
end
|
|
65
|
-
result
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
def initialize(ok:, input:, ast: nil, error: nil)
|
|
70
|
-
@ast = ast
|
|
71
|
-
@error = error
|
|
72
|
-
@input = input
|
|
73
|
-
@ok = ok
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|