Skip to content

Commit

Permalink
[merge] Support opaque resources
Browse files Browse the repository at this point in the history
Fixes #360

* modules:
  [tests] Add a test for invalid use of opaque resources
  [compiler] Write opaque resources to interface files
  [compiler] Handle opaque resources in interfaces
  [compiler/parse] Update an old comment in the parser
  [docs] Add opaque keyword to resource definitions
  [tests] Add a test for opaque resource syntax
  [compiler/ast] Resources use the sharing_opaque type
  [compiler/parse] Refactor how exports are parsed
  [compiler] Rename sharing_type to sharing_opaque
  • Loading branch information
PaulBone committed Jan 26, 2025
2 parents 74181ed + 1d04d08 commit d086aae
Show file tree
Hide file tree
Showing 20 changed files with 259 additions and 105 deletions.
2 changes: 1 addition & 1 deletion docs/plasma_ref.txt
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ a time.
== Resources

----
ResourceDefinition := 'export'? 'resource' Ident 'from' QualifiedIdent
ResourceDefinition := ('export' 'opaque'?)? 'resource' Ident 'from' QualifiedIdent
----

This defines a new resource. The resource has the given name and is a
Expand Down
11 changes: 8 additions & 3 deletions src/ast.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
; ast_pragma(ast_pragma).

:- type ast_interface_entry
---> asti_resource(q_name, ast_resource)
---> asti_resource(
q_name,

% Opaque resources won't have a definition.
maybe(ast_resource)
)
; asti_type(q_name, ast_type(q_name))
; asti_function(q_name, ast_function_decl).

Expand All @@ -63,7 +68,7 @@
---> ast_type(
at_params :: list(string),
at_costructors :: list(at_constructor(Name)),
at_export :: sharing_type,
at_export :: sharing_opaque,
at_context :: context
)
% An abstractly-imported type.
Expand All @@ -77,7 +82,7 @@
:- type ast_resource
---> ast_resource(
ar_from :: q_name,
ar_sharing :: sharing,
ar_sharing :: sharing_opaque,
ar_context :: context
).

Expand Down
14 changes: 7 additions & 7 deletions src/builtins.m
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@
MaybeName = nq_name_det("Maybe"),
core_set_type(MaybeType,
type_init(q_name_append(builtin_module_name, MaybeName),
[MaybeParamName], [NoneId, SomeId], st_private, i_imported,
[MaybeParamName], [NoneId, SomeId], so_private, i_imported,
builtin_context),
!Core),
root_name(MaybeName, bi_type(MaybeType, arity(1)), !Map).
Expand Down Expand Up @@ -291,7 +291,7 @@
BoolName = nq_name_det("Bool"),
core_set_type(BoolId,
type_init(q_name_append(builtin_module_name, BoolName), [],
[FalseId, TrueId], st_private, i_imported, builtin_context),
[FalseId, TrueId], so_private, i_imported, builtin_context),
!Core),
root_name(BoolName, bi_type(BoolId, arity(0)), !Map),

Expand Down Expand Up @@ -472,7 +472,7 @@

core_set_type(ListId,
type_init(q_name_append_str(builtin_module_name, "List"), [T],
[NilId, ConsId], st_private, i_imported, builtin_context),
[NilId, ConsId], so_private, i_imported, builtin_context),
!Core),

root_name(nq_name_det("List"), bi_type(ListId, arity(1)), !Map).
Expand Down Expand Up @@ -515,7 +515,7 @@
IOResultName = nq_name_det("IOResult"),
core_set_type(IOResultType,
type_init(q_name_append(builtin_module_name, IOResultName),
[OkParamName], [OkId, EOFId], st_private, i_imported, builtin_context),
[OkParamName], [OkId, EOFId], so_private, i_imported, builtin_context),
!Core),
root_name(IOResultName, bi_type(IOResultType, arity(1)), !Map),

