From 3268f98fd7b35e87c5ff1e4cbf1005566f53701c Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Thu, 18 Jun 2020 00:36:02 +0200 Subject: [PATCH] libeval_compiler: support for method calls (e.g. item.onlayer('layer') ) --- common/libeval_compiler/libeval_compiler.cpp | 75 ++++++++------- include/libeval_compiler/libeval_compiler.h | 97 +++++++++++++------- 2 files changed, 105 insertions(+), 67 deletions(-) diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp index 61db4fd79c..98275c67ae 100644 --- a/common/libeval_compiler/libeval_compiler.cpp +++ b/common/libeval_compiler/libeval_compiler.cpp @@ -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 ) diff --git a/include/libeval_compiler/libeval_compiler.h b/include/libeval_compiler/libeval_compiler.h index 02c028562d..27b5e506ca 100644 --- a/include/libeval_compiler/libeval_compiler.h +++ b/include/libeval_compiler/libeval_compiler.h @@ -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 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 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;