Compare commits

...

38 Commits

Author SHA1 Message Date
Matt Godbolt 17f5202831 Sketching of layout for A/B/Difference view 11 years ago
Matt Godbolt e8ae595c53 WIP diff 11 years ago
Matt Godbolt 68e4edd3a4 First pass at trying to extract some kind of object out of the compiler mass, in preparation for diffing 11 years ago
Matt Godbolt 78108c19da Only show intel option if it is available 11 years ago
Matt Godbolt b39de1abdc Only apply -masm= if supported by compiler 11 years ago
Alin Rus b40e49c64d Add option to view assembly using intel syntax 11 years ago
Alin Rus 60dfa82c19 Show literal constants 11 years ago
Matt Godbolt 3cc04bee12 Spot negative constant numbers 11 years ago
Matt Godbolt 01b63c93a9 Fix sorting. I shouldn't be allowed to code before my third cup of coffee in the morning 11 years ago
Matt Godbolt 557a4957dd Sort compilers alphabetically in compiler list 11 years ago
Matt Godbolt 34c18aab45 Use gutter to mark error/warn messages which then plays nicer with the colouration. 11 years ago
Matt Godbolt 62fecbeb77 Enable ARM compiler on Matt's laptop 11 years ago
Matt Godbolt a6d90f7e6e Add gcc4.6 for ARM 11 years ago
Matt Godbolt 50881e7efc Don't update the assembly display if the C code only changes. Not quite sure why I thought that was necessary, was slowing down the whole thing. 11 years ago
Matt Godbolt 879f177088 Fix issue with clicking permalink loses colours 11 years ago
Matt Godbolt 4e1517c4d7 Slightly improve comment filtering 11 years ago
Matt Godbolt c81325e555 Set some better default filters. 11 years ago
Matt Godbolt aeac0d7f9d Don't count labels as used if they're used only by directives and we're filtering them out 11 years ago
Matt Godbolt 863b35c136 Add basic colouration 11 years ago
Matt Godbolt cf98f5a338 Parse out debug information 11 years ago
Matt Godbolt abd3f1b81f Prevent enter in the options from clicking the filter buttons 11 years ago
Matt Godbolt 186fb2987c Allow reading the spec files for msp430 11 years ago
Matt Godbolt 954a445b83 Msp430 support 11 years ago
Matt Godbolt 2c1529242b Fix loss of compiler choice from permalinks 11 years ago
Matt Godbolt 1fda182367 Fix bug with persistent storage of filters 11 years ago
Matt Godbolt 40587ca2b1 Added a bunch of filters to the assembly output 11 years ago
Matt Godbolt 1e49fadb0e Add avr-g++ 11 years ago
Matt Godbolt d6c0fc51b0 Stop being so chatty 11 years ago
Matt Godbolt f97d902ba4 Use the compiler wrapper on Amazon 11 years ago
Matt Godbolt 847a0cd8ee Fix up amazon make issue 11 years ago
Matt Godbolt 7b6fd25eb1 Add a config for my laptop 11 years ago
Matt Godbolt 89fd0d42f4 Fix for running npm all the time unnecessarily 11 years ago
Matt Godbolt d66cd446ee Try and separate amazon settings from general development settings 11 years ago
Matt Godbolt c8a66a32de Make a compiler-wrapper script 11 years ago
Matt Godbolt e410737091 First attempt at an arguably naive LD_PRELOAD library to try and restrict file access 11 years ago
Matt Godbolt af4fd27491 Add clang 11 years ago
Matt Godbolt 349c5ad873 Add permalink functionality 11 years ago
Matt Godbolt e8c9356234 WIP diff 11 years ago
  1. 0
      .npm-updated
  2. 9
      Makefile
  3. 55
      app.js
  4. 1
      c-preload/.gitignore
  5. 19
      c-preload/Makefile
  6. 7
      c-preload/compiler-wrapper
  7. 83
      c-preload/preload.c
  8. 2
      c-preload/tests/bad-includes
  9. 6
      c-preload/tests/testfile
  10. 4
      etc/config/gcc-explorer.amazon.properties
  11. 5
      etc/config/gcc-explorer.defaults.properties
  12. 2
      etc/config/gcc-explorer.lud-ldnmg01.properties
  13. 4
      etc/config/gcc-explorer.wud-mgodbolt01.properties
  14. 70
      static/asm.js
  15. 49
      static/ext/google-diff-match-patch/diff_match_patch.js
  16. 9
      static/gcc.css
  17. 372
      static/gcc.js
  18. 193
      static/index.html

0
.npm-updated

9
Makefile

@ -7,13 +7,20 @@ else
default: run
endif
node_modules: package.json
NODE_MODULES=.npm-updated
$(NODE_MODULES): package.json
npm install
@touch $@
node_modules: $(NODE_MODULES)
clean:
rm -rf node_modules
.PHONY: clean run
run: node_modules
./node_modules/.bin/supervisor ./app.js
run-amazon: node_modules
$(MAKE) -C c-preload
./node_modules/.bin/supervisor -- ./app.js --env amazon

55
app.js

