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.
@@ -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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Birman
4
+ VERSION = "0.1.0"
5
+ 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: []