#!/usr/bin/env python3 import fileinput import io, os, re, datetime import hashlib import variables import time from concurrent.futures import ThreadPoolExecutor from concurrent.futures import as_completed qsp_sources_path = "locations" tw_sources_path = os.path.join("sugarcube","src") verbose = False #verbose = True skipMode = 0 #skipMode = -1 verbose_i = 20 error_counter = 1 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 pv(desc,line): if(verbose): print(desc.ljust(verbose_i, ' ')+line) def convert_calculation(right): pv("START CALCULATION:",right) brackets_regex = r"""(? 0: calculation = calculations.pop() index = f"$CALC_HELPER_{len(calculations)}" right = right.replace(index,f"({calculation})") pv("IS CALCULATION:",right) return right def convert_command(command_raw): command = command_raw.strip() #if (command.startswith('<') or and command.endswith('>'): # return command 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,1) if len(split_by_assign) > 1: left = split_by_assign[0] if left.startswith('set '): left = left[4:] right = split_by_assign[1] right = convert_calculation(right) pv("IS ASSIGNMENT:",right) return f'<>' if match := re.match(r"^(?:set\s*)?(\$?\w+)\s*(\+=|-=|=)\s*([\$']?\w*'?|\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\))$",command): return f'<>' if match := re.match(r"""^(x?gt|gs)([\s'"].+)$""",command): arguments = match.group(2) pv('GS OR GT:',command) i = 0 replaces = [] while brackets_match := re.search(r"""\(([^\(^\)]*?,[^\(^\)]*?)\)""",arguments): original = brackets_match.group(1) pv("REPLACE:",original) indentifier = f'$BRACKET_HELER_{i}' arguments = arguments.replace(original,indentifier) replaces.append(original) i += 1 arguments = " ".join([convert_literal(l) for l in arguments.split(',')]) while len(replaces) > 0: original = replaces.pop() indentifier = f'$BRACKET_HELER_{len(replaces)}' arguments = arguments.replace(indentifier,original) return f'<<{match.group(1)} {arguments}>>' if match := re.match(r"""^msg\s*(.+)$""",command,re.I): return f"<>" if match := re.match(r"""^dynamic \$(.*)$""",command,re.I): arguments = match.group(1).replace(',',' ') return f"<<{arguments}>>" pv("NO COMMAND MATCH:",command) return '' def convert_condition(condition_raw): condition = condition_raw.strip() if(re.match(r"dyneval\(",condition)): return condition #condition = convert_calculation(condition) #print(condition) subconditions = [] bracket_search_regex = r"""(? 0: condition = convert_condition(condition) while len(subconditions) > 0: subcondition = subconditions.pop() subcondition_ident = f"$CON_HELPER_{len(subconditions)} == 1" condition = condition.replace(subcondition_ident,f"({subcondition})") #print(condition) return condition 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] == '(' and condition[-1] == ')'): condition = condition[1:-1] #print(condition) match = re.match(r"([^<^>^=^!]+)\s*([=>^=^!]+)",condition) if match: left = convert_literal(convert_calculation(match.group(1))) right = convert_literal(match.group(3)) operator = match.group(2) if operator == '=': operator = '==' elif operator == '!': operator = '!=' elif 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() pv("START LITERAL:",literal) if not literal: return '' subliterals = [] bracket_search_regex = r"""\[\s*([^\]^\[]+)\s*\]""" while match := re.search(bracket_search_regex,literal): fullmatch = match.group(0) subcondition = match.group(1) subcondition_converted = convert_literal(subcondition) subcondition_ident = f"LIT_HELPER_{len(subliterals)}" literal = literal.replace(fullmatch,subcondition_ident) subliterals.append(subcondition_converted) #print(condition) if len(subliterals) > 0: literal = convert_literal(literal) while len(subliterals) > 0: subcondition = subliterals.pop() subcondition_ident = f"LIT_HELPER_{len(subliterals)}" literal = literal.replace(subcondition_ident,f"[{subcondition}]") #print(condition) return literal #brackets_regex = r"""\(\s*([^\)^\(]+)\s*\)""" #function_name_regex = r"""(? 0: # literal = convert_literal(literal) # while len(calculations) > 0: # calculation = calculations.pop() # index = f"$LIT_HELPER_{len(calculations)}" # literal = literal.replace(index,f"({calculation})") # pv("LITERAL AFTER BRACKETS:",literal) if(re.match(r"dyneval\(",literal)): return literal if literal == "''" or literal == '""': return literal if(literal.isnumeric() or (literal.startswith('-') and literal[1:].isnumeric())): pv("IS NUMERIC",literal) return literal if(literal.startswith('(') and len(literal) > 1): return '('+literal[1:] if(literal.endswith(')') and len(literal) > 1): return literal[:-1]+')' #array_braces = False #while match:=re.match(r"\$?([a-z][a-z0-9\-_{}'\+]*)(\['(.*?<<.*?>>'*?)'\])",literal,re.I): # value = match.group(3) # if not value.startswith("<"): # value = value.replace("<<","'+") # else: # value = value.replace("<<","")# # # if not value.endswith(">"): # value = value.replace(">>","+'") # else: # value = value.replace(">>","") # literal = literal.replace(match.group(2),r"{{"+value+r"}}") # array_braces = True #if array_braces: # literal = literal.replace(r'{{','[').replace(r'}}',']') if(len(literal)>= 3 and ((literal[0] == '\'' and literal[-1] == '\'') or (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,re.I)): 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'^\$ARGS(LIT_HELPER_\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))}]" #print(literal) 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)})' while(match := re.search(r'<<(\$\w+)>>',literal)): literal = literal.replace(match.group(0),match.group(1)) #Arithmetic Operations arith_operations = ['*','/','-','+','%',',','mod'] for arith_operation in arith_operations: split_by_arith = literal.split(arith_operation) if len(split_by_arith) > 1: if arith_operation == 'mod': arith_operation = '%' return f' {arith_operation} '.join([convert_literal(s) for s in split_by_arith]) if literal.startswith('wait '): return f'<<{literal}>>' if(match := re.match(r"""^killvar\s+['"]\$?(.*)['"]$""",literal)): return f'<>' if literal.startswith('jump '): jump_san = literal.replace('"','').replace("'","") return f"<>" if literal.startswith(':'): return f"<>" if literal == "'" or literal == '"': return '' if re.match(r"""^['"\w\s\?\.!\(\)\$]+$""",literal): pv("Plain String",literal) return literal #return literal return f'ERROR: FAILED TO CONVERT LITERAL: """{literal}"""' function_name_conversions = [] def convert_lineblock(lines,location_identifier=''): outputs = [] nesting = [] commenting = False isfunction = False functionlines = [] functionlines_temp = [] function_name = '' subpassages = {} subpassage = '' for line_raw in lines: #line_raw = lines[line_num] line = line_raw.strip() original = line pv("START:",line) if len(line) == 0: continue whitespace_count = len(nesting) # Subpassages if len(subpassage) > 0: if line.startswith('~$'): endSubpassageName = line[2:] gtOrGs = 'gt' if endSubpassageName.startswith('gs:'): gtOrGs = 'gs' endSubpassageName = endSubpassageName[3:] if endSubpassageName == subpassage: outputs.append( whitespace_count * '\t' + f"<<{gtOrGs} '{subpassage}' $location_var[$here][0] $location_var[$here][1] $location_var[$here][2] $location_var[$here][3] $location_var[$here][4]>>\n") subpassages[subpassage].append('') subpassage = '' continue subpassages[subpassage].append(line) continue if len(subpassage) == 0: if line.startswith('~^'): startSubpassageName = line[2:] subpassage = startSubpassageName subpassages[subpassage] = [] continue for preparation in preparations: if len(preparation) > 2: line = re.sub(preparation[0],preparation[1],line,0,preparation[2]) else: line = re.sub(preparation[0],preparation[1],line) line_output = '' purges = [ 'CLOSE ALL', 'close all', '*clr & cla', 'killall', 'showstat 0','showstat 1', 'showobjs 0','showobjs 1', 'showinput 0','showinput 1', "gs 'stat'","gs'stat'", ] for purge in purges: line = line.replace(purge,'') pv("AFTER PURGES:",line) #line = line.replace(" mod "," % ") #while match := re.match(r"iif\s*\((.+),(.*),(.*)\)",line): # line = line.replace(match.group(0),f"({convert_condition(match.group(1))}) ? {convert_literal(match.group(2))} : {convert_literal(match.group(3))}") # FUNCTIONS if isfunction: if line.endswith('}'): isfunction = False functionname_sanatized = function_name.replace('$','').replace('[','').replace(']','').replace("'",'') functionlines.append(f':: {functionname_sanatized}_macro[widget]\n<>\n') functionlines_temp = convert_lineblock(functionlines_temp) for fl in functionlines_temp: functionlines.append(f'\t{fl}') functionlines.append(f'<>\n') function_name_conversions.append([function_name,functionname_sanatized]) else: functionlines_temp.append(line) continue if match := re.match(r"""(\$[a-z][a-z0-9\-_'"\[\]]+)\s*=\s*{""",line,re.I): isfunction = True #functionlines.append(f'<>') function_name = match.group(1) functionlines_temp = [] continue pv("AFTER FUNCTIONS:",line) while fuckyoumatch := re.search(r"""\[["']([^\]]*?)<<(.*?)>>(.*?)["']\]""",line): index = f'${fuckyoumatch.group(2)}' #left = '' if fuckyoumatch.group(1): index = f"'{fuckyoumatch.group(1)}'+" + index #right = '' if fuckyoumatch.group(3): index = index + f"+'{fuckyoumatch.group(3)}'" # right = fuckyoumatch.group(3) #index = f"'{left}'+${fuckyoumatch.group(2)}+'{right}'" #print(index) line = line.replace(fuckyoumatch.group(0),f"[{index}]") #print("MATCH") pv("AFTER ARRAY []:",line) while dynevalmatch := re.search(r"""dyneval\s*\(\s*'\s*RESULT\s*=\s*(<<.*?)'\s*\)""",line): fullmatch = dynevalmatch.group(0) varname = dynevalmatch.group(1) varname = varname.replace(r"[''",r"['").replace(r"'']",r"']") varname = "State.getVar('$"+varname.replace('<<',"'+").replace('>>',"+'")+"')" line = line.replace(fullmatch,varname) #print(line) pv("AFTER DYNEVAL:",line) while dynevalmatch := re.search(r"""dyneval\s*\(\s*'\s*RESULT\s*=\s*\$?(.*?)'\s*\)""",line): fullmatch = dynevalmatch.group(0) varname = "$"+dynevalmatch.group(1) varname = varname.replace('<<',"'+").replace('>>',"+'") #varname = varname.replace(r"[''",r"['").replace(r"'']",r"']") varname = varname.replace("['+","[").replace(r"+']",r"]") varname = varname.replace('$$',"$") line = line.replace(fullmatch,varname) pv("AFTER DYNEVAL2:",line) if line.startswith('!{') or line.startswith('!!{') or line == '!!{': line_output = '' else: commenting = True pv("IS COMMENT:",line_output) elif line.endswith('}') and commenting: line_output = line+' -->' commenting = False pv("IS COMMENT:",line_output) elif commenting: line_output = line.replace('--','-') pv("IS COMMENT:",line_output) elif line.lower() == 'end' or line.lower().startswith('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 = '<>' pv("IS END:",line_output) elif line.startswith('!'): line_output = '' pv("IS COMMENT:",line_output) elif line.lower() == 'else': #file.write('<>\n') line_output = '<>' whitespace_count -= 1 pv("IS ELSE:",line_output) elif line.lower() == 'cls': line_output = '' pv("IS CLS:",line_output) elif line.lower() == '*nl': #file.write('\n') line_output = '' pv("IS NL:",line_output) elif line[0:3] == '---': line_output = '' pv("IS EOF:",line_output) elif match := re.match(r"^\s*msg\s*'(.*)'\s*$",line,re.I): msg = match.group(1).replace("'",'"') line_output = f"""<>""" pv("IS MSG:",line_output) elif match := re.match(r"""act\s*'(.*?)\s*\(<> Willpower\)':\s*'
You don''t have enough willpower to use this action.'""",line,re.I): label = match.group(1).replace("'",'"') line_output = f"<>
You don`t have enough willpower to use this action.
<
>" 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'''<>''' pv("IS IMAGE:",line_output) elif match := re.match(r"""^'?(?:
)?>\s+)*(?:\s*autoplay\s*|\s*loop\s*)*src="images\/([\w\/\.]+)(?:'\s*\+\s*rand\((\d+,\d+)\)\s*\+\s*')?([\w\/\.]+)"\s*>(?:<\/video>)?(?:<\/center>)?'?""",line,re.I): #Images if match.group(2): line_output = f'''<