123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- #!/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'<<set {convert_literal(split_by_assign[0])} {assign_operator} {convert_literal(split_by_assign[1])}>>'
- if match := re.match(r"^(\$?\w+)\s*(\+=|-=|=)\s*([\$']?\w*'?|\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\))$",command):
- return f'<<set {convert_literal(match.group(1))} {match.group(2)} {convert_literal(match.group(3))}>>'
- 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*([=><!]+)\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"<<set ${match.group(2)} to null>>"
- 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'<!-- GENERATED: {datetime.datetime.now()} -->\n')
- file.write(f'::{location_identifier}\n')
- file.write(f"<<set $here = '{location_identifier}'>>\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('<</if>>\n')
- line_output = '<</if>>'
- elif end_command == 'while':
- #file.write('<</while>>\n')
- line_output = '<</while>>'
- elif end_command == 'act':
- #file.write('<</act>>\n')
- line_output = '<</act>>'
- else:
- print(f'ERROR: UNKNOWN NESTRING: {end_command}')
- else:
- line_output = '<</END>>'
- elif line.lower() == 'else':
- #file.write('<<else>>\n')
- line_output = '<<else>>'
- whitespace_count -= 1
- elif line.lower() == '*nl':
- #file.write('\n')
- line_output = ''
- elif line[0:3] == '---':
- line_output = ''
- elif match := re.match(r"""^'(?:<center>)?<img\s+(?:<<\$?\w+>>\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'''<<image "{match.group(1)}#{match.group(3)}" {match.group(2).replace(',',' ')}>>'''
- else:
- line_output = f'''<<image "{match.group(1)}{match.group(3)}">>'''
- elif match := re.match(r"""^'[\w<>\s=:'"\/\.\(\),\*]+'$""",line):
- #Plain HTML
- line_output = line[1:-1]
- if link_match := re.findall(r"""(<a href="exec:([^"]+)">([^<]+)<\/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"""<<link "{lmatch[2]}">>{convert_command(lmatch[1])}<</link>>""")
- 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'<</{command}>>'
- 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'<</{command}>>'
- 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'<</if>>'
- #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'<p>{line_output[1:-1]}</p>'
- 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')
|