Add support for Ruby (#2816)

This commit is contained in:
Quinton Miller
2021-07-31 04:29:37 +08:00
committed by GitHub
parent 678adac15b
commit 7e1835fa0f
11 changed files with 232 additions and 1 deletions

3
.github/labeler.yml vendored
View File

@@ -74,6 +74,9 @@ lang-pascal:
lang-python:
- lib/compilers/python.js
- etc/config/python.*.properties
lang-ruby:
- lib/compilers/ruby.js
- etc/config/ruby.*.properties
lang-rust:
- lib/compilers/rust.js
- etc/config/rust.*.properties

View File

@@ -0,0 +1,17 @@
compilers=&ruby
defaultCompiler=ruby302
group.ruby.compilers=ruby302:ruby274:ruby268:ruby259
group.ruby.isSemVer=true
group.ruby.baseName=Ruby
group.ruby.groupName=Ruby YARV
group.ruby.compilerType=ruby
compiler.ruby302.semver=3.0.2
compiler.ruby302.exe=/opt/compiler-explorer/ruby-3.0.2/bin/ruby
compiler.ruby274.semver=2.7.4
compiler.ruby274.exe=/opt/compiler-explorer/ruby-2.7.4/bin/ruby
compiler.ruby268.semver=2.6.8
compiler.ruby268.exe=/opt/compiler-explorer/ruby-2.6.8/bin/ruby
compiler.ruby259.semver=2.5.9
compiler.ruby259.exe=/opt/compiler-explorer/ruby-2.5.9/bin/ruby

View File

@@ -0,0 +1,6 @@
compilers=/usr/bin/ruby
supportsBinary=false
supportsExecute=true
interpreted=true
compilerType=ruby
disasmScript=

View File

@@ -0,0 +1,38 @@
# Copyright (c) 2021, Compiler Explorer Authors
# 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.
require 'optparse'
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: disasm.rb [options]"
opts.on("-i", "--inputfile FILE", "Use FILE as input") { |v| options[:inputfile] = v }
opts.on("-o", "--outputfile FILE", "Use FILE as output") { |v| options[:outputfile] = v }
opts.on("-n", "--fname NAME", "Use NAME as input file name") { |v| options[:fname] = v }
end.parse!
src = File.read(options[:inputfile])
insns = RubyVM::InstructionSequence.compile(src, options[:fname] || options[:inputfile], options[:inputfile], 1)
File.write(options[:outputfile], insns.disassemble)

4
examples/ruby/default.rb Normal file
View File

@@ -0,0 +1,4 @@
# Type your code here, or load an example.
def square(num)
num * num
end

View File

@@ -61,6 +61,7 @@ export { PascalWinCompiler } from './pascal-win';
export { PPCICompiler } from './ppci';
export { PtxAssembler } from './ptxas';
export { PythonCompiler } from './python';
export { RubyCompiler } from './ruby';
export { RustCompiler } from './rust';
export { RustcCgGCCCompiler } from './rustc-cg-gcc';
export { MrustcCompiler } from './mrustc';

95
lib/compilers/ruby.js Normal file
View File

@@ -0,0 +1,95 @@
// Copyright (c) 2021, Compiler Explorer Authors
// 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.
import path from 'path';
import { BaseCompiler } from '../base-compiler';
import { resolvePathFromAppRoot } from '../utils';
import { BaseParser } from './argument-parsers';
export class RubyCompiler extends BaseCompiler {
static get key() { return 'ruby'; }
constructor(compilerInfo, env) {
super(compilerInfo, env);
this.compiler.demangler = null;
this.demanglerClass = null;
}
processAsm(result, filters) {
const lineRe = /\(\s*(\d+)\)(?:\[[^\]]+\])?$/;
const fileRe = /ISeq:.*?@(.*?):(\d+) /;
const baseFile = path.basename(this.compileFilename);
const bytecodeLines = result.asm.split('\n');
const bytecodeResult = [];
let lastFile = null;
let lastLineNo = null;
for (const line of bytecodeLines) {
const match = line.match(lineRe);
if (match) {
lastLineNo = parseInt(match[1]);
} else if (!line) {
lastFile = null;
lastLineNo = null;
} else {
const fileMatch = line.match(fileRe);
if (fileMatch) {
lastFile = fileMatch[1];
lastLineNo = parseInt(fileMatch[2]);
}
}
const file = lastFile == baseFile ? null : lastFile;
const result = {text: line, source: {line: lastLineNo, file: file}};
bytecodeResult.push(result);
}
return {asm: bytecodeResult};
}
getDisasmScriptPath() {
const script = this.compilerProps('disasmScript');
return script || resolvePathFromAppRoot('etc', 'scripts', 'ruby', 'disasm.rb');
}
optionsForFilter(filters, outputFilename) {
return [
this.getDisasmScriptPath(),
'--outputfile',
outputFilename,
'--fname',
path.basename(this.compileFilename),
'--inputfile'];
}
getArgumentParser() {
return BaseParser;
}
}

View File

@@ -235,6 +235,13 @@ export const languages = {
alias: [],
previewFilter: /^\s*#include/,
},
ruby: {
name: 'Ruby',
monaco: 'ruby',
extensions: ['.rb'],
alias: [],
monacoDisassembly: 'asmruby',
},
};
_.each(languages, (lang, key) => {

View File

@@ -0,0 +1,59 @@
// Copyright (c) 2021, Compiler Explorer Authors
// 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.
'use strict';
var monaco = require('monaco-editor');
function definition() {
return {
tokenizer: {
root: [
[/^(\| )*==.*$/, 'comment'],
[/^(\| )*catch type.*$/, 'comment'],
[/^(\| )*local table.*$/, 'comment'],
[/^(\| )*\[\s*\d+\].*$/, 'comment'],
[/^(\| )*\|-+$/, 'comment'],
[/^((?:\| )*)(\d+)/, ['comment', { token: 'number', next: '@opcode' }]],
[/^((?:\| )*)(\d+)(\s+)/, ['comment', 'number', { token: '', next: '@opcode' }]],
],
opcode: [
[/[a-z_]\w*\s*$/, { token: 'keyword', next: '@root' }],
[/([a-z_]\w*)(\s+)/, ['keyword', { token: '', next: '@arguments' }]],
],
arguments: [
[/(.*?)(\(\s*\d+\)(?:\[[^\]]+\])?)$/, ['', { token: 'comment', next: '@root' }]],
[/.*$/, { token: '', next: '@root' }],
],
},
};
}
var def = definition();
monaco.languages.register({ id: 'asmruby' });
monaco.languages.setMonarchTokensProvider('asmruby', def);
module.exports = def;

View File

@@ -44,6 +44,7 @@ var CompilerPicker = require('../compiler-picker');
var Settings = require('../settings');
require('../modes/asm-mode');
require('../modes/asmruby-mode');
require('../modes/ptx-mode');
var OpcodeCache = new LruCache({

View File

@@ -46,7 +46,7 @@ const staticPath = path.join(distPath, 'static');
const webjackJsHack = '.v4.';
const plugins = [
new MonacoEditorWebpackPlugin({
languages: [ 'cpp', 'go', 'pascal', 'python', 'rust', 'swift', 'java', 'kotlin', 'scala' ],
languages: [ 'cpp', 'go', 'pascal', 'python', 'rust', 'swift', 'java', 'kotlin', 'scala', 'ruby' ],
filename: isDev ? '[name].worker.js' : `[name]${webjackJsHack}worker.[contenthash].js`,
}),
new CopyWebpackPlugin([