aboutsummaryrefslogtreecommitdiff
path: root/interpreter.py
diff options
context:
space:
mode:
Diffstat (limited to 'interpreter.py')
-rw-r--r--interpreter.py308
1 files changed, 75 insertions, 233 deletions
diff --git a/interpreter.py b/interpreter.py
index 84fae67..1e6d78d 100644
--- a/interpreter.py
+++ b/interpreter.py
@@ -193,15 +193,9 @@ def interpretAnd(symbol, args, env):
GLOBALS.register("and", Builtin(interpretAnd, [or_arg, or_arg], or_arg))
def interpretEq(symbol, args, env):
- # equal
# NOTE this currently only works for literals
- first = evaluate(args[0], env)
- second = evaluate(args[1], env)
- if not (isinstance(first, Literal) and isinstance(second, Literal)):
- raise InterpretPanic(symbol, "can only compare :literals")
# compare types because 0 != #false in neb
- # TODO number equality?
- if type(first) == type(second) and first.value == second.value:
+ if type(args[0]) == type(args[1]) and args[0].value == args[1].value:
return Bool(True)
else:
return Bool(False)
@@ -210,57 +204,30 @@ eq_arg = Arg("value", T.Literal, False, False)
GLOBALS.register("eq?", Builtin(interpretEq, [eq_arg, eq_arg]))
def interpretGreaterThan(symbol, args, env):
- left = evaluate(args[0], env)
- if not (isinstance(left, Int) or isinstance(left, Float)):
- raise InterpretPanic(symbol, "first argument must be a :number", left)
- right = evaluate(args[1], env)
- if not (isinstance(right, Int) or isinstance(right, Float)):
- raise InterpretPanic(symbol, "second argument must be a :number", right)
- return Bool(left.value > right.value)
+ return Bool(args[0].value > args[1].value)
compare_arg = Arg("num", T.Number, False, False)
GLOBALS.register(">", Builtin(interpretGreaterThan, [compare_arg, compare_arg]))
def interpretGreaterThanEqual(symbol, args, env):
- left = evaluate(args[0], env)
- if not (isinstance(left, Int) or isinstance(left, Float)):
- raise InterpretPanic(symbol, "first argument must be a :number", left)
- right = evaluate(args[1], env)
- if not (isinstance(right, Int) or isinstance(right, Float)):
- raise InterpretPanic(symbol, "second argument must be a :number", right)
- return Bool(left.value >= right.value)
+ return Bool(args[0].value >= args[1].value)
GLOBALS.register(">=", Builtin(interpretGreaterThanEqual, [compare_arg, compare_arg]))
def interpretLessThan(symbol, args, env):
- left = evaluate(args[0], env)
- if not (isinstance(left, Int) or isinstance(left, Float)):
- raise InterpretPanic(symbol, "first argument must be a :number", left)
- right = evaluate(args[1], env)
- if not (isinstance(right, Int) or isinstance(right, Float)):
- raise InterpretPanic(symbol, "second argument must be a :number", right)
- return Bool(left.value < right.value)
+ return Bool(args[0].value < args[1].value)
GLOBALS.register("<", Builtin(interpretLessThan, [compare_arg, compare_arg]))
def interpretLessThanEqual(symbol, args, env):
- left = evaluate(args[0], env)
- if not (isinstance(left, Int) or isinstance(left, Float)):
- raise InterpretPanic(symbol, "first argument must be a :number", left)
- right = evaluate(args[1], env)
- if not (isinstance(right, Int) or isinstance(right, Float)):
- raise InterpretPanic(symbol, "second argument must be a :number", right)
- return Bool(left.value <= right.value)
+ return Bool(args[0].value <= args[1].value)
GLOBALS.register("<=", Builtin(interpretLessThanEqual, [compare_arg, compare_arg]))
def interpretAddition(symbol, args, env):
res = 0
for arg in args:
- ev = evaluate(arg, env)
- if not (isinstance(ev, Int) or isinstance(ev, Float)):
- raise InterpretPanic(symbol, "argument must be a :number", ev)
- res += ev.value
+ res += arg.value
if isinstance(res, float):
return Float(res)
else:
@@ -270,18 +237,12 @@ term_arg = Arg("term", T.Number, False, False)
GLOBALS.register("+", Builtin(interpretAddition, [term_arg], term_arg))
def interpretSubtraction(symbol, args, env):
- first = evaluate(args[0], env)
- if not (isinstance(first, Int) or isinstance(first, Float)):
- raise InterpretPanic(symbol, "argument must be a :number", first)
if len(args) == 1:
- res = -first.value
+ res = -args[0].value
else:
- res = first.value
+ res = args[0].value
for arg in args[1:]:
- ev = evaluate(arg, env)
- if not (isinstance(ev, Int) or isinstance(ev, Float)):
- raise InterpretPanic(symbol, "argument must be a :number", ev)
- res -= ev.value
+ res -= arg.value
if isinstance(res, float):
return Float(res)
else:
@@ -290,15 +251,9 @@ def interpretSubtraction(symbol, args, env):
GLOBALS.register("-", Builtin(interpretSubtraction, [term_arg], term_arg))
def interpretMultiplication(symbol, args, env):
- first = evaluate(args[0], env)
- if not (isinstance(first, Int) or isinstance(first, Float)):
- raise InterpretPanic(symbol, "argument must be a :number", first)
- res = first.value
+ res = args[0].value
for arg in args[1:]:
- tmp = evaluate(arg, env)
- if not (isinstance(tmp, Int) or isinstance(tmp, Float)):
- raise InterpretPanic(symbol, "argument must be a :number", tmp)
- res = res * tmp.value
+ res = res * arg.value
if isinstance(res, float):
return Float(res)
else:
@@ -308,13 +263,7 @@ factor_arg = Arg("factor", T.Number, False, False)
GLOBALS.register("*", Builtin(interpretMultiplication, [factor_arg, factor_arg], factor_arg))
def interpretDivision(symbol, args, env):
- num = evaluate(args[0], env)
- if not (isinstance(num, Int) or isinstance(num, Float)):
- raise InterpretPanic(symbol, "numerator must be a :number", num)
- denom = evaluate(args[1], env)
- if not (isinstance(denom, Int) or isinstance(denom, Float)):
- raise InterpretPanic(symbol, "denominator must be a :number", denom)
- ret = num.value / denom.value
+ ret = args[0].value / args[1].value
if int(ret) == ret:
return Int(int(ret))
else:
@@ -323,24 +272,18 @@ def interpretDivision(symbol, args, env):
GLOBALS.register("/", Builtin(interpretDivision, [factor_arg, factor_arg]))
def interpretNot(symbol, args, env):
- res = evaluate(args[0], env)
- if not isinstance(res, Bool):
- raise InterpretPanic(symbol, "requires a :bool", res)
- return Bool(not res.value)
+ return Bool(not args[0].value)
not_arg = Arg("not", T.Bool, False, False)
GLOBALS.register("not", Builtin(interpretNot, [not_arg]))
def interpretIf(symbol, args, env):
# if cond t-branch [f-branch]
- cond = evaluate(args[0], env)
- if not isinstance(cond, Bool):
- raise InterpretPanic(symbol, "condition must be :bool", cond)
- if cond.value:
+ if args[0].value:
return evaluate(args[1], env)
elif len(args) == 3:
return evaluate(args[2], env)
- return List([]) # this shouldn't be reached
+ return List([])
cond = Arg("cond", T.Bool, False, False)
t_branch = Arg("t-branch", T.Any, False, True)
@@ -348,11 +291,7 @@ f_branch = Arg("f-branch", T.Any, True, True)
GLOBALS.register("if", Builtin(interpretIf, [cond, t_branch, f_branch]))
def interpretPrint(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, String):
- raise InterpretPanic(symbol, "requires a :string")
- print(ev.value)
-
+ print(args[0].value)
return List([]) # print returns nothing
GLOBALS.register("print", Builtin(interpretPrint, [Arg("arg", T.String, False, False)]))
@@ -364,8 +303,7 @@ def interpretDef(symbol, args, env):
if not isinstance(name, str):
raise InterpretPanic(symbol, "requires a :string name")
- ev = evaluate(args[1], env)
- env.register(name, ev)
+ env.register(name, args[1]) # TODO since this isn't lazily evaluated, side effects are allowed (bad!)
return List([])
def_name_arg = Arg("name", T.Any, False, True)
@@ -379,8 +317,7 @@ def interpretRedef(symbol, args, env):
if not env.contains(name):
raise InterpretPanic(symbol, "not previously defined", args[0])
- ev = evaluate(args[1], env)
- env.reregister(name, ev)
+ env.reregister(name, args[1])
return List([])
GLOBALS.register("redef", Builtin(interpretRedef, [def_name_arg, def_val_arg]))
@@ -397,13 +334,13 @@ lambda_body_arg = Arg("body", T.Any, False, True)
GLOBALS.register("lambda", Builtin(interpretLambda, [lambda_args_arg, lambda_body_arg], lambda_body_arg))
def interpretToString(symbol, args, env):
- ev = evaluate(args[0], env)
- if isinstance(ev, String):
- return ev
- elif isinstance(ev, Literal):
- return String(str(ev))
+ item = args[0]
+ if isinstance(item, String):
+ return item
+ elif isinstance(item, Literal):
+ return String(str(item))
else:
- return String(f"{ev}")
+ return String(f"{item}")
GLOBALS.register("->string", Builtin(interpretToString, [Arg("arg", T.Any, False, False)]))
@@ -411,10 +348,7 @@ def interpretConcat(symbol, args, env):
# concat str1 str2...strN
out = ""
for arg in args:
- tmp = evaluate(arg, env)
- if not isinstance(tmp, String):
- raise InterpretPanic(symbol, "requires :string", tmp)
- out += tmp.value
+ out += arg.value
return String(out)
string_arg = Arg("arg", T.String, False, False)
@@ -422,12 +356,9 @@ GLOBALS.register("concat", Builtin(interpretConcat, [string_arg, string_arg], st
def interpretForCount(symbol, args, env):
# for-count int exprs
- num = evaluate(args[0], env)
- if not isinstance(num, Int):
- raise InterpretPanic(symbol, "count must be an integer", num)
new_env = Environment(env)
ret = None
- for idx in range(0, num.value):
+ 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)
@@ -441,12 +372,9 @@ GLOBALS.register("for-count", Builtin(interpretForCount, [for_count_arg, for_bod
def interpretForEach(symbol, args, env):
# for-each list exprs
- lst = evaluate(args[0], env)
- if not isinstance(lst, List):
- raise InterpretPanic(symbok, "requires a :list", lst)
new_env = Environment(env)
ret = None
- for item in lst.args:
+ for item in args[0].args:
new_env.register("_item_", evaluate(item, env))
for arg in args[1:]:
ret = evaluate(arg, new_env)
@@ -509,7 +437,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):
- target_file_name = evaluate(args[0], env).value
+ 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)
@@ -522,36 +450,26 @@ GLOBALS.register("read-lines", Builtin(interpretReadLines, [Arg("filename", T.St
# - strip whitespace from string
def interpretStrip(symbol, args, env):
- out = evaluate(args[0], env)
- if not isinstance(out, String):
- raise InterpretPanic(symbol, "requires a :string", out)
- return String(out.value.strip())
+ return String(args[0].value.strip())
GLOBALS.register("strip", Builtin(interpretStrip, [Arg("filename", T.String, False, False)]))
# - string->int and string->float
def interpretStringToInt(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, String):
- raise InterpretPanic(symbol, "requires a :string", ev)
try:
- val = int(ev.value)
+ val = int(args[0].value)
return Int(val)
except:
- raise InterpretPanic(symbol, "can't convert to an :int", ev)
+ raise InterpretPanic(symbol, "can't convert to an :int", args[0])
GLOBALS.register("string->int", Builtin(interpretStringToInt, [Arg("arg", T.String, False, False)]))
# - split a string by a given field
def interpretSplit(symbol, args, env):
- target = evaluate(args[0], env)
- if not isinstance(target, String):
- raise InterpretPanic(symbol, "requires a :string as its first argument", target)
+ target = args[0]
if len(args) == 1:
return List([String(char) for char in target.value], True)
- splitter = evaluate(args[1], env)
- if not isinstance(splitter, String):
- raise InterpretPanic(symbol, "requires a :string as its second argument", splitter)
+ splitter = args[1]
ret = target.value.split(splitter.value)
return List([String(r) for r in ret], True)
@@ -559,30 +477,21 @@ GLOBALS.register("split", Builtin(interpretSplit, [Arg("target", T.String, False
# - get the length of a list
def interpretListLength(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, List):
- raise InterpretPanic(symbol, "requires a :list", ev)
- return Int(len(ev.args))
+ return Int(len(args[0].args))
GLOBALS.register("list-length", Builtin(interpretListLength, [Arg("arg", T.List, False, False)]))
# - first/rest of list
def interpretFirst(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, List):
- raise InterpretPanic(symbol, "requires a :list", ev)
- if len(ev.args) == 0:
+ if len(args[0].args) == 0:
raise InterpretPanic(symbol, "list is empty")
- return evaluate(ev.args[0], env)
+ return evaluate(args[0].args[0], env)
GLOBALS.register("first", Builtin(interpretFirst, [Arg("arg", T.List, False, False)]))
def interpretRest(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, List):
- raise InterpretPanic(symbol, "requires a :list", ev)
# TODO do we know it's not evaluated?
- return List(ev.args[1:], True) # we don't evaluate the remainder of the list
+ return List(args[0].args[1:], True) # we don't evaluate the remainder of the list
GLOBALS.register("rest", Builtin(interpretRest, [Arg("arg", T.List, False, False)]))
@@ -603,20 +512,17 @@ def interpretMap(symbol, args, env):
return List(out, True)
GLOBALS.register("map", Builtin(interpretMap, [Arg("func", T.Any, False, True), Arg("list", T.List, False, False)]))
+#GLOBALS.register("map", Builtin(interpretMap, [Arg("func", T.Any, False, False), Arg("list", T.List, False, False)]))
def interpretZip(symbol, args, env):
- z1 = evaluate(args[0], env)
- if not isinstance(z1, List):
- raise InterpretPanic(symbol, "requires two :lists", z1)
- z2 = evaluate(args[1], env)
- if not isinstance(z2, List):
- raise InterpretPanic(symbol, "requires two :lists", z2)
+ z1 = args[0]
+ z2 = args[1]
if len(z1.args) != len(z2.args):
raise InterpretPanic(symbol, "requires two :lists of the same size")
out = []
for idx in range(len(z1.args)):
- f = evaluate(z1.args[idx], env)
- s = evaluate(z2.args[idx], env)
+ f = z1.args[idx]
+ s = z2.args[idx]
out.append(List([f, s], True))
return List(out, True)
@@ -624,75 +530,54 @@ zip_arg = Arg("list", T.List, False, False)
GLOBALS.register("zip", Builtin(interpretZip, [zip_arg, zip_arg]))
def interpretList(symbol, args, env):
- out = []
- for arg in args:
- out.append(evaluate(arg, env))
- return List(out, True)
+ return List(args, True)
GLOBALS.register("list", Builtin(interpretList, [], Arg("item", T.Any, False, False)))
def interpretListReverse(symbol, args, env):
- lst = evaluate(args[0], env)
- if not isinstance(lst, List):
- raise InterpretPanic(symbol, "requires a :list", lst)
- new_args = lst.args[:] # make a copy of the args
+ 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", T.List, False, False)]))
def interpretApply(symbol, args, env):
+ # 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)
- if not isinstance(lst, List):
- raise InterpretPanic(symbol, "requires a :list as its second argument". lst)
- new_lst = List([func] + lst.args)
+ new_lst = List([func] + args[1].args)
return evaluate(new_lst, env)
GLOBALS.register("apply", Builtin(interpretApply, [Arg("func", T.Any, False, True), Arg("list", T.List, False, False)]))
def interpretGlob(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, String):
- raise InterpretPanic(symbol, "requires a :string", ev)
- items = glob(ev.value)
+ items = glob(args[0].value)
return List([String(item) for item in items], True)
GLOBALS.register("glob", Builtin(interpretGlob, [Arg("regex", T.String, False, False)]))
def interpretShell(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, String):
- raise InterpretPanic(symbol, "requires a :string", ev)
# TODO either fail or throw exception (?) on error
- ret = subprocess.run(shlex.split(ev.value), capture_output=True)
+ 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", T.String, False, False)]))
def interpretEmpty(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, List):
- raise InterpretPanic(symbol, "requires a :list", ev)
- return Bool(len(ev.args) == 0)
+ return Bool(len(args[0].args) == 0)
GLOBALS.register("empty?", Builtin(interpretEmpty, [Arg("list", T.List, False, False)]))
def interpretShuf(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, List):
- raise InterpretPanic(symbol, "expects a :list", ev)
- items = ev.args[:]
+ items = args[0].args[:]
random.shuffle(items)
return List(items, True)
GLOBALS.register("shuf", Builtin(interpretShuf, [Arg("list", T.List, False, False)]))
def interpretIsList(symbol, args, env):
- ev = evaluate(args[0], env)
- return Bool(isinstance(ev, List))
+ return Bool(isinstance(args[0], List))
GLOBALS.register("list?", Builtin(interpretIsList, [Arg("arg", T.Any, False, False)]))
@@ -706,9 +591,7 @@ block_arg = Arg("expr", T.Any, False, True)
GLOBALS.register("block", Builtin(interpretBlock, [block_arg], block_arg))
def interpretExit(symbol, args, env):
- status = 0 if len(args) == 0 else evaluate(args[0], env).value
- if not isinstance(status, int):
- raise InterpretPanic(symbol, "expects an :int", status)
+ status = 0 if len(args) == 0 else args[0].value
sys.exit(status)
return List([])
@@ -716,10 +599,7 @@ exit_arg = Arg("status", T.Int, True, False)
GLOBALS.register("exit", Builtin(interpretExit, [exit_arg]))
def interpretUnlink(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, String):
- raise InterpretPanic(symbol, "expects a :string", ev)
- target_path = Path(ev.value).resolve()
+ target_path = Path(args[0].value).resolve()
if not target_path.exists():
raise InterpretPanic(symbol, "target file does not exist", target_path)
target_path.unlink()
@@ -736,15 +616,10 @@ def interpretArgv(symbol, args, env):
GLOBALS.register("argv", Builtin(interpretArgv, []))
def interpretIn(symbol, args, env):
- target = evaluate(args[0], env)
- if not isinstance(target, Literal):
- raise InterpretPanic(symbol, "expects a :literal as its first argument", target)
- lst = evaluate(args[1], env)
- if not isinstance(lst, List):
- raise InterpretPanic(symbol, "expects a :list as its second argument", lst)
+ target = args[0]
+ lst = args[1]
for arg in lst.args:
- ev = evaluate(arg, env)
- if type(ev) == type(target) and ev.value == target.value:
+ if type(arg) == type(target) and arg.value == target.value:
return Bool(True)
return Bool(False)
@@ -753,22 +628,15 @@ in_list_arg = Arg("list", T.List, False, False)
GLOBALS.register("in?", Builtin(interpretIn, [in_target_arg, in_list_arg]))
def interpretLast(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, List):
- raise InterpretPanic("'last' expects a List")
- if len(ev.args) == 0:
+ if len(args[0].args) == 0:
raise InterpretPanic("List is empty")
- return evaluate(ev.args[-1], env)
+ return evaluate(args[0].args[-1], env)
GLOBALS.register("last", Builtin(interpretLast, [Arg("list", T.List, False, False)]))
def interpretJoin(symbol, args, env):
- lst = evaluate(args[0], env)
- if not isinstance(lst, List):
- raise InterpretPanic(symbol, "expects a :list as its first argument", lst)
- target = evaluate(args[1], env)
- if not isinstance(target, String):
- raise InterpretPanic(symbol, "expects a :string as its second argument", target)
+ lst = args[0]
+ target = args[1]
return String(target.value.join([a.value for a in lst.args]))
join_list_arg = Arg("list", T.List, False, False)
@@ -776,11 +644,7 @@ join_string_arg = Arg("joiner", T.String, False, False)
GLOBALS.register("join", Builtin(interpretJoin, [join_list_arg, join_string_arg]))
def interpretWithWrite(symbol, args, env):
- if len(args) == 0:
- raise InterpretPanic(symbol, "expects at least one argument")
- target_file = evaluate(args[0], env)
- if not isinstance(target_file, String):
- raise InterpretPanic(symbol, "expects a :string as its first argument", target_file)
+ target_file = args[0]
new_env = Environment(env)
target_path = Path(target_file.value).resolve()
ret = Literal([])
@@ -790,14 +654,12 @@ def interpretWithWrite(symbol, args, env):
ret = evaluate(arg, new_env)
return ret
-GLOBALS.register("with-write", Builtin(interpretWithWrite, [Arg("filename", T.String, False, False)]))
+GLOBALS.register("with-write", Builtin(interpretWithWrite, [Arg("filename", T.String, False, False)], Arg("exprs", T.Any, False, True)))
def interpretWrite(symbol, args, env):
# write :string :filehandle
- line = evaluate(args[0], env)
- if not isinstance(line, String):
- raise InterpretPanic(symbol, "expects a :string as its first argument", line)
- handle = evaluate(args[1], env)
+ line = args[0]
+ handle = args[1]
handle.args[0].write(line.value) # TODO wrong! how do we evaluate a handle?
return Literal([])
@@ -809,43 +671,28 @@ def interpretNewline(symbol, args, env):
GLOBALS.register("newline", Builtin(interpretNewline, []))
def interpretExists(symbol, args, env):
- file_or_dir = evaluate(args[0], env)
- if not isinstance(file_or_dir, String):
- raise InterpretPanic(symbol, "expects a :string", file_or_dir)
- return Bool(Path(file_or_dir.value).resolve().exists())
+ return Bool(Path(args[0].value).resolve().exists())
GLOBALS.register("exists?", Builtin(interpretExists, [Arg("filename", T.String, False, False)]))
def interpretFirstChar(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, String):
- raise InterpretPanic(symbol, "expects a :string", ev)
- if len(ev.value) == 0:
+ if len(args[0].value) == 0:
raise InterpretPanic(symbol, ":string is empty", ev)
- return String(ev.value[0])
+ return String(args[0].value[0])
GLOBALS.register("first-char", Builtin(interpretFirstChar, [Arg("string", T.String, False, False)]))
def interpretRestChar(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, String):
- raise InterpretPanic(symbol, "expects a string", ev)
- return String(ev.value[1:])
+ return String(args[0].value[1:])
GLOBALS.register("rest-char", Builtin(interpretRestChar, [Arg("string", T.String, False, False)]))
def interpretSlice(symbol, args, env):
- lst = evaluate(args[0], env)
- if not isinstance(lst, List):
- raise InterpretPanic(symbol, "expects a :list as its first argument", lst)
- idx = evaluate(args[1], env)
- if not isinstance(idx, Int):
- raise InterpretPanic(symbol, "expects an :int as its second argument", idx)
+ lst = args[0]
+ idx = args[1]
if len(args) == 2:
return List(lst.args[idx.value - 1:])
- length = evaluate(args[2], env)
- if not isinstance(length, Int):
- raise InterpretPanic(symbol, "expects an :int as its third argument", length)
+ length = args[2]
diff = idx.value - 1 + length.value
return List(lst.args[idx.value - 1:diff])
@@ -861,19 +708,14 @@ def interpretClear(symbol, args, env):
GLOBALS.register("clear", Builtin(interpretClear, []))
def interpretInput(symbol, args, env):
- ev = evaluate(args[0], env)
- if not isinstance(ev, String):
- raise InterpretPanic(symbol, "expects a :string", ev)
- ret = input(ev.value)
+ ret = input(args[0].value)
return String(ret)
GLOBALS.register("input", Builtin(interpretInput, [Arg("prompt", T.String, False, False)]))
def interpretAppend(symbol, args, env):
- lst = evaluate(args[0], env)
- if not isinstance(lst, List):
- raise InterpretPanic(symbol, "expects a :list as its first argument", lst)
- val = evaluate(args[1], env)
+ lst = args[0]
+ val = args[1]
items = lst.args[:]
return List(items + [val], True)
@@ -914,7 +756,7 @@ def interpretAnsiEscape(symbol, args, env):
GLOBALS.register("ansi-escape", Builtin(interpretAnsiEscape, []))
def interpretUse(symbol, args, env):
- target_file_name = evaluate(args[0], env).value
+ 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)