lib/figtree/parser.rb in figtree-1.2.0 vs lib/figtree/parser.rb in figtree-2.0.0
- old
+ new
@@ -6,113 +6,183 @@
class Parser < Parslet::Parser
include IPv4
include IPv6
rule(:eof) { any.absent? }
- rule(:group_title) { match('[a-zA-Z]').repeat(1) }
- rule(:space) { match("\s").repeat(0) }
- rule(:newline) { match("\n") >> match("\r").maybe }
+ rule(:group_title) { match('[a-zA-Z_]').repeat(1) }
+ rule(:space) { (match("\s") | str(' ')) }
+ rule(:spaces) { (space.repeat(2) | comment) }
+ rule(:newline) { str("\n") >> match("\r").maybe }
+ rule(:terminator) do
+ space.repeat(0) >> (comment | newline | eof)
+ end
+ rule(:backslash) do
+ space.repeat(0) >> str("\\")
+ end
rule(:grouper) do
- newline.maybe >>
str('[') >>
group_title.as(:group_title) >>
str(']')
end
+ rule(:comment_start) { (str(';') | str('#')) }
+ rule(:comment_end) { (newline | eof) }
rule(:comment) do
- # comments go uncaptured
- (str(';') >>
- (newline.absent? >> any).repeat) >>
- newline.maybe
+ (
+ comment_start >>
+ space.repeat(0) >>
+ (
+ comment_end.absent? >> any
+ ).repeat
+ ) >>
+ space.repeat(0) >>
+ comment_end
end
- rule(:string) do
+ rule(:quoted_string) do
str('"') >>
- ((str('\\') >> any) | (str('"').absent? >> any)).repeat.as(:string) >>
+ (
+ (str('\\') >> any) | (str('"').absent? >> any)
+ ).repeat(1) >>
str('"')
end
+
+ rule(:unquoted_string) do
+ (
+ (
+ (
+ (backslash | terminator).absent?
+ ) >> any
+ ).repeat(1).as(:left) >>
+ backslash >>
+ terminator
+ ).repeat(0) >>
+ (
+ terminator.absent? >> any
+ ).repeat(1).as(:right) >>
+ terminator
+ end
+
+ rule(:string) do
+ (quoted_string | unquoted_string).as(:string)
+ end
+
rule(:boolean) do
- # expand this check
- (str('no') | str('yes')).as(:boolean)
+ (
+ str('no') |
+ str('yes') |
+ str('false') |
+ str('true')
+ ).as(:boolean)
end
rule(:number) do
match('[0-9]').repeat(1).as(:number)
end
rule(:ip_address) do
(ipv4 | ipv6).as(:ip_address)
end
+ rule(:at_least_one_char) do
+ match('[a-zA-Z]').repeat(1)
+ end
+
rule(:array) do
- (match('[a-zA-Z]').repeat(1) >>
- (str(',') >>
- match('[a-zA-Z]').repeat(1)).repeat.maybe).maybe.as(:array) >>
- (str(',') | newline | eof)
+ (
+ # minimum array
+ at_least_one_char >>
+ (
+ # extending elementwise
+ str(',') >> space.repeat.maybe >>
+ at_least_one_char
+ ).repeat(1)
+ ).as(:array) >>
+ (newline | eof)
end
rule(:file_path) do
- match('[/a-z/]').repeat(1).as(:file_path)
+ (
+ (
+ str('/') >>
+ at_least_one_char
+ ).repeat(1) >>
+ str('/').maybe
+ ).as(:file_path)
end
rule(:snake_case_key) do
- match('[a-zA-Z0-9_]').repeat(1).as(:snake_case_key)
+ match('[a-zA-Z0-9_]').repeat(1).
+ as(:snake_case_key)
end
rule(:snakey_option_key) do
snake_case_key.as(:key_to_be_overridden) >>
str('<') >>
snake_case_key.as(:optional_key) >>
str('>')
end
- rule(:assignment) do
- snake_case_key >>
- space >>
- str("=") >>
- space >>
+ rule(:value) do
# this ordering matters
# we are roughly moving from more
# to less specific
- (ip_address |
- number |
- boolean |
- array |
- snake_case_key |
- file_path |
- string)
+ (
+ ip_address |
+ number |
+ boolean |
+ array |
+ file_path |
+ string
+ )
end
+ rule(:equals_value) do
+ space.repeat(0) >>
+ str("=") >>
+ space.repeat(0) >>
+ value >>
+ newline.repeat(0)
+ end
+
+ rule(:assignment) do
+ snake_case_key >>
+ equals_value
+ end
+
rule(:override_assignment) do
snakey_option_key >>
- space >>
- str("=") >>
- space >>
- file_path
+ equals_value
end
rule(:assignment_or_comment) do
( comment | assignment | override_assignment )
end
rule(:group_member) do
- newline.maybe >>
assignment_or_comment >>
- newline.maybe
+ space.repeat(0) >>
+ newline.repeat(0)
end
rule(:group) do
- (grouper >>
- group_member.repeat.maybe).as(:group).
- repeat.maybe
+ (
+ grouper >>
+ space.repeat(0) >>
+ comment.maybe >>
+ newline.repeat(0) >>
+ group_member.repeat(0)
+ ).as(:group).
+ repeat(0)
end
rule(:comment_or_group) do
- comment.maybe >>
- newline.maybe >>
- group.maybe
+ # may start file with attribution
+ # comment or timestamp etc
+ comment.repeat.maybe >>
+ group
end
root(:comment_or_group)
end
end