Skip to content

Commit

Permalink
Parenthesized sub-expressions in the parser, and supported by numeric…
Browse files Browse the repository at this point in the history
… operators
  • Loading branch information
Phrogz committed Jul 9, 2008
1 parent ffcdbd1 commit 83e102a
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 72 deletions.
25 changes: 19 additions & 6 deletions core.lua
Expand Up @@ -219,12 +219,26 @@ end

-- ##########################################################################

function slurpNextValue( callState )
local theNextValue = callState.message.next
if theNextValue ~= Roots['nil'] then
callState.callingContext.nextMessage = theNextValue.next
if runtime.isKindOf( theNextValue, Roots.Expression ) then
theNextValue = evaluateExpression( theNextValue, callState.callingContext )
elseif runtime.isKindOf( theNextValue, Roots.Message ) then
theNextValue = sendMessage( callState.callingContext, theNextValue, callState.callingContext )
end
end
return theNextValue
end

-- ##########################################################################

-- TODO: remove this debug function (or more to debug utils)
function printObjectAsXML( object, depth, recursingFlag )
function printObjectAsXML( object, showReferenced, depth, recursingFlag )
if not depth then depth = 0 end

if not recursingFlag then
print( "<!-- ################################################################ -->" )
_G.objectsPrinted = {}
end

Expand Down Expand Up @@ -265,7 +279,7 @@ function printObjectAsXML( object, depth, recursingFlag )
if #objectShowingChildren > 0 then
print( ">" )
for _,childObj in ipairs(objectShowingChildren) do
printObjectAsXML( childObj, depth+1, true )
printObjectAsXML( childObj, showReferenced, depth+1, true )
end
print( indent.."</"..runtime.luastring[ object.__name ]..">" )
else
Expand All @@ -275,14 +289,13 @@ function printObjectAsXML( object, depth, recursingFlag )

_G.objectsPrinted[ object ] = true

if not recursingFlag then
if showReferenced and not recursingFlag then
print( "<!-- ############### Referenced Objects ############### -->" )
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 )
printObjectAsXML( object, showReferenced, 0, true )
end
end
print( "<!-- ################################################################ -->" )
end
end

Expand Down
50 changes: 30 additions & 20 deletions core/number.lua
Expand Up @@ -15,12 +15,11 @@ Roots.Number['+'] = createLuaFunc( 'addend', function( context ) -- Number#+
local lvalue = runtime.luanumber[ context.self ]
local rvalue = runtime.luanumber[ context.addend ]
if not rvalue then
local theNextMessageOrLiteral = context.callState.message.next
if theNextMessageOrLiteral == Roots['nil'] then
error( "Number#+ is missing an addend" )
rvalue = slurpNextValue( context.callState )
if rvalue == Roots['nil'] then
error( "Number#+ is mising an addend" )
end
context.callState.callingContext.nextMessage = theNextMessageOrLiteral.next
rvalue = runtime.luanumber[ sendMessage( context.callState.callingContext, theNextMessageOrLiteral, context.callState.callingContext ) ]
rvalue = runtime.luanumber[ rvalue ]
end
return runtime.number[ lvalue + rvalue ]
end )
Expand All @@ -29,38 +28,50 @@ Roots.Number['-'] = createLuaFunc( 'subtrahend', function( context ) -- Number#-
local lvalue = runtime.luanumber[ context.self ]
local rvalue = runtime.luanumber[ context.subtrahend ]
if not rvalue then
local theNextMessageOrLiteral = context.callState.message.next
if theNextMessageOrLiteral == Roots['nil'] then
error( "Number#- is missing a subtrahend" )
rvalue = slurpNextValue( context.callState )
if rvalue == Roots['nil'] then
error( "Number#- is mising a subtrahend" )
end
context.callState.callingContext.nextMessage = theNextMessageOrLiteral.next
rvalue = runtime.luanumber[ sendMessage( context.callState.callingContext, theNextMessageOrLiteral, context.callState.callingContext ) ]
rvalue = runtime.luanumber[ rvalue ]
end
return runtime.number[ lvalue - rvalue ]
end )

