summaryrefslogtreecommitdiff
path: root/internal/parser/parser.ha
diff options
context:
space:
mode:
authorJulian Hurst <ark@mansus.space>2026-03-28 22:54:01 +0100
committerJulian Hurst <ark@mansus.space>2026-03-28 22:54:01 +0100
commit85ae695db10555d4890556c2abac6c18eb4c2182 (patch)
tree9b5bd87fe8a465b4a2dbe28029829c6284c09969 /internal/parser/parser.ha
parent474c14c92de165516f4302685e3fa8acc3a64f45 (diff)
downloadrabbitscript-85ae695db10555d4890556c2abac6c18eb4c2182.tar.gz
Handle EOF better
Diffstat (limited to 'internal/parser/parser.ha')
-rw-r--r--internal/parser/parser.ha96
1 files changed, 73 insertions, 23 deletions
diff --git a/internal/parser/parser.ha b/internal/parser/parser.ha
index 39b9abc..55b143e 100644
--- a/internal/parser/parser.ha
+++ b/internal/parser/parser.ha
@@ -69,6 +69,8 @@ export type parser = struct {
state: tokentype,
unreadbuf: [2]rune,
unreadcount: size,
+ currentline: size,
+ end: bool,
};
type validrunecondfn = *fn(c: rune) bool;
@@ -105,7 +107,16 @@ fn read_rune(p: *parser) (rune | io::EOF | error) = {
p.unreadcount -= 1;
return p.unreadbuf[p.unreadcount];
} else {
- return bufio::read_rune(p.h)?;
+ return match (bufio::read_rune(p.h)?) {
+ case let r: rune =>
+ if (r == '\n') {
+ p.currentline += 1;
+ };
+ yield r;
+ case io::EOF =>
+ p.end = true;
+ yield io::EOF;
+ };
};
};
@@ -124,13 +135,15 @@ fn parsetil(
til: (rune | []rune),
cond: (void | validrunecond),
runecount: size,
- linenb: size = 0,
)
-(str | error) = {
+(str | io::EOF | error) = {
let m = memio::dynamic();
defer io::close(&m)!;
return for (let r => read_rune(p)?) {
+ if (r == '\n') {
+ continue;
+ };
runecount += 1;
const ismatch = match (til) {
case let ru: rune =>
@@ -150,15 +163,18 @@ fn parsetil(
if (c.f(r)) {
memio::appendrune(&m, r)?;
} else {
- break (runecount, linenb, c.err): error;
+ break (runecount, p.currentline, c.err): error;
};
};
} else {
- return (runecount, linenb, "Syntax error: variable not assigned or used"): error;
+ if (runecount == 0) {
+ return io::EOF;
+ };
+ return (runecount, p.currentline, "Syntax error: variable not assigned or used"): error;
};
};
-fn parsevarname(p: *parser, runecount: size, linenb: size = 0) (varname | error) = {
+fn parsevarname(p: *parser, runecount: size) (varname | error) = {
let m = memio::dynamic();
defer io::close(&m)!;
@@ -172,14 +188,14 @@ fn parsevarname(p: *parser, runecount: size, linenb: size = 0) (varname | error)
if (ascii::isalnum(r)) {
memio::appendrune(&m, r)?;
} else {
- break (runecount, linenb, "Character is not alphanumeric"): error;
+ break (runecount, p.currentline, "Character is not alphanumeric"): error;
};
} else {
- return (runecount, linenb, "Syntax error: variable not assigned or used"): error;
+ return (runecount, p.currentline, "Syntax error: variable not assigned or used"): error;
};
};
-fn parsearglist(p: *parser, runecount: size, linenb: size = 0) (arglist | error) = {
+fn parsearglist(p: *parser, runecount: size) (arglist | error) = {
static let buf: [256]u8 = @undefined;
let arglist: arglist = [];
@@ -190,11 +206,23 @@ fn parsearglist(p: *parser, runecount: size, linenb: size = 0) (arglist | error)
switch (r) {
case '"' =>
let arg = parsetil(p, '"', void, 0z)?;
+ let arg = match (arg) {
+ case io::EOF =>
+ return (runecount, p.currentline, "Unexpected EOF"): error;
+ case let a: str =>
+ yield a;
+ };
// reread unread "
read_rune(p)?;
append(arglist, arg)?;
case '\'' =>
let arg = parsetil(p, '\'', void, 0z)?;
+ let arg = match (arg) {
+ case io::EOF =>
+ return (runecount, p.currentline, "Unexpected EOF"): error;
+ case let a: str =>
+ yield a;
+ };
// reread unread '
read_rune(p)?;
append(arglist, arg)?;
@@ -203,13 +231,13 @@ fn parsearglist(p: *parser, runecount: size, linenb: size = 0) (arglist | error)
case ')' =>
break;
case =>
- return (runecount, linenb, "Argument literals must be wrapped with \" or '"): error;
+ return (runecount, p.currentline, "Argument literals must be wrapped with \" or '"): error;
};
};
return arglist;
};
-fn parseoperation(p: *parser, runecount: size, linenb: size = 0) (operation | error) = {
+fn parseoperation(p: *parser, runecount: size) (operation | error) = {
static let buf: [256]u8 = @undefined;
let stack: []argument = [];
@@ -258,7 +286,7 @@ fn parseoperation(p: *parser, runecount: size, linenb: size = 0) (operation | er
break;
case =>
const msg = fmt::bsprintf(buf, "Unexpected char '{}'", r)?;
- return (runecount, linenb, msg): error;
+ return (runecount, p.currentline, msg): error;
};
};
};
@@ -290,7 +318,12 @@ export type ast = struct {
children: []ast,
};
-export fn parse(p: *parser, linenb: size = 0) (ast | error) = {
+export fn parse(p: *parser) (ast | done | error) = {
+ if (p.end) {
+ fmt::errorln("newdone")!;
+ return done;
+ };
+
let stop = false;
//let t = parsetoken(p, linenb);
@@ -300,17 +333,28 @@ export fn parse(p: *parser, linenb: size = 0) (ast | error) = {
let root: ast = @undefined;
for (!stop) {
- let t = parsetoken(p, linenb)?;
+ let t = parsetoken(p)?;
match (t) {
- case varname =>
+ case io::EOF =>
+ return done;
+ case let t: varname =>
let node: ast = ast {
value = t,
children = [],
};
append(tree, node)?;
- case (assign | finvoke) =>
+ case let t: finvoke =>
+ root.value = t;
+ case let t: assign =>
root.value = t;
- case (operation | arglist) =>
+ case let t: operation =>
+ let node: ast = ast {
+ value = t,
+ children = [],
+ };
+ append(tree, node)?;
+ stop = true;
+ case let t: arglist =>
let node: ast = ast {
value = t,
children = [],
@@ -325,7 +369,7 @@ export fn parse(p: *parser, linenb: size = 0) (ast | error) = {
fn isalnum(c: rune) bool = ascii::isalnum(c);
-export fn parsetoken(p: *parser, linenb: size = 0) (token | error) = {
+export fn parsetoken(p: *parser) (token | io::EOF | error) = {
static let buf: [256]u8 = @undefined;
let runecount = 0z;
@@ -338,8 +382,13 @@ export fn parsetoken(p: *parser, linenb: size = 0) (token | error) = {
err = "Character is not alphanumeric",
};
let t = parsetil(p, ['=', '('], cond, 0z)?;
- p.state = tokentype::VARNAME;
- yield t;
+ yield match (t) {
+ case io::EOF =>
+ return io::EOF;
+ case let t: str =>
+ p.state = tokentype::VARNAME;
+ yield t;
+ };
case tokentype::VARNAME =>
// look for ASSIGN
let r = read_rune(p)?;
@@ -353,10 +402,10 @@ export fn parsetoken(p: *parser, linenb: size = 0) (token | error) = {
yield '(': finvoke;
} else {
const msg = fmt::bsprintf(buf, "Missing '=' or '(', found '{}' instead", r)?;
- yield (runecount, linenb, msg): error;
+ yield (runecount, p.currentline, msg): error;
};
case io::EOF =>
- yield (runecount, linenb, "Unexpected EOF"): error;
+ yield (runecount, p.currentline, "Unexpected EOF"): error;
};
case tokentype::FINVOKE =>
// look for FINVOKE
@@ -365,11 +414,12 @@ export fn parsetoken(p: *parser, linenb: size = 0) (token | error) = {
yield t;
case tokentype::ASSIGN =>
// look for OPERATION
+ fmt::errorln("parseoperation")!;
let t = parseoperation(p, 0z)?;
p.state = tokentype::START;
yield t;
case =>
- yield (runecount, linenb, "Not implemented"): error;
+ yield (runecount, p.currentline, "Not implemented"): error;
};
//return for (let r => read_rune(p)?) {