Skip to content
This repository has been archived by the owner on Apr 1, 2024. It is now read-only.

Commit

Permalink
RFC/Proof-of-concept: Implement children declarations as a trait (#214)
Browse files Browse the repository at this point in the history
* RFC: Implement children declarations as a trait

Currently serializes to the same format as HackC, to allow migrating to
the new syntax with no changes to validation.

Some normalization is needed, as HackC emits some overly-complex
structures - e.g. with `$expr = tuple(EXACTLY_ONE, EXPRESSION, $inner_expr)`
can be simplified to `$expr = $inner_expr`.

It is not currently in a form suitable for use - the trait I've added
merely confirms that the two forms of children declaration are
semanticaly equivalent.

I think that's a meaningful first step; if we're happy for this, we can
merge it, start on migration tools, then add an alternative trait to
allow removal of the legacy syntax.

This is very much a draft API; open to a complete rewrite if desired :)

refs #212

* make child declaration a static method

* rename trait for consistency, add new-way-only trait too

* remove bogus child declaration
  • Loading branch information
fredemmott authored Feb 12, 2020
1 parent cc03980 commit 83e81a3
Show file tree
Hide file tree
Showing 21 changed files with 682 additions and 5 deletions.
20 changes: 20 additions & 0 deletions src/children/Any.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

final class Any implements Constraint {
public function legacySerialize(): mixed {
return 1;
}

public function legacySerializeAsLeaf(): (LegacyConstraintType, mixed) {
return tuple(LegacyConstraintType::ANY, null);
}
}
15 changes: 15 additions & 0 deletions src/children/AnyNumberOf.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

final class AnyNumberOf<T as Constraint> extends QuantifierConstraint<T> {
const LegacyExpressionType LEGACY_EXPRESSION_TYPE =
LegacyExpressionType::ANY_QUANTITY;
}
41 changes: 41 additions & 0 deletions src/children/AnyOf.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

use namespace HH\Lib\{C, Vec};

final class AnyOf<T as Constraint> implements LegacyExpression {
private vec<T> $children;
public function __construct(T $a, T $b, T ...$rest) {
$this->children = Vec\concat(vec[$a, $b], $rest);
}

public function legacySerialize(): (LegacyExpressionType, mixed, mixed) {
$it = tuple(
LegacyExpressionType::EITHER,
$this->children[0]->legacySerialize(),
$this->children[1]->legacySerialize(),
);
$rest = Vec\drop($this->children, 2);
while (!C\is_empty($rest)) {
$it = tuple(
LegacyExpressionType::EITHER,
$it,
$rest[0]->legacySerialize(),
);
$rest = Vec\drop($rest, 1);
}
return $it;
}

final public function legacySerializeAsLeaf(): null {
return null;
}
}
15 changes: 15 additions & 0 deletions src/children/AtLeastOneOf.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

final class AtLeastOneOf<T as Constraint> extends QuantifierConstraint<T> {
const LegacyExpressionType LEGACY_EXPRESSION_TYPE =
LegacyExpressionType::AT_LEAST_ONE;
}
27 changes: 27 additions & 0 deletions src/children/Category.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

use namespace HH\Lib\Str;

final class Category extends LeafConstraint {
public function __construct(private string $category) {
}

public function legacySerializeAsLeaf(): (LegacyConstraintType, string) {
return tuple(
LegacyConstraintType::CATEGORY,
$this->category
|> Str\strip_prefix($$, '%')
|> Str\replace($$, ':', '__')
|> Str\replace($$, '-', '_'),
);
}
}
15 changes: 15 additions & 0 deletions src/children/Constraint.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

interface Constraint {
public function legacySerialize(): mixed;
public function legacySerializeAsLeaf(): ?(LegacyConstraintType, mixed);
}
21 changes: 21 additions & 0 deletions src/children/LeafConstraint.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

