Skip to content
This repository has been archived by the owner on Aug 31, 2021. It is now read-only.

[[ Bug 23149 ]] Replace mode syntax factory functions #7544

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 0 additions & 7 deletions engine/src/mode.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,6 @@ bool MCModeCanLoadHome(void);
//
void MCModeSetupCrashReporting(void);

// These hooks are used to create mode-specific syntax objects.
//
// They are called by the MCN_new_* methods.
//
MCStatement *MCModeNewCommand(int2 which);
MCExpression *MCModeNewFunction(int2 which);

// This hook is used to determine whether to queue stacks that are wanting to
// be opened (e.g. via an AppleEvent OpenDoc event).
//
Expand Down
37 changes: 19 additions & 18 deletions engine/src/mode_development.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
#include "player.h"
#include "objptr.h"
#include "osspec.h"
#include "newobj.h"

#include "globals.h"
#include "license.h"
Expand Down Expand Up @@ -245,6 +246,24 @@ void MCRevRelicense::exec_ctxt(MCExecContext& ctxt)
atexit(restart_livecode);
}

/* Define the factory function handling development mode syntax. */
static MCStatement *MCN_new_statement_development(int2 which)
{
switch(which)
{
case S_REV_RELICENSE:
return new MCRevRelicense;
default:
break;
}

return NULL;
}

/* Define a new statement factory wrapping the factory function. */
static MCNewStatementFactory
MCdevelopmentmodestatementfactory(MCN_new_statement_development);

////////////////////////////////////////////////////////////////////////////////
//
// Implementation of MCDispatch::startup method for DEVELOPMENT mode.
Expand Down Expand Up @@ -602,24 +621,6 @@ bool MCModeCanLoadHome(void)
return true;
}

MCStatement *MCModeNewCommand(int2 which)
{
switch(which)
{
case S_REV_RELICENSE:
return new MCRevRelicense;
default:
break;
}

return NULL;
}

MCExpression *MCModeNewFunction(int2 which)
{
return NULL;
}

bool MCModeShouldQueueOpeningStacks(void)
{
return MCscreen == NULL || MCenvironmentactive;
Expand Down
10 changes: 0 additions & 10 deletions engine/src/mode_installer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1603,16 +1603,6 @@ bool MCModeCanLoadHome(void)
return false;
}

MCStatement *MCModeNewCommand(int2 which)
{
return NULL;
}

MCExpression *MCModeNewFunction(int2 which)
{
return NULL;
}

MCObject *MCModeGetU3MessageTarget(void)
{
return MCdefaultstackptr -> getcard();
Expand Down
10 changes: 0 additions & 10 deletions engine/src/mode_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,16 +301,6 @@ bool MCModeCanLoadHome(void)
return false;
}

MCStatement *MCModeNewCommand(int2 which)
{
return NULL;
}

MCExpression *MCModeNewFunction(int2 which)
{
return NULL;
}

bool MCModeShouldQueueOpeningStacks(void)
{
return false;
Expand Down
10 changes: 0 additions & 10 deletions engine/src/mode_standalone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1222,16 +1222,6 @@ bool MCModeCanLoadHome(void)
return false;
}

MCStatement *MCModeNewCommand(int2 which)
{
return NULL;
}

MCExpression *MCModeNewFunction(int2 which)
{
return NULL;
}

MCObject *MCModeGetU3MessageTarget(void)
{
return MCdefaultstackptr -> getcard();
Expand Down
32 changes: 23 additions & 9 deletions engine/src/newobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */

#include "mode.h"

/* Define the roots of the new object factory lists - one for each kind. These
* are used internally by the MCNewObjFactory derived classes. */
MCNewStatementFactory::Base *MCNewStatementFactory::s_functions = nullptr;
MCNewFunctionFactory::Base *MCNewFunctionFactory::s_functions = nullptr;
MCNewOperatorFactory::Base *MCNewOperatorFactory::s_functions = nullptr;

MCStatement *MCN_new_statement(int2 which)
{
switch (which)
Expand Down Expand Up @@ -309,8 +315,8 @@ MCStatement *MCN_new_statement(int2 which)
break;
}

MCStatement *t_new_statement;
t_new_statement = MCModeNewCommand(which);
MCStatement *t_new_statement
= MCNewStatementFactory::New(which);
if (t_new_statement != NULL)
return t_new_statement;

Expand Down Expand Up @@ -871,12 +877,11 @@ MCExpression *MCN_new_function(int2 which)
break;
}

MCExpression *t_new_function;
t_new_function = MCModeNewFunction(which);

// SN-2014-11-25: [[ Bug 14088 ]] A NULL pointer is returned if no function exists.
// (that avoids to get a MCFunction which does not implement eval_ctxt).
return t_new_function;
/* Unlike statements and operators, functions return nullptr if a function
* cannot be instantiated. This handles special-cases like 'templateField()'
* which only makes sense in container context (where it is instantiated
* explicitly). */
return MCNewFunctionFactory::New(which);
}

MCExpression *MCN_new_operator(int2 which)
Expand Down Expand Up @@ -942,6 +947,15 @@ MCExpression *MCN_new_operator(int2 which)
case O_ENDS_WITH:
return new MCEndsWith;
default:
return new MCExpression;
break;
}

MCExpression *t_new_operator
= MCNewOperatorFactory::New(which);
if (t_new_operator != nullptr)
{
return t_new_operator;
}

return new MCExpression;
}
122 changes: 122 additions & 0 deletions engine/src/newobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,131 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
//
// create new script objects
//
#ifndef NEWOBJ_H
#define NEWOBJ_H

class MCStatement;
class MCExpression;

/* The MCNewObjFactory class is designed to be derived from to form the three
* lists of newobj functions for statements, functions and operators.
*
* Derivations of the class are declared as global instances which automatically
* hook themselves into a globally-linked list via global constructors.
*
* As there is no guaranteed order to global constructors, care
* must be taken to ensure the syntax ids handled by each registerd function are
* distinct.
*
* The template base class exploits the fact that template arguments can be
* a derived class. This allows all the code to be in the base-class, with
* derived classes only needing to add a class variable `s_functions` which
* holds the root of the list and a constructor. */
template<typename Derived, typename Node>
class MCNewObjFactory
{
public:
typedef Derived Self;
typedef MCNewObjFactory<Derived, Node> Base;
typedef Node *(*Function)(int2 p_which);

MCNewObjFactory(
Function p_function)
: m_function(p_function)
{
m_next = Derived::s_functions;
Derived::s_functions = this;
}

static Node *
New(int2 p_which)
{
if (Derived::s_functions == nullptr)
{
return nullptr;
}
return Derived::s_functions->_New(p_which);
}

private:
Node *_New(
int2 p_which)
{
Node *t_instance
= m_function(p_which);
if (t_instance != nullptr)
{
return t_instance;
}

if (m_next == nullptr)
{
return nullptr;
}

return m_next->New(p_which);
}

Base *m_next;
Function m_function;
};

/* The MCNewStatementFactory class should be globally instantiated with
* a factory function for statement ids. */
class MCNewStatementFactory
: public MCNewObjFactory<MCNewStatementFactory, MCStatement>
{
public:
MCNewStatementFactory(
Function p_function)
: Base(p_function)
{
}

private:
static Base *s_functions;
friend Base;
};

/* The MCNewFunctionFactory class should be globally instantiated with a factory
* function for function ids. */
class MCNewFunctionFactory
: public MCNewObjFactory<MCNewFunctionFactory, MCExpression>
{
public:
MCNewFunctionFactory(
Function p_function)
: Base(p_function)
{
}

private:
static Base *s_functions;
friend Base;
};

/* The MCNewOperatorFactory class should be globally instantiated with a factory
* function for operator ids. */
class MCNewOperatorFactory
: public MCNewObjFactory<MCNewOperatorFactory, MCExpression>
{
public:
MCNewOperatorFactory(
Function p_function)
: Base(p_function)
{
}

private:
static Base *s_functions;
friend Base;
};

/* The new methods for each type of syntax id which can be instantiated. These
* functions handle the main syntax ids first, and then pass on responsibility
* to the list of factories for the syntax type. */
extern MCStatement *MCN_new_statement(int2 which);
extern MCExpression *MCN_new_function(int2 which);
extern MCExpression *MCN_new_operator(int2 which);

#endif