Browse Source

Initial coalesce operator implementation

pull/824/head
Nikita Popov 11 years ago
committed by Andrea Faulds
parent
commit
69e7c9d89c
  1. 1
      Zend/zend_ast.h
  2. 27
      Zend/zend_compile.c
  3. 4
      Zend/zend_language_parser.y
  4. 6058
      Zend/zend_language_scanner.c
  5. 4
      Zend/zend_language_scanner.l
  6. 2
      Zend/zend_language_scanner_defs.h
  7. 1
      Zend/zend_opcode.c
  8. 35
      Zend/zend_vm_def.h
  9. 163
      Zend/zend_vm_execute.h
  10. 3
      Zend/zend_vm_opcodes.c
  11. 1
      Zend/zend_vm_opcodes.h
  12. 1
      main/php_version.h

1
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,

27
Zend/zend_compile.c

@ -6917,6 +6917,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];
@ -7754,6 +7778,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;

4
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); }

6058
Zend/zend_language_scanner.c
File diff suppressed because it is too large
View File

4
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;
}

2
Zend/zend_language_scanner_defs.h

@ -1,4 +1,4 @@
/* Generated by re2c 0.13.5 */
/* Generated by re2c 0.13.6 */
#line 3 "Zend/zend_language_scanner_defs.h"
enum YYCONDTYPE {

1
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:

35
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

163
Zend/zend_vm_execute.h

@ -3303,6 +3303,40 @@ static int ZEND_FASTCALL ZEND_JMP_SET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_AR
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_COALESCE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zval *value;
int is_ref = 0;
SAVE_OPLINE();
value = opline->op1.zv;
if ((IS_CONST == IS_VAR || IS_CONST == 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 (IS_CONST == IS_CONST) {
if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
zval_copy_ctor_func(EX_VAR(opline->result.var));
}
} else if (IS_CONST == IS_CV) {
if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
} else if (IS_CONST == IS_VAR && is_ref) {
if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
}
ZEND_VM_JMP(opline->op2.jmp_addr);
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@ -10040,6 +10074,41 @@ static int ZEND_FASTCALL ZEND_JMP_SET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_COALESCE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op1;
zval *value;
int is_ref = 0;
SAVE_OPLINE();
value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
if ((IS_TMP_VAR == IS_VAR || IS_TMP_VAR == 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 (IS_TMP_VAR == IS_CONST) {
if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
zval_copy_ctor_func(EX_VAR(opline->result.var));
}
} else if (IS_TMP_VAR == IS_CV) {
if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
} else if (IS_TMP_VAR == IS_VAR && is_ref) {
if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
zval_dtor(free_op1.var);
}
ZEND_VM_JMP(opline->op2.jmp_addr);
}
zval_dtor(free_op1.var);
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@ -16910,6 +16979,41 @@ static int ZEND_FASTCALL ZEND_JMP_SET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_COALESCE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op1;
zval *value;
int is_ref = 0;
SAVE_OPLINE();
value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
if ((IS_VAR == IS_VAR || IS_VAR == 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 (IS_VAR == IS_CONST) {
if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
zval_copy_ctor_func(EX_VAR(opline->result.var));
}
} else if (IS_VAR == IS_CV) {
if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
} else if (IS_VAR == IS_VAR && is_ref) {
if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
zval_ptr_dtor_nogc(free_op1.var);
}
ZEND_VM_JMP(opline->op2.jmp_addr);
}
zval_ptr_dtor_nogc(free_op1.var);
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@ -34099,6 +34203,40 @@ static int ZEND_FASTCALL ZEND_JMP_SET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_COALESCE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zval *value;
int is_ref = 0;
SAVE_OPLINE();
value = _get_zval_ptr_cv_BP_VAR_IS(execute_data, opline->op1.var TSRMLS_CC);
if ((IS_CV == IS_VAR || IS_CV == 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 (IS_CV == IS_CONST) {
if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
zval_copy_ctor_func(EX_VAR(opline->result.var));
}
} else if (IS_CV == IS_CV) {
if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
} else if (IS_CV == IS_VAR && is_ref) {
if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
}
ZEND_VM_JMP(opline->op2.jmp_addr);
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@ -47722,6 +47860,31 @@ void zend_init_opcodes_handlers(void)
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_COALESCE_SPEC_CONST_HANDLER,
ZEND_COALESCE_SPEC_CONST_HANDLER,
ZEND_COALESCE_SPEC_CONST_HANDLER,
ZEND_COALESCE_SPEC_CONST_HANDLER,
ZEND_COALESCE_SPEC_CONST_HANDLER,
ZEND_COALESCE_SPEC_TMP_HANDLER,
ZEND_COALESCE_SPEC_TMP_HANDLER,
ZEND_COALESCE_SPEC_TMP_HANDLER,
ZEND_COALESCE_SPEC_TMP_HANDLER,
ZEND_COALESCE_SPEC_TMP_HANDLER,
ZEND_COALESCE_SPEC_VAR_HANDLER,
ZEND_COALESCE_SPEC_VAR_HANDLER,
ZEND_COALESCE_SPEC_VAR_HANDLER,
ZEND_COALESCE_SPEC_VAR_HANDLER,
ZEND_COALESCE_SPEC_VAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_COALESCE_SPEC_CV_HANDLER,
ZEND_COALESCE_SPEC_CV_HANDLER,
ZEND_COALESCE_SPEC_CV_HANDLER,
ZEND_COALESCE_SPEC_CV_HANDLER,
ZEND_COALESCE_SPEC_CV_HANDLER,
ZEND_NULL_HANDLER
};
zend_opcode_handlers = (opcode_handler_t*)labels;

3
Zend/zend_vm_opcodes.c

@ -21,7 +21,7 @@
#include <stdio.h>
#include <zend.h>
const char *zend_vm_opcodes_map[169] = {
const char *zend_vm_opcodes_map[170] = {
"ZEND_NOP",
"ZEND_ADD",
"ZEND_SUB",
@ -191,6 +191,7 @@ const char *zend_vm_opcodes_map[169] = {
"ZEND_POW",
"ZEND_ASSIGN_POW",
"ZEND_BIND_GLOBAL",
"ZEND_COALESCE",
};
ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {

1
Zend/zend_vm_opcodes.h

@ -180,5 +180,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode);
#define ZEND_POW 166
#define ZEND_ASSIGN_POW 167
#define ZEND_BIND_GLOBAL 168
#define ZEND_COALESCE 169
#endif

1
main/php_version.h

@ -6,4 +6,3 @@
#define PHP_EXTRA_VERSION "-dev"
#define PHP_VERSION "7.0.0-dev"
#define PHP_VERSION_ID 70000
Loading…
Cancel
Save