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;