Created
September 16, 2014 17:10
-
-
Save nikic/c02f84105a393737c89d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h | |
index 2a1582c..b571ee1 100644 | |
--- a/Zend/zend_ast.h | |
+++ b/Zend/zend_ast.h | |
@@ -115,6 +115,7 @@ enum _zend_ast_kind { | |
ZEND_AST_NEW, | |
ZEND_AST_INSTANCEOF, | |
ZEND_AST_YIELD, | |
+ ZEND_AST_COALESCE, | |
ZEND_AST_STATIC, | |
ZEND_AST_WHILE, | |
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c | |
index 0f91a81..2ecadb6 100644 | |
--- a/Zend/zend_compile.c | |
+++ b/Zend/zend_compile.c | |
@@ -6922,6 +6922,30 @@ void zend_compile_conditional(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ | |
} | |
/* }}} */ | |
+void zend_compile_coalesce(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ | |
+{ | |
+ zend_ast *expr_ast = ast->child[0]; | |
+ zend_ast *default_ast = ast->child[1]; | |
+ | |
+ znode expr_node, default_node; | |
+ zend_op *opline; | |
+ uint32_t opnum; | |
+ | |
+ zend_compile_var(&expr_node, expr_ast, BP_VAR_IS TSRMLS_CC); | |
+ | |
+ opnum = get_next_op_number(CG(active_op_array)); | |
+ zend_emit_op(result, ZEND_COALESCE, &expr_node, NULL TSRMLS_CC); | |
+ | |
+ zend_compile_expr(&default_node, default_ast TSRMLS_CC); | |
+ | |
+ opline = zend_emit_op(NULL, ZEND_QM_ASSIGN, &default_node, NULL TSRMLS_CC); | |
+ SET_NODE(opline->result, result); | |
+ | |
+ opline = &CG(active_op_array)->opcodes[opnum]; | |
+ opline->op2.opline_num = get_next_op_number(CG(active_op_array)); | |
+} | |
+/* }}} */ | |
+ | |
void zend_compile_print(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ | |
{ | |
zend_ast *expr_ast = ast->child[0]; | |
@@ -7759,6 +7783,9 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ | |
case ZEND_AST_CONDITIONAL: | |
zend_compile_conditional(result, ast TSRMLS_CC); | |
return; | |
+ case ZEND_AST_COALESCE: | |
+ zend_compile_coalesce(result, ast TSRMLS_CC); | |
+ return; | |
case ZEND_AST_PRINT: | |
zend_compile_print(result, ast TSRMLS_CC); | |
return; | |
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y | |
index 6bfef22..97fc4de 100644 | |
--- a/Zend/zend_language_parser.y | |
+++ b/Zend/zend_language_parser.y | |
@@ -67,6 +67,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); | |
%right T_YIELD | |
%left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL T_POW_EQUAL | |
%left '?' ':' | |
+%right T_COALESCE | |
%left T_BOOLEAN_OR | |
%left T_BOOLEAN_AND | |
%left '|' | |
@@ -221,6 +222,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); | |
%token T_NS_C "__NAMESPACE__ (T_NS_C)" | |
%token T_NS_SEPARATOR "\\ (T_NS_SEPARATOR)" | |
%token T_ELLIPSIS "... (T_ELLIPSIS)" | |
+%token T_COALESCE "?? (T_COALESCE)" | |
%token T_POW "** (T_POW)" | |
%token T_POW_EQUAL "**= (T_POW_EQUAL)" | |
@@ -827,6 +829,8 @@ expr_without_variable: | |
{ $$ = zend_ast_create(ZEND_AST_CONDITIONAL, $1, $3, $5); } | |
| expr '?' ':' expr | |
{ $$ = zend_ast_create(ZEND_AST_CONDITIONAL, $1, NULL, $4); } | |
+ | expr T_COALESCE expr | |
+ { $$ = zend_ast_create(ZEND_AST_COALESCE, $1, $3); } | |
| internal_functions_in_yacc { $$ = $1; } | |
| T_INT_CAST expr { $$ = zend_ast_create_cast(IS_LONG, $2); } | |
| T_DOUBLE_CAST expr { $$ = zend_ast_create_cast(IS_DOUBLE, $2); } | |
diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l | |
index bcc341e..3da8406 100644 | |
--- a/Zend/zend_language_scanner.l | |
+++ b/Zend/zend_language_scanner.l | |
@@ -1202,6 +1202,10 @@ NEWLINE ("\r"|"\n"|"\r\n") | |
return T_ELLIPSIS; | |
} | |
+<ST_IN_SCRIPTING>"??" { | |
+ return T_COALESCE; | |
+} | |
+ | |
<ST_IN_SCRIPTING>"new" { | |
return T_NEW; | |
} | |
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c | |
index d57721e..8c294f1 100644 | |
--- a/Zend/zend_opcode.c | |
+++ b/Zend/zend_opcode.c | |
@@ -738,6 +738,7 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) | |
case ZEND_JMPZ_EX: | |
case ZEND_JMPNZ_EX: | |
case ZEND_JMP_SET: | |
+ case ZEND_COALESCE: | |
case ZEND_NEW: | |
case ZEND_FE_RESET: | |
case ZEND_FE_FETCH: | |
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h | |
index a3ae246..d28227e 100644 | |
--- a/Zend/zend_vm_def.h | |
+++ b/Zend/zend_vm_def.h | |
@@ -5238,6 +5238,41 @@ ZEND_VM_HANDLER(152, ZEND_JMP_SET, CONST|TMP|VAR|CV, ANY) | |
ZEND_VM_NEXT_OPCODE(); | |
} | |
+ZEND_VM_HANDLER(169, ZEND_COALESCE, CONST|TMP|VAR|CV, ANY) | |
+{ | |
+ USE_OPLINE | |
+ zend_free_op free_op1; | |
+ zval *value; | |
+ int is_ref = 0; | |
+ | |
+ SAVE_OPLINE(); | |
+ value = GET_OP1_ZVAL_PTR(BP_VAR_IS); | |
+ | |
+ if ((OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) && Z_ISREF_P(value)) { | |
+ is_ref = 1; | |
+ value = Z_REFVAL_P(value); | |
+ } | |
+ | |
+ if (Z_TYPE_P(value) > IS_NULL) { | |
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value); | |
+ if (OP1_TYPE == IS_CONST) { | |
+ if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) { | |
+ zval_copy_ctor_func(EX_VAR(opline->result.var)); | |
+ } | |
+ } else if (OP1_TYPE == IS_CV) { | |
+ if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); | |
+ } else if (OP1_TYPE == IS_VAR && is_ref) { | |
+ if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); | |
+ FREE_OP1(); | |
+ } | |
+ ZEND_VM_JMP(opline->op2.jmp_addr); | |
+ } | |
+ | |
+ FREE_OP1(); | |
+ CHECK_EXCEPTION(); | |
+ ZEND_VM_NEXT_OPCODE(); | |
+} | |
+ | |
ZEND_VM_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY) | |
{ | |
USE_OPLINE | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment