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];
|
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 )
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue