format-torque.py 5.56 KB
Newer Older
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3 4 5 6 7 8 9
# 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."""

10 11 12
# for py2/py3 compatibility
from __future__ import print_function

13 14 15 16 17
import subprocess
import sys
import re
from subprocess import Popen, PIPE

18
kPercentEscape = r'α';  # Unicode alpha
19 20
kDerefEscape = r'☆'; # Unicode star
kAddressofEscape = r'⌂'; # Unicode house
21

22
def preprocess(input):
23 24 25 26 27 28 29 30 31 32
  # 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)


33 34
  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)
35 36 37
  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)
38

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

52 53 54 55 56
  # 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)

57 58 59 60 61
  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)
62
  output = re.sub(r'(\n\s*)labels( [A-Z])', r'\1    labels\2', output)
63
  output = re.sub(r'\/\*_OPE \'([^\']+)\'\*\/', r"operator '\1'", output)
64 65 66
  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)
67 68 69
  output = re.sub(r'\n_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/',
      r"\n    generates '\1'", output)
  output = re.sub(r'_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/',
70 71 72
      r"generates '\1'", output)
  output = re.sub(r'_CoNsExP_\s*\/\*([^@]+)@\*\/',
      r"constexpr '\1'", output)
73 74 75 76 77 78
  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)
79
  output = re.sub(r'@iF\(', r'@if(', output)
80 81
  output = re.sub(r'@eXpOrT',
      r"@export", output)
82 83
  output = re.sub(r'jS_iMpLiCiT_',
      r"js-implicit ", output)
84
  output = re.sub(r'}\n *label ', r'} label ', output);
85
  output = re.sub(r'^(\s*namespace\s+[a-zA-Z_0-9]+\s*{)}(\s*)$', r'\1\2', output, flags = re.MULTILINE);
86

87
  output = re.sub(kPercentEscape, r'%', output)
88 89 90
  output = re.sub(kDerefEscape, r'*', output)
  output = re.sub(kAddressofEscape, r'&', output)

91

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

94 95
  return output

96
def process(filename, lint, should_format):
97
  with open(filename, 'r') as content_file:
98 99 100 101
    content = content_file.read()

  original_input = content

102 103 104 105
  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)
106
  output, err = p.communicate(preprocess(content))
107 108
  output = postprocess(output)
  rc = p.returncode
109 110
  if (rc != 0):
    print("error code " + str(rc) + " running clang-format. Exiting...")
111 112
    sys.exit(rc);

113 114
  if (output != original_input):
    if lint:
115
      print(filename + ' requires formatting', file=sys.stderr)
116

117 118 119 120
    if should_format:
      output_file = open(filename, 'w')
      output_file.write(output);
      output_file.close()
121 122

def print_usage():
123 124 125 126
  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')
127 128 129

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

134 135 136 137
  def is_option(arg):
    return arg in ['-i', '-l', '-il']

  should_format = lint = False
138
  use_stdout = True
139

140 141 142 143 144 145 146 147 148
  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
149
  else:
150
    print("error: -i and/or -l flags must be specified")
151 152 153
    print_usage();
    sys.exit(-1);

154 155
  for filename in files:
    process(filename, lint, should_format)
156 157

  return 0
158

159 160
if __name__ == '__main__':
  sys.exit(Main());