From a102a4ed5256ba7903f8ec98f3b3c953d90bee66 Mon Sep 17 00:00:00 2001 From: "Moritz Schubotz (physikerwelt)" Date: Sun, 18 Feb 2024 00:02:37 +0100 Subject: [PATCH] Remove curly To reduce the complexity of the parse tree we remove the curly element which is used for grouping in TeX. Instead, we use use an attribute which defines if the group is put into curly brackets or not. The functionality of the curly element is transferred to the TexArray which was the only possible child of the curly element before. To ease the transition, we add a special constructor to TexArray. We could not measure any performance implications of this change. Bug: T333973 Change-Id: Idcb58694022831113bdc437576bb9f48658fff2f --- maintenance/buildPHPparser.js | 1 - src/WikiTexVC/MMLmappings/BaseParsing.php | 32 ++++++------ src/WikiTexVC/MMLmappings/Util/MMLutil.php | 12 ++--- src/WikiTexVC/Nodes/Curly.php | 51 ------------------- src/WikiTexVC/Nodes/DQ.php | 2 +- src/WikiTexVC/Nodes/FQ.php | 15 ++---- src/WikiTexVC/Nodes/TexArray.php | 33 +++++++++--- src/WikiTexVC/Nodes/TexNode.php | 5 ++ src/WikiTexVC/Parser.php | 13 +++-- src/WikiTexVC/ParserUtil.php | 5 +- src/WikiTexVC/parser.pegjs | 14 ++--- .../unit/WikiTexVC/Nodes/CurlyTest.php | 48 +++++------------ tests/phpunit/unit/WikiTexVC/Nodes/DQTest.php | 3 +- tests/phpunit/unit/WikiTexVC/Nodes/FQTest.php | 7 +-- .../phpunit/unit/WikiTexVC/Nodes/Fun1Test.php | 13 +++-- 15 files changed, 100 insertions(+), 154 deletions(-) delete mode 100644 src/WikiTexVC/Nodes/Curly.php diff --git a/maintenance/buildPHPparser.js b/maintenance/buildPHPparser.js index d77483acb..cb231c7f5 100755 --- a/maintenance/buildPHPparser.js +++ b/maintenance/buildPHPparser.js @@ -65,7 +65,6 @@ const useStatements = 'use MediaWiki\\Extension\\Math\\WikiTexVC\\Nodes\\Big;\n' + 'use MediaWiki\\Extension\\Math\\WikiTexVC\\Nodes\\ChemFun2u;\n' + 'use MediaWiki\\Extension\\Math\\WikiTexVC\\Nodes\\ChemWord;\n' + - 'use MediaWiki\\Extension\\Math\\WikiTexVC\\Nodes\\Curly;\n' + 'use MediaWiki\\Extension\\Math\\WikiTexVC\\Nodes\\Declh;\n' + 'use MediaWiki\\Extension\\Math\\WikiTexVC\\Nodes\\Dollar;\n' + 'use MediaWiki\\Extension\\Math\\WikiTexVC\\Nodes\\DQ;\n' + diff --git a/src/WikiTexVC/MMLmappings/BaseParsing.php b/src/WikiTexVC/MMLmappings/BaseParsing.php index 1e024baef..ba77aac52 100644 --- a/src/WikiTexVC/MMLmappings/BaseParsing.php +++ b/src/WikiTexVC/MMLmappings/BaseParsing.php @@ -31,7 +31,6 @@ use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtext; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtr; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmunder; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmunderover; -use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; use MediaWiki\Extension\Math\WikiTexVC\Nodes\FQ; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun1; @@ -41,6 +40,7 @@ use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun2sq; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun4; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Matrix; +use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray; use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode; use MediaWiki\Extension\Math\WikiTexVC\TexVC; @@ -136,7 +136,7 @@ class BaseParsing { foreach ( $tableRow->getArgs() as $tableCell ) { $renderedInner .= $mtd->getStart(); foreach ( $tableCell->getArgs() as $cellItem ) { - if ( !$discarded && $cellItem instanceof Curly ) { + if ( !$discarded && $cellItem->isCurly() ) { $discarded = true; // Just discard the number of rows atm, it is in the first Curly } else { @@ -357,7 +357,7 @@ class BaseParsing { } public static function hskip( $node, $passedArgs, $operatorContent, $name ) { - if ( $node->getArg() instanceof Curly ) { + if ( $node->getArg()->isCurly() ) { $unit = MMLutil::squashLitsToUnit( $node->getArg() ); if ( !$unit ) { return null; @@ -556,7 +556,7 @@ class BaseParsing { $addHlines = true; } } - if ( count( $arg->getArgs() ) >= 1 && $arg->getArgs()[0] instanceof Curly ) { + if ( count( $arg->getArgs() ) >= 1 && $arg->getArgs()[0]->isCurly() ) { // Discarding the column information Curly at the moment // $usedArg->getArgs()[0] = null; $columnInfo = $usedArg->getArgs()[0]->render(); @@ -743,7 +743,8 @@ class BaseParsing { } $arg1 = $node->getArg1(); - if ( $arg1 instanceof Curly ) { + // the second check is to avoid a false positive for PhanTypeMismatchArgumentSuperType + if ( $arg1->isCurly() && $arg1 instanceof TexArray ) { $unit = MMLutil::squashLitsToUnit( $arg1 ); if ( !$unit ) { return null; @@ -1043,8 +1044,8 @@ class BaseParsing { if ( $node instanceof Fun2sq ) { $arg1 = $node->getArg1(); $arg1i = ""; - if ( $arg1 instanceof Curly ) { - $arg1i = $arg1->getArg()->render(); + if ( $arg1->isCurly() ) { + $arg1i = $arg1->render(); } if ( str_contains( $arg1i, "{b}" ) ) { @@ -1099,11 +1100,12 @@ class BaseParsing { // match args in row of subargs, unless an element has explicit annotations // nested annotations ? $arg1 = $node->getArg1(); - if ( !$node->getArg2() instanceof Curly ) { + $arg2 = $node->getArg2(); + if ( !$arg2->isCurly() ) { return null; } // tbd refactor intent form and fiddle in mml or tree - $intentStr = MMLutil::squashLitsToUnitIntent( $node->getArg2() ); + $intentStr = MMLutil::squashLitsToUnitIntent( $arg2 ); $intentContent = MMLParsingUtil::getIntentContent( $intentStr ); $intentParams = MMLParsingUtil::getIntentParams( $intentContent ); // Sometimes the intent has additioargs = {array[3]} nal args in the same string @@ -1122,19 +1124,19 @@ class BaseParsing { $intentParamsState = $intentParams ? [ "intent-params" => $intentParams ] : $operatorContent; // Here are some edge cases, they might go into renderMML in the related element if ( str_contains( $intentContent, "matrix" ) || - ( $arg1 instanceof Curly && $arg1->getArg()->getArgs()[0] instanceof Matrix ) ) { - $element = $arg1->getArg()->getArgs()[0]; + ( $arg1->isCurly() && $arg1->getArgs()[0] instanceof Matrix ) ) { + $element = $arg1->getArgs()[0]; $rendered = $element->renderMML( [], $intentParamsState ); $hackyXML = MMLParsingUtil::forgeIntentToSpecificElement( $rendered, $intentContentAtr, "mtable" ); return $hackyXML; - } elseif ( $arg1 instanceof Curly && count( $arg1->getArg()->getArgs() ) >= 2 ) { + } elseif ( $arg1->isCurly() && count( $arg1->getArgs() ) >= 2 ) { // Create a surrounding element which holds the intents $mrow = new MMLmrow( "", $intentContentAtr ); return $mrow->encapsulateRaw( $arg1->renderMML( [], $intentParamsState ) ); - } elseif ( $arg1 instanceof Curly && count( $arg1->getArg()->getArgs() ) >= 1 ) { + } elseif ( $arg1->isCurly() && count( $arg1->getArgs() ) >= 1 ) { // Forge the intent attribute to the top-level element after MML rendering - $element = $arg1->getArg()->getArgs()[0]; + $element = $arg1->getArgs()[0]; $rendered = $element->renderMML( [], $intentParamsState ); $hackyXML = MMLParsingUtil::forgeIntentToTopElement( $rendered, $intentContentAtr ); return $hackyXML; @@ -1185,7 +1187,7 @@ class BaseParsing { $mmlMrow = new MMLmrow(); $mtext = new MMLmtext( "", MMLParsingUtil::getFontArgs( $name, null, null ) ); - $inner = $node->getArg() instanceof Curly ? $node->getArg()->getArg()->renderMML( + $inner = $node->getArg()->isCurly() ? $node->getArg()->renderMML( [], [ "inHBox" => true ] ) : $node->getArg()->renderMML( [ "fromHBox" => true ] ); return $mmlMrow->encapsulateRaw( $mtext->encapsulateRaw( $inner ) ); diff --git a/src/WikiTexVC/MMLmappings/Util/MMLutil.php b/src/WikiTexVC/MMLmappings/Util/MMLutil.php index e11685723..d247ecf98 100644 --- a/src/WikiTexVC/MMLmappings/Util/MMLutil.php +++ b/src/WikiTexVC/MMLmappings/Util/MMLutil.php @@ -2,9 +2,9 @@ namespace MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util; use IntlChar; -use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal; +use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray; use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode; /** @@ -78,12 +78,12 @@ class MMLutil { /** * Assumes the input curly contains an TexArray of literals, squashes the TexArray characters to a string. - * @param Curly $node curly containing a TexArray of literals + * @param TexArray $node TexArray of literals * @return ?string squashed string in example "2mu", "-3mu" etc. Null if no TexArray inside curly. */ - public static function squashLitsToUnit( Curly $node ): ?string { + public static function squashLitsToUnit( TexArray $node ): ?string { $unit = ""; - foreach ( $node->getArg()->getArgs() as $literal ) { + foreach ( $node->getArgs() as $literal ) { if ( !$literal instanceof Literal ) { continue; } @@ -220,11 +220,11 @@ class MMLutil { * @return ?string squashed string in example "2mu", "-3mu" etc. Null if no TexArray inside curly. */ public static function squashLitsToUnitIntent( TexNode $node ): ?string { - if ( !$node instanceof Curly ) { + if ( !$node->isCurly() ) { return null; } $unit = ""; - foreach ( $node->getArg()->getArgs() as $literal ) { + foreach ( $node->getArgs() as $literal ) { if ( $literal instanceof DQ ) { $args = $literal->getArgs(); if ( !$args[0] instanceof Literal || !$args[1] instanceof Literal ) { diff --git a/src/WikiTexVC/Nodes/Curly.php b/src/WikiTexVC/Nodes/Curly.php deleted file mode 100644 index ac76db2cb..000000000 --- a/src/WikiTexVC/Nodes/Curly.php +++ /dev/null @@ -1,51 +0,0 @@ -arg = $arg; - } - - /** - * @return TexArray - */ - public function getArg(): TexArray { - return $this->arg; - } - - public function render() { - return $this->arg->inCurlies(); - } - - public function renderMML( $arguments = [], $state = [] ) { - if ( count( $this->arg->getArgs() ) > 1 ) { - $mmlRow = new MMLmrow(); - return $mmlRow->encapsulateRaw( parent::renderMML( $arguments, $state ) ); - } - - return parent::renderMML( $arguments, $state ); - } - - public function inCurlies() { - return $this->render(); - } - - public function extractSubscripts() { - return $this->arg->extractSubscripts(); - } - - public function getModIdent() { - return $this->arg->getModIdent(); - } - -} diff --git a/src/WikiTexVC/Nodes/DQ.php b/src/WikiTexVC/Nodes/DQ.php index 8f7a8279a..7ee3f1e5a 100644 --- a/src/WikiTexVC/Nodes/DQ.php +++ b/src/WikiTexVC/Nodes/DQ.php @@ -47,7 +47,7 @@ class DQ extends TexNode { $emptyMrow = ""; // In cases with empty curly preceding like: "{}_pF_q" - if ( $this->getBase() instanceof Curly && $this->getBase()->isEmpty() ) { + if ( $this->getBase()->isCurly() && $this->getBase()->isEmpty() ) { $mrow = new MMLmrow(); $emptyMrow = $mrow->getEmpty(); } diff --git a/src/WikiTexVC/Nodes/FQ.php b/src/WikiTexVC/Nodes/FQ.php index d3fa5bada..b2a106fcd 100644 --- a/src/WikiTexVC/Nodes/FQ.php +++ b/src/WikiTexVC/Nodes/FQ.php @@ -57,24 +57,19 @@ class FQ extends TexNode { // A specific FQ case with preceding limits, just invoke the limits parsing manually. return BaseParsing::limits( $this, $arguments, $state, "" ); } + $base = $this->getBase(); - if ( $this->getArgs()[0]->getLength() == 0 ) { + if ( $base->getLength() == 0 && !$base->isCurly() ) { // this happens when FQ is located in Sideset (is this a common parsing way?) $mrow = new MMLmrow(); return $mrow->encapsulateRaw( $this->getDown()->renderMML( [], $state ) ) . $mrow->encapsulateRaw( $this->getUp()->renderMML( [], $state ) ); } - // Not sure if this case is necessary .. - if ( is_string( $this->getArgs()[0] ) ) { - return $this->parseToMML( $this->getArgs()[0], $arguments, null ); - } - $melement = new MMLmsubsup(); // tbd check for more such cases like TexUtilTest 317 - $base = $this->getBase(); if ( $base instanceof Literal ) { - $litArg = trim( $this->getBase()->getArgs()[0] ); + $litArg = trim( $base->getArgs()[0] ); $tu = TexUtil::getInstance(); // "sum", "bigcap", "bigcup", "prod" ... all are nullary macros. if ( $tu->nullary_macro( $litArg ) && !$tu->is_literal( $litArg ) ) { @@ -85,13 +80,13 @@ class FQ extends TexNode { $mrow = new MMLmrow(); $emptyMrow = ""; // In cases with empty curly preceding like: "{}_1^2\!\Omega_3^4" - if ( $this->getBase() instanceof Curly && $this->getBase()->isEmpty() ) { + if ( $base->isCurly() && $base->isEmpty() ) { $emptyMrow = $mrow->getEmpty(); } // This seems to be the common case $inner = $melement->encapsulateRaw( $emptyMrow . - $this->getBase()->renderMML( [], $state ) . + $base->renderMML( [], $state ) . $mrow->encapsulateRaw( $this->getDown()->renderMML( $arguments, $state ) ) . $mrow->encapsulateRaw( $this->getUp()->renderMML( $arguments, $state ) ) ); diff --git a/src/WikiTexVC/Nodes/TexArray.php b/src/WikiTexVC/Nodes/TexArray.php index 4a95ec38a..c05ad8360 100644 --- a/src/WikiTexVC/Nodes/TexArray.php +++ b/src/WikiTexVC/Nodes/TexArray.php @@ -9,11 +9,19 @@ use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\BaseMappings; use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLParsingUtil; use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLutil; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmo; +use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmstyle; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsup; use MediaWiki\Extension\Math\WikiTexVC\TexUtil; class TexArray extends TexNode { + protected bool $curly = false; + + public static function newCurly( ...$args ) { + $node = new self( ...$args ); + $node->curly = true; + return $node; + } public function __construct( ...$args ) { $nargs = []; @@ -246,10 +254,10 @@ class TexArray extends TexNode { if ( $styleArguments ) { $state["styleargs"] = $styleArguments; - if ( $next instanceof Curly ) { + $mmlStyle = new MMLmstyle( "", $styleArguments ); + $fullRenderedArray .= $mmlStyle->getStart(); + if ( $next->isCurly() ) { // Wrap with style-tags when the next element is a Curly which determines start and end tag. - $mmlStyle = new MMLmstyle( "", $styleArguments ); - $fullRenderedArray .= $mmlStyle->getStart(); $fullRenderedArray .= $this->createMMLwithContext( $currentColor, $next, $state, $arguments ); $fullRenderedArray .= $mmlStyle->getEnd(); $mmlStyle = null; @@ -257,8 +265,6 @@ class TexArray extends TexNode { $i++; } else { // Start the style indicator in cases like \textstyle abc - $mmlStyle = new MMLmstyle( "", $styleArguments ); - $fullRenderedArray .= $mmlStyle->getStart(); $mmlStyles[] = $mmlStyle->getEnd(); } @@ -280,6 +286,10 @@ class TexArray extends TexNode { foreach ( array_reverse( $mmlStyles ) as $mmlStyleEnd ) { $fullRenderedArray .= $mmlStyleEnd; } + if ( $this->curly && count( $this->getArgs() ) > 1 ) { + $mmlRow = new MMLmrow(); + return $mmlRow->encapsulateRaw( $fullRenderedArray ); + } return $fullRenderedArray; } @@ -340,7 +350,7 @@ class TexArray extends TexNode { if ( isset( $this->args[0] ) && count( $this->args ) == 1 ) { return $this->args[0]->inCurlies(); } else { - return '{' . $this->render() . '}'; + return '{' . parent::render() . '}'; } } @@ -455,4 +465,15 @@ class TexArray extends TexNode { } } + public function render() { + if ( $this->curly ) { + return $this->inCurlies(); + } + return parent::render(); + } + + public function isCurly(): bool { + return $this->curly; + } + } diff --git a/src/WikiTexVC/Nodes/TexNode.php b/src/WikiTexVC/Nodes/TexNode.php index ed3c9b506..3bb1962b5 100644 --- a/src/WikiTexVC/Nodes/TexNode.php +++ b/src/WikiTexVC/Nodes/TexNode.php @@ -204,4 +204,9 @@ class TexNode { return false; } + + public function isCurly(): bool { + return false; + } + } diff --git a/src/WikiTexVC/Parser.php b/src/WikiTexVC/Parser.php index 998d3c15b..35e918fa0 100644 --- a/src/WikiTexVC/Parser.php +++ b/src/WikiTexVC/Parser.php @@ -11,7 +11,6 @@ use MediaWiki\Extension\Math\WikiTexVC\Nodes\Box; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Big; use MediaWiki\Extension\Math\WikiTexVC\Nodes\ChemFun2u; use MediaWiki\Extension\Math\WikiTexVC\Nodes\ChemWord; -use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Declh; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Dollar; use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; @@ -462,14 +461,14 @@ class Parser { private function peg_f26($b, $r) { return new Big($b, $r); } private function peg_f27($b) { return new Big($b, "]"); } private function peg_f28($l, $e, $r) {return new Lr($l, $r, ParserUtil::lst2arr($e)); } - private function peg_f29($name, $e, $l) { return new Fun2sq($name, new Curly(ParserUtil::lst2arr($e)), $l); } + private function peg_f29($name, $e, $l) { return new Fun2sq($name, ParserUtil::lst2arr($e, true), $l); } private function peg_f30($name, $l) { return new Fun1($name, $l); } private function peg_f31($name, $l) {return new Fun1nb($name, $l); } private function peg_f32($name, $l) { return new Mhchem($name, $l); } private function peg_f33($name, $l1, $l2) { return new Fun2($name, $l1, $l2); } private function peg_f34($name, $l1, $l2, $l3, $l4) { return new Fun4($name, $l1, $l2, $l3, $l4); } private function peg_f35($name, $l1, $l2) { return new Fun2nb($name, $l1, $l2); } - private function peg_f36($e) { return new Curly(ParserUtil::lst2arr($e)); } + private function peg_f36($e) { return ParserUtil::lst2arr($e, true); } private function peg_f37($e1, $name, $e2) { return new Infix($name, ParserUtil::lst2arr($e1), ParserUtil::lst2arr($e2)); } private function peg_f38($m) { return new Matrix("matrix", ParserUtil::lst2arr($m)); } private function peg_f39($m) { return new Matrix("pmatrix", ParserUtil::lst2arr($m)); } @@ -504,8 +503,8 @@ class Parser { private function peg_f57($e, $l) { return $l; } private function peg_f58($e, $tail) { return new TexArray($e, $tail); } private function peg_f59() { return $this->text(); } - private function peg_f60($cs) { return new Curly(new TexArray(new Literal($cs))); } - private function peg_f61($num) { return new Curly(new TexArray(new Literal($num))); } + private function peg_f60($cs) { return TexArray::newCurly(new Literal($cs)); } + private function peg_f61($num) { return TexArray::newCurly(new Literal($num)); } private function peg_f62($p, $s) { return new TexArray($p,new TexArray(new Literal(" "),$s)); } private function peg_f63($p) { return new TexArray($p,new TexArray()); } private function peg_f64($m) { return new Literal($m); } @@ -516,9 +515,9 @@ class Parser { private function peg_f69() { return new Literal(""); } private function peg_f70($m) { return $m;} private function peg_f71($c) { return new Literal($c); } - private function peg_f72($c) { return new Curly(new TexArray($c)); } + private function peg_f72($c) { return TexArray::newCurly($c); } private function peg_f73($c) { return new Dollar(ParserUtil::lst2arr($c)); } - private function peg_f74($e) { return new Curly(new TexArray(new Literal($e))); } + private function peg_f74($e) { return TexArray::newCurly(new Literal($e)); } private function peg_f75($a, $b) { return new ChemWord(new Literal($a), new Literal($b)); } private function peg_f76($a, $b) { return new ChemWord(new Literal($a), $b); } private function peg_f77($a, $b) { return new ChemWord(new Literal($a), new Dollar(ParserUtil::lst2arr($b))); } diff --git a/src/WikiTexVC/ParserUtil.php b/src/WikiTexVC/ParserUtil.php index 919e3424f..12c1b74e0 100644 --- a/src/WikiTexVC/ParserUtil.php +++ b/src/WikiTexVC/ParserUtil.php @@ -10,10 +10,11 @@ class ParserUtil { /** * @param TexArray|null $l + * @param bool $curly * @return TexArray */ - public static function lst2arr( $l ) { - $arr = new TexArray(); + public static function lst2arr( $l, $curly = false ) { + $arr = $curly ? TexArray::newCurly() : new TexArray(); while ( $l !== null ) { $first = $l->first(); diff --git a/src/WikiTexVC/parser.pegjs b/src/WikiTexVC/parser.pegjs index c867bd94c..e5f5eac5c 100644 --- a/src/WikiTexVC/parser.pegjs +++ b/src/WikiTexVC/parser.pegjs @@ -143,7 +143,7 @@ lit / b:BIG SQ_CLOSE { return new Big($b, "]"); } / l:left e:expr r:right {return new Lr($l, $r, ParserUtil::lst2arr($e)); } / name:FUN_AR1opt e:expr_nosqc SQ_CLOSE l:lit /* must be before FUN_AR1 */ - { return new Fun2sq($name, new Curly(ParserUtil::lst2arr($e)), $l); } + { return new Fun2sq($name, ParserUtil::lst2arr($e, true), $l); } / name:FUN_AR1 l:lit { return new Fun1($name, $l); } / name:FUN_AR1nb l:lit {return new Fun1nb($name, $l); } / name:FUN_MHCHEM l:chem_lit { return new Mhchem($name, $l); } @@ -152,7 +152,7 @@ lit / name:FUN_AR2nb l1:lit l2:lit { return new Fun2nb($name, $l1, $l2); } / BOX / CURLY_OPEN e:expr CURLY_CLOSE - { return new Curly(ParserUtil::lst2arr($e)); } + { return ParserUtil::lst2arr($e, true); } / CURLY_OPEN e1:ne_expr name:FUN_INFIX e2:ne_expr CURLY_CLOSE { return new Infix($name, ParserUtil::lst2arr($e1), ParserUtil::lst2arr($e2)); } / BEGIN_MATRIX m:(array/matrix) END_MATRIX @@ -222,7 +222,7 @@ line column_spec = CURLY_OPEN cs:(one_col+ { return $this->text(); }) CURLY_CLOSE - { return new Curly(new TexArray(new Literal($cs))); } + { return TexArray::newCurly(new Literal($cs)); } one_col = [lrc] _ @@ -237,7 +237,7 @@ one_col alignat_spec = CURLY_OPEN num:([0-9]+ { return $this->text(); }) _ CURLY_CLOSE - { return new Curly(new TexArray(new Literal($num))); } + { return TexArray::newCurly(new Literal($num)); } opt_pos = "[" _ [tcb] _ "]" _ @@ -249,7 +249,7 @@ opt_pos chem_lit - = CURLY_OPEN e:chem_sentence CURLY_CLOSE { return new Curly(ParserUtil::lst2arr($e)); } + = CURLY_OPEN e:chem_sentence CURLY_CLOSE { return ParserUtil::lst2arr($e, true); } chem_sentence = _ p:chem_phrase " " s:chem_sentence { return new TexArray($p,new TexArray(new Literal(" "),$s)); } / @@ -275,14 +275,14 @@ chem_char = chem_char_nl = m:chem_script { return $m;} / - CURLY_OPEN c:chem_text CURLY_CLOSE { return new Curly(new TexArray($c)); } / + CURLY_OPEN c:chem_text CURLY_CLOSE { return TexArray::newCurly($c); } / BEGIN_MATH c:expr END_MATH { return new Dollar(ParserUtil::lst2arr($c)); }/ name:CHEM_BONDI l:chem_bond { return new Fun1($name, $l); } / m:chem_macro { return $m; } / c:CHEM_NONLETTER { return new Literal($c); } chem_bond - = CURLY_OPEN e:CHEM_BOND_TYPE CURLY_CLOSE { return new Curly(new TexArray(new Literal($e))); } + = CURLY_OPEN e:CHEM_BOND_TYPE CURLY_CLOSE { return TexArray::newCurly(new Literal($e)); } chem_script = a:CHEM_SUPERSUB b:CHEM_SCRIPT_FOLLOW { return new ChemWord(new Literal($a), new Literal($b)); } / diff --git a/tests/phpunit/unit/WikiTexVC/Nodes/CurlyTest.php b/tests/phpunit/unit/WikiTexVC/Nodes/CurlyTest.php index ca6b1e44f..4ea8da228 100644 --- a/tests/phpunit/unit/WikiTexVC/Nodes/CurlyTest.php +++ b/tests/phpunit/unit/WikiTexVC/Nodes/CurlyTest.php @@ -2,77 +2,53 @@ namespace MediaWiki\Extension\Math\Tests\WikiTexVC\Nodes; -use ArgumentCountError; -use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal; use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray; -use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode; use MediaWikiUnitTestCase; -use RuntimeException; -use TypeError; /** - * @covers \MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly + * @covers \MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray */ class CurlyTest extends MediaWikiUnitTestCase { - public function testEmptyDollar() { - $this->expectException( ArgumentCountError::class ); - new Curly(); - throw new ArgumentCountError( 'Should not create an empty curly' ); - } - - public function testOneArgumentCurly() { - $this->expectException( ArgumentCountError::class ); - new Curly( new TexArray( new TexNode( 'a' ) ), new TexArray( new TexNode( 'b' ) ) ); - throw new ArgumentCountError( 'Should not create a curly with more than one argument' ); - } - - public function testIncorrectTypeCurly() { - $this->expectException( TypeError::class ); - new Curly( new TexNode() ); - throw new RuntimeException( 'Should not create a curly with incorrect type' ); - } - public function testRenderTexCurly() { - $curly = new Curly( new TexArray() ); + $curly = TexArray::newCurly(); $this->assertEquals( '{}', $curly->render(), 'Should render a curly with empty tex array' ); } public function testRenderListCurly() { - $curly = new Curly( new TexArray( - new Literal( 'hello' ), - new Literal( ' ' ), - new Literal( 'world' ) - ) ); + $curly = TexArray::newCurly( + new Literal( 'hello' ), + new Literal( ' ' ), + new Literal( 'world' ) + ); $this->assertEquals( '{hello world}', $curly->render(), 'Should render a list' ); } public function testGetters() { - $curly = new Curly( new TexArray( new Literal( 'b' ) ) ); + $curly = TexArray::newCurly( new Literal( 'b' ) ); $this->assertNotEmpty( $curly->getArgs() ); - $this->assertNotEmpty( $curly->getArg() ); } public function testNoExtraCurliesDQ() { $dq = new DQ( new Literal( 'a' ), - new Curly( new TexArray( new Literal( 'b' ) ) ) ); + TexArray::newCurly( new Literal( 'b' ) ) ); $this->assertEquals( 'a_{b}', $dq->render(), 'Should not create extra curlies from dq' ); } public function testNoExtraCurliesCurly() { - $curly = new Curly( new TexArray( new Literal( 'a' ) ) ); + $curly = TexArray::newCurly( new Literal( 'a' ) ); $this->assertEquals( '{a}', $curly->inCurlies(), 'Should not create extra curlies from curly' ); } public function testExtractIdentifierModsCurly() { - $curly = new Curly( new TexArray( new Literal( 'b' ) ) ); + $curly = TexArray::newCurly( new Literal( 'b' ) ); $this->assertEquals( 'b', $curly->getModIdent(), 'Should extract identifier modifications' ); } public function testExtractSubscirpts() { - $curly = new Curly( new TexArray( new Literal( 'b' ) ) ); + $curly = TexArray::newCurly( new Literal( 'b' ) ); $this->assertEquals( 'b', $curly->extractSubscripts(), 'Should extract subscripts' ); } } diff --git a/tests/phpunit/unit/WikiTexVC/Nodes/DQTest.php b/tests/phpunit/unit/WikiTexVC/Nodes/DQTest.php index 2ea0b100f..e2a4c4bd8 100644 --- a/tests/phpunit/unit/WikiTexVC/Nodes/DQTest.php +++ b/tests/phpunit/unit/WikiTexVC/Nodes/DQTest.php @@ -4,7 +4,6 @@ namespace MediaWiki\Extension\Math\Tests\WikiTexVC\Nodes; use ArgumentCountError; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow; -use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal; use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray; @@ -53,7 +52,7 @@ class DQTest extends MediaWikiUnitTestCase { } public function testRenderEmptyDq() { - $dq = new DQ( new Curly( new TexArray() ), new Literal( 'b' ) ); + $dq = new DQ( TexArray::newCurly(), new Literal( 'b' ) ); $this->assertStringContainsString( ( new MMLmrow() )->getEmpty(), $dq->renderMML() ); } diff --git a/tests/phpunit/unit/WikiTexVC/Nodes/FQTest.php b/tests/phpunit/unit/WikiTexVC/Nodes/FQTest.php index 4774a31fa..232171274 100644 --- a/tests/phpunit/unit/WikiTexVC/Nodes/FQTest.php +++ b/tests/phpunit/unit/WikiTexVC/Nodes/FQTest.php @@ -4,7 +4,6 @@ namespace MediaWiki\Extension\Math\Tests\WikiTexVC\Nodes; use ArgumentCountError; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow; -use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; use MediaWiki\Extension\Math\WikiTexVC\Nodes\FQ; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal; use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray; @@ -47,8 +46,10 @@ class FQTest extends MediaWikiUnitTestCase { } public function testRenderEmptyFq() { - $fq = new FQ( new Curly( new TexArray() ), new Literal( 'b' ), new Literal( 'c' ) ); - $this->assertStringContainsString( ( new MMLmrow() )->getEmpty(), $fq->renderMML() ); + $fq = new FQ( TexArray::newCurly(), new Literal( 'b' ), new Literal( 'c' ) ); + $result = $fq->renderMML(); + $this->assertStringContainsString( 'msubsup', $result ); + $this->assertStringContainsString( ( new MMLmrow() )->getEmpty(), $result ); } public function testLatin() { diff --git a/tests/phpunit/unit/WikiTexVC/Nodes/Fun1Test.php b/tests/phpunit/unit/WikiTexVC/Nodes/Fun1Test.php index 2eb189f98..0cd7f44d7 100644 --- a/tests/phpunit/unit/WikiTexVC/Nodes/Fun1Test.php +++ b/tests/phpunit/unit/WikiTexVC/Nodes/Fun1Test.php @@ -3,7 +3,6 @@ namespace MediaWiki\Extension\Math\Tests\WikiTexVC\Nodes; use ArgumentCountError; -use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; use MediaWiki\Extension\Math\WikiTexVC\Nodes\FQ; use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun1; @@ -108,28 +107,28 @@ class Fun1Test extends MediaWikiUnitTestCase { } public function testMathRmCurly() { - $f = new Fun1( '\\mathrm', new Curly( new TexArray( + $f = new Fun1( '\\mathrm', TexArray::newCurly( new Literal( 'a' ), new Literal( 'b' ), - ) ) ); + ) ); $rendering = $f->renderMML(); preg_match_all( '/mathvariant="normal"/', $rendering, $matches ); $this->assertCount( 2, $matches[0] ); } public function testMathRmDq() { - $f = new Fun1( '\\mathrm', new Curly( new TexArray( + $f = new Fun1( '\\mathrm', TexArray::newCurly( new DQ( new Literal( 'a' ), new Literal( 'b' ) ) - ) ) ); + ) ); $rendering = $f->renderMML(); preg_match_all( '/mathvariant="normal"/', $rendering, $matches ); $this->assertCount( 2, $matches[0] ); } public function testMathRmFq() { - $f = new Fun1( '\\mathrm', new Curly( new TexArray( + $f = new Fun1( '\\mathrm', TexArray::newCurly( new FQ( new Literal( 'a' ), new Literal( 'b' ), new Literal( 'c' ) ) - ) ) ); + ) ); $rendering = $f->renderMML(); preg_match_all( '/mathvariant="normal"/', $rendering, $matches ); $this->assertCount( 2, $matches[0] );