hare

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

commit 7ae2b8126ebb7af67bbaddbe852f2b6fdc5c1fbe
parent 434b0543c55064256c267256bc455f5217fee897
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue,  6 Apr 2021 12:15:15 -0400

hare::parse: skeleton for postfix-expression

Diffstat:
Mhare/lex/lex.ha | 1+
Mhare/lex/token.ha | 12++++++++----
Mhare/parse/expr.ha | 42++++++++++++++++++++++++++++++++++++++++--
Mhare/parse/util.ha | 26++++++++++++++++++++++++++
4 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha @@ -89,6 +89,7 @@ export fn lex(lex: *lexer) ((token, location) | io::EOF | error) = { ']' => btoken::RBRACKET, ')' => btoken::RPAREN, ';' => btoken::SEMICOLON, + '?' => btoken::QUESTION, }; return (tok, loc); }; diff --git a/hare/lex/token.ha b/hare/lex/token.ha @@ -24,6 +24,7 @@ export type btoken = enum { CONTINUE, DEF, DEFER, + DELETE, ELSE, ENUM, EXPORT, @@ -71,6 +72,8 @@ export type btoken = enum { BAND, BNOT, BOR, + BXOR, + BXOREQ, CASE, COLON, COMMA, @@ -104,6 +107,7 @@ export type btoken = enum { PLUS, PLUSEQ, PLUSPLUS, + QUESTION, RBRACE, RBRACKET, RPAREN, @@ -113,8 +117,6 @@ export type btoken = enum { SLICE, TIMES, TIMESEQ, - BXOR, - BXOREQ, }; const bmap: [_]str = [ @@ -138,6 +140,7 @@ const bmap: [_]str = [ "continue", "def", "defer", + "delete", "else", "enum", "export", @@ -180,6 +183,8 @@ const bmap: [_]str = [ "void", "&=", "&", + "^", + "^=", "~", "|", "=>", @@ -208,6 +213,7 @@ const bmap: [_]str = [ "-", "-=", "--", + "?", "%=", "%", "!=", @@ -224,8 +230,6 @@ const bmap: [_]str = [ "..", "*", "*=", - "^", - "^=", ]; // A loop label, such as ':example' diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha @@ -72,16 +72,54 @@ fn objsel(lexer: *lex::lexer) (ast::expr | error) = { abort(); // TODO }; -fn postfix(lexer: *lex::lexer) (ast::expr | error) = { +fn plain_expression(lexer: *lex::lexer) (ast::expr | error) = { want_btoken(lexer, btoken::VOID)?; // TODO return void; }; +fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = { + // Built-ins (XXX: these should probably be moved in the Hare grammar) + match (peek_btoken(lexer, + btoken::ALLOC, btoken::APPEND, btoken::FREE, + btoken::DELETE, btoken::ABORT, btoken::ASSERT, + btoken::STATIC, btoken::SIZE, btoken::LEN, + btoken::OFFSET)?) { + tok: btoken => { + if (lvalue is ast::expr) { + return syntaxerr(mkloc(lexer), + "Unexpected {}, was expecting '(', '.', or '['", + lex::tokstr(tok)); + }; + abort(); // TODO: Delegate as appropriate + }, + void => void, + }; + + let lvalue = match (lvalue) { + void => plain_expression(lexer)?, + ex: ast::expr => ex, + }; + + match (try_btoken(lexer, btoken::LPAREN, btoken::DOT, btoken::LBRACKET, + btoken::QUESTION)) { + tok: btoken => switch (tok) { + btoken::LPAREN => abort(), // TODO: Calls + btoken::DOT => abort(), // TODO: Field access + btoken::LBRACKET => abort(), // TODO: Indexing + btoken::QUESTION => abort(), // TODO: Propagation + * => abort(), + }, + void => return lvalue, + }; + + return postfix(lexer, lvalue); +}; + fn unarithm(lexer: *lex::lexer) (ast::expr | error) = { const tok = match (try_btoken(lexer, btoken::PLUS, btoken::MINUS, btoken::BNOT, btoken::LNOT, btoken::TIMES, btoken::BAND)) { - void => return postfix(lexer), + void => return postfix(lexer, void), tok: btoken => tok, }; const op = switch (tok) { diff --git a/hare/parse/util.ha b/hare/parse/util.ha @@ -93,6 +93,32 @@ fn try_btoken( lex::unlex(lexer, tuple); }; +// Looks for a matching btoken from the lexer, unlexes the token, and returns +// it; or void if it was not a btoken. +fn peek_btoken( + lexer: *lex::lexer, + want: lex::btoken... +) (lex::btoken | error | void) = { + let tok = lex::lex(lexer); + let tuple = match (tok?) { + io::EOF => return, + t: (lex::token, lex::location) => { + match (t.0) { + b: lex::btoken => + for (let i = 0z; i < len(want); i += 1) { + if (b == want[i]) { + lex::unlex(lexer, t); + return b; + }; + }, + * => void, + }; + t; + }, + }; + lex::unlex(lexer, tuple); +}; + // Identical to [lex::lex], but considers io::EOF a syntax error. fn mustlex(lexer: *lex::lexer) ((lex::token, lex::location) | error) = { return match (lex::lex(lexer)) {