Expression Trees: Dsl Types
For every literal supported in a DSL, the visitor must provide a stub method that shows what type it should have.
class MyDsl {
// Types for literals
public static function intType(): MyDslInt {
throw new Exception();
}
public static function floatType(): MyDslFloat {
throw new Exception();
}
public static function boolType(): MyDslBool {
throw new Exception();
}
public static function stringType(): MyDslString {
throw new Exception();
}
// Visitors can use the normal Hack types if they wish.
// This is particularly common for null and void.
public static function nullType(): null {
throw new Exception();
}
public static function voidType(): void {
throw new Exception();
}
// symbolType is used in function calls.
// In this example, MyDsl is using normal Hack
// functions but DSLs may choose more specific APIs.
public static function symbolType<T>(
T $_,
): T {
throw new Exception();
}
}
All types used in the visitor need to define what operators they support. Here's an expanded version of MyDsl
with types that are very similar to plain Hack.
interface MyDslNonnull {
public function __tripleEquals(?MyDslNonnull $_): MyDslBool;
public function __notTripleEquals(?MyDslNonnull $_): MyDslBool;
}
interface MyDslNum extends MyDslNonnull {
// Arithmetic
public function __plus(MyDslNum $_): MyDslNum;
public function __minus(MyDslNum $_): MyDslNum;
public function __star(MyDslNum $_): MyDslNum;
public function __slash(MyDslNum $_): MyDslNum;
public function __negate(): MyDslNum;
// Comparisons
public function __lessThan(MyDslNum $_): MyDslBool;
public function __lessThanEqual(MyDslNum $_): MyDslBool;
public function __greaterThan(MyDslNum $_): MyDslBool;
public function __greaterThanEqual(MyDslNum $_): MyDslBool;
}
interface MyDslInt extends MyDslNum {
// Only support modulus on integers in our demo.
public function __percent(MyDslInt $_): MyDslInt;
// Bitwise operators
public function __amp(MyDslInt $_): MyDslInt;
public function __bar(MyDslInt $_): MyDslInt;
public function __caret(MyDslInt $_): MyDslInt;
public function __lessThanLessThan(MyDslInt $_): MyDslInt;
public function __greaterThanGreaterThan(MyDslInt $_): MyDslInt;
public function __tilde(): MyDslInt;
}
interface MyDslFloat extends MyDslNum {
<<__Override>>
public function __plus(MyDslNum $_): MyDslFloat;
}
interface MyDslString extends MyDslNonnull {
public function __dot(MyDslString $_): MyDslString;
}
interface MyDslBool extends MyDslNonnull {
// __bool signifies that we can use MyDslBool in positions that require
// a truthy value, such as if statements.
public function __bool(): bool;
// Infix operators that return another MyDslBool.
public function __ampamp(MyDslBool $_): MyDslBool;
public function __barbar(MyDslBool $_): MyDslBool;
public function __exclamationMark(): MyDslBool;
}
Thank You!
Thank You! If you'd like to share more feedback, please file an issue.