|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
/*
* This file:
* https://anggtwu.net/lisptree/lisptree.mac.html
* https://anggtwu.net/lisptree/lisptree.mac
* (find-lisptree "lisptree.mac")
* See: https://anggtwu.net/lisptree.html (<- has screenshots!)
* https://github.com/edrx/lisptree
* Author: Eduardo Ochs <eduardoochs@gmail.com>
* License: Public Domain.
* Version: 2025oct04
*
* LispTree Draw Maxima objects as trees (using Lisp).
* This Maxima command
*
* lisptree(f(2,g(3,4));
*
* prints this:
*
* f__.
* | |
* 2 g__.
* | |
* 3 4
*
* See the "introduction" below for more details.
*
* «.introduction» (to "introduction")
* «.introduction-tests» (to "introduction-tests")
* «.download-test» (to "download-test")
* «.types» (to "types")
* «.load-lisp» (to "load-lisp")
* «.format» (to "format")
* «.atoms» (to "atoms")
* «.atoms-tests» (to "atoms-tests")
* «.lisptree0» (to "lisptree0")
* «.lisptree0-tests» (to "lisptree0-tests")
* «.config» (to "config")
* «.config-tests» (to "config-tests")
* «.lisptree» (to "lisptree")
* «.lisptree-tests» (to "lisptree-tests")
*/
/* «introduction» (to ".introduction")
* The main top-level function in this file is `lisptree', that draws
* Maxima objects as trees, like this:
*
* f__.
* | |
* lisptree(f(2,g(3,4)); ==> 2 g__.
* | |
* 3 4
*
* Lisptree has some support for drawing as trees Maxima objects whose
* tree representations are not obvious. Here are some examples:
*
* lisptree(a[b,c][d,e](f,g)(h,i));
*
* ap_____________________.__.
* | | |
* ap_______________.__. h i
* | | |
* ==> [_]________.__. f g
* | | |
* [_]__.__. d e
* | | |
* a b c
*
* format([args]) := apply(?format, append([false], args));
* lisptree(fundef(format));
*
* :=______.
* | |
* format apply____.
* | | |
* ==> [ ?format append__.
* | | |
* args [ args
* |
* false
*
* lisptree0_config('lisp)$
* lisptree(fundef(format));
*
* ":="_____.
* | |
* $FORMAT $APPLY__.
* | | |
* ==> "[" FORMAT $APPEND__.
* | | |
* $ARGS "[" $ARGS
* |
* NIL
*/
/* «introduction-tests» (to ".introduction-tests")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
lisptree(a[b,c][d,e](f,g)(h,i));
format([args]) := apply(?format, append([false], args))$
fundef(format);
lisptree(fundef(format));
lisptree0_config('lisp)$
lisptree(fundef(format));
*/
/* «download-test» (to ".download-test")
** Download Lisptree in /tmp/lisptree/ and test it there.
* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
rm -Rfv /tmp/lisptree/
mkdir /tmp/lisptree/
git clone https://github.com/edrx/lisptree /tmp/lisptree/
maxima --no-init
load("/tmp/lisptree/lisptree.mac");
lisptree(a[b,c][d,e](f,g)(h,i));
lisptree(fundef(format));
lisptree0_config('lisp)$
lisptree(fundef(format));
*/
/* «types» (to ".types")
* LispTree uses these "types" of objects:
* A "Maxima object" is something like f(2,g(3,4)).
* A "Maxima tree" is something like [f,2,[g,3,4]].
* A "Lispy tree " is something like ($F 2 ($G 3 4)).
* A "2D tree" is something like this,
*
* f__.
* | |
* 2 g__.
* | |
* 3 4
*
* as a string with newlines.
* The main functions in this file do these conversions:
*
* lisptree: Maxima object --> Maxima tree --> Lispy Tree --> 2D tree
* lisptreeq: Maxima object --> Maxima tree --> Lispy Tree --> 2D tree
* lispytree: Maxima object --> Maxima tree --> Lispy tree --> string
* lispytreeq: Maxima object --> Maxima tree --> Lispy tree --> string
* lisptree0: Maxima object --> Maxima tree
*
* The versions that end in "q" are macros that quote their arguments.
* `lisptree0' is very configurable. See `lisptree0_config' below.
*/
/* «load-lisp» (to ".load-lisp")
* See: (find-lisptree "lisptree.lisp")
* (find-lisptree "lisptree-middle.lisp")
*/
lisptreedir : pathname_directory(load_pathname);
load(concat(lisptreedir, "lisptree.lisp"));
load(concat(lisptreedir, "lisptree-middle.lisp"));
/* «format» (to ".format")
*/
format([args]) := apply(?format, append([false], args));
format0 (o) := format("~s",o); /* the Lisp representation of o, as a string */
stringp (o) := ?stringp(o); /* instead of an autoload to stringproc */
/* «atoms» (to ".atoms")
* See: (find-maximanode "Lisp and Maxima" "Lisp symbol" "?foo")
* (find-maximanode "Nouns and Verbs" "verb form" "$")
* (find-maximanode "Nouns and Verbs" "noun form" "%")
* (find-es "maxima" "low-level-nouns")
*
* Note: THIS IS BUGGY!
* See the test below!
*/
lisptree0_string0(o) := o; /* send strings to Lisp unchanged */
lisptree0_string1(o) := format("~s", o); /* add double quotes to all strings */
lisptree0_number0(o) := o; /* send numbers to Lisp unchanged */
lisptree0_number1(o) := string(o);
verbp (o) := symbolp(o) and (o = verbify(o));
nounp (o) := symbolp(o) and (o = nounify(o));
specialnounp (o) := nounp(o) and (string(o)#concat("",o));
lisptree0_symbol0(o) := o; /* send symbols to Lisp unchanged */
lisptree0_symbol1(o) := format0(o); /* Low-level names: %FOO, $FOO and FOO */
lisptree0_symbol3(o) :=
if nounp(o) then concat("'",string(o)) /* %DERIVATIVE -> 'diff */
else string(o); /* $FOO -> foo, FOO -> ?foo */
lisptree0_symbol4(o) :=
if specialnounp(o) then concat("",o) /* %DERIVATIVE -> derivative */
elseif nounp(o) then concat("'",o) /* %F -> 'f */
else string(o); /* $FOO -> foo, FOO -> ?foo */
/* «atoms-tests» (to ".atoms-tests")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
_qfoo : op('foo(42));
_qdiff : op('diff(y,x));
mysymbols : [?foo, foo, _qfoo, diff, _qdiff];
lsymbol(n) := parse_string(concat("lisptree0_symbol", n));
lsyline(n) := map(lsymbol(n),mysymbols);
lsylines : matrix(lsyline(0), lsyline(1), lsyline(3), lsyline(4));
propline(o) := [format0(o), verbp(o), nounp(o), specialnounp(o)];
topline : rhs(fundef(propline));
otherlines : map('propline, mysymbols);
proplines : apply('matrix, append([topline],otherlines));
*/
/* «config» (to ".config")
*/
lisptree0_config ([opts]) := makelist(lisptree0_config1(opt), opt, opts);
lisptree0_config1(opt) :=
if opt = 'nq then lisptree0_string (o) := lisptree0_string0(o) /* no quotes */
elseif opt = 'q then lisptree0_string (o) := lisptree0_string1(o) /* use quotes */
elseif opt = 'n0 then lisptree0_number (o) := lisptree0_number0(o)
elseif opt = 'n1 then lisptree0_number (o) := lisptree0_number1(o)
elseif opt = 's0 then lisptree0_symbol (o) := lisptree0_symbol0(o)
elseif opt = 's1 then lisptree0_symbol (o) := lisptree0_symbol1(o)
elseif opt = 's3 then lisptree0_symbol (o) := lisptree0_symbol3(o)
elseif opt = 's4 then lisptree0_symbol (o) := lisptree0_symbol4(o)
elseif opt = 'raw then lisptree0_config('nq,'n0,'s0)
elseif opt = 'lisp then lisptree0_config( 'q,'n1,'s1)
elseif opt = 'maxima then lisptree0_config('nq,'n1,'s4)
elseif opt = 'Maxima then lisptree0_config( 'q,'n1,'s4)
else error();
/* «config-tests» (to ".config-tests")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
lisptree0_config(nq,s0)$ lisptree0(f("foo", ?f));
lisptree0_config(q, s4)$ lisptree0(f("foo", ?f));
fundef(format);
lisptree0_config('raw)$ lisptree(fundef(format));
lisptree0_config('lisp)$ lisptree(fundef(format));
lisptree0_config('maxima)$ lisptree(fundef(format));
lisptree0_config('Maxima)$ lisptree(fundef(format));
*/
/* «lisptree0» (to ".lisptree0")
*/
lisptree0_string (o) := lisptree0_string0(o); /* Default: don't add double quotes */
lisptree0_number (o) := lisptree0_string1(o); /* Default: convert to string */
lisptree0_symbol (o) := lisptree0_symbol3(o); /* Default: "'diff" */
lisptree0_apatom (o) := append([ lisptree0(op(o))], map(lisptree0, args(o)));
lisptree0_apother(o) := append(["ap", lisptree0(op(o))], map(lisptree0, args(o)));
lisptree0_subvarp(o) := append(["[_]", lisptree0(op(o))], map(lisptree0, args(o)));
lisptree0(o) :=
if stringp(o) then lisptree0_string (o)
elseif symbolp(o) then lisptree0_symbol (o)
elseif numberp(o) then lisptree0_number (o)
elseif subvarp(o) then lisptree0_subvarp(o)
elseif atom(op(o)) then lisptree0_apatom (o)
else lisptree0_apother(o);
/* «lisptree0-tests» (to ".lisptree0-tests")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
lisptree0(f(a,g(b,c)));
[f,a,[g,b,c]];
*/
/* «lisptree» (to ".lisptree")
* See: (find-lisptree "lisptree-middle.lisp")
* These are the high-level words.
*/
lispytree (o) := tolispytreestr(lisptree0(o));
lispytreeq(o) ::= block([simp:false], tolispytreestr(lisptree0(o)));
lisptree_ (o) := tolisptree2d_(lisptree0(o));
lisptree (o) := tolisptree2d (lisptree0(o));
lisptreeq (o) ::= block([simp:false], tolisptree2d(lisptree0(o)));
/* «lisptree-tests» (to ".lisptree-tests")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
lisptree0_config(nq,s0,n0)$ lisptreeq(a+2+3);
lisptree0_config(q, s3,n0)$ lisptreeq(a+2+3);
lisptree0_config(nq,s0,n0)$ lispytreeq(a+2+3);
lisptree0_config(q, s3,n0)$
lisptree (a+2+3);
lisptreeq(a+2+3);
lisptreeq(a[b][c][d]);
lisptreeq(a(b)(c)(d));
lisptree0_config(q, s0)$ lisptreeq('diff(x^2,x)); "%DERIVATIVE"$
lisptree0_config(nq,s4)$ lisptreeq('diff(x^2,x)); "derivative"$
lisptree0_config(nq,s3)$ lisptreeq('diff(x^2,x)); "'diff"$
lisptree0_config(q, s3)$ lisptreeq('diff(x^2,x)); "'diff"$
*/