Type-guard the ops.
This commit is contained in:
parent
67fd88f68a
commit
4f48ffbb5f
|
|
@ -44,6 +44,10 @@ class NotAnIntError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NotABoolError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StackUnderflowError(Exception):
|
class StackUnderflowError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -142,13 +146,16 @@ token_scanner = Scanner(
|
||||||
|
|
||||||
|
|
||||||
class Symbol(str):
|
class Symbol(str):
|
||||||
'''A string class that represents Joy function names.'''
|
'''
|
||||||
|
A string class that represents Joy function names.
|
||||||
|
'''
|
||||||
|
|
||||||
__repr__ = str.__str__
|
__repr__ = str.__str__
|
||||||
|
|
||||||
|
|
||||||
def text_to_expression(text):
|
def text_to_expression(text):
|
||||||
'''Convert a string to a Joy expression.
|
'''
|
||||||
|
Convert a string to a Joy expression.
|
||||||
|
|
||||||
When supplied with a string this function returns a Python datastructure
|
When supplied with a string this function returns a Python datastructure
|
||||||
that represents the Joy datastructure described by the text expression.
|
that represents the Joy datastructure described by the text expression.
|
||||||
|
|
@ -162,7 +169,9 @@ def text_to_expression(text):
|
||||||
|
|
||||||
|
|
||||||
class ParseError(ValueError):
|
class ParseError(ValueError):
|
||||||
'''Raised when there is a error while parsing text.'''
|
'''
|
||||||
|
Raised when there is a error while parsing text.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
def _tokenize(text):
|
def _tokenize(text):
|
||||||
|
|
@ -804,21 +813,80 @@ def swap(stack):
|
||||||
return (a1, (a2, s23))
|
return (a1, (a2, s23))
|
||||||
|
|
||||||
|
|
||||||
def BinaryFunc(f):
|
def BinaryLogicWrapper(f):
|
||||||
'''
|
'''
|
||||||
Wrap functions that take two arguments and return a single result.
|
Wrap functions that take two numbers and return a single result.
|
||||||
|
'''
|
||||||
|
@wraps(f)
|
||||||
|
def inner(stack, expression, dictionary):
|
||||||
|
try:
|
||||||
|
(a, (b, stack)) = stack
|
||||||
|
except ValueError:
|
||||||
|
raise StackUnderflowError('Not enough values on stack.')
|
||||||
|
if (not isinstance(a, bool)
|
||||||
|
or not isinstance(b, bool)
|
||||||
|
):
|
||||||
|
raise NotABoolError
|
||||||
|
result = f(b, a)
|
||||||
|
return (result, stack), expression, dictionary
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
def BinaryMathWrapper(func):
|
||||||
|
'''
|
||||||
|
Wrap functions that take two numbers and return a single result.
|
||||||
|
'''
|
||||||
|
@wraps(func)
|
||||||
|
def inner(stack, expression, dictionary):
|
||||||
|
try:
|
||||||
|
(a, (b, stack)) = stack
|
||||||
|
except ValueError:
|
||||||
|
raise StackUnderflowError('Not enough values on stack.')
|
||||||
|
if ( not isinstance(a, int)
|
||||||
|
or not isinstance(b, int)
|
||||||
|
or isinstance(a, bool)
|
||||||
|
or isinstance(b, bool)
|
||||||
|
):
|
||||||
|
raise NotAnIntError
|
||||||
|
result = func(b, a)
|
||||||
|
return (result, stack), expression, dictionary
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
def UnaryLogicWrapper(f):
|
||||||
|
'''
|
||||||
|
Wrap functions that take one argument and return a single result.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def inner(stack, expression, dictionary):
|
def inner(stack, expression, dictionary):
|
||||||
(a, (b, stack)) = stack
|
(a, stack) = stack
|
||||||
result = f(b, a)
|
if not isinstance(a, bool):
|
||||||
|
raise NotABoolError
|
||||||
|
result = f(a)
|
||||||
return (result, stack), expression, dictionary
|
return (result, stack), expression, dictionary
|
||||||
|
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
|
|
||||||
def UnaryBuiltinWrapper(f):
|
def UnaryMathWrapper(f):
|
||||||
|
'''
|
||||||
|
Wrap functions that take one argument and return a single result.
|
||||||
|
'''
|
||||||
|
|
||||||
|
@wraps(f)
|
||||||
|
def inner(stack, expression, dictionary):
|
||||||
|
(a, stack) = stack
|
||||||
|
if (not isinstance(b, int)
|
||||||
|
or isinstance(a, bool)):
|
||||||
|
raise NotAnIntError
|
||||||
|
result = f(a)
|
||||||
|
return (result, stack), expression, dictionary
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
def UnaryWrapper(f):
|
||||||
'''
|
'''
|
||||||
Wrap functions that take one argument and return a single result.
|
Wrap functions that take one argument and return a single result.
|
||||||
'''
|
'''
|
||||||
|
|
@ -839,39 +907,40 @@ for F in (
|
||||||
##██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██╔══██║██╔══██╗██║╚════██║██║██║ ██║██║╚██╗██║
|
##██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██╔══██║██╔══██╗██║╚════██║██║██║ ██║██║╚██╗██║
|
||||||
##╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ██║ ██║██║ ██║██║███████║██║╚██████╔╝██║ ╚████║
|
##╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ██║ ██║██║ ██║██║███████║██║╚██████╔╝██║ ╚████║
|
||||||
## ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝
|
## ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝
|
||||||
BinaryFunc(operator.eq),
|
BinaryMathWrapper(operator.eq),
|
||||||
BinaryFunc(operator.ge),
|
BinaryMathWrapper(operator.ge),
|
||||||
BinaryFunc(operator.gt),
|
BinaryMathWrapper(operator.gt),
|
||||||
BinaryFunc(operator.le),
|
BinaryMathWrapper(operator.le),
|
||||||
BinaryFunc(operator.lt),
|
BinaryMathWrapper(operator.lt),
|
||||||
BinaryFunc(operator.ne),
|
BinaryMathWrapper(operator.ne),
|
||||||
##██╗ ██████╗ ██████╗ ██╗ ██████╗
|
##██╗ ██████╗ ██████╗ ██╗ ██████╗
|
||||||
##██║ ██╔═══██╗██╔════╝ ██║██╔════╝
|
##██║ ██╔═══██╗██╔════╝ ██║██╔════╝
|
||||||
##██║ ██║ ██║██║ ███╗██║██║
|
##██║ ██║ ██║██║ ███╗██║██║
|
||||||
##██║ ██║ ██║██║ ██║██║██║
|
##██║ ██║ ██║██║ ██║██║██║
|
||||||
##███████╗╚██████╔╝╚██████╔╝██║╚██████╗
|
##███████╗╚██████╔╝╚██████╔╝██║╚██████╗
|
||||||
##╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
|
##╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
|
||||||
BinaryFunc(operator.xor),
|
UnaryWrapper(bool), # Convert any value to Boolean.
|
||||||
BinaryFunc(operator.and_),
|
# (The only polymorphic function.)
|
||||||
BinaryFunc(operator.or_),
|
BinaryLogicWrapper(operator.xor),
|
||||||
UnaryBuiltinWrapper(operator.not_),
|
BinaryLogicWrapper(operator.and_),
|
||||||
|
BinaryLogicWrapper(operator.or_),
|
||||||
|
UnaryLogicWrapper(operator.not_),
|
||||||
##███╗ ███╗ █████╗ ████████╗██╗ ██╗
|
##███╗ ███╗ █████╗ ████████╗██╗ ██╗
|
||||||
##████╗ ████║██╔══██╗╚══██╔══╝██║ ██║
|
##████╗ ████║██╔══██╗╚══██╔══╝██║ ██║
|
||||||
##██╔████╔██║███████║ ██║ ███████║
|
##██╔████╔██║███████║ ██║ ███████║
|
||||||
##██║╚██╔╝██║██╔══██║ ██║ ██╔══██║
|
##██║╚██╔╝██║██╔══██║ ██║ ██╔══██║
|
||||||
##██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║
|
##██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║
|
||||||
##╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
|
##╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
|
||||||
BinaryFunc(operator.lshift),
|
BinaryMathWrapper(operator.lshift),
|
||||||
BinaryFunc(operator.rshift),
|
BinaryMathWrapper(operator.rshift),
|
||||||
BinaryFunc(operator.add),
|
BinaryMathWrapper(operator.add),
|
||||||
BinaryFunc(operator.floordiv),
|
BinaryMathWrapper(operator.floordiv),
|
||||||
BinaryFunc(operator.mod),
|
BinaryMathWrapper(operator.mod),
|
||||||
BinaryFunc(operator.mul),
|
BinaryMathWrapper(operator.mul),
|
||||||
BinaryFunc(operator.pow),
|
BinaryMathWrapper(operator.pow),
|
||||||
BinaryFunc(operator.sub),
|
BinaryMathWrapper(operator.sub),
|
||||||
UnaryBuiltinWrapper(abs),
|
UnaryMathWrapper(abs),
|
||||||
UnaryBuiltinWrapper(bool),
|
UnaryMathWrapper(operator.neg),
|
||||||
UnaryBuiltinWrapper(operator.neg),
|
|
||||||
):
|
):
|
||||||
inscribe(F)
|
inscribe(F)
|
||||||
|
|
||||||
|
|
@ -887,8 +956,16 @@ for F in (
|
||||||
|
|
||||||
|
|
||||||
class Def(object):
|
class Def(object):
|
||||||
|
'''
|
||||||
|
Definitions are given by equations:
|
||||||
|
|
||||||
tribar = '\u2261' # ≡
|
name ≡ foo bar baz ...
|
||||||
|
|
||||||
|
When a definition symbol is evaluated its body expression is put onto
|
||||||
|
the pending expression.
|
||||||
|
'''
|
||||||
|
|
||||||
|
tribar = '\u2261' # '≡'
|
||||||
|
|
||||||
def __init__(self, name, body):
|
def __init__(self, name, body):
|
||||||
self.__doc__ = f'{name} {self.tribar} {expression_to_string(body)}'
|
self.__doc__ = f'{name} {self.tribar} {expression_to_string(body)}'
|
||||||
|
|
@ -901,6 +978,10 @@ class Def(object):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_definitions(class_, stream, dictionary):
|
def load_definitions(class_, stream, dictionary):
|
||||||
|
'''
|
||||||
|
Given an iterable of lines (strings) and a dictionary put any
|
||||||
|
definitions (lines with '≡' in them) into the dictionary.
|
||||||
|
'''
|
||||||
for line in stream:
|
for line in stream:
|
||||||
if class_.tribar not in line:
|
if class_.tribar not in line:
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue