]> Repositorios git - scryer-prolog.git/commitdiff
print errors with line numbers in GNU style
authorMark Thom <[email protected]>
Fri, 4 Oct 2019 21:32:26 +0000 (15:32 -0600)
committerMark Thom <[email protected]>
Fri, 4 Oct 2019 21:32:26 +0000 (15:32 -0600)
src/prolog/lib/dcgs.pl
src/prolog/lib/terms.pl
src/prolog/machine/compile.rs
src/prolog/machine/dynamic_database.rs
src/prolog/machine/mod.rs
src/prolog/toplevel.pl
src/tests.rs

index 3dea6bb3919778f1771dfa99d2f5fdcff0313333..626a6b8bc69d07bac2e91c791dd7aad5d2bced1a 100644 (file)
@@ -20,7 +20,7 @@ phrase(G, Ls0, Ls2) :-
     nonvar(G), G = (G1, G2), !,
     phrase(G1, Ls0, Ls1), phrase(G2, Ls1, Ls2).
 phrase(G, Ls0, Ls1) :-
-    nonvar(G), G == !, !, Ls0 = [], Ls1 = [].
+    nonvar(G), G == !, !, Ls0 = Ls1.
 phrase(G, Ls0, Ls1) :-
     call(G, Ls0, Ls1).
 
index 8391457b9c0b4b25ea6647432da019cbcf9e86f2..d9f41528b7260665a7ac10de01b12eadf3f42755 100644 (file)
@@ -1,10 +1,11 @@
 :- module(terms, [numbervars/3]).
 
 :- use_module(library(error)).
-    
+
 numbervars(Term, N0, N) :-
-   catch(internal_numbervars(Term, N0, N), error(E,Ctx),
-      ( ( var(Ctx) -> Ctx = numbervars/3 ; true ), throw(error(E,Ctx) ) ) ).
+   catch(internal_numbervars(Term, N0, N),
+        error(E,Ctx),
+        ( ( var(Ctx) -> Ctx = numbervars/3 ; true ), throw(error(E,Ctx) ) ) ).
 
 internal_numbervars(Term, N0, N) :-
    must_be(integer, N0),
@@ -12,7 +13,7 @@ internal_numbervars(Term, N0, N) :-
    term_variables(Term, Vars),
    numberlist(Vars, N0, N).
 
-numberlist([], N,N).
-numberlist(['$VAR'(N0)|Vars], N0,N) :-
+numberlist([], N, N).
+numberlist(['$VAR'(N0)|Vars], N0, N) :-
    N1 is N0+1,
-   numberlist(Vars, N1,N).
+   numberlist(Vars, N1, N).
index b946951a40d7e7866e83b7b9b2de1dfd07bcce44..11b80f74a0dc1254ab0da5fd2414742835203f49 100644 (file)
@@ -61,26 +61,35 @@ fn load_module<R: Read>(
     wam: &mut Machine,
     stream: ParsingStream<R>,
     suppress_warnings: bool,
+    listing_src: ClauseName,
 ) -> Result<Option<ClauseName>, SessionError> {
     // follow the operation of compile_user_module, but before
     // compiling, check that a module is declared in the file. if not,
     // throw an exception.
     let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
     setup_indices(wam, clause_name!("builtins"), &mut indices)?;
+    
+    let mut compiler = ListingCompiler::new(
+        &wam.code_repo,
+        suppress_warnings,
+        listing_src,
+    );
 
-    let mut compiler = ListingCompiler::new(&wam.code_repo, suppress_warnings);
-    let results = compiler.gather_items(wam, stream, &mut indices)?;
-
+    let results = compiler.gather_items(wam, stream, &mut indices);
+    
     let module_name = if let Some(ref module) = &compiler.module {
         Some(module.module_decl.name.clone())
     } else {
         None
     };
 
-    match compile_work_impl(&mut compiler, wam, indices, results) {
-        EvalSession::Error(e) => Err(e),
-        _ => Ok(module_name),
-    }
+    results.and_then(|results| compile_work_impl(&mut compiler, wam, indices, results))
+           .or_else(|e| {
+               compiler.print_error(&e);
+               Err(e)
+           })?;
+
+    Ok(module_name)
 }
 
 pub(super)
