viv-compiler 0.1.0__py3-none-any.whl → 0.1.1__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.
viv_compiler/cli.py CHANGED
@@ -22,16 +22,17 @@ def main() -> None:
22
22
  args = parser.parse_args()
23
23
  # If the user has requested the compiler version, print it and exit
24
24
  if args.version:
25
- print(f"\nviv_compiler {get_version()}\n")
25
+ print(get_version())
26
26
  sys.exit(0)
27
+ # If test mode is not engaged and no source file was provided, error and exit
28
+ if not args.test and not args.input:
29
+ parser.error("Unless the 'test' flag is engaged, an action file must be provided")
27
30
  # If test mode is engaged, invoke the compiler on a test file and exit
31
+ print("\nCompiling...\n", file=sys.stderr)
28
32
  if args.test:
29
33
  _run_smoke_test(args=args)
30
34
  sys.exit(0)
31
- elif not args.input:
32
- parser.error("Unless the 'test' flag is engaged, an action file must be provided")
33
35
  # Otherwise, it's showtime, so let's invoke the compiler
34
- print("\nCompiling...\n", file=sys.stderr)
35
36
  if args.output:
36
37
  path_to_output_file = Path(args.output).expanduser().resolve()
37
38
  if not path_to_output_file.parent.exists():
@@ -152,7 +153,7 @@ def _run_smoke_test(args: argparse.Namespace) -> None:
152
153
  source_file_path=sample_path,
153
154
  default_salience=float(args.default_salience),
154
155
  default_associations=args.default_associations,
155
- default_reaction_priority=float(args.default_priority),
156
+ default_reaction_priority=float(args.default_reaction_priority),
156
157
  debug=False,
157
158
  use_memoization=True,
158
159
  )
@@ -174,7 +175,7 @@ def _invoke_compiler(args: argparse.Namespace) -> CompiledContentBundle:
174
175
  source_file_path=source_file_path,
175
176
  default_salience=float(args.default_salience),
176
177
  default_associations=args.default_associations,
177
- default_reaction_priority=float(args.default_priority),
178
+ default_reaction_priority=float(args.default_reaction_priority),
178
179
  debug=args.debug,
179
180
  use_memoization=args.memoization,
180
181
  )
