list(
      paramsOrCallback?:
        | Params$Resource$Projects$Topics$Snapshots$List
        | BodyResponseCallback<Schema$ListTopicSnapshotsResponse>,
      optionsOrCallback?:
        | MethodOptions
        | BodyResponseCallback<Schema$ListTopicSnapshotsResponse>,
      callback?: BodyResponseCallback<Schema$ListTopicSnapshotsResponse>
    ): void | GaxiosPromise<Schema$ListTopicSnapshotsResponse> {
      let params = (paramsOrCallback ||
        {}) as Params$Resource$Projects$Topics$Snapshots$List;
      let options = (optionsOrCallback || {}) as MethodOptions;

      if (typeof paramsOrCallback === 'function') {
        callback = paramsOrCallback;
        params = {} as Params$Resource$Projects$Topics$Snapshots$List;
        options = {};
      }

      if (typeof optionsOrCallback === 'function') {
        callback = optionsOrCallback;
        options = {};
      }

      const rootUrl = options.rootUrl || 'https://pubsub.googleapis.com/';
      const parameters = {
        options: Object.assign(
          {
            url: (rootUrl + '/v1/{+topic}/snapshots').replace(
              /([^:]\/)\/+/g,
              '$1'
            ),
            method: 'GET',
          },
          options
        ),
        params,
        requiredParams: ['topic'],
        pathParams: ['topic'],
        context: this.context,
      };
      if (callback) {
        createAPIRequest<Schema$ListTopicSnapshotsResponse>(
          parameters,
          callback
        );
      } else {
        return createAPIRequest<Schema$ListTopicSnapshotsResponse>(parameters);
      }
    }


/**
     * pubsub.projects.topics.subscriptions.list
     * @desc Lists the names of the subscriptions on this topic.
     * @example
     * * // BEFORE RUNNING:
     * // ---------------
     * // 1. If not already done, enable the Cloud Pub/Sub API
     * //    and check the quota for your project at
     * //    https://console.developers.google.com/apis/api/pubsub
     * // 2. This sample uses Application Default Credentials for authentication.
     * //    If not already done, install the gcloud CLI from
     * //    https://cloud.google.com/sdk and run
     * //    `gcloud beta auth application-default login`.
     * //    For more information, see
     * //    https://developers.google.com/identity/protocols/application-default-credentials
     * // 3. Install the Node.js client library by running
     * //    `npm install googleapis --save`
     *
     * const {google} = require('googleapis');
     * var pubsub = google.pubsub('v1');
     *
     * authorize(function(authClient) {
     *   var request = {
     *     // The name of the topic that subscriptions are attached to.
     *     // Format is `projects/{project}/topics/{topic}`.
     *     topic: 'projects/my-project/topics/my-topic',  // TODO: Update placeholder value.
     *
     *     auth: authClient,
     *   };
     *
     *   var handlePage = function(err, response) {
     *     if (err) {
     *       console.error(err);
     *       return;
     *     }
     *
     *     var subscriptionsPage = response['subscriptions'];
     *     if (!subscriptionsPage) {
     *       return;
     *     }
     *     for (var i = 0; i < subscriptionsPage.length; i++) {
     *       // TODO: Change code below to process each resource in `subscriptionsPage`:
     *       console.log(JSON.stringify(subscriptionsPage[i], null, 2));
     *     }
     *
     *     if (response.nextPageToken) {
     *       request.pageToken = response.nextPageToken;
     *       pubsub.projects.topics.subscriptions.list(request, handlePage);
     *     }
     *   };
     *
     *   pubsub.projects.topics.subscriptions.list(request, handlePage);
     * });
     *
     * function authorize(callback) {
     *   google.auth.getClient({
     *     scopes: ['https://www.googleapis.com/auth/cloud-platform']
     *   }).then(client => {
     *     callback(client);
     *   }).catch(err => {
     *     console.error('authentication failed: ', err);
     *   });
     * }
     * @alias pubsub.projects.topics.subscriptions.list
     * @memberOf! ()
     *
     * @param {object} params Parameters for request
     * @param {integer=} params.pageSize Maximum number of subscription names to return.
     * @param {string=} params.pageToken The value returned by the last `ListTopicSubscriptionsResponse`; indicates that this is a continuation of a prior `ListTopicSubscriptions` call, and that the system should return the next page of data.
     * @param {string} params.topic The name of the topic that subscriptions are attached to. Format is `projects/{project}/topics/{topic}`.
     * @param {object} [options] Optionally override request options, such as `url`, `method`, and `encoding`.
     * @param {callback} callback The callback that handles the response.
     * @return {object} Request object
     */
list(
      params?: Params$Resource$Projects$Topics$Subscriptions$List,
      options?: MethodOptions
    ): GaxiosPromise<Schema$ListTopicSubscriptionsResponse>;


list(
      params: Params$Resource$Projects$Topics$Subscriptions$List,
      options:
        | MethodOptions
        | BodyResponseCallback<Schema$ListTopicSubscriptionsResponse>,
      callback: BodyResponseCallback<Schema$ListTopicSubscriptionsResponse>
    ): void;


list(
      params: Params$Resource$Projects$Topics$Subscriptions$List,
      callback: BodyResponseCallback<Schema$ListTopicSubscriptionsResponse>
    ): void;


list(
      callback: BodyResponseCallback<Schema$ListTopicSubscriptionsResponse>
    ): void;


list(
      paramsOrCallback?:
        | Params$Resource$Projects$Topics$Subscriptions$List
        | BodyResponseCallback<Schema$ListTopicSubscriptionsResponse>,
      optionsOrCallback?:
        | MethodOptions
        | BodyResponseCallback<Schema$ListTopicSubscriptionsResponse>,
      callback?: BodyResponseCallback<Schema$ListTopicSubscriptionsResponse>
    ): void | GaxiosPromise<Schema$ListTopicSubscriptionsResponse> {
      let params = (paramsOrCallback ||
        {}) as Params$Resource$Projects$Topics$Subscriptions$List;
      let options = (optionsOrCallback || {}) as MethodOptions;

      if (typeof paramsOrCallback === 'function') {
        callback = paramsOrCallback;
        params = {} as Params$Resource$Projects$Topics$Subscriptions$List;
        options = {};
      }

      if (typeof optionsOrCallback === 'function') {
        callback = optionsOrCallback;
        options = {};
      }

      const rootUrl = options.rootUrl || 'https://pubsub.googleapis.com/';
      const parameters = {
        options: Object.assign(
          {
            url: (rootUrl + '/v1/{+topic}/subscriptions').replace(
              /([^:]\/)\/+/g,
              '$1'
            ),
            method: 'GET',
          },
          options
        ),
        params,
        requiredParams: ['topic'],
        pathParams: ['topic'],
        context: this.context,
      };
      if (callback) {
        createAPIRequest<Schema$ListTopicSubscriptionsResponse>(
          parameters,
          callback
        );
      } else {
        return createAPIRequest<Schema$ListTopicSubscriptionsResponse>(
          parameters
        );
      }
    }


async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const { PORT = 3434 } = process.env;

  await app.listen(PORT);

  Logger.log(`> :${PORT}`);
}


() => {
    it("should render with custom SDK", () => {
        const wrapper = mount(
            <Heatmap workspace="foo" measure={ReferenceMd.Amount} backend={dummyBackend()} />,
        );
        expect(wrapper.find(CoreHeatmap)).toHaveLength(1);
    });
}


() => {
        const wrapper = mount(
            <Heatmap workspace="foo" measure={ReferenceMd.Amount} backend={dummyBackend()} />,
        );
        expect(wrapper.find(CoreHeatmap)).toHaveLength(1);
    }


dummyBackend()


() => {
  const fakeLogger = {
    error: spy(),
  };
  const fakeSend = spy();
  const services: unknown = {
    store: {
      get: (key: string) =>
        Promise.resolve(key === "greeting::1111" ? "A welcome message" : undefined),
    },
    log: fakeLogger,
  };
  const handler = handleGreeting(services as Services);

  beforeEach(() => {
    fakeLogger.error.resetHistory();
    fakeSend.resetHistory();
  });

  it("should DM the new guild member with a welcome message", async () => {
    const payload: unknown = { send: fakeSend, guild: { id: "1111" } };
    await handler(payload as GuildMember);
    expect(fakeSend.firstCall.args[0]).to.equal("A welcome message");
  });
  it("should not DM the new guild member if there's no welcome message", async () => {
    const payload: unknown = { send: fakeSend, guild: { id: "1112" } };
    await handler(payload as GuildMember);
    expect(fakeSend.called).to.be.false;
  });
  it("should log the error if something goes wrong with handling the event", async () => {
    const error = new Error("Something went wrong");
    const payload: unknown = {
      send: () => Promise.reject(error),
      guild: { id: "1111" },
    };
    try {
      await handler(payload as GuildMember);
      expect(fakeLogger.error.firstCall.args[0]).to.equal(error);
    } catch (error) {
      expect.fail("Should have been handled successfully");
    }
  });
}


(key: string) =>
        Promise.resolve(key === "greeting::1111" ? "A welcome message" : undefined)


() => {
    fakeLogger.error.resetHistory();
    fakeSend.resetHistory();
  }


async () => {
    const payload: unknown = { send: fakeSend, guild: { id: "1111" } };
    await handler(payload as GuildMember);
    expect(fakeSend.firstCall.args[0]).to.equal("A welcome message");
  }


async () => {
    const payload: unknown = { send: fakeSend, guild: { id: "1112" } };
    await handler(payload as GuildMember);
    expect(fakeSend.called).to.be.false;
  }


async () => {
    const error = new Error("Something went wrong");
    const payload: unknown = {
      send: () => Promise.reject(error),
      guild: { id: "1111" },
    };
    try {
      await handler(payload as GuildMember);
      expect(fakeLogger.error.firstCall.args[0]).to.equal(error);
    } catch (error) {
      expect.fail("Should have been handled successfully");
    }
  }


() => Promise.reject(error)


(distances, visited) => {
	let shortest = null;

	for (let node in distances) {
		let currentIsShortest =
			shortest === null || distances[node] < distances[shortest];
		if (currentIsShortest && !visited.includes(node)) {
			shortest = node;
		}
	}
	return shortest;
}


(graph: Graph, startNode: string, endNode: string): { distance: number, path: string[] } => {
	// establish object for recording distances from the start node
	let distances = {};
	distances[endNode] = "Infinity";
	distances = Object.assign(distances, graph[startNode]);

	// track paths
	let parents = { endNode: null };
	for (let child in graph[startNode]) {
		parents[child] = startNode;
	}

	// track nodes that have already been visited
	let visited = [];

	// find the nearest node
	let node = shortestDistanceNode(distances, visited);

	// for that node
	while (node) {
		// find its distance from the start node & its child nodes
		let distance = distances[node];
		let children = graph[node];
		// for each of those child nodes
		for (let child in children) {
			// make sure each child node is not the start node
			if (String(child) === String(startNode)) {
				continue;
			} else {
				// save the distance from the start node to the child node
				let newdistance = distance + children[child];
				// if there's no recorded distance from the start node to the child node in the distances object
				// or if the recorded distance is shorter than the previously stored distance from the start node to the child node
				// save the distance to the object
				// record the path
				if (!distances[child] || distances[child] > newdistance) {
					distances[child] = newdistance;
					parents[child] = node;
				}
			}
		}
		// move the node to the visited set
		visited.push(node);
		// move to the nearest neighbor node
		node = shortestDistanceNode(distances, visited);
	}

	// using the stored paths from start node to end node
	// record the shortest path
	let shortestPath = [endNode];
	let parent = parents[endNode];
	while (parent) {
		shortestPath.push(parent);
		parent = parents[parent];
	}
	shortestPath.reverse();

	// return the shortest path from start node to end node & its distance
	let results = {
		distance: distances[endNode],
		path: shortestPath,
	};

	return results;
}


export type Graph = {
	[key: string]: { [key: string]: number }
};


({ row }) => {
  const classes = useStyles();
  const userData = useSelector((state: RootState) => state.userData);
  const { t } = useTranslation();

  const [open, setOpen] = React.useState(false);
  // Function to display date in format Do MMM,YYYY Hr:MM AM/PM
  const formatDate = (date: string) => {
    const day = moment(date).format('Do MMM, YYYY LT');
    return day;
  };

  // mutation to remove member
  const [removeMember, { loading }] = useMutation<MemberInvitation>(
    REMOVE_INVITATION,
    {
      onCompleted: () => {
        setOpen(false);
      },
      onError: () => {},
      refetchQueries: [
        { query: GET_USER, variables: { username: userData.username } },
      ],
    }
  );

  return (
    <>
      <TableCell className={classes.firstTC} component="th" scope="row">

          <Avatar
            data-cy="avatar"
            alt="User"
            className={classes.avatarBackground}
          >
            {row.name ? userAvatar(row.name) : userAvatar(row.user_name)}
          </Avatar>
          {row.name}

      </TableCell>
      <TableCell className={classes.otherTC}>{row.role}</TableCell>
      <TableCell className={classes.otherTC}>{row.email}</TableCell>
      <TableCell className={classes.otherTC}>

          {formatDate(row.joined_at)}

      </TableCell>

      <TableCell className={classes.otherTC} key={row.user_name}>
        <IconButton
          onClick={() => {
            setOpen(true);
          }}
        >

        </IconButton>
      </TableCell>
      <Unimodal
        isOpen={open}
        handleClose={()


(state: RootState) => state.userData


(date: string) => {
    const day = moment(date).format('Do MMM, YYYY LT');
    return day;
  }


() => {
        setOpen(false);
      }


() => {
            setOpen(true);
          }


interface TableDataProps {
  row: Member;
  index: number;
}


formatDate(row


t('settings.teamingTab.deleteModal.header')


t('settings.teamingTab.deleteModal.text')


t('settings.teamingTab.deleteModal.body')


t('settings.teamingTab.deleteModal.noButton')


loading ? (
                  <div


t('settings.teamingTab.deleteModal.yesButton')


async (apiPath: string, axiosConfig?: AxiosRequestConfig) => axios.get(apiPath, axiosConfig)


async (apiPath: string, body?: any, axiosConfig?: AxiosRequestConfig) => axios.post(apiPath, body, axiosConfig)


(browser) =>
      safariBrowsers.includes(browser)


(browser) => {
      const [agentId, version] = browser.split(' ');

      const browserData = data.stats[agentId];
      const featureStatus = (browserData && browserData[version]) as
        | string
        | undefined;

      // We are only interested in the first character
      // Ex: when 'a #4 #5', we only need to check for 'a'
      // as for such cases we should polyfill these features as needed
      return !featureStatus || !criteria.includes(featureStatus.charAt(0));
    }


export class BuildBrowserFeatures {
  private readonly _supportedBrowsers: string[];
  private readonly _es6TargetOrLater: boolean;

  constructor(
    private projectRoot: string,
    private scriptTarget: ts.ScriptTarget
  ) {
    this._supportedBrowsers = browserslist(undefined, {
      path: this.projectRoot,
    });
    this._es6TargetOrLater = this.scriptTarget > ts.ScriptTarget.ES5;
  }

  /**
   * True, when one or more browsers requires ES5
   * support and the script target is ES2015 or greater.
   */
  isDifferentialLoadingNeeded(): boolean {
    return this._es6TargetOrLater && this.isEs5SupportNeeded();
  }

  /**
   * True, when one or more browsers requires ES5 support
   */
  isEs5SupportNeeded(): boolean {
    return !this.isFeatureSupported('es6-module');
  }

  /**
   * Safari 10.1 and iOS Safari 10.3 supports modules,
   * but does not support the `nomodule` attribute.
   * While return `true`, when support for Safari 10.1 and iOS Safari 10.3
   * is required and in differential loading is enabled.
   */
  isNoModulePolyfillNeeded(): boolean {
    if (!this.isDifferentialLoadingNeeded()) {
      return false;
    }

    const safariBrowsers = ['safari 10.1', 'ios_saf 10.3'];

    return this._supportedBrowsers.some((browser) =>
      safariBrowsers.includes(browser)
    );
  }

  /**
   * True, when a browser feature is supported partially or fully.
   */
  isFeatureSupported(featureId: string): boolean {
    // y: feature is fully available
    // n: feature is unavailable
    // a: feature is partially supported
    // x: feature is prefixed
    const criteria = ['y', 'a'];

    const data = feature(features[featureId]);

    return !this._supportedBrowsers.some((browser) => {
      const [agentId, version] = browser.split(' ');

      const browserData = data.stats[agentId];
      const featureStatus = (browserData && browserData[version]) as
        | string
        | undefined;

      // We are only interested in the first character
      // Ex: when 'a #4 #5', we only need to check for 'a'
      // as for such cases we should polyfill these features as needed
      return !featureStatus || !criteria.includes(featureStatus.charAt(0));
    });
  }
}


/**
   * True, when one or more browsers requires ES5
   * support and the script target is ES2015 or greater.
   */
isDifferentialLoadingNeeded(): boolean {
    return this._es6TargetOrLater && this.isEs5SupportNeeded();
  }


/**
   * True, when one or more browsers requires ES5 support
   */
isEs5SupportNeeded(): boolean {
    return !this.isFeatureSupported('es6-module');
  }


/**
   * Safari 10.1 and iOS Safari 10.3 supports modules,
   * but does not support the `nomodule` attribute.
   * While return `true`, when support for Safari 10.1 and iOS Safari 10.3
   * is required and in differential loading is enabled.
   */
isNoModulePolyfillNeeded(): boolean {
    if (!this.isDifferentialLoadingNeeded()) {
      return false;
    }

    const safariBrowsers = ['safari 10.1', 'ios_saf 10.3'];

    return this._supportedBrowsers.some((browser) =>
      safariBrowsers.includes(browser)
    );
  }


/**
   * True, when a browser feature is supported partially or fully.
   */
isFeatureSupported(featureId: string): boolean {
    // y: feature is fully available
    // n: feature is unavailable
    // a: feature is partially supported
    // x: feature is prefixed
    const criteria = ['y', 'a'];

    const data = feature(features[featureId]);

    return !this._supportedBrowsers.some((browser) => {
      const [agentId, version] = browser.split(' ');

      const browserData = data.stats[agentId];
      const featureStatus = (browserData && browserData[version]) as
        | string
        | undefined;

      // We are only interested in the first character
      // Ex: when 'a #4 #5', we only need to check for 'a'
      // as for such cases we should polyfill these features as needed
      return !featureStatus || !criteria.includes(featureStatus.charAt(0));
    });
  }


user => {
        if (user) return true;
        this.toastr.error('You shall not pass!')
      }


@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private accountService: AccountService, private toastr: ToastrService) {}

  canActivate(): Observable<boolean> {
    return this.accountService.currentUser$.pipe(
      map(user => {
        if (user) return true;
        this.toastr.error('You shall not pass!')
      })
    )
  }

}


canActivate(): Observable<boolean> {
    return this.accountService.currentUser$.pipe(
      map(user => {
        if (user) return true;
        this.toastr.error('You shall not pass!')
      })
    )
  }


function isAmbient() {
                return hasFlag(modifiers, Modifiers.Ambient) || hasFlag(parentModifiers, Modifiers.Ambient);
            }


function mayNotBeExported() {
                if (hasFlag(modifiers, Modifiers.Exported)) {
                    this.reportError("Statement may not be exported");
                }
            }


export function quickParse(logger: TypeScript.ILogger, scopeStartAST: AST, sourceText: ISourceText, minChar: number, limChar: number,
        errorCapture: (minChar: number, charLen: number, message: string, unitIndex: number) => void ): QuickParseResult {

        var fragment = sourceText.getText(minChar, limChar);
        logger.log("Quick parse range (" + minChar + "," + limChar + "): \"" + TypeScript.stringToLiteral(fragment, 100) + "\"");

        var quickParser = new Parser();
        quickParser.setErrorRecovery(null);
        quickParser.errorCallback = errorCapture;

        // REVIEW: use enclosing scope to determine this
        // REVIEW: Why even use class here?
        var quickClassDecl = new ClassDeclaration(null, null, null, null);
        quickParser.currentClassDecl = quickClassDecl;

        var result = quickParser.quickParse(new StringSourceText(fragment), "", 0);
        return result;
    }


(operand: AST) : boolean => {
                if (operand.nodeType == NodeType.Comma) {
                    return this.transformAnonymousArgsIntoFormals(formals, operand);
                }
                else if (operand.nodeType == NodeType.Name || operand.nodeType == NodeType.Asg) {
                    var opArg = operand.nodeType == NodeType.Asg ? (<BinaryExpression>operand).operand1 : operand;

                    var arg = new ArgDecl(<Identifier>opArg);
                    arg.preComments = opArg.preComments;
                    arg.postComments = opArg.postComments;
                    arg.minChar = operand.minChar;
                    arg.limChar = operand.limChar;

                    if (hasFlag(opArg.flags, ASTFlags.PossibleOptionalParameter)) {
                        arg.isOptional = true;
                    }

                    if (operand.nodeType == NodeType.Asg) {
                        arg.init = (<BinaryExpression>operand).operand2;
                    }

                    formals.append(arg);

                    return arg.isOptional || arg.init;
                }
                else {
                    this.reportParseError("Invalid lambda argument");
                }
                return false;
            }


(message) =>this.reportParseError(message)


export class QuickParseResult {
        constructor (public Script: Script, public endLexState: LexState) { }
    }


export interface IStatementInfo {
        stmt: Statement;
        labels: ASTList;
    }


export interface ILambdaArgumentContext {
        preProcessedLambdaArgs: AST;
    }


export enum TypeContext {
        NoTypes = 0,
        ArraySuffix = 1,
        Primitive = 2,
        Named = 4,
        AllSimpleTypes = Primitive | Named,
        AllTypes = Primitive | Named | ArraySuffix,
    }


export enum ParseState {
        None,
        StartScript,
        StartStatementList,
        StartStatement,
        StartFncDecl,
        FncDeclName,
        FncDeclArgs,
        FncDeclReturnType,
        ForInit,
        ForInitAfterVar,
        ForCondStart,
        EndStmtList,
        EndScript,
    }


private resetStmtStack() {
            this.statementInfoStack = new IStatementInfo[];
        }


private inLoop() {
            for (var j = this.statementInfoStack.length - 1; j >= 0; j--) {
                if (this.statementInfoStack[j].stmt.isLoop()) {
                    return true;
                }
            }
            return false;
        }


private pushStmt(stmt: Statement, labels: ASTList) {
            // allocate here to avoid always storing this information in statements
            var info = { stmt: stmt, labels: labels };
            this.statementInfoStack.push(info);
        }


private popStmt(): IStatementInfo {
            return this.statementInfoStack.pop();
        }


private resolveJumpTarget(jump: Jump): void {
            var resolvedTarget = AST.getResolvedIdentifierName(jump.target);
            var len = this.statementInfoStack.length;
            for (var i = len - 1; i >= 0; i--) {
                var info = this.statementInfoStack[i];
                if (jump.target) {
                    if (info.labels && (info.labels.members.length > 0)) {
                        for (var j = 0, labLen = info.labels.members.length; j < labLen; j++) {
                            var label = <Label>info.labels.members[j];
                            if (label.id.text == resolvedTarget) {
                                jump.setResolvedTarget(this, info.stmt);
                                return;
                            }
                        }
                    }
                }
                else {
                    if (info.stmt.isLoop()) {
                        jump.setResolvedTarget(this, info.stmt);
                        return;
                    }
                    else if ((info.stmt.nodeType == NodeType.Switch) && (jump.nodeType == NodeType.Break)) {
                        jump.setResolvedTarget(this, info.stmt);
                        return;
                    }
                }
            }
            // no luck
            if (jump.target) {
                this.reportParseError("could not find enclosing statement with label " + jump.target);
            }
            else {
                if (jump.nodeType == NodeType.Break) {
                    this.reportParseError("break statement requires enclosing loop or switch");
                }
                else {
                    this.reportParseError("continue statement requires enclosing loop");
                }
            }
        }


public setErrorRecovery(outfile: ITextWriter) {
            this.outfile = outfile;
            this.errorRecovery = true;
        }


public getSourceLineCol(lineCol: ILineCol, minChar: number): void {
            getSourceLineColFromMap(lineCol, minChar, this.scanner.lineMap);
        }


private createRef(text: string, hasEscapeSequence: boolean, minChar: number): Identifier {
            var id = new Identifier(text, hasEscapeSequence);
            id.minChar = minChar;
            return id;
        }


private reportParseStyleError(message: string) {
            this.reportParseError("STYLE: " + message);
        }


public reportParseError(message: string, startPos = this.scanner.startPos, pos = this.scanner.pos) {
            var len = Math.max(1, pos - startPos);
            if (this.errorCallback) {
                this.errorCallback(startPos, len, message, this.currentUnitIndex);
            }
            else if (this.errorRecovery) {
                var lineCol = { line: -1, col: -1 };
                this.getSourceLineCol(lineCol, startPos);
                if (this.outfile) {
                    this.outfile.WriteLine("// " + this.fname + " (" + lineCol.line + "," + lineCol.col + "): " + message);
                }
            }
            else {
                throw new SyntaxError(this.fname + " (" + this.scanner.line + "," + this.scanner.col + "): " + message);
            }
        }


private checkNextToken(tokenId: TokenID, errorRecoverySet: ErrorRecoverySet, errorText: string = null): void {
            this.currentToken = this.scanner.scan();
            this.checkCurrentToken(tokenId, errorRecoverySet, errorText);
        }


private skip(errorRecoverySet: ErrorRecoverySet) {
            errorRecoverySet |= ErrorRecoverySet.EOF;
            var ersTok = ErrorRecoverySet.None;
            var tokenInfo = lookupToken(this.currentToken.tokenId);
            if (tokenInfo != undefined) {
                ersTok = tokenInfo.ers;
            }
            var pendingRightCurlies = 0;
            while (((ersTok & errorRecoverySet) == ErrorRecoverySet.None) ||
                   (this.currentToken.tokenId == TokenID.CloseBrace) && (pendingRightCurlies > 0)) {
                if (this.currentToken.tokenId == TokenID.OpenBrace) {
                    pendingRightCurlies++;
                }
                else if (this.currentToken.tokenId == TokenID.CloseBrace) {
                    pendingRightCurlies--;
                }
                this.currentToken = this.scanner.scan();
                ersTok = ErrorRecoverySet.None;
                tokenInfo = lookupToken(this.currentToken.tokenId);
                if (tokenInfo != undefined) {
                    ersTok = tokenInfo.ers;
                }
                // TODO: regex rescan
            }
        }


private checkCurrentToken(tokenId: TokenID, errorRecoverySet: ErrorRecoverySet, errorText: string = null): void {
            if (this.currentToken.tokenId != tokenId) {
                errorText = errorText == null ? ("Expected '" + tokenTable[tokenId].text + "'") : errorText;
                this.reportParseError(errorText);
                if (this.errorRecovery) {
                    this.skip(errorRecoverySet);
                }
            }
            else {
                this.currentToken = this.scanner.scan();
            }
        }


private pushDeclLists() {
            this.staticsLists.push(new ASTList());
            this.varLists.push(new ASTList());
            this.scopeLists.push(new ASTList());
        }


private popDeclLists() {
            this.staticsLists.pop();
            this.varLists.pop();
            this.scopeLists.pop();
        }


private topVarList() {
            return this.varLists[this.varLists.length - 1];
        }


private topScopeList() {
            return this.scopeLists[this.scopeLists.length - 1];
        }


private topStaticsList() {
            return this.staticsLists[this.staticsLists.length - 1];
        }


private parseComment(comment: CommentToken) {
            if (comment) {
                var c: Comment = new Comment(comment.value, comment.isBlock, comment.endsLine);
                c.minChar = comment.startPos;
                c.limChar = comment.startPos + comment.value.length;
                var lineCol = { line: -1, col: -1 };
                this.getSourceLineCol(lineCol, c.minChar);
                c.minLine = lineCol.line;
                this.getSourceLineCol(lineCol, c.limChar);
                c.limLine = lineCol.line;

                if (!comment.isBlock && comment.value.length > 3 && comment.value.substring(0, 3) == "///") {
                    var dependencyPath = getAdditionalDependencyPath(comment.value);

                    if (dependencyPath) {
                        this.amdDependencies.push(dependencyPath);
                    }

                    if (getImplicitImport(comment.value)) {
                        this.hasTopLevelImportOrExport = true;
                    }
                }

                return c;
            }
            else {
                return null;
            }
        }


private parseCommentsInner(comments: CommentToken[]) {
            if (comments) {
                var commentASTs: Comment[] = new Comment[];
                for (var i = 0; i < comments.length; i++) {
                    commentASTs.push(this.parseComment(comments[i]));
                }
                return commentASTs;
            } else {
                return null;
            }
        }


private parseComments() {
            var comments = this.scanner.getComments();
            return this.parseCommentsInner(comments);
        }


private parseCommentsForLine(line: number) {
            var comments = this.scanner.getCommentsForLine(line);

            return this.parseCommentsInner(comments);
        }


private combineComments(comment1: Comment[], comment2: Comment[]) {
            if (comment1 == null) {
                return comment2;
            }
            else if (comment2 == null) {
                return comment1;
            }
            else {
                return comment1.concat(comment2);
            }
        }


private parseEnumDecl(errorRecoverySet: ErrorRecoverySet, modifiers: Modifiers): ModuleDeclaration {
            var leftCurlyCount = this.scanner.leftCurlyCount;
            var rightCurlyCount = this.scanner.rightCurlyCount;

            var name: Identifier = null;
            if ((this.currentToken.tokenId == TokenID.Identifier) || convertTokToID(this.currentToken, this.strictMode)) {
                name = Identifier.fromToken(this.currentToken);
                name.minChar = this.scanner.startPos;
                name.limChar = this.scanner.pos;
                this.currentToken = this.scanner.scan();
            }
            else {
                this.reportParseError("Enum declaration requires identifier");
                if (this.errorRecovery) {
                    name = new MissingIdentifier();
                    name.minChar = this.scanner.startPos;
                    name.limChar = this.scanner.startPos;
                    name.flags |= ASTFlags.Error;
                }
            }

            var membersMinChar = this.scanner.startPos;
            this.checkCurrentToken(TokenID.OpenBrace, errorRecoverySet | ErrorRecoverySet.ID);
            this.pushDeclLists();
            var members = new ASTList();
            members.minChar = membersMinChar;
            var mapDecl = new VarDecl(new Identifier("_map"), 0);
            mapDecl.varFlags |= VarFlags.Exported;
            mapDecl.varFlags |= VarFlags.Private;

            // REVIEW: Is this still necessary?
            mapDecl.varFlags |= (VarFlags.Property | VarFlags.Public);
            mapDecl.init = new UnaryExpression(NodeType.ArrayLit, null);
            members.append(mapDecl);
            var lastValue: NumberLiteral = null;
            for (; ;) {
                var minChar = this.scanner.startPos;
                var limChar;
                var memberName: Identifier = null;
                var memberValue: AST = null;
                var preComments = null;
                var postComments = null;

                if ((this.currentToken.tokenId == TokenID.Identifier) || convertTokToIDName(this.currentToken)) {
                    memberName = Identifier.fromToken(this.currentToken);
                    memberName.minChar = this.scanner.startPos;
                    memberName.limChar = this.scanner.pos;
                }
                else if (this.currentToken.tokenId == TokenID.CloseBrace) {
                    break;
                }
                else {
                    this.reportParseError("Expected identifer of enum member");
                    if (this.errorRecovery) {
                        memberName = new MissingIdentifier();
                        memberName.minChar = this.scanner.startPos;
                        memberName.limChar = this.scanner.startPos;
                        memberName.flags |= ASTFlags.Error;
                    }
                }

                limChar = this.scanner.pos;
                preComments = this.parseComments();
                this.currentToken = this.scanner.scan();
                postComments = this.parseComments();

                if (this.currentToken.tokenId == TokenID.Equals) {
                    this.currentToken = this.scanner.scan();
                    memberValue = this.parseExpr(errorRecoverySet, OperatorPrecedence.Comma, true,
                                          TypeContext.NoTypes);
                    lastValue = <NumberLiteral>memberValue;
                    limChar = memberValue.limChar;
                }
                else {
                    if (lastValue == null) {
                        memberValue = new NumberLiteral(0);
                        lastValue = <NumberLiteral>memberValue;
                    }
                    else {
                        memberValue = new NumberLiteral(lastValue.value + 1);
                        lastValue = <NumberLiteral>memberValue;
                    }
                    var map: BinaryExpression =
                        new BinaryExpression(NodeType.Asg,
                                             new BinaryExpression(NodeType.Index,
                                                                  new Identifier("_map"),
                                                                  memberValue),
                                             new StringLiteral('"' + memberName.actualText + '"'));
                    members.append(map);
                }
                var member = new VarDecl(memberName, this.nestingLevel);
                member.minChar = minChar;
                member.limChar = limChar;
                member.init = memberValue;
                // Note: Leave minChar, limChar as "-1" on typeExpr as this is a parsing artifact.
                member.typeExpr = new TypeReference(this.createRef(name.actualText, name.hasEscapeSequence, -1), 0);
                member.varFlags |= (VarFlags.Readonly | VarFlags.Property);
                if (memberValue.nodeType == NodeType.NumberLit) {
                    member.varFlags |= VarFlags.Constant;
                }
                member.preComments = preComments;
                members.append(member);
                member.postComments = postComments;
                // all enum members are exported
                member.varFlags |= VarFlags.Exported;

                if (this.currentToken.tokenId == TokenID.Comma) {
                    this.currentToken = this.scanner.scan();
                    member.postComments = this.combineComments(member.postComments, this.parseCommentsForLine(this.scanner.prevLine));
                    if ((this.currentToken.tokenId == TokenID.Identifier) || (convertTokToIDName(this.currentToken))) {
                        continue;
                    }
                }
                break;
            }
            var endingToken = new ASTSpan();
            endingToken.minChar = this.scanner.startPos;
            endingToken.limChar = this.scanner.pos;

            this.checkCurrentToken(TokenID.CloseBrace, errorRecoverySet);
            members.limChar = this.scanner.lastTokenLimChar();
            var modDecl = new ModuleDeclaration(name, members, this.topVarList(), this.topScopeList(), endingToken);
            modDecl.modFlags |= ModuleFlags.IsEnum;
            this.popDeclLists();

            modDecl.leftCurlyCount = this.scanner.leftCurlyCount - leftCurlyCount;
            modDecl.rightCurlyCount = this.scanner.rightCurlyCount - rightCurlyCount;
            return modDecl;
        }


private parseDottedName(enclosedList: AST[]): void {
            this.currentToken = this.scanner.scan();
            if ((this.currentToken.tokenId == TokenID.Identifier) || convertTokToID(this.currentToken, this.strictMode)) {
                var id = Identifier.fromToken(this.currentToken);
                id.preComments = this.parseComments();
                enclosedList[enclosedList.length] = id;
                id.minChar = this.scanner.startPos;
                id.limChar = this.scanner.pos;
                this.currentToken = this.scanner.scan();
                if (this.currentToken.tokenId == TokenID.Dot) {
                    this.parseDottedName(enclosedList);
                }
            }
            else {
                this.reportParseError("need identifier after '.'");
            }
        }


// REVIEW: This is much more lenient than the spec - we're basically just checking to see if the
// path is rooted or contains an extension, not if it could potentially be a bogus file path
private isValidImportPath(importPath: string) {
            importPath = stripQuotes(importPath);

            if (!importPath ||
                importPath.indexOf(':') != -1 ||
                importPath.indexOf('\\') != -1 ||
                //(importPath.indexOf('.') != -1 && importPath.charAt(0) != '.') ||
                importPath.charAt(0) == '/') {
                return false;
            }
            return true;
        }


private parseImportDeclaration(errorRecoverySet: ErrorRecoverySet, modifiers: Modifiers): ImportDeclaration {

            var name: Identifier = null;
            var alias: AST = null;
            var importDecl: ImportDeclaration = null;
            var minChar = this.scanner.startPos;
            var isDynamicImport = false;

            this.currentToken = this.scanner.scan();

            if (this.currentToken.tokenId == TokenID.Identifier || convertTokToID(this.currentToken, this.strictMode)) {
                name = Identifier.fromToken(this.currentToken);
            }
            else {
                this.reportParseError("Expected identifer after 'import'");
                name = new MissingIdentifier();
            }

            name.minChar = this.scanner.startPos;
            name.limChar = this.scanner.pos;

            this.currentToken = this.scanner.scan();

            this.checkCurrentToken(TokenID.Equals, errorRecoverySet | ErrorRecoverySet.ID);

            var aliasPreComments = this.parseComments();

            var limChar;
            if (this.currentToken.tokenId == TokenID.Identifier || convertTokToID(this.currentToken, this.strictMode)) {

                if (this.currentToken.tokenId == TokenID.Module) {
                    limChar = this.scanner.pos;
                    this.currentToken = this.scanner.scan();
                    if (this.currentToken.tokenId == TokenID.OpenParen) {
                        this.currentToken = this.scanner.scan();

                        if (this.currentToken.tokenId == TokenID.StringLiteral || this.currentToken.tokenId == TokenID.Identifier || convertTokToID(this.currentToken, this.strictMode)) {

                            if (this.currentToken.tokenId == TokenID.StringLiteral) {

                                if (this.topLevel) {
                                    this.hasTopLevelImportOrExport = true;
                                } else if (!this.allowImportDeclaration) {
                                    this.reportParseError("Import declaration of external module is permitted only in global or top level dynamic modules");
                                }

                                var aliasText = this.currentToken.getText();
                                alias = Identifier.fromToken(this.currentToken);
                                alias.minChar = this.scanner.startPos;
                                alias.limChar = this.scanner.pos;

                                if (!this.isValidImportPath((<Identifier>alias).text)) {
                                    this.reportParseError("Invalid import path");
                                }

                                isDynamicImport = true;
                                this.currentToken = this.scanner.scan();

                                alias.preComments = aliasPreComments;
                            }
                            else {
                                alias = this.parseExpr(errorRecoverySet | ErrorRecoverySet.SColon,
                                            OperatorPrecedence.Assignment, true,
                                            TypeContext.NoTypes);

                                alias.preComments = aliasPreComments;
                            }
                        }

                        limChar = this.scanner.pos;
                        this.checkCurrentToken(TokenID.CloseParen, errorRecoverySet | ErrorRecoverySet.ID);

                        if (alias) {
                            alias.postComments = this.parseComments();
                        }
                    }
                }
                else {
                    alias = this.parseExpr(errorRecoverySet | ErrorRecoverySet.SColon,
                                            OperatorPrecedence.Assignment, true,
                                            TypeContext.NoTypes);
                    limChar = this.scanner.pos; // Include semicolon if needed
                }
            }
            else {
                this.reportParseError("Expected module name");
                alias = new MissingIdentifier();
                alias.minChar = this.scanner.startPos;
                if (this.currentToken.tokenId == TokenID.Semicolon) {
                    alias.limChar = this.scanner.startPos;
                } else {
                    alias.limChar = this.scanner.pos;
                    this.currentToken = this.scanner.scan();
                }
                alias.flags |= ASTFlags.Error;
                limChar = alias.limChar;
            }

            importDecl = new ImportDeclaration(name, alias);
            importDecl.isDynamicImport = isDynamicImport;

            importDecl.minChar = minChar;
            importDecl.limChar = limChar;

            return importDecl;
        }


private parseModuleDecl(errorRecoverySet: ErrorRecoverySet, modifiers: Modifiers, preComments: Comment[]): ModuleDeclaration {
            var leftCurlyCount = this.scanner.leftCurlyCount;
            var rightCurlyCount = this.scanner.rightCurlyCount;

            var svAmbient = this.ambientModule;
            var svTopLevel = this.topLevel;
            this.topLevel = false;
            if (this.parsingDeclareFile || svAmbient || hasFlag(modifiers, Modifiers.Ambient)) {
                this.ambientModule = true;
            }

            this.currentToken = this.scanner.scan();
            var name: AST = null;
            var enclosedList: AST[] = null;
            this.pushDeclLists();
            var minChar = this.scanner.startPos;
            var isDynamicMod = false;

            if ((this.currentToken.tokenId == TokenID.Identifier) || (this.currentToken.tokenId == TokenID.StringLiteral) || (!isPrimitiveTypeToken(this.currentToken) && convertTokToID(this.currentToken, this.strictMode))) {
                var nameText = this.currentToken.getText();

                if (this.currentToken.tokenId == TokenID.StringLiteral) {
                    isDynamicMod = true;
                    if (!this.ambientModule) {
                        this.reportParseError("Only ambient dynamic modules may have string literal names");
                    }

                    if (!svTopLevel) {
                        this.reportParseError("Dynamic modules may not be nested within other modules");
                    }
                }

                name = Identifier.fromToken(this.currentToken);
                name.minChar = this.scanner.startPos;
                name.limChar = this.scanner.pos;

                this.currentToken = this.scanner.scan();
            }
            else if (this.currentToken.tokenId == TokenID.OpenBrace) {
                this.reportParseError("Module name missing");
                name = new Identifier("");
                // "fake" position of where the ID would be
                name.minChar = minChar;
                name.limChar = minChar;
            }

            if (this.currentToken.tokenId == TokenID.Dot) {
                enclosedList = new AST[];
                this.parseDottedName(enclosedList);
            }

            if (name == null) {
                name = new MissingIdentifier();
            }

            var moduleBody = new ASTList();
            var bodyMinChar = this.scanner.startPos;
            this.checkCurrentToken(TokenID.OpenBrace, errorRecoverySet | ErrorRecoverySet.ID);

            if (svTopLevel && isDynamicMod) {
                this.allowImportDeclaration = true;
            } else {
                this.allowImportDeclaration = false;
            }
            this.parseStatementList(
                errorRecoverySet | ErrorRecoverySet.RCurly, moduleBody,
                /*sourceElements:*/ true, /*noLeadingCase:*/ true, AllowedElements.Global, modifiers);
            moduleBody.minChar = bodyMinChar;
            moduleBody.limChar = this.scanner.pos;

            var endingToken = new ASTSpan();
            endingToken.minChar = this.scanner.startPos;
            endingToken.limChar = this.scanner.pos;
            this.checkCurrentToken(TokenID.CloseBrace, errorRecoverySet);

            var limChar = this.scanner.lastTokenLimChar();
            var moduleDecl: ModuleDeclaration;

            this.allowImportDeclaration = svTopLevel;

            if (enclosedList && (enclosedList.length > 0)) {
                var len = enclosedList.length;
                var innerName = <Identifier>enclosedList[len - 1];
                var innerDecl = new ModuleDeclaration(innerName, moduleBody, this.topVarList(),
                                                this.topScopeList(), endingToken);
                innerDecl.preComments = preComments;

                if (this.parsingDeclareFile || hasFlag(modifiers, Modifiers.Ambient)) {
                    innerDecl.modFlags |= ModuleFlags.Ambient;
                }

                innerDecl.modFlags |= ModuleFlags.Exported;

                // REVIEW: will also possibly need to re-parent comments as well
                innerDecl.minChar = minChar;
                innerDecl.limChar = limChar;

                this.popDeclLists();
                var outerModBod: ASTList;
                for (var i = len - 2; i >= 0; i--) {
                    outerModBod = new ASTList();
                    outerModBod.append(innerDecl);
                    innerName = <Identifier>enclosedList[i];
                    innerDecl = new ModuleDeclaration(innerName, outerModBod, new ASTList(),
                                                new ASTList(), endingToken);
                    outerModBod.minChar = innerDecl.minChar = minChar;
                    outerModBod.limChar = innerDecl.limChar = limChar;

                    if (this.parsingDeclareFile || hasFlag(modifiers, Modifiers.Ambient)) {
                        innerDecl.modFlags |= ModuleFlags.Ambient;
                    }

                    innerDecl.modFlags |= ModuleFlags.Exported;
                }
                outerModBod = new ASTList();
                outerModBod.append(innerDecl);
                outerModBod.minChar = minChar;
                outerModBod.limChar = limChar;
                moduleDecl = new ModuleDeclaration(<Identifier>name, outerModBod, new ASTList(),
                                            new ASTList(), endingToken);
            }
            else {
                moduleDecl = new ModuleDeclaration(<Identifier>name, moduleBody, this.topVarList(), this.topScopeList(), endingToken);
                moduleDecl.preComments = preComments;
                this.popDeclLists();
            }

            if (this.parsingDeclareFile || svAmbient || hasFlag(modifiers, Modifiers.Ambient)) {
                moduleDecl.modFlags |= ModuleFlags.Ambient;
            }
            if (svAmbient || hasFlag(modifiers, Modifiers.Exported)) {
                moduleDecl.modFlags |= ModuleFlags.Exported;
            }
            if (isDynamicMod) {
                moduleDecl.modFlags |= ModuleFlags.IsDynamic;
            }

            this.ambientModule = svAmbient;

            this.topLevel = svTopLevel;
            moduleDecl.leftCurlyCount = this.scanner.leftCurlyCount - leftCurlyCount;
            moduleDecl.rightCurlyCount = this.scanner.rightCurlyCount - rightCurlyCount;
            moduleDecl.limChar = moduleBody.limChar;
            return moduleDecl;
        }


private parseTypeReferenceTail(errorRecoverySet: ErrorRecoverySet, minChar: number, term: AST): TypeReference {
            var result = new TypeReference(term, 0);
            result.minChar = minChar;
            while (this.currentToken.tokenId == TokenID.OpenBracket) {
                this.currentToken = this.scanner.scan();
                result.arrayCount++;
                this.checkCurrentToken(TokenID.CloseBracket, errorRecoverySet | ErrorRecoverySet.LBrack);
            }
            result.limChar = this.scanner.lastTokenLimChar();
            return result;
        }


// REVIEW: Consider renaming to parseTypeName.
private parseNamedType(errorRecoverySet: ErrorRecoverySet, minChar: number, term: AST, tail: boolean): AST {
            this.currentToken = this.scanner.scan();
            if (this.currentToken.tokenId == TokenID.Dot) {
                var curpos = this.scanner.pos;
                this.currentToken = this.scanner.scan();
                // Don't allow reserved words if immediately after a new line and error recovery is enabled
                if ((this.currentToken.tokenId == TokenID.Identifier) || ((!this.errorRecovery || !this.scanner.lastTokenHadNewline()) && convertTokToID(this.currentToken, this.strictMode))) {
                    var op2 = Identifier.fromToken(this.currentToken);
                    op2.minChar = this.scanner.startPos;
                    op2.limChar = this.scanner.pos;
                    var dotNode = new BinaryExpression(NodeType.Dot, term, op2);
                    dotNode.minChar = term.minChar;
                    dotNode.limChar = op2.limChar;
                    return this.parseNamedType(errorRecoverySet, minChar,
                                            dotNode, tail);
                }
                else {
                    this.reportParseError("need identifier after '.'");
                    if (this.errorRecovery) {
                        term.flags |= ASTFlags.DotLHS;
                        // We set "limChar" to be slightly innacurate for completion list behavior
                        // (last AST node from "quickParse" will match DotLHS and be at end of file position)
                        // This is to match the behavior of TokenId.Dot processing in parsePostfixOperators.
                        term.limChar = this.scanner.lastTokenLimChar();
                        return term;
                    }
                    else {
                        var eop2 = new MissingIdentifier();
                        eop2.minChar = this.scanner.pos;
                        eop2.limChar = this.scanner.pos;
                        var edotNode = new BinaryExpression(NodeType.Dot, term, eop2);
                        edotNode.flags |= ASTFlags.Error;
                        edotNode.minChar = term.minChar;
                        edotNode.limChar = eop2.limChar;
                        return this.parseNamedType(errorRecoverySet, minChar,
                                                edotNode, tail);
                    }
                }
            }
            else {
                if (tail) {
                    return this.parseTypeReferenceTail(errorRecoverySet, minChar, term);
                }
                else {
                    return term;
                }
            }
        }


// REVIEW: Reconsider renaming this to parseType to match the grammar.
private parseTypeReference(errorRecoverySet: ErrorRecoverySet, allowVoid: boolean): AST {
            var minChar = this.scanner.startPos;
            var isConstructorMember = false;

            switch (this.currentToken.tokenId) {
                case TokenID.Void:
                    if (!allowVoid) {
                        this.reportParseError("void not a valid type in this context");
                    }
                // Intentional fall-through
                case TokenID.Any:
                case TokenID.Number:
                case TokenID.Bool:
                case TokenID.String: {
                    var text = tokenTable[this.currentToken.tokenId].text;
                    var predefinedIdentifier = new Identifier(text);
                    predefinedIdentifier.minChar = minChar;
                    predefinedIdentifier.limChar = this.scanner.pos;
                    this.currentToken = this.scanner.scan();
                    return this.parseTypeReferenceTail(errorRecoverySet, minChar, predefinedIdentifier);
                }

                case TokenID.Identifier:
                    var ident = this.createRef(this.currentToken.getText(), (<IdentifierToken>this.currentToken).hasEscapeSequence, minChar);
                    ident.limChar = this.scanner.pos;
                    return this.parseNamedType(errorRecoverySet, minChar, ident, true);

                case TokenID.OpenBrace:
                    return this.parseObjectType(minChar, errorRecoverySet);

                case TokenID.New:
                    this.currentToken = this.scanner.scan();
                    // can't use chkCurrentTok, since we don't want to advance the token
                    if (this.currentToken.tokenId != TokenID.OpenParen) {
                        this.reportParseError("Expected '('");
                    }
                    else {
                        isConstructorMember = true;
                        // fall through...
                    }

                case TokenID.OpenParen: {
                    // ( formals ) => type
                    var formals = new ASTList();
                    var variableArgList =
                        this.parseFormalParameterList(errorRecoverySet | ErrorRecoverySet.RParen,
                                            formals, false, true, false, false, false, false, null, true);
                    this.checkCurrentToken(TokenID.EqualsGreaterThan, errorRecoverySet);
                    var returnType = this.parseTypeReference(errorRecoverySet, true);
                    var funcDecl = new FuncDecl(null, null, false, formals, null, null, null,
                                                NodeType.FuncDecl);
                    funcDecl.returnTypeAnnotation = returnType;
                    funcDecl.variableArgList = variableArgList;
                    funcDecl.fncFlags |= FncFlags.Signature;

                    if (isConstructorMember) {
                        funcDecl.fncFlags |= FncFlags.ConstructMember;
                        funcDecl.hint = "_construct";
                        funcDecl.classDecl = null;
                    }
                    funcDecl.minChar = minChar;
                    return this.parseTypeReferenceTail(errorRecoverySet, minChar, funcDecl);
                }

                default:
                    this.reportParseError("Expected type name");
                    var etr = new TypeReference(null, 0);
                    etr.flags |= ASTFlags.Error;
                    etr.minChar = this.scanner.pos;
                    etr.limChar = this.scanner.pos;
                    return etr;
            }
        }


private parseObjectType(minChar: number, errorRecoverySet: ErrorRecoverySet): TypeReference {
            this.currentToken = this.scanner.scan();

            var members = new ASTList();
            members.minChar = minChar;

            var prevInInterfaceDecl = this.inInterfaceDecl;
            this.inInterfaceDecl = true;
            this.parseTypeMemberList(errorRecoverySet | ErrorRecoverySet.RCurly, members);
            this.inInterfaceDecl = prevInInterfaceDecl;

            this.checkCurrentToken(TokenID.CloseBrace, errorRecoverySet);

            // REVIEW: We're parsing an ObjectType, but we give a NodeType of Interface here.
            var interfaceDecl = new InterfaceDeclaration(
                this.anonId, members, /*extends:*/ null, /*implementsL*/ null);

            interfaceDecl.minChar = minChar;
            interfaceDecl.limChar = members.limChar;    // "}"

            return this.parseTypeReferenceTail(errorRecoverySet, minChar, interfaceDecl);
        }


private parseFunctionBlock(errorRecoverySet: ErrorRecoverySet,
                                   allowedElements: AllowedElements,
                                   parentModifiers: Modifiers,
                                   bod: ASTList,
                                   bodMinChar: number): void {
            this.state = ParseState.StartStatementList;
            this.checkCurrentToken(TokenID.OpenBrace, errorRecoverySet | ErrorRecoverySet.StmtStart);
            var savedInFunction = this.inFunction;
            this.inFunction = true;
            this.parseStatementList(
                errorRecoverySet | ErrorRecoverySet.RCurly | ErrorRecoverySet.StmtStart,
                bod, /*sourceElements:*/ true, /*noLeadingCase:*/ false, allowedElements, parentModifiers);
            bod.minChar = bodMinChar;
            bod.limChar = this.scanner.pos;
            this.inFunction = savedInFunction;
            var ec = new EndCode();
            ec.minChar = bod.limChar;
            ec.limChar = ec.minChar;
            bod.append(ec);
        }


private parseFunctionStatements(errorRecoverySet: ErrorRecoverySet,
                                        name: Identifier,
                                        isConstructor: boolean,
                                        isMethod: boolean,
                                        args: ASTList,
                                        allowedElements: AllowedElements,
                                        minChar: number,
                                        requiresSignature: boolean,
                                        parentModifiers: Modifiers) {

            this.pushDeclLists();
            // start new statement stack
            var svStmtStack = this.statementInfoStack;
            this.resetStmtStack();

            var bod: ASTList = null;
            var wasShorthand = false;
            var isAnonLambda = false;
            var limChar: number;

            if (requiresSignature) {
                // If we require a signature, but they provided a block, then give an error, but
                // still consume the block.
                limChar = this.scanner.pos;
                if (this.currentToken.tokenId === TokenID.OpenBrace) {
                    this.reportParseError("Function declarations are not permitted within interfaces, ambient modules or classes")
                    bod = new ASTList();
                    var bodMinChar = this.scanner.startPos;

                    this.parseFunctionBlock(errorRecoverySet, allowedElements, parentModifiers, bod, bodMinChar);
                    this.checkCurrentToken(TokenID.CloseBrace, errorRecoverySet);

                    // If there's also a semicolon, then just skip over it.  We don't want to report an
                    // additional error here.
                    if (this.currentToken.tokenId === TokenID.Semicolon) {
                        this.currentToken = this.scanner.scan();
                    }
                }
                else {
                    this.checkCurrentToken(TokenID.Semicolon, errorRecoverySet, "Expected ';'");
                }
            }
            else {
                bod = new ASTList();
                var bodMinChar = this.scanner.startPos;
                if (this.currentToken.tokenId == TokenID.EqualsGreaterThan) {
                    if (isMethod) {
                        this.reportParseError("'=>' may not be used for class methods");
                    }
                    wasShorthand = true;
                    this.currentToken = this.scanner.scan();
                }

                if (wasShorthand && this.currentToken.tokenId != TokenID.OpenBrace) {
                    var retExpr = this.parseExpr(errorRecoverySet | ErrorRecoverySet.SColon,
                                            OperatorPrecedence.Assignment, true,
                                            TypeContext.NoTypes);
                    var retStmt = new ReturnStatement();
                    retStmt.returnExpression = retExpr;
                    retStmt.minChar = retExpr.minChar;
                    retStmt.limChar = retExpr.limChar;
                    bod.minChar = bodMinChar;
                    bod.append(retStmt);
                }
                else {
                    isAnonLambda = wasShorthand;
                    this.parseFunctionBlock(errorRecoverySet, allowedElements, parentModifiers, bod, bodMinChar);
                }

                limChar = this.scanner.pos;
            }

            var funcDecl = new FuncDecl(name, bod, isConstructor, args, this.topVarList(),
                                        this.topScopeList(), this.topStaticsList(), NodeType.FuncDecl);
            this.popDeclLists();
            var scopeList = this.topScopeList();
            scopeList.append(funcDecl);
            var staticFuncDecl = false;

            if (!requiresSignature) {
                if (!wasShorthand || isAnonLambda) {
                    funcDecl.endingToken = new ASTSpan();
                    funcDecl.endingToken.minChar = this.scanner.startPos;
                    funcDecl.endingToken.limChar = this.scanner.pos;
                    this.checkCurrentToken(TokenID.CloseBrace, errorRecoverySet);

                    if (isAnonLambda) {
                        funcDecl.fncFlags |= FncFlags.IsFatArrowFunction;
                    }
                }
                else {
                    funcDecl.fncFlags |= FncFlags.IsFatArrowFunction;
                    funcDecl.endingToken = new ASTSpan();

                    funcDecl.endingToken.minChar = bod.members[0].minChar;
                    funcDecl.endingToken.limChar = bod.members[0].limChar;
                }
            }
            funcDecl.minChar = minChar;
            funcDecl.limChar = limChar;

            if (!requiresSignature) {
                funcDecl.fncFlags |= FncFlags.Definition;
            }

            this.statementInfoStack = svStmtStack;
            return funcDecl;
        }


private transformAnonymousArgsIntoFormals(formals: ASTList, argList: AST) : boolean {

            var translateBinExOperand = (operand: AST) : boolean => {
                if (operand.nodeType == NodeType.Comma) {
                    return this.transformAnonymousArgsIntoFormals(formals, operand);
                }
                else if (operand.nodeType == NodeType.Name || operand.nodeType == NodeType.Asg) {
                    var opArg = operand.nodeType == NodeType.Asg ? (<BinaryExpression>operand).operand1 : operand;

                    var arg = new ArgDecl(<Identifier>opArg);
                    arg.preComments = opArg.preComments;
                    arg.postComments = opArg.postComments;
                    arg.minChar = operand.minChar;
                    arg.limChar = operand.limChar;

                    if (hasFlag(opArg.flags, ASTFlags.PossibleOptionalParameter)) {
                        arg.isOptional = true;
                    }

                    if (operand.nodeType == NodeType.Asg) {
                        arg.init = (<BinaryExpression>operand).operand2;
                    }

                    formals.append(arg);

                    return arg.isOptional || arg.init;
                }
                else {
                    this.reportParseError("Invalid lambda argument");
                }
                return false;
            }

            if (argList) {
                if (argList.nodeType == NodeType.Comma) {
                    var commaList = <BinaryExpression> argList;
                    if (commaList.operand1.isParenthesized) {
                        this.reportParseError("Invalid lambda argument", commaList.operand1.minChar, commaList.operand1.limChar);
                    }
                    if (commaList.operand2.isParenthesized) {
                        this.reportParseError("Invalid lambda argument", commaList.operand2.minChar, commaList.operand2.limChar);
                    }
                    var isOptional = translateBinExOperand(commaList.operand1);
                    isOptional = translateBinExOperand(commaList.operand2) || isOptional;
                    return isOptional;
                }
                else {
                    return translateBinExOperand(argList);
                }
            }
        }


private parseFncDecl(errorRecoverySet: ErrorRecoverySet,
                             isDecl: boolean,
                             requiresSignature: boolean,
                             isMethod: boolean,
                             methodName: Identifier,
                             indexer: boolean,
                             isStatic: boolean,
                             markedAsAmbient: boolean,
                             modifiers: Modifiers,
                             lambdaArgContext: ILambdaArgumentContext,
                             expectClosingRParen: boolean): AST {

            var leftCurlyCount = this.scanner.leftCurlyCount;
            var rightCurlyCount = this.scanner.rightCurlyCount;

            var prevInConstr = this.parsingClassConstructorDefinition;
            this.parsingClassConstructorDefinition = false;

            var name: Identifier = null;
            var fnMin = this.scanner.startPos;
            var minChar = this.scanner.pos;
            var prevNestingLevel = this.nestingLevel;
            var preComments = this.parseComments();
            var isLambda = !!lambdaArgContext;
            this.nestingLevel = 0;
            if ((!this.style_funcInLoop) && this.inLoop()) {
                this.reportParseStyleError("function declaration in loop");
            }
            if (!isMethod && !isStatic && !indexer && !lambdaArgContext) {
                // past function keyword
                this.currentToken = this.scanner.scan();
                this.state = ParseState.StartFncDecl;
                if ((this.currentToken.tokenId != TokenID.Identifier) && (!convertTokToID(this.currentToken, this.strictMode))) {
                    if (isDecl) {
                        this.reportParseError("Function declaration must include identifier");

                        this.nestingLevel = prevNestingLevel;
                        return new IncompleteAST(fnMin, this.scanner.pos);
                    }
                }
                else {
                    name = Identifier.fromToken(this.currentToken);
                    name.minChar = this.scanner.startPos;
                    name.limChar = this.scanner.pos;
                    this.currentToken = this.scanner.scan();
                }
            }
            else {
                if (methodName) {
                    name = methodName;
                }
            }

            this.state = ParseState.FncDeclName;
            var args: ASTList = new ASTList();
            var variableArgList = false;
            var isOverload = false;
            var isGetter = hasFlag(modifiers, Modifiers.Getter);
            var isSetter = hasFlag(modifiers, Modifiers.Setter);
            if ((this.currentToken.tokenId == TokenID.OpenParen) || (indexer && (this.currentToken.tokenId == TokenID.OpenBracket)) || (lambdaArgContext && (lambdaArgContext.preProcessedLambdaArgs || this.currentToken.tokenId == TokenID.DotDotDot))) {
                // arg list
                variableArgList = this.parseFormalParameterList(errorRecoverySet, args, false, requiresSignature, indexer, isGetter, isSetter, isLambda, lambdaArgContext ? lambdaArgContext.preProcessedLambdaArgs : null, expectClosingRParen);
            }
            this.state = ParseState.FncDeclArgs;
            var returnType: AST = null;
            if (this.currentToken.tokenId == TokenID.Colon) {
                this.currentToken = this.scanner.scan();
                if (hasFlag(modifiers, Modifiers.Setter)) {
                    this.reportParseError("Property setters may not declare a return type");
                }
                returnType = this.parseTypeReference(errorRecoverySet, true);
            }

            if (indexer && args.members.length == 0) {
                this.reportParseError("Index signatures require a parameter type to be specified");
            }
            this.state = ParseState.FncDeclReturnType;

            if (isLambda && this.currentToken.tokenId != TokenID.EqualsGreaterThan) {
                this.reportParseError("Expected '=>'");
            }

            // REVIEW:
            // Currently, it's imperative that ambient functions *not* be marked as overloads.  At some point, we may
            // want to unify the two concepts internally
            if (isDecl && !(this.parsingDeclareFile || markedAsAmbient) && (!isMethod || !(this.ambientModule || this.ambientClass || this.inInterfaceDecl)) && this.currentToken.tokenId == TokenID.Semicolon) {
                isOverload = true;
                isDecl = false;
                requiresSignature = true;
            }
            var svInFncDecl = this.inFncDecl;
            this.inFncDecl = true;
            var funcDecl: FuncDecl =
                this.parseFunctionStatements(
                errorRecoverySet | ErrorRecoverySet.RCurly,
                name, /*isConstructor:*/ false, isMethod, args, AllowedElements.None,
                minChar, requiresSignature, Modifiers.None);

            this.inFncDecl = svInFncDecl;
            funcDecl.variableArgList = variableArgList;
            funcDecl.isOverload = isOverload;

            if (!requiresSignature) { // REVIEW: What's the point of this?  Why not just use 'Signature' instead of 'Definition'?
                funcDecl.fncFlags |= FncFlags.Definition;
            }

            if (isStatic) {
                funcDecl.fncFlags |= FncFlags.Static;
            }

            if (requiresSignature) {
                funcDecl.fncFlags |= FncFlags.Signature;
            }
            if (indexer) {
                funcDecl.fncFlags |= FncFlags.IndexerMember;
            }
            funcDecl.returnTypeAnnotation = returnType;
            if (isMethod) {
                funcDecl.fncFlags |= FncFlags.Method;
                // all class property methods are currently exported
                funcDecl.fncFlags |= FncFlags.ClassPropertyMethodExported;
            }
            funcDecl.leftCurlyCount = this.scanner.leftCurlyCount - leftCurlyCount;
            funcDecl.rightCurlyCount = this.scanner.rightCurlyCount - rightCurlyCount;

            this.nestingLevel = prevNestingLevel;
            this.parsingClassConstructorDefinition = prevInConstr;
            funcDecl.preComments = preComments;
            return funcDecl;
        }


private convertToTypeReference(ast: AST): TypeReference {
            var result: TypeReference;
            switch (ast.nodeType) {
                case NodeType.TypeRef:
                    return <TypeReference>ast;
                case NodeType.Name:
                    result = new TypeReference(ast, 0);
                    result.minChar = ast.minChar;
                    result.limChar = ast.limChar;
                    return result;
                case NodeType.Index: {
                    var expr = <BinaryExpression>ast;
                    result = this.convertToTypeReference(expr.operand1);
                    if (result) {
                        result.arrayCount++;
                        result.minChar = expr.minChar;
                        result.limChar = expr.limChar;
                        return result;
                    }
                    else {
                        var etr = <TypeReference>new AST(NodeType.Error);
                        return etr;
                    }
                }
            }
            return null;
        }


private parseArgList(errorRecoverySet: ErrorRecoverySet): ASTList {
            var args: ASTList = new ASTList();
            args.minChar = this.scanner.startPos;

            // skip left paren
            this.currentToken = this.scanner.scan();

            if (this.currentToken.tokenId !== TokenID.CloseParen) {
                while (true) {
                    if (args.members.length > 0xffff) {
                        this.reportParseError("max number of args exceeded");
                        break;
                    }

                    var arg = this.parseExpr(
                        ErrorRecoverySet.Comma | errorRecoverySet,
                        OperatorPrecedence.Comma,
                        /*allowIn:*/ true,
                        TypeContext.NoTypes);

                    args.append(arg);
                    if (this.currentToken.tokenId != TokenID.Comma) {
                        break;
                    }

                    this.currentToken = this.scanner.scan();
                }
            }

            args.limChar = this.scanner.pos;
            return args;
        }


private parseBaseList(extendsList: ASTList,
                              implementsList: ASTList,
                              errorRecoverySet: ErrorRecoverySet,
                              isClass: boolean): void {
            var keyword = true;
            var currentList = extendsList;
            for (; ;) {
                if (keyword) {
                    if (this.currentToken.tokenId === TokenID.Implements) {
                        currentList = implementsList;
                    }
                    else if (this.currentToken.tokenId == TokenID.Extends && !this.requiresExtendsBlock) {
                        this.requiresExtendsBlock = isClass;
                    }
                    this.currentToken = this.scanner.scan();
                    keyword = false;
                }
                var baseName: Identifier = null;
                if ((this.currentToken.tokenId == TokenID.Identifier) || convertTokToID(this.currentToken, this.strictMode)) {
                    var minChar = this.scanner.startPos;
                    baseName = Identifier.fromToken(this.currentToken);
                    baseName.minChar = minChar;
                    baseName.limChar = this.scanner.pos;
                    baseName = <Identifier>this.parseNamedType(errorRecoverySet | ErrorRecoverySet.LCurly,
                                            minChar, baseName, false);
                }
                else {
                    this.reportParseError("Expected base name");
                    if (this.errorRecovery) {
                        baseName = new MissingIdentifier();
                        baseName.minChar = this.scanner.pos;
                        baseName.limChar = this.scanner.pos;
                        baseName.flags |= ASTFlags.Error;
                    }
                }
                if (this.currentToken.tokenId == TokenID.OpenParen) {
                    if (isClass) {
                        this.reportParseError("Base classes may only be initialized via a 'super' call within the constructor body");
                    }
                    else {
                        this.reportParseError("Interfaces may not be extended with a call expression");
                    }
                }
                else {
                    currentList.append(baseName);
                }

                if (isClass && currentList == extendsList && extendsList.members.length > 1) {
                    this.reportParseError("A class may only extend one other class");
                }

                if (this.currentToken.tokenId == TokenID.Comma) {
                    this.currentToken = this.scanner.scan();
                    continue;
                }

                else if ((this.currentToken.tokenId == TokenID.Extends) ||
                         (this.currentToken.tokenId == TokenID.Implements)) {

                    if (this.currentToken.tokenId == TokenID.Extends && !this.requiresExtendsBlock) {
                        this.requiresExtendsBlock = isClass;
                    }

                    currentList = extendsList;
                    keyword = true;
                    continue;
                }

                break;
            }
        }


private parseClassDecl(errorRecoverySet: ErrorRecoverySet, minChar: number, modifiers: Modifiers): ClassDeclaration {
            var leftCurlyCount = this.scanner.leftCurlyCount;
            var rightCurlyCount = this.scanner.rightCurlyCount;

            if ((modifiers & Modifiers.Readonly) != Modifiers.None) {
                this.reportParseError("const modifier is implicit for class");
            }

            // mark the class as ambient, as necessary
            if (this.parsingDeclareFile || this.ambientModule) {
                modifiers |= Modifiers.Ambient;
                modifiers |= Modifiers.Exported;
            }
            var classIsMarkedAsAmbient = this.parsingDeclareFile || (modifiers & Modifiers.Ambient) != Modifiers.None;
            var svAmbientClass = this.ambientClass;
            this.ambientClass = classIsMarkedAsAmbient;

            // grab the class's name
            this.currentToken = this.scanner.scan();
            var name: Identifier = null;
            if ((this.currentToken.tokenId == TokenID.Identifier) || (!isPrimitiveTypeToken(this.currentToken) && convertTokToID(this.currentToken, this.strictMode)) ) {
                name = Identifier.fromToken(this.currentToken);
                name.minChar = this.scanner.startPos;
                name.limChar = this.scanner.pos;
                this.currentToken = this.scanner.scan();
            }
            else {
                this.reportParseError("class missing name");
                if (this.errorRecovery) {
                    name = new MissingIdentifier();
                    name.minChar = this.scanner.pos;
                    name.limChar = this.scanner.pos;
                    name.flags |= ASTFlags.Error;
                }
            }

            var extendsList: ASTList = null;
            var implementsList: ASTList = null;
            var requiresSignature = false;

            if ((this.currentToken.tokenId == TokenID.Extends) ||
                (this.currentToken.tokenId == TokenID.Implements)) {
                extendsList = new ASTList();
                implementsList = new ASTList();
                this.parseBaseList(extendsList, implementsList, errorRecoverySet, /*isClass:*/ true);
            }

            // REVIEW: Note that we don't set this as the current class decl
            var classDecl = new ClassDeclaration(name, new ASTList(), extendsList, implementsList);

            this.currentClassDefinition = classDecl;

            // parse the classes members
            this.parseClassElements(classDecl, errorRecoverySet, modifiers);

            if (this.ambientModule || this.parsingDeclareFile || hasFlag(modifiers, Modifiers.Exported)) {
                classDecl.varFlags |= VarFlags.Exported;
            }

            if (this.ambientModule || hasFlag(modifiers, Modifiers.Ambient)) {
                classDecl.varFlags |= VarFlags.Ambient;
            }

            classDecl.varFlags |= VarFlags.Class;

            this.ambientClass = svAmbientClass;
            classDecl.leftCurlyCount = this.scanner.leftCurlyCount - leftCurlyCount;
            classDecl.rightCurlyCount = this.scanner.rightCurlyCount - rightCurlyCount;
            return classDecl;
        }


private parseClassElements(classDecl: ClassDeclaration, errorRecoverySet: ErrorRecoverySet, parentModifiers: Modifiers) {
            var modifiers = parentModifiers;
            var resetModifiers = false;

            var membersMinChar = this.scanner.startPos;
            this.checkCurrentToken(TokenID.OpenBrace, errorRecoverySet);

            this.nestingLevel++;

            var currentMemberMinChar = this.scanner.startPos;
            var wasGetOrSetId = false;

            while (!(this.currentToken.tokenId == TokenID.CloseBrace || this.currentToken.tokenId == TokenID.EndOfFile)) {
                var scanNext = true;
                var publicOrPrivateFlags = Modifiers.Public | Modifiers.Private;

                // modifiers
                if (this.currentToken.tokenId == TokenID.Get) {
                    if (modifiers & Modifiers.Getter) {
                        this.reportParseError("Duplicate 'get' declaration in class body");
                    }
                    if (modifiers & Modifiers.Setter) {
                        this.reportParseError("Getter already marked as a setter");
                    }
                    modifiers |= Modifiers.Getter;
                }
                else if (this.currentToken.tokenId == TokenID.Set) {
                    if (modifiers & Modifiers.Setter) {
                        this.reportParseError("Duplicate 'set' declaration in class body");
                    }
                    if (modifiers & Modifiers.Getter) {
                        this.reportParseError("Setter already marked as a getter");
                    }
                    modifiers |= Modifiers.Setter;

                }
                else if (this.currentToken.tokenId == TokenID.Private) {
                    if (modifiers & publicOrPrivateFlags) {
                        this.reportParseError("Multiple modifiers may not be applied to class members");
                    }
                    modifiers |= Modifiers.Private;
                }
                else if (this.currentToken.tokenId == TokenID.Public) {
                    if (modifiers & publicOrPrivateFlags) {
                        this.reportParseError("Multiple modifiers may not be applied to class members");
                    }
                    modifiers |= Modifiers.Public;
                }
                else if (this.currentToken.tokenId == TokenID.Static) {
                    if (modifiers & Modifiers.Static) { // only check for double instances of static
                        this.reportParseError("Multiple modifiers may not be applied to class members");
                    }
                    modifiers |= Modifiers.Static;
                }  // constructors
                else if (this.currentToken.tokenId == TokenID.Constructor) {

                    if (modifiers != parentModifiers) {
                        this.reportParseError("Constructors may not have modifiers");
                    }

                    this.parseClassConstructorDeclaration(currentMemberMinChar, errorRecoverySet, modifiers);
                    scanNext = false; // parsing functions advances the token for us
                    resetModifiers = true;
                }  // member declarations
                else if (wasGetOrSetId || this.currentToken.tokenId == TokenID.Identifier || convertTokToIDName(this.currentToken)) {

                    var idText = wasGetOrSetId ? ((modifiers & Modifiers.Getter) ? "get" : "set") : this.currentToken.getText();
                    var id = wasGetOrSetId ? new Identifier(idText) : Identifier.fromToken(this.currentToken);
                    id.minChar = this.scanner.startPos;
                    id.limChar = this.scanner.pos;

                    // unset the get/set bit, if we're using it for an id
                    if (wasGetOrSetId) {
                        modifiers = modifiers ^ ((modifiers & Modifiers.Getter) ? Modifiers.Getter : Modifiers.Setter);
                        wasGetOrSetId = false;
                    }
                    else {
                        this.currentToken = this.scanner.scan();
                    }

                    if (this.currentToken.tokenId == TokenID.OpenParen) {
                        this.parseClassMemberFunctionDeclaration(id, currentMemberMinChar, errorRecoverySet, modifiers);
                        scanNext = false; // parsing functions advances the token for us
                    }
                    else {
                        if (modifiers & Modifiers.Getter || modifiers & Modifiers.Setter) {
                            this.reportParseError("Property accessors must be functions");
                        }

                        var varDecl = this.parseClassMemberVariableDeclaration(id, currentMemberMinChar, false, errorRecoverySet, modifiers);

                        if (varDecl.init && varDecl.init.nodeType == NodeType.FuncDecl) {
                            if (this.currentToken.tokenId == TokenID.CloseBrace) {
                                scanNext = false;
                            }
                        }
                        else if (varDecl.init && varDecl.init.nodeType == NodeType.ObjectLit && this.currentToken.tokenId != TokenID.Semicolon) {
                            scanNext = false;
                            varDecl.init.flags |= ASTFlags.AutomaticSemicolon;
                        }
                        else if (this.currentToken.tokenId != TokenID.Semicolon) {
                            this.reportParseError("Expected ';'");
                            scanNext = false;
                        }
                    }

                    resetModifiers = true;
                } // catch errant uses of 'super'
                else if (this.currentToken.tokenId == TokenID.Super) {
                    this.reportParseError("Base class initializers must be the first statement in a class definition");
                }
                else if (!wasGetOrSetId && ((modifiers & Modifiers.Getter) || (modifiers & Modifiers.Setter)) &&
                         (this.currentToken.tokenId == TokenID.OpenParen) || (this.currentToken.tokenId == TokenID.Equals)) {
                             // catch a 'get' or 'set' used as an identifier
                    wasGetOrSetId = true;
                    scanNext = false;

                }  // mark anything else as an error
                else if (this.currentToken.tokenId != TokenID.Semicolon) { // jettison semicolons
                    this.reportParseError("Unexpected '" + this.currentToken.getText() + "' in class definition");
                    resetModifiers = true;
                }

                if (scanNext) {
                    this.currentToken = this.scanner.scan();
                }

                if (resetModifiers) {
                    modifiers = parentModifiers;
                    currentMemberMinChar = this.scanner.startPos;
                    resetModifiers = false;
                }
            }

            var membersLimChar = this.scanner.pos;
            if (this.currentToken.tokenId == TokenID.CloseBrace) {
                classDecl.endingToken = new ASTSpan();
                classDecl.endingToken.minChar = this.scanner.startPos;
                classDecl.endingToken.limChar = this.scanner.pos;

                // for a class with an empty body, consume any 'dangling' inner comments
                if (!this.currentClassDefinition.members.members.length) {
                    this.currentClassDefinition.preComments = this.parseComments();
                }

                this.currentToken = this.scanner.scan();
            }

            this.nestingLevel--;

            this.currentClassDefinition.members.minChar = membersMinChar;
            this.currentClassDefinition.members.limChar = membersLimChar;
            this.currentClassDefinition.limChar = membersLimChar;
            this.currentClassDefinition = null;
        }


private parseClassConstructorDeclaration(minChar: number, errorRecoverySet: ErrorRecoverySet, modifiers: Modifiers) {
            this.parsingClassConstructorDefinition = true;

            var isAmbient = this.parsingDeclareFile || hasFlag(modifiers, Modifiers.Ambient);

            var args: ASTList = new ASTList();
            var variableArgList = false;
            var preComments = this.parseComments();

            this.currentToken = this.scanner.scan(); // scan past the 'constructor' token

            if (this.currentToken.tokenId == TokenID.OpenParen) {
                variableArgList = this.parseFormalParameterList(errorRecoverySet, args, true, isAmbient, false, false, false, false, null, true);
                if (args.members.length > 0) {
                    var lastArg = args.members[args.members.length - 1];
                }
            }

            var requiresSignature = isAmbient || this.currentToken.tokenId == TokenID.Semicolon;

            if (requiresSignature) {
                for (var i = 0; i < args.members.length; i++) {
                    var arg = <ArgDecl> args.members[i];
                    if (hasFlag(arg.varFlags, VarFlags.Property)) {
                        this.reportParseError("Overload or ambient signatures may not specify parameter properties", arg.minChar, arg.limChar);
                    }
                }
            }

            if (!requiresSignature) {
                this.currentClassDefinition.constructorNestingLevel = this.nestingLevel + 1;
            }

            var constructorFuncDecl = this.parseFunctionStatements(
                errorRecoverySet | ErrorRecoverySet.RCurly, this.currentClassDefinition.name,
                /*isConstructor:*/ true, /*isMethod:*/ false, args, AllowedElements.Properties,
                minChar, requiresSignature, modifiers);

            constructorFuncDecl.preComments = preComments;

            if (requiresSignature && !isAmbient) {
                constructorFuncDecl.isOverload = true;
            }

            constructorFuncDecl.variableArgList = variableArgList;
            this.currentClassDecl = null;
            constructorFuncDecl.returnTypeAnnotation = this.convertToTypeReference(this.currentClassDefinition.name);
            constructorFuncDecl.classDecl = this.currentClassDefinition;

            if (isAmbient) {
                constructorFuncDecl.fncFlags |= FncFlags.Ambient;
            }

            if (requiresSignature) {
                constructorFuncDecl.fncFlags |= FncFlags.Signature;
            }

            if (this.ambientModule || hasFlag(modifiers, Modifiers.Exported)) {
                constructorFuncDecl.fncFlags |= FncFlags.Exported;
            }

            if (this.currentClassDefinition.constructorDecl) {
                if (!isAmbient && !this.currentClassDefinition.constructorDecl.isSignature() && !constructorFuncDecl.isSignature()) {
                    this.reportParseError("Duplicate constructor definition");
                }
            }

            if (isAmbient || !constructorFuncDecl.isSignature()) {
                this.currentClassDefinition.constructorDecl = constructorFuncDecl;
            }

            // REVIEW: Should we have a separate flag for class constructors?  (Constructors are not methods)
            constructorFuncDecl.fncFlags |= FncFlags.ClassMethod;

            this.currentClassDefinition.members.members[this.currentClassDefinition.members.members.length] = constructorFuncDecl;

            this.parsingClassConstructorDefinition = false;

            return constructorFuncDecl;
        }


private parseClassMemberVariableDeclaration(text: Identifier, minChar: number, isDeclaredInConstructor: boolean, errorRecoverySet: ErrorRecoverySet, modifiers: Modifiers) {

            var varDecl = new VarDecl(text, this.nestingLevel);
            varDecl.minChar = minChar;
            var isStatic = false;
            varDecl.preComments = this.parseComments();

            if (this.currentToken.tokenId == TokenID.Colon) {
                this.currentToken = this.scanner.scan();
                varDecl.typeExpr =
                    this.parseTypeReference(errorRecoverySet | ErrorRecoverySet.Asg | ErrorRecoverySet.Comma, false);
                if (varDecl.typeExpr && varDecl.typeExpr.nodeType == NodeType.TypeRef) {
                    var typeExpr = (<TypeReference>varDecl.typeExpr);
                    if (typeExpr.term && typeExpr.term.nodeType == NodeType.FuncDecl) {
                        typeExpr.term.preComments = varDecl.preComments;
                    }
                }
            }

            if (this.currentToken.tokenId == TokenID.Equals) {
                if (this.parsingDeclareFile || hasFlag(modifiers, Modifiers.Ambient)) {
                    this.reportParseError("context does not permit variable initializer");
                    if (this.errorRecovery) {
                        this.skip(errorRecoverySet);
                        varDecl.flags |= ASTFlags.Error;
                        varDecl.limChar = this.scanner.lastTokenLimChar();
                        return varDecl;
                    }
                }

                // TODO: note assignment for language service
                this.currentToken = this.scanner.scan();

                varDecl.init = this.parseExpr(ErrorRecoverySet.Comma | errorRecoverySet,
                                        OperatorPrecedence.Comma, true, TypeContext.NoTypes);

                varDecl.limChar = varDecl.init.limChar;

                // member initializers on instance properties require that super be invoked as the first call within the constructor
                if (!(modifiers & Modifiers.Static)) {
                    this.currentClassDefinition.varFlags |= VarFlags.ClassSuperMustBeFirstCallInConstructor;
                }
            }
            else {
                varDecl.limChar = this.scanner.pos;
            }

            if (modifiers & Modifiers.Static) {
                varDecl.varFlags |= VarFlags.Static;
                isStatic = true;
            }

            if ((modifiers & Modifiers.Private) != Modifiers.None) {
                varDecl.varFlags |= VarFlags.Private;
            }
            else {
                varDecl.varFlags |= VarFlags.Public;
            }

            varDecl.varFlags |= VarFlags.Property;

            if (isDeclaredInConstructor) {
                varDecl.varFlags |= VarFlags.ClassConstructorProperty;
            }

            if (!isDeclaredInConstructor && !isStatic) {
                varDecl.varFlags |= VarFlags.ClassBodyProperty;
            }

            this.currentClassDefinition.knownMemberNames[text.actualText] = true;

            if (!isDeclaredInConstructor) {
                this.currentClassDefinition.members.members[this.currentClassDefinition.members.members.length] = varDecl;
            }

            varDecl.postComments = this.parseComments();
            return varDecl;
        }