Include generated Opcode enum in the immediates module.

Generate nice doc comments for the Opcode enum variants that 'cargo doc'
will pick up.

Include a `Display` trait implementation that prints the lower
snake-case version of the opcode name.
This commit is contained in:
Jakob Stoklund Olesen
2016-04-06 14:55:21 -07:00
parent eba396546a
commit ee09a39aef
3 changed files with 86 additions and 11 deletions

View File

@@ -8,6 +8,9 @@
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::mem; use std::mem;
// The `Opcode` enum is generated from the meta instruction descriptions.
include!(concat!(env!("OUT_DIR"), "/opcodes.rs"));
/// 64-bit immediate integer operand. /// 64-bit immediate integer operand.
/// ///
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -41,11 +44,13 @@ impl Display for Imm64 {
/// An IEEE binary32 immediate floating point value. /// An IEEE binary32 immediate floating point value.
/// ///
/// All bit patterns are allowed. /// All bit patterns are allowed.
#[derive(Copy, Clone, Debug)]
pub struct Ieee32(f32); pub struct Ieee32(f32);
/// An IEEE binary64 immediate floating point value. /// An IEEE binary64 immediate floating point value.
/// ///
/// All bit patterns are allowed. /// All bit patterns are allowed.
#[derive(Copy, Clone, Debug)]
pub struct Ieee64(f64); pub struct Ieee64(f64);
// Format a floating point number in a way that is reasonably human-readable, and that can be // Format a floating point number in a way that is reasonably human-readable, and that can be
@@ -155,6 +160,19 @@ mod tests {
use super::*; use super::*;
use std::{f32, f64}; use std::{f32, f64};
#[test]
fn opcodes() {
let x = Opcode::Iadd;
let mut y = Opcode::Isub;
assert!(x != y);
y = Opcode::Iadd;
assert_eq!(x, y);
assert_eq!(format!("{:?}", Opcode::IaddImm), "IaddImm");
assert_eq!(format!("{}", Opcode::IaddImm), "iadd_imm");
}
#[test] #[test]
fn format_imm64() { fn format_imm64() {
assert_eq!(format!("{}", Imm64(0)), "0"); assert_eq!(format!("{}", Imm64(0)), "0");

View File

@@ -17,13 +17,31 @@ def collect_instr_groups(targets):
def gen_opcodes(groups, out_dir): def gen_opcodes(groups, out_dir):
"""Generate opcode enumerations.""" """Generate opcode enumerations."""
fmt = srcgen.Formatter() fmt = srcgen.Formatter()
fmt.line('enum Opcode {')
fmt.indent_push() fmt.doc_comment('An instruction opcode.')
fmt.doc_comment('')
fmt.doc_comment('All instructions from all supported targets are present.')
fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
instrs = []
with fmt.indented('pub enum Opcode {', '}'):
for g in groups: for g in groups:
for i in g.instructions: for i in g.instructions:
instrs.append(i)
# Build a doc comment.
prefix = ', '.join(o.name for o in i.outs)
if prefix:
prefix = prefix + ' = '
suffix = ', '.join(o.name for o in i.ins)
fmt.doc_comment('`{}{} {}`.'.format(prefix, i.name, suffix))
# Enum variant itself.
fmt.line(i.camel_name + ',') fmt.line(i.camel_name + ',')
fmt.indent_pop()
fmt.line('}') with fmt.indented('impl Display for Opcode {', '}'):
with fmt.indented('fn fmt(&self, f: &mut Formatter) -> fmt::Result {', '}'):
with fmt.indented('f.write_str(match *self {', '})'):
for i in instrs:
fmt.format('Opcode::{} => "{}",', i.camel_name, i.name)
fmt.update_file('opcodes.rs', out_dir) fmt.update_file('opcodes.rs', out_dir)
def generate(targets, out_dir): def generate(targets, out_dir):

View File

@@ -25,15 +25,15 @@ class Formatter(object):
>>> f.indent_push() >>> f.indent_push()
>>> f.comment('Nested comment') >>> f.comment('Nested comment')
>>> f.indent_pop() >>> f.indent_pop()
>>> f.line('Back again') >>> f.format('Back {} again', 'home')
>>> f.writelines() >>> f.writelines()
Hello line 1 Hello line 1
// Nested comment // Nested comment
Back again Back home again
""" """
shiftwidth = 2 shiftwidth = 4
def __init__(self): def __init__(self):
self.indent = '' self.indent = ''
@@ -64,10 +64,49 @@ class Formatter(object):
with open(filename, 'w') as f: with open(filename, 'w') as f:
self.writelines(f) self.writelines(f)
class _IndentedScope(object):
def __init__(self, fmt, after):
self.fmt = fmt
self.after = after
def __enter__(self):
self.fmt.indent_push();
def __exit__(self, t, v, tb):
self.fmt.indent_pop()
if self.after:
self.fmt.line(self.after)
def indented(self, before=None, after=None):
"""
Return a scope object for use with a `with` statement:
>>> f = Formatter()
>>> with f.indented('prefix {', '} suffix'):
... f.line('hello')
>>> f.writelines()
prefix {
hello
} suffix
The optional `before` and `after` parameters are surrounding lines
which are *not* indented.
"""
if before:
self.line(before)
return self._IndentedScope(self, after)
def format(self, fmt, *args):
self.line(fmt.format(*args))
def comment(self, s): def comment(self, s):
"""Add a comment line.""" """Add a comment line."""
self.line('// ' + s) self.line('// ' + s)
def doc_comment(self, s):
"""Add a documentation comment line."""
self.line('/// ' + s)
if __name__ == "__main__": if __name__ == "__main__":
import doctest import doctest
doctest.testmod() doctest.testmod()