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

Commit 67a9f89

Browse files
committed
[[ Bug 23149 ]] Replace mode syntax factory functions
This patch replaces the current mode syntax factory functions: `MCModeNewCommand` and `MCModeNewFunction` with a more general mechanism based around instantiating a class as a global-variable, constructed using a syntax factory function pointer. There are three global classes which can be instantiated in this manner - `MCNewStatementFactory`, `MCNewFunctionFactory` and `MCNewOperatorFactory` - corresponding to the top-level factory functions `MCN_new_statement`, `MCN_new_function` and `MCN_new_operator`. The classes 'hide' a linked list of factory functions, which are invoked in turn if the top-level functions do not recognise an id.
1 parent 9d4dc77 commit 67a9f89

7 files changed

Lines changed: 150 additions & 64 deletions

File tree

engine/src/mode.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,6 @@ bool MCModeCanLoadHome(void);
152152
//
153153
void MCModeSetupCrashReporting(void);
154154

155-
// These hooks are used to create mode-specific syntax objects.
156-
//
157-
// They are called by the MCN_new_* methods.
158-
//
159-
MCStatement *MCModeNewCommand(int2 which);
160-
MCExpression *MCModeNewFunction(int2 which);
161-
162155
// This hook is used to determine whether to queue stacks that are wanting to
163156
// be opened (e.g. via an AppleEvent OpenDoc event).
164157
//

engine/src/mode_development.cpp

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
5151
#include "player.h"
5252
#include "objptr.h"
5353
#include "osspec.h"
54+
#include "newobj.h"
5455

5556
#include "globals.h"
5657
#include "license.h"
@@ -245,6 +246,24 @@ void MCRevRelicense::exec_ctxt(MCExecContext& ctxt)
245246
atexit(restart_livecode);
246247
}
247248

249+
/* Define the factory function handling development mode syntax. */
250+
static MCStatement *MCN_new_statement_development(int2 which)
251+
{
252+
switch(which)
253+
{
254+
case S_REV_RELICENSE:
255+
return new MCRevRelicense;
256+
default:
257+
break;
258+
}
259+
260+
return NULL;
261+
}
262+
263+
/* Define a new statement factory wrapping the factory function. */
264+
static MCNewStatementFactory
265+
MCdevelopmentmodestatementfactory(MCN_new_statement_development);
266+
248267
////////////////////////////////////////////////////////////////////////////////
249268
//
250269
// Implementation of MCDispatch::startup method for DEVELOPMENT mode.
@@ -602,24 +621,6 @@ bool MCModeCanLoadHome(void)
602621
return true;
603622
}
604623

605-
MCStatement *MCModeNewCommand(int2 which)
606-
{
607-
switch(which)
608-
{
609-
case S_REV_RELICENSE:
610-
return new MCRevRelicense;
611-
default:
612-
break;
613-
}
614-
615-
return NULL;
616-
}
617-
618-
MCExpression *MCModeNewFunction(int2 which)
619-
{
620-
return NULL;
621-
}
622-
623624
bool MCModeShouldQueueOpeningStacks(void)
624625
{
625626
return MCscreen == NULL || MCenvironmentactive;

engine/src/mode_installer.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,16 +1603,6 @@ bool MCModeCanLoadHome(void)
16031603
return false;
16041604
}
16051605

1606-
MCStatement *MCModeNewCommand(int2 which)
1607-
{
1608-
return NULL;
1609-
}
1610-
1611-
MCExpression *MCModeNewFunction(int2 which)
1612-
{
1613-
return NULL;
1614-
}
1615-
16161606
MCObject *MCModeGetU3MessageTarget(void)
16171607
{
16181608
return MCdefaultstackptr -> getcard();

engine/src/mode_server.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -301,16 +301,6 @@ bool MCModeCanLoadHome(void)
301301
return false;
302302
}
303303

304-
MCStatement *MCModeNewCommand(int2 which)
305-
{
306-
return NULL;
307-
}
308-
309-
MCExpression *MCModeNewFunction(int2 which)
310-
{
311-
return NULL;
312-
}
313-
314304
bool MCModeShouldQueueOpeningStacks(void)
315305
{
316306
return false;

engine/src/mode_standalone.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,16 +1222,6 @@ bool MCModeCanLoadHome(void)
12221222
return false;
12231223
}
12241224

1225-
MCStatement *MCModeNewCommand(int2 which)
1226-
{
1227-
return NULL;
1228-
}
1229-
1230-
MCExpression *MCModeNewFunction(int2 which)
1231-
{
1232-
return NULL;
1233-
}
1234-
12351225
MCObject *MCModeGetU3MessageTarget(void)
12361226
{
12371227
return MCdefaultstackptr -> getcard();

engine/src/newobj.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
3232

3333
#include "mode.h"
3434

35+
/* Define the roots of the new object factory lists - one for each kind. These
36+
* are used internally by the MCNewObjFactory derived classes. */
37+
MCNewStatementFactory::Base *MCNewStatementFactory::s_functions = nullptr;
38+
MCNewFunctionFactory::Base *MCNewFunctionFactory::s_functions = nullptr;
39+
MCNewOperatorFactory::Base *MCNewOperatorFactory::s_functions = nullptr;
40+
3541
MCStatement *MCN_new_statement(int2 which)
3642
{
3743
switch (which)
@@ -309,8 +315,8 @@ MCStatement *MCN_new_statement(int2 which)
309315
break;
310316
}
311317

312-
MCStatement *t_new_statement;
313-
t_new_statement = MCModeNewCommand(which);
318+
MCStatement *t_new_statement
319+
= MCNewStatementFactory::New(which);
314320
if (t_new_statement != NULL)
315321
return t_new_statement;
316322

@@ -871,12 +877,11 @@ MCExpression *MCN_new_function(int2 which)
871877
break;
872878
}
873879

