format-torque.py 5.65 KB
Newer Older
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3 4 5 6 7 8 9 10 11 12 13 14
# Copyright 2014 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""This program either generates the parser files for Torque, generating
the source and header files directly in V8's src directory."""

import subprocess
import sys
import re
from subprocess import Popen, PIPE

15 16
def decode(arg, encoding="utf-8"):
  return arg.decode(encoding)
17

18 19
def encode(arg, encoding="utf-8"):
  return arg.encode(encoding)
20

21
kPercentEscape = r'α';  # Unicode alpha
22 23
kDerefEscape = r'☆'; # Unicode star
kAddressofEscape = r'⌂'; # Unicode house
24

25
def preprocess(input):
26 27 28 29 30 31 32 33 34 35
  # Special handing of '%' for intrinsics, turn the percent
  # into a unicode character so that it gets treated as part of the
  # intrinsic's name if it's already adjacent to it.
  input = re.sub(r'%([A-Za-z])', kPercentEscape + r'\1', input)
  # Similarly, avoid treating * and & as binary operators when they're
  # probably used as address operators.
  input = re.sub(r'([^/])\*([a-zA-Z(])', r'\1' + kDerefEscape + r'\2', input)
  input = re.sub(r'&([a-zA-Z(])', kAddressofEscape + r'\1', input)


36 37
  input = re.sub(r'(if\s+)constexpr(\s*\()', r'\1/*COxp*/\2', input)
  input = re.sub(r'(\s+)operator\s*(\'[^\']+\')', r'\1/*_OPE \2*/', input)
38 39 40
  input = re.sub(r'\btypeswitch\s*(\([^{]*\))\s{', r' if /*tPsW*/ \1 {', input)
  input = re.sub(r'\bcase\s*(\([^{]*\))\s*:\s*deferred\s*{', r' if /*cAsEdEfF*/ \1 {', input)
  input = re.sub(r'\bcase\s*(\([^{]*\))\s*:\s*{', r' if /*cA*/ \1 {', input)
41

42
  input = re.sub(r'\bgenerates\s+\'([^\']+)\'\s*',
43
      r'_GeNeRaTeS00_/*\1@*/', input)
44
  input = re.sub(r'\bconstexpr\s+\'([^\']+)\'\s*',
45
      r' _CoNsExP_/*\1@*/', input)
46 47 48 49
  input = re.sub(r'\notherwise',
      r'\n otherwise', input)
  input = re.sub(r'(\n\s*\S[^\n]*\s)otherwise',
      r'\1_OtheSaLi', input)
50
  input = re.sub(r'@if\(', r'@iF(', input)
51
  input = re.sub(r'@export', r'@eXpOrT', input)
52
  input = re.sub(r'js-implicit[ \n]+', r'jS_iMpLiCiT_', input)
53
  input = re.sub(r'^(\s*namespace\s+[a-zA-Z_0-9]+\s*{)(\s*)$', r'\1}\2', input, flags = re.MULTILINE)
54

55 56 57 58 59
  # includes are not recognized, change them into comments so that the
  # formatter ignores them first, until we can figure out a way to format cpp
  # includes within a JS file.
  input = re.sub(r'^#include', r'// InClUdE', input, flags=re.MULTILINE)

60 61 62 63 64
  return input

def postprocess(output):
  output = re.sub(r'\/\*COxp\*\/', r'constexpr', output)
  output = re.sub(r'(\S+)\s*: type([,>])', r'\1: type\2', output)
65
  output = re.sub(r'(\n\s*)labels( [A-Z])', r'\1    labels\2', output)
66
  output = re.sub(r'\/\*_OPE \'([^\']+)\'\*\/', r"operator '\1'", output)
67 68 69
  output = re.sub(r'\bif\s*\/\*tPsW\*\/', r'typeswitch', output)
  output = re.sub(r'\bif\s*\/\*cA\*\/\s*(\([^{]*\))\s*{', r'case \1: {', output)
  output = re.sub(r'\bif\s*\/\*cAsEdEfF\*\/\s*(\([^{]*\))\s*{', r'case \1: deferred {', output)
70 71 72
  output = re.sub(r'\n_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/',
      r"\n    generates '\1'", output)
  output = re.sub(r'_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/',
73 74 75
      r"generates '\1'", output)
  output = re.sub(r'_CoNsExP_\s*\/\*([^@]+)@\*\/',
      r"constexpr '\1'", output)
76 77 78 79 80 81
  output = re.sub(r'\n(\s+)otherwise',
      r"\n\1    otherwise", output)
  output = re.sub(r'\n(\s+)_OtheSaLi',
      r"\n\1otherwise", output)
  output = re.sub(r'_OtheSaLi',
      r"otherwise", output)
82
  output = re.sub(r'@iF\(', r'@if(', output)
83 84
  output = re.sub(r'@eXpOrT',
      r"@export", output)
85 86
  output = re.sub(r'jS_iMpLiCiT_',
      r"js-implicit ", output)
87
  output = re.sub(r'}\n *label ', r'} label ', output);
88
  output = re.sub(r'^(\s*namespace\s+[a-zA-Z_0-9]+\s*{)}(\s*)$', r'\1\2', output, flags = re.MULTILINE);
89

90
  output = re.sub(kPercentEscape, r'%', output)
91 92 93
  output = re.sub(kDerefEscape, r'*', output)
  output = re.sub(kAddressofEscape, r'&', output)

94

95 96
  output = re.sub( r'^// InClUdE',r'#include', output, flags=re.MULTILINE)

97 98
  return output

99
def process(filename, lint, should_format):
100
  with open(filename, 'r') as content_file:
101 102 103 104
    content = content_file.read()

  original_input = content

105 106 107 108
  if sys.platform.startswith('win'):
    p = Popen(['clang-format', '-assume-filename=.ts'], stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
  else:
    p = Popen(['clang-format', '-assume-filename=.ts'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
109 110
  output, err = p.communicate(encode(preprocess(content)))
  output = postprocess(decode(output))
111
  rc = p.returncode
112 113
  if (rc != 0):
    print("error code " + str(rc) + " running clang-format. Exiting...")
114 115
    sys.exit(rc);

116 117
  if (output != original_input):
    if lint:
118
      print(filename + ' requires formatting', file=sys.stderr)
119

120
    if should_format:
121
      output_file = open(filename, 'wb')
122
      output_file.write(encode(output))
123
      output_file.close()
124 125

def print_usage():
126 127 128 129
  print('format-torque -i file1[, file2[, ...]]')
  print('    format and overwrite input files')
  print('format-torque -l file1[, file2[, ...]]')
  print('    merely indicate which files need formatting')
130 131 132

def Main():
  if len(sys.argv) < 3:
133
    print("error: at least 2 arguments required")
134 135 136
    print_usage();
    sys.exit(-1)

137 138 139 140
  def is_option(arg):
    return arg in ['-i', '-l', '-il']

  should_format = lint = False
141
  use_stdout = True
142

143 144 145 146 147 148 149 150 151
  flag, files = sys.argv[1], sys.argv[2:]
  if is_option(flag):
    if '-i' == flag:
      should_format = True
    elif '-l' == flag:
      lint = True
    else:
      lint = True
      should_format = True
152
  else:
153
    print("error: -i and/or -l flags must be specified")
154 155 156
    print_usage();
    sys.exit(-1);

157 158
  for filename in files:
    process(filename, lint, should_format)
159 160

  return 0
161

162 163
if __name__ == '__main__':
  sys.exit(Main());