Mocking Boo
Okay, I built it to relax a bit, because I am extremely annoyed at the moment. I apologize in advance for the code quality, it is POC only, but still, I wouldn't generally release it like this.
What is this? Do you see the highlighted bit at the bottom? This is Boo code that invokes a Macro on compile. It will generate an adapter and an interface, so you don't have to do it manually. The implementation code is below:
class AdapterMacro(AbstractAstMacro):
def Expand(macro as MacroStatement):
if macro.Arguments.Count != 1 or not macro.Arguments[0] isa ReferenceExpression:
raise "adapter must be called with a single argument"
entity = NameResolutionService.Resolve(macro.Arguments[0].ToString())
raise "adapter only accept types" unless entity.EntityType == EntityType.Type
BuildType(macro, entity)
def GetModule(node as Node) as Boo.Lang.Compiler.Ast.Module:
return node if node isa Boo.Lang.Compiler.Ast.Module
return GetModule(node.ParentNode)
def BuildType(macro as MacroStatement, type as IType):
adapter = ClassDefinition(Name: "${type.Name}Adapter")
adapter.Members.Extend(
Field(Name: "theTarget", Type: SimpleTypeReference(type.FullName) )
)
ctor = Constructor()
ctor.Parameters.Add(ParameterDeclaration("target", SimpleTypeReference(type.FullName) ) )
ctor.Body.Add(
BinaryExpression(BinaryOperatorType.Assign,
ReferenceExpression("theTarget"),
ReferenceExpression(Name: "target")
)
)
adapter.Members.Add(ctor)
adapterInterface = InterfaceDefinition(Name: "I${type.Name}")
GetModule(macro).Members.Add(adapter)
GetModule(macro).Members.Add(adapterInterface)
adapter.BaseTypes.Add( SimpleTypeReference(adapterInterface.FullName) )
for member in type.GetMembers():
AddMethod(adapter, adapterInterface, member) if member isa IMethod
BooPrinterVisitor(System.Console.Out).Visit(adapterInterface)
BooPrinterVisitor(System.Console.Out).Visit(adapter)
def AddMethod(adapter as ClassDefinition,
adapterInterface as InterfaceDefinition,
method as IMethod):
return unless method.IsPublic
interfaceMethod = Method(Name: method.Name)
forwarder = Method(Name: method.Name)
if method.ReturnType.IsByRef or method.ReturnType.IsArray:
return
args = []
for param in method.GetParameters():
if param.IsByRef or param.Type.IsArray:
return
forwarder.Parameters.Extend(
ParameterDeclaration(
Name: param.Name,
Type: SimpleTypeReference(param.Type.FullName)
)
)
interfaceMethod.Parameters.Extend(
ParameterDeclaration(
Name: param.Name,
Type: SimpleTypeReference(param.Type.FullName)
)
)
args.Add( ReferenceExpression(param.Name) )
adapterInterface.Members.Add(interfaceMethod)
adapter.Members.Add(forwarder)
mie = MethodInvocationExpression(
Target: AstUtil.CreateReferenceExpression("theTarget.${method.Name}")
)
mie.Arguments.Extend(args)
forwarder.ReturnType = SimpleTypeReference(method.ReturnType.FullName)
interfaceMethod.ReturnType = SimpleTypeReference(method.ReturnType.FullName)
if method.ReturnType == typeof(void):
forwarder.Body.Add(mie)
else:
forwarder.Body.Add(ReturnStatement(mie))
Comments
Do you actually have different implementations for Int32? Or was it just an exotic example? :)
Just an example.
Comment preview