Expand Down Expand Up @@ -558,7 +558,7 @@
EnvironmentName = nq_name_det("Environment"),
EnvironmentQName = q_name_append(builtin_module_name, EnvironmentName),
register_builtin_resource(EnvironmentName,
r_other(EnvironmentQName, RIO, s_private, i_imported, builtin_context),
r_other(EnvironmentQName, RIO, so_private, i_imported, builtin_context),
REnv, !Map, !Core),
SetenvName = q_name_append_str(builtin_module_name, "setenv"),
register_builtin_func_root(nq_name_det("setenv"),
Expand All @@ -571,7 +571,7 @@
TimeName = nq_name_det("Time"),
TimeQName = q_name_append(builtin_module_name, TimeName),
register_builtin_resource(TimeName,
r_other(TimeQName, RIO, s_private, i_imported, builtin_context),
r_other(TimeQName, RIO, so_private, i_imported, builtin_context),
RTime, !Map, !Core),
GettimeofdayName = q_name_append_str(builtin_module_name, "gettimeofday"),
register_builtin_func_builtin(nq_name_det("gettimeofday"),
Expand Down Expand Up @@ -615,7 +615,7 @@
core_set_type(CodepointCategoryId,
type_init(q_name_append(builtin_module_name,
CodepointCategoryTypeName), [],
[WhitespaceId, OtherId], st_private, i_imported, builtin_context),
[WhitespaceId, OtherId], so_private, i_imported, builtin_context),
!Core),
root_name(CodepointCategoryTypeName,
bi_type(CodepointCategoryId, arity(0)), !Map),
Expand Down
12 changes: 6 additions & 6 deletions src/common_types.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
---> s_public
; s_private.

% Types have a 3rd option, to export the type name but not its details
% (constructors & fields).
% Types and resources have a 3rd option, to export the name but not its
% details.
%
:- type sharing_type
---> st_private
; st_public
; st_public_opaque.
:- type sharing_opaque
---> so_private
; so_public
; so_public_opaque.

% Is an exported function an entrypoint.
%
Expand Down
21 changes: 13 additions & 8 deletions src/compile.m
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,12 @@
( if
env_add_resource(q_name(Name), ResId, !Env),
Sharing = Res ^ ar_sharing,
( Sharing = s_public,
( ( Sharing = so_public
; Sharing = so_public_opaque
),
env_add_resource(q_name_append(ModuleName, Name), ResId,
!ImportEnv)
; Sharing = s_private
; Sharing = so_private
)
then
true
Expand All @@ -320,12 +322,12 @@
env_add_type(q_name(Name), Arity, TypeId, !Env),
Sharing = Type ^ at_export,
(
( Sharing = st_public
; Sharing = st_public_opaque
( Sharing = so_public
; Sharing = so_public_opaque
),
env_add_type(q_name_append(ModuleName, Name), Arity, TypeId,
!ImportEnv)
; Sharing = st_private
; Sharing = so_private
)
then
true
Expand All @@ -344,15 +346,18 @@
filter_entries(Entries, _, Resources0, Types0, _, _),

filter_map((pred(NamedRes::in, Name::out) is semidet :-
NamedRes = nq_named(NQName, ast_resource(_, s_public, _)),
NamedRes = nq_named(NQName, ast_resource(_, Sharing, _)),
( Sharing = so_public
; Sharing = so_public_opaque
),
Name = q_name_append(ModuleName, NQName)
),
Resources0, Resources),

filter_map((pred(NamedRes::in, {Name, Arity}::out) is semidet :-
NamedRes = nq_named(NQName, ast_type(Params, _, Sharing, _)),
( Sharing = st_public
; Sharing = st_public_opaque
( Sharing = so_public
; Sharing = so_public_opaque
),
Name = q_name_append(ModuleName, NQName),
Arity = arity(length(Params))
Expand Down
12 changes: 8 additions & 4 deletions src/core.m
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,7 @@

type_is_exported(_ - Type) :-
Sharing = utype_get_sharing(Type),
( Sharing = st_public
; Sharing = st_public_opaque
).
sharing_is_exported(Sharing).

core_get_type(Core, TypeId) = Type :-
lookup(Core ^ c_types, TypeId, Type).
Expand Down Expand Up @@ -334,6 +332,12 @@

:- pred resource_is_exported(pair(resource_id, resource)::in) is semidet.

resource_is_exported(_ - r_other(_, _, s_public, _, _)).
resource_is_exported(_ - r_other(_, _, Sharing, _, _)) :-
sharing_is_exported(Sharing).

:- pred sharing_is_exported(sharing_opaque::in) is semidet.

sharing_is_exported(so_public).
sharing_is_exported(so_public_opaque).

%-----------------------------------------------------------------------%
29 changes: 18 additions & 11 deletions src/core.pretty.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
% we probably should parameterise it and other pretty-printer functions
% here.
%
:- func type_decl_pretty(core, user_type) = pretty.
:- func type_interface_pretty(core, user_type) = pretty.

% Print the argument parts of a function type. You can either put
% "func" in front of this or the name of the variable at a call site.
Expand All @@ -61,7 +61,7 @@

% Pretty print a resource definition.
%
:- func resource_decl_pretty(core, resource) = pretty.
:- func resource_interface_pretty(core, resource) = pretty.

:- func constructor_name_pretty(core, set(ctor_id)) = pretty.

Expand All @@ -88,11 +88,11 @@

%-----------------------------------------------------------------------%

type_decl_pretty(Core, Type) = p_expr(Pretty) :-
type_interface_pretty(Core, Type) = p_expr(Pretty) :-
Sharing = utype_get_sharing(Type),
( Sharing = st_private,
( Sharing = so_private,
unexpected($file, $pred, "st_private")
; Sharing = st_public,
; Sharing = so_public,
MaybeParams = utype_get_params(Type),
( MaybeParams = yes(Params)
; MaybeParams = no,
Expand All @@ -112,7 +112,7 @@
unexpected($file, $pred, "Public type without constructors")
),
Pretty = PrettyHead ++ PrettyBody
; Sharing = st_public_opaque,
; Sharing = so_public_opaque,
Pretty = [p_str("type "),
q_name_pretty(utype_get_name(Type)),
p_str("/"),
Expand Down Expand Up @@ -405,11 +405,18 @@
resource_pretty(Core, ResId) =
p_str(resource_to_string(core_get_resource(Core, ResId))).

resource_decl_pretty(_, r_io) = unexpected($file, $pred, "IO").
resource_decl_pretty(Core, r_other(Name, From, _, _, _)) =
p_expr([p_str("resource"), p_spc, q_name_pretty(Name),
p_spc, p_str("from"), p_spc, resource_pretty(Core, From)]).
resource_decl_pretty(_, r_abstract(Name)) =
resource_interface_pretty(_, r_io) = unexpected($file, $pred, "IO").
resource_interface_pretty(Core, r_other(Name, From, Sharing, _, _)) = Pretty :-
( Sharing = so_public,
Pretty = p_expr([p_str("resource"), p_spc, q_name_pretty(Name),
p_spc, p_str("from"), p_spc, resource_pretty(Core, From)])
; Sharing = so_public_opaque,
Pretty = p_expr([p_str("resource"), p_spc, q_name_pretty(Name)])
; Sharing = so_private,
Pretty = p_empty
).

resource_interface_pretty(_, r_abstract(Name)) =
p_expr([p_str("resource"), p_spc, q_name_pretty(Name)]).

%-----------------------------------------------------------------------%
Expand Down
2 changes: 1 addition & 1 deletion src/core.resource.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
; r_other(
ro_name :: q_name,
ro_from :: resource_id,
ro_sharing :: sharing,
ro_sharing :: sharing_opaque,
ro_imported :: imported,
ro_context :: context
)
Expand Down
8 changes: 4 additions & 4 deletions src/core.types.m
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

:- type user_type.

:- func type_init(q_name, list(string), list(ctor_id), sharing_type,
:- func type_init(q_name, list(string), list(ctor_id), sharing_opaque,
imported, context) = user_type.

:- func type_init_abstract(q_name, arity, context) = user_type.
Expand All @@ -72,7 +72,7 @@

:- func utype_get_ctors(user_type) = maybe(list(ctor_id)).

:- func utype_get_sharing(user_type) = sharing_type.
:- func utype_get_sharing(user_type) = sharing_opaque.

:- func utype_get_imported(user_type) = imported.

Expand Down Expand Up @@ -162,7 +162,7 @@
t_symbol :: q_name,
t_params :: list(string),
t_ctors :: list(ctor_id),
t_sharing :: sharing_type,
t_sharing :: sharing_opaque,
t_imported :: imported,
t_context :: context
)
Expand Down Expand Up @@ -191,7 +191,7 @@
).

utype_get_sharing(user_type(_, _, _, Sharing, _, _)) = Sharing.
utype_get_sharing(abstract_type(_, _, _)) = st_private.
utype_get_sharing(abstract_type(_, _, _)) = so_private.

utype_get_imported(user_type(_, _, _, _, Imported, _)) = Imported.
utype_get_imported(abstract_type(_, _, _)) = i_imported.
Expand Down
Loading

0 comments on commit d086aae

Please sign in to comment.