Browse Source

Add IDEA files.

Update copyrights, fix jslint issues, tidy code.
dev/git-series/gccdum
Matt Godbolt 8 years ago
parent
commit
c60cad2e7e
  1. 2
      .idea/.gitignore
  2. 4
      .idea/deployment.xml
  3. 4
      .idea/encodings.xml
  4. 11
      .idea/gcc-explorer.iml
  5. 6
      .idea/jsLibraryMappings.xml
  6. 14
      .idea/libraries/gcc_explorer_node_modules.xml
  7. 4
      .idea/misc.xml
  8. 8
      .idea/modules.xml
  9. 5
      .idea/scopes/scope_settings.xml
  10. 6
      .idea/vcs.xml
  11. 14
      .idea/webResources.xml
  12. 4
      .jshintrc
  13. 2
      LICENSE
  14. 3
      Notes.md
  15. 2
      README.md
  16. 109
      app.js
  17. 24
      c-preload/preload.c
  18. 24
      d/demangle.d
  19. 14
      lib/properties.js
  20. 30
      lib/sources/browser.js
  21. 98
      lib/sources/builtin.js
  22. 14
      package.json
  23. 112
      static/asm-mode.js
  24. 42
      static/asm.js
  25. 80
      static/compiler.js
  26. 130
      static/gcc.js
  27. 32
      test/test.js

2
.idea/.gitignore vendored

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

4
.idea/deployment.xml

@ -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

@ -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

@ -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

@ -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>

14
.idea/libraries/gcc_explorer_node_modules.xml

@ -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

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

8
.idea/modules.xml

@ -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

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

6
.idea/vcs.xml

@ -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

@ -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

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

2
LICENSE

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

3
Notes.md

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

2
README.md

@ -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.
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

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

24
c-preload/preload.c

@ -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
#include <dlfcn.h>
#include <stdio.h>

24
d/demangle.d

@ -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.demangle;
import std.regex;

14
lib/properties.js

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

30
lib/sources/browser.js

@ -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.
exports.name = "Browser";
exports.urlpart = "browser";
exports.name = "Browser";
exports.urlpart = "browser";
}).call(this);

98
lib/sources/builtin.js

