did you miss me? ahh? I bet you did! this week's challenge is to implement ysl, I hear. submissions may be written in any language.
take a gander at this here document, if you please.
YSL specification
YSL
The lines of the program are stored in a sorted map, where the key is integers and the
values are strings which contain a line of code. The interpreter gets a line of code
from here every time a statement is run and parses it with a split function. This split
function splits by any whitespaces unless it's in a string. Example:
print meow "meow meow"
is parsed as:
["print", "meow", "meow meow"]
Elements in this array are referred to as "parts"
Part replacement
Then, the interpreter evaluates variables and other identifiers. A $ prefix on an
identifier means get an integer from a variable. Variables are integer arrays. The string
containing the identifier will be replaced with the first value of the variable's array.
A ! prefix means string. A string is created from the variable's array, where each
element is an ASCII character. A & prefix means the part will be replaced with the
next character's ASCII value.
Passing
Then the parsed array is passed to the function named in the first element. The array
when passed to the function will have the first element removed.
Self modifying
To write to the program's map, the line number is written before the statement. The
line number must also be replaced if it contains an identifier (see Part replacement)
I'm sure we can all agree that this specification is rather terse and ambiguous. worry not, my friend, for in this life you are free!
you alone decide how it should be interpreted. the arbiter of YSL's behaviour is you, dear reader! I encourage you to fill in the
blanks in this specification on your own.
all that being said, your challenge, given a YSL program, is to compile or evaluate it according to the language's semantics. (which are, as
explained previously, decided by you.) as any language is allowed, there is no fixed API.
defimplement_ysl(program:str,line_number=2):print(line_number)# "The lines of the program are stored in a sorted map, where the key is integers# and the values are strings which contain a line of code."integers=lambdas:all(list(filter(str.isdigit,s)))sorted_map=sorted(map(str,program.split('\n')),key=integers)# "The interpreter gets a line of code from here every time a statement is run"statement=Truej=-1whilestatement:defget():nonlocaljj+=1returnsorted_map[j%len(sorted_map)]# "and parses it with a split function."defsplit(line:str):# "This split function splits by any whitespaces unless it's in a string.# Example:# ```# print meow "meow meow"# ```# is parsed as:# ```# ["print", "meow", "meow meow"]# ```"importregexreturn[s.removeprefix('"').removesuffix('"')forsinregex.split(r'(?!(?<=".*)(?=.*")) ',line)]assertsplit('print meow "meow meow"')==['print','meow','meow meow']# "Elements in this array are referred to as "parts""parts=split(get())# "Then, the interpreter evaluates variables and other identifiers."foriinrange(len(parts)):# A $ prefix on an identifier means get an integer from a variable. variable=Noneifparts[i].startswith('$'):variable=parts[i][1:]# "Variables are integer arrays." variables:dict={'':[line_number]}# "The string containing the identifier will be replaced with the# first value of the variable's array."ifarray:=variables.get(variable):parts[i]=array[0]continue# "A ! prefix means string. A string is created from the variable's array,# where each element is an ASCII character."variable=Noneifparts[i].startswith('!'):variable=parts[i][1:]ifarray:=variables.get(variable):parts[i]=ascii(array)continue# "A & prefix means the part will be replaced with the next character's# ASCII value."ifparts[i].startswith('&'):importregexnext_character=regex.match(r'\X',parts[i][1:]).group()importencodings.idnaparts[i]=int.from_bytes(encodings.idna.ToASCII(next_character))continue# "Then the parsed array is passed to the function named in the first element."function_name=parts[0]defpass_to_function(parsed_array:list):function=functions[function_name]function(parsed_array)# The array when passed to the function will have the first element removed."defthe(array:list):array.pop(0)nonlocalline_number,jif(line_number/array[1]*array[0]).is_integer():line_number*=array[0]line_number//=array[1]print(line_number)j=-1functions={'the':the}pass_to_function(parts)# "To write to the program's map, the line number is written before the statement."line_number_is_written=line_numberinpartsifline_number_is_written:statement=line_number# "The line number must also be replaced if it contains an identifier (see Part replacement)"ifstr(line_number).isidentifier():line_number='<Part>'implement_ysl(open('mqpy.YSL','rb').read().decode())
YSL
The lines of the program are stored in a sorted map, where the key is integers and the values are strings which contain a line of code. The interpreter gets a line of code from here every time a statement is run and parses it with a split function. This split function splits by any whitespaces unless it's in a string. Example:
is parsed as:
Elements in this array are referred to as "parts"
Part replacement
Then, the interpreter evaluates variables and other identifiers. A
$
prefix on an identifier means get an integer from a variable. Variables are integer arrays. The string containing the identifier will be replaced with the first value of the variable's array. A!
prefix means string. A string is created from the variable's array, where each element is an ASCII character. A&
prefix means the part will be replaced with the next character's ASCII value.Passing
Then the parsed array is passed to the function named in the first element. The array when passed to the function will have the first element removed.
Self modifying
To write to the program's map, the line number is written before the statement. The line number must also be replaced if it contains an identifier (see Part replacement)