diff --git a/Makefile b/Makefile index 36b760b048..975ca92b9c 100644 --- a/Makefile +++ b/Makefile @@ -447,3 +447,27 @@ support/ui: wiki/UpcomingCards.wiki: cards/new.txt echo "#summary New cards in the next release" > $@ cat <(echo "{{{") $^ <(echo "}}}") >> $@ + +parser/test: $(MAG) grammar/parsable.txt + $(JAVA) magic.grammar.Check < $(word 2,$^) + +parser/test_all: $(MAG) grammar/rules.txt + $(JAVA) magic.grammar.Check < $(word 2,$^) + +parser/run: $(MAG) + $(JAVA) magic.grammar.Check + +grammar/parsable.txt: grammar/mtg.peg + make parser/test_all > grammar/test_all.out + cat grammar/test_all.out | grep PARSED | sed 's/PARSED: //' | sort | uniq > $@ + cat grammar/test_all.out | grep FAILED | sort | uniq -c | sort -n > grammar/failed.txt + +src/magic/grammar/MagicRuleParser.java: grammar/mtg.peg + java -cp lib/Mouse-1.5.1.jar mouse.Generate -M -G $^ -P MagicRuleParser -S MagicSyntaxTree -p magic.grammar -r magic.grammar + mv MagicRuleParser.java $@ + sed -i 's/accept()/sem.action() \&\& accept()/g' $@ + +grammar/CounterType: grammar/rules.txt + grep -o "[^ ]* counter \(on\|from\)" $@ | cut -d' ' -f1 | sort | uniq > $@ + # remove a, each, that + # add poison diff --git a/grammar/Check.java b/src/magic/grammar/Check.java similarity index 90% rename from grammar/Check.java rename to src/magic/grammar/Check.java index d894f8edf5..bd32b9ee8b 100644 --- a/grammar/Check.java +++ b/src/magic/grammar/Check.java @@ -1,4 +1,6 @@ -import mouse.runtime.SourceString; +package magic.grammar; + +import magic.grammar.SourceString; import java.util.Scanner; class Check { diff --git a/src/magic/grammar/CurrentRule.java b/src/magic/grammar/CurrentRule.java new file mode 100644 index 0000000000..1023a7c10e --- /dev/null +++ b/src/magic/grammar/CurrentRule.java @@ -0,0 +1,57 @@ +//========================================================================= +// +// Part of PEG parser generator Mouse. +// +// Copyright (C) 2009 by Roman R. Redziejowski (www.romanredz.se). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//------------------------------------------------------------------------- +// +// Change log +// 090701 License changed by the author to Apache v.2. +// 090717 Name changed from 'Parser' to 'CurrentRule'. +// +//========================================================================= + +package magic.grammar; + + +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +// +// Current Rule seen by a semantic action +// +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + +public interface CurrentRule +{ + //------------------------------------------------------------------- + // Left-hand side. + //------------------------------------------------------------------- + Phrase lhs(); + + //------------------------------------------------------------------- + // Number of right-hand side items. + //------------------------------------------------------------------- + int rhsSize(); + + //------------------------------------------------------------------- + // i-th item on the right-hand side. + //------------------------------------------------------------------- + Phrase rhs(int i); + + //------------------------------------------------------------------- + // String represented by right-hand side items i through j-1. + //------------------------------------------------------------------- + String rhsText(int i,int j); +} diff --git a/src/magic/grammar/MagicRuleParser.java b/src/magic/grammar/MagicRuleParser.java new file mode 100644 index 0000000000..fb58ce183f --- /dev/null +++ b/src/magic/grammar/MagicRuleParser.java @@ -0,0 +1,4665 @@ +//========================================================================= +// +// This file was generated by Mouse 1.5 at 2012-12-13 05:52:01 GMT +// from grammar '/home/melvin/Modules/magarena/grammar/mtg.peg'. +// +//========================================================================= + +package magic.grammar; + +import magic.grammar.Source; + +public class MagicRuleParser extends magic.grammar.ParserMemo +{ + final MagicSyntaxTree sem; + + //======================================================================= + // + // Initialization + // + //======================================================================= + //------------------------------------------------------------------- + // Constructor + //------------------------------------------------------------------- + public MagicRuleParser() + { + sem = new MagicSyntaxTree(); + sem.rule = this; + super.sem = sem; + caches = cacheList; + } + + //------------------------------------------------------------------- + // Run the parser + //------------------------------------------------------------------- + public boolean parse(Source src) + { + super.init(src); + sem.init(); + if (Rule()) return true; + return failure(); + } + + //------------------------------------------------------------------- + // Get semantics + //------------------------------------------------------------------- + public MagicSyntaxTree semantics() + { return sem; } + + //======================================================================= + // + // Parsing procedures + // + //======================================================================= + //===================================================================== + // Rule = (AbilityWord " \u2014 ")? Ability EOR ; + //===================================================================== + private boolean Rule() + { + if (saved(Rule)) return reuse(); + Rule_0(); + if (!Ability()) return reject(); + if (!EOR()) return reject(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // Rule_0 = AbilityWord " \u2014 " + //------------------------------------------------------------------- + private boolean Rule_0() + { + if (savedInner(Rule_0)) return reuseInner(); + if (!AbilityWord()) return rejectInner(); + if (!next(" \u2014 ")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // Ability = SpellEffect / KeywordAbility / ActivatedAbility / + // TriggeredAbility / AdditionalCost ; + //===================================================================== + private boolean Ability() + { + if (saved(Ability)) return reuse(); + if (SpellEffect()) return sem.action() && accept(); + if (KeywordAbility()) return sem.action() && accept(); + if (ActivatedAbility()) return sem.action() && accept(); + if (TriggeredAbility()) return sem.action() && accept(); + if (AdditionalCost()) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // SpellEffect = Effect EOS (SPACE Effect EOS)* ; + //===================================================================== + private boolean SpellEffect() + { + if (saved(SpellEffect)) return reuse(); + if (!Effect()) return reject(); + if (!EOS()) return reject(); + while (SpellEffect_0()); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // SpellEffect_0 = SPACE Effect EOS + //------------------------------------------------------------------- + private boolean SpellEffect_0() + { + if (savedInner(SpellEffect_0)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!Effect()) return rejectInner(); + if (!EOS()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // Effect = SingleEffect (SEP SingleEffect)* ; + //===================================================================== + private boolean Effect() + { + if (saved(Effect)) return reuse(); + if (!SingleEffect()) return reject(); + while (Effect_0()); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // Effect_0 = SEP SingleEffect + //------------------------------------------------------------------- + private boolean Effect_0() + { + if (savedInner(Effect_0)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!SingleEffect()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SingleEffect = (Duration SEP)? (Optional SPACE)? (SelectPlayer + // SPACE)? (Optional SPACE)? Action (SPACE Duration)? ; + //===================================================================== + private boolean SingleEffect() + { + if (saved(SingleEffect)) return reuse(); + SingleEffect_0(); + SingleEffect_1(); + SingleEffect_2(); + SingleEffect_1(); + if (!Action()) return reject(); + SingleEffect_3(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // SingleEffect_0 = Duration SEP + //------------------------------------------------------------------- + private boolean SingleEffect_0() + { + if (savedInner(SingleEffect_0)) return reuseInner(); + if (!Duration()) return rejectInner(); + if (!SEP()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SingleEffect_1 = Optional SPACE + //------------------------------------------------------------------- + private boolean SingleEffect_1() + { + if (savedInner(SingleEffect_1)) return reuseInner(); + if (!Optional()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SingleEffect_2 = SelectPlayer SPACE + //------------------------------------------------------------------- + private boolean SingleEffect_2() + { + if (savedInner(SingleEffect_2)) return reuseInner(); + if (!SelectPlayer()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SingleEffect_3 = SPACE Duration + //------------------------------------------------------------------- + private boolean SingleEffect_3() + { + if (savedInner(SingleEffect_3)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!Duration()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // Optional = "you may have" / "you may" / "if you don't," / "if you + // can't," / "if you do," / "may" ; + //===================================================================== + private boolean Optional() + { + if (saved(Optional)) return reuse(); + if (next("you may have")) return sem.action() && accept(); + if (next("you may")) return sem.action() && accept(); + if (next("if you don't,")) return sem.action() && accept(); + if (next("if you can't,")) return sem.action() && accept(); + if (next("if you do,")) return sem.action() && accept(); + if (next("may")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // AbilityWord = "metalcraft" / "landfall" / "threshold" / "hellbent" + // / "morbid" ; + //===================================================================== + private boolean AbilityWord() + { + if (saved(AbilityWord)) return reuse(); + if (next("metalcraft")) return sem.action() && accept(); + if (next("landfall")) return sem.action() && accept(); + if (next("threshold")) return sem.action() && accept(); + if (next("hellbent")) return sem.action() && accept(); + if (next("morbid")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // KeywordAbility = Keyword / Enchant ; + //===================================================================== + private boolean KeywordAbility() + { + if (saved(KeywordAbility)) return reuse(); + if (Keyword()) return sem.action() && accept(); + if (Enchant()) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // ActivatedAbility = ActivationCosts EOC SpellEffect (SPACE + // AbilityRestriction EOS)? ; + //===================================================================== + private boolean ActivatedAbility() + { + if (saved(ActivatedAbility)) return reuse(); + if (!ActivationCosts()) return reject(); + if (!EOC()) return reject(); + if (!SpellEffect()) return reject(); + ActivatedAbility_0(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // ActivatedAbility_0 = SPACE AbilityRestriction EOS + //------------------------------------------------------------------- + private boolean ActivatedAbility_0() + { + if (savedInner(ActivatedAbility_0)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!AbilityRestriction()) return rejectInner(); + if (!EOS()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // ActivationCosts = Action (SEP Action)* ; + //===================================================================== + private boolean ActivationCosts() + { + if (saved(ActivationCosts)) return reuse(); + if (!Action()) return reject(); + while (ActivationCosts_0()); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // ActivationCosts_0 = SEP Action + //------------------------------------------------------------------- + private boolean ActivationCosts_0() + { + if (savedInner(ActivationCosts_0)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!Action()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // TriggeredAbility = Trigger (SEP IfCondition)? SEP SpellEffect ; + //===================================================================== + private boolean TriggeredAbility() + { + if (saved(TriggeredAbility)) return reuse(); + if (!Trigger()) return reject(); + TriggeredAbility_0(); + if (!SEP()) return reject(); + if (!SpellEffect()) return reject(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // TriggeredAbility_0 = SEP IfCondition + //------------------------------------------------------------------- + private boolean TriggeredAbility_0() + { + if (savedInner(TriggeredAbility_0)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!IfCondition()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // AdditionalCost = "as an additional cost to cast @, " Effect EOS ; + //===================================================================== + private boolean AdditionalCost() + { + if (saved(AdditionalCost)) return reuse(); + if (!next("as an additional cost to cast @, ")) return reject(); + if (!Effect()) return reject(); + if (!EOS()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // Trigger = EntersBattlefieldTrigger / LeavesBattlefieldTrigger / + // EntersGraveyardTrigger / BeginningUpkeepTrigger / + // BeginningEndStepTrigger / DiesTrigger / DealsDamageTrigger / + // CastTrigger / BecomesTargetTrigger / BlocksTrigger / + // AttacksTrigger / BlockedTrigger ; + //===================================================================== + private boolean Trigger() + { + if (saved(Trigger)) return reuse(); + if (EntersBattlefieldTrigger()) return sem.action() && accept(); + if (LeavesBattlefieldTrigger()) return sem.action() && accept(); + if (EntersGraveyardTrigger()) return sem.action() && accept(); + if (BeginningUpkeepTrigger()) return sem.action() && accept(); + if (BeginningEndStepTrigger()) return sem.action() && accept(); + if (DiesTrigger()) return sem.action() && accept(); + if (DealsDamageTrigger()) return sem.action() && accept(); + if (CastTrigger()) return sem.action() && accept(); + if (BecomesTargetTrigger()) return sem.action() && accept(); + if (BlocksTrigger()) return sem.action() && accept(); + if (AttacksTrigger()) return sem.action() && accept(); + if (BlockedTrigger()) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Action = DestroyNoRegenAction / DestroyAction / ExileAction / + // CounterAction / DamageAction / DrawAction / DiscardAction / + // TapAction / PreventAction / RegenerateAction / PumpAction / + // GainAction / BounceAction / AddManaAction / ReturnAction / + // SacrificeAction / ChangeLifeAction / ChangeCounterAction / + // PutTokenAction / PutCardAction / ControlAction / ShuffleAction / + // DoesntUntapAction / EntersTapped / EntersWithCounter / + // PayManaAction / MillAction / PoisonAction / SetPTAction / + // ChangeStateAction / AnimateAction / AnimateActionReminder / + // ChangeLoyaltyAction ; + //===================================================================== + private boolean Action() + { + if (saved(Action)) return reuse(); + if (DestroyNoRegenAction()) return sem.action() && accept(); + if (DestroyAction()) return sem.action() && accept(); + if (ExileAction()) return sem.action() && accept(); + if (CounterAction()) return sem.action() && accept(); + if (DamageAction()) return sem.action() && accept(); + if (DrawAction()) return sem.action() && accept(); + if (DiscardAction()) return sem.action() && accept(); + if (TapAction()) return sem.action() && accept(); + if (PreventAction()) return sem.action() && accept(); + if (RegenerateAction()) return sem.action() && accept(); + if (PumpAction()) return sem.action() && accept(); + if (GainAction()) return sem.action() && accept(); + if (BounceAction()) return sem.action() && accept(); + if (AddManaAction()) return sem.action() && accept(); + if (ReturnAction()) return sem.action() && accept(); + if (SacrificeAction()) return sem.action() && accept(); + if (ChangeLifeAction()) return sem.action() && accept(); + if (ChangeCounterAction()) return sem.action() && accept(); + if (PutTokenAction()) return sem.action() && accept(); + if (PutCardAction()) return sem.action() && accept(); + if (ControlAction()) return sem.action() && accept(); + if (ShuffleAction()) return sem.action() && accept(); + if (DoesntUntapAction()) return sem.action() && accept(); + if (EntersTapped()) return sem.action() && accept(); + if (EntersWithCounter()) return sem.action() && accept(); + if (PayManaAction()) return sem.action() && accept(); + if (MillAction()) return sem.action() && accept(); + if (PoisonAction()) return sem.action() && accept(); + if (SetPTAction()) return sem.action() && accept(); + if (ChangeStateAction()) return sem.action() && accept(); + if (AnimateAction()) return sem.action() && accept(); + if (AnimateActionReminder()) return sem.action() && accept(); + if (ChangeLoyaltyAction()) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Keyword = "flash" / "flying" / "haste" / "defender" / "vigilance" / + // "reach" / "battle cry" / "trample" / "first strike" / "double + // strike" / "infect" / "wither" / "fear" / "shadow" / "storm" / + // "swampwalk" / "plainswalk" / "forestwalk" / "islandwalk" / + // "mountainwalk" / "changeling" / "deathtouch" / "lifelink" / + // "exalted" / "shroud" / "persist" / "protection from all colors" / + // "protection from " Color / "protection from " Tribal / + // "protection from artifacts" / "protection from creatures" / + // "protection from everything" / "hexproof" / "soulbond" / + // "undying" / "flanking" / "intimidate" / "living weapon" / "totem + // armor" / "affinity for artifacts" / "bushido" SPACE Number / + // "rampage" SPACE Number / "soulshift" SPACE Number / "fading" + // SPACE Number / "devour" SPACE Number / "modular" SPACE Number / + // "vanishing" SPACE Number / "bloodthirst" SPACE Number / + // "annihilator" SPACE Number / "buyback" SPACE ManaCost / "echo" + // SPACE ManaCost / "kicker" SPACE ManaCost / "multikicker" SPACE + // ManaCost / "equip" SPACE ManaCost / "cumulative upkeep" SPACE + // ManaCost / "replicate" SPACE ManaCost / "miracle" SPACE ManaCost + // / "level up" SPACE ManaCost / "level" SPACE Number "-" Number / + // "level" SPACE Number "+" / "champion" SPACE "a" "n"? SPACE + // SelectCreature ; + //===================================================================== + private boolean Keyword() + { + if (saved(Keyword)) return reuse(); + if (next("flash")) return sem.action() && accept(); + if (next("flying")) return sem.action() && accept(); + if (next("haste")) return sem.action() && accept(); + if (next("defender")) return sem.action() && accept(); + if (next("vigilance")) return sem.action() && accept(); + if (next("reach")) return sem.action() && accept(); + if (next("battle cry")) return sem.action() && accept(); + if (next("trample")) return sem.action() && accept(); + if (next("first strike")) return sem.action() && accept(); + if (next("double strike")) return sem.action() && accept(); + if (next("infect")) return sem.action() && accept(); + if (next("wither")) return sem.action() && accept(); + if (next("fear")) return sem.action() && accept(); + if (next("shadow")) return sem.action() && accept(); + if (next("storm")) return sem.action() && accept(); + if (next("swampwalk")) return sem.action() && accept(); + if (next("plainswalk")) return sem.action() && accept(); + if (next("forestwalk")) return sem.action() && accept(); + if (next("islandwalk")) return sem.action() && accept(); + if (next("mountainwalk")) return sem.action() && accept(); + if (next("changeling")) return sem.action() && accept(); + if (next("deathtouch")) return sem.action() && accept(); + if (next("lifelink")) return sem.action() && accept(); + if (next("exalted")) return sem.action() && accept(); + if (next("shroud")) return sem.action() && accept(); + if (next("persist")) return sem.action() && accept(); + if (next("protection from all colors")) return sem.action() && accept(); + if (Keyword_0()) return sem.action() && accept(); + if (Keyword_1()) return sem.action() && accept(); + if (next("protection from artifacts")) return sem.action() && accept(); + if (next("protection from creatures")) return sem.action() && accept(); + if (next("protection from everything")) return sem.action() && accept(); + if (next("hexproof")) return sem.action() && accept(); + if (next("soulbond")) return sem.action() && accept(); + if (next("undying")) return sem.action() && accept(); + if (next("flanking")) return sem.action() && accept(); + if (next("intimidate")) return sem.action() && accept(); + if (next("living weapon")) return sem.action() && accept(); + if (next("totem armor")) return sem.action() && accept(); + if (next("affinity for artifacts")) return sem.action() && accept(); + if (Keyword_2()) return sem.action() && accept(); + if (Keyword_3()) return sem.action() && accept(); + if (Keyword_4()) return sem.action() && accept(); + if (Keyword_5()) return sem.action() && accept(); + if (Keyword_6()) return sem.action() && accept(); + if (Keyword_7()) return sem.action() && accept(); + if (Keyword_8()) return sem.action() && accept(); + if (Keyword_9()) return sem.action() && accept(); + if (Keyword_10()) return sem.action() && accept(); + if (Keyword_11()) return sem.action() && accept(); + if (Keyword_12()) return sem.action() && accept(); + if (Keyword_13()) return sem.action() && accept(); + if (Keyword_14()) return sem.action() && accept(); + if (Keyword_15()) return sem.action() && accept(); + if (Keyword_16()) return sem.action() && accept(); + if (Keyword_17()) return sem.action() && accept(); + if (Keyword_18()) return sem.action() && accept(); + if (Keyword_19()) return sem.action() && accept(); + if (Keyword_20()) return sem.action() && accept(); + if (Keyword_21()) return sem.action() && accept(); + if (Keyword_22()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // Keyword_0 = "protection from " Color + //------------------------------------------------------------------- + private boolean Keyword_0() + { + if (savedInner(Keyword_0)) return reuseInner(); + if (!next("protection from ")) return rejectInner(); + if (!Color()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_1 = "protection from " Tribal + //------------------------------------------------------------------- + private boolean Keyword_1() + { + if (savedInner(Keyword_1)) return reuseInner(); + if (!next("protection from ")) return rejectInner(); + if (!Tribal()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_2 = "bushido" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_2() + { + if (savedInner(Keyword_2)) return reuseInner(); + if (!next("bushido")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_3 = "rampage" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_3() + { + if (savedInner(Keyword_3)) return reuseInner(); + if (!next("rampage")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_4 = "soulshift" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_4() + { + if (savedInner(Keyword_4)) return reuseInner(); + if (!next("soulshift")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_5 = "fading" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_5() + { + if (savedInner(Keyword_5)) return reuseInner(); + if (!next("fading")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_6 = "devour" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_6() + { + if (savedInner(Keyword_6)) return reuseInner(); + if (!next("devour")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_7 = "modular" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_7() + { + if (savedInner(Keyword_7)) return reuseInner(); + if (!next("modular")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_8 = "vanishing" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_8() + { + if (savedInner(Keyword_8)) return reuseInner(); + if (!next("vanishing")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_9 = "bloodthirst" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_9() + { + if (savedInner(Keyword_9)) return reuseInner(); + if (!next("bloodthirst")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_10 = "annihilator" SPACE Number + //------------------------------------------------------------------- + private boolean Keyword_10() + { + if (savedInner(Keyword_10)) return reuseInner(); + if (!next("annihilator")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_11 = "buyback" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_11() + { + if (savedInner(Keyword_11)) return reuseInner(); + if (!next("buyback")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_12 = "echo" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_12() + { + if (savedInner(Keyword_12)) return reuseInner(); + if (!next("echo")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_13 = "kicker" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_13() + { + if (savedInner(Keyword_13)) return reuseInner(); + if (!next("kicker")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_14 = "multikicker" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_14() + { + if (savedInner(Keyword_14)) return reuseInner(); + if (!next("multikicker")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_15 = "equip" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_15() + { + if (savedInner(Keyword_15)) return reuseInner(); + if (!next("equip")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_16 = "cumulative upkeep" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_16() + { + if (savedInner(Keyword_16)) return reuseInner(); + if (!next("cumulative upkeep")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_17 = "replicate" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_17() + { + if (savedInner(Keyword_17)) return reuseInner(); + if (!next("replicate")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_18 = "miracle" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_18() + { + if (savedInner(Keyword_18)) return reuseInner(); + if (!next("miracle")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_19 = "level up" SPACE ManaCost + //------------------------------------------------------------------- + private boolean Keyword_19() + { + if (savedInner(Keyword_19)) return reuseInner(); + if (!next("level up")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_20 = "level" SPACE Number "-" Number + //------------------------------------------------------------------- + private boolean Keyword_20() + { + if (savedInner(Keyword_20)) return reuseInner(); + if (!next("level")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + if (!next('-')) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_21 = "level" SPACE Number "+" + //------------------------------------------------------------------- + private boolean Keyword_21() + { + if (savedInner(Keyword_21)) return reuseInner(); + if (!next("level")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Number()) return rejectInner(); + if (!next('+')) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Keyword_22 = "champion" SPACE "a" "n"? SPACE SelectCreature + //------------------------------------------------------------------- + private boolean Keyword_22() + { + if (savedInner(Keyword_22)) return reuseInner(); + if (!next("champion")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!next('a')) return rejectInner(); + next('n'); + if (!SPACE()) return rejectInner(); + if (!SelectCreature()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // ColorlessCost = "{" Number "}" / "{x}" ; + //===================================================================== + private boolean ColorlessCost() + { + if (saved(ColorlessCost)) return reuse(); + if (ColorlessCost_0()) return sem.action() && accept(); + if (next("{x}")) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // ColorlessCost_0 = "{" Number "}" + //------------------------------------------------------------------- + private boolean ColorlessCost_0() + { + if (savedInner(ColorlessCost_0)) return reuseInner(); + if (!next('{')) return rejectInner(); + if (!Number()) return rejectInner(); + if (!next('}')) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SingleColor = "{b}" / "{u}" / "{g}" / "{r}" / "{w}" ; + //===================================================================== + private boolean SingleColor() + { + if (saved(SingleColor)) return reuse(); + if (next("{b}")) return sem.action() && accept(); + if (next("{u}")) return sem.action() && accept(); + if (next("{g}")) return sem.action() && accept(); + if (next("{r}")) return sem.action() && accept(); + if (next("{w}")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // HybridSingleCost = "{g/u}" / "{g/w}" / "{r/g}" / "{r/w}" / "{u/r}" + // / "{u/b}" / "{b/g}" / "{b/r}" / "{w/b}" ; + //===================================================================== + private boolean HybridSingleCost() + { + if (saved(HybridSingleCost)) return reuse(); + if (next("{g/u}")) return sem.action() && accept(); + if (next("{g/w}")) return sem.action() && accept(); + if (next("{r/g}")) return sem.action() && accept(); + if (next("{r/w}")) return sem.action() && accept(); + if (next("{u/r}")) return sem.action() && accept(); + if (next("{u/b}")) return sem.action() && accept(); + if (next("{b/g}")) return sem.action() && accept(); + if (next("{b/r}")) return sem.action() && accept(); + if (next("{w/b}")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // ManaCost = ColorlessCost+ HybridSingleCost* SingleColor* / + // HybridSingleCost+ SingleColor* / SingleColor+ ; + //===================================================================== + private boolean ManaCost() + { + if (saved(ManaCost)) return reuse(); + if (ManaCost_0()) return sem.action() && accept(); + if (ManaCost_1()) return sem.action() && accept(); + if (ManaCost_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // ManaCost_0 = ColorlessCost+ HybridSingleCost* SingleColor* + //------------------------------------------------------------------- + private boolean ManaCost_0() + { + if (savedInner(ManaCost_0)) return reuseInner(); + if (!ColorlessCost()) return rejectInner(); + while (ColorlessCost()); + while (HybridSingleCost()); + while (SingleColor()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ManaCost_1 = HybridSingleCost+ SingleColor* + //------------------------------------------------------------------- + private boolean ManaCost_1() + { + if (savedInner(ManaCost_1)) return reuseInner(); + if (!HybridSingleCost()) return rejectInner(); + while (HybridSingleCost()); + while (SingleColor()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ManaCost_2 = SingleColor+ + //------------------------------------------------------------------- + private boolean ManaCost_2() + { + if (savedInner(ManaCost_2)) return reuseInner(); + if (!SingleColor()) return rejectInner(); + while (SingleColor()); + return acceptInner(); + } + + //===================================================================== + // BecomesTargetTrigger = "when @ becomes the target of a spell or + // ability" ; + //===================================================================== + private boolean BecomesTargetTrigger() + { + if (saved(BecomesTargetTrigger)) return reuse(); + if (!next("when @ becomes the target of a spell or ability")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // BlocksTrigger = "whenever @ blocks" ; + //===================================================================== + private boolean BlocksTrigger() + { + if (saved(BlocksTrigger)) return reuse(); + if (!next("whenever @ blocks")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // BlockedTrigger = "whenever @ becomes blocked" ; + //===================================================================== + private boolean BlockedTrigger() + { + if (saved(BlockedTrigger)) return reuse(); + if (!next("whenever @ becomes blocked")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // CastTrigger = "whenever " SelectPlayer SPACE Cast SPACE SelectSpell + // / "when " SelectPlayer SPACE Cast SPACE SelectSpell ; + //===================================================================== + private boolean CastTrigger() + { + if (saved(CastTrigger)) return reuse(); + if (CastTrigger_0()) return sem.action() && accept(); + if (CastTrigger_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // CastTrigger_0 = "whenever " SelectPlayer SPACE Cast SPACE + // SelectSpell + //------------------------------------------------------------------- + private boolean CastTrigger_0() + { + if (savedInner(CastTrigger_0)) return reuseInner(); + if (!next("whenever ")) return rejectInner(); + if (!SelectPlayer()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Cast()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!SelectSpell()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // CastTrigger_1 = "when " SelectPlayer SPACE Cast SPACE + // SelectSpell + //------------------------------------------------------------------- + private boolean CastTrigger_1() + { + if (savedInner(CastTrigger_1)) return reuseInner(); + if (!next("when ")) return rejectInner(); + if (!SelectPlayer()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Cast()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!SelectSpell()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // Cast = "cast" "s"? ; + //===================================================================== + private boolean Cast() + { + if (saved(Cast)) return reuse(); + if (!next("cast")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // LeavesBattlefieldTrigger = "when @ leaves the battlefield" ; + //===================================================================== + private boolean LeavesBattlefieldTrigger() + { + if (saved(LeavesBattlefieldTrigger)) return reuse(); + if (!next("when @ leaves the battlefield")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // EntersGraveyardTrigger = "when @ is put into a graveyard from the + // battlefield" / "when @ is put into a graveyard from anywhere" ; + //===================================================================== + private boolean EntersGraveyardTrigger() + { + if (saved(EntersGraveyardTrigger)) return reuse(); + if (next("when @ is put into a graveyard from the battlefield")) return sem.action() && accept(); + if (next("when @ is put into a graveyard from anywhere")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // EntersBattlefieldTrigger = EntersVerb SPACE SelectPermanent SPACE + // "enters the battlefield" (SPACE "under your control")? ; + //===================================================================== + private boolean EntersBattlefieldTrigger() + { + if (saved(EntersBattlefieldTrigger)) return reuse(); + if (!EntersVerb()) return reject(); + if (!SPACE()) return reject(); + if (!SelectPermanent()) return reject(); + if (!SPACE()) return reject(); + if (!next("enters the battlefield")) return reject(); + EntersBattlefieldTrigger_0(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // EntersBattlefieldTrigger_0 = SPACE "under your control" + //------------------------------------------------------------------- + private boolean EntersBattlefieldTrigger_0() + { + if (savedInner(EntersBattlefieldTrigger_0)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!next("under your control")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // EntersVerb = "whenever" / "when" / "as" ; + //===================================================================== + private boolean EntersVerb() + { + if (saved(EntersVerb)) return reuse(); + if (next("whenever")) return sem.action() && accept(); + if (next("when")) return sem.action() && accept(); + if (next("as")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // BeginningEndStepTrigger = "at the beginning of the end step" / "at + // the beginning of each end step" ; + //===================================================================== + private boolean BeginningEndStepTrigger() + { + if (saved(BeginningEndStepTrigger)) return reuse(); + if (next("at the beginning of the end step")) return sem.action() && accept(); + if (next("at the beginning of each end step")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // BeginningUpkeepTrigger = "at the beginning of your upkeep" / "at + // the beginning of each player's upkeep" ; + //===================================================================== + private boolean BeginningUpkeepTrigger() + { + if (saved(BeginningUpkeepTrigger)) return reuse(); + if (next("at the beginning of your upkeep")) return sem.action() && accept(); + if (next("at the beginning of each player's upkeep")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // DiesTrigger = "when" SPACE SelectCreature SPACE "dies" / "whenever" + // SPACE SelectCreature SPACE "dies" ; + //===================================================================== + private boolean DiesTrigger() + { + if (saved(DiesTrigger)) return reuse(); + if (DiesTrigger_0()) return sem.action() && accept(); + if (DiesTrigger_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // DiesTrigger_0 = "when" SPACE SelectCreature SPACE "dies" + //------------------------------------------------------------------- + private boolean DiesTrigger_0() + { + if (savedInner(DiesTrigger_0)) return reuseInner(); + if (!next("when")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!SelectCreature()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!next("dies")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DiesTrigger_1 = "whenever" SPACE SelectCreature SPACE "dies" + //------------------------------------------------------------------- + private boolean DiesTrigger_1() + { + if (savedInner(DiesTrigger_1)) return reuseInner(); + if (!next("whenever")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!SelectCreature()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!next("dies")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // DealsDamageTrigger = "whenever @ deals" " combat"? " damage" (" to + // a " DamageReceiver)? ; + //===================================================================== + private boolean DealsDamageTrigger() + { + if (saved(DealsDamageTrigger)) return reuse(); + if (!next("whenever @ deals")) return reject(); + next(" combat"); + if (!next(" damage")) return reject(); + DealsDamageTrigger_0(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // DealsDamageTrigger_0 = " to a " DamageReceiver + //------------------------------------------------------------------- + private boolean DealsDamageTrigger_0() + { + if (savedInner(DealsDamageTrigger_0)) return reuseInner(); + if (!next(" to a ")) return rejectInner(); + if (!DamageReceiver()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // DamageReceiver = "itself" / SelectPlayer &(SEP SingleEffect) / + // SelectPlayer (SEP SelectCreature)? / SelectCreature &(SEP + // SingleEffect) / SelectCreature (SEP SelectPlayer)? ; + //===================================================================== + private boolean DamageReceiver() + { + if (saved(DamageReceiver)) return reuse(); + if (next("itself")) return sem.action() && accept(); + if (DamageReceiver_0()) return sem.action() && accept(); + if (DamageReceiver_1()) return sem.action() && accept(); + if (DamageReceiver_2()) return sem.action() && accept(); + if (DamageReceiver_3()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // DamageReceiver_0 = SelectPlayer &(SEP SingleEffect) + //------------------------------------------------------------------- + private boolean DamageReceiver_0() + { + if (savedInner(DamageReceiver_0)) return reuseInner(); + if (!SelectPlayer()) return rejectInner(); + if (!DamageReceiver_4()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageReceiver_1 = SelectPlayer (SEP SelectCreature)? + //------------------------------------------------------------------- + private boolean DamageReceiver_1() + { + if (savedInner(DamageReceiver_1)) return reuseInner(); + if (!SelectPlayer()) return rejectInner(); + DamageReceiver_5(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageReceiver_2 = SelectCreature &(SEP SingleEffect) + //------------------------------------------------------------------- + private boolean DamageReceiver_2() + { + if (savedInner(DamageReceiver_2)) return reuseInner(); + if (!SelectCreature()) return rejectInner(); + if (!DamageReceiver_4()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageReceiver_3 = SelectCreature (SEP SelectPlayer)? + //------------------------------------------------------------------- + private boolean DamageReceiver_3() + { + if (savedInner(DamageReceiver_3)) return reuseInner(); + if (!SelectCreature()) return rejectInner(); + DamageReceiver_6(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageReceiver_4 = &(SEP SingleEffect) + //------------------------------------------------------------------- + private boolean DamageReceiver_4() + { + if (savedInner(DamageReceiver_4)) return reusePred(); + if (!Effect_0()) return rejectAnd(); + return acceptAnd(); + } + + //------------------------------------------------------------------- + // DamageReceiver_5 = SEP SelectCreature + //------------------------------------------------------------------- + private boolean DamageReceiver_5() + { + if (savedInner(DamageReceiver_5)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!SelectCreature()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageReceiver_6 = SEP SelectPlayer + //------------------------------------------------------------------- + private boolean DamageReceiver_6() + { + if (savedInner(DamageReceiver_6)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!SelectPlayer()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // AttacksTrigger = "whenever @ attacks" ; + //===================================================================== + private boolean AttacksTrigger() + { + if (saved(AttacksTrigger)) return reuse(); + if (!next("whenever @ attacks")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // AbilityRestriction = "activate this ability only any time you could + // cast a sorcery" / "activate this ability only if seven or more + // cards are in your graveyard" / "activate this ability only if you + // have no cards in hand" ; + //===================================================================== + private boolean AbilityRestriction() + { + if (saved(AbilityRestriction)) return reuse(); + if (next("activate this ability only any time you could cast a sorcery")) return sem.action() && accept(); + if (next("activate this ability only if seven or more cards are in your graveyard")) return sem.action() && accept(); + if (next("activate this ability only if you have no cards in hand")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // IfCondition = "if a creature died this turn" ; + //===================================================================== + private boolean IfCondition() + { + if (saved(IfCondition)) return reuse(); + if (!next("if a creature died this turn")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // AnimateAction = SelectPermanent " becomes a " CreatureSpec ; + //===================================================================== + private boolean AnimateAction() + { + if (saved(AnimateAction)) return reuse(); + if (!SelectPermanent()) return reject(); + if (!next(" becomes a ")) return reject(); + if (!CreatureSpec()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // AnimateActionReminder = "it's still a land" ; + //===================================================================== + private boolean AnimateActionReminder() + { + if (saved(AnimateActionReminder)) return reuse(); + if (!next("it's still a land")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // ChangeLoyaltyAction = SignedNumber / "0" ; + //===================================================================== + private boolean ChangeLoyaltyAction() + { + if (saved(ChangeLoyaltyAction)) return reuse(); + if (SignedNumber()) return sem.action() && accept(); + if (next('0')) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // ChangeStateAction = (SelectPermanent SPACE)? PermanentState ; + //===================================================================== + private boolean ChangeStateAction() + { + if (saved(ChangeStateAction)) return reuse(); + ChangeStateAction_0(); + if (!PermanentState()) return reject(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // ChangeStateAction_0 = SelectPermanent SPACE + //------------------------------------------------------------------- + private boolean ChangeStateAction_0() + { + if (savedInner(ChangeStateAction_0)) return reuseInner(); + if (!SelectPermanent()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // PermanentState = "can't attack or block" / "can't attack" / "can't + // block" / "is indestructible" / "are indestructible" / "is + // unblockable" / "are unblockable" / "attacks each turn if able" / + // "can't be countered" / "are " ColorSpec / "are " Tribal " in + // addition to their other creature types" ; + //===================================================================== + private boolean PermanentState() + { + if (saved(PermanentState)) return reuse(); + if (next("can't attack or block")) return sem.action() && accept(); + if (next("can't attack")) return sem.action() && accept(); + if (next("can't block")) return sem.action() && accept(); + if (next("is indestructible")) return sem.action() && accept(); + if (next("are indestructible")) return sem.action() && accept(); + if (next("is unblockable")) return sem.action() && accept(); + if (next("are unblockable")) return sem.action() && accept(); + if (next("attacks each turn if able")) return sem.action() && accept(); + if (next("can't be countered")) return sem.action() && accept(); + if (PermanentState_0()) return sem.action() && accept(); + if (PermanentState_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // PermanentState_0 = "are " ColorSpec + //------------------------------------------------------------------- + private boolean PermanentState_0() + { + if (savedInner(PermanentState_0)) return reuseInner(); + if (!next("are ")) return rejectInner(); + if (!ColorSpec()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // PermanentState_1 = "are " Tribal " in addition to their other + // creature types" + //------------------------------------------------------------------- + private boolean PermanentState_1() + { + if (savedInner(PermanentState_1)) return reuseInner(); + if (!next("are ")) return rejectInner(); + if (!Tribal()) return rejectInner(); + if (!next(" in addition to their other creature types")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SetPTAction = "@'s power and toughness are each equal to the number + // of " SelectPermanent / SelectPermanent " are " Number "/" Number + // ; + //===================================================================== + private boolean SetPTAction() + { + if (saved(SetPTAction)) return reuse(); + if (SetPTAction_0()) return sem.action() && accept(); + if (SetPTAction_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // SetPTAction_0 = "@'s power and toughness are each equal to the + // number of " SelectPermanent + //------------------------------------------------------------------- + private boolean SetPTAction_0() + { + if (savedInner(SetPTAction_0)) return reuseInner(); + if (!next("@'s power and toughness are each equal to the number of ")) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SetPTAction_1 = SelectPermanent " are " Number "/" Number + //------------------------------------------------------------------- + private boolean SetPTAction_1() + { + if (savedInner(SetPTAction_1)) return reuseInner(); + if (!SelectPermanent()) return rejectInner(); + if (!next(" are ")) return rejectInner(); + if (!Number()) return rejectInner(); + if (!next('/')) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SacrificeAction = "sacrifice" "s"? SPACE SelectPermanent (SPACE + // "unless you" SPACE Action)? ; + //===================================================================== + private boolean SacrificeAction() + { + if (saved(SacrificeAction)) return reuse(); + if (!next("sacrifice")) return reject(); + next('s'); + if (!SPACE()) return reject(); + if (!SelectPermanent()) return reject(); + SacrificeAction_0(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // SacrificeAction_0 = SPACE "unless you" SPACE Action + //------------------------------------------------------------------- + private boolean SacrificeAction_0() + { + if (savedInner(SacrificeAction_0)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!next("unless you")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Action()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // PoisonAction = "gets" SPACE Count SPACE "poison counter" "s"? ; + //===================================================================== + private boolean PoisonAction() + { + if (saved(PoisonAction)) return reuse(); + if (!next("gets")) return reject(); + if (!SPACE()) return reject(); + if (!Count()) return reject(); + if (!SPACE()) return reject(); + if (!next("poison counter")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // MillAction = "put" "s"? " the top " (Count SPACE)? Card " of his or + // her library into his or her graveyard" ; + //===================================================================== + private boolean MillAction() + { + if (saved(MillAction)) return reuse(); + if (!next("put")) return reject(); + next('s'); + if (!next(" the top ")) return reject(); + MillAction_0(); + if (!Card()) return reject(); + if (!next(" of his or her library into his or her graveyard")) return reject(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // MillAction_0 = Count SPACE + //------------------------------------------------------------------- + private boolean MillAction_0() + { + if (savedInner(MillAction_0)) return reuseInner(); + if (!Count()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // DoesntUntapAction = SelectPermanent " doesn't untap during its + // controller's untap step" / SelectPermanent " doesn't untap during + // its controller's next untap step" / SelectPermanent " doesn't + // untap during your untap step" ; + //===================================================================== + private boolean DoesntUntapAction() + { + if (saved(DoesntUntapAction)) return reuse(); + if (DoesntUntapAction_0()) return sem.action() && accept(); + if (DoesntUntapAction_1()) return sem.action() && accept(); + if (DoesntUntapAction_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // DoesntUntapAction_0 = SelectPermanent " doesn't untap during its + // controller's untap step" + //------------------------------------------------------------------- + private boolean DoesntUntapAction_0() + { + if (savedInner(DoesntUntapAction_0)) return reuseInner(); + if (!SelectPermanent()) return rejectInner(); + if (!next(" doesn't untap during its controller's untap step")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DoesntUntapAction_1 = SelectPermanent " doesn't untap during its + // controller's next untap step" + //------------------------------------------------------------------- + private boolean DoesntUntapAction_1() + { + if (savedInner(DoesntUntapAction_1)) return reuseInner(); + if (!SelectPermanent()) return rejectInner(); + if (!next(" doesn't untap during its controller's next untap step")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DoesntUntapAction_2 = SelectPermanent " doesn't untap during your + // untap step" + //------------------------------------------------------------------- + private boolean DoesntUntapAction_2() + { + if (savedInner(DoesntUntapAction_2)) return reuseInner(); + if (!SelectPermanent()) return rejectInner(); + if (!next(" doesn't untap during your untap step")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // ShuffleAction = "shuffle it into its owner's library" / "shuffle + // your library" ; + //===================================================================== + private boolean ShuffleAction() + { + if (saved(ShuffleAction)) return reuse(); + if (next("shuffle it into its owner's library")) return sem.action() && accept(); + if (next("shuffle your library")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // PutTokenAction = "put " Count SPACE CreatureTokenSpec " onto the + // battlefield" / "put a token that's a copy of " SelectPermanent " + // onto the battlefield" ; + //===================================================================== + private boolean PutTokenAction() + { + if (saved(PutTokenAction)) return reuse(); + if (PutTokenAction_0()) return sem.action() && accept(); + if (PutTokenAction_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // PutTokenAction_0 = "put " Count SPACE CreatureTokenSpec " onto + // the battlefield" + //------------------------------------------------------------------- + private boolean PutTokenAction_0() + { + if (savedInner(PutTokenAction_0)) return reuseInner(); + if (!next("put ")) return rejectInner(); + if (!Count()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!CreatureTokenSpec()) return rejectInner(); + if (!next(" onto the battlefield")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // PutTokenAction_1 = "put a token that's a copy of " + // SelectPermanent " onto the battlefield" + //------------------------------------------------------------------- + private boolean PutTokenAction_1() + { + if (savedInner(PutTokenAction_1)) return reuseInner(); + if (!next("put a token that's a copy of ")) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + if (!next(" onto the battlefield")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // CreatureTokenSpec = PowerToughness SPACE ColorSpec (SPACE + // CreatureType)* " artifact"? " creature token" "s"? (SPACE + // WithAbilitySpec)? ; + //===================================================================== + private boolean CreatureTokenSpec() + { + if (saved(CreatureTokenSpec)) return reuse(); + if (!PowerToughness()) return reject(); + if (!SPACE()) return reject(); + if (!ColorSpec()) return reject(); + while (CreatureTokenSpec_0()); + next(" artifact"); + if (!next(" creature token")) return reject(); + next('s'); + CreatureTokenSpec_1(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // CreatureTokenSpec_0 = SPACE CreatureType + //------------------------------------------------------------------- + private boolean CreatureTokenSpec_0() + { + if (savedInner(CreatureTokenSpec_0)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!CreatureType()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // CreatureTokenSpec_1 = SPACE WithAbilitySpec + //------------------------------------------------------------------- + private boolean CreatureTokenSpec_1() + { + if (savedInner(CreatureTokenSpec_1)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!WithAbilitySpec()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // WithAbilitySpec = "with " Keyword SEP Keyword / "with " Keyword ; + //===================================================================== + private boolean WithAbilitySpec() + { + if (saved(WithAbilitySpec)) return reuse(); + if (WithAbilitySpec_0()) return sem.action() && accept(); + if (WithAbilitySpec_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // WithAbilitySpec_0 = "with " Keyword SEP Keyword + //------------------------------------------------------------------- + private boolean WithAbilitySpec_0() + { + if (savedInner(WithAbilitySpec_0)) return reuseInner(); + if (!next("with ")) return rejectInner(); + if (!Keyword()) return rejectInner(); + if (!SEP()) return rejectInner(); + if (!Keyword()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // WithAbilitySpec_1 = "with " Keyword + //------------------------------------------------------------------- + private boolean WithAbilitySpec_1() + { + if (savedInner(WithAbilitySpec_1)) return reuseInner(); + if (!next("with ")) return rejectInner(); + if (!Keyword()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // CreatureSpec = PowerToughness (SPACE ColorSpec)? (SPACE + // CreatureType)* " artifact"? " creature" (SPACE WithAbilitySpec)? + // ; + //===================================================================== + private boolean CreatureSpec() + { + if (saved(CreatureSpec)) return reuse(); + if (!PowerToughness()) return reject(); + CreatureSpec_0(); + while (CreatureTokenSpec_0()); + next(" artifact"); + if (!next(" creature")) return reject(); + CreatureTokenSpec_1(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // CreatureSpec_0 = SPACE ColorSpec + //------------------------------------------------------------------- + private boolean CreatureSpec_0() + { + if (savedInner(CreatureSpec_0)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!ColorSpec()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // ControlAction = "control" "s"? SPACE SelectPermanent / "gain + // control of " SelectPermanent ; + //===================================================================== + private boolean ControlAction() + { + if (saved(ControlAction)) return reuse(); + if (ControlAction_0()) return sem.action() && accept(); + if (ControlAction_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // ControlAction_0 = "control" "s"? SPACE SelectPermanent + //------------------------------------------------------------------- + private boolean ControlAction_0() + { + if (savedInner(ControlAction_0)) return reuseInner(); + if (!next("control")) return rejectInner(); + next('s'); + if (!SPACE()) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ControlAction_1 = "gain control of " SelectPermanent + //------------------------------------------------------------------- + private boolean ControlAction_1() + { + if (savedInner(ControlAction_1)) return reuseInner(); + if (!next("gain control of ")) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // ChangeCounterAction = CounterVerb SPACE Count SPACE CounterType + // SPACE Counter " from " SelectPermanent / CounterVerb SPACE Count + // SPACE CounterType SPACE Counter " on " SelectPermanent ; + //===================================================================== + private boolean ChangeCounterAction() + { + if (saved(ChangeCounterAction)) return reuse(); + if (ChangeCounterAction_0()) return sem.action() && accept(); + if (ChangeCounterAction_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // ChangeCounterAction_0 = CounterVerb SPACE Count SPACE CounterType + // SPACE Counter " from " SelectPermanent + //------------------------------------------------------------------- + private boolean ChangeCounterAction_0() + { + if (savedInner(ChangeCounterAction_0)) return reuseInner(); + if (!CounterVerb()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Count()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!CounterType()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Counter()) return rejectInner(); + if (!next(" from ")) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ChangeCounterAction_1 = CounterVerb SPACE Count SPACE CounterType + // SPACE Counter " on " SelectPermanent + //------------------------------------------------------------------- + private boolean ChangeCounterAction_1() + { + if (savedInner(ChangeCounterAction_1)) return reuseInner(); + if (!CounterVerb()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Count()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!CounterType()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Counter()) return rejectInner(); + if (!next(" on ")) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // CounterVerb = "remove" / "put" ; + //===================================================================== + private boolean CounterVerb() + { + if (saved(CounterVerb)) return reuse(); + if (next("remove")) return sem.action() && accept(); + if (next("put")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Counter = "counter" "s"? ; + //===================================================================== + private boolean Counter() + { + if (saved(Counter)) return reuse(); + if (!next("counter")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // PayManaAction = "pay" "s"? SPACE ManaCost / ManaCost ; + //===================================================================== + private boolean PayManaAction() + { + if (saved(PayManaAction)) return reuse(); + if (PayManaAction_0()) return sem.action() && accept(); + if (ManaCost()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // PayManaAction_0 = "pay" "s"? SPACE ManaCost + //------------------------------------------------------------------- + private boolean PayManaAction_0() + { + if (savedInner(PayManaAction_0)) return reuseInner(); + if (!next("pay")) return rejectInner(); + next('s'); + if (!SPACE()) return rejectInner(); + if (!ManaCost()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // ChangeLifeAction = ChangeLifeVerb SPACE Number SPACE "life" ; + //===================================================================== + private boolean ChangeLifeAction() + { + if (saved(ChangeLifeAction)) return reuse(); + if (!ChangeLifeVerb()) return reject(); + if (!SPACE()) return reject(); + if (!Number()) return reject(); + if (!SPACE()) return reject(); + if (!next("life")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // ChangeLifeVerb = "lose" "s"? / "gain" "s"? / "pay" "s"? ; + //===================================================================== + private boolean ChangeLifeVerb() + { + if (saved(ChangeLifeVerb)) return reuse(); + if (ChangeLifeVerb_0()) return sem.action() && accept(); + if (ChangeLifeVerb_1()) return sem.action() && accept(); + if (ChangeLifeVerb_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // ChangeLifeVerb_0 = "lose" "s"? + //------------------------------------------------------------------- + private boolean ChangeLifeVerb_0() + { + if (savedInner(ChangeLifeVerb_0)) return reuseInner(); + if (!next("lose")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ChangeLifeVerb_1 = "gain" "s"? + //------------------------------------------------------------------- + private boolean ChangeLifeVerb_1() + { + if (savedInner(ChangeLifeVerb_1)) return reuseInner(); + if (!next("gain")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ChangeLifeVerb_2 = "pay" "s"? + //------------------------------------------------------------------- + private boolean ChangeLifeVerb_2() + { + if (savedInner(ChangeLifeVerb_2)) return reuseInner(); + if (!next("pay")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //===================================================================== + // SelectPlayer = Player &(SEP SingleEffect) / Player (SEP Player)* ; + //===================================================================== + private boolean SelectPlayer() + { + if (saved(SelectPlayer)) return reuse(); + if (SelectPlayer_0()) return sem.action() && accept(); + if (SelectPlayer_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // SelectPlayer_0 = Player &(SEP SingleEffect) + //------------------------------------------------------------------- + private boolean SelectPlayer_0() + { + if (savedInner(SelectPlayer_0)) return reuseInner(); + if (!Player()) return rejectInner(); + if (!DamageReceiver_4()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectPlayer_1 = Player (SEP Player)* + //------------------------------------------------------------------- + private boolean SelectPlayer_1() + { + if (savedInner(SelectPlayer_1)) return reuseInner(); + if (!Player()) return rejectInner(); + while (SelectPlayer_2()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectPlayer_2 = SEP Player + //------------------------------------------------------------------- + private boolean SelectPlayer_2() + { + if (savedInner(SelectPlayer_2)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!Player()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // Player = "target player" / "target opponent" / "that player" / + // "each player" / "each opponent" / "your opponents" / "an + // opponent" / "you" / "he or she" / "its controller" / "that + // creature's controller" / "its owner" / "player" / "a player" ; + //===================================================================== + private boolean Player() + { + if (saved(Player)) return reuse(); + if (next("target player")) return sem.action() && accept(); + if (next("target opponent")) return sem.action() && accept(); + if (next("that player")) return sem.action() && accept(); + if (next("each player")) return sem.action() && accept(); + if (next("each opponent")) return sem.action() && accept(); + if (next("your opponents")) return sem.action() && accept(); + if (next("an opponent")) return sem.action() && accept(); + if (next("you")) return sem.action() && accept(); + if (next("he or she")) return sem.action() && accept(); + if (next("its controller")) return sem.action() && accept(); + if (next("that creature's controller")) return sem.action() && accept(); + if (next("its owner")) return sem.action() && accept(); + if (next("player")) return sem.action() && accept(); + if (next("a player")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // PutCardAction = "put " SelectCard " onto the battlefield under your + // control" / "put " SelectCard " onto the battlefield" ; + //===================================================================== + private boolean PutCardAction() + { + if (saved(PutCardAction)) return reuse(); + if (PutCardAction_0()) return sem.action() && accept(); + if (PutCardAction_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // PutCardAction_0 = "put " SelectCard " onto the battlefield under + // your control" + //------------------------------------------------------------------- + private boolean PutCardAction_0() + { + if (savedInner(PutCardAction_0)) return reuseInner(); + if (!next("put ")) return rejectInner(); + if (!SelectCard()) return rejectInner(); + if (!next(" onto the battlefield under your control")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // PutCardAction_1 = "put " SelectCard " onto the battlefield" + //------------------------------------------------------------------- + private boolean PutCardAction_1() + { + if (savedInner(PutCardAction_1)) return reuseInner(); + if (!next("put ")) return rejectInner(); + if (!SelectCard()) return rejectInner(); + if (!next(" onto the battlefield")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // ReturnAction = BounceVerb SPACE SelectCard SPACE BounceLocation ; + //===================================================================== + private boolean ReturnAction() + { + if (saved(ReturnAction)) return reuse(); + if (!BounceVerb()) return reject(); + if (!SPACE()) return reject(); + if (!SelectCard()) return reject(); + if (!SPACE()) return reject(); + if (!BounceLocation()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // BounceAction = BounceVerb SPACE SelectPermanent SPACE + // BounceLocation ; + //===================================================================== + private boolean BounceAction() + { + if (saved(BounceAction)) return reuse(); + if (!BounceVerb()) return reject(); + if (!SPACE()) return reject(); + if (!SelectPermanent()) return reject(); + if (!SPACE()) return reject(); + if (!BounceLocation()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // BounceLocation = "to its owner's hand" / "to their owners' hands" / + // "to your hand" / "to the battlefield under its owner's control" / + // "to the battlefield" / "on top of its owner's library" / "on top + // of your library" / "on the bottom of its owner's library" ; + //===================================================================== + private boolean BounceLocation() + { + if (saved(BounceLocation)) return reuse(); + if (next("to its owner's hand")) return sem.action() && accept(); + if (next("to their owners' hands")) return sem.action() && accept(); + if (next("to your hand")) return sem.action() && accept(); + if (next("to the battlefield under its owner's control")) return sem.action() && accept(); + if (next("to the battlefield")) return sem.action() && accept(); + if (next("on top of its owner's library")) return sem.action() && accept(); + if (next("on top of your library")) return sem.action() && accept(); + if (next("on the bottom of its owner's library")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // BounceVerb = "return" "s"? / "put" "s"? ; + //===================================================================== + private boolean BounceVerb() + { + if (saved(BounceVerb)) return reuse(); + if (BounceVerb_0()) return sem.action() && accept(); + if (BounceVerb_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // BounceVerb_0 = "return" "s"? + //------------------------------------------------------------------- + private boolean BounceVerb_0() + { + if (savedInner(BounceVerb_0)) return reuseInner(); + if (!next("return")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // BounceVerb_1 = "put" "s"? + //------------------------------------------------------------------- + private boolean BounceVerb_1() + { + if (savedInner(BounceVerb_1)) return reuseInner(); + if (!next("put")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //===================================================================== + // PreventAction = "prevent the next " Number SPACE Damage SPACE "that + // would be dealt" (SPACE DamageRestriction)? / "prevent all " + // Damage SPACE "that would be dealt" (SPACE DamageRestriction)? / + // "if damage would be dealt to " DamageReceiver ", prevent that + // damage" ; + //===================================================================== + private boolean PreventAction() + { + if (saved(PreventAction)) return reuse(); + if (PreventAction_0()) return sem.action() && accept(); + if (PreventAction_1()) return sem.action() && accept(); + if (PreventAction_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // PreventAction_0 = "prevent the next " Number SPACE Damage SPACE + // "that would be dealt" (SPACE DamageRestriction)? + //------------------------------------------------------------------- + private boolean PreventAction_0() + { + if (savedInner(PreventAction_0)) return reuseInner(); + if (!next("prevent the next ")) return rejectInner(); + if (!Number()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Damage()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!next("that would be dealt")) return rejectInner(); + PreventAction_3(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // PreventAction_1 = "prevent all " Damage SPACE "that would be + // dealt" (SPACE DamageRestriction)? + //------------------------------------------------------------------- + private boolean PreventAction_1() + { + if (savedInner(PreventAction_1)) return reuseInner(); + if (!next("prevent all ")) return rejectInner(); + if (!Damage()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!next("that would be dealt")) return rejectInner(); + PreventAction_3(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // PreventAction_2 = "if damage would be dealt to " DamageReceiver + // ", prevent that damage" + //------------------------------------------------------------------- + private boolean PreventAction_2() + { + if (savedInner(PreventAction_2)) return reuseInner(); + if (!next("if damage would be dealt to ")) return rejectInner(); + if (!DamageReceiver()) return rejectInner(); + if (!next(", prevent that damage")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // PreventAction_3 = SPACE DamageRestriction + //------------------------------------------------------------------- + private boolean PreventAction_3() + { + if (savedInner(PreventAction_3)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!DamageRestriction()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // DamageRestriction = DamageVerb SPACE DamageReceiver (SPACE "this + // turn by" SPACE DamageReceiver)? ; + //===================================================================== + private boolean DamageRestriction() + { + if (saved(DamageRestriction)) return reuse(); + if (!DamageVerb()) return reject(); + if (!SPACE()) return reject(); + if (!DamageReceiver()) return reject(); + DamageRestriction_0(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // DamageRestriction_0 = SPACE "this turn by" SPACE DamageReceiver + //------------------------------------------------------------------- + private boolean DamageRestriction_0() + { + if (savedInner(DamageRestriction_0)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!next("this turn by")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!DamageReceiver()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // DamageVerb = "to and dealt by" / "to" / "by" ; + //===================================================================== + private boolean DamageVerb() + { + if (saved(DamageVerb)) return reuse(); + if (next("to and dealt by")) return sem.action() && accept(); + if (next("to")) return sem.action() && accept(); + if (next("by")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Damage = "damage" / "combat damage" ; + //===================================================================== + private boolean Damage() + { + if (saved(Damage)) return reuse(); + if (next("damage")) return sem.action() && accept(); + if (next("combat damage")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // TapAction = TapVerb SPACE SelectPermanent / "{t}" / "{q}" ; + //===================================================================== + private boolean TapAction() + { + if (saved(TapAction)) return reuse(); + if (TapAction_0()) return sem.action() && accept(); + if (next("{t}")) return sem.action() && accept(); + if (next("{q}")) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // TapAction_0 = TapVerb SPACE SelectPermanent + //------------------------------------------------------------------- + private boolean TapAction_0() + { + if (savedInner(TapAction_0)) return reuseInner(); + if (!TapVerb()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // TapVerb = "tap or untap" / "tap" / "untap" ; + //===================================================================== + private boolean TapVerb() + { + if (saved(TapVerb)) return reuse(); + if (next("tap or untap")) return sem.action() && accept(); + if (next("tap")) return sem.action() && accept(); + if (next("untap")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // RegenerateAction = "regenerate" SPACE SelectPermanent ; + //===================================================================== + private boolean RegenerateAction() + { + if (saved(RegenerateAction)) return reuse(); + if (!next("regenerate")) return reject(); + if (!SPACE()) return reject(); + if (!SelectPermanent()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // DamageAction = (SelectPermanent SPACE)? (Deal SPACE)? Number " + // damage to " DamageReceiver / SelectPermanent SPACE Deal " damage + // equal to its power to " DamageReceiver / SelectPermanent SPACE + // Deal " damage equal to the number of " CounterType " counters on + // it to " DamageReceiver / SelectPermanent SPACE Deal " damage to " + // DamageReceiver " equal to the number of " SelectPermanent ; + //===================================================================== + private boolean DamageAction() + { + if (saved(DamageAction)) return reuse(); + if (DamageAction_0()) return sem.action() && accept(); + if (DamageAction_1()) return sem.action() && accept(); + if (DamageAction_2()) return sem.action() && accept(); + if (DamageAction_3()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // DamageAction_0 = (SelectPermanent SPACE)? (Deal SPACE)? Number " + // damage to " DamageReceiver + //------------------------------------------------------------------- + private boolean DamageAction_0() + { + if (savedInner(DamageAction_0)) return reuseInner(); + ChangeStateAction_0(); + DamageAction_4(); + if (!Number()) return rejectInner(); + if (!next(" damage to ")) return rejectInner(); + if (!DamageReceiver()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageAction_1 = SelectPermanent SPACE Deal " damage equal to its + // power to " DamageReceiver + //------------------------------------------------------------------- + private boolean DamageAction_1() + { + if (savedInner(DamageAction_1)) return reuseInner(); + if (!SelectPermanent()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Deal()) return rejectInner(); + if (!next(" damage equal to its power to ")) return rejectInner(); + if (!DamageReceiver()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageAction_2 = SelectPermanent SPACE Deal " damage equal to the + // number of " CounterType " counters on it to " DamageReceiver + //------------------------------------------------------------------- + private boolean DamageAction_2() + { + if (savedInner(DamageAction_2)) return reuseInner(); + if (!SelectPermanent()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Deal()) return rejectInner(); + if (!next(" damage equal to the number of ")) return rejectInner(); + if (!CounterType()) return rejectInner(); + if (!next(" counters on it to ")) return rejectInner(); + if (!DamageReceiver()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageAction_3 = SelectPermanent SPACE Deal " damage to " + // DamageReceiver " equal to the number of " SelectPermanent + //------------------------------------------------------------------- + private boolean DamageAction_3() + { + if (savedInner(DamageAction_3)) return reuseInner(); + if (!SelectPermanent()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Deal()) return rejectInner(); + if (!next(" damage to ")) return rejectInner(); + if (!DamageReceiver()) return rejectInner(); + if (!next(" equal to the number of ")) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DamageAction_4 = Deal SPACE + //------------------------------------------------------------------- + private boolean DamageAction_4() + { + if (savedInner(DamageAction_4)) return reuseInner(); + if (!Deal()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // Deal = "deal" "s"? ; + //===================================================================== + private boolean Deal() + { + if (saved(Deal)) return reuse(); + if (!next("deal")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // EntersTapped = "@ enters the battlefield tapped" ; + //===================================================================== + private boolean EntersTapped() + { + if (saved(EntersTapped)) return reuse(); + if (!next("@ enters the battlefield tapped")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // EntersWithCounter = "@ enters the battlefield with" SPACE Count + // SPACE CounterType SPACE Counter " on it" ; + //===================================================================== + private boolean EntersWithCounter() + { + if (saved(EntersWithCounter)) return reuse(); + if (!next("@ enters the battlefield with")) return reject(); + if (!SPACE()) return reject(); + if (!Count()) return reject(); + if (!SPACE()) return reject(); + if (!CounterType()) return reject(); + if (!SPACE()) return reject(); + if (!Counter()) return reject(); + if (!next(" on it")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // CounterType = "-0/-1" / "+0/+1" / "-0/-2" / "+0/+2" / "-1/-0" / + // "+1/+0" / "-1/-1" / "+1/+1" / "+1/+2" / "-2/-2" / "+2/+2" / "age" + // / "aim" / "arrow" / "arrowhead" / "awakening" / "blaze" / "blood" + // / "bounty" / "bribery" / "carrion" / "charge" / "corpse" / + // "credit" / "cube" / "currency" / "death" / "delay" / "depletion" + // / "despair" / "devotion" / "divinity" / "doom" / "dream" / "echo" + // / "elixir" / "energy" / "eon" / "fade" / "fate" / "feather" / + // "filibuster" / "flame" / "flood" / "fungus" / "fuse" / "glyph" / + // "gold" / "growth" / "hatchling" / "healing" / "hoofprint" / + // "hourglass" / "hunger" / "husk" / "ice" / "infection" / + // "intervention" / "javelin" / "ki" / "level" / "lore" / "luck" / + // "magnet" / "mannequin" / "matrix" / "mine" / "mining" / "mire" / + // "music" / "net" / "omen" / "ore" / "page" / "pain" / + // "paralyzation" / "petal" / "petrification" / "phylactery" / "pin" + // / "plague" / "poison" / "polyp" / "pressure" / "pupa" / "quest" / + // "rust" / "scream" / "scroll" / "shell" / "shield" / "shred" / + // "sleep" / "sleight" / "slime" / "soot" / "spore" / "storage" / + // "strife" / "study" / "tide" / "time" / "training" / "trap" / + // "treasure" / "velocity" / "verse" / "vitality" / "wage" / "winch" + // / "wind" / "wish" ; + //===================================================================== + private boolean CounterType() + { + if (saved(CounterType)) return reuse(); + if (next("-0/-1")) return sem.action() && accept(); + if (next("+0/+1")) return sem.action() && accept(); + if (next("-0/-2")) return sem.action() && accept(); + if (next("+0/+2")) return sem.action() && accept(); + if (next("-1/-0")) return sem.action() && accept(); + if (next("+1/+0")) return sem.action() && accept(); + if (next("-1/-1")) return sem.action() && accept(); + if (next("+1/+1")) return sem.action() && accept(); + if (next("+1/+2")) return sem.action() && accept(); + if (next("-2/-2")) return sem.action() && accept(); + if (next("+2/+2")) return sem.action() && accept(); + if (next("age")) return sem.action() && accept(); + if (next("aim")) return sem.action() && accept(); + if (next("arrow")) return sem.action() && accept(); + if (next("arrowhead")) return sem.action() && accept(); + if (next("awakening")) return sem.action() && accept(); + if (next("blaze")) return sem.action() && accept(); + if (next("blood")) return sem.action() && accept(); + if (next("bounty")) return sem.action() && accept(); + if (next("bribery")) return sem.action() && accept(); + if (next("carrion")) return sem.action() && accept(); + if (next("charge")) return sem.action() && accept(); + if (next("corpse")) return sem.action() && accept(); + if (next("credit")) return sem.action() && accept(); + if (next("cube")) return sem.action() && accept(); + if (next("currency")) return sem.action() && accept(); + if (next("death")) return sem.action() && accept(); + if (next("delay")) return sem.action() && accept(); + if (next("depletion")) return sem.action() && accept(); + if (next("despair")) return sem.action() && accept(); + if (next("devotion")) return sem.action() && accept(); + if (next("divinity")) return sem.action() && accept(); + if (next("doom")) return sem.action() && accept(); + if (next("dream")) return sem.action() && accept(); + if (next("echo")) return sem.action() && accept(); + if (next("elixir")) return sem.action() && accept(); + if (next("energy")) return sem.action() && accept(); + if (next("eon")) return sem.action() && accept(); + if (next("fade")) return sem.action() && accept(); + if (next("fate")) return sem.action() && accept(); + if (next("feather")) return sem.action() && accept(); + if (next("filibuster")) return sem.action() && accept(); + if (next("flame")) return sem.action() && accept(); + if (next("flood")) return sem.action() && accept(); + if (next("fungus")) return sem.action() && accept(); + if (next("fuse")) return sem.action() && accept(); + if (next("glyph")) return sem.action() && accept(); + if (next("gold")) return sem.action() && accept(); + if (next("growth")) return sem.action() && accept(); + if (next("hatchling")) return sem.action() && accept(); + if (next("healing")) return sem.action() && accept(); + if (next("hoofprint")) return sem.action() && accept(); + if (next("hourglass")) return sem.action() && accept(); + if (next("hunger")) return sem.action() && accept(); + if (next("husk")) return sem.action() && accept(); + if (next("ice")) return sem.action() && accept(); + if (next("infection")) return sem.action() && accept(); + if (next("intervention")) return sem.action() && accept(); + if (next("javelin")) return sem.action() && accept(); + if (next("ki")) return sem.action() && accept(); + if (next("level")) return sem.action() && accept(); + if (next("lore")) return sem.action() && accept(); + if (next("luck")) return sem.action() && accept(); + if (next("magnet")) return sem.action() && accept(); + if (next("mannequin")) return sem.action() && accept(); + if (next("matrix")) return sem.action() && accept(); + if (next("mine")) return sem.action() && accept(); + if (next("mining")) return sem.action() && accept(); + if (next("mire")) return sem.action() && accept(); + if (next("music")) return sem.action() && accept(); + if (next("net")) return sem.action() && accept(); + if (next("omen")) return sem.action() && accept(); + if (next("ore")) return sem.action() && accept(); + if (next("page")) return sem.action() && accept(); + if (next("pain")) return sem.action() && accept(); + if (next("paralyzation")) return sem.action() && accept(); + if (next("petal")) return sem.action() && accept(); + if (next("petrification")) return sem.action() && accept(); + if (next("phylactery")) return sem.action() && accept(); + if (next("pin")) return sem.action() && accept(); + if (next("plague")) return sem.action() && accept(); + if (next("poison")) return sem.action() && accept(); + if (next("polyp")) return sem.action() && accept(); + if (next("pressure")) return sem.action() && accept(); + if (next("pupa")) return sem.action() && accept(); + if (next("quest")) return sem.action() && accept(); + if (next("rust")) return sem.action() && accept(); + if (next("scream")) return sem.action() && accept(); + if (next("scroll")) return sem.action() && accept(); + if (next("shell")) return sem.action() && accept(); + if (next("shield")) return sem.action() && accept(); + if (next("shred")) return sem.action() && accept(); + if (next("sleep")) return sem.action() && accept(); + if (next("sleight")) return sem.action() && accept(); + if (next("slime")) return sem.action() && accept(); + if (next("soot")) return sem.action() && accept(); + if (next("spore")) return sem.action() && accept(); + if (next("storage")) return sem.action() && accept(); + if (next("strife")) return sem.action() && accept(); + if (next("study")) return sem.action() && accept(); + if (next("tide")) return sem.action() && accept(); + if (next("time")) return sem.action() && accept(); + if (next("training")) return sem.action() && accept(); + if (next("trap")) return sem.action() && accept(); + if (next("treasure")) return sem.action() && accept(); + if (next("velocity")) return sem.action() && accept(); + if (next("verse")) return sem.action() && accept(); + if (next("vitality")) return sem.action() && accept(); + if (next("wage")) return sem.action() && accept(); + if (next("winch")) return sem.action() && accept(); + if (next("wind")) return sem.action() && accept(); + if (next("wish")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Count = "an" / "a" / "one" / "two" / "three" / "four" / "five" / + // "six" / "seven" / "eight" / "nine" / "ten" / "x" ; + //===================================================================== + private boolean Count() + { + if (saved(Count)) return reuse(); + if (next("an")) return sem.action() && accept(); + if (next('a')) return sem.action() && accept(); + if (next("one")) return sem.action() && accept(); + if (next("two")) return sem.action() && accept(); + if (next("three")) return sem.action() && accept(); + if (next("four")) return sem.action() && accept(); + if (next("five")) return sem.action() && accept(); + if (next("six")) return sem.action() && accept(); + if (next("seven")) return sem.action() && accept(); + if (next("eight")) return sem.action() && accept(); + if (next("nine")) return sem.action() && accept(); + if (next("ten")) return sem.action() && accept(); + if (next('x')) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Enchant = "enchant" SPACE RestrictedPermanent / "enchant player" ; + //===================================================================== + private boolean Enchant() + { + if (saved(Enchant)) return reuse(); + if (Enchant_0()) return sem.action() && accept(); + if (next("enchant player")) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // Enchant_0 = "enchant" SPACE RestrictedPermanent + //------------------------------------------------------------------- + private boolean Enchant_0() + { + if (savedInner(Enchant_0)) return reuseInner(); + if (!next("enchant")) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!RestrictedPermanent()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // Duration = "until end of turn" / "for as long as " SelectPlayer " + // control @" / "as long as you control three or more artifacts" / + // "as long as seven or more cards are in your graveyard" / "as long + // as you have no cards in hand" / "this turn" / "at the beginning + // of the next turn's upkeep" / "at the beginning of the next end + // step" / "at the beginning of your next end step" ; + //===================================================================== + private boolean Duration() + { + if (saved(Duration)) return reuse(); + if (next("until end of turn")) return sem.action() && accept(); + if (Duration_0()) return sem.action() && accept(); + if (next("as long as you control three or more artifacts")) return sem.action() && accept(); + if (next("as long as seven or more cards are in your graveyard")) return sem.action() && accept(); + if (next("as long as you have no cards in hand")) return sem.action() && accept(); + if (next("this turn")) return sem.action() && accept(); + if (next("at the beginning of the next turn's upkeep")) return sem.action() && accept(); + if (next("at the beginning of the next end step")) return sem.action() && accept(); + if (next("at the beginning of your next end step")) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // Duration_0 = "for as long as " SelectPlayer " control @" + //------------------------------------------------------------------- + private boolean Duration_0() + { + if (savedInner(Duration_0)) return reuseInner(); + if (!next("for as long as ")) return rejectInner(); + if (!SelectPlayer()) return rejectInner(); + if (!next(" control @")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // GainAction = (SelectPermanent SPACE)? GainVerb SPACE Keyword (SEP + // Keyword)* ; + //===================================================================== + private boolean GainAction() + { + if (saved(GainAction)) return reuse(); + ChangeStateAction_0(); + if (!GainVerb()) return reject(); + if (!SPACE()) return reject(); + if (!Keyword()) return reject(); + while (GainAction_0()); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // GainAction_0 = SEP Keyword + //------------------------------------------------------------------- + private boolean GainAction_0() + { + if (savedInner(GainAction_0)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!Keyword()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // GainVerb = "has" / "have" / "gain" "s"? / "lose" "s"? ; + //===================================================================== + private boolean GainVerb() + { + if (saved(GainVerb)) return reuse(); + if (next("has")) return sem.action() && accept(); + if (next("have")) return sem.action() && accept(); + if (ChangeLifeVerb_1()) return sem.action() && accept(); + if (ChangeLifeVerb_0()) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // PumpAction = SelectCreature SPACE "get" "s"? SPACE SignedNumber "/" + // SignedNumber ; + //===================================================================== + private boolean PumpAction() + { + if (saved(PumpAction)) return reuse(); + if (!SelectCreature()) return reject(); + if (!SPACE()) return reject(); + if (!next("get")) return reject(); + next('s'); + if (!SPACE()) return reject(); + if (!SignedNumber()) return reject(); + if (!next('/')) return reject(); + if (!SignedNumber()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // AddManaAction = "add " ManaSource " to your mana pool" ; + //===================================================================== + private boolean AddManaAction() + { + if (saved(AddManaAction)) return reuse(); + if (!next("add ")) return reject(); + if (!ManaSource()) return reject(); + if (!next(" to your mana pool")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // ManaSource = "{1}" / SingleColor (SEP SingleColor)* / "one mana of + // any color" ; + //===================================================================== + private boolean ManaSource() + { + if (saved(ManaSource)) return reuse(); + if (next("{1}")) return sem.action() && accept(); + if (ManaSource_0()) return sem.action() && accept(); + if (next("one mana of any color")) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // ManaSource_0 = SingleColor (SEP SingleColor)* + //------------------------------------------------------------------- + private boolean ManaSource_0() + { + if (savedInner(ManaSource_0)) return reuseInner(); + if (!SingleColor()) return rejectInner(); + while (ManaSource_1()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ManaSource_1 = SEP SingleColor + //------------------------------------------------------------------- + private boolean ManaSource_1() + { + if (savedInner(ManaSource_1)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!SingleColor()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // DrawAction = Draw SPACE Count SPACE Card ; + //===================================================================== + private boolean DrawAction() + { + if (saved(DrawAction)) return reuse(); + if (!Draw()) return reject(); + if (!SPACE()) return reject(); + if (!Count()) return reject(); + if (!SPACE()) return reject(); + if (!Card()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // Draw = "draw" "s"? ; + //===================================================================== + private boolean Draw() + { + if (saved(Draw)) return reuse(); + if (!next("draw")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // DiscardAction = Discard SPACE SelectCard " at random"? / Discard + // SPACE Count SPACE RestrictedCard " at random" ; + //===================================================================== + private boolean DiscardAction() + { + if (saved(DiscardAction)) return reuse(); + if (DiscardAction_0()) return sem.action() && accept(); + if (DiscardAction_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // DiscardAction_0 = Discard SPACE SelectCard " at random"? + //------------------------------------------------------------------- + private boolean DiscardAction_0() + { + if (savedInner(DiscardAction_0)) return reuseInner(); + if (!Discard()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!SelectCard()) return rejectInner(); + next(" at random"); + return acceptInner(); + } + + //------------------------------------------------------------------- + // DiscardAction_1 = Discard SPACE Count SPACE RestrictedCard " at + // random" + //------------------------------------------------------------------- + private boolean DiscardAction_1() + { + if (savedInner(DiscardAction_1)) return reuseInner(); + if (!Discard()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!Count()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!RestrictedCard()) return rejectInner(); + if (!next(" at random")) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // Discard = "discard" "s"? ; + //===================================================================== + private boolean Discard() + { + if (saved(Discard)) return reuse(); + if (!next("discard")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // DestroyNoRegenAction = "destroy" SPACE SelectPermanent EOS SPACE + // NoRegen ; + //===================================================================== + private boolean DestroyNoRegenAction() + { + if (saved(DestroyNoRegenAction)) return reuse(); + if (!next("destroy")) return reject(); + if (!SPACE()) return reject(); + if (!SelectPermanent()) return reject(); + if (!EOS()) return reject(); + if (!SPACE()) return reject(); + if (!NoRegen()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // DestroyAction = "destroy" SPACE SelectPermanent ; + //===================================================================== + private boolean DestroyAction() + { + if (saved(DestroyAction)) return reuse(); + if (!next("destroy")) return reject(); + if (!SPACE()) return reject(); + if (!SelectPermanent()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // ExileAction = "exile " SelectPermanent / "exile " SelectCard ; + //===================================================================== + private boolean ExileAction() + { + if (saved(ExileAction)) return reuse(); + if (ExileAction_0()) return sem.action() && accept(); + if (ExileAction_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // ExileAction_0 = "exile " SelectPermanent + //------------------------------------------------------------------- + private boolean ExileAction_0() + { + if (savedInner(ExileAction_0)) return reuseInner(); + if (!next("exile ")) return rejectInner(); + if (!SelectPermanent()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ExileAction_1 = "exile " SelectCard + //------------------------------------------------------------------- + private boolean ExileAction_1() + { + if (savedInner(ExileAction_1)) return reuseInner(); + if (!next("exile ")) return rejectInner(); + if (!SelectCard()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // CounterAction = "counter " SelectSpell (" unless " SingleEffect)? + // ; + //===================================================================== + private boolean CounterAction() + { + if (saved(CounterAction)) return reuse(); + if (!next("counter ")) return reject(); + if (!SelectSpell()) return reject(); + CounterAction_0(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // CounterAction_0 = " unless " SingleEffect + //------------------------------------------------------------------- + private boolean CounterAction_0() + { + if (savedInner(CounterAction_0)) return reuseInner(); + if (!next(" unless ")) return rejectInner(); + if (!SingleEffect()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SelectOp = "target" / "another target" / "all" / "an" / "a" / + // "each" / "the" / "that" / "those" ; + //===================================================================== + private boolean SelectOp() + { + if (saved(SelectOp)) return reuse(); + if (next("target")) return sem.action() && accept(); + if (next("another target")) return sem.action() && accept(); + if (next("all")) return sem.action() && accept(); + if (next("an")) return sem.action() && accept(); + if (next('a')) return sem.action() && accept(); + if (next("each")) return sem.action() && accept(); + if (next("the")) return sem.action() && accept(); + if (next("that")) return sem.action() && accept(); + if (next("those")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // SelectCard = "@" (SPACE CardRestriction)? (SEP RestrictedCard)* / + // "it" (SEP RestrictedCard)* / SelectOp SPACE RestrictedCard (SEP + // RestrictedCard)* ; + //===================================================================== + private boolean SelectCard() + { + if (saved(SelectCard)) return reuse(); + if (SelectCard_0()) return sem.action() && accept(); + if (SelectCard_1()) return sem.action() && accept(); + if (SelectCard_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // SelectCard_0 = "@" (SPACE CardRestriction)? (SEP + // RestrictedCard)* + //------------------------------------------------------------------- + private boolean SelectCard_0() + { + if (savedInner(SelectCard_0)) return reuseInner(); + if (!next('@')) return rejectInner(); + SelectCard_3(); + while (SelectCard_4()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectCard_1 = "it" (SEP RestrictedCard)* + //------------------------------------------------------------------- + private boolean SelectCard_1() + { + if (savedInner(SelectCard_1)) return reuseInner(); + if (!next("it")) return rejectInner(); + while (SelectCard_4()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectCard_2 = SelectOp SPACE RestrictedCard (SEP + // RestrictedCard)* + //------------------------------------------------------------------- + private boolean SelectCard_2() + { + if (savedInner(SelectCard_2)) return reuseInner(); + if (!SelectOp()) return rejectInner(); + if (!SPACE()) return rejectInner(); + if (!RestrictedCard()) return rejectInner(); + while (SelectCard_4()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectCard_3 = SPACE CardRestriction + //------------------------------------------------------------------- + private boolean SelectCard_3() + { + if (savedInner(SelectCard_3)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!CardRestriction()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectCard_4 = SEP RestrictedCard + //------------------------------------------------------------------- + private boolean SelectCard_4() + { + if (savedInner(SelectCard_4)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!RestrictedCard()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SelectCreature = "@" (SEP RestrictedCreature)* / "it" (SEP + // RestrictedCreature)* / (SelectOp SPACE)? RestrictedCreature (SEP + // RestrictedCreature)* ; + //===================================================================== + private boolean SelectCreature() + { + if (saved(SelectCreature)) return reuse(); + if (SelectCreature_0()) return sem.action() && accept(); + if (SelectCreature_1()) return sem.action() && accept(); + if (SelectCreature_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // SelectCreature_0 = "@" (SEP RestrictedCreature)* + //------------------------------------------------------------------- + private boolean SelectCreature_0() + { + if (savedInner(SelectCreature_0)) return reuseInner(); + if (!next('@')) return rejectInner(); + while (SelectCreature_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectCreature_1 = "it" (SEP RestrictedCreature)* + //------------------------------------------------------------------- + private boolean SelectCreature_1() + { + if (savedInner(SelectCreature_1)) return reuseInner(); + if (!next("it")) return rejectInner(); + while (SelectCreature_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectCreature_2 = (SelectOp SPACE)? RestrictedCreature (SEP + // RestrictedCreature)* + //------------------------------------------------------------------- + private boolean SelectCreature_2() + { + if (savedInner(SelectCreature_2)) return reuseInner(); + SelectCreature_4(); + if (!RestrictedCreature()) return rejectInner(); + while (SelectCreature_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectCreature_3 = SEP RestrictedCreature + //------------------------------------------------------------------- + private boolean SelectCreature_3() + { + if (savedInner(SelectCreature_3)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!RestrictedCreature()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectCreature_4 = SelectOp SPACE + //------------------------------------------------------------------- + private boolean SelectCreature_4() + { + if (savedInner(SelectCreature_4)) return reuseInner(); + if (!SelectOp()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SelectPermanent = "@" (SEP RestrictedPermanent)* / "it" (SEP + // RestrictedPermanent)* / (SelectOp SPACE)? RestrictedPermanent + // (SEP RestrictedPermanent)* ; + //===================================================================== + private boolean SelectPermanent() + { + if (saved(SelectPermanent)) return reuse(); + if (SelectPermanent_0()) return sem.action() && accept(); + if (SelectPermanent_1()) return sem.action() && accept(); + if (SelectPermanent_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // SelectPermanent_0 = "@" (SEP RestrictedPermanent)* + //------------------------------------------------------------------- + private boolean SelectPermanent_0() + { + if (savedInner(SelectPermanent_0)) return reuseInner(); + if (!next('@')) return rejectInner(); + while (SelectPermanent_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectPermanent_1 = "it" (SEP RestrictedPermanent)* + //------------------------------------------------------------------- + private boolean SelectPermanent_1() + { + if (savedInner(SelectPermanent_1)) return reuseInner(); + if (!next("it")) return rejectInner(); + while (SelectPermanent_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectPermanent_2 = (SelectOp SPACE)? RestrictedPermanent (SEP + // RestrictedPermanent)* + //------------------------------------------------------------------- + private boolean SelectPermanent_2() + { + if (savedInner(SelectPermanent_2)) return reuseInner(); + SelectCreature_4(); + if (!RestrictedPermanent()) return rejectInner(); + while (SelectPermanent_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectPermanent_3 = SEP RestrictedPermanent + //------------------------------------------------------------------- + private boolean SelectPermanent_3() + { + if (savedInner(SelectPermanent_3)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!RestrictedPermanent()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SelectSpell = "@" (SEP RestrictedSpell)* / "it" (SEP + // RestrictedSpell)* / (SelectOp SPACE)? RestrictedSpell (SEP + // RestrictedSpell)* ; + //===================================================================== + private boolean SelectSpell() + { + if (saved(SelectSpell)) return reuse(); + if (SelectSpell_0()) return sem.action() && accept(); + if (SelectSpell_1()) return sem.action() && accept(); + if (SelectSpell_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // SelectSpell_0 = "@" (SEP RestrictedSpell)* + //------------------------------------------------------------------- + private boolean SelectSpell_0() + { + if (savedInner(SelectSpell_0)) return reuseInner(); + if (!next('@')) return rejectInner(); + while (SelectSpell_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectSpell_1 = "it" (SEP RestrictedSpell)* + //------------------------------------------------------------------- + private boolean SelectSpell_1() + { + if (savedInner(SelectSpell_1)) return reuseInner(); + if (!next("it")) return rejectInner(); + while (SelectSpell_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectSpell_2 = (SelectOp SPACE)? RestrictedSpell (SEP + // RestrictedSpell)* + //------------------------------------------------------------------- + private boolean SelectSpell_2() + { + if (savedInner(SelectSpell_2)) return reuseInner(); + SelectCreature_4(); + if (!RestrictedSpell()) return rejectInner(); + while (SelectSpell_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SelectSpell_3 = SEP RestrictedSpell + //------------------------------------------------------------------- + private boolean SelectSpell_3() + { + if (savedInner(SelectSpell_3)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!RestrictedSpell()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // RestrictedPermanent = (PermanentRestriction SPACE)* Permanent + // (SPACE PermanentRestriction)* / RestrictedCreature / + // RestrictedLand / RestrictedArtifact / RestrictedEnchantment / + // RestrictedTribal ; + //===================================================================== + private boolean RestrictedPermanent() + { + if (saved(RestrictedPermanent)) return reuse(); + if (RestrictedPermanent_0()) return sem.action() && accept(); + if (RestrictedCreature()) return sem.action() && accept(); + if (RestrictedLand()) return sem.action() && accept(); + if (RestrictedArtifact()) return sem.action() && accept(); + if (RestrictedEnchantment()) return sem.action() && accept(); + if (RestrictedTribal()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // RestrictedPermanent_0 = (PermanentRestriction SPACE)* Permanent + // (SPACE PermanentRestriction)* + //------------------------------------------------------------------- + private boolean RestrictedPermanent_0() + { + if (savedInner(RestrictedPermanent_0)) return reuseInner(); + while (RestrictedPermanent_1()); + if (!Permanent()) return rejectInner(); + while (RestrictedPermanent_2()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // RestrictedPermanent_1 = PermanentRestriction SPACE + //------------------------------------------------------------------- + private boolean RestrictedPermanent_1() + { + if (savedInner(RestrictedPermanent_1)) return reuseInner(); + if (!PermanentRestriction()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // RestrictedPermanent_2 = SPACE PermanentRestriction + //------------------------------------------------------------------- + private boolean RestrictedPermanent_2() + { + if (savedInner(RestrictedPermanent_2)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!PermanentRestriction()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // RestrictedArtifact = (PermanentRestriction SPACE)*+ Artifact (SPACE + // PermanentRestriction)* ; + //===================================================================== + private boolean RestrictedArtifact() + { + if (saved(RestrictedArtifact)) return reuse(); + while (!Artifact()) + if (!RestrictedArtifact_0()) return reject(); + while (RestrictedPermanent_2()); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // RestrictedArtifact_0 = PermanentRestriction SPACE + //------------------------------------------------------------------- + private boolean RestrictedArtifact_0() + { + if (savedInner(RestrictedArtifact_0)) return reuseInner(); + if (!PermanentRestriction()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // RestrictedEnchantment = (PermanentRestriction SPACE)? Enchantment + // (SPACE PermanentRestriction)? ; + //===================================================================== + private boolean RestrictedEnchantment() + { + if (saved(RestrictedEnchantment)) return reuse(); + RestrictedPermanent_1(); + if (!Enchantment()) return reject(); + RestrictedPermanent_2(); + return sem.action() && accept(); + } + + //===================================================================== + // RestrictedLand = (LandRestriction SPACE)? Land (SPACE + // LandRestriction)? ; + //===================================================================== + private boolean RestrictedLand() + { + if (saved(RestrictedLand)) return reuse(); + RestrictedLand_0(); + if (!Land()) return reject(); + RestrictedLand_1(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // RestrictedLand_0 = LandRestriction SPACE + //------------------------------------------------------------------- + private boolean RestrictedLand_0() + { + if (savedInner(RestrictedLand_0)) return reuseInner(); + if (!LandRestriction()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // RestrictedLand_1 = SPACE LandRestriction + //------------------------------------------------------------------- + private boolean RestrictedLand_1() + { + if (savedInner(RestrictedLand_1)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!LandRestriction()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // RestrictedTribal = (PermanentRestriction SPACE)? Tribal (SPACE + // PermanentRestriction)? ; + //===================================================================== + private boolean RestrictedTribal() + { + if (saved(RestrictedTribal)) return reuse(); + RestrictedPermanent_1(); + if (!Tribal()) return reject(); + RestrictedPermanent_2(); + return sem.action() && accept(); + } + + //===================================================================== + // RestrictedSpell = (SpellRestriction SPACE)? Spell (SPACE + // SpellRestriction)? ; + //===================================================================== + private boolean RestrictedSpell() + { + if (saved(RestrictedSpell)) return reuse(); + RestrictedSpell_0(); + if (!Spell()) return reject(); + RestrictedSpell_1(); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // RestrictedSpell_0 = SpellRestriction SPACE + //------------------------------------------------------------------- + private boolean RestrictedSpell_0() + { + if (savedInner(RestrictedSpell_0)) return reuseInner(); + if (!SpellRestriction()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // RestrictedSpell_1 = SPACE SpellRestriction + //------------------------------------------------------------------- + private boolean RestrictedSpell_1() + { + if (savedInner(RestrictedSpell_1)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!SpellRestriction()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // ColorSpec = Color (SEP Color)* / "non" Color / "colorless" ; + //===================================================================== + private boolean ColorSpec() + { + if (saved(ColorSpec)) return reuse(); + if (ColorSpec_0()) return sem.action() && accept(); + if (ColorSpec_1()) return sem.action() && accept(); + if (next("colorless")) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // ColorSpec_0 = Color (SEP Color)* + //------------------------------------------------------------------- + private boolean ColorSpec_0() + { + if (savedInner(ColorSpec_0)) return reuseInner(); + if (!Color()) return rejectInner(); + while (ColorSpec_2()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ColorSpec_1 = "non" Color + //------------------------------------------------------------------- + private boolean ColorSpec_1() + { + if (savedInner(ColorSpec_1)) return reuseInner(); + if (!next("non")) return rejectInner(); + if (!Color()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // ColorSpec_2 = SEP Color + //------------------------------------------------------------------- + private boolean ColorSpec_2() + { + if (savedInner(ColorSpec_2)) return reuseInner(); + if (!SEP()) return rejectInner(); + if (!Color()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // SpellRestriction = ColorSpec / "creature" / "multicolored" / + // "noncreature" / "enchantment" / "spirit or arcane" / "treefolk" / + // "vampire creature" / "wizard" / "artifact" / "during an + // opponent's turn" / "instant or sorcery" / "instant" / "sorcery" / + // "with infect" / "with converted mana cost " Number " or less" / + // "with converted mana cost " Number " or greater" / "with + // converted mana cost " Number ; + //===================================================================== + private boolean SpellRestriction() + { + if (saved(SpellRestriction)) return reuse(); + if (ColorSpec()) return sem.action() && accept(); + if (next("creature")) return sem.action() && accept(); + if (next("multicolored")) return sem.action() && accept(); + if (next("noncreature")) return sem.action() && accept(); + if (next("enchantment")) return sem.action() && accept(); + if (next("spirit or arcane")) return sem.action() && accept(); + if (next("treefolk")) return sem.action() && accept(); + if (next("vampire creature")) return sem.action() && accept(); + if (next("wizard")) return sem.action() && accept(); + if (next("artifact")) return sem.action() && accept(); + if (next("during an opponent's turn")) return sem.action() && accept(); + if (next("instant or sorcery")) return sem.action() && accept(); + if (next("instant")) return sem.action() && accept(); + if (next("sorcery")) return sem.action() && accept(); + if (next("with infect")) return sem.action() && accept(); + if (SpellRestriction_0()) return sem.action() && accept(); + if (SpellRestriction_1()) return sem.action() && accept(); + if (SpellRestriction_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // SpellRestriction_0 = "with converted mana cost " Number " or + // less" + //------------------------------------------------------------------- + private boolean SpellRestriction_0() + { + if (savedInner(SpellRestriction_0)) return reuseInner(); + if (!next("with converted mana cost ")) return rejectInner(); + if (!Number()) return rejectInner(); + if (!next(" or less")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SpellRestriction_1 = "with converted mana cost " Number " or + // greater" + //------------------------------------------------------------------- + private boolean SpellRestriction_1() + { + if (savedInner(SpellRestriction_1)) return reuseInner(); + if (!next("with converted mana cost ")) return rejectInner(); + if (!Number()) return rejectInner(); + if (!next(" or greater")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // SpellRestriction_2 = "with converted mana cost " Number + //------------------------------------------------------------------- + private boolean SpellRestriction_2() + { + if (savedInner(SpellRestriction_2)) return reuseInner(); + if (!next("with converted mana cost ")) return rejectInner(); + if (!Number()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // RestrictedCard = (CardRestriction SPACE)* Card (SPACE + // CardRestriction)* ; + //===================================================================== + private boolean RestrictedCard() + { + if (saved(RestrictedCard)) return reuse(); + while (RestrictedCard_0()); + if (!Card()) return reject(); + while (SelectCard_3()); + return sem.action() && accept(); + } + + //------------------------------------------------------------------- + // RestrictedCard_0 = CardRestriction SPACE + //------------------------------------------------------------------- + private boolean RestrictedCard_0() + { + if (savedInner(RestrictedCard_0)) return reuseInner(); + if (!CardRestriction()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // CardRestriction = "exiled" / "from a graveyard" / "from your + // graveyard" / "from your hand" / "basic land" / "land" / + // SpellRestriction / RestrictedCreature ; + //===================================================================== + private boolean CardRestriction() + { + if (saved(CardRestriction)) return reuse(); + if (next("exiled")) return sem.action() && accept(); + if (next("from a graveyard")) return sem.action() && accept(); + if (next("from your graveyard")) return sem.action() && accept(); + if (next("from your hand")) return sem.action() && accept(); + if (next("basic land")) return sem.action() && accept(); + if (next("land")) return sem.action() && accept(); + if (SpellRestriction()) return sem.action() && accept(); + if (RestrictedCreature()) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // RestrictedCreature = (CreatureRestriction SPACE)* Creature (SPACE + // CreatureRestriction)* / (CreatureRestriction SPACE)*+ Tribal + // (SPACE CreatureRestriction)* ; + //===================================================================== + private boolean RestrictedCreature() + { + if (saved(RestrictedCreature)) return reuse(); + if (RestrictedCreature_0()) return sem.action() && accept(); + if (RestrictedCreature_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // RestrictedCreature_0 = (CreatureRestriction SPACE)* Creature + // (SPACE CreatureRestriction)* + //------------------------------------------------------------------- + private boolean RestrictedCreature_0() + { + if (savedInner(RestrictedCreature_0)) return reuseInner(); + while (RestrictedCreature_2()); + if (!Creature()) return rejectInner(); + while (RestrictedCreature_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // RestrictedCreature_1 = (CreatureRestriction SPACE)*+ Tribal + // (SPACE CreatureRestriction)* + //------------------------------------------------------------------- + private boolean RestrictedCreature_1() + { + if (savedInner(RestrictedCreature_1)) return reuseInner(); + while (!Tribal()) + if (!RestrictedCreature_4()) return rejectInner(); + while (RestrictedCreature_3()); + return acceptInner(); + } + + //------------------------------------------------------------------- + // RestrictedCreature_2 = CreatureRestriction SPACE + //------------------------------------------------------------------- + private boolean RestrictedCreature_2() + { + if (savedInner(RestrictedCreature_2)) return reuseInner(); + if (!CreatureRestriction()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // RestrictedCreature_3 = SPACE CreatureRestriction + //------------------------------------------------------------------- + private boolean RestrictedCreature_3() + { + if (savedInner(RestrictedCreature_3)) return reuseInner(); + if (!SPACE()) return rejectInner(); + if (!CreatureRestriction()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // RestrictedCreature_4 = CreatureRestriction SPACE + //------------------------------------------------------------------- + private boolean RestrictedCreature_4() + { + if (savedInner(RestrictedCreature_4)) return reuseInner(); + if (!CreatureRestriction()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // PermanentRestriction = ColorSpec / SelectPlayer " control" "s"? / + // SelectPlayer " don't control" / "tapped" / "untapped" / + // "noncreature" / "nonartifact, nonblack" / "nonartifact" / + // "nonland" / "nontoken" / "token" "s"? / "artifact" / "other than + // @" / "another" / "other" / "legendary" / "enchanted" / "with + // converted mana cost " Number " or less" / "with converted mana + // cost " Number " or greater" / "with converted mana cost " Number + // ; + //===================================================================== + private boolean PermanentRestriction() + { + if (saved(PermanentRestriction)) return reuse(); + if (ColorSpec()) return sem.action() && accept(); + if (PermanentRestriction_0()) return sem.action() && accept(); + if (PermanentRestriction_1()) return sem.action() && accept(); + if (next("tapped")) return sem.action() && accept(); + if (next("untapped")) return sem.action() && accept(); + if (next("noncreature")) return sem.action() && accept(); + if (next("nonartifact, nonblack")) return sem.action() && accept(); + if (next("nonartifact")) return sem.action() && accept(); + if (next("nonland")) return sem.action() && accept(); + if (next("nontoken")) return sem.action() && accept(); + if (PermanentRestriction_2()) return sem.action() && accept(); + if (next("artifact")) return sem.action() && accept(); + if (next("other than @")) return sem.action() && accept(); + if (next("another")) return sem.action() && accept(); + if (next("other")) return sem.action() && accept(); + if (next("legendary")) return sem.action() && accept(); + if (next("enchanted")) return sem.action() && accept(); + if (SpellRestriction_0()) return sem.action() && accept(); + if (SpellRestriction_1()) return sem.action() && accept(); + if (SpellRestriction_2()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // PermanentRestriction_0 = SelectPlayer " control" "s"? + //------------------------------------------------------------------- + private boolean PermanentRestriction_0() + { + if (savedInner(PermanentRestriction_0)) return reuseInner(); + if (!SelectPlayer()) return rejectInner(); + if (!next(" control")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // PermanentRestriction_1 = SelectPlayer " don't control" + //------------------------------------------------------------------- + private boolean PermanentRestriction_1() + { + if (savedInner(PermanentRestriction_1)) return reuseInner(); + if (!SelectPlayer()) return rejectInner(); + if (!next(" don't control")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // PermanentRestriction_2 = "token" "s"? + //------------------------------------------------------------------- + private boolean PermanentRestriction_2() + { + if (savedInner(PermanentRestriction_2)) return reuseInner(); + if (!next("token")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //===================================================================== + // CreatureRestriction = "with power " Number " or less" / "with power + // " Number " or greater" / "with " Keyword / "without " Keyword / + // "with a " (CounterType SPACE)? "counter on it" / "tapped or + // blocking" / "attacking or blocking" / "attacking" / "blocking" / + // "blocked" / "equipped" / Tribal / PermanentRestriction / + // PowerToughness ; + //===================================================================== + private boolean CreatureRestriction() + { + if (saved(CreatureRestriction)) return reuse(); + if (CreatureRestriction_0()) return sem.action() && accept(); + if (CreatureRestriction_1()) return sem.action() && accept(); + if (WithAbilitySpec_1()) return sem.action() && accept(); + if (CreatureRestriction_2()) return sem.action() && accept(); + if (CreatureRestriction_3()) return sem.action() && accept(); + if (next("tapped or blocking")) return sem.action() && accept(); + if (next("attacking or blocking")) return sem.action() && accept(); + if (next("attacking")) return sem.action() && accept(); + if (next("blocking")) return sem.action() && accept(); + if (next("blocked")) return sem.action() && accept(); + if (next("equipped")) return sem.action() && accept(); + if (Tribal()) return sem.action() && accept(); + if (PermanentRestriction()) return sem.action() && accept(); + if (PowerToughness()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // CreatureRestriction_0 = "with power " Number " or less" + //------------------------------------------------------------------- + private boolean CreatureRestriction_0() + { + if (savedInner(CreatureRestriction_0)) return reuseInner(); + if (!next("with power ")) return rejectInner(); + if (!Number()) return rejectInner(); + if (!next(" or less")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // CreatureRestriction_1 = "with power " Number " or greater" + //------------------------------------------------------------------- + private boolean CreatureRestriction_1() + { + if (savedInner(CreatureRestriction_1)) return reuseInner(); + if (!next("with power ")) return rejectInner(); + if (!Number()) return rejectInner(); + if (!next(" or greater")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // CreatureRestriction_2 = "without " Keyword + //------------------------------------------------------------------- + private boolean CreatureRestriction_2() + { + if (savedInner(CreatureRestriction_2)) return reuseInner(); + if (!next("without ")) return rejectInner(); + if (!Keyword()) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // CreatureRestriction_3 = "with a " (CounterType SPACE)? "counter + // on it" + //------------------------------------------------------------------- + private boolean CreatureRestriction_3() + { + if (savedInner(CreatureRestriction_3)) return reuseInner(); + if (!next("with a ")) return rejectInner(); + CreatureRestriction_4(); + if (!next("counter on it")) return rejectInner(); + return acceptInner(); + } + + //------------------------------------------------------------------- + // CreatureRestriction_4 = CounterType SPACE + //------------------------------------------------------------------- + private boolean CreatureRestriction_4() + { + if (savedInner(CreatureRestriction_4)) return reuseInner(); + if (!CounterType()) return rejectInner(); + if (!SPACE()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // LandRestriction = "nonbasic" / "basic" / PermanentRestriction ; + //===================================================================== + private boolean LandRestriction() + { + if (saved(LandRestriction)) return reuse(); + if (next("nonbasic")) return sem.action() && accept(); + if (next("basic")) return sem.action() && accept(); + if (PermanentRestriction()) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Color = "black" / "blue" / "green" / "red" / "white" ; + //===================================================================== + private boolean Color() + { + if (saved(Color)) return reuse(); + if (next("black")) return sem.action() && accept(); + if (next("blue")) return sem.action() && accept(); + if (next("green")) return sem.action() && accept(); + if (next("red")) return sem.action() && accept(); + if (next("white")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Tribal = CreatureType "s"? / "non-" CreatureType ; + //===================================================================== + private boolean Tribal() + { + if (saved(Tribal)) return reuse(); + if (Tribal_0()) return sem.action() && accept(); + if (Tribal_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // Tribal_0 = CreatureType "s"? + //------------------------------------------------------------------- + private boolean Tribal_0() + { + if (savedInner(Tribal_0)) return reuseInner(); + if (!CreatureType()) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Tribal_1 = "non-" CreatureType + //------------------------------------------------------------------- + private boolean Tribal_1() + { + if (savedInner(Tribal_1)) return reuseInner(); + if (!next("non-")) return rejectInner(); + if (!CreatureType()) return rejectInner(); + return acceptInner(); + } + + //===================================================================== + // CreatureType = "advisor" / "ally" / "angel" / "anteater" / + // "antelope" / "ape" / "archer" / "archon" / "artificer" / + // "assassin" / "assembly-worker" / "atog" / "aurochs" / "avatar" / + // "badger" / "barbarian" / "basilisk" / "bat" / "bear" / "beast" / + // "beeble" / "berserker" / "bird" / "blinkmoth" / "boar" / + // "bringer" / "brushwagg" / "camarid" / "camel" / "caribou" / + // "carrier" / "cat" / "centaur" / "cephalid" / "chimera" / + // "citizen" / "cleric" / "cockatrice" / "construct" / "coward" / + // "crab" / "crocodile" / "cyclops" / "dauthi" / "demon" / + // "deserter" / "devil" / "djinn" / "dragon" / "drake" / + // "dreadnought" / "drone" / "druid" / "dryad" / "dwarf" / "efreet" + // / "elder" / "eldrazi" / "elemental" / "elephant" / "elf" / "elk" + // / "eye" / "faerie" / "ferret" / "fish" / "flagbearer" / "fox" / + // "frog" / "fungus" / "gargoyle" / "germ" / "giant" / "gnome" / + // "goat" / "goblin" / "golem" / "gorgon" / "graveborn" / "gremlin" + // / "griffin" / "hag" / "harpy" / "hellion" / "hippo" / + // "hippogriff" / "homarid" / "homunculus" / "horror" / "horse" / + // "hound" / "human" / "hydra" / "hyena" / "illusion" / "imp" / + // "incarnation" / "insect" / "jellyfish" / "juggernaut" / "kavu" / + // "kirin" / "kithkin" / "knight" / "kobold" / "kor" / "kraken" / + // "lammasu" / "leech" / "leviathan" / "lhurgoyf" / "licid" / + // "lizard" / "manticore" / "masticore" / "mercenary" / "merfolk" / + // "metathran" / "minion" / "minotaur" / "monger" / "mongoose" / + // "monk" / "moonfolk" / "mutant" / "myr" / "mystic" / "nautilus" / + // "nephilim" / "nightmare" / "nightstalker" / "ninja" / "noggle" / + // "nomad" / "octopus" / "ogre" / "ooze" / "orb" / "orc" / "orgg" / + // "ouphe" / "ox" / "oyster" / "pegasus" / "pentavite" / "pest" / + // "phelddagrif" / "phoenix" / "pincher" / "pirate" / "plant" / + // "praetor" / "prism" / "rabbit" / "rat" / "rebel" / "reflection" / + // "rhino" / "rigger" / "rogue" / "salamander" / "samurai" / "sand" + // / "saproling" / "satyr" / "scarecrow" / "scorpion" / "scout" / + // "serf" / "serpent" / "shade" / "shaman" / "shapeshifter" / + // "sheep" / "siren" / "skeleton" / "slith" / "sliver" / "slug" / + // "snake" / "soldier" / "soltari" / "spawn" / "specter" / + // "spellshaper" / "sphinx" / "spider" / "spike" / "spirit" / + // "splinter" / "sponge" / "squid" / "squirrel" / "starfish" / + // "surrakar" / "survivor" / "tetravite" / "thalakos" / "thopter" / + // "thrull" / "treefolk" / "triskelavite" / "troll" / "turtle" / + // "unicorn" / "vampire" / "vedalken" / "viashino" / "volver" / + // "wall" / "warrior" / "weird" / "werewolf" / "whale" / "wizard" / + // "wolf" / "wolverine" / "wombat" / "worm" / "wraith" / "wurm" / + // "yeti" / "zombie" / "zubera" ; + //===================================================================== + private boolean CreatureType() + { + if (saved(CreatureType)) return reuse(); + if (next("advisor")) return sem.action() && accept(); + if (next("ally")) return sem.action() && accept(); + if (next("angel")) return sem.action() && accept(); + if (next("anteater")) return sem.action() && accept(); + if (next("antelope")) return sem.action() && accept(); + if (next("ape")) return sem.action() && accept(); + if (next("archer")) return sem.action() && accept(); + if (next("archon")) return sem.action() && accept(); + if (next("artificer")) return sem.action() && accept(); + if (next("assassin")) return sem.action() && accept(); + if (next("assembly-worker")) return sem.action() && accept(); + if (next("atog")) return sem.action() && accept(); + if (next("aurochs")) return sem.action() && accept(); + if (next("avatar")) return sem.action() && accept(); + if (next("badger")) return sem.action() && accept(); + if (next("barbarian")) return sem.action() && accept(); + if (next("basilisk")) return sem.action() && accept(); + if (next("bat")) return sem.action() && accept(); + if (next("bear")) return sem.action() && accept(); + if (next("beast")) return sem.action() && accept(); + if (next("beeble")) return sem.action() && accept(); + if (next("berserker")) return sem.action() && accept(); + if (next("bird")) return sem.action() && accept(); + if (next("blinkmoth")) return sem.action() && accept(); + if (next("boar")) return sem.action() && accept(); + if (next("bringer")) return sem.action() && accept(); + if (next("brushwagg")) return sem.action() && accept(); + if (next("camarid")) return sem.action() && accept(); + if (next("camel")) return sem.action() && accept(); + if (next("caribou")) return sem.action() && accept(); + if (next("carrier")) return sem.action() && accept(); + if (next("cat")) return sem.action() && accept(); + if (next("centaur")) return sem.action() && accept(); + if (next("cephalid")) return sem.action() && accept(); + if (next("chimera")) return sem.action() && accept(); + if (next("citizen")) return sem.action() && accept(); + if (next("cleric")) return sem.action() && accept(); + if (next("cockatrice")) return sem.action() && accept(); + if (next("construct")) return sem.action() && accept(); + if (next("coward")) return sem.action() && accept(); + if (next("crab")) return sem.action() && accept(); + if (next("crocodile")) return sem.action() && accept(); + if (next("cyclops")) return sem.action() && accept(); + if (next("dauthi")) return sem.action() && accept(); + if (next("demon")) return sem.action() && accept(); + if (next("deserter")) return sem.action() && accept(); + if (next("devil")) return sem.action() && accept(); + if (next("djinn")) return sem.action() && accept(); + if (next("dragon")) return sem.action() && accept(); + if (next("drake")) return sem.action() && accept(); + if (next("dreadnought")) return sem.action() && accept(); + if (next("drone")) return sem.action() && accept(); + if (next("druid")) return sem.action() && accept(); + if (next("dryad")) return sem.action() && accept(); + if (next("dwarf")) return sem.action() && accept(); + if (next("efreet")) return sem.action() && accept(); + if (next("elder")) return sem.action() && accept(); + if (next("eldrazi")) return sem.action() && accept(); + if (next("elemental")) return sem.action() && accept(); + if (next("elephant")) return sem.action() && accept(); + if (next("elf")) return sem.action() && accept(); + if (next("elk")) return sem.action() && accept(); + if (next("eye")) return sem.action() && accept(); + if (next("faerie")) return sem.action() && accept(); + if (next("ferret")) return sem.action() && accept(); + if (next("fish")) return sem.action() && accept(); + if (next("flagbearer")) return sem.action() && accept(); + if (next("fox")) return sem.action() && accept(); + if (next("frog")) return sem.action() && accept(); + if (next("fungus")) return sem.action() && accept(); + if (next("gargoyle")) return sem.action() && accept(); + if (next("germ")) return sem.action() && accept(); + if (next("giant")) return sem.action() && accept(); + if (next("gnome")) return sem.action() && accept(); + if (next("goat")) return sem.action() && accept(); + if (next("goblin")) return sem.action() && accept(); + if (next("golem")) return sem.action() && accept(); + if (next("gorgon")) return sem.action() && accept(); + if (next("graveborn")) return sem.action() && accept(); + if (next("gremlin")) return sem.action() && accept(); + if (next("griffin")) return sem.action() && accept(); + if (next("hag")) return sem.action() && accept(); + if (next("harpy")) return sem.action() && accept(); + if (next("hellion")) return sem.action() && accept(); + if (next("hippo")) return sem.action() && accept(); + if (next("hippogriff")) return sem.action() && accept(); + if (next("homarid")) return sem.action() && accept(); + if (next("homunculus")) return sem.action() && accept(); + if (next("horror")) return sem.action() && accept(); + if (next("horse")) return sem.action() && accept(); + if (next("hound")) return sem.action() && accept(); + if (next("human")) return sem.action() && accept(); + if (next("hydra")) return sem.action() && accept(); + if (next("hyena")) return sem.action() && accept(); + if (next("illusion")) return sem.action() && accept(); + if (next("imp")) return sem.action() && accept(); + if (next("incarnation")) return sem.action() && accept(); + if (next("insect")) return sem.action() && accept(); + if (next("jellyfish")) return sem.action() && accept(); + if (next("juggernaut")) return sem.action() && accept(); + if (next("kavu")) return sem.action() && accept(); + if (next("kirin")) return sem.action() && accept(); + if (next("kithkin")) return sem.action() && accept(); + if (next("knight")) return sem.action() && accept(); + if (next("kobold")) return sem.action() && accept(); + if (next("kor")) return sem.action() && accept(); + if (next("kraken")) return sem.action() && accept(); + if (next("lammasu")) return sem.action() && accept(); + if (next("leech")) return sem.action() && accept(); + if (next("leviathan")) return sem.action() && accept(); + if (next("lhurgoyf")) return sem.action() && accept(); + if (next("licid")) return sem.action() && accept(); + if (next("lizard")) return sem.action() && accept(); + if (next("manticore")) return sem.action() && accept(); + if (next("masticore")) return sem.action() && accept(); + if (next("mercenary")) return sem.action() && accept(); + if (next("merfolk")) return sem.action() && accept(); + if (next("metathran")) return sem.action() && accept(); + if (next("minion")) return sem.action() && accept(); + if (next("minotaur")) return sem.action() && accept(); + if (next("monger")) return sem.action() && accept(); + if (next("mongoose")) return sem.action() && accept(); + if (next("monk")) return sem.action() && accept(); + if (next("moonfolk")) return sem.action() && accept(); + if (next("mutant")) return sem.action() && accept(); + if (next("myr")) return sem.action() && accept(); + if (next("mystic")) return sem.action() && accept(); + if (next("nautilus")) return sem.action() && accept(); + if (next("nephilim")) return sem.action() && accept(); + if (next("nightmare")) return sem.action() && accept(); + if (next("nightstalker")) return sem.action() && accept(); + if (next("ninja")) return sem.action() && accept(); + if (next("noggle")) return sem.action() && accept(); + if (next("nomad")) return sem.action() && accept(); + if (next("octopus")) return sem.action() && accept(); + if (next("ogre")) return sem.action() && accept(); + if (next("ooze")) return sem.action() && accept(); + if (next("orb")) return sem.action() && accept(); + if (next("orc")) return sem.action() && accept(); + if (next("orgg")) return sem.action() && accept(); + if (next("ouphe")) return sem.action() && accept(); + if (next("ox")) return sem.action() && accept(); + if (next("oyster")) return sem.action() && accept(); + if (next("pegasus")) return sem.action() && accept(); + if (next("pentavite")) return sem.action() && accept(); + if (next("pest")) return sem.action() && accept(); + if (next("phelddagrif")) return sem.action() && accept(); + if (next("phoenix")) return sem.action() && accept(); + if (next("pincher")) return sem.action() && accept(); + if (next("pirate")) return sem.action() && accept(); + if (next("plant")) return sem.action() && accept(); + if (next("praetor")) return sem.action() && accept(); + if (next("prism")) return sem.action() && accept(); + if (next("rabbit")) return sem.action() && accept(); + if (next("rat")) return sem.action() && accept(); + if (next("rebel")) return sem.action() && accept(); + if (next("reflection")) return sem.action() && accept(); + if (next("rhino")) return sem.action() && accept(); + if (next("rigger")) return sem.action() && accept(); + if (next("rogue")) return sem.action() && accept(); + if (next("salamander")) return sem.action() && accept(); + if (next("samurai")) return sem.action() && accept(); + if (next("sand")) return sem.action() && accept(); + if (next("saproling")) return sem.action() && accept(); + if (next("satyr")) return sem.action() && accept(); + if (next("scarecrow")) return sem.action() && accept(); + if (next("scorpion")) return sem.action() && accept(); + if (next("scout")) return sem.action() && accept(); + if (next("serf")) return sem.action() && accept(); + if (next("serpent")) return sem.action() && accept(); + if (next("shade")) return sem.action() && accept(); + if (next("shaman")) return sem.action() && accept(); + if (next("shapeshifter")) return sem.action() && accept(); + if (next("sheep")) return sem.action() && accept(); + if (next("siren")) return sem.action() && accept(); + if (next("skeleton")) return sem.action() && accept(); + if (next("slith")) return sem.action() && accept(); + if (next("sliver")) return sem.action() && accept(); + if (next("slug")) return sem.action() && accept(); + if (next("snake")) return sem.action() && accept(); + if (next("soldier")) return sem.action() && accept(); + if (next("soltari")) return sem.action() && accept(); + if (next("spawn")) return sem.action() && accept(); + if (next("specter")) return sem.action() && accept(); + if (next("spellshaper")) return sem.action() && accept(); + if (next("sphinx")) return sem.action() && accept(); + if (next("spider")) return sem.action() && accept(); + if (next("spike")) return sem.action() && accept(); + if (next("spirit")) return sem.action() && accept(); + if (next("splinter")) return sem.action() && accept(); + if (next("sponge")) return sem.action() && accept(); + if (next("squid")) return sem.action() && accept(); + if (next("squirrel")) return sem.action() && accept(); + if (next("starfish")) return sem.action() && accept(); + if (next("surrakar")) return sem.action() && accept(); + if (next("survivor")) return sem.action() && accept(); + if (next("tetravite")) return sem.action() && accept(); + if (next("thalakos")) return sem.action() && accept(); + if (next("thopter")) return sem.action() && accept(); + if (next("thrull")) return sem.action() && accept(); + if (next("treefolk")) return sem.action() && accept(); + if (next("triskelavite")) return sem.action() && accept(); + if (next("troll")) return sem.action() && accept(); + if (next("turtle")) return sem.action() && accept(); + if (next("unicorn")) return sem.action() && accept(); + if (next("vampire")) return sem.action() && accept(); + if (next("vedalken")) return sem.action() && accept(); + if (next("viashino")) return sem.action() && accept(); + if (next("volver")) return sem.action() && accept(); + if (next("wall")) return sem.action() && accept(); + if (next("warrior")) return sem.action() && accept(); + if (next("weird")) return sem.action() && accept(); + if (next("werewolf")) return sem.action() && accept(); + if (next("whale")) return sem.action() && accept(); + if (next("wizard")) return sem.action() && accept(); + if (next("wolf")) return sem.action() && accept(); + if (next("wolverine")) return sem.action() && accept(); + if (next("wombat")) return sem.action() && accept(); + if (next("worm")) return sem.action() && accept(); + if (next("wraith")) return sem.action() && accept(); + if (next("wurm")) return sem.action() && accept(); + if (next("yeti")) return sem.action() && accept(); + if (next("zombie")) return sem.action() && accept(); + if (next("zubera")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // Creature = "creature" "s"? ; + //===================================================================== + private boolean Creature() + { + if (saved(Creature)) return reuse(); + if (!next("creature")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // Artifact = "artifact" "s"? / "equipment" "s"? ; + //===================================================================== + private boolean Artifact() + { + if (saved(Artifact)) return reuse(); + if (Artifact_0()) return sem.action() && accept(); + if (Artifact_1()) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // Artifact_0 = "artifact" "s"? + //------------------------------------------------------------------- + private boolean Artifact_0() + { + if (savedInner(Artifact_0)) return reuseInner(); + if (!next("artifact")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Artifact_1 = "equipment" "s"? + //------------------------------------------------------------------- + private boolean Artifact_1() + { + if (savedInner(Artifact_1)) return reuseInner(); + if (!next("equipment")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //===================================================================== + // Land = "land" "s"? / "swamp" "s"? / "island" "s"? / "forest" "s"? / + // "mountain" "s"? / "plains" ; + //===================================================================== + private boolean Land() + { + if (saved(Land)) return reuse(); + if (Land_0()) return sem.action() && accept(); + if (Land_1()) return sem.action() && accept(); + if (Land_2()) return sem.action() && accept(); + if (Land_3()) return sem.action() && accept(); + if (Land_4()) return sem.action() && accept(); + if (next("plains")) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // Land_0 = "land" "s"? + //------------------------------------------------------------------- + private boolean Land_0() + { + if (savedInner(Land_0)) return reuseInner(); + if (!next("land")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Land_1 = "swamp" "s"? + //------------------------------------------------------------------- + private boolean Land_1() + { + if (savedInner(Land_1)) return reuseInner(); + if (!next("swamp")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Land_2 = "island" "s"? + //------------------------------------------------------------------- + private boolean Land_2() + { + if (savedInner(Land_2)) return reuseInner(); + if (!next("island")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Land_3 = "forest" "s"? + //------------------------------------------------------------------- + private boolean Land_3() + { + if (savedInner(Land_3)) return reuseInner(); + if (!next("forest")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //------------------------------------------------------------------- + // Land_4 = "mountain" "s"? + //------------------------------------------------------------------- + private boolean Land_4() + { + if (savedInner(Land_4)) return reuseInner(); + if (!next("mountain")) return rejectInner(); + next('s'); + return acceptInner(); + } + + //===================================================================== + // Enchantment = "enchantment" "s"? ; + //===================================================================== + private boolean Enchantment() + { + if (saved(Enchantment)) return reuse(); + if (!next("enchantment")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // Permanent = "permanent" "s"? ; + //===================================================================== + private boolean Permanent() + { + if (saved(Permanent)) return reuse(); + if (!next("permanent")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // Card = "card" "s"? ; + //===================================================================== + private boolean Card() + { + if (saved(Card)) return reuse(); + if (!next("card")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // Spell = "spell" "s"? ; + //===================================================================== + private boolean Spell() + { + if (saved(Spell)) return reuse(); + if (!next("spell")) return reject(); + next('s'); + return sem.action() && accept(); + } + + //===================================================================== + // NoRegen = "it can't be regenerated" / "they can't be regenerated" + // ; + //===================================================================== + private boolean NoRegen() + { + if (saved(NoRegen)) return reuse(); + if (next("it can't be regenerated")) return sem.action() && accept(); + if (next("they can't be regenerated")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // PowerToughness = Number "/" Number ; + //===================================================================== + private boolean PowerToughness() + { + if (saved(PowerToughness)) return reuse(); + if (!Number()) return reject(); + if (!next('/')) return reject(); + if (!Number()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // SignedNumber = Sign Number ; + //===================================================================== + private boolean SignedNumber() + { + if (saved(SignedNumber)) return reuse(); + if (!Sign()) return reject(); + if (!Number()) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // Number = [0-9]+ / "that much" / "x" ; + //===================================================================== + private boolean Number() + { + if (saved(Number)) return reuse(); + if (Number_0()) return sem.action() && accept(); + if (next("that much")) return sem.action() && accept(); + if (next('x')) return sem.action() && accept(); + return reject(); + } + + //------------------------------------------------------------------- + // Number_0 = [0-9]+ + //------------------------------------------------------------------- + private boolean Number_0() + { + if (savedInner(Number_0)) return reuseInner(); + if (!nextIn('0','9')) return rejectInner(); + while (nextIn('0','9')); + return acceptInner(); + } + + //===================================================================== + // Sign = "+" / "-" ; + //===================================================================== + private boolean Sign() + { + if (saved(Sign)) return reuse(); + if (next('+')) return sem.action() && accept(); + if (next('-')) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // SEP = ", or " / ", and " / ", then " / ", " / " or " / " and " ; + //===================================================================== + private boolean SEP() + { + if (saved(SEP)) return reuse(); + if (next(", or ")) return sem.action() && accept(); + if (next(", and ")) return sem.action() && accept(); + if (next(", then ")) return sem.action() && accept(); + if (next(", ")) return sem.action() && accept(); + if (next(" or ")) return sem.action() && accept(); + if (next(" and ")) return sem.action() && accept(); + return reject(); + } + + //===================================================================== + // EOC = ": " ; + //===================================================================== + private boolean EOC() + { + if (saved(EOC)) return reuse(); + if (!next(": ")) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // SPACE = " " ; + //===================================================================== + private boolean SPACE() + { + if (saved(SPACE)) return reuse(); + if (!next(' ')) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // EOS = "." ; + //===================================================================== + private boolean EOS() + { + if (saved(EOS)) return reuse(); + if (!next('.')) return reject(); + return sem.action() && accept(); + } + + //===================================================================== + // EOR = !_ ; + //===================================================================== + private boolean EOR() + { + if (saved(EOR)) return reuse(); + if (!aheadNot()) return reject(); + return sem.action() && accept(); + } + + //======================================================================= + // + // Cache objects + // + //======================================================================= + + final Cache Rule = new Cache("Rule","Rule"); + final Cache Ability = new Cache("Ability","Ability"); + final Cache SpellEffect = new Cache("SpellEffect","SpellEffect"); + final Cache Effect = new Cache("Effect","Effect"); + final Cache SingleEffect = new Cache("SingleEffect","SingleEffect"); + final Cache Optional = new Cache("Optional","Optional"); + final Cache AbilityWord = new Cache("AbilityWord","AbilityWord"); + final Cache KeywordAbility = new Cache("KeywordAbility","KeywordAbility"); + final Cache ActivatedAbility = new Cache("ActivatedAbility","ActivatedAbility"); + final Cache ActivationCosts = new Cache("ActivationCosts","ActivationCosts"); + final Cache TriggeredAbility = new Cache("TriggeredAbility","TriggeredAbility"); + final Cache AdditionalCost = new Cache("AdditionalCost","AdditionalCost"); + final Cache Trigger = new Cache("Trigger","Trigger"); + final Cache Action = new Cache("Action","Action"); + final Cache Keyword = new Cache("Keyword","Keyword"); + final Cache ColorlessCost = new Cache("ColorlessCost","ColorlessCost"); + final Cache SingleColor = new Cache("SingleColor","SingleColor"); + final Cache HybridSingleCost = new Cache("HybridSingleCost","HybridSingleCost"); + final Cache ManaCost = new Cache("ManaCost","ManaCost"); + final Cache BecomesTargetTrigger = new Cache("BecomesTargetTrigger","BecomesTargetTrigger"); + final Cache BlocksTrigger = new Cache("BlocksTrigger","BlocksTrigger"); + final Cache BlockedTrigger = new Cache("BlockedTrigger","BlockedTrigger"); + final Cache CastTrigger = new Cache("CastTrigger","CastTrigger"); + final Cache Cast = new Cache("Cast","Cast"); + final Cache LeavesBattlefieldTrigger = new Cache("LeavesBattlefieldTrigger","LeavesBattlefieldTrigger"); + final Cache EntersGraveyardTrigger = new Cache("EntersGraveyardTrigger","EntersGraveyardTrigger"); + final Cache EntersBattlefieldTrigger = new Cache("EntersBattlefieldTrigger","EntersBattlefieldTrigger"); + final Cache EntersVerb = new Cache("EntersVerb","EntersVerb"); + final Cache BeginningEndStepTrigger = new Cache("BeginningEndStepTrigger","BeginningEndStepTrigger"); + final Cache BeginningUpkeepTrigger = new Cache("BeginningUpkeepTrigger","BeginningUpkeepTrigger"); + final Cache DiesTrigger = new Cache("DiesTrigger","DiesTrigger"); + final Cache DealsDamageTrigger = new Cache("DealsDamageTrigger","DealsDamageTrigger"); + final Cache DamageReceiver = new Cache("DamageReceiver","DamageReceiver"); + final Cache AttacksTrigger = new Cache("AttacksTrigger","AttacksTrigger"); + final Cache AbilityRestriction = new Cache("AbilityRestriction","AbilityRestriction"); + final Cache IfCondition = new Cache("IfCondition","IfCondition"); + final Cache AnimateAction = new Cache("AnimateAction","AnimateAction"); + final Cache AnimateActionReminder = new Cache("AnimateActionReminder","AnimateActionReminder"); + final Cache ChangeLoyaltyAction = new Cache("ChangeLoyaltyAction","ChangeLoyaltyAction"); + final Cache ChangeStateAction = new Cache("ChangeStateAction","ChangeStateAction"); + final Cache PermanentState = new Cache("PermanentState","PermanentState"); + final Cache SetPTAction = new Cache("SetPTAction","SetPTAction"); + final Cache SacrificeAction = new Cache("SacrificeAction","SacrificeAction"); + final Cache PoisonAction = new Cache("PoisonAction","PoisonAction"); + final Cache MillAction = new Cache("MillAction","MillAction"); + final Cache DoesntUntapAction = new Cache("DoesntUntapAction","DoesntUntapAction"); + final Cache ShuffleAction = new Cache("ShuffleAction","ShuffleAction"); + final Cache PutTokenAction = new Cache("PutTokenAction","PutTokenAction"); + final Cache CreatureTokenSpec = new Cache("CreatureTokenSpec","CreatureTokenSpec"); + final Cache WithAbilitySpec = new Cache("WithAbilitySpec","WithAbilitySpec"); + final Cache CreatureSpec = new Cache("CreatureSpec","CreatureSpec"); + final Cache ControlAction = new Cache("ControlAction","ControlAction"); + final Cache ChangeCounterAction = new Cache("ChangeCounterAction","ChangeCounterAction"); + final Cache CounterVerb = new Cache("CounterVerb","CounterVerb"); + final Cache Counter = new Cache("Counter","Counter"); + final Cache PayManaAction = new Cache("PayManaAction","PayManaAction"); + final Cache ChangeLifeAction = new Cache("ChangeLifeAction","ChangeLifeAction"); + final Cache ChangeLifeVerb = new Cache("ChangeLifeVerb","ChangeLifeVerb"); + final Cache SelectPlayer = new Cache("SelectPlayer","SelectPlayer"); + final Cache Player = new Cache("Player","Player"); + final Cache PutCardAction = new Cache("PutCardAction","PutCardAction"); + final Cache ReturnAction = new Cache("ReturnAction","ReturnAction"); + final Cache BounceAction = new Cache("BounceAction","BounceAction"); + final Cache BounceLocation = new Cache("BounceLocation","BounceLocation"); + final Cache BounceVerb = new Cache("BounceVerb","BounceVerb"); + final Cache PreventAction = new Cache("PreventAction","PreventAction"); + final Cache DamageRestriction = new Cache("DamageRestriction","DamageRestriction"); + final Cache DamageVerb = new Cache("DamageVerb","DamageVerb"); + final Cache Damage = new Cache("Damage","Damage"); + final Cache TapAction = new Cache("TapAction","TapAction"); + final Cache TapVerb = new Cache("TapVerb","TapVerb"); + final Cache RegenerateAction = new Cache("RegenerateAction","RegenerateAction"); + final Cache DamageAction = new Cache("DamageAction","DamageAction"); + final Cache Deal = new Cache("Deal","Deal"); + final Cache EntersTapped = new Cache("EntersTapped","EntersTapped"); + final Cache EntersWithCounter = new Cache("EntersWithCounter","EntersWithCounter"); + final Cache CounterType = new Cache("CounterType","CounterType"); + final Cache Count = new Cache("Count","Count"); + final Cache Enchant = new Cache("Enchant","Enchant"); + final Cache Duration = new Cache("Duration","Duration"); + final Cache GainAction = new Cache("GainAction","GainAction"); + final Cache GainVerb = new Cache("GainVerb","GainVerb"); + final Cache PumpAction = new Cache("PumpAction","PumpAction"); + final Cache AddManaAction = new Cache("AddManaAction","AddManaAction"); + final Cache ManaSource = new Cache("ManaSource","ManaSource"); + final Cache DrawAction = new Cache("DrawAction","DrawAction"); + final Cache Draw = new Cache("Draw","Draw"); + final Cache DiscardAction = new Cache("DiscardAction","DiscardAction"); + final Cache Discard = new Cache("Discard","Discard"); + final Cache DestroyNoRegenAction = new Cache("DestroyNoRegenAction","DestroyNoRegenAction"); + final Cache DestroyAction = new Cache("DestroyAction","DestroyAction"); + final Cache ExileAction = new Cache("ExileAction","ExileAction"); + final Cache CounterAction = new Cache("CounterAction","CounterAction"); + final Cache SelectOp = new Cache("SelectOp","SelectOp"); + final Cache SelectCard = new Cache("SelectCard","SelectCard"); + final Cache SelectCreature = new Cache("SelectCreature","SelectCreature"); + final Cache SelectPermanent = new Cache("SelectPermanent","SelectPermanent"); + final Cache SelectSpell = new Cache("SelectSpell","SelectSpell"); + final Cache RestrictedPermanent = new Cache("RestrictedPermanent","RestrictedPermanent"); + final Cache RestrictedArtifact = new Cache("RestrictedArtifact","RestrictedArtifact"); + final Cache RestrictedEnchantment = new Cache("RestrictedEnchantment","RestrictedEnchantment"); + final Cache RestrictedLand = new Cache("RestrictedLand","RestrictedLand"); + final Cache RestrictedTribal = new Cache("RestrictedTribal","RestrictedTribal"); + final Cache RestrictedSpell = new Cache("RestrictedSpell","RestrictedSpell"); + final Cache ColorSpec = new Cache("ColorSpec","ColorSpec"); + final Cache SpellRestriction = new Cache("SpellRestriction","SpellRestriction"); + final Cache RestrictedCard = new Cache("RestrictedCard","RestrictedCard"); + final Cache CardRestriction = new Cache("CardRestriction","CardRestriction"); + final Cache RestrictedCreature = new Cache("RestrictedCreature","RestrictedCreature"); + final Cache PermanentRestriction = new Cache("PermanentRestriction","PermanentRestriction"); + final Cache CreatureRestriction = new Cache("CreatureRestriction","CreatureRestriction"); + final Cache LandRestriction = new Cache("LandRestriction","LandRestriction"); + final Cache Color = new Cache("Color","Color"); + final Cache Tribal = new Cache("Tribal","Tribal"); + final Cache CreatureType = new Cache("CreatureType","CreatureType"); + final Cache Creature = new Cache("Creature","Creature"); + final Cache Artifact = new Cache("Artifact","Artifact"); + final Cache Land = new Cache("Land","Land"); + final Cache Enchantment = new Cache("Enchantment","Enchantment"); + final Cache Permanent = new Cache("Permanent","Permanent"); + final Cache Card = new Cache("Card","Card"); + final Cache Spell = new Cache("Spell","Spell"); + final Cache NoRegen = new Cache("NoRegen","NoRegen"); + final Cache PowerToughness = new Cache("PowerToughness","PowerToughness"); + final Cache SignedNumber = new Cache("SignedNumber","SignedNumber"); + final Cache Number = new Cache("Number","Number"); + final Cache Sign = new Cache("Sign","Sign"); + final Cache SEP = new Cache("SEP","SEP"); + final Cache EOC = new Cache("EOC","EOC"); + final Cache SPACE = new Cache("SPACE","SPACE"); + final Cache EOS = new Cache("EOS","EOS"); + final Cache EOR = new Cache("EOR","EOR"); + + final Cache Rule_0 = new Cache("Rule_0"); // AbilityWord " \u2014 " + final Cache SpellEffect_0 = new Cache("SpellEffect_0"); // SPACE Effect EOS + final Cache Effect_0 = new Cache("Effect_0"); // SEP SingleEffect + final Cache SingleEffect_0 = new Cache("SingleEffect_0"); // Duration SEP + final Cache SingleEffect_1 = new Cache("SingleEffect_1"); // Optional SPACE + final Cache SingleEffect_2 = new Cache("SingleEffect_2"); // SelectPlayer SPACE + final Cache SingleEffect_3 = new Cache("SingleEffect_3"); // SPACE Duration + final Cache ActivatedAbility_0 = new Cache("ActivatedAbility_0"); // SPACE AbilityRestriction EOS + final Cache ActivationCosts_0 = new Cache("ActivationCosts_0"); // SEP Action + final Cache TriggeredAbility_0 = new Cache("TriggeredAbility_0"); // SEP IfCondition + final Cache Keyword_0 = new Cache("Keyword_0"); // "protection from " Color + final Cache Keyword_1 = new Cache("Keyword_1"); // "protection from " Tribal + final Cache Keyword_2 = new Cache("Keyword_2"); // "bushido" SPACE Number + final Cache Keyword_3 = new Cache("Keyword_3"); // "rampage" SPACE Number + final Cache Keyword_4 = new Cache("Keyword_4"); // "soulshift" SPACE Number + final Cache Keyword_5 = new Cache("Keyword_5"); // "fading" SPACE Number + final Cache Keyword_6 = new Cache("Keyword_6"); // "devour" SPACE Number + final Cache Keyword_7 = new Cache("Keyword_7"); // "modular" SPACE Number + final Cache Keyword_8 = new Cache("Keyword_8"); // "vanishing" SPACE Number + final Cache Keyword_9 = new Cache("Keyword_9"); // "bloodthirst" SPACE Number + final Cache Keyword_10 = new Cache("Keyword_10"); // "annihilator" SPACE Number + final Cache Keyword_11 = new Cache("Keyword_11"); // "buyback" SPACE ManaCost + final Cache Keyword_12 = new Cache("Keyword_12"); // "echo" SPACE ManaCost + final Cache Keyword_13 = new Cache("Keyword_13"); // "kicker" SPACE ManaCost + final Cache Keyword_14 = new Cache("Keyword_14"); // "multikicker" SPACE ManaCost + final Cache Keyword_15 = new Cache("Keyword_15"); // "equip" SPACE ManaCost + final Cache Keyword_16 = new Cache("Keyword_16"); // "cumulative upkeep" SPACE ManaCost + final Cache Keyword_17 = new Cache("Keyword_17"); // "replicate" SPACE ManaCost + final Cache Keyword_18 = new Cache("Keyword_18"); // "miracle" SPACE ManaCost + final Cache Keyword_19 = new Cache("Keyword_19"); // "level up" SPACE ManaCost + final Cache Keyword_20 = new Cache("Keyword_20"); // "level" SPACE Number "-" Number + final Cache Keyword_21 = new Cache("Keyword_21"); // "level" SPACE Number "+" + final Cache Keyword_22 = new Cache("Keyword_22"); // "champion" SPACE "a" "n"? SPACE SelectCreature + final Cache ColorlessCost_0 = new Cache("ColorlessCost_0"); // "{" Number "}" + final Cache ManaCost_0 = new Cache("ManaCost_0"); // ColorlessCost+ HybridSingleCost* SingleColor* + final Cache ManaCost_1 = new Cache("ManaCost_1"); // HybridSingleCost+ SingleColor* + final Cache ManaCost_2 = new Cache("ManaCost_2"); // SingleColor+ + final Cache CastTrigger_0 = new Cache("CastTrigger_0"); // "whenever " SelectPlayer SPACE Cast SPACE SelectSpell + final Cache CastTrigger_1 = new Cache("CastTrigger_1"); // "when " SelectPlayer SPACE Cast SPACE SelectSpell + final Cache EntersBattlefieldTrigger_0 = new Cache("EntersBattlefieldTrigger_0"); // SPACE "under your control" + final Cache DiesTrigger_0 = new Cache("DiesTrigger_0"); // "when" SPACE SelectCreature SPACE "dies" + final Cache DiesTrigger_1 = new Cache("DiesTrigger_1"); // "whenever" SPACE SelectCreature SPACE "dies" + final Cache DealsDamageTrigger_0 = new Cache("DealsDamageTrigger_0"); // " to a " DamageReceiver + final Cache DamageReceiver_0 = new Cache("DamageReceiver_0"); // SelectPlayer &(SEP SingleEffect) + final Cache DamageReceiver_1 = new Cache("DamageReceiver_1"); // SelectPlayer (SEP SelectCreature)? + final Cache DamageReceiver_2 = new Cache("DamageReceiver_2"); // SelectCreature &(SEP SingleEffect) + final Cache DamageReceiver_3 = new Cache("DamageReceiver_3"); // SelectCreature (SEP SelectPlayer)? + final Cache DamageReceiver_4 = new Cache("DamageReceiver_4","SEP SingleEffect"); // &(SEP SingleEffect) + final Cache DamageReceiver_5 = new Cache("DamageReceiver_5"); // SEP SelectCreature + final Cache DamageReceiver_6 = new Cache("DamageReceiver_6"); // SEP SelectPlayer + final Cache ChangeStateAction_0 = new Cache("ChangeStateAction_0"); // SelectPermanent SPACE + final Cache PermanentState_0 = new Cache("PermanentState_0"); // "are " ColorSpec + final Cache PermanentState_1 = new Cache("PermanentState_1"); // "are " Tribal " in addition to their other creature types" + final Cache SetPTAction_0 = new Cache("SetPTAction_0"); // "@'s power and toughness are each equal to the number of " SelectPermanent + final Cache SetPTAction_1 = new Cache("SetPTAction_1"); // SelectPermanent " are " Number "/" Number + final Cache SacrificeAction_0 = new Cache("SacrificeAction_0"); // SPACE "unless you" SPACE Action + final Cache MillAction_0 = new Cache("MillAction_0"); // Count SPACE + final Cache DoesntUntapAction_0 = new Cache("DoesntUntapAction_0"); // SelectPermanent " doesn't untap during its controller's untap step" + final Cache DoesntUntapAction_1 = new Cache("DoesntUntapAction_1"); // SelectPermanent " doesn't untap during its controller's next untap step" + final Cache DoesntUntapAction_2 = new Cache("DoesntUntapAction_2"); // SelectPermanent " doesn't untap during your untap step" + final Cache PutTokenAction_0 = new Cache("PutTokenAction_0"); // "put " Count SPACE CreatureTokenSpec " onto the battlefield" + final Cache PutTokenAction_1 = new Cache("PutTokenAction_1"); // "put a token that's a copy of " SelectPermanent " onto the battlefield" + final Cache CreatureTokenSpec_0 = new Cache("CreatureTokenSpec_0"); // SPACE CreatureType + final Cache CreatureTokenSpec_1 = new Cache("CreatureTokenSpec_1"); // SPACE WithAbilitySpec + final Cache WithAbilitySpec_0 = new Cache("WithAbilitySpec_0"); // "with " Keyword SEP Keyword + final Cache WithAbilitySpec_1 = new Cache("WithAbilitySpec_1"); // "with " Keyword + final Cache CreatureSpec_0 = new Cache("CreatureSpec_0"); // SPACE ColorSpec + final Cache ControlAction_0 = new Cache("ControlAction_0"); // "control" "s"? SPACE SelectPermanent + final Cache ControlAction_1 = new Cache("ControlAction_1"); // "gain control of " SelectPermanent + final Cache ChangeCounterAction_0 = new Cache("ChangeCounterAction_0"); // CounterVerb SPACE Count SPACE CounterType SPACE Counter " from " SelectPermanent + final Cache ChangeCounterAction_1 = new Cache("ChangeCounterAction_1"); // CounterVerb SPACE Count SPACE CounterType SPACE Counter " on " SelectPermanent + final Cache PayManaAction_0 = new Cache("PayManaAction_0"); // "pay" "s"? SPACE ManaCost + final Cache ChangeLifeVerb_0 = new Cache("ChangeLifeVerb_0"); // "lose" "s"? + final Cache ChangeLifeVerb_1 = new Cache("ChangeLifeVerb_1"); // "gain" "s"? + final Cache ChangeLifeVerb_2 = new Cache("ChangeLifeVerb_2"); // "pay" "s"? + final Cache SelectPlayer_0 = new Cache("SelectPlayer_0"); // Player &(SEP SingleEffect) + final Cache SelectPlayer_1 = new Cache("SelectPlayer_1"); // Player (SEP Player)* + final Cache SelectPlayer_2 = new Cache("SelectPlayer_2"); // SEP Player + final Cache PutCardAction_0 = new Cache("PutCardAction_0"); // "put " SelectCard " onto the battlefield under your control" + final Cache PutCardAction_1 = new Cache("PutCardAction_1"); // "put " SelectCard " onto the battlefield" + final Cache BounceVerb_0 = new Cache("BounceVerb_0"); // "return" "s"? + final Cache BounceVerb_1 = new Cache("BounceVerb_1"); // "put" "s"? + final Cache PreventAction_0 = new Cache("PreventAction_0"); // "prevent the next " Number SPACE Damage SPACE "that would be dealt" (SPACE DamageRestriction)? + final Cache PreventAction_1 = new Cache("PreventAction_1"); // "prevent all " Damage SPACE "that would be dealt" (SPACE DamageRestriction)? + final Cache PreventAction_2 = new Cache("PreventAction_2"); // "if damage would be dealt to " DamageReceiver ", prevent that damage" + final Cache PreventAction_3 = new Cache("PreventAction_3"); // SPACE DamageRestriction + final Cache DamageRestriction_0 = new Cache("DamageRestriction_0"); // SPACE "this turn by" SPACE DamageReceiver + final Cache TapAction_0 = new Cache("TapAction_0"); // TapVerb SPACE SelectPermanent + final Cache DamageAction_0 = new Cache("DamageAction_0"); // (SelectPermanent SPACE)? (Deal SPACE)? Number " damage to " DamageReceiver + final Cache DamageAction_1 = new Cache("DamageAction_1"); // SelectPermanent SPACE Deal " damage equal to its power to " DamageReceiver + final Cache DamageAction_2 = new Cache("DamageAction_2"); // SelectPermanent SPACE Deal " damage equal to the number of " CounterType " counters on it to " DamageReceiver + final Cache DamageAction_3 = new Cache("DamageAction_3"); // SelectPermanent SPACE Deal " damage to " DamageReceiver " equal to the number of " SelectPermanent + final Cache DamageAction_4 = new Cache("DamageAction_4"); // Deal SPACE + final Cache Enchant_0 = new Cache("Enchant_0"); // "enchant" SPACE RestrictedPermanent + final Cache Duration_0 = new Cache("Duration_0"); // "for as long as " SelectPlayer " control @" + final Cache GainAction_0 = new Cache("GainAction_0"); // SEP Keyword + final Cache ManaSource_0 = new Cache("ManaSource_0"); // SingleColor (SEP SingleColor)* + final Cache ManaSource_1 = new Cache("ManaSource_1"); // SEP SingleColor + final Cache DiscardAction_0 = new Cache("DiscardAction_0"); // Discard SPACE SelectCard " at random"? + final Cache DiscardAction_1 = new Cache("DiscardAction_1"); // Discard SPACE Count SPACE RestrictedCard " at random" + final Cache ExileAction_0 = new Cache("ExileAction_0"); // "exile " SelectPermanent + final Cache ExileAction_1 = new Cache("ExileAction_1"); // "exile " SelectCard + final Cache CounterAction_0 = new Cache("CounterAction_0"); // " unless " SingleEffect + final Cache SelectCard_0 = new Cache("SelectCard_0"); // "@" (SPACE CardRestriction)? (SEP RestrictedCard)* + final Cache SelectCard_1 = new Cache("SelectCard_1"); // "it" (SEP RestrictedCard)* + final Cache SelectCard_2 = new Cache("SelectCard_2"); // SelectOp SPACE RestrictedCard (SEP RestrictedCard)* + final Cache SelectCard_3 = new Cache("SelectCard_3"); // SPACE CardRestriction + final Cache SelectCard_4 = new Cache("SelectCard_4"); // SEP RestrictedCard + final Cache SelectCreature_0 = new Cache("SelectCreature_0"); // "@" (SEP RestrictedCreature)* + final Cache SelectCreature_1 = new Cache("SelectCreature_1"); // "it" (SEP RestrictedCreature)* + final Cache SelectCreature_2 = new Cache("SelectCreature_2"); // (SelectOp SPACE)? RestrictedCreature (SEP RestrictedCreature)* + final Cache SelectCreature_3 = new Cache("SelectCreature_3"); // SEP RestrictedCreature + final Cache SelectCreature_4 = new Cache("SelectCreature_4"); // SelectOp SPACE + final Cache SelectPermanent_0 = new Cache("SelectPermanent_0"); // "@" (SEP RestrictedPermanent)* + final Cache SelectPermanent_1 = new Cache("SelectPermanent_1"); // "it" (SEP RestrictedPermanent)* + final Cache SelectPermanent_2 = new Cache("SelectPermanent_2"); // (SelectOp SPACE)? RestrictedPermanent (SEP RestrictedPermanent)* + final Cache SelectPermanent_3 = new Cache("SelectPermanent_3"); // SEP RestrictedPermanent + final Cache SelectSpell_0 = new Cache("SelectSpell_0"); // "@" (SEP RestrictedSpell)* + final Cache SelectSpell_1 = new Cache("SelectSpell_1"); // "it" (SEP RestrictedSpell)* + final Cache SelectSpell_2 = new Cache("SelectSpell_2"); // (SelectOp SPACE)? RestrictedSpell (SEP RestrictedSpell)* + final Cache SelectSpell_3 = new Cache("SelectSpell_3"); // SEP RestrictedSpell + final Cache RestrictedPermanent_0 = new Cache("RestrictedPermanent_0"); // (PermanentRestriction SPACE)* Permanent (SPACE PermanentRestriction)* + final Cache RestrictedPermanent_1 = new Cache("RestrictedPermanent_1"); // PermanentRestriction SPACE + final Cache RestrictedPermanent_2 = new Cache("RestrictedPermanent_2"); // SPACE PermanentRestriction + final Cache RestrictedArtifact_0 = new Cache("RestrictedArtifact_0"); // PermanentRestriction SPACE + final Cache RestrictedLand_0 = new Cache("RestrictedLand_0"); // LandRestriction SPACE + final Cache RestrictedLand_1 = new Cache("RestrictedLand_1"); // SPACE LandRestriction + final Cache RestrictedSpell_0 = new Cache("RestrictedSpell_0"); // SpellRestriction SPACE + final Cache RestrictedSpell_1 = new Cache("RestrictedSpell_1"); // SPACE SpellRestriction + final Cache ColorSpec_0 = new Cache("ColorSpec_0"); // Color (SEP Color)* + final Cache ColorSpec_1 = new Cache("ColorSpec_1"); // "non" Color + final Cache ColorSpec_2 = new Cache("ColorSpec_2"); // SEP Color + final Cache SpellRestriction_0 = new Cache("SpellRestriction_0"); // "with converted mana cost " Number " or less" + final Cache SpellRestriction_1 = new Cache("SpellRestriction_1"); // "with converted mana cost " Number " or greater" + final Cache SpellRestriction_2 = new Cache("SpellRestriction_2"); // "with converted mana cost " Number + final Cache RestrictedCard_0 = new Cache("RestrictedCard_0"); // CardRestriction SPACE + final Cache RestrictedCreature_0 = new Cache("RestrictedCreature_0"); // (CreatureRestriction SPACE)* Creature (SPACE CreatureRestriction)* + final Cache RestrictedCreature_1 = new Cache("RestrictedCreature_1"); // (CreatureRestriction SPACE)*+ Tribal (SPACE CreatureRestriction)* + final Cache RestrictedCreature_2 = new Cache("RestrictedCreature_2"); // CreatureRestriction SPACE + final Cache RestrictedCreature_3 = new Cache("RestrictedCreature_3"); // SPACE CreatureRestriction + final Cache RestrictedCreature_4 = new Cache("RestrictedCreature_4"); // CreatureRestriction SPACE + final Cache PermanentRestriction_0 = new Cache("PermanentRestriction_0"); // SelectPlayer " control" "s"? + final Cache PermanentRestriction_1 = new Cache("PermanentRestriction_1"); // SelectPlayer " don't control" + final Cache PermanentRestriction_2 = new Cache("PermanentRestriction_2"); // "token" "s"? + final Cache CreatureRestriction_0 = new Cache("CreatureRestriction_0"); // "with power " Number " or less" + final Cache CreatureRestriction_1 = new Cache("CreatureRestriction_1"); // "with power " Number " or greater" + final Cache CreatureRestriction_2 = new Cache("CreatureRestriction_2"); // "without " Keyword + final Cache CreatureRestriction_3 = new Cache("CreatureRestriction_3"); // "with a " (CounterType SPACE)? "counter on it" + final Cache CreatureRestriction_4 = new Cache("CreatureRestriction_4"); // CounterType SPACE + final Cache Tribal_0 = new Cache("Tribal_0"); // CreatureType "s"? + final Cache Tribal_1 = new Cache("Tribal_1"); // "non-" CreatureType + final Cache Artifact_0 = new Cache("Artifact_0"); // "artifact" "s"? + final Cache Artifact_1 = new Cache("Artifact_1"); // "equipment" "s"? + final Cache Land_0 = new Cache("Land_0"); // "land" "s"? + final Cache Land_1 = new Cache("Land_1"); // "swamp" "s"? + final Cache Land_2 = new Cache("Land_2"); // "island" "s"? + final Cache Land_3 = new Cache("Land_3"); // "forest" "s"? + final Cache Land_4 = new Cache("Land_4"); // "mountain" "s"? + final Cache Number_0 = new Cache("Number_0"); // [0-9]+ + + //------------------------------------------------------------------- + // List of Cache objects + //------------------------------------------------------------------- + + Cache[] cacheList = + { + Rule,Ability,SpellEffect,Effect,SingleEffect,Optional,AbilityWord, + KeywordAbility,ActivatedAbility,ActivationCosts,TriggeredAbility, + AdditionalCost,Trigger,Action,Keyword,ColorlessCost,SingleColor, + HybridSingleCost,ManaCost,BecomesTargetTrigger,BlocksTrigger, + BlockedTrigger,CastTrigger,Cast,LeavesBattlefieldTrigger, + EntersGraveyardTrigger,EntersBattlefieldTrigger,EntersVerb, + BeginningEndStepTrigger,BeginningUpkeepTrigger,DiesTrigger, + DealsDamageTrigger,DamageReceiver,AttacksTrigger, + AbilityRestriction,IfCondition,AnimateAction, + AnimateActionReminder,ChangeLoyaltyAction,ChangeStateAction, + PermanentState,SetPTAction,SacrificeAction,PoisonAction, + MillAction,DoesntUntapAction,ShuffleAction,PutTokenAction, + CreatureTokenSpec,WithAbilitySpec,CreatureSpec,ControlAction, + ChangeCounterAction,CounterVerb,Counter,PayManaAction, + ChangeLifeAction,ChangeLifeVerb,SelectPlayer,Player,PutCardAction, + ReturnAction,BounceAction,BounceLocation,BounceVerb,PreventAction, + DamageRestriction,DamageVerb,Damage,TapAction,TapVerb, + RegenerateAction,DamageAction,Deal,EntersTapped,EntersWithCounter, + CounterType,Count,Enchant,Duration,GainAction,GainVerb,PumpAction, + AddManaAction,ManaSource,DrawAction,Draw,DiscardAction,Discard, + DestroyNoRegenAction,DestroyAction,ExileAction,CounterAction, + SelectOp,SelectCard,SelectCreature,SelectPermanent,SelectSpell, + RestrictedPermanent,RestrictedArtifact,RestrictedEnchantment, + RestrictedLand,RestrictedTribal,RestrictedSpell,ColorSpec, + SpellRestriction,RestrictedCard,CardRestriction, + RestrictedCreature,PermanentRestriction,CreatureRestriction, + LandRestriction,Color,Tribal,CreatureType,Creature,Artifact,Land, + Enchantment,Permanent,Card,Spell,NoRegen,PowerToughness, + SignedNumber,Number,Sign,SEP,EOC,SPACE,EOS,EOR,Rule_0, + SpellEffect_0,Effect_0,SingleEffect_0,SingleEffect_1, + SingleEffect_2,SingleEffect_3,ActivatedAbility_0, + ActivationCosts_0,TriggeredAbility_0,Keyword_0,Keyword_1, + Keyword_2,Keyword_3,Keyword_4,Keyword_5,Keyword_6,Keyword_7, + Keyword_8,Keyword_9,Keyword_10,Keyword_11,Keyword_12,Keyword_13, + Keyword_14,Keyword_15,Keyword_16,Keyword_17,Keyword_18,Keyword_19, + Keyword_20,Keyword_21,Keyword_22,ColorlessCost_0,ManaCost_0, + ManaCost_1,ManaCost_2,CastTrigger_0,CastTrigger_1, + EntersBattlefieldTrigger_0,DiesTrigger_0,DiesTrigger_1, + DealsDamageTrigger_0,DamageReceiver_0,DamageReceiver_1, + DamageReceiver_2,DamageReceiver_3,DamageReceiver_4, + DamageReceiver_5,DamageReceiver_6,ChangeStateAction_0, + PermanentState_0,PermanentState_1,SetPTAction_0,SetPTAction_1, + SacrificeAction_0,MillAction_0,DoesntUntapAction_0, + DoesntUntapAction_1,DoesntUntapAction_2,PutTokenAction_0, + PutTokenAction_1,CreatureTokenSpec_0,CreatureTokenSpec_1, + WithAbilitySpec_0,WithAbilitySpec_1,CreatureSpec_0, + ControlAction_0,ControlAction_1,ChangeCounterAction_0, + ChangeCounterAction_1,PayManaAction_0,ChangeLifeVerb_0, + ChangeLifeVerb_1,ChangeLifeVerb_2,SelectPlayer_0,SelectPlayer_1, + SelectPlayer_2,PutCardAction_0,PutCardAction_1,BounceVerb_0, + BounceVerb_1,PreventAction_0,PreventAction_1,PreventAction_2, + PreventAction_3,DamageRestriction_0,TapAction_0,DamageAction_0, + DamageAction_1,DamageAction_2,DamageAction_3,DamageAction_4, + Enchant_0,Duration_0,GainAction_0,ManaSource_0,ManaSource_1, + DiscardAction_0,DiscardAction_1,ExileAction_0,ExileAction_1, + CounterAction_0,SelectCard_0,SelectCard_1,SelectCard_2, + SelectCard_3,SelectCard_4,SelectCreature_0,SelectCreature_1, + SelectCreature_2,SelectCreature_3,SelectCreature_4, + SelectPermanent_0,SelectPermanent_1,SelectPermanent_2, + SelectPermanent_3,SelectSpell_0,SelectSpell_1,SelectSpell_2, + SelectSpell_3,RestrictedPermanent_0,RestrictedPermanent_1, + RestrictedPermanent_2,RestrictedArtifact_0,RestrictedLand_0, + RestrictedLand_1,RestrictedSpell_0,RestrictedSpell_1,ColorSpec_0, + ColorSpec_1,ColorSpec_2,SpellRestriction_0,SpellRestriction_1, + SpellRestriction_2,RestrictedCard_0,RestrictedCreature_0, + RestrictedCreature_1,RestrictedCreature_2,RestrictedCreature_3, + RestrictedCreature_4,PermanentRestriction_0, + PermanentRestriction_1,PermanentRestriction_2, + CreatureRestriction_0,CreatureRestriction_1,CreatureRestriction_2, + CreatureRestriction_3,CreatureRestriction_4,Tribal_0,Tribal_1, + Artifact_0,Artifact_1,Land_0,Land_1,Land_2,Land_3,Land_4,Number_0 + }; +} diff --git a/grammar/MagicSyntaxTree.java b/src/magic/grammar/MagicSyntaxTree.java similarity index 94% rename from grammar/MagicSyntaxTree.java rename to src/magic/grammar/MagicSyntaxTree.java index 7599e56c89..abfc3fea74 100644 --- a/grammar/MagicSyntaxTree.java +++ b/src/magic/grammar/MagicSyntaxTree.java @@ -1,4 +1,6 @@ -class MagicSyntaxTree extends mouse.runtime.SemanticsBase { +package magic.grammar; + +class MagicSyntaxTree extends magic.grammar.SemanticsBase { Node tree; boolean action() { final Node node = new Node(); diff --git a/grammar/Node.java b/src/magic/grammar/Node.java similarity index 91% rename from grammar/Node.java rename to src/magic/grammar/Node.java index f547cc8f34..85e75e2da6 100644 --- a/grammar/Node.java +++ b/src/magic/grammar/Node.java @@ -1,3 +1,5 @@ +package magic.grammar; + import java.util.List; import java.util.LinkedList; diff --git a/src/magic/grammar/ParserBase.java b/src/magic/grammar/ParserBase.java new file mode 100644 index 0000000000..971dacde94 --- /dev/null +++ b/src/magic/grammar/ParserBase.java @@ -0,0 +1,758 @@ +//========================================================================= +// +// Part of PEG parser generator Mouse. +// +// Copyright (C) 2009, 2010, 2011, 2012 +// by Roman R. Redziejowski (www.romanredz.se). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//------------------------------------------------------------------------- +// +// Change log +// 090720 Created for Mouse 1.1. +// Version 1.2 +// 100320 Bug fix in accept(): upgrade error info on success. +// 100320 Bug fix in rejectNot(): backtrack before registering failure. +// Version 1.3 +// 100429 Bug fix in errMerge(Phrase): assignment to errText replaced +// by clear + addAll (assignment produced alias resulting in +// explosion of errText in memo version). +// 101105 Changed errMerge(msg,pos) to errAdd(who). +// 101105 Commented error handling. +// 101129 Added 'boolReject'. +// 101203 Convert result of 'listErr' to printable. +// Version 1.4 +// 110918 Changed 'listErr' to separate 'not' texts as 'not expected'. +// 111004 Added methods to implement ^[s]. +// 111004 Implemented method 'where' of Phrase. +// Version 1.5 +// 111027 Revised methods for ^[s] and ^[c]. +// 111104 Implemented methods 'rule' and 'isTerm' of Phrase. +// Version 1.5.1 +// 120102 (Steve Owens) Ensure failure() method does not emit blank +// line when error info is absent. +// +//========================================================================= + +package magic.grammar; + +import magic.grammar.Source; +import java.util.Vector; + + +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +// +// ParserBase +// +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + + +public class ParserBase implements magic.grammar.CurrentRule +{ + //------------------------------------------------------------------- + // Input + //------------------------------------------------------------------- + Source source; // Source of text to parse + int endpos; // Position after the end of text + int pos; // Current position in the text + + //------------------------------------------------------------------- + // Semantics (base) + //------------------------------------------------------------------- + protected magic.grammar.SemanticsBase sem; + + //------------------------------------------------------------------- + // Trace string. + //------------------------------------------------------------------- + protected String trace = ""; + + //------------------------------------------------------------------- + // Current phrase (top of parse stack). + //------------------------------------------------------------------- + Phrase current = null; + + //------------------------------------------------------------------- + // Constructor + //------------------------------------------------------------------- + protected ParserBase() + {} + + //------------------------------------------------------------------- + // Initialize parsing + //------------------------------------------------------------------- + public void init(Source src) + { + source = src; + pos = 0; + endpos = source.end(); + current = new Phrase("","",0); // Dummy bottom of parse stack + } + + //------------------------------------------------------------------- + // Implementation of Parser interface CurrentRule + //------------------------------------------------------------------- + public Phrase lhs() + { return current; } + + public Phrase rhs(int i) + { return current.rhs.elementAt(i); } + + public int rhsSize() + { return current.rhs.size(); } + + public String rhsText(int i,int j) + { return source.at(rhs(i).start,rhs(j-1).end); } + + //------------------------------------------------------------------- + // Set trace + //------------------------------------------------------------------- + public void setTrace(String trace) + { + this.trace = trace; + sem.trace = trace; + } + + //------------------------------------------------------------------- + // Print final error message (if not caught otherwise). + //------------------------------------------------------------------- + protected boolean failure() + { + if (current.errPos>=0) + System.out.println(current.errMsg()); + return false; + } + + //===================================================================== + // + // Methods called from parsing procedures + // + //===================================================================== + //------------------------------------------------------------------- + // Initialize processing of a nonterminal + //------------------------------------------------------------------- + protected void begin(final String name) + { + Phrase p = new Phrase(name,name,pos); + p.parent = current; + current = p; + } + + protected void begin(final String name,final String diag) + { + Phrase p = new Phrase(name,diag,pos); + p.parent = current; + current = p; + } + + //------------------------------------------------------------------- + // Accept Rule + // Note: 'upgrade error info' is applied when rule such as + // R = A/B/C/... or R = (A/B/C/...)* consumed empty string after one + // or more of A,B,C failed without advancing cursor. + // In case of a later failure, it gives message 'expected R', + // which is not strictly correct because R succeeded, but is + // more comprehensible than 'expected A or B or C or ...'. + //------------------------------------------------------------------- + protected boolean accept() + { + Phrase p = pop(); // Pop p from compile stack + p.rhs = null; // Remove right-hand side of p + if (p.errPos==p.start) // Upgrade error info of p + p.errSet(p.diag,p.start); + p.success = true; // Indicate p successful + current.end = pos; // Update end of parent + current.rhs.add(p); // Attach p to rhs of parent + current.errMerge(p); // Merge error info with parent + return true; + } + + //------------------------------------------------------------------- + // Accept Inner + //------------------------------------------------------------------- + protected boolean acceptInner() + { + Phrase p = pop(); // Pop p from compile stack + p.success = true; // Indicate p successful + current.end = pos; // Update end of parent + current.rhs.addAll(p.rhs); // Add rhs of p to rhs of parent + current.errMerge(p); // Merge error info with parent + return true; + } + + //------------------------------------------------------------------- + // Accept And-predicate (argument was accepted) + // Note: we ignore all failures encountered in processing the argument. + //------------------------------------------------------------------- + protected boolean acceptAnd() + { + Phrase p = pop(); // Pop p from compile stack + p.end = p.start; // Reset end of P + p.rhs = null; // Remove right-hand side of p + p.errClear(); // Remove error info from p + p.success = true; // Indicate p successful + pos = p.start; // Backtrack to start of p + return true; + } + + //------------------------------------------------------------------- + // Accept Not-predicate (argument was rejected) + // Note: we ignore all failures encountered in processing the argument. + //------------------------------------------------------------------- + protected boolean acceptNot() + { + Phrase p = pop(); // Pop p from compile stack + p.rhs = null; // Remove right-hand side of p + p.errClear(); // Remove error info from p + p.success = true; // Indicate p successful + return true; + } + + + + //------------------------------------------------------------------- + // Reject Rule + // Note: 'upgrade error info' is applied when rule such as + // R = A/B/C/... failed after one or more of A,B,C failed without + // advancing cursor. In case of a later failure, it gives message + // 'expected R', instead of 'expected A or B or C or ...'. + //------------------------------------------------------------------- + protected boolean reject() + { + Phrase p = pop(); // Pop p from compile stack + p.end = p.start; // Reset end of p + p.rhs = null; // Remove right-hand side of p + if (p.errPos==p.start) // Upgrade error info of p + p.errSet(p.diag,p.start); + p.success = false; // Indicate p failed + current.errMerge(p); // Merge error info with parent + pos = p.start; // Backtrack to start of p + return false; + } + + //------------------------------------------------------------------- + // Simulate failure after boolean action returned false. + // Note: the action was called after the Rule accepted some text. + // We ignore all failures encountered in the process + // and report failure at the start of the text. + //------------------------------------------------------------------- + protected boolean boolReject() + { + pos = current.start; // Backtrack to start + current.end = pos; // Reset end + current.rhs.clear(); // Clear right-hand side + current.errSet(current.diag,pos);// Register failure + return false; + } + + //------------------------------------------------------------------- + // Reject Inner + //------------------------------------------------------------------- + protected boolean rejectInner() + { + Phrase p = pop(); // Pop p from compile stack + p.end = p.start; // Reset end of p + p.rhs = null; // Remove right-hand side of p + p.success = false; // Indicate p failed + current.errMerge(p); // Merge error info with parent + pos = p.start; // Backtrack to start of p + return false; + } + + //------------------------------------------------------------------- + // Reject And-predicate (argument was rejected) + // Note: we ignore all failures encountered in processing the argument, + // and register failure at the point of call of the predicate. + //------------------------------------------------------------------- + protected boolean rejectAnd() + { + Phrase p = pop(); // Pop p from compile stack + p.rhs = null; // Remove right-hand side of p + p.errSet(p.diag,pos); // Register 'xxx expected' + p.success = false; // Indicate p failed + current.errMerge(p); // Merge error info with parent + return false; + } + + //------------------------------------------------------------------- + // Reject Not-predicate (argument was accepted) + // Note: we ignore all failures encountered in processing the argument, + // and register failure at the point of call of the predicate. + //------------------------------------------------------------------- + protected boolean rejectNot() + { + Phrase p = pop(); // Pop p from compile stack + p.end = p.start; // Reset end of p + p.rhs = null; // Remove right-hand side of p + pos = p.start; // Backtrack to start of p + p.errSet(p.diag,pos); // Register 'xxx not expected' + p.success = false; // Indicate p failed + current.errMerge(p); // Merge error info with parent + return false; + } + + + //------------------------------------------------------------------- + // Execute expression 'c' + //------------------------------------------------------------------- + protected boolean next(char ch) + { + if (pos=0) return consume(1); + else return fail("[" + s + "]"); + } + + //------------------------------------------------------------------- + // Execute expression ^[s] + //------------------------------------------------------------------- + protected boolean nextNotIn(String s) + { + if (pos=0) return true; + else return fail("[" + s + "]"); + } + + protected boolean aheadNotNotIn(String s) // temporary + { return aheadIn(s); } + + //------------------------------------------------------------------- + // Execute expression ![s], &^[s] + //------------------------------------------------------------------- + protected boolean aheadNotIn(String s) + { + if (pos=0) return fail("not [" + s + "]"); + else return true; + } + + + //------------------------------------------------------------------- + // Execute expression [a-z] + //------------------------------------------------------------------- + protected boolean nextIn(char a, char z) + { + if (pos=a && source.at(pos)<=z) + return consume(1); + else return fail("[" + a + "-" + z + "]"); + } + + //------------------------------------------------------------------- + // Execute expression &[a-z] + //------------------------------------------------------------------- + protected boolean aheadIn(char a, char z) + { + if (pos=a && source.at(pos)<=z) + return true; + else return fail("[" + a + "-" + z + "]"); + } + + //------------------------------------------------------------------- + // Execute expression ![a-z] + //------------------------------------------------------------------- + protected boolean aheadNotIn(char a, char z) + { + if (pos=a && source.at(pos)<=z) + return fail("not [" + a + "-" + z + "]"); + else return true; + } + + + //------------------------------------------------------------------- + // Execute expression _ + //------------------------------------------------------------------- + protected boolean next() + { + if (pos rhs = new Vector(10,10); + Object value = null; + Phrase parent = null; + + //----------------------------------------------------------------- + // Errors encountered in processing of this Phrase. + // We keep information about the failure farthest down in text, + // and only failure of a rule or a terminal (inner expressions + // do not have diagnostic names. + // - 'errPos' is position the failure, or -1 if there was none. + // - 'errTxt' identifies the expression(s) that failed at 'errPos'. + // There may be several such expressions if 'errPos' was reached + // on several attempts. The expressions are identified + // by their diagnostic names. + //----------------------------------------------------------------- + int errPos = -1; + Vector errTxt = new Vector(); + + + //=================================================================== + // + // Constructor + // + //=================================================================== + + Phrase(final String name,final String diag,int start) + { + this.name = name; + this.diag = diag; + this.start = start; + this.end = start; + } + + //=================================================================== + // + // Interface 'magic.grammar.Phrase' + // + //=================================================================== + //----------------------------------------------------------------- + // Set value + //----------------------------------------------------------------- + public void put(Object o) + { value = o; } + + //----------------------------------------------------------------- + // Get value + //----------------------------------------------------------------- + public Object get() + { return value; } + + //----------------------------------------------------------------- + // Get text + //----------------------------------------------------------------- + public String text() + { return source.at(start,end); } + + //------------------------------------------------------------------- + // Get i-th character of text + //------------------------------------------------------------------- + public char charAt(int i) + { return source.at(start+i); } + + //----------------------------------------------------------------- + // Is text empty? + //----------------------------------------------------------------- + public boolean isEmpty() + { return start==end; } + + //------------------------------------------------------------------- + // Get name of rule that created this Phrase. + //------------------------------------------------------------------- + public String rule() + { return name; } + + //------------------------------------------------------------------- + // Was this Phrase created by rule 'rule'? + //------------------------------------------------------------------- + public boolean isA(String rule) + { return name.equals(rule); } + + //------------------------------------------------------------------- + // Was this Phrase created by a terminal? + //------------------------------------------------------------------- + public boolean isTerm() + { return name.isEmpty(); } + + //----------------------------------------------------------------- + // Get error message + //----------------------------------------------------------------- + public String errMsg() + { + if (errPos<0) return ""; + return source.where(errPos) + ":" + listErr(); + } + + //----------------------------------------------------------------- + // Clear error information + //----------------------------------------------------------------- + public void errClear() + { + errTxt.clear(); + errPos = -1; + } + + //----------------------------------------------------------------- + // Describe position of i-th character of the Phrase in source text. + //----------------------------------------------------------------- + public String where(int i) + { return source.where(start+i); } + + + //=================================================================== + // + // Operations on error info + // + //=================================================================== + + //----------------------------------------------------------------- + // Set fresh info ('who' failed 'where'), discarding any previous. + //----------------------------------------------------------------- + void errSet(final String who, int where) + { + errTxt.clear(); + errTxt.add(who); + errPos = where; + } + + //----------------------------------------------------------------- + // Add info about 'who' failing at current position. + //----------------------------------------------------------------- + void errAdd(final String who) + { + if (errPos>pos) return; // If current position older: forget + if (errPosp.errPos) return; // If error in p older: forget + if (errPos done = new Vector(); + for (String s: errTxt) + { + if (done.contains(s)) continue; + done.add(s); + if (s.startsWith("not ")) + toPrint(" or " + s.substring(4),two); + else + toPrint(" or " + s,one); + } + + if (one.length()>0) + { + if (two.length()==0) + return " expected " + one.toString().substring(4); + else + return " expected " + one.toString().substring(4) + + "; not expected " + two.toString().substring(4); + } + else + return " not expected " + two.toString().substring(4); + } + + //----------------------------------------------------------------- + // Convert string to printable and append to StringBuilder. + //----------------------------------------------------------------- + private void toPrint(final String s, StringBuilder sb) + { + for (int i=0;i256) + { + String u = "000" + Integer.toHexString(c); + sb.append("\\u" + u.substring(u.length()-4,u.length())); + } + else sb.append(c); + continue; + } + } + } + } + +} + + + diff --git a/src/magic/grammar/ParserMemo.java b/src/magic/grammar/ParserMemo.java new file mode 100644 index 0000000000..a5977384a2 --- /dev/null +++ b/src/magic/grammar/ParserMemo.java @@ -0,0 +1,224 @@ +//========================================================================= +// +// Part of PEG parser generator Mouse. +// +// Copyright (C) 2009, 2010 +// by Roman R. Redziejowski (www.romanredz.se). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//------------------------------------------------------------------------- +// +// Change log +// 090721 Created for Mouse 1.1. +// Version 1.3 +// 100504 Added c.diag to arguments of begin in saved and savedInner. +// 100504 In Cache(String) set diag to name instead of null. +// +//========================================================================= + +package magic.grammar; + +import magic.grammar.Source; + + +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +// +// ParserMemo +// +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + + +public class ParserMemo extends ParserBase +{ + //------------------------------------------------------------------- + // Cache size. + //------------------------------------------------------------------- + int cacheSize = 1; + + //------------------------------------------------------------------- + // Phrase to reuse. + //------------------------------------------------------------------- + Phrase reuse; + + //------------------------------------------------------------------- + // List of Cache objects for initialization. + //------------------------------------------------------------------- + protected Cache[] caches; + + //------------------------------------------------------------------- + // Constructor + //------------------------------------------------------------------- + protected ParserMemo() + {} + + //------------------------------------------------------------------- + // Initialize + //------------------------------------------------------------------- + public void init(Source src) + { + super.init(src); + for (Cache c: caches) // Reset Cache objects + c.reset(); + } + + //------------------------------------------------------------------- + // Set cache size. + //------------------------------------------------------------------- + public void setMemo(int m) + { + if (m<1 | m>9) throw new Error("m=" + m + " outside range 1-9"); + cacheSize = m; + } + + + //===================================================================== + // + // Methods called from parsing procedures + // + //===================================================================== + //------------------------------------------------------------------- + // If saved result found, use it, otherwise begin new procedure. + // Version for Rule. + //------------------------------------------------------------------- + protected boolean saved(Cache c) + { + reuse = c.find(); + if (reuse!=null) // If found Phrase to reuse.. + return true; // .. return + + begin(c.name,c.diag); // Otherwise push new Phrase + c.save(current); // .. and cache it + return false; + } + + //------------------------------------------------------------------- + // If saved result found, use it, otherwise begin new procedure. + // Version for Inner. + //------------------------------------------------------------------- + protected boolean savedInner(Cache c) + { + reuse = c.find(); + if (reuse!=null) // If found Phrase to reuse.. + return true; // .. return + + begin("",c.diag); // Otherwise push new Phrase + c.save(current); // .. and cache it + return false; + } + + //------------------------------------------------------------------- + // Reuse Rule + //------------------------------------------------------------------- + protected boolean reuse() + { + if (reuse.success) + { + pos = reuse.end; // Update position + current.end = pos; // Update end of current + current.rhs.add(reuse); // Attach p to rhs of current + current.errMerge(reuse); // Merge error info with current + return true; + } + else + { + current.errMerge(reuse); // Merge error info with current + return false; + } + } + + //------------------------------------------------------------------- + // Reuse Inner + //------------------------------------------------------------------- + protected boolean reuseInner() + { + if (reuse.success) + { + pos = reuse.end; // Update position + current.end = pos; // Update end of current + current.rhs.addAll(reuse.rhs); // Add rhs to rhs of current + current.errMerge(reuse); // Merge error info with current + return true; + } + else + { + current.errMerge(reuse); // Merge error info with current + return false; + } + } + + //------------------------------------------------------------------- + // Reuse predicate + //------------------------------------------------------------------- + protected boolean reusePred() + { + if (reuse.success) + return true; + else + { + current.errMerge(reuse); // Merge error info with current + return false; + } + } + + + //HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + // + // Cache + // + //HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + + protected class Cache + { + public final String name; + public final String diag; + + Phrase[] cache; + int last; + + public Cache(final String name) + { + this.name = name; + this.diag = name; + } + + public Cache(final String name, final String diag) + { + this.name = name; + this.diag = diag; + } + + void reset() + { + cache = new Phrase[cacheSize]; + last = 0; + } + + void save(Phrase p) + { + last = (last+1)%cacheSize; + cache[last] = p; + } + + Phrase find() + { + for (Phrase p: cache) + if (p!=null && p.start==pos) return p; + return null; + } + } + +} + + + diff --git a/src/magic/grammar/ParserTest.java b/src/magic/grammar/ParserTest.java new file mode 100644 index 0000000000..83d31a70b3 --- /dev/null +++ b/src/magic/grammar/ParserTest.java @@ -0,0 +1,526 @@ +//========================================================================= +// +// Part of PEG parser generator Mouse. +// +// Copyright (C) 2009, 2010, 2011 +// by Roman R. Redziejowski (www.romanredz.se). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//------------------------------------------------------------------------- +// +// Change log +// 090721 Created for Mouse 1.1. +// Version 1.3 +// 100429 In error trace added name of the Phrase owning error info. +// 100504 Added c.diag to arguments of begin in saved and savedInner. +// 100504 In error trace changed current.name to current.diag. +// 101127 Renamed 'startpos' to 'endpos' in tracing. +// Version 1.4 +// 111004 Added methods to implement ^[s]. +// Version 1.5 +// 111105 Revised methods for ^[s] and ^[c]. +// +//========================================================================= + +package magic.grammar; + +import java.util.BitSet; + + +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +// +// ParserTest +// +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + +public class ParserTest extends ParserMemo +{ + //------------------------------------------------------------------- + // Cache size. + //------------------------------------------------------------------- + int cacheSize = 1; + + //------------------------------------------------------------------- + // Trace switches. + //------------------------------------------------------------------- + public boolean traceRules; // Trace Rules + public boolean traceInner; // Trace subexpressions + public boolean traceError; // Trace error info + + //------------------------------------------------------------------- + // Constructor + //------------------------------------------------------------------- + protected ParserTest() + {} + + //------------------------------------------------------------------- + // Set cache size. + //------------------------------------------------------------------- + public void setMemo(int m) + { + if (m<0 | m>9) throw new Error("m=" + m + " outside range 0-9"); + cacheSize = m; + } + + //------------------------------------------------------------------- + // Set trace + //------------------------------------------------------------------- + public void setTrace(String trace) + { + super.setTrace(trace); + traceRules = trace.indexOf('r')>=0; + traceInner = trace.indexOf('i')>=0; + traceError = trace.indexOf('e')>=0; + } + + //------------------------------------------------------------------- + // Access to cache list + //------------------------------------------------------------------- + public Cache[] caches() + { return (Cache[])caches; } + + //------------------------------------------------------------------- + // Write trace + //------------------------------------------------------------------- + void trace(final String s) + { System.out.println(s); } + + + //===================================================================== + // + // Methods called from parsing procedures + // + //===================================================================== + //------------------------------------------------------------------- + // If saved result found, use it, otherwise begin new procedure. + // Version for Rule. + //------------------------------------------------------------------- + protected boolean saved(Cache c) + { + c.calls++; + if (traceRules) trace(source.where(pos) + ": INIT " + c.name); + reuse = c.find(); + if (reuse!=null) + { + c.reuse++; + if (traceRules) trace("REUSE " + (reuse.success? "succ " : "fail ")); + return true; + } + + begin(c.name,c.diag); + c.save(current); + if (c.prevpos.get(pos)) c.rescan++; + else c.prevpos.set(pos); + return false; + } + + //------------------------------------------------------------------- + // If saved result found, use it, otherwise begin new procedure. + // Version for Inner. + //------------------------------------------------------------------- + protected boolean savedInner(Cache c) + { + c.calls++; + if (traceInner) trace(source.where(pos) + ": INIT " + c.name); + reuse = c.find(); + if (reuse!=null) + { + c.reuse++; + if (traceInner) trace("REUSE " + (reuse.success? "succ " : "fail ")); + return true; + } + + begin("",c.diag); + c.save(current); + if (c.prevpos.get(pos)) c.rescan++; + else c.prevpos.set(pos); + return false; + } + + + //------------------------------------------------------------------- + // Accept Rule + //------------------------------------------------------------------- + protected boolean accept(Cache c) + { + super.accept(); + traceAccept(c,traceRules); + return true; + } + + //------------------------------------------------------------------- + // Accept Inner + //------------------------------------------------------------------- + protected boolean acceptInner(Cache c) + { + super.acceptInner(); + traceAccept(c,traceInner); + return true; + } + + //------------------------------------------------------------------- + // Accept And-predicate (argument was accepted) + //------------------------------------------------------------------- + protected boolean acceptAnd(Cache c) + { + super.acceptAnd(); + traceAccept(c,traceInner); + return true; + } + + //------------------------------------------------------------------- + // Accept Not-predicate (argument was rejected) + //------------------------------------------------------------------- + protected boolean acceptNot(Cache c) + { + super.acceptNot(); + traceAccept(c,traceInner); + return true; + } + + //------------------------------------------------------------------- + // Trace accept + //------------------------------------------------------------------- + private void traceAccept(Cache c, boolean cond) + { + if (cond) + { + trace(source.where(pos) + ": ACCEPT " + c.name); + if (traceError) trace(current.diag + " --" + current.errMsg()); + } + c.succ++; + } + + + //------------------------------------------------------------------- + // Reject Rule + //------------------------------------------------------------------- + protected boolean reject(Cache c) + { + int endpos = pos; + super.reject(); + traceReject(c,traceRules,endpos); + return false; + } + + //------------------------------------------------------------------- + // Reject Inner + //------------------------------------------------------------------- + protected boolean rejectInner(Cache c) + { + int endpos = pos; + super.rejectInner(); + traceReject(c,traceInner,endpos); + return false; + } + + //------------------------------------------------------------------- + // Reject And-predicate (argument was rejected) + //------------------------------------------------------------------- + protected boolean rejectAnd(Cache c) + { + int endpos = pos; + super.rejectAnd(); + traceReject(c,traceInner,endpos); + return false; + } + + //------------------------------------------------------------------- + // Reject Not-predicate (argument was accepted) + //------------------------------------------------------------------- + protected boolean rejectNot(Cache c) + { + int endpos = pos; + super.rejectNot(); + traceReject(c,traceInner,endpos); + return false; + } + + //------------------------------------------------------------------- + // Trace reject + //------------------------------------------------------------------- + private void traceReject(Cache c, boolean cond, int endpos) + { + if (cond) + { + trace(source.where(endpos) + ": REJECT " + c.name); + if (traceError) trace(current.diag + " --" + current.errMsg()); + } + if (pos==endpos) c.fail++; // No backtrack + else // Backtrack + { + int b = endpos-pos; + c.back++; + c.totback += b; + if (b>c.maxback) + { + c.maxback = b; + c.maxbpos = pos; + } + } + } + + + //------------------------------------------------------------------- + // Execute expression 'c' + //------------------------------------------------------------------- + protected boolean next(char ch,Cache c) + { + int endpos = pos; + boolean succ = super.next(ch); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression ^'c' + //------------------------------------------------------------------- + protected boolean nextNot(char ch,Cache c) + { + int endpos = pos; + boolean succ = super.nextNot(ch); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression &'c', !^'c' + //------------------------------------------------------------------- + protected boolean ahead(char ch,Cache c) + { + int endpos = pos; + boolean succ = super.ahead(ch); + return traceTerm(endpos,succ,c); + } + + protected boolean aheadNotNot(char ch,Cache c) + { return ahead(ch,c); } + + //------------------------------------------------------------------- + // Execute expression !'c', &^'c' + //------------------------------------------------------------------- + protected boolean aheadNot(char ch,Cache c) + { + int endpos = pos; + boolean succ = super.aheadNot(ch); + return traceTerm(endpos,succ,c); + } + + + //------------------------------------------------------------------- + // Execute expression "s" + //------------------------------------------------------------------- + protected boolean next(String s,Cache c) + { + int endpos = pos; + boolean succ = super.next(s); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression &"s" + //------------------------------------------------------------------- + protected boolean ahead(String s,Cache c) + { + int endpos = pos; + boolean succ = super.ahead(s); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression !"s" + //------------------------------------------------------------------- + protected boolean aheadNot(String s,Cache c) + { + int endpos = pos; + boolean succ = super.aheadNot(s); + return traceTerm(endpos,succ,c); + } + + + //------------------------------------------------------------------- + // Execute expression [s] + //------------------------------------------------------------------- + protected boolean nextIn(String s,Cache c) + { + int endpos = pos; + boolean succ = super.nextIn(s); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression ^[s] + //------------------------------------------------------------------- + protected boolean nextNotIn(String s,Cache c) + { + int endpos = pos; + boolean succ = super.nextNotIn(s); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression &[s], !^[s] + //------------------------------------------------------------------- + protected boolean aheadIn(String s,Cache c) + { + int endpos = pos; + boolean succ = super.aheadIn(s); + return traceTerm(endpos,succ,c); + } + + protected boolean aheadNotNotIn(String s,Cache c) + { return aheadIn(s,c); } + + //------------------------------------------------------------------- + // Execute expression ![s], &^[s] + //------------------------------------------------------------------- + protected boolean aheadNotIn(String s,Cache c) + { + int endpos = pos; + boolean succ = super.aheadNotIn(s); + return traceTerm(endpos,succ,c); + } + + + //------------------------------------------------------------------- + // Execute expression [a-z] + //------------------------------------------------------------------- + protected boolean nextIn(char a, char z, Cache c) + { + int endpos = pos; + boolean succ = super.nextIn(a,z); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression &[a-z] + //------------------------------------------------------------------- + protected boolean aheadIn(char a, char z, Cache c) + { + int endpos = pos; + boolean succ = super.aheadIn(a,z); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression ![a-z] + //------------------------------------------------------------------- + protected boolean aheadNotIn(char a, char z, Cache c) + { + int endpos = pos; + boolean succ = super.aheadNotIn(a,z); + return traceTerm(endpos,succ,c); + } + + + //------------------------------------------------------------------- + // Execute expression _ + //------------------------------------------------------------------- + protected boolean next(Cache c) + { + int endpos = pos; + boolean succ = super.next(); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression &_ + //------------------------------------------------------------------- + protected boolean ahead(Cache c) + { + int endpos = pos; + boolean succ = super.ahead(); + return traceTerm(endpos,succ,c); + } + + //------------------------------------------------------------------- + // Execute expression !_ + //------------------------------------------------------------------- + protected boolean aheadNot(Cache c) + { + int endpos = pos; + boolean succ = super.aheadNot(); + return traceTerm(endpos,succ,c); + } + + + //------------------------------------------------------------------- + // Trace term + //------------------------------------------------------------------- + private boolean traceTerm(int endpos, boolean succ, Cache c) + { + c.calls++; + if (c.prevpos.get(endpos)) c.rescan++; + else c.prevpos.set(endpos); + if (succ) { c.succ++; return true; } + else { c.fail++; return false; } + } + + + + //HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + // + // Cache object + // + //HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + + public class Cache extends ParserMemo.Cache + { + public int calls ; // Total number of calls + public int rescan ; // How many were rescans without reuse + public int reuse ; // How many were rescans with reuse + public int succ ; // How many resulted in success + public int fail ; // How many resulted in failure, no backtrack + public int back ; // How many resulted in backtrack + public int totback; // Accumulated amount of backtrack + public int maxback; // Maximum length of backtrack + public int maxbpos; // Position of naximal backtrack + BitSet prevpos ; // Scan history + + + public Cache(final String name) + { super(name); } + + public Cache(final String name,final String diag) + { super(name,diag); } + + void save(Phrase p) + { + if (cacheSize==0) return; + super.save(p); + } + + Phrase find() + { + if (cacheSize==0) return null; + return super.find(); + } + + void reset() + { + super.reset(); + calls = 0; + rescan = 0; + reuse = 0; + succ = 0; + fail = 0; + back = 0; + totback = 0; + maxback = 0; + maxbpos = 0; + prevpos = new BitSet(60000); + } + } +} + + + diff --git a/src/magic/grammar/Phrase.java b/src/magic/grammar/Phrase.java new file mode 100644 index 0000000000..4a4710344f --- /dev/null +++ b/src/magic/grammar/Phrase.java @@ -0,0 +1,97 @@ +//========================================================================= +// +// Part of PEG parser generator Mouse. +// +// Copyright (C) 2009, 2011 by Roman R. Redziejowski (www.romanredz.se). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//------------------------------------------------------------------------- +// +// Change log +// 090701 License changed by the author to Apache v.2. +// 090717 Removed unused import of java.util.Vector. +// Version 1.4 +// 111004 Added method 'where'. +// Version 1.5 +// 111104 Added methods 'rule' and 'isTerm'. +// +//========================================================================= + +package magic.grammar; + + +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +// +// Phrase seen from Semantics +// +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + +public interface Phrase +{ + //------------------------------------------------------------------- + // Set value + //------------------------------------------------------------------- + void put(Object o); + + //------------------------------------------------------------------- + // Get value + //------------------------------------------------------------------- + Object get(); + + //------------------------------------------------------------------- + // Get text + //------------------------------------------------------------------- + String text(); + + //------------------------------------------------------------------- + // Get i-th character of text + //------------------------------------------------------------------- + char charAt(int i); + + //------------------------------------------------------------------- + // Is text empty? + //------------------------------------------------------------------- + boolean isEmpty(); + + //------------------------------------------------------------------- + // Get name of rule that created this Phrase. + //------------------------------------------------------------------- + String rule(); + + //------------------------------------------------------------------- + // Was this Phrase created by rule 'name'? + //------------------------------------------------------------------- + boolean isA(String name); + + //------------------------------------------------------------------- + // Was this Phrase created by a terminal? + //------------------------------------------------------------------- + boolean isTerm(); + + //------------------------------------------------------------------- + // Get error message + //------------------------------------------------------------------- + String errMsg(); + + //------------------------------------------------------------------- + // Clear error message + //------------------------------------------------------------------- + void errClear(); + + //------------------------------------------------------------------- + // Describe position of i-th character of the Phrase in source text. + //------------------------------------------------------------------- + String where(int i); + +} diff --git a/src/magic/grammar/SemanticsBase.java b/src/magic/grammar/SemanticsBase.java new file mode 100644 index 0000000000..203a3f0938 --- /dev/null +++ b/src/magic/grammar/SemanticsBase.java @@ -0,0 +1,106 @@ +//========================================================================= +// +// Part of PEG parser generator Mouse. +// +// Copyright (C) 2009 by Roman R. Redziejowski (www.romanredz.se). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//------------------------------------------------------------------------- +// +// Change log +// 090701 License changed by the author to Apache v.2. +// 090717 Interface 'Parser' renamed to 'CurrentRule'. +// 090810 Name changed from 'Semantics'. +// +//========================================================================= + +package magic.grammar; + + + +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +// +// SemanticsBase +// +//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + +public class SemanticsBase +{ + //===================================================================== + // + // Fields set by the Parser. + // + //===================================================================== + //------------------------------------------------------------------- + // Reference to current rule in the Parser. + // Set when Parser instantiates Semantics. + //------------------------------------------------------------------- + public CurrentRule rule; + + //------------------------------------------------------------------- + // String that you can use to trigger trace. + // Set by applying method 'setTrace' to the Parser. + //------------------------------------------------------------------- + public String trace = ""; + + + //===================================================================== + // + // Initialization. + // + //===================================================================== + //------------------------------------------------------------------- + // Invoked at the beginning of each invocation of the Parser. + // You can override it to perform your own initialization. + //------------------------------------------------------------------- + public void init() + {} + + + //===================================================================== + // + // Methods to be invoked from semantic actions. + // They call back the parser to obtain details of the environment + // in which the action was invoked. + // + //===================================================================== + //------------------------------------------------------------------- + // Returns the left-hand side Phrase object. + //------------------------------------------------------------------- + protected Phrase lhs() + { return rule.lhs(); } + + //------------------------------------------------------------------- + // Returns the number of Phrase objects on the right-hand side. + //------------------------------------------------------------------- + protected int rhsSize() + { return rule.rhsSize(); } + + //------------------------------------------------------------------- + // Returns the i-th right-hand side object, 0<=i15) + return "After '... " + text.substring(p-15,p) + "'"; + else if (p>0) + return "After '" + text.substring(0,p) + "'"; + else + return "At start"; + } +}