## typecheck-api.pkg -- typecheck an API.
# Compiled by:
#
src/lib/compiler/front/typer/typer.sublib# The center of the typechecker is
#
#
src/lib/compiler/front/typer/main/type-package-language-g.pkg#
# -- see it for a higher-level overview.
#
# In this file we handle the subtask of
# analysing a package or generic api
# and returning an appropriate symbol table
# entry. (Note that symbolmapstack-entry.pkg
# has NAMED_API of mld::Api
# and NAMED_GENERIC_API of mld::Generic_Api
# matching our two return values below.)
#
# XXX BUGGO FIXME Should we rename these
# to something like makeSymbolmapstackEntryFor... ?
stipulate
package mtt = more_type_types; # more_type_types is from
src/lib/compiler/front/typer/types/more-type-types.pkg package err = error_message; # error_message is from
src/lib/compiler/front/basics/errormsg/error-message.pkg package eu = typer_junk; # typer_junk is from
src/lib/compiler/front/typer/main/typer-junk.pkg package ex = expand_type; # expand_type is from
src/lib/compiler/front/typer/modules/expand-type.pkg package fst = find_in_symbolmapstack; # find_in_symbolmapstack is from
src/lib/compiler/front/typer-stuff/symbolmapstack/find-in-symbolmapstack.pkg package id = inlining_data; # inlining_data is from
src/lib/compiler/front/typer-stuff/basics/inlining-data.pkg package ip = inverse_path; # inverse_path is from
src/lib/compiler/front/typer-stuff/basics/symbol-path.pkg package lms = list_mergesort; # list_mergesort is from
src/lib/src/list-mergesort.pkg package mj = module_junk; # module_junk is from
src/lib/compiler/front/typer-stuff/modules/module-junk.pkg package mld = module_level_declarations; # module_level_declarations is from
src/lib/compiler/front/typer-stuff/modules/module-level-declarations.pkg package raw = raw_syntax; # raw_syntax is from
src/lib/compiler/front/parser/raw-syntax/raw-syntax.pkg package spc = stamppath_context; # stamppath_context is from
src/lib/compiler/front/typer-stuff/modules/stamppath-context.pkg package sxe = symbolmapstack_entry; # symbolmapstack_entry is from
src/lib/compiler/front/typer-stuff/symbolmapstack/symbolmapstack-entry.pkg package sy = symbol; # symbol is from
src/lib/compiler/front/basics/map/symbol.pkg package syp = symbol_path; # symbol_path is from
src/lib/compiler/front/typer-stuff/basics/symbol-path.pkg package syx = symbolmapstack; # symbolmapstack is from
src/lib/compiler/front/typer-stuff/symbolmapstack/symbolmapstack.pkg package tro = typerstore; # typerstore is from
src/lib/compiler/front/typer-stuff/modules/typerstore.pkg package ts = type_junk; # type_junk is from
src/lib/compiler/front/typer-stuff/types/type-junk.pkg package tt = type_type; # type_type is from
src/lib/compiler/front/typer/main/type-type.pkg package tdt = type_declaration_types; # type_declaration_types is from
src/lib/compiler/front/typer-stuff/types/type-declaration-types.pkg package vh = varhome; # varhome is from
src/lib/compiler/front/typer-stuff/basics/varhome.pkg #
include package module_level_declarations; # module_level_declarations is from
src/lib/compiler/front/typer-stuff/modules/module-level-declarations.pkgherein
package type_api
: (weak) Type_Api # Type_Api is from
src/lib/compiler/front/typer/main/type-api.api {
# Debugging boilerplate:
#
fun bug msg = error_message::impossible ("type_api: " + msg);
say = control_print::say;
debugging = typer_control::type_api_debugging; # set_control "typechecker::typecheck_api_debugging" "TRUE";
#
fun if_debugging_say (msg: String)
=
if *debugging
say msg;
say "\n";
fi;
#
fun debug_print x
=
typer_debugging::debug_print debugging x;
include package typer_debugging;
debug_print = (\\ x = debug_print debugging x);
fun unparse_api_expression
(
msg: String,
declaration: raw_syntax::Api_Expression,
symbolmapstack: symbolmapstack::Symbolmapstack
)
=
if *debugging
print "\n";
print msg;
pp = standard_prettyprinter::make_standard_prettyprinter_into_file "/dev/stdout" [];
pps = pp.pp;
unparse_raw_syntax::unparse_api_expression
(symbolmapstack, NULL)
pp
(declaration, 100);
pp.flush ();
pp.close ();
print "\n";
fi;
result_id = symbol::make_package_symbol "<result_package>";
# utility stuff
#
fun strip_mark_sig (raw::SOURCE_CODE_REGION_FOR_API (api_expression, source_code_region'), _)
=>
strip_mark_sig (api_expression, source_code_region');
strip_mark_sig x
=>
x;
end;
#
fun find_package_definition_via_symbol_path (symbolmapstack, symbol_path, stamppath_context, err)
=
{ package_definition
=
fst::find_package_definition_via_symbol_path (symbolmapstack, symbol_path, err);
case package_definition
#
VARIABLE_PACKAGE_DEFINITION _
=>
package_definition;
CONSTANT_PACKAGE_DEFINITION a_package
=>
case a_package
mld::ERRONEOUS_PACKAGE => package_definition;
mld::A_PACKAGE { an_api, ... }
=>
case (spc::find_stamppath_for_package (stamppath_context, mj::packagestamp_of a_package) )
#
NULL => package_definition;
THE stamppath
=>
VARIABLE_PACKAGE_DEFINITION (an_api, stamppath);
esac;
mld::PACKAGE_API _ => bug "find_package_definition_via_symbol_path";
esac;
esac;
};
# Code for processing 'where' definitions
#
fun closed_definitions definitions
=
not (list::exists
#
\\ ( (_, EXTERNAL_DEFINITION_OF_TYPE { extdef_is_relative => TRUE, ... } )
| (_, EXTERNAL_DEFINITION_OF_PACKAGE (_, VARIABLE_PACKAGE_DEFINITION _))
)
=> TRUE;
_ => FALSE;
end
#
definitions
);
# Definitions = prepare where_definitions /* sorted by initial path symbol */
#
fun sort_definitions (definitions)
=
{ fun gt ([], _) => FALSE;
gt (_, []) => TRUE;
#
gt (s1 ! _, s2 ! _)
=>
symbol::symbol_gt (s1, s2);
end;
lms::sort_list
#
(\\ ((p1, d1), (p2, d2))
=
gt (p1, p2)
)
#
definitions;
};
#
fun prepare_definitions where_definitions
=
sort_definitions (
map
\\ (def as EXTERNAL_DEFINITION_OF_PACKAGE (syp::SYMBOL_PATH path, _)) => (path, def);
(def as EXTERNAL_DEFINITION_OF_TYPE { extdef_path => syp::SYMBOL_PATH path, ... } ) => (path, def);
end
#
where_definitions
);
#
fun push_definitions (elements, definitions, error, make_stamp)
=
loop (elements, definitions, NIL)
where
fun find_definitions (symbol, definitions) # Returns a pair "(localDefinitions, otherDefinitions)"
=
find_loop (definitions, NIL, NIL)
where
fun find_loop ((item as (s ! rest, def)) ! definitions, this, others)
=>
if (sy::eq (s, symbol))
#
find_loop (definitions, (rest, def) ! this, others);
else
if (sy::symbol_gt (s, symbol))
#
(sort_definitions this, (reverse others @ (item ! definitions)));
else
find_loop (definitions, this, item ! others);
fi;
fi;
find_loop (NIL, this, others)
=>
(sort_definitions this, reverse others);
find_loop _
=>
bug "push_definitions: find_definitions: find_loop";
end; # fun find_loop
end; # where
#
fun apply_type_def
(
type_spec as TYPE_IN_API { module_stamp, type=>spec, ... },
#
EXTERNAL_DEFINITION_OF_TYPE { extdef_path => symbol_path,
extdef_type => type,
...
}
)
=>
case spec
#
tdt::SUM_TYPE
{
kind,
arity,
is_eqtype => eqp,
namepath => tpath,
...
}
=>
case kind
#
tdt::FORMAL
=>
if (ts::arity_of_type type == arity)
#
TYPE_IN_API
{
module_stamp,
type,
is_a_replica => FALSE,
scope => syp::length symbol_path
};
# David B MacQueen: we should check at this point that the
# definition represented by
# EXTERNAL_DEFINITION_OF_TYPE#type
# has the appropriate equality property to match
# the spec, but this does not seem to be feasible
# without excessive work.
#
# The problem is computing whether type is
# an equality type, when it contains
# PATHtypes, as in bug1433.2.sml. XXX BUGGO FIXME
else
error ("where type definition has wrong arity: " + syp::to_string symbol_path);
type_spec;
fi;
tdt::SUMTYPE _
=>
# We allow a 'where' type definition to constrain
# a sumtype spec, if right-hand-side sumtype is
# "compatible" with spec.
#
# We use an extremely weak notion of compatibility -- same arity.
#
# The definition should be a compatible sumtype
# (not checked here!), making this an indirect
# sumtype replication spec. XXX BUGGO FIXME
# type is NAMED_TYPE!
# This will have to be unwrapped when the
# api is macro expanded (bugs 1364, 1432).
if (arity == ts::arity_of_type type)
#
TYPE_IN_API { module_stamp,
type,
is_a_replica => TRUE,
scope => syp::length symbol_path # ???
};
else
error ( "where type definition has wrong arity: "
+ syp::to_string symbol_path
);
type_spec;
fi;
_ => bug "elabsig: SUM_TYPE is neither FORMAL nor DATA";
esac;
tdt::NAMED_TYPE _
=>
{ error
( "'where' type definition applied to definitional specification: "
+ syp::to_string symbol_path
);
type_spec;
};
_ => bug "applyTypeConstructorDef (1)";
esac;
apply_type_def _ => bug "applyTypeConstructorDef (2)";
end; # fun apply_type_def
#
fun apply_package_definitions (
spec as PACKAGE_IN_API { module_stamp, an_api, definition, slot },
definitions
)
=>
# In the case where the 'where' def has a different api,
# could propagate definitions in to the components,
# as is done currently during typechecked_package.
#
# If a VARIABLE_PACKAGE_DEFINITION applies to a spec
# with a different api, this propagation of
# VAR definitions into the components means that
# the spec api is open -- i.e. that the
# "closed" field should become FALSE.
#
# This is currently being handled within macro_expand.
#
case definition
#
THE _
=>
{ error "where defn applied to definitional spec";
spec;
};
NULL => case definitions
#
(NIL, EXTERNAL_DEFINITION_OF_PACKAGE (symbol_path, package_definition)) ! rest
=>
# Applies directly
case rest
#
NIL => PACKAGE_IN_API
{
module_stamp,
an_api,
definition => THE (package_definition, syp::length symbol_path),
slot
};
_ => { error "redundant where definitions";
#
spec;
};
esac;
_ => PACKAGE_IN_API
{
module_stamp,
definition => NULL,
slot,
an_api => add_where_definitions ( an_api, definitions, NULL, error, make_stamp )
};
esac;
esac;
apply_package_definitions _
=>
bug "apply_package_definitions";
end; # fun apply_package_definitions
#
fun loop (NIL, definitions, elements) # All elements processed.
=>
case definitions
#
NIL =>
reverse elements; # All definitions consumed.
_ => # Left-over definitions.
{ apply
\\ (_, EXTERNAL_DEFINITION_OF_TYPE { extdef_path, ... } )
=>
(error (cat [ "unbound left hand side in 'where' type: ",
syp::to_string extdef_path
]
)
);
(_, EXTERNAL_DEFINITION_OF_PACKAGE (p, _))
=>
(error
(cat [ "unbound left hand side in 'where' (package): ",
syp::to_string p
]
)
);
end
#
definitions;
reverse elements;
};
esac;
loop (elements, NIL, elements') # All definitions processed.
=>
reverse elements' @ elements;
loop ((element as (symbol, type_spec as TYPE_IN_API _)) ! elements, definitions, elements')
=>
{ (find_definitions (symbol, definitions))
->
(localdefinitions, otherdefinitions);
case localdefinitions
#
[ (NIL, type_definition) ]
=>
loop (
elements,
otherdefinitions,
( symbol,
apply_type_def (type_spec, type_definition)
)
!
elements'
);
NIL => loop (elements, definitions, element ! elements');
_ => { error ("multiple where definitions for " + sy::name symbol);
loop (elements, otherdefinitions, element ! elements');
};
esac;
};
loop ((element as (symbol, sspec as PACKAGE_IN_API _)) ! elements, definitions, elements')
=>
{ my (localdefinitions, otherdefinitions) = find_definitions (symbol, definitions);
case localdefinitions
NIL /* no definitions apply to this element */
=>
loop (elements, otherdefinitions, element ! elements');
_
=>
loop (
elements,
otherdefinitions,
( symbol,
apply_package_definitions (sspec, localdefinitions)
)
!
elements'
);
esac;
};
loop (element ! elements, definitions, elements')
=>
loop (elements, definitions, element ! elements');
end; # fun loop
end # where (== fun push_definitions)
# Does this belong in module_junk or typer_junk? David B MacQueen XXX BUGGO FIXME
#
also
fun add_where_definitions (an_api, NIL, name_or_null, error, make_stamp)
=>
bug "addWhereDefinitions";
add_where_definitions(
an_api as API {
stamp,
name,
closed,
contains_generic,
stub,
symbols,
api_elements,
property_list,
type_sharing,
package_sharing
},
where_definitions,
name_or_null,
error,
make_stamp
)
=>
API { stamp => make_stamp(), # Give modified api a new stamp -- could stack stamps
name => case name_or_null
THE _ => name_or_null; # New name provided.
NULL => name; # Retain old name (?)
esac,
closed => closed and closed_definitions where_definitions,
api_elements => push_definitions (api_elements, where_definitions, error, make_stamp),
property_list => property_list::make_property_list (),
stub => NULL,
contains_generic,
type_sharing,
symbols,
package_sharing
};
add_where_definitions _ => bug "addWhereDefinitions";
end; # fun add_where_definitions
#
fun local_path (symbol_path, api_elements)
=
{ mj::get_api_element (api_elements, syp::first symbol_path);
TRUE;
}
except
mj::UNBOUND _
=
FALSE;
parameter_id = sy::make_package_symbol "<parameter>";
generic_id = sy::make_generic_symbol "<generic>";
# Elements are added in reverse order, so at the end, the elements
# lists must be reversed. In the long run, this could be changed
# if we move to a dictionary-based representation of the elements.
#
fun add_element (x, elements)
=
x ! elements;
#
fun add (symbol, spec, elements, err)
=
# Check to see whether symbol is already bound in the given dictionary
#
{ if_debugging_say (">>type_api::add: " + sy::name symbol);
if ( list::exists
(\\ (n, _) = sy::eq (symbol, n))
elements
)
# If so, this indicates a duplicate specification error
err
err::ERROR
( "duplicate definitions for "
+ sy::name_space_to_string (sy::name_space symbol)
+ " "
+ sy::name symbol
+ " in api"
)
err::null_error_body;
elements;
else
# Otherwise, add the symbol:
add_element ((symbol, spec), elements);
fi;
};
# Typechecking 'where' type clauses around apis:
#
fun typecheck_where
(
api_expression,
symbolmapstack,
stamppath_context,
make_stamp,
error,
source_code_region
)
=
loop (api_expression, NIL, source_code_region)
where
# Arg1 holds the input raw syntax tree that we are consuming;
# Arg2 holds the result list we are generating (initially NIL)
# Arg3 is just diagnostic support.
#
fun loop (raw::API_WITH_WHERE_SPECS (api_expression, whspecs), resultlist, source_code_region)
=>
loop1 (whspecs, resultlist)
where
# Arg1 is the input list of 'where' api constraints which we are consuming;
# Arg2 is the result list which we are accumulating:
#
fun loop1 (NIL, resultlist) # No more input, so done with loop1.
=>
loop (api_expression, resultlist, source_code_region);
loop1 (raw::WHERE_TYPE (path, typevars, type) ! rest, resultlist)
=>
{ symbol_path = syp::SYMBOL_PATH path;
#
if_debugging_say ("typecheckWhere: WHERE_TYPE: " + syp::to_string symbol_path);
typevars = tt::type_typevar_list (typevars, error, source_code_region);
arity = length typevars;
(tt::type_type (type, symbolmapstack, error, source_code_region))
->
(typoid, typevars');
eu::check_bound_typevars (typevars', typevars, error source_code_region);
ts::resolve_typevars_to_typescheme_slots typevars;
ts::drop_macro_expanded_indirections_from_type typoid;
stamp = make_stamp ();
namepath = ip::INVERSE_PATH [list::last path];
strict = eu::calculate_strictness (arity, typoid);
(mj::relativize_typoid stamppath_context typoid)
->
(nty, relative);
type = tdt::NAMED_TYPE { typescheme => tdt::TYPESCHEME { arity, body => nty },
stamp,
namepath,
strict
};
loop1 (
#
rest,
#
EXTERNAL_DEFINITION_OF_TYPE
{
extdef_path => symbol_path,
extdef_type => type,
extdef_is_relative => relative
}
!
resultlist
);
};
loop1 (raw::WHERE_PACKAGE (left_hand_side, right_hand_side) ! rest, resultlist)
=>
( { left_hand_side_path = syp::SYMBOL_PATH left_hand_side;
package_definition
=
find_package_definition_via_symbol_path (
#
symbolmapstack,
syp::SYMBOL_PATH right_hand_side,
stamppath_context,
error source_code_region
);
package_definition
=
# Remove varhome & inline info (bug 1201):
#
case package_definition
CONSTANT_PACKAGE_DEFINITION (A_PACKAGE { an_api, typechecked_package, ... } )
=>
CONSTANT_PACKAGE_DEFINITION (A_PACKAGE { an_api,
typechecked_package,
varhome => varhome::null_varhome,
inlining_data => id::NIL
}
);
_ => package_definition;
esac;
loop1 (
rest,
EXTERNAL_DEFINITION_OF_PACKAGE (left_hand_side_path, package_definition) ! resultlist
);
}
except
syx::UNBOUND
=
{ error
source_code_region
err::ERROR
"unbound right-hand side in where clause"
err::null_error_body;
loop1 (rest, resultlist);
}
);
end; # fun loop1
end; # where
loop (raw::SOURCE_CODE_REGION_FOR_API (api_expression, source_code_region), resultlist, _)
=>
loop (api_expression, resultlist, source_code_region);
loop (api_expression, resultlist, source_code_region)
=>
(api_expression, resultlist, source_code_region);
end; # fun loop
end; # where
# typecheck_body is the main function for elaborating api bodies.
#
# Its return type is
#
# ( elements, List of (name_symbol, type) pairs, one per declaration.
# symbols, List of symbols, each naming one element.
# List( TypeSharingSpec ),
# List( StructureSharingSpec ),
# Bool 'contains_generic'
# )
#
# It does not need to return an updated symbol table.
#
fun typecheck_body (
api_elements,
symbolmapstack,
typerstore,
api_context,
stamppath_context,
source_code_region,
per_compile_stuff as { make_fresh_stamp, error_fn, ... } : eu::Per_Compile_Stuff
)
=
{ # Typecheck type specification --- return
# (symbolmapstack, elements, symbols)
#
fun typecheck_type_definition_in_api (tspecs, symbolmapstack, elements, symbols, eqspec, source_code_region)
=
{ if_debugging_say ">typecheck_type_definition_in_api";
#
err = error_fn source_code_region;
#
is_eqtype
=
if eqspec tdt::e::YES;
else tdt::e::INDETERMINATE;
fi;
#
loop (tspecs, symbolmapstack, elements, symbols)
where
fun loop ([], symbolmapstack, elements, symbols)
=>
(symbolmapstack, elements, symbols);
loop ( (name, typevars, abbrev) ! rest, symbolmapstack, elements, symbols)
=>
{ typevars
=
tt::type_typevar_list (
typevars,
error_fn,
source_code_region
);
arity = length typevars;
type = case abbrev
#
THE definition
=>
if eqspec
#
error_fn
source_code_region
err::ERROR
( "eqtype spec with a definition: "
+ sy::name name
)
err::null_error_body;
tdt::ERRONEOUS_TYPE;
else
(tt::type_type (definition, symbolmapstack, error_fn, source_code_region))
->
(type, typevars');
eu::check_bound_typevars (typevars', typevars, err);
ts::resolve_typevars_to_typescheme_slots typevars;
ts::drop_macro_expanded_indirections_from_type type;
(mj::relativize_typoid stamppath_context type)
->
(nty, _);
tdt::NAMED_TYPE
{
stamp => make_fresh_stamp (),
namepath => ip::INVERSE_PATH [name],
strict => eu::calculate_strictness (arity, type),
#
typescheme => tdt::TYPESCHEME { arity, body=>nty }
};
fi;
NULL => tdt::SUM_TYPE
{
stamp => make_fresh_stamp (),
namepath => ip::INVERSE_PATH [name],
is_eqtype => REF is_eqtype,
#
kind => tdt::FORMAL,
stub => NULL,
arity
};
esac;
module_stamp = make_fresh_stamp ();
etyc = tdt::TYPE_BY_STAMPPATH
{
stamppath => [ module_stamp ],
namepath => ip::INVERSE_PATH [ name ],
arity
};
symbolmapstack' = syx::bind (name, sxe::NAMED_TYPE etyc, symbolmapstack);
ts = TYPE_IN_API { is_a_replica => FALSE,
scope => 0,
module_stamp,
type
};
elements' = add (name, ts, elements, err);
loop (rest, symbolmapstack', elements', name ! symbols);
};
end; # fun loop
end; # where
};
#
fun all_but_last list
=
list::take_n (list, list::length list - 1);
# Typecheck sumtype replication specifications.
#
# Uses NAMED_TYPE wrappings of
# the right-hand side sumtype in the resulting specs.
#
# Need to check that this will
# do the "right thing" in macro_expand. XXX BUGGO FIXME
#
fun typecheck_sumtype_replication (name, symbols, symbolmapstack, elements, symbolsx, source_code_region)
=
{ type = find_in_symbolmapstack::find_type_via_symbol_path (
symbolmapstack,
syp::SYMBOL_PATH symbols,
error_fn source_code_region
);
# right-hand side is not local to current (outermost) api
#
fun no_sumtype ()
=
{ error_fn
source_code_region
err::ERROR
"right-hand side of sumtype replication spec not a sumtype"
err::null_error_body;
(symbolmapstack, elements, symbolsx);
};
case type
#
tdt::TYPE_BY_STAMPPATH { stamppath, arity, ... }
=>
{
# Local to current outermost api
# Get the spec, using expandTypeConstructor.
# Check that it is a sumtype:
api_context = elements ! api_context;
type' = ex::expand_type (
type,
api_context,
typerstore
);
case type'
#
tdt::SUM_TYPE { kind, ... }
=>
case kind
#
tdt::SUMTYPE { index,
family as { members, ... },
stamps,
free_types,
...
}
=>
{ stamp = vector::get (stamps, index);
(vector::get (members, index))
->
{ name_symbol, arity, valcons, an_api, is_lazy, ... };
module_stamp = make_fresh_stamp (); # Add the type.
# Spec uses wrapped version of the TYPE_BY_STAMPPATH!!
#
tspec = TYPE_IN_API
{
is_a_replica => TRUE,
scope => 0,
type => ts::wrap_definition (
type,
make_fresh_stamp ()
),
module_stamp
};
elements'
=
add (name, tspec, elements, error_fn source_code_region);
etyc = tdt::TYPE_BY_STAMPPATH { arity,
stamppath => [ module_stamp ],
namepath => ip::INVERSE_PATH [name]
};
symbolmapstack'
=
syx::bind (name, sxe::NAMED_TYPE etyc, symbolmapstack);
symbols' = name ! symbolsx;
# Unlike normal case (right-hand side=VALCONS),
# won't bother to re-register the type
# in stamppath_context:
#
prefix = all_but_last stamppath;
#
fun expand_type (
type as tdt::TYPE_BY_STAMPPATH {
stamppath,
arity,
namepath
}
)
=>
# See if the path stamppath is defined externally
# in the typerstore:
#
( { tro::find_entry_by_module_stamp
(
typerstore,
head stamppath
);
type; # external type
}
except
tro::UNBOUND
=
# type is local to api
tdt::TYPE_BY_STAMPPATH
{
stamppath => prefix @ stamppath,
arity,
namepath
}
);
expand_type (tdt::FREE_TYPE n)
=>
( (list::nth (free_types, n))
except
_
=
bug "unexpected free_types in expandTypeConstructor");
expand_type (tdt::RECURSIVE_TYPE n)
=>
if (n == index)
etyc; # Could equivalently be type?
else
stamp = vector::get (stamps, n);
#
(vector::get (members, n))
->
{ name_symbol, arity, ... };
tdt::TYPE_BY_STAMPPATH
{
arity,
stamppath => prefix @ [stamp],
namepath => ip::INVERSE_PATH [ name_symbol ]
};
fi;
# Reconstructing the stamppath for sibling
# sumtypes using the fact that the Module_Stamp
# for a sumtype spec is the same as the
# stamp of the sumtype.
# See typecheck_sumtype_in_api'
#
expand_type type
=>
type;
end;
expand = ts::map_constructor_typoid_dot_type expand_type; # Construct type transform function.
#
fun add_union_types ([], elements, symbols)
=>
(elements, symbols);
add_union_types (
(d as { name, form, domain } ) ! dds,
elements,
symbols
)
=>
{ typoid = ts::sumtype_to_typoid (
type,
null_or::map expand domain
);
is_constant = case domain
#
NULL => TRUE;
_ => FALSE;
esac;
nd = tdt::VALCON
{
signature => an_api,
form,
name,
is_constant,
is_lazy,
typoid
};
dspec = VALCON_IN_API {
sumtype => nd,
slot => NULL
};
elements'
=
add (
name,
dspec,
elements,
error_fn source_code_region
);
add_union_types (dds, elements', name ! symbols);
};
end;
(add_union_types (valcons, elements', symbols'))
->
(elements'', symbols'');
( symbolmapstack',
elements'',
symbols''
);
};
_ => no_sumtype ();
esac;
_ => no_sumtype ();
esac;
};
tdt::SUM_TYPE { arity, kind, ... }
=>
case kind
#
tdt::SUMTYPE _
=>
{
# right-hand side is not local to current outermost api
my (type', _)
=
mj::relativize_type stamppath_context type;
case type'
#
tdt::TYPE_BY_STAMPPATH { stamppath, arity, ... }
=>
{
# outside current sig but local to enclosing generic
module_stamp = make_fresh_stamp (); # Add the type.
# spec uses wrapped version of the TYPE_BY_STAMPPATH!!
tspec
=
TYPE_IN_API {
module_stamp,
is_a_replica => TRUE,
scope => 0,
type => ts::wrap_definition (
type',
make_fresh_stamp ()
)
};
elements' = add (name, tspec, elements, error_fn source_code_region);
etyc = tdt::TYPE_BY_STAMPPATH
{
arity,
stamppath => [ module_stamp ],
namepath => ip::INVERSE_PATH [ name ]
};
symbolmapstack'
=
syx::bind (
name,
sxe::NAMED_TYPE etyc,
symbolmapstack
);
symbols' = name ! symbolsx;
# Get the dcons -- quick and dirty (buggy?) hack XXX BUGGO FIXME
dcons = ts::extract_sumtype type;
#
fun add_union_types ([], elements, symbols)
=>
(elements, symbols);
add_union_types (
( d as tdt::VALCON { name,
form,
is_constant,
is_lazy,
signature,
typoid
}
) ! ds,
elements,
symbols
)
=>
{ nd = tdt::VALCON
{
signature,
form,
name,
is_lazy,
is_constant,
typoid => #1 (mj::relativize_typoid stamppath_context typoid)
};
dspec = VALCON_IN_API {
sumtype => nd,
slot => NULL
};
elements' = add (name, dspec, elements, error_fn source_code_region);
add_union_types (ds, elements', name ! symbols);
};
end;
(add_union_types (dcons, elements', symbols'))
->
(elements'', symbols'');
(symbolmapstack', elements'', symbols'');
};
_ =>
{ # Fixed global
module_stamp = make_fresh_stamp (); # Add the type.
tspec = mld::TYPE_IN_API {
is_a_replica => TRUE,
scope => 0,
type => ts::wrap_definition (
type,
make_fresh_stamp ()
),
module_stamp
};
# Put in the constant type
# how to treat this in macroExpand? XXX BUGGO FIXME
#
elements'
=
add (
name,
tspec,
elements,
error_fn source_code_region
);
etyc = tdt::TYPE_BY_STAMPPATH
{
arity,
stamppath => [ module_stamp ],
namepath => ip::INVERSE_PATH [ name ]
};
symbolmapstack' = syx::bind (name, sxe::NAMED_TYPE etyc, symbolmapstack);
symbols' = name ! symbolsx;
dcons = ts::extract_sumtype type;
#
fun add_union_types ([], elements, symbols)
=>
(elements, symbols);
add_union_types (
(dc as tdt::VALCON { name, ... } ) ! dcs,
elements,
symbols
)
=>
{ dspec
=
VALCON_IN_API {
sumtype => dc,
slot => NULL
};
elements'
=
add (
name,
dspec,
elements,
error_fn source_code_region
);
add_union_types (dcs, elements', name ! symbols);
};
end;
my (elements'', symbols'')
=
add_union_types (dcons, elements', symbols');
(symbolmapstack', elements'', symbols'');
};
esac;
};
_ => no_sumtype ();
esac;
_ => no_sumtype ();
esac;
}; # fun typecheck_sumtype_replication
# Typechecking sumtype specification:
#
fun typecheck_sumtype_in_api' (dtypespec, symbolmapstack, elements, symbols, source_code_region)
=
{ if_debugging_say ">>typecheck_sumtype_in_api";
#
err = error_fn source_code_region;
# Push a local stamppath_context dictionary
# to be used to relativize the Constructor
# types and bodies of withtype defns
# within this declaration:
#
stamppath_context
=
spc::enter_closed stamppath_context;
#
fun is_free (tdt::TYPE_BY_STAMPPATH _)
=>
TRUE;
is_free tc
=>
case (spc::find_stamppath_for_type (
stamppath_context,
mj::typestamp_of tc
))
THE _ => TRUE;
_ => FALSE;
esac;
end;
my (dtypes, wtypes, dcons, _)
=
tt::type_sumtype_declaration (
dtypespec,
symbolmapstack,
elements ! api_context,
typerstore,
is_free,
ip::INVERSE_PATH [],
source_code_region,
per_compile_stuff
);
if_debugging_say "--typecheck_sumtype_in_api: type_sumtype_declaration done";
# The following code readjusts the definitions
# of sumtypes and with_types without
# changing their stamps; this is ok, because all
# references to the sumtypes with same types
# will be relativized, so there won't be two
# sumtypes with same type stamps.
#
# The ones returned from type_sumtype_declaration,
# i.e., dtypes, are destroyed. (ZHONG)
vizty = (\\ typoid = #1 (mj::relativize_typoid stamppath_context typoid));
viztc = (\\ tc = #1 (mj::relativize_type stamppath_context tc ));
ndtypes
=
case dtypes
#
(tdt::SUM_TYPE { stamp, kind, ... } ! _)
=>
case kind
#
tdt::SUMTYPE { index=>0, family, free_types, stamps, root }
=>
{ # MAJOR GROSS HACK: use the stamp of the type as its
# Module_Stamp. This makes possible to reconstruct the
# stamppath associated with a RECty when translating the
# types of domains in typecheckSumtypeReplication. See >>HACK<< signs.
# XXX BUGGO FIXME
rtev = stamp; # make_fresh_stamp() >>HACK<<
nfreetypes = map viztc free_types;
#
map newdt dtypes
where
fun newdt (dt as tdt::SUM_TYPE { kind, arity, is_eqtype, namepath, ... } )
=>
case kind
#
tdt::SUMTYPE { index => i, ... }
=>
{ s = vector::get (stamps, i);
#
my (module_stamp, rt)
=
if (i==0) (rtev, NULL);
else (s, # make_fresh_stamp() >>HACK<<
THE rtev);
fi;
nkind
=
tdt::SUMTYPE
{
index => i,
free_types => nfreetypes,
root =>rt,
stamps,
family
};
ndt = tdt::SUM_TYPE
{
stamp => s,
kind => nkind,
stub => NULL,
#
arity,
is_eqtype,
namepath
};
spc::bind_typepath (
#
stamppath_context,
mj::typestamp_of ndt,
module_stamp
);
(module_stamp, arity, ndt);
};
_ => bug "unexpected case in newdtyc (1)";
esac;
newdt _ => bug "unexpected case in newdtyc (2)";
end; # fun newdt
end; # where
};
_ => bug "unexpected types in bindNewTypes (1)";
esac;
_ => bug "unexpected types in bindNewTypes (2)";
esac;
nwtypes
=
map newwt wtypes
where
fun newwt (
tdt::NAMED_TYPE {
stamp,
strict,
namepath,
typescheme => tdt::TYPESCHEME { arity, body }
}
)
=>
{ module_stamp = stamp; # make_fresh_stamp() >>HACK<< XXX BUGGO FIXME
nwt = tdt::NAMED_TYPE {
stamp,
strict,
namepath,
typescheme => tdt::TYPESCHEME
{
body => vizty body,
arity
}
};
spc::bind_typepath (
#
stamppath_context,
mj::typestamp_of nwt,
module_stamp
);
(module_stamp, arity, nwt);
};
newwt _ => bug "newwt";
end;
end;
#
fun add_types ([], symbolmapstack, elements, symbols)
=>
(symbolmapstack, elements, symbols);
add_types((module_stamp, arity, type) ! types, symbolmapstack, elements, symbols)
=>
{ tspec =
TYPE_IN_API {
#
type,
module_stamp,
is_a_replica => FALSE,
scope => 0
};
name = ts::name_of_type type;
if_debugging_say ("--typecheck_sumtype_in_api - name: "+ sy::name name);
elements' = add (name, tspec, elements, err);
etyc = tdt::TYPE_BY_STAMPPATH {
#
stamppath => [ module_stamp ],
namepath => ip::INVERSE_PATH [name],
arity
};
symbolmapstack'
=
syx::bind (
name,
sxe::NAMED_TYPE etyc,
symbolmapstack
);
add_types (
types,
symbolmapstack',
elements',
name ! symbols
);
};
end;
my (symbolmapstack', elements', symbols')
=
add_types (
ndtypes @ nwtypes,
symbolmapstack,
elements,
symbols
);
if_debugging_say "--typecheck_sumtype_in_api: types added";
#
fun add_union_types ([], elements, symbols)
=>
(elements, symbols);
add_union_types (
( tdt::VALCON {
name,
form,
is_constant,
signature,
typoid,
is_lazy
}
) ! ds,
elements,
symbols
)
=>
{ debug_print(
"addSumtypeConstructors - type: ",
( \\ pps = \\ typoid
=
unparse_type::unparse_typoid symbolmapstack pps typoid
),
typoid
);
nd = tdt::VALCON
{
typoid => vizty typoid,
signature,
form,
name,
is_constant,
is_lazy
};
# NOTICE that the call to vizty will kill all the
# references to old sumtypes, dtypes,
# because the same stamp has been mapped to
# TYPE_BY_STAMPPATH in stamppath_context
# already. Is it tricky ?! (ZHONG) XXX BUGGO FIXME
dspec = VALCON_IN_API { sumtype => nd, slot => NULL };
elements' = add (name, dspec, elements, err);
add_union_types (ds, elements', name ! symbols);
};
end;
(add_union_types (dcons, elements', symbols'))
->
(elements'', symbols'');
if_debugging_say "--typecheck_sumtype_in_api: dcons added";
if_debugging_say "<<typecheck_sumtype_in_api";
(symbolmapstack', elements'', symbols'');
};
#
fun typecheck_sumtype_in_api (
#
db as { sumtypes,
with_types
},
symbolmapstack,
elements,
symbols,
source_code_region
)
=
case sumtypes
#
( [ spec as raw::SUM_TYPE { right_hand_side => raw::REPLICAS right_hand_side_symbols,
name_symbol,
typevars => [],
is_lazy => FALSE
}
]
)
=>
# LAZY: not allowing sumtype replication with lazy keyword
typecheck_sumtype_replication (
name_symbol,
right_hand_side_symbols,
symbolmapstack,
elements,
symbols,
source_code_region
);
( raw::SUM_TYPE { right_hand_side => raw::VALCONS _, ... } ! _)
=>
typecheck_sumtype_in_api' (
db,
symbolmapstack,
elements,
symbols,
source_code_region
);
_ => { error_fn
source_code_region
err::ERROR
"ill-formed sumtype spec"
err::null_error_body;
(symbolmapstack, elements, symbols);
};
esac;
# Typechecking package specification:
#
fun typecheck_package_element_in_api (
(name, api_expression, def_op), # Element to process.
symbolmapstack, # Api so far, including outer nested ones.
elements, # Result elements.
symbols,
slots,
source_code_region
)
=
{ if_debugging_say ("--typecheck_package_element_in_api: " + sy::name name);
source_code_region0 = source_code_region;
err = error_fn source_code_region;
module_stamp = make_fresh_stamp (); # The Module_Stamp for this package element.
my (an_api, definitionpackage_op)
=
{ my (api_expression, where_definitions, source_code_region)
=
typecheck_where (
api_expression,
symbolmapstack,
stamppath_context,
make_fresh_stamp,
error_fn,
source_code_region
);
an_api
=
case api_expression
raw::API_BY_NAME name'
=>
fst::find_api_by_symbol (symbolmapstack, name', err);
raw::API_DEFINITION api_elements
=>
{ my ( elements',
symbols',
type_sharing',
package_sharing',
contains_generic'
)
=
typecheck_body (
api_elements,
symbolmapstack,
typerstore,
elements ! api_context,
stamppath_context,
source_code_region,
per_compile_stuff
);
an_api'
=
API {
stamp => make_fresh_stamp(),
name => NULL,
closed => FALSE,
stub => NULL,
symbols => symbols',
api_elements => elements',
property_list => property_list::make_property_list (),
type_sharing => type_sharing',
contains_generic => contains_generic',
package_sharing => package_sharing'
};
an_api';
};
_ => bug "typecheck_package_element_in_api. strspecs";
esac;
an_api
=
case an_api
ERRONEOUS_API
=>
ERRONEOUS_API;
_ =>
case where_definitions
NIL => an_api; # No where definitions
_ => add_where_definitions (
an_api,
prepare_definitions where_definitions,
NULL,
( \\ msg
=
error_fn
source_code_region
err::ERROR msg
err::null_error_body
),
make_fresh_stamp
);
esac;
esac;
definitionpackage_op
=
case def_op
#
NULL => NULL;
THE path
=>
( THE (
find_package_definition_via_symbol_path (
symbolmapstack,
syp::SYMBOL_PATH path,
stamppath_context,
error_fn source_code_region
),
length path
)
except
syx::UNBOUND
=
{ error_fn
source_code_region
err::ERROR
"unbound right-hand side in package definition spec"
err::null_error_body;
NULL;
}
);
esac;
(an_api, definitionpackage_op);
};
if_debugging_say "--typecheck_package_element_in_api: api elaborated";
symbolmapstack'
=
syx::bind (
name,
sxe::NAMED_PACKAGE (
#
PACKAGE_API { an_api,
stamppath => [ module_stamp ]
}
),
symbolmapstack
);
package_spec
=
PACKAGE_IN_API {
an_api,
module_stamp,
definition => definitionpackage_op,
slot => slots
};
elements'
=
add (name, package_spec, elements, err);
if_debugging_say "<<typecheck_package_element_in_api";
contains_generic
=
case an_api
API { contains_generic, ... } => contains_generic;
_ => FALSE;
esac;
(symbolmapstack', elements', name ! symbols, contains_generic);
}; # fun typecheck_package_element_in_api
# Typechecking package specifications:
#
fun typecheck_package_elements_in_api ([], symbolmapstack, elements, symbols, slots, source_code_region, contains_generic)
=>
(symbolmapstack, elements, symbols, [], [], slots, contains_generic);
typecheck_package_elements_in_api (
element ! rest, symbolmapstack, elements, symbols, slots, source_code_region, contains_generic
)
=>
{ my (symbolmapstack', elements', symbols', contains_generic')
=
typecheck_package_element_in_api (element, symbolmapstack, elements, symbols, slots, source_code_region);
typecheck_package_elements_in_api (
rest, symbolmapstack', elements', symbols', slots+1, source_code_region, contains_generic or contains_generic'
);
};
end; # function typecheck_package_elements_in_api
# Current api's elements are passed in so that add can check for
# respecifications of the same name. The result accumulates new specs
# in the new values of elements that are returned in the result, along
# with the new value of slots.
#
# The symbolmapstack argument includes all previous api elements
# (i.e. arguments) at this api level, as well as outer api levels.
#
# The elements are in surface-syntax order.
#
# The return type of typecheck_api_element is
#
# syx::Symbolmapstack
# * elements
# * typeSharingSpec List
# * structureSharingSpec List
# * Int (slot #)
#
# Only the IMPORT_IN_API, TYPE_SHARING_IN_API, and PACKAGE_SHARING_IN_API
# cases can produce non-NIL typeSharingSpec and structureSharingSpec result components.
#
fun typecheck_api_element
(
api_element,
symbolmapstack,
elements,
symbols,
slots,
source_code_region
)
=
case api_element
raw::PACKAGES_IN_API package_elements
=>
typecheck_package_elements_in_api (
package_elements, symbolmapstack, elements, symbols, slots, source_code_region, FALSE
);
raw::GENERICS_IN_API specs
=>
{ if_debugging_say "--typecheck_api_element[GENERICS_IN_API]";
err = error_fn source_code_region;
#
fun generic_specs (NIL, elements, symbols, slots)
=>
(symbolmapstack, elements, symbols, [], [], slots, TRUE);
generic_specs ((name, a_generic_api) ! rest, elements, symbols, slots)
=>
{ a_generic_api
=
type_generic_api' {
generic_api_expression => a_generic_api,
name_or_null => NULL,
symbolmapstack,
curried => FALSE,
per_compile_stuff,
typerstore,
api_context,
stamppath_context,
source_code_region
};
module_stamp = make_fresh_stamp ();
api_element
=
GENERIC_IN_API {
a_generic_api,
slot => slots,
module_stamp
};
elements' = add (name, api_element, elements, err);
generic_specs (rest, elements', name ! symbols, slots+1);
};
end;
generic_specs (specs, elements, symbols, slots);
};
raw::TYPES_IN_API (specs, eqspec)
=>
{ if_debugging_say "--typecheck_api_element [TYPES_IN_API]";
my (symbolmapstack', elements', symbols')
=
typecheck_type_definition_in_api (specs, symbolmapstack, elements, symbols, eqspec, source_code_region);
(symbolmapstack', elements', symbols', [], [], slots, FALSE);
};
raw::VALCONS_IN_API spec
=>
{ if_debugging_say "--typecheck_api_element[VALCONS_IN_API]";
(typecheck_sumtype_in_api (spec, symbolmapstack, elements, symbols, source_code_region))
->
(symbolmapstack', elements', symbols');
(symbolmapstack', elements', symbols', [], [], slots, FALSE);
};
raw::VALUES_IN_API specs
=>
{ err = error_fn source_code_region;
#
valspecs (specs, elements, symbols, slots)
where
fun valspecs (NIL, elements, symbols, slots)
=>
(symbolmapstack, elements, symbols, [], [], slots, FALSE);
valspecs ((name, type) ! rest, elements, symbols, slots)
=>
{ if_debugging_say ("--typecheck_api_element[VALUES_IN_API]: " + sy::name name);
(tt::type_type (type, symbolmapstack, error_fn, source_code_region))
->
(type, typevar_set);
type = case (typevar_set::get_elements typevar_set)
#
[] => type;
typevars
=>
{ typescheme_eqflags = ts::resolve_typevars_to_typescheme_slots_1 typevars;
#
tdt::TYPESCHEME_TYPOID {
typescheme_eqflags,
typescheme => tdt::TYPESCHEME {
arity => length typevars,
body => type
}
};
};
esac;
ts::drop_macro_expanded_indirections_from_type type;
my (typoid, _) = mj::relativize_typoid stamppath_context type;
vspec = VALUE_IN_API { typoid, slot => slots };
elements' = add (name, vspec, elements, err);
valspecs (rest, elements', name ! symbols, slots+1);
};
end; # fun valspecs
end; # where
};
raw::EXCEPTIONS_IN_API (specs)
=>
{ err = error_fn source_code_region;
#
exception_specs (specs, elements, symbols, slots)
where
fun exception_specs (NIL, elements, symbols, slots)
=>
(symbolmapstack, elements, symbols, [], [], slots, FALSE);
exception_specs ((name, ty_op) ! rest, elements, symbols, slots)
=>
{ my (type, is_constant)
=
case ty_op
#
THE type
=>
{ my (body, typevar_set)
=
tt::type_type (
type,
symbolmapstack,
error_fn,
source_code_region
);
nty = case (typevar_set::get_elements typevar_set)
NIL => mtt::(-->) (body, mtt::exception_typoid);
_ => { err
err::ERROR
( "type variable in exception spec: "
+ sy::name name
)
err::null_error_body;
tdt::WILDCARD_TYPOID;
};
esac;
ts::drop_macro_expanded_indirections_from_type nty;
( #1 (mj::relativize_typoid stamppath_context nty),
FALSE
);
};
NULL => (mtt::exception_typoid, TRUE);
esac;
form = vh::EXCEPTION (vh::null_varhome);
sumtype = tdt::VALCON
{
name,
is_lazy => FALSE,
signature => vh::NULLARY_CONSTRUCTOR,
typoid => type,
is_constant,
form
};
cspec = VALCON_IN_API { sumtype,
slot => THE slots
};
elements' = add (name, cspec, elements, err);
exception_specs (rest, elements', name ! symbols, slots+1);
};
end; # fun exception_specs
end; # where
};
raw::SOURCE_CODE_REGION_FOR_API_ELEMENT (api_element, source_code_region')
=>
typecheck_api_element (api_element, symbolmapstack, elements, symbols, slots, source_code_region');
raw::PACKAGE_SHARING_IN_API symbol_path_list
=>
{ sharespec = loop (symbol_path_list, NIL);
(symbolmapstack, elements, symbols, [], [sharespec], slots, FALSE);
}
where
fun loop (NIL, result_paths)
=>
result_paths;
loop (symbol_path ! rest, result_paths)
=>
if (local_path (syp::SYMBOL_PATH symbol_path, elements))
#
case (find_package_definition_via_symbol_path (
#
symbolmapstack,
syp::SYMBOL_PATH symbol_path,
stamppath_context,
error_fn source_code_region
))
VARIABLE_PACKAGE_DEFINITION z
=>
loop (rest, (syp::SYMBOL_PATH symbol_path) ! result_paths);
CONSTANT_PACKAGE_DEFINITION (ERRONEOUS_PACKAGE)
=>
loop (rest, result_paths); # find_package_definition_via_symbol_path has already complained
_ => bug "typecheck_api_element[PACKAGE_SHARING_IN_API]";
esac;
/* except syx::UNBOUND =>
(error_fn source_code_region err::ERROR
("unbound path in package sharing: " +
syp::to_string (syp::SYMBOL_PATH p))
err::null_error_body;
loop (rest, resultPaths))
*/
else
error_fn
source_code_region
err::ERROR
( "nonlocal path in package sharing: "
+ syp::to_string (syp::SYMBOL_PATH symbol_path)
)
err::null_error_body;
loop (rest, result_paths);
fi;
end; # fun loop
end; # where
raw::TYPE_SHARING_IN_API symbol_path_list
=>
{ sharespec = loop (symbol_path_list, NIL);
(symbolmapstack, elements, symbols, [sharespec], [], slots, FALSE);
}
where
fun loop (NIL, result_paths)
=>
result_paths;
loop (symbol_path ! rest, result_paths)
=>
if (local_path (syp::SYMBOL_PATH symbol_path, elements))
#
fst::find_type_via_symbol_path (
symbolmapstack,
syp::SYMBOL_PATH symbol_path,
error_fn source_code_region
);
loop (rest, (syp::SYMBOL_PATH symbol_path) ! result_paths);
else
error_fn
source_code_region
err::ERROR
( "nonlocal path in type sharing: "
+ syp::to_string (syp::SYMBOL_PATH symbol_path)
)
err::null_error_body;
loop (rest, result_paths);
fi;
end; # fun loop
end; # where
raw::IMPORT_IN_API api_expression # Parameter was "name"
=>
{ new_api
=
type_api {
name_or_null => NULL,
api_expression,
symbolmapstack,
typerstore,
stamppath_context,
source_code_region,
per_compile_stuff
};
# fst::find_api_by_symbol (symbolmapstack, name, error_fn source_code_region)
# XXX BUGGO FIXME: this may not work with open api expressions
my (symbolmapstack', elements', symbols', type_sharing', package_sharing', slots', contains_generic')
=
include_mumble::typecheck_include (
new_api,
symbolmapstack,
elements,
symbols,
slots,
source_code_region,
per_compile_stuff
);
(symbolmapstack', elements', symbols', type_sharing', package_sharing', slots', contains_generic');
};
esac
also
fun typecheck_api_elements (
[], symbolmapstack, elements, symbols, type_sharing, package_sharing, slots, source_code_region, contains_generic
)
=>
(symbolmapstack, elements, symbols, type_sharing, package_sharing, slots, contains_generic);
typecheck_api_elements (
api_element ! rest,
symbolmapstack,
elements,
symbols,
type_sharing,
package_sharing,
slots,
source_code_region,
contains_generic
)
=>
{ my (symbolmapstack', elements', symbols', type_sharing', package_sharing', slots', contains_generic')
=
typecheck_api_element (api_element, symbolmapstack, elements, symbols, slots, source_code_region);
typecheck_api_elements (
rest,
symbolmapstack',
elements',
symbols',
type_sharing' @ type_sharing,
package_sharing' @ package_sharing,
slots',
source_code_region,
contains_generic' or contains_generic
);
};
end;
my (_, elements, symbols, type_sharing, package_sharing, slots, contains_generic)
=
typecheck_api_elements (
api_elements,
symbolmapstack,
NIL,
NIL,
NIL,
NIL,
0,
source_code_region,
FALSE
);
( reverse elements,
reverse symbols,
type_sharing,
package_sharing,
contains_generic
);
} # function typecheck_body
also
fun type_generic_api' {
generic_api_expression,
curried,
name_or_null,
symbolmapstack,
typerstore,
api_context,
stamppath_context,
source_code_region,
per_compile_stuff as { make_fresh_stamp, error_fn, ... }: eu::Per_Compile_Stuff
}
=
{ sname
=
case name_or_null
THE name => sy::name name;
_ => "<anonymous generic api>";
esac;
if_debugging_say (">>type_generic_api: " + sname);
case generic_api_expression
#
raw::GENERIC_API_DEFINITION { parameter => [ (optional_parameter_name, parameter_specification) ], result }
=>
{ parameter_api
=
typecheck_api' {
api_expression => parameter_specification,
name_or_null => NULL,
symbolmapstack,
typerstore,
api_context,
stamppath_context,
source_code_region,
per_compile_stuff
};
parameter_name
=
case optional_parameter_name
#
NULL => parameter_id;
THE symbol => symbol;
esac;
parameter_module_stamp
=
make_fresh_stamp ();
parameter_package
=
PACKAGE_API
{
an_api => parameter_api,
stamppath => [ parameter_module_stamp ]
};
stipulate
parameter_specification
=
PACKAGE_IN_API
{
module_stamp => parameter_module_stamp,
an_api => parameter_api,
definition => NULL,
slot => 0
};
param_elmt = [ (parameter_name, parameter_specification) ];
herein
new_api_context = param_elmt ! api_context;
end; # A temporary work-around for the api_context hack XXX BUGGO FIXME
symbolmapstack'
=
case optional_parameter_name
#
THE id => syx::bind (id, sxe::NAMED_PACKAGE parameter_package, symbolmapstack); # Expose binding of parameter_name
NULL => mj::include_package (symbolmapstack, parameter_package);
esac;
my (result, source_code_region)
=
strip_mark_sig (result, source_code_region);
result
=
if curried result;
else raw::API_DEFINITION [ raw::PACKAGES_IN_API [ (result_id, result, NULL) ] ];
fi;
body_api
=
typecheck_api'
{
api_expression => result,
name_or_null => NULL,
symbolmapstack => symbolmapstack',
api_context => new_api_context,
typerstore,
stamppath_context,
source_code_region,
per_compile_stuff
};
GENERIC_API {
kind => name_or_null,
parameter_variable => parameter_module_stamp,
parameter_symbol => optional_parameter_name,
parameter_api,
body_api
};
};
# ** Currying Generic_Api arguments automatically inserts package wrapping **
raw::GENERIC_API_DEFINITION { parameter => a ! r, result }
=>
{ new_generic_api
=
raw::API_DEFINITION [
raw::GENERICS_IN_API [
( generic_id,
raw::GENERIC_API_DEFINITION {
parameter => r,
result
}
)
]
];
type_generic_api' {
curried => TRUE,
name_or_null,
symbolmapstack,
per_compile_stuff,
typerstore,
api_context,
stamppath_context,
source_code_region,
generic_api_expression => raw::GENERIC_API_DEFINITION {
parameter => [a],
result => new_generic_api
}
};
};
raw::GENERIC_API_BY_NAME name'
=>
fst::find_generic_api_by_symbol (symbolmapstack, name', error_fn source_code_region);
raw::GENERIC_API_DEFINITION { parameter => [], result }
=>
bug "type_generic_api";
raw::SOURCE_CODE_REGION_FOR_GENERIC_API (generic_api_expression', source_code_region')
=>
type_generic_api' {
generic_api_expression => generic_api_expression',
source_code_region => source_code_region',
name_or_null,
symbolmapstack,
per_compile_stuff,
curried,
typerstore,
stamppath_context,
api_context
};
esac;
} # function type_generic_api'
also
fun typecheck_api' {
api_expression, # This is the raw syntax we're typechecking.
name_or_null,
symbolmapstack,
typerstore,
api_context,
stamppath_context,
source_code_region,
per_compile_stuff as { make_fresh_stamp, error_fn, ... } : eu::Per_Compile_Stuff
}
=
{
unparse_api_expression ("typecheck-api.pkg: type_api()/TOP", api_expression, symbolmapstack );
source_code_region0 = source_code_region;
api_name
=
case name_or_null
#
THE name => sy::name name;
_ => "<anonymous function api>";
esac;
if_debugging_say (">>type_api: " + api_name);
my (api_expression, where_definitions, source_code_region)
=
typecheck_where (
api_expression,
symbolmapstack,
stamppath_context,
make_fresh_stamp,
error_fn,
source_code_region
);
an_api
=
case api_expression
raw::API_BY_NAME name'
=>
fst::find_api_by_symbol (symbolmapstack, name', error_fn source_code_region);
raw::API_DEFINITION api_elements
=>
{ if_debugging_say "--type_api >> API_DEFINITION";
my (api_elements, symbols, type_sharing, package_sharing, contains_generic)
=
typecheck_body (
api_elements,
symbolmapstack,
typerstore,
api_context,
stamppath_context,
source_code_region,
per_compile_stuff
);
if_debugging_say "--type_api: after typecheck_body";
an_api
=
API {
stamp => make_fresh_stamp (),
name => name_or_null,
stub => NULL,
#
property_list => property_list::make_property_list (),
#
closed => case name_or_null
#
THE _ => TRUE;
NULL => FALSE;
esac,
#
symbols,
api_elements,
type_sharing,
contains_generic,
package_sharing
};
debug_print (
"--type_api: returned api:",
( \\ pps =
\\ an_api = unparse_package_language::unparse_api
pps
(an_api, symbolmapstack, 6)
),
an_api
);
if_debugging_say "--type_api: << API_DEFINITION";
an_api;
};
raw::SOURCE_CODE_REGION_FOR_API (api_expression', source_code_region')
=>
bug "typecheck_api'"; # typecheck_where should have stripped this
_ => bug "typecheck_api': api_expression";
esac;
an_api
=
case an_api
ERRONEOUS_API => ERRONEOUS_API;
_ =>
case where_definitions
NIL => an_api; # No 'where' definitions.
_ =>
add_where_definitions (
an_api,
prepare_definitions where_definitions,
name_or_null,
( \\ msg = error_fn
source_code_region0
err::ERROR msg
err::null_error_body
),
make_fresh_stamp
);
esac;
esac;
an_api;
} # function typecheck_api'
also
fun type_generic_api {
generic_api_expression,
name_or_null,
symbolmapstack,
typerstore,
stamppath_context,
source_code_region,
per_compile_stuff
}
=
type_generic_api' {
curried => FALSE,
api_context => [],
generic_api_expression,
name_or_null,
symbolmapstack,
typerstore,
stamppath_context,
source_code_region,
per_compile_stuff
}
also
fun type_api {
api_expression, # This is the raw syntax we're typechecking.
name_or_null,
symbolmapstack,
typerstore,
stamppath_context,
source_code_region,
per_compile_stuff
}
=
typecheck_api' {
api_expression, # This is the raw syntax we're typechecking.
api_context => [], # <-- Only additional/changed argument.
name_or_null,
symbolmapstack,
typerstore,
stamppath_context,
source_code_region,
per_compile_stuff
};
/*
typecheck_api_phase = compile_statistics::make_phase "Compiler 032 5-type_api"
type_api = \\ x => compile_statistics::do_phase typecheck_api_phase type_api x
*/
}; # package type_api
end; # stipulate