@ -49,6 +49,8 @@ var rootDir = opts.rootDir || './etc';
props.initialize(rootDir + '/config', propHierarchy);
var port = props.get('gcc-explorer', 'port', 10240);
var compilers = [];
var compilersByExe = {};
function checkOptions(options) {
var okOptions = new RegExp(props.get('gcc-options', 'whitelistRe', '.*'));
@ -81,7 +83,12 @@ function compile(req, res) {
if (getCompilerExecutables().indexOf(compiler) < 0) {
return res.end(JSON.stringify({code: -1, stderr: "bad compiler " + compiler}));
}
var compilerInfo = compilersByExe[compiler];
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 filters = req.body.filters;
var optionsErr = checkOptions(options);
if (optionsErr) {
return res.end(JSON.stringify({code: -1, stderr: optionsErr}));
@ -95,7 +102,17 @@ function compile(req, res) {
return res.end(JSON.stringify({code: -1, stderr: "Unable to open temp file: " + err}));
}
var outputFilename = path.join(dirPath, 'output.S');
options = options.concat([ '-x', 'c++', '-o', outputFilename, '-S', '-']);
if (compilerInfo.supportedOpts['-masm']) {
var syntax = '-masm=att'; // default at&t
if (filters["intel"]) syntax = '-masm=intel';
options = options.concat([syntax]);
}
options = options.concat(['-x', 'c++', '-g', '-o', outputFilename, '-S', '-']);
var compilerWrapper = props.get("gcc-explorer", "compiler-wrapper");
if (compilerWrapper) {
options = [compiler].concat(options);
compiler = compilerWrapper;
}
var child = child_process.spawn(
compiler,
options
@ -187,29 +204,45 @@ function getCompilerExecutables() {
}
function getCompilers(req, res) {
res.end(JSON.stringify(compilers));
}
function findCompilers() {
async.map(getCompilerExecutables(),
function (compiler, callback) {
fs.stat(compiler, function(err, result) {
if (err) {
callback(null, null);
} else {
child_process.exec(compiler + ' --version', function(err, output) {
if (err) {
callback(null, null);
} else {
callback(null, {exe: compiler, version: output.split('\n')[0]});
if (err) return callback(null, null);
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) {
var options = {};
if (!err) {
var splitness = /--?[-a-zA-Z]+( ?[-a-zA-Z]+)/;
output.split('\n').forEach(function(line) {
var match = line.match(splitness);
if (!match) return;
options[match[0]] = true;
});
}
callback(null, {exe: compiler, version: version, supportedOpts: options});
});
}
});
});
},
function (err, all) {
all = all.filter(function(x){return x!=null;});
res.end(JSON.stringify(all));
compilers = all.sort(function(x,y){return x.version < y.version ? -1 : x.version > y.version ? 1 : 0;});
compilersByExe = {};
compilers.forEach(function(compiler) {
compilersByExe[compiler.exe] = compiler;
});
}
);
}
findCompilers();
// WebServer.
var webServer = connect();
webServer

1
c-preload/.gitignore vendored

@ -0,0 +1 @@
libpreload.so

19
c-preload/Makefile

@ -0,0 +1,19 @@
all: libpreload.so
libpreload.so: preload.c
$(CC) -std=c99 -shared -O1 -fPIC $^ -o $@ -ldl
.PHONY: test clean
test: libpreload.so
-@rm -f /tmp/allowed
cat tests/testfile | ./compiler-wrapper g++ -std=c++0x -S -o /tmp/allowed -x c++ -
@if [ ! -s /tmp/allowed ]; then echo "/tmp/allowed should exist"; false; fi
-@rm -f /tmp/allowed
cat tests/bad-includes | ./compiler-wrapper g++ -std=c++0x -S -o /tmp/allowed -x c++ - 2>&1 | grep 'Denying'
@if [ -s /tmp/allowed ]; then echo "/tmp/allowed should not exist"; false; fi
-@rm -f not-allowed
cat tests/testfile | ./compiler-wrapper g++ -std=c++0x -S -o not-allowed -x c++ - 2>&1 | grep 'Denying'
@if [ -e not-allowed ]; then echo "not-allowed should not exist"; false; fi
clean:
rm -f libpreload.so

7
c-preload/compiler-wrapper

@ -0,0 +1,7 @@
#/bin/sh
export LD_PRELOAD=$(dirname $0)/libpreload.so
export ALLOWED_FOR_CREATE=/tmp
export ALLOWED_FOR_READ=/usr/local/include:/usr/include:/usr/lib:/usr/msp430
"$@"

83
c-preload/preload.c

@ -0,0 +1,83 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#ifndef O_CREAT
#define O_CREAT 0100
#endif
static int allowed_env(const char* pathname, const char* envvar) {
char* dirpathbuf = strdup(pathname);
char* dirpath = dirname(dirpathbuf);
char resolvedBuf[PATH_MAX];
char* resolved = realpath(dirpath, resolvedBuf);
free(dirpathbuf);
if (resolved == NULL) {
return 0;
}
const char* okpath = getenv(envvar);
if (okpath == NULL) {
errno = EINVAL;
return 0;
}
while (*okpath) {
const char* end = strchrnul(okpath, ':');
if (strncmp(okpath, resolved, end - okpath) == 0) return 1;
okpath = end;
while (*okpath == ':') ++okpath;
}
//fprintf(stderr, "Access to \"%s\" denied by gcc-explorer policy\n", pathname);
errno = EACCES;
return 0;
}
static int allowed(const char* pathname, int flags) {
if (flags & O_CREAT)
return allowed_env(pathname, "ALLOWED_FOR_CREATE");
else
return allowed_env(pathname, "ALLOWED_FOR_READ");
}
int open(const char *pathname, int flags, mode_t mode) {
static int (*real_open)(const char*, int, mode_t) = NULL;
if (!real_open) real_open = dlsym(RTLD_NEXT, "open");
if (!allowed(pathname, flags)) {
return -1;
}
return real_open(pathname, flags, mode);
}
int creat(const char *pathname, mode_t mode) {
static int (*real_creat)(const char*, mode_t) = NULL;
if (!real_creat) real_creat = dlsym(RTLD_NEXT, "creat");
if (!allowed(pathname, O_CREAT)) {
return -1;
}
return real_creat(pathname, mode);
}
FILE* fopen(const char* name, const char* mode) {
static FILE* (*real_fopen)(const char*, const char*) = NULL;
if (!real_fopen) real_fopen = dlsym(RTLD_NEXT, "fopen");
if (!allowed(name, (mode[0] == 'r') ? 0 : O_CREAT)) {
return NULL;
}
return real_fopen(name, mode);
}

2
c-preload/tests/bad-includes

@ -0,0 +1,2 @@
#define DOTDOTFILE "../../../etc/passwd"
#include DOTDOTFILE

6
c-preload/tests/testfile

@ -0,0 +1,6 @@
// I am a test C++ program
#include <cstdint>
int foo() {
return 1;
}

4
etc/config/gcc-explorer.amazon.properties

@ -0,0 +1,4 @@
# Settings overridden for Amazon EC2 instances that power http://gcc.godbolt.org/
compileTimeoutMs=200
compilers=/usr/bin/g++-4.4:/usr/bin/g++-4.5:/usr/bin/g++-4.6:/usr/bin/g++-4.7:/usr/bin/arm-linux-gnueabi-g++-4.5:/usr/bin/clang++:/usr/bin/avr-g++:/usr/bin/msp430-g++:/usr/bin/arm-linux-gnueabi-g++-4.6
compiler-wrapper=./c-preload/compiler-wrapper

5
etc/config/gcc-explorer.defaults.properties

@ -1,3 +1,4 @@
# Default settings for GCC Explorer.
port=10240
compileTimeoutMs=200
compilers=/usr/bin/g++-4.4:/usr/bin/g++-4.5:/usr/bin/g++-4.6:/usr/bin/g++-4.7:/usr/bin/arm-linux-gnueabi-g++-4.5
compileTimeoutMs=1000
compilers=/usr/bin/g++-4.4:/usr/bin/g++-4.5:/usr/bin/g++-4.6:/usr/bin/g++-4.7:/usr/bin/clang++

2
etc/config/gcc-explorer.lud-ldnmg01.properties

@ -0,0 +1,2 @@
# Settings used on Matt's laptop.
compilers=/usr/bin/g++-4.4:/usr/bin/g++-4.5:/usr/bin/g++-4.6:/usr/bin/g++-4.7:/usr/bin/clang++:/home/mgodbolt/apps/intel-icc-oss/bin/icc:/usr/bin/arm-linux-gnueabi-g++-4.6

4
etc/config/gcc-explorer.wud-mgodbolt01.properties

@ -0,0 +1,4 @@
# Default settings for GCC Explorer.
port=10240
compileTimeoutMs=1000
compilers=/usr/bin/g++-4.4:/usr/bin/g++-4.5:/usr/bin/g++-4.6:/usr/bin/g++-4.7:/usr/bin/clang++:/usr/bin/arm-linux-gnueabi-g++-4.6

70
static/asm.js

@ -28,7 +28,7 @@ CodeMirror.defineMode("asm", function() {
return tokenString(ch)(stream);
}
if (/[\[\]{}\(\),;\:]/.test(ch)) return null;
if (/[\d$]/.test(ch)) {
if (/[\d$]/.test(ch) || (ch == '-' && stream.peek().match(/[0-9]/))) {
stream.eatWhile(/[\w\.]/);
return "number";
}
@ -47,3 +47,71 @@ CodeMirror.defineMode("asm", function() {
});
CodeMirror.defineMIME("text/x-asm", "asm");
function processAsm(asm, filters) {
var result = [];
var asmLines = asm.split("\n");
var labelsUsed = {};
var labelFind = /\.[a-zA-Z0-9$_.]+/g;
var files = {};
var prevLabel = "";
var literalConstant = /^\.LC\d+/;
var lcString = /\.string/;
var fileFind = /^\s*\.file\s+(\d+)\s+"([^"]+)"$/;
var hasOpcode = /^\s*([a-zA-Z0-9$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
$.each(asmLines, 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.
$.each(match, function(_, label) { labelsUsed[label] = true; });
}
match = line.match(fileFind);
if (match) {
files[parseInt(match[1])] = match[2];
}
});
var directive = /^\s*\..*$/;
var labelDefinition = /^(\.[a-zA-Z0-9$_.]+):/;
var commentOnly = /^\s*(#|@|\/\/).*/;
var sourceTag = /^\s*\.loc\s+(\d+)\s+(\d+).*/;
var stdInLooking = /.*<stdin>|-/;
var source = null;
$.each(asmLines, function(_, line) {
var match;
if (line.trim() == "") return;
if (match = line.match(sourceTag)) {
source = null;
var file = files[parseInt(match[1])];
if (file && file.match(stdInLooking)) {
source = parseInt(match[2]);
}
}
if (filters.commentOnly && line.match(commentOnly)) return;
match = line.match(labelDefinition);
if (!match && line.match(lcString) && prevLabel) {
result.push({text: line, source: null});
prevLabel = "";
return;
}
if (match && labelsUsed[match[1]] == undefined) {
if (filters.labels) return;
}
if (match && line.match(literalConstant)) {
prevLabel = line;
}
if (!match && filters.directives) {
// Check for directives only if it wasn't a label; the regexp would
// otherwise misinterpret labels as directives.
match = line.match(directive);
if (match) return;
}
var hasOpcodeMatch = line.match(hasOpcode);
result.push({text: line, source: hasOpcodeMatch ? source : null});
});
return result;
}

49
static/ext/google-diff-match-patch/diff_match_patch.js

@ -0,0 +1,49 @@
(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32}
diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b),c=a.substring(0,f),a=a.substring(f),b=b.substring(f),f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f),a=a.substring(0,a.length-f),b=b.substring(0,b.length-f),a=this.diff_compute_(a,
b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a};
diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);if(-1!=g)return c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c;if(1==f.length)return[[-1,a],[1,b]];return(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100<a.length&&100<b.length?this.diff_lineMode_(a,
b,d):this.diff_bisect_(a,b,d)};
diff_match_patch.prototype.diff_lineMode_=function(a,b,c){var d=this.diff_linesToChars_(a,b),a=d.chars1,b=d.chars2,d=d.lineArray,a=this.diff_main(a,b,!1,c);this.diff_charsToLines_(a,d);this.diff_cleanupSemantic(a);a.push([0,""]);for(var e=d=b=0,f="",g="";b<a.length;){switch(a[b][0]){case 1:e++;g+=a[b][1];break;case -1:d++;f+=a[b][1];break;case 0:if(1<=d&&1<=e){a.splice(b-d-e,d+e);b=b-d-e;d=this.diff_main(f,g,!1,c);for(e=d.length-1;0<=e;e--)a.splice(b,0,d[e]);b+=d.length}d=e=0;g=f=""}b++}a.pop();return a};
diff_match_patch.prototype.diff_bisect_=function(a,b,c){for(var d=a.length,e=b.length,f=Math.ceil((d+e)/2),g=f,h=2*f,j=Array(h),i=Array(h),k=0;k<h;k++)j[k]=-1,i[k]=-1;j[g+1]=0;i[g+1]=0;for(var k=d-e,p=0!=k%2,q=0,s=0,o=0,v=0,u=0;u<f&&!((new Date).getTime()>c);u++){for(var n=-u+q;n<=u-s;n+=2){var l=g+n,m;m=n==-u||n!=u&&j[l-1]<j[l+1]?j[l+1]:j[l-1]+1;for(var r=m-n;m<d&&r<e&&a.charAt(m)==b.charAt(r);)m++,r++;j[l]=m;if(m>d)s+=2;else if(r>e)q+=2;else if(p&&(l=g+k-n,0<=l&&l<h&&-1!=i[l])){var t=d-i[l];if(m>=
t)return this.diff_bisectSplit_(a,b,m,r,c)}}for(n=-u+o;n<=u-v;n+=2){l=g+n;t=n==-u||n!=u&&i[l-1]<i[l+1]?i[l+1]:i[l-1]+1;for(m=t-n;t<d&&m<e&&a.charAt(d-t-1)==b.charAt(e-m-1);)t++,m++;i[l]=t;if(t>d)v+=2;else if(m>e)o+=2;else if(!p&&(l=g+k-n,0<=l&&l<h&&-1!=j[l]&&(m=j[l],r=g+m-l,t=d-t,m>=t)))return this.diff_bisectSplit_(a,b,m,r,c)}}return[[-1,a],[1,b]]};
diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d),a=a.substring(c),b=b.substring(d),f=this.diff_main(f,g,!1,e),e=this.diff_main(a,b,!1,e);return f.concat(e)};
diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;f<a.length-1;){f=a.indexOf("\n",c);-1==f&&(f=a.length-1);var q=a.substring(c,f+1),c=f+1;(e.hasOwnProperty?e.hasOwnProperty(q):void 0!==e[q])?b+=String.fromCharCode(e[q]):(b+=String.fromCharCode(g),e[q]=g,d[g++]=q)}return b}var d=[],e={};d[0]="";var f=c(a),g=c(b);return{chars1:f,chars2:g,lineArray:d}};
diff_match_patch.prototype.diff_charsToLines_=function(a,b){for(var c=0;c<a.length;c++){for(var d=a[c][1],e=[],f=0;f<d.length;f++)e[f]=b[d.charCodeAt(f)];a[c][1]=e.join("")}};diff_match_patch.prototype.diff_commonPrefix=function(a,b){if(!a||!b||a.charAt(0)!=b.charAt(0))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(f,e)==b.substring(f,e)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
diff_match_patch.prototype.diff_commonSuffix=function(a,b){if(!a||!b||a.charAt(a.length-1)!=b.charAt(b.length-1))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(a.length-e,a.length-f)==b.substring(b.length-e,b.length-f)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
diff_match_patch.prototype.diff_commonOverlap_=function(a,b){var c=a.length,d=b.length;if(0==c||0==d)return 0;c>d?a=a.substring(c-d):c<d&&(b=b.substring(0,c));c=Math.min(c,d);if(a==b)return c;for(var d=0,e=1;;){var f=a.substring(c-e),f=b.indexOf(f);if(-1==f)return d;e+=f;if(0==f||a.substring(c-e)==b.substring(0,e))d=e,e++}};
diff_match_patch.prototype.diff_halfMatch_=function(a,b){function c(a,b,c){for(var d=a.substring(c,c+Math.floor(a.length/4)),e=-1,g="",h,j,n,l;-1!=(e=b.indexOf(d,e+1));){var m=f.diff_commonPrefix(a.substring(c),b.substring(e)),r=f.diff_commonSuffix(a.substring(0,c),b.substring(0,e));g.length<r+m&&(g=b.substring(e-r,e)+b.substring(e,e+m),h=a.substring(0,c-r),j=a.substring(c+m),n=b.substring(0,e-r),l=b.substring(e+m))}return 2*g.length>=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null;
var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.length<d.length)return null;var f=this,g=c(d,e,Math.ceil(d.length/4)),d=c(d,e,Math.ceil(d.length/2)),h;if(!g&&!d)return null;h=d?g?g[4].length>d[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]};
diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f<a.length;)0==a[f][0]?(c[d++]=f,g=j,h=i,i=j=0,e=a[f][1]):(1==a[f][0]?j+=a[f][1].length:i+=a[f][1].length,e&&e.length<=Math.max(g,h)&&e.length<=Math.max(j,i)&&(a.splice(c[d-1],0,[-1,e]),a[c[d-1]+1][0]=1,d--,d--,f=0<d?c[d-1]:-1,i=j=h=g=0,e=null,b=!0)),f++;b&&this.diff_cleanupMerge(a);this.diff_cleanupSemanticLossless(a);for(f=1;f<a.length;){if(-1==a[f-1][0]&&1==a[f][0]){b=a[f-1][1];c=a[f][1];
d=this.diff_commonOverlap_(b,c);e=this.diff_commonOverlap_(c,b);if(d>=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}};
diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_);
return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c<a.length-1;){if(0==a[c-1][0]&&0==a[c+1][0]){var d=a[c-1][1],e=a[c][1],f=a[c+1][1],g=this.diff_commonSuffix(d,e);if(g)var h=e.substring(e.length-g),d=d.substring(0,d.length-g),e=h+e.substring(0,e.length-g),f=h+f;for(var g=d,h=e,j=f,i=b(d,e)+b(e,f);e.charAt(0)===f.charAt(0);){var d=d+e.charAt(0),e=e.substring(1)+f.charAt(0),f=f.substring(1),k=b(d,e)+b(e,f);k>=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]=
h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/;
diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;f<a.length;){if(0==a[f][0])a[f][1].length<this.Diff_EditCost&&(j||i)?(c[d++]=f,g=j,h=i,e=a[f][1]):(d=0,e=null),j=i=!1;else if(-1==a[f][0]?i=!0:j=!0,e&&(g&&h&&j&&i||e.length<this.Diff_EditCost/2&&3==g+h+j+i))a.splice(c[d-1],0,[-1,e]),a[c[d-1]+1][0]=1,d--,e=null,g&&h?(j=i=!0,d=0):(d--,f=0<d?c[d-1]:-1,j=i=!1),b=!0;f++}b&&this.diff_cleanupMerge(a)};
diff_match_patch.prototype.diff_cleanupMerge=function(a){a.push([0,""]);for(var b=0,c=0,d=0,e="",f="",g;b<a.length;)switch(a[b][0]){case 1:d++;f+=a[b][1];b++;break;case -1:c++;e+=a[b][1];b++;break;case 0:1<c+d?(0!==c&&0!==d&&(g=this.diff_commonPrefix(f,e),0!==g&&(0<b-c-d&&0==a[b-c-d-1][0]?a[b-c-d-1][1]+=f.substring(0,g):(a.splice(0,0,[0,f.substring(0,g)]),b++),f=f.substring(g),e=e.substring(g)),g=this.diff_commonSuffix(f,e),0!==g&&(a[b][1]=f.substring(f.length-g)+a[b][1],f=f.substring(0,f.length-
g),e=e.substring(0,e.length-g))),0===c?a.splice(b-d,c+d,[1,f]):0===d?a.splice(b-c,c+d,[-1,e]):a.splice(b-c-d,c+d,[-1,e],[1,f]),b=b-c-d+(c?1:0)+(d?1:0)+1):0!==b&&0==a[b-1][0]?(a[b-1][1]+=a[b][1],a.splice(b,1)):b++,c=d=0,f=e=""}""===a[a.length-1][1]&&a.pop();c=!1;for(b=1;b<a.length-1;)0==a[b-1][0]&&0==a[b+1][0]&&(a[b][1].substring(a[b][1].length-a[b-1][1].length)==a[b-1][1]?(a[b][1]=a[b-1][1]+a[b][1].substring(0,a[b][1].length-a[b-1][1].length),a[b+1][1]=a[b-1][1]+a[b+1][1],a.splice(b-1,1),c=!0):a[b][1].substring(0,
a[b+1][1].length)==a[b+1][1]&&(a[b-1][1]+=a[b+1][1],a[b][1]=a[b][1].substring(a[b+1][1].length)+a[b+1][1],a.splice(b+1,1),c=!0)),b++;c&&this.diff_cleanupMerge(a)};diff_match_patch.prototype.diff_xIndex=function(a,b){var c=0,d=0,e=0,f=0,g;for(g=0;g<a.length;g++){1!==a[g][0]&&(c+=a[g][1].length);-1!==a[g][0]&&(d+=a[g][1].length);if(c>b)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)};
diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=/</g,e=/>/g,f=/\n/g,g=0;g<a.length;g++){var h=a[g][0],j=a[g][1],j=j.replace(c,"&amp;").replace(d,"&lt;").replace(e,"&gt;").replace(f,"&para;<br>");switch(h){case 1:b[g]='<ins style="background:#e6ffe6;">'+j+"</ins>";break;case -1:b[g]='<del style="background:#ffe6e6;">'+j+"</del>";break;case 0:b[g]="<span>"+j+"</span>"}}return b.join("")};
diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;c<a.length;c++)1!==a[c][0]&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_text2=function(a){for(var b=[],c=0;c<a.length;c++)-1!==a[c][0]&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_levenshtein=function(a){for(var b=0,c=0,d=0,e=0;e<a.length;e++){var f=a[e][0],g=a[e][1];switch(f){case 1:c+=g.length;break;case -1:d+=g.length;break;case 0:b+=Math.max(c,d),d=c=0}}return b+=Math.max(c,d)};
diff_match_patch.prototype.diff_toDelta=function(a){for(var b=[],c=0;c<a.length;c++)switch(a[c][0]){case 1:b[c]="+"+encodeURI(a[c][1]);break;case -1:b[c]="-"+a[c][1].length;break;case 0:b[c]="="+a[c][1].length}return b.join("\t").replace(/%20/g," ")};
diff_match_patch.prototype.diff_fromDelta=function(a,b){for(var c=[],d=0,e=0,f=b.split(/\t/g),g=0;g<f.length;g++){var h=f[g].substring(1);switch(f[g].charAt(0)){case "+":try{c[d++]=[1,decodeURI(h)]}catch(j){throw Error("Illegal escape in diff_fromDelta: "+h);}break;case "-":case "=":var i=parseInt(h,10);if(isNaN(i)||0>i)throw Error("Invalid number in diff_fromDelta: "+h);h=a.substring(e,e+=i);"="==f[g].charAt(0)?c[d++]=[0,h]:c[d++]=[-1,h];break;default:if(f[g])throw Error("Invalid diff operation in diff_fromDelta: "+
f[g]);}}if(e!=a.length)throw Error("Delta length ("+e+") does not equal source text length ("+a.length+").");return c};diff_match_patch.prototype.match_main=function(a,b,c){if(null==a||null==b||null==c)throw Error("Null input. (match_main)");c=Math.max(0,Math.min(c,a.length));return a==b?0:a.length?a.substring(c,c+b.length)==b?c:this.match_bitap_(a,b,c):-1};
diff_match_patch.prototype.match_bitap_=function(a,b,c){function d(a,d){var e=a/b.length,g=Math.abs(c-d);return!f.Match_Distance?g?1:e:e+g/f.Match_Distance}if(b.length>this.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<<b.length-1,h=-1,i,k,p=b.length+a.length,q,s=0;s<b.length;s++){i=0;for(k=p;i<k;)d(s,c+
k)<=g?i=k:p=k,k=Math.floor((p-i)/2+i);p=k;i=Math.max(1,c-k+1);var o=Math.min(c+k,a.length)+b.length;k=Array(o+2);for(k[o+1]=(1<<s)-1;o>=i;o--){var v=e[a.charAt(o-1)];k[o]=0===s?(k[o+1]<<1|1)&v:(k[o+1]<<1|1)&v|(q[o+1]|q[o])<<1|1|q[o+1];if(k[o]&j&&(v=d(s,o-1),v<=g))if(g=v,h=o-1,h>c)i=Math.max(1,2*c-h);else break}if(d(s+1,c)>g)break;q=k}return h};
diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c<a.length;c++)b[a.charAt(c)]=0;for(c=0;c<a.length;c++)b[a.charAt(c)]|=1<<a.length-c-1;return b};
diff_match_patch.prototype.patch_addContext_=function(a,b){if(0!=b.length){for(var c=b.substring(a.start2,a.start2+a.length1),d=0;b.indexOf(c)!=b.lastIndexOf(c)&&c.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)d+=this.Patch_Margin,c=b.substring(a.start2-d,a.start2+a.length1+d);d+=this.Patch_Margin;(c=b.substring(a.start2-d,a.start2))&&a.diffs.unshift([0,c]);(d=b.substring(a.start2+a.length1,a.start2+a.length1+d))&&a.diffs.push([0,d]);a.start1-=c.length;a.start2-=c.length;a.length1+=
c.length+d.length;a.length2+=c.length+d.length}};
diff_match_patch.prototype.patch_make=function(a,b,c){var d;if("string"==typeof a&&"string"==typeof b&&"undefined"==typeof c)d=a,b=this.diff_main(d,b,!0),2<b.length&&(this.diff_cleanupSemantic(b),this.diff_cleanupEfficiency(b));else if(a&&"object"==typeof a&&"undefined"==typeof b&&"undefined"==typeof c)b=a,d=this.diff_text1(b);else if("string"==typeof a&&b&&"object"==typeof b&&"undefined"==typeof c)d=a;else if("string"==typeof a&&"string"==typeof b&&c&&"object"==typeof c)d=a,b=c;else throw Error("Unknown call format to patch_make.");
if(0===b.length)return[];for(var c=[],a=new diff_match_patch.patch_obj,e=0,f=0,g=0,h=d,j=0;j<b.length;j++){var i=b[j][0],k=b[j][1];!e&&0!==i&&(a.start1=f,a.start2=g);switch(i){case 1:a.diffs[e++]=b[j];a.length2+=k.length;d=d.substring(0,g)+k+d.substring(g);break;case -1:a.length1+=k.length;a.diffs[e++]=b[j];d=d.substring(0,g)+d.substring(g+k.length);break;case 0:k.length<=2*this.Patch_Margin&&e&&b.length!=j+1?(a.diffs[e++]=b[j],a.length1+=k.length,a.length2+=k.length):k.length>=2*this.Patch_Margin&&
e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c],e=new diff_match_patch.patch_obj;e.diffs=[];for(var f=0;f<d.diffs.length;f++)e.diffs[f]=d.diffs[f].slice();e.start1=d.start1;e.start2=d.start2;e.length1=d.length1;e.length2=d.length2;b[c]=e}return b};
diff_match_patch.prototype.patch_apply=function(a,b){if(0==a.length)return[b,[]];var a=this.patch_deepCopy(a),c=this.patch_addPadding(a),b=c+b+c;this.patch_splitMax(a);for(var d=0,e=[],f=0;f<a.length;f++){var g=a[f].start2+d,h=this.diff_text1(a[f].diffs),j,i=-1;if(h.length>this.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g);
if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;i<a[f].diffs.length;i++){var p=a[f].diffs[i];0!==p[0]&&(k=this.diff_xIndex(g,h));1===p[0]?b=b.substring(0,
j+k)+p[1]+b.substring(j+k):-1===p[0]&&(b=b.substring(0,j+k)+b.substring(j+this.diff_xIndex(g,h+p[1].length)));-1!==p[0]&&(h+=p[1].length)}}}b=b.substring(c.length,b.length-c.length);return[b,e]};
diff_match_patch.prototype.patch_addPadding=function(a){for(var b=this.Patch_Margin,c="",d=1;d<=b;d++)c+=String.fromCharCode(d);for(d=0;d<a.length;d++)a[d].start1+=b,a[d].start2+=b;var d=a[0],e=d.diffs;if(0==e.length||0!=e[0][0])e.unshift([0,c]),d.start1-=b,d.start2-=b,d.length1+=b,d.length2+=b;else if(b>e[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0,
c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c};
diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c<a.length;c++)if(!(a[c].length1<=b)){var d=a[c];a.splice(c--,1);for(var e=d.start1,f=d.start2,g="";0!==d.diffs.length;){var h=new diff_match_patch.patch_obj,j=!0;h.start1=e-g.length;h.start2=f-g.length;""!==g&&(h.length1=h.length2=g.length,h.diffs.push([0,g]));for(;0!==d.diffs.length&&h.length1<b-this.Patch_Margin;){var g=d.diffs[0][0],i=d.diffs[0][1];1===g?(h.length2+=i.length,f+=i.length,h.diffs.push(d.diffs.shift()),
j=!1):-1===g&&1==h.diffs.length&&0==h.diffs[0][0]&&i.length>2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&&
(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c<a.length;c++)b[c]=a[c];return b.join("")};
diff_match_patch.prototype.patch_fromText=function(a){var b=[];if(!a)return b;for(var a=a.split("\n"),c=0,d=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;c<a.length;){var e=a[c].match(d);if(!e)throw Error("Invalid patch string: "+a[c]);var f=new diff_match_patch.patch_obj;b.push(f);f.start1=parseInt(e[1],10);""===e[2]?(f.start1--,f.length1=1):"0"==e[2]?f.length1=0:(f.start1--,f.length1=parseInt(e[2],10));f.start2=parseInt(e[3],10);""===e[4]?(f.start2--,f.length2=1):"0"==e[4]?f.length2=0:(f.start2--,f.length2=
parseInt(e[4],10));for(c++;c<a.length;){e=a[c].charAt(0);try{var g=decodeURI(a[c].substring(1))}catch(h){throw Error("Illegal escape in patch_fromText: "+g);}if("-"==e)f.diffs.push([-1,g]);else if("+"==e)f.diffs.push([1,g]);else if(" "==e)f.diffs.push([0,g]);else if("@"==e)break;else if(""!==e)throw Error('Invalid patch mode "'+e+'" in: '+g);c++}}return b};diff_match_patch.patch_obj=function(){this.diffs=[];this.start2=this.start1=null;this.length2=this.length1=0};
diff_match_patch.patch_obj.prototype.toString=function(){var a,b;a=0===this.length1?this.start1+",0":1==this.length1?this.start1+1:this.start1+1+","+this.length1;b=0===this.length2?this.start2+",0":1==this.length2?this.start2+1:this.start2+1+","+this.length2;a=["@@ -"+a+" +"+b+" @@\n"];var c;for(b=0;b<this.diffs.length;b++){switch(this.diffs[b][0]){case 1:c="+";break;case -1:c="-";break;case 0:c=" "}a[b+1]=c+encodeURI(this.diffs[b][1])+"\n"}return a.join("").replace(/%20/g," ")};
this.diff_match_patch=diff_match_patch;this.DIFF_DELETE=-1;this.DIFF_INSERT=1;this.DIFF_EQUAL=0;})()

9
static/gcc.css

@ -47,3 +47,12 @@ li.social {
.indented {
margin-left: 36px;
}
.rainbow-0 { background: #ffa !important; }
.rainbow-1 { background: #faf !important; }
.rainbow-2 { background: #faa !important; }
.rainbow-3 { background: #aff !important; }
.rainbow-4 { background: #afa !important; }
.rainbow-5 { background: #aaf !important; }
.rainbow-6 { background: #77a !important; }
.rainbow-7 { background: #a77 !important; }

372
static/gcc.js

@ -22,10 +22,6 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
var pendingTimeout = null;
var asmCodeMirror = null;
var lastRequest = null;
function parseLines(lines, callback) {
var re = /^\<stdin\>:([0-9]+):([0-9]+):\s+(.*)/;
$.each(lines.split('\n'), function(_, line) {
@ -40,56 +36,10 @@ function parseLines(lines, callback) {
}
});
}
var errorLines = [];
function onCompileResponse(data) {
var stdout = data.stdout || "";
var stderr = data.stderr || "";
if (data.code == 0) {
stdout += "\nCompiled ok";
} else {
stderr += "\nCompilation failed";
function clearBackground(cm) {
for (var i = 0; i < cm.lineCount(); ++i) {
cm.setLineClass(i, null, null);
}
$.each(errorLines, function(_, line) {
if (line) cppEditor.setLineClass(line, null, null);
});
errorLines = [];
$('.result .output :visible').remove();
parseLines(stderr + stdout, function(lineNum, msg) {
var elem = $('.result .output .template').clone().appendTo('.result .output').removeClass('template');
if (lineNum) {
errorLines.push(cppEditor.setLineClass(lineNum - 1, null, "error"));
elem.html($('<a href="#">').append(lineNum + " : " + msg)).click(function() {
cppEditor.setSelection({line: lineNum - 1, ch: 0}, {line: lineNum, ch: 0});
return false;
});
} else {
elem.text(msg);
}
});
asmCodeMirror.setValue(data.asm || "[no output]");
}
function onChange() {
if (pendingTimeout) clearTimeout(pendingTimeout);
pendingTimeout = setTimeout(function() {
var data = {
source: cppEditor.getValue(),
compiler: $('.compiler').val(),
options: $('.compiler_options').val()
};
window.localStorage['compiler'] = data.compiler;
window.localStorage['compilerOptions'] = data.options;
if (data == lastRequest) return;
lastRequest = data;
$.ajax({
type: 'POST',
url: '/compile',
dataType: 'json',
data: data,
success: onCompileResponse});
}, 750);
window.localStorage['code'] = cppEditor.getValue();
}
function getSource() {
@ -122,6 +72,8 @@ function getSource() {
}
}
var compilersByExe = {};
var currentFileList = {};
function updateFileList() {
getSource().list(function(results) {
@ -140,49 +92,293 @@ function onSourceChange() {
window.localStorage['source'] = $('.source').val();
}
function loadFile() {
var name = $('.filename').val();
window.localStorage['filename'] = name;
getSource().load(name, function(results) {
if (results.file) {
cppEditor.setValue(results.file);
function Compiler(domRoot) {
var pendingTimeout = null;
var asmCodeMirror = null;
var cppEditor = null;
var lastRequest = null;
var currentAssembly = null;
var ignoreChanges = true; // Horrible hack to avoid onChange doing anything on first starting, ie before we've set anything up.
cppEditor = CodeMirror.fromTextArea(domRoot.find(".editor textarea")[0], {
lineNumbers: true,
matchBrackets: true,
useCPP: true,
mode: "text/x-c++src",
onChange: onChange
});
asmCodeMirror = CodeMirror.fromTextArea(domRoot.find(".asm textarea")[0], {
lineNumbers: true,
matchBrackets: true,
mode: "text/x-asm",
readOnly: true
});
if (window.localStorage['code']) cppEditor.setValue(window.localStorage['code']);
domRoot.find('.compiler').change(onCompilerChange);
domRoot.find('.compiler_options').change(onChange).keyup(onChange);
ignoreChanges = false;
$('.filter button.btn').click(function(e) {
$(e.target).toggleClass('active');
onChange();
});
function onCompileResponse(data) {
var stdout = data.stdout || "";
var stderr = data.stderr || "";
if (data.code == 0) {
stdout += "\nCompiled ok";
} else {
// TODO: error?
console.log(results);
stderr += "\nCompilation failed";
}
});
}
$('.result .output :visible').remove();
var highlightLine = (data.asm == null);
for (var i = 0; i < cppEditor.lineCount(); ++i) cppEditor.setMarker(i);
parseLines(stderr + stdout, function(lineNum, msg) {
var elem = $('.result .output .template').clone().appendTo('.result .output').removeClass('template');
if (lineNum) {
cppEditor.setMarker(lineNum - 1, null, "error");
elem.html($('<a href="#">').append(lineNum + " : " + msg)).click(function() {
cppEditor.setSelection({line: lineNum - 1, ch: 0}, {line: lineNum, ch: 0});
return false;
});
} else {
elem.text(msg);
}
});
currentAssembly = data.asm || "[no output]";
updateAsm();
}
function saveFile() {
saveAs($('.files .filename').val());
}
function numberUsedLines(asm) {
var sourceLines = {};
$.each(asm, function(_, x) { if (x.source) sourceLines[x.source - 1] = true; });
var ordinal = 0;
$.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 };
}
var lastUpdatedAsm = null;
function updateAsm(forceUpdate) {
if (!currentAssembly) return;
var newFilters = getAsmFilters();
var hashedUpdate = JSON.stringify({
asm: currentAssembly,
filter: newFilters
});
if (!forceUpdate && lastUpdatedAsm == hashedUpdate) { return; }
lastUpdatedAsm = hashedUpdate;
var asm = processAsm(currentAssembly, newFilters);
var asmText = $.map(asm, function(x){ return x.text; }).join("\n");
var numberedLines = numberUsedLines(asm);
asmCodeMirror.setValue(asmText);
clearBackground(cppEditor);
clearBackground(asmCodeMirror);
if (newFilters.colouriseAsm) {
$.each(numberedLines.source, function(line, ordinal) {
cppEditor.setLineClass(parseInt(line), null, "rainbow-" + (ordinal & 7));
});
$.each(numberedLines.asm, function(line, ordinal) {
asmCodeMirror.setLineClass(parseInt(line), null, "rainbow-" + (ordinal & 7));
});
}
}
function onChange() {
if (ignoreChanges) return; // Ugly hack during startup.
if (pendingTimeout) clearTimeout(pendingTimeout);
pendingTimeout = setTimeout(function() {
var data = {
source: cppEditor.getValue(),
compiler: $('.compiler').val(),
options: $('.compiler_options').val(),
filters: getAsmFilters()
};
window.localStorage['compiler'] = data.compiler;
window.localStorage['compilerOptions'] = data.options;
if (data == lastRequest) return;
lastRequest = data;
$.ajax({
type: 'POST',
url: '/compile',
dataType: 'json',
data: data,
success: onCompileResponse});
}, 750);
window.localStorage['code'] = cppEditor.getValue();
window.localStorage['filter'] = JSON.stringify(getAsmFilters());
updateAsm();
$('a.permalink').attr('href', '#' + serialiseState());
}
function loadFile() {
var name = $('.filename').val();
window.localStorage['filename'] = name;
getSource().load(name, function(results) {
if (results.file) {
cppEditor.setValue(results.file);
} else {
// TODO: error?
console.log(results);
}
});
}
function saveAs(filename) {
var prevFilename = window.localStorage['filename'] || "";
if (filename != prevFilename && currentFileList[filename]) {
// TODO!
alert("Coming soon - overwriting files");
return;
function saveFile() {
saveAs($('.files .filename').val());
}
var obj = { urlpart: filename, name: filename, file: cppEditor.getValue() };
getSource().save(obj, function(ok) {
if (ok) {
window.localStorage['filename'] = filename;
updateFileList();
function saveAs(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: cppEditor.getValue() };
getSource().save(obj, function(ok) {
if (ok) {
window.localStorage['filename'] = filename;
updateFileList();
}
});
}
function saveFileAs() {
$('#saveDialog').modal();
$('#saveDialog .save-filename').val($('.files .filename').val());
$('#saveDialog .save-filename').focus();
function onSave() {
$('#saveDialog').modal('hide');
saveAs($('#saveDialog .save-filename').val());
};
$('#saveDialog .save').click(onSave);
$('#saveDialog .save-filename').keyup(function(event) {
if (event.keyCode == 13) onSave();
});
}
function serialiseState() {
var state = {
version: 2,
source: cppEditor.getValue(),
compiler: domRoot.find('.compiler').val(),
options: domRoot.find('.compiler_options').val(),
filterAsm: getAsmFilters()
};
return encodeURIComponent(JSON.stringify(state));
}
function deserialiseState(state) {
try {
var state = $.parseJSON(decodeURIComponent(state));
if (state.version == 1) {
state.filterAsm = {};
}
else if (state.version != 2) return false;
} catch (ignored) { return false; }
cppEditor.setValue(state.source);
domRoot.find('.compiler').val(state.compiler);
domRoot.find('.compiler_options').val(state.options);
setFilterUi(state.filterAsm);
// Somewhat hackily persist compiler into local storage else when the ajax response comes in
// with the list of compilers it can splat over the deserialized version.
// The whole serialize/hash/localStorage code is a mess! TODO(mg): fix
window.localStorage['compiler'] = state.compiler;
updateAsm(true); // Force the update to reset colours after calling cppEditor.setValue
return true;
}
function onCompilerChange() {
onChange();
var compiler = compilersByExe[$('.compiler').val()];
domRoot.find('.filter button.btn[value="intel"]').toggleClass("disabled", !compiler.supportedOpts["-masm"]);
}
function setCompilers(compilers) {
domRoot.find('.compiler option').remove();
$.each(compilers, function(index, arg) {
$('.compiler').append($('<option value="' + arg.exe + '">' + arg.version + '</option>'));
});
onCompilerChange();
}
return {
deserialiseState: deserialiseState,
setCompilers: setCompilers,
loadFile: loadFile,
saveFile: saveFile,
saveFileAs: saveFileAs
};
}
function initialise() {
var compiler = new Compiler($('body'));
if (window.localStorage['compilerOptions']) $('.compiler_options').val(window.localStorage['compilerOptions']);
var defaultFilters = JSON.stringify(getAsmFilters());
setFilterUi($.parseJSON(window.localStorage['filter'] || defaultFilters));
$('form').submit(function() { return false; });
$('.files .source').change(onSourceChange);
$.getJSON("/compilers", function(results) {
compilersByExe = {};
$.each(results, function(index, arg) {
compilersByExe[arg.exe] = arg;
});
compiler.setCompilers(results);
});
$.getJSON("/sources", function(results) {
$('.source option').remove();
$.each(results, function(index, arg) {
$('.files .source').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>'));
if (window.localStorage['source'] == arg.urlpart) {
$('.files .source').val(arg.urlpart);
}
});
onSourceChange();
});
$('.files .load').click(function() {
compiler.loadFile();
return false;
});
$('.files .save').click(function() {
compiler.saveFile();
return false;
});
$('.files .saveas').click(function() {
compiler.saveFileAs();
return false;
});
function loadFromHash() {
compiler.deserialiseState(window.location.hash.substr(1));
}
$(window).bind('hashchange', function() {
loadFromHash();
});
loadFromHash();
ignoreChanges = false;
}
function saveFileAs() {
$('#saveDialog').modal();
$('#saveDialog .save-filename').val($('.files .filename').val());
$('#saveDialog .save-filename').focus();
function onSave() {
$('#saveDialog').modal('hide');
saveAs($('#saveDialog .save-filename').val());
};
$('#saveDialog .save').click(onSave);
$('#saveDialog .save-filename').keyup(function(event) {
if (event.keyCode == 13) onSave();
function getAsmFilters() {
var asmFilters = {};
$('.filter button.btn.active').each(function() {
asmFilters[$(this).val()] = true;
});
return asmFilters;
}
function setFilterUi(asmFilters) {
$('.filter button.btn').each(function() {
$(this).toggleClass('active', !!asmFilters[$(this).val()]);
});
}
$(initialise);

193
static/index.html

@ -9,65 +9,10 @@
<script src="ext/codemirror/clike.js"></script>
<script src="asm.js"></script>
<script src="ext/jquery/jquery-1.7.1.min.js"></script>
<script src="ext/google-diff-match-patch/diff_match_patch.js"></script>
<script src="gcc.js"></script>
<script type="text/javascript">
$(function() {
cppEditor = CodeMirror.fromTextArea($("#c")[0], {
lineNumbers: true,
matchBrackets: true,
useCPP: true,
mode: "text/x-c++src",
onChange: onChange
});
asmCodeMirror = CodeMirror.fromTextArea($(".asm textarea")[0], {
lineNumbers: true,
matchBrackets: true,
mode: "text/x-asm",
readOnly: true
});
$('form').submit(function() { return false; });
$('.compiler').change(onChange);
$('.compiler_options').change(onChange).keyup(onChange);
$.getJSON("/compilers", function(results) {
$('.compiler option').remove();
$.each(results, function(index, arg) {
$('.compiler').append($('<option value="' + arg.exe + '">' + arg.version + '</option>'));
if (window.localStorage['compiler'] == arg.exe) {
$('.compiler').val(arg.exe);
}
});
onChange();
});
$('.files .source').change(onSourceChange);
$.getJSON("/sources", function(results) {
$('.source option').remove();
$.each(results, function(index, arg) {
$('.files .source').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>'));
if (window.localStorage['source'] == arg.urlpart) {
$('.files .source').val(arg.urlpart);
}
});
onSourceChange();
});