Skip to content
Browse files

Merge branch 'cog'

  • Loading branch information...
2 parents 06dd742 + 9d9e949 commit 05c9e4c3ac0259dc55ead7e887a0b10cfd7524a0 @jdf committed
View
1 .classpath
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="buildtime/src"/>
<classpathentry kind="src" path="testing/tests"/>
<classpathentry kind="src" path="runtime/src"/>
<classpathentry kind="src" path="runtime/generated"/>
View
6 .pydevproject 100644 → 100755
@@ -2,6 +2,10 @@
<?eclipse-pydev version="1.0"?>
<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Jython</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">jython 2.5</pydev_property>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/processing.py/buildtime/lib/jython/Lib</path>
+<path>/processing.py/buildtime/py</path>
+</pydev_pathproperty>
</pydev_project>
View
31 build.xml
@@ -56,24 +56,19 @@
</copy>
</target>
- <target name="generate-driver"
- depends="build-driver-generator"
- description="Generate DriverImpl class">
- <java classpath="bin:buildtime/lib/processing/core.jar"
- classname="jycessing.build.DriverGenerator"
- fork="true">
- <arg value="buildtime/template/DriverImpl.java"/>
- <arg value="runtime/generated/jycessing/DriverImpl.java"/>
- </java>
- </target>
-
- <target name="build-driver-generator">
- <mkdir dir="bin" />
- <javac srcdir="buildtime/src"
- includes="jycessing/build/**"
- classpath="buildtime/lib/processing/core.jar"
- destdir="bin" />
- </target>
+ <target name="generate-driver"
+ description="Generate DriverImpl class">
+ <java classpath="buildtime/lib/jython/jython.jar:buildtime/lib/processing/core.jar"
+ classname="org.python.util.jython"
+ fork="true">
+ <env key="JYTHONPATH" value="builtime/py/lib"/>
+ <arg value="buildtime/py/cog.py"/>
+ <arg value="-U"/>
+ <arg value="-o"/>
+ <arg value="runtime/generated/jycessing/DriverImpl.java"/>
+ <arg value="buildtime/template/DriverImpl.java.cog"/>
+ </java>
+ </target>
<target name="clean">
<delete dir="bin" />
View
7 buildtime/lib/jython/Lib/cogapp/__init__.py
@@ -0,0 +1,7 @@
+""" Cog code generation tool.
+ http://nedbatchelder.com/code/cog
+
+ Copyright 2004-2005, Ned Batchelder.
+"""
+
+from cogapp import *
View
709 buildtime/lib/jython/Lib/cogapp/cogapp.py
@@ -0,0 +1,709 @@
+""" Cog code generation tool.
+ http://nedbatchelder.com/code/cog
+
+ Copyright 2004-2009, Ned Batchelder.
+"""
+
+import copy, getopt, imp, os, re, string, sys, traceback
+from cStringIO import StringIO
+
+# The recommended way to compute md5's changed in Python 2.5
+try:
+ import hashlib
+ hash_factory = hashlib.md5
+except ImportError:
+ import md5
+ hash_factory = md5.new
+
+__all__ = ['Cog', 'CogUsageError']
+
+__version__ = '2.2' # History at the end of the file.
+
+usage = """\
+cog - generate code with inlined Python code.
+
+cog [OPTIONS] [INFILE | @FILELIST] ...
+
+INFILE is the name of an input file.
+FILELIST is the name of a text file containing file names or
+ other @FILELISTs.
+
+OPTIONS:
+ -c Checksum the output to protect it against accidental change.
+ -d Delete the generator code from the output file.
+ -D name=val Define a global string available to your generator code.
+ -e Warn if a file has no cog code in it.
+ -I PATH Add PATH to the list of directories for data files and modules.
+ -o OUTNAME Write the output to OUTNAME.
+ -r Replace the input file with the output.
+ -s STRING Suffix all generated output lines with STRING.
+ -U Write the output with Unix newlines (only LF line-endings).
+ -w CMD Use CMD if the output file needs to be made writable.
+ A %s in the CMD will be filled with the filename.
+ -x Excise all the generated output without running the generators.
+ -z The [[[end]]] marker can be omitted, and is assumed at eof.
+ -v Print the version of cog and exit.
+ -h Print this help.
+"""
+
+# Other package modules
+from whiteutils import *
+
+class CogError(Exception):
+ """ Any exception raised by Cog.
+ """
+ def __init__(self, msg, file='', line=0):
+ if file:
+ Exception.__init__(self, "%s(%d): %s" % (file, line, msg))
+ else:
+ Exception.__init__(self, msg)
+
+class CogUsageError(CogError):
+ """ An error in usage of command-line arguments in cog.
+ """
+ pass #pragma: no cover
+
+class CogInternalError(CogError):
+ """ An error in the coding of Cog. Should never happen.
+ """
+ pass #pragma: no cover
+
+class CogGeneratedError(CogError):
+ """ An error raised by a user's cog generator.
+ """
+ pass #pragma: no cover
+
+class Redirectable:
+ """ An object with its own stdout and stderr files.
+ """
+ def __init__(self):
+ self.stdout = sys.stdout
+ self.stderr = sys.stderr
+
+ def setOutput(self, stdout=None, stderr=None):
+ """ Assign new files for standard out and/or standard error.
+ """
+ if stdout:
+ self.stdout = stdout
+ if stderr:
+ self.stderr = stderr
+
+class CogGenerator(Redirectable):
+ """ A generator pulled from a source file.
+ """
+ def __init__(self):
+ Redirectable.__init__(self)
+ self.markers = []
+ self.lines = []
+
+ def parseMarker(self, l):
+ self.markers.append(l)
+
+ def parseLine(self, l):
+ self.lines.append(l.strip('\n'))
+
+ def getCode(self):
+ """ Extract the executable Python code from the generator.
+ """
+ # If the markers and lines all have the same prefix
+ # (end-of-line comment chars, for example),
+ # then remove it from all the lines.
+ prefIn = commonPrefix(self.markers + self.lines)
+ if prefIn:
+ self.markers = [ l.replace(prefIn, '', 1) for l in self.markers ]
+ self.lines = [ l.replace(prefIn, '', 1) for l in self.lines ]
+
+ return reindentBlock(self.lines, '')
+
+ def evaluate(self, cog, globals, fname='cog generator'):
+ # figure out the right whitespace prefix for the output
+ prefOut = whitePrefix(self.markers)
+
+ intext = self.getCode()
+ if not intext:
+ return ''
+
+ # In Python 2.2, the last line has to end in a newline.
+ intext = "import cog\n" + intext + "\n"
+ code = compile(intext, str(fname), 'exec')
+
+ # Make sure the "cog" module has our state.
+ cog.cogmodule.msg = self.msg
+ cog.cogmodule.out = self.out
+ cog.cogmodule.outl = self.outl
+ cog.cogmodule.error = self.error
+
+ self.outstring = ''
+ eval(code, globals)
+
+ # We need to make sure that the last line in the output
+ # ends with a newline, or it will be joined to the
+ # end-output line, ruining cog's idempotency.
+ if self.outstring and self.outstring[-1] != '\n':
+ self.outstring += '\n'
+
+ return reindentBlock(self.outstring, prefOut)
+
+ def msg(self, s):
+ print >>self.stdout, "Message: "+s
+
+ def out(self, sOut='', dedent=False, trimblanklines=False):
+ """ The cog.out function.
+ """
+ if trimblanklines and ('\n' in sOut):
+ lines = sOut.split('\n')
+ if lines[0].strip() == '':
+ del lines[0]
+ if lines and lines[-1].strip() == '':
+ del lines[-1]
+ sOut = '\n'.join(lines)+'\n'
+ if dedent:
+ sOut = reindentBlock(sOut)
+ self.outstring += sOut
+
+ def outl(self, sOut='', **kw):
+ """ The cog.outl function.
+ """
+ self.out(sOut, **kw)
+ self.out('\n')
+
+ def error(self, msg='Error raised by cog generator.'):
+ """ The cog.error function.
+ Instead of raising standard python errors, cog generators can use
+ this function. It will display the error without a scary Python
+ traceback.
+ """
+ raise CogGeneratedError(msg)
+
+
+class NumberedFileReader:
+ """ A decorator for files that counts the readline()'s called.
+ """
+ def __init__(self, f):
+ self.f = f
+ self.n = 0
+
+ def readline(self):
+ l = self.f.readline()
+ if l:
+ self.n += 1
+ return l
+
+ def linenumber(self):
+ return self.n
+
+
+class CogOptions:
+ """ Options for a run of cog.
+ """
+ def __init__(self):
+ # Defaults for argument values.
+ self.args = []
+ self.includePath = []
+ self.defines = {}
+ self.bShowVersion = False
+ self.sMakeWritableCmd = None
+ self.bReplace = False
+ self.bNoGenerate = False
+ self.sOutputName = None
+ self.bWarnEmpty = False
+ self.bHashOutput = False
+ self.bDeleteCode = False
+ self.bEofCanBeEnd = False
+ self.sSuffix = None
+ self.bNewlines = False
+
+ def __cmp__(self, other):
+ """ Comparison operator for tests to use.
+ """
+ return self.__dict__.__cmp__(other.__dict__)
+
+ def clone(self):
+ """ Make a clone of these options, for further refinement.
+ """
+ return copy.deepcopy(self)
+
+ def addToIncludePath(self, dirs):
+ """ Add directories to the include path.
+ """
+ dirs = dirs.split(os.pathsep)
+ self.includePath.extend(dirs)
+
+ def parseArgs(self, argv):
+ # Parse the command line arguments.
+ try:
+ opts, self.args = getopt.getopt(argv, 'cdD:eI:o:rs:Uvw:xz')
+ except getopt.error, msg:
+ raise CogUsageError(msg)
+
+ # Handle the command line arguments.
+ for o, a in opts:
+ if o == '-c':
+ self.bHashOutput = True
+ elif o == '-d':
+ self.bDeleteCode = True
+ elif o == '-D':
+ if a.count('=') < 1:
+ raise CogUsageError("-D takes a name=value argument")
+ name, value = a.split('=', 1)
+ self.defines[name] = value
+ elif o == '-e':
+ self.bWarnEmpty = True
+ elif o == '-I':
+ self.addToIncludePath(a)
+ elif o == '-o':
+ self.sOutputName = a
+ elif o == '-r':
+ self.bReplace = True
+ elif o == '-s':
+ self.sSuffix = a
+ elif o == '-U':
+ self.bNewlines = True
+ elif o == '-v':
+ self.bShowVersion = True
+ elif o == '-w':
+ self.sMakeWritableCmd = a
+ elif o == '-x':
+ self.bNoGenerate = True
+ elif o == '-z':
+ self.bEofCanBeEnd = True
+ else:
+ # Since getopt.getopt is given a list of possible flags,
+ # this is an internal error.
+ raise CogInternalError("Don't understand argument %s" % o)
+
+ def validate(self):
+ """ Does nothing if everything is OK, raises CogError's if it's not.
+ """
+ if self.bReplace and self.bDeleteCode:
+ raise CogUsageError("Can't use -d with -r (or you would delete all your source!)")
+
+ if self.bReplace and self.sOutputName:
+ raise CogUsageError("Can't use -o with -r (they are opposites)")
+
+
+class Cog(Redirectable):
+ """ The Cog engine.
+ """
+ def __init__(self):
+ Redirectable.__init__(self)
+ self.sBeginSpec = '[[[cog'
+ self.sEndSpec = ']]]'
+ self.sEndOutput = '[[[end]]]'
+ self.reEndOutput = re.compile(r'\[\[\[end]]](?P<hashsect> *\(checksum: (?P<hash>[a-f0-9]+)\))')
+ self.sEndFormat = '[[[end]]] (checksum: %s)'
+
+ self.options = CogOptions()
+ self.sOutputMode = 'w'
+
+ self.installCogModule()
+
+ def showWarning(self, msg):
+ print >>self.stdout, "Warning:", msg
+
+ def isBeginSpecLine(self, s):
+ return string.find(s, self.sBeginSpec) >= 0
+
+ def isEndSpecLine(self, s):
+ return string.find(s, self.sEndSpec) >= 0 and \
+ not self.isEndOutputLine(s)
+
+ def isEndOutputLine(self, s):
+ return string.find(s, self.sEndOutput) >= 0
+
+ def installCogModule(self):
+ """ Magic mumbo-jumbo so that imported Python modules
+ can say "import cog" and get our state.
+ """
+ self.cogmodule = imp.new_module('cog')
+ self.cogmodule.path = []
+ sys.modules['cog'] = self.cogmodule
+
+ def processFile(self, fIn, fOut, fname=None, globals=None):
+ """ Process an input file object to an output file object.
+ fIn and fOut can be file objects, or file names.
+ """
+
+ sFileIn = fname or ''
+ sFileOut = fname or ''
+ fInToClose = fOutToClose = None
+ # Convert filenames to files.
+ if isinstance(fIn, basestring):
+ # Open the input file.
+ sFileIn = fIn
+ fIn = fInToClose = open(fIn, 'r')
+ if isinstance(fOut, basestring):
+ # Open the output file.
+ sFileOut = fOut
+ fOut = fOutToClose = open(fOut, self.sOutputMode)
+
+ try:
+ fIn = NumberedFileReader(fIn)
+
+ bSawCog = False
+
+ self.cogmodule.inFile = sFileIn
+ self.cogmodule.outFile = sFileOut
+
+ # The globals dict we'll use for this file.
+ if globals is None:
+ globals = {}
+
+ # If there are any global defines, put them in the globals.
+ globals.update(self.options.defines)
+
+ # loop over generator chunks
+ l = fIn.readline()
+ while l:
+ # Find the next spec begin
+ while l and not self.isBeginSpecLine(l):
+ if self.isEndSpecLine(l):
+ raise CogError("Unexpected '%s'" % self.sEndSpec,
+ file=sFileIn, line=fIn.linenumber())
+ if self.isEndOutputLine(l):
+ raise CogError("Unexpected '%s'" % self.sEndOutput,
+ file=sFileIn, line=fIn.linenumber())
+ fOut.write(l)
+ l = fIn.readline()
+ if not l:
+ break
+ if not self.options.bDeleteCode:
+ fOut.write(l)
+
+ # l is the begin spec
+ gen = CogGenerator()
+ gen.setOutput(stdout=self.stdout)
+ gen.parseMarker(l)
+ firstLineNum = fIn.linenumber()
+ self.cogmodule.firstLineNum = firstLineNum
+
+ # If the spec begin is also a spec end, then process the single
+ # line of code inside.
+ if self.isEndSpecLine(l):
+ beg = string.find(l, self.sBeginSpec)
+ end = string.find(l, self.sEndSpec)
+ if beg > end:
+ raise CogError("Cog code markers inverted",
+ file=sFileIn, line=firstLineNum)
+ else:
+ sCode = l[beg+len(self.sBeginSpec):end].strip()
+ gen.parseLine(sCode)
+ else:
+ # Deal with an ordinary code block.
+ l = fIn.readline()
+
+ # Get all the lines in the spec
+ while l and not self.isEndSpecLine(l):
+ if self.isBeginSpecLine(l):
+ raise CogError("Unexpected '%s'" % self.sBeginSpec,
+ file=sFileIn, line=fIn.linenumber())
+ if self.isEndOutputLine(l):
+ raise CogError("Unexpected '%s'" % self.sEndOutput,
+ file=sFileIn, line=fIn.linenumber())
+ if not self.options.bDeleteCode:
+ fOut.write(l)
+ gen.parseLine(l)
+ l = fIn.readline()
+ if not l:
+ raise CogError(
+ "Cog block begun but never ended.",
+ file=sFileIn, line=firstLineNum)
+
+ if not self.options.bDeleteCode:
+ fOut.write(l)
+ gen.parseMarker(l)
+
+ l = fIn.readline()
+
+ # Eat all the lines in the output section. While reading past
+ # them, compute the md5 hash of the old output.
+ hasher = hash_factory()
+ while l and not self.isEndOutputLine(l):
+ if self.isBeginSpecLine(l):
+ raise CogError("Unexpected '%s'" % self.sBeginSpec,
+ file=sFileIn, line=fIn.linenumber())
+ if self.isEndSpecLine(l):
+ raise CogError("Unexpected '%s'" % self.sEndSpec,
+ file=sFileIn, line=fIn.linenumber())
+ hasher.update(l)
+ l = fIn.readline()
+ curHash = hasher.hexdigest()
+
+ if not l and not self.options.bEofCanBeEnd:
+ # We reached end of file before we found the end output line.
+ raise CogError("Missing '%s' before end of file." % self.sEndOutput,
+ file=sFileIn, line=fIn.linenumber())
+
+ # Write the output of the spec to be the new output if we're
+ # supposed to generate code.
+ hasher = hash_factory()
+ if not self.options.bNoGenerate:
+ sFile = "%s+%d" % (sFileIn, firstLineNum)
+ sGen = gen.evaluate(cog=self, globals=globals, fname=sFile)
+ sGen = self.suffixLines(sGen)
+ hasher.update(sGen)
+ fOut.write(sGen)
+ newHash = hasher.hexdigest()
+
+ bSawCog = True
+
+ # Write the ending output line
+ hashMatch = self.reEndOutput.search(l)
+ if self.options.bHashOutput:
+ if hashMatch:
+ oldHash = hashMatch.groupdict()['hash']
+ if oldHash != curHash:
+ raise CogError("Output has been edited! Delete old checksum to unprotect.",
+ file=sFileIn, line=fIn.linenumber())
+ # Create a new end line with the correct hash.
+ endpieces = l.split(hashMatch.group(0), 1)
+ else:
+ # There was no old hash, but we want a new hash.
+ endpieces = l.split(self.sEndOutput, 1)
+ l = (self.sEndFormat % newHash).join(endpieces)
+ else:
+ # We don't want hashes output, so if there was one, get rid of
+ # it.
+ if hashMatch:
+ l = l.replace(hashMatch.groupdict()['hashsect'], '', 1)
+
+ if not self.options.bDeleteCode:
+ fOut.write(l)
+ l = fIn.readline()
+
+ if not bSawCog and self.options.bWarnEmpty:
+ self.showWarning("no cog code found in %s" % sFileIn)
+ finally:
+ if fInToClose:
+ fInToClose.close()
+ if fOutToClose:
+ fOutToClose.close()
+
+
+ # A regex for non-empty lines, used by suffixLines.
+ reNonEmptyLines = re.compile("^\s*\S+.*$", re.MULTILINE)
+
+ def suffixLines(self, text):
+ """ Add suffixes to the lines in text, if our options desire it.
+ text is many lines, as a single string.
+ """
+ if self.options.sSuffix:
+ # Find all non-blank lines, and add the suffix to the end.
+ repl = r"\g<0>" + self.options.sSuffix.replace('\\', '\\\\')
+ text = self.reNonEmptyLines.sub(repl, text)
+ return text
+
+ def processString(self, sInput, fname=None):
+ """ Process sInput as the text to cog.
+ Return the cogged output as a string.
+ """
+ fOld = StringIO(sInput)
+ fNew = StringIO()
+ self.processFile(fOld, fNew, fname=fname)
+ return fNew.getvalue()
+
+ def replaceFile(self, sOldPath, sNewText):
+ """ Replace file sOldPath with the contents sNewText
+ """
+ if not os.access(sOldPath, os.W_OK):
+ # Need to ensure we can write.
+ if self.options.sMakeWritableCmd:
+ # Use an external command to make the file writable.
+ cmd = self.options.sMakeWritableCmd.replace('%s', sOldPath)
+ self.stdout.write(os.popen(cmd).read())
+ if not os.access(sOldPath, os.W_OK):
+ raise CogError("Couldn't make %s writable" % sOldPath)
+ else:
+ # Can't write!
+ raise CogError("Can't overwrite %s" % sOldPath)
+ f = open(sOldPath, self.sOutputMode)
+ f.write(sNewText)
+ f.close()
+
+ def saveIncludePath(self):
+ self.savedInclude = self.options.includePath[:]
+ self.savedSysPath = sys.path[:]
+
+ def restoreIncludePath(self):
+ self.options.includePath = self.savedInclude
+ self.cogmodule.path = self.options.includePath
+ sys.path = self.savedSysPath
+
+ def addToIncludePath(self, includePath):
+ self.cogmodule.path.extend(includePath)
+ sys.path.extend(includePath)
+
+ def processOneFile(self, sFile):
+ """ Process one filename through cog.
+ """
+
+ self.saveIncludePath()
+
+ try:
+ self.addToIncludePath(self.options.includePath)
+ # Since we know where the input file came from,
+ # push its directory onto the include path.
+ self.addToIncludePath([os.path.dirname(sFile)])
+
+ # Set the file output mode based on whether we want \n or native
+ # line endings.
+ self.sOutputMode = 'w'
+ if self.options.bNewlines:
+ self.sOutputMode = 'wb'
+
+ # How we process the file depends on where the output is going.
+ if self.options.sOutputName:
+ self.processFile(sFile, self.options.sOutputName, sFile)
+ elif self.options.bReplace:
+ # We want to replace the cog file with the output,
+ # but only if they differ.
+ print >>self.stdout, "Cogging %s" % sFile,
+ bNeedNewline = True
+
+ try:
+ fOldFile = open(sFile)
+ sOldText = fOldFile.read()
+ fOldFile.close()
+ sNewText = self.processString(sOldText, fname=sFile)
+ if sOldText != sNewText:
+ print >>self.stdout, " (changed)"
+ bNeedNewline = False
+ self.replaceFile(sFile, sNewText)
+ finally:
+ # The try-finally block is so we can print a partial line
+ # with the name of the file, and print (changed) on the
+ # same line, but also make sure to break the line before
+ # any traceback.
+ if bNeedNewline:
+ print >>self.stdout
+ else:
+ self.processFile(sFile, self.stdout, sFile)
+ finally:
+ self.restoreIncludePath()
+
+ def processFileList(self, sFileList):
+ """ Process the files in a file list.
+ """
+ flist = open(sFileList)
+ lines = flist.readlines()
+ flist.close()
+ for l in lines:
+ # Use shlex to parse the line like a shell.
+ lex = shlex.shlex(l, posix=True)
+ lex.whitespace_split = True
+ lex.commenters = '#'
+ # No escapes, so that backslash can be part of the path
+ lex.escape = ''
+ args = list(lex)
+ if args:
+ self.processArguments(args)
+
+ def processArguments(self, args):
+ """ Process one command-line.
+ """
+ saved_options = self.options
+ self.options = self.options.clone()
+
+ self.options.parseArgs(args[1:])
+ self.options.validate()
+
+ if args[0][0] == '@':
+ if self.options.sOutputName:
+ raise CogUsageError("Can't use -o with @file")
+ self.processFileList(args[0][1:])
+ else:
+ self.processOneFile(args[0])
+
+ self.options = saved_options
+
+ def callableMain(self, argv):
+ """ All of command-line cog, but in a callable form.
+ This is used by main.
+ argv is the equivalent of sys.argv.
+ """
+ argv0 = argv.pop(0)
+
+ # Provide help if asked for anywhere in the command line.
+ if '-?' in argv or '-h' in argv:
+ print >>self.stderr, usage,
+ return
+
+ self.options.parseArgs(argv)
+ self.options.validate()
+
+ if self.options.bShowVersion:
+ print >>self.stdout, "Cog version %s" % __version__
+ return
+
+ if self.options.args:
+ for a in self.options.args:
+ self.processArguments([a])
+ else:
+ raise CogUsageError("No files to process")
+
+ def main(self, argv):
+ """ Handle the command-line execution for cog.
+ """
+
+ try:
+ self.callableMain(argv)
+ return 0
+ except CogUsageError, err:
+ print >>self.stderr, err
+ print >>self.stderr, "(for help use -?)"
+ return 2
+ except CogGeneratedError, err:
+ print >>self.stderr, "Error: %s" % err
+ return 3
+ except CogError, err:
+ print >>self.stderr, err
+ return 1
+ except:
+ traceback.print_exc(None, self.stderr)
+ return 1
+
+# History:
+# 20040210: First public version.
+# 20040220: Text preceding the start and end marker are removed from Python lines.
+# -v option on the command line shows the version.
+# 20040311: Make sure the last line of output is properly ended with a newline.
+# 20040605: Fixed some blank line handling in cog.
+# Fixed problems with assigning to xml elements in handyxml.
+# 20040621: Changed all line-ends to LF from CRLF.
+# 20041002: Refactor some option handling to simplify unittesting the options.
+# 20041118: cog.out and cog.outl have optional string arguments.
+# 20041119: File names weren't being properly passed around for warnings, etc.
+# 20041122: Added cog.firstLineNum: a property with the line number of the [[[cog line.
+# Added cog.inFile and cog.outFile: the names of the input and output file.
+# 20041218: Single-line cog generators, with start marker and end marker on
+# the same line.
+# 20041230: Keep a single globals dict for all the code fragments in a single
+# file so they can share state.
+# 20050206: Added the -x switch to remove all generated output.
+# 20050218: Now code can be on the marker lines as well.
+# 20050219: Added -c switch to checksum the output so that edits can be
+# detected before they are obliterated.
+# 20050521: Added cog.error, contributed by Alexander Belchenko.
+# 20050720: Added code deletion and settable globals contributed by Blake Winton.
+# 20050724: Many tweaks to improve code coverage.
+# 20050726: Error messages are now printed with no traceback.
+# Code can no longer appear on the marker lines,
+# except for single-line style.
+# -z allows omission of the [[[end]]] marker, and it will be assumed
+# at the end of the file.
+# 20050729: Refactor option parsing into a separate class, in preparation for
+# future features.
+# 20050805: The cogmodule.path wasn't being properly maintained.
+# 20050808: Added the -D option to define a global value.
+# 20050810: The %s in the -w command is dealt with more robustly.
+# Added the -s option to suffix output lines with a marker.
+# 20050817: Now @files can have arguments on each line to change the cog's
+# behavior for that line.
+# 20051006: Version 2.0
+# 20080521: -U options lets you create Unix newlines on Windows. Thanks,
+# Alexander Belchenko.
+# 20080522: It's now ok to have -d with output to stdout, and now we validate
+# the args after each line of an @file.
+# 20090520: Use hashlib where it's available, to avoid a warning.
+# Use the builtin compile() instead of compiler, for Jython.
+# Explicitly close files we opened, Jython likes this.
View
63 buildtime/lib/jython/Lib/cogapp/whiteutils.py
@@ -0,0 +1,63 @@
+""" Indentation utilities for Cog.
+ http://nedbatchelder.com/code/cog
+
+ Copyright 2004-2009, Ned Batchelder.
+"""
+
+import re
+
+def whitePrefix(strings):
+ """ Determine the whitespace prefix common to all non-blank lines
+ in the argument list.
+ """
+ # Remove all blank lines from the list
+ strings = [s for s in strings if s.strip() != '']
+
+ if not strings: return ''
+
+ # Find initial whitespace chunk in the first line.
+ # This is the best prefix we can hope for.
+ prefix = re.match(r'\s*', strings[0]).group(0)
+
+ # Loop over the other strings, keeping only as much of
+ # the prefix as matches each string.
+ for s in strings:
+ for i in range(len(prefix)):
+ if prefix[i] != s[i]:
+ prefix = prefix[:i]
+ break
+ return prefix
+
+def reindentBlock(lines, newIndent=''):
+ """ Take a block of text as a string or list of lines.
+ Remove any common whitespace indentation.
+ Re-indent using newIndent, and return it as a single string.
+ """
+ if isinstance(lines, basestring):
+ lines = lines.split('\n')
+ oldIndent = whitePrefix(lines)
+ outLines = []
+ for l in lines:
+ if oldIndent:
+ l = l.replace(oldIndent, '', 1)
+ if l and newIndent:
+ l = newIndent + l
+ outLines.append(l)
+ return '\n'.join(outLines)
+
+def commonPrefix(strings):
+ """ Find the longest string that is a prefix of all the strings.
+ """
+ if not strings:
+ return ''
+ prefix = strings[0]
+ for s in strings:
+ if len(s) < len(prefix):
+ prefix = prefix[:len(s)]
+ if not prefix:
+ return ''
+ for i in range(len(prefix)):
+ if prefix[i] != s[i]:
+ prefix = prefix[:i]
+ break
+ return prefix
View
17 buildtime/py/cog.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+""" Cog code generation tool.
+ http://nedbatchelder.com/code/cog
+
+ Copyright 2004-2005, Ned Batchelder.
+"""
+
+import time
+start = time.clock()
+
+import sys
+from cogapp import Cog
+
+ret = Cog().main(sys.argv)
+
+#print "Time: %.2f sec" % (time.clock() - start)
+sys.exit(ret)
View
255 buildtime/py/processing_parser.py
@@ -0,0 +1,255 @@
+import __builtin__
+
+import re
+import cog
+
+from java.lang.reflect import Field, Method, Modifier
+from java.lang import Class, String, Void
+from processing.core import PApplet
+
+
+BAD_FIELD = re.compile(r'''
+ ^(
+ screen|args|recorder|frame|g|selectedFile|keyEvent|mouseEvent
+ |sketchPath|screen(Width|Height)|defaultSize|firstMouse|finished
+ |requestImageMax
+ )$
+ ''', re.X)
+
+
+BAD_METHOD = re.compile(r'''
+ ^(
+ init|handleDraw|draw|parse[A-Z].*|arraycopy|openStream|str|.*Pressed
+ |.*Released|(un)?register[A-Z].*|print(ln)?|setup[A-Z].+|thread
+ |(get|set|remove)Cache|max|update|destroy|main|flush|addListeners|dataFile
+ |die|setup|mouseE(ntered|xited)|paint|sketch[A-Z].*|stop|save(File|Path)
+ |displayable|method|runSketch|start|focus(Lost|Gained)|(data|create)Path
+ )$
+ ''', re.X)
+
+
+# I don't know of any other way to refer to primitive classes in Jython.
+prim = lambda(type_name): Class.forName(type_name).getField("TYPE").get(None)
+PRIMITIVES = { 'int': prim("java.lang.Integer"),
+ 'char': prim("java.lang.Character"),
+ 'byte': prim("java.lang.Byte"),
+ 'long': prim("java.lang.Long"),
+ 'double': prim("java.lang.Double"),
+ 'float': prim("java.lang.Float"),
+ 'boolean': prim("java.lang.Boolean") }
+
+CHAR_TYPES = (PRIMITIVES['char'], Class.forName('[C'))
+WANTED_METHODS = [m for m in Class.getDeclaredMethods(PApplet)
+ if Modifier.isPublic(m.getModifiers())
+ and not BAD_METHOD.match(m.getName())
+ and not any(k in CHAR_TYPES for k in m.getParameterTypes())]
+
+WANTED_FIELDS = [f for f in Class.getDeclaredFields(PApplet)
+ if Modifier.isPublic(f.getModifiers())
+ and not Modifier.isStatic(f.getModifiers())
+ and not BAD_FIELD.match(f.getName())]
+
+class ClassConversionInfo(object):
+ def __init__(self, to_python_prefix, to_java_format, typecheck_format):
+ self.to_python_prefix = to_python_prefix
+ self.to_java_format = to_java_format
+ self.typecheck_format = typecheck_format
+
+"""
+ Mapping from java type to various expressions needed in code
+ generation around those types.
+"""
+CONVERSIONS = {
+ PRIMITIVES['int']:
+ ClassConversionInfo('new PyInteger',
+ '%s.asInt()',
+ '%(name)s == PyInteger.TYPE'),
+ PRIMITIVES['byte']:
+ ClassConversionInfo(None,
+ '(byte)%s.asInt()',
+ '%(name)s == PyInteger.TYPE'),
+ PRIMITIVES['float']:
+ ClassConversionInfo('new PyFloat',
+ '(float)%s.asDouble()',
+ '(%(name)s == PyFloat.TYPE '
+ '|| %(name)s == PyInteger.TYPE '
+ '|| %(name)s == PyLong.TYPE)'),
+ PRIMITIVES['long']:
+ ClassConversionInfo('new PyLong',
+ '%s.asLong()',
+ None),
+ Class.forName("java.lang.String"):
+ ClassConversionInfo('new PyString',
+ '%s.asString()',
+ '%(name)s == PyString.TYPE'),
+ PRIMITIVES['char']:
+ ClassConversionInfo('new PyString',
+ '%s.asString().charAt(0)',
+ None),
+ PRIMITIVES['boolean']:
+ ClassConversionInfo('new PyBoolean',
+ '%s.__nonzero__()',
+ '%(name)s == PyBoolean.TYPE')
+}
+
+def emit_python_prefix(klass):
+ try:
+ cog.out(CONVERSIONS[klass].to_python_prefix)
+ except (KeyError, AttributeError):
+ if klass.isPrimitive():
+ raise Exception("You need a converter for %s" % klass.getName())
+ cog.out('Py.java2py')
+ cog.out('(')
+
+def emit_java_expression(klass, name):
+ try:
+ cog.out(CONVERSIONS[klass].to_java_format % name)
+ except KeyError:
+ if klass.isPrimitive():
+ raise Exception("You need a converter for %s" % klass.getName())
+ simpleName = Class.getName(klass)
+ if klass.isArray():
+ simpleName = Class.getSimpleName(klass)
+ if simpleName != 'java.lang.Object':
+ cog.out('(%s)' % simpleName)
+ cog.out('%s.__tojava__(%s.class)' % (name, simpleName))
+
+def emit_typecheck_expression(klass, name):
+ try:
+ cog.out(CONVERSIONS[klass].typecheck_format % {'name': name})
+ except (TypeError, KeyError):
+ if klass.isPrimitive():
+ raise Exception("You need a converter for %s" % klass.getName())
+ cog.out('%s.getProxyType() != null '
+ '&& %s.getProxyType() == %s.class' % (name,
+ name,
+ Class.getSimpleName(klass)))
+
+def is_builtin(name):
+ return name in ('map', 'filter', 'set', 'str')
+
+class PolymorphicMethod(object):
+ def __init__(self, name, arity):
+ self.name = name
+ self.arity = arity
+ self.methods = []
+
+ def add_method(self, m):
+ assert len(m.getParameterTypes()) == self.arity
+ self.methods.append(m)
+
+ def emit_method(self, m):
+ if m.getReturnType() is not Void.TYPE:
+ cog.out('return ')
+ emit_python_prefix(m.getReturnType())
+ cog.out('%s(' % self.name)
+ for i in range(self.arity):
+ if i > 0:
+ cog.out(', ')
+ emit_java_expression(m.getParameterTypes()[i], 'args[%d]' % i)
+ cog.out(')')
+ if m.getReturnType() is Void.TYPE:
+ cog.outl(';')
+ cog.outl('\t\t\t\treturn Py.None;')
+ else:
+ cog.outl(');')
+
+ def emit(self):
+ cog.outl('\t\t\tcase %d: {' % self.arity)
+ if len(self.methods) == 1 and not is_builtin(self.name):
+ cog.out('\t\t\t\t')
+ self.emit_method(self.methods[0])
+ else:
+ for i in range(self.arity):
+ cog.outl('\t\t\t\tfinal PyType t%d = args[%d].getType();' % (i, i))
+ self.methods.sort(key=lambda p: [m.getSimpleName() for m in p.getParameterTypes()])
+ for i in range(len(self.methods)):
+ m = self.methods[i]
+ if i > 0:
+ cog.out(' else ')
+ else:
+ cog.out('\t\t\t\t')
+ if self.arity > 0:
+ cog.out('if (')
+ for j in range(self.arity):
+ if j > 0:
+ cog.out(' && ')
+ emit_typecheck_expression(m.getParameterTypes()[j],
+ 't%d' % j)
+ cog.out(') {\n\t\t\t\t\t')
+ self.emit_method(m)
+ if self.arity > 0:
+ cog.out('\t\t\t\t}')
+ if is_builtin(self.name):
+ cog.outl(' else { return %s_builtin.__call__(args, kws); }' % self.name)
+ elif self.arity > 0:
+ cog.outl(' else { throw new UnexpectedInvocationError'
+ '("%s", args, kws); }' % self.name)
+ cog.outl('\t\t\t}')
+
+
+class Binding(object):
+ def __init__(self, name):
+ self.name = name
+ self.field = None
+ self.methods = {}
+
+ def add_method(self, m):
+ arity = len(m.getParameterTypes())
+ pm = self.methods.setdefault(arity, PolymorphicMethod(self.name, arity))
+ pm.add_method(m)
+
+ def set_field(self, f):
+ if self.field:
+ raise Exception("Binding %s's field was already set!" % self.name)
+ self.field = f
+
+ def emit(self):
+ has_methods = len(self.methods.values()) > 0
+ is_wrapped_integer = self.field and self.field.getType() == PRIMITIVES['int']
+ n = self.name
+ if is_builtin(n):
+ cog.outl('final PyObject %s_builtin = builtins.__getitem__("%s");' % (n, n))
+ cog.out('builtins.__setitem__("%s",' % n)
+ if self.field:
+ if is_wrapped_integer:
+ cog.out('new WrappedInteger()')
+ else:
+ emit_python_prefix(self.field.getType())
+ cog.out('%s)' % n)
+ else:
+ cog.out('new PyObject()')
+ if has_methods or is_wrapped_integer:
+ cog.outl('{')
+ if has_methods:
+ cog.outl('\tpublic PyObject __call__(final PyObject[] args, final String[] kws) {')
+ cog.outl('\t\tswitch(args.length) {')
+ cog.outl('\t\t\tdefault: ');
+ cog.out('\t\t\t\t')
+ if is_builtin(n):
+ cog.outl('return %s_builtin.__call__(args, kws);' % n)
+ else:
+ cog.outl('throw new RuntimeException("Can\'t call \\"%s\\" with "'
+ ' + args.length + " parameters."); ' % n)
+ for k in sorted(self.methods.keys()):
+ self.methods[k].emit()
+ cog.outl('\t\t}\n\t}')
+ if is_wrapped_integer:
+ cog.outl('\tpublic int getValue() { return %s; }' % n)
+ if has_methods or is_wrapped_integer:
+ cog.out('}')
+ cog.outl(');')
+
+bindings = {}
+for m in WANTED_METHODS:
+ bindings.setdefault(m.getName(), Binding(m.getName())).add_method(m)
+for f in WANTED_FIELDS:
+ bindings.setdefault(f.getName(), Binding(f.getName())).set_field(f)
+
+simple_method_bindings = [b for b in bindings.values() if not b.field]
+integer_field_bindings = [b for b in bindings.values()
+ if b.field
+ and b.field.getType() is PRIMITIVES['int']]
+field_bindings = [b for b in bindings.values()
+ if b.field
+ and b.field.getType() is not PRIMITIVES['int']]
View
121 buildtime/src/jycessing/build/Binding.java
@@ -1,121 +0,0 @@
-/*
- * Copyright 2010 Jonathan Feinberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package jycessing.build;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-
-public class Binding {
- private final String name;
- private final ArrayList<PolymorphicMethod> methods = new ArrayList<PolymorphicMethod>();
- private Field global = null;
- private final boolean isPythonBuiltin;
-
- public Binding(final String name, final boolean isPythonBuiltin) {
- this.name = name;
- this.isPythonBuiltin = isPythonBuiltin;
- }
-
- public boolean hasGlobal() {
- return global != null;
- }
-
- public Class<?> getGlobalType() {
- return global.getType();
- }
-
- public String toString() {
- final boolean hasMethods = methods.size() > 0;
- final boolean isWrappedInteger = hasGlobal()
- && global.getType().equals(int.class);
-
- final StringBuilder sb = new StringBuilder();
- if (isPythonBuiltin) {
- sb.append("final PyObject ").append(name).append("_builtin = ");
- sb.append(String.format("builtins.__getitem__(\"%s\");\n", name));
- }
- sb.append(String.format("builtins.__setitem__(\"%s\", ", name));
-
- if (hasGlobal()) {
- if (isWrappedInteger) {
- sb.append("new WrappedInteger()");
- } else {
- sb.append(TypeUtil.pyConversionPrefix(global.getType()));
- sb.append(global.getName());
- sb.append(")");
- }
- } else {
- sb.append("new PyObject()");
- }
- if (hasMethods || isWrappedInteger) {
- sb.append("{");
- }
- if (hasMethods) {
- sb
- .append("\tpublic PyObject __call__(final PyObject[] args, final String[] kws) {\n");
- sb.append("\t\tswitch(args.length) {\n");
- sb.append("\t\t\tdefault: ");
- if (isPythonBuiltin) {
- sb.append("return ").append(name).append(
- "_builtin.__call__(args, kws);\n");
- } else {
- sb.append("throw new RuntimeException(\"");
- sb.append(String.format(
- "Can't call \\\"%s\\\" with \" + args.length + \" parameters.",
- name));
- sb.append("\");\n");
- }
- for (final PolymorphicMethod m : methods) {
- if (m == null) {
- continue;
- }
- sb.append(m.toString());
- }
- sb.append("\t\t}\n\t}\n");
- }
- if (isWrappedInteger) {
- sb.append("\tpublic int getValue() { return ").append(name).append("; }\n");
- }
- if (hasMethods || isWrappedInteger) {
- sb.append("}");
- }
- sb.append(");\n");
-
- return sb.toString();
- }
-
- public void add(final Method m) {
- final int arity = m.getParameterTypes().length;
- if (methods.size() < arity + 1) {
- for (int i = methods.size(); i < arity + 1; i++) {
- methods.add(null);
- }
- }
- if (methods.get(arity) == null) {
- methods.set(arity, new PolymorphicMethod(name, arity, isPythonBuiltin));
- }
- methods.get(arity).add(m);
- }
-
- public void setField(final Field f) {
- if (global != null) {
- throw new IllegalStateException("Binding " + name
- + "'s global was already set!");
- }
- global = f;
- }
-}
View
167 buildtime/src/jycessing/build/DriverGenerator.java
@@ -1,167 +0,0 @@
-/*
- * Copyright 2010 Jonathan Feinberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package jycessing.build;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Reader;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import processing.core.PApplet;
-
-@SuppressWarnings("serial")
-public class DriverGenerator {
- final String BAD_METHOD = "^(" //
- + "init|handleDraw|draw|parse[A-Z].*"
- + "|arraycopy|openStream|str|.*Pressed|.*Released"
- + "|(un)?register[A-Z].*|print(ln)?|setup[A-Z].+|thread" //
- + "|(get|set|remove)Cache|max|update|destroy|main|flush" //
- + "|addListeners|dataFile|die|setup|mouseE(ntered|xited)" //
- + "|paint|sketch[A-Z].*|stop|save(File|Path)|displayable|method" //
- + "|runSketch|start|focus(Lost|Gained)" //
- + ")$";
-
- private static final Set<String> BAD_FIELDS = new HashSet<String>(
- Arrays.asList("screen", "args", "recorder", "frame", "g",
- "selectedFile", "keyEvent", "mouseEvent", "sketchPath",
- "screenWidth", "screenHeight", "defaultSize", "firstMouse",
- "finished", "requestImageMax"));
-
- private static final Set<String> ALL_APPLET_METHODS = Collections
- .unmodifiableSet(new HashSet<String>() {
- {
- for (final Method m : PApplet.class.getDeclaredMethods()) {
- if (!Modifier.isPublic(m.getModifiers())) {
- continue;
- }
- add(m.getName());
- }
- }
- });
-
- private static final Set<String> PYTHON_BUILTINS = new HashSet<String>(
- Arrays.asList("map", "filter", "set", "str"));
-
- final Map<String, Binding> bindings = new HashMap<String, Binding>();
-
- public DriverGenerator() {
- for (final Method m : PApplet.class.getDeclaredMethods()) {
- maybeAdd(m);
- }
- for (final Field f : PApplet.class.getDeclaredFields()) {
- maybeAdd(f);
- }
- }
-
- private Binding findOrCreateBinding(final String name) {
- if (!bindings.containsKey(name)) {
- bindings.put(name,
- new Binding(name, PYTHON_BUILTINS.contains(name)));
- }
- return bindings.get(name);
- }
-
- private void maybeAdd(final Method m) {
- final String name = m.getName();
- final int mods = m.getModifiers();
- if (!Modifier.isPublic(mods) || !PolymorphicMethod.shouldAdd(m)
- || name.matches(BAD_METHOD)
- || !ALL_APPLET_METHODS.contains(name)) {
- return;
- }
- findOrCreateBinding(name).add(m);
- }
-
- private void maybeAdd(final Field f) {
- final String name = f.getName();
- final int mods = f.getModifiers();
- if (!Modifier.isPublic(mods) || Modifier.isStatic(mods)
- || BAD_FIELDS.contains(name)) {
- return;
- }
- findOrCreateBinding(name).setField(f);
- }
-
- public String getMethodBindings() {
- final StringBuilder sb = new StringBuilder();
- for (final Binding b : bindings.values()) {
- if (!b.hasGlobal()) {
- sb.append(b.toString());
- }
- }
- return sb.toString();
- }
-
- public String getFieldBindings() {
- final StringBuilder sb = new StringBuilder();
- for (final Binding b : bindings.values()) {
- if (b.hasGlobal() && !b.getGlobalType().equals(int.class)) {
- sb.append(b.toString());
- }
- }
- return sb.toString();
- }
-
- public String getIntegerFieldBindings() {
- final StringBuilder sb = new StringBuilder();
- for (final Binding b : bindings.values()) {
- if (b.hasGlobal() && b.getGlobalType().equals(int.class)) {
- sb.append(b.toString());
- }
- }
- return sb.toString();
- }
-
- public static String getText(final Reader r) throws IOException {
- final BufferedReader reader = new BufferedReader(r);
- final StringBuilder sb = new StringBuilder();
- String line;
- try {
- while ((line = reader.readLine()) != null) {
- sb.append(line).append("\n");
- }
- return sb.toString();
- } finally {
- reader.close();
- }
- }
-
- public static void main(final String[] args) throws Exception {
- final DriverGenerator gen = new DriverGenerator();
-
- final String template = getText(new FileReader(args[0]));
- final String withMethodBindings = template.replace("%METHOD_BINDINGS%",
- gen.getMethodBindings());
- final String withFieldBindings = withMethodBindings.replace(
- "%FIELD_BINDINGS%", gen.getFieldBindings());
- final String withIntegerFieldBindings = withFieldBindings.replace(
- "%INTEGER_FIELD_BINDINGS%", gen.getIntegerFieldBindings());
-
- final FileWriter out = new FileWriter(args[1]);
- out.write(withIntegerFieldBindings);
- out.close();
- }
-}
View
161 buildtime/src/jycessing/build/PolymorphicMethod.java
@@ -1,161 +0,0 @@
-/*
- * Copyright 2010 Jonathan Feinberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package jycessing.build;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class PolymorphicMethod {
- private final String name;
- private final int arity;
- private final List<Signature> signatures = new ArrayList<Signature>();
- private final boolean isPythonBuiltin;
-
- public PolymorphicMethod(final String name, final int arity,
- final boolean isPythonBuiltin) {
- this.name = name;
- this.arity = arity;
- this.isPythonBuiltin = isPythonBuiltin;
- }
-
- public static boolean shouldAdd(final Method method) {
- final Class<?>[] types = method.getParameterTypes();
- for (final Class<?> k : types) {
- if (k == char.class || k == char[].class) {
- return false;
- }
- }
- return true;
- }
-
- public void add(final Method method) {
- final Class<?>[] types = method.getParameterTypes();
- if (types.length != arity) {
- throw new IllegalArgumentException("I expect methods with " + arity
- + " args, but got " + method);
- }
- if (!shouldAdd(method)) {
- throw new IllegalArgumentException("I can't cope with " + method
- + " because it's evil.");
- }
- signatures.add(new Signature(method));
- }
-
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append(String.format("\t\t\tcase %d: {\n", arity));
- if (!isPythonBuiltin && signatures.size() == 1) {
- sb.append("\t\t\t\t");
- append(signatures.get(0), sb);
- } else {
- for (int i = 0; i < arity; i++) {
- final String typeTemp = "\t\t\t\tfinal PyType t%d = args[%d].getType();\n";
- sb.append(String.format(typeTemp, i, i));
- }
- Collections.sort(signatures);
- for (int i = 0; i < signatures.size(); i++) {
- final Signature sig = signatures.get(i);
- if (i > 0) {
- sb.append(" else ");
- } else {
- sb.append("\t\t\t\t");
- }
- if (arity > 0) {
- sb.append("if (");
- for (int j = 0; j < arity; j++) {
- if (j > 0) {
- sb.append(" && ");
- }
- final String typeExpr = String.format("t%d", j);
- sb.append(sig.getTypecheckExpression(j, typeExpr));
- }
- sb.append(") {\n\t\t\t\t\t");
- }
- append(sig, sb);
- if (arity > 0) {
- sb.append("\t\t\t\t}");
- }
- }
- if (isPythonBuiltin) {
- sb.append(" else { return ").append(name).append(
- "_builtin.__call__(args, kws); }\n");
- } else if (arity > 0) {
- sb.append(" else { throw new UnexpectedInvocationError(\"");
- sb.append(name);
- sb.append("\", args, kws); }\n");
- }
- }
- sb.append("\t\t\t}\n");
- return sb.toString();
- }
-
- private void append(final Signature signature, final StringBuilder sb) {
- if (!signature.isVoid()) {
- final String prefix = TypeUtil.pyConversionPrefix(signature.getReturnType());
- sb.append("return ").append(prefix);
- }
- sb.append(name).append('(');
- for (int i = 0; i < arity; i++) {
- if (i > 0) {
- sb.append(", ");
- }
- sb.append(asJavaExpression(signature, i));
- }
- sb.append(')');
- if (signature.isVoid()) {
- sb.append(";\n");
- sb.append("\t\t\t\treturn Py.None;");
- } else {
- sb.append(");");
- }
- sb.append('\n');
- }
-
- public static String asJavaExpression(final Signature signature, final int i) {
- final String name = "args[" + i + "]";
- final Class<?> javaType = signature.getArgType(i);
- final StringBuilder sb = new StringBuilder();
- if (javaType == float.class) {
- sb.append("(float)").append(name).append(".asDouble()");
- } else if (javaType == int.class) {
- sb.append(name).append(".asInt()");
- } else if (javaType == String.class) {
- sb.append(name).append(".asString()");
- } else if (javaType == char.class) {
- sb.append(name).append(".asString().charAt(0)");
- } else if (javaType == long.class) {
- sb.append(name).append(".asLong()");
- } else if (javaType == byte.class) {
- sb.append("(byte)").append(name).append(".asInt()");
- } else if (javaType == boolean.class) {
- sb.append(name).append(".__nonzero__()");
- } else if (javaType.isPrimitive()) {
- throw new RuntimeException("You need a converter for " + javaType);
- } else {
- final String simpleName = javaType.isArray() ? javaType.getSimpleName()
- : javaType.getName();
- // no need to cast Object to Object
- if (!simpleName.equals("java.lang.Object")) {
- sb.append('(').append(simpleName).append(')');
- }
- sb.append(name).append(".__tojava__(").append(simpleName).append(".class)");
- }
- return sb.toString();
- }
-
-}
View
90 buildtime/src/jycessing/build/Signature.java
@@ -1,90 +0,0 @@
-/*
- * Copyright 2010 Jonathan Feinberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package jycessing.build;
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-
-public class Signature implements Comparable<Signature> {
- private static final Comparator<Class<?>> CLASS_COMP = new Comparator<Class<?>>() {
- public int compare(final Class<?> a, final Class<?> b) {
- if (a == int.class && b == float.class) {
- return -1;
- }
- if (a == float.class && b == int.class) {
- return 1;
- }
- return a.getSimpleName().compareTo(b.getSimpleName());
- }
- };
-
- public int compareTo(final Signature o) {
- if (argTypes.size() != o.argTypes.size()) {
- throw new IllegalArgumentException("Can't compare Signatures of unlike size");
- }
- for (int i = 0; i < argTypes.size(); i++) {
- final int c = CLASS_COMP.compare(argTypes.get(i), o.argTypes.get(i));
- if (c != 0) {
- return c;
- }
- }
- return 0;
- }
-
- private final List<Class<?>> argTypes;
- private final Class<?> returnType;
-
- public Signature(final Method method) {
- argTypes = Arrays.asList(method.getParameterTypes());
- returnType = method.getReturnType();
- }
-
- public boolean isVoid() {
- return returnType == Void.TYPE;
- }
-
- public String getTypecheckExpression(final int i, final String name) {
- final Class<?> k = argTypes.get(i);
- if (k == float.class) {
- return String.format(
- "(%s == PyFloat.TYPE || %s == PyInteger.TYPE || %s == PyLong.TYPE)",
- name, name, name);
- } else if (k == int.class || k == byte.class) {
- return String.format("%s == PyInteger.TYPE", name);
- } else if (k == boolean.class) {
- return String.format("%s == PyBoolean.TYPE", name);
- } else if (k == String.class) {
- return String.format("%s == PyString.TYPE", name);
- } else if (k.isPrimitive()) {
- throw new RuntimeException("You need a converter for " + k);
- } else {
- return String.format(
- "%s.getProxyType() != null && %s.getProxyType() == %s.class", name,
- name, k.getSimpleName());
- }
- }
-
- public Class<?> getArgType(final int index) {
- return argTypes.get(index);
- }
-
- public Class<?> getReturnType() {
- return returnType;
- }
-
-}
View
38 buildtime/src/jycessing/build/TypeUtil.java
@@ -1,38 +0,0 @@
-/*
- * Copyright 2010 Jonathan Feinberg
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package jycessing.build;
-
-
-public class TypeUtil {
- public static String pyConversionPrefix(final Class<?> k) {
- if (k == float.class) {
- return "new PyFloat(";
- } else if (k == int.class) {
- return "new PyInteger(";
- } else if (k == long.class) {
- return "new PyLong(";
- } else if (k == String.class || k == char.class) {
- return "new PyString(";
- } else if (k == boolean.class) {
- return "new PyBoolean(";
- } else if (k.isPrimitive()) {
- throw new RuntimeException("You need a converter for " + k);
- } else {
- return "Py.java2py(";
- }
- }
-
-}
View
26 buildtime/template/DriverImpl.java → buildtime/template/DriverImpl.java.cog 100644 → 100755
@@ -13,6 +13,11 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+/*[[[cog
+ import processing_parser as p
+ import cog
+ ]]]
+ [[[end]]] */
package jycessing;
import org.python.util.InteractiveConsole;
@@ -27,19 +32,32 @@ public DriverImpl(final InteractiveConsole interp,
final String sketchPath, final String programText) {
super(interp, sketchPath, programText);
}
+
+
@Override
protected void populateBuiltins() {
- %METHOD_BINDINGS%
+ /*[[[cog
+ for b in p.simple_method_bindings:
+ b.emit()
+ ]]]*/
+ /*[[[end]]]*/
}
@Override
protected void setIntegerFields() {
- %INTEGER_FIELD_BINDINGS%
+ /*[[[cog
+ for b in p.integer_field_bindings:
+ b.emit()
+ ]]]*/
+ /*[[[end]]] */
}
@Override
protected void setFields() {
- %FIELD_BINDINGS%
+ /*[[[cog
+ for b in p.field_bindings:
+ b.emit()
+ ]]]*/
+ /*[[[end]]] */
}
-
}
View
3 runtime/src/jycessing/WrappedInteger.java
@@ -10,4 +10,7 @@ public WrappedInteger() {
super(0);
}
+ public static void main(String[] args) throws Exception {
+ System.err.println(Class.forName("int"));
+ }
}

0 comments on commit 05c9e4c

Please sign in to comment.
Something went wrong with that request. Please try again.