From 75808d925a212ad67c99b8fec58a53dde717adad Mon Sep 17 00:00:00 2001 From: Tristan Murphy <72839119+HyperCodec@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:25:35 +0000 Subject: [PATCH 1/3] create return statement (there is an error with fibonacci that needs to be looked into) --- examples/return.zisp | 5 +++++ src/eval.zig | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 examples/return.zisp diff --git a/examples/return.zisp b/examples/return.zisp new file mode 100644 index 0000000..665d769 --- /dev/null +++ b/examples/return.zisp @@ -0,0 +1,5 @@ +(def test () ( + return "hi" +)) + +(println (test)) \ No newline at end of file diff --git a/src/eval.zig b/src/eval.zig index 27026bc..136faba 100644 --- a/src/eval.zig +++ b/src/eval.zig @@ -35,6 +35,23 @@ pub fn evaluate(allocator: std.mem.Allocator, ast: std.ArrayList(model.TokenTree return switch (ast.items[0]) { .ident => |ident| { + if(std.mem.eql(u8, ident.str(), "return")) { + if(ast.items.len == 2) { + return switch(ast.items[1]) { + .constant => |constant| constant, + .context => |context| evaluate(allocator, context, runtime), + .ident => |ident2| (try runtime.env.fetch_variable(ident2.str())).?.*, + .list_init => { + var list = std.ArrayList(model.TokenTree).init(allocator); + defer list.deinit(); + try list.append(ast.items[1]); + + return evaluate(allocator, list, runtime); + }, + }; + } + } + if (std.mem.eql(u8, ident.str(), "if")) { // if cond (true) (false) const cond = switch (ast.items[1]) { From 439644e4922a779fd09fcce82c54771582fc62c9 Mon Sep 17 00:00:00 2001 From: Tristan Murphy <72839119+HyperCodec@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:49:56 +0000 Subject: [PATCH 2/3] add more conditional functions and attempt to fix fibonacci (still not working) --- README.md | 6 ++++- examples/fibonacci.zisp | 22 ++++++++------- src/std/conditional.zig | 60 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ee98e6d..5e2aba2 100644 --- a/README.md +++ b/README.md @@ -105,4 +105,8 @@ Comments can be added with `//`. When a comment character is reached, the interp - `neq arg1 arg2 ...` - Opposite of eq. - `not arg` - Reverses a boolean value. - `or arg1 arg2 ...` - Returns true if any of the args are true, false otherwise. -- `and arg1 arg2 ...` - Returns true if all of the args are true, false otherwise. \ No newline at end of file +- `and arg1 arg2 ...` - Returns true if all of the args are true, false otherwise. +- `< arg1 arg2` - returns whether the first value is less than the second. +- `<= arg1 arg2` - returns whether the first value is less than or equal to the second. +- `> arg1 arg2` - returns whether the first value is greater than the second. +- `>= arg1 arg2` - returns whether the firs tvalue is greater than or equal to the second. \ No newline at end of file diff --git a/examples/fibonacci.zisp b/examples/fibonacci.zisp index 9973a1a..f765ef7 100644 --- a/examples/fibonacci.zisp +++ b/examples/fibonacci.zisp @@ -1,19 +1,21 @@ // not doable yet with current std (var "cache" (createTable)) (def fibonacci (n) ( - (if (or (eq n 0) (eq n 1)) ( + (if (<= n 1) ( + (print "n: ") + (println n) (return n) - )) - - (if (has cache n) ( - (return (kget cache n)) - )) + ) ( + (if (has cache n) ( + return (kget cache n) + ) ( + (var "v" (- (fibonacci (- n 1)) (fibonacci (- n 2)))) - (var "v" (- (fibonacci (- n 1)) (fibonacci (- n 2)))) + (put cache n v) - (put cache n v) - - (return v) + (return v) + )) + )) )) (def fibSeq (depth) ( diff --git a/src/std/conditional.zig b/src/std/conditional.zig index 97a74e5..179c340 100644 --- a/src/std/conditional.zig +++ b/src/std/conditional.zig @@ -11,6 +11,10 @@ pub fn setup(env: *eval.Environment) !void { try env.register_internal_function("not", internal_not); try env.register_internal_function("or", internal_or); try env.register_internal_function("and", internal_and); + try env.register_internal_function("<", internal_lessthan); + try env.register_internal_function("<=", internal_lessthaneq); + try env.register_internal_function(">", internal_greaterthan); + try env.register_internal_function(">=", internal_greaterthaneq); } pub fn internal_eq(_: Allocator, args: []*model.Atom, _: *Runtime) !?model.Atom { @@ -77,3 +81,59 @@ pub fn internal_and(_: Allocator, args: []*model.Atom, _: *Runtime) !?model.Atom return model.Atom{ .bool = true }; } + +pub fn internal_lessthan(_: Allocator, args: []*model.Atom, _: *Runtime) !?model.Atom { + if(args.len != 2) { + return error.InvalidArgCount; + } + + return switch(args[0].*) { + .int => |a| switch(args[1].*) { + .int => |b| model.Atom { .bool = a < b }, + else => error.TypeMismatch, + }, + else => error.TypeMismatch, + }; +} + +pub fn internal_lessthaneq(_: Allocator, args: []*model.Atom, _: *Runtime) !?model.Atom { + if(args.len != 2) { + return error.InvalidArgCount; + } + + return switch(args[0].*) { + .int => |a| switch(args[1].*) { + .int => |b| model.Atom { .bool = a <= b }, + else => error.TypeMismatch, + }, + else => error.TypeMismatch, + }; +} + +pub fn internal_greaterthan(_: Allocator, args: []*model.Atom, _: *Runtime) !?model.Atom { + if(args.len != 2) { + return error.InvalidArgCount; + } + + return switch (args[0].*) { + .int => |a| switch (args[1].*) { + .int => |b| model.Atom { .bool = a > b }, + else => error.TypeMismatch, + }, + else => error.TypeMismatch, + }; +} + +pub fn internal_greaterthaneq(_: Allocator, args: []*model.Atom, _: *Runtime) !?model.Atom { + if(args.len != 2) { + return error.InvalidArgCount; + } + + return switch (args[0].*) { + .int => |a| switch(args[1].*) { + .int => |b| model.Atom { .bool = a >= b }, + else => error.TypeMismatch, + }, + else => error.TypeMismatch, + }; +} \ No newline at end of file From 353f47091c4a79407710f0a8ab2363775ab1751e Mon Sep 17 00:00:00 2001 From: Tristan Murphy <72839119+HyperCodec@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:24:50 +0000 Subject: [PATCH 3/3] implement more advanced returns --- README.md | 2 +- examples/fibonacci.zisp | 22 ++++++--------- src/eval.zig | 62 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 5e2aba2..a8eb993 100644 --- a/README.md +++ b/README.md @@ -109,4 +109,4 @@ Comments can be added with `//`. When a comment character is reached, the interp - `< arg1 arg2` - returns whether the first value is less than the second. - `<= arg1 arg2` - returns whether the first value is less than or equal to the second. - `> arg1 arg2` - returns whether the first value is greater than the second. -- `>= arg1 arg2` - returns whether the firs tvalue is greater than or equal to the second. \ No newline at end of file +- `>= arg1 arg2` - returns whether the first value is greater than or equal to the second. \ No newline at end of file diff --git a/examples/fibonacci.zisp b/examples/fibonacci.zisp index f765ef7..7d80bc1 100644 --- a/examples/fibonacci.zisp +++ b/examples/fibonacci.zisp @@ -1,21 +1,17 @@ -// not doable yet with current std (var "cache" (createTable)) (def fibonacci (n) ( (if (<= n 1) ( - (print "n: ") - (println n) - (return n) - ) ( - (if (has cache n) ( - return (kget cache n) - ) ( - (var "v" (- (fibonacci (- n 1)) (fibonacci (- n 2)))) - - (put cache n v) + return n + )) - (return v) - )) + (if (has cache n) ( + return (kget cache n) )) + + (var "v" (+ (fibonacci (- n 1)) (fibonacci (- n 2)))) + (put cache n v) + + (return v) )) (def fibSeq (depth) ( diff --git a/src/eval.zig b/src/eval.zig index 136faba..95e83e4 100644 --- a/src/eval.zig +++ b/src/eval.zig @@ -4,11 +4,23 @@ const String = @import("string").String; const internal_std = @import("std/root.zig"); pub fn evaluate(allocator: std.mem.Allocator, ast: std.ArrayList(model.TokenTree), runtime: *Runtime) !?model.Atom { + if(runtime.env.has_returned()) { + return runtime.env.get_current_return(); + } + if (ast.items.len == 1) { return switch (ast.items[0]) { .constant => |constant| constant, .context => |context| evaluate(allocator, context, runtime), - .ident => |ident| runtime.run_function(allocator, ident.str(), &[_]*model.Atom{}), + .ident => |ident| { + if(std.mem.eql(u8, ident.str(), "return")) { + // no-value return + runtime.env.return_current(null); + return null; + } + + return runtime.run_function(allocator, ident.str(), &[_]*model.Atom{}); + }, .list_init => |items| { var contents = std.ArrayList(model.Atom).init(allocator); @@ -38,15 +50,29 @@ pub fn evaluate(allocator: std.mem.Allocator, ast: std.ArrayList(model.TokenTree if(std.mem.eql(u8, ident.str(), "return")) { if(ast.items.len == 2) { return switch(ast.items[1]) { - .constant => |constant| constant, - .context => |context| evaluate(allocator, context, runtime), - .ident => |ident2| (try runtime.env.fetch_variable(ident2.str())).?.*, + .constant => |constant| { + runtime.env.return_current(constant); + return constant; + }, + .context => |context| { + const atom = try evaluate(allocator, context, runtime); + runtime.env.return_current(atom); + return atom; + }, + .ident => |ident2| { + const atom = (try runtime.env.fetch_variable(ident2.str())).?.*; + runtime.env.return_current(atom); + return atom; + }, .list_init => { var list = std.ArrayList(model.TokenTree).init(allocator); defer list.deinit(); try list.append(ast.items[1]); - return evaluate(allocator, list, runtime); + const list2 = try evaluate(allocator, list, runtime); + runtime.env.return_current(list2); + + return list2; }, }; } @@ -132,6 +158,7 @@ pub fn evaluate(allocator: std.mem.Allocator, ast: std.ArrayList(model.TokenTree // TODO evaluation could be null, need an actual error handling .context => |context| { + // runtime.env.print_stacktrace(); var result = (try evaluate(allocator, context, runtime)).?; try args.append(&result); @@ -161,6 +188,10 @@ pub fn evaluate(allocator: std.mem.Allocator, ast: std.ArrayList(model.TokenTree _ = try evaluate(allocator, context, runtime); for (ast.items[1..]) |tree| { + if(runtime.env.has_returned()) { + return runtime.env.get_current_return(); + } + switch (tree) { .context => |context2| _ = try evaluate(allocator, context2, runtime), .constant => return error.CannotCallValue, @@ -173,7 +204,7 @@ pub fn evaluate(allocator: std.mem.Allocator, ast: std.ArrayList(model.TokenTree } } - return null; + return runtime.env.get_current_return(); }, .list_init => return error.CannotCallValue, }; @@ -225,6 +256,7 @@ pub const Runtime = struct { const val = try self.env.fetch_variable(ident); if (val == null) { + std.debug.print("Identifier: {s}\n", .{ident}); return error.IdentDoesNotExist; } @@ -276,7 +308,7 @@ pub const Environment = struct { } pub fn enter_new_frame(self: *Self, functionName: []const u8, allocator: std.mem.Allocator) !void { - try self.stack.append(StackFrame{ .name = functionName, .locals = std.StringHashMap(model.Atom).init(allocator) }); + try self.stack.append(StackFrame{ .name = functionName, .locals = std.StringHashMap(model.Atom).init(allocator), .return_value = null, .has_returned = false }); } pub fn exit_frame(self: *Self) void { @@ -331,6 +363,20 @@ pub const Environment = struct { }, }); } + + pub fn return_current(self: *Self, val: ?model.Atom) void { + var frame = self.current_stack_frame(); + frame.return_value = val; + frame.has_returned = true; + } + + pub fn get_current_return(self: *Self) ?model.Atom { + return self.current_stack_frame().return_value; + } + + pub fn has_returned(self: *Self) bool { + return self.current_stack_frame().has_returned; + } }; pub const StackFrame = struct { @@ -338,6 +384,8 @@ pub const StackFrame = struct { locals: std.StringHashMap(model.Atom), name: []const u8, + return_value: ?model.Atom, + has_returned: bool, pub fn deinit(self: *Self) void { //self.name.deinit();