Expression tree DSLs can use most of the expression and statement syntax in Hack.
For a full list of supported syntax, see also expr_tree.hhi.
Literals
Example |
Visitor Runtime |
Typing |
true |
$v->visitBool($position, true) |
MyDsl::boolType() |
1 |
$v->visitInt($position, 1) |
MyDsl::intType() |
1.23 |
$v->visitFloat($position, 1.23) |
MyDsl::floatType() |
"foo" |
$v->visitString($position, "foo") |
MyDsl::stringType() |
null |
$v->visitString($position) |
MyDsl::nullType() |
N/A |
N/A |
MyDsl::voidType() |
Binary Operators
Operator names are based on the appearance of the symbol, as different
DSLs may choose different semantics for an operator.
Example |
Visitor Runtime |
Typing |
$x + $y |
$v->visitBinop($position, ..., '__plus', ...) |
__plus method on $x |
$x - $y |
$v->visitBinop($position, ..., '__minus', ...) |
__minus method on $x |
$x * $y |
$v->visitBinop($position, ..., '__star', ...) |
__star method on $x |
$x / $y |
$v->visitBinop($position, ..., '__slash', ...) |
__slash method on $x |
$x % $y |
$v->visitBinop($position, ..., '__percent', ...) |
__percent method on $x |
$x && $y |
$v->visitBinop($position, ..., '__ampamp', ...) |
__ampamp method on $x |
$x || $y |
$v->visitBinop($position, ..., '__barbar', ...) |
__barbar method on $x |
$x < $y |
$v->visitBinop($position, ..., '__lessThan', ...) |
__lessThan method on $x |
$x <= $y |
$v->visitBinop($position, ..., '__lessThanEqual', ...) |
__lessThanEqual method on $x |
$x > $y |
$v->visitBinop($position, ..., '__greaterThan', ...) |
__greaterThan method on $x |
$x >= $y |
$v->visitBinop($position, ..., '__greaterThanEqual', ...) |
__greaterThanEqual method on $x |
$x === $y |
$v->visitBinop($position, ..., '__tripleEquals', ...) |
__tripleEquals method on $x |
$x !== $y |
$v->visitBinop($position, ..., '__notTripleEquals', ...) |
__notTripleEquals method on $x |
$x . $y |
$v->visitBinop($position, ..., '__dot', ...) |
__dot method on $x |
$x & $y |
$v->visitBinop($position, ..., '__amp', ...) |
__amp method on $x |
$x | $y |
$v->visitBinop($position, ..., '__bar', ...) |
__bar method on $x |
$x ^ $y |
$v->visitBinop($position, ..., '__caret', ...) |
__caret method on $x |
$x << $y |
$v->visitBinop($position, ..., '__lessThanLessThan', ...) |
__lessThanLessThan method on $x |
$x >> $y |
$v->visitBinop($position, ..., '__greaterThanGreaterThan', ...) |
__greaterThanGreaterThan method on $x |
Ternary Operators
Example |
Visitor Runtime |
Typing |
$x ? $y : $z |
$v->visitTernary($position, ..., ..., ...) |
$x->__bool() ? $y : $z |
Unary Operators
Example |
Visitor Runtime |
Typing |
!$x |
$v->visitUnop($position, ..., '__exclamationMark') |
__exclamationMark method on $x |
-$x |
$v->visitUnop($position, ..., '__negate') |
__negate method on $x |
~$x |
$v->visitUnop($position, ..., '__tilde') |
__tilde method on $x |
$x++ |
$v->visitUnop($position, ..., '__postfixPlusPlus') |
__postfixPlusPlus method on $x |
$x-- |
$v->visitUnop($position, ..., '__postfixMinusMinus') |
__postfixMinusMinus method on $x |
Local Variables
Example |
Visitor Runtime |
Typing |
$x |
$v->visitLocal($position, '$x') |
Same as normal Hack |
You can see here that the visitor runtime does not know the type of $x
, it
just sees a call to visitLocal
with the variable name as a string
'$x'
.
Note that expression trees do not allow free variables. You can only
use local variables that have been previously assigned or introduced
with a lambda.
Lambdas
Example |
Visitor Runtime |
Typing |
(Foo $x) ==> $y |
$v->visitLambda($position, vec['$x'], vec[...]) |
Same as normal Hack |
Note that the visitor runtime does not see the type of $x
.
Statements
Example |
Visitor Runtime |
Typing |
$x = $y; |
$v->visitAssign($position, ..., ...) |
Same as normal Hack |
return $x; |
$v->visitReturn($position, ...) |
Same as normal Hack |
return; |
$v->visitReturn($position, null) |
Same as normal Hack |
if (...) {...} else {...} |
$v->visitIf($position, ..., ..., ...) |
if (...->__bool()) {...} else {...} |
while (...) {...} |
$v->visitWhile($position, ..., vec[...]) |
while (...->__bool()) {...} |
for (...; ...; ...) {...} |
$v->visitFor($position, vec[...], ..., vec[...], vec[...]) |
for (...; ...->__bool(); ...) {...} |
break; |
$v->visitBreak($position) |
Same as normal Hack |
continue; |
$v->visitContinue($position) |
Same as normal Hack |
Calls
Example |
Visitor Runtime |
Typing |
foo(...) |
$v->visitCall($position, $v->visitGlobalFunction($position, foo<>), vec[...]) |
MyDsl::symbolType(foo<>)() |
Foo::bar(...) |
$v->visitCall($position, $v->visitStaticMethod($position, Foo::bar<>), vec[...]) |
MyDsl::symbolType(Foo::bar<>)() |
$x->bar(...) |
$v->visitMethodCall($position, $v->visitLocal($position, '$x'), 'bar', vec[...]) |
$x->bar(...) |
Note that the function or method must have a Hack definition, so the typechecker can verify that it's being called with appropriate arguments.
The visitor runtime only receives the method name for instance methods. For global functions and static methods, the visitor receives a function pointer, which contains more information.
XHP Literals
Example |
Visitor Runtime |
Typing |
<foo ...>...</foo> |
$v->visitXhp($position, :foo::class, dict[...], vec[...]) |
<foo ...>...</foo> |
Property Access
Example |
Visitor Runtime |
Typing |
(...)->foo |
$v->visitPropertyAccess($position, ..., 'foo') |
(...)->foo |
Splicing
Example |
Visitor Runtime |
Typing |
${$x} |
$v->splice($position, 'key0', $x) |
Extract the inferred type out of the third type argument of Spliceable |
Unsupported Features
Expression trees may only contain expressions between the backticks.
MyDsl`1`; // OK: 1 is an expression
MyDsl`while(true) {}`; // Bad: statement
MyDsl`() ==> { while true() {} }`; // OK: statements are allowed in lambdas
MyDsl`class Foo {}`; // Bad: top-level declaration.
Thank You!
Thank You! If you'd like to share more feedback, please
file an issue.