#!/usr/bin/env python3 import io, os, re, datetime regex_parts = {} regex_parts['operator_assign'] = r'=|\+=|-=' regex_parts['parameter'] = r"\$ARGS\[\d+\]" regex_parts['var'] = r"\$?[a-z]+\w*" regex_parts['functioncall'] = r"\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\)" regex_parts['integer'] = r"\d+" regex_parts['string'] = r"""'\w'|"""+ r'''"\w"''' regex_parts['value_literal'] = "|".join([regex_parts['integer'],regex_parts['string']]) regex_parts['value'] = "|".join([regex_parts['parameter'],regex_parts['var'],regex_parts['functioncall'],regex_parts['value_literal'] ]) regex_parts['statement'] = '?' regex_parts['assignment'] = f"\s*({regex_parts['var']})\s*({regex_parts['operator_assign']})\s*({regex_parts['value']})\s*" def convert_command(command_raw): command = command_raw.strip() split_by_and = command.split(' & ') if len(split_by_and) > 1: return ' '.join([convert_command(s) for s in split_by_and]) assign_operators = ['=','-=','+='] for assign_operator in assign_operators: split_by_assign = command.split(assign_operator) if len(split_by_assign) > 1: return f'<>' if match := re.match(r"^(\$?\w+)\s*(\+=|-=|=)\s*([\$']?\w*'?|\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\))$",command): return f'<>' if match := re.match(r"^(gt|gs)\s+(.+)$",command): arguments = " ".join([convert_literal(l) for l in match.group(2).split(',')]) return f'<<{match.group(1)} {arguments}>>' return '' def convert_condition(condition_raw): condition = condition_raw.strip() split_by_or = condition.split(' or ') if len(split_by_or) > 1: return ' or '.join([convert_condition(s) for s in split_by_or]) split_by_xor = condition.split(' xor ') if len(split_by_xor) > 1: return ' xor '.join([convert_condition(s) for s in split_by_xor]) split_by_and = condition.split(' and ') if len(split_by_and) > 1: return ' and '.join([convert_condition(s) for s in split_by_and]) #match = re.match(r"(\$ARGS\[\d+\]|\$?\w+)\s*([=><]+)\s*('?\w+'?)",condition) #match = re.match(r"(\S+)\s*([=><]+)\s*(\S+)",condition) if(len(condition) >= 2 and condition[0] == '('): condition = condition[1:-1] match = re.match(r"([^<^>^=^!]+)\s*([=>^=^!]+)",condition) if match: left = convert_literal(match.group(1)) right = convert_literal(match.group(3)) operator = match.group(2) if operator == '=': operator = '==' elif operator == '!': operator = '!=' return ' '.join([left,operator,right]) return f'ERROR: FAILED TO CONVERT CONDITION: {condition}' def convert_literal(literal_raw): literal = literal_raw.strip() if not literal: return '' if literal == "''": return literal if(literal.isnumeric()): return literal if(len(literal)>= 3 and literal[0] == '\'' and literal[-1] == '\''): literal = literal.replace('<<','') literal = literal.replace('>>','') literal = literal.replace("''","'") return literal if(match := re.match(r"^arrsize\(\s*'(\$?)([a-z]+\w*)'\s*\)$",literal)): return f"${match.group(2)}.length" if(match := re.match(r"^killvar\s+'(\$?)([a-z]+\w*)'$",literal)): return f"<>" if(match := re.match(r'^\$ARGS\[(\d+)\]$',literal,re.I)): #ARGS return f'$location_var[$here][{match.group(1)}]' if(match := re.match(r"^(\$?)[a-zA-z]+\w*(\[('\w*'|\d+)\])?$",literal)): if match.group(1): return literal return '$'+literal if(match := re.match(r"^(\$?)([a-zA-z]+\w*)\[(.+)\]$",literal)): if match.group(1): return f"{match.group(2)}[{convert_literal(match.group(3))}]" return f"${match.group(2)}[{convert_literal(match.group(3))}]" if(match := re.match(r'^(\w+)\s*\((\s*\w+\s*(?:,\s*\w*\s*)*)\)$',literal)): function_name = match.group(1) function_parameters = match.group(2) return f'{function_name}({convert_literal(function_parameters)})' #Arithmetic Operations arith_operations = ['*','/','-','+','%',','] for arith_operation in arith_operations: split_by_arith = literal.split(arith_operation) if len(split_by_arith) > 1: return f' {arith_operation} '.join([convert_literal(s) for s in split_by_arith]) return f'ERROR: FAILED TO CONVERT LITERAL: "{literal}"' def convert_file(filename,skipIfNotExplicit=0,defaultsubfolder=False): skip = skipIfNotExplicit qsp_filename = filename+".qsrc" qsp_filepath = os.path.join(qsp_sources_path,qsp_filename) tw_filename = filename+".tw" tw_filepath = os.path.join(tw_sources_path,tw_filename) if defaultsubfolder: os.makedirs(os.path.join(tw_sources_path,defaultsubfolder),exist_ok =True) tw_filepath = os.path.join(tw_sources_path,defaultsubfolder,tw_filename) try: with open(qsp_filepath) as file: lines = [line.rstrip() for line in file] except: try: with open(qsp_filepath, encoding="utf-8") as file: lines = [line.rstrip() for line in file] except: return f"FAILED: {qsp_filename}" location_identifier = '' if match := re.match(r"^\s*!!\s*(FOLDER\s*:\s*\w+)?\s*(SKIP\s*:\s*-?\d)?$",lines[0],re.I): if match.group(1): parts = match.group(1).split(':') new_path = os.path.join(tw_sources_path,parts[1]) os.makedirs(new_path,exist_ok =True) tw_filepath = os.path.join(new_path,tw_filename) if match.group(2): parts = match.group(2).split(':') arg = int(parts[1]) if arg == 1: skip = 1 elif arg == 0: skip = 0 elif arg == -1: skip = -1 if skip == 1: return if skip == -1 and os.path.exists(tw_filepath): modification_time_delta = os.path.getmtime(qsp_filepath) - os.path.getmtime(tw_filepath) if modification_time_delta <= 0: return identifier_line = 0 for line_num in range(0,len(lines)-1): line_raw = lines[line_num] line = line_raw.strip() match = re.match(r"#\s*(\S+)", line) if match: location_identifier = match.group(1) identifier_line = line_num break with open(tw_filepath, 'w') as file: #file.write(f'\n') file.write(f'::{location_identifier}\n') file.write(f"<>\n") nesting = [] for line_num in range(identifier_line+1,len(lines)-1): line_raw = lines[line_num] line = line_raw.strip() commentsplit = line.split("!!") if len(commentsplit) > 1: line = commentsplit[0] if not line: continue if line[0] == '!': continue #image-convert #line = re.sub(r'src=\"images\/([^\"]+)\"',r'''@src="$media_path+'\1'"''',line) line_output = '' whitespace_count = len(nesting) #file.write(whitespace_count * '\t') purges = [ 'CLOSE ALL', 'close all', '*clr & cla', "gs 'stat'", 'killall', 'showstat 0','showstat 1', 'showobjs 0','showobjs 1', 'showinput 0','showinput 1' ] for purge in purges: line = line.replace(purge,'') if line.lower() == 'end': whitespace_count -= 1 if len(nesting) > 0: end_command = nesting.pop() if end_command == 'if': #file.write('<>\n') line_output = '<>' elif end_command == 'while': #file.write('<>\n') line_output = '<>' elif end_command == 'act': #file.write('<>\n') line_output = '<>' else: print(f'ERROR: UNKNOWN NESTRING: {end_command}') else: line_output = '<>' elif line.lower() == 'else': #file.write('<>\n') line_output = '<>' whitespace_count -= 1 elif line.lower() == '*nl': #file.write('\n') line_output = '' elif line[0:3] == '---': line_output = '' elif match := re.match(r"""^'(?:
)?>\s+)src="images\/([\w\/\.]+)(?:'\s*\+\s*rand\((\d+,\d+)\)\s*\+\s*')?([\w\/\.]+)"\s*>(?:<\/center>)?'""",line,re.I): #Images if match.group(2): line_output = f'''<>''' else: line_output = f'''<>''' elif match := re.match(r"""^'[\w<>\s=:'"\/\.\(\),\*]+'$""",line): #Plain HTML line_output = line[1:-1] if link_match := re.findall(r"""(([^<]+)<\/a>)""",line_output): #line_output = #line_output.replace(link_match[0],"moep") #print("moep") #print(link_match) for lmatch in link_match: line_output = line_output.replace(lmatch[0],f"""<>{convert_command(lmatch[1])}<>""") elif match := re.match(r"\s*(if|while)\s+([^:]+):(.*)",line,re.I): command = match.group(1).lower() line_w = f'<<{command} {convert_condition(match.group(2))}>>' if match.group(3): line_w += '\n' + (whitespace_count+1) * '\t'+convert_command(match.group(3)) line_w += '\n' + whitespace_count * '\t'+f'<>' else: nesting.append(command) #file.write(line_w) line_output = line_w elif match := re.match(r"\s*(act)\s+(.+):(.*)",line,re.I): # Act-Command command = match.group(1).lower() line_w = f'<<{command} {convert_literal(match.group(2))}>>' if match.group(3): line_w += '\n' + (whitespace_count+1) * '\t'+convert_command(match.group(3)) line_w += '\n' + whitespace_count * '\t'+f'<>' else: nesting.append(command) #file.write(line_w) line_output = line_w elif match := re.match(r"\s*(elseif)\s+([^:]+):(.*)",line,re.I): # ElseIf command = match.group(1).lower() line_w = f'<<{command} {convert_condition(match.group(2))}>>' if match.group(3): line_w += '\n' + whitespace_count * '\t'+f'<>' #nesting.pop() #file.write(line_w) line_output = line_w elif match := convert_command(line): line_output = match else: line_output = convert_literal(line) if len(line_output) >= 2 and line_output[0] == '\'' and line_output[-1] == '\'': line_output = f'

{line_output[1:-1]}

' whitespace = whitespace_count * '\t' output = f'{whitespace}{line_output}\n' if output.strip(): file.write(output) print(f"Completed {filename}") qsp_sources_path = "locations" tw_sources_path = os.path.join("sugarcube","src","autogenerated") os.makedirs(tw_sources_path, exist_ok=True) for file in os.listdir(qsp_sources_path): if file.endswith(".qsrc"): convert_file(os.path.splitext(file)[0],-1,'unsorted')