1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright 2014 the V8 project authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""This program either generates the parser files for Torque, generating 8the source and header files directly in V8's src directory.""" 9 10# for py2/py3 compatibility 11from __future__ import print_function 12 13import subprocess 14import sys 15import re 16from subprocess import Popen, PIPE 17 18kPercentEscape = r'α'; # Unicode alpha 19kDerefEscape = r'☆'; # Unicode star 20kAddressofEscape = r'⌂'; # Unicode house 21 22def preprocess(input): 23 # Special handing of '%' for intrinsics, turn the percent 24 # into a unicode character so that it gets treated as part of the 25 # intrinsic's name if it's already adjacent to it. 26 input = re.sub(r'%([A-Za-z])', kPercentEscape + r'\1', input) 27 # Similarly, avoid treating * and & as binary operators when they're 28 # probably used as address operators. 29 input = re.sub(r'([^/])\*([a-zA-Z(])', r'\1' + kDerefEscape + r'\2', input) 30 input = re.sub(r'&([a-zA-Z(])', kAddressofEscape + r'\1', input) 31 32 33 input = re.sub(r'(if\s+)constexpr(\s*\()', r'\1/*COxp*/\2', input) 34 input = re.sub(r'(\s+)operator\s*(\'[^\']+\')', r'\1/*_OPE \2*/', input) 35 input = re.sub(r'\btypeswitch\s*(\([^{]*\))\s{', r' if /*tPsW*/ \1 {', input) 36 input = re.sub(r'\bcase\s*(\([^{]*\))\s*:\s*deferred\s*{', r' if /*cAsEdEfF*/ \1 {', input) 37 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 input = re.sub(r'\notherwise', 44 r'\n otherwise', input) 45 input = re.sub(r'(\n\s*\S[^\n]*\s)otherwise', 46 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 # includes are not recognized, change them into comments so that the 53 # formatter ignores them first, until we can figure out a way to format cpp 54 # includes within a JS file. 55 input = re.sub(r'^#include', r'// InClUdE', input, flags=re.MULTILINE) 56 57 return input 58 59def postprocess(output): 60 output = re.sub(r'\/\*COxp\*\/', r'constexpr', output) 61 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 output = re.sub(r'\bif\s*\/\*tPsW\*\/', r'typeswitch', output) 65 output = re.sub(r'\bif\s*\/\*cA\*\/\s*(\([^{]*\))\s*{', r'case \1: {', output) 66 output = re.sub(r'\bif\s*\/\*cAsEdEfF\*\/\s*(\([^{]*\))\s*{', r'case \1: deferred {', output) 67 output = re.sub(r'\n_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/', 68 r"\n generates '\1'", output) 69 output = re.sub(r'_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/', 70 r"generates '\1'", output) 71 output = re.sub(r'_CoNsExP_\s*\/\*([^@]+)@\*\/', 72 r"constexpr '\1'", output) 73 output = re.sub(r'\n(\s+)otherwise', 74 r"\n\1 otherwise", output) 75 output = re.sub(r'\n(\s+)_OtheSaLi', 76 r"\n\1otherwise", output) 77 output = re.sub(r'_OtheSaLi', 78 r"otherwise", output) 79 output = re.sub(r'@iF\(', r'@if(', output) 80 output = re.sub(r'@eXpOrT', 81 r"@export", output) 82 output = re.sub(r'jS_iMpLiCiT_', 83 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 output = re.sub(kDerefEscape, r'*', output) 89 output = re.sub(kAddressofEscape, r'&', output) 90 91 92 output = re.sub( r'^// InClUdE',r'#include', output, flags=re.MULTILINE) 93 94 return output 95 96def process(filename, lint, should_format): 97 with open(filename, 'r') as content_file: 98 content = content_file.read() 99 100 original_input = content 101 102 if sys.platform.startswith('win'): 103 p = Popen(['clang-format', '-assume-filename=.ts'], stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True) 104 else: 105 p = Popen(['clang-format', '-assume-filename=.ts'], stdin=PIPE, stdout=PIPE, stderr=PIPE) 106 output, err = p.communicate(preprocess(content)) 107 output = postprocess(output) 108 rc = p.returncode 109 if (rc != 0): 110 print("error code " + str(rc) + " running clang-format. Exiting...") 111 sys.exit(rc); 112 113 if (output != original_input): 114 if lint: 115 print(filename + ' requires formatting', file=sys.stderr) 116 117 if should_format: 118 output_file = open(filename, 'wb') 119 output_file.write(output); 120 output_file.close() 121 122def print_usage(): 123 print('format-torque -i file1[, file2[, ...]]') 124 print(' format and overwrite input files') 125 print('format-torque -l file1[, file2[, ...]]') 126 print(' merely indicate which files need formatting') 127 128def Main(): 129 if len(sys.argv) < 3: 130 print("error: at least 2 arguments required") 131 print_usage(); 132 sys.exit(-1) 133 134 def is_option(arg): 135 return arg in ['-i', '-l', '-il'] 136 137 should_format = lint = False 138 use_stdout = True 139 140 flag, files = sys.argv[1], sys.argv[2:] 141 if is_option(flag): 142 if '-i' == flag: 143 should_format = True 144 elif '-l' == flag: 145 lint = True 146 else: 147 lint = True 148 should_format = True 149 else: 150 print("error: -i and/or -l flags must be specified") 151 print_usage(); 152 sys.exit(-1); 153 154 for filename in files: 155 process(filename, lint, should_format) 156 157 return 0 158 159if __name__ == '__main__': 160 sys.exit(Main()); 161