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 +9 -8
- viv_compiler/core/__init__.py +3 -3
- viv_compiler/core/core.py +5 -5
- viv_compiler/core/{importer.py → includes.py} +5 -5
- viv_compiler/core/metadata.py +69 -0
- viv_compiler/core/{postprocessor.py → postprocessing.py} +6 -32
- viv_compiler/core/{validator.py → validation.py} +1 -24
- viv_compiler/core/visitor.py +44 -14
- viv_compiler/grammar/viv.peg +15 -10
- viv_compiler/types/content_public_schemas.py +27 -4
- viv_compiler/types/dsl_public_schemas.py +9 -3
- {viv_compiler-0.1.0.dist-info → viv_compiler-0.1.1.dist-info}/METADATA +111 -73
- {viv_compiler-0.1.0.dist-info → viv_compiler-0.1.1.dist-info}/RECORD +17 -16
- {viv_compiler-0.1.0.dist-info → viv_compiler-0.1.1.dist-info}/WHEEL +0 -0
- {viv_compiler-0.1.0.dist-info → viv_compiler-0.1.1.dist-info}/entry_points.txt +0 -0
- {viv_compiler-0.1.0.dist-info → viv_compiler-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {viv_compiler-0.1.0.dist-info → viv_compiler-0.1.1.dist-info}/top_level.txt +0 -0
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(
|
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.
|
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.
|
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("
|
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"
|
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
|
viv_compiler/core/__init__.py
CHANGED
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 .
|
26
|
+
from .includes import integrate_included_files
|
27
27
|
from .visitor import Visitor
|
28
|
-
from .
|
29
|
-
from .
|
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
|
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 =
|
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 `
|
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__ = ["
|
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
|
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)
|
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
|
-
"""
|
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 .
|
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 =
|
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
|
-
"""
|
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
|
|
viv_compiler/core/visitor.py
CHANGED
@@ -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
|
-
|
724
|
+
component = {"type": ExpressionDiscriminator.CONDITIONAL, "value": {}}
|
713
725
|
for child in children:
|
714
|
-
|
715
|
-
return
|
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 =
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
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
|
-
|
1067
|
-
|
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":
|
1072
|
-
"scaled":
|
1101
|
+
"name": name,
|
1102
|
+
"scaled": not unscaled,
|
1073
1103
|
"minus": additive_inverse_present
|
1074
1104
|
}
|
1075
1105
|
}
|
viv_compiler/grammar/viv.peg
CHANGED
@@ -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" / "
|
61
|
-
|
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
|
-
|
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
|
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
|
-
|
108
|
-
|
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 =
|
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.
|
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
|
-
|
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
|
-
|
181
|
+
### API Reference
|
186
182
|
|
187
|
-
|
183
|
+
#### `compile_from_path()`
|
188
184
|
|
189
|
-
*
|
185
|
+
* **Purpose**
|
190
186
|
|
191
|
-
*
|
187
|
+
* Invokes the compiler for a specified Viv source file.
|
192
188
|
|
193
|
-
*
|
189
|
+
* **Arguments**
|
194
190
|
|
195
|
-
*
|
191
|
+
* `source_file_path` (`Path`)
|
192
|
+
|
193
|
+
* Absolute path to a `.viv` source file.
|
196
194
|
|
197
|
-
* `
|
195
|
+
* `default_salience` (`float`)
|
198
196
|
|
199
|
-
|
197
|
+
* Default salience for actions (if unspecified).
|
200
198
|
|
201
|
-
* `
|
199
|
+
* `default_associations` `(list[str])`
|
202
200
|
|
203
|
-
|
204
|
-
|
205
|
-
* `use_memoization` (`bool`)
|
201
|
+
* Default associations for actions (if unspecified).
|
206
202
|
|
207
|
-
*
|
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
|
-
*
|
215
|
+
* **Returns**
|
210
216
|
|
211
|
-
*
|
217
|
+
* The compiled Viv bundle, in a JSON-serializable format conforming to the `CompiledContentBundle` schema defined in the project code.
|
212
218
|
|
213
|
-
**
|
219
|
+
* **Raises**
|
214
220
|
|
215
|
-
*
|
221
|
+
* `VivCompileError`
|
222
|
+
|
223
|
+
* Raised when compilation fails.
|
216
224
|
|
217
|
-
**
|
225
|
+
* **Example**
|
218
226
|
|
219
|
-
|
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
|
-
|
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
|
-
|
247
|
+
* None.
|
230
248
|
|
231
|
-
|
249
|
+
* **Returns**
|
232
250
|
|
251
|
+
* A string constituting the version number of the installed Viv compiler.
|
233
252
|
|
234
|
-
|
253
|
+
* **Example**
|
235
254
|
|
236
|
-
|
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
|
-
|
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
|
-
|
265
|
+
* **Purpose**
|
250
266
|
|
251
|
-
|
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
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
276
|
+
```
|
277
|
+
git clone https://github.com/james-owen-ryan/viv
|
278
|
+
cd viv/compiler
|
279
|
+
```
|
270
280
|
|
271
|
-
|
272
|
-
python -m pip install -e .
|
281
|
+
* Create a virtual environment:
|
273
282
|
|
274
|
-
|
275
|
-
python -m
|
283
|
+
```
|
284
|
+
python -m venv .venv-viv-compiler
|
285
|
+
```
|
276
286
|
|
277
|
-
|
278
|
-
|
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=
|
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=
|
13
|
-
viv_compiler/core/core.py,sha256=
|
14
|
-
viv_compiler/core/
|
15
|
-
viv_compiler/core/
|
16
|
-
viv_compiler/core/
|
17
|
-
viv_compiler/core/
|
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=
|
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=
|
22
|
-
viv_compiler/types/dsl_public_schemas.py,sha256=
|
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.
|
28
|
-
viv_compiler-0.1.
|
29
|
-
viv_compiler-0.1.
|
30
|
-
viv_compiler-0.1.
|
31
|
-
viv_compiler-0.1.
|
32
|
-
viv_compiler-0.1.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|