# along with Thun. If not see <http://www.gnu.org/licenses/>.
#
'''
+This module exports a single function for converting text to a joy
+expression as well as a single Symbol class and a single Exception type.
+The Symbol string class is used by the interpreter to recognize literals
+by the fact that they are not Symbol objects.
-§ Converting text to a joy expression.
+A crude grammar::
-This module exports a single function:
+ joy = term*
+ term = int | float | string | '[' joy ']' | function
- text_to_expression(text)
+A Joy expression is a sequence of zero or more terms
-As well as a single Symbol class and a single Exception type:
- ParseError
-
-When supplied with a string this function returns a Python datastructure
-that represents the Joy datastructure described by the text expression.
-Any unbalanced square brackets will raise a ParseError.
'''
+#TODO: explain the details of float lits and strings.
from re import Scanner
from .utils.stack import list_to_stack
class Symbol(str):
+ '''A string class that represents Joy function names.'''
__repr__ = str.__str__
def text_to_expression(text):
- '''
- Convert a text to a Joy expression.
+ '''Convert a string to a Joy expression.
+
+ When supplied with a string this function returns a Python datastructure
+ that represents the Joy datastructure described by the text expression.
+ Any unbalanced square brackets will raise a ParseError.
+
+ :param str text: Text to convert.
+ :rtype: quote
+ :raises ParseError: if the parse fails.
'''
return _parse(_tokenize(text))
-class ParseError(ValueError): pass
+class ParseError(ValueError):
+ '''Raised when there is a error while parsing text.'''
def _tokenize(text):
- '''
- Convert a text into a stream of tokens, converting symbols using
- symbol(token). Raise ValueError (with some of the failing text)
- if the scan fails.
+ '''Convert a text into a stream of tokens.
+
+ Converts function names to Symbols.
+
+ Raise ParseError (with some of the failing text) if the scan fails.
'''
tokens, rest = _scanner.scan(text)
if rest:
# along with Thun. If not see <http://www.gnu.org/licenses/>.
#
'''
-
-
-§ Stack
-
-
-When talking about Joy we use the terms "stack", "list", "sequence" and
-"aggregate" to mean the same thing: a simple datatype that permits
-certain operations such as iterating and pushing and popping values from
-(at least) one end.
+When talking about Joy we use the terms "stack", "list", "sequence",
+"quote" and others to mean the same thing: a simple linear datatype that
+permits certain operations such as iterating and pushing and popping
+values from (at least) one end.
We use the venerable two-tuple recursive form of sequences where the
empty tuple () is the empty stack and (head, rest) gives the recursive
-form of a stack with one or more items on it.
-
- ()
- (1, ())
- (2, (1, ()))
- (3, (2, (1, ())))
- ...
-
-And so on.
-
+form of a stack with one or more items on it::
-We have two very simple functions to build up a stack from a Python
-iterable and also to iterate through a stack and yield its items
-one-by-one in order, and two functions to generate string representations
-of stacks:
+ stack := () | (item, stack)
- list_to_stack()
+Putting some numbers onto a stack::
- iter_stack()
-
- expression_to_string() (prints left-to-right)
-
- stack_to_string() (prints right-to-left)
-
-
-A word about the stack data structure.
+ ()
+ (1, ())
+ (2, (1, ()))
+ (3, (2, (1, ())))
+ ...
Python has very nice "tuple packing and unpacking" in its syntax which
means we can directly "unpack" the expected arguments to a Joy function.
-For example:
+For example::
- def dup(stack):
- head, tail = stack
+ def dup((head, tail)):
return head, (head, tail)
We replace the argument "stack" by the expected structure of the stack,
-in this case "(head, tail)", and Python takes care of de-structuring the
-incoming argument and assigning values to the names. Note that Python
+in this case "(head, tail)", and Python takes care of unpacking the
+incoming tuple and assigning values to the names. (Note that Python
syntax doesn't require parentheses around tuples used in expressions
-where they would be redundant.
+where they would be redundant.)
'''
+##We have two very simple functions to build up a stack from a Python
+##iterable and also to iterate through a stack and yield its items
+##one-by-one in order, and two functions to generate string representations
+##of stacks::
+##
+## list_to_stack()
+##
+## iter_stack()
+##
+## expression_to_string() (prints left-to-right)
+##
+## stack_to_string() (prints right-to-left)
+##
+##
+##A word about the stack data structure.
+
+
def list_to_stack(el, stack=()):
- '''Convert a list (or other sequence) to a stack.
+ '''Convert a Python list (or other sequence) to a Joy stack::
[1, 2, 3] -> (1, (2, (3, ())))
'''
Return a "pretty print" string for a stack.
- The items are written right-to-left:
+ The items are written right-to-left::
- (top, (second, ...)) -> '... second top'
+ (top, (second, ...)) -> '... second top'
'''
f = lambda stack: reversed(list(iter_stack(stack)))
return _to_string(stack, f)
'''
Return a "pretty print" string for a expression.
- The items are written left-to-right:
+ The items are written left-to-right::
- (top, (second, ...)) -> 'top second ...'
+ (top, (second, ...)) -> 'top second ...'
'''
return _to_string(expression, iter_stack)