RbYAML 0.0.1
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.
- data/LICENSE +19 -0
- data/README +31 -0
- data/lib/rbyaml.rb +378 -0
- data/lib/rbyaml/composer.rb +189 -0
- data/lib/rbyaml/constructor.rb +374 -0
- data/lib/rbyaml/detector.rb +44 -0
- data/lib/rbyaml/dumper.rb +40 -0
- data/lib/rbyaml/emitter.rb +1116 -0
- data/lib/rbyaml/error.rb +81 -0
- data/lib/rbyaml/events.rb +92 -0
- data/lib/rbyaml/loader.rb +49 -0
- data/lib/rbyaml/nodes.rb +69 -0
- data/lib/rbyaml/parser.rb +488 -0
- data/lib/rbyaml/reader.rb +127 -0
- data/lib/rbyaml/representer.rb +183 -0
- data/lib/rbyaml/scanner.rb +1258 -0
- data/lib/rbyaml/serializer.rb +120 -0
- data/lib/rbyaml/test.rb +56 -0
- data/lib/rbyaml/tokens.rb +163 -0
- data/lib/rbyaml/yaml.rb +143 -0
- data/test/test_rbyaml.rb +18 -0
- data/test/yaml/gems.yml +130951 -0
- data/test/yaml/gems2.yml +113 -0
- data/test/yaml/test1.yml +3 -0
- data/test/yaml/test10.yml +8 -0
- data/test/yaml/test12.yml +8 -0
- data/test/yaml/test13.yml +4 -0
- data/test/yaml/test14.yml +4 -0
- data/test/yaml/test15.yml +8 -0
- data/test/yaml/test16.yml +7 -0
- data/test/yaml/test18.yml +6 -0
- data/test/yaml/test19.yml +5 -0
- data/test/yaml/test2.yml +3 -0
- data/test/yaml/test20.yml +6 -0
- data/test/yaml/test21.yml +4 -0
- data/test/yaml/test22.yml +4 -0
- data/test/yaml/test23.yml +13 -0
- data/test/yaml/test24.yml +14 -0
- data/test/yaml/test25.yml +7 -0
- data/test/yaml/test26.yml +7 -0
- data/test/yaml/test27.yml +29 -0
- data/test/yaml/test28.yml +26 -0
- data/test/yaml/test29.yml +13 -0
- data/test/yaml/test3.yml +8 -0
- data/test/yaml/test30.yml +7 -0
- data/test/yaml/test31.yml +2 -0
- data/test/yaml/test32.yml +13 -0
- data/test/yaml/test33.yml +2 -0
- data/test/yaml/test34.yml +8 -0
- data/test/yaml/test35.yml +4 -0
- data/test/yaml/test36.yml +8 -0
- data/test/yaml/test37.yml +2 -0
- data/test/yaml/test38.yml +8 -0
- data/test/yaml/test39.yml +2 -0
- data/test/yaml/test4.yml +8 -0
- data/test/yaml/test40.yml +3 -0
- data/test/yaml/test41.yml +5 -0
- data/test/yaml/test42.yml +12 -0
- data/test/yaml/test43.yml +15 -0
- data/test/yaml/test44.yml +23 -0
- data/test/yaml/test5.yml +3 -0
- data/test/yaml/test6.yml +5 -0
- data/test/yaml/test7.yml +10 -0
- data/test/yaml/test8.yml +10 -0
- data/test/yaml/test9.yml +8 -0
- metadata +111 -0
data/lib/rbyaml/error.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
module RbYAML
|
3
|
+
class Mark
|
4
|
+
attr_reader :name,:index,:line,:column,:buffer,:pointer
|
5
|
+
def initialize(name, index, line, column, buffer, pointer)
|
6
|
+
@name = name
|
7
|
+
@index = index
|
8
|
+
@line = line
|
9
|
+
@column = column
|
10
|
+
@buffer = buffer
|
11
|
+
@pointer = pointer
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_snippet(indent=4, max_length=75)
|
15
|
+
return nil if @buffer.nil?
|
16
|
+
head = ""
|
17
|
+
start = @pointer
|
18
|
+
while start > 0 && !"\0\r\n\x85".include?(@buffer[start-1])
|
19
|
+
start -= 1
|
20
|
+
if @pointer-start > max_length/2-1
|
21
|
+
head = " ... "
|
22
|
+
start += 5
|
23
|
+
break
|
24
|
+
end
|
25
|
+
end
|
26
|
+
tail = ""
|
27
|
+
tend = @pointer
|
28
|
+
while tend < @buffer.length && !"\0\r\n\x85".include?(@buffer[tend])
|
29
|
+
tend += 1
|
30
|
+
if tend-@pointer > max_length/2-1
|
31
|
+
tail = " ... "
|
32
|
+
tend -= 5
|
33
|
+
break
|
34
|
+
end
|
35
|
+
end
|
36
|
+
snippet = @buffer[start..tend]
|
37
|
+
' ' * indent + "#{head}#{snippet}#{tail}\n" + ' '*(indent+@pointer-start+head.length) + ' '
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
snippet = get_snippet()
|
42
|
+
where = " in \"#{@name}\", line #{@line+1}, column #{@column+1}"
|
43
|
+
if snippet
|
44
|
+
where << ":\n" << snippet
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class YAMLError < StandardError
|
50
|
+
end
|
51
|
+
|
52
|
+
class TypeError < YAMLError
|
53
|
+
end
|
54
|
+
|
55
|
+
class MarkedYAMLError < YAMLError
|
56
|
+
def initialize(context=nil, context_mark=nil, problem=nil, problem_mark=nil, note=nil)
|
57
|
+
super()
|
58
|
+
@context = context
|
59
|
+
@context_mark = context_mark
|
60
|
+
@problem = problem
|
61
|
+
@problem_mark = problem_mark
|
62
|
+
@note = note
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
lines = []
|
67
|
+
|
68
|
+
lines << @context if @context
|
69
|
+
if @context_mark && (@problem.nil? || @problem_mark.nil? ||
|
70
|
+
@context_mark.name != @problem_mark.name ||
|
71
|
+
@context_mark.line != @problem_mark.line ||
|
72
|
+
@context_mark.column != @problem_mark.column)
|
73
|
+
lines << @context_mark.to_s
|
74
|
+
end
|
75
|
+
lines << @problem if @problem
|
76
|
+
lines << @problem_mark.to_s if @problem_mark
|
77
|
+
lines << @note if @note
|
78
|
+
lines.join("\n")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
|
2
|
+
module RbYAML
|
3
|
+
class Event
|
4
|
+
attr_reader :start_mark, :end_mark
|
5
|
+
def initialize(start_mark=nil,end_mark=nil)
|
6
|
+
@start_mark = start_mark
|
7
|
+
@end_mark = end_mark
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
attributes = ["@anchor","@tag","@value"] & self.instance_variables
|
12
|
+
args = attributes.collect {|val| "#{val[1..-1]}=" + eval("#{val}").to_s}.join(", ")
|
13
|
+
"#{self.class.name}(#{args})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class NodeEvent < Event
|
18
|
+
attr_reader :anchor
|
19
|
+
def initialize(anchor, start_mark=nil, end_mark=nil)
|
20
|
+
super(start_mark,end_mark)
|
21
|
+
@anchor = anchor
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class CollectionStartEvent < NodeEvent
|
26
|
+
attr_reader :tag, :flow_style
|
27
|
+
def initialize(anchor,tag,start_mark=nil, end_mark=nil,flow_style=nil)
|
28
|
+
super(anchor,start_mark,end_mark)
|
29
|
+
@tag = tag
|
30
|
+
@flow_style = flow_style
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class CollectionEndEvent < Event
|
35
|
+
end
|
36
|
+
|
37
|
+
class StreamStartEvent < Event
|
38
|
+
attr_reader :encoding
|
39
|
+
def initialize(start_mark=nil,end_mark=nil,encoding=nil)
|
40
|
+
super(start_mark,end_mark)
|
41
|
+
@encoding = encoding
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class StreamEndEvent < Event
|
46
|
+
end
|
47
|
+
|
48
|
+
class DocumentStartEvent < Event
|
49
|
+
attr_reader :explicit, :version, :tags
|
50
|
+
def initialize(start_mark=nil,end_mark=nil,explicit=nil,version=nil,tags=nil)
|
51
|
+
super(start_mark,end_mark)
|
52
|
+
@explicit = explicit
|
53
|
+
@version = version
|
54
|
+
@tags = tags
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class DocumentEndEvent < Event
|
59
|
+
attr_reader :explicit
|
60
|
+
def initialize(start_mark=nil,end_mark=nil,explicit=nil)
|
61
|
+
super(start_mark,end_mark)
|
62
|
+
@explicit = explicit
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class AliasEvent < NodeEvent
|
67
|
+
end
|
68
|
+
|
69
|
+
class ScalarEvent < NodeEvent
|
70
|
+
attr_reader :tag, :style, :value, :implicit
|
71
|
+
def initialize(anchor,tag,implicit,value,start_mark=nil, end_mark=nil,style=nil)
|
72
|
+
super(anchor,start_mark,end_mark)
|
73
|
+
@tag = tag
|
74
|
+
@style = style
|
75
|
+
@value = value
|
76
|
+
@implicit = implicit
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class SequenceStartEvent < CollectionStartEvent
|
81
|
+
end
|
82
|
+
|
83
|
+
class SequenceEndEvent < CollectionEndEvent
|
84
|
+
end
|
85
|
+
|
86
|
+
class MappingStartEvent < CollectionStartEvent
|
87
|
+
end
|
88
|
+
|
89
|
+
class MappingEndEvent < CollectionEndEvent
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# This is a more or less straight translation of PyYAML3000 to Ruby
|
2
|
+
|
3
|
+
require 'rbyaml/reader'
|
4
|
+
require 'rbyaml/scanner'
|
5
|
+
require 'rbyaml/parser'
|
6
|
+
require 'rbyaml/composer'
|
7
|
+
require 'rbyaml/constructor'
|
8
|
+
require 'rbyaml/detector'
|
9
|
+
|
10
|
+
module RbYAML
|
11
|
+
class CommonLoader
|
12
|
+
include Reader, Scanner, Parser
|
13
|
+
|
14
|
+
def initialize(stream)
|
15
|
+
super()
|
16
|
+
initialize_reader(stream)
|
17
|
+
initialize_scanner
|
18
|
+
initialize_parser
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class BaseLoader < CommonLoader
|
23
|
+
include BaseComposer, BaseConstructor, BaseDetector
|
24
|
+
def initialize(stream)
|
25
|
+
super
|
26
|
+
initialize_composer
|
27
|
+
initialize_constructor
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class SafeLoader < CommonLoader
|
32
|
+
include Composer, SafeConstructor, Detector
|
33
|
+
def initialize(stream)
|
34
|
+
super
|
35
|
+
initialize_composer
|
36
|
+
initialize_constructor
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Loader < CommonLoader
|
41
|
+
include Composer, Constructor, Detector
|
42
|
+
def initialize(stream)
|
43
|
+
super
|
44
|
+
initialize_composer
|
45
|
+
initialize_constructor
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
data/lib/rbyaml/nodes.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
module RbYAML
|
3
|
+
class Node
|
4
|
+
attr_accessor :tag, :value, :start_mark, :end_mark
|
5
|
+
|
6
|
+
def initialize(tag, value, start_mark, end_mark)
|
7
|
+
@tag = tag
|
8
|
+
@value = value
|
9
|
+
@start_mark = start_mark
|
10
|
+
@end_mark = end_mark
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
value = @value
|
15
|
+
if Array === value
|
16
|
+
if value.empty?
|
17
|
+
value = "<empty>"
|
18
|
+
elsif value.length == 1
|
19
|
+
value = "<1 item>"
|
20
|
+
else
|
21
|
+
value = "#{value.length} items>"
|
22
|
+
end
|
23
|
+
else
|
24
|
+
if value.length > 75
|
25
|
+
value = value[0..70].to_s+"..."
|
26
|
+
else
|
27
|
+
value = value.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
"#{self.class.name}(tag=#{@tag}, value=#{value})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class ScalarNode < Node
|
36
|
+
def tid
|
37
|
+
"scalar"
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_accessor :style
|
41
|
+
|
42
|
+
def initialize(tag, value,start_mark=nil,end_mark=nil,style=nil)
|
43
|
+
super(tag,value,start_mark,end_mark)
|
44
|
+
@style = style
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class CollectionNode < Node
|
49
|
+
attr_accessor :flow_style
|
50
|
+
|
51
|
+
def initialize(tag, value,start_mark=nil,end_mark=nil,flow_style=nil)
|
52
|
+
super(tag,value,start_mark,end_mark)
|
53
|
+
@flow_style = flow_style
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class SequenceNode < CollectionNode
|
58
|
+
def tid
|
59
|
+
"sequence"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class MappingNode < CollectionNode
|
64
|
+
def tid
|
65
|
+
"mapping"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,488 @@
|
|
1
|
+
|
2
|
+
# YAML can be parsed by an LL(1) parser!
|
3
|
+
#
|
4
|
+
# We use the following production rules:
|
5
|
+
# stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
|
6
|
+
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END?
|
7
|
+
# implicit_document ::= block_node DOCUMENT-END?
|
8
|
+
# block_node ::= ALIAS | properties? block_content
|
9
|
+
# flow_node ::= ALIAS | properties? flow_content
|
10
|
+
# properties ::= TAG ANCHOR? | ANCHOR TAG?
|
11
|
+
# block_content ::= block_collection | flow_collection | SCALAR
|
12
|
+
# flow_content ::= flow_collection | SCALAR
|
13
|
+
# block_collection ::= block_sequence | block_mapping
|
14
|
+
# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
|
15
|
+
# block_mapping ::= BLOCK-MAPPING_START ((KEY block_node_or_indentless_sequence?)? (VALUE block_node_or_indentless_sequence?)?)* BLOCK-END
|
16
|
+
# block_node_or_indentless_sequence ::= ALIAS | properties? (block_content | indentless_block_sequence)
|
17
|
+
# indentless_block_sequence ::= (BLOCK-ENTRY block_node?)+
|
18
|
+
# flow_collection ::= flow_sequence | flow_mapping
|
19
|
+
# flow_sequence ::= FLOW-SEQUENCE-START (flow_sequence_entry FLOW-ENTRY)* flow_sequence_entry? FLOW-SEQUENCE-END
|
20
|
+
# flow_mapping ::= FLOW-MAPPING-START (flow_mapping_entry FLOW-ENTRY)* flow_mapping_entry? FLOW-MAPPING-END
|
21
|
+
# flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
22
|
+
# flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
23
|
+
|
24
|
+
# TODO: support for BOM within a stream.
|
25
|
+
# stream ::= (BOM? implicit_document)? (BOM? explicit_document)* STREAM-END
|
26
|
+
|
27
|
+
# FIRST sets:
|
28
|
+
# stream: { STREAM-START }
|
29
|
+
# explicit_document: { DIRECTIVE DOCUMENT-START }
|
30
|
+
# implicit_document: FIRST(block_node)
|
31
|
+
# block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
32
|
+
# flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
33
|
+
# block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
|
34
|
+
# flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
|
35
|
+
# block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
|
36
|
+
# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
37
|
+
# block_sequence: { BLOCK-SEQUENCE-START }
|
38
|
+
# block_mapping: { BLOCK-MAPPING-START }
|
39
|
+
# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
|
40
|
+
# indentless_sequence: { ENTRY }
|
41
|
+
# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
42
|
+
# flow_sequence: { FLOW-SEQUENCE-START }
|
43
|
+
# flow_mapping: { FLOW-MAPPING-START }
|
44
|
+
# flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
|
45
|
+
# flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
|
46
|
+
|
47
|
+
require 'rbyaml/error'
|
48
|
+
require 'rbyaml/tokens'
|
49
|
+
require 'rbyaml/events'
|
50
|
+
require 'rbyaml/scanner'
|
51
|
+
|
52
|
+
module RbYAML
|
53
|
+
class ParserError < MarkedYAMLError
|
54
|
+
end
|
55
|
+
|
56
|
+
module Parser
|
57
|
+
|
58
|
+
DEFAULT_TAGS = {
|
59
|
+
'!' => '!',
|
60
|
+
'!!' => 'tag:yaml.org,2002:'
|
61
|
+
}
|
62
|
+
|
63
|
+
def initialize_parser
|
64
|
+
@current_event = nil
|
65
|
+
@yaml_version = nil
|
66
|
+
@events = nil
|
67
|
+
@working_events = nil
|
68
|
+
@tag_handles = { }
|
69
|
+
end
|
70
|
+
|
71
|
+
def check_event(*choices)
|
72
|
+
init_events
|
73
|
+
@current_event = @working_events.shift if @current_event.nil?
|
74
|
+
if @current_event
|
75
|
+
return true if choices.empty?
|
76
|
+
for choice in choices
|
77
|
+
return true if choice === @current_event
|
78
|
+
end
|
79
|
+
end
|
80
|
+
false
|
81
|
+
end
|
82
|
+
|
83
|
+
def peek_event
|
84
|
+
init_events
|
85
|
+
@current_event = @working_events.shift if @current_event.nil?
|
86
|
+
@current_event
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_event
|
90
|
+
init_events
|
91
|
+
@current_event = @working_events.shift if @current_event.nil?
|
92
|
+
value = @current_event
|
93
|
+
@current_event = nil
|
94
|
+
value
|
95
|
+
end
|
96
|
+
|
97
|
+
def init_events
|
98
|
+
@events ||= parse_stream
|
99
|
+
@working_events ||= @events
|
100
|
+
end
|
101
|
+
|
102
|
+
def each_event(&block)
|
103
|
+
init_events
|
104
|
+
@events.each(&block)
|
105
|
+
end
|
106
|
+
|
107
|
+
def parse_stream
|
108
|
+
# STREAM-START implicit_document? explicit_document* STREAM-END
|
109
|
+
|
110
|
+
# Parse start of stream.
|
111
|
+
events = []
|
112
|
+
token = get_token
|
113
|
+
events << StreamStartEvent.new(token.start_mark, token.end_mark,token.encoding)
|
114
|
+
|
115
|
+
# Parse implicit document.
|
116
|
+
unless check_token(DirectiveToken, DocumentStartToken,StreamEndToken)
|
117
|
+
@tag_handles = DEFAULT_TAGS
|
118
|
+
token = peek_token
|
119
|
+
start_mark = end_mark = token.start_mark
|
120
|
+
events << DocumentStartEvent.new(start_mark, end_mark,false)
|
121
|
+
events += parse_block_node
|
122
|
+
token = peek_token
|
123
|
+
start_mark = end_mark = token.start_mark
|
124
|
+
explicit = false
|
125
|
+
while check_token(DocumentEndToken)
|
126
|
+
token = get_token
|
127
|
+
end_mark = token.end_mark
|
128
|
+
explicit = true
|
129
|
+
end
|
130
|
+
events << DocumentEndEvent.new(start_mark, end_mark,explicit)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Parse explicit documents.
|
134
|
+
while !check_token(StreamEndToken)
|
135
|
+
token = peek_token
|
136
|
+
start_mark = token.start_mark
|
137
|
+
version, tags = process_directives
|
138
|
+
raise ParserError.new(nil, nil,"expected '<document start>', but found #{peek_token.id}",peek_token.start_mark) unless check_token(DocumentStartToken)
|
139
|
+
token = get_token
|
140
|
+
end_mark = token.end_mark
|
141
|
+
events << DocumentStartEvent.new(start_mark, end_mark,true,version,tags)
|
142
|
+
if check_token(DirectiveToken,DocumentStartToken, DocumentEndToken, StreamEndToken)
|
143
|
+
events << process_empty_scalar(token.end_mark)
|
144
|
+
else
|
145
|
+
events += parse_block_node
|
146
|
+
end
|
147
|
+
token = peek_token
|
148
|
+
start_mark = end_mark = token.start_mark
|
149
|
+
explicit = false
|
150
|
+
while check_token(DocumentEndToken)
|
151
|
+
token = get_token
|
152
|
+
end_mark = token.end_mark
|
153
|
+
explicit=true
|
154
|
+
end
|
155
|
+
events << DocumentEndEvent.new(start_mark, end_mark,explicit)
|
156
|
+
end
|
157
|
+
# Parse end of stream.
|
158
|
+
token = get_token
|
159
|
+
events << StreamEndEvent.new(token.start_mark, token.end_mark)
|
160
|
+
events
|
161
|
+
end
|
162
|
+
|
163
|
+
def process_directives
|
164
|
+
# DIRECTIVE*
|
165
|
+
while check_token(DirectiveToken)
|
166
|
+
token = get_token
|
167
|
+
if token.name == "YAML"
|
168
|
+
raise ParserError.new(nil, nil,"found duplicate YAML directive", token.start_mark) if !@yaml_version.nil?
|
169
|
+
major, minor = token.value[0].to_i, token.value[1].to_i
|
170
|
+
raise ParserError.new(nil,nil,"found incompatible YAML document (version 1.* is required)",token.start_mark) if major != 1
|
171
|
+
@yaml_version = [major,minor]
|
172
|
+
elsif token.name == "TAG"
|
173
|
+
handle, prefix = token.value
|
174
|
+
raise ParserError.new(nil,nil,"duplicate tag handle #{handle}",token.start_mark) if @tag_handles.member?(handle)
|
175
|
+
@tag_handles[handle] = prefix
|
176
|
+
end
|
177
|
+
end
|
178
|
+
if !@tag_handles.empty?
|
179
|
+
value = @yaml_version, @tag_handles.dup
|
180
|
+
else
|
181
|
+
value = @yaml_version, nil
|
182
|
+
end
|
183
|
+
for key in DEFAULT_TAGS.keys
|
184
|
+
@tag_handles[key] = DEFAULT_TAGS[key] if !@tag_handles.include?(key)
|
185
|
+
end
|
186
|
+
value
|
187
|
+
end
|
188
|
+
|
189
|
+
def parse_block_node
|
190
|
+
parse_node(true)
|
191
|
+
end
|
192
|
+
|
193
|
+
def parse_flow_node
|
194
|
+
parse_node
|
195
|
+
end
|
196
|
+
|
197
|
+
def parse_block_node_or_indentless_sequence
|
198
|
+
parse_node(true, true)
|
199
|
+
end
|
200
|
+
|
201
|
+
def parse_node(block=false, indentless_sequence=false)
|
202
|
+
# block_node ::= ALIAS | properties? block_content
|
203
|
+
# flow_node ::= ALIAS | properties? flow_content
|
204
|
+
# properties ::= TAG ANCHOR? | ANCHOR TAG?
|
205
|
+
# block_content ::= block_collection | flow_collection | SCALAR
|
206
|
+
# flow_content ::= flow_collection | SCALAR
|
207
|
+
# block_collection ::= block_sequence | block_mapping
|
208
|
+
# block_node_or_indentless_sequence ::= ALIAS | properties?
|
209
|
+
# (block_content | indentless_block_sequence)
|
210
|
+
events = []
|
211
|
+
if check_token(AliasToken)
|
212
|
+
token = get_token
|
213
|
+
events << AliasEvent.new(token.value, token.start_mark, token.end_mark)
|
214
|
+
else
|
215
|
+
anchor = nil
|
216
|
+
tag = nil
|
217
|
+
start_mark = end_mark = tag_mark = nil
|
218
|
+
if check_token(AnchorToken)
|
219
|
+
token = get_token
|
220
|
+
start_mark = token.start_mark
|
221
|
+
end_mark = token.end_mark
|
222
|
+
anchor = token.value
|
223
|
+
if check_token(TagToken)
|
224
|
+
token = get_token
|
225
|
+
tag_mark = token.start_mark
|
226
|
+
end_mark = token.end_mark
|
227
|
+
tag = token.value
|
228
|
+
end
|
229
|
+
elsif check_token(TagToken)
|
230
|
+
token = get_token
|
231
|
+
start_mark = tag_mark = token.start_mark
|
232
|
+
end_mark = token.end_mark
|
233
|
+
tag = token.value
|
234
|
+
if check_token(AnchorToken)
|
235
|
+
token = get_token
|
236
|
+
end_mark = token.end_mark
|
237
|
+
anchor = token.value
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
if !tag.nil? and tag != "!"
|
242
|
+
handle, suffix = tag
|
243
|
+
if !handle.nil?
|
244
|
+
raise ParserError.new("while parsing a node", start_mark,"found undefined tag handle #{handle}",tag_mark) if !@tag_handles.include?(handle)
|
245
|
+
tag = @tag_handles[handle]+suffix
|
246
|
+
else
|
247
|
+
tag = suffix
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
#if tag == u'!':
|
252
|
+
# raise ParserError("while parsing a node", start_mark,
|
253
|
+
# "found non-specific tag '!'", tag_mark,
|
254
|
+
# "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag' and share your opinion.")
|
255
|
+
if start_mark.nil?
|
256
|
+
start_mark = end_mark = peek_token.start_mark
|
257
|
+
end
|
258
|
+
event = nil
|
259
|
+
collection_events = nil
|
260
|
+
if indentless_sequence && check_token(BlockEntryToken)
|
261
|
+
end_mark = peek_token.end_mark
|
262
|
+
event = SequenceStartEvent.new(anchor, tag, start_mark, end_mark)
|
263
|
+
collection_events = parse_indentless_sequence
|
264
|
+
else
|
265
|
+
if check_token(ScalarToken)
|
266
|
+
token = get_token
|
267
|
+
end_mark = token.end_mark
|
268
|
+
implicit = ((tag.nil? || tag == "!") && token.implicit)
|
269
|
+
event = ScalarEvent.new(anchor, tag, implicit, token.value,start_mark, end_mark,token.style)
|
270
|
+
elsif check_token(FlowSequenceStartToken)
|
271
|
+
end_mark = peek_token.end_mark
|
272
|
+
event = SequenceStartEvent.new(anchor, tag, start_mark, end_mark,true)
|
273
|
+
collection_events = parse_flow_sequence
|
274
|
+
elsif check_token(FlowMappingStartToken)
|
275
|
+
end_mark = peek_token.end_mark
|
276
|
+
event = MappingStartEvent.new(anchor, tag, start_mark, end_mark,true)
|
277
|
+
collection_events = parse_flow_mapping
|
278
|
+
elsif block && check_token(BlockSequenceStartToken)
|
279
|
+
end_mark = peek_token.start_mark
|
280
|
+
event = SequenceStartEvent.new(anchor, tag, start_mark, end_mark,false)
|
281
|
+
collection_events = parse_block_sequence
|
282
|
+
elsif block && check_token(BlockMappingStartToken)
|
283
|
+
end_mark = peek_token.start_mark
|
284
|
+
event = MappingStartEvent.new(anchor, tag, start_mark, end_mark,false)
|
285
|
+
collection_events = parse_block_mapping
|
286
|
+
elsif !anchor.nil? || !tag.nil?
|
287
|
+
# Empty scalars are allowed even if a tag or an anchor is
|
288
|
+
# specified.
|
289
|
+
implicit = (tag.nil? || tag == "!")
|
290
|
+
event = ScalarEvent.new(anchor, tag, implicit,"",start_mark, end_mark)
|
291
|
+
else
|
292
|
+
if block
|
293
|
+
node = "block"
|
294
|
+
else
|
295
|
+
node = "flow"
|
296
|
+
end
|
297
|
+
token = peek_token
|
298
|
+
raise ParserError.new("while scanning a #{node} node", start_mark,"expected the node content, but found #{token.tid}",token.start_mark)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
events << event
|
302
|
+
events += collection_events if collection_events
|
303
|
+
end
|
304
|
+
events
|
305
|
+
end
|
306
|
+
|
307
|
+
def parse_block_sequence
|
308
|
+
# BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
|
309
|
+
events = []
|
310
|
+
token = get_token
|
311
|
+
start_mark = token.start_mark
|
312
|
+
while check_token(BlockEntryToken)
|
313
|
+
token = get_token
|
314
|
+
if !check_token(BlockEntryToken, BlockEndToken)
|
315
|
+
events += parse_block_node
|
316
|
+
else
|
317
|
+
events << process_empty_scalar(token.end_mark)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
if !check_token(BlockEndToken)
|
321
|
+
token = peek_token
|
322
|
+
raise ParserError.new("while scanning a block collection", start_mark,"expected <block end>, but found #{token.tid}", token.start_mark)
|
323
|
+
end
|
324
|
+
token = get_token
|
325
|
+
events << SequenceEndEvent.new(token.start_mark, token.end_mark)
|
326
|
+
events
|
327
|
+
end
|
328
|
+
|
329
|
+
def parse_indentless_sequence
|
330
|
+
# (BLOCK-ENTRY block_node?)+
|
331
|
+
events = []
|
332
|
+
while check_token(BlockEntryToken)
|
333
|
+
token = get_token
|
334
|
+
if !check_token(BlockEntryToken,KeyToken, ValueToken, BlockEndToken)
|
335
|
+
events += parse_block_node
|
336
|
+
else
|
337
|
+
events << process_empty_scalar(token.end_mark)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
token = peek_token
|
341
|
+
events << SequenceEndEvent.new(token.start_mark, token.start_mark)
|
342
|
+
events
|
343
|
+
end
|
344
|
+
|
345
|
+
|
346
|
+
def parse_block_mapping
|
347
|
+
# BLOCK-MAPPING_START
|
348
|
+
# ((KEY block_node_or_indentless_sequence?)?
|
349
|
+
# (VALUE block_node_or_indentless_sequence?)?)*
|
350
|
+
# BLOCK-END
|
351
|
+
events = []
|
352
|
+
token = get_token
|
353
|
+
start_mark = token.start_mark
|
354
|
+
while check_token(KeyToken, ValueToken)
|
355
|
+
if check_token(KeyToken)
|
356
|
+
token = get_token
|
357
|
+
if !check_token(KeyToken, ValueToken, BlockEndToken)
|
358
|
+
events += parse_block_node_or_indentless_sequence
|
359
|
+
else
|
360
|
+
events << process_empty_scalar(token.end_mark)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
if check_token(ValueToken)
|
364
|
+
token = get_token
|
365
|
+
if !check_token(KeyToken, ValueToken, BlockEndToken)
|
366
|
+
events += parse_block_node_or_indentless_sequence
|
367
|
+
else
|
368
|
+
events << process_empty_scalar(token.end_mark)
|
369
|
+
end
|
370
|
+
else
|
371
|
+
token = peek_token
|
372
|
+
events << process_empty_scalar(token.start_mark)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
if !check_token(BlockEndToken)
|
376
|
+
token = peek_token
|
377
|
+
raise ParserError.new("while scanning a block mapping", start_mark,"expected <block end>, but found #{token.tid}", token.start_mark)
|
378
|
+
end
|
379
|
+
token = get_token
|
380
|
+
events << MappingEndEvent.new(token.start_mark, token.end_mark)
|
381
|
+
events
|
382
|
+
end
|
383
|
+
|
384
|
+
def parse_flow_sequence
|
385
|
+
# flow_sequence ::= FLOW-SEQUENCE-START
|
386
|
+
# (flow_sequence_entry FLOW-ENTRY)*
|
387
|
+
# flow_sequence_entry?
|
388
|
+
# FLOW-SEQUENCE-END
|
389
|
+
# flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
390
|
+
#
|
391
|
+
# Note that while production rules for both flow_sequence_entry and
|
392
|
+
# flow_mapping_entry are equal, their interpretations are different.
|
393
|
+
# For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
|
394
|
+
# generate an inline mapping (set syntax).
|
395
|
+
events = []
|
396
|
+
token = get_token
|
397
|
+
start_mark = token.start_mark
|
398
|
+
while !check_token(FlowSequenceEndToken)
|
399
|
+
if check_token(KeyToken)
|
400
|
+
token = get_token
|
401
|
+
events << MappingStartEvent.new(nil,nil,token.start_mark, token.end_mark,true)
|
402
|
+
if !check_token(ValueToken,FlowEntryToken, FlowSequenceEndToken)
|
403
|
+
events += parse_flow_node
|
404
|
+
else
|
405
|
+
events << process_empty_scalar(token.end_mark)
|
406
|
+
end
|
407
|
+
if check_token(ValueToken)
|
408
|
+
token = get_token
|
409
|
+
if !check_token(FlowEntryToken, FlowSequenceEndToken)
|
410
|
+
events += parse_flow_node
|
411
|
+
else
|
412
|
+
events << process_empty_scalar(token.end_mark)
|
413
|
+
end
|
414
|
+
else
|
415
|
+
token = peek_token
|
416
|
+
events << process_empty_scalar(token.start_mark)
|
417
|
+
end
|
418
|
+
token = peek_token
|
419
|
+
events << MappingEndEvent.new(token.start_mark, token.start_mark)
|
420
|
+
else
|
421
|
+
events += parse_flow_node
|
422
|
+
end
|
423
|
+
if !check_token(FlowEntryToken, FlowSequenceEndToken)
|
424
|
+
token = peek_token
|
425
|
+
raise ParserError.new("while scanning a flow sequence", start_mark,"expected ',' or ']', but got #{token.tid}", token.start_mark)
|
426
|
+
end
|
427
|
+
if check_token(FlowEntryToken)
|
428
|
+
get_token
|
429
|
+
end
|
430
|
+
end
|
431
|
+
token = get_token
|
432
|
+
events << SequenceEndEvent.new(token.start_mark, token.end_mark)
|
433
|
+
events
|
434
|
+
end
|
435
|
+
|
436
|
+
def parse_flow_mapping
|
437
|
+
# flow_mapping ::= FLOW-MAPPING-START
|
438
|
+
# (flow_mapping_entry FLOW-ENTRY)*
|
439
|
+
# flow_mapping_entry?
|
440
|
+
# FLOW-MAPPING-END
|
441
|
+
# flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
442
|
+
events = []
|
443
|
+
token = get_token
|
444
|
+
start_mark = token.start_mark
|
445
|
+
while !check_token(FlowMappingEndToken)
|
446
|
+
if check_token(KeyToken)
|
447
|
+
token = get_token
|
448
|
+
if !check_token(ValueToken,FlowEntryToken, FlowMappingEndToken)
|
449
|
+
events += parse_flow_node
|
450
|
+
else
|
451
|
+
events << process_empty_scalar(token.end_mark)
|
452
|
+
end
|
453
|
+
if check_token(ValueToken)
|
454
|
+
token = get_token
|
455
|
+
if !check_token(FlowEntryToken, FlowMappingEndToken)
|
456
|
+
events += parse_flow_node
|
457
|
+
else
|
458
|
+
events << process_empty_scalar(token.end_mark)
|
459
|
+
end
|
460
|
+
else
|
461
|
+
token = peek_token
|
462
|
+
events << process_empty_scalar(token.start_mark)
|
463
|
+
end
|
464
|
+
else
|
465
|
+
events += parse_flow_node
|
466
|
+
events << process_empty_scalar(peek_token.start_mark)
|
467
|
+
end
|
468
|
+
if !check_token(FlowEntryToken, FlowMappingEndToken)
|
469
|
+
token = peek_token
|
470
|
+
raise ParserError.new("while scanning a flow mapping", start_mark,"expected ',' or '}', but got #{token.tid}", token.start_mark)
|
471
|
+
end
|
472
|
+
get_token if check_token(FlowEntryToken)
|
473
|
+
end
|
474
|
+
if !check_token(FlowMappingEndToken)
|
475
|
+
token = peek_token
|
476
|
+
raise ParserError.new("while scanning a flow mapping", start_mark,"expected '}', but found #{token.tid}", token.start_mark)
|
477
|
+
end
|
478
|
+
token = get_token
|
479
|
+
events << MappingEndEvent.new(token.start_mark, token.end_mark)
|
480
|
+
events
|
481
|
+
end
|
482
|
+
|
483
|
+
def process_empty_scalar(mark)
|
484
|
+
ScalarEvent.new(nil, nil, nil, "", mark, mark)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|