void HighlightStateBuilder::build(DelimitedLangElem *elem, HighlightState *state) { const string &name = elem->getName(); StringDef *start = elem->getStart(); StringDef *end = elem->getEnd(); StringDef *escape = elem->getEscape(); string start_string = (start ? start->toString() : ""); string end_string = (end ? end->toString() : ""); string escape_string = (escape ? escape->toString() : ""); if (elem->isNested() && start_string == end_string) { // the two delimiters must be different for nested elements throw HighlightBuilderException( "delimiters must be different for nested elements", elem); } bool end_string_has_references = false; // check possible back reference markers and their correctness if (end && end->hasBackRef() && end_string.size()) { backreference_info ref_info = RegexPreProcessor::num_of_references( end_string); subexpressions_info info = RegexPreProcessor::num_of_marked_subexpressions(start_string, true, true); // possible errors, e.g., unbalanced parenthesis if (info.errors.size()) { throw HighlightBuilderException(info.errors, elem); } // check that there are enough subexpressions as requested by the maximal // back reference number unsigned int max = ref_info.second; if (max > info.marked) { std::ostringstream error; error << max << " subexpressions requested, but only " << info.marked << " found"; throw HighlightBuilderException(error.str(), elem); } end_string_has_references = true; } HighlightRulePtr rule; // if this element starts a new state/environment, we must split it if (elem->getStateLangElem() || elem->isMultiline() || end_string_has_references) { rule = HighlightRulePtr(highlightRuleFactory->createMultiLineRule(name, start_string, end_string, escape_string, elem->isNested())); if (end_string_has_references) { // record that the state (and the rule representing the end) // need to have dynamic back references replaced rule->getNextState()->setNeedsReferenceReplacement(); rule->getNextState()->getRuleList().front()->setNeedsReferenceReplacement(); // and that the starting rule has sub expressions // (that will be used for replacing dynamic back references) rule->setHasSubexpressions(); // if the element is nested, then the last rule is a sort of copy // of the first one, so we need to record that it has subexpressions too if (elem->isNested()) { rule->getNextState()->getRuleList().back()->setHasSubexpressions(); } } } else { rule = HighlightRulePtr(highlightRuleFactory->createLineRule(name, start_string, end_string, escape_string, elem->isNested())); } rule->setAdditionalInfo(elem->toStringParserInfo()); state->addRule(rule); if (rule->getNextState().get()) { // as for exit level, if the rule was split using states, we must set // the exit level of the first rule of the next state (i.e., the end expression) of the rule // this exit level must be incremented by one: 1 is for exiting the inner state // of the rule, and 1 for exiting the state this rule belongs to setExitLevel(elem, rule->getNextState()->getRuleList().front().get(), 1); // adjust the additional info of the exiting rule rule->getNextState()->getRuleList().front()->setAdditionalInfo( elem->toStringParserInfo()); // since this is a delimited element, we must set the default element for // the inner state to the name of the element itself rule->getNextState()->setDefaultElement(name); } else { setExitLevel(elem, rule.get()); } }