abstract class LeafConstraint implements LegacyExpression {
abstract public function legacySerializeAsLeaf(
): (LegacyConstraintType, mixed);

final public function legacySerialize(
): (LegacyExpressionType, LegacyConstraintType, mixed) {
$as_leaf = $this->legacySerializeAsLeaf();
return tuple(LegacyExpressionType::EXACTLY_ONE, $as_leaf[0], $as_leaf[1]);
}
}
18 changes: 18 additions & 0 deletions src/children/LegacyConstraintType.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

enum LegacyConstraintType: int {
ANY = 1;
PCDATA = 2;
CLASSNAME = 3;
CATEGORY = 4;
EXPRESSION = 5;
}
14 changes: 14 additions & 0 deletions src/children/LegacyExpression.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

interface LegacyExpression extends Constraint {
public function legacySerialize(): (LegacyExpressionType, mixed, mixed);
}
19 changes: 19 additions & 0 deletions src/children/LegacyExpressionType.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

enum LegacyExpressionType: int {
EXACTLY_ONE = 0;
ANY_QUANTITY = 1;
ZERO_OR_ONE = 2;
AT_LEAST_ONE = 3;
SEQUENCE = 4;
EITHER = 5;
}
20 changes: 20 additions & 0 deletions src/children/None.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

final class None implements Constraint {
public function legacySerialize(): mixed {
return 0;
}

public function legacySerializeAsLeaf(): null {
return null;
}
}
19 changes: 19 additions & 0 deletions src/children/OfType.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

final class OfType<<<__Enforceable>> reify T> extends LeafConstraint {
public function legacySerializeAsLeaf(): (LegacyConstraintType, string) {
return tuple(
LegacyConstraintType::CLASSNAME,
\HH\ReifiedGenerics\get_classname<T>(),
);
}
}
15 changes: 15 additions & 0 deletions src/children/Optional.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

final class Optional<T as Constraint> extends QuantifierConstraint<T> {
const LegacyExpressionType LEGACY_EXPRESSION_TYPE =
LegacyExpressionType::ZERO_OR_ONE;
}
16 changes: 16 additions & 0 deletions src/children/PCData.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

final class PCData extends LeafConstraint {
public function legacySerializeAsLeaf(): (LegacyConstraintType, mixed) {
return tuple(LegacyConstraintType::PCDATA, null);
}
}
36 changes: 36 additions & 0 deletions src/children/QuantifierConstraint.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

abstract class QuantifierConstraint<T as Constraint>
implements LegacyExpression {
abstract const LegacyExpressionType LEGACY_EXPRESSION_TYPE;

final public function __construct(private T $child) {}

final public function legacySerialize(
): (LegacyExpressionType, mixed, mixed) {
$inner = $this->child;
$as_leaf = $inner->legacySerializeAsLeaf();
if ($as_leaf is nonnull) {
return tuple(static::LEGACY_EXPRESSION_TYPE, $as_leaf[0], $as_leaf[1]);
}

return tuple(
static::LEGACY_EXPRESSION_TYPE,
LegacyConstraintType::EXPRESSION,
$inner->legacySerialize(),
);
}

final public function legacySerializeAsLeaf(): null {
return null;
}
}
42 changes: 42 additions & 0 deletions src/children/Sequence.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\XHP\ChildValidation;

use namespace HH\Lib\{C, Vec};

final class Sequence<T as Constraint> implements LegacyExpression {
private vec<T> $children;

public function __construct(T $a, T $b, T ...$rest) {
$this->children = Vec\concat(vec[$a, $b], $rest);
}

public function legacySerialize(): (LegacyExpressionType, mixed, mixed) {
$it = tuple(
LegacyExpressionType::SEQUENCE,
$this->children[0]->legacySerialize(),
$this->children[1]->legacySerialize(),
);
$rest = Vec\drop($this->children, 2);
while (!C\is_empty($rest)) {
$it = tuple(
LegacyExpressionType::SEQUENCE,
$it,
$rest[0]->legacySerialize(),
);
$rest = Vec\drop($rest, 1);
}
return $it;
}

public function legacySerializeAsLeaf(): null {
return null;
}
}
Loading

0 comments on commit 83e81a3

Please sign in to comment.