[m-rev.] for review: initial erlang code generator

Peter Ross pro at missioncriticalit.com
Mon May 14 16:14:05 AEST 2007


On Mon, May 14, 2007 at 02:02:13PM +1000, Peter Wang wrote:
> Estimated hours taken: 50
> Branches: main
> 
> Initial version of a HLDS->Erlang code generator.  Currently det and semidet
> code is supported.  The code generator converts HLDS data structures into a
> new ELDS data structure, which is an internal representation of Erlang code.
> Then the ELDS data structure is printed out into concrete Erlang syntax.
> 
> compiler/elds.m:
> compiler/elds_to_erlang.m:
> compiler/erl_backend.m:
> compiler/erl_call_gen.m:
> compiler/erl_code_gen.m:
> compiler/erl_code_util.m:
> compiler/erl_unify_gen.m:
> 	New files.
> 
> compiler/Mercury.options:
> 	Add --no-warn-unused-imports for erl_backend package.
> 
> compiler/top_level.m:
> compiler/mercury_compile.m:
> 	Import the Erlang backend and call it for --target erlang.
> 
> compiler/modules.m:
> 	Add module_name_to_file_name_sep which is like module_name_to_file_name
> 	but allows modules to be qualified with a string other than ".".
> 
> library/array.m:
> library/bitmap.m:
> library/io.m:
> 	Add Erlang foreign_type declarations for array(T),
> 	bitmap and io.system_error.
> 
Say why you've added these.

> Index: compiler/elds.m
> ===================================================================
> RCS file: compiler/elds.m
> diff -N compiler/elds.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ compiler/elds.m	14 May 2007 04:00:50 -0000
> @@ -0,0 +1,222 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 2007 The University of Melbourne.
> +% This file may only be copied under the terms of the GNU General
> +% Public License - see the file COPYING in the Mercury distribution.
> +%-----------------------------------------------------------------------------%
> +%
> +% File: elds.m.
> +% Main author: wangp.
> +%
> +% ELDS - The Erlang Data Structure.
> +%
> +% This module defines the ELDS data structure itself.
> +% The ELDS is an intermediate data structure used in compilation;
> +% we compile Mercury source -> parse tree -> HLDS -> ELDS -> target (Erlang).
> +% The ELDS uses the same types for variables and procedure ids as the HLDS
> +% so as not the clutter the ELDS code generator with conversions between types.
> +%
> +%-----------------------------------------------------------------------------%
> +
> +:- module erl_backend.elds.
> +:- interface.
> +
> +:- import_module hlds.hlds_pred.
> +:- import_module mdbcomp.
> +:- import_module mdbcomp.prim_data.
> +:- import_module parse_tree.prog_data.
> +
> +:- import_module char.
> +:- import_module list.
> +:- import_module maybe.
> +
> +%-----------------------------------------------------------------------------%
> +

> +
> +:- type elds_term
> +    --->    elds_char(char)
> +    ;       elds_int(int)
> +    ;       elds_float(float)
> +    ;       elds_string(string)
> +    ;       elds_atom_raw(string)
> +    ;       elds_atom(sym_name)

what is the difference between these two, a comment of some sort is
needed.

> +    ;       elds_tuple(list(elds_expr))
> +    ;       elds_var(prog_var)
> +    ;       elds_anon_var.
> +
> +% XXX we should use insts (or some other method) to restrict expressions in
> +% tuples to be terms, if the tuple is going to be used in a pattern.
> +
Why not have a variant of the tuple which takes a list(elds_term)?
Actually even then you will have a problem because the term can contain
an expression.


> +%-----------------------------------------------------------------------------%
> +
> +    % Some useful constants.
> +    %
> +:- func elds_true = elds_term.
> +:- func elds_false = elds_term.
> +:- func elds_fail = elds_term.
> +:- func elds_empty_tuple = elds_term.
> +
> +:- func term_from_var(prog_var) = elds_term.
> +:- func terms_from_vars(prog_vars) = list(elds_term).
> +:- func expr_from_var(prog_var) = elds_expr.
> +:- func exprs_from_vars(prog_vars) = list(elds_expr).
> +
> +    % Convert an expression to a term, aborting on failure.
> +    %
> +:- func expr_to_term(elds_expr) = elds_term.
> +
> +    % Join two expressions into one block expression, flattening any nested
> +    % blocks.
> +    %
> +:- func join_exprs(elds_expr, elds_expr) = elds_expr.
> +
> +    % maybe_join_exprs(ExprA, MaybeExprB)
> +    %
> +    % Join ExprA and ExprB as above if MaybeExprB = `yes(ExprB)',
> +    % otherwise return ExprA.
> +    %
> +:- func maybe_join_exprs(elds_expr, maybe(elds_expr)) = elds_expr.
> +
> +    % expr_or_void(MaybeExpr)
> +    %
> +    % Return `E' if MaybeExpr unifies with `yes(E)', or any constant expression
> +    % if MaybeExpr unifies with `no'.  MaybeExpr should only be `no' if value
> +    % that an expression evaluates to doesn't matter.
> +    %
> +:- func expr_or_void(maybe(elds_expr)) = elds_expr.
> +
I find the above hard to parse.  Can you reword it?  I'm not sure how.

