Browse Source

new parenthesized function call syntax

master
Martin Dørum 3 years ago
parent
commit
07d6688baf
4 changed files with 121 additions and 78 deletions
  1. 1
    0
      include/lang2/parse/lex.h
  2. 1
    1
      include/lang2/trace.h
  3. 22
    13
      lib/parse/lex.c
  4. 97
    64
      lib/parse/parse.c

+ 1
- 0
include/lang2/parse/lex.h View File

#include "../io.h" #include "../io.h"


enum l2_token_kind { enum l2_token_kind {
L2_TOK_OPEN_PAREN_NS,
L2_TOK_OPEN_PAREN, L2_TOK_OPEN_PAREN,
L2_TOK_CLOSE_PAREN, L2_TOK_CLOSE_PAREN,
L2_TOK_OPEN_BRACE, L2_TOK_OPEN_BRACE,

+ 1
- 1
include/lang2/trace.h View File

#ifdef __GNUC__ #ifdef __GNUC__
#define l2_trace_scope(name) \ #define l2_trace_scope(name) \
l2_trace_push(name); \ l2_trace_push(name); \
__attribute__((cleanup(l2_trace_cleanup))) int l2_trace_scope
__attribute__((unused,cleanup(l2_trace_cleanup))) int l2_trace_scope
#define l2_trace_func() l2_trace_scope(__func__) #define l2_trace_func() l2_trace_scope(__func__)
#else #else
#define l2_trace_scope(name) l2_trace(name) #define l2_trace_scope(name) l2_trace(name)

+ 22
- 13
lib/parse/lex.c View File



const char *l2_token_kind_name(enum l2_token_kind kind) { const char *l2_token_kind_name(enum l2_token_kind kind) {
switch (kind) { switch (kind) {
case L2_TOK_OPEN_PAREN_NS:
return "open-paren-no-space";
case L2_TOK_OPEN_PAREN: case L2_TOK_OPEN_PAREN:
return "open-paren"; return "open-paren";
case L2_TOK_CLOSE_PAREN: case L2_TOK_CLOSE_PAREN:
ch != ':' && ch != ';'; ch != ':' && ch != ';';
} }


static int skip_whitespace(struct l2_lexer *lexer) {
int nl = 0;
static void skip_whitespace(struct l2_lexer *lexer, int *nl, int *skipped) {
while (1) { while (1) {
while (is_whitespace(peek_ch(lexer))) {
int ch = read_ch(lexer);
if (ch == '\n') {
nl = 1;
}
if (is_whitespace(peek_ch(lexer))) {
*skipped = 1;
do {
int ch = read_ch(lexer);
if (ch == '\n') {
*nl = 1;
}
} while (is_whitespace(peek_ch(lexer)));
} }


if (peek_ch(lexer) == '#') { if (peek_ch(lexer) == '#') {
nl = 1;
*nl = 1;
while (read_ch(lexer) != '\n'); while (read_ch(lexer) != '\n');
} else { } else {
break; break;
} }
}


return nl;
*skipped = 1;
}
} }


static int read_integer(struct l2_lexer *lexer, long long *num, long long *base, char **err) { static int read_integer(struct l2_lexer *lexer, long long *num, long long *base, char **err) {
static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) {
tok->line = lexer->line; tok->line = lexer->line;
tok->ch = lexer->ch; tok->ch = lexer->ch;
int nl = skip_whitespace(lexer);
int nl = 0, skipped_whitespace = 0;
skip_whitespace(lexer, &nl, &skipped_whitespace);


if (nl && lexer->parens == 0) { if (nl && lexer->parens == 0) {
tok->v.flags = L2_TOK_EOL; tok->v.flags = L2_TOK_EOL;
switch (ch) { switch (ch) {
case '(': case '(':
read_ch(lexer); read_ch(lexer);
tok->v.flags = L2_TOK_OPEN_PAREN;
if (skipped_whitespace) {
tok->v.flags = L2_TOK_OPEN_PAREN;
} else {
tok->v.flags =L2_TOK_OPEN_PAREN_NS;
}
lexer->parens += 1; lexer->parens += 1;
break; break;


tok->v.flags = L2_TOK_EOL; tok->v.flags = L2_TOK_EOL;
do { do {
read_ch(lexer); read_ch(lexer);
skip_whitespace(lexer);
skip_whitespace(lexer, &nl, &skipped_whitespace);
} while (peek_ch(lexer) == ';'); } while (peek_ch(lexer) == ';');
break; break;



+ 97
- 64
lib/parse/parse.c View File

l2_lexer_consume(lexer); // ')' l2_lexer_consume(lexer); // ')'
} else if (l2_token_get_kind(tok) == L2_TOK_IDENT) { } else if (l2_token_get_kind(tok) == L2_TOK_IDENT) {
l2_trace_scope("ident"); l2_trace_scope("ident");
l2_trace("ident '%s'", tok->v.str);
if (l2_token_is_small(tok)) {
l2_trace("ident '%s'", tok->v.strbuf);
} else {
l2_trace("ident '%s'", tok->v.str);
}
struct l2_token_value ident = l2_token_extract_val(tok); struct l2_token_value ident = l2_token_extract_val(tok);
l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident


return 0; return 0;
} }


static int parse_func_call_after_base(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err,
size_t infix_start) {
l2_trace_scope("func call after base");

size_t argc = 0;

do {
if (argc >= infix_start && tok_is_infix(l2_lexer_peek(lexer, 1))) {
do {
// We already have one value (the lhs) on the stack,
// so we need to parse the operator, then the rhs

// Operator
if (parse_arg_level_expression(lexer, gen, err) < 0) {
return -1;
}

// RHS
if (parse_arg_level_expression(lexer, gen, err) < 0) {
return -1;
}

l2_gen_func_call_infix(gen);
} while (tok_is_infix(l2_lexer_peek(lexer, 1)));

// If this was the "first argument", this wasn't a function call
// after all, it was just a (series of?) infix calls.
if (argc == 0) {
return 0;
}

// Don't increment argc here, because after an infix, we have
// neither added nor removed an arguemnt, just transformed one
} else {
l2_trace_scope("func call param");
if (parse_arg_level_expression(lexer, gen, err) < 0) {
return -1;
}

argc += 1;
}
} while (!tok_is_end(l2_lexer_peek(lexer, 1)));

// The 'argc' previous expressions were arguments, the one before that was the function
l2_gen_func_call(gen, argc);

return 0;
}

static int parse_arg_level_expression( static int parse_arg_level_expression(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_scope("arg level expression"); l2_trace_scope("arg level expression");
struct l2_token *tok2 = l2_lexer_peek(lexer, 2); struct l2_token *tok2 = l2_lexer_peek(lexer, 2);
struct l2_token *tok3 = l2_lexer_peek(lexer, 3); struct l2_token *tok3 = l2_lexer_peek(lexer, 3);


if (
l2_token_get_kind(tok) == L2_TOK_OPEN_PAREN &&
l2_token_get_kind(tok2) == L2_TOK_CLOSE_PAREN) {
l2_trace_scope("niladic func call");
if (l2_token_get_kind(tok) == L2_TOK_OPEN_PAREN_NS) {
l2_trace_scope("parenthesized func call");
l2_lexer_consume(lexer); // '(' l2_lexer_consume(lexer); // '('
l2_lexer_consume(lexer); // ')'


l2_gen_func_call(gen, 0);
if (l2_token_get_kind(l2_lexer_peek(lexer, 1)) == L2_TOK_CLOSE_PAREN) {
l2_lexer_consume(lexer); // ')'
l2_gen_func_call(gen, 0);
} else {
if (parse_func_call_after_base(lexer, gen, err, 1) < 0) {
return -1;
}

tok = l2_lexer_peek(lexer, 1);
if (l2_token_get_kind(tok) != L2_TOK_CLOSE_PAREN) {
l2_parse_err(err, tok, "Expected ')', got %s",
l2_token_get_name(tok));
return -1;
}
l2_lexer_consume(lexer); // ')'
}
} else if ( } else if (
l2_token_get_kind(tok) == L2_TOK_PERIOD && l2_token_get_kind(tok) == L2_TOK_PERIOD &&
l2_token_get_kind(tok2) == L2_TOK_IDENT && l2_token_get_kind(tok2) == L2_TOK_IDENT &&
l2_token_get_kind(tok3) == L2_TOK_EQUALS) { l2_token_get_kind(tok3) == L2_TOK_EQUALS) {
l2_trace_scope("namespace assign"); l2_trace_scope("namespace assign");
l2_trace("ident '%s'", tok2->v.str);
if (l2_token_is_small(tok2)) {
l2_trace("ident '%s'", tok2->v.strbuf);
} else {
l2_trace("ident '%s'", tok2->v.str);
}
struct l2_token_value ident = l2_token_extract_val(tok2); struct l2_token_value ident = l2_token_extract_val(tok2);
l2_lexer_consume(lexer); // '.' l2_lexer_consume(lexer); // '.'
l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident
l2_token_get_kind(tok) == L2_TOK_PERIOD && l2_token_get_kind(tok) == L2_TOK_PERIOD &&
l2_token_get_kind(tok2) == L2_TOK_IDENT) { l2_token_get_kind(tok2) == L2_TOK_IDENT) {
l2_trace_scope("namespace lookup"); l2_trace_scope("namespace lookup");
l2_trace("ident '%s'", tok2->v.str);
if (l2_token_is_small(tok2)) {
l2_trace("ident '%s'", tok2->v.strbuf);
} else {
l2_trace("ident '%s'", tok2->v.str);
}
struct l2_token_value ident = l2_token_extract_val(tok2); struct l2_token_value ident = l2_token_extract_val(tok2);
l2_lexer_consume(lexer); // '.' l2_lexer_consume(lexer); // '.'
l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident
return -1; return -1;
} }


if (l2_token_get_kind(l2_lexer_peek(lexer, 1)) != L2_TOK_CLOSE_PAREN) {
l2_parse_err(err, tok, "Expected '(', got %s",
tok = l2_lexer_peek(lexer, 1);
if (l2_token_get_kind(tok) != L2_TOK_CLOSE_PAREN) {
l2_parse_err(err, tok, "Expected ')', got %s",
l2_token_get_name(tok)); l2_token_get_name(tok));
return -1; return -1;
} }
return 0; return 0;
} }


static int parse_func_call_after_base(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_scope("func call after base");

size_t argc = 0;

do {
if (tok_is_infix(l2_lexer_peek(lexer, 1))) {
do {
// We already have one value (the lhs) on the stack,
// so we need to parse the operator, then the rhs

// Operator
if (parse_arg_level_expression(lexer, gen, err) < 0) {
return -1;
}

// RHS
if (parse_arg_level_expression(lexer, gen, err) < 0) {
return -1;
}

l2_gen_func_call_infix(gen);
} while (tok_is_infix(l2_lexer_peek(lexer, 1)));

// If this was the "first argument", this wasn't a function call
// after all, it was just a (series of?) infix calls.
if (argc == 0) {
return 0;
}

// Don't increment argc here, because after an infix, we have
// neither added nor removed an arguemnt, just transformed one
} else {
l2_trace_scope("func call param");
if (parse_arg_level_expression(lexer, gen, err) < 0) {
return -1;
}

argc += 1;
}

} while (!tok_is_end(l2_lexer_peek(lexer, 1)));

// The 'argc' previous expressions were arguments, the one before that was the function
l2_gen_func_call(gen, argc);

return 0;
}

static int parse_expression( static int parse_expression(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_scope("expression"); l2_trace_scope("expression");
l2_token_get_kind(tok) == L2_TOK_IDENT && l2_token_get_kind(tok) == L2_TOK_IDENT &&
l2_token_get_kind(tok2) == L2_TOK_COLON_EQ) { l2_token_get_kind(tok2) == L2_TOK_COLON_EQ) {
l2_trace_scope("assign expression"); l2_trace_scope("assign expression");
l2_trace("ident '%s'", tok->v.str);
if (l2_token_is_small(tok)) {
l2_trace("ident '%s'", tok->v.strbuf);
} else {
l2_trace("ident '%s'", tok->v.str);
}
struct l2_token_value ident = l2_token_extract_val(tok); struct l2_token_value ident = l2_token_extract_val(tok);
l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident
l2_lexer_consume(lexer); // := l2_lexer_consume(lexer); // :=
l2_token_get_kind(tok) == L2_TOK_IDENT && l2_token_get_kind(tok) == L2_TOK_IDENT &&
l2_token_get_kind(tok2) == L2_TOK_EQUALS) { l2_token_get_kind(tok2) == L2_TOK_EQUALS) {
l2_trace_scope("replacement assign expression"); l2_trace_scope("replacement assign expression");
l2_trace("ident '%s'", tok->v.str);
if (l2_token_is_small(tok)) {
l2_trace("ident '%s'", tok->v.strbuf);
} else {
l2_trace("ident '%s'", tok->v.str);
}
struct l2_token_value ident = l2_token_extract_val(tok); struct l2_token_value ident = l2_token_extract_val(tok);
l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident
l2_lexer_consume(lexer); // = l2_lexer_consume(lexer); // =
} }


if (!tok_is_end(l2_lexer_peek(lexer, 1))) { if (!tok_is_end(l2_lexer_peek(lexer, 1))) {
if (parse_func_call_after_base(lexer, gen, err) < 0) {
if (parse_func_call_after_base(lexer, gen, err, 0) < 0) {
return -1; return -1;
} }
} }

Loading…
Cancel
Save