zpy

A lisp like language written in hare
Log | Files | Refs

commit 102aa58ebfdc93faff8397c578fbef465877d6ec
parent 2aa6b92667ea64a185d8db290ebc9470adb99374
Author: thing1 <thing1@seacrossedlovers.xyz>
Date:   Tue, 12 May 2026 17:42:33 +0100

updates

Diffstat:
Mzpy/lex/+test.ha | 6++----
Mzpy/parse/+test.ha | 56+++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mzpy/parse/parse.ha | 24+++++-------------------
3 files changed, 60 insertions(+), 26 deletions(-)

diff --git a/zpy/lex/+test.ha b/zpy/lex/+test.ha @@ -8,10 +8,8 @@ fn check(lex: *lexer, expect: [](types | invalid)) void = { let n = next(lex); match (exp) { - case let ty: types => - assert((n as token).ty == ty); - case invalid => - assert(n is error); + case let ty: types => assert((n as token).ty == ty); + case invalid => assert(n is error); }; }; }; diff --git a/zpy/parse/+test.ha b/zpy/parse/+test.ha @@ -2,12 +2,54 @@ use zpy::lex; use memio; use strings; +fn equalNodes(n1: node, n2: node) bool = { + match (n1) { + case let n1: sexpr => + if (n2 is sexpr) { + if ((n2 as sexpr).func == n1.func) { + if (len(n1.args) != len((n2 as sexpr).args)) + return false; + + for (let i = 0z; i < len (n1.args); i+=1) { + if (!equalNodes(*n1.args[i], *(n2 as sexpr).args[i])) + return false; + }; + + return true; + }; + }; + + case let n1: name => + if (n2 is name) + if ((n2 as name) == n1) + return true; + + case let n1: lit => + if (n2 is lit) + if ((n2 as lit) == n1) + return true; + }; + + return false; +}; + @test fn BinaryExpr() void = { let lex = lex::new(&memio::fixed(strings::toutf8("(foo 1 2)"))); - let sexpr = try(lex, [&parseSexpr])! as sexpr; - assert(sexpr.func == "foo"); - assert(len(sexpr.args) == 2); + let s = try(lex, [&parseSexpr])! as sexpr; + + assert(s.func == "foo"); + assert(len(s.args) == 2); + assert(*s.args[0] == 1); + assert(*s.args[1] == 2); + + //if (!equalNodes(s, sexpr{ + // func = "foo", + // args = [ + // &1: *node, + // &2: *node + // ] + //})) abort(); }; @test @@ -41,3 +83,11 @@ fn NestedExpr() void = { assert(sexpr.func == "foo"); assert(len(sexpr.args) == 1); }; + +@test +fn DeeplyNestedExpr() void = { + let lex = lex::new(&memio::fixed(strings::toutf8("(foo (bar (baz (boo 1))) 42)"))); + let sexpr = try(lex, [&parseSexpr])! as sexpr; + assert(sexpr.func == "foo"); + assert(len(sexpr.args) == 2); +}; diff --git a/zpy/parse/parse.ha b/zpy/parse/parse.ha @@ -4,38 +4,24 @@ use strconv; use fmt; use bufio; +// TODO put nodes on the heap, as pointers fuck this all up + export type parserfn = fn(_: *lex::lexer) (node | error); export fn try(l: *lex::lexer, fs: []*parserfn) (node | error) = { let save = io::tell(l.in)!; - for (let i = 0z; i < len(fs); i+=1) { - let f = fs[i]; - + for (let f .. fs) { match (f(l)) { case let n: node => return n; - case let e: error => - io::seek(l.in, save, io::whence::SET)!; - printrest(l); + case let e: error => io::seek(l.in, save, io::whence::SET)!; }; }; return ("reached end of try block", 0); }; -fn printrest(l: *lex::lexer) void = { - let save = io::tell(l.in)!; - for (true) { - match (bufio::read_rune(l.in)!) { - case let r: rune => fmt::print(r)!; - case => break; - }; - }; - fmt::println()!; - io::seek(l.in, save, io::whence::SET)!; -}; - export fn parseSexpr(l: *lex::lexer) (node | error) = { match (want(l, [lex::types::OBRACE])) { case lex::token => yield; @@ -47,7 +33,7 @@ export fn parseSexpr(l: *lex::lexer) (node | error) = { let args: []*node = []; for (true) { - match (try(l, [ &parseName, &parseSexpr, &parseLit])) { + match (try(l, [&parseSexpr, &parseName, &parseLit])) { case let n: node => append(args, &n)!; case let e: error =>