Saturday, November 14, 2009

Well it makes sense to me

A fully self-contained library that provides the fibonacci function, all in Dynamos Assembly. The only parameters to this library are numberFactory and listFactory.

Debug("creating fibonacci library", numberFactory),

CreateValueObject(interpreter, 1), // create constant for '1'
Push(Symbol.RESULT),
SetObject(numberFactory),
FunctionCall(Symbol.get("numberFrom:")),
Push(Symbol.RESULT),
FunctionCall(Symbol.get("one:")),

CreateValueObject(interpreter, 2), // create constant for '2'
Push(Symbol.RESULT),
SetObject(numberFactory),
FunctionCall(Symbol.get("numberFrom:")),
Push(Symbol.RESULT),
FunctionCall(Symbol.get("two:")),

// create second anonymous function
SetObject(listFactory), // empty symbol list
FunctionCall(Symbol.get("newList")),
Push(Symbol.RESULT), // copy into arguments
FunctionCall(argumentList.toSetterSymbol()),

SetObject(listFactory), // empty symbol list
FunctionCall(Symbol.get("newList")),
Push(Symbol.RESULT), // copy into locals
FunctionCall(locals.toSetterSymbol()),
PushSymbol(temp1), // add 'temp1' local
SetObject(argumentList),
FunctionCall(Symbol.get("add:")),

StartOpCodeList(),
Push(one), // result = index - 1
SetObject(index),
FunctionCall(minus$),

Push(Symbol.RESULT), // result = fibonacci( result )
FunctionCall(fibonacci$),

Push(Symbol.RESULT), // temp1 = result
FunctionCall(temp1Setter), // temp1 = result

Push(two), // result = index - 2
SetObject(index),
FunctionCall(minus$),

Push(Symbol.RESULT), // result = fibonacci( result )
FunctionCall(fibonacci$),

Debug("left side", temp1),
Debug("right side", Symbol.RESULT),
Push(Symbol.RESULT), // temp1 = temp1 + result
SetObject(temp1),
FunctionCall(plus$),
EndOpCodeList(),
Debug("got opcodes", Symbol.RESULT),

Push(argumentList), // create anon2 function
Push(locals),
Push(Symbol.RESULT),
FunctionCall(Symbol.CREATE_FUNCTION_WITH_ARGUMENTS_$_LOCALS_$_OPCODES_$),
Debug("created", Symbol.RESULT),

Push(Symbol.RESULT),
FunctionCall(anon2.toSetterSymbol()),

// Create fibonacci function
SetObject(listFactory), // empty symbol list
FunctionCall(Symbol.get("newList")),
Push(Symbol.RESULT), // copy into arguments
FunctionCall(argumentList.toSetterSymbol()),
PushSymbol(index), // add 'index' parameter
SetObject(argumentList),
FunctionCall(Symbol.get("add:")),

SetObject(listFactory), // empty symbol list
FunctionCall(Symbol.get("newList")),
Push(Symbol.RESULT), // copy into locals
FunctionCall(locals.toSetterSymbol()),

StartOpCodeList(),
// create first anonymous function
// mainly here to make sure the nesting of op code lists works, otherwise would be in top context
SetObject(listFactory), // empty symbol list
FunctionCall(Symbol.get("newList")),
Push(Symbol.RESULT), // copy into arguments
FunctionCall(argumentList.toSetterSymbol()),

SetObject(listFactory), // empty symbol list
FunctionCall(Symbol.get("newList")),
Push(Symbol.RESULT), // copy into locals
FunctionCall(locals.toSetterSymbol()),

StartOpCodeList(),
new OpCode.Push(one),
new OpCode.FunctionCall(Symbol.RESULT_$),
Debug("returning (1) ", Symbol.RESULT),
EndOpCodeList(),
Debug("got opcodes", Symbol.RESULT),

Push(argumentList), // create anon1 function
Push(locals),
Push(Symbol.RESULT),
FunctionCall(Symbol.CREATE_FUNCTION_WITH_ARGUMENTS_$_LOCALS_$_OPCODES_$),
Debug("created", Symbol.RESULT),

Push(Symbol.RESULT),
FunctionCall(anon1.toSetterSymbol()),

// actual fibonacci function code
Debug("in fibonacci with argument", index),
Debug("******************************", numberFactory),
Push(two), // result = index isLessThan: two
SetObject(index),
FunctionCall(isLessThan$),

Push(anon1), // result = result ifTrue: [anon1] ifFalse: [anon2]
Push(anon2),
SetObject(Symbol.RESULT),
FunctionCall(ifTrue$IfFalse$),
Debug("true or false?", Symbol.RESULT),

Push(Symbol.RESULT), // contextualize anon function
Push(Symbol.CURRENT_CONTEXT),
FunctionCall(Symbol.CONTEXTUALIZE_FUNCTION_$_IN_$),
Debug("contextualized", Symbol.RESULT),

SetObject(Symbol.RESULT), // call anon function
FunctionCall(Symbol.EXECUTE),
Debug("executed function", Symbol.RESULT),
EndOpCodeList(),
Debug("got opcodes", Symbol.RESULT),

Push(argumentList), // create fibonacci function
Push(locals),
Push(Symbol.RESULT),
FunctionCall(Symbol.CREATE_FUNCTION_WITH_ARGUMENTS_$_LOCALS_$_OPCODES_$),
Debug("created", Symbol.RESULT),

Push(Symbol.RESULT), // contextualise the newly created function
Push(Symbol.CURRENT_CONTEXT),
FunctionCall(Symbol.CONTEXTUALIZE_FUNCTION_$_IN_$),
Debug("contextualized", Symbol.RESULT),

Push(Symbol.RESULT), // store fibonacci function temp
FunctionCall(temp1.toSetterSymbol()),

PushSymbol(fibonacci$), // save fibonacci to context
Push(temp1),
FunctionCall(Symbol.SET_FUNCTION_$_TO_$),

FunctionCall(Symbol.NEW_OBJECT), // create a new, empy object, move into fibonacciLibrarySlot
Push(Symbol.RESULT),
FunctionCall(fibonacciLibrarySlot.toSetterSymbol()),

PushSymbol(fibonacci$), // and add to the fibonacci library
Push(temp1),
SetObject(fibonacciLibrarySlot),
FunctionCall(Symbol.SET_FUNCTION_$_TO_$),
Debug("created fibonacci library", fibonacciLibrarySlot),

Push(fibonacciLibrarySlot), // return the library
FunctionCall(Symbol.RESULT_$)

This manages to do a lot of what is needed, the hairy stuff left is all about inheritance and especially getters/setters/slots.

The problem with the slots is that, because everything is supposed to be a message send, how do you ever actually update slots? At the moment, when a slot (always in the context so far) is created, the slot gets a default getter and setter. But how does one override the default getter/setter and still actually update the slot?

Also the Context setter is different from the object setter; the context setter updates the contents of the slot where it is defined, where as the object setter updates the contents of the current object.

I guess I'll probably end up with an addSlot: function, with some variants that provide different getters/setters. Then aliasing could be used to save the setter somewhere.

Still thinking.

No comments:

Post a Comment