Delimit package/module names from members

This change removes some ambiguity that existed in MuIL tokens given the
simplistic naming scheme of only using "/" as a delimiter.  We could have
resolved this ambiguity through successive name bindings, but I prefer a
more deterministic approach.  A module member token now delimits the
package/module name from the member name by a ":" character, as in
"aws/ec2:VM".  Furthermore, when reexporting elements from the current
package/module, we will use the self-referential "." character, as in
".:VM".
This commit is contained in:
joeduffy 2017-01-13 07:44:51 -08:00
parent 2097ab2f19
commit 048557ca79
6 changed files with 33 additions and 28 deletions

View file

@ -18,7 +18,7 @@ understand how to recognize. The details of how a language does this is outside
## References ## References
Each package is referred to using a URL-like scheme, facilitating multiple package management distribution schemes. Each package is referenced using a URL-like scheme, facilitating multiple package management distribution schemes.
For example, the URL `https://hub.mu.com/aws/ec2#^1.0.6` references the `aws/ec2` package on MuHub's built-in package For example, the URL `https://hub.mu.com/aws/ec2#^1.0.6` references the `aws/ec2` package on MuHub's built-in package
manager, and askes specifically for version `1.0.6` or higher using semantic versioning resolution. manager, and askes specifically for version `1.0.6` or higher using semantic versioning resolution.
@ -37,10 +37,15 @@ Although there are four parts, three of them are optional, because because Mu us
* `hub.mu.com/` is the default base URL. * `hub.mu.com/` is the default base URL.
* `latest` is the default version number (a.k.a., "tip"). * `latest` is the default version number (a.k.a., "tip").
Although we're concerned with package references right now, we'll see soon that the same reference scheme is also used Although we're concerned with package references right now, we'll see soon that a similar reference scheme is used
to address elements exported from a package, like a module, class, function, or variable. For example, to reference the to address elements exported from a package, like a module, class, function, or variable. The package plus module uses
`VM` class from a MuIL token, we might say `https://hub.mu.com/aws/ec2/VM#^1.0.6`. Most likely, we would leave the same grammar as above, however members inside of a module are followed by a `:`. Furthermore, such references do
off the protocol, base URL, and version in the token, and leave it to the MuPackage to bind to a specific version. not have version numbers. These references are not strictly URLs and must be interpreted by the Mu toolchain.
For example, to reference the `VM` class from a MuIL token -- assuming we have a dependency declared on
`https://hub.mu.com/aws/ec2#^1.0.6` as shown above -- we would most likely say `aws/ec2:VM`. A fully qualified, but
versionless, reference is also permitted, as in `https://hub.mu.com/aws/ec2:VM`, although this is less conventional.
Sometimes the self-referential package plus module identifier `.` will be used as a short-hand, as in `.:VM`.
The way these URLs are resolved to physical MuPackages is discussed later on. The way these URLs are resolved to physical MuPackages is discussed later on.

View file

@ -259,10 +259,13 @@ export class Transformer {
} }
// createModuleMemberToken binds a string-based exported member name to the associated token that references it. // createModuleMemberToken binds a string-based exported member name to the associated token that references it.
private createModuleMemberToken(mod: ModuleReference, name: string): symbols.Token { private createModuleMemberToken(mod: ModuleReference | undefined, name: string): symbols.Token {
// The concatenated name of the module plus identifier will resolve correctly to an exported definition. // The concatenated name of the module plus identifier will resolve correctly to an exported definition.
if (!mod) {
mod = symbols.selfModule;
}
let modtok: symbols.ModuleToken = this.createModuleToken(mod); let modtok: symbols.ModuleToken = this.createModuleToken(mod);
return `${modtok}${symbols.tokenSep}${name}`; return `${modtok}${symbols.moduleSep}${name}`;
} }
// createModuleReference turns a ECMAScript import path into a MuIL module token. // createModuleReference turns a ECMAScript import path into a MuIL module token.
@ -515,14 +518,10 @@ export class Transformer {
// The export is being renamed (`<propertyName> as <name>`). This yields an export node, even for // The export is being renamed (`<propertyName> as <name>`). This yields an export node, even for
// elements exported from the current module. // elements exported from the current module.
let propertyName: ast.Identifier = this.transformIdentifier(exportClause.propertyName); let propertyName: ast.Identifier = this.transformIdentifier(exportClause.propertyName);
let token: symbols.Token = propertyName.ident;
if (sourceModule) {
token = this.createModuleMemberToken(sourceModule, token);
}
exports.push(<ast.Export>{ exports.push(<ast.Export>{
kind: ast.exportKind, kind: ast.exportKind,
name: name, name: name,
token: token, token: this.createModuleMemberToken(sourceModule, propertyName.ident),
}); });
} }
else { else {

View file

@ -7,7 +7,8 @@ export type TypeToken = Token; // a symbol token that resolves to a type.
export type VariableToken = Token; // a symbol token that resolves to a variable. export type VariableToken = Token; // a symbol token that resolves to a variable.
export type FunctionToken = Token; // a symbol token that resolves to a function. export type FunctionToken = Token; // a symbol token that resolves to a function.
export const tokenSep = "/"; // the separator for token "parts" (modules names, etc). export const moduleSep = ":"; // a character delimiting module / member names (e.g., "module:member").
export const selfModule: ModuleToken = "."; // a self-referential token for the current module.
// Accessibility modifiers. // Accessibility modifiers.
export type Accessibility = "public" | "private"; // accessibility modifiers common to all. export type Accessibility = "public" | "private"; // accessibility modifiers common to all.

View file

@ -191,7 +191,7 @@
} }
} }
}, },
"token": "other/C" "token": "other:C"
}, },
"I": { "I": {
"kind": "Export", "kind": "Export",
@ -210,7 +210,7 @@
} }
} }
}, },
"token": "other/I" "token": "other:I"
}, },
"v": { "v": {
"kind": "Export", "kind": "Export",
@ -229,7 +229,7 @@
} }
} }
}, },
"token": "other/v" "token": "other:v"
} }
}, },
"loc": { "loc": {

View file

@ -174,29 +174,29 @@
"ident": "index" "ident": "index"
}, },
"members": { "members": {
"other/C": { "other:C": {
"kind": "Export", "kind": "Export",
"name": { "name": {
"kind": "Identifier", "kind": "Identifier",
"ident": "other/C" "ident": "other:C"
}, },
"token": "other/C" "token": "other:C"
}, },
"other/I": { "other:I": {
"kind": "Export", "kind": "Export",
"name": { "name": {
"kind": "Identifier", "kind": "Identifier",
"ident": "other/I" "ident": "other:I"
}, },
"token": "other/I" "token": "other:I"
}, },
"other/v": { "other:v": {
"kind": "Export", "kind": "Export",
"name": { "name": {
"kind": "Identifier", "kind": "Identifier",
"ident": "other/v" "ident": "other:v"
}, },
"token": "other/v" "token": "other:v"
} }
}, },
"loc": { "loc": {

View file

@ -191,7 +191,7 @@
} }
} }
}, },
"token": "other/C" "token": "other:C"
}, },
"J": { "J": {
"kind": "Export", "kind": "Export",
@ -210,7 +210,7 @@
} }
} }
}, },
"token": "other/I" "token": "other:I"
}, },
"w": { "w": {
"kind": "Export", "kind": "Export",
@ -229,7 +229,7 @@
} }
} }
}, },
"token": "other/v" "token": "other:v"
} }
}, },
"loc": { "loc": {