diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ad83485ef..8a347305b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - axis limits recalculate with `hggroup`. - `axes` forces focus on current axe. +- function_handle parenthese precedence. ## 0.7.10 (2023-10-27) diff --git a/modules/function_handle/tests/test_function_anonymous.m b/modules/function_handle/tests/test_function_anonymous.m index 3d7fbe70e4..b3262d164d 100644 --- a/modules/function_handle/tests/test_function_anonymous.m +++ b/modules/function_handle/tests/test_function_anonymous.m @@ -89,7 +89,7 @@ %============================================================================= F = @(c) (integral(@(x) (x .^ 2 + c*x + 1),0,1)); R = func2str(F); -REF = '@(c)integral(@(x)x.^2+c*x+1,0,1)'; +REF = '@(c)integral(@(x)(((x.^2)+(c*x))+1),0,1)'; assert_isequal(R, REF); %============================================================================= myfunction = @(x,y) (x^2 + y^2 + x*y); @@ -101,6 +101,6 @@ %============================================================================= F = @(x,y) ndgrid((-x:x/c:x),(-y:y/c:y)); R = func2str(F); -REF = '@(x,y)ndgrid(-x:x/c:x,-y:y/c:y)'; +REF = '@(x,y)ndgrid(-x:(x/c):x,-y:(y/c):y)'; assert_isequal(R, REF); %============================================================================= diff --git a/modules/function_handle/tests/test_str2func.m b/modules/function_handle/tests/test_str2func.m index 010e85c5f9..b1bcbeb342 100644 --- a/modules/function_handle/tests/test_str2func.m +++ b/modules/function_handle/tests/test_str2func.m @@ -55,7 +55,8 @@ str = '@(x)7*x-13'; fh = str2func(str); R = func2str(fh); -assert_isequal(R, str) +REF = '@(x)(7*x)-13' +assert_isequal(R, REF) assert_isequal(fh(3), 8) %============================================================================= str = '@(x)7*x-13+a'; diff --git a/modules/hdf5/tests/test_savenh5_function_handle.m b/modules/hdf5/tests/test_savenh5_function_handle.m index 2911029ffe..b1b5dac08c 100644 --- a/modules/hdf5/tests/test_savenh5_function_handle.m +++ b/modules/hdf5/tests/test_savenh5_function_handle.m @@ -15,7 +15,7 @@ %============================================================================= A = 1; B = 2; -C = @(x) x + A + B; +C = @(x) (x + A) + B; %============================================================================= savenh5(test_h5save_file, 'C'); R = h5readatt(test_h5save_file, '/C', 'NELSON_class'); @@ -27,7 +27,7 @@ R = h5read(test_h5save_file, '/C/is_function_handle'); assert_isequal(R, uint8(0)); R = h5read(test_h5save_file, '/C/function_handle'); -assert_isequal(char(R), 'x+A+B'); +assert_isequal(char(R), '(x+A)+B'); R = h5read(test_h5save_file, '/C/arguments/0'); assert_isequal(char(R), 'x'); %============================================================================= diff --git a/modules/interpreter/src/cpp/AbstractSyntaxTreeHelpers.cpp b/modules/interpreter/src/cpp/AbstractSyntaxTreeHelpers.cpp index ed8250a712..7db72a88d4 100644 --- a/modules/interpreter/src/cpp/AbstractSyntaxTreeHelpers.cpp +++ b/modules/interpreter/src/cpp/AbstractSyntaxTreeHelpers.cpp @@ -25,7 +25,7 @@ static std::unordered_map keywords = { { NLS_KEYWORD_BREAK, "b { NLS_KEYWORD_ENDFUNCTION, "endfunction" } }; //============================================================================= static std::string -expression(AbstractSyntaxTreePtr expr) +expression(AbstractSyntaxTreePtr expr, bool firstLevel) { if (expr == nullptr) { return ""; @@ -37,9 +37,9 @@ expression(AbstractSyntaxTreePtr expr) switch (expr->type) { case id_node: { if (expr->down) { - res = expr->text + expression(expr->down); + res = expr->text + expression(expr->down, false); } else { - res = expr->text + expression(expr->right); + res = expr->text + expression(expr->right, false); } } break; case const_character_array_node: { @@ -75,24 +75,25 @@ expression(AbstractSyntaxTreePtr expr) switch (expr->opNum) { case OP_COLON: { if ((expr->down != nullptr) && (expr->down->opNum == (OP_COLON))) { - res = expression(expr->down->down) + ":" + expression(expr->down->down->right) + ":" - + expression(expr->down->right); + res = expression(expr->down->down, false) + ":" + + expression(expr->down->down->right, false) + ":" + + expression(expr->down->right, false); } else { - res = expression(expr->down) + ":" + expression(expr->down->right); + res = expression(expr->down, false) + ":" + expression(expr->down->right, false); } } break; case OP_SEMICOLON: { if (expr->right != nullptr) { - std::string left = expression(expr->down); - std::string right = expression(expr->right); + std::string left = expression(expr->down, false); + std::string right = expression(expr->right, false); if (right.empty()) { res = left; } else { res = left + ";" + right; } } else { - std::string left = expression(expr->down); - std::string right = expression(expr->down->right); + std::string left = expression(expr->down, false); + std::string right = expression(expr->down->right, false); if (right.empty()) { res = left; } else { @@ -107,16 +108,16 @@ expression(AbstractSyntaxTreePtr expr) res = "{}"; } break; case OP_BRACKETS: { - res = "[" + expression(expr->down) + "]"; + res = "[" + expression(expr->down, false) + "]"; } break; case OP_BRACES: { - res = "{" + expression(expr->down) + "}"; + res = "{" + expression(expr->down, false) + "}"; } break; case OP_PARENS: { res = "("; expr = expr->down; while (expr != nullptr) { - res = res + expression(expr) + ","; + res = res + expression(expr, false) + ","; expr = expr->right; } if (StringHelpers::ends_with(res, ",")) { @@ -125,82 +126,142 @@ expression(AbstractSyntaxTreePtr expr) res = res + ")"; } break; case OP_PLUS: { - res = expression(expr->down) + "+" + expression(expr->down->right); + res = expression(expr->down, false) + "+" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_SUBTRACT: { - res = expression(expr->down) + "-" + expression(expr->down->right); + res = expression(expr->down, false) + "-" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_TIMES: { - res = expression(expr->down) + "*" + expression(expr->down->right); + res = expression(expr->down, false) + "*" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_SOR: { - res = expression(expr->down) + "||" + expression(expr->down->right); + res = expression(expr->down, false) + "||" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_OR: { - res = expression(expr->down) + "|" + expression(expr->down->right); + res = expression(expr->down, false) + "|" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_SAND: { - res = expression(expr->down) + "&&" + expression(expr->down->right); + res = expression(expr->down, false) + "&&" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_AND: { - res = expression(expr->down) + "&" + expression(expr->down->right); + res = expression(expr->down, false) + "&" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_LT: { - res = expression(expr->down) + "<" + expression(expr->down->right); + res = expression(expr->down, false) + "<" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_LEQ: { - res = expression(expr->down) + "<=" + expression(expr->down->right); + res = expression(expr->down, false) + "<=" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_GT: { - res = expression(expr->down) + ">" + expression(expr->down->right); + res = expression(expr->down, false) + ">" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_GEQ: { - res = expression(expr->down) + ">=" + expression(expr->down->right); + res = expression(expr->down, false) + ">=" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_EQ: { - res = expression(expr->down) + "==" + expression(expr->down->right); + res = expression(expr->down, false) + "==" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_NEQ: { - res = expression(expr->down) + "~=" + expression(expr->down->right); + res = expression(expr->down, false) + "~=" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_DOT_TIMES: { - res = expression(expr->down) + ".*" + expression(expr->down->right); + res = expression(expr->down, false) + ".*" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_UPLUS: { - res = "+" + expression(expr->down); + res = "+" + expression(expr->down, false); } break; case OP_UMINUS: { - res = "-" + expression(expr->down); + res = "-" + expression(expr->down, false); } break; case OP_NOT: { - res = "~" + expression(expr->down); + res = "~" + expression(expr->down, false); } break; case OP_TRANSPOSE: { - res = expression(expr->down) + "'"; + res = expression(expr->down, false) + "'"; } break; case OP_DOT_TRANSPOSE: { - res = expression(expr->down) + ".'"; + res = expression(expr->down, false) + ".'"; } break; case OP_RHS: { - res = expression(expr->down); + res = expression(expr->down, false); } break; case OP_RDIV: { - res = expression(expr->down) + "/" + expression(expr->down->right); + res = expression(expr->down, false) + "/" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_LDIV: { - res = expression(expr->down) + "\\" + expression(expr->down->right); + res = expression(expr->down, false) + "\\" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_DOT_RDIV: { - res = expression(expr->down) + "./" + expression(expr->down->right); + res = expression(expr->down, false) + "./" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_DOT_LDIV: { - res = expression(expr->down) + ".\\" + expression(expr->down->right); + res = expression(expr->down, false) + ".\\" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_POWER: { - res = expression(expr->down) + ".^" + expression(expr->down->right); + res = expression(expr->down, false) + ".^" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_MPOWER: { - res = expression(expr->down) + "^" + expression(expr->down->right); + res = expression(expr->down, false) + "^" + expression(expr->down->right, false); + if (!firstLevel) { + res = "(" + res + ")"; + } } break; case OP_FUNCTION_HANDLE_ANONYMOUS: { res = "@("; @@ -219,7 +280,7 @@ expression(AbstractSyntaxTreePtr expr) } res = res + ")"; } - res = res + expression(expr); + res = res + expression(expr, false); } break; case OP_FUNCTION_HANDLE_NAMED: { res = res + "@"; @@ -235,8 +296,8 @@ expression(AbstractSyntaxTreePtr expr) std::string AbstractSyntaxTree::toString() { - return expression(this); + return expression(this, true); } //============================================================================= } // namespace Nelson - //============================================================================= +//=============================================================================