anchor.diff:  Nonterminals
     grammar
     expr_list
  -  exprs
     expr
  -  match_expr
  -  send_expr
  -  bool_expr
  -  bool_op
  -  comp_expr
  -  comp_op
  -  range_expr
     add_expr
  +  mult_expr
  +  pow_expr
  +  unary_expr
  +  terminal_expr
     add_op
  -  mult_expr
     mult_op
  -  pow_expr
     pow_op
  -  declaration
  -  module_decl
  -  class_decl
  -  functions
  -  function
  -  funref_expr
  -  funref
  -  funcall_expr
  -  funcall
  -  function_identifier
  -  function_params
  -  block
  -  class_inst_expr
  -  class_inst
  -  erl_funcall_expr
  -  erl_funcall
  -  unary_expr
  -  unary_op  
  -  max_expr
  -  ivar
  -  clauses
  -  clause
  -  case_expr
  -  receive_expr
  -  after_clause
  -  if_expr
  -  inline_if_expr
  -  if_clause
  -  elseif_clauses
  -  elseif_clause
  -  else_clause
  -  for_expr
  -  try_expr
  -  catch_clauses
  -  catch_clause
  -  throw_expr
  +  unary_op
     number
  -  list
  -  tuple
  -  dict
  -  dict_entries
  -  binary
  -  lambda
  -  list_comprehension
  -  lc_exprs
  -  lc_expr
     .
     
   Terminals
  -  true false nil float integer string regexp atom
  -  identifier punctuated_identifier constant module class
  -  eol def fun do 'end' 'case' when 'if' elseif else unless 
  -  'and' 'or' 'not' 'try' 'catch' throw for in 'receive' 'after'
  -  '(' ')' '[' ']' '{' '}' '|' '<<' '>>'
  -  '+' '-' '*' '/' '%' '**' '!'
  -  '.' '..' ',' '::' '@' '&'
  -  '=' '==' '===' '!=' '>' '<' '=>' '<=' '>=' '<-'
  +  eol '(' ')'
  +  float integer
  +  '+' '-' '*' '/' '%' '**'
     .
   
   Rootsymbol grammar.
  
positive.code: %% Unary operators
  unary_op -> '+'   : '$1'.
  unary_op -> '-'   : '$1'.
  unary_op -> 'not' : '$1'.
  
  %% Declarations
  declaration -> module_decl : '$1'.
  declaration -> class_decl : '$1'.
  
  %% Module declaration
  module_decl -> module constant eol functions 'end' : {module, line('$1'), '$2', '$4'}.
  
  %% Class declaration
  class_decl -> class constant eol functions 'end' : {class, line('$1'), '$2', '$4'}.
  class_decl -> class constant '<' constant eol functions 'end' : {class, line('$1'), '$2', '$4', '$6'}.
  
  %% Functions
  functions -> function : ['$1'].
  functions -> function eol : ['$1'].
  functions -> eol functions : '$2'.
  functions -> function eol functions : ['$1'|'$3'].
  
  %% Function definitions
  function -> def function_identifier eol expr_list 'end' : {function, line('$1'), '$2', [], {nil, line('$2')}, '$4'}.
  function -> def function_identifier '(' ')' eol expr_list 'end' : {function, line('$1'), '$2', [], {nil, line('$2')}, '$6'}.
  function -> def function_identifier '(' exprs ')' eol expr_list 'end' : {function, line('$1'), '$2', '$4', {nil, line('$2')}, '$7'}.
  
  %% Function definitions with block arguments
  function -> def function_identifier '(' '&' identifier ')' eol expr_list 'end' : {function, line('$1'), '$2', [], '$5', '$8'}.
  function -> def function_identifier '(' function_params '&' identifier ')' eol expr_list 'end' : {function, line('$1'), '$2', '$4', '$6', '$9'}.
  
  %% FIXME: workaround for shift/reduce conflicts involving ',' and block args
  %% Doesn't handle newlines properly
  function_params -> expr ',' : ['$1'].
  function_params -> expr ',' function_params : ['$1'|'$3'].
  
  %% Function identifiers
  function_identifier -> identifier : function_identifier('$1').
  function_identifier -> punctuated_identifier : function_identifier('$1').
  function_identifier -> class : function_identifier('$1').
  
  %% Function references
  funref -> funcall_expr '.' function_identifier : {funref, line('$2'), '$1', '$3'}.
  
  %% Local function calls
  funcall -> function_identifier '(' ')' : {funcall, line('$2'), '$1', [], {atom, line('$2'), nil}}.
  funcall -> function_identifier '(' exprs ')' : {funcall, line('$2'), '$1', '$3', {atom, line('$2'), nil}}.
  
  %% Remote function calls
  funcall -> funcall_expr '.' function_identifier '(' ')' : {funcall, line('$2'), '$1', '$3', [], {atom, line('$2'), nil}}.
  funcall -> funcall_expr '.' function_identifier '(' exprs ')' : {funcall, line('$2'), '$1', '$3', '$5', {atom, line('$2'), nil}}.
  funcall -> funcall_expr '[' expr ']' : {funcall, line('$2'), '$1', {identifier, line('$2'), '[]'}, ['$3'], {atom, line('$2'), nil}}.
  funcall -> funcall_expr '.' function_identifier '[' expr ']' : {funcall, line('$2'), {funcall, line('$2'), '$1', '$3', [], {atom, line('$2'), nil}}, {identifier, line('$2'), '[]'}, ['$5'], {atom, line('$2'), nil}}.
  
  %% Async function calls
  funcall -> funcall_expr '<-' function_identifier '(' ')' : {cast, line('$2'), '$1', '$3', [], {atom, line('$2'), nil}}.
  funcall -> funcall_expr '<-' function_identifier '(' exprs ')' : {cast, line('$2'), '$1', '$3', '$5', {atom, line('$2'), nil}}.
  
  %% Local function calls with blocks
  funcall -> function_identifier block : {funcall, line('$2'), '$1', [], '$2'}.
  funcall -> function_identifier '(' ')' block : {funcall, line('$2'), '$1', [], '$4'}.
  funcall -> function_identifier '(' exprs ')' block : {funcall, line('$2'), '$1', '$3', '$5'}.
  
  %% Remote function calls with blocks
  funcall -> funcall_expr '.' function_identifier block : {funcall, line('$2'), '$1', '$3', [], '$4'}.
  funcall -> funcall_expr '.' function_identifier '(' ')' block : {funcall, line('$2'), '$1', '$3', [], '$6'}.
  funcall -> funcall_expr '.' function_identifier '(' exprs ')' block : {funcall, line('$2'), '$1', '$3', '$5', '$7'}.
  
  % Async function calls with blocks
  funcall -> funcall_expr '<-' function_identifier block : {cast, line('$2'), '$1', '$3', [], '$4'}.
  funcall -> funcall_expr '<-' function_identifier '(' ')' block : {cast, line('$2'), '$1', '$3', [], '$6'}.
  funcall -> funcall_expr '<-' function_identifier '(' exprs ')' block : {cast, line('$2'), '$1', '$3', '$5', '$7'}.
  
  %% Local function calls with lambdas passed as blocks
  funcall -> function_identifier '(' '&' identifier ')' : {funcall, line('$2'), '$1', [], '$4'}.
  funcall -> function_identifier '(' function_params '&' identifier ')' : {funcall, line('$2'), '$1', '$3', '$5'}.
  
  % Remote function calls with lambdas passed as blocks
  funcall -> funcall_expr '.' function_identifier '(' '&' identifier ')' : {funcall, line('$2'), '$1', '$3', [], '$6'}.
  funcall -> funcall_expr '.' function_identifier '(' function_params '&' identifier ')' : {funcall, line('$2'), '$1', '$3', '$5', '$7'}.
  
  % Async function calls with lambdas passed as blocks
  funcall -> funcall_expr '<-' function_identifier '(' '&' identifier ')' : {cast, line('$2'), '$1', '$3', [], '$6'}.
  funcall -> funcall_expr '<-' function_identifier '(' function_params '&' identifier ')' : {cast, line('$2'), '$1', '$3', '$5', '$7'}.
  
  %% Class instantiations
  class_inst -> constant '(' ')' : {class_inst, line('$2'), '$1', []}.
  class_inst -> constant '(' exprs ')' : {class_inst, line('$2'), '$1', '$3'}.
  
  %% Class instantiations with blocks
  class_inst -> constant block : {funcall, line('$2'), '$1', [], '$2'}.
  class_inst -> constant '(' ')' block : {funcall, line('$2'), '$1', [], '$4'}.
  class_inst -> constant '(' exprs ')' block : {funcall, line('$2'), '$1', '$3', '$5'}.
  
  %% Blocks
  
  block -> '{' expr_list '}' : {lambda, line('$1'), [], '$2'}.
  block -> '{' '|' exprs '|' expr_list '}' : {lambda, line('$1'), '$3', '$5'}.
  
  block -> do expr_list 'end' : {lambda, line('$1'), [], '$2'}.
  block -> do '|' exprs '|' expr_list 'end' : {lambda, line('$1'), '$3', '$5'}.
  
  %% Erlang function calls
  erl_funcall -> identifier '::' identifier '(' ')' : {erl_funcall, line('$2'), '$1', '$3', []}.
  erl_funcall -> identifier '::' identifier '(' exprs ')' : {erl_funcall, line('$2'), '$1', '$3', '$5'}.
  
  %% Numbers
  number -> float : '$1'.
  number -> integer : '$1'.
  
  %% Lists
  list -> '[' ']' : {list, line('$1'), []}.
  list -> '[' exprs ']' : {list, line('$1'), '$2'}.
  
  %% Tuples
  tuple -> '(' ')' : {tuple, line('$1'), []}.
  tuple -> '(' expr ',' ')' : {tuple, line('$1'), ['$2']}.
  tuple -> '(' expr ',' exprs ')': {tuple, line('$1'), ['$2'|'$4']}.
  
  %% Dicts
  dict -> '{' '}' : {dict, line('$1'), []}.
  dict -> '{' dict_entries '}' : {dict, line('$1'), '$2'}.
  
  dict_entries -> bool_expr '=>' expr : [{'$1','$3'}].
  dict_entries -> bool_expr '=>' expr ',' dict_entries : [{'$1','$3'}|'$5'].
  
  %% Binaries
  binary -> '<<' string '>>' : {binary, line('$1'), '$2'}.
  
  %% Lambdas
  lambda -> fun '{' expr_list '}' : {lambda, line('$1'), [], '$3'}.
  lambda -> fun '(' ')' '{' expr_list '}' : {lambda, line('$1'), [], '$5'}.
  lambda -> fun '(' exprs ')' '{' expr_list '}' : {lambda, line('$1'), '$3', '$6'}.
  lambda -> fun do expr_list 'end' : {lambda, line('$1'), [], '$3'}.
  lambda -> fun '(' ')' do expr_list 'end' : {lambda, line('$1'), [], '$5'}.
  lambda -> fun '(' exprs ')' do expr_list 'end' : {lambda, line('$1'), '$3', '$6'}.
    
  %% List comprehensions
  list_comprehension -> '[' expr '|' lc_exprs ']' : {lc, line('$1'), '$2', '$4'}.
  
  lc_exprs -> lc_expr : ['$1'].
  lc_exprs -> lc_expr ',' lc_exprs: ['$1'|'$3'].
  
  lc_expr -> expr : '$1'.
  lc_expr -> expr 'in' expr : {generate, line('$2'), '$1', '$3'}.
  
  Erlang code.
  
  
negative.code: mult_expr -> pow_expr mult_op mult_expr : {op, line('$1'), op('$2'), '$1', '$3'}.
  mult_expr -> pow_expr : '$1'.
  
  pow_expr -> unary_expr pow_op pow_expr : {op, line('$1'), op('$2'), '$1', '$3'}.
  pow_expr -> unary_expr : '$1'.
  
  unary_expr -> unary_op unary_expr : {op, line('$1'), op('$1'), '$2'}.
  unary_expr -> terminal_expr : '$1'.
  
  % Terminals
  terminal_expr -> number     : '$1'.
  terminal_expr -> '(' expr ')' : '$2'.
  
  %% Addition operators
  add_op -> '+' : '$1'.
  