Skip to content

Instantly share code, notes, and snippets.

@jul
Last active September 22, 2019 18:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jul/619bb89fc984d7ea8cf4af59df353c79 to your computer and use it in GitHub Desktop.
Save jul/619bb89fc984d7ea8cf4af59df353c79 to your computer and use it in GitHub Desktop.
une calculatrice qui parle (si espeak est installé)
#/!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Perversion
"""
from collections import MutableMapping, Counter, MutableSequence
from json import *
from functools import reduce
#sum = lambda *alot: reduce(lambda x, y: x+y, alot)
MARKER=object()
RECURSOR=object()
STOPER=object()
class Path(tuple):
def endswith( self, *a_tuple ):
"""
>>> p = Path( [ 'a', 'b', 'c' ] )
>>> p.endswith( 'b', 'c' )
>>> True
"""
return self[len(self) - len(a_tuple) : ] == a_tuple
def startswith( self, *a_tuple ):
"""
>>> p = Path( [ 'a', 'b', 'c', 'd' ] )
>>> p.startswith( 'a', 'b' )
>>> True
"""
return self[: len( a_tuple ) ] == a_tuple
def _contains( self, a_tuple, _from = 0, follow = 0):
if len( a_tuple) == follow:
return True
index = False
here = self[ _from:]
try:
index = here.index(a_tuple[follow] )
return self._contains(
a_tuple,
index + 1 ,
follow + 1
)
except ValueError:
return False
return False
def contains(self, *a_tuple ):
"""
>>> p = Path( [ 'a', 'b', 'c', 'd' ] )
>>> p.contains( 'b', 'c' )
>>> True
"""
return self._contains(a_tuple)
def value(self):
""" returns the left most value
"""
return self[-1]
def key(self):
""" returns all the keys in the Path
"""
return Path(self[:-1])
def _any(p):
return True
def identity(p, acc=MARKER):
yield p
dispatch = pandoc_disp = dict()
pandoc_disp[_any]=identity
def mapping_row_iter(tree, path=MARKER, predicate=pandoc_disp,accumulator=MARKER):
"""
iterator on a tree that yield an iterator on a mapping in the form of
a list of ordered key that leads to the element and the value
"""
if path is MARKER:
path = ()
p = Path(path+(tree,))
for pred, effector in predicate.items():
switch = pred(p)
if isinstance(switch, tuple):
switch, predicate = switch
def recursor(p, predicate=predicate):
return mapping_row_iter(p.value(),path=p.key(), predicate=predicate, accumulator=accumulator)
_effector = accumulator is MARKER and (lambda e:effector(e)) or (lambda e:effector(e, accumulator))
if switch in {RECURSOR,}:
for value in _effector(p):
yield from recursor(value)
break
if switch:
yield from _effector(p)
break
compute_me="""/A -e-e-10 0 + 1 1.+ A 12 2 x 1. 1+ 2 1 _XZZT 1.5 e2-2
-e-e1 *2/4/ .25// 23000e-BUG3 M 200 m 2 + 10 2.1e1 A N e2-2 +"""
def while_digit(e, acc):
acc["index"]+=1
acc["current"] += e.value()
yield MARKER
def _move_to_stack(e, acc, ind=1):
print(acc)
if acc["current"]:
try:
acc["stack"] += [float(acc["current"],)]
yield ("=", acc["current"])
acc["load"] += 1
except Exception as ex:
acc["err"] += [ (acc["index"], str(ex),), ]
acc["current"] = ""
acc["index"]+=ind
print(acc)
def move_to_stack(e, acc):
yield from _move_to_stack(e,acc)
def store(e, acc):
acc["mem"] = acc["stack"]
acc["pc"]+=1
yield ("S", acc["stack"])
def recall(e, acc):
acc["stack"] += acc.get("mem",list())
acc["pc"]+=1
yield ("R",acc.get("mem", list()))
rop = lambda op: lambda s: reduce(op,s)
def flatten(a, acc=MARKER):
for x in a.value():
yield Path(x,)
dmux = dict({
"+": rop(float.__add__), "_": rop(float.__sub__), "M": rop(max),
"/": rop(float.__truediv__), "x": rop(float.__mul__), "D": lambda s: sorted(s)[int(len(s)/2)],
"*": rop(float.__mul__), "m": rop(min), "A": lambda s: sum(s)/len(s),
})
def muxer(e,acc):
yield from _move_to_stack(e,acc,0)
acc["index"]+=1
try:
acc["stack"]= [ dmux[e.value()](acc["stack"]), ]
acc["pc"] += 1
yield (e.value(), acc["stack"])
except Exception as e:
acc["err"] += [ (acc["index"], str(e),),]
def is_this(needles):
return lambda hay: hay.value() in set(needles)
def clear(e,acc):
acc["stack"]=list()
acc["index"]=0
acc["pc"]=0
acc["load"]=0
acc["ctrl"]=1
acc["err"]=acc["ignored"]=list()
yield ("C", acc)
def debug(e,acc):
print(dumps(acc, indent=4))
acc["ctrl"]+=1
yield ("d",acc)
def indexor(e,acc):
acc['index']+=1
acc["ignored"] += [(acc['index'], e.value(),),]
yield MARKER
is_array = lambda p: isinstance(p.value(), MutableSequence) and RECURSOR
def quit(e,acc):
raise ValueError("quit)")
dispatch=dict((
(is_array, flatten),
(is_this(".e0123456789-"), while_digit),
(is_this(" "), move_to_stack),
(is_this(dmux.keys()), muxer),
(is_this("C"), clear),
(is_this("d"), debug),
(is_this("Q"), quit),
(is_this("S"), store),
(is_this("R"), recall),
(any, indexor),
))
new_pile=lambda :dict(current="",ctrl=0, pc=0, load=0, stack=list(), err=list(), index=0, ignored=list())
pile=new_pile()
res = mapping_row_iter(list(compute_me), predicate=dispatch, accumulator=pile)
print(";".join(map(lambda e:"%s%s" %e,(filter(lambda e : e is not MARKER,list(res))))))
# >>> =12;=2;x(24.0,);=1.;=1;+(26.0,);=2;=1;_(23.0,);=1.5;*(34.5,);=2;/(17.25,);=23000e-3;M(23.0,);=200;m(23.0,);=2;+(25.0,);=10;=2.1e1;A(18.666666666666668,);N([-18.666666666666668],)
print(pile)
# >>> {'current': '', 'pc': 10, 'load': 13, 'stack': ([-18.666666666666668],)}
for i,v in pile["err"]:
print(compute_me)
print((" "*(i - 1)) + '^ ' + str(v))
print()
# >>> {'current': '', 'pc': 10, 'load': 13, 'stack': ([-18.666666666666668],)}
for i,v in pile["ignored"]:
print(compute_me)
print((" "*(i - 1)) + "^ was ignored")
print()
pile=new_pile()
lasterr=0
from tkinter import *
gui = Tk()
gui.title("Simple Calculator")
# set the configuration of GUI window
gui.geometry()
equation = StringVar()
result=StringVar()
error=StringVar()
deb=StringVar()
current_proc=""
DEF_TOSY=dict({
"-s" : "145",
"-v" : "fr"
})
def say(tosay,**_kw):
kw = DEF_TOSY.copy()
kw.update(_kw)
call([ "espeak",] + sum([[k,v] for k,v in kw.items()],[]) + [ tosay,] )
translate = dict({
"/" : "divisé", "+" : "pluce ", "*" : "fois",
"e" : "dix puissance ", "-" : "moins", "." : "point",
"A" : "moyenne", "D" : "médiane ",
"M" : "maximum", "_" : "soustraction ",
"m" : "minimum", " " : "puis",
'\x08': "effacer ",
"S" : "enregistre pile ", "R" : "rappel la pile ",
"C" : "remise à zéro", "=" : "",
})
translate.update({ str(x):str(x) for x in range(10) })
def current_str(string):
if string.isdecimal():
return str(int(string))
# in face of ambiguity refuse to guess
return " ".join(map(lambda ac:translate.get(ac,ac), list(string)))
def key(a,**kw):
global current_proc,equation, result, error
try:
tosay = translate[a.char]
except KeyError:
return "break"
if a.char=="C":
equation.set("")
if tosay=="effacer ":
equation.set(equation.get()[:-1])
if not(pile["current"]):
try:
pile["current"]=str(pile["stack"].pop())
except IndexError:
pass
try:
pile["current"] = pile["current"][:-1]
tosay = "en cours " + current_str(pile["current"])
except IndexError:
pass
run=mapping_row_iter(list(a.char), predicate=dispatch, accumulator=pile)
print(";".join(map(lambda e:"%s%s" %e,(filter(lambda e : e is not
MARKER, run)))))
if tosay == "puis":
tosay=" " if bool(pile["current"]) else "et"
if a.char == "=" :
tosay+=pile["current"] and "en cours " + current_str(pile["current"]) or (pile["stack"] and " et ".join(map(lambda f:("%g" % f).replace(".",","),pile["stack"])) or "vide" )
print(tosay)
say(tosay)
if a.char == "C":
equation.set("")
return "break"
deb.set(dumps(pile, indent=4))
if not pile["err"] and not pile["ignored"]:
error.set("")
if pile["err"]:
tosay="pile vide"
error.set(tosay)
say(tosay)
pile["err"]=list()
if pile["ignored"]:
error.set("<" + str(pile["ignored"][-1][1]) + "> is not a valid character")
result.set("\n".join([ "%2d: %.2f" % t for t in enumerate(pile["stack"][::-1])][::-1]))
import sys
from subprocess import call
q=Button(gui, text="Quit", command=lambda *a:sys.exit())
q.grid()
pref=dict(font=("Courier", 44), background="blue", foreground="white")
pref2=dict(font=("Courier", 30), relief="sunken", anchor="w", justify="left" ,background="white", foreground="midnightblue")
expression_field = Entry(gui, textvariable=equation, width=30, **pref)
expression_field.grid(row=0,columnspan=4,)
expression_field.bind("<Key>", key)
error_field = Label(gui, textvariable=error,**pref2)
error_field.grid(columnspan=4, row=1, column=0,)
result_field = Label(gui, textvariable=result, **pref2)
result_field.grid(columnspan=2,sticky ="W", row=2,column=0,rowspan=6)
pile_field = Label(gui, textvariable=deb, **pref2)
pile_field.grid(columnspan=2,sticky ="W", row=2,column=1, rowspan=6)
equation.set('>')
gui.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment