Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- The semantic model's most involved derivations are split into one helper per concern with no change to what they derive: the parameter tables of `structureParameterTable`, `structureBehaviorGenerals` and `structureImplicitParameterRedefinitions` (`internal/semantic/metamodel`), the feature-chain, type-operand and expression readings of `ReflectiveElements`, the per-metaclass ends of `implicitRelationshipElements`, the direction reading of `implicitParameterTargets` and the family rules of `familyNestedFQN` (`internal/semantic/semantics`).
229 changes: 143 additions & 86 deletions internal/semantic/metamodel/structure_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,18 @@ func (e *Evaluator) structureBehaviorGenerals(owner Element) ([]Element, bool) {
if !ok {
return nil, false
}
for _, base := range impliedFeatures {
generals, ok = e.structureImpliedBaseBehaviors(impliedFeatures, nested)
if !ok {
return nil, false
}
return uniqueStructureElements(generals, e.options.Structure), true
}

// structureImpliedBaseBehaviors is the behaviors typing the implied base features, the one
// named by the nested subsetting FQN excepted.
func (e *Evaluator) structureImpliedBaseBehaviors(bases []Element, nested string) ([]Element, bool) {
var generals []Element
for _, base := range bases {
symbol := e.structureElementSymbol(base)
if symbol == nil || (nested != "" && e.model.QualifiedNameOf(symbol) == nested) {
continue
Expand All @@ -102,25 +113,14 @@ func (e *Evaluator) structureBehaviorGenerals(owner Element) ([]Element, bool) {
}
}
}
return uniqueStructureElements(generals, e.options.Structure), true
return generals, true
}

// structureParameterTable mirrors the semantic parameter table: owner's own positional
// parameters, then what each general leaves unclaimed by clause or position, and the result.
func (e *Evaluator) structureParameterTable(owner Element, visiting map[ElementKey]bool) ([]structureParameter, *structureParameter, bool) {
if symbol := e.structureElementSymbol(owner); symbol != nil && !e.structureKnows(owner) {
var positional []structureParameter
for i := 0; ; i++ {
sym, direction := e.model.PositionalParameter(symbol, i, false)
if sym == nil {
break
}
positional = append(positional, structureParameter{ElementOf(sym), direction})
}
var result *structureParameter
if sym, direction := e.model.PositionalParameter(symbol, 0, true); sym != nil {
result = &structureParameter{ElementOf(sym), direction}
}
positional, result := e.structureSymbolParameters(symbol)
return positional, result, true
}
if visiting[owner.Key()] {
Expand All @@ -133,9 +133,67 @@ func (e *Evaluator) structureParameterTable(owner Element, visiting map[ElementK
if !handled || !ok {
return nil, nil, false
}
positional, result, ok := e.structureOwnedParameters(owner, owned.Values)
if !ok {
return nil, nil, false
}
generals, ok := e.structureBehaviorGenerals(owner)
if !ok {
return nil, nil, false
}
declared := positional
for _, general := range generals {
inherited, inheritedResult, ok := e.structureParameterTable(general, visiting)
if !ok {
return nil, nil, false
}
claimed, ok := e.structureClaimedParameters(declared, result, inherited, inheritedResult)
if !ok {
return nil, nil, false
}
for _, p := range inherited {
if claimed[p.element.Key()] {
continue
}
listed, ok := e.structureListsParameter(positional[len(declared):], p.element)
if !ok {
return nil, nil, false
}
if !listed {
positional = append(positional, p)
}
}
if result == nil && inheritedResult != nil && !claimed[inheritedResult.element.Key()] {
result = inheritedResult
}
}
return positional, result, true
}

// structureSymbolParameters is the semantic model's parameter table of a symbol-backed owner:
// its positional parameters in order, and its result parameter.
func (e *Evaluator) structureSymbolParameters(symbol *symbols.Symbol) ([]structureParameter, *structureParameter) {
var positional []structureParameter
for i := 0; ; i++ {
sym, direction := e.model.PositionalParameter(symbol, i, false)
if sym == nil {
break
}
positional = append(positional, structureParameter{ElementOf(sym), direction})
}
var result *structureParameter
for _, value := range owned.Values {
if sym, direction := e.model.PositionalParameter(symbol, 0, true); sym != nil {
result = &structureParameter{ElementOf(sym), direction}
}
return positional, result
}

// structureOwnedParameters is the directed features among owner's owned features: the
// positional ones in order, and the first result parameter.
func (e *Evaluator) structureOwnedParameters(owner Element, owned []Value) ([]structureParameter, *structureParameter, bool) {
var positional []structureParameter
var result *structureParameter
for _, value := range owned {
if value.Kind != ElementValue {
return nil, nil, false
}
Expand All @@ -159,61 +217,41 @@ func (e *Evaluator) structureParameterTable(owner Element, visiting map[ElementK
}
positional = append(positional, p)
}
generals, ok := e.structureBehaviorGenerals(owner)
if !ok {
return nil, nil, false
}
declared := positional
for _, general := range generals {
inherited, inheritedResult, ok := e.structureParameterTable(general, visiting)
return positional, result, true
}

// structureClaimedParameters is the set of a general's parameters the declared ones claim:
// by redefinition clause, else by position with an agreeing direction; the result by its role.
func (e *Evaluator) structureClaimedParameters(declared []structureParameter, result *structureParameter, inherited []structureParameter, inheritedResult *structureParameter) (map[ElementKey]bool, bool) {
claimed := make(map[ElementKey]bool)
for i, p := range declared {
explicit, ok := e.structureRedefinitionTargets(p.element)
if !ok {
return nil, nil, false
}
claimed := make(map[ElementKey]bool)
for i, p := range declared {
explicit, ok := e.structureRedefinitionTargets(p.element)
if !ok {
return nil, nil, false
}
if len(explicit) > 0 {
for _, target := range explicit {
claimed[target.Key()] = true
}
continue
}
if i < len(inherited) && inherited[i].direction == p.direction {
claimed[inherited[i].element.Key()] = true
}
return nil, false
}
if result != nil {
explicit, ok := e.structureRedefinitionTargets(result.element)
if !ok {
return nil, nil, false
}
if len(explicit) > 0 {
for _, target := range explicit {
claimed[target.Key()] = true
}
if inheritedResult != nil {
claimed[inheritedResult.element.Key()] = true
}
continue
}
for _, p := range inherited {
if claimed[p.element.Key()] {
continue
}
listed, ok := e.structureListsParameter(positional[len(declared):], p.element)
if !ok {
return nil, nil, false
}
if !listed {
positional = append(positional, p)
}
if i < len(inherited) && inherited[i].direction == p.direction {
claimed[inherited[i].element.Key()] = true
}
if result == nil && inheritedResult != nil && !claimed[inheritedResult.element.Key()] {
result = inheritedResult
}
if result != nil {
explicit, ok := e.structureRedefinitionTargets(result.element)
if !ok {
return nil, false
}
for _, target := range explicit {
claimed[target.Key()] = true
}
if inheritedResult != nil {
claimed[inheritedResult.element.Key()] = true
}
}
return positional, result, true
return claimed, true
}

// structureListsParameter reports whether the parameters inherited so far carry feature, as
Expand Down Expand Up @@ -264,25 +302,14 @@ func (e *Evaluator) structureImplicitParameterRedefinitions(feature Element, mat
}
return elementsOf(e.model.MaskedParameterRedefinitions(symbol)), true
}
owner, handled, ok := e.structureOwningType(feature)
if !handled || !ok {
return nil, false
}
if owner.Kind != ElementValue {
return nil, true
}
isBehavior, known := e.isMetaclass(owner.Element, "Behavior")
if !known {
return nil, false
}
isStep, known := e.isMetaclass(owner.Element, "Step")
if !known {
owner, behaviorLike, ok := e.structureBehaviorOwner(feature)
if !ok {
return nil, false
}
if !isBehavior && !isStep {
if !behaviorLike {
return nil, true
}
direction, ok := e.structureEffectiveDirection(owner.Element, feature)
direction, ok := e.structureEffectiveDirection(owner, feature)
if !ok {
return nil, false
}
Expand All @@ -295,31 +322,24 @@ func (e *Evaluator) structureImplicitParameterRedefinitions(feature Element, mat
}
position := -1
if !isResult {
position, ok = e.structureParameterPosition(owner.Element, feature)
position, ok = e.structureParameterPosition(owner, feature)
if !ok {
return nil, false
}
if position < 0 {
return nil, true
}
}
generals, ok := e.structureBehaviorGenerals(owner.Element)
generals, ok := e.structureBehaviorGenerals(owner)
if !ok {
return nil, false
}
var out []Element
for _, general := range generals {
positional, result, ok := e.structureParameterTable(general, make(map[ElementKey]bool))
target, ok := e.structureParameterAt(general, position, isResult)
if !ok {
return nil, false
}
target := result
if !isResult {
target = nil
if position < len(positional) {
target = &positional[position]
}
}
if target == nil || target.element.Key() == feature.Key() {
continue
}
Expand All @@ -331,6 +351,43 @@ func (e *Evaluator) structureImplicitParameterRedefinitions(feature Element, mat
return out, true
}

// structureBehaviorOwner is the type owning feature; behaviorLike reports whether it is a
// Behavior or a Step, false too when feature has no owning type element.
func (e *Evaluator) structureBehaviorOwner(feature Element) (owner Element, behaviorLike, ok bool) {
owning, handled, ok := e.structureOwningType(feature)
if !handled || !ok {
return Element{}, false, false
}
if owning.Kind != ElementValue {
return Element{}, false, true
}
isBehavior, known := e.isMetaclass(owning.Element, "Behavior")
if !known {
return Element{}, false, false
}
isStep, known := e.isMetaclass(owning.Element, "Step")
if !known {
return Element{}, false, false
}
return owning.Element, isBehavior || isStep, true
}

// structureParameterAt is general's result parameter, or the one at position, nil when it
// has none there.
func (e *Evaluator) structureParameterAt(general Element, position int, isResult bool) (*structureParameter, bool) {
positional, result, ok := e.structureParameterTable(general, make(map[ElementKey]bool))
if !ok {
return nil, false
}
if isResult {
return result, true
}
if position < len(positional) {
return &positional[position], true
}
return nil, true
}

// structureMaskedParameterRedefinitions is what a parameter without a clause masks for its
// owner: the general parameters at its position whatever their direction, as the semantic masking.
func (e *Evaluator) structureMaskedParameterRedefinitions(feature Element) ([]Element, bool) {
Expand Down
Loading
Loading