redsnow 0.0.8

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