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