72 ... """))) |
72 ... """))) |
73 34 |
73 34 |
74 |
74 |
75 Empty list: |
75 Empty list: |
76 |
76 |
77 >>> list(parsedag("")) |
77 >>> list(parsedag(b"")) |
78 [] |
78 [] |
79 |
79 |
80 A simple linear run: |
80 A simple linear run: |
81 |
81 |
82 >>> list(parsedag("+3")) |
82 >>> list(parsedag(b"+3")) |
83 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] |
83 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] |
84 |
84 |
85 Some non-standard ways to define such runs: |
85 Some non-standard ways to define such runs: |
86 |
86 |
87 >>> list(parsedag("+1+2")) |
87 >>> list(parsedag(b"+1+2")) |
88 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] |
88 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] |
89 |
89 |
90 >>> list(parsedag("+1*1*")) |
90 >>> list(parsedag(b"+1*1*")) |
91 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] |
91 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] |
92 |
92 |
93 >>> list(parsedag("*")) |
93 >>> list(parsedag(b"*")) |
94 [('n', (0, [-1]))] |
94 [('n', (0, [-1]))] |
95 |
95 |
96 >>> list(parsedag("...")) |
96 >>> list(parsedag(b"...")) |
97 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] |
97 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] |
98 |
98 |
99 A fork and a join, using numeric back references: |
99 A fork and a join, using numeric back references: |
100 |
100 |
101 >>> list(parsedag("+2*2*/2")) |
101 >>> list(parsedag(b"+2*2*/2")) |
102 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))] |
102 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))] |
103 |
103 |
104 >>> list(parsedag("+2<2+1/2")) |
104 >>> list(parsedag(b"+2<2+1/2")) |
105 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))] |
105 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))] |
106 |
106 |
107 Placing a label: |
107 Placing a label: |
108 |
108 |
109 >>> list(parsedag("+1 :mylabel +1")) |
109 >>> list(parsedag(b"+1 :mylabel +1")) |
110 [('n', (0, [-1])), ('l', (0, 'mylabel')), ('n', (1, [0]))] |
110 [('n', (0, [-1])), ('l', (0, 'mylabel')), ('n', (1, [0]))] |
111 |
111 |
112 An empty label (silly, really): |
112 An empty label (silly, really): |
113 |
113 |
114 >>> list(parsedag("+1:+1")) |
114 >>> list(parsedag(b"+1:+1")) |
115 [('n', (0, [-1])), ('l', (0, '')), ('n', (1, [0]))] |
115 [('n', (0, [-1])), ('l', (0, '')), ('n', (1, [0]))] |
116 |
116 |
117 Fork and join, but with labels instead of numeric back references: |
117 Fork and join, but with labels instead of numeric back references: |
118 |
118 |
119 >>> list(parsedag("+1:f +1:p2 *f */p2")) |
119 >>> list(parsedag(b"+1:f +1:p2 *f */p2")) |
120 [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')), |
120 [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')), |
121 ('n', (2, [0])), ('n', (3, [2, 1]))] |
121 ('n', (2, [0])), ('n', (3, [2, 1]))] |
122 |
122 |
123 >>> list(parsedag("+1:f +1:p2 <f +1 /p2")) |
123 >>> list(parsedag(b"+1:f +1:p2 <f +1 /p2")) |
124 [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')), |
124 [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')), |
125 ('n', (2, [0])), ('n', (3, [2, 1]))] |
125 ('n', (2, [0])), ('n', (3, [2, 1]))] |
126 |
126 |
127 Restarting from the root: |
127 Restarting from the root: |
128 |
128 |
129 >>> list(parsedag("+1 $ +1")) |
129 >>> list(parsedag(b"+1 $ +1")) |
130 [('n', (0, [-1])), ('n', (1, [-1]))] |
130 [('n', (0, [-1])), ('n', (1, [-1]))] |
131 |
131 |
132 Annotations, which are meant to introduce sticky state for subsequent nodes: |
132 Annotations, which are meant to introduce sticky state for subsequent nodes: |
133 |
133 |
134 >>> list(parsedag("+1 @ann +1")) |
134 >>> list(parsedag(b"+1 @ann +1")) |
135 [('n', (0, [-1])), ('a', 'ann'), ('n', (1, [0]))] |
135 [('n', (0, [-1])), ('a', 'ann'), ('n', (1, [0]))] |
136 |
136 |
137 >>> list(parsedag('+1 @"my annotation" +1')) |
137 >>> list(parsedag(b'+1 @"my annotation" +1')) |
138 [('n', (0, [-1])), ('a', 'my annotation'), ('n', (1, [0]))] |
138 [('n', (0, [-1])), ('a', 'my annotation'), ('n', (1, [0]))] |
139 |
139 |
140 Commands, which are meant to operate on the most recently created node: |
140 Commands, which are meant to operate on the most recently created node: |
141 |
141 |
142 >>> list(parsedag("+1 !cmd +1")) |
142 >>> list(parsedag(b"+1 !cmd +1")) |
143 [('n', (0, [-1])), ('c', 'cmd'), ('n', (1, [0]))] |
143 [('n', (0, [-1])), ('c', 'cmd'), ('n', (1, [0]))] |
144 |
144 |
145 >>> list(parsedag('+1 !"my command" +1')) |
145 >>> list(parsedag(b'+1 !"my command" +1')) |
146 [('n', (0, [-1])), ('c', 'my command'), ('n', (1, [0]))] |
146 [('n', (0, [-1])), ('c', 'my command'), ('n', (1, [0]))] |
147 |
147 |
148 >>> list(parsedag('+1 !!my command line\\n +1')) |
148 >>> list(parsedag(b'+1 !!my command line\\n +1')) |
149 [('n', (0, [-1])), ('C', 'my command line'), ('n', (1, [0]))] |
149 [('n', (0, [-1])), ('C', 'my command line'), ('n', (1, [0]))] |
150 |
150 |
151 Comments, which extend to the end of the line: |
151 Comments, which extend to the end of the line: |
152 |
152 |
153 >>> list(parsedag('+1 # comment\\n+1')) |
153 >>> list(parsedag(b'+1 # comment\\n+1')) |
154 [('n', (0, [-1])), ('n', (1, [0]))] |
154 [('n', (0, [-1])), ('n', (1, [0]))] |
155 |
155 |
156 Error: |
156 Error: |
157 |
157 |
158 >>> try: list(parsedag('+1 bad')) |
158 >>> try: list(parsedag(b'+1 bad')) |
159 ... except Exception, e: print(e) |
159 ... except Exception, e: print(e) |
160 invalid character in dag description: bad... |
160 invalid character in dag description: bad... |
161 |
161 |
162 ''' |
162 ''' |
163 if not desc: |
163 if not desc: |
411 Examples |
411 Examples |
412 -------- |
412 -------- |
413 |
413 |
414 Linear run: |
414 Linear run: |
415 |
415 |
416 >>> dagtext([('n', (0, [-1])), ('n', (1, [0]))]) |
416 >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [0]))]) |
417 '+2' |
417 '+2' |
418 |
418 |
419 Two roots: |
419 Two roots: |
420 |
420 |
421 >>> dagtext([('n', (0, [-1])), ('n', (1, [-1]))]) |
421 >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [-1]))]) |
422 '+1 $ +1' |
422 '+1 $ +1' |
423 |
423 |
424 Fork and join: |
424 Fork and join: |
425 |
425 |
426 >>> dagtext([('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), |
426 >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [0])), (b'n', (2, [0])), |
427 ... ('n', (3, [2, 1]))]) |
427 ... (b'n', (3, [2, 1]))]) |
428 '+2 *2 */2' |
428 '+2 *2 */2' |
429 |
429 |
430 Fork and join with labels: |
430 Fork and join with labels: |
431 |
431 |
432 >>> dagtext([('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), |
432 >>> dagtext([(b'n', (0, [-1])), (b'l', (0, b'f')), (b'n', (1, [0])), |
433 ... ('l', (1, 'p2')), ('n', (2, [0])), ('n', (3, [2, 1]))]) |
433 ... (b'l', (1, b'p2')), (b'n', (2, [0])), (b'n', (3, [2, 1]))]) |
434 '+1 :f +1 :p2 *f */p2' |
434 '+1 :f +1 :p2 *f */p2' |
435 |
435 |
436 Annotations: |
436 Annotations: |
437 |
437 |
438 >>> dagtext([('n', (0, [-1])), ('a', 'ann'), ('n', (1, [0]))]) |
438 >>> dagtext([(b'n', (0, [-1])), (b'a', b'ann'), (b'n', (1, [0]))]) |
439 '+1 @ann +1' |
439 '+1 @ann +1' |
440 |
440 |
441 >>> dagtext([('n', (0, [-1])), |
441 >>> dagtext([(b'n', (0, [-1])), |
442 ... ('a', 'my annotation'), |
442 ... (b'a', b'my annotation'), |
443 ... ('n', (1, [0]))]) |
443 ... (b'n', (1, [0]))]) |
444 '+1 @"my annotation" +1' |
444 '+1 @"my annotation" +1' |
445 |
445 |
446 Commands: |
446 Commands: |
447 |
447 |
448 >>> dagtext([('n', (0, [-1])), ('c', 'cmd'), ('n', (1, [0]))]) |
448 >>> dagtext([(b'n', (0, [-1])), (b'c', b'cmd'), (b'n', (1, [0]))]) |
449 '+1 !cmd +1' |
449 '+1 !cmd +1' |
450 |
450 |
451 >>> dagtext([('n', (0, [-1])), ('c', 'my command'), ('n', (1, [0]))]) |
451 >>> dagtext([(b'n', (0, [-1])), |
|
452 ... (b'c', b'my command'), |
|
453 ... (b'n', (1, [0]))]) |
452 '+1 !"my command" +1' |
454 '+1 !"my command" +1' |
453 |
455 |
454 >>> dagtext([('n', (0, [-1])), |
456 >>> dagtext([(b'n', (0, [-1])), |
455 ... ('C', 'my command line'), |
457 ... (b'C', b'my command line'), |
456 ... ('n', (1, [0]))]) |
458 ... (b'n', (1, [0]))]) |
457 '+1 !!my command line\\n+1' |
459 '+1 !!my command line\\n+1' |
458 |
460 |
459 Comments: |
461 Comments: |
460 |
462 |
461 >>> dagtext([('n', (0, [-1])), ('#', ' comment'), ('n', (1, [0]))]) |
463 >>> dagtext([(b'n', (0, [-1])), (b'#', b' comment'), (b'n', (1, [0]))]) |
462 '+1 # comment\\n+1' |
464 '+1 # comment\\n+1' |
463 |
465 |
464 >>> dagtext([]) |
466 >>> dagtext([]) |
465 '' |
467 '' |
466 |
468 |
467 Combining parsedag and dagtext: |
469 Combining parsedag and dagtext: |
468 |
470 |
469 >>> dagtext(parsedag('+1 :f +1 :p2 *f */p2')) |
471 >>> dagtext(parsedag(b'+1 :f +1 :p2 *f */p2')) |
470 '+1 :f +1 :p2 *f */p2' |
472 '+1 :f +1 :p2 *f */p2' |
471 |
473 |
472 ''' |
474 ''' |
473 return "\n".join(dagtextlines(dag, |
475 return "\n".join(dagtextlines(dag, |
474 addspaces, |
476 addspaces, |