redsnow 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -0
  3. data/ext/snowcrash/Makefile +1 -1
  4. data/ext/snowcrash/bin/snowcrash +0 -0
  5. data/ext/snowcrash/configure +9 -9
  6. data/ext/snowcrash/ext/markdown-parser/Makefile +87 -0
  7. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/CONTRIBUTING.md +0 -0
  8. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/Makefile +2 -1
  9. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/Makefile.win +0 -0
  10. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/examples/smartypants.c +0 -0
  11. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/examples/sundown.c +0 -0
  12. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini.h +0 -0
  13. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini_href_e.c +0 -0
  14. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini_html_e.c +0 -0
  15. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html.c +0 -0
  16. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html.h +0 -0
  17. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html_smartypants.c +0 -0
  18. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html_block_names.txt +0 -0
  19. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/autolink.c +0 -0
  20. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/autolink.h +0 -0
  21. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/buffer.c +0 -0
  22. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/buffer.h +1 -1
  23. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/html_blocks.h +0 -0
  24. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/markdown.c +9 -3
  25. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/markdown.h +0 -0
  26. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/src_map.c +11 -7
  27. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/src_map.h +1 -1
  28. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/stack.c +0 -0
  29. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/stack.h +0 -0
  30. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/sundown.def +0 -0
  31. data/ext/snowcrash/ext/markdown-parser/msvc/markdown/markdown.vcproj +188 -0
  32. data/ext/snowcrash/ext/markdown-parser/msvc/msvc.sln +38 -0
  33. data/ext/snowcrash/ext/markdown-parser/msvc/sundown/sundown.vcproj +206 -0
  34. data/ext/snowcrash/ext/markdown-parser/src/ByteBuffer.cc +92 -0
  35. data/ext/snowcrash/ext/markdown-parser/src/ByteBuffer.h +82 -0
  36. data/ext/snowcrash/ext/markdown-parser/src/MarkdownNode.cc +152 -0
  37. data/ext/snowcrash/ext/markdown-parser/src/MarkdownNode.h +103 -0
  38. data/ext/snowcrash/ext/markdown-parser/src/MarkdownParser.cc +388 -0
  39. data/ext/snowcrash/{src → ext/markdown-parser/src}/MarkdownParser.h +43 -33
  40. data/ext/snowcrash/snowcrash.gyp +114 -63
  41. data/ext/snowcrash/src/ActionParser.h +334 -398
  42. data/ext/snowcrash/src/AssetParser.h +82 -171
  43. data/ext/snowcrash/src/Blueprint.h +7 -2
  44. data/ext/snowcrash/src/BlueprintParser.h +212 -286
  45. data/ext/snowcrash/src/BlueprintUtility.h +2 -2
  46. data/ext/snowcrash/src/CBlueprint.h +1 -1
  47. data/ext/snowcrash/src/CSourceAnnotation.cc +11 -11
  48. data/ext/snowcrash/src/CSourceAnnotation.h +9 -9
  49. data/ext/snowcrash/src/CodeBlockUtility.h +199 -149
  50. data/ext/snowcrash/src/HeadersParser.h +197 -0
  51. data/ext/snowcrash/src/ParameterParser.h +429 -0
  52. data/ext/snowcrash/src/ParametersParser.h +136 -211
  53. data/ext/snowcrash/src/PayloadParser.h +458 -562
  54. data/ext/snowcrash/src/Platform.h +0 -3
  55. data/ext/snowcrash/src/ResourceGroupParser.h +183 -164
  56. data/ext/snowcrash/src/ResourceParser.h +325 -493
  57. data/ext/snowcrash/src/Section.cc +42 -0
  58. data/ext/snowcrash/src/Section.h +47 -0
  59. data/ext/snowcrash/src/SectionParser.h +229 -0
  60. data/ext/snowcrash/src/SectionParserData.h +81 -0
  61. data/ext/snowcrash/src/SectionProcessor.h +211 -0
  62. data/ext/snowcrash/src/Signature.cc +74 -0
  63. data/ext/snowcrash/src/Signature.h +32 -0
  64. data/ext/snowcrash/src/SourceAnnotation.h +7 -20
  65. data/ext/snowcrash/src/StringUtility.h +30 -10
  66. data/ext/snowcrash/src/SymbolTable.h +7 -7
  67. data/ext/snowcrash/src/UriTemplateParser.cc +10 -10
  68. data/ext/snowcrash/src/UriTemplateParser.h +11 -14
  69. data/ext/snowcrash/src/ValuesParser.h +122 -0
  70. data/ext/snowcrash/src/Version.h +2 -2
  71. data/ext/snowcrash/src/csnowcrash.cc +5 -5
  72. data/ext/snowcrash/src/csnowcrash.h +3 -3
  73. data/ext/snowcrash/src/snowcrash.cc +74 -4
  74. data/ext/snowcrash/src/snowcrash.h +9 -4
  75. data/ext/snowcrash/src/snowcrash/snowcrash.cc +16 -16
  76. data/ext/snowcrash/tools/homebrew/snowcrash.rb +3 -2
  77. data/ext/snowcrash/vcbuild.bat +13 -4
  78. data/lib/redsnow.rb +5 -5
  79. data/lib/redsnow/binding.rb +1 -1
  80. data/lib/redsnow/blueprint.rb +33 -2
  81. data/lib/redsnow/parseresult.rb +7 -4
  82. data/lib/redsnow/version.rb +1 -1
  83. data/test/redsnow_binding_test.rb +6 -6
  84. data/test/redsnow_parseresult_test.rb +1 -1
  85. metadata +62 -42
  86. data/ext/snowcrash/src/BlockUtility.h +0 -186
  87. data/ext/snowcrash/src/BlueprintParserCore.h +0 -190
  88. data/ext/snowcrash/src/BlueprintSection.h +0 -140
  89. data/ext/snowcrash/src/DescriptionSectionUtility.h +0 -156
  90. data/ext/snowcrash/src/HeaderParser.h +0 -289
  91. data/ext/snowcrash/src/ListBlockUtility.h +0 -273
  92. data/ext/snowcrash/src/ListUtility.h +0 -95
  93. data/ext/snowcrash/src/MarkdownBlock.cc +0 -176
  94. data/ext/snowcrash/src/MarkdownBlock.h +0 -93
  95. data/ext/snowcrash/src/MarkdownParser.cc +0 -266
  96. data/ext/snowcrash/src/ParameterDefinitonParser.h +0 -645
  97. data/ext/snowcrash/src/Parser.cc +0 -71
  98. data/ext/snowcrash/src/Parser.h +0 -29
  99. data/ext/snowcrash/src/ParserCore.cc +0 -120
  100. data/ext/snowcrash/src/ParserCore.h +0 -82
  101. data/ext/snowcrash/src/SectionUtility.h +0 -142
@@ -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