PreviousUpNext

15.4.568  src/lib/compiler/front/parser/raw-syntax/expand-list-comprehension-syntax.pkg

## expand-list-comprehension-syntax.pkg

# Compiled by:
#     src/lib/compiler/front/parser/parser.sublib

# A list comprehension like
#
#     [ i*i for i in (1..99) where isprime i ];
#
# evaluates to
#
#     [ 1, 4, 9, 25, 49, 121, 169, 289, 361, 529, 841, 961, 1369, 
#       1681, 1849, 2209, 2809, 3481, 3721, 4489, 5041, 5329, 6241, 
#       6889, 7921, 9409
#     ]
#
# The Mythryl compiler treats list comprehensions as
# derived forms, which early in parsing are expanded
# into vanilla Mythryl code.  That is our job here.
#
# We get invoked directly from:
#
#     src/lib/compiler/front/parser/yacc/mythryl.grammar
#


package   expand_list_comprehension_syntax
:         Expand_List_Comprehension_Syntax                                      # Expand_List_Comprehension_Syntax      is from   src/lib/compiler/front/parser/raw-syntax/expand-list-comprehension-syntax.api
{
    include package   fast_symbol;
    include package   raw_syntax;
    include package   raw_syntax_junk;

    List_Comprehension_Clause

        = LIST_COMPREHENSION_RESULT_CLAUSE
              Raw_Expression

        | LIST_COMPREHENSION_FOR_CLAUSE
            {
              pattern:    Case_Pattern,
              expression: Raw_Expression
            }

        | LIST_COMPREHENSION_WHERE_CLAUSE
              Raw_Expression

        ;


    fun make ( (LIST_COMPREHENSION_FOR_CLAUSE { pattern, expression } ) 
             ! remaining_clauses
             )
            =>
            # Here we generate the code for a
            # 'for' clause.  In the example
            #
            #     [ i*i for i in (1..99) where isprime i ];
            #
            # the for clause is the expression
            #
            #     for i in (1..99) 
            #
            # Our synthesized code will look like
            #
            #     {   fun loop__fn ([], result__list)
            #                 =>
            #                 result__list;
            #
            #             loop__fn (  <pattern>                                 # <---- non-boilerplate code.
            #                         !
            #                         remaining__input,
            #
            #                         result__list
            #                      )
            #                 =>
            #                 {   result__list = <make remaining_clauses>;      # <---- non-boilerplate code.
            #                      
            #                     loop__fn (remaining__input, result__list);
            #                 };
            #           
            #         end;
            #
            #         loop__fn
            #           (
            #             <expression>,                                         # <---- non-boilerplate code.
            #
            #             result__list
            #           );
            #     };
            #
            # As indicated above, there are only three parts of the
            # code which are not boilerplate:
            #
            #   o The two spots where we plug in our parameters
            #         pattern
            #         expression
            #
            #   o The spot where we plug in a recursively generated subexpression.
            #
            LET_EXPRESSION
              {
                declaration                                                             # Declaration
                    =>
                    FUNCTION_DECLARATIONS 
                      (
                        [ 
                          NAMED_FUNCTION
                            {
                              kind    => PLAIN_FUN,
                              is_lazy => FALSE,

                              null_or_type => NULL,

                              pattern_clauses
                                  =>
                                  [                                                                                     # List( Pattern_Clause )
                                    # Here we  handle clause
                                    #
                                    #     fun loop__fn ([], result__list)
                                    #             =>
                                    #             result__list;
                                    #
                                    PATTERN_CLAUSE
                                      { patterns
                                            =>
                                            [ { fixity => NULL,
                                                source_code_region => (0,0),
                                                item => VARIABLE_IN_PATTERN [ symbol::make_value_symbol "loop__fn" ]
                                              },

                                              { fixity => NULL,
                                                source_code_region => (0,0),
                                                item
                                                    =>
                                                    TUPLE_PATTERN
                                                      [
                                                        LIST_PATTERN NIL,
                                                        VARIABLE_IN_PATTERN [ symbol::make_value_symbol "result__list" ]
                                                      ]
                                              }
                                            ],

                                        result_type => NULL,

                                        expression
                                            =>
                                            VARIABLE_IN_EXPRESSION
                                              [ symbol::make_value_symbol "result__list" ]
                                      },

                                    # Here we  handle clause
                                    #
                                    #     loop__fn (  <pattern>                                 # <---- non-boilerplate code.
                                    #                 !
                                    #                 remaining__input,
                                    #   
                                    #                 result__list
                                    #              )
                                    #         =>
                                    #         {   result__list = <make remaining_clauses>;      # <---- non-boilerplate code.
                                    #              
                                    #             loop__fn (remaining__input, result__list);
                                    #         };
                                    #
                                    PATTERN_CLAUSE
                                      { patterns
                                            =>
                                            [ { fixity => NULL,
                                                source_code_region => (0,0),
                                                item => VARIABLE_IN_PATTERN [ symbol::make_value_symbol "loop__fn" ]
                                              },

                                              { fixity => NULL,
                                                source_code_region => (0,0),
                                                item
                                                    =>
                                                    TUPLE_PATTERN
                                                      [ APPLY_PATTERN
                                                          {
                                                            constructor                                         # Case_Pattern
                                                              =>
                                                              VARIABLE_IN_PATTERN
                                                                [ symbol::make_value_symbol "!" ],

                                                            argument                                                    # Case_Pattern
                                                              =>
                                                              TUPLE_PATTERN [                                           # List( Case_Pattern )

                /* non boilerplate -----> */                    pattern,

                                                                VARIABLE_IN_PATTERN
                                                                  [ symbol::make_value_symbol "remaining__input" ]
                                                              ]
                                                          },

                                                        VARIABLE_IN_PATTERN [ symbol::make_value_symbol "result__list" ]
                                                      ]
                                              }
                                            ],

                                        result_type => NULL,

                                        expression
                                            =>
                                            # Here we handle:
                                            #   
                                            #     {   result__list = <make remaining_clauses>;  # <---- non-boilerplate code.
                                            #          
                                            #         loop__fn (remaining__input, result__list);
                                            #     };
                                            #   
                                            LET_EXPRESSION
                                              {
                                                # Handle
                                                #
                                                #     result__list = <make remaining_clauses>;
                                                #
                                                declaration                                                             # Declaration
                                                    =>
                                                    VALUE_DECLARATIONS (
                                                      [ NAMED_VALUE {                                                   # List( Named_Value )

                                                          is_lazy => FALSE,

                                                          pattern                                                       # Case_Pattern
                                                              =>        
                                                              VARIABLE_IN_PATTERN
                                                                [ symbol::make_value_symbol "result__list" ],

                                                          expression                                                    # Raw_Expression
                                                              =>
                /* non boilerplate -----> */                  make remaining_clauses
                                                        }
                                                      ],
                                                      []                                                                # List( Typevar_Ref )
                                                    ),                                                                  # VALUE_DECLARATIONS

                                                # Handle
                                                #
                                                #     loop__fn (remaining__input, result__list);
                                                #
                                                expression                                                              # Raw_Expression
                                                    =>
                                                    APPLY_EXPRESSION
                                                      {
                                                        function                                                                # Raw_Expression
                                                          =>
                                                          VARIABLE_IN_EXPRESSION
                                                            [ symbol::make_value_symbol   "loop__fn" ],

                                                        argument                                                                # Raw_Expression
                                                          =>
                                                          TUPLE_EXPRESSION                                                      # List( Raw_Expression )
                                                            [
                                                              VARIABLE_IN_EXPRESSION [ symbol::make_value_symbol "remaining__input" ],
                                                              VARIABLE_IN_EXPRESSION [ symbol::make_value_symbol "result__list"     ]
                                                            ]
                                                      }
                                              }
                                      }
                                  ]
                            }
                        ],
                        []                                                                                              # List( Typevar_Ref )
                      ),

                expression                                                              # Raw_Expression
                    =>
                    # Here we handle:
                    #
                    #     loop__fn
                    #       (
                    #         <expression>,                                     # <---- non-boilerplate code.
                    #
                    #         result__list
                    #       );
                    #
                    APPLY_EXPRESSION
                      {
                        function                                                                # Raw_Expression
                          =>
                          VARIABLE_IN_EXPRESSION
                            [ symbol::make_value_symbol   "loop__fn" ],

                        argument                                                                # Raw_Expression
                          =>
                          TUPLE_EXPRESSION                                                      # List( Raw_Expression )
                            [
    /* non boilerplate -> */  expression,
                              VARIABLE_IN_EXPRESSION [ symbol::make_value_symbol "result__list"     ]
                            ]
                      }
              };

        make (LIST_COMPREHENSION_RESULT_CLAUSE expression  !  remaining_clauses)
            =>
            # Here we generate the code for a
            # result clause.  In the example
            #
            #     [ i*i for i in (1..99) where isprime i ];
            #
            # the result clause is the expression
            #
            #     i*i
            #
            # The result clause comes first in surface syntax,
            # but is always placed at the end of our 'clauses'
            # argument list because it is logically the innermost
            # expression in the generated code and must be
            # handled last.  Hence, 'remaining_clauses' should
            # always be NIL here; we do not currently verify that.
            #
            # The code we generate is very simple:
            #
            #     <expression> ! result__list;
            #
            APPLY_EXPRESSION
              {
                function
                    => 
                    VARIABLE_IN_EXPRESSION
                      [ symbol::make_value_symbol "!" ],

                argument
                    =>
                    TUPLE_EXPRESSION
                      [
                        expression,                     # <----- non boilerplate code.

                        VARIABLE_IN_EXPRESSION
                          [ symbol::make_value_symbol "result__list" ]
                      ]
              };

        make (LIST_COMPREHENSION_WHERE_CLAUSE expression  !  remaining_clauses)
            =>
            # Here we generate the code for a
            # 'where' clause.  In the example
            #
            #     [ i*i for i in (1..99) where isprime i ];
            #
            # the where clause is the expression
            #
            #     where isprime i
            #
            # Our synthesized code will look like
            #
            #     if <expression>
            #         <make remaining_clauses>
            #     else
            #         result__list;
            #     fi
            #
            IF_EXPRESSION
              {
                test_case
                    =>
                    expression,                         # <----- non boilerplate code.

                then_case
                    =>
                    make remaining_clauses,             # <----- non boilerplate code.

                else_case
                    =>
                    VARIABLE_IN_EXPRESSION
                      [ symbol::make_value_symbol "result__list" ]
              };

        make []
            =>
            # This should never happen because a
            #     LIST_COMPREHENSION_RESULT_CLAUSE
            # should always end the 'clauses'
            # arg, and we don't recurse on that case:
            #
            raise exception DIE "Compiler bug";
    end;


    fun expand_list_comprehension_syntax  remaining_clauses
        =
        {   # Here we generate the wrapper code
            #
            #     {   result__list = [];
            #         result__list = reverse <make remaining_clauses>;
            #         result__list;     
            #     };
            #
            # All the actual work is done by
            # the <make remaining_clauses> call:
            #
            LET_EXPRESSION
              {
                declaration                                                             # Declaration
                    =>
                    SEQUENTIAL_DECLARATIONS
                      [
                        VALUE_DECLARATIONS
                          (
                            # result__list = [];
                            #
                            [ NAMED_VALUE
                                { pattern    => VARIABLE_IN_PATTERN [ symbol::make_value_symbol "result__list" ],
                                  expression => LIST_EXPRESSION  NIL,
                                  is_lazy    => FALSE   
                                }
                            ],
                            []
                          ),

                        VALUE_DECLARATIONS
                          (
                            # result__list = [];
                            #
                            [ NAMED_VALUE
                                {
                                  pattern    => VARIABLE_IN_PATTERN
                                                    [ symbol::make_value_symbol "result__list" ],

                                  expression
                                      =>
                                      APPLY_EXPRESSION
                                        {
                                          function                                                              # Raw_Expression
                                              =>
                                              VARIABLE_IN_EXPRESSION
                                                [ symbol::make_value_symbol "reverse" ],

                                          argument                                                              # Raw_Expression
                                              =>
                                              make remaining_clauses            # <---------------- The part that isn't boilerplate.
                                        },

                                  is_lazy    => FALSE   
                                }
                            ],
                            []
                          )
                      ],

                expression                                                              # Raw_Expression
                    =>
                    VARIABLE_IN_EXPRESSION
                      [ symbol::make_value_symbol "result__list" ]
              };
        };
};


## Code by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext