Skip to content

Commit 501a9e6

Browse files
committed
Make throw statement an expression
1 parent 4b8171e commit 501a9e6

File tree

5 files changed

+155
-8
lines changed

5 files changed

+155
-8
lines changed

Zend/tests/throw/001.phpt

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
--TEST--
2+
throw expression
3+
--FILE--
4+
<?php
5+
6+
try {
7+
$result = true && throw new Exception("true && throw");
8+
var_dump($result);
9+
} catch (Exception $e) {
10+
var_dump($e->getMessage());
11+
}
12+
13+
try {
14+
$result = true || throw new Exception("true || throw");
15+
var_dump($result);
16+
} catch (Exception $e) {
17+
var_dump($e->getMessage());
18+
}
19+
20+
try {
21+
$result = false && throw new Exception("false && throw");
22+
var_dump($result);
23+
} catch (Exception $e) {
24+
var_dump($e->getMessage());
25+
}
26+
27+
try {
28+
$result = false || throw new Exception("false || throw");
29+
var_dump($result);
30+
} catch (Exception $e) {
31+
var_dump($e->getMessage());
32+
}
33+
34+
try {
35+
$result = null ?? throw new Exception("null ?? throw");
36+
var_dump($result);
37+
} catch (Exception $e) {
38+
var_dump($e->getMessage());
39+
}
40+
41+
try {
42+
$result = "foo" ?? throw new Exception('"foo" ?? throw');
43+
var_dump($result);
44+
} catch (Exception $e) {
45+
var_dump($e->getMessage());
46+
}
47+
48+
try {
49+
$result = null ?: throw new Exception("null ?: throw");
50+
var_dump($result);
51+
} catch (Exception $e) {
52+
var_dump($e->getMessage());
53+
}
54+
55+
try {
56+
$result = "foo" ?: throw new Exception('"foo" ?: throw');
57+
var_dump($result);
58+
} catch (Exception $e) {
59+
var_dump($e->getMessage());
60+
}
61+
62+
try {
63+
$callable = fn() => throw new Exception("fn() => throw");
64+
var_dump("not yet");
65+
$callable();
66+
} catch (Exception $e) {
67+
var_dump($e->getMessage());
68+
}
69+
70+
$result = "bar";
71+
try {
72+
$result = throw new Exception();
73+
} catch (Exception $e) {}
74+
var_dump($result);
75+
76+
try {
77+
var_dump(
78+
throw new Exception("exception 1"),
79+
throw new Exception("exception 2")
80+
);
81+
} catch (Exception $e) {
82+
var_dump($e->getMessage());
83+
}
84+
85+
try {
86+
$result = true ? true : throw new Exception("true ? true : throw");
87+
var_dump($result);
88+
} catch (Exception $e) {
89+
var_dump($e->getMessage());
90+
}
91+
92+
try {
93+
$result = false ? true : throw new Exception("false ? true : throw");
94+
var_dump($result);
95+
} catch (Exception $e) {
96+
var_dump($e->getMessage());
97+
}
98+
99+
try {
100+
throw new Exception() + 1;
101+
} catch (Throwable $e) {
102+
var_dump($e->getMessage());
103+
}
104+
105+
try {
106+
throw $exception = new Exception('throw $exception = new Exception();');
107+
} catch (Exception $e) {}
108+
var_dump($exception->getMessage());
109+
110+
try {
111+
$exception = null;
112+
throw $exception ??= new Exception('throw $exception ??= new Exception();');
113+
} catch (Exception $e) {}
114+
var_dump($exception->getMessage());
115+
116+
try {
117+
throw null ?? new Exception('throw null ?? new Exception();');
118+
} catch (Exception $e) {
119+
var_dump($e->getMessage());
120+
}
121+
122+
?>
123+
--EXPECTF--
124+
string(13) "true && throw"
125+
bool(true)
126+
bool(false)
127+
string(14) "false || throw"
128+
string(13) "null ?? throw"
129+
string(3) "foo"
130+
string(13) "null ?: throw"
131+
string(3) "foo"
132+
string(7) "not yet"
133+
string(13) "fn() => throw"
134+
string(3) "bar"
135+
string(11) "exception 1"
136+
bool(true)
137+
string(20) "false ? true : throw"
138+
139+
Notice: Object of class Exception could not be converted to number in %s on line %d
140+
string(22) "Can only throw objects"
141+
string(35) "throw $exception = new Exception();"
142+
string(37) "throw $exception ??= new Exception();"
143+
string(30) "throw null ?? new Exception();"

Zend/zend_compile.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4570,14 +4570,17 @@ void zend_compile_echo(zend_ast *ast) /* {{{ */
45704570
}
45714571
/* }}} */
45724572

4573-
void zend_compile_throw(zend_ast *ast) /* {{{ */
4573+
void zend_compile_throw(znode *result, zend_ast *ast) /* {{{ */
45744574
{
45754575
zend_ast *expr_ast = ast->child[0];
45764576

45774577
znode expr_node;
45784578
zend_compile_expr(&expr_node, expr_ast);
45794579

45804580
zend_emit_op(NULL, ZEND_THROW, &expr_node, NULL);
4581+
4582+
result->op_type = IS_CONST;
4583+
ZVAL_BOOL(&result->u.constant, 1);
45814584
}
45824585
/* }}} */
45834586

@@ -8753,9 +8756,6 @@ void zend_compile_stmt(zend_ast *ast) /* {{{ */
87538756
case ZEND_AST_ECHO:
87548757
zend_compile_echo(ast);
87558758
break;
8756-
case ZEND_AST_THROW:
8757-
zend_compile_throw(ast);
8758-
break;
87598759
case ZEND_AST_BREAK:
87608760
case ZEND_AST_CONTINUE:
87618761
zend_compile_break_continue(ast);
@@ -8965,6 +8965,9 @@ void zend_compile_expr(znode *result, zend_ast *ast) /* {{{ */
89658965
case ZEND_AST_ARROW_FUNC:
89668966
zend_compile_func_decl(result, ast, 0);
89678967
return;
8968+
case ZEND_AST_THROW:
8969+
zend_compile_throw(result, ast);
8970+
break;
89688971
default:
89698972
ZEND_ASSERT(0 /* not supported */);
89708973
}

Zend/zend_language_parser.y

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
5151
%destructor { zend_ast_destroy($$); } <ast>
5252
%destructor { if ($$) zend_string_release_ex($$, 0); } <str>
5353

54+
%precedence T_THROW
5455
%precedence PREC_ARROW_FUNCTION
5556
%precedence T_INCLUDE T_INCLUDE_ONCE T_REQUIRE T_REQUIRE_ONCE
5657
%left T_LOGICAL_OR
@@ -457,7 +458,6 @@ statement:
457458
| ';' /* empty statement */ { $$ = NULL; }
458459
| T_TRY '{' inner_statement_list '}' catch_list finally_statement
459460
{ $$ = zend_ast_create(ZEND_AST_TRY, $3, $5, $6); }
460-
| T_THROW expr ';' { $$ = zend_ast_create(ZEND_AST_THROW, $2); }
461461
| T_GOTO T_STRING ';' { $$ = zend_ast_create(ZEND_AST_GOTO, $2); }
462462
| T_STRING ':' { $$ = zend_ast_create(ZEND_AST_LABEL, $1); }
463463
;
@@ -1019,6 +1019,7 @@ expr:
10191019
| T_YIELD expr { $$ = zend_ast_create(ZEND_AST_YIELD, $2, NULL); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
10201020
| T_YIELD expr T_DOUBLE_ARROW expr { $$ = zend_ast_create(ZEND_AST_YIELD, $4, $2); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
10211021
| T_YIELD_FROM expr { $$ = zend_ast_create(ZEND_AST_YIELD_FROM, $2); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
1022+
| T_THROW expr { $$ = zend_ast_create(ZEND_AST_THROW, $2); }
10221023
| inline_function { $$ = $1; }
10231024
| T_STATIC inline_function { $$ = $2; ((zend_ast_decl *) $$)->flags |= ZEND_ACC_STATIC; }
10241025
;

ext/tokenizer/tests/token_get_all_variation4.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ array(88) {
8080
[5]=>
8181
array(3) {
8282
[0]=>
83-
int(286)
83+
int(%d)
8484
[1]=>
8585
string(2) "=="
8686
[2]=>

ext/tokenizer/tokenizer_data.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626

2727
void tokenizer_register_constants(INIT_FUNC_ARGS) {
28+
REGISTER_LONG_CONSTANT("T_THROW", T_THROW, CONST_CS | CONST_PERSISTENT);
2829
REGISTER_LONG_CONSTANT("T_INCLUDE", T_INCLUDE, CONST_CS | CONST_PERSISTENT);
2930
REGISTER_LONG_CONSTANT("T_INCLUDE_ONCE", T_INCLUDE_ONCE, CONST_CS | CONST_PERSISTENT);
3031
REGISTER_LONG_CONSTANT("T_REQUIRE", T_REQUIRE, CONST_CS | CONST_PERSISTENT);
@@ -114,7 +115,6 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) {
114115
REGISTER_LONG_CONSTANT("T_TRY", T_TRY, CONST_CS | CONST_PERSISTENT);
115116
REGISTER_LONG_CONSTANT("T_CATCH", T_CATCH, CONST_CS | CONST_PERSISTENT);
116117
REGISTER_LONG_CONSTANT("T_FINALLY", T_FINALLY, CONST_CS | CONST_PERSISTENT);
117-
REGISTER_LONG_CONSTANT("T_THROW", T_THROW, CONST_CS | CONST_PERSISTENT);
118118
REGISTER_LONG_CONSTANT("T_USE", T_USE, CONST_CS | CONST_PERSISTENT);
119119
REGISTER_LONG_CONSTANT("T_INSTEADOF", T_INSTEADOF, CONST_CS | CONST_PERSISTENT);
120120
REGISTER_LONG_CONSTANT("T_GLOBAL", T_GLOBAL, CONST_CS | CONST_PERSISTENT);
@@ -168,6 +168,7 @@ char *get_token_type_name(int token_type)
168168
{
169169
switch (token_type) {
170170

171+
case T_THROW: return "T_THROW";
171172
case T_INCLUDE: return "T_INCLUDE";
172173
case T_INCLUDE_ONCE: return "T_INCLUDE_ONCE";
173174
case T_REQUIRE: return "T_REQUIRE";
@@ -257,7 +258,6 @@ char *get_token_type_name(int token_type)
257258
case T_TRY: return "T_TRY";
258259
case T_CATCH: return "T_CATCH";
259260
case T_FINALLY: return "T_FINALLY";
260-
case T_THROW: return "T_THROW";
261261
case T_USE: return "T_USE";
262262
case T_INSTEADOF: return "T_INSTEADOF";
263263
case T_GLOBAL: return "T_GLOBAL";

0 commit comments

Comments
 (0)