Permalink
Browse files

Add Array Attribute Type Descriptors

Adds the ability to type keys and values when declaring array
attributes in XHP. The format follows standard Map type declarations:

```
attribute array<int> intValuesOnly;
attribute array<string => Foo> stringKeysAndFooInstanceValuesOnly;
```

The supported keys are just `int` and `string`, and the supported
values are `int`, `float`, `bool`, `string`, `array`, and class names.
There is no nesting of types yet. If people really want that it won't
be too hard to add.
  • Loading branch information...
1 parent 177b52d commit 14bdf9917ac762217de8bbdeefdc41870e33cbff @Swahvay Swahvay committed Nov 14, 2013
Showing with 144 additions and 0 deletions.
  1. +73 −0 php-lib/core.php
  2. +15 −0 tests/anonymous_function.phpt
  3. +20 −0 tests/array-types.phpt
  4. +36 −0 xhp/parser.y
View
@@ -498,6 +498,54 @@ protected function &__xhpChildrenDeclaration() {
if (!is_array($val)) {
throw new XHPInvalidAttributeException($this, 'array', $attr, $val);
}
+ if ($decl[$attr][1]) {
+ if ($decl[$attr][1][0]) {
+ if ($decl[$attr][1][0] == self::TYPE_STRING) {
+ $type = 'string';
+ $func = 'is_string';
+ } else {
+ $type = 'int';
+ $func = 'is_int';
+ }
+ if (count($val) != count(array_filter(array_keys($val), $func))) {
+ $bad = $type == 'string' ? 'int' : 'string';
+ throw new XHPInvalidArrayKeyAttributeException($this, $type, $attr, $bad);
+ }
+ }
+ switch ($decl[$attr][1][1]) {
+ case self::TYPE_STRING:
+ $type = 'string';
+ $func = 'is_string';
+ break;
+ case self::TYPE_BOOL:
+ $type = 'bool';
+ $func = 'is_bool';
+ break;
+ case self::TYPE_NUMBER:
+ $type = 'int';
+ $func = 'is_int';
+ break;
+ case self::TYPE_FLOAT:
+ $type = 'float';
+ $func = 'is_numeric';
+ break;
+ case self::TYPE_ARRAY:
+ $type = 'array';
+ $func = 'is_array';
+ break;
+ case self::TYPE_OBJECT:
+ $type = $decl[$attr][1][2];
+ $func = function($item) use ($type) {
+ return $item instanceof $type;
+ };
+ break;
+ }
+ $filtered = array_filter($val, $func);
+ if (count($val) != count($filtered)) {
+ $bad = array_diff($val, $filtered);
+ throw new XHPInvalidArrayAttributeException($this, $type, $attr, reset($bad));
+ }
+ }
return;
case self::TYPE_OBJECT:
@@ -849,6 +897,31 @@ public function __construct($that, $rend) {
class XHPRenderArrayException extends XHPException {
}
+class XHPInvalidArrayAttributeException extends XHPException {
+ public function __construct($that, $type, $attr, $val) {
+ if (is_object($val)) {
+ $val_type = get_class($val);
+ } else {
+ $val_type = gettype($val);
+ }
+ parent::__construct(
+ "Invalid attribute `$attr` of type array<`$val_type`> supplied to element `".
+ :x:base::class2element(get_class($that))."`, expected array<`$type`>.\n\n".
+ $that->source
+ );
+ }
+}
+
+class XHPInvalidArrayKeyAttributeException extends XHPException {
+ public function __construct($that, $type, $attr, $val_type) {
+ parent::__construct(
+ "Invalid key in attribute `$attr` of type array<$val_type => ?> supplied to element `".
+ :x:base::class2element(get_class($that))."`, expected array<$type => ?>.\n\n".
+ $that->source
+ );
+ }
+}
+
class XHPAttributeNotSupportedException extends XHPException {
public function __construct($that, $attr) {
parent::__construct(
@@ -0,0 +1,15 @@
+--TEST--
+Anonymous Functions
+--SKIPIF--
+<?php
+if (version_compare(PHP_VERSION, '5.2', '<')) exit("Skip This test is for PHP 5.3 only.");
+?>
+--FILE--
+<?php
+$one = 1;
+$func = function($two) use ($one) {
+ return $one + $two;
+};
+echo $func(2);
+--EXPECT--
+3
View
@@ -0,0 +1,20 @@
+--TEST--
+Types in Array
+--FILE--
+<?php
+class Foo {}
+class :x {
+ attribute
+ array<int> a,
+ array<float> b,
+ array<string> c,
+ array<bool> d,
+ array<array> e,
+ array<Foo> f,
+ array<string => int> g,
+ array<int => string> h;
+}
+$x = <x a={array(1)} />;
+echo 'pass';
+--EXPECT--
+pass
View
@@ -1951,6 +1951,12 @@ xhp_attribute_decl_type:
| T_XHP_NUMBER {
$$ = "3, null";
}
+| T_XHP_ARRAY '<' xhp_attribute_array_key_type T_DOUBLE_ARROW xhp_attribute_array_type '>' {
+ $$ = "4, array(" + $3 + ", " + $5 + ")";
+ }
+| T_XHP_ARRAY '<' xhp_attribute_array_type '>' {
+ $$ = "4, array(null, " + $3 + ")";
+ }
| T_XHP_ARRAY {
$$ = "4, null";
}
@@ -1971,6 +1977,36 @@ xhp_attribute_decl_type:
}
;
+xhp_attribute_array_key_type:
+ T_XHP_STRING {
+ $$ = "1";
+ }
+| T_XHP_NUMBER {
+ $$ = "3";
+ }
+;
+
+xhp_attribute_array_type:
+ T_XHP_STRING {
+ $$ = "1";
+ }
+| T_XHP_BOOLEAN {
+ $$ = "2";
+ }
+| T_XHP_NUMBER {
+ $$ = "3";
+ }
+| T_XHP_ARRAY {
+ $$ = "4";
+ }
+| class_name {
+ $$ = "5, '" + $1 + "'";
+ }
+| T_XHP_FLOAT {
+ $$ = "8";
+ }
+;
+
xhp_attribute_enum:
common_scalar {
$1.strip_lines();

0 comments on commit 14bdf99

Please sign in to comment.