PreviousUpNext

15.4.569  src/lib/compiler/front/parser/raw-syntax/make-raw-syntax.pkg

## make-raw-syntax.pkg

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



###               "One of the endlessly alluring aspects
###                of mathematics is that its thorniest
###                paradoxes have a way of blooming into
###                beautiful theories."
###
###                                -- Philip Davis 

stipulate
    package lms =  list_mergesort;                              # list_mergesort        is from   src/lib/src/list-mergesort.pkg
    package mrs =  map_raw_syntax;                              # map_raw_syntax        is from   src/lib/compiler/front/parser/raw-syntax/map-raw-syntax.pkg
    package raw =  raw_syntax;                                  # raw_syntax            is from   src/lib/compiler/front/parser/raw-syntax/raw-syntax.pkg
    package sy  =  symbol;                                      # symbol                is from   src/lib/compiler/front/basics/map/symbol.pkg
herein

    package make_raw_syntax
          : Make_Raw_Syntax                                     # Make_Raw_Syntax       is from   src/lib/compiler/front/parser/raw-syntax/make-raw-syntax.api
    {
        include package   fast_symbol;
        include package   raw_syntax;
        include package   raw_syntax_junk;

        fun to_fixity_item   (item, left, right)
            =
            {   item,
                source_code_region => (left, right),
                fixity             => NULL
            };


        # Construct raw syntax for parameter tuple in
        #
        #     \\ (arg1, arg2, ... ) = ...
        #
        fun make_parameter_tuple
                (parameters as p1 ! p2 ! rest, left, right)
                =>
                pattern
                where
                    parameters
                        =
                        map
                            (\\ parameter
                                =  
                                raw::PRE_FIXITY_PATTERN [
                                    to_fixity_item (
                                        raw::VARIABLE_IN_PATTERN
                                            [ parameter ],
                                        left,
                                        right
                                    )
                                ]
                            )
                            parameters;

                    pattern    =  to_fixity_item (
                                      raw::TUPLE_PATTERN parameters,
                                      left,
                                      right
                                  );

                end;

            make_parameter_tuple _
                =>
                {   exception BAD_TUPLE String; 
                    raise exception BAD_TUPLE "parameter tuple must have at least two elements";
                };
        end;

        # Construct raw syntax for argument tuple in
        #
        #     f (arg1, arg2, ... )
        #
        fun make_argument_tuple
                (args as p1 ! p2 ! rest, left, right)
                =>
                expression
                where
                    args
                        =
                        map
                            (\\ arg
                                =  
                                raw::PRE_FIXITY_EXPRESSION [
                                    to_fixity_item (
                                        raw::VARIABLE_IN_EXPRESSION
                                            [ arg ],
                                        left,
                                        right
                                    )
                                ]
                            )
                            args;

                    expression  =  to_fixity_item (
                                      raw::TUPLE_EXPRESSION args,
                                      left,
                                      right
                                  );

                end;

            make_argument_tuple _
                =>
                {   exception BAD_TUPLE String; 
                    raise exception BAD_TUPLE "argument tuple must have at least two elements";
                };
        end;

        # Construct raw syntax for expression tuple in
        #
        #     f (0, "a", ... )
        #
        fun make_expression_tuple
                (expressions as p1 ! p2 ! rest, left, right)
                =>
                expression
                where
                    expressions
                        =
                        map
                            (\\ expression
                                =  
                                raw::PRE_FIXITY_EXPRESSION [
                                    to_fixity_item (
                                        expression,
                                        left,
                                        right
                                    )
                                ]
                            )
                            expressions;

                    expression  =  to_fixity_item (
                                      raw::TUPLE_EXPRESSION  expressions,
                                      left,
                                      right
                                  );

                end;

            make_expression_tuple _
                =>
                {   exception BAD_TUPLE String; 
                    raise exception BAD_TUPLE "expression tuple must have at least two elements";
                };
        end;

        # Construct raw syntax for
        #
        #     \\ (arg1, arg2... ) = expression;
        #
        fun make_tuple_arg_fn_syntax (parameters, expression, left, right)
                =
                function
                where
                    pattern    =  make_parameter_tuple (parameters, left, right);
                    pattern    =  raw::PRE_FIXITY_PATTERN [ pattern ];
                    case_rule  =  raw::CASE_RULE { pattern, expression };
                    function   =  raw::FN_EXPRESSION [ case_rule ];
                end;


        # Construct raw syntax for
        #
        #     \\ arg1 = \\ arg2 = \\ arg3 = ... = expression;
        #
        # (At present we only use it for the
        # one-parameter case, but it doesn't
        # hurt to have it more general.)
        #
        fun make_curried_fn_syntax ([], expression, left, right)
                =>
                expression;

            make_curried_fn_syntax (parameter ! parameters, expression, left, right)
                =>
                function
                where
                    expression =  make_curried_fn_syntax( parameters, expression, left, right );

                    pattern    =  raw::PRE_FIXITY_PATTERN [
                                      to_fixity_item (
                                          raw::VARIABLE_IN_PATTERN
                                              [ parameter ],
                                          left,
                                          right
                                      )
                                  ];

                    case_rule  =  raw::CASE_RULE { pattern, expression };

                    function   =  raw::FN_EXPRESSION [ case_rule ];
                end;
        end;


        fun expression_to_expression_fixity_item
                (expression, left, right)
            =
            {   {   item               => expression,
                    source_code_region => (left, right),
                    fixity                 => NULL
                };
            };


        fun lowercase_id_to_variable_in_expression_fixity_item
                (lowercase_id, left, right)
            =
            {   my (v, f)
                    =
                    make_value_and_fixity_symbols  lowercase_id;

                {   item               => mark_expression (VARIABLE_IN_EXPRESSION [v], left, right),
                    source_code_region => (left, right),
                    fixity                 => THE f
                };
            };


        fun lowercase_id_to_variable_in_pattern_fixity_item
                (lowercase_id, left, right)
            =
            {   my (v, f)
                    =
                    make_value_and_fixity_symbols  lowercase_id;

                {   item               => VARIABLE_IN_PATTERN [v],
                    source_code_region => (left, right),
                    fixity                 => THE f
                };
            };

        # There is a problem in that if we naively
        # translate
        #
        #     for (i=0, j=10; i<10; ++i) { ++j; printf "%d %d\n" i j; }
        #
        # into something like
        # 
        #      {   fun foo (i, j)
        #              =
        #              if   i < 10
        #              then
        #                   { ++j; printf "%d %d\n" i j; };
        #                   ++i;
        #                   foo (i, j);
        #              else
        #                   ();
        #              fi;
        #
        #           foo (0, 10);
        #      };
        #
        # then 'j' won't increment as the user expects due to it being
        # local to a sub-block.  To get around this, we need to combine
        # the user's loop-body block with our added stuff to produce
        #
        #      {   fun foo (i, j)
        #              =
        #              if   i < 10
        #              then
        #                   ++j;
        #                   printf "%d %d\n" i j;
        #                   ++i;
        #                   foo (i, j);
        #              else
        #                   ();
        #              fi;
        #
        #           foo (0, 10);
        #      };
        #
        # 
        # Our job here is to help implement this by, if 'body'
        # is a LET_EXPRESSION, dissolving it into a list of its
        # constituents, to which our caller can then append the new
        # stuff.  If 'body' is not a LET_EXPRESSION, we do very little:
        # 
        fun let_expression_to_declaration_list
                (body, left, right)
            =
            case body

                 # This is the case that will run if
                 # the for loop body is a block:
                 #      
                 PRE_FIXITY_EXPRESSION [ { fixity, source_code_region, item => SOURCE_CODE_REGION_FOR_EXPRESSION (LET_EXPRESSION { declaration, expression },region) } ]
                     =>
                     [ declaration, expression_to_declaration( expression, left, right) ];


                 # This case won't currently run,
                 # but provides some robustness
                 # against changes elsewhere:
                 #      
                 PRE_FIXITY_EXPRESSION [ { fixity, source_code_region, item => LET_EXPRESSION { declaration, expression } } ]
                     =>
                     [ declaration, expression_to_declaration( expression, left, right) ];

                 # This is the case that will run if
                 # the for loop body is not a block:
                 #      
                 _   =>  [ expression_to_declaration  (body, left, right) ];
            esac;


        # Here we expand
        #      for (i = 0; i < 10; ++i) printf "%d\n" i;
        # into
        #      {   fun foo i                    # Actually we call it 'for' not 'foo'.
        #              =
        #              if   i < 10
        #              then
        #                   printf "%d\n" i;
        #                   ++i;
        #                   foo i;
        #              else
        #                   ();
        #              fi;
        #
        #           foo 0;
        #      };
        #
        fun for_loop
                ( (for_tleft, for_tright),
                  inits
                      as 
                      ( ( (lvar as (lvar_expression,  lvar_left, lvar_right)),          # "lvar" == "loop variable" (i)
                          (init as (init_expression,  init_left, init_right))
                        )
                        !
                        more
                      ),
                  test as (test_expression,  test_left, test_right),
                  loops,
                  done as (done_expression,  done_left, done_right),
                  body as (body_expression,  body_left, body_right)
                 )
                =>
                {   # Name our loop function 'for':
                    # Since 'for' is a reserved word,
                    # that eliminates any risk of
                    # shadowing a user variable:
                    #
                    fvar                                                        # "fvar" == "'for'/'foo'/'fun' variable"
                        =
                        (make_raw_symbol "for", for_tleft, for_tright);

                    lvars = map #1 inits;
                    exprs = map #2 inits;

                    tail_call_arguments
                        =
                        case lvars

                             [lvar]
                                 =>
                                 lowercase_id_to_variable_in_expression_fixity_item lvar;


                             (lvar ! more)
                                 =>
                                 {   args = map #1 lvars;
                                     args = map make_value_symbol args; 
                                     make_argument_tuple (args, body_left, body_right);
                                 };


                             []  => { exception IMPOSSIBLE; raise exception IMPOSSIBLE; };
                        esac;


                    init_call_arguments
                        =
                        case exprs

                             [expr]
                                 =>
                                 expression_to_expression_fixity_item   expr;


                             (expr ! more)
                                 =>
                                 {   expressions = map #1 exprs;
                                     make_expression_tuple (expressions, body_left, body_right);
                                 };


                             []  => { exception IMPOSSIBLE; raise exception IMPOSSIBLE; };
                        esac;


                    parameters
                        =
                        case lvars

                             [lvar]
                                 =>
                                 lowercase_id_to_variable_in_pattern_fixity_item  lvar;


                             (lvar ! more)
                                 =>
                                 {   parameters = map #1 lvars;
                                     parameters = map  make_value_symbol  parameters;
                                     make_parameter_tuple (parameters, body_left, body_right);
                                 };


                             []  => { exception IMPOSSIBLE; raise exception IMPOSSIBLE; };
                        esac;


                    # Raw syntax for our tail-recursive call:
                    #
                    tail_call_expression
                        =
                        PRE_FIXITY_EXPRESSION
                            [ lowercase_id_to_variable_in_expression_fixity_item fvar,
                              tail_call_arguments
                            ];

                    # Raw syntax for our initial call:
                    #
                    initial_call_expression
                        =
                        PRE_FIXITY_EXPRESSION
                            [ lowercase_id_to_variable_in_expression_fixity_item fvar,
                              init_call_arguments
                            ];

                    # Our list of loop-step expressions
                    # like   ++i, ++j:
                    #
                    loop_declarations
                        =
                        map #1 (loops: List( (raw::Declaration, Int, Int)));

                    # Synthesize block of code to execute on
                    # non-final iterations.  This consists
                    # of, in order:
                    #    o  The user-supplied loop body:   printf "%d\n" i;
                    #    o  The user-supplied increments:  ++i
                    #    o  The tail-recursive call:       foo i;
                    #
                    then_expression
                        =
                        # NOTE: The list we give to  'block_to_let'
                        #       must be in REVERSE order!
                        #
                        block_to_let
                            (
                                [ expression_to_declaration  (tail_call_expression, body_left, body_right) ]    # foo i
                                @
                                (reverse loop_declarations)                                                             # ++i
                                @
                                (reverse (let_expression_to_declaration_list body))                                     # printf "%d\n" i
                            );

                    if_expression
                        = 
                        IF_EXPRESSION
                            { test_case =>  test_expression,
                              then_case =>  then_expression,
                              else_case =>  done_expression     
                            };

                    fun_apats
                        =
                        [ lowercase_id_to_variable_in_pattern_fixity_item  fvar,
                          parameters
                        ];

                    eq_clause
                        =
                        PATTERN_CLAUSE
                            {
                              patterns    => fun_apats,
                              result_type => NULL,              # constraint
                              expression  => mark_expression (if_expression, body_left, body_right)
                            };

                    pattern_clauses
                        =
                        [ eq_clause ];

                    fun_decls
                        =
                        [ SOURCE_CODE_REGION_FOR_NAMED_FUNCTION
                              ( NAMED_FUNCTION { pattern_clauses, is_lazy => FALSE, kind => PLAIN_FUN, null_or_type => NULL },
                                (body_left, body_right)
                              )
                        ];

                    fun_definition
                        =
                        FUNCTION_DECLARATIONS (fun_decls, NIL);


                    outermost_block
                        =
                        LET_EXPRESSION {
                            declaration => fun_definition,
                            expression  => initial_call_expression
                        };

                    outermost_block;
                };

            for_loop _
                =>
                {   exception       IMPOSSIBLE;
                    raise exception IMPOSSIBLE;
                };
        end;


        # Here we expand a thunk like  {. #a < #b }
        # into equivalent raw syntax   \\ a =  \\ b =  a < b;
        #
        fun thunk
                ( lbrace_dotleft,
                  lbrace_dotright,
                  block_contents,
                  block_contentsleft,
                  block_contentsright,
                  rbraceright
                )
            =
            {
                my (block_contents, parameters)
                    =
                    mrs::map_raw_expression
                        ( block_contents,
                          []
                        )
                        \\ (x, y)
                            =>
                            case x
                                #
                                raw::IMPLICIT_THUNK_PARAMETER (path as [ fastsymbol ])
                                    =>
                                    ( raw::VARIABLE_IN_EXPRESSION path,
                                      fastsymbol ! y
                                    ); 

                                _   =>  (x, y);
                            esac;
                        end;

                aexp    = block_contents;

                dot_exp =  [   {   item               => mark_expression (aexp, block_contentsleft, block_contentsright),
                                   source_code_region => (block_contentsleft, block_contentsright),
                                   fixity             => NULL
                               }
                           ];



                app_exp    = dot_exp;

                expression = PRE_FIXITY_EXPRESSION app_exp;

    # XXX BUGGO FIXME Right now if a #var is used outside of a {. ... }
    #                 it triggers an "IMPOSSIBLE" exception.  We need to
    #                 do something like keep a count of #vars generated
    #                 and consumed during parsetree generation, and if
    #                 the numbers don't match (a single up/down counter
    #                 would suffice, actually), then do a sweep through
    #                 the parsetree turning them into regular variables
    #                 while issuing sane diagnostic messages.

                # If parameter list contains more than one element,
                # sort it alphabetically and merge duplicates.
                # This may reduce it to a one-element list:
                #
                parameters
                    =
                    case parameters
                        #
                        []  =>  parameters;
                        [x] =>  parameters;
                        _   =>  lms::sort_list_and_drop_duplicates
                                    #
                                    sy::symbol_compare
                                    parameters;
                    esac;

                case parameters
                    #
                    [] =>   {   apat  =     {   item               =>  void_pattern,
                                                source_code_region =>  (lbrace_dotleft, lbrace_dotright),
                                                fixity             =>  NULL
                                            };

                                apats   =   [apat];

                                pattern =   PRE_FIXITY_PATTERN apats;

                                eq_rule =   CASE_RULE
                                              {
                                                pattern, 
                                                expression => mark_expression ( expression,
                                                                                block_contentsleft,
                                                                                block_contentsright
                                                                               )
                                              };

                                mark_expression (FN_EXPRESSION [eq_rule], lbrace_dotleft, rbraceright);
                            };

                    [x]  => {

                                make_curried_fn_syntax( parameters, expression, block_contentsleft, block_contentsright );
                            };

                    _    => make_tuple_arg_fn_syntax( parameters, expression, block_contentsleft, block_contentsright );
                esac;
            }; 
    };
end;


## Copyright 1992 by AT&T Bell Laboratories 
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext