Merge branch 'goldenlayout' of github.com:mattgodbolt/gcc-explorer into goldenlayout

dev/git-series/gccdum
Matt Godbolt 7 years ago
commit 5fbb22501f

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value />
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</component>
</project>

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$" libraries="{gcc-explorer/node_modules}" />
<file url="file://$PROJECT_DIR$/static/ext/golden-layout" libraries="{gcc-explorer/static/ext/golden-layout/node_modules}" />
<includedPredefinedLibrary name="Node.js Core" />
</component>
</project>

@ -1,15 +0,0 @@
<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>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -144,6 +144,7 @@ function clientOptionsHandler(compilers, fileSources) {
defaultCompiler: compilerProps('defaultCompiler', ''),
compileOptions: compilerProps("options"),
supportsBinary: !!compilerProps("supportsBinary"),
postProcess: compilerProps("postProcess"),
sources: sources
};
var text = JSON.stringify(options);
@ -282,7 +283,8 @@ function configuredCompilers() {
is6g: !!props("is6g", false),
intelAsm: props("intelAsm", ""),
needsMulti: !!props("needsMulti", true),
supportsBinary: !!props("supportsBinary", true)
supportsBinary: !!props("supportsBinary", true),
postProcess: props("postProcess", "")
});
}));
}

@ -19,7 +19,7 @@
"codemirror": "CodeMirror#^5.17.0",
"requirejs": "^2.2.0",
"underscore": "^1.8.3",
"golden-layout": "^1.5.1",
"golden-layout": "^1.5.5",
"jquery": "^3.1.0",
"bootstrap": "^3.3.7",
"selectize": "^0.12.2",

