From cf0ae625ddc9076e0ca02079b8d461de22244998 Mon Sep 17 00:00:00 2001 From: mryouse Date: Tue, 5 Jul 2022 03:24:17 +0000 Subject: start to standardize :handle --- neb/std/fs.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- neb/std/types.py | 7 +++++ 2 files changed, 82 insertions(+), 5 deletions(-) (limited to 'neb/std') diff --git a/neb/std/fs.py b/neb/std/fs.py index 495c7ea..d20cde9 100644 --- a/neb/std/fs.py +++ b/neb/std/fs.py @@ -2,9 +2,15 @@ from .. import TypeEnum, Environment, Arg, Builtin, evaluate, InterpretPanic from ..structs import * from pathlib import Path from glob import glob +from io import UnsupportedOperation +import sys FS = Environment() +FS.register("_stdin_", Handle(sys.stdin)) +FS.register("_stdout_", Handle(sys.stdout)) +FS.register("_stderr_", Handle(sys.stderr)) + def interpretExists(symbol, args, env, ns): return Bool(Path(args[0].value).resolve().exists()) @@ -39,13 +45,77 @@ def interpretWithWrite(symbol, args, env, ns): FS.register("with-write", Builtin("with-write", interpretWithWrite, [Arg("filename", TypeEnum.STRING)], Arg("exprs", TypeEnum.ANY, lazy=True))) def interpretWrite(symbol, args, env, ns): - # write :string :filehandle - line = args[0] + string = args[0] handle = args[1] - handle.args[0].write(line.value) # TODO wrong! how do we evaluate a handle? - return Literal([]) + try: + handle.file.write(string.value) + except UnsupportedOperation: + raise InterpretPanic(symbol, f"{handle} is not writable!") + except ValueError: + raise InterpretPanic(symbol, f"{handle} is closed") + return List([]) + +FS.register("write", Builtin("write", interpretWrite, [Arg("string", TypeEnum.STRING), Arg("handle", TypeEnum.HANDLE)], return_type=TypeEnum.LIST)) + +def interpretOpenRead(symbol, args, env, ns): + name = args[0].value + fil = Path(name) + if not fil.exists(): + raise InterpretPanic(symbol, "file does not exist", fil) + try: + f = open(str(fil), "r") + except: + raise InterpretPanic(symbol, "cannot open {fil} for reading") + return Handle(f) + +FS.register("open-read", Builtin("open-read", interpretOpenRead, [Arg("filename", TypeEnum.STRING)], return_type=TypeEnum.HANDLE)) + +def interpretOpenWrite(symbol, args, env, ns): + name = args[0].value + fil = Path(name) + try: + f = open(str(fil), "w") + except: + raise InterpretPanic(symbol, "cannot open {fil} for writing") + return Handle(f) + +FS.register("open-write", Builtin("open-write", interpretOpenWrite, [Arg("filename", TypeEnum.STRING)], return_type=TypeEnum.HANDLE)) + +def interpretOpenAppend(symbol, args, env, ns): + name = args[0].value + fil = Path(name) + try: + f = open(str(fil), "a") + except: + raise InterpretPanic(symbol, "cannot open {fil} for appending") + return Handle(f) + +FS.register("open-append", Builtin("open-append", interpretOpenAppend, [Arg("filename", TypeEnum.STRING)], return_type=TypeEnum.HANDLE)) + +def interpretClose(symbol, args, env, ns): + try: + args[0].file.close() + # TODO ideally we'd be able to remove it from the env + # but by this point, we don't know its symbol + # though it may not be in the env, e.g. + # (close (print (read (open-read "fil.txt")))) + except: + raise InterpretPanic(symbol, "cannot close {args[0]}") + return List([]) + +FS.register("close", Builtin("close", interpretClose, [Arg("handle", TypeEnum.HANDLE)], return_type=TypeEnum.LIST)) + +def interpretRead(symbol, args, env, ns): + handle = args[0] + try: + inp = args[0].file.read() + except UnsupportedOperation: + raise InterpretPanic(symbol, f"{handle} is not writable!") + except ValueError: + raise InterpretPanic(symbol, f"{handle} is closed") + return String(inp) -FS.register("write", Builtin("write", interpretWrite, [Arg("string", TypeEnum.STRING), Arg("filename", TypeEnum.LIST)])) +FS.register("read", Builtin("read", interpretRead, [Arg("handle", TypeEnum.HANDLE)], return_type=TypeEnum.STRING)) def interpretReadLines(symbol, args, env, ns): target_file_name = args[0].value diff --git a/neb/std/types.py b/neb/std/types.py index f8d5405..872f29a 100644 --- a/neb/std/types.py +++ b/neb/std/types.py @@ -69,6 +69,11 @@ def interpretIsLiteral(symbol, args, env, ns): TYPES.register("literal?", Builtin("literal?", interpretIsLiteral, [Arg("arg", TypeEnum.ANY)], return_type=Type(":bool"))) +def interpretIsHandle(symbol, args, env, ns): + return Bool(isinstance(args[0], Handle)) + +TYPES.register("handle?", Builtin("handle?", interpretIsHandle, [Arg("arg", TypeEnum.ANY)], return_type=Type(":bool"))) + # add types to env any_type = NebType(":any", None, interpretIsAny) literal_type = NebType(":literal", any_type, interpretIsLiteral) @@ -78,6 +83,7 @@ bool_type = NebType(":bool", literal_type, interpretIsBool) number_type = NebType(":number", literal_type, interpretIsNumber) int_type = NebType(":int", number_type, interpretIsInt) float_type = NebType(":float", number_type, interpretIsFloat) +handle_type = NebType(":handle", any_type, interpretIsHandle) TYPES.register(":any", any_type) TYPES.register(":literal", literal_type) @@ -87,3 +93,4 @@ TYPES.register(":bool", bool_type) TYPES.register(":number", number_type) TYPES.register(":int", int_type) TYPES.register(":float", float_type) +TYPES.register(":handle", handle_type) -- cgit v1.2.3