Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:811 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 93035 invoked from network); 8 Apr 2003 21:44:28 -0000 Received: from unknown (HELO carmine.bestweb.net) (209.94.102.73) by pb1.pair.com with SMTP; 8 Apr 2003 21:44:28 -0000 Received: from [192.168.1.101] (ip216-179-71-153.cust.bestweb.net [216.179.71.153]) by carmine.bestweb.net (Postfix) with ESMTP id C5716235CA; Tue, 8 Apr 2003 16:44:18 -0500 (EST) To: internals@lists.php.net Cc: andi@zend.com, Zeev Suraski In-Reply-To: <1049825304.20585.10.camel@hasele> References: <1049764010.24472.618.camel@hasele> <1049769838.24472.719.camel@hasele> <1049825151.20585.8.camel@hasele> <1049825304.20585.10.camel@hasele> Content-Type: multipart/mixed; boundary="=-43GeOyfY2JinzI3E2fwI" Organization: Message-ID: <1049836977.20585.27.camel@hasele> Mime-Version: 1.0 X-Mailer: Ximian Evolution 1.2.3 Date: 08 Apr 2003 17:22:57 -0400 Subject: Re: [PHP-DEV] [PATCH] Allow constant expressions From: sterling@bumblebury.com (Sterling Hughes) --=-43GeOyfY2JinzI3E2fwI Content-Type: text/plain Content-Transfer-Encoding: 7bit The last patch introduced a couple of bugs: 1) global constants weren't allowed, this includes true, false, null, etc. 2) it overrode the default behaviour for var $variable = someconstant; since we're folding these, such initialization cannot reasonably happen (big BC break). Attached is a new patch (hopefully the last one), which fixes these bugs and adds the new functionality. -Sterling On Tue, 2003-04-08 at 14:08, Sterling Hughes wrote: > Yargh, a little debug info got into the last patch. > > Attached is the last patch, minus my little debug stuff. > > > On Tue, 2003-04-08 at 14:05, Sterling Hughes wrote: > > Ok, attached is the updated patch, the result of a conversation between > > myself and Zeev. > > > > *) Class constants are allowed to be operands to constants. However, > > constants must exist within the current class only, and they must be > > defined before usage, so for example: > > > > class simple { > > const second = 1; > > const minute = 60 * second; > > const hour = 60 * minute; > > const day = 24 * hour; > > } > > > > Would work. > > > > However: > > > > class simple { > > const minute = second * 60; > > const second = 1; > > } > > > > Wouldn't, and neither would: > > > > class simple { > > const foo = "bar"; > > } > > > > class simple1 { > > const baz = "bar" . foo; > > } > > > > Currently, referencing the current class also doesn't work, ie, > > > > class simple { > > const bar = "baz"; > > const foo = simple::bar . "naz"; > > } > > > > Although that could be added. > > > > It is also important to note that const is now *fully* compile time, > > therefore const cannot, for example, reference a define() which is > > called above (because define() is runtime). > > > > Also, this patch removes the ability to use operators in array > > initialization, as a bunch of people seem to have found that behaviour > > distasteful. Patch attached. > > > > > > On Mon, 2003-04-07 at 22:43, Sterling Hughes wrote: > > > I've updated my patch (attached), which allows for parentheses groupings > > > such as : > > > > > > const foo = (1<<2) | (2 & 5); > > > > > > -Sterling > > > > > > On Mon, 2003-04-07 at 21:06, Sterling Hughes wrote: > > > > Hi, > > > > > > > > The attached patch allows constant expressions within class variables > > > > and constants. I came into this problem when I wanted the following > > > > sequence: > > > > > > > > class foo { > > > > const A = 1<<0; > > > > const B = 1<<1; > > > > const C = 1<<2; > > > > } > > > > > > > > And the current parser doesn't allow such rules. I therefore added the > > > > attached patch which allows operators to be used on constants within > > > > these expressions (and also within array declarations). This is > > > > achieved by folding statements such as '1<<0' into their equivalent > > > > values at compile time. The following operators are supported: << >> | > > > > & + - * / . % ^ ~ xor > > > > > > > > Please review it, and let me know if its ok to commit. :) > > > > > > > > -Sterling -- "Science is like sex: sometimes something useful comes out, but that is not the reason we are doing it." - Richard Feynman --=-43GeOyfY2JinzI3E2fwI Content-Disposition: attachment; filename=constant.diff Content-Type: text/x-patch; name=constant.diff; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Index: zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.408 diff -u -r1.408 zend_compile.c --- zend_compile.c 3 Apr 2003 14:44:41 -0000 1.408 +++ zend_compile.c 8 Apr 2003 21:40:19 -0000 @@ -166,6 +166,43 @@ } +void zend_do_fold_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC) +{ + int (*do_op)(zval *, zval *, zval *); + zend_op *opline; + + if (op == ZEND_SL) { + do_op = shift_left_function; + } else if (op == ZEND_SR) { + do_op = shift_right_function; + } else if (op == ZEND_BW_OR) { + do_op = bitwise_or_function; + } else if (op == ZEND_BW_AND) { + do_op = bitwise_and_function; + } else if (op == ZEND_BW_XOR) { + do_op = bitwise_xor_function; + } else if (op == ZEND_CONCAT) { + do_op = concat_function; + } else if (op == ZEND_ADD) { + do_op = add_function; + } else if (op == ZEND_SUB) { + do_op = sub_function; + } else if (op == ZEND_MUL) { + do_op = mul_function; + } else if (op == ZEND_DIV) { + do_op = div_function; + } else if (op == ZEND_MOD) { + do_op = mod_function; + } else if (op == ZEND_BW_NOT) { + bitwise_not_function(&result->u.constant, &op1->u.constant); + return; + } else if (op == ZEND_BOOL_XOR) { + do_op = boolean_xor_function; + } + + do_op(&result->u.constant, &op1->u.constant, &op2->u.constant); +} + void zend_do_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC) { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -2518,6 +2555,23 @@ *result = CG(active_op_array)->opcodes[new_token->u.opline_num].op1; } +void zend_do_fold_constant(znode *result, znode *constant_name TSRMLS_DC) +{ + zval **zresult; + + if (zend_hash_find(&CG(active_class_entry)->constants_table, constant_name->u.constant.value.str.val, + constant_name->u.constant.value.str.len+1, (void **) &zresult) != SUCCESS) { + if (zend_get_constant(constant_name->u.constant.value.str.val, constant_name->u.constant.value.str.len, &result->u.constant)) { + return; + } else { + zend_error(E_COMPILE_ERROR, "Cannot find %s constant in class %s\n", + constant_name->u.constant.value.str.val, CG(active_class_entry)->name); + } + } + + result->u.constant = **zresult; + zval_copy_ctor(&result->u.constant); +} void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode TSRMLS_DC) { Index: zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.235 diff -u -r1.235 zend_compile.h --- zend_compile.h 7 Apr 2003 21:48:17 -0000 1.235 +++ zend_compile.h 8 Apr 2003 21:40:21 -0000 @@ -274,6 +274,7 @@ /* parser-driven code generators */ +void zend_do_fold_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); void zend_do_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); void zend_do_unary_op(zend_uchar op, znode *result, znode *op1 TSRMLS_DC); void zend_do_binary_assign_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); Index: zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.110 diff -u -r1.110 zend_language_parser.y --- zend_language_parser.y 2 Apr 2003 16:51:49 -0000 1.110 +++ zend_language_parser.y 8 Apr 2003 21:40:23 -0000 @@ -332,8 +332,8 @@ ; namespace_const_declaration: - namespace_const_declaration ',' T_STRING '=' static_scalar { zend_do_declare_namespace_constant(&$3, &$5 TSRMLS_CC); } - | T_CONST T_STRING '=' static_scalar { zend_do_declare_namespace_constant(&$2, &$4 TSRMLS_CC); } + namespace_const_declaration ',' T_STRING '=' const_scalar_expr { zend_do_declare_namespace_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' const_scalar_expr { zend_do_declare_namespace_constant(&$2, &$4 TSRMLS_CC); } ; extends_from: @@ -545,8 +545,8 @@ ; class_constant_declaration: - class_constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); } - | T_CONST T_STRING '=' static_scalar { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); } + class_constant_declaration ',' T_STRING '=' const_scalar_expr { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' const_scalar_expr { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); } ; echo_expr_list: @@ -700,15 +700,45 @@ ; +const_scalar_expr: /* compile-time evaluated scalar expressions */ + const_scalar { $$ = $1; } + | const_scalar_expr_list { $$ = $1; } +; + +const_scalar_expr_list: + const_scalar_expr T_SL const_scalar_expr { zend_do_fold_binary_op(ZEND_SL, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr T_SR const_scalar_expr { zend_do_fold_binary_op(ZEND_SR, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr T_LOGICAL_XOR const_scalar_expr { zend_do_fold_binary_op(ZEND_BOOL_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '|' const_scalar_expr { zend_do_fold_binary_op(ZEND_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '&' const_scalar_expr { zend_do_fold_binary_op(ZEND_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '^' const_scalar_expr { zend_do_fold_binary_op(ZEND_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '.' const_scalar_expr { zend_do_fold_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '+' const_scalar_expr { zend_do_fold_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '-' const_scalar_expr { zend_do_fold_binary_op(ZEND_SUB, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '*' const_scalar_expr { zend_do_fold_binary_op(ZEND_MUL, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '/' const_scalar_expr { zend_do_fold_binary_op(ZEND_DIV, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '%' const_scalar_expr { zend_do_fold_binary_op(ZEND_MOD, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '~' const_scalar_expr { zend_do_fold_binary_op(ZEND_BW_NOT, &$$, &$1, &$3 TSRMLS_CC); } + | '(' const_scalar_expr ')' { $$ = $2; } +; + +const_scalar: + common_scalar { $$ = $1; } + | T_STRING { zend_do_fold_constant(&$$, &$1 TSRMLS_CC); } + | '+' const_scalar { $$ = $2; } + | '-' const_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; } + | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; $$.u.constant.type = IS_CONSTANT_ARRAY; } + | class_or_namespace_constant { /* FIXME */ } +; + static_scalar: /* compile-time evaluated scalars */ common_scalar { $$ = $1; } | T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT TSRMLS_CC); } | '+' static_scalar { $$ = $2; } - | '-' static_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; } + | '-' static_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; } | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; $$.u.constant.type = IS_CONSTANT_ARRAY; } | class_or_namespace_constant { /* FIXME */ } ; - scalar: T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT TSRMLS_CC); } --=-43GeOyfY2JinzI3E2fwI--