[m-rev.] for review: improve error reporting for more foreign language interface pragmas

Julien Fischer jfischer at opturion.com
Wed May 25 11:37:30 AEST 2016


For review by anyone.

Note I will handle pragma foreign_{decl,code,type,proc} in a separate
change.  By and large I haven't changed the content of the error
messages, although that could be improved in many cases.  I will
post something about that latter point to the developers list later.

------------------

Improve error reporting for more foreign language interface pragmas.

The first argument of all foreign language interface pragmas specifies the
foreign language.  Define a separate predicate that can be used to parse
this for all of them and use that predicate for foreign_{enum,export_enum,
import_module,export} pragmas.  (The others will be converted in a separate
change.)

Report all of the syntax errors occurring in foreign_{export_enum,import_module,
export) pragmas, not just the first one.

Improve test coverage for syntax errors occurring in the above pragmas.

compiler/parse_pragma.m:
      Rename parse_foreign_language/2 and re-purpose the existing name for
      a new predicate that parses a foreign language, possibly returning
      an error spec.

      Report all syntax errors that occur in foreign_{export_enum,import_module,
      export} pragmas.

      Add a comment noting some additional checks we could perform for
      foreign_export pragmas.

      For foreign_import_module pragmas, generate separate error messages
      for an incorrect number of arguments and an invalid module name.

      Use the correct error context in a number of places.

      Re-word some error messages.

compiler/parse_mutable.m:
      Conform to the above change to parse_foreign_language.

tests/invalid/Mmakefile:
      Add the new tests.

tests/invalid/bad_foreign_export.{m,err_exp}:
tests/invalid/bad_foreign_export_enum.{m,err_exp}:
tests/invalid/bad_foreign_import_module.{m,err_exp}:
     New tests for syntax errors in these pragmas.

Julien.

diff --git a/compiler/parse_mutable.m b/compiler/parse_mutable.m
index 9277f28..129e21f 100644
--- a/compiler/parse_mutable.m
+++ b/compiler/parse_mutable.m
@@ -410,7 +410,7 @@ parse_mutable_attr(MutAttrTerm, MutAttrResult) :-
      else if
          MutAttrTerm = term.functor(term.atom("foreign_name"), Args, _),
          Args = [LangTerm, ForeignNameTerm],
-        parse_foreign_language(LangTerm, Lang),
+        term_to_foreign_language(LangTerm, Lang),
          ForeignNameTerm = term.functor(term.string(ForeignName), [], _)
      then
          MutAttr = mutable_attr_foreign_name(foreign_name(Lang, ForeignName)),
diff --git a/compiler/parse_pragma.m b/compiler/parse_pragma.m
index 58cbed1..99d570c 100644
--- a/compiler/parse_pragma.m
+++ b/compiler/parse_pragma.m
@@ -38,7 +38,7 @@

      % Parse a term that represents a foreign language.
      %
-:- pred parse_foreign_language(term::in, foreign_language::out) is semidet.
+:- pred term_to_foreign_language(term::in, foreign_language::out) is semidet.

  %---------------------------------------------------------------------------%
  %---------------------------------------------------------------------------%
@@ -153,7 +153,7 @@ parse_pragma_type(ModuleName, VarSet, ErrorTerm, PragmaName, PragmaTerms,
              PragmaTerms, Context, SeqNum, MaybeIOM)
      ;
          PragmaName = "foreign_import_module",
