track variable hoistability

pull/2011/head
Richard Harris 7 years ago
parent d92e0130ea
commit 6743d8c238

@ -861,8 +861,7 @@ export default class Component {
// reference instance variables other than other // reference instance variables other than other
// hoistable functions. TODO others? // hoistable functions. TODO others?
const { hoistable_names, hoistable_nodes, imported_declarations, instance_scope: scope } = this; const { hoistable_names, hoistable_nodes, imported_declarations, var_lookup } = this;
const template_scope = this.fragment.scope;
const top_level_function_declarations = new Map(); const top_level_function_declarations = new Map();
@ -870,6 +869,8 @@ export default class Component {
if (node.type === 'VariableDeclaration') { if (node.type === 'VariableDeclaration') {
if (node.declarations.every(d => d.init && d.init.type === 'Literal' && !this.var_lookup.get(d.id.name).mutated)) { if (node.declarations.every(d => d.init && d.init.type === 'Literal' && !this.var_lookup.get(d.id.name).mutated)) {
node.declarations.forEach(d => { node.declarations.forEach(d => {
const variable = this.var_lookup.get(d.id.name);
variable.hoistable = true;
hoistable_names.add(d.id.name); hoistable_names.add(d.id.name);
}); });
@ -920,7 +921,9 @@ export default class Component {
else if (owner === instance_scope) { else if (owner === instance_scope) {
if (name === fn_declaration.id.name) return; if (name === fn_declaration.id.name) return;
if (hoistable_names.has(name)) return;
const variable = var_lookup.get(name);
if (variable.hoistable) return;
if (imported_declarations.has(name)) return; if (imported_declarations.has(name)) return;
if (top_level_function_declarations.has(name)) { if (top_level_function_declarations.has(name)) {
@ -957,6 +960,8 @@ export default class Component {
for (const [name, node] of top_level_function_declarations) { for (const [name, node] of top_level_function_declarations) {
if (!checked.has(node) && is_hoistable(node)) { if (!checked.has(node) && is_hoistable(node)) {
const variable = this.var_lookup.get(name);
variable.hoistable = true;
hoistable_names.add(name); hoistable_names.add(name);
hoistable_nodes.add(node); hoistable_nodes.add(node);
@ -1079,7 +1084,8 @@ export default class Component {
} }
qualify(name) { qualify(name) {
if (this.hoistable_names.has(name)) return name; const variable = this.var_lookup.get(name);
if (variable && variable.hoistable) return name;
if (this.imported_declarations.has(name)) return name; if (this.imported_declarations.has(name)) return name;
if (this.declarations.indexOf(name) === -1) return name; if (this.declarations.indexOf(name) === -1) return name;

@ -457,10 +457,12 @@ function isContextual(component: Component, scope: TemplateScope, name: string)
// if it's a name below root scope, it's contextual // if it's a name below root scope, it's contextual
if (!scope.isTopLevel(name)) return true; if (!scope.isTopLevel(name)) return true;
const variable = component.var_lookup.get(name);
// hoistables, module declarations, and imports are non-contextual // hoistables, module declarations, and imports are non-contextual
if (component.hoistable_names.has(name)) return false; if (variable.hoistable) return false;
if (component.module_scope && component.module_scope.declarations.has(name)) return false; if (variable.module) return false; // TODO make all module-level variables hoistable by default
if (component.imported_declarations.has(name)) return false; if (variable.import_type) return false; // TODO ditto
// assume contextual // assume contextual
return true; return true;

@ -97,7 +97,7 @@ export default function dom(
props.forEach(x => { props.forEach(x => {
const variable = component.var_lookup.get(x.name); const variable = component.var_lookup.get(x.name);
if (component.imported_declarations.has(x.name) || component.hoistable_names.has(x.name)) { if (component.imported_declarations.has(x.name) || variable.hoistable) {
body.push(deindent` body.push(deindent`
get ${x.exported_as}() { get ${x.exported_as}() {
return ${x.name}; return ${x.name};
@ -254,14 +254,18 @@ export default function dom(
`); `);
const filtered_declarations = component.declarations.filter(name => { const filtered_declarations = component.declarations.filter(name => {
if (component.hoistable_names.has(name)) return false; const variable = component.var_lookup.get(name);
if (variable && variable.hoistable) return false;
if (component.imported_declarations.has(name)) return false; if (component.imported_declarations.has(name)) return false;
if (props.find(p => p.exported_as === name)) return true; if (props.find(p => p.exported_as === name)) return true;
return component.template_references.has(name); return component.template_references.has(name);
}); });
const filtered_props = props.filter(prop => { const filtered_props = props.filter(prop => {
if (component.hoistable_names.has(prop.name)) return false; const variable = component.var_lookup.get(prop.name);
if (variable.hoistable) return false;
if (component.imported_declarations.has(prop.name)) return false; if (component.imported_declarations.has(prop.name)) return false;
if (prop.name[0] === '$') return false; if (prop.name[0] === '$') return false;
return true; return true;

@ -22,11 +22,8 @@ export default function addActions(
); );
block.addVariable(name); block.addVariable(name);
const fn = component.imported_declarations.has(action.name) || component.hoistable_names.has(action.name)
? action.name
: `ctx.${action.name}`;
component.add_reference(action.name); const fn = component.qualify(action.name);
block.builders.mount.addLine( block.builders.mount.addLine(
`${name} = ${fn}.call(null, ${target}${snippet ? `, ${snippet}` : ''}) || {};` `${name} = ${fn}.call(null, ${target}${snippet ? `, ${snippet}` : ''}) || {};`

@ -91,4 +91,5 @@ export interface Var {
referenced?: boolean; referenced?: boolean;
writable?: boolean; writable?: boolean;
initialised?: boolean; initialised?: boolean;
hoistable?: boolean;
} }
Loading…
Cancel
Save