łň
6ÔaKc           @   sp   d  Z  d d k l Z d d k Z d e f d     YZ d d
 d     YZ d   Z e d	 j o e   n d S(   s-   
Parse Pd files and emit useful information.
i˙˙˙˙(   t   and_Nt   PdParserExceptionc           B   s   e  Z RS(    (   t   __name__t
   __module__(    (    (    s   ./PdParser.pyR      s   t   PdParserc           B   s)   e  Z d  Z d   Z d   Z d   Z RS(   s  
	Parse Pd files using user defined filters.
	
	>>> p = PdParser("patches/parser-test.pd")
	>>> def found(canvasStack, type, action, bits):
	...   print "canvasStack:", canvasStack, "type:", type, "action:", action, "arguments:", bits
	... 
	>>> p.add_filter_method(found, canvas="REFERENCE", type="#X", action="text")
	>>> p.add_filter_method(found, canvas="semicolon-test", type="#X", action="msg")
	>>> p.add_filter_method(found, object="osc~")
	>>> p.parse()
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 135 336 Tags: tag_one \, tag_two
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 115 301 Description: Some kind of verbose description here.
	<BLANKLINE>
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 114 121 Name: thing
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 114 174 Argument 0: first argument (required)
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 114 194 Argument 1: second argument (optional)
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 114 214 Inlet 0: my first inlet is blah
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 114 234 Inlet 1: msg1 <msg1arg>: what this message does. msg2
	<msg2arg>: what this other message does \, default 0 which is the default
	<BLANKLINE>
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 114 278 Outlet 0: what comes out the second outlet.
	canvasStack: ['patches/parser-test.pd', 'REFERENCE'] type: #X action: text arguments: 113 141 Summary: what this thing does is blah blah blah
	canvasStack: ['patches/parser-test.pd'] type: #X action: obj arguments: 471 83 osc~ 220
	canvasStack: ['patches/parser-test.pd', 'semicolon-test'] type: #X action: msg arguments: 10 18 this is a message box \, with comments \, and also \;
	semicolons! yes it is. it's like this: yo. test \; test \; test \;
	<BLANKLINE>
	canvasStack: ['patches/parser-test.pd'] type: #X action: obj arguments: 633 213 osc~ 440
	49
	c         C   s>   t  |  } | i   |  _ | i   | g |  _ g  |  _ d S(   s0   
		>>> p = PdParser("patches/parser-test.pd")
		N(   t   filet   readt   contentst   closet   canvast   filters(   t   selft   filenamet   pfile(    (    s   ./PdParser.pyt   __init__.   s
    
c         K   s   |  i  i | | f  d S(   s  
		The method will be called on each filter which matches for each line-element of the Pd file.
		
		The method can be passed the following variables:
		 The current canvas stack (an array), where the last element is the current canvas.
		 The type, such as "#X", "#N", etc.
		 The action, such as "canvas", "obj", "msg", "txt"
		 The first argument (such as the actual object passed) like "osc~"
		 The remaining arguments, as a string.
		
		>>> def found(canvasStack, type, action, bits):
		...   print "canvasStack:", canvasStack, "type:", type, "action:", action, "arguments:", bits
		... 
		
		For example:
		 canvas = "REFERENCE" will fire the method on each line inside that canvas.
		 type = "#X" will fire the method on each line which has a type of #X.
		 action = "obj" will fire on each line which has an 'action' of "obj.
		 object = "osc~" will fire on each line which has a first argument of 'obj~'
		
		You can chain multiple of these in the filter.
		For example, to find all comments in the subpatch called "REFERENCE":
		
		>>> p = PdParser("patches/parser-test.pd")
		>>> p.add_filter_method(found, canvas="REFERENCE", type="#X", action="text")
		N(   R
   t   append(   R   t   methodt   kwargs(    (    s   ./PdParser.pyt   add_filter_method=   s    c      
   C   s,  t  i d t  i t  i B } d } x| i |  i  D]ď} | d 7} | i d  } | i d  } | i d  } | i d  } t	 |  d j o | d p d } t	 |  d j p | d d j o t
 d	 t   n | d
 j o< t	 |  d j o% | d j o |  i i | d  q(n | d j o5 t	 |  d j o | d j o |  i i   qjn xˇ |  i D]Ź \ }	 }
 d |  i d f d | f d | f d | f g } t t g  } | D]. \ } } | |
 i |  p |
 | | j qÂ~  o# |	 |  i | | d i |   qtqtWq5 W| S(   s   
		Trigger the actual parse.
		
		>>> p = PdParser("patches/parser-test.pd")
		>>> print p.parse(), "elements found"
		49 elements found
		s   (#(.*?)[^\\]);
i    i   t    i   i   t    t   #s)   Type did not begin with '#' at element %ds   #Ni   R	   i   s   #Xt   restorei˙˙˙˙t   typet   actiont   object(   t   ret   compilet	   MULTILINEt   DOTALLt   finditerR   t   groupt   splitt   popt   lenR   t   lR	   R   R
   t   reduceR    t   has_keyt   join(   R   t
   element_ret   countt   foundt   linet   bitsR   R   R   R   t   filtert   testFilterst   _[1]t   ft   t(    (    s   ./PdParser.pyt   parseZ   s0     
$&  
 1L+(   R   R   t   __doc__R   R   R1   (    (    (    s   ./PdParser.pyR      s   		c          C   s   d d  k  }  |  i   d  S(   Ni˙˙˙˙(   t   doctestt   testmod(   R3   (    (    s   ./PdParser.pyt   _test   s    t   __main__(    (	   R2   t   operatorR    R   t	   ExceptionR   R   R5   R   (    (    (    s   ./PdParser.pys   <module>   s   w	