Merge pull request #294 from FSMaxB/totex

Update toTex to better handle parenthesis
This commit is contained in:
Jos de Jong 2015-03-01 19:08:52 +00:00
commit ed47c7fa35
7 changed files with 102 additions and 105 deletions

View File

@ -92,12 +92,24 @@ AssignmentNode.prototype.toString = function() {
* @return {String}
*/
AssignmentNode.prototype.toTex = function() {
var precedence = operators.getPrecedence(this);
var exprPrecedence = operators.getPrecedence(this.expr);
var expr = this.expr.toTex();
if ((exprPrecedence !== null) && (exprPrecedence <= precedence)) {
//adds visible round brackets
expr = latex.addBraces(expr, true);
}
else {
//adds (invisible) curly braces
expr = latex.addBraces(expr, false);
}
var brace;
if (this.expr instanceof ArrayNode) {
brace = ['\\mathbf{', '}'];
}
return latex.addBraces(latex.toSymbol(this.name), brace) + '=' +
latex.addBraces(this.expr.toTex());
return latex.addBraces(latex.toSymbol(this.name), brace) + '=' + expr;
};
module.exports = AssignmentNode;
module.exports = AssignmentNode;

View File

@ -113,9 +113,22 @@ FunctionAssignmentNode.prototype.toString = function() {
* @return {String} str
*/
FunctionAssignmentNode.prototype.toTex = function() {
return this.name +
latex.addBraces(this.params.map(latex.toSymbol).join(', '), true) + '=' +
latex.addBraces(this.expr.toTex());
var precedence = operators.getPrecedence(this);
var exprPrecedence = operators.getPrecedence(this.expr);
var expr = this.expr.toTex();
if ((exprPrecedence !== null) && (exprPrecedence <= precedence)) {
//adds visible round brackets
expr = latex.addBraces(expr, true);
}
else {
//add (invisible) curly braces
expr = latex.addBraces(expr, false);
}
return latex.toFunction(this.name)
+ latex.addBraces(this.params.map(latex.toSymbol).join(', '), true) + '='
+ expr;
};
module.exports = FunctionAssignmentNode;

View File

@ -239,98 +239,53 @@ OperatorNode.prototype.toString = function() {
* @return {String} str
*/
OperatorNode.prototype.toTex = function() {
var args = this.args,
mop = latex.toOperator(this.op),
lp = args[0],
rp = args[1];
var args = this.args;
var parens = calculateNecessaryParentheses(this, args);
var op = latex.toOperator(this.op); //operator
switch (args.length) {
case 1:
var operand = lp.toTex();
switch (this.op) {
case '-': //unary minus needs brackets around '-' and '+'
if (lp instanceof OperatorNode && (lp.op === '-' || lp.op === '+')) {
return this.op + latex.addBraces(operand, true);
}
case '+':
return this.op + operand;
break;
default: // fox example '5!'
if (lp instanceof OperatorNode) {
return latex.addBraces(operand, true) + this.op;
}
return operand + this.op;
}
switch (args.length) {
case 1: //unary operators
var assoc = operators.getAssociativity(this);
case 2: // for example '2+3'
var lhs = lp.toTex(),
lhb = false,
rhs = rp.toTex(),
rhb = false,
lop = '',
rop = '';
var operand = args[0].toTex();
if (parens[0]) {
operand = latex.addBraces(operand, true);
}
switch (this.op) {
case '/':
lop = mop;
mop = '';
if (assoc === 'right') { //prefix operator
return op + operand;
}
else if (assoc === 'left') { //postfix operator
return operand + op;
}
break;
//fall back to postfix
return operand + op;
case '*':
if (lp instanceof OperatorNode) {
if (lp.op === '+' || lp.op === '-') {
lhb = true;
}
}
case 2: //binary operators
var lhs = args[0]; //left hand side
//reminder: if parens[0] is false, this puts it in curly braces
var lhsTex = latex.addBraces(lhs.toTex(), parens[0]);
var rhs = args[1]; //right hand side
var rhsTex = latex.addBraces(rhs.toTex(), parens[1]);
if (rp instanceof OperatorNode) {
if (rp.op === '+' || rp.op === '-' || rp.op === '*') {
rhb = true;
}
}
switch (this.getIdentifier()) {
case 'OperatorNode:divide':
//op contains '\\frac' at this point
return op + lhsTex + rhsTex;
if ((lp instanceof ConstantNode || lp instanceof OperatorNode) &&
(rp instanceof ConstantNode || rp instanceof OperatorNode)) {
mop = ' \\cdot ';
}
else {
mop = ' \\, ';
}
case 'OperatorNode:to':
rhsTex = latex.toUnit(rhs.toTex());
rhsTex = latex.addBraces(rhsTex, parens[1]);
break;
}
return lhsTex + ' ' + op + ' ' + rhsTex;
break;
case '-':
if (rp instanceof OperatorNode) {
if (rp.op === '+' | rp.op === '-' ) {
rhb = true;
}
}
break;
case '^':
if (lp instanceof OperatorNode || lp instanceof FunctionNode) {
lhb = true;
}
else if (lp instanceof SymbolNode) {
lhb = null;
}
break;
case 'to':
rhs = latex.toUnit(rhs, true);
break;
}
lhs = latex.addBraces(lhs, lhb);
rhs = latex.addBraces(rhs, rhb);
return lop + lhs + mop + rhs + rop;
default: // this should not occur. format as a function call
return mop + '(' + this.args.map(latex.toSymbol).join(', ') + ')';
}
default:
//fall back to formatting as a function call
var argumentList = this.args.map(latex.toSymbol).join(', ');
return latex.toFunction(this.fn) + latex.addBraces(argumentList, true);
}
};
/**

View File

@ -216,4 +216,13 @@ describe('AssignmentNode', function() {
assert.equal(n.toTex(), '{b}={3}');
});
it ('should LaTeX an AssignmentNode containing an AssignmentNode', function () {
var a = new ConstantNode(2);
var b = new AssignmentNode('a', a);
var n = new AssignmentNode('b', b);
assert.equal(n.toTex(), '{b}=\\left({{a}={2}}\\right)');
});
});

View File

@ -195,7 +195,15 @@ describe('FunctionAssignmentNode', function() {
var p = new OperatorNode('^', 'pow', [o, a]);
var n = new FunctionAssignmentNode('f', ['x'], p);
assert.equal(n.toTex(), 'f\\left({x}\\right)={\\left({\\frac{x}{2}}\\right)^{2}}');
assert.equal(n.toTex(), 'f\\left({x}\\right)={\\left({\\frac{x}{2}}\\right) ^ {2}}');
});
it ('should LaTeX a FunctionAssignmentNode containing an AssignmentNode', function () {
var a = new ConstantNode(2);
var n1 = new AssignmentNode('a', a);
var n = new FunctionAssignmentNode('f', ['x'], n1);
assert.equal(n.toTex(), 'f\\left({x}\\right)=\\left({{a}={2}}\\right)');
});
});

View File

@ -278,7 +278,7 @@ describe('FunctionNode', function() {
var o = new OperatorNode('+', 'add', [c1, c2]);
var n3 = new FunctionNode('permutations', [o]);
assert.equal(n3.toTex(), '{\\left({4}+{5}\\right)!}');
assert.equal(n3.toTex(), '{\\left({4} + {5}\\right)!}');
});
it ('should have an identifier', function () {

View File

@ -276,7 +276,7 @@ describe('OperatorNode', function() {
var c = new ConstantNode(4);
var n = new OperatorNode('+', 'add', [a, b]);
assert.equal(n.toTex(), '{2}+{3}');
assert.equal(n.toTex(), '{2} + {3}');
});
it ('should LaTeX an OperatorNode with factorial', function () {
@ -298,8 +298,8 @@ describe('OperatorNode', function() {
var n2= new OperatorNode('!', 'factorial', [add] );
var n3= new OperatorNode('!', 'factorial', [mult] );
var n4= new OperatorNode('!', 'factorial', [div] );
assert.equal(n1.toTex(), '\\left({{2}-{3}}\\right)!');
assert.equal(n2.toTex(), '\\left({{2}+{3}}\\right)!');
assert.equal(n1.toTex(), '\\left({{2} - {3}}\\right)!');
assert.equal(n2.toTex(), '\\left({{2} + {3}}\\right)!');
assert.equal(n3.toTex(), '\\left({{2} \\cdot {3}}\\right)!');
assert.equal(n4.toTex(), '\\left({\\frac{2}{3}}\\right)!');
});
@ -316,8 +316,8 @@ describe('OperatorNode', function() {
var n3 = new OperatorNode('-', 'unaryMinus', [add]);
assert.equal(n1.toTex(), '-2');
assert.equal(n2.toTex(), '-\\left({{2}-{3}}\\right)');
assert.equal(n3.toTex(), '-\\left({{2}+{3}}\\right)');
assert.equal(n2.toTex(), '-\\left({{2} - {3}}\\right)');
assert.equal(n3.toTex(), '-\\left({{2} + {3}}\\right)');
});
it ('should LaTeX an OperatorNode that subtracts an OperatorNode', function() {
@ -331,13 +331,13 @@ describe('OperatorNode', function() {
var n1 = new OperatorNode('-', 'subtract', [a, sub]);
var n2 = new OperatorNode('-', 'subtract', [a, add]);
assert.equal(n1.toTex(), '{1}-\\left({{2}-{3}}\\right)');
assert.equal(n2.toTex(), '{1}-\\left({{2}+{3}}\\right)');
assert.equal(n1.toTex(), '{1} - \\left({{2} - {3}}\\right)');
assert.equal(n2.toTex(), '{1} - \\left({{2} + {3}}\\right)');
});
it ('should LaTeX an OperatorNode with zero arguments', function () {
var n = new OperatorNode('foo', 'foo', []);
assert.equal(n.toTex(), 'foo()');
assert.equal(n.toTex(), 'foo\\left({}\\right)');
});
it ('should LaTeX an OperatorNode with more than two operators', function () {
@ -346,7 +346,7 @@ describe('OperatorNode', function() {
var c = new ConstantNode(4);
var n = new OperatorNode('foo', 'foo', [a, b, c]);
assert.equal(n.toTex(), 'foo(2, 3, 4)');
assert.equal(n.toTex(), 'foo\\left({2, 3, 4}\\right)');
});
@ -363,10 +363,10 @@ describe('OperatorNode', function() {
var m2 = new OperatorNode('*', 'multiply', [n1, c]);
var m3 = new OperatorNode('-', 'subtract', [m2, d]);
assert.equal(n1.toTex(), '{2}+{3}');
assert.equal(n2.toTex(), '{4}-{5}');
assert.equal(n3.toTex(), '\\left({{2}+{3}}\\right) \\cdot \\left({{4}-{5}}\\right)');
assert.equal(m3.toTex(), '{\\left({{2}+{3}}\\right) \\cdot {4}}-{5}');
assert.equal(n1.toTex(), '{2} + {3}');
assert.equal(n2.toTex(), '{4} - {5}');
assert.equal(n3.toTex(), '\\left({{2} + {3}}\\right) \\cdot \\left({{4} - {5}}\\right)');
assert.equal(m3.toTex(), '{\\left({{2} + {3}}\\right) \\cdot {4}} - {5}');
});
it ('should have an identifier', function () {