feat: implement conditions
This commit is contained in:
+213
-4
@@ -120,6 +120,8 @@ static fzl_nodetype_t unary_op_to_type(fzl_toktype_t type)
|
||||
return FZL_NODETYPE_UNARY_PLUS;
|
||||
case FZL_TOKTYPE_MINUS:
|
||||
return FZL_NODETYPE_UNARY_MINUS;
|
||||
case FZL_TOKTYPE_NOT:
|
||||
return FZL_NODETYPE_NOT;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
@@ -144,6 +146,11 @@ fzl_node_t *parse_primary(fzl_parser_t *parser)
|
||||
fzl_token_t *tok = consume(parser);
|
||||
return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_BOOL_LITERAL))
|
||||
{
|
||||
fzl_token_t *tok = consume(parser);
|
||||
return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_LPAREN))
|
||||
{
|
||||
consume(parser);
|
||||
@@ -241,7 +248,8 @@ fzl_node_t *parse_unary(fzl_parser_t *parser)
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
if (!is(parser, FZL_TOKTYPE_MINUS) && !is(parser, FZL_TOKTYPE_PLUS))
|
||||
if (!is(parser, FZL_TOKTYPE_MINUS) && !is(parser, FZL_TOKTYPE_PLUS) &&
|
||||
!is(parser, FZL_TOKTYPE_NOT))
|
||||
return parse_postfix(parser);
|
||||
|
||||
fzl_token_t *op = consume(parser);
|
||||
@@ -372,12 +380,131 @@ fzl_node_t *parse_term(fzl_parser_t *parser)
|
||||
return left;
|
||||
}
|
||||
|
||||
// Expression parsing
|
||||
fzl_node_t *parse_expression(fzl_parser_t *parser)
|
||||
// Parse conditional operations
|
||||
fzl_node_t *parse_cond(fzl_parser_t *parser)
|
||||
{
|
||||
return parse_term(parser);
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
fzl_node_t *left = parse_term(parser);
|
||||
fzl_node_t *right = NULL;
|
||||
|
||||
if (!left)
|
||||
return NULL;
|
||||
|
||||
while (is(parser, FZL_TOKTYPE_EQEQ) || is(parser, FZL_TOKTYPE_NEQ) ||
|
||||
is(parser, FZL_TOKTYPE_LANGLE) || is(parser, FZL_TOKTYPE_LEQ) ||
|
||||
is(parser, FZL_TOKTYPE_RANGLE) || is(parser, FZL_TOKTYPE_REQ))
|
||||
{
|
||||
fzl_token_t *op = consume(parser);
|
||||
right = parse_term(parser);
|
||||
if (!right)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld",
|
||||
op->ln, op->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *result;
|
||||
switch (op->type)
|
||||
{
|
||||
case FZL_TOKTYPE_EQEQ:
|
||||
result = fzl_mknode(FZL_NODETYPE_EQUAL, op);
|
||||
break;
|
||||
case FZL_TOKTYPE_NEQ:
|
||||
result = fzl_mknode(FZL_NODETYPE_NEQUAL, op);
|
||||
break;
|
||||
case FZL_TOKTYPE_LANGLE:
|
||||
result = fzl_mknode(FZL_NODETYPE_LESS, op);
|
||||
break;
|
||||
case FZL_TOKTYPE_LEQ:
|
||||
result = fzl_mknode(FZL_NODETYPE_LESS_EQUAL, op);
|
||||
break;
|
||||
case FZL_TOKTYPE_RANGLE:
|
||||
result = fzl_mknode(FZL_NODETYPE_GREATER, op);
|
||||
break;
|
||||
case FZL_TOKTYPE_REQ:
|
||||
result = fzl_mknode(FZL_NODETYPE_GREATER_EQUAL, op);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result->binary_op.left = left;
|
||||
result->binary_op.right = right;
|
||||
left = result;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// Parse conditional &&
|
||||
fzl_node_t *parse_and(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
fzl_node_t *left = parse_cond(parser);
|
||||
fzl_node_t *right = NULL;
|
||||
|
||||
if (!left)
|
||||
return NULL;
|
||||
|
||||
while (is(parser, FZL_TOKTYPE_DAMPERSAND))
|
||||
{
|
||||
fzl_token_t * or = consume(parser);
|
||||
right = parse_cond(parser);
|
||||
if (!right)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld",
|
||||
or->ln, or->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_AND, or);
|
||||
node->binary_op.left = left;
|
||||
node->binary_op.right = right;
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// Parse conditional ||
|
||||
fzl_node_t *parse_or(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
fzl_node_t *left = parse_and(parser);
|
||||
fzl_node_t *right = NULL;
|
||||
|
||||
if (!left)
|
||||
return NULL;
|
||||
|
||||
while (is(parser, FZL_TOKTYPE_DVBAR))
|
||||
{
|
||||
fzl_token_t * or = consume(parser);
|
||||
right = parse_and(parser);
|
||||
if (!right)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld",
|
||||
or->ln, or->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_OR, or);
|
||||
node->binary_op.left = left;
|
||||
node->binary_op.right = right;
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// Expression parsing
|
||||
fzl_node_t *parse_expression(fzl_parser_t *parser) { return parse_and(parser); }
|
||||
|
||||
// Statement parsing
|
||||
fzl_node_t *parse_statement(fzl_parser_t *parser)
|
||||
{
|
||||
@@ -447,6 +574,88 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
|
||||
return left;
|
||||
}
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_IF))
|
||||
{
|
||||
fzl_token_t *if_tok = consume(parser);
|
||||
fzl_token_t *lparen = consume(parser);
|
||||
if (lparen->type != FZL_TOKTYPE_LPAREN)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"expected '(' before condition at %ld:%ld", lparen->ln,
|
||||
lparen->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *condition = parse_expression(parser);
|
||||
if (!condition)
|
||||
return NULL;
|
||||
|
||||
fzl_token_t *rparen = consume(parser);
|
||||
if (rparen->type != FZL_TOKTYPE_RPAREN)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"expected ')' after condition at %ld:%ld", rparen->ln,
|
||||
rparen->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *else_block = NULL;
|
||||
fzl_node_t *true_block = parse_statement(parser);
|
||||
if (!true_block)
|
||||
return NULL;
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_ELSE))
|
||||
{
|
||||
consume(parser); // else
|
||||
else_block = parse_statement(parser);
|
||||
if (!else_block)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *stmt_node = fzl_mknode(FZL_NODETYPE_CONDITIONAL, if_tok);
|
||||
stmt_node->cond.condition = condition;
|
||||
stmt_node->cond.true_block = true_block;
|
||||
stmt_node->cond.else_block = else_block;
|
||||
|
||||
return stmt_node;
|
||||
}
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_LBRACE))
|
||||
{
|
||||
fzl_token_t *block_tok = consume(parser);
|
||||
|
||||
size_t remainder = 2;
|
||||
size_t count = 0;
|
||||
fzl_node_t **stmts = malloc(remainder * sizeof(fzl_node_t *));
|
||||
|
||||
while (peek(parser) && !is(parser, FZL_TOKTYPE_RBRACE))
|
||||
{
|
||||
fzl_node_t *node = parse_statement(parser);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
if (remainder <= count)
|
||||
{
|
||||
remainder *= 2;
|
||||
stmts = realloc(stmts, remainder);
|
||||
}
|
||||
|
||||
stmts[count++] = node;
|
||||
}
|
||||
fzl_token_t *rbrace = consume(parser);
|
||||
if (!rbrace || rbrace->type != FZL_TOKTYPE_RBRACE)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"missing '}' after block at %ld:%ld", rbrace->ln, rbrace->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_BLOCK, block_tok);
|
||||
node->list.entries = stmts;
|
||||
node->list.entry_count = count;
|
||||
return node;
|
||||
}
|
||||
|
||||
return parse_expression(parser);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user