2 # Author: Michael H. Hohn (mhhohn@lbl.gov)
4 # Copyright (c) 2006, The Regents of the University of California
6 # See legal.txt and license.txt
10 Extra tools for viewing l3 trees in various ways.
12 import re
, pdb
, sys
, pprint
, os
13 from pprint
import pprint
14 from l3lang
import ast
, utils
15 from l3lang
.globals import logger
17 from l3lang
.ast
import \
49 from l3lang
.ast
import TreeWork
54 def strip_comment(st
):
55 # strip comments off a repr() string -- uses \\n etc.
56 return (re
.sub(r
"#.*?\\n", "", st
))
58 def combine_newlines(st
):
59 # combine trailing form-feeds off a repr() string -- uses \\l etc.
60 return re
.sub(r
'(\\l){1,}$', r
'\\l', st
)
62 def leading_lines(str, num_lines
= 4, max_len
= 80):
63 # Return the first num_lines empty lines of str, each
64 # truncated to max_len
66 lines
= str.split("\n")
69 lines
= filter(lambda s
: len(s
) != 0 and (not s
.isspace()), lines
)
71 lines
= lines
[0:num_lines
]
78 lines
= map(shorten
, lines
)
87 # Trivial And Ugly -- but useful.
88 # Use a stream with .write() method.
90 # Indentation is handled by Nested() types; Immediates always print.
93 def prefix_dump(self
, stream
, indent
= 0):
94 stream
.write(str(self
._primary
[0]) + " ")
95 Immediate
.prefix_dump
= prefix_dump
97 def prefix_dump(self
, stream
, indent
= 0):
98 stream
.write(repr(self
._primary
[0]) + " ")
99 String
.prefix_dump
= prefix_dump
101 def prefix_dump(self
, stream
, indent
= 0):
103 a
.prefix_dump(stream
, indent
)
105 b
.prefix_dump(stream
, indent
)
106 Member
.prefix_dump
= prefix_dump
109 def prefix_dump(self
, stream
, indent
= 0):
110 # Output format is usually (name args)
111 full_name
= self
.__class
__.__name
__
121 print_name
= name_map
.get(full_name
, full_name
)
122 stream
.write("(%s " % print_name
)
125 for sub
in (self
._primary
):
126 stream
.write("\n" + "\t" * indent
) # nl / indent
127 sub
.prefix_dump(stream
, indent
)
131 ## stream.write("\n" + "\t" * indent) # nl / indent
132 Nested
.prefix_dump
= prefix_dump
134 def prefix_dump(self
, stream
, indent
= 0):
140 stream
.write("\n" + "\t" * indent
) # nl / indent
141 sub
.prefix_dump(stream
, indent
)
145 ## stream.write("\n" + "\t" * indent) # nl / indent
146 aList
.prefix_dump
= prefix_dump
149 #** infix tree formation (pretty-printing)
151 # Ignores precedence for now; that can be added in a separate pass
152 # providing annnotations.
155 # ----------------------
156 # Output format defaults to Python syntax; this may lead to invalid
157 # strings if l3's nesting abilities are used heavily (like a
158 # function definition inside an Environment, which in Python would be
159 # a `def` inside a dict ({}), and is invalid.
161 # A l3-syntax output formatter can be added later.
164 # ----------------------
165 # To find an error, a printout is needed. Thus, raising
166 # exceptions in printing routines is a bad idea. Instead, errors are
167 # inserted into the output as comments.
169 # Immediate.infix_string includes
176 # Types that don't (yet) need .infix_string():
181 #*** pretty-printer imports
182 from l3lang
.pretty
import \
193 B
= lambda : DocBreak(" ")
194 BW
= lambda s
: DocBreak(s
)
195 C
= lambda x
,y
: DocCons(x
, y
)
196 T
= lambda t
: DocText(t
)
197 G
= lambda x
: DocGroupAuto(x
)
198 GB
= lambda x
: DocGroupBreak(x
)
199 GF
= lambda x
: DocGroupFill(x
)
200 GFL
= lambda x
: DocGroupFlat(x
)
201 I
= lambda r
, x
: DocNest(r
, x
)
204 #*** main entry points
205 def get_infix_string(self
, width
, comment_dct
= {}):
206 ''' Return a pretty-printed representation of self.
207 The string width is kept below `width` when possible.
208 If the (tree id -> comment string) dict (comment_dct) is provided,
213 S
._comment
= comment_dct
215 # Comment printing requires a .setup() tree.
217 if not hasattr(self
, '_id'):
218 logger
.warn("get_infix_string: argument is not set up and "
219 "cannot be printed with comments.")
221 # Statement / expression distinction.
222 S
._in
_statement
= [True]
223 S
.es
= lambda : S
._in
_statement
.append(False) # expression start
224 S
.ee
= lambda : S
._in
_statement
.pop()
225 S
.ss
= lambda : S
._in
_statement
.append(True) # statement start
226 S
.se
= lambda : S
._in
_statement
.pop()
227 S
.in_statement
= lambda : S
._in
_statement
[-1]
229 return self
.infix_string(S
).toString(width
)
230 astType
.get_infix_string
= get_infix_string
231 aList
.get_infix_string
= get_infix_string
232 aNone
.get_infix_string
= get_infix_string
233 Native
.get_infix_string
= get_infix_string
235 def tree_difference(self
, self_tbl
, pptree
, pptree_tbl
):
236 ''' Compares trees (including comments) and returns a difference description.
237 For eql trees, returns "".
239 o_it
= self
.top_down()
240 pp_it
= pptree
.top_down()
242 try: o_nd
= o_it
.next()
243 except StopIteration: break
247 if o_nd
.eql_1(pp_nd
):
248 if self_tbl
.has_key(o_nd
._id
):
249 if self_tbl
[o_nd
._id
].eql_1(pptree_tbl
[pp_nd
._id
]):
252 return ("Tree comment difference from line %d, col %d\n"
253 " to line %d, col %d\n"
254 % (o_nd
._first
_char
[0], o_nd
._first
_char
[1],
255 pp_nd
._first
_char
[0], pp_nd
._first
_char
[1]))
259 return ("Tree difference: line %d, col %d\n original:\n%s\n"
262 (pp_nd
._first
_char
[0], pp_nd
._first
_char
[1],
263 str(o_nd
), str(pp_nd
)))
265 astType
.tree_difference
= tree_difference
267 def tree_difference(self
, self_tbl
, pptree
, pptree_tbl
):
269 Native
.tree_difference
= tree_difference
272 #*** comment functions
273 def with_comment(self
, S
, body
):
276 if S
._comment
.has_key(self
._id
):
277 # Multi-line comments must be properly indented.
278 # Form every line separately and assemble the group.
279 comm_lines
= S
._comment
[self
._id
].split('\n') # windows?
280 while comm_lines
[-1] == '': # Strip trailing blanks
283 for line
in comm_lines
:
284 comment |
= T("#" + line
) |
B()
285 return GB(comment | body
)
286 except AttributeError:
287 return body
# Ignore missing self._id
289 astType
.with_comment
= with_comment
290 aList
.with_comment
= with_comment
291 Native
.with_comment
= with_comment
295 def infix_string(self
, S
):
296 return self
.with_comment(S
, T(str(self
._primary
[0])))
297 Immediate
.infix_string
= infix_string
299 def infix_string(self
, S
):
300 # Using repr() introduces escaped escapes ('\\n' instead of '\n')
301 # so that `print repr(a)` == a.
302 # But using repr() inside another string without print is wrong
303 # when PARSING the contents:
307 # Parsing this will read \\n instead of \n. The \\n is correct
308 # only within a string-conversion pass.
310 # str(aa) converts unprintables into ascii
311 # repr(aa) converts unprintables into ascii and escapes when needed
313 # Here, we only want unprintables -> ascii plus correct quotes.
315 got
= lambda sub
: self
._primary
[0].find(sub
) != -1
319 raise Exception("String too complicated for infix_string.")
321 pstr
= '"""%s"""' % self
._primary
[0]
323 pstr
= "'''%s'''" % self
._primary
[0]
325 return self
.with_comment(S
, T(pstr
))
331 raise Exception("String too complicated for infix_string.")
333 pstr
= '"""%s"""' % self
._primary
[0]
335 pstr
= "'''%s'''" % self
._primary
[0]
337 pstr
= "'%s'" % self
._primary
[0]
339 pstr
= '"%s"' % self
._primary
[0]
341 return self
.with_comment(S
, T(pstr
))
342 String
.infix_string
= infix_string
346 def infix_string(self
, S
):
347 return self
.with_comment(S
, GB(T("program:") |
349 self
[0].infix_string(S
) ))))
350 Program
.infix_string
= infix_string
352 def infix_string(self
, S
):
353 return self
.with_comment(S
, GB(T("subdir:") |
355 self
[0].infix_string(S
) ))))
356 Subdir
.infix_string
= infix_string
358 def infix_string(self
, S
):
363 # is invalid; requires \ as break character:
367 # Or use GroupFill to force first element onto same line.
368 return self
.with_comment(S
, GF( T('return ') |
369 self
[0].infix_string(S
)))
370 Return
.infix_string
= infix_string
372 def infix_string(self
, S
):
375 body
= (T('{|') | self
[0].infix_string(S
) |
# args
378 self
[1].infix_string(S
))) |
# body
383 return self
.with_comment(S
, G(body
))
384 Function
.infix_string
= infix_string
386 def infix_string(self
, S
):
387 fname
= self
.calltree_str() # function name.
388 if fname
[0].isalpha():
389 # Standard prefix form f(a,b); ignore special cases for f.
390 body
= T(fname
) |
T('(')
392 body |
= (I(4, self
[1].infix_string(S
)) |
# arguments.
395 return self
.with_comment(S
, G(body
))
398 if self
.nargs() == 1:
399 # Assume unary prefix operator.
403 I(4, self
[1].infix_string(S
)) |
# arguments.
406 return self
.with_comment(S
, body
)
409 # Assume binary infix operator.
410 left
, right
= self
.positional_args()
413 left
.infix_string(S
) |
417 right
.infix_string(S
) |
420 return self
.with_comment(S
, body
)
421 Call
.infix_string
= infix_string
423 def infix_string(self
, S
):
426 return self
.with_comment(S
, G(a
.infix_string(S
) |
429 Member
.infix_string
= infix_string
431 def infix_string(self
, S
):
436 cond
, yes
, no
= self
._primary
441 I(4, B() | no
.infix_string(S
)))
446 if not S
.in_statement():
447 body
= T("# ERROR: For printing, If must not be in an expression.") |
B()
453 body |
= cond
.infix_string(S
)
456 body |
= T(":") |
I(4, B() | yes
.infix_string(S
)) | the_else
458 return self
.with_comment(S
, GB(body
))
459 If
.infix_string
= infix_string
461 def infix_string(self
, S
):
463 # Special case for `def foo(a,b): body`
468 Set(MarkerTyped(Symbol('LNAME'), Symbol('symbol')),
469 Function(MarkerTyped(Symbol('LARGS'), aList([])),
470 MarkerTyped(Symbol('LBODY'), aList([]))))):
472 body
= T('def ') | ma
['LNAME'].infix_string(S
) |
T('(')
474 body |
= ma
['LARGS'].infix_string(S
) |
T('):')
476 body |
= I(4, B() | ma
['LBODY'].infix_string(S
))
477 return self
.with_comment(S
, GB(body
))
480 lhs
, rhs
= self
._primary
481 return self
.with_comment(S
, GF(lhs
.infix_string(S
) |
483 rhs
.infix_string(S
)))
484 Set
.infix_string
= infix_string
486 def infix_string(self
, S
):
491 self
[0].infix_string(S
)))|
495 return self
.with_comment(S
, body
)
496 List
.infix_string
= infix_string
499 def infix_string(self
, S
):
500 body
= GF(T('if ("outline",') |
B() |
501 T(repr(self
.get_label())) |
504 body |
= I(4, B() | self
[0].infix_string(S
))
506 return self
.with_comment(S
, GB(body
))
507 cls_viewList
.infix_string
= infix_string
510 def infix_string(self
, S
):
515 self
[0].infix_string(S
)))|
519 return self
.with_comment(S
, body
)
520 Map
.infix_string
= infix_string
522 def infix_string(self
, S
):
526 I(1, self
[0].infix_string(S
)) |
529 return self
.with_comment(S
, body
)
530 Tuple
.infix_string
= infix_string
534 def infix_string(self
, S
):
536 aNone
.infix_string
= infix_string
538 def infix_string(self
, S
):
539 return self
.with_comment(S
, T(repr(self
._primary
[0])))
540 Native
.infix_string
= infix_string
543 def infix_string(self
, S
):
545 return self
.with_comment(S
, GFL( T('inline') |
B() | self
[0].infix_string(S
)))
546 Inline
.infix_string
= infix_string
548 def infix_string(self
, S
):
552 # inside program, def: ';' '\n' (no ',')
554 body
= body | sub
.infix_string(S
) |
BW(';')
555 body
= body
.head() # strip BW(';')
557 # inside list, dict: ' ' '\n' (always with ',')
559 body
= body | sub
.infix_string(S
) |
T(',') |
B()
560 body
= body
.head().head() # strip T(',') | B()
562 return self
.with_comment(S
, G( body
))
563 aList
.infix_string
= infix_string
568 # As of [Fri Sep 17 11:35:26 2004],
569 # A tree's ._id is used in
573 # (RamMem) storage.store / load
574 # storage.get_attribute / set_attributes
575 # (IncEval) storage.ie_.touch_setup / touch / get_timestamp
577 # (Env) env.bind_id / lookup_symbol_id
579 def print_references(storage
, tree_id
, indent
= 0):
580 # Print information about references to tree_id, from various
584 # print_references(storage, 140163)
586 # pprint(user_env.dump())
587 # print_info(storage, 140163)
589 tree
= storage
.load(tree_id
)
590 print ' '*indent
, 'id / string:', tree_id
, tree
.source_substring()
591 print ' '*indent
, 'tree:', tree
593 # Parent referring to tree.
594 parent_id
= tree
.parent_id()
595 if parent_id
is None:
596 print ' '*indent
, "no parent"
598 parent
= storage
.load(parent_id
)
599 print ' '*indent
, "index %d of parent %d" % (parent
.find_child_index(tree_id
),
602 # Children referring to tree
603 child_id_l
= tree
.childrens_ids()
604 for ch
in child_id_l
:
605 print ' '*indent
, "has child %d" % ch
606 if storage
.load(ch
).parent_id() != tree_id
:
607 print ' '*indent
, "warning: child has other parent"
610 for cmd_s
in ['tree._arg_env', # block
611 'tree._block_env', # block
612 'tree._def_env', # block
613 'tree._eval_env', # some Nested()s
614 'storage.get_attribute(tree_id, "interp_env")',
619 if env
._program
== tree
:
620 print ' '*indent
, cmd_s
, '._program'
622 # name -> value, tree may be value
623 # (name, 'ie_status') -> timestamp
625 if isinstance(tree
, Symbol
):
626 the_name
= tree
.as_index()
627 for nm
, val
in env
._bindings
.iteritems():
629 print ' '*indent
, cmd_s
, '._bindings[', repr(nm
), ']'
631 print ' '*indent
, cmd_s
, '._bindings[', repr(nm
), ']'
632 if nm
== (the_name
, 'ie_status'):
633 print ' '*indent
, cmd_s
, '._bindings[', \
634 repr((the_name
, 'ie_status')), ']'
636 # name -> id, tree_id may == id
637 for nm
, id in env
._bindings
_ids
.iteritems():
639 print ' '*indent
, cmd_s
, '._bindings_ids[', repr(nm
), ']'
641 except AttributeError:
642 print ' '*indent
, 'no ', cmd_s
, 'attribute'
645 def print_all_references(storage
, tree_id
, indent
= 0):
646 # Traverse all clones (recursively) and call print_references()
649 print ' '*indent
, "---------------------- original data"
650 print_references(storage
, tree_id
, indent
= indent
)
652 clone_l
= storage
.get_attribute(tree_id
, "interp_clone")
654 print ' '*indent
, "---------------------- clone data"
655 for clone
in clone_l
:
656 print_all_references(storage
, clone
, indent
= indent
+ 4)
660 #** print_info: prefix format tabular dump
661 def print_info(storage
, tree
,
666 per_level_indent
= 4,
671 # `custom` is a caller-chosen expression; may use `nd` for the
674 # Print id & timestamp with leading parts of the ast, in a prefix
676 # This prefix dump ignores clones.
678 lead
= space
* lead_indent
* per_level_indent
680 # lead id time [custom] indent node-string
681 print "%s%5s %6s %8s %s %s" % (lead
, 'id', 'time', custom
, '', 'node')
682 print "%s--------------------------------------------" % lead
683 for nd
, indent
in tree
.top_down_indented():
684 # id = nd._id fails w/o ._id attribute.
685 id = nd
.__dict
__.get('_id')
688 nd_str
= str(nd
) # Inefficient string formation...
691 if isinstance(nd
, (Nested
, aList
)):
692 nd_str
= nd_str
[0:nd_str
.find('(')]
695 if isinstance(nd
, (String
, Symbol
)):
696 if len(nd_str
) + indent
* per_level_indent
> node_width
and \
697 len(nd_str
) > max_node_len
:
698 off
= nd_str
.find('(')
699 cutoff
= max(off
+ 8,
700 abs(node_width
- indent
* per_level_indent
- off
))
701 nd_str
= nd_str
[0 : cutoff
] + " ...')"
703 # Print source macro.
704 if show_macros
and hasattr(nd
, '_macro_id'):
705 macro
= storage
.load(nd
._macro
_id
)
706 print "\n%s[ From macro:" % lead
707 print_info(storage
, macro
, show_macros
= show_macros
,
708 lead_indent
= indent
, custom
= custom
)
712 print "%s----- ---------- %s %s" % (
714 space
* per_level_indent
* indent
,
719 cus_val
= eval(custom
)
722 print "%s%5d %6s %8s %s %s" % (
725 storage
.ie_
.get_timestamp(id),
727 space
* per_level_indent
* indent
,
731 #** print_ast: prefix format dump, needs only ast.
736 per_level_indent
= 4,
739 # Print leading parts of the ast, in a prefix format.
741 lead
= space
* lead_indent
* per_level_indent
742 print "%s%5s %10s %s %s" % (lead
, 'id', 'time', '', 'node')
743 print "%s--------------------------------------------" % lead
744 for nd
, indent
in tree
.top_down_indented():
746 nd_str
= str(nd
) # Inefficient string formation...
749 if isinstance(nd
, (Nested
, aList
)):
750 nd_str
= nd_str
[0:nd_str
.find('(')]
753 if isinstance(nd
, (String
, Symbol
)):
754 if len(nd_str
) + indent
* per_level_indent
> node_width
and \
755 len(nd_str
) > max_node_len
:
756 off
= nd_str
.find('(')
757 cutoff
= max(off
+ 8,
758 abs(node_width
- indent
* per_level_indent
- off
))
759 nd_str
= nd_str
[0 : cutoff
] + " ...')"
761 print "%s----- ---------- %s %s" % (
763 space
* per_level_indent
* indent
,
769 #** print_all_info: prefix format tabular dump with clones.
770 def print_all_info(storage
, tree
,
771 per_level_indent
= 4,
774 # print id, timestamp and clone level information,
775 # with leading parts of the ast.
776 # This provides a long dump of all tree nodes and their clones;
777 # useful for comparing state between runs.
781 print "%5s %10s %5s %s %s" % ('id', 'time', 'clone', '', 'node')
782 print "--------------------------------------------"
783 geta
= storage
.get_attribute
784 for nd
, clone_lev
, indent
in tree
.prefix_all(storage
):
786 # print a clone's nested elements only once, as part of the
788 if printed
.has_key(id): continue
791 # Inefficient string formation...
793 if isinstance(nd
, (Nested
, aList
)):
794 nd_str
= nd_str
[0:nd_str
.find('(')]
796 print "%5d %10s %.5d %s %s" % (
798 storage
.ie_
.get_timestamp(id),
800 space
* per_level_indent
* indent
,
804 val
= geta(id, 'interp_result')
807 print "%5s %10s %5s %s `...... %.30s" % (
811 space
* per_level_indent
* indent
,
816 #** print_calling_context
817 def print_calling_context(self
, context
, level
= 0):
818 geta
= self
._storage
.get_attribute
819 load
= self
._storage
.load
820 gts
= self
._storage
.ie_
.get_timestamp
825 print src
, gts(src
), load(src
).source_string(), " -> ", \
826 clone
, gts(clone
), load(clone
).source_string()
827 ## print geta(clone, "interp_result")
829 self
.print_calling_context( path
[1:], level
+ 1)
830 TreeWork
.print_calling_context
= print_calling_context
834 def print_call_ctxt(self
, ctxt
):
835 geta
= self
._storage
.get_attribute
836 load
= self
._storage
.load
837 gts
= self
._storage
.ie_
.get_timestamp
839 def _show_path(path
, level
):
844 print cc
.J
, gts(cc
.J
), load(cc
.J
).source_string(), " -> ", \
845 cc
.K
, gts(cc
.K
), load(cc
.K
).source_string()
847 print "program source", " -> ", \
848 cc
.K
, gts(cc
.K
), load(cc
.K
).source_string()
852 print cc
.O
, gts(cc
.O
), '[['
853 print load(cc
.O
).source_string()
856 ## print geta(clone, "interp_result")
858 _show_path( path
[1:], level
+ 1)
863 TreeWork
.print_call_ctxt
= print_call_ctxt
866 #** print_call_ctxt_dot
867 def print_call_ctxt_dot(self
, ctxt
,
868 title
= "print_call_ctxt_dot",
872 # Produce O -> J -> C locally, and recurse. This omits the
873 # lexical source of O, which is important for nested loops.
875 # K is contained in C, so substitute
880 # Path leading to goal call goal call
896 # | K----------> | J | . .|. . | C |
897 # +----+ +----+ | +---+
908 # ALL calling paths are shown, so for a target T reached
909 # via N paths passing through P, P will have N incoming and (N-1)
910 # outgoing edges. Use unique = True to get only one.
915 geta
= self
._storage
.get_attribute
916 load
= self
._storage
.load
917 gts
= self
._storage
.ie_
.get_timestamp
920 # Get a dot-usable string from the node id.
921 return combine_newlines(
922 strip_comment(repr(load(id).source_string()))[1:-1].\
923 replace(r
"\n", "\l") + "\l")
925 def _show_path(path
, J_from
, level
):
930 print >> out
, cc
.O
, '[label="%s"];' % dotify(cc
.O
)
932 print >> out
, cc
.J
, \
933 '[label="call %d\l%s"];' % (cc
.J
, dotify(cc
.J
))
938 print >> out
, cc
.C
, \
939 '[label="%s"];' % (dotify(cc
.C
))
941 print >> out
, cc
.C
, \
942 '[label="clone %d\l%s"];' % (cc
.C
, dotify(cc
.C
))
946 if not uniq_t
.has_key((cc
.O
, cc
.J
)):
947 print >> out
, cc
.O
, '->', cc
.J
, '[label="used by"];'
948 print >> out
, cc
.J
, '->', cc
.C
, '[label="produces"];'
950 uniq_t
[(cc
.O
, cc
.J
)] = 1
951 uniq_t
[(cc
.J
, cc
.C
)] = 1
953 if not uniq_t
.has_key((J_from
, cc
.J
)):
954 print >> out
, J_from
, '->', cc
.J
, '[label="contains"];'
956 uniq_t
[(J_from
, cc
.J
)] = 1
959 # Continue down the call chain.
960 _show_path( path
[1:], cc
.C
, level
+ 1)
962 # Show the goal call K.
963 print >> out
, cc
.K
, \
964 '[label="call %d\l%s"];' % (cc
.K
, dotify(cc
.K
))
965 print >> out
, cc
.C
, '->', cc
.K
, '[label="contains"];'
969 page = "8.5,11.0"; /* size of single physical page */
970 size="7.5,10.0"; /* graph size */
976 edge [fontname = "Helvetica", fontsize=24];
977 node [style=filled, color=grey90, shape=plaintext,
978 fontname="Helvetica", fontsize=24];
982 title_node [label="%s", fontname="Helvetica", fontsize=20];
986 _show_path(path
, None, 0)
989 # Rank alignment for all target clones.
990 print >> out
, "{ rank=same;"
992 print >> out
, path
[-1].K
, ';'
998 TreeWork
.print_call_ctxt_dot
= print_call_ctxt_dot
1002 #** print_call_chains
1003 def print_call_chains(self
, ctxt
):
1005 # Show only the dynamic call chains; subset of print_call_ctxt.
1007 geta
= self
._storage
.get_attribute
1008 load
= self
._storage
.load
1009 gts
= self
._storage
.ie_
.get_timestamp
1011 def _show_path(path
, level
):
1015 print cc
.J
, gts(cc
.J
), load(cc
.J
).source_string(), " -> ", \
1016 cc
.K
, gts(cc
.K
), load(cc
.K
).source_string()
1018 print "program source", " -> ", \
1019 cc
.K
, gts(cc
.K
), load(cc
.K
).source_string()
1022 _show_path( path
[1:], level
+ 1)
1027 TreeWork
.print_call_chains
= print_call_chains
1029 #* interpretation-generated environments
1032 for (k
,v
, env
, lev
) in env
.all_bindings_recursive():
1034 print " "* 4 * ol
, "{" * (lev
- ol
)
1037 print " "* 4 * lev
, "}" * (ol
- lev
)
1039 print "%s%s = %s\n" % (" "* 4 * lev
, k
, v
)
1041 print " "* 4 * lev
, "}" * (lev
- 0)
1045 #* Decoration (title / label / comment) support
1046 #** Find appropriate decoration text
1047 def deco_title_text(self
):
1048 return self
.__class
__.__name
__
1049 Nested
.deco_title_text
= deco_title_text
1051 def deco_title_text(self
):
1053 Immediate
.deco_title_text
= deco_title_text
1055 def deco_title_text(self
):
1057 Native
.deco_title_text
= deco_title_text
1059 def deco_title_text(self
):
1062 Call(Marker('func_name'), Marker('rhs'))):
1063 return ma
['func_name'].get_infix_string(23)
1065 Call
.deco_title_text
= deco_title_text
1067 def deco_title_text(self
):
1070 Set(Marker('lhs'), Marker('rhs')) ):
1071 return "define " + ma
['lhs'].get_infix_string(23)
1073 Set
.deco_title_text
= deco_title_text
1075 def deco_title_text(self
):
1076 if self
.l_label
is None:
1080 if hasattr(lbl
, 'get_infix_string'):
1081 return lbl
.get_infix_string(23)
1084 List
.deco_title_text
= deco_title_text
1086 def deco_title_text(self
):
1087 if self
.m_label
is None:
1088 if isinstance(self
, Subdir
):
1094 if hasattr(lbl
, 'get_infix_string'):
1095 return lbl
.get_infix_string(23)
1098 Map
.deco_title_text
= deco_title_text
1100 def deco_title_text(self
):
1101 if self
.p_label
is None:
1105 if hasattr(lbl
, 'get_infix_string'):
1106 return lbl
.get_infix_string(23)
1109 Program
.deco_title_text
= deco_title_text
1111 def deco_title_text(self
):
1113 Function
.deco_title_text
= deco_title_text
1115 def deco_title_text(self
):
1117 Inline
.deco_title_text
= deco_title_text