PageRenderTime 36ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/GCog.groovy

http://gcog.googlecode.com/
Groovy | 262 lines | 153 code | 23 blank | 86 comment | 34 complexity | 31da53adaaa9bfad50ff85dabb693c76 MD5 | raw file
  1. /**
  2. * gcog - generate code with inlined Groovy code.
  3. * http://code.google.com/p/gcog/
  4. *
  5. * Copyright 2008, Tobias Hientzsch.
  6. *
  7. * MIT license http://www.opensource.org/licenses/mit-license.php
  8. *
  9. * Original idea and code from Cog code generation tool.
  10. * http://nedbatchelder.com/code/cog
  11. *
  12. * Copyright 2004-2008, Ned Batchelder.
  13. *
  14. */
  15. public class GCog {
  16. def sBeginSpec
  17. def sEndSpec
  18. def sEndOutput
  19. def sEndFormat
  20. def sOutputMode
  21. def reEndOutput
  22. def options
  23. def GCog() {
  24. sBeginSpec = '[[[gcog'
  25. sEndSpec = ']]]'
  26. sEndOutput = '[[[end]]]'
  27. // reEndOutput = /\[\[\[end]]](?P<hashsect> *\(checksum: (?P<hash>[a-f0-9]+)\))/
  28. // sEndFormat = '[[[end]]] (checksum: %s)'
  29. //options = CogOptions()
  30. options = [:]
  31. // sOutputMode = 'w'
  32. //installCogModule()
  33. }
  34. def showWarning(msg) {
  35. println "Warning:", msg
  36. }
  37. def isBeginSpecLine(String s) {
  38. return s.indexOf(sBeginSpec) >= 0
  39. }
  40. def isEndSpecLine(String s) {
  41. return s.indexOf(sEndSpec) >= 0 && !isEndOutputLine(s)
  42. }
  43. def isEndOutputLine(String s) {
  44. return s.indexOf(sEndOutput) >= 0
  45. }
  46. def processString(fIn , fname=null) {
  47. def fOut = new StringWriter();
  48. process(new StringReader(fIn), fOut, fname);
  49. return fOut.toString()
  50. }
  51. void processFile(fIn, fOut, fname=null) {
  52. fOut = new FileWriter(new File(fOut));
  53. fIn = new FileReader(new File(fIn));
  54. process(fIn, fOut, fname);
  55. fOut.flush();
  56. fOut.close();
  57. }
  58. def processOneFile(fInOut , fname=null) {
  59. def fIn = new File(fInOut).getText();
  60. def fOut = processString(fIn, fInOut);
  61. if(fIn != fOut) {
  62. fOut = new File(fInOut).write(fOut)
  63. }
  64. }
  65. def process(fIn, Writer fOut, fname=null) {
  66. fIn = new NumberedFileReader(fIn)
  67. def sFileIn = fname || ''
  68. def bSawCog = false
  69. // loop over generator chunks
  70. def l = fIn.readLine()
  71. def firstLine = true
  72. def write = { s ->
  73. if(firstLine){
  74. firstLine = false
  75. } else {
  76. s = '\n' + s
  77. }
  78. fOut.write(s)
  79. }
  80. while(l!=null) {
  81. // Find the next spec begin
  82. while(l!=null && !isBeginSpecLine(l)) {
  83. if (isEndSpecLine(l)) {
  84. throw new Exception("Unexpected '$sEndSpec'" /*% self.sEndSpec,
  85. file=sFileIn, line=fIn.linenumber()*/)
  86. }
  87. if (isEndOutputLine(l)) {
  88. throw new Exception("Unexpected '$sEndOutput'" /*% self.sEndOutput,
  89. file=sFileIn, line=fIn.linenumber()*/)
  90. }
  91. write(l)
  92. l = fIn.readLine()
  93. }
  94. if(l==null)
  95. break
  96. if(!options.bDeleteCode) {
  97. write(l)
  98. }
  99. // l is the begin spec
  100. def gen = new GCogGenerator()
  101. //gen.setOutput(stdout=self.stdout)
  102. gen.parseMarker(l)
  103. def firstLineNum = fIn.linenumber()
  104. // If the spec begin is also a spec end, then process the single
  105. // line of code inside.
  106. if(isEndSpecLine(l)) {
  107. def beg = l.indexOf(sBeginSpec)
  108. def end = l.indexOf(sEndSpec)
  109. if(beg > end && end >=0) {
  110. throw new Exception("Cog code markers inverted");
  111. //file=sFileIn, line=firstLineNum)
  112. } else {
  113. def sCode = l[beg+sBeginSpec.length() .. end-1].trim()
  114. gen.parseLine(sCode)
  115. }
  116. } else {
  117. // Deal with an ordinary code block.
  118. l = fIn.readLine()
  119. // Get all the lines in the spec
  120. while(l!=null && !isEndSpecLine(l)) {
  121. if(isBeginSpecLine(l)){
  122. throw new Exception("Unexpected '$sBeginSpec'") /*% self.,
  123. file=sFileIn, line=fIn.linenumber())*/
  124. }
  125. if(isEndOutputLine(l)) {
  126. throw new Exception("Unexpected '$sEndOutput'") /* % self.sEndOutput,
  127. file=sFileIn, line=fIn.linenumber())*/
  128. }
  129. if(!options.bDeleteCode) {
  130. write(l)
  131. }
  132. gen.parseLine(l)
  133. l = fIn.readLine()
  134. }
  135. if (l==null) {
  136. new Exception(
  137. "Cog block begun but never ended.");/*,
  138. file=sFileIn, line=firstLineNum)*/
  139. }
  140. if(!options.bDeleteCode) {
  141. write(l)
  142. }
  143. gen.parseMarker(l)
  144. }
  145. l = fIn.readLine()
  146. // Eat all the lines in the output section. While reading past
  147. // them, compute the md5 hash of the old output.
  148. //hasher = md5.new()
  149. while(l!=null && !isEndOutputLine(l)) {
  150. if (isBeginSpecLine(l)){
  151. throw new Exception("Unexpected '$sBeginSpec'")/* % self.sBeginSpec,
  152. file=sFileIn, line=fIn.linenumber())*/
  153. }
  154. if(isEndSpecLine(l)) {
  155. throw new Exception("Unexpected '$sEndSpec'") /* % self.sEndSpec,
  156. file=sFileIn, line=fIn.linenumber())*/
  157. }
  158. //hasher.update(l)
  159. l = fIn.readLine()
  160. }
  161. //curHash = hasher.hexdigest()
  162. if(l==null && !options.bEofCanBeEnd) {
  163. // We reached end of file before we found the end output line.
  164. throw new Exception("Missing '$sEndOutput' before end of file.")/* % self.sEndOutput,
  165. file=sFileIn, line=fIn.linenumber())*/
  166. }
  167. // Write the output of the spec to be the new output if we're
  168. // supposed to generate code.
  169. //hasher = md5.new()
  170. if(!options.bNoGenerate) {
  171. def sFile = "$sFileIn+$firstLineNum"
  172. def globals = []
  173. def sGen = gen.evaluate(this, globals, fname=sFile)
  174. //sGen = suffixLines(sGen)
  175. //hasher.update(sGen)
  176. if(sGen != '') {
  177. write(sGen)
  178. firstLine = true //TODO: get rid of this workaround
  179. }
  180. }
  181. //newHash = hasher.hexdigest()
  182. bSawCog = true
  183. /*
  184. // Write the ending output line
  185. hashMatch = self.reEndOutput.search(l)
  186. if self.options.bHashOutput:
  187. if hashMatch:
  188. oldHash = hashMatch.groupdict()['hash']
  189. if oldHash != curHash:
  190. raise CogError("Output has been edited! Delete old checksum to unprotect.",
  191. file=sFileIn, line=fIn.linenumber())
  192. # Create a new end line with the correct hash.
  193. endpieces = l.split(hashMatch.group(0), 1)
  194. else:
  195. # There was no old hash, but we want a new hash.
  196. endpieces = l.split(self.sEndOutput, 1)
  197. l = (self.sEndFormat % newHash).join(endpieces)
  198. else:
  199. # We don't want hashes output, so if there was one, get rid of
  200. # it.
  201. if hashMatch:
  202. l = l.replace(hashMatch.groupdict()['hashsect'], '', 1)
  203. */
  204. if(!options.bDeleteCode) {
  205. write(l)
  206. }
  207. l = fIn.readLine()
  208. }
  209. if(!bSawCog && options.bWarnEmpty) {
  210. println "no cog code found in $sFileIn"
  211. }
  212. }
  213. /*
  214. // A regex for non-empty lines, used by suffixLines.
  215. def reNonEmptyLines = re.compile(/^\s*\S+.*$/, re.MULTILINE)
  216. def suffixLines(text) {
  217. """ Add suffixes to the lines in text, if our options desire it.
  218. text is many lines, as a single string.
  219. """
  220. if(options.sSuffix) {
  221. // Find all non-blank lines, and add the suffix to the end.
  222. repl = /\g<0>/ + options.sSuffix.replaceAll('\\', '\\\\')
  223. text = self.reNonEmptyLines.sub(repl, text)
  224. }
  225. return text
  226. }
  227. */
  228. /**
  229. * @param args
  230. */
  231. static def void main(String[] args){
  232. def c = new GCog()
  233. if(args.size()> 0) {
  234. def f = args[0]
  235. c.processOneFile(f,f)
  236. }
  237. }
  238. }