Code Search for Developers
 
 
  

ly.py from gzz at Krugle


Show ly.py syntax highlighted

# ly.py -- the lyterate programming thingy ;-)
# http://sf.net/projects/lyterate
# Copyright (c) 2002 Benja Fallenstein
# ATTENTION: This file is autogenerated from several .ly input files.
# Please, DO NOT EDIT this file as your changes will be lost the
# next time it's regenerated from the .ly source. Edit the source
# instead.
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# XXX To be documented.
import rfc822
import string
import getopt
import sys
import os
import re
ly_version = '0.0.5pre1'
ly_versions_supported = [ly_version,
			 '0.0.4a', '0.0.4', '0.0.3', '0.0.2', '0.0.1']
class LiterateProgram:
	def readFile(self, file, filename):
		msg = rfc822.Message(file)
		if msg.has_key('ly-version'):
			if msg['ly-version'] not in ly_versions_supported:
				print
				print "File " + filename + " requests ",
				print "Ly version '" + msg['ly-version'] + "',"
				print "but the only versions supported are:"
				print ly_versions_supported
				print
				print "Exiting now."
				print
				sys.exit(1)
		
		lines = file.readlines()
		lines = map(string.rstrip, lines)
		chunks = splitList(lines, "")
		self.readChunks(chunks, filename)
		return weave(msg, chunks)
	
	def __init__(self):
		self.code = {}
		self.filepaths = {}
	def readChunks(self, paras, filename):
		"""paras -- paragraphs"""
		name = None
		for para in paras:
			if para == []:
				# empty paragraph-- ignore
				continue
			first = para[0]
			if first[:2] == "--":
				if name != None:
					self.chunk_read(name, chunk)
				if not re.match(r'-- .*:', first):
					print
					print "A code chunk name in file "+filename+" does not"
					print "have the correct form: it should be two dashes,"
					print "a space, the chunk name and a colon. Instead, it is:"
					print
					print first
					print
					print "Exiting now."
					print
					sys.exit(1)
				
				name = first[3:-1]
				self.chunk_started(name, filename)
				chunk = []
				first = para[1]
				para = para[1:]
				ws = first[:lws_amount(first)]
			if first[0] in string.whitespace:
				for line in para:
					if not line[:len(ws)] == ws:
						print
						print "I have found a line in one code chunk that"
						print "is not indented like the first line in"
						print "the code chunk. I'm sorry, but I'm completely"
						print "stupid about that: all lines in a code chunk"
						print "must be indented at least as much as the"
						print "first line in the chunk, and the same mix"
						print "of tabs and spaces must be used."
						print
						print "Here is the chunk in question (in file "+filename+"):"
						print
						print string.join(para, '\n')
						print
						print "The offending line is:"
						print repr(line)
						print
						print "Here is the indentation of the first line"
						print "in the chunk: " + repr(ws)
						print
						print "Exiting now."
						print
						sys.exit(1)
				
				stripws = lambda s, ws=ws: s[len(ws):]
				chunk += map(stripws, para)
		if name != None:
			self.chunk_read(name, chunk)
	def chunk_read(self, name, lines):
		#print "write: ", name
		#print "\n".join(lines)
		lines = self.filterInlineChunks(lines)
		if not self.code.has_key(name):
			self.code[name] = []
		self.code[name] += lines
		self.code[name] += ['']
	def chunk_started(self, chunkname, lyname):
		if chunkname[:6] == 'file "':
			lydir = os.path.dirname(lyname)
			tanglename = chunkname[6:-1]
			tangledir = os.path.dirname(tanglename)
			if tangledir != '':
				# set no dir if the filename contains
				# the dir itself
				self.filepaths[tanglename] = ''
			elif not self.filepaths.has_key(tanglename):
				self.filepaths[tanglename] = lydir
			else:
				if self.filepaths[tanglename] != lydir:
					print
					print "Two ly files in different ",
					print "directories declared the same ",
					print "file to be tangled, " + tanglename + "."
					print "I don't know whether to put it ",
					print "to " + dirname + " or ",
					print self.filepaths[tanglename] + "."
					print
					print "Exiting now."
					print
					sys.exit(1)
				
	
	def filterInlineChunks(self, lines):
		name = None
		indent = None
		chunk = None
		result = []
		for line in lines:
			if indent != None:
				if line.startswith(indent) and \
				   line[len(indent)] in string.whitespace:
					chunk.append(line[len(indent):])
					continue
				else:
					self.chunk_read(name,
					    strip_least_indent(chunk))
					name = None
					indent = None
					chunk = None
					
			m = re.match(r'(\s*)-- (.*):', line)
			if m == None:
				result.append(line)
			else:
				#print "Inline chunk: "+line
				indent = m.groups()[0]
				name = check_chunk_name(m.groups()[1])
				chunk = []
				result.append("%s-- %s." % (indent, name))
		if name != None:
			self.chunk_read(name, strip_least_indent(chunk))
		return result
	
	def tangleFiles(self):
		files = {}
		for key in self.code.keys():
			if key[:6] != 'file "': continue
			filename = key[6:-1]
			path = self.filepaths[filename]
			write_to = os.path.join(path, filename)
			lines = self.tangleChunk(key)
			files[write_to] = string.join(lines, "\n")
		return files
	def tangleChunk(self, chunkname):
		"""Tangle a chunk into a list of lines."""
		if not self.code.has_key('__runPython__ @ ' + chunkname):
			if not self.code.has_key(chunkname):
				print (
				"The program attempted to tangle the chunk '%s',\n"
				"but no definition for this chunk was found.\n"
				"(Spelling error, maybe?)\n"
				"Exiting now.\n"
				"\n"
				) % (chunkname,)
				sys.exit(1)
			
			chunk = self.code[chunkname]
		elif not self.code.has_key(chunkname):
			chunk = self.tangleActiveChunk(chunkname)
		else:
			raise TypeError("Both '"+chunkname+"' and "
					"'__runPython__ @ "+chunkname+"' "
					"are defined!")
		result = []
		for line in chunk:
			stripped = string.lstrip(line)
			if stripped[:2] != "--":
				result.append(line)
				continue
			if not re.match(r'-- .*\.', stripped):
				print (
				"A chunk inclusion in chunk %s does not\n"
				"have the correct form: it should be two dashes,\n"
				"a space, the chunk name and a period. Instead, it is:\n"
				"%s\n"
				"Exiting now.\n"
				"\n"
				) % (chunkname, stripped)
				sys.exit(1)
			
			name = stripped[3:-1]
			chunk = self.tangleChunk(name)
			ws = line[:lws_amount(line)]
			indent = lambda s, ws=ws: ws + s
			chunk = map(indent, chunk)
			result += chunk
		parts = [string.strip(part) for part in chunkname.split('@')]
		if len(parts) > 1 and parts[0] == 'quote-string':
			# preprocess as quoted string
			def quote(line):
				line = '\\\\'.join(line.split('\\'))
				line = '\\"'.join(line.split('"'))
				return '"%s\\n"' % (line,)
			result = [quote(line) for line in result]
		return result
	def tangleActiveChunk(self, chunkname):
		lines = self.tangleChunk('__runPython__ @ '+chunkname)
		indent = lambda s: '\t'+s
		lines = map(indent, lines)
		code = 'def script(self):\n'
		code += string.join(lines, '\n')
		code += '\n'
		dict = {}
		exec code in dict
		script = dict['script']
		return script(self)
	
