redsnow 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -0
  3. data/ext/snowcrash/Makefile +1 -1
  4. data/ext/snowcrash/bin/snowcrash +0 -0
  5. data/ext/snowcrash/configure +9 -9
  6. data/ext/snowcrash/ext/markdown-parser/Makefile +87 -0
  7. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/CONTRIBUTING.md +0 -0
  8. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/Makefile +2 -1
  9. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/Makefile.win +0 -0
  10. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/examples/smartypants.c +0 -0
  11. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/examples/sundown.c +0 -0
  12. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini.h +0 -0
  13. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini_href_e.c +0 -0
  14. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini_html_e.c +0 -0
  15. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html.c +0 -0
  16. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html.h +0 -0
  17. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html_smartypants.c +0 -0
  18. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html_block_names.txt +0 -0
  19. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/autolink.c +0 -0
  20. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/autolink.h +0 -0
  21. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/buffer.c +0 -0
  22. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/buffer.h +1 -1
  23. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/html_blocks.h +0 -0
  24. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/markdown.c +9 -3
  25. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/markdown.h +0 -0
  26. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/src_map.c +11 -7
  27. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/src_map.h +1 -1
  28. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/stack.c +0 -0
  29. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/stack.h +0 -0
  30. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/sundown.def +0 -0
  31. data/ext/snowcrash/ext/markdown-parser/msvc/markdown/markdown.vcproj +188 -0
  32. data/ext/snowcrash/ext/markdown-parser/msvc/msvc.sln +38 -0
  33. data/ext/snowcrash/ext/markdown-parser/msvc/sundown/sundown.vcproj +206 -0
  34. data/ext/snowcrash/ext/markdown-parser/src/ByteBuffer.cc +92 -0
  35. data/ext/snowcrash/ext/markdown-parser/src/ByteBuffer.h +82 -0
  36. data/ext/snowcrash/ext/markdown-parser/src/MarkdownNode.cc +152 -0
  37. data/ext/snowcrash/ext/markdown-parser/src/MarkdownNode.h +103 -0
  38. data/ext/snowcrash/ext/markdown-parser/src/MarkdownParser.cc +388 -0
  39. data/ext/snowcrash/{src → ext/markdown-parser/src}/MarkdownParser.h +43 -33
  40. data/ext/snowcrash/snowcrash.gyp +114 -63
  41. data/ext/snowcrash/src/ActionParser.h +334 -398
  42. data/ext/snowcrash/src/AssetParser.h +82 -171
  43. data/ext/snowcrash/src/Blueprint.h +7 -2
  44. data/ext/snowcrash/src/BlueprintParser.h +212 -286
  45. data/ext/snowcrash/src/BlueprintUtility.h +2 -2
  46. data/ext/snowcrash/src/CBlueprint.h +1 -1
  47. data/ext/snowcrash/src/CSourceAnnotation.cc +11 -11
  48. data/ext/snowcrash/src/CSourceAnnotation.h +9 -9
  49. data/ext/snowcrash/src/CodeBlockUtility.h +199 -149
  50. data/ext/snowcrash/src/HeadersParser.h +197 -0
  51. data/ext/snowcrash/src/ParameterParser.h +429 -0
  52. data/ext/snowcrash/src/ParametersParser.h +136 -211
  53. data/ext/snowcrash/src/PayloadParser.h +458 -562
  54. data/ext/snowcrash/src/Platform.h +0 -3
  55. data/ext/snowcrash/src/ResourceGroupParser.h +183 -164
  56. data/ext/snowcrash/src/ResourceParser.h +325 -493
  57. data/ext/snowcrash/src/Section.cc +42 -0
  58. data/ext/snowcrash/src/Section.h +47 -0
  59. data/ext/snowcrash/src/SectionParser.h +229 -0
  60. data/ext/snowcrash/src/SectionParserData.h +81 -0
  61. data/ext/snowcrash/src/SectionProcessor.h +211 -0
  62. data/ext/snowcrash/src/Signature.cc +74 -0
  63. data/ext/snowcrash/src/Signature.h +32 -0
  64. data/ext/snowcrash/src/SourceAnnotation.h +7 -20
  65. data/ext/snowcrash/src/StringUtility.h +30 -10
  66. data/ext/snowcrash/src/SymbolTable.h +7 -7
  67. data/ext/snowcrash/src/UriTemplateParser.cc +10 -10
  68. data/ext/snowcrash/src/UriTemplateParser.h +11 -14
  69. data/ext/snowcrash/src/ValuesParser.h +122 -0
  70. data/ext/snowcrash/src/Version.h +2 -2
  71. data/ext/snowcrash/src/csnowcrash.cc +5 -5
  72. data/ext/snowcrash/src/csnowcrash.h +3 -3
  73. data/ext/snowcrash/src/snowcrash.cc +74 -4
  74. data/ext/snowcrash/src/snowcrash.h +9 -4
  75. data/ext/snowcrash/src/snowcrash/snowcrash.cc +16 -16
  76. data/ext/snowcrash/tools/homebrew/snowcrash.rb +3 -2
  77. data/ext/snowcrash/vcbuild.bat +13 -4
  78. data/lib/redsnow.rb +5 -5
  79. data/lib/redsnow/binding.rb +1 -1
  80. data/lib/redsnow/blueprint.rb +33 -2
  81. data/lib/redsnow/parseresult.rb +7 -4
  82. data/lib/redsnow/version.rb +1 -1
  83. data/test/redsnow_binding_test.rb +6 -6
  84. data/test/redsnow_parseresult_test.rb +1 -1
  85. metadata +62 -42
  86. data/ext/snowcrash/src/BlockUtility.h +0 -186
  87. data/ext/snowcrash/src/BlueprintParserCore.h +0 -190
  88. data/ext/snowcrash/src/BlueprintSection.h +0 -140
  89. data/ext/snowcrash/src/DescriptionSectionUtility.h +0 -156
  90. data/ext/snowcrash/src/HeaderParser.h +0 -289
  91. data/ext/snowcrash/src/ListBlockUtility.h +0 -273
  92. data/ext/snowcrash/src/ListUtility.h +0 -95
  93. data/ext/snowcrash/src/MarkdownBlock.cc +0 -176
  94. data/ext/snowcrash/src/MarkdownBlock.h +0 -93
  95. data/ext/snowcrash/src/MarkdownParser.cc +0 -266
  96. data/ext/snowcrash/src/ParameterDefinitonParser.h +0 -645
  97. data/ext/snowcrash/src/Parser.cc +0 -71
  98. data/ext/snowcrash/src/Parser.h +0 -29
  99. data/ext/snowcrash/src/ParserCore.cc +0 -120
  100. data/ext/snowcrash/src/ParserCore.h +0 -82
  101. data/ext/snowcrash/src/SectionUtility.h +0 -142
