-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
233 lines (201 loc) · 11 KB
/
main.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# main.py is repl.it's starting point for projects of type 'Python'.
import exemplar as e
import html as h # To avoid weird "AttributeError: 'function' object has no attribute 'escape'" error.
import random
from flask import Flask, request # Flask is a micro web framework.
from typing import List
# begin()->demo()->generate() (calls reverse_trace then) ->html(). See method html() after these Flask handlers
# for the HTML and JavaScript that gets returned.
app = Flask(__name__)
def python_colorize(lines: List[str]) -> str:
colorized = ''
for line in lines:
if not line.strip():
colorized += '\n'
elif line[0] == '<':
colorized += "<font color='blue'>" + h.escape(line) + "</font>"
elif line[0] == '>':
colorized += "<font color='green'>" + h.escape(line) + "</font>"
else:
colorized += h.escape(line)
return colorized
@app.route('/')
def begin():
return demo("guess4") # Start off with a demonstration.
@app.route('/demo/<string:demo>', methods=['POST'])
def demo(demo):
return generate(file=demo + ".exem") # Pull an exem.
@app.route('/generate', methods=['POST'])
def generate(file=""):
if file:
user_examples_list = e.from_file(file)
else:
# Write the user's examples from the request object into a file.
# request.form window.form['examples_f'].div['examples_edit']
user_examples = request.form['examples_i']
# return "<!DOCTYPE html><html lang='en'><body>" + str(user_examples) + "</body></html>"
name = request.form['function_name']
if name and name != 'NameYourFunctionHere':
file = name + ".exem" # User-specified function name
else:
file = 'e' + str(random.randrange(10)) + ".exem" # Pick a name at random.
e.to_file(file, user_examples) # Write to it.
user_examples_list = user_examples.split('\n')
code, test_file_contents = e.reverse_trace(file) # Capture code for display.
# return "<!DOCTYPE html><html lang='en'><body>" + str(len(code)) + "</body></html>"
return html(user_examples_list, code, test_file_contents)
# Return html to the browser with embedded JavaScript.
def html(examples_list, code, test_file_contents):
# return "<!DOCTYPE html><html lang='en'><body>" + "\n".join(examples_list) + "</body></html>"
head_html = """<!DOCTYPE html><html lang="en">
<head><meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"><meta charset="UTF-8">
<link rel="icon" type="image/png" href="https://cultivatedbigcustomization--gherson.repl.co/truth.png">
<title>Exemplar</title>
<style>
td, th {
border: 1px solid black;
}
</style>
<script src="http://www.google.com/jsapi"></script>
<script>google.load('prototype', '1.6.0.2');</script>
<script>
function resizeIt(textarea_name) { // Uses Prototype. From https://stackoverflow.com/a/7523/575012
var str = $(textarea_name).value;
var cols = $(textarea_name).cols;
var lineCount = 0;
$A(str.split("\\n")).each( function(l) {
lineCount += Math.ceil( l.length / cols ); // Take into account long lines
})
$(textarea_name).rows = lineCount + 1;
};
// Workaround for Flask not putting div elements' content into the Request object.
function copyDivToInput(f) { // examples_edit to examples_i
var examples = document.getElementById("examples_edit");
f.examples_i.value = examples.innerText;
f.submit();
}
function encodeAndWrap(str, tag) {
return str.replace(/[\u00A0-\u99999<>\&]/g, function(i) {
return (tag ? '<'+tag+'>' :'')+'&#'+i.charCodeAt(0)+';'+(tag ? '</'+tag+'>' : '');
});
}; // HTML entity encoder, from http://jsfiddle.net/E3EqX/4/ 4/18/19
function table_maker(input, truth, output) { // Line by line.
input = encodeAndWrap(input, '')
truth = encodeAndWrap(truth, '')
output = encodeAndWrap(output, '')
var examples = document.getElementById("examples_t");
examples_t.innerHTML += "<tr><td>" + input + "</td><td>" + truth + "</td><td>" + \
output + "</td></tr>\\n";
}
function exem_table(examples) { // From iterable to fields to calling table_maker() a line at a time.
input = ''; truth = '';
for (var i=0; i<examples.length; i++) {
line = examples[i];
if (line == '') table_maker(' ',' ',' ')
// Input
if (line.substring(0,1) == '<') {
if (input != '' || truth != '') {
table_maker(input, truth, '');
input = ''; truth = '';
}
input = line.substring(1);
// Truth
} else if (line.substring(0,1) != '<' && line.substring(0,1) != '>') {
if (truth != '') {
table_maker(input, truth, '');
input = ''; truth = '';
}
truth = line;
// Output
} else {
if (line.substring(0,1) != '>') {
throw new Error("Output line expected, not " + line );
}
table_maker(input, truth, line.substring(1));
input = ''; truth = '';
}
}
// If examples do not end with output, call table_maker() 1 more time.
if (line.substring(0,1) != '>') {
table_maker(input, truth, '');
}
}
function copyFunction(textarea_name, button_id) {
// Get the text field
var copyText = document.getElementById(textarea_name);
// Select the text field
copyText.select();
// Copy the text inside the text field
document.execCommand("copy");
document.getElementById(button_id).style.background='#D3D3D3';
document.getElementById(button_id).innerHTML = "Copied!";
} // by TG
function mouseUp(button_id) {
document.getElementById(button_id).innerHTML = "Copy";
document.getElementById(button_id).style.background='#FFFFFF';
}
function generate_name() { // Provide default function name
exem = document.getElementById('examples_edit').innerText; // div
document.getElementById('function_name').value = exem.substring(0,15).trim().replace(/[^a-zA-Z0-9]/g, '');
}
// Creating an examples array:
var examples = new Array();\n"""
# Back to python to...
clean_examples_list = e.clean(examples_list) # Snip comments and header.
# return "<!DOCTYPE html><html lang='en'><body>" + "\n".join(clean_examples_list) + "</body></html>"
i = 0
for example in clean_examples_list: # Create a large JS array.
head_html += "\texamples[" + str(i) + '] = "' + example.rstrip() + '";\n'
i += 1
""" What the JS array looks like:
examples[0] = '>Hello! What is your name?';
examples[1] = '<Albert';
examples[2] = 'name==i1';
"""
head_html += "</script></head>\n"
demos_html = """<br/>Other demonstrations:\n
<table><tr>""" # TABLE opens
demos = ['prime_number', 'leap_year', 'guess4', 'fizz_buzz']
for demo in demos:
demos_html += "<td><form method='POST' action='/demo/" + demo + \
"'>\n<input type='submit' value='" + demo + "'/></form></td>\n"
demos_html += "</tr></table>\n"
key = "" # """"<p>Notes:</p><ul><li><dl><dt>term</dt><dd>definition</dd></dl></li></ul>"""
# print("example:", examples) # Took a few restarts to appear (in console).
body_top = """<body onload="exem_table(examples);"><center>
<b>Exemplar</b>: Programming via code trace\n
</center><table><tr><td width="50%">
<b>Instructions</b>:
<ol><li>Enter <<font color='blue'><i>input</i></font>↲><font color='green'><i>output</i></font>↲<i>assertions</i> sequences demonstrating desired behavior on the left. Assertions ("truth") may be line or comma separated.</li>\n
<li>To name your input (for references in the Truth column only), immediately follow that input with line <code><i>yourname</i>==i1</code></li>\n
<li>Only trace those conditions leading to a consequence. E.g., omit <code>some_trigger==False</code></li>\n
<li>Separate your examples (use cases) with a blank line.</li>\n
<li>Press Submit below to have Exemplar attempt to generate conforming Python code on the right.</li>\n
</ol> <a href="https://cultivatedbigcustomization--gherson.repl.co/example%20correlations.png" target="_blank">Example correlations</a> from trace to code<br/><br/></td>\n
<td>This is a working proof of concept that the essential elements of a general algorithm, i.e., input, output, control structure,
calculation, variable naming and substitution, can be successfully demonstrated for a code generator with little to no abstraction or structure. <br/>Exemplar is already useful for creating unit tests and simple functions. gherson 2019-11-09<br/>""" + demos_html + "</td></tr></table>\n"
# Show the raw examples, the examples tabulated, the code generated, and finally, a choice of demos.
# The HTML structure is a table: the 1st row is headings and the second row cells are form, table, and textarea, respectively. 4/18/19
# return "<!DOCTYPE html><html lang='en'><body>" + str(len(clean_examples_list)) + "</body></html>"
return head_html + body_top + '''<table cellpadding="7"><tr><th width="25%">Editable examples</th><th width="33%">Examples tabulated</th><th>Code generated </th></tr>\n
<tr><td valign="top">
<form name="examples_f" id="examples_f" method="POST" action="/generate">Editable function name<br/>\n
<input type="text" id="function_name" name="function_name" value="NameYourFunctionHere"/><input type="hidden" name="examples_i"/>
<div name="examples_edit" id="examples_edit" contenteditable="true" style="border: thin solid black; width: 400px; overflow: auto"><pre>''' + python_colorize(examples_list) + '''</pre></div><input type="submit" value="Submit" onclick="copyDivToInput(this.form)"/> </form><br/></td>\n
<td valign="top" align="center" style="text-align:center">
<table id="examples_t" cellpadding="1"><tr><th><font color="blue">input</font></th><th>truth</th>
<th><font color="green">output</font></th></tr></table></td>\n
<td valign="top"><textarea name="code_generated" id="code_generated" rows="10" cols="60" readonly = "readonly">''' + code + '''</textarea><br/>\n
<button id="code_button" onmousedown="copyFunction('code_generated', 'code_button')" onmouseup="mouseUp('code_button')">Copy</button><br/><br/>\n
<button id="test_file_button" onmousedown="copyFunction('test_file_contents', 'test_file_button')" onmouseup="mouseUp('test_file_button')">Copy</button>
<b><center>Code generated with unit tests</center></b>
<textarea name="test_file_contents" id="test_file_contents" rows="10" cols="60" readonly = "readonly">''' + test_file_contents + '''</textarea><br/></td></tr>\n
</table>\n''' + key + """<script>
resizeIt('code_generated'); // Initial on load
resizeIt('test_file_contents'); // Initial on load
generate_name(); // Provide default function name
</script></html>"""
if __name__ == '__main__':
# pass
app.run(host='0.0.0.0', port=8080)
# With this IF, execution never reaches here.