## 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.