@@ -59,6 +59,7 @@ typedef enum
59
59
60
60
PREC_ASSIGN , // x = y
61
61
PREC_PIPE , // x |> y
62
+ PREC_CUSTOM_OPERATOR , // custom operators
62
63
PREC_LOGIC_OR , // x || y
63
64
PREC_LOGIC_AND , // x && y
64
65
PREC_INFIX_CALL , // x `y` z
@@ -129,6 +130,8 @@ static ASTNode_T* parse_type_expr(Parser_T* p);
129
130
static ASTNode_T * parse_infix_call (Parser_T * p , ASTNode_T * left );
130
131
131
132
static ASTNode_T * parse_call (Parser_T * p , ASTNode_T * left );
133
+ static ASTNode_T * parse_custom_infix_operator (Parser_T * p , ASTNode_T * left );
134
+ static ASTNode_T * parse_custom_prefix_operator (Parser_T * p );
132
135
static ASTNode_T * parse_cast (Parser_T * p , ASTNode_T * left );
133
136
static ASTNode_T * parse_member (Parser_T * p , ASTNode_T * left );
134
137
static ASTNode_T * parse_pipe (Parser_T * p , ASTNode_T * left );
@@ -287,10 +290,9 @@ static inline PrefixParseFn_T get_PrefixParseFn_T(Parser_T* p, Token_T* tok)
287
290
if (tok -> type == TOKEN_OPERATOR )
288
291
{
289
292
OperatorContext_T * context = hashmap_get (p -> operator_context , tok -> value );
290
- if (!context )
291
- throw_error (p -> context , ERR_SYNTAX_ERROR , tok , "custom operators not supported yet" );
292
-
293
- return context -> pfn ;
293
+ if (context )
294
+ return context -> pfn ;
295
+ return parse_custom_prefix_operator ;
294
296
}
295
297
else
296
298
return expr_parse_fns [tok -> type ].pfn ;
@@ -301,10 +303,9 @@ static inline InfixParseFn_T get_InfixParseFn_T(Parser_T* p, Token_T* tok)
301
303
if (tok -> type == TOKEN_OPERATOR )
302
304
{
303
305
OperatorContext_T * context = hashmap_get (p -> operator_context , tok -> value );
304
- if (!context )
305
- throw_error (p -> context , ERR_SYNTAX_ERROR , tok , "custom operators not supported yet" );
306
-
307
- return context -> ifn ;
306
+ if (context )
307
+ return context -> ifn ;
308
+ return parse_custom_infix_operator ;
308
309
}
309
310
else
310
311
return expr_parse_fns [tok -> type ].ifn ;
@@ -315,10 +316,9 @@ static inline Precedence_T get_precedence(Parser_T* p, Token_T* tok)
315
316
if (tok -> type == TOKEN_OPERATOR )
316
317
{
317
318
OperatorContext_T * context = hashmap_get (p -> operator_context , tok -> value );
318
- if (!context )
319
- throw_error (p -> context , ERR_SYNTAX_ERROR , tok , "custom operators not supported yet" );
320
-
321
- return context -> precedence ;
319
+ if (context )
320
+ return context -> precedence ;
321
+ return PREC_CUSTOM_OPERATOR ;
322
322
}
323
323
else
324
324
return expr_parse_fns [tok -> type ].prec ;
@@ -558,7 +558,7 @@ static ASTIdentifier_T* __parse_identifier(Parser_T* p, ASTIdentifier_T* outer,
558
558
if (tok_is_operator (p , STATIC_MEMBER ) && !is_simple && parser_peek (p , 1 )-> type == TOKEN_ID )
559
559
{
560
560
if (is_operator (parser_peek (p , 1 ), "<" ))
561
- return id ; // :: followed by < would be a generic in a functon or - call
561
+ return id ; // :: followed by < would be a generic in a function call
562
562
563
563
parser_advance (p );
564
564
return __parse_identifier (p , id , false);
@@ -917,6 +917,7 @@ static ASTObj_T* parse_extern_def(Parser_T *p, bool is_extern_c)
917
917
throw_error (p -> context , ERR_SYNTAX_WARNING , ext_var -> value -> tok , "cannot set a value to an extern variable" );
918
918
return ext_var ;
919
919
}
920
+ case TOKEN_OPERATOR_KW :
920
921
case TOKEN_FN :
921
922
{
922
923
ASTObj_T * ext_fn = parse_fn_def (p );
@@ -1017,16 +1018,34 @@ static ASTNode_T* parse_stmt(Parser_T* p, bool needs_semicolon);
1017
1018
static ASTObj_T * parse_fn_def (Parser_T * p )
1018
1019
{
1019
1020
ASTObj_T * fn = init_ast_obj (OBJ_FUNCTION , p -> tok );
1020
- parser_consume ( p , TOKEN_FN , "expect `fn` keyword for a function definition" ) ;
1021
+ bool is_operator_define = false ;
1021
1022
1022
- fn -> id = parse_simple_identifier (p );
1023
+ if (tok_is (p , TOKEN_OPERATOR_KW ))
1024
+ {
1025
+ parser_advance (p );
1026
+ fn -> id = init_ast_identifier (p -> tok , p -> tok -> value );
1027
+ if (p -> tok -> type != TOKEN_OPERATOR )
1028
+ throw_error (p -> context , ERR_SYNTAX_ERROR , p -> tok , "expect operator after `operator`" );
1029
+ if (hashmap_get (p -> operator_context , p -> tok -> value ))
1030
+ throw_error (p -> context , ERR_REDEFINITION , p -> tok , "redefinition of built-in operator `%s`" , p -> tok -> value );
1031
+ parser_advance (p );
1032
+ is_operator_define = true;
1033
+ }
1034
+ else
1035
+ {
1036
+ parser_consume (p , TOKEN_FN , "expect `fn` keyword for a function definition" );
1037
+ fn -> id = parse_simple_identifier (p );
1038
+ }
1023
1039
1024
1040
parser_consume (p , TOKEN_LPAREN , "expect `(` after function name" );
1025
-
1041
+
1026
1042
ASTIdentifier_T * va_id = NULL ;
1027
1043
fn -> args = parse_argument_list (p , TOKEN_RPAREN , & va_id );
1028
1044
mem_add_list (fn -> args );
1029
1045
1046
+ if (is_operator_define && fn -> args -> size != 1 && fn -> args -> size != 2 )
1047
+ throw_error (p -> context , ERR_SYNTAX_ERROR_UNCR , fn -> tok , "`operator` functions can only take one or two arguments, got `%zu`" , fn -> args -> size );
1048
+
1030
1049
if (va_id )
1031
1050
{
1032
1051
fn -> va_area = init_ast_obj (OBJ_LOCAL , fn -> tok );
@@ -1183,6 +1202,7 @@ void parse_obj(Parser_T* p, List_T* obj_list)
1183
1202
list_push (obj_list , parse_global (p ));
1184
1203
break ;
1185
1204
case TOKEN_FN :
1205
+ case TOKEN_OPERATOR_KW :
1186
1206
list_push (obj_list , parse_fn (p ));
1187
1207
break ;
1188
1208
case TOKEN_EXTERN :
@@ -2283,6 +2303,39 @@ static ASTNode_T* parse_call(Parser_T* p, ASTNode_T* left)
2283
2303
return call ;
2284
2304
}
2285
2305
2306
+ static ASTNode_T * parse_custom_prefix_operator (Parser_T * p )
2307
+ {
2308
+ ASTNode_T * call = init_ast_node (ND_CALL , p -> tok );
2309
+ call -> expr = init_ast_node (ND_ID , p -> tok );
2310
+ call -> expr -> id = init_ast_identifier (p -> tok , p -> tok -> value );
2311
+
2312
+ parser_consume (p , TOKEN_OPERATOR , "expect operator" );
2313
+
2314
+ ASTNode_T * arg = parse_expr (p , PREC_UNARY , TOKEN_SEMICOLON );
2315
+
2316
+ call -> args = init_list ();
2317
+ list_push (call -> args , arg );
2318
+
2319
+ return call ;
2320
+ }
2321
+
2322
+ static ASTNode_T * parse_custom_infix_operator (Parser_T * p , ASTNode_T * left )
2323
+ {
2324
+ ASTNode_T * call = init_ast_node (ND_CALL , p -> tok );
2325
+ call -> expr = init_ast_node (ND_ID , p -> tok );
2326
+ call -> expr -> id = init_ast_identifier (p -> tok , p -> tok -> value );
2327
+
2328
+ parser_consume (p , TOKEN_OPERATOR , "expect operator" );
2329
+
2330
+ ASTNode_T * right = parse_expr (p , PREC_CUSTOM_OPERATOR , TOKEN_SEMICOLON );
2331
+
2332
+ call -> args = init_list ();
2333
+ list_push (call -> args , left );
2334
+ list_push (call -> args , right );
2335
+
2336
+ return call ;
2337
+ }
2338
+
2286
2339
static ASTNode_T * parse_index (Parser_T * p , ASTNode_T * left )
2287
2340
{
2288
2341
ASTNode_T * index = init_ast_node (ND_INDEX , p -> tok );
0 commit comments