Swidi
Swidi is a small, declarative language implemented by SWID and consumed by a dedicated Swidi frontend in SWID.
#
ObjectiveProvide an escape hatch in SWID to add declarations to existing Dart libraries to allow for clean type-system bridging, specify APIs that are underspecified, and override existing declarations in a clean and integrated way.
#
BackgroundSWID is based on the principle that the Dart package being consumed cannot (and should not) be hand-edited by the user in order to influence the kind of code that SWID will produce. This frees the user from having to specify every single symbol being emitted (whether through annotations or other methods). It however comes with the downside that SWID becomes impossible to influence. Swidi provides clear (and constrained) avenues for the user to influence code generation.
#
StructureSwidi is used to describe the public API surface of one or more Dart symbols from one or more Dart libraries. Swidi attempts to be as simple (from an implementation perspective) as possible. It is not turing complete and does not support any form of file includes or imports. Swidi does not have any form of inference or intrinsics. All semantic information describing a symbol is given at its usage site.
Declarations described in Swidi are merged by SWID with the declarations read from the original Dart source code with preference given to those declarations from Swidi. This allows for declarations in Swidi to selectively override those given in Dart source code.
#
ClassesSwidi classes are declared with a library scope prefix of the path an importer would use to import the declaring library in Dart. Consider the following:
The above declares an empty set of overrides for the class IterableBase
from the Dart library dart:collection
.
#
Reference Declaration PrefixesBecause Swidi has neither inference nor intrinsics, all semantic information about a given symbol is given at its usage site. For types, Swidi expresses this through a combination of library scope prefixes (as for class declarations) and reference declaration prefixes. They are given in the order library::reference declaration::type name
.
There are five reference declaration prefixes in Swidi
class
- The given symbol refers to the class type declared in the library specified in the library prefix scope.
enum
- The given symbol refers to the enumeration type declared in the library specified in the library prefix scope.
void
- The given symbol refers to the void type. No library scope prefix is permitted.
type
- The given symbol refers to a type formal. No library scope prefix is permitted.
dynamic
- The given symbol refers to the dynamic type. No library scope prefix is permitted.
#
MethodsMethods are declared on classes in Swidi in the same manner as in Dart (though without bodies).
The above declares an override for the method called contains
on the class IterableBase
. contains
has a return type of bool
(which is a class declared in dart:core
), has a single positional parameter called element
which is of type Object
(which is a class declared in dart:core
) and can be null.
#
Optional ParametersOptional parameters can be declared in Swidi in the same manner as in Dart. Consider the following:
The above declares an override for the method called lastIndexOf
on the class UnmodifiableInt16ListView
. lastIndexOf
has a return type of int
(which is a class declared in dart:core
), has a single positional parameter called element
which is of type Object
(which is a class declared in dart:core
) and can be null, and has a single optional parameter called start
which is of type int
(which is a class declared in dart:core
) and can be null.
#
Named ParametersNamed parameters can be declared in Swidi in the same manner as in Dart. In Swidi, the required
keyword currently cannot be used. Consider the following:
The above declares an override for the method called foo
on the class IconData
. foo
has a return type of void
, has a single positional parameter called bar
which is of type int
(which is a class declared in dart:core
), has a named parameter called baz
which is type int
(which is a class declared in dart:core
), a named parameter called qux
which is of type int
(which is a class declared in dart:core
) and can be null.
#
Constant InitializersConstant initializers for parameters can be declared immediately after the parameter declaration in much the same way as in Dart. In Swidi, constant string literals are prefixed with @
. Consider the following:
The above declares an override for the method called foo
on the class IconData
. foo
has a return type of void
, has a single positional parameter called bar
which is of type int
(which is a class declared in dart:core
) and has a default value of 0, has a named parameter called baz
which is type int
(which is a class declared in dart:core
) and has a default value of 123, a named parameter called qux
which is of type String
(which is a class declared in dart:core
) can be null and has a default value of "default value".
#
Type FormalsType formals can be declared on methods similarly as in Dart. Consider the following:
The above declares an override for the method called foo
on the class List
. foo
has a return type of List
(which is a class declared in dart:core
), has a type formal called T
(whos bound is nullable Object
), a type formal called U
, and a type formal called T
(which is bound to the type formal T
).
#
Function TypesFunction typed symbols in Swidi take a slightly different form to that of Dart. In Swidi, they begin with the function keyword, followed by their return type. Positional and optional parameters in function types cannot be named. Consider the following:
The above declares an override for the method called foo
on the class List
. foo
has a return type of void
, has a single positional parameter called callback
which is a nullable function that has a return type of void
, has a positional parameter of type int
(which is a class declared in dart:core
), has an optional parameter of type String
(which is a class declared in dart:core
) that can be null, and a named parameter called bar
which is of type dynamic
.
#
Type ArgumentsType arguments can be specified on symbols in the same manner as in Dart. Consider the following:
The above declares an override for the method called foo
on the class List
. foo
has a return type of void
, has a single positional parameter called fooList
which is of type List
(which is a class declared in dart:core
) and has a type argument of type int
(which is a class declared in dart:core
).
#
Symbol AnnotationsSymbols in Swidi can be declared with one or more optional annotations. These are declared as a constant function invocation between pairs of [[ ]]
. Consider the following:
#
Short Hand OverridesShort hand overrides in Swidi can be used to provide extra semantic information to an entire declaration. They are expressed as a constant map.
#
ClassesShort hand class overrides can be provided immediately after a class declaration. Consider the following:
#
MethodsShort hand method overrides can be provided immediately after a method declaration. Consider the following:
#
ErrorsWhile Swidi's grammar (especially around constants) is relatively permissive, not every possible declaration makes sense. The below are validation errors that may be encountered when writing Swidi declarations.
#
Empty annotation on declaration (E1)This error can be encountered in Swidi code like the following:
#
Number used as an annotation (E2)This error can be encountered in Swidi code like the following:
#
String used as an annotation (E3)This error can be encountered in Swidi code like the following:
#
Annotations can't have named parameters (E4)This error can be encountered in Swidi code like the following:
#
Annotations must have a positional parameter (E5)This error can be encountered in Swidi code like the following:
#
Annotations must have a single positional parameter (E6)This error can be encountered in Swidi code like the following:
#
Number used as a parameter in an annotation (E7)This error can be encountered in Swidi code like the following:
#
Function used as a parameter in an annotation(E8)This error can be encountered in Swidi code like the following:
#
Map used as a parameter in an annotation (E9)This error can be encountered in Swidi code like the following:
#
Map used as an annotation (E10)This error can be encountered in Swidi code like the following:
#
Number used as a method short hand override (E11)This error can be encountered in Swidi code like the following:
#
String used as a method short hand override (E12)This error can be encountered in Swidi code like the following:
#
Function used as a method short hand override (E13)This error can be encountered in Swidi code like the following:
#
Number used as a key in a method short hand override (E14)This error can be encountered in Swidi code like the following:
#
Function used as a key in a method short hand override (E15)This error can be encountered in Swidi code like the following:
#
Map used as a key in a method short hand override (E16)This error can be encountered in Swidi code like the following:
#
Key is not a valid short hand override key (E17)This error can be encountered in Swidi code like the following:
#
Invalid annotation name (E18)This error can be encountered in Swidi code like the following:
#
Invalid annotation parameter (E19)This error can be encountered in Swidi code like the following:
#
Boolean used as an annotation (E20)This error can be encountered in Swidi code like the following:
#
Boolean used as a parameter in an annotation (E21)This error can be encountered in Swidi code like the following:
#
Boolean used as a method short hand override (E22)This error can be encountered in Swidi code like the following:
#
Boolean used as a key in a method short hand override (E23)This error can be encountered in Swidi code like the following:
#
Number used as a value in a method short hand override (E24)This error can be encountered in Swidi code like the following:
#
Function used as a value in a method short hand override (E25)This error can be encountered in Swidi code like the following:
#
Map used as a value in a method short hand override (E26)This error can be encountered in Swidi code like the following: