Class implements Interface error check
General Pattern
We need a way to expres that a class implementing an interface should implement all the methods required by the interface.
interface I{ public void foo(); } class A implements I{ }There should be an error on
A: The typeAmust implement the inherited abstract methodI.foo()This pattern surfaces with required attributes in entities.
model entity X{ i : Int j : String } data X x{ i = 3 }This should give an error on
x:x.jshould be set.Solution (Tasks)
For classes implementing interface the solution will be along the lines of.
- match on the
Class(name, _, implementsInterfaces, _, methods)- resolve
interfacetointeface uriby looking at the Use(Def(…)) =>/ ClassOrInterface:"I"#0 /- get all
method urisinsideinterface uri=>[ / ClassOrInterface:"I"#0 / Method:"foo"#0 / , ... ]- get all
method urisinsideself=>[ ... ]- use stratego to find missing, and if there are give error on
nameHowever this only works if the thing matched on defines stuff in the index.
The entity instantiation does not define the attributes(fields) inside the entity. So in that case step 4 does not apply and one compares the
methodsin ‘Class(…)’ directly with themethod uris.Solution (TS and NaBL)
…
Submitted by Daco Harkes on 13 March 2014 at 13:39
Issue Log
You can do some of this with existing tasks, which we typically use for content completion. These tasks will give you all definitions in a scope, for example all methods of an interface or all methods of the class. There is also a task which turns the results of another task into a list as a single result, but this might not even be needed. The comparison is the issue here. Maybe you can come up with a new task for this. This task should be a combinator and should take two parameters
s1ands2. It should result ins1 \ s2. When this task has no results, everything is fine in your example.
One more problem is that properties of definitions also need to be taken into account. In Java we need to compare the signature of methods, not their names.
This is probably related to the solution for disambiguation/filtering then. But for Daco’s use case, a difference task should be sufficient. BTW, there is already a
Difftask, what does exactly what I described.
A possible syntax:
t@ClassDec(m*, c, SuperDec(sc), _) :- where not m* contains Abstract() and foreach Method m with modifiers Abstract() in definition of sc where m has parameter-types p-ty* and surrounding Type contains Method m with parameter-types p-ty* without modifiers Abstract() else error "Non-abstract class must implement all inherited abstract methods" on t
The “contains all of something” has been generalized to a stratego implementation.
Interface:
ContainsAll( namespace of which all should be present, filter on properties of elements in the namespace, function that succeeds for element which should contain all items, function that gets the definition for this element, function that gets all uses in the element, function that gets the element name (for error reporting) )Use:
rules // check if entities have all the required attributes and roles assigned contains-all-errors = ![ ContainsAll( NablNsAttribute(), [ (NablProp_derivation-type(), Normal()), (NablProp_multiplicity(), One()) ], "ei-a1", "ei-a2", "ei-a3", "ei-a4" ), ContainsAll( NablNsRole(), [], "ei-r1", "ei-r2", "ei-r3", "ei-r4" ) ] eval(|f) = where("ei-a1":=f); is-entityinstance eval(|f) = where("ei-a2":=f); entityinstance-get-type eval(|f) = where("ei-a3":=f); entityinstance-get-attrvalues;map(attributevalue-get-attr) eval(|f) = where("ei-a4":=f); entityinstance-get-name eval(|f) = where("ei-r1":=f); is-entityinstance eval(|f) = where("ei-r2":=f); entityinstance-get-type eval(|f) = where("ei-r3":=f); entityinstance-get-rolevalues;map(rolevalue-get-role) eval(|f) = where("ei-r4":=f); entityinstance-get-nameImplementation:
rules // api for checking something contains all of def // interface implemented by language contains-all-errors = fail eval(|f) = fail nabl-constraint(|ctx): a -> <fail> with contains-all-errors;map(try(nabl-constraint(|ctx, a))) nabl-constraint(|ctx, a): f -> <id> where ContainsAll( def-child-ns, filters, f-on, f-def-of, f-ast-children, f-msg-on ) := f where <eval(|f-on)>a with a-ty := <eval(|f-def-of)>a; a-ty-def := <_nabl-create-collectdefs(|ctx)> a-ty; [a-ty-def-children] := <_nabl-resolve-all-tasks(|ctx, def-child-ns, [])> [a-ty-def]; a-children := <eval(|f-ast-children)>a; a-children-defs := <map(_nabl-create-collectdefs(|ctx));_task-create-combine(|ctx)>a-children; diff := <_task-create-diff(|ctx)> (a-ty-def-children, a-children-defs); diff-filtered := <filter-propconstraints(|ctx,filters)>diff; a-msg-on := <eval(|f-msg-on)>a; msg := ["Provide all required ", <_pp-ns>def-child-ns, "s: ", diff-filtered]; <_task-create-error-on-success(|ctx, diff-filtered, msg)> a-msg-on filter-propconstraints(|ctx, filters) = where(!(filters, []);equal);id filter-propconstraints(|ctx, filters): def-list -> def-list-filtered-rec where !(filters, []);not(equal) with [filter|filters-tail] := filters; (nablprop, propvalue) := filter; def-list-filtered := <_nabl-create-propconstraint(|ctx, nablprop, def-list)> propvalue; def-list-filtered-rec := <filter-propconstraints(|ctx, filters-tail)>def-list-filtered
Log in to post comments