scm.py: support eval. Improve eval in home page

This commit is contained in:
Nicolò Balzarotti 2023-02-22 03:58:53 +01:00
parent 13e1ed9f34
commit 40c9655424
5 changed files with 31 additions and 20 deletions

3
app.py
View File

@ -90,8 +90,7 @@ def handle_new_client():
@socketio.on('eval scheme') @socketio.on('eval scheme')
def eval_scheme(code): def eval_scheme(code):
output = phasectrl.safe_eval(code, statemachine.env) output = phasectrl.safe_eval(code, statemachine.env, notify=False)
phasectrl.safe_eval(f'(notify "{output}")', statemachine.env)
socketio.emit('eval output', output) socketio.emit('eval output', output)
@socketio.on('get sensors history') @socketio.on('get sensors history')

View File

@ -14,13 +14,15 @@ MY_GLOBAL_ENV = (
_('format-time', 1, lambda x: stohms(x.car), _('format-time', 1, lambda x: stohms(x.car),
GLOBAL_ENV))) GLOBAL_ENV)))
def safe_eval(data, env): def safe_eval(data, env, notify=True):
try: try:
return eval(data, env) return eval(data, env)
except Exception as e: except Exception as e:
err = ' '.join(('evaluating:', data, ':', str(e))) err = ' '.join(('evaluating:', data, ':', str(e)))
if notify:
chat.send_sync(err) chat.send_sync(err)
return True return True
return err
def load_phase(json): def load_phase(json):
def fallback(v): def fallback(v):
@ -244,7 +246,7 @@ class State():
actuators[actuator].enable() actuators[actuator].enable()
else: else:
actuators[actuator].disable() actuators[actuator].disable()
print('setting actuator ', actuator, 'to value', value, print('setting actuator', actuator, 'to value', value,
', remember to change it manually if stopping?') ', remember to change it manually if stopping?')
def get_total_consumption(self): def get_total_consumption(self):

14
scm.py
View File

@ -82,6 +82,9 @@ class SchemeString:
def __repr__(self): def __repr__(self):
return '"' + self.string + '"' return '"' + self.string + '"'
def __eq__(self, other):
return self.string == other.string
class Environment (object): class Environment (object):
"Linked list of bindings mapping symbols to values" "Linked list of bindings mapping symbols to values"
@ -206,11 +209,13 @@ GLOBAL_ENV = (
# My custom helpers # My custom helpers
from datetime import datetime from datetime import datetime
GLOBAL_ENV = ( GLOBAL_ENV = (
_('now', 0, lambda x: datetime.now(), _('now', 0, lambda x: datetime.now(),
_('concat', -1, lambda x: ''.join((stringify(x, False) for x in x)), _('concat', -1, lambda x: ''.join((stringify(x, False) for x in x)),
_('exit', 0, lambda x: exit(), _('exit', 0, lambda x: exit(),
GLOBAL_ENV)))) _('eval', 1, lambda x: evaluate(x.car),
GLOBAL_ENV)))))
# records = {} # records = {}
# def make_record_type(name, params): # def make_record_type(name, params):
@ -249,11 +254,12 @@ GLOBAL_ENV = Environment(
_('cdr', 1, lambda x: x.car.cdr, _('cdr', 1, lambda x: x.car.cdr,
_('cons', 2, lambda x: Cell(x.car, x.cdr.car), _('cons', 2, lambda x: Cell(x.car, x.cdr.car),
_('eq?', 2, lambda x: x.car is x.cdr.car, _('eq?', 2, lambda x: x.car is x.cdr.car,
_('equal?', 2, lambda x: x.car == x.cdr.car,
_('pair?', 1, lambda x: isinstance(x.car, Cell), _('pair?', 1, lambda x: isinstance(x.car, Cell),
_('null?', 1, lambda x: x.car is NIL, _('null?', 1, lambda x: x.car is NIL,
_('not', 1, lambda x: x.car is False, _('not', 1, lambda x: x.car is False,
_('list', -1, lambda x: x, _('list', -1, lambda x: x,
GLOBAL_ENV))))))))) GLOBAL_ENV))))))))))
@ -393,8 +399,8 @@ def apply_function(fun, arg, k, env):
elif isinstance(fun, tuple): # as a continuation elif isinstance(fun, tuple): # as a continuation
return arg.car, fun, env return arg.car, fun, env
else: else:
raise TypeError('not a function: ' + stringify(fun) + ' with ' raise TypeError('wrong type to apply: ' + stringify(fun) + ' with '
+ stringify(arg)) + stringify(arg) + ' instance is ' + str(type(fun)))
def _push_RESTORE_ENV(k, env): def _push_RESTORE_ENV(k, env):
if k is NOCONT or k[0] is not RESTORE_ENV: # unless tail call... if k is NOCONT or k[0] is not RESTORE_ENV: # unless tail call...

View File

@ -21,6 +21,9 @@
socket.on("state", (data) => { socket.on("state", (data) => {
applyState(data); applyState(data);
}); });
socket.on("eval output", (data) => {
document.getElementById('eval-output').value = data;
});
socket.on("sensors", (data) => { socket.on("sensors", (data) => {
add_plot_data(data); add_plot_data(data);
render_sensors(data); render_sensors(data);

View File

@ -61,12 +61,13 @@
</header> </header>
<div class="card-content"> <div class="card-content">
<div class="content"> <div class="content">
<div class="field has-addons"> <textarea class="textarea" value="#t" id="scheme-eval">
<textarea class="textarea" value="#t" id="scheme-eval"/></textarea> </textarea>
<a class="button is-info" onclick="eval_scheme('scheme-eval')"> <a class="button is-info" onclick="eval_scheme('scheme-eval')">
Eval Eval
</a> </a>
</div> <textarea class="textarea" value="#t" id="eval-output" readonly>
</textarea>
</div> </div>
</div> </div>
</div> </div>