# d.py #Place in \pythonXX\lib\site-packages\trac\wikimacros\ import re # D keywords # from http://www.digitalmars.com/d/lex.html#keyword # list checked 2005/03/18 keywords = ['abstract', 'alias', 'align', 'asm', 'assert', 'auto', 'bit', 'body', 'break', 'byte', 'case', 'cast', 'catch', 'cdouble', 'cent', 'cfloat', 'char', 'class', 'const', 'continue', 'creal', 'dchar', 'debug', 'default', 'delegate', 'delete', 'deprecated', 'do', 'double', 'else', 'enum', 'export', 'extern', 'false', 'final', 'finally', 'float', 'for', 'foreach', 'function', 'goto', 'idouble', 'if', 'ifloat', 'import', 'in', 'inout', 'int', 'interface', 'invariant', 'ireal', 'is', 'long', 'mixin', 'module', 'new', 'null', 'out', 'override', 'package', 'pragma', 'private', 'protected', 'public', 'real', 'return', 'short', 'static', 'struct', 'super', 'switch', 'synchronized', 'template', 'this', 'throw', 'true', 'try', 'typedef', 'typeid', 'typeof', 'ubyte', 'ucent', 'uint', 'ulong', 'union', 'unittest', 'ushort', 'version', 'void', 'volatile', 'wchar', 'while', 'with'] # Regex Links # http://www.amk.ca/python/howto/regex/regex.html#SECTION000310000000000000000 # http://docs.python.org/lib/matching-searching.html def dIsAlpha(c): # /* true if c is a letter or an underscore, false otherwise */ return c.isalpha() or (c == '_') def dIsDigit(c): # /* true if c is a number or an underscore, false otherwise */ return c.isdigit() or (c == '_') def ishexdigit(c): # /* true if c is a hexadecimal digit, false otherwise */ return re.compile("^[0-9A-F_]+$").match(c) def isoctdigit(c): # /* true if c is an octal digit, false otherwise */ return re.compile("^[0-7_]+$").match(c) def issymbol(c): # /* true if c is legal D symbol, false otherwise */ # /* "-" also needs to be escaped (in addition to the list at http://www.amk.ca/python/howto/regex/)? */ return re.compile(r"^[?~:|!%{}\\\(\)\[\]\.,;=<>\+\-\*/&\^]+$").match(c) def iskeyword(token): #, keywords): #/* true if token is a D keyword, false otherwise */ for x in keywords: #(i = 0; i < count(keywords.length; $i++) /* keywords.length*/ if (x == token): return True return False class Stream: # /* This somewhat emulates Phobos's Stream class, so I didn't have to completely rewrite d2html. */ pos = 0 src = "" def position(self): return self.pos def read(self): self.pos = self.pos + 1 if(self.pos < len(self.src) + 1): return self.src[self.pos - 1 : self.pos] else: return " " def write(self, c): self.src = self.src + c def writeString(self, c): self.src = self.src + c def writeLine(self, c): self.src = self.src + c + "\n" # /* append with a newline */ def __init__(self, s): self.src = s self.pos = 0 def execute(hdf, text, env): """ This function is called when code is embedded in a trac wiki page: {{{ #!d int main(char[] args) { printf("Hello World\n"); return 0; } }}} The "d" indicates to use the D processor that this file contains. For more information, see http://projects.edgewall.com/trac/wiki/WikiProcessors. """ # hdf is an HDFObjectType (and can't be concatenated with a string) # env is an instance (and can't be concatenated with a string) return d2html(text) def d2html(raw_code): # * Copyright (c) 2001 # * Pavel "EvilOne" Minayev # * # * Permission to use, copy, modify, distribute and sell this software # * and its documentation for any purpose is hereby granted without fee, # * provided that the above copyright notice appear in all copies and # * that both that copyright notice and this permission notice appear # * in supporting documentation. Author makes no representations about # * the suitability of this software for any purpose. It is provided # * "as is" without express or implied warranty. # * Updated by J C Calvarese, http://jcc_7.tripod.com/d/, 2003/12/18 # * Ported to Python by J C Calvarese, 2005/03 # ### Porting Tips ### # Concatenation: # D: ~ # PHP: . # Python: + # PHP do-while Python equivalent # ------------ ----------------- # doIt = True # do { while(doIt): # ... ... # if not(condition): # } while (condition) doIt = False # PHP for Python equivalent # ------- ----------------- # for (i = 0; i < spaces; i++) for i in range(spaces): # By the way, string methods come in handy when doing text processing: # http://docs.python.org/lib/string-methods.html code = raw_code #/* Remove trailing CR and/or LF (doesn't seem to work, but doesn't seem to hurt either). */ done = False while done == False: iLen = len(code) code = code.rstrip() if iLen == len(code): done = True tabsize = 4 #/* number of spaces in tab */ lineNumber = 0 spaces = 0 #/* Colors for syntax highlighting, default values are # Pavel Minayev's preferences in Microsoft Visual Studio editor */ Colors_keyword = "0000FF" Colors_number = "008000" Colors_string = "000080" Colors_comment = "808080" #useStyleSheet = True useStyleSheet = False xhtmlFormat = True linestart = 0 #/* for tabs */ c = "" c2 = "" src = Stream(code) dst = Stream("") c = src.read() while src.position() < len(code): if (c.isspace()): #/* whitespace */ doIt = True while(doIt): if c == "\t": #/* tab character */ #/* expand tabs to spaces */ spaces = tabsize - (src.position() - linestart) % tabsize for i in range(spaces): dst.writeString(" ") linestart = src.position() - tabsize + 1 elif c == "\n": #//10: /* linefeed */ linestart = src.position() + 1 #/* reset line start on newline */ dst.write(c) elif c == "\r": #//13: /* control return */ linestart = src.position() + 1 #/* reset line start on newline */ if(c2 != "\n"): #//10) dst.write(c) else: #/* space is left, anything else? */ dst.write(c) c2 = c c = src.read() if not c.isspace(): doIt = False elif (dIsAlpha(c)): #/* keyword or identifier */ token = "" doIt = True while(doIt): token = token + c c = src.read() if not(dIsAlpha(c) or dIsDigit(c)): doIt = False if(iskeyword(token)): #/* keyword */ if(useStyleSheet): dst.writeString('' + token + "") else: dst.writeString("" + token + "") else: # /* simple identifier */ dst.writeString(token) elif (c == '0'): #/* binary, octal or hexadecimal number */ if useStyleSheet: dst.writeString('') else: dst.writeString("") dst.write(c) c = src.read() if c == 'X' or c == 'x': #/* hexadecimal */ dst.write(c) c = src.read() while ishexdigit(c): dst.write(c) c = src.read() # /* TODO: add support for hexadecimal floats */ elif (c == 'B' or c == 'b'): #/* binary */ dst.write(c) c = src.read() while c == '0' or c == '1' or c == '_': dst.write(c) c = src.read() else: #/* octal */ doIt = True while (doIt): dst.write(c) c = src.read() if not(isoctdigit(c)): doIt = False dst.write(c) c = src.read() if useStyleSheet: dst.writeString("") else: dst.writeString("") elif dIsDigit(c): #/* decimal number */ if(useStyleSheet): dst.writeString('') else: dst.writeString("") #/* integral part */ doIt = True while(doIt): dst.write(c) c = src.read() if not(dIsDigit(c)): doIt = False #/* fractional part */ if c == '.': dst.write(c) c = src.read() while dIsDigit(c): dst.write(c) c = src.read() #/* scientific notation */ if c == 'E' or c == 'e': dst.write(c) c = src.read() if c == '+' or c == '-': dst.write(c) c = src.read() while dIsDigit(c): dst.write(c) c = src.read() #/* suffixes */ while c == 'U' or c == 'u' or c == 'L' or c == 'l' or c == 'F' or c == 'f': dst.write(c) c = src.read() if useStyleSheet: dst.writeString("") else: dst.writeString("") elif c == "\\": #/* naked escape sequence (\) */ if(useStyleSheet): dst.writeString("") else: dst.writeString("") dst.write(c) prev = c c = src.read() dst.write(c) c = src.read() if useStyleSheet: dst.writeString("") else: dst.writeString("") elif c == "\"": #/* string (") with escape sequences */ if(useStyleSheet): dst.writeString('') else: dst.writeString("") doIt = True while(doIt): if c == '<': #/* special symbol in HTML */ dst.writeString("<") else: dst.write(c) prev = c if ((prev == '\\' and c == '"') or (prev == '\\' and c == '\\') and not isEscape): isEscape = True else: isEscape = False c = src.read() if not(isEscape or c != '"'): doIt = False dst.write(c) c = src.read() if useStyleSheet: dst.writeString("") else: dst.writeString("") elif c == "'": #/* character (') with escape sequences */ if useStyleSheet: dst.writeString('') else: dst.writeString("") doIt = True while(doIt): if c == '<': #/* special symbol in HTML */ dst.writeString("<") else: dst.write(c) prev = c if (prev == "\\" and c == "'") or (prev == "\\" and c == "\\") and not isEscape: isEscape = True else: isEscape = False c = src.read() if not(isEscape or c != '\''): doIt = False dst.write(c) c = src.read() if useStyleSheet: dst.writeString("") else: dst.writeString("") elif c == '`': #/* character (`) with no escape sequences */ if useStyleSheet: dst.writeString('') else: dst.writeString("") doIt = True while(doIt): if (c == '<'): #/* special symbol in HTML */ dst.writeString("<") else: dst.write(c) c = src.read() if c == "`": #/* 96 */ doIt = False dst.write(c) c = src.read() if useStyleSheet: dst.writeString("") else: dst.writeString("") elif issymbol(c): #/* either operator or comment */ if c == '<': #/* special symbol in HTML */ dst.writeString("<") c = src.read() elif c == '/': #/* could be a comment... */ c = src.read() if c == '/': #/* single-line one */ if useStyleSheet: dst.writeString("/") else: dst.writeString("/") while c != "\n" and c != "\r": #//10 and $c != 13: if c == '<': #/* special symbol in HTML */ dst.writeString("<") elif c == "\t": #// 9 #/* expand tabs */ spaces = tabsize - (src.position() - linestart) % tabsize for i in range(spaces): dst.writeString(" ") linestart = src.position() - tabsize + 1 else: dst.write(c) c2 = c c = src.read() if useStyleSheet: dst.writeString("") else: dst.writeString("") elif (c == '*'): #/* multi-line one */ prevprev = "" prev = '/' if useStyleSheet: dst.writeString('/'); else: dst.writeString("/") doIt = True while(doIt): if c == '<': #/* special symbol in HTML */ dst.writeString("<") elif (c == "\t"): #//9) #/* expand tabs */ spaces = tabsize - (src.position() - linestart) % tabsize for i in range(spaces): dst.writeString(" ") linestart = src.position() - tabsize + 1 else: if(c == "\n" or c == "\r"): #//c == 10 || c == 13) linestart = src.position() + 1 #/* reset line start on newline */ dst.write(c) prevprev = prev prev = c c = src.read() if prevprev != '/' and prev == '*' and c == '/': doIt = False dst.write(c) if useStyleSheet: dst.writeString("") else: dst.writeString("") c = src.read() elif (c == '+'): #/* nestable multi-line comment */ prevprev = '/' prev = '+' level = 0 if useStyleSheet: dst.writeString("/") else: dst.writeString("/") doIt = True while(doIt): if (c == '<'): #/* special symbol in HTML */ dst.writeString("<") elif (c == "\t"): #//9) #/* expand tabs */ spaces = tabsize - (src.position() - linestart) % tabsize for i in range(spaces): dst.writeString(" ") linestart = src.position() - tabsize + 1 else: #/* reset line start on newline */ if (c == "\n" or c == "\r"): #//10 || $c == 13) linestart = src.position() + 1 dst.write(c) if (prev == '/' and c == '+'): level = level + 1 if (prevprev != '/' and prev == '+' and c == '/'): level = level - 1 prevprev = prev prev = c c = src.read() if prev == '+' and c == '/' and level == 0: doIt = False dst.write(c) if useStyleSheet: dst.writeString("") else: dst.writeString("") c = src.read() else: #/* just an operator */ dst.write('/') else: #/* just an operator */ dst.write(c) c = src.read() else: #/* whatever it is, it doesn't seem to be valid */ dst.write("{error!}") dst.write(c) strippedSrc = dst.src.strip if(strippedSrc != ""): #/* make sure there's actual content */ return "
" + dst.src + "
" # class=\"example\" return ""