mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 10:33:59 -05:00
Add support for Ruby (#2816)
This commit is contained in:
3
.github/labeler.yml
vendored
3
.github/labeler.yml
vendored
@@ -74,6 +74,9 @@ lang-pascal:
|
|||||||
lang-python:
|
lang-python:
|
||||||
- lib/compilers/python.js
|
- lib/compilers/python.js
|
||||||
- etc/config/python.*.properties
|
- etc/config/python.*.properties
|
||||||
|
lang-ruby:
|
||||||
|
- lib/compilers/ruby.js
|
||||||
|
- etc/config/ruby.*.properties
|
||||||
lang-rust:
|
lang-rust:
|
||||||
- lib/compilers/rust.js
|
- lib/compilers/rust.js
|
||||||
- etc/config/rust.*.properties
|
- etc/config/rust.*.properties
|
||||||
|
|||||||
17
etc/config/ruby.amazon.properties
Normal file
17
etc/config/ruby.amazon.properties
Normal 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
|
||||||
6
etc/config/ruby.defaults.properties
Normal file
6
etc/config/ruby.defaults.properties
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
compilers=/usr/bin/ruby
|
||||||
|
supportsBinary=false
|
||||||
|
supportsExecute=true
|
||||||
|
interpreted=true
|
||||||
|
compilerType=ruby
|
||||||
|
disasmScript=
|
||||||
38
etc/scripts/ruby/disasm.rb
Normal file
38
etc/scripts/ruby/disasm.rb
Normal 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
4
examples/ruby/default.rb
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Type your code here, or load an example.
|
||||||
|
def square(num)
|
||||||
|
num * num
|
||||||
|
end
|
||||||
@@ -61,6 +61,7 @@ export { PascalWinCompiler } from './pascal-win';
|
|||||||
export { PPCICompiler } from './ppci';
|
export { PPCICompiler } from './ppci';
|
||||||
export { PtxAssembler } from './ptxas';
|
export { PtxAssembler } from './ptxas';
|
||||||
export { PythonCompiler } from './python';
|
export { PythonCompiler } from './python';
|
||||||
|
export { RubyCompiler } from './ruby';
|
||||||
export { RustCompiler } from './rust';
|
export { RustCompiler } from './rust';
|
||||||
export { RustcCgGCCCompiler } from './rustc-cg-gcc';
|
export { RustcCgGCCCompiler } from './rustc-cg-gcc';
|
||||||
export { MrustcCompiler } from './mrustc';
|
export { MrustcCompiler } from './mrustc';
|
||||||
|
|||||||
95
lib/compilers/ruby.js
Normal file
95
lib/compilers/ruby.js
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -235,6 +235,13 @@ export const languages = {
|
|||||||
alias: [],
|
alias: [],
|
||||||
previewFilter: /^\s*#include/,
|
previewFilter: /^\s*#include/,
|
||||||
},
|
},
|
||||||
|
ruby: {
|
||||||
|
name: 'Ruby',
|
||||||
|
monaco: 'ruby',
|
||||||
|
extensions: ['.rb'],
|
||||||
|
alias: [],
|
||||||
|
monacoDisassembly: 'asmruby',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
_.each(languages, (lang, key) => {
|
_.each(languages, (lang, key) => {
|
||||||
|
|||||||
59
static/modes/asmruby-mode.js
Normal file
59
static/modes/asmruby-mode.js
Normal 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;
|
||||||
@@ -44,6 +44,7 @@ var CompilerPicker = require('../compiler-picker');
|
|||||||
var Settings = require('../settings');
|
var Settings = require('../settings');
|
||||||
|
|
||||||
require('../modes/asm-mode');
|
require('../modes/asm-mode');
|
||||||
|
require('../modes/asmruby-mode');
|
||||||
require('../modes/ptx-mode');
|
require('../modes/ptx-mode');
|
||||||
|
|
||||||
var OpcodeCache = new LruCache({
|
var OpcodeCache = new LruCache({
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const staticPath = path.join(distPath, 'static');
|
|||||||
const webjackJsHack = '.v4.';
|
const webjackJsHack = '.v4.';
|
||||||
const plugins = [
|
const plugins = [
|
||||||
new MonacoEditorWebpackPlugin({
|
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`,
|
filename: isDev ? '[name].worker.js' : `[name]${webjackJsHack}worker.[contenthash].js`,
|
||||||
}),
|
}),
|
||||||
new CopyWebpackPlugin([
|
new CopyWebpackPlugin([
|
||||||
|
|||||||
Reference in New Issue
Block a user