Skip to content
This repository has been archived by the owner on Apr 25, 2018. It is now read-only.

Commit

Permalink
Added ternary if. Leaving statements for later, as they turn out to b…
Browse files Browse the repository at this point in the history
…e complex.
  • Loading branch information
mikewest committed May 19, 2009
1 parent 5307ac2 commit 18c0f4a
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 30 deletions.
87 changes: 58 additions & 29 deletions javascriptparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ def __init__( self, parser ):

#####################################################################( 30)
# conditional ?:
def led( self, left ):
self.first = left
self.second = parser.expression( 0 )
parser.next( ':' )
self.third = parser.expression( 0 )
return self
self.new_symbol( '?', 30, led=led )


#####################################################################( 20)
# assignment = += -= *= /= %= <<= >>= >>>= &= ^= |=
Expand All @@ -110,8 +118,15 @@ def __init__( self, parser ):
self.infix( '|=', 20 ) # bitwise or assignment

#####################################################################( 10)
# statement seperators
# statement seperators, closers
self.infix( ',', 10 ) # comma
self.new_symbol( ';' )
self.new_symbol( ':' )
self.new_symbol( '}' )
self.new_symbol( ')' )
self.new_symbol( ']' )
self.new_symbol( 'else' )


### Generate literal symbols
self.literal( '(NUMBER)' )
Expand All @@ -125,7 +140,7 @@ def __init__( self, parser ):
def get( self, id ):
return self._table[ id ]

def new_symbol( self, id, bp = 0 ):
def new_symbol( self, id, bp = 0, nud = None, led = None ):
try:
s = self._table[ id ]
except KeyError:
Expand All @@ -137,38 +152,49 @@ class s( SymbolBase ):
self._table[ id ] = s
else:
s.lbp = max( bp, s.lbp )

if nud is not None:
s.nud = nud
if led is not None:
s.led = led

return s
#
# Helpers for known types of Symbols
#
def infix( self, id, bp ): # Left associative infix operators ( +, -, *, etc. )
p = self._parser
def led( self, left ):
self.first = left
self.second = p.expression( bp )
return self
self.new_symbol( id, bp ).led = led
def infix( self, id, bp, nud=None, led=None ): # Left associative infix operators ( +, -, *, etc. )
if led is None:
p = self._parser
if led is None:
def led( self, left ):
self.first = left
self.second = p.expression( bp )
return self
self.new_symbol( id, bp, nud, led )

def prefix( self, id, bp ): # Prefix operators (!, +, -, etc.)
p = self._parser
def nud( self ):
self.first = p.expression( bp )
self.second = None
return self
self.new_symbol( id, bp ).nud = nud
def prefix( self, id, bp, nud=None, led=None ): # Prefix operators (!, +, -, etc.)
if nud is None:
p = self._parser
def nud( self ):
self.first = p.expression( bp )
self.second = None
return self
self.new_symbol( id, bp, nud, led )

def infix_r( self, id, bp ): # Right associative infix operators
p = self._parser
def led( self, left ):
self.first = left
self.second = p.expression( bp - 1 )
return self
self.new_symbol( id, bp ).led = led
def infix_r( self, id, bp, nud=None, led=None ): # Right associative infix operators
if led is None:
p = self._parser
def led( self, left ):
self.first = left
self.second = p.expression( bp - 1 )
return self
self.new_symbol( id, bp, nud, led )

def literal( self, id ): # Literals (strings, numbers, etc)
def nud( self ):
return self
self.new_symbol( id ).nud = nud
def literal( self, id, nud=None, led=None ): # Literals (strings, numbers, etc)
if nud is None:
def nud( self ):
return self
self.new_symbol( id, 0, nud, led )

class JavaScriptParser( object ):
def __init__( self, string_to_parse ):
Expand All @@ -180,7 +206,10 @@ def __init__( self, string_to_parse ):
#
# Grab the next token, convert it to a symbol
#
def next( self ):
def next( self, id = None ):
if ( id is not None and self.current_symbol.id != id ):
raise SyntaxError( 'Expected `%r`, got `%r`' % ( id, self.current_symbol.id ) )

t = self.tokens.next()
s = None
if t is None:
Expand Down Expand Up @@ -212,7 +241,7 @@ def expression( self, right_binding_power = 0 ):
print "Parser:"
print "======="
print
p = JavaScriptParser('1 * 1')
p = JavaScriptParser('1 ; 1 ;')

print "Parse Tree:"
print "-----------"
Expand Down
20 changes: 19 additions & 1 deletion tests/TestJavaScriptParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from javascriptparser import JavaScriptParser
import unittest

class KnownValues( unittest.TestCase ):
class KnownExpressionValues( unittest.TestCase ):
"""Testing correct evaluation of simple expressions: single statements"""
def assertEqualTree( self, expected, result ):
self.assertEqual( expected, str( result ) )

Expand Down Expand Up @@ -69,6 +70,17 @@ def assertEqualTree( self, expected, result ):
'1<<2^3||4', '(|| (^ (<< (NUMBER 1) (NUMBER 2)) (NUMBER 3)) (NUMBER 4))'
),
]
TernaryKnownValues = [
(
'1?2:3', '(? (NUMBER 1) (NUMBER 2) (NUMBER 3))'
),
(
'1?2:3>>4', '(? (NUMBER 1) (NUMBER 2) (>> (NUMBER 3) (NUMBER 4)))'
),
(
'1?2+3:4*5', '(? (NUMBER 1) (+ (NUMBER 2) (NUMBER 3)) (* (NUMBER 4) (NUMBER 5)))'
),
]
def testJavaScriptParserKnownSimpleValues( self ):
"""Parser.parse_tree should give known result with known input"""
for string, tree in self.SimpleKnownValues:
Expand All @@ -80,6 +92,12 @@ def testJavaScriptParserKnownBitwiseValues( self ):
for string, tree in self.BitwiseKnownValues:
result = JavaScriptParser( string ).parse_tree
self.assertEqualTree( tree, result )

def testJavaScriptParserKnownTernaryValues( self ):
"""Parser.parse_tree should give known result with known ternary if structures"""
for string, tree in self.TernaryKnownValues:
result = JavaScriptParser( string ).parse_tree
self.assertEqualTree( tree, result )

if __name__ == "__main__":
unittest.main()
Expand Down

0 comments on commit 18c0f4a

Please sign in to comment.