Names in Basic Storm
    Names in Basic Storm are similar to the generic syntax in Storm. The
    syntax of names are, however, altered slightly to allow using the dot . operator for member
    access, like C++ and Java. The difference from the generic Storm syntax is as follows:
- 
        The dot .has been replaced by a colon:(inspired by the::operator in C++).
- 
        Parentheses ()have been replaced by angle brackets<>.
This means that names in Basic Storm generally have the following form:
a:b<c:d>:e
    The rationale behind these differences is to distinguish the member access operator (.) from the
    scope resolution operator (:). Basic Storm uses . as the member access operator and : as the
    scope resolution operator to resemble the syntax of languages like C++. Similarly, since the name
    syntax is most often used to refer to the name of types, angle brackets (<>) were used instead of
    parentheses (()) to distinguish type parameters from function parameters.
    Historical note: The original plan was for Basic Storm to overload the dot operator (.) like
    Java, so that its meaning would depend on the context in which it was used. This has not yet
    happened.
To illustrate the syntax, consider the following examples:
- 
        core:Intis the name of theInttype in thecorepackage.
- 
        core:Array<core:Int>is the name of theArraytype for theInttype.
Short-Hand Names
Basic Storm provides a number of short-hand names for common types as follows:
- 
        T[]is short forArray<T>(an array ofT)
- 
        T?is short forMaybe<T>(eitherTornull)
- 
        K->Vis short forMap<K, V>(a hash map fromKtoV)
- 
        K&->Vis short forRefMap<K, V>(a hash map fromKtoVthat hashes based on object identity)
- 
        fn(...)->Tis short forFn<T, ...>(a function with parameters...and return valueT)
    Additional type aliases can be added by providing additional productions for the rule
    lang.bs.SType.
Use Statements
    Each Basic Storm file may start with zero or more use statements. A use statement specifies a
    package to "import" into the current source file. For example: use my:package;. A use statement
    serves two purposes. First, they make all names inside the specified package visible in the current
    file without qualification. For example, if use lang:bs; is present, then the name Expr can
    refer to the type lang:bs:Expr. Secondly, use statements import syntax from the specified package.
    The imported syntax is available in the remainder of the file, but only after all use statements.
Name Lookup
A name in Basic Storm may appear in two contexts. The first, and simplest, is when a name appears in a location where a type name appears. In this case, the name is resolved as-is after any short-hand names have been expanded.
    A name may also appear in an expression, possibly with parameters and in conjunction with the member
    access operator. To understand the motivation behind the name lookup rules for this case, it is
    important to note that Basic Storm uses uniform function call syntax. This means that it is
    possible to call the member f of the variable x by writing either f.x() or x(f). These two
    expressions are almost exactly equivalent. They only differ in which x takes priority if there are
    multiple overloads of x available.
In general, names that appear in an expression may have the following form:
a.N<T, U, ...>(b, c, ...)
    In the generic form, N, T and U are fully qualified names according to the syntax above (i.e.
    parts separated with : and any parameters specified with <>). The parameters to the last part of
    N (if any) are T, U, and optionally more parameters. Of cours, N may contain multiple parts.
    However, the parameters of the last part are important for the name lookup, which is why they are
    explicit in the form above. Furthermore, a, b, and c are expressions. The exact syntax of
    expressions are covered later. What is important here is that all expressions have a type that is
    known at compile-time. This type is used during name lookup. All parts of the generic form are
    optional except for N. This means that the following forms are also valid: N, a.N, N(a, b, ...), etc.
Name lookup then consists of two steps. First, the system decides on one or two names that should be resolved in the name tree as follows:
- 
        If the last part of Ncontain any parameters (i.e.<T, U, ...>above), then the nameN<T, U, ...>has to refer to a type. Any parameters in parentheses are then parameters to the constructor of the type. For example, the namecore:Array<Int>(1, 0)refers to the constructor of the typecore:Array<core:Int>. Note: The constructor is named__initwith suitable parameters. It is, however, not possible to explicitly call the constructor by name from Basic Storm.
- 
        If the name has the form a.N(...), with or without parameters in parentheses, then the name is interpreted asN(a, ...), and name lookup proceeds as usual. The termais remembered to be scope-altering for the future scope traversal. The last part ofNis appended with the parametersa,b,c, ...
- 
        If the name did not have the form a.N(...)originally, and the name occurs in a context where a variable namedthisexists (for example, in a member function), then two versions of the name are created. The first with parameters the type ofthis,a,b, ... and the second with parametersa,b, ... (These correspond toN(this, a, b, ...)andN(a, b)). Both are resolved, but the original form takes priority at each step.
After the interpretation of the name has been determined, the name tree is traversed as follows;
- 
        If Nconsists of only one part, and the first parameter was marked as scope altering (step 2 above), look inside the type of the first parameter for a match.This means that expressions like x.N()always resolve in the type ofxif it exists.
- 
        Traverse the name tree from the current local scope until a package is reached. At each step,
        attempt to resolve Nwith its current parameters.This means that names are resolved in the lexical context of the current file and package first. However, since this step ends at the current package, a name like a:bthat occurs in the packagec:dwill not be able to matchc:a:b, which would likely lead to confusion.
- 
        If Nconsists of only one part, and the first parameter was not marked as scope altering, look inside the type of the first parameter for a match.This means that expressions like N(x)are allowed to match against member functions in the type ofx, but that function calls namedNdeclared lexically closer have precedence when this form is used. Compare this to step 2, which applies to names of the formx.N().
- 
        Attempt to resolve Nagainst the root package.This means that absolute names are matched at this stage, and that they take precedence over any usestatements.
- 
        Attempt to resolve Nagainst the packagecore.This makes all types in the corepackage (e.g.core:Int,core:Str) automatically visible everywhere.
- 
        Attempt to resolve Nagainst eachusestatement in the current file.This means that usestatements are used as a last restort for name resolution.
