aboutsummaryrefslogtreecommitdiff
path: root/neb
diff options
context:
space:
mode:
authormryouse2022-07-09 02:39:27 +0000
committermryouse2022-07-09 02:39:27 +0000
commit4038aa87fddbe7e79c61603cf8d4514ebb47f3fe (patch)
tree8f5493f5fb8d9f9ea1de4cd1ade03b7d6c9447d9 /neb
parent7ffeef0faef3fbc389069df853109afc76260f0d (diff)
parent4fb8873f45c8596ba044c87060191778b8238952 (diff)
Merge branch 'master' into feature/listtypes
Diffstat (limited to 'neb')
-rw-r--r--neb/__init__.py44
-rw-r--r--neb/std/boolean.py25
-rw-r--r--neb/std/core.py172
-rw-r--r--neb/std/fs.py13
-rw-r--r--neb/std/functools.py10
-rw-r--r--neb/std/repl.py28
-rw-r--r--neb/std/sys.py9
-rw-r--r--neb/structs.py11
8 files changed, 187 insertions, 125 deletions
diff --git a/neb/__init__.py b/neb/__init__.py
index 42e1d00..e3167b9 100644
--- a/neb/__init__.py
+++ b/neb/__init__.py
@@ -12,7 +12,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) or isinstance(expr, Handle):
+ if isinstance(expr, Literal) or isinstance(expr, Callable) 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):
@@ -51,7 +51,8 @@ def evaluate(expr, env, ns=None):
else:
raise InterpretPanic(expr.args[0], "unable to evaluate")
-class Function:
+
+class Callable:
def __init__(self, name, params, body, args=None, many=None):
self.name = name
@@ -84,7 +85,35 @@ class Function:
raise InterpretPanic(symbol, f"expected [{fmt}] arguments, received {len(params)}")
return True
- def evaluate_args(self, symbol, params, env, ns):
+ def call(self, expr, env):
+ pass
+
+class Special(Callable):
+
+ def __init__(self, name, params, body, args=None, many=None):
+ super().__init__(name, params, body, args, many)
+
+class NebSyntax(Special):
+
+ def __init__(self, name, callable_, args=None, many=None, return_type=None):
+ super().__init__(name, None, callable_, args, many)
+ if return_type is not None:
+ self.return_type = return_type
+
+ def __str__(self):
+ return f"syntax function {self.name}"
+
+ def call(self, expr, env, ns):
+ self.arity_check(expr.args[0], expr.args[1:])
+ return self.body(expr.args[0], expr.args[1:], env, ns)
+
+
+class Function(Callable):
+
+ def __init__(self, name, params, body, args=None, many=None):
+ super().__init__(name, params, body, args, many)
+
+ def precall(self, symbol, params, env, ns):
ret = []
for idx, param in enumerate(params):
@@ -92,9 +121,6 @@ class Function:
arg = self.args[idx]
else:
arg = self.many
- if arg.lazy:
- ret.append(param)
- continue
ev = evaluate(param, env, ns)
expected_type = evaluate(arg.type_, env, ns)
valid = expected_type.validate_type(ev, env, ns)
@@ -105,8 +131,6 @@ class Function:
ret.append(ev)
return ret
- def call(self, expr, env):
- pass
class Builtin(Function):
@@ -120,7 +144,7 @@ class Builtin(Function):
def call(self, expr, env, ns):
self.arity_check(expr.args[0], expr.args[1:])
- evaluated_args = self.evaluate_args(expr.args[0], expr.args[1:], env, ns)
+ evaluated_args = self.precall(expr.args[0], expr.args[1:], env, ns)
return self.body(expr.args[0], evaluated_args, env, ns)
@@ -172,7 +196,7 @@ class UserFunction(Function):
def call(self, expr, env, ns):
self.arity_check(expr.args[0], expr.args[1:])
- evaluated_args = self.evaluate_args(expr.args[0], expr.args[1:], env, ns)
+ evaluated_args = self.precall(expr.args[0], expr.args[1:], env, ns)
this_env = Environment(env)
for idx, param in enumerate(self.params):
this_env.register(param.name, evaluated_args[idx])
diff --git a/neb/std/boolean.py b/neb/std/boolean.py
index 973fa67..e716a87 100644
--- a/neb/std/boolean.py
+++ b/neb/std/boolean.py
@@ -3,31 +3,6 @@ from ..structs import *
BOOLEAN = Environment()
-def interpretOr(symbol, args, env, ns):
- # or returns true for the first expression that returns true
- for arg in args:
- ev = evaluate(arg, env, ns)
- if not isinstance(ev, Bool):
- raise InterpretPanic(symbol, "requires :bool arguments")
- if ev.value == True:
- return ev
- return Bool(False)
-
-or_arg = Arg("arg", TypeEnum.BOOL, lazy=True)
-BOOLEAN.register("or", Builtin("or", interpretOr, [or_arg, or_arg], or_arg, Type(":bool")))
-
-def interpretAnd(symbol, args, env, ns):
- # and returns false for the first expression that returns false
- for arg in args:
- ev = evaluate(arg, env, ns)
- if not isinstance(ev, Bool):
- raise InterpretPanic(symbol, "requires :bool arguments")
- if ev.value == False:
- return ev
- return Bool(True)
-
-BOOLEAN.register("and", Builtin("and", interpretAnd, [or_arg, or_arg], or_arg, Type(":bool")))
-
def interpretEq(symbol, args, env, ns):
# NOTE this currently only works for literals
# compare types because 0 != #false in neb
diff --git a/neb/std/core.py b/neb/std/core.py
index a44417c..9e2e743 100644
--- a/neb/std/core.py
+++ b/neb/std/core.py
@@ -1,48 +1,49 @@
-from .. import TypeEnum, Environment, Arg, Builtin, UserFunction, evaluate, interpret, parse, lex, InterpretPanic, TypeWrap, Function, UserType
+from .. import TypeEnum, Environment, Arg, Builtin, UserFunction, evaluate, interpret, parse, lex, InterpretPanic, TypeWrap, Function, UserType, NebSyntax
from ..structs import *
from pathlib import Path
CORE = Environment()
def interpretIf(symbol, args, env, ns):
- if args[0].value:
+ cond = evaluate(args[0], env, ns)
+ if not isinstance(cond, Bool):
+ raise InterpretPanic(symbol, "requires a :bool condition", cond)
+
+ if cond.value:
return evaluate(args[1], env, ns)
elif len(args) == 3:
return evaluate(args[2], env, ns)
return List([])
cond = Arg("cond", TypeEnum.BOOL)
-t_branch = Arg("t-branch", TypeEnum.ANY, lazy=True)
-f_branch = Arg("f-branch", TypeEnum.ANY, optional=True, lazy=True)
-CORE.register("if", Builtin("if", interpretIf, [cond, t_branch, f_branch]))
+t_branch = Arg("t-branch", TypeEnum.ANY)
+f_branch = Arg("f-branch", TypeEnum.ANY, optional=True)
+CORE.register("if", NebSyntax("if", interpretIf, [cond, t_branch, f_branch]))
def interpretDef(symbol, args, env, ns):
-
if not isinstance(args[0], Symbol):
- raise InterpretPanic(symbol, "requires a :string name", args[0])
+ raise InterpretPanic(symbol, "requires a :symbol", args[0])
name = args[0].name # NOTE: we are not evaluating the name!!
- if not isinstance(name, str):
- raise InterpretPanic(symbol, "requires a :string name")
-
- env.register(name, args[1]) # TODO since this isn't lazily evaluated, side effects are allowed (bad!)
-
+ res = evaluate(args[1], env, ns)
+ env.register(name, res)
return List([])
-def_name_arg = Arg("name", TypeEnum.ANY, lazy=True)
+def_name_arg = Arg("name", TypeEnum.ANY)
def_val_arg = Arg("value", TypeEnum.ANY)
-CORE.register("def", Builtin("def", interpretDef, [def_name_arg, def_val_arg], return_type=Type(":list")))
+CORE.register("def", NebSyntax("def", interpretDef, [def_name_arg, def_val_arg], return_type=Type(":list")))
def interpretRedef(symbol, args, env, ns):
if not isinstance(args[0], Symbol):
- raise InterpretPanic(symbol, "requires a :string name", args[0])
+ raise InterpretPanic(symbol, "requires a :symbol", args[0])
name = args[0].name # NOTE: we are not evaluating the name!!
if not env.contains(name):
raise InterpretPanic(symbol, "not previously defined", args[0])
- env.reregister(name, args[1])
+ res = evaluate(args[1], env, ns)
+ env.reregister(name, res)
return List([])
-CORE.register("redef", Builtin("redef", interpretRedef, [def_name_arg, def_val_arg], return_type=Type(":list")))
+CORE.register("redef", NebSyntax("redef", interpretRedef, [def_name_arg, def_val_arg], return_type=Type(":list")))
def interpretLambda(symbol, args, env, ns):
new_args = args
@@ -58,14 +59,17 @@ def interpretLambda(symbol, args, env, ns):
func.return_type = return_type
return func
-lambda_args_arg = Arg("args", TypeEnum.ANY, lazy=True)
-lambda_body_arg = Arg("body", TypeEnum.ANY, lazy=True)
-CORE.register("lambda", Builtin("lambda", interpretLambda, [lambda_args_arg, lambda_body_arg], lambda_body_arg))
+lambda_args_arg = Arg("args", TypeEnum.ANY)
+lambda_body_arg = Arg("body", TypeEnum.ANY)
+CORE.register("lambda", NebSyntax("lambda", interpretLambda, [lambda_args_arg, lambda_body_arg], lambda_body_arg))
def interpretForCount(symbol, args, env, ns):
+ num = evaluate(args[0], env, ns)
+ if not isinstance(num, Int):
+ raise InterpretPanic(symbol, "count must be an :int", num)
new_env = Environment(env)
ret = None
- for idx in range(0, args[0].value):
+ for idx in range(0, num.value):
new_env.register("idx", Int(idx + 1))
for arg in args[1:]:
ret = evaluate(arg, new_env, ns)
@@ -74,13 +78,16 @@ def interpretForCount(symbol, args, env, ns):
return ret
for_count_arg = Arg("count", TypeEnum.INT)
-for_body_arg = Arg("body", TypeEnum.ANY, lazy=True)
-CORE.register("for-count", Builtin("for-count", interpretForCount, [for_count_arg, for_body_arg], for_body_arg))
+for_body_arg = Arg("body", TypeEnum.ANY)
+CORE.register("for-count", NebSyntax("for-count", interpretForCount, [for_count_arg, for_body_arg], for_body_arg))
def interpretForEach(symbol, args, env, ns):
+ coll = evaluate(args[0], env, ns)
+ if not isinstance(coll, List):
+ raise InterpretPanic(symbol, "coll must be a :list", coll)
new_env = Environment(env)
ret = None
- for item in args[0].args:
+ for item in coll.args:
new_env.register("_item_", evaluate(item, env, ns))
for arg in args[1:]:
ret = evaluate(arg, new_env, ns)
@@ -89,12 +96,12 @@ def interpretForEach(symbol, args, env, ns):
return ret
for_each_arg = Arg("list", TypeEnum.LIST)
-CORE.register("for-each", Builtin("for-each", interpretForEach, [for_each_arg, for_body_arg], for_body_arg))
+CORE.register("for-each", NebSyntax("for-each", interpretForEach, [for_each_arg, for_body_arg], for_body_arg))
def interpretBranch(symbol, args, env, ns):
for arg in args:
if len(arg.args) != 2:
- raise InterpretPanic(symbol, "each branch requires two expressions")
+ raise InterpretPanic(symbol, "each branch requires two expressions", len(arg.args))
cond = evaluate(arg.args[0], env, ns) # this is the condition
if not isinstance(cond, Bool):
raise InterpretPanic(symbol, "branch condition must be :bool", cond)
@@ -102,11 +109,11 @@ def interpretBranch(symbol, args, env, ns):
return evaluate(arg.args[1], env, ns)
return List([])
-CORE.register("branch", Builtin("branch", interpretBranch, [for_body_arg], for_body_arg))
+CORE.register("branch", NebSyntax("branch", interpretBranch, [for_body_arg], for_body_arg))
def interpretFunc(symbol, args, env, ns):
if not isinstance(args[0], Symbol):
- raise InterpretPanic(symbol, "requires a :string name")
+ raise InterpretPanic(symbol, "requires a :symbol")
name = args[0].name # NOTE: we are not evaluating the name!!
if ns is not None:
@@ -121,7 +128,7 @@ def interpretFunc(symbol, args, env, ns):
env.register(name, func)
return List([])
-CORE.register("func", Builtin("func", interpretFunc, [def_name_arg, lambda_args_arg, lambda_body_arg], lambda_body_arg, Type(":list")))
+CORE.register("func", NebSyntax("func", interpretFunc, [def_name_arg, lambda_args_arg, lambda_body_arg], lambda_body_arg, Type(":list")))
def interpretBlock(symbol, args, env, ns):
new_env = Environment(env)
@@ -130,8 +137,8 @@ def interpretBlock(symbol, args, env, ns):
ret = evaluate(arg, new_env, ns)
return ret
-block_arg = Arg("expr", TypeEnum.ANY, lazy=True)
-CORE.register("block", Builtin("block", interpretBlock, [block_arg], block_arg))
+block_arg = Arg("expr", TypeEnum.ANY)
+CORE.register("block", NebSyntax("block", interpretBlock, [block_arg], block_arg))
def interpretWhile(symbol, args, env, ns):
new_env = Environment(env)
@@ -140,18 +147,21 @@ def interpretWhile(symbol, args, env, ns):
while True:
ev = evaluate(cond, new_env, ns)
if not isinstance(ev, Bool):
- raise InterpretPanic(symbol, "expects a :bool condition", ev)
+ raise InterpretPanic(symbol, "requires a :bool condition", cond)
if not ev.value:
break
for arg in args[1:]:
ret = evaluate(arg, new_env, ns)
return ret
-CORE.register("while", Builtin("while", interpretWhile, [Arg("cond", TypeEnum.BOOL, lazy=True)], Arg("expr", TypeEnum.ANY, lazy=True)))
+CORE.register("while", NebSyntax("while", interpretWhile, [Arg("cond", TypeEnum.BOOL)], Arg("expr", TypeEnum.ANY)))
+# NOTE this doesn't technically need to be a macro
def interpretUse(symbol, args, env, ns):
- target_file_name = args[0].value
- target_file = Path(target_file_name).resolve()
+ target = evaluate(args[0], env, ns)
+ if not isinstance(target, String):
+ raise InterpretPanic(symbol, "filename must be a :string", target)
+ target_file = Path(target.value).resolve()
if not target_file.exists():
raise InterpretPanic(symbol, "no such file", target_file)
with open(target_file, "r") as fil:
@@ -159,38 +169,48 @@ def interpretUse(symbol, args, env, ns):
interpret(parse(lex(data)), env, ns)
return List([])
-CORE.register("use", Builtin("use", interpretUse, [Arg("filename", TypeEnum.STRING)], return_type=Type(":list")))
+CORE.register("use", NebSyntax("use", interpretUse, [Arg("filename", TypeEnum.STRING)], return_type=Type(":list")))
+# NOTE this doesn't technically need to be a macro
def interpretAssert(symbol, args, env, ns):
- if args[0].value != True:
+ cond = evaluate(args[0], env, ns)
+ if not isinstance(cond, Bool):
+ raise InterpretPanic(symbol, "requires a :bool condition", cond)
+ if cond.value != True:
raise InterpretPanic(symbol, "assertion failed")
return List([])
-CORE.register("assert", Builtin("assert", interpretAssert, [Arg("cond", TypeEnum.BOOL)], return_type=Type(":list")))
+CORE.register("assert", NebSyntax("assert", interpretAssert, [Arg("cond", TypeEnum.BOOL)], return_type=Type(":list")))
def interpretUseAs(symbol, args, env, ns):
- target_file_name = args[0].value
- target_file = Path(target_file_name).resolve()
+ target = evaluate(args[0], env, ns)
+ if not isinstance(target, String):
+ raise InterpretPanic(symbol, "filename must be a :string", target)
+ target_file = Path(target.value).resolve()
if not target_file.exists():
raise InterpretPanic(symbol, "no such file", target_file)
+ if not isinstance(args[1], Symbol):
+ raise InterpretPanic(symbol, "requires a :symbol", args[1])
+ new_ns = args[1].name
with open(target_file, "r") as fil:
data = fil.read()
- interpret(parse(lex(data)), env, args[1].name)
+ interpret(parse(lex(data)), env, new_ns)
return List([])
-CORE.register("use-as", Builtin("use-as", interpretUseAs, [Arg("filename", TypeEnum.STRING), Arg("namespace", TypeEnum.ANY, lazy=True)], return_type=Type(":list")))
+CORE.register("use-as", NebSyntax("use-as", interpretUseAs, [Arg("filename", TypeEnum.STRING), Arg("namespace", TypeEnum.ANY)], return_type=Type(":list")))
def interpretQuote(symbol, args, env, ns):
return args[0]
-quote_arg = Arg("arg", TypeEnum.ANY, lazy=True)
-CORE.register("quote", Builtin("quote", interpretQuote, [quote_arg]))
+quote_arg = Arg("arg", TypeEnum.ANY)
+CORE.register("quote", NebSyntax("quote", interpretQuote, [quote_arg]))
def interpretEval(symbol, args, env, ns):
- return evaluate(args[0], env, ns) # TODO why do i have to explicitly evaluate here?
+ ev = evaluate(args[0], env, ns) # TODO why do i have to evaluate twice?
+ return evaluate(ev, env, ns)
eval_arg = Arg("arg", TypeEnum.ANY)
-CORE.register("eval", Builtin("eval", interpretEval, [eval_arg]))
+CORE.register("eval", NebSyntax("eval", interpretEval, [eval_arg]))
def interpretType(symbol, args, env, ns):
# (type typename parent func)
@@ -201,13 +221,14 @@ def interpretType(symbol, args, env, ns):
# TODO we may need to do namespace things here
# also, we probably shouldn't be able to rename types
- if not isinstance(args[1], TypeWrap):
- raise InterpretPanic(symbol, "parent must be a valid type", args[1])
- elif not env.contains(args[1].name.name):
- raise InterpretPanic(symbol, f"no such type {args[1]}")
- parent = env.get(args[1].name.name)
+ parent_type = evaluate(args[1], env, ns)
+ if not isinstance(parent_type, TypeWrap):
+ raise InterpretPanic(symbol, "parent must be a valid type", parent_type)
+ elif not env.contains(parent_type.name):
+ raise InterpretPanic(symbol, f"no such type {parent_type}")
+ parent = env.get(parent_type.name)
- func = args[2]
+ func = evaluate(args[2], env, ns)
if not isinstance(func, Function):
raise InterpretPanic(symbol, "validation must be a :func", func)
@@ -215,8 +236,51 @@ def interpretType(symbol, args, env, ns):
env.register(name, new_type)
return List([])
-type_name_arg = Arg("name", TypeEnum.ANY, lazy=True)
+type_name_arg = Arg("name", TypeEnum.ANY)
type_parent_arg = Arg("name", TypeEnum.ANY)
type_func_arg = Arg("func", TypeEnum.ANY)
-CORE.register("type", Builtin("type", interpretType, [type_name_arg, type_parent_arg, type_func_arg]))
+CORE.register("type", NebSyntax("type", interpretType, [type_name_arg, type_parent_arg, type_func_arg]))
+
+def interpretOr(symbol, args, env, ns):
+ # or returns true for the first expression that returns true
+ for arg in args:
+ ev = evaluate(arg, env, ns)
+ if not isinstance(ev, Bool):
+ raise InterpretPanic(symbol, "requires :bool arguments")
+ if ev.value == True:
+ return ev
+ return Bool(False)
+
+or_arg = Arg("arg", TypeEnum.BOOL)
+CORE.register("or", NebSyntax("or", interpretOr, [or_arg, or_arg], or_arg, Type(":bool")))
+
+def interpretAnd(symbol, args, env, ns):
+ # and returns false for the first expression that returns false
+ for arg in args:
+ ev = evaluate(arg, env, ns)
+ if not isinstance(ev, Bool):
+ raise InterpretPanic(symbol, "requires :bool arguments")
+ if ev.value == False:
+ return ev
+ return Bool(True)
+
+CORE.register("and", NebSyntax("and", interpretAnd, [or_arg, or_arg], or_arg, Type(":bool")))
+
+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
+
+CORE.register("bench", NebSyntax("bench", interpretBench, [Arg("command", TypeEnum.ANY)], return_type=Type(":any")))
+
+def interpretTry(symbol, args, env, ns):
+ try:
+ return evaluate(args[0], env, ns)
+ except NebPanic as e:
+ new_env = Environment(env)
+ new_env.register("_panic_", String(f"{e}"))
+ return evaluate(args[1], new_env, ns)
+CORE.register("try", NebSyntax("try", interpretTry, [Arg("expr", TypeEnum.ANY), Arg("except", TypeEnum.ANY)], return_type=Type(":any")))
diff --git a/neb/std/fs.py b/neb/std/fs.py
index d20cde9..144df0f 100644
--- a/neb/std/fs.py
+++ b/neb/std/fs.py
@@ -31,19 +31,6 @@ def interpretUnlink(symbol, args, env, ns):
FS.register("unlink", Builtin("unlink", interpretUnlink, [Arg("filename", TypeEnum.STRING)], return_type=Type(":list")))
-def interpretWithWrite(symbol, args, env, ns):
- target_file = args[0]
- new_env = Environment(env)
- target_path = Path(target_file.value).resolve()
- ret = Literal([])
- with open(str(target_path), "w") as fil:
- new_env.register("_file_", List([fil])) # TODO wrong!
- for arg in args[1:]:
- ret = evaluate(arg, new_env, ns)
- return ret
-
-FS.register("with-write", Builtin("with-write", interpretWithWrite, [Arg("filename", TypeEnum.STRING)], Arg("exprs", TypeEnum.ANY, lazy=True)))
-
def interpretWrite(symbol, args, env, ns):
string = args[0]
handle = args[1]
diff --git a/neb/std/functools.py b/neb/std/functools.py
index 9e426b8..f83c49d 100644
--- a/neb/std/functools.py
+++ b/neb/std/functools.py
@@ -34,13 +34,11 @@ def interpretMap(symbol, args, env, ns):
FUNCTOOLS.register("map", Builtin("map", interpretMap, [Arg("func", TypeEnum.ANY), Arg("list", TypeEnum.LIST)], return_type=Type(":list")))
+# TODO I think this is wrong
def interpretApply(symbol, args, env, ns):
- # TODO: to support lambdas, we can't assume the func is defined
func = args[0]
- if not isinstance(func, Symbol):
+ if not isinstance(func, Function):
raise InterpretPanic(symbol, "requires a symbol as its first argument", func)
- new_expr = Expr([func] + args[1].args)
- return evaluate(new_expr, env, ns)
-
-FUNCTOOLS.register("apply", Builtin("apply", interpretApply, [Arg("func", TypeEnum.ANY, lazy=True), Arg("list", TypeEnum.LIST)]))
+ return func.call(Expr([func] + args[1].args), env, ns)
+FUNCTOOLS.register("apply", Builtin("apply", interpretApply, [Arg("func", TypeEnum.ANY), Arg("list", TypeEnum.LIST)]))
diff --git a/neb/std/repl.py b/neb/std/repl.py
index 16efb20..6b6be83 100644
--- a/neb/std/repl.py
+++ b/neb/std/repl.py
@@ -1,10 +1,11 @@
-from .. import TypeEnum, Environment, Arg, Builtin, UserFunction, Function, evaluate, InterpretPanic
+from .. import TypeEnum, Environment, Arg, Builtin, UserFunction, Function, evaluate, InterpretPanic, Callable, NebSyntax, lex, parse
+from .core import interpretQuote
from ..structs import *
REPL = Environment()
def interpretHowTo(symbol, args, env, ns):
- if not isinstance(args[0], Function):
+ if not isinstance(args[0], Callable):
raise InterpretPanic(symbol, "expects a :func", args[0])
print(args[0].describe())
return List([])
@@ -12,19 +13,36 @@ def interpretHowTo(symbol, args, env, ns):
REPL.register("howto", Builtin("howto", interpretHowTo, [Arg("symbol", TypeEnum.ANY)], return_type=Type(":list")))
def interpretSymbols(symbol, args, env, ns):
- keys = [Symbol(k, -1) for k,v in sorted(env.environment.items())]
+ keys = [Symbol(k, -1) for k,v in sorted(env.get_all().items())]
return List(keys)
REPL.register("symbols", Builtin("symbols", interpretSymbols, [], return_type=Type(":list")))
def interpretFuncs(symbol, args, env, ns):
- keys = [Symbol(k, -1) for k,v in env.environment.items() if isinstance(v, Builtin)]
+ keys = [Symbol(k, -1) for k,v in sorted(env.get_all().items()) if isinstance(v, Function)]
return List(keys)
REPL.register("funcs", Builtin("funcs", interpretFuncs, [], return_type=Type(":list")))
def interpretUserSymbols(symbol, args, env, ns):
- keys = [Symbol(k, -1) for k,v in env.environment.items() if isinstance(v, UserFunction) or isinstance(v, Literal)]
+ keys = [Symbol(k, -1) for k,v in env.get_all().items() if isinstance(v, UserFunction) or isinstance(v, Literal)]
return List(keys)
REPL.register("user-symbols", Builtin("user-symbols", interpretUserSymbols, [], return_type=Type(":list")))
+
+def interpretUserFuncs(symbol, args, env, ns):
+ keys = [Symbol(k, -1) for k,v in env.get_all().items() if isinstance(v, UserFunction)]
+ return List(keys)
+
+REPL.register("user-funcs", Builtin("user-funcs", interpretUserFuncs, [], return_type=Type(":list")))
+
+def interpretSyntax(symbol, args, env, ns):
+ keys = [Symbol(k, -1) for k,v in sorted(env.get_all().items()) if isinstance(v, NebSyntax)]
+ return List(keys)
+
+REPL.register("syntax", Builtin("syntax", interpretSyntax, [], return_type=Type(":list")))
+
+def interpretParseNeb(symbol, args, env, ns):
+ return interpretQuote(None, [parse(lex(args[0].value))[0]], env, ns)
+
+REPL.register("parse-neb", Builtin("parse-neb", interpretParseNeb, [Arg("string", TypeEnum.STRING)], return_type=Type(":any")))
diff --git a/neb/std/sys.py b/neb/std/sys.py
index 525895a..f92eb77 100644
--- a/neb/std/sys.py
+++ b/neb/std/sys.py
@@ -35,15 +35,6 @@ def interpretPrint(symbol, args, env, ns):
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")))
-
def interpretEnv(symbol, args, env, ns):
items = os.environ[args[0].value].split(":")
return List([String(item) for item in items])
diff --git a/neb/structs.py b/neb/structs.py
index c623ed3..45e69a7 100644
--- a/neb/structs.py
+++ b/neb/structs.py
@@ -112,7 +112,7 @@ class Type:
else:
return self.name
-_native_types = ":any :literal :string :bool :number :int :float :[] :handle"
+_native_types = ":any :literal :string :bool :number :int :float :[] :handle :type"
ALL_TYPES = {x: Type(x) for x in _native_types.split(" ")}
class Symbol:
@@ -140,14 +140,13 @@ class List:
# function things
class Arg:
- def __init__(self, name, type_, *, optional=False, lazy=False):
+ def __init__(self, name, type_, *, optional=False):
self.name = name
if f"{type_}" == ":list":
self.type_ = ALL_TYPES[":[]"]
else:
self.type_ = ALL_TYPES[f"{type_}"]
self.optional = optional
- self.lazy = lazy
def __str__(self):
return f"{self.name} {self.type_}"
@@ -194,6 +193,12 @@ class Environment:
except:
raise NebPanic(f"undefined symbol: '{key}")
+ def get_all(self):
+ if self.parent is None:
+ return self.environment
+ else:
+ return dict(self.parent.get_all(), **self.environment)
+
def __str__(self):
out = ""
for k, v in self.environment.items():