Skip to content

Commit

Permalink
xslt, c, zig: test for, fix seq parsing EOF errors
Browse files Browse the repository at this point in the history
xslt:
- The reader was returning the an odd args error when a hash-map literal
  was not closed. This was because the the parsing error happened and
  then the odd args test happened after and overwrote the parsing error.
- Also, fix the read-string function so that if an error is set by the
  reader, this is converted to a full error that bubbles up.

c:
- read_list errors were not being detected/propagated in read_hash_map
  after calling read_list.

zig:
- reader errors were not being caught in the rep loop until step 8, so
  those errors in step6 and step7 were causing the REPL to exit.
  • Loading branch information
kanaka committed Aug 22, 2024
1 parent 39563fd commit a2973ab
Show file tree
Hide file tree
Showing 14 changed files with 121 additions and 71 deletions.
5 changes: 3 additions & 2 deletions impls/c/reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ MalVal *read_list(Reader *reader, MalType type, char start, char end) {
MalVal *ast, *form;
char *token = reader_next(reader);
//g_print("read_list start token: %s\n", token);
if (token[0] != start) { abort("expected '(' or '['"); }
if (token[0] != start) { abort("expected '(', '[', or '{'"); }

ast = malval_new_list(type, g_array_new(TRUE, TRUE, sizeof(MalVal*)));

Expand All @@ -148,14 +148,15 @@ MalVal *read_list(Reader *reader, MalType type, char start, char end) {
}
g_array_append_val(ast->val.array, form);
}
if (!token) { abort("expected ')' or ']', got EOF"); }
if (!token) { abort("expected ')', ']', or '}', got EOF"); }
reader_next(reader);
//g_print("read_list end token: %s\n", token);
return ast;
}