@@ -17,17 +17,14 @@
17
17
  #endif
18
18
 
19
19
  #if defined(_MSC_VER)
20
- # define FORCEINLINE __forceinline
21
20
  # if !defined(DEPRECATED)
22
21
  # define DEPRECATED __declspec(deprecated)
23
22
  # endif
24
23
  #elif defined(__clang__) || defined(__GNUC__)
25
- # define FORCEINLINE inline
26
24
  # if !defined(DEPRECATED)
27
25
  # define DEPRECATED __attribute__((deprecated))
28
26
  # endif
29
27
  #else
30
- # define FORCEINLINE inline
31
28
  # if !defined(DEPRECATED)
32
29
  # define DEPRECATED
33
30
  # endif
@@ -9,187 +9,206 @@
9
9
  #ifndef SNOWCRASH_RESOURCEGROUPPARSER_H
10
10
  #define SNOWCRASH_RESOURCEGROUPPARSER_H
11
11
 
12
- #include "BlueprintParserCore.h"
13
- #include "Blueprint.h"
12
+ #include "SectionParser.h"
14
13
  #include "ResourceParser.h"
14
+ #include "RegexMatch.h"
15
+
16
+ namespace snowcrash {
15
17
 
16
- namespace snowcrashconst {
17
-
18
18
  const char* const GroupHeaderRegex = "^[[:blank:]]*[Gg]roup[[:blank:]]+" SYMBOL_IDENTIFIER "[[:blank:]]*$";
19
- }
20
19
 
21
- namespace snowcrash {
22
-
23
- /**
24
- * \brief Find a group in the blueprint by the group name.
25
- * \param blueprint A blueprint AST to be searched.
26
- * \param group A resource group to look for.
27
- * \returns An iterator at matching group within blueprint's resource groups collection.
28
- */
29
- FORCEINLINE Collection<ResourceGroup>::const_iterator FindResourceGroup(const Blueprint& blueprint,
30
- const ResourceGroup& group) {
31
-
32
- return std::find_if(blueprint.resourceGroups.begin(),
33
- blueprint.resourceGroups.end(),
34
- std::bind2nd(MatchName<ResourceGroup>(), group));
35
- }
36
-
37
- /**
38
- * \brief Check a markdown block of Group signature, also retrieves a group name.
39
- * \param block A markdown block to query for its signature and retrieve a group name from.
40
- * \param name An output buffer to retrieve a Resource Group Name into.
41
- * \returns True if the given markdown block has Resource group signature, false otherwise.
42
- */
43
- FORCEINLINE bool GetResourceGroupSignature(const MarkdownBlock& block,
44
- Name& name) {
45
- if (block.type != HeaderBlockType ||
46
- block.content.empty())
47
- return false;
48
-
49
- CaptureGroups captureGroups;
50
- if (RegexCapture(block.content, snowcrashconst::GroupHeaderRegex, captureGroups, 3)) {
51
- name = captureGroups[1];
52
- return true;
53
- }
54
-
55
- return false;
56
- }
57
-
20
+ /** Resource iterator pair: its containment group and resource iterator itself */
21
+ typedef std::pair<Collection<ResourceGroup>::const_iterator, ResourceIterator> ResourceIteratorPair;
22
+
23
+ /** Internal type alias for Collection of Resource */
24
+ typedef Collection<ResourceGroup>::type ResourceGroups;
25
+
26
+ typedef Collection<ResourceGroup>::const_iterator ResourceGroupIterator;
27
+
58
28
  /**
59
- * \brief Query whether given block has resource group signature.
60
- * \param block A markdown block to query its signature
61
- * \returns True if the given markdown block has Resource group signature, false otherwise.
29
+ * ResourceGroup Section processor
62
30
  */
63
- FORCEINLINE bool HasResourceGroupSignature(const MarkdownBlock& block)
64
- {
65
- Name name;
66
- return GetResourceGroupSignature(block, name);
67
- }
68
-
69
- /** Internal list items classifier, Resource Group Context */
70
- template <>
71
- FORCEINLINE SectionType ClassifyInternaListBlock<ResourceGroup>(const BlockIterator& begin,
72
- const BlockIterator& end) {
73
- return UndefinedSectionType;
74
- }
75
-
76
- /** Block Classifier, Resource Group Context */
77
- template <>
78
- FORCEINLINE SectionType ClassifyBlock<ResourceGroup>(const BlockIterator& begin,
79
- const BlockIterator& end,
80
- const SectionType& context) {
81
-
82
- if (HasResourceGroupSignature(*begin))
83
- return (context == UndefinedSectionType) ? ResourceGroupSectionType : UndefinedSectionType;
84
-
85
- if (HasResourceSignature(*begin))
86
- return ResourceSectionType;
87
-
88
- return (context == ResourceGroupSectionType) ? context : UndefinedSectionType;
89
- }
90
-
91
- /** Resource Group SectionType Parser */
92
31
  template<>
93
- struct SectionParser<ResourceGroup> {
94
-
95
- static ParseSectionResult ParseSection(const BlueprintSection& section,
96
- const BlockIterator& cur,
97
- BlueprintParserCore& parser,
98
- ResourceGroup& group) {
99
-
100
- ParseSectionResult result = std::make_pair(Result(), cur);
101
- switch (section.type) {
102
-
103
- case ResourceGroupSectionType:
104
- result = HandleResourceGroupOverviewBlock(section, cur, parser, group);
105
- break;
106
-
107
- case ResourceSectionType:
108
- result = HandleResource(section, cur, parser, group);
109
- break;
110
-
111
- case UndefinedSectionType:
112
- break;
113
-
114
- default:
115
- result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
116
- break;
32
+ struct SectionProcessor<ResourceGroup> : public SectionProcessorBase<ResourceGroup> {
33
+
34
+ static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
35
+ const MarkdownNodes& siblings,
36
+ SectionParserData& pd,
37
+ SectionLayout& layout,
38
+ Report& report,
39
+ ResourceGroup& out) {
40
+
41
+ MarkdownNodeIterator cur = node;
42
+ SectionType nestedType = nestedSectionType(cur);
43
+
44
+ // Resources only, parse as exclusive nested sections
45
+ if (nestedType != UndefinedSectionType) {
46
+ layout = ExclusiveNestedSectionLayout;
47
+ return cur;
48
+ }
49
+
50
+ CaptureGroups captureGroups;
51
+
52
+ if (RegexCapture(node->text, GroupHeaderRegex, captureGroups, 3)) {
53
+ out.name = captureGroups[1];
54
+ TrimString(out.name);
117
55
  }
118
-
119
- return result;
56
+
57
+ return ++MarkdownNodeIterator(node);
120
58
  }
121
59
 
122
- static void Finalize(const SectionBounds& bounds,
123
- BlueprintParserCore& parser,
124
- ResourceGroup& group,
125
- Result& result) {}
126
-
127
- static ParseSectionResult HandleResourceGroupOverviewBlock(const BlueprintSection& section,
128
- const BlockIterator& cur,
129
- BlueprintParserCore& parser,
130
- ResourceGroup& group) {
131
-
132
- ParseSectionResult result = std::make_pair(Result(), cur);
133
- BlockIterator sectionCur(cur);
134
-
135
- // Group Name
136
- if (sectionCur == section.bounds.first) {
137
-
138
- GetResourceGroupSignature(*cur, group.name);
139
- result.second = ++sectionCur;
140
- return result;
60
+ static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
61
+ const MarkdownNodes& siblings,
62
+ SectionParserData& pd,
63
+ Report& report,
64
+ ResourceGroup& out) {
65
+
66
+ if (pd.sectionContext() == ResourceSectionType) {
67
+
68
+ Resource resource;
69
+ MarkdownNodeIterator cur = ResourceParser::parse(node, siblings, pd, report, resource);
70
+
71
+ ResourceIterator duplicate = findResource(out.resources, resource);
72
+ ResourceIteratorPair globalDuplicate;
73
+
74
+ if (duplicate == out.resources.end()) {
75
+ globalDuplicate = findResource(pd.blueprint, resource);
76
+ }
77
+
78
+ if (duplicate != out.resources.end() ||
79
+ globalDuplicate.first != pd.blueprint.resourceGroups.end()) {
80
+
81
+ // WARN: Duplicate resource
82
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
83
+ report.warnings.push_back(Warning("the resource '" + resource.uriTemplate + "' is already defined",
84
+ DuplicateWarning,
85
+ sourceMap));
86
+ }
87
+
88
+ out.resources.push_back(resource);
89
+
90
+ return cur;
141
91
  }
142
-
143
- // Group Description
144
- result = ParseDescriptionBlock<ResourceGroup>(section,
145
- sectionCur,
146
- parser.sourceData,
147
- group);
148
- return result;
149
-
92
+
93
+ return node;
150
94
  }
151
-
152
- static ParseSectionResult HandleResource(const BlueprintSection& section,
153
- const BlockIterator& cur,
154
- BlueprintParserCore& parser,
155
- ResourceGroup& group)
156
- {
157
- Resource resource;
158
- ParseSectionResult result = ResourceParser::Parse(cur,
159
- section.bounds.second,
160
- section,
161
- parser,
162
- resource);
163
- if (result.first.error.code != Error::OK)
164
- return result;
165
-
166
- ResourceIterator duplicate = FindResource(group, resource);
167
- ResourceIteratorPair globalDuplicate;
168
- if (duplicate == group.resources.end())
169
- globalDuplicate = FindResource(parser.blueprint, resource);
170
-
171
-
172
-
173
- if (duplicate != group.resources.end() ||
174
- globalDuplicate.first != parser.blueprint.resourceGroups.end()) {
175
-
176
- // WARN: Duplicate resource
177
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
178
- result.first.warnings.push_back(Warning("the resource '" +
179
- resource.uriTemplate +
180
- "' is already defined",
181
- DuplicateWarning,
182
- sourceBlock));
95
+
96
+ static MarkdownNodeIterator processUnexpectedNode(const MarkdownNodeIterator& node,
97
+ const MarkdownNodes& siblings,
98
+ SectionParserData& pd,
99
+ SectionType& lastSectionType,
100
+ Report& report,
101
+ ResourceGroup& out) {
102
+
103
+ if (SectionProcessor<Action>::actionType(node) == DependentActionType &&
104
+ !out.resources.empty()) {
105
+
106
+ mdp::ByteBuffer method;
107
+ mdp::ByteBuffer name;
108
+
109
+ SectionProcessor<Action>::actionHTTPMethodAndName(node, method, name);
110
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
111
+
112
+ // WARN: Unexpected action
113
+ std::stringstream ss;
114
+ ss << "unexpected action '" << method << "', to define multiple actions for the '" << out.resources.back().uriTemplate;
115
+ ss << "' resource omit the HTTP method in its definition, e.g. '# /resource'";
116
+
117
+ report.warnings.push_back(Warning(ss.str(),
118
+ IgnoringWarning,
119
+ sourceMap));
120
+
121
+ return ++MarkdownNodeIterator(node);
183
122
  }
184
123
 
124
+ return SectionProcessorBase<ResourceGroup>::processUnexpectedNode(node, siblings, pd, lastSectionType, report, out);
125
+ }
126
+
127
+ static SectionType sectionType(const MarkdownNodeIterator& node) {
128
+
129
+ if (node->type == mdp::HeaderMarkdownNodeType
130
+ && !node->text.empty()) {
131
+
132
+ mdp::ByteBuffer subject = node->text;
133
+ TrimString(subject);
134
+
135
+ if (RegexMatch(subject, GroupHeaderRegex)) {
136
+ return ResourceGroupSectionType;
137
+ }
138
+ }
139
+
140
+ return UndefinedSectionType;
141
+ }
142
+
143
+ static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
144
+
145
+ // Return ResourceSectionType or UndefinedSectionType
146
+ return SectionProcessor<Resource>::sectionType(node);
147
+ }
148
+
149
+ static SectionTypes nestedSectionTypes() {
150
+ SectionTypes nested;
151
+
152
+ // Resource & descendants
153
+ nested.push_back(ResourceSectionType);
154
+ SectionTypes types = SectionProcessor<Resource>::nestedSectionTypes();
155
+ nested.insert(nested.end(), types.begin(), types.end());
156
+
157
+ return nested;
158
+ }
159
+
160
+ static bool isDescriptionNode(const MarkdownNodeIterator& node,
161
+ SectionType sectionType) {
162
+
163
+ mdp::ByteBuffer method;
185
164
 
186
-
187
- group.resources.push_back(resource); // FIXME: C++11 move
188
- return result;
165
+ if (SectionProcessor<Action>::actionType(node) == CompleteActionType) {
166
+ return false;
167
+ }
168
+
169
+ return SectionProcessorBase<ResourceGroup>::isDescriptionNode(node, sectionType);
170
+ }
171
+
172
+ static bool isUnexpectedNode(const MarkdownNodeIterator& node,
173
+ SectionType sectionType) {
174
+
175
+ if (SectionProcessor<Action>::actionType(node) == DependentActionType) {
176
+ return true;
177
+ }
178
+
179
+ return SectionProcessorBase<ResourceGroup>::isUnexpectedNode(node, sectionType);
180
+ }
181
+
182
+ /** Finds a resource inside an resources collection */
183
+ static ResourceIterator findResource(const Resources& resources,
184
+ const Resource& resource) {
185
+
186
+ return std::find_if(resources.begin(),
187
+ resources.end(),
188
+ std::bind2nd(MatchResource(), resource));
189
+ }
190
+
191
+ /** Finds a resource in blueprint by its URI template */
192
+ static ResourceIteratorPair findResource(const Blueprint& blueprint,
193
+ const Resource& resource) {
194
+
195
+ for (Collection<ResourceGroup>::const_iterator it = blueprint.resourceGroups.begin();
196
+ it != blueprint.resourceGroups.end();
197
+ ++it) {
198
+
199
+ ResourceIterator match = findResource(it->resources, resource);
200
+
201
+ if (match != it->resources.end()) {
202
+ return std::make_pair(it, match);
203
+ }
204
+ }
205
+
206
+ return std::make_pair(blueprint.resourceGroups.end(), ResourceIterator());
189
207
  }
190
208
  };
191
-
192
- typedef BlockParser<ResourceGroup, SectionParser<ResourceGroup> > ResourceGroupParser;
209
+
210
+ /** ResourceGroup Section Parser */
211
+ typedef SectionParser<ResourceGroup, HeaderSectionAdapter> ResourceGroupParser;
193
212
  }
194
213
 
195
214
  #endif
@@ -9,576 +9,408 @@
9
9
  #ifndef SNOWCRASH_RESOURCEPARSER_H
10
10
  #define SNOWCRASH_RESOURCEPARSER_H
11
11
 
12
- #include <sstream>
13
- #include "BlueprintParserCore.h"
14
- #include "Blueprint.h"
12
+ #include "SectionParser.h"
15
13
  #include "ActionParser.h"
16
- #include "RegexMatch.h"
17
- #include "StringUtility.h"
14
+ #include "HeadersParser.h"
18
15
  #include "ParametersParser.h"
19
- #include "DescriptionSectionUtility.h"
20
16
  #include "UriTemplateParser.h"
17
+ #include "RegexMatch.h"
21
18
 
22
- namespace snowcrashconst {
19
+ namespace snowcrash {
23
20
 
24
21
  /** Nameless resource matching regex */
25
22
  const char* const ResourceHeaderRegex = "^[[:blank:]]*(" HTTP_REQUEST_METHOD "[[:blank:]]+)?" URI_TEMPLATE "$";
26
23
 
27
24
  /** Named resource matching regex */
28
25
  const char* const NamedResourceHeaderRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "[[:blank:]]+\\[" URI_TEMPLATE "]$";
29
- }
30
26
 
31
- namespace snowcrash {
32
-
33
- // Resource signature
34
- enum ResourceSignature {
35
- UndefinedResourceSignature,
36
- NoResourceSignature,
37
- URIResourceSignature,
38
- MethodURIResourceSignature,
39
- NamedResourceSignature
40
- };
41
-
42
- // Query resource signature
43
- FORCEINLINE ResourceSignature GetResourceSignature(const MarkdownBlock& block,
44
- Name& name,
45
- URITemplate& uri,
46
- HTTPMethod& method) {
47
- if (block.type != HeaderBlockType ||
48
- block.content.empty())
49
- return NoResourceSignature;
50
-
51
- CaptureGroups captureGroups;
52
- // Nameless resource
53
- if (RegexCapture(block.content, snowcrashconst::ResourceHeaderRegex, captureGroups, 4)) {
54
- method = captureGroups[2];
55
- uri = captureGroups[3];
56
- return (method.empty()) ? URIResourceSignature : MethodURIResourceSignature;
57
- }
58
- else if (RegexCapture(block.content, snowcrashconst::NamedResourceHeaderRegex, captureGroups, 4)) {
59
- method.clear();
60
- name = captureGroups[1];
61
- TrimString(name);
62
- uri = captureGroups[2];
63
- return NamedResourceSignature;
64
- }
27
+ /** Internal type alias for Collection of Resource */
28
+ typedef Collection<Resource>::type Resources;
65
29
 
66
- return NoResourceSignature;
67
- }
68
-
69
- // Returns true if block has resource header signature, false otherwise
70
- FORCEINLINE bool HasResourceSignature(const MarkdownBlock& block) {
30
+ typedef Collection<Resource>::const_iterator ResourceIterator;
71
31
 
72
- Name name;
73
- URITemplate uri;
74
- HTTPMethod method;
75
- return GetResourceSignature(block, name, uri, method) != NoResourceSignature;
76
- }
32
+ /**
33
+ * Resource Section processor
34
+ */
35
+ template<>
36
+ struct SectionProcessor<Resource> : public SectionProcessorBase<Resource> {
77
37
 
78
- // Resource iterator in its containment group
79
- typedef Collection<Resource>::const_iterator ResourceIterator;
80
-
81
- // Finds a resource in resource group by its URI template
82
- FORCEINLINE ResourceIterator FindResource(const ResourceGroup& group,
83
- const Resource& resource) {
84
- return std::find_if(group.resources.begin(),
85
- group.resources.end(),
86
- std::bind2nd(MatchResource(), resource));
87
- }
88
-
89
- // Resource iterator pair: its containment group and resource iterator itself
90
- typedef std::pair<Collection<ResourceGroup>::const_iterator, ResourceIterator> ResourceIteratorPair;
91
-
92
- // Finds a resource in blueprint by its URI template
93
- FORCEINLINE ResourceIteratorPair FindResource(const Blueprint& blueprint,
94
- const Resource& resource) {
95
-
96
- for (Collection<ResourceGroup>::const_iterator it = blueprint.resourceGroups.begin();
97
- it != blueprint.resourceGroups.end();
98
- ++it) {
99
-
100
- Collection<Resource>::const_iterator match = FindResource(*it, resource);
101
- if (match != it->resources.end())
102
- return std::make_pair(it, match);
103
- }
104
-
105
- return std::make_pair(blueprint.resourceGroups.end(), Collection<Resource>::iterator());
106
- }
107
-
108
-
109
- //
110
- // Classifier of internal list items, Resource context
111
- //
112
- template <>
113
- FORCEINLINE SectionType ClassifyInternaListBlock<Resource>(const BlockIterator& begin,
114
- const BlockIterator& end) {
115
- if (HasHeaderSignature(begin, end))
116
- return HeadersSectionType;
117
-
118
- if (HasParametersSignature(begin, end))
119
- return ParametersSectionType;
120
-
121
- Name name;
122
- SourceData mediaType;
123
- PayloadSignature payloadSignature = GetPayloadSignature(begin, end, name, mediaType);
124
- if (payloadSignature == ObjectPayloadSignature)
125
- return ObjectSectionType;
126
- else if (payloadSignature == ModelPayloadSignature)
127
- return ModelSectionType;
128
-
129
- return UndefinedSectionType;
130
- }
131
-
132
- /** Children blocks classifier */
133
- template <>
134
- FORCEINLINE SectionType ClassifyChildrenListBlock<Resource>(const BlockIterator& begin,
135
- const BlockIterator& end) {
136
-
137
- SectionType type = ClassifyInternaListBlock<Resource>(begin, end);
138
- if (type != UndefinedSectionType)
139
- return type;
140
-
141
- type = ClassifyChildrenListBlock<HeaderCollection>(begin, end);
142
- if (type != UndefinedSectionType)
143
- return type;
144
-
145
- type = ClassifyChildrenListBlock<ParameterCollection>(begin, end);
146
- if (type != UndefinedSectionType)
147
- return type;
148
-
149
- type = ClassifyChildrenListBlock<Payload>(begin, end);
150
- if (type != UndefinedSectionType)
151
- return type;
152
-
153
- return UndefinedSectionType;
154
- }
155
-
156
- //
157
- // Block Classifier, Resource Context
158
- //
159
- template <>
160
- FORCEINLINE SectionType ClassifyBlock<Resource>(const BlockIterator& begin,
161
- const BlockIterator& end,
162
- const SectionType& context) {
163
- if (HasResourceGroupSignature(*begin))
164
- return UndefinedSectionType;
38
+ static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
39
+ const MarkdownNodes& siblings,
40
+ SectionParserData& pd,
41
+ SectionLayout& layout,
42
+ Report& report,
43
+ Resource& out) {
44
+
45
+ CaptureGroups captureGroups;
46
+
47
+ // If Abbreviated resource section
48
+ if (RegexCapture(node->text, ResourceHeaderRegex, captureGroups, 4)) {
49
+
50
+ out.uriTemplate = captureGroups[3];
51
+
52
+ // Make this section an action
53
+ if (!captureGroups[2].empty()) {
165
54
 
166
- Name name;
167
- URITemplate uri;
168
- HTTPMethod method;
169
- ResourceSignature resourceSignature = GetResourceSignature(*begin, name, uri, method);
170
- if (resourceSignature != NoResourceSignature) {
171
- return (context == UndefinedSectionType) ?
172
- ((resourceSignature == MethodURIResourceSignature) ? ResourceMethodSectionType : ResourceSectionType) :
173
- UndefinedSectionType;
55
+ Action action;
56
+ MarkdownNodeIterator cur = ActionParser::parse(node, node->parent().children(), pd, report, action);
57
+
58
+ out.actions.push_back(action);
59
+ layout = RedirectSectionLayout;
60
+
61
+ return cur;
62
+ }
63
+ } else if (RegexCapture(node->text, NamedResourceHeaderRegex, captureGroups, 4)) {
64
+
65
+ out.name = captureGroups[1];
66
+ TrimString(out.name);
67
+ out.uriTemplate = captureGroups[2];
68
+ }
69
+
70
+ return ++MarkdownNodeIterator(node);
174
71
  }
175
-
176
- if (HasActionSignature(*begin))
177
- return (context != ResourceMethodSectionType) ? ActionSectionType : UndefinedSectionType;
178
-
179
- SectionType listSection = ClassifyInternaListBlock<Resource>(begin, end);
180
- if (listSection != UndefinedSectionType)
181
- return listSection;
182
-
183
- // Unrecognized list item at this level
184
- if (begin->type == ListItemBlockBeginType)
185
- return ForeignSectionType;
186
-
187
- return (context == ResourceSectionType) ? context : UndefinedSectionType;
188
- }
189
-
190
- //
191
- // Resource SectionType Parser
192
- //
193
- template<>
194
- struct SectionParser<Resource> {
195
-
196
- static ParseSectionResult ParseSection(const BlueprintSection& section,
197
- const BlockIterator& cur,
198
- BlueprintParserCore& parser,
199
- Resource& resource) {
200
- ParseSectionResult result = std::make_pair(Result(), cur);
201
-
202
- switch (section.type) {
203
- case ResourceSectionType:
204
- result = HandleResourceDescriptionBlock(section, cur, parser, resource);
205
- break;
206
-
207
- case ResourceMethodSectionType:
208
- result = HandleResourceMethod(section, cur, parser, resource);
209
- break;
210
-
211
- case ModelSectionType:
212
- case ObjectSectionType:
213
- result = HandleModel(section, cur, parser, resource);
214
- break;
215
-
72
+
73
+ static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
74
+ const MarkdownNodes& siblings,
75
+ SectionParserData& pd,
76
+ Report& report,
77
+ Resource& out) {
78
+
79
+ switch (pd.sectionContext()) {
80
+ case ActionSectionType:
81
+ return processAction(node, siblings, pd, report, out);
82
+
216
83
  case ParametersSectionType:
217
- result = HandleParameters(section, cur, parser, resource);
218
- break;
219
-
84
+ return processParameters(node, siblings, pd, report, out);
85
+
86
+ case ModelSectionType:
87
+ case ModelBodySectionType:
88
+ return processModel(node, siblings, pd, report, out);
89
+
220
90
  case HeadersSectionType:
221
- result = HandleDeprecatedHeaders(section, cur, parser, resource);
222
- break;
223
-
224
- case ActionSectionType:
225
- result = HandleAction(section, cur, parser, resource);
226
- break;
227
-
228
- case UndefinedSectionType:
229
- CheckAmbiguousMethod(section, cur, resource, parser.sourceData, result.first);
230
- result.second = CloseList(cur, section.bounds.second);
231
- break;
232
-
233
- case ForeignSectionType:
234
- result = HandleForeignSection<Resource>(section, cur, parser.sourceData);
235
- break;
236
-
91
+ return SectionProcessor<Action>::handleDeprecatedHeaders(node, siblings, pd, report, out.headers);
92
+
237
93
  default:
238
- result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
239
94
  break;
240
95
  }
241
96
 
97
+ return node;
98
+ }
99
+
100
+ static MarkdownNodeIterator processUnexpectedNode(const MarkdownNodeIterator& node,
101
+ const MarkdownNodes& siblings,
102
+ SectionParserData& pd,
103
+ SectionType& sectionType,
104
+ Report& report,
105
+ Resource& out) {
242
106
 
243
- return result;
107
+ if ((node->type == mdp::ParagraphMarkdownNodeType ||
108
+ node->type == mdp::CodeMarkdownNodeType) &&
109
+ (sectionType == ModelBodySectionType ||
110
+ sectionType == ModelSectionType)) {
111
+
112
+ CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.model.body);
113
+
114
+ // Update model in the symbol table as well
115
+ ResourceModelSymbolTable::iterator it = pd.symbolTable.resourceModels.find(out.model.name);
116
+
117
+ if (it != pd.symbolTable.resourceModels.end()) {
118
+ it->second.body = out.model.body;
119
+ }
120
+
121
+ return ++MarkdownNodeIterator(node);
122
+ }
123
+
124
+ return SectionProcessorBase<Resource>::processUnexpectedNode(node, siblings, pd, sectionType, report, out);
244
125
  }
245
126
 
246
- static void Finalize(const SectionBounds& bounds,
247
- BlueprintParserCore& parser,
248
- Resource& resource,
249
- Result& result)
250
- {
127
+ static bool isDescriptionNode(const MarkdownNodeIterator& node,
128
+ SectionType sectionType) {
129
+
130
+ if (SectionProcessor<Action>::actionType(node) == CompleteActionType) {
131
+ return false;
132
+ }
133
+
134
+ return SectionProcessorBase<Resource>::isDescriptionNode(node, sectionType);
135
+ }
136
+
137
+ static SectionType sectionType(const MarkdownNodeIterator& node) {
138
+
139
+ if (node->type == mdp::HeaderMarkdownNodeType
140
+ && !node->text.empty()) {
141
+
142
+ CaptureGroups captureGroups;
143
+ mdp::ByteBuffer subject = node->text;
144
+
145
+ TrimString(subject);
146
+
147
+ if (RegexMatch(subject, NamedResourceHeaderRegex) ||
148
+ RegexMatch(subject, ResourceHeaderRegex)) {
149
+ return ResourceSectionType;
150
+ }
151
+ }
152
+
153
+ return UndefinedSectionType;
154
+ }
155
+
156
+ static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
157
+
158
+ SectionType nestedType = UndefinedSectionType;
159
+
160
+ // Check if parameters section
161
+ nestedType = SectionProcessor<Parameters>::sectionType(node);
162
+
163
+ if (nestedType != UndefinedSectionType) {
164
+ return nestedType;
165
+ }
166
+
167
+ // Check if headers section
168
+ nestedType = SectionProcessor<Headers>::sectionType(node);
169
+
170
+ if (nestedType == HeadersSectionType) {
171
+ return nestedType;
172
+ }
173
+
174
+ // Check if model section
175
+ nestedType = SectionProcessor<Payload>::sectionType(node);
176
+
177
+ if (nestedType == ModelSectionType ||
178
+ nestedType == ModelBodySectionType) {
179
+
180
+ return nestedType;
181
+ }
182
+
183
+ // Check if action section
184
+ nestedType = SectionProcessor<Action>::sectionType(node);
185
+
186
+ if (nestedType == ActionSectionType) {
187
+
188
+ // Do not consider complete actions as nested
189
+ mdp::ByteBuffer method;
190
+ if (SectionProcessor<Action>::actionType(node) == CompleteActionType)
191
+ return UndefinedSectionType;
192
+
193
+ return nestedType;
194
+ }
195
+
196
+ return UndefinedSectionType;
197
+ }
198
+
199
+ static SectionTypes nestedSectionTypes() {
200
+ SectionTypes nested;
201
+
202
+ // Action & descendants
203
+ nested.push_back(ActionSectionType);
204
+ SectionTypes types = SectionProcessor<Action>::nestedSectionTypes();
205
+ nested.insert(nested.end(), types.begin(), types.end());
206
+
207
+ nested.push_back(ModelSectionType);
208
+ nested.push_back(ModelBodySectionType);
209
+
210
+ return nested;
211
+ }
212
+
213
+ static void finalize(const MarkdownNodeIterator& node,
214
+ SectionParserData& pd,
215
+ Report& report,
216
+ Resource& out) {
217
+
218
+ if (!out.uriTemplate.empty()) {
251
219
 
252
- if (!resource.uriTemplate.empty()) {
253
220
  URITemplateParser uriTemplateParser;
254
221
  ParsedURITemplate parsedResult;
255
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(bounds.first, bounds.first, bounds, parser.sourceData);
222
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
223
+
224
+ uriTemplateParser.parse(out.uriTemplate, sourceMap, parsedResult);
256
225
 
257
- uriTemplateParser.parse(resource.uriTemplate, sourceBlock, parsedResult);
258
- if (parsedResult.result.warnings.size() > 0) {
259
- result += parsedResult.result;
226
+ if (!parsedResult.report.warnings.empty()) {
227
+ report += parsedResult.report;
260
228
  }
261
229
  }
262
230
 
263
231
  // Consolidate depraceted headers into subsequent payloads
264
- if (!resource.headers.empty()) {
265
- for (Collection<Action>::iterator it = resource.actions.begin();
266
- it != resource.actions.end();
232
+ if (!out.headers.empty()) {
233
+
234
+ for (Collection<Action>::iterator it = out.actions.begin();
235
+ it != out.actions.end();
267
236
  ++it) {
268
- InjectDeprecatedHeaders(resource.headers, it->examples);
237
+
238
+ SectionProcessor<Headers>::injectDeprecatedHeaders(out.headers, it->examples);
269
239
  }
270
-
271
- resource.headers.clear();
240
+
241
+ out.headers.clear();
272
242
  }
243
+ }
244
+
245
+ /** Process Action section */
246
+ static MarkdownNodeIterator processAction(const MarkdownNodeIterator& node,
247
+ const MarkdownNodes& siblings,
248
+ SectionParserData& pd,
249
+ Report& report,
250
+ Resource& out) {
251
+
252
+ Action action;
253
+ MarkdownNodeIterator cur = ActionParser::parse(node, siblings, pd, report, action);
273
254
 
255
+ ActionIterator duplicate = findAction(out.actions, action);
256
+
257
+ if (duplicate != out.actions.end()) {
258
+
259
+ // WARN: duplicate method
260
+ std::stringstream ss;
261
+ ss << "action with method '" << action.method << "' already defined for resource '";
262
+ ss << out.uriTemplate << "'";
263
+
264
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
265
+ report.warnings.push_back(Warning(ss.str(),
266
+ DuplicateWarning,
267
+ sourceMap));
268
+ }
269
+
270
+ if (!action.parameters.empty()) {
271
+
272
+ checkParametersEligibility(node, pd, out, action.parameters, report);
273
+ }
274
+
275
+ out.actions.push_back(action);
276
+
277
+ return cur;
274
278
  }
275
-
276
- static ParseSectionResult HandleResourceDescriptionBlock(const BlueprintSection& section,
277
- const BlockIterator& cur,
278
- BlueprintParserCore& parser,
279
- Resource& resource) {
280
-
281
- ParseSectionResult result = std::make_pair(Result(), cur);
282
- BlockIterator sectionCur(cur);
283
-
284
- // Retrieve URI
285
- if (cur->type == HeaderBlockType &&
286
- cur == section.bounds.first) {
287
-
288
- HTTPMethod method;
289
- GetResourceSignature(*cur, resource.name, resource.uriTemplate, method);
290
- result.second = ++sectionCur;
291
- return result;
279
+
280
+ /** Process Parameters section */
281
+ static MarkdownNodeIterator processParameters(const MarkdownNodeIterator& node,
282
+ const MarkdownNodes& siblings,
283
+ SectionParserData& pd,
284
+ Report& report,
285
+ Resource& out) {
286
+
287
+ Parameters parameters;
288
+ MarkdownNodeIterator cur = ParametersParser::parse(node, siblings, pd, report, parameters);
289
+
290
+ if (!parameters.empty()) {
291
+
292
+ checkParametersEligibility(node, pd, out, parameters, report);
293
+ out.parameters.insert(out.parameters.end(), parameters.begin(), parameters.end());
292
294
  }
293
295
 
294
- result = ParseDescriptionBlock<Resource>(section,
295
- sectionCur,
296
- parser.sourceData,
297
- resource);
298
- return result;
296
+ return cur;
299
297
  }
300
-
301
- static ParseSectionResult HandleModel(const BlueprintSection& section,
302
- const BlockIterator& cur,
303
- BlueprintParserCore& parser,
304
- Resource& resource)
305
- {
306
- Payload payload;
307
- ParseSectionResult result = PayloadParser::Parse(cur,
308
- section.bounds.second,
309
- section,
310
- parser,
311
- payload);
312
- if (result.first.error.code != Error::OK)
313
- return result;
314
-
315
- // Check whether there isnt a model already
316
- if (!resource.model.name.empty()) {
298
+
299
+ /** Process Model section */
300
+ static MarkdownNodeIterator processModel(const MarkdownNodeIterator& node,
301
+ const MarkdownNodes& siblings,
302
+ SectionParserData& pd,
303
+ Report& report,
304
+ Resource& out) {
305
+
306
+ Payload model;
307
+ MarkdownNodeIterator cur = PayloadParser::parse(node, siblings, pd, report, model);
308
+
309
+ // Check whether there isn't a model already
310
+ if (!out.model.name.empty()) {
317
311
 
318
312
  // WARN: Model already defined
319
313
  std::stringstream ss;
320
- ss << "overshadowing previous model definiton for '";
314
+ ss << "overshadowing previous model definition for '";
321
315
 
322
- if (!resource.name.empty())
323
- ss << resource.name << "(" << resource.uriTemplate << ")";
324
- else
325
- ss << resource.uriTemplate;
316
+ if (!out.name.empty()) {
317
+ ss << out.name << "(" << out.uriTemplate << ")";
318
+ } else {
319
+ ss << out.uriTemplate;
320
+ }
326
321
 
327
322
  ss << "' resource, a resource can be represented by a single model only";
328
-
329
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
330
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
331
- result.first.warnings.push_back(Warning(ss.str(),
332
- DuplicateWarning,
333
- sourceBlock));
334
-
335
- return result;
323
+
324
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
325
+ report.warnings.push_back(Warning(ss.str(),
326
+ DuplicateWarning,
327
+ sourceMap));
336
328
  }
337
329
 
338
- // Check symbol name
339
- if (payload.name.empty()) {
340
-
341
- if (!resource.name.empty()) {
342
- payload.name = resource.name;
343
- }
344
- else {
330
+ if (model.name.empty()) {
331
+
332
+ if (!out.name.empty()) {
333
+ model.name = out.name;
334
+ } else {
335
+
345
336
  // ERR: No name specified for resource model
346
337
  std::stringstream ss;
347
338
  ss << "resource model can be specified only for a named resource";
348
- ss << ", name your resource, e.g. '# <resource name> [" << resource.uriTemplate << "]'";
339
+ ss << ", name your resource, e.g. '# <resource name> [" << out.uriTemplate << "]'";
349
340
 
350
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
351
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
352
- result.first.error = Error(ss.str(),
353
- SymbolError,
354
- sourceBlock);
341
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
342
+ report.error = Error(ss.str(),
343
+ SymbolError,
344
+ sourceMap);
355
345
  }
356
346
  }
357
-
358
- // Check whether symbol isn't already defined
359
- ResourceModelSymbolTable::const_iterator it = parser.symbolTable.resourceModels.find(payload.name);
360
- if (it == parser.symbolTable.resourceModels.end()) {
361
347
 
362
- parser.symbolTable.resourceModels[payload.name] = payload;
363
- }
364
- else {
348
+ ResourceModelSymbolTable::iterator it = pd.symbolTable.resourceModels.find(model.name);
349
+
350
+ if (it == pd.symbolTable.resourceModels.end()) {
351
+
352
+ pd.symbolTable.resourceModels[model.name] = model;
353
+ } else {
354
+
365
355
  // ERR: Symbol already defined
366
356
  std::stringstream ss;
367
- ss << "symbol '" << payload.name << "' already defined";
357
+ ss << "symbol '" << model.name << "' already defined";
368
358
 
369
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
370
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
371
- result.first.error = Error(ss.str(),
372
- SymbolError,
373
- sourceBlock);
374
- }
375
-
376
- // Assign model
377
- resource.model = payload;
378
-
379
- return result;
380
- }
381
-
382
- /** Parse Parameters section */
383
- static ParseSectionResult HandleParameters(const BlueprintSection& section,
384
- const BlockIterator& cur,
385
- BlueprintParserCore& parser,
386
- Resource& resource) {
387
- ParameterCollection parameters;
388
- ParseSectionResult result = ParametersParser::Parse(cur,
389
- section.bounds.second,
390
- section,
391
- parser,
392
- parameters);
393
- if (result.first.error.code != Error::OK)
394
- return result;
395
-
396
- if (parameters.empty()) {
397
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
398
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
399
- result.first.warnings.push_back(Warning(snowcrashconst::NoParametersMessage,
400
- FormattingWarning,
401
- sourceBlock));
402
- }
403
- else {
404
- // Check Eligibility
405
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
406
- CheckParametersEligibility(resource, parameters, nameBlock->sourceMap, parser.sourceData, result.first);
407
-
408
- // Insert
409
- resource.parameters.insert(resource.parameters.end(), parameters.begin(), parameters.end());
359
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
360
+ report.error = Error(ss.str(),
361
+ SymbolError,
362
+ sourceMap);
410
363
  }
411
-
412
- return result;
364
+
365
+ out.model = model;
366
+
367
+ return cur;
413
368
  }
414
-
415
- /** Check parameter eligibility, reporting if a parameter is not specified in URI template */
416
- static void CheckParametersEligibility(const Resource& resource,
417
- const ParameterCollection& parameters,
418
- const SourceDataBlock& location,
419
- const SourceData& sourceData,
420
- Result& result)
421
- {
422
- for (ParameterCollection::const_iterator it = parameters.begin();
369
+
370
+ /** Check Parameters eligibility in URI template */
371
+ static void checkParametersEligibility(const MarkdownNodeIterator& node,
372
+ const SectionParserData& pd,
373
+ Resource& resource,
374
+ Parameters& parameters,
375
+ Report& report) {
376
+
377
+ for (ParameterIterator it = parameters.begin();
423
378
  it != parameters.end();
424
379
  ++it) {
425
-
380
+
426
381
  // Naive check whether parameter is present in URI Template
427
382
  if (resource.uriTemplate.find(it->name) == std::string::npos) {
383
+
428
384
  // WARN: parameter name not present
429
385
  std::stringstream ss;
430
386
  ss << "parameter '" << it->name << "' not specified in ";
431
- if (!resource.name.empty())
387
+
388
+ if (!resource.name.empty()) {
432
389
  ss << "'" << resource.name << "' ";
390
+ }
391
+
433
392
  ss << "its '" << resource.uriTemplate << "' URI template";
434
393
 
435
- result.warnings.push_back(Warning(ss.str(),
394
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
395
+ report.warnings.push_back(Warning(ss.str(),
436
396
  LogicalErrorWarning,
437
- MapSourceDataBlock(location, sourceData)));
397
+ sourceMap));
438
398
  }
439
399
  }
440
400
  }
441
-
442
- static ParseSectionResult HandleResourceMethod(const BlueprintSection& section,
443
- const BlockIterator& cur,
444
- BlueprintParserCore& parser,
445
- Resource& resource) {
446
-
447
- // Retrieve URI template
448
- HTTPMethod method;
449
- GetResourceSignature(*cur, resource.name, resource.uriTemplate, method);
450
-
451
- // Parse as a resource action abbreviation
452
- return HandleAction(section, cur, parser, resource, true);
453
- }
454
-
455
- static ParseSectionResult HandleAction(const BlueprintSection& section,
456
- const BlockIterator& cur,
457
- BlueprintParserCore& parser,
458
- Resource& resource,
459
- bool abbrev = false)
460
- {
461
- Action action;
462
- ParseSectionResult result = ActionParser::Parse(cur,
463
- section.bounds.second,
464
- section,
465
- parser,
466
- action);
467
- if (result.first.error.code != Error::OK)
468
- return result;
469
-
470
- if (!abbrev) {
471
- Name name;
472
- HTTPMethod httpMethod;
473
- ActionSignature actionSignature = GetActionSignature(*cur, name, httpMethod);
474
-
475
- if (actionSignature == MethodURIActionSignature) {
476
- // WARN: ignoring extraneous content in action header
477
- std::stringstream ss;
478
- ss << "ignoring additional content in method header '" << cur->content << "'";
479
- ss << ", expected method-only e.g. '# " << action.method << "'";
480
-
481
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
482
- result.first.warnings.push_back(Warning(ss.str(),
483
- IgnoringWarning,
484
- sourceBlock));
485
- }
486
- }
487
-
488
- Collection<Action>::iterator duplicate = FindAction(resource, action);
489
- if (duplicate != resource.actions.end()) {
490
-
491
- // WARN: duplicate method
492
- std::stringstream ss;
493
- ss << "action with method '" << action.method << "' already defined for resource '";
494
- ss << resource.uriTemplate << "'";
495
-
496
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
497
- result.first.warnings.push_back(Warning(ss.str(),
498
- DuplicateWarning,
499
- sourceBlock));
500
- }
501
-
502
- // Check Eligibility
503
- if (!action.parameters.empty())
504
- CheckParametersEligibility(resource, action.parameters, cur->sourceMap, parser.sourceData, result.first);
505
-
506
-
507
- // Check for header duplictes
508
- DeepCheckHeaderDuplicates(resource, action, cur->sourceMap, parser.sourceData, result.first);
509
-
510
- if (action.examples.empty() ||
511
- action.examples.front().responses.empty()) {
512
- // WARN: method has no response
513
- std::stringstream ss;
514
- ss << "no response defined for '" << action.method << " " << resource.uriTemplate << "'";
515
-
516
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
517
- result.first.warnings.push_back(Warning(ss.str(),
518
- EmptyDefinitionWarning,
519
- sourceBlock));
520
- }
521
-
522
- resource.actions.push_back(action);
523
- return result;
524
- }
525
-
526
- static void DeepCheckHeaderDuplicates(const Resource& resource,
527
- const Action& action,
528
- const SourceDataBlock& sourceMap,
529
- const SourceData& sourceData,
530
- Result& result) {
531
-
532
- if (action.examples.empty())
533
- return;
534
-
535
- CheckHeaderDuplicates(resource, action, sourceMap, sourceData, result);
536
- for (Collection<Request>::const_iterator it = action.examples.front().requests.begin();
537
- it != action.examples.front().requests.end();
538
- ++it) {
539
-
540
- CheckHeaderDuplicates(resource, *it, sourceMap, sourceData, result);
541
- }
542
- for (Collection<Response>::const_iterator it = action.examples.front().responses.begin();
543
- it != action.examples.front().responses.end();
544
- ++it) {
545
-
546
- CheckHeaderDuplicates(resource, *it, sourceMap, sourceData, result);
547
- }
548
- }
549
-
550
- // Check whether abbreviated resource action isn't followed by an
551
- // action header which would imply possible additional method intended.
552
- static void CheckAmbiguousMethod(const BlueprintSection& section,
553
- const BlockIterator& cur,
554
- const Resource& resource,
555
- const SourceData& sourceData,
556
- Result& result) {
557
-
558
- if (cur == section.bounds.second ||
559
- cur->type != HeaderBlockType)
560
- return;
561
-
562
- Name name;
563
- HTTPMethod method;
564
- ActionSignature actionSignature = GetActionSignature(*cur, name, method);
565
- if (actionSignature == MethodActionSignature ||
566
- actionSignature == NamedActionSignature) {
567
- // WARN: ignoring possible method header
568
- std::stringstream ss;
569
- ss << "unexpected action '" << cur->content << "', ";
570
- ss << "to the define muliple actions for the '" << resource.uriTemplate << "' resource omit the HTTP method in its definition, ";
571
- ss << "e.g. '# " << resource.uriTemplate << "'";
572
-
573
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, sourceData);
574
- result.warnings.push_back(Warning(ss.str(),
575
- IgnoringWarning,
576
- sourceBlock));
577
- }
401
+
402
+ /** Finds an action inside an actions collection */
403
+ static ActionIterator findAction(const Actions& actions,
404
+ const Action& action) {
405
+
406
+ return std::find_if(actions.begin(),
407
+ actions.end(),
408
+ std::bind2nd(MatchAction<Action>(), action));
578
409
  }
579
410
  };
580
-
581
- typedef BlockParser<Resource, SectionParser<Resource> > ResourceParser;
411
+
412
+ /** Resource Section Parser */
413
+ typedef SectionParser<Resource, HeaderSectionAdapter> ResourceParser;
582
414
  }
583
415
 
584
416
  #endif