@ -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'),
path = require('path'),
fs = require('fs');
(function () {
var sourcePath = props.get('builtin', 'sourcepath', './examples/c++');
var sourceMatch = new RegExp(props.get('builtin', 'extensionRe', '.*\.cpp$'));
var examples = fs.readdirSync(sourcePath)
.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 });
var props = require('../properties.js'),
path = require('path'),
fs = require('fs');
function load(filename, callback) {
var path = byUrlpart[filename];
if (!path) { callback("No such path"); return; }
fs.readFile(path, 'utf-8', function(err, res) {
if (err) { callback(err); return; }
callback(null, {file: res});
var sourcePath = props.get('builtin', 'sourcepath', './examples/c++');
var sourceMatch = new RegExp(props.get('builtin', 'extensionRe', '.*\.cpp$'));
var examples = fs.readdirSync(sourcePath)
.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 list(callback) {
callback(null, examples.map(function(example) {
return {urlpart: example.urlpart, name: example.name};
}));
}
function load(filename, callback) {
var path = byUrlpart[filename];
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;
exports.save = null;
exports.list = list;
exports.name = "Examples";
exports.urlpart = "builtin";
function list(callback) {
callback(null, examples.map(function (example) {
return {urlpart: example.urlpart, name: example.name};
}));
}
exports.load = load;
exports.save = null;
exports.list = list;
exports.name = "Examples";
exports.urlpart = "builtin";
}).call(this);

14
package.json

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

112
static/asm-mode.js

@ -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() {
function tokenString(quote) {
return function(stream) {
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
if (next == quote && !escaped) {end = true; break;}
escaped = !escaped && next == "\\";
}
return "string";
};
}
CodeMirror.defineMode("asm", function () {
function tokenString(quote) {
return function (stream) {
var escaped = false, next, end = false;
while ((next = stream.next()) !== null) {
if (next == quote && !escaped) {
end = true;
break;
}
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);
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";
}
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");

42
static/asm.js

@ -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) {
var result = [];
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 fileFind = /^\s*\.file\s+(\d+)\s+"([^"]+)"$/;
var hasOpcode = /^\s*([a-zA-Z0-9$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
asmLines.forEach(function(line) {
if (line == "" || line[0] == ".") return;
asmLines.forEach(function (line) {
if (line === "" || line[0] === ".") return;
var match = line.match(labelFind);
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.
match.forEach(function(label) { labelsUsed[label] = true; });
match.forEach(function (label) {
labelsUsed[label] = true;
});
}
match = line.match(fileFind);
if (match) {
@ -28,13 +54,13 @@ function processAsm(asm, filters) {
var stdInLooking = /.*<stdin>|-/;
var endBlock = /\.(cfi_endproc|data|text|section)/;
var source = null;
asmLines.forEach(function(line) {
asmLines.forEach(function (line) {
var match;
if (line.trim() == "") {
result.push({text:"", source:null});
if (line.trim() === "") {
result.push({text: "", source: null});
return;
}
if (match = line.match(sourceTag)) {
if (!!(match = line.match(sourceTag))) {
source = null;
var file = files[parseInt(match[1])];
if (file && file.match(stdInLooking)) {
@ -51,7 +77,7 @@ function processAsm(asm, filters) {
match = line.match(labelDefinition);
if (match) {
// It's a label definition.
if (labelsUsed[match[1]] == undefined) {
if (labelsUsed[match[1]] === undefined) {
// It's an unused label.
if (filters.labels) return;
} else {

80
static/compiler.js

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

130
static/gcc.js

@ -1,4 +1,4 @@
// Copyright (c) 2012, Matt Godbolt
// Copyright (c) 2012-2014, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -28,55 +28,63 @@ var allCompilers = [];
function getSource() {
var source = $('.source').val();
if (source == "browser") {
if (window.localStorage['files'] == undefined) window.localStorage['files'] = "{}";
if (window.localStorage.files === undefined) window.localStorage.files = "{}";
return {
list: function(callback) {
var files = JSON.parse(window.localStorage['files']);
callback($.map(files, function(val, key) { return val; }));
list: function (callback) {
var files = JSON.parse(window.localStorage.files);
callback($.map(files, function (val, key) {
return val;
}));
},
load: function(name, callback) {
var files = JSON.parse(window.localStorage['files']);
load: function (name, callback) {
var files = JSON.parse(window.localStorage.files);
callback(files[name]);
},
save: function(obj, callback) {
var files = JSON.parse(window.localStorage['files']);
save: function (obj, callback) {
var files = JSON.parse(window.localStorage.files);
files[obj.name] = obj;
window.localStorage['files'] = JSON.stringify(files);
window.localStorage.files = JSON.stringify(files);
callback(true);
}
};
} else {
var base = "/source/" + source;
return {
list: function(callback) { $.getJSON(base + "/list", callback); },
load: function(name, callback) { $.getJSON(base + "/load/" + name, callback); },
save: function(obj, callback) { alert("Coming soon..."); }
list: function (callback) {
$.getJSON(base + "/list", callback);
},
load: function (name, callback) {
$.getJSON(base + "/load/" + name, callback);
},
save: function (obj, callback) {
alert("Coming soon...");
}
};
}
}
var currentFileList = {};
function updateFileList() {
getSource().list(function(results) {
getSource().list(function (results) {
currentFileList = {};
$('.filename option').remove();
$.each(results, function(index, arg) {
$.each(results, function (index, arg) {
currentFileList[arg.name] = arg;
$('.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() {
updateFileList();
window.localStorage['source'] = $('.source').val();
window.localStorage.source = $('.source').val();
}
function loadFile() {
var name = $('.filename').val();
window.localStorage['filename'] = name;
getSource().load(name, function(results) {
window.localStorage.filename = name;
getSource().load(name, function (results) {
if (results.file) {
currentCompiler.setSource(results.file);
} else {
@ -91,16 +99,16 @@ function saveFile() {
}
function saveAs(filename) {
var prevFilename = window.localStorage['filename'] || "";
var prevFilename = window.localStorage.filename || "";
if (filename != prevFilename && currentFileList[filename]) {
// TODO!
alert("Coming soon - overwriting files");
return;
}
var obj = { urlpart: filename, name: filename, file: currentCompiler.getSource() };
getSource().save(obj, function(ok) {
var obj = {urlpart: filename, name: filename, file: currentCompiler.getSource()};
getSource().save(obj, function (ok) {
if (ok) {
window.localStorage['filename'] = filename;
window.localStorage.filename = filename;
updateFileList();
}
});
@ -113,9 +121,10 @@ function saveFileAs() {
function onSave() {
$('#saveDialog').modal('hide');
saveAs($('#saveDialog .save-filename').val());
};
}
$('#saveDialog .save').click(onSave);
$('#saveDialog .save-filename').keyup(function(event) {
$('#saveDialog .save-filename').keyup(function (event) {
if (event.keyCode == 13) onSave();
});
}
@ -141,7 +150,7 @@ function makePermalink() {
longUrl: window.location.href.split('#')[0] + '#' + serialiseState(),
}
});
request.execute(function(response) {
request.execute(function (response) {
$('#permalink').val(response.id);
});
}
@ -167,7 +176,9 @@ function serialiseState() {
var state = {
version: 3,
filterAsm: getAsmFilters(),
compilers: $.map(allCompilers, function(compiler) { return compiler.serialiseState(); })
compilers: $.map(allCompilers, function (compiler) {
return compiler.serialiseState();
})
};
return encodeURIComponent(JSON.stringify(state));
}
@ -176,18 +187,20 @@ function deserialiseState(state) {
try {
state = $.parseJSON(decodeURIComponent(state));
switch (state.version) {
case 1:
state.filterAsm = {};
// falls into
case 2:
state.compilers = [state];
// falls into
case 3:
break;
default:
return false;
case 1:
state.filterAsm = {};
/* falls through */
case 2:
state.compilers = [state];
/* falls through */
case 3:
break;
default:
return false;
}