@@ -407,6 +407,285 @@ implementation
407407 end ;
408408
409409
410+ function match_statement (is_expr:boolean=false) : tnode;
411+ { Match statement: first-match (if-elseif) or fallthrough (match all).
412+ Subject-based: match EXPR of pat: stmt; end;
413+ Condition-based: match cond: stmt; end; }
414+
415+ function is_wildcard_underscore : boolean; inline;
416+ begin
417+ result:=(current_scanner.token=_ID) and (current_scanner.pattern=' _' );
418+ end ;
419+
420+ procedure append_else (var ifchain:tnode;elseblock:tnode);
421+ var
422+ tailnode : tnode;
423+ begin
424+ if ifchain=nil then
425+ ifchain:=elseblock
426+ else
427+ begin
428+ tailnode:=ifchain;
429+ while assigned(tifnode(tailnode).t1) do
430+ tailnode:=tifnode(tailnode).t1;
431+ tifnode(tailnode).t1:=elseblock;
432+ end ;
433+ end ;
434+
435+ function parse_branch_cond (has_subject:boolean;subject:tnode) : tnode;
436+ { Parse pattern(s) for a branch. Subject mode supports comma-separated
437+ patterns (OR'd) and tuple patterns with _ wildcards. }
438+ var
439+ pat,cond : tnode;
440+ fields : array of tnode;
441+ fieldcount,i,symidx : integer;
442+ sym : tsym;
443+ recdef : trecorddef;
444+ begin
445+ { tuple pattern with potential _ wildcards }
446+ if has_subject and (current_scanner.token=_LKLAMMER) and
447+ assigned(subject.resultdef) and (subject.resultdef.typ=recorddef) and
448+ (df_tuple in subject.resultdef.defoptions) then
449+ begin
450+ consume(_LKLAMMER);
451+ fieldcount:=0 ;
452+ setlength(fields,8 );
453+ repeat
454+ if fieldcount>=length(fields) then
455+ setlength(fields,fieldcount*2 );
456+ if (current_scanner.token=_ID) and (current_scanner.pattern=' _' ) then
457+ begin
458+ fields[fieldcount]:=nil ;
459+ consume(_ID);
460+ end
461+ else
462+ begin
463+ fields[fieldcount]:=comp_expr([ef_accept_equal]);
464+ do_typecheckpass(fields[fieldcount]);
465+ end ;
466+ inc(fieldcount);
467+ until not try_to_consume(_COMMA);
468+ { single expression in parens = parenthesized expr, not tuple }
469+ if fieldcount=1 then
470+ begin
471+ consume(_RKLAMMER);
472+ if fields[0 ]=nil then
473+ result:=cordconstnode.create(1 ,pasbool1type,false)
474+ else
475+ result:=caddnode.create(equaln,subject.getcopy,fields[0 ]);
476+ exit;
477+ end ;
478+ consume(_RKLAMMER);
479+ { build per-field AND chain, skipping wildcards }
480+ recdef:=trecorddef(subject.resultdef);
481+ cond:=nil ;
482+ i:=0 ;
483+ for symidx:=0 to recdef.symtable.symlist.count-1 do
484+ begin
485+ sym:=tsym(recdef.symtable.symlist[symidx]);
486+ if sym.typ<>fieldvarsym then
487+ continue;
488+ if i>=fieldcount then
489+ break;
490+ if fields[i]<>nil then
491+ begin
492+ pat:=caddnode.create(equaln,
493+ csubscriptnode.create(tfieldvarsym(sym),subject.getcopy),
494+ fields[i]);
495+ if cond=nil then
496+ cond:=pat
497+ else
498+ cond:=caddnode.create(andn,cond,pat);
499+ end ;
500+ inc(i);
501+ end ;
502+ if cond=nil then
503+ cond:=cordconstnode.create(1 ,pasbool1type,false);
504+ result:=cond;
505+ end
506+ else
507+ begin
508+ { normal pattern with optional comma-separated OR }
509+ pat:=comp_expr([ef_accept_equal]);
510+ do_typecheckpass(pat);
511+ if has_subject then
512+ begin
513+ result:=caddnode.create(equaln,subject.getcopy,pat);
514+ while try_to_consume(_COMMA) do
515+ begin
516+ pat:=comp_expr([ef_accept_equal]);
517+ do_typecheckpass(pat);
518+ result:=caddnode.create(orn,result,
519+ caddnode.create(equaln,subject.getcopy,pat));
520+ end ;
521+ end
522+ else
523+ result:=pat;
524+ end ;
525+ end ;
526+
527+ var
528+ subject,cond,stmt,ifchain,firstcond,walknode,stmtblock : tnode;
529+ fallthrough,has_subject,has_catchall : boolean;
530+ stmts,exprstatements : tstatementnode;
531+ resultdef : tdef;
532+ resultvar : ttempcreatenode;
533+ begin
534+ consume(_MATCH);
535+ { check for 'all' (context-sensitive) }
536+ fallthrough:=(current_scanner.token=_ID) and (current_scanner.pattern=' ALL' );
537+ if fallthrough then
538+ consume(_ID);
539+ { determine mode: subject-based (match X of) vs condition-based }
540+ has_subject:=false;
541+ subject:=nil ;
542+ firstcond:=nil ;
543+ if not is_wildcard_underscore then
544+ begin
545+ firstcond:=comp_expr([ef_accept_equal]);
546+ do_typecheckpass(firstcond);
547+ if current_scanner.token=_OF then
548+ begin
549+ has_subject:=true;
550+ subject:=firstcond;
551+ set_varstate(subject,vs_read,[vsf_must_be_valid]);
552+ consume(_OF);
553+ firstcond:=nil ;
554+ end ;
555+ end ;
556+ if fallthrough then
557+ begin
558+ { fallthrough: independent if-statements in repeat..until true }
559+ stmtblock:=internalstatements(stmts);
560+ repeat
561+ if is_wildcard_underscore then
562+ begin
563+ consume(_ID);
564+ consume(_COLON);
565+ addstatement(stmts,statement);
566+ if not (current_scanner.token in [_END]) then
567+ consume(_SEMICOLON);
568+ break;
569+ end ;
570+ if firstcond<>nil then
571+ begin
572+ cond:=firstcond;
573+ firstcond:=nil ;
574+ end
575+ else
576+ cond:=parse_branch_cond(has_subject,subject);
577+ consume(_COLON);
578+ addstatement(stmts,cifnode.create(cond,statement,nil ));
579+ if not (current_scanner.token in [_ELSE,_OTHERWISE,_END]) then
580+ consume(_SEMICOLON);
581+ until current_scanner.token in [_ELSE,_OTHERWISE,_END];
582+ if try_to_consume(_ELSE) or try_to_consume(_OTHERWISE) then
583+ addstatement(stmts,statements_til_end)
584+ else
585+ consume(_END);
586+ if has_subject then
587+ subject.free;
588+ result:=cwhilerepeatnode.create(
589+ cordconstnode.create(1 ,pasbool1type,false),
590+ stmtblock,false,true);
591+ end
592+ else
593+ begin
594+ { first-match: if-elseif chain }
595+ resultdef:=nil ;
596+ has_catchall:=false;
597+ ifchain:=nil ;
598+ repeat
599+ if is_wildcard_underscore then
600+ begin
601+ has_catchall:=true;
602+ consume(_ID);
603+ consume(_COLON);
604+ if is_expr then
605+ begin
606+ stmt:=expr(true);
607+ resultdef:=branch_type(resultdef,stmt.resultdef);
608+ end
609+ else
610+ stmt:=statement;
611+ append_else(ifchain,stmt);
612+ if not (current_scanner.token in [_END]) then
613+ consume(_SEMICOLON);
614+ break;
615+ end ;
616+ if firstcond<>nil then
617+ begin
618+ cond:=firstcond;
619+ firstcond:=nil ;
620+ end
621+ else
622+ cond:=parse_branch_cond(has_subject,subject);
623+ consume(_COLON);
624+ if is_expr then
625+ begin
626+ stmt:=expr(true);
627+ resultdef:=branch_type(resultdef,stmt.resultdef);
628+ end
629+ else
630+ stmt:=statement;
631+ stmt:=cifnode.create(cond,stmt,nil );
632+ append_else(ifchain,stmt);
633+ if not (current_scanner.token in [_ELSE,_OTHERWISE,_END]) then
634+ consume(_SEMICOLON);
635+ until current_scanner.token in [_ELSE,_OTHERWISE,_END];
636+ if try_to_consume(_ELSE) or try_to_consume(_OTHERWISE) then
637+ begin
638+ has_catchall:=true;
639+ if is_expr then
640+ begin
641+ stmt:=expr(true);
642+ resultdef:=branch_type(resultdef,stmt.resultdef);
643+ end
644+ else
645+ stmt:=statements_til_end;
646+ append_else(ifchain,stmt);
647+ end
648+ else if is_expr and not has_catchall then
649+ consume(_ELSE)
650+ else
651+ consume(_END);
652+ if has_subject then
653+ subject.free;
654+ if not is_expr then
655+ result:=ifchain
656+ else
657+ begin
658+ { expression mode: wrap branches in temp var assignments }
659+ result:=internalstatements(exprstatements);
660+ resultvar:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
661+ addstatement(exprstatements,resultvar);
662+ { walk if-chain, wrap each branch value in assignment }
663+ walknode:=ifchain;
664+ while walknode.nodetype=ifn do
665+ begin
666+ tifnode(walknode).right:=cassignmentnode.create(
667+ ctemprefnode.create(resultvar),tifnode(walknode).right);
668+ if assigned(tifnode(walknode).t1) and (tifnode(walknode).t1.nodetype=ifn) then
669+ walknode:=tifnode(walknode).t1
670+ else
671+ begin
672+ if assigned(tifnode(walknode).t1) then
673+ tifnode(walknode).t1:=cassignmentnode.create(
674+ ctemprefnode.create(resultvar),tifnode(walknode).t1);
675+ break;
676+ end ;
677+ end ;
678+ if ifchain.nodetype<>ifn then
679+ { single catch-all value }
680+ ifchain:=cassignmentnode.create(ctemprefnode.create(resultvar),ifchain);
681+ addstatement(exprstatements,ifchain);
682+ addstatement(exprstatements,ctempdeletenode.create_normal_temp(resultvar));
683+ addstatement(exprstatements,ctemprefnode.create(resultvar));
684+ end ;
685+ end ;
686+ end ;
687+
688+
410689 function repeat_statement : tnode;
411690
412691 var
@@ -2966,6 +3245,8 @@ ((hdef.typ = arraydef) or (hdef.typ = recorddef)) then
29663245 code:=if_statement;
29673246 _CASE :
29683247 code:=case_statement;
3248+ _MATCH :
3249+ code:=match_statement;
29693250 _REPEAT :
29703251 code:=repeat_statement;
29713252 _WHILE :
@@ -3347,6 +3628,7 @@ ((hdef.typ = arraydef) or (hdef.typ = recorddef)) then
33473628 case current_scanner.token of
33483629 _IF: p1:=if_statement(true);
33493630 _CASE: p1:=case_statement(true);
3631+ _MATCH: p1:=match_statement(true);
33503632 _TRY: p1:=try_statement(true);
33513633 else
33523634 result:=false;
0 commit comments