diff --git a/core.lua b/core.lua index 439ee46..985c54c 100644 --- a/core.lua +++ b/core.lua @@ -50,8 +50,8 @@ function createLuaFunc( ... ) local theNumArgs = select('#',...) - 1 for i=1,theNumArgs do local theArgName = select(i,...) + -- TODO: remove check for speed? if type(theArgName)~="string" then - -- TODO: remove for speed error( "Argument #"..i.." to createLuaFunc() is "..tostring(theArgName)) end func.namedArguments[i] = runtime.string[theArgName] @@ -83,8 +83,7 @@ function evaluateChunk( chunk, context ) end function evaluateExpression( expression, context ) - --TODO: via setSlot as a message? - expression.context = context + -- FIXME: Shouldn't this be set by createExpression (defaulting to Lawn sometimes)? if expression.creationContext == Roots['nil'] then expression.creationContext = context end @@ -94,13 +93,13 @@ function evaluateExpression( expression, context ) while context.nextMessage ~= Roots['nil'] do local theCurrentMessage = context.nextMessage context.nextMessage = context.nextMessage.next - receiver = sendMessage( receiver, theCurrentMessage ) + receiver = sendMessage( receiver, theCurrentMessage, context ) end return receiver end -function sendMessage( receiver, messageOrLiteral ) +function sendMessage( receiver, messageOrLiteral, callingContext ) if messageOrLiteral.identifier == Roots['nil'] then -- Presumably this is a literal -- TODO: Warning about literals sent as message if the receiver isn't a context @@ -117,16 +116,20 @@ function sendMessage( receiver, messageOrLiteral ) print( "Warning: Cannot find message '"..tostring(messageName).."' on "..tostring(receiver) ) end elseif obj.executeOnAccess ~= Roots['nil'] then - obj = executeFunction( obj, receiver, messageOrLiteral ) + obj = executeFunction( obj, receiver, messageOrLiteral, callingContext ) end return obj or Roots['nil'] end -function executeFunction( functionObject, receiver, message ) - local callingContext = message.parent.context +function executeFunction( functionObject, receiver, message, callingContext ) if callingContext == Roots['nil'] then - -- if _DEBUG then print( "Warning: No message/expression context when sending '"..runtime.luastring[message.identifier].."'...so I'm using the Lawn instead.") end + if arg.debugLevel and arg.debugLevel >= 2 then + local messageString = runtime.luastring[message.identifier] + if messageString ~= 'toString' and messageString ~= 'asCode' then + print( "Warning: No message/expression context when sending '"..messageString.."'...so I'm using the Lawn instead." ) + end + end callingContext = Roots.Lawn end @@ -144,12 +147,16 @@ function executeFunction( functionObject, receiver, message ) if functionObject.namedArguments ~= Roots['nil'] then local theNextMessageInCallingContext = callingContext.nextMessage for i=1,#functionObject.namedArguments do - -- TODO: warn if this conflicts, or maybe don't shove locals onto the context, but inherit the context from locals local theArgName = runtime.luastring[ functionObject.namedArguments[i] ] + if arg.debugLevel and arg.debugLevel >= 2 and rawget( context, theArgName ) then + print( "Warning: overriding built in context property '"..theArgName.."'" ) + end if message.arguments[i] ~= Roots['nil'] then context[ theArgName ] = evaluateChunk( message.arguments[i], callingContext ) else - if _DEBUG then print( "Warning: No argument passed for parameter '"..theArgName.."'; setting to Roots.nil" ) end + if arg.debugLevel and arg.debugLevel >= 3 then + print( "Warning: No argument passed for parameter '"..theArgName.."'; setting to Roots.nil" ) + end context[ theArgName ] = Roots['nil'] end end @@ -186,7 +193,7 @@ function sendMessageAsString( object, messageString, ... ) if theFunction == Roots['nil'] then error( "Cannot find '"..messageString.."' on "..tostring(object) ) end - return executeFunction( theFunction, object, theMessage ) + return executeFunction( theFunction, object, theMessage, Roots.Lawn ) end -- ########################################################################## @@ -196,7 +203,7 @@ function toObjString( object ) object = object.__name elseif not runtime.isKindOf( object, String ) then -- TODO: Perhaps replace test with a simple runtime.luastring[object], since every string object should have an entry here - object = sendMessage( object, messageCache['toString'] ) + object = sendMessage( object, messageCache['toString'], Roots.Lawn ) end -- TODO: Perhaps replace test with a simple runtime.luastring[object], since every string object should have an entry here if runtime.isKindOf( object, String ) then @@ -212,6 +219,75 @@ end -- ########################################################################## +-- TODO: remove this debug function (or more to debug utils) +function printObjectAsXML( object, depth, recursingFlag ) + if not depth then depth = 0 end + + if not recursingFlag then + print( "" ) + _G.objectsPrinted = {} + end + + local indent = string.rep( " ", depth ) + + if runtime.luanumber[ object ] then + print( indent.."(N)"..runtime.luanumber[ object ] ) + + elseif runtime.luastring[ object ] then + print( indent.."(S)"..string.sub( string.format("%q",runtime.luastring[object]), 2, -2 ) ) + + else + local attrs = {} + for attrName,attrObj in pairs(object) do + if not tonumber( attrName ) then + local valueString = (runtime.luanumber[ attrObj ] and ("(N)"..runtime.luanumber[attrObj])) or + (runtime.luastring[ attrObj ] and ("(S)"..string.sub( string.format("%q",runtime.luastring[attrObj]), 2, -2 ) ) ) or + ( runtime.ObjectId[ attrObj ] and string.format( "0x%04x", runtime.ObjectId[ attrObj ] ) ) or + tostring( attrObj ) + attrs[ attrName ] = valueString + end + end + local objectName = runtime.luastring[ object.__name ] + if objectName == "Lawn" and object ~= Roots.Lawn then + objectName = "Context" + end + io.write( string.format( '%s<%s id="0x%04x"', indent, objectName, runtime.ObjectId[ object ] ) ) + for attrName,valueString in pairs(attrs) do + io.write( " "..attrName..'="'..valueString..'"' ) + end + + local objectShowingChildren = object + if runtime.isKindOf( object.arguments, Roots.ArgList ) then + objectShowingChildren = object.arguments + _G.objectsPrinted[ object.arguments ] = true + end + + if #objectShowingChildren > 0 then + print( ">" ) + for _,childObj in ipairs(objectShowingChildren) do + printObjectAsXML( childObj, depth+1, true ) + end + print( indent.."" ) + else + print( " />" ) + end + end + + _G.objectsPrinted[ object ] = true + + if not recursingFlag then + print( "" ) + for id,object in ipairs(runtime.ObjectById) do + if not _G.objectsPrinted[ object ] and not runtime.luastring[ object ] and not runtime.luanumber[ object ] then + printObjectAsXML( object, 0, true ) + end + end + print( "" ) + end +end + +-- ########################################################################## + -- TODO: replace with uber-portable directory scan lua_files = { "1a_basics.lua", @@ -237,4 +313,5 @@ for _,fileName in ipairs(lua_files) do local fileChunk = loadfile( "core/" .. fileName ) setfenv( fileChunk, _M ) fileChunk( ) -end \ No newline at end of file +end + diff --git a/core/expression.lua b/core/expression.lua index fc49666..d690199 100644 --- a/core/expression.lua +++ b/core/expression.lua @@ -3,7 +3,7 @@ Roots.Expression = runtime.childFrom( Roots.Array, "Expression" ) Roots.Expression.new = createLuaFunc( function( context ) -- Expression#new -- Re-use existing expression created for the first chunk argument, if available local args = context.callState.message.arguments - local theExpression = args[1] ~= Roots['nil'] and args[1][1] or executeFunction( Roots.Object.new, context.self, messageCache['new'] ) + local theExpression = (#args > 0) and (#args[1] > 0 ) and args[1][1] or executeFunction( Roots.Object.new, context.self, messageCache['new'], context.callState.callingContext ) theExpression.creationContext = context.callState.callingContext return theExpression end ) diff --git a/core/message.lua b/core/message.lua index 0167a20..885e43f 100644 --- a/core/message.lua +++ b/core/message.lua @@ -2,7 +2,8 @@ Roots.Message = runtime.childFrom( Roots.Object, "Message" ) Roots.Message.new = createLuaFunc( "identifier", function( context ) -- Message#new -- TODO: perhaps stop trying to be so DRY and just runtime.childFrom( Roots.Message ) - local theMessage = executeFunction( Roots.Object.new, context.self, messageCache['new'] ) + -- ...or wait, why isn't this using createMessage()? + local theMessage = executeFunction( Roots.Object.new, context.self, messageCache['new'], context.callState.callingContext ) if context.identifier ~= Roots['nil'] then theMessage.identifier = context.identifier end diff --git a/docs/INSTALL b/docs/INSTALL new file mode 100644 index 0000000..7bef5c8 --- /dev/null +++ b/docs/INSTALL @@ -0,0 +1,17 @@ +=============================================================================== +Installing Lua +=============================================================================== + Download the Lua source from http://www.lua.org/ftp/ + Follow the build instructions to build it. + + +=============================================================================== +Installing LPEG +=============================================================================== + Download LPEG from http://www.inf.puc-rio.br/~roberto/lpeg.html#download + + To build and install LPEG for Mac OS X: + export MACOSX_DEPLOYMENT_TARGET=10.3 + gcc -I../.. -Wall -O2 -bundle -undefined dynamic_lookup -o lpeg.so lpeg.c + sudo mv lpeg.so /usr/local/lib/lua/5.1/ + \ No newline at end of file diff --git a/runtime.lua b/runtime.lua index be90b4d..bbb5599 100644 --- a/runtime.lua +++ b/runtime.lua @@ -25,6 +25,9 @@ function childFrom( parentObject, name ) end local object = blank( name ) addInheritance( object, parentObject ) + if arg.debugLevel and arg.debugLevel >= 4 and parentObject.__name then + print( "Created "..luastring[parentObject.__name].." #"..ObjectId[object] ) + end return object end @@ -139,6 +142,7 @@ function isKindOf( object, ancestorObject ) return false end +-- TODO: remove this, as no code is using it? -- Shallow duplicate preserving inheritance hierarchy function duplicate( object ) local duplicateObject = {} @@ -156,3 +160,14 @@ function duplicate( object ) return duplicateObject end +-- TODO: Remove (debug function) +function showHier( obj, depth ) + if not depth then depth = 0 end + local indent = (" "):rep( depth ) + print( indent .. luastring[ core.sendMessageAsString( obj, 'asCode' ) ] ) + if AncestorsPerObject[ obj ] and obj ~= core.Roots.Lawn then + for i,ancestor in ipairs(AncestorsPerObject[obj]) do + showHier( ancestor, depth+1 ) + end + end +end