Skip to content

Commit 2fdf3f6

Browse files
committed
Add warnings for unimplemented features. Update README.
1 parent e0296b0 commit 2fdf3f6

6 files changed

Lines changed: 71 additions & 28 deletions

File tree

README.md

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,27 +50,10 @@ A few gotchas to look out for:
5050
- Make sure to open the compiled story file as a binary file (see the above example, use `open(filename, 'rb')`) in order for it to be properly parsed by the compiled protobuf library.
5151
- Unless you pass `autostart=False` to the runner when creating it, it will automatically start and run to the next choice point.
5252

53-
All Yarn Spinner opcodes are currently implemented. This may certainly change over time, if new opcodes are added to the language. The current status is:
54-
55-
| OpCode | Status |
56-
| ---------------- | ------------------------------------------------------ |
57-
| `JUMP_TO` |  Implemented in `runner.__jump_to` |
58-
| `JUMP` |  Implemented in `runner.__jump` |
59-
| `RUN_LINE` |  Implemented in `runner.__run_line` |
60-
| `RUN_COMMAND` |  Implemented in `runner.__run_command` |
61-
| `ADD_OPTION` |  Implemented in `runner.__add_option` |
62-
| `SHOW_OPTIONS` |  Implemented in `runner.__show_options` |
63-
| `PUSH_STRING` |  Implemented in `runner.__push_string` |
64-
| `PUSH_FLOAT` |  Implemented in `runner.__push_float` |
65-
| `PUSH_BOOL` |  Implemented in `runner.__push_bool` |
66-
| `PUSH_NULL` |  Implemented in `runner.__push_null` |
67-
| `JUMP_IF_FALSE` |  Implemented in `runner.__jump_if_false` |
68-
| `POP` |  Implemented in `runner.__pop` |
69-
| `CALL_FUNC` |  Implemented in `runner.__call_func` |
70-
| `PUSH_VARIABLE` |  Implemented in `runner.__push_variable` |
71-
| `STORE_VARIABLE` |  Implemented in `runner.__store_variable` |
72-
| `STOP` |  Implemented in `runner.__stop` |
73-
| `RUN_NODE` |  Implemented in `runner.__run_node` |
53+
As of version 2.0, all Yarn Spinner opcodes are currently implemented, as well as Yarn's internal standard library of functions and operators. This may certainly change over time, if new opcodes, functions, or operators are added to the language. The current missing features are:
54+
55+
- Inline expressions [(see Yarn docs)](https://yarnspinner.dev/docs/writing/expressions-and-variables/#inline-expressions)
56+
- Localisation tags and Format functions [(see Yarn syntax reference)](https://yarnspinner.dev/docs/syntax/#localisation-tags)
7457

7558
## Development
7659

examples/expressions.csv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
id,text,file,node,lineNumber
2+
expressions-Start-0,Hello there {0}.,expressions,Start,5

examples/expressions.yarn

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
title: Start
2+
---
3+
<<set $name to "Sam">>
4+
5+
Hello there {$name}.
6+
===

examples/expressions.yarnc

103 Bytes
Binary file not shown.

tests/test_expressions.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import os
2+
from .context import YarnRunner
3+
4+
compiled_yarn_f = open(os.path.join(os.path.dirname(
5+
__file__), '../examples/expressions.yarnc'), 'rb')
6+
names_csv_f = open(os.path.join(os.path.dirname(
7+
__file__), '../examples/expressions.csv'), 'r')
8+
9+
runner = YarnRunner(compiled_yarn_f, names_csv_f, autostart=False)
10+
11+
# TODO: implement a test for expression parsing
12+
13+
14+
def test_expressions():
15+
try:
16+
runner.resume()
17+
18+
# the runner should throw an error
19+
raise Exception(
20+
"The runner ran without any issues. This test should fail. An Exception was expected.")
21+
except Exception as e:
22+
assert str(
23+
e) == "Yarn stories with interpolated inline expressions are not yet supported."

yarnrunner_python/runner.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ def __find_label(self, label_key):
5959
raise Exception(
6060
f"The current node `{self.current_node}` does not have a label named `{label_key}")
6161

62+
def __find_expressions(self, operand):
63+
# TODO: implement this functionality
64+
if int(operand.float_value) != 0:
65+
raise Exception(
66+
f"Yarn stories with interpolated inline expressions are not yet supported.")
67+
6268
def __debug_log(self, msg, **kwargs):
6369
if self._enable_tracing:
6470
print(msg, **kwargs)
@@ -160,21 +166,43 @@ def __go_to_node(self, node_key):
160166
def __run_line(self, instruction):
161167
string_key = instruction.operands[0].string_value
162168

169+
# if this instruction has a second operand, it's the number of expressions
170+
# on the line that need to be evaluated.
171+
if len(instruction.operands) > 1:
172+
line_substitutions = self.__find_expressions(
173+
instruction.operands[1])
174+
# TODO: implement substitutions
175+
163176
self._line_buffer.append(self.__lookup_string(string_key))
164177

165178
def __run_command(self, instruction):
166179
command, *args = instruction.operands[0].string_value.split(" ")
180+
167181
if command not in self._command_handlers.keys():
168182
warn(
169183
f"Command '{command}' does not have a registered command handler.")
170184
else:
171-
# TODO: maybe do some argument parsing later
185+
# if this instruction has a second operand, it's the number of expressions
186+
# on the line that need to be evaluated.
187+
if len(instruction.operands) > 1:
188+
line_substitutions = self.__find_expressions(
189+
instruction.operands[1])
190+
# TODO: implement substitutions
191+
192+
# TODO: maybe do some argument type parsing later
172193
self._command_handlers[command](*args)
173194

174195
def __add_option(self, instruction):
175196
title_string_key = instruction.operands[0].string_value
176197
choice_path = instruction.operands[1].string_value
177198

199+
# if this instruction has a second operand, it's the number of expressions
200+
# on the line that need to be evaluated.
201+
if len(instruction.operands) > 2:
202+
line_substitutions = self.__find_expressions(
203+
instruction.operands[2])
204+
# TODO: implement substitutions
205+
178206
self._option_buffer.append({
179207
'index': len(self._option_buffer),
180208
'text': self.__lookup_string(title_string_key),
@@ -281,12 +309,6 @@ def __process_instruction(self):
281309

282310
instruction = self._vm_instruction_stack[self._program_counter]
283311

284-
def noop(instruction):
285-
if (len(instruction.operands) > 0):
286-
print(instruction.operands)
287-
raise Exception(
288-
f"OpCode {Instruction.OpCode.Name(instruction.opcode)} is not yet implemented")
289-
290312
opcode_functions = {
291313
Instruction.OpCode.JUMP_TO: self.__jump_to,
292314
Instruction.OpCode.JUMP: self.__jump,
@@ -308,6 +330,13 @@ def noop(instruction):
308330
}
309331

310332
self._program_counter += 1
333+
334+
if instruction.opcode not in opcode_functions:
335+
if (len(instruction.operands) > 0):
336+
print(instruction.operands)
337+
raise Exception(
338+
f"OpCode {Instruction.OpCode.Name(instruction.opcode)} is not yet implemented")
339+
311340
opcode_functions[instruction.opcode](instruction)
312341

313342
if not self.paused and not self.finished:

0 commit comments

Comments
 (0)