diff options
author | Patrick Quist <partouf@gmail.com> | 2022-05-22 03:04:37 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-22 03:04:37 +0200 |
commit | a4cd29794381a71a0542886413405db2620e65f5 (patch) | |
tree | f0ac07f73d42759a65d03204fa4cabc2ff7943f8 | |
parent | baceaf2d3315f9ed433b5274ac73d986c751096f (diff) | |
download | compiler-explorer-a4cd29794381a71a0542886413405db2620e65f5.tar.gz compiler-explorer-a4cd29794381a71a0542886413405db2620e65f5.zip |
Beeb (#3679)gh-3045
-rw-r--r-- | etc/config/assembly.amazon.properties | 14 | ||||
-rw-r--r-- | lib/compilers/beebasm.ts (renamed from lib/compilers/beebasm.js) | 46 | ||||
-rw-r--r-- | lib/languages.js | 2 | ||||
-rw-r--r-- | lib/parsers/asm-parser-beebasm.js | 54 | ||||
-rw-r--r-- | static/.eslint-ce-static.yml | 2 | ||||
-rw-r--r-- | static/alert.interfaces.ts | 4 | ||||
-rw-r--r-- | static/alert.ts | 2 | ||||
-rw-r--r-- | static/panes/compiler.js | 48 | ||||
-rw-r--r-- | views/popups.pug | 6 |
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") |