From 5f0ace085ea78bb1e5fd8febce81b2da17ea858e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 05:01:41 +0000 Subject: [PATCH 01/11] feat(runtime): evaluate the unbounded value `*` and `elem.metadata` `*` in expression position now evaluates to a dedicated unbounded scalar that orders above every finite number, equals itself, prints as `*` in values, traces and solver output, crosses the wire in its own Value arm behind the infinity_value capability, and is refused with a typed error naming the operation in every arithmetic form. `elem.metadata` reads the annotation side table and answers an ordered sequence of materialized metadata instances, including features bound in an annotation body and the metadata type's own defaults, an empty sequence for an unannotated element, and a typed error for a non-element operand. Co-Authored-By: jason.han --- api/proto/sysml.pb.go | 25 +- api/proto/sysml.proto | 4 + .../infinity-and-metadata-values.added.md | 9 + .../org/openmbee/opensysml/Capabilities.java | 3 + .../java/org/openmbee/opensysml/Value.java | 8 + .../openmbee/opensysml/internal/Protos.java | 1 + .../org/openmbee/opensysml/proto/Sysml.java | 349 +++++++++--------- .../org/openmbee/opensysml/proto/Value.java | 128 +++++++ .../opensysml/proto/ValueOrBuilder.java | 23 ++ .../opensysml/conformance/Rendering.java | 2 + clients/node/src/core/capabilities.ts | 2 + clients/node/src/core/index.ts | 1 + clients/node/src/core/values.ts | 7 + clients/node/src/generated/sysml_pb.ts | 12 +- clients/python/opensysml/capabilities.py | 6 + clients/python/opensysml/connection.py | 13 + clients/python/opensysml/document.py | 13 +- clients/python/opensysml/proto/sysml_pb2.py | 164 ++++---- clients/python/opensysml/proto/sysml_pb2.pyi | 6 +- clients/python/opensysml/values.py | 29 +- .../rust/conformance/sysml.descriptor.binpb | Bin 75103 -> 75374 bytes clients/rust/opensysml/src/domain.rs | 4 + .../rust/opensysml/src/proto/sysml/sysml.rs | 7 +- docs/project/spec-compliance.md | 2 + docs/reference/service-transports.md | 7 +- docs/reference/wire-contract.md | 3 + internal/core/parser/expr.go | 24 ++ .../unbounded_and_metadata_access.golden | 40 ++ .../parse/unbounded_and_metadata_access.sysml | 21 ++ internal/core/runtime/conformance_test.go | 6 + internal/core/runtime/eval.go | 37 ++ internal/core/runtime/infinity_test.go | 124 +++++++ .../core/runtime/invoke_calc_body_test.go | 10 +- internal/core/runtime/metadata.go | 101 +++++ internal/core/runtime/metadata_test.go | 166 +++++++++ internal/core/runtime/robustness_test.go | 42 +++ .../runtime/testdata/conformance/README.md | 2 + .../metadata_access_annotations.expected.json | 13 + .../metadata_access_annotations.sysml | 40 ++ ...unbounded_arithmetic_refused.expected.json | 16 + .../value_unbounded_arithmetic_refused.sysml | 17 + .../value_unbounded_comparison.expected.json | 17 + .../value_unbounded_comparison.sysml | 18 + internal/core/semantics/annotations.go | 72 ++++ internal/core/semantics/eval.go | 66 ++++ internal/core/semantics/quantity.go | 2 +- internal/core/semantics/valuetype.go | 4 + internal/core/solve/pin.go | 2 +- internal/grpc/capability_response.go | 4 + internal/grpc/convert.go | 13 +- internal/grpc/convert_infinity_test.go | 144 ++++++++ internal/grpc/service.go | 12 +- internal/repl/docquery.go | 2 +- internal/repl/runtime_commands_test.go | 2 +- 54 files changed, 1556 insertions(+), 289 deletions(-) create mode 100644 changes/unreleased/infinity-and-metadata-values.added.md create mode 100644 internal/core/parser/testdata/parse/unbounded_and_metadata_access.golden create mode 100644 internal/core/parser/testdata/parse/unbounded_and_metadata_access.sysml create mode 100644 internal/core/runtime/infinity_test.go create mode 100644 internal/core/runtime/metadata.go create mode 100644 internal/core/runtime/metadata_test.go create mode 100644 internal/core/runtime/testdata/conformance/metadata_access_annotations.expected.json create mode 100644 internal/core/runtime/testdata/conformance/metadata_access_annotations.sysml create mode 100644 internal/core/runtime/testdata/conformance/value_unbounded_arithmetic_refused.expected.json create mode 100644 internal/core/runtime/testdata/conformance/value_unbounded_arithmetic_refused.sysml create mode 100644 internal/core/runtime/testdata/conformance/value_unbounded_comparison.expected.json create mode 100644 internal/core/runtime/testdata/conformance/value_unbounded_comparison.sysml create mode 100644 internal/grpc/convert_infinity_test.go diff --git a/api/proto/sysml.pb.go b/api/proto/sysml.pb.go index 20790fe15..be5e1161b 100644 --- a/api/proto/sysml.pb.go +++ b/api/proto/sysml.pb.go @@ -3888,6 +3888,7 @@ type Value struct { // *Value_Vector // *Value_VectorQuantity // *Value_MeasurementRef + // *Value_Infinity Kind isValue_Kind `protobuf_oneof:"kind"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -4065,6 +4066,15 @@ func (x *Value) GetMeasurementRef() *MeasurementRef { return nil } +func (x *Value) GetInfinity() bool { + if x != nil { + if x, ok := x.Kind.(*Value_Infinity); ok { + return x.Infinity + } + } + return false +} + type isValue_Kind interface { isValue_Kind() } @@ -4131,6 +4141,13 @@ type Value_MeasurementRef struct { MeasurementRef *MeasurementRef `protobuf:"bytes,15,opt,name=measurement_ref,json=measurementRef,proto3,oneof"` // a unit by itself, no magnitude } +type Value_Infinity struct { + // The unbounded value `*`, which is no number and no string: ordered above + // every finite magnitude and refused by arithmetic. Always true when set, + // as DocumentValue.infinity is. + Infinity bool `protobuf:"varint,16,opt,name=infinity,proto3,oneof"` +} + func (*Value_IntValue) isValue_Kind() {} func (*Value_RealValue) isValue_Kind() {} @@ -4161,6 +4178,8 @@ func (*Value_VectorQuantity) isValue_Kind() {} func (*Value_MeasurementRef) isValue_Kind() {} +func (*Value_Infinity) isValue_Kind() {} + // Array is a Collections::Array: its elements flattened in row-major order // under its dimensions, compared by content rather than by the object read. type Array struct { @@ -6813,7 +6832,7 @@ const file_sysml_proto_rawDesc = "" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x12\n" + "\x04type\x18\x02 \x01(\tR\x04type\x12\"\n" + "\x05value\x18\x03 \x01(\v2\f.sysml.ValueR\x05value\x12\x12\n" + - "\x04unit\x18\x04 \x01(\tR\x04unit\"\x81\x05\n" + + "\x04unit\x18\x04 \x01(\tR\x04unit\"\x9f\x05\n" + "\x05Value\x12\x1d\n" + "\tint_value\x18\x01 \x01(\x03H\x00R\bintValue\x12\x1f\n" + "\n" + @@ -6833,7 +6852,8 @@ const file_sysml_proto_rawDesc = "" + "\x05array\x18\f \x01(\v2\f.sysml.ArrayH\x00R\x05array\x12'\n" + "\x06vector\x18\r \x01(\v2\r.sysml.VectorH\x00R\x06vector\x12@\n" + "\x0fvector_quantity\x18\x0e \x01(\v2\x15.sysml.VectorQuantityH\x00R\x0evectorQuantity\x12@\n" + - "\x0fmeasurement_ref\x18\x0f \x01(\v2\x15.sysml.MeasurementRefH\x00R\x0emeasurementRefB\x06\n" + + "\x0fmeasurement_ref\x18\x0f \x01(\v2\x15.sysml.MeasurementRefH\x00R\x0emeasurementRef\x12\x1c\n" + + "\binfinity\x18\x10 \x01(\bH\x00R\binfinityB\x06\n" + "\x04kind\"Q\n" + "\x05Array\x12\x1e\n" + "\n" + @@ -7373,6 +7393,7 @@ func file_sysml_proto_init() { (*Value_Vector)(nil), (*Value_VectorQuantity)(nil), (*Value_MeasurementRef)(nil), + (*Value_Infinity)(nil), } file_sysml_proto_msgTypes[54].OneofWrappers = []any{ (*Quantity_IntMagnitude)(nil), diff --git a/api/proto/sysml.proto b/api/proto/sysml.proto index 56295b092..9ff7359ae 100644 --- a/api/proto/sysml.proto +++ b/api/proto/sysml.proto @@ -700,6 +700,10 @@ message Value { Vector vector = 13; // numeric components, never a sequence VectorQuantity vector_quantity = 14; // components each with their unit MeasurementRef measurement_ref = 15; // a unit by itself, no magnitude + // The unbounded value `*`, which is no number and no string: ordered above + // every finite magnitude and refused by arithmetic. Always true when set, + // as DocumentValue.infinity is. + bool infinity = 16; } } diff --git a/changes/unreleased/infinity-and-metadata-values.added.md b/changes/unreleased/infinity-and-metadata-values.added.md new file mode 100644 index 000000000..d445c0513 --- /dev/null +++ b/changes/unreleased/infinity-and-metadata-values.added.md @@ -0,0 +1,9 @@ +- **`*` is a value.** In an expression position `*` evaluates to the unbounded value: it exceeds + every finite Integer, Real and Natural, equals itself, prints as `*` in the REPL and in traces, + and crosses gRPC on its own `Value.infinity` arm under the `infinity_value` capability — never + as the ordinary string `"*"`. Arithmetic over it is refused with a typed error naming the + operation rather than an infinity or a NaN. +- **`elem.metadata` reads an element's metadata.** `ref.metadata` yields the metadata annotating + the element as a sequence of metadata instances, in declaration order, with the feature values + the annotation body binds and the metadata type's own defaults where it binds none. An element + with no metadata yields the empty sequence, and reading metadata off a value is a typed error. diff --git a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/Capabilities.java b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/Capabilities.java index 3ea930d94..9105e27a4 100644 --- a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/Capabilities.java +++ b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/Capabilities.java @@ -47,6 +47,9 @@ public final class Capabilities { /** A bare measurement unit ({@code SI::m}, {@code m / s}) travels as itself rather than as an unsupported null. */ public static final String MEASUREMENT_REFS = "measurement_refs"; + /** The unbounded value {@code *} travels as itself rather than as an unsupported null. */ + public static final String INFINITY_VALUE = "infinity_value"; + /** The {@code ApplyEdits} RPC edits a parsed model's own source. */ public static final String APPLY_EDITS = "apply_edits"; diff --git a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/Value.java b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/Value.java index 5273b4c34..d0c816efc 100644 --- a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/Value.java +++ b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/Value.java @@ -67,6 +67,14 @@ record NullValue() implements Value {} */ record UnsetValue() implements Value {} + /** + * The unbounded value {@code *}: no number, ordered above every finite magnitude. + * + *

Only a service advertising the {@code infinity_value} capability reports it as itself rather + * than as an unsupported {@link NullValue}. + */ + record InfinityValue() implements Value {} + /** * A reference to a runtime instance, by the id the service assigned it. * diff --git a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/Protos.java b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/Protos.java index 14882906f..9e347a9dc 100644 --- a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/Protos.java +++ b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/Protos.java @@ -54,6 +54,7 @@ public static Optional value(org.openmbee.opensysml.proto.Value value) { case QUANTITY -> Optional.of(new Value.QuantityValue(quantity(value.getQuantity()))); case ENUM_LITERAL -> Optional.of(new Value.EnumerationValue(literal(value.getEnumLiteral()))); case UNSET -> Optional.of(new Value.UnsetValue()); + case INFINITY -> Optional.of(new Value.InfinityValue()); case ARRAY -> Optional.of(array(value.getArray())); case VECTOR -> Optional.of(vector(value.getVector())); case VECTOR_QUANTITY -> Optional.of(vectorQuantity(value.getVectorQuantity())); diff --git a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/Sysml.java b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/Sysml.java index 40c5f03e6..1a843e626 100644 --- a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/Sysml.java +++ b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/Sysml.java @@ -699,7 +699,7 @@ public static void registerAllExtensions( "\030\001 \001(\tR\005lower\022\024\n\005upper\030\002 \001(\tR\005upper\"o\n\rA" + "ttributeInfo\022\022\n\004name\030\001 \001(\tR\004name\022\022\n\004type" + "\030\002 \001(\tR\004type\022\"\n\005value\030\003 \001(\0132\014.sysml.Valu" + - "eR\005value\022\022\n\004unit\030\004 \001(\tR\004unit\"\201\005\n\005Value\022\035" + + "eR\005value\022\022\n\004unit\030\004 \001(\tR\004unit\"\237\005\n\005Value\022\035" + "\n\tint_value\030\001 \001(\003H\000R\010intValue\022\037\n\nreal_va" + "lue\030\002 \001(\001H\000R\trealValue\022\037\n\nbool_value\030\003 \001" + "(\010H\000R\tboolValue\022#\n\014string_value\030\004 \001(\tH\000R" + @@ -715,178 +715,179 @@ public static void registerAllExtensions( "orH\000R\006vector\022@\n\017vector_quantity\030\016 \001(\0132\025." + "sysml.VectorQuantityH\000R\016vectorQuantity\022@" + "\n\017measurement_ref\030\017 \001(\0132\025.sysml.Measurem" + - "entRefH\000R\016measurementRefB\006\n\004kind\"Q\n\005Arra" + - "y\022\036\n\ndimensions\030\001 \003(\003R\ndimensions\022(\n\010ele" + - "ments\030\002 \003(\0132\014.sysml.ValueR\010elements\"6\n\006V" + - "ector\022,\n\ncomponents\030\001 \003(\0132\014.sysml.ValueR" + - "\ncomponents\"A\n\016VectorQuantity\022/\n\ncompone" + - "nts\030\001 \003(\0132\017.sysml.QuantityR\ncomponents\";" + - "\n\007Complex\022\022\n\004real\030\001 \001(\001R\004real\022\034\n\timagina" + - "ry\030\002 \001(\001R\timaginary\"g\n\013EnumLiteral\022\035\n\nli" + - "teral_id\030\001 \001(\tR\tliteralId\022%\n\016enumeration" + - "_id\030\002 \001(\tR\renumerationId\022\022\n\004name\030\003 \001(\tR\004" + - "name\"9\n\rValueSequence\022(\n\010elements\030\001 \003(\0132" + - "\014.sysml.ValueR\010elements\"\251\001\n\010Quantity\022%\n\r" + - "int_magnitude\030\001 \001(\003H\000R\014intMagnitude\022\'\n\016r" + - "eal_magnitude\030\002 \001(\001H\000R\rrealMagnitude\022\022\n\004" + - "unit\030\003 \001(\tR\004unit\022,\n\tunit_term\030\004 \001(\0132\017.sy" + - "sml.UnitTermR\010unitTermB\013\n\tmagnitude\"k\n\016M" + - "easurementRef\022\022\n\004unit\030\001 \001(\tR\004unit\022,\n\tuni" + - "t_term\030\002 \001(\0132\017.sysml.UnitTermR\010unitTerm\022" + - "\027\n\007unit_id\030\003 \001(\tR\006unitId\"q\n\010UnitTerm\022\033\n\t" + - "scale_num\030\001 \001(\001R\010scaleNum\022\033\n\tscale_den\030\002" + - " \001(\001R\010scaleDen\022+\n\007factors\030\003 \003(\0132\021.sysml." + - "UnitFactorR\007factors\"A\n\nUnitFactor\022\027\n\007uni" + - "t_id\030\001 \001(\tR\006unitId\022\032\n\010exponent\030\002 \001(\001R\010ex" + - "ponent\"c\n\nDiagnostic\022\032\n\010severity\030\001 \001(\tR\010" + - "severity\022\030\n\007message\030\002 \001(\tR\007message\022\037\n\004sp" + - "an\030\003 \001(\0132\013.sysml.SpanR\004span\"\212\001\n\004Span\022\022\n\004" + - "file\030\001 \001(\tR\004file\022\035\n\nstart_line\030\002 \001(\005R\tst" + - "artLine\022\033\n\tstart_col\030\003 \001(\005R\010startCol\022\031\n\010" + - "end_line\030\004 \001(\005R\007endLine\022\027\n\007end_col\030\005 \001(\005" + - "R\006endCol\"\023\n\021ServerInfoRequest\"R\n\022ServerI" + - "nfoResponse\022\030\n\007version\030\001 \001(\tR\007version\022\"\n" + - "\014capabilities\030\002 \003(\tR\014capabilities\"p\n\014Que" + - "ryRequest\022\035\n\nmodel_hash\030\001 \001(\tR\tmodelHash" + - "\022\"\n\005query\030\002 \001(\0132\014.sysml.QueryR\005query\022\035\n\n" + - "oslc_query\030\003 \001(\tR\toslcQuery\"F\n\rQueryResp" + - "onse\0225\n\010elements\030\001 \003(\0132\031.sysml.QueryResu" + - "ltElementR\010elements\"^\n\005Query\022\024\n\005scope\030\001 " + - "\003(\tR\005scope\022\026\n\006select\030\002 \003(\tR\006select\022\'\n\005wh" + - "ere\030\003 \001(\0132\021.sysml.ConstraintR\005where\"\222\001\n\n" + - "Constraint\022:\n\tprimitive\030\001 \001(\0132\032.sysml.Pr" + - "imitiveConstraintH\000R\tprimitive\022:\n\tcompos" + - "ite\030\002 \001(\0132\032.sysml.CompositeConstraintH\000R" + - "\tcompositeB\014\n\nconstraint\"\227\001\n\023PrimitiveCo" + - "nstraint\022\030\n\007inverse\030\001 \001(\010R\007inverse\022\032\n\010pr" + - "operty\030\002 \001(\tR\010property\0224\n\010operator\030\003 \001(\016" + - "2\030.sysml.PrimitiveOperatorR\010operator\022\024\n\005" + - "value\030\004 \003(\tR\005value\"~\n\023CompositeConstrain" + - "t\0224\n\010operator\030\001 \001(\0162\030.sysml.CompositeOpe" + - "ratorR\010operator\0221\n\nconstraint\030\002 \003(\0132\021.sy" + - "sml.ConstraintR\nconstraint\"\302\001\n\022QueryResu" + - "ltElement\022\016\n\002id\030\001 \001(\tR\002id\022\022\n\004type\030\002 \001(\tR" + - "\004type\022I\n\nproperties\030\003 \003(\0132).sysml.QueryR" + - "esultElement.PropertiesEntryR\nproperties" + - "\032=\n\017PropertiesEntry\022\020\n\003key\030\001 \001(\tR\003key\022\024\n" + - "\005value\030\002 \001(\tR\005value:\0028\001\"\220\001\n\nSweepRange\022\034" + - "\n\tparameter\030\001 \001(\tR\tparameter\022\"\n\005start\030\002 " + - "\001(\0132\014.sysml.ValueR\005start\022\036\n\003end\030\003 \001(\0132\014." + - "sysml.ValueR\003end\022 \n\004step\030\004 \001(\0132\014.sysml.V" + - "alueR\004step\"\244\003\n\017RunSweepRequest\022\035\n\nmodel_" + - "hash\030\001 \001(\tR\tmodelHash\022\033\n\tsymbol_id\030\002 \001(\t" + - "R\010symbolId\022*\n\021subject_symbol_id\030\003 \001(\tR\017s" + - "ubjectSymbolId\022*\n\targuments\030\004 \003(\0132\014.sysm" + - "l.ValueR\targuments\022S\n\017named_arguments\030\005 " + - "\003(\0132*.sysml.RunSweepRequest.NamedArgumen" + - "tsEntryR\016namedArguments\022)\n\006ranges\030\006 \003(\0132" + - "\021.sysml.SweepRangeR\006ranges\022\030\n\007samples\030\007 " + - "\001(\003R\007samples\022\022\n\004seed\030\010 \001(\004R\004seed\032O\n\023Name" + - "dArgumentsEntry\022\020\n\003key\030\001 \001(\tR\003key\022\"\n\005val" + - "ue\030\002 \001(\0132\014.sysml.ValueR\005value:\0028\001\"\210\002\n\010Sw" + - "eepRow\022)\n\006inputs\030\001 \003(\0132\021.sysml.CalcOutpu" + - "tR\006inputs\022+\n\007outputs\030\002 \003(\0132\021.sysml.CalcO" + - "utputR\007outputs\022*\n\010verdicts\030\003 \003(\0132\016.sysml" + - ".VerdictR\010verdicts\022%\n\016elapsed_micros\030\004 \001" + - "(\003R\relapsedMicros\022\024\n\005error\030\005 \001(\tR\005error\022" + - ";\n\016failure_reason\030\006 \001(\0162\024.sysml.FailureR" + - "easonR\rfailureReason\"\274\002\n\020RunSweepRespons" + - "e\022#\n\004rows\030\001 \003(\0132\017.sysml.SweepRowR\004rows\022\036" + - "\n\nparameters\030\002 \003(\tR\nparameters\022\030\n\007sample" + - "d\030\003 \001(\010R\007sampled\022\022\n\004seed\030\004 \001(\004R\004seed\022\024\n\005" + - "error\030\005 \001(\tR\005error\0223\n\013diagnostics\030\006 \003(\0132" + - "\021.sysml.DiagnosticR\013diagnostics\022;\n\016failu" + - "re_reason\030\007 \001(\0162\024.sysml.FailureReasonR\rf" + - "ailureReason\022-\n\tinstances\030\010 \003(\0132\017.sysml." + - "InstanceR\tinstances\"\214\001\n\027RunDocumentQuery" + - "Request\022\035\n\nmodel_hash\030\001 \001(\tR\tmodelHash\022\031" + - "\n\010query_id\030\002 \001(\tR\007queryId\0227\n\010bindings\030\003 " + - "\003(\0132\033.sysml.DocumentQueryBindingR\010bindin" + - "gs\"b\n\024DocumentQueryBinding\022\034\n\tparameter\030" + - "\001 \001(\tR\tparameter\022,\n\006values\030\002 \003(\0132\024.sysml" + - ".DocumentValueR\006values\"\256\002\n\rDocumentValue" + - "\022\037\n\nelement_id\030\001 \001(\tH\000R\telementId\022#\n\014str" + - "ing_value\030\002 \001(\tH\000R\013stringValue\022\035\n\tint_va" + - "lue\030\003 \001(\003H\000R\010intValue\022\037\n\nreal_value\030\004 \001(" + - "\001H\000R\trealValue\022\037\n\nbool_value\030\005 \001(\010H\000R\tbo" + - "olValue\022\034\n\010infinity\030\006 \001(\010H\000R\010infinity\022-\n" + - "\010quantity\030\010 \001(\0132\017.sysml.QuantityH\000R\010quan" + - "tity\022!\n\014element_type\030\007 \001(\tR\013elementTypeB" + - "\006\n\004kind\")\n\023DocumentQueryColumn\022\022\n\004name\030\001" + - " \001(\tR\004name\"A\n\021DocumentQueryCell\022,\n\006value" + - "s\030\001 \003(\0132\024.sysml.DocumentValueR\006values\"r\n" + - "\020DocumentQueryRow\022.\n\007element\030\001 \001(\0132\024.sys" + - "ml.DocumentValueR\007element\022.\n\005cells\030\002 \003(\013" + - "2\030.sysml.DocumentQueryCellR\005cells\"}\n\030Run" + - "DocumentQueryResponse\0224\n\007columns\030\001 \003(\0132\032" + - ".sysml.DocumentQueryColumnR\007columns\022+\n\004r" + - "ows\030\002 \003(\0132\027.sysml.DocumentQueryRowR\004rows" + - "\"W\n\025RenderDocumentRequest\022\035\n\nmodel_hash\030" + - "\001 \001(\tR\tmodelHash\022\037\n\013document_id\030\002 \001(\tR\nd" + - "ocumentId\"4\n\026RenderDocumentResponse\022\032\n\010m" + - "arkdown\030\001 \001(\tR\010markdown*\223\001\n\rFailureReaso" + - "n\022\036\n\032FAILURE_REASON_UNSPECIFIED\020\000\022\035\n\031FAI" + - "LURE_REASON_EVALUATION\020\001\022\035\n\031FAILURE_REAS" + - "ON_WRONG_KIND\020\002\022$\n FAILURE_REASON_AMBIGU" + - "OUS_SUBJECT\020\003*\235\004\n\013EditFailure\022\034\n\030EDIT_FA" + - "ILURE_UNSPECIFIED\020\000\022\036\n\032EDIT_FAILURE_NO_O" + - "PERATIONS\020\001\022\037\n\033EDIT_FAILURE_UNKNOWN_TARG" + - "ET\020\002\022!\n\035EDIT_FAILURE_AMBIGUOUS_TARGET\020\003\022" + - "\033\n\027EDIT_FAILURE_NOT_VALUED\020\004\022\036\n\032EDIT_FAI" + - "LURE_INVALID_VALUE\020\005\022\035\n\031EDIT_FAILURE_INV" + - "ALID_NAME\020\006\022\032\n\026EDIT_FAILURE_NOT_NAMED\020\007\022" + - "\"\n\036EDIT_FAILURE_RENAME_REFERENCED\020\010\022\"\n\036E" + - "DIT_FAILURE_OVERLAPPING_EDITS\020\t\022\037\n\033EDIT_" + - "FAILURE_RESULT_INVALID\020\n\022\036\n\032EDIT_FAILURE" + - "_OWNER_UNKNOWN\020\013\022$\n EDIT_FAILURE_OWNER_N" + - "OT_NAMESPACE\020\014\022\035\n\031EDIT_FAILURE_ILLEGAL_K" + - "IND\020\r\022\"\n\036EDIT_FAILURE_MEMBER_NAME_TAKEN\020" + - "\016\022\"\n\036EDIT_FAILURE_DELETE_REFERENCED\020\017*\222\001" + - "\n\021PrimitiveOperator\022\"\n\036PRIMITIVE_OPERATO" + - "R_UNSPECIFIED\020\000\022\034\n\030PRIMITIVE_OPERATOR_EQ" + - "UAL\020\001\022\036\n\032PRIMITIVE_OPERATOR_GREATER\020\002\022\033\n" + - "\027PRIMITIVE_OPERATOR_LESS\020\003*n\n\021CompositeO" + - "perator\022\"\n\036COMPOSITE_OPERATOR_UNSPECIFIE" + - "D\020\000\022\032\n\026COMPOSITE_OPERATOR_AND\020\001\022\031\n\025COMPO" + - "SITE_OPERATOR_OR\020\0022\244\013\n\014SysMLService\022D\n\rG" + - "etServerInfo\022\030.sysml.ServerInfoRequest\032\031" + - ".sysml.ServerInfoResponse\022>\n\tParseFile\022\027" + - ".sysml.ParseFileRequest\032\030.sysml.ParseFil" + - "eResponse\022G\n\014ParseSources\022\032.sysml.ParseS" + - "ourcesRequest\032\033.sysml.ParseSourcesRespon" + - "se\022;\n\tGetSymbol\022\027.sysml.GetSymbolRequest" + - "\032\025.sysml.SymbolResponse\022G\n\016GetDiagnostic" + - "s\022\031.sysml.DiagnosticsRequest\032\032.sysml.Dia" + - "gnosticsResponse\022;\n\010Evaluate\022\026.sysml.Eva" + - "luateRequest\032\027.sysml.EvaluateResponse\022D\n" + - "\013Instantiate\022\031.sysml.InstantiateRequest\032" + - "\032.sysml.InstantiateResponse\022J\n\rExecuteAc" + - "tion\022\033.sysml.ExecuteActionRequest\032\034.sysm" + - "l.ExecuteActionResponse\022G\n\014ExecuteState\022" + - "\032.sysml.ExecuteStateRequest\032\033.sysml.Exec" + - "uteStateResponse\0228\n\007Convert\022\025.sysml.Conv" + - "ertRequest\032\026.sysml.ConvertResponse\022A\n\nAp" + - "plyEdits\022\030.sysml.ApplyEditsRequest\032\031.sys" + - "ml.ApplyEditsResponse\022S\n\020VerifyConstrain" + - "t\022\036.sysml.VerifyConstraintRequest\032\037.sysm" + - "l.VerifyConstraintResponse\022V\n\021VerifyRequ" + - "irement\022\037.sysml.VerifyRequirementRequest" + - "\032 .sysml.VerifyRequirementResponse\022Y\n\022Ve" + - "rifySatisfaction\022 .sysml.VerifySatisfact" + - "ionRequest\032!.sysml.VerifySatisfactionRes" + - "ponse\022G\n\014EvaluateCalc\022\032.sysml.EvaluateCa" + - "lcRequest\032\033.sysml.EvaluateCalcResponse\022D" + - "\n\013RunAnalysis\022\031.sysml.RunAnalysisRequest" + - "\032\032.sysml.RunAnalysisResponse\022;\n\010RunSweep" + - "\022\026.sysml.RunSweepRequest\032\027.sysml.RunSwee" + - "pResponse\0222\n\005Query\022\023.sysml.QueryRequest\032" + - "\024.sysml.QueryResponse\022S\n\020RunDocumentQuer" + - "y\022\036.sysml.RunDocumentQueryRequest\032\037.sysm" + - "l.RunDocumentQueryResponse\022M\n\016RenderDocu" + - "ment\022\034.sysml.RenderDocumentRequest\032\035.sys" + - "ml.RenderDocumentResponseBJ\n\034org.openmbe", - "e.opensysml.protoP\001Z(github.com/Open-MBE" + - "E/OpenSysML/api/protob\006proto3" + "entRefH\000R\016measurementRef\022\034\n\010infinity\030\020 \001" + + "(\010H\000R\010infinityB\006\n\004kind\"Q\n\005Array\022\036\n\ndimen" + + "sions\030\001 \003(\003R\ndimensions\022(\n\010elements\030\002 \003(" + + "\0132\014.sysml.ValueR\010elements\"6\n\006Vector\022,\n\nc" + + "omponents\030\001 \003(\0132\014.sysml.ValueR\ncomponent" + + "s\"A\n\016VectorQuantity\022/\n\ncomponents\030\001 \003(\0132" + + "\017.sysml.QuantityR\ncomponents\";\n\007Complex\022" + + "\022\n\004real\030\001 \001(\001R\004real\022\034\n\timaginary\030\002 \001(\001R\t" + + "imaginary\"g\n\013EnumLiteral\022\035\n\nliteral_id\030\001" + + " \001(\tR\tliteralId\022%\n\016enumeration_id\030\002 \001(\tR" + + "\renumerationId\022\022\n\004name\030\003 \001(\tR\004name\"9\n\rVa" + + "lueSequence\022(\n\010elements\030\001 \003(\0132\014.sysml.Va" + + "lueR\010elements\"\251\001\n\010Quantity\022%\n\rint_magnit" + + "ude\030\001 \001(\003H\000R\014intMagnitude\022\'\n\016real_magnit" + + "ude\030\002 \001(\001H\000R\rrealMagnitude\022\022\n\004unit\030\003 \001(\t" + + "R\004unit\022,\n\tunit_term\030\004 \001(\0132\017.sysml.UnitTe" + + "rmR\010unitTermB\013\n\tmagnitude\"k\n\016Measurement" + + "Ref\022\022\n\004unit\030\001 \001(\tR\004unit\022,\n\tunit_term\030\002 \001" + + "(\0132\017.sysml.UnitTermR\010unitTerm\022\027\n\007unit_id" + + "\030\003 \001(\tR\006unitId\"q\n\010UnitTerm\022\033\n\tscale_num\030" + + "\001 \001(\001R\010scaleNum\022\033\n\tscale_den\030\002 \001(\001R\010scal" + + "eDen\022+\n\007factors\030\003 \003(\0132\021.sysml.UnitFactor" + + "R\007factors\"A\n\nUnitFactor\022\027\n\007unit_id\030\001 \001(\t" + + "R\006unitId\022\032\n\010exponent\030\002 \001(\001R\010exponent\"c\n\n" + + "Diagnostic\022\032\n\010severity\030\001 \001(\tR\010severity\022\030" + + "\n\007message\030\002 \001(\tR\007message\022\037\n\004span\030\003 \001(\0132\013" + + ".sysml.SpanR\004span\"\212\001\n\004Span\022\022\n\004file\030\001 \001(\t" + + "R\004file\022\035\n\nstart_line\030\002 \001(\005R\tstartLine\022\033\n" + + "\tstart_col\030\003 \001(\005R\010startCol\022\031\n\010end_line\030\004" + + " \001(\005R\007endLine\022\027\n\007end_col\030\005 \001(\005R\006endCol\"\023" + + "\n\021ServerInfoRequest\"R\n\022ServerInfoRespons" + + "e\022\030\n\007version\030\001 \001(\tR\007version\022\"\n\014capabilit" + + "ies\030\002 \003(\tR\014capabilities\"p\n\014QueryRequest\022" + + "\035\n\nmodel_hash\030\001 \001(\tR\tmodelHash\022\"\n\005query\030" + + "\002 \001(\0132\014.sysml.QueryR\005query\022\035\n\noslc_query" + + "\030\003 \001(\tR\toslcQuery\"F\n\rQueryResponse\0225\n\010el" + + "ements\030\001 \003(\0132\031.sysml.QueryResultElementR" + + "\010elements\"^\n\005Query\022\024\n\005scope\030\001 \003(\tR\005scope" + + "\022\026\n\006select\030\002 \003(\tR\006select\022\'\n\005where\030\003 \001(\0132" + + "\021.sysml.ConstraintR\005where\"\222\001\n\nConstraint" + + "\022:\n\tprimitive\030\001 \001(\0132\032.sysml.PrimitiveCon" + + "straintH\000R\tprimitive\022:\n\tcomposite\030\002 \001(\0132" + + "\032.sysml.CompositeConstraintH\000R\tcomposite" + + "B\014\n\nconstraint\"\227\001\n\023PrimitiveConstraint\022\030" + + "\n\007inverse\030\001 \001(\010R\007inverse\022\032\n\010property\030\002 \001" + + "(\tR\010property\0224\n\010operator\030\003 \001(\0162\030.sysml.P" + + "rimitiveOperatorR\010operator\022\024\n\005value\030\004 \003(" + + "\tR\005value\"~\n\023CompositeConstraint\0224\n\010opera" + + "tor\030\001 \001(\0162\030.sysml.CompositeOperatorR\010ope" + + "rator\0221\n\nconstraint\030\002 \003(\0132\021.sysml.Constr" + + "aintR\nconstraint\"\302\001\n\022QueryResultElement\022" + + "\016\n\002id\030\001 \001(\tR\002id\022\022\n\004type\030\002 \001(\tR\004type\022I\n\np" + + "roperties\030\003 \003(\0132).sysml.QueryResultEleme" + + "nt.PropertiesEntryR\nproperties\032=\n\017Proper" + + "tiesEntry\022\020\n\003key\030\001 \001(\tR\003key\022\024\n\005value\030\002 \001" + + "(\tR\005value:\0028\001\"\220\001\n\nSweepRange\022\034\n\tparamete" + + "r\030\001 \001(\tR\tparameter\022\"\n\005start\030\002 \001(\0132\014.sysm" + + "l.ValueR\005start\022\036\n\003end\030\003 \001(\0132\014.sysml.Valu" + + "eR\003end\022 \n\004step\030\004 \001(\0132\014.sysml.ValueR\004step" + + "\"\244\003\n\017RunSweepRequest\022\035\n\nmodel_hash\030\001 \001(\t" + + "R\tmodelHash\022\033\n\tsymbol_id\030\002 \001(\tR\010symbolId" + + "\022*\n\021subject_symbol_id\030\003 \001(\tR\017subjectSymb" + + "olId\022*\n\targuments\030\004 \003(\0132\014.sysml.ValueR\ta" + + "rguments\022S\n\017named_arguments\030\005 \003(\0132*.sysm" + + "l.RunSweepRequest.NamedArgumentsEntryR\016n" + + "amedArguments\022)\n\006ranges\030\006 \003(\0132\021.sysml.Sw" + + "eepRangeR\006ranges\022\030\n\007samples\030\007 \001(\003R\007sampl" + + "es\022\022\n\004seed\030\010 \001(\004R\004seed\032O\n\023NamedArguments" + + "Entry\022\020\n\003key\030\001 \001(\tR\003key\022\"\n\005value\030\002 \001(\0132\014" + + ".sysml.ValueR\005value:\0028\001\"\210\002\n\010SweepRow\022)\n\006" + + "inputs\030\001 \003(\0132\021.sysml.CalcOutputR\006inputs\022" + + "+\n\007outputs\030\002 \003(\0132\021.sysml.CalcOutputR\007out" + + "puts\022*\n\010verdicts\030\003 \003(\0132\016.sysml.VerdictR\010" + + "verdicts\022%\n\016elapsed_micros\030\004 \001(\003R\relapse" + + "dMicros\022\024\n\005error\030\005 \001(\tR\005error\022;\n\016failure" + + "_reason\030\006 \001(\0162\024.sysml.FailureReasonR\rfai" + + "lureReason\"\274\002\n\020RunSweepResponse\022#\n\004rows\030" + + "\001 \003(\0132\017.sysml.SweepRowR\004rows\022\036\n\nparamete" + + "rs\030\002 \003(\tR\nparameters\022\030\n\007sampled\030\003 \001(\010R\007s" + + "ampled\022\022\n\004seed\030\004 \001(\004R\004seed\022\024\n\005error\030\005 \001(" + + "\tR\005error\0223\n\013diagnostics\030\006 \003(\0132\021.sysml.Di" + + "agnosticR\013diagnostics\022;\n\016failure_reason\030" + + "\007 \001(\0162\024.sysml.FailureReasonR\rfailureReas" + + "on\022-\n\tinstances\030\010 \003(\0132\017.sysml.InstanceR\t" + + "instances\"\214\001\n\027RunDocumentQueryRequest\022\035\n" + + "\nmodel_hash\030\001 \001(\tR\tmodelHash\022\031\n\010query_id" + + "\030\002 \001(\tR\007queryId\0227\n\010bindings\030\003 \003(\0132\033.sysm" + + "l.DocumentQueryBindingR\010bindings\"b\n\024Docu" + + "mentQueryBinding\022\034\n\tparameter\030\001 \001(\tR\tpar" + + "ameter\022,\n\006values\030\002 \003(\0132\024.sysml.DocumentV" + + "alueR\006values\"\256\002\n\rDocumentValue\022\037\n\nelemen" + + "t_id\030\001 \001(\tH\000R\telementId\022#\n\014string_value\030" + + "\002 \001(\tH\000R\013stringValue\022\035\n\tint_value\030\003 \001(\003H" + + "\000R\010intValue\022\037\n\nreal_value\030\004 \001(\001H\000R\trealV" + + "alue\022\037\n\nbool_value\030\005 \001(\010H\000R\tboolValue\022\034\n" + + "\010infinity\030\006 \001(\010H\000R\010infinity\022-\n\010quantity\030" + + "\010 \001(\0132\017.sysml.QuantityH\000R\010quantity\022!\n\014el" + + "ement_type\030\007 \001(\tR\013elementTypeB\006\n\004kind\")\n" + + "\023DocumentQueryColumn\022\022\n\004name\030\001 \001(\tR\004name" + + "\"A\n\021DocumentQueryCell\022,\n\006values\030\001 \003(\0132\024." + + "sysml.DocumentValueR\006values\"r\n\020DocumentQ" + + "ueryRow\022.\n\007element\030\001 \001(\0132\024.sysml.Documen" + + "tValueR\007element\022.\n\005cells\030\002 \003(\0132\030.sysml.D" + + "ocumentQueryCellR\005cells\"}\n\030RunDocumentQu" + + "eryResponse\0224\n\007columns\030\001 \003(\0132\032.sysml.Doc" + + "umentQueryColumnR\007columns\022+\n\004rows\030\002 \003(\0132" + + "\027.sysml.DocumentQueryRowR\004rows\"W\n\025Render" + + "DocumentRequest\022\035\n\nmodel_hash\030\001 \001(\tR\tmod" + + "elHash\022\037\n\013document_id\030\002 \001(\tR\ndocumentId\"" + + "4\n\026RenderDocumentResponse\022\032\n\010markdown\030\001 " + + "\001(\tR\010markdown*\223\001\n\rFailureReason\022\036\n\032FAILU" + + "RE_REASON_UNSPECIFIED\020\000\022\035\n\031FAILURE_REASO" + + "N_EVALUATION\020\001\022\035\n\031FAILURE_REASON_WRONG_K" + + "IND\020\002\022$\n FAILURE_REASON_AMBIGUOUS_SUBJEC" + + "T\020\003*\235\004\n\013EditFailure\022\034\n\030EDIT_FAILURE_UNSP" + + "ECIFIED\020\000\022\036\n\032EDIT_FAILURE_NO_OPERATIONS\020" + + "\001\022\037\n\033EDIT_FAILURE_UNKNOWN_TARGET\020\002\022!\n\035ED" + + "IT_FAILURE_AMBIGUOUS_TARGET\020\003\022\033\n\027EDIT_FA" + + "ILURE_NOT_VALUED\020\004\022\036\n\032EDIT_FAILURE_INVAL" + + "ID_VALUE\020\005\022\035\n\031EDIT_FAILURE_INVALID_NAME\020" + + "\006\022\032\n\026EDIT_FAILURE_NOT_NAMED\020\007\022\"\n\036EDIT_FA" + + "ILURE_RENAME_REFERENCED\020\010\022\"\n\036EDIT_FAILUR" + + "E_OVERLAPPING_EDITS\020\t\022\037\n\033EDIT_FAILURE_RE" + + "SULT_INVALID\020\n\022\036\n\032EDIT_FAILURE_OWNER_UNK" + + "NOWN\020\013\022$\n EDIT_FAILURE_OWNER_NOT_NAMESPA" + + "CE\020\014\022\035\n\031EDIT_FAILURE_ILLEGAL_KIND\020\r\022\"\n\036E" + + "DIT_FAILURE_MEMBER_NAME_TAKEN\020\016\022\"\n\036EDIT_" + + "FAILURE_DELETE_REFERENCED\020\017*\222\001\n\021Primitiv" + + "eOperator\022\"\n\036PRIMITIVE_OPERATOR_UNSPECIF" + + "IED\020\000\022\034\n\030PRIMITIVE_OPERATOR_EQUAL\020\001\022\036\n\032P" + + "RIMITIVE_OPERATOR_GREATER\020\002\022\033\n\027PRIMITIVE" + + "_OPERATOR_LESS\020\003*n\n\021CompositeOperator\022\"\n" + + "\036COMPOSITE_OPERATOR_UNSPECIFIED\020\000\022\032\n\026COM" + + "POSITE_OPERATOR_AND\020\001\022\031\n\025COMPOSITE_OPERA" + + "TOR_OR\020\0022\244\013\n\014SysMLService\022D\n\rGetServerIn" + + "fo\022\030.sysml.ServerInfoRequest\032\031.sysml.Ser" + + "verInfoResponse\022>\n\tParseFile\022\027.sysml.Par" + + "seFileRequest\032\030.sysml.ParseFileResponse\022" + + "G\n\014ParseSources\022\032.sysml.ParseSourcesRequ" + + "est\032\033.sysml.ParseSourcesResponse\022;\n\tGetS" + + "ymbol\022\027.sysml.GetSymbolRequest\032\025.sysml.S" + + "ymbolResponse\022G\n\016GetDiagnostics\022\031.sysml." + + "DiagnosticsRequest\032\032.sysml.DiagnosticsRe" + + "sponse\022;\n\010Evaluate\022\026.sysml.EvaluateReque" + + "st\032\027.sysml.EvaluateResponse\022D\n\013Instantia" + + "te\022\031.sysml.InstantiateRequest\032\032.sysml.In" + + "stantiateResponse\022J\n\rExecuteAction\022\033.sys" + + "ml.ExecuteActionRequest\032\034.sysml.ExecuteA" + + "ctionResponse\022G\n\014ExecuteState\022\032.sysml.Ex" + + "ecuteStateRequest\032\033.sysml.ExecuteStateRe" + + "sponse\0228\n\007Convert\022\025.sysml.ConvertRequest" + + "\032\026.sysml.ConvertResponse\022A\n\nApplyEdits\022\030" + + ".sysml.ApplyEditsRequest\032\031.sysml.ApplyEd" + + "itsResponse\022S\n\020VerifyConstraint\022\036.sysml." + + "VerifyConstraintRequest\032\037.sysml.VerifyCo" + + "nstraintResponse\022V\n\021VerifyRequirement\022\037." + + "sysml.VerifyRequirementRequest\032 .sysml.V" + + "erifyRequirementResponse\022Y\n\022VerifySatisf" + + "action\022 .sysml.VerifySatisfactionRequest" + + "\032!.sysml.VerifySatisfactionResponse\022G\n\014E" + + "valuateCalc\022\032.sysml.EvaluateCalcRequest\032" + + "\033.sysml.EvaluateCalcResponse\022D\n\013RunAnaly" + + "sis\022\031.sysml.RunAnalysisRequest\032\032.sysml.R" + + "unAnalysisResponse\022;\n\010RunSweep\022\026.sysml.R" + + "unSweepRequest\032\027.sysml.RunSweepResponse\022" + + "2\n\005Query\022\023.sysml.QueryRequest\032\024.sysml.Qu" + + "eryResponse\022S\n\020RunDocumentQuery\022\036.sysml." + + "RunDocumentQueryRequest\032\037.sysml.RunDocum" + + "entQueryResponse\022M\n\016RenderDocument\022\034.sys" + + "ml.RenderDocumentRequest\032\035.sysml.RenderD", + "ocumentResponseBJ\n\034org.openmbee.opensysm" + + "l.protoP\001Z(github.com/Open-MBEE/OpenSysM" + + "L/api/protob\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, @@ -1215,7 +1216,7 @@ public static void registerAllExtensions( internal_static_sysml_Value_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_sysml_Value_descriptor, - new java.lang.String[] { "IntValue", "RealValue", "BoolValue", "StringValue", "InstanceId", "Sequence", "Null", "Quantity", "EnumLiteral", "Unset", "Complex", "Array", "Vector", "VectorQuantity", "MeasurementRef", "Kind", }); + new java.lang.String[] { "IntValue", "RealValue", "BoolValue", "StringValue", "InstanceId", "Sequence", "Null", "Quantity", "EnumLiteral", "Unset", "Complex", "Array", "Vector", "VectorQuantity", "MeasurementRef", "Infinity", "Kind", }); internal_static_sysml_Array_descriptor = getDescriptor().getMessageType(48); internal_static_sysml_Array_fieldAccessorTable = new diff --git a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/Value.java b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/Value.java index 1aee10580..78aec21c3 100644 --- a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/Value.java +++ b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/Value.java @@ -68,6 +68,7 @@ public enum KindCase VECTOR(13), VECTOR_QUANTITY(14), MEASUREMENT_REF(15), + INFINITY(16), KIND_NOT_SET(0); private final int value; private KindCase(int value) { @@ -100,6 +101,7 @@ public static KindCase forNumber(int value) { case 13: return VECTOR; case 14: return VECTOR_QUANTITY; case 15: return MEASUREMENT_REF; + case 16: return INFINITY; case 0: return KIND_NOT_SET; default: return null; } @@ -674,6 +676,39 @@ public org.openmbee.opensysml.proto.MeasurementRefOrBuilder getMeasurementRefOrB return org.openmbee.opensysml.proto.MeasurementRef.getDefaultInstance(); } + public static final int INFINITY_FIELD_NUMBER = 16; + /** + *

+   * The unbounded value `*`, which is no number and no string: ordered above
+   * every finite magnitude and refused by arithmetic. Always true when set,
+   * as DocumentValue.infinity is.
+   * 
+ * + * bool infinity = 16 [json_name = "infinity"]; + * @return Whether the infinity field is set. + */ + @java.lang.Override + public boolean hasInfinity() { + return kindCase_ == 16; + } + /** + *
+   * The unbounded value `*`, which is no number and no string: ordered above
+   * every finite magnitude and refused by arithmetic. Always true when set,
+   * as DocumentValue.infinity is.
+   * 
+ * + * bool infinity = 16 [json_name = "infinity"]; + * @return The infinity. + */ + @java.lang.Override + public boolean getInfinity() { + if (kindCase_ == 16) { + return (java.lang.Boolean) kind_; + } + return false; + } + private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { @@ -738,6 +773,10 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (kindCase_ == 15) { output.writeMessage(15, (org.openmbee.opensysml.proto.MeasurementRef) kind_); } + if (kindCase_ == 16) { + output.writeBool( + 16, (boolean)((java.lang.Boolean) kind_)); + } getUnknownFields().writeTo(output); } @@ -810,6 +849,11 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeMessageSize(15, (org.openmbee.opensysml.proto.MeasurementRef) kind_); } + if (kindCase_ == 16) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize( + 16, (boolean)((java.lang.Boolean) kind_)); + } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; @@ -888,6 +932,10 @@ public boolean equals(final java.lang.Object obj) { if (!getMeasurementRef() .equals(other.getMeasurementRef())) return false; break; + case 16: + if (getInfinity() + != other.getInfinity()) return false; + break; case 0: default: } @@ -968,6 +1016,11 @@ public int hashCode() { hash = (37 * hash) + MEASUREMENT_REF_FIELD_NUMBER; hash = (53 * hash) + getMeasurementRef().hashCode(); break; + case 16: + hash = (37 * hash) + INFINITY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getInfinity()); + break; case 0: default: } @@ -1282,6 +1335,10 @@ public Builder mergeFrom(org.openmbee.opensysml.proto.Value other) { mergeMeasurementRef(other.getMeasurementRef()); break; } + case INFINITY: { + setInfinity(other.getInfinity()); + break; + } case KIND_NOT_SET: { break; } @@ -1405,6 +1462,11 @@ public Builder mergeFrom( kindCase_ = 15; break; } // case 122 + case 128: { + kind_ = input.readBool(); + kindCase_ = 16; + break; + } // case 128 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag @@ -3245,6 +3307,72 @@ public org.openmbee.opensysml.proto.MeasurementRefOrBuilder getMeasurementRefOrB return measurementRefBuilder_; } + /** + *
+     * The unbounded value `*`, which is no number and no string: ordered above
+     * every finite magnitude and refused by arithmetic. Always true when set,
+     * as DocumentValue.infinity is.
+     * 
+ * + * bool infinity = 16 [json_name = "infinity"]; + * @return Whether the infinity field is set. + */ + public boolean hasInfinity() { + return kindCase_ == 16; + } + /** + *
+     * The unbounded value `*`, which is no number and no string: ordered above
+     * every finite magnitude and refused by arithmetic. Always true when set,
+     * as DocumentValue.infinity is.
+     * 
+ * + * bool infinity = 16 [json_name = "infinity"]; + * @return The infinity. + */ + public boolean getInfinity() { + if (kindCase_ == 16) { + return (java.lang.Boolean) kind_; + } + return false; + } + /** + *
+     * The unbounded value `*`, which is no number and no string: ordered above
+     * every finite magnitude and refused by arithmetic. Always true when set,
+     * as DocumentValue.infinity is.
+     * 
+ * + * bool infinity = 16 [json_name = "infinity"]; + * @param value The infinity to set. + * @return This builder for chaining. + */ + public Builder setInfinity(boolean value) { + + kindCase_ = 16; + kind_ = value; + onChanged(); + return this; + } + /** + *
+     * The unbounded value `*`, which is no number and no string: ordered above
+     * every finite magnitude and refused by arithmetic. Always true when set,
+     * as DocumentValue.infinity is.
+     * 
+ * + * bool infinity = 16 [json_name = "infinity"]; + * @return This builder for chaining. + */ + public Builder clearInfinity() { + if (kindCase_ == 16) { + kindCase_ = 0; + kind_ = null; + onChanged(); + } + return this; + } + // @@protoc_insertion_point(builder_scope:sysml.Value) } diff --git a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/ValueOrBuilder.java b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/ValueOrBuilder.java index 2f61dd66a..82dc6529d 100644 --- a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/ValueOrBuilder.java +++ b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/proto/ValueOrBuilder.java @@ -321,5 +321,28 @@ public interface ValueOrBuilder extends */ org.openmbee.opensysml.proto.MeasurementRefOrBuilder getMeasurementRefOrBuilder(); + /** + *
+   * The unbounded value `*`, which is no number and no string: ordered above
+   * every finite magnitude and refused by arithmetic. Always true when set,
+   * as DocumentValue.infinity is.
+   * 
+ * + * bool infinity = 16 [json_name = "infinity"]; + * @return Whether the infinity field is set. + */ + boolean hasInfinity(); + /** + *
+   * The unbounded value `*`, which is no number and no string: ordered above
+   * every finite magnitude and refused by arithmetic. Always true when set,
+   * as DocumentValue.infinity is.
+   * 
+ * + * bool infinity = 16 [json_name = "infinity"]; + * @return The infinity. + */ + boolean getInfinity(); + org.openmbee.opensysml.proto.Value.KindCase getKindCase(); } diff --git a/clients/java/opensysml-conformance/src/main/java/org/openmbee/opensysml/conformance/Rendering.java b/clients/java/opensysml-conformance/src/main/java/org/openmbee/opensysml/conformance/Rendering.java index ca155cd16..4ab23f099 100644 --- a/clients/java/opensysml-conformance/src/main/java/org/openmbee/opensysml/conformance/Rendering.java +++ b/clients/java/opensysml-conformance/src/main/java/org/openmbee/opensysml/conformance/Rendering.java @@ -59,6 +59,8 @@ static org.openmbee.opensysml.proto.Value value(Value value) { builder.setNull(""); } else if (value instanceof Value.UnsetValue) { builder.setUnset(true); + } else if (value instanceof Value.InfinityValue) { + builder.setInfinity(true); } else if (value instanceof Value.QuantityValue quantity) { builder.setQuantity(quantity(quantity.quantity())); } else if (value instanceof Value.EnumerationValue literal) { diff --git a/clients/node/src/core/capabilities.ts b/clients/node/src/core/capabilities.ts index a7f572ce5..fb65578a7 100644 --- a/clients/node/src/core/capabilities.ts +++ b/clients/node/src/core/capabilities.ts @@ -22,6 +22,8 @@ export const CAPABILITY_COMPLEX_VALUES = "complex_values"; export const CAPABILITY_STRUCTURED_VALUES = "structured_values"; /** A bare measurement unit (`SI::m`, `m / s`) as `Value.measurement_ref`, rather than an unsupported null. */ export const CAPABILITY_MEASUREMENT_REFS = "measurement_refs"; +/** The unbounded value `*` as `Value.infinity`, rather than an unsupported null. */ +export const CAPABILITY_INFINITY_VALUE = "infinity_value"; /** `ParseFileRequest.language`, which declares the language of inline content. */ export const CAPABILITY_INLINE_LANGUAGE = "inline_language"; /** `ParseFileRequest.strict_conformance`. */ diff --git a/clients/node/src/core/index.ts b/clients/node/src/core/index.ts index 0727025c3..7ecdae194 100644 --- a/clients/node/src/core/index.ts +++ b/clients/node/src/core/index.ts @@ -28,6 +28,7 @@ export { CAPABILITY_ENUM_VALUES, CAPABILITY_EVALUATE_SUBJECT, CAPABILITY_FEATURE_VALUES, + CAPABILITY_INFINITY_VALUE, CAPABILITY_INLINE_LANGUAGE, CAPABILITY_MEASUREMENT_REFS, CAPABILITY_QUERY, diff --git a/clients/node/src/core/values.ts b/clients/node/src/core/values.ts index 1c748eb28..873d0b125 100644 --- a/clients/node/src/core/values.ts +++ b/clients/node/src/core/values.ts @@ -109,6 +109,7 @@ export type SysMLValue = | { kind: "vectorQuantity"; components: QuantityValue[] } | { kind: "null"; reason: string } | { kind: "unset" } + | { kind: "infinity" } | { kind: "absent" }; /** What a verification answered about. Kept for the verification RPCs of a later version. */ @@ -178,6 +179,8 @@ export function decodeValue(value: Value | undefined): SysMLValue { return { kind: "null", reason: kind.value }; case "unset": return { kind: "unset" }; + case "infinity": + return { kind: "infinity" }; case undefined: return { kind: "absent" }; } @@ -255,6 +258,8 @@ export function encodeValue(value: SysMLValue): Value { return create(ValueSchema, { kind: { case: "null", value: value.reason } }); case "unset": return create(ValueSchema, { kind: { case: "unset", value: true } }); + case "infinity": + return create(ValueSchema, { kind: { case: "infinity", value: true } }); case "absent": throw new MalformedValueError("an absent value is no value at all, so it cannot be sent"); } @@ -331,6 +336,8 @@ export function formatValue(value: SysMLValue): string { return value.reason === "" ? "null" : `null (${value.reason})`; case "unset": return "unset"; + case "infinity": + return "*"; case "absent": return "absent"; } diff --git a/clients/node/src/generated/sysml_pb.ts b/clients/node/src/generated/sysml_pb.ts index 8880c3111..1fbafc31f 100644 --- a/clients/node/src/generated/sysml_pb.ts +++ b/clients/node/src/generated/sysml_pb.ts @@ -10,7 +10,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file sysml.proto. */ export const file_sysml: GenFile = /*@__PURE__*/ - fileDesc("CgtzeXNtbC5wcm90bxIFc3lzbWwi4gEKB1ZlcmRpY3QSDAoEa2luZBgBIAEoCRISCgplbGVtZW50X2lkGAIgASgJEg8KB2VsZW1lbnQYAyABKAkSDQoFaG9sZHMYBCABKAgSEQoJY29uZGl0aW9uGAUgASgJEhMKC2luc3RhbmNlX2lkGAYgASgDEhgKEGluc3RhbmNlX3R5cGVfaWQYByABKAkSDQoFZXJyb3IYCCABKAkSLAoOZmFpbHVyZV9yZWFzb24YCSABKA4yFC5zeXNtbC5GYWlsdXJlUmVhc29uEhYKDnJlcXVpcmVtZW50X2lkGAogASgJIlsKF1ZlcmlmeUNvbnN0cmFpbnRSZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSEQoJc3ltYm9sX2lkGAIgASgJEhkKEXN1YmplY3Rfc3ltYm9sX2lkGAMgASgJIpYBChhWZXJpZnlDb25zdHJhaW50UmVzcG9uc2USHwoHdmVyZGljdBgBIAEoCzIOLnN5c21sLlZlcmRpY3QSIgoJaW5zdGFuY2VzGAIgAygLMg8uc3lzbWwuSW5zdGFuY2USDQoFZXJyb3IYAyABKAkSJgoLZGlhZ25vc3RpY3MYBCADKAsyES5zeXNtbC5EaWFnbm9zdGljIlwKGFZlcmlmeVJlcXVpcmVtZW50UmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhEKCXN5bWJvbF9pZBgCIAEoCRIZChFzdWJqZWN0X3N5bWJvbF9pZBgDIAEoCSJtChNWZXJpZmljYXRpb25WZXJkaWN0Eg8KB2Nhc2VfaWQYASABKAkSDAoEa2luZBgCIAEoCRIOCgZkZXRhaWwYAyABKAkSDwoHc3ViY2FzZRgEIAEoCBIWCg5yZXF1aXJlbWVudF9pZBgFIAEoCSLSAQoZVmVyaWZ5UmVxdWlyZW1lbnRSZXNwb25zZRIfCgd2ZXJkaWN0GAEgASgLMg4uc3lzbWwuVmVyZGljdBIiCglpbnN0YW5jZXMYAiADKAsyDy5zeXNtbC5JbnN0YW5jZRINCgVlcnJvchgDIAEoCRImCgtkaWFnbm9zdGljcxgEIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSOQoVdmVyaWZpY2F0aW9uX3ZlcmRpY3RzGAUgAygLMhouc3lzbWwuVmVyaWZpY2F0aW9uVmVyZGljdCJCChlWZXJpZnlTYXRpc2ZhY3Rpb25SZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSEQoJc3ltYm9sX2lkGAIgASgJIoICChpWZXJpZnlTYXRpc2ZhY3Rpb25SZXNwb25zZRIgCgh2ZXJkaWN0cxgBIAMoCzIOLnN5c21sLlZlcmRpY3QSIgoJaW5zdGFuY2VzGAIgAygLMg8uc3lzbWwuSW5zdGFuY2USDQoFZXJyb3IYAyABKAkSJgoLZGlhZ25vc3RpY3MYBCADKAsyES5zeXNtbC5EaWFnbm9zdGljEiwKDmZhaWx1cmVfcmVhc29uGAUgASgOMhQuc3lzbWwuRmFpbHVyZVJlYXNvbhI5ChV2ZXJpZmljYXRpb25fdmVyZGljdHMYBiADKAsyGi5zeXNtbC5WZXJpZmljYXRpb25WZXJkaWN0Il0KE0V2YWx1YXRlQ2FsY1JlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRIRCglzeW1ib2xfaWQYAiABKAkSHwoJYXJndW1lbnRzGAMgAygLMgwuc3lzbWwuVmFsdWUivQEKFEV2YWx1YXRlQ2FsY1Jlc3BvbnNlEhwKBnJlc3VsdBgBIAEoCzIMLnN5c21sLlZhbHVlEiIKB291dHB1dHMYAiADKAsyES5zeXNtbC5DYWxjT3V0cHV0Eg0KBWVycm9yGAMgASgJEiYKC2RpYWdub3N0aWNzGAQgAygLMhEuc3lzbWwuRGlhZ25vc3RpYxIsCg5mYWlsdXJlX3JlYXNvbhgFIAEoDjIULnN5c21sLkZhaWx1cmVSZWFzb24iNwoKQ2FsY091dHB1dBIMCgRuYW1lGAEgASgJEhsKBXZhbHVlGAIgASgLMgwuc3lzbWwuVmFsdWUihAIKElJ1bkFuYWx5c2lzUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhEKCXN5bWJvbF9pZBgCIAEoCRIZChFzdWJqZWN0X3N5bWJvbF9pZBgDIAEoCRIfCglhcmd1bWVudHMYBCADKAsyDC5zeXNtbC5WYWx1ZRJGCg9uYW1lZF9hcmd1bWVudHMYBSADKAsyLS5zeXNtbC5SdW5BbmFseXNpc1JlcXVlc3QuTmFtZWRBcmd1bWVudHNFbnRyeRpDChNOYW1lZEFyZ3VtZW50c0VudHJ5EgsKA2tleRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlOgI4ASKfAgoTUnVuQW5hbHlzaXNSZXNwb25zZRIiCgdvdXRwdXRzGAEgAygLMhEuc3lzbWwuQ2FsY091dHB1dBIgCgh2ZXJkaWN0cxgCIAMoCzIOLnN5c21sLlZlcmRpY3QSIgoJaW5zdGFuY2VzGAMgAygLMg8uc3lzbWwuSW5zdGFuY2USDQoFZXJyb3IYBCABKAkSJgoLZGlhZ25vc3RpY3MYBSADKAsyES5zeXNtbC5EaWFnbm9zdGljEiwKDmZhaWx1cmVfcmVhc29uGAYgASgOMhQuc3lzbWwuRmFpbHVyZVJlYXNvbhI5ChV2ZXJpZmljYXRpb25fdmVyZGljdHMYByADKAsyGi5zeXNtbC5WZXJpZmljYXRpb25WZXJkaWN0IowBChBQYXJzZUZpbGVSZXF1ZXN0EhMKCWZpbGVfcGF0aBgBIAEoCUgAEhEKB2NvbnRlbnQYAiABKAlIABIYCgxjb250ZW50X2hhc2gYAyABKAlCAhgBEhAKCGxhbmd1YWdlGAQgASgJEhoKEnN0cmljdF9jb25mb3JtYW5jZRgFIAEoCEIICgZzb3VyY2UiYgoOU291cmNlRG9jdW1lbnQSEwoJZmlsZV9wYXRoGAEgASgJSAASEQoHY29udGVudBgCIAEoCUgAEhAKCGxhbmd1YWdlGAMgASgJEgwKBG5hbWUYBCABKAlCCAoGc291cmNlIlsKE1BhcnNlU291cmNlc1JlcXVlc3QSKAoJZG9jdW1lbnRzGAEgAygLMhUuc3lzbWwuU291cmNlRG9jdW1lbnQSGgoSc3RyaWN0X2NvbmZvcm1hbmNlGAIgASgIIoMBChRQYXJzZVNvdXJjZXNSZXNwb25zZRISCgptb2RlbF9oYXNoGAEgASgJEiAKBXJvb3RzGAIgAygLMhEuc3lzbWwuU3ltYm9sSW5mbxImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSDQoFZXJyb3IYBCABKAkifwoRUGFyc2VGaWxlUmVzcG9uc2USEgoKbW9kZWxfaGFzaBgBIAEoCRIfCgRyb290GAIgASgLMhEuc3lzbWwuU3ltYm9sSW5mbxImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSDQoFZXJyb3IYBCABKAkiOQoQR2V0U3ltYm9sUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhEKCXN5bWJvbF9pZBgCIAEoCSJCCg5TeW1ib2xSZXNwb25zZRIhCgZzeW1ib2wYASABKAsyES5zeXNtbC5TeW1ib2xJbmZvEg0KBWVycm9yGAIgASgJIigKEkRpYWdub3N0aWNzUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJIkwKE0RpYWdub3N0aWNzUmVzcG9uc2USJgoLZGlhZ25vc3RpY3MYASADKAsyES5zeXNtbC5EaWFnbm9zdGljEg0KBWVycm9yGAIgASgJIm8KD0V2YWx1YXRlUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhIKCmV4cHJlc3Npb24YAiABKAkSGQoRY29udGV4dF9zeW1ib2xfaWQYAyABKAkSGQoRc3ViamVjdF9zeW1ib2xfaWQYBCABKAkiZwoQRXZhbHVhdGVSZXNwb25zZRIcCgZyZXN1bHQYASABKAsyDC5zeXNtbC5WYWx1ZRINCgVlcnJvchgCIAEoCRImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMiwgEKCEluc3RhbmNlEgoKAmlkGAEgASgDEhYKDnR5cGVfc3ltYm9sX2lkGAIgASgJEjoKDmZlYXR1cmVfdmFsdWVzGAQgAygLMiIuc3lzbWwuSW5zdGFuY2UuRmVhdHVyZVZhbHVlc0VudHJ5GkkKEkZlYXR1cmVWYWx1ZXNFbnRyeRILCgNrZXkYASABKAkSIgoFdmFsdWUYAiABKAsyEy5zeXNtbC5GZWF0dXJlVmFsdWU6AjgBSgQIAxAEUgVzbG90cyKEAQoMRmVhdHVyZVZhbHVlEhQKDGZlYXR1cmVfbmFtZRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlEhwKBnZhbHVlcxgDIAMoCzIMLnN5c21sLlZhbHVlEhQKDG1hdGVyaWFsaXplZBgEIAEoCBINCgVlcnJvchgFIAEoCSI7ChJJbnN0YW50aWF0ZVJlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRIRCglzeW1ib2xfaWQYAiABKAkikwEKE0luc3RhbnRpYXRlUmVzcG9uc2USIQoIaW5zdGFuY2UYASABKAsyDy5zeXNtbC5JbnN0YW5jZRINCgVlcnJvchgCIAEoCRImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSIgoJaW5zdGFuY2VzGAQgAygLMg8uc3lzbWwuSW5zdGFuY2UiugEKFEV4ZWN1dGVBY3Rpb25SZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSGAoQYWN0aW9uX3N5bWJvbF9pZBgCIAEoCRI3CgZpbnB1dHMYAyADKAsyJy5zeXNtbC5FeGVjdXRlQWN0aW9uUmVxdWVzdC5JbnB1dHNFbnRyeRo7CgtJbnB1dHNFbnRyeRILCgNrZXkYASABKAkSGwoFdmFsdWUYAiABKAsyDC5zeXNtbC5WYWx1ZToCOAEiyAEKFUV4ZWN1dGVBY3Rpb25SZXNwb25zZRI6CgdvdXRwdXRzGAEgAygLMikuc3lzbWwuRXhlY3V0ZUFjdGlvblJlc3BvbnNlLk91dHB1dHNFbnRyeRINCgVlcnJvchgCIAEoCRImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMaPAoMT3V0cHV0c0VudHJ5EgsKA2tleRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlOgI4ASJaChNFeGVjdXRlU3RhdGVSZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSHwoXc3RhdGVfbWFjaGluZV9zeW1ib2xfaWQYAiABKAkSDgoGZXZlbnRzGAMgAygJIu4BChRFeGVjdXRlU3RhdGVSZXNwb25zZRIWCg5zdGF0ZXNfdmlzaXRlZBgBIAMoCRJECg1maW5hbF9jb250ZXh0GAIgAygLMi0uc3lzbWwuRXhlY3V0ZVN0YXRlUmVzcG9uc2UuRmluYWxDb250ZXh0RW50cnkSDQoFZXJyb3IYAyABKAkSJgoLZGlhZ25vc3RpY3MYBCADKAsyES5zeXNtbC5EaWFnbm9zdGljGkEKEUZpbmFsQ29udGV4dEVudHJ5EgsKA2tleRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlOgI4ASKgAQoOQ29udmVydFJlcXVlc3QSEwoJZmlsZV9wYXRoGAEgASgJSAASEQoHY29udGVudBgCIAEoCUgAEhQKCm1vZGVsX2hhc2gYBiABKAlIABITCgtmcm9tX2Zvcm1hdBgDIAEoCRIRCgl0b19mb3JtYXQYBCABKAkSHgoWdG9sZXJhdGVfc3ludGF4X2Vycm9ycxgFIAEoCEIICgZzb3VyY2UitAEKD0NvbnZlcnRSZXNwb25zZRIPCgdjb250ZW50GAEgASgJEhMKC2Zyb21fZm9ybWF0GAIgASgJEhEKCXRvX2Zvcm1hdBgDIAEoCRINCgVlcnJvchgEIAEoCRImCgtkaWFnbm9zdGljcxgFIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSFAoMZXhwZXJpbWVudGFsGAYgASgIEhsKE2V4cGVyaW1lbnRhbF9ub3RpY2UYByABKAkiUQoRQXBwbHlFZGl0c1JlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRIoCgpvcGVyYXRpb25zGAIgAygLMhQuc3lzbWwuRWRpdE9wZXJhdGlvbiK8AQoNRWRpdE9wZXJhdGlvbhIoCglzZXRfdmFsdWUYASABKAsyEy5zeXNtbC5TZXRWYWx1ZUVkaXRIABIjCgZyZW5hbWUYAiABKAsyES5zeXNtbC5SZW5hbWVFZGl0SAASKgoKYWRkX21lbWJlchgDIAEoCzIULnN5c21sLkFkZE1lbWJlckVkaXRIABIjCgZkZWxldGUYBCABKAsyES5zeXNtbC5EZWxldGVFZGl0SABCCwoJb3BlcmF0aW9uIoIBCg1BZGRNZW1iZXJFZGl0Eg0KBW93bmVyGAEgASgJEgwKBGtpbmQYAiABKAkSDAoEbmFtZRgDIAEoCRIMCgR0eXBlGAQgASgJEhQKDG11bHRpcGxpY2l0eRgFIAEoCRINCgV2YWx1ZRgGIAEoCRITCgtzcGVjaWFsaXplcxgHIAMoCSItCgpEZWxldGVFZGl0Eg4KBnRhcmdldBgBIAEoCRIPCgdjYXNjYWRlGAIgASgIIi0KDFNldFZhbHVlRWRpdBIOCgZ0YXJnZXQYASABKAkSDQoFdmFsdWUYAiABKAkiLgoKUmVuYW1lRWRpdBIOCgZ0YXJnZXQYASABKAkSEAoIbmV3X25hbWUYAiABKAkiwgEKEkFwcGx5RWRpdHNSZXNwb25zZRIPCgdjb250ZW50GAEgASgJEiMKB2FwcGxpZWQYAiADKAsyEi5zeXNtbC5BcHBsaWVkRWRpdBINCgVlcnJvchgDIAEoCRIjCgdmYWlsdXJlGAQgASgOMhIuc3lzbWwuRWRpdEZhaWx1cmUSJgoLZGlhZ25vc3RpY3MYBSADKAsyES5zeXNtbC5EaWFnbm9zdGljEhoKEnJlZmVycmluZ19lbGVtZW50cxgGIAMoCSJ6CgtBcHBsaWVkRWRpdBIXCg9vcGVyYXRpb25faW5kZXgYASABKAUSDgoGdGFyZ2V0GAIgASgJEg4KBm9mZnNldBgDIAEoBRIOCgZsZW5ndGgYBCABKAUSEAoIb2xkX3RleHQYBSABKAkSEAoIbmV3X3RleHQYBiABKAki/QIKClN5bWJvbEluZm8SCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRIMCgRraW5kGAMgASgJEjEKCG1ldGFkYXRhGAQgAygLMh8uc3lzbWwuU3ltYm9sSW5mby5NZXRhZGF0YUVudHJ5EhEKCWNoaWxkX2lkcxgFIAMoCRIoCgphdHRyaWJ1dGVzGAYgAygLMhQuc3lzbWwuQXR0cmlidXRlSW5mbxIiCgl0eXBlX2luZm8YByABKAsyDy5zeXNtbC5UeXBlSW5mbxItCgxtdWx0aXBsaWNpdHkYCCABKAsyFy5zeXNtbC5NdWx0aXBsaWNpdHlJbmZvEi4KD3NwZWNpYWxpemF0aW9ucxgJIAMoCzIVLnN5c21sLlNwZWNpYWxpemF0aW9uEiMKG3dpdGhoZWxkX2xpYnJhcnlfYXR0cmlidXRlcxgKIAEoBRovCg1NZXRhZGF0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiWAoOU3BlY2lhbGl6YXRpb24SDAoEa2luZBgBIAEoCRIQCghkZWNsYXJlZBgCIAEoCRIRCgl0YXJnZXRfaWQYAyABKAkSEwoLdGFyZ2V0X2tpbmQYBCABKAkilQEKCFR5cGVJbmZvEhAKCGRlY2xhcmVkGAEgASgJEhMKC3Jlc29sdmVkX2lkGAIgASgJEhUKDXJlc29sdmVkX2tpbmQYAyABKAkSEQoJcHJpbWl0aXZlGAQgASgJEhgKEHByaW1pdGl2ZV9zb3VyY2UYBSABKAkSEAoIcXVhbnRpdHkYBiABKAgSDAoEdW5pdBgHIAEoCSIwChBNdWx0aXBsaWNpdHlJbmZvEg0KBWxvd2VyGAEgASgJEg0KBXVwcGVyGAIgASgJIlYKDUF0dHJpYnV0ZUluZm8SDAoEbmFtZRgBIAEoCRIMCgR0eXBlGAIgASgJEhsKBXZhbHVlGAMgASgLMgwuc3lzbWwuVmFsdWUSDAoEdW5pdBgEIAEoCSLiAwoFVmFsdWUSEwoJaW50X3ZhbHVlGAEgASgDSAASFAoKcmVhbF92YWx1ZRgCIAEoAUgAEhQKCmJvb2xfdmFsdWUYAyABKAhIABIWCgxzdHJpbmdfdmFsdWUYBCABKAlIABIVCgtpbnN0YW5jZV9pZBgFIAEoA0gAEigKCHNlcXVlbmNlGAYgASgLMhQuc3lzbWwuVmFsdWVTZXF1ZW5jZUgAEg4KBG51bGwYByABKAlIABIjCghxdWFudGl0eRgIIAEoCzIPLnN5c21sLlF1YW50aXR5SAASKgoMZW51bV9saXRlcmFsGAkgASgLMhIuc3lzbWwuRW51bUxpdGVyYWxIABIPCgV1bnNldBgKIAEoCEgAEiEKB2NvbXBsZXgYCyABKAsyDi5zeXNtbC5Db21wbGV4SAASHQoFYXJyYXkYDCABKAsyDC5zeXNtbC5BcnJheUgAEh8KBnZlY3RvchgNIAEoCzINLnN5c21sLlZlY3RvckgAEjAKD3ZlY3Rvcl9xdWFudGl0eRgOIAEoCzIVLnN5c21sLlZlY3RvclF1YW50aXR5SAASMAoPbWVhc3VyZW1lbnRfcmVmGA8gASgLMhUuc3lzbWwuTWVhc3VyZW1lbnRSZWZIAEIGCgRraW5kIjsKBUFycmF5EhIKCmRpbWVuc2lvbnMYASADKAMSHgoIZWxlbWVudHMYAiADKAsyDC5zeXNtbC5WYWx1ZSIqCgZWZWN0b3ISIAoKY29tcG9uZW50cxgBIAMoCzIMLnN5c21sLlZhbHVlIjUKDlZlY3RvclF1YW50aXR5EiMKCmNvbXBvbmVudHMYASADKAsyDy5zeXNtbC5RdWFudGl0eSIqCgdDb21wbGV4EgwKBHJlYWwYASABKAESEQoJaW1hZ2luYXJ5GAIgASgBIkcKC0VudW1MaXRlcmFsEhIKCmxpdGVyYWxfaWQYASABKAkSFgoOZW51bWVyYXRpb25faWQYAiABKAkSDAoEbmFtZRgDIAEoCSIvCg1WYWx1ZVNlcXVlbmNlEh4KCGVsZW1lbnRzGAEgAygLMgwuc3lzbWwuVmFsdWUifAoIUXVhbnRpdHkSFwoNaW50X21hZ25pdHVkZRgBIAEoA0gAEhgKDnJlYWxfbWFnbml0dWRlGAIgASgBSAASDAoEdW5pdBgDIAEoCRIiCgl1bml0X3Rlcm0YBCABKAsyDy5zeXNtbC5Vbml0VGVybUILCgltYWduaXR1ZGUiUwoOTWVhc3VyZW1lbnRSZWYSDAoEdW5pdBgBIAEoCRIiCgl1bml0X3Rlcm0YAiABKAsyDy5zeXNtbC5Vbml0VGVybRIPCgd1bml0X2lkGAMgASgJIlQKCFVuaXRUZXJtEhEKCXNjYWxlX251bRgBIAEoARIRCglzY2FsZV9kZW4YAiABKAESIgoHZmFjdG9ycxgDIAMoCzIRLnN5c21sLlVuaXRGYWN0b3IiLwoKVW5pdEZhY3RvchIPCgd1bml0X2lkGAEgASgJEhAKCGV4cG9uZW50GAIgASgBIkoKCkRpYWdub3N0aWMSEAoIc2V2ZXJpdHkYASABKAkSDwoHbWVzc2FnZRgCIAEoCRIZCgRzcGFuGAMgASgLMgsuc3lzbWwuU3BhbiJeCgRTcGFuEgwKBGZpbGUYASABKAkSEgoKc3RhcnRfbGluZRgCIAEoBRIRCglzdGFydF9jb2wYAyABKAUSEAoIZW5kX2xpbmUYBCABKAUSDwoHZW5kX2NvbBgFIAEoBSITChFTZXJ2ZXJJbmZvUmVxdWVzdCI7ChJTZXJ2ZXJJbmZvUmVzcG9uc2USDwoHdmVyc2lvbhgBIAEoCRIUCgxjYXBhYmlsaXRpZXMYAiADKAkiUwoMUXVlcnlSZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSGwoFcXVlcnkYAiABKAsyDC5zeXNtbC5RdWVyeRISCgpvc2xjX3F1ZXJ5GAMgASgJIjwKDVF1ZXJ5UmVzcG9uc2USKwoIZWxlbWVudHMYASADKAsyGS5zeXNtbC5RdWVyeVJlc3VsdEVsZW1lbnQiSAoFUXVlcnkSDQoFc2NvcGUYASADKAkSDgoGc2VsZWN0GAIgAygJEiAKBXdoZXJlGAMgASgLMhEuc3lzbWwuQ29uc3RyYWludCJ8CgpDb25zdHJhaW50Ei8KCXByaW1pdGl2ZRgBIAEoCzIaLnN5c21sLlByaW1pdGl2ZUNvbnN0cmFpbnRIABIvCgljb21wb3NpdGUYAiABKAsyGi5zeXNtbC5Db21wb3NpdGVDb25zdHJhaW50SABCDAoKY29uc3RyYWludCJzChNQcmltaXRpdmVDb25zdHJhaW50Eg8KB2ludmVyc2UYASABKAgSEAoIcHJvcGVydHkYAiABKAkSKgoIb3BlcmF0b3IYAyABKA4yGC5zeXNtbC5QcmltaXRpdmVPcGVyYXRvchINCgV2YWx1ZRgEIAMoCSJoChNDb21wb3NpdGVDb25zdHJhaW50EioKCG9wZXJhdG9yGAEgASgOMhguc3lzbWwuQ29tcG9zaXRlT3BlcmF0b3ISJQoKY29uc3RyYWludBgCIAMoCzIRLnN5c21sLkNvbnN0cmFpbnQioAEKElF1ZXJ5UmVzdWx0RWxlbWVudBIKCgJpZBgBIAEoCRIMCgR0eXBlGAIgASgJEj0KCnByb3BlcnRpZXMYAyADKAsyKS5zeXNtbC5RdWVyeVJlc3VsdEVsZW1lbnQuUHJvcGVydGllc0VudHJ5GjEKD1Byb3BlcnRpZXNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBInMKClN3ZWVwUmFuZ2USEQoJcGFyYW1ldGVyGAEgASgJEhsKBXN0YXJ0GAIgASgLMgwuc3lzbWwuVmFsdWUSGQoDZW5kGAMgASgLMgwuc3lzbWwuVmFsdWUSGgoEc3RlcBgEIAEoCzIMLnN5c21sLlZhbHVlIsACCg9SdW5Td2VlcFJlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRIRCglzeW1ib2xfaWQYAiABKAkSGQoRc3ViamVjdF9zeW1ib2xfaWQYAyABKAkSHwoJYXJndW1lbnRzGAQgAygLMgwuc3lzbWwuVmFsdWUSQwoPbmFtZWRfYXJndW1lbnRzGAUgAygLMiouc3lzbWwuUnVuU3dlZXBSZXF1ZXN0Lk5hbWVkQXJndW1lbnRzRW50cnkSIQoGcmFuZ2VzGAYgAygLMhEuc3lzbWwuU3dlZXBSYW5nZRIPCgdzYW1wbGVzGAcgASgDEgwKBHNlZWQYCCABKAQaQwoTTmFtZWRBcmd1bWVudHNFbnRyeRILCgNrZXkYASABKAkSGwoFdmFsdWUYAiABKAsyDC5zeXNtbC5WYWx1ZToCOAEiyAEKCFN3ZWVwUm93EiEKBmlucHV0cxgBIAMoCzIRLnN5c21sLkNhbGNPdXRwdXQSIgoHb3V0cHV0cxgCIAMoCzIRLnN5c21sLkNhbGNPdXRwdXQSIAoIdmVyZGljdHMYAyADKAsyDi5zeXNtbC5WZXJkaWN0EhYKDmVsYXBzZWRfbWljcm9zGAQgASgDEg0KBWVycm9yGAUgASgJEiwKDmZhaWx1cmVfcmVhc29uGAYgASgOMhQuc3lzbWwuRmFpbHVyZVJlYXNvbiLtAQoQUnVuU3dlZXBSZXNwb25zZRIdCgRyb3dzGAEgAygLMg8uc3lzbWwuU3dlZXBSb3cSEgoKcGFyYW1ldGVycxgCIAMoCRIPCgdzYW1wbGVkGAMgASgIEgwKBHNlZWQYBCABKAQSDQoFZXJyb3IYBSABKAkSJgoLZGlhZ25vc3RpY3MYBiADKAsyES5zeXNtbC5EaWFnbm9zdGljEiwKDmZhaWx1cmVfcmVhc29uGAcgASgOMhQuc3lzbWwuRmFpbHVyZVJlYXNvbhIiCglpbnN0YW5jZXMYCCADKAsyDy5zeXNtbC5JbnN0YW5jZSJuChdSdW5Eb2N1bWVudFF1ZXJ5UmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhAKCHF1ZXJ5X2lkGAIgASgJEi0KCGJpbmRpbmdzGAMgAygLMhsuc3lzbWwuRG9jdW1lbnRRdWVyeUJpbmRpbmciTwoURG9jdW1lbnRRdWVyeUJpbmRpbmcSEQoJcGFyYW1ldGVyGAEgASgJEiQKBnZhbHVlcxgCIAMoCzIULnN5c21sLkRvY3VtZW50VmFsdWUi1QEKDURvY3VtZW50VmFsdWUSFAoKZWxlbWVudF9pZBgBIAEoCUgAEhYKDHN0cmluZ192YWx1ZRgCIAEoCUgAEhMKCWludF92YWx1ZRgDIAEoA0gAEhQKCnJlYWxfdmFsdWUYBCABKAFIABIUCgpib29sX3ZhbHVlGAUgASgISAASEgoIaW5maW5pdHkYBiABKAhIABIjCghxdWFudGl0eRgIIAEoCzIPLnN5c21sLlF1YW50aXR5SAASFAoMZWxlbWVudF90eXBlGAcgASgJQgYKBGtpbmQiIwoTRG9jdW1lbnRRdWVyeUNvbHVtbhIMCgRuYW1lGAEgASgJIjkKEURvY3VtZW50UXVlcnlDZWxsEiQKBnZhbHVlcxgBIAMoCzIULnN5c21sLkRvY3VtZW50VmFsdWUiYgoQRG9jdW1lbnRRdWVyeVJvdxIlCgdlbGVtZW50GAEgASgLMhQuc3lzbWwuRG9jdW1lbnRWYWx1ZRInCgVjZWxscxgCIAMoCzIYLnN5c21sLkRvY3VtZW50UXVlcnlDZWxsIm4KGFJ1bkRvY3VtZW50UXVlcnlSZXNwb25zZRIrCgdjb2x1bW5zGAEgAygLMhouc3lzbWwuRG9jdW1lbnRRdWVyeUNvbHVtbhIlCgRyb3dzGAIgAygLMhcuc3lzbWwuRG9jdW1lbnRRdWVyeVJvdyJAChVSZW5kZXJEb2N1bWVudFJlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRITCgtkb2N1bWVudF9pZBgCIAEoCSIqChZSZW5kZXJEb2N1bWVudFJlc3BvbnNlEhAKCG1hcmtkb3duGAEgASgJKpMBCg1GYWlsdXJlUmVhc29uEh4KGkZBSUxVUkVfUkVBU09OX1VOU1BFQ0lGSUVEEAASHQoZRkFJTFVSRV9SRUFTT05fRVZBTFVBVElPThABEh0KGUZBSUxVUkVfUkVBU09OX1dST05HX0tJTkQQAhIkCiBGQUlMVVJFX1JFQVNPTl9BTUJJR1VPVVNfU1VCSkVDVBADKp0ECgtFZGl0RmFpbHVyZRIcChhFRElUX0ZBSUxVUkVfVU5TUEVDSUZJRUQQABIeChpFRElUX0ZBSUxVUkVfTk9fT1BFUkFUSU9OUxABEh8KG0VESVRfRkFJTFVSRV9VTktOT1dOX1RBUkdFVBACEiEKHUVESVRfRkFJTFVSRV9BTUJJR1VPVVNfVEFSR0VUEAMSGwoXRURJVF9GQUlMVVJFX05PVF9WQUxVRUQQBBIeChpFRElUX0ZBSUxVUkVfSU5WQUxJRF9WQUxVRRAFEh0KGUVESVRfRkFJTFVSRV9JTlZBTElEX05BTUUQBhIaChZFRElUX0ZBSUxVUkVfTk9UX05BTUVEEAcSIgoeRURJVF9GQUlMVVJFX1JFTkFNRV9SRUZFUkVOQ0VEEAgSIgoeRURJVF9GQUlMVVJFX09WRVJMQVBQSU5HX0VESVRTEAkSHwobRURJVF9GQUlMVVJFX1JFU1VMVF9JTlZBTElEEAoSHgoaRURJVF9GQUlMVVJFX09XTkVSX1VOS05PV04QCxIkCiBFRElUX0ZBSUxVUkVfT1dORVJfTk9UX05BTUVTUEFDRRAMEh0KGUVESVRfRkFJTFVSRV9JTExFR0FMX0tJTkQQDRIiCh5FRElUX0ZBSUxVUkVfTUVNQkVSX05BTUVfVEFLRU4QDhIiCh5FRElUX0ZBSUxVUkVfREVMRVRFX1JFRkVSRU5DRUQQDyqSAQoRUHJpbWl0aXZlT3BlcmF0b3ISIgoeUFJJTUlUSVZFX09QRVJBVE9SX1VOU1BFQ0lGSUVEEAASHAoYUFJJTUlUSVZFX09QRVJBVE9SX0VRVUFMEAESHgoaUFJJTUlUSVZFX09QRVJBVE9SX0dSRUFURVIQAhIbChdQUklNSVRJVkVfT1BFUkFUT1JfTEVTUxADKm4KEUNvbXBvc2l0ZU9wZXJhdG9yEiIKHkNPTVBPU0lURV9PUEVSQVRPUl9VTlNQRUNJRklFRBAAEhoKFkNPTVBPU0lURV9PUEVSQVRPUl9BTkQQARIZChVDT01QT1NJVEVfT1BFUkFUT1JfT1IQAjKkCwoMU3lzTUxTZXJ2aWNlEkQKDUdldFNlcnZlckluZm8SGC5zeXNtbC5TZXJ2ZXJJbmZvUmVxdWVzdBoZLnN5c21sLlNlcnZlckluZm9SZXNwb25zZRI+CglQYXJzZUZpbGUSFy5zeXNtbC5QYXJzZUZpbGVSZXF1ZXN0Ghguc3lzbWwuUGFyc2VGaWxlUmVzcG9uc2USRwoMUGFyc2VTb3VyY2VzEhouc3lzbWwuUGFyc2VTb3VyY2VzUmVxdWVzdBobLnN5c21sLlBhcnNlU291cmNlc1Jlc3BvbnNlEjsKCUdldFN5bWJvbBIXLnN5c21sLkdldFN5bWJvbFJlcXVlc3QaFS5zeXNtbC5TeW1ib2xSZXNwb25zZRJHCg5HZXREaWFnbm9zdGljcxIZLnN5c21sLkRpYWdub3N0aWNzUmVxdWVzdBoaLnN5c21sLkRpYWdub3N0aWNzUmVzcG9uc2USOwoIRXZhbHVhdGUSFi5zeXNtbC5FdmFsdWF0ZVJlcXVlc3QaFy5zeXNtbC5FdmFsdWF0ZVJlc3BvbnNlEkQKC0luc3RhbnRpYXRlEhkuc3lzbWwuSW5zdGFudGlhdGVSZXF1ZXN0Ghouc3lzbWwuSW5zdGFudGlhdGVSZXNwb25zZRJKCg1FeGVjdXRlQWN0aW9uEhsuc3lzbWwuRXhlY3V0ZUFjdGlvblJlcXVlc3QaHC5zeXNtbC5FeGVjdXRlQWN0aW9uUmVzcG9uc2USRwoMRXhlY3V0ZVN0YXRlEhouc3lzbWwuRXhlY3V0ZVN0YXRlUmVxdWVzdBobLnN5c21sLkV4ZWN1dGVTdGF0ZVJlc3BvbnNlEjgKB0NvbnZlcnQSFS5zeXNtbC5Db252ZXJ0UmVxdWVzdBoWLnN5c21sLkNvbnZlcnRSZXNwb25zZRJBCgpBcHBseUVkaXRzEhguc3lzbWwuQXBwbHlFZGl0c1JlcXVlc3QaGS5zeXNtbC5BcHBseUVkaXRzUmVzcG9uc2USUwoQVmVyaWZ5Q29uc3RyYWludBIeLnN5c21sLlZlcmlmeUNvbnN0cmFpbnRSZXF1ZXN0Gh8uc3lzbWwuVmVyaWZ5Q29uc3RyYWludFJlc3BvbnNlElYKEVZlcmlmeVJlcXVpcmVtZW50Eh8uc3lzbWwuVmVyaWZ5UmVxdWlyZW1lbnRSZXF1ZXN0GiAuc3lzbWwuVmVyaWZ5UmVxdWlyZW1lbnRSZXNwb25zZRJZChJWZXJpZnlTYXRpc2ZhY3Rpb24SIC5zeXNtbC5WZXJpZnlTYXRpc2ZhY3Rpb25SZXF1ZXN0GiEuc3lzbWwuVmVyaWZ5U2F0aXNmYWN0aW9uUmVzcG9uc2USRwoMRXZhbHVhdGVDYWxjEhouc3lzbWwuRXZhbHVhdGVDYWxjUmVxdWVzdBobLnN5c21sLkV2YWx1YXRlQ2FsY1Jlc3BvbnNlEkQKC1J1bkFuYWx5c2lzEhkuc3lzbWwuUnVuQW5hbHlzaXNSZXF1ZXN0Ghouc3lzbWwuUnVuQW5hbHlzaXNSZXNwb25zZRI7CghSdW5Td2VlcBIWLnN5c21sLlJ1blN3ZWVwUmVxdWVzdBoXLnN5c21sLlJ1blN3ZWVwUmVzcG9uc2USMgoFUXVlcnkSEy5zeXNtbC5RdWVyeVJlcXVlc3QaFC5zeXNtbC5RdWVyeVJlc3BvbnNlElMKEFJ1bkRvY3VtZW50UXVlcnkSHi5zeXNtbC5SdW5Eb2N1bWVudFF1ZXJ5UmVxdWVzdBofLnN5c21sLlJ1bkRvY3VtZW50UXVlcnlSZXNwb25zZRJNCg5SZW5kZXJEb2N1bWVudBIcLnN5c21sLlJlbmRlckRvY3VtZW50UmVxdWVzdBodLnN5c21sLlJlbmRlckRvY3VtZW50UmVzcG9uc2VCKlooZ2l0aHViLmNvbS9PcGVuLU1CRUUvT3BlblN5c01ML2FwaS9wcm90b2IGcHJvdG8z"); + fileDesc("CgtzeXNtbC5wcm90bxIFc3lzbWwi4gEKB1ZlcmRpY3QSDAoEa2luZBgBIAEoCRISCgplbGVtZW50X2lkGAIgASgJEg8KB2VsZW1lbnQYAyABKAkSDQoFaG9sZHMYBCABKAgSEQoJY29uZGl0aW9uGAUgASgJEhMKC2luc3RhbmNlX2lkGAYgASgDEhgKEGluc3RhbmNlX3R5cGVfaWQYByABKAkSDQoFZXJyb3IYCCABKAkSLAoOZmFpbHVyZV9yZWFzb24YCSABKA4yFC5zeXNtbC5GYWlsdXJlUmVhc29uEhYKDnJlcXVpcmVtZW50X2lkGAogASgJIlsKF1ZlcmlmeUNvbnN0cmFpbnRSZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSEQoJc3ltYm9sX2lkGAIgASgJEhkKEXN1YmplY3Rfc3ltYm9sX2lkGAMgASgJIpYBChhWZXJpZnlDb25zdHJhaW50UmVzcG9uc2USHwoHdmVyZGljdBgBIAEoCzIOLnN5c21sLlZlcmRpY3QSIgoJaW5zdGFuY2VzGAIgAygLMg8uc3lzbWwuSW5zdGFuY2USDQoFZXJyb3IYAyABKAkSJgoLZGlhZ25vc3RpY3MYBCADKAsyES5zeXNtbC5EaWFnbm9zdGljIlwKGFZlcmlmeVJlcXVpcmVtZW50UmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhEKCXN5bWJvbF9pZBgCIAEoCRIZChFzdWJqZWN0X3N5bWJvbF9pZBgDIAEoCSJtChNWZXJpZmljYXRpb25WZXJkaWN0Eg8KB2Nhc2VfaWQYASABKAkSDAoEa2luZBgCIAEoCRIOCgZkZXRhaWwYAyABKAkSDwoHc3ViY2FzZRgEIAEoCBIWCg5yZXF1aXJlbWVudF9pZBgFIAEoCSLSAQoZVmVyaWZ5UmVxdWlyZW1lbnRSZXNwb25zZRIfCgd2ZXJkaWN0GAEgASgLMg4uc3lzbWwuVmVyZGljdBIiCglpbnN0YW5jZXMYAiADKAsyDy5zeXNtbC5JbnN0YW5jZRINCgVlcnJvchgDIAEoCRImCgtkaWFnbm9zdGljcxgEIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSOQoVdmVyaWZpY2F0aW9uX3ZlcmRpY3RzGAUgAygLMhouc3lzbWwuVmVyaWZpY2F0aW9uVmVyZGljdCJCChlWZXJpZnlTYXRpc2ZhY3Rpb25SZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSEQoJc3ltYm9sX2lkGAIgASgJIoICChpWZXJpZnlTYXRpc2ZhY3Rpb25SZXNwb25zZRIgCgh2ZXJkaWN0cxgBIAMoCzIOLnN5c21sLlZlcmRpY3QSIgoJaW5zdGFuY2VzGAIgAygLMg8uc3lzbWwuSW5zdGFuY2USDQoFZXJyb3IYAyABKAkSJgoLZGlhZ25vc3RpY3MYBCADKAsyES5zeXNtbC5EaWFnbm9zdGljEiwKDmZhaWx1cmVfcmVhc29uGAUgASgOMhQuc3lzbWwuRmFpbHVyZVJlYXNvbhI5ChV2ZXJpZmljYXRpb25fdmVyZGljdHMYBiADKAsyGi5zeXNtbC5WZXJpZmljYXRpb25WZXJkaWN0Il0KE0V2YWx1YXRlQ2FsY1JlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRIRCglzeW1ib2xfaWQYAiABKAkSHwoJYXJndW1lbnRzGAMgAygLMgwuc3lzbWwuVmFsdWUivQEKFEV2YWx1YXRlQ2FsY1Jlc3BvbnNlEhwKBnJlc3VsdBgBIAEoCzIMLnN5c21sLlZhbHVlEiIKB291dHB1dHMYAiADKAsyES5zeXNtbC5DYWxjT3V0cHV0Eg0KBWVycm9yGAMgASgJEiYKC2RpYWdub3N0aWNzGAQgAygLMhEuc3lzbWwuRGlhZ25vc3RpYxIsCg5mYWlsdXJlX3JlYXNvbhgFIAEoDjIULnN5c21sLkZhaWx1cmVSZWFzb24iNwoKQ2FsY091dHB1dBIMCgRuYW1lGAEgASgJEhsKBXZhbHVlGAIgASgLMgwuc3lzbWwuVmFsdWUihAIKElJ1bkFuYWx5c2lzUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhEKCXN5bWJvbF9pZBgCIAEoCRIZChFzdWJqZWN0X3N5bWJvbF9pZBgDIAEoCRIfCglhcmd1bWVudHMYBCADKAsyDC5zeXNtbC5WYWx1ZRJGCg9uYW1lZF9hcmd1bWVudHMYBSADKAsyLS5zeXNtbC5SdW5BbmFseXNpc1JlcXVlc3QuTmFtZWRBcmd1bWVudHNFbnRyeRpDChNOYW1lZEFyZ3VtZW50c0VudHJ5EgsKA2tleRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlOgI4ASKfAgoTUnVuQW5hbHlzaXNSZXNwb25zZRIiCgdvdXRwdXRzGAEgAygLMhEuc3lzbWwuQ2FsY091dHB1dBIgCgh2ZXJkaWN0cxgCIAMoCzIOLnN5c21sLlZlcmRpY3QSIgoJaW5zdGFuY2VzGAMgAygLMg8uc3lzbWwuSW5zdGFuY2USDQoFZXJyb3IYBCABKAkSJgoLZGlhZ25vc3RpY3MYBSADKAsyES5zeXNtbC5EaWFnbm9zdGljEiwKDmZhaWx1cmVfcmVhc29uGAYgASgOMhQuc3lzbWwuRmFpbHVyZVJlYXNvbhI5ChV2ZXJpZmljYXRpb25fdmVyZGljdHMYByADKAsyGi5zeXNtbC5WZXJpZmljYXRpb25WZXJkaWN0IowBChBQYXJzZUZpbGVSZXF1ZXN0EhMKCWZpbGVfcGF0aBgBIAEoCUgAEhEKB2NvbnRlbnQYAiABKAlIABIYCgxjb250ZW50X2hhc2gYAyABKAlCAhgBEhAKCGxhbmd1YWdlGAQgASgJEhoKEnN0cmljdF9jb25mb3JtYW5jZRgFIAEoCEIICgZzb3VyY2UiYgoOU291cmNlRG9jdW1lbnQSEwoJZmlsZV9wYXRoGAEgASgJSAASEQoHY29udGVudBgCIAEoCUgAEhAKCGxhbmd1YWdlGAMgASgJEgwKBG5hbWUYBCABKAlCCAoGc291cmNlIlsKE1BhcnNlU291cmNlc1JlcXVlc3QSKAoJZG9jdW1lbnRzGAEgAygLMhUuc3lzbWwuU291cmNlRG9jdW1lbnQSGgoSc3RyaWN0X2NvbmZvcm1hbmNlGAIgASgIIoMBChRQYXJzZVNvdXJjZXNSZXNwb25zZRISCgptb2RlbF9oYXNoGAEgASgJEiAKBXJvb3RzGAIgAygLMhEuc3lzbWwuU3ltYm9sSW5mbxImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSDQoFZXJyb3IYBCABKAkifwoRUGFyc2VGaWxlUmVzcG9uc2USEgoKbW9kZWxfaGFzaBgBIAEoCRIfCgRyb290GAIgASgLMhEuc3lzbWwuU3ltYm9sSW5mbxImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSDQoFZXJyb3IYBCABKAkiOQoQR2V0U3ltYm9sUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhEKCXN5bWJvbF9pZBgCIAEoCSJCCg5TeW1ib2xSZXNwb25zZRIhCgZzeW1ib2wYASABKAsyES5zeXNtbC5TeW1ib2xJbmZvEg0KBWVycm9yGAIgASgJIigKEkRpYWdub3N0aWNzUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJIkwKE0RpYWdub3N0aWNzUmVzcG9uc2USJgoLZGlhZ25vc3RpY3MYASADKAsyES5zeXNtbC5EaWFnbm9zdGljEg0KBWVycm9yGAIgASgJIm8KD0V2YWx1YXRlUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhIKCmV4cHJlc3Npb24YAiABKAkSGQoRY29udGV4dF9zeW1ib2xfaWQYAyABKAkSGQoRc3ViamVjdF9zeW1ib2xfaWQYBCABKAkiZwoQRXZhbHVhdGVSZXNwb25zZRIcCgZyZXN1bHQYASABKAsyDC5zeXNtbC5WYWx1ZRINCgVlcnJvchgCIAEoCRImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMiwgEKCEluc3RhbmNlEgoKAmlkGAEgASgDEhYKDnR5cGVfc3ltYm9sX2lkGAIgASgJEjoKDmZlYXR1cmVfdmFsdWVzGAQgAygLMiIuc3lzbWwuSW5zdGFuY2UuRmVhdHVyZVZhbHVlc0VudHJ5GkkKEkZlYXR1cmVWYWx1ZXNFbnRyeRILCgNrZXkYASABKAkSIgoFdmFsdWUYAiABKAsyEy5zeXNtbC5GZWF0dXJlVmFsdWU6AjgBSgQIAxAEUgVzbG90cyKEAQoMRmVhdHVyZVZhbHVlEhQKDGZlYXR1cmVfbmFtZRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlEhwKBnZhbHVlcxgDIAMoCzIMLnN5c21sLlZhbHVlEhQKDG1hdGVyaWFsaXplZBgEIAEoCBINCgVlcnJvchgFIAEoCSI7ChJJbnN0YW50aWF0ZVJlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRIRCglzeW1ib2xfaWQYAiABKAkikwEKE0luc3RhbnRpYXRlUmVzcG9uc2USIQoIaW5zdGFuY2UYASABKAsyDy5zeXNtbC5JbnN0YW5jZRINCgVlcnJvchgCIAEoCRImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSIgoJaW5zdGFuY2VzGAQgAygLMg8uc3lzbWwuSW5zdGFuY2UiugEKFEV4ZWN1dGVBY3Rpb25SZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSGAoQYWN0aW9uX3N5bWJvbF9pZBgCIAEoCRI3CgZpbnB1dHMYAyADKAsyJy5zeXNtbC5FeGVjdXRlQWN0aW9uUmVxdWVzdC5JbnB1dHNFbnRyeRo7CgtJbnB1dHNFbnRyeRILCgNrZXkYASABKAkSGwoFdmFsdWUYAiABKAsyDC5zeXNtbC5WYWx1ZToCOAEiyAEKFUV4ZWN1dGVBY3Rpb25SZXNwb25zZRI6CgdvdXRwdXRzGAEgAygLMikuc3lzbWwuRXhlY3V0ZUFjdGlvblJlc3BvbnNlLk91dHB1dHNFbnRyeRINCgVlcnJvchgCIAEoCRImCgtkaWFnbm9zdGljcxgDIAMoCzIRLnN5c21sLkRpYWdub3N0aWMaPAoMT3V0cHV0c0VudHJ5EgsKA2tleRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlOgI4ASJaChNFeGVjdXRlU3RhdGVSZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSHwoXc3RhdGVfbWFjaGluZV9zeW1ib2xfaWQYAiABKAkSDgoGZXZlbnRzGAMgAygJIu4BChRFeGVjdXRlU3RhdGVSZXNwb25zZRIWCg5zdGF0ZXNfdmlzaXRlZBgBIAMoCRJECg1maW5hbF9jb250ZXh0GAIgAygLMi0uc3lzbWwuRXhlY3V0ZVN0YXRlUmVzcG9uc2UuRmluYWxDb250ZXh0RW50cnkSDQoFZXJyb3IYAyABKAkSJgoLZGlhZ25vc3RpY3MYBCADKAsyES5zeXNtbC5EaWFnbm9zdGljGkEKEUZpbmFsQ29udGV4dEVudHJ5EgsKA2tleRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlOgI4ASKgAQoOQ29udmVydFJlcXVlc3QSEwoJZmlsZV9wYXRoGAEgASgJSAASEQoHY29udGVudBgCIAEoCUgAEhQKCm1vZGVsX2hhc2gYBiABKAlIABITCgtmcm9tX2Zvcm1hdBgDIAEoCRIRCgl0b19mb3JtYXQYBCABKAkSHgoWdG9sZXJhdGVfc3ludGF4X2Vycm9ycxgFIAEoCEIICgZzb3VyY2UitAEKD0NvbnZlcnRSZXNwb25zZRIPCgdjb250ZW50GAEgASgJEhMKC2Zyb21fZm9ybWF0GAIgASgJEhEKCXRvX2Zvcm1hdBgDIAEoCRINCgVlcnJvchgEIAEoCRImCgtkaWFnbm9zdGljcxgFIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSFAoMZXhwZXJpbWVudGFsGAYgASgIEhsKE2V4cGVyaW1lbnRhbF9ub3RpY2UYByABKAkiUQoRQXBwbHlFZGl0c1JlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRIoCgpvcGVyYXRpb25zGAIgAygLMhQuc3lzbWwuRWRpdE9wZXJhdGlvbiK8AQoNRWRpdE9wZXJhdGlvbhIoCglzZXRfdmFsdWUYASABKAsyEy5zeXNtbC5TZXRWYWx1ZUVkaXRIABIjCgZyZW5hbWUYAiABKAsyES5zeXNtbC5SZW5hbWVFZGl0SAASKgoKYWRkX21lbWJlchgDIAEoCzIULnN5c21sLkFkZE1lbWJlckVkaXRIABIjCgZkZWxldGUYBCABKAsyES5zeXNtbC5EZWxldGVFZGl0SABCCwoJb3BlcmF0aW9uIoIBCg1BZGRNZW1iZXJFZGl0Eg0KBW93bmVyGAEgASgJEgwKBGtpbmQYAiABKAkSDAoEbmFtZRgDIAEoCRIMCgR0eXBlGAQgASgJEhQKDG11bHRpcGxpY2l0eRgFIAEoCRINCgV2YWx1ZRgGIAEoCRITCgtzcGVjaWFsaXplcxgHIAMoCSItCgpEZWxldGVFZGl0Eg4KBnRhcmdldBgBIAEoCRIPCgdjYXNjYWRlGAIgASgIIi0KDFNldFZhbHVlRWRpdBIOCgZ0YXJnZXQYASABKAkSDQoFdmFsdWUYAiABKAkiLgoKUmVuYW1lRWRpdBIOCgZ0YXJnZXQYASABKAkSEAoIbmV3X25hbWUYAiABKAkiwgEKEkFwcGx5RWRpdHNSZXNwb25zZRIPCgdjb250ZW50GAEgASgJEiMKB2FwcGxpZWQYAiADKAsyEi5zeXNtbC5BcHBsaWVkRWRpdBINCgVlcnJvchgDIAEoCRIjCgdmYWlsdXJlGAQgASgOMhIuc3lzbWwuRWRpdEZhaWx1cmUSJgoLZGlhZ25vc3RpY3MYBSADKAsyES5zeXNtbC5EaWFnbm9zdGljEhoKEnJlZmVycmluZ19lbGVtZW50cxgGIAMoCSJ6CgtBcHBsaWVkRWRpdBIXCg9vcGVyYXRpb25faW5kZXgYASABKAUSDgoGdGFyZ2V0GAIgASgJEg4KBm9mZnNldBgDIAEoBRIOCgZsZW5ndGgYBCABKAUSEAoIb2xkX3RleHQYBSABKAkSEAoIbmV3X3RleHQYBiABKAki/QIKClN5bWJvbEluZm8SCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRIMCgRraW5kGAMgASgJEjEKCG1ldGFkYXRhGAQgAygLMh8uc3lzbWwuU3ltYm9sSW5mby5NZXRhZGF0YUVudHJ5EhEKCWNoaWxkX2lkcxgFIAMoCRIoCgphdHRyaWJ1dGVzGAYgAygLMhQuc3lzbWwuQXR0cmlidXRlSW5mbxIiCgl0eXBlX2luZm8YByABKAsyDy5zeXNtbC5UeXBlSW5mbxItCgxtdWx0aXBsaWNpdHkYCCABKAsyFy5zeXNtbC5NdWx0aXBsaWNpdHlJbmZvEi4KD3NwZWNpYWxpemF0aW9ucxgJIAMoCzIVLnN5c21sLlNwZWNpYWxpemF0aW9uEiMKG3dpdGhoZWxkX2xpYnJhcnlfYXR0cmlidXRlcxgKIAEoBRovCg1NZXRhZGF0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiWAoOU3BlY2lhbGl6YXRpb24SDAoEa2luZBgBIAEoCRIQCghkZWNsYXJlZBgCIAEoCRIRCgl0YXJnZXRfaWQYAyABKAkSEwoLdGFyZ2V0X2tpbmQYBCABKAkilQEKCFR5cGVJbmZvEhAKCGRlY2xhcmVkGAEgASgJEhMKC3Jlc29sdmVkX2lkGAIgASgJEhUKDXJlc29sdmVkX2tpbmQYAyABKAkSEQoJcHJpbWl0aXZlGAQgASgJEhgKEHByaW1pdGl2ZV9zb3VyY2UYBSABKAkSEAoIcXVhbnRpdHkYBiABKAgSDAoEdW5pdBgHIAEoCSIwChBNdWx0aXBsaWNpdHlJbmZvEg0KBWxvd2VyGAEgASgJEg0KBXVwcGVyGAIgASgJIlYKDUF0dHJpYnV0ZUluZm8SDAoEbmFtZRgBIAEoCRIMCgR0eXBlGAIgASgJEhsKBXZhbHVlGAMgASgLMgwuc3lzbWwuVmFsdWUSDAoEdW5pdBgEIAEoCSL2AwoFVmFsdWUSEwoJaW50X3ZhbHVlGAEgASgDSAASFAoKcmVhbF92YWx1ZRgCIAEoAUgAEhQKCmJvb2xfdmFsdWUYAyABKAhIABIWCgxzdHJpbmdfdmFsdWUYBCABKAlIABIVCgtpbnN0YW5jZV9pZBgFIAEoA0gAEigKCHNlcXVlbmNlGAYgASgLMhQuc3lzbWwuVmFsdWVTZXF1ZW5jZUgAEg4KBG51bGwYByABKAlIABIjCghxdWFudGl0eRgIIAEoCzIPLnN5c21sLlF1YW50aXR5SAASKgoMZW51bV9saXRlcmFsGAkgASgLMhIuc3lzbWwuRW51bUxpdGVyYWxIABIPCgV1bnNldBgKIAEoCEgAEiEKB2NvbXBsZXgYCyABKAsyDi5zeXNtbC5Db21wbGV4SAASHQoFYXJyYXkYDCABKAsyDC5zeXNtbC5BcnJheUgAEh8KBnZlY3RvchgNIAEoCzINLnN5c21sLlZlY3RvckgAEjAKD3ZlY3Rvcl9xdWFudGl0eRgOIAEoCzIVLnN5c21sLlZlY3RvclF1YW50aXR5SAASMAoPbWVhc3VyZW1lbnRfcmVmGA8gASgLMhUuc3lzbWwuTWVhc3VyZW1lbnRSZWZIABISCghpbmZpbml0eRgQIAEoCEgAQgYKBGtpbmQiOwoFQXJyYXkSEgoKZGltZW5zaW9ucxgBIAMoAxIeCghlbGVtZW50cxgCIAMoCzIMLnN5c21sLlZhbHVlIioKBlZlY3RvchIgCgpjb21wb25lbnRzGAEgAygLMgwuc3lzbWwuVmFsdWUiNQoOVmVjdG9yUXVhbnRpdHkSIwoKY29tcG9uZW50cxgBIAMoCzIPLnN5c21sLlF1YW50aXR5IioKB0NvbXBsZXgSDAoEcmVhbBgBIAEoARIRCglpbWFnaW5hcnkYAiABKAEiRwoLRW51bUxpdGVyYWwSEgoKbGl0ZXJhbF9pZBgBIAEoCRIWCg5lbnVtZXJhdGlvbl9pZBgCIAEoCRIMCgRuYW1lGAMgASgJIi8KDVZhbHVlU2VxdWVuY2USHgoIZWxlbWVudHMYASADKAsyDC5zeXNtbC5WYWx1ZSJ8CghRdWFudGl0eRIXCg1pbnRfbWFnbml0dWRlGAEgASgDSAASGAoOcmVhbF9tYWduaXR1ZGUYAiABKAFIABIMCgR1bml0GAMgASgJEiIKCXVuaXRfdGVybRgEIAEoCzIPLnN5c21sLlVuaXRUZXJtQgsKCW1hZ25pdHVkZSJTCg5NZWFzdXJlbWVudFJlZhIMCgR1bml0GAEgASgJEiIKCXVuaXRfdGVybRgCIAEoCzIPLnN5c21sLlVuaXRUZXJtEg8KB3VuaXRfaWQYAyABKAkiVAoIVW5pdFRlcm0SEQoJc2NhbGVfbnVtGAEgASgBEhEKCXNjYWxlX2RlbhgCIAEoARIiCgdmYWN0b3JzGAMgAygLMhEuc3lzbWwuVW5pdEZhY3RvciIvCgpVbml0RmFjdG9yEg8KB3VuaXRfaWQYASABKAkSEAoIZXhwb25lbnQYAiABKAEiSgoKRGlhZ25vc3RpYxIQCghzZXZlcml0eRgBIAEoCRIPCgdtZXNzYWdlGAIgASgJEhkKBHNwYW4YAyABKAsyCy5zeXNtbC5TcGFuIl4KBFNwYW4SDAoEZmlsZRgBIAEoCRISCgpzdGFydF9saW5lGAIgASgFEhEKCXN0YXJ0X2NvbBgDIAEoBRIQCghlbmRfbGluZRgEIAEoBRIPCgdlbmRfY29sGAUgASgFIhMKEVNlcnZlckluZm9SZXF1ZXN0IjsKElNlcnZlckluZm9SZXNwb25zZRIPCgd2ZXJzaW9uGAEgASgJEhQKDGNhcGFiaWxpdGllcxgCIAMoCSJTCgxRdWVyeVJlcXVlc3QSEgoKbW9kZWxfaGFzaBgBIAEoCRIbCgVxdWVyeRgCIAEoCzIMLnN5c21sLlF1ZXJ5EhIKCm9zbGNfcXVlcnkYAyABKAkiPAoNUXVlcnlSZXNwb25zZRIrCghlbGVtZW50cxgBIAMoCzIZLnN5c21sLlF1ZXJ5UmVzdWx0RWxlbWVudCJICgVRdWVyeRINCgVzY29wZRgBIAMoCRIOCgZzZWxlY3QYAiADKAkSIAoFd2hlcmUYAyABKAsyES5zeXNtbC5Db25zdHJhaW50InwKCkNvbnN0cmFpbnQSLwoJcHJpbWl0aXZlGAEgASgLMhouc3lzbWwuUHJpbWl0aXZlQ29uc3RyYWludEgAEi8KCWNvbXBvc2l0ZRgCIAEoCzIaLnN5c21sLkNvbXBvc2l0ZUNvbnN0cmFpbnRIAEIMCgpjb25zdHJhaW50InMKE1ByaW1pdGl2ZUNvbnN0cmFpbnQSDwoHaW52ZXJzZRgBIAEoCBIQCghwcm9wZXJ0eRgCIAEoCRIqCghvcGVyYXRvchgDIAEoDjIYLnN5c21sLlByaW1pdGl2ZU9wZXJhdG9yEg0KBXZhbHVlGAQgAygJImgKE0NvbXBvc2l0ZUNvbnN0cmFpbnQSKgoIb3BlcmF0b3IYASABKA4yGC5zeXNtbC5Db21wb3NpdGVPcGVyYXRvchIlCgpjb25zdHJhaW50GAIgAygLMhEuc3lzbWwuQ29uc3RyYWludCKgAQoSUXVlcnlSZXN1bHRFbGVtZW50EgoKAmlkGAEgASgJEgwKBHR5cGUYAiABKAkSPQoKcHJvcGVydGllcxgDIAMoCzIpLnN5c21sLlF1ZXJ5UmVzdWx0RWxlbWVudC5Qcm9wZXJ0aWVzRW50cnkaMQoPUHJvcGVydGllc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEicwoKU3dlZXBSYW5nZRIRCglwYXJhbWV0ZXIYASABKAkSGwoFc3RhcnQYAiABKAsyDC5zeXNtbC5WYWx1ZRIZCgNlbmQYAyABKAsyDC5zeXNtbC5WYWx1ZRIaCgRzdGVwGAQgASgLMgwuc3lzbWwuVmFsdWUiwAIKD1J1blN3ZWVwUmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhEKCXN5bWJvbF9pZBgCIAEoCRIZChFzdWJqZWN0X3N5bWJvbF9pZBgDIAEoCRIfCglhcmd1bWVudHMYBCADKAsyDC5zeXNtbC5WYWx1ZRJDCg9uYW1lZF9hcmd1bWVudHMYBSADKAsyKi5zeXNtbC5SdW5Td2VlcFJlcXVlc3QuTmFtZWRBcmd1bWVudHNFbnRyeRIhCgZyYW5nZXMYBiADKAsyES5zeXNtbC5Td2VlcFJhbmdlEg8KB3NhbXBsZXMYByABKAMSDAoEc2VlZBgIIAEoBBpDChNOYW1lZEFyZ3VtZW50c0VudHJ5EgsKA2tleRgBIAEoCRIbCgV2YWx1ZRgCIAEoCzIMLnN5c21sLlZhbHVlOgI4ASLIAQoIU3dlZXBSb3cSIQoGaW5wdXRzGAEgAygLMhEuc3lzbWwuQ2FsY091dHB1dBIiCgdvdXRwdXRzGAIgAygLMhEuc3lzbWwuQ2FsY091dHB1dBIgCgh2ZXJkaWN0cxgDIAMoCzIOLnN5c21sLlZlcmRpY3QSFgoOZWxhcHNlZF9taWNyb3MYBCABKAMSDQoFZXJyb3IYBSABKAkSLAoOZmFpbHVyZV9yZWFzb24YBiABKA4yFC5zeXNtbC5GYWlsdXJlUmVhc29uIu0BChBSdW5Td2VlcFJlc3BvbnNlEh0KBHJvd3MYASADKAsyDy5zeXNtbC5Td2VlcFJvdxISCgpwYXJhbWV0ZXJzGAIgAygJEg8KB3NhbXBsZWQYAyABKAgSDAoEc2VlZBgEIAEoBBINCgVlcnJvchgFIAEoCRImCgtkaWFnbm9zdGljcxgGIAMoCzIRLnN5c21sLkRpYWdub3N0aWMSLAoOZmFpbHVyZV9yZWFzb24YByABKA4yFC5zeXNtbC5GYWlsdXJlUmVhc29uEiIKCWluc3RhbmNlcxgIIAMoCzIPLnN5c21sLkluc3RhbmNlIm4KF1J1bkRvY3VtZW50UXVlcnlSZXF1ZXN0EhIKCm1vZGVsX2hhc2gYASABKAkSEAoIcXVlcnlfaWQYAiABKAkSLQoIYmluZGluZ3MYAyADKAsyGy5zeXNtbC5Eb2N1bWVudFF1ZXJ5QmluZGluZyJPChREb2N1bWVudFF1ZXJ5QmluZGluZxIRCglwYXJhbWV0ZXIYASABKAkSJAoGdmFsdWVzGAIgAygLMhQuc3lzbWwuRG9jdW1lbnRWYWx1ZSLVAQoNRG9jdW1lbnRWYWx1ZRIUCgplbGVtZW50X2lkGAEgASgJSAASFgoMc3RyaW5nX3ZhbHVlGAIgASgJSAASEwoJaW50X3ZhbHVlGAMgASgDSAASFAoKcmVhbF92YWx1ZRgEIAEoAUgAEhQKCmJvb2xfdmFsdWUYBSABKAhIABISCghpbmZpbml0eRgGIAEoCEgAEiMKCHF1YW50aXR5GAggASgLMg8uc3lzbWwuUXVhbnRpdHlIABIUCgxlbGVtZW50X3R5cGUYByABKAlCBgoEa2luZCIjChNEb2N1bWVudFF1ZXJ5Q29sdW1uEgwKBG5hbWUYASABKAkiOQoRRG9jdW1lbnRRdWVyeUNlbGwSJAoGdmFsdWVzGAEgAygLMhQuc3lzbWwuRG9jdW1lbnRWYWx1ZSJiChBEb2N1bWVudFF1ZXJ5Um93EiUKB2VsZW1lbnQYASABKAsyFC5zeXNtbC5Eb2N1bWVudFZhbHVlEicKBWNlbGxzGAIgAygLMhguc3lzbWwuRG9jdW1lbnRRdWVyeUNlbGwibgoYUnVuRG9jdW1lbnRRdWVyeVJlc3BvbnNlEisKB2NvbHVtbnMYASADKAsyGi5zeXNtbC5Eb2N1bWVudFF1ZXJ5Q29sdW1uEiUKBHJvd3MYAiADKAsyFy5zeXNtbC5Eb2N1bWVudFF1ZXJ5Um93IkAKFVJlbmRlckRvY3VtZW50UmVxdWVzdBISCgptb2RlbF9oYXNoGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJIioKFlJlbmRlckRvY3VtZW50UmVzcG9uc2USEAoIbWFya2Rvd24YASABKAkqkwEKDUZhaWx1cmVSZWFzb24SHgoaRkFJTFVSRV9SRUFTT05fVU5TUEVDSUZJRUQQABIdChlGQUlMVVJFX1JFQVNPTl9FVkFMVUFUSU9OEAESHQoZRkFJTFVSRV9SRUFTT05fV1JPTkdfS0lORBACEiQKIEZBSUxVUkVfUkVBU09OX0FNQklHVU9VU19TVUJKRUNUEAMqnQQKC0VkaXRGYWlsdXJlEhwKGEVESVRfRkFJTFVSRV9VTlNQRUNJRklFRBAAEh4KGkVESVRfRkFJTFVSRV9OT19PUEVSQVRJT05TEAESHwobRURJVF9GQUlMVVJFX1VOS05PV05fVEFSR0VUEAISIQodRURJVF9GQUlMVVJFX0FNQklHVU9VU19UQVJHRVQQAxIbChdFRElUX0ZBSUxVUkVfTk9UX1ZBTFVFRBAEEh4KGkVESVRfRkFJTFVSRV9JTlZBTElEX1ZBTFVFEAUSHQoZRURJVF9GQUlMVVJFX0lOVkFMSURfTkFNRRAGEhoKFkVESVRfRkFJTFVSRV9OT1RfTkFNRUQQBxIiCh5FRElUX0ZBSUxVUkVfUkVOQU1FX1JFRkVSRU5DRUQQCBIiCh5FRElUX0ZBSUxVUkVfT1ZFUkxBUFBJTkdfRURJVFMQCRIfChtFRElUX0ZBSUxVUkVfUkVTVUxUX0lOVkFMSUQQChIeChpFRElUX0ZBSUxVUkVfT1dORVJfVU5LTk9XThALEiQKIEVESVRfRkFJTFVSRV9PV05FUl9OT1RfTkFNRVNQQUNFEAwSHQoZRURJVF9GQUlMVVJFX0lMTEVHQUxfS0lORBANEiIKHkVESVRfRkFJTFVSRV9NRU1CRVJfTkFNRV9UQUtFThAOEiIKHkVESVRfRkFJTFVSRV9ERUxFVEVfUkVGRVJFTkNFRBAPKpIBChFQcmltaXRpdmVPcGVyYXRvchIiCh5QUklNSVRJVkVfT1BFUkFUT1JfVU5TUEVDSUZJRUQQABIcChhQUklNSVRJVkVfT1BFUkFUT1JfRVFVQUwQARIeChpQUklNSVRJVkVfT1BFUkFUT1JfR1JFQVRFUhACEhsKF1BSSU1JVElWRV9PUEVSQVRPUl9MRVNTEAMqbgoRQ29tcG9zaXRlT3BlcmF0b3ISIgoeQ09NUE9TSVRFX09QRVJBVE9SX1VOU1BFQ0lGSUVEEAASGgoWQ09NUE9TSVRFX09QRVJBVE9SX0FORBABEhkKFUNPTVBPU0lURV9PUEVSQVRPUl9PUhACMqQLCgxTeXNNTFNlcnZpY2USRAoNR2V0U2VydmVySW5mbxIYLnN5c21sLlNlcnZlckluZm9SZXF1ZXN0Ghkuc3lzbWwuU2VydmVySW5mb1Jlc3BvbnNlEj4KCVBhcnNlRmlsZRIXLnN5c21sLlBhcnNlRmlsZVJlcXVlc3QaGC5zeXNtbC5QYXJzZUZpbGVSZXNwb25zZRJHCgxQYXJzZVNvdXJjZXMSGi5zeXNtbC5QYXJzZVNvdXJjZXNSZXF1ZXN0Ghsuc3lzbWwuUGFyc2VTb3VyY2VzUmVzcG9uc2USOwoJR2V0U3ltYm9sEhcuc3lzbWwuR2V0U3ltYm9sUmVxdWVzdBoVLnN5c21sLlN5bWJvbFJlc3BvbnNlEkcKDkdldERpYWdub3N0aWNzEhkuc3lzbWwuRGlhZ25vc3RpY3NSZXF1ZXN0Ghouc3lzbWwuRGlhZ25vc3RpY3NSZXNwb25zZRI7CghFdmFsdWF0ZRIWLnN5c21sLkV2YWx1YXRlUmVxdWVzdBoXLnN5c21sLkV2YWx1YXRlUmVzcG9uc2USRAoLSW5zdGFudGlhdGUSGS5zeXNtbC5JbnN0YW50aWF0ZVJlcXVlc3QaGi5zeXNtbC5JbnN0YW50aWF0ZVJlc3BvbnNlEkoKDUV4ZWN1dGVBY3Rpb24SGy5zeXNtbC5FeGVjdXRlQWN0aW9uUmVxdWVzdBocLnN5c21sLkV4ZWN1dGVBY3Rpb25SZXNwb25zZRJHCgxFeGVjdXRlU3RhdGUSGi5zeXNtbC5FeGVjdXRlU3RhdGVSZXF1ZXN0Ghsuc3lzbWwuRXhlY3V0ZVN0YXRlUmVzcG9uc2USOAoHQ29udmVydBIVLnN5c21sLkNvbnZlcnRSZXF1ZXN0GhYuc3lzbWwuQ29udmVydFJlc3BvbnNlEkEKCkFwcGx5RWRpdHMSGC5zeXNtbC5BcHBseUVkaXRzUmVxdWVzdBoZLnN5c21sLkFwcGx5RWRpdHNSZXNwb25zZRJTChBWZXJpZnlDb25zdHJhaW50Eh4uc3lzbWwuVmVyaWZ5Q29uc3RyYWludFJlcXVlc3QaHy5zeXNtbC5WZXJpZnlDb25zdHJhaW50UmVzcG9uc2USVgoRVmVyaWZ5UmVxdWlyZW1lbnQSHy5zeXNtbC5WZXJpZnlSZXF1aXJlbWVudFJlcXVlc3QaIC5zeXNtbC5WZXJpZnlSZXF1aXJlbWVudFJlc3BvbnNlElkKElZlcmlmeVNhdGlzZmFjdGlvbhIgLnN5c21sLlZlcmlmeVNhdGlzZmFjdGlvblJlcXVlc3QaIS5zeXNtbC5WZXJpZnlTYXRpc2ZhY3Rpb25SZXNwb25zZRJHCgxFdmFsdWF0ZUNhbGMSGi5zeXNtbC5FdmFsdWF0ZUNhbGNSZXF1ZXN0Ghsuc3lzbWwuRXZhbHVhdGVDYWxjUmVzcG9uc2USRAoLUnVuQW5hbHlzaXMSGS5zeXNtbC5SdW5BbmFseXNpc1JlcXVlc3QaGi5zeXNtbC5SdW5BbmFseXNpc1Jlc3BvbnNlEjsKCFJ1blN3ZWVwEhYuc3lzbWwuUnVuU3dlZXBSZXF1ZXN0Ghcuc3lzbWwuUnVuU3dlZXBSZXNwb25zZRIyCgVRdWVyeRITLnN5c21sLlF1ZXJ5UmVxdWVzdBoULnN5c21sLlF1ZXJ5UmVzcG9uc2USUwoQUnVuRG9jdW1lbnRRdWVyeRIeLnN5c21sLlJ1bkRvY3VtZW50UXVlcnlSZXF1ZXN0Gh8uc3lzbWwuUnVuRG9jdW1lbnRRdWVyeVJlc3BvbnNlEk0KDlJlbmRlckRvY3VtZW50Ehwuc3lzbWwuUmVuZGVyRG9jdW1lbnRSZXF1ZXN0Gh0uc3lzbWwuUmVuZGVyRG9jdW1lbnRSZXNwb25zZUIqWihnaXRodWIuY29tL09wZW4tTUJFRS9PcGVuU3lzTUwvYXBpL3Byb3RvYgZwcm90bzM"); /** * Verdict is one verification's answer: whether the condition held, and, when @@ -2119,6 +2119,16 @@ export type Value = Message<"sysml.Value"> & { */ value: MeasurementRef; case: "measurementRef"; + } | { + /** + * The unbounded value `*`, which is no number and no string: ordered above + * every finite magnitude and refused by arithmetic. Always true when set, + * as DocumentValue.infinity is. + * + * @generated from field: bool infinity = 16; + */ + value: boolean; + case: "infinity"; } | { case: undefined; value?: undefined }; }; diff --git a/clients/python/opensysml/capabilities.py b/clients/python/opensysml/capabilities.py index 07bfbaf21..abd9e0fd6 100644 --- a/clients/python/opensysml/capabilities.py +++ b/clients/python/opensysml/capabilities.py @@ -107,6 +107,12 @@ #: verification case. CAPABILITY_VERIFICATION_VERDICTS = "verification_verdicts" +#: The unbounded value ``*`` as ``Value.infinity``, read as +#: :data:`~opensysml.values.INFINITY`. Without it the service sends an +#: unsupported null naming it, which is an error, and refuses one sent to it +#: with ``UNIMPLEMENTED``. +CAPABILITY_INFINITY_VALUE = "infinity_value" + @dataclass(frozen=True) class ServerInfo: diff --git a/clients/python/opensysml/connection.py b/clients/python/opensysml/connection.py index a5fcbdb6c..225b08551 100644 --- a/clients/python/opensysml/connection.py +++ b/clients/python/opensysml/connection.py @@ -21,6 +21,7 @@ CAPABILITY_DOCUMENT_QUERY, CAPABILITY_EVALUATE_SUBJECT, CAPABILITY_FEATURE_VALUES, + CAPABILITY_INFINITY_VALUE, CAPABILITY_MEASUREMENT_REFS, CAPABILITY_QUERY, CAPABILITY_RENDER_DOCUMENT, @@ -62,6 +63,7 @@ Quantity, Vector, VectorQuantity, + _Infinity, value_to_python, ) from opensysml.verdict import ( @@ -1660,6 +1662,14 @@ def _require_measurement_refs(self): upgrade_remedy(CAPABILITY_MEASUREMENT_REFS), ) + def _require_infinity_value(self): + """Refuse to send the unbounded value ``*`` a service without ``infinity_value`` would read as null.""" + require( + self.server_info(), + CAPABILITY_INFINITY_VALUE, + upgrade_remedy(CAPABILITY_INFINITY_VALUE), + ) + def _require_feature_values(self): """Refuse instances from a service that populates only the removed `slots` field.""" require( @@ -1704,6 +1714,9 @@ def _python_to_value(self, py_value): return sysml_pb2.Value(instance_id=py_value.id) elif isinstance(py_value, Quantity): return sysml_pb2.Value(quantity=py_value.to_pb()) + elif isinstance(py_value, _Infinity): + self._require_infinity_value() + return sysml_pb2.Value(infinity=True) elif isinstance(py_value, MeasurementRef): self._require_measurement_refs() return sysml_pb2.Value(measurement_ref=py_value.to_pb()) diff --git a/clients/python/opensysml/document.py b/clients/python/opensysml/document.py index 282adfa27..564c0ccb7 100644 --- a/clients/python/opensysml/document.py +++ b/clients/python/opensysml/document.py @@ -17,7 +17,7 @@ from opensysml.errors import OpenSysMLError, UnsupportedValueError from opensysml.proto import sysml_pb2 -from opensysml.values import Quantity +from opensysml.values import INFINITY, Quantity, _Infinity class DocumentQueryError(OpenSysMLError, ValueError): @@ -41,17 +41,6 @@ def __str__(self): return f"{self.id} ({self.type})" if self.type else self.id -class _Infinity: - """The unbounded multiplicity a query may answer with.""" - - def __repr__(self): - return "INFINITY" - - -#: An unbounded multiplicity in an answered cell. Only ever answered: binding -#: it is refused by the service. -INFINITY = _Infinity() - #: What a binding value or an answered cell value may be. DocumentValue = Union[ElementRef, str, int, float, bool, Quantity, _Infinity] diff --git a/clients/python/opensysml/proto/sysml_pb2.py b/clients/python/opensysml/proto/sysml_pb2.py index 1e1b1dfc4..391c35afc 100644 --- a/clients/python/opensysml/proto/sysml_pb2.py +++ b/clients/python/opensysml/proto/sysml_pb2.py @@ -24,7 +24,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0bsysml.proto\x12\x05sysml\"\xe2\x01\n\x07Verdict\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12\x12\n\nelement_id\x18\x02 \x01(\t\x12\x0f\n\x07\x65lement\x18\x03 \x01(\t\x12\r\n\x05holds\x18\x04 \x01(\x08\x12\x11\n\tcondition\x18\x05 \x01(\t\x12\x13\n\x0binstance_id\x18\x06 \x01(\x03\x12\x18\n\x10instance_type_id\x18\x07 \x01(\t\x12\r\n\x05\x65rror\x18\x08 \x01(\t\x12,\n\x0e\x66\x61ilure_reason\x18\t \x01(\x0e\x32\x14.sysml.FailureReason\x12\x16\n\x0erequirement_id\x18\n \x01(\t\"[\n\x17VerifyConstraintRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x03 \x01(\t\"\x96\x01\n\x18VerifyConstraintResponse\x12\x1f\n\x07verdict\x18\x01 \x01(\x0b\x32\x0e.sysml.Verdict\x12\"\n\tinstances\x18\x02 \x03(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\"\\\n\x18VerifyRequirementRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x03 \x01(\t\"m\n\x13VerificationVerdict\x12\x0f\n\x07\x63\x61se_id\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x03 \x01(\t\x12\x0f\n\x07subcase\x18\x04 \x01(\x08\x12\x16\n\x0erequirement_id\x18\x05 \x01(\t\"\xd2\x01\n\x19VerifyRequirementResponse\x12\x1f\n\x07verdict\x18\x01 \x01(\x0b\x32\x0e.sysml.Verdict\x12\"\n\tinstances\x18\x02 \x03(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\x39\n\x15verification_verdicts\x18\x05 \x03(\x0b\x32\x1a.sysml.VerificationVerdict\"B\n\x19VerifySatisfactionRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\"\x82\x02\n\x1aVerifySatisfactionResponse\x12 \n\x08verdicts\x18\x01 \x03(\x0b\x32\x0e.sysml.Verdict\x12\"\n\tinstances\x18\x02 \x03(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\x12,\n\x0e\x66\x61ilure_reason\x18\x05 \x01(\x0e\x32\x14.sysml.FailureReason\x12\x39\n\x15verification_verdicts\x18\x06 \x03(\x0b\x32\x1a.sysml.VerificationVerdict\"]\n\x13\x45valuateCalcRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x1f\n\targuments\x18\x03 \x03(\x0b\x32\x0c.sysml.Value\"\xbd\x01\n\x14\x45valuateCalcResponse\x12\x1c\n\x06result\x18\x01 \x01(\x0b\x32\x0c.sysml.Value\x12\"\n\x07outputs\x18\x02 \x03(\x0b\x32\x11.sysml.CalcOutput\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\x12,\n\x0e\x66\x61ilure_reason\x18\x05 \x01(\x0e\x32\x14.sysml.FailureReason\"7\n\nCalcOutput\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value\"\x84\x02\n\x12RunAnalysisRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x03 \x01(\t\x12\x1f\n\targuments\x18\x04 \x03(\x0b\x32\x0c.sysml.Value\x12\x46\n\x0fnamed_arguments\x18\x05 \x03(\x0b\x32-.sysml.RunAnalysisRequest.NamedArgumentsEntry\x1a\x43\n\x13NamedArgumentsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"\x9f\x02\n\x13RunAnalysisResponse\x12\"\n\x07outputs\x18\x01 \x03(\x0b\x32\x11.sysml.CalcOutput\x12 \n\x08verdicts\x18\x02 \x03(\x0b\x32\x0e.sysml.Verdict\x12\"\n\tinstances\x18\x03 \x03(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x04 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x05 \x03(\x0b\x32\x11.sysml.Diagnostic\x12,\n\x0e\x66\x61ilure_reason\x18\x06 \x01(\x0e\x32\x14.sysml.FailureReason\x12\x39\n\x15verification_verdicts\x18\x07 \x03(\x0b\x32\x1a.sysml.VerificationVerdict\"\x8c\x01\n\x10ParseFileRequest\x12\x13\n\tfile_path\x18\x01 \x01(\tH\x00\x12\x11\n\x07\x63ontent\x18\x02 \x01(\tH\x00\x12\x18\n\x0c\x63ontent_hash\x18\x03 \x01(\tB\x02\x18\x01\x12\x10\n\x08language\x18\x04 \x01(\t\x12\x1a\n\x12strict_conformance\x18\x05 \x01(\x08\x42\x08\n\x06source\"b\n\x0eSourceDocument\x12\x13\n\tfile_path\x18\x01 \x01(\tH\x00\x12\x11\n\x07\x63ontent\x18\x02 \x01(\tH\x00\x12\x10\n\x08language\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\tB\x08\n\x06source\"[\n\x13ParseSourcesRequest\x12(\n\tdocuments\x18\x01 \x03(\x0b\x32\x15.sysml.SourceDocument\x12\x1a\n\x12strict_conformance\x18\x02 \x01(\x08\"\x83\x01\n\x14ParseSourcesResponse\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12 \n\x05roots\x18\x02 \x03(\x0b\x32\x11.sysml.SymbolInfo\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"\x7f\n\x11ParseFileResponse\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x1f\n\x04root\x18\x02 \x01(\x0b\x32\x11.sysml.SymbolInfo\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"9\n\x10GetSymbolRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\"B\n\x0eSymbolResponse\x12!\n\x06symbol\x18\x01 \x01(\x0b\x32\x11.sysml.SymbolInfo\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"(\n\x12\x44iagnosticsRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\"L\n\x13\x44iagnosticsResponse\x12&\n\x0b\x64iagnostics\x18\x01 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"o\n\x0f\x45valuateRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x12\n\nexpression\x18\x02 \x01(\t\x12\x19\n\x11\x63ontext_symbol_id\x18\x03 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x04 \x01(\t\"g\n\x10\x45valuateResponse\x12\x1c\n\x06result\x18\x01 \x01(\x0b\x32\x0c.sysml.Value\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\"\xc2\x01\n\x08Instance\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x16\n\x0etype_symbol_id\x18\x02 \x01(\t\x12:\n\x0e\x66\x65\x61ture_values\x18\x04 \x03(\x0b\x32\".sysml.Instance.FeatureValuesEntry\x1aI\n\x12\x46\x65\x61tureValuesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.sysml.FeatureValue:\x02\x38\x01J\x04\x08\x03\x10\x04R\x05slots\"\x84\x01\n\x0c\x46\x65\x61tureValue\x12\x14\n\x0c\x66\x65\x61ture_name\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value\x12\x1c\n\x06values\x18\x03 \x03(\x0b\x32\x0c.sysml.Value\x12\x14\n\x0cmaterialized\x18\x04 \x01(\x08\x12\r\n\x05\x65rror\x18\x05 \x01(\t\";\n\x12InstantiateRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\"\x93\x01\n\x13InstantiateResponse\x12!\n\x08instance\x18\x01 \x01(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\"\n\tinstances\x18\x04 \x03(\x0b\x32\x0f.sysml.Instance\"\xba\x01\n\x14\x45xecuteActionRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x18\n\x10\x61\x63tion_symbol_id\x18\x02 \x01(\t\x12\x37\n\x06inputs\x18\x03 \x03(\x0b\x32\'.sysml.ExecuteActionRequest.InputsEntry\x1a;\n\x0bInputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"\xc8\x01\n\x15\x45xecuteActionResponse\x12:\n\x07outputs\x18\x01 \x03(\x0b\x32).sysml.ExecuteActionResponse.OutputsEntry\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\x1a<\n\x0cOutputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"Z\n\x13\x45xecuteStateRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x1f\n\x17state_machine_symbol_id\x18\x02 \x01(\t\x12\x0e\n\x06\x65vents\x18\x03 \x03(\t\"\xee\x01\n\x14\x45xecuteStateResponse\x12\x16\n\x0estates_visited\x18\x01 \x03(\t\x12\x44\n\rfinal_context\x18\x02 \x03(\x0b\x32-.sysml.ExecuteStateResponse.FinalContextEntry\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\x1a\x41\n\x11\x46inalContextEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"\xa0\x01\n\x0e\x43onvertRequest\x12\x13\n\tfile_path\x18\x01 \x01(\tH\x00\x12\x11\n\x07\x63ontent\x18\x02 \x01(\tH\x00\x12\x14\n\nmodel_hash\x18\x06 \x01(\tH\x00\x12\x13\n\x0b\x66rom_format\x18\x03 \x01(\t\x12\x11\n\tto_format\x18\x04 \x01(\t\x12\x1e\n\x16tolerate_syntax_errors\x18\x05 \x01(\x08\x42\x08\n\x06source\"\xb4\x01\n\x0f\x43onvertResponse\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12\x13\n\x0b\x66rom_format\x18\x02 \x01(\t\x12\x11\n\tto_format\x18\x03 \x01(\t\x12\r\n\x05\x65rror\x18\x04 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x05 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\x14\n\x0c\x65xperimental\x18\x06 \x01(\x08\x12\x1b\n\x13\x65xperimental_notice\x18\x07 \x01(\t\"Q\n\x11\x41pplyEditsRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12(\n\noperations\x18\x02 \x03(\x0b\x32\x14.sysml.EditOperation\"\xbc\x01\n\rEditOperation\x12(\n\tset_value\x18\x01 \x01(\x0b\x32\x13.sysml.SetValueEditH\x00\x12#\n\x06rename\x18\x02 \x01(\x0b\x32\x11.sysml.RenameEditH\x00\x12*\n\nadd_member\x18\x03 \x01(\x0b\x32\x14.sysml.AddMemberEditH\x00\x12#\n\x06\x64\x65lete\x18\x04 \x01(\x0b\x32\x11.sysml.DeleteEditH\x00\x42\x0b\n\toperation\"\x82\x01\n\rAddMemberEdit\x12\r\n\x05owner\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\t\x12\x14\n\x0cmultiplicity\x18\x05 \x01(\t\x12\r\n\x05value\x18\x06 \x01(\t\x12\x13\n\x0bspecializes\x18\x07 \x03(\t\"-\n\nDeleteEdit\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\x0f\n\x07\x63\x61scade\x18\x02 \x01(\x08\"-\n\x0cSetValueEdit\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\".\n\nRenameEdit\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\x10\n\x08new_name\x18\x02 \x01(\t\"\xc2\x01\n\x12\x41pplyEditsResponse\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12#\n\x07\x61pplied\x18\x02 \x03(\x0b\x32\x12.sysml.AppliedEdit\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12#\n\x07\x66\x61ilure\x18\x04 \x01(\x0e\x32\x12.sysml.EditFailure\x12&\n\x0b\x64iagnostics\x18\x05 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\x1a\n\x12referring_elements\x18\x06 \x03(\t\"z\n\x0b\x41ppliedEdit\x12\x17\n\x0foperation_index\x18\x01 \x01(\x05\x12\x0e\n\x06target\x18\x02 \x01(\t\x12\x0e\n\x06offset\x18\x03 \x01(\x05\x12\x0e\n\x06length\x18\x04 \x01(\x05\x12\x10\n\x08old_text\x18\x05 \x01(\t\x12\x10\n\x08new_text\x18\x06 \x01(\t\"\xfd\x02\n\nSymbolInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04kind\x18\x03 \x01(\t\x12\x31\n\x08metadata\x18\x04 \x03(\x0b\x32\x1f.sysml.SymbolInfo.MetadataEntry\x12\x11\n\tchild_ids\x18\x05 \x03(\t\x12(\n\nattributes\x18\x06 \x03(\x0b\x32\x14.sysml.AttributeInfo\x12\"\n\ttype_info\x18\x07 \x01(\x0b\x32\x0f.sysml.TypeInfo\x12-\n\x0cmultiplicity\x18\x08 \x01(\x0b\x32\x17.sysml.MultiplicityInfo\x12.\n\x0fspecializations\x18\t \x03(\x0b\x32\x15.sysml.Specialization\x12#\n\x1bwithheld_library_attributes\x18\n \x01(\x05\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"X\n\x0eSpecialization\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12\x10\n\x08\x64\x65\x63lared\x18\x02 \x01(\t\x12\x11\n\ttarget_id\x18\x03 \x01(\t\x12\x13\n\x0btarget_kind\x18\x04 \x01(\t\"\x95\x01\n\x08TypeInfo\x12\x10\n\x08\x64\x65\x63lared\x18\x01 \x01(\t\x12\x13\n\x0bresolved_id\x18\x02 \x01(\t\x12\x15\n\rresolved_kind\x18\x03 \x01(\t\x12\x11\n\tprimitive\x18\x04 \x01(\t\x12\x18\n\x10primitive_source\x18\x05 \x01(\t\x12\x10\n\x08quantity\x18\x06 \x01(\x08\x12\x0c\n\x04unit\x18\x07 \x01(\t\"0\n\x10MultiplicityInfo\x12\r\n\x05lower\x18\x01 \x01(\t\x12\r\n\x05upper\x18\x02 \x01(\t\"V\n\rAttributeInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x1b\n\x05value\x18\x03 \x01(\x0b\x32\x0c.sysml.Value\x12\x0c\n\x04unit\x18\x04 \x01(\t\"\xe2\x03\n\x05Value\x12\x13\n\tint_value\x18\x01 \x01(\x03H\x00\x12\x14\n\nreal_value\x18\x02 \x01(\x01H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x12\x16\n\x0cstring_value\x18\x04 \x01(\tH\x00\x12\x15\n\x0binstance_id\x18\x05 \x01(\x03H\x00\x12(\n\x08sequence\x18\x06 \x01(\x0b\x32\x14.sysml.ValueSequenceH\x00\x12\x0e\n\x04null\x18\x07 \x01(\tH\x00\x12#\n\x08quantity\x18\x08 \x01(\x0b\x32\x0f.sysml.QuantityH\x00\x12*\n\x0c\x65num_literal\x18\t \x01(\x0b\x32\x12.sysml.EnumLiteralH\x00\x12\x0f\n\x05unset\x18\n \x01(\x08H\x00\x12!\n\x07\x63omplex\x18\x0b \x01(\x0b\x32\x0e.sysml.ComplexH\x00\x12\x1d\n\x05\x61rray\x18\x0c \x01(\x0b\x32\x0c.sysml.ArrayH\x00\x12\x1f\n\x06vector\x18\r \x01(\x0b\x32\r.sysml.VectorH\x00\x12\x30\n\x0fvector_quantity\x18\x0e \x01(\x0b\x32\x15.sysml.VectorQuantityH\x00\x12\x30\n\x0fmeasurement_ref\x18\x0f \x01(\x0b\x32\x15.sysml.MeasurementRefH\x00\x42\x06\n\x04kind\";\n\x05\x41rray\x12\x12\n\ndimensions\x18\x01 \x03(\x03\x12\x1e\n\x08\x65lements\x18\x02 \x03(\x0b\x32\x0c.sysml.Value\"*\n\x06Vector\x12 \n\ncomponents\x18\x01 \x03(\x0b\x32\x0c.sysml.Value\"5\n\x0eVectorQuantity\x12#\n\ncomponents\x18\x01 \x03(\x0b\x32\x0f.sysml.Quantity\"*\n\x07\x43omplex\x12\x0c\n\x04real\x18\x01 \x01(\x01\x12\x11\n\timaginary\x18\x02 \x01(\x01\"G\n\x0b\x45numLiteral\x12\x12\n\nliteral_id\x18\x01 \x01(\t\x12\x16\n\x0e\x65numeration_id\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\"/\n\rValueSequence\x12\x1e\n\x08\x65lements\x18\x01 \x03(\x0b\x32\x0c.sysml.Value\"|\n\x08Quantity\x12\x17\n\rint_magnitude\x18\x01 \x01(\x03H\x00\x12\x18\n\x0ereal_magnitude\x18\x02 \x01(\x01H\x00\x12\x0c\n\x04unit\x18\x03 \x01(\t\x12\"\n\tunit_term\x18\x04 \x01(\x0b\x32\x0f.sysml.UnitTermB\x0b\n\tmagnitude\"S\n\x0eMeasurementRef\x12\x0c\n\x04unit\x18\x01 \x01(\t\x12\"\n\tunit_term\x18\x02 \x01(\x0b\x32\x0f.sysml.UnitTerm\x12\x0f\n\x07unit_id\x18\x03 \x01(\t\"T\n\x08UnitTerm\x12\x11\n\tscale_num\x18\x01 \x01(\x01\x12\x11\n\tscale_den\x18\x02 \x01(\x01\x12\"\n\x07\x66\x61\x63tors\x18\x03 \x03(\x0b\x32\x11.sysml.UnitFactor\"/\n\nUnitFactor\x12\x0f\n\x07unit_id\x18\x01 \x01(\t\x12\x10\n\x08\x65xponent\x18\x02 \x01(\x01\"J\n\nDiagnostic\x12\x10\n\x08severity\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x19\n\x04span\x18\x03 \x01(\x0b\x32\x0b.sysml.Span\"^\n\x04Span\x12\x0c\n\x04\x66ile\x18\x01 \x01(\t\x12\x12\n\nstart_line\x18\x02 \x01(\x05\x12\x11\n\tstart_col\x18\x03 \x01(\x05\x12\x10\n\x08\x65nd_line\x18\x04 \x01(\x05\x12\x0f\n\x07\x65nd_col\x18\x05 \x01(\x05\"\x13\n\x11ServerInfoRequest\";\n\x12ServerInfoResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x14\n\x0c\x63\x61pabilities\x18\x02 \x03(\t\"S\n\x0cQueryRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x1b\n\x05query\x18\x02 \x01(\x0b\x32\x0c.sysml.Query\x12\x12\n\noslc_query\x18\x03 \x01(\t\"<\n\rQueryResponse\x12+\n\x08\x65lements\x18\x01 \x03(\x0b\x32\x19.sysml.QueryResultElement\"H\n\x05Query\x12\r\n\x05scope\x18\x01 \x03(\t\x12\x0e\n\x06select\x18\x02 \x03(\t\x12 \n\x05where\x18\x03 \x01(\x0b\x32\x11.sysml.Constraint\"|\n\nConstraint\x12/\n\tprimitive\x18\x01 \x01(\x0b\x32\x1a.sysml.PrimitiveConstraintH\x00\x12/\n\tcomposite\x18\x02 \x01(\x0b\x32\x1a.sysml.CompositeConstraintH\x00\x42\x0c\n\nconstraint\"s\n\x13PrimitiveConstraint\x12\x0f\n\x07inverse\x18\x01 \x01(\x08\x12\x10\n\x08property\x18\x02 \x01(\t\x12*\n\x08operator\x18\x03 \x01(\x0e\x32\x18.sysml.PrimitiveOperator\x12\r\n\x05value\x18\x04 \x03(\t\"h\n\x13\x43ompositeConstraint\x12*\n\x08operator\x18\x01 \x01(\x0e\x32\x18.sysml.CompositeOperator\x12%\n\nconstraint\x18\x02 \x03(\x0b\x32\x11.sysml.Constraint\"\xa0\x01\n\x12QueryResultElement\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12=\n\nproperties\x18\x03 \x03(\x0b\x32).sysml.QueryResultElement.PropertiesEntry\x1a\x31\n\x0fPropertiesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"s\n\nSweepRange\x12\x11\n\tparameter\x18\x01 \x01(\t\x12\x1b\n\x05start\x18\x02 \x01(\x0b\x32\x0c.sysml.Value\x12\x19\n\x03\x65nd\x18\x03 \x01(\x0b\x32\x0c.sysml.Value\x12\x1a\n\x04step\x18\x04 \x01(\x0b\x32\x0c.sysml.Value\"\xc0\x02\n\x0fRunSweepRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x03 \x01(\t\x12\x1f\n\targuments\x18\x04 \x03(\x0b\x32\x0c.sysml.Value\x12\x43\n\x0fnamed_arguments\x18\x05 \x03(\x0b\x32*.sysml.RunSweepRequest.NamedArgumentsEntry\x12!\n\x06ranges\x18\x06 \x03(\x0b\x32\x11.sysml.SweepRange\x12\x0f\n\x07samples\x18\x07 \x01(\x03\x12\x0c\n\x04seed\x18\x08 \x01(\x04\x1a\x43\n\x13NamedArgumentsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"\xc8\x01\n\x08SweepRow\x12!\n\x06inputs\x18\x01 \x03(\x0b\x32\x11.sysml.CalcOutput\x12\"\n\x07outputs\x18\x02 \x03(\x0b\x32\x11.sysml.CalcOutput\x12 \n\x08verdicts\x18\x03 \x03(\x0b\x32\x0e.sysml.Verdict\x12\x16\n\x0e\x65lapsed_micros\x18\x04 \x01(\x03\x12\r\n\x05\x65rror\x18\x05 \x01(\t\x12,\n\x0e\x66\x61ilure_reason\x18\x06 \x01(\x0e\x32\x14.sysml.FailureReason\"\xed\x01\n\x10RunSweepResponse\x12\x1d\n\x04rows\x18\x01 \x03(\x0b\x32\x0f.sysml.SweepRow\x12\x12\n\nparameters\x18\x02 \x03(\t\x12\x0f\n\x07sampled\x18\x03 \x01(\x08\x12\x0c\n\x04seed\x18\x04 \x01(\x04\x12\r\n\x05\x65rror\x18\x05 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x06 \x03(\x0b\x32\x11.sysml.Diagnostic\x12,\n\x0e\x66\x61ilure_reason\x18\x07 \x01(\x0e\x32\x14.sysml.FailureReason\x12\"\n\tinstances\x18\x08 \x03(\x0b\x32\x0f.sysml.Instance\"n\n\x17RunDocumentQueryRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x10\n\x08query_id\x18\x02 \x01(\t\x12-\n\x08\x62indings\x18\x03 \x03(\x0b\x32\x1b.sysml.DocumentQueryBinding\"O\n\x14\x44ocumentQueryBinding\x12\x11\n\tparameter\x18\x01 \x01(\t\x12$\n\x06values\x18\x02 \x03(\x0b\x32\x14.sysml.DocumentValue\"\xd5\x01\n\rDocumentValue\x12\x14\n\nelement_id\x18\x01 \x01(\tH\x00\x12\x16\n\x0cstring_value\x18\x02 \x01(\tH\x00\x12\x13\n\tint_value\x18\x03 \x01(\x03H\x00\x12\x14\n\nreal_value\x18\x04 \x01(\x01H\x00\x12\x14\n\nbool_value\x18\x05 \x01(\x08H\x00\x12\x12\n\x08infinity\x18\x06 \x01(\x08H\x00\x12#\n\x08quantity\x18\x08 \x01(\x0b\x32\x0f.sysml.QuantityH\x00\x12\x14\n\x0c\x65lement_type\x18\x07 \x01(\tB\x06\n\x04kind\"#\n\x13\x44ocumentQueryColumn\x12\x0c\n\x04name\x18\x01 \x01(\t\"9\n\x11\x44ocumentQueryCell\x12$\n\x06values\x18\x01 \x03(\x0b\x32\x14.sysml.DocumentValue\"b\n\x10\x44ocumentQueryRow\x12%\n\x07\x65lement\x18\x01 \x01(\x0b\x32\x14.sysml.DocumentValue\x12\'\n\x05\x63\x65lls\x18\x02 \x03(\x0b\x32\x18.sysml.DocumentQueryCell\"n\n\x18RunDocumentQueryResponse\x12+\n\x07\x63olumns\x18\x01 \x03(\x0b\x32\x1a.sysml.DocumentQueryColumn\x12%\n\x04rows\x18\x02 \x03(\x0b\x32\x17.sysml.DocumentQueryRow\"@\n\x15RenderDocumentRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x13\n\x0b\x64ocument_id\x18\x02 \x01(\t\"*\n\x16RenderDocumentResponse\x12\x10\n\x08markdown\x18\x01 \x01(\t*\x93\x01\n\rFailureReason\x12\x1e\n\x1a\x46\x41ILURE_REASON_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x46\x41ILURE_REASON_EVALUATION\x10\x01\x12\x1d\n\x19\x46\x41ILURE_REASON_WRONG_KIND\x10\x02\x12$\n FAILURE_REASON_AMBIGUOUS_SUBJECT\x10\x03*\x9d\x04\n\x0b\x45\x64itFailure\x12\x1c\n\x18\x45\x44IT_FAILURE_UNSPECIFIED\x10\x00\x12\x1e\n\x1a\x45\x44IT_FAILURE_NO_OPERATIONS\x10\x01\x12\x1f\n\x1b\x45\x44IT_FAILURE_UNKNOWN_TARGET\x10\x02\x12!\n\x1d\x45\x44IT_FAILURE_AMBIGUOUS_TARGET\x10\x03\x12\x1b\n\x17\x45\x44IT_FAILURE_NOT_VALUED\x10\x04\x12\x1e\n\x1a\x45\x44IT_FAILURE_INVALID_VALUE\x10\x05\x12\x1d\n\x19\x45\x44IT_FAILURE_INVALID_NAME\x10\x06\x12\x1a\n\x16\x45\x44IT_FAILURE_NOT_NAMED\x10\x07\x12\"\n\x1e\x45\x44IT_FAILURE_RENAME_REFERENCED\x10\x08\x12\"\n\x1e\x45\x44IT_FAILURE_OVERLAPPING_EDITS\x10\t\x12\x1f\n\x1b\x45\x44IT_FAILURE_RESULT_INVALID\x10\n\x12\x1e\n\x1a\x45\x44IT_FAILURE_OWNER_UNKNOWN\x10\x0b\x12$\n EDIT_FAILURE_OWNER_NOT_NAMESPACE\x10\x0c\x12\x1d\n\x19\x45\x44IT_FAILURE_ILLEGAL_KIND\x10\r\x12\"\n\x1e\x45\x44IT_FAILURE_MEMBER_NAME_TAKEN\x10\x0e\x12\"\n\x1e\x45\x44IT_FAILURE_DELETE_REFERENCED\x10\x0f*\x92\x01\n\x11PrimitiveOperator\x12\"\n\x1ePRIMITIVE_OPERATOR_UNSPECIFIED\x10\x00\x12\x1c\n\x18PRIMITIVE_OPERATOR_EQUAL\x10\x01\x12\x1e\n\x1aPRIMITIVE_OPERATOR_GREATER\x10\x02\x12\x1b\n\x17PRIMITIVE_OPERATOR_LESS\x10\x03*n\n\x11\x43ompositeOperator\x12\"\n\x1e\x43OMPOSITE_OPERATOR_UNSPECIFIED\x10\x00\x12\x1a\n\x16\x43OMPOSITE_OPERATOR_AND\x10\x01\x12\x19\n\x15\x43OMPOSITE_OPERATOR_OR\x10\x02\x32\xa4\x0b\n\x0cSysMLService\x12\x44\n\rGetServerInfo\x12\x18.sysml.ServerInfoRequest\x1a\x19.sysml.ServerInfoResponse\x12>\n\tParseFile\x12\x17.sysml.ParseFileRequest\x1a\x18.sysml.ParseFileResponse\x12G\n\x0cParseSources\x12\x1a.sysml.ParseSourcesRequest\x1a\x1b.sysml.ParseSourcesResponse\x12;\n\tGetSymbol\x12\x17.sysml.GetSymbolRequest\x1a\x15.sysml.SymbolResponse\x12G\n\x0eGetDiagnostics\x12\x19.sysml.DiagnosticsRequest\x1a\x1a.sysml.DiagnosticsResponse\x12;\n\x08\x45valuate\x12\x16.sysml.EvaluateRequest\x1a\x17.sysml.EvaluateResponse\x12\x44\n\x0bInstantiate\x12\x19.sysml.InstantiateRequest\x1a\x1a.sysml.InstantiateResponse\x12J\n\rExecuteAction\x12\x1b.sysml.ExecuteActionRequest\x1a\x1c.sysml.ExecuteActionResponse\x12G\n\x0c\x45xecuteState\x12\x1a.sysml.ExecuteStateRequest\x1a\x1b.sysml.ExecuteStateResponse\x12\x38\n\x07\x43onvert\x12\x15.sysml.ConvertRequest\x1a\x16.sysml.ConvertResponse\x12\x41\n\nApplyEdits\x12\x18.sysml.ApplyEditsRequest\x1a\x19.sysml.ApplyEditsResponse\x12S\n\x10VerifyConstraint\x12\x1e.sysml.VerifyConstraintRequest\x1a\x1f.sysml.VerifyConstraintResponse\x12V\n\x11VerifyRequirement\x12\x1f.sysml.VerifyRequirementRequest\x1a .sysml.VerifyRequirementResponse\x12Y\n\x12VerifySatisfaction\x12 .sysml.VerifySatisfactionRequest\x1a!.sysml.VerifySatisfactionResponse\x12G\n\x0c\x45valuateCalc\x12\x1a.sysml.EvaluateCalcRequest\x1a\x1b.sysml.EvaluateCalcResponse\x12\x44\n\x0bRunAnalysis\x12\x19.sysml.RunAnalysisRequest\x1a\x1a.sysml.RunAnalysisResponse\x12;\n\x08RunSweep\x12\x16.sysml.RunSweepRequest\x1a\x17.sysml.RunSweepResponse\x12\x32\n\x05Query\x12\x13.sysml.QueryRequest\x1a\x14.sysml.QueryResponse\x12S\n\x10RunDocumentQuery\x12\x1e.sysml.RunDocumentQueryRequest\x1a\x1f.sysml.RunDocumentQueryResponse\x12M\n\x0eRenderDocument\x12\x1c.sysml.RenderDocumentRequest\x1a\x1d.sysml.RenderDocumentResponseB*Z(github.com/Open-MBEE/OpenSysML/api/protob\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0bsysml.proto\x12\x05sysml\"\xe2\x01\n\x07Verdict\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12\x12\n\nelement_id\x18\x02 \x01(\t\x12\x0f\n\x07\x65lement\x18\x03 \x01(\t\x12\r\n\x05holds\x18\x04 \x01(\x08\x12\x11\n\tcondition\x18\x05 \x01(\t\x12\x13\n\x0binstance_id\x18\x06 \x01(\x03\x12\x18\n\x10instance_type_id\x18\x07 \x01(\t\x12\r\n\x05\x65rror\x18\x08 \x01(\t\x12,\n\x0e\x66\x61ilure_reason\x18\t \x01(\x0e\x32\x14.sysml.FailureReason\x12\x16\n\x0erequirement_id\x18\n \x01(\t\"[\n\x17VerifyConstraintRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x03 \x01(\t\"\x96\x01\n\x18VerifyConstraintResponse\x12\x1f\n\x07verdict\x18\x01 \x01(\x0b\x32\x0e.sysml.Verdict\x12\"\n\tinstances\x18\x02 \x03(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\"\\\n\x18VerifyRequirementRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x03 \x01(\t\"m\n\x13VerificationVerdict\x12\x0f\n\x07\x63\x61se_id\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x03 \x01(\t\x12\x0f\n\x07subcase\x18\x04 \x01(\x08\x12\x16\n\x0erequirement_id\x18\x05 \x01(\t\"\xd2\x01\n\x19VerifyRequirementResponse\x12\x1f\n\x07verdict\x18\x01 \x01(\x0b\x32\x0e.sysml.Verdict\x12\"\n\tinstances\x18\x02 \x03(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\x39\n\x15verification_verdicts\x18\x05 \x03(\x0b\x32\x1a.sysml.VerificationVerdict\"B\n\x19VerifySatisfactionRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\"\x82\x02\n\x1aVerifySatisfactionResponse\x12 \n\x08verdicts\x18\x01 \x03(\x0b\x32\x0e.sysml.Verdict\x12\"\n\tinstances\x18\x02 \x03(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\x12,\n\x0e\x66\x61ilure_reason\x18\x05 \x01(\x0e\x32\x14.sysml.FailureReason\x12\x39\n\x15verification_verdicts\x18\x06 \x03(\x0b\x32\x1a.sysml.VerificationVerdict\"]\n\x13\x45valuateCalcRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x1f\n\targuments\x18\x03 \x03(\x0b\x32\x0c.sysml.Value\"\xbd\x01\n\x14\x45valuateCalcResponse\x12\x1c\n\x06result\x18\x01 \x01(\x0b\x32\x0c.sysml.Value\x12\"\n\x07outputs\x18\x02 \x03(\x0b\x32\x11.sysml.CalcOutput\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\x12,\n\x0e\x66\x61ilure_reason\x18\x05 \x01(\x0e\x32\x14.sysml.FailureReason\"7\n\nCalcOutput\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value\"\x84\x02\n\x12RunAnalysisRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x03 \x01(\t\x12\x1f\n\targuments\x18\x04 \x03(\x0b\x32\x0c.sysml.Value\x12\x46\n\x0fnamed_arguments\x18\x05 \x03(\x0b\x32-.sysml.RunAnalysisRequest.NamedArgumentsEntry\x1a\x43\n\x13NamedArgumentsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"\x9f\x02\n\x13RunAnalysisResponse\x12\"\n\x07outputs\x18\x01 \x03(\x0b\x32\x11.sysml.CalcOutput\x12 \n\x08verdicts\x18\x02 \x03(\x0b\x32\x0e.sysml.Verdict\x12\"\n\tinstances\x18\x03 \x03(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x04 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x05 \x03(\x0b\x32\x11.sysml.Diagnostic\x12,\n\x0e\x66\x61ilure_reason\x18\x06 \x01(\x0e\x32\x14.sysml.FailureReason\x12\x39\n\x15verification_verdicts\x18\x07 \x03(\x0b\x32\x1a.sysml.VerificationVerdict\"\x8c\x01\n\x10ParseFileRequest\x12\x13\n\tfile_path\x18\x01 \x01(\tH\x00\x12\x11\n\x07\x63ontent\x18\x02 \x01(\tH\x00\x12\x18\n\x0c\x63ontent_hash\x18\x03 \x01(\tB\x02\x18\x01\x12\x10\n\x08language\x18\x04 \x01(\t\x12\x1a\n\x12strict_conformance\x18\x05 \x01(\x08\x42\x08\n\x06source\"b\n\x0eSourceDocument\x12\x13\n\tfile_path\x18\x01 \x01(\tH\x00\x12\x11\n\x07\x63ontent\x18\x02 \x01(\tH\x00\x12\x10\n\x08language\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\tB\x08\n\x06source\"[\n\x13ParseSourcesRequest\x12(\n\tdocuments\x18\x01 \x03(\x0b\x32\x15.sysml.SourceDocument\x12\x1a\n\x12strict_conformance\x18\x02 \x01(\x08\"\x83\x01\n\x14ParseSourcesResponse\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12 \n\x05roots\x18\x02 \x03(\x0b\x32\x11.sysml.SymbolInfo\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"\x7f\n\x11ParseFileResponse\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x1f\n\x04root\x18\x02 \x01(\x0b\x32\x11.sysml.SymbolInfo\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"9\n\x10GetSymbolRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\"B\n\x0eSymbolResponse\x12!\n\x06symbol\x18\x01 \x01(\x0b\x32\x11.sysml.SymbolInfo\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"(\n\x12\x44iagnosticsRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\"L\n\x13\x44iagnosticsResponse\x12&\n\x0b\x64iagnostics\x18\x01 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"o\n\x0f\x45valuateRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x12\n\nexpression\x18\x02 \x01(\t\x12\x19\n\x11\x63ontext_symbol_id\x18\x03 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x04 \x01(\t\"g\n\x10\x45valuateResponse\x12\x1c\n\x06result\x18\x01 \x01(\x0b\x32\x0c.sysml.Value\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\"\xc2\x01\n\x08Instance\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x16\n\x0etype_symbol_id\x18\x02 \x01(\t\x12:\n\x0e\x66\x65\x61ture_values\x18\x04 \x03(\x0b\x32\".sysml.Instance.FeatureValuesEntry\x1aI\n\x12\x46\x65\x61tureValuesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.sysml.FeatureValue:\x02\x38\x01J\x04\x08\x03\x10\x04R\x05slots\"\x84\x01\n\x0c\x46\x65\x61tureValue\x12\x14\n\x0c\x66\x65\x61ture_name\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value\x12\x1c\n\x06values\x18\x03 \x03(\x0b\x32\x0c.sysml.Value\x12\x14\n\x0cmaterialized\x18\x04 \x01(\x08\x12\r\n\x05\x65rror\x18\x05 \x01(\t\";\n\x12InstantiateRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\"\x93\x01\n\x13InstantiateResponse\x12!\n\x08instance\x18\x01 \x01(\x0b\x32\x0f.sysml.Instance\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\"\n\tinstances\x18\x04 \x03(\x0b\x32\x0f.sysml.Instance\"\xba\x01\n\x14\x45xecuteActionRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x18\n\x10\x61\x63tion_symbol_id\x18\x02 \x01(\t\x12\x37\n\x06inputs\x18\x03 \x03(\x0b\x32\'.sysml.ExecuteActionRequest.InputsEntry\x1a;\n\x0bInputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"\xc8\x01\n\x15\x45xecuteActionResponse\x12:\n\x07outputs\x18\x01 \x03(\x0b\x32).sysml.ExecuteActionResponse.OutputsEntry\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32\x11.sysml.Diagnostic\x1a<\n\x0cOutputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"Z\n\x13\x45xecuteStateRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x1f\n\x17state_machine_symbol_id\x18\x02 \x01(\t\x12\x0e\n\x06\x65vents\x18\x03 \x03(\t\"\xee\x01\n\x14\x45xecuteStateResponse\x12\x16\n\x0estates_visited\x18\x01 \x03(\t\x12\x44\n\rfinal_context\x18\x02 \x03(\x0b\x32-.sysml.ExecuteStateResponse.FinalContextEntry\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x04 \x03(\x0b\x32\x11.sysml.Diagnostic\x1a\x41\n\x11\x46inalContextEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"\xa0\x01\n\x0e\x43onvertRequest\x12\x13\n\tfile_path\x18\x01 \x01(\tH\x00\x12\x11\n\x07\x63ontent\x18\x02 \x01(\tH\x00\x12\x14\n\nmodel_hash\x18\x06 \x01(\tH\x00\x12\x13\n\x0b\x66rom_format\x18\x03 \x01(\t\x12\x11\n\tto_format\x18\x04 \x01(\t\x12\x1e\n\x16tolerate_syntax_errors\x18\x05 \x01(\x08\x42\x08\n\x06source\"\xb4\x01\n\x0f\x43onvertResponse\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12\x13\n\x0b\x66rom_format\x18\x02 \x01(\t\x12\x11\n\tto_format\x18\x03 \x01(\t\x12\r\n\x05\x65rror\x18\x04 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x05 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\x14\n\x0c\x65xperimental\x18\x06 \x01(\x08\x12\x1b\n\x13\x65xperimental_notice\x18\x07 \x01(\t\"Q\n\x11\x41pplyEditsRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12(\n\noperations\x18\x02 \x03(\x0b\x32\x14.sysml.EditOperation\"\xbc\x01\n\rEditOperation\x12(\n\tset_value\x18\x01 \x01(\x0b\x32\x13.sysml.SetValueEditH\x00\x12#\n\x06rename\x18\x02 \x01(\x0b\x32\x11.sysml.RenameEditH\x00\x12*\n\nadd_member\x18\x03 \x01(\x0b\x32\x14.sysml.AddMemberEditH\x00\x12#\n\x06\x64\x65lete\x18\x04 \x01(\x0b\x32\x11.sysml.DeleteEditH\x00\x42\x0b\n\toperation\"\x82\x01\n\rAddMemberEdit\x12\r\n\x05owner\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\t\x12\x14\n\x0cmultiplicity\x18\x05 \x01(\t\x12\r\n\x05value\x18\x06 \x01(\t\x12\x13\n\x0bspecializes\x18\x07 \x03(\t\"-\n\nDeleteEdit\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\x0f\n\x07\x63\x61scade\x18\x02 \x01(\x08\"-\n\x0cSetValueEdit\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\".\n\nRenameEdit\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\x10\n\x08new_name\x18\x02 \x01(\t\"\xc2\x01\n\x12\x41pplyEditsResponse\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12#\n\x07\x61pplied\x18\x02 \x03(\x0b\x32\x12.sysml.AppliedEdit\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12#\n\x07\x66\x61ilure\x18\x04 \x01(\x0e\x32\x12.sysml.EditFailure\x12&\n\x0b\x64iagnostics\x18\x05 \x03(\x0b\x32\x11.sysml.Diagnostic\x12\x1a\n\x12referring_elements\x18\x06 \x03(\t\"z\n\x0b\x41ppliedEdit\x12\x17\n\x0foperation_index\x18\x01 \x01(\x05\x12\x0e\n\x06target\x18\x02 \x01(\t\x12\x0e\n\x06offset\x18\x03 \x01(\x05\x12\x0e\n\x06length\x18\x04 \x01(\x05\x12\x10\n\x08old_text\x18\x05 \x01(\t\x12\x10\n\x08new_text\x18\x06 \x01(\t\"\xfd\x02\n\nSymbolInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04kind\x18\x03 \x01(\t\x12\x31\n\x08metadata\x18\x04 \x03(\x0b\x32\x1f.sysml.SymbolInfo.MetadataEntry\x12\x11\n\tchild_ids\x18\x05 \x03(\t\x12(\n\nattributes\x18\x06 \x03(\x0b\x32\x14.sysml.AttributeInfo\x12\"\n\ttype_info\x18\x07 \x01(\x0b\x32\x0f.sysml.TypeInfo\x12-\n\x0cmultiplicity\x18\x08 \x01(\x0b\x32\x17.sysml.MultiplicityInfo\x12.\n\x0fspecializations\x18\t \x03(\x0b\x32\x15.sysml.Specialization\x12#\n\x1bwithheld_library_attributes\x18\n \x01(\x05\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"X\n\x0eSpecialization\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12\x10\n\x08\x64\x65\x63lared\x18\x02 \x01(\t\x12\x11\n\ttarget_id\x18\x03 \x01(\t\x12\x13\n\x0btarget_kind\x18\x04 \x01(\t\"\x95\x01\n\x08TypeInfo\x12\x10\n\x08\x64\x65\x63lared\x18\x01 \x01(\t\x12\x13\n\x0bresolved_id\x18\x02 \x01(\t\x12\x15\n\rresolved_kind\x18\x03 \x01(\t\x12\x11\n\tprimitive\x18\x04 \x01(\t\x12\x18\n\x10primitive_source\x18\x05 \x01(\t\x12\x10\n\x08quantity\x18\x06 \x01(\x08\x12\x0c\n\x04unit\x18\x07 \x01(\t\"0\n\x10MultiplicityInfo\x12\r\n\x05lower\x18\x01 \x01(\t\x12\r\n\x05upper\x18\x02 \x01(\t\"V\n\rAttributeInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x1b\n\x05value\x18\x03 \x01(\x0b\x32\x0c.sysml.Value\x12\x0c\n\x04unit\x18\x04 \x01(\t\"\xf6\x03\n\x05Value\x12\x13\n\tint_value\x18\x01 \x01(\x03H\x00\x12\x14\n\nreal_value\x18\x02 \x01(\x01H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x12\x16\n\x0cstring_value\x18\x04 \x01(\tH\x00\x12\x15\n\x0binstance_id\x18\x05 \x01(\x03H\x00\x12(\n\x08sequence\x18\x06 \x01(\x0b\x32\x14.sysml.ValueSequenceH\x00\x12\x0e\n\x04null\x18\x07 \x01(\tH\x00\x12#\n\x08quantity\x18\x08 \x01(\x0b\x32\x0f.sysml.QuantityH\x00\x12*\n\x0c\x65num_literal\x18\t \x01(\x0b\x32\x12.sysml.EnumLiteralH\x00\x12\x0f\n\x05unset\x18\n \x01(\x08H\x00\x12!\n\x07\x63omplex\x18\x0b \x01(\x0b\x32\x0e.sysml.ComplexH\x00\x12\x1d\n\x05\x61rray\x18\x0c \x01(\x0b\x32\x0c.sysml.ArrayH\x00\x12\x1f\n\x06vector\x18\r \x01(\x0b\x32\r.sysml.VectorH\x00\x12\x30\n\x0fvector_quantity\x18\x0e \x01(\x0b\x32\x15.sysml.VectorQuantityH\x00\x12\x30\n\x0fmeasurement_ref\x18\x0f \x01(\x0b\x32\x15.sysml.MeasurementRefH\x00\x12\x12\n\x08infinity\x18\x10 \x01(\x08H\x00\x42\x06\n\x04kind\";\n\x05\x41rray\x12\x12\n\ndimensions\x18\x01 \x03(\x03\x12\x1e\n\x08\x65lements\x18\x02 \x03(\x0b\x32\x0c.sysml.Value\"*\n\x06Vector\x12 \n\ncomponents\x18\x01 \x03(\x0b\x32\x0c.sysml.Value\"5\n\x0eVectorQuantity\x12#\n\ncomponents\x18\x01 \x03(\x0b\x32\x0f.sysml.Quantity\"*\n\x07\x43omplex\x12\x0c\n\x04real\x18\x01 \x01(\x01\x12\x11\n\timaginary\x18\x02 \x01(\x01\"G\n\x0b\x45numLiteral\x12\x12\n\nliteral_id\x18\x01 \x01(\t\x12\x16\n\x0e\x65numeration_id\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\"/\n\rValueSequence\x12\x1e\n\x08\x65lements\x18\x01 \x03(\x0b\x32\x0c.sysml.Value\"|\n\x08Quantity\x12\x17\n\rint_magnitude\x18\x01 \x01(\x03H\x00\x12\x18\n\x0ereal_magnitude\x18\x02 \x01(\x01H\x00\x12\x0c\n\x04unit\x18\x03 \x01(\t\x12\"\n\tunit_term\x18\x04 \x01(\x0b\x32\x0f.sysml.UnitTermB\x0b\n\tmagnitude\"S\n\x0eMeasurementRef\x12\x0c\n\x04unit\x18\x01 \x01(\t\x12\"\n\tunit_term\x18\x02 \x01(\x0b\x32\x0f.sysml.UnitTerm\x12\x0f\n\x07unit_id\x18\x03 \x01(\t\"T\n\x08UnitTerm\x12\x11\n\tscale_num\x18\x01 \x01(\x01\x12\x11\n\tscale_den\x18\x02 \x01(\x01\x12\"\n\x07\x66\x61\x63tors\x18\x03 \x03(\x0b\x32\x11.sysml.UnitFactor\"/\n\nUnitFactor\x12\x0f\n\x07unit_id\x18\x01 \x01(\t\x12\x10\n\x08\x65xponent\x18\x02 \x01(\x01\"J\n\nDiagnostic\x12\x10\n\x08severity\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x19\n\x04span\x18\x03 \x01(\x0b\x32\x0b.sysml.Span\"^\n\x04Span\x12\x0c\n\x04\x66ile\x18\x01 \x01(\t\x12\x12\n\nstart_line\x18\x02 \x01(\x05\x12\x11\n\tstart_col\x18\x03 \x01(\x05\x12\x10\n\x08\x65nd_line\x18\x04 \x01(\x05\x12\x0f\n\x07\x65nd_col\x18\x05 \x01(\x05\"\x13\n\x11ServerInfoRequest\";\n\x12ServerInfoResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x14\n\x0c\x63\x61pabilities\x18\x02 \x03(\t\"S\n\x0cQueryRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x1b\n\x05query\x18\x02 \x01(\x0b\x32\x0c.sysml.Query\x12\x12\n\noslc_query\x18\x03 \x01(\t\"<\n\rQueryResponse\x12+\n\x08\x65lements\x18\x01 \x03(\x0b\x32\x19.sysml.QueryResultElement\"H\n\x05Query\x12\r\n\x05scope\x18\x01 \x03(\t\x12\x0e\n\x06select\x18\x02 \x03(\t\x12 \n\x05where\x18\x03 \x01(\x0b\x32\x11.sysml.Constraint\"|\n\nConstraint\x12/\n\tprimitive\x18\x01 \x01(\x0b\x32\x1a.sysml.PrimitiveConstraintH\x00\x12/\n\tcomposite\x18\x02 \x01(\x0b\x32\x1a.sysml.CompositeConstraintH\x00\x42\x0c\n\nconstraint\"s\n\x13PrimitiveConstraint\x12\x0f\n\x07inverse\x18\x01 \x01(\x08\x12\x10\n\x08property\x18\x02 \x01(\t\x12*\n\x08operator\x18\x03 \x01(\x0e\x32\x18.sysml.PrimitiveOperator\x12\r\n\x05value\x18\x04 \x03(\t\"h\n\x13\x43ompositeConstraint\x12*\n\x08operator\x18\x01 \x01(\x0e\x32\x18.sysml.CompositeOperator\x12%\n\nconstraint\x18\x02 \x03(\x0b\x32\x11.sysml.Constraint\"\xa0\x01\n\x12QueryResultElement\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12=\n\nproperties\x18\x03 \x03(\x0b\x32).sysml.QueryResultElement.PropertiesEntry\x1a\x31\n\x0fPropertiesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"s\n\nSweepRange\x12\x11\n\tparameter\x18\x01 \x01(\t\x12\x1b\n\x05start\x18\x02 \x01(\x0b\x32\x0c.sysml.Value\x12\x19\n\x03\x65nd\x18\x03 \x01(\x0b\x32\x0c.sysml.Value\x12\x1a\n\x04step\x18\x04 \x01(\x0b\x32\x0c.sysml.Value\"\xc0\x02\n\x0fRunSweepRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x11\n\tsymbol_id\x18\x02 \x01(\t\x12\x19\n\x11subject_symbol_id\x18\x03 \x01(\t\x12\x1f\n\targuments\x18\x04 \x03(\x0b\x32\x0c.sysml.Value\x12\x43\n\x0fnamed_arguments\x18\x05 \x03(\x0b\x32*.sysml.RunSweepRequest.NamedArgumentsEntry\x12!\n\x06ranges\x18\x06 \x03(\x0b\x32\x11.sysml.SweepRange\x12\x0f\n\x07samples\x18\x07 \x01(\x03\x12\x0c\n\x04seed\x18\x08 \x01(\x04\x1a\x43\n\x13NamedArgumentsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1b\n\x05value\x18\x02 \x01(\x0b\x32\x0c.sysml.Value:\x02\x38\x01\"\xc8\x01\n\x08SweepRow\x12!\n\x06inputs\x18\x01 \x03(\x0b\x32\x11.sysml.CalcOutput\x12\"\n\x07outputs\x18\x02 \x03(\x0b\x32\x11.sysml.CalcOutput\x12 \n\x08verdicts\x18\x03 \x03(\x0b\x32\x0e.sysml.Verdict\x12\x16\n\x0e\x65lapsed_micros\x18\x04 \x01(\x03\x12\r\n\x05\x65rror\x18\x05 \x01(\t\x12,\n\x0e\x66\x61ilure_reason\x18\x06 \x01(\x0e\x32\x14.sysml.FailureReason\"\xed\x01\n\x10RunSweepResponse\x12\x1d\n\x04rows\x18\x01 \x03(\x0b\x32\x0f.sysml.SweepRow\x12\x12\n\nparameters\x18\x02 \x03(\t\x12\x0f\n\x07sampled\x18\x03 \x01(\x08\x12\x0c\n\x04seed\x18\x04 \x01(\x04\x12\r\n\x05\x65rror\x18\x05 \x01(\t\x12&\n\x0b\x64iagnostics\x18\x06 \x03(\x0b\x32\x11.sysml.Diagnostic\x12,\n\x0e\x66\x61ilure_reason\x18\x07 \x01(\x0e\x32\x14.sysml.FailureReason\x12\"\n\tinstances\x18\x08 \x03(\x0b\x32\x0f.sysml.Instance\"n\n\x17RunDocumentQueryRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x10\n\x08query_id\x18\x02 \x01(\t\x12-\n\x08\x62indings\x18\x03 \x03(\x0b\x32\x1b.sysml.DocumentQueryBinding\"O\n\x14\x44ocumentQueryBinding\x12\x11\n\tparameter\x18\x01 \x01(\t\x12$\n\x06values\x18\x02 \x03(\x0b\x32\x14.sysml.DocumentValue\"\xd5\x01\n\rDocumentValue\x12\x14\n\nelement_id\x18\x01 \x01(\tH\x00\x12\x16\n\x0cstring_value\x18\x02 \x01(\tH\x00\x12\x13\n\tint_value\x18\x03 \x01(\x03H\x00\x12\x14\n\nreal_value\x18\x04 \x01(\x01H\x00\x12\x14\n\nbool_value\x18\x05 \x01(\x08H\x00\x12\x12\n\x08infinity\x18\x06 \x01(\x08H\x00\x12#\n\x08quantity\x18\x08 \x01(\x0b\x32\x0f.sysml.QuantityH\x00\x12\x14\n\x0c\x65lement_type\x18\x07 \x01(\tB\x06\n\x04kind\"#\n\x13\x44ocumentQueryColumn\x12\x0c\n\x04name\x18\x01 \x01(\t\"9\n\x11\x44ocumentQueryCell\x12$\n\x06values\x18\x01 \x03(\x0b\x32\x14.sysml.DocumentValue\"b\n\x10\x44ocumentQueryRow\x12%\n\x07\x65lement\x18\x01 \x01(\x0b\x32\x14.sysml.DocumentValue\x12\'\n\x05\x63\x65lls\x18\x02 \x03(\x0b\x32\x18.sysml.DocumentQueryCell\"n\n\x18RunDocumentQueryResponse\x12+\n\x07\x63olumns\x18\x01 \x03(\x0b\x32\x1a.sysml.DocumentQueryColumn\x12%\n\x04rows\x18\x02 \x03(\x0b\x32\x17.sysml.DocumentQueryRow\"@\n\x15RenderDocumentRequest\x12\x12\n\nmodel_hash\x18\x01 \x01(\t\x12\x13\n\x0b\x64ocument_id\x18\x02 \x01(\t\"*\n\x16RenderDocumentResponse\x12\x10\n\x08markdown\x18\x01 \x01(\t*\x93\x01\n\rFailureReason\x12\x1e\n\x1a\x46\x41ILURE_REASON_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x46\x41ILURE_REASON_EVALUATION\x10\x01\x12\x1d\n\x19\x46\x41ILURE_REASON_WRONG_KIND\x10\x02\x12$\n FAILURE_REASON_AMBIGUOUS_SUBJECT\x10\x03*\x9d\x04\n\x0b\x45\x64itFailure\x12\x1c\n\x18\x45\x44IT_FAILURE_UNSPECIFIED\x10\x00\x12\x1e\n\x1a\x45\x44IT_FAILURE_NO_OPERATIONS\x10\x01\x12\x1f\n\x1b\x45\x44IT_FAILURE_UNKNOWN_TARGET\x10\x02\x12!\n\x1d\x45\x44IT_FAILURE_AMBIGUOUS_TARGET\x10\x03\x12\x1b\n\x17\x45\x44IT_FAILURE_NOT_VALUED\x10\x04\x12\x1e\n\x1a\x45\x44IT_FAILURE_INVALID_VALUE\x10\x05\x12\x1d\n\x19\x45\x44IT_FAILURE_INVALID_NAME\x10\x06\x12\x1a\n\x16\x45\x44IT_FAILURE_NOT_NAMED\x10\x07\x12\"\n\x1e\x45\x44IT_FAILURE_RENAME_REFERENCED\x10\x08\x12\"\n\x1e\x45\x44IT_FAILURE_OVERLAPPING_EDITS\x10\t\x12\x1f\n\x1b\x45\x44IT_FAILURE_RESULT_INVALID\x10\n\x12\x1e\n\x1a\x45\x44IT_FAILURE_OWNER_UNKNOWN\x10\x0b\x12$\n EDIT_FAILURE_OWNER_NOT_NAMESPACE\x10\x0c\x12\x1d\n\x19\x45\x44IT_FAILURE_ILLEGAL_KIND\x10\r\x12\"\n\x1e\x45\x44IT_FAILURE_MEMBER_NAME_TAKEN\x10\x0e\x12\"\n\x1e\x45\x44IT_FAILURE_DELETE_REFERENCED\x10\x0f*\x92\x01\n\x11PrimitiveOperator\x12\"\n\x1ePRIMITIVE_OPERATOR_UNSPECIFIED\x10\x00\x12\x1c\n\x18PRIMITIVE_OPERATOR_EQUAL\x10\x01\x12\x1e\n\x1aPRIMITIVE_OPERATOR_GREATER\x10\x02\x12\x1b\n\x17PRIMITIVE_OPERATOR_LESS\x10\x03*n\n\x11\x43ompositeOperator\x12\"\n\x1e\x43OMPOSITE_OPERATOR_UNSPECIFIED\x10\x00\x12\x1a\n\x16\x43OMPOSITE_OPERATOR_AND\x10\x01\x12\x19\n\x15\x43OMPOSITE_OPERATOR_OR\x10\x02\x32\xa4\x0b\n\x0cSysMLService\x12\x44\n\rGetServerInfo\x12\x18.sysml.ServerInfoRequest\x1a\x19.sysml.ServerInfoResponse\x12>\n\tParseFile\x12\x17.sysml.ParseFileRequest\x1a\x18.sysml.ParseFileResponse\x12G\n\x0cParseSources\x12\x1a.sysml.ParseSourcesRequest\x1a\x1b.sysml.ParseSourcesResponse\x12;\n\tGetSymbol\x12\x17.sysml.GetSymbolRequest\x1a\x15.sysml.SymbolResponse\x12G\n\x0eGetDiagnostics\x12\x19.sysml.DiagnosticsRequest\x1a\x1a.sysml.DiagnosticsResponse\x12;\n\x08\x45valuate\x12\x16.sysml.EvaluateRequest\x1a\x17.sysml.EvaluateResponse\x12\x44\n\x0bInstantiate\x12\x19.sysml.InstantiateRequest\x1a\x1a.sysml.InstantiateResponse\x12J\n\rExecuteAction\x12\x1b.sysml.ExecuteActionRequest\x1a\x1c.sysml.ExecuteActionResponse\x12G\n\x0c\x45xecuteState\x12\x1a.sysml.ExecuteStateRequest\x1a\x1b.sysml.ExecuteStateResponse\x12\x38\n\x07\x43onvert\x12\x15.sysml.ConvertRequest\x1a\x16.sysml.ConvertResponse\x12\x41\n\nApplyEdits\x12\x18.sysml.ApplyEditsRequest\x1a\x19.sysml.ApplyEditsResponse\x12S\n\x10VerifyConstraint\x12\x1e.sysml.VerifyConstraintRequest\x1a\x1f.sysml.VerifyConstraintResponse\x12V\n\x11VerifyRequirement\x12\x1f.sysml.VerifyRequirementRequest\x1a .sysml.VerifyRequirementResponse\x12Y\n\x12VerifySatisfaction\x12 .sysml.VerifySatisfactionRequest\x1a!.sysml.VerifySatisfactionResponse\x12G\n\x0c\x45valuateCalc\x12\x1a.sysml.EvaluateCalcRequest\x1a\x1b.sysml.EvaluateCalcResponse\x12\x44\n\x0bRunAnalysis\x12\x19.sysml.RunAnalysisRequest\x1a\x1a.sysml.RunAnalysisResponse\x12;\n\x08RunSweep\x12\x16.sysml.RunSweepRequest\x1a\x17.sysml.RunSweepResponse\x12\x32\n\x05Query\x12\x13.sysml.QueryRequest\x1a\x14.sysml.QueryResponse\x12S\n\x10RunDocumentQuery\x12\x1e.sysml.RunDocumentQueryRequest\x1a\x1f.sysml.RunDocumentQueryResponse\x12M\n\x0eRenderDocument\x12\x1c.sysml.RenderDocumentRequest\x1a\x1d.sysml.RenderDocumentResponseB*Z(github.com/Open-MBEE/OpenSysML/api/protob\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -50,14 +50,14 @@ _globals['_QUERYRESULTELEMENT_PROPERTIESENTRY']._serialized_options = b'8\001' _globals['_RUNSWEEPREQUEST_NAMEDARGUMENTSENTRY']._loaded_options = None _globals['_RUNSWEEPREQUEST_NAMEDARGUMENTSENTRY']._serialized_options = b'8\001' - _globals['_FAILUREREASON']._serialized_start=10308 - _globals['_FAILUREREASON']._serialized_end=10455 - _globals['_EDITFAILURE']._serialized_start=10458 - _globals['_EDITFAILURE']._serialized_end=10999 - _globals['_PRIMITIVEOPERATOR']._serialized_start=11002 - _globals['_PRIMITIVEOPERATOR']._serialized_end=11148 - _globals['_COMPOSITEOPERATOR']._serialized_start=11150 - _globals['_COMPOSITEOPERATOR']._serialized_end=11260 + _globals['_FAILUREREASON']._serialized_start=10328 + _globals['_FAILUREREASON']._serialized_end=10475 + _globals['_EDITFAILURE']._serialized_start=10478 + _globals['_EDITFAILURE']._serialized_end=11019 + _globals['_PRIMITIVEOPERATOR']._serialized_start=11022 + _globals['_PRIMITIVEOPERATOR']._serialized_end=11168 + _globals['_COMPOSITEOPERATOR']._serialized_start=11170 + _globals['_COMPOSITEOPERATOR']._serialized_end=11280 _globals['_VERDICT']._serialized_start=23 _globals['_VERDICT']._serialized_end=249 _globals['_VERIFYCONSTRAINTREQUEST']._serialized_start=251 @@ -165,79 +165,79 @@ _globals['_ATTRIBUTEINFO']._serialized_start=6365 _globals['_ATTRIBUTEINFO']._serialized_end=6451 _globals['_VALUE']._serialized_start=6454 - _globals['_VALUE']._serialized_end=6936 - _globals['_ARRAY']._serialized_start=6938 - _globals['_ARRAY']._serialized_end=6997 - _globals['_VECTOR']._serialized_start=6999 - _globals['_VECTOR']._serialized_end=7041 - _globals['_VECTORQUANTITY']._serialized_start=7043 - _globals['_VECTORQUANTITY']._serialized_end=7096 - _globals['_COMPLEX']._serialized_start=7098 - _globals['_COMPLEX']._serialized_end=7140 - _globals['_ENUMLITERAL']._serialized_start=7142 - _globals['_ENUMLITERAL']._serialized_end=7213 - _globals['_VALUESEQUENCE']._serialized_start=7215 - _globals['_VALUESEQUENCE']._serialized_end=7262 - _globals['_QUANTITY']._serialized_start=7264 - _globals['_QUANTITY']._serialized_end=7388 - _globals['_MEASUREMENTREF']._serialized_start=7390 - _globals['_MEASUREMENTREF']._serialized_end=7473 - _globals['_UNITTERM']._serialized_start=7475 - _globals['_UNITTERM']._serialized_end=7559 - _globals['_UNITFACTOR']._serialized_start=7561 - _globals['_UNITFACTOR']._serialized_end=7608 - _globals['_DIAGNOSTIC']._serialized_start=7610 - _globals['_DIAGNOSTIC']._serialized_end=7684 - _globals['_SPAN']._serialized_start=7686 - _globals['_SPAN']._serialized_end=7780 - _globals['_SERVERINFOREQUEST']._serialized_start=7782 - _globals['_SERVERINFOREQUEST']._serialized_end=7801 - _globals['_SERVERINFORESPONSE']._serialized_start=7803 - _globals['_SERVERINFORESPONSE']._serialized_end=7862 - _globals['_QUERYREQUEST']._serialized_start=7864 - _globals['_QUERYREQUEST']._serialized_end=7947 - _globals['_QUERYRESPONSE']._serialized_start=7949 - _globals['_QUERYRESPONSE']._serialized_end=8009 - _globals['_QUERY']._serialized_start=8011 - _globals['_QUERY']._serialized_end=8083 - _globals['_CONSTRAINT']._serialized_start=8085 - _globals['_CONSTRAINT']._serialized_end=8209 - _globals['_PRIMITIVECONSTRAINT']._serialized_start=8211 - _globals['_PRIMITIVECONSTRAINT']._serialized_end=8326 - _globals['_COMPOSITECONSTRAINT']._serialized_start=8328 - _globals['_COMPOSITECONSTRAINT']._serialized_end=8432 - _globals['_QUERYRESULTELEMENT']._serialized_start=8435 - _globals['_QUERYRESULTELEMENT']._serialized_end=8595 - _globals['_QUERYRESULTELEMENT_PROPERTIESENTRY']._serialized_start=8546 - _globals['_QUERYRESULTELEMENT_PROPERTIESENTRY']._serialized_end=8595 - _globals['_SWEEPRANGE']._serialized_start=8597 - _globals['_SWEEPRANGE']._serialized_end=8712 - _globals['_RUNSWEEPREQUEST']._serialized_start=8715 - _globals['_RUNSWEEPREQUEST']._serialized_end=9035 + _globals['_VALUE']._serialized_end=6956 + _globals['_ARRAY']._serialized_start=6958 + _globals['_ARRAY']._serialized_end=7017 + _globals['_VECTOR']._serialized_start=7019 + _globals['_VECTOR']._serialized_end=7061 + _globals['_VECTORQUANTITY']._serialized_start=7063 + _globals['_VECTORQUANTITY']._serialized_end=7116 + _globals['_COMPLEX']._serialized_start=7118 + _globals['_COMPLEX']._serialized_end=7160 + _globals['_ENUMLITERAL']._serialized_start=7162 + _globals['_ENUMLITERAL']._serialized_end=7233 + _globals['_VALUESEQUENCE']._serialized_start=7235 + _globals['_VALUESEQUENCE']._serialized_end=7282 + _globals['_QUANTITY']._serialized_start=7284 + _globals['_QUANTITY']._serialized_end=7408 + _globals['_MEASUREMENTREF']._serialized_start=7410 + _globals['_MEASUREMENTREF']._serialized_end=7493 + _globals['_UNITTERM']._serialized_start=7495 + _globals['_UNITTERM']._serialized_end=7579 + _globals['_UNITFACTOR']._serialized_start=7581 + _globals['_UNITFACTOR']._serialized_end=7628 + _globals['_DIAGNOSTIC']._serialized_start=7630 + _globals['_DIAGNOSTIC']._serialized_end=7704 + _globals['_SPAN']._serialized_start=7706 + _globals['_SPAN']._serialized_end=7800 + _globals['_SERVERINFOREQUEST']._serialized_start=7802 + _globals['_SERVERINFOREQUEST']._serialized_end=7821 + _globals['_SERVERINFORESPONSE']._serialized_start=7823 + _globals['_SERVERINFORESPONSE']._serialized_end=7882 + _globals['_QUERYREQUEST']._serialized_start=7884 + _globals['_QUERYREQUEST']._serialized_end=7967 + _globals['_QUERYRESPONSE']._serialized_start=7969 + _globals['_QUERYRESPONSE']._serialized_end=8029 + _globals['_QUERY']._serialized_start=8031 + _globals['_QUERY']._serialized_end=8103 + _globals['_CONSTRAINT']._serialized_start=8105 + _globals['_CONSTRAINT']._serialized_end=8229 + _globals['_PRIMITIVECONSTRAINT']._serialized_start=8231 + _globals['_PRIMITIVECONSTRAINT']._serialized_end=8346 + _globals['_COMPOSITECONSTRAINT']._serialized_start=8348 + _globals['_COMPOSITECONSTRAINT']._serialized_end=8452 + _globals['_QUERYRESULTELEMENT']._serialized_start=8455 + _globals['_QUERYRESULTELEMENT']._serialized_end=8615 + _globals['_QUERYRESULTELEMENT_PROPERTIESENTRY']._serialized_start=8566 + _globals['_QUERYRESULTELEMENT_PROPERTIESENTRY']._serialized_end=8615 + _globals['_SWEEPRANGE']._serialized_start=8617 + _globals['_SWEEPRANGE']._serialized_end=8732 + _globals['_RUNSWEEPREQUEST']._serialized_start=8735 + _globals['_RUNSWEEPREQUEST']._serialized_end=9055 _globals['_RUNSWEEPREQUEST_NAMEDARGUMENTSENTRY']._serialized_start=1782 _globals['_RUNSWEEPREQUEST_NAMEDARGUMENTSENTRY']._serialized_end=1849 - _globals['_SWEEPROW']._serialized_start=9038 - _globals['_SWEEPROW']._serialized_end=9238 - _globals['_RUNSWEEPRESPONSE']._serialized_start=9241 - _globals['_RUNSWEEPRESPONSE']._serialized_end=9478 - _globals['_RUNDOCUMENTQUERYREQUEST']._serialized_start=9480 - _globals['_RUNDOCUMENTQUERYREQUEST']._serialized_end=9590 - _globals['_DOCUMENTQUERYBINDING']._serialized_start=9592 - _globals['_DOCUMENTQUERYBINDING']._serialized_end=9671 - _globals['_DOCUMENTVALUE']._serialized_start=9674 - _globals['_DOCUMENTVALUE']._serialized_end=9887 - _globals['_DOCUMENTQUERYCOLUMN']._serialized_start=9889 - _globals['_DOCUMENTQUERYCOLUMN']._serialized_end=9924 - _globals['_DOCUMENTQUERYCELL']._serialized_start=9926 - _globals['_DOCUMENTQUERYCELL']._serialized_end=9983 - _globals['_DOCUMENTQUERYROW']._serialized_start=9985 - _globals['_DOCUMENTQUERYROW']._serialized_end=10083 - _globals['_RUNDOCUMENTQUERYRESPONSE']._serialized_start=10085 - _globals['_RUNDOCUMENTQUERYRESPONSE']._serialized_end=10195 - _globals['_RENDERDOCUMENTREQUEST']._serialized_start=10197 - _globals['_RENDERDOCUMENTREQUEST']._serialized_end=10261 - _globals['_RENDERDOCUMENTRESPONSE']._serialized_start=10263 - _globals['_RENDERDOCUMENTRESPONSE']._serialized_end=10305 - _globals['_SYSMLSERVICE']._serialized_start=11263 - _globals['_SYSMLSERVICE']._serialized_end=12707 + _globals['_SWEEPROW']._serialized_start=9058 + _globals['_SWEEPROW']._serialized_end=9258 + _globals['_RUNSWEEPRESPONSE']._serialized_start=9261 + _globals['_RUNSWEEPRESPONSE']._serialized_end=9498 + _globals['_RUNDOCUMENTQUERYREQUEST']._serialized_start=9500 + _globals['_RUNDOCUMENTQUERYREQUEST']._serialized_end=9610 + _globals['_DOCUMENTQUERYBINDING']._serialized_start=9612 + _globals['_DOCUMENTQUERYBINDING']._serialized_end=9691 + _globals['_DOCUMENTVALUE']._serialized_start=9694 + _globals['_DOCUMENTVALUE']._serialized_end=9907 + _globals['_DOCUMENTQUERYCOLUMN']._serialized_start=9909 + _globals['_DOCUMENTQUERYCOLUMN']._serialized_end=9944 + _globals['_DOCUMENTQUERYCELL']._serialized_start=9946 + _globals['_DOCUMENTQUERYCELL']._serialized_end=10003 + _globals['_DOCUMENTQUERYROW']._serialized_start=10005 + _globals['_DOCUMENTQUERYROW']._serialized_end=10103 + _globals['_RUNDOCUMENTQUERYRESPONSE']._serialized_start=10105 + _globals['_RUNDOCUMENTQUERYRESPONSE']._serialized_end=10215 + _globals['_RENDERDOCUMENTREQUEST']._serialized_start=10217 + _globals['_RENDERDOCUMENTREQUEST']._serialized_end=10281 + _globals['_RENDERDOCUMENTRESPONSE']._serialized_start=10283 + _globals['_RENDERDOCUMENTRESPONSE']._serialized_end=10325 + _globals['_SYSMLSERVICE']._serialized_start=11283 + _globals['_SYSMLSERVICE']._serialized_end=12727 # @@protoc_insertion_point(module_scope) diff --git a/clients/python/opensysml/proto/sysml_pb2.pyi b/clients/python/opensysml/proto/sysml_pb2.pyi index 9fb7855a5..c9b193c9c 100644 --- a/clients/python/opensysml/proto/sysml_pb2.pyi +++ b/clients/python/opensysml/proto/sysml_pb2.pyi @@ -686,7 +686,7 @@ class AttributeInfo(_message.Message): def __init__(self, name: _Optional[str] = ..., type: _Optional[str] = ..., value: _Optional[_Union[Value, _Mapping]] = ..., unit: _Optional[str] = ...) -> None: ... class Value(_message.Message): - __slots__ = ("int_value", "real_value", "bool_value", "string_value", "instance_id", "sequence", "null", "quantity", "enum_literal", "unset", "complex", "array", "vector", "vector_quantity", "measurement_ref") + __slots__ = ("int_value", "real_value", "bool_value", "string_value", "instance_id", "sequence", "null", "quantity", "enum_literal", "unset", "complex", "array", "vector", "vector_quantity", "measurement_ref", "infinity") INT_VALUE_FIELD_NUMBER: _ClassVar[int] REAL_VALUE_FIELD_NUMBER: _ClassVar[int] BOOL_VALUE_FIELD_NUMBER: _ClassVar[int] @@ -702,6 +702,7 @@ class Value(_message.Message): VECTOR_FIELD_NUMBER: _ClassVar[int] VECTOR_QUANTITY_FIELD_NUMBER: _ClassVar[int] MEASUREMENT_REF_FIELD_NUMBER: _ClassVar[int] + INFINITY_FIELD_NUMBER: _ClassVar[int] int_value: int real_value: float bool_value: bool @@ -717,7 +718,8 @@ class Value(_message.Message): vector: Vector vector_quantity: VectorQuantity measurement_ref: MeasurementRef - def __init__(self, int_value: _Optional[int] = ..., real_value: _Optional[float] = ..., bool_value: _Optional[bool] = ..., string_value: _Optional[str] = ..., instance_id: _Optional[int] = ..., sequence: _Optional[_Union[ValueSequence, _Mapping]] = ..., null: _Optional[str] = ..., quantity: _Optional[_Union[Quantity, _Mapping]] = ..., enum_literal: _Optional[_Union[EnumLiteral, _Mapping]] = ..., unset: _Optional[bool] = ..., complex: _Optional[_Union[Complex, _Mapping]] = ..., array: _Optional[_Union[Array, _Mapping]] = ..., vector: _Optional[_Union[Vector, _Mapping]] = ..., vector_quantity: _Optional[_Union[VectorQuantity, _Mapping]] = ..., measurement_ref: _Optional[_Union[MeasurementRef, _Mapping]] = ...) -> None: ... + infinity: bool + def __init__(self, int_value: _Optional[int] = ..., real_value: _Optional[float] = ..., bool_value: _Optional[bool] = ..., string_value: _Optional[str] = ..., instance_id: _Optional[int] = ..., sequence: _Optional[_Union[ValueSequence, _Mapping]] = ..., null: _Optional[str] = ..., quantity: _Optional[_Union[Quantity, _Mapping]] = ..., enum_literal: _Optional[_Union[EnumLiteral, _Mapping]] = ..., unset: _Optional[bool] = ..., complex: _Optional[_Union[Complex, _Mapping]] = ..., array: _Optional[_Union[Array, _Mapping]] = ..., vector: _Optional[_Union[Vector, _Mapping]] = ..., vector_quantity: _Optional[_Union[VectorQuantity, _Mapping]] = ..., measurement_ref: _Optional[_Union[MeasurementRef, _Mapping]] = ..., infinity: _Optional[bool] = ...) -> None: ... class Array(_message.Message): __slots__ = ("dimensions", "elements") diff --git a/clients/python/opensysml/values.py b/clients/python/opensysml/values.py index 35cbb7fb4..02c9834f0 100644 --- a/clients/python/opensysml/values.py +++ b/clients/python/opensysml/values.py @@ -668,6 +668,30 @@ def __repr__(self) -> str: UNSET = UnsetType() +class _Infinity: + """The unbounded value ``*``: no number, ordered above every finite one. + + A singleton, so ``is INFINITY`` tests it; also the unbounded multiplicity a + document query may answer with. + """ + + _instance = None + + def __new__(cls): + if cls._instance is None: + cls._instance = super().__new__(cls) + return cls._instance + + def __repr__(self) -> str: + return "INFINITY" + + __str__ = __repr__ + + +#: The unbounded value ``*``. See :class:`_Infinity`. +INFINITY = _Infinity() + + def value_to_python(pb_value, resolve_instance=None): """Convert a protobuf Value into a plain Python value. @@ -677,7 +701,8 @@ def value_to_python(pb_value, resolve_instance=None): when omitted, instance references are returned as their integer id. Returns: - int, float, complex, bool, str, list, None, :data:`UNSET`, a + int, float, complex, bool, str, list, None, :data:`UNSET`, + :data:`INFINITY`, a :class:`Quantity`, a :class:`MeasurementRef`, an :class:`Array`, a :class:`Vector`, a :class:`VectorQuantity`, an :class:`~opensysml.enumeration.EnumLiteral`, @@ -720,6 +745,8 @@ def value_to_python(pb_value, resolve_instance=None): return EnumLiteral(lit.literal_id, lit.enumeration_id, lit.name) if kind == 'unset': return UNSET + if kind == 'infinity': + return INFINITY if kind == 'null': # A non-empty null carries the reason the value could not be sent. if pb_value.null: diff --git a/clients/rust/conformance/sysml.descriptor.binpb b/clients/rust/conformance/sysml.descriptor.binpb index c25df9379148312c93ec98ebaecd4ff9e755620f..4ff62872071e6ce08fddcc3a4c4dfa9ee2335506 100644 GIT binary patch delta 7500 zcmYLNd304pp1$|y-KxqBkjKqJ2-_uqxIlukZ;_oqKsNV2XAS|LkeMc7k|2i}Pd`wk zm1c(JHe8ej0;q$A_7EZjl~s0zO`sJKL>6^0ZQvN71#Fq`S9Oc`-}|cS`|7vVuj<{4 zMqgKHjG;}8}oZDF!%c39U5tVR@3G1Ks&z2bRv;FE7gtcu_Mj0H=Ewm(_-Gtl1ZgA zOQyu8crO?IerC*@_~^t=-mGcGlc#yblD_de9b)os|@bE|%d&j`&?ptm=2fwv;f&AbiA5 ziAp6v2p_SVw$Kp5N9@*ZoadwfCXf2bCtv7)G$CLz3?>9jT4OhD9txNcIBK_S<;;X( zkGt%1+xVNm=43_mb6YfV){?_;2;73laN&U(ena(SaeS&1q`e^OhIO-O>!0lG7S2G)u-wRX zfAJTCpKar&Z8|AVQlvXp{%ng38G`O)aD#2BfCEJ& zRK*C0>@?`41A^M1YpJ`HL7p^FF;!7|dbsQt+j!ld`sD}iFSdv}&%)Xs!f@GL+xn;9 z?(8%1yS7lF??L2h02#rX!~FYa{oFY$Of?2Un!~~>0R(9dLzR3%=b;C|dH(LN&gRWy z;W@<^DDzlKdT4PHtzpfwoSPOx(bHuMnemsJgXhZ4=t71Qu$Yv3lGls;k>{7@F4CK0 z3`&di=73OIM4NxAD46wq=faL$UvJ)1I_c}p0YUL;^ZF#Y3w&HzbL+wlGjC;L8}e}_ zOID4gr}S|pOG|hDNV)6fvPx#W=cj)=Kedt}cjF<{i_Bf;zyIyi@pW1UW6)X0!ear5 zz1J}u3(8F|+GIToPZSVx1E@|Epqza`C9~HPwLnr~^}Ec<$?oF~Dk`UIp}3;lD}BkU zm=^P2xzx2kCRLJqSr+Q@U6zs|gAWMZcUfjD4Wauk^V≪8|~%z0Zul`hUMPF!g;V zT&ED5^(N1%{C<~5$E&n?7=uieju0SZswhI_S#R27BeOE)9zgI6P3-X*sSRuPipBELQG|D_v4IkzJ2smp)`ywLknyr+Bp% z#~8$`Stt$&@oEw$yZVq_o0+9T0R+1Mm0f^xHcUDosGGG*edsLIFiTYg5P}NGq=y}V z!L4CDMPfj3Ygm(1=W+Pd*JZWL*x@(3+9h7gL?dZSU$TB13tKS|YyniZ077q@u5&=> zZKFCTH~P|MAM3&a0u_+Uy#eJcf<%`uAgCYfnv3@(KR(f^0Rk6Lb4mFVhQ6b?uZ32*omuHU!`TS9z?vHYcRRx+rMMArw=*}* zd7X}1KRgfoSHAmWbPp5F(bcU;f0ylJ#yvmn`vK8?Ok_K!==Areh#vAMe}5+TkPalq zAbm*JDIlZ|ky$sgBn7i~Yhpi?HOjxMPfULq(7P-}MFEf&F<13aKuFwWxM!b%Dfuq@ zjTx_TKjY?v=xWNr40tSYza5s=4SQ=OBv`dxtms#_Kz$xx`e~A|D#k6pbeM# zeSi6}-!i=q#t_D3JWLB9_F2YVb?*UUpJg2P-V0IylYw7!=Xd>rga93sAR$1(47i&m z4ILnZ8SoY@o#&+hg87#J%bgeV-r`oHa0w;nE#6oitpW0szs1p$<;!)T%T{w^y+8Nv z`uJ*&^VbAA1L;a%!>x5ZNooK?V+~DHx(AY@l{}(?1%yxnDxUzcwvuPHRaEI>C2!v$ zq+)Vyf=ZPFD5;M@n7mt?;8LlqCGPXc!XTHu$Bk-aVWj7;eKgI#bnnU3_qb?*eiexf zBBM6=dB1ke-N3^ZhcW1F;Jk^n1rT~0cvIK;A4=FDicFQi_}BO2Rl3wLMuR-;#ekqx z@vs*UqDHilTgo>em=CDleSn~D6`;Xcats}Kq-Wx8RuAd7PF7I@v;Bc-^QkX#O+L{gA=hW z3dWXTqG`5mkKdqg;g&~1pegvUg|}<(q{)?--0F|JpAp~6t?Y1#i6vWktJdKXpjtSc zV|zLIInqYRkh2(-&JvW1;H*-GiQBl!kRYzH@X z`+vVbC%%KyO0_naJlUxu4upsUs)z$Zai@+rAhz8}5m!`9?&4Mlnf$?)i3R|uVhjkS zT|9hY0LsOgGDwk3U`XwvC{d7;T(*}R2LsbI$ENPpQBES;_ED5O#`o#?Vi0caBW4ET zn?zyS&#hKD+{?lL+b|XwR^##<(<+em(>YF;B%lL`Z4UEtO3NN_NDIUAw17h)KS0gn zrs*JnLtJ)@8=nVJ%WOzJ#&N?8L;#17k;el!$sFAIxUO;xLh3kAR#!hDygklw_0vOb z2<>wscs0o!89$Mrki{o>_=Lt9P)<-Ar&tdmTTbd&10lG8>dgWO>Pa337ZB8w6rne$ zyAE~Pm)!Uk=lYK6O_&vn%@|))GBrk@21HR^m!p%~_}@40ce zb`UpvnIpgFLfx;!$m<_)NlFqBt^`1JIRZlR2YopLLh=W?9EZW2VPxyIV4pAxp178v zP%f|OfME?N*C=2wN(!8><5rvOQU2p)U4oKiv*Q!MdOK3Aojx~^I;F+pT145#Kng%XJ zlEC8I!S)pMz1-V6Zx{sUHV+?rfZ*KbcByQpg1^p^nn>>ad7TX zg`J^xH{50Sx$$4Y(~Zs3(fb@v(5JEcaLV*t5%g?gKGScm2;+uP7&TXf%?c38b4BO@ zAe83{cu*oGFgY(c)Wn?8Z(c%y+TFZ_0u{hK5&oeXE(>6uz#pm!QUL`pKd4BB4f7KU z6qxxUMZF`2%R?|b=|JHH{q;vX*4{f5AQWvYEZS|plh z<3AL6PVcke-=gM-&I?3XY#4-{3q-QIzyU#7AaH?qmlR}sVQ?vG_RL!-EcFl{F4MbE zMAgd|5R`=iFW>*Auot*&sW9FNhBq~jys%V=EO}@PDD1wl)N2q3wg9TC1%&6m2tQ!~ z!X{s&tJ4UG4Sa#tJsUO^(CJtn{HtsJXTRkM1$x9S7vU=qYiN@Wz*+ahe(fV4=U z{?<{=7Erub1#QyJcjBuO9E$fU9dE1wXBBNjt*wAg*J@#@cOMWG0Ckk;l&#hkhFK`B z7Mbd)1PG&(k95PB8dP}%gg~XvBOnASDUYuy^Ks=)ghaLQ9@Y>N)#9;EIJQ<~ zq|3GlV_Oh!ZjO&{5u&9`+DP(Zs|Y{X0KpGH)yx4QxK)HVCm;m33S0z~?~$}yt*}(D z1wy_7RlWgXTCGS?#{f_+ZmukC1`MfMk<-rkGX=ZQWjlp&q;_hynP%qh6!?=y|1=8e zpT;g>9Te)H1~6oH3EYqLs4pbrcLy6BYhiViUHF|aEmyZx|Cj(FbyeU|f1d8yu`c^j7}sI)G1K!0 z=4S+zIp*%vABAWoo9kGzx{jLbBe``t^B9C?oo=gu(5$0cUqdZ&EZJ8d9B5~*?OLDU zkRA0RSv?T32Aq0+w8`&lzD)VZFaN!7zo*Bw{M|WO|rv% z{;_L)68!GObIFfgnc;PT>~NAj>)O7e03m*W(m)8Fbc}|f$}DdVj2S`3v<4fR<_>N(LKuTk ztDCNU1cXqlo7>%+p%|F_GU$JD=HM?=4BGljH(eVx!ltdibn|<96BWbuo%2D>$;rv{ zDTWQkdE@5@+Xmyj_S1Go`uw76U2>Th^U|D=Sb5QvIVuDr$>4U^)&U1{6x78Ci0rhR zqyvK5Zfa?yokO0qQ!)J?rDv4SzjCd|gI_go^1pIr+`9|bj*^zoJ6!vlVA!cUlO3+q zp&v#2UUi*bD)c}IJz%esHLO$GuLP@4>>W@EbE0YUwm zOk9Q1mLMZ|*W94n>7eMEi5><)x@MvW2+}o*UK5>%Q3RI;M^85oS<0hxiZM`@@>q6c zaT=}R-SfP!Y=mO8&zE!Suk}r59%1q294Fu}q%@kmUJ=aucvaB~9@QDfptOQVB?<_o z6&#!I))dTE20hO1Evht|k5*1rn#}=0sie&>rm0=vV_5IBTw+7Q)HdW}$kTOW8LfN_ zc~-XfH05rL&#SrhV$ko?ii~QG+}#18F=Xz#VCSblNv<HbF+BpzM(;F3oYi~c9E3ika z>=yE@HYor6_6KW?c^HFCt%(pIWNIlwB>$3|}Fsy%?<8KCwIP|c=inpsdc^6VUM zDl8c5^Ud6PHDLcN&Dcy9+z7p~WIK0vOl9RLjOD_q1B1_bvN-Yvts8P<>Uc|Et@ z2nL=Tnylxti?U@LS-+h}O&18Z0BTzRp|{;sG$8c0Q$>>-<7l(jOo;%23MkaxfNB;& zqT3J<)YnXPCC8B;ubU(QfeUE3r2INZhtXVe<8>3gafEi5=mCKWXsC3WcTnAHDxKyX zCVJy+G{v3V&K@1jI^Y5ut^@8)j_XKs9dLJYKg)ZH4py=6>|Mb>L$<*D}(9Zv=y&3!Wcu`R*EPMfDm3Oe0`$PxAST!m10Juic&T zqL4k&mKx4iMChB3r*<072a-3KHI7y&K@>VC#49kKb&P zI!U#i%_gaUP}pp$0+1+F6>~frFIxVpuwD!Hd_OzmRpI7(13bsI$?dJ-BAfN?kKdqg z6?TH$r72juRrKrcWvP{z+*WlT%Smn%c7C*kVaYbpyHB(Ps2=VWx{1P)LUkk{LvCSI zxkXSdf?HY@CTevE8ahHiLAhz8_vDH*e?iTg{mFCGd!;uEmM;Z`HyG8Uk091=}Rgj!q zU`XwzC{d8pe7;XuZ-sH2&Cb|oqMSyyHBgiXB^yk9F$lLBh?#@Nl`#{DCrYZa{&i+)?WK6>#^qWNVVg!VK z6ZNpwnuFO>VXk0nlBYy;&rDGXI7Qu=?ioOEP8oNmkUOVE^b!JsJAnF%0)*gcA$9No zK|M{uqpF)i=!~%S#R>!}pr#H42KS7>14(a7XZeiChm6cxd=Lj}00OY`CP~D$-Twz;5JyD|L=v zD=tu5_<_eBD{eCU8rR0=q>7s84dySwOuu=U@lQk&jV z7er2f6+}Q#E{H)lP$MCi5uWxi)`dMWzCE?8i$t`W^Nux;XcxJ^QNkvw^T+w50Dng=noMf6qZW-A)2cckoRTb6LHwEETuq!Steup zwJ=qkgk>^Ie|G|e!ZL~PJEN5X(34?yCc9ovyXg)~`DtC;*x$(J5PNDh#twS}Sw)%Louk zYb73Rl({mhrD|#S%O8}u`+;ER13wypAw8zk2nc?)Nh2Wm)s)63wDmY~HQ|Ra)D_XY$z{$*ofMQmL9w zUTl-mXBHs%0jN7SAOyF`=+Xp);5Lb_Pg$N$yVXlucUT}~8Bk{#5T@13m@a-mwYZ12 zv^y}Q>SbX+Z#BiZ+~>Qb_3n;e^<-IW_%4ZmT=XxZoc=}ZmiAjx|BC>I%x;ORkzVfQ zWc(iKp%wq8#Q)qzLa*xdGp{y?_>-Wm&vmp>12Q*YNcdv}; zKO~q1b+3#*8 zWpgAYhYKT68gsXHLM>em|}CFEkFo1 zQs254g17tpeQ6yF4;8Ta^WT^FVnX4+odl1Xngv2g0d@ER;p$OSvw+Y)Dx;bOg#J+~ z*~QSG>GKoPY7UbL_Hf1tx*zBp^-R)l3cpXVdy-A&rokYDnq*v86Ci||Of}7BvU=pA<2@ocolren+0IJ2k3(aCEosn0$mKf}fS-gs=2t4e>9e?5(=& zY_hslcUk;K{##A{0ioP#x-1}+TdCq}sAJA1E8D`4`m^=J+fp2|rcI{nS0dJc(S`4B^iCV1%fqzx*7qYe90UlKqz0r WA^JIgXz`*Yi-v#Lk>*G%&-#Bt@%Xd= diff --git a/clients/rust/opensysml/src/domain.rs b/clients/rust/opensysml/src/domain.rs index f79c0a389..daae82160 100644 --- a/clients/rust/opensysml/src/domain.rs +++ b/clients/rust/opensysml/src/domain.rs @@ -414,6 +414,8 @@ pub enum Value { Null, /// A materialized feature with no value. Unset, + /// The unbounded value `*`, ordered above every finite magnitude. + Infinity, } pub(crate) fn value_from_wire(value: wire::Value) -> Result { @@ -474,6 +476,7 @@ pub(crate) fn value_from_wire(value: wire::Value) -> Result { name: v.name, })), wire::value::Kind::Unset(_) => Ok(Value::Unset), + wire::value::Kind::Infinity(_) => Ok(Value::Infinity), } } @@ -490,6 +493,7 @@ fn kind_name(kind: &wire::value::Kind) -> &'static str { wire::value::Kind::Quantity(_) => "quantity", wire::value::Kind::EnumLiteral(_) => "enum_literal", wire::value::Kind::Unset(_) => "unset", + wire::value::Kind::Infinity(_) => "infinity", wire::value::Kind::Complex(_) => "complex", wire::value::Kind::Array(_) => "array", wire::value::Kind::Vector(_) => "vector", diff --git a/clients/rust/opensysml/src/proto/sysml/sysml.rs b/clients/rust/opensysml/src/proto/sysml/sysml.rs index bfb869cb4..a809e0542 100644 --- a/clients/rust/opensysml/src/proto/sysml/sysml.rs +++ b/clients/rust/opensysml/src/proto/sysml/sysml.rs @@ -825,7 +825,7 @@ pub struct AttributeInfo { /// Value represents a runtime-evaluable value #[derive(Clone, PartialEq, ::prost::Message)] pub struct Value { - #[prost(oneof="value::Kind", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15")] + #[prost(oneof="value::Kind", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16")] pub kind: ::core::option::Option, } /// Nested message and enum types in `Value`. @@ -872,6 +872,11 @@ pub mod value { /// a unit by itself, no magnitude #[prost(message, tag="15")] MeasurementRef(super::MeasurementRef), + /// The unbounded value `*`, which is no number and no string: ordered above + /// every finite magnitude and refused by arithmetic. Always true when set, + /// as DocumentValue.infinity is. + #[prost(bool, tag="16")] + Infinity(bool), } } /// Array is a Collections::Array: its elements flattened in row-major order diff --git a/docs/project/spec-compliance.md b/docs/project/spec-compliance.md index 7eebecded..b9a465214 100644 --- a/docs/project/spec-compliance.md +++ b/docs/project/spec-compliance.md @@ -659,6 +659,8 @@ by name is refused naming what is missing rather than approximated. | Unary operators (-, +, not) | `eval.go` evalUnary | `calc_unary_operators.sysml` | ✅ Faithful | | Conditional (`if c ? a else b`) and null coalescing (`??`), both lazy | `eval.go` evalConditional/evalNullCoalesce | `calc_conditional_branch.sysml`, `calc_null_coalesce.sysml` | ✅ Faithful | | Literal values (Integer, Real, Boolean, String) | `eval.go:109` evalLiteral* | `calc_simple_add.sysml` | ✅ Faithful | +| `*` in an expression position is the unbounded value (KerML §8.4.4.6 `LiteralInfinity`, typed `ScalarValues::Positive`): it exceeds every finite Integer, Real and Natural, equals itself, orders consistently under `<`, `<=`, `>`, `>=`, and prints as `*` in a value, a trace, a solver pin and a document-query cell. It is no number, so every arithmetic operation over it — `+`, `-`, `*`, `/`, `%`, `**`, unary `+` and unary `-` — is `ErrTypeMismatch` naming the operation, never an infinity, a NaN or a finite answer | `runtime/eval.go` `evalLiteralInfinity`, `constArithmetic`, `constCompare`; `semantics/eval.go` `Value.IsUnbounded`, `UnboundedOrder`, `OrderSatisfies`, `FormatConst`; `semantics/valuetype.go` `exprConformance`; `solve/pin.go`; `repl/docquery.go` | `runtime/infinity_test.go:TestInfinityValue`, `:TestInfinityComparison`, `:TestInfinityArithmeticRefused`; conformance `value_unbounded_comparison`, `value_unbounded_arithmetic_refused`; `parse/unbounded_and_metadata_access.golden`; `robustness_test.go:arithmetic_over_the_unbounded_value`, `:unbounded_value_compared_with_a_string` | ✅ Faithful | +| `ref.metadata` is a MetadataAccessExpression (KerML §8.4.4.10): it yields the metadata annotating the element `ref` names as a sequence of metadata instances in declaration order — inline `@`-annotations first, `metadata … about` ones after — each instance carrying the feature values the annotation body binds and, where the body binds none, the metadata type's own declared defaults. An element no metadata annotates yields the empty sequence; metadata read off a value (`1.metadata`) is `ErrTypeMismatch`, and a name that resolves to nothing is `ErrUnresolvedReference` | `parser/expr.go` `parsePostfixes` (`metadataAccessRef`); `semantics/annotations.go` `Model.ElementMetadataOf`, `metadataBindings` (the annotation side table an element filter classifies by); `runtime/metadata.go` `evalMetadataAccess`, `metadataSubject`, `metadataInstance` | `runtime/metadata_test.go:TestMetadataAccessBoundValues`, `:TestMetadataAccessAboutForm`, `:TestMetadataAccessEmpty`, `:TestMetadataAccessNotAnElement`, `:TestMetadataAccessUnresolved`, `:TestMetadataAccessUnknownFeature`; conformance `metadata_access_annotations`; `parse/unbounded_and_metadata_access.golden`; `robustness_test.go:metadata_of_a_value`, `:metadata_of_an_unresolved_name` | ✅ Faithful | | Feature reference resolution | `eval.go:141` evalFeatureReference | `constraint_literal.sysml` | ✅ Faithful | | Qualified name resolution (A::B::C) | `eval.go:53` Eval + `resolve/qualified.go` | `calc_qualified_names.sysml` | ✅ Faithful | | A qualified name evaluates as the checker resolves it, imports included (KerML §8.2.3.5 import, §8.2.3.3 visibility): a segment that names a member a `public import` re-exports — of every member (`Bq::x` with `public import A::*`), of one (`public import A::x`), recursively (`import A::**`), through a façade of a façade, by short name or through an `alias` — reaches the same element the checker reaches, which is how the library's `ISQ` and `SI` re-export the ISQ part packages (`ISQ::speed`, `SI::speed`); a `private import` stays reachable only from inside the importing namespace, and a name the checker rejects fails at evaluation with the checker's own message and classification (`unresolved reference: Priv::x`; `ambiguous reference: Twice::t (2 candidates)` when several members answer to a segment) | `runtime/eval.go` `evalNameGeneral` resolves the whole name through `resolve.Resolver.ReadQualified` (the checker's `walkQualified`, so the two tiers cannot disagree), whose `Reading` carries the element, the resolved segments — routing a calc usage's outputs to `evalCalcUsageMembers` and keeping the variant/literal reports in `unresolvedQualifiedName` — and the candidate count of a name rejected as ambiguous; a reading is memoized by scope and node, so one expression evaluated in several scopes answers in each with what that scope sees | `calc_qualified_name_through_import.sysml`, `calc_qualified_name_private_import.sysml`, `calc_qualified_name_ambiguous.sysml`, `qualified_import_test.go:TestQualifiedNameThroughImportEvaluates`, `:TestQualifiedNameThroughImportRejectedAsChecked`, `:TestQualifiedNameThroughImportKeepsTypedErrors`, `:TestLibraryQuantityThroughFacadeResolves`, `:TestQualifiedNameEvaluatedInSeveralScopes`, `resolve/reading_test.go:TestReadQualifiedAnswersPerScope`, `:TestReadQualifiedReportsFailure` | ✅ Faithful (a library quantity reached through a façade resolves to its declaration, which like `SI::m` carries no scalar value, so the evaluator reports that declaration rather than a missing member) | diff --git a/docs/reference/service-transports.md b/docs/reference/service-transports.md index 5200052a1..0a2b070c4 100644 --- a/docs/reference/service-transports.md +++ b/docs/reference/service-transports.md @@ -52,10 +52,11 @@ capability's definition rather than something a client has to guess: | The capability describes | A request that needs it | What a client should do | |---|---|---| | what the service can be *asked*: `strict_conformance`, `inline_language`, `parse_sources`, `evaluate_subject`, `verification`, `convert`, `apply_edits`, `authoring`, `query`, `oslc_query`, `document_query`, `render_document` | is **refused** with `UNIMPLEMENTED`, naming the capability | check the advertised list first, and report the missing capability locally rather than spending a round trip | -| how a response is *populated*: `type_facts`, `symbol_attributes`, `feature_values`, `enum_values`, `unset_value`, `complex_values`, `structured_values`, `measurement_refs`, `verification_verdicts` | is answered with those fields **omitted** | check before reading the fields; an omitted field is not an error | +| how a response is *populated*: `type_facts`, `symbol_attributes`, `feature_values`, `enum_values`, `unset_value`, `complex_values`, `structured_values`, `measurement_refs`, `verification_verdicts`, `infinity_value` | is answered with those fields **omitted** | check before reading the fields; an omitted field is not an error | -`complex_values`, `structured_values` and `measurement_refs` sit in both rows: a complex — or -an array, vector or vector quantity, or a bare measurement reference — in a response is +`complex_values`, `structured_values`, `measurement_refs` and `infinity_value` sit in both +rows: a complex — or an array, vector or vector quantity, a bare measurement reference, or the +unbounded value `*` — in a response is reported as an `unsupported` null without it, and one in an action input or calc argument is refused with `UNIMPLEMENTED` rather than read as another value — a service that predates the arm would read it as an unknown field, so every client checks the list before sending one diff --git a/docs/reference/wire-contract.md b/docs/reference/wire-contract.md index 96d298204..821c32590 100644 --- a/docs/reference/wire-contract.md +++ b/docs/reference/wire-contract.md @@ -217,6 +217,7 @@ arms, each captured from `Evaluate` against the model at the end of this section | `vector` | object | `{"result":{"vector":{"components":[{"realValue":3},{"realValue":4}]}}}` | Numeric vector; each component an `intValue` or `realValue` | | `vectorQuantity` | object | `{"result":{"vectorQuantity":{"components":[{"realMagnitude":3,"unit":"m","unitTerm":{…}},…]}}}` | Vector of quantities; one `quantity` body per component | | `measurementRef` | object | `{"result":{"measurementRef":{"unit":"m","unitTerm":{…},"unitId":"SI::metre"}}}` | A measurement reference on its own: a unit, its reduction, and the declaration it names | +| `infinity` | boolean | `{"result":{"infinity":true}}` | The unbounded value `*`, which is no number and no string | The `array`, `vector` and `vectorQuantity` rows were captured against `conformance/fixtures/structured.sysml` (`S::grid`, `S::v`, `S::d`), `measurementRef` against @@ -281,6 +282,8 @@ decode(v): measurementRef → unit := v.measurementRef.unit, id := v.measurementRef.unitId; require v.measurementRef.unitTerm when either is present, else an error; require unit or id, else an error; id absent means a composed unit + infinity → the language's unbounded sentinel, distinct from a number and from the + string "*"; it compares above every finite number and equals itself anything else → an error: a newer service than this decoder ``` diff --git a/internal/core/parser/expr.go b/internal/core/parser/expr.go index 33e7d8ddd..2df55874e 100644 --- a/internal/core/parser/expr.go +++ b/internal/core/parser/expr.go @@ -200,6 +200,19 @@ func (p *Parser) parsePrimary() ast.Node { return p.parsePostfixes(start, expr) } +// metadataAccessRef is the element reference `ref.metadata` reads the metadata +// of; nothing but a name is one (KerMLExpressions MetadataAccessExpression). +func metadataAccessRef(expr ast.Node) *ast.QualifiedName { + switch e := expr.(type) { + case *ast.FeatureReference: + return e.Name + case *ast.QualifiedName: + return e + default: + return nil + } +} + // atExprStart reports whether the current token can start an expression. func (p *Parser) atExprStart() bool { t := p.peek() @@ -242,6 +255,17 @@ func (p *Parser) parsePostfixes(start int, expr ast.Node) ast.Node { expr = c continue } + // `ref.metadata` is a MetadataAccessExpression over an element + // reference, not a chain through a feature named `metadata`. + if p.atKeyword("metadata") { + if ref := metadataAccessRef(expr); ref != nil { + p.advance() // metadata + m := &ast.MetadataAccessExpr{Ref: ref} + m.NodeSpan = p.spanFrom(start) + expr = m + continue + } + } // Use relaxed parsing to allow keywords as feature names (e.g., oSP.exit, state.entry) member := p.parseQualifiedNameRelaxed() fc := &ast.FeatureChainExpr{Operand: expr, Member: member} diff --git a/internal/core/parser/testdata/parse/unbounded_and_metadata_access.golden b/internal/core/parser/testdata/parse/unbounded_and_metadata_access.golden new file mode 100644 index 000000000..fd806ac3d --- /dev/null +++ b/internal/core/parser/testdata/parse/unbounded_and_metadata_access.golden @@ -0,0 +1,40 @@ +(RootNamespace + (Membership visibility="default" + (Package name="test" library=false standard=false + (Membership visibility="default" + (Definition kind="metadata" abstract=false variation=false name="Safety" + (Membership visibility="default" + (Usage kind="attribute" name="level" ref=false direction="none" composite=false derived=false ordered=false nonunique=false)))) + (Membership visibility="default" + (Definition kind="part" abstract=false variation=false name="Vehicle")) + (Membership visibility="default" + (Usage kind="part" name="seatBelt" ref=false direction="none" composite=false derived=false ordered=false nonunique=false + (Relationship kind="typing" target=Vehicle + (*ast.QualifiedName)) + (Membership visibility="default" + (PrefixMetadata type="Safety" + (Membership visibility="default" + (Usage kind="attribute" name="level" ref=false direction="none" composite=false derived=false ordered=false nonunique=false + (LiteralInteger value="4"))))))) + (Membership visibility="default" + (Definition kind="part" abstract=false variation=false name="Report" + (Membership visibility="default" + (Usage kind="attribute" name="unbounded" ref=false direction="none" composite=false derived=false ordered=false nonunique=false + (LiteralInfinity))) + (Membership visibility="default" + (Usage kind="attribute" name="exceedsFinite" ref=false direction="none" composite=false derived=false ordered=false nonunique=false + (OperatorExpr operator=">" + (LiteralInfinity) + (LiteralInteger value="1000")))) + (Membership visibility="default" + (Usage kind="attribute" name="annotations" ref=false direction="none" composite=false derived=false ordered=false nonunique=false + (MetadataAccessExpr ref="seatBelt"))) + (Membership visibility="default" + (Usage kind="attribute" name="qualified" ref=false direction="none" composite=false derived=false ordered=false nonunique=false + (MetadataAccessExpr ref="test::seatBelt"))) + (Membership visibility="default" + (Usage kind="attribute" name="level" ref=false direction="none" composite=false derived=false ordered=false nonunique=false + (FeatureChainExpr member="level" + (IndexExpr + (MetadataAccessExpr ref="seatBelt") + (LiteralInteger value="1")))))))))) \ No newline at end of file diff --git a/internal/core/parser/testdata/parse/unbounded_and_metadata_access.sysml b/internal/core/parser/testdata/parse/unbounded_and_metadata_access.sysml new file mode 100644 index 000000000..9a968b8c9 --- /dev/null +++ b/internal/core/parser/testdata/parse/unbounded_and_metadata_access.sysml @@ -0,0 +1,21 @@ +package test { + metadata def Safety { + attribute level; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + level = 4; + } + } + + part def Report { + attribute unbounded = *; + attribute exceedsFinite = * > 1000; + attribute annotations = seatBelt.metadata; + attribute qualified = test::seatBelt.metadata; + attribute level = seatBelt.metadata#(1).level; + } +} diff --git a/internal/core/runtime/conformance_test.go b/internal/core/runtime/conformance_test.go index 85b0b9890..3ba2aebc8 100644 --- a/internal/core/runtime/conformance_test.go +++ b/internal/core/runtime/conformance_test.go @@ -1554,6 +1554,8 @@ func expectedToRuntimeValue(t *testing.T, ev ExpectedValue) Value { t.Fatalf("invalid String value type: %T", ev.Value) case "Null": return Value{Kind: ValNull} + case "Infinity": + return Value{Kind: ValConst, Const: semantics.Value{Kind: semantics.ValInfinity}} case "Variant": t.Fatalf("a variant is named by the model, so it cannot be built from a case value") case "EnumLiteral": @@ -1687,6 +1689,10 @@ func validateValue(t reporter, ctx *Context, name string, expected ExpectedValue if actual.Kind != ValNull { t.Errorf("%s: type = %v, want Null", name, actual.Kind) } + case "Infinity": + if actual.Kind != ValConst || !actual.Const.IsUnbounded() { + t.Errorf("%s: type = %v (Const.Kind=%v), want the unbounded `*`", name, actual.Kind, actual.Const.Kind) + } case "Variant": if actual.Kind != ValVariant || actual.Variant() == nil { t.Errorf("%s: type = %v, want Variant", name, actual.Kind) diff --git a/internal/core/runtime/eval.go b/internal/core/runtime/eval.go index c2911178d..6eb8c2982 100644 --- a/internal/core/runtime/eval.go +++ b/internal/core/runtime/eval.go @@ -274,6 +274,10 @@ func (ec *EvalContext) eval(node ast.Node) (Value, error) { return ec.evalLiteralBool(n) case *ast.LiteralString: return ec.evalLiteralString(n) + case *ast.LiteralInfinity: + return ec.evalLiteralInfinity(n) + case *ast.MetadataAccessExpr: + return ec.evalMetadataAccess(n) case *ast.NullExpr: return ec.evalNull(n) case *ast.FeatureReference: @@ -397,6 +401,12 @@ func (ec *EvalContext) evalLiteralString(n *ast.LiteralString) (Value, error) { } // evalNull evaluates a null expression. +// evalLiteralInfinity evaluates `*`, the unbounded value: a scalar constant of +// its own, ordered above every finite number and refused by arithmetic. +func (ec *EvalContext) evalLiteralInfinity(_ *ast.LiteralInfinity) (Value, error) { + return Value{Kind: ValConst, Const: semantics.Value{Kind: semantics.ValInfinity}}, nil +} + func (ec *EvalContext) evalNull(n *ast.NullExpr) (Value, error) { return Value{Kind: ValNull}, nil } @@ -1112,12 +1122,18 @@ func (ec *EvalContext) chainMemberValue(value Value, parts []ast.NameSegment, fr } return ec.chainMemberValue(Value{Kind: ValInstance, Instance: inst.ID}, parts, from) default: + if err := metadataOfAValue(value, parts); err != nil { + return Value{}, err + } return Value{}, fmt.Errorf("cannot chain through non-instance member %s (%v)", from, value.Kind) } // A selected variant is chained through the object it materialized. id, isObject := value.Object() if !isObject { + if err := metadataOfAValue(value, parts); err != nil { + return Value{}, err + } return Value{}, fmt.Errorf("cannot chain through non-instance member %s (%v)", from, value.Kind) } inst, ok := ec.ctx.instances[id] @@ -1783,6 +1799,13 @@ func arithmeticValues(op ast.OperatorKind, left, right Value, span source.Span) // evaluator and the compiled calc tier share so both report the same results // and the same errors. func constArithmetic(op ast.OperatorKind, left, right semantics.Value) (semantics.Value, error) { + // The unbounded `*` is no number: arithmetic over it is refused rather than + // answered with a finite result or an infinity. + if left.IsUnbounded() || right.IsUnbounded() { + return semantics.Value{}, fmt.Errorf("%w: operator '%s' is not defined for the unbounded value '*': %s %s %s", + ErrTypeMismatch, op, semantics.FormatConst(left), op, semantics.FormatConst(right)) + } + // Exponentiation shares the folder's implementation, so a folded and an // evaluated `**` agree; the folder declines where this reports the error. if op == ast.OpPow { @@ -1957,6 +1980,20 @@ func comparisonValues(op ast.OperatorKind, left, right Value, span source.Span) // constComparison orders two scalar constants, the core the evaluator and the // compiled calc tier share. func constComparison(op ast.OperatorKind, left, right semantics.Value) (bool, error) { + // The unbounded `*` orders above every finite number and equals itself. + if left.IsUnbounded() || right.IsUnbounded() { + order, ok := semantics.UnboundedOrder(left, right) + if !ok { + return false, fmt.Errorf("%w: '%s' is not defined between %s and %s", + ErrTypeMismatch, op, semantics.FormatConst(left), semantics.FormatConst(right)) + } + res, ok := semantics.OrderSatisfies(op, order) + if !ok { + return false, fmt.Errorf("unknown comparison operator: %v", op) + } + return res, nil + } + // Compare integers if left.Kind == semantics.ValInt && right.Kind == semantics.ValInt { switch op { diff --git a/internal/core/runtime/infinity_test.go b/internal/core/runtime/infinity_test.go new file mode 100644 index 000000000..631571d09 --- /dev/null +++ b/internal/core/runtime/infinity_test.go @@ -0,0 +1,124 @@ +package runtime + +import ( + "errors" + "strings" + "testing" + + "github.com/Open-MBEE/OpenSysML/internal/core/ast" + "github.com/Open-MBEE/OpenSysML/internal/core/semantics" +) + +// evalDeclaredExpr evaluates expr as the value of an attribute declared beside src. +func evalDeclaredExpr(t *testing.T, src, expr string) (*Context, Value, error) { + t.Helper() + full := src + "\npackage probe {\n\tattribute result = " + expr + ";\n}" + model, resolver, root := parseAndBuildLibraryModel(t, full) + pkg, ok := root.LookupLocal("probe") + if !ok || pkg == nil || pkg.Scope == nil { + t.Fatal("package probe has no scope") + } + sym, ok := pkg.Scope.LookupLocal("result") + if !ok || sym == nil { + t.Fatal("attribute result not found") + } + decl, ok := sym.Decl.(*ast.Usage) + if !ok { + t.Fatalf("result declares %T, want a usage", sym.Decl) + } + ctx := NewContext(model, resolver, 10000) + got, err := NewEvalContext(ctx, pkg.Scope).Eval(decl.Value) + return ctx, got, err +} + +// TestInfinityValue evaluates `*`: its own scalar value, printed as written. +func TestInfinityValue(t *testing.T) { + _, got, err := evalDeclaredExpr(t, "package test {}", "*") + if err != nil { + t.Fatalf("* failed: %v", err) + } + if got.Kind != ValConst || !got.Const.IsUnbounded() { + t.Fatalf("* evaluated to %v (%v), want the unbounded constant", got.Kind, got.Const.Kind) + } + if text := FormatValue(got); text != "*" { + t.Errorf("FormatValue = %q, want %q", text, "*") + } + if text := FormatTraceValue(got); text != "*" { + t.Errorf("FormatTraceValue = %q, want %q", text, "*") + } +} + +// TestInfinityComparison orders `*` above every finite number and equal to itself. +func TestInfinityComparison(t *testing.T) { + cases := []struct { + expr string + want bool + }{ + {"* > 1", true}, + {"* > 1.5", true}, + {"* > -100", true}, + {"1 < *", true}, + {"* >= 7", true}, + {"* <= 1", false}, + {"* < 1", false}, + {"* == *", true}, + {"* >= *", true}, + {"* <= *", true}, + {"* > *", false}, + {"* < *", false}, + {"* != *", false}, + {"* == 1", false}, + {"* != 1", true}, + } + for _, tc := range cases { + t.Run(tc.expr, func(t *testing.T) { + _, got, err := evalDeclaredExpr(t, "package test {}", tc.expr) + if err != nil { + t.Fatalf("%s failed: %v", tc.expr, err) + } + if got.Kind != ValConst || got.Const.Kind != semantics.ValBool { + t.Fatalf("%s evaluated to %v, want a Boolean", tc.expr, got.Kind) + } + if got.Const.Bool != tc.want { + t.Errorf("%s = %v, want %v", tc.expr, got.Const.Bool, tc.want) + } + }) + } +} + +// TestInfinityArithmeticRefused refuses arithmetic over `*` with a typed error +// naming the operation rather than answering with a number. +func TestInfinityArithmeticRefused(t *testing.T) { + cases := []struct { + expr string + want string + }{ + {"* + 1", "operator '+' is not defined for the unbounded value '*'"}, + {"1 + *", "operator '+' is not defined for the unbounded value '*'"}, + {"* - 1", "operator '-' is not defined for the unbounded value '*'"}, + {"2 * *", "operator '*' is not defined for the unbounded value '*'"}, + {"* / 2", "operator '/' is not defined for the unbounded value '*'"}, + {"* % 2", "operator '%' is not defined for the unbounded value '*'"}, + {"* ** 2", "operator '**' is not defined for the unbounded value '*'"}, + {"-*", "unary '-' is not defined for *"}, + {"+*", "unary '+' is not defined for *"}, + {`* > "a"`, "'>' is not defined"}, + } + for _, tc := range cases { + t.Run(tc.expr, func(t *testing.T) { + _, _, err := evalDeclaredExpr(t, "package test {}", tc.expr) + if err == nil { + t.Fatalf("%s succeeded, want a typed error", tc.expr) + } + if !errors.Is(err, ErrTypeMismatch) { + t.Errorf("%s: error %v, want a type mismatch", tc.expr, err) + } + if !strings.Contains(err.Error(), tc.want) { + t.Errorf("%s: error %q, want it to contain %q", tc.expr, err, tc.want) + } + if strings.Contains(err.Error(), "∞") || strings.Contains(err.Error(), "Inf") { + t.Errorf("%s: error %q names the value as an infinity, want `*`", tc.expr, err) + } + }) + } +} diff --git a/internal/core/runtime/invoke_calc_body_test.go b/internal/core/runtime/invoke_calc_body_test.go index a63fee787..6b92f2d36 100644 --- a/internal/core/runtime/invoke_calc_body_test.go +++ b/internal/core/runtime/invoke_calc_body_test.go @@ -341,13 +341,13 @@ func TestCalcBodySuccessionIsNotAStep(t *testing.T) { const unevaluableResultModel = ` package test { item def Foo { attribute v; } - calc def mk { + calc def complement { in n; - Foo.metadata + ~n } - calc def unbounded { + calc def cast { in n; - * + n as Foo } } ` @@ -474,7 +474,7 @@ func TestUnevaluableResultIsNotReportedAsMissing(t *testing.T) { idx, _, ctx := buildRuntime(t, "", parseAndBuild(t, unevaluableResultModel)) root := idx.DocumentRoot("") - for _, name := range []string{"mk", "unbounded"} { + for _, name := range []string{"complement", "cast"} { calc, scope := calcByName(t, root, "test", name) _, err := ctx.InvokeCalc(calc, []Value{constInt(1)}, scope) if err == nil { diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go new file mode 100644 index 000000000..84e984c49 --- /dev/null +++ b/internal/core/runtime/metadata.go @@ -0,0 +1,101 @@ +package runtime + +import ( + "fmt" + + "github.com/Open-MBEE/OpenSysML/internal/core/ast" + "github.com/Open-MBEE/OpenSysML/internal/core/semantics" + "github.com/Open-MBEE/OpenSysML/internal/core/symbols" +) + +// evalMetadataAccess evaluates `ref.metadata` (KerML 8.4.4.10 MetadataAccessExpression): +// the metadata annotating the element ref names, as a sequence of objects of the +// annotating metadata types, in the order the annotations are stated. An element +// no metadata annotates reads as the empty sequence. +func (ec *EvalContext) evalMetadataAccess(n *ast.MetadataAccessExpr) (Value, error) { + sym, err := ec.metadataSubject(n) + if err != nil { + return Value{}, err + } + if ec.ctx.model == nil { + return Value{}, fmt.Errorf("%w: no model holds the metadata of %s", + ErrTypeMismatch, ec.ctx.qualifiedSymbolName(sym)) + } + annotations := ec.ctx.model.ElementMetadataOf(sym) + values := make([]Value, 0, len(annotations)) + for _, annotation := range annotations { + val, err := ec.metadataInstance(annotation) + if err != nil { + return Value{}, err + } + values = append(values, val) + } + return ec.newSequence(values) +} + +// metadataSubject is the element `ref.metadata` reads the metadata of. A name +// that resolves to no element, or to something that is a value rather than an +// element, is refused rather than answered with an empty sequence. +func (ec *EvalContext) metadataSubject(n *ast.MetadataAccessExpr) (*symbols.Symbol, error) { + name := ast.QualifiedText(n.Ref) + if name == "" { + return nil, fmt.Errorf("%w: metadata access names no element", ErrTypeMismatch) + } + if ec.ctx == nil || ec.ctx.resolver == nil { + return nil, fmt.Errorf("%w: %s", ErrUnresolvedReference, name) + } + sym, ok := ec.ctx.resolver.ResolveQualified(ec.scope, n.Ref) + if !ok || sym == nil { + return nil, fmt.Errorf("%w: %s", ErrUnresolvedReference, name) + } + if resolved, aliasOK := ec.ctx.resolver.ResolveAliasTarget(sym); aliasOK { + sym = resolved + } + if sym.Decl == nil { + return nil, fmt.Errorf("%w: metadata access requires an element, but %s declares none", + ErrTypeMismatch, name) + } + return sym, nil +} + +// metadataOfAValue reports `.metadata` read from a value rather than an element: +// only an element is annotated, so a scalar has no metadata to answer with. +func metadataOfAValue(value Value, parts []ast.NameSegment) error { + if len(parts) == 0 || parts[0].Text != "metadata" { + return nil + } + return fmt.Errorf("%w: metadata access requires an element, but %s is a value", + ErrTypeMismatch, describeValue(value)) +} + +// metadataInstance materializes one annotation as an object of its metadata +// type, with the features its body binds set to the values they are bound to; +// the remaining features keep the defaults the type declares. +func (ec *EvalContext) metadataInstance(annotation semantics.ElementMetadata) (Value, error) { + ctx := ec.ctx + mark := len(ctx.created) + inst, err := ctx.materialize(annotation.Type, 0, nil, "") + if err != nil { + ctx.abandonInstancesSince(mark) + return Value{}, fmt.Errorf("metadata %s: %w", ctx.qualifiedSymbolName(annotation.Type), err) + } + body := NewEvalContext(ctx, annotation.Scope) + for _, binding := range annotation.Bindings { + if fv, held := inst.FeatureValues[binding.Feature]; !held || fv == nil { + ctx.abandonInstancesSince(mark) + return Value{}, fmt.Errorf("%w: metadata %s declares no feature %s", + ErrTypeMismatch, ctx.qualifiedSymbolName(annotation.Type), binding.Feature) + } + val, err := body.Eval(binding.Value) + if err != nil { + ctx.abandonInstancesSince(mark) + return Value{}, fmt.Errorf("metadata %s: %s: %w", + ctx.qualifiedSymbolName(annotation.Type), binding.Feature, err) + } + if err := inst.SetFeatureValue(ctx, binding.Feature, val); err != nil { + ctx.abandonInstancesSince(mark) + return Value{}, fmt.Errorf("metadata %s: %w", ctx.qualifiedSymbolName(annotation.Type), err) + } + } + return Value{Kind: ValInstance, Instance: inst.ID}, nil +} diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go new file mode 100644 index 000000000..4e147a5d1 --- /dev/null +++ b/internal/core/runtime/metadata_test.go @@ -0,0 +1,166 @@ +package runtime + +import ( + "errors" + "slices" + "strings" + "testing" +) + +const metadataSrc = ` +package test { + private import ScalarValues::*; + + metadata def Safety { + attribute isMandatory : Boolean; + attribute level : Integer = 2; + } + + metadata def Legacy; + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + isMandatory = true; + } + @Legacy; + } + + part plain : Vehicle; + + attribute mass = 3; +} + +package about { + metadata test::Legacy about test::plain; +} +` + +// metadataTypeNames is the metadata type of every object in a `.metadata` sequence. +func metadataTypeNames(t *testing.T, ctx *Context, value Value) []string { + t.Helper() + if value.Kind != ValSequence { + t.Fatalf("metadata read as %v, want a sequence", value.Kind) + } + var names []string + for _, elem := range elementsOf(value) { + inst, ok := ctx.getInstance(elem.Instance) + if !ok { + t.Fatalf("element %v is no object", elem.Kind) + } + names = append(names, ctx.qualifiedSymbolName(inst.Type)) + } + return names +} + +// featureValue is what an object holds for the named feature. +func featureValue(t *testing.T, ctx *Context, inst *Instance, name string) Value { + t.Helper() + fv, err := inst.GetFeatureValue(ctx, name) + if err != nil { + t.Fatalf("feature %s: %v", name, err) + } + return fv.HeldValue() +} + +// TestMetadataAccessBoundValues reads the metadata of an annotated element: one +// object per annotation, in the order stated, carrying the values its body binds +// and the defaults its type declares. +func TestMetadataAccessBoundValues(t *testing.T) { + ctx, got, err := evalDeclaredExpr(t, metadataSrc, "test::seatBelt.metadata") + if err != nil { + t.Fatalf("seatBelt.metadata failed: %v", err) + } + if want := []string{"test::Safety", "test::Legacy"}; !slices.Equal(metadataTypeNames(t, ctx, got), want) { + t.Errorf("metadata types = %v, want %v", metadataTypeNames(t, ctx, got), want) + } + safety, ok := ctx.getInstance(elementsOf(got)[0].Instance) + if !ok { + t.Fatal("the first metadata value is no object") + } + if v := featureValue(t, ctx, safety, "isMandatory"); FormatValue(v) != "true" { + t.Errorf("isMandatory = %s, want true", FormatValue(v)) + } + if v := featureValue(t, ctx, safety, "level"); FormatValue(v) != "2" { + t.Errorf("level = %s, want the declared default 2", FormatValue(v)) + } +} + +// TestMetadataAccessAboutForm reads metadata an `about` annotation states elsewhere. +func TestMetadataAccessAboutForm(t *testing.T) { + ctx, got, err := evalDeclaredExpr(t, metadataSrc, "test::plain.metadata") + if err != nil { + t.Fatalf("plain.metadata failed: %v", err) + } + if want := []string{"test::Legacy"}; !slices.Equal(metadataTypeNames(t, ctx, got), want) { + t.Errorf("metadata types = %v, want %v", metadataTypeNames(t, ctx, got), want) + } +} + +// TestMetadataAccessEmpty reads the metadata of an element nothing annotates. +func TestMetadataAccessEmpty(t *testing.T) { + for _, expr := range []string{"test::mass.metadata", "test::Vehicle.metadata"} { + ctx, got, err := evalDeclaredExpr(t, metadataSrc, expr) + if err != nil { + t.Fatalf("%s failed: %v", expr, err) + } + if names := metadataTypeNames(t, ctx, got); len(names) != 0 { + t.Errorf("%s = %v, want the empty sequence", expr, names) + } + } +} + +// TestMetadataAccessNotAnElement refuses `.metadata` read from a value. +func TestMetadataAccessNotAnElement(t *testing.T) { + for _, expr := range []string{"1.metadata", `"abc".metadata`, "(1 + 2).metadata"} { + _, _, err := evalDeclaredExpr(t, metadataSrc, expr) + if err == nil { + t.Fatalf("%s succeeded, want a typed error", expr) + } + if !errors.Is(err, ErrTypeMismatch) { + t.Errorf("%s: error %v, want a type mismatch", expr, err) + } + if !strings.Contains(err.Error(), "metadata access requires an element") { + t.Errorf("%s: error %q, want it to require an element", expr, err) + } + } +} + +// TestMetadataAccessUnresolved refuses `.metadata` over a name that names nothing. +func TestMetadataAccessUnresolved(t *testing.T) { + _, _, err := evalDeclaredExpr(t, metadataSrc, "test::nope.metadata") + if !errors.Is(err, ErrUnresolvedReference) { + t.Errorf("error %v, want an unresolved reference", err) + } +} + +// TestMetadataAccessUnknownFeature refuses a body binding the metadata type declares +// no feature for, rather than dropping the value. +func TestMetadataAccessUnknownFeature(t *testing.T) { + src := ` +package test { + metadata def Safety { + attribute level : ScalarValues::Integer = 2; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + severity = 3; + } + } +} +` + _, _, err := evalDeclaredExpr(t, src, "test::seatBelt.metadata") + if err == nil { + t.Fatal("an unknown metadata feature succeeded, want a typed error") + } + if !errors.Is(err, ErrTypeMismatch) { + t.Errorf("error %v, want a type mismatch", err) + } + if !strings.Contains(err.Error(), "severity") { + t.Errorf("error %q, want it to name severity", err) + } +} diff --git a/internal/core/runtime/robustness_test.go b/internal/core/runtime/robustness_test.go index fd340bf09..a0d048450 100644 --- a/internal/core/runtime/robustness_test.go +++ b/internal/core/runtime/robustness_test.go @@ -183,6 +183,10 @@ func TestRuntimeRobustness(t *testing.T) { t.Run("operation_of_a_destroyed_object", testOperationOfADestroyedObject) t.Run("structured_attribute_chain_of_an_unknown_feature", testStructuredAttributeChainOfAnUnknownFeature) t.Run("elements_chain_of_a_non_numeric_collection", testElementsChainOfANonNumericCollection) + t.Run("arithmetic_over_the_unbounded_value", testArithmeticOverTheUnboundedValue) + t.Run("unbounded_value_compared_with_a_string", testUnboundedValueComparedWithAString) + t.Run("metadata_of_a_value", testMetadataOfAValue) + t.Run("metadata_of_an_unresolved_name", testMetadataOfAnUnresolvedName) t.Run("constraint_missing_feature", testConstraintMissingFeature) t.Run("nested_condition_subject_is_ambiguous", testNestedConditionSubjectIsAmbiguous) t.Run("satisfaction_subject_is_ambiguous", testSatisfactionSubjectIsAmbiguous) @@ -11440,3 +11444,41 @@ func testVerificationWithAnArgumentTheCaseDoesNotTake(t *testing.T) { t.Fatalf("error = %v, want ErrUnknownParameter", err) } } + +// testArithmeticOverTheUnboundedValue: `*` is no number, so arithmetic over it +// fails with a typed error naming the operation. +func testArithmeticOverTheUnboundedValue(t *testing.T) { + for _, expr := range []string{"* + 1", "1 - *", "2 * *", "* / 2", "* % 2", "* ** 2", "-*", "+*"} { + _, _, err := evalDeclaredExpr(t, "package test {}", expr) + if !errors.Is(err, ErrTypeMismatch) { + t.Errorf("%s: error = %v, want ErrTypeMismatch", expr, err) + } + } +} + +// testUnboundedValueComparedWithAString: nothing orders `*` against a string. +func testUnboundedValueComparedWithAString(t *testing.T) { + _, _, err := evalDeclaredExpr(t, "package test {}", `* > "a"`) + if !errors.Is(err, ErrTypeMismatch) { + t.Fatalf("error = %v, want ErrTypeMismatch", err) + } +} + +// testMetadataOfAValue: only an element carries metadata, so reading it from a +// scalar fails rather than answering with the empty sequence. +func testMetadataOfAValue(t *testing.T) { + for _, expr := range []string{"1.metadata", `"abc".metadata`} { + _, _, err := evalDeclaredExpr(t, "package test {}", expr) + if !errors.Is(err, ErrTypeMismatch) { + t.Errorf("%s: error = %v, want ErrTypeMismatch", expr, err) + } + } +} + +// testMetadataOfAnUnresolvedName: a name that names no element is refused. +func testMetadataOfAnUnresolvedName(t *testing.T) { + _, _, err := evalDeclaredExpr(t, "package test {}", "test::missing.metadata") + if !errors.Is(err, ErrUnresolvedReference) { + t.Fatalf("error = %v, want ErrUnresolvedReference", err) + } +} diff --git a/internal/core/runtime/testdata/conformance/README.md b/internal/core/runtime/testdata/conformance/README.md index a3a80be2c..5c2bb7527 100644 --- a/internal/core/runtime/testdata/conformance/README.md +++ b/internal/core/runtime/testdata/conformance/README.md @@ -311,6 +311,8 @@ Supported types: - `Boolean`: JSON boolean - `String`: JSON string - `Null`: JSON null +- `Infinity`: the unbounded `*`, which is no number and carries no `value` + (`{"type": "Infinity"}`) - `Quantity`: JSON number, with the `unit` the magnitude is written in - `MeasurementRef`: the `unit` a measurement reference names, and no `value` (`{"type": "MeasurementRef", "unit": "m**2"}`) diff --git a/internal/core/runtime/testdata/conformance/metadata_access_annotations.expected.json b/internal/core/runtime/testdata/conformance/metadata_access_annotations.expected.json new file mode 100644 index 000000000..9b6c21dc2 --- /dev/null +++ b/internal/core/runtime/testdata/conformance/metadata_access_annotations.expected.json @@ -0,0 +1,13 @@ +{ + "type": "instance", + "instantiate": "test::Report", + "libraries": true, + "slots": { + "annotations": {"type": "Sequence", "elements": [{"type": "Instance"}, {"type": "Instance"}]}, + "mandatory": {"type": "Boolean", "value": true}, + "level": {"type": "Integer", "value": 4}, + "superseded": {"type": "String", "value": "none"}, + "defaulted": {"type": "Integer", "value": 2}, + "none": {"type": "Sequence", "elements": []} + } +} diff --git a/internal/core/runtime/testdata/conformance/metadata_access_annotations.sysml b/internal/core/runtime/testdata/conformance/metadata_access_annotations.sysml new file mode 100644 index 000000000..7c43030fd --- /dev/null +++ b/internal/core/runtime/testdata/conformance/metadata_access_annotations.sysml @@ -0,0 +1,40 @@ +// `.metadata` (KerML 8.3.3.1 MetadataAccessExpression) reads the metadata +// annotating an element: one object per annotation, in the order stated, +// carrying the values its body binds over the defaults its type declares. +package test { + private import ScalarValues::*; + + metadata def Safety { + attribute isMandatory : Boolean; + attribute level : Integer = 2; + } + + metadata def Legacy { + attribute supersededBy : String = "none"; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + isMandatory = true; + level = 4; + } + @Legacy; + } + + part airbag : Vehicle { + @Safety; + } + + part chassis : Vehicle; + + part def Report { + attribute annotations [*] = seatBelt.metadata; + attribute mandatory = seatBelt.metadata#(1).isMandatory; + attribute level = seatBelt.metadata#(1).level; + attribute superseded = seatBelt.metadata#(2).supersededBy; + attribute defaulted = airbag.metadata#(1).level; + attribute none [*] = chassis.metadata; + } +} diff --git a/internal/core/runtime/testdata/conformance/value_unbounded_arithmetic_refused.expected.json b/internal/core/runtime/testdata/conformance/value_unbounded_arithmetic_refused.expected.json new file mode 100644 index 000000000..e30882143 --- /dev/null +++ b/internal/core/runtime/testdata/conformance/value_unbounded_arithmetic_refused.expected.json @@ -0,0 +1,16 @@ +{ + "type": "instance", + "instantiate": "test::Arithmetic", + "libraries": true, + "slots": { + "sum": {"error": "operator '+' is not defined for the unbounded value '*': * + 1"}, + "addedTo": {"error": "operator '+' is not defined for the unbounded value '*': 1 + *"}, + "difference": {"error": "operator '-' is not defined for the unbounded value '*': * - 1"}, + "product": {"error": "operator '*' is not defined for the unbounded value '*': 2 * *"}, + "quotient": {"error": "operator '/' is not defined for the unbounded value '*': * / 2"}, + "remainder": {"error": "operator '%' is not defined for the unbounded value '*': * % 2"}, + "power": {"error": "operator '**' is not defined for the unbounded value '*': * ** 2"}, + "negated": {"error": "unary '-' is not defined for *"}, + "positive": {"error": "unary '+' is not defined for *"} + } +} diff --git a/internal/core/runtime/testdata/conformance/value_unbounded_arithmetic_refused.sysml b/internal/core/runtime/testdata/conformance/value_unbounded_arithmetic_refused.sysml new file mode 100644 index 000000000..7e1b749f0 --- /dev/null +++ b/internal/core/runtime/testdata/conformance/value_unbounded_arithmetic_refused.sysml @@ -0,0 +1,17 @@ +// `*` is no number, so arithmetic over it is refused with an error naming the +// operation rather than answered with a finite result. +package test { + private import ScalarValues::*; + + part def Arithmetic { + attribute sum = * + 1; + attribute addedTo = 1 + *; + attribute difference = * - 1; + attribute product = 2 * *; + attribute quotient = * / 2; + attribute remainder = * % 2; + attribute power = * ** 2; + attribute negated = -*; + attribute positive = +*; + } +} diff --git a/internal/core/runtime/testdata/conformance/value_unbounded_comparison.expected.json b/internal/core/runtime/testdata/conformance/value_unbounded_comparison.expected.json new file mode 100644 index 000000000..471696b73 --- /dev/null +++ b/internal/core/runtime/testdata/conformance/value_unbounded_comparison.expected.json @@ -0,0 +1,17 @@ +{ + "type": "instance", + "instantiate": "test::Bounds", + "libraries": true, + "slots": { + "unbounded": {"type": "Infinity"}, + "exceedsNatural": {"type": "Boolean", "value": true}, + "exceedsInteger": {"type": "Boolean", "value": true}, + "exceedsReal": {"type": "Boolean", "value": true}, + "belowUnbounded": {"type": "Boolean", "value": true}, + "equalsItself": {"type": "Boolean", "value": true}, + "atMostItself": {"type": "Boolean", "value": true}, + "aboveItself": {"type": "Boolean", "value": false}, + "atMostFinite": {"type": "Boolean", "value": false}, + "differsFromFinite": {"type": "Boolean", "value": true} + } +} diff --git a/internal/core/runtime/testdata/conformance/value_unbounded_comparison.sysml b/internal/core/runtime/testdata/conformance/value_unbounded_comparison.sysml new file mode 100644 index 000000000..6e1318b76 --- /dev/null +++ b/internal/core/runtime/testdata/conformance/value_unbounded_comparison.sysml @@ -0,0 +1,18 @@ +// `*` (KerML 8.3.3.1 LiteralInfinity) is a value of its own: it exceeds every +// finite number, whatever its type, and equals itself. +package test { + private import ScalarValues::*; + + part def Bounds { + attribute unbounded = *; + attribute exceedsNatural = * > 1000000; + attribute exceedsInteger = * > -3; + attribute exceedsReal = * > 1.5e10; + attribute belowUnbounded = 42 < *; + attribute equalsItself = * == *; + attribute atMostItself = * <= *; + attribute aboveItself = * > *; + attribute atMostFinite = * <= 7; + attribute differsFromFinite = * != 7; + } +} diff --git a/internal/core/semantics/annotations.go b/internal/core/semantics/annotations.go index 9c18a55e5..ad2e92fec 100644 --- a/internal/core/semantics/annotations.go +++ b/internal/core/semantics/annotations.go @@ -123,6 +123,78 @@ func (m *Model) AnnotationSitesOf(sym *symbols.Symbol) []AnnotationSite { return out } +// MetadataBinding is one feature an annotation body binds and the expression it +// is bound to, read in the scope the annotation is stated in. +type MetadataBinding struct { + Feature string + Value ast.Node +} + +// ElementMetadata is one metadata annotation of an element as `.metadata` reads +// it: the metadata type to materialize and the values its body binds. Values +// the body leaves unbound come from the type's own declarations. +type ElementMetadata struct { + Type *symbols.Symbol + Node ast.Node + // Scope is where the annotating node is declared, which its bound values + // resolve names against. + Scope *symbols.Scope + About bool + Bindings []MetadataBinding +} + +// ElementMetadataOf returns the metadata annotating sym, inline annotations +// first and `about`-form ones after, each in declaration order — the same side +// table an element filter classifies by. +func (m *Model) ElementMetadataOf(sym *symbols.Symbol) []ElementMetadata { + var out []ElementMetadata + for _, a := range m.annotationsOf(sym) { + if a.typ == nil || a.node == nil { + continue + } + out = append(out, ElementMetadata{ + Type: a.typ, + Node: a.node, + Scope: a.scope, + About: a.about, + Bindings: metadataBindings(metadataBody(a.node)), + }) + } + return out +} + +// metadataBody is the body an annotation node binds feature values in. +func metadataBody(node ast.Node) []ast.Node { + switch n := node.(type) { + case *ast.PrefixMetadata: + return n.Body + case *ast.Usage: + return n.Members + default: + return nil + } +} + +// metadataBindings is the features an annotation body binds, in declaration order. +func metadataBindings(body []ast.Node) []MetadataBinding { + var out []MetadataBinding + for _, member := range body { + if mem, ok := member.(*ast.Membership); ok { + member = mem.Member + } + usage, ok := member.(*ast.Usage) + if !ok || usage.Value == nil { + continue + } + name := boundFeatureName(usage) + if name == "" { + continue + } + out = append(out, MetadataBinding{Feature: name, Value: usage.Value}) + } + return out +} + // sortedFeatureNames orders an annotation's bound features by name, so that what // is reported does not depend on map iteration order. func sortedFeatureNames(values map[string]symbols.FilterValue) []string { diff --git a/internal/core/semantics/eval.go b/internal/core/semantics/eval.go index ad09e4409..f6e59951b 100644 --- a/internal/core/semantics/eval.go +++ b/internal/core/semantics/eval.go @@ -125,6 +125,38 @@ func (v Value) WholeNumber() (int64, bool) { return 0, false } +// IsUnbounded reports whether the value is the unbounded `*`. +func (v Value) IsUnbounded() bool { return v.Kind == ValInfinity } + +// UnboundedOrder compares l and r where at least one is the unbounded `*`: `*` +// exceeds every finite number and equals itself. ok is false when the other +// operand is neither a number nor `*`, since nothing orders it against one. +func UnboundedOrder(l, r Value) (order int, ok bool) { + ordinal := func(v Value) (int, bool) { + switch { + case v.IsUnbounded(): + return 1, true + case v.IsNumeric(): + return 0, true + default: + return 0, false + } + } + lo, lok := ordinal(l) + ro, rok := ordinal(r) + if !lok || !rok { + return 0, false + } + switch { + case lo == ro: + return 0, true + case lo > ro: + return 1, true + default: + return -1, true + } +} + // AsReal returns the value as a float64 (int and real only). func (v Value) AsReal() float64 { if v.Kind == ValInt { @@ -382,6 +414,12 @@ func evalEquality(op ast.OperatorKind, l, r Value) (Value, bool) { switch { case l.Kind == ValBool && r.Kind == ValBool: eq = l.Bool == r.Bool + case l.IsUnbounded() || r.IsUnbounded(): + order, ok := UnboundedOrder(l, r) + if !ok { + return Value{}, false + } + eq = order == 0 case l.IsNumeric() && r.IsNumeric(): eq = l.AsReal() == r.AsReal() default: @@ -394,6 +432,17 @@ func evalEquality(op ast.OperatorKind, l, r Value) (Value, bool) { } func evalComparison(op ast.OperatorKind, l, r Value) (Value, bool) { + if l.IsUnbounded() || r.IsUnbounded() { + order, ok := UnboundedOrder(l, r) + if !ok { + return Value{}, false + } + res, ok := OrderSatisfies(op, order) + if !ok { + return Value{}, false + } + return Value{Kind: ValBool, Bool: res}, true + } if !l.IsNumeric() || !r.IsNumeric() { return Value{}, false } @@ -412,6 +461,23 @@ func evalComparison(op ast.OperatorKind, l, r Value) (Value, bool) { return Value{Kind: ValBool, Bool: res}, true } +// OrderSatisfies applies an ordering operator to a comparison result of -1, 0 +// or 1. ok is false for an operator that is no ordering. +func OrderSatisfies(op ast.OperatorKind, order int) (res, ok bool) { + switch op { + case ast.OpLt: + return order < 0, true + case ast.OpLe: + return order <= 0, true + case ast.OpGt: + return order > 0, true + case ast.OpGe: + return order >= 0, true + default: + return false, false + } +} + func evalArithmetic(op ast.OperatorKind, l, r Value) (Value, bool) { if !l.IsNumeric() || !r.IsNumeric() { return Value{}, false diff --git a/internal/core/semantics/quantity.go b/internal/core/semantics/quantity.go index f6314804b..3a2ca63f8 100644 --- a/internal/core/semantics/quantity.go +++ b/internal/core/semantics/quantity.go @@ -117,7 +117,7 @@ func FormatConst(c Value) string { case ValBool: return strconv.FormatBool(c.Bool) case ValInfinity: - return "∞" + return "*" default: return "" } diff --git a/internal/core/semantics/valuetype.go b/internal/core/semantics/valuetype.go index c61f6c842..f278d66d3 100644 --- a/internal/core/semantics/valuetype.go +++ b/internal/core/semantics/valuetype.go @@ -17,6 +17,7 @@ const ( fqnString = "ScalarValues::String" fqnNatural = "ScalarValues::Natural" + fqnPositive = "ScalarValues::Positive" fqnInteger = "ScalarValues::Integer" fqnRational = "ScalarValues::Rational" fqnReal = "ScalarValues::Real" @@ -103,6 +104,9 @@ func (m *Model) exprConformance(scope *symbols.Scope, node ast.Node, want *symbo return m.typeConformance(m.libSymbol(fqnNatural), want) case *ast.LiteralReal: return m.typeConformance(m.libSymbol(fqnRational), want) + case *ast.LiteralInfinity: + // `*` is the natural number exceeding every other (KerML 8.4.4.6). + return m.typeConformance(m.libSymbol(fqnPositive), want) case *ast.FeatureReference, *ast.QualifiedName, *ast.FeatureChainExpr: sym, ok := m.resolver.ResolveTarget(scope, n) if !ok || sym == nil { diff --git a/internal/core/solve/pin.go b/internal/core/solve/pin.go index eeb68e852..eabcf9c9d 100644 --- a/internal/core/solve/pin.go +++ b/internal/core/solve/pin.go @@ -558,7 +558,7 @@ func constText(c semantics.Value) string { case semantics.ValBool: return strconv.FormatBool(c.Bool) case semantics.ValInfinity: - return "∞" + return "*" default: return "" } diff --git a/internal/grpc/capability_response.go b/internal/grpc/capability_response.go index c8651db28..50346189f 100644 --- a/internal/grpc/capability_response.go +++ b/internal/grpc/capability_response.go @@ -93,6 +93,10 @@ func (s *Service) filterValueCapabilities(value *pb.Value) { shown := displayValue(value) value.Kind = &pb.Value_Null{Null: "unsupported: " + shown.Kind.String() + " " + runtime.FormatValue(shown)} } + case *pb.Value_Infinity: + if !s.capabilities.has(CapabilityInfinityValue) { + value.Kind = &pb.Value_Null{Null: "unsupported: unbounded value *"} + } } } diff --git a/internal/grpc/convert.go b/internal/grpc/convert.go index 09b4fd013..4e39e188a 100644 --- a/internal/grpc/convert.go +++ b/internal/grpc/convert.go @@ -250,7 +250,7 @@ func ValueToProtoIn(rt *runtime.Context, val runtime.Value, idx *symbols.Index) case semantics.ValBool: return &pb.Value{Kind: &pb.Value_BoolValue{BoolValue: val.Const.Bool}} case semantics.ValInfinity: - return &pb.Value{Kind: &pb.Value_StringValue{StringValue: "*"}} + return &pb.Value{Kind: &pb.Value_Infinity{Infinity: true}} default: return &pb.Value{Kind: &pb.Value_Null{Null: "unsupported const kind"}} } @@ -488,6 +488,15 @@ func ValueCarriesMeasurementRef(pv *pb.Value) bool { }) } +// ValueCarriesInfinity reports whether a value, or any value nested in it, is +// the unbounded value: the kind infinity_value governs. +func ValueCarriesInfinity(pv *pb.Value) bool { + return valueCarries(pv, func(v *pb.Value) bool { + _, ok := v.GetKind().(*pb.Value_Infinity) + return ok + }) +} + // ValueCarriesComplex reports whether a value, or any value nested in it, is a // Complex: the kind the complex_values capability governs. func ValueCarriesComplex(pv *pb.Value) bool { @@ -1141,6 +1150,8 @@ func protoToScalar(pv *pb.Value) runtime.Value { return runtime.Value{Kind: runtime.ValNull} case *pb.Value_Complex: return runtime.NewComplex(ProtoToComplex(k.Complex)) + case *pb.Value_Infinity: + return runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValInfinity}} default: return runtime.Value{Kind: runtime.ValNull} } diff --git a/internal/grpc/convert_infinity_test.go b/internal/grpc/convert_infinity_test.go new file mode 100644 index 000000000..48a9008e6 --- /dev/null +++ b/internal/grpc/convert_infinity_test.go @@ -0,0 +1,144 @@ +package grpc + +import ( + "context" + "strings" + "testing" + + "connectrpc.com/connect" + + pb "github.com/Open-MBEE/OpenSysML/api/proto" + "github.com/Open-MBEE/OpenSysML/internal/core/runtime" + "github.com/Open-MBEE/OpenSysML/internal/core/semantics" + "github.com/Open-MBEE/OpenSysML/internal/core/symbols" +) + +// infinityWireModel yields the unbounded value as a feature value, alone and +// nested in a sequence, beside the ordinary string that prints the same way. +const infinityWireModel = ` +package U { + private import ScalarValues::*; + + attribute unbounded = *; + attribute star : String = "*"; + attribute bounds [*] = (1, *); + + action pass { + in x; + out y; + first start; + action inner { assign y := x; } + then done; + succession first start then inner; + } +} +` + +func infinityValue() *pb.Value { + return &pb.Value{Kind: &pb.Value_Infinity{Infinity: true}} +} + +// The unbounded value crosses as its own arm, distinct from the string "*" a +// client would otherwise read as text, and reads back as the same value. +func TestInfinityRoundTrip(t *testing.T) { + idx := symbols.NewIndex() + unbounded := runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValInfinity}} + + pv := ValueToProto(unbounded, idx) + if _, ok := pv.GetKind().(*pb.Value_Infinity); !ok { + t.Fatalf("* crossed as %T, want the infinity arm", pv.GetKind()) + } + + back, err := ProtoToValueIn(pv, idx, nil) + if err != nil { + t.Fatalf("ProtoToValueIn: %v", err) + } + if back.Kind != runtime.ValConst || !back.Const.IsUnbounded() { + t.Errorf("round trip of * = %s (%v)", back.Kind, back) + } + + // The string "*" stays a string in both directions. + str := ValueToProto(runtime.NewStringValue("*"), idx) + if str.GetStringValue() != "*" { + t.Errorf(`"*" crossed as %T, want a string`, str.GetKind()) + } + strBack, err := ProtoToValueIn(str, idx, nil) + if err != nil { + t.Fatalf(`ProtoToValueIn("*"): %v`, err) + } + if strBack.Kind != runtime.ValString || strBack.Str() != "*" { + t.Errorf(`round trip of "*" = %s (%v)`, strBack.Kind, strBack) + } + + seq := runtime.NewSequence() + seq.Append(runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValInt, Int: 1}}) + seq.Append(unbounded) + elements := ValueToProto(runtime.NewSequenceValue(seq), idx).GetSequence().GetElements() + if len(elements) != 2 { + t.Fatalf("(1, *) crossed as %d elements", len(elements)) + } + if _, ok := elements[1].GetKind().(*pb.Value_Infinity); !ok { + t.Errorf("(1, *)#2 crossed as %T, want the infinity arm", elements[1].GetKind()) + } +} + +// Evaluating the model reports the unbounded value on the arm and the ordinary +// string as text, so a client can tell them apart. +func TestInfinityEvaluate(t *testing.T) { + srv := mustNewService(t, 4) + modelHash := mustParse(t, srv, infinityWireModel) + + if pv := mustEvaluate(t, srv, modelHash, "U::unbounded"); !pv.GetInfinity() { + t.Errorf("U::unbounded = %v, want the infinity arm", pv) + } + if pv := mustEvaluate(t, srv, modelHash, "U::star"); pv.GetStringValue() != "*" { + t.Errorf(`U::star = %v, want the string "*"`, pv) + } + bounds := mustEvaluate(t, srv, modelHash, "U::bounds").GetSequence().GetElements() + if len(bounds) != 2 || bounds[0].GetIntValue() != 1 || !bounds[1].GetInfinity() { + t.Errorf("U::bounds = %v, want (1, *)", bounds) + } +} + +// The arm is advertised under its own capability, so a client can require it; a +// service withholding it reports the value as unsupported — nested in a +// structured value included — and refuses one sent to it rather than reading it +// as another value. The string "*" is unaffected. +func TestInfinityCapability(t *testing.T) { + ctx := context.Background() + found := false + for _, c := range Capabilities() { + found = found || c == CapabilityInfinityValue + } + if !found { + t.Errorf("capabilities %v do not include %q", Capabilities(), CapabilityInfinityValue) + } + + withheld := mustNewServiceWithout(t, CapabilityInfinityValue) + modelHash := mustParse(t, withheld, infinityWireModel) + + const want = "unsupported: unbounded value *" + got := mustEvaluate(t, withheld, modelHash, "U::unbounded") + if got.GetInfinity() || got.GetNull() != want { + t.Errorf("U::unbounded without %s = %v, want null %q", CapabilityInfinityValue, got, want) + } + if pv := mustEvaluate(t, withheld, modelHash, "U::star"); pv.GetStringValue() != "*" { + t.Errorf(`U::star without %s = %v, want the string "*"`, CapabilityInfinityValue, pv) + } + bounds := mustEvaluate(t, withheld, modelHash, "U::bounds").GetSequence().GetElements() + if len(bounds) != 2 || bounds[1].GetNull() != want { + t.Errorf("U::bounds without %s = %v, want the element withheld", CapabilityInfinityValue, bounds) + } + + nested := &pb.Value{Kind: &pb.Value_Sequence{Sequence: &pb.ValueSequence{Elements: []*pb.Value{infinityValue()}}}} + for name, input := range map[string]*pb.Value{"unbounded": infinityValue(), "nested": nested} { + _, err := withheld.ExecuteAction(ctx, &pb.ExecuteActionRequest{ + ModelHash: modelHash, + ActionSymbolId: "U::pass", + Inputs: map[string]*pb.Value{"x": input}, + }) + if connect.CodeOf(err) != connect.CodeUnimplemented || !strings.Contains(err.Error(), CapabilityInfinityValue) { + t.Errorf("ExecuteAction with %s input without %s: err = %v, want UNIMPLEMENTED naming the capability", name, CapabilityInfinityValue, err) + } + } +} diff --git a/internal/grpc/service.go b/internal/grpc/service.go index 699005caf..10c6bc9be 100644 --- a/internal/grpc/service.go +++ b/internal/grpc/service.go @@ -109,6 +109,10 @@ const CapabilityMeasurementRefs = "measurement_refs" // verification case through RunAnalysis. const CapabilityVerificationVerdicts = "verification_verdicts" +// CapabilityInfinityValue names the capability of carrying the unbounded value +// `*` as Value.infinity, rather than reporting it as an unsupported null. +const CapabilityInfinityValue = "infinity_value" + // capabilities is what this build supports, in report order. A capability is // only ever added: renaming or dropping one breaks clients that require it. var capabilities = []string{ @@ -119,6 +123,7 @@ var capabilities = []string{ CapabilityStrictConformance, CapabilityDocumentQuery, CapabilityRenderDocument, CapabilityParseSources, CapabilityComplexValues, CapabilityStructuredValues, CapabilityMeasurementRefs, CapabilityVerificationVerdicts, + CapabilityInfinityValue, } type capabilityAvailability struct { @@ -269,7 +274,12 @@ func (s *Service) requireValueCapabilities(pv *pb.Value) error { } } if ValueCarriesMeasurementRef(pv) { - return s.requireCapability(CapabilityMeasurementRefs) + if err := s.requireCapability(CapabilityMeasurementRefs); err != nil { + return err + } + } + if ValueCarriesInfinity(pv) { + return s.requireCapability(CapabilityInfinityValue) } return nil } diff --git a/internal/repl/docquery.go b/internal/repl/docquery.go index 858d99f63..1d6244408 100644 --- a/internal/repl/docquery.go +++ b/internal/repl/docquery.go @@ -376,7 +376,7 @@ func formatQueryValue(value queryexec.Value) string { return strconv.FormatBool(boolean) } if value.Kind() == queryexec.ValueInfinity { - return "∞" + return "*" } if quantity, ok := value.Quantity(); ok { return quantity.String() diff --git a/internal/repl/runtime_commands_test.go b/internal/repl/runtime_commands_test.go index 1e91841f8..bfef4f846 100644 --- a/internal/repl/runtime_commands_test.go +++ b/internal/repl/runtime_commands_test.go @@ -367,7 +367,7 @@ func TestFormatValue(t *testing.T) { {"int", runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValInt, Int: 7}}, "7"}, {"real", runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValReal, Real: 1.5}}, "1.5"}, {"bool", runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValBool, Bool: true}}, "true"}, - {"infinity", runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValInfinity}}, "∞"}, + {"infinity", runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValInfinity}}, "*"}, {"null", runtime.Value{Kind: runtime.ValNull}, "null"}, {"string", runtime.NewStringValue("hi"), `"hi"`}, {"instance", runtime.Value{Kind: runtime.ValInstance, Instance: 3}, "Instance(ID: 3)"}, From 8dfe9b4d10ac6b0a0b27150f43965393f428fdc8 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 00:47:36 +0000 Subject: [PATCH 02/11] fix(semantics): reach an `about` annotation from a re-indexed element MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `about` index keys the annotated element by symbol, but the prompt evaluates against a scope tree re-indexed from the same declarations, so its twin of the element missed every annotation stated about it — `elem.metadata` and package metadata read as empty there while the same document answered them over gRPC. The index now also keys the annotations by the annotated element's declaration, which identifies it across both trees. Co-Authored-By: jason.han --- docs/project/spec-compliance.md | 2 +- internal/core/semantics/annotations.go | 14 +++++++- internal/core/semantics/model.go | 3 ++ internal/repl/metadata_about_eval_test.go | 42 +++++++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 internal/repl/metadata_about_eval_test.go diff --git a/docs/project/spec-compliance.md b/docs/project/spec-compliance.md index b9a465214..2307c6088 100644 --- a/docs/project/spec-compliance.md +++ b/docs/project/spec-compliance.md @@ -660,7 +660,7 @@ by name is refused naming what is missing rather than approximated. | Conditional (`if c ? a else b`) and null coalescing (`??`), both lazy | `eval.go` evalConditional/evalNullCoalesce | `calc_conditional_branch.sysml`, `calc_null_coalesce.sysml` | ✅ Faithful | | Literal values (Integer, Real, Boolean, String) | `eval.go:109` evalLiteral* | `calc_simple_add.sysml` | ✅ Faithful | | `*` in an expression position is the unbounded value (KerML §8.4.4.6 `LiteralInfinity`, typed `ScalarValues::Positive`): it exceeds every finite Integer, Real and Natural, equals itself, orders consistently under `<`, `<=`, `>`, `>=`, and prints as `*` in a value, a trace, a solver pin and a document-query cell. It is no number, so every arithmetic operation over it — `+`, `-`, `*`, `/`, `%`, `**`, unary `+` and unary `-` — is `ErrTypeMismatch` naming the operation, never an infinity, a NaN or a finite answer | `runtime/eval.go` `evalLiteralInfinity`, `constArithmetic`, `constCompare`; `semantics/eval.go` `Value.IsUnbounded`, `UnboundedOrder`, `OrderSatisfies`, `FormatConst`; `semantics/valuetype.go` `exprConformance`; `solve/pin.go`; `repl/docquery.go` | `runtime/infinity_test.go:TestInfinityValue`, `:TestInfinityComparison`, `:TestInfinityArithmeticRefused`; conformance `value_unbounded_comparison`, `value_unbounded_arithmetic_refused`; `parse/unbounded_and_metadata_access.golden`; `robustness_test.go:arithmetic_over_the_unbounded_value`, `:unbounded_value_compared_with_a_string` | ✅ Faithful | -| `ref.metadata` is a MetadataAccessExpression (KerML §8.4.4.10): it yields the metadata annotating the element `ref` names as a sequence of metadata instances in declaration order — inline `@`-annotations first, `metadata … about` ones after — each instance carrying the feature values the annotation body binds and, where the body binds none, the metadata type's own declared defaults. An element no metadata annotates yields the empty sequence; metadata read off a value (`1.metadata`) is `ErrTypeMismatch`, and a name that resolves to nothing is `ErrUnresolvedReference` | `parser/expr.go` `parsePostfixes` (`metadataAccessRef`); `semantics/annotations.go` `Model.ElementMetadataOf`, `metadataBindings` (the annotation side table an element filter classifies by); `runtime/metadata.go` `evalMetadataAccess`, `metadataSubject`, `metadataInstance` | `runtime/metadata_test.go:TestMetadataAccessBoundValues`, `:TestMetadataAccessAboutForm`, `:TestMetadataAccessEmpty`, `:TestMetadataAccessNotAnElement`, `:TestMetadataAccessUnresolved`, `:TestMetadataAccessUnknownFeature`; conformance `metadata_access_annotations`; `parse/unbounded_and_metadata_access.golden`; `robustness_test.go:metadata_of_a_value`, `:metadata_of_an_unresolved_name` | ✅ Faithful | +| `ref.metadata` is a MetadataAccessExpression (KerML §8.4.4.10): it yields the metadata annotating the element `ref` names as a sequence of metadata instances in declaration order — inline `@`-annotations first, `metadata … about` ones after — each instance carrying the feature values the annotation body binds and, where the body binds none, the metadata type's own declared defaults. An element no metadata annotates yields the empty sequence; metadata read off a value (`1.metadata`) is `ErrTypeMismatch`, and a name that resolves to nothing is `ErrUnresolvedReference` | `parser/expr.go` `parsePostfixes` (`metadataAccessRef`); `semantics/annotations.go` `Model.ElementMetadataOf`, `metadataBindings` (the annotation side table an element filter classifies by); `runtime/metadata.go` `evalMetadataAccess`, `metadataSubject`, `metadataInstance`; `semantics/annotations.go` `aboutAnnotations` reaches an `about` annotation from a re-indexed twin of the annotated symbol, so the prompt's own scope tree reads it as the index does | `runtime/metadata_test.go:TestMetadataAccessBoundValues`, `:TestMetadataAccessAboutForm`, `:TestMetadataAccessEmpty`, `:TestMetadataAccessNotAnElement`, `:TestMetadataAccessUnresolved`, `:TestMetadataAccessUnknownFeature`; conformance `metadata_access_annotations`; `parse/unbounded_and_metadata_access.golden`; `robustness_test.go:metadata_of_a_value`, `:metadata_of_an_unresolved_name`; `repl/metadata_about_eval_test.go:TestEvalMetadataReadsAboutAnnotations` | ✅ Faithful | | Feature reference resolution | `eval.go:141` evalFeatureReference | `constraint_literal.sysml` | ✅ Faithful | | Qualified name resolution (A::B::C) | `eval.go:53` Eval + `resolve/qualified.go` | `calc_qualified_names.sysml` | ✅ Faithful | | A qualified name evaluates as the checker resolves it, imports included (KerML §8.2.3.5 import, §8.2.3.3 visibility): a segment that names a member a `public import` re-exports — of every member (`Bq::x` with `public import A::*`), of one (`public import A::x`), recursively (`import A::**`), through a façade of a façade, by short name or through an `alias` — reaches the same element the checker reaches, which is how the library's `ISQ` and `SI` re-export the ISQ part packages (`ISQ::speed`, `SI::speed`); a `private import` stays reachable only from inside the importing namespace, and a name the checker rejects fails at evaluation with the checker's own message and classification (`unresolved reference: Priv::x`; `ambiguous reference: Twice::t (2 candidates)` when several members answer to a segment) | `runtime/eval.go` `evalNameGeneral` resolves the whole name through `resolve.Resolver.ReadQualified` (the checker's `walkQualified`, so the two tiers cannot disagree), whose `Reading` carries the element, the resolved segments — routing a calc usage's outputs to `evalCalcUsageMembers` and keeping the variant/literal reports in `unresolvedQualifiedName` — and the candidate count of a name rejected as ambiguous; a reading is memoized by scope and node, so one expression evaluated in several scopes answers in each with what that scope sees | `calc_qualified_name_through_import.sysml`, `calc_qualified_name_private_import.sysml`, `calc_qualified_name_ambiguous.sysml`, `qualified_import_test.go:TestQualifiedNameThroughImportEvaluates`, `:TestQualifiedNameThroughImportRejectedAsChecked`, `:TestQualifiedNameThroughImportKeepsTypedErrors`, `:TestLibraryQuantityThroughFacadeResolves`, `:TestQualifiedNameEvaluatedInSeveralScopes`, `resolve/reading_test.go:TestReadQualifiedAnswersPerScope`, `:TestReadQualifiedReportsFailure` | ✅ Faithful (a library quantity reached through a façade resolves to its declaration, which like `SI::m` carries no scalar value, so the evaluator reports that declaration rather than a missing member) | diff --git a/internal/core/semantics/annotations.go b/internal/core/semantics/annotations.go index ad2e92fec..b45f3c6e5 100644 --- a/internal/core/semantics/annotations.go +++ b/internal/core/semantics/annotations.go @@ -338,7 +338,15 @@ func bodyScope(_ *ast.Usage, declared *symbols.Scope) *symbols.Scope { return de // aboutAnnotations returns the annotations that `metadata m about sym;` // declarations elsewhere in the workspace state about sym. func (m *Model) aboutAnnotations(sym *symbols.Symbol) []annotation { - return m.annotationsAbout()[sym] + if out, ok := m.annotationsAbout()[sym]; ok { + return out + } + // The caller may hold a symbol re-indexed from the same declaration as the + // one indexed here, which the declaration identifies across both trees. + if sym.Decl == nil { + return nil + } + return m.aboutByDecl[sym.Decl] } // AboutAnnotatedSymbols returns every element an `about` metadata usage @@ -358,6 +366,7 @@ func (m *Model) annotationsAbout() map[*symbols.Symbol][]annotation { return m.aboutAnnots } m.aboutAnnots = make(map[*symbols.Symbol][]annotation) + m.aboutByDecl = make(map[ast.Node][]annotation) idx := m.resolver.Index() if idx == nil { return m.aboutAnnots @@ -417,6 +426,9 @@ func (m *Model) indexAboutUsage(sym *symbols.Symbol) { m.aboutOrder = append(m.aboutOrder, target) } m.aboutAnnots[target] = append(m.aboutAnnots[target], a) + if target.Decl != nil { + m.aboutByDecl[target.Decl] = append(m.aboutByDecl[target.Decl], a) + } } } diff --git a/internal/core/semantics/model.go b/internal/core/semantics/model.go index ab6ae5550..d2717c4d5 100644 --- a/internal/core/semantics/model.go +++ b/internal/core/semantics/model.go @@ -71,6 +71,9 @@ type Model struct { filterTypes map[string]*symbols.Symbol annotations map[*symbols.Symbol][]annotation aboutAnnots map[*symbols.Symbol][]annotation + // aboutByDecl keys the same annotations by the declaration of the element + // annotated, reaching them from a re-indexed twin of that symbol. + aboutByDecl map[ast.Node][]annotation // aboutOrder lists aboutAnnots' targets in first-annotation order. aboutOrder []*symbols.Symbol diff --git a/internal/repl/metadata_about_eval_test.go b/internal/repl/metadata_about_eval_test.go new file mode 100644 index 000000000..14826e84d --- /dev/null +++ b/internal/repl/metadata_about_eval_test.go @@ -0,0 +1,42 @@ +package repl + +import ( + "strings" + "testing" +) + +// aboutAnnotatedModel annotates one part inline and from an `about` usage in +// another package, and annotates the package itself. +const aboutAnnotatedModel = `package Probe { + private import ScalarValues::*; + metadata def Safety { attribute level : Integer = 2; } + metadata def Legacy; + part def Vehicle; + part seatBelt : Vehicle { + @Safety { level = 3; } + @Legacy; + } +} +package About { + metadata Probe::Safety about Probe::seatBelt { level = 9; } + metadata Probe::Legacy about Probe; +}` + +// TestEvalMetadataReadsAboutAnnotations requires `.metadata` at the prompt to +// answer the `about`-form annotations too: the prompt evaluates against its own +// scope tree, so reaching them cannot depend on holding the indexed symbol. +func TestEvalMetadataReadsAboutAnnotations(t *testing.T) { + s := NewSession() + submitModel(t, s, aboutAnnotatedModel) + + got := metaOK(t, s, "%eval Probe::seatBelt.metadata") + if n := strings.Count(got, "Instance("); n != 3 { + t.Errorf("seatBelt.metadata = %q, want the two inline annotations and the `about` one", got) + } + if got := metaOK(t, s, "%eval Probe::seatBelt.metadata#(3).level"); !strings.Contains(got, "9") { + t.Errorf("the `about` annotation's level = %q, want the bound 9", got) + } + if got := metaOK(t, s, "%eval Probe.metadata"); strings.Count(got, "Instance(") != 1 { + t.Errorf("Probe.metadata = %q, want the annotation about the package", got) + } +} From db403f9f45779d67dd3fe844bd2188601ab7321b Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 01:15:45 +0000 Subject: [PATCH 03/11] fix(runtime): make a metadata access atomic and refuse a false infinity arm Review found two paths. A metadata access that failed part-way left the objects of the annotations already read registered in the context, so a retried access accumulated unreachable objects; one access now materializes every annotation or none. And the infinity arm arriving as false read as the unbounded value, letting a malformed request execute with a value it never supplied; the arm is the value itself, so only true carries it and false is refused. Co-Authored-By: jason.han --- docs/reference/wire-contract.md | 5 +++- internal/core/runtime/metadata.go | 19 ++++++++----- internal/core/runtime/metadata_test.go | 37 ++++++++++++++++++++++++++ internal/grpc/convert.go | 12 +++++++++ internal/grpc/convert_infinity_test.go | 25 +++++++++++++++++ 5 files changed, 90 insertions(+), 8 deletions(-) diff --git a/docs/reference/wire-contract.md b/docs/reference/wire-contract.md index 821c32590..94340faf3 100644 --- a/docs/reference/wire-contract.md +++ b/docs/reference/wire-contract.md @@ -283,7 +283,10 @@ decode(v): require v.measurementRef.unitTerm when either is present, else an error; require unit or id, else an error; id absent means a composed unit infinity → the language's unbounded sentinel, distinct from a number and from the - string "*"; it compares above every finite number and equals itself + string "*"; it compares above every finite number and equals itself. + The arm is the value itself, so only true carries it: a caller sending + infinity: false, directly or nested, is answered with an error rather + than with the unbounded value anything else → an error: a newer service than this decoder ``` diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go index 84e984c49..16e872283 100644 --- a/internal/core/runtime/metadata.go +++ b/internal/core/runtime/metadata.go @@ -22,15 +22,24 @@ func (ec *EvalContext) evalMetadataAccess(n *ast.MetadataAccessExpr) (Value, err ErrTypeMismatch, ec.ctx.qualifiedSymbolName(sym)) } annotations := ec.ctx.model.ElementMetadataOf(sym) + // One access materializes every annotation or none: an annotation that fails + // leaves behind no object of the ones read before it. + mark := len(ec.ctx.created) values := make([]Value, 0, len(annotations)) for _, annotation := range annotations { val, err := ec.metadataInstance(annotation) if err != nil { + ec.ctx.abandonInstancesSince(mark) return Value{}, err } values = append(values, val) } - return ec.newSequence(values) + seq, err := ec.newSequence(values) + if err != nil { + ec.ctx.abandonInstancesSince(mark) + return Value{}, err + } + return seq, nil } // metadataSubject is the element `ref.metadata` reads the metadata of. A name @@ -70,30 +79,26 @@ func metadataOfAValue(value Value, parts []ast.NameSegment) error { // metadataInstance materializes one annotation as an object of its metadata // type, with the features its body binds set to the values they are bound to; -// the remaining features keep the defaults the type declares. +// the remaining features keep the defaults the type declares. Its caller +// abandons what a failure left created. func (ec *EvalContext) metadataInstance(annotation semantics.ElementMetadata) (Value, error) { ctx := ec.ctx - mark := len(ctx.created) inst, err := ctx.materialize(annotation.Type, 0, nil, "") if err != nil { - ctx.abandonInstancesSince(mark) return Value{}, fmt.Errorf("metadata %s: %w", ctx.qualifiedSymbolName(annotation.Type), err) } body := NewEvalContext(ctx, annotation.Scope) for _, binding := range annotation.Bindings { if fv, held := inst.FeatureValues[binding.Feature]; !held || fv == nil { - ctx.abandonInstancesSince(mark) return Value{}, fmt.Errorf("%w: metadata %s declares no feature %s", ErrTypeMismatch, ctx.qualifiedSymbolName(annotation.Type), binding.Feature) } val, err := body.Eval(binding.Value) if err != nil { - ctx.abandonInstancesSince(mark) return Value{}, fmt.Errorf("metadata %s: %s: %w", ctx.qualifiedSymbolName(annotation.Type), binding.Feature, err) } if err := inst.SetFeatureValue(ctx, binding.Feature, val); err != nil { - ctx.abandonInstancesSince(mark) return Value{}, fmt.Errorf("metadata %s: %w", ctx.qualifiedSymbolName(annotation.Type), err) } } diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go index 4e147a5d1..20fa7a8bd 100644 --- a/internal/core/runtime/metadata_test.go +++ b/internal/core/runtime/metadata_test.go @@ -164,3 +164,40 @@ package test { t.Errorf("error %q, want it to name severity", err) } } + +// TestMetadataAccessFailureAbandonsInstances requires one access to materialize +// every annotation or none: an annotation that fails leaves no object behind of +// the annotations read before it. +func TestMetadataAccessFailureAbandonsInstances(t *testing.T) { + src := ` +package test { + metadata def Safety { + attribute level : ScalarValues::Integer = 2; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + level = 1; + } + @Safety { + severity = 3; + } + } +} +` + ctx, _, err := evalDeclaredExpr(t, src, "test::seatBelt.metadata") + if err == nil { + t.Fatal("the failing annotation succeeded, want a typed error") + } + if !errors.Is(err, ErrTypeMismatch) { + t.Errorf("error %v, want a type mismatch", err) + } + if live := len(ctx.instances); live != 0 { + t.Errorf("%d object(s) outlived the failed access, want none", live) + } + if created := len(ctx.created); created != 0 { + t.Errorf("%d object(s) stay registered as created, want none", created) + } +} diff --git a/internal/grpc/convert.go b/internal/grpc/convert.go index 4e39e188a..2fc094f9a 100644 --- a/internal/grpc/convert.go +++ b/internal/grpc/convert.go @@ -446,6 +446,10 @@ var ( // that a feature value holds no value, which is something to read, not to supply. ErrUnsetNotAccepted = errors.New("unset is not a value a caller can supply") + // ErrInfinityNotAsserted reports the infinity arm arriving as false. The arm + // is the unbounded value itself, so false states no value at all. + ErrInfinityNotAsserted = errors.New("the infinity arm states no value unless it is true") + // ErrArrayDimensionNotPositive reports an array sent with a dimension of no // extent, which Collections::Array declares as dimensions: Positive. ErrArrayDimensionNotPositive = errors.New("array dimension is not positive") @@ -579,6 +583,11 @@ func ProtoToValueIn(pv *pb.Value, idx *symbols.Index, sem *semantics.Model) (run return protoToVectorQuantity(k.VectorQuantity, idx, sem) case *pb.Value_MeasurementRef: return ProtoToMeasurementRef(k.MeasurementRef, idx, sem) + case *pb.Value_Infinity: + if !k.Infinity { + return runtime.Value{}, ErrInfinityNotAsserted + } + return protoToScalar(pv), nil default: return protoToScalar(pv), nil } @@ -1151,6 +1160,9 @@ func protoToScalar(pv *pb.Value) runtime.Value { case *pb.Value_Complex: return runtime.NewComplex(ProtoToComplex(k.Complex)) case *pb.Value_Infinity: + if !k.Infinity { + return runtime.Value{Kind: runtime.ValNull} + } return runtime.Value{Kind: runtime.ValConst, Const: semantics.Value{Kind: semantics.ValInfinity}} default: return runtime.Value{Kind: runtime.ValNull} diff --git a/internal/grpc/convert_infinity_test.go b/internal/grpc/convert_infinity_test.go index 48a9008e6..15a4c1f2f 100644 --- a/internal/grpc/convert_infinity_test.go +++ b/internal/grpc/convert_infinity_test.go @@ -2,6 +2,7 @@ package grpc import ( "context" + "errors" "strings" "testing" @@ -142,3 +143,27 @@ func TestInfinityCapability(t *testing.T) { } } } + +// TestProtoToValueRefusesAFalseInfinityArm refuses the infinity arm sent as +// false, directly and nested: the arm is the unbounded value itself, so false +// states no value and must not be read as one. +func TestProtoToValueRefusesAFalseInfinityArm(t *testing.T) { + false_ := &pb.Value{Kind: &pb.Value_Infinity{Infinity: false}} + for _, tc := range []struct { + name string + sent *pb.Value + }{ + {"directly", false_}, + {"in a sequence", &pb.Value{Kind: &pb.Value_Sequence{Sequence: &pb.ValueSequence{Elements: []*pb.Value{false_}}}}}, + {"in an array", &pb.Value{Kind: &pb.Value_Array{Array: &pb.Array{Dimensions: []int64{1}, Elements: []*pb.Value{false_}}}}}, + } { + t.Run(tc.name, func(t *testing.T) { + if _, err := ProtoToValueIn(tc.sent, nil, nil); !errors.Is(err, ErrInfinityNotAsserted) { + t.Errorf("error %v, want the infinity arm refused", err) + } + }) + } + if got, err := ProtoToValueIn(infinityValue(), nil, nil); err != nil || !got.Const.IsUnbounded() { + t.Errorf("infinity: true read as %v (%v), want the unbounded value", got.Kind, err) + } +} From f43ba47aa4abc331ee21b76ec31f3b84a9aa1469 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 01:21:48 +0000 Subject: [PATCH 04/11] fix(runtime): abandon the behaviors a failed metadata access started A metadata annotation body can read an object whose classifier behavior starts, so abandoning only the objects left that behavior attached to the context, able to run after the object it belongs to is gone. The access now rolls back from the behavior boundary as well. Co-Authored-By: jason.han --- internal/core/runtime/metadata.go | 8 +++--- internal/core/runtime/metadata_test.go | 37 +++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go index 16e872283..d90882932 100644 --- a/internal/core/runtime/metadata.go +++ b/internal/core/runtime/metadata.go @@ -23,20 +23,20 @@ func (ec *EvalContext) evalMetadataAccess(n *ast.MetadataAccessExpr) (Value, err } annotations := ec.ctx.model.ElementMetadataOf(sym) // One access materializes every annotation or none: an annotation that fails - // leaves behind no object of the ones read before it. - mark := len(ec.ctx.created) + // leaves behind no object, and no behavior of one, of the ones read before it. + mark, attached := len(ec.ctx.created), len(ec.ctx.objectBehaviors) values := make([]Value, 0, len(annotations)) for _, annotation := range annotations { val, err := ec.metadataInstance(annotation) if err != nil { - ec.ctx.abandonInstancesSince(mark) + ec.ctx.abandonCreationSince(mark, attached) return Value{}, err } values = append(values, val) } seq, err := ec.newSequence(values) if err != nil { - ec.ctx.abandonInstancesSince(mark) + ec.ctx.abandonCreationSince(mark, attached) return Value{}, err } return seq, nil diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go index 20fa7a8bd..c2cd9a4d5 100644 --- a/internal/core/runtime/metadata_test.go +++ b/internal/core/runtime/metadata_test.go @@ -166,20 +166,38 @@ package test { } // TestMetadataAccessFailureAbandonsInstances requires one access to materialize -// every annotation or none: an annotation that fails leaves no object behind of -// the annotations read before it. +// every annotation or none: an annotation that fails leaves behind no object, +// and no behavior of one, of the annotations read before it. func TestMetadataAccessFailureAbandonsInstances(t *testing.T) { src := ` package test { + part def Controller { + attribute count : ScalarValues::Integer = 0; + exhibit state modes { + entry; then running; + state running { + entry action bump { assign count := count + 1; } + } + } + } + + part ctrl : Controller; + metadata def Safety { attribute level : ScalarValues::Integer = 2; } part def Vehicle; + part reader : Vehicle { + @Safety { + level = ctrl.count; + } + } + part seatBelt : Vehicle { @Safety { - level = 1; + level = ctrl.count; } @Safety { severity = 3; @@ -187,6 +205,16 @@ package test { } } ` + // The first annotation reads an object whose machine runs, so the failing + // access has behaviors as well as objects to abandon. + ok, _, err := evalDeclaredExpr(t, src, "test::reader.metadata") + if err != nil { + t.Fatalf("test::reader.metadata: %v", err) + } + if len(ok.objectBehaviors) == 0 { + t.Fatal("reading the annotation started no behavior, so the test proves nothing") + } + ctx, _, err := evalDeclaredExpr(t, src, "test::seatBelt.metadata") if err == nil { t.Fatal("the failing annotation succeeded, want a typed error") @@ -200,4 +228,7 @@ package test { if created := len(ctx.created); created != 0 { t.Errorf("%d object(s) stay registered as created, want none", created) } + if attached, pending := len(ctx.objectBehaviors), len(ctx.pendingBehaviors); attached != 0 || pending != 0 { + t.Errorf("%d behavior(s) (%d pending) outlived the failed access, want none", attached, pending) + } } From 2645ab757b88ea1094aeaa07dac337e7ae27833f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 04:54:10 +0000 Subject: [PATCH 05/11] fix(runtime): scope metadata bindings, nest them, and type the unbounded value Metadata body values resolve in the body's own scope, nested body declarations bind through the object their feature holds, a ValInfinity constant answers ScalarValues::Positive as its direct type, and every client decoder refuses an infinity arm that is not asserted. Co-Authored-By: jason.han --- .../openmbee/opensysml/internal/Protos.java | 13 ++- .../opensysml/internal/ProtosTest.java | 17 +++ clients/node/src/core/values.ts | 4 + clients/node/test/values.test.ts | 14 +++ clients/python/opensysml/values.py | 4 + clients/python/tests/test_infinity.py | 31 +++++ clients/rust/opensysml/src/domain.rs | 28 ++++- internal/core/runtime/array.go | 1 + internal/core/runtime/eval.go | 6 + internal/core/runtime/infinity_test.go | 26 +++++ internal/core/runtime/metadata.go | 64 +++++++++-- internal/core/runtime/metadata_test.go | 107 ++++++++++++++++++ internal/core/semantics/annotations.go | 41 ++++--- 13 files changed, 327 insertions(+), 29 deletions(-) create mode 100644 clients/python/tests/test_infinity.py diff --git a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/Protos.java b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/Protos.java index 9e347a9dc..093d32821 100644 --- a/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/Protos.java +++ b/clients/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/Protos.java @@ -54,7 +54,7 @@ public static Optional value(org.openmbee.opensysml.proto.Value value) { case QUANTITY -> Optional.of(new Value.QuantityValue(quantity(value.getQuantity()))); case ENUM_LITERAL -> Optional.of(new Value.EnumerationValue(literal(value.getEnumLiteral()))); case UNSET -> Optional.of(new Value.UnsetValue()); - case INFINITY -> Optional.of(new Value.InfinityValue()); + case INFINITY -> Optional.of(infinity(value)); case ARRAY -> Optional.of(array(value.getArray())); case VECTOR -> Optional.of(vector(value.getVector())); case VECTOR_QUANTITY -> Optional.of(vectorQuantity(value.getVectorQuantity())); @@ -63,6 +63,17 @@ public static Optional value(org.openmbee.opensysml.proto.Value value) { }; } + /** Only an asserted arm carries the unbounded value. */ + private static Value infinity(org.openmbee.opensysml.proto.Value value) { + if (!value.getInfinity()) { + throw new TransportException( + "the service answered a malformed value: the infinity arm states no value unless it is" + + " true", + null); + } + return new Value.InfinityValue(); + } + private static Value array(org.openmbee.opensysml.proto.Array array) { List elements = new ArrayList<>(array.getElementsCount()); for (org.openmbee.opensysml.proto.Value element : array.getElementsList()) { diff --git a/clients/java/opensysml-client/src/test/java/org/openmbee/opensysml/internal/ProtosTest.java b/clients/java/opensysml-client/src/test/java/org/openmbee/opensysml/internal/ProtosTest.java index 8c0744413..ca9629e01 100644 --- a/clients/java/opensysml-client/src/test/java/org/openmbee/opensysml/internal/ProtosTest.java +++ b/clients/java/opensysml-client/src/test/java/org/openmbee/opensysml/internal/ProtosTest.java @@ -466,4 +466,21 @@ void anInstanceReadsItsFeatureValuesWholeAndImmutably() { assertTrue(mass.materialized()); assertEquals(Optional.empty(), mass.error()); } + + @Test + void onlyAnAssertedInfinityArmIsTheUnboundedValue() { + org.openmbee.opensysml.proto.Value asserted = + org.openmbee.opensysml.proto.Value.newBuilder().setInfinity(true).build(); + assertEquals(Optional.of(new Value.InfinityValue()), Protos.value(asserted)); + + org.openmbee.opensysml.proto.Value denied = + org.openmbee.opensysml.proto.Value.newBuilder().setInfinity(false).build(); + assertThrows(TransportException.class, () -> Protos.value(denied)); + + org.openmbee.opensysml.proto.Value nested = + org.openmbee.opensysml.proto.Value.newBuilder() + .setSequence(ValueSequence.newBuilder().addElements(denied)) + .build(); + assertThrows(TransportException.class, () -> Protos.value(nested)); + } } diff --git a/clients/node/src/core/values.ts b/clients/node/src/core/values.ts index 873d0b125..39e1684a5 100644 --- a/clients/node/src/core/values.ts +++ b/clients/node/src/core/values.ts @@ -180,6 +180,10 @@ export function decodeValue(value: Value | undefined): SysMLValue { case "unset": return { kind: "unset" }; case "infinity": + // Only an asserted arm carries the unbounded value. + if (kind.value !== true) { + throw new MalformedValueError("the infinity arm states no value unless it is true"); + } return { kind: "infinity" }; case undefined: return { kind: "absent" }; diff --git a/clients/node/test/values.test.ts b/clients/node/test/values.test.ts index 0d01ace11..730177aa7 100644 --- a/clients/node/test/values.test.ts +++ b/clients/node/test/values.test.ts @@ -460,3 +460,17 @@ test("every failure reason has a name", () => { assert.equal(failureCause(FailureReason.WRONG_KIND), "wrong_kind"); assert.equal(failureCause(FailureReason.AMBIGUOUS_SUBJECT), "ambiguous_subject"); }); + +test("only an asserted infinity arm is the unbounded value", () => { + const asserted = create(ValueSchema, { kind: { case: "infinity", value: true } }); + assert.deepEqual(decodeValue(asserted), { kind: "infinity" }); + const denied = create(ValueSchema, { kind: { case: "infinity", value: false } }); + assert.throws(() => decodeValue(denied), MalformedValueError); + const nested = create(ValueSchema, { + kind: { + case: "sequence", + value: create(ValueSequenceSchema, { elements: [denied] }), + }, + }); + assert.throws(() => decodeValue(nested), MalformedValueError); +}); diff --git a/clients/python/opensysml/values.py b/clients/python/opensysml/values.py index 02c9834f0..920e2ba46 100644 --- a/clients/python/opensysml/values.py +++ b/clients/python/opensysml/values.py @@ -746,6 +746,10 @@ def value_to_python(pb_value, resolve_instance=None): if kind == 'unset': return UNSET if kind == 'infinity': + # Only an asserted arm carries the unbounded value. + if not pb_value.infinity: + raise UnsupportedValueError( + "the infinity arm states no value unless it is true") return INFINITY if kind == 'null': # A non-empty null carries the reason the value could not be sent. diff --git a/clients/python/tests/test_infinity.py b/clients/python/tests/test_infinity.py new file mode 100644 index 000000000..f9414ea2b --- /dev/null +++ b/clients/python/tests/test_infinity.py @@ -0,0 +1,31 @@ +"""Tests for the unbounded value ``*`` as a Python value. + +The infinity arm is a boolean, and only ``true`` asserts the value: a ``false`` +arm is malformed transport data rather than an unbounded number. +""" + +import pytest + +from opensysml.errors import UnsupportedValueError +from opensysml.proto import sysml_pb2 +from opensysml.values import INFINITY, value_to_python + + +def test_an_asserted_infinity_arm_is_the_unbounded_value(): + assert value_to_python(sysml_pb2.Value(infinity=True)) is INFINITY + + +def test_a_denied_infinity_arm_is_malformed(): + with pytest.raises(UnsupportedValueError): + value_to_python(sysml_pb2.Value(infinity=False)) + + +def test_a_denied_infinity_arm_nested_in_a_sequence_is_malformed(): + sequence = sysml_pb2.Value( + sequence=sysml_pb2.ValueSequence( + elements=[sysml_pb2.Value(int_value=1), sysml_pb2.Value(infinity=False)] + ) + ) + + with pytest.raises(UnsupportedValueError): + value_to_python(sequence) diff --git a/clients/rust/opensysml/src/domain.rs b/clients/rust/opensysml/src/domain.rs index daae82160..bddc60f7b 100644 --- a/clients/rust/opensysml/src/domain.rs +++ b/clients/rust/opensysml/src/domain.rs @@ -476,7 +476,15 @@ pub(crate) fn value_from_wire(value: wire::Value) -> Result { name: v.name, })), wire::value::Kind::Unset(_) => Ok(Value::Unset), - wire::value::Kind::Infinity(_) => Ok(Value::Infinity), + // Only an asserted arm carries the unbounded value. + wire::value::Kind::Infinity(asserted) => { + if !asserted { + return Err(Error::Decode( + "the infinity arm states no value unless it is true".to_owned(), + )); + } + Ok(Value::Infinity) + } } } @@ -918,6 +926,24 @@ mod tests { ); } + #[test] + fn only_an_asserted_infinity_arm_is_the_unbounded_value() { + let arm = |asserted| wire::Value { + kind: Some(wire::value::Kind::Infinity(asserted)), + }; + assert_eq!(value_from_wire(arm(true)).ok(), Some(Value::Infinity)); + assert!(matches!( + value_from_wire(arm(false)), + Err(Error::Decode(_)) + )); + let nested = wire::Value { + kind: Some(wire::value::Kind::Sequence(wire::ValueSequence { + elements: vec![arm(false)], + })), + }; + assert!(matches!(value_from_wire(nested), Err(Error::Decode(_)))); + } + #[test] fn a_complex_number_prints_in_rectangular_form() { let print = |real, imaginary| Complex { real, imaginary }.to_string(); diff --git a/internal/core/runtime/array.go b/internal/core/runtime/array.go index 184706614..2a1fe2a4f 100644 --- a/internal/core/runtime/array.go +++ b/internal/core/runtime/array.go @@ -241,6 +241,7 @@ const ( cartesianThreeVectorTypeFQN = "VectorValues::CartesianThreeVectorValue" vectorQuantityTypeFQN = "Quantities::VectorQuantityValue" scalarValueTypeFQN = "ScalarValues::ScalarValue" + positiveTypeFQN = "ScalarValues::Positive" ) // structuredFeature reads a library feature of an array, vector, vector, tensor diff --git a/internal/core/runtime/eval.go b/internal/core/runtime/eval.go index 6eb8c2982..5df75b906 100644 --- a/internal/core/runtime/eval.go +++ b/internal/core/runtime/eval.go @@ -1477,6 +1477,12 @@ func (ctx *Context) directValueType(scope *symbols.Scope, value Value) (*symbols name = "Real" case semantics.ValBool: name = "Boolean" + case semantics.ValInfinity: + // `*` is the natural number exceeding every other (KerML 8.4.4.6). + if positive := ctx.librarySymbol(positiveTypeFQN); positive != nil { + return positive, nil + } + return nil, fmt.Errorf("%w: direct type %q", ErrUndeterminedValueType, positiveTypeFQN) default: return nil, fmt.Errorf("%w: %s", ErrUndeterminedValueType, value.Kind) } diff --git a/internal/core/runtime/infinity_test.go b/internal/core/runtime/infinity_test.go index 631571d09..82d80ab36 100644 --- a/internal/core/runtime/infinity_test.go +++ b/internal/core/runtime/infinity_test.go @@ -122,3 +122,29 @@ func TestInfinityArithmeticRefused(t *testing.T) { }) } } + +// TestInfinityDirectType classifies `*` as the Positive it is typed as in +// expression position, and so as a Natural, but as nothing unrelated. +func TestInfinityDirectType(t *testing.T) { + cases := map[string]string{ + "* istype ScalarValues::Positive": "true", + "* hastype ScalarValues::Positive": "true", + "* istype ScalarValues::Natural": "true", + // hastype demands the direct type itself, which Natural is only above. + "* hastype ScalarValues::Natural": "false", + "* istype ScalarValues::String": "false", + "* hastype ScalarValues::Boolean": "false", + "* @ ScalarValues::Positive": "true", + "* @ ScalarValues::String": "false", + } + for expr, want := range cases { + _, got, err := evalDeclaredExpr(t, "package test {}", expr) + if err != nil { + t.Errorf("%s failed: %v", expr, err) + continue + } + if text := FormatValue(got); text != want { + t.Errorf("%s = %s, want %s", expr, text, want) + } + } +} diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go index d90882932..8a17794e8 100644 --- a/internal/core/runtime/metadata.go +++ b/internal/core/runtime/metadata.go @@ -87,20 +87,64 @@ func (ec *EvalContext) metadataInstance(annotation semantics.ElementMetadata) (V if err != nil { return Value{}, fmt.Errorf("metadata %s: %w", ctx.qualifiedSymbolName(annotation.Type), err) } - body := NewEvalContext(ctx, annotation.Scope) - for _, binding := range annotation.Bindings { + if err := ec.bindMetadataFeatures(annotation.Type, inst, annotation.Bindings); err != nil { + return Value{}, err + } + return Value{Kind: ValInstance, Instance: inst.ID}, nil +} + +// bindMetadataFeatures writes the values one body level binds to the object it +// annotates, descending into the object a nested declaration writes through. +func (ec *EvalContext) bindMetadataFeatures(typ *symbols.Symbol, inst *Instance, bindings []semantics.MetadataBinding) error { + ctx := ec.ctx + name := ctx.qualifiedSymbolName(typ) + for _, binding := range bindings { if fv, held := inst.FeatureValues[binding.Feature]; !held || fv == nil { - return Value{}, fmt.Errorf("%w: metadata %s declares no feature %s", - ErrTypeMismatch, ctx.qualifiedSymbolName(annotation.Type), binding.Feature) + return fmt.Errorf("%w: metadata %s declares no feature %s", + ErrTypeMismatch, name, binding.Feature) + } + if binding.Value != nil { + val, err := NewEvalContext(ctx, binding.Scope).Eval(binding.Value) + if err != nil { + return fmt.Errorf("metadata %s: %s: %w", name, binding.Feature, err) + } + if err := inst.SetFeatureValue(ctx, binding.Feature, val); err != nil { + return fmt.Errorf("metadata %s: %w", name, err) + } + } + if len(binding.Nested) == 0 { + continue } - val, err := body.Eval(binding.Value) + nested, err := ec.metadataNestedObject(typ, inst, binding.Feature) if err != nil { - return Value{}, fmt.Errorf("metadata %s: %s: %w", - ctx.qualifiedSymbolName(annotation.Type), binding.Feature, err) + return err } - if err := inst.SetFeatureValue(ctx, binding.Feature, val); err != nil { - return Value{}, fmt.Errorf("metadata %s: %w", ctx.qualifiedSymbolName(annotation.Type), err) + if err := ec.bindMetadataFeatures(typ, nested, binding.Nested); err != nil { + return err } } - return Value{Kind: ValInstance, Instance: inst.ID}, nil + return nil +} + +// metadataNestedObject is the object a nested body level writes through: the one +// the named feature holds, which a feature holding a value rather than an object +// has none of. +func (ec *EvalContext) metadataNestedObject(typ *symbols.Symbol, inst *Instance, feature string) (*Instance, error) { + ctx := ec.ctx + name := ctx.qualifiedSymbolName(typ) + fv, err := inst.GetFeatureValue(ctx, feature) + if err != nil { + return nil, fmt.Errorf("metadata %s: %s: %w", name, feature, err) + } + id, isObject := fv.HeldValue().Object() + if !isObject { + return nil, fmt.Errorf("%w: metadata %s: feature %s holds no object to bind through", + ErrTypeMismatch, name, feature) + } + nested, live := ctx.instances[id] + if !live || nested == nil { + return nil, fmt.Errorf("%w: metadata %s: feature %s holds no object to bind through", + ErrTypeMismatch, name, feature) + } + return nested, nil } diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go index c2cd9a4d5..8affcc57f 100644 --- a/internal/core/runtime/metadata_test.go +++ b/internal/core/runtime/metadata_test.go @@ -232,3 +232,110 @@ package test { t.Errorf("%d behavior(s) (%d pending) outlived the failed access, want none", attached, pending) } } + +// TestMetadataAccessNestedBindings reads an annotation whose body binds a value +// through a nested declaration: the object the outer feature holds carries it. +func TestMetadataAccessNestedBindings(t *testing.T) { + src := ` +package test { + private import ScalarValues::*; + + metadata def Cause { + attribute code : Integer = 0; + } + + metadata def Risk { + attribute level : Integer = 0; + attribute note : String = "none"; + attribute cause : Cause; + } + + metadata def Safety { + attribute risk : Risk; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + risk { + level = 7; + cause { + code = 42; + } + } + } + } +} +` + ctx, got, err := evalDeclaredExpr(t, src, "test::seatBelt.metadata") + if err != nil { + t.Fatalf("seatBelt.metadata failed: %v", err) + } + safety, ok := ctx.getInstance(elementsOf(got)[0].Instance) + if !ok { + t.Fatal("the metadata value is no object") + } + id, isObject := featureValue(t, ctx, safety, "risk").Object() + if !isObject { + t.Fatal("risk holds no object") + } + risk, ok := ctx.getInstance(id) + if !ok { + t.Fatal("the object risk holds is not live") + } + if v := featureValue(t, ctx, risk, "level"); FormatValue(v) != "7" { + t.Errorf("risk.level = %s, want the nested binding 7", FormatValue(v)) + } + if v := featureValue(t, ctx, risk, "note"); FormatValue(v) != `"none"` { + t.Errorf("risk.note = %s, want the declared default", FormatValue(v)) + } + causeID, isObject := featureValue(t, ctx, risk, "cause").Object() + if !isObject { + t.Fatal("cause holds no object") + } + cause, ok := ctx.getInstance(causeID) + if !ok { + t.Fatal("the object cause holds is not live") + } + if v := featureValue(t, ctx, cause, "code"); FormatValue(v) != "42" { + t.Errorf("risk.cause.code = %s, want the nested binding 42", FormatValue(v)) + } +} + +// TestMetadataAccessBindingScope reads a body value naming a feature of the +// metadata type that an element around the annotation also names: the body sees +// the metadata type's own member. +func TestMetadataAccessBindingScope(t *testing.T) { + src := ` +package test { + private import ScalarValues::*; + + attribute limit = 1; + + metadata def Safety { + attribute limit : Integer = 9; + attribute level : Integer = 0; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + level = limit; + } + } +} +` + ctx, got, err := evalDeclaredExpr(t, src, "test::seatBelt.metadata") + if err != nil { + t.Fatalf("seatBelt.metadata failed: %v", err) + } + safety, ok := ctx.getInstance(elementsOf(got)[0].Instance) + if !ok { + t.Fatal("the metadata value is no object") + } + if v := featureValue(t, ctx, safety, "level"); FormatValue(v) != "9" { + t.Errorf("level = %s, want 9, the limit the metadata type declares", FormatValue(v)) + } +} diff --git a/internal/core/semantics/annotations.go b/internal/core/semantics/annotations.go index b45f3c6e5..407d96cf1 100644 --- a/internal/core/semantics/annotations.go +++ b/internal/core/semantics/annotations.go @@ -123,22 +123,23 @@ func (m *Model) AnnotationSitesOf(sym *symbols.Symbol) []AnnotationSite { return out } -// MetadataBinding is one feature an annotation body binds and the expression it -// is bound to, read in the scope the annotation is stated in. +// MetadataBinding is one feature an annotation body binds: the value it is bound +// to, if any, and the bindings its own body nests under it. type MetadataBinding struct { Feature string Value ast.Node + // Scope is where the value resolves names: the body's own scope, which sees + // the metadata type's members before those around the annotated element. + Scope *symbols.Scope + Nested []MetadataBinding } // ElementMetadata is one metadata annotation of an element as `.metadata` reads // it: the metadata type to materialize and the values its body binds. Values // the body leaves unbound come from the type's own declarations. type ElementMetadata struct { - Type *symbols.Symbol - Node ast.Node - // Scope is where the annotating node is declared, which its bound values - // resolve names against. - Scope *symbols.Scope + Type *symbols.Symbol + Node ast.Node About bool Bindings []MetadataBinding } @@ -155,9 +156,8 @@ func (m *Model) ElementMetadataOf(sym *symbols.Symbol) []ElementMetadata { out = append(out, ElementMetadata{ Type: a.typ, Node: a.node, - Scope: a.scope, About: a.about, - Bindings: metadataBindings(metadataBody(a.node)), + Bindings: metadataBindings(valueScope(a.scope, a.node), metadataBody(a.node)), }) } return out @@ -175,22 +175,29 @@ func metadataBody(node ast.Node) []ast.Node { } } -// metadataBindings is the features an annotation body binds, in declaration order. -func metadataBindings(body []ast.Node) []MetadataBinding { +// metadataBindings is the features an annotation body binds, in declaration +// order, each with the bindings its own body states under it. +func metadataBindings(scope *symbols.Scope, body []ast.Node) []MetadataBinding { var out []MetadataBinding for _, member := range body { - if mem, ok := member.(*ast.Membership); ok { - member = mem.Member - } - usage, ok := member.(*ast.Usage) - if !ok || usage.Value == nil { + usage := metadataBodyFeature(member) + if usage == nil { continue } name := boundFeatureName(usage) if name == "" { continue } - out = append(out, MetadataBinding{Feature: name, Value: usage.Value}) + nested := metadataBindings(valueScope(scope, usage), usage.Members) + if usage.Value == nil && len(nested) == 0 { + continue + } + out = append(out, MetadataBinding{ + Feature: name, + Value: usage.Value, + Scope: scope, + Nested: nested, + }) } return out } From 0b78ad5f54f54f9e1231f1995ad688033e2efc8a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 04:56:40 +0000 Subject: [PATCH 06/11] style(clients): satisfy eslint and rustfmt on the infinity arm check Co-Authored-By: jason.han --- clients/node/src/core/values.ts | 2 +- clients/rust/opensysml/src/domain.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/clients/node/src/core/values.ts b/clients/node/src/core/values.ts index 39e1684a5..e1a84e1e6 100644 --- a/clients/node/src/core/values.ts +++ b/clients/node/src/core/values.ts @@ -181,7 +181,7 @@ export function decodeValue(value: Value | undefined): SysMLValue { return { kind: "unset" }; case "infinity": // Only an asserted arm carries the unbounded value. - if (kind.value !== true) { + if (!kind.value) { throw new MalformedValueError("the infinity arm states no value unless it is true"); } return { kind: "infinity" }; diff --git a/clients/rust/opensysml/src/domain.rs b/clients/rust/opensysml/src/domain.rs index bddc60f7b..231ad2635 100644 --- a/clients/rust/opensysml/src/domain.rs +++ b/clients/rust/opensysml/src/domain.rs @@ -932,10 +932,7 @@ mod tests { kind: Some(wire::value::Kind::Infinity(asserted)), }; assert_eq!(value_from_wire(arm(true)).ok(), Some(Value::Infinity)); - assert!(matches!( - value_from_wire(arm(false)), - Err(Error::Decode(_)) - )); + assert!(matches!(value_from_wire(arm(false)), Err(Error::Decode(_)))); let nested = wire::Value { kind: Some(wire::value::Kind::Sequence(wire::ValueSequence { elements: vec![arm(false)], From 347a8fa413bc1764350ced81c3b1e9a584caf569 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 05:09:43 +0000 Subject: [PATCH 07/11] fix(semantics): bind metadata body values through renamed redefinitions A body declaration with a name of its own writes to the feature it redefines, so `severity :>> level = 3` binds level rather than being refused. A body value naming a sibling feature reads it off the object being bound. Co-Authored-By: jason.han --- internal/core/runtime/metadata.go | 3 +- internal/core/runtime/metadata_test.go | 88 ++++++++++++++++++++++++++ internal/core/semantics/annotations.go | 16 ++++- 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go index 8a17794e8..9c04f9404 100644 --- a/internal/core/runtime/metadata.go +++ b/internal/core/runtime/metadata.go @@ -104,7 +104,8 @@ func (ec *EvalContext) bindMetadataFeatures(typ *symbols.Symbol, inst *Instance, ErrTypeMismatch, name, binding.Feature) } if binding.Value != nil { - val, err := NewEvalContext(ctx, binding.Scope).Eval(binding.Value) + // A value naming a sibling feature reads it off the object being bound. + val, err := NewEvalContextIn(ctx, binding.Scope, inst).Eval(binding.Value) if err != nil { return fmt.Errorf("metadata %s: %s: %w", name, binding.Feature, err) } diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go index 8affcc57f..bac7b4c66 100644 --- a/internal/core/runtime/metadata_test.go +++ b/internal/core/runtime/metadata_test.go @@ -339,3 +339,91 @@ package test { t.Errorf("level = %s, want 9, the limit the metadata type declares", FormatValue(v)) } } + +// TestMetadataAccessRenamedRedefinition binds a metadata feature through a +// redefinition that gives it a name of its own, at both body levels. +func TestMetadataAccessRenamedRedefinition(t *testing.T) { + src := ` +package test { + private import ScalarValues::*; + + metadata def Cause { + attribute code : Integer = 0; + } + + metadata def Safety { + attribute level : Integer = 0; + attribute cause : Cause; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + attribute severity :>> level = 3; + cause { + attribute reason :>> code = 42; + } + } + } +} +` + ctx, got, err := evalDeclaredExpr(t, src, "test::seatBelt.metadata") + if err != nil { + t.Fatalf("seatBelt.metadata failed: %v", err) + } + safety, ok := ctx.getInstance(elementsOf(got)[0].Instance) + if !ok { + t.Fatal("the metadata value is no object") + } + if v := featureValue(t, ctx, safety, "level"); FormatValue(v) != "3" { + t.Errorf("level = %s, want the redefining binding 3", FormatValue(v)) + } + id, isObject := featureValue(t, ctx, safety, "cause").Object() + if !isObject { + t.Fatal("cause holds no object") + } + cause, ok := ctx.getInstance(id) + if !ok { + t.Fatal("the object cause holds is not live") + } + if v := featureValue(t, ctx, cause, "code"); FormatValue(v) != "42" { + t.Errorf("cause.code = %s, want the redefining binding 42", FormatValue(v)) + } +} + +// TestMetadataAccessDependentBindings reads a body value naming a feature an +// earlier binding of the same body bound: it reads what was bound, not the +// default the metadata type declares. +func TestMetadataAccessDependentBindings(t *testing.T) { + src := ` +package test { + private import ScalarValues::*; + + metadata def Safety { + attribute level : Integer = 0; + attribute margin : Integer = 0; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + level = 2; + margin = level + 1; + } + } +} +` + ctx, got, err := evalDeclaredExpr(t, src, "test::seatBelt.metadata") + if err != nil { + t.Fatalf("seatBelt.metadata failed: %v", err) + } + safety, ok := ctx.getInstance(elementsOf(got)[0].Instance) + if !ok { + t.Fatal("the metadata value is no object") + } + if v := featureValue(t, ctx, safety, "margin"); FormatValue(v) != "3" { + t.Errorf("margin = %s, want 3, one more than the level bound before it", FormatValue(v)) + } +} diff --git a/internal/core/semantics/annotations.go b/internal/core/semantics/annotations.go index 407d96cf1..7c5041b2e 100644 --- a/internal/core/semantics/annotations.go +++ b/internal/core/semantics/annotations.go @@ -184,7 +184,7 @@ func metadataBindings(scope *symbols.Scope, body []ast.Node) []MetadataBinding { if usage == nil { continue } - name := boundFeatureName(usage) + name := redefinedFeatureName(usage) if name == "" { continue } @@ -491,6 +491,20 @@ func boundFeatureName(u *ast.Usage) string { if u.Ident.Name != "" { return u.Ident.Name } + return redefinitionTargetName(u) +} + +// redefinedFeatureName is the metadata feature a body member writes to: the one +// it redefines, which a name of its own renames rather than replaces. +func redefinedFeatureName(u *ast.Usage) string { + if name := redefinitionTargetName(u); name != "" { + return name + } + return u.Ident.Name +} + +// redefinitionTargetName is the feature a `:>> f` clause names, or "". +func redefinitionTargetName(u *ast.Usage) string { for _, rel := range u.Relationships { if rel == nil || rel.Kind != ast.RelRedefines { continue From 291d18a76f24ba175bc0ba79565da7f4a928b06a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 05:20:04 +0000 Subject: [PATCH 08/11] fix(runtime): read one object per metadata annotation, journaling the access An annotation denotes one object, so a second `elem.metadata` answers what the first made rather than a fresh identity. The access is bracketed by a journal, so a failing annotation also undoes writes made while reading the ones before it, not only the objects and behaviors they left. Co-Authored-By: jason.han --- internal/core/runtime/classifier_behavior.go | 5 +++ internal/core/runtime/context.go | 4 ++ internal/core/runtime/infinity_test.go | 14 +++++-- internal/core/runtime/metadata.go | 25 ++++++++---- internal/core/runtime/metadata_test.go | 43 ++++++++++++++++++++ 5 files changed, 79 insertions(+), 12 deletions(-) diff --git a/internal/core/runtime/classifier_behavior.go b/internal/core/runtime/classifier_behavior.go index 69f9f7a7d..3a138a879 100644 --- a/internal/core/runtime/classifier_behavior.go +++ b/internal/core/runtime/classifier_behavior.go @@ -302,6 +302,11 @@ func (ctx *Context) abandonInstancesBetween(mark, end int) { delete(ctx.occurrences, sym) } } + for node, id := range ctx.metadataObjects { + if _, live := ctx.instances[id]; !live { + delete(ctx.metadataObjects, node) + } + } ctx.forgetLives(abandoned) ctx.forgetVariantsNaming(abandoned) ctx.forgetEdgesOf(gone) diff --git a/internal/core/runtime/context.go b/internal/core/runtime/context.go index 6051e6f63..b9ed8ea32 100644 --- a/internal/core/runtime/context.go +++ b/internal/core/runtime/context.go @@ -108,6 +108,9 @@ type Context struct { // occurrences holds the object each usage carrying no value of its own // denotes, so a feature chain through a part reads one occurrence of it. occurrences map[*symbols.Symbol]int64 + // metadataObjects holds the object each metadata annotation denotes, so + // reading `.metadata` twice reads one object per annotation. + metadataObjects map[ast.Node]int64 // behaving memoizes runsBehaviors per type; the model is fixed for the context's life. behaving map[*symbols.Symbol]bool // behavingFeatures memoizes behavingParts and redefGroups redefinitionGroups, per type. @@ -321,6 +324,7 @@ func NewContext(model *semantics.Model, resolver *resolve.Resolver, maxSteps int maxSweepRuns: DefaultMaxSweepRuns, occurrences: make(map[*symbols.Symbol]int64), + metadataObjects: make(map[ast.Node]int64), behaving: make(map[*symbols.Symbol]bool), behavingFeatures: make(map[*symbols.Symbol][]int), redefGroups: make(map[*symbols.Symbol][][]string), diff --git a/internal/core/runtime/infinity_test.go b/internal/core/runtime/infinity_test.go index 82d80ab36..3e8e0a5d8 100644 --- a/internal/core/runtime/infinity_test.go +++ b/internal/core/runtime/infinity_test.go @@ -7,10 +7,20 @@ import ( "github.com/Open-MBEE/OpenSysML/internal/core/ast" "github.com/Open-MBEE/OpenSysML/internal/core/semantics" + "github.com/Open-MBEE/OpenSysML/internal/core/symbols" ) // evalDeclaredExpr evaluates expr as the value of an attribute declared beside src. func evalDeclaredExpr(t *testing.T, src, expr string) (*Context, Value, error) { + t.Helper() + ctx, scope, decl := declaredExpr(t, src, expr) + got, err := NewEvalContext(ctx, scope).Eval(decl) + return ctx, got, err +} + +// declaredExpr is expr as the value of an attribute declared beside src, with +// the context and scope to evaluate it in, so one context can evaluate it twice. +func declaredExpr(t *testing.T, src, expr string) (*Context, *symbols.Scope, ast.Node) { t.Helper() full := src + "\npackage probe {\n\tattribute result = " + expr + ";\n}" model, resolver, root := parseAndBuildLibraryModel(t, full) @@ -26,9 +36,7 @@ func evalDeclaredExpr(t *testing.T, src, expr string) (*Context, Value, error) { if !ok { t.Fatalf("result declares %T, want a usage", sym.Decl) } - ctx := NewContext(model, resolver, 10000) - got, err := NewEvalContext(ctx, pkg.Scope).Eval(decl.Value) - return ctx, got, err + return NewContext(model, resolver, 10000), pkg.Scope, decl.Value } // TestInfinityValue evaluates `*`: its own scalar value, printed as written. diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go index 9c04f9404..419ad7437 100644 --- a/internal/core/runtime/metadata.go +++ b/internal/core/runtime/metadata.go @@ -22,23 +22,24 @@ func (ec *EvalContext) evalMetadataAccess(n *ast.MetadataAccessExpr) (Value, err ErrTypeMismatch, ec.ctx.qualifiedSymbolName(sym)) } annotations := ec.ctx.model.ElementMetadataOf(sym) - // One access materializes every annotation or none: an annotation that fails - // leaves behind no object, and no behavior of one, of the ones read before it. - mark, attached := len(ec.ctx.created), len(ec.ctx.objectBehaviors) + // One access answers every annotation or none: what a failing one wrote, made + // or started, here or in a behavior it woke, is undone with it. + commit, rollback := ec.ctx.beginJournal() values := make([]Value, 0, len(annotations)) for _, annotation := range annotations { val, err := ec.metadataInstance(annotation) if err != nil { - ec.ctx.abandonCreationSince(mark, attached) + rollback() return Value{}, err } values = append(values, val) } seq, err := ec.newSequence(values) if err != nil { - ec.ctx.abandonCreationSince(mark, attached) + rollback() return Value{}, err } + commit() return seq, nil } @@ -77,12 +78,17 @@ func metadataOfAValue(value Value, parts []ast.NameSegment) error { ErrTypeMismatch, describeValue(value)) } -// metadataInstance materializes one annotation as an object of its metadata -// type, with the features its body binds set to the values they are bound to; -// the remaining features keep the defaults the type declares. Its caller -// abandons what a failure left created. +// metadataInstance is the object one annotation denotes, of its metadata type, +// with the features its body binds set to the values they are bound to and the +// remaining ones keeping the defaults the type declares. One annotation denotes +// one object, so a second read of it answers the object the first made. func (ec *EvalContext) metadataInstance(annotation semantics.ElementMetadata) (Value, error) { ctx := ec.ctx + if id, held := ctx.metadataObjects[annotation.Node]; held { + if _, live := ctx.instances[id]; live { + return Value{Kind: ValInstance, Instance: id}, nil + } + } inst, err := ctx.materialize(annotation.Type, 0, nil, "") if err != nil { return Value{}, fmt.Errorf("metadata %s: %w", ctx.qualifiedSymbolName(annotation.Type), err) @@ -90,6 +96,7 @@ func (ec *EvalContext) metadataInstance(annotation semantics.ElementMetadata) (V if err := ec.bindMetadataFeatures(annotation.Type, inst, annotation.Bindings); err != nil { return Value{}, err } + ctx.metadataObjects[annotation.Node] = inst.ID return Value{Kind: ValInstance, Instance: inst.ID}, nil } diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go index bac7b4c66..199aad4d4 100644 --- a/internal/core/runtime/metadata_test.go +++ b/internal/core/runtime/metadata_test.go @@ -427,3 +427,46 @@ package test { t.Errorf("margin = %s, want 3, one more than the level bound before it", FormatValue(v)) } } + +// TestMetadataAccessSameObjects reads the metadata of one element twice: an +// annotation denotes one object, so both reads answer it and no second object +// of the metadata type is made. +func TestMetadataAccessSameObjects(t *testing.T) { + src := ` +package test { + private import ScalarValues::*; + + metadata def Safety { + attribute level : Integer = 0; + } + + part def Vehicle; + + part seatBelt : Vehicle { + @Safety { + level = 3; + } + } +} +` + ctx, scope, decl := declaredExpr(t, src, "test::seatBelt.metadata") + first, err := NewEvalContext(ctx, scope).Eval(decl) + if err != nil { + t.Fatalf("seatBelt.metadata failed: %v", err) + } + made := len(ctx.instances) + second, err := NewEvalContext(ctx, scope).Eval(decl) + if err != nil { + t.Fatalf("the second seatBelt.metadata failed: %v", err) + } + one, two := elementsOf(first), elementsOf(second) + if len(one) != 1 || len(two) != 1 { + t.Fatalf("read %d then %d metadata values, want one each", len(one), len(two)) + } + if one[0].Instance != two[0].Instance { + t.Errorf("the reads answered objects %d and %d, want one object", one[0].Instance, two[0].Instance) + } + if len(ctx.instances) != made { + t.Errorf("the second read left %d objects, want the %d the first did", len(ctx.instances), made) + } +} From 2ccefd358b201262df492650a281398e531a523d Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 05:27:50 +0000 Subject: [PATCH 09/11] fix(runtime): keep the object an annotation denotes through a reanalysis A metadata annotation is named by the element it annotates and its place among that element's annotations rather than by its syntax node, so a carry-over rebinds it and a later read of a carried metadata object answers that object instead of making a second one. Co-Authored-By: jason.han --- internal/core/runtime/adopt.go | 15 ++++- internal/core/runtime/classifier_behavior.go | 4 +- internal/core/runtime/context.go | 8 ++- internal/core/runtime/metadata.go | 17 +++-- internal/core/runtime/metadata_test.go | 69 ++++++++++++++++++++ 5 files changed, 100 insertions(+), 13 deletions(-) diff --git a/internal/core/runtime/adopt.go b/internal/core/runtime/adopt.go index d38e208c8..061ca5f12 100644 --- a/internal/core/runtime/adopt.go +++ b/internal/core/runtime/adopt.go @@ -953,9 +953,10 @@ func (a *adoption) abandon() { } // carryDerived takes over the state the previous context derived about the -// objects carried over: which usage denotes which occurrence, and which variant -// each of them selected. What a rebound declaration no longer has is dropped, so -// it is derived again rather than kept wrong. +// objects carried over: which usage denotes which occurrence, which annotation +// denotes which object, and which variant each of them selected. What a rebound +// declaration no longer has is dropped, so it is derived again rather than kept +// wrong. func (a *adoption) carryDerived(adopted map[int64]bool) { for sym, id := range a.prev.occurrences { if !adopted[id] { @@ -969,6 +970,14 @@ func (a *adoption) carryDerived(adopted map[int64]bool) { a.ctx.occurrences[found] = id } } + for key, id := range a.prev.metadataObjects { + if !adopted[id] { + continue + } + if element, err := a.rebind(key.element, "the element it annotates"); err == nil { + a.ctx.metadataObjects[metadataAnnotation{element: element, index: key.index}] = id + } + } for key, id := range a.prev.variantObjects { if !adopted[key.owner] || !adopted[id] { continue diff --git a/internal/core/runtime/classifier_behavior.go b/internal/core/runtime/classifier_behavior.go index 3a138a879..c38f467c0 100644 --- a/internal/core/runtime/classifier_behavior.go +++ b/internal/core/runtime/classifier_behavior.go @@ -302,9 +302,9 @@ func (ctx *Context) abandonInstancesBetween(mark, end int) { delete(ctx.occurrences, sym) } } - for node, id := range ctx.metadataObjects { + for annotation, id := range ctx.metadataObjects { if _, live := ctx.instances[id]; !live { - delete(ctx.metadataObjects, node) + delete(ctx.metadataObjects, annotation) } } ctx.forgetLives(abandoned) diff --git a/internal/core/runtime/context.go b/internal/core/runtime/context.go index b9ed8ea32..e3b3a201b 100644 --- a/internal/core/runtime/context.go +++ b/internal/core/runtime/context.go @@ -109,8 +109,10 @@ type Context struct { // denotes, so a feature chain through a part reads one occurrence of it. occurrences map[*symbols.Symbol]int64 // metadataObjects holds the object each metadata annotation denotes, so - // reading `.metadata` twice reads one object per annotation. - metadataObjects map[ast.Node]int64 + // reading `.metadata` twice reads one object per annotation. The annotation + // is named by the element it annotates and its place among that element's + // annotations, so a reanalysis can rebind it. + metadataObjects map[metadataAnnotation]int64 // behaving memoizes runsBehaviors per type; the model is fixed for the context's life. behaving map[*symbols.Symbol]bool // behavingFeatures memoizes behavingParts and redefGroups redefinitionGroups, per type. @@ -324,7 +326,7 @@ func NewContext(model *semantics.Model, resolver *resolve.Resolver, maxSteps int maxSweepRuns: DefaultMaxSweepRuns, occurrences: make(map[*symbols.Symbol]int64), - metadataObjects: make(map[ast.Node]int64), + metadataObjects: make(map[metadataAnnotation]int64), behaving: make(map[*symbols.Symbol]bool), behavingFeatures: make(map[*symbols.Symbol][]int), redefGroups: make(map[*symbols.Symbol][][]string), diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go index 419ad7437..a527ab1ee 100644 --- a/internal/core/runtime/metadata.go +++ b/internal/core/runtime/metadata.go @@ -26,8 +26,8 @@ func (ec *EvalContext) evalMetadataAccess(n *ast.MetadataAccessExpr) (Value, err // or started, here or in a behavior it woke, is undone with it. commit, rollback := ec.ctx.beginJournal() values := make([]Value, 0, len(annotations)) - for _, annotation := range annotations { - val, err := ec.metadataInstance(annotation) + for i, annotation := range annotations { + val, err := ec.metadataInstance(metadataAnnotation{element: sym, index: i}, annotation) if err != nil { rollback() return Value{}, err @@ -78,13 +78,20 @@ func metadataOfAValue(value Value, parts []ast.NameSegment) error { ErrTypeMismatch, describeValue(value)) } +// metadataAnnotation names one annotation of one element: the element it +// annotates and its place among that element's annotations. +type metadataAnnotation struct { + element *symbols.Symbol + index int +} + // metadataInstance is the object one annotation denotes, of its metadata type, // with the features its body binds set to the values they are bound to and the // remaining ones keeping the defaults the type declares. One annotation denotes // one object, so a second read of it answers the object the first made. -func (ec *EvalContext) metadataInstance(annotation semantics.ElementMetadata) (Value, error) { +func (ec *EvalContext) metadataInstance(key metadataAnnotation, annotation semantics.ElementMetadata) (Value, error) { ctx := ec.ctx - if id, held := ctx.metadataObjects[annotation.Node]; held { + if id, held := ctx.metadataObjects[key]; held { if _, live := ctx.instances[id]; live { return Value{Kind: ValInstance, Instance: id}, nil } @@ -96,7 +103,7 @@ func (ec *EvalContext) metadataInstance(annotation semantics.ElementMetadata) (V if err := ec.bindMetadataFeatures(annotation.Type, inst, annotation.Bindings); err != nil { return Value{}, err } - ctx.metadataObjects[annotation.Node] = inst.ID + ctx.metadataObjects[key] = inst.ID return Value{Kind: ValInstance, Instance: inst.ID}, nil } diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go index 199aad4d4..95a1c7110 100644 --- a/internal/core/runtime/metadata_test.go +++ b/internal/core/runtime/metadata_test.go @@ -470,3 +470,72 @@ package test { t.Errorf("the second read left %d objects, want the %d the first did", len(ctx.instances), made) } } + +const adoptMetadataSrc = `package Demo { + metadata def Safety { attribute level = 3; } + part def Vehicle; + part seatBelt : Vehicle { + @Safety { + level = 5; + } + } + part def Holder { attribute mark; } + part def Reader { attribute seen = seatBelt.metadata; } +}` + +// TestAdoptKeepsTheObjectAnAnnotationDenotes carries an object holding what an +// annotation denotes into a re-analysis: the annotation still denotes that +// object there, so reading it again answers it rather than making a second one. +func TestAdoptKeepsTheObjectAnAnnotationDenotes(t *testing.T) { + prev := contextOver(t, adoptMetadataSrc) + reader, err := prev.Instantiate(lookupOne(t, prev.resolver.Index(), "Demo::Reader")) + if err != nil { + t.Fatalf("Instantiate: %v", err) + } + fv, err := reader.GetFeatureValue(prev, "seen") + if err != nil { + t.Fatalf("GetFeatureValue(seen): %v", err) + } + holder, err := prev.Instantiate(lookupOne(t, prev.resolver.Index(), "Demo::Holder")) + if err != nil { + t.Fatalf("Instantiate: %v", err) + } + if err := holder.SetFeatureValue(prev, "mark", fv.Value); err != nil { + t.Fatalf("SetFeatureValue(mark): %v", err) + } + carried := elementsOf(fv.Value) + if len(carried) != 1 { + t.Fatalf("mark holds %d metadata values, want one", len(carried)) + } + shapes := prev.ShapesOf(holder) + + ctx := contextOver(t, adoptMetadataSrc+"\npart def Widget;") + if _, err := ctx.Adopt(prev, shapes, holder); err != nil { + t.Fatalf("Adopt: %v", err) + } + if _, found := ctx.Instance(carried[0].Instance); !found { + t.Fatalf("the metadata object %d was not carried over, so the test proves nothing", + carried[0].Instance) + } + made := len(ctx.instances) + again, err := ctx.Instantiate(lookupOne(t, ctx.resolver.Index(), "Demo::Reader")) + if err != nil { + t.Fatalf("Instantiate after adoption: %v", err) + } + seen, err := again.GetFeatureValue(ctx, "seen") + if err != nil { + t.Fatalf("GetFeatureValue(seen) after adoption: %v", err) + } + read := elementsOf(seen.Value) + if len(read) != 1 { + t.Fatalf("the annotation reads as %d metadata values after adoption, want one", len(read)) + } + if read[0].Instance != carried[0].Instance { + t.Errorf("the annotation denotes object %d after adoption, want the carried %d", + read[0].Instance, carried[0].Instance) + } + if len(ctx.instances) != made+1 { + t.Errorf("reading the annotation again left %d objects, want the %d carried plus the reader", + len(ctx.instances), made) + } +} From 8542b2f53701373bcd2cfa366571e813d65fcc00 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 05:34:48 +0000 Subject: [PATCH 10/11] fix(runtime): carry an annotation's object only while it reads as it read A carry-over compares what the annotation at that place states, type and text, before taking over the object made for it, so an annotation edited, reordered or retyped between analyses is read again rather than answered with a stale object. Co-Authored-By: jason.han --- internal/core/runtime/adopt.go | 12 +++++- internal/core/runtime/metadata.go | 20 +++++++++ internal/core/runtime/metadata_test.go | 60 ++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/internal/core/runtime/adopt.go b/internal/core/runtime/adopt.go index 061ca5f12..5dba76871 100644 --- a/internal/core/runtime/adopt.go +++ b/internal/core/runtime/adopt.go @@ -974,9 +974,17 @@ func (a *adoption) carryDerived(adopted map[int64]bool) { if !adopted[id] { continue } - if element, err := a.rebind(key.element, "the element it annotates"); err == nil { - a.ctx.metadataObjects[metadataAnnotation{element: element, index: key.index}] = id + element, err := a.rebind(key.element, "the element it annotates") + if err != nil { + continue + } + // An annotation denotes the object made for it only while it still reads + // as it read: an edited or reordered one is read again rather than reused. + stated := a.prev.metadataAnnotationDigest(key.element, key.index) + if stated == "" || stated != a.ctx.metadataAnnotationDigest(element, key.index) { + continue } + a.ctx.metadataObjects[metadataAnnotation{element: element, index: key.index}] = id } for key, id := range a.prev.variantObjects { if !adopted[key.owner] || !adopted[id] { diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go index a527ab1ee..c8e383880 100644 --- a/internal/core/runtime/metadata.go +++ b/internal/core/runtime/metadata.go @@ -85,6 +85,26 @@ type metadataAnnotation struct { index int } +// metadataAnnotationDigest renders the annotation at that place as this context +// reads it: its metadata type and the text it states, so an annotation edited, +// reordered or retyped is not taken for the one an object was made for. The +// empty string says this context has no annotation there. +func (ctx *Context) metadataAnnotationDigest(element *symbols.Symbol, index int) string { + if ctx.model == nil || element == nil { + return "" + } + annotations := ctx.model.ElementMetadataOf(element) + if index < 0 || index >= len(annotations) { + return "" + } + annotation := annotations[index] + if annotation.Node == nil { + return "" + } + return ctx.qualifiedSymbolName(annotation.Type) + " " + + ctx.declText(element, annotation.Node.Span()) +} + // metadataInstance is the object one annotation denotes, of its metadata type, // with the features its body binds set to the values they are bound to and the // remaining ones keeping the defaults the type declares. One annotation denotes diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go index 95a1c7110..fef25f772 100644 --- a/internal/core/runtime/metadata_test.go +++ b/internal/core/runtime/metadata_test.go @@ -2,6 +2,7 @@ package runtime import ( "errors" + "fmt" "slices" "strings" "testing" @@ -539,3 +540,62 @@ func TestAdoptKeepsTheObjectAnAnnotationDenotes(t *testing.T) { len(ctx.instances), made) } } + +// TestAdoptReadsAChangedAnnotationAgain edits the annotation body between the +// two analyses: the object made for what it said before does not stand for what +// it says now, so the annotation is read again and answers the new value. +func TestAdoptReadsAChangedAnnotationAgain(t *testing.T) { + prev := contextOver(t, adoptMetadataSrc) + reader, err := prev.Instantiate(lookupOne(t, prev.resolver.Index(), "Demo::Reader")) + if err != nil { + t.Fatalf("Instantiate: %v", err) + } + fv, err := reader.GetFeatureValue(prev, "seen") + if err != nil { + t.Fatalf("GetFeatureValue(seen): %v", err) + } + holder, err := prev.Instantiate(lookupOne(t, prev.resolver.Index(), "Demo::Holder")) + if err != nil { + t.Fatalf("Instantiate: %v", err) + } + if err := holder.SetFeatureValue(prev, "mark", fv.Value); err != nil { + t.Fatalf("SetFeatureValue(mark): %v", err) + } + carried := elementsOf(fv.Value) + if len(carried) != 1 { + t.Fatalf("the annotation reads as %d metadata values, want one", len(carried)) + } + shapes := prev.ShapesOf(holder) + + ctx := contextOver(t, strings.Replace(adoptMetadataSrc, "level = 5", "level = 9", 1)) + if _, err := ctx.Adopt(prev, shapes, holder); err != nil { + t.Fatalf("Adopt: %v", err) + } + again, err := ctx.Instantiate(lookupOne(t, ctx.resolver.Index(), "Demo::Reader")) + if err != nil { + t.Fatalf("Instantiate after adoption: %v", err) + } + seen, err := again.GetFeatureValue(ctx, "seen") + if err != nil { + t.Fatalf("GetFeatureValue(seen) after adoption: %v", err) + } + read := elementsOf(seen.Value) + if len(read) != 1 { + t.Fatalf("the annotation reads as %d metadata values after adoption, want one", len(read)) + } + if read[0].Instance == carried[0].Instance { + t.Fatalf("the edited annotation reused object %d, made for what it said before", + carried[0].Instance) + } + obj, found := ctx.Instance(read[0].Instance) + if !found { + t.Fatalf("the annotation reads as object %d, which the context does not hold", read[0].Instance) + } + level, err := obj.GetFeatureValue(ctx, "level") + if err != nil { + t.Fatalf("GetFeatureValue(level): %v", err) + } + if got := fmt.Sprint(level.Value.Const); !strings.Contains(got, "9") { + t.Errorf("level = %s, want the 9 the annotation states now", got) + } +} From e9f5a7d80a4273dc2c288a52fb98e5e98ca469b8 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 05:41:26 +0000 Subject: [PATCH 11/11] fix(runtime): digest an annotation from the document stating it An `about` annotation is stated away from the element it annotates, so its digest now reads the annotating document rather than the annotated element's, which an edit there did not change and an unrelated edit here did. Co-Authored-By: jason.han --- internal/core/runtime/adopt.go | 6 ++ internal/core/runtime/metadata.go | 6 +- internal/core/runtime/metadata_test.go | 88 ++++++++++++++++++++++++++ internal/core/semantics/annotations.go | 8 ++- 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/internal/core/runtime/adopt.go b/internal/core/runtime/adopt.go index 5dba76871..a2625642c 100644 --- a/internal/core/runtime/adopt.go +++ b/internal/core/runtime/adopt.go @@ -389,6 +389,12 @@ func (ctx *Context) declText(owner *symbols.Symbol, span source.Span) string { if owner != nil { file = owner.DocName } + return ctx.textIn(file, span) +} + +// textIn renders the text the named document wrote at the given span, falling +// back to the span for a document whose text this context was not given. +func (ctx *Context) textIn(file string, span source.Span) string { if sf, ok := ctx.sources[file]; ok && span.End() <= sf.Len() { return strings.Join(strings.Fields(sf.Text(span)), " ") } diff --git a/internal/core/runtime/metadata.go b/internal/core/runtime/metadata.go index c8e383880..5fab69fe5 100644 --- a/internal/core/runtime/metadata.go +++ b/internal/core/runtime/metadata.go @@ -101,8 +101,10 @@ func (ctx *Context) metadataAnnotationDigest(element *symbols.Symbol, index int) if annotation.Node == nil { return "" } - return ctx.qualifiedSymbolName(annotation.Type) + " " + - ctx.declText(element, annotation.Node.Span()) + // An `about` annotation states itself away from the element it annotates, so + // the text comes from the document stating it. + return ctx.qualifiedSymbolName(annotation.Type) + " " + annotation.Doc + " " + + ctx.textIn(annotation.Doc, annotation.Node.Span()) } // metadataInstance is the object one annotation denotes, of its metadata type, diff --git a/internal/core/runtime/metadata_test.go b/internal/core/runtime/metadata_test.go index fef25f772..61c851ff1 100644 --- a/internal/core/runtime/metadata_test.go +++ b/internal/core/runtime/metadata_test.go @@ -6,6 +6,12 @@ import ( "slices" "strings" "testing" + + "github.com/Open-MBEE/OpenSysML/internal/core/parser" + "github.com/Open-MBEE/OpenSysML/internal/core/resolve" + "github.com/Open-MBEE/OpenSysML/internal/core/semantics" + "github.com/Open-MBEE/OpenSysML/internal/core/source" + "github.com/Open-MBEE/OpenSysML/internal/core/symbols" ) const metadataSrc = ` @@ -599,3 +605,85 @@ func TestAdoptReadsAChangedAnnotationAgain(t *testing.T) { t.Errorf("level = %s, want the 9 the annotation states now", got) } } + +// contextOverDocs indexes each named document and gives the context every text, +// so a digest over an annotation reads the document stating it. +func contextOverDocs(t *testing.T, docs [][2]string) *Context { + t.Helper() + idx := symbols.NewIndex() + for _, doc := range docs { + idx.AddDocument(doc[0], parser.New(source.New(doc[0], []byte(doc[1]))).ParseFile()) + } + resolver := resolve.New(idx) + ctx := NewContext(semantics.NewModel(resolver), resolver, 10000) + for _, doc := range docs { + ctx.RegisterSource(source.New(doc[0], []byte(doc[1]))) + } + return ctx +} + +const adoptAboutModel = `package Demo { + metadata def Safety { attribute level = 3; } + part def Vehicle; + part seatBelt : Vehicle; + part def Holder { attribute mark; } + part def Reader { attribute seen = seatBelt.metadata; } +}` + +const adoptAboutNotes = `package Notes { + metadata Demo::Safety about Demo::seatBelt { + level = 5; + } +}` + +// TestAdoptReadsAChangedAboutAnnotationAgain states the annotation away from the +// element it annotates: editing the annotating document is what makes the object +// made for it stale, and editing the annotated element's document does not. +func TestAdoptReadsAChangedAboutAnnotationAgain(t *testing.T) { + read := func(t *testing.T, ctx *Context, obj *Instance) Value { + t.Helper() + fv, err := obj.GetFeatureValue(ctx, "seen") + if err != nil { + t.Fatalf("GetFeatureValue(seen): %v", err) + } + vals := elementsOf(fv.Value) + if len(vals) != 1 { + t.Fatalf("the annotation reads as %d metadata values, want one", len(vals)) + } + return vals[0] + } + carry := func(t *testing.T, model, notes string) (int64, int64) { + t.Helper() + prev := contextOverDocs(t, [][2]string{{"model.sysml", adoptAboutModel}, {"notes.sysml", adoptAboutNotes}}) + reader, err := prev.Instantiate(lookupOne(t, prev.resolver.Index(), "Demo::Reader")) + if err != nil { + t.Fatalf("Instantiate: %v", err) + } + before := read(t, prev, reader) + holder, err := prev.Instantiate(lookupOne(t, prev.resolver.Index(), "Demo::Holder")) + if err != nil { + t.Fatalf("Instantiate: %v", err) + } + if err := holder.SetFeatureValue(prev, "mark", before); err != nil { + t.Fatalf("SetFeatureValue(mark): %v", err) + } + ctx := contextOverDocs(t, [][2]string{{"model.sysml", model}, {"notes.sysml", notes}}) + if _, err := ctx.Adopt(prev, prev.ShapesOf(holder), holder); err != nil { + t.Fatalf("Adopt: %v", err) + } + again, err := ctx.Instantiate(lookupOne(t, ctx.resolver.Index(), "Demo::Reader")) + if err != nil { + t.Fatalf("Instantiate after adoption: %v", err) + } + return before.Instance, read(t, ctx, again).Instance + } + + before, after := carry(t, adoptAboutModel+"\npart def Widget;", adoptAboutNotes) + if before != after { + t.Errorf("an unedited annotation read as object %d, want the %d it denoted", after, before) + } + before, after = carry(t, adoptAboutModel, strings.Replace(adoptAboutNotes, "level = 5", "level = 9", 1)) + if before == after { + t.Errorf("the edited annotation reused object %d, made for what it said before", before) + } +} diff --git a/internal/core/semantics/annotations.go b/internal/core/semantics/annotations.go index 7c5041b2e..333561881 100644 --- a/internal/core/semantics/annotations.go +++ b/internal/core/semantics/annotations.go @@ -138,8 +138,11 @@ type MetadataBinding struct { // it: the metadata type to materialize and the values its body binds. Values // the body leaves unbound come from the type's own declarations. type ElementMetadata struct { - Type *symbols.Symbol - Node ast.Node + Type *symbols.Symbol + Node ast.Node + // Doc is the document stating the annotation, which an `about` form states + // away from the element it annotates. + Doc string About bool Bindings []MetadataBinding } @@ -156,6 +159,7 @@ func (m *Model) ElementMetadataOf(sym *symbols.Symbol) []ElementMetadata { out = append(out, ElementMetadata{ Type: a.typ, Node: a.node, + Doc: symbols.DocNameOf(a.scope), About: a.about, Bindings: metadataBindings(valueScope(a.scope, a.node), metadataBody(a.node)), })