mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-03 21:30:29 +02:00
Fix the mess I made.
This commit is contained in:
parent
440333c865
commit
4304846e08
16 changed files with 3032 additions and 0 deletions
286
scripts/ChangeLog
Normal file
286
scripts/ChangeLog
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
2002-05-18 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* api-diff (group-diff): Also output +N and -N adds and subs
|
||||||
|
details, respectively.
|
||||||
|
|
||||||
|
2002-05-13 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* read-rfc822: New script.
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): Add api-diff and read-rfc822.
|
||||||
|
|
||||||
|
* scan-api (scan-api): No longer include timestamp.
|
||||||
|
|
||||||
|
2002-05-11 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* scan-api (scan-api): Fix bug: No longer omit `C' and `Scheme' in
|
||||||
|
groups in the presence of the grouper.
|
||||||
|
|
||||||
|
* api-diff: Use modules (ice-9 format), (ice-9 getopt-long).
|
||||||
|
Autoload module (srfi srfi-13).
|
||||||
|
No longer export `diff-alists'.
|
||||||
|
|
||||||
|
(diff, diff-alists, display-list): Remove.
|
||||||
|
(put, get, read-api-alist-file, hang-by-the-roots, diff?,
|
||||||
|
diff+note!, group-diff): New procs.
|
||||||
|
(api-diff): Rewrite.
|
||||||
|
|
||||||
|
2002-05-10 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* scan-api (add-props): New proc.
|
||||||
|
(make-grok-proc): Renamed from `make-grok-hook'.
|
||||||
|
(make-members-proc): Renamed from `make-members-hook'.
|
||||||
|
(make-grouper): Renamed from `make-grouping-hook'. Update callers.
|
||||||
|
Add handling for multiple grouping-defs files.
|
||||||
|
(scan-api): Add handling for multiple grouping-defs files.
|
||||||
|
Cache `symbol->string' result; adjust `sort' usage.
|
||||||
|
|
||||||
|
2002-05-09 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* scan-api (scan-C!): Use more robust regexp.
|
||||||
|
|
||||||
|
2002-05-08 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* scan-api: New script.
|
||||||
|
(scan-api): Handle case where `grouping-hook' is #f.
|
||||||
|
|
||||||
|
Remove top-level `debug-enable' form.
|
||||||
|
Add TODO comment; nfc.
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): Add "scan-api".
|
||||||
|
|
||||||
|
2002-04-30 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* summarize-guile-TODO (make-display-item):
|
||||||
|
Hoist some lambdas; nfc.
|
||||||
|
|
||||||
|
2002-04-29 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* summarize-guile-TODO: Fix commentary typo; nfc.
|
||||||
|
|
||||||
|
2002-04-08 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* summarize-guile-TODO: Use (ice-9 getopt-long).
|
||||||
|
Autoload (ice-9 common-list).
|
||||||
|
|
||||||
|
(select-items): New proc.
|
||||||
|
(make-display-item): New proc.
|
||||||
|
(display-item): Delete.
|
||||||
|
(display-items): Use `make-display-item'.
|
||||||
|
(summarize-guile-TODO): Add option handling.
|
||||||
|
|
||||||
|
2002-04-07 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* summarize-guile-TODO: Add "Bugs" section to commentary.
|
||||||
|
Autoload (srfi srfi-13) on `string-tokenize'.
|
||||||
|
|
||||||
|
(as-leaf): New proc.
|
||||||
|
(hang-by-the-leaves): Use `as-leaf'.
|
||||||
|
(read-TODO-file): Expand regexp and specs
|
||||||
|
to handle "D", "X" and "N%". Fix regexp
|
||||||
|
to make isolating `who' easier.
|
||||||
|
(display-item): Handle "D", "X" and "N%".
|
||||||
|
|
||||||
|
2002-04-06 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* summarize-guile-TODO: New script.
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): Add "summarize-guile-TODO".
|
||||||
|
|
||||||
|
2002-04-05 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* read-text-outline (display-outline-tree): No longer export this proc.
|
||||||
|
|
||||||
|
(*depth-cue-rx*, *subm-number*, *level-divisor*, >>,
|
||||||
|
display-outline-tree): Delete these vars and procs.
|
||||||
|
|
||||||
|
(??, msub, ??-predicates, make-line-parser,
|
||||||
|
make-text-outline-reader): New procs.
|
||||||
|
|
||||||
|
(make-text-outline-reader): Export.
|
||||||
|
(read-text-outline-silently): Rewrite
|
||||||
|
using `make-text-outline-reader'.
|
||||||
|
|
||||||
|
2002-04-04 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* lint: New script.
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): Add "lint".
|
||||||
|
|
||||||
|
2002-04-02 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* PROGRAM: Update copyright; nfc.
|
||||||
|
|
||||||
|
* read-text-outline: New script.
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): Add "read-text-outline".
|
||||||
|
|
||||||
|
* read-text-outline (read-text-outline-silently):
|
||||||
|
Move `tp' inside `loop'; nfc.
|
||||||
|
|
||||||
|
2002-03-12 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* snarf-check-and-output-texi (snarf-check-and-output-texi): If
|
||||||
|
supplied, the `--manual' flag arrives as a string, not a symbol,
|
||||||
|
so test for it as such.
|
||||||
|
|
||||||
|
2002-03-03 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* snarf-guile-m4-docs (display-texi): Strip off `# ' from start of
|
||||||
|
docstring lines if possible, rather than just `#'.
|
||||||
|
|
||||||
|
2002-02-26 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* Makefile.am: Update path to pre-inst-guile automake frag.
|
||||||
|
|
||||||
|
2002-02-22 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* api-diff: New script.
|
||||||
|
|
||||||
|
2002-02-05 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* Include $(top_srcdir)/pre-inst-guile.am.
|
||||||
|
|
||||||
|
(overview): Use $(preinstguiletool).
|
||||||
|
|
||||||
|
2002-01-11 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): Add autofrisk.
|
||||||
|
|
||||||
|
* autofrisk: New script.
|
||||||
|
|
||||||
|
* frisk: Fix typo in commentary; nfc.
|
||||||
|
|
||||||
|
* use2dot: Autoload module (ice-9 getopt-long).
|
||||||
|
Use module (srfi srfi-13).
|
||||||
|
Export `use2dot'.
|
||||||
|
|
||||||
|
(string-append/separator, mapconcat): Delete.
|
||||||
|
(vv): Now take list of pairs, and return the mapping..
|
||||||
|
(>>header): Use `string-join'.
|
||||||
|
(>>): New proc.
|
||||||
|
(use2dot): Use `getopt-long'. Use `>>'.
|
||||||
|
|
||||||
|
2002-01-08 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): Add frisk.
|
||||||
|
(list): New target.
|
||||||
|
(overview): Also report module interfaces.
|
||||||
|
|
||||||
|
* use2dot: Rewrite using (scripts frisk).
|
||||||
|
|
||||||
|
* frisk: Initial revision.
|
||||||
|
|
||||||
|
2002-01-02 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* snarf-guile-m4-docs: New script.
|
||||||
|
|
||||||
|
2001-11-28 Thien-Thi Nguyen <ttn@giblet.glug.org>
|
||||||
|
|
||||||
|
* punify (write-punily): Handle symbols w/ ":" prefix specially.
|
||||||
|
|
||||||
|
* use2dot (ferret): New proc.
|
||||||
|
(grok): Use `ferret'.
|
||||||
|
|
||||||
|
2001-11-16 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* snarf-check-and-output-texi: Change generated @deffn categories
|
||||||
|
from "function" and "primitive" to "C Function" and "Scheme
|
||||||
|
Procedure".
|
||||||
|
(end-multiline): Take out @findex generation again; not needed
|
||||||
|
since index entries are implicit in @deffn forms.
|
||||||
|
|
||||||
|
These changes add a @deffnx C function declaration and function
|
||||||
|
index entries for each Guile primitive to the copy of the doc
|
||||||
|
snarf output that is used for reference manual synchronization.
|
||||||
|
Online help is unchanged.
|
||||||
|
|
||||||
|
* snarf-check-and-output-texi (*manual-flag*,
|
||||||
|
snarf-check-and-output-texi): Handle `--manual' invocation arg
|
||||||
|
passed through from libguile/Makefile.am.
|
||||||
|
(*c-function-name*, begin-multiline, do-command): Pick out C
|
||||||
|
function name from snarfed token stream.
|
||||||
|
(end-multiline): Add @deffnx C declaration and function index
|
||||||
|
entries to output.
|
||||||
|
(*primitive-deffnx-signature*, *primitive-deffnx-sig-length*):
|
||||||
|
Fluff to help insert the C declaration after any "@deffnx
|
||||||
|
primitive" lines in the snarfed docstring.
|
||||||
|
|
||||||
|
2001-10-05 Thien-Thi Nguyen <ttn@glug.org>
|
||||||
|
|
||||||
|
* read-scheme-source (quoted?, clump): New procs, exported.
|
||||||
|
|
||||||
|
2001-09-30 Thien-Thi Nguyen <ttn@glug.org>
|
||||||
|
|
||||||
|
* display-commentary (module-name->filename-frag,
|
||||||
|
display-module-commentary): New procs.
|
||||||
|
(display-commentary): Also handle refs that look like module
|
||||||
|
names.
|
||||||
|
|
||||||
|
2001-08-25 Marius Vollmer <mvo@zagadka.ping.de>
|
||||||
|
|
||||||
|
* Makefile.am (AUTOMAKE_OPTIONS): Change "foreign" to "gnu".
|
||||||
|
|
||||||
|
2001-08-07 Michael Livshin <mlivshin@bigfoot.com>
|
||||||
|
|
||||||
|
* snarf-check-and-output-texi: print optional args in a prettier
|
||||||
|
manner.
|
||||||
|
|
||||||
|
2001-08-01 Thien-Thi Nguyen <ttn@revel.glug.org>
|
||||||
|
|
||||||
|
* PROGRAM, README, display-commentary, doc-snarf,
|
||||||
|
generate-autoload, punify, read-scheme-source,
|
||||||
|
snarf-check-and-output-texi, use2dot:
|
||||||
|
In boilerplate, use -l$0.
|
||||||
|
Thanks to Daniel Skarda.
|
||||||
|
|
||||||
|
2001-07-22 Thien-Thi Nguyen <ttn@revel.glug.org>
|
||||||
|
|
||||||
|
* generate-autoload (autoload-info):
|
||||||
|
Also handle `defmacro-public' forms.
|
||||||
|
|
||||||
|
2001-07-14 Thien-Thi Nguyen <ttn@revel.glug.org>
|
||||||
|
|
||||||
|
* PROGRAM, display-commentary, doc-snarf, generate-autoload,
|
||||||
|
punify, read-scheme-source, snarf-check-and-output-texi, use2dot:
|
||||||
|
Re-add authorship info.
|
||||||
|
|
||||||
|
2001-07-12 Michael Livshin <mlivshin@bigfoot.com>
|
||||||
|
|
||||||
|
* snarf-check-and-output-texi (do-argpos): complain to the stderr,
|
||||||
|
not stdout. thanks to Dale P. Smith!
|
||||||
|
(nice-sig): cosmetic fix.
|
||||||
|
|
||||||
|
2001-07-09 Thien-Thi Nguyen <ttn@revel.glug.org>
|
||||||
|
|
||||||
|
* PROGRAM, generate-autoload, use2dot, punify, display-commentary,
|
||||||
|
doc-snarf, read-scheme-source, snarf-check-and-output-texi:
|
||||||
|
Remove authorship info.
|
||||||
|
|
||||||
|
2001-06-25 Michael Livshin <mlivshin@bigfoot.com>
|
||||||
|
|
||||||
|
* snarf-check-and-output-texi: rewrite.
|
||||||
|
|
||||||
|
2001-05-31 Michael Livshin <mlivshin@bigfoot.com>
|
||||||
|
|
||||||
|
* snarf-check-and-output-texi: new file.
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): add snarf-check-and-output-texi.
|
||||||
|
|
||||||
|
2001-05-14 Thien-Thi Nguyen <ttn@revel.glug.org>
|
||||||
|
|
||||||
|
* PROGRAM, display-commentary, doc-snarf, generate-autoload,
|
||||||
|
punify, read-scheme-source, use2dot: Move author tag outside
|
||||||
|
commentary; nfc.
|
||||||
|
|
||||||
|
2001-05-08 Thien-Thi Nguyen <ttn@revel.glug.org>
|
||||||
|
|
||||||
|
* read-scheme-source: New file
|
||||||
|
|
||||||
|
* Makefile.am (scripts_sources): Add read-scheme-source.
|
||||||
|
|
||||||
|
2001-04-29 Thien-Thi Nguyen <ttn@revel.glug.org>
|
||||||
|
|
||||||
|
* Makefile.am, PROGRAM, README, display-commentary,
|
||||||
|
doc-snarf, generate-autoload, punify, use2dot: New file
|
||||||
|
|
67
scripts/Makefile.am
Normal file
67
scripts/Makefile.am
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
## Process this file with automake to produce Makefile.in.
|
||||||
|
##
|
||||||
|
## Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
##
|
||||||
|
## This file is part of GUILE.
|
||||||
|
##
|
||||||
|
## GUILE 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, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## GUILE 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 GUILE; see the file COPYING. If not, write
|
||||||
|
## to the Free Software Foundation, Inc., 59 Temple Place, Suite
|
||||||
|
## 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
AUTOMAKE_OPTIONS = gnu
|
||||||
|
|
||||||
|
# These should be installed and distributed.
|
||||||
|
scripts_sources = \
|
||||||
|
PROGRAM \
|
||||||
|
autofrisk \
|
||||||
|
display-commentary \
|
||||||
|
doc-snarf \
|
||||||
|
frisk \
|
||||||
|
generate-autoload \
|
||||||
|
lint \
|
||||||
|
punify \
|
||||||
|
read-scheme-source \
|
||||||
|
read-text-outline \
|
||||||
|
use2dot \
|
||||||
|
snarf-check-and-output-texi \
|
||||||
|
summarize-guile-TODO \
|
||||||
|
scan-api \
|
||||||
|
api-diff \
|
||||||
|
read-rfc822
|
||||||
|
|
||||||
|
subpkgdatadir = $(pkgdatadir)/$(VERSION)/scripts
|
||||||
|
subpkgdata_SCRIPTS = $(scripts_sources)
|
||||||
|
|
||||||
|
EXTRA_DIST = $(scripts_sources)
|
||||||
|
|
||||||
|
list:
|
||||||
|
@echo $(scripts_sources)
|
||||||
|
|
||||||
|
include $(top_srcdir)/am/pre-inst-guile
|
||||||
|
|
||||||
|
overview: $(scripts_sources)
|
||||||
|
@echo '----------------------------'
|
||||||
|
@echo Overview
|
||||||
|
@echo I. Commentaries
|
||||||
|
@echo II. Module Interfaces
|
||||||
|
@echo '----------------------------'
|
||||||
|
@echo I. Commentaries
|
||||||
|
@echo '----------------------------'
|
||||||
|
$(preinstguiletool)/display-commentary $^
|
||||||
|
@echo '----------------------------'
|
||||||
|
@echo II. Module Interfaces
|
||||||
|
@echo '----------------------------'
|
||||||
|
$(preinstguiletool)/frisk $^
|
||||||
|
|
||||||
|
# Makefile.am ends here
|
45
scripts/PROGRAM
Executable file
45
scripts/PROGRAM
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts PROGRAM)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; PROGRAM --- Does something
|
||||||
|
|
||||||
|
;; Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: J.R.Hacker
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: PROGRAM [ARGS]
|
||||||
|
;;
|
||||||
|
;; PROGRAM does something.
|
||||||
|
;;
|
||||||
|
;; TODO: Write it!
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts PROGRAM)
|
||||||
|
:export (PROGRAM))
|
||||||
|
|
||||||
|
(define (PROGRAM . args)
|
||||||
|
#t)
|
||||||
|
|
||||||
|
(define main PROGRAM)
|
||||||
|
|
||||||
|
;;; PROGRAM ends here
|
76
scripts/README
Normal file
76
scripts/README
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
Overview and Usage
|
||||||
|
------------------
|
||||||
|
|
||||||
|
This directory contains Scheme programs, some useful in maintaining Guile.
|
||||||
|
On "make install", these programs are copied to PKGDATADIR/VERSION/scripts.
|
||||||
|
|
||||||
|
You can invoke a program from the shell, or alternatively, load its file
|
||||||
|
as a Guile Scheme module, and use its exported procedure(s) from Scheme code.
|
||||||
|
Typically for any PROGRAM:
|
||||||
|
|
||||||
|
(use-modules (scripts PROGRAM))
|
||||||
|
(PROGRAM ARG1 ARG2 ...)
|
||||||
|
|
||||||
|
For programs that write to stdout, you might try, instead:
|
||||||
|
|
||||||
|
(use-modules (scripts PROGRAM))
|
||||||
|
(with-output-to-string (lambda () (PROGRAM ARG1 ARG2 ...)))
|
||||||
|
|
||||||
|
Note that all args must be strings.
|
||||||
|
|
||||||
|
To see PROGRAM's commentary, which may or may not be helpful:
|
||||||
|
|
||||||
|
(help (scripts PROGRAM))
|
||||||
|
|
||||||
|
To see all commentaries and module dependencies, try: "make overview".
|
||||||
|
|
||||||
|
If you want to try the programs before installing Guile, you will probably
|
||||||
|
need to set environment variable GUILE_LOAD_PATH to be the parent directory.
|
||||||
|
This can be done in Bourne-compatible shells like so:
|
||||||
|
|
||||||
|
GUILE_LOAD_PATH=`(cd .. ; pwd)`
|
||||||
|
export GUILE_LOAD_PATH
|
||||||
|
|
||||||
|
[FIXME: Can someone supply the csh-compatible equivalent?]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
How to Contribute
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
See template file PROGRAM for a quick start.
|
||||||
|
|
||||||
|
Programs must follow the "executable module" convention, documented here:
|
||||||
|
|
||||||
|
- The file name must not end in ".scm".
|
||||||
|
|
||||||
|
- The file must be executable (chmod +x).
|
||||||
|
|
||||||
|
- The module name must be "(scripts PROGRAM)". A procedure named PROGRAM w/
|
||||||
|
signature "(PROGRAM . args)" must be exported. Basically, use some variant
|
||||||
|
of the form:
|
||||||
|
|
||||||
|
(define-module (scripts PROGRAM)
|
||||||
|
:export (PROGRAM))
|
||||||
|
|
||||||
|
Feel free to export other definitions useful in the module context.
|
||||||
|
|
||||||
|
- There must be the alias:
|
||||||
|
|
||||||
|
(define main PROGRAM)
|
||||||
|
|
||||||
|
However, `main' must NOT be exported.
|
||||||
|
|
||||||
|
- The beginning of the file must use the following invocation sequence:
|
||||||
|
|
||||||
|
#!/bin/sh
|
||||||
|
main='(module-ref (resolve-module '\''(scripts PROGRAM)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
|
||||||
|
Following these conventions allows the program file to be used as module
|
||||||
|
(scripts PROGRAM) in addition to as a standalone executable. Please also
|
||||||
|
include a helpful Commentary section w/ some usage info.
|
||||||
|
|
||||||
|
|
||||||
|
[README ends here]
|
181
scripts/api-diff
Executable file
181
scripts/api-diff
Executable file
|
@ -0,0 +1,181 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts api-diff)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; api-diff --- diff guile-api.alist files
|
||||||
|
|
||||||
|
;; Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen <ttn@gnu.org>
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: api-diff [-d GROUPS] ALIST-FILE-A ALIST-FILE-B
|
||||||
|
;;
|
||||||
|
;; Read in the alists from files ALIST-FILE-A and ALIST-FILE-B
|
||||||
|
;; and display a (count) summary of the groups defined therein.
|
||||||
|
;; Optional arg "--details" (or "-d") specifies a comma-separated
|
||||||
|
;; list of groups, in which case api-diff displays instead the
|
||||||
|
;; elements added and deleted for each of the specified groups.
|
||||||
|
;;
|
||||||
|
;; For scheme programming, this module exports the proc:
|
||||||
|
;; (api-diff A-file B-file)
|
||||||
|
;;
|
||||||
|
;; Note that the convention is that the "older" alist/file is
|
||||||
|
;; specified first.
|
||||||
|
;;
|
||||||
|
;; TODO: Develop scheme interface.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts api-diff)
|
||||||
|
:use-module (ice-9 common-list)
|
||||||
|
:use-module (ice-9 format)
|
||||||
|
:use-module (ice-9 getopt-long)
|
||||||
|
:autoload (srfi srfi-13) (string-tokenize)
|
||||||
|
:export (api-diff))
|
||||||
|
|
||||||
|
(define (read-alist-file file)
|
||||||
|
(with-input-from-file file
|
||||||
|
(lambda () (read))))
|
||||||
|
|
||||||
|
(define put set-object-property!)
|
||||||
|
(define get object-property)
|
||||||
|
|
||||||
|
(define (read-api-alist-file file)
|
||||||
|
(let* ((alist (read-alist-file file))
|
||||||
|
(meta (assq-ref alist 'meta))
|
||||||
|
(interface (assq-ref alist 'interface)))
|
||||||
|
(put interface 'meta meta)
|
||||||
|
(put interface 'groups (let ((ht (make-hash-table 31)))
|
||||||
|
(for-each (lambda (group)
|
||||||
|
(hashq-set! ht group '()))
|
||||||
|
(assq-ref meta 'groups))
|
||||||
|
ht))
|
||||||
|
interface))
|
||||||
|
|
||||||
|
(define (hang-by-the-roots interface)
|
||||||
|
(let ((ht (get interface 'groups)))
|
||||||
|
(for-each (lambda (x)
|
||||||
|
(for-each (lambda (group)
|
||||||
|
(hashq-set! ht group
|
||||||
|
(cons (car x)
|
||||||
|
(hashq-ref ht group))))
|
||||||
|
(assq-ref x 'groups)))
|
||||||
|
interface))
|
||||||
|
interface)
|
||||||
|
|
||||||
|
(define (diff? a b)
|
||||||
|
(let ((result (set-difference a b)))
|
||||||
|
(if (null? result)
|
||||||
|
#f ; CL weenies bite me
|
||||||
|
result)))
|
||||||
|
|
||||||
|
(define (diff+note! a b note-removals note-additions note-same)
|
||||||
|
(let ((same? #t))
|
||||||
|
(cond ((diff? a b) => (lambda (x) (note-removals x) (set! same? #f))))
|
||||||
|
(cond ((diff? b a) => (lambda (x) (note-additions x) (set! same? #f))))
|
||||||
|
(and same? (note-same))))
|
||||||
|
|
||||||
|
(define (group-diff i-old i-new . options)
|
||||||
|
(let* ((i-old (hang-by-the-roots i-old))
|
||||||
|
(g-old (hash-fold acons '() (get i-old 'groups)))
|
||||||
|
(g-old-names (map car g-old))
|
||||||
|
(i-new (hang-by-the-roots i-new))
|
||||||
|
(g-new (hash-fold acons '() (get i-new 'groups)))
|
||||||
|
(g-new-names (map car g-new)))
|
||||||
|
(cond ((null? options)
|
||||||
|
(diff+note! g-old-names g-new-names
|
||||||
|
(lambda (removals)
|
||||||
|
(format #t "groups-removed: ~A\n" removals))
|
||||||
|
(lambda (additions)
|
||||||
|
(format #t "groups-added: ~A\n" additions))
|
||||||
|
(lambda () #t))
|
||||||
|
(for-each (lambda (group)
|
||||||
|
(let* ((old (assq-ref g-old group))
|
||||||
|
(new (assq-ref g-new group))
|
||||||
|
(old-count (and old (length old)))
|
||||||
|
(new-count (and new (length new)))
|
||||||
|
(delta (and old new (- new-count old-count))))
|
||||||
|
(format #t " ~5@A ~5@A : "
|
||||||
|
(or old-count "-")
|
||||||
|
(or new-count "-"))
|
||||||
|
(cond ((and old new)
|
||||||
|
(let ((add-count 0) (sub-count 0))
|
||||||
|
(diff+note!
|
||||||
|
old new
|
||||||
|
(lambda (subs)
|
||||||
|
(set! sub-count (length subs)))
|
||||||
|
(lambda (adds)
|
||||||
|
(set! add-count (length adds)))
|
||||||
|
(lambda () #t))
|
||||||
|
(format #t "~5@D ~5@D : ~5@D"
|
||||||
|
add-count (- sub-count) delta)))
|
||||||
|
(else
|
||||||
|
(format #t "~5@A ~5@A : ~5@A" "-" "-" "-")))
|
||||||
|
(format #t " ~A\n" group)))
|
||||||
|
(sort (union g-old-names g-new-names)
|
||||||
|
(lambda (a b)
|
||||||
|
(string<? (symbol->string a)
|
||||||
|
(symbol->string b))))))
|
||||||
|
((assq-ref options 'details)
|
||||||
|
=> (lambda (groups)
|
||||||
|
(for-each (lambda (group)
|
||||||
|
(let* ((old (or (assq-ref g-old group) '()))
|
||||||
|
(new (or (assq-ref g-new group) '()))
|
||||||
|
(>>! (lambda (label ls)
|
||||||
|
(format #t "~A ~A:\n" group label)
|
||||||
|
(for-each (lambda (x)
|
||||||
|
(format #t " ~A\n" x))
|
||||||
|
ls))))
|
||||||
|
(diff+note! old new
|
||||||
|
(lambda (removals)
|
||||||
|
(>>! 'removals removals))
|
||||||
|
(lambda (additions)
|
||||||
|
(>>! 'additions additions))
|
||||||
|
(lambda ()
|
||||||
|
(format #t "~A: no changes\n"
|
||||||
|
group)))))
|
||||||
|
groups)))
|
||||||
|
(else
|
||||||
|
(error "api-diff: group-diff: bad options")))))
|
||||||
|
|
||||||
|
(define (api-diff . args)
|
||||||
|
(let* ((p (getopt-long (cons 'api-diff args)
|
||||||
|
'((details (single-char #\d)
|
||||||
|
(value #t))
|
||||||
|
;; Add options here.
|
||||||
|
)))
|
||||||
|
(rest (option-ref p '() '("/dev/null" "/dev/null")))
|
||||||
|
(i-old (read-api-alist-file (car rest)))
|
||||||
|
(i-new (read-api-alist-file (cadr rest)))
|
||||||
|
(options '()))
|
||||||
|
(cond ((option-ref p 'details #f)
|
||||||
|
=> (lambda (groups)
|
||||||
|
(set! options (cons (cons 'details
|
||||||
|
(map string->symbol
|
||||||
|
(string-tokenize
|
||||||
|
groups
|
||||||
|
#\,)))
|
||||||
|
options)))))
|
||||||
|
(apply group-diff i-old i-new options)))
|
||||||
|
|
||||||
|
(define main api-diff)
|
||||||
|
|
||||||
|
;;; api-diff ends here
|
221
scripts/autofrisk
Executable file
221
scripts/autofrisk
Executable file
|
@ -0,0 +1,221 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts autofrisk)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; autofrisk --- Generate module checks for use with auto* tools
|
||||||
|
|
||||||
|
;; Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen <ttn@gnu.org>
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: autofrisk [file]
|
||||||
|
;;
|
||||||
|
;; This program looks for the file modules.af in the current directory
|
||||||
|
;; and writes out modules.af.m4 containing autoconf definitions.
|
||||||
|
;; If given, look for FILE instead of modules.af and output to FILE.m4.
|
||||||
|
;;
|
||||||
|
;; After running autofrisk, you should add to configure.ac the lines:
|
||||||
|
;; AUTOFRISK_CHECKS
|
||||||
|
;; AUTOFRISK_SUMMARY
|
||||||
|
;; Then run "aclocal -I ." to update aclocal.m4, and finally autoconf.
|
||||||
|
;;
|
||||||
|
;; The modules.af file consists of a series of configuration forms (Scheme
|
||||||
|
;; lists), which have one of the following formats:
|
||||||
|
;; (files-glob PATTERN ...)
|
||||||
|
;; (non-critical-external MODULE ...)
|
||||||
|
;; (non-critical-internal MODULE ...)
|
||||||
|
;; (programs (MODULE PROG ...) ...)
|
||||||
|
;; (pww-varname VARNAME)
|
||||||
|
;; PATTERN is a string that may contain "*" and "?" characters to be
|
||||||
|
;; expanded into filenames. MODULE is a list of symbols naming a
|
||||||
|
;; module, such as `(srfi srfi-1)'. VARNAME is a shell-safe name to use
|
||||||
|
;; instead of "probably_wont_work", the default. This var is passed to
|
||||||
|
;; `AC_SUBST'. PROG is a string.
|
||||||
|
;;
|
||||||
|
;; Only the `files-glob' form is required.
|
||||||
|
;;
|
||||||
|
;; TODO: Write better commentary.
|
||||||
|
;; Make "please see README" configurable.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts autofrisk)
|
||||||
|
:autoload (ice-9 popen) (open-input-pipe)
|
||||||
|
:use-module (srfi srfi-1)
|
||||||
|
:use-module (srfi srfi-8)
|
||||||
|
:use-module (srfi srfi-13)
|
||||||
|
:use-module (srfi srfi-14)
|
||||||
|
:use-module (scripts read-scheme-source)
|
||||||
|
:use-module (scripts frisk)
|
||||||
|
:export (autofrisk))
|
||||||
|
|
||||||
|
(define *recognized-keys* '(files-glob
|
||||||
|
non-critical-external
|
||||||
|
non-critical-internal
|
||||||
|
programs
|
||||||
|
pww-varname))
|
||||||
|
|
||||||
|
(define (canonical-configuration forms)
|
||||||
|
(let ((chk (lambda (condition . x)
|
||||||
|
(or condition (apply error "syntax error:" x)))))
|
||||||
|
(chk (list? forms) "input not a list")
|
||||||
|
(chk (every list? forms) "non-list element")
|
||||||
|
(chk (every (lambda (form) (< 1 (length form))) forms) "list too short")
|
||||||
|
(let ((un #f))
|
||||||
|
(chk (every (lambda (form)
|
||||||
|
(let ((key (car form)))
|
||||||
|
(and (symbol? key)
|
||||||
|
(or (eq? 'quote key)
|
||||||
|
(memq key *recognized-keys*)
|
||||||
|
(begin
|
||||||
|
(set! un key)
|
||||||
|
#f)))))
|
||||||
|
forms)
|
||||||
|
"unrecognized key:" un))
|
||||||
|
(let ((bunched (map (lambda (key)
|
||||||
|
(fold (lambda (form so-far)
|
||||||
|
(or (and (eq? (car form) key)
|
||||||
|
(cdr form)
|
||||||
|
(append so-far (cdr form)))
|
||||||
|
so-far))
|
||||||
|
(list key)
|
||||||
|
forms))
|
||||||
|
*recognized-keys*)))
|
||||||
|
(lambda (key)
|
||||||
|
(assq-ref bunched key)))))
|
||||||
|
|
||||||
|
(define (>>strong modules)
|
||||||
|
(for-each (lambda (module)
|
||||||
|
(format #t "GUILE_MODULE_REQUIRED~A\n" module))
|
||||||
|
modules))
|
||||||
|
|
||||||
|
(define (safe-name module)
|
||||||
|
(let ((var (object->string module)))
|
||||||
|
(string-map! (lambda (c)
|
||||||
|
(if (char-set-contains? char-set:letter+digit c)
|
||||||
|
c
|
||||||
|
#\_))
|
||||||
|
var)
|
||||||
|
var))
|
||||||
|
|
||||||
|
(define *pww* "probably_wont_work")
|
||||||
|
|
||||||
|
(define (>>weak weak-edges)
|
||||||
|
(for-each (lambda (edge)
|
||||||
|
(let* ((up (edge-up edge))
|
||||||
|
(down (edge-down edge))
|
||||||
|
(var (format #f "have_guile_module~A" (safe-name up))))
|
||||||
|
(format #t "GUILE_MODULE_AVAILABLE(~A, ~A)\n" var up)
|
||||||
|
(format #t "test \"$~A\" = no &&\n ~A=\"~A $~A\"~A"
|
||||||
|
var *pww* down *pww* "\n\n")))
|
||||||
|
weak-edges))
|
||||||
|
|
||||||
|
(define (>>program module progs)
|
||||||
|
(let ((vars (map (lambda (prog)
|
||||||
|
(format #f "guile_module~Asupport_~A"
|
||||||
|
(safe-name module)
|
||||||
|
prog))
|
||||||
|
progs)))
|
||||||
|
(for-each (lambda (var prog)
|
||||||
|
(format #t "AC_PATH_PROG(~A, ~A)\n" var prog))
|
||||||
|
vars progs)
|
||||||
|
(format #t "test \\\n")
|
||||||
|
(for-each (lambda (var)
|
||||||
|
(format #t " \"$~A\" = \"\" -o \\\n" var))
|
||||||
|
vars)
|
||||||
|
(format #t "~A &&\n~A=\"~A $~A\"\n\n"
|
||||||
|
(list-ref (list "war = peace"
|
||||||
|
"freedom = slavery"
|
||||||
|
"ignorance = strength")
|
||||||
|
(random 3))
|
||||||
|
*pww* module *pww*)))
|
||||||
|
|
||||||
|
(define (>>programs programs)
|
||||||
|
(for-each (lambda (form)
|
||||||
|
(>>program (car form) (cdr form)))
|
||||||
|
programs))
|
||||||
|
|
||||||
|
(define (unglob pattern)
|
||||||
|
(let ((p (open-input-pipe (format #f "echo '(' ~A ')'" pattern))))
|
||||||
|
(map symbol->string (read p))))
|
||||||
|
|
||||||
|
(define (>>checks forms)
|
||||||
|
(let* ((cfg (canonical-configuration forms))
|
||||||
|
(files (apply append (map unglob (cfg 'files-glob))))
|
||||||
|
(ncx (cfg 'non-critical-external))
|
||||||
|
(nci (cfg 'non-critical-internal))
|
||||||
|
(prog (cfg 'non-critical))
|
||||||
|
(report ((make-frisker) files))
|
||||||
|
(external (report 'external)))
|
||||||
|
(let ((pww-varname (cfg 'pww-varname)))
|
||||||
|
(or (null? pww-varname) (set! *pww* (car pww-varname))))
|
||||||
|
(receive (weak strong)
|
||||||
|
(partition (lambda (module)
|
||||||
|
(or (member module ncx)
|
||||||
|
(every (lambda (i)
|
||||||
|
(member i nci))
|
||||||
|
(map edge-down (mod-down-ls module)))))
|
||||||
|
external)
|
||||||
|
(format #t "AC_DEFUN([AUTOFRISK_CHECKS],[\n\n")
|
||||||
|
(>>strong strong)
|
||||||
|
(format #t "\n~A=~S\n\n" *pww* "")
|
||||||
|
(>>weak (fold (lambda (module so-far)
|
||||||
|
(append so-far (mod-down-ls module)))
|
||||||
|
(list)
|
||||||
|
weak))
|
||||||
|
(>>programs (cfg 'programs))
|
||||||
|
(format #t "AC_SUBST(~A)\n])\n\n" *pww*))))
|
||||||
|
|
||||||
|
(define (>>summary)
|
||||||
|
(format #t
|
||||||
|
(symbol->string
|
||||||
|
'#{
|
||||||
|
AC_DEFUN([AUTOFRISK_SUMMARY],[
|
||||||
|
if test ! "$~A" = "" ; then
|
||||||
|
p=" ***"
|
||||||
|
echo "$p"
|
||||||
|
echo "$p NOTE:"
|
||||||
|
echo "$p The following modules probably won't work:"
|
||||||
|
echo "$p $~A"
|
||||||
|
echo "$p They can be installed anyway, and will work if their"
|
||||||
|
echo "$p dependencies are installed later. Please see README."
|
||||||
|
echo "$p"
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
}#)
|
||||||
|
*pww* *pww*))
|
||||||
|
|
||||||
|
(define (autofrisk . args)
|
||||||
|
(let ((file (if (null? args) "modules.af" (car args))))
|
||||||
|
(or (file-exists? file)
|
||||||
|
(error "could not find input file:" file))
|
||||||
|
(with-output-to-file (format #f "~A.m4" file)
|
||||||
|
(lambda ()
|
||||||
|
(>>checks (read-scheme-source-silently file))
|
||||||
|
(>>summary)))))
|
||||||
|
|
||||||
|
(define main autofrisk)
|
||||||
|
|
||||||
|
;; Local variables:
|
||||||
|
;; eval: (put 'receive 'scheme-indent-function 2)
|
||||||
|
;; End:
|
||||||
|
|
||||||
|
;;; autofrisk ends here
|
70
scripts/display-commentary
Executable file
70
scripts/display-commentary
Executable file
|
@ -0,0 +1,70 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts display-commentary)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; display-commentary --- As advertized
|
||||||
|
|
||||||
|
;; Copyright (C) 2001 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: display-commentary REF1 REF2 ...
|
||||||
|
;;
|
||||||
|
;; Display Commentary section from REF1, REF2 and so on.
|
||||||
|
;; Each REF may be a filename or module name (list of symbols).
|
||||||
|
;; In the latter case, a filename is computed by searching `%load-path'.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts display-commentary)
|
||||||
|
:use-module (ice-9 documentation)
|
||||||
|
:export (display-commentary))
|
||||||
|
|
||||||
|
(define (display-commentary-one file)
|
||||||
|
(format #t "~A commentary:\n~A" file (file-commentary file)))
|
||||||
|
|
||||||
|
(define (module-name->filename-frag ls) ; todo: export or move
|
||||||
|
(let ((ls (map symbol->string ls)))
|
||||||
|
(let loop ((ls (cdr ls)) (acc (car ls)))
|
||||||
|
(if (null? ls)
|
||||||
|
acc
|
||||||
|
(loop (cdr ls) (string-append acc "/" (car ls)))))))
|
||||||
|
|
||||||
|
(define (display-module-commentary module-name)
|
||||||
|
(cond ((%search-load-path (module-name->filename-frag module-name))
|
||||||
|
=> (lambda (file)
|
||||||
|
(format #t "module ~A\n" module-name)
|
||||||
|
(display-commentary-one file)))))
|
||||||
|
|
||||||
|
(define (display-commentary . refs)
|
||||||
|
(for-each (lambda (ref)
|
||||||
|
(cond ((string? ref)
|
||||||
|
(if (equal? 0 (string-index ref #\())
|
||||||
|
(display-module-commentary
|
||||||
|
(with-input-from-string ref read))
|
||||||
|
(display-commentary-one ref)))
|
||||||
|
((list? ref)
|
||||||
|
(display-module-commentary ref))))
|
||||||
|
refs))
|
||||||
|
|
||||||
|
(define main display-commentary)
|
||||||
|
|
||||||
|
;;; display-commentary ends here
|
442
scripts/doc-snarf
Executable file
442
scripts/doc-snarf
Executable file
|
@ -0,0 +1,442 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts doc-snarf)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; doc-snarf --- Extract documentation from source files
|
||||||
|
|
||||||
|
;; Copyright (C) 2001 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Martin Grabmueller
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: doc-snarf FILE
|
||||||
|
;;
|
||||||
|
;; This program reads in a Scheme source file and extracts docstrings
|
||||||
|
;; in the format specified below. Additionally, a procedure protoype
|
||||||
|
;; is infered from the procedure definition line starting with
|
||||||
|
;; (define... ).
|
||||||
|
;;
|
||||||
|
;; Currently, two output modi are implemented: texinfo and plaintext.
|
||||||
|
;; Default is plaintext, texinfo can be switched on with the
|
||||||
|
;; `--texinfo, -t' command line option.
|
||||||
|
;;
|
||||||
|
;; Format: A docstring can span multiple lines and a docstring line
|
||||||
|
;; begins with `;; ' (two semicoli and a space). A docstring is ended
|
||||||
|
;; by either a line beginning with (define ...) or one or more lines
|
||||||
|
;; beginning with `;;-' (two semicoli and a dash). These lines are
|
||||||
|
;; called `options' and begin with a keyword, followed by a colon and
|
||||||
|
;; a string.
|
||||||
|
;;
|
||||||
|
;; Additionally, "standard internal docstrings" (for Scheme source) are
|
||||||
|
;; recognized and output as "options". The output formatting is likely
|
||||||
|
;; to change in the future.
|
||||||
|
;;
|
||||||
|
;; Example:
|
||||||
|
|
||||||
|
;; This procedure foos, or bars, depending on the argument @var{braz}.
|
||||||
|
;;-Author: Martin Grabmueller
|
||||||
|
(define (foo/bar braz)
|
||||||
|
(if braz 'foo 'bar))
|
||||||
|
|
||||||
|
;;; Which results in the following docstring if texinfo output is
|
||||||
|
;;; enabled:
|
||||||
|
#!
|
||||||
|
foo/bar
|
||||||
|
@deffn procedure foo/bar braz
|
||||||
|
This procedure foos, or bars, depending on the argument @var{braz}.
|
||||||
|
@c Author: Martin Grabmueller
|
||||||
|
@end deffn
|
||||||
|
!#
|
||||||
|
|
||||||
|
;;; Or in this if plaintext output is used:
|
||||||
|
#!
|
||||||
|
Procedure: foo/bar braz
|
||||||
|
This procedure foos, or bars, depending on the argument @var{braz}.
|
||||||
|
;; Author: Martin Grabmueller
|
||||||
|
^L
|
||||||
|
!#
|
||||||
|
|
||||||
|
;; TODO: Convert option lines to alist.
|
||||||
|
;; More parameterization.
|
||||||
|
;; ../libguile/guile-doc-snarf emulation
|
||||||
|
|
||||||
|
(define doc-snarf-version "0.0.2") ; please update before publishing!
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts doc-snarf)
|
||||||
|
:use-module (ice-9 getopt-long)
|
||||||
|
:use-module (ice-9 regex)
|
||||||
|
:use-module (ice-9 string-fun)
|
||||||
|
:use-module (ice-9 rdelim)
|
||||||
|
:export (doc-snarf))
|
||||||
|
|
||||||
|
(define command-synopsis
|
||||||
|
'((version (single-char #\v) (value #f))
|
||||||
|
(help (single-char #\h) (value #f))
|
||||||
|
(output (single-char #\o) (value #t))
|
||||||
|
(texinfo (single-char #\t) (value #f))
|
||||||
|
(lang (single-char #\l) (value #t))))
|
||||||
|
|
||||||
|
;; Display version information and exit.
|
||||||
|
;;-ttn-mod: use var
|
||||||
|
(define (display-version)
|
||||||
|
(display "doc-snarf ") (display doc-snarf-version) (newline))
|
||||||
|
|
||||||
|
;; Display the usage help message and exit.
|
||||||
|
;;-ttn-mod: change option "source" to "lang"
|
||||||
|
(define (display-help)
|
||||||
|
(display "Usage: doc-snarf [options...] inputfile\n")
|
||||||
|
(display " --help, -h Show this usage information\n")
|
||||||
|
(display " --version, -v Show version information\n")
|
||||||
|
(display
|
||||||
|
" --output=FILE, -o Specify output file [default=stdout]\n")
|
||||||
|
(display " --texinfo, -t Format output as texinfo\n")
|
||||||
|
(display " --lang=[c,scheme], -l Specify the input language\n"))
|
||||||
|
|
||||||
|
;; Main program.
|
||||||
|
;;-ttn-mod: canonicalize lang
|
||||||
|
(define (doc-snarf . args)
|
||||||
|
(let ((options (getopt-long (cons "doc-snarf" args) command-synopsis)))
|
||||||
|
(let ((help-wanted (option-ref options 'help #f))
|
||||||
|
(version-wanted (option-ref options 'version #f))
|
||||||
|
(texinfo-wanted (option-ref options 'texinfo #f))
|
||||||
|
(lang (string->symbol
|
||||||
|
(string-downcase (option-ref options 'lang "scheme")))))
|
||||||
|
(cond
|
||||||
|
(version-wanted (display-version))
|
||||||
|
(help-wanted (display-help))
|
||||||
|
(else
|
||||||
|
(let ((input (option-ref options '() #f))
|
||||||
|
(output (option-ref options 'output #f)))
|
||||||
|
(if
|
||||||
|
;; Bonard B. Timmons III says `(pair? input)' alone is sufficient.
|
||||||
|
;; (and input (pair? input))
|
||||||
|
(pair? input)
|
||||||
|
(snarf-file (car input) output texinfo-wanted lang)
|
||||||
|
(display-help))))))))
|
||||||
|
|
||||||
|
(define main doc-snarf)
|
||||||
|
|
||||||
|
;; Supported languages and their parameters. Each element has form:
|
||||||
|
;; (LANG DOC-START DOC-END DOC-PREFIX OPT-PREFIX SIG-START STD-INT-DOC?)
|
||||||
|
;; LANG is a symbol, STD-INT-DOC? is a boolean indicating whether or not
|
||||||
|
;; LANG supports "standard internal docstring" (a string after the formals),
|
||||||
|
;; everything else is a string specifying a regexp.
|
||||||
|
;;-ttn-mod: new var
|
||||||
|
(define supported-languages
|
||||||
|
'((c
|
||||||
|
"^/\\*(.*)"
|
||||||
|
"^ \\*/"
|
||||||
|
"^ \\* (.*)"
|
||||||
|
"^ \\*-(.*)"
|
||||||
|
"NOTHING AT THIS TIME!!!"
|
||||||
|
#f
|
||||||
|
)
|
||||||
|
(scheme
|
||||||
|
"^;; (.*)"
|
||||||
|
"^;;\\."
|
||||||
|
"^;; (.*)"
|
||||||
|
"^;;-(.*)"
|
||||||
|
"^\\(define"
|
||||||
|
#t
|
||||||
|
)))
|
||||||
|
|
||||||
|
;; Get @var{lang}'s @var{parameter}. Both args are symbols.
|
||||||
|
;;-ttn-mod: new proc
|
||||||
|
(define (lang-parm lang parm)
|
||||||
|
(list-ref (assq-ref supported-languages lang)
|
||||||
|
(case parm
|
||||||
|
((docstring-start) 0)
|
||||||
|
((docstring-end) 1)
|
||||||
|
((docstring-prefix) 2)
|
||||||
|
((option-prefix) 3)
|
||||||
|
((signature-start) 4)
|
||||||
|
((std-int-doc?) 5))))
|
||||||
|
|
||||||
|
;; Snarf all docstrings from the file @var{input} and write them to
|
||||||
|
;; file @var{output}. Use texinfo format for the output if
|
||||||
|
;; @var{texinfo?} is true.
|
||||||
|
;;-ttn-mod: don't use string comparison, consult table instead
|
||||||
|
(define (snarf-file input output texinfo? lang)
|
||||||
|
(or (memq lang (map car supported-languages))
|
||||||
|
(error "doc-snarf: input language must be c or scheme."))
|
||||||
|
(write-output (snarf input lang) output
|
||||||
|
(if texinfo? format-texinfo format-plain)))
|
||||||
|
|
||||||
|
;; fixme: this comment is required to trigger standard internal
|
||||||
|
;; docstring snarfing... ideally, it wouldn't be necessary.
|
||||||
|
;;-ttn-mod: new proc, from snarf-docs (aren't these names fun?)
|
||||||
|
(define (find-std-int-doc line input-port)
|
||||||
|
"Unread @var{line} from @var{input-port}, then read in the entire form and
|
||||||
|
return the standard internal docstring if found. Return #f if not."
|
||||||
|
(unread-string line input-port) ; ugh
|
||||||
|
(let ((form (read input-port)))
|
||||||
|
(cond ((and (list? form) ; (define (PROC ARGS) "DOC" ...)
|
||||||
|
(< 3 (length form))
|
||||||
|
(eq? 'define (car form))
|
||||||
|
(pair? (cadr form))
|
||||||
|
(symbol? (caadr form))
|
||||||
|
(string? (caddr form)))
|
||||||
|
(caddr form))
|
||||||
|
((and (list? form) ; (define VAR (lambda ARGS "DOC" ...))
|
||||||
|
(< 2 (length form))
|
||||||
|
(eq? 'define (car form))
|
||||||
|
(symbol? (cadr form))
|
||||||
|
(list? (caddr form))
|
||||||
|
(< 3 (length (caddr form)))
|
||||||
|
(eq? 'lambda (car (caddr form)))
|
||||||
|
(string? (caddr (caddr form))))
|
||||||
|
(caddr (caddr form)))
|
||||||
|
(else #f))))
|
||||||
|
|
||||||
|
;; Split @var{string} into lines, adding @var{prefix} to each.
|
||||||
|
;;-ttn-mod: new proc
|
||||||
|
(define (split-prefixed string prefix)
|
||||||
|
(separate-fields-discarding-char
|
||||||
|
#\newline string
|
||||||
|
(lambda lines
|
||||||
|
(map (lambda (line)
|
||||||
|
(string-append prefix line))
|
||||||
|
lines))))
|
||||||
|
|
||||||
|
;; snarf input-file output-file
|
||||||
|
;; Extract docstrings from the input file @var{input}, presumed
|
||||||
|
;; to be written in language @var{lang}.
|
||||||
|
;;-Author: Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
|
||||||
|
;;-Created: 2001-02-17
|
||||||
|
;;-ttn-mod: regluarize lang parm lookup, add "std int doc" snarfing (2 places)
|
||||||
|
(define (snarf input-file lang)
|
||||||
|
(let* ((i-p (open-input-file input-file))
|
||||||
|
(parm-regexp (lambda (parm) (make-regexp (lang-parm lang parm))))
|
||||||
|
(docstring-start (parm-regexp 'docstring-start))
|
||||||
|
(docstring-end (parm-regexp 'docstring-end))
|
||||||
|
(docstring-prefix (parm-regexp 'docstring-prefix))
|
||||||
|
(option-prefix (parm-regexp 'option-prefix))
|
||||||
|
(signature-start (parm-regexp 'signature-start))
|
||||||
|
(augmented-options
|
||||||
|
(lambda (line i-p options)
|
||||||
|
(let ((int-doc (and (lang-parm lang 'std-int-doc?)
|
||||||
|
(let ((d (find-std-int-doc line i-p)))
|
||||||
|
(and d (split-prefixed d "internal: "))))))
|
||||||
|
(if int-doc
|
||||||
|
(append (reverse int-doc) options)
|
||||||
|
options)))))
|
||||||
|
|
||||||
|
(let lp ((line (read-line i-p)) (state 'neutral) (doc-strings '())
|
||||||
|
(options '()) (entries '()) (lno 0))
|
||||||
|
(cond
|
||||||
|
((eof-object? line)
|
||||||
|
(close-input-port i-p)
|
||||||
|
(reverse entries))
|
||||||
|
|
||||||
|
;; State 'neutral: we're currently not within a docstring or
|
||||||
|
;; option section
|
||||||
|
((eq? state 'neutral)
|
||||||
|
(let ((m (regexp-exec docstring-start line)))
|
||||||
|
(if m
|
||||||
|
(lp (read-line i-p) 'doc-string
|
||||||
|
(list (match:substring m 1)) '() entries (+ lno 1))
|
||||||
|
(lp (read-line i-p) state '() '() entries (+ lno 1)))))
|
||||||
|
|
||||||
|
;; State 'doc-string: we have started reading a docstring and
|
||||||
|
;; are waiting for more, for options or for a define.
|
||||||
|
((eq? state 'doc-string)
|
||||||
|
(let ((m0 (regexp-exec docstring-prefix line))
|
||||||
|
(m1 (regexp-exec option-prefix line))
|
||||||
|
(m2 (regexp-exec signature-start line))
|
||||||
|
(m3 (regexp-exec docstring-end line)))
|
||||||
|
(cond
|
||||||
|
(m0
|
||||||
|
(lp (read-line i-p) 'doc-string
|
||||||
|
(cons (match:substring m0 1) doc-strings) '() entries
|
||||||
|
(+ lno 1)))
|
||||||
|
(m1
|
||||||
|
(lp (read-line i-p) 'options
|
||||||
|
doc-strings (cons (match:substring m1 1) options) entries
|
||||||
|
(+ lno 1)))
|
||||||
|
(m2
|
||||||
|
(let ((options (augmented-options line i-p options))) ; ttn-mod
|
||||||
|
(lp (read-line i-p) 'neutral '() '()
|
||||||
|
(cons (parse-entry doc-strings options line input-file lno)
|
||||||
|
entries)
|
||||||
|
(+ lno 1))))
|
||||||
|
(m3
|
||||||
|
(lp (read-line i-p) 'neutral '() '()
|
||||||
|
(cons (parse-entry doc-strings options #f input-file lno)
|
||||||
|
entries)
|
||||||
|
(+ lno 1)))
|
||||||
|
(else
|
||||||
|
(lp (read-line i-p) 'neutral '() '() entries (+ lno 1))))))
|
||||||
|
|
||||||
|
;; State 'options: We're waiting for more options or for a
|
||||||
|
;; define.
|
||||||
|
((eq? state 'options)
|
||||||
|
(let ((m1 (regexp-exec option-prefix line))
|
||||||
|
(m2 (regexp-exec signature-start line))
|
||||||
|
(m3 (regexp-exec docstring-end line)))
|
||||||
|
(cond
|
||||||
|
(m1
|
||||||
|
(lp (read-line i-p) 'options
|
||||||
|
doc-strings (cons (match:substring m1 1) options) entries
|
||||||
|
(+ lno 1)))
|
||||||
|
(m2
|
||||||
|
(let ((options (augmented-options line i-p options))) ; ttn-mod
|
||||||
|
(lp (read-line i-p) 'neutral '() '()
|
||||||
|
(cons (parse-entry doc-strings options line input-file lno)
|
||||||
|
entries)
|
||||||
|
(+ lno 1))))
|
||||||
|
(m3
|
||||||
|
(lp (read-line i-p) 'neutral '() '()
|
||||||
|
(cons (parse-entry doc-strings options #f input-file lno)
|
||||||
|
entries)
|
||||||
|
(+ lno 1)))
|
||||||
|
(else
|
||||||
|
(lp (read-line i-p) 'neutral '() '() entries (+ lno 1))))))))))
|
||||||
|
|
||||||
|
(define (make-entry symbol signature docstrings options filename line)
|
||||||
|
(vector 'entry symbol signature docstrings options filename line))
|
||||||
|
(define (entry-symbol e)
|
||||||
|
(vector-ref e 1))
|
||||||
|
(define (entry-signature e)
|
||||||
|
(vector-ref e 2))
|
||||||
|
(define (entry-docstrings e)
|
||||||
|
(vector-ref e 3))
|
||||||
|
(define (entry-options e)
|
||||||
|
(vector-ref e 4))
|
||||||
|
(define (entry-filename e)
|
||||||
|
(vector-ref e 5))
|
||||||
|
(define (entry-line e)
|
||||||
|
"This docstring will not be snarfed, unfortunately..."
|
||||||
|
(vector-ref e 6))
|
||||||
|
|
||||||
|
;; Create a docstring entry from the docstring line list
|
||||||
|
;; @var{doc-strings}, the option line list @var{options} and the
|
||||||
|
;; define line @var{def-line}
|
||||||
|
(define (parse-entry docstrings options def-line filename line-no)
|
||||||
|
; (write-line docstrings)
|
||||||
|
(cond
|
||||||
|
(def-line
|
||||||
|
(make-entry (get-symbol def-line)
|
||||||
|
(make-prototype def-line) (reverse docstrings)
|
||||||
|
(reverse options) filename
|
||||||
|
(+ (- line-no (length docstrings) (length options)) 1)))
|
||||||
|
((> (length docstrings) 0)
|
||||||
|
(make-entry (string->symbol (car (reverse docstrings)))
|
||||||
|
(car (reverse docstrings))
|
||||||
|
(cdr (reverse docstrings))
|
||||||
|
(reverse options) filename
|
||||||
|
(+ (- line-no (length docstrings) (length options)) 1)))
|
||||||
|
(else
|
||||||
|
(make-entry 'foo "" (reverse docstrings) (reverse options) filename
|
||||||
|
(+ (- line-no (length docstrings) (length options)) 1)))))
|
||||||
|
|
||||||
|
;; Create a string which is a procedure prototype. The necessary
|
||||||
|
;; information for constructing the prototype is taken from the line
|
||||||
|
;; @var{def-line}, which is a line starting with @code{(define...}.
|
||||||
|
(define (make-prototype def-line)
|
||||||
|
(call-with-input-string
|
||||||
|
def-line
|
||||||
|
(lambda (s-p)
|
||||||
|
(let* ((paren (read-char s-p))
|
||||||
|
(keyword (read s-p))
|
||||||
|
(tmp (read s-p)))
|
||||||
|
(cond
|
||||||
|
((pair? tmp)
|
||||||
|
(join-symbols tmp))
|
||||||
|
((symbol? tmp)
|
||||||
|
(symbol->string tmp))
|
||||||
|
(else
|
||||||
|
""))))))
|
||||||
|
|
||||||
|
(define (get-symbol def-line)
|
||||||
|
(call-with-input-string
|
||||||
|
def-line
|
||||||
|
(lambda (s-p)
|
||||||
|
(let* ((paren (read-char s-p))
|
||||||
|
(keyword (read s-p))
|
||||||
|
(tmp (read s-p)))
|
||||||
|
(cond
|
||||||
|
((pair? tmp)
|
||||||
|
(car tmp))
|
||||||
|
((symbol? tmp)
|
||||||
|
tmp)
|
||||||
|
(else
|
||||||
|
'foo))))))
|
||||||
|
|
||||||
|
;; Append the symbols in the string list @var{s}, separated with a
|
||||||
|
;; space character.
|
||||||
|
(define (join-symbols s)
|
||||||
|
(cond ((null? s)
|
||||||
|
"")
|
||||||
|
((symbol? s)
|
||||||
|
(string-append ". " (symbol->string s)))
|
||||||
|
((null? (cdr s))
|
||||||
|
(symbol->string (car s)))
|
||||||
|
(else
|
||||||
|
(string-append (symbol->string (car s)) " " (join-symbols (cdr s))))))
|
||||||
|
|
||||||
|
;; Write @var{entries} to @var{output-file} using @var{writer}.
|
||||||
|
;; @var{writer} is a proc that takes one entry.
|
||||||
|
;; If @var{output-file} is #f, write to stdout.
|
||||||
|
;;-ttn-mod: new proc
|
||||||
|
(define (write-output entries output-file writer)
|
||||||
|
(with-output-to-port (cond (output-file (open-output-file output-file))
|
||||||
|
(else (current-output-port)))
|
||||||
|
(lambda () (for-each writer entries))))
|
||||||
|
|
||||||
|
;; Write an @var{entry} using texinfo format.
|
||||||
|
;;-ttn-mod: renamed from `texinfo-output', distilled
|
||||||
|
(define (format-texinfo entry)
|
||||||
|
(display "\n\f")
|
||||||
|
(display (entry-symbol entry))
|
||||||
|
(newline)
|
||||||
|
(display "@c snarfed from ")
|
||||||
|
(display (entry-filename entry))
|
||||||
|
(display ":")
|
||||||
|
(display (entry-line entry))
|
||||||
|
(newline)
|
||||||
|
(display "@deffn procedure ")
|
||||||
|
(display (entry-signature entry))
|
||||||
|
(newline)
|
||||||
|
(for-each (lambda (s) (write-line s))
|
||||||
|
(entry-docstrings entry))
|
||||||
|
(for-each (lambda (s) (display "@c ") (write-line s))
|
||||||
|
(entry-options entry))
|
||||||
|
(write-line "@end deffn"))
|
||||||
|
|
||||||
|
;; Write an @var{entry} using plain format.
|
||||||
|
;;-ttn-mod: renamed from `texinfo-output', distilled
|
||||||
|
(define (format-plain entry)
|
||||||
|
(display "Procedure: ")
|
||||||
|
(display (entry-signature entry))
|
||||||
|
(newline)
|
||||||
|
(for-each (lambda (s) (write-line s))
|
||||||
|
(entry-docstrings entry))
|
||||||
|
(for-each (lambda (s) (display ";; ") (write-line s))
|
||||||
|
(entry-options entry))
|
||||||
|
(display "Snarfed from ")
|
||||||
|
(display (entry-filename entry))
|
||||||
|
(display ":")
|
||||||
|
(display (entry-line entry))
|
||||||
|
(newline)
|
||||||
|
(write-line "\f"))
|
||||||
|
|
||||||
|
;;; doc-snarf ends here
|
292
scripts/frisk
Executable file
292
scripts/frisk
Executable file
|
@ -0,0 +1,292 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts frisk)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; frisk --- Grok the module interfaces of a body of files
|
||||||
|
|
||||||
|
;; Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen <ttn@gnu.org>
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: frisk [options] file ...
|
||||||
|
;;
|
||||||
|
;; Analyze FILE... module interfaces in aggregate (as a "body"),
|
||||||
|
;; and display a summary. Modules that are `define-module'd are
|
||||||
|
;; considered "internal" (and those not, "external"). When module X
|
||||||
|
;; uses module Y, X is said to be "(a) downstream of" Y, and Y is
|
||||||
|
;; "(an) upstream of" X.
|
||||||
|
;;
|
||||||
|
;; Normally, the summary displays external modules and their internal
|
||||||
|
;; downstreams, as this is the usual question asked by a body. There
|
||||||
|
;; are several options that modify this output.
|
||||||
|
;;
|
||||||
|
;; -u, --upstream show upstream edges
|
||||||
|
;; -d, --downstream show downstream edges (default)
|
||||||
|
;; -i, --internal show internal modules
|
||||||
|
;; -x, --external show external modules (default)
|
||||||
|
;;
|
||||||
|
;; If given both `upstream' and `downstream' options ("frisk -ud"), the
|
||||||
|
;; output is formatted: "C MODULE --- UP-LS --- DOWN-LS", where C is
|
||||||
|
;; either `i' or `x', and each element of UP-LS and DOWN-LS is (TYPE
|
||||||
|
;; MODULE-NAME ...).
|
||||||
|
;;
|
||||||
|
;; In all other cases, the "C MODULE" occupies its own line, and
|
||||||
|
;; subsequent lines list the up- or downstream edges, respectively,
|
||||||
|
;; indented by some non-zero amount of whitespace.
|
||||||
|
;;
|
||||||
|
;; Top-level `use-modules' (or `load' or 'primitive-load') forms in a
|
||||||
|
;; file that do not follow a `define-module' result an edge where the
|
||||||
|
;; downstream is the "default module", normally `(guile-user)'. This
|
||||||
|
;; can be set to another value by using:
|
||||||
|
;;
|
||||||
|
;; -m, --default-module MOD set MOD as the default module
|
||||||
|
|
||||||
|
;; Usage from a Scheme Program: (use-modules (scripts frisk))
|
||||||
|
;;
|
||||||
|
;; Module export list:
|
||||||
|
;; (frisk . args)
|
||||||
|
;; (make-frisker . options) => (lambda (files) ...) [see below]
|
||||||
|
;; (mod-up-ls module) => upstream edges
|
||||||
|
;; (mod-down-ls module) => downstream edges
|
||||||
|
;; (mod-int? module) => is the module internal?
|
||||||
|
;; (edge-type edge) => symbol: {regular,autoload,computed}
|
||||||
|
;; (edge-up edge) => upstream module
|
||||||
|
;; (edge-down edge) => downstream module
|
||||||
|
;;
|
||||||
|
;; OPTIONS is an alist. Recognized keys are:
|
||||||
|
;; default-module
|
||||||
|
;;
|
||||||
|
;; `make-frisker' returns a procedure that takes a list of files, the
|
||||||
|
;; FRISKER. FRISKER returns a closure, REPORT, that takes one of the
|
||||||
|
;; keys:
|
||||||
|
;; modules -- entire list of modules
|
||||||
|
;; internal -- list of internal modules
|
||||||
|
;; external -- list of external modules
|
||||||
|
;; i-up -- list of modules upstream of internal modules
|
||||||
|
;; x-up -- list of modules upstream of external modules
|
||||||
|
;; i-down -- list of modules downstream of internal modules
|
||||||
|
;; x-down -- list of modules downstream of external modules
|
||||||
|
;; edges -- list of edges
|
||||||
|
;; Note that `x-up' should always be null, since by (lack of!)
|
||||||
|
;; definition, we only know external modules by reference.
|
||||||
|
;;
|
||||||
|
;; The module and edge objects managed by REPORT can be examined in
|
||||||
|
;; detail by using the other (self-explanatory) procedures. Be careful
|
||||||
|
;; not to confuse a freshly consed list of symbols, like `(a b c)' with
|
||||||
|
;; the module `(a b c)'. If you want to find the module by that name,
|
||||||
|
;; try: (cond ((member '(a b c) (REPORT 'modules)) => car)).
|
||||||
|
|
||||||
|
;; TODO: Make "frisk -ud" output less ugly.
|
||||||
|
;; Consider default module as internal; add option to invert.
|
||||||
|
;; Support `edge-misc' data.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts frisk)
|
||||||
|
:autoload (ice-9 getopt-long) (getopt-long)
|
||||||
|
:use-module ((srfi srfi-1) :select (filter remove))
|
||||||
|
:export (frisk
|
||||||
|
make-frisker
|
||||||
|
mod-up-ls mod-down-ls mod-int?
|
||||||
|
edge-type edge-up edge-down))
|
||||||
|
|
||||||
|
(define *default-module* '(guile-user))
|
||||||
|
|
||||||
|
(define (grok-proc default-module note-use!)
|
||||||
|
(lambda (filename)
|
||||||
|
(let* ((p (open-file filename "r"))
|
||||||
|
(next (lambda () (read p)))
|
||||||
|
(ferret (lambda (use) ;;; handle "((foo bar) :select ...)"
|
||||||
|
(let ((maybe (car use)))
|
||||||
|
(if (list? maybe)
|
||||||
|
maybe
|
||||||
|
use))))
|
||||||
|
(curmod #f))
|
||||||
|
(let loop ((form (next)))
|
||||||
|
(cond ((eof-object? form))
|
||||||
|
((not (list? form)) (loop (next)))
|
||||||
|
(else (case (car form)
|
||||||
|
((define-module)
|
||||||
|
(let ((module (cadr form)))
|
||||||
|
(set! curmod module)
|
||||||
|
(note-use! 'def module #f)
|
||||||
|
(let loop ((ls form))
|
||||||
|
(or (null? ls)
|
||||||
|
(case (car ls)
|
||||||
|
((:use-module)
|
||||||
|
(note-use! 'regular module (ferret (cadr ls)))
|
||||||
|
(loop (cddr ls)))
|
||||||
|
((:autoload)
|
||||||
|
(note-use! 'autoload module (cadr ls))
|
||||||
|
(loop (cdddr ls)))
|
||||||
|
(else (loop (cdr ls))))))))
|
||||||
|
((use-modules)
|
||||||
|
(for-each (lambda (use)
|
||||||
|
(note-use! 'regular
|
||||||
|
(or curmod default-module)
|
||||||
|
(ferret use)))
|
||||||
|
(cdr form)))
|
||||||
|
((load primitive-load)
|
||||||
|
(note-use! 'computed
|
||||||
|
(or curmod default-module)
|
||||||
|
(let ((file (cadr form)))
|
||||||
|
(if (string? file)
|
||||||
|
file
|
||||||
|
(format #f "[computed in ~A]"
|
||||||
|
filename))))))
|
||||||
|
(loop (next))))))))
|
||||||
|
|
||||||
|
(define up-ls (make-object-property)) ; list
|
||||||
|
(define dn-ls (make-object-property)) ; list
|
||||||
|
(define int? (make-object-property)) ; defined via `define-module'
|
||||||
|
|
||||||
|
(define mod-up-ls up-ls)
|
||||||
|
(define mod-down-ls dn-ls)
|
||||||
|
(define mod-int? int?)
|
||||||
|
|
||||||
|
(define (i-or-x module)
|
||||||
|
(if (int? module) 'i 'x))
|
||||||
|
|
||||||
|
(define edge-type (make-object-property)) ; symbol
|
||||||
|
|
||||||
|
(define (make-edge type up down)
|
||||||
|
(let ((new (cons up down)))
|
||||||
|
(set! (edge-type new) type)
|
||||||
|
new))
|
||||||
|
|
||||||
|
(define edge-up car)
|
||||||
|
(define edge-down cdr)
|
||||||
|
|
||||||
|
(define (up-ls+! m new) (set! (up-ls m) (cons new (up-ls m))))
|
||||||
|
(define (dn-ls+! m new) (set! (dn-ls m) (cons new (dn-ls m))))
|
||||||
|
|
||||||
|
(define (make-body alist)
|
||||||
|
(lambda (key)
|
||||||
|
(assq-ref alist key)))
|
||||||
|
|
||||||
|
(define (scan default-module files)
|
||||||
|
(let* ((modules (list))
|
||||||
|
(edges (list))
|
||||||
|
(intern (lambda (module)
|
||||||
|
(cond ((member module modules) => car)
|
||||||
|
(else (set! (up-ls module) (list))
|
||||||
|
(set! (dn-ls module) (list))
|
||||||
|
(set! modules (cons module modules))
|
||||||
|
module))))
|
||||||
|
(grok (grok-proc default-module
|
||||||
|
(lambda (type d u)
|
||||||
|
(let ((d (intern d)))
|
||||||
|
(if (eq? type 'def)
|
||||||
|
(set! (int? d) #t)
|
||||||
|
(let* ((u (intern u))
|
||||||
|
(edge (make-edge type u d)))
|
||||||
|
(set! edges (cons edge edges))
|
||||||
|
(up-ls+! d edge)
|
||||||
|
(dn-ls+! u edge))))))))
|
||||||
|
(for-each grok files)
|
||||||
|
(make-body
|
||||||
|
`((modules . ,modules)
|
||||||
|
(internal . ,(filter int? modules))
|
||||||
|
(external . ,(remove int? modules))
|
||||||
|
(i-up . ,(filter int? (map edge-down edges)))
|
||||||
|
(x-up . ,(remove int? (map edge-down edges)))
|
||||||
|
(i-down . ,(filter int? (map edge-up edges)))
|
||||||
|
(x-down . ,(remove int? (map edge-up edges)))
|
||||||
|
(edges . ,edges)))))
|
||||||
|
|
||||||
|
(define (make-frisker . options)
|
||||||
|
(let ((default-module (or (assq-ref options 'default-module)
|
||||||
|
*default-module*)))
|
||||||
|
(lambda (files)
|
||||||
|
(scan default-module files))))
|
||||||
|
|
||||||
|
(define (dump-updown modules)
|
||||||
|
(for-each (lambda (m)
|
||||||
|
(format #t "~A ~A --- ~A --- ~A\n"
|
||||||
|
(i-or-x m) m
|
||||||
|
(map (lambda (edge)
|
||||||
|
(cons (edge-type edge)
|
||||||
|
(edge-up edge)))
|
||||||
|
(up-ls m))
|
||||||
|
(map (lambda (edge)
|
||||||
|
(cons (edge-type edge)
|
||||||
|
(edge-down edge)))
|
||||||
|
(dn-ls m))))
|
||||||
|
modules))
|
||||||
|
|
||||||
|
(define (dump-up modules)
|
||||||
|
(for-each (lambda (m)
|
||||||
|
(format #t "~A ~A\n" (i-or-x m) m)
|
||||||
|
(for-each (lambda (edge)
|
||||||
|
(format #t "\t\t\t ~A\t~A\n"
|
||||||
|
(edge-type edge) (edge-up edge)))
|
||||||
|
(up-ls m)))
|
||||||
|
modules))
|
||||||
|
|
||||||
|
(define (dump-down modules)
|
||||||
|
(for-each (lambda (m)
|
||||||
|
(format #t "~A ~A\n" (i-or-x m) m)
|
||||||
|
(for-each (lambda (edge)
|
||||||
|
(format #t "\t\t\t ~A\t~A\n"
|
||||||
|
(edge-type edge) (edge-down edge)))
|
||||||
|
(dn-ls m)))
|
||||||
|
modules))
|
||||||
|
|
||||||
|
(define (frisk . args)
|
||||||
|
(let* ((parsed-opts (getopt-long
|
||||||
|
(cons "frisk" args) ;;; kludge
|
||||||
|
'((upstream (single-char #\u))
|
||||||
|
(downstream (single-char #\d))
|
||||||
|
(internal (single-char #\i))
|
||||||
|
(external (single-char #\x))
|
||||||
|
(default-module
|
||||||
|
(single-char #\m)
|
||||||
|
(value #t)))))
|
||||||
|
(=u (option-ref parsed-opts 'upstream #f))
|
||||||
|
(=d (option-ref parsed-opts 'downstream #f))
|
||||||
|
(=i (option-ref parsed-opts 'internal #f))
|
||||||
|
(=x (option-ref parsed-opts 'external #f))
|
||||||
|
(files (option-ref parsed-opts '() (list)))
|
||||||
|
(report ((make-frisker
|
||||||
|
`(default-module
|
||||||
|
. ,(option-ref parsed-opts 'default-module
|
||||||
|
*default-module*)))
|
||||||
|
files))
|
||||||
|
(modules (report 'modules))
|
||||||
|
(internal (report 'internal))
|
||||||
|
(external (report 'external))
|
||||||
|
(edges (report 'edges)))
|
||||||
|
(format #t "~A ~A, ~A ~A (~A ~A, ~A ~A), ~A ~A\n\n"
|
||||||
|
(length files) "files"
|
||||||
|
(length modules) "modules"
|
||||||
|
(length internal) "internal"
|
||||||
|
(length external) "external"
|
||||||
|
(length edges) "edges")
|
||||||
|
((cond ((and =u =d) dump-updown)
|
||||||
|
(=u dump-up)
|
||||||
|
(else dump-down))
|
||||||
|
(cond ((and =i =x) modules)
|
||||||
|
(=i internal)
|
||||||
|
(else external)))))
|
||||||
|
|
||||||
|
(define main frisk)
|
||||||
|
|
||||||
|
;;; frisk ends here
|
146
scripts/generate-autoload
Executable file
146
scripts/generate-autoload
Executable file
|
@ -0,0 +1,146 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts generate-autoload)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; generate-autoload --- Display define-module form with autoload info
|
||||||
|
|
||||||
|
;; Copyright (C) 2001 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: generate-autoload [OPTIONS] FILE1 FILE2 ...
|
||||||
|
;;
|
||||||
|
;; The autoload form is displayed to standard output:
|
||||||
|
;;
|
||||||
|
;; (define-module (guile-user)
|
||||||
|
;; :autoload (ZAR FOO) (FOO-1 FOO-2 ...)
|
||||||
|
;; :
|
||||||
|
;; :
|
||||||
|
;; :autoload (ZAR BAR) (BAR-1 BAR-2 ...))
|
||||||
|
;;
|
||||||
|
;; For each file, a symbol triggers an autoload if it is found in one
|
||||||
|
;; of these situations:
|
||||||
|
;; - in the `:export' clause of a `define-module' form
|
||||||
|
;; - in a top-level `export' or `export-syntax' form
|
||||||
|
;; - in a `define-public' form
|
||||||
|
;; - in a `defmacro-public' form
|
||||||
|
;;
|
||||||
|
;; The module name is inferred from the `define-module' form. If either the
|
||||||
|
;; module name or the exports list cannot be determined, no autoload entry is
|
||||||
|
;; generated for that file.
|
||||||
|
;;
|
||||||
|
;; Options:
|
||||||
|
;; --target MODULE-NAME -- Use MODULE-NAME instead of `(guile-user)'.
|
||||||
|
;; Note that some shells may require you to
|
||||||
|
;; quote the argument to handle parentheses
|
||||||
|
;; and spaces.
|
||||||
|
;;
|
||||||
|
;; Usage examples from Scheme code as a module:
|
||||||
|
;; (use-modules (scripts generate-autoload))
|
||||||
|
;; (generate-autoload "generate-autoload")
|
||||||
|
;; (generate-autoload "--target" "(my module)" "generate-autoload")
|
||||||
|
;; (apply generate-autoload "--target" "(my module)" '("foo" "bar" "baz"))
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts generate-autoload)
|
||||||
|
:export (generate-autoload))
|
||||||
|
|
||||||
|
(define (autoload-info file)
|
||||||
|
(let ((p (open-input-file file)))
|
||||||
|
(let loop ((form (read p)) (module-name #f) (exports '()))
|
||||||
|
(if (eof-object? form)
|
||||||
|
(and module-name
|
||||||
|
(not (null? exports))
|
||||||
|
(list module-name exports)) ; ret
|
||||||
|
(cond ((and (list? form)
|
||||||
|
(< 1 (length form))
|
||||||
|
(eq? 'define-module (car form)))
|
||||||
|
(loop (read p)
|
||||||
|
(cadr form)
|
||||||
|
(cond ((member ':export form)
|
||||||
|
=> (lambda (val)
|
||||||
|
(append (cadr val) exports)))
|
||||||
|
(else exports))))
|
||||||
|
((and (list? form)
|
||||||
|
(< 1 (length form))
|
||||||
|
(memq (car form) '(export export-syntax)))
|
||||||
|
(loop (read p)
|
||||||
|
module-name
|
||||||
|
(append (cdr form) exports)))
|
||||||
|
((and (list? form)
|
||||||
|
(< 2 (length form))
|
||||||
|
(eq? 'define-public (car form))
|
||||||
|
(list? (cadr form))
|
||||||
|
(symbol? (caadr form)))
|
||||||
|
(loop (read p)
|
||||||
|
module-name
|
||||||
|
(cons (caadr form) exports)))
|
||||||
|
((and (list? form)
|
||||||
|
(< 2 (length form))
|
||||||
|
(eq? 'define-public (car form))
|
||||||
|
(symbol? (cadr form)))
|
||||||
|
(loop (read p)
|
||||||
|
module-name
|
||||||
|
(cons (cadr form) exports)))
|
||||||
|
((and (list? form)
|
||||||
|
(< 3 (length form))
|
||||||
|
(eq? 'defmacro-public (car form))
|
||||||
|
(symbol? (cadr form)))
|
||||||
|
(loop (read p)
|
||||||
|
module-name
|
||||||
|
(cons (cadr form) exports)))
|
||||||
|
(else (loop (read p) module-name exports)))))))
|
||||||
|
|
||||||
|
(define (generate-autoload . args)
|
||||||
|
(let* ((module-count 0)
|
||||||
|
(syms-count 0)
|
||||||
|
(target-override (cond ((member "--target" args) => cadr)
|
||||||
|
(else #f)))
|
||||||
|
(files (if target-override (cddr args) (cdr args))))
|
||||||
|
(display ";;; do not edit --- generated ")
|
||||||
|
(display (strftime "%Y-%m-%d %H:%M:%S" (localtime (current-time))))
|
||||||
|
(newline)
|
||||||
|
(display "(define-module ")
|
||||||
|
(display (or target-override "(guile-user)"))
|
||||||
|
(for-each (lambda (file)
|
||||||
|
(cond ((autoload-info file)
|
||||||
|
=> (lambda (info)
|
||||||
|
(and info
|
||||||
|
(apply (lambda (module-name exports)
|
||||||
|
(set! module-count (1+ module-count))
|
||||||
|
(set! syms-count (+ (length exports)
|
||||||
|
syms-count))
|
||||||
|
(for-each display
|
||||||
|
(list "\n :autoload "
|
||||||
|
module-name " "
|
||||||
|
exports)))
|
||||||
|
info))))))
|
||||||
|
files)
|
||||||
|
(display ")")
|
||||||
|
(newline)
|
||||||
|
(for-each display (list " ;;; "
|
||||||
|
syms-count " symbols in "
|
||||||
|
module-count " modules\n"))))
|
||||||
|
|
||||||
|
(define main generate-autoload)
|
||||||
|
|
||||||
|
;;; generate-autoload ends here
|
319
scripts/lint
Executable file
319
scripts/lint
Executable file
|
@ -0,0 +1,319 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts lint)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; lint --- Preemptive checks for coding errors in Guile Scheme code
|
||||||
|
|
||||||
|
;; Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Neil Jerram
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: lint FILE1 FILE2 ...
|
||||||
|
;;
|
||||||
|
;; Perform various preemptive checks for coding errors in Guile Scheme
|
||||||
|
;; code.
|
||||||
|
;;
|
||||||
|
;; Right now, there is only one check available, for unresolved free
|
||||||
|
;; variables. The intention is that future lint-like checks will be
|
||||||
|
;; implemented by adding to this script file.
|
||||||
|
;;
|
||||||
|
;; Unresolved free variables
|
||||||
|
;; -------------------------
|
||||||
|
;;
|
||||||
|
;; Free variables are those whose definitions come from outside the
|
||||||
|
;; module under investigation. In Guile, these definitions are
|
||||||
|
;; imported from other modules using `#:use-module' forms.
|
||||||
|
;;
|
||||||
|
;; This tool scans the specified files for unresolved free variables -
|
||||||
|
;; i.e. variables for which you may have forgotten the appropriate
|
||||||
|
;; `#:use-module', or for which the module that is supposed to export
|
||||||
|
;; them forgot to.
|
||||||
|
;;
|
||||||
|
;; It isn't guaranteed that the scan will find absolutely all such
|
||||||
|
;; errors. Quoted (and quasiquoted) expressions are skipped, since
|
||||||
|
;; they are most commonly used to describe constant data, not code, so
|
||||||
|
;; code that is explicitly evaluated using `eval' will not be checked.
|
||||||
|
;; For example, the `unresolved-var' in `(eval 'unresolved-var
|
||||||
|
;; (current-module))' would be missed.
|
||||||
|
;;
|
||||||
|
;; False positives are also possible. Firstly, the tool doesn't
|
||||||
|
;; understand all possible forms of implicit quoting; in particular,
|
||||||
|
;; it doesn't detect and expand uses of macros. Secondly, it picks up
|
||||||
|
;; explicit compatibility code like `(if (defined? 'x) (define y x))'.
|
||||||
|
;; Thirdly, there are occasional oddities like `next-method'.
|
||||||
|
;; However, the number of false positives for realistic code is
|
||||||
|
;; hopefully small enough that they can be individually considered and
|
||||||
|
;; ignored.
|
||||||
|
;;
|
||||||
|
;; Example
|
||||||
|
;; -------
|
||||||
|
;;
|
||||||
|
;; Note: most of the unresolved variables found in this example are
|
||||||
|
;; false positives, as you would hope. => scope for improvement.
|
||||||
|
;;
|
||||||
|
;; $ guile-tools lint `guile-tools`
|
||||||
|
;; No unresolved free variables in PROGRAM
|
||||||
|
;; No unresolved free variables in autofrisk
|
||||||
|
;; No unresolved free variables in display-commentary
|
||||||
|
;; Unresolved free variables in doc-snarf:
|
||||||
|
;; doc-snarf-version
|
||||||
|
;; No unresolved free variables in frisk
|
||||||
|
;; No unresolved free variables in generate-autoload
|
||||||
|
;; No unresolved free variables in lint
|
||||||
|
;; No unresolved free variables in punify
|
||||||
|
;; No unresolved free variables in read-scheme-source
|
||||||
|
;; Unresolved free variables in snarf-check-and-output-texi:
|
||||||
|
;; name
|
||||||
|
;; pos
|
||||||
|
;; line
|
||||||
|
;; x
|
||||||
|
;; rest
|
||||||
|
;; ...
|
||||||
|
;; do-argpos
|
||||||
|
;; do-command
|
||||||
|
;; do-args
|
||||||
|
;; type
|
||||||
|
;; num
|
||||||
|
;; file
|
||||||
|
;; do-arglist
|
||||||
|
;; req
|
||||||
|
;; opt
|
||||||
|
;; var
|
||||||
|
;; command
|
||||||
|
;; do-directive
|
||||||
|
;; s
|
||||||
|
;; ?
|
||||||
|
;; No unresolved free variables in use2dot
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts lint)
|
||||||
|
#:use-module (ice-9 common-list)
|
||||||
|
#:use-module (ice-9 format)
|
||||||
|
#:export (lint))
|
||||||
|
|
||||||
|
(define (lint filename)
|
||||||
|
(let ((module-name (scan-file-for-module-name filename))
|
||||||
|
(free-vars (uniq (scan-file-for-free-variables filename))))
|
||||||
|
(let ((module (resolve-module module-name))
|
||||||
|
(all-resolved? #t))
|
||||||
|
(let loop ((free-vars free-vars))
|
||||||
|
(or (null? free-vars)
|
||||||
|
(begin
|
||||||
|
(catch #t
|
||||||
|
(lambda ()
|
||||||
|
(eval (car free-vars) module))
|
||||||
|
(lambda args
|
||||||
|
(if all-resolved?
|
||||||
|
(format #t
|
||||||
|
"Unresolved free variables in ~A:\n"
|
||||||
|
filename))
|
||||||
|
(write-char #\tab)
|
||||||
|
(write (car free-vars))
|
||||||
|
(newline)
|
||||||
|
(set! all-resolved? #f)))
|
||||||
|
(loop (cdr free-vars)))))
|
||||||
|
(if all-resolved?
|
||||||
|
(format #t
|
||||||
|
"No unresolved free variables in ~A\n"
|
||||||
|
filename)))))
|
||||||
|
|
||||||
|
(define (scan-file-for-module-name filename)
|
||||||
|
(with-input-from-file filename
|
||||||
|
(lambda ()
|
||||||
|
(let loop ((x (read)))
|
||||||
|
(cond ((eof-object? x) #f)
|
||||||
|
((and (pair? x)
|
||||||
|
(eq? (car x) 'define-module))
|
||||||
|
(cadr x))
|
||||||
|
(else (loop (read))))))))
|
||||||
|
|
||||||
|
(define (scan-file-for-free-variables filename)
|
||||||
|
(with-input-from-file filename
|
||||||
|
(lambda ()
|
||||||
|
(let loop ((x (read)) (fvlists '()))
|
||||||
|
(if (eof-object? x)
|
||||||
|
(apply append fvlists)
|
||||||
|
(loop (read) (cons (detect-free-variables x '()) fvlists)))))))
|
||||||
|
|
||||||
|
; guile> (detect-free-variables '(let ((a 1)) a) '())
|
||||||
|
; ()
|
||||||
|
; guile> (detect-free-variables '(let ((a 1)) b) '())
|
||||||
|
; (b)
|
||||||
|
; guile> (detect-free-variables '(let ((a 1) (b a)) b) '())
|
||||||
|
; (a)
|
||||||
|
; guile> (detect-free-variables '(let* ((a 1) (b a)) b) '())
|
||||||
|
; ()
|
||||||
|
; guile> (detect-free-variables '(define a 1) '())
|
||||||
|
; ()
|
||||||
|
; guile> (detect-free-variables '(define a b) '())
|
||||||
|
; (b)
|
||||||
|
; guile> (detect-free-variables '(define (a b c) b) '())
|
||||||
|
; ()
|
||||||
|
; guile> (detect-free-variables '(define (a b c) e) '())
|
||||||
|
; (e)
|
||||||
|
|
||||||
|
(define (detect-free-variables x locals)
|
||||||
|
;; Given an expression @var{x} and a list @var{locals} of local
|
||||||
|
;; variables (symbols) that are in scope for @var{x}, return a list
|
||||||
|
;; of free variable symbols.
|
||||||
|
(cond ((symbol? x)
|
||||||
|
(if (memq x locals) '() (list x)))
|
||||||
|
|
||||||
|
((pair? x)
|
||||||
|
(case (car x)
|
||||||
|
((define-module define-generic quote quasiquote)
|
||||||
|
;; No code of interest in these expressions.
|
||||||
|
'())
|
||||||
|
|
||||||
|
((let letrec)
|
||||||
|
;; Check for named let. If there is a name, transform the
|
||||||
|
;; expression so that it looks like an unnamed let with
|
||||||
|
;; the name as one of the bindings.
|
||||||
|
(if (symbol? (cadr x))
|
||||||
|
(set-cdr! x (cons (cons (list (cadr x) #f) (caddr x))
|
||||||
|
(cdddr x))))
|
||||||
|
;; Unnamed let processing.
|
||||||
|
(let ((letrec? (eq? (car x) 'letrec))
|
||||||
|
(locals-for-let-body (append locals (map car (cadr x)))))
|
||||||
|
(append (apply append
|
||||||
|
(map (lambda (binding)
|
||||||
|
(detect-free-variables (cadr binding)
|
||||||
|
(if letrec?
|
||||||
|
locals-for-let-body
|
||||||
|
locals)))
|
||||||
|
(cadr x)))
|
||||||
|
(apply append
|
||||||
|
(map (lambda (bodyform)
|
||||||
|
(detect-free-variables bodyform
|
||||||
|
locals-for-let-body))
|
||||||
|
(cddr x))))))
|
||||||
|
|
||||||
|
((let* and-let*)
|
||||||
|
;; Handle bindings recursively.
|
||||||
|
(if (null? (cadr x))
|
||||||
|
(apply append
|
||||||
|
(map (lambda (bodyform)
|
||||||
|
(detect-free-variables bodyform locals))
|
||||||
|
(cddr x)))
|
||||||
|
(append (detect-free-variables (cadr (caadr x)) locals)
|
||||||
|
(detect-free-variables `(let* ,(cdadr x) ,@(cddr x))
|
||||||
|
(cons (caaadr x) locals)))))
|
||||||
|
|
||||||
|
((define define-public define-macro)
|
||||||
|
(if (pair? (cadr x))
|
||||||
|
(begin
|
||||||
|
(set! locals (cons (caadr x) locals))
|
||||||
|
(detect-free-variables `(lambda ,(cdadr x) ,@(cddr x))
|
||||||
|
locals))
|
||||||
|
(begin
|
||||||
|
(set! locals (cons (cadr x) locals))
|
||||||
|
(detect-free-variables (caddr x) locals))))
|
||||||
|
|
||||||
|
((lambda lambda*)
|
||||||
|
(let ((locals-for-lambda-body (let loop ((locals locals)
|
||||||
|
(args (cadr x)))
|
||||||
|
(cond ((null? args) locals)
|
||||||
|
((pair? args)
|
||||||
|
(loop (cons (car args) locals)
|
||||||
|
(cdr args)))
|
||||||
|
(else
|
||||||
|
(cons args locals))))))
|
||||||
|
(apply append
|
||||||
|
(map (lambda (bodyform)
|
||||||
|
(detect-free-variables bodyform
|
||||||
|
locals-for-lambda-body))
|
||||||
|
(cddr x)))))
|
||||||
|
|
||||||
|
((receive)
|
||||||
|
(let ((locals-for-receive-body (append locals (cadr x))))
|
||||||
|
(apply append
|
||||||
|
(detect-free-variables (caddr x) locals)
|
||||||
|
(map (lambda (bodyform)
|
||||||
|
(detect-free-variables bodyform
|
||||||
|
locals-for-receive-body))
|
||||||
|
(cdddr x)))))
|
||||||
|
|
||||||
|
((define-method define*)
|
||||||
|
(let ((locals-for-method-body (let loop ((locals locals)
|
||||||
|
(args (cdadr x)))
|
||||||
|
(cond ((null? args) locals)
|
||||||
|
((pair? args)
|
||||||
|
(loop (cons (if (pair? (car args))
|
||||||
|
(caar args)
|
||||||
|
(car args))
|
||||||
|
locals)
|
||||||
|
(cdr args)))
|
||||||
|
(else
|
||||||
|
(cons args locals))))))
|
||||||
|
(apply append
|
||||||
|
(map (lambda (bodyform)
|
||||||
|
(detect-free-variables bodyform
|
||||||
|
locals-for-method-body))
|
||||||
|
(cddr x)))))
|
||||||
|
|
||||||
|
((define-class)
|
||||||
|
;; Avoid picking up slot names at the start of slot
|
||||||
|
;; definitions.
|
||||||
|
(apply append
|
||||||
|
(map (lambda (slot/option)
|
||||||
|
(detect-free-variables-noncar (if (pair? slot/option)
|
||||||
|
(cdr slot/option)
|
||||||
|
slot/option)
|
||||||
|
locals))
|
||||||
|
(cdddr x))))
|
||||||
|
|
||||||
|
((case)
|
||||||
|
(apply append
|
||||||
|
(detect-free-variables (cadr x) locals)
|
||||||
|
(map (lambda (case)
|
||||||
|
(detect-free-variables (cdr case) locals))
|
||||||
|
(cddr x))))
|
||||||
|
|
||||||
|
((unquote unquote-splicing else =>)
|
||||||
|
(detect-free-variables-noncar (cdr x) locals))
|
||||||
|
|
||||||
|
(else (append (detect-free-variables (car x) locals)
|
||||||
|
(detect-free-variables-noncar (cdr x) locals)))))
|
||||||
|
|
||||||
|
(else '())))
|
||||||
|
|
||||||
|
(define (detect-free-variables-noncar x locals)
|
||||||
|
;; Given an expression @var{x} and a list @var{locals} of local
|
||||||
|
;; variables (symbols) that are in scope for @var{x}, return a list
|
||||||
|
;; of free variable symbols.
|
||||||
|
(cond ((symbol? x)
|
||||||
|
(if (memq x locals) '() (list x)))
|
||||||
|
|
||||||
|
((pair? x)
|
||||||
|
(case (car x)
|
||||||
|
((=>)
|
||||||
|
(detect-free-variables-noncar (cdr x) locals))
|
||||||
|
|
||||||
|
(else (append (detect-free-variables (car x) locals)
|
||||||
|
(detect-free-variables-noncar (cdr x) locals)))))
|
||||||
|
|
||||||
|
(else '())))
|
||||||
|
|
||||||
|
(define (main . files)
|
||||||
|
(for-each lint files))
|
||||||
|
|
||||||
|
;;; lint ends here
|
89
scripts/punify
Executable file
89
scripts/punify
Executable file
|
@ -0,0 +1,89 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts punify)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; punify --- Display Scheme code w/o unnecessary comments / whitespace
|
||||||
|
|
||||||
|
;; Copyright (C) 2001 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: punify FILE1 FILE2 ...
|
||||||
|
;;
|
||||||
|
;; Each file's forms are read and written to stdout.
|
||||||
|
;; The effect is to remove comments and much non-essential whitespace.
|
||||||
|
;; This is useful when installing Scheme source to space-limited media.
|
||||||
|
;;
|
||||||
|
;; Example:
|
||||||
|
;; $ wc ./punify ; ./punify ./punify | wc
|
||||||
|
;; 89 384 3031 ./punify
|
||||||
|
;; 0 42 920
|
||||||
|
;;
|
||||||
|
;; TODO: Read from stdin.
|
||||||
|
;; Handle vectors.
|
||||||
|
;; Identifier punification.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts punify)
|
||||||
|
:export (punify))
|
||||||
|
|
||||||
|
(define (write-punily form)
|
||||||
|
(cond ((and (list? form) (not (null? form)))
|
||||||
|
(let ((first (car form)))
|
||||||
|
(display "(")
|
||||||
|
(write-punily first)
|
||||||
|
(let loop ((ls (cdr form)) (last-was-list? (list? first)))
|
||||||
|
(if (null? ls)
|
||||||
|
(display ")")
|
||||||
|
(let* ((new-first (car ls))
|
||||||
|
(this-is-list? (list? new-first)))
|
||||||
|
(and (not last-was-list?)
|
||||||
|
(not this-is-list?)
|
||||||
|
(display " "))
|
||||||
|
(write-punily new-first)
|
||||||
|
(loop (cdr ls) this-is-list?))))))
|
||||||
|
((and (symbol? form)
|
||||||
|
(let ((ls (string->list (symbol->string form))))
|
||||||
|
(and (char=? (car ls) #\:)
|
||||||
|
(not (memq #\space ls))
|
||||||
|
(list->string (cdr ls)))))
|
||||||
|
=> (lambda (symbol-name-after-colon)
|
||||||
|
(display #\:)
|
||||||
|
(display symbol-name-after-colon)))
|
||||||
|
(else (write form))))
|
||||||
|
|
||||||
|
(define (punify-one file)
|
||||||
|
(with-input-from-file file
|
||||||
|
(lambda ()
|
||||||
|
(let ((toke (lambda () (read (current-input-port)))))
|
||||||
|
(let loop ((form (toke)))
|
||||||
|
(or (eof-object? form)
|
||||||
|
(begin
|
||||||
|
(write-punily form)
|
||||||
|
(loop (toke)))))))))
|
||||||
|
|
||||||
|
(define (punify . args)
|
||||||
|
(for-each punify-one args))
|
||||||
|
|
||||||
|
(define main punify)
|
||||||
|
|
||||||
|
;;; punify ends here
|
284
scripts/read-scheme-source
Executable file
284
scripts/read-scheme-source
Executable file
|
@ -0,0 +1,284 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts read-scheme-source)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; read-scheme-source --- Read a file, recognizing scheme forms and comments
|
||||||
|
|
||||||
|
;; Copyright (C) 2001 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: read-scheme-source FILE1 FILE2 ...
|
||||||
|
;;
|
||||||
|
;; This program parses each FILE and writes to stdout sexps that describe the
|
||||||
|
;; top-level structures of the file: scheme forms, single-line comments, and
|
||||||
|
;; hash-bang comments. You can further process these (to associate comments
|
||||||
|
;; w/ scheme forms as a kind of documentation, for example).
|
||||||
|
;;
|
||||||
|
;; The output sexps have one of these forms:
|
||||||
|
;;
|
||||||
|
;; (quote (filename FILENAME))
|
||||||
|
;;
|
||||||
|
;; (quote (comment :leading-semicolons N
|
||||||
|
;; :text LINE))
|
||||||
|
;;
|
||||||
|
;; (quote (whitespace :text LINE))
|
||||||
|
;;
|
||||||
|
;; (quote (hash-bang-comment :line LINUM
|
||||||
|
;; :line-count N
|
||||||
|
;; :text-list (LINE1 LINE2 ...)))
|
||||||
|
;;
|
||||||
|
;; (quote (following-form-properties :line LINUM
|
||||||
|
;; :line-count N)
|
||||||
|
;; :type TYPE
|
||||||
|
;; :signature SIGNATURE
|
||||||
|
;; :std-int-doc DOCSTRING))
|
||||||
|
;;
|
||||||
|
;; SEXP
|
||||||
|
;;
|
||||||
|
;; The first four are straightforward (both FILENAME and LINE are strings sans
|
||||||
|
;; newline, while LINUM and N are integers). The last two always go together,
|
||||||
|
;; in that order. SEXP is scheme code processed only by `read' and then
|
||||||
|
;; `write'.
|
||||||
|
;;
|
||||||
|
;; The :type field may be omitted if the form is not recognized. Otherwise,
|
||||||
|
;; TYPE may be one of: procedure, alias, define-module, variable.
|
||||||
|
;;
|
||||||
|
;; The :signature field may be omitted if the form is not a procedure.
|
||||||
|
;; Otherwise, SIGNATURE is a list showing the procedure's signature.
|
||||||
|
;;
|
||||||
|
;; If the type is `procedure' and the form has a standard internal docstring
|
||||||
|
;; (first body form a string), that is extracted in full -- including any
|
||||||
|
;; embedded newlines -- and recorded by field :std-int-doc.
|
||||||
|
;;
|
||||||
|
;;
|
||||||
|
;; Usage from a program: The output list of sexps can be retrieved by scheme
|
||||||
|
;; programs w/o having to capture stdout, like so:
|
||||||
|
;;
|
||||||
|
;; (use-modules (scripts read-scheme-source))
|
||||||
|
;; (define source-forms (read-scheme-source-silently "FILE1" "FILE2" ...))
|
||||||
|
;;
|
||||||
|
;; There are also two convenience procs exported for use by Scheme programs:
|
||||||
|
;;
|
||||||
|
;; (clump FORMS) --- filter FORMS combining contiguous comment forms that
|
||||||
|
;; have the same number of leading semicolons.
|
||||||
|
;;
|
||||||
|
;; (quoted? SYM FORM) --- see if FORM looks like: "(quote (SYM ...))", parse
|
||||||
|
;; the ":tags", and return alist of (TAG . VAL) elems.
|
||||||
|
;;
|
||||||
|
;; TODO: Add option "--clump-comments", maybe w/ different clumping styles.
|
||||||
|
;; Make `annotate!' extensible.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts read-scheme-source)
|
||||||
|
:use-module (ice-9 rdelim)
|
||||||
|
:export (read-scheme-source
|
||||||
|
read-scheme-source-silently
|
||||||
|
quoted?
|
||||||
|
clump))
|
||||||
|
|
||||||
|
;; Try to figure out what FORM is and its various attributes.
|
||||||
|
;; Call proc NOTE! with key (a symbol) and value.
|
||||||
|
;;
|
||||||
|
(define (annotate! form note!)
|
||||||
|
(cond ((and (list? form)
|
||||||
|
(< 2 (length form))
|
||||||
|
(eq? 'define (car form))
|
||||||
|
(pair? (cadr form))
|
||||||
|
(symbol? (caadr form)))
|
||||||
|
(note! ':type 'procedure)
|
||||||
|
(note! ':signature (cadr form))
|
||||||
|
(and (< 3 (length form))
|
||||||
|
(string? (caddr form))
|
||||||
|
(note! ':std-int-doc (caddr form))))
|
||||||
|
((and (list? form)
|
||||||
|
(< 2 (length form))
|
||||||
|
(eq? 'define (car form))
|
||||||
|
(symbol? (cadr form))
|
||||||
|
(list? (caddr form))
|
||||||
|
(< 3 (length (caddr form)))
|
||||||
|
(eq? 'lambda (car (caddr form)))
|
||||||
|
(string? (caddr (caddr form))))
|
||||||
|
(note! ':type 'procedure)
|
||||||
|
(note! ':signature (cons (cadr form) (cadr (caddr form))))
|
||||||
|
(note! ':std-int-doc (caddr (caddr form))))
|
||||||
|
((and (list? form)
|
||||||
|
(= 3 (length form))
|
||||||
|
(eq? 'define (car form))
|
||||||
|
(symbol? (cadr form))
|
||||||
|
(symbol? (caddr form)))
|
||||||
|
(note! ':type 'alias))
|
||||||
|
((and (list? form)
|
||||||
|
(eq? 'define-module (car form)))
|
||||||
|
(note! ':type 'define-module))
|
||||||
|
;; Add other types here.
|
||||||
|
(else (note! ':type 'variable))))
|
||||||
|
|
||||||
|
;; Process FILE, calling NB! on parsed top-level elements.
|
||||||
|
;; Recognized: #!-!# and regular comments in addition to normal forms.
|
||||||
|
;;
|
||||||
|
(define (process file nb!)
|
||||||
|
(nb! `'(filename ,file))
|
||||||
|
(let ((hash-bang-rx (make-regexp "^#!"))
|
||||||
|
(bang-hash-rx (make-regexp "^!#"))
|
||||||
|
(all-comment-rx (make-regexp "^[ \t]*(;+)"))
|
||||||
|
(all-whitespace-rx (make-regexp "^[ \t]*$"))
|
||||||
|
(p (open-input-file file)))
|
||||||
|
(let loop ((n (1+ (port-line p))) (line (read-line p)))
|
||||||
|
(or (not n)
|
||||||
|
(eof-object? line)
|
||||||
|
(begin
|
||||||
|
(cond ((regexp-exec hash-bang-rx line)
|
||||||
|
(let loop ((line (read-line p))
|
||||||
|
(text (list line)))
|
||||||
|
(if (or (eof-object? line)
|
||||||
|
(regexp-exec bang-hash-rx line))
|
||||||
|
(nb! `'(hash-bang-comment
|
||||||
|
:line ,n
|
||||||
|
:line-count ,(1+ (length text))
|
||||||
|
:text-list ,(reverse
|
||||||
|
(cons line text))))
|
||||||
|
(loop (read-line p)
|
||||||
|
(cons line text)))))
|
||||||
|
((regexp-exec all-whitespace-rx line)
|
||||||
|
(nb! `'(whitespace :text ,line)))
|
||||||
|
((regexp-exec all-comment-rx line)
|
||||||
|
=> (lambda (m)
|
||||||
|
(nb! `'(comment
|
||||||
|
:leading-semicolons
|
||||||
|
,(let ((m1 (vector-ref m 1)))
|
||||||
|
(- (cdr m1) (car m1)))
|
||||||
|
:text ,line))))
|
||||||
|
(else
|
||||||
|
(unread-string line p)
|
||||||
|
(let* ((form (read p))
|
||||||
|
(count (- (port-line p) n))
|
||||||
|
(props (let* ((props '())
|
||||||
|
(prop+ (lambda args
|
||||||
|
(set! props
|
||||||
|
(append props args)))))
|
||||||
|
(annotate! form prop+)
|
||||||
|
props)))
|
||||||
|
(or (= count 1) ; ugh
|
||||||
|
(begin
|
||||||
|
(read-line p)
|
||||||
|
(set! count (1+ count))))
|
||||||
|
(nb! `'(following-form-properties
|
||||||
|
:line ,n
|
||||||
|
:line-count ,count
|
||||||
|
,@props))
|
||||||
|
(nb! form))))
|
||||||
|
(loop (1+ (port-line p)) (read-line p)))))))
|
||||||
|
|
||||||
|
;;; entry points
|
||||||
|
|
||||||
|
(define (read-scheme-source-silently . files)
|
||||||
|
"See commentary in module (scripts read-scheme-source)."
|
||||||
|
(let* ((res '()))
|
||||||
|
(for-each (lambda (file)
|
||||||
|
(process file (lambda (e) (set! res (cons e res)))))
|
||||||
|
files)
|
||||||
|
(reverse res)))
|
||||||
|
|
||||||
|
(define (read-scheme-source . files)
|
||||||
|
"See commentary in module (scripts read-scheme-source)."
|
||||||
|
(for-each (lambda (file)
|
||||||
|
(process file (lambda (e) (write e) (newline))))
|
||||||
|
files))
|
||||||
|
|
||||||
|
;; Recognize: (quote (SYM :TAG1 VAL1 :TAG2 VAL2 ...))
|
||||||
|
;; and return alist: ((TAG1 . VAL1) (TAG2 . VAL2) ...)
|
||||||
|
;; where the tags are symbols.
|
||||||
|
;;
|
||||||
|
(define (quoted? sym form)
|
||||||
|
(and (list? form)
|
||||||
|
(= 2 (length form))
|
||||||
|
(eq? 'quote (car form))
|
||||||
|
(let ((inside (cadr form)))
|
||||||
|
(and (list? inside)
|
||||||
|
(< 0 (length inside))
|
||||||
|
(eq? sym (car inside))
|
||||||
|
(let loop ((ls (cdr inside)) (alist '()))
|
||||||
|
(if (null? ls)
|
||||||
|
alist ; retval
|
||||||
|
(let ((first (car ls)))
|
||||||
|
(or (symbol? first)
|
||||||
|
(error "bad list!"))
|
||||||
|
(loop (cddr ls)
|
||||||
|
(acons (string->symbol
|
||||||
|
(substring (symbol->string first) 1))
|
||||||
|
(cadr ls)
|
||||||
|
alist)))))))))
|
||||||
|
|
||||||
|
;; Filter FORMS, combining contiguous comment forms that have the same number
|
||||||
|
;; of leading semicolons. Do not include in them whitespace lines.
|
||||||
|
;; Whitespace lines outside of such comment groupings are ignored, as are
|
||||||
|
;; hash-bang comments. All other forms are passed through unchanged.
|
||||||
|
;;
|
||||||
|
(define (clump forms)
|
||||||
|
(let loop ((forms forms) (acc '()) (pass-this-one-through? #f))
|
||||||
|
(if (null? forms)
|
||||||
|
(reverse acc) ; retval
|
||||||
|
(let ((form (car forms)))
|
||||||
|
(cond (pass-this-one-through?
|
||||||
|
(loop (cdr forms) (cons form acc) #f))
|
||||||
|
((quoted? 'following-form-properties form)
|
||||||
|
(loop (cdr forms) (cons form acc) #t))
|
||||||
|
((quoted? 'whitespace form) ;;; ignore
|
||||||
|
(loop (cdr forms) acc #f))
|
||||||
|
((quoted? 'hash-bang-comment form) ;;; ignore for now
|
||||||
|
(loop (cdr forms) acc #f))
|
||||||
|
((quoted? 'comment form)
|
||||||
|
=> (lambda (alist)
|
||||||
|
(let cloop ((inner-forms (cdr forms))
|
||||||
|
(level (assq-ref alist 'leading-semicolons))
|
||||||
|
(text (list (assq-ref alist 'text))))
|
||||||
|
(let ((up (lambda ()
|
||||||
|
(loop inner-forms
|
||||||
|
(cons (cons level (reverse text))
|
||||||
|
acc)
|
||||||
|
#f))))
|
||||||
|
(if (null? inner-forms)
|
||||||
|
(up)
|
||||||
|
(let ((inner-form (car inner-forms)))
|
||||||
|
(cond ((quoted? 'comment inner-form)
|
||||||
|
=> (lambda (inner-alist)
|
||||||
|
(let ((new-level
|
||||||
|
(assq-ref
|
||||||
|
inner-alist
|
||||||
|
'leading-semicolons)))
|
||||||
|
(if (= new-level level)
|
||||||
|
(cloop (cdr inner-forms)
|
||||||
|
level
|
||||||
|
(cons (assq-ref
|
||||||
|
inner-alist
|
||||||
|
'text)
|
||||||
|
text))
|
||||||
|
(up)))))
|
||||||
|
(else (up)))))))))
|
||||||
|
(else (loop (cdr forms) (cons form acc) #f)))))))
|
||||||
|
|
||||||
|
;;; script entry point
|
||||||
|
|
||||||
|
(define main read-scheme-source)
|
||||||
|
|
||||||
|
;;; read-scheme-source ends here
|
313
scripts/snarf-check-and-output-texi
Executable file
313
scripts/snarf-check-and-output-texi
Executable file
|
@ -0,0 +1,313 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main="(module-ref (resolve-module '(scripts snarf-check-and-output-texi)) 'main)"
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; snarf-check-and-output-texi --- called by the doc snarfer.
|
||||||
|
|
||||||
|
;; Copyright (C) 2001 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Michael Livshin
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts snarf-check-and-output-texi)
|
||||||
|
:use-module (ice-9 streams)
|
||||||
|
:use-module (ice-9 match)
|
||||||
|
:export (snarf-check-and-output-texi))
|
||||||
|
|
||||||
|
;;; why aren't these in some module?
|
||||||
|
|
||||||
|
(define-macro (when cond . body)
|
||||||
|
`(if ,cond (begin ,@body)))
|
||||||
|
|
||||||
|
(define-macro (unless cond . body)
|
||||||
|
`(if (not ,cond) (begin ,@body)))
|
||||||
|
|
||||||
|
(define *manual-flag* #f)
|
||||||
|
|
||||||
|
(define (snarf-check-and-output-texi . flags)
|
||||||
|
(if (member "--manual" flags)
|
||||||
|
(set! *manual-flag* #t))
|
||||||
|
(process-stream (current-input-port)))
|
||||||
|
|
||||||
|
(define (process-stream port)
|
||||||
|
(let loop ((input (stream-map (match-lambda
|
||||||
|
(('id . s)
|
||||||
|
(cons 'id (string->symbol s)))
|
||||||
|
(('int_dec . s)
|
||||||
|
(cons 'int (string->number s)))
|
||||||
|
(('int_oct . s)
|
||||||
|
(cons 'int (string->number s 8)))
|
||||||
|
(('int_hex . s)
|
||||||
|
(cons 'int (string->number s 16)))
|
||||||
|
((and x (? symbol?))
|
||||||
|
(cons x x))
|
||||||
|
((and x (? string?))
|
||||||
|
(cons 'string x))
|
||||||
|
(x x))
|
||||||
|
(make-stream (lambda (s)
|
||||||
|
(let loop ((s s))
|
||||||
|
(cond
|
||||||
|
((stream-null? s) #t)
|
||||||
|
((eq? 'eol (stream-car s))
|
||||||
|
(loop (stream-cdr s)))
|
||||||
|
(else (cons (stream-car s) (stream-cdr s))))))
|
||||||
|
(port->stream port read)))))
|
||||||
|
|
||||||
|
(unless (stream-null? input)
|
||||||
|
(let ((token (stream-car input)))
|
||||||
|
(if (eq? (car token) 'snarf_cookie)
|
||||||
|
(dispatch-top-cookie (stream-cdr input)
|
||||||
|
loop)
|
||||||
|
(loop (stream-cdr input)))))))
|
||||||
|
|
||||||
|
(define (dispatch-top-cookie input cont)
|
||||||
|
|
||||||
|
(when (stream-null? input)
|
||||||
|
(error 'syntax "premature end of file"))
|
||||||
|
|
||||||
|
(let ((token (stream-car input)))
|
||||||
|
(cond
|
||||||
|
((eq? (car token) 'brace_open)
|
||||||
|
(consume-multiline (stream-cdr input)
|
||||||
|
cont))
|
||||||
|
(else
|
||||||
|
(consume-upto-cookie process-singleline
|
||||||
|
input
|
||||||
|
cont)))))
|
||||||
|
|
||||||
|
(define (consume-upto-cookie process input cont)
|
||||||
|
(let loop ((acc '()) (input input))
|
||||||
|
|
||||||
|
(when (stream-null? input)
|
||||||
|
(error 'syntax "premature end of file in directive context"))
|
||||||
|
|
||||||
|
(let ((token (stream-car input)))
|
||||||
|
(cond
|
||||||
|
((eq? (car token) 'snarf_cookie)
|
||||||
|
(process (reverse! acc))
|
||||||
|
(cont (stream-cdr input)))
|
||||||
|
|
||||||
|
(else (loop (cons token acc) (stream-cdr input)))))))
|
||||||
|
|
||||||
|
(define (consume-multiline input cont)
|
||||||
|
(begin-multiline)
|
||||||
|
|
||||||
|
(let loop ((input input))
|
||||||
|
|
||||||
|
(when (stream-null? input)
|
||||||
|
(error 'syntax "premature end of file in multiline context"))
|
||||||
|
|
||||||
|
(let ((token (stream-car input)))
|
||||||
|
(cond
|
||||||
|
((eq? (car token) 'brace_close)
|
||||||
|
(end-multiline)
|
||||||
|
(cont (stream-cdr input)))
|
||||||
|
|
||||||
|
(else (consume-upto-cookie process-multiline-directive
|
||||||
|
input
|
||||||
|
loop))))))
|
||||||
|
|
||||||
|
(define *file* #f)
|
||||||
|
(define *line* #f)
|
||||||
|
(define *c-function-name* #f)
|
||||||
|
(define *function-name* #f)
|
||||||
|
(define *snarf-type* #f)
|
||||||
|
(define *args* #f)
|
||||||
|
(define *sig* #f)
|
||||||
|
(define *docstring* #f)
|
||||||
|
|
||||||
|
(define (begin-multiline)
|
||||||
|
(set! *file* #f)
|
||||||
|
(set! *line* #f)
|
||||||
|
(set! *c-function-name* #f)
|
||||||
|
(set! *function-name* #f)
|
||||||
|
(set! *snarf-type* #f)
|
||||||
|
(set! *args* #f)
|
||||||
|
(set! *sig* #f)
|
||||||
|
(set! *docstring* #f))
|
||||||
|
|
||||||
|
(define *primitive-deffnx-signature* "@deffnx {Scheme Procedure} ")
|
||||||
|
(define *primitive-deffnx-sig-length* (string-length *primitive-deffnx-signature*))
|
||||||
|
|
||||||
|
(define (end-multiline)
|
||||||
|
(let* ((req (car *sig*))
|
||||||
|
(opt (cadr *sig*))
|
||||||
|
(var (caddr *sig*))
|
||||||
|
(all (+ req opt var)))
|
||||||
|
(if (and (not (eqv? *snarf-type* 'register))
|
||||||
|
(not (= (length *args*) all)))
|
||||||
|
(error (format #f "~A:~A: ~A's C implementation takes ~A args (should take ~A)"
|
||||||
|
*file* *line* name (length *args*) all)))
|
||||||
|
(let ((nice-sig
|
||||||
|
(if (eq? *snarf-type* 'register)
|
||||||
|
*function-name*
|
||||||
|
(with-output-to-string
|
||||||
|
(lambda ()
|
||||||
|
(format #t "~A" *function-name*)
|
||||||
|
(let loop-req ((args *args*) (r 0))
|
||||||
|
(if (< r req)
|
||||||
|
(begin
|
||||||
|
(format #t " ~A" (car args))
|
||||||
|
(loop-req (cdr args) (+ 1 r)))
|
||||||
|
(let loop-opt ((o 0) (args args) (tail '()))
|
||||||
|
(if (< o opt)
|
||||||
|
(begin
|
||||||
|
(format #t " [~A" (car args))
|
||||||
|
(loop-opt (+ 1 o) (cdr args) (cons #\] tail)))
|
||||||
|
(begin
|
||||||
|
(if (> var 0)
|
||||||
|
(format #t " . ~A"
|
||||||
|
(car args)))
|
||||||
|
(let loop-tail ((tail tail))
|
||||||
|
(if (not (null? tail))
|
||||||
|
(begin
|
||||||
|
(format #t "~A" (car tail))
|
||||||
|
(loop-tail (cdr tail))))))))))))))
|
||||||
|
(scm-deffnx
|
||||||
|
(if (and *manual-flag* (eq? *snarf-type* 'primitive))
|
||||||
|
(with-output-to-string
|
||||||
|
(lambda ()
|
||||||
|
(format #t "@deffnx {C Function} ~A (" *c-function-name*)
|
||||||
|
(unless (null? *args*)
|
||||||
|
(format #t "~A" (car *args*))
|
||||||
|
(let loop ((args (cdr *args*)))
|
||||||
|
(unless (null? args)
|
||||||
|
(format #t ", ~A" (car args))
|
||||||
|
(loop (cdr args)))))
|
||||||
|
(format #t ")\n")))
|
||||||
|
#f)))
|
||||||
|
(format #t "\n~A\n" *function-name*)
|
||||||
|
(format #t "@c snarfed from ~A:~A\n" *file* *line*)
|
||||||
|
(format #t "@deffn {Scheme Procedure} ~A\n" nice-sig)
|
||||||
|
(let loop ((strings *docstring*) (scm-deffnx scm-deffnx))
|
||||||
|
(cond ((null? strings))
|
||||||
|
((or (not scm-deffnx)
|
||||||
|
(and (>= (string-length (car strings))
|
||||||
|
*primitive-deffnx-sig-length*)
|
||||||
|
(string=? (substring (car strings)
|
||||||
|
0 *primitive-deffnx-sig-length*)
|
||||||
|
*primitive-deffnx-signature*)))
|
||||||
|
(display (car strings))
|
||||||
|
(loop (cdr strings) scm-deffnx))
|
||||||
|
(else (display scm-deffnx)
|
||||||
|
(loop strings #f))))
|
||||||
|
(display "\n")
|
||||||
|
(display "@end deffn\n"))))
|
||||||
|
|
||||||
|
(define (texi-quote s)
|
||||||
|
(let rec ((i 0))
|
||||||
|
(if (= i (string-length s))
|
||||||
|
""
|
||||||
|
(string-append (let ((ss (substring s i (+ i 1))))
|
||||||
|
(if (string=? ss "@")
|
||||||
|
"@@"
|
||||||
|
ss))
|
||||||
|
(rec (+ i 1))))))
|
||||||
|
|
||||||
|
(define (process-multiline-directive l)
|
||||||
|
|
||||||
|
(define do-args
|
||||||
|
(match-lambda
|
||||||
|
|
||||||
|
(('(paren_close . paren_close))
|
||||||
|
'())
|
||||||
|
|
||||||
|
(('(comma . comma) rest ...)
|
||||||
|
(do-args rest))
|
||||||
|
|
||||||
|
(('(id . SCM) ('id . name) rest ...)
|
||||||
|
(cons name (do-args rest)))
|
||||||
|
|
||||||
|
(x (error (format #f "invalid argument syntax: ~A" (map cdr x))))))
|
||||||
|
|
||||||
|
(define do-arglist
|
||||||
|
(match-lambda
|
||||||
|
|
||||||
|
(('(paren_open . paren_open) '(id . void) '(paren_close . paren_close))
|
||||||
|
'())
|
||||||
|
|
||||||
|
(('(paren_open . paren_open) rest ...)
|
||||||
|
(do-args rest))
|
||||||
|
|
||||||
|
(x (error (format #f "invalid arglist syntax: ~A" (map cdr x))))))
|
||||||
|
|
||||||
|
(define do-command
|
||||||
|
(match-lambda
|
||||||
|
|
||||||
|
(('cname ('id . name))
|
||||||
|
(set! *c-function-name* (texi-quote (symbol->string name))))
|
||||||
|
|
||||||
|
(('fname ('string . name))
|
||||||
|
(set! *function-name* (texi-quote name)))
|
||||||
|
|
||||||
|
(('type ('id . type))
|
||||||
|
(set! *snarf-type* type))
|
||||||
|
|
||||||
|
(('type ('int . num))
|
||||||
|
(set! *snarf-type* num))
|
||||||
|
|
||||||
|
(('location ('string . file) ('int . line))
|
||||||
|
(set! *file* file)
|
||||||
|
(set! *line* line))
|
||||||
|
|
||||||
|
(('arglist rest ...)
|
||||||
|
(set! *args* (do-arglist rest)))
|
||||||
|
|
||||||
|
(('argsig ('int . req) ('int . opt) ('int . var))
|
||||||
|
(set! *sig* (list req opt var)))
|
||||||
|
|
||||||
|
(x (error (format #f "unknown doc attribute: ~A" x)))))
|
||||||
|
|
||||||
|
(define do-directive
|
||||||
|
(match-lambda
|
||||||
|
|
||||||
|
((('id . command) rest ...)
|
||||||
|
(do-command (cons command rest)))
|
||||||
|
|
||||||
|
((('string . string) ...)
|
||||||
|
(set! *docstring* string))
|
||||||
|
|
||||||
|
(x (error (format #f "unknown doc attribute syntax: ~A" x)))))
|
||||||
|
|
||||||
|
(do-directive l))
|
||||||
|
|
||||||
|
(define (process-singleline l)
|
||||||
|
|
||||||
|
(define do-argpos
|
||||||
|
(match-lambda
|
||||||
|
((('id . name) ('int . pos) ('int . line))
|
||||||
|
(let ((idx (list-index *args* name)))
|
||||||
|
(when idx
|
||||||
|
(unless (= (+ idx 1) pos)
|
||||||
|
(display (format #f "~A:~A: wrong position for argument ~A: ~A (should be ~A)\n"
|
||||||
|
*file* line name pos (+ idx 1))
|
||||||
|
(current-error-port))))))
|
||||||
|
(x #f)))
|
||||||
|
|
||||||
|
(define do-command
|
||||||
|
(match-lambda
|
||||||
|
(('(id . argpos) rest ...)
|
||||||
|
(do-argpos rest))
|
||||||
|
(x (error (format #f "unknown check: ~A" x)))))
|
||||||
|
|
||||||
|
(when *function-name*
|
||||||
|
(do-command l)))
|
||||||
|
|
||||||
|
(define main snarf-check-and-output-texi)
|
88
scripts/snarf-guile-m4-docs
Executable file
88
scripts/snarf-guile-m4-docs
Executable file
|
@ -0,0 +1,88 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts snarf-guile-m4-docs)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; snarf-guile-m4-docs --- Parse guile.m4 comments for texi documentation
|
||||||
|
|
||||||
|
;; Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen <ttn@gnu.org>
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: snarf-guile-m4-docs FILE
|
||||||
|
;;
|
||||||
|
;; Grep FILE for comments preceding macro definitions, massage
|
||||||
|
;; them into valid texi, and display to stdout. For each comment,
|
||||||
|
;; lines preceding "^# Usage:" are discarded.
|
||||||
|
;;
|
||||||
|
;; TODO: Generalize.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts snarf-guile-m4-docs)
|
||||||
|
:use-module (ice-9 rdelim)
|
||||||
|
:export (snarf-guile-m4-docs))
|
||||||
|
|
||||||
|
(define (display-texi lines)
|
||||||
|
(display "@deffn {Autoconf Macro}")
|
||||||
|
(for-each (lambda (line)
|
||||||
|
(display (cond ((and (>= (string-length line) 2)
|
||||||
|
(string=? "# " (substring line 0 2)))
|
||||||
|
(substring line 2))
|
||||||
|
((string=? "#" (substring line 0 1))
|
||||||
|
(substring line 1))
|
||||||
|
(else line)))
|
||||||
|
(newline))
|
||||||
|
lines)
|
||||||
|
(display "@end deffn")
|
||||||
|
(newline) (newline))
|
||||||
|
|
||||||
|
(define (prefix? line sub)
|
||||||
|
(false-if-exception
|
||||||
|
(string=? sub (substring line 0 (string-length sub)))))
|
||||||
|
|
||||||
|
(define (massage-usage line)
|
||||||
|
(let loop ((line (string->list line)) (acc '()))
|
||||||
|
(if (null? line)
|
||||||
|
(list (list->string (reverse acc)))
|
||||||
|
(loop (cdr line)
|
||||||
|
(cons (case (car line)
|
||||||
|
((#\( #\) #\,) #\space)
|
||||||
|
(else (car line)))
|
||||||
|
acc)))))
|
||||||
|
|
||||||
|
(define (snarf-guile-m4-docs . args)
|
||||||
|
(let* ((p (open-file (car args) "r"))
|
||||||
|
(next (lambda () (read-line p))))
|
||||||
|
(let loop ((line (next)) (acc #f))
|
||||||
|
(or (eof-object? line)
|
||||||
|
(cond ((prefix? line "# Usage:")
|
||||||
|
(loop (next) (massage-usage (substring line 8))))
|
||||||
|
((prefix? line "AC_DEFUN")
|
||||||
|
(display-texi (reverse acc))
|
||||||
|
(loop (next) #f))
|
||||||
|
((and acc (prefix? line "#"))
|
||||||
|
(loop (next) (cons line acc)))
|
||||||
|
(else
|
||||||
|
(loop (next) #f)))))))
|
||||||
|
|
||||||
|
(define main snarf-guile-m4-docs)
|
||||||
|
|
||||||
|
;;; snarf-guile-m4-docs ends here
|
113
scripts/use2dot
Executable file
113
scripts/use2dot
Executable file
|
@ -0,0 +1,113 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# aside from this initial boilerplate, this is actually -*- scheme -*- code
|
||||||
|
main='(module-ref (resolve-module '\''(scripts use2dot)) '\'main')'
|
||||||
|
exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
|
||||||
|
!#
|
||||||
|
;;; use2dot --- Display module dependencies as a DOT specification
|
||||||
|
|
||||||
|
;; Copyright (C) 2001 Free Software Foundation, Inc.
|
||||||
|
;;
|
||||||
|
;; 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, 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 software; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
;; Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
;;; Author: Thien-Thi Nguyen
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Usage: use2dot [OPTIONS] [FILE ...]
|
||||||
|
;; Display to stdout a DOT specification that describes module dependencies
|
||||||
|
;; in FILEs.
|
||||||
|
;;
|
||||||
|
;; A top-level `use-modules' form or a `:use-module' `define-module'-component
|
||||||
|
;; results in a "solid" style edge.
|
||||||
|
;;
|
||||||
|
;; An `:autoload' `define-module'-component results in a "dotted" style edge
|
||||||
|
;; with label "N" indicating that N names are responsible for triggering the
|
||||||
|
;; autoload. [The "N" label is not implemented.]
|
||||||
|
;;
|
||||||
|
;; A top-level `load' or `primitive-load' form results in a a "bold" style
|
||||||
|
;; edge to a node named with either the file name if the `load' argument is a
|
||||||
|
;; string, or "[computed in FILE]" otherwise.
|
||||||
|
;;
|
||||||
|
;; Options:
|
||||||
|
;; -m, --default-module MOD -- Set MOD as the default module (for top-level
|
||||||
|
;; `use-modules' forms that do not follow some
|
||||||
|
;; `define-module' form in a file). MOD should be
|
||||||
|
;; be a list or `#f', in which case such top-level
|
||||||
|
;; `use-modules' forms are effectively ignored.
|
||||||
|
;; Default value: `(guile-user)'.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (scripts use2dot)
|
||||||
|
:autoload (ice-9 getopt-long) (getopt-long)
|
||||||
|
:use-module ((srfi srfi-13) :select (string-join))
|
||||||
|
:use-module ((scripts frisk)
|
||||||
|
:select (make-frisker edge-type edge-up edge-down))
|
||||||
|
:export (use2dot))
|
||||||
|
|
||||||
|
(define *default-module* '(guile-user))
|
||||||
|
|
||||||
|
(define (q s) ; quote
|
||||||
|
(format #f "~S" s))
|
||||||
|
|
||||||
|
(define (vv pairs) ; => ("var=val" ...)
|
||||||
|
(map (lambda (pair)
|
||||||
|
(format #f "~A=~A" (car pair) (cdr pair)))
|
||||||
|
pairs))
|
||||||
|
|
||||||
|
(define (>>header)
|
||||||
|
(format #t "digraph use2dot {\n")
|
||||||
|
(for-each (lambda (s) (format #t " ~A;\n" s))
|
||||||
|
(vv `((label . ,(q "Guile Module Dependencies"))
|
||||||
|
;;(rankdir . LR)
|
||||||
|
;;(size . ,(q "7.5,10"))
|
||||||
|
(ratio . fill)
|
||||||
|
;;(nodesep . ,(q "0.05"))
|
||||||
|
))))
|
||||||
|
|
||||||
|
(define (>>body edges)
|
||||||
|
(for-each
|
||||||
|
(lambda (edge)
|
||||||
|
(format #t " \"~A\" -> \"~A\"" (edge-down edge) (edge-up edge))
|
||||||
|
(cond ((case (edge-type edge)
|
||||||
|
((autoload) '((style . dotted) (fontsize . 5)))
|
||||||
|
((computed) '((style . bold)))
|
||||||
|
(else #f))
|
||||||
|
=> (lambda (etc)
|
||||||
|
(format #t " [~A]" (string-join (vv etc) ",")))))
|
||||||
|
(format #t ";\n"))
|
||||||
|
edges))
|
||||||
|
|
||||||
|
(define (>>footer)
|
||||||
|
(format #t "}"))
|
||||||
|
|
||||||
|
(define (>> edges)
|
||||||
|
(>>header)
|
||||||
|
(>>body edges)
|
||||||
|
(>>footer))
|
||||||
|
|
||||||
|
(define (use2dot . args)
|
||||||
|
(let* ((parsed-args (getopt-long (cons "use2dot" args) ;;; kludge
|
||||||
|
'((default-module
|
||||||
|
(single-char #\m) (value #t)))))
|
||||||
|
(=m (option-ref parsed-args 'default-module *default-module*))
|
||||||
|
(scan (make-frisker `(default-module . ,=m)))
|
||||||
|
(files (option-ref parsed-args '() '())))
|
||||||
|
(>> (reverse ((scan files) 'edges)))))
|
||||||
|
|
||||||
|
(define main use2dot)
|
||||||
|
|
||||||
|
;;; use2dot ends here
|
Loading…
Add table
Add a link
Reference in a new issue