-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcheck.py
122 lines (102 loc) · 3.66 KB
/
check.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#! /usr/bin/env python
"""
CS 121 Style-Checker
--------------------
This makes sure that your assignment submissions are formatted correctly. It is
unable to catch assignment-specific configurations (like if you actually
submitted something for every question). It is also unable to check for MySQL
syntax errors.
Usage: python check.py filename1 [filename2 ...]
python check.py *
Errors:
[BAD PROBLEM HEADER] - Problem header was not formatted correctly.
[DO NOT USE TABS] - Tabs should not be used for indentation. Use spaces.
[LINE TOO LONG] - Lines should not be longer than 80 characters.
[PUT SPACE AFTER COMMA] - There should be a space after any comma.
[CODE BEFORE PROBLEM HEADER] - No code should appear before the first problem
header.
[NO DOUBLE-QUOTED STRINGS] - Strings must be enclosed by SINGLE quotes.
"""
import os
import re
import sys
MAX_LINE_LENGTH = 80
S = r"[^\>\<\=\(\) \t\n\r\f\v]"
header = re.compile(r"-- \[Problem (([0-9])+([a-zA-Z])*|[a-zA-Z])\]")
bad_header = re.compile(r"-- \[Problem([^\]])*\]")
comment = re.compile(r"\s*--.|/\*.|\*/.")
tabs = re.compile(r"\t+")
comma_space = re.compile(r",[^ ][^\n]")
negative_num = re.compile(r"\-([0-9]*\.?[0-9]+)")
count_star = re.compile(r"\(\*\)|\(DISTINCT \*\)")
double_quote = re.compile(r"\"([^\"])*\"")
HAS_HEADER = False
MULTILINE_COMMENT = False
def check_line(line, line_number):
"""
Function: check_line
--------------------
Checks a line of a file for style violations.
"""
global HAS_HEADER, MULTILINE_COMMENT
is_bad_header = False
def h():
return "Line %d " % (line_number)
def f(line):
return ":\n %s" % line.strip()
if not len(line.strip()):
return
# Check for problem header formatting errors (cannot have code before a
# problem header).
if not HAS_HEADER and header.search(line):
HAS_HEADER = True
if line.strip().startswith("/*"):
MULTILINE_COMMENT = True
# Check for style mistakes.
if bad_header.search(line) and not header.search(line):
print h() + "[BAD PROBLEM HEADER]" + f(line)
is_bad_header = True
if tabs.search(line):
print h() + "[DO NOT USE TABS]" + f(line)
if len(line) > MAX_LINE_LENGTH:
print h() + "[LINE TOO LONG (" + str(len(line)) + " CHARS)]" + f(line)
if not MULTILINE_COMMENT and not comment.search(line):
if comma_space.search(line):
print h() + "[PUT SPACE AFTER COMMA]" + f(line)
if double_quote.search(line):
print h() + "[NO DOUBLE-QUOTED STRINGS]" + f(line)
# Continue checking for problem header mistakes.
if not (HAS_HEADER or
MULTILINE_COMMENT or
is_bad_header or
comment.search(line.strip())):
print h() + "[CODE BEFORE PROBLEM HEADER]" + f(line)
if line.strip().startswith("*/") or line.strip().endswith("*/"):
MULTILINE_COMMENT = False
if __name__ == '__main__':
# Main program.
if len(sys.argv) < 2:
print "\nUsage: check.py filename1 [filename2 ...] OR\n" + \
" check.py *"
sys.exit()
files = []
# If checking all SQL files.
if sys.argv[1] == '*':
files = [f for f in os.listdir(".") if f.endswith(".sql")]
# If checking specific files.
else: files = sys.argv[1:]
for filename in files:
f = open(filename, 'r')
lines = f.readlines()
f.close()
print "\n", filename
print "-" * len(filename)
# Check for encoding.
try:
"\n".join(lines).decode('utf-8')
except UnicodeDecodeError:
print "FILE IS NOT IN UTF-8 ENCODING!"
continue
for i in range(len(lines)):
line = lines[i][:-1]
check_line(line, i + 1)