Permalink
Browse files

Parenthesized sub-expressions in the parser, and supported by numeric…

… operators
  • Loading branch information...
1 parent ffcdbd1 commit 83e102aba11cfe20a5e71456e4090645b7066b7c @Phrogz committed Jul 9, 2008
Showing with 93 additions and 72 deletions.
  1. +19 −6 core.lua
  2. +30 −20 core/number.lua
  3. +6 −0 mab
  4. +34 −45 parser.lua
  5. +1 −0 test/acceptance/18_subexpressions.expected
  6. +1 −0 test/acceptance/18_subexpressions.mab
  7. +2 −1 test/test_acceptance.lua
View
@@ -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
@@ -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
@@ -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
View
@@ -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 )
@@ -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 )
@@ -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 )
View
6 mab
@@ -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
View
@@ -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 <- [=~`!@$%^&*|<>?/\\+-]+
@@ -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") )
@@ -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 )
@@ -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
@@ -0,0 +1 @@
+42
@@ -0,0 +1 @@
+p( 2 + ( 8 * 5 ) )
View
@@ -27,7 +27,8 @@ tests = {
"15_ObjectScope",
"15b_SubtleObjectScope",
"16_locals_shadow_context",
- "17_scope_resolution"
+ "17_scope_resolution",
+ "18_subexpressions"
}
function setup()

0 comments on commit 83e102a

Please sign in to comment.