From 016d25d104f5f5a26def51be40ac08c7c5644738 Mon Sep 17 00:00:00 2001 From: Ryan Gonzalez Date: Fri, 26 Jun 2015 16:10:22 -0500 Subject: [PATCH] Add one-argument division and rationals (closes #825 and #826) --- docs/language/core.rst | 20 ++++++++++++++++++++ docs/tutorial.rst | 4 ++++ hy/compiler.py | 7 ++++--- hy/core/language.hy | 15 ++++++++------- hy/lex/parser.py | 8 ++++++++ tests/lex/test_lex.py | 7 +++++++ tests/native_tests/language.hy | 5 +++++ 7 files changed, 56 insertions(+), 10 deletions(-) diff --git a/docs/language/core.rst b/docs/language/core.rst index a3dd511..077907a 100644 --- a/docs/language/core.rst +++ b/docs/language/core.rst @@ -207,6 +207,26 @@ Returns ``True`` if *x* is a float. False +.. _fraction-fn: + +fraction +-------- + +Returns a Python object of type ``fractions.Fraction``. + +.. code-block:: hy + + => (fraction 1 2) + Fraction(1, 2) + +Note that Hy has a built-in fraction literal that does the same thing: + +.. code-block:: hy + + => 1/2 + Fraction(1, 2) + + .. _even?-fn: even? diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 88a6d9e..6b32b30 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -200,6 +200,10 @@ Hy. Let's experiment with this in the hy interpreter:: (1, 2, 3) => #{3 1 2} {1, 2, 3} + => 1/2 + Fraction(1, 2) + +Notice the last two lines: Hy has a fraction literal like Clojure. If you are familiar with other Lisps, you may be interested that Hy supports the Common Lisp method of quoting: diff --git a/hy/compiler.py b/hy/compiler.py index 5da2b4b..043d9a0 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1721,8 +1721,6 @@ class HyASTCompiler(object): col_offset=e.start_column) @builds("%") - @builds("/") - @builds("//") @builds("**") @builds("<<") @builds(">>") @@ -1764,11 +1762,14 @@ class HyASTCompiler(object): @builds("+") @builds("*") + @builds("/") + @builds("//") def compile_maths_expression_mul(self, expression): if len(expression) > 2: return self.compile_maths_expression(expression) else: - id_op = {"+": HyInteger(0), "*": HyInteger(1)} + id_op = {"+": HyInteger(0), "*": HyInteger(1), "/": HyInteger(1), + "//": HyInteger(1)} op = expression.pop(0) arg = expression.pop(0) if expression else id_op[op] diff --git a/hy/core/language.hy b/hy/core/language.hy index 3922a71..b17f041 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -26,6 +26,7 @@ (import itertools) (import functools) (import collections) +(import [fractions [Fraction :as fraction]]) (import sys) (import [hy._compat [long-type]]) ; long for python2, int for python3 (import [hy.models.cons [HyCons]] @@ -418,10 +419,10 @@ (def *exports* '[Botsbuildbots butlast calling-module-name coll? cons cons? cycle dec distinct disassemble drop drop-last drop-while empty? even? - every? first filter filterfalse flatten float? gensym identity - inc input instance? integer integer? integer-char? interleave - interpose iterable? iterate iterator? keyword keyword? last list* - macroexpand macroexpand-1 map merge-with name neg? nil? none? - nth numeric? odd? pos? range read remove repeat repeatedly - rest reduce second some string string? symbol? take take-nth - take-while zero? zip zip_longest zipwith]) + every? first filter filterfalse flatten float? fraction gensym + identity inc input instance? integer integer? integer-char? + interleave interpose iterable? iterate iterator? keyword + keyword? last list* macroexpand macroexpand-1 map merge-with + name neg? nil? none? nth numeric? odd? pos? range read remove + repeat repeatedly rest reduce second some string string? + symbol? take take-nth take-while zero? zip zip_longest zipwith]) diff --git a/hy/lex/parser.py b/hy/lex/parser.py index 04aa121..a63be3e 100644 --- a/hy/lex/parser.py +++ b/hy/lex/parser.py @@ -266,6 +266,14 @@ def t_identifier(p): except ValueError: pass + if '/' in obj: + try: + lhs, rhs = obj.split('/') + return HyExpression([HySymbol('fraction'), HyInteger(lhs), + HyInteger(rhs)]) + except ValueError: + pass + try: return HyFloat(obj) except ValueError: diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index 07429d4..cc95675 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -108,6 +108,13 @@ def test_lex_integers(): assert objs == [HyInteger(42)] +def test_lex_fractions(): + """ Make sure that fractions are valid expressions""" + objs = tokenize("1/2") + assert objs == [HyExpression([HySymbol("fraction"), HyInteger(1), + HyInteger(2)])] + + def test_lex_expression_float(): """ Make sure expressions can produce floats """ objs = tokenize("(foo 2.)") diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 11fde4d..08804c0 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -12,6 +12,11 @@ (assert (isinstance sys.argv list))) +(defn test-fractions [] + "NATIVE: test fractions" + (assert (= 1/2 (fraction 1 2)))) + + (defn test-lists [] "NATIVE: test lists work right" (assert (= [1 2 3 4] (+ [1 2] [3 4]))))