ext/snowcrash/src/BlueprintParser.h in redsnow-0.2.1 vs ext/snowcrash/src/BlueprintParser.h in redsnow-0.3.0
- old
+ new
@@ -30,18 +30,19 @@
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
const MarkdownNodes& siblings,
SectionParserData& pd,
SectionLayout& layout,
- ParseResult<Blueprint>& out) {
+ const ParseResultRef<Blueprint>& out) {
MarkdownNodeIterator cur = node;
while (cur != siblings.end() &&
cur->type == mdp::ParagraphMarkdownNodeType) {
- ParseResult<MetadataCollection> metadata(out.report);
+ IntermediateParseResult<MetadataCollection> metadata(out.report);
+
parseMetadata(cur, pd, metadata);
// First block is paragraph and is not metadata (no API name)
if (metadata.node.empty()) {
return processDescription(cur, siblings, pd, out);
@@ -55,11 +56,11 @@
}
}
cur++;
}
-
+
// Ideally this parsing metadata should be handled by separate parser
// that way the following check would be covered in SectionParser::parse()
if (cur == siblings.end())
return cur;
@@ -89,16 +90,17 @@
}
static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
const MarkdownNodes& siblings,
SectionParserData& pd,
- ParseResult<Blueprint>& out) {
+ const ParseResultRef<Blueprint>& out) {
if (pd.sectionContext() == ResourceGroupSectionType ||
pd.sectionContext() == ResourceSectionType) {
- ParseResult<ResourceGroup> resourceGroup(out.report);
+ IntermediateParseResult<ResourceGroup> resourceGroup(out.report);
+
MarkdownNodeIterator cur = ResourceGroupParser::parse(node, siblings, pd, resourceGroup);
ResourceGroupIterator duplicate = findResourceGroup(out.node.resourceGroups, resourceGroup.node);
if (duplicate != out.node.resourceGroups.end()) {
@@ -169,23 +171,25 @@
return nested;
}
static void finalize(const MarkdownNodeIterator& node,
SectionParserData& pd,
- ParseResult<Blueprint>& out) {
-
+ const ParseResultRef<Blueprint>& out) {
+
+ checkLazyReferencing(pd, out);
+
if (!out.node.name.empty())
return;
if (pd.options & RequireBlueprintNameOption) {
// ERR: No API name specified
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
out.report.error = Error(ExpectedAPINameMessage,
BusinessError,
sourceMap);
-
+
}
else if (!out.node.description.empty()) {
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
out.report.warnings.push_back(Warning(ExpectedAPINameMessage,
APINameWarning,
@@ -193,19 +197,19 @@
}
}
static bool isUnexpectedNode(const MarkdownNodeIterator& node,
SectionType sectionType) {
-
+
// Since Blueprint is currently top-level node any unprocessed node should be reported
return true;
}
static void parseMetadata(const MarkdownNodeIterator& node,
SectionParserData& pd,
- ParseResult<MetadataCollection>& out) {
+ const ParseResultRef<MetadataCollection>& out) {
mdp::ByteBuffer content = node->text;
TrimStringEnd(content);
std::vector<mdp::ByteBuffer> lines = Split(content, '\n');
@@ -275,9 +279,214 @@
const ResourceGroup& resourceGroup) {
return std::find_if(resourceGroups.begin(),
resourceGroups.end(),
std::bind2nd(MatchName<ResourceGroup>(), resourceGroup));
+ }
+
+ /**
+ * \brief Checks both blueprint and source map AST to resolve references with `Pending` state (Lazy referencing)
+ * \param pd Section parser state
+ * \param out Processed output
+ */
+ static void checkLazyReferencing(SectionParserData& pd,
+ const ParseResultRef<Blueprint>& out) {
+
+ Collection<SourceMap<ResourceGroup> >::iterator resourceGroupSourceMapIt;
+
+ if (pd.exportSourceMap()) {
+ resourceGroupSourceMapIt = out.sourceMap.resourceGroups.collection.begin();
+ }
+
+ for (ResourceGroups::iterator resourceGroupIt = out.node.resourceGroups.begin();
+ resourceGroupIt != out.node.resourceGroups.end();
+ ++resourceGroupIt) {
+
+ checkResourceLazyReferencing(*resourceGroupIt, resourceGroupSourceMapIt, pd, out);
+
+ if (pd.exportSourceMap()) {
+ resourceGroupSourceMapIt++;
+ }
+ }
+ }
+
+ /** Traverses Resource Collection to resolve references with `Pending` state (Lazy referencing) */
+ static void checkResourceLazyReferencing(ResourceGroup& resourceGroup,
+ Collection<SourceMap<ResourceGroup> >::iterator resourceGroupSourceMapIt,
+ SectionParserData& pd,
+ const ParseResultRef<Blueprint>& out) {
+
+ Collection<SourceMap<Resource> >::iterator resourceSourceMapIt;
+
+ if (pd.exportSourceMap()) {
+ resourceSourceMapIt = resourceGroupSourceMapIt->resources.collection.begin();
+ }
+
+ for (Resources::iterator resourceIt = resourceGroup.resources.begin();
+ resourceIt != resourceGroup.resources.end();
+ ++resourceIt) {
+
+ checkActionLazyReferencing(*resourceIt, resourceSourceMapIt, pd, out);
+
+ if (pd.exportSourceMap()) {
+ resourceSourceMapIt++;
+ }
+ }
+ }
+
+ /** Traverses Action Collection to resolve references with `Pending` state (Lazy referencing) */
+ static void checkActionLazyReferencing(Resource& resource,
+ Collection<SourceMap<Resource> >::iterator resourceSourceMapIt,
+ SectionParserData& pd,
+ const ParseResultRef<Blueprint>& out) {
+
+ Collection<SourceMap<Action> >::iterator actionSourceMapIt;
+
+ if (pd.exportSourceMap()) {
+ actionSourceMapIt = resourceSourceMapIt->actions.collection.begin();
+ }
+
+ for (Actions::iterator actionIt = resource.actions.begin();
+ actionIt != resource.actions.end();
+ ++actionIt) {
+
+ checkExampleLazyReferencing(*actionIt, actionSourceMapIt, pd, out);
+
+ if (pd.exportSourceMap()) {
+ actionSourceMapIt++;
+ }
+ }
+ }
+
+ /** Traverses Transaction Example Collection AST to resolve references with `Pending` state (Lazy referencing) */
+ static void checkExampleLazyReferencing(Action& action,
+ Collection<SourceMap<Action> >::iterator actionSourceMapIt,
+ SectionParserData& pd,
+ const ParseResultRef<Blueprint>& out) {
+
+ Collection<SourceMap<TransactionExample> >::iterator exampleSourceMapIt;
+
+ if (pd.exportSourceMap()) {
+ exampleSourceMapIt = actionSourceMapIt->examples.collection.begin();
+ }
+
+ for (TransactionExamples::iterator transactionExampleIt = action.examples.begin();
+ transactionExampleIt != action.examples.end();
+ ++transactionExampleIt) {
+
+ checkRequestLazyReferencing(*transactionExampleIt, exampleSourceMapIt, pd, out);
+ checkResponseLazyReferencing(*transactionExampleIt, exampleSourceMapIt, pd, out);
+
+ if (pd.exportSourceMap()) {
+ exampleSourceMapIt++;
+ }
+ }
+ }
+
+ /** Traverses Request Collection to resolve references with `Pending` state (Lazy referencing) */
+ static void checkRequestLazyReferencing(TransactionExample& transactionExample,
+ Collection<SourceMap<TransactionExample> >::iterator transactionExampleSourceMapIt,
+ SectionParserData& pd,
+ const ParseResultRef<Blueprint>& out) {
+
+ Collection<SourceMap<Request> >::iterator requestSourceMapIt;
+
+ if (pd.exportSourceMap()) {
+ requestSourceMapIt = transactionExampleSourceMapIt->requests.collection.begin();
+ }
+
+ for (Requests::iterator requestIt = transactionExample.requests.begin();
+ requestIt != transactionExample.requests.end();
+ ++requestIt) {
+
+ if (!requestIt->reference.id.empty() &&
+ requestIt->reference.meta.state == Reference::StatePending) {
+
+ if (pd.exportSourceMap()) {
+
+ ParseResultRef<Payload> payload(out.report, *requestIt, *requestSourceMapIt);
+ resolvePendingSymbols(pd, payload);
+ SectionProcessor<Payload>::checkRequest(requestIt->reference.meta.node, pd, payload);
+ }
+ else {
+
+ SourceMap<Payload> tempSourceMap;
+ ParseResultRef<Payload> payload(out.report, *requestIt, tempSourceMap);
+ resolvePendingSymbols(pd, payload);
+ SectionProcessor<Payload>::checkRequest(requestIt->reference.meta.node, pd, payload);
+ }
+ }
+
+ if (pd.exportSourceMap()) {
+ requestSourceMapIt++;
+ }
+ }
+ }
+
+ /** Traverses Response Collection to resolve references with `Pending` state (Lazy referencing) */
+ static void checkResponseLazyReferencing(TransactionExample& transactionExample,
+ Collection<SourceMap<TransactionExample> >::iterator transactionExampleSourceMapIt,
+ SectionParserData& pd,
+ const ParseResultRef<Blueprint>& out) {
+
+ Collection<SourceMap<Response> >::iterator responseSourceMapIt;
+
+ if (pd.exportSourceMap()) {
+ responseSourceMapIt = transactionExampleSourceMapIt->responses.collection.begin();
+ }
+
+ for (Responses::iterator responseIt = transactionExample.responses.begin();
+ responseIt != transactionExample.responses.end();
+ ++responseIt) {
+
+ if (!responseIt->reference.id.empty() &&
+ responseIt->reference.meta.state == Reference::StatePending) {
+
+ if (pd.exportSourceMap()) {
+
+ ParseResultRef<Payload> payload(out.report, *responseIt, *responseSourceMapIt);
+ resolvePendingSymbols(pd, payload);
+ SectionProcessor<Payload>::checkResponse(responseIt->reference.meta.node, pd, payload);
+ }
+ else {
+
+ SourceMap<Payload> tempSourceMap;
+ ParseResultRef<Payload> payload(out.report, *responseIt, tempSourceMap);
+ resolvePendingSymbols(pd, payload);
+ SectionProcessor<Payload>::checkResponse(responseIt->reference.meta.node, pd, payload);
+ }
+ }
+
+ if (pd.exportSourceMap()) {
+ responseSourceMapIt++;
+ }
+ }
+ }
+
+ /**
+ * \brief Resolve pending references
+ * \param pd Section parser state
+ * \param out Processed output
+ */
+ static void resolvePendingSymbols(SectionParserData& pd,
+ const ParseResultRef<Payload>& out) {
+
+ if (pd.symbolTable.resourceModels.find(out.node.reference.id) == pd.symbolTable.resourceModels.end()) {
+
+ // ERR: Undefined symbol
+ std::stringstream ss;
+ ss << "Undefined symbol " << out.node.reference.id;
+
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(out.node.reference.meta.node->sourceMap, pd.sourceData);
+ out.report.error = Error(ss.str(), SymbolError, sourceMap);
+
+ out.node.reference.meta.state = Reference::StateUnresolved;
+ }
+ else {
+
+ out.node.reference.meta.state = Reference::StateResolved;
+ SectionProcessor<Payload>::assingReferredPayload(pd, out);
+ }
}
};
/** Blueprint Parser */
typedef SectionParser<Blueprint, BlueprintSectionAdapter> BlueprintParser;