hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mhare/lex/+test.ha | 59++++++++++++++++++++++++++++++++++-------------------------
Mhare/lex/lex.ha | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mhare/lex/token.ha | 20+++++++++++++-------
Mhare/parse/+test/expr.ha | 3+++
Mhare/parse/expr.ha | 14+++++++++-----
Mhare/unparse/expr.ha | 3+++
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(), }, };