@@ -90,13 +99,13 @@ fn load_module_from_file(
     suppress_warnings: bool,
 ) -> Result<Option<ClauseName>, SessionError> {
     let path = fix_filename(wam.indices.atom_tbl.clone(), filename)?;
+    let filename = clause_name!(path.to_string_lossy().to_string(), wam.indices.atom_tbl);
 
     let file_handle = File::open(&path).or_else(|_| {
-        let filename = clause_name!(path.to_string_lossy().to_string(), wam.indices.atom_tbl);
-        Err(SessionError::InvalidFileName(filename))
+        Err(SessionError::InvalidFileName(filename.clone()))
     })?;
 
-    load_module(wam, parsing_stream(file_handle), suppress_warnings)
+    load_module(wam, parsing_stream(file_handle), suppress_warnings, filename)
 }
 
 pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
@@ -115,7 +124,7 @@ fn compile_relation(
 }
 
 fn issue_singleton_warnings(
-    module_name: ClauseName,
+    src_name: ClauseName,
     terms_and_locs: Vec<(Term, usize, usize)>,
 ) {
     for (term, line_num, _col_num) in terms_and_locs {
@@ -128,7 +137,7 @@ fn issue_singleton_warnings(
                 *entry += 1;
             }
         }
-        
+
         for (var, count) in var_count {
             if count == 1 && !var.starts_with("_") && var.as_str() != "!" {
                 singletons.push(var);
@@ -137,12 +146,12 @@ fn issue_singleton_warnings(
 
         if let Some(last_var) = singletons.pop() {
             print!("Warning: {}:{}: Singleton variables: [",
-                   module_name, line_num);
-            
+                   src_name, line_num);
+
             for var in singletons {
                 print!("{}, ", var);
             }
-            
+
             println!("{}]", last_var);
         }
     }
@@ -247,7 +256,7 @@ pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession {
             }
         }
         TopLevelPacket::Decl(TopLevel::Declaration(decl), _) => {
-            let mut compiler = ListingCompiler::new(&wam.code_repo, false);
+            let mut compiler = ListingCompiler::new(&wam.code_repo, false, clause_name!("user"));
             let indices = try_eval_session!(compile_decl(wam, &mut compiler, decl));
 
             try_eval_session!(wam.check_toplevel_code(&indices));
@@ -332,7 +341,7 @@ pub(super) fn compile_into_module<R: Read>(
     let mut indices = default_index_store!(wam.atom_tbl_of(&name));
     try_eval_session!(setup_indices(wam, module_name.clone(), &mut indices));
 
-    let mut compiler = ListingCompiler::new(&wam.code_repo, true);
+    let mut compiler = ListingCompiler::new(&wam.code_repo, true, module_name.clone());
 
     match compile_into_module_impl(wam, &mut compiler, module_name, src, indices) {
         Ok(()) => EvalSession::EntrySuccess,
@@ -478,7 +487,8 @@ pub struct ListingCompiler {
     orig_term_expansion_lens: (usize, usize),
     orig_goal_expansion_lens: (usize, usize),
     initialization_goals: (Vec<QueryTerm>, VecDeque<TopLevel>),
-    suppress_warnings: bool
+    suppress_warnings: bool,
+    listing_src: ClauseName // a file? a module?
 }
 
 fn add_toplevel_code(wam: &mut Machine, code: Code, mut indices: IndexStore) {
@@ -533,7 +543,8 @@ fn load_library(
 ) -> Result<ClauseName, SessionError> {
     match LIBRARIES.borrow().get(name.as_str()) {
         Some(code) => {
-            let module_name = load_module(wam, parsing_stream(code.as_bytes()), suppress_warnings)?;
+            let module_name = load_module(wam, parsing_stream(code.as_bytes()),
+                                          suppress_warnings, name.clone())?;
             module_name.ok_or(SessionError::NoModuleDeclaration(name))
         }
         None => Err(SessionError::ModuleNotFound)
@@ -542,7 +553,11 @@ fn load_library(
 
 impl ListingCompiler {
     #[inline]
-    pub fn new(code_repo: &CodeRepo, suppress_warnings: bool) -> Self {
+    pub fn new(
+        code_repo: &CodeRepo,
+        suppress_warnings: bool,
+        listing_src: ClauseName,
+    ) -> Self {
         ListingCompiler {
             non_counted_bt_preds: IndexSet::new(),
             module: None,
@@ -552,7 +567,8 @@ impl ListingCompiler {
             orig_goal_expansion_lens: code_repo
                 .term_dir_entry_len((clause_name!("goal_expansion"), 2)),
            initialization_goals: (vec![], VecDeque::from(vec![])),
-            suppress_warnings
+            suppress_warnings,
+            listing_src
         }
     }
 
@@ -958,6 +974,14 @@ impl ListingCompiler {
         discard_result!(code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags));
         discard_result!(code_repo.compile_hook(CompileTimeHook::UserTermExpansion, flags));
     }
+
+    fn print_error(&self, e: &SessionError) {
+        if let &SessionError::ParserError(ref e) = e {
+            if let Some((line_num, _col_num)) = e.line_and_col_num() {
+                println!("{}:{}: {}", self.listing_src, line_num, e.as_str());
+            }
+        }
+    }
 }
 
 fn compile_work_impl(
@@ -965,19 +989,19 @@ fn compile_work_impl(
     wam: &mut Machine,
     mut indices: IndexStore,
     mut results: GatherResult,
-) -> EvalSession {
-    let module_code = try_eval_session!(compiler.generate_code(
+) -> Result<(), SessionError> {
+    let module_code = compiler.generate_code(
         results.worker_results,
         wam,
         &mut indices.code_dir,
         0
-    ));
-    let toplvl_code = try_eval_session!(compiler.generate_code(
+    )?;
+    let toplvl_code = compiler.generate_code(
         results.toplevel_results,
         wam,
         &mut results.toplevel_indices.code_dir,
         module_code.len()
-    ));
+    )?;
 
     if let Some(ref mut module) = &mut compiler.module {
         module.user_term_expansions = results.addition_results.take_term_expansions();
@@ -986,49 +1010,46 @@ fn compile_work_impl(
 
     let flags = wam.machine_flags();
 
-    try_eval_session!(wam
-        .code_repo
-        .compile_hook(CompileTimeHook::UserTermExpansion, flags));
-    try_eval_session!(wam
-        .code_repo
-        .compile_hook(CompileTimeHook::UserGoalExpansion, flags));
+    wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion, flags)?;
+    wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags)?;
 
     if let Some(module) = compiler.module.take() {
         let mut clause_code_generator =
             ClauseCodeGenerator::new(module_code.len() + toplvl_code.len(),
                                      module.module_decl.name.clone());
 
-        try_eval_session!(wam.check_toplevel_code(&results.toplevel_indices));
-        try_eval_session!(
-            clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)
-        );
+        wam.check_toplevel_code(&results.toplevel_indices)?;
+        clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
 
         add_module_code(wam, module, module_code, indices);
         add_toplevel_code(wam, toplvl_code, results.toplevel_indices);
 
         clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
     } else {
-        try_eval_session!(add_non_module_code(
+        add_non_module_code(
             wam,
             results.dynamic_clause_map,
             module_code,
             indices
-        ));
+        )?;
     }
 
-    let init_goal_code = try_eval_session!(compiler.generate_init_goal_code(
+    let init_goal_code = compiler.generate_init_goal_code(
        wam.machine_flags()
-    ));
+    )?;
 
     if init_goal_code.len() > 0 {
        wam.run_init_code(init_goal_code);
     }
 
     if !compiler.suppress_warnings {
-        issue_singleton_warnings(compiler.get_module_name(), results.top_level_terms);
+        issue_singleton_warnings(
+            compiler.listing_src.clone(),
+            results.top_level_terms,
+        );
     }
-    
-    EvalSession::EntrySuccess
+
+    Ok(())
 }
 
 fn compile_work<R: Read>(
@@ -1038,7 +1059,8 @@ fn compile_work<R: Read>(
     mut indices: IndexStore,
 ) -> EvalSession {
     let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
-    compile_work_impl(compiler, wam, indices, results)
+    try_eval_session!(compile_work_impl(compiler, wam, indices, results));
+    EvalSession::EntrySuccess
 }
 
 /* This is a truncated version of compile_user_module, used for
@@ -1047,11 +1069,12 @@ M:verify_attributes on attributed variables. */
 pub fn compile_special_form<R: Read>(
     wam: &mut Machine,
     src: ParsingStream<R>,
+    listing_src: ClauseName,
 ) -> Result<Code, SessionError> {
     let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
     setup_indices(wam, clause_name!("builtins"), &mut indices)?;
 
-    let mut compiler = ListingCompiler::new(&wam.code_repo, true);
+    let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src);
     let results = compiler.gather_items(wam, src, &mut indices)?;
 
     compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)
@@ -1062,13 +1085,16 @@ pub fn compile_listing<R: Read>(
     wam: &mut Machine,
     src: ParsingStream<R>,
     indices: IndexStore,
-    suppress_warnings: bool
+    suppress_warnings: bool,
+    listing_src: ClauseName,
 ) -> EvalSession {
-    let mut compiler = ListingCompiler::new(&wam.code_repo, suppress_warnings);
+    let mut compiler = ListingCompiler::new(&wam.code_repo, suppress_warnings, listing_src);
 
     match compile_work(&mut compiler, wam, src, indices) {
         EvalSession::Error(e) => {
             compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo);
+            compiler.print_error(&e);
+
             EvalSession::Error(e)
         }
         result => result,
@@ -1095,8 +1121,9 @@ pub fn compile_user_module<R: Read>(
     wam: &mut Machine,
     src: ParsingStream<R>,
     suppress_warnings: bool,
+    listing_src: ClauseName,
 ) -> EvalSession {
     let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
     try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices));
-    compile_listing(wam, src, indices, suppress_warnings)
+    compile_listing(wam, src, indices, suppress_warnings, listing_src)
 }
index 9ebdcdf66951c609c61f80888524f5d12f744e37..de6352fcfaf851a94294553d7a055290dba80013 100644 (file)
@@ -21,17 +21,19 @@ impl Machine {
         name: ClauseName,
         arity: usize,
     ) -> EvalSession {
+        let user_src = clause_name!("user");
+
         match name.owning_module().as_str() {
             "user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() {
                 Some(idx) => {
                     let module = idx.0.borrow().1.clone();
 
                     match module.as_str() {
-                        "user" => compile_user_module(self, src, true),
-                        _ => compile_into_module(self, module, src, name),
+                        "user" => compile_user_module(self, src, true, user_src),
+                        _ => compile_into_module(self, module, src, name)                                                 
                     }
                 }
-                None => compile_user_module(self, src, true),
+                None => compile_user_module(self, src, true, user_src),
             },
             _ => compile_into_module(self, name.owning_module(), src, name),
         }
index a77268c273002941ebf2f5876f5fedfb8cbf66e8..35c1d6e2c6149123fadfdaaf2c85f71276e8b702 100644 (file)
@@ -174,7 +174,11 @@ static TOPLEVEL: &str = include_str!("../toplevel.pl");
 
 impl Machine {
     fn compile_special_forms(&mut self) {
-        match compile_special_form(self, parsing_stream(VERIFY_ATTRS.as_bytes())) {
+        let verify_attrs_src = clause_name!("verify_attrs.pl");
+        let project_attrs_src = clause_name!("project_attributes.pl");
+
+        match compile_special_form(self, parsing_stream(VERIFY_ATTRS.as_bytes()), verify_attrs_src)
+        {
             Ok(code) => {
                 self.machine_st.attr_var_init.verify_attrs_loc = self.code_repo.code.len();
                 self.code_repo.code.extend(code.into_iter());
@@ -182,7 +186,8 @@ impl Machine {
             Err(_) => panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
         }
 
-        match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes())) {
+        match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes()), project_attrs_src)
+        {
             Ok(code) => {
                 self.machine_st.attr_var_init.project_attrs_loc = self.code_repo.code.len();
                 self.code_repo.code.extend(code.into_iter());
@@ -193,7 +198,8 @@ impl Machine {
 
     fn compile_top_level(&mut self) {
         self.toplevel_idx = self.code_repo.code.len();
-        compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()), true);
+        compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()),
+                            true, clause_name!("toplevel.pl"));
     }
 
     fn compile_scryerrc(&mut self) {
@@ -210,7 +216,8 @@ impl Machine {
                 Err(_) => return,
             };
 
-            compile_user_module(self, file_src, true);
+            compile_user_module(self, file_src, true,
+                                clause_name!("$HOME/.scryerrc"));
         }
     }
 
@@ -224,7 +231,7 @@ impl Machine {
     pub fn run_init_code(&mut self, code: Code) {
        let old_machine_st = self.machine_st.sink_to_snapshot();
        self.machine_st.reset();
-       
+
        self.code_repo.cached_query = code;
        self.run_query(&AllocVarDict::new());
 
@@ -268,16 +275,21 @@ impl Machine {
             &mut wam,
             parsing_stream(BUILTINS.as_bytes()),
             default_index_store!(atom_tbl.clone()),
-            true
+            true,
+            clause_name!("builtins.pl"),
         );
 
         wam.compile_special_forms();
 
-        compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()), true);
-        compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()), true);
-        compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()), true);
-        compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true);
-        
+        compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()), true,
+                            clause_name!("error"));
+        compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()), true,
+                            clause_name!("lists"));
+        compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()), true,
+                            clause_name!("non_iso"));
+        compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
+                            clause_name!("si"));
+
         wam.compile_top_level();
         wam.compile_scryerrc();
 
