Package: noweb Version: 2.11b-7 Severity: wishlist Tags: patch These patches do considerable violence to the model of noweb, and so I'm uploading them in preliminary form to discuss what might be the appropriate action to take.
I could not simply add pipeline stages since the tangled file needs to refer to itself and to the .nw file, and the filenames are not available in standard processing. I also wanted to add column information to the -L directive, and I found the out of the box behavior of -L not to work with python--it screwed up the indentation of subsequent lines. This had not been an issue, I assume, because #line did no good in python anyway, and so no one used it. Some of the final processing to make the output suitable for detangle could be done as a separate stage rather than baked into the main program. I'm also contemplating using the python ast module to parse the code for index purposes in noweave. Currently, only notangle has changed. -- System Information: Debian Release: 5.0.9 APT prefers oldstable APT policy: (995, 'oldstable') Architecture: i386 (i686) Kernel: Linux 2.6.26-2-686 (SMP w/2 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages noweb depends on: ii gawk 1:3.1.5.dfsg-4.1 GNU awk, a pattern scanning and pr ii iconx 9.4.3-2 Executor for Icon, a high-level pr ii libc6 2.7-18lenny7 GNU C Library: Shared libraries noweb recommends no packages. noweb suggests no packages. -- no debconf information
01_debian 02_tmp_fix 04_uninstall 05_security_CVE-2005-3342 06_roff_output 08_tmac_dir 09_awk 10_vmargin 11_german 12_nostrip 13_bashism 15_python 16_python-derived 99_touch
#! /bin/sh /usr/share/dpatch/dpatch-run ## 15_python_dpatch by Ross Boylan <r...@biostat.ucsf.edu> ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Add python #line-like handling @DPATCH@ diff -Naur noweb-2.11b/CHANGES noweb-2.12rb/CHANGES --- noweb-2.11b/CHANGES 2006-06-12 21:12:44.000000000 +0000 +++ noweb-2.12rb/CHANGES 2012-02-21 06:38:51.000000000 +0000 @@ -1,3 +1,12 @@ +Changes for Version 2.12rb - released 20 Feb 2012 +Special handling for Python code, by Ross Boylan <r...@biostat.ucsf.edu> +notangle behavior changed: -Pwfile activates python mode. +This takes input from wfile, not stdin, and writes to file in -R, not +stdout. -R is required; -L is ignored but gets at %I option for indent level +(usable outside of -P mode too). The python mode output works with +the python module detangle to report error messages in the location in the +origial noweb file (as indicated by the -P argument). + CHANGES FOR VERSION 2.11b - released 12 Jun 2006 Make noroff use -mm by default (Debian 218050) Fixed flagrant errors in noweave -x -troff (but bad formatting remains) diff -Naur noweb-2.11b/debian/changelog noweb-2.12rb/debian/changelog --- noweb-2.11b/debian/changelog 2012-02-22 06:36:15.000000000 +0000 +++ noweb-2.12rb/debian/changelog 2012-02-22 00:59:42.000000000 +0000 @@ -1,3 +1,9 @@ +noweb (2.12rb-1) unstable; urgency=low + + * Add support for -P python mode in notangle. + + -- Ross Boylan <r...@biostat.ucsf.edu> Mon, 21 Feb 2012 22:42:36 -0700 + noweb (2.11b-7) unstable; urgency=low * debian/patches/13_bashism.dpatch: Fix unportable backslash in call to echo. diff -Naur noweb-2.11b/src/c/main.nw noweb-2.12rb/src/c/main.nw --- noweb-2.11b/src/c/main.nw 2006-06-12 21:03:53.000000000 +0000 +++ noweb-2.12rb/src/c/main.nw 2012-02-22 00:10:13.000000000 +0000 @@ -21,12 +21,70 @@ to set global state, and counting any roots it sees. It then makes a second pass to emit all the roots, or if there are no roots on the command line, it emits the module (chunk) named [[<<*>>]]. + +@ +\subsubsection{Python Support} +\newcommand{linedirective}{[[\#line]]} +Ross Boylan (r...@biostat.ucsf.edu) added support for +pseudo-\linedirective directives in python. It requires the python module +[[detangle]], which permits error messages that point to the original +web sources. + +This requires a number of changes, not all of which could reasonably +be done by a filter: +\begin{description} +\item[Web file name] The output file must refer to the original web + file. The previous design took input from [[stdin]] only, and so + had no way of knowing what the proper name was. +\item[Preserve Indentation after \linedirective] For reasons that are unclear, + but apparently deliberate, the previous design screwed up the + indentation after output a \linediretive{} directive. This is absolutely + fatal in python; it was not an issue since such directives are not + legal python now. +\item[Preserve Indentation information in \linedirective] Because + tangling can add indentation relative to the original source, we + need to communicate that information to permit accurate mapping + between reported columns in the original and tangled files. +\item[Mangle for [[detangle]]] This involves pre-pending a header and + then inserting a \# before every output line. +\end{description} + +This implies the following new or changed features: +\begin{description} +\item[Command Line] The new option [[-P]] \<{\it web file name}\> now + specifies the input file and activates special python mangling. The + [[-L]] option will be ignored, as well any data on the standard + input. You {\em must} specify an output file name with the [[-R]] + option, though continues to go to [[stdout]]. The input ultimately + comes from the file named in [[-P]], not the standard input of the + command line. That substitution is done in the [[noweave]] shell + script, not this program, which continues to read from the standard + input. +\item[I format] [[%I]] in the line format will now cause the + indentation setting to be output. This is available regardless of + whether [[-P]] is specified; in fact is is mostly for internal use + in python mode. +\item[Mangled output] The output file will have an initial block of + code that activates the python [[detangle]] module and tells it the + name of the the original (from [[-P]]) and mangled (from [[-R]]) + files files. Then the mangled code appears, with each line starting + with a \# and \linedirective{} directives where appropriate. +\end{description} + <<*>>= main(int argc, char **argv) { int i; char *locformat = ""; char *Clocformat = "#line %L \"%F\"%N"; + char *Plocformat = "#line %L %I %F%N"; int root_options_seen = 0; + char *pythonweb = ""; + + /* These were in contemplation of switching the file. + But the program is part of a pipeline. */ + FILE *fin = stdin; + FILE *fout = stdout; + char *fout_name; tabsize = 0; /* default for nt is not to use tabs */ progname = argv[0]; @@ -36,14 +94,22 @@ <<process argument [[i]]---first pass>> } - read_defs(stdin); /* read all the definitions */ + <<check for valid option combinations>> + read_defs(fin); /* read all the definitions */ +@ Note that error exits may leave [[fin]] or [[fout]] open. This is not ideal. +<<*>>= + close(fin); apply_each_module(remove_final_newline); /* pretty up the module texts */ if (root_options_seen == 0) - emit_module_named(stdout, "*", locformat); + emit_module_named(stdout, "*", locformat, pythonweb); else for (i=1; i<argc; i++) - if (argv[i][0] == '-' && argv[i][1] == 'R') - emit_module_named(stdout, argv[i]+2, locformat); + if (argv[i][0] == '-' && argv[i][1] == 'R') { + fout_name = argv[i]+2; + <<handle python mode in [[main]]>> + emit_module_named(fout, fout_name, locformat, pythonweb); + close(fout); + } nowebexit(NULL); return errorlevel; /* slay warning */ @@ -63,6 +129,9 @@ -L[format]& Use the given format to write {\tt\#line} numbers. If -L is given alone, use ANSI C format. If not given, write no {\tt\#line} numbers.\\ +-Pname& Enable python-mode with \linedirective. Requires use of [[-R]] and ignores [[-L]]. + The resulting output file requires the python [[detangle]] module for Python 2.7; + it might work with Python 2.6.\\ -t[tabsize]& Fiddle with tabs \end{fields} <<handle option in argument [[i]]>>= @@ -75,6 +144,11 @@ else errormsg(Error, "%s: ill-formed option %s\n", argv[0], argv[i]); break; + case 'P': /* enabled special tangled python mode */ + pythonweb = argv[i]+2; + if (*pythonweb == 0) + errormsg(Fatal, "-P requires a file name. No spaces.\n"); + break; case 'R': /* change name of root module */ root_options_seen++; break; @@ -90,3 +164,21 @@ errormsg(Warning, "I can't handle arguments yet, so I'll just ignore `%s'",argv[i]); +@ Ross used braces around [[errormsg()]] in my new code so that it is safe even if it +becomes a macro. In that case, old code would need to be checked and updated if necessary. +<<check for valid option combinations>>= +if (*pythonweb && (root_options_seen == 0)){ + errormsg(Fatal, "-P requires the use of -R"); + } +if (*pythonweb && (*locformat != 0)) { + errormsg(Warning, "-P ignore your -L option and uses its own."); + } + +@ +<<handle python mode in [[main]]>>= +if (*pythonweb) { + locformat = Plocformat; + fprintf(fout, "from detangle import detangle\n"); + fprintf(fout, "detangle('%s', '%s')\n\n", fout_name, pythonweb); + fprintf(fout, "#if 0:\n"); + } diff -Naur noweb-2.11b/src/c/mnt.nw noweb-2.12rb/src/c/mnt.nw --- noweb-2.11b/src/c/mnt.nw 2006-06-12 21:03:53.000000000 +0000 +++ noweb-2.12rb/src/c/mnt.nw 2012-02-21 08:01:04.000000000 +0000 @@ -22,12 +22,18 @@ <<local prototypes>> +@ [[pythonweb]] is for future use of the [[-P]] option. It needs to +be global so the argument can make it to +[[emit_if_unused_and_conforming]] via [[apply_each_module()]], which +does not permit any additional arguments. Where possible, I pass it as an argument. + +<<*>>= #define Clocformat "#line %L \"%F\"%N" static char *locformat = Clocformat; +static char *pythonweb = ""; /* for future expansion */ main(int argc, char **argv) { int i; - tabsize = 0; /* default for nt is not to use tabs */ progname = argv[0]; @@ -36,7 +42,7 @@ for (i=1; i<argc; i++) switch (*argv[i]) { case '-': <<handle option in [[argv[i]]]>> break; - default: emitfile(argv[i]); break; + default: emitfile(argv[i], pythonweb); break; } nowebexit(NULL); return errorlevel; /* slay warning */ @@ -77,15 +83,15 @@ errormsg(Error, "@<<*@>> is not a good chunk name for noweb; " "use notangle instead"); else - emitfile(mp->name); + emitfile(mp->name, pythonweb); else errormsg(Error, "@<<%s@>> cannot be an output chunk; " "it contains a metacharacter", mp->name); } <<local prototypes>>= -static void emitfile(char *modname); +static void emitfile(char *modname, char *pythonweb); <<*>>= -static void emitfile(char *modname) { +static void emitfile(char *modname, char *pythonweb) { Module root = lookup(modname); char *tempname = tempnam(".", 0); FILE *fp; @@ -117,7 +123,7 @@ } <<expand [[root]] onto [[fp]] and close the file>>= resetloc(); -(void) expand(root, 0, 0, 0, lfmt, fp); +(void) expand(root, 0, 0, 0, lfmt, pythonweb, fp); putc('\n', fp); fclose(fp); @ diff -Naur noweb-2.11b/src/c/modules.nw noweb-2.12rb/src/c/modules.nw --- noweb-2.11b/src/c/modules.nw 2006-06-12 21:03:54.000000000 +0000 +++ noweb-2.12rb/src/c/modules.nw 2012-02-21 23:50:12.000000000 +0000 @@ -126,7 +126,7 @@ } *Parent; int expand (Module mp, int indent, int partial_distance, Parent parent, - char *locformat, FILE *out); + char *locformat, char *pythonweb, FILE *out); /* expand a module, writing to file out */ <<local data>>= static char *lastfilename = 0; @@ -143,7 +143,7 @@ [[partial_distance]] is the width of what has already been written to the current line. <<C functions>>= int expand (Module mp, int indent, int partial_distance, Parent parent, - char *locformat, FILE *out) { + char *locformat, char *pythonweb, FILE *out) { struct modpart *p; Module newmod; int error=Normal; @@ -172,19 +172,33 @@ is emitted, {\em except} when it's the first line of a module (hack! hack!). [[printloc]] returns nonzero when [[#line]] is actually emitted. +Ross triple-hacks: if in python mode, disable the obnoxious loss of indent. +Except I don't really understand how this is working, and am not sure blank newlines will be handled properly. + <<print a string>>= if (*(p->contents) != '\0') { - if (*locformat) { - if (printloc(out,locformat,p->loc,partial_distance) && (p != mp->head)) - indent_for(partial_distance, out); - } else if (partial_distance == 0) { - indent_for(indent, out); - partial_distance = indent; + if (*pythonweb) { + printloc(out, locformat,p->loc,partial_distance); + fputc('#', out); + indent_for(indent, out); + partial_distance = indent; + fprintf(out, "%s",p->contents); + } + else { + if (*locformat) { + if (printloc(out,locformat,p->loc,partial_distance) && (p != mp->head)) + indent_for(partial_distance, out); + } else if (partial_distance == 0) { + indent_for(indent, out); + partial_distance = indent; + } + fprintf(out,"%s",p->contents); } - fprintf(out,"%s",p->contents); partial_distance = limitcolumn(p->contents, partial_distance); } <<print a newline>>= +if (*pythonweb && partial_distance==0) + putc('#', out); partial_distance = 0; putc('\n', out); lastlineno++; @@ -209,7 +223,7 @@ partial_distance = indent; } retcode = expand (newmod, partial_distance, partial_distance, - &thismodule, locformat, out); + &thismodule, locformat, pythonweb, out); if (retcode > error) error = retcode; } partial_distance = limitcolumn(p->contents, partial_distance + 2) + 2; @@ -267,6 +281,7 @@ case 'N': putc('\n', fp); break; case 'F': fprintf(fp, "%s", loc.filename); break; case 'L': fprintf(fp, "%d", loc.lineno); break; + case 'I': fprintf(fp, "%d", partial); break; case '-': case '+': if (isdigit(p[1]) && p[2] == 'L') { fprintf(fp, "%d", *p == '+' ? loc.lineno + (p[1] - '0') diff -Naur noweb-2.11b/src/c/notangle.nw noweb-2.12rb/src/c/notangle.nw --- noweb-2.11b/src/c/notangle.nw 2006-06-12 21:03:54.000000000 +0000 +++ noweb-2.12rb/src/c/notangle.nw 2012-02-21 06:14:21.000000000 +0000 @@ -13,7 +13,7 @@ in a table supplied by [[modtrees.h]]; we'll cover the details later. <<header>>= -void emit_module_named (FILE *out, char *rootname, char *locformat); +void emit_module_named (FILE *out, char *rootname, char *locformat, char *pythonweb); <<*>>= static char rcsid[] = "$Id: notangle.nw,v 2.22 2006/06/12 21:03:53 nr Exp nr $"; static char rcsname[] = "$Name: v2_11b $"; @@ -34,12 +34,12 @@ <<Function declarations>> -void emit_module_named (FILE *out, char *rootname, char *locformat) { +void emit_module_named (FILE *out, char *rootname, char *locformat, char *pythonweb) { Module root = NULL; /* ptr to root module */ root = lookup(rootname); <<quit if we couldn't find the root>> - (void) expand(root,0,0,0,locformat,out); + (void) expand(root,0,0,0,locformat, pythonweb, out); putc('\n',out); /* make output end with newline */ } @ diff -Naur noweb-2.11b/src/shell/notangle.nw noweb-2.12rb/src/shell/notangle.nw --- noweb-2.11b/src/shell/notangle.nw 1998-08-17 00:13:05.000000000 +0000 +++ noweb-2.12rb/src/shell/notangle.nw 2012-02-21 18:37:03.000000000 +0000 @@ -8,6 +8,7 @@ # $Name: $ LIB=|LIBDIR| markup=$LIB/markup opt= arg= markopt= filters= +getinput= while [ $# -gt 0 ]; do case $1 in -ml|-m3|-awk|-icn|-icon|-pascal|-c|-c++|-f77|-f90|-tex|-w[0-9][0-9]*) ;; @@ -19,6 +20,7 @@ -markup) markup="$2" ; shift ;; -) arg="$arg '$1'" ;; -L*) opt="$opt -t '$1'" ; markopt="$markopt -t" ;; + -R*) opt="$opt $1"; getinput="<${$1:2} ";; -*) opt="$opt '$1'" ;; *) arg="$arg '$1'" ;; esac @@ -26,5 +28,5 @@ done PATH="$PATH:$LIB" export PATH -eval "$markup $markopt $arg | $filters $LIB/nt $opt "'; rc=$?' +eval "$getinput $markup $markopt $arg | $filters $LIB/nt $opt "'; rc=$?' exit $rc diff -Naur noweb-2.11b/src/xdoc/docdate.nw noweb-2.12rb/src/xdoc/docdate.nw --- noweb-2.11b/src/xdoc/docdate.nw 2006-06-12 21:03:53.000000000 +0000 +++ noweb-2.12rb/src/xdoc/docdate.nw 2012-02-22 00:56:01.000000000 +0000 @@ -1,13 +1,15 @@ <<noweb documentation date>>= -3/28/2001 +2/21/2012 <<AUTHOR section>>= .SH VERSION This man page is from .I noweb -version $Name: v2_11b $. +version $Name: v2_12rb $. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP. diff -Naur noweb-2.11b/src/xdoc/manpage.nw noweb-2.12rb/src/xdoc/manpage.nw --- noweb-2.11b/src/xdoc/manpage.nw 2006-05-04 16:07:04.000000000 +0000 +++ noweb-2.12rb/src/xdoc/manpage.nw 2012-02-22 01:09:41.000000000 +0000 @@ -4,7 +4,7 @@ notangle, noweave, nountangle \- noweb, a literate-programming tool .SH SYNOPSIS .B notangle -[\fB\-R\fProotname ...] [\fB\-filter\fP command] +[\fB\-P\fPwebname] [\fB\-R\fProotname ...] [\fB\-filter\fP command] [\fB\-L\fP[format]] [file] ... .br \fBnountangle\fP @@ -167,6 +167,17 @@ .B \-R option is given, expand the chunk named \fB@<<\fP*\fB@>>\fP. .TP +.B \-P\fIwebname\fR +Enter Python mode. Input will come from the file \fIwebname\fR, not +the standard input, which will be ignored. This produces tangled +output design to work with the python \fBdetangle\fR module so that +errors and strack traces refer to the correct location in +\fIwebname\fR rather than in the tangled file. Ordinarily, +\fIwebname\fR will have a .py extension. If you use this option +\-\fBr\fR is mandatory and \-\fBL\fR will be ignored. The \fIname\fR +for \-\fBR\fR should match the name of the file the command creates, +though you still need to specify the output file explicitly. +.TP .B \-L\fIformat\fR Emit line number indications at chunk boundaries. A line number indication identifies the source of the line that follows it. @@ -176,6 +187,8 @@ indicates the name of the source file, .B "%L" indicates the line number of the source file, +.B "%I" +indicates the indentation level of this module. .B "%N" indicates a newline, and @@ -249,6 +262,20 @@ transforms documentation chunks into comments, create comments on lines of width \fIn\fP. .I notangle ignores this option. +.TP +.B Python output format +.B \-P +creates a file that imports +.B detangle +and then executes it to scan the rest of the file. Regular code +begins after +.nf +#if 0: +.fi +It is the tangled python code with a # before every line. It also includes special #line directives that +.B detangle +uses to map to the proper location in the source noweb file. + .SH WEAVING <<man page: WEAVING section>> .SH INDEXING AND CROSS-REFERENCE
#! /bin/sh /usr/share/dpatch/dpatch-run ## 16_python-derived.dpatch by Ross Boylan <r...@biostat.ucsf.edu> ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Add python #line handling--derived files ## All changes in this section can be derived from those of the previous patch. ## They are here so that the build system does not require a working noweb ## to build noweb. @DPATCH@ diff -Naur noweb-2.11b/src/c/main.c noweb-2.12rb/src/c/main.c --- noweb-2.11b/src/c/main.c 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/c/main.c 2012-02-22 00:56:39.000000000 +0000 @@ -11,12 +11,20 @@ #include "modules.h" #include "modtrees.h" -#line 25 "main.nw" +#line 75 "main.nw" main(int argc, char **argv) { int i; char *locformat = ""; char *Clocformat = "#line %L \"%F\"%N"; + char *Plocformat = "#line %L %I %F%N"; int root_options_seen = 0; + char *pythonweb = ""; + + /* These were in contemplation of switching the file. + But the program is part of a pipeline. */ + FILE *fin = stdin; + FILE *fout = stdout; + char *fout_name; tabsize = 0; /* default for nt is not to use tabs */ progname = argv[0]; @@ -24,10 +32,10 @@ for (i=1; i<argc; i++) { -#line 53 "main.nw" +#line 119 "main.nw" if (*argv[i]=='-') { -#line 69 "main.nw" +#line 138 "main.nw" switch (argv[i][1]) { case 't': /* set tab size or turn off */ if (isdigit(argv[i][2])) @@ -37,6 +45,11 @@ else errormsg(Error, "%s: ill-formed option %s\n", argv[0], argv[i]); break; + case 'P': /* enabled special tangled python mode */ + pythonweb = argv[i]+2; + if (*pythonweb == 0) + errormsg(Fatal, "-P requires a file name. No spaces.\n"); + break; case 'R': /* change name of root module */ root_options_seen++; break; @@ -47,26 +60,50 @@ default: errormsg(Warning, "Ignoring unknown option -%s", argv[i]); } -#line 55 "main.nw" +#line 121 "main.nw" } else { -#line 90 "main.nw" +#line 164 "main.nw" errormsg(Warning, "I can't handle arguments yet, so I'll just ignore `%s'",argv[i]); -#line 57 "main.nw" +#line 123 "main.nw" } -#line 37 "main.nw" +#line 95 "main.nw" } - read_defs(stdin); /* read all the definitions */ + +#line 170 "main.nw" +if (*pythonweb && (root_options_seen == 0)){ + errormsg(Fatal, "-P requires the use of -R"); + } +if (*pythonweb && (*locformat != 0)) { + errormsg(Warning, "-P ignore your -L option and uses its own."); + } + +#line 98 "main.nw" + read_defs(fin); /* read all the definitions */ +#line 101 "main.nw" + close(fin); apply_each_module(remove_final_newline); /* pretty up the module texts */ if (root_options_seen == 0) - emit_module_named(stdout, "*", locformat); + emit_module_named(stdout, "*", locformat, pythonweb); else for (i=1; i<argc; i++) - if (argv[i][0] == '-' && argv[i][1] == 'R') - emit_module_named(stdout, argv[i]+2, locformat); + if (argv[i][0] == '-' && argv[i][1] == 'R') { + fout_name = argv[i]+2; + +#line 179 "main.nw" +if (*pythonweb) { + locformat = Plocformat; + fprintf(fout, "from detangle import detangle\n"); + fprintf(fout, "detangle('%s', '%s')\n\n", fout_name, pythonweb); + fprintf(fout, "#if 0:\n"); + } +#line 110 "main.nw" + emit_module_named(fout, fout_name, locformat, pythonweb); + close(fout); + } nowebexit(NULL); return errorlevel; /* slay warning */ diff -Naur noweb-2.11b/src/c/mnt.c noweb-2.12rb/src/c/mnt.c --- noweb-2.11b/src/c/mnt.c 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/c/mnt.c 2012-02-21 08:01:23.000000000 +0000 @@ -13,47 +13,47 @@ #include "columns.h" #include "strsave.h" -#line 52 "mnt.nw" +#line 58 "mnt.nw" void add_uses_to_usecounts(Module mp); void emit_if_unused_and_conforming(Module mp); -#line 86 "mnt.nw" -static void emitfile(char *modname); -#line 180 "mnt.nw" +#line 92 "mnt.nw" +static void emitfile(char *modname, char *pythonweb); +#line 186 "mnt.nw" #ifdef TEMPNAM extern char *tempnam (const char *dir, const char *pfx); /* temp file in dir */ #else #define tempnam(DIR,PFX) (strsave(tmpnam(NULL))) #endif -#line 25 "mnt.nw" +#line 31 "mnt.nw" #define Clocformat "#line %L \"%F\"%N" static char *locformat = Clocformat; +static char *pythonweb = ""; /* for future expansion */ main(int argc, char **argv) { int i; - tabsize = 0; /* default for nt is not to use tabs */ progname = argv[0]; finalstage = 1; -#line 46 "mnt.nw" +#line 52 "mnt.nw" read_defs(stdin); apply_each_module(remove_final_newline); -#line 36 "mnt.nw" +#line 42 "mnt.nw" for (i=1; i<argc; i++) switch (*argv[i]) { case '-': -#line 152 "mnt.nw" +#line 158 "mnt.nw" switch (*++argv[i]) { case 'a': if (strcmp(argv[i], "all")) errormsg(Warning, "Ignoring unknown option -%s", argv[i]); else { -#line 49 "mnt.nw" +#line 55 "mnt.nw" apply_each_module(add_uses_to_usecounts); apply_each_module(emit_if_unused_and_conforming); -#line 156 "mnt.nw" +#line 162 "mnt.nw" } break; case 't': /* set tab size or turn off */ @@ -71,14 +71,14 @@ default: errormsg(Warning, "Ignoring unknown option -%s", argv[i]); } -#line 38 "mnt.nw" +#line 44 "mnt.nw" break; - default: emitfile(argv[i]); break; + default: emitfile(argv[i], pythonweb); break; } nowebexit(NULL); return errorlevel; /* slay warning */ } -#line 55 "mnt.nw" +#line 61 "mnt.nw" void add_uses_to_usecounts(Module mp) { Module used; struct modpart *p; @@ -89,7 +89,7 @@ used->usecount++; } } -#line 71 "mnt.nw" +#line 77 "mnt.nw" void emit_if_unused_and_conforming(Module mp) { char *index; if (mp->usecount == 0 && strpbrk(mp->name, " \n\t\v\r\f") == NULL) @@ -99,19 +99,19 @@ errormsg(Error, "<<*>> is not a good chunk name for noweb; " "use notangle instead"); else - emitfile(mp->name); + emitfile(mp->name, pythonweb); else errormsg(Error, "<<%s>> cannot be an output chunk; " "it contains a metacharacter", mp->name); } -#line 88 "mnt.nw" -static void emitfile(char *modname) { +#line 94 "mnt.nw" +static void emitfile(char *modname, char *pythonweb) { Module root = lookup(modname); char *tempname = tempnam(".", 0); FILE *fp; char *lfmt, *filename; -#line 108 "mnt.nw" +#line 114 "mnt.nw" { int n = strlen(modname) - 1; if (n >= 0 && modname[n] == '*') { lfmt = locformat; @@ -122,25 +122,25 @@ filename = modname; } } -#line 94 "mnt.nw" +#line 100 "mnt.nw" -#line 147 "mnt.nw" +#line 153 "mnt.nw" if (root == NULL) { errormsg(Error, "Chunk <<%s>> is undefined", filename); return; } -#line 95 "mnt.nw" +#line 101 "mnt.nw" fp = fopen(tempname, "w"); if (fp == NULL) errormsg(Fatal, "Can't open temporary file %s", tempname); -#line 119 "mnt.nw" +#line 125 "mnt.nw" resetloc(); -(void) expand(root, 0, 0, 0, lfmt, fp); +(void) expand(root, 0, 0, 0, lfmt, pythonweb, fp); putc('\n', fp); fclose(fp); -#line 98 "mnt.nw" +#line 104 "mnt.nw" -#line 125 "mnt.nw" +#line 131 "mnt.nw" { FILE *dest, *tmp; dest = fopen(filename, "r"); if (dest != NULL) { @@ -159,23 +159,23 @@ } } } -#line 99 "mnt.nw" +#line 105 "mnt.nw" remove(filename); if (rename(tempname, filename) != 0) { /* different file systems? (may have to copy) */ FILE *fp = fopen(filename, "w"); if (fp == NULL) {remove(tempname); -#line 144 "mnt.nw" +#line 150 "mnt.nw" errormsg(Error, "Can't open output file %s", filename); return; -#line 102 "mnt.nw" +#line 108 "mnt.nw" } -#line 119 "mnt.nw" +#line 125 "mnt.nw" resetloc(); -(void) expand(root, 0, 0, 0, lfmt, fp); +(void) expand(root, 0, 0, 0, lfmt, pythonweb, fp); putc('\n', fp); fclose(fp); -#line 104 "mnt.nw" +#line 110 "mnt.nw" remove(tempname); } } diff -Naur noweb-2.11b/src/c/modules.c noweb-2.12rb/src/c/modules.c --- noweb-2.11b/src/c/modules.c 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/c/modules.c 2012-02-21 23:50:43.000000000 +0000 @@ -17,7 +17,7 @@ static void append(Module mp, struct modpart *p); -#line 227 "modules.nw" +#line 241 "modules.nw" static int seekcycle(Module mp, Parent parent); #line 132 "modules.nw" static char *lastfilename = 0; @@ -74,19 +74,19 @@ } #line 145 "modules.nw" int expand (Module mp, int indent, int partial_distance, Parent parent, - char *locformat, FILE *out) { + char *locformat, char *pythonweb, FILE *out) { struct modpart *p; Module newmod; int error=Normal; struct parent thismodule; /* the value only matters when we're expanding a module */ -#line 219 "modules.nw" +#line 233 "modules.nw" thismodule.this = mp; thismodule.parent = parent; #line 153 "modules.nw" -#line 222 "modules.nw" +#line 236 "modules.nw" if (seekcycle(mp, parent)) { errormsg(Error, "<<%s>>", mp->name); return Error; @@ -96,22 +96,31 @@ for (p=mp->head; p!=NULL; p=p->next) { switch (p->ptype) { case STRING: -#line 176 "modules.nw" +#line 179 "modules.nw" if (*(p->contents) != '\0') { - if (*locformat) { - if (printloc(out,locformat,p->loc,partial_distance) && (p != mp->head)) - indent_for(partial_distance, out); - } else if (partial_distance == 0) { - indent_for(indent, out); - partial_distance = indent; + if (*pythonweb) { + printloc(out, locformat,p->loc,partial_distance); + fputc('#', out); + indent_for(indent, out); + partial_distance = indent; + fprintf(out, "%s",p->contents); + } + else { + if (*locformat) { + if (printloc(out,locformat,p->loc,partial_distance) && (p != mp->head)) + indent_for(partial_distance, out); + } else if (partial_distance == 0) { + indent_for(indent, out); + partial_distance = indent; + } + fprintf(out,"%s",p->contents); } - fprintf(out,"%s",p->contents); partial_distance = limitcolumn(p->contents, partial_distance); } #line 157 "modules.nw" ; break; case MODULE: -#line 201 "modules.nw" +#line 215 "modules.nw" newmod = lookup(p->contents); if (newmod==NULL) { errormsg (Error, "undefined chunk name: <<%s>>", p->contents); @@ -123,7 +132,7 @@ partial_distance = indent; } retcode = expand (newmod, partial_distance, partial_distance, - &thismodule, locformat, out); + &thismodule, locformat, pythonweb, out); if (retcode > error) error = retcode; } partial_distance = limitcolumn(p->contents, partial_distance + 2) + 2; @@ -131,7 +140,9 @@ #line 158 "modules.nw" ; break; case NEWLINE: -#line 188 "modules.nw" +#line 200 "modules.nw" +if (*pythonweb && partial_distance==0) + putc('#', out); partial_distance = 0; putc('\n', out); lastlineno++; @@ -142,7 +153,7 @@ } return error; } -#line 229 "modules.nw" +#line 243 "modules.nw" static int seekcycle(Module mp, Parent parent) { if (parent == NULL) { return 0; @@ -155,14 +166,14 @@ return 0; } } -#line 251 "modules.nw" +#line 265 "modules.nw" int printloc(FILE *fp, char *fmt, Location loc, int partial) { char *p; if (*fmt && (loc.filename!=lastfilename || lastlineno != loc.lineno)) { if (partial) putc('\n',fp); -#line 263 "modules.nw" +#line 277 "modules.nw" for (p = fmt; *p; p++) { if (*p == '%') { switch (*++p) { @@ -170,6 +181,7 @@ case 'N': putc('\n', fp); break; case 'F': fprintf(fp, "%s", loc.filename); break; case 'L': fprintf(fp, "%d", loc.lineno); break; + case 'I': fprintf(fp, "%d", partial); break; case '-': case '+': if (isdigit(p[1]) && p[2] == 'L') { fprintf(fp, "%d", *p == '+' ? loc.lineno + (p[1] - '0') @@ -177,35 +189,35 @@ p += 2; } else -#line 283 "modules.nw" +#line 298 "modules.nw" { static int complained = 0; if (!complained) { errormsg(Error,"Bad format sequence ``%%%c'' in -L%s",*p,fmt); complained = 1; } } -#line 277 "modules.nw" +#line 292 "modules.nw" break; default: -#line 283 "modules.nw" +#line 298 "modules.nw" { static int complained = 0; if (!complained) { errormsg(Error,"Bad format sequence ``%%%c'' in -L%s",*p,fmt); complained = 1; } } -#line 278 "modules.nw" +#line 293 "modules.nw" break; } } else putc(*p, fp); } -#line 257 "modules.nw" +#line 271 "modules.nw" lastfilename = loc.filename; lastlineno = loc.lineno; return 1; } else return 0; } -#line 309 "modules.nw" +#line 324 "modules.nw" void remove_final_newline (Module mp) { /* remove trailing newline that must be in module */ if (mp->tail==NULL) /* module has no text */ diff -Naur noweb-2.11b/src/c/modules.h noweb-2.12rb/src/c/modules.h --- noweb-2.11b/src/c/modules.h 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/c/modules.h 2012-02-21 23:50:42.000000000 +0000 @@ -29,7 +29,7 @@ } *Parent; int expand (Module mp, int indent, int partial_distance, Parent parent, - char *locformat, FILE *out); + char *locformat, char *pythonweb, FILE *out); /* expand a module, writing to file out */ void resetloc(void); int printloc(FILE *fp, char *fmt, Location loc, int partial); diff -Naur noweb-2.11b/src/c/notangle.c noweb-2.12rb/src/c/notangle.c --- noweb-2.11b/src/c/notangle.c 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/c/notangle.c 2012-02-21 06:50:06.000000000 +0000 @@ -22,7 +22,7 @@ void insist(char *line, char *keyword, char *msg); #line 37 "notangle.nw" -void emit_module_named (FILE *out, char *rootname, char *locformat) { +void emit_module_named (FILE *out, char *rootname, char *locformat, char *pythonweb) { Module root = NULL; /* ptr to root module */ root = lookup(rootname); @@ -33,7 +33,7 @@ return; } #line 42 "notangle.nw" - (void) expand(root,0,0,0,locformat,out); + (void) expand(root,0,0,0,locformat, pythonweb, out); putc('\n',out); /* make output end with newline */ } #line 56 "notangle.nw" diff -Naur noweb-2.11b/src/c/notangle.h noweb-2.12rb/src/c/notangle.h --- noweb-2.11b/src/c/notangle.h 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/c/notangle.h 2012-02-21 06:50:06.000000000 +0000 @@ -1,2 +1,2 @@ -void emit_module_named (FILE *out, char *rootname, char *locformat); +void emit_module_named (FILE *out, char *rootname, char *locformat, char *pythonweb); void read_defs(FILE *in); /* read module definitions */ diff -Naur noweb-2.11b/src/shell/notangle noweb-2.12rb/src/shell/notangle --- noweb-2.11b/src/shell/notangle 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/shell/notangle 2012-02-21 20:30:20.000000000 +0000 @@ -5,23 +5,32 @@ # $Name: $ LIB=|LIBDIR| markup=$LIB/markup opt= arg= markopt= filters= +getinput= while [ $# -gt 0 ]; do - case $1 in + case $1 in -ml|-m3|-awk|-icn|-icon|-pascal|-c|-c++|-f77|-f90|-tex|-w[0-9][0-9]*) ;; - # deliberately ignore nountangle args - -t) ;; # this is default + # deliberately ignore nountangle args + -t) ;; # this is default -t*) markopt="$markopt -t" ; opt="$opt '$1'" ;; - # copy tabs at markup, use width given in notangle - -filter) filters="$filters $2 | " ; shift ;; - -markup) markup="$2" ; shift ;; - -) arg="$arg '$1'" ;; - -L*) opt="$opt -t '$1'" ; markopt="$markopt -t" ;; - -*) opt="$opt '$1'" ;; - *) arg="$arg '$1'" ;; - esac - shift + # copy tabs at markup, use width given in notangle + -filter) filters="$filters $2 | " ; shift ;; + -markup) markup="$2" ; shift ;; + -) arg="$arg '$1'" ;; + -L*) opt="$opt -t '$1'" ; markopt="$markopt -t" ;; + -P*) opt="$opt $1"; + pfn=${1#-P}; + if [ -z ${pfn##/*} ]; then + getinp="<$pfn"; + else + getinput="<${PWD}/${pfn#-P} "; + fi; + ;; + -*) opt="$opt '$1'" ;; + *) arg="$arg '$1'" ;; + esac + shift done PATH="$PATH:$LIB" export PATH -eval "$markup $markopt $arg | $filters $LIB/nt $opt "'; rc=$?' +eval "$getinput $markup $markopt $arg | $filters $LIB/nt $opt "'; rc=$?' exit $rc diff -Naur noweb-2.11b/src/xdoc/htmltoc.1 noweb-2.12rb/src/xdoc/htmltoc.1 --- noweb-2.11b/src/xdoc/htmltoc.1 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/xdoc/htmltoc.1 2012-02-22 00:56:41.000000000 +0000 @@ -1,4 +1,4 @@ -.TH NOWEB 1 "local 3/28/2001" +.TH NOWEB 1 "local 2/21/2012" .SH NAME htmltoc \- add table of contents to HTML document .SH SYNOPSIS @@ -31,11 +31,13 @@ .SH VERSION This man page is from .I noweb -version 2.11b. +version 2.12rb. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP. .PP diff -Naur noweb-2.11b/src/xdoc/nodefs.1 noweb-2.12rb/src/xdoc/nodefs.1 --- noweb-2.11b/src/xdoc/nodefs.1 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/xdoc/nodefs.1 2012-02-22 00:56:41.000000000 +0000 @@ -1,4 +1,4 @@ -.TH NOWEB 1 "local 3/28/2001" +.TH NOWEB 1 "local 2/21/2012" .SH NAME nodefs \- find definitions in noweb file .SH SYNOPSIS @@ -45,10 +45,12 @@ .SH VERSION This man page is from .I noweb -version 2.11b. +version 2.12rb. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP. diff -Naur noweb-2.11b/src/xdoc/noindex.1 noweb-2.12rb/src/xdoc/noindex.1 --- noweb-2.11b/src/xdoc/noindex.1 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/xdoc/noindex.1 2012-02-22 00:56:41.000000000 +0000 @@ -1,4 +1,4 @@ -.TH NOWEB 1 "local 3/28/2001" +.TH NOWEB 1 "local 2/21/2012" .SH NAME noindex \- build external index for noweb document .SH SYNOPSIS @@ -162,10 +162,12 @@ .SH VERSION This man page is from .I noweb -version 2.11b. +version 2.12rb. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP. diff -Naur noweb-2.11b/src/xdoc/noroff.1 noweb-2.12rb/src/xdoc/noroff.1 --- noweb-2.11b/src/xdoc/noroff.1 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/xdoc/noroff.1 2012-02-22 00:56:41.000000000 +0000 @@ -1,4 +1,4 @@ -.TH NOWEB 1 "local 3/28/2001" +.TH NOWEB 1 "local 2/21/2012" .SH NAME noroff \- format woven \fItroff\fP documentation .SH SYNOPSIS @@ -41,11 +41,13 @@ .SH VERSION This man page is from .I noweb -version 2.11b. +version 2.12rb. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP. .PP diff -Naur noweb-2.11b/src/xdoc/noroots.1 noweb-2.12rb/src/xdoc/noroots.1 --- noweb-2.11b/src/xdoc/noroots.1 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/xdoc/noroots.1 2012-02-22 00:56:41.000000000 +0000 @@ -1,4 +1,4 @@ -.TH NOWEB 1 "local 3/28/2001" +.TH NOWEB 1 "local 2/21/2012" .SH NAME noroots \- print roots of a noweb file .SH SYNOPSIS @@ -21,10 +21,12 @@ .SH VERSION This man page is from .I noweb -version 2.11b. +version 2.12rb. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP. diff -Naur noweb-2.11b/src/xdoc/nowebfilters.7 noweb-2.12rb/src/xdoc/nowebfilters.7 --- noweb-2.11b/src/xdoc/nowebfilters.7 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/xdoc/nowebfilters.7 2012-02-22 00:56:41.000000000 +0000 @@ -1,4 +1,4 @@ -.TH NOWEB 7 "local 3/28/2001" +.TH NOWEB 7 "local 2/21/2012" .SH NAME nowebfilters \- filters and parsers for use with noweb .SH SYNOPSIS @@ -199,10 +199,12 @@ .SH VERSION This man page is from .I noweb -version 2.11b. +version 2.12rb. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP. diff -Naur noweb-2.11b/src/xdoc/sl2h.1 noweb-2.12rb/src/xdoc/sl2h.1 --- noweb-2.11b/src/xdoc/sl2h.1 2006-06-12 21:16:23.000000000 +0000 +++ noweb-2.12rb/src/xdoc/sl2h.1 2012-02-22 00:56:41.000000000 +0000 @@ -1,4 +1,4 @@ -.TH NOWEB 1 "local 3/28/2001" +.TH NOWEB 1 "local 2/21/2012" .SH NAME sl2h \- simple latex to HTML converter .SH SYNOPSIS @@ -28,10 +28,12 @@ .SH VERSION This man page is from .I noweb -version 2.11b. +version 2.12rb. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP. diff -Naur noweb-2.11b/src/xdoc/notangle.1 noweb-2.12rb/src/xdoc/notangle.1 --- noweb-2.11b/src/xdoc/notangle.1 2012-02-27 21:19:19.000000000 +0000 +++ noweb-2.12rb/src/xdoc/notangle.1 2012-02-27 21:26:56.000000000 +0000 @@ -1,9 +1,9 @@ -.TH NOWEB 1 "local 3/28/2001" +.TH NOWEB 1 "local 2/21/2012" .SH NAME notangle, noweave, nountangle \- noweb, a literate-programming tool .SH SYNOPSIS .B notangle -[\fB\-R\fProotname ...] [\fB\-filter\fP command] +[\fB\-P\fPwebname] [\fB\-R\fProotname ...] [\fB\-filter\fP command] [\fB\-L\fP[format]] [file] ... .br \fBnountangle\fP @@ -132,6 +132,17 @@ .B \-R option is given, expand the chunk named \fB<<\fP*\fB>>\fP. .TP +.B \-P\fIwebname\fR +Enter Python mode. Input will come from the file \fIwebname\fR, not +the standard input, which will be ignored. This produces tangled +output design to work with the python \fBdetangle\fR module so that +errors and strack traces refer to the correct location in +\fIwebname\fR rather than in the tangled file. Ordinarily, +\fIwebname\fR will have a .py extension. If you use this option +\-\fBr\fR is mandatory and \-\fBL\fR will be ignored. The \fIname\fR +for \-\fBR\fR should match the name of the file the command creates, +though you still need to specify the output file explicitly. +.TP .B \-L\fIformat\fR Emit line number indications at chunk boundaries. A line number indication identifies the source of the line that follows it. @@ -141,6 +152,8 @@ indicates the name of the source file, .B "%L" indicates the line number of the source file, +.B "%I" +indicates the indentation level of this module. .B "%N" indicates a newline, and @@ -228,6 +241,20 @@ transforms documentation chunks into comments, create comments on lines of width \fIn\fP. .I notangle ignores this option. +.TP +.B Python output format +.B \-P +creates a file that imports +.B detangle +and then executes it to scan the rest of the file. Regular code +begins after +.nf +#if 0: +.fi +It is the tangled python code with a # before every line. It also includes special #line directives that +.B detangle +uses to map to the proper location in the source noweb file. + .SH WEAVING Output from \fInoweave\fP can be used in \fITeX\fP documents that @@ -632,10 +657,12 @@ .SH VERSION This man page is from .I noweb -version 2.11b. +version 2.12rb. .SH AUTHOR Norman Ramsey, Harvard University. Internet address \f...@eecs.harvard.edu\fP. .br +Python mode added by Ross Boylan <\fbr...@biostat.ucsf.edu\fP>. +.br Noweb home page at \fBhttp://www.eecs.harvard.edu/~nr/noweb\fP.
#! /usr/bin/python # File: detangle.py # Author: Ross Boylan # Created: 2012-02-20 # # (c) 2012 # Released under GPL 3 or later. # Compile and execute a tangled file so that the source # appears to be from the original file. # # Intended Use in a file tangled.py: # from detangle import detangle # detangle("tangled.py", "original") # if 0: # def foo(bar): # pass # #line 45 6 # class X: # "some comment" # # # So the original code is indented one space and disabled by an if 0: # It may have #line directives interspersed. # #line lineno [indent [filename]] # Makes it appear as if following lines are from <filename> (defaults to the # 2nd argument of detangle) starting at <lineno>, which will be the apparent # line number of the next physical line. <indent> (default 0) implies the # following code has been indented relative to the original source. import pdb import ast from bisect import bisect import re def detangle(thisfile, originalfile): """Compile the code in thisfile <String> making it appear to have come from originalfile <String> with line and column position as indicated by #line directives""" text, linemap = scancode(thisfile, originalfile) try: tree = ast.parse(text, filename=originalfile) except SyntaxError as e: raise linemap.revised_exception(e) tree = linemap.rewrite_ast(tree) code = compile(tree, originalfile, "exec") exec code def scancode(thisfile, originalfile): "locate code in thisfile and return text and a line map" # skip to start of quoted code foundit = False map = Linemap(originalfile) text = "" lineRE = re.compile(r"^#line (?P<line>\d+)( (?P<indent>\d+)( (?P<file>.*))?)?(\n)?$") with open(thisfile, "r") as inf: # locate start of quoted code for line in inf: if line.startswith("#if 0:"): foundit = True break if not foundit: raise Exception("No quoted code in %s"%thisfile) lineno = 0 for line in inf: lineno += 1 m = lineRE.match(line) if m: d = m.groupdict() original_lineno = int(d["line"]) indent = d["indent"] indent = int(indent) if indent else 0 map.add_map(lineno, original_lineno, indent, d["file"]) lineno -= 1 else: text = ''.join((text, line[1:])) return text, map class Linemap: "maps from tangle source to original source" def __init__(self, original_file): "sets the default original file name" self.default_original = original_file # self.map[i] is for tangled lines starting at # self.tangled_lines[i] self.map = [] self.tangled_lines = [] self.last_tangled_lineno = -1 self.last_tangled_map = None def add_map(self, tangled_lineno, original_lineno, indent=0, original_file=None): """add a remapping that takes effect at tangled_lineno. Assumess calling with increaseing tangled_lineno""" self.tangled_lines.append(tangled_lineno) self.map.append((original_lineno, indent, original_file)) def map_for(self, tangled_lineno, tangled_column=None): "return the map object for the indicated line" if tangled_lineno == self.last_tangled_lineno: return self.last_tangled_map i = bisect(self.tangled_lines, tangled_lineno) if i > 0: i -= 1 x = self.map[i] file = x[2] if x[2] else self.default_original line = x[0]+tangled_lineno-self.tangled_lines[i] column = tangled_column-x[1] if tangled_column else None else: "This really should not happen" line = tangled_lineno column = tangled_column file = "<neverland>" self.last_tangled_lineno = tangled_lineno self.last_tangled_map = line, column, file return self.last_tangled_map def revised_exception(self, e): line, column, file = self.map_for(e.lineno, e.offset) e.lineno = line if column: indent = e.offset - column e.offset = column e.text = e.text[indent:] e.file = file print "Changed except to bet at line %i in %s"%(e.lineno, e.file) return e def rewrite_ast(self, tree): for node in ast.walk(tree): if hasattr(node, 'lineno'): hasCol = hasattr(node, 'column_offset') tangled_column = node.column_offset if hasCol else None line, column, file = self.map_for(node.lineno, tangled_column) if line == 29: pdb.set_trace() node.lineno = line if column and hasattr(node, 'column_offset'): node.column_offset = column return tree