aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/base-compiler.js17
-rw-r--r--lib/compilation-env.js1
-rw-r--r--lib/compile-handler.js117
-rw-r--r--lib/compilers/WSL-CL.js2
-rw-r--r--lib/compilers/Wine-CL.js2
-rw-r--r--lib/compilers/golang.js2
-rw-r--r--lib/languages.js105
7 files changed, 169 insertions, 77 deletions
diff --git a/lib/base-compiler.js b/lib/base-compiler.js
index 89f70bb0a..c3b117a47 100644
--- a/lib/base-compiler.js
+++ b/lib/base-compiler.js
@@ -43,8 +43,8 @@ function Compile(compiler, env, langId) {
this.compiler = compiler;
this.lang = langId;
this.env = env;
- this.env.compilerProps = _.partial(this.env.compilerPropsL, this.lang);
- this.asm = new asm.AsmParser(env.compilerProps);
+ this.compilerProps = _.partial(this.env.compilerPropsL, this.lang);
+ this.asm = new asm.AsmParser(this.compilerProps);
this.compiler.supportsIntel = !!this.compiler.intelAsm;
}
@@ -86,7 +86,7 @@ Compile.prototype.getDefaultExecOptions = function () {
timeoutMs: this.env.ceProps("compileTimeoutMs", 100),
maxErrorOutput: this.env.ceProps("max-error-output", 5000),
env: this.env.getEnv(this.compiler.needsMulti),
- wrapper: this.env.compilerProps("compiler-wrapper")
+ wrapper: this.compilerProps("compiler-wrapper")
};
};
@@ -234,13 +234,13 @@ Compile.prototype.compile = function (source, options, backendOptions, filters)
return Promise.resolve(cached);
}
- if (filters.binary && !source.match(this.env.compilerProps("stubRe"))) {
- source += "\n" + this.env.compilerProps("stubText") + "\n";
+ if (filters.binary && !source.match(this.compilerProps("stubRe"))) {
+ source += "\n" + this.compilerProps("stubText") + "\n";
}
return self.env.enqueue(function () {
var tempFileAndDirPromise = Promise.resolve().then(function () {
return self.newTempDir().then(function (dirPath) {
- var inputFilename = path.join(dirPath, self.env.compilerProps("compileFilename"));
+ var inputFilename = path.join(dirPath, self.compilerProps("compileFilename"));
return self.writeFile(inputFilename, source).then(function () {
return {inputFilename: inputFilename, dirPath: dirPath};
});
@@ -378,7 +378,7 @@ Compile.prototype.processOptOutput = function (hasOptOutput, optPath) {
var output = [],
//if we have no compileFilename for whatever reason
//let everything through
- inputFile = this.env.compilerProps("compileFilename", "");
+ inputFile = this.compilerProps("compileFilename", "");
return new Promise(
function (resolve) {
fs.createReadStream(optPath, {encoding: "utf-8"})
@@ -553,7 +553,8 @@ Compile.prototype.postProcess = function (result, outputFilename, filters) {
if (filters.binary && this.supportsObjdump()) {
asmPromise = this.objdump(outputFilename, result, maxSize, filters.intel, filters.demangle);
} else {
- asmPromise = this.stat(outputFilename).then(_.bind(function (stat) {
+ asmPromise = this.stat(outputFilename)
+ .then(_.bind(function (stat) {
if (stat.size >= maxSize) {
result.asm = "<No output: generated assembly was too large (" + stat.size + " > " + maxSize + " bytes)>";
return result;
diff --git a/lib/compilation-env.js b/lib/compilation-env.js
index f87aa95cd..1d2d7b6cb 100644
--- a/lib/compilation-env.js
+++ b/lib/compilation-env.js
@@ -35,7 +35,6 @@ Queue.configure(Promise);
function CompilationEnvironment(ceProps, compilerPropsL) {
this.ceProps = ceProps;
this.compilerPropsL = compilerPropsL;
- this.compilerProps = compilerPropsL;
this.okOptions = new RegExp(ceProps('optionsWhitelistRe', '.*'));
this.badOptions = new RegExp(ceProps('optionsBlacklistRe', '(?!)'));
this.cache = LRU({
diff --git a/lib/compile-handler.js b/lib/compile-handler.js
index fcf6523e9..9ea4a9349 100644
--- a/lib/compile-handler.js
+++ b/lib/compile-handler.js
@@ -33,8 +33,7 @@ var child_process = require('child_process'),
logger = require('./logger').logger,
utils = require('./utils'),
CompilationEnvironment = require('./compilation-env').CompilationEnvironment,
- Raven = require('raven')
- Languages = require('./languages').list();
+ Raven = require('raven');
temp.track();
@@ -58,94 +57,52 @@ function initialise(ceProps, compilerEnv) {
}
function CompileHandler(ceProps, compilerPropsL) {
+ var self = this;
this.compilersById = {};
this.compilerEnv = new CompilationEnvironment(ceProps, compilerPropsL);
initialise(ceProps, this.compilerEnv);
this.factories = {};
this.stat = Promise.denodeify(fs.stat);
+ this.proxy = httpProxy.createProxyServer({});
+ this.textBanner = ceProps('textBanner');
+
this.create = function (compiler) {
var type = compiler.compilerType || "default";
- if (this.factories[type] === undefined) {
+ if (self.factories[type] === undefined) {
var compilerPath = './compilers/' + type;
- logger.info("Loading compiler from", compilerPath);
- this.factories[type] = require(compilerPath);
+ logger.debug("Loading compiler from", compilerPath);
+ self.factories[type] = require(compilerPath);
}
if (path.isAbsolute(compiler.exe)) {
// Try stat'ing the compiler to cache its mtime and only re-run it if it
// has changed since the last time.
- return this.stat(compiler.exe)
+ return self.stat(compiler.exe)
.then(_.bind(function (res) {
- var cached = this.findCompiler(compiler.lang, compiler.id);
+ var cached = self.findCompiler(compiler.lang, compiler.id);
if (cached && cached.mtime.getTime() === res.mtime.getTime()) {
logger.debug(compiler.id + " is unchanged");
return cached;
}
- return this.factories[type](compiler, this.compilerEnv, compiler.lang).then(function (compiler) {
+ return self.factories[type](compiler, self.compilerEnv, compiler.lang).then(function (compiler) {
compiler.mtime = res.mtime;
return compiler;
});
- }, this))
+ }, self))
.catch(function (err) {
logger.warn("Unable to stat compiler binary", err);
return null;
});
} else {
- return this.factories[type](compiler, this.compilerEnv, compiler.lang);
- }
- };
-
- var createCompilers = compilers => _.map(compilers, this.create, this);
-
- this.setCompilers = function (compilers) {
- return Promise.all(createCompilers(compilers))
- .then(compilers => _.filter(compilers, _.identity))
- .then(_.bind(function (compilers) {
- _.each(compilers, function (compiler) {
- var langId = compiler.compiler.lang;
- if (!this.compilersById[langId]) this.compilersById[langId] = {};
- this.compilersById[langId][compiler.compiler.id] = compiler;
- }, this);
- return _.map(compilers, function (compiler) {
- return compiler.getInfo();
- });
- }, this)).catch(function (err) {
- logger.error(err);
- });
- };
- var proxy = httpProxy.createProxyServer({});
- var textBanner = ceProps('textBanner');
-
- this.findCompiler = function (langId, compilerId) {
- var response;
- if (langId && this.compilersById[langId]) {
- logger.error("Should not be visible");
- response = this.compilersById[langId][compilerId];
- }
- if (!response) {
- // If the lang is bad, try to find it in every language
- logger.warn(this.compilersById);
- _.find(this.compilersById, byLang => {
- return _.find(byLang, compiler => {
- if (compiler.id === compilerId) {
- response = compiler;
- return true;
- }
- }) !== undefined;
- });
+ return self.factories[type](compiler, self.compilerEnv, compiler.lang);
}
- logger.warn(langId, compilerId, response);
- return response;
};
-
- this.handler = _.bind(function compile(req, res, next) {
- var source, options, backendOptions, filters, compiler;
- logger.warn("Compiling!");
+ this.handler = function compile(req, res, next) {
+ var source, options, backendOptions, filters,
+ compiler = self.findCompiler(req.lang || req.body.lang, req.compiler || req.body.compiler);
+ if (!compiler) return next();
if (req.is('json')) {
// JSON-style request
- // Find the compiler the user is interested in...
- compiler = this.findCompiler(req.lang || req.body.lang, req.compiler || req.body.compiler);
- if (!compiler) return next();
var requestOptions = req.body.options;
source = req.body.source;
options = requestOptions.userArguments;
@@ -154,8 +111,6 @@ function CompileHandler(ceProps, compilerPropsL) {
} else {
// API-style
// Find the compiler the user is interested in...
- compiler = this.findCompiler(req.lang, req.compiler);
- if (!compiler) return next();
source = req.body;
options = req.query.options;
// By default we get the default filters.
@@ -178,7 +133,7 @@ function CompileHandler(ceProps, compilerPropsL) {
var remote = compiler.getRemote();
if (remote) {
req.url = req.originalUrl; // Undo any routing that was done to get here (i.e. /api/* path has been removed)
- proxy.web(req, res, {target: remote}, function (e) {
+ self.proxy.web(req, res, {target: remote}, function (e) {
logger.error("Proxy error: ", e);
next(e);
});
@@ -208,7 +163,7 @@ function CompileHandler(ceProps, compilerPropsL) {
} else {
res.set('Content-Type', 'text/plain');
try {
- if (!_.isEmpty(textBanner)) res.write('# ' + textBanner + "\n");
+ if (!_.isEmpty(self.textBanner)) res.write('# ' + self.textBanner + "\n");
res.write(textify(result.asm));
if (result.code !== 0) res.write("\n# Compiler exited with result code " + result.code);
if (!_.isEmpty(result.stdout)) res.write("\nStandard out:\n" + textify(result.stdout));
@@ -236,7 +191,39 @@ function CompileHandler(ceProps, compilerPropsL) {
res.end(JSON.stringify({code: -1, stderr: [{text: error}]}));
}
);
- }, this);
+ };
+ this.setCompilers = function (newCompilers) {
+ // Delete every compiler first...
+ self.compilersById = {};
+ return Promise.all(_.map(newCompilers, self.create))
+ .then(compilers => _.filter(compilers, _.identity))
+ .then(compilers => {
+ _.each(compilers, compiler => {
+ var langId = compiler.compiler.lang;
+ if (!self.compilersById[langId]) self.compilersById[langId] = {};
+ self.compilersById[langId][compiler.compiler.id] = compiler;
+ }, self);
+ return _.map(compilers,compiler => compiler.getInfo());
+ })
+ .catch(logger.error);
+ };
+ this.findCompiler = function (langId, compilerId) {
+ if (langId && self.compilersById[langId]) {
+ return self.compilersById[langId][compilerId];
+ }
+ // If the lang is bad, try to find it in every language
+ var response;
+ _.each(self.compilersById, compilerInLang => {
+ if (response === undefined) {
+ _.each(compilerInLang, compiler => {
+ if (response === undefined && compiler.compiler.id === compilerId) {
+ response = compiler;
+ }
+ });
+ }
+ });
+ return response;
+ };
}
module.exports = {
diff --git a/lib/compilers/WSL-CL.js b/lib/compilers/WSL-CL.js
index 559bf41f4..6181f4f54 100644
--- a/lib/compilers/WSL-CL.js
+++ b/lib/compilers/WSL-CL.js
@@ -33,7 +33,7 @@ var asm = require('../asm-cl');
function compileCl(info, env, langId) {
var compile = new Compile(info, env, langId);
- compile.asm = new asm.AsmParser(env.compilerProps);
+ compile.asm = new asm.AsmParser(compile.compilerProps);
info.supportsFiltersInBinary = true;
if (process.platform == "linux") {
var origExec = compile.exec;
diff --git a/lib/compilers/Wine-CL.js b/lib/compilers/Wine-CL.js
index 3d5340ba0..d206bb0f2 100644
--- a/lib/compilers/Wine-CL.js
+++ b/lib/compilers/Wine-CL.js
@@ -27,7 +27,7 @@ var asm = require('../asm-cl');
function compileCl(info, env, langId) {
var compile = new Compile(info, env, langId);
- compile.asm = new asm.AsmParser(env.compilerProps);
+ compile.asm = new asm.AsmParser(compile.compilerProps);
info.supportsFiltersInBinary = true;
if (process.platform == "linux") {
var wine = env.ceProps("wine");
diff --git a/lib/compilers/golang.js b/lib/compilers/golang.js
index 27ec62a40..b550ee0d6 100644
--- a/lib/compilers/golang.js
+++ b/lib/compilers/golang.js
@@ -71,7 +71,7 @@ function compilenewgol(info, env, langId) {
compiler.getDefaultExecOptions = function () {
var execOptions = this.originalGetDefaultExecOptions();
- var goroot = this.env.compilerProps("compiler." + this.compiler.id + ".goroot");
+ var goroot = this.compilerProps("compiler." + this.compiler.id + ".goroot");
if (goroot) {
execOptions.env.GOROOT = goroot;
}
diff --git a/lib/languages.js b/lib/languages.js
new file mode 100644
index 000000000..9be2edf4d
--- /dev/null
+++ b/lib/languages.js
@@ -0,0 +1,105 @@
+// Copyright (c) 2012-2017, 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.
+
+/* id is what we internally use to identify the language.
+ Same as the key so we can always query for it, everywhere.
+ Used in: properties, url redirect, lang dropdown
+ name is what we display to the user
+ Used in: UI
+ monaco is how we tell the monaco editor which language is this
+ Used in: Monaco.editor.language
+ extension is an array for the usual extensions of the language.
+ The first one declared will be used as the default, else txt
+ Leading point is needed
+ Used in: Save to file extension
+*/
+function languages() {
+ return {
+ 'c++': {
+ id: 'c++',
+ name: 'C++',
+ monaco: 'cppp',
+ extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c']
+ },
+ cppx: {
+ id: 'cppx',
+ name: 'Cppx',
+ monaco: 'cppp',
+ extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c']
+ },
+ c: {
+ id: 'c',
+ name: 'C',
+ monaco: 'c',
+ extensions: ['.c', '.h']
+ },
+ rust: {
+ id: 'rust',
+ name: 'Rust',
+ monaco: 'rust',
+ extensions: ['.rs']
+ },
+ d: {
+ id: 'd',
+ name: 'D',
+ monaco: 'd',
+ extensions: ['.d']
+ },
+ go: {
+ id: 'go',
+ name: 'Go',
+ monaco: 'go',
+ extensions: ['.go']
+ },
+ ispc: {
+ id: 'ispc',
+ name: 'ispc',
+ monaco: 'ispc',
+ extensions: ['.ispc']
+ },
+ haskell: {
+ id: 'haskell',
+ name: 'Haskell',
+ monaco: 'haskell',
+ extensions: ['.haskell']
+ },
+ swift: {
+ id: 'swift',
+ name: 'Swift',
+ monaco: 'swift',
+ extensions: ['.swift']
+ }
+ };
+}
+
+var _ = require('underscore-node');
+
+function asArray() {
+ return _.map(languages(), _.identity);
+}
+module.exports = {
+ list: languages,
+ toArray: asArray
+};