Roots.Number['>'] = createLuaFunc( 'rvalue', function( context ) -- Number#>
local lvalue = runtime.luanumber[ context.self ]
local rvalue = runtime.luanumber[ context.rvalue ]
if not rvalue then
rvalue = slurpNextValue( context.callState )
if rvalue == Roots['nil'] then
error( "Number#> is mising an rvalue" )
end
rvalue = runtime.luanumber[ rvalue ]
end
return (lvalue > rvalue) and Roots['true'] or Roots['false']
end )

Roots.Number['<'] = createLuaFunc( 'rvalue', function( context ) -- Number#<
local lvalue = runtime.luanumber[ context.self ]
local rvalue = runtime.luanumber[ context.rvalue ]
if not rvalue then
rvalue = slurpNextValue( context.callState )
if rvalue == Roots['nil'] then
error( "Number#< is mising an rvalue" )
end
rvalue = runtime.luanumber[ rvalue ]
end
return (lvalue < rvalue) and Roots['true'] or Roots['false']
end )

Roots.Number['*'] = createLuaFunc( 'multiplicand', function( context ) -- Number#*
local lvalue = runtime.luanumber[ context.self ]
local rvalue = runtime.luanumber[ context.multiplicand ]
if not rvalue then
local theNextMessageOrLiteral = context.callState.message.next
if theNextMessageOrLiteral == Roots['nil'] then
error( "Number#* is missing a multiplicand" )
rvalue = slurpNextValue( context.callState )
if rvalue == Roots['nil'] then
error( "Number#* is mising a multiplicand" )
end
context.callState.callingContext.nextMessage = theNextMessageOrLiteral.next
rvalue = runtime.luanumber[ sendMessage( context.callState.callingContext, theNextMessageOrLiteral, context.callState.callingContext ) ]
rvalue = runtime.luanumber[ rvalue ]
end
return runtime.number[ lvalue * rvalue ]
end )
Expand All @@ -69,12 +80,11 @@ Roots.Number['/'] = createLuaFunc( 'divisor', function( context ) -- Number#/
local lvalue = runtime.luanumber[ context.self ]
local rvalue = runtime.luanumber[ context.divisor ]
if not rvalue then
local theNextMessageOrLiteral = context.callState.message.next
if theNextMessageOrLiteral == Roots['nil'] then
error( "Number#/ is missing a divisor" )
rvalue = slurpNextValue( context.callState )
if rvalue == Roots['nil'] then
error( "Number#/ is mising a divisor" )
end
context.callState.callingContext.nextMessage = theNextMessageOrLiteral.next
rvalue = runtime.luanumber[ sendMessage( context.callState.callingContext, theNextMessageOrLiteral, context.callState.callingContext ) ]
rvalue = runtime.luanumber[ rvalue ]
end
return runtime.number[ lvalue / rvalue ]
end )
Expand Down
6 changes: 6 additions & 0 deletions mab
Expand Up @@ -71,6 +71,12 @@ if arg.sourcefile then
LastCoreObjectIndex = #runtime.ObjectById
core.Roots.Lawn.program = parser.parse( code )
LastParsedObjectIndex = #runtime.ObjectById

if arg.debugLevel and arg.debugLevel >= 3 then
print( "Parsed program tree:" )
core.printObjectAsXML( core.Roots.Lawn.program )
end

core.evaluateChunk( core.Roots.Lawn.program )
LastRuntimeObjectIndex = #runtime.ObjectById
end
Expand Down
79 changes: 34 additions & 45 deletions parser.lua
Expand Up @@ -7,10 +7,11 @@ require 'utils'
module('parser',package.seeall)

grammar = [[
Chunk <- &. -> startChunk <Expression> (<Terminator> <Expression>)* -> endChunk
Expression <- &. -> startExpr <Space> (<Message>/<String>/<Number>)+ -> endExpr
ArgExpression <- <Chunk> -> addArgChunk ("," <Space> / &<CloseParen>)
Message <- ( <Identifier> / <Operator> ) -> startMessage <Arguments>? <Separator>* -> endMessage
Chunk <- &. -> startChunk <Expression> (<Terminator> <Expression>)* -> closeChunk
Expression <- &. -> startExpr <Space> (<Message>/<String>/<Number>/<SubExpression>)+ -> closeExpr
SubExpression <- <OpenParen> <Expression> <CloseParen>
ArgExpression <- <Chunk> ("," <Space> / &<CloseParen>)
Message <- ( <Identifier> / <Operator> ) -> startMessage <Arguments>? <Separator>* -> closeMessage
Arguments <- <OpenParen> <ArgExpression>* <CloseParen>
Identifier <- [a-zA-Z_]+
Operator <- [=~`!@$%^&*|<>?/\\+-]+
Expand All @@ -26,53 +27,37 @@ grammar = [[
]]

ast = {}
exprStack = {}
chunkStack = {}
argsStack = {}
messageStack = {}
stringStack = {}

parseFuncs = {}
function parseFuncs.startChunk( )
local chunk = { tag="chunk" }
table.insert( chunkStack, chunk )
function pushNode( tagName, str )
table.insert( ast, { tag=tagName, str=str } )
end

function parseFuncs.endChunk( inMatch )
table.insert( ast, table.remove( chunkStack ) )
end

function parseFuncs.startExpr( inMatch )
local expression = { tag="expression" }
table.insert( exprStack, expression )
end

function parseFuncs.endExpr( inMatch )
table.insert( chunkStack[#chunkStack], table.remove( exprStack ) )
end

function parseFuncs.startMessage( inMatch )
local message = { tag="message", str=inMatch }
table.insert( messageStack, message )
end

function parseFuncs.endMessage( inMatch )
table.insert( exprStack[#exprStack], table.remove( messageStack ) )
end

function parseFuncs.addArgChunk( )
table.insert( messageStack[#messageStack], table.remove( ast ) )
function popNode( expectedTagName )
local node = table.remove( ast )
if node.tag ~= expectedTagName then
error( "Popped a "..node.tag.." off the ast stack when I expected a "..expectedTagName )
end
if #ast > 0 then
table.insert( ast[#ast], node )
else
ast.rootNode = node
end
end

function parseFuncs.addString( inMatch )
local string = { tag="string", str=inMatch }
table.insert( exprStack[#exprStack], string )
function addChild( tagName, str )
table.insert( ast[#ast], { tag=tagName, str=str } )
end

function parseFuncs.addNumber( inMatch )
local number = { tag="number", str=inMatch }
table.insert( exprStack[#exprStack], number )
end
parseFuncs = {
startChunk = function( ) pushNode( 'chunk' ) end,
closeChunk = function( ) popNode( 'chunk' ) end,
startExpr = function( ) pushNode( 'expression' ) end,
closeExpr = function( ) popNode( 'expression' ) end,
startMessage = function( s ) pushNode( 'message', s ) end,
closeMessage = function( ) popNode( 'message' ) end,
addString = function( s ) addChild( 'string', s ) end,
addNumber = function( s ) addChild( 'number', s ) end
}

function parseFile( file )
return parse( io.input(file):read("*a") )
Expand All @@ -84,7 +69,7 @@ function parse( code )
table.dump( ast )
error( "Failed to parse code! (Got to around char "..tostring(matchLength).." / "..(#code)..")" )
end
return codeFromAST( table.remove( ast ) )
return codeFromAST( ast.rootNode )
end

function codeFromAST( t )
Expand Down Expand Up @@ -132,6 +117,10 @@ end )

function runString( code )
core.Roots.Lawn.program = parser.parse( code )
if arg.debugLevel and arg.debugLevel >= 3 then
print( "Parsed program tree:" )
core.printObjectAsXML( core.Roots.Lawn.program )
end
core.evaluateChunk( core.Roots.Lawn.program )
-- TODO: error codes
end
1 change: 1 addition & 0 deletions test/acceptance/18_subexpressions.expected
@@ -0,0 +1 @@
42
1 change: 1 addition & 0 deletions test/acceptance/18_subexpressions.mab
@@ -0,0 +1 @@
p( 2 + ( 8 * 5 ) )
3 changes: 2 additions & 1 deletion test/test_acceptance.lua
Expand Up @@ -27,7 +27,8 @@ tests = {
"15_ObjectScope",
"15b_SubtleObjectScope",
"16_locals_shadow_context",
"17_scope_resolution"
"17_scope_resolution",
"18_subexpressions"
}

function setup()
Expand Down

0 comments on commit 83e102a

Please sign in to comment.