Compare commits
No commits in common. "1e5ed474976e2f55ca54782b1c789bd841e4a2ef" and "b76792813048519e35d78d014a6d597b821ad08d" have entirely different histories.
1e5ed47497
...
b767928130
3 changed files with 10 additions and 75 deletions
|
@ -13,8 +13,6 @@ use io;
|
||||||
mkword("def")]),
|
mkword("def")]),
|
||||||
(`#t #f`, [true, false]),
|
(`#t #f`, [true, false]),
|
||||||
(`#\a #\space #\nul`, ['a', ' ', '\0']),
|
(`#\a #\space #\nul`, ['a', ' ', '\0']),
|
||||||
(`"\x0a;" "\x2014;" "\x2f9f4;"`, ["\n", "—", "嶲"]),
|
|
||||||
(`#\x #\x0a; #\x2014; #\x2f9f4;`, ['x', '\n', '—', '嶲']),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let i = 0z; i < len(cases); i += 1) {
|
for (let i = 0z; i < len(cases); i += 1) {
|
||||||
|
@ -25,16 +23,7 @@ use io;
|
||||||
|
|
||||||
for (let j = 0z; j < len(cases[i].1); j += 1) {
|
for (let j = 0z; j < len(cases[i].1); j += 1) {
|
||||||
const want = cases[i].1[j];
|
const want = cases[i].1[j];
|
||||||
const have = match (lex(&lexer)) {
|
const have = lex(&lexer)! as token;
|
||||||
case let tok: token =>
|
|
||||||
yield tok;
|
|
||||||
case io::EOF =>
|
|
||||||
assert(false, "reached EOF");
|
|
||||||
return;
|
|
||||||
case let err: error =>
|
|
||||||
assert(false, strerror(err));
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!tokeq(want, have)) {
|
if (!tokeq(want, have)) {
|
||||||
fmt::printfln("Case {}: {}", i, cases[i].0)!;
|
fmt::printfln("Case {}: {}", i, cases[i].0)!;
|
||||||
|
|
54
parse/lex.ha
54
parse/lex.ha
|
@ -246,9 +246,6 @@ fn scanchar(lex: *lexer) (rune | error) = {
|
||||||
unget(lex, rnn);
|
unget(lex, rnn);
|
||||||
if (isspace(rnn)) {
|
if (isspace(rnn)) {
|
||||||
return rn;
|
return rn;
|
||||||
} else {
|
|
||||||
if (rn == 'x') {
|
|
||||||
return scanescape2(lex);
|
|
||||||
} else {
|
} else {
|
||||||
memio::appendrune(&namebuf, rn)!;
|
memio::appendrune(&namebuf, rn)!;
|
||||||
memio::concat(&namebuf, scanword(lex)?)!;
|
memio::concat(&namebuf, scanword(lex)?)!;
|
||||||
|
@ -260,7 +257,6 @@ fn scanchar(lex: *lexer) (rune | error) = {
|
||||||
};
|
};
|
||||||
return lex.loc: invalid;
|
return lex.loc: invalid;
|
||||||
};
|
};
|
||||||
};
|
|
||||||
case io::EOF =>
|
case io::EOF =>
|
||||||
return rn;
|
return rn;
|
||||||
};
|
};
|
||||||
|
@ -286,56 +282,6 @@ fn scanescape(lex: *lexer) (rune | error) = {
|
||||||
case 'v' => return '\v';
|
case 'v' => return '\v';
|
||||||
case '\\' => return '\\';
|
case '\\' => return '\\';
|
||||||
case '"' => return '"';
|
case '"' => return '"';
|
||||||
case 'x' => return scanescape2(lex)?;
|
|
||||||
case =>
|
|
||||||
return lex.loc: invalid;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
fn scanescape2(lex: *lexer) (rune | error) = {
|
|
||||||
// This handles the `\xhh...;` family of escapes.
|
|
||||||
// It's on a separate function since both [[scanescape]] and
|
|
||||||
// [[scanchar]] make use of it. Much like how [[scanescape]] assumes
|
|
||||||
// that the backslash has already been consumed, this one assumes that
|
|
||||||
// the leading character has been consumed prior to entering this
|
|
||||||
// function.
|
|
||||||
|
|
||||||
const rn = match (nextrune(lex)?) {
|
|
||||||
case let rn: rune =>
|
|
||||||
yield rn;
|
|
||||||
case io::EOF =>
|
|
||||||
return ("escape sequence", lex.loc.0, lex.loc.1): unterminated;
|
|
||||||
};
|
|
||||||
|
|
||||||
const buf: [6]u8 = [0...];
|
|
||||||
let buf = memio::fixed(buf);
|
|
||||||
memio::appendrune(&buf, rn)!;
|
|
||||||
|
|
||||||
let count = 1z;
|
|
||||||
for (true) {
|
|
||||||
const rn = match (nextrune(lex)?) {
|
|
||||||
case let rn: rune =>
|
|
||||||
yield rn;
|
|
||||||
case io::EOF =>
|
|
||||||
return ("escape sequence", lex.loc.0, lex.loc.1): unterminated;
|
|
||||||
};
|
|
||||||
|
|
||||||
count += 1;
|
|
||||||
|
|
||||||
if (count > 6) {
|
|
||||||
return lex.loc: invalid;
|
|
||||||
} else if (rn == ';') {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
memio::appendrune(&buf, rn)!;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const buf = memio::string(&buf)!;
|
|
||||||
|
|
||||||
return match (strconv::stou32(buf, strconv::base::HEX)) {
|
|
||||||
case let codepoint: u32 =>
|
|
||||||
return codepoint: rune;
|
|
||||||
case =>
|
case =>
|
||||||
return lex.loc: invalid;
|
return lex.loc: invalid;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,10 +22,10 @@ export fn strerror(err: error) const str = {
|
||||||
match (err) {
|
match (err) {
|
||||||
case let err: invalid =>
|
case let err: invalid =>
|
||||||
return fmt::bsprintf(buf,
|
return fmt::bsprintf(buf,
|
||||||
"Invalid token found at {}:{}", err.0, err.1);
|
"{}:{}: Invalid token found", err.0, err.1);
|
||||||
case let err: unterminated =>
|
case let err: unterminated =>
|
||||||
return fmt::bsprintf(buf,
|
return fmt::bsprintf(buf,
|
||||||
"Unterminated {} found at {}:{}", err.0, err.1, err.2);
|
"{}:{}: Unterminated {} found", err.1, err.2, err.0);
|
||||||
case let err: io::error =>
|
case let err: io::error =>
|
||||||
return io::strerror(err);
|
return io::strerror(err);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue