Skip to content

Commit

Permalink
Merge e47add3 into d75361e
Browse files Browse the repository at this point in the history
  • Loading branch information
codalogic committed Jan 16, 2018
2 parents d75361e + e47add3 commit a5df072
Show file tree
Hide file tree
Showing 6 changed files with 298 additions and 95 deletions.
38 changes: 25 additions & 13 deletions abnf/jcr-abnf.txt
Expand Up @@ -58,14 +58,13 @@ target-rule-name = annotations "$"
name = ALPHA *( ALPHA / DIGIT / "-" / "_" )

rule-def = member-rule / type-designator rule-def-type-rule /
array-rule / object-rule / group-rule /
target-rule-name
value-rule / group-rule / target-rule-name
type-designator = type-kw 1*sp-cmt / ":" *sp-cmt
rule-def-type-rule = value-rule / type-choice
value-rule = primitive-rule / array-rule / object-rule
member-rule = annotations
member-name-spec *sp-cmt ":" *sp-cmt type-rule
member-name-spec = regex / q-string
member-name-spec = backtick-regex / q-string
type-rule = value-rule / type-choice / target-rule-name
type-choice = annotations "(" type-choice-items
*( choice-combiner type-choice-items ) ")"
Expand All @@ -84,7 +83,7 @@ annotation-name = name
annotation-parameters = multi-line-parameters

primitive-rule = annotations primitive-def
primitive-def = string-type / string-range / string-value /
primitive-def = string-type / string-range / string-value1 / string-value2 /
null-type / boolean-type / true-value /
false-value / double-type / float-type /
float-range / float-value /
Expand All @@ -100,7 +99,8 @@ boolean-type = boolean-kw
true-value = true-kw
false-value = false-kw
string-type = string-kw
string-value = q-string
string-value1 = sq-string
string-value2 = q-string
string-range = regex
double-type = double-kw
float-type = float-kw
Expand Down Expand Up @@ -194,29 +194,41 @@ exp = e [ minus / plus ] 1*DIGIT
e = %x65 / %x45 ; e E
zero = %x30 ; 0

q-string = quotation-mark *char quotation-mark
; From RFC 7159
q-string = quotation-mark *char quotation-mark
; Derive from RFC 7159
quotation-mark = %x22 ; " quotation mark U+0022
char = unescaped /
escape (
%x22 / ; " quotation mark U+0022
%x5C / ; \ reverse solidus U+005C
quotation-mark /
escape-codes )
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
escape = %x5C ; \
escape-codes =
%x2F / ; / solidus U+002F
%x62 / ; b backspace U+0008
%x66 / ; f form feed U+000C
%x6E / ; n line feed U+000A
%x72 / ; r carriage return U+000D
%x74 / ; t tab U+0009
%x75 4HEXDIG ) ; uXXXX U+XXXX
escape = %x5C ; \
quotation-mark = %x22 ; "
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
%x75 4HEXDIG ; uXXXX U+XXXX

sq-string = single-quote-mark *sq-char single-quote-mark
single-quote-mark = %x27 ; ' single quotation mark U+0027
sq-char = sq-unescaped /
escape (
single-quote-mark /
escape-codes )
sq-unescaped = %x20-26 / %x28-5B / %x5D-10FFFF ; Not ' or \

regex = "/" *( escape "/" / not-slash ) "/"
[ regex-modifiers ]
not-slash = HTAB / CR / LF / %x20-2E / %x30-10FFFF
; Any char except "/"
regex-modifiers = *( "i" / "s" / "x" )

backtick-regex = "`" *( escape "`" / not-backtick ) "`"
not-backtick = HTAB / CR / LF / %x20-5F / %x61-10FFFF
; Any char except "`"
uri-scheme = 1*ALPHA

;; Keywords
Expand Down
2 changes: 1 addition & 1 deletion lib/jcr/evaluate_member_rules.rb
Expand Up @@ -60,7 +60,7 @@ def self.evaluate_member jcr, rule_atom, data, econs, behavior, target_annotatio
match_spec = Regexp.new( "" )
trace( econs, "Noting empty regular expression." )
else
match_spec = Regexp.new( rule[:member_regex][:regex].to_s )
match_spec = Regexp.new( "^#{rule[:member_regex][:regex].to_s}$" )
end
if match_spec =~ data[ 0 ]
member_match = true
Expand Down
62 changes: 43 additions & 19 deletions lib/jcr/parser.rb
Expand Up @@ -129,10 +129,9 @@ class Parser < Parslet::Parser
#!

rule(:rule_def) { member_rule | (type_designator >> rule_def_type_rule) |
array_rule | object_rule | group_rule | target_rule_name }
value_rule | group_rule | target_rule_name }
#! rule_def = member_rule / type_designator rule_def_type_rule /
#! array_rule / object_rule / group_rule /
#! target_rule_name
#! value_rule / group_rule / target_rule_name
rule(:type_designator) { str('type') >> spcCmnt.repeat(1) | str(':') >> spcCmnt? }
#! type_designator = type-kw 1*spcCmnt / ":" spcCmnt?
#> type-kw = "type"
Expand All @@ -143,8 +142,8 @@ class Parser < Parslet::Parser
rule(:member_rule) { ( annotations >> member_name_spec >> spcCmnt? >> str(':') >> spcCmnt? >> type_rule ).as(:member_rule) }
#! member_rule = annotations
#! member_name_spec spcCmnt? ":" spcCmnt? type_rule
rule(:member_name_spec) { regex.as(:member_regex) | q_string.as(:member_name) }
#! member_name_spec = regex / q_string
rule(:member_name_spec) { backtick_regex.as(:member_regex) | q_string.as(:member_name) }
#! member_name_spec = backtick_regex / q_string
rule(:type_rule) { value_rule | type_choice | target_rule_name }
#! type_rule = value_rule / type_choice / target_rule_name
rule(:type_choice) { ( annotations >> str('(') >> type_choice_items >> ( choice_combiner >> type_choice_items ).repeat >> str(')') ).as(:group_rule) }
Expand Down Expand Up @@ -182,7 +181,7 @@ class Parser < Parslet::Parser
#! primitive_rule = annotations primitive_def

rule(:primitive_def) {
string_type | string_range | string_value |
string_type | string_range | string_value1 | string_value2 |
null_type | boolean_type | true_value | false_value |
double_type | float_type | float_range | float_value |
integer_type | integer_range | integer_value |
Expand All @@ -193,7 +192,7 @@ class Parser < Parslet::Parser
hex_type | base32hex_type | base32_type | base64url_type | base64_type |
any
}
#! primitive_def = string_type / string_range / string_value /
#! primitive_def = string_type / string_range / string_value1 / string_value2 /
#! null_type / boolean_type / true_value /
#! false_value / double_type / float_type /
#! float_range / float_value /
Expand All @@ -219,8 +218,10 @@ class Parser < Parslet::Parser
rule(:string_type) { str('string').as(:string) }
#! string_type = string-kw
#> string-kw = "string"
rule(:string_value) { q_string }
#! string_value = q_string
rule(:string_value1) { sq_string }
#! string_value1 = sq_string
rule(:string_value2) { q_string }
#! string_value2 = q_string
rule(:string_range) { regex }
#! string_range = regex
rule(:double_type) { str('double').as(:double_v) }
Expand Down Expand Up @@ -415,27 +416,45 @@ class Parser < Parslet::Parser
#! zero = %x30 ; 0
#!

rule(:q_string) {
rule(:q_string) { # (Double) quoted string
str('"') >>
( str('\\') >> match('[^\r\n]') | str('"').absent? >> match('[^\r\n]') ).repeat.as(:q_string) >>
# ( str('\\') >> match('[^\r\n]') | str('"').absent? >> match('[^\r\n]') ).repeat.as(:q_string) >>
( match('\.') | match('[^"]') ).repeat.as(:q_string) >>
str('"')
}
#! q_string = quotation-mark *char quotation-mark
#! ; From RFC 7159

#! q_string = quotation-mark *char quotation-mark
#! ; Derive from RFC 7159
#! quotation-mark = %x22 ; " quotation mark U+0022
#! char = unescaped /
#! escape (
#! %x22 / ; " quotation mark U+0022
#! %x5C / ; \ reverse solidus U+005C
#! quotation-mark /
#! escape_codes )
#! unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
#! escape = %x5C ; \
#! escape_codes =
#! %x2F / ; / solidus U+002F
#! %x62 / ; b backspace U+0008
#! %x66 / ; f form feed U+000C
#! %x6E / ; n line feed U+000A
#! %x72 / ; r carriage return U+000D
#! %x74 / ; t tab U+0009
#! %x75 4HEXDIG ) ; uXXXX U+XXXX
#! escape = %x5C ; \
#! quotation-mark = %x22 ; "
#! unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
#! %x75 4HEXDIG ; uXXXX U+XXXX
#!

rule(:sq_string) { # Single quoted string
str("'") >>
( str('\\') >> match('[^\r\n]') | str("'").absent? >> match('[^\r\n]') ).repeat.as(:q_string) >>
str("'")
}

#! sq_string = single-quote-mark *sq_char single-quote-mark
#! single-quote-mark = %x27 ; ' single quotation mark U+0027
#! sq_char = sq_unescaped /
#! escape (
#! single-quote-mark /
#! escape_codes )
#! sq_unescaped = %x20-26 / %x28-5B / %x5D-10FFFF ; Not ' or \
#!

rule(:regex) { str('/') >> (str('\\/') | match('[^/]+')).repeat.as(:regex) >> str('/') >> regex_modifiers.maybe }
Expand All @@ -447,6 +466,11 @@ class Parser < Parslet::Parser
#! regex_modifiers = *( "i" / "s" / "x" )
#!

rule(:backtick_regex) { str('`') >> (str('\\`') | match('[^`]+')).repeat.as(:regex) >> str('`') }
#! backtick_regex = "`" *( escape "`" / not-backtick ) "`"
#! not-backtick = HTAB / CR / LF / %x20-5F / %x61-10FFFF
#! ; Any char except "`"

rule(:uri_scheme) { ( match('[a-zA-Z]').repeat(1) ).as(:uri_scheme) }
#! uri_scheme = 1*ALPHA

Expand Down
48 changes: 40 additions & 8 deletions spec/evaluate_member_rules_spec.rb
Expand Up @@ -83,55 +83,87 @@
#

it 'should pass a member with regex and any value' do
tree = JCR.parse( '$mrule = /ab.*/ :any' )
tree = JCR.parse( '$mrule = `ab.*` :any' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "abc", "anything" ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_truthy
end

it 'should fail a member with regex and any value with {not} annotation' do
tree = JCR.parse( '$mrule = @{not} /ab.*/ :any' )
tree = JCR.parse( '$mrule = @{not} `ab.*` :any' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "abc", "anything" ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_falsey
end

it 'should pass a member with regex and an integer' do
tree = JCR.parse( '$mrule = /ab*/ :integer' )
tree = JCR.parse( '$mrule = `ab*` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "abc", 2 ], JCR::EvalConditions.new( mapping, nil ) )
e = JCR.evaluate_rule( tree[0], tree[0], [ "abb", 2 ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_truthy
end

it 'should fail a member with mismatch regex and an integer' do
tree = JCR.parse( '$mrule = /ab.*/ :integer' )
tree = JCR.parse( '$mrule = `ab.*` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "blah", 2 ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_falsey
end

it 'should fail a member with mismatch regex if name not suitably anchored and an integer' do
tree = JCR.parse( '$mrule = `ab.*` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "xabc", 2 ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_falsey
end

it 'should pass a member with regex with numbers and an integer' do
tree = JCR.parse( '$mrule = `ab\d*` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "ab123", 2 ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_truthy
end

it 'should fail a member with mismatch regex if name not suitably anchored and an integer' do
tree = JCR.parse( '$mrule = `ab\d*` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "ab123x", 2 ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_falsey
end

it 'should pass a member with empty regex and an integer matching any string' do
tree = JCR.parse( '$mrule = `` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "blah", 2 ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_truthy
end

it 'should pass a member with mismatch regex and an integer with {not} annotation' do
tree = JCR.parse( '$mrule = @{not} /ab.*/ :integer' )
tree = JCR.parse( '$mrule = @{not} `ab.*` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "blah", 2 ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_truthy
end

it 'should fail a member with regex and an integer against member with string' do
tree = JCR.parse( '$mrule = /ab.*/ :integer' )
tree = JCR.parse( '$mrule = `ab.*` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "abc", "a string" ], JCR::EvalConditions.new( mapping, nil ) )
expect( e.success ).to be_falsey
end

it 'should fail a member with mismatch regex and an integer against member with string' do
tree = JCR.parse( '$mrule = /ab.*/ :integer' )
tree = JCR.parse( '$mrule = `ab.*` :integer' )
mapping = JCR.map_rule_names( tree )
JCR.check_rule_target_names( tree, mapping )
e = JCR.evaluate_rule( tree[0], tree[0], [ "blah", "a string" ], JCR::EvalConditions.new( mapping, nil ) )
Expand Down

0 comments on commit a5df072

Please sign in to comment.