Merge pull request #6 from frantic/transpile-js

Automated script to transpile code and tests to C
This commit is contained in:
Alexander Kotliarskyi
2014-09-26 17:50:24 -07:00
8 changed files with 133 additions and 3386 deletions

View File

@@ -1,6 +1,11 @@
FILES=src/__tests__/Layout-test.c src/Layout.c src/Layout-test-utils.c
all: c test
c:
@node ./src/transpile.js
test:
@gcc -Weverything -Werror -Wno-padded $(FILES) && ./a.out
@rm a.out

View File

@@ -2,6 +2,16 @@
#include "Layout-test-utils.h"
#include <stdlib.h>
/** START_GENERATED **/
#define SMALL_WIDTH 34.671875
#define SMALL_HEIGHT 18
#define BIG_WIDTH 172.421875
#define BIG_HEIGHT 36
#define BIG_MIN_WIDTH 100.453125
#define SMALL_TEXT "small"
#define LONG_TEXT "loooooooooong with space"
/** END_GENERATED **/
typedef struct failed_test_t {
struct failed_test_t *next;
const char *name;
@@ -52,14 +62,14 @@ css_dim_t measure(void *context, float width) {
if (width != width) {
width = 1000000;
}
if (strcmp(text, "small") == 0) {
dim.dimensions[CSS_WIDTH] = fminf(33, width);
dim.dimensions[CSS_HEIGHT] = 18;
if (strcmp(text, SMALL_TEXT) == 0) {
dim.dimensions[CSS_WIDTH] = fminf(SMALL_WIDTH, width);
dim.dimensions[CSS_HEIGHT] = SMALL_HEIGHT;
return dim;
}
if (strcmp(text, "loooooooooong with space") == 0) {
dim.dimensions[CSS_WIDTH] = width >= 171 ? 171 : fmaxf(100, width);
dim.dimensions[CSS_HEIGHT] = width >= 171 ? 18 : 36;
if (strcmp(text, LONG_TEXT) == 0) {
dim.dimensions[CSS_WIDTH] = width >= BIG_WIDTH ? BIG_WIDTH : fmaxf(BIG_MIN_WIDTH, width);
dim.dimensions[CSS_HEIGHT] = width >= BIG_WIDTH ? SMALL_HEIGHT : BIG_HEIGHT;
return dim;
}

View File

@@ -1,7 +1,11 @@
/** @nolint */
/* globals document, computeLayout */
var layoutTestUtils = (function() {
var iframe = (function() {
var cachedIframe;
function getIframe() {
if (cachedIframe) {
return cachedIframe;
}
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var doc = iframe.contentDocument;
@@ -29,15 +33,14 @@ var layoutTestUtils = (function() {
}
*/} + '').slice(15, -4);
doc.head.appendChild(style);
cachedIframe = iframe;
return iframe;
})();
var body = iframe.contentDocument.body;
}
var iframeText = document.createElement('iframe');
document.body.appendChild(iframeText);
var realComputeLayout = computeLayout;
if (typeof computeLayout === 'function') {
var realComputeLayout = computeLayout;
}
function computeCSSLayout(rootNode) {
function fillNodes(node) {
@@ -74,7 +77,7 @@ var layoutTestUtils = (function() {
}
function computeDOMLayout(node) {
var body = iframe.contentDocument.body;
var body = getIframe().contentDocument.body;
function transfer(div, node, name, ext) {
if (name in node.style) {
@@ -229,7 +232,11 @@ var layoutTestUtils = (function() {
return node;
}
var iframeText;
function measureTextSizes(text, width) {
iframeText = iframeText || document.createElement('iframe');
document.body.appendChild(iframeText);
var body = iframeText.contentDocument.body;
if (width === undefined || width !== width) {
width = Infinity;
@@ -262,13 +269,24 @@ var layoutTestUtils = (function() {
big: 'loooooooooong with space',
};
var textSizes = {
smallWidth: measureTextSizes(texts.small, 0).width,
smallHeight: measureTextSizes(texts.small, 0).height,
bigWidth: measureTextSizes(texts.big).width,
bigHeight: measureTextSizes(texts.big, 0).height,
bigMinWidth: measureTextSizes(texts.big, 0).width,
};
var textSizes;
if (typeof require === 'function') {
textSizes = {
smallWidth: 34.671875,
smallHeight: 18,
bigWidth: 172.421875,
bigHeight: 36,
bigMinWidth: 100.453125
};
} else {
textSizes = {
smallWidth: measureTextSizes(texts.small, 0).width,
smallHeight: measureTextSizes(texts.small, 0).height,
bigWidth: measureTextSizes(texts.big).width,
bigHeight: measureTextSizes(texts.big, 0).height,
bigMinWidth: measureTextSizes(texts.big, 0).width,
};
}
return {
texts: texts,
@@ -317,3 +335,7 @@ var layoutTestUtils = (function() {
}
}
})();
if (typeof module !== 'undefined') {
module.exports = layoutTestUtils;
}

View File

@@ -322,6 +322,7 @@ static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) {
}
static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
/** START_GENERATED **/
css_flex_direction_t mainAxis = getFlexDirection(node);
css_flex_direction_t crossAxis = mainAxis == CSS_FLEX_DIRECTION_ROW ?
CSS_FLEX_DIRECTION_COLUMN :
@@ -672,6 +673,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
}
}
}
/** END_GENERATED **/
}
void layoutNode(css_node_t *node, float parentMaxWidth) {
@@ -702,4 +704,3 @@ void layoutNode(css_node_t *node, float parentMaxWidth) {
layout->last_position[CSS_LEFT] = layout->position[CSS_LEFT];
}
}

View File

@@ -551,4 +551,7 @@ var computeLayout = (function() {
};
})();
if (typeof module === 'object') {
module.exports = computeLayout;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,6 @@
/* globals layoutTestUtils */
var testLayout = layoutTestUtils.testLayout;
var testRandomLayout = layoutTestUtils.testRandomLayout;
var computeLayout = layoutTestUtils.computeLayout;
var computeDOMLayout = layoutTestUtils.computeDOMLayout;
var reduceTest = layoutTestUtils.reduceTest;
var text = layoutTestUtils.text;
var texts = layoutTestUtils.texts;
var textSizes = layoutTestUtils.textSizes;

View File

@@ -1,75 +1,41 @@
<script src="Layout.js"></script>
var layoutTestUtils = require('./Layout-test-utils.js');
var computeLayout = require('./Layout.js');
var fs = require('fs');
<style>
textarea {
height: 200px;
width: 800px;
border: 1px solid black;
font-size: 12px;
font-family: monospace;
}
</style>
<h1>layoutCode</h1>
<textarea id="layout_code" onclick="this.select()"></textarea>
<script>
document.getElementById('layout_code').value = computeLayout.toString()
.replace('node.style.measure', 'node.measure')
.replace(/\.children\.length/g, '.children_count')
.replace(/\.width/g, '.dimensions[CSS_WIDTH]')
.replace(/\.height/g, '.dimensions[CSS_HEIGHT]')
.replace(/layout\[dim/g, 'layout.dimensions[dim')
.replace(/layout\[pos/g, 'layout.position[pos')
.replace(/layout\[leading/g, 'layout.position[leading')
.replace(/style\[dim/g, 'style.dimensions[dim')
.replace(/node.children\[i\]/g, 'node->get_child(node->context, i)')
.replace(/node\./g, 'node->')
.replace(/child\./g, 'child->')
.replace(/parent\./g, 'parent->')
.replace(/var\/\*([^\/]+)\*\//g, '$1')
.replace(/ === /g, ' == ')
.replace(/\n /g, '\n')
.replace(/\/[*]!([^*]+)[*]\//g, '$1')
.split('\n').slice(1).join('\n');
</script>
<h1>Tests</h1>
<textarea id="test_code" onclick="this.select()"></textarea>
<script src="Layout-test-utils.js"></script>
<script>
var currentTest = '';
var allTests = [];
var computeDOMLayout = layoutTestUtils.computeDOMLayout;
var computeLayout = layoutTestUtils.computeLayout;
var reduceTest = layoutTestUtils.reduceTest;
var text = layoutTestUtils.text;
var layoutTestUtils = {
global.layoutTestUtils = {
testLayout: function(node, expectedLayout) {
allTests.push({name: currentTest, node: node, expectedLayout: expectedLayout});
},
testRandomLayout: function(node, i) {
allTests.push({name: 'Random #' + i, node: node, expectedLayout: computeDOMLayout(node)});
},
computeLayout: computeLayout,
computeDOMLayout: computeDOMLayout,
computeLayout: layoutTestUtils.computeLayout,
reduceTest: reduceTest,
text: text,
text: layoutTestUtils.text,
texts: layoutTestUtils.texts,
textSizes: layoutTestUtils.textSizes,
textSizes: layoutTestUtils.textSizes
};
function describe(name, cb) { cb(); }
function it(name, cb) { currentTest = name; cb(); }
xit = it;
</script>
<script src="__tests__/Layout-test.js"></script>
<script>
global.describe = function(name, cb) { cb(); };
global.it = function(name, cb) { currentTest = name; cb(); };
global.xit = global.it;
require('./__tests__/Layout-test.js');
function printLayout(test) {
var level = 1;
var res = [];
function add(str) {
res.push(indent(level) + str);
if (str.length > 0) {
str = indent(level) + str;
}
res.push(str);
}
function isEmpty(obj) {
@@ -237,10 +203,53 @@ function printLayout(test) {
add('test("' + test.name.replace(/"/g, '\\"') + '", root_node, root_layout);');
level--;
add('}');
add('');
add('tests_finished();');
return res.join('\n');
}
document.getElementById('test_code').value = allTests.map(printLayout).join('\n\n');
</script>
function transpileAnnotatedJStoC(jsCode) {
return jsCode
.replace('node.style.measure', 'node.measure')
.replace(/\.children\.length/g, '.children_count')
.replace(/\.width/g, '.dimensions[CSS_WIDTH]')
.replace(/\.height/g, '.dimensions[CSS_HEIGHT]')
.replace(/layout\[dim/g, 'layout.dimensions[dim')
.replace(/layout\[pos/g, 'layout.position[pos')
.replace(/layout\[leading/g, 'layout.position[leading')
.replace(/style\[dim/g, 'style.dimensions[dim')
.replace(/node.children\[i\]/g, 'node->get_child(node->context, i)')
.replace(/node\./g, 'node->')
.replace(/child\./g, 'child->')
.replace(/parent\./g, 'parent->')
.replace(/var\/\*([^\/]+)\*\//g, '$1')
.replace(/ === /g, ' == ')
.replace(/\n /g, '\n')
.replace(/\/[*]!([^*]+)[*]\//g, '$1')
.split('\n').slice(1, -1).join('\n');
}
function makeConstDefs() {
var lines = [
'#define SMALL_WIDTH ' + layoutTestUtils.textSizes.smallWidth,
'#define SMALL_HEIGHT ' + layoutTestUtils.textSizes.smallHeight,
'#define BIG_WIDTH ' + layoutTestUtils.textSizes.bigWidth,
'#define BIG_HEIGHT ' + layoutTestUtils.textSizes.bigHeight,
'#define BIG_MIN_WIDTH ' + layoutTestUtils.textSizes.bigMinWidth,
'#define SMALL_TEXT "' + layoutTestUtils.texts.small + '"',
'#define LONG_TEXT "' + layoutTestUtils.texts.big + '"'
];
return lines.join('\n');
}
function generateFile(fileName, generatedContent) {
var content = fs.readFileSync(fileName, 'utf8').toString();
content = content.replace(new RegExp(
/\/\*\* START_GENERATED \*\*\/[\s\S]*\/\*\* END_GENERATED \*\*\//
), '/** START_GENERATED **/\n' + generatedContent + '\n /** END_GENERATED **/');
fs.writeFileSync(fileName, content);
}
generateFile(__dirname + '/__tests__/Layout-test.c', allTests.map(printLayout).join('\n\n'));
generateFile(__dirname + '/Layout-test-utils.c', makeConstDefs());
generateFile(__dirname + '/Layout.c', transpileAnnotatedJStoC(computeLayout.toString()));