libeval_compiler: support for method calls (e.g. item.onlayer('layer') )
This commit is contained in:
parent
7e8e02072e
commit
3268f98fd7
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue