Skip to content

Instantly share code, notes, and snippets.

@joseoliv
Last active August 30, 2022 08:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joseoliv/609dc35bfb2a93c192ef44e3862fbf37 to your computer and use it in GitHub Desktop.
Save joseoliv/609dc35bfb2a93c192ef44e3862fbf37 to your computer and use it in GitHub Desktop.
metaobject action_afti_dsa
package metaobjectTest
// @doc{+* is used instead of @doc{* because '{*' is used
// in the text attached to @doc
@doc{+*
This metaobject can add fields and methods to the current prototype,
add code before methods, and add code inside methods (if the annotation
is inside a method). This text is in language Markdown. Unlike other
metaobjects, this one demands the understanding of the Cyan Metaobject
Protocol to be used. To use an annotation of action_afterResTypes_semAn is
an alternative of building a whole metaobject class in Java.
The annotations take an attached DSL code of a language called *Myan*
which is interpreted Cyan with the possibility of declararing fields
and methods.
Each method should correspond to a method of a Java interface implemented by this
metaobject class:
IAction_semAn, IActionNewPrototypes_semAn,
IAction_afterResTypes, IActionNewPrototypes_afterResTypes,
IParseWithCyanCompiler_parsing,
ICommunicateInPrototype_afterResTypes_semAn
And it should not have parameters. For example, there
is a method `afterResTypes_addCodeTo` in the Java interface
`meta.IAction_afterResTypes`. However, this method takes two arguments and in the
Cyan code below it has none. To simplify the coding of metaobjects, the
formal parameters of the methods are implicitly declared. In the code
below we list which are the parameter names. Inside the methods, two
variables can be used: ``metaobject``, which is the metaobject that
received the message (it would be ``self``) and ``env``, the environment.
For those interface methods that have a ``compiler`` parameter, there is
a variable ``compiler`` available in the corresponding *Myan* method.
// field declarations
func afterResTypes_codeToAdd {
// two variables are accessible:
// ICompiler_afterResTypes compiler
// List<Tuple2<CyanMetaobjectAnnotation,
// List<ISlotInterfaceProgramUnit>>> infoList
// the return value has the Cyan type Tuple<String, String>
}
func semAn_codeToAdd {
// variable ICompiler_semAn compiler is accessible
// return value has the Cyan type String
}
func runUntilFixedPoint {
// either 'return true' or 'return false'
}
func afterResTypes_beforeMethodCodeList {
// variable ICompiler_afterResTypes compiler is accessible
// the return value has Cyan type
// Array<Tuple<String, String, Boolean>>
}
func afterResTypes_renameMethod {
// variable ICompiler_afterResTypes compiler is accessible
// the return value has the Cyan type
// Array<Tuple<String, Array<String>>>
}
func semAn_NewPrototypeList {
// variable ICompiler_semAn compiler is accessible
// return value has the Cyan type
// Array<Tuple<String, String>>
}
func afterResTypes_NewPrototypeList {
// variable ICompiler_afterResTypes compiler is accessible
// return value has the Cyan type
// Array<Tuple<String, String>>
}
func afterResTypes_semAn_shareInfoPrototype {
// the return value is Object
}
func afterResTypes_semAn_receiveInfoPrototype {
// variable annotationInfoSet has the Cyan type
// Set<Tuple<String, Int, Int, Dyn>>
}
Each Cyan method can also return a value. For example,
`afterResTypes_codeTo` should return a value of type
Tuple<String, String>
If there is no `return` statement inside the code, the Cyan
interpreter considers that the Java `null` value was returned.
All classes of the Cyan compiler and java.lang are implicitly
imported, as `meta.Tuple2` (Cyan compiler) and `StringBuffer`
(java.lang). So there is no need of importing them. If necessary, Java
packages (not classes) may be imported using the `import` keyword:
import ufscar.dcomp.lib
``import`` statements should come before any others *inside* a method.
A jar file with the package should be in the `--meta\meta` directory
of the current package (of the compilation unit in which the annotation
is used). Or in the Java path. Java classes with the full path can be
used if a jar file with them are in `--meta\meta`.
The workings of this metaobject class is simple: it declares a method
for every inherited interface method. This method just interprets the
method with the same name of the *Myan* code. The result is that
metaprogramming is made in interpreted Cyan, *Myan*.
In *Myan*, the ``self`` object has two important methods: ``runFile:``
and ``call:``. The first takes at least a string with the name of a
file that should be in a directory ``--data`` of a package, with
extension ``myan``.
@action_afterResTypes_semAn{*
func semAn_codeToAdd {
runFile: #printProtoData_semAn;
}
*}
There should be a file ``printProtoData_semAn.myan`` in the ``--data``
directory of the current package. To use this file in other package,
it is necessary to precede it with the package name. Import declarations
of the Cyan source code are not taken into consideration here. Parameters
can be passed to the file:
runFile: "checkProto", "test", 0;
There should be a file ``--data\checkProto(P,Q).myan`` in the current
package directory. Parameters ``P`` and ``Q`` can be anyone. But there
should be a file with **two** parameters since the ``runFile:`` method
has **three** parameters. ``P``and ``Q`` are textually replaced by the
parameters ``"test"`` and ``0``. But only when they are full words inside
the file (In the file, ``Proto`` is not changed to ``"test"roto).
Method ``call:`` calls an action metaobject. An *action metaobject* class
should inherit from class `CyanMetaobject` and implement interface
`IActionFunction`. A method
Object eval(Object arg)
should be defined. Inside *Myan* code, ``call:`` will call `eval` passing
as a parameter an object of
Tuple6<IAbstractCyanCompiler,
CyanMetaobjectWithAt, ArrayList<Object>, WrSymbol,
WrMethodDec, WrEnv>
The first tuple element is the `compiler`object passed as parameter to
several interface methods. It may be `null` because some interfaces do
not take a `compiler` parameter. The second tuple element is the
metaobject, the original one. The third is the list of parameters.
Using Cyan syntax, it would be
[ "run", "at: Int put: String", 0 ]
in
call: "checkNumberCalls", "at: Int put: String", 0
The four element, of type `WrSymbol`, is a symbol that may be used
inside the *action metaobject* to issue errors. The fifth element is
the current method and the last one is the current environment.
By the way, the action metaobject ``checkNumberCalls`` does not exist.
But `shouldCallSuperMethod` does. It does not take parameters and
checks whether the method, the fifth tuple element, extends the
superprototype method. Its first statatement should be a call to the
superprototype method. Otherwise an error is issued.
*Action metaobjects* are used to tasks that Myan code cannot do.
Like visit AST nodes. It is necessary a Java object for that. Precisely,
a Java object of class `WrASTVisitor` is expected as parameter to method
`accept` of every AST class. Then the AST cannot be visited using Cyan
code. This job must be done using *action metaobjects*. A good project
is to create a *action metaobject* that calls Cyan code for each AST
class. The *action metaobject* would be called as
@action_afterResTypes_semAn{*
visit: """
visit: WrMethodDec node, WrEnv env {
// visit a method
}
visit: WrStatementAssignmentList node,
WrEnv env {
// visit an assignment
}
""";
*}
The Cyan code would be able to visit methods and statements of a
protototype, for example.
*+}
open
object Action_afterResTypes_semAn
var Int counter = 0;
func getCounter -> Int {
return counter;
}
func run {
var one = 0;
@action_afterResTypes_semAn{*
func semAn_codeToAdd {
// file printData_at_semAn.myan is at
// directory --data of the current package
// The code of this file will print a lot
// of information on this prototype at
// compile-time
runFile: #printData_at_semAn;
// 'one = 1;' will be added after
// the annotation
return "one = 1; ";
}
func afterResTypes_codeToAdd {
return [. """
func getZero -> Int = 0;
""", "func getZero -> Int" .];
}
func afterResTypes_beforeMethodCodeList {
return [ [. "getCounter", "counter = 5;", false .] ]
}
*}
// getCounter return counter that should be 0 but
// metaobject action_afterResTypes_semAn, method 'afterResTypes_beforeMethodCodeList',
// changed its value to 5 by adding code 'counter = 5;' before
// the first method statement
assert getCounter == 5;
// method getZero was added by method 'afterResTypes_codeToAdd' of
// action_afterResTypes_semAn
assert getZero == 0;
assert one == 1;
var String s = "aaa";
@action_afterResTypes_semAn{*
func semAn_codeToAdd {
return """ s = "bbb";""";
}
*}
assert s == "bbb";
/* use the action metaobject 'fat', for demonstration only,
to calculate the factorial of 10
*/
var Long fat10 = 0L;
@action_afterResTypes_semAn{*
func semAn_codeToAdd {
let String s = call: #fat, 10;
return " fat10 = " ++ s ++ ";\n";
}
*}
assert fat10 == 3628800L;
fat10 = 0L;
fat10 = @eval("cyan.lang", "Long"){*
let String s = call: #fat, 10;
return s;
*};
assert fat10 == 3628800L;
}
/* methods communicateInPrototype_111 and communicateInPrototype_222
test the communication among metaobjects of the same
prototype
*/
func communicateInPrototype_111 {
@action_afterResTypes_semAn{*
func afterResTypes_semAn_afterSemAn_shareInfoPrototype {
return "AAAA";
}
func afterResTypes_semAn_afterSemAn_receiveInfoPrototype {
var Array<Tuple<String, Int, Int, Dyn>> annotInfoArray =
annotationInfoSet asArray;
"The set of shared info is:" println;
for t in annotInfoArray {
Out println: "[. " ++ t f1 ++ ", " ++ t f2 ++ ", " ++ t f3 ++
", " ++ t f4 ++ " .]";
}
}
*}
}
func communicateInPrototype_222 {
@action_afterResTypes_semAn{*
func afterResTypes_semAn_afterSemAn_shareInfoPrototype {
return "BBBB";
}
func afterResTypes_semAn_afterSemAn_receiveInfoPrototype {
Out println: "number of shared objects is " ++ annotationInfoSet size;
}
*}
}
func myprint: Int n {
}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment