this takes evaluated left and right (i.e. values not expressions)

def evalop(op,left,right):
  "this takes evaluated left and right (i.e. values not expressions)"
  if op in ('=','!=','>','<'): return threevl.ThreeVL.compare(op,left,right)
  elif op in ('+','-','*','/'): # todo: does arithmetic require threevl?
    if op=='/': raise NotImplementedError('todo: spec about int/float division')
    return (left + right) if op=='+' else (left - right) if op=='-' else (left * right) if op=='*' else (left/right)
  elif op=='in': return (tuple(left) in right) if isinstance(left,list) and isinstance(right[0],tuple) else (left in right)
  elif op in ('and','or'): return threevl.ThreeVL.andor(op,left,right)
  elif op in ('is not','is'):
    if right is not None: raise NotImplementedError('can null be on either side? what if neither value is null?')
    return (left is not None) if (op=='is not') else (left is None)
  elif op=='@>':
    # todo: support a TextSearchDoc that will overload a lot of these operators
    if not all(isinstance(x,list) for x in (left,right)): raise TypeError('non-array-args',op,left,right)
    return set(left)>=set(right)
  elif op=='||':
    if not all(isinstance(x,list) for x in (left,right)): raise TypeError('non-array-args',op,left,right)
    return left+right
  elif op=='@@':
    if not all(isinstance(x,set) for x in (left,right)): raise TypeError('non_set_args',op,type(left),type(right))
    return bool(left&right)
  else: raise NotImplementedError(op,left,right)