Recursive import qualified name bug

Hi all,

I came across a bug today. Take the following library.sysml:

package Library {
    public import SubLibrary::*;
    
    package SubLibrary {
        action def ActionMeta;
        action actionMetas[*] : ActionMeta;
        metadata def actionMeta :> Metaobjects::SemanticMetadata {
            :> annotatedElement : SysML::ActionUsage;
            :>> baseType = actionMetas meta SysML::ActionUsage;
        }
    }
}

So then as a user you shouldn’t care that SubLibrary exists, you can just use #actionMeta right away. For example, the following should be fine:

package Model {
    private import Library::*;

    part thePart {
        #actionMeta references theAction;
    }

    action theAction;
}

However, when I try to recreate this using Syside Automator using this script:

import syside

model, _ = syside.load_model(['library.sysml'])
for node in model.nodes(syside.MetadataDefinition, include_subtypes=True):
    if node.name == 'actionMeta':
        action_meta_def = node
        library_package = action_meta_def.owner.owner
        assert library_package.name == 'Library'
        break
else:
    raise RuntimeError('actionMeta not found!')

new_doc = syside.Document.create_st(
    syside.DocumentOptions(url=syside.Url('memory://new_doc.sysml'), language='sysml'))
model.documents.append(new_doc)

with model.documents[-1].lock() as doc:
    root_node = doc.root_node

    # Create package
    package: syside.Package
    _, package = root_node.children.append(syside.OwningMembership, syside.Package)
    package.declared_name = 'ModelFromScratch'

    # Add import
    package.children.insert(0, syside.NamespaceImport, library_package)

    # Create part
    _, part = package.children.append(syside.OwningMembership, syside.PartUsage)
    part.declared_name = 'thePart'

    # Create action
    _, action = package.children.append(syside.OwningMembership, syside.ActionUsage)
    action.declared_name = 'theAction'

    # Create reference to action in part
    _, ref_action = part.children.append(syside.OwningMembership, syside.Usage)
    ref_action.heritage.append(syside.ReferenceSubsetting, action)

    # Set prefix annotation
    _, annotation = ref_action.prefixes.append(syside.OwningMembership, syside.MetadataUsage)
    annotation.heritage.append(syside.FeatureTyping, action_meta_def)

    # Print and write to SysML
    printer_config = syside.PrinterConfig(line_width=80, tab_width=2)
    printer = syside.ModelPrinter.sysml()
    output = syside.pprint(root_node, printer, printer_config)
    print(output)

    with open('created_model.sysml', 'wb') as fp:
        fp.write(output.encode('utf-8'))

model, _ = syside.load_model(['library.sysml', 'created_model.sysml'])
with model.documents[-1].lock() as doc:
    printer_config = syside.PrinterConfig(line_width=80, tab_width=2)
    printer = syside.ModelPrinter.sysml()
    print(syside.pprint(doc.root_node, printer, printer_config))

It outputs the following model:

package ModelFromScratch {
  private import Library::*;
  part thePart { #SubLibrary::actionMeta ::> theAction; }
  action theAction;
}

And I get errors when loading it:

created_model.sysml:3:29: error (parsing-error): Unexpected token '::'.
created_model.sysml:3:18: error (metadata-feature-metaclass): Metadata feature must be typed by exactly one metaclass
created_model.sysml:3:19: error (reference-error): Expected Type element but found Package (Library::SubLibrary)

It seems that Syside Automator does not expect a fully qualified name to be used as an annotation (however I thought that was ok?).
But most importantly, it doesn’t recognize the fact that by importing Library I’m also importing everything in SubLibrary so that doesn’t have to be written in the output in the first place.

Is there any way to solve this currently or does this need a more sophisticated by Automator to check which parts of the qualified name need to be printed?

Greetings,
Jasper

Thanks for the report.

#SubLibrary::actionMeta ::> theAction;

failing to parse is indeed a parser (rather, grammar) bug.

But most importantly, it doesn’t recognize the fact that by importing Library I’m also importing everything in SubLibrary so that doesn’t have to be written in the output in the first place.

Synthetic reference printer is limited as-is. There are some edge-cases handled, like shortening qualified names via inheritance, and owned imports in ancestor scopes. In this case, transitive imports are not handled.

Is there any way to solve this currently or does this need a more sophisticated by Automator to check which parts of the qualified name need to be printed?

Add a namespace import to Sublibrary in any of the ancestor namespaces.

Hi Daumantas,

Right, but transitive imports are handled by the loader (and parser in VScode, which is I guess the same), so it’s only natural to assume that also the writer would handle it.

Anyway, I tried adding a namespace import as you suggested like so:

package Library {
    public import SubLibrary;
    public import SubLibrary::*;

    package SubLibrary {
        action def ActionMeta;
        action actionMetas[*] : ActionMeta;
        metadata def actionMeta :> Metaobjects::SemanticMetadata {
            :> annotatedElement : SysML::ActionUsage;
            :>> baseType = actionMetas meta SysML::ActionUsage;
        }
    }
}

But I still get exactly the same errors.

Greetings,
Jasper

Sorry, I meant in the generated model:

package Model {
    private import Library::SubLibrary::*;

    part thePart {
        #actionMeta references theAction;
    }

    action theAction;
}

Right, but transitive imports are handled by the loader (and parser in VScode, which is I guess the same), so it’s only natural to assume that also the writer would handle it.

Only looks like it. Resolver only needs to visit nodes in a graph looking for a single matching name. Printer needs to look for any ancestors of the referenced element while also checking that the name is reachable. Maybe in the future.

Hi Daumantas,

Ah ok that looks like a solution for now indeed, but in the future it would be nice if this is supported better then :slight_smile:

Thank you!

Greetings,
Jasper

Fixed for v0.8.3 most likely.

1 Like