Skip to content

Resolve an MCOS object nested in a struct field or cell element - #65

Merged
ww-mw merged 1 commit into
mainfrom
nested-mcos-objects
Oct 9, 2026
Merged

ww-mw merged 1 commit into
mainfrom
nested-mcos-objects

Conversation

@ww-mw

@ww-mw ww-mw commented Oct 9, 2026

Copy link
Copy Markdown
Member

An MCOS object saved inside a struct field, a struct-array element or a cell element of a .mat file or a model workspace now becomes the node the same object gets at the top level. Until now it was never decoded:

Where Before After
strings_nested.mat mixStruct.p <1x1 Simulink.Parameter>, no children Parameter node, Value 7
strings_nested.mat mixStruct.s <1x1 string> "inStruct"
strings_nested.mat mixCell{2} <1x1 string> "inCell"

How

  • Parser. Every class-17 element carries its own object handle as its fourth part. parseOpaque now keeps it: integer storage only, read in stored order (as MATLAB reads it), and bounded to its own part and its container. A malformed handle is recorded as refused, and the variable degrades exactly as before.
  • Decoder. decodeMcosVariables resolves every opaque in a file, at any depth, against the one shared MCOS heap in a single pass, keyed by variable rather than by name. The existing range and class-match checks are unchanged. decodeMcosBlob keeps its by-name contract as a wrapper.
  • Containers. MatNode and ModelNode attach the results in a side table (mcosDecodedTable.ts, a WeakMap), so the parsed variables themselves are untouched.
  • Nodes. parseMatVariable's opaque arm, the one dispatch every nested value goes through, builds a resolved object with modelOpaqueMcosVariable, the factory top-level objects use, through NodeRegistry, so no module-load cycle is added.

Unchanged on purpose

  • A cell's one-line summary and its Variable Editor grid still spell an object element as <1x1 Class>. Across 93 files, every container summary and cell grid is unchanged.
  • A decoded object in a MAT struct field refuses a rename, like its sibling fields (fixesChildNames). This changes 11 nodes in .mat files and models and 0 in dictionaries.
  • .sldd handling is untouched. -v7.3 stays refused.

Tests

  • New fixtures written by MATLAB R2027a: test/fixtures/mcos/nested_objects.mat and nested_ws.slx, generated by make_nested_fixtures.m, with MATLAB's answers in two truth files.
    • They cover nested objects in struct fields at two depths, a struct array, cells and cells of cells, object arrays, and strings (scalar, array, empty, missing), plus a model workspace.
    • Each nested object is graded against a separately built top-level twin, recursively through every child row, and against MATLAB's recorded values.
  • test/nestedMcos.test.ts covers the parser, the decoder, the hand-built malformed handles, and the handle read order against MATLAB.
  • test/matStringOpaque.test.ts's nested-string pins are flipped deliberately.
  • Every part of the change is pinned by a test that fails when that part is reverted (deliberate mutations, files restored byte-identically).

npm run verify is green: typecheck, build, smoke, 5,417 tests passed, 0 failed, check:pack, check:leak, check:browser.

An MCOS object saved inside a struct field, a struct-array element or a cell
element of a .mat file or a model workspace now becomes the node the same object
gets at the top level. A nested Simulink.Parameter is a Parameter node with its
Value and properties, a nested string shows its text, and a nested Bus lists its
elements. Until now such an object was never decoded, and showed as
<1x1 Simulink.Parameter> or <1x1 string> with nothing under it.

Every class-17 element carries its own object handle as its fourth part. The
parser now keeps that handle: integer storage only, read in stored order, and
bounded to its own part and its container. The decoder resolves every opaque in
a file against the one shared MCOS heap in a single pass, keyed by variable
rather than by name, and keeps the results in a side table rather than on the
parsed variables. parseMatVariable's opaque arm builds a resolved object through
the same factory top-level objects use, reached through NodeRegistry so that no
module-load cycle is added. An object that cannot be resolved stays exactly as
it was.

Unchanged on purpose: a cell's one-line summary and its grid still spell an
object element as <1x1 Class>, and a decoded object in a MAT struct field refuses
a rename, as its sibling fields do. .sldd handling is untouched.

The fixtures are written by MATLAB R2027a: test/fixtures/mcos/nested_objects.mat
and nested_ws.slx, generated by make_nested_fixtures.m, with MATLAB's answers in
two truth files. Each nested object is graded against a separately built
top-level twin and against MATLAB's recorded values.
@ww-mw
ww-mw merged commit e4f557b into main Oct 9, 2026
4 checks passed
@ww-mw
ww-mw deleted the nested-mcos-objects branch October 9, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant