Index: trunk/extensions/ParserWiki/ParseEngine.php |
— | — | @@ -0,0 +1,233 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Acts as the primary interface between the world and the parser. |
| 5 | + * mStartRule - the first rule to use while parsing |
| 6 | + * mRules - The list of rules to use while parsing |
| 7 | + * mDom - Used to create Dom objects and get's returned at the end of parsing |
| 8 | + * mIter - Keeps track of how many times the parser recurses to stop endless loops |
| 9 | + */ |
| 10 | +class ParseEngine { |
| 11 | + const maxIter = 4096; |
| 12 | + private $mGrammar; |
| 13 | + |
| 14 | + function __construct($grammar) { |
| 15 | + $xpath = new DOMXPath($grammar); |
| 16 | + $rootRules = $xpath->query("/grammar/parseObject | /grammar/rule/parseObject"); |
| 17 | + foreach ($rootRules as $child) { |
| 18 | + $this->pushTags($child, NULL); |
| 19 | + } |
| 20 | + $this->mGrammar = $grammar; |
| 21 | + } |
| 22 | + |
| 23 | + function parse($text) { |
| 24 | + wfDebugLog("ParseEngine", "==========Start Parse Engine==========\n"); |
| 25 | + $xpath = new DOMXPath($this->mGrammar); |
| 26 | + $rootAssign = $xpath->query("/grammar/parseObject")->item(0); |
| 27 | + $doc = new DOMDocument(); |
| 28 | + if (! $this->parseRec($rootAssign, "", "", $iter, $text, $doc)) { |
| 29 | + $doc = NULL; |
| 30 | + } |
| 31 | + return $doc; |
| 32 | + } |
| 33 | + |
| 34 | + static function unparse($inNodes) { |
| 35 | + $retStr = ""; |
| 36 | + foreach ($inNodes as $child) { |
| 37 | + if ($child instanceof DOMText) { |
| 38 | + $retStr .= $child->data; |
| 39 | + } else { |
| 40 | + $retStr .= $child->getAttribute("tag") . self::unparse($child->childNodes); |
| 41 | + } |
| 42 | + } |
| 43 | + return $retStr; |
| 44 | + } |
| 45 | + |
| 46 | + private function parseRec($rule, $replaceStr, $saveTags, &$iter, &$text, &$outNode) { |
| 47 | + $iter ++; |
| 48 | + if ($iter > ParseEngine::maxIter) { |
| 49 | + throw new MWException("Parser iterated too many times. Probable loop in grammar."); |
| 50 | + } |
| 51 | + $rule = $rule->firstChild; |
| 52 | + if ($rule->nodeName == "assignment" || $rule->nodeName == "reference" || $rule->nodeName == "text") { |
| 53 | + $saveTags = str_replace("~r", preg_quote($replaceStr, "/"), $saveTags); |
| 54 | + $newTags = $rule->getAttribute("saveTags"); |
| 55 | + if ($saveTags == "") { |
| 56 | + $saveTags = $newTags; |
| 57 | + } elseif ($newTags != "") { |
| 58 | + $saveTags .= "|" . $newTags; |
| 59 | + } |
| 60 | + } |
| 61 | + $dom = $outNode->ownerDocument == NULL ? $outNode : $outNode->ownerDocument; |
| 62 | + $xpath = new DOMXPath($rule->ownerDocument); |
| 63 | + $childRules = $xpath->query("parseObject", $rule); |
| 64 | + $retCode = TRUE; |
| 65 | + if ($rule->nodeName == "assignment") { |
| 66 | + $patterns = $xpath->query("pattern", $rule); |
| 67 | + $tag = ""; |
| 68 | + if ($patterns->length > 0) { |
| 69 | + $pattern = str_replace("~r", $replaceStr, $patterns->item(0)->getAttribute("tag")); |
| 70 | + $retCode = preg_match("/^$pattern/s", $text, $matches); |
| 71 | + if ($retCode) { |
| 72 | + $tag = $matches[0]; |
| 73 | + if (isset($matches[1])) { |
| 74 | + $replaceStr = $matches[1]; |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + if ($retCode) { |
| 79 | + $newText = $text; |
| 80 | + $newElement = $dom->createElement($rule->getAttribute("tag")); |
| 81 | + if ($tag != "") { |
| 82 | + $newText = substr($newText, strlen($tag)); |
| 83 | + $newElement->setAttribute("tag", $tag); |
| 84 | + } |
| 85 | + $retCode = $childRules->length <= 0 || $this->parseRec($childRules->item(0), $replaceStr, $saveTags, $iter, $newText, $newElement); |
| 86 | + if ($retCode) { |
| 87 | + $outNode->appendChild($newElement); |
| 88 | + $text = $newText; |
| 89 | + } |
| 90 | + } |
| 91 | + } elseif ($rule->nodeName == "sequence") { |
| 92 | + $pushInd = $rule->getAttribute("pushInd"); |
| 93 | + if ($pushInd > 0) { |
| 94 | + $saveText = $text; |
| 95 | + $saveNode = $outNode->cloneNode(TRUE); |
| 96 | + } |
| 97 | + foreach ($childRules as $i => $child) { |
| 98 | + $pushTags = $i >= $pushInd ? $saveTags : ""; |
| 99 | + $retCode = $this->parseRec($child, $replaceStr, $pushTags, $iter, $text, $outNode); |
| 100 | + if (! $retCode) { |
| 101 | + if ($i > 0) { |
| 102 | + $text = $saveText; |
| 103 | + $outNode = $saveNode; |
| 104 | + } |
| 105 | + break; |
| 106 | + } |
| 107 | + } |
| 108 | + } elseif ($rule->nodeName == "choice") { |
| 109 | + foreach ($childRules as $child) { |
| 110 | + $retCode = $this->parseRec($child, $replaceStr, $saveTags, $iter, $text, $outNode); |
| 111 | + if ($retCode) { |
| 112 | + break; |
| 113 | + } |
| 114 | + } |
| 115 | + $retCode |= $rule->hasAttribute("tag"); |
| 116 | + } elseif ($rule->nodeName == "reference") { |
| 117 | + $childRule = $rule->getAttribute("tag"); |
| 118 | + wfDebugLog("ParseEngine", "Entering $childRule\n"); |
| 119 | + $varNode = $xpath->query("pattern", $rule); |
| 120 | + if ($varNode->length > 0) { |
| 121 | + $replaceStr = str_replace("~r", $replaceStr, $varNode->item(0)->getAttribute("tag")); |
| 122 | + } |
| 123 | + $refRule = $xpath->query("/grammar/rule[@tag='$childRule']/parseObject")->item(0); |
| 124 | + $retCode = $this->parseRec($refRule, $replaceStr, $saveTags, $iter, $text, $outNode); |
| 125 | + wfDebugLog("ParseEngine", "Exiting $childRule, Return Code - $retCode\n"); |
| 126 | + wfDebugLog("ParseEngine", "text - $text\n"); |
| 127 | + } elseif ($rule->nodeName == "text") { |
| 128 | + $tagSearch = $rule->getAttribute("childTags"); |
| 129 | + if ($tagSearch == "") { |
| 130 | + $tagSearch = $saveTags; |
| 131 | + } elseif ($saveTags != "") { |
| 132 | + $tagSearch .= "|" . $saveTags; |
| 133 | + } |
| 134 | + $childNode = $childRules->length <= 0 ? NULL : $childRules->item(0); |
| 135 | + while ($text != "" && ($saveTags == "" || ! preg_match("/^($saveTags)/s", $text))) { |
| 136 | + $offset = $childNode != NULL && $this->parseRec($childNode, $replaceStr, "", $iter, $text, $outNode) ? 0 : 1; |
| 137 | + if (preg_match("/$tagSearch/s", $text, $matches, PREG_OFFSET_CAPTURE, $offset)) { |
| 138 | + if ($matches[0][1] > 0) { |
| 139 | + $outNode->appendChild($dom->createTextNode(substr($text, 0, $matches[0][1]))); |
| 140 | + $text = substr($text, $matches[0][1]); |
| 141 | + } |
| 142 | + } else { |
| 143 | + $outNode->appendChild($dom->createTextNode($text)); |
| 144 | + $text = ""; |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | + return $retCode; |
| 149 | + } |
| 150 | + |
| 151 | + private function pushTags($rule, $tagStr) { |
| 152 | + $rule = $rule->firstChild; |
| 153 | + $xpath = new DOMXPath($rule->ownerDocument); |
| 154 | + $childRules = $xpath->query("parseObject", $rule); |
| 155 | + if ($rule->nodeName == "sequence") { |
| 156 | + $pushInd = 0; |
| 157 | + for ($i = $childRules->length - 1; $i >= 0; $i --) { |
| 158 | + $this->pushTags($childRules->item($i), $tagStr); |
| 159 | + if ($i > 0) { |
| 160 | + if ($this->pullTags($childRules->item($i), $iter, $childTag)) { |
| 161 | + if ($tagStr == "") { |
| 162 | + $tagStr = $childTag; |
| 163 | + } elseif ($childTag != "") { |
| 164 | + $tagStr .= "|" . $childTag; |
| 165 | + } |
| 166 | + } else { |
| 167 | + if ($pushInd < $i) { |
| 168 | + $pushInd = $i; |
| 169 | + } |
| 170 | + $tagStr = $childTag; |
| 171 | + } |
| 172 | + } |
| 173 | + } |
| 174 | + $rule->setAttribute("pushInd", $pushInd); |
| 175 | + } else { |
| 176 | + if ($rule->nodeName != "choice") { |
| 177 | + $rule->setAttribute("saveTags", $tagStr); |
| 178 | + $tagStr = NULL; |
| 179 | + if ($rule->nodeName == "text") { |
| 180 | + $childTags = ""; |
| 181 | + foreach ($childRules as $child) { |
| 182 | + if ($childTags != "") { |
| 183 | + $childTags .= "|"; |
| 184 | + } |
| 185 | + $this->pullTags($child, $iter, $childTag); |
| 186 | + $childTags .= $childTag; |
| 187 | + } |
| 188 | + $rule->setAttribute("childTags", $childTags); |
| 189 | + } |
| 190 | + } |
| 191 | + foreach ($childRules as $child) { |
| 192 | + $this->pushTags($child, $tagStr); |
| 193 | + } |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + private function pullTags($rule, &$iter, &$childTags) { |
| 198 | + $iter ++; |
| 199 | + if ($iter > ParseEngine::maxIter) { |
| 200 | + throw new MWException("Collecter iterated too many times. Probable loop in grammar."); |
| 201 | + } |
| 202 | + $rule = $rule->firstChild; |
| 203 | + $xpath = new DOMXPath($rule->ownerDocument); |
| 204 | + $childTags = ""; |
| 205 | + $failSafe = TRUE; |
| 206 | + if ($rule->nodeName == "assignment") { |
| 207 | + $patterns = $xpath->query("pattern", $rule); |
| 208 | + if ($patterns->length > 0) { |
| 209 | + $childTags = $patterns->item(0)->getAttribute("tag"); |
| 210 | + } |
| 211 | + $failSafe = FALSE; |
| 212 | + } elseif ($rule->nodeName == "choice" || $rule->nodeName == "sequence") { |
| 213 | + $childRules = $xpath->query("parseObject", $rule); |
| 214 | + $failSafe = $rule->nodeName == "sequence"; |
| 215 | + foreach ($childRules as $child) { |
| 216 | + $failSafe = $this->pullTags($child, $iter, $newTags); |
| 217 | + if ($childTags == "") { |
| 218 | + $childTags = $newTags; |
| 219 | + } elseif ($newTags != "") { |
| 220 | + $childTags .= "|" . $newTags; |
| 221 | + } |
| 222 | + if (($failSafe && $rule->nodeName == "choice") || (! $failSafe && $rule->nodeName == "sequence")) { |
| 223 | + break; |
| 224 | + } |
| 225 | + } |
| 226 | + $failSafe |= $rule->hasAttribute("tag"); |
| 227 | + } elseif ($rule->nodeName == "reference") { |
| 228 | + $refRule = $xpath->query("/grammar/rule[@tag='{$rule->getAttribute("tag")}']/parseObject")->item(0); |
| 229 | + $failSafe = $this->pullTags($refRule, $iter, $childTags); |
| 230 | + } |
| 231 | + return $failSafe; |
| 232 | + } |
| 233 | +} |
| 234 | + |
Property changes on: trunk/extensions/ParserWiki/ParseEngine.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 235 | + native |
Index: trunk/extensions/ParserWiki/ParserWiki.php |
— | — | @@ -0,0 +1,58 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Allows people to define a grammar in a wiki then use that grammar to input information to the same wiki |
| 5 | + * @ingroup Extensions |
| 6 | + * @author Nathanael Thompson <than4213@gmail.com> |
| 7 | + * @copyright Copyright © 2010 Nathanael Thompson |
| 8 | + * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License |
| 9 | + */ |
| 10 | +if ( !defined( "MEDIAWIKI" ) ) { |
| 11 | + die( "This is not a valid entry point.\n" ); |
| 12 | +} |
| 13 | + |
| 14 | +$wgExtensionCredits["other"][] = array( |
| 15 | + "path" => __FILE__, |
| 16 | + "name" => "ParserWiki", |
| 17 | + "author" => "Nathanael Thompson", |
| 18 | + "url" => "http://www.mediawiki.org/wiki/Extension:ParserWiki", |
| 19 | + "version" => "1.0", |
| 20 | + "descriptionmsg" => "parserwiki-desc", |
| 21 | +); |
| 22 | + |
| 23 | +$wgAutoloadClasses["ParseEngine"] = dirname( __FILE__ ) . "/ParseEngine.php"; |
| 24 | + |
| 25 | +$wgTheParserWiki = new ParserWiki(); |
| 26 | +$wgHooks["ParserBeforeStrip"][] = array($wgTheParserWiki, "callFromParse"); |
| 27 | + |
| 28 | +define ( "NS_GRAMMAR" , 91628); |
| 29 | +define ( "NS_GRAMMAR_TALK" , 91629); |
| 30 | +$wgExtraNamespaces[NS_GRAMMAR] = "Grammar"; |
| 31 | +$wgExtraNamespaces[NS_GRAMMAR_TALK] = "Grammar_talk"; |
| 32 | + |
| 33 | +class ParserWiki { |
| 34 | + private $mEngines; |
| 35 | + |
| 36 | + function __construct() { |
| 37 | + $this->mEngines = array(); |
| 38 | + } |
| 39 | + |
| 40 | + function callFromParse($unUsed, &$text) { |
| 41 | + global $wgParserWikiGrammar; |
| 42 | + $engine = $this->mEngines[$wgParserWikiGrammar]; |
| 43 | + if ($engine == NULL) { |
| 44 | + $revision = Revision::newFromTitle(Title::newFromText($wgParserWikiGrammar, NS_GRAMMAR)); |
| 45 | + $grammar = new DOMDocument(); |
| 46 | + if ($revision == NULL || ! $grammar->loadXML($revision->getText(), LIBXML_NOBLANKS)) { |
| 47 | + return TRUE; |
| 48 | + } |
| 49 | + $engine = new ParseEngine($grammar); |
| 50 | + $this->mEngines[$wgParserWikiGrammar] = $engine; |
| 51 | + } |
| 52 | + $parseTree = $engine->parse($text); |
| 53 | + if ($parseTree == NULL) { |
| 54 | + return TRUE; |
| 55 | + } |
| 56 | + $text = $parseTree->saveXML(); |
| 57 | + return FALSE; |
| 58 | + } |
| 59 | +} |
Property changes on: trunk/extensions/ParserWiki/ParserWiki.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 60 | + native |
Index: trunk/extensions/ParserWiki/parserTests.txt |
— | — | @@ -0,0 +1,37 @@ |
| 2 | +# Tests for the ParseEngine using maintenance/parserTests.php |
| 3 | +# Please make sure that the input parser XML is an exact duplicate of the test result |
| 4 | + |
| 5 | +!!article |
| 6 | +Grammar:WikiGrammar1_0 |
| 7 | +!!text |
| 8 | +<grammar><tag tag=";; grammar for WikiGrammar v1.0 ;; only one parseObject at base level for the start rule / root node <"/><parseObject><assignment tag="grammar"><tag tag=" ["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="parseObject"/></parseObject><tag tag=" ->"/><parseObject><reference tag="ruleList"/></parseObject><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/></assignment></parseObject><tag tag=">"/><tag tag=" ;; ignore whitespace, comments lines starting in # and tags "/><rule tag="tag"><tag tag=" ="/><tag tag=" <"/><parseObject><assignment tag="tag"><tag tag=" /"/><pattern tag="(?:\s+|;;[^\n]*)*~r"/><tag tag="/"/></assignment></parseObject><tag tag=">"/></rule><tag tag=" "/><rule tag="pattern"><tag tag=" ="/><tag tag=" ["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\/"/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="pattern"><tag tag=" /"/><pattern tag="(?:[^\\\/]|\\.)*"/><tag tag="/"/></assignment></parseObject><tag tag=">"/><tag tag=" <"/><parseObject><assignment tag="tag"><tag tag=" /"/><pattern tag="\/"/><tag tag="/"/></assignment></parseObject><tag tag=">"/></sequence></parseObject><tag tag="]"/></rule><tag tag=" ;; This works a lot like polymorphism -> new feature "/><rule tag="parseObject"><tag tag=" ="/><tag tag=" ("/><parseObject><choice><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="->"/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="reference"><tag tag=" /"/><pattern tag="\w+"/><tag tag="/"/><tag tag=" ("/><parseObject><choice tag="?"><tag tag="["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="="/><tag tag="/"/></reference></parseObject><tag tag=" ->"/><parseObject><reference tag="pattern"/></parseObject></sequence></parseObject><tag tag="]"/></choice></parseObject><tag tag=")"/></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/></sequence></parseObject><tag tag="]"/><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\("/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="choice"><tag tag=" /"/><pattern tag="\??"/><tag tag="/"/><tag tag=" ->"/><parseObject><reference tag="objectList"/></parseObject></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\)"/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\["/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="sequence"><tag tag=" ->"/><parseObject><reference tag="objectList"/></parseObject></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\]"/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="$"/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="text"><tag tag=" ("/><parseObject><choice tag="?"><tag tag="->"/><parseObject><reference tag="parseObject"/></parseObject></choice></parseObject><tag tag=")"/></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="$"/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="<"/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="assignment"><tag tag=" /"/><pattern tag="\w+"/><tag tag="/"/><tag tag=" ["/><parseObject><sequence><tag tag=" 		("/><parseObject><choice tag="?"><tag tag="->"/><parseObject><reference tag="pattern"/></parseObject></choice></parseObject><tag tag=")"/><tag tag=" 		("/><parseObject><choice tag="?"><tag tag="->"/><parseObject><reference tag="parseObject"/></parseObject></choice></parseObject><tag tag=")"/></sequence></parseObject><tag tag=" 	]"/></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag=">"/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/></choice></parseObject><tag tag=" )"/></rule><tag tag=" ;; Lists work a lot like regEx +'s -> syntactic sugar "/><rule tag="objectList"><tag tag=" ="/><tag tag=" ("/><parseObject><choice tag="?"><tag tag="["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="parseObject"/></parseObject><tag tag=" ->"/><parseObject><reference tag="objectList"/></parseObject></sequence></parseObject><tag tag="]"/></choice></parseObject><tag tag=")"/></rule><tag tag=" "/><rule tag="ruleList"><tag tag=" ="/><tag tag=" ("/><parseObject><choice tag="?"><tag tag="["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="rule"><tag tag=" /"/><pattern tag="\w+"/><tag tag="/"/><tag tag=" ["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="="/><tag tag="/"/></reference></parseObject><tag tag=" ->"/><parseObject><reference tag="parseObject"/></parseObject></sequence></parseObject><tag tag="]"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="ruleList"/></parseObject></sequence></parseObject><tag tag="]"/></choice></parseObject><tag tag=")"/></rule><tag/></grammar> |
| 9 | +!!endarticle |
| 10 | + |
| 11 | +!! test |
| 12 | +Generic Test |
| 13 | +!! input |
| 14 | +;; grammar for WikiGrammar v1.0 |
| 15 | +;; only one parseObject at base level for the start rule / root node |
| 16 | +<grammar [->parseObject ->ruleList ->tag=//]> |
| 17 | +;; ignore whitespace, comments lines starting in # and tags |
| 18 | +tag = <tag /(?:\s+|;;[^\n]*)*~r/> |
| 19 | +pattern = [->tag=/\// <pattern /(?:[^\\\/]|\\.)*/> <tag /\//>] |
| 20 | +;; This works a lot like polymorphism -> new feature |
| 21 | +parseObject = ( |
| 22 | + [->tag=/->/ <parseObject <reference /\w+/ (?[->tag=/=/ ->pattern])>>] |
| 23 | + [->tag=/\(/ <parseObject <choice /\??/ ->objectList>> ->tag=/\)/] |
| 24 | + [->tag=/\[/ <parseObject <sequence ->objectList>> ->tag=/\]/] |
| 25 | + [->tag=/$/ <parseObject <text (?->parseObject)>> ->tag=/$/] |
| 26 | + [->tag=/</ <parseObject <assignment /\w+/ [ |
| 27 | + (?->pattern) |
| 28 | + (?->parseObject) |
| 29 | + ]>> ->tag=/>/] |
| 30 | +) |
| 31 | +;; Lists work a lot like regEx +'s -> syntactic sugar |
| 32 | +objectList = (?[->parseObject ->objectList]) |
| 33 | +ruleList = (?[->tag=// <rule /\w+/ [->tag=/=/ ->parseObject]> ->ruleList]) |
| 34 | +!! result |
| 35 | +<grammar><tag tag=";; grammar for WikiGrammar v1.0 ;; only one parseObject at base level for the start rule / root node <"/><parseObject><assignment tag="grammar"><tag tag=" ["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="parseObject"/></parseObject><tag tag=" ->"/><parseObject><reference tag="ruleList"/></parseObject><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/></assignment></parseObject><tag tag=">"/><tag tag=" ;; ignore whitespace, comments lines starting in # and tags "/><rule tag="tag"><tag tag=" ="/><tag tag=" <"/><parseObject><assignment tag="tag"><tag tag=" /"/><pattern tag="(?:\s+|;;[^\n]*)*~r"/><tag tag="/"/></assignment></parseObject><tag tag=">"/></rule><tag tag=" "/><rule tag="pattern"><tag tag=" ="/><tag tag=" ["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\/"/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="pattern"><tag tag=" /"/><pattern tag="(?:[^\\\/]|\\.)*"/><tag tag="/"/></assignment></parseObject><tag tag=">"/><tag tag=" <"/><parseObject><assignment tag="tag"><tag tag=" /"/><pattern tag="\/"/><tag tag="/"/></assignment></parseObject><tag tag=">"/></sequence></parseObject><tag tag="]"/></rule><tag tag=" ;; This works a lot like polymorphism -> new feature "/><rule tag="parseObject"><tag tag=" ="/><tag tag=" ("/><parseObject><choice><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="->"/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="reference"><tag tag=" /"/><pattern tag="\w+"/><tag tag="/"/><tag tag=" ("/><parseObject><choice tag="?"><tag tag="["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="="/><tag tag="/"/></reference></parseObject><tag tag=" ->"/><parseObject><reference tag="pattern"/></parseObject></sequence></parseObject><tag tag="]"/></choice></parseObject><tag tag=")"/></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/></sequence></parseObject><tag tag="]"/><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\("/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="choice"><tag tag=" /"/><pattern tag="\??"/><tag tag="/"/><tag tag=" ->"/><parseObject><reference tag="objectList"/></parseObject></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\)"/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\["/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="sequence"><tag tag=" ->"/><parseObject><reference tag="objectList"/></parseObject></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="\]"/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="$"/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="text"><tag tag=" ("/><parseObject><choice tag="?"><tag tag="->"/><parseObject><reference tag="parseObject"/></parseObject></choice></parseObject><tag tag=")"/></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="$"/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/><tag tag=" 	["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="<"/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="parseObject"><tag tag=" <"/><parseObject><assignment tag="assignment"><tag tag=" /"/><pattern tag="\w+"/><tag tag="/"/><tag tag=" ["/><parseObject><sequence><tag tag=" 		("/><parseObject><choice tag="?"><tag tag="->"/><parseObject><reference tag="pattern"/></parseObject></choice></parseObject><tag tag=")"/><tag tag=" 		("/><parseObject><choice tag="?"><tag tag="->"/><parseObject><reference tag="parseObject"/></parseObject></choice></parseObject><tag tag=")"/></sequence></parseObject><tag tag=" 	]"/></assignment></parseObject><tag tag=">"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag=">"/><tag tag="/"/></reference></parseObject></sequence></parseObject><tag tag="]"/></choice></parseObject><tag tag=" )"/></rule><tag tag=" ;; Lists work a lot like regEx +'s -> syntactic sugar "/><rule tag="objectList"><tag tag=" ="/><tag tag=" ("/><parseObject><choice tag="?"><tag tag="["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="parseObject"/></parseObject><tag tag=" ->"/><parseObject><reference tag="objectList"/></parseObject></sequence></parseObject><tag tag="]"/></choice></parseObject><tag tag=")"/></rule><tag tag=" "/><rule tag="ruleList"><tag tag=" ="/><tag tag=" ("/><parseObject><choice tag="?"><tag tag="["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern/><tag tag="/"/></reference></parseObject><tag tag=" <"/><parseObject><assignment tag="rule"><tag tag=" /"/><pattern tag="\w+"/><tag tag="/"/><tag tag=" ["/><parseObject><sequence><tag tag="->"/><parseObject><reference tag="tag"><tag tag="="/><tag tag="/"/><pattern tag="="/><tag tag="/"/></reference></parseObject><tag tag=" ->"/><parseObject><reference tag="parseObject"/></parseObject></sequence></parseObject><tag tag="]"/></assignment></parseObject><tag tag=">"/><tag tag=" ->"/><parseObject><reference tag="ruleList"/></parseObject></sequence></parseObject><tag tag="]"/></choice></parseObject><tag tag=")"/></rule><tag/></grammar> |
| 36 | + |
| 37 | +!! end |
| 38 | + |
Property changes on: trunk/extensions/ParserWiki/parserTests.txt |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 39 | + native |