This change rearranges the old way we dealt with URLs. In the old system, virtually every reference to an element, including types, was fully qualified with a possible URL-like reference. (The old pkg/tokens/Ref type.) In the new model, only dependency references are URL-like. All maps and references within the MuPack/MuIL format are token and name based, using the new pkg/tokens/Token and pkg/tokens/Name family of related types. As such, this change renames Ref to PackageURLString, and RefParts to PackageURL. (The convenient name is given to the thing with "more" structure, since we prefer to deal with structured types and not strings.) It moves out of the pkg/tokens package and into pkg/pack, since it is exclusively there to support package resolution. Similarly, the Version, VersionSpec, and related types move out of pkg/tokens and into pkg/pack. This change cleans up the various binder, package, and workspace logic. Most of these changes are a natural fallout of this overall restructuring, although in a few places we remained sloppy about the difference between Token, Name, and URL. Now the type system supports these distinctions and forces us to be more methodical about any conversions that take place.
77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
// Copyright 2016 Marapongo, Inc. All rights reserved.
|
|
|
|
package tokens
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/marapongo/mu/pkg/util/contract"
|
|
)
|
|
|
|
// Name is an identifier. It conforms to the regex [A-Za-z_.][A-Za-z0-9_]*.
|
|
type Name string
|
|
|
|
var NameRegexp = regexp.MustCompile(NameRegexpPattern)
|
|
var NameRegexpPattern = "[A-Za-z_.][A-Za-z0-9_]*"
|
|
|
|
// Q turns a Name into a qualified name; this is legal, since Name's is a proper subset of QName's grammar.
|
|
func (nm Name) Q() QName { return QName(nm) }
|
|
|
|
// IsName checks whether a string is a legal Name.
|
|
func IsName(s string) bool {
|
|
return NameRegexp.FindString(s) == s
|
|
}
|
|
|
|
// AsName converts a given string to a Name, asserting its validity.
|
|
func AsName(s string) Name {
|
|
contract.Assertf(IsName(s), "Expected string '%v' to be a name (%v)", s, NameRegexpPattern)
|
|
return Name(s)
|
|
}
|
|
|
|
// QName is a qualified identifier. The "/" character optionally delimits different pieces of the name. Each element
|
|
// conforms to the Name regex [A-Za-z_][A-Za-z0-9_]*. For example, "marapongo/mu/stack".
|
|
type QName string
|
|
|
|
// QNameDelimiter is what delimits Namespace and Name parts.
|
|
const QNameDelimiter = "/"
|
|
|
|
var QNameRegexp = regexp.MustCompile(QNameRegexpPattern)
|
|
var QNameRegexpPattern = "(" + NameRegexpPattern + "\\" + QNameDelimiter + ")*" + NameRegexpPattern
|
|
|
|
// IsQName checks whether a string is a legal Name.
|
|
func IsQName(s string) bool {
|
|
return QNameRegexp.FindString(s) == s
|
|
}
|
|
|
|
// AsQName converts a given string to a QName, asserting its validity.
|
|
func AsQName(s string) QName {
|
|
contract.Assertf(IsQName(s), "Expected string '%v' to be a name (%v)", s, QNameRegexpPattern)
|
|
return QName(s)
|
|
}
|
|
|
|
// Name extracts the Name portion of a QName (dropping any namespace).
|
|
func (nm QName) Name() Name {
|
|
ix := strings.LastIndex(string(nm), QNameDelimiter)
|
|
var nmn string
|
|
if ix == -1 {
|
|
nmn = string(nm)
|
|
} else {
|
|
nmn = string(nm[ix+1:])
|
|
}
|
|
contract.Assert(IsName(nmn))
|
|
return Name(nmn)
|
|
}
|
|
|
|
// Namespace extracts the namespace portion of a QName (dropping the name); this may be empty.
|
|
func (nm QName) Namespace() QName {
|
|
ix := strings.LastIndex(string(nm), QNameDelimiter)
|
|
var qn string
|
|
if ix == -1 {
|
|
qn = ""
|
|
} else {
|
|
qn = string(nm[:ix])
|
|
}
|
|
contract.Assert(IsQName(qn))
|
|
return QName(qn)
|
|
}
|