Pattern Matching

Felix provides an advanced pattern matching system which includes generic patterns and user defined patterns.

Pattern matching provides a way to decode a data structure by providing an image of the type with “holes” in it which are indicated by variables. Provided pattern matches the value the variables take on the value of the part of the type which is missing.

For products, pattern variables are projections of the value, possibly chained together in reverse order.

For sum types including variants, the argument of the constructor which created the value is extracted, after checking the value was indeed made by the corresponding injection function. If not, the next pattern is tried.

A pattern match over a product type is said to be irrefutable because it cannot fail after static type checking; however a pattern it is included in may fail, and a pattern matching a component may also fail.

Matches

Syntax

syntax patterns {

  block = match_stmt;

  smatch_head := "chainmatch" sexpr "with" stmt_matching+ =># "`(,_2 ,_4)";
  smatch_link := "ormatch" sexpr "with" stmt_matching+ =># "`(,_2 ,_4)";
  smatch_chain := smatch_chain smatch_link =># "(cons _2 _1)"; // revsersed
  smatch_chain := smatch_link =># "`(,_1)";

  match_stmt := smatch_head smatch_chain "endmatch" ";" =>#
    "`(ast_stmt_chainmatch ,_sr ,(cons _1 (reverse _2)))"
  ;

  match_stmt := smatch_head "endmatch" ";" =>#
    "`(ast_stmt_match (,_sr ,_1))"
  ;

  //$ Pattern match statement.
  //$ At least one branch must match or the program aborts with a match failure.
  match_stmt:= "match" sexpr "with" stmt_matching+ "endmatch" ";" =>#
    "`(ast_stmt_match (,_sr ,_2 ,_4))";

  match_stmt:= "match" sexpr "do" stmt_matching+ "done" =>#
    "`(ast_stmt_match (,_sr ,_2 ,_4))";

  //$ A single branch of a pattern match statement.
  //$ The match argument expression is compared to the pattern.
  //$ If it matches any contained pattern variables are assigned
  //$ the values in the corresponding possition of the expression,
  //$ and the statements are executed.
  private stmt_matching := "|" spattern "=>" stmt+ =># "`(,_2 ,_4)";

  //$ Pattern match expression with terminator.
  satom := pattern_match "endmatch" =># "_1";

  //$ Pattern match expression without terminator.
  //$ Match the expression against each of the branches in the matchings.
  //$ At least one branch must match or the program aborts with a match failure.
  pattern_match := "match" sexpr "with" smatching+ =>#
    "`(ast_match ,_sr (,_2 ,_4))";

  //$ The match argument expression is compared to the pattern.
  //$ If it matches any contained pattern variables are assigned
  //$ the values in the corresponding possition of the expression,
  //$ and expression is evaluated and becomes the return value
  //$ of the whole match.
  smatching := "|" spattern "=>" x[let_pri] =># "`(,_2 ,_4)";

  //$ Match nothing.
  smatching := "|" "=>" sexpr =># "`((pat_none ,_sr) ,_3)";

Patterns

Syntax

spattern := sguard_pattern ("|" sguard_pattern)* =># "(chain 'pat_alt _1 _2)";
sguard_pattern := swith_pattern "when" sexpr =># "`(pat_when ,_sr ,_1 ,_3)";
sguard_pattern := swith_pattern =># "_1";

With pattern

Syntax

swith_pattern := sas_pattern "with" spat_avars =># "`(pat_with ,_sr ,_1 ,_3)";
  spat_avar := sname "=" stypeexpr =># "`(,_1 ,_3)";
  spat_avars := list::commalist1<spat_avar> =># "_1";
swith_pattern := sas_pattern =># "_1";

As pattern

Syntax

sas_pattern := scons_pattern "as" sname =># "`(pat_as ,_sr ,_1 ,_3)";
sas_pattern := scons_pattern =># "_1";

Cons pattern

Syntax

scons_pattern := stuple_cons_pattern "!" scons_pattern
scons_pattern := stuple_cons_pattern
scons_pattern :="[" slist_pattern "]"
scons_pattern :="[" "]"

List pattern

Syntax

slist_pattern := scoercive_pattern "," slist_pattern
slist_pattern := scoercive_pattern
slist_pattern := scoercive_pattern ",," scoercive_pattern

Tuple Cons Pattern

Syntax

stuple_cons_pattern := stuple_pattern ",," stuple_cons_pattern =>#
stuple_cons_pattern := stuple_pattern "<,,>" stuple_cons_pattern =>#
stuple_cons_pattern := stuple_pattern =># "_1"

Tuple Pattern

Syntax

stuple_pattern := scoercive_pattern ("," scoercive_pattern )* =>#

Coercive Pattern

Syntax

scoercive_pattern := sapplicative_pattern "|>" x[sarrow_pri]
scoercive_pattern := sapplicative_pattern ":" x[sarrow_pri]
scoercive_pattern := sapplicative_pattern
scoercive_pattern := stypeexpr ":>>" sname

Applicative Pattern

Syntax

sapplicative_pattern := sctor_name sargument_pattern

private sapplicative_pattern := sctor_name stypeexpr+ sargument_pattern

  //$ The sum type constructor can either be a qualified name...
  private sctor_name := sname

  //$ or it can be a case literal.
  sctor_name := "case" sinteger
  sctor_name := "`" sinteger


sapplicative_pattern := "case" sname sargument_pattern
sapplicative_pattern := "`" sname sargument_pattern
  sargument_pattern := satomic_pattern
sapplicative_pattern := satomic_pattern

Atomic Pattern

Syntax

  satomic_pattern := sname
  satomic_pattern := "?" sname
  satomic_pattern := "val" sname
  satomic_pattern := "#" sctor_name
  satomic_pattern := "#" "case" sname
  satomic_pattern := "`" sname
  satomic_pattern := "case" sinteger
  satomic_pattern := "`" sinteger

  satomic_pattern := "true"
  satomic_pattern := "false"

  satomic_pattern := "_"
  satomic_pattern := "(" spattern ")"
  satomic_pattern := "(" ")"

  satomic_pattern :=  "(" spat_assign ("," spat_assign )* ")"
    spat_assign := sname "=" spattern =># "`(,_1 ,_3)";

  satomic_pattern :=  "(" spat_assign ("," spat_assign )* "|" sname ")"

  satomic_pattern := "$" "(" sexpr ")"
  satomic_pattern := sliteral
  satomic_pattern := sliteral ".." sliteral

}