From 5f00921dea3203eaec73e6cdb8c39409d9ddf34a Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Mon, 6 Mar 2017 08:51:25 -0800 Subject: [PATCH] Fix #1243: `read` raises EOFError on false inputs (#1244) * Fix #1243: `read` raises EOFError on false inputs * Fix crash when trying to `eval` false values --- NEWS | 2 ++ hy/compiler.py | 18 ++++++++++-------- hy/core/language.hy | 14 +++++++------- tests/native_tests/language.hy | 24 +++++++++++++++++++++++- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index 89ce8c2..41217ab 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ Changes from 0.12.1 * Shadowed comparison operators now use `and` instead of `&` for chained comparisons * partition no longer prematurely exhausts input iterators + * read and read-str no longer raise an error when the input + parses to a false value (e.g., the empty string) Changes from 0.12.0 diff --git a/hy/compiler.py b/hy/compiler.py index 4ad08e8..740d40b 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -24,9 +24,9 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -from hy.models import (HyExpression, HyKeyword, HyInteger, HyComplex, HyString, - HyBytes, HySymbol, HyFloat, HyList, HySet, HyDict, - HyCons) +from hy.models import (HyObject, HyExpression, HyKeyword, HyInteger, HyComplex, + HyString, HyBytes, HySymbol, HyFloat, HyList, HySet, + HyDict, HyCons) from hy.errors import HyCompileError, HyTypeError from hy.lex.parser import hy_symbol_mangle @@ -2689,7 +2689,10 @@ def hy_compile(tree, module_name, root=ast.Module, get_expr=False): body = [] expr = None - if tree: + if not (isinstance(tree, HyObject) or type(tree) is list): + raise HyCompileError("tree must be a HyObject or a list") + + if isinstance(tree, HyObject) or tree: compiler = HyASTCompiler(module_name) result = compiler.compile(tree) expr = result.force_expr @@ -2697,10 +2700,9 @@ def hy_compile(tree, module_name, root=ast.Module, get_expr=False): if not get_expr: result += result.expr_as_stmt() - if isinstance(tree, list): - spoof_tree = tree[0] - else: - spoof_tree = tree + # We need to test that the type is *exactly* `list` because we don't + # want to do `tree[0]` on HyList or such. + spoof_tree = tree[0] if type(tree) is list else tree body = compiler.imports_as_stmts(spoof_tree) + result.stmts ret = root(body=body) diff --git a/hy/core/language.hy b/hy/core/language.hy index baf8d5d..06a2839 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -435,17 +435,17 @@ [eof ""]] "Read from input and returns a tokenized string. Can take a given input buffer to read from" - (def buff "") + (setv buff "") (while True - (def inn (str (.readline from-file))) + (setv inn (string (.readline from-file))) (if (= inn eof) - (raise (EOFError "Reached end of file" ))) - (setv buff (+ buff inn)) + (raise (EOFError "Reached end of file"))) + (+= buff inn) (try - (def parsed (first (tokenize buff))) + (setv parsed (first (tokenize buff))) (except [e [PrematureEndOfInput IndexError]]) - (else (if parsed (break))))) - parsed) + (else (break)))) + parsed) (defn read-str [input] "Reads and tokenizes first line of input" diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 0b29efd..3717e1e 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -1055,6 +1055,19 @@ (assert (= None (eval (quote (print "")))))) +(defn test-eval-false [] + (assert (is (eval 'False) False)) + (assert (is (eval 'None) None)) + (assert (= (eval '0) 0)) + (assert (= (eval '"") "")) + (assert (= (eval 'b"") b"")) + (assert (= (eval ':) :)) + (assert (= (eval '[]) [])) + (assert (= (eval '(,)) (,))) + (assert (= (eval '{}) {})) + (assert (= (eval '#{}) #{}))) + + (defn test-eval-globals [] "NATIVE: test eval with explicit global dict" (assert (= 'bar (eval (quote foo) {'foo 'bar}))) @@ -1383,7 +1396,16 @@ (defn test-read-str [] "NATIVE: test read-str" - (assert (= (read-str "(print 1)") '(print 1)))) + (assert (= (read-str "(print 1)") '(print 1))) + (assert (is (type (read-str "(print 1)")) (type '(print 1)))) + + ; Watch out for false values: https://github.com/hylang/hy/issues/1243 + (assert (= (read-str "\"\"") '"")) + (assert (is (type (read-str "\"\"")) (type '""))) + (assert (= (read-str "[]") '[])) + (assert (is (type (read-str "[]")) (type '[]))) + (assert (= (read-str "0") '0)) + (assert (is (type (read-str "0")) (type '0)))) (defn test-keyword-creation [] "NATIVE: Test keyword creation"