Add defun (custom functions).
Rename defvar to setq, add local environment and let.
This commit is contained in:
parent
8b7e6ae7ba
commit
ddabe282a4
1 changed files with 92 additions and 44 deletions
132
i3toolwait
132
i3toolwait
|
@ -23,27 +23,37 @@ except ImportError:
|
|||
from yaml import SafeLoader
|
||||
|
||||
|
||||
def lazy_fc_if(env, a, b, c):
|
||||
a.reduce(env)
|
||||
def lazy_fc_if(env, local, a, b, c):
|
||||
a.reduce(env, local)
|
||||
if a.reduced:
|
||||
b.reduce(env)
|
||||
return b
|
||||
c.reduce(env)
|
||||
b.reduce(env, local)
|
||||
return b.reduced
|
||||
c.reduce(env, local)
|
||||
return c.reduced
|
||||
|
||||
def lazy_fc_nif(env, a, b, c):
|
||||
a.reduce(env)
|
||||
def lazy_fc_nif(env, local, a, b, c):
|
||||
a.reduce(env, local)
|
||||
if not a.reduced:
|
||||
b.reduce(env)
|
||||
return b
|
||||
c.reduce(env)
|
||||
b.reduce(env, local)
|
||||
return b.reduced
|
||||
c.reduce(env, local)
|
||||
c.reduced
|
||||
|
||||
def fc_load(env, path):
|
||||
def lazy_fc_defun(env, local, name, variables, func):
|
||||
_ = local
|
||||
# need ugly hack, because variables are actually a function with n-1 args
|
||||
varnames = [variables._fc] + [v._value for v in variables._args]
|
||||
env.set_lisp_function(name._value, varnames, func)
|
||||
|
||||
def fc_load(env, local, path):
|
||||
_ = local
|
||||
ipc_value = env.input
|
||||
for k in path.strip('.').split('.'):
|
||||
ipc_value = ipc_value[k]
|
||||
return ipc_value
|
||||
|
||||
def fc_has_key(env, path):
|
||||
def fc_has_key(env, local, path):
|
||||
_ = local
|
||||
ipc_value = env.input
|
||||
for k in path.strip('.').split('.'):
|
||||
try:
|
||||
|
@ -58,28 +68,31 @@ class Environment:
|
|||
self._input = input
|
||||
self._variables = {}
|
||||
self._functions = {
|
||||
'__last__': lambda *a: a[-1], # special function, if multiple expressions, execute all and return result of last one
|
||||
'defvar': lambda env, n, v: env.set_variable(n, v),
|
||||
'write': lambda _, a: print(a),
|
||||
'__last__': lambda _env, _local, *a: a[-1], # special function, if multiple expressions, execute all and return result of last one
|
||||
'setq': lambda env, _, n, v: env.set_variable(n, v),
|
||||
'let': lambda _, local, n, v: local.set_variable(n, v),
|
||||
'write': lambda _env, _local, a: print(a),
|
||||
'load': fc_load,
|
||||
'has-key': fc_has_key,
|
||||
'=': lambda _, a, b: a == b,
|
||||
'!=': lambda _, a, b: a != b,
|
||||
'>': lambda _, a, b: a > b,
|
||||
'<': lambda _, a, b: a < b,
|
||||
'>=': lambda _, a, b: a >= b,
|
||||
'<=': lambda _, a, b: a <= b,
|
||||
'+': lambda _, *a: sum(a),
|
||||
'-': lambda _, a, b: a - b,
|
||||
'*': lambda _, *a: functools.reduce(lambda a, b: a * b, a),
|
||||
'/': lambda _, a, b: a // b,
|
||||
'|': lambda _, *a: functools.reduce(lambda a, b: a or b, a),
|
||||
'&': lambda _, *a: functools.reduce(lambda a, b: a and b, a),
|
||||
'=': lambda _, _l, a, b: a == b,
|
||||
'!=': lambda _, _l, a, b: a != b,
|
||||
'>': lambda _, _l, a, b: a > b,
|
||||
'<': lambda _, _l, a, b: a < b,
|
||||
'>=': lambda _, _l, a, b: a >= b,
|
||||
'<=': lambda _, _l, a, b: a <= b,
|
||||
'+': lambda _, _l, *a: sum(a),
|
||||
'-': lambda _, _l, a, b: a - b,
|
||||
'*': lambda _, _l, *a: functools.reduce(lambda a, b: a * b, a),
|
||||
'/': lambda _, _l, a, b: a // b,
|
||||
'|': lambda _, _l, *a: functools.reduce(lambda a, b: a or b, a),
|
||||
'&': lambda _, _l, *a: functools.reduce(lambda a, b: a and b, a),
|
||||
}
|
||||
self._lazy_functions = {
|
||||
'?': lazy_fc_if,
|
||||
'!?': lazy_fc_nif,
|
||||
'defun': lazy_fc_defun,
|
||||
}
|
||||
self._lisp_functions = {}
|
||||
|
||||
@property
|
||||
def input(self):
|
||||
|
@ -97,6 +110,28 @@ class Environment:
|
|||
def get_lazy_function(self, name: str):
|
||||
return self._lazy_functions[name]
|
||||
|
||||
def set_lisp_function(self, name: str, vars: list[object], e: object):
|
||||
self._lisp_functions[name] = vars, e
|
||||
|
||||
def get_lisp_function(self, name: str) -> tuple[list[str], object]:
|
||||
return self._lisp_functions[name]
|
||||
|
||||
class LocalEnvironment:
|
||||
|
||||
def __init__(self):
|
||||
self._variables = {}
|
||||
|
||||
def copy(self) -> 'LocalEnvironment':
|
||||
n = LocalEnvironment()
|
||||
n._variables = self._variables.copy()
|
||||
return n
|
||||
|
||||
def set_variable(self, name: str, value: object):
|
||||
self._variables[name] = value
|
||||
|
||||
def get_variable(self, name: str):
|
||||
return self._variables[name]
|
||||
|
||||
class Expression:
|
||||
|
||||
STATE_CONSTRUCTED = 0
|
||||
|
@ -106,14 +141,14 @@ class Expression:
|
|||
self._state = Expression.STATE_CONSTRUCTED
|
||||
self._reduced = None
|
||||
|
||||
def _reduce(self, env: Environment, args: list[object]):
|
||||
_ = env, args
|
||||
def _reduce(self, env: Environment, local: LocalEnvironment, args: list[object]):
|
||||
_ = env, local, args
|
||||
raise NotImplementedError('Implement in subclass')
|
||||
|
||||
def reduce(self, env: Environment):
|
||||
def reduce(self, env: Environment, local: LocalEnvironment):
|
||||
if self._state == Expression.STATE_REDUCED:
|
||||
return
|
||||
self._reduced = self._reduce(env, [])
|
||||
self._reduced = self._reduce(env, local, [])
|
||||
self._state = Expression.STATE_REDUCED
|
||||
|
||||
@property
|
||||
|
@ -131,8 +166,8 @@ class Constant(Expression):
|
|||
def __repr__(self):
|
||||
return repr(self._value)
|
||||
|
||||
def _reduce(self, env: Environment, args: list[Expression]):
|
||||
_ = env, args
|
||||
def _reduce(self, env: Environment, local: LocalEnvironment, args: list[Expression]):
|
||||
_ = env, local, args
|
||||
return self._value
|
||||
|
||||
class VariableSet(Constant):
|
||||
|
@ -140,8 +175,11 @@ class VariableSet(Constant):
|
|||
|
||||
class VariableGet(Constant):
|
||||
|
||||
def _reduce(self, env: Environment, args: list[Expression]):
|
||||
def _reduce(self, env: Environment, local: LocalEnvironment, args: list[Expression]):
|
||||
_ = args
|
||||
try:
|
||||
return local.get_variable(self._value)
|
||||
except KeyError:
|
||||
return env.get_variable(self._value)
|
||||
|
||||
class Function(Expression):
|
||||
|
@ -154,20 +192,30 @@ class Function(Expression):
|
|||
def __repr__(self):
|
||||
return f'({self._fc} {self._args})'
|
||||
|
||||
def _reduce(self, env: Environment, args: list[Expression]):
|
||||
def _reduce(self, env: Environment, local: LocalEnvironment, args: list[Expression]):
|
||||
try:
|
||||
argnames, fc = env.get_lisp_function(self._fc)
|
||||
assert isinstance(fc, Expression)
|
||||
l = local.copy()
|
||||
for an, av in zip(argnames, args):
|
||||
av.reduce(env, l)
|
||||
l.set_variable(an, av.reduced)
|
||||
fc.reduce(env, l)
|
||||
r = fc.reduced
|
||||
except KeyError as e:
|
||||
try:
|
||||
fc = env.get_function(self._fc)
|
||||
[a.reduce(env) for a in args]
|
||||
r = fc(env, *[a.reduced for a in args])
|
||||
except KeyError as e:
|
||||
[a.reduce(env, local) for a in args]
|
||||
r = fc(env, local, *[a.reduced for a in args])
|
||||
except KeyError:
|
||||
fc = env.get_lazy_function(self._fc)
|
||||
r = fc(env, *args)
|
||||
r = fc(env, local, *args)
|
||||
return r
|
||||
|
||||
def reduce(self, env: Environment):
|
||||
def reduce(self, env: Environment, local: LocalEnvironment):
|
||||
if self._state == Expression.STATE_REDUCED:
|
||||
return
|
||||
self._reduced = self._reduce(env, self._args)
|
||||
self._reduced = self._reduce(env, local, self._args)
|
||||
self._state = Expression.STATE_REDUCED
|
||||
|
||||
class Token:
|
||||
|
@ -530,7 +578,7 @@ def window_new(runtime_data: RuntimeData, *, debug):
|
|||
print(json.dumps(e.ipc_data))
|
||||
async with runtime_data.lock:
|
||||
for i, cfg in enumerate(runtime_data.programs):
|
||||
cfg.match.reduce(Environment(e.ipc_data))
|
||||
cfg.match.reduce(Environment(e.ipc_data), LocalEnvironment())
|
||||
if cfg.match.reduced:
|
||||
container_id = e.ipc_data['container']['id']
|
||||
await ipc.command(f'for_window [con_id="{container_id}"] focus')
|
||||
|
|
Loading…
Reference in a new issue