Skip to content

Commit 72bee99

Browse files
committed
[[ ReturnValue ]] Provide new return forms to return values and errors
This patch adds two new forms of the 'return' command: return value <value> return error <value> These forms act slightly differently, depending on whether the handler calling them is a command or a function handler. If the handler performing the return is a command handler then: The 'return value' form, sets 'it' in the caller to <value> and sets 'the result' to empty. The 'return error' form, sets 'it' in the caller to empty and sets 'the result' to <value>. If the handler performingthe return is a function handler then: The 'return value' form, returns <value> as the return value of the function call and sets 'the result' to empty. The 'return error' form, returns empty as the return value of the function call and sets 'the result' to <value>. These forms of return are designed to be used by script library functions to allow them to have the same ability as built-in engine functions and commands - namely the ability to return a value (in it for commands, or return value for functions) *or* return a status (in the result).
1 parent 2346677 commit 72bee99

18 files changed

Lines changed: 472 additions & 158 deletions

docs/dictionary/control_st/return.lcdoc

Lines changed: 126 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,142 @@ Name: return
22

33
Type: control structure
44

5-
Syntax: return <value>
5+
Syntax: return [ { value | error } ] <value>
66

7-
Summary: Stops the current <handler> and <return|returns> a <value> to the <handler> that <call|called> the current <handler>. Sets the result to the value as well
7+
Summary: Stops the current <handler> and <return|returns> a <value> to the
8+
<handler> that <call|called> the current <handler>.
89

910
Introduced: 1.0
1011

12+
Changed: 8.1.0
13+
1114
OS: mac,windows,linux,ios,android
1215

1316
Platforms: desktop,server,web,mobile
1417

15-
Parameters:
16-
value:
17-
handler: The name of the handler in which the return control structure appears.
18+
Example:
19+
function simpleFunction
20+
return 1
21+
end simpleFunction
22+
on testSimpleFunction
23+
local tVar
24+
put simpleFunction() into tVar
25+
-- tVar contains 1, the result contains 1
26+
end testSimpleFunction
27+
28+
Example:
29+
function simpleFunction
30+
return value 1
31+
end simpleFunction
32+
on testSimpleFunction
33+
local tVar
34+
put simpleFunction() into tVar
35+
-- tVar contains 1, the result contains empty
36+
end testSimpleFunction
37+
38+
Example:
39+
function simpleFunction
40+
return error 1
41+
end simpleFunction
42+
on testSimpleFunction
43+
local tVar
44+
put simpleFunction() into tVar
45+
-- tVar contains empty, the result contains 1
46+
end testSimpleFunction
47+
48+
Example:
49+
command simpleCommand
50+
return 1
51+
end simpleCommand
52+
on testSimpleCommand
53+
simpleCommand
54+
-- the result contains 1
55+
end testSimpleCommand
56+
57+
Example:
58+
command simpleCommand
59+
return value 1
60+
end simpleCommand
61+
on testSimpleCommand
62+
simpleCommand
63+
-- it contains 1, the result contains empty
64+
end testSimpleCommand
65+
66+
Example:
67+
command simpleCommand
68+
return error 1
69+
end simpleCommand
70+
on testSimpleCommand
71+
simpleCommand
72+
-- it contains empty, the result contains 1
73+
end testSimpleCommand
1874

19-
The result: The <return> control structure set <the result> to the value being returned. If the <return> <control structure> is within an <on> or <setProp> <control structure>, the <value> can be retrieved by checking the <result> <function> in the <caller|calling handler>. Usually, when the <return> <control structure> is used within an <on> or <setProp> <control structure>, it <return(glossary)|returns> an error message. (If you want a <handler> to compute a <value> as its main reason for existence, you should implement it as a custom function rather than a custom command.). >*Note:* As well as the <return> <control structure> returns the value to the caller, it sets <the result> to the value.
75+
Parameters:
76+
value: The value to return to the calling handler.
2077

2178
Description:
22-
Use the <return> <control structure> to <return(constant)> a <value> from a custom function or <getProp> <handler>, or to <return(constant)> an error message from a <message handler> or <setProp> <handler>.
79+
Use the <return> <control structure> to <return(constant)> a <value> from a
80+
custom function or <getProp> <handler>, or to <return(constant)> an error
81+
message from a <message handler> or <setProp> <handler>.
2382

2483
Form:
25-
The <return> <statement> appears on a line by itself, anywhere inside a <handler>.
26-
27-
When the <return> <control structure> is <execute|executed>, any remaining <statement|statements> in the <handler> are skipped. Hence, the <return> <control structure> is usually used either at the end of a <handler> or within an <if> <control structure>.
28-
29-
If the <return> <control structure> is within a <function> or <getProp> <control structure>, the <value> is returned to the <caller|calling handler> as the <function> <value> or <property> setting. For example, if you have the following <function> <handler> :
30-
31-
which is called in the following statement:
32-
33-
then 1, the value returned by "simpleFunction", is placed in the field.
34-
35-
When a message handler executes a <return> <statement>, the <message> stops and is not <pass|passed> to the next <object(glossary)> in the <message path>. To halt the current <message handler> and <pass> the <message> on through the <message path>, use the <pass> <control structure> instead. To halt the current <handler> without returning a result, use the <exit> <control structure> instead.
36-
37-
>*Note:* The <return> <control structure> is implemented internally as a <command> and appears in the <commandNames>.
38-
39-
40-
References: object (glossary), return (constant), result (function), commandNames (function), value (function), merge (function), the result (function), message handler (glossary), return (glossary), call (glossary), property (glossary), pass (glossary), execute (glossary), command (glossary), control structure (glossary), message path (glossary), caller (glossary), message (glossary), statement (glossary), handler (glossary), setProp (control structure), getProp (control structure), throw (control structure), if (control structure), pass (control structure), exit (control structure), on (control structure), function (control structure)
84+
The <return> <statement> appears on a line by itself, anywhere inside a
85+
<handler>.
86+
87+
When the <return> <control structure> is <execute|executed>, any remaining
88+
<statement|statements> in the <handler> are skipped. Hence, the <return>
89+
<control structure> is usually used either at the end of a <handler> or within
90+
an <if> <control structure>.
91+
92+
The plain form of the <return> <control structure> always sets <the result> to
93+
<value>. Additionally, if it is used within a <function> or <getProp> <handler>
94+
then <value> is passed to the calling handler as the return value of the
95+
<function>, or value of the property.
96+
97+
The value form of the <return> <control structure> always sets <the result> to
98+
empty. If it is used within a <command> or <message> handler then the <it>
99+
variable in the calling handler will be set to <value>. If it is used within a
100+
<function> handler, then <value> is passed to the calling handler as the return
101+
value of the <function>, or value of the property.
102+
103+
The error form of the <return> <control structure> sets <the result> to <value>.
104+
If it is used within a <command> or <message> handler, then the <it> variable
105+
in the calling handler will be set to empty. If it is used within a <function>
106+
handler, then the return value of the <function> or the value of the property is
107+
returned as empty.
108+
109+
*Note:* The value and error forms can only be used within message, command and
110+
function handlers - not getProp or setProp handlers.
111+
112+
When a message handler executes a <return> <statement>, the <message> stops and
113+
is not <pass|passed> to the next <object(glossary)> in the <message path>. To
114+
halt the current <message handler> and <pass> the <message> on through the
115+
<message path>, use the <pass> <control structure> instead. To halt the current
116+
<handler> without returning a value, use the <exit> <control structure>
117+
instead.
118+
119+
The <return error> and <return value> forms of the <return> command allow much
120+
easier scripting of the distinction between a return value of a handler call,
121+
and an error return value of a handler call. If a command or function <handler>
122+
succeeds, then the 'return value' form should be used to return the result of
123+
the execution to the calling <handler>. If a command or function <handler> fails,
124+
then the 'return error' form should be used to return an error status to the
125+
calling <handler>.
126+
127+
Any callers of handlers using the new error and value forms of the <return>
128+
command can uniformly check <the result> is empty to determine if the
129+
operation succeeded, and if it did then either <it> or the return value can be
130+
processed to continue operation.
131+
132+
>*Note:* The <return> <control structure> is implemented internally as a
133+
<command> and appears in the <commandNames>.
134+
135+
References: object (glossary), return (constant), result (function),
136+
commandNames (function), value (function), merge (function),
137+
the result (function), message handler (glossary), return (glossary),
138+
call (glossary), property (glossary), pass (glossary), execute (glossary),
139+
command (glossary), control structure (glossary), message path (glossary),
140+
caller (glossary), message (glossary), statement (glossary), handler (glossary),
141+
setProp (control structure), getProp (control structure),
142+
throw (control structure), if (control structure), pass (control structure),
143+
exit (control structure), on (control structure), function (control structure)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Improved return command
2+
The 'return' command has had two new forms added:
3+
4+
return value <value>
5+
return error <value>
6+
7+
When running in a command handler, the 'return value' form will cause execution
8+
of the handler to halt, and control to return to the calling handler. At this
9+
point the 'it' variable in the calling handler will be set to 'value' and
10+
'the result' will be set to empty. In contrast, the 'return error' form will
11+
cause the 'it' variable in the calling handler to be set to empty and
12+
'the result' to be set to 'value'.
13+
14+
When running in a function handler, the 'return value' form will cause execution
15+
of the handler to halt, and control to return to the calling handler. At this
16+
point the return value of the function call will be 'value', and 'the result'
17+
will be set to empty. In contrast, the 'return error' form will cause the
18+
return value of the function call to be empty, and 'the result' will be set to
19+
'value'.
20+
21+
These forms of return are designed to be used by script library functions to
22+
allow them to have the same ability as built-in engine functions and commands -
23+
namely the ability to return a value (in it for commands, or return value for
24+
functions) *or* return a status (in the result).

engine/src/cmds.cpp

Lines changed: 74 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,46 +1275,58 @@ void MCReset::compile(MCSyntaxFactoryRef ctxt)
12751275
MCReturn::~MCReturn()
12761276
{
12771277
delete source;
1278-
delete url;
1279-
delete var;
1278+
delete extra_source;
12801279
}
12811280

12821281
Parse_stat MCReturn::parse(MCScriptPoint &sp)
12831282
{
12841283
initpoint(sp);
1285-
if (sp.parseexp(False, True, &source) != PS_NORMAL)
1284+
if (sp.skip_token(SP_SUGAR, TT_UNDEFINED, SG_VALUE) == PS_NORMAL)
1285+
{
1286+
kind = kReturnValue;
1287+
}
1288+
else if (sp.skip_token(SP_SUGAR, TT_UNDEFINED, SG_ERROR) == PS_NORMAL)
1289+
{
1290+
kind = kReturnError;
1291+
}
1292+
else
1293+
{
1294+
kind = kReturn;
1295+
}
1296+
1297+
if (sp.parseexp(False, True, &source) != PS_NORMAL)
12861298
{
12871299
MCperror->add
12881300
(PE_RETURN_BADEXP, sp);
12891301
return PS_ERROR;
12901302
}
1291-
if (sp.skip_token(SP_REPEAT, TT_UNDEFINED, RF_WITH) == PS_NORMAL)
1292-
{
1293-
if (sp.skip_token(SP_FACTOR, TT_CHUNK, CT_URL))
1294-
{
1295-
// MW-2011-06-22: [[ SERVER ]] Update to use SP findvar method to take into account
1296-
// execution outwith a handler.
1297-
Symbol_type type;
1298-
if (sp.next(type) != PS_NORMAL || sp.findvar(sp.gettoken_nameref(), &var) != PS_NORMAL)
1299-
sp.backup();
1300-
else
1301-
var->parsearray(sp);
1302-
}
1303-
if (var == NULL)
1304-
{
1305-
sp.skip_token(SP_FACTOR, TT_FUNCTION, F_CACHED_URLS);
1306-
if (sp.parseexp(False, True, &url) != PS_NORMAL)
1307-
{
1308-
MCperror->add
1309-
(PE_RETURN_BADEXP, sp);
1310-
return PS_ERROR;
1311-
}
1312-
}
1303+
1304+
if (kind == kReturn &&
1305+
sp.skip_token(SP_REPEAT, TT_UNDEFINED, RF_WITH) == PS_NORMAL)
1306+
{
1307+
kind = kReturnWithUrlResult;
1308+
if (sp.skip_token(SP_SUGAR, TT_UNDEFINED, SG_URL_RESULT) == PS_NORMAL)
1309+
;
1310+
if (sp.parseexp(False, True, &extra_source) != PS_NORMAL)
1311+
{
1312+
MCperror->add(PE_RETURN_BADEXP, sp);
1313+
return PS_ERROR;
1314+
}
13131315
}
1316+
1317+
Handler_type t_handler_type;
1318+
t_handler_type = sp.gethandler()->gettype();
1319+
if (kind != kReturn &&
1320+
t_handler_type != HT_MESSAGE &&
1321+
t_handler_type != HT_FUNCTION)
1322+
{
1323+
MCperror->add(PE_RETURN_BADFORMINCONTEXT, sp);
1324+
return PS_ERROR;
1325+
}
1326+
13141327
return PS_NORMAL;
13151328
}
13161329

1317-
13181330
// MW-2007-07-03: [[ Bug 4570 ]] - Using the return command now causes a
13191331
// RETURN_HANDLER status rather than EXIT_HANDLER. This is used to not
13201332
// clear the result in this case. (see MCHandler::exec).
@@ -1325,23 +1337,27 @@ void MCReturn::exec_ctxt(MCExecContext &ctxt)
13251337
if (!ctxt . EvalExprAsValueRef(source, EE_RETURN_BADEXP, &t_result))
13261338
return;
13271339

1328-
if (url != nil)
1329-
{
1330-
MCAutoValueRef t_url_result;
1331-
if (!ctxt . EvalExprAsValueRef(url, EE_RETURN_BADEXP, &t_url_result))
1340+
if (kind == kReturn)
1341+
{
1342+
MCEngineExecReturn(ctxt, *t_result);
1343+
}
1344+
else if (kind == kReturnValue)
1345+
{
1346+
MCEngineExecReturnValue(ctxt, *t_result);
1347+
}
1348+
else if (kind == kReturnError)
1349+
{
1350+
MCEngineExecReturnError(ctxt, *t_result);
1351+
}
1352+
else if (kind == kReturnWithUrlResult)
1353+
{
1354+
MCAutoValueRef t_extra_result;
1355+
if (!ctxt . EvalExprAsValueRef(extra_source, EE_RETURN_BADEXP, &t_extra_result))
13321356
return;
1357+
1358+
MCNetworkExecReturnValueAndUrlResult(ctxt, *t_result, *t_extra_result);
1359+
}
13331360

1334-
MCNetworkExecReturnValueAndUrlResult(ctxt, *t_result, *t_url_result);
1335-
}
1336-
else if (var != nil)
1337-
{
1338-
MCNetworkExecReturnValueAndUrlResultFromVar(ctxt, *t_result, var);
1339-
}
1340-
else
1341-
{
1342-
MCEngineExecReturnValue(ctxt, *t_result);
1343-
}
1344-
13451361
if (!ctxt . HasError())
13461362
ctxt . SetIsReturnHandler();
13471363
}
@@ -1357,18 +1373,23 @@ void MCReturn::compile(MCSyntaxFactoryRef ctxt)
13571373

