Author: chrisz
Date: Fri Sep 23 20:46:46 2005
New Revision: 3241
Modified:
Webware/trunk/PSP/BraceConverter.py
Webware/trunk/PSP/Context.py
Webware/trunk/PSP/Docs/UsersGuide.rawhtml
Webware/trunk/PSP/Generators.py
Webware/trunk/PSP/PSPCompiler.py
Webware/trunk/PSP/PSPPage.py
Webware/trunk/PSP/PSPParser.py
Webware/trunk/PSP/PSPServletFactory.py
Webware/trunk/PSP/PSPUtils.py
Webware/trunk/PSP/ParseEventHandler.py
Webware/trunk/PSP/ServletWriter.py
Webware/trunk/PSP/StreamReader.py
Webware/trunk/PSP/Tests/CompileTest.py
Webware/trunk/PSP/Tests/PSPUtilsTest.py
Webware/trunk/PSP/cl_psp.py
Log:
Cleanup efforts in PSP code, made PSPTests example run again
Modified: Webware/trunk/PSP/BraceConverter.py
==============================================================================
--- Webware/trunk/PSP/BraceConverter.py (original)
+++ Webware/trunk/PSP/BraceConverter.py Fri Sep 23 20:46:46 2005
@@ -1,26 +1,28 @@
-"""
- BraceConverter (2000-09-04) by Dave Wallace (dwallace@...)
-
- Converts Brace-blocked Python into normal indented Python.
- Brace-blocked Python is non-indentation aware and blocks are delimited by ':{' and '}' pairs.
-
- Thus:
- for x in range(10) :{
- if x%2 :{ print x } else :{ print z }
- }
-
- Becomes: (roughly, barring some spurious newlines)
- for x in range(10) :
- if x%2 :
- print x
- else :
- print z
-
- This implementation is fed a line at a time via parseLine(), outputs to
- a PSPServletWriter, and tracks the current quotation and block levels internally.
-
+
+"""BraceConverter.py
+
+ Contributed 2000-09-04 by Dave Wallace (dwallace@...)
+
+ Converts Brace-blocked Python into normal indented Python.
+ Brace-blocked Python is non-indentation aware and blocks are delimited by ':{' and '}' pairs.
+
+ Thus:
+ for x in range(10) :{
+ if x%2 :{ print x } else :{ print z }
+ }
+
+ Becomes (roughly, barring some spurious newlines):
+ for x in range(10) :
+ if x%2 :
+ print x
+ else :
+ print z
+
+ This implementation is fed a line at a time via parseLine(), outputs to
+ a PSPServletWriter, and tracks the current quotation and block levels internally.
"""
+
import re
import string
import sys
@@ -28,168 +30,163 @@
class BraceConverter:
- CSKIP = re.compile("(^[^\"'{}:#]+)")
- COLONBRACE=re.compile(":\s*{\s*([^\s].*)?$")
-
- def __init__(self):
- self.inquote = 0
- self.dictlevel = 0
-
-
- # The only public method of this class, call with subsequent lines and an
- # instance of PSPServletWriter
- def parseLine(self,line,writer):
- self.line = line
-
- if self.inquote and self.line:
- self.skipquote(writer)
-
- self.line = string.lstrip(self.line)
- if not self.line:
- writer.printChars('\n')
- return
-
- writer.printIndent()
-
- while self.line:
- while self.inquote and self.line:
- self.skipquote(writer)
-
- match = self.CSKIP.search(self.line)
- if match:
- writer.printChars(self.line[:match.end(1)])
- self.line = self.line[match.end(1):]
- else:
- ch = self.line[0]
- if ch == "'":
- self.handleQuote("'",writer)
- self.skipquote(writer)
- elif ch == '"':
- self.handleQuote('"',writer)
- self.skipquote(writer)
- elif ch == '{':
- self.openBrace(writer)
- elif ch == '}':
- self.closeBrace(writer)
- elif ch == ':':
- self.openBlock(writer)
- elif ch == '#':
- writer.printChars(self.line)
- self.line=""
- else:
- # should never get here
- raise Exception()
- else:
- writer.printChars('\n')
-
-
-
-
- # open a new block
- def openBlock(self,writer):
- match = self.COLONBRACE.match(self.line)
- if match and not self.dictlevel:
- writer.printChars(":")
- writer.pushIndent()
- if match.group(1):
- # text follows :{, if its a comment leave it on the same line
- # else start a new line and leave the text for processing
- if match.group(1)[0] == '#':
- writer.printChars(" " + match.group(1))
- self.line = ""
- else:
- writer.printChars('\n')
- writer.printIndent()
- self.line = match.group(1)
- else:
- self.line = ""
- else:
- writer.printChars(":")
- self.line = self.line[1:]
-
- # open brace encountered
- def openBrace(self,writer):
- writer.printChars("{")
- self.line=self.line[1:]
- self.dictlevel = self.dictlevel + 1
-
- # close brace encountered
- def closeBrace(self,writer):
- if self.dictlevel:
- writer.printChars("}")
- self.line=self.line[1:]
- self.dictlevel = self.dictlevel - 1
- else:
- writer.popIndent()
- self.line = string.lstrip(self.line[1:])
- if (self.line):
- writer.printChars('\n')
- writer.printIndent()
-
- # skip over all chars until the line is exhausted
- # or the current non-escaped quote sequence is encountered
- def skipquote(self,writer):
- pos = string.find(self.line,self.quotechars)
- if -1 == pos:
- writer.printChars(self.line)
- self.line=""
- elif (pos > 0) and self.line[pos-1] == '\\':
- pos = pos +1
- writer.printChars(self.line[:pos])
- self.line = self.line[pos:]
- self.skipquote(writer)
- else:
- pos = pos + len(self.quotechars)
- writer.printChars(self.line[:pos])
- self.line = self.line[pos:]
- self.inquote = 0
-
- # Check and handle if current pos is a single or triple quote
- def handleQuote(self,quote,writer):
- self.inquote=1
- triple = quote*3
- if self.line[0:3]==triple:
- self.quotechars=triple
- writer.printChars(triple)
- self.line = self.line[3:]
- else:
- self.quotechars=quote
- writer.printChars(quote)
- self.line = self.line[1:]
+ CSKIP = re.compile("(^[^\"'{}:#]+)")
+ COLONBRACE=re.compile(":\s*{\s*([^\s].*)?$")
+ def __init__(self):
+ self.inquote = 0
+ self.dictlevel = 0
+
+ def parseLine(self,line,writer):
+ """Parse a line.
+
+ The only public method of this class, call with subsequent lines
+ and an instance of PSPServletWriter.
+
+ """
+ self.line = line
+ if self.inquote and self.line:
+ self.skipquote(writer)
+ self.line = string.lstrip(self.line)
+ if not self.line:
+ writer.printChars('\n')
+ return
+ writer.printIndent()
+ while self.line:
+ while self.inquote and self.line:
+ self.skipquote(writer)
+ match = self.CSKIP.search(self.line)
+ if match:
+ writer.printChars(self.line[:match.end(1)])
+ self.line = self.line[match.end(1):]
+ else:
+ ch = self.line[0]
+ if ch == "'":
+ self.handleQuote("'",writer)
+ self.skipquote(writer)
+ elif ch == '"':
+ self.handleQuote('"',writer)
+ self.skipquote(writer)
+ elif ch == '{':
+ self.openBrace(writer)
+ elif ch == '}':
+ self.closeBrace(writer)
+ elif ch == ':':
+ self.openBlock(writer)
+ elif ch == '#':
+ writer.printChars(self.line)
+ self.line=""
+ else:
+ # should never get here
+ raise Exception()
+ else:
+ writer.printChars('\n')
+
+ def openBlock(self,writer):
+ """Open a new block."""
+ match = self.COLONBRACE.match(self.line)
+ if match and not self.dictlevel:
+ writer.printChars(":")
+ writer.pushIndent()
+ if match.group(1):
+ # text follows :{, if its a comment leave it on the same line
+ # else start a new line and leave the text for processing
+ if match.group(1)[0] == '#':
+ writer.printChars(" " + match.group(1))
+ self.line = ""
+ else:
+ writer.printChars('\n')
+ writer.printIndent()
+ self.line = match.group(1)
+ else:
+ self.line = ""
+ else:
+ writer.printChars(":")
+ self.line = self.line[1:]
+
+ def openBrace(self,writer):
+ """Open brace encountered."""
+ writer.printChars("{")
+ self.line=self.line[1:]
+ self.dictlevel = self.dictlevel + 1
+
+ def closeBrace(self,writer):
+ """Close brace encountered."""
+ if self.dictlevel:
+ writer.printChars("}")
+ self.line=self.line[1:]
+ self.dictlevel = self.dictlevel - 1
+ else:
+ writer.popIndent()
+ self.line = string.lstrip(self.line[1:])
+ if (self.line):
+ writer.printChars('\n')
+ writer.printIndent()
+
+ def skipquote(self,writer):
+ """Skip to end of quote.
+
+ Skip over all chars until the line is exhausted
+ or the current non-escaped quote sequence is encountered.
+
+ """
+ pos = string.find(self.line,self.quotechars)
+ if -1 == pos:
+ writer.printChars(self.line)
+ self.line=""
+ elif (pos > 0) and self.line[pos-1] == '\\':
+ pos = pos +1
+ writer.printChars(self.line[:pos])
+ self.line = self.line[pos:]
+ self.skipquote(writer)
+ else:
+ pos = pos + len(self.quotechars)
+ writer.printChars(self.line[:pos])
+ self.line = self.line[pos:]
+ self.inquote = 0
+
+ def handleQuote(self,quote,writer):
+ "Check and handle if current pos is a single or triple quote."""
+ self.inquote=1
+ triple = quote*3
+ if self.line[0:3]==triple:
+ self.quotechars=triple
+ writer.printChars(triple)
+ self.line = self.line[3:]
+ else:
+ self.quotechars=quote
+ writer.printChars(quote)
+ self.line = self.line[1:]
### testing
-if __name__ == "__main__":
- from ServletWriter import ServletWriter
- # for stand alone testing
- class DummyWriter(ServletWriter):
- def __init__(self):
- self._filehandle = sys.stdout
- self._tabcnt = 0
- self._blockcount = 0 # a hack to handle nested blocks of python code
- self._indentSpaces = ServletWriter.SPACES
- self._useTabs=1
- self._useBraces=0
- self._indent='\t'
- self._userIndent = ServletWriter.EMPTY_STRING
-
-
- test=r"""
- for x in range(10) :{ q={
- 'test':x
- }
- print x
- }
-
- for x in range(10) :{ q={'test':x}; print x} else :{ print "\"done\"" #""}{
- x = { 'test1':{'sub2':{'subsub1':2}} # yee ha
- }
- } print "all done"
-
- """
- p = BraceConverter()
- dw = DummyWriter()
-
- for line in test.split('\n'):
- p.parseLine(line,dw)
+if __name__ == "__main__":
+ from ServletWriter import ServletWriter
+ # For stand alone testing:
+ class DummyWriter(ServletWriter):
+ def __init__(self):
+ self._filehandle = sys.stdout
+ self._tabcnt = 0
+ self._blockcount = 0 # a hack to handle nested blocks of python code
+ self._indentSpaces = ServletWriter.SPACES
+ self._useTabs=1
+ self._useBraces=0
+ self._indent='\t'
+ self._userIndent = ServletWriter.EMPTY_STRING
+ test = r'''
+ for x in range(10) :{ q={
+ 'test':x
+ }
+ print x
+ }
+
+ for x in range(10) :{ q={'test':x}; print x} else :{ print "\"done\"" #""}{
+ x = { 'test1':{'sub2':{'subsub1':2}} # yee ha
+ }
+ } print "all done"
+
+ '''
+ p = BraceConverter()
+ dw = DummyWriter()
+ for line in test.split('\n'):
+ p.parseLine(line,dw)
Modified: Webware/trunk/PSP/Context.py
==============================================================================
--- Webware/trunk/PSP/Context.py (original)
+++ Webware/trunk/PSP/Context.py Fri Sep 23 20:46:46 2005
@@ -1,46 +1,46 @@
-"""
-A utility class that holds information about the file we are parsing and the
-environment we are doing it in.
+"""Utility class for keeping track of the context.
---------------------------------------------------------------------------
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+ A utility class that holds information about the file we are parsing
+ and the environment we are doing it in.
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+ (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- This software is based in part on work done by the Jakarta group.
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee or royalty is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation or portions thereof, including modifications,
+ that you make.
+
+ THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
-"""
+ This software is based in part on work done by the Jakarta group.
+"""
from ParseEventHandler import *
import os
-"""
-Holds all the common stuff that various parts of the compilation will need access to.
-The items in this class will be used by both the compiler and the class generator.
-"""
-
class PSPContext:
- """ PSPContext is an abstract base class for Context classes."""
+ """PSPContext is an abstract base class for Context classes.
+
+ Holds all the common stuff that various parts of the compilation
+ will need access to. The items in this class will be used by both
+ the compiler and the class generator.
+
+ """
+
def __init__(self):
raise NotImplementedError
-
def getClassPath(self):
raise NotImplementedError
@@ -51,16 +51,18 @@
raise NotImplementedError
def getOutputDirectory(self):
- """provide directory to dump PSP source file to"""
+ """Provide directory to dump PSP source file to."""
raise NotImplementedError
def getServletClassName(self):
- """returns the class name of the servlet being generated"""
+ """Return the class name of the servlet being generated."""
raise NotImplementedError
def getFullClassName(self):
- """return class name including package prefixes
- Wont use this for now"""
+ """Return class name including package prefixes.
+
+ Won't use this for now.
+ """
raise NotImplementedError
def getPythonFileName(self):
@@ -68,38 +70,38 @@
raise NotImplementedError
def setPSPReader(self):
- """set the PSPReader for this context"""
+ """Set the PSPReader for this context."""
raise NotImplementedError
def setServletWriter(self):
- """set the PSPWriter instance for this context"""
+ """Set the PSPWriter instance for this context."""
raise NotImplementedError
def setPythonFileName(self):
- """sets the name of the .py file to generate"""
+ """Set the name of the .py file to generate."""
raise NotImplementedError
+#I'll implement this as I need it:
+class PSPCLContext(PSPContext):
+ """A context for command line compilation.
+ Currently used for both cammand line and PSPServletEngine compilation.
+ This class provides all the information necessary during the parsing
+ and page generation steps of the PSP compilation process.
+
+ """
-#I'll implement this as I need it
-class PSPCLContext(PSPContext):
- """a context for command line compilation. Currently used for both cammand line and PSPServletEngine compilation.
- This class provides all the information necessary during the parsing and page generation steps of the PSP compilation
- process."""
-
def __init__(self, pspfile, trans=None):
- #self._transactrion = trans #I don't think I need this
+ #self._transactrion = trans # I don't think I need this
self._baseUri, self._pspfile = os.path.split(pspfile)
- self._fullpath = pspfile#os.path.join(path,pspfile)#trans.application().pathForServletInTransaction(trans)
+ self._fullpath = pspfile
-
-
def getClassPath(self):
raise NotImplementedError
def getReader(self):
- """return the PSPReader object assigned to this context"""
+ """Return the PSPReader object assigned to this context."""
return self._pspReader
def getServletWriter(self):
@@ -107,21 +109,29 @@
return self._servletWriter
def getOutputDirectory(self):
- """provide directory to dump PSP source file to. I am probably doing this in reverse order at the moment.
- I should start with this and get the python filename from it."""
+ """Provide directory to dump PSP source file to.
+
+ I am probably doing this in reverse order at the moment.
+ I should start with this and get the python filename from it.
+
+ """
return os.path.split(self._pyFileName)[0]
def getServletClassName(self):
- """returns the class name of the servlet being generated"""
+ """Return the class name of the servlet being generated.
+
+ """
return self._className
def getFullClassName(self):
- """return class name including package prefixes
- Wont use this for now"""
+ """Return class name including package prefixes.
+
+ Won't use this for now.
+ """
raise NotImplementedError
def getPythonFileName(self):
- """the filename that we are generating to"""
+ """The filename that we are generating to."""
return self._pyFileName
def getPspFileName(self):
@@ -131,25 +141,29 @@
return self._fullpath
def setPSPReader(self, reader):
- """set the PSPReader for this context"""
+ """Set the PSPReader for this context."""
self._pspReader = reader
-
+
def setServletWriter(self, writer):
- """set the ServletWriter instance for this context"""
+ """Set the ServletWriter instance for this context."""
self._servletWriter = writer
-
def setPythonFileName(self,name):
- """sets the name of the .py file to generate"""
+ """Sets the name of the .py file to generate."""
self._pyFileName = name
def setClassName(self , name):
- """set the class name to create"""
+ """Set the class name to create."""
self._className = name
def resolveRelativeURI(self, uri):
- """This is used mainly for including files. It simply returns the location relative to the base context
- directory, ie Examples/. If the filename has a leading /, it is assumed to be an absolute path. """
+ """This is used mainly for including files.
+
+ It simply returns the location relative to the base context
+ directory, ie Examples/. If the filename has a leading /,
+ it is assumed to be an absolute path.
+
+ """
if os.path.isabs(uri):
return uri
else:
@@ -157,7 +171,3 @@
def getBaseUri(self):
return self._baseUri
-
-
-
-
Modified: Webware/trunk/PSP/Docs/UsersGuide.rawhtml
==============================================================================
--- Webware/trunk/PSP/Docs/UsersGuide.rawhtml (original)
+++ Webware/trunk/PSP/Docs/UsersGuide.rawhtml Fri Sep 23 20:46:46 2005
@@ -63,10 +63,10 @@
for this page, it will be dynamically compiled into a WebKit servlet class, and an
instance of this class will be instantiated to serve requests for that page.</p>
-<p>There are two general types of PSP tags, <span class="pyInline"><%</span> and <span class="pyInline"><psp:</span>. Each of these tags have special characteristics, described below.</p>
+<p>There are two general types of PSP tags, <span class="py"><%...%></span> and <span class="py"><psp:...></span>. Each of these tags have special characteristics, described below.</p>
<p>Whether or not you will need to include standard HTML tags in the start of your PSP page,
- such as <HTML> and <head>, etc depends on the base class you choose for your
+ such as <html>, <head> etc. depends on the base class you choose for your
PSP class. The default setup does not output any of those tags automatically.</p>
<a name="Tags"></a><h2>PSP Tags</h2>
@@ -84,14 +84,14 @@
<pre class="py">The current time is <%= time.time() %></pre>
<p>When the PSP parsing engine encounters Expression tags, it wraps the contents in a call to the
-python <i>str()</i> function. Multiple lines are not supported in a PSP expression tag.</p>
+Python <i>str()</i> function. Multiple lines are not supported in a PSP expression tag.</p>
<a name="ScriptTag"></a><h3>Script Tag – <% script code %></h3>
<p>The script tag is used to enclose Python code that should be run by the WebKit Servlet
runner when requests are processed by the Servlet which this PSP page produces. Any valid Python
code can be used in Script tags. Inside a script tag, indentation is up to the author, and is used
-just like in regular python. (More info on blocks below) The PSP Engine actually just outputs the strings in a Script tag
+just like in regular Python. (More info on blocks below) The PSP Engine actually just outputs the strings in a Script tag
into the method body that is being produced by this PSP page.</p>
<a name="4.2.1.1"></a><h5>Example</h5>
@@ -158,9 +158,9 @@
<a name="Braces"></a><h4>Braces</h4>
<p>PSP also supports using braces to handle indentation.
-This goes against the grain of python, we know, but is useful for this specific application.
+This goes against the grain of Python, we know, but is useful for this specific application.
To use this feature, specify it as you indentation style in a page directive, like so:
-<span class="pyInline"><%@page indentType="braces" %></span></p>
+<span class="py"><%@page indentType="braces" %></span></p>
<p>Now use braces to signify the start and end of blocks.
The braces can span multiple script tags. No automatic indentation will occur.
@@ -210,7 +210,7 @@
<a name="5.1.1.2"></a><h5>Example</h5>
-<p>At the class level you can define methods using ordinary python syntax instead of the <psp:method > syntax below.</p>
+<p>At the class level you can define methods using ordinary Python syntax instead of the <psp:method > syntax below.</p>
<pre class="py"><psp:class><br> def writeNavBar(self):
for uri, title in self.menuPages():
@@ -223,7 +223,7 @@
That is no problem, PSP will adjust accordingly.</p>
<p>There is one special case with adding methods via the <psp:class> tag.
-The <span class="pyInline">awake()</span> method requires special handling,
+The <span class="py">awake()</span> method requires special handling,
so you should always use the <psp:method> tag below if you want to override the awake() method.</p>
<p>The <psp:file> and <psp:class> tags were added to Webware v0.91</p>
@@ -269,7 +269,7 @@
the WebKit Application's forwardRequestFast function, which means that the current Request, Response and Session objects
will also be used by the URL to which this request is sent.</p>
-<p><b>Example:</b> <span class="pyInline"><psp:include path="myfile.html" ></span></p>
+<p><b>Example:</b> <span class="py"><psp:include path="myfile.html" ></span></p>
<a name="PSPInsert"></a><h3>Insert Tag – <psp:insert ...></h3>
@@ -286,7 +286,7 @@
Setting this attribute to true will cause the inserted file's contents to be embedded in the PSP class at generation time.
Any subsequent changes to the file will not be seen by the servlet. (This was the default behavior prior to PSP 0.4).</p>
-<p><b>Example:</b> <span class="pyInline"><psp:insert file="myfile.html" ></span></p>
+<p><b>Example:</b> <span class="py"><psp:insert file="myfile.html" ></span></p>
<a name="Directives"></a><h2>Directives</h2>
@@ -306,26 +306,26 @@
<ul>
<li><p><span class="typed">imports</span> –
-The imports attribute of the page directive tells the PSP parser to import certain python modules into the PSP Class source file.</p>
+The imports attribute of the page directive tells the PSP parser to import certain Python modules into the PSP Class source file.</p>
<p>The format of this directive is as follows:</p>
-<p><b>Example:</b> <span class="pyInline"><%@ page imports="sys,os"%></span></p>
+<p><b>Example:</b> <span class="py"><%@ page imports="sys,os"%></span></p>
<p>The value of the imports parameter may have multiple, comma separated items.</p>
<p><i>from X import Y</i> is supported by separating the source package from the object to be imported with a colon (:), like this:</p>
-<p><b>Example:</b> <span class="pyInline"><%@ page imports="os:path" %></span> This will import the path object from the os module.</p>
+<p><b>Example:</b> <span class="py"><%@ page imports="os:path" %></span> This will import the path object from the os module.</p>
-<p>Please note the <b>=</b> sign used in this directive. Those who are used to python might try to skip it.</p></li>
+<p>Please note the <b>=</b> sign used in this directive. Those who are used to Python might try to skip it.</p></li>
<li><p><span class="typed">extends</span> –
The extends attribute of the page tells the PSP parser what base class this Servlet should be derived from.
The PSP servlet produced by parsing the PSP file will inherit all of the attributes and methods of the base class.
The Servlet will have access to each of those atributes and methods. They will still need to be accessed using the self. sytax of Python.</p>
-<p><b>Example:</b> <span class="pyInline"><%@ page extends="MyPSPBaseClass"%></span></p>
+<p><b>Example:</b> <span class="py"><%@ page extends="MyPSPBaseClass"%></span></p>
<p>This is a very powerful feature of PSP and Webware.
The developer can code a series of Servlets that have common functionality for a series of pages,
@@ -343,7 +343,7 @@
The <i>method</i> attribute of the <i>page</i> directive tells the PSP parser which method
of the base class the HTML of this PSP page should be placed in and override.</p>
-<p><b>Example:</b> <span class="pyInline"><%@ page method="WriteHTML"%></span></p>
+<p><b>Example:</b> <span class="py"><%@ page method="WriteHTML"%></span></p>
<p>Standard methods are WriteHTML, of the standard HTTPServlet class, and writeBody, of the Page and PSPPage classes.
The default is writeBody. However, depending on the base class you choose for your PSP class, you may want to override some other method.</p></li>
@@ -352,7 +352,7 @@
The <i>isThreadSafe</i> attribute of <i>page</i> tells the PSP parser whether the class it is producing
can be utilized by multiple threads simultaneously. This is analogous to the isThreadSafe function in WebKit servlets.</p>
-<p><b>Example:</b> <span class="pyInline"><%@ page threadSafe="yes"%></span></p>
+<p><b>Example:</b> <span class="py"><%@ page threadSafe="yes"%></span></p>
<p>valid values are "yes" and "no". The default is "no".</p></li>
@@ -361,17 +361,17 @@
whether one instance of the class being produced may be used multiple times.
This is analogous to the isInstanceSafe function of WebKit Servlets.</p>
-<p><b>Example:</b> <span class="pyInline"> <%@ page isInstanceSafe="yes"%> </span></p>
+<p><b>Example:</b> <span class="py"> <%@ page isInstanceSafe="yes"%> </span></p>
<p>Valid values are "yes" and "no". The default is "yes".</p></li>
<li><p><span class="typed">indentType</span> –
-The <i>indentType </i> attribute of the page directive tells the parser how to handle block indention in the python sourcefile it creates.
+The <i>indentType </i> attribute of the page directive tells the parser how to handle block indention in the Python sourcefile it creates.
The <i> indentType</i> attribute sets whether the sourcefile will be indented with tabs or spaces, or braces.
Valid values are "tabs", "spaces" or "braces". If this is set to "spaces", see <i>indentSpaces</i> for setting the number of spaces to be used.
(also, see blocks, below). The default is "tabs"</p>
-<p><b>Example:</b> <span class="pyInline"><%@ page indentType="tabs"%></span></p>
+<p><b>Example:</b> <span class="py"><%@ page indentType="tabs"%></span></p>
<p>This is a bit of a tricky item, because many editors will automatically replace tabs with spaces in their output,
without the user realizing it. If you are having trouble with complex blocks, look at that first.</p></li>
@@ -379,7 +379,7 @@
<li><p><span class="typed">indentSpaces</span> –
Sets the number of spaces to be used for indentation when <i>indentType</i> is set to spaces. The default is "4".</p>
-<p><b>Example:</b> <span class="pyInline"> <%@ page indentSpaces="8" %></span></p></li>
+<p><b>Example:</b> <span class="py"> <%@ page indentSpaces="8" %></span></p></li>
<li><p><span class="typed">gobbleWhitespace</span> –
The <i>gobblewhitespace</i> attribute of the <i>page</i> directive tells the PSP parser whether it can safely assume
@@ -395,7 +395,7 @@
<p>If you do need whitespace between two script blocks, use the &nbsp; code.</p>
-<p><b>Example:</b> <span class="pyInline"><%@ page gobbleWhitspace="No"%></span></p>
+<p><b>Example:</b> <span class="py"><%@ page gobbleWhitspace="No"%></span></p>
<p>Valid values are "yes" and "no". The default is "yes".</p></li>
@@ -425,7 +425,7 @@
<a name="Other Tags"></a><h2>Other Tags</h2>
<ul>
-<li><b>Declaration</b> (<span class="pyInline"><%! ... %></span>) – No need for this tag. Simply use script tags to declare local variables.</li>
+<li><b>Declaration</b> (<span class="py"><%! ... %></span>) – No need for this tag. Simply use script tags to declare local variables.</li>
<li><b>Forwarding</b> functionality is now available in WebKit, but no tag based support has been added to PSP yet.</lI>
</ul>
Modified: Webware/trunk/PSP/Generators.py
==============================================================================
--- Webware/trunk/PSP/Generators.py (original)
+++ Webware/trunk/PSP/Generators.py Fri Sep 23 20:46:46 2005
@@ -1,13 +1,11 @@
+"""Generate Python code from PSP templates.
-"""
- This module holds the classes that generate the python code reulting from the PSP template file.
+ This module holds the classes that generate the Python code resulting from the PSP template file.
As the parser encounters PSP elements, it creates a new Generator object for that type of element.
Each of these elements is put into a list maintained by the ParseEventHandler object. When it comes
time to output the Source Code, each generator is called in turn to create it's source.
-
---------------------------------------------------------------------------------
(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
Permission to use, copy, modify, and distribute this software and its
@@ -25,12 +23,10 @@
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
- This software is based in part on work done by the Jakarta group.
+ This software is based in part on work done by the Jakarta group.
"""
-
-
import re
import PSPUtils
import BraceConverter
@@ -44,7 +40,7 @@
except:
pass
-#these are global so that the ParseEventHandler and this module agree.
+# These are global so that the ParseEventHandler and this module agree:
ResponseObject = 'res'
AwakeCreated = 0
@@ -57,9 +53,12 @@
class ExpressionGenerator(GenericGenerator):
- """ This class handles expression blocks. It simply outputs
- the (hopefully) python expression within the block wrapped
- with a _formatter() call. """
+ """This class handles expression blocks.
+
+ It simply outputs the (hopefully) python expression within the block
+ wrapped with a _formatter() call.
+
+ """
def __init__(self, chars):
self.chars = chars
@@ -69,27 +68,29 @@
writer.println('res.write(_formatter(' + PSPUtils.removeQuotes(self.chars) + '))')
+class CharDataGenerator(GenericGenerator):
+ """This class handles standard character output, mostly HTML.
+ It just dumps it out. Need to handle all the escaping of characters.
+ It's just skipped for now.
-class CharDataGenerator(GenericGenerator):
- """This class handles standard character output, mostly HTML. It just dumps it out.
- Need to handle all the escaping of characters. It's just skipped for now."""
+ """
def __init__(self, chars):
GenericGenerator.__init__(self)
self.chars = chars
def generate(self, writer, phase=None):
- # Quote any existing backslash so generated python will not interpret it when running.
+ # Quote any existing backslash so generated Python will not interpret it when running.
self.chars = string.replace(self.chars, '\\', r'\\')
- # quote any single quotes so it does not get confused with our triple-quotes
+ # Quote any single quotes so it does not get confused with our triple-quotes:
self.chars = string.replace(self.chars,'"',r'\"')
self.generateChunk(writer)
def generateChunk(self, writer, start=0, stop=None):
- writer.printIndent()#gives a tab
+ writer.printIndent() # gives a tab
writer.printChars(ResponseObject+'.write("""')
writer.printChars(self.chars)
writer.printChars('""")')
@@ -98,164 +99,174 @@
def mergeData(self, cdGen):
self.chars = self.chars + cdGen.chars
+
class ScriptGenerator(GenericGenerator):
- """generates scripts"""
+ """Generate scripts."""
+
def __init__(self, chars, attrs):
- GenericGenerator.__init__(self)
+ GenericGenerator.__init__(self)
self.chars = chars
def generate(self, writer, phase=None):
-
- self.chars = PSPUtils.normalizeIndentation( self.chars )
-
+ self.chars = PSPUtils.normalizeIndentation(self.chars, writer._indent)
if writer._useBraces:
- # send lines to be output by the braces generator
+ # Send lines to be output by the braces generator:
bc = BraceConverter.BraceConverter()
- lines = PSPUtils.splitLines( PSPUtils.removeQuotes(self.chars) )
+ lines = PSPUtils.splitLines(PSPUtils.removeQuotes(self.chars))
for line in lines:
bc.parseLine(line,writer)
return
-
-
- #check for whitespace at the beginning and if less than 2 spaces, remove
+ # Check for whitespace at the beginning and if less than 2 spaces, remove:
if self.chars[:1]==' ' and self.chars[:2]!= ' ':
self.chars=string.lstrip(self.chars)
- lines = PSPUtils.splitLines( PSPUtils.removeQuotes(self.chars) )
-
-
- #userIndent check
- if len(lines[-1])>0 and lines[-1][-1] == '$':
+ lines = PSPUtils.splitLines(PSPUtils.removeQuotes(self.chars))
+ # userIndent check
+ if len(lines[-1]) > 0 and lines[-1][-1] == '$':
lastline = lines[-1] = lines[-1][:-1]
- if lastline == '': lastline = lines[-2] #handle endscript marker on its own line
+ if lastline == '':
+ lastline = lines[-2] # handle endscript marker on its own line
count=0
while lastline[count] in string.whitespace:
- count=count+1
+ count = count + 1
userIndent = lastline[:count]
else:
userIndent = writer.EMPTY_STRING
- lastline=lines[-1]
-
- #print out code, (moved from above)
- writer._userIndent = writer.EMPTY_STRING #reset to none
+ lastline = lines[-1]
+ # Print out code (moved from above):
+ writer._userIndent = writer.EMPTY_STRING # reset to none
writer.printList(lines)
writer.printChars('\n')
-
- #check for a block
- #lastline = string.splitfields(PSPUtils.removeQuotes(self.chars),'\n')[-1]
+ # Check for a block:
+ # lastline = string.splitfields(PSPUtils.removeQuotes(self.chars),'\n')[-1]
commentstart = string.find(lastline,'#')
- if commentstart > 0: lastline = lastline[:commentstart]
+ if commentstart > 0:
+ lastline = lastline[:commentstart]
blockcheck=string.rstrip(lastline)
- if len(blockcheck)>0 and blockcheck[-1] == ':':
+ if len(blockcheck) > 0 and blockcheck[-1] == ':':
writer.pushIndent()
writer.println()
writer._blockcount = writer._blockcount+1
- #check for end of block, "pass" by itself
- if string.strip(self.chars) == 'pass' and writer._blockcount>0:
+ # Check for end of block, "pass" by itself:
+ if string.strip(self.chars) == 'pass' and writer._blockcount > 0:
writer.popIndent()
writer.println()
writer._blockcount = writer._blockcount-1
-
- #set userIndent for subsequent HTML
+ # Set userIndent for subsequent HTML:
writer._userIndent = userIndent
+
class EndBlockGenerator(GenericGenerator):
+
def __init__(self):
GenericGenerator.__init__(self)
def generate(self, writer, phase=None):
- if writer._blockcount>0:
+ if writer._blockcount > 0:
writer.popIndent()
writer.println()
writer._blockcount = writer._blockcount-1
writer._userIndent = writer.EMPTY_STRING
-
+
class ScriptFileGenerator(GenericGenerator):
- """
- Add Python code at the file/module level.
- """
+ """Add Python code at the file/module level."""
+
def __init__(self, chars, attrs):
GenericGenerator.__init__(self)
- self.phase='psp:file'
- self.attrs=attrs
- self.chars=chars
+ self.phase = 'psp:file'
+ self.attrs = attrs
+ self.chars = chars
def generate(self, writer, phase=None):
writer.println('\n# File level user code')
- pySrc = PSPUtils.normalizeIndentation( self.chars )
- pySrc = PSPUtils.splitLines( PSPUtils.removeQuotes(pySrc) )
+ pySrc = PSPUtils.normalizeIndentation(self.chars, writer._indent)
+ pySrc = PSPUtils.splitLines(PSPUtils.removeQuotes(pySrc))
writer.printList(pySrc)
class ScriptClassGenerator(GenericGenerator):
- """
- Add Python code at the class level.
- """
+ """Add Python code at the class level."""
+
def __init__(self, chars, attrs):
GenericGenerator.__init__(self)
- self.phase='psp:class'
- self.attrs=attrs
- self.chars=chars
+ self.phase = 'psp:class'
+ self.attrs = attrs
+ self.chars = chars
def generate(self, writer, phase=None):
writer.println('# Class level user code\n')
- pySrc = PSPUtils.normalizeIndentation( self.chars )
- pySrc = PSPUtils.splitLines( PSPUtils.removeQuotes(pySrc) )
+ pySrc = PSPUtils.normalizeIndentation(self.chars, writer._indent)
+ pySrc = PSPUtils.splitLines(PSPUtils.removeQuotes(pySrc))
writer.printList(pySrc)
class MethodGenerator(GenericGenerator):
- """ generates class methods defined in the PSP page. There are two parts to method generation. This
- class handles getting the method name and parameters set up."""
+ """Generate class methods defined in the PSP page.
+
+ There are two parts to method generation.
+ This class handles getting the method name and parameters set up.
+
+ """
+
def __init__(self, chars, attrs):
GenericGenerator.__init__(self)
- self.phase='Declarations'
- self.attrs=attrs
-
+ self.phase = 'Declarations'
+ self.attrs = attrs
+
def generate(self, writer, phase=None):
writer.printIndent()
writer.printChars('def ')
writer.printChars(self.attrs['name'])
writer.printChars('(')
- #self.attrs['params']
+ # self.attrs['params']
writer.printChars('self')
if self.attrs.has_key('params') and self.attrs['params'] != '':
writer.printChars(', ')
writer.printChars(self.attrs['params'])
writer.printChars('):\n')
- if self.attrs['name'] == 'awake': #This is hacky, need better method, but it works: MAybe I should require a standard parent and do the intPSP call in that awake???????
+ if self.attrs['name'] == 'awake':
+ # This is hacky, need better method, but it works.
+ # @@ Maybe I should require a standard parent and do the intPSP call in that awake?
AwakeCreated = 1
- #below indented on 6/1/00, was outside if block
+ # Below indented on 6/1/00, was outside if block:
writer.pushIndent()
writer.println('self.initPSP()\n')
writer.popIndent()
writer.println()
class MethodEndGenerator(GenericGenerator):
- """ Part of class method generation. After MethodGenerator, MethodEndGenerator actually generates
- the code for the method body."""
+ """Part of class method generation.
+
+ After MethodGenerator, MethodEndGenerator actually generates
+ the code for the method body.
+
+ """
+
def __init__(self, chars, attrs):
GenericGenerator.__init__(self)
- self.phase='Declarations'
- self.attrs=attrs
- self.chars=chars
+ self.phase = 'Declarations'
+ self.attrs = attrs
+ self.chars = chars
def generate(self, writer, phase=None):
writer.pushIndent()
- writer.printList( PSPUtils.splitLines( PSPUtils.removeQuotes(self.chars) ) )
+ writer.printList(PSPUtils.splitLines(PSPUtils.removeQuotes(self.chars)))
writer.printChars('\n')
writer.popIndent()
class IncludeGenerator(GenericGenerator):
- """
- Handles psp:include directives. This is a new version of this directive that actually
+ """Handle psp:include directives.
+
+ This is a new version of this directive that actually
forwards the request to the specified page.
+
"""
-# _theFunction = """
-#__pspincludepath = self.transaction().request().urlPathDir() + "%s"
-#self.transaction().application().includeURL(self.transaction(), __pspincludepath)
+ # _theFunction = """
+ # __pspincludepath = self.transaction().request().urlPathDir() + "%s"
+ # self.transaction().application().includeURL(self.transaction(), __pspincludepath)
+ # """
_theFunction = """
__pspincludepath = "%s"
self.transaction().application().includeURL(self.transaction(), __pspincludepath)
@@ -270,22 +281,23 @@
self.url = attrs.get('path')
if self.url == None:
raise "No path attribute in Include"
-
+
self.scriptgen = ScriptGenerator(self._theFunction % self.url, None)
-
def generate(self, writer, phase=None):
- """
- Just insert theFunction
- """
+ """Just insert theFunction."""
self.scriptgen.generate(writer, phase)
class InsertGenerator(GenericGenerator):
- """ Include files designated by the psp:insert syntax.
- If the attribute static is set to true or 1, we include the file now, at compile time.
- Otherwise, we use a function added to every PSP page named __includeFile, which reads the file at run time.
+ """Include files designated by the psp:insert syntax.
+
+ If the attribute static is set to true or 1, we include the file now,
+ at compile time. Otherwise, we use a function added to every PSP page
+ named __includeFile, which reads the file at run time.
+
"""
+
def __init__(self, attrs, param, ctxt):
GenericGenerator.__init__(self,ctxt)
self.attrs = attrs
@@ -298,24 +310,25 @@
raise "No Page attribute in Include"
thepath=self._ctxt.resolveRelativeURI(self.page)
-
self.static = attrs.get('static', None)
if self.static == string.lower("true") or self.static == "1":
self.static=1
-
+
if not os.path.exists(thepath):
print self.page
raise "Invalid included file",thepath
self.page=thepath
if not self.static:
- self.scriptgen = ScriptGenerator("self.__includeFile('%s')" % string.replace(thepath, '\\', '\\\\'), None)
+ self.scriptgen = ScriptGenerator("self.__includeFile('%s')"
+ % string.replace(thepath, '\\', '\\\\'), None)
def generate(self, writer, phase=None):
- """ JSP does this in the servlet. I'm doing it here because I have triple quotes.
- Note: res.write statements inflate the size of the resulting classfile when it is cached.
- Cut down on those by using a single res.write on the whole file, after escaping any triple-double quotes."""
-
+ # JSP does this in the servlet. I'm doing it here because
+ # I have triple quotes. # Note: res.write statements inflate
+ # the size of the resulting classfile when it is cached.
+ # Cut down on those by using a single res.write on the whole
+ # file, after escaping any triple-double quotes."""
if self.static:
data = open(self.page).read()
data=string.replace(data,'"""',r'\"""')
@@ -323,6 +336,3 @@
writer.println()
else:
self.scriptgen.generate(writer, phase)
-
-
-
Modified: Webware/trunk/PSP/PSPCompiler.py
==============================================================================
--- Webware/trunk/PSP/PSPCompiler.py (original)
+++ Webware/trunk/PSP/PSPCompiler.py Fri Sep 23 20:46:46 2005
@@ -1,9 +1,7 @@
-"""
-A simple little module. It organizes the actual page generation.
+"""A simple little module that organizes the actual page generation.
---------------------------------------------------------------------------
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+ (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee or royalty is hereby granted,
@@ -24,42 +22,28 @@
"""
-
from StreamReader import StreamReader
from ServletWriter import ServletWriter
from PSPParser import PSPParser
from ParseEventHandler import ParseEventHandler
-
-
-
class Compiler:
- """the main compilation class"""
+ """The main compilation class-"""
def __init__(self,context):
self._ctxt = context
-
def compile(self):
-
reader = StreamReader(self._ctxt.getPspFileName(),self._ctxt)
reader.init()
writer = ServletWriter(self._ctxt)
-
self._ctxt.setPSPReader(reader)
self._ctxt.setServletWriter(writer)
-
parser = PSPParser(self._ctxt)
handler = ParseEventHandler(self._ctxt,parser)
parser.setEventHandler(handler)
-
handler.beginProcessing()
parser.parse()
handler.endProcessing()
writer.close()
-
-
-
-
-
Modified: Webware/trunk/PSP/PSPPage.py
==============================================================================
--- Webware/trunk/PSP/PSPPage.py (original)
+++ Webware/trunk/PSP/PSPPage.py Fri Sep 23 20:46:46 2005
@@ -1,9 +1,11 @@
-"""This class is intended to be used in the future as the default base class
+"""Default base class for PSP pages.
+
+This class is intended to be used in the future as the default base class
for PSP pages in the event that some special processing is needed.
Right now, no special processing is needed, so the default base class
-for PSP pages is rhe standard WebKit Page.
-"""
+for PSP pages is the standard WebKit Page.
+"""
from WebKit.Page import Page
import string
@@ -21,6 +23,3 @@
self.parent.awake(self, trans)
self.out = trans.response()
-
-
-
Modified: Webware/trunk/PSP/PSPParser.py
==============================================================================
--- Webware/trunk/PSP/PSPParser.py (original)
+++ Webware/trunk/PSP/PSPParser.py Fri Sep 23 20:46:46 2005
@@ -1,10 +1,10 @@
-"""
-This module handles the actual reading of the characters in the source psp file
-and checking it for valid psp tokens. When it finds one, it calls ParseEventHandler
-with the characters it found.
+"""The PSP parser.
+
+ This module handles the actual reading of the characters in the source
+ PSP file and checking it for valid psp tokens. When it finds one,
+ it calls ParseEventHandler with the characters it found.
---------------------------------------------------------------------------
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+ (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee or royalty is hereby granted,
@@ -21,7 +21,7 @@
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
- This software is based in part on work done by the Jakarta group.
+ This software is based in part on work done by the Jakarta group.
"""
@@ -33,35 +33,45 @@
from StringIO import StringIO
-
class PSPParser:
- """ The PSPParser class does the actual sniffing through the input file looking for anything we're interested in.
- Basically, it starts by looking at the code looking for a '<' symbol. It looks at the code by working with a PSPReader
- object, which handle the current location in the code. When it finds one, it calls a list of functions, the xxxChecks,
- asking each if it recognizes the characters as its kind of input. When the check functions look at the characters,
- if they want it, they go ahead and gobble it up and set up to create it in the Servlet when the time comes. When they
- return, they return true if they acceptes the character, and the PSPReader object cursor is positioned past the end of
- the block that the check function accepted."""
+ """The main PSP parser class.
+
+ The PSPParser class does the actual sniffing through the input file
+ looking for anything we're interested in. Basically, it starts by
+ looking at the code looking for a '<' symbol. It looks at the code by
+ working with a PSPReader object, which handle the current location in
+ the code. When it finds one, it calls a list of functions, the xxxChecks,
+ asking each if it recognizes the characters as its kind of input.
+ When the check functions look at the characters, if they want it,
+ they go ahead and gobble it up and set up to create it in the servlet
+ when the time comes. When they return, they return true if they accept
+ the character, and the PSPReader object cursor is positioned past the
+ end of the block that the check function accepted.
+
+ """
checklist=[]
-
- def __init__(self,ctxt):
+ def __init__(self,ctxt):
self._reader = ctxt.getReader()
self._writer = ctxt.getServletWriter()
self._handler = None
-
- self.cout = StringIO() #This is where we dump straight HTML code that none of the checks want
- self.tmplStart=0 #marks the start of HTML code
+ self.cout = StringIO() # This is where we dump straight HTML code that none of the checks want
+ self.tmplStart = 0 # marks the start of HTML code
self.tmplStop = 0 #marks the end of HTML code
self.currentFile = self._reader.Mark().getFile()
def setEventHandler(self,handler):
- """Set the handler this parser will use when it finds psp code."""
+ """Set the handler this parser will use when it finds PSP code."""
self._handler = handler
def flushCharData(self, start, stop):
- """Dump all the HTML that we've accumulated over to the character data handler in the event handler object."""
+ """Dump everything to the char data handler.
+
+ Dump all the HTML that we've accumulated over to the character data
+ handler in the event handler object.
+
+ """
data = self.cout.getvalue()
self.cout.close()
if len(data) > 0: # make sure there's something there
@@ -69,37 +79,30 @@
self.cout = StringIO()
def commentCheck(self, handler, reader):
- """Comments just get eaten"""
+ """Comments just get eaten."""
OPEN_COMMENT = '<%--'
CLOSE_COMMENT = '--%>'
-
if reader.Matches(OPEN_COMMENT):
reader.Advance(len(OPEN_COMMENT))
start = reader.Mark()
stop = reader.skipUntil(CLOSE_COMMENT)
if stop == None:
raise 'ParseException'
-
self.flushCharData(self.tmplStart, self.tmplStop)
return 1
return 0
- checklist.append(commentCheck) #add this checker to the list that the parse function will call
-
+ checklist.append(commentCheck) # add this checker to the list that the parse function will call
def checkExpression(self, handler, reader):
- """ Look for "expressions" and handle them"""
-
- OPEN_EXPR = '<%='
- CLOSE_EXPR = '%>'
+ """Look for "expressions" and handle them"""
+ OPEN_EXPR = '<%='
+ CLOSE_EXPR = '%>'
end_open = None
- attrs=None
-
+ attrs = None
if not reader.Matches(OPEN_EXPR):
return 0
-
- reader.Advance(len(OPEN_EXPR)) #eat the opening tag
-
+ reader.Advance(len(OPEN_EXPR)) # eat the opening tag
if end_open != None:
attrs = reader.parseTagAttributes()
reader.skipSpaces()
@@ -107,9 +110,8 @@
raise 'ParseException'
reader.Advance(len(end_open))
reader.skipSpaces()
- #below not implemented
- #PSPUtil.checkAttrs('Expression',attrs,validAttrs)
-
+ # below not implemented
+ # PSPUtil.checkAttrs('Expression',attrs,validAttrs)
reader.peekChar()
reader.skipSpaces()
start = reader.Mark()
@@ -122,68 +124,55 @@
checklist.append(checkExpression)
-
-
def checkDirective(self, handler, reader):
- """ Check for directives. I support two right now, page and include."""
+ """Check for directives. I support two right now, page and include."""
validDirectives = ['page','include']
OPEN_DIRECTIVE = r'<%@'
CLOSE_DIRECTIVE = r'%>'
-
if reader.Matches(OPEN_DIRECTIVE):
opening = OPEN_DIRECTIVE
close = CLOSE_DIRECTIVE
else:
return 0
start = reader.Mark()
-
reader.Advance(len(OPEN_DIRECTIVE))
-
- match = None
+ match = None
reader.skipSpaces()
- for i in validDirectives:
+ for i in validDirectives:
if reader.Matches(i):
match = i
break
-
if match == None:
raise 'Invalid Directive'
-
reader.Advance(len(match))
-
- #parse the directive attr:val pair dictionary
+ # parse the directive attr:val pair dictionary
attrs = reader.parseTagAttributes()
-## not checking for validity yet
-## if match == 'page':
-## PSPUtils.checkAttributes('Page Directive', attrs, pageDvalidAttrs)
-## elif match == 'include':
-## PSPUtils.checkAttributes('Include Directive', attrs, includeDvalidAttrs)
-## elif match == 'taglib':
-## raise 'Not Implemented Error'
-
- #match close
+ # not checking for validity yet
+ # if match == 'page':
+ # PSPUtils.checkAttributes('Page Directive', attrs, pageDvalidAttrs)
+ # elif match == 'include':
+ # PSPUtils.checkAttributes('Include Directive', attrs, includeDvalidAttrs)
+ # elif match == 'taglib':
+ # raise 'Not Implemented Error'
+ # match close
reader.skipSpaces() #skip to where we expect a close tag
if not reader.Matches(close):
raise 'Unterminated directive error'
else:
reader.Advance(len(close)) #advance past it
stop = reader.Mark()
-
handler.setTemplateInfo(self.tmplStart, self.tmplStop)
handler.handleDirective(match, start, stop, attrs)
-
return 1
checklist.append(checkDirective)
-
def checkEndBlock(self, handler, reader):
OPEN_SCRIPT='<%'
CLOSE_SCRIPT='%>'
CLOSE_SCRIPT2='$%>'
CENTER_SCRIPT='end'
start=reader.Mark()
-
if reader.Matches(OPEN_SCRIPT):
reader.Advance(len(OPEN_SCRIPT))
reader.skipSpaces()
@@ -201,41 +190,33 @@
handler.handleEndBlock()
print ">>>>Putting a $ at the end of an end tag does nothing, I Say"
return 1
- #that wasn't it
+ # that wasn't it
reader.reset(start)
return 0
checklist.append(checkEndBlock)
-
-
-
def checkScript(self, handler, reader):
- """ The main thing we're after. Check for embedded scripts"""
- OPEN_SCRIPT = '<%'
- CLOSE_SCRIPT = '%>'
+ """The main thing we're after. Check for embedded scripts."""
+ OPEN_SCRIPT = '<%'
+ CLOSE_SCRIPT = '%>'
attrs=None
-
end_open = None
-
if reader.Matches(OPEN_SCRIPT):
open = OPEN_SCRIPT
close = CLOSE_SCRIPT
else:
return 0
-
- reader.Advance(len(open))#Matches advances it
-
+ reader.Advance(len(open))# Matches advances it
if end_open != None:
attrs = reader.parseTagAttributes()
-
reader.skipSpaces()
if not reader.Matches(end_open):
raise 'Unterminated script'
reader.Advance(len(end_open))
reader.skipSpaces()
PSPUtils.checkAttributes('Script', attrs, ValidAttributes)
- #reader.skipSpaces() #don't skip as spaces may be significant, leave this for the generator
+ # reader.skipSpaces() # don't skip as spaces may be significant, leave this for the generator
start = reader.Mark()
try:
stop = reader.skipUntil(close)
@@ -249,92 +230,86 @@
checklist.append(checkScript)
-
def checkScriptFile(self, handler, reader):
- """
- Check for python code that should go in the beginning of the generated module.
+ """Check for file level code.
+
+ Check for Python code that should go in the beginning of the generated module.
+
<psp:file>
import xyz
print 'hi Mome!'
def foo(): return 'foo'
- </psp:file>
- """
- OPEN_SCRIPT='<psp:file>'
- CLOSE_SCRIPT='</psp:file>'
- attrs=None
-
+ </psp:file>
+ """
+ OPEN_SCRIPT = '<psp:file>'
+ CLOSE_SCRIPT = '</psp:file>'
+ attrs = None
if reader.Matches(OPEN_SCRIPT):
reader.Advance(len(OPEN_SCRIPT))
start = reader.Mark()
-
try:
stop = reader.skipUntil(CLOSE_SCRIPT)
if stop == None:
raise 'Unterminated Script is %s block' % OPEN_SCRIPT
except EOFError:
raise EOFError("Reached EOF while looking for ending script tag (%s)" % CLOSE_SCRIPT)
-
handler.setTemplateInfo(self.tmplStart, self.tmplStop)
handler.handleScriptFile(start, stop, attrs)
-
return 1
return 0
checklist.append(checkScriptFile)
-
def checkScriptClass(self, handler, reader):
- """
- Check for python code that should go in the class definition.
+ """Check for class level code.
+
+ Check for Python code that should go in the class definition.
+
<psp:class>
- def foo(self):
+ def foo(self):
return self.dosomething()
- </psp:class>
- """
- OPEN_SCRIPT='<psp:class>'
- CLOSE_SCRIPT='</psp:class>'
- attrs=None
-
+ </psp:class>
+ """
+ OPEN_SCRIPT = '<psp:class>'
+ CLOSE_SCRIPT = '</psp:class>'
+ attrs = None
if reader.Matches(OPEN_SCRIPT):
reader.Advance(len(OPEN_SCRIPT))
start = reader.Mark()
-
try:
stop = reader.skipUntil(CLOSE_SCRIPT)
if stop == None:
raise 'Unterminated Script is %s block' % OPEN_SCRIPT
except EOFError:
raise EOFError("Reached EOF while looking for ending script tag (%s)" % CLOSE_SCRIPT)
-
handler.setTemplateInfo(self.tmplStart, self.tmplStop)
handler.handleScriptClass(start, stop, attrs)
-
return 1
return 0
checklist.append(checkScriptClass)
-
-
def checkMethod(self, handler, reader):
- """ Check for class methods defined in the page. I only support one format for these,
- <psp:method name="xxx" params="xxx,xxx"> Then the function BODY, then <psp:method> """
- OPEN_METHOD='<psp:method'
- CLOSE_METHOD='/>'
- CLOSE_METHOD_2='</psp:method>'
- CLOSE_METHOD_3='>'
+ """Check for class methods defined in the page.
- attrs=None
-
- validAttributes=('name','params')
+ I only support one format for these,
+ <psp:method name="xxx" params="xxx,xxx">
+ Then the function BODY, then <psp:method>.
+ """
+ OPEN_METHOD = '<psp:method'
+ CLOSE_METHOD = '/>'
+ CLOSE_METHOD_2 = '</psp:method>'
+ CLOSE_METHOD_3 = '>'
+ attrs = None
+ validAttributes = ('name','params')
if reader.Matches(OPEN_METHOD):
start = reader.Mark()
reader.Advance(len(OPEN_METHOD))
attrs=reader.parseTagAttributes()
- #PSPUtils.checkAttributes('method',attrs,validAttributes)
+ # PSPUtils.checkAttributes('method',attrs,validAttributes)
reader.skipSpaces()
if not reader.Matches(CLOSE_METHOD_3):
raise 'Expected method declaration close'
@@ -350,20 +325,14 @@
checklist.append(checkMethod)
-
-
def checkInclude(self, handler, reader):
- """
- Check for inserting another pages output in this spot.
- """
-
+ """Check for inserting another pages output in this spot."""
OPEN_INCLUDE = '<psp:include'
CLOSE_INCLUDE_NO_BODY = "/>"
CLOSE_INCLUDE_BODY = ">"
CLOSE_INCLUDE = "</psp:include>"
OPEN_INDIVIDUAL_PARAM = "<psp:param"
CLOSE_INDIVIDUAL_PARAM = "/>"
-
if reader.Matches(OPEN_INCLUDE):
param={}
start = reader.Mark()
@@ -382,28 +351,28 @@
return 0
checklist.append(checkInclude)
-
-
def checkInsert(self, handler, reader):
- """Check for straight character dumps. No big hurry for this. It's almost the same as
- as the page include directive. This is only a partial implementation of what JSP does.
- JSP can pull it from another server, servlet, JSP page, etc."""
-
+ """Check for straight character dumps.
+
+ No big hurry for this. It's almost the same as the page include
+ directive. This is only a partial implementation of what JSP does.
+ JSP can pull it from another server, servlet, JSP page, etc.
+
+ """
OPEN_INSERT = '<psp:insert'
CLOSE_INSERT_NO_BODY = "/>"
CLOSE_INSERT_BODY = ">"
CLOSE_INSERT = "</psp:insert>"
OPEN_INDIVIDUAL_PARAM = "<psp:param"
CLOSE_INDIVIDUAL_PARAM = "/>"
-
if reader.Matches(OPEN_INSERT):
param={}
start = reader.Mark()
reader.Advance(len(OPEN_INSERT))
reader.skipSpaces()
attrs = reader.parseTagAttributes()
- #PSPUtils.checkTagAttributes()....
+ # PSPUtils.checkTagAttributes()....
reader.skipSpaces()
if not reader.Matches(CLOSE_INSERT_BODY):
raise "Insert bodies not implemented"
@@ -416,42 +385,31 @@
checklist.append(checkInsert)
-
def parse(self, until=None, accept=None):
- """ Parse the PSP file"""
+ """Parse the PSP file."""
noPspElement = 0
reader = self._reader
handler = self._handler
-
while reader.hasMoreInput():
-
- #This is for XML style blocks, which I'm not handling yet
+ # This is for XML style blocks, which I'm not handling yet
if until !=None and reader.Matches(until):
return
-
-
-
#If the file the reader is working on has changed due to a push or pop,
#flush any char data from the old file
if not reader.Mark().getFile() == self.currentFile:
self.flushCharData(self.tmplStart, self.tmplStop)
self.currentFile = reader.Mark().getFile()
self.tmplStart = reader.Mark()
-
-
- ##in JSP, this is an array of valid tag type to check for, I'm not using it now,
- ## and I don't think JSP does either
+ # in JSP, this is an array of valid tag type to check for,
+ # I'm not using it now, # and I don't think JSP does either
if accept:
pass
-
accepted = 0
-
for checkfunc in self.checklist:
if checkfunc(self, handler, reader):
accepted = 1
noPspElement = 0
break
-
if not accepted:
if not noPspElement:
self.tmplStart = reader.Mark()
@@ -459,10 +417,4 @@
st = reader.nextContent() #skip till the next possible tag
self.tmplStop = reader.Mark() #mark the end of HTML data
self.cout.write(st) #write out the raw HTML data
-
self.flushCharData(self.tmplStart, self.tmplStop) #dump remaining raw HTML
-
-
-
-
-
Modified: Webware/trunk/PSP/PSPServletFactory.py
==============================================================================
--- Webware/trunk/PSP/PSPServletFactory.py (original)
+++ Webware/trunk/PSP/PSPServletFactory.py Fri Sep 23 20:46:46 2005
@@ -1,25 +1,22 @@
-"""
-This module handles requests from the application for PSP pages.
-
---------------------------------------------------------------------------
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+"""This module handles requests from the application for PSP pages.
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+ (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee or royalty is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation or portions thereof, including modifications,
+ that you make.
+
+ THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
"""
@@ -32,9 +29,9 @@
class PSPServletFactory(ServletFactory):
- """
- Servlet Factory for PSP files.
- Very sloppy. Need to come back and do a serious cleanup.
+ """Servlet Factory for PSP files.
+
+ Very sloppy. Need to come back and do a serious cleanup.
"""
@@ -42,61 +39,58 @@
ServletFactory.__init__(self,application)
self.cacheDir = application.serverSidePath('Cache/PSP')
sys.path.append(self.cacheDir)
-
self._cacheClassFiles = self._cacheClasses
-
l = ['_'] * 256
for c in string.digits + string.letters:
l[ord(c)] = c
self._classNameTrans = string.join(l, '')
-
if application.setting('ClearPSPCacheOnStart', 1):
self.clearFileCache()
self._lock = threading.RLock()
def uniqueness(self):
- return 'file'
+ return 'file'
def extensions(self):
- return ['.psp']
+ return ['.psp']
def flushCache(self):
- """
- Clean out the cache of classes we keep in memory.
+ """Clean out the cache of classes we keep in memory.
+
Also, clear the class files stored on disk.
+
"""
ServletFactory.flushCache()
self.clearFileCache()
def clearFileCache(self):
- """
- Clear class files stored on disk.
- """
+ """Clear class files stored on disk."""
import glob
files = glob.glob(os.path.join(self.cacheDir,'*.*'))
map(os.remove, files)
def computeClassName(self,pagename):
+ """Generates a <hopefully> unique class/file name for each PSP file.
+
+ Argument: pagename: the path to the PSP source file
+ Returns: A unique name for the class generated fom this PSP source file.
+
"""
- Generates a <hopefully> unique class/file name for
- each PSP file. Argument: pagename: the path to the
- PSP source file Returns: A unique name for the class
- generated fom this PSP source file.
- """
- # Compute class name by taking the path and
- # substituting underscores for all non-alphanumeric
- # characters.
+ # Compute class name by taking the path and substituting
+ # underscores for all non-alphanumeric characters:
return string.translate(os.path.splitdrive(pagename)[1], self._classNameTrans)
def loadClassFromFile(self, transaction, filename, classname):
- """
- Create an actual class instance. The module
- containing the class is imported as though it were a
- module within the context's package (and appropriate
- subpackages).
+ """Create an actual class instance.
+
+ The module containing the class is imported as though it were a
+ module within the context's package (and appropriate subpackages).
+
"""
module = self.importAsPackage(transaction,filename)
- assert module.__dict__.has_key(classname), 'Cannot find expected class named %s in %s.' % (repr(classname), repr(filename))
+ assert module.__dict__.has_key(classname), \
+ 'Cannot find expected class named %s in %s.' \
+ % (repr(classname), repr(filename))
theClass = getattr(module, classname)
return theClass
@@ -104,15 +98,16 @@
classname = self.computeClassName(path)
classfile = os.path.join(self.cacheDir, classname + ".py")
mtime = os.path.getmtime(path)
- if not os.path.exists(classfile) or os.path.getmtime(classfile) != mtime:
+ if not os.path.exists(classfile) \
+ or os.path.getmtime(classfile) != mtime:
context = Context.PSPCLContext(path, transaction)
context.setClassName(classname)
context.setPythonFileName(classfile)
clc = PSPCompiler.Compiler(context)
clc.compile()
- # Set the modification time of the compiled file to be the same as the source file;
- # that's how we'll know if it needs to be recompiled
+ # Set the modification time of the compiled file
+ # to be the same as the source file;
+ # that's how we'll know if it needs to be recompiled:
os.utime(classfile, (os.path.getatime(classfile), mtime))
theClass = self.loadClassFromFile(transaction, classfile, classname)
return theClass
-
Modified: Webware/trunk/PSP/PSPUtils.py
==============================================================================
--- Webware/trunk/PSP/PSPUtils.py (original)
+++ Webware/trunk/PSP/PSPUtils.py Fri Sep 23 20:46:46 2005
@@ -1,9 +1,7 @@
-"""
-A bunch of utility functions for the PSP generator.
+"""A bunch of utility functions for the PSP generator.
---------------------------------------------------------------------------
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+ (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee or royalty is hereby granted,
@@ -20,97 +18,115 @@
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
- This software is based in part on work done by the Jakarta group.
+ This software is based in part on work done by the Jakarta group.
"""
-import string
-import copy
-import re
-
-"""various utility functions"""
-
+"""Various utility functions"""
def removeQuotes(st):
- return string.replace(st,"%\\\\>","%>")
+ return st.replace("%\\\\>", "%>")
def isExpression(st):
+ """Check whether this is a PSP expression."""
OPEN_EXPR = '<%='
CLOSE_EXPR = '%>'
-
- if ((st[:len(OPEN_EXPR)] == OPEN_EXPR) and (st[-len(CLOSE_EXPR):] == CLOSE_EXPR)):
+ if st.startswith(OPEN_EXPR) and st.endswith(CLOSE_EXPR):
return 1
return 1
def getExpr(st):
+ """Get the content of a PSP expression."""
OPEN_EXPR = '<%='
CLOSE_EXPR = '%>'
- length = len(st)
- if ((st[:len(OPEN_EXPR)] == OPEN_EXPR) and (st[-len(CLOSE_EXPR):] == CLOSE_EXPR)):
- retst = st[len(OPEN_EXPR):-(len(CLOSE_EXPR))]
+ print "GETEXPR", st
+ if st.startswith(OPEN_EXPR) and st.endswith(CLOSE_EXPR):
+ return st[len(OPEN_EXPR):-len(CLOSE_EXPR)]
else:
- retst=''
- return retst
-
+ return ''
def checkAttributes(tagtype, attrs, validAttrs):
+ """Missing check for mandatory atributes."""
+ pass #see line 186 in JSPUtils.java
- #missing check for mandatory atributes
- #see line 186 in JSPUtils.java
-
- pass
-
-
-
-RE_LINES = re.compile("[\n\r]*")
-def splitLines( text ):
- '''
- Split text into lines, but works for Unix, or Windows format,
- i.e. with \n or \r for line endings.
- '''
- return RE_LINES.split( text )
-
+def splitLines(text, keepends=0):
+ """Split text into lines."""
+ return text.splitlines(keepends)
+
+def startsNewBlock(line):
+ """Determine whether line starts a new block.
+
+ Utility function for normalizeIndentation
+
+ Added by Christoph Zwerschke.
+
+ """
+ if line.startswith('#'):
+ return 0
+ try:
+ compile(line, '<string>', 'exec')
+ return 0
+ except SyntaxError:
+ try:
+ compile(line + '\n\tpass', '<string>', 'exec')
+ return 1
+ except:
+ pass
+ else:
+ pass
+ return line.endswith(':')
+def normalizeIndentation(pySource, tab='\t'):
+ """Take a block of code that may be too indented, and move it all to the left.
-def normalizeIndentation( pySource ):
- '''
- Takes a block of code that may be too indented, and moved it all the the left.
-
See PSPUtilsTest for examples.
-
- - Winston Wolff
- '''
-
- # split into lines, but keep \n and \r chars.
- lines = re.findall( "[^\n\r]*[\n\r]*", pySource)
-
- # find the line with the least indentation
- indent = 999 # This should be big enough
- for line in lines:
- lstripped = line.lstrip()
-
- # if line is empty or comment, don't measure the indentation
- if len(lstripped) == 0 or lstripped[0] == '#':
- continue
- indent = min( indent, len(line) - len(lstripped) )
-
- # Strip off the first 'indent' characters from each line
+ First written by Winston Wolff.
+ Improved version by Christoph Zwerschke.
+
+ """
+ print
+ print "------- in ---------------"
+ print pySource
+ print "---------------------------"
+ lines = splitLines(pySource, 1)
+ # Find out which kind of line feeds are used:
+ crlf = ''
+ line0 = lines.pop(0)
+ while line0 and line0[-1] in '\r\n':
+ crlf = crlf + line0[-1]
+ line0 = line0[:-1]
+ # The first line may be stripped completely:
strippedLines = []
+ charsToStrip = None
+ # Find the least indentation of the remaining lines:
for line in lines:
-
- # Remove the first 'indent' whitespace chars, but not \n or \r
- charsToStrip = 0
- for i in range(0,min( indent, len(line)) ):
- if line[i] in ' \t':
- charsToStrip = charsToStrip+1
- else:
- break # don't check any more characters
-
- strippedLines.append( line[charsToStrip:] )
-
- # write lines back out
- result = ''.join(strippedLines)
-
- return result
+ line = line.rstrip()
+ strippedLines.append(line)
+ if charsToStrip == 0:
+ continue
+ if line != '':
+ s = line.lstrip()
+ if s[0] != '#':
+ i = len(line) - len(s)
+ if charsToStrip is None or i < charsToStrip:
+ charsToStrip = i
+ if charsToStrip is not None:
+ # If there is code on the first line, strip one column less:
+ if line0 and line0[0] != '#' and charsToStrip != 0:
+ charsToStrip = charsToStrip - 1
+ # Strip off the first indent characters from each line:
+ if charsToStrip != 0:
+ lines = []
+ for line in strippedLines:
+ line = line[:charsToStrip].lstrip() + line[charsToStrip:]
+ lines.append(line)
+ strippedLines = lines
+ # Write lines back out:
+ strippedLines.insert(0, line0)
+ pySource = crlf.join(strippedLines)
+ print "----------------out ------------"
+ print pySource
+ print "--------------------------------"
+ return pySource
Modified: Webware/trunk/PSP/ParseEventHandler.py
==============================================================================
--- Webware/trunk/PSP/ParseEventHandler.py (original)
+++ Webware/trunk/PSP/ParseEventHandler.py Fri Sep 23 20:46:46 2005
@@ -1,42 +1,46 @@
-"""
-This module is called when the Parser encounters psp tokens. It creates a generator to handle the psp
-token. When the PSP source file is fully parsed, this module calls all of the generators in turn to
-output their source code.
-
-
------------------------------------------------------------------------------------------------------
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
- This software is based in part on work done by the Jakarta group.
+"""Event handler for parsing PSP tokens.
-"""
+ This module is called when the Parser encounters psp tokens.
+ It creates a generator to handle the PSP token. When the PSP
+ source file is fully parsed, this module calls all of the
+ generators in turn to output their source code.
+
+ (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee or royalty is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation or portions thereof, including modifications,
+ that you make.
+
+ THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+ This software is based in part on work done by the Jakarta group.
+
+"""
-from Generators import * # ResponseObject, plus all the *Generator functions.
+from Generators import * # ResponseObject, plus all the *Generator functions.
import string, time
+class ParseEventHandler:
+ """This is a key class.
+ It implements the handling of all the parsing elements.
+ Note: This files JSP cousin is called ParseEventListener,
+ I don\'t know why, but Handler seemed more appropriate to me.
-class ParseEventHandler:
- """This is a key class. It implements the handling of all the parsing elements. Note: This files JSP cousin is called ParseEventListener, I don\'t know why, but Handler seemed more appropriate to me."""
+ """
- aspace=' '
+ aspace= ' '
defaults = {'BASE_CLASS':'WebKit.Page',
'BASE_METHOD':'writeHTML',
'imports':{'filename':'classes'},
@@ -48,15 +52,11 @@
}
def __init__(self, ctxt, parser):
-
self._ctxt = ctxt
-
self._gens=[]
-
self._reader = ctxt.getReader()
self._writer = ctxt.getServletWriter()
self._parser = parser
-
self._imports=[]
self._importedSymbols = []
self._baseMethod = self.defaults['BASE_METHOD']
@@ -70,43 +70,44 @@
def addGenerator(self, gen):
self._gens.append(gen)
-
def handleExpression(self, start, stop, attrs):
- """Flush any template data into a CharGen and then create a new Expression Gen"""
+ """Flush any template data into a CharGen and then create a new ExpressionGen."""
self._parser.flushCharData(self.tmplStart, self.tmplStop)
exp = ExpressionGenerator(self._reader.getChars(start,stop))
self.addGenerator(exp)
def handleCharData(self, start, stop, chars):
- """flush character data into a chargen"""
+ """Flush character data into a CharGen."""
if chars !='' or '\n':
gen = CharDataGenerator(chars)
self.addGenerator(gen)
-
def handleComment(self, start, stop):
- """Comments get swallowed into nothing"""
+ """Comments get swallowed into nothing."""
self._parser.flushCharData(self.tmplStart, self.tmplStop)
return #just eats the comment
-
def handleInclude(self, attrs,param):
- """
- this is for includes of the form <psp:include ...>
- This function essentially forwards the request to the specified URL and includes that output.
+ """This is for includes of the form <psp:include ...>
+
+ This function essentially forwards the request to the specified
+ URL and includes that output.
+
"""
self._parser.flushCharData(self.tmplStart, self.tmplStop)
gen = IncludeGenerator(attrs, param,self._ctxt)
self.addGenerator(gen)
def handleInsert(self, attrs,param):
- """ this is for includes of the form <psp:insert ...>
- This type of include is not parsed, it is just inserted in the output stream."""
+ """This is for includes of the form <psp:insert ...>
+
+ This type of include is not parsed, it is just inserted in the output stream.
+
+ """
self._parser.flushCharData(self.tmplStart, self.tmplStop)
gen = InsertGenerator(attrs, param,self._ctxt)
self.addGenerator(gen)
-
def importHandler(self, imports, start, stop):
importlist = string.split(imports,',')
for i in importlist:
@@ -119,51 +120,72 @@
self._imports.append('import '+string.strip(i))
def extendsHandler(self,bc,start,stop):
- """extends is a page directive. It sets the base class (or multiple base classes) for the class that this class
- will generate. The choice of base class affects the choice of a method to override with
- the BaseMethod page directive. The default base class is PSPPage. PSPPage inherits from Page.py."""
+ """Extends is a page directive.
+
+ It sets the base class (or multiple base classes) for the class
+ that this class will generate. The choice of base class affects
+ the choice of a method to override with the BaseMethod page directive.
+ The default base class is PSPPage. PSPPage inherits from Page.py.
+
+ """
self._baseClasses = map(string.strip, string.split(bc, ','))
def mainMethodHandler(self, method, start, stop):
- """BaseMethod is a page directive. It sets the class method that the main body
- of this PSP page over-rides. The default is WriteHTML. This value should be set to either WriteHTML
- or writeBody. See the PSPPage.py and Page.py servlet classes for more information."""
- self._baseMethod=method
+ """BaseMethod is a page directive.
+
+ It sets the class method that the main body of this PSP page
+ over-rides. The default is WriteHTML. This value should be set
+ to either WriteHTML or writeBody. See the PSPPage.py and Page.py
+ servlet classes for more information.
+
+ """
+ self._baseMethod = method
def threadSafeHandler(self, bool, start, stop):
- """isThreadSafe is a page directive. The value can be "yes" or "no". Default is no because the default base class,
- PAge.py, isn't thread safe."""
- self._threadSafe=bool
+ """Handle isThreadSage.
+
+ isThreadSafe is a page directive.
+ The value can be "yes" or "no".
+ Default is no because the default base class,
+ Page.py, isn't thread safe.
+
+ """
+ self._threadSafe = bool
def instanceSafeHandler(self, bool, start, stop):
- """isInstanceSafe tells the Servlet Engine whether it is safe to use object instances of this page
- multiple times. The default is "yes". Saying "no" here hurts performance."""
+ """Handle isInstanceSafe.
+
+ isInstanceSafe tells the Servlet engine whether it is safe
+ to use object instances of this page multiple times.
+ The default is "yes".
+
+ Saying "no" here hurts performance.
+
+ """
self._instanceSafe=bool
- def indentTypeHandler(self,type,start, stop):
- """Use tabs to indent source code?"""
+ def indentTypeHandler(self, type, start, stop):
+ """Declare whether tabs are used to indent source code."""
type = string.lower(type)
- if type !="tabs" and type !="spaces" and type !="braces":
+ if type != "tabs" and type != "spaces" and type != "braces":
raise "Invalid Indentation Type"
self._writer.setIndentType(type)
-
def indentSpacesHandler(self,amount,start,stop):
- """set number of spaces used to indent in generated source"""
+ """Set number of spaces used to indent in generated source."""
self._indentSpaces=int(amount)#don't really need this
self._writer.setIndentSpaces(int(amount))
def gobbleWhitespaceHandler(self, value, start, stop):
- """ Should we gobble up whitespace between script tags"""
- if string.upper(value) == "NO" or value=="0":
- self._gobbleWhitespace=0
+ """Declare whether whitespace between script tags are gobble up."""
+ if string.upper(value) == "NO" or value == "0":
+ self._gobbleWhitespace = 0
def formatterHandler(self, value, start, stop):
""" set an alternate formatter function to use instead of str() """
self._formatter = value
-
directiveHandlers = {'imports':importHandler,
'import':importHandler,
'extends':extendsHandler,
@@ -176,13 +198,11 @@
'gobbleWhitespace':gobbleWhitespaceHandler,
'formatter':formatterHandler}
-
def handleDirective(self, directive, start, stop, attrs):
validDirectives = ['page','include']
- """Flush any template data into a CharGen and then create a new Directive Gen"""
+ """Flush any template data into a CharGen and then create a new DirectiveGen."""
self._parser.flushCharData(self.tmplStart, self.tmplStop)
- #big switch
-
+ # big switch
if directive == 'page':
e = attrs.keys()
for i in e:
@@ -191,7 +211,6 @@
else:
print i
raise 'No Page Directive Handler'
-
elif directive == 'include':
try:
filenm = attrs['file']
@@ -209,8 +228,6 @@
print directive
raise "Invalid Directive"
-
-
def handleScript(self, start, stop, attrs):
"""handling scripting elements"""
self._parser.flushCharData(self.tmplStart, self.tmplStop)
@@ -230,9 +247,9 @@
self.addGenerator(gen)
def handleEndBlock(self):
- self._parser.flushCharData(self.tmplStart, self.tmplStop)
- gen = EndBlockGenerator()
- self.addGenerator(gen)
+ self._parser.flushCharData(self.tmplStart, self.tmplStop)
+ gen = EndBlockGenerator()
+ self.addGenerator(gen)
def handleMethod(self, start, stop, attrs):
self._parser.flushCharData(self.tmplStart, self.tmplStop)
@@ -244,20 +261,19 @@
gen = MethodEndGenerator(self._reader.getChars(start, stop),attrs)
self.addGenerator(gen)
-
-
- #####################################################################
- ##The generation of the page begins here
- ####################################################################3
+ #####################################################################
+ ##The generation of the page begins here
+ #####################################################################
def beginProcessing(self):
- pass
+ pass
def endProcessing(self):
- self._writer.println('# Generated automatically by PSP compiler on %s\n' % time.asctime() )
+ self._writer.println('# Generated automatically by PSP compiler on %s\n'
+ % time.asctime())
self.generateHeader()
self.generateAll('psp:file')
- self.generateDeclarations() #I'll overwrite this later when I can handle extends
+ self.generateDeclarations() # I'll overwrite this later when I can handle extends
self.generateInitPSP()
self.generateAll('psp:class')
self.generateAll('Declarations')
@@ -271,34 +287,35 @@
self.generateFooter()
def setTemplateInfo(self, start, stop):
- """marks non code data"""
+ """Mark non code data."""
self.tmplStart = start
self.tmplStop = stop
def generateHeader(self):
for i in self._imports:
self._writer.println(i)
-## self._writer.println('try:\n')
-## self._writer.pushIndent()
- #self._writer.println('from ' +self._baseClass+ ' import ' +self._baseClass +'\n')
+ # self._writer.println('try:\n')
+ # self._writer.pushIndent()
+ # self._writer.println('from ' +self._baseClass+ ' import ' +self._baseClass +'\n')
self._writer.println('import WebKit')
self._writer.println('from WebKit import Page')
for baseClass in self._baseClasses:
if string.find(baseClass,'.')<0 and baseClass not in self._importedSymbols:
self._writer.println('import ' + baseClass)
-## self._writer.popIndent()
-## self._writer.println('except:\n')
-## self._writer.pushIndent()
-## self._writer.println('pass\n')
-## self._writer.popIndent()
+ # self._writer.popIndent()
+ # self._writer.println('except:\n')
+ # self._writer.pushIndent()
+ # self._writer.println('pass\n')
+ # self._writer.popIndent()
self._writer.println("__orig_file__ = %r" % self._ctxt.getFullPspFileName())
def generateDeclarations(self):
- # The PSP "extends" directive allows you to use a shortcut -- if the module name
- # is the same as the class name, you can say "Classname" instead of "ClassName.ClassName".
- # But we can't tell right now which names are actually class names, and which
- # names are really module names that contain a class of the same name.
- # So we have to generate code that checks at runtime.
+ # The PSP "extends" directive allows you to use a shortcut
+ # -- if the module name is the same as the class name,
+ # you can say "Classname" instead of "ClassName.ClassName".
+ # But we can't tell right now which names are actually class names,
+ # and which names are really module names that contain a class of
+ # the same name. So we have to generate code that checks at runtime.
self._writer.println()
self._writer.println('import types')
self._writer.println('_baseClasses = []')
@@ -313,7 +330,7 @@
self._writer.println('_baseClasses.append(%s)' % baseClass)
self._writer.popIndent()
self._writer.println()
- # Now write the class line
+ # Now write the class line:
self._writer.printChars('class ')
self._writer.printChars(self._ctxt.getServletClassName())
self._writer.printChars('(')
@@ -324,7 +341,6 @@
self._writer.printChars('):')
#self._writer.printChars('('+self._baseClass+'):')
self._writer.printChars('\n')
-
self._writer.pushIndent()
self._writer.println('def canBeThreaded(self):') # I Hope to take this out soon!
self._writer.pushIndent()
@@ -334,7 +350,6 @@
self._writer.println('return 1')
self._writer.popIndent()
self._writer.println()
-
self._writer.println('def canBeReused(self):') # I Hope to take this out soon!
self._writer.pushIndent()
if string.lower(self._instanceSafe) == 'no':
@@ -343,7 +358,6 @@
self._writer.println('return 1')
self._writer.popIndent()
self._writer.println()
-
if not AwakeCreated:
self._writer.println('def awake(self,trans):')
self._writer.pushIndent()
@@ -355,30 +369,27 @@
self._writer.println('break\n')
self._writer.popIndent() # end if statement
self._writer.popIndent() # end for statement
-
self._writer.println('self.initPSP()\n')
self._writer.println()
self._writer.popIndent()
self._writer.println()
-
self._writer.println('def __includeFile(self, filename):')
self._writer.pushIndent()
self._writer.println('self.write(open(filename).read())')
self._writer.popIndent()
self._writer.println()
-
return
def generateInitPSP(self):
self._writer.println('def initPSP(self):\n')
self._writer.pushIndent()
- self._writer.println('pass\n') #nothing for now
+ self._writer.println('pass\n') # nothing for now
self._writer.popIndent()
self._writer.println()
def generateMainMethod(self):
-
- # write the output method that the user requested in with <%@ page method="WriteHTML"%>
+ # Write the output method that the user requested in with
+ # <%@ page method="WriteHTML"%>
self._writer.printIndent()
self._writer.printChars('def %s(self, transaction=None):\n' % self._baseMethod )
self._writer.pushIndent()
@@ -386,19 +397,21 @@
self._writer.println('trans = self._transaction')
self._writer.println(ResponseObject+ ' = trans.response()')
self._writer.println('req = trans.request()')
- self._writer.println('self._%s( %s, req, trans )\n' % (self._baseMethod, ResponseObject) )
-
- # Put the real output code in a function that is doesn't need a 'transaction' for unit tests.
+ self._writer.println('self._%s( %s, req, trans )\n'
+ % (self._baseMethod, ResponseObject))
+ # Put the real output code in a function that doesn't need
+ # a 'transaction' for unit tests.
self._writer.popIndent()
- self._writer.println('def _%s( self, %s, req=None, trans=None ):' % (self._baseMethod, ResponseObject))
+ self._writer.println('def _%s( self, %s, req=None, trans=None ):'
+ % (self._baseMethod, ResponseObject))
self._writer.pushIndent()
self._writer.println('"""I take a file-like object. I am useful for unit testing."""')
self._writer.println('_formatter = %s' % self._formatter)
-
- #self._writer.println('app = trans.application()')
+ # self._writer.println('app = trans.application()')
def generateFooter(self):
- """cant decide if this is in the class or outside. Guess Ill know when Im done"""
+ # Can't decide if this is in the class or outside.
+ # Guess I'll know when I'm done"""
self._writer.popIndent()
self._writer.println('##footer')
@@ -408,47 +421,61 @@
i.generate(self._writer)
def optimizeCharData(self):
- """ Too many char data generators make the Servlet Slow. If the current Generator and the next are both CharData type, merge their data."""
+ """Optimize the CharData.
+
+ Too many char data generators make the servlet slow.
+ If the current Generator and the next are both CharData type,
+ merge their data.
+
+ """
gens=self._gens
count=0
gencount = len(gens)
while count < gencount-1:
- if isinstance(gens[count],CharDataGenerator) and isinstance(gens[count+1],CharDataGenerator):
+ if isinstance(gens[count],CharDataGenerator) \
+ and isinstance(gens[count+1],CharDataGenerator):
gens[count].mergeData(gens[count+1])
gens.remove(gens[count+1])
- gencount = gencount-1
+ gencount = gencount - 1
else:
- count = count+1
-
+ count = count + 1
def gobbleWhitespace(self):
+ """Gobble up whitespace.
+
+ This method looks for a character block between two PSP blocks
+ that contains only whitespace. If it finds one, it deletes it.
+
+ This is necessary so that a write() line can't sneek in between
+ a if/else, try/except etc.
+
"""
- This method looks for a character block between two psp blocks that contains only whitespace.
- If it finds one, it deletes it.
- This is necessary so that a write() line can't sneek in between a if/else, try/except etc.
- """
- debug=0
- gens=self._gens
- sideClasses=(ScriptGenerator, EndBlockGenerator)##, ExpressionGenerator)
- count=1
+ debug = 0
+ gens = self._gens
+ sideClasses = (ScriptGenerator, EndBlockGenerator)
+ count = 1
gencount = len(gens)
if debug:
for i in gens:
- print "Generator type=%s" % i.__class__
+ print "Generator type = %s" % i.__class__
while count < gencount-1:
- if isinstance(gens[count],CharDataGenerator) and gens[count+1].__class__ in sideClasses and gens[count-1].__class__ in sideClasses:
+ if isinstance(gens[count],CharDataGenerator) \
+ and gens[count+1].__class__ in sideClasses \
+ and gens[count-1].__class__ in sideClasses:
if checkForTextHavingOnlyGivenChars(gens[count].chars):
gens.remove(gens[count])
- gencount=gencount-1
- count = count+1
-
+ gencount = gencount - 1
+ count = count + 1
def checkForTextHavingOnlyGivenChars(text, ws=string.whitespace):
- """ Does the given text contain anything other than the ws characters?
- Return true if text is only ws characters
- Should redo this as a regex.
+ """Checks whether text contains only whitespace (or other chars).
+
+ Does the given text contain anything other than the ws characters?
+ Return true if text is only ws characters.
+
"""
+ # Should redo this as a regex.
for i in text:
if i not in ws:
return 0
Modified: Webware/trunk/PSP/ServletWriter.py
==============================================================================
--- Webware/trunk/PSP/ServletWriter.py (original)
+++ Webware/trunk/PSP/ServletWriter.py Fri Sep 23 20:46:46 2005
@@ -1,25 +1,24 @@
-"""
-This module holds the actual file writer class.
---------------------------------------------------------------------------
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+"""This module holds the actual file writer class.
+
+ (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee or royalty is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation or portions thereof, including modifications,
+ that you make.
+
+ THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
- This software is based in part on work done by the Jakarta group.
+ This software is based in part on work done by the Jakarta group.
"""
@@ -29,8 +28,11 @@
import string, os, sys, tempfile
class ServletWriter:
+ """This file creates the servlet source code.
+
+ Well, it writes it out to a file at least.
- """ This file creates the servlet source code. Well, it writes it out to a file at least."""
+ """
TAB = '\t'
SPACES = ' ' # 4 spaces
@@ -43,20 +45,20 @@
self._tabcnt = 0
self._blockcount = 0 # a hack to handle nested blocks of python code
self._indentSpaces = self.SPACES
- self._useTabs=1
- self._useBraces=0
- self._indent='\t'
+ self._useTabs = 1
+ self._useBraces = 0
+ self._indent = '\t'
self._userIndent = self.EMPTY_STRING
def setIndentSpaces(self,amt):
- self._indentSpaces=' '*amt
+ self._indentSpaces = ' '*amt
self.setIndention()
def setIndention(self):
if self._useTabs:
- self._indent='\t'
+ self._indent = '\t'
else:
- self._indent=self._indentSpaces#' '*self._indentSpaces
+ self._indent = self._indentSpaces # ' '*self._indentSpaces
def setIndentType(self, type):
if type=="tabs":
@@ -69,7 +71,7 @@
self._useTabs=0
self._useBraces=1
self.setIndention()
-
+
def close(self):
self._filehandle.close()
if os.path.exists(self._pyfilename):
@@ -83,14 +85,11 @@
def popIndent(self):
if self._tabcnt > 0:
self._tabcnt = self._tabcnt - 1
-
-
- def printComment(self, start, stop, chars):
+ def printComment(self, start, stop, chars):
if start and stop:
self.println('## from ' + str(start))
self.println('## from ' + str(stop))
-
if chars:
sp = string.split(chars,'\n')
for i in sp:
@@ -99,48 +98,41 @@
self._filehandle.write(i)
def quoteString(self, s):
- """escape the string"""
- #None
+ """Escape the string."""
if s == None:
return 'None'
- #this probably wont work, Ill be back for this
+ # this probably won't work, I'll be back for this
return 'r'+s
- def indent(self,st):
- """Added userIndent 6/18/00"""
- if self._tabcnt>0:
- return self._userIndent + self._indent*self._tabcnt +st
+ def indent(self, st):
+ """Indent the string."""
+ # added userIndent 6/18/00
+ if self._tabcnt > 0:
+ return self._userIndent + self._indent*self._tabcnt + st
return st
-
+
def println(self, line=None):
- """Prints with Indentation and a newline if none supplied"""
+ """Print with indentation and a newline if none supplied."""
if line:
self._filehandle.write(self.indent(line))
else:
self._filehandle.write(self.indent('\n'))
-
-
if line and line[:-1] != '\n':
self._filehandle.write('\n')
def printChars(self, st):
- """just prints what its given"""
+ """Just prints what its given."""
self._filehandle.write(st)
def printMultiLn(self, st):
raise 'NotImplemented Error'
-
def printList(self, strlist):
- """prints a list of strings with indentation and a newline"""
+ """Prints a list of strings with indentation and a newline."""
for i in strlist:
self.printChars(self.indent(i))
self.printChars('\n')
def printIndent(self):
- """just prints tabs"""
+ """Just prints tabs."""
self.printChars(self.indent(''))
-
-
-
-
Modified: Webware/trunk/PSP/StreamReader.py
==============================================================================
--- Webware/trunk/PSP/StreamReader.py (original)
+++ Webware/trunk/PSP/StreamReader.py Fri Sep 23 20:46:46 2005
@@ -1,26 +1,25 @@
-"""
-This module co-ordinates the reading of the source file.
-It maintains the current position of the parser in the source file.
+"""This module co-ordinates the reading of the source file.
+
+ It maintains the current position of the parser in the source file.
---------------------------------------------------------------------------
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+ (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee or royalty is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation or portions thereof, including modifications,
+ that you make.
+
+ THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
- This software is based in part on work done by the Jakarta group.
+ This software is based in part on work done by the Jakarta group.
"""
@@ -32,12 +31,11 @@
import os
-
class Mark:
"""The Mark class marks a point in an input stream."""
def __init__(self, reader, fileid=None, stream=None, inBaseDir=None, encoding=None):
-
+
if isinstance(reader,StreamReader):
self.reader = reader
self.fileid = fileid
@@ -46,26 +44,21 @@
self.stream = stream
self.baseDir=inBaseDir
self.encoding=encoding
-
else:
self = copy.copy(reader)
-
-## I think the includeStack will be copied correctly, but check here for problems
-## raise 'clone include stack'
-
-
-## JSP has an equals function, but I don't think I need that, b/c of using copy,
-## but maybe I do
+ # I think the includeStack will be copied correctly,
+ # but check here for problems: raise 'clone include stack'
+ # JSP has an equals function, but I don't think I need that,
+ # because of using copy, but maybe I do.
def getFile(self):
return self.reader.getFile(self.fileid)
def __str__(self):
return self.getFile() + '(' + str(self.line) + str(self.col) + ')'
-
-
+
def __repr__(self):
- return self.getFile() + '(' + str(self.col) + ')'
+ return self.getFile() + '(' + str(self.col) + ')'
def pushStream(self, infileid, inStream, inBaseDir, inEncoding):
self.includeStack.append((self.cursor, self.fileid, self.baseDir, self.encoding, self.stream))
@@ -75,7 +68,6 @@
self.encoding=inEncoding
self.stream=inStream
-
def popStream(self):
if len(self.includeStack) == 0:
return 0 #false
@@ -86,16 +78,15 @@
self.baseDir=list[2]
self.encoding=list[3]
self.stream=list[4]
- return 1 #true
-
-
-
-
+ return 1 # true
class StreamReader:
- """This class handles the psp source file
+ """This class handles the PSP source file.
+
It provides the characters to the other parts of the system.
- It can move forward and backwards in a file and remember locactions"""
+ It can move forward and backwards in a file and remember locactions.
+
+ """
def __init__(self,filename,ctxt):
self._pspfile = filename
@@ -109,7 +100,6 @@
def init(self):
self.pushFile(self._ctxt.getFullPspFileName())
-
def registerSourceFile(self, file):
self.sourcefiles.append(file)
self.size = self.size+1 #what is size for?
@@ -117,49 +107,41 @@
def pushFile(self, file, encoding=None):
assert type(file)==type('')
- #if type(file) != type(''): #we've got an open filehandle-don't think this case exists
-
- #don't know what this master stuff is, but until I do, implement it
- #Oh, it's the original file
-
+ # if type(file) != type(''):
+ # we've got an open file handle - don't think this case exists
+ # Don't know what this master stuff is, but until I do, implement it.
+ # Oh, it's the original file.
if self.master == None:
parent = None
self.master=file
else:
parent = os.path.split(self.master)[0]
-
isAbsolute = os.path.isabs(file)
-
if parent != None and not isAbsolute:
file = os.path.join(parent,file)
-
-
fileid = self.registerSourceFile(file)
handle = open(file,'r')
stream = handle.read()
handle.seek(0,0)
- lines = handle.readlines() #(self, reader, linearray, fileid, includestack, stream):
- #mark = Mark(self, lines, fileid, None, stream, self._ctxt.getBaseUri(),encoding)
-
- z=0
+ lines = handle.readlines()
+ z = 0
for i in lines:
lines[z]=string.replace(i,'\r\n','\n')
- z=z+1
-
+ z = z + 1
stream=string.join(lines,'')
if self.current == None:
- #self.current = mark
- self.current = mark = Mark(self, fileid, stream, self._ctxt.getBaseUri(),encoding)
+ self.current = mark = Mark(self, fileid, stream,
+ self._ctxt.getBaseUri(),encoding)
else:
- self.current.pushStream(fileid, stream, self._ctxt.getBaseUri(), encoding) #don't use yet
+ self.current.pushStream(fileid, stream,
+ self._ctxt.getBaseUri(), encoding) # don't use yet
def popFile(self):
-
if self.current == None:
return 0
- self.size = self.size-1 #what the hell is this?
- r=self.current.popStream()
+ self.size = self.size - 1 # @@ what the hell is this?
+ r = self.current.popStream()
return r
def getFile(self,i):
@@ -173,27 +155,18 @@
def Mark(self):
return copy.copy(self.current)
- #return Mark(self.current)
-
-## def advanceLine(self):
-## raise "NotUsingAnymore"
-## if self.current.row < len(self.current.linearray)-1:
-## self.current.cursor = self.current.cursor + len(self.current.linearray[self.current.row][self.current.col:])
-## self.current.row = self.current.row + 1
-## self.current.col = 0
-## else:
-## self.current.cursor = self.current.cursor + len(self.current.linearray[self.current.row][self.current.col:])
-## self.current.col = len(self.current.linearray[self.current.row][:])
-## if self.hasMoreInput() == 0:
-## raise EOFError()
def skipUntil(self, st):
- """greedy search, return the point before the string, but move reader past it"""
+ """Greedy search.
+
+ Return the point before the string, but move reader past it.
+
+ """
pt = string.find(self.current.stream[self.current.cursor:],st)
if pt == -1:
self.current.cursor = len(self.current.stream)
if self.hasMoreInput():
- self.popFile() #Should I do this here? 6/1/00
+ self.popFile() # @@ Should I do this here? 6/1/00
self.skipUntil(st)
else:
raise "EndofInputError"
@@ -203,14 +176,12 @@
self.current.cursor = self.current.cursor+len(st)
return ret
-
-
def reset(self, mark):
- self.current = mark #Mark(mark)
-
+ self.current = mark
def Matches(self,st):
- if st == self.current.stream[self.current.cursor:self.current.cursor+len(st)]:
+ if st == self.current.stream[
+ self.current.cursor:self.current.cursor+len(st)]:
return 1
return 0
@@ -220,32 +191,31 @@
self.current.cursor = self.current.cursor+length
else:
prog = len(self.current.stream) - self.current.cursor
- self.current.cursor=len(self.current.stream) # -1??
+ self.current.cursor = len(self.current.stream) # @@ -1?
if self.hasMoreInput():
self.Advance(length-prog)
else:
raise EOFError()
-
def nextChar(self):
- if self.hasMoreInput() == 0: return -1
+ if self.hasMoreInput() == 0:
+ return -1
ch = self.current.stream[self.current.cursor]
self.Advance(1)
return ch
-
def isSpace(self):
- """no advancing"""
- return self.current.stream[self.current.cursor] == ' ' or self.current.stream[self.current.cursor] == '\n'
-
+ """No advancing."""
+ return self.current.stream[self.current.cursor] == ' ' \
+ or self.current.stream[self.current.cursor] == '\n'
def isDelimiter(self):
if not self.isSpace():
ch = self.peekChar()
- #look for single character work delimiter
+ # Look for single character work delimiter:
if ch == '=' or ch == '\"' or ch == "'" or ch == '/':
return 1
- #look for end of comment or basic end tag
+ # Look for end of comment or basic end tag:
if ch == '-':
mark = self.Mark()
ch = self.nextChar()
@@ -258,9 +228,6 @@
return 0
else:
return 1
-
-
-
def peekChar(self,cnt=1):
if self.hasMoreInput():
@@ -289,23 +256,19 @@
return 0
return 1
-
def nextContent(self):
- """ Find next <"""
+ """Find next < char."""
cur_cursor = self.current.cursor
self.current.cursor = self.current.cursor+1
pt = string.find(self.current.stream[self.current.cursor:],'<')
if pt == -1:
- self.current.cursor = len(self.current.stream) #-1???
+ self.current.cursor = len(self.current.stream) # @@ -1?
else:
self.current.cursor=self.current.cursor+pt
return self.current.stream[cur_cursor:self.current.cursor]
-
-
def parseTagAttributes(self):
- """parses the attributes at the beginning of a tag"""
-
+ """Parse the attributes at the beginning of a tag."""
values = {}
while 1:
self.skipSpaces()
@@ -330,12 +293,10 @@
return values
finally:
self.reset(mark)
-
if ch == None:
break
-
self.parseAttributeValue(values)
- #EOF
+ # EOF
raise 'Unterminated Attribute'
def parseAttributeValue(self, valuedict):
@@ -351,7 +312,7 @@
valuedict[name]=value
def parseToken(self, quoted):
- """ This may not be quite right"""
+ # This may not be quite right:
buffer=[]
self.skipSpaces()
ch = self.peekChar()
@@ -361,7 +322,7 @@
ch = self.nextChar()
ch=self.peekChar()
while ch != None and ch != endquote:
- ch = self.nextChar()
+ ch = self.nextChar()
if ch == '\\':
ch = nextChar()
buffer.append(ch)
@@ -379,5 +340,3 @@
ch = self.nextChar()
buffer.append(ch)
return string.join(buffer,'')
-
-
Modified: Webware/trunk/PSP/Tests/CompileTest.py
==============================================================================
--- Webware/trunk/PSP/Tests/CompileTest.py (original)
+++ Webware/trunk/PSP/Tests/CompileTest.py Fri Sep 23 20:46:46 2005
@@ -1,7 +1,6 @@
"""
Automated tests for PSP Kit
- --------------------------------------------------------------------------------
(c) Copyright by Winston Wolff, 2004 http://www.stratolab.com
Permission to use, copy, modify, and distribute this software and its
@@ -18,7 +17,9 @@
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+
"""
+
import os, sys
import imp
import logging
@@ -31,7 +32,6 @@
# so I have to import both AppServer before Page imports Application.
import WebKit.AppServer
-
_log = logging.getLogger( __name__ )
### Turn on debuging messages, and turn off deleting of files after test.
@@ -44,35 +44,29 @@
class CompileTest(unittest.TestCase):
def compileString(self, pspSource, classname ):
- '''
- Takes a string, compiles it, imports the python file, and returns you
+ '''Compile a string to an object.
+
+ Takes a string, compiles it, imports the Python file, and returns you
the Python class object.
classname = some string so that each file is unique per test case.
'''
-
# write string to temporary file
moduleName = "tmp_CompileTest_"+classname
tmpInName = moduleName+".psp"
tmpOutName = moduleName+".py"
-
_log.debug('Writing PSP source to: "%s"', tmpInName)
fp = open( tmpInName, 'w' )
fp.write( pspSource )
fp.close()
-
# Compile PSP into .py file
context = Context.PSPCLContext( tmpInName )
context.setClassName( classname )
context.setPythonFileName( tmpOutName )
-
clc = PSPCompiler.Compiler( context )
clc.compile()
-
-
# Have Python import the .py file.
fp = open( tmpOutName )
-
try:
description = ('.py', 'r', imp.PY_SOURCE)
theModule = imp.load_module(moduleName, fp, tmpOutName, description)
@@ -80,81 +74,64 @@
# Since we may exit via an exception, close fp explicitly.
if fp:
fp.close()
-
if not DEBUG:
os.remove( tmpInName )
os.remove( tmpOutName )
os.remove( moduleName+".pyc" )
-
# want to return the class inside the module.
theClass = getattr( theModule, classname)
-
return theClass
-
def compileAndRun( self, pspSource, classname ):
-
pspClass = self.compileString( pspSource, classname )
pspInstance = pspClass()
outStream = StringIO()
pspInstance._writeHTML( outStream )
output = outStream.getvalue()
-
return output
-
def testExpression(self):
-
output = self.compileAndRun( 'two plus three is: <%= 2+3 %>', 'testExpression' )
self.assertEquals( "two plus three is: 5", output )
-
def testScript(self):
-
output = self.compileAndRun( 'one plus two is: <% res.write( 1+2) %>', 'testScript' )
self.assertEquals( "one plus two is: 3", output )
def testScript_NewLines(self):
-
- psp = '''\nthree plus two is: \n<%\nres.write( 3+2) \n%>'''
+ psp = '''\nthree plus two is: \n<%\nres.write( 3+2) \n%>'''
expect = '''\nthree plus two is: \n5'''
output = self.compileAndRun( psp, 'testScript_NewLines' )
self.assertEquals( output, expect )
-
-
- psp = '''\nthree plus two is: \n<%\n res.write( 3+2) \n%>'''
+ psp = '''\nthree plus two is: \n<%\n res.write( 3+2) \n%>'''
expect = '''\nthree plus two is: \n5'''
output = self.compileAndRun( psp, 'testScript_NewLines' )
self.assertEquals( output, expect )
-
def testScript_Returns(self):
- psp = '''\rthree plus two is: \r<%\rres.write( 3+2) \r%>'''
+ psp = '''\rthree plus two is: \r<%\rres.write( 3+2) \r%>'''
expect = '''\nthree plus two is: \n5'''
output = self.compileAndRun( psp, 'testScript_Returns' )
self.assertEquals( output, expect )
-
- psp = '''\rthree plus two is: \r<%\r res.write( 3+2) \r%>'''
+ psp = '''\rthree plus two is: \r<%\r res.write( 3+2) \r%>'''
expect = '''\nthree plus two is: \n5'''
output = self.compileAndRun( psp, 'testScript_Returns' )
self.assertEquals( output, expect )
def testScript_If(self):
- psp = '''PSP is <% if True: %>Good<% end %>'''
+ psp = '''PSP is <% if True: %>Good<% end %>'''
expect = '''PSP is Good'''
output = self.compileAndRun( psp, 'testScript_IfElse' )
self.assertEquals( output, expect )
-
def testScript_IfElse(self):
- psp = '''JSP is <% if False: %>Good<% end %><% else: %>Bad<% end %>'''
+ psp = '''JSP is <% if False: %>Good<% end %><% else: %>Bad<% end %>'''
expect = '''JSP is Bad'''
output = self.compileAndRun( psp, 'testScript_IfElse' )
self.assertEquals( output, expect )
-
def testScript_Blocks(self):
- psp = '''
+ psp = '''
<% for i in range(3): %>
<%= i %><br/>
<% end %>'''
@@ -169,9 +146,8 @@
output = self.compileAndRun( psp, 'testScript_Blocks' )
self.assertEquals( output, expect )
-
def testScript_Braces(self):
- psp = '''
+ psp = '''
<%@page indentType="braces" %>
<% for i in range(3): { %>
<%= i %><br/>
@@ -187,7 +163,6 @@
output = self.compileAndRun( psp, 'testScript_Braces' )
self.assertEquals( output, expect )
-
def testPspMethod(self):
psp = '''
<psp:method name="add" params="a,b">
@@ -198,7 +173,6 @@
output = self.compileAndRun( psp, 'testPspMethod' ).strip()
self.assertEquals( "7 plus 8 = 15", output )
-
def testPspFile(self):
psp = '''
<psp:file>
@@ -220,5 +194,3 @@
'''
output = self.compileAndRun( psp, 'testPspClass' ).strip()
self.assertEquals( "4^2 = 16", output )
-
-
Modified: Webware/trunk/PSP/Tests/PSPUtilsTest.py
==============================================================================
--- Webware/trunk/PSP/Tests/PSPUtilsTest.py (original)
+++ Webware/trunk/PSP/Tests/PSPUtilsTest.py Fri Sep 23 20:46:46 2005
@@ -1,16 +1,15 @@
"""
Automated tests for PSPUtils
-
- --------------------------------------------------------------------------------
+
(c) Copyright by Winston Wolff, 2004 http://www.stratolab.com
-
+
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee or royalty is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation or portions thereof, including modifications,
that you make.
-
+
THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
@@ -18,7 +17,9 @@
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+
"""
+
import unittest
import doctest
from PSP import PSPUtils
@@ -29,17 +30,17 @@
# Combine our unittest with our doctests.
# '''
# result = unittest.TestSuite()
-#
-# result.addTest( doctest.DocTestSuite( PSPUtils ) )
-# result.addTest( unittest.defaultTestLoader.loadTestsFromTestCase( PSPUtilsTest ) )
-#
+#
+# result.addTest(doctest.DocTestSuite(PSPUtils))
+# result.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(PSPUtilsTest))
+#
# return result
-
-
+
+
class PSPUtilsTest(unittest.TestCase):
-
+
def testNormalizeIndentation(self):
-
+
before = """
def add(a,b):
return a+b"""
@@ -47,9 +48,8 @@
"""
def add(a,b):
return a+b"""
-
- self.assertEquals( PSPUtils.normalizeIndentation( before ), expected )
-
+
+ self.assertEquals(PSPUtils.normalizeIndentation(before), expected)
# Comments should be ignored for the unindentation
before = """
@@ -61,16 +61,15 @@
# Will comments throw off the indentation?
def add(a,b):
return a+b"""
-
- self.assertEquals( PSPUtils.normalizeIndentation( before ), expected )
-
-
+
+ self.assertEquals(PSPUtils.normalizeIndentation(before), expected)
+
# Will blank lines cause a problem?
before = """
# Will blank lines cause a problem?
def add(a,b):
-
+
return a+b"""
expected = \
"""
@@ -79,22 +78,20 @@
def add(a,b):
return a+b"""
-
- self.assertEquals( PSPUtils.normalizeIndentation( before ), expected )
+ self.assertEquals(PSPUtils.normalizeIndentation(before), expected)
# Different line endings OK?
- before = '#line endings\r def add(a,b):\r \r return a+b\r'
- expected = '#line endings\rdef add(a,b):\r\rreturn a+b\r'
-
- self.assertEquals( PSPUtils.normalizeIndentation( before ), expected )
+ before = '#line endings\r def add(a,b):\r \r return a+b'
+ expected = '#line endings\rdef add(a,b):\r\rreturn a+b'
+ self.assertEquals(PSPUtils.normalizeIndentation(before), expected)
def testSplitLines(self):
-
+
text = 'one\rtwo\rthree'
- self.assertEquals( 3, len( PSPUtils.splitLines( text ) ) )
+ self.assertEquals(3, len(PSPUtils.splitLines(text)))
text = 'one\ntwo\nthree'
- self.assertEquals( 3, len( PSPUtils.splitLines( text ) ) )
-
+ self.assertEquals(3, len(PSPUtils.splitLines(text)))
+
Modified: Webware/trunk/PSP/cl_psp.py
==============================================================================
--- Webware/trunk/PSP/cl_psp.py (original)
+++ Webware/trunk/PSP/cl_psp.py Fri Sep 23 20:46:46 2005
@@ -1,7 +1,6 @@
-
from ServletWriter import ServletWriter
-#from PSPReader import PSPReader
+# from PSPReader import PSPReader
from Context import *
from PSPCompiler import *
@@ -9,38 +8,18 @@
import string
import sys
-
#move this to a class like JPS?
def PSPCompile(*args):
- pspfilename=args[0]
-
-
- fil,ext=string.split(os.path.basename(pspfilename),'.')
- classname = fil + '_' + ext
- pythonfilename = classname + '.py'
-
- context = PSPCLContext(pspfilename)
- context.setClassName(classname)
- context.setPythonFileName(pythonfilename)
-
- clc = Compiler(context)
-
- clc.compile()
+ pspfilename=args[0]
+ fil,ext=string.split(os.path.basename(pspfilename),'.')
+ classname = fil + '_' + ext
+ pythonfilename = classname + '.py'
+ context = PSPCLContext(pspfilename)
+ context.setClassName(classname)
+ context.setPythonFileName(pythonfilename)
+ clc = Compiler(context)
+ clc.compile()
if __name__ == '__main__':
- PSPCompile(sys.argv[1])
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ PSPCompile(sys.argv[1])
|