Discard and warn against conflicting expression operators.

This commit is contained in:
Miguel Lechon
2021-09-09 12:21:03 +02:00
parent c6c790e50d
commit c0a50bfe27
3 changed files with 205 additions and 98 deletions
+157 -81
View File
@@ -2976,7 +2976,8 @@ MD_NodeDeepMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags)
MD_FUNCTION_IMPL void
MD_ExprOperatorPush(MD_Arena *arena, MD_ExprOperatorList *list,
MD_u32 op_id, MD_ExprOperatorKind kind,
MD_u64 precedence, MD_Node *md_node){
MD_u64 precedence, MD_Node *md_node)
{
MD_ExprOperatorNode *node = MD_PushArray(arena, MD_ExprOperatorNode, 1);
MD_QueuePush(list->first, list->last, node);
list->count += 1;
@@ -2986,66 +2987,17 @@ MD_ExprOperatorPush(MD_Arena *arena, MD_ExprOperatorList *list,
node->op.md_node = md_node;
}
MD_FUNCTION_IMPL MD_ExprOperatorTable
MD_ExprBakeOperatorTableFromList(MD_Arena *arena, MD_ExprOperatorList *list){
MD_ExprOperatorTable result = MD_ZERO_STRUCT;
for(MD_ExprOperatorNode *op_node = list->first; op_node; op_node = op_node->next){
MD_ExprOperatorList *list = result.table+op_node->op.kind;
MD_ExprOperatorNode *op_node_copy = MD_PushArray(arena, MD_ExprOperatorNode, 1);
MD_QueuePush(list->first, list->last, op_node_copy);
list->count += 1;
op_node_copy->op = op_node->op;
if(op_node->op.kind == MD_ExprOperatorKind_Postfix &&
MD_S8Match(op_node->op.md_node->string, MD_S8Lit("()"), 0)){
result.call_op = &op_node_copy->op;
}
else if(op_node->op.kind == MD_ExprOperatorKind_Binary &&
MD_S8Match(op_node->op.md_node->string, MD_S8Lit("[]"), 0)){
result.subscript_op = &op_node_copy->op;
}
// TODO(mal): Check: non-repeat operators, same precedence binary ops should share associativity
}
return(result);
}
typedef struct _MD_ExprParseCtx _MD_ExprParseCtx;
struct _MD_ExprParseCtx{
MD_ExprOperatorTable *op_table;
MD_Node *first;
MD_Node *one_past_last;
};
MD_FUNCTION_IMPL MD_ExprParseResult
_MD_ExprParse_Ctx_MinPrecedence(MD_Arena *arena, _MD_ExprParseCtx *ctx, MD_u32 min_precedence);
MD_FUNCTION_IMPL MD_ExprNode * _MD_Expr_Make(MD_Arena *arena, MD_ExprOperator *op, MD_Node *op_node,
MD_ExprNode *left, MD_ExprNode *right){
MD_ExprNode *result = MD_PushArrayZero(arena, MD_ExprNode, 1);
result->is_op = 1;
result->op_id = op->op_id;
result->md_op_node = op->md_node;
result->md_node = op_node;
result->left = left;
result->right = right;
result->left->parent = result;
if(result->right){ // TODO(mal): Introduce Nil expr node?
result->right->parent = result;
}
return result;
}
MD_FUNCTION_IMPL MD_ExprOperator *
_MD_ExprOperatorMatch(MD_ExprOperatorTable *table, MD_ExprOperatorKind kind, MD_String8 s){
MD_FUNCTION_IMPL MD_ExprOperator *
_MD_ExprOperatorMatch(MD_ExprOperatorTable *table, MD_ExprOperatorKind kind, MD_String8 s)
{
// NOTE(mal): Look for operator on one or all (kind == MD_ExprOperatorKind_Null) tables
MD_ExprOperator *result = 0;
for(MD_ExprOperatorKind cur_kind = (MD_ExprOperatorKind)(MD_ExprOperatorKind_Null+1);
!result && cur_kind < MD_ExprOperatorKind_COUNT;
cur_kind = (MD_ExprOperatorKind)(cur_kind+1)){
if(kind == MD_ExprOperatorKind_Null || kind == cur_kind){
!result && cur_kind < MD_ExprOperatorKind_COUNT;
cur_kind = (MD_ExprOperatorKind)(cur_kind+1))
{
if(kind == MD_ExprOperatorKind_Null || kind == cur_kind)
{
MD_ExprOperatorList *op_list = table->table+cur_kind;
for(MD_ExprOperatorNode *op_node = op_list->first; !result && op_node; op_node = op_node->next)
{
@@ -3058,17 +3010,122 @@ _MD_ExprOperatorMatch(MD_ExprOperatorTable *table, MD_ExprOperatorKind kind, MD_
return result;
}
MD_FUNCTION_IMPL void _MD_CtxAdvance(_MD_ExprParseCtx *ctx){
MD_FUNCTION_IMPL MD_ExprOperatorTable
MD_ExprBakeOperatorTableFromList(MD_Arena *arena, MD_ExprOperatorList *list)
{
MD_ExprOperatorTable result = MD_ZERO_STRUCT;
for(MD_ExprOperatorNode *op_node = list->first; op_node; op_node = op_node->next)
{
MD_ExprOperator op = op_node->op;
MD_String8 op_s = op.md_node->string;
MD_String8 error_str = MD_ZERO_STRUCT;
if(op.kind != MD_ExprOperatorKind_Prefix && op.kind != MD_ExprOperatorKind_Postfix &&
op.kind != MD_ExprOperatorKind_Binary && op.kind != MD_ExprOperatorKind_BinaryRightAssociative)
{
error_str = MD_S8Fmt(arena, "Invalid operator kind.");
}
else
{
for(MD_ExprOperatorNode *op_node2 = list->first; op_node2 != op_node; op_node2 = op_node2->next)
{ // NOTE(mal): O(n^2)
MD_ExprOperator op2 = op_node2->op;
MD_String8 op2_s = op2.md_node->string;
if(op.precedence == op2.precedence &&
((op.kind == MD_ExprOperatorKind_Binary && op2.kind == MD_ExprOperatorKind_BinaryRightAssociative) ||
(op.kind == MD_ExprOperatorKind_BinaryRightAssociative && op2.kind == MD_ExprOperatorKind_Binary)))
{
error_str = MD_S8Fmt(arena, "Ignored binary operator \"%.*s\" because another binary operator"
"has the same precedence and different associativity", MD_S8VArg(op_s));
}
else if(MD_S8Match(op_s, op2_s, 0))
{
if(op.kind == op2.kind)
{
error_str = MD_S8Fmt(arena, "Ignored repeat operator \"%.*s\".", MD_S8VArg(op_s));
}
else if(op.kind != MD_ExprOperatorKind_Prefix && op2.kind != MD_ExprOperatorKind_Prefix)
{
error_str = MD_S8Fmt(arena, "Ignored conflicting repeat operator \"%.*s\". There can't be"
"more than one posfix/binary operator associated to the same token",
MD_S8VArg(op_s));
}
}
}
}
if(error_str.size == 0)
{
MD_ExprOperatorList *list = result.table+op.kind;
MD_ExprOperatorNode *op_node_copy = MD_PushArray(arena, MD_ExprOperatorNode, 1);
MD_QueuePush(list->first, list->last, op_node_copy);
list->count += 1;
op_node_copy->op = op;
if(op.kind == MD_ExprOperatorKind_Postfix && MD_S8Match(op_s, MD_S8Lit("()"), 0))
{
result.call_op = &op_node_copy->op;
}
else if(op.kind == MD_ExprOperatorKind_Binary && MD_S8Match(op_s, MD_S8Lit("[]"), 0))
{
result.subscript_op = &op_node_copy->op;
}
}
else
{
MD_Message *error = MD_MakeNodeError(arena, op.md_node, MD_MessageKind_Warning, error_str);
MD_MessageListPush(&result.errors, error);
}
}
return(result);
}
typedef struct _MD_ExprParseCtx _MD_ExprParseCtx;
struct _MD_ExprParseCtx
{
MD_ExprOperatorTable *op_table;
MD_Node *first;
MD_Node *one_past_last;
};
MD_FUNCTION_IMPL MD_ExprParseResult
_MD_ExprParse_Ctx_MinPrecedence(MD_Arena *arena, _MD_ExprParseCtx *ctx, MD_u32 min_precedence);
MD_FUNCTION_IMPL MD_ExprNode * _MD_Expr_Make(MD_Arena *arena, MD_ExprOperator *op, MD_Node *op_node,
MD_ExprNode *left, MD_ExprNode *right)
{
MD_ExprNode *result = MD_PushArrayZero(arena, MD_ExprNode, 1);
result->is_op = 1;
result->op_id = op->op_id;
result->md_op_node = op->md_node;
result->md_node = op_node;
result->left = left;
result->right = right;
result->left->parent = result;
if(result->right)
{ // TODO(mal): Introduce Nil expr node?
result->right->parent = result;
}
return result;
}
MD_FUNCTION_IMPL void _MD_CtxAdvance(_MD_ExprParseCtx *ctx)
{
ctx->first = ctx->first->next;
}
MD_FUNCTION_IMPL MD_b32 _MD_ExprOperatorConsumed(_MD_ExprParseCtx *ctx, MD_ExprOperatorKind kind, MD_u32 min_precedence,
MD_ExprOperator **op_out){
MD_ExprOperator **op_out)
{
MD_b32 result = 0;
if(!MD_NodeIsNil(ctx->first)){
if(!MD_NodeIsNil(ctx->first))
{
MD_Node *node = ctx->first;
MD_ExprOperator *op = _MD_ExprOperatorMatch(ctx->op_table, kind, node->string);
if(op && op->precedence >= min_precedence){
if(op && op->precedence >= min_precedence)
{
result = 1;
*op_out = op;
_MD_CtxAdvance(ctx);
@@ -3078,7 +3135,8 @@ MD_FUNCTION_IMPL MD_b32 _MD_ExprOperatorConsumed(_MD_ExprParseCtx *ctx, MD_ExprO
}
MD_FUNCTION_IMPL _MD_ExprParseCtx
_MD_ExprParse_MakeContext(MD_ExprOperatorTable *op_table, MD_Node *first, MD_Node *one_past_last){
_MD_ExprParse_MakeContext(MD_ExprOperatorTable *op_table, MD_Node *first, MD_Node *one_past_last)
{
_MD_ExprParseCtx result = MD_ZERO_STRUCT;
result.op_table = op_table;
result.first = first;
@@ -3087,35 +3145,41 @@ _MD_ExprParse_MakeContext(MD_ExprOperatorTable *op_table, MD_Node *first, MD_Nod
}
MD_FUNCTION_IMPL MD_ExprParseResult
_MD_ExprParse_Atom(MD_Arena *arena, _MD_ExprParseCtx *ctx){
_MD_ExprParse_Atom(MD_Arena *arena, _MD_ExprParseCtx *ctx)
{
MD_ExprParseResult result = MD_ZERO_STRUCT;
MD_Node *node = ctx->first;
MD_ExprOperator *op = 0;
if(node->flags & MD_NodeFlag_HasParenLeft && node->flags & MD_NodeFlag_HasParenRight){ // NOTE(mal): Parens
if(node->flags & MD_NodeFlag_HasParenLeft && node->flags & MD_NodeFlag_HasParenRight)
{ // NOTE(mal): Parens
_MD_CtxAdvance(ctx);
_MD_ExprParseCtx sub_ctx = _MD_ExprParse_MakeContext(ctx->op_table, node->first_child, node->last_child->next);
result = _MD_ExprParse_Ctx_MinPrecedence(arena, &sub_ctx, 0);
}
else if((node->flags & MD_NodeFlag_HasBracketLeft && node->flags & MD_NodeFlag_HasBracketRight) ||
(node->flags & MD_NodeFlag_HasBraceLeft && node->flags & MD_NodeFlag_HasBraceRight)){
(node->flags & MD_NodeFlag_HasBraceLeft && node->flags & MD_NodeFlag_HasBraceRight))
{
_MD_CtxAdvance(ctx);
// NOTE(mal): Unparsed leaf sets ({ ... }, [ ... ])
result.node = MD_PushArrayZero(arena, MD_ExprNode, 1);
result.node->md_node = node;
}
else if(_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_Prefix, 1, &op)){
else if(_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_Prefix, 1, &op))
{
MD_u32 min_precedence = op->precedence + 1;
MD_ExprParseResult sub_parse_result = _MD_ExprParse_Ctx_MinPrecedence(arena, ctx, min_precedence);
if(sub_parse_result.errors.max_message_kind == MD_MessageKind_Null){
if(sub_parse_result.errors.max_message_kind == MD_MessageKind_Null)
{
result.node = _MD_Expr_Make(arena, op, node, sub_parse_result.node, 0);
}
else{
result.errors = sub_parse_result.errors;
}
}
else if(_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_Null, 1, &op)){
else if(_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_Null, 1, &op))
{
MD_String8 error_str = MD_S8Fmt(arena, "Expected leaf. Got operator \"%.*s\".", MD_S8VArg(node->string));
MD_Message *error = MD_MakeNodeError(arena, node, MD_MessageKind_Error, error_str);
MD_MessageListPush(&result.errors, error);
@@ -3130,26 +3194,31 @@ _MD_ExprParse_Atom(MD_Arena *arena, _MD_ExprParseCtx *ctx){
}
MD_FUNCTION_IMPL MD_ExprParseResult
_MD_ExprParse_Ctx_MinPrecedence(MD_Arena *arena, _MD_ExprParseCtx *ctx, MD_u32 min_precedence){
_MD_ExprParse_Ctx_MinPrecedence(MD_Arena *arena, _MD_ExprParseCtx *ctx, MD_u32 min_precedence)
{
MD_ExprParseResult result = MD_ZERO_STRUCT;
MD_ExprOperator *subscript_op = ctx->op_table->subscript_op;
result = _MD_ExprParse_Atom(arena, ctx);
if(result.errors.max_message_kind == MD_MessageKind_Null){
while(!MD_NodeIsNil(ctx->first) && ctx->first != ctx->one_past_last){
if(result.errors.max_message_kind == MD_MessageKind_Null)
{
while(!MD_NodeIsNil(ctx->first) && ctx->first != ctx->one_past_last)
{
MD_Node *node = ctx->first;
MD_ExprOperator *op;
if(subscript_op && subscript_op->precedence >= min_precedence &&
node->flags & MD_NodeFlag_HasBracketLeft && node->flags & MD_NodeFlag_HasBracketRight){
node->flags & MD_NodeFlag_HasBracketLeft && node->flags & MD_NodeFlag_HasBracketRight)
{
_MD_CtxAdvance(ctx);
// NOTE(mal): Array subscript
_MD_ExprParseCtx sub_ctx = _MD_ExprParse_MakeContext(ctx->op_table,
node->first_child, node->last_child->next);
MD_ExprParseResult sub_parse_result = _MD_ExprParse_Ctx_MinPrecedence(arena, &sub_ctx, 0);
if(sub_parse_result.errors.max_message_kind == MD_MessageKind_Null){
if(sub_parse_result.errors.max_message_kind == MD_MessageKind_Null)
{
result.node = _MD_Expr_Make(arena, subscript_op, node, result.node, sub_parse_result.node);
}
else{
@@ -3158,10 +3227,12 @@ _MD_ExprParse_Ctx_MinPrecedence(MD_Arena *arena, _MD_ExprParseCtx *ctx, MD_u32 m
}
}
else if(_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_Binary, min_precedence, &op) ||
_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_BinaryRightAssociative, min_precedence, &op)){
_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_BinaryRightAssociative, min_precedence, &op))
{
MD_u32 next_min_precedence = op->precedence + (op->kind == MD_ExprOperatorKind_Binary);
MD_ExprParseResult sub_parse_result = _MD_ExprParse_Ctx_MinPrecedence(arena, ctx, next_min_precedence);
if(sub_parse_result.errors.max_message_kind == MD_MessageKind_Null){
if(sub_parse_result.errors.max_message_kind == MD_MessageKind_Null)
{
result.node = _MD_Expr_Make(arena, op, node, result.node, sub_parse_result.node);
}
else{
@@ -3170,11 +3241,13 @@ _MD_ExprParse_Ctx_MinPrecedence(MD_Arena *arena, _MD_ExprParseCtx *ctx, MD_u32 m
}
}
else if(ctx->op_table->call_op && ctx->op_table->call_op->precedence >= min_precedence &&
node->flags & MD_NodeFlag_HasParenLeft && node->flags & MD_NodeFlag_HasParenRight){ // NOTE: call
node->flags & MD_NodeFlag_HasParenLeft && node->flags & MD_NodeFlag_HasParenRight)
{ // NOTE: call
_MD_CtxAdvance(ctx);
result.node = _MD_Expr_Make(arena, ctx->op_table->call_op, node, result.node, 0);
}
else if(_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_Postfix, min_precedence, &op)){
else if(_MD_ExprOperatorConsumed(ctx, MD_ExprOperatorKind_Postfix, min_precedence, &op))
{
result.node = _MD_Expr_Make(arena, op, node, result.node, 0);
}
else{
@@ -3187,13 +3260,16 @@ _MD_ExprParse_Ctx_MinPrecedence(MD_Arena *arena, _MD_ExprParseCtx *ctx, MD_u32 m
}
MD_FUNCTION_IMPL MD_ExprParseResult
MD_ExprParse(MD_Arena *arena, MD_ExprOperatorTable *op_table, MD_Node *first, MD_Node *one_past_last){
MD_ExprParse(MD_Arena *arena, MD_ExprOperatorTable *op_table, MD_Node *first, MD_Node *one_past_last)
{
MD_ExprParseResult result = MD_ZERO_STRUCT;
_MD_ExprParseCtx ctx = _MD_ExprParse_MakeContext(op_table, first, one_past_last);
result = _MD_ExprParse_Ctx_MinPrecedence(arena, &ctx, 0);
if(result.errors.max_message_kind == MD_MessageKind_Null){
if(ctx.first != ctx.one_past_last){
if(result.errors.max_message_kind == MD_MessageKind_Null)
{
if(ctx.first != ctx.one_past_last)
{
MD_String8 error_str =
MD_S8Fmt(arena, "Partial parse. Expected binary or unary postfix operator."); // TODO(mal): More detail?
MD_Message *error = MD_MakeNodeError(arena, ctx.first, MD_MessageKind_Error, error_str);
+2 -4
View File
@@ -719,11 +719,9 @@ struct MD_ExprOperatorTable
{
// TODO(mal): Something faster; arrays indexed by op kind or hash table...
MD_ExprOperatorList table[MD_ExprOperatorKind_COUNT];
MD_ExprOperator *call_op;
MD_ExprOperator *subscript_op;
MD_MessageList errors;
MD_ExprOperator *call_op; // TODO: Move elsewhere
MD_ExprOperator *subscript_op;
};
typedef struct MD_ExprNode MD_ExprNode;
+46 -13
View File
@@ -1,15 +1,5 @@
//$ exe //
#if 0
#define ASSERT(expr) {if(!(expr)){fprintf(stderr, "Assertion failed: %s, line %d (%s)\n", __FILE__, __LINE__, #expr); __builtin_debugtrap();}}
#define HARD_ASSERT(expr) {if(!(expr)){fprintf(stderr, "Assertion failed: %s, line %d (%s)\n", __FILE__, __LINE__, #expr); __builtin_debugtrap();}}
#define BP ASSERT(!"Break point");
#define NotTested ASSERT(!"Not tested");
#define STATIC_ASSERT(expr) U8 MACRO_CONCAT(static_assert_, __COUNTER__)[(expr)?(1):(-1)]
#define NotImplemented ASSERT(!"Not implemented");
#endif
#include "md.h"
#include "md.c"
@@ -86,7 +76,6 @@ typedef enum{
} Op;
#undef X
static MD_String8 node_raw_contents(MD_Node *node, MD_b32 exclude_outer){
MD_String8 result = {0};
@@ -194,7 +183,6 @@ static MD_String8 parenthesize(MD_Arena *arena, OperatorDescription *descs, MD_E
return result;
}
int main(void){
OperatorDescription operator_array[Op_COUNT] = {0};
#define X(name, token, kind_, prec) \
@@ -204,9 +192,54 @@ int main(void){
#undef X
arena = MD_ArenaAlloc(1ull << 40);
/* NOTE: Operator table bake errors */ {
MD_ExprOperatorList operator_list = {0};
MD_ExprOperatorTable op_table = {0};
MD_String8 plus = MD_S8Lit("+");
MD_String8 minus = MD_S8Lit("-");
MD_Node *plus_node = MD_MakeNode(arena, MD_NodeKind_Main, plus, plus, 0);
MD_Node *minus_node = MD_MakeNode(arena, MD_NodeKind_Main, minus, minus, 0);
MD_Node *plus_node_bis = MD_MakeNode(arena, MD_NodeKind_Main, plus, plus, 0);
// NOTE: Wrong operator kind
operator_list = (MD_ExprOperatorList){0};
MD_ExprOperatorPush(arena, &operator_list, Op_Addition, MD_ExprOperatorKind_Null, 1, plus_node);
op_table = MD_ExprBakeOperatorTableFromList(arena, &operator_list);
MD_Assert(op_table.errors.max_message_kind = MD_MessageKind_Warning && op_table.errors.node_count == 1 &&
op_table.errors.first->node == plus_node);
// NOTE: Repeat operator
operator_list = (MD_ExprOperatorList){0};
MD_ExprOperatorPush(arena, &operator_list, Op_Addition, MD_ExprOperatorKind_Binary, 1, plus_node);
MD_ExprOperatorPush(arena, &operator_list, Op_Addition, MD_ExprOperatorKind_Binary, 1, plus_node_bis);
op_table = MD_ExprBakeOperatorTableFromList(arena, &operator_list);
MD_Assert(op_table.errors.max_message_kind = MD_MessageKind_Warning && op_table.errors.node_count == 1 &&
op_table.errors.first->node == plus_node_bis);
operator_list = (MD_ExprOperatorList){0};
// NOTE: Binary-postfix operator conflict
MD_ExprOperatorPush(arena, &operator_list, Op_Addition, MD_ExprOperatorKind_Binary, 1, plus_node);
MD_ExprOperatorPush(arena, &operator_list, Op_Addition, MD_ExprOperatorKind_Postfix, 1, plus_node_bis);
op_table = MD_ExprBakeOperatorTableFromList(arena, &operator_list);
MD_Assert(op_table.errors.max_message_kind = MD_MessageKind_Warning && op_table.errors.node_count == 1 &&
op_table.errors.first->node == plus_node_bis);
operator_list = (MD_ExprOperatorList){0};
// NOTE: Same precedence difference associativity conflict
MD_ExprOperatorPush(arena, &operator_list, Op_Addition, MD_ExprOperatorKind_Binary, 1, plus_node);
MD_ExprOperatorPush(arena, &operator_list, Op_Addition, MD_ExprOperatorKind_BinaryRightAssociative,
1, minus_node);
op_table = MD_ExprBakeOperatorTableFromList(arena, &operator_list);
MD_Assert(op_table.errors.max_message_kind = MD_MessageKind_Warning && op_table.errors.node_count == 1 &&
op_table.errors.first->node == minus_node);
}
MD_ExprOperatorList operator_list = {0};
for(Op op= Op_Null+1; op < Op_COUNT; ++op){
for(Op op = Op_Null+1; op < Op_COUNT; ++op){
OperatorDescription *desc = operator_array + op;
MD_Node *node = MD_MakeNode(arena, MD_NodeKind_Main, desc->s, desc->s, 0);
MD_ExprOperatorPush(arena, &operator_list, op, desc->op.kind, desc->op.precedence, node);