mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 01:49:19 +00:00
163 lines
6.4 KiB
Python
163 lines
6.4 KiB
Python
|
|
# Colon Locater and Reporter, by RemieRichards V1.0 - 25/10/15
|
|
|
|
# Locates the byond operator ":", which is largely frowned upon due to the fact it ignores any type safety.
|
|
# This tool produces a .txt of "filenames line,line?,line totalcolons" (where line? represents a colon in a ternary operation) from all
|
|
# .dm files in the /code directory of an SS13 codebase, but can work on any Byond project if you modify scan_dir and real_dir
|
|
# the .txt take's todays date in reverse order and adds -colon_operator_log to the end, eg: "2015/10/25-colon_operator_log.txt"
|
|
|
|
import sys
|
|
import os
|
|
from datetime import date
|
|
|
|
|
|
#Climbs up from /tools/ColonCatcher and along to ../code
|
|
scan_dir = "code" #used later to truncate log file paths
|
|
real_dir = os.path.abspath("../../"+scan_dir)
|
|
|
|
|
|
#Scan a directory, scanning any dm files it finds
|
|
def colon_scan_dir(scan_dir):
|
|
if os.path.exists(scan_dir):
|
|
if os.path.isdir(scan_dir):
|
|
|
|
output_str = ""
|
|
|
|
files_scanned = 0
|
|
files_with_colons = 0
|
|
for root, dirs, files in os.walk(scan_dir):
|
|
for f in files:
|
|
print str(f)
|
|
scan_result = scan_dm_file(os.path.join(root, f))
|
|
files_scanned += 1
|
|
if scan_result:
|
|
output_str += scan_result+"\n"
|
|
files_with_colons += 1
|
|
output_str += str(files_with_colons) + "/" + str(files_scanned) + " files have colons in them"
|
|
|
|
todays_file = str(date.today())+"-colon_operator_log.txt"
|
|
output_file = open(todays_file, "w") #w so it overrides existing files for today, there should only really be one file per day
|
|
output_file.write(output_str)
|
|
|
|
|
|
|
|
#Scan one file, returning a string as a "report" or if there are no colons, False
|
|
def scan_dm_file(_file):
|
|
|
|
if not _file.endswith(".dm"):
|
|
return False
|
|
|
|
with open(_file, "r") as dm_file:
|
|
characters = dm_file.read()
|
|
|
|
line_num = 1
|
|
colon_count = 0
|
|
last_char = ""
|
|
|
|
in_embed_statement = 0 # [ ... ] num due to embeds in embeds
|
|
in_multiline_comment = 0 #/* ... */ num due to /* /* */ */
|
|
in_singleline_comment = False #// ... \n
|
|
in_string = False # " ... "
|
|
ternary_on_line = False #If there's a ? anywhere on the line, used to report "false"-positives
|
|
|
|
lines_with_colons = []
|
|
|
|
for char in characters:
|
|
#Line info
|
|
if char == "\n" or char == "\r":
|
|
if not in_string:
|
|
ternary_on_line = False #Stop any old ternary operation
|
|
line_num += 1
|
|
in_embed_statement = 0
|
|
|
|
#Not in a comment
|
|
if (not in_singleline_comment) and (in_multiline_comment == 0):
|
|
#Not in a string
|
|
if not in_string:
|
|
if last_char == "/":
|
|
if char == "/":
|
|
in_singleline_comment = True
|
|
if char == "*":
|
|
in_multiline_comment += 1
|
|
if char == "\"":
|
|
in_string = True
|
|
|
|
#In a string
|
|
else:
|
|
if char == "\"": #Only " ends a string, as byond supports multiline strings
|
|
if last_char != "\\": #make sure it's a real " not an escaped one (\")
|
|
in_string = False
|
|
|
|
#It's not an embedded statment if it's not in a string
|
|
if char == "[":
|
|
in_embed_statement += 1
|
|
if char == "]":
|
|
in_embed_statement -= 1
|
|
in_embed_statement = max(in_embed_statement,0)
|
|
|
|
#ternary statements, True when in_embed_statement+in_string OR when not in_string
|
|
if char == "?":
|
|
if in_string:
|
|
if in_embed_statement != 0:
|
|
ternary_on_line = True
|
|
else:
|
|
ternary_on_line = True
|
|
|
|
#A Colon!
|
|
#If we're in a string, but not embedded: Ok, it's just rawtext
|
|
#If we're in a string, and embedded but NOT in a ternary operation: Bad, guaranteed to be a : used to avoid typechecks
|
|
#If we're in a string, and embedded AND in a ternary operation: Potentially Bad, this could be a : used to avoid typechecks (bad) or the middle : of the ternary operation (generally ok)
|
|
|
|
if char == ":":
|
|
if not in_string:
|
|
colon_count += 1
|
|
data = str(line_num)
|
|
if ternary_on_line:
|
|
data += "?"
|
|
if not data in lines_with_colons: #only add the line twice if it's like: 76, 76? (eg: a "bad" colon and a ternary colon)
|
|
lines_with_colons.append(data)
|
|
else:
|
|
if in_embed_statement != 0:
|
|
colon_count += 1
|
|
data = str(line_num)
|
|
if ternary_on_line:
|
|
data += "?"
|
|
if not data in lines_with_colons:
|
|
lines_with_colons.append(data)
|
|
|
|
#In a comment
|
|
else:
|
|
if char == "/":
|
|
if last_char == "*":
|
|
in_multiline_comment -= 1
|
|
in_multiline_comment = max(in_multiline_comment,0)
|
|
|
|
if char == "\n" or char == "\r":
|
|
in_singleline_comment = False
|
|
|
|
|
|
if char != "": #Spaces aren't useful to us
|
|
last_char = char
|
|
|
|
|
|
if colon_count:
|
|
file_report = ".."+scan_dir+str(_file).split(scan_dir)[1]+" " #crop it down to ..\code\DIR\FILE.dm, everything else is developer specific
|
|
|
|
first = True
|
|
for line in lines_with_colons:
|
|
if first:
|
|
first = False
|
|
file_report += "Lines: "+line
|
|
else:
|
|
file_report += ", "+line
|
|
|
|
file_report += " Total Colons: "+str(colon_count)
|
|
return file_report
|
|
else:
|
|
return False
|
|
|
|
|
|
|
|
colon_scan_dir(real_dir)
|
|
print "Done!"
|