Skip to content

Commit

Permalink
'end' magic keyword can be overloaded for classes (applied to table
Browse files Browse the repository at this point in the history
… class) (#1254)
  • Loading branch information
Nelson-numerical-software authored Oct 8, 2024
1 parent 658eae5 commit 71de8ae
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `end` magic keyword can be overloaded for classes (applied to `table` class).

- [#1250](http://github.com/nelson-lang/nelson/issues/1250) `head`, `tail` functions for table and array.

## 1.8.0 (2024-10-04)
Expand Down
46 changes: 42 additions & 4 deletions modules/interpreter/src/cpp/Evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,52 @@ Evaluator::EndReference(const ArrayOf& v, indexType index, size_t count)
{
Dimensions dim(v.getDimensions());
ArrayOf res;
if (count == 1) {
res = ArrayOf::doubleConstructor(static_cast<double>(dim.getElementCount()));
} else {
res = ArrayOf::doubleConstructor(static_cast<double>(dim.getDimensionLength(index)));
bool useStandardMethod = true;
if (v.isClassType()) {
bool needToBeOverloaded = false;
res = EndOverloadReference(v, index, count, needToBeOverloaded);
useStandardMethod = needToBeOverloaded;
if (useStandardMethod) {
Warning(L"Nelson:End:Overloading:missing", _W("numel and size need to be overloaded."));
}
}
if (useStandardMethod) {
if (count == 1) {
return ArrayOf::doubleConstructor(static_cast<double>(dim.getElementCount()));
}
return ArrayOf::doubleConstructor(static_cast<double>(dim.getDimensionLength(index)));
}
return res;
}
//=============================================================================
ArrayOf
Evaluator::EndOverloadReference(
const ArrayOf& v, indexType index, size_t count, bool& needToBeOverloaded)
{
std::string currentClass;
ClassName(v, currentClass);
std::string functionNameEndClass = getOverloadFunctionName(currentClass, "end");
Context* _context = this->getContext();
FunctionDef* funcDef = nullptr;
_context->lookupFunction(functionNameEndClass, funcDef);
if (funcDef) {
ArrayOfVector input;
input << v;
input << ArrayOf::doubleConstructor((double)index + 1);
input << ArrayOf::doubleConstructor((double)count);
int nLhs = 1;
CallStack backupCallStack = callstack;
ArrayOfVector res = funcDef->evaluateFunction(this, input, nLhs);
callstack = backupCallStack;
if (res.size() == 1) {
needToBeOverloaded = false;
return res[0];
}
}
needToBeOverloaded = true;
return {};
}
//=============================================================================
static bool
approximatelyEqual(double a, double b, double epsilon)
{
Expand Down
57 changes: 41 additions & 16 deletions modules/interpreter/src/cpp/MacroFunctionDef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <fmt/printf.h>
#include <fmt/format.h>
#include <fmt/xchar.h>
#include <regex>
#include "MacroFunctionDef.hpp"
#include "Context.hpp"
#include "FileParser.hpp"
Expand All @@ -29,6 +30,7 @@
#include "i18n.hpp"
#include "PredefinedErrorMessages.hpp"
#include "OverloadHelpers.hpp"
#include "StringHelpers.hpp"
//=============================================================================
namespace Nelson {
//=============================================================================
Expand Down Expand Up @@ -422,24 +424,47 @@ MacroFunctionDef::updateCode()
ParserState pstate = ParserState::ParseError;
AbstractSyntaxTree::clearReferences();
AbstractSyntaxTreePtrVector ptAstCode;
try {
pstate = parseFile(fr, wstring_to_utf8(this->getFilename()));
ptAstCode = AbstractSyntaxTree::getReferences();
} catch (const Exception&) {
AbstractSyntaxTree::deleteReferences();

if (this->isOverload() && StringHelpers::ends_with(this->getFilename(), L"/end.m")) {

std::string fileContent;
char buffer[4096];

while (fgets(buffer, sizeof(buffer), fr)) {
fileContent += buffer;
}
fclose(fr);

std::regex pattern(R"(\s*=\s*end\s*\()");
fileContent = std::regex_replace(fileContent, pattern, " = endmagic(");

try {
pstate = parseString(fileContent);
ptAstCode = AbstractSyntaxTree::getReferences();
} catch (const Exception&) {
AbstractSyntaxTree::deleteReferences();
throw;
}
} else {
try {
pstate = parseFile(fr, wstring_to_utf8(this->getFilename()));
ptAstCode = AbstractSyntaxTree::getReferences();
} catch (const Exception&) {
AbstractSyntaxTree::deleteReferences();
if (fr != nullptr) {
fclose(fr);
}
throw;
}
if (fr != nullptr) {
fclose(fr);
}
throw;
}
if (fr != nullptr) {
fclose(fr);
}
if (pstate == ParserState::ParseError) {
AbstractSyntaxTree::deleteReferences(ptAstCode);
AbstractSyntaxTree::clearReferences();
Error(_W("a valid function definition expected.") + std::wstring(L"\n")
+ this->getFilename());
if (pstate == ParserState::ParseError) {
AbstractSyntaxTree::deleteReferences(ptAstCode);
AbstractSyntaxTree::clearReferences();
Error(_W("a valid function definition expected.") + std::wstring(L"\n")
+ this->getFilename());
}
}
try {
if (pstate == ParserState::FuncDef) {
Expand Down Expand Up @@ -503,7 +528,7 @@ MacroFunctionDef::updateCode()
this->setName(functionNameFromFile);
}
}
if (this->getName() != functionNameFromFile) {
if ((this->getName() != functionNameFromFile) && (functionNameFromFile != "end")) {
std::string name = this->getName();
std::string msg = fmt::sprintf(_("Filename and function name are not same (%s vs %s)."),
name, functionNameFromFile);
Expand Down
3 changes: 3 additions & 0 deletions modules/interpreter/src/include/Evaluator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,9 @@ class NLSINTERPRETER_IMPEXP Evaluator
getHandle(ArrayOf r, const std::string& fieldname, const ArrayOfVector& params);
ArrayOf
EndReference(const ArrayOf& v, indexType index, size_t count);
ArrayOf
EndOverloadReference(const ArrayOf& v, indexType index, size_t count, bool& needToBeOverloaded);

size_t
countSubExpressions(AbstractSyntaxTreePtr t);

Expand Down
24 changes: 24 additions & 0 deletions modules/table/functions/@table/end.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
%=============================================================================
% Copyright (c) 2016-present Allan CORNET (Nelson)
%=============================================================================
% This file is part of the Nelson.
%=============================================================================
% LICENCE_BLOCK_BEGIN
% SPDX-License-Identifier: LGPL-3.0-or-later
% LICENCE_BLOCK_END
%=============================================================================
function varargout = end(varargin)
narginchk(3, 3);
nargoutchk(0, 1);
T = varargin{1};
k = varargin{2};
n = varargin{3};
sz = size(T);
if k < n
ind = sz(k);
else
ind = prod(sz(k:end));
end
varargout{1} = ind;
end
%=============================================================================
16 changes: 16 additions & 0 deletions modules/table/functions/@table/numel.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
%=============================================================================
% Copyright (c) 2016-present Allan CORNET (Nelson)
%=============================================================================
% This file is part of the Nelson.
%=============================================================================
% LICENCE_BLOCK_BEGIN
% SPDX-License-Identifier: LGPL-3.0-or-later
% LICENCE_BLOCK_END
%=============================================================================
function varargout = numel(varargin)
narginchk(1, 1);
nargoutchk(0, 1);
obj = varargin{1};
varargout{1} = prod(size(obj));
end
%=============================================================================
24 changes: 24 additions & 0 deletions modules/table/tests/test_end_table.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
%=============================================================================
% Copyright (c) 2016-present Allan CORNET (Nelson)
%=============================================================================
% This file is part of the Nelson.
%=============================================================================
% LICENCE_BLOCK_BEGIN
% SPDX-License-Identifier: LGPL-3.0-or-later
% LICENCE_BLOCK_END
%=============================================================================
LastName = {'Sanchez';'Johnson';'Li';'Diaz';'Brown'};
Age = [38;43;38;40;49];
Smoker = logical([1;0;1;0;1]);
Height = [71;69;64;67;64];
Weight = [176;163;131;133;119];
BloodPressure = [124 93; 109 77; 125 83; 117 75; 122 80];
T = table(LastName, Age, Smoker, Height, Weight, BloodPressure);
R = T(end, 1);
REF = table({'Brown'}, 'VariableNames', {'LastName'});
assert(isequal(R, REF))
%=============================================================================
R = T(2:end-1, 1);
REF = table({'Johnson';'Li';'Diaz'}, 'VariableNames', {'LastName'});
assert(isequal(R, REF))
%=============================================================================

0 comments on commit 71de8ae

Please sign in to comment.