bool Command::hasArg(const String& str) { for(Shard *it = first(); it; it = it->next()) { Block *block = (Block*) it->first(); if(!block || block->type() != BLOCK) continue; for(Shard *arg = block->first(); arg; arg = arg->next()) { // Blocks have only Tokens as children! if(((Token*)arg)->token() == str) return true; } } return false; }
Token *Command::arg(int idx) { for(Shard *it = first(); it; it = it->next()) { if(idx--) continue; it = it->first(); if(!it || it->type() != BLOCK) break; return (Token*) it->first(); } return 0; }
Macro::Macro(const String& n, Shard *macroShard, const String& args) : Linkable() { _name = n; _argTypes = args; if (macroShard) { // Steal macroShard's children. Shard *next; for (Shard *it = macroShard->first(); it; it = next) { next = it->next(); _shard.add(macroShard->remove(it)); } } }
/** * An exception will be thrown if there is an error. */ void RuleSet::generateRule(Command *command) { Rule *rule; Shard *it; GemTest *terms; // Create the rule object. if(command->isName("format")) { rule = new FormatRule(((Block*)command->last()->first())->collect()); } else { rule = new LengthRule; } terms = &rule->terms(); // Compile the terms (command -> shards -> blocks -> tokens). for(it = command->first(); it && it != command->last(); it = it->next()) { if(!it->first()) continue; terms->addBefore(new GemTest((Token*)it->first()->first())); } if(command->isName("format")) { // There must not be format rules with matching terms. removeMatching(*terms, Rule::FORMAT); add(rule); } else { add(rule); Length *len = &((LengthRule*)rule)->length(); // Set the lengths that were given. // Get last argument -> block -> first token. len->init((Token*)command->last()->first()->first()); // Was this all for naught? if(len->isClear()) delete remove(rule); } }
void GemTest::init(Token *first) { enum testArgType_e { TA_NONE = 0, TA_NUMBER, TA_TEXT}; struct { const char *name; GemTestID cmdId; testArgType_e argType; } tests[] = { { "try", BeginTry, TA_NONE }, { "pass", CheckIfPassed, TA_NONE }, { "top", IsTop, TA_NONE }, { "me", IsMe, TA_NONE }, { "myparent", IsMyParent, TA_NONE }, { "myancestor", IsMyAncestor, TA_NONE }, { "break", IsBreak, TA_NONE }, { "br", IsLineBreak, TA_NONE }, { "control", IsControl, TA_NONE }, { "@", GoSelf, TA_NONE }, { "final", GoFinal, TA_NONE }, { "child", NthChild, TA_NUMBER }, { "order", NthOrder, TA_NUMBER }, { "count", ChildCount, TA_NUMBER }, { "width", CellWidth, TA_NUMBER }, { "text", Text, TA_TEXT }, { "begins", TextBegins, TA_TEXT }, { 0, InvalidGemTest, TA_NONE } }; struct { const char *condition; GemClass::GemType type; } gemTypes[] = { { "gem", GemClass::Gem }, { "indent", GemClass::Indent }, { "list", GemClass::List }, { "deflist", GemClass::DefinitionList }, { "table", GemClass::Table }, { "part", GemClass::PartTitle }, { "chapter", GemClass::ChapterTitle }, { "section", GemClass::SectionTitle }, { "subsec", GemClass::SubSectionTitle }, { "sub2sec", GemClass::Sub2SectionTitle }, { "sub3sec", GemClass::Sub3SectionTitle }, { "sub4sec", GemClass::Sub4SectionTitle }, { "contents", GemClass::Contents }, { 0, GemClass::None } }; struct { const char* condition; GemClass::FlushMode mode; } gemFlushModes[] = { { "left", GemClass::FlushLeft }, { "right", GemClass::FlushRight }, { "center", GemClass::FlushCenter }, { 0, GemClass::FlushInherit } }; int i; // Destroy existing commands. _commands.destroy(); // Next we'll convert all the shards to test commands. for(Shard *it = first; it; it = it->next()) { String con = ((Token*)it)->unEscape(); if(con.isEmpty()) continue; // This'll report unknown commands. _addedBit = false; // Normally 'false' is the failing condition. _failBit = false; while(con[0] == '!') { // Use a negative test. con.remove(0, 1); _failBit = !_failBit; } // Check for escalation. _escalateBit = false; if(con[0] == '^') { con.remove(0, 1); _escalateBit = true; } // Navigation of the test pointer. if((i = CompareCount(con, "parent"))) newTest(GoParent, i); else if((i = CompareCount(con, "next"))) newTest(GoNext, i); else if((i = CompareCount(con, "prev"))) newTest(GoPrev, i); else if((i = CompareCount(con, "first"))) newTest(GoFirst, i); else if((i = CompareCount(con, "last"))) newTest(GoLast, i); else if((i = CompareCount(con, "following"))) newTest(GoFollowing, i); else if((i = CompareCount(con, "preceding"))) newTest(GoPreceding, i); for(i = 0; tests[i].name; i++) if(con == tests[i].name) { if(tests[i].argType == TA_NUMBER) { int arg = 0; if(it->next()) { it = it->next(); arg = ((Token*)it)->token().toInt(); } newTest(tests[i].cmdId, arg); } else if(tests[i].argType == TA_TEXT) { String txt; if(it->next()) { it = it->next(); txt = ((Token*)it)->unEscape(); } newTest(tests[i].cmdId, 0, txt); } else { newTest(tests[i].cmdId); } break; } // Types. for(i = 0; gemTypes[i].condition; i++) if(con == gemTypes[i].condition) { newTest(GemType, gemTypes[i].type); break; } // Flush modes. for(i = 0; gemFlushModes[i].condition; ++i) if(con == gemFlushModes[i].condition) { newTest(GemFlushMode, gemFlushModes[i].mode); break; } // Flags that must be present. String lowCon = stringCase(con, LOWERCASE_ALL); bool checkForJust = con[0].isUpper(); if((i = styleForName(lowCon))) { newTest(checkForJust? ExclusiveFlag : HasFlag, i); } if(!_addedBit) { // Print a warning message. qWarning() << con << ": Unknown test command."; } } }