-        parse_pragma_foreign_import_module(ErrorTerm,
+        parse_pragma_foreign_import_module(VarSet, ErrorTerm,
              PragmaTerms, Context, SeqNum, MaybeIOM)
      ;
          (
@@ -387,7 +387,7 @@ parse_pragma_foreign_type(ModuleName, VarSet, ErrorTerm, PragmaTerms,
              MaybeAssertionTerm = yes(AssertionTerm0)
          )
      then
-        ( if parse_foreign_language(LangTerm, Language) then
+        ( if term_to_foreign_language(LangTerm, Language) then
              parse_foreign_language_type(ForeignTypeTerm, VarSet, Language,
                  MaybeForeignType)
          else
@@ -525,46 +525,33 @@ parse_pragma_foreign_export_enum(VarSet, ErrorTerm, PragmaTerms,
              MaybeOverridesTerm = yes(OverridesTerm)
          )
      then
-        ( if parse_foreign_language(LangTerm, ForeignLang) then
-            parse_type_ctor_name_arity("foreign_export_enum", MercuryTypeTerm,
-                MaybeTypeCtor),
-            (
-                MaybeTypeCtor = ok1(TypeCtor),
-                maybe_parse_export_enum_attributes(VarSet, MaybeAttributesTerm,
-                    MaybeAttributes),
-                (
-                    MaybeAttributes = ok1(Attributes),
-                    maybe_parse_export_enum_overrides(VarSet,
-                        MaybeOverridesTerm, MaybeOverrides),
-                    (
-                        MaybeOverrides = ok1(Overrides),
-                        FEEInfo = pragma_info_foreign_export_enum(ForeignLang,
-                            TypeCtor, Attributes, Overrides),
-                        Pragma = pragma_foreign_export_enum(FEEInfo),
-                        ItemPragma = item_pragma_info(Pragma, item_origin_user,
-                            Context, SeqNum),
-                        Item = item_pragma(ItemPragma),
-                        MaybeIOM = ok1(iom_item(Item))
-                    ;
-                        MaybeOverrides = error1(Specs),
-                        MaybeIOM = error1(Specs)
-                    )
-                ;
-                    MaybeAttributes = error1(Specs),
-                    MaybeIOM = error1(Specs)
-                )
-            ;
-                MaybeTypeCtor = error1(Specs),
-                MaybeIOM = error1(Specs)
-            )
+        parse_foreign_language("foreign_export_enum", VarSet, LangTerm,
+            MaybeForeignLang),
+        parse_type_ctor_name_arity("foreign_export_enum", MercuryTypeTerm,
+            MaybeTypeCtor),
+        maybe_parse_export_enum_attributes(VarSet, MaybeAttributesTerm,
+            MaybeAttributes),
+        maybe_parse_export_enum_overrides(VarSet, MaybeOverridesTerm,
+            MaybeOverrides),
+        ( if
+            MaybeForeignLang = ok1(ForeignLang),
+            MaybeTypeCtor = ok1(TypeCtor),
+            MaybeAttributes = ok1(Attributes),
+            MaybeOverrides = ok1(Overrides)
+        then
+            FEEInfo = pragma_info_foreign_export_enum(ForeignLang, TypeCtor,
+                Attributes, Overrides),
+            Pragma = pragma_foreign_export_enum(FEEInfo),
+            ItemPragma = item_pragma_info(Pragma, item_origin_user, Context,
+                SeqNum),
+            Item = item_pragma(ItemPragma),
+            MaybeIOM = ok1(iom_item(Item))
          else
-            Pieces = [words("Error: invalid foreign language in"),
-                pragma_decl("foreign_export_enum"), words("declaration."),
-                nl],
-            % XXX Get_term_context(LangTerm) would be better.
-            Spec = error_spec(severity_error, phase_term_to_parse_tree,
-                [simple_msg(get_term_context(ErrorTerm), [always(Pieces)])]),
-            MaybeIOM = error1([Spec])
+            Specs = get_any_errors1(MaybeForeignLang) ++
+                get_any_errors1(MaybeTypeCtor) ++
+                get_any_errors1(MaybeAttributes) ++
+                get_any_errors1(MaybeOverrides),
+            MaybeIOM = error1(Specs)
          )
      else
          Pieces = [words("Error: wrong number of arguments in"),
@@ -726,18 +713,8 @@ parse_pragma_foreign_enum(VarSet, ErrorTerm, PragmaTerms, Context, SeqNum,
          MaybeIOM) :-
      ( if PragmaTerms = [LangTerm, MercuryTypeTerm, ValuesTerm] then

-        ( if parse_foreign_language(LangTerm, ForeignLang) then
-            MaybeForeignLang = ok1(ForeignLang)
-        else
-            LangPieces = [words("Error: invalid foreign language"),
-                quote(describe_error_term(VarSet, LangTerm)), words("in"),
-                pragma_decl("foreign_enum"), words("declaration."),
-                nl],
-            LangSpec = error_spec(severity_error, phase_term_to_parse_tree,
-                [simple_msg(get_term_context(LangTerm), [always(LangPieces)])]),
-            MaybeForeignLang = error1([LangSpec])
-        ),
-
+        parse_foreign_language("foreign_enum", VarSet, LangTerm,
+            MaybeForeignLang),
          parse_type_ctor_name_arity("foreign_enum", MercuryTypeTerm,
              MaybeTypeCtor),

@@ -776,12 +753,11 @@ parse_pragma_foreign_enum(VarSet, ErrorTerm, PragmaTerms, Context, SeqNum,
          ),

          ( if
-            MaybeForeignLang = ok1(ForeignLangPrime),
+            MaybeForeignLang = ok1(ForeignLang),
              MaybeTypeCtor = ok1(TypeCtor),
              MaybeValues = ok1(Values)
          then
-            FEInfo = pragma_info_foreign_enum(ForeignLangPrime, TypeCtor,
-                Values),
+            FEInfo = pragma_info_foreign_enum(ForeignLang, TypeCtor, Values),
              Pragma = pragma_foreign_enum(FEInfo),
              ItemPragma = item_pragma_info(Pragma, item_origin_user, Context,
                  SeqNum),
@@ -806,6 +782,22 @@ parse_pragma_foreign_enum(VarSet, ErrorTerm, PragmaTerms, Context, SeqNum,
  % Common code for parsing foreign_export_enum and foreign_enum pragms.
  %

+:- pred parse_foreign_language(string::in, varset::in, term::in,
+    maybe1(foreign_language)::out) is det.
+
+parse_foreign_language(PragmaName, VarSet, LangTerm, MaybeForeignLang) :-
+    ( if term_to_foreign_language(LangTerm, ForeignLang) then
+        MaybeForeignLang = ok1(ForeignLang)
+    else
+        LangPieces = [words("Error: invalid foreign language"),
+            quote(describe_error_term(VarSet, LangTerm)), words("in"),
+            pragma_decl(PragmaName), words("declaration."),
+            nl],
+       LangSpec = error_spec(severity_error, phase_term_to_parse_tree,
+            [simple_msg(get_term_context(LangTerm), [always(LangPieces)])]),
+            MaybeForeignLang = error1([LangSpec])
+    ).
+
  :- pred parse_type_ctor_name_arity(string::in, term::in,
      maybe1(type_ctor)::out) is det.

@@ -831,46 +823,49 @@ parse_type_ctor_name_arity(PragmaName, TypeTerm, MaybeTypeCtor) :-
  parse_pragma_foreign_export(VarSet, ErrorTerm, PragmaTerms, Context, SeqNum,
          MaybeIOM) :-
      ( if PragmaTerms = [LangTerm, PredAndModesTerm, FunctionTerm] then
-        ( if FunctionTerm = term.functor(term.string(Function), [], _) then
-            ContextPieces = cord.from_list([words("In"),
-                pragma_decl("foreign_export"), words("declaration:")]),
-            parse_pred_or_func_and_arg_modes(no, VarSet, ContextPieces,
-                PredAndModesTerm, MaybePredAndModes),
-            (
-                MaybePredAndModes = ok3(PredName, PredOrFunc, Modes),
-                ( if parse_foreign_language(LangTerm, ForeignLanguage) then
-                    PredNameModesPF = pred_name_modes_pf(PredName, Modes,
-                        PredOrFunc),
-                    FPEInfo = pragma_info_foreign_proc_export(ForeignLanguage,
-                        PredNameModesPF, Function),
-                    Pragma = pragma_foreign_proc_export(FPEInfo),
-                    ItemPragma = item_pragma_info(Pragma, item_origin_user,
-                        Context, SeqNum),
-                    Item = item_pragma(ItemPragma),
-                    MaybeIOM = ok1(iom_item(Item))
-                else
-                    Pieces = [words("Error: invalid foreign language in"),
-                        pragma_decl("foreign_export"), words("declaration."),
-                        nl],
-                    Spec = error_spec(severity_error, phase_term_to_parse_tree,
-                        [simple_msg(get_term_context(LangTerm),
-                            [always(Pieces)])]),
-                    MaybeIOM = error1([Spec])
-                )
-            ;
-                MaybePredAndModes = error3(Specs),
-                MaybeIOM = error1(Specs)
-            )
+        parse_foreign_language("foreign_export", VarSet, LangTerm,
+            MaybeForeignLang),
+        ContextPieces = cord.from_list([words("In"),
+            pragma_decl("foreign_export"), words("declaration:")]),
+        parse_pred_or_func_and_arg_modes(no, VarSet, ContextPieces,
+            PredAndModesTerm, MaybePredAndModes),
+        ( if FunctionTerm = term.functor(term.string(Function0), [], _) then
+            MaybeFunction = ok1(Function0)
+            % XXX TODO: do some additional checks here:
+            % 1. check that Function0 is not the empty string.
+            % 2. if we have a valid foreign language, check that Function0
+            %    is a valid identifier in that language.
          else
-            % XXX Why this wording?
-            Pieces = [words("Error: expected pragma"),
-                words("foreign_export(Lang, PredName(ModeList), Function)."),
-                nl],
-            % XXX Should we use the context of FunctionTerm?
-            Spec = error_spec(severity_error, phase_term_to_parse_tree,
-                [simple_msg(get_term_context(PredAndModesTerm),
-                    [always(Pieces)])]),
-            MaybeIOM = error1([Spec])
+            FunctionPieces = [
+                words("In"), pragma_decl("foreign_export"),
+                words("declaration: error:"),
+                words("string expected at"),
+                quote(describe_error_term(VarSet, FunctionTerm)),
+                suffix("."), nl
+            ],
+            FunctionSpec = error_spec(severity_error, phase_term_to_parse_tree,
+                [simple_msg(get_term_context(FunctionTerm),
+                    [always(FunctionPieces)])]),
+            MaybeFunction = error1([FunctionSpec])
+        ),
+        ( if
+            MaybeForeignLang = ok1(ForeignLang),
+            MaybePredAndModes = ok3(PredName, PredOrFunc, Modes),
+            MaybeFunction = ok1(Function)
+        then
+            PredNameModesPF = pred_name_modes_pf(PredName, Modes, PredOrFunc),
+            FPEInfo = pragma_info_foreign_proc_export(ForeignLang,
+                PredNameModesPF, Function),
+            Pragma = pragma_foreign_proc_export(FPEInfo),
+            ItemPragma = item_pragma_info(Pragma, item_origin_user, Context,
+                SeqNum),
+            Item = item_pragma(ItemPragma),
+            MaybeIOM = ok1(iom_item(Item))
+        else
+            Specs = get_any_errors1(MaybeForeignLang) ++
+                get_any_errors3(MaybePredAndModes) ++
+                get_any_errors1(MaybeFunction),
+            MaybeIOM = error1(Specs)
          )
      else
          Pieces = [words("Error: wrong number of arguments in"),
@@ -882,34 +877,49 @@ parse_pragma_foreign_export(VarSet, ErrorTerm, PragmaTerms, Context, SeqNum,

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

-:- pred parse_pragma_foreign_import_module(term::in, list(term)::in,
-    prog_context::in, int::in, maybe1(item_or_marker)::out) is det.
+:- pred parse_pragma_foreign_import_module(varset::in, term::in,
+    list(term)::in, prog_context::in, int::in, maybe1(item_or_marker)::out)
+    is det.

-parse_pragma_foreign_import_module(ErrorTerm, PragmaTerms, Context, SeqNum,
-        MaybeIOM) :-
+parse_pragma_foreign_import_module(VarSet, ErrorTerm, PragmaTerms, Context,
+        SeqNum, MaybeIOM) :-
      ( if
-        PragmaTerms = [LangTerm, ImportTerm],
-        try_parse_sym_name_and_no_args(ImportTerm, Import)
+        PragmaTerms = [LangTerm, ImportTerm]
      then
-        ( if parse_foreign_language(LangTerm, Language) then
+        parse_foreign_language("foreign_import_language", VarSet, LangTerm,
+            MaybeForeignLang),
+        ( if try_parse_sym_name_and_no_args(ImportTerm, Import0) then
+            MaybeImportModule = ok1(Import0)
+        else
+            ImportModulePieces = [
+                words("Error: invalid module name"),
+                quote(describe_error_term(VarSet, ImportTerm)),
+                words("in"), pragma_decl("foreign_import_module"),
+                words("declaration."), nl],
+            ImportModuleSpec = error_spec(severity_error,
+                phase_term_to_parse_tree,
+                [simple_msg(get_term_context(ImportTerm),
+                [always(ImportModulePieces)])]),
+            MaybeImportModule = error1([ImportModuleSpec])
+        ),
+        ( if
+            MaybeForeignLang = ok1(Language),
+            MaybeImportModule = ok1(Import)
+        then
              FIM = foreign_import_module_info(Language, Import),
              FIMInfo = pragma_info_foreign_import_module(FIM),
              Pragma = pragma_foreign_import_module(FIMInfo),
-            ItemPragma = item_pragma_info(Pragma, item_origin_user,
-                Context, SeqNum),
+            ItemPragma = item_pragma_info(Pragma, item_origin_user, Context,
+                SeqNum),
              Item = item_pragma(ItemPragma),
              MaybeIOM = ok1(iom_item(Item))
          else
-            Pieces = [words("Error: invalid foreign language in"),
-                pragma_decl("foreign_import_module"),
-                words("declaration."), nl],
-            Spec = error_spec(severity_error, phase_term_to_parse_tree,
-                [simple_msg(get_term_context(LangTerm), [always(Pieces)])]),
-            MaybeIOM = error1([Spec])
+            Specs = get_any_errors1(MaybeForeignLang) ++
+                get_any_errors1(MaybeImportModule),
+            MaybeIOM = error1(Specs)
          )
      else
-        Pieces = [words("Error: wrong number of arguments"),
-            words("or invalid module name in"),
+        Pieces = [words("Error: wrong number of arguments in"),
              pragma_decl("foreign_import_module"),
              words("declaration."), nl],
          Spec = error_spec(severity_error, phase_term_to_parse_tree,
@@ -1906,9 +1916,9 @@ parse_foreign_literal_or_include(Term, LiteralOrInclude) :-
          LiteralOrInclude = floi_include_file(FileName)
      ).

-parse_foreign_language(term.functor(term.string(String), _, _), Lang) :-
+term_to_foreign_language(term.functor(term.string(String), _, _), Lang) :-
      globals.convert_foreign_language(String, Lang).
-parse_foreign_language(term.functor(term.atom(String), _, _), Lang) :-
+term_to_foreign_language(term.functor(term.atom(String), _, _), Lang) :-
      globals.convert_foreign_language(String, Lang).

  :- pred parse_foreign_language_type(term::in, varset::in, foreign_language::in,
@@ -1985,7 +1995,7 @@ parse_pragma_foreign_decl_pragma(VarSet, ErrorTerm, PragmaTerms,
              parse_foreign_decl_is_local(IsLocalTerm, IsLocal)
          )
      then
-        ( if parse_foreign_language(LangTerm, ForeignLanguage) then
+        ( if term_to_foreign_language(LangTerm, ForeignLanguage) then
              ( if
                  parse_foreign_literal_or_include(HeaderTerm, LiteralOrInclude)
              then
@@ -2034,7 +2044,7 @@ parse_pragma_foreign_code_pragma(ErrorTerm,
      InvalidDeclPrefix = [words("Error: invalid"),
          pragma_decl("foreign_code"), words("declaration:")],
      ( if PragmaTerms = [LangTerm, CodeTerm] then
-        ( if parse_foreign_language(LangTerm, ForeignLanguagePrime) then
+        ( if term_to_foreign_language(LangTerm, ForeignLanguagePrime) then
              ForeignLanguage = ForeignLanguagePrime,
              LangSpecs = []
          else
@@ -2091,7 +2101,7 @@ parse_pragma_foreign_proc_pragma(ModuleName, VarSet, ErrorTerm,
          pragma_decl("foreign_proc"), words("declaration:")],
      (
          PragmaTerms = [LangTerm | RestTerms],
-        ( if parse_foreign_language(LangTerm, ForeignLanguagePrime) then
+        ( if term_to_foreign_language(LangTerm, ForeignLanguagePrime) then
              ForeignLanguage = ForeignLanguagePrime,
              LangSpecs = []
          else
diff --git a/tests/invalid/Mmakefile b/tests/invalid/Mmakefile
index 295526b..7efb373 100644
--- a/tests/invalid/Mmakefile
+++ b/tests/invalid/Mmakefile
@@ -50,6 +50,9 @@ SINGLEMODULE= \
  	bad_detism \
  	bad_end_module \
  	bad_foreign_enum \
+	bad_foreign_export \
+	bad_foreign_export_enum \
+	bad_foreign_import_module \
  	bad_finalise_decl \
  	bad_initialise_decl \
  	bad_inst_for_type \
diff --git a/tests/invalid/bad_foreign_export.err_exp b/tests/invalid/bad_foreign_export.err_exp
index e69de29..4e746ae 100644
--- a/tests/invalid/bad_foreign_export.err_exp
+++ b/tests/invalid/bad_foreign_export.err_exp
@@ -0,0 +1,14 @@
+bad_foreign_export.m:020: Error: wrong number of arguments in
+bad_foreign_export.m:020:   `:- pragma foreign_export' declaration.
+bad_foreign_export.m:024: In `:- pragma foreign_export' declaration: error:
+bad_foreign_export.m:024:   atom expected at 12345.
+bad_foreign_export.m:028: In `:- pragma foreign_export' declaration: error:
+bad_foreign_export.m:028:   string expected at `12345'.
+bad_foreign_export.m:032: Error: invalid foreign language `"InvalidLanguage"'
+bad_foreign_export.m:032:   in `:- pragma foreign_export' declaration.
+bad_foreign_export.m:037: Error: invalid foreign language `"InvalidLanguage"'
+bad_foreign_export.m:037:   in `:- pragma foreign_export' declaration.
+bad_foreign_export.m:038: In `:- pragma foreign_export' declaration: error:
+bad_foreign_export.m:038:   atom expected at 1234.
+bad_foreign_export.m:039: In `:- pragma foreign_export' declaration: error:
+bad_foreign_export.m:039:   string expected at `5678'.
diff --git a/tests/invalid/bad_foreign_export.m b/tests/invalid/bad_foreign_export.m
index e69de29..a693b1a 100644
--- a/tests/invalid/bad_foreign_export.m
+++ b/tests/invalid/bad_foreign_export.m
@@ -0,0 +1,40 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
+%---------------------------------------------------------------------------%
+%
+% Test for the error messages generated for syntax errror in 'foreign_export'
+% pragmas.
+
+:- module bad_foreign_export.
+:- interface.
+
+:- func foo(int, int) = int.
+
+:- implementation.
+:- import_module int.
+
+foo(X, Y) = X + Y.
+
+    % Incorrect number of arguments.
+    %
+:- pragma foreign_export("C").
+
+    % Second arg is not pred-and-modes.
+    %
+:- pragma foreign_export("C", 12345, "Test2").
+
+    % Third arg is not a string.
+    %
+:- pragma foreign_export("C", foo(in, in) = out, 12345).
+
+    % Invalid foreign laguage.
+    %
+:- pragma foreign_export("InvalidLanguage", foo(in, in) = out, "Test4").
+
+    % Check that the contexts error messages for each argument are correct.
+    %
+:- pragma foreign_export(
+    "InvalidLanguage",
+    1234,
+    5678
+).
diff --git a/tests/invalid/bad_foreign_export_enum.err_exp b/tests/invalid/bad_foreign_export_enum.err_exp
index e69de29..8aec84f 100644
--- a/tests/invalid/bad_foreign_export_enum.err_exp
+++ b/tests/invalid/bad_foreign_export_enum.err_exp
@@ -0,0 +1,16 @@
+bad_foreign_export_enum.m:017: Error: wrong number of arguments in
+bad_foreign_export_enum.m:017:   `:- pragma foreign_export_enum' declaration.
+bad_foreign_export_enum.m:021: Error: invalid foreign language
+bad_foreign_export_enum.m:021:   `"InvalidLanguage"' in
+bad_foreign_export_enum.m:021:   `:- pragma foreign_export_enum' declaration.
+bad_foreign_export_enum.m:025: Error: expected name/arity for type in
+bad_foreign_export_enum.m:025:   `:- pragma foreign_export_enum' declaration.
+bad_foreign_export_enum.m:028: Error: invalid foreign language
+bad_foreign_export_enum.m:028:   `"InvalidLanguage"' in
+bad_foreign_export_enum.m:028:   `:- pragma foreign_export_enum' declaration.
+bad_foreign_export_enum.m:029: Error: expected name/arity for type in
+bad_foreign_export_enum.m:029:   `:- pragma foreign_export_enum' declaration.
+bad_foreign_export_enum.m:030: Error: malformed attributes list in
+bad_foreign_export_enum.m:030:   `:- pragma foreign_export_enum' declaration.
+bad_foreign_export_enum.m:031: Error: expected list of mapping elements, not
+bad_foreign_export_enum.m:031:   `5678'.
diff --git a/tests/invalid/bad_foreign_export_enum.m b/tests/invalid/bad_foreign_export_enum.m
index e69de29..7e914d1 100644
--- a/tests/invalid/bad_foreign_export_enum.m
+++ b/tests/invalid/bad_foreign_export_enum.m
@@ -0,0 +1,33 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
+%---------------------------------------------------------------------------%
+
+:- module bad_foreign_export_enum.
+:- interface.
+
+:- type fruit
+    --->    orange
+    ;       lemon
+    ;       apple.
+
+:- implementation.
+
+    % Wrong number of arguments.
+    %
+:- pragma foreign_export_enum("C").
+
+    % Invalid foreign language.
+    %
+:- pragma foreign_export_enum("InvalidLanguage", fruit/0).
+
+    % Second arg is not name / arity.
+    %
+:- pragma foreign_export_enum("C", fruit).
+
+:- pragma foreign_export_enum(
+    "InvalidLanguage",
+    fruit,
+    1234,
+    5678
+).
+
diff --git a/tests/invalid/bad_foreign_import_module.err_exp b/tests/invalid/bad_foreign_import_module.err_exp
index e69de29..49a865b 100644
--- a/tests/invalid/bad_foreign_import_module.err_exp
+++ b/tests/invalid/bad_foreign_import_module.err_exp
@@ -0,0 +1,14 @@
+bad_foreign_import_module.m:018: Error: wrong number of arguments in
+bad_foreign_import_module.m:018:   `:- pragma foreign_import_module'
+bad_foreign_import_module.m:018:   declaration.
+bad_foreign_import_module.m:022: Error: invalid foreign language
+bad_foreign_import_module.m:022:   `"InvalidForeignLang"' in
+bad_foreign_import_module.m:022:   `:- pragma foreign_import_language'
+bad_foreign_import_module.m:022:   declaration.
+bad_foreign_import_module.m:027: Error: invalid foreign language
+bad_foreign_import_module.m:027:   `"InvalidForeignLang"' in
+bad_foreign_import_module.m:027:   `:- pragma foreign_import_language'
+bad_foreign_import_module.m:027:   declaration.
+bad_foreign_import_module.m:028: Error: invalid module name `int(int)' in
+bad_foreign_import_module.m:028:   `:- pragma foreign_import_module'
+bad_foreign_import_module.m:028:   declaration.
diff --git a/tests/invalid/bad_foreign_import_module.m b/tests/invalid/bad_foreign_import_module.m
index e69de29..83a79c4 100644
--- a/tests/invalid/bad_foreign_import_module.m
+++ b/tests/invalid/bad_foreign_import_module.m
@@ -0,0 +1,29 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
+%---------------------------------------------------------------------------%
+%
+% Test for error messages produced by syntax errors in 'foreign_import_module'
+% pragmas.
+%
+
+:- module bad_foreign_import_module.
+:- interface.
+
+:- type foo ---> foo.
+
+:- implementation.
+
+    % Incorrect number of arguments.
+    %
+:- pragma foreign_import_module("C").
+
+    % Invalid foreign language.
+    %
+:- pragma foreign_import_module("InvalidForeignLang", int).
+
+    % Check that contexts for the language and import term are correct.
+    %
+:- pragma foreign_import_module(
+     "InvalidForeignLang",
+      int(int)
+).


More information about the reviews mailing list