From b60b2ce135d59f2952ea3fc329bf74ba9c493cfe Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 31 Oct 2017 10:51:49 -0700 Subject: [PATCH] Change parse_multiline to follow PEP 257. The main change is that it avoids creating blank lines when processing docstrings. This also adds blank lines in various places to make the generated code prettier. --- lib/cretonne/meta/gen_instr.py | 31 +++++++++++++++++++++++-------- lib/cretonne/meta/gen_types.py | 1 + lib/cretonne/meta/srcgen.py | 32 +++++++++++++++++++++++++------- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index 4c537acf12..2bd34a926c 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -28,11 +28,13 @@ def gen_formats(fmt): # type: (srcgen.Formatter) -> None """Generate an instruction format enumeration""" - fmt.doc_comment('An instruction format') - fmt.doc_comment('') - fmt.doc_comment('Every opcode has a corresponding instruction format') - fmt.doc_comment('which is represented by both the `InstructionFormat`') - fmt.doc_comment('and the `InstructionData` enums.') + fmt.doc_comment(''' + An instruction format + + Every opcode has a corresponding instruction format + which is represented by both the `InstructionFormat` + and the `InstructionData` enums. + ''') fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]') with fmt.indented('pub enum InstructionFormat {', '}'): for f in InstructionFormat.all_formats: @@ -126,6 +128,7 @@ def gen_instruction_data_impl(fmt): fmt.line( 'InstructionData::{} {{ opcode, .. }} => opcode,' .format(f.name)) + fmt.line() fmt.doc_comment('Get the controlling type variable operand.') with fmt.indented( @@ -153,18 +156,22 @@ def gen_instruction_data_impl(fmt): n + ' {{ ref args, .. }} => Some(args[{}]),' .format(i)) + fmt.line() fmt.doc_comment( """ Get the value arguments to this instruction. """) gen_arguments_method(fmt, False) + fmt.line() + fmt.doc_comment( """ Get mutable references to the value arguments to this instruction. """) gen_arguments_method(fmt, True) + fmt.line() fmt.doc_comment( """ @@ -184,6 +191,7 @@ def gen_instruction_data_impl(fmt): fmt.line( n + ' { ref mut args, .. } => Some(args.take()),') fmt.line('_ => None,') + fmt.line() fmt.doc_comment( """ @@ -227,9 +235,11 @@ def gen_opcodes(groups, fmt): Return a list of all instructions. """ - fmt.doc_comment('An instruction opcode.') - fmt.doc_comment('') - fmt.doc_comment('All instructions from all supported ISAs are present.') + fmt.doc_comment(''' + An instruction opcode. + + All instructions from all supported ISAs are present. + ''') fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]') instrs = [] @@ -272,6 +282,8 @@ def gen_opcodes(groups, fmt): i.camel_name, i.name) fmt.line('_ => false,') + fmt.line() + fmt.line() # Generate a private opcode_format table. with fmt.indented( @@ -437,8 +449,10 @@ def gen_type_constraints(fmt, instrs): fmt.line('flags: {:#04x},'.format(flags)) fmt.line('typeset_offset: {},'.format(ctrl_typeset)) fmt.line('constraint_offset: {},'.format(offset)) + fmt.line() gen_typesets_table(fmt, type_sets) + fmt.line() fmt.comment('Table of operand constraint sequences.') with fmt.indented( @@ -668,6 +682,7 @@ def generate(isas, out_dir): fmt = srcgen.Formatter() gen_formats(fmt) gen_instruction_data_impl(fmt) + fmt.line() instrs = gen_opcodes(groups, fmt) gen_type_constraints(fmt, instrs) fmt.update_file('opcodes.rs', out_dir) diff --git a/lib/cretonne/meta/gen_types.py b/lib/cretonne/meta/gen_types.py index c5e36758ba..bc912e78f7 100644 --- a/lib/cretonne/meta/gen_types.py +++ b/lib/cretonne/meta/gen_types.py @@ -28,6 +28,7 @@ def emit_type(ty, fmt): fmt.line( 'pub const {}: Type = Type({:#x});' .format(name, ty.number)) + fmt.line() def emit_vectors(bits, fmt): diff --git a/lib/cretonne/meta/srcgen.py b/lib/cretonne/meta/srcgen.py index f0f7931ea1..9761160487 100644 --- a/lib/cretonne/meta/srcgen.py +++ b/lib/cretonne/meta/srcgen.py @@ -168,12 +168,30 @@ def parse_multiline(s): # type: (str) -> List[str] """ Given a multi-line string, split it into a sequence of lines after - stripping a common indentation. This is useful for strings defined with doc - strings: + stripping a common indentation, as described in the "trim" function + from PEP 257. This is useful for strings defined with doc strings: >>> parse_multiline('\\n hello\\n world\\n') - [None, 'hello', 'world'] + ['hello', 'world'] """ - lines = s.splitlines() - indents = list(i for i in (_indent(l) for l in lines) if i) - indent = min(indents) if indents else 0 - return list(l[indent:] if len(l) > indent else None for l in lines) + if not s: + return [] + # Convert tabs to spaces (following the normal Python rules) + # and split into a list of lines: + lines = s.expandtabs().splitlines() + # Determine minimum indentation (first line doesn't count): + indent = sys.maxsize + for line in lines[1:]: + stripped = line.lstrip() + if stripped: + indent = min(indent, len(line) - len(stripped)) + # Remove indentation (first line is special): + trimmed = [lines[0].strip()] + if indent < sys.maxsize: + for line in lines[1:]: + trimmed.append(line[indent:].rstrip()) + # Strip off trailing and leading blank lines: + while trimmed and not trimmed[-1]: + trimmed.pop() + while trimmed and not trimmed[0]: + trimmed.pop(0) + return trimmed