Skip to content

Commit

Permalink
Clean up variables
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Apr 16, 2018
1 parent 339f5ab commit 4978d7c
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 99 deletions.
2 changes: 1 addition & 1 deletion src/ast/nodes/TaggedTemplateExpression.ts
Expand Up @@ -28,7 +28,7 @@ export default class TaggedTemplateExpression extends NodeBase {
);
}

if ((<Identifier>this.tag).name === 'eval' && variable.isGlobal) {
if ((<Identifier>this.tag).name === 'eval') {
this.module.warn(
{
code: 'EVAL',
Expand Down
22 changes: 11 additions & 11 deletions src/ast/variables/ArgumentsVariable.ts
Expand Up @@ -16,20 +16,11 @@ const getParameterVariable = (path: ObjectPath, options: ExecutionPathOptions) =
};

export default class ArgumentsVariable extends LocalVariable {
private _parameters: ParameterVariable[];
private parameters: ParameterVariable[];

constructor(parameters: ParameterVariable[]) {
super('arguments', null, UNKNOWN_EXPRESSION);
this._parameters = parameters;
}

reassignPath(path: ObjectPath, options: ExecutionPathOptions) {
const firstArgNum = parseInt(<string>path[0], 10);
if (path.length > 0) {
if (firstArgNum >= 0 && this._parameters[firstArgNum]) {
this._parameters[firstArgNum].reassignPath(path.slice(1), options);
}
}
this.parameters = parameters;
}

hasEffectsWhenAccessedAtPath(path: ObjectPath, options: ExecutionPathOptions) {
Expand Down Expand Up @@ -62,6 +53,15 @@ export default class ArgumentsVariable extends LocalVariable {
);
}

reassignPath(path: ObjectPath, options: ExecutionPathOptions) {
const firstArgNum = parseInt(<string>path[0], 10);
if (path.length > 0) {
if (firstArgNum >= 0 && this.parameters[firstArgNum]) {
this.parameters[firstArgNum].reassignPath(path.slice(1), options);
}
}
}

someReturnExpressionWhenCalledAtPath(
path: ObjectPath,
callOptions: CallOptions,
Expand Down
19 changes: 11 additions & 8 deletions src/ast/variables/ExportDefaultVariable.ts
Expand Up @@ -12,37 +12,40 @@ export function isExportDefaultVariable(variable: Variable): variable is ExportD
export default class ExportDefaultVariable extends LocalVariable {
isDefault: true;
hasId: boolean;
private _original: Variable;

// Not initialised during construction
private original: Variable | null = null;

constructor(name: string, exportDefaultDeclaration: ExportDefaultDeclaration) {
super(name, exportDefaultDeclaration, exportDefaultDeclaration.declaration);
this.isDefault = true;
this.hasId = !!(<FunctionDeclaration | ClassDeclaration>exportDefaultDeclaration.declaration)
.id;
}

addReference(identifier: Identifier) {
this.name = identifier.name;
if (this._original) {
this._original.addReference(identifier);
if (this.original !== null) {
this.original.addReference(identifier);
}
}

getName(reset?: boolean) {
if (!reset && this.safeName) return this.safeName;
if (this._original && !this._original.isReassigned) return this._original.getName();
if (this.original !== null && !this.original.isReassigned) return this.original.getName();
return this.name;
}

referencesOriginal() {
return this._original && !this._original.isReassigned;
return this.original && !this.original.isReassigned;
}

getOriginalVariableName() {
return this._original && this._original.getName();
return this.original && this.original.getName();
}

setOriginalVariable(original: Variable) {
this._original = original;
this.original = original;
}
}

ExportDefaultVariable.prototype.isDefault = true;
3 changes: 2 additions & 1 deletion src/ast/variables/ExternalVariable.ts
Expand Up @@ -15,7 +15,6 @@ export default class ExternalVariable extends Variable {
constructor(module: ExternalModule, name: string) {
super(name);
this.module = module;
this.isExternal = true;
this.isNamespace = name === '*';
this.referenced = false;
}
Expand All @@ -36,3 +35,5 @@ export default class ExternalVariable extends Variable {
return true;
}
}

ExternalVariable.prototype.isExternal = true;
12 changes: 3 additions & 9 deletions src/ast/variables/GlobalVariable.ts
Expand Up @@ -4,15 +4,7 @@ import { ObjectPath } from '../values';

export default class GlobalVariable extends Variable {
isExternal: true;
isGlobal: true;

constructor(name: string) {
super(name);
this.isExternal = true;
this.isGlobal = true;
this.isReassigned = false;
this.included = true;
}
included = true;

hasEffectsWhenAccessedAtPath(path: ObjectPath) {
// path.length == 0 can also have an effect but we postpone this for now
Expand All @@ -37,3 +29,5 @@ export default class GlobalVariable extends Variable {
);
}
}

GlobalVariable.prototype.isExternal = true;
2 changes: 0 additions & 2 deletions src/ast/variables/LocalVariable.ts
Expand Up @@ -26,8 +26,6 @@ export default class LocalVariable extends Variable {
init: ExpressionEntity
) {
super(name);
this.isReassigned = false;
this.exportName = null;
this.declarations = new Set(declarator ? [declarator] : null);
this.boundExpressions = new VariableReassignmentTracker(init);
}
Expand Down
31 changes: 12 additions & 19 deletions src/ast/variables/NamespaceVariable.ts
Expand Up @@ -11,29 +11,22 @@ export function isNamespaceVariable(variable: Variable): variable is NamespaceVa
export default class NamespaceVariable extends Variable {
isNamespace: true;
module: Module;
needsNamespaceBlock: boolean;
referencedEarly: boolean;
originals: {
[name: string]: Variable;
};
references: Identifier[];

// Not initialised during construction
originals: { [name: string]: Variable } = Object.create(null);
needsNamespaceBlock: boolean = false;
private referencedEarly: boolean = false;
private references: Identifier[] = [];

constructor(module: Module) {
super(module.basename());
this.isNamespace = true;
this.module = module;
this.needsNamespaceBlock = false;
this.referencedEarly = false;

this.references = null;
this.originals = Object.create(null);
for (const name of this.module.getExports().concat(module.getReexports())) {
this.originals[name] = this.module.traceExport(name);
}
}

addReference(identifier: Identifier) {
this.references = this.references || [];
this.references.push(identifier);
this.name = identifier.name;
}
Expand All @@ -43,12 +36,10 @@ export default class NamespaceVariable extends Variable {
return false;
}
this.needsNamespaceBlock = true;
if (this.references) {
for (const identifier of this.references) {
if (identifier.module.execIndex <= this.module.execIndex) {
this.referencedEarly = true;
break;
}
for (const identifier of this.references) {
if (identifier.module.execIndex <= this.module.execIndex) {
this.referencedEarly = true;
break;
}
}
Object.keys(this.originals).forEach(original => this.originals[original].include());
Expand Down Expand Up @@ -100,3 +91,5 @@ ${callee}(${name});`;
return output;
}
}

NamespaceVariable.prototype.isNamespace = true;
25 changes: 13 additions & 12 deletions src/ast/variables/Variable.ts
Expand Up @@ -9,17 +9,18 @@ import {
} from '../nodes/shared/Expression';

export default class Variable implements ExpressionEntity {
exportName?: string;
included: boolean;
name: string;
safeName: string;
isExternal?: boolean;
isGlobal?: boolean;
isDefault?: boolean;
isNamespace?: boolean;
isReassigned: boolean;
isId: boolean;
name: string;
reexported?: boolean;
safeName: string;

// Not initialised during construction
exportName: string | null = null;
included: boolean = false;
isId: boolean = false;
reexported: boolean = false;
isReassigned: boolean = false;

constructor(name: string) {
this.name = name;
Expand Down Expand Up @@ -89,6 +90,10 @@ export default class Variable implements ExpressionEntity {

reassignPath(_path: ObjectPath, _options: ExecutionPathOptions) {}

setSafeName(name: string) {
this.safeName = name;
}

someReturnExpressionWhenCalledAtPath(
_path: ObjectPath,
_callOptions: CallOptions,
Expand All @@ -101,8 +106,4 @@ export default class Variable implements ExpressionEntity {
toString() {
return this.name;
}

setSafeName(name: string) {
this.safeName = name;
}
}
65 changes: 29 additions & 36 deletions src/ast/variables/VariableReassignmentTracker.ts
Expand Up @@ -10,88 +10,81 @@ import ExecutionPathOptions from '../ExecutionPathOptions';
import { ExpressionEntity } from '../nodes/shared/Expression';

class ReassignedPathTracker {
_reassigned: boolean;
_unknownReassignedSubPath: boolean;
_subPaths: Map<ObjectPathKey, ReassignedPathTracker>;

constructor() {
this._reassigned = false;
this._unknownReassignedSubPath = false;
this._subPaths = new Map();
}
private reassigned: boolean = false;
private unknownReassignedSubPath: boolean = false;
private subPaths: Map<ObjectPathKey, ReassignedPathTracker> = new Map();

isReassigned(path: ObjectPath): boolean {
if (path.length === 0) {
return this._reassigned;
return this.reassigned;
}
const [subPath, ...remainingPath] = path;
return (
this._unknownReassignedSubPath ||
(this._subPaths.has(subPath) && this._subPaths.get(subPath).isReassigned(remainingPath))
this.unknownReassignedSubPath ||
(this.subPaths.has(subPath) && this.subPaths.get(subPath).isReassigned(remainingPath))
);
}

reassignPath(path: ObjectPath) {
if (this._reassigned) return;
if (this.reassigned) return;
if (path.length === 0) {
this._reassigned = true;
this.reassigned = true;
} else {
this._reassignSubPath(path);
this.reassignSubPath(path);
}
}

_reassignSubPath(path: ObjectPath) {
if (this._unknownReassignedSubPath) return;
reassignSubPath(path: ObjectPath) {
if (this.unknownReassignedSubPath) return;
const [subPath, ...remainingPath] = path;
if (subPath === UNKNOWN_KEY) {
this._unknownReassignedSubPath = true;
this.unknownReassignedSubPath = true;
} else {
if (!this._subPaths.has(<string>subPath)) {
this._subPaths.set(<string>subPath, new ReassignedPathTracker());
if (!this.subPaths.has(<string>subPath)) {
this.subPaths.set(<string>subPath, new ReassignedPathTracker());
}
this._subPaths.get(<string>subPath).reassignPath(remainingPath);
this.subPaths.get(<string>subPath).reassignPath(remainingPath);
}
}

someReassignedPath(path: ObjectPath, callback: PathPredicate): boolean {
return this._reassigned
return this.reassigned
? callback(path, UNKNOWN_EXPRESSION)
: path.length >= 1 && this._onSubPathIfReassigned(path, callback);
: path.length >= 1 && this.onSubPathIfReassigned(path, callback);
}

_onSubPathIfReassigned(path: ObjectPath, callback: PathPredicate): boolean {
onSubPathIfReassigned(path: ObjectPath, callback: PathPredicate): boolean {
const [subPath, ...remainingPath] = path;
return this._unknownReassignedSubPath || subPath === UNKNOWN_KEY
return this.unknownReassignedSubPath || subPath === UNKNOWN_KEY
? callback(remainingPath, UNKNOWN_EXPRESSION)
: this._subPaths.has(<string>subPath) &&
this._subPaths.get(<string>subPath).someReassignedPath(remainingPath, callback);
: this.subPaths.has(<string>subPath) &&
this.subPaths.get(<string>subPath).someReassignedPath(remainingPath, callback);
}
}

export default class VariableReassignmentTracker {
private _initialExpression: ExpressionEntity;
private _reassignedPathTracker: ReassignedPathTracker;
private initialExpression: ExpressionEntity;
private reassignedPathTracker: ReassignedPathTracker = new ReassignedPathTracker();

constructor(initialExpression: ExpressionEntity) {
this._initialExpression = initialExpression;
this._reassignedPathTracker = new ReassignedPathTracker();
this.initialExpression = initialExpression;
}

reassignPath(path: ObjectPath, options: ExecutionPathOptions) {
if (path.length > 0) {
this._initialExpression && this._initialExpression.reassignPath(path, options);
this.initialExpression && this.initialExpression.reassignPath(path, options);
}
this._reassignedPathTracker.reassignPath(path);
this.reassignedPathTracker.reassignPath(path);
}

forEachAtPath(path: ObjectPath, callback: PathCallback) {
this._initialExpression && callback(path, this._initialExpression);
this.initialExpression && callback(path, this.initialExpression);
}

someAtPath(path: ObjectPath, predicateFunction: PathPredicate) {
return (
this._reassignedPathTracker.someReassignedPath(path, predicateFunction) ||
(this._initialExpression && predicateFunction(path, this._initialExpression))
this.reassignedPathTracker.someReassignedPath(path, predicateFunction) ||
(this.initialExpression && predicateFunction(path, this.initialExpression))
);
}
}

0 comments on commit 4978d7c

Please sign in to comment.