Skip to content

Commit

Permalink
Using cannonical conformance tests now
Browse files Browse the repository at this point in the history
  • Loading branch information
fd committed May 29, 2011
1 parent 0eef7ef commit 6f05750
Show file tree
Hide file tree
Showing 84 changed files with 346 additions and 569 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "spec/fixtures/conformance"]
path = spec/fixtures/conformance
url = git://github.com/lloyd/JSONSelectTests.git
223 changes: 179 additions & 44 deletions lib/json_select/selector_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,18 @@ def a
end

def e
elements[4]
elements[5]
end

end

module Pseudo2
def a
elements[1]
end

def s
elements[5]
end

end
Expand Down Expand Up @@ -669,53 +680,66 @@ def _nt_pseudo
end
s4 << r5
if r5
r6 = _nt_pseudo_function_name
r6 = _nt_positional_pseudo_function_name
s4 << r6
if r6
if has_terminal?('(', false, index)
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure('(')
r7 = nil
s7, i7 = [], index
loop do
r8 = _nt_ws
if r8
s7 << r8
else
break
end
end
r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
s4 << r7
if r7
s8, i8 = [], index
loop do
r9 = _nt_ws
if r9
s8 << r9
else
break
end
if has_terminal?('(', false, index)
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure('(')
r9 = nil
end
r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
s4 << r8
if r8
r10 = _nt_expression
s4 << r9
if r9
s10, i10 = [], index
loop do
r11 = _nt_ws
if r11
s10 << r11
else
break
end
end
r10 = instantiate_node(SyntaxNode,input, i10...index, s10)
s4 << r10
if r10
s11, i11 = [], index
loop do
r12 = _nt_ws
if r12
s11 << r12
else
break
end
end
r11 = instantiate_node(SyntaxNode,input, i11...index, s11)
s4 << r11
if r11
if has_terminal?(')', false, index)
r13 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure(')')
r13 = nil
r12 = _nt_expression
s4 << r12
if r12
s13, i13 = [], index
loop do
r14 = _nt_ws
if r14
s13 << r14
else
break
end
end
r13 = instantiate_node(SyntaxNode,input, i13...index, s13)
s4 << r13
if r13
if has_terminal?(')', false, index)
r15 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure(')')
r15 = nil
end
s4 << r15
end
end
end
end
Expand All @@ -732,8 +756,95 @@ def _nt_pseudo
if r4
r0 = r4
else
@index = i0
r0 = nil
i16, s16 = index, []
if has_terminal?(':', false, index)
r17 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure(':')
r17 = nil
end
s16 << r17
if r17
r18 = _nt_subselector_pseudo_function_name
s16 << r18
if r18
s19, i19 = [], index
loop do
r20 = _nt_ws
if r20
s19 << r20
else
break
end
end
r19 = instantiate_node(SyntaxNode,input, i19...index, s19)
s16 << r19
if r19
if has_terminal?('(', false, index)
r21 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure('(')
r21 = nil
end
s16 << r21
if r21
s22, i22 = [], index
loop do
r23 = _nt_ws
if r23
s22 << r23
else
break
end
end
r22 = instantiate_node(SyntaxNode,input, i22...index, s22)
s16 << r22
if r22
r24 = _nt_selectors_group
s16 << r24
if r24
s25, i25 = [], index
loop do
r26 = _nt_ws
if r26
s25 << r26
else
break
end
end
r25 = instantiate_node(SyntaxNode,input, i25...index, s25)
s16 << r25
if r25
if has_terminal?(')', false, index)
r27 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure(')')
r27 = nil
end
s16 << r27
end
end
end
end
end
end
end
if s16.last
r16 = instantiate_node(JSONSelect::Ast::PseudoSelector,input, i16...index, s16)
r16.extend(Pseudo2)
else
@index = i16
r16 = nil
end
if r16
r0 = r16
else
@index = i0
r0 = nil
end
end
end

Expand Down Expand Up @@ -817,10 +928,10 @@ def _nt_pseudo_class_name
r0
end