874-
MCExpression *t_new_function;
875-
t_new_function = MCModeNewFunction(which);
876-
877-
// SN-2014-11-25: [[ Bug 14088 ]] A NULL pointer is returned if no function exists.
878-
// (that avoids to get a MCFunction which does not implement eval_ctxt).
879-
return t_new_function;
880+
/* Unlike statements and operators, functions return nullptr if a function
881+
* cannot be instantiated. This handles special-cases like 'templateField()'
882+
* which only makes sense in container context (where it is instantiated
883+
* explicitly). */
884+
return MCNewFunctionFactory::New(which);
880885
}
881886

882887
MCExpression *MCN_new_operator(int2 which)
@@ -942,6 +947,15 @@ MCExpression *MCN_new_operator(int2 which)
942947
case O_ENDS_WITH:
943948
return new MCEndsWith;
944949
default:
945-
return new MCExpression;
950+
break;
946951
}
952+
953+
MCExpression *t_new_operator
954+
= MCNewOperatorFactory::New(which);
955+
if (t_new_operator != nullptr)
956+
{
957+
return t_new_operator;
958+
}
959+
960+
return new MCExpression;
947961
}

engine/src/newobj.h

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,117 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
1717
//
1818
// create new script objects
1919
//
20+
#ifndef NEWOBJ_H
21+
#define NEWOBJ_H
22+
2023
class MCStatement;
2124
class MCExpression;
2225

26+
/* The MCNewObjFactory class is designed to be derived from to form the three
27+
* lists of newobj functions for statements, functions and operators.
28+
*
29+
* Derivations of the class are declared as global instances which automatically
30+
* hook themselves into a globally-linked list via global constructors.
31+
*
32+
* As there is no guaranteed order to global constructors, care
33+
* must be taken to ensure the syntax ids handled by each registerd function are
34+
* distinct.
35+
*
36+
* The template base class exploits the fact that template arguments can be
37+
* a derived class. This allows all the code to be in the base-class, with
38+
* derived classes only needing to add a class variable `s_functions` which
39+
* holds the root of the list and a constructor. */
40+
template<typename Derived, typename Node>
41+
class MCNewObjFactory
42+
{
43+
public:
44+
typedef Derived Self;
45+
typedef MCNewObjFactory<Derived, Node> Base;
46+
typedef Node *(*Function)(int2 p_which);
47+
48+
MCNewObjFactory(
49+
Function p_function)
50+
: m_function(p_function)
51+
{
52+
m_next = Derived::s_functions;
53+
Derived::s_functions = this;
54+
}
55+
56+
static Node *
57+
New(int2 p_which)
58+
{
59+
if (Derived::s_functions == nullptr)
60+
{
61+
return nullptr;
62+
}
63+
return Derived::s_functions->_New(p_which);
64+
}
65+
66+
private:
67+
Node *_New(
68+
int2 p_which)
69+
{
70+
Node *t_instance
71+
= m_function(p_which);
72+
if (t_instance != nullptr)
73+
{
74+
return t_instance;
75+
}
76+
77+
if (m_next == nullptr)
78+
{
79+
return nullptr;
80+
}
81+
82+
return m_next->New(p_which);
83+
}
84+
85+
Base *m_next;
86+
Function m_function;
87+
};
88+
89+
/* The MCNewStatementFactory class should be globally instantiated with
90+
* a factory function for statement ids. */
91+
class MCNewStatementFactory
92+
: public MCNewObjFactory<MCNewStatementFactory, MCStatement>
93+
{
94+
public:
95+
MCNewStatementFactory(
96+
Function p_function)
97+
: Base(p_function)
98+
{
99+
}
100+
101+
private:
102+
static Base *s_functions;
103+
friend Base;
104+
};
105+
106+
/* The MCNewFunctionFactory class should be globally instantiated with a factory
107+
* function for function ids. */
108+
class MCNewFunctionFactory
109+
: public MCNewObjFactory<MCNewFunctionFactory, MCExpression>
110+
{
111+
private:
112+
static Base *s_functions;
113+
friend Base;
114+
};
115+
116+
/* The MCNewOperatorFactory class should be globally instantiated with a factory
117+
* function for operator ids. */
118+
class MCNewOperatorFactory
119+
: public MCNewObjFactory<MCNewOperatorFactory, MCExpression>
120+
{
121+
private:
122+
static Base *s_functions;
123+
friend Base;
124+
};
125+
126+
/* The new methods for each type of syntax id which can be instantiated. These
127+
* functions handle the main syntax ids first, and then pass on responsibility
128+
* to the list of factories for the syntax type. */
23129
extern MCStatement *MCN_new_statement(int2 which);
24130
extern MCExpression *MCN_new_function(int2 which);
25131
extern MCExpression *MCN_new_operator(int2 which);
132+
133+
#endif

0 commit comments

Comments
 (0)