@ -23,6 +23,7 @@
// POSSIBILITY OF SUCH DAMAGE.
(function () {
var _ = require('underscore-node');
var tabsRe = /\t/g;
function expandTabs(line) {
@ -35,35 +36,91 @@
});
}
function processAsm(asm, filters) {
if (filters.binary) return processBinaryAsm(asm, filters);
var labelFind = /[.a-zA-Z_][a-zA-Z0-9$_.]*/g;
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-Z$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
var labelDef = /^([.a-zA-Z_][a-zA-Z0-9$_.]+):/;
var hasOpcode = /^\s*([a-zA-Z$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
var result = [];
var asmLines = asm.split("\n");
function findUsedLabels(asmLines, filterDirectives) {
var labelsUsed = {};
var labelFind = /[.a-zA-Z0-9_][a-zA-Z0-9$_.]*/g;
var files = {};
var prevLabel = "";
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].*/;
var weakUsages = {};
var currentLabel = "";
// Scan through looking for definite label usages (ones used by opcodes),
// and ones that are weakly used: that is, their use is conditional on another label.
// For example:
// .foo: .string "moo"
// .baz: .quad .foo
// mov eax, .baz
// In this case, the '.baz' is used by an opcode, and so is strongly used.
// The '.foo' is weakly used by .baz.
asmLines.forEach(function (line) {
if (line === "" || line[0] === ".") return;
var match = line.match(labelFind);
if (match && (!filters.directives || line.match(hasOpcode))) {
var match = line.match(labelDef);
if (match)
currentLabel = match[1];
if (!line || line[0] === '.') return;
match = line.match(labelFind);
if (!match) return;
if (!filterDirectives || 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;
});
} else if (currentLabel) {
// Note any "weak" usages by this label; that is, usages that are only
// interesting if the currentLabel is used by an opcode.
if (!weakUsages[currentLabel]) weakUsages[currentLabel] = [];
match.forEach(function (label) {
weakUsages[currentLabel].push(label);
});
}
match = line.match(fileFind);
});
// Now follow the chains of used labels, marking any weak references they refer
// to as also used. We iteratively do this until either no new labels are found,
// or we hit a limit (only here to prevent a pathological case from hanging).
var MaxLabelIterations = 10;
for (var iter = 0; iter < MaxLabelIterations; ++iter) {
var toAdd = [];
_.each(labelsUsed, function (t, label) {
_.each(weakUsages[label], function (nowused) {
if (labelsUsed[nowused]) return;
toAdd.push(nowused);
});
});
if (!toAdd) break;
_.each(toAdd, function (label) {
labelsUsed[label] = true;
});
}
return labelsUsed;
}
function parseFiles(asmLines) {
var files = {};
asmLines.forEach(function (line) {
var match = line.match(fileFind);
if (match) {
files[parseInt(match[1])] = match[2];
}
});
return files;
}
function processAsm(asm, filters) {
if (filters.binary) return processBinaryAsm(asm, filters);
var result = [];
var asmLines = asm.split("\n");
var labelsUsed = findUsedLabels(asmLines, filters.directives);
var files = parseFiles(asmLines);
var prevLabel = "";
var directive = /^\s*\..*$/;
var labelDefinition = /^([a-zA-Z0-9$_.]+):/;
var commentOnly = /^\s*(#|@|\/\/).*/;
var sourceTag = /^\s*\.loc\s+(\d+)\s+(\d+).*/;
var stdInLooking = /.*<stdin>|-/;
@ -89,7 +146,7 @@
if (filters.commentOnly && line.match(commentOnly)) return;
match = line.match(labelDefinition);
match = line.match(labelDef);
if (match) {
// It's a label definition.
if (labelsUsed[match[1]] === undefined) {

@ -254,7 +254,10 @@ Compile.prototype.compile = function (source, compiler, options, filters) {
var compileToAsmPromise = tempFileAndDirPromise.then(function (info) {
var inputFilename = info.inputFilename;
var dirPath = info.dirPath;
var postProcess = compilerProps("postProcess");
var postProcess = [compilerProps("postProcess"), compilerInfo.postProcess];
postProcess = postProcess.filter(function (x) {
return x;
});
var outputFilename = path.join(dirPath, 'output.S');
if (compilerInfo.options) {
options = options.concat(compilerInfo.options.split(" "));
@ -296,9 +299,9 @@ Compile.prototype.compile = function (source, compiler, options, filters) {
result.asm = "<No output: generated assembly was too large (" + stat.size + " > " + maxSize + " bytes)>";
return result;
}
if (postProcess) {
if (postProcess.length) {
return new Promise(function (resolve) {
child_process.exec('cat "' + outputFilename + '" | ' + postProcess,
child_process.exec('cat "' + outputFilename + '" | ' + postProcess.join(" | "),
{maxBuffer: maxSize},
function (err, data) {
if (err)

@ -28,7 +28,8 @@
"nopt": "3.0.x",
"serve-favicon": "2.3.x",
"serve-static": "1.10.x",
"temp": "0.8.x"
"temp": "0.8.x",
"underscore-node": "*"
},
"devDependencies": {
"supervisor": "0.3.1",

@ -31,6 +31,7 @@ define(function (require) {
var ga = require('analytics').ga;
var colour = require('colour');
var Toggles = require('toggles');
var FontScale = require('fontscale');
require('asm-mode');
require('selectize');
@ -56,14 +57,13 @@ define(function (require) {
this.debouncedAjax = _.debounce($.ajax, 250);
this.domRoot.find(".compiler").selectize({
this.domRoot.find(".compiler-picker").selectize({
sortField: 'name',
valueField: 'id',
labelField: 'name',
searchField: ['name'],
options: compilers,
items: this.compiler ? [this.compiler.id] : [],
openOnFocus: true
items: this.compiler ? [this.compiler.id] : []
}).on('change', function () {
self.onCompilerChange($(this).val());
});
@ -87,11 +87,18 @@ define(function (require) {
});
this.outputEditor = outputEditor;
this.fontScale = new FontScale(this.domRoot, state);
this.fontScale.on('change', _.bind(this.saveState, this));
function refresh() {
outputEditor.refresh();
}
function resize() {
var topBarHeight = self.domRoot.find(".top-bar").outerHeight(true);
var bottomBarHeight = self.domRoot.find(".bottom-bar").outerHeight(true);
outputEditor.setSize(self.domRoot.width(), self.domRoot.height() - topBarHeight - bottomBarHeight);
outputEditor.refresh();
refresh();
}
this.filters.on('change', _.bind(this.onFilterChange, this));
@ -101,6 +108,7 @@ define(function (require) {
self.eventHub.emit('compilerClose', self.id);
}, this);
container.on('resize', resize);
container.on('shown', refresh);
container.on('open', function () {
self.eventHub.emit('compilerOpen', self.id);
});
@ -297,12 +305,14 @@ define(function (require) {
};
Compiler.prototype.saveState = function () {
this.container.setState({
var state = {
compiler: this.compiler ? this.compiler.id : "",
options: this.options,
source: this.editor,
filters: this.filters.get() // NB must *not* be effective filters
});
};
this.fontScale.addState(state);
this.container.setState(state);
};
Compiler.prototype.onColours = function (editor, colours) {

@ -31,6 +31,7 @@ define(function (require) {
var Toggles = require('toggles');
var compiler = require('compiler');
var loadSaveLib = require('loadSave');
var FontScale = require('fontscale');
require('codemirror/mode/clike/clike');
require('codemirror/mode/d/d');
@ -78,6 +79,9 @@ define(function (require) {
mode: cmMode
});
this.fontScale = new FontScale(this.domRoot, state);
this.fontScale.on('change', _.bind(this.updateState, this));
if (state.source) {
this.editor.setValue(state.source);
} else if (defaultSrc) {
@ -120,20 +124,26 @@ define(function (require) {
self.updateColours(colours);
}, ColourDebounceMs);
function refresh() {
self.editor.refresh();
}
function resize() {
var topBarHeight = self.domRoot.find(".top-bar").outerHeight(true);
self.editor.setSize(self.domRoot.width(), self.domRoot.height() - topBarHeight);
self.editor.refresh();
refresh();
}
this.domRoot.find('.load-save').click(_.bind(function () {
loadSave.run(_.bind(function (text) {
this.editor.setValue(text);
this.updateState();
this.maybeEmitChange();
}, this));
}, this));
container.on('resize', resize);
container.on('shown', refresh);
container.on('open', function () {
self.eventHub.emit('editorOpen', self.id);
});
@ -152,8 +162,22 @@ define(function (require) {
this.eventHub.on('compileResult', this.onCompileResponse, this);
var compilerConfig = compiler.getComponent(this.id);
function findParentRowOrColumn(elem) {
while (elem) {
if (elem.isRow || elem.isColumn) return elem;
elem = elem.parent;
}
return elem;
}
this.container.layoutManager.createDragSource(
this.domRoot.find('.btn.add-compiler'), compilerConfig);
this.domRoot.find('.btn.add-compiler').click(_.bind(function () {
var insertPoint = findParentRowOrColumn(this.container)
|| this.container.layoutManager.root.contentItems[0];
insertPoint.addChild(compilerConfig);
}, this));
}
Editor.prototype.maybeEmitChange = function (force) {
@ -164,11 +188,13 @@ define(function (require) {
};
Editor.prototype.updateState = function () {
this.container.setState({
var state = {
id: this.id,
source: this.getSource(),
options: this.options.get()
});
};
this.fontScale.addState(state);
this.container.setState(state);
};
Editor.prototype.getSource = function () {
@ -195,7 +221,8 @@ define(function (require) {
var clazz = "error";
if (text.match(/^warning/)) clazz = "warning";
if (text.match(/^note/)) clazz = "note";
var node = $('<div class="' + clazz + ' inline-msg"><span class="icon">!!</span><span class="compiler">: </span><span class="msg"></span></div>');
var node = $('.template .inline-msg').clone();
node.find('.icon').addClass(clazz);
node.find(".msg").text(text);
node.find(".compiler").text(compiler);
return node[0];
@ -283,6 +310,9 @@ define(function (require) {
type: 'component',
componentName: 'codeEditor',
componentState: {id: id},
// TODO: making this non closeable breaks placement
// See: https://github.com/deepstreamIO/golden-layout/issues/17
// https://github.com/deepstreamIO/golden-layout/issues/60 and others
isClosable: false
};
},
@ -295,4 +325,4 @@ define(function (require) {
};
}
};
});
});

@ -2,8 +2,8 @@
display: none;
}
.compiler {
width: 13em;
.compiler-picker {
width: 14em;
}
.CodeMirror {
@ -161,3 +161,25 @@ span.icon {
color: #0000b0;
font-weight: bold;
}
.decrease-font-size span.glyphicon {
font-size: 70%;
}
.reset-font-size span.glyphicon {
font-size: 90%;
}
.increase-font-size span.glyphicon {
font-size: 110%;
}
.lm_splitter.lm_vertical .lm_drag_handle {
height: 10px;
top: -2.5px;
}
.lm_splitter.lm_horizontal .lm_drag_handle {
width: 10px;
left: -2.5px;
}

@ -0,0 +1,67 @@
// Copyright (c) 2012-2016, 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(function (require) {
"use strict";
var _ = require('underscore');
var EventEmitter = require('events');
function FontScale(domRoot, state) {
EventEmitter.call(this);
this.domRoot = domRoot;
this.scale = state.fontScale || 1.0;
this.apply();
this.domRoot.find('.increase-font-size').click(_.bind(function () {
this.scale += 0.1;
this.apply();
this.emit('change');
}, this));
this.domRoot.find('.decrease-font-size').click(_.bind(function () {
if (this.scale <= 0.3) return;
this.scale -= 0.1;
this.apply();
this.emit('change');
}, this));
this.domRoot.find('.reset-font-size').click(_.bind(function () {
this.scale = 1.0;
this.apply();
this.emit('change');
}, this));
}
_.extend(FontScale.prototype, EventEmitter.prototype);
FontScale.prototype.apply = function () {
this.domRoot.find('.CodeMirror').css('font-size', (10 * this.scale) + "pt");
};
FontScale.prototype.addState = function (state) {
if (this.scale != 1.0)
state.fontScale = this.scale;
};
return FontScale;
});

@ -12,7 +12,6 @@
<link href="ext/selectize/dist/css/selectize.bootstrap2.css" rel="stylesheet">
<link href="explorer.css" rel="stylesheet">
<script data-main="main" src="ext/requirejs/require.js"></script>
<!--<script src="ext/clipboard.min.js"></script>x-->
</head>
<body>
@ -65,7 +64,7 @@
<div id="root"></div>
<div class="gl_keep template">
<div id="codeEditor" class="template">
<div id="codeEditor">
<div class="top-bar btn-toolbar" role="toolbar">
<div class="btn-group btn-group-sm options" role="group">
<button title="Colourise lines so one can see how the source maps to the output"
@ -82,7 +81,19 @@
class="btn btn-default btn-sm load-save">
<span class="glyphicon glyphicon-floppy-disk"></span>
</button>
<button title="Add a new compiler window (drag)"
<button title="Decrease font size"
class="btn btn-default btn-sm decrease-font-size">
<span class="glyphicon glyphicon-sm glyphicon-font"></span>
</button>
<button title="Reset font size"
class="btn btn-default btn-sm reset-font-size">
<span class="glyphicon glyphicon-sm glyphicon-font"></span>
</button>
<button title="Increase font size"
class="btn btn-default btn-sm increase-font-size">
<span class="glyphicon glyphicon-sm glyphicon-font"></span>
</button>
<button title="Add a new compiler window (click or drag)"
class="btn btn-default btn-sm add-compiler">
<span class="glyphicon glyphicon-plus"></span>
</button>
@ -91,11 +102,11 @@
<textarea>// Type your code here, or load an example.</textarea>
</div>
<div id="compiler" class="template">
<div id="compiler">
<div class="top-bar">
<table>
<tr>
<td><select class="compiler" placeholder="Select a compiler..."></select></td>
<td><select class="compiler-picker" placeholder="Select a compiler..."></select></td>
<td><input class="options form-control" type="text" placeholder="compiler options..."
size="256"></td>
</tr>
@ -123,6 +134,20 @@
<span>Intel</span>
</button>
</div>
<div class="btn-group btn-group-sm">
<button title="Decrease font size"
class="btn btn-default btn-sm decrease-font-size">
<span class="glyphicon glyphicon-sm glyphicon-font"></span>
</button>
<button title="Reset font size"
class="btn btn-default btn-sm reset-font-size">
<span class="glyphicon glyphicon-sm glyphicon-font"></span>
</button>
<button title="Increase font size"
class="btn btn-default btn-sm increase-font-size">
<span class="glyphicon glyphicon-sm glyphicon-font"></span>
</button>
</div>
</div>
<textarea>[Waiting...]</textarea>
<div class="bottom-bar">
@ -131,7 +156,7 @@
</div>
</div>
<div class="urls template">
<div class="urls">
<div class="input-group">
<input type="text"
class="form-control input-sm permalink"
@ -147,15 +172,19 @@
</div>
</div>
<div class="inline-msg">
<span class="compiler"></span><span class="icon">!!</span><span class="msg"></span>
</div>
<pre class="template lang c">// Type your code here, or load an example.
int square(int num) {
return num * num;
}</pre>
<pre class="template lang rust">// Type your code here, or load an example.
<pre class="template lang rust">// Type your code here, or load an example.
pub fn square(num: i32) -&gt; i32 {
num * num
}</pre>
<pre class="template lang go">// Type your code here, or load an example.
<pre class="template lang go">// Type your code here, or load an example.
// Your function name should start with a capital letter.
package main
@ -164,7 +193,7 @@ func Square(x int) int {
}
func main() {}</pre>
<pre class="template lang d">// Type your code here, or load an example.
<pre class="template lang d">// Type your code here, or load an example.
int square(int num) {
return num * num;
}</pre>

@ -34,7 +34,7 @@ define(function (require) {
$.getJSON('/source/builtin/list', _.bind(function (list) {
this.modal.find('.example:visible').remove();
var examples = this.modal.find('.examples');
var template = examples.find('.example.template');
var template = examples.find('.template.example');
_.each(list, _.bind(function (elem) {
template
.clone()

@ -69,7 +69,7 @@ define(function (require) {
$('.language-name').text(options.language);
var safeLang = options.language.toLowerCase().replace(/[^a-z_]+/g, '');
var defaultSrc = $('.template.lang.' + safeLang).text().trim();
var defaultSrc = $('.template .lang.' + safeLang).text().trim();
var defaultConfig = {
settings: {showPopoutIcon: false},
content: [{type: 'row', content: [editor.getComponent(1), compiler.getComponent(1)]}]
@ -112,7 +112,7 @@ define(function (require) {
new clipboard('.btn.clippy');
function initPopover(getLink, provider) {
var html = $('.urls.template').html();
var html = $('.template .urls').html();
getLink.popover({
container: 'body',

@ -0,0 +1,46 @@
.file "example.cpp"
.intel_syntax noprefix
.text
.Ltext0:
.globl s_sA
.section .rodata
.LC0:
.string "hello world!"
.data
.align 8
.type s_sA, @object
.size s_sA, 8
s_sA:
.quad .LC0
.section .rodata
.align 8
.type s_sB, @object
.size s_sB, 10
s_sB:
.string "hey there"
.text
.globl main
.type main, @function
main:
.LFB0:
.file 1 "/tmp/gcc-explorer-compiler116820-58-ewfj5u/example.cpp"
.loc 1 6 0
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
.loc 1 7 0
mov rax, QWORD PTR s_sA[rip]
mov rdi, rax
call puts
.loc 1 8 0
mov edi, OFFSET FLAT:s_sB
call puts
.loc 1 9 0
mov eax, 0
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc

@ -0,0 +1,17 @@
.LC0:
.string "hello world!"
s_sA:
.quad .LC0
s_sB:
.string "hey there"
main:
push rbp
mov rbp, rsp
mov rax, QWORD PTR s_sA[rip]
mov rdi, rax
call puts
mov edi, OFFSET FLAT:s_sB
call puts
mov eax, 0
pop rbp
ret

@ -68,7 +68,6 @@ function testFilter(filename, suffix, filters, withSource) {
assertEq(file[i], lineExpected, expected + ":" + (i + 1));
}
}
cases.forEach(function (x) {
testFilter(x, "", {})
});
@ -91,4 +90,5 @@ cases.forEach(function (x) {
if (failures) {
console.log(failures + " failures");
process.exit(1);
}

Loading…
Cancel
Save