Skip to content

Commit 5ba9c7a

Browse files
GillesDuvertGiloo
andauthored
Implement LAMBDA and LAMBDAP (#2168), verified.
Co-authored-by: Giloo <gildas@localhost>
1 parent 03f40cf commit 5ba9c7a

File tree

11 files changed

+176
-28
lines changed

11 files changed

+176
-28
lines changed

src/GDLInterpreter.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -415,15 +415,15 @@ GDLInterpreter::GDLInterpreter()
415415
}
416416
catch ( GDLException& e) {
417417

418-
// errors while typing commands in inner loop (called via Control-C, STOP, error) should be ignored.
419-
if (e.Interpreter()->IsInnerInterpreterLoop()) {
420-
e.Interpreter()->SetInnerInterpeterLoop(false);
421-
_retTree=NULL;
422-
debugMode=DEBUG_CLEAR;
423-
// we cannot throw, here, it caused #2017
424-
Warning(e.getMessage()); //just warn that there was a (typing ?) error see #1855
425-
return RC_OK;
426-
}
418+
// errors while typing commands in inner loop (called via Control-C, STOP, error) should be ignored.
419+
if (e.Interpreter()->IsInnerInterpreterLoop()) {
420+
e.Interpreter()->SetInnerInterpeterLoop(false);
421+
_retTree=NULL;
422+
debugMode=DEBUG_CLEAR;
423+
// we cannot throw, here, it caused #2017
424+
Warning(e.getMessage()); //just warn that there was a (typing ?) error see #1855
425+
return RC_OK;
426+
}
427427
// reset _retTree to last statement
428428
// (might otherwise be inside an expression in which case
429429
// .CONTINUE does not work)

src/GDLInterpreter.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ class CUSTOM_API GDLInterpreter : public antlr::TreeParser, public GDLInterprete
178178
// procedure (searchForPro == true) or function (searchForPro == false)
179179
static bool CompileFile(const std::string& f,
180180
const std::string& untilPro="",
181-
bool searchForPro=true);
181+
bool searchForPro=true,
182+
bool inlined=false);
182183
static bool CompileSaveFile(RefDNode theAST);
183184
typedef RefHeap<BaseGDL> RefBaseGDL;
184185
typedef RefHeap<DStructGDL> RefDStructGDL;

src/basic_fun.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,88 @@ namespace lib {
16031603
}
16041604
return int_fun(e);
16051605
}
1606+
// LAMBDAS
1607+
static std::map<unsigned int, int> lambdaFunMemory;
1608+
static std::map<unsigned int, int> lambdaProMemory;
1609+
1610+
//deemed dangerous, but should be enough to uniquely identify if 2 lambdas are the same
1611+
unsigned int JSHash(const std::string& str)
1612+
{
1613+
unsigned int hash = 1315423911;
16061614

1615+
for(std::size_t i = 0; i < str.length(); i++)
1616+
{
1617+
hash ^= ((hash << 5) + str[i] + (hash >> 2));
1618+
}
1619+
1620+
return (hash & 0x7FFFFFFF);
1621+
}
1622+
1623+
BaseGDL* lambda_fun(EnvT* e) {
1624+
static const std::string EOL("\n");
1625+
static int lambdanum=1;
1626+
DStringGDL* GDLexpr = e->GetParAs<DStringGDL>(0);
1627+
DString expr=(*GDLexpr)[0];
1628+
unsigned int hash=JSHash(expr);
1629+
std::map<unsigned int,int>::iterator it;
1630+
it = lambdaFunMemory.find(hash);
1631+
if (it != lambdaFunMemory.end()) return new DStringGDL("IDL$LAMBDAF"+i2s((*it).second));
1632+
1633+
size_t pos=expr.find(":",0);
1634+
if (pos==std::string::npos) e->Throw("Code must be of the form \"arg1,arg2,... : statement\"");
1635+
std::string arguments=expr.substr(0,pos);
1636+
string lambdaFunName="IDL$LAMBDAF"+i2s(lambdanum);
1637+
std::string functionText;
1638+
functionText+="FUNCTION ";
1639+
functionText+=lambdaFunName;
1640+
functionText+=",";
1641+
functionText+=arguments;
1642+
functionText+=EOL;
1643+
functionText+="COMPILE_OPT IDL2, hidden\nRETURN,";
1644+
functionText+=expr.substr(pos+1);
1645+
functionText+=EOL;
1646+
functionText+="END";
1647+
bool ok=GDLInterpreter::CompileFile(functionText,"", false, true);
1648+
if (!ok) e->Throw("Syntax error in code.");
1649+
1650+
lambdaFunMemory.insert(std::pair<unsigned int,int>(hash,lambdanum));
1651+
lambdanum++;
1652+
return new DStringGDL(lambdaFunName);
1653+
}
1654+
1655+
BaseGDL* lambda_pro(EnvT* e) {
1656+
static const std::string EOL("\n");
1657+
static int lambdanum=1;
1658+
DStringGDL* GDLexpr = e->GetParAs<DStringGDL>(0);
1659+
DString expr=(*GDLexpr)[0];
1660+
unsigned int hash=JSHash(expr);
1661+
std::map<unsigned int,int>::iterator it;
1662+
it = lambdaProMemory.find(hash);
1663+
if (it != lambdaProMemory.end()) return new DStringGDL("IDL$LAMBDAP"+i2s((*it).second));
1664+
1665+
size_t pos=expr.find(":",0);
1666+
if (pos==std::string::npos) e->Throw("Code must be of the form \"arg1,arg2,... : statement\"");
1667+
std::string arguments=expr.substr(0,pos);
1668+
string lambdaProName="IDL$LAMBDAP"+i2s(lambdanum);
1669+
std::string proText;
1670+
proText+="PRO ";
1671+
proText+=lambdaProName;
1672+
proText+=",";
1673+
proText+=arguments;
1674+
proText+=EOL;
1675+
proText+="COMPILE_OPT IDL2, hidden";
1676+
proText+=EOL;
1677+
proText+=expr.substr(pos+1);
1678+
proText+=EOL;
1679+
proText+="END";
1680+
bool ok=GDLInterpreter::CompileFile(proText,"", false, true);
1681+
if (!ok) e->Throw("Syntax error in code.");
1682+
1683+
lambdaProMemory.insert(std::pair<unsigned int,int>(hash,lambdanum));
1684+
lambdanum++;
1685+
return new DStringGDL(lambdaProName);
1686+
}
1687+
16071688
BaseGDL* call_function(EnvT* e) {
16081689
int nParam = e->NParam();
16091690
if (nParam == 0)

src/basic_fun.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ namespace lib {
179179
BaseGDL** scope_varfetch_reference( EnvT* e); // special version for LEval()
180180
BaseGDL* scope_varname_fun( EnvT* e);
181181
BaseGDL* mean_fun(EnvT* e);
182-
BaseGDL* moment_fun(EnvT* e);
182+
BaseGDL* moment_fun(EnvT* e);
183+
BaseGDL* lambda_fun(EnvT* e);
184+
BaseGDL* lambda_pro(EnvT* e);
183185
} // namespace
184186

185187
#endif

src/dinterpreter.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -644,14 +644,16 @@ void GDLInterpreter::ReportCompileError( GDLException& e, const string& file)
644644
// compiles file, returns success
645645
// if untilPro is set to "" the whole file is compiled
646646
// procedure (searchForPro == true (default)) or function (searchForPro == false)
647-
bool GDLInterpreter::CompileFile(const string& f, const string& untilPro, bool searchForPro)
647+
bool GDLInterpreter::CompileFile(const string& f, const string& untilPro, bool searchForPro, bool inlined)
648648
{
649-
ifstream in(f.c_str());
650-
if( !in) return false; // maybe throw exception here
651-
649+
//Note that std::unique_ptr is better that raw pointers
650+
std::unique_ptr<std::istream> stream;
651+
//stream holds a string
652+
if (inlined) stream = std::make_unique<std::istringstream>(f); else stream = std::make_unique<std::ifstream>(std::ifstream{ f.c_str() });
653+
652654
RefDNode theAST;
653655
try {
654-
GDLLexer lexer(in, f, GDLParser::NONE, untilPro, searchForPro);
656+
GDLLexer lexer(*stream, f, GDLParser::NONE, untilPro, searchForPro);
655657
GDLParser& parser=lexer.Parser();
656658

657659
// parsing

src/dpro.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,9 @@ typedef std::vector<DPro*> ProListT;
631631
typedef std::set<std::string> UnknownFunListT;
632632
typedef std::set<std::string> UnknownProListT;
633633

634+
typedef std::map<std::string, DFun*> LambdaFunListT;
635+
typedef std::map<std::string, DPro*> LambdaProListT;
636+
634637
typedef std::vector<DLibFun*> LibFunListT;
635638
typedef std::vector<DLibPro*> LibProListT;
636639

src/gdlc.i.g

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ public:
231231
// procedure (searchForPro == true) or function (searchForPro == false)
232232
static bool CompileFile(const std::string& f,
233233
const std::string& untilPro="",
234-
bool searchForPro=true);
234+
bool searchForPro=true,
235+
bool inlined=false);
235236
static bool CompileSaveFile(RefDNode theAST);
236237
typedef RefHeap<BaseGDL> RefBaseGDL;
237238
typedef RefHeap<DStructGDL> RefDStructGDL;

src/libinit.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ void LibInit()
113113
new DLibFunRetNew(lib::orderedhash_fun,string("ORDEREDHASH"),-1,hashKey);
114114

115115
new DLibFun(lib::scope_level,string("SCOPE_LEVEL"),0);
116+
//LAMBDA function
117+
new DLibFun(lib::lambda_fun,string("LAMBDA"),1);
118+
new DLibFun(lib::lambda_pro,string("LAMBDAP"),1);
116119

117120
//SCOPE_VARFETCH WARNING: changes in lib::scope_varfetch_value must be reported also in lib::scope_varfetch_reference
118121
const string scope_varfetchKey[]={"LEVEL","ENTER", "REF_EXTRA", "COMMON", KLISTEND};

src/objects.cpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,13 +1022,8 @@ bool IsPro(antlr::RefToken rT1)
10221022
{
10231023
antlr::Token& T1=*rT1;
10241024

1025-
// search for T1.getText() in function table and path
10261025
string searchName=StrUpCase(T1.getText());
10271026

1028-
// cout << "IsFun: Searching for: " << searchName << endl;
1029-
1030-
// Speeds up the process of finding (in gdlc.g) if a syntax like foo(bar) is a call to the function 'foo'
1031-
// or the 'bar' element of array 'foo'.
10321027
LibProListT::iterator p=find_if(libProList.begin(),libProList.end(),
10331028
Is_eq<DLibPro>(searchName));
10341029
if( p != libProList.end()) if( *p != NULL) return true;
@@ -1041,9 +1036,6 @@ bool IsPro(antlr::RefToken rT1)
10411036
for ( UnknownProListT::iterator r=unknownProList.begin(); r!=unknownProList.end(); ++r) {
10421037
if( (*r) == searchName ) return true;
10431038
}
1044-
1045-
// cout << "Not found: " << searchName << endl;
1046-
10471039
return false;
10481040
}
10491041

@@ -1052,14 +1044,44 @@ int ProIx(const string& n)
10521044
SizeT nF=proList.size();
10531045
for( SizeT i=0; i<nF; i++) if( Is_eq<DPro>(n)(proList[i]))
10541046
return (int)i;
1055-
return -1;
1056-
}
1047+
//may be a lambda list ? so it's a UD Pro
1048+
EnvT* requestedScope = (EnvT*) DInterpreter::CallStackBack();
1049+
DSubUD* pro = static_cast<DSubUD*> (requestedScope->GetPro());
1050+
int xI = pro->FindVar(n);
1051+
if (xI != -1) {
1052+
BaseGDL*& var = requestedScope->GetTheKW(xI);
1053+
if (var == NULL) return -1;
1054+
if (var->N_Elements() != 1) return -1;
1055+
if (var->Type() == GDL_STRING) { //examine string
1056+
DString *s = static_cast<DString*> (var->DataAddr());
1057+
if (s->find("IDL$LAMBDAP", 0) == 0) { //is a lambda
1058+
for (SizeT i = 0; i < nF; i++) if (Is_eq<DPro>(*s)(proList[i])) return (int) i;
1059+
}
1060+
}
1061+
}
1062+
return -1;
1063+
}
10571064

10581065
int FunIx(const string& n)
10591066
{
10601067
SizeT nF=funList.size();
10611068
for( SizeT i=0; i<nF; i++) if( Is_eq<DFun>(n)(funList[i]))
10621069
return (int)i;
1070+
//may be a lambda list ? so it's a UD Fun
1071+
EnvT* requestedScope = (EnvT*) DInterpreter::CallStackBack();
1072+
DSubUD* pro = static_cast<DSubUD*> (requestedScope->GetPro());
1073+
int xI = pro->FindVar(n);
1074+
if (xI != -1) {
1075+
BaseGDL*& var = requestedScope->GetTheKW(xI);
1076+
if (var == NULL) return -1;
1077+
if (var->N_Elements() !=1) return -1;
1078+
if (var->Type() == GDL_STRING) { //examine string
1079+
DString *s=static_cast<DString*>(var->DataAddr());
1080+
if (s->find("IDL$LAMBDAF",0)==0) { //is a lambda
1081+
for( SizeT i=0; i<nF; i++) if( Is_eq<DFun>(*s)(funList[i])) return (int)i;
1082+
}
1083+
}
1084+
}
10631085
return -1;
10641086
}
10651087

@@ -1069,7 +1091,7 @@ int LibProIx(const string& n)
10691091
for( SizeT i=0; i<nF; i++)
10701092
{
10711093
if( Is_eq<DLibPro>(n)(libProList[i])) return (int)i;
1072-
}
1094+
}
10731095
return -1;
10741096
}
10751097

testsuite/LIST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ test_l64.pro
121121
test_la_least_squares.pro
122122
test_la_trired.pro
123123
test_label_date.pro
124+
test_lambdas.pro
124125
test_linfit.pro
125126
test_list.pro
126127
test_ludc_lusol.pro

0 commit comments

Comments
 (0)