Browse Source

new parenthesized function call syntax

master
Martin Dørum 7 months 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

@@ -4,6 +4,7 @@
#include "../io.h"

enum l2_token_kind {
L2_TOK_OPEN_PAREN_NS,
L2_TOK_OPEN_PAREN,
L2_TOK_CLOSE_PAREN,
L2_TOK_OPEN_BRACE,

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

@@ -16,7 +16,7 @@ extern int l2_trace_depth;
#ifdef __GNUC__
#define l2_trace_scope(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__)
#else
#define l2_trace_scope(name) l2_trace(name)

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

@@ -30,6 +30,8 @@ static void log_token(struct l2_token *tok) {

const char *l2_token_kind_name(enum l2_token_kind kind) {
switch (kind) {
case L2_TOK_OPEN_PAREN_NS:
return "open-paren-no-space";
case L2_TOK_OPEN_PAREN:
return "open-paren";
case L2_TOK_CLOSE_PAREN:
@@ -137,25 +139,27 @@ static int is_ident(int 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 (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) == '#') {
nl = 1;
*nl = 1;
while (read_ch(lexer) != '\n');
} else {
break;
}
}

return nl;
*skipped = 1;
}
}

static int read_integer(struct l2_lexer *lexer, long long *num, long long *base, char **err) {
@@ -464,7 +468,8 @@ static void read_ident(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->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) {
tok->v.flags = L2_TOK_EOL;
@@ -475,7 +480,11 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) {
switch (ch) {
case '(':
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;
break;

@@ -509,7 +518,7 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) {
tok->v.flags = L2_TOK_EOL;
do {
read_ch(lexer);
skip_whitespace(lexer);
skip_whitespace(lexer, &nl, &skipped_whitespace);
} while (peek_ch(lexer) == ';');
break;


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

@@ -258,7 +258,11 @@ static int parse_arg_level_expression_base(
l2_lexer_consume(lexer); // ')'
} else if (l2_token_get_kind(tok) == L2_TOK_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);
l2_lexer_consume(lexer); // ident

@@ -316,6 +320,56 @@ static int parse_arg_level_expression_base(
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(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_scope("arg level expression");
@@ -328,20 +382,36 @@ static int parse_arg_level_expression(
struct l2_token *tok2 = l2_lexer_peek(lexer, 2);
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_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 (
l2_token_get_kind(tok) == L2_TOK_PERIOD &&
l2_token_get_kind(tok2) == L2_TOK_IDENT &&
l2_token_get_kind(tok3) == L2_TOK_EQUALS) {
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);
l2_lexer_consume(lexer); // '.'
l2_lexer_consume(lexer); // ident
@@ -362,7 +432,11 @@ static int parse_arg_level_expression(
l2_token_get_kind(tok) == L2_TOK_PERIOD &&
l2_token_get_kind(tok2) == L2_TOK_IDENT) {
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);
l2_lexer_consume(lexer); // '.'
l2_lexer_consume(lexer); // ident
@@ -403,8 +477,9 @@ static int parse_arg_level_expression(
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));
return -1;
}
@@ -428,56 +503,6 @@ static int parse_arg_level_expression(
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(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_scope("expression");
@@ -488,7 +513,11 @@ static int parse_expression(
l2_token_get_kind(tok) == L2_TOK_IDENT &&
l2_token_get_kind(tok2) == L2_TOK_COLON_EQ) {
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);
l2_lexer_consume(lexer); // ident
l2_lexer_consume(lexer); // :=
@@ -507,7 +536,11 @@ static int parse_expression(
l2_token_get_kind(tok) == L2_TOK_IDENT &&
l2_token_get_kind(tok2) == L2_TOK_EQUALS) {
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);
l2_lexer_consume(lexer); // ident
l2_lexer_consume(lexer); // =
@@ -528,7 +561,7 @@ static int parse_expression(
}

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;
}
}

Loading…
Cancel
Save