Add IDEA files.

Update copyrights, fix jslint issues, tidy code.
This commit is contained in:
Matt Godbolt
2014-11-26 08:24:40 -06:00
parent 20e30ba82f
commit c60cad2e7e
27 changed files with 553 additions and 247 deletions

2
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
/.name
/workspace.xml

4
.idea/deployment.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" serverName="GCC explorer" />
</project>

4
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>

11
.idea/gcc-explorer.iml generated Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="gcc-explorer node_modules" level="project" />
</component>
</module>

6
.idea/jsLibraryMappings.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$" libraries="{gcc-explorer node_modules}" />
</component>
</project>

View File

@@ -0,0 +1,14 @@
<component name="libraryTable">
<library name="gcc-explorer node_modules" type="javaScript">
<properties>
<option name="frameworkName" value="node_modules" />
<sourceFilesUrls>
<item url="file://$PROJECT_DIR$/node_modules" />
</sourceFilesUrls>
</properties>
<CLASSES>
<root url="file://$PROJECT_DIR$/node_modules" />
</CLASSES>
<SOURCES />
</library>
</component>

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/gcc-explorer.iml" filepath="$PROJECT_DIR$/.idea/gcc-explorer.iml" />
</modules>
</component>
</project>

5
.idea/scopes/scope_settings.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="DependencyValidationManager">
<state>
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</state>
</component>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

14
.idea/webResources.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WebResourcesPaths">
<contentEntries>
<entry url="file://$PROJECT_DIR$">
<entryData>
<resourceRoots>
<path value="file://$PROJECT_DIR$/static" />
</resourceRoots>
</entryData>
</entry>
</contentEntries>
</component>
</project>

4
.jshintrc Normal file
View File

@@ -0,0 +1,4 @@
{
"esnext": true,
"supernew": true
}

View File

@@ -1,4 +1,4 @@
Copyright (c) 2012, Matt Godbolt Copyright (c) 2012-2014, Matt Godbolt
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@@ -12,5 +12,4 @@ Notes:
NB NB
-- --
Killing due to time seems broken. Bug with clicked URLs and race to get the list of compilers (null compiler)
Bug with clicked URLs and race to get the list of copmilers (null compiler)

View File

