@@ -9,8 +9,8 @@ In the simplest terms, a composition is a collection of components that
99are instantiated in a topological order and certain exports from those
1010instances are made available as exports of the composition itself.
1111
12- WAC currently has three statements that extend the WIT language: imports,
13- ` let ` , and exports .
12+ WAC currently has three statements that extend the WIT language: import
13+ statements, let statements , and export statements .
1414
1515### Import Statements
1616
@@ -41,11 +41,11 @@ resulting composition; in the above example, the import name would be
4141The ` as ` keyword can be used to rename the imported item:
4242
4343``` wac
44- import greeter as " my-greeter" : example:greeter/greeter;
44+ import greeter as my-greeter: example:greeter/greeter;
4545```
4646
47- Here the name of the import becomes ` my-greeter ` ; the name may be any valid import
48- name in the component model.
47+ Here the name of the import becomes ` my-greeter ` ; the name may be any valid
48+ import name in the component model.
4949
5050The local name ` greeter ` can then be used to refer to the imported item from
5151the rest of the composition.
@@ -95,7 +95,8 @@ let my-instance = new example:my-component { ... };
9595
9696The special ` ... ` syntax indicates that any arguments that were not specified
9797as part of the ` new ` expression should be imported from the composition and
98- passed through to the instantiation.
98+ passed through to the instantiation. The ` ... ` syntax must be used as the last
99+ argument to the ` new ` expression.
99100
100101The above is equivalent to:
101102
@@ -154,19 +155,20 @@ The `let` statement allows for binding a local name in the composition to the
154155result of an expression.
155156
156157Note that local names are not variables and cannot be reassigned; a
157- redefinition of a name is an error.
158+ redefinition of a previous name is an error.
158159
159- There are currently four expressions in WAC:
160+ There are currently five expressions in WAC:
160161
162+ * A local name (e.g. ` a ` ), resulting in the value of the name.
161163* The ` new ` expression (e.g ` new a:b { } ` )
162164* The postfix access expression (e.g. ` a.b ` ).
163165* The postfix named access expression (e.g. ` a["b"] ` )
164166* The nested expression (e.g. ` (<expr>) ` ).
165167
166168#### New Expressions
167169
168- A ` new ` expression instantiates a component and returns an instance
169- representing the _ exports_ of the component .
170+ A ` new ` expression instantiates a component and returns a component instance
171+ representing its _ exports_ .
170172
171173The ` new ` expression takes the name of the package (i.e. component) to
172174instantiate and a list of instantiation arguments (i.e. imports).
@@ -178,35 +180,40 @@ arguments to the instantiation.
178180If ` ... ` is not specified, then all instantiation arguments must be explicitly
179181specified.
180182
181- There are two forms of instantiation arguments: implicitly named and explicitly
182- named.
183+ There are three forms of instantiation arguments: inferred arguments,
184+ named arguments, and spread arguments .
183185
184- An implicitly named argument is passed by identifier alone:
186+ ##### Inferred Arguments
187+
188+ An inferred argument is passed directly by local name:
185189
186190``` wac
187191let i = new a:b { c };
188192```
189193
190194Where ` i ` is the name of the bound instance, ` a:b ` is the package being
191- instantiated, and ` c ` is the instantiation argument.
195+ instantiated, and the local name ` c ` is the instantiation argument.
192196
193197The name of the instantiation argument is inferred according to these rules (in
194198order of precedence):
195199
196- * If ` c ` is an instance of an interface with an associated package path (e.g.
197- ` x:y/z ` ) and package ` a:b ` has an import with a matching path, then the path
198- will be used as the argument name.
200+ * If the local name is bound to an instance with an associated package path (
201+ e.g. ` foo:bar/baz ` ) and the component being instantiated has an import with a
202+ matching path, then the path will be used as the argument name.
203+
204+ * If the local name is bound to an explicit import or an access of an instance
205+ export and the component being instantiated has an import with a matching name,
206+ then the import/export name will be used as the argument name.
199207
200- * If ` c ` is an explicit import or an access of an instance export and the
201- package ` a:b ` has an import with a matching name, then the import/export name
202- will be used as the argument name.
208+ * If the component being instantiated has exactly one import that has a path
209+ which ends with the local name (e.g. ` foo:bar/c ` ) , then the path will be used
210+ as the argument name.
203211
204- * If component ` a:b ` has exactly one import with ` c ` as the final component of
205- a path (e.g. ` x:y/c ` ), then the path will be used as the argument name.
212+ * Lastly, the local name will be used as the argument name.
206213
207- * Lastly, ` c ` will be used as the argument name.
214+ ##### Named Arguments
208215
209- Explicitly named arguments are passed as a name/value pair :
216+ Named arguments provide the name of the instantiation argument to use :
210217
211218``` wac
212219let i = new a:b { c: d };
@@ -216,19 +223,67 @@ Where `i` is the name of the bound instance, `a:b` is the package being
216223instantiated, ` c ` is the name of the instantiation argument, and ` d ` is the
217224value of the argument.
218225
219- Even with this form, the name of the instantiation argument is inferred
220- according to the last two rules stated above; for example, the explicit
221- argument ` input-stream: stream ` may be used to refer to an import of `wasi: io /
222- input-stream` or an import of ` input-stream`.
226+ The name may be specified as a kebab-case identifier (e.g. ` foo-bar ` ) or as a
227+ string (e.g. ` "foo-bar" ` ).
228+
229+ When using a kebab-case identifier, a special rule is used to determine the
230+ actual name of the argument:
223231
224- Explicit argument names may also be strings:
232+ * If the component being instantiated has exactly one import that has a path
233+ which ends with the local name (e.g. ` foo:bar/foo-bar ` ), then the path will be
234+ used as the argument name.
235+
236+ * Otherwise, the kebab-case identifier will be used as the argument name.
237+
238+ With this rule, the following example is valid:
225239
226240``` wac
227- let i = new a:b { "c": d };
241+ let stream = new my:stream {};
242+
243+ // Assumption: `a:b` has an import with path `wasi:io/input-stream`
244+ let i = new a:b { input-stream: stream };
228245```
229246
230- This is equivalent to the previous example except that the argument name ` c ` is
231- _ always_ used; no inference is performed.
247+ ##### Spread Arguments
248+
249+ Spread arguments allow for specifying the _ exports of an instance_ as arguments
250+ to the instantiation of a component.
251+
252+ Like the ` ... ` syntax for implicit imports, a ` ... ` precedes a local name as an
253+ indication to spread the instance's exports as arguments to the instantiation:
254+
255+ ``` wac
256+ let i = new a:b { ...c };
257+ ```
258+
259+ Where ` i ` is the name of the bound instance, ` a:b ` is the package being
260+ instantiated and ` c ` is the local name of an instance.
261+
262+ It in an error for the local name used in a spread argument to name anything
263+ other than an instance.
264+
265+ With this syntax, the exports of the instance ` c ` will be spread to any
266+ _ unspecified_ and _ unsatisfied_ instantiation arguments.
267+
268+ Note that spread arguments apply _ after_ inferred and named arguments and are
269+ applied _ in-order_ ; this means that the order of spread arguments is important:
270+
271+ ```
272+ let i = new a:b { foo: bar, ...c, baz, ...d };
273+ ```
274+
275+ In the above example, arguments ` foo ` and ` baz ` will bind to the instantiation
276+ arguments of ` a:b ` first.
277+
278+ Any unsatisfied arguments will then be satisfied by the matching exports of
279+ instance ` c ` , followed by any matching the exports of instance ` d ` .
280+
281+ The above behavior differs from JavaScript's spread argument syntax, which is
282+ the inspiration for this syntax, because component instantiation arguments are
283+ _ named_ and not _ positional_ .
284+
285+ Additionally, it is an evaluation error if a spread argument has no matching
286+ exports.
232287
233288#### Access Expressions
234289
@@ -242,14 +297,17 @@ let i = new a:b { ... };
242297let s = i.outgoing-stream;
243298``````
244299
245- Access expressions use the following rules to determine the name of the export:
300+ Taking the above example into consideration, access expressions use the
301+ following rules to determine the name of the export:
246302
247303* If component `a:b` has exactly one export with `outgoing-stream` as the final
248304component of a path (e.g. `wasi:io/outgoing-stream`), then the path will be
249305used as the export name.
250306
251307* Otherwise, `outgoing-stream` will be used as the export name.
252308
309+ It is invalid to use an access expression on anything other than an instance.
310+
253311#### Named Access Expressions
254312
255313Similar to the postfix access expression, the postfix named access expression
@@ -264,48 +322,83 @@ let s = i["wasi:io/outgoing-stream"];
264322```
265323
266324This is equivalent to the previous example except that the export name is
267- _ exactly_ what was specified; no inference is performed.
325+ _ exactly_ what is specified by the string ; no inference is performed.
268326
269327The string may be any legal export name in the component model.
270328
329+ It is invalid to use a named access expression on anything other than an
330+ instance.
331+
271332### Export Statements
272333
273334Export statements are used to export the result of an expression from the
274- composition itself.
335+ composition itself:
275336
276- The export statement can be used to export the item represented by a local name:
337+ ``` wac
338+ let my-run = new a:b { ... }.run;
339+ export my-run;
340+
341+ // note: this is also equivalent to:
342+ // export new a:b { ... }.run;
343+ ```
344+
345+ In the above example, component ` a:b ` is instantiated and the local name
346+ ` my-run ` is bound to the export of ` run ` from the instance, which we can assume
347+ in this example to be a function of type ` func() ` .
348+
349+ The ` export ` statement is then used to export the ` my-run ` function from the
350+ composition using the export name ` run ` as that is the name that was accessed
351+ from the instance.
352+
353+ The ` as ` keyword can be used to rename the export:
277354
278355``` wac
279- let i = new a:b { ... };
280- let s = i.streams;
281- export s;
356+ let my-run = new a:b { ... }.run;
357+ export my-run as "my-run";
282358```
283359
284- In the above example, component ` a:b ` is instantiated and ` s ` is bound to the
285- export of ` wasi:io/streams ` from the instance.
360+ Like spread arguments in ` new ` expressions, exports of an instance may be
361+ _ spread _ as exports of the composition:
286362
287- The ` export ` statement is then used to export ` s ` from the composition.
363+ ``` wac
364+ let my-instance = new a:b { ... };
365+ export my-instance...;
366+ ```
367+
368+ If we assume that component ` a:b ` in the above example has the following world:
369+
370+ ``` wit
371+ interface setup {
372+ setup: func(config: string);
373+ }
288374
289- The name of the export is inferred according to these rules (in order of
290- precedence):
375+ world a:b {
376+ export run: func();
377+ export setup: setup;
378+ }
379+ ```
291380
292- * If the item is an instance of an interface with an associated package path (e.g.
293- ` x:y/z ` ), then the path is used as the export name .
381+ Then the composition will export a ` run ` function of type ` func() ` and an
382+ instance with name ` a:b/setup ` .
294383
295- * If the item is an explicit import or an access of an instance export, then
296- that name is used .
384+ It is an evaluation error if the instance being spread has no exports; it is a
385+ syntax error to use an ` as ` clause with a spread export .
297386
298- In the above example, the export will be named ` wasi:io/streams ` as that is
299- ultimately the name of the export that was accessed from instance ` i ` .
387+ Spread exports will only create new exports that do not conflict with
388+ previously exported items .
300389
301- If the export name cannot be inferred, then the export name must be explicitly
302- specified with the ` as ` keyword:
390+ If we extend the above example to be:
303391
304392``` wac
305- let i = new a:b { ... };
306- export i as "my-instance";
393+ let my-instance = new a:b { ... };
394+ let run = b:c { ... }.run;
395+ export run;
396+ export my-instance...;
307397```
308398
399+ Then the ` run ` function exported by the composition will be from the instance
400+ named ` b:c ` and not the instance named ` a:b ` .
401+
309402### WAC Grammar
310403
311404The current WAC grammar:
@@ -403,14 +496,15 @@ expr ::= primary-expr postfix-expr*
403496primary-expr ::= new-expr | nested-expr | id
404497new-expr ::= 'new' package-name '{' instantiation-args '}'
405498instantiation-args ::= instantiation-arg (',' instantiation-arg)* (',' '...'?)?
406- instantiation-arg ::= named-instantiation-arg | id
499+ instantiation-arg ::= id | '...' id | named-instantiation-arg
407500named-instantiation-arg ::= (id | string) ':' expr
408501nested-expr ::= '(' expr ')'
409502postfix-expr ::= access-expr | named-access-expr
410503access-expr ::= '.' id
411504named-access-expr ::= '[' string ']'
412505
413- export-statement ::= 'export' expr ('as' (id | string))? ';'
506+ export-statement ::= 'export' expr (export-options)? ';'
507+ export-options ::= `...` | 'as' (id | string)
414508
415509id ::= '%'?[a-z][a-z0-9]*('-'[a-z][a-z0-9]*)*
416510string ::= '"' character-that-is-not-a-double-quote* '"'
0 commit comments