MalVal *read_hash_map(Reader *reader) {
MalVal *lst = read_list(reader, MAL_LIST, '{', '}');
if (!lst) { return NULL; }
MalVal *hm = _hash_map(lst);
malval_free(lst);
return hm;
Expand Down
2 changes: 2 additions & 0 deletions impls/tests/step1_read_print.mal
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ false
;/.*(EOF|end of input|unbalanced).*
[1 2
;/.*(EOF|end of input|unbalanced).*
{"a" 2
;/.*(EOF|end of input|unbalanced).*

;;; These should throw some error with no return value
"abc
Expand Down
9 changes: 8 additions & 1 deletion impls/tests/step6_file.mal
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
;;; Differing output, but make sure no fatal error
(read-string ";; comment")


(eval (read-string "(+ 2 3)"))
;=>5

Expand Down Expand Up @@ -112,6 +111,14 @@
;;
;; -------- Deferrable Functionality --------

;; Testing read-string parsing errors
(read-string "(+ 1")
;/.*(EOF|end of input|unbalanced).*
(read-string "[+ 1")
;/.*(EOF|end of input|unbalanced).*
(read-string "{:a 1")
;/.*(EOF|end of input|unbalanced).*

;; Testing reading of large files
(load-file "../tests/computations.mal")
;=>nil
Expand Down
11 changes: 9 additions & 2 deletions impls/tests/step9_try.mal
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
(try* (map throw (list "my err")) (catch* exc exc))
;=>"my err"


;;
;; Testing builtin functions

Expand Down Expand Up @@ -113,6 +112,14 @@
;; ------- Deferrable Functionality ----------
;; ------- (Needed for self-hosting) -------

;; Test catch of reader errors
(try* (eval (read-string "(+ 1")) (catch* e (prn :e e)))
;/.*(EOF|end of input|unbalanced).*
(try* (eval (read-string "[+ 1")) (catch* e (prn :e e)))
;/.*(EOF|end of input|unbalanced).*
(try* (eval (read-string "{:a 1")) (catch* e (prn :e e)))
;/.*(EOF|end of input|unbalanced).*

;; Testing symbol and keyword functions
(symbol? :abc)
;=>false
Expand Down Expand Up @@ -413,4 +420,4 @@
(bar {:foo (fn* [x] x)})
(bar {:foo 3})
;=>{:foo 3}
;; shouldn't give an error
;; shouldn't give an error
12 changes: 10 additions & 2 deletions impls/xslt/core.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,16 @@
<xsl:value-of select="$args/value/malval/lvalue/malval[1]/@value"/>
</str>
</xsl:variable>
<xsl:for-each select="$read-string-context">
<xsl:call-template name="malreader-read_str"/>
<xsl:variable name="form">
<xsl:for-each select="$read-string-context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error), core:makeMALValue(string(error), 'string'))"/>
</xsl:if>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:when>
<xsl:when test="$func/malval/@name = 'slurp'">
Expand Down
5 changes: 4 additions & 1 deletion impls/xslt/reader.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@
</value>
</xsl:variable>
<xsl:choose>
<xsl:when test="error">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$listkind = '{'">
<xsl:choose>
<xsl:when test="count($value/value/malval/lvalue/malval) mod 2 = 1">
Expand Down Expand Up @@ -419,7 +422,7 @@
</xsl:when>
<xsl:otherwise>
<error>
<malval kind="error">EOF while reading list</malval>
<malval kind="error">EOF while reading sequence</malval>
</error>
</xsl:otherwise>
</xsl:choose>
Expand Down
2 changes: 1 addition & 1 deletion impls/zig/step3_env.zig
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ fn EVAL_let(mal: *MalType, env: *Env) MalError!*MalType {
optional_node = iterator.next();
key_mal.delete(Allocator);
}

linked_list.destroy(Allocator, &binding_ll, true);
binding_arg.data = MalData{.Nil=undefined};
mal.delete(Allocator);
Expand Down
2 changes: 1 addition & 1 deletion impls/zig/step4_if_fn_do.zig
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ fn EVAL_let(mal: *MalType, env: *Env) MalError!*MalType {
optional_node = iterator.next();
key_mal.delete(Allocator);
}

linked_list.destroy(Allocator, &binding_ll, true);
binding_arg.data = MalData{.Nil=undefined};
mal.delete(Allocator);
Expand Down
4 changes: 2 additions & 2 deletions impls/zig/step5_tco.zig
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fn EVAL_let(mal_ptr: **MalType, env_ptr: **Env) MalError!void {
optional_node = iterator.next();
key_mal.delete(Allocator);
}

linked_list.destroy(Allocator, &binding_ll, true);
binding_arg.data = MalData{.Nil=undefined};
mal.delete(Allocator);
Expand Down Expand Up @@ -275,7 +275,7 @@ fn make_environment() MalError!*Env {
if(optional_output) |output| {
Allocator.free(output);
}

return environment;
}

Expand Down
45 changes: 28 additions & 17 deletions impls/zig/step6_file.zig
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ fn EVAL_let(mal_ptr: **MalType, env_ptr: **Env) MalError!void {
optional_node = iterator.next();
key_mal.delete(Allocator);
}

linked_list.destroy(Allocator, &binding_ll, true);
binding_arg.data = MalData{.Nil=undefined};
binding_arg.delete(Allocator);
Expand Down Expand Up @@ -202,8 +202,27 @@ fn rep(environment: *Env, input: [] const u8) MalError!?[] u8 {
return print_input;
}

fn rep_and_print_errors(environment: *Env, input: [] const u8) ?[]u8 {
return rep(environment, input) catch |err| {
switch(err) {
MalError.KeyError => { },
MalError.OutOfBounds => {
warn("Error: out of bounds\n");
},
MalError.ReaderUnmatchedParen => {
warn("Error: expected closing paren, got EOF\n");
},
else => {
warn("Unhandled error\n");
},
}
return null;
};
}


fn lookup(environment: *Env, symbol: []const u8, do_warn: bool) MalError!*MalType {
var mal = environment.get(symbol) catch |err| {
var mal = environment.get(symbol) catch |err| {
if(do_warn) {
const s1 = string_concat(Allocator, "'", symbol) catch return MalError.SystemError;
const s2 = string_concat(Allocator, s1, "' not found") catch return MalError.SystemError;
Expand Down Expand Up @@ -290,7 +309,7 @@ fn make_environment() MalError!*Env {
const eval_mal = try MalType.new_nil(Allocator);
eval_mal.data = MalData{.Fn1 = &eval};
try environment.set("eval", eval_mal);

const def_not_string: [] const u8 =
\\(def! not (fn* (a) (if a false true)))
;
Expand Down Expand Up @@ -351,21 +370,13 @@ pub fn main() !void {
var output = try rep(environment, run_cmd);
return;
}

while(true) {
var line = (try getline(Allocator)) orelse break;
var optional_output = rep(environment, line) catch |err| {
if(err == MalError.KeyError) {
continue;
} else {
return err;
}
};
if(optional_output) |output| {
try stdout_file.write(output);
Allocator.free(output);
Allocator.free(line);
try stdout_file.write("\n");
}
var output = rep_and_print_errors(environment, line) orelse continue;
try stdout_file.write(output);
Allocator.free(output);
Allocator.free(line);
try stdout_file.write("\n");
}
}
45 changes: 28 additions & 17 deletions impls/zig/step7_quote.zig
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ fn EVAL_let(mal_ptr: **MalType, env_ptr: **Env) MalError!void {
optional_node = iterator.next();
key_mal.delete(Allocator);
}

linked_list.destroy(Allocator, &binding_ll, true);
binding_arg.data = MalData{.Nil=undefined};
binding_arg.delete(Allocator);
Expand Down Expand Up @@ -287,8 +287,27 @@ fn rep(environment: *Env, input: [] const u8) MalError!?[] u8 {
return print_input;
}

fn rep_and_print_errors(environment: *Env, input: [] const u8) ?[]u8 {
return rep(environment, input) catch |err| {
switch(err) {
MalError.KeyError => { },
MalError.OutOfBounds => {
warn("Error: out of bounds\n");
},
MalError.ReaderUnmatchedParen => {
warn("Error: expected closing paren, got EOF\n");
},
else => {
warn("Unhandled error\n");
},
}
return null;
};
}


fn lookup(environment: *Env, symbol: []const u8, do_warn: bool) MalError!*MalType {
var mal = environment.get(symbol) catch |err| {
var mal = environment.get(symbol) catch |err| {
if(do_warn) {
const s1 = string_concat(Allocator, "'", symbol) catch return MalError.SystemError;
const s2 = string_concat(Allocator, s1, "' not found") catch return MalError.SystemError;
Expand Down Expand Up @@ -375,7 +394,7 @@ fn make_environment() MalError!*Env {
const eval_mal = try MalType.new_nil(Allocator);
eval_mal.data = MalData{.Fn1 = &eval};
try environment.set("eval", eval_mal);

const def_not_string: [] const u8 =
\\(def! not (fn* (a) (if a false true)))
;
Expand Down Expand Up @@ -436,21 +455,13 @@ pub fn main() !void {
var output = try rep(environment, run_cmd);
return;
}

while(true) {
var line = (try getline(Allocator)) orelse break;
var optional_output = rep(environment, line) catch |err| {
if(err == MalError.KeyError) {
continue;
} else {
return err;
}
};
if(optional_output) |output| {
try stdout_file.write(output);
Allocator.free(output);
Allocator.free(line);
try stdout_file.write("\n");
}
var output = rep_and_print_errors(environment, line) orelse continue;
try stdout_file.write(output);
Allocator.free(output);
Allocator.free(line);
try stdout_file.write("\n");
}
}
10 changes: 5 additions & 5 deletions impls/zig/step8_macros.zig
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ fn macroexpand(mal: *MalType, env: *Env) MalError!*MalType {
first.delete(Allocator);
}
try linked_list.prepend_mal(Allocator, &new_list, macro);
var new_mal = try apply_function(Allocator, new_list);
linked_list.destroy(Allocator, &new_list, false);
var new_mal = try apply_function(Allocator, new_list);
linked_list.destroy(Allocator, &new_list, false);
cur_mal.shallow_destroy(Allocator);
cur_mal = new_mal;
optional_macro = is_macro_call(cur_mal, env);
Expand Down Expand Up @@ -216,7 +216,7 @@ fn EVAL_let(mal_ptr: **MalType, env_ptr: **Env) MalError!void {
optional_node = iterator.next();
key_mal.delete(Allocator);
}

linked_list.destroy(Allocator, &binding_ll, true);
binding_arg.data = MalData{.Nil=undefined};
binding_arg.delete(Allocator);
Expand Down Expand Up @@ -367,7 +367,7 @@ fn rep_and_print_errors(environment: *Env, input: [] const u8) ?[]u8 {


fn lookup(environment: *Env, symbol: []const u8, do_warn: bool) MalError!*MalType {
var mal = environment.get(symbol) catch |err| {
var mal = environment.get(symbol) catch |err| {
if(do_warn) {
const s1 = string_concat(Allocator, "'", symbol) catch return MalError.SystemError;
const s2 = string_concat(Allocator, s1, "' not found") catch return MalError.SystemError;
Expand Down Expand Up @@ -462,7 +462,7 @@ fn make_environment() MalError!*Env {
if(optional_output) |output| {
Allocator.free(output);
}

const load_file_string: [] const u8 =
\\(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) "\nnil)")))))
;
Expand Down
Loading

0 comments on commit a2973ab

Please sign in to comment.