aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Quist <partouf@gmail.com>2022-05-22 03:04:37 +0200
committerGitHub <noreply@github.com>2022-05-22 03:04:37 +0200
commita4cd29794381a71a0542886413405db2620e65f5 (patch)
treef0ac07f73d42759a65d03204fa4cabc2ff7943f8
parentbaceaf2d3315f9ed433b5274ac73d986c751096f (diff)
downloadcompiler-explorer-a4cd29794381a71a0542886413405db2620e65f5.tar.gz
compiler-explorer-a4cd29794381a71a0542886413405db2620e65f5.zip
Beeb (#3679)gh-3045
-rw-r--r--etc/config/assembly.amazon.properties14
-rw-r--r--lib/compilers/beebasm.ts (renamed from lib/compilers/beebasm.js)46
-rw-r--r--lib/languages.js2
-rw-r--r--lib/parsers/asm-parser-beebasm.js54
-rw-r--r--static/.eslint-ce-static.yml2
-rw-r--r--static/alert.interfaces.ts4
-rw-r--r--static/alert.ts2
-rw-r--r--static/panes/compiler.js48
-rw-r--r--views/popups.pug6
9 files changed, 170 insertions, 8 deletions
diff --git a/etc/config/assembly.amazon.properties b/etc/config/assembly.amazon.properties
index 268d9c7dc..a67f85bc5 100644
--- a/etc/config/assembly.amazon.properties
+++ b/etc/config/assembly.amazon.properties
@@ -1,4 +1,4 @@
-compilers=&nasm:&gnuas:&llvmas:&ptxas:&gnuasarm:&gnuasarm64
+compilers=&nasm:&gnuas:&llvmas:&ptxas:&gnuasarm:&gnuasarm64:&beebasm
compilerType=assembly
objdumper=/opt/compiler-explorer/gcc-12.1.0/bin/objdump
supportsBinary=true
@@ -250,6 +250,18 @@ compiler.ptxasnvcc115.objdumper=/opt/compiler-explorer/cuda/11.5.0/bin/nvdisasm
compiler.ptxasnvcc115.semver=11.5.0
compiler.ptxasnvcc115.exe=/opt/compiler-explorer/cuda/11.5.0/bin/ptxas
+group.beebasm.compilers=beebasm109
+group.beebasm.versionFlag=--help
+group.beebasm.options=
+group.beebasm.isSemVer=true
+group.beebasm.baseName=BeebAsm
+group.beebasm.compilerType=beebasm
+group.beebasm.supportsBinary=false
+group.beebasm.instructionSet=6502
+
+compiler.beebasm109.semver=1.09
+compiler.beebasm109.exe=/opt/compiler-explorer/beebasm-1.09/beebasm
+
#################################
#################################
# Installed tools
diff --git a/lib/compilers/beebasm.js b/lib/compilers/beebasm.ts
index f4b528560..720a22914 100644
--- a/lib/compilers/beebasm.js
+++ b/lib/compilers/beebasm.ts
@@ -26,22 +26,31 @@ import path from 'path';
import fs from 'fs-extra';
+/// <reference types="../base-compiler" />
import {BaseCompiler} from '../base-compiler';
+import {AsmParserBeebAsm} from '../parsers/asm-parser-beebasm';
+import * as utils from '../utils';
export class BeebAsmCompiler extends BaseCompiler {
static get key() {
return 'beebasm';
}
- optionsForFilter() {
+ constructor(compilerInfo, env) {
+ super(compilerInfo, env);
+
+ this.asm = new AsmParserBeebAsm(this.compilerProps);
+ }
+
+ override optionsForFilter() {
return ['-v', '-do', 'disk.ssd'];
}
- getSharedLibraryPathsAsArguments() {
+ override getSharedLibraryPathsAsArguments() {
return [];
}
- async runCompiler(compiler, options, inputFilename, execOptions) {
+ override async runCompiler(compiler, options, inputFilename, execOptions) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
}
@@ -53,17 +62,46 @@ export class BeebAsmCompiler extends BaseCompiler {
options.splice(-1, 0, '-i');
+ const hasBootOption = options.some(opt => opt.includes('-boot'));
+
const result = await this.exec(compiler, options, execOptions);
result.inputFilename = inputFilename;
const transformedInput = result.filenameTransform(inputFilename);
- if (result.code === 0 && options.includes('-v')) {
+ if (result.stdout.length > 0) {
const outputFilename = this.getOutputFilename(dirPath, this.outputFilebase);
fs.writeFileSync(outputFilename, result.stdout);
+ result.stdout = '';
+ }
+
+ if (result.code === 0 && options.includes('-v')) {
+ const diskfile = path.join(dirPath, 'disk.ssd');
+ if (await utils.fileExists(diskfile)) {
+ const file_buffer = await fs.readFile(diskfile);
+ const binary_base64 = file_buffer.toString('base64');
+ result.bbcdiskimage = binary_base64;
+
+ if (!hasBootOption) {
+ if (!result.hints) result.hints = [];
+ result.hints.push(
+ 'Try using the "-boot <filename>" option so you don\'t have to manually run your file',
+ );
+ }
+ }
}
this.parseCompilationOutput(result, transformedInput);
+ const hasNoSaveError = result.stderr.some(opt => opt.text.includes('warning: no SAVE command in source file'));
+ if (hasNoSaveError) {
+ if (!result.hints) result.hints = [];
+ result.hints.push(
+ 'You should SAVE your code to a file using\nSAVE "filename", start, end [, exec [, reload] ]',
+ );
+ }
+
+ result.forceBinaryView = true;
+
return result;
}
}
diff --git a/lib/languages.js b/lib/languages.js
index 7fc62af89..2ccefd90e 100644
--- a/lib/languages.js
+++ b/lib/languages.js
@@ -219,7 +219,7 @@ export const languages = {
assembly: {
name: 'Assembly',
monaco: 'asm',
- extensions: ['.asm'],
+ extensions: ['.asm', '.6502'],
alias: ['asm'],
logoUrl: 'assembly.png', // TODO: Find a better alternative
},
diff --git a/lib/parsers/asm-parser-beebasm.js b/lib/parsers/asm-parser-beebasm.js
new file mode 100644
index 000000000..6188c02c3
--- /dev/null
+++ b/lib/parsers/asm-parser-beebasm.js
@@ -0,0 +1,54 @@
+import * as utils from '../utils';
+
+import {AsmParser} from './asm-parser';
+
+export class AsmParserBeebAsm extends AsmParser {
+ constructor(compilerProps) {
+ super(compilerProps);
+
+ this.labelDef = /^(\.\w+)/i;
+ this.asmOpcodeRe = /^\s*(?<address>[\dA-F]+)\s*(?<opcodes>([\dA-F]{2} ?)+)\s*(?<disasm>.*)/;
+ }
+
+ processAsm(asm, filters) {
+ const startTime = process.hrtime.bigint();
+
+ const asmLines = [];
+ const labelDefinitions = {};
+
+ let startingLineCount = 0;
+
+ utils.eachLine(asm, line => {
+ startingLineCount++;
+
+ const labelMatch = line.match(this.labelDef);
+ if (labelMatch) {
+ asmLines.push({
+ text: line,
+ });
+ labelDefinitions[labelMatch[1]] = asmLines.length;
+ return;
+ }
+
+ const addressAndInstructionMatch = line.match(this.asmOpcodeRe);
+ if (addressAndInstructionMatch) {
+ const opcodes = (addressAndInstructionMatch.groups.opcodes || '').split(' ').filter(x => !!x);
+ const address = parseInt(addressAndInstructionMatch.groups.address, 16);
+ asmLines.push({
+ address: address,
+ opcodes: opcodes,
+ text: ' ' + addressAndInstructionMatch.groups.disasm,
+ });
+ }
+ });
+
+ const endTime = process.hrtime.bigint();
+
+ return {
+ asm: asmLines,
+ labelDefinitions: labelDefinitions,
+ parsingTime: ((endTime - startTime) / BigInt(1000000)).toString(),
+ filteredCount: startingLineCount - asm.length,
+ };
+ }
+}
diff --git a/static/.eslint-ce-static.yml b/static/.eslint-ce-static.yml
index 4a4c1f594..ef96bb6d6 100644
--- a/static/.eslint-ce-static.yml
+++ b/static/.eslint-ce-static.yml
@@ -80,7 +80,7 @@ rules:
sonarjs/prefer-single-boolean-return: error
unicorn/filename-case: error
parserOptions:
- ecmaVersion: 5
+ ecmaVersion: 6
globals:
define: false
__webpack_public_path__: true
diff --git a/static/alert.interfaces.ts b/static/alert.interfaces.ts
index e23beaf81..6b842090f 100644
--- a/static/alert.interfaces.ts
+++ b/static/alert.interfaces.ts
@@ -71,4 +71,8 @@ export interface AlertNotifyOptions {
* Default: 5000
*/
dismissTime?: number;
+ /**
+ * onLoadHandler(element)
+ */
+ onBeforeShow?: (any) => void;
}
diff --git a/static/alert.ts b/static/alert.ts
index 6c63c73c7..14ed2ec1c 100644
--- a/static/alert.ts
+++ b/static/alert.ts
@@ -92,6 +92,7 @@ export class Alert {
alertClass = '',
autoDismiss = true,
dismissTime = 5000,
+ onBeforeShow = () => {},
}: AlertNotifyOptions
) {
const container = $('#notifications');
@@ -122,6 +123,7 @@ export class Alert {
}
newElement.attr('data-group', group);
}
+ onBeforeShow(newElement);
newElement.toast('show');
}
diff --git a/static/panes/compiler.js b/static/panes/compiler.js
index 820392d52..1d5dad767 100644
--- a/static/panes/compiler.js
+++ b/static/panes/compiler.js
@@ -1184,7 +1184,7 @@ Compiler.prototype.setAssembly = function (result, filteredCount) {
this.updateDecorations();
var codeLenses = [];
- if (this.getEffectiveFilters().binary) {
+ if (this.getEffectiveFilters().binary || result.forceBinaryView) {
this.setBinaryMargin();
_.each(
this.assembly,
@@ -1365,6 +1365,35 @@ Compiler.prototype.postCompilationResult = function (request, result) {
this.checkForUnwiseArguments(result.compilationOptions);
this.setCompilationOptionsPopover(result.compilationOptions ? result.compilationOptions.join(' ') : '');
+
+ this.checkForHints(result);
+
+ if (result.bbcdiskimage) {
+ this.emulateBbcDisk(result.bbcdiskimage);
+ }
+};
+
+Compiler.prototype.emulateBbcDisk = function (bbcdiskimage) {
+ var dialog = $('#jsbeebemu');
+
+ this.alertSystem.notify(
+ 'Click <a target="_blank" id="emulink" style="cursor:pointer;" click="javascript:;">here</a> to emulate',
+ {
+ group: 'emulation',
+ collapseSimilar: true,
+ dismissTime: 10000,
+ onBeforeShow: function (elem) {
+ elem.find('#emulink').on('click', function () {
+ dialog.modal();
+
+ var emuwindow = dialog.find('#jsbeebemuframe')[0].contentWindow;
+ var tmstr = Date.now();
+ emuwindow.location =
+ 'https://bbc.godbolt.org/?' + tmstr + '#embed&autoboot&disc1=b64data:' + bbcdiskimage;
+ });
+ },
+ }
+ );
};
Compiler.prototype.onEditorChange = function (editor, source, langId, compilerId) {
@@ -2332,6 +2361,23 @@ Compiler.prototype.onOptionsChange = function (options) {
}
};
+function htmlEncode(rawStr) {
+ return rawStr.replace(/[\u00A0-\u9999<>&]/g, function (i) {
+ return '&#' + i.charCodeAt(0) + ';';
+ });
+}
+
+Compiler.prototype.checkForHints = function (result) {
+ if (result.hints) {
+ result.hints.forEach(hint => {
+ this.alertSystem.notify(htmlEncode(hint), {
+ group: 'hints',
+ collapseSimilar: false,
+ });
+ });
+ }
+};
+
Compiler.prototype.checkForUnwiseArguments = function (optionsArray) {
// Check if any options are in the unwiseOptions array and remember them
var unwiseOptions = _.intersection(
diff --git a/views/popups.pug b/views/popups.pug
index 1a89dd719..041dec103 100644
--- a/views/popups.pug
+++ b/views/popups.pug
@@ -393,3 +393,9 @@
#chart
.modal-footer
button.btn.btn-outline-primary(type="button" data-dismiss="modal") Close
+
+#jsbeebemu.modal.fade.gl_keep(tabindex="-1" role="dialog")
+ .modal-dialog.modal-xl
+ .modal-content
+ .modal-body
+ iframe#jsbeebemuframe(src="about:blank" width="1280" height="768")