*/ class OperatorBinary extends TokenBinary implements ICloudformationNative { /** * List of valid operators. * @var string[] */ public const OPERATORS = [ 'and', 'or', 'eq', 'concat', 'select' ]; /** * The operator this instance represents. * @var string */ protected $operator; /** * New binary operator. * * @param string $operator */ public function __construct(string $operator) { $this->operator = $operator; } /** * Get the operator this instance represents. * * @return string */ public function getOperator(): string { return $this->operator; } public static function isToken(string $stream): bool { foreach (static::OPERATORS as $operator) { if (strlen($stream) >= strlen($operator) && substr($stream, 0, strlen($operator)) == $operator) { return true; } } return false; } public static function getToken(string &$stream): Token { foreach (static::OPERATORS as $operator) { if (strlen($stream) >= strlen($operator) && substr($stream, 0, strlen($operator)) == $operator) { $operator = substr($stream, 0, strlen($operator)); $stream = substr($stream, strlen($operator)); return new OperatorBinary($operator); } } throw new \Exception('Could not parse OperatorBinary'); } /** * Execute the operator. * * Suppressing accesses to arguments since this is guaranteed valid * unless there are bugs in Expression. * @suppress PhanTypeArraySuspiciousNullable * @param ?\App\Util\GraphNode[] $arguments * @return \App\Util\GraphNode|Token|scalar|null */ public function execute(?array $arguments = null) { $value1 = $arguments[0]->getValue(); $value2 = $arguments[1]->getValue(); switch ($this->getOperator()) { case 'and': if (is_scalar($value1) && is_scalar($value2)) { return $value1 && $value2; } elseif (is_scalar($value1)) { return $value1 ? $arguments[1] : false; } elseif (is_scalar($value2)) { return $value2 ? $arguments[0] : false; } elseif ($value1 instanceof Parameter && $value2 instanceof Parameter && $value1->getName() == $value2->getName()) { return $value1; } return null; case 'or': if (is_scalar($value1) && is_scalar($value2)) { return $value1 || $value2; } elseif (is_scalar($value1)) { return $value1 ? true : $arguments[1]; } elseif (is_scalar($value2)) { return $value2 ? true : $arguments[0]; } elseif ($value1 instanceof Parameter && $value2 instanceof Parameter && $value1->getName() == $value2->getName()) { return $value1; } return null; case 'eq': if (is_scalar($value1) && is_scalar($value2)) { return $arguments[0] == $arguments[1]; } elseif ($value1 instanceof Parameter && $value2 instanceof Parameter && $value1->getName() == $value2->getName()) { return true; } return null; case 'concat': if (is_scalar($value1) && is_scalar($value2)) { return $value2.$value1; } elseif ($value1 instanceof Parameter && is_scalar($value2) && empty($value2)) { return $value1; } elseif ($value2 instanceof Parameter && is_scalar($value1) && empty($value1)) { return $value2; } return null; case 'select': if (is_scalar($value1) && is_array($value2)) { return $value2[$value1]; } return null; default: throw new \Exception('Missing implementation for binary operator: '.$this->getOperator()); } } /** * Convert this token into a CloudFormation intrinsic. * * Suppressing accesses to arguments since this is guaranteed valid * unless there are bugs in Expression. * @suppress PhanTypeArraySuspiciousNullable * @param ?\App\Util\GraphNode[] $arguments * @return mixed[] */ public function toCloudformation(?array $arguments = null): array { $value1 = $arguments[0]->getValue(); $value2 = $arguments[1]->getValue(); switch ($this->getOperator()) { case 'and': return ['Fn::And' => [$value1, $value2]]; case 'or': return ['Fn::Or' => [$value1, $value2]]; case 'eq': return ['Fn::Equals' => [$value1, $value2]]; case 'concat': return ['Fn::Join' => ['', [$value2, $value1]]]; case 'select': return ['Fn::Select' => [$value1, $value2]]; default: throw new \Exception('Operator cannot be applied to parameters: '.$this->getOperator()); } } }