@@ -211,7 +212,7 @@ def _emit_results(
211
212
  """
212
213
  # If we're to print out the result, let's do so now, via `stdout` (with headers piped to `stderr`)
213
214
  if args.print:
214
- print("\t== Result ==\n", file=sys.stderr)
215
+ print(" == Result ==\n", file=sys.stderr)
215
216
  sys.stdout.write(json.dumps(compiled_content_bundle, indent=2, sort_keys=True))
216
217
  sys.stdout.write("\n\n")
217
218
  # If we're to list out the compiled actions, let's do so now (again via
@@ -223,7 +224,7 @@ def _emit_results(
223
224
  lines.append(action_name)
224
225
  if not action_names:
225
226
  lines.append("N/A")
226
- print(f"\t== Actions ({len(action_names)}) ==\n", file=sys.stderr)
227
+ print(f" == Actions ({len(action_names)}) ==\n", file=sys.stderr)
227
228
  print("\n".join(f"- {line}" for line in lines), file=sys.stderr)
228
229
  print("", file=sys.stderr)
229
230
  # If an output file path has been provided, write the output file to the specified path
@@ -1,5 +1,5 @@
1
1
  from .core import *
2
- from .importer import *
3
- from .postprocessor import *
4
- from .validator import *
2
+ from .includes import *
3
+ from .postprocessing import *
4
+ from .validation import *
5
5
  from .visitor import *
viv_compiler/core/core.py CHANGED
@@ -23,10 +23,10 @@ import viv_compiler.types
23
23
  from typing import Any
24
24
  from pathlib import Path
25
25
  from importlib.resources import files
26
- from .importer import integrate_imported_files
26
+ from .includes import integrate_included_files
27
27
  from .visitor import Visitor
28
- from .postprocessor import postprocess_combined_ast
29
- from .validator import validate_content_bundle
28
+ from .postprocessing import postprocess_combined_ast
29
+ from .validation import validate_content_bundle
30
30
  # noinspection PyUnresolvedReferences
31
31
  from arpeggio.cleanpeg import ParserPEG
32
32
 
@@ -37,7 +37,7 @@ def compile_viv_source_code(
37
37
  default_associations: list[str],
38
38
  default_reaction_priority: float,
39
39
  use_memoization: bool,
40
- debug = False,
40
+ debug=False,
41
41
  ) -> viv_compiler.types.CompiledContentBundle:
42
42
  """Compile the given Viv source file to produce a JSON-serializable compiled content bundle.
43
43
 
@@ -71,7 +71,7 @@ def compile_viv_source_code(
71
71
  # construct an abstract syntax tree (AST).
72
72
  ast: viv_compiler.types.AST = _sanitize_ast(ast=arpeggio.visit_parse_tree(tree, Visitor()))
73
73
  # If there are any include declarations (i.e., import statements), honor those now
74
- combined_ast: viv_compiler.types.CombinedAST = integrate_imported_files(
74
+ combined_ast: viv_compiler.types.CombinedAST = integrate_included_files(
75
75
  viv_parser=viv_parser,
76
76
  ast=ast,
77
77
  entry_point_file_path=source_file_path
@@ -1,10 +1,10 @@
1
1
  """Module that handles importing between Viv files.
2
2
 
3
- The entrypoint function is `integrate_imported_files()`, and everything else is only meant to be
3
+ The entrypoint function is `integrate_included_files()`, and everything else is only meant to be
4
4
  invoked internally, i.e., within this module.
5
5
  """
6
6
 
7
- __all__ = ["integrate_imported_files"]
7
+ __all__ = ["integrate_included_files"]
8
8
 
9
9
  import arpeggio
10
10
  import viv_compiler.types
@@ -14,13 +14,13 @@ from .visitor import Visitor
14
14
  from arpeggio.cleanpeg import ParserPEG
15
15
 
16
16
 
17
- def integrate_imported_files(
17
+ def integrate_included_files(
18
18
  viv_parser: ParserPEG,
19
19
  ast: viv_compiler.types.AST,
20
20
  entry_point_file_path: Path,
21
21
  ) -> viv_compiler.types.CombinedAST:
22
- """Handle any include declarations in the given AST (including any recursive ones) and return a dictionary
23
- containing trope definitions and action definitions.
22
+ """Handle any `include` declarations in the given AST (including any recursive ones)
23
+ and return a dictionary containing trope definitions and action definitions.
24
24
 
25
25
  Args:
26
26
  viv_parser: A prepared Viv parser.
@@ -0,0 +1,69 @@
1
+ """Module that handles the creation of metadata to attach to a compiled content bundle.
2
+
3
+ The entrypoint function is `create_metadata()`.
4
+ """
5
+
6
+ __all__ = ["create_metadata"]
7
+
8
+ import viv_compiler.types
9
+ import viv_compiler.utils
10
+ from viv_compiler import __version__
11
+ from viv_compiler.types import ExpressionDiscriminator
12
+ from viv_compiler.utils import get_all_expressions_of_type
13
+
14
+
15
+ def create_metadata(
16
+ action_definitions: list[viv_compiler.types.ActionDefinition],
17
+ trope_definitions: list[viv_compiler.types.TropeDefinition],
18
+ ) -> viv_compiler.types.CompiledContentBundleMetadata:
19
+ """Return a package containing metadata for the given compiled content bundle.
20
+
21
+ Args:
22
+ action_definitions: List containing all actions in the content bundle.
23
+ trope_definitions: List containing all tropes in the content bundle.
24
+
25
+ Returns:
26
+ A metadata package for the given content bundle.
27
+ """
28
+ metadata = {
29
+ "vivVersion": __version__,
30
+ "referencedEnums": [],
31
+ "referencedFunctionNames": [],
32
+ "itemRoles": [],
33
+ "buildRoles": [],
34
+ "timeOfDayConstrainedReactions": []
35
+ }
36
+ for ast_chunk in action_definitions + trope_definitions:
37
+ # Compile all referenced enums
38
+ all_referenced_enum_names = set(viv_compiler.utils.get_all_referenced_enum_names(ast_chunk=ast_chunk))
39
+ metadata["referencedEnums"].extend(all_referenced_enum_names)
40
+ # Compile all referenced adapter functions
41
+ all_referenced_function_names = set(
42
+ viv_compiler.utils.get_all_referenced_adapter_function_names(ast_chunk=ast_chunk)
43
+ )
44
+ metadata["referencedFunctionNames"].extend(all_referenced_function_names)
45
+ for action_definition in action_definitions:
46
+ # Compile all roles carrying 'item' and 'build' labels
47
+ for role_definition in action_definition["roles"].values():
48
+ if role_definition["item"]:
49
+ metadata["itemRoles"].append({
50
+ "action": action_definition["name"],
51
+ "role": role_definition["name"]
52
+ })
53
+ if role_definition["build"]:
54
+ metadata["buildRoles"].append({
55
+ "action": action_definition["name"],
56
+ "role": role_definition["name"]
57
+ })
58
+ # Compile all reactions referencing time of day
59
+ all_nested_reactions = get_all_expressions_of_type(
60
+ expression_type=ExpressionDiscriminator.REACTION,
61
+ ast_chunk=action_definition
62
+ )
63
+ for reaction in all_nested_reactions:
64
+ if reaction["options"]["when"] and reaction["options"]["when"]["timeOfDay"]:
65
+ metadata["timeOfDayConstrainedReactions"].append({
66
+ "action": action_definition["name"],
67
+ "reaction": reaction["actionName"]
68
+ })
69
+ return metadata
@@ -1,4 +1,4 @@
1
- """Postprocessor for the Viv DSL.
1
+ """Module that handles postprocessing of compiled ASTs for the Viv DSL.
2
2
 
3
3
  This module takes in ASTs produced by the Viv parser (with imports honored) and
4
4
  postprocesses them to produce compiled content bundles that are ready for validation.
@@ -13,9 +13,9 @@ import copy
13
13
  import viv_compiler.config
14
14
  import viv_compiler.types
15
15
  import viv_compiler.utils
16
- from viv_compiler import __version__
17
16
  from typing import Any, cast
18
- from .validator import validate_join_directives, validate_preliminary_action_definitions
17
+ from .validation import validate_join_directives, validate_preliminary_action_definitions
18
+ from .metadata import create_metadata
19
19
 
20
20
 
21
21
  def postprocess_combined_ast(combined_ast: viv_compiler.types.CombinedAST) -> viv_compiler.types.CompiledContentBundle:
@@ -62,15 +62,15 @@ def postprocess_combined_ast(combined_ast: viv_compiler.types.CombinedAST) -> vi
62
62
  # Isolate the trope definitions
63
63
  finalized_trope_definitions = combined_ast["tropes"]
64
64
  # Create metadata to be attached to the compiled content bundle
65
- content_bundle_metadata = _create_metadata(
65
+ content_bundle_metadata = create_metadata(
66
66
  action_definitions=finalized_action_definitions,
67
67
  trope_definitions=finalized_trope_definitions
68
68
  )
69
69
  # Package up and return the compiled content bundle
70
70
  compiled_content_bundle: viv_compiler.types.CompiledContentBundle = {
71
+ "meta": content_bundle_metadata,
71
72
  "tropes": {trope["name"]: trope for trope in finalized_trope_definitions},
72
- "actions": {action["name"]: action for action in finalized_action_definitions},
73
- "meta": content_bundle_metadata
73
+ "actions": {action["name"]: action for action in finalized_action_definitions}
74
74
  }
75
75
  return compiled_content_bundle
76
76
 
@@ -721,29 +721,3 @@ def _attribute_preconditions(
721
721
  )
722
722
  final_action_definitions.append(final_action_definition)
723
723
  return final_action_definitions
724
-
725
-
726
- def _create_metadata(
727
- action_definitions: list[viv_compiler.types.ActionDefinition],
728
- trope_definitions: list[viv_compiler.types.TropeDefinition],
729
- ) -> viv_compiler.types.CompiledContentBundleMetadata:
730
- """Return a package containing metadata for the given compiled content bundle.
731
-
732
- Args:
733
- action_definitions: List containing all actions in the content bundle.
734
- trope_definitions: List containing all tropes in the content bundle.
735
-
736
- Returns:
737
- A metadata package for the given content bundle.
738
- """
739
- metadata = {
740
- "vivVersion": __version__,
741
- "referencedEnums": [],
742
- "referencedFunctionNames": []
743
- }
744
- for ast_chunk in action_definitions + trope_definitions:
745
- all_referenced_enum_names = set(viv_compiler.utils.get_all_referenced_enum_names(ast_chunk=ast_chunk))
746
- metadata["referencedEnums"].extend(all_referenced_enum_names)
747
- all_referenced_function_names = set(viv_compiler.utils.get_all_referenced_enum_names(ast_chunk=ast_chunk))
748
- metadata["referencedFunctionNames"].extend(all_referenced_function_names)
749
- return metadata
@@ -1,4 +1,4 @@
1
- """A library of functions to validate preliminary action definitions and compiled content bundles.
1
+ """Module that handles validation of preliminary action definitions and compiled content bundles.
2
2
 
3
3
  The entrypoint functions are as follows:
4
4
  * `validate_join_directives()`: Invoked prior to handling of action inheritance.
@@ -19,29 +19,6 @@ from importlib import import_module
19
19
  from pydantic import TypeAdapter
20
20
 
21
21
 
22
- # todo do we already ensure all references are anchored in a (valid) role name?
23
- # todo warn or error if precondition references scaled enum?
24
- # todo validate time of day to ensure 0-23 and 0-59
25
- # todo technically you could inject major side effects (e.g. reaction queueing) into trope-fit expressions
26
- # todo ensure closing time period is always later than opening time period
27
- # todo ensure embargo is either permanent or has a declared time period
28
- # todo don't allow reaction to precast same entity multiple times
29
- # todo build roles:
30
- # - they can cast exactly one entity, with no chance and no mean
31
- # - no pool declarations
32
- # - can never be precast
33
- # - preconditions cannot reference build roles
34
- # - don't allow them in embargoes (embargo would not be violable)
35
- # todo apparently the grammar allows e.g. multiple roles fields in an action definition
36
- # - test what happens (presumably last in wins)
37
- # todo make sure times like 88:76 aren't allowed (grammar allows them)
38
- # todo role renaming (make sure new name being duplicate of existing one is already caught)
39
- # - just detect duplicate role names right away post-visitor
40
- # todo prohibit entity references anchored in symbol roles
41
- # - not ideal, but interpreter enforces this at runtime currently
42
- # todo assignments only allowed in scratch and effects
43
-
44
-
45
22
  def validate_join_directives(raw_action_definitions: list[viv_compiler.types.RawActionDefinition]) -> None:
46
23
  """Ensure that the given action definition makes proper use of `join` directives.
47
24
 
@@ -166,7 +166,6 @@ class Visitor(arpeggio.PTNodeVisitor):
166
166
  "partner": False,
167
167
  "recipient": False,
168
168
  "bystander": False,
169
- "subject": False,
170
169
  "absent": False,
171
170
  "precast": False,
172
171
  "build": False,
@@ -641,6 +640,19 @@ class Visitor(arpeggio.PTNodeVisitor):
641
640
  conditional_object['value'].update(child)
642
641
  return conditional_object
643
642
 
643
+ @staticmethod
644
+ def visit_associations_conditional_branches(_, children: Any) -> dict[str, viv_compiler.types.Expression]:
645
+ """Visit a <associations_conditional_branches> node."""
646
+ return {"branches": children}
647
+
648
+ @staticmethod
649
+ def visit_associations_conditional_branch(_, children: Any) -> dict[str, viv_compiler.types.Expression]:
650
+ """Visit a <associations_conditional_branch> node."""
651
+ component = {}
652
+ for child in children:
653
+ component.update(child)
654
+ return component
655
+
644
656
  @staticmethod
645
657
  def visit_associations_conditional_consequent(_, children: Any) -> dict[str, list[viv_compiler.types.Expression]]:
646
658
  """Visit a <associations_conditional_consequent> node."""
@@ -709,10 +721,23 @@ class Visitor(arpeggio.PTNodeVisitor):
709
721
  @staticmethod
710
722
  def visit_conditional(_, children: Any) -> viv_compiler.types.Conditional:
711
723
  """Visit a <conditional> node."""
712
- conditional_object = {"type": ExpressionDiscriminator.CONDITIONAL, "value": {}}
724
+ component = {"type": ExpressionDiscriminator.CONDITIONAL, "value": {}}
713
725
  for child in children:
714
- conditional_object['value'].update(child)
715
- return conditional_object
726
+ component['value'].update(child)
727
+ return component
728
+
729
+ @staticmethod
730
+ def visit_conditional_branches(_, children: Any) -> dict[str, viv_compiler.types.Expression]:
731
+ """Visit a <conditional_branches> node."""
732
+ return {"branches": children}
733
+
734
+ @staticmethod
735
+ def visit_conditional_branch(_, children: Any) -> dict[str, viv_compiler.types.Expression]:
736
+ """Visit a <conditional_branch> node."""
737
+ component = {}
738
+ for child in children:
739
+ component.update(child)
740
+ return component
716
741
 
717
742
  @staticmethod
718
743
  def visit_condition(_, children: Any) -> dict[str, viv_compiler.types.Expression]:
@@ -926,12 +951,13 @@ class Visitor(arpeggio.PTNodeVisitor):
926
951
  # just syntactic sugar for `@this.scratch.`, which means any reference anchored in a global
927
952
  # variable is in fact an entity reference anchored in a role name.
928
953
  anchor = viv_compiler.config.GLOBAL_VARIABLE_REFERENCE_ANCHOR
929
- path = viv_compiler.config.GLOBAL_VARIABLE_REFERENCE_PATH_PREFIX
930
- # Add in the global variable itself, as a property name
931
- path.append({
932
- "type": ReferencePathComponentDiscriminator.REFERENCE_PATH_COMPONENT_PROPERTY_NAME,
933
- "propertyName": children[0]["name"],
934
- })
954
+ path = [
955
+ *viv_compiler.config.GLOBAL_VARIABLE_REFERENCE_PATH_PREFIX,
956
+ {
957
+ "type": ReferencePathComponentDiscriminator.REFERENCE_PATH_COMPONENT_PROPERTY_NAME,
958
+ "name": children[0]["name"],
959
+ }
960
+ ]
935
961
  path += children[1] if len(children) > 1 else []
936
962
  else:
937
963
  anchor = children[0]["name"]
@@ -1063,13 +1089,17 @@ class Visitor(arpeggio.PTNodeVisitor):
1063
1089
  @staticmethod
1064
1090
  def visit_enum(_, children: Any) -> viv_compiler.types.Enum:
1065
1091
  """Visit an <enum> node."""
1066
- scaled = "#" in children # As opposed to ##, which yields an unscaled enum
1067
- additive_inverse_present = "-" in children
1092
+ additive_inverse_present = False
1093
+ if len(children) > 1:
1094
+ additive_inverse_present = children[0] == "-"
1095
+ token = children[-1]
1096
+ unscaled = token[:2] == "##" # As opposed to '#', which yields an scaled enum
1097
+ name = token.lstrip('#')
1068
1098
  component = {
1069
1099
  "type": ExpressionDiscriminator.ENUM,
1070
1100
  "value": {
1071
- "name": children[-1],
1072
- "scaled": scaled,
1101
+ "name": name,
1102
+ "scaled": not unscaled,
1073
1103
  "minus": additive_inverse_present
1074
1104
  }
1075
1105
  }
@@ -57,8 +57,8 @@ binding_pool_directive = binding_pool_from_directive / binding_pool_is_directive
57
57
  binding_pool_from_directive = "from" expression
58
58
  binding_pool_is_directive = "is" expression
59
59
  role_labels = role_label ("," role_label)*
60
- role_label = "initiator" / "partner" / "recipient" / "bystander" / "subject" / "location" /
61
- "symbol" / "absent" / "action" / "item" / "precast" / build_directive
60
+ role_label = "initiator" / "partner" / "recipient" / "bystander" / "location" /
61
+ "symbol" / "absent" / "action" / "item" / "precast" / build_directive
62
62
  build_directive = "build" "(" build_directive_entity_recipe ")"
63
63
  build_directive_entity_recipe = object
64
64
  binding_rate_directive = chance_directive / mean_directive
@@ -94,20 +94,23 @@ time = hh (":" mm)? ("pm" / "am" / "PM" / "AM")
94
94
  hh = r"[0-9]{1,2}"
95
95
  mm = r"[0-9]{2}"
96
96
  abandonment_conditions = "abandon" ":" statements
97
- saliences = child_join_operator? "saliences" saliences_default_value saliences_body?
97
+
98
+ salience_associations_local_variable_name = "c"
99
+
100
+ saliences = (child_join_operator? "saliences" saliences_default_value) /
101
+ (child_join_operator? "saliences" "for" local_variable_sigil salience_associations_local_variable_name saliences_default_value saliences_body?)
98
102
  saliences_default_value = "default" (enum / number)
99
103
  saliences_body = ":" statement+
100
104
 
101
- associations = child_join_operator? "associations" associations_default_value associations_body?
105
+ associations = (child_join_operator? "associations" associations_default_value) /
106
+ (child_join_operator? "associations" "for" local_variable_sigil salience_associations_local_variable_name associations_default_value associations_body?)
102
107
  associations_default_value = "default" tags
103
108
  associations_body = ":" associations_statements
104
109
  associations_statements = associations_statement+
105
110
  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 = associations_conditional_branches ("else:" associations_conditional_alternative)? "end"
112
+ associations_conditional_branches = "if" associations_conditional_branch ("elif" associations_conditional_branch)*
113
+ associations_conditional_branch = condition ":" associations_conditional_consequent
111
114
  associations_conditional_consequent = associations_scoped_statements ""
112
115
  associations_conditional_alternative = associations_scoped_statements ""
113
116
  associations_loop =
@@ -146,7 +149,9 @@ adapter_function_call = "~" name "(" args? ")" eval_fail_safe_marker?
146
149
  args = expression ("," expression)*
147
150
  statements = statement+
148
151
  statement = conditional / loop / reaction / expression / literal
149
- conditional = "if" condition ":" consequent ("else:" alternative)? "end"
152
+ conditional = conditional_branches ("else:" alternative)? "end"
153
+ conditional_branches = "if" conditional_branch ("elif" conditional_branch)*
154
+ conditional_branch = condition ":" consequent
150
155
  condition = expression
151
156
  consequent = scoped_statements ""
152
157
  alternative = scoped_statements ""
@@ -29,12 +29,12 @@ if TYPE_CHECKING:
29
29
 
30
30
  class CompiledContentBundle(TypedDict):
31
31
  """A content bundle in the format produced by the Viv compiler."""
32
+ # Metadata for the content bundle, which is currently used for validation purposes
33
+ meta: CompiledContentBundleMetadata
32
34
  # Trope definitions, keyed by name
33
35
  tropes: dict[TropeName, TropeDefinition]
34
36
  # Action definitions, keyed by name
35
37
  actions: dict[ActionName, ActionDefinition]
36
- # Metadata for the content bundle, which is currently used for validation purposes
37
- meta: CompiledContentBundleMetadata
38
38
 
39
39
 
40
40
  class CompiledContentBundleMetadata(TypedDict):
@@ -57,6 +57,31 @@ class CompiledContentBundleMetadata(TypedDict):
57
57
  # content bundle. This is used for validation during the initialization of
58
58
  # a target application's Viv adapter.
59
59
  referencedFunctionNames: list[AdapterFunctionName]
60
+ # An array specifying all role definitions carrying the `item` label. This is used
61
+ # for validation during the initialization of a target application's Viv adapter.
62
+ itemRoles: list[CompiledContentBundleMetadataRoleEntry]
63
+ # An array specifying all role definitions carrying the `build` label. This is used
64
+ # for validation during the initialization of a target application's Viv adapter.
65
+ buildRoles: list[CompiledContentBundleMetadataRoleEntry]
66
+ # An array specifying all reactions that are constrained by the time of day. This is used
67
+ # for validation during the initialization of a target application's Viv adapter.
68
+ timeOfDayConstrainedReactions: list[CompiledContentBundleMetadataTimeOfDayConstrainedReaction]
69
+
70
+
71
+ class CompiledContentBundleMetadataRoleEntry(TypedDict):
72
+ """A simple record of a case of a role carrying a `build` label, used for validation purposes."""
73
+ # The name of the action containing a role carrying the `build` label
74
+ action: ActionName
75
+ # The name of the role carrying the `build` label
76
+ role: RoleName
77
+
78
+
79
+ class CompiledContentBundleMetadataTimeOfDayConstrainedReaction(TypedDict):
80
+ """A simple record of a case of reaction that is constrained by the time of day, used for validation purposes."""
81
+ # The name of the action containing a reaction that is constrained by the time of day
82
+ action: ActionName
83
+ # The name of the target action of the reaction that is constrained by the time of day
84
+ reaction: ActionName
60
85
 
61
86
 
62
87
  # Unique name for an arbitrary function exposed in a target application's Viv adapter
@@ -175,8 +200,6 @@ class RoleDefinition(TypedDict, total=False):
175
200
  recipient: bool
176
201
  # Whether an entity cast in this role is an uninvolved witness to the associated action
177
202
  bystander: bool
178
- # Whether an entity cast in this role is the subject of the associated action
179
- subject: bool
180
203
  # Whether an entity cast in this role is a character who is not physically present for the associated action
181
204
  absent: bool
182
205
  # Whether this role must be precast via reaction bindings. See Reaction docs for details
@@ -216,13 +216,19 @@ class Conditional(TypedDict):
216
216
 
217
217
  class ConditionalValue(TypedDict, total=False):
218
218
  """The actual expression value for a Viv conditional."""
219
+ # Branches representing the `if` and `elif` clauses in this conditional expression
220
+ branches: list[ConditionalBranch]
221
+ # If an author has provided an alternative body (via an `else` clause), a list
222
+ # of expressions that will be evaluated/executed should the condition not hold.
223
+ alternative: list[Expression]
224
+
225
+
226
+ class ConditionalBranch(TypedDict):
227
+ """A Viv conditional branch, representing an `if` or `elif` clause."""
219
228
  # The condition that will be tested, which holds if its evaluation is truthy
220
229
  condition: Expression
221
230
  # A list of expressions that will be evaluated/executed should the condition hold
222
231
  consequent: list[Expression]
223
- # If an author has provided an alternative body (via an `else` clause), a list
224
- # of expressions that will be evaluated/executed should the condition not hold.
225
- alternative: list[Expression]
226
232
 
227
233
 
228
234
  class Conjunction(NegatableExpression):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: viv-compiler
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Compiler for the DSL of Viv, an action system for emergent narrative.
5
5
  Author-email: James Ryan <mail@jamesryan.ai>
6
6
  License: MIT License
@@ -71,8 +71,6 @@ Install from PyPI:
71
71
  pip install viv-compiler
72
72
  ```
73
73
 
74
- This installs both the `viv_compiler` Python package and the `vivc` command-line interface.
75
-
76
74
  Smoke test to confirm your installation looks good:
77
75
 
78
76
  ```
@@ -156,127 +154,167 @@ vivc --input path/to/source.viv [options]
156
154
 
157
155
  ### Examples
158
156
 
159
- Compile a source file and write the resulting content bundle to file:
157
+ * Compile a source file and write the resulting content bundle to file:
160
158
 
161
- ```
162
- vivc --input /path/to/my-actions.viv --output /path/to/myContentBundle.json
163
- ```
159
+ ```
160
+ vivc --input /path/to/my-actions.viv --output /path/to/myContentBundle.json
161
+ ```
164
162
 
165
- Compile a source file and log the output in the console:
163
+ * Compile a source file and log the output in the console:
166
164
 
167
- ```
168
- vivc --input /path/to/my-actions.viv --print
169
- ```
165
+ ```
166
+ vivc --input /path/to/my-actions.viv --print
167
+ ```
170
168
 
171
- Log the version number for the installed Viv compiler:
169
+ * Log the version number for the installed Viv compiler:
172
170
 
173
- ```
174
- vivc -v
175
- ```
171
+ ```
172
+ vivc -v
173
+ ```
176
174
 
177
175
 
178
176
  ## Python API
179
177
 
180
- The API is intended for programmatic invocation of the compiler.
181
-
178
+ Once you've installed `viv-compiler`, the Viv compiler Python API can be invoked by importing `viv_compiler` into your project.
182
179
 
183
- ### `compile_from_path()`
184
180
 
185
- This function invokes the compiler for a specified Viv source file.
181
+ ### API Reference
186
182
 
187
- **Arguments**
183
+ #### `compile_from_path()`
188
184
 
189
- * `source_file_path` (`Path`)
185
+ * **Purpose**
190
186
 
191
- * Absolute path to a `.viv` source file.
187
+ * Invokes the compiler for a specified Viv source file.
192
188
 
193
- * `default_salience` (`float`)
189
+ * **Arguments**
194
190
 
195
- * Default salience for actions (if unspecified).
191
+ * `source_file_path` (`Path`)
192
+
193
+ * Absolute path to a `.viv` source file.
196
194
 
197
- * `default_associations` `(list[str])`
195
+ * `default_salience` (`float`)
198
196
 
199
- * Default associations for actions (if unspecified).
197
+ * Default salience for actions (if unspecified).
200
198
 
201
- * `default_reaction_priority` (`float`)
199
+ * `default_associations` `(list[str])`
202
200
 
203
- * Default reaction priority for actions (if unspecified).
204
-
205
- * `use_memoization` (`bool`)
201
+ * Default associations for actions (if unspecified).
206
202
 
207
- * Whether to enable memoization in the underlying PEG parser (faster but uses more memory).
203
+ * `default_reaction_priority` (`float`)
204
+
205
+ * Default reaction priority for actions (if unspecified).
206
+
207
+ * `use_memoization` (`bool`)
208
+
209
+ * Whether to enable memoization in the underlying PEG parser (faster but uses more memory).
210
+
211
+ * `debug` (`bool`)
212
+
213
+ * Whether to enable verbose debugging for the underlying PEG parser.
208
214
 
209
- * `debug` (`bool`)
215
+ * **Returns**
210
216
 
211
- * Whether to enable verbose debugging for the underlying PEG parser.
217
+ * The compiled Viv bundle, in a JSON-serializable format conforming to the `CompiledContentBundle` schema defined in the project code.
212
218
 
213
- **Returns**
219
+ * **Raises**
214
220
 
215
- * The compiled Viv bundle, in a JSON-serializable format conforming to the `CompiledContentBundle` schema defined in the project code.
221
+ * `VivCompileError`
222
+
223
+ * Raised when compilation fails.
216
224
 
217
- **Raises**
225
+ * **Example**
218
226
 
219
- * `VivCompileError`
227
+ ```python
228
+ from pathlib import Path
229
+ from viv_compiler import compile_from_path
230
+
231
+ try:
232
+ content_bundle = compile_from_path(source_file_path=Path("my-actions.viv"))
233
+ print("Compilation succeeded:", content_bundle)
234
+ except VivCompileError as e:
235
+ print("Compilation failed:", e)
236
+ ```
220
237
 
221
- * Raised when compilation fails.
222
238
 
239
+ #### `get_version()`
223
240
 
224
- ### `get_version()`
241
+ * **Purpose**
225
242
 
226
- Returns the version string for the currently installed compiler.
243
+ * Returns the version string for the currently installed compiler. All content bundles produced by the compiler will be stamped with the same version number, making them compatible with any Viv runtime with the same version number.
227
244
 
245
+ * **Arguments**
228
246
 
229
- ### `VivCompileError`
247
+ * None.
230
248
 
231
- Custom exception type raised by the API when compilation fails. Inherits from `Exception`.
249
+ * **Returns**
232
250
 
251
+ * A string constituting the version number of the installed Viv compiler.
233
252
 
234
- ### Examples
253
+ * **Example**
235
254
 
236
- Compile a source file:
255
+ ```python
256
+ from viv_compiler import get_version
257
+
258
+ version = get_version()
259
+ print("Viv compiler version:", version)
260
+ ```
237
261
 
238
- ```python
239
- from pathlib import Path
240
- from viv_compiler import compile_from_path, VivCompileError
241
262
 
242
- try:
243
- content_bundle = compile_from_path(source_file_path=Path("my-actions.viv"))
244
- print("Compilation succeeded:", content_bundle)
245
- except VivCompileError as e:
246
- print("Compilation failed:", e)
247
- ```
263
+ #### `VivCompileError`
248
264
 
249
- Print the version number for the installed Viv compiler:
265
+ * **Purpose**
250
266
 
251
- ```python
252
- from viv_compiler import get_version
253
- print(get_version())
254
- ```
267
+ * Custom exception type (inherits from `Exception`) raised by the API when compilation fails.
255
268
 
256
269
 
257
270
  ## Running from Source
258
271
 
259
272
  For contributors or developers working directly from a repo checkout:
260
273
 
261
- ```
262
- # Clone the Viv monorepo
263
- git clone https://github.com/james-owen-ryan/viv
264
- cd viv/compiler
274
+ * Clone the Viv monorepo:
265
275
 
266
- # Create a virtual environment
267
- python -m venv .venv-viv-compiler
268
- source .venv-viv-compiler/bin/activate # macOS/Linux
269
- # Windows PowerShell: .\.venv-viv-compiler\Scripts\Activate.ps1
276
+ ```
277
+ git clone https://github.com/james-owen-ryan/viv
278
+ cd viv/compiler
279
+ ```
270
280
 
271
- # Install the compiler package from source (editable)
272
- python -m pip install -e .
281
+ * Create a virtual environment:
273
282
 
274
- # Invoke the CLI directly
275
- python -m viv_compiler --test
283
+ ```
284
+ python -m venv .venv-viv-compiler
285
+ ```
276
286
 
277
- # Or use the installed console script
278
- vivc --test
279
- ```
287
+ * Activate the virtual environment...
288
+
289
+ * macOS/Linux:
290
+
291
+ ```
292
+ source .venv-viv-compiler/bin/activate
293
+ ```
294
+
295
+ * Windows PowerShell:
296
+
297
+ ```
298
+ .\.venv-viv-compiler\Scripts\Activate.ps1
299
+ ```
300
+
301
+ * Install the compiler package from source (editable):
302
+
303
+ ```
304
+ python -m pip install -e .
305
+ ```
306
+
307
+ * Invoke the CLI directly:
308
+
309
+ ```
310
+ python -m viv_compiler --test
311
+ ```
312
+
313
+ * Or use the installed console script:
314
+
315
+ ```
316
+ vivc --test
317
+ ```
280
318
 
281
319
 
282
320
  ## License
@@ -1,7 +1,7 @@
1
1
  viv_compiler/__init__.py,sha256=qYCGYC46CCguVk7LybHbWlV1b4dPY7K0UOfrEF8k0E8,592
2
2
  viv_compiler/__main__.py,sha256=dyCH7r86O9Nw516E38Gm0gQjcSYDd57dhLGRBPoCi7s,60
3
3
  viv_compiler/api.py,sha256=8vr_WoLEzPSOMRNmovewE2f4b8_-r5xp5PdYc7S2rgc,2164
4
- viv_compiler/cli.py,sha256=6ZMj0TnDNXS99NpOV2Y3CiOVAh-cpknmOACrR_bBmh0,8350
4
+ viv_compiler/cli.py,sha256=BEMXRpOfPal7sri_fzY2zPdeE6QmxgITatfMZoh3HVM,8448
5
5
  viv_compiler/py.typed,sha256=qrkHrYJvGoZpU2BpVLNxJB44LlhqVSKyYOwD_L_1m3s,10
6
6
  viv_compiler/_samples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  viv_compiler/_samples/smoke-test.viv,sha256=hBgnuOvO7A78iDZPTM6Z6xlkaLAA9zgmkuxPVwCLUGQ,152
@@ -9,24 +9,25 @@ viv_compiler/backports/__init__.py,sha256=OozGI7C0wkn6Xjn19DPE_SSdSKX-gRiOQu8yoo
9
9
  viv_compiler/backports/backports.py,sha256=NkZcknH0-iuZczNfGSlL-3yy9FpL9-Y9j_H65TQs_FA,243
10
10
  viv_compiler/config/__init__.py,sha256=A00lpnUKg-q3y_b-cN3jKF9urkGTGjb2Yz_gGc9WCLs,22
11
11
  viv_compiler/config/config.py,sha256=y8R2W2mctP6lbyB_aqIAmJINDIqAAXtzPJrA6lYv-bk,3981
12
- viv_compiler/core/__init__.py,sha256=QHyfqFCifNLT5ZTmLFUMWCURN4BuN2_uY4Z-7wTAeQo,121
13
- viv_compiler/core/core.py,sha256=1ViI19Qa6F_mQbiqbEC7sYyJGH3VbuABI4mqF9xwFik,7828
14
- viv_compiler/core/importer.py,sha256=XRv9wum_V4ll_vHU0pyerwmJW1Nr1IVlA_-ALtmzGxo,4877
15
- viv_compiler/core/postprocessor.py,sha256=EBW8GAJa7Pikln5FzHQEpJ2QfPC66-HOmfAjGIA_HEY,40160
16
- viv_compiler/core/validator.py,sha256=punxJ-2iPBFhyyR0ZePcyQAjMTma3ENr4gIiRKckWzU,42314
17
- viv_compiler/core/visitor.py,sha256=t70j4e6CK363h7ey3W-v2_FbGeu80r4fOTK7npgxRmk,46864
12
+ viv_compiler/core/__init__.py,sha256=ZAU-F0_tXtRWRmw-anqCdZZDabN42nCrIfm_74RdBpE,123
13
+ viv_compiler/core/core.py,sha256=bJzNpf6DM8F1ITn7vmCRxsCELnZ2FgY_23eCxULOGao,7828
14
+ viv_compiler/core/includes.py,sha256=Peth-YttHzbyTB9NXoyBKSDKBJ_NX6MEwOTGEUcHvIg,4879
15
+ viv_compiler/core/metadata.py,sha256=QZToKtisN-ZYNckJsejMaGwXsMSR_TI11MbIuAl8_No,2894
16
+ viv_compiler/core/postprocessing.py,sha256=fgogeBR4U92_dH-GBNDFrZqv9CuzCI1nlx7xHs3j6Iw,39073
17
+ viv_compiler/core/validation.py,sha256=_fYvYxl2keAdF0KFx41c3JIl4EchrI9feVSM8VXj-fE,41000
18
+ viv_compiler/core/visitor.py,sha256=ZF6h_Ebj8nujUbxDjNSxK-U2st_Bl6ZX3UFYeu5jBdE,47931
18
19
  viv_compiler/grammar/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- viv_compiler/grammar/viv.peg,sha256=otsDwXAAE14XmdzgjL4oPYgY651RgVVHVFQmmyde4TE,10538
20
+ viv_compiler/grammar/viv.peg,sha256=9xGvGl_TgNp0oX66um3Z2RQzG8MOJGBrDEiHoW6sP0I,11152
20
21
  viv_compiler/types/__init__.py,sha256=FLwJ0wV_vdR95waeHfZ4YnUIvkK7v8RqR139lpnP1RE,102
21
- viv_compiler/types/content_public_schemas.py,sha256=4yPq3rEUzvKp6WOBoCERZuifUVtl-bXsSen_eQjithw,22019
22
- viv_compiler/types/dsl_public_schemas.py,sha256=UMRoL197O0U-UAnpGHE_XXGzdg1I8S2jyXtV71ekoGI,22318
22
+ viv_compiler/types/content_public_schemas.py,sha256=WOHhgjIhoB-jiqHXDjqmnbY0V-QtxMQO9TBo_vOneo4,23422
23
+ viv_compiler/types/dsl_public_schemas.py,sha256=Jzy3zxtjyrnorgD52Lb39t3GCMd-vSRGKYXdBkG2dQA,22556
23
24
  viv_compiler/types/internal_types.py,sha256=LOU4kT_tjxjU0CXqnqfluV-EBgX2KkhmUOa07B0i1xo,7816
24
25
  viv_compiler/utils/__init__.py,sha256=alIDGBnxWH4JvP-UW-7N99seBBi0r1GV1h8f1ERFBec,21
25
26
  viv_compiler/utils/_version.py,sha256=B40VyT6r1P2PNwgWWItzAYhh25_deCqUcl4EaXq0Beg,88
26
27
  viv_compiler/utils/utils.py,sha256=TwT9VKV1fXVFLToSXO-Cu046Gu2siA_Y7xGog_Zx9pA,7257
27
- viv_compiler-0.1.0.dist-info/licenses/LICENSE,sha256=_N1SL7eyeeqRS4HHgl_n85kuwUSw22qWP6IpQZ9F_M4,1066
28
- viv_compiler-0.1.0.dist-info/METADATA,sha256=GH9QH_XkSBoMYrmmqyTz-hP4EXIdejMDgWzimmgmVFI,7955
29
- viv_compiler-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
- viv_compiler-0.1.0.dist-info/entry_points.txt,sha256=YluMB1bLcPmnfaeAaMAtxXsKCkIEvyhb2dVgkVp55Ko,84
31
- viv_compiler-0.1.0.dist-info/top_level.txt,sha256=fd_4ocrOmLnp5oEnwxv2_Yt_JkluHdKD-Jr5eN__iaE,13
32
- viv_compiler-0.1.0.dist-info/RECORD,,
28
+ viv_compiler-0.1.1.dist-info/licenses/LICENSE,sha256=_N1SL7eyeeqRS4HHgl_n85kuwUSw22qWP6IpQZ9F_M4,1066
29
+ viv_compiler-0.1.1.dist-info/METADATA,sha256=MZmgisVHYAOH3B9lZTgkaZgienTQYfAWrRL_f5e_fTU,8427
30
+ viv_compiler-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ viv_compiler-0.1.1.dist-info/entry_points.txt,sha256=YluMB1bLcPmnfaeAaMAtxXsKCkIEvyhb2dVgkVp55Ko,84
32
+ viv_compiler-0.1.1.dist-info/top_level.txt,sha256=fd_4ocrOmLnp5oEnwxv2_Yt_JkluHdKD-Jr5eN__iaE,13
33
+ viv_compiler-0.1.1.dist-info/RECORD,,