From b9f8075cf0e07b7c5febc7d4a475ef5184514afa Mon Sep 17 00:00:00 2001 From: mryouse Date: Mon, 4 Jul 2022 01:36:45 +0000 Subject: implement bench function --- neb/std/sys.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'neb/std') diff --git a/neb/std/sys.py b/neb/std/sys.py index 61e83c2..3dc87e9 100644 --- a/neb/std/sys.py +++ b/neb/std/sys.py @@ -3,6 +3,7 @@ from ..structs import * import shlex import subprocess import sys +from datetime import datetime SYS = Environment() @@ -33,3 +34,12 @@ def interpretPrint(symbol, args, env, ns): return List([]) # print returns nothing SYS.register("print", Builtin("print", interpretPrint, [Arg("arg", TypeEnum.STRING)], return_type=Type(":list"))) + +def interpretBench(symbol, args, env, ns): + before = datetime.now() + ret = evaluate(args[0], env, ns) + after = datetime.now() + print(f"bench [{symbol.line}]: {args[0]} => {after - before}") + return ret + +SYS.register("bench", Builtin("bench", interpretBench, [Arg("command", TypeEnum.ANY, lazy=True)], return_type=Type(":any"))) -- cgit v1.2.3 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/__init__.py | 2 +- neb/std/fs.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- neb/std/types.py | 7 +++++ neb/structs.py | 6 +++++ neb/typeclass.py | 1 + 5 files changed, 90 insertions(+), 6 deletions(-) (limited to 'neb/std') diff --git a/neb/__init__.py b/neb/__init__.py index 9b3c1e9..7296c58 100644 --- a/neb/__init__.py +++ b/neb/__init__.py @@ -11,7 +11,7 @@ def interpret(exprs, env, ns=None): return ret def evaluate(expr, env, ns=None): - if isinstance(expr, Literal) or isinstance(expr, Function) or isinstance(expr, TypeWrap) or isinstance(expr, List): + if isinstance(expr, Literal) or isinstance(expr, Function) or isinstance(expr, TypeWrap) or isinstance(expr, List) or isinstance(expr, Handle): return expr elif isinstance(expr, Symbol) or isinstance(expr, Type): if env.contains(expr.name): 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) diff --git a/neb/structs.py b/neb/structs.py index b8effd0..8598344 100644 --- a/neb/structs.py +++ b/neb/structs.py @@ -91,6 +91,12 @@ class String(Literal): def __str__(self): return f'"{repr(self.value)[1:-1]}"' +class Handle: + def __init__(self, file): + self.file = file + def __str__(self): + return f"{self.file.name} :handle" + class Type: def __init__(self, name): self.name = name diff --git a/neb/typeclass.py b/neb/typeclass.py index 9e37a2d..a6daaf9 100644 --- a/neb/typeclass.py +++ b/neb/typeclass.py @@ -9,6 +9,7 @@ class TypeEnum(Enum): LIST = auto() LITERAL = auto() BOOL = auto() + HANDLE = auto() USER = auto() def __str__(self): -- cgit v1.2.3