@@ -15,4 +15,4 @@ Assuming you have npm and node installed, simply running `make` ought to get you
If you want to point it at your own GCC or similar binaries, either edit the `etc/config/gcc-explorer.defaults.properties` or else make a new one with the name `gcc-explorer.YOURHOSTNAME.properties`. The config system leaves a lot to be desired, I'm working on porting [CCS](https://github.com/hellige/ccs-cpp) to javascript and then something more rational can be used. If you want to point it at your own GCC or similar binaries, either edit the `etc/config/gcc-explorer.defaults.properties` or else make a new one with the name `gcc-explorer.YOURHOSTNAME.properties`. The config system leaves a lot to be desired, I'm working on porting [CCS](https://github.com/hellige/ccs-cpp) to javascript and then something more rational can be used.
Feel free to raise an issue on github or email me directly for more help. Feel free to raise an issue on [github](https://github.com/mattgodbolt/gcc-explorer/issues) or [email me directly](mailto:matt@godbolt.org) for more help.

109
app.js
View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
// Copyright (c) 2012, Matt Godbolt // Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,6 @@
var nopt = require('nopt'), var nopt = require('nopt'),
os = require('os'), os = require('os'),
props = require('./lib/properties'), props = require('./lib/properties'),
querystring = require('querystring'),
connect = require('connect'), connect = require('connect'),
child_process = require('child_process'), child_process = require('child_process'),
temp = require('temp'), temp = require('temp'),
@@ -37,11 +36,12 @@ var nopt = require('nopt'),
fs = require('fs-extra'); fs = require('fs-extra');
var opts = nopt({ var opts = nopt({
'env': [String], 'env': [String],
'rootDir': [String]}); 'rootDir': [String]
});
var propHierarchy = [ var propHierarchy = [
'defaults', 'defaults',
opts.env || 'dev', opts.env || 'dev',
os.hostname()]; os.hostname()];
@@ -54,30 +54,31 @@ var compilers = [];
var compilersByExe = {}; var compilersByExe = {};
var compilerExecutables; var compilerExecutables;
var cache = LRU({ var cache = LRU({
max: props.get('gcc-explorer', 'cacheMb') * 1024 * 1024, max: props.get('gcc-explorer', 'cacheMb') * 1024 * 1024,
length: function(n) { return n.length; } length: function (n) {
return n.length;
}
}); });
var cacheHits = 0; var cacheHits = 0;
var cacheMisses = 0; var cacheMisses = 0;
var compileQueue = async.queue(function(task, callback) { var compileQueue = async.queue(function (task, callback) {
console.log("Compiling, queue size " + compileQueue.length()); console.log("Compiling, queue size " + compileQueue.length());
task.task(callback); task.task(callback);
}, props.get("gcc-explorer", "maxConcurrentCompiles", 1)); }, props.get("gcc-explorer", "maxConcurrentCompiles", 1));
compileQueue.drain = function() { compileQueue.drain = function () {
console.log("Compile queue empty"); console.log("Compile queue empty");
}; };
compileQueue.saturated = function() { compileQueue.saturated = function () {
console.log("Compile queue full"); console.log("Compile queue full");
}; };
function checkOptions(options) { function checkOptions(options) {
var okOptions = new RegExp(props.get('gcc-options', 'whitelistRe', '.*')); var okOptions = new RegExp(props.get('gcc-options', 'whitelistRe', '.*'));
var badOptions = new RegExp(props.get('gcc-options', 'blacklistRe')); var badOptions = new RegExp(props.get('gcc-options', 'blacklistRe'));
var error = []; var error = [];
options.forEach(function(option) { options.forEach(function (option) {
if (!option.match(okOptions) || option.match(badOptions)) { if (!option.match(okOptions) || option.match(badOptions)) {
error.push(option); error.push(option);
} }
@@ -89,7 +90,7 @@ function checkOptions(options) {
function checkSource(source) { function checkSource(source) {
var re = /^\s*#include(_next)?\s+["<"](\/|.*\.\.)/; var re = /^\s*#include(_next)?\s+["<"](\/|.*\.\.)/;
var failed = []; var failed = [];
source.split('\n').forEach(function(line, index) { source.split('\n').forEach(function (line, index) {
if (line.match(re)) { if (line.match(re)) {
failed.push("<stdin>:" + (index + 1) + ":1: no absolute or relative includes please"); failed.push("<stdin>:" + (index + 1) + ":1: no absolute or relative includes please");
} }
@@ -112,7 +113,9 @@ function compile(req, res) {
if (!compilerInfo) { if (!compilerInfo) {
return res.end(JSON.stringify({code: -1, stderr: "bad compiler " + compiler})); return res.end(JSON.stringify({code: -1, stderr: "bad compiler " + compiler}));
} }
var options = req.body.options.split(' ').filter(function(x){return x!=""}); var options = req.body.options.split(' ').filter(function (x) {
return x !== "";
});
var filters = req.body.filters; var filters = req.body.filters;
var optionsErr = checkOptions(options); var optionsErr = checkOptions(options);
if (optionsErr) { if (optionsErr) {
@@ -123,7 +126,7 @@ function compile(req, res) {
return res.end(JSON.stringify({code: -1, stderr: sourceErr})); return res.end(JSON.stringify({code: -1, stderr: sourceErr}));
} }
var key = compiler + " | " + source + " | " + options + " | " + filters["intel"]; var key = compiler + " | " + source + " | " + options + " | " + filters.intel;
var cached = cache.get(key); var cached = cache.get(key);
if (cached) { if (cached) {
cacheHits++; cacheHits++;
@@ -133,8 +136,8 @@ function compile(req, res) {
} }
cacheMisses++; cacheMisses++;
var compileTask = function(taskFinished) { var compileTask = function (taskFinished) {
temp.mkdir('gcc-explorer-compiler', function(err, dirPath) { temp.mkdir('gcc-explorer-compiler', function (err, dirPath) {
if (err) { if (err) {
return res.end(JSON.stringify({code: -1, stderr: "Unable to open temp file: " + err})); return res.end(JSON.stringify({code: -1, stderr: "Unable to open temp file: " + err}));
} }
@@ -143,7 +146,7 @@ function compile(req, res) {
var outputFilename = path.join(dirPath, 'output.S'); var outputFilename = path.join(dirPath, 'output.S');
if (compilerInfo.supportedOpts['-masm']) { if (compilerInfo.supportedOpts['-masm']) {
var syntax = '-masm=att'; // default at&t var syntax = '-masm=att'; // default at&t
if (filters["intel"] == "true") syntax = '-masm=intel'; if (filters.intel == "true") syntax = '-masm=intel';
options = options.concat([syntax]); options = options.concat([syntax]);
} }
var compileToAsm = props.get("gcc-explorer", "compileToAsm", "-S").split(" "); var compileToAsm = props.get("gcc-explorer", "compileToAsm", "-S").split(" ");
@@ -161,21 +164,25 @@ function compile(req, res) {
compiler, compiler,
options, options,
{detached: true} {detached: true}
); );
var stdout = ""; var stdout = "";
var stderr = ""; var stderr = "";
var timeout = setTimeout(function() { var timeout = setTimeout(function () {
okToCache = false; okToCache = false;
child.kill(); child.kill();
stderr += "\nKilled - processing time exceeded"; stderr += "\nKilled - processing time exceeded";
}, props.get("gcc-explorer", "compileTimeoutMs", 100)); }, props.get("gcc-explorer", "compileTimeoutMs", 100));
child.stdout.on('data', function (data) { stdout += data; }); child.stdout.on('data', function (data) {
child.stderr.on('data', function (data) { stderr += data; }); stdout += data;
});
child.stderr.on('data', function (data) {
stderr += data;
});
child.on('exit', function (code) { child.on('exit', function (code) {
clearTimeout(timeout); clearTimeout(timeout);
child_process.exec('cat "' + outputFilename + '" | ' + postProcess, child_process.exec('cat "' + outputFilename + '" | ' + postProcess,
{ maxBuffer: props.get("gcc-explorer", "max-asm-size", 8 * 1024 * 1024) }, {maxBuffer: props.get("gcc-explorer", "max-asm-size", 8 * 1024 * 1024)},
function(err, filt_stdout, filt_stderr) { function (err, filt_stdout, filt_stderr) {
var data = filt_stdout; var data = filt_stdout;
if (err) { if (err) {
data = '<No output: ' + err + '>'; data = '<No output: ' + err + '>';
@@ -185,7 +192,8 @@ function compile(req, res) {
stdout: stdout, stdout: stdout,
stderr: stderr, stderr: stderr,
asm: data, asm: data,
code: code }); code: code
});
if (okToCache) { if (okToCache) {
cache.set(key, result); cache.set(key, result);
cacheStats(); cacheStats();
@@ -205,17 +213,23 @@ function compile(req, res) {
function loadSources() { function loadSources() {
var sourcesDir = "lib/sources"; var sourcesDir = "lib/sources";
var sources = fs.readdirSync(sourcesDir) var sources = fs.readdirSync(sourcesDir)
.filter(function(file) { return file.match(/.*\.js$/); }) .filter(function (file) {
.map(function(file) { return require("./" + path.join(sourcesDir, file)); }); return file.match(/.*\.js$/);
})
.map(function (file) {
return require("./" + path.join(sourcesDir, file));
});
return sources; return sources;
} }
var fileSources = loadSources(); var fileSources = loadSources();
var sourceToHandler = {}; var sourceToHandler = {};
fileSources.forEach(function(source) { sourceToHandler[source.urlpart] = source; }); fileSources.forEach(function (source) {
sourceToHandler[source.urlpart] = source;
});
function compareOn(key) { function compareOn(key) {
return function(xObj, yObj) { return function (xObj, yObj) {
var x = xObj[key]; var x = xObj[key];
var y = yObj[key]; var y = yObj[key];
if (x < y) return -1; if (x < y) return -1;
@@ -225,7 +239,7 @@ function compareOn(key) {
} }
function getSources(req, res) { function getSources(req, res) {
var sources = fileSources.map(function(source) { var sources = fileSources.map(function (source) {
return {name: source.name, urlpart: source.urlpart}; return {name: source.name, urlpart: source.urlpart};
}); });
res.end(JSON.stringify(sources.sort(compareOn("name")))); res.end(JSON.stringify(sources.sort(compareOn("name"))));
@@ -250,16 +264,17 @@ function getSource(req, res, next) {
else if (action == "load") action = handler.load; else if (action == "load") action = handler.load;
else if (action == "save") action = handler.save; else if (action == "save") action = handler.save;
else action = null; else action = null;
if (action == null) { if (action === null) {
next(); next();
return; return;
} }
action.apply(handler, bits.slice(3).concat(function(err, response) { action.apply(handler, bits.slice(3).concat(function (err, response) {
if (err) { if (err) {
res.end(JSON.stringify({err: err})); res.end(JSON.stringify({err: err}));
} else { } else {
res.end(JSON.stringify(response)); res.end(JSON.stringify(response));
}})); }
}));
} }
function getCompilerExecutables() { function getCompilerExecutables() {
@@ -270,10 +285,10 @@ function getCompilerExecutables() {
var ndk = props.get('gcc-explorer', 'androidNdk'); var ndk = props.get('gcc-explorer', 'androidNdk');
if (ndk) { if (ndk) {
var toolchains = fs.readdirSync(ndk + "/toolchains"); var toolchains = fs.readdirSync(ndk + "/toolchains");
toolchains.forEach(function(v, i, a) { toolchains.forEach(function (v, i, a) {
var path = ndk + "/toolchains/" + v + "/prebuilt/linux-x86_64/bin/"; var path = ndk + "/toolchains/" + v + "/prebuilt/linux-x86_64/bin/";
if (fs.existsSync(path)) { if (fs.existsSync(path)) {
var cc = fs.readdirSync(path).filter(function(filename) { var cc = fs.readdirSync(path).filter(function (filename) {
return filename.indexOf("g++") != -1; return filename.indexOf("g++") != -1;
}); });
a[i] = path + cc[0]; a[i] = path + cc[0];
@@ -281,7 +296,9 @@ function getCompilerExecutables() {
a[i] = null; a[i] = null;
} }
}); });
toolchains = toolchains.filter(function(x){return x!=null;}); toolchains = toolchains.filter(function (x) {
return x !== null;
});
exes.push.apply(exes, toolchains); exes.push.apply(exes, toolchains);
} }
compilerExecutables = exes; compilerExecutables = exes;
@@ -295,16 +312,16 @@ function getCompilers(req, res) {
function findCompilers() { function findCompilers() {
async.map(getCompilerExecutables(), async.map(getCompilerExecutables(),
function (compiler, callback) { function (compiler, callback) {
fs.stat(compiler, function(err, result) { fs.stat(compiler, function (err, result) {
if (err) return callback(null, null); if (err) return callback(null, null);
child_process.exec(compiler + ' --version', function(err, output) { child_process.exec(compiler + ' --version', function (err, output) {
if (err) return callback(null, null); if (err) return callback(null, null);
var version = output.split('\n')[0]; var version = output.split('\n')[0];
child_process.exec(compiler + ' --target-help', function(err, output) { child_process.exec(compiler + ' --target-help', function (err, output) {
var options = {}; var options = {};
if (!err) { if (!err) {
var splitness = /--?[-a-zA-Z]+( ?[-a-zA-Z]+)/; var splitness = /--?[-a-zA-Z]+( ?[-a-zA-Z]+)/;
output.split('\n').forEach(function(line) { output.split('\n').forEach(function (line) {
var match = line.match(splitness); var match = line.match(splitness);
if (!match) return; if (!match) return;
options[match[0]] = true; options[match[0]] = true;
@@ -316,10 +333,14 @@ function findCompilers() {
}); });
}, },
function (err, all) { function (err, all) {
all = all.filter(function(x){return x!=null;}); all = all.filter(function (x) {
compilers = all.sort(function(x,y){return x.version < y.version ? -1 : x.version > y.version ? 1 : 0;}); return x !== null;
});
compilers = all.sort(function (x, y) {
return x.version < y.version ? -1 : x.version > y.version ? 1 : 0;
});
compilersByExe = {}; compilersByExe = {};
compilers.forEach(function(compiler) { compilers.forEach(function (compiler) {
compilersByExe[compiler.exe] = compiler; compilersByExe[compiler.exe] = compiler;
}); });
} }

View File

@@ -1,3 +1,27 @@
// Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#define _GNU_SOURCE #define _GNU_SOURCE
#include <dlfcn.h> #include <dlfcn.h>
#include <stdio.h> #include <stdio.h>

View File

@@ -1,3 +1,27 @@
// Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import std.stdio; import std.stdio;
import std.demangle; import std.demangle;
import std.regex; import std.regex;

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2012, Matt Godbolt // Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@ function debug(string) {
function get(base, property, defaultValue) { function get(base, property, defaultValue) {
var result = defaultValue; var result = defaultValue;
var source = 'default'; var source = 'default';
hierarchy.forEach(function(elem) { hierarchy.forEach(function (elem) {
var propertyMap = findProps(base, elem); var propertyMap = findProps(base, elem);
if (propertyMap && propertyMap[property]) { if (propertyMap && propertyMap[property]) {
debug(base + '.' + property + ': overriding ' + source + ' value (' + result + ') with ' + propertyMap[property]); debug(base + '.' + property + ': overriding ' + source + ' value (' + result + ') with ' + propertyMap[property]);
@@ -62,12 +62,12 @@ function toProperty(prop) {
function parseProperties(blob, name) { function parseProperties(blob, name) {
var props = {}; var props = {};
blob.split('\n').forEach(function(line, index) { blob.split('\n').forEach(function (line, index) {
line = line.replace(/#.*/, '').trim(); line = line.replace(/#.*/, '').trim();
if (!line) return; if (!line) return;
var split = line.match(/([^=]+)=(.*)/); var split = line.match(/([^=]+)=(.*)/);
if (!split) { if (!split) {
console.log("Bad line: " + line + " in " + name + ":" + (index+1)); console.log("Bad line: " + line + " in " + name + ":" + (index + 1));
return; return;
} }
props[split[1].trim()] = toProperty(split[2].trim()); props[split[1].trim()] = toProperty(split[2].trim());
@@ -77,15 +77,15 @@ function parseProperties(blob, name) {
} }
function initialize(directory, hier) { function initialize(directory, hier) {
if (hier == null) throw new Error('Must supply a hierarchy array'); if (hier === null) throw new Error('Must supply a hierarchy array');
console.log("Reading properties from " + directory + " with hierarchy " + hier); console.log("Reading properties from " + directory + " with hierarchy " + hier);
hierarchy = hier; hierarchy = hier;
var endsWith = /\.properties$/; var endsWith = /\.properties$/;
var propertyFiles = fs.readdirSync(directory).filter(function(filename) { var propertyFiles = fs.readdirSync(directory).filter(function (filename) {
return filename.match(endsWith); return filename.match(endsWith);
}); });
properties = {}; properties = {};
propertyFiles.forEach(function(file) { propertyFiles.forEach(function (file) {
var baseName = file.replace(endsWith, ''); var baseName = file.replace(endsWith, '');
file = directory + '/' + file; file = directory + '/' + file;
debug('Reading config from ' + file); debug('Reading config from ' + file);

View File

@@ -1,5 +1,29 @@
(function() { // Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
(function () {
// This is a fake plugin. All of the functionality is in the browser code. // This is a fake plugin. All of the functionality is in the browser code.
exports.name = "Browser"; exports.name = "Browser";
exports.urlpart = "browser"; exports.urlpart = "browser";
}).call(this); }).call(this);

View File

@@ -1,39 +1,75 @@
(function() { // Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
var props = require('../properties.js'), (function () {
path = require('path'),
fs = require('fs');
var sourcePath = props.get('builtin', 'sourcepath', './examples/c++'); var props = require('../properties.js'),
var sourceMatch = new RegExp(props.get('builtin', 'extensionRe', '.*\.cpp$')); path = require('path'),
var examples = fs.readdirSync(sourcePath) fs = require('fs');
.filter(function(file) { return file.match(sourceMatch); })
.map(function(file) {
var nicename = file.replace(/\.cpp$/, '');
return { urlpart: nicename, name: nicename.replace(/_/g, ' '), path: path.join(sourcePath, file) };
}).sort(function(x,y) { return y.name < x.name; });
var byUrlpart = {};
examples.forEach(function(e) { byUrlpart[e.urlpart] = e.path });
function load(filename, callback) { var sourcePath = props.get('builtin', 'sourcepath', './examples/c++');
var path = byUrlpart[filename]; var sourceMatch = new RegExp(props.get('builtin', 'extensionRe', '.*\.cpp$'));
if (!path) { callback("No such path"); return; } var examples = fs.readdirSync(sourcePath)
fs.readFile(path, 'utf-8', function(err, res) { .filter(function (file) {
if (err) { callback(err); return; } return file.match(sourceMatch);
callback(null, {file: res}); })
.map(function (file) {
var nicename = file.replace(/\.cpp$/, '');
return {urlpart: nicename, name: nicename.replace(/_/g, ' '), path: path.join(sourcePath, file)};
}).sort(function (x, y) {
return y.name < x.name;
});
var byUrlpart = {};
examples.forEach(function (e) {
byUrlpart[e.urlpart] = e.path
}); });
}
function list(callback) { function load(filename, callback) {
callback(null, examples.map(function(example) { var path = byUrlpart[filename];
return {urlpart: example.urlpart, name: example.name}; if (!path) {
})); callback("No such path");
} return;
}
fs.readFile(path, 'utf-8', function (err, res) {
if (err) {
callback(err);
return;
}
callback(null, {file: res});
});
}
exports.load = load; function list(callback) {
exports.save = null; callback(null, examples.map(function (example) {
exports.list = list; return {urlpart: example.urlpart, name: example.name};
exports.name = "Examples"; }));
exports.urlpart = "builtin"; }
exports.load = load;
exports.save = null;
exports.list = list;
exports.name = "Examples";
exports.urlpart = "builtin";
}).call(this); }).call(this);

View File

@@ -8,15 +8,15 @@
}, },
"main": "./app.js", "main": "./app.js",
"dependencies": { "dependencies": {
"async": "0.7.x", "async": "0.7.x",
"connect": "2.14.x", "connect": "2.14.x",
"fs-extra": "0.8.x", "fs-extra": "0.8.x",
"lru-cache": "2.5.x", "lru-cache": "2.5.x",
"nopt": "1.0.x", "nopt": "1.0.x",
"temp": "0.7.x" "temp": "0.7.x"
}, },
"devDependencies": { "devDependencies": {
"supervisor": "0.3.1" "supervisor": "0.3.1"
}, },
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
} }

View File

@@ -1,49 +1,75 @@
// Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
CodeMirror.defineMode("asm", function() { CodeMirror.defineMode("asm", function () {
function tokenString(quote) { function tokenString(quote) {
return function(stream) { return function (stream) {
var escaped = false, next, end = false; var escaped = false, next, end = false;
while ((next = stream.next()) != null) { while ((next = stream.next()) !== null) {
if (next == quote && !escaped) {end = true; break;} if (next == quote && !escaped) {
escaped = !escaped && next == "\\"; end = true;
} break;
return "string"; }
}; escaped = !escaped && next == "\\";
} }
return "string";
return { };
token: function(stream) {
if (stream.match(/^.+:$/)) {
return "variable-2";
}
if (stream.sol() && stream.match(/^\s*\.\w+/)) {
return "header";
}
if (stream.sol() && stream.match(/^\s\w+/)) {
return "keyword";
}
if (stream.eatSpace()) return null;
var ch = stream.next();
if (ch == '"' || ch == "'") {
return tokenString(ch)(stream);
}
if (/[\[\]{}\(\),;\:]/.test(ch)) return null;
if (/[\d$]/.test(ch) || (ch == '-' && stream.peek().match(/[0-9]/))) {
stream.eatWhile(/[\w\.]/);
return "number";
}
if (ch == '%') {
stream.eatWhile(/\w+/);
return "variable-3";
}
if (ch == '#') {
stream.eatWhile(/.*/);
return "comment";
}
stream.eatWhile(/[\w\$_]/);
return "word";
} }
};
return {
token: function (stream) {
if (stream.match(/^.+:$/)) {
return "variable-2";
}
if (stream.sol() && stream.match(/^\s*\.\w+/)) {
return "header";
}
if (stream.sol() && stream.match(/^\s\w+/)) {
return "keyword";
}
if (stream.eatSpace()) return null;
var ch = stream.next();
if (ch == '"' || ch == "'") {
return tokenString(ch)(stream);
}
if (/[\[\]{}\(\),;\:]/.test(ch)) return null;
if (/[\d$]/.test(ch) || (ch == '-' && stream.peek().match(/[0-9]/))) {
stream.eatWhile(/[\w\.]/);
return "number";
}
if (ch == '%') {
stream.eatWhile(/\w+/);
return "variable-3";
}
if (ch == '#') {
stream.eatWhile(/.*/);
return "comment";
}
stream.eatWhile(/[\w\$_]/);
return "word";
}
};
}); });
CodeMirror.defineMIME("text/x-asm", "asm"); CodeMirror.defineMIME("text/x-asm", "asm");

View File

@@ -1,3 +1,27 @@
// Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
function processAsm(asm, filters) { function processAsm(asm, filters) {
var result = []; var result = [];
var asmLines = asm.split("\n"); var asmLines = asm.split("\n");
@@ -8,12 +32,14 @@ function processAsm(asm, filters) {
var dataDefn = /\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)/; var dataDefn = /\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)/;
var fileFind = /^\s*\.file\s+(\d+)\s+"([^"]+)"$/; var fileFind = /^\s*\.file\s+(\d+)\s+"([^"]+)"$/;
var hasOpcode = /^\s*([a-zA-Z0-9$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/; var hasOpcode = /^\s*([a-zA-Z0-9$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
asmLines.forEach(function(line) { asmLines.forEach(function (line) {
if (line == "" || line[0] == ".") return; if (line === "" || line[0] === ".") return;
var match = line.match(labelFind); var match = line.match(labelFind);
if (match && (!filters.directives || line.match(hasOpcode))) { if (match && (!filters.directives || line.match(hasOpcode))) {
// Only count a label as used if it's used by an opcode, or else we're not filtering directives. // Only count a label as used if it's used by an opcode, or else we're not filtering directives.
match.forEach(function(label) { labelsUsed[label] = true; }); match.forEach(function (label) {
labelsUsed[label] = true;
});
} }
match = line.match(fileFind); match = line.match(fileFind);
if (match) { if (match) {
@@ -28,13 +54,13 @@ function processAsm(asm, filters) {
var stdInLooking = /.*<stdin>|-/; var stdInLooking = /.*<stdin>|-/;
var endBlock = /\.(cfi_endproc|data|text|section)/; var endBlock = /\.(cfi_endproc|data|text|section)/;
var source = null; var source = null;
asmLines.forEach(function(line) { asmLines.forEach(function (line) {
var match; var match;
if (line.trim() == "") { if (line.trim() === "") {
result.push({text:"", source:null}); result.push({text: "", source: null});
return; return;
} }
if (match = line.match(sourceTag)) { if (!!(match = line.match(sourceTag))) {
source = null; source = null;
var file = files[parseInt(match[1])]; var file = files[parseInt(match[1])];
if (file && file.match(stdInLooking)) { if (file && file.match(stdInLooking)) {
@@ -51,7 +77,7 @@ function processAsm(asm, filters) {
match = line.match(labelDefinition); match = line.match(labelDefinition);
if (match) { if (match) {
// It's a label definition. // It's a label definition.
if (labelsUsed[match[1]] == undefined) { if (labelsUsed[match[1]] === undefined) {
// It's an unused label. // It's an unused label.
if (filters.labels) return; if (filters.labels) return;
} else { } else {

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2012, Matt Godbolt // Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@@ -24,9 +24,9 @@
function parseLines(lines, callback) { function parseLines(lines, callback) {
var re = /^\/tmp\/[^:]+:([0-9]+)(:([0-9]+))?:\s+(.*)/; var re = /^\/tmp\/[^:]+:([0-9]+)(:([0-9]+))?:\s+(.*)/;
$.each(lines.split('\n'), function(_, line) { $.each(lines.split('\n'), function (_, line) {
line = line.trim(); line = line.trim();
if (line != "") { if (line !== "") {
var match = line.match(re); var match = line.match(re);
if (match) { if (match) {
callback(parseInt(match[1]), match[4].trim()); callback(parseInt(match[1]), match[4].trim());
@@ -72,6 +72,7 @@ function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback, cmM
function getSetting(name) { function getSetting(name) {
return window.localStorage[windowLocalPrefix + "." + name]; return window.localStorage[windowLocalPrefix + "." + name];
} }
function setSetting(name, value) { function setSetting(name, value) {
window.localStorage[windowLocalPrefix + "." + name] = value; window.localStorage[windowLocalPrefix + "." + name] = value;
} }
@@ -95,10 +96,11 @@ function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback, cmM
} }
var errorWidgets = []; var errorWidgets = [];
function onCompileResponse(request, data) { function onCompileResponse(request, data) {
var stdout = data.stdout || ""; var stdout = data.stdout || "";
var stderr = data.stderr || ""; var stderr = data.stderr || "";
if (data.code == 0) { if (data.code === 0) {
stdout += "\nCompiled ok"; stdout += "\nCompiled ok";
} else { } else {
stderr += "\nCompilation failed"; stderr += "\nCompilation failed";
@@ -108,17 +110,16 @@ function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback, cmM
_gaq.push(['_trackTiming', 'Compile', 'Timing', new Date() - request.timestamp]); _gaq.push(['_trackTiming', 'Compile', 'Timing', new Date() - request.timestamp]);
} }
$('.result .output :visible').remove(); $('.result .output :visible').remove();
var highlightLine = (data.asm == null); for (var i = 0; i < errorWidgets.length; ++i)
for (var i = 0; i < errorWidgets.length; ++i)
cppEditor.removeLineWidget(errorWidgets[i]); cppEditor.removeLineWidget(errorWidgets[i]);
errorWidgets.length = 0; errorWidgets.length = 0;
parseLines(stderr + stdout, function(lineNum, msg) { parseLines(stderr + stdout, function (lineNum, msg) {
var elem = $('.result .output .template').clone().appendTo('.result .output').removeClass('template'); var elem = $('.result .output .template').clone().appendTo('.result .output').removeClass('template');
if (lineNum) { if (lineNum) {
errorWidgets.push(cppEditor.addLineWidget(lineNum - 1, makeErrNode(msg), { errorWidgets.push(cppEditor.addLineWidget(lineNum - 1, makeErrNode(msg), {
coverGutter:false, noHScroll: true coverGutter: false, noHScroll: true
})); }));
elem.html($('<a href="#">').append(lineNum + " : " + msg)).click(function() { elem.html($('<a href="#">').append(lineNum + " : " + msg)).click(function () {
cppEditor.setSelection({line: lineNum - 1, ch: 0}, {line: lineNum, ch: 0}); cppEditor.setSelection({line: lineNum - 1, ch: 0}, {line: lineNum, ch: 0});
return false; return false;
}); });
@@ -132,43 +133,56 @@ function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback, cmM
function numberUsedLines(asm) { function numberUsedLines(asm) {
var sourceLines = {}; var sourceLines = {};
$.each(asm, function(_, x) { if (x.source) sourceLines[x.source - 1] = true; }); $.each(asm, function (_, x) {
if (x.source) sourceLines[x.source - 1] = true;
});
var ordinal = 0; var ordinal = 0;
$.each(sourceLines, function(k, _) { sourceLines[k] = ordinal++; }); $.each(sourceLines, function (k, _) {
sourceLines[k] = ordinal++;
});
var asmLines = {}; var asmLines = {};
$.each(asm, function(index, x) { if (x.source) asmLines[index] = sourceLines[x.source - 1]; }); $.each(asm, function (index, x) {
return { source: sourceLines, asm: asmLines }; if (x.source) asmLines[index] = sourceLines[x.source - 1];
});
return {source: sourceLines, asm: asmLines};
} }
var lastUpdatedAsm = null; var lastUpdatedAsm = null;
function updateAsm(forceUpdate) { function updateAsm(forceUpdate) {
if (!currentAssembly) return; if (!currentAssembly) return;
var hashedUpdate = JSON.stringify({ var hashedUpdate = JSON.stringify({
asm: currentAssembly, asm: currentAssembly,
filters: filters filters: filters
}); });
if (!forceUpdate && lastUpdatedAsm == hashedUpdate) { return; } if (!forceUpdate && lastUpdatedAsm == hashedUpdate) {
return;
}
lastUpdatedAsm = hashedUpdate; lastUpdatedAsm = hashedUpdate;
var asm = processAsm(currentAssembly, filters); var asm = processAsm(currentAssembly, filters);
var asmText = $.map(asm, function(x){ return x.text; }).join("\n"); var asmText = $.map(asm, function (x) {
return x.text;
}).join("\n");
var numberedLines = numberUsedLines(asm); var numberedLines = numberUsedLines(asm);
cppEditor.operation(function(){ clearBackground(cppEditor);}); cppEditor.operation(function () {
asmCodeMirror.operation(function() { clearBackground(cppEditor);
asmCodeMirror.setValue(asmText); });
asmCodeMirror.operation(function () {
asmCodeMirror.setValue(asmText);
clearBackground(asmCodeMirror); clearBackground(asmCodeMirror);
}); });
if (filters.colouriseAsm) { if (filters.colouriseAsm) {
cppEditor.operation(function() { cppEditor.operation(function () {
$.each(numberedLines.source, function(line, ordinal) { $.each(numberedLines.source, function (line, ordinal) {
cppEditor.addLineClass(parseInt(line), cppEditor.addLineClass(parseInt(line),
"background", "rainbow-" + (ordinal % NumRainbowColours)); "background", "rainbow-" + (ordinal % NumRainbowColours));
}); });
}); });
asmCodeMirror.operation(function() { asmCodeMirror.operation(function () {
$.each(numberedLines.asm, function(line, ordinal) { $.each(numberedLines.asm, function (line, ordinal) {
asmCodeMirror.addLineClass(parseInt(line), asmCodeMirror.addLineClass(parseInt(line),
"background", "rainbow-" + (ordinal % NumRainbowColours)); "background", "rainbow-" + (ordinal % NumRainbowColours));
}); });
}); });
@@ -176,14 +190,14 @@ function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback, cmM
} }
function pickOnlyRequestFilters(filters) { function pickOnlyRequestFilters(filters) {
return {intel: !!filters.intel }; return {intel: !!filters.intel};
} }
function onChange() { function onChange() {
if (ignoreChanges) return; // Ugly hack during startup. if (ignoreChanges) return; // Ugly hack during startup.
if (pendingTimeout) clearTimeout(pendingTimeout); if (pendingTimeout) clearTimeout(pendingTimeout);
pendingTimeout = setTimeout(function() { pendingTimeout = setTimeout(function () {
var data = { var data = {
source: cppEditor.getValue(), source: cppEditor.getValue(),
compiler: $('.compiler').val(), compiler: $('.compiler').val(),
options: $('.compiler_options').val(), options: $('.compiler_options').val(),
@@ -200,7 +214,9 @@ function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback, cmM
url: '/compile', url: '/compile',
dataType: 'json', dataType: 'json',
data: data, data: data,
success: function(result) { onCompileResponse(data, result);} success: function (result) {
onCompileResponse(data, result);
}
}); });
currentAssembly = "[Processing...]"; currentAssembly = "[Processing...]";
updateAsm(); updateAsm();
@@ -250,11 +266,11 @@ function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback, cmM
return; return;
domRoot.find('.filter button.btn[value="intel"]').toggleClass("disabled", !compiler.supportedOpts["-masm"]); domRoot.find('.filter button.btn[value="intel"]').toggleClass("disabled", !compiler.supportedOpts["-masm"]);
} }
function setCompilers(compilers) { function setCompilers(compilers) {
domRoot.find('.compiler option').remove(); domRoot.find('.compiler option').remove();
compilersByExe = {}; compilersByExe = {};
$.each(compilers, function(index, arg) { $.each(compilers, function (index, arg) {
compilersByExe[arg.exe] = arg; compilersByExe[arg.exe] = arg;
domRoot.find('.compiler').append($('<option value="' + arg.exe + '">' + arg.version + '</option>')); domRoot.find('.compiler').append($('<option value="' + arg.exe + '">' + arg.version + '</option>'));
}); });

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2012, Matt Godbolt // Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@@ -28,55 +28,63 @@ var allCompilers = [];
function getSource() { function getSource() {
var source = $('.source').val(); var source = $('.source').val();
if (source == "browser") { if (source == "browser") {
if (window.localStorage['files'] == undefined) window.localStorage['files'] = "{}"; if (window.localStorage.files === undefined) window.localStorage.files = "{}";
return { return {
list: function(callback) { list: function (callback) {
var files = JSON.parse(window.localStorage['files']); var files = JSON.parse(window.localStorage.files);
callback($.map(files, function(val, key) { return val; })); callback($.map(files, function (val, key) {
return val;
}));
}, },
load: function(name, callback) { load: function (name, callback) {
var files = JSON.parse(window.localStorage['files']); var files = JSON.parse(window.localStorage.files);
callback(files[name]); callback(files[name]);
}, },
save: function(obj, callback) { save: function (obj, callback) {
var files = JSON.parse(window.localStorage['files']); var files = JSON.parse(window.localStorage.files);
files[obj.name] = obj; files[obj.name] = obj;
window.localStorage['files'] = JSON.stringify(files); window.localStorage.files = JSON.stringify(files);
callback(true); callback(true);
} }
}; };
} else { } else {
var base = "/source/" + source; var base = "/source/" + source;
return { return {
list: function(callback) { $.getJSON(base + "/list", callback); }, list: function (callback) {
load: function(name, callback) { $.getJSON(base + "/load/" + name, callback); }, $.getJSON(base + "/list", callback);
save: function(obj, callback) { alert("Coming soon..."); } },
load: function (name, callback) {
$.getJSON(base + "/load/" + name, callback);
},
save: function (obj, callback) {
alert("Coming soon...");
}
}; };
} }
} }
var currentFileList = {}; var currentFileList = {};
function updateFileList() { function updateFileList() {
getSource().list(function(results) { getSource().list(function (results) {
currentFileList = {}; currentFileList = {};
$('.filename option').remove(); $('.filename option').remove();
$.each(results, function(index, arg) { $.each(results, function (index, arg) {
currentFileList[arg.name] = arg; currentFileList[arg.name] = arg;
$('.filename').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>')); $('.filename').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>'));
if (window.localStorage['filename'] == arg.urlpart) $('.filename').val(arg.urlpart); if (window.localStorage.filename == arg.urlpart) $('.filename').val(arg.urlpart);
}); });
}); });
} }
function onSourceChange() { function onSourceChange() {
updateFileList(); updateFileList();
window.localStorage['source'] = $('.source').val(); window.localStorage.source = $('.source').val();
} }
function loadFile() { function loadFile() {
var name = $('.filename').val(); var name = $('.filename').val();
window.localStorage['filename'] = name; window.localStorage.filename = name;
getSource().load(name, function(results) { getSource().load(name, function (results) {
if (results.file) { if (results.file) {
currentCompiler.setSource(results.file); currentCompiler.setSource(results.file);
} else { } else {
@@ -91,16 +99,16 @@ function saveFile() {
} }
function saveAs(filename) { function saveAs(filename) {
var prevFilename = window.localStorage['filename'] || ""; var prevFilename = window.localStorage.filename || "";
if (filename != prevFilename && currentFileList[filename]) { if (filename != prevFilename && currentFileList[filename]) {
// TODO! // TODO!
alert("Coming soon - overwriting files"); alert("Coming soon - overwriting files");
return; return;
} }
var obj = { urlpart: filename, name: filename, file: currentCompiler.getSource() }; var obj = {urlpart: filename, name: filename, file: currentCompiler.getSource()};
getSource().save(obj, function(ok) { getSource().save(obj, function (ok) {
if (ok) { if (ok) {
window.localStorage['filename'] = filename; window.localStorage.filename = filename;
updateFileList(); updateFileList();
} }
}); });
@@ -113,9 +121,10 @@ function saveFileAs() {
function onSave() { function onSave() {
$('#saveDialog').modal('hide'); $('#saveDialog').modal('hide');
saveAs($('#saveDialog .save-filename').val()); saveAs($('#saveDialog .save-filename').val());
}; }
$('#saveDialog .save').click(onSave); $('#saveDialog .save').click(onSave);
$('#saveDialog .save-filename').keyup(function(event) { $('#saveDialog .save-filename').keyup(function (event) {
if (event.keyCode == 13) onSave(); if (event.keyCode == 13) onSave();
}); });
} }
@@ -141,7 +150,7 @@ function makePermalink() {
longUrl: window.location.href.split('#')[0] + '#' + serialiseState(), longUrl: window.location.href.split('#')[0] + '#' + serialiseState(),
} }
}); });
request.execute(function(response) { request.execute(function (response) {
$('#permalink').val(response.id); $('#permalink').val(response.id);
}); });
} }
@@ -167,7 +176,9 @@ function serialiseState() {
var state = { var state = {
version: 3, version: 3,
filterAsm: getAsmFilters(), filterAsm: getAsmFilters(),
compilers: $.map(allCompilers, function(compiler) { return compiler.serialiseState(); }) compilers: $.map(allCompilers, function (compiler) {
return compiler.serialiseState();
})
}; };
return encodeURIComponent(JSON.stringify(state)); return encodeURIComponent(JSON.stringify(state));
} }
@@ -176,18 +187,20 @@ function deserialiseState(state) {
try { try {
state = $.parseJSON(decodeURIComponent(state)); state = $.parseJSON(decodeURIComponent(state));
switch (state.version) { switch (state.version) {
case 1: case 1:
state.filterAsm = {}; state.filterAsm = {};
// falls into /* falls through */
case 2: case 2:
state.compilers = [state]; state.compilers = [state];
// falls into /* falls through */
case 3: case 3:
break; break;
default: default:
return false; return false;
} }
} catch (ignored) { return false; } } catch (ignored) {
return false;
}
setFilterUi(state.filterAsm); setFilterUi(state.filterAsm);
for (var i = 0; i < Math.min(allCompilers.length, state.compilers.length); i++) { for (var i = 0; i < Math.min(allCompilers.length, state.compilers.length); i++) {
allCompilers[i].deserialiseState(state.compilers[i]); allCompilers[i].deserialiseState(state.compilers[i]);
@@ -197,7 +210,7 @@ function deserialiseState(state) {
function initialise() { function initialise() {
var defaultFilters = JSON.stringify(getAsmFilters()); var defaultFilters = JSON.stringify(getAsmFilters());
var actualFilters = $.parseJSON(window.localStorage['filter'] || defaultFilters); var actualFilters = $.parseJSON(window.localStorage.filter || defaultFilters);
setFilterUi(actualFilters); setFilterUi(actualFilters);
// Synchronous request here to make the whole race condition problem of // Synchronous request here to make the whole race condition problem of
@@ -207,7 +220,7 @@ function initialise() {
url: "/info", url: "/info",
dataType: "json", dataType: "json",
async: false, async: false,
success: function(results) { success: function (results) {
$(".language-name").text(results.language); $(".language-name").text(results.language);
if (results.language == "Rust") { if (results.language == "Rust") {
languageType = "text/x-rustsrc"; languageType = "text/x-rustsrc";
@@ -218,52 +231,54 @@ function initialise() {
} }
}); // must be ahead of the compiler creation. This is all terrible. }); // must be ahead of the compiler creation. This is all terrible.
var compiler = new Compiler($('body'), actualFilters, "a", function() { var compiler = new Compiler($('body'), actualFilters, "a", function () {
hidePermalink(); hidePermalink();
}, languageType); }, languageType);
allCompilers.push(compiler); allCompilers.push(compiler);
currentCompiler = compiler; currentCompiler = compiler;
$('form').submit(function() { return false; }); $('form').submit(function () {
return false;
});
$('.files .source').change(onSourceChange); $('.files .source').change(onSourceChange);
$.getJSON("/compilers", function(results) { $.getJSON("/compilers", function (results) {
compilersByExe = {}; compilersByExe = {};
$.each(results, function(index, arg) { $.each(results, function (index, arg) {
compilersByExe[arg.exe] = arg; compilersByExe[arg.exe] = arg;
}); });
compiler.setCompilers(results); compiler.setCompilers(results);
}); });
$.getJSON("/sources", function(results) { $.getJSON("/sources", function (results) {
$('.source option').remove(); $('.source option').remove();
$.each(results, function(index, arg) { $.each(results, function (index, arg) {
$('.files .source').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>')); $('.files .source').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>'));
if (window.localStorage['source'] == arg.urlpart) { if (window.localStorage.source == arg.urlpart) {
$('.files .source').val(arg.urlpart); $('.files .source').val(arg.urlpart);
} }
}); });
onSourceChange(); onSourceChange();
}); });
$('.files .load').click(function() { $('.files .load').click(function () {
loadFile(); loadFile();
return false; return false;
}); });
$('.files .save').click(function() { $('.files .save').click(function () {
saveFile(); saveFile();
return false; return false;
}); });
$('.files .saveas').click(function() { $('.files .saveas').click(function () {
saveFileAs(); saveFileAs();
return false; return false;
}); });
$('.files .permalink').click(function(e) { $('.files .permalink').click(function (e) {
togglePermalink(e); togglePermalink(e);
return false; return false;
}); });
$('.filter button.btn').click(function(e) { $('.filter button.btn').click(function (e) {
$(e.target).toggleClass('active'); $(e.target).toggleClass('active');
var filters = getAsmFilters(); var filters = getAsmFilters();
window.localStorage['filter'] = JSON.stringify(filters); window.localStorage.filter = JSON.stringify(filters);
currentCompiler.setFilters(filters); currentCompiler.setFilters(filters);
}); });
@@ -271,7 +286,7 @@ function initialise() {
deserialiseState(window.location.hash.substr(1)); deserialiseState(window.location.hash.substr(1));
} }
$(window).bind('hashchange', function() { $(window).bind('hashchange', function () {
loadFromHash(); loadFromHash();
}); });
loadFromHash(); loadFromHash();
@@ -286,20 +301,21 @@ function initialise() {
var height = windowHeight - top - resultHeight - 40; var height = windowHeight - top - resultHeight - 40;
currentCompiler.setEditorHeight(height); currentCompiler.setEditorHeight(height);
} }
$(window).on("resize", resizeEditors); $(window).on("resize", resizeEditors);
resizeEditors(); resizeEditors();
} }
function getAsmFilters() { function getAsmFilters() {
var asmFilters = {}; var asmFilters = {};
$('.filter button.btn.active').each(function() { $('.filter button.btn.active').each(function () {
asmFilters[$(this).val()] = true; asmFilters[$(this).val()] = true;
}); });
return asmFilters; return asmFilters;
} }
function setFilterUi(asmFilters) { function setFilterUi(asmFilters) {
$('.filter button.btn').each(function() { $('.filter button.btn').each(function () {
$(this).toggleClass('active', !!asmFilters[$(this).val()]); $(this).toggleClass('active', !!asmFilters[$(this).val()]);
}); });
} }

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
// Copyright (c) 2012, Matt Godbolt // Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,12 @@ function processAsm(filename, filters) {
} }
var cases = fs.readdirSync('./cases') var cases = fs.readdirSync('./cases')
.filter(function(x){return x.match(/\.asm$/)}) .filter(function (x) {
.map(function(x){return './cases/' + x;}); return x.match(/\.asm$/)
})
.map(function (x) {
return './cases/' + x;
});
var failures = 0; var failures = 0;
@@ -56,17 +60,25 @@ function testFilter(filename, suffix, filters) {
assertEq(file.length, result.length, expected); assertEq(file.length, result.length, expected);
if (file.length != result.length) return; if (file.length != result.length) return;
for (var i = 0; i < file.length; ++i) { for (var i = 0; i < file.length; ++i) {
assertEq(file[i], result[i].text, expected + ":" + (i+1)); assertEq(file[i], result[i].text, expected + ":" + (i + 1));
} }
} }
cases.forEach(function(x){ testFilter(x, "", {}) }); cases.forEach(function (x) {
cases.forEach(function(x){ testFilter(x, ".directives", { directives: true}) }); testFilter(x, "", {})
cases.forEach(function(x){ testFilter(x, ".directives.labels", });
{ directives: true, labels: true}) }); cases.forEach(function (x) {
cases.forEach(function(x){ testFilter(x, ".directives.labels.comments", testFilter(x, ".directives", {directives: true})
{ directives: true, labels: true, commentOnly: true }) }); });
cases.forEach(function (x) {
testFilter(x, ".directives.labels",
{directives: true, labels: true})
});
cases.forEach(function (x) {
testFilter(x, ".directives.labels.comments",
{directives: true, labels: true, commentOnly: true})
});
if (failures) { if (failures) {
console.log(failures + " failures"); console.log(failures + " failures");