redsnow 0.1.6 → 0.2.0

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.
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