commit 021fff570a17e7ccde8ee55a5ec063c727b3dcc9
parent 810193db9cbb6a84b757fc26aa526eac1c151b58
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 19 Feb 2021 16:32:22 -0500
hare::lex: implement string literals
TODO: write a test for this. Would do it now but I am kind of tired
Diffstat:
2 files changed, 50 insertions(+), 27 deletions(-)
diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha
@@ -69,7 +69,7 @@ export fn lex(lex: *lexer) ((token, location) | io::EOF | error) = {
* => return syntaxerr(loc, "invalid character"),
'"', '\'' => {
unget(lex, r);
- return lex_string(lex, loc);
+ return lex_rn_str(lex, loc);
},
'.', '<', '>' => return lex3(lex, loc, r),
'^', '*', '%', '/', '+', '-', ':', '!', '&', '|', '=' => {
@@ -107,13 +107,6 @@ fn lex_rune(lex: *lexer, loc: location) (rune | error) = {
r: rune => r,
};
if (r != '\\') {
- match (next(lex)) {
- io::EOF => return syntaxerr(loc,
- "unexpected EOF scanning rune, expected \"\'\""),
- err: io::error => return err,
- r: rune => if (r != '\'')
- return syntaxerr(loc, "expected \"\'\" after rune"),
- };
return r;
};
r = match (next(lex)) {
@@ -137,13 +130,6 @@ fn lex_rune(lex: *lexer, loc: location) (rune | error) = {
'x' => abort(), // TODO
'u' => abort(), // TODO
};
- match (next(lex)) {
- io::EOF => return syntaxerr(loc,
- "unexpected EOF scanning escape sequence, expected \"\'\""),
- err: io::error => return err,
- r: rune => if (r != '\'') return syntaxerr(loc,
- "expected \"\'\" after escape sequence"),
- };
return r;
};
@@ -151,24 +137,59 @@ fn lex_string(
lex: *lexer,
loc: location,
) ((token, location) | io::EOF | error) = {
+ // TODO: test me
+ let chars: []u8 = [];
+ for (true) match (next(lex)) {
+ err: io::error => return err,
+ io::EOF => return syntaxerr(loc, "unexpected EOF scanning string literal"),
+ r: rune =>
+ if (r == '"') break
+ else {
+ unget(lex, r);
+ r = match (lex_rune(lex, loc)) {
+ err: error => return err,
+ r: rune => r,
+ };
+ append(chars, ...utf8::encode_rune(r));
+ },
+ };
+ return (literal {
+ storage = literal_type::STR,
+ string = strings::from_utf8(chars),
+ }: token, loc);
+};
+
+fn lex_rn_str(
+ lex: *lexer,
+ loc: location,
+) ((token, location) | io::EOF | error) = {
let r = match (next(lex)) {
r: rune => r,
(io::EOF | io::error) => abort(),
};
- return switch (r) {
- '\'' => match (lex_rune(lex, loc)) {
- err: error => err,
- r: rune => (literal {
- storage = literal_type::RUNE,
- _rune = r,
- }: token, loc),
- },
- '\"' => {
- let chars: []u8 = [];
- abort(); // TODO
- },
+ switch (r) {
+ '\"' => return lex_string(lex, loc),
+ '\'' => void,
* => abort(), // Invariant
};
+
+ // Rune literal
+ let ret = match (lex_rune(lex, loc)) {
+ err: error => return err,
+ r: rune => (literal {
+ storage = literal_type::RUNE,
+ _rune = r,
+ }: token, loc),
+ };
+ match (next(lex)) {
+ err: io::error =>
+ return err,
+ io::EOF =>
+ return syntaxerr(loc, "unexpected EOF"),
+ n: rune => if (n != '\'')
+ return syntaxerr(loc, "expected \"\'\""),
+ };
+ return ret;
};
fn lex_name(
diff --git a/hare/lex/token.ha b/hare/lex/token.ha
@@ -252,6 +252,7 @@ export type literal_type = enum {
F64,
FCONST,
RUNE,
+ STR,
};
// A token for a literal value, such as '1337u32'
@@ -283,6 +284,7 @@ export fn tokstr(tok: token) const str = {
n: name => n: str,
l: literal => switch (l.storage) {
literal_type::RUNE => "rune",
+ literal_type::STR => "string",
* => abort(), // TODO
},
* => abort(), // TODO