-
Notifications
You must be signed in to change notification settings - Fork 4
/
v8halp.py
executable file
·98 lines (84 loc) · 3.05 KB
/
v8halp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python
"""
Run a Halp-extended .js sourcefile from stdin; write to stdout the
same sourcefile with evaluation results placed inline.
"""
import difflib
import subprocess
import sys
# Evaluation
def halp(module_text):
"""Given a module's code as a string, produce the Halp output as a
string."""
input_lines = module_text.split('\n')
input = [line for line in input_lines if not line.startswith('//. ')]
output = eval_module(input)
#print 'output', output
return diff(output, input_lines)
def eval_module(input):
"""Given a module's code as a list of lines, produce the Halp
output as a list of lines."""
halp_lines = []
halp_linenos = []
for i, line in enumerate(input):
if line.startswith('/// '):
halp_lines.append(line[len('/// '):])
halp_linenos.append(i+1)
result_string = call_v8halp('\n'.join(input), halp_lines)
result_lines = result_string.split('\n')
result_chunks = []
j = 0
#print 'result_lines', result_lines
while j < len(result_lines):
if result_lines[j] == '': break
nlines = int(result_lines[j])
result_chunks.append(result_lines[j+1:j+1+nlines])
j += 1 + nlines
#print 'result_chunks', result_chunks
#print 'halp_linenos', halp_linenos
assert len(result_chunks) == len(halp_linenos)
output = list(input)
for lineno, chunk in reversed(zip(halp_linenos, result_chunks)):
output[lineno:lineno] = ['//. ' + line for line in chunk]
return output
def call_v8halp(text, halp_lines):
#print 'halp_lines', halp_lines
args = ['v8halp'] + halp_lines
p = subprocess.Popen(args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=None)
stdout, stderr = p.communicate(input=text)
#print 'stdout', repr(stdout)
#print stderr
return stdout
# Producing a diff between input and output
def diff(new_lines, old_lines):
return format_diff(compute_diff(None, new_lines, old_lines))
def format_diff(triples):
return ''.join('%d %d %d\n%s' % (lo+1, hi-lo, len(lines),
''.join(line + '\n' for line in lines))
for lines, lo, hi in triples)
def compute_diff(is_junk, a, b):
"""
Pre: is_junk: None or (string -> bool)
a, b: [string]
Return a list of triples (lines, lo, hi) representing the edits
to convert b to a. The ranges (lo,hi) are disjoint and in
descending order. Setting each b[lo:hi] = lines, in order, yields a.
"""
sm = difflib.SequenceMatcher(is_junk, a, b)
i = j = 0
triples = []
for ai, bj, size in sm.get_matching_blocks():
# Invariant:
# triples is the diff for a[:i], b[:j]
# and the next matching block is a[ai:ai+size] == b[bj:bj+size].
if i < ai or j < bj:
triples.append((a[i:ai], j, bj))
i, j = ai+size, bj+size
triples.reverse()
return triples
# Main program
if __name__ == '__main__':
sys.stdout.write(halp(sys.stdin.read()))