Index: trunk/extensions/WikiScripts/interpreter/Scanner.php |
— | — | @@ -91,9 +91,12 @@ |
92 | 92 | $this->mEof = true; |
93 | 93 | return $this->mCur = null; |
94 | 94 | } |
| 95 | + |
| 96 | + wfProfileIn( __METHOD__ ); |
95 | 97 | list( $val, $type ) = $this->nextToken(); |
96 | 98 | |
97 | 99 | $lineno = count( explode( "\n", substr( $this->mCode, 0, $this->mPos ) ) ); |
| 100 | + wfProfileOut( __METHOD__ ); |
98 | 101 | return $this->mCur = new WSToken( $type, $val, $lineno ); |
99 | 102 | } |
100 | 103 | |
Index: trunk/extensions/WikiScripts/interpreter/EvaluationContext.php |
— | — | @@ -591,13 +591,27 @@ |
592 | 592 | } |
593 | 593 | |
594 | 594 | protected function deleteVar( $lval, $rec ) { |
| 595 | + // First throw an exception if a variable does not exist |
| 596 | + $this->getVar( $lval, $rec + 1 ); |
| 597 | + |
595 | 598 | $c = $lval->getChildren(); |
596 | | - $line = $c[0]->line; |
597 | | - $varname = $c[0]->value; |
598 | | - if( isset( $c[1] ) ) { |
599 | | - throw new WSException( 'delete() is not usable for array elements' ); |
| 599 | + if( $c[0] instanceof WSToken ) { |
| 600 | + // Variable |
| 601 | + $varname = $c[0]->value; |
| 602 | + unset( $this->mVars[$varname] ); |
| 603 | + } else { |
| 604 | + // Array element |
| 605 | + $ref = $this->setVarGetRef( $c[0], $rec + 1 ); |
| 606 | + $idxchildren = $c[1]->getChildren(); |
| 607 | + $key = $this->evaluateNode( $idxchildren[1], $rec + 1 ); |
| 608 | + |
| 609 | + if( $ref->type == WSData::DAssoc ) { |
| 610 | + unset( $ref->data[$key->toString()] ); |
| 611 | + } else { |
| 612 | + array_splice( $ref->data, $key->toInt(), 1 ); |
| 613 | + } |
| 614 | + unset( $ref ); |
600 | 615 | } |
601 | | - unset( $this->mVars[$varname] ); |
602 | 616 | } |
603 | 617 | |
604 | 618 | public function error( $name, $line, $params = array() ) { |
Index: trunk/extensions/WikiScripts/interpreter/Interpreter.php |
— | — | @@ -162,6 +162,7 @@ |
163 | 163 | // Try local cache |
164 | 164 | $key = WSModule::getCacheKey( $title ); |
165 | 165 | if( $this->mUseCache && isset( $this->mParserCache[$key] ) ) { |
| 166 | + wfIncrStats( 'script_pcache_hit_local' ); |
166 | 167 | $module = $this->mParserCache[$key]; |
167 | 168 | $this->addModuleTitle( $module->getTitle() ); |
168 | 169 | wfProfileOut( __METHOD__ ); |
— | — | @@ -172,24 +173,32 @@ |
173 | 174 | wfProfileIn( __METHOD__ . '-unserialize' ); |
174 | 175 | $cached = $parserMemc->get( $key ); |
175 | 176 | wfProfileOut( __METHOD__ . '-unserialize' ); |
176 | | - if( $this->mUseCache && @$cached instanceof WSModule && !$cached->isOutOfDate() ) { |
177 | | - $this->mParserCache[$key] = $cached; |
178 | | - $this->addModuleTitle( $cached->getTitle() ); |
179 | | - wfProfileOut( __METHOD__ ); |
180 | | - return $cached; |
| 177 | + if( $this->mUseCache && @$cached instanceof WSModule ) { |
| 178 | + if( !$cached->isOutOfDate() ) { |
| 179 | + wfIncrStats( 'script_pcache_hit_object' ); |
| 180 | + $this->mParserCache[$key] = $cached; |
| 181 | + $this->addModuleTitle( $cached->getTitle() ); |
| 182 | + wfProfileOut( __METHOD__ ); |
| 183 | + return $cached; |
| 184 | + } else { |
| 185 | + wfIncrStats( 'script_pcache_expired' ); |
| 186 | + } |
181 | 187 | } |
182 | 188 | |
183 | 189 | // Load from database |
| 190 | + wfIncrStats( 'script_pcache_missing' ); |
184 | 191 | $rev = self::getModuleRev( $title ); |
185 | | - if( !$rev || $rev->getTitle()->getNamespace() != NS_MODULE ) { |
186 | | - return false; |
| 192 | + |
| 193 | + if( $rev && $rev->getTitle()->getNamespace() == NS_MODULE ) { |
| 194 | + // Parse |
| 195 | + $moduleName = $rev->getTitle()->getText(); |
| 196 | + $out = self::invokeCodeParser( $rev->getText(), $moduleName ); |
| 197 | + $module = WSModule::newFromParserOutput( $this, $rev->getTitle(), $rev->getId(), $out ); |
| 198 | + } else { |
| 199 | + // Invalid module. Still record that to cache |
| 200 | + $module = false; |
187 | 201 | } |
188 | 202 | |
189 | | - // Parse |
190 | | - $moduleName = $rev->getTitle()->getText(); |
191 | | - $out = self::invokeCodeParser( $rev->getText(), $moduleName ); |
192 | | - $module = WSModule::newFromParserOutput( $this, $rev->getTitle(), $rev->getId(), $out ); |
193 | | - |
194 | 203 | // Save to cache |
195 | 204 | $this->mParserCache[$key] = $module; |
196 | 205 | $parserMemc->set( $key, $module ); |
Index: trunk/extensions/WikiScripts/interpreter/Library.php |
— | — | @@ -64,12 +64,21 @@ |
65 | 65 | public function callFunction( $name, $args, $context, $line ) { |
66 | 66 | $funcs = $this->getFunctions(); |
67 | 67 | list( $method, $minArgs ) = $funcs[ $name ]; |
| 68 | + $fullname = __CLASS__ . "::{$method}"; |
68 | 69 | |
69 | 70 | $argsNumber = count( $args ); |
70 | 71 | if( $argsNumber < $minArgs ) { |
71 | 72 | $context->error( 'notenoughargs', $line, array( $name, $minArgs, $argsNumber ) ); |
72 | 73 | } |
73 | 74 | |
74 | | - return $this->$method( $args, $context, $line ); |
| 75 | + wfProfileIn( $fullname ); |
| 76 | + try { |
| 77 | + $result = $this->$method( $args, $context, $line ); |
| 78 | + wfProfileOut( $fullname ); |
| 79 | + return $result; |
| 80 | + } catch( WSException $e ) { |
| 81 | + wfProfileOut( $fullname ); |
| 82 | + throw $e; |
| 83 | + } |
75 | 84 | } |
76 | 85 | } |
Index: trunk/extensions/WikiScripts/interpreterTests.txt |
— | — | @@ -584,6 +584,27 @@ |
585 | 585 | !! end |
586 | 586 | |
587 | 587 | !! article |
| 588 | +Module:Lists: unset |
| 589 | +!! text |
| 590 | +function run() { |
| 591 | + lst = [ 'a', 'b', 'c', 'd' ]; |
| 592 | + delete( lst[2] ); |
| 593 | + return lst; |
| 594 | +} |
| 595 | +!! endarticle |
| 596 | + |
| 597 | +!! test |
| 598 | +Lists: unset |
| 599 | +!! input |
| 600 | +{{i:Lists: unset|run}} |
| 601 | +!! result |
| 602 | +<p>a |
| 603 | +b |
| 604 | +d |
| 605 | +</p> |
| 606 | +!! end |
| 607 | + |
| 608 | +!! article |
588 | 609 | Module:Associated arrays: basics |
589 | 610 | !! text |
590 | 611 | function run() { |
— | — | @@ -608,6 +629,31 @@ |
609 | 630 | !! end |
610 | 631 | |
611 | 632 | !! article |
| 633 | +Module:Associated arrays: isset/unset |
| 634 | +!! text |
| 635 | +function run() { |
| 636 | + a = { "a" : 2, "b" : 13, "c" : 48 }; |
| 637 | + delete( a['b'] ); |
| 638 | + a["e"] = isset( a['a'] ); |
| 639 | + |
| 640 | + for( k : v in a ) { |
| 641 | + append k + " = " + v + "\n\n"; |
| 642 | + } |
| 643 | +} |
| 644 | +!! endarticle |
| 645 | + |
| 646 | +!! test |
| 647 | +Associated arrays: isset/unset |
| 648 | +!! input |
| 649 | +{{i:Associated arrays: isset/unset|run}} |
| 650 | +!! result |
| 651 | +<p>a = 2 |
| 652 | +</p><p>c = 48 |
| 653 | +</p><p>e = 1 |
| 654 | +</p> |
| 655 | +!! end |
| 656 | + |
| 657 | +!! article |
612 | 658 | Module:Mixed arrays |
613 | 659 | !! text |
614 | 660 | function run() { |