118 lines
3.2 KiB
C++
118 lines
3.2 KiB
C++
|
|
#include "FrameLib_Expression.h"
|
|
#include "FrameLib_MaxClass.h"
|
|
|
|
// These objects parses its arguments differently to normal, which is handled by pre-parsing the atoms into a different format
|
|
|
|
class ArgumentParser
|
|
{
|
|
|
|
public:
|
|
|
|
ArgumentParser(t_symbol *s, long argc, t_atom *argv) : mSymbol(s)
|
|
{
|
|
concatenate(argc, argv);
|
|
|
|
while (argc--)
|
|
{
|
|
if (atom_getsym(argv) == gensym("/expr"))
|
|
concatenate(argc, ++argv);
|
|
else
|
|
mArgs.push_back(*argv++);
|
|
}
|
|
}
|
|
|
|
t_symbol *symbol() const { return mSymbol;}
|
|
long count() const { return static_cast<long>(mArgs.size());}
|
|
t_atom* args() const { return const_cast<t_atom*>(mArgs.data()); }
|
|
|
|
private:
|
|
|
|
// Tag Detection
|
|
|
|
bool isValidTag(t_atom *a)
|
|
{
|
|
t_symbol *sym = atom_getsym(a);
|
|
size_t len = strlen(sym->s_name);
|
|
|
|
// Input tag
|
|
|
|
if (len > 2 && sym->s_name[0] == '[' && sym->s_name[len - 1] == ']')
|
|
return true;
|
|
|
|
// Basic parameter tag test
|
|
|
|
if (len <= 1 || sym->s_name[0] != '/')
|
|
return false;
|
|
|
|
// Escape division by known constants
|
|
|
|
if (sym == gensym("/pi") || sym == gensym("/epsilon") || sym == gensym("/e") || sym == gensym("/inf"))
|
|
return false;
|
|
|
|
// Require a parameter tag to have only letters after the slash
|
|
|
|
for (const char *c = sym->s_name + 1; *c; c++)
|
|
if (!((*c >= 'a') && (*c <= 'z')) || ((*c >= 'A') && (*c <= 'Z')))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Concatenator
|
|
|
|
void concatenate(long& argc, t_atom*& argv)
|
|
{
|
|
std::string concatenated;
|
|
|
|
for (; argc && !isValidTag(argv); argc--, argv++)
|
|
{
|
|
if (atom_gettype(argv) == A_SYM)
|
|
concatenated += atom_getsym(argv)->s_name;
|
|
else
|
|
concatenated += std::to_string(atom_getfloat(argv));
|
|
|
|
// Add whitespace between symbols
|
|
|
|
concatenated += " ";
|
|
}
|
|
|
|
if (concatenated.length())
|
|
{
|
|
t_symbol *arg = gensym(concatenated.c_str());
|
|
mArgs.push_back(t_atom());
|
|
atom_setsym(&mArgs.back(), arg);
|
|
}
|
|
}
|
|
|
|
t_symbol *mSymbol;
|
|
std::vector<t_atom> mArgs;
|
|
};
|
|
|
|
// This class is a wrapper that allows the parsing to happen correctly
|
|
|
|
struct FrameLib_MaxClass_Expression_Parsed : public FrameLib_MaxClass_Expand<FrameLib_Expression>
|
|
{
|
|
FrameLib_MaxClass_Expression_Parsed(const ArgumentParser &parsed) :
|
|
FrameLib_MaxClass(parsed.symbol(), parsed.count(), parsed.args(), new FrameLib_MaxProxy()) {}
|
|
};
|
|
|
|
// Max Class (inherits from the parsed version which inherits the standard max class
|
|
|
|
struct FrameLib_MaxClass_Expression : public FrameLib_MaxClass_Expression_Parsed
|
|
{
|
|
// Constructor
|
|
|
|
FrameLib_MaxClass_Expression(t_symbol *s, long argc, t_atom *argv) :
|
|
FrameLib_MaxClass_Expression_Parsed(ArgumentParser(s, argc, argv)) {}
|
|
};
|
|
|
|
#ifndef FRAMELIB_MAX_SINGLE_OBJECT
|
|
|
|
extern "C" int C74_EXPORT main(void)
|
|
{
|
|
FrameLib_MaxClass_Expression::makeClass<FrameLib_MaxClass_Expression>("fl.expr~");
|
|
}
|
|
|
|
#endif
|