aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interpreter.py226
-rw-r--r--libs/ansi.neb136
2 files changed, 197 insertions, 165 deletions
diff --git a/interpreter.py b/interpreter.py
index 80c6a50..869f424 100644
--- a/interpreter.py
+++ b/interpreter.py
@@ -59,7 +59,7 @@ class Function:
raise InterpretPanic(symbol, f"expected [{fmt}] arguments, received {len(params)}")
return True
- def evaluate_args(self, symbol, params, env):
+ def evaluate_args(self, symbol, params, env, ns):
self.arity_check(symbol, params)
ret = []
@@ -87,10 +87,10 @@ class Builtin(Function):
def __init__(self, callable_, args=None, many=None):
super().__init__("<builtin>", None, callable_, args, many)
- def call(self, expr, env):
+ 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)
- return self.body(expr.args[0], evaluated_args, env)
+ evaluated_args = self.evaluate_args(expr.args[0], expr.args[1:], env, ns)
+ return self.body(expr.args[0], evaluated_args, env, ns)
class UserFunction(Function):
@@ -100,13 +100,14 @@ class UserFunction(Function):
args = [Arg(p.name, TypeEnum.ANY, False, False) for p in params]
super().__init__(name, params, body, args)
- def call(self, expr, env):
+ 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)
+ evaluated_args = self.evaluate_args(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])
- return interpret(self.body, this_env)
+ #return interpret(self.body, this_env, ns)
+ return interpret(self.body, env=this_env, ns=ns)
class Environment:
@@ -149,20 +150,32 @@ class Environment:
GLOBALS = Environment()
-def interpret(exprs, env=GLOBALS):
+def interpret(exprs, *, env=GLOBALS, ns=None):
ret = None
for expr in exprs:
- ret = evaluate(expr, env)
+ ret = evaluate(expr, env, ns)
return ret
-def evaluate(expr, env):
+def evaluate(expr, env, ns=None):
if isinstance(expr, Literal) or isinstance(expr, Function):
#return expr.value
return expr
elif isinstance(expr, Symbol):
+ if env.contains(expr.name):
+ return evaluate(env.get(expr.name), env, ns)
+ elif ns is not None and env.contains(f"{ns}/{expr.name}"):
+ return evaluate(env.get(f"{ns}/{expr.name}"), env, ns)
+ else:
+ raise NebPanic(f"no such symbol: {expr}")
+
+ '''
if not env.contains(expr.name):
raise NebPanic(f"no such symbol: {expr}")
- return evaluate(env.get(expr.name), env)
+ if ns is None:
+ return evaluate(env.get(expr.name), env, ns)
+ else:
+ return evaluate(env.get(f"{ns}/{expr.name}"), env, ns)
+ '''
# if it's a literal list, return it
if expr.data:
@@ -174,16 +187,19 @@ def evaluate(expr, env):
if not isinstance(expr.args[0], Symbol):
raise NebPanic("can't evaluate without a symbol")
name = expr.args[0].name
-
+ #if ns is not None:
+ # name = f"{ns}/{name}"
if env.contains(name):
- return env.get(name).call(expr, env)
+ return env.get(name).call(expr, env, ns)
+ elif ns is not None and env.contains(f"{ns}/{name}"):
+ return env.get(f"{ns}/{name}").call(expr, env, ns)
else:
raise InterpretPanic(expr.args[0], "unable to evaluate")
-def interpretOr(symbol, args, env):
+def interpretOr(symbol, args, env, ns):
# or returns true for the first expression that returns true
for arg in args:
- ev = evaluate(arg, env)
+ ev = evaluate(arg, env, ns)
if not isinstance(ev, Bool):
raise InterpretPanic(symbol, "requires :bool arguments")
if ev.value == True:
@@ -194,10 +210,10 @@ def interpretOr(symbol, args, env):
or_arg = Arg("arg", TypeEnum.BOOL, False, True)
GLOBALS.register("or", Builtin(interpretOr, [or_arg, or_arg], or_arg))
-def interpretAnd(symbol, args, env):
+def interpretAnd(symbol, args, env, ns):
# and returns false for the first expression that returns false
for arg in args:
- ev = evaluate(arg, env)
+ ev = evaluate(arg, env, ns)
if not isinstance(ev, Bool):
raise InterpretPanic(symbol, "requires :bool arguments")
if ev.value == False:
@@ -206,7 +222,7 @@ def interpretAnd(symbol, args, env):
GLOBALS.register("and", Builtin(interpretAnd, [or_arg, or_arg], or_arg))
-def interpretEq(symbol, args, env):
+def interpretEq(symbol, args, env, ns):
# NOTE this currently only works for literals
# compare types because 0 != #false in neb
if type(args[0]) == type(args[1]) and args[0].value == args[1].value:
@@ -217,28 +233,28 @@ def interpretEq(symbol, args, env):
eq_arg = Arg("value", TypeEnum.LITERAL, False, False)
GLOBALS.register("eq?", Builtin(interpretEq, [eq_arg, eq_arg]))
-def interpretGreaterThan(symbol, args, env):
+def interpretGreaterThan(symbol, args, env, ns):
return Bool(args[0].value > args[1].value)
compare_arg = Arg("num", TypeEnum.NUMBER, False, False)
GLOBALS.register(">", Builtin(interpretGreaterThan, [compare_arg, compare_arg]))
-def interpretGreaterThanEqual(symbol, args, env):
+def interpretGreaterThanEqual(symbol, args, env, ns):
return Bool(args[0].value >= args[1].value)
GLOBALS.register(">=", Builtin(interpretGreaterThanEqual, [compare_arg, compare_arg]))
-def interpretLessThan(symbol, args, env):
+def interpretLessThan(symbol, args, env, ns):
return Bool(args[0].value < args[1].value)
GLOBALS.register("<", Builtin(interpretLessThan, [compare_arg, compare_arg]))
-def interpretLessThanEqual(symbol, args, env):
+def interpretLessThanEqual(symbol, args, env, ns):
return Bool(args[0].value <= args[1].value)
GLOBALS.register("<=", Builtin(interpretLessThanEqual, [compare_arg, compare_arg]))
-def interpretAddition(symbol, args, env):
+def interpretAddition(symbol, args, env, ns):
res = 0
for arg in args:
res += arg.value
@@ -250,7 +266,7 @@ def interpretAddition(symbol, args, env):
term_arg = Arg("term", TypeEnum.NUMBER, False, False)
GLOBALS.register("+", Builtin(interpretAddition, [term_arg], term_arg))
-def interpretSubtraction(symbol, args, env):
+def interpretSubtraction(symbol, args, env, ns):
if len(args) == 1:
res = -args[0].value
else:
@@ -264,7 +280,7 @@ def interpretSubtraction(symbol, args, env):
GLOBALS.register("-", Builtin(interpretSubtraction, [term_arg], term_arg))
-def interpretMultiplication(symbol, args, env):
+def interpretMultiplication(symbol, args, env, ns):
res = args[0].value
for arg in args[1:]:
res = res * arg.value
@@ -276,7 +292,7 @@ def interpretMultiplication(symbol, args, env):
factor_arg = Arg("factor", TypeEnum.NUMBER, False, False)
GLOBALS.register("*", Builtin(interpretMultiplication, [factor_arg, factor_arg], factor_arg))
-def interpretDivision(symbol, args, env):
+def interpretDivision(symbol, args, env, ns):
ret = args[0].value / args[1].value
if int(ret) == ret:
return Int(int(ret))
@@ -285,18 +301,18 @@ def interpretDivision(symbol, args, env):
GLOBALS.register("/", Builtin(interpretDivision, [factor_arg, factor_arg]))
-def interpretNot(symbol, args, env):
+def interpretNot(symbol, args, env, ns):
return Bool(not args[0].value)
not_arg = Arg("not", TypeEnum.BOOL, False, False)
GLOBALS.register("not", Builtin(interpretNot, [not_arg]))
-def interpretIf(symbol, args, env):
+def interpretIf(symbol, args, env, ns):
# if cond t-branch [f-branch]
if args[0].value:
- return evaluate(args[1], env)
+ return evaluate(args[1], env, ns)
elif len(args) == 3:
- return evaluate(args[2], env)
+ return evaluate(args[2], env, ns)
return List([])
cond = Arg("cond", TypeEnum.BOOL, False, False)
@@ -304,13 +320,14 @@ t_branch = Arg("t-branch", TypeEnum.ANY, False, True)
f_branch = Arg("f-branch", TypeEnum.ANY, True, True)
GLOBALS.register("if", Builtin(interpretIf, [cond, t_branch, f_branch]))
-def interpretPrint(symbol, args, env):
+def interpretPrint(symbol, args, env, ns):
print(args[0].value)
return List([]) # print returns nothing
GLOBALS.register("print", Builtin(interpretPrint, [Arg("arg", TypeEnum.STRING, False, False)]))
-def interpretDef(symbol, args, env):
+def interpretDef(symbol, args, env, ns):
+
if not isinstance(args[0], Symbol):
raise InterpretPanic(symbol, "requires a :string name", args[0])
name = args[0].name # NOTE: we are not evaluating the name!!
@@ -318,13 +335,14 @@ def interpretDef(symbol, args, env):
raise InterpretPanic(symbol, "requires a :string name")
env.register(name, args[1]) # TODO since this isn't lazily evaluated, side effects are allowed (bad!)
+
return List([])
def_name_arg = Arg("name", TypeEnum.ANY, False, True)
def_val_arg = Arg("value", TypeEnum.ANY, False, False)
GLOBALS.register("def", Builtin(interpretDef, [def_name_arg, def_val_arg]))
-def interpretRedef(symbol, args, env):
+def interpretRedef(symbol, args, env, ns):
if not isinstance(args[0], Symbol):
raise InterpretPanic(symbol, "requires a :string name", args[0])
name = args[0].name # NOTE: we are not evaluating the name!!
@@ -336,7 +354,7 @@ def interpretRedef(symbol, args, env):
GLOBALS.register("redef", Builtin(interpretRedef, [def_name_arg, def_val_arg]))
-def interpretLambda(symbol, args, env):
+def interpretLambda(symbol, args, env, ns):
if len(args[0].args) != 0:
func = UserFunction("<lambda>", args[0].args, args[1:])
else:
@@ -347,7 +365,7 @@ lambda_args_arg = Arg("args", TypeEnum.ANY, False, True)
lambda_body_arg = Arg("body", TypeEnum.ANY, False, True)
GLOBALS.register("lambda", Builtin(interpretLambda, [lambda_args_arg, lambda_body_arg], lambda_body_arg))
-def interpretToString(symbol, args, env):
+def interpretToString(symbol, args, env, ns):
item = args[0]
if isinstance(item, String):
return item
@@ -358,7 +376,7 @@ def interpretToString(symbol, args, env):
GLOBALS.register("->string", Builtin(interpretToString, [Arg("arg", TypeEnum.ANY, False, False)]))
-def interpretConcat(symbol, args, env):
+def interpretConcat(symbol, args, env, ns):
# concat str1 str2...strN
out = ""
for arg in args:
@@ -368,14 +386,14 @@ def interpretConcat(symbol, args, env):
string_arg = Arg("arg", TypeEnum.STRING, False, False)
GLOBALS.register("concat", Builtin(interpretConcat, [string_arg, string_arg], string_arg))
-def interpretForCount(symbol, args, env):
+def interpretForCount(symbol, args, env, ns):
# for-count int exprs
new_env = Environment(env)
ret = None
for idx in range(0, args[0].value):
new_env.register("idx", Int(idx + 1))
for arg in args[1:]:
- ret = evaluate(arg, new_env)
+ ret = evaluate(arg, new_env, ns)
if ret is None:
return List([])
return ret
@@ -384,14 +402,14 @@ for_count_arg = Arg("count", TypeEnum.INT, False, False)
for_body_arg = Arg("body", TypeEnum.ANY, False, True)
GLOBALS.register("for-count", Builtin(interpretForCount, [for_count_arg, for_body_arg], for_body_arg))
-def interpretForEach(symbol, args, env):
+def interpretForEach(symbol, args, env, ns):
# for-each list exprs
new_env = Environment(env)
ret = None
for item in args[0].args:
- new_env.register("_item_", evaluate(item, env))
+ new_env.register("_item_", evaluate(item, env, ns))
for arg in args[1:]:
- ret = evaluate(arg, new_env)
+ ret = evaluate(arg, new_env, ns)
if ret is None:
return List([])
return ret
@@ -399,13 +417,13 @@ def interpretForEach(symbol, args, env):
for_each_arg = Arg("list", TypeEnum.LIST, False, False)
GLOBALS.register("for-each", Builtin(interpretForEach, [for_each_arg, for_body_arg], for_body_arg))
-def interpretPipe(symbol, args, env):
+def interpretPipe(symbol, args, env, ns):
new_env = Environment(env)
pipe = None
for arg in args:
if pipe is not None:
new_env.register("items", pipe)
- pipe = evaluate(arg, new_env)
+ pipe = evaluate(arg, new_env, ns)
if pipe is None:
return List([])
return pipe
@@ -413,34 +431,35 @@ def interpretPipe(symbol, args, env):
# TODO
GLOBALS.register("|", Builtin(interpretPipe, 2))
-def interpretBranch(symbol, args, env):
+def interpretBranch(symbol, args, env, ns):
for arg in args:
if len(arg.args) != 2:
raise InterpretPanic(symbol, "each branch requires two expressions")
- cond = evaluate(arg.args[0], env) # this is the condition
+ 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)
if cond.value:
- return evaluate(arg.args[1], env)
+ return evaluate(arg.args[1], env, ns)
return List([])
GLOBALS.register("branch", Builtin(interpretBranch, [for_body_arg], for_body_arg))
-def interpretFunc(symbol, args, env):
+def interpretFunc(symbol, args, env, ns):
# func <name> (args) (exprs)
# maybe:
# arg [:type] -> type is optional
# ?arg default -> 'arg' is optional, defaulted
# *arg [:type] -> 'arg' is a list containing the remaining args
-
-
if not isinstance(args[0], Symbol):
raise InterpretPanic(symbol, "requires a :string name")
name = args[0].name # NOTE: we are not evaluating the name!!
+ if ns is not None:
+ name = f"{ns}/{name}"
+
# compose a lambda
- func = interpretLambda(None, args[1:], env)
+ func = interpretLambda(None, args[1:], env, ns)
env.register(name, func)
return List([])
@@ -449,7 +468,7 @@ GLOBALS.register("func", Builtin(interpretFunc, [def_name_arg, lambda_args_arg,
# THINGS NEEDED FOR AOC
# - read the contents of a file
-def interpretReadLines(symbol, args, env):
+def interpretReadLines(symbol, args, env, ns):
target_file_name = args[0].value
target_file = Path(target_file_name).resolve()
if not target_file.exists():
@@ -462,13 +481,13 @@ def interpretReadLines(symbol, args, env):
GLOBALS.register("read-lines", Builtin(interpretReadLines, [Arg("filename", TypeEnum.STRING, False, False)]))
# - strip whitespace from string
-def interpretStrip(symbol, args, env):
+def interpretStrip(symbol, args, env, ns):
return String(args[0].value.strip())
GLOBALS.register("strip", Builtin(interpretStrip, [Arg("filename", TypeEnum.STRING, False, False)]))
# - string->int and string->float
-def interpretStringToInt(symbol, args, env):
+def interpretStringToInt(symbol, args, env, ns):
try:
val = int(args[0].value)
return Int(val)
@@ -478,7 +497,7 @@ def interpretStringToInt(symbol, args, env):
GLOBALS.register("string->int", Builtin(interpretStringToInt, [Arg("arg", TypeEnum.STRING, False, False)]))
# - split a string by a given field
-def interpretSplit(symbol, args, env):
+def interpretSplit(symbol, args, env, ns):
target = args[0]
if len(args) == 1:
return List([String(char) for char in target.value], True)
@@ -489,20 +508,20 @@ def interpretSplit(symbol, args, env):
GLOBALS.register("split", Builtin(interpretSplit, [Arg("target", TypeEnum.STRING, False, False)], Arg("splitter", TypeEnum.STRING, True, False)))
# - get the length of a list
-def interpretListLength(symbol, args, env):
+def interpretListLength(symbol, args, env, ns):
return Int(len(args[0].args))
GLOBALS.register("list-length", Builtin(interpretListLength, [Arg("arg", TypeEnum.LIST, False, False)]))
# - first/rest of list
-def interpretFirst(symbol, args, env):
+def interpretFirst(symbol, args, env, ns):
if len(args[0].args) == 0:
raise InterpretPanic(symbol, "list is empty")
- return evaluate(args[0].args[0], env)
+ return evaluate(args[0].args[0], env, ns)
GLOBALS.register("first", Builtin(interpretFirst, [Arg("arg", TypeEnum.LIST, False, False)]))
-def interpretRest(symbol, args, env):
+def interpretRest(symbol, args, env, ns):
# TODO do we know it's not evaluated?
return List(args[0].args[1:], True) # we don't evaluate the remainder of the list
@@ -510,23 +529,23 @@ GLOBALS.register("rest", Builtin(interpretRest, [Arg("arg", TypeEnum.LIST, False
# - iterate over list
# - map
-def interpretMap(symbol, args, env):
+def interpretMap(symbol, args, env, ns):
# TODO: to support lambdas, we can't assume the func is defined
func = args[0]
if not isinstance(func, Symbol):
raise InterpretPanic(symbol, "requires a symbol as its first argument", func)
- lst = evaluate(args[1], env)
+ lst = evaluate(args[1], env, ns)
if not isinstance(lst, List):
raise InterpretPanic(symbol, "requires a :list as its second argument", lst)
out = []
for arg in lst.args:
- ev = evaluate(List([func, arg]), env)
+ ev = evaluate(List([func, arg]), env, ns)
out.append(ev)
return List(out, True)
GLOBALS.register("map", Builtin(interpretMap, [Arg("func", TypeEnum.ANY, False, True), Arg("list", TypeEnum.LIST, False, False)]))
-def interpretZip(symbol, args, env):
+def interpretZip(symbol, args, env, ns):
z1 = args[0]
z2 = args[1]
if len(z1.args) != len(z2.args):
@@ -541,68 +560,68 @@ def interpretZip(symbol, args, env):
zip_arg = Arg("list", TypeEnum.LIST, False, False)
GLOBALS.register("zip", Builtin(interpretZip, [zip_arg, zip_arg]))
-def interpretList(symbol, args, env):
+def interpretList(symbol, args, env, ns):
return List(args, True)
GLOBALS.register("list", Builtin(interpretList, [], Arg("item", TypeEnum.ANY, False, False)))
-def interpretListReverse(symbol, args, env):
+def interpretListReverse(symbol, args, env, ns):
new_args = args[0].args[:] # make a copy of the args
new_args.reverse()
return List(new_args, True)
GLOBALS.register("list-reverse", Builtin(interpretListReverse, [Arg("list", TypeEnum.LIST, False, False)]))
-def interpretApply(symbol, args, env):
+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):
raise InterpretPanic(symbol, "requires a symbol as its first argument", func)
new_lst = List([func] + args[1].args)
- return evaluate(new_lst, env)
+ return evaluate(new_lst, env, ns)
GLOBALS.register("apply", Builtin(interpretApply, [Arg("func", TypeEnum.ANY, False, True), Arg("list", TypeEnum.LIST, False, False)]))
-def interpretGlob(symbol, args, env):
+def interpretGlob(symbol, args, env, ns):
items = glob(args[0].value)
return List([String(item) for item in items], True)
GLOBALS.register("glob", Builtin(interpretGlob, [Arg("regex", TypeEnum.STRING, False, False)]))
-def interpretShell(symbol, args, env):
+def interpretShell(symbol, args, env, ns):
# TODO either fail or throw exception (?) on error
ret = subprocess.run(shlex.split(args[0].value), capture_output=True)
return List([String(r) for r in ret.stdout.decode("utf-8").split("\n")], True)
GLOBALS.register("$", Builtin(interpretShell, [Arg("command", TypeEnum.STRING, False, False)]))
-def interpretEmpty(symbol, args, env):
+def interpretEmpty(symbol, args, env, ns):
return Bool(len(args[0].args) == 0)
GLOBALS.register("empty?", Builtin(interpretEmpty, [Arg("list", TypeEnum.LIST, False, False)]))
-def interpretShuf(symbol, args, env):
+def interpretShuf(symbol, args, env, ns):
items = args[0].args[:]
random.shuffle(items)
return List(items, True)
GLOBALS.register("shuf", Builtin(interpretShuf, [Arg("list", TypeEnum.LIST, False, False)]))
-def interpretIsList(symbol, args, env):
+def interpretIsList(symbol, args, env, ns):
return Bool(isinstance(args[0], List))
GLOBALS.register("list?", Builtin(interpretIsList, [Arg("arg", TypeEnum.ANY, False, False)]))
-def interpretBlock(symbol, args, env):
+def interpretBlock(symbol, args, env, ns):
ret = List([])
for arg in args:
- ret = evaluate(arg, env)
+ ret = evaluate(arg, env, ns)
return ret
block_arg = Arg("expr", TypeEnum.ANY, False, True)
GLOBALS.register("block", Builtin(interpretBlock, [block_arg], block_arg))
-def interpretExit(symbol, args, env):
+def interpretExit(symbol, args, env, ns):
status = 0 if len(args) == 0 else args[0].value
sys.exit(status)
return List([])
@@ -610,7 +629,7 @@ def interpretExit(symbol, args, env):
exit_arg = Arg("status", TypeEnum.INT, True, False)
GLOBALS.register("exit", Builtin(interpretExit, [exit_arg]))
-def interpretUnlink(symbol, args, env):
+def interpretUnlink(symbol, args, env, ns):
target_path = Path(args[0].value).resolve()
if not target_path.exists():
raise InterpretPanic(symbol, "target file does not exist", target_path)
@@ -619,7 +638,7 @@ def interpretUnlink(symbol, args, env):
GLOBALS.register("unlink", Builtin(interpretUnlink, [Arg("filename", TypeEnum.STRING, False, False)]))
-def interpretArgv(symbol, args, env):
+def interpretArgv(symbol, args, env, ns):
out = []
for arg in sys.argv[1:]:
out.append(String(arg))
@@ -627,7 +646,7 @@ def interpretArgv(symbol, args, env):
GLOBALS.register("argv", Builtin(interpretArgv, []))
-def interpretIn(symbol, args, env):
+def interpretIn(symbol, args, env, ns):
target = args[0]
lst = args[1]
for arg in lst.args:
@@ -639,14 +658,14 @@ in_target_arg = Arg("target", TypeEnum.LITERAL, False, False)
in_list_arg = Arg("list", TypeEnum.LIST, False, False)
GLOBALS.register("in?", Builtin(interpretIn, [in_target_arg, in_list_arg]))
-def interpretLast(symbol, args, env):
+def interpretLast(symbol, args, env, ns):
if len(args[0].args) == 0:
raise InterpretPanic("List is empty")
- return evaluate(args[0].args[-1], env)
+ return evaluate(args[0].args[-1], env, ns)
GLOBALS.register("last", Builtin(interpretLast, [Arg("list", TypeEnum.LIST, False, False)]))
-def interpretJoin(symbol, args, env):
+def interpretJoin(symbol, args, env, ns):
lst = args[0]
target = args[1]
return String(target.value.join([a.value for a in lst.args]))
@@ -655,7 +674,7 @@ join_list_arg = Arg("list", TypeEnum.LIST, False, False)
join_string_arg = Arg("joiner", TypeEnum.STRING, False, False)
GLOBALS.register("join", Builtin(interpretJoin, [join_list_arg, join_string_arg]))
-def interpretWithWrite(symbol, args, env):
+def interpretWithWrite(symbol, args, env, ns):
target_file = args[0]
new_env = Environment(env)
target_path = Path(target_file.value).resolve()
@@ -663,12 +682,12 @@ def interpretWithWrite(symbol, args, env):
with open(str(target_path), "w") as fil:
new_env.register("_file_", List([fil], True)) # TODO wrong!
for arg in args[1:]:
- ret = evaluate(arg, new_env)
+ ret = evaluate(arg, new_env, ns)
return ret
GLOBALS.register("with-write", Builtin(interpretWithWrite, [Arg("filename", TypeEnum.STRING, False, False)], Arg("exprs", TypeEnum.ANY, False, True)))
-def interpretWrite(symbol, args, env):
+def interpretWrite(symbol, args, env, ns):
# write :string :filehandle
line = args[0]
handle = args[1]
@@ -677,29 +696,29 @@ def interpretWrite(symbol, args, env):
GLOBALS.register("write", Builtin(interpretWrite, [Arg("string", TypeEnum.STRING, False, False), Arg("filename", TypeEnum.LIST, False, False)]))
-def interpretNewline(symbol, args, env):
+def interpretNewline(symbol, args, env, ns):
return String("\n")
GLOBALS.register("newline", Builtin(interpretNewline, []))
-def interpretExists(symbol, args, env):
+def interpretExists(symbol, args, env, ns):
return Bool(Path(args[0].value).resolve().exists())
GLOBALS.register("exists?", Builtin(interpretExists, [Arg("filename", TypeEnum.STRING, False, False)]))
-def interpretFirstChar(symbol, args, env):
+def interpretFirstChar(symbol, args, env, ns):
if len(args[0].value) == 0:
raise InterpretPanic(symbol, ":string is empty", ev)
return String(args[0].value[0])
GLOBALS.register("first-char", Builtin(interpretFirstChar, [Arg("string", TypeEnum.STRING, False, False)]))
-def interpretRestChar(symbol, args, env):
+def interpretRestChar(symbol, args, env, ns):
return String(args[0].value[1:])
GLOBALS.register("rest-char", Builtin(interpretRestChar, [Arg("string", TypeEnum.STRING, False, False)]))
-def interpretSlice(symbol, args, env):
+def interpretSlice(symbol, args, env, ns):
lst = args[0]
idx = args[1]
if len(args) == 2:
@@ -713,19 +732,19 @@ slice_idx_arg = Arg("idx", TypeEnum.INT, False, False)
slice_length_arg = Arg("length", TypeEnum.INT, True, False)
GLOBALS.register("slice", Builtin(interpretSlice, [slice_list_arg, slice_idx_arg, slice_length_arg]))
-def interpretClear(symbol, args, env):
+def interpretClear(symbol, args, env, ns):
subprocess.run(["clear"])
return List([])
GLOBALS.register("clear", Builtin(interpretClear, []))
-def interpretReadLine(symbol, args, env):
+def interpretReadLine(symbol, args, env, ns):
ret = input(args[0].value)
return String(ret)
GLOBALS.register("read-line", Builtin(interpretReadLine, [Arg("prompt", TypeEnum.STRING, False, False)]))
-def interpretReadChar(symbol, args, env):
+def interpretReadChar(symbol, args, env, ns):
import termios, tty
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
@@ -740,7 +759,7 @@ def interpretReadChar(symbol, args, env):
GLOBALS.register("read-char", Builtin(interpretReadChar, []))
-def interpretAppend(symbol, args, env):
+def interpretAppend(symbol, args, env, ns):
lst = args[0]
val = args[1]
items = lst.args[:]
@@ -749,7 +768,7 @@ def interpretAppend(symbol, args, env):
GLOBALS.register("append", Builtin(interpretAppend, [Arg("list", TypeEnum.LIST, False, False), Arg("item", TypeEnum.ANY, False, False)]))
# TODO: this is actually for records/structs/whatever they're called
-def interpretRemove(symbol, args, env):
+def interpretRemove(symbol, args, env, ns):
lst = args[0]
key = args[1]
out = []
@@ -760,22 +779,22 @@ def interpretRemove(symbol, args, env):
GLOBALS.register("remove", Builtin(interpretRemove, [Arg("list", TypeEnum.LIST, False, False), Arg("key", TypeEnum.ANY, False, False)]))
-def interpretWhile(symbol, args, env):
+def interpretWhile(symbol, args, env, ns):
cond = args[0]
ret = List([])
while True:
- ev = evaluate(cond, env)
+ ev = evaluate(cond, env, ns)
if not isinstance(ev, Bool):
raise InterpretPanic(symbol, "expects a :bool condition", ev)
if not ev.value:
break
for arg in args[1:]:
- ret = evaluate(arg, env)
+ ret = evaluate(arg, env, ns)
return ret
GLOBALS.register("while", Builtin(interpretWhile, [Arg("cond", TypeEnum.BOOL, False, True)], Arg("expr", TypeEnum.ANY, False, True)))
-def interpretUse(symbol, args, env):
+def interpretUse(symbol, args, env, ns):
target_file_name = args[0].value
target_file = Path(target_file_name).resolve()
if not target_file.exists():
@@ -817,3 +836,16 @@ def interpretSymbols(symbol, args, env):
return List([])
GLOBALS.register("symbols", Builtin(interpretSymbols, []))
+
+def interpretUseAs(symbol, args, env, ns):
+ target_file_name = args[0].value
+ target_file = Path(target_file_name).resolve()
+ if not target_file.exists():
+ raise InterpretPanic(symbol, "no such file", target_file)
+ with open(target_file, "r") as fil:
+ data = fil.read()
+ interpret(parse(lex(data)), ns=args[1].name)
+ return List([])
+
+# TODO takes a symbol as its second, that may be wrong
+GLOBALS.register("use-as", Builtin(interpretUseAs, [Arg("filename", T.String, False, False), Arg("namespace", T.Any, False, True)]))
diff --git a/libs/ansi.neb b/libs/ansi.neb
index 7d9ebb6..fbdaaf9 100644
--- a/libs/ansi.neb
+++ b/libs/ansi.neb
@@ -1,98 +1,98 @@
; ansi.neb
; functions and such for colors in the terminal
-(func ansi-wrap (color-code)
+(func wrap (color-code)
(concat "\033[" color-code "m"))
-(def ansi-reset (ansi-wrap "0"))
+(def reset (wrap "0"))
; COLORS
-(def ansi-black-on (ansi-wrap "30"))
-(func ansi-black (str)
- (concat ansi-black-on str ansi-reset))
+(def black-on (wrap "30"))
+(func black (str)
+ (concat black-on str reset))
-(def ansi-bright-black-on (ansi-wrap "90"))
-(func ansi-bright-black (str)
- (concat ansi-bright-black-on str ansi-reset))
+(def bright-black-on (wrap "90"))
+(func bright-black (str)
+ (concat bright-black-on str reset))
-(def ansi-red-on (ansi-wrap "31"))
-(func ansi-red (str)
- (concat ansi-red str ansi-reset))
+(def red-on (wrap "31"))
+(func red (str)
+ (concat red str reset))
-(def ansi-bright-red-on (ansi-wrap "91"))
-(func ansi-bright-red (str)
- (concat ansi-bright-red-on str ansi-reset))
+(def bright-red-on (wrap "91"))
+(func bright-red (str)
+ (concat bright-red-on str reset))
-(def ansi-green-on (ansi-wrap "32"))
-(func ansi-green (str)
- (concat ansi-green-on str ansi-reset))
+(def green-on (wrap "32"))
+(func green (str)
+ (concat green-on str reset))
-(def ansi-bright-green-on (ansi-wrap "92"))
-(func ansi-bright-green (str)
- (concat ansi-bright-green-on str ansi-reset))
+(def bright-green-on (wrap "92"))
+(func bright-green (str)
+ (concat bright-green-on str reset))
-(def ansi-yellow-on (ansi-wrap "33"))
-(func ansi-yellow (str)
- (concat ansi-yellow-on str ansi-reset))
+(def yellow-on (wrap "33"))
+(func yellow (str)
+ (concat yellow-on str reset))
-(def ansi-bright-yellow-on (ansi-wrap "93"))
-(func ansi-bright-yellow (str)
- (concat ansi-bright-yellow-on str ansi-reset))
+(def bright-yellow-on (wrap "93"))
+(func bright-yellow (str)
+ (concat bright-yellow-on str reset))
-(def ansi-blue-on (ansi-wrap "34"))
-(func ansi-blue (str)
- (concat ansi-blue-on str ansi-reset))
+(def blue-on (wrap "34"))
+(func blue (str)
+ (concat blue-on str reset))
-(def ansi-bright-blue-on (ansi-wrap "94"))
-(func ansi-bright-blue (str)
- (concat ansi-bright-blue-on str ansi-reset))
+(def bright-blue-on (wrap "94"))
+(func bright-blue (str)
+ (concat bright-blue-on str reset))
-(def ansi-magenta-on (ansi-wrap "35"))
-(func ansi-magenta (str)
- (concat ansi-magenta-on str ansi-reset))
+(def magenta-on (wrap "35"))
+(func magenta (str)
+ (concat magenta-on str reset))
-(def ansi-bright-magenta-on (ansi-wrap "95"))
-(func ansi-bright-magenta (str)
- (concat ansi-bright-magenta-on str ansi-reset))
+(def bright-magenta-on (wrap "95"))
+(func bright-magenta (str)
+ (concat bright-magenta-on str reset))
-(def ansi-cyan-on (ansi-wrap "36"))
-(func ansi-cyan (str)
- (concat ansi-cyan-on str ansi-reset))
+(def cyan-on (wrap "36"))
+(func cyan (str)
+ (concat cyan-on str reset))
-(def ansi-bright-cyan-on (ansi-wrap "96"))
-(func ansi-bright-cyan (str)
- (concat ansi-bright-cyan-on str ansi-reset))
+(def bright-cyan-on (wrap "96"))
+(func bright-cyan (str)
+ (concat bright-cyan-on str reset))
-(def ansi-white-on (ansi-wrap "37"))
-(func ansi-white (str)
- (concat ansi-white-on str ansi-reset))
+(def white-on (wrap "37"))
+(func white (str)
+ (concat white-on str reset))
-(def ansi-bright-white-on (ansi-wrap "97"))
-(func ansi-bright-white (str)
- (concat ansi-bright-white-on str ansi-reset))
+(def bright-white-on (wrap "97"))
+(func bright-white (str)
+ (concat bright-white-on str reset))
; STYLES
-(def ansi-bold-on (ansi-wrap "1"))
-(func ansi-bold (str)
- (concat ansi-bold-on str ansi-reset))
+(def bold-on (wrap "1"))
+(func bold (str)
+ (concat bold-on str reset))
-(def ansi-faint-on (ansi-wrap "2"))
-(func ansi-faint (str)
- (concat ansi-faint-on str ansi-reset))
+(def faint-on (wrap "2"))
+(func faint (str)
+ (concat faint-on str reset))
-(def ansi-italic-on (ansi-wrap "3"))
-(func ansi-italic (str)
- (concat ansi-italic-on str ansi-reset))
+(def italic-on (wrap "3"))
+(func italic (str)
+ (concat italic-on str reset))
-(def ansi-underline-on (ansi-wrap "4"))
-(func ansi-underline (str)
- (concat ansi-underline-on str ansi-reset))
+(def underline-on (wrap "4"))
+(func underline (str)
+ (concat underline-on str reset))
-(def ansi-blink-on (ansi-wrap "5"))
-(func ansi-blink (str)
- (concat ansi-blink-on str ansi-reset))
+(def blink-on (wrap "5"))
+(func blink (str)
+ (concat blink-on str reset))
-(def ansi-reverse-on (ansi-wrap "7"))
-(func ansi-reverse (str)
- (concat ansi-reverse-on str ansi-reset))
+(def reverse-on (wrap "7"))
+(func reverse (str)
+ (concat reverse-on str reset))