birman 0.1.0
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/CHANGELOG.md +42 -0
- data/LICENSE.txt +21 -0
- data/README.md +193 -0
- data/lib/birman/ast.rb +80 -0
- data/lib/birman/combinators.rb +75 -0
- data/lib/birman/context.rb +123 -0
- data/lib/birman/error_formatter.rb +38 -0
- data/lib/birman/grammar.rb +122 -0
- data/lib/birman/matchers.rb +396 -0
- data/lib/birman/nodes.rb +90 -0
- data/lib/birman/result.rb +65 -0
- data/lib/birman/rule_set.rb +39 -0
- data/lib/birman/rules.rb +77 -0
- data/lib/birman/version.rb +5 -0
- data/lib/birman.rb +42 -0
- metadata +60 -0
data/lib/birman/rules.rb
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Birman
|
|
4
|
+
# A standard library of rule modules. Include the ones you need;
|
|
5
|
+
# later includes override earlier ones (Comments replaces
|
|
6
|
+
# Whitespace's `spacing`, for example).
|
|
7
|
+
#
|
|
8
|
+
# Value rules (number, string, identifier) are lexemes: in a grammar
|
|
9
|
+
# that declares `ignore :spacing`, they skip trailing spacing on their own.
|
|
10
|
+
module Rules
|
|
11
|
+
# Whitespace as the `spacing` rule, plus a `token` helper for grammars
|
|
12
|
+
# that don't declare `ignore`.
|
|
13
|
+
module Whitespace
|
|
14
|
+
extend RuleSet
|
|
15
|
+
|
|
16
|
+
rule(:spacing) { match(/\s*/).quiet }
|
|
17
|
+
|
|
18
|
+
# A matcher followed by whitespace. Only needed in grammars that
|
|
19
|
+
# don't declare `ignore`.
|
|
20
|
+
def token(m) = Pick.new([Birman.coerce(m), spacing], 0)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Whitespace including comments. Works on its own or after
|
|
24
|
+
# Whitespace. Override comment_pattern for other comment syntaxes.
|
|
25
|
+
module Comments
|
|
26
|
+
extend RuleSet
|
|
27
|
+
|
|
28
|
+
rule(:spacing) { (match(/\s+/) | comment).rep.quiet }
|
|
29
|
+
rule(:comment) { match(comment_pattern).label("comment") }
|
|
30
|
+
|
|
31
|
+
def comment_pattern = /#[^\n]*/
|
|
32
|
+
def token(m) = Pick.new([Birman.coerce(m), spacing], 0)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Integers and floats, as Ruby numbers.
|
|
36
|
+
module Numbers
|
|
37
|
+
extend RuleSet
|
|
38
|
+
|
|
39
|
+
lexeme(:integer) { match(/\d+/).map(&:to_i).label("integer") }
|
|
40
|
+
lexeme(:float) { match(/\d+\.\d+/).map(&:to_f).label("float") }
|
|
41
|
+
lexeme(:number) { (float | integer).label("number") }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Double-quoted strings with backslash escapes. The opening quote
|
|
45
|
+
# commits, so an unterminated string is reported where it breaks.
|
|
46
|
+
module Strings
|
|
47
|
+
extend RuleSet
|
|
48
|
+
|
|
49
|
+
ESCAPES = { "n" => "\n", "t" => "\t", "r" => "\r", "0" => "\0" }.freeze
|
|
50
|
+
|
|
51
|
+
lexeme(:string) do
|
|
52
|
+
(str('"') > (string_part.rep >> str('"').label("closing quote")))
|
|
53
|
+
.map { |(_, parts, _)| parts.join }
|
|
54
|
+
.label("string")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
rule(:string_part) do
|
|
58
|
+
(match(/\\./).map { ESCAPES.fetch(_1[1], _1[1]) } |
|
|
59
|
+
match(/[^"\\\n]+/)).label("string character")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Identifiers that can't be reserved words. Declare those in the
|
|
64
|
+
# grammar with `keywords "if", "then", ...`.
|
|
65
|
+
module Identifiers
|
|
66
|
+
extend RuleSet
|
|
67
|
+
|
|
68
|
+
lexeme(:identifier) { (reserved_word.absent & match(/[A-Za-z_]\w*/)).label("identifier") }
|
|
69
|
+
|
|
70
|
+
rule(:reserved_word) do
|
|
71
|
+
next never if keywords.empty?
|
|
72
|
+
|
|
73
|
+
match(/(?:#{keywords.map { Regexp.escape(_1) }.join("|")})\b/)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
data/lib/birman.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# A small PEG parser library for Ruby 3.2+.
|
|
4
|
+
#
|
|
5
|
+
# Greeting = Birman.node(:name)
|
|
6
|
+
#
|
|
7
|
+
# class MyGrammar
|
|
8
|
+
# include Birman::Grammar
|
|
9
|
+
# include Birman::Rules::Whitespace
|
|
10
|
+
# include Birman::Rules::Identifiers
|
|
11
|
+
#
|
|
12
|
+
# root :greeting
|
|
13
|
+
# ignore :spacing
|
|
14
|
+
# rule(:greeting) { seq("hello", commit, identifier.as(:name)).to(Greeting) }
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# case MyGrammar.parse("hello world")
|
|
18
|
+
# in Birman::Success(value) then value
|
|
19
|
+
# in Birman::Failure => f then warn f.message
|
|
20
|
+
# end
|
|
21
|
+
module Birman
|
|
22
|
+
# The character offset of a byte offset into input. Free for ASCII
|
|
23
|
+
# input (Ruby caches ascii_only?), linear otherwise; used once per
|
|
24
|
+
# parse for a Failure, and only on demand for a Span.
|
|
25
|
+
def self.char_offset(input, byte_pos)
|
|
26
|
+
input.ascii_only? ? byte_pos : input.byteslice(0, byte_pos).length
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
require "strscan"
|
|
31
|
+
|
|
32
|
+
require_relative "birman/version"
|
|
33
|
+
require_relative "birman/result"
|
|
34
|
+
require_relative "birman/nodes"
|
|
35
|
+
require_relative "birman/context"
|
|
36
|
+
require_relative "birman/matchers"
|
|
37
|
+
require_relative "birman/rule_set"
|
|
38
|
+
require_relative "birman/combinators"
|
|
39
|
+
require_relative "birman/grammar"
|
|
40
|
+
require_relative "birman/error_formatter"
|
|
41
|
+
require_relative "birman/ast"
|
|
42
|
+
require_relative "birman/rules"
|
metadata
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: birman
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Tad Thorley
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Module-based grammars, immutable Data matchers and AST nodes with source
|
|
13
|
+
spans, packrat memoization, commit points, labels, and Success/Failure results.
|
|
14
|
+
email:
|
|
15
|
+
- phaedryx@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- CHANGELOG.md
|
|
21
|
+
- LICENSE.txt
|
|
22
|
+
- README.md
|
|
23
|
+
- lib/birman.rb
|
|
24
|
+
- lib/birman/ast.rb
|
|
25
|
+
- lib/birman/combinators.rb
|
|
26
|
+
- lib/birman/context.rb
|
|
27
|
+
- lib/birman/error_formatter.rb
|
|
28
|
+
- lib/birman/grammar.rb
|
|
29
|
+
- lib/birman/matchers.rb
|
|
30
|
+
- lib/birman/nodes.rb
|
|
31
|
+
- lib/birman/result.rb
|
|
32
|
+
- lib/birman/rule_set.rb
|
|
33
|
+
- lib/birman/rules.rb
|
|
34
|
+
- lib/birman/version.rb
|
|
35
|
+
homepage: https://github.com/phaedryx/birman
|
|
36
|
+
licenses:
|
|
37
|
+
- MIT
|
|
38
|
+
metadata:
|
|
39
|
+
homepage_uri: https://github.com/phaedryx/birman
|
|
40
|
+
source_code_uri: https://github.com/phaedryx/birman
|
|
41
|
+
changelog_uri: https://github.com/phaedryx/birman/blob/main/CHANGELOG.md
|
|
42
|
+
rubygems_mfa_required: 'true'
|
|
43
|
+
rdoc_options: []
|
|
44
|
+
require_paths:
|
|
45
|
+
- lib
|
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
47
|
+
requirements:
|
|
48
|
+
- - ">="
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: 3.2.0
|
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0'
|
|
56
|
+
requirements: []
|
|
57
|
+
rubygems_version: 4.0.3
|
|
58
|
+
specification_version: 4
|
|
59
|
+
summary: A small PEG parser library for Ruby.
|
|
60
|
+
test_files: []
|