Hugging a syntax tree
We are hiring JavaScript developers for Shoutem and Five agency
Random text
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin urna odio, aliquam vulputate faucibus id, elementum lobortis felis. Mauris urna dolor, placerat ac sagittis quis.
Random code
var bla = function(foo, bar) {
return foo * bar;
}
console.log("we all know the answer "
+ bla(7,6));
g = 1;
f = 2;
var h = 1, i;
g = 1;
d = 2;
var h = 1, i;
diff --git a/example1.js b/ex3.js
index 2b85dd4..e92c113 100644
--- a/example1.js
+++ b/ex3.js
@@ -1,3 +1,3 @@
g = 1;
-f = 2;
+d = 2;
var h = 1, i;
diff - compare files line by line
displays the changes made in a standard format, such that both humans and machines can understand the changes and apply them
diff --git a/example1.js b/ex3.js
index 2b85dd4..e92c113 100644
--- a/example1.js
+++ b/ex3.js
@@ -1,3 +1,3 @@
g = 1;
-f = 2;
+d = 2;
var h = 1, i;
g = 1;
f = 2;
var h = 1, i;
g = 1;
d = 2;
var h = 1, i;
patch - apply a diff file to an original
example.js
example.diff
modified example.js
patch [options] [originalfile [patchfile]]
diff --git a/source_replacer.js b/bla
index b002aba..cd9b732 100644
--- a/source_replacer.js [0/317]
+++ b/bla
@@ -1,30 +1,30 @@
-'use strict';
+"use strict"
function transformToStringIndex(originalSource, line, column) {
- var startLine = line - 1,
- lineStart = 0,
- lineStartIndexes = originalSource.split('\n').map(function (line) {
- return line.length;
- });
+ var startLine = line - 1,
+ lineStart = 0,
+ lineStartIndexes = originalSource.split('\n').map(function(line) {
+ return line.length;
+ });
- if (startLine > 0) {
- lineStart = lineStartIndexes.slice(0, startLine).reduce(function (a, b) {
- return a + b;
- }) + startLine;
- }
+ if (startLine > 0) {
+ lineStart = lineStartIndexes.slice(0, startLine).reduce(function(a, b) {
+ return a + b;
+ }) + startLine;
+ }
- return lineStart + column;
+ return lineStart + column;
}
function replaceOnLocations(target, source, originalSource) {
- var loc1 = transformToStringIndex(originalSource, source.start.line, source.start.column),
- loc2 = transformToStringIndex(originalSource, source.end.line, source.end.column),
- loc3 = transformToStringIndex(target.source, target.start.line, target.start.column),
- loc4 = transformToStringIndex(target.source, target.end.line, target.end.column);
+ var loc1 = transformToStringIndex(originalSource, source.start.line, source.start.column),
+ loc2 = transformToStringIndex(originalSource, source.end.line, source.end.column),
+ loc3 = transformToStringIndex(target.source, target.start.line, target.start.column),
+ loc4 = transformToStringIndex(target.source, target.end.line, target.end.column);
- return originalSource.substring(0, loc1) + target.source.substring(loc3, loc4) + originalSource.substring(loc2);
+ return originalSource.substring(0, loc1) + target.source.substring(loc3, loc4) + originalSource.substring(loc2);
}
module.exports = {
- patchSource: replaceOnLocations
+ patchSource: replaceOnLocations
};
How browsers read our JavaScript
g = 1;
f = 2;
var h = 1, i;
g = 1;
f=2;var h=1,i;
Code formatting does not matter
{
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "AssignmentExpression",
"operator": "=",
"left": {
"type": "Identifier",
"name": "g"
},
"right": {
"type": "Literal",
"value": 1,
"raw": "1"
}
}
},
{
"type": "ExpressionStatement",
"expression": {
"type": "AssignmentExpression",
"operator": "=",
"left": {
"type": "Identifier",
"name": "f"
},
"right": {
"type": "Literal",
"value": 2,
"raw": "2"
}
}
},
{
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "h"
},
...
Abstract Syntax Tree (AST)
- non-ambiguous representation of our JavaScript code
- traversable tree-structured representation of a context-free grammar
Useful properties to us:
AST Parsers in JavaScript
- Acorn: https://github.com/ternjs/acorn
- Esprima: http://esprima.org/
AST specification
astii diff
JavaScript source file1 JavaScript source file2
+ +
| |
| |
| |
v v
abstract syntax tree abstract syntax tree
+ +
| |
| |
| |
v v
generated JS source file generated JS source file2
+ +
| |
| ++++ |
+---> diff <---+
----
compare AST-neutral representations of two JavaScript files line by line
Index: undefined
===================================================================
--- undefined
+++ undefined
@@ -1,3 +1,3 @@
g = 1;
-f = 2;
+d = 2;
var h = 1, i;
\ No newline at end of file
g = 1;
f = 2;
var h = 1, i;
g = 1;
d = 2;
var h = 1,
i;
astii diff - AST to Javascript code generation
astii patch
apply an astii-generated diff file to an original in an AST-aware way, preserving original formatting
original JavaScript source
+
|
|
|
v
abstract syntax tree
+
|
|
|
v
generated JS source file
+
|
|
<---+ patch <---+ AST-aware patchfile
|
|
v
patched JavaScript source
patched JavaScript source original JavaScript source
+ +
| |
| |
| |
v v
abstract syntax tree of patched abstract syntax tree of original
+ +
| |
| |
| |
+---------->Compare and swap<---------+
Preserving the original formatting
Parallel traverse and compare
Swap code
...
},
"type": "BlockStatement",
"body": [
{
"loc": {
"start": {
"line": 5,
"column": 4
},
"end": {
"line": 5,
"column": 17
}
},
"type": "VariableDeclaration",
"declarations": [
{
"loc": {
"start": {
"line": 5,
"column": 8
},
"end": {
"line": 5,
"column": 16
}
},
"type": "VariableDeclarator",
...
...
},
"type": "BlockStatement",
"body": [
{
"loc": {
"start": {
"line": 5,
"column": 4
},
"end": {
"line": 7,
"column": 12
}
},
"type": "VariableDeclaration",
"declarations": [
{
"loc": {
"start": {
"line": 5,
"column": 8
},
"end": {
"line": 5,
"column": 16
}
},
"type": "VariableDeclarator",
...
The future
- AST-aware git blame
- diff and patch support for multiple files
- pluggable into git
- ideas?
Hugging a syntax tree
By vunovati
Hugging a syntax tree
- 992