diff --git a/docs/intro/releases.md b/docs/intro/releases.md index a51eb2a6..4c55a74f 100644 --- a/docs/intro/releases.md +++ b/docs/intro/releases.md @@ -18,6 +18,7 @@ Upgraded to LLVM 17 (from 15). - Updates to several existing functions, such as adding `key` and `default` arguments to `min()` and `max()`. - Slice arguments can now be of any type, not just `int`. +- Added `input()` function. ## Other improvements diff --git a/stdlib/internal/builtin.codon b/stdlib/internal/builtin.codon index f14cf825..cc9b77d3 100644 --- a/stdlib/internal/builtin.codon +++ b/stdlib/internal/builtin.codon @@ -34,6 +34,28 @@ def print(*args, sep: str = " ", end: str = "\n", file=_stdout, flush: bool = Fa if flush: _C.fflush(fp) +def input(prompt: str = ""): + stdout = _C.seq_stdout() + stderr = _C.seq_stderr() + stdin = _C.seq_stdin() + _C.fflush(stderr) + _C.fflush(stdout) + print(prompt, end="") + buf = cobj() + n = 0 + s = _C.getline(__ptr__(buf), __ptr__(n), stdin) + if s > 0: + if buf[s - 1] == byte(10): + s -= 1 # skip trailing '\n' + if s != 0 and buf[s - 1] == byte(13): + s -= 1 # skip trailing '\r' + ans = str(buf, s).__ptrcopy__() + _C.free(buf) + return ans + else: + _C.free(buf) + raise EOFError("EOF when reading a line") + @extend class __internal__: def print(*args): diff --git a/stdlib/internal/python.codon b/stdlib/internal/python.codon index 5b57a9b4..c86885a2 100644 --- a/stdlib/internal/python.codon +++ b/stdlib/internal/python.codon @@ -157,6 +157,7 @@ PyExc_RuntimeError = cobj() PyExc_NotImplementedError = cobj() PyExc_StopIteration = cobj() PyExc_AssertionError = cobj() +PyExc_EOFError = cobj() PyExc_SystemExit = cobj() _PY_MODULE_CACHE = Dict[str, pyobj]() @@ -327,6 +328,7 @@ def init_handles_dlopen(py_handle: cobj): global PyExc_NotImplementedError global PyExc_StopIteration global PyExc_AssertionError + global PyExc_EOFError global PyExc_SystemExit Py_DecRef = dlsym(py_handle, "Py_DecRef") @@ -460,6 +462,7 @@ def init_handles_dlopen(py_handle: cobj): PyExc_NotImplementedError = Ptr[cobj](dlsym(py_handle, "PyExc_NotImplementedError", cobj))[0] PyExc_StopIteration = Ptr[cobj](dlsym(py_handle, "PyExc_StopIteration", cobj))[0] PyExc_AssertionError = Ptr[cobj](dlsym(py_handle, "PyExc_AssertionError", cobj))[0] + PyExc_EOFError = Ptr[cobj](dlsym(py_handle, "PyExc_EOFError", cobj))[0] PyExc_SystemExit = Ptr[cobj](dlsym(py_handle, "PyExc_SystemExit", cobj))[0] def init_handles_static(): @@ -594,6 +597,7 @@ def init_handles_static(): from C import PyExc_NotImplementedError: cobj as _PyExc_NotImplementedError from C import PyExc_StopIteration: cobj as _PyExc_StopIteration from C import PyExc_AssertionError: cobj as _PyExc_AssertionError + from C import PyExc_EOFError: cobj as _PyExc_EOFError from C import PyExc_SystemExit: cobj as _PyExc_SystemExit global Py_DecRef @@ -727,6 +731,7 @@ def init_handles_static(): global PyExc_NotImplementedError global PyExc_StopIteration global PyExc_AssertionError + global PyExc_EOFError global PyExc_SystemExit Py_DecRef = _Py_DecRef @@ -860,6 +865,7 @@ def init_handles_static(): PyExc_NotImplementedError = _PyExc_NotImplementedError PyExc_StopIteration = _PyExc_StopIteration PyExc_AssertionError = _PyExc_AssertionError + PyExc_EOFError = _PyExc_EOFError PyExc_SystemExit = _PyExc_SystemExit def init_error_py_types(): @@ -881,6 +887,7 @@ def init_error_py_types(): NotImplementedError._pytype = PyExc_NotImplementedError StopIteration._pytype = PyExc_StopIteration AssertionError._pytype = PyExc_AssertionError + EOFError._pytype = PyExc_EOFError SystemExit._pytype = PyExc_SystemExit def setup_python(python_loaded: bool): diff --git a/stdlib/internal/types/error.codon b/stdlib/internal/types/error.codon index 0b53b9dc..f863edab 100644 --- a/stdlib/internal/types/error.codon +++ b/stdlib/internal/types/error.codon @@ -152,6 +152,12 @@ class AssertionError(Static[Exception]): super().__init__("AssertionError", message) self.python_type = self.__class__._pytype +class EOFError(Static[Exception]): + _pytype: ClassVar[cobj] = cobj() + def __init__(self, message: str = ""): + super().__init__("EOFError", message) + self.python_type = self.__class__._pytype + class SystemExit(Static[BaseException]): _pytype: ClassVar[cobj] = cobj() _status: int diff --git a/test/app/input.codon b/test/app/input.codon new file mode 100644 index 00000000..1b622b75 --- /dev/null +++ b/test/app/input.codon @@ -0,0 +1,7 @@ +print(input("input: "), end=',') +print(input(), end=',') +print(input(), end=',') +try: + input() +except EOFError: + print('X') diff --git a/test/app/input.txt b/test/app/input.txt new file mode 100644 index 00000000..f602501c --- /dev/null +++ b/test/app/input.txt @@ -0,0 +1,3 @@ +aa bb + +cc \ No newline at end of file diff --git a/test/app/test.sh b/test/app/test.sh index 038644f8..faed0327 100755 --- a/test/app/test.sh +++ b/test/app/test.sh @@ -18,3 +18,6 @@ gcc "$testdir/test.c" -L"$arg" -Wl,-rpath,"$arg" -lcodon_export_test -o "$arg/te # exit code test $codon run "$testdir/exit.codon" || if [[ $? -ne 42 ]]; then exit 4; fi + +# input test +[ "$($codon run "$testdir/input.codon" < "$testdir/input.txt")" == "input: aa bb,,cc,X" ] || exit 5