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

View File

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