1 //   Copyright (c) 2009 Giovanni Lagorio (lagorio@disi.unige.it)
2 //
3 //   This file is part of the source of CoCoALib, the CoCoA Library.
4 //
5 //   CoCoALib is free software: you can redistribute it and/or modify
6 //   it under the terms of the GNU General Public License as published by
7 //   the Free Software Foundation, either version 3 of the License, or
8 //   (at your option) any later version.
9 //
10 //   CoCoALib is distributed in the hope that it will be useful,
11 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //   GNU General Public License for more details.
14 //
15 //   You should have received a copy of the GNU General Public License
16 //   along with CoCoALib.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #ifdef CoCoA_WITH_READLINE
19 #include "stdlib.h"
20 #include "stdio.h"
21 #include "unistd.h"
22 #include "readline/readline.h"
23 #include "readline/history.h"
24 #endif
25 
26 #include <boost/iostreams/filter/newline.hpp>
27 #include <cstring>
28 #include <cctype>
29 #include <iostream>
30 #include "LineProviders.H"
31 
32 namespace CoCoA {
33 namespace LexerNS {
34 
35 using namespace std;
36 using namespace boost;
37 using namespace boost::iostreams;
38 using namespace CoCoA;
39 
~ReferenceCountedObject()40 ReferenceCountedObject::~ReferenceCountedObject() {}
41 
FileLineProvider(const std::string & file)42 FileLineProvider::FileLineProvider(const std::string &file)
43 {
44   filename = file;
45 	input.push(newline_filter(newline::posix));
46 	const file_source fs(filename.c_str());
47 	if (!fs.is_open())
48 		throw IOException("Cannot open file \""+filename+"\" for reading.");
49 	input.push(fs);
50 }
51 
FileRegionLineProvider(const std::string & file,long FromLine,long FromChar,long ToLine,long ToChar)52   FileRegionLineProvider::FileRegionLineProvider(const std::string &file, long FromLine, long FromChar, long ToLine, long ToChar) :
53       myFromLine(FromLine),
54       myFromChar(FromChar),
55       myToLine(ToLine),
56       myToChar(ToChar),
57       myCurrLine(0)
58   {
59     filename = file;
60     if (FromLine <= 0 || FromChar <= 0 || ToLine <= 0 || ToChar <= 0)
61       throw IOException("Line number and char position must be positive");
62     if (FromLine > ToLine || (FromLine == ToLine && FromChar > ToChar))
63       throw IOException("Impossible region");
64     input.push(newline_filter(newline::posix));
65     const file_source fs(filename.c_str());
66     if (!fs.is_open())
67       throw IOException("Cannot open file \""+filename+"\" for reading.");
68     input.push(fs);
69 }
70 
71 string InteractiveLineProvider::promptSuffix("#");
72 
prompt(const LexerStatus & ls,const ParserNS::ParserStatus & ps)73 string InteractiveLineProvider::prompt(const LexerStatus &ls, const ParserNS::ParserStatus &ps) {
74 	if (ps.isInRecoveryMode())
75 		throw ParserNS::AskingForNewInteractiveInputDuringRecoveryException();
76 	string s = ps.promptHeader();
77 	if (ps.isInTheMiddleOfAStatement()) s.append("... ");
78 	else if (ls.isInMultiLineComment()) s.append("/* ... ");
79 	else if (ls.isInStringLiteral())    s.append("\" ... ");
80 	s.append(promptSuffix);
81 	s.append(" ");
82 	return s;
83 }
84 
doReadNextLine(const LexerStatus & ls,const ParserNS::ParserStatus & ps,string & chars)85 bool GetlineLineProvider::doReadNextLine(const LexerStatus &ls, const ParserNS::ParserStatus &ps, string &chars) {
86 	if (cin.eof())
87 		return false;
88 // Line below does automatic prompt suppression if cin.syn_with_stdio(false) has been called (commented out first line of main() in Main.C)
89 //        if (cin.rdbuf()->in_avail() == 0) cout << prompt(ls, ps);
90 	cout << prompt(ls, ps); // always print prompt
91 	getline(cin, chars);
92 	return true;
93 }
94 
95 
96 #ifdef CoCoA_WITH_READLINE
doReadNextLine(const LexerStatus & ls,const ParserNS::ParserStatus & ps,string & chars)97 bool ReadlineLineProvider::doReadNextLine(const LexerStatus &ls, const ParserNS::ParserStatus &ps, string &chars)
98 {
99 //???	if (cin.eof()) return false;
100         rl_bind_key ('\t', rl_insert);
101         char* input;
102 	input = readline(prompt(ls, ps).c_str()); // readline handles the prompt
103         if (input == nullptr) return false; // check for EOF
104         if (input && *input) add_history(input);
105         string tmp(input); chars.swap(tmp); // equiv. to chars = string(input);
106         free(input);
107 	return true;
108 }
109 #endif
110 
111 
doReadNextLine(const LexerStatus &,const ParserNS::ParserStatus &,string & chars)112 bool FileLineProvider::doReadNextLine(const LexerStatus &, const ParserNS::ParserStatus &, string &chars) {
113 	if (input.eof())
114 		return false;
115 	getline(input, chars);
116 	if (input.bad())
117 		throw IOException("Cannot read from \""+filename+"\".");
118 #ifdef C5IDE
119 	this->wholeFile += chars;
120 	this->wholeFile += '\n';
121 #endif // #ifdef C5IDE
122 	return true;
123 }
124 
doReadNextLine(const LexerStatus &,const ParserNS::ParserStatus &,string & chars)125 bool FileRegionLineProvider::doReadNextLine(const LexerStatus &, const ParserNS::ParserStatus &, string &chars)
126 {
127   ++myCurrLine;  // Become index of the line we are about to read...
128   const bool EndOfRegion = (myCurrLine > myToLine) ||
129                            (myCurrLine == myToLine && myToChar == 1);
130   if (input.eof() || EndOfRegion) return false;
131   getline(input, chars);
132   if (input.bad())
133     throw IOException("Cannot read from \""+filename+"\".");
134   if (myCurrLine < myFromLine) chars.clear();
135   if (myCurrLine == myFromLine && static_cast<size_t>(myFromChar-1) > chars.size())
136     throw IOException("SourceRegion FromChar beyond EOL");
137   if (myCurrLine == myToLine && static_cast<size_t>(myToChar-1) > chars.size())
138     throw IOException("SourceRegion ToChar beyond EOL");
139   if (myCurrLine == myToLine) chars = chars.erase(myToChar-1);       // This line first;
140   if (myCurrLine == myFromLine) chars = chars.substr(myFromChar-1);  // this line second!
141 #ifdef C5IDE
142   this->wholeFile += chars;
143   this->wholeFile += '\n';
144 #endif // #ifdef C5IDE
145   return true;
146 }
147 
148 } // namespace LexerNS
149 } // namespace CoCoA
150