commit f00b8af1a53c4a47dba9bb3efcf6a8e6266de371
parent 5c77b21fb50b1d9236add4396182da64df09f7dc
Author: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
Date: Fri, 30 Apr 2021 19:00:50 +0200
hare::{lex,parse}: add &&=, ||= and ^^= operators
Signed-off-by: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
Diffstat:
6 files changed, 150 insertions(+), 56 deletions(-)
diff --git a/hare/lex/+test.ha b/hare/lex/+test.ha
@@ -87,32 +87,23 @@ fn loc(line: uint, col: uint) location = location {
@test fn lex2() void = {
// Ends with = to test =, EOF
- const in = "^ ^^ ^= * *= % %= + += - -= : :: & && &= | || |= = == / /= =";
+ const in = "* *= % %= + += - -= : :: = == / /= =";
const expected: [_]token = [
- (ltok::BXOR, void, loc(1, 1)),
- (ltok::LXOR, void, loc(1, 3)),
- (ltok::BXOREQ, void, loc(1, 6)),
- (ltok::TIMES, void, loc(1, 9)),
- (ltok::TIMESEQ, void, loc(1, 11)),
- (ltok::MODULO, void, loc(1, 14)),
- (ltok::MODEQ, void, loc(1, 16)),
- (ltok::PLUS, void, loc(1, 19)),
- (ltok::PLUSEQ, void, loc(1, 21)),
- (ltok::MINUS, void, loc(1, 24)),
- (ltok::MINUSEQ, void, loc(1, 26)),
- (ltok::COLON, void, loc(1, 29)),
- (ltok::DOUBLE_COLON, void, loc(1, 31)),
- (ltok::BAND, void, loc(1, 34)),
- (ltok::LAND, void, loc(1, 36)),
- (ltok::ANDEQ, void, loc(1, 39)),
- (ltok::BOR, void, loc(1, 42)),
- (ltok::LOR, void, loc(1, 44)),
- (ltok::OREQ, void, loc(1, 47)),
- (ltok::EQUAL, void, loc(1, 50)),
- (ltok::LEQUAL, void, loc(1, 52)),
- (ltok::DIV, void, loc(1, 55)),
- (ltok::DIVEQ, void, loc(1, 57)),
- (ltok::EQUAL, void, loc(1, 60)),
+ (ltok::TIMES, void, loc(1, 1)),
+ (ltok::TIMESEQ, void, loc(1, 3)),
+ (ltok::MODULO, void, loc(1, 6)),
+ (ltok::MODEQ, void, loc(1, 8)),
+ (ltok::PLUS, void, loc(1, 11)),
+ (ltok::PLUSEQ, void, loc(1, 13)),
+ (ltok::MINUS, void, loc(1, 16)),
+ (ltok::MINUSEQ, void, loc(1, 18)),
+ (ltok::COLON, void, loc(1, 21)),
+ (ltok::DOUBLE_COLON, void, loc(1, 23)),
+ (ltok::EQUAL, void, loc(1, 26)),
+ (ltok::LEQUAL, void, loc(1, 28)),
+ (ltok::DIV, void, loc(1, 31)),
+ (ltok::DIVEQ, void, loc(1, 33)),
+ (ltok::EQUAL, void, loc(1, 36)),
];
lextest(in, expected);
};
@@ -134,6 +125,24 @@ fn loc(line: uint, col: uint) location = location {
(ltok::RSHIFT, void, loc(1, 34)),
];
lextest(in, expected);
+
+ const in = "& && &= &&= | || |= ||= ^ ^^ ^= ^^= ^";
+ const expected: [_]token = [
+ (ltok::BAND, void, loc(1, 1)),
+ (ltok::LAND, void, loc(1, 3)),
+ (ltok::BANDEQ, void, loc(1, 6)),
+ (ltok::LANDEQ, void, loc(1, 9)),
+ (ltok::BOR, void, loc(1, 13)),
+ (ltok::LOR, void, loc(1, 15)),
+ (ltok::BOREQ, void, loc(1, 18)),
+ (ltok::LOREQ, void, loc(1, 21)),
+ (ltok::BXOR, void, loc(1, 25)),
+ (ltok::LXOR, void, loc(1, 27)),
+ (ltok::BXOREQ, void, loc(1, 30)),
+ (ltok::LXOREQ, void, loc(1, 33)),
+ (ltok::BXOR, void, loc(1, 37)),
+ ];
+ lextest(in, expected);
};
@test fn lexname() void = {
diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha
@@ -96,8 +96,8 @@ export fn lex(lex: *lexer) (token | error) = {
unget(lex, r);
return lex_rn_str(lex, loc);
},
- '.', '<', '>' => return lex3(lex, loc, r),
- '^', '*', '%', '/', '+', '-', ':', '!', '&', '|', '=' => {
+ '.', '<', '>', '&', '|', '^' => return lex3(lex, loc, r),
+ '*', '%', '/', '+', '-', ':', '!', '=' => {
return lex2(lex, loc, r);
},
'~' => ltok::BNOT,
@@ -524,22 +524,6 @@ fn lex2(lexr: *lexer, loc: location, r: rune) (token | error) = {
},
io::EOF => ltok::LNOT,
},
- '&' => match (n) {
- r: rune => switch (r) {
- '&' => return (ltok::LAND, void, loc),
- '=' => return (ltok::ANDEQ, void, loc),
- * => ltok::BAND,
- },
- io::EOF => ltok::BAND,
- },
- '|' => match (n) {
- r: rune => switch (r) {
- '|' => return (ltok::LOR, void, loc),
- '=' => return (ltok::OREQ, void, loc),
- * => ltok::BOR,
- },
- io::EOF => ltok::BOR,
- },
'=' => match (n) {
r: rune => switch (r) {
'=' => return (ltok::LEQUAL, void, loc),
@@ -560,6 +544,9 @@ fn lex3(lex: *lexer, loc: location, r: rune) (token | error) = {
'.' => (ltok::DOT, void, loc),
'<' => (ltok::LESS, void, loc),
'>' => (ltok::GREATER, void, loc),
+ '&' => (ltok::BAND, void, loc),
+ '|' => (ltok::BOR, void, loc),
+ '^' => (ltok::BXOR, void, loc),
* => abort(), // Invariant
},
r: rune => r,
@@ -568,7 +555,10 @@ fn lex3(lex: *lexer, loc: location, r: rune) (token | error) = {
'.' => lex3dot(lex, loc, n),
'<' => lex3lt(lex, loc, n),
'>' => lex3gt(lex, loc, n),
- * => syntaxerr(loc, "unknown token sequence"),
+ '&' => lex3and(lex, loc, n),
+ '|' => lex3or(lex, loc, n),
+ '^' => lex3xor(lex, loc, n),
+ * => syntaxerr(loc, "unknown token sequence"),
};
};
@@ -649,6 +639,85 @@ fn lex3gt(lex: *lexer, loc: location, n: rune) (token | error) = {
return (tok, void, loc);
};
+fn lex3and(lex: *lexer, loc: location, n: rune) (token | error) = {
+ let tok: ltok = switch (n) {
+ '&' => {
+ let q = match (next(lex)?) {
+ io::EOF => io::EOF,
+ r: rune => r,
+ };
+ let t = match (q) {
+ r: rune => switch (r) {
+ '=' => return (ltok::LANDEQ, void, loc),
+ * => ltok::LAND,
+ },
+ io::EOF => ltok::LAND,
+ };
+ unget(lex, q);
+ t;
+ },
+ '=' => ltok::BANDEQ,
+ * => {
+ unget(lex, n);
+ ltok::BAND;
+ }
+ };
+ return (tok, void, loc);
+};
+
+fn lex3or(lex: *lexer, loc: location, n: rune) (token | error) = {
+ let tok: ltok = switch (n) {
+ '|' => {
+ let q = match (next(lex)?) {
+ io::EOF => io::EOF,
+ r: rune => r,
+ };
+ let t = match (q) {
+ r: rune => switch (r) {
+ '=' => return (ltok::LOREQ, void, loc),
+ * => ltok::LOR,
+ },
+ io::EOF => ltok::LOR,
+ };
+ unget(lex, q);
+ t;
+ },
+ '=' => ltok::BOREQ,
+ * => {
+ unget(lex, n);
+ ltok::BOR;
+ }
+ };
+ return (tok, void, loc);
+};
+
+fn lex3xor(lex: *lexer, loc: location, n: rune) (token | error) = {
+ let tok: ltok = switch (n) {
+ '^' => {
+ let q = match (next(lex)?) {
+ io::EOF => io::EOF,
+ r: rune => r,
+ };
+ let t = match (q) {
+ r: rune => switch (r) {
+ '=' => return (ltok::LXOREQ, void, loc),
+ * => ltok::LXOR,
+ },
+ io::EOF => ltok::LXOR,
+ };
+ unget(lex, q);
+ t;
+ },
+ '=' => ltok::BXOREQ,
+ * => {
+ unget(lex, n);
+ ltok::BXOR;
+ }
+ };
+ return (tok, void, loc);
+};
+
+
// Unlex a single token. The next call to [[lex]] will return this token. Only one
// unlex is supported at a time; you must call [[lex]] before calling [[unlex]]
// again.
diff --git a/hare/lex/token.ha b/hare/lex/token.ha
@@ -68,10 +68,11 @@ export type ltok = enum uint {
LAST_KEYWORD = VOID,
// Operators
- ANDEQ,
BAND,
+ BANDEQ,
BNOT,
BOR,
+ BOREQ,
BXOR,
BXOREQ,
CASE,
@@ -86,6 +87,7 @@ export type ltok = enum uint {
GREATER,
GREATEREQ,
LAND,
+ LANDEQ,
LBRACE,
LBRACKET,
LEQUAL,
@@ -93,17 +95,18 @@ export type ltok = enum uint {
LESSEQ,
LNOT,
LOR,
+ LOREQ,
LPAREN,
LSHIFT,
LSHIFTEQ,
LXOR,
+ LXOREQ,
MINUS,
MINUSEQ,
MINUSMINUS,
MODEQ,
MODULO,
NEQUAL,
- OREQ,
PLUS,
PLUSEQ,
PLUSPLUS,
@@ -205,12 +208,13 @@ const bmap: [_]str = [
"union",
"use",
"void",
- "&=",
"&",
- "^",
- "^=",
+ "&=",
"~",
"|",
+ "|=",
+ "^",
+ "^=",
"=>",
":",
",",
@@ -223,6 +227,7 @@ const bmap: [_]str = [
">",
">=",
"&&",
+ "&&=",
"{",
"[",
"==",
@@ -230,21 +235,22 @@ const bmap: [_]str = [
"<=",
"!",
"||",
+ "||=",
"(",
"<<",
"<<=",
"^^",
+ "^^=",
"-",
"-=",
"--",
- "?",
"%=",
"%",
"!=",
- "|=",
"+",
"+=",
"++",
+ "?",
"}",
"]",
")",
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -14,6 +14,9 @@
x ^= 10;
x >>= 10;
x <<= 10;
+ x &&= true;
+ x ||= true;
+ x ^^= true;
};
");
};
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -12,9 +12,10 @@ export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
// All assignment-op tokens
const atoks: []ltok = [
- ltok::EQUAL, ltok::ANDEQ, ltok::BXOREQ, ltok::DIVEQ,
- ltok::LSHIFTEQ, ltok::MINUSEQ, ltok::MODEQ, ltok::OREQ,
- ltok::PLUSEQ, ltok::RSHIFTEQ, ltok::TIMESEQ,
+ ltok::EQUAL, ltok::BANDEQ, ltok::BOREQ, ltok::BXOREQ,
+ ltok::DIVEQ, ltok::LANDEQ, ltok::LOREQ, ltok::LXOREQ,
+ ltok::LSHIFTEQ, ltok::MINUSEQ, ltok::MODEQ, ltok::PLUSEQ,
+ ltok::RSHIFTEQ, ltok::TIMESEQ,
];
const expr: ast::expr = if (indirect) {
@@ -60,13 +61,16 @@ export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
return ast::assign_expr {
op = switch (tok.0) {
ltok::EQUAL => void,
- ltok::ANDEQ => ast::binarithm_op::BAND,
+ ltok::BANDEQ => ast::binarithm_op::BAND,
+ ltok::BOREQ => ast::binarithm_op::BOR,
ltok::BXOREQ => ast::binarithm_op::BXOR,
ltok::DIVEQ => ast::binarithm_op::DIV,
+ ltok::LANDEQ => ast::binarithm_op::LAND,
+ ltok::LOREQ => ast::binarithm_op::LOR,
ltok::LSHIFTEQ => ast::binarithm_op::LSHIFT,
+ ltok::LXOREQ => ast::binarithm_op::LXOR,
ltok::MINUSEQ => ast::binarithm_op::MINUS,
ltok::MODEQ => ast::binarithm_op::MODULO,
- ltok::OREQ => ast::binarithm_op::BOR,
ltok::PLUSEQ => ast::binarithm_op::PLUS,
ltok::RSHIFTEQ => ast::binarithm_op::RSHIFT,
ltok::TIMESEQ => ast::binarithm_op::TIMES,
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -103,7 +103,9 @@ export fn expr(
void => "=",
op: ast::binarithm_op => switch (op) {
ast::binarithm_op::BAND => "&=",
+ ast::binarithm_op::LAND => "&&=",
ast::binarithm_op::BOR => "|=",
+ ast::binarithm_op::LOR => "||=",
ast::binarithm_op::DIV => "/=",
ast::binarithm_op::LSHIFT => "<<=",
ast::binarithm_op::MINUS => "-=",
@@ -112,6 +114,7 @@ export fn expr(
ast::binarithm_op::RSHIFT => ">>=",
ast::binarithm_op::TIMES => "*=",
ast::binarithm_op::BXOR => "^=",
+ ast::binarithm_op::LXOR => "^^=",
* => abort(),
},
};