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
@@ -9,244 +9,169 @@
9
9
  #ifndef SNOWCRASH_PARAMETERSPARSER_H
10
10
  #define SNOWCRASH_PARAMETERSPARSER_H
11
11
 
12
- #include <sstream>
13
- #include "BlueprintParserCore.h"
14
- #include "Blueprint.h"
12
+ #include "SectionParser.h"
13
+ #include "ParameterParser.h"
15
14
  #include "RegexMatch.h"
16
15
  #include "StringUtility.h"
17
- #include "BlockUtility.h"
18
- #include "ParameterDefinitonParser.h"
16
+ #include "BlueprintUtility.h"
17
+
18
+ namespace snowcrash {
19
19
 
20
- namespace snowcrashconst {
21
-
22
20
  /** Parameters matching regex */
23
21
  const char* const ParametersRegex = "^[[:blank:]]*[Pp]arameters?[[:blank:]]*$";
24
22
 
25
- /** Expected parameters content */
26
- const char* const ExpectedParametersContent = "a nested list of parameters, one parameter per list item";
27
-
28
23
  /** No parameters specified message */
29
24
  const char* const NoParametersMessage = "no parameters specified, expected a nested list of parameters, one parameter per list item";
30
- }
31
25
 
32
- namespace snowcrash {
33
-
34
- /** Internal type alias for Collection of Paramaeter */
35
- typedef Collection<Parameter>::type ParameterCollection;
36
-
37
-
38
- /** Finds a parameter inside a parameters collection */
39
- FORCEINLINE ParameterCollection::iterator FindParameter(ParameterCollection& parameters,
40
- const Parameter& parameter) {
41
- return std::find_if(parameters.begin(),
42
- parameters.end(),
43
- std::bind2nd(MatchName<Parameter>(), parameter));
44
- }
45
-
46
- /**
47
- * Returns true if given block has parameters signature, false otherwise.
48
- */
49
- FORCEINLINE bool HasParametersSignature(const BlockIterator& begin,
50
- const BlockIterator& end) {
26
+ /** Internal type alias for Collection of Parameter */
27
+ typedef Collection<Parameter>::type Parameters;
51
28
 
52
- if (begin->type != ListBlockBeginType &&
53
- begin->type != ListItemBlockBeginType)
54
- return false;
55
-
56
- SourceData remainingContent;
57
- SourceData content = GetListItemSignature(begin, end, remainingContent);
58
- TrimString(content);
59
- return RegexMatch(content, snowcrashconst::ParametersRegex);
60
- }
61
-
62
- /** Children List Block Classifier, ParameterCollection context. */
63
- template <>
64
- FORCEINLINE SectionType ClassifyChildrenListBlock<ParameterCollection>(const BlockIterator& begin,
65
- const BlockIterator& end){
66
- // TODO:
67
- return UndefinedSectionType;
68
- }
69
-
70
- /** Block Classifier, ParameterCollection context. */
71
- template <>
72
- FORCEINLINE SectionType ClassifyBlock<ParameterCollection>(const BlockIterator& begin,
73
- const BlockIterator& end,
74
- const SectionType& context) {
75
-
76
- if (context == UndefinedSectionType) {
77
- if (HasParametersSignature(begin, end))
78
- return ParametersSectionType;
79
- }
80
- else if (context == ParametersSectionType) {
81
-
82
- if (begin->type == ListItemBlockEndType ||
83
- begin->type == ListBlockEndType)
84
- return UndefinedSectionType;
85
-
86
- if (HasParameterDefinitionSignature(begin, end))
87
- return ParameterDefinitionSectionType;
88
-
89
- if (begin->type == ListBlockBeginType)
90
- return ForeignSectionType; // Foreign nested list-item
91
-
92
- if (begin->type == ListItemBlockBeginType)
93
- return UndefinedSectionType;
94
- }
95
- else if (context == ParameterDefinitionSectionType ||
96
- context == ForeignSectionType) {
97
-
98
- if (begin->type == ListItemBlockEndType ||
99
- begin->type == ListBlockEndType)
100
- return UndefinedSectionType;
101
-
102
- if (HasParameterDefinitionSignature(begin, end))
103
- return ParameterDefinitionSectionType;
104
-
105
- return ForeignSectionType;
106
- }
107
-
108
- return (context == ParametersSectionType) ? context : UndefinedSectionType;
109
- }
29
+ typedef Collection<Parameter>::iterator ParameterIterator;
110
30
 
111
31
  /**
112
- * Parameters section parser.
32
+ * Parameters section processor
113
33
  */
114
34
  template<>
115
- struct SectionParser<ParameterCollection> {
116
-
117
- static ParseSectionResult ParseSection(const BlueprintSection& section,
118
- const BlockIterator& cur,
119
- BlueprintParserCore& parser,
120
- ParameterCollection& parameters) {
121
-
122
- ParseSectionResult result = std::make_pair(Result(), cur);
123
- switch (section.type) {
124
- case ParametersSectionType:
125
- result = HandleParmetersSection(section, cur, parser, parameters);
126
- break;
127
-
128
- case ParameterDefinitionSectionType:
129
- result = HandleParmeterDefinitionSection(section, cur, parser, parameters);
130
- break;
131
-
132
- case ForeignSectionType:
133
- result = HandleForeignSection<ParameterCollection>(section, cur, parser.sourceData);
134
- break;
135
-
136
- case UndefinedSectionType:
137
- result.second = CloseList(cur, section.bounds.second);
138
- break;
139
-
140
- default:
141
- result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
142
- break;
35
+ struct SectionProcessor<Parameters> : public SectionProcessorBase<Parameters> {
36
+
37
+ static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
38
+ const MarkdownNodes& siblings,
39
+ SectionParserData& pd,
40
+ SectionLayout& layout,
41
+ Report& report,
42
+ Parameters& out) {
43
+
44
+ mdp::ByteBuffer remainingContent;
45
+
46
+ GetFirstLine(node->text, remainingContent);
47
+
48
+ if (!remainingContent.empty()) {
49
+
50
+ // WARN: Extra content in parameters section
51
+ std::stringstream ss;
52
+ ss << "ignoring additional content after 'parameters' keyword,";
53
+ ss << " expected a nested list of parameters, one parameter per list item";
54
+
55
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
56
+ report.warnings.push_back(Warning(ss.str(),
57
+ IgnoringWarning,
58
+ sourceMap));
143
59
  }
144
-
145
- return result;
60
+
61
+ return ++MarkdownNodeIterator(node);
146
62
  }
147
-
148
- static void Finalize(const SectionBounds& bounds,
149
- BlueprintParserCore& parser,
150
- ParameterCollection& parameters,
151
- Result& result) {}
152
-
153
- /**
154
- * \brief Parse Parameters top-level section blocks.
155
- * \param section Actual section being parsed.
156
- * \param cur The actual position within Markdown block buffer.
157
- * \param parser Parser's instance.
158
- * \param payload An output buffer to write parameters into.
159
- * \return A block parser section result.
160
- */
161
- static ParseSectionResult HandleParmetersSection(const BlueprintSection& section,
162
- const BlockIterator& cur,
163
- BlueprintParserCore& parser,
164
- ParameterCollection& parameters) {
165
-
166
- ParseSectionResult result = std::make_pair(Result(), cur);
167
- BlockIterator sectionCur = cur;
168
-
169
- // Signature
170
- if (sectionCur == section.bounds.first) {
171
-
172
- CheckSignatureAdditionalContent(section,
173
- sectionCur,
174
- parser.sourceData,
175
- "'parameters' keyword",
176
- snowcrashconst::ExpectedParametersContent,
177
- result.first);
178
- result.second = SkipSignatureBlock(sectionCur, section.bounds.second);
179
- return result;
180
- }
181
-
182
- // Unexpected description
183
- if (sectionCur->type == QuoteBlockBeginType) {
184
- sectionCur = SkipToClosingBlock(sectionCur, section.bounds.second, QuoteBlockBeginType, QuoteBlockEndType);
185
- }
186
- else if (sectionCur->type == ListBlockBeginType) {
187
- sectionCur = SkipToClosingBlock(sectionCur, section.bounds.second, ListBlockBeginType, ListItemBlockEndType);
188
- }
189
-
190
- if (!CheckCursor(section, sectionCur, parser.sourceData, result.first))
191
- return result;
192
-
193
- // WARN: on ignoring additional content
194
- std::stringstream ss;
195
- ss << "ignoring additional content in the 'parameters' definition, expected " << snowcrashconst::ExpectedParametersContent;
196
-
197
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(sectionCur, cur, section.bounds, parser.sourceData);
198
- result.first.warnings.push_back(Warning(ss.str(),
199
- IgnoringWarning,
200
- sourceBlock));
201
-
202
- if (sectionCur != section.bounds.second)
203
- result.second = ++sectionCur;
204
-
205
- return result;
63
+
64
+ static MarkdownNodeIterator processDescription(const MarkdownNodeIterator& node,
65
+ const MarkdownNodes& siblings,
66
+ SectionParserData& pd,
67
+ Report& report,
68
+ Parameters& out) {
69
+
70
+ return node;
206
71
  }
207
-
208
- /** Parse a parameter definition top-level section blocks. */
209
- static ParseSectionResult HandleParmeterDefinitionSection(const BlueprintSection& section,
210
- const BlockIterator& cur,
211
- BlueprintParserCore& parser,
212
- ParameterCollection& parameters) {
72
+
73
+ static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
74
+ const MarkdownNodes& siblings,
75
+ SectionParserData& pd,
76
+ Report& report,
77
+ Parameters& out) {
78
+
79
+ if (pd.sectionContext() != ParameterSectionType) {
80
+ return node;
81
+ }
82
+
213
83
  Parameter parameter;
214
- ParseSectionResult result = ParameterDefinitionParser::Parse(cur,
215
- section.bounds.second,
216
- section,
217
- parser,
218
- parameter);
219
- if (result.first.error.code != Error::OK)
220
- return result;
221
-
222
- // Check duplicates
223
- if (!parameters.empty()) {
224
- ParameterCollection::iterator duplicate = FindParameter(parameters, parameter);
225
- if (duplicate != parameters.end()) {
84
+ ParameterParser::parse(node, siblings, pd, report, parameter);
85
+
86
+ if (!out.empty()) {
87
+
88
+ ParameterIterator duplicate = findParameter(out, parameter);
89
+
90
+ if (duplicate != out.end()) {
226
91
 
227
92
  // WARN: Parameter already defined
228
93
  std::stringstream ss;
229
94
  ss << "overshadowing previous parameter '" << parameter.name << "' definition";
230
95
 
231
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
232
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
233
- result.first.warnings.push_back(Warning(ss.str(),
234
- RedefinitionWarning,
235
- sourceBlock));
236
-
237
- // Erase origan duplicate
238
- parameters.erase(duplicate);
96
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
97
+ report.warnings.push_back(Warning(ss.str(),
98
+ RedefinitionWarning,
99
+ sourceMap));
100
+ }
101
+ }
102
+
103
+ out.push_back(parameter);
104
+
105
+ return ++MarkdownNodeIterator(node);
106
+ }
107
+
108
+ static bool isDescriptionNode(const MarkdownNodeIterator& node,
109
+ SectionType sectionType) {
110
+
111
+ return false;
112
+ }
113
+
114
+ static SectionType sectionType(const MarkdownNodeIterator& node) {
115
+
116
+ if (node->type == mdp::ListItemMarkdownNodeType
117
+ && !node->children().empty()) {
118
+
119
+ mdp::ByteBuffer remaining, subject = node->children().front().text;
120
+
121
+ subject = GetFirstLine(subject, remaining);
122
+ TrimString(subject);
123
+
124
+ if (RegexMatch(subject, ParametersRegex)) {
125
+ return ParametersSectionType;
239
126
  }
240
127
  }
241
-
242
- parameters.push_back(parameter);
243
-
244
- return result;
128
+
129
+ return UndefinedSectionType;
130
+ }
131
+
132
+ static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
133
+
134
+ return SectionProcessor<Parameter>::sectionType(node);
135
+ }
136
+
137
+ static SectionTypes nestedSectionTypes() {
138
+ SectionTypes nested;
139
+
140
+ // Parameter & descendants
141
+ nested.push_back(ParameterSectionType);
142
+ SectionTypes types = SectionProcessor<Parameter>::nestedSectionTypes();
143
+ nested.insert(nested.end(), types.begin(), types.end());
144
+
145
+ return nested;
146
+ }
147
+
148
+ static void finalize(const MarkdownNodeIterator& node,
149
+ SectionParserData& pd,
150
+ Report& report,
151
+ Parameters& out) {
152
+
153
+ if (out.empty()) {
154
+
155
+ // WARN: No parameters defined
156
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
157
+ report.warnings.push_back(Warning(NoParametersMessage,
158
+ FormattingWarning,
159
+ sourceMap));
160
+ }
161
+ }
162
+
163
+ /** Finds a parameter inside a parameters collection */
164
+ static ParameterIterator findParameter(Parameters& parameters,
165
+ const Parameter& parameter) {
166
+
167
+ return std::find_if(parameters.begin(),
168
+ parameters.end(),
169
+ std::bind2nd(MatchName<Parameter>(), parameter));
245
170
  }
246
171
  };
247
-
248
- typedef BlockParser<ParameterCollection, SectionParser<ParameterCollection> > ParametersParser;
249
- }
250
172
 
173
+ /** Parameters Section parser */
174
+ typedef SectionParser<Parameters, ListSectionAdapter> ParametersParser;
175
+ }
251
176
 
252
177
  #endif
@@ -9,664 +9,560 @@
9
9
  #ifndef SNOWCRASH_PARSEPAYLOAD_H
10
10
  #define SNOWCRASH_PARSEPAYLOAD_H
11
11
 
12
- #include <algorithm>
13
- #include <sstream>
14
- #include "BlueprintParserCore.h"
15
- #include "Blueprint.h"
12
+ #include "SectionParser.h"
16
13
  #include "RegexMatch.h"
17
14
  #include "AssetParser.h"
18
- #include "HeaderParser.h"
19
- #include "DescriptionSectionUtility.h"
20
- #include "StringUtility.h"
21
- #include "BlockUtility.h"
15
+ #include "HeadersParser.h"
16
+ #include "ParametersParser.h"
22
17
 
23
18
  /** Media type in brackets regex */
24
19
  #define MEDIA_TYPE "([[:blank:]]*\\(([^\\)]*)\\))"
25
20
 
26
- namespace snowcrashconst {
27
-
21
+ namespace snowcrash {
22
+
23
+ /// Payload signature
24
+ enum PayloadSignature {
25
+ NoPayloadSignature = 0,
26
+ RequestPayloadSignature, /// < Request payload.
27
+ ResponsePayloadSignature, /// < Response payload.
28
+ ModelPayloadSignature, /// < Resource Model payload.
29
+ UndefinedPayloadSignature = -1
30
+ };
31
+
28
32
  /** Request matching regex */
29
33
  const char* const RequestRegex = "^[[:blank:]]*[Rr]equest" SYMBOL_IDENTIFIER "?" MEDIA_TYPE "?[[:blank:]]*";
30
-
34
+
31
35
  /** Response matching regex */
32
36
  const char* const ResponseRegex = "^[[:blank:]]*[Rr]esponse([[:blank:][:digit:]]+)?" MEDIA_TYPE "?[[:blank:]]*";
33
-
34
- /** Object matching regex */
35
- const char* const ObjectRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "[Oo]bject" MEDIA_TYPE "?[[:blank:]]*$";
36
-
37
+
37
38
  /** Model matching regex */
38
- const char* const ModelRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "?[Mm]odel" MEDIA_TYPE "?[[:blank:]]*";
39
- }
39
+ const char* const ModelRegex = "^[[:blank:]]*(" SYMBOL_IDENTIFIER "[[:blank:]]+)?[Mm]odel" MEDIA_TYPE "?[[:blank:]]*$";
40
40
 
41
- namespace snowcrash {
42
-
43
- /**
44
- * Payload signature
45
- */
46
- enum PayloadSignature {
47
- UndefinedPayloadSignature, /// < Undefined payload.
48
- NoPayloadSignature, /// < Not a payload.
49
- RequestPayloadSignature, /// < Request payload.
50
- ResponsePayloadSignature, /// < Response payload.
51
- ObjectPayloadSignature, /// < Resource object payload.
52
- ModelPayloadSignature /// < Resource Model payload.
53
- };
54
-
55
- /**
56
- * \brief Query the payload signature of a given block.
57
- * \param begin The begin of the block to be queried.
58
- * \param end The end of the markdown block buffer.
59
- * \param name A buffer to retrieve payload name into.
60
- * \param mediaType A buffer to retrieve payload media type into.
61
- * \return The %PayloadSignature of the given block.
41
+ /**
42
+ * Payload Section Processor
62
43
  */
63
- FORCEINLINE PayloadSignature GetPayloadSignature(const BlockIterator& begin,
64
- const BlockIterator& end,
65
- Name& name,
66
- SourceData& mediaType) {
67
-
68
- if (begin->type == ListBlockBeginType || begin->type == ListItemBlockBeginType) {
69
-
70
- BlockIterator cur = ListItemNameBlock(begin, end);
71
- if (cur == end)
72
- return NoPayloadSignature;
73
-
74
- if (cur->type != ParagraphBlockType &&
75
- cur->type != ListItemBlockEndType)
76
- return NoPayloadSignature;
77
-
78
- std::string content = GetFirstLine(cur->content);
79
-
80
- CaptureGroups captureGroups;
81
- if (RegexCapture(content, snowcrashconst::RequestRegex, captureGroups, 5)) {
82
- name = captureGroups[1];
83
- TrimString(name);
84
- mediaType = captureGroups[3];
85
- return RequestPayloadSignature;
86
- }
87
- else if (RegexCapture(content, snowcrashconst::ResponseRegex, captureGroups, 5)) {
88
- name = captureGroups[1];
89
- TrimString(name);
90
- mediaType = captureGroups[3];
91
- return ResponsePayloadSignature;
92
- }
93
- else if (RegexCapture(content, snowcrashconst::ObjectRegex, captureGroups, 5)) {
94
- name = captureGroups[1];
95
- TrimString(name);
96
- mediaType = captureGroups[3];
97
- return ObjectPayloadSignature;
44
+ template<>
45
+ struct SectionProcessor<Payload> : public SectionProcessorBase<Payload> {
46
+
47
+ static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
48
+ const MarkdownNodes& siblings,
49
+ SectionParserData& pd,
50
+ SectionLayout& layout,
51
+ Report& report,
52
+ Payload& out) {
53
+
54
+ mdp::ByteBuffer signature, remainingContent;
55
+ signature = GetFirstLine(node->text, remainingContent);
56
+
57
+ parseSignature(node, pd, signature, report, out);
58
+
59
+ // WARN: missing status code
60
+ if (out.name.empty() &&
61
+ (pd.sectionContext() == ResponseSectionType || pd.sectionContext() == ResponseBodySectionType)) {
62
+
63
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
64
+ report.warnings.push_back(Warning("missing response HTTP status code, assuming 'Response 200'",
65
+ EmptyDefinitionWarning,
66
+ sourceMap));
67
+ out.name = "200";
98
68
  }
99
- else if (RegexCapture(content, snowcrashconst::ModelRegex, captureGroups, 5)) {
100
- name = captureGroups[1];
101
- TrimString(name);
102
- mediaType = captureGroups[3];
103
- return ModelPayloadSignature;
69
+
70
+ if (!remainingContent.empty()) {
71
+ if (!isAbbreviated(pd.sectionContext())) {
72
+ out.description = remainingContent;
73
+ } else if (!parseSymbolReference(node, pd, remainingContent, report, out)) {
74
+
75
+ // NOTE: NOT THE CORRECT WAY TO DO THIS
76
+ // https://github.com/apiaryio/snowcrash/commit/a7c5868e62df0048a85e2f9aeeb42c3b3e0a2f07#commitcomment-7322085
77
+ pd.sectionsContext.push_back(BodySectionType);
78
+ CodeBlockUtility::signatureContentAsCodeBlock(node, pd, report, out.body);
79
+ pd.sectionsContext.pop_back();
80
+ }
104
81
  }
82
+
83
+ return ++MarkdownNodeIterator(node);
105
84
  }
106
85
 
107
- return NoPayloadSignature;
108
- }
109
-
110
- /**
111
- * Returns true if given block has any payload signature, false otherwise.
112
- */
113
- FORCEINLINE bool HasPayloadSignature(const BlockIterator& begin,
114
- const BlockIterator& end) {
115
- Name name;
116
- SourceData mediaType;
117
- PayloadSignature signature = GetPayloadSignature(begin, end, name, mediaType);
118
- return signature != NoPayloadSignature;
119
- }
120
-
121
- /**
122
- * Retruns true if given block has any payload signature and
123
- * is written in the abbreviated form. False otherwise.
124
- */
125
- FORCEINLINE bool HasPayloadAssetSignature(const BlockIterator& begin,
126
- const BlockIterator& end) {
127
- if (!HasPayloadSignature(begin, end))
128
- return false;
129
-
130
- return !HasNestedListBlock(begin, end);
131
- }
132
-
133
- /**
134
- * Classifier of internal list items, payload context.
135
- */
136
- template <>
137
- FORCEINLINE SectionType ClassifyInternaListBlock<Payload>(const BlockIterator& begin,
138
- const BlockIterator& end) {
139
-
140
- AssetSignature asset = GetAssetSignature(begin, end);
141
- if (asset == BodyAssetSignature)
142
- return BodySectionType;
143
- else if (asset == SchemaAssetSignature)
144
- return SchemaSectionType;
145
-
146
- if (HasHeaderSignature(begin, end))
147
- return HeadersSectionType;
148
-
149
- return UndefinedSectionType;
150
- }
151
-
152
- /** Children blocks classifier */
153
- template <>
154
- FORCEINLINE SectionType ClassifyChildrenListBlock<Payload>(const BlockIterator& begin,
155
- const BlockIterator& end) {
156
-
157
- SectionType type = ClassifyInternaListBlock<Payload>(begin, end);
158
- if (type != UndefinedSectionType)
159
- return type;
160
-
161
- return UndefinedSectionType;
162
- }
163
-
164
- /**
165
- * Block Classifier, payload context.
166
- */
167
- template <>
168
- FORCEINLINE SectionType ClassifyBlock<Payload>(const BlockIterator& begin,
169
- const BlockIterator& end,
170
- const SectionType& context) {
171
-
172
- if (context == UndefinedSectionType) {
173
-
174
- Name name;
175
- SourceData mediaType;
176
- PayloadSignature payload = GetPayloadSignature(begin, end, name, mediaType);
177
- if (payload == RequestPayloadSignature) {
86
+ static MarkdownNodeIterator processContent(const MarkdownNodeIterator& node,
87
+ const MarkdownNodes& siblings,
88
+ SectionParserData& pd,
89
+ Report& report,
90
+ Payload& out) {
178
91
 
179
- return (HasNestedListBlock(begin, end)) ? RequestSectionType : RequestBodySectionType;
180
- }
181
- else if (payload == ResponsePayloadSignature) {
182
-
183
- return (HasNestedListBlock(begin, end)) ? ResponseSectionType : ResponseBodySectionType;
184
- }
185
- else if (payload == ObjectPayloadSignature) {
186
-
187
- return (HasNestedListBlock(begin, end)) ? ObjectSectionType : ObjectBodySectionType;
188
- }
189
- else if (payload == ModelPayloadSignature) {
190
-
191
- return (HasNestedListBlock(begin, end)) ? ModelSectionType : ModelBodySectionType;
92
+ mdp::ByteBuffer content;
93
+
94
+ if (!out.symbol.empty()) {
95
+ //WARN: ignoring extraneous content after symbol reference
96
+ std::stringstream ss;
97
+
98
+ ss << "ignoring extraneous content after symbol reference";
99
+ ss << ", expected symbol reference only e.g. '[" << out.symbol << "][]'";
100
+
101
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
102
+ report.warnings.push_back(Warning(ss.str(),
103
+ IgnoringWarning,
104
+ sourceMap));
105
+ } else {
106
+
107
+ if (!out.body.empty() ||
108
+ node->type != mdp::ParagraphMarkdownNodeType ||
109
+ !parseSymbolReference(node, pd, node->text, report, out)) {
110
+
111
+ // NOTE: NOT THE CORRECT WAY TO DO THIS
112
+ // https://github.com/apiaryio/snowcrash/commit/a7c5868e62df0048a85e2f9aeeb42c3b3e0a2f07#commitcomment-7322085
113
+ pd.sectionsContext.push_back(BodySectionType);
114
+ CodeBlockUtility::contentAsCodeBlock(node, pd, report, content);
115
+ pd.sectionsContext.pop_back();
116
+
117
+ out.body += content;
118
+ }
192
119
  }
193
120
 
121
+ return ++MarkdownNodeIterator(node);
194
122
  }
195
- else if (context == RequestSectionType ||
196
- context == ResponseSectionType ||
197
- context == ObjectSectionType ||
198
- context == ModelSectionType) {
199
-
200
- // SectionType closure
201
- if (begin->type == ListItemBlockEndType ||
202
- begin->type == ListBlockEndType)
203
- return UndefinedSectionType;
204
-
205
- SectionType listSection = ClassifyInternaListBlock<Payload>(begin, end);
206
- if (listSection != UndefinedSectionType)
207
- return listSection;
208
-
209
- // Adjacent list item
210
- if (begin->type == ListItemBlockBeginType)
211
- return UndefinedSectionType;
212
- }
213
- else if (context == HeadersSectionType ||
214
- context == BodySectionType ||
215
- context == SchemaSectionType ||
216
- context == ForeignSectionType) {
217
-
218
- // SectionType closure
219
- if (begin->type == ListItemBlockEndType ||
220
- begin->type == ListBlockEndType)
221
- return UndefinedSectionType;
222
-
223
- SectionType listSection = ClassifyInternaListBlock<Payload>(begin, end);
224
- if (listSection != UndefinedSectionType)
225
- return listSection;
226
-
227
- if (HasPayloadAssetSignature(begin, end))
228
- return UndefinedSectionType;
229
-
230
- return ForeignSectionType;
231
- }
232
-
233
- return (context == RequestSectionType ||
234
- context == ResponseSectionType ||
235
- context == ObjectSectionType ||
236
- context == ModelSectionType) ? context : UndefinedSectionType;
237
- }
238
-
239
- /**
240
- * Payload section parser.
241
- */
242
- template<>
243
- struct SectionParser<Payload> {
244
-
245
- static ParseSectionResult ParseSection(const BlueprintSection& section,
246
- const BlockIterator& cur,
247
- BlueprintParserCore& parser,
248
- Payload& payload) {
249
-
250
- ParseSectionResult result = std::make_pair(Result(), cur);
251
123
 
252
- switch (section.type) {
253
- case RequestSectionType:
254
- case ResponseSectionType:
255
- case ObjectSectionType:
256
- case ModelSectionType:
257
- result = HandleDescriptionSectionBlock(section, cur, parser, payload);
258
- break;
259
-
260
- case RequestBodySectionType:
261
- case ResponseBodySectionType:
262
- case ObjectBodySectionType:
263
- case ModelBodySectionType:
264
- result = HandlePayloadAsset(section, cur, parser, payload);
265
- break;
266
-
124
+ static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
125
+ const MarkdownNodes& siblings,
126
+ SectionParserData& pd,
127
+ Report& report,
128
+ Payload& out) {
129
+
130
+ switch (pd.sectionContext()) {
267
131
  case HeadersSectionType:
268
- result = HandleHeaders(section, cur, parser, payload);
269
- break;
270
-
132
+ return HeadersParser::parse(node, siblings, pd, report, out.headers);
133
+
271
134
  case BodySectionType:
135
+ if (!out.body.empty()) {
136
+ // WARN: Multiple body section
137
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
138
+ report.warnings.push_back(Warning("ignoring additional 'body' content, it is already defined",
139
+ RedefinitionWarning,
140
+ sourceMap));
141
+ }
142
+
143
+ return AssetParser::parse(node, siblings, pd, report, out.body);
144
+
272
145
  case SchemaSectionType:
273
- result = HandleAsset(section, cur, parser, payload);
274
- break;
275
-
276
- case UndefinedSectionType:
277
- result.second = CloseList(cur, section.bounds.second);
278
- break;
279
-
280
- case ForeignSectionType:
281
- result = HandleForeignSection<Payload>(section, cur, parser.sourceData);
282
- break;
283
-
146
+ if (!out.schema.empty()) {
147
+ // WARN: Multiple schema section
148
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
149
+ report.warnings.push_back(Warning("ignoring additional 'schema' content, it is already defined",
150
+ RedefinitionWarning,
151
+ sourceMap));
152
+ }
153
+
154
+ return AssetParser::parse(node, siblings, pd, report, out.schema);
155
+
284
156
  default:
285
- result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
286
157
  break;
287
158
  }
288
-
289
- return result;
159
+
160
+ return node;
290
161
  }
291
-
292
- static void Finalize(const SectionBounds& bounds,
293
- BlueprintParserCore& parser,
294
- Payload& payload,
295
- Result& result) {}
296
-
297
- /**
298
- * \brief Parse Payload's description blocks.
299
- * \param section The current section's signature.
300
- * \param cur The actual position within Markdown block buffer.
301
- * \param bound Boundaries of Markdown block buffer.
302
- * \param parser A parser's instance.
303
- * \param payload An output buffer to write overview description into.
304
- * \return A block parser section result.
305
- */
306
- static ParseSectionResult HandleDescriptionSectionBlock(const BlueprintSection& section,
307
- const BlockIterator& cur,
308
- BlueprintParserCore& parser,
309
- Payload& payload) {
310
-
311
- ParseSectionResult result = std::make_pair(Result(), cur);
312
- BlockIterator sectionCur = cur;
313
162
 
314
- // Signature
315
- if (sectionCur == section.bounds.first) {
163
+ static MarkdownNodeIterator processUnexpectedNode(const MarkdownNodeIterator& node,
164
+ const MarkdownNodes& siblings,
165
+ SectionParserData& pd,
166
+ SectionType& sectionType,
167
+ Report& report,
168
+ Payload& out) {
316
169
 
317
- ProcessSignature(section, sectionCur, parser.sourceData, result.first, payload);
318
- sectionCur = FirstContentBlock(cur, section.bounds.second);
170
+ if ((node->type == mdp::ParagraphMarkdownNodeType ||
171
+ node->type == mdp::CodeMarkdownNodeType) &&
172
+ sectionType == BodySectionType) {
319
173
 
320
- result.second = ++sectionCur;
321
- return result;
322
-
174
+ CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.body);
175
+ return ++MarkdownNodeIterator(node);
323
176
  }
177
+
178
+ return SectionProcessorBase<Payload>::processUnexpectedNode(node, siblings, pd, sectionType, report, out);
179
+ }
180
+
181
+ static bool isDescriptionNode(const MarkdownNodeIterator& node,
182
+ SectionType sectionType) {
324
183
 
325
- // Description
326
- result = ParseDescriptionBlock<Payload>(section,
327
- sectionCur,
328
- parser.sourceData,
329
- payload);
330
- return result;
184
+ if (!isAbbreviated(sectionType) &&
185
+ SectionProcessorBase<Payload>::isDescriptionNode(node, sectionType)) {
331
186
 
187
+ return true;
188
+ }
189
+
190
+ return false;
332
191
  }
333
-
334
- /**
335
- * \brief Parse an asset.
336
- * \param section The current section's signature.
337
- * \param begin The begin of the block to be parsed.
338
- * \param end The end of the markdown block buffer.
339
- * \param parser A parser's instance.
340
- * \param payload An output buffer to save the parsed asset to.
341
- * \return A block parser section result.
342
- */
343
- static ParseSectionResult HandleAsset(const BlueprintSection& section,
344
- const BlockIterator& cur,
345
- BlueprintParserCore& parser,
346
- Payload& payload) {
347
- Asset asset;
348
- ParseSectionResult result = AssetParser::Parse(cur, section.bounds.second, section, parser, asset);
349
- if (result.first.error.code != Error::OK)
350
- return result;
351
-
352
- if (!SetAsset(section.type, asset, payload)) {
353
- // WARN: asset already set
354
- std::stringstream ss;
355
- ss << "ignoring additional " << SectionName(section.type) << " content, content is already defined";
356
-
357
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
358
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
359
- result.first.warnings.push_back(Warning(ss.str(),
360
- RedefinitionWarning,
361
- sourceBlock));
192
+
193
+ static bool isContentNode(const MarkdownNodeIterator& node,
194
+ SectionType sectionType) {
195
+
196
+ if (isAbbreviated(sectionType) &&
197
+ (SectionKeywordSignature(node) == UndefinedSectionType)) {
198
+
199
+ return true;
362
200
  }
363
-
364
- return result;
201
+
202
+ return false;
365
203
  }
366
-
367
- /**
368
- * \brief Parse payload and abbreviated asset.
369
- * \param section The current section's signature.
370
- * \param begin The parsed of the block to be queried.
371
- * \param end The end of the markdown block buffer.
372
- * \param parser A parser's instance.
373
- * \param payload An output buffer to save the parsed paylod and asset into.
374
- * \return A block parser section result.
375
- */
376
- static ParseSectionResult HandlePayloadAsset(const BlueprintSection& section,
377
- const BlockIterator& cur,
378
- BlueprintParserCore& parser,
379
- Payload& payload) {
380
- // Try to parse as a Symbol reference
381
- SymbolName symbol;
382
- SourceDataBlock symbolSourceMap;
383
- ParseSectionResult result = ParseSymbolReference(cur, section.bounds, parser, symbol, symbolSourceMap);
384
- if (result.first.error.code != Error::OK)
385
- return result;
386
-
387
- if (result.second != cur) {
388
- // Process a symbol reference
389
- ResourceModelSymbolTable::const_iterator symbolEntry = parser.symbolTable.resourceModels.find(symbol);
390
- if (symbolEntry == parser.symbolTable.resourceModels.end()) {
391
-
392
- // ERR: Undefined symbol
393
- std::stringstream ss;
394
- ss << "undefined symbol '" << symbol << "'";
395
- result.first.error = Error(ss.str(),
396
- SymbolError,
397
- MapSourceDataBlock(symbolSourceMap, parser.sourceData));
398
- return result;
204
+
205
+ static SectionType sectionType(const MarkdownNodeIterator& node) {
206
+
207
+ if (node->type == mdp::ListItemMarkdownNodeType
208
+ && !node->children().empty()) {
209
+
210
+ SectionType nestedType = UndefinedSectionType;
211
+ PayloadSignature signature = payloadSignature(node);
212
+
213
+ if (signature == NoPayloadSignature) {
214
+ return UndefinedSectionType;
399
215
  }
400
-
401
- // Retrieve payload from symbol table
402
- payload = symbolEntry->second;
403
- }
404
- else {
405
- // Parse as an asset
406
- result = HandleAsset(section, cur, parser, payload);
216
+
217
+ for (MarkdownNodeIterator child = node->children().begin();
218
+ child != node->children().end();
219
+ ++child) {
220
+
221
+ nestedType = nestedSectionType(child);
222
+
223
+ if (nestedType != UndefinedSectionType) {
224
+ return getSectionType(signature, nestedType);
225
+ }
226
+ }
227
+
228
+ // Return abbreviated signature
229
+ return getSectionType(signature, nestedType);
407
230
  }
408
-
409
- // Retrieve signature
410
- ProcessSignature(section, cur, parser.sourceData, result.first, payload);
411
-
412
- return result;
231
+
232
+ return UndefinedSectionType;
413
233
  }
414
-
415
- /**
416
- * \brief Parse a symbol reference.
417
- * \param begin The begin of the block to be parsed.
418
- * \param end The end of the markdown block buffer.
419
- * \param parser A parser's instance.
420
- * \param symbolName Output buffer to put parsed symbol's name into.
421
- * \param symbolSourceMap Source map of the parsed symbol reference.
422
- * \return A block parser section result.
423
- */
424
- static ParseSectionResult ParseSymbolReference(const BlockIterator& cur,
425
- const SectionBounds& bounds,
426
- BlueprintParserCore& parser,
427
- SymbolName& symbolName,
428
- SourceDataBlock& symbolSourceMap) {
429
-
430
- ParseSectionResult result = std::make_pair(Result(), cur);
431
- BlockIterator sectionCur = cur;
432
- SourceData content;
433
- SourceData signature = GetListItemSignature(sectionCur, bounds.second, content);
434
- if (!content.empty()) {
435
- sectionCur = ListItemNameBlock(sectionCur, bounds.second);
234
+
235
+ static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
236
+
237
+ SectionType nestedType = UndefinedSectionType;
238
+
239
+ // Check if headers section
240
+ nestedType = SectionProcessor<Headers>::sectionType(node);
241
+
242
+ if (nestedType != UndefinedSectionType) {
243
+ return nestedType;
436
244
  }
437
- else {
438
- sectionCur = FirstContentBlock(cur, bounds.second);
439
- if (sectionCur == bounds.second ||
440
- sectionCur->type != ParagraphBlockType)
441
- return result;
442
-
443
- // Try the next block
444
- if (++sectionCur == bounds.second ||
445
- sectionCur->type != ParagraphBlockType)
446
- return result;
447
-
448
- content = sectionCur->content;
245
+
246
+ // Check if asset section
247
+ nestedType = SectionProcessor<Asset>::sectionType(node);
248
+
249
+ if (nestedType != UndefinedSectionType) {
250
+ return nestedType;
449
251
  }
450
-
451
- TrimString(content);
452
- SymbolName symbol;
453
- if (!GetSymbolReference(content, symbol))
454
- return result;
455
-
456
- symbolName = symbol;
457
- symbolSourceMap = sectionCur->sourceMap;
458
-
459
- // Close list item
460
- BlockIterator endCur = cur;
461
- if (endCur->type == ListBlockBeginType)
462
- ++endCur;
463
- endCur = SkipToClosingBlock(endCur, bounds.second, ListItemBlockBeginType, ListItemBlockEndType);
464
-
465
- // Check extraneous content
466
- if (sectionCur != endCur) {
467
- ++sectionCur;
468
- for (; sectionCur != endCur; ++sectionCur) {
469
252
 
470
- if (sectionCur->type == QuoteBlockBeginType)
471
- sectionCur = SkipToClosingBlock(sectionCur, endCur, QuoteBlockBeginType, QuoteBlockEndType);
472
-
473
- if (sectionCur->type == ListBlockBeginType)
474
- sectionCur = SkipToClosingBlock(sectionCur, endCur, ListBlockBeginType, ListBlockEndType);
475
-
476
- // WARN: ignoring extraneous content after symbol reference
253
+ return UndefinedSectionType;
254
+ }
255
+
256
+ static SectionTypes nestedSectionTypes() {
257
+ SectionTypes nested, types;
258
+
259
+ nested.push_back(HeadersSectionType);
260
+ nested.push_back(BodySectionType);
261
+ nested.push_back(SchemaSectionType);
262
+
263
+ // Parameters & descendants
264
+ nested.push_back(ParametersSectionType);
265
+ types = SectionProcessor<Parameters>::nestedSectionTypes();
266
+ nested.insert(nested.end(), types.begin(), types.end());
267
+
268
+ return nested;
269
+ }
270
+
271
+ static void finalize(const MarkdownNodeIterator& node,
272
+ SectionParserData& pd,
273
+ Report& report,
274
+ Payload& out) {
275
+
276
+ bool warnEmptyBody = false;
277
+
278
+ mdp::ByteBuffer contentLength;
279
+ mdp::ByteBuffer transferEncoding;
280
+
281
+ SectionType sectionType = pd.sectionContext();
282
+
283
+ for (Collection<Header>::const_iterator it = out.headers.begin();
284
+ it != out.headers.end();
285
+ ++it) {
286
+
287
+ if (it->first == HTTPHeaderName::ContentLength) {
288
+ contentLength = it->second;
289
+ }
290
+
291
+ if (it->first == HTTPHeaderName::TransferEncoding) {
292
+ transferEncoding = it->second;
293
+ }
294
+ }
295
+
296
+ if ((sectionType == RequestSectionType || sectionType == RequestBodySectionType) && out.body.empty()) {
297
+
298
+ // Warn when content-length or transfer-encoding is specified or both headers and body are empty
299
+ if (out.headers.empty()) {
300
+ warnEmptyBody = true;
301
+ } else {
302
+ warnEmptyBody = !contentLength.empty() || !transferEncoding.empty();
303
+ }
304
+
305
+ if (warnEmptyBody) {
306
+ // WARN: empty body
477
307
  std::stringstream ss;
478
- ss << "ignoring extraneous content after symbol reference";
479
- ss << ", expected symbol reference only e.g. '[" << symbolName << "][]'";
480
-
481
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(sectionCur, cur, bounds, parser.sourceData);
482
- result.first.warnings.push_back(Warning(ss.str(),
483
- IgnoringWarning,
484
- sourceBlock));
308
+ ss << "empty " << SectionName(sectionType) << " " << SectionName(BodySectionType);
309
+
310
+ if (!contentLength.empty()) {
311
+ ss << ", expected " << SectionName(BodySectionType) << " for '" << contentLength << "' Content-Length";
312
+ } else if (!transferEncoding.empty()) {
313
+ ss << ", expected " << SectionName(BodySectionType) << " for '" << transferEncoding << "' Transfer-Encoding";
314
+ }
315
+
316
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
317
+ report.warnings.push_back(Warning(ss.str(),
318
+ EmptyDefinitionWarning,
319
+ sourceMap));
320
+ }
321
+ } else if ((sectionType == ResponseSectionType || sectionType == ResponseBodySectionType)) {
322
+
323
+ HTTPStatusCode code = 200;
324
+
325
+ if (!out.name.empty()) {
326
+ std::stringstream(out.name) >> code;
327
+ }
328
+
329
+ StatusCodeTraits statusCodeTraits = GetStatusCodeTrait(code);
330
+
331
+ if (!statusCodeTraits.allowBody && !out.body.empty()) {
332
+ // WARN: not empty body
333
+ std::stringstream ss;
334
+ ss << "the " << code << " response MUST NOT include a " << SectionName(BodySectionType);
335
+
336
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
337
+ report.warnings.push_back(Warning(ss.str(),
338
+ EmptyDefinitionWarning,
339
+ sourceMap));
485
340
  }
486
341
  }
487
-
488
- endCur = CloseList(sectionCur, bounds.second);
489
- result.second = endCur;
490
-
491
- return result;
492
342
  }
493
-
494
- /**
495
- * Retrieve and process payload signature.
496
- */
497
- static void ProcessSignature(const BlueprintSection& section,
498
- const BlockIterator& cur,
499
- const SourceData& sourceData,
500
- Result& result,
501
- Payload& payload) {
502
-
503
- SourceData remainingContent;
504
- SourceData signature = GetListItemSignature(cur, section.bounds.second, remainingContent);
505
343
 
506
- // Capture name & payload type
507
- SourceData mediaType;
508
- GetPayloadSignature(cur, section.bounds.second, payload.name, mediaType);
509
-
510
- // Check signature
511
- if (!CheckSignature(section, cur, signature, sourceData, result)) {
512
- // Clear all readouts
513
- payload.name.clear();
514
- mediaType.clear();
515
- remainingContent.clear();
516
- }
517
-
518
- // Add any extra lines to description unless abbreviated body
519
- if (!remainingContent.empty() &&
520
- section.type != RequestBodySectionType &&
521
- section.type != ResponseBodySectionType) {
522
- payload.description += remainingContent;
523
- }
524
-
525
- // WARN: missing status code
526
- if (payload.name.empty() &&
527
- (section.type == ResponseSectionType || section.type == ResponseBodySectionType)) {
528
-
529
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
530
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, sourceData);
531
- result.warnings.push_back(Warning("missing response HTTP status code, assuming 'Response 200'",
532
- EmptyDefinitionWarning,
533
- sourceBlock));
534
- payload.name = "200";
535
- }
536
-
537
-
538
- // WARN: Object deprecation
539
- if (section.type == ObjectSectionType || section.type == ObjectBodySectionType) {
344
+ /** Resolve payload signature */
345
+ static PayloadSignature payloadSignature(const MarkdownNodeIterator& node) {
540
346
 
541
- std::stringstream ss;
542
- ss << "the 'object' keyword is deprecated and as such it will be removed in a future release, please use the 'model' keyword instead";
543
-
544
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
545
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, sourceData);
546
- result.warnings.push_back(Warning(ss.str(),
547
- DeprecatedWarning,
548
- sourceBlock));
549
- }
550
-
551
- if (!mediaType.empty()) {
552
- Header header = std::make_pair(HTTPHeaderName::ContentType, mediaType);
553
- TrimString(header.second);
554
- payload.headers.push_back(header);
347
+ mdp::ByteBuffer subject = node->children().front().text;
348
+ mdp::ByteBuffer signature;
349
+ mdp::ByteBuffer remainingContent;
350
+
351
+ signature = GetFirstLine(subject, remainingContent);
352
+ TrimString(signature);
353
+
354
+ if (RegexMatch(signature, RequestRegex))
355
+ return RequestPayloadSignature;
356
+
357
+ if (RegexMatch(signature, ResponseRegex))
358
+ return ResponsePayloadSignature;
359
+
360
+ if (RegexMatch(signature, ModelRegex))
361
+ return ModelPayloadSignature;
362
+
363
+ return NoPayloadSignature;
364
+ }
365
+
366
+ /** Get SectionType from PayloadSignature and nestedSectionType */
367
+ static SectionType getSectionType(PayloadSignature signature,
368
+ SectionType nestedType) {
369
+
370
+ switch (signature) {
371
+ case RequestPayloadSignature:
372
+ return (nestedType != UndefinedSectionType) ? RequestSectionType : RequestBodySectionType;
373
+
374
+ case ResponsePayloadSignature:
375
+ return (nestedType != UndefinedSectionType) ? ResponseSectionType : ResponseBodySectionType;
376
+
377
+ case ModelPayloadSignature:
378
+ return (nestedType != UndefinedSectionType) ? ModelSectionType : ModelBodySectionType;
379
+
380
+ default:
381
+ break;
555
382
  }
383
+
384
+ return UndefinedSectionType;
556
385
  }
557
-
558
- /**
559
- * \brief Checks and report invalid signature
560
- * \return True if signature is correct, false otherwise.
561
- */
562
- static bool CheckSignature(const BlueprintSection& section,
563
- const BlockIterator& cur,
564
- const SourceData& signature,
565
- const SourceData& sourceData,
566
- Result& result) {
567
-
568
- std::string regex;
569
- switch (section.type) {
570
-
386
+
387
+ /** True if abbreviated section type */
388
+ static bool isAbbreviated(SectionType sectionType) {
389
+
390
+ return (sectionType == RequestBodySectionType ||
391
+ sectionType == ResponseBodySectionType ||
392
+ sectionType == ModelBodySectionType);
393
+ }
394
+
395
+ /** Given the signature, parse it */
396
+ static bool parseSignature(const MarkdownNodeIterator& node,
397
+ SectionParserData& pd,
398
+ const mdp::ByteBuffer& signature,
399
+ Report& report,
400
+ Payload& out) {
401
+
402
+ const char* regex;
403
+ mdp::ByteBuffer mediaType;
404
+ CaptureGroups captureGroups;
405
+
406
+ switch (pd.sectionContext()) {
571
407
  case RequestSectionType:
572
408
  case RequestBodySectionType:
573
- regex = snowcrashconst::RequestRegex;
409
+ regex = RequestRegex;
574
410
  break;
575
-
576
- case ResponseBodySectionType:
411
+
577
412
  case ResponseSectionType:
578
- regex = snowcrashconst::ResponseRegex;
413
+ case ResponseBodySectionType:
414
+ regex = ResponseRegex;
579
415
  break;
580
-
416
+
581
417
  case ModelSectionType:
582
418
  case ModelBodySectionType:
583
- regex = snowcrashconst::ModelRegex;
419
+ regex = ModelRegex;
584
420
  break;
585
-
421
+
586
422
  default:
587
423
  return true;
588
424
  }
589
-
590
- CaptureGroups captureGroups;
591
- if (RegexCapture(signature, regex, captureGroups) &&
425
+
426
+ if (RegexCapture(signature, regex, captureGroups, 5) &&
592
427
  !captureGroups.empty()) {
593
428
 
594
- std::string target = signature;
595
- std::string::size_type pos = target.find(captureGroups[0]);
596
- if (pos != std::string::npos)
597
- target.replace(pos, captureGroups[0].length(), std::string());
429
+ mdp::ByteBuffer target = signature;
430
+ mdp::ByteBuffer::size_type pos = target.find(captureGroups[0]);
431
+
432
+ if (pos != mdp::ByteBuffer::npos) {
433
+ target.replace(pos, captureGroups[0].length(), mdp::ByteBuffer());
434
+ }
598
435
 
599
436
  TrimString(target);
437
+
600
438
  if (!target.empty()) {
601
439
  // WARN: unable to parse payload signature
602
440
  std::stringstream ss;
603
- ss << "unable to parse " << SectionName(section.type) << " signature, expected ";
604
-
605
- switch (section.type) {
606
-
441
+ ss << "unable to parse " << SectionName(pd.sectionContext()) << " signature, expected ";
442
+
443
+ switch (pd.sectionContext()) {
607
444
  case RequestSectionType:
608
445
  case RequestBodySectionType:
609
446
  ss << "'request [<identifier>] [(<media type>)]'";
610
447
  break;
611
-
448
+
612
449
  case ResponseBodySectionType:
613
450
  case ResponseSectionType:
614
451
  ss << "'response [<HTTP status code>] [(<media type>)]'";
615
452
  break;
616
-
453
+
617
454
  case ModelSectionType:
618
455
  case ModelBodySectionType:
619
456
  ss << "'model [(<media type>)]'";
620
457
  break;
621
-
458
+
622
459
  default:
623
460
  return false;
624
461
  }
625
-
626
- BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
627
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, sourceData);
628
- result.warnings.push_back(Warning(ss.str(),
462
+
463
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
464
+ report.warnings.push_back(Warning(ss.str(),
629
465
  FormattingWarning,
630
- sourceBlock));
631
-
466
+ sourceMap));
467
+
632
468
  return false;
633
469
  }
470
+
471
+ if (pd.sectionContext() == ModelSectionType ||
472
+ pd.sectionContext() == ModelBodySectionType) {
473
+
474
+ out.name = captureGroups[2];
475
+ mediaType = captureGroups[4];
476
+ } else {
477
+ out.name = captureGroups[1];
478
+ mediaType = captureGroups[3];
479
+ }
480
+
481
+ TrimString(out.name);
482
+ TrimString(mediaType);
483
+
484
+ if (!mediaType.empty()) {
485
+ Header header = std::make_pair(HTTPHeaderName::ContentType, mediaType);
486
+ out.headers.push_back(header);
487
+ }
634
488
  }
635
-
489
+
636
490
  return true;
637
491
  }
638
-
639
- /**
640
- * \brief Set payload's asset.
641
- * \return True on success, false when an asset is already set.
642
- */
643
- static bool SetAsset(const SectionType& sectionType, const Asset& asset, Payload& payload) {
644
-
645
- if (sectionType == BodySectionType ||
646
- sectionType == RequestBodySectionType ||
647
- sectionType == ResponseBodySectionType ||
648
- sectionType == ModelBodySectionType ||
649
- sectionType == ObjectBodySectionType ||
650
- sectionType == DanglingBodySectionType) {
651
- if (!payload.body.empty())
652
- return false;
653
492
 
654
- payload.body = asset;
655
- }
656
- else if (sectionType == SchemaSectionType ||
657
- sectionType == DanglingSchemaSectionType) {
658
- if (!payload.schema.empty())
659
- return false;
493
+ static bool parseSymbolReference(const MarkdownNodeIterator& node,
494
+ SectionParserData& pd,
495
+ mdp::ByteBuffer& source,
496
+ Report& report,
497
+ Payload& out) {
498
+
499
+ SymbolName symbol;
500
+ ResourceModel model;
501
+
502
+ TrimString(source);
503
+
504
+ if (GetSymbolReference(source, symbol)) {
505
+ out.symbol = symbol;
506
+
507
+ // If symbol doesn't exist
508
+ if (pd.symbolTable.resourceModels.find(symbol) == pd.symbolTable.resourceModels.end()) {
509
+
510
+ // ERR: Undefined symbol
511
+ std::stringstream ss;
512
+ ss << "Undefined symbol " << symbol;
513
+
514
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
515
+ report.error = Error(ss.str(), SymbolError, sourceMap);
516
+
517
+ return true;
518
+ }
519
+
520
+ model = pd.symbolTable.resourceModels.at(symbol);
660
521
 
661
- payload.schema = asset;
522
+ out.description = model.description;
523
+ out.parameters = model.parameters;
524
+
525
+ Collection<Header>::const_iterator modelContentType = std::find_if(model.headers.begin(),
526
+ model.headers.end(),
527
+ std::bind2nd(MatchFirstWith<Header, std::string>(),
528
+ HTTPHeaderName::ContentType));
529
+
530
+ bool isPayloadContentType = !out.headers.empty();
531
+ bool isModelContentType = modelContentType != model.headers.end();
532
+
533
+ if (isPayloadContentType && isModelContentType) {
534
+
535
+ // WARN: Ignoring payload content-type, when referencing a model with headers
536
+ std::stringstream ss;
537
+
538
+ ss << "ignoring additional " << SectionName(pd.sectionContext()) << " header(s), ";
539
+ ss << "specify this header(s) in the referenced model definition instead";
540
+
541
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
542
+ report.warnings.push_back(Warning(ss.str(),
543
+ IgnoringWarning,
544
+ sourceMap));
545
+ }
546
+
547
+ if (isPayloadContentType && !isModelContentType) {
548
+ out.headers.insert(out.headers.end(), model.headers.begin(), model.headers.end());
549
+ }
550
+ else {
551
+ out.headers = model.headers;
552
+ }
553
+
554
+ out.body = model.body;
555
+ out.schema = model.schema;
556
+
557
+ return true;
662
558
  }
663
-
664
- return true;
559
+
560
+ return false;
665
561
  }
666
562
  };
667
-
668
- /** Payload Parser */
669
- typedef BlockParser<Payload, SectionParser<Payload> > PayloadParser;
563
+
564
+ /** Payload Section Parser */
565
+ typedef SectionParser<Payload, ListSectionAdapter> PayloadParser;
670
566
  }
671
567
 
672
568
  #endif