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.
This commit is contained in:
Dan Gohman
2017-10-31 10:51:49 -07:00
parent 149a41a684
commit b60b2ce135
3 changed files with 49 additions and 15 deletions

View File

@@ -28,11 +28,13 @@ def gen_formats(fmt):
# type: (srcgen.Formatter) -> None # type: (srcgen.Formatter) -> None
"""Generate an instruction format enumeration""" """Generate an instruction format enumeration"""
fmt.doc_comment('An instruction format') fmt.doc_comment('''
fmt.doc_comment('') An instruction format
fmt.doc_comment('Every opcode has a corresponding instruction format')
fmt.doc_comment('which is represented by both the `InstructionFormat`') Every opcode has a corresponding instruction format
fmt.doc_comment('and the `InstructionData` enums.') which is represented by both the `InstructionFormat`
and the `InstructionData` enums.
''')
fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]') fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
with fmt.indented('pub enum InstructionFormat {', '}'): with fmt.indented('pub enum InstructionFormat {', '}'):
for f in InstructionFormat.all_formats: for f in InstructionFormat.all_formats:
@@ -126,6 +128,7 @@ def gen_instruction_data_impl(fmt):
fmt.line( fmt.line(
'InstructionData::{} {{ opcode, .. }} => opcode,' 'InstructionData::{} {{ opcode, .. }} => opcode,'
.format(f.name)) .format(f.name))
fmt.line()
fmt.doc_comment('Get the controlling type variable operand.') fmt.doc_comment('Get the controlling type variable operand.')
with fmt.indented( with fmt.indented(
@@ -153,18 +156,22 @@ def gen_instruction_data_impl(fmt):
n + n +
' {{ ref args, .. }} => Some(args[{}]),' ' {{ ref args, .. }} => Some(args[{}]),'
.format(i)) .format(i))
fmt.line()
fmt.doc_comment( fmt.doc_comment(
""" """
Get the value arguments to this instruction. Get the value arguments to this instruction.
""") """)
gen_arguments_method(fmt, False) gen_arguments_method(fmt, False)
fmt.line()
fmt.doc_comment( fmt.doc_comment(
""" """
Get mutable references to the value arguments to this Get mutable references to the value arguments to this
instruction. instruction.
""") """)
gen_arguments_method(fmt, True) gen_arguments_method(fmt, True)
fmt.line()
fmt.doc_comment( fmt.doc_comment(
""" """
@@ -184,6 +191,7 @@ def gen_instruction_data_impl(fmt):
fmt.line( fmt.line(
n + ' { ref mut args, .. } => Some(args.take()),') n + ' { ref mut args, .. } => Some(args.take()),')
fmt.line('_ => None,') fmt.line('_ => None,')
fmt.line()
fmt.doc_comment( fmt.doc_comment(
""" """
@@ -227,9 +235,11 @@ def gen_opcodes(groups, fmt):
Return a list of all instructions. Return a list of all instructions.
""" """
fmt.doc_comment('An instruction opcode.') fmt.doc_comment('''
fmt.doc_comment('') An instruction opcode.
fmt.doc_comment('All instructions from all supported ISAs are present.')
All instructions from all supported ISAs are present.
''')
fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]') fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]')
instrs = [] instrs = []
@@ -272,6 +282,8 @@ def gen_opcodes(groups, fmt):
i.camel_name, i.name) i.camel_name, i.name)
fmt.line('_ => false,') fmt.line('_ => false,')
fmt.line()
fmt.line()
# Generate a private opcode_format table. # Generate a private opcode_format table.
with fmt.indented( with fmt.indented(
@@ -437,8 +449,10 @@ def gen_type_constraints(fmt, instrs):
fmt.line('flags: {:#04x},'.format(flags)) fmt.line('flags: {:#04x},'.format(flags))
fmt.line('typeset_offset: {},'.format(ctrl_typeset)) fmt.line('typeset_offset: {},'.format(ctrl_typeset))
fmt.line('constraint_offset: {},'.format(offset)) fmt.line('constraint_offset: {},'.format(offset))
fmt.line()
gen_typesets_table(fmt, type_sets) gen_typesets_table(fmt, type_sets)
fmt.line()
fmt.comment('Table of operand constraint sequences.') fmt.comment('Table of operand constraint sequences.')
with fmt.indented( with fmt.indented(
@@ -668,6 +682,7 @@ def generate(isas, out_dir):
fmt = srcgen.Formatter() fmt = srcgen.Formatter()
gen_formats(fmt) gen_formats(fmt)
gen_instruction_data_impl(fmt) gen_instruction_data_impl(fmt)
fmt.line()
instrs = gen_opcodes(groups, fmt) instrs = gen_opcodes(groups, fmt)
gen_type_constraints(fmt, instrs) gen_type_constraints(fmt, instrs)
fmt.update_file('opcodes.rs', out_dir) fmt.update_file('opcodes.rs', out_dir)

View File

@@ -28,6 +28,7 @@ def emit_type(ty, fmt):
fmt.line( fmt.line(
'pub const {}: Type = Type({:#x});' 'pub const {}: Type = Type({:#x});'
.format(name, ty.number)) .format(name, ty.number))
fmt.line()
def emit_vectors(bits, fmt): def emit_vectors(bits, fmt):

View File

@@ -168,12 +168,30 @@ def parse_multiline(s):
# type: (str) -> List[str] # type: (str) -> List[str]
""" """
Given a multi-line string, split it into a sequence of lines after 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 stripping a common indentation, as described in the "trim" function
strings: from PEP 257. This is useful for strings defined with doc strings:
>>> parse_multiline('\\n hello\\n world\\n') >>> parse_multiline('\\n hello\\n world\\n')
[None, 'hello', 'world'] ['hello', 'world']
""" """
lines = s.splitlines() if not s:
indents = list(i for i in (_indent(l) for l in lines) if i) return []
indent = min(indents) if indents else 0 # Convert tabs to spaces (following the normal Python rules)
return list(l[indent:] if len(l) > indent else None for l in lines) # 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