> Index: compiler/elds_to_erlang.m
> ===================================================================
> RCS file: compiler/elds_to_erlang.m
> diff -N compiler/elds_to_erlang.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ compiler/elds_to_erlang.m	14 May 2007 04:00:50 -0000
> @@ -0,0 +1,669 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 2007 The University of Melbourne.
> +% This file may only be copied under the terms of the GNU General
> +% Public License - see the file COPYING in the Mercury distribution.
> +%-----------------------------------------------------------------------------%
> +% 
> +% File: elds_to_erlang.m.
> +% Main authors: wangp.
> +% 
> +% Convert ELDS to Erlang code.
> +% 
> +%-----------------------------------------------------------------------------%
> +
> +:- module erl_backend.elds_to_erlang.
> +:- interface.
> +
> +:- import_module erl_backend.elds.
> +:- import_module hlds.hlds_module.
> +
> +:- import_module io.
> +
> +%-----------------------------------------------------------------------------%
> +
> +    % output_elds(ELDS, !IO):
> +    %
> +    % Output Erlang code to the appropriate .erl file.  The file names are
> +    % determined by the module name.
> +    %
> +:- pred output_elds(module_info::in, elds::in, io::di, io::uo) is det.
> +
> +    % Output a Erlang function definition to the current output stream.
> +    % This is exported for debugging purposes. 
> +    %
> +:- pred output_defn(module_info::in, elds_defn::in, io::di, io::uo)
> +    is det.
> +
> +%-----------------------------------------------------------------------------%
> +%-----------------------------------------------------------------------------%
> +

> +:- pred output_var(prog_varset::in, prog_var::in, io::di, io::uo) is det.
> +
> +output_var(VarSet, Var, !IO) :-
> +    varset.lookup_name(VarSet, Var, VarName),
> +    term.var_to_int(Var, VarNumber),
> +    % XXX this assumes all Mercury variable names are a subset of Erlang
> +    % variable names

But you think it is because of Erlangs roots in prolog, correct?

> +    io.write_string(VarName, !IO),
> +    io.write_char('_', !IO),
> +    io.write_int(VarNumber, !IO),
> +    space(!IO).
> +

> Index: compiler/erl_call_gen.m
> ===================================================================
> RCS file: compiler/erl_call_gen.m
> diff -N compiler/erl_call_gen.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ compiler/erl_call_gen.m	14 May 2007 04:00:50 -0000
> @@ -0,0 +1,349 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 2007 The University of Melbourne.
> +% This file may only be copied under the terms of the GNU General
> +% Public License - see the file COPYING in the Mercury distribution.
> +%-----------------------------------------------------------------------------%
> +% 
> +% File: erl_call_gen.m.
> +% Main author: wangp.
> +% 
> +% This module is part of the ELDS code generator.  It handles code generation
> +% of procedures calls, calls to builtins, and other closely related stuff.
> +% 
> +%-----------------------------------------------------------------------------%
> +
> +:- module erl_backend.erl_call_gen.
> +:- interface.
> +
> +:- import_module erl_backend.elds.
> +:- import_module erl_backend.erl_code_util.
> +:- import_module hlds.code_model.
> +:- import_module hlds.hlds_goal.
> +:- import_module hlds.hlds_pred.
> +:- import_module parse_tree.prog_data.
> +
> +:- import_module list.
> +:- import_module maybe.
> +
> +%-----------------------------------------------------------------------------%
> +
> +    % erl_gen_call(PredId, ProcId, ArgNames, ArgTypes,
> +    %   CodeModel, Context, SuccessExpr, Statement, !Info):
> +    %
> +    % Generate ELDS code for an HLDS procedure call.
> +    %
> +:- pred erl_gen_call(pred_id::in, proc_id::in, prog_vars::in,
> +    list(mer_type)::in, code_model::in, prog_context::in, maybe(elds_expr)::in,
> +    elds_expr::out, erl_gen_info::in, erl_gen_info::out) is det.
> +
What is a SuccessExpr?

