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