Two critical binder functions are bindSourceFile
and mergeSymbolTable
. We will take a look at these next.
Basically checks if file.locals
is defined, if not it hands over to (a local function) bind
.
Note: locals
is defined on Node
and is of type SymbolTable
. Note that SourceFile
is also a Node
(in fact a root node in the AST).
TIP: local functions are used heavily within the TypeScript compiler. A local function very likely uses variables from the parent function (captured by closure). In the case of bind
(a local function within bindSourceFile
) it (or a function it calls) will setup the symbolCount
and classifiableNames
among others, that are then stored on the returned SourceFile
.
Bind takes any Node
(not just SourceFile
). First thing it does is assign the node.parent
(if parent
variable has been setup ... which again is something the binder does during its processing within the bindChildren
function), then hands off to bindWorker
which does the heavy lifting. Finally it calls bindChildren
(a function that simply stores the binder state e.g. current parent
within its function local vars, then calls bind
on each child, and then restores the binder state). Now let's look at bindWorker
which is the more interesting function.
This function switches on node.kind
(of type SyntaxKind
) and delegates work to the appropriate bindFoo
function (also defined within binder.ts
). For example if the node
is a SourceFile
it calls (eventually and only if its an external file module) bindAnonymousDeclaration
There are a few patterns common to bindFoo
functions as well as some utility functions that these use. One function that is almost always used is the createSymbol
function. It is presented in its entirety below:
function createSymbol(flags: SymbolFlags, name: string): Symbol {
symbolCount++;
return new Symbol(flags, name);
}
As you can see it is simply keeping the symbolCount
(a local to bindSourceFile
) up to date and creating the symbol with the specified parameters.