json-pipeline
Version:
JSON pipeline for abstract compiler
235 lines (189 loc) • 5.38 kB
JavaScript
var assert = require('assert');
var assertText = require('assert-text');
assertText.options.trim = true;
var pipeline = require('../');
var fixtures = require('./fixtures');
describe('JSON CFG Builder', function() {
var p;
beforeEach(function() {
p = pipeline.create('cfg');
});
it('should generate CFG', function() {
var start = p.block('start');
assert.equal(start.index, 0);
var one = p.add('literal').addLiteral(1);
var two = p.add('literal').addLiteral(2);
var add = p.add('add', [ one, two ]);
var branch = p.addControl('if', [ add ]);
var left = p.jumpFrom(start);
assert.equal(left.blockIndex, 1);
var x0 = p.add('literal').addLiteral('ok');
var leftEnd = p.addControl('jump');
var right = p.jumpFrom(start);
var x1 = p.add('literal').addLiteral('not-ok');
var rightEnd = p.addControl('jump');
var merge = p.merge(left, right);
var phi = p.addControl('phi', [ x0, x1 ]);
p.addControl('return', [ phi ]);
assert(phi.block === merge);
p.link();
p.verify();
// Normal export
assert.deepEqual(p.render('json'), fixtures.json.p1);
// CFG export
assert.deepEqual(p.render({ cfg: true }, 'json'), fixtures.json.p1cfg);
});
it('should parse CFG', function() {
p.parse(fixtures.json.p1cfg, { cfg: true }, 'json');
p.verify();
// NOTE: we can't use `.render()` + `deepEqual()` here, because the indexes
// are off after parsing
assert.equal(p.blocks[0].nodes.length, 4);
assert.equal(p.blocks[0].successors.length, 2);
assert.equal(p.blocks[1].nodes.length, 2);
assert.equal(p.blocks[1].successors.length, 1);
assert.equal(p.blocks[2].nodes.length, 2);
assert.equal(p.blocks[2].successors.length, 1);
assert.equal(p.blocks[3].nodes.length, 2);
assert.equal(p.blocks[3].successors.length, 0);
});
it('should reindex branch', function() {
var start = p.block('start');
var one = p.add('literal').addLiteral(1);
var two = p.add('literal').addLiteral(2);
var add = p.add('add', [ one, two ]);
var branch = p.addControl('if', [ add ]);
var left = p.jumpFrom(start);
var x0 = p.add('literal').addLiteral('ok');
var leftEnd = p.addControl('jump');
var right = p.jumpFrom(start);
var x1 = p.add('literal').addLiteral('not-ok');
var rightEnd = p.addControl('jump');
var merge = p.merge(left, right);
var phi = p.addControl('phi', [ x0, x1 ]);
p.addControl('return', [ phi ]);
p.reindex();
p.link();
p.verify();
// CFG export
var text = p.render({ cfg: true }, 'printable');
assertText.equal(text, fixtures.fn2str(function() {/*
pipeline {
b0 {
i0 = literal 1
i1 = literal 2
i2 = add i0, i1
i3 = if ^b0, i2
}
b0 -> b1, b2
b1 {
i4 = literal "ok"
i5 = jump ^b1
}
b1 -> b3
b2 {
i6 = literal "not-ok"
i7 = jump ^b2
}
b2 -> b3
b3 {
i8 = phi ^b3, i4, i6
i9 = return ^i8, i8
}
}
*/}));
// Index of nodes
assert.equal(start.index, 0);
assert.equal(left.index, 1);
assert.equal(right.index, 2);
});
it('should reindex loop', function() {
var start = p.block('start');
p.addControl('jump');
var head = p.jumpFrom(start);
var read = p.add('read');
var next = p.jumpFrom(head);
var branch = p.addControl('if', [ read ]);
var body = p.jumpFrom(next);
p.add('print');
// Ensure no X intersection
body.jump(head);
var end = p.jumpFrom(next);
p.addControl('return', read);
p.reindex();
p.link();
p.verify();
// CFG export
var text = p.render({ cfg: true }, 'printable');
assertText.equal(text, fixtures.fn2str(function() {/*
pipeline {
b0 {
i0 = jump ^b0
}
b0 -> b1
b1 {
i1 = read
}
b1 -> b2
b2 {
i2 = if ^b2, i1
}
b2 -> b3, b4
b3 {
i3 = print
}
b3 -> b1
b4 {
i4 = return ^b4, i1
}
}
*/}));
});
it('should link', function() {
var start = p.block();
p.addControl('if');
var left = p.block();
p.addControl('jump');
var right = p.block();
p.addControl('jump');
var merge = p.block();
var one = p.add('literal').addLiteral(1);
p.addControl('return', one);
start.jump(left);
start.jump(right);
left.jump(merge);
right.jump(merge);
p.link();
p.verify();
var text = p.render('printable');
assertText.equal(text, fixtures.fn2str(function() {/*
pipeline {
i0 = start
i1 = if ^i0
i2 = region ^i1
i3 = jump ^i2
i4 = region ^i1
i5 = jump ^i4
i6 = region ^i3, ^i5
i7 = literal 1
i8 = return ^i6, i7
}
*/}));
});
it('should remove', function() {
var start = p.block();
var rem = p.add('to-be-removed');
p.addControl('return');
p.remove(rem);
p.link();
p.verify();
var text = p.render({ cfg: true }, 'printable');
assertText.equal(text, fixtures.fn2str(function() {/*
pipeline {
b0 {
i0 = return ^b0
}
}
*/}));
});
});