@@ -371,9 +383,9 @@ impl Machine {
         }
     }
 
-    pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
+    fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
         let h = self.machine_st.heap.h;
-
+        
         let err = MachineError::session_error(h, err);
         let stub = MachineError::functor_stub(key.0, key.1);
         let err = self.machine_st.error_form(err, stub);
@@ -447,13 +459,13 @@ impl Machine {
                self.indices.remove_module(clause_name!("user"), &module);
                self.indices.use_module(&mut self.code_repo, self.machine_st.flags,
                                         &module)?;
-               
+
                Ok(self.indices.insert_module(module))
            } else {
                 Ok(())
             }
-        );     
-       
+        );
+
        self.code_repo.cached_query = cached_query;
 
        if let Err(e) = result {
@@ -496,7 +508,7 @@ impl Machine {
                                                  self.machine_st.flags,
                                                  &module,
                                                  &exports)?;
-                
+
                Ok(self.indices.insert_module(module))
            } else {
                 Ok(())
@@ -513,10 +525,12 @@ impl Machine {
     fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
         match code_ptr {
             REPLCodePtr::CompileBatch => {
+                let user_src = clause_name!("user");
+
                 let src = readline::input_stream();
                 readline::set_prompt(false);
 
-                if let EvalSession::Error(e) = compile_user_module(self, src, false) {
+                if let EvalSession::Error(e) = compile_user_module(self, src, false, user_src) {
                     self.throw_session_error(e, (clause_name!("repl"), 0));
                 }
             }
@@ -642,7 +656,7 @@ impl Machine {
                        raw_stdout.flush().unwrap();
                        next_keypress()
                    };
-                   
+
                     let result = match keypress {
                         ContinueResult::ContinueQuery => {
                            print!(" ;\r\n");
@@ -713,7 +727,7 @@ impl Machine {
 
         self.machine_st.absorb_snapshot(snapshot);
     }
-    
+
     pub(super) fn run_query(&mut self, alloc_locs: &AllocVarDict) {
        self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
         let end_ptr = CodePtr::Local(self.machine_st.cp);
index 0bd6ed74a15f3c647f4fb0e1a718ae19cbbaee00..443ebda75dca81c40ba59826bebf810306c1aa3a 100644 (file)
     !.
 
 '$print_exception'(E) :-
-    write_term('caught: ', [quoted(false)]),
-    writeq(E),
-    nl.
+    (  E = error(_, _:_) -> true % if the error source contains a line
+                                 % number, a GNU-style error message
+                                 % is expected to be printed instead.
+    ;  write_term('caught: ', [quoted(false)]),
+       writeq(E),
+       nl
+    ).
 
 '$predicate_indicator'(Source, PI) :-
     (  nonvar(PI) ->
index 1b482e9e36a14c3125758bc6b732e101796c329d..4f88b3350d6f58716dac9efb0f2b51cd4e743d0e 100644 (file)
@@ -1,4 +1,4 @@
-use prolog_parser::ast::parsing_stream;
+use prolog_parser::ast::{ClauseName, parsing_stream};
 
 use prolog::heap_print::*;
 use prolog::machine::compile::*;
@@ -195,7 +195,7 @@ pub fn submit_query_with_limit(
 
 #[allow(dead_code)]
 pub fn submit_code(wam: &mut Machine, buf: &str) -> EvalSession {
-    compile_user_module(wam, parsing_stream(buf.as_bytes()), true)
+    compile_user_module(wam, parsing_stream(buf.as_bytes()), true, clause_name!("tests"))
 }
 
 #[allow(unused_macros)]