> +    % Generate ELDS code for a higher order call.
> +    %
> +:- pred erl_gen_higher_order_call(generic_call::in(higher_order),
> +    prog_vars::in, list(mer_mode)::in, determinism::in, prog_context::in,
> +    maybe(elds_expr)::in, elds_expr::out,
> +    erl_gen_info::in, erl_gen_info::out) is det.
> +
> +:- inst higher_order
> +    --->    higher_order(ground, ground, ground, ground).
> +
> +    % Generate ELDS code for a call to a builtin procedure.
> +    %
> +:- pred erl_gen_builtin(pred_id::in, proc_id::in, prog_vars::in,
> +    code_model::in, prog_context::in, maybe(elds_expr)::in, elds_expr::out,
> +    erl_gen_info::in, erl_gen_info::out) is det.
> +
> +    % Generate ELDS code for a cast. The list of argument variables
> +    % must have only two elements, the input and the output.
> +    %
> +:- pred erl_gen_cast(prog_context::in, prog_vars::in, maybe(elds_expr)::in,
> +    elds_expr::out, erl_gen_info::in, erl_gen_info::out) is det.
> +

> Index: compiler/erl_code_gen.m
> ===================================================================
> RCS file: compiler/erl_code_gen.m
> diff -N compiler/erl_code_gen.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ compiler/erl_code_gen.m	14 May 2007 04:00:50 -0000
> @@ -0,0 +1,791 @@

> +%-----------------------------------------------------------------------------%
> +%
> +% Code for negation
> +%
> +
> +:- pred erl_gen_negation(hlds_goal::in, code_model::in, instmap::in,
> +    prog_context::in, maybe(elds_expr)::in, elds_expr::out,
> +    erl_gen_info::in, erl_gen_info::out) is det.
> +
> +erl_gen_negation(Cond, CodeModel, InstMap, _Context, MaybeSuccessExpr,
> +        Statement, !Info) :-
> +    Cond = hlds_goal(_, CondGoalInfo),
> +    goal_info_get_code_model(CondGoalInfo, CondCodeModel),
> +    (
> +        % model_det negation:
> +        %       <not(Goal)>
> +        %   ===>
> +
> +        CodeModel = model_det,
> +        % XXX haven't found a test case for this yet
> +        sorry(this_file, "erl_gen_negation: model_det")

:- pred q is det.
q :- not p.

:- pred p is failure.
p :- fail.

> +    ;
> +        % model_semi negation, model_det goal:
> +        %       <succeeded = not(Goal)>
> +        %   ===>
> +        %       <do Goal>,
> +        %       fail
> +
> +        CodeModel = model_semi, CondCodeModel = model_det,
> +        erl_gen_goal(model_det, InstMap, Cond, no, CondStatement, !Info),
> +        Statement = join_exprs(CondStatement, elds_term(elds_fail))
> +    ;
> +        % model_semi negation, model_semi goal:
> +        %       <succeeded = not(Goal)>
> +        %   ===>
> +        %
> +        %   case
> +        %       <Goal [[ true ]]>
> +        %   of
> +        %       fail ->
> +        %           <SuccessExpr> ;
> +        %       _ ->
> +        %           fail
> +        %   end
> +
> +        CodeModel = model_semi, CondCodeModel = model_semi,
> +
> +        OnSuccess = yes(elds_term(elds_true)),  % anything other than fail
> +        erl_gen_goal(model_semi, InstMap, Cond, OnSuccess, CondStatement,
> +            !Info),
> +        Statement = elds_case_expr(CondStatement, [FailCase, OtherCase]),
> +        FailCase = elds_case(elds_fail, expr_or_void(MaybeSuccessExpr)),
> +        OtherCase = elds_case(elds_anon_var, elds_term(elds_fail))
> +    ;
> +        CodeModel = model_semi, CondCodeModel = model_non,
> +        unexpected(this_file, "erl_gen_negation: nondet cond")
> +    ;
> +        CodeModel = model_non,
> +        unexpected(this_file, "erl_gen_negation: nondet negation")
> +    ).
> +

> Index: compiler/erl_code_util.m
> ===================================================================
> RCS file: compiler/erl_code_util.m
> diff -N compiler/erl_code_util.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ compiler/erl_code_util.m	14 May 2007 04:00:50 -0000
> @@ -0,0 +1,413 @@

> +    % erl_bind_unbound_vars(ModuleInfo, VarsToBind, Goal, InstMap,
> +    %   !Statement)
> +    %
> +    % For any variables in VarsToBind which are not bound in Goal, add
> +    % assignment expressions to !Statement.  This is necessary to ensure that
> +    % all branches of ELDS code bind the same variables, to avoid warnings from
> +    % the Erlang compiler when one branch doesn't bind all the variables
> +    % because it has determinism `erroneous'.
> +    %
> +:- pred erl_bind_unbound_vars(module_info::in, set(prog_var)::in,
> +    hlds_goal::in, instmap::in, elds_expr::in, elds_expr::out) is det.
> +
Mention that it doesn't matter to what the variables are bound to.



-- 
Software Engineer                                (Work)   +32 2 757 10 15
Mission Critical                                 (Mobile) +32 485 482 559
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list