PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/core/ReflectionXHPChildrenDeclaration.php

http://github.com/facebook/xhp
PHP | 199 lines | 166 code | 24 blank | 9 comment | 10 complexity | 025600dac262b5023fc7f3df7b9f1cae MD5 | raw file
Possible License(s): MIT, MPL-2.0-no-copyleft-exception
  1. <?hh // strict
  2. /*
  3. * Copyright (c) 2015, Facebook, Inc.
  4. * All rights reserved.
  5. *
  6. * This source code is licensed under the BSD-style license found in the
  7. * LICENSE file in the root directory of this source tree. An additional grant
  8. * of patent rights can be found in the PATENTS file in the same directory.
  9. *
  10. */
  11. enum XHPChildrenDeclarationType: int {
  12. NO_CHILDREN = 0;
  13. ANY_CHILDREN = 1;
  14. EXPRESSION = ~0;
  15. }
  16. enum XHPChildrenExpressionType: int {
  17. SINGLE = 0; // :thing
  18. ANY_NUMBER = 1; // :thing*
  19. ZERO_OR_ONE = 2; // :thing?
  20. ONE_OR_MORE = 3; // :thing+
  21. SUB_EXPR_SEQUENCE = 4; // (expr, expr)
  22. SUB_EXPR_DISJUNCTION = 5; // (expr | expr)
  23. }
  24. enum XHPChildrenConstraintType: int {
  25. ANY = 1;
  26. PCDATA = 2;
  27. ELEMENT = 3;
  28. CATEGORY = 4;
  29. SUB_EXPR = 5;
  30. }
  31. class ReflectionXHPChildrenDeclaration {
  32. public function __construct(
  33. private string $context,
  34. private mixed $data,
  35. ) {
  36. }
  37. <<__Memoize>>
  38. public function getType(): XHPChildrenDeclarationType {
  39. if (is_array($this->data)) {
  40. return XHPChildrenDeclarationType::EXPRESSION;
  41. }
  42. return XHPChildrenDeclarationType::assert($this->data);
  43. }
  44. <<__Memoize>>
  45. public function getExpression(): ReflectionXHPChildrenExpression {
  46. $data = $this->data;
  47. invariant(
  48. is_array($data),
  49. "Tried to get child expression for XHP class %s, but it does not ".
  50. "have an expression.",
  51. :xhp::class2element(get_class($this->context)),
  52. );
  53. return new ReflectionXHPChildrenExpression(
  54. $this->context,
  55. $data,
  56. );
  57. }
  58. public function __toString(): string {
  59. if ($this->getType() === XHPChildrenDeclarationType::ANY_CHILDREN) {
  60. return 'any';
  61. }
  62. if ($this->getType() === XHPChildrenDeclarationType::NO_CHILDREN) {
  63. return 'empty';
  64. }
  65. return (string) $this->getExpression();
  66. }
  67. }
  68. class ReflectionXHPChildrenExpression {
  69. public function __construct(
  70. private string $context,
  71. private array<int, mixed> $data,
  72. ) {
  73. }
  74. <<__Memoize>>
  75. public function getType(): XHPChildrenExpressionType {
  76. return XHPChildrenExpressionType::assert($this->data[0]);
  77. }
  78. <<__Memoize>>
  79. public function getSubExpressions(
  80. ): (ReflectionXHPChildrenExpression, ReflectionXHPChildrenExpression) {
  81. $type = $this->getType();
  82. invariant(
  83. $type === XHPChildrenExpressionType::SUB_EXPR_SEQUENCE
  84. || $type === XHPChildrenExpressionType::SUB_EXPR_DISJUNCTION,
  85. 'Only disjunctions and sequences have two sub-expressions - in %s',
  86. :xhp::class2element(get_class($this->context)),
  87. );
  88. $sub_expr_1 = $this->data[1];
  89. $sub_expr_2 = $this->data[2];
  90. invariant(
  91. is_array($sub_expr_1) && is_array($sub_expr_2),
  92. 'Data is not subexpressions - in %s',
  93. $this->context,
  94. );
  95. return tuple(
  96. new ReflectionXHPChildrenExpression($this->context, $sub_expr_1),
  97. new ReflectionXHPChildrenExpression($this->context, $sub_expr_2),
  98. );
  99. }
  100. <<__Memoize>>
  101. public function getConstraintType(): XHPChildrenConstraintType {
  102. $type = $this->getType();
  103. invariant(
  104. $type !== XHPChildrenExpressionType::SUB_EXPR_SEQUENCE
  105. && $type !== XHPChildrenExpressionType::SUB_EXPR_DISJUNCTION,
  106. 'Disjunctions and sequences do not have a constraint type - in %s',
  107. :xhp::class2element(get_class($this->context)),
  108. );
  109. return XHPChildrenConstraintType::assert($this->data[1]);
  110. }
  111. <<__Memoize>>
  112. public function getConstraintString(): string {
  113. $type = $this->getConstraintType();
  114. invariant(
  115. $type === XHPChildrenConstraintType::ELEMENT
  116. || $type === XHPChildrenConstraintType::CATEGORY,
  117. 'Only element and category constraints have string data - in %s',
  118. :xhp::class2element(get_class($this->context)),
  119. );
  120. $data = $this->data[2];
  121. invariant(is_string($data), 'Expected string data');
  122. return $data;
  123. }
  124. <<__Memoize>>
  125. public function getSubExpression(): ReflectionXHPChildrenExpression {
  126. invariant(
  127. $this->getConstraintType() === XHPChildrenConstraintType::SUB_EXPR,
  128. 'Only expression constraints have a single sub-expression - in %s',
  129. $this->context,
  130. );
  131. $data = $this->data[2];
  132. invariant(
  133. is_array($data),
  134. 'Expected a sub-expression, got a %s - in %s',
  135. is_object($data) ? get_class($data) : gettype($data),
  136. $this->context,
  137. );
  138. return new ReflectionXHPChildrenExpression(
  139. $this->context,
  140. $data,
  141. );
  142. }
  143. public function __toString(): string {
  144. switch ($this->getType()) {
  145. case XHPChildrenExpressionType::SINGLE:
  146. return $this->__constraintToString();
  147. case XHPChildrenExpressionType::ANY_NUMBER:
  148. return $this->__constraintToString().'*';
  149. case XHPChildrenExpressionType::ZERO_OR_ONE:
  150. return $this->__constraintToString().'?';
  151. case XHPChildrenExpressionType::ONE_OR_MORE:
  152. return $this->__constraintToString().'+';
  153. case XHPChildrenExpressionType::SUB_EXPR_SEQUENCE:
  154. list($e1, $e2) = $this->getSubExpressions();
  155. return $e1.','.$e2;
  156. case XHPChildrenExpressionType::SUB_EXPR_DISJUNCTION:
  157. list($e1, $e2) = $this->getSubExpressions();
  158. return $e1.'|'.$e2;
  159. }
  160. }
  161. private function __constraintToString(): string {
  162. switch ($this->getConstraintType()) {
  163. case XHPChildrenConstraintType::ANY:
  164. return 'any';
  165. case XHPChildrenConstraintType::PCDATA:
  166. return 'pcdata';
  167. case XHPChildrenConstraintType::ELEMENT:
  168. return ':' . :xhp::class2element($this->getConstraintString());
  169. case XHPChildrenConstraintType::CATEGORY:
  170. return '%' . $this->getConstraintString();
  171. case XHPChildrenConstraintType::SUB_EXPR:
  172. return '('.$this->getSubExpression().')';
  173. }
  174. }
  175. }