From 9fd6c3d4081f3a42ea5a1f00497391bf886d69d3 Mon Sep 17 00:00:00 2001
From: Rich-Harris <richard.a.harris@gmail.com>
Date: Sat, 19 Nov 2016 12:12:56 -0500
Subject: [PATCH] inline expressions

---
 compiler/generate/index.js                   | 45 +++++++++++++++++---
 test/compiler/inline-expressions/_config.js  | 13 ++++++
 test/compiler/inline-expressions/main.svelte |  1 +
 3 files changed, 52 insertions(+), 7 deletions(-)
 create mode 100644 test/compiler/inline-expressions/_config.js
 create mode 100644 test/compiler/inline-expressions/main.svelte

diff --git a/compiler/generate/index.js b/compiler/generate/index.js
index 1e84d0c400..82658ff902 100644
--- a/compiler/generate/index.js
+++ b/compiler/generate/index.js
@@ -3,6 +3,7 @@ import { walk } from 'estree-walker';
 import deindent from './utils/deindent.js';
 import walkHtml from './utils/walkHtml.js';
 import flattenReference from './utils/flattenReference.js';
+import isReference from './utils/isReference.js';
 import contextualise from './utils/contextualise.js';
 import counter from './utils/counter.js';
 
@@ -53,7 +54,11 @@ export default function generate ( parsed, template ) {
 	}
 
 	const renderers = [];
+	const expressionFunctions = [];
 
+	const getName = counter();
+
+	// TODO use getName instead of counters
 	const counters = {
 		if: 0,
 		each: 0
@@ -209,7 +214,6 @@ export default function generate ( parsed, template ) {
 			MustacheTag: {
 				enter ( node ) {
 					const name = current.counter( 'text' );
-					const expression = flattenExpression( node.expression, current.contexts );
 
 					current.initStatements.push( deindent`
 						var ${name} = document.createTextNode( '' );
@@ -217,12 +221,37 @@ export default function generate ( parsed, template ) {
 						${current.target}.appendChild( ${name} );
 					` );
 
-					current.updateStatements.push( deindent`
-						if ( ${expression} !== ${name}_value ) {
-							${name}_value = ${expression};
-							${name}.data = ${name}_value;
-						}
-					` );
+					const usedContexts = contextualise( code, node.expression, current.contexts );
+					const snippet = `[✂${node.expression.start}-${node.expression.end}✂]`;
+
+					if ( isReference( node.expression ) ) {
+						const reference = `${template.slice( node.expression.start, node.expression.end )}`;
+						const qualified = usedContexts[0] === 'root' ? `root.${reference}` : reference;
+
+						current.updateStatements.push( deindent`
+							if ( ${snippet} !== ${name}_value ) {
+								${name}_value = ${qualified};
+								${name}.data = ${name}_value;
+							}
+						` );
+					} else {
+						const expressionFunction = getName( 'expression' );
+						expressionFunctions.push( deindent`
+							function ${expressionFunction} ( ${usedContexts.join( ', ' )} ) {
+								return ${snippet};
+							}
+						` );
+
+						const temp = getName( 'temp' );
+
+						current.updateStatements.push( deindent`
+							var ${temp} = ${expressionFunction}( ${usedContexts.join( ', ' )} );
+							if ( ${temp} !== ${name}_value ) {
+								${name}_value = ${temp};
+								${name}.data = ${name}_value;
+							}
+						` );
+					}
 				}
 			},
 
@@ -399,6 +428,8 @@ export default function generate ( parsed, template ) {
 	const result = deindent`
 		${parsed.js ? `[✂${parsed.js.content.start}-${parsed.js.content.end}✂]` : ``}
 
+		${expressionFunctions.join( '\n\n' )}
+
 		${renderers.reverse().join( '\n\n' )}
 
 		export default function createComponent ( options ) {
diff --git a/test/compiler/inline-expressions/_config.js b/test/compiler/inline-expressions/_config.js
new file mode 100644
index 0000000000..e6033aa6cf
--- /dev/null
+++ b/test/compiler/inline-expressions/_config.js
@@ -0,0 +1,13 @@
+import * as assert from 'assert';
+
+export default {
+	data: {
+		a: 1,
+		b: 2
+	},
+	html: '<p>1 + 2 = 3</p>',
+	test ( component, target ) {
+		component.set({ a: 3, b: 4 });
+		assert.equal( target.innerHTML, '<p>3 + 4 = 7</p>' );
+	}
+};
diff --git a/test/compiler/inline-expressions/main.svelte b/test/compiler/inline-expressions/main.svelte
new file mode 100644
index 0000000000..93c55f37e3
--- /dev/null
+++ b/test/compiler/inline-expressions/main.svelte
@@ -0,0 +1 @@
+<p>{{a}} + {{b}} = {{a + b}}</p>