13581374
source -> compile(ctxt);
13591375

1360-
if (url != nil)
1361-
{
1362-
url -> compile(ctxt);
1363-
MCSyntaxFactoryExecMethod(ctxt, kMCNetworkExecReturnValueAndUrlResultMethodInfo);
1364-
}
1365-
else if (var != nil)
1366-
{
1367-
MCSyntaxFactoryEvalConstant(ctxt, var);
1368-
MCSyntaxFactoryExecMethod(ctxt, kMCNetworkExecReturnValueAndUrlResultFromVarMethodInfo);
1369-
}
1370-
else
1371-
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecReturnValueMethodInfo);
1376+
if (kind == kReturn)
1377+
{
1378+
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecReturnMethodInfo);
1379+
}
1380+
else if (kind == kReturnValue)
1381+
{
1382+
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecReturnValueMethodInfo);
1383+
}
1384+
else if (kind == kReturnError)
1385+
{
1386+
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecReturnErrorMethodInfo);
1387+
}
1388+
else if (kind == kReturnWithUrlResult)
1389+
{
1390+
extra_source -> compile(ctxt);
1391+
MCSyntaxFactoryExecMethod(ctxt, kMCNetworkExecReturnValueAndUrlResultMethodInfo);
1392+
}
13721393

13731394
MCSyntaxFactoryEndStatement(ctxt);
13741395
}

engine/src/cmds.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,22 @@ class MCReset : public MCStatement
317317

318318
class MCReturn : public MCStatement
319319
{
320+
enum Kind
321+
{
322+
kReturn,
323+
kReturnValue,
324+
kReturnError,
325+
kReturnWithUrlResult,
326+
};
320327
MCExpression *source;
321-
MCExpression *url;
322-
MCVarref *var;
328+
MCExpression *extra_source;
329+
Kind kind;
323330
public:
324331
MCReturn()
325332
{
326-
source = url = NULL;
327-
var = NULL;
333+
source = NULL;
334+
extra_source = NULL;
335+
kind = kReturn;
328336
}
329337
virtual ~MCReturn();
330338
virtual Parse_stat parse(MCScriptPoint &);

0 commit comments

Comments
 (0)