11import csv
22from warnings import warn
33from .yarn_spinner_pb2 import Program as YarnProgram , Instruction
4+ from .vm_std_lib import functions as std_lib_functions
45
56
67class YarnRunner (object ):
@@ -48,6 +49,14 @@ def __lookup_string(self, string_key):
4849 else :
4950 return self .string_lookup_table [string_key ]["text" ]
5051
52+ def __find_label (self , label_key ):
53+ labels = self ._compiled_yarn .nodes [self .current_node ].labels
54+ if label_key in labels :
55+ return labels [label_key ]
56+ else :
57+ raise Exception (
58+ f"The current node `{ self .current_node } ` does not have a label named `{ label_key } " )
59+
5160 def debug_vm (self ):
5261 print (f"VM paused: { self .paused } " )
5362 print (f"VM finished: { self .finished } " )
@@ -61,10 +70,16 @@ def debug_variables(self):
6170 print (self .variables )
6271
6372 def debug_vm_instruction_stack (self ):
64- print (f"The current program counter is: { self ._program_counter } " )
73+ print (f"The current node is: { self .current_node } " )
6574 print ("The current VM instruction stack is:" )
6675 for (idx , instruction ) in enumerate (self ._vm_instruction_stack ):
67- print (f" { idx } : { Instruction .OpCode .Name (instruction .opcode )} " )
76+ arrow = "-->" if idx == self ._program_counter else " "
77+ print (
78+ f"{ arrow } { idx } : { Instruction .OpCode .Name (instruction .opcode )} (" , end = '' )
79+ print (* list (map (lambda o : o .string_value or o .float_value ,
80+ instruction .operands )), sep = ", " , end = ")\n " )
81+ print ("The current labels are:" )
82+ print (self ._compiled_yarn .nodes [self .current_node ].labels )
6883
6984 def debug_program_proto (self ):
7085 print ("The protobuf representation of the current program is:" )
@@ -105,7 +120,14 @@ def add_command_handler(self, command, fn):
105120
106121 ##### OpCode Implementations below here #####
107122
123+ def __jump_to (self , instruction ):
124+ # print(f"Jump from {self._program_counter} ", end='')
125+ self ._program_counter = self .__find_label (
126+ instruction .operands [0 ].string_value )
127+ print (f"to { self ._program_counter } " )
128+
108129 def __go_to_node (self , node_key ):
130+ # print(f"Go from {self.current_node} to node {node_key}")
109131 if node_key not in self ._compiled_yarn .nodes .keys ():
110132 raise Exception (
111133 f"{ node_key } is not a valid node in this Yarn story." )
@@ -147,9 +169,37 @@ def __show_options(self, _instruction):
147169 def __push_float (self , instruction ):
148170 self ._vm_data_stack .insert (0 , instruction .operands [0 ].float_value )
149171
172+ def __jump_if_false (self , instruction ):
173+ if self ._vm_data_stack [0 ] == False :
174+ self .__jump_to (instruction )
175+
150176 def __pop (self , _instruction ):
151177 self ._vm_data_stack .pop (0 )
152178
179+ def __call_func (self , instruction ):
180+ function_name = instruction .operands [0 ].string_value
181+ if function_name not in std_lib_functions :
182+ raise Exception (
183+ f"The internal function `{ function_name } ` is not implemented in this Yarn runtime." )
184+
185+ expected_params , fn = std_lib_functions [function_name ]
186+ actual_params = int (self ._vm_data_stack .pop (0 ))
187+
188+ if expected_params != actual_params :
189+ raise Exception (
190+ f"The internal function `{ function_name } expects { expected_params } parameters but received { actual_params } parameters" )
191+
192+ params = []
193+ while expected_params > 0 :
194+ params .insert (0 , self ._vm_data_stack .pop (0 ))
195+ expected_params -= 1
196+
197+ # invoke the function
198+ ret = fn (params )
199+
200+ # Store the return value on the stack
201+ self ._vm_data_stack .insert (0 , ret )
202+
153203 def __push_variable (self , instruction ):
154204 self ._vm_data_stack .insert (
155205 0 , self .variables [instruction .operands [0 ].string_value ])
@@ -193,7 +243,7 @@ def noop(instruction):
193243 f"OpCode { Instruction .OpCode .Name (instruction .opcode )} is not yet implemented" )
194244
195245 opcode_functions = {
196- Instruction .OpCode .JUMP_TO : noop ,
246+ Instruction .OpCode .JUMP_TO : self . __jump_to ,
197247 Instruction .OpCode .JUMP : noop ,
198248 Instruction .OpCode .RUN_LINE : self .__run_line ,
199249 Instruction .OpCode .RUN_COMMAND : self .__run_command ,
@@ -203,9 +253,9 @@ def noop(instruction):
203253 Instruction .OpCode .PUSH_FLOAT : self .__push_float ,
204254 Instruction .OpCode .PUSH_BOOL : noop ,
205255 Instruction .OpCode .PUSH_NULL : noop ,
206- Instruction .OpCode .JUMP_IF_FALSE : noop ,
256+ Instruction .OpCode .JUMP_IF_FALSE : self . __jump_if_false ,
207257 Instruction .OpCode .POP : self .__pop ,
208- Instruction .OpCode .CALL_FUNC : noop ,
258+ Instruction .OpCode .CALL_FUNC : self . __call_func ,
209259 Instruction .OpCode .PUSH_VARIABLE : self .__push_variable ,
210260 Instruction .OpCode .STORE_VARIABLE : self .__store_variable ,
211261 Instruction .OpCode .STOP : self .__stop ,
0 commit comments