The Weaver is a meta-programming tool. It is given instructions (from various sources) about how to arrange fragments of Javacode, executes the instructions, and outputs the finished code.
+-------+
*.cd, *.beh -> |DemJava| --+
+-------+ |
|
+-------+ +---------> +-------+
*.cool -> | Cool | --- *.wvr --> |Weaver | -> *.java
+-------+ +---------> +-------+
|
+-------+ |
*.ridl -> | Ridl | --+
+-------+
The format of a weaver file is:
Weaver ::= Aspect ":" List(CodeFrag) *EOF* . Aspect ::= Ident .
The Weaver needs to know which aspect each file relates to in order to decide the order the weaving gets done. For example, Ridl's weaving should happen after Cool's so that the objects being coordinated are all local. (The last aspect woven has the highest priority.)
There are nine weaver commands:
CodeFrag ::= PackageSpec
| ImportStatement
| AddClass
| AddInterface
| AddAttribute
| AugmentMethod
| ImplementInterface
| RenameMethod
| VarAssignment .
The syntax described in this chapter is a more readable version of the grammar you can find in weaver.cd.
AddClass and AddInterface are the most basic weaving commands. If you had full knowledge of how the target code should look, these would be the only two commands you would need (except for maybe ImportStatement). The syntax of AddClass is:
AddClass ::= "add:" [FixVisibility] [FixModifiers] "class" Ident
["extends" DotList(Ident)]
["implements" CommaList(DotList(Ident))]
["package" Pack]
"{" List(ClassPart) "}" .
ClassPart ::= ParsableClassPart | <javacode> Text .
ParsableClassPart ::= ClassMethod | ClassField .
ClassMethod ::= [Visibility] [Modifiers] MemberType <name> Ident
"(" [CommaList(Argument)] ")"
["throws" CommaList(DotList(Ident))]
MethodBody .
ClassField ::= [Visibility] [Modifiers]
DataType <name> Ident [SquareBarckets]
ClassFieldTrailer .
ClassFieldTrailer ::= "=" JavaCode | ";" .
Visibility ::= FixVisibility | VarVisibility .
VarVisibility ::= "visibility:" VarRef .
Modifiers ::= FixModifiers | VarModifiers .
VarModifiers ::= "modifiers:" VarRef .
MemberType ::= ConstructorType | DataType .
ConstructorType ::= "constructor" .
DataType ::= FixDataType | VarDataType .
FixDataType ::= DotList(Ident) [SquareBrackets] .
VarDataType ::= "return:" VarRef .
SquareBracketses ::= List("[]") .
Argument ::= DataType Ident [SquareBrackets] .
MethodBody ::= FixMethodBody | VarMethodBody .
VarMethodBody ::= "body:" VarRef ";" .
FixMethodBody ::= <javacode> Text .
The syntax of AddInterface is similar. VarRef is explained in "Variables", below.
You may add methods/method signatures and data members to classes and interfaces:
AugmentMethod ::= InsertPlace <name> FullMethodName JavaCode .
InsertPlace ::= "before:" | "after:" .
FullMethodName ::= <classname> Ident "." GenMethodName
[<args> MethodArgTypes] .
GenMethodName ::= Ident | "*" .
For example:
before: MyClass.* (@
System.out.println("Entering some method of class MyClass");
@)
Will prepend each method of MyClass with the code shown. To implement an interface in an existing class, use:
"implement:" InterfaceName "in:" ClassName ";" .
For example:
implement: java.util.Enumeration in: MyStack;
will do just that.
"RenameMethod" is somewhat of a misnomer. You may change the name, argument types, return value, visibility, or modifiers of a method or set of methods with this instruction. The syntax is:
RenameMethod ::= "rename:" FullMethodName
"to:" FullMethodProto ";" .
FullMethodName ::= <classname> Ident "." GenMethodName
[MethodArgTypes] .
GenMethodName ::= Ident | "*" .
MethodArgTypes ::= "(" [CommaList(FixDataType)] ")" .
FixDataType ::= DotList(Ident) [SquareBrackets] .
FullMethodProto ::= [Visibility] [Modifiers] [ReturnType]
<name> Ident [FullMethodArgTypes] .
FullMethodArgTypes ::= "(" [CommaList(Argument)] ")" .
Argument ::= DataType Ident [SquareBrackets] .
For example:
rename: MyClass.f to old_f;will change the name of any method "f" in class MyClass to "g", while
rename: MyClass.f() to g;will only rename the method "f" which takes no arguments.
rename: MyClass.f() to public g(int n);will also change the arguments the function takes and make it public.
PackageSpec ::= "package" Pack ";" . Pack ::= FixPackage | VarRef . FixPackage ::= DotList(Ident) .
The scope of the effect of a PackageSpec continues from the statement either to the end of the file or to the next PackageSpec, if one exists. This may be temporarily overridden inline in a class or interface definition.
For Example:
add: class A {}
package One;
add: class B {}
add: class C package Two {}
add: class D {}
package Three;
add: class E {}
Class A will have no package, classes B and D will be in package One, class C
will be in package Two, and class E will be in package Three.
The scope of an ImportStatement lasts until the end of the file. There is no way to "unimport" a package or class once it has been imported except to begin a new file.
ImportStatement ::= "import" <name> ImportName ";" . ImportName ::= DotList(Ident) [".*"] .
Using Variables, you may store and reference attributes of classes and methods. Occasionally you may need to set an attribute of a method (return type, visibility, etc.) to the same value as some other method without knowing what that value is.
VarAssignment ::= VarName "=" Rvalue .
Varname ::= Ident .
Rvalue ::= RVisibility | RModifiers | RReturnType
| RBody | RPackage | RVar | JavaCode .
RVisibility ::= "visibility:" FullMethodName ";" .
RModifiers ::= "modifiers:" FullMethodName ";" .
RReturnType ::= "return:" FullMethodName ";" .
RBody ::= "body:" FullMethodName ";" .
RPackage ::= "package:" ClassName ";" .
RVar ::= RVarExp ";" .
RVarExp ::= VarRef ["+" RVarExp] .
VarRef ::= "#" VarName .
For example:
add: class MyClass {
public void f() (@ ... @)
}
visvar = visibility: MyClass.f;
add: class MyOtherClass {
visibility: #visvar void g() (@ ... @)
}
Trying to reference a variable as a different type than it was declared will result in a type error except for variables which store Javacode or method bodies - these are interchangable. The "+" operator is defined only for Javacode (concatenation) and Modifiers (set union).
Example:
add: class MyClass {
public void f() (@ fCode(); @)
}
fbody = body: MyClass.f;
newbody = (@ moreCode(); @)
newbody = #fbody + #newbody;
add: MyOtherClass {
public void g() body:#newbody;
}
The body of MyOtherClass.g() will be (@ fCode(); moreCode(); @).