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
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
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.
* `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
to address elements exported from a package, like a module, class, function, or variable. For example, to reference the
`VM` class from a MuIL token, we might say `https://hub.mu.com/aws/ec2/VM#^1.0.6`. Most likely, we would leave
off the protocol, base URL, and version in the token, and leave it to the MuPackage to bind to a specific version.
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. The package plus module uses
the same grammar as above, however members inside of a module are followed by a `:`. Furthermore, such references do
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.

View file

@ -259,10 +259,13 @@ export class Transformer {
}
// 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.
if (!mod) {
mod = symbols.selfModule;
}
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.
@ -515,14 +518,10 @@ export class Transformer {
// The export is being renamed (`<propertyName> as <name>`). This yields an export node, even for
// elements exported from the current module.
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>{
kind: ast.exportKind,
name: name,
token: token,
token: this.createModuleMemberToken(sourceModule, propertyName.ident),
});
}
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 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.
export type Accessibility = "public" | "private"; // accessibility modifiers common to all.

View file

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

View file

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

View file

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