def _nt_pseudo_function_name
def _nt_positional_pseudo_function_name
start_index = index
if node_cache[:pseudo_function_name].has_key?(index)
cached = node_cache[:pseudo_function_name][index]
if node_cache[:positional_pseudo_function_name].has_key?(index)
cached = node_cache[:positional_pseudo_function_name][index]
if cached
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
@index = cached.interval.end
Expand Down Expand Up @@ -854,7 +965,31 @@ def _nt_pseudo_function_name
end
end

node_cache[:pseudo_function_name][start_index] = r0
node_cache[:positional_pseudo_function_name][start_index] = r0

r0
end

def _nt_subselector_pseudo_function_name
start_index = index
if node_cache[:subselector_pseudo_function_name].has_key?(index)
cached = node_cache[:subselector_pseudo_function_name][index]
if cached
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
@index = cached.interval.end
end
return cached
end

if has_terminal?('has', false, index)
r0 = instantiate_node(SyntaxNode,input, index...(index + 3))
@index += 3
else
terminal_parse_failure('has')
r0 = nil
end

node_cache[:subselector_pseudo_function_name][start_index] = r0

r0
end
Expand Down
11 changes: 9 additions & 2 deletions lib/json_select/selector_parser.tt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ grammar JSONSelectSelector
# ;
rule pseudo
( ':' a:pseudo_class_name <JSONSelect::Ast::PseudoSelector> ) /
( ':' a:pseudo_function_name '(' ws* e:expression ws* ')' <JSONSelect::Ast::PseudoSelector> )
( ':' a:positional_pseudo_function_name ws* '(' ws* e:expression ws* ')' <JSONSelect::Ast::PseudoSelector> ) /
( ':' a:subselector_pseudo_function_name ws* '(' ws* s:selectors_group ws* ')' <JSONSelect::Ast::PseudoSelector> )
end

# pseudo_class_name
Expand All @@ -74,10 +75,16 @@ grammar JSONSelectSelector

# pseudo_function_name
# : `nth-child` | `nth-last-child`
rule pseudo_function_name
rule positional_pseudo_function_name
'nth-child' / 'nth-last-child'
end

# pseudo_function_name
# : `nth-child` | `nth-last-child`
rule subselector_pseudo_function_name
'has'
end

# expression
# /* expression is and of the form "an+b" */
# : TODO
Expand Down
Loading

6 comments on commit 6f05750

@lloyd
Copy link

@lloyd lloyd commented on 6f05750 May 29, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are you finding the broken out conformance tests? How do you feel about the negative tests, those where the .output file contains Error:. Is it useful that actual error messages emitted by the javascript implementation occur in test files, or annoying?

@fd
Copy link
Owner Author

@fd fd commented on 6f05750 May 29, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they are great. The negative tests are less useful but it's easy enough to map the JS error messages to Ruby error messages. Maybe it's a good idea to define standardized error numbers. Like this the tests are not coupled to the JS implementation.

@lloyd
Copy link

@lloyd lloyd commented on 6f05750 May 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if I care to regulate how errors are reported in other implementations... But you are the only other implementor at this point, so basically I'm all ears.

One thing I was thinking is to change the extension of negative tests to .error (from .output). This way crazy over zealous implementations could copy the ref impl's js errors verbatim, while others could just check for the existence of the error file to determine whether or not an error was expected.

@fd
Copy link
Owner Author

@fd fd commented on 6f05750 May 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think changing the extension of the negative tests to .error is better as it makes the test type more explicit.

Also I think that negative tests like this one are not in the right place. I feel that the level_{1,2,3} groups should contain tests about the value-selecting logic not about the parser. A forth group of tests, the parser tests (or maybe level_0), might contain the tests for the parser details (like white space, precedence, parse errors, etc.).

@lloyd
Copy link

@lloyd lloyd commented on 6f05750 May 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I'll make the change to .error: lloyd/JSONSelectTests#1

I understand the suggestion about level_0, but it would be confusing. level_{123} correspond to conformance levels. Syntax errors in level 3 language constructs have to reside somewhere that they can be filtered out by implementers building level 1 support.

One thing we could do is create subdirectories under the level_{123} directories... perhaps syntax and matching directories. But then that gets into a pretty complicated structure for a fairly simple collection of stuff. what do you think?

@fd
Copy link
Owner Author

@fd fd commented on 6f05750 May 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Let's just keep the level_0 stuff as it is and when things grow out of controle (which would presumably be in the distant future) we can still add more structure.

Please sign in to comment.