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