-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support on-demand parse for typedef-shadowed files #237
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -138,7 +138,23 @@ export class BrsFile { | |
} | ||
} | ||
|
||
public parser = new Parser(); | ||
public get parser() { | ||
if (!this._parser) { | ||
//remove the typedef file (if it exists) | ||
this.hasTypedef = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these need to be removed before calling |
||
this.typedefFile = undefined; | ||
|
||
//reset the deferred | ||
this.parseDeferred = new Deferred(); | ||
//parse the file (it should parse fully since there's no linked typedef | ||
this.parse(this.fileContents); | ||
|
||
//re-link the typedef (if it exists...which it should) | ||
this.resolveTypdef(); | ||
} | ||
return this._parser; | ||
} | ||
private _parser: Parser; | ||
|
||
public fileContents: string; | ||
|
||
|
@@ -188,13 +204,6 @@ export class BrsFile { | |
//event that fires anytime a dependency changes | ||
this.unsubscribeFromDependencyGraph = this.program.dependencyGraph.onchange(this.dependencyGraphKey, () => { | ||
this.resolveTypdef(); | ||
|
||
//if there is no typedef file, and this file hasn't been parsed yet, parse it now | ||
//(solves issue when typedef gets deleted and this file had skipped parsing) | ||
if (!this.hasTypedef && this.wasParseSkipped) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is no longer necessary, since the parser is a getter, it will parse the file on-demand the first time it's needed. |
||
this.parseDeferred = new Deferred(); | ||
this.parse(this.fileContents); | ||
} | ||
}); | ||
|
||
const dependencies = this.ownScriptImports.filter(x => !!x.pkgPath).map(x => x.pkgPath.toLowerCase()); | ||
|
@@ -208,11 +217,6 @@ export class BrsFile { | |
dependencyGraph.addOrReplace(this.dependencyGraphKey, dependencies); | ||
} | ||
|
||
/** | ||
* Was parsing skipped because the file has a typedef? | ||
*/ | ||
private wasParseSkipped = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not necessary now that parser is a getter. |
||
|
||
/** | ||
* Calculate the AST for this file | ||
* @param fileContents | ||
|
@@ -226,7 +230,6 @@ export class BrsFile { | |
|
||
//if we have a typedef file, skip parsing this file | ||
if (this.hasTypedef) { | ||
this.wasParseSkipped = true; | ||
this.parseDeferred.resolve(); | ||
return; | ||
} | ||
|
@@ -260,7 +263,7 @@ export class BrsFile { | |
let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens; | ||
|
||
this.program.logger.time(LogLevel.debug, ['parser.parse', chalk.green(this.pathAbsolute)], () => { | ||
this.parser.parse(tokens, { | ||
this._parser = Parser.parse(tokens, { | ||
mode: this.parseMode, | ||
logger: this.program.logger | ||
}); | ||
|
@@ -270,7 +273,7 @@ export class BrsFile { | |
this.diagnostics.push( | ||
...lexer.diagnostics as BsDiagnostic[], | ||
...preprocessor.diagnostics as BsDiagnostic[], | ||
...this.parser.diagnostics as BsDiagnostic[] | ||
...this._parser.diagnostics as BsDiagnostic[] | ||
); | ||
|
||
//notify AST ready | ||
|
@@ -289,14 +292,13 @@ export class BrsFile { | |
diagnostic.file = this; | ||
} | ||
} catch (e) { | ||
this.parser = new Parser(); | ||
this._parser = new Parser(); | ||
this.diagnostics.push({ | ||
file: this, | ||
range: util.createRange(0, 0, 0, Number.MAX_VALUE), | ||
...DiagnosticMessages.genericParserMessage('Critical error parsing file: ' + JSON.stringify(serializeError(e))) | ||
}); | ||
} | ||
this.wasParseSkipped = false; | ||
this.parseDeferred.resolve(); | ||
} | ||
|
||
|
@@ -318,8 +320,8 @@ export class BrsFile { | |
} | ||
|
||
let statements = [ | ||
...this.parser.references.libraryStatements, | ||
...this.parser.references.importStatements | ||
...this._parser.references.libraryStatements, | ||
...this._parser.references.importStatements | ||
]; | ||
for (let result of statements) { | ||
//register import statements | ||
|
@@ -652,7 +654,7 @@ export class BrsFile { | |
private findFunctionCalls() { | ||
this.functionCalls = []; | ||
//for every function in the file | ||
for (let func of this.parser.references.functionExpressions) { | ||
for (let func of this._parser.references.functionExpressions) { | ||
//for all function calls in this function | ||
for (let expression of func.callExpressions) { | ||
|
||
|
@@ -891,8 +893,9 @@ export class BrsFile { | |
|
||
//consume tokens backwards until we find someting other than a dot or an identifier | ||
let tokens = []; | ||
for (let i = this.parser.tokens.indexOf(currentToken); i >= 0; i--) { | ||
currentToken = this.parser.tokens[i]; | ||
const parser = this.parser; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lift the parser out of the loop so we only pay the getter cost once. |
||
for (let i = parser.tokens.indexOf(currentToken); i >= 0; i--) { | ||
currentToken = parser.tokens[i]; | ||
if (identifierAndDotKinds.includes(currentToken.kind)) { | ||
tokens.unshift(currentToken.text); | ||
} else { | ||
|
@@ -932,8 +935,9 @@ export class BrsFile { | |
} | ||
|
||
public getPreviousToken(token: Token) { | ||
let idx = this.parser.tokens.indexOf(token); | ||
return this.parser.tokens[idx - 1]; | ||
const parser = this.parser; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lift the parser out of the loop so we only pay the getter cost once. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, that's not safe. This is a public method, which provides no guarantees about who will be calling it. Could be a plug-in, in which case _parser might be undefined. |
||
let idx = parser.tokens.indexOf(token); | ||
return parser.tokens[idx - 1]; | ||
} | ||
|
||
/** | ||
|
@@ -1093,7 +1097,7 @@ export class BrsFile { | |
} | ||
|
||
public dispose() { | ||
this.parser?.dispose(); | ||
this._parser?.dispose(); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,12 +10,10 @@ import { InterfaceType } from './types/InterfaceType'; | |
import { ObjectType } from './types/ObjectType'; | ||
import { StringType } from './types/StringType'; | ||
import { VoidType } from './types/VoidType'; | ||
import { Parser } from './parser'; | ||
import util from './util'; | ||
|
||
export let globalFile = new BrsFile('global', 'global', null); | ||
globalFile.parser = new Parser(); | ||
globalFile.parser.parse([]); | ||
globalFile.parse(''); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. simplify the global file a bit |
||
|
||
let mathFunctions = [{ | ||
name: 'Abs', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swapped the order of the file loading, so we can ensure the file was fully parsed (since it didn't know about the .d.bs file)