libeval_compiler: support for method calls (e.g. item.onlayer('layer') )

This commit is contained in:
Tomasz Wlostowski 2020-06-18 00:36:02 +02:00
parent 7e8e02072e
commit 3268f98fd7
2 changed files with 105 additions and 67 deletions

View File

@ -84,7 +84,7 @@ static const std::string formatOpName( int op )
}
std::string UCODE::UOP::Format() const
std::string UOP::Format() const
{
char str[1024];
@ -102,8 +102,14 @@ std::string UCODE::UOP::Format() const
sprintf( str, "PUSH STR [%s]", val->AsString().c_str() );
break;
}
case TR_OP_METHOD_CALL:
sprintf(str, "MCALL" );
break;
case TR_OP_FUNC_CALL:
sprintf(str, "FCALL" );
break;
default:
sprintf( str, "%s", formatOpName( m_op ).c_str() );
sprintf( str, "%s %d", formatOpName( m_op ).c_str(), m_op );
break;
}
return str;
@ -504,7 +510,7 @@ const std::string formatNode( TREE_NODE* tok )
void dumpNode( std::string& buf, TREE_NODE* tok, int depth = 0 )
{
char str[1024];
sprintf( str, "\n[%p] ", tok ); //[tok %p] ", tok);
sprintf( str, "\n[%p L0:%-20p L1:%-20p] ", tok, tok->leaf[0], tok->leaf[1] ); //[tok %p] ", tok);
buf += str;
for( int i = 0; i < 2 * depth; i++ )
buf += " ";
@ -584,8 +590,6 @@ bool COMPILER::generateUCode( UCODE* aCode )
return visitedNodes.find( node ) != visitedNodes.end();
};
UCODE code;
assert( m_tree );
stack.push_back( m_tree );
@ -594,21 +598,21 @@ bool COMPILER::generateUCode( UCODE* aCode )
dumpNode( dump, m_tree, 0 );
libeval_dbg(3,"Tree: %s", dump.c_str() );
libeval_dbg(3,"Tree dump:\n%s\n\n", dump.c_str() );
while( !stack.empty() )
{
auto node = stack.back();
bool isTerminalNode = true;
libeval_dbg( 4, "process node %p [op %d] [stack %d]\n", node, node->op, stack.size() );
// process terminal nodes first
switch( node->op )
{
case TR_OP_FUNC_CALL:
break;
case TR_STRUCT_REF:
{
assert( node->leaf[0]->op == TR_IDENTIFIER );
@ -623,16 +627,17 @@ bool COMPILER::generateUCode( UCODE* aCode )
if( m_errorStatus.pendingError )
{
printf("varref fail\n");
libeval_dbg(4, "varref fail\n");
return false;
}
aCode->AddOp( TR_UOP_PUSH_VAR, vref );
node->uop = makeUop( TR_UOP_PUSH_VAR, vref );
node->isTerminal = true;
break;
}
case TR_OP_FUNC_CALL:
{
//printf("got a method call... [%s], this = %s\n", node->leaf[1]->leaf[0]->value.str, node->leaf[0]->value.str);
libeval_dbg(4, "got a method call... [%s], this = %s\n", node->leaf[1]->leaf[0]->value.str, node->leaf[0]->value.str);
auto vref = aCode->createVarRef( this, node->leaf[0]->value.str, "");
auto func = aCode->createFuncCall( this, node->leaf[1]->leaf[0]->value.str );
@ -640,6 +645,7 @@ bool COMPILER::generateUCode( UCODE* aCode )
{
m_errorStatus.pendingError = true;
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
libeval_dbg(0, "unable to resolve func %s\n", node->leaf[1]->leaf[0]->value.str );
return false;
// fixme: generate a message
}
@ -647,13 +653,11 @@ bool COMPILER::generateUCode( UCODE* aCode )
// printf("cfc4 test\n");
// func(nullptr, nullptr, nullptr);
aCode->AddOp( TR_OP_METHOD_CALL, func, vref );
isTerminalNode = false;
visitedNodes.insert( node );
visitedNodes.insert( node->leaf[0] );
//visitedNodes.insert( node->leaf[1]->leaf[1] );
visitedNodes.insert( node->leaf[1]->leaf[0] );
node->uop = makeUop( TR_OP_METHOD_CALL, func, vref );
node->isTerminal = false;
break;
}
@ -677,49 +681,50 @@ bool COMPILER::generateUCode( UCODE* aCode )
visitedNodes.insert( son );
}
aCode->AddOp( TR_UOP_PUSH_VALUE, value );
node->uop = makeUop( TR_UOP_PUSH_VALUE, value );
node->isTerminal = true;
break;
}
case TR_STRING:
{
aCode->AddOp( TR_UOP_PUSH_VALUE, node->value.str );
node->uop = makeUop( TR_UOP_PUSH_VALUE, node->value.str );
node->isTerminal = true;
break;
}
default:
isTerminalNode = false;
node->uop = makeUop( node->op );
break;
}
if( isTerminalNode )
{
visitedNodes.insert( node );
stack.pop_back();
continue;
}
if( node->leaf[0] && !visited( node->leaf[0] ) )
if( !node->isTerminal && node->leaf[0] && !visited( node->leaf[0] ) )
{
stack.push_back( node->leaf[0] );
visitedNodes.insert( node->leaf[0] );
continue;
}
else if( node->leaf[1] && !visited( node->leaf[1] ) )
else if( !node->isTerminal && node->leaf[1] && !visited( node->leaf[1] ) )
{
stack.push_back( node->leaf[1] );
visitedNodes.insert( node->leaf[1] );
continue;
}
else
{
aCode->AddOp( node->op );
visitedNodes.insert( node );
stack.pop_back();
}
visitedNodes.insert( node );
if(node->uop)
aCode->AddOp(node->uop);
stack.pop_back();
}
libeval_dbg(2,"DUMp: \n%s\n", aCode->Dump().c_str() );
return true;
}
void UCODE::UOP::Exec( CONTEXT* ctx, UCODE* ucode )
void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
{
switch( m_op )

View File

@ -44,7 +44,7 @@
#define TR_OP_BOOL_OR 0x20c
#define TR_OP_BOOL_NOT 0x100
#define TR_OP_FUNC_CALL 24
#define TR_OP_METHOD_CALL 25
#define TR_UOP_PUSH_VAR 1
#define TR_UOP_PUSH_VALUE 2
@ -92,6 +92,8 @@ enum TOKEN_TYPE_T
#define LIBEVAL_MAX_LITERAL_LENGTH 1024
class UOP;
struct TREE_NODE
{
struct value_s
@ -101,7 +103,9 @@ struct TREE_NODE
} value;
int op;
TREE_NODE* leaf[2];
UOP* uop;
bool valid;
bool isTerminal;
};
static inline TREE_NODE* copyNode( TREE_NODE& t )
@ -113,6 +117,8 @@ static inline TREE_NODE* copyNode( TREE_NODE& t )
t2->value.type = t.value.type;
t2->leaf[0] = t.leaf[0];
t2->leaf[1] = t.leaf[1];
t2->isTerminal = false;
t2->uop = nullptr;
return t2;
}
@ -127,6 +133,8 @@ static inline TREE_NODE* newNode( int op, int type, std::string value )
t2->value.type = type;
t2->leaf[0] = nullptr;
t2->leaf[1] = nullptr;
t2->isTerminal = false;
t2->uop = nullptr;
return t2;
}
@ -244,10 +252,12 @@ class VAR_REF
virtual VALUE GetValue( UCODE* aUcode ) = 0;
};
class UCODE
{
public:
class CONTEXT
{
public:
@ -289,36 +299,11 @@ public:
int m_memPos = 0;
};
class UOP
typedef std::function<void(UCODE*, CONTEXT*, void*)> FUNC_PTR;
void AddOp( UOP* uop )
{
public:
UOP( int op, void* arg ) : m_op( op ), m_arg( arg )
{};
void Exec( CONTEXT* ctx, UCODE *ucode );
std::string Format() const;
private:
int m_op;
void *m_arg;
};
void AddOp( int op, double value )
{
auto uop = new UOP( op, new VALUE( value ) );
m_ucode.push_back( uop );
}
void AddOp( int op, std::string value )
{
auto uop = new UOP( op, new VALUE( value ) );
m_ucode.push_back( uop );
}
void AddOp( int op, VAR_REF* aRef = nullptr )
{
auto uop = new UOP( op, aRef );
m_ucode.push_back( uop );
m_ucode.push_back(uop);
}
VALUE* Run();
@ -330,10 +315,33 @@ public:
return nullptr;
};
virtual FUNC_PTR createFuncCall( COMPILER* aCompiler, const std::string& name )
{
return nullptr;
};
private:
std::vector<UOP*> m_ucode;
};
class UOP
{
public:
UOP( int op, void* arg ) : m_op( op ), m_arg( arg )
{};
UOP( int op, UCODE::FUNC_PTR func, void *arg ) : m_op( op ), m_arg(arg), m_func( func )
{};
void Exec( UCODE::CONTEXT* ctx, UCODE *ucode );
std::string Format() const;
private:
int m_op;
void *m_arg;
UCODE::FUNC_PTR m_func;
};
class TOKENIZER
{
public:
@ -439,11 +447,36 @@ protected:
/* Used by processing loop */
void parse( int token, TREE_NODE value );
void* m_parser; // the current lemon parser state machine
int resolveUnits();
UOP* makeUop( int op, double value )
{
auto uop = new UOP( op, new VALUE( value ) );
return uop;
}
UOP* makeUop( int op, std::string value )
{
auto uop = new UOP( op, new VALUE( value ) );
return uop;
}
UOP* makeUop( int op, VAR_REF* aRef = nullptr )
{
auto uop = new UOP( op, aRef );
return uop;
}
UOP* makeUop( int op, UCODE::FUNC_PTR aFunc, void *arg = nullptr )
{
auto uop = new UOP( op, aFunc, arg );
return uop;
}
/* Token state for input string. */
void* m_parser; // the current lemon parser state machine
TOKENIZER m_tokenizer;
char m_localeDecimalSeparator;