viv-compiler 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,228 @@
1
+ // This is a specification of the syntax of the Viv action language, declared in a variant of extended Backus--Naur
2
+ // form (EBNF) that is associated with the parsing expression grammar (PEG) formalism. More specifically, it is in
3
+ // the format expected by the Arpeggio Python library (version 2.0.0).
4
+
5
+
6
+ // The top-level nonterminal combines include declarations with action and trope definitions, in any order
7
+
8
+ file = (include / trope / action)* EOF
9
+
10
+
11
+ // Include declaration
12
+
13
+ include = "include" filename
14
+ filename = '"' (!'"' ((r'(\w+)' / r'.')))* '"' /
15
+ "'" (!"'" ((r'(\w+)' / r'.')))* "'"
16
+
17
+
18
+ // Action definition
19
+
20
+ action = action_header action_body
21
+ action_header = special_action_tag? "action" name parent_action_declaration? ":"
22
+ parent_action_declaration = "from" name
23
+ action_body = (
24
+ (&"gloss" gloss)? /
25
+ (&"report" report)? /
26
+ (&"saliences" saliences)? /
27
+ (&"associations" associations)? /
28
+ (&"embargoes" embargoes)? /
29
+ (&"tags" tags_field / &"join" tags_field)? /
30
+ (&"roles" roles / &"join" roles)? /
31
+ (&"preconditions" preconditions / &"join" preconditions)? /
32
+ (&"scratch" scratch / &"join" scratch)? /
33
+ (&"effects" effects / &"join" effects)? /
34
+ (&"reactions" reactions / &"join" reactions)?
35
+ )#
36
+
37
+ // Trope definition
38
+
39
+ trope = "trope" name trope_role_names? ":" statements
40
+ trope_role_names = "with" name ("," name)*
41
+
42
+
43
+ // Main components of Viv definitions
44
+
45
+ special_action_tag = "special"
46
+ gloss = "gloss" ":" string
47
+ report = "report" ":" templated_text
48
+ tags_field = child_join_operator? "tags" ":" tags
49
+ tags = tag ("," tag)*
50
+ tag = token
51
+ roles = child_join_operator? "roles" ":" role+
52
+ role = role_renaming / (number_range? binding_rate_directive? role_name binding_pool_directive? ":" role_labels)
53
+ role_renaming = role_name "<<" role_name
54
+ number_range = number ("-" number)?
55
+ role_name = name ""
56
+ binding_pool_directive = binding_pool_from_directive / binding_pool_is_directive
57
+ binding_pool_from_directive = "from" expression
58
+ binding_pool_is_directive = "is" expression
59
+ role_labels = role_label ("," role_label)*
60
+ role_label = "initiator" / "partner" / "recipient" / "bystander" / "subject" / "location" /
61
+ "symbol" / "absent" / "action" / "item" / "precast" / build_directive
62
+ build_directive = "build" "(" build_directive_entity_recipe ")"
63
+ build_directive_entity_recipe = object
64
+ binding_rate_directive = chance_directive / mean_directive
65
+ chance_directive = "[" "-"? r"[0-9]+(\.[0-9]+)?" "%" "]"
66
+ mean_directive = "[" "~" "-"? r"[0-9]+(\.[0-9]+)?" "]"
67
+ preconditions = child_join_operator? "preconditions" ":" statements
68
+ child_join_operator = "join"
69
+ scratch = child_join_operator? "scratch" ":" statements
70
+ effects = child_join_operator? "effects" ":" statements
71
+ reactions = child_join_operator? "reactions" ":" (conditional / loop / reaction)+
72
+ reaction = "queue" reaction_action_name ":" reaction_options
73
+ reaction_action_name = name
74
+ reaction_options = (bindings / urgent? / priority? / kill_code? / when? / where? / abandonment_conditions?)#
75
+ bindings = "bindings" ":" binding+
76
+ binding = (name ":" reference) / loop
77
+ urgent = "urgent" ":" expression
78
+ priority = "priority" ":" expression
79
+ kill_code = "kill_code" ":" expression
80
+ where = "where" ":" expression
81
+ when = "when" (when_action_timestamp_anchor / when_hearing_timestamp_anchor) ":" time_expression
82
+ when_action_timestamp_anchor = "from action"
83
+ when_hearing_timestamp_anchor = "from hearing"
84
+ time_expression = time_statement ("," time_statement)?
85
+ time_statement = before_time_statement / after_time_statement / between_time_statement
86
+ before_time_statement = "before" (time_period / time)
87
+ after_time_statement = "after" (time_period / time)
88
+ between_time_statement = "between" time_period "and" time_period / "between" time "and" time
89
+ time_period = (number / number_word) ("minutes" / "hours" / "days" / "weeks" / "months" / "years" /
90
+ "minute" / "hour" / "day" / "week" / "month" / "year" )
91
+ number_word = "one" / "two" / "three" / "four" / "five" / "six" / "seven" / "eight" / "nine" /
92
+ "ten" / "eleven" / "twelve"
93
+ time = hh (":" mm)? ("pm" / "am" / "PM" / "AM")
94
+ hh = r"[0-9]{1,2}"
95
+ mm = r"[0-9]{2}"
96
+ abandonment_conditions = "abandon" ":" statements
97
+ saliences = child_join_operator? "saliences" saliences_default_value saliences_body?
98
+ saliences_default_value = "default" (enum / number)
99
+ saliences_body = ":" statement+
100
+
101
+ associations = child_join_operator? "associations" associations_default_value associations_body?
102
+ associations_default_value = "default" tags
103
+ associations_body = ":" associations_statements
104
+ associations_statements = associations_statement+
105
+ associations_statement = associations_conditional / associations_loop / tags
106
+ associations_conditional =
107
+ "if" condition ":"
108
+ associations_conditional_consequent
109
+ ("else:" associations_conditional_alternative)?
110
+ "end"
111
+ associations_conditional_consequent = associations_scoped_statements ""
112
+ associations_conditional_alternative = associations_scoped_statements ""
113
+ associations_loop =
114
+ "loop" unary_expression "as" local_variable_reference ":"
115
+ associations_scoped_statements
116
+ "end"
117
+ associations_scoped_statements = (!"end" !"else:" associations_statement)+
118
+
119
+ embargoes = child_join_operator? "embargoes" ":" embargo+
120
+ embargo = embargo_roles? embargo_time_period embargo_location?
121
+ embargo_roles = !embargo_time_period role_name ("," role_name)*
122
+ embargo_time_period = ("for" time_period) / "forever"
123
+ embargo_location = "here" ""
124
+ trope_fit_expression = trope_fit_expression_args &"fits" "fits" name
125
+ trope_fit_expression_args = reference ("," reference)*
126
+ name = (!reserved r"[A-Za-z_][A-Za-z0-9\-_]*")
127
+ reserved = "loop" / "gloss" / "roles" / "preconditions" / "effects" / "reactions" / "saliences" /
128
+ "priority" / "kill_code" / "abandon" / "if" / "else" / "end" / "action" / "when" /
129
+ "where" / "associations" / "special" / "default" / "urgent" / "type" / "__causes__" /
130
+ "__groups__" / "__action__" / "join" / "tags" / "embargoes" / "here" / "include" /
131
+ "report" / "trope" / "fits" / "with" / "scratch"
132
+
133
+
134
+ // High-level language features
135
+
136
+ comment = r"\/\/[^\n]*"
137
+ role_reference = role_reference_sigil name
138
+ role_reference_sigil = "@"
139
+ local_variable_reference = local_variable_sigil name
140
+ local_variable_sigil = "$$"
141
+ global_variable_reference = global_variable_sigil name
142
+ global_variable_sigil = "$"
143
+ role_unpacking = role_unpacking_sigil name
144
+ role_unpacking_sigil = "*"
145
+ adapter_function_call = "~" name "(" args? ")" eval_fail_safe_marker?
146
+ args = expression ("," expression)*
147
+ statements = statement+
148
+ statement = conditional / loop / reaction / expression / literal
149
+ conditional = "if" condition ":" consequent ("else:" alternative)? "end"
150
+ condition = expression
151
+ consequent = scoped_statements ""
152
+ alternative = scoped_statements ""
153
+ scoped_statements = (!"end" !"else:" statement)+
154
+ loop = "loop" unary_expression "as" local_variable_reference ":" scoped_statements "end"
155
+
156
+
157
+ // General expressions
158
+
159
+ expression = assignment_expression / arithmetic_expression / logical_expression / unary_expression
160
+ assignment_expression = &"{" &assignment_lvalue_start "{" assignment_lvalue assignment_operator expression "}" /
161
+ assignment_lvalue assignment_operator expression
162
+ assignment_lvalue = role_anchored_reference / local_variable_anchored_reference
163
+ assignment_lvalue_start = role_reference_sigil / local_variable_sigil / global_variable_sigil
164
+ arithmetic_expression = "{" unary_expression arithmetic_operator expression "}" /
165
+ unary_expression arithmetic_operator expression
166
+ logical_expression = disjunction ''
167
+ disjunction = conjunction ("||" conjunction)* /
168
+ negation? "{" conjunction ("||" conjunction)+ "}" !"&&"
169
+ conjunction = ("{" expression "}" / relational_expression) ("&&" logical_expression)* /
170
+ negation? "{" ("{" expression "}" / relational_expression) ("&&" logical_expression)+ "}"
171
+ relational_expression = negation? "{" unary_expression relational_operator unary_expression "}" /
172
+ unary_expression relational_operator unary_expression /
173
+ unary_expression
174
+ unary_expression = negation? "{" simple_unary_expression "}" / negation? simple_unary_expression
175
+ simple_unary_expression = object / chance_expression / trope_fit_expression / adapter_function_call /
176
+ list / role_anchored_reference / local_variable_anchored_reference /
177
+ role_unpacking / literal
178
+ chance_expression = "-"? r"[0-9]+(\.[0-9]+)?" "%"
179
+ negation = "!"
180
+ assignment_operator = "+=" / "-=" / "*=" / "/=" / "=" / "append" / "remove"
181
+ relational_operator = "==" / "!=" / "<=" / ">=" / "<" / ">" / "in"
182
+ arithmetic_operator = "+" / "-" !">" / "*" / "/"
183
+ literal = enum / string / number / boolean / null_type
184
+
185
+
186
+ // References
187
+
188
+ reference = role_anchored_reference / local_variable_anchored_reference
189
+ role_anchored_reference = (role_reference / global_variable_reference) reference_path?
190
+ local_variable_anchored_reference = local_variable_reference reference_path?
191
+ reference_path = (reference_path_property_name / reference_path_pointer / reference_path_lookup)+
192
+ reference_path_property_name = "." property_name eval_fail_safe_marker?
193
+ reference_path_pointer = "->" property_name eval_fail_safe_marker?
194
+ reference_path_lookup = "[" expression "]" eval_fail_safe_marker?
195
+ property_name = r"[a-zA-Z0-9_]+"
196
+ eval_fail_safe_marker = "?" ""
197
+
198
+
199
+ // Data structures
200
+
201
+ list = "[" (expression ("," expression)*)? "]"
202
+ object = &"{" &object_key_start "{" (key_value_pair ("," key_value_pair)*)? "}"
203
+ object_key_start = '"' / "'" / r"[A-Za-z_]"
204
+ key_value_pair = key ":" value
205
+ key = string / bare_key
206
+ bare_key = r"[A-Za-z_][A-Za-z0-9_\-]*"
207
+ value = expression ''
208
+
209
+
210
+ // Literals
211
+
212
+ number = sign? r"[0-9]*" point r"[0-9]+" / sign? r"[0-9]+" point?
213
+ sign = '-' / '+'
214
+ point = "." / "." // There must be multiple rules to get the point itself to surface
215
+ string = '"' (!'"' (reference / space / character))* '"' /
216
+ "'" (!"'" (reference / space / character))* "'"
217
+ character = r'[^"\'{@*$]+'
218
+ space = r"[ \t]+"
219
+ token = !reserved r"[A-Za-z_][A-Za-z0-9\-_]*"
220
+ boolean = "true" / "false"
221
+ null_type = "null"
222
+ enum = ('-' / '+')? enum_token
223
+ enum_token = r'(##|#)[A-Za-z_][A-Za-z0-9\-_]*'
224
+ templated_text = '"' (!'"' template_gap / template_frame_component_double_quote)+ '"' /
225
+ "'" (!"'" template_gap / template_frame_component_single_quote)+ "'"
226
+ template_frame_component_double_quote = r'[^"{]+'
227
+ template_frame_component_single_quote = r"[^'{]+"
228
+ template_gap = "{" (reference / role_unpacking) "}"
viv_compiler/py.typed ADDED
@@ -0,0 +1 @@
1
+ # PEP 561
@@ -0,0 +1,3 @@
1
+ from .content_public_schemas import *
2
+ from .dsl_public_schemas import *
3
+ from .internal_types import *
@@ -0,0 +1,420 @@
1
+ """Types associated with the higher-level concerns represented in Viv compiled content bundles.
2
+
3
+ This module and `dsl_public_schemas.py` together define the public, stable schema for Viv compiled
4
+ content bundles. The schemas capture the compiler's emitted JSON shapes, which are mirrored in the
5
+ corresponding runtime type definitions, assuming the same version number for the compiler and runtime.
6
+ As such, the schemas constitute a reliable contract between the compiler and any Viv runtime.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Union, Literal, TYPE_CHECKING
12
+ from typing_extensions import TypedDict, NotRequired
13
+
14
+ if TYPE_CHECKING:
15
+ from .dsl_public_schemas import (
16
+ Enum,
17
+ EnumName,
18
+ Expression,
19
+ ExpressionDiscriminator,
20
+ FloatField,
21
+ IntField,
22
+ ListField,
23
+ ObjectField,
24
+ StringField,
25
+ TemplateStringField,
26
+ VariableName,
27
+ )
28
+
29
+
30
+ class CompiledContentBundle(TypedDict):
31
+ """A content bundle in the format produced by the Viv compiler."""
32
+ # Trope definitions, keyed by name
33
+ tropes: dict[TropeName, TropeDefinition]
34
+ # Action definitions, keyed by name
35
+ actions: dict[ActionName, ActionDefinition]
36
+ # Metadata for the content bundle, which is currently used for validation purposes
37
+ meta: CompiledContentBundleMetadata
38
+
39
+
40
+ class CompiledContentBundleMetadata(TypedDict):
41
+ """Metadata on the content bundle.
42
+
43
+ This metadata attaches a Viv version number to the content bundle, which guarantees
44
+ compatibility with any Viv runtime with the same version number.
45
+
46
+ The metadata here is also used to support validation during initialization of a target application's
47
+ Viv adapter by, e.g., confirming that any referenced enums and adapter functions actually exist.
48
+ """
49
+ # The Viv compiler version at the time of compiling this content bundle. If this
50
+ # version number corresponds to the version number for a Viv runtime, the content
51
+ # bundle is guaranteed to be compatible with that runtime.
52
+ vivVersion: str
53
+ # An array containing the names of all enums referenced in the content bundle. This is
54
+ # used for validation during the initialization of a target application's Viv adapter.
55
+ referencedEnums: list[EnumName]
56
+ # An array containing the names of all adapter functions referenced in the
57
+ # content bundle. This is used for validation during the initialization of
58
+ # a target application's Viv adapter.
59
+ referencedFunctionNames: list[AdapterFunctionName]
60
+
61
+
62
+ # Unique name for an arbitrary function exposed in a target application's Viv adapter
63
+ AdapterFunctionName = str
64
+
65
+
66
+ class TropeDefinition(TypedDict):
67
+ """A definition for a Viv trope (reusable bundle of conditions)."""
68
+ # The (unique) name of the trope
69
+ name: TropeName
70
+ # The parameters for the trope. These take entity references as arguments,
71
+ # allowing the conditions to refer to those entities.
72
+ params: list[TropeParamName]
73
+ # The ordered set of conditions composing the trope
74
+ conditions: list[Expression]
75
+
76
+
77
+ # A unique name for a trope
78
+ TropeName = str
79
+
80
+ # A unique trope parameter name
81
+ TropeParamName = str
82
+
83
+
84
+ class ActionDefinition(TypedDict):
85
+ """A compiled definition for a Viv action."""
86
+ # The (unique) name of the action
87
+ name: ActionName
88
+ # Whether this action may only be targeted as a queued reaction (True if so)
89
+ special: bool
90
+ # Name of the parent action from which this one inherited, if any. This field is
91
+ # not currently used by the runtimes, but it can sometimes be useful for debugging.
92
+ parent: ActionName | None
93
+ # Tags on the action, whose purposes will depend on the target application
94
+ tags: ListField
95
+ # Mapping from the names of the roles associated with this action to their respective role definitions
96
+ roles: dict[RoleName, RoleDefinition]
97
+ # Definition for a simple templated string describing this action in a sentence or so
98
+ gloss: StringField | TemplateStringField | None
99
+ # Definition for a more detailed templated string describing this action in a paragraph or so
100
+ report: TemplateStringField | None
101
+ # Preconditions for the action, grouped by role name. A precondition is an expression that
102
+ # must hold (i.e., evaluate to a truthy value) in order for an action to be performed with
103
+ # a prospective cast.
104
+ preconditions: dict[RoleName, list[WrappedExpression]]
105
+ # An ordered set of expressions that prepare a set of temporary variables that may be referenced
106
+ # downstream in the action definition. These temporary variables can be referenced by an author
107
+ # using the `$` sigil, but this is syntactic sugar for `@this.scratch` — e.g., `$foo` is equivalent
108
+ # to `@this.scratch.foo`.
109
+ scratch: list[Expression]
110
+ # An ordered set of expressions that, when executed, cause updates to the target application state
111
+ effects: list[WrappedExpression]
112
+ # A set of expressions that each produce a reaction when evaluated. A reaction specifies an action that
113
+ # may be queued up for some time in the future, should an instance of the one at hand be performed.
114
+ reactions: list[WrappedExpression]
115
+ # Specifications for yielding numeric salience values for the action
116
+ saliences: Saliences
117
+ # Specifications for yielding subjective associations for the action
118
+ associations: Associations
119
+ # Embargo directives, which are authorial levers for controlling the frequency
120
+ # with which an action will be performed in the target application.
121
+ embargoes: list[EmbargoDeclaration]
122
+ # Definition for this role's initiator, copied from the `roles` field,
123
+ # where it also lives, into this top-level property as an optimization.
124
+ initiator: RoleDefinition
125
+
126
+
127
+ # A unique name for an action
128
+ ActionName = str
129
+
130
+
131
+ class RoleDefinition(TypedDict, total=False):
132
+ """A definition for a role in a Viv action definition."""
133
+ # A name for this role, unique only within the associated action definition
134
+ name: RoleName
135
+ # The minimum number of entities to be cast into this role
136
+ min: int
137
+ # The maximum number of entities to be cast into this role
138
+ max: int
139
+ # If specified, the chance that a qualifying entity will be cast into the role. This field was
140
+ # first implemented to support a pattern of specifying how likely it is that a given nearby
141
+ # character will witness an action, which can be accomplished by defining a `bystander` role
142
+ # with a high `max` and a specified `chance` value. Chance values are always guaranteed to
143
+ # fall between `0.0` and `1.0`.
144
+ chance: float | None
145
+ # A mean on which to anchor a distribution from which will be sampled the number of entities
146
+ # to cast into the role. This distribution must also be parameterized by a `sd` value.
147
+ mean: float | None
148
+ # Standard deviation for a distribution from which will be sampled the number of entities
149
+ # to cast into the role. This distribution must also be parameterized by a `mean` value.
150
+ sd: float | None
151
+ # If specified, a directive specifying the pool of entities who may be cast into this role
152
+ # at a given point in time, given an initiator and possibly other prospective role bindings.
153
+ pool: BindingPool | None
154
+ # The name of this role's parent, if any, in the dependency tree that is used
155
+ # during role casting. This dependency tree is used to optimize this process.
156
+ parent: RoleName | None
157
+ # The names of this role's children, if any, in the dependency tree that is
158
+ # used during casting. This dependency tree is used to optimize this process.
159
+ children: list[RoleName]
160
+ # Whether a character must be cast in this role
161
+ character: bool
162
+ # Whether an item must be cast in this role
163
+ item: bool
164
+ # Whether another action must be cast in this role
165
+ action: bool
166
+ # Whether a location must be cast in this role
167
+ location: bool
168
+ # Whether a symbol (some kind of literal value) must be cast in this role
169
+ symbol: bool
170
+ # Whether an entity cast in this role is initiator of the associated action
171
+ initiator: bool
172
+ # Whether an entity cast in this role is a co-initiator of the associated action
173
+ partner: bool
174
+ # Whether an entity cast in this role is a recipient of the associated action
175
+ recipient: bool
176
+ # Whether an entity cast in this role is an uninvolved witness to the associated action
177
+ bystander: bool
178
+ # Whether an entity cast in this role is the subject of the associated action
179
+ subject: bool
180
+ # Whether an entity cast in this role is a character who is not physically present for the associated action
181
+ absent: bool
182
+ # Whether this role must be precast via reaction bindings. See Reaction docs for details
183
+ precast: bool
184
+ # Whether the entity cast in this role is to be constructed as a result of the
185
+ # associated action. Build roles are always accompanied by an entity recipe.
186
+ build: bool
187
+ # For `build` roles only, an expression that evaluates to the recipe for constructing an entity
188
+ # to be cast into the role. The format used here is completely dependent on the target application,
189
+ # but Viv allows authors to specify an arbitrary Viv object. When it's time to build a new entity,
190
+ # the entity recipe will be passed to the `buildEntity()` adapter function, which is tasked with
191
+ # actually constructing the entity.
192
+ entityRecipe: NotRequired[ObjectField]
193
+
194
+
195
+ # A name for an action role (unique only within its action definition)
196
+ RoleName = str
197
+
198
+
199
+ class BindingPool(TypedDict):
200
+ """A directive specifying the pool of entities who may be cast into a role at a given
201
+ point in time, given an initiator and possibly other prospective role bindings.
202
+ """
203
+ # The Viv expression that should evaluate to a binding pool
204
+ body: Expression
205
+ # Whether the binding pool is uncachable. A binding pool is cachable so long as the associated
206
+ # pool declaration does not reference a non-initiator role, in which case the role pool would
207
+ # have to be re-computed if the parent role[s] are re-cast (which never happens with an
208
+ # initiator role). When a binding pool is cached, it is not recomputed even as other
209
+ # non-initiator roles are re-cast.
210
+ uncachable: bool
211
+
212
+
213
+ class Reaction(TypedDict):
214
+ """A Viv reaction expression.
215
+
216
+ A reaction specifies an action that may be queued up for some time in the future,
217
+ should an instance of the one at hand be performed.
218
+ """
219
+ # Discriminator for Viv reaction expressions
220
+ type: Literal[ExpressionDiscriminator.REACTION]
221
+ # The actual expression value
222
+ value: ReactionValue
223
+
224
+
225
+ class ReactionValue(TypedDict):
226
+ """A specification of the parameters defining a reaction."""
227
+ # The name of the target action, i.e., the one queued up by this reaction
228
+ actionName: ActionName
229
+ # Specification for how to precast entities in (a subset of) the roles of the target action
230
+ bindings: list[ReactionBinding]
231
+ # Parameterization of the reaction along various options
232
+ options: ReactionOptions
233
+
234
+
235
+ class ReactionBinding(TypedDict):
236
+ """An expression specifying how to precast a particular role in a reaction's target action."""
237
+ # Discriminator for Viv binding expressions
238
+ type: Literal[ExpressionDiscriminator.BINDING]
239
+ # The actual expression value
240
+ value: ReactionBindingValue
241
+
242
+
243
+ class ReactionBindingValue(TypedDict):
244
+ """Value of a binding expression."""
245
+ # The name of the role in the target action that will be precast via this binding
246
+ role: RoleName
247
+ # An expression that should evaluate to the entity to precast in the role associated with this binding
248
+ entity: Expression
249
+
250
+
251
+ class ReactionOptions(TypedDict, total=False):
252
+ """A set of options parameterizing a reaction."""
253
+ # An expression that should evaluate to a boolean value indicating whether the reaction will queue its
254
+ # target action urgently. (The evaluated value will be cast to a boolean, so authors should be careful
255
+ # here.) Urgent actions receive the highest priority in action queueing.
256
+ urgent: Expression
257
+ # An expression that should evaluate to a numeric value specifying the priority of the queued
258
+ # action. Within a given queue group (urgent or non-urgent), queued actions are targeted in
259
+ # descending order of priority.
260
+ priority: Expression
261
+ # An expression that should evaluate to a string or number constituting a *kill code*. (If a number is
262
+ # produced, it will be coerced into a string, for use as an object key.) When a queued action is performed,
263
+ # its kill code (if any) is asserted, which causes all other queued actions with the same kill code to be
264
+ # dequeued. This supports an authoring pattern where multiple competing reaction alternatives are queued
265
+ # at the same time, each with the same kill code, where only the first one to be targeted successfully
266
+ # will actually be performed. As a concrete example, imagine a character who is punched by someone and
267
+ # whose personality is such that fighting back and running away would each be believable in their own
268
+ # right. Instead of selecting one exclusively, an author can queue both and let it play out by chance,
269
+ # with the winner dequeueing the others. Or they can queue multiple alternatives whose reaction options
270
+ # conditionalize the prospects, such that the evolving state of the storyworld will ultimately decide
271
+ # the winner. In each case, a kill code marks incompatibility between the alternatives, and in turn
272
+ # guarantees that at most one of them will ever be performed. See pp. 618--619 of my PhD thesis for an
273
+ # example of advanced usage of kill codes to coordinate and manage complex potential action sequences.
274
+ killCode: Expression | None
275
+ # An expression that should evaluate to a location, that being the specific location
276
+ # at which the queued action must be performed.
277
+ where: Expression | None
278
+ # A time expression constraining when exactly the queued action may be performed.
279
+ when: TemporalConstraints | None
280
+ # A set of expressions such that, if all of them hold (i.e., evaluate to a truthy value),
281
+ # the queued action will be dequeued.
282
+ abandonmentConditions: list[Expression]
283
+
284
+
285
+ class Saliences(TypedDict):
286
+ """Specifications for determining a numeric salience score for the action that will be held
287
+ by a given character who experiences, observes, or otherwise learns about the action.
288
+ """
289
+ # A specification for a default value to be used as a fallback for any character for
290
+ # which no `body` expressions hold. This will always be structured as a Viv enum,
291
+ # int, or float, where even the enum should resolve to a numeric value.
292
+ default: Union[Enum, IntField, FloatField]
293
+ # The name of the variable to which a character will be bound when computing a salience for
294
+ # them. This allows for evaluation of the body expressions, which may refer to this variable
295
+ # in order to do things like conditionalize salience based on the character at hand.
296
+ variable: VariableName
297
+ # An ordered array of Viv expressions that will each evaluate to a numeric value, as in the
298
+ # `default` property. These will be evaluated in turn, with the first numeric evaluated value
299
+ # being assigned as the character's salience. If no body expression evaluates to a numeric
300
+ # value, the default value will be used.
301
+ body: list[Expression]
302
+
303
+
304
+ class Associations(TypedDict):
305
+ """Specifications for determining the subjective associations for the action that will be held
306
+ by a given character who experiences, observes, or otherwise learns about the action.
307
+ """
308
+ # A specification for a default value to be used as a fallback for any character for which no
309
+ # `body` expressions hold. This will always be structured as a Viv list whose elements will be
310
+ # simple Viv string expressions.
311
+ default: ListField
312
+ # The name of the variable to which a character will be bound when computing associations for
313
+ # them. This allows for evaluation of the body expressions, which may refer to this variable
314
+ # in order to do things like conditionalize associations based on the character at hand.
315
+ variable: VariableName
316
+ # An ordered array of Viv expressions that will each evaluate to Viv lists containing simple
317
+ # Viv string expressions, as in the `default` property. These will be evaluated in turn, with
318
+ # all the results being concatenated together to compose the associations for the character
319
+ # at hand. If no body expression evaluates to a list value, the default value will be used.
320
+ body: list[Expression]
321
+
322
+
323
+ class EmbargoDeclaration(TypedDict):
324
+ """An embargo declaration constraining the subsequent performance of an associated action."""
325
+ # Names for all the roles constituting the bindings over which this embargo holds. For instance,
326
+ # if two roles R1 and R2 were specified here, and if an action A was performed with bindings
327
+ # R1=[E1] and R2=[E2, E3], then this embargo would hold over all cases of A with any prospective
328
+ # bindings that cast E1 in R1 and *either* E2 and/or E3 in R2. Stated differently, the embargo
329
+ # holds if for all roles specified here, some subset overlaps between the embargo role bindings
330
+ # and the prospective role bindings. Often, an embargo will only specify an initiator.
331
+ roles: list[RoleName] | None
332
+ # Whether the embargo is permanent. If so, `period` will always be null, and exactly one of
333
+ # the fields is guaranteed to be truthy.
334
+ permanent: bool
335
+ # For an embargo that is not permanent, a specification of the time period over which the embargo
336
+ # will hold. If `period` is present, `permanent` will always be false, and exactly one of the fields
337
+ # is guaranteed to be truthy.
338
+ period: TimePeriod | None
339
+ # Whether the embargo holds only over a certain location, that being the location
340
+ # at which an instance of the associated action has just been performed.
341
+ here: bool
342
+
343
+
344
+ class TemporalConstraints(TypedDict, total=False):
345
+ """A set of one or more temporal constraints, which an author specifies (in a reaction declaration)
346
+ to control the time at which a queued action may be performed.
347
+ """
348
+ # Whether to anchor the temporal constraints in the timestamp of the action that directly triggered this
349
+ # reaction -- meaning the action whose definition included the reaction declaration -- as opposed to the
350
+ # current simulation timestamp. This distinction only matters for time-period constraints, and specifically
351
+ # for cases where a reaction is triggered because a character has learned about an action after the fact.
352
+ # In such cases, we need to know whether a time-period constraint like "between 1 year and 3 years" holds
353
+ # relative to the timestamp of the original action or relative to the time at which the character learned
354
+ # about the original action.
355
+ useActionTimestamp: bool
356
+ # If specified, a temporal constraint specifying an acceptable range between
357
+ # two points in time, where one end of the range may be open-ended.
358
+ timePeriod: TimePeriodRangeConstraint | None
359
+ # If specified, a temporal constraint specifying an acceptable range between
360
+ # two times of day, where one end of the range may be open-ended.
361
+ timeOfDay: TimeOfDayRangeConstraint | None
362
+
363
+
364
+ class TimePeriodRangeConstraint(TypedDict, total=False):
365
+ """A temporal constraint specifying an acceptable range between two points in time.
366
+ """
367
+ # The point in time at which the range opens. This is specified as a relative time period (e.g., `5 days`)
368
+ # that the target application can resolve at runtime into a point in time (by anchoring it relative to a
369
+ # given simulation timestamp). If no relative time period is specified here, the range is open on this end.
370
+ open: TimePeriod | None
371
+ # The point in time at which the range closes. This is specified as a relative time period (e.g., `5 days`)
372
+ # that the target application can resolve at runtime into a point in time (by anchoring it relative to a
373
+ # given simulation timestamp). If no relative time period is specified here, the range is open on this end.
374
+ close: TimePeriod | None
375
+
376
+
377
+ class TimePeriod(TypedDict):
378
+ """A relative time period (e.g., "2 weeks") that the target application can resolve
379
+ at runtime into a point in time.
380
+ """
381
+ # The number of time units -- e.g., `2` in `2 weeks`
382
+ amount: int
383
+ # The unit of time -- e.g., `weeks` in `2 weeks`
384
+ unit: TemporalConstraintTimeUnit
385
+
386
+
387
+ class TimeOfDayRangeConstraint(TypedDict, total=False):
388
+ """A temporal constraint specifying an acceptable range between two times of day.
389
+ """
390
+ # The time of day that opens the range marked acceptable by the temporal constraint. If no
391
+ # time of day is specified here, the range is open on this end. Note that the target
392
+ # application is tasked with determining whether a given time of day has passed.
393
+ open: TimeOfDay | None
394
+ # The time of day that closes the range marked acceptable by the temporal constraint. If no
395
+ # time of day is specified here, the range is open on this end. Note that the target
396
+ # application is tasked with determining whether a given time of day has passed.
397
+ close: TimeOfDay | None
398
+
399
+
400
+ class TimeOfDay(TypedDict):
401
+ """A specified time of day."""
402
+ # The hour of day
403
+ hour: int
404
+ # The minute of the hour of day
405
+ minute: int
406
+
407
+
408
+ # Enum containing the valid temporal-constraint time units
409
+ TemporalConstraintTimeUnit = Literal["minutes", "hours", "days", "weeks", "months", "years"]
410
+
411
+
412
+ class WrappedExpression(TypedDict):
413
+ """A Viv expression wrapped with an array containing the names of all roles that it references.
414
+
415
+ These reference lists are used for various optimizations.
416
+ """
417
+ # The actual Viv expression that is being wrapped
418
+ body: Expression
419
+ # Names of the roles referenced in the Viv expression
420
+ references: list[RoleName]