Skip to content

Commit

Permalink
feat(expr): support loop syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
Water-Melon committed Mar 22, 2024
1 parent 470851e commit 7ddf1c6
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 0 deletions.
11 changes: 11 additions & 0 deletions docs/book/cn/expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ else
else
fi
fi
-- loop
loop condition do
aaa
func(func2())
if a then
bbb
else
ccc
fi
end
```


Expand Down
11 changes: 11 additions & 0 deletions docs/book/en/expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ else
else
fi
fi
-- loop
loop condition do
aaa
func(func2())
if a then
bbb
else
ccc
fi
end
```


Expand Down
135 changes: 135 additions & 0 deletions src/mln_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ static mln_string_t keywords[] = {
mln_string("then"),
mln_string("else"),
mln_string("fi"),
mln_string("loop"),
mln_string("do"),
mln_string("end"),
mln_string(NULL)
};

Expand All @@ -27,6 +30,9 @@ MLN_DEFINE_TOKEN_TYPE_AND_STRUCT(static, \
EXPR_TK_THEN, \
EXPR_TK_ELSE, \
EXPR_TK_FI, \
EXPR_TK_LOOP, \
EXPR_TK_DO, \
EXPR_TK_END, \
EXPR_TK_STRING);
MLN_DEFINE_TOKEN(static, \
mln_expr, \
Expand All @@ -38,10 +44,15 @@ MLN_DEFINE_TOKEN(static, \
{EXPR_TK_THEN, "EXPR_TK_THEN"}, \
{EXPR_TK_ELSE, "EXPR_TK_ELSE"}, \
{EXPR_TK_FI, "EXPR_TK_FI"}, \
{EXPR_TK_LOOP, "EXPR_TK_LOOP"}, \
{EXPR_TK_DO, "EXPR_TK_DO"}, \
{EXPR_TK_END, "EXPR_TK_END"}, \
{EXPR_TK_STRING, "EXPR_TK_STRING"});

static inline int
mln_expr_parse_if(mln_lex_t *lex, mln_expr_cb_t cb, void *data, mln_expr_val_t *ret, int *eof, mln_expr_struct_t **next);
static inline int
mln_expr_parse_loop(mln_lex_t *lex, mln_expr_cb_t cb, void *data, mln_expr_val_t *ret, int *eof, mln_expr_struct_t **next);

MLN_FUNC(static inline, int, mln_get_char, (mln_lex_t *lex, char c), (lex, c), {
if (c == '\\') {
Expand Down Expand Up @@ -338,6 +349,10 @@ MLN_FUNC(static inline, int, mln_expr_parse, \
mln_expr_free(name);
return mln_expr_parse_if(lex, cb, data, ret, eof, next);
}
if (type == EXPR_TK_LOOP) {
mln_expr_free(name);
return mln_expr_parse_loop(lex, cb, data, ret, eof, next);
}
if (type != EXPR_TK_ID) {
rc = mln_expr_val_init(ret, name);
mln_expr_free(name);
Expand Down Expand Up @@ -572,6 +587,126 @@ MLN_FUNC(static inline, int, mln_expr_parse_if, \
return MLN_EXPR_RET_OK;
})

MLN_FUNC(static inline, int, mln_expr_parse_loop, \
(mln_lex_t *lex, mln_expr_cb_t cb, void *data, mln_expr_val_t *ret, int *eof, mln_expr_struct_t **next), \
(lex, cb, data, ret, eof, next), \
{
enum mln_expr_enum type;
int rc, is_true = 1, count = 0;
mln_expr_struct_t *tk;
mln_expr_val_t v;
mln_lex_off_t off = mln_lex_snapshot_record(lex);

begin:
v.type = mln_expr_type_null;
if ((rc = mln_expr_parse(lex, cb, data, &v, eof, next)) != MLN_EXPR_RET_OK) {
mln_expr_val_destroy(&v);
return rc;
}
if (*eof) {
mln_expr_val_destroy(&v);
return MLN_EXPR_RET_ERR;
}

switch (v.type) {
case mln_expr_type_null:
is_true = 0;
break;
case mln_expr_type_bool:
is_true = v.data.b;
break;
case mln_expr_type_int:
is_true = v.data.i? 1: 0;
break;
case mln_expr_type_real:
is_true = v.data.r == 0.0? 0: 1;
break;
case mln_expr_type_string:
is_true = (v.data.s != NULL && v.data.s->len)? 1: 0;
break;
default: /* mln_expr_type_udata */
is_true = v.data.u != NULL? 1: 0;
break;
}
mln_expr_val_destroy(&v);

/* do */
again:
if (*next != NULL) {
tk = *next;
*next = NULL;
} else {
if ((tk = mln_expr_token(lex)) == NULL) {
return MLN_EXPR_RET_ERR;
}
}
type = tk->type;
mln_expr_free(tk);
if (type == EXPR_TK_SPACE) {
goto again;
}
if (type != EXPR_TK_DO) {
return MLN_EXPR_RET_ERR;
}

if (is_true) {
while (1) {
if (*next != NULL) {
tk = *next;
*next = NULL;
} else {
if ((tk = mln_expr_token(lex)) == NULL) {
return MLN_EXPR_RET_ERR;
}
}
if (tk->type == EXPR_TK_END) {
break;
}
*next = tk;
v.type = mln_expr_type_null;
if ((rc = mln_expr_parse(lex, cb, data, &v, eof, next)) != MLN_EXPR_RET_OK) {
mln_expr_val_destroy(&v);
return rc;
}
if (*eof) {
mln_expr_val_destroy(&v);
return MLN_EXPR_RET_ERR;
}

if (ret != NULL) mln_expr_val_destroy(ret);
mln_expr_val_copy(ret, &v);
mln_expr_val_destroy(&v);
}
mln_lex_snapshot_apply(lex, off);
goto begin;
} else {
while (1) {
if (*next != NULL) {
tk = *next;
*next = NULL;
} else {
lp:
if ((tk = mln_expr_token(lex)) == NULL) {
return MLN_EXPR_RET_ERR;
}
}

type = tk->type;
mln_expr_free(tk);
if (type == EXPR_TK_LOOP) {
++count;
} else if (type == EXPR_TK_EOF) {
return MLN_EXPR_RET_ERR;
} else if (type == EXPR_TK_END) {
if (count-- == 0) break;
}
goto lp;
}
}

return MLN_EXPR_RET_OK;
})

MLN_FUNC(, mln_expr_val_t *, mln_expr_run, (mln_string_t *exp, mln_expr_cb_t cb, void *data), (exp, cb, data), {
mln_lex_t *lex = NULL;
struct mln_lex_attr lattr;
Expand Down

0 comments on commit 7ddf1c6

Please sign in to comment.