def text_para(header, lines):
	str = string.join(lines, "\n")
	str = "<p>\n" + str
	if ((not header.has_key('easy-tags')) or
	    string.lower(string.strip(header['easy-tags'])) != 'off'):
		str = replace_easy_tags(header, str)
	return str
def code_para(header, lines):
	import re
	defined_chunk_re=re.compile(r"^(--\s+(.+):)(\n|$)")
	called_chunk_re=re.compile(r"([ \t]+--\s+)(.+)\.(\n|$)")
	str = string.join(lines, "\n")
	str = replace(str, "&", "&amp;")
	str = replace(str, "<", "&lt;")
	str = defined_chunk_re.sub(r'<a name="\2">\1</a>\n',str)
	if header.has_key('link-chunks') and \
	   string.strip(string.lower(header['link-chunks'])) == 'on':
		str = called_chunk_re.sub(
				r'\1<a href="#\2">\2</a>.\n',str)
	return "<p><pre>%s</pre>" % (str,)
def replace(str, what, by_what):
	return string.join(string.split(str, what), by_what)

template = """<html>
<head>
	<title>%s</title>
</head>
<body>
%s
</body>
</html>"""

def replace_easy_tags(header, str):
	entities = {'<<': '&lt;', '>>': '&gt;', '&&': '&amp;',
		    '~': '&nbsp;'}
	for (char, entity) in entities.items():
		str = mask(str, char)
		str = replace(str, char, entity)
		str = unmask(str, char)
	
	tags = {'|': 'code', '_': 'em', '*': 'strong'}
	for (char, tag) in tags.items():
		str = mask(str, char)
		parts = string.split(str, char)
		str = parts[0]
		open = 0
		for part in parts[1:]:
			if not open:
				str += "<" + tag + ">"
				open = 1
			else:
				str += "</" + tag + ">"
				open = 0
			str += part
		if open:
			raise SyntaxError("Unbalanced easy tag "
					+ char + " (" + tag + "):\n" + str)
		str = unmask(str, char)
	
	str = mask(str, "[")
	str = string.join(string.split(str, '\255'), '\253')
	str = string.join(string.split(str, '\254'), r'\\')
	str = mask(str, "]")
	result = ""
	position = string.find(str, "[")
	
	last_position = 0
	
	while position >= 0:
		result += str[last_position:position]
		
		start = position
		end = string.index(str, "]", position)
		delim = string.rindex(str, "->", start, end)
		link_text = str[start+1 : delim]
		url = str[delim+2 : end]
		link_text = string.rstrip(link_text)
		url = string.lstrip(url)
		result += '<a href="%s">%s</a>' % (url, link_text)
		position = end + 1
		
		last_position = position
		
		position = string.find(str, "[", position)
		
	result += str[last_position:]
	
	str = result
	str = unmask(str, "]")
	str = string.join(string.split(str, '\253'), '\255')
	str = unmask(str, "[")
	
	return str

def mask(str, char):
	if '\254' in str: raise "\\254 in str: HELP!!!"
	if '\255' in str: raise "\\255 in str: HELP!!!"
	str = replace(str, '\\\\', '\254')
	str = replace(str, '\\' + char, '\255')
	str = replace(str, char + char, '\255')
	return str
def unmask(str, char):
	str = replace(str, '\254', '\\\\')
	str = replace(str, '\255', char)
	return str

def lws_amount(s):
	"""Return the amount of the whitespace at the beginning of a string."""
	# tricky
	return len(s) - len(string.lstrip(s))
def splitList(list, at):
	"""Split a list wherever it contains a specified element."""
	result = []
	current = []
	for el in list:
		if el == at:
			result.append(current)
			current = []
		else:
			current.append(el)
	result.append(current)
	return result

def strip_least_indent(lines):
	if not lines: return lines
	n = lws_amount(lines[0])
	for l in lines:
		n = min(n, lws_amount(l))
	return map(lambda s,n=n:s[n:], lines)
def check_chunk_name(name):
	parts = name.split('@')
	parts = map(string.strip, parts)
	if parts[-1] == '':
		import random
		parts[-1] = str(random.random())
	return ' @ '.join(parts)
pass



def process(filenames):
	"""Process a list of .ly files, weaving and tangling.
	filenames -- The names of the .ly files, without suffix.
	"""
	lp = LiterateProgram()
	for name in filenames:
		base, ext = os.path.splitext(name)
		if ext == '.html':
			print
			print "Filename " + name + " given as an input file. ",
			print "If I wrote the woven version of this input "
			print "file there (which is a .html, too), the ",
			print "input file would be overwritten, so I don't."
			print
			print "Exiting now."
			print
			sys.exit(1)
		
		f = open(name)
		woven = lp.readFile(f, name)
		f.close()
		
		g = open(base + '.html', 'w')
		g.write(woven)
		g.close()
		
	tangled = lp.tangleFiles()
	for (name, contents) in tangled.items():
		g = open (name, 'w')
		g.write(contents)
		g.close()
	
	tangled = lp.tangleFiles()
	for (name, contents) in tangled.items():
		g = open (name, 'w')
		g.write(contents)
		g.close()

def read_dir_into(dir, files):
	def visit(arg, dirname, names, files=files):
		list = map(lambda n,d=dirname: os.path.join(d,n), names)
		list = filter(lambda f: os.path.splitext(f)[1] == '.ly',
			      list)
		files.extend(list)
	os.path.walk(dir, visit, None)

def weave(header, chunks):
	paras = []
	for chunk in chunks:
		if chunk == []:
			continue
		first = chunk[0]
		if first[:3] == "-- " or first[0] in string.whitespace:
			paras.append(code_para(header, chunk))
		else:
			paras.append(text_para(header, chunk))
	title = header["title"]
	body = string.join(paras, "\n\n")
	return template % (title, body)

if __name__ == '__main__':
	options, files = getopt.getopt(sys.argv[1:], [])
	if len(files) == 0:
		files = ['./']
	list = []
	for file in files:
		if not os.path.isdir(file):
			list.append(file)
		else:
			read_dir_into(file, list)
	process(list)
	




See more files for this project here

gzz

An implementation of Ted Nelson's ZZstructure. ZZstructure is a new type of programming platform for structured data.

Project homepage: http://savannah.nongnu.org/projects/gzz
Programming language(s): C++,Java,Python
License: lgpl21

  HTTPClient.zip
  README
  collections-kaffe.jar
  docutils.jar
  docutils.license
  gpl.txt
  icu.license
  icu4j.jar
  jena.jar
  jena.license
  junit.copyright
  junit.jar
  jython.jar
  jython.license
  jythonlib.jar
  ly.py
  python.license
  pythonlib.jar
  rst2html.py
  xerces.jar
  xerces.license