diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base-compiler.js | 17 | ||||
-rw-r--r-- | lib/compilation-env.js | 1 | ||||
-rw-r--r-- | lib/compile-handler.js | 117 | ||||
-rw-r--r-- | lib/compilers/WSL-CL.js | 2 | ||||
-rw-r--r-- | lib/compilers/Wine-CL.js | 2 | ||||
-rw-r--r-- | lib/compilers/golang.js | 2 | ||||
-rw-r--r-- | lib/languages.js | 105 |
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 +}; |