October 2007
[ bamboo ] 09:50, Wednesday, 31 October 2007

Oren talks about a simple but interesting macro to aid with mocking. I decided to see if and how the latest meta programming facilities I've been working on are actually useful. Here's the complete application, what do you think?

    namespace Adapter

    import Boo.Lang.Compiler
    import Boo.Lang.Compiler.Ast
    import Boo.Lang.Compiler.Ast.Visitors
    import Boo.Lang.Compiler.TypeSystem
    import Boo.Lang.Compiler.MetaProgramming

    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.GetAncestor(NodeType.Module)

        def BuildType(macro as MacroStatement, type as IType):
            adapterInterface = [|
                interface $("I" + type.Name):
                    pass
            |]

            adapter = [|
                class $(type.Name + "Adapter")($adapterInterface):

                    theTarget as $(type.FullName)

                    def constructor(target as $(type.FullName)):
                        theTarget = target
            |]

            GetModule(macro).Members.Add(adapter)
            GetModule(macro).Members.Add(adapterInterface)

            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):

            if not method.IsPublic: return
            if method.IsStatic: return
            if method.ReturnType.IsByRef: return
            if method.ReturnType.IsArray: return

            interfaceMethod = [|
                def $(method.Name)() as $(method.ReturnType.FullName):
                    pass
            |]

            forwarder = interfaceMethod.CloneNode()

            forwardInvocation = [| theTarget.$(method.Name)() |]
            for param in method.GetParameters():
                if param.IsByRef or param.Type.IsArray:
                    return

                forwarder.Parameters.Add(
                    ParameterDeclaration(
                        Name: param.Name,
                        Type: SimpleTypeReference(param.Type.FullName)))

                interfaceMethod.Parameters.Add(
                    ParameterDeclaration(
                        Name: param.Name,
                        Type: SimpleTypeReference(param.Type.FullName)))

                forwardInvocation.Arguments.Add(ReferenceExpression(param.Name))


            adapterInterface.Members.Add(interfaceMethod)
            adapter.Members.Add(forwarder)

            if method.ReturnType == TypeSystemServices.VoidType:
                forwarder.Body.Add(forwardInvocation)
            else:
                forwarder.Body.Add([| return $forwardInvocation |])


    code = [|
        import Adapter

        adapter int

        print Int32Adapter(42) isa IInt32
    |]

    try:
        module = compile(code, typeof(AdapterMacro).Assembly)
        module.EntryPoint.Invoke(null, (null,))
    except x as CompilationErrorsException:
        print x.Errors.ToString(true)

[ bamboo ] 00:33, Saturday, 27 October 2007

boojay does eclipse
Today history was made. The first eclipse plugin written in boo and compiled down to java bytecodes by boojay has come to life. The plugin is a direct translation of the the plugin described here.
And the boo code:

    """
    Hello World eclipse plugin.

    A direct translation of
    http://www.eclipse.org/articles/Article-Your%20First%20Plug-in/YourFirstPlugin.html
    to boo.
    """
    namespace HelloWorldPlugin

    import org.eclipse.ui
    import org.eclipse.jface.action
    import org.eclipse.jface.dialogs
    import org.eclipse.jface.viewers

    class HelloWorldAction(IWorkbenchWindowActionDelegate):

        activeWindow as IWorkbenchWindow

        def run(proxyAction as IAction):
            shell = activeWindow.getShell()
            MessageDialog.openInformation(shell, "Hello from boojay!", "Hello World!")

        def init(window as IWorkbenchWindow):
            activeWindow = window

        def dispose():
            pass

        def selectionChanged(proxyAction as IAction, selection as ISelection):
            pass


[ bamboo ] 22:08, Thursday, 25 October 2007

If you think it makes sense to have a JVM backend for the boo programming language, join us.

[ bamboo ] 14:08, Thursday, 25 October 2007

This release includes bug fixes, performance improvements and better meta-programming capabilities [1].

Special thanks to Marcus Griep, Nick Fortune and Matt McElheny!

What? - http://boo.codehaus.org/
Download - http://boo.codehaus.org/Download
Official irc channel - irc://irc.codehaus.org/boo


Complete change log here.
Have fun!
[1] see the 'match' and 'data' macros in the boo-extensions project for examples

[ bamboo ] 11:56, Wednesday, 24 October 2007

Yeah, I won't be playing Halo 3 unless I get one for free (hint, hint).

[ bamboo ] 20:21, Tuesday, 23 October 2007

Consider the following simple application for a moment:

import org.eclipse.swt
import org.eclipse.swt.widgets

display = Display()
shell = Shell(display)
shell.setText("Hello!")
shell.setSize(200, 200)
shell.open()

while not shell.isDisposed():
    if not display.readAndDispatch():
        display.sleep()
        
display.dispose()

A boo application using the SWT java GUI library. Thanks to IKVM that's not only possible but very simple as well.

So what's the news? Well, Friday morning I was chatting with Klaus and he said to me "if you get boo to emit java bytecodes I'll do all my stuff in boo". How's that for a challenge? :)

Thanks again to IKVM, ObjectWeb ASM and the extensible boo pipeline architecture after a weekend of relaxed hacking boojay was born.

UPDATE: Just in case it's not clear, the generated class files DO NOT require IKVM in any way and can be executed in any compliant JVM.

[ bamboo ] 18:22, Tuesday, 16 October 2007

I've finally took some time off this weekend to implement a simple object pattern matching facility as part of the newly created boo-extensions project.

Here's some code using the new 'match' and 'data' macros to implement an expression evaluator:

import Boo.PatternMatching
import Boo.Adt

def eval(e as Expression) as int:
   match e:
      case Const(value):
        return value
      case Add(left, right):
        return eval(left) + eval(right)

def simplify(e as Expression) as Expression:
    match e:
        case Add(left: Const(value: 0), right):
            return simplify(right)
        case Add(left, right: Const(value: 0)):
            return simplify(left)
        case Add(left, right):
            return Add(simplify(left), simplify(right))
        case _:
            return _

data Expression = Const(value as int) | Add(left as Expression, right as Expression)

e = Add(Add(Const(19), Const(0)), Add(Const(0), Const(23)))

print simplify(e)
print eval(e)
print eval(simplify(e))

'match' coupled with our recently acquired quasiquoting capabilities makes writing macros for boo a pleasant endeavour actually.

Dont believe me? Take a look at the data macro again.