2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
2014-01-07 14:08:37 +04:00
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
# include "cling/MetaProcessor/MetaProcessor.h"
2012-11-28 20:50:13 +04:00
# include "Display.h"
2012-09-05 13:37:39 +04:00
# include "InputValidator.h"
2012-12-01 04:45:43 +04:00
# include "MetaParser.h"
# include "MetaSema.h"
2012-09-05 13:37:39 +04:00
# include "cling/Interpreter/Interpreter.h"
2014-02-27 01:37:16 +04:00
# include "cling/Interpreter/Value.h"
2016-09-10 22:04:39 +03:00
# include "cling/Utils/Output.h"
2012-09-05 13:37:39 +04:00
# include "clang/Basic/FileManager.h"
# include "clang/Basic/TargetInfo.h"
# include "clang/Frontend/CompilerInstance.h"
# include "clang/Lex/Preprocessor.h"
2013-09-19 19:59:58 +04:00
# include "llvm/Support/Path.h"
2012-09-05 13:37:39 +04:00
2016-08-31 00:06:03 +03:00
# include <fcntl.h>
2012-10-30 17:40:25 +04:00
# include <fstream>
2012-11-28 20:38:02 +04:00
# include <cstdlib>
2012-11-21 00:21:29 +04:00
# include <cctype>
2016-12-07 09:35:33 +03:00
# include <sstream>
2013-12-18 18:51:27 +04:00
# include <stdio.h>
2014-02-03 17:02:56 +04:00
# ifndef WIN32
# include <unistd.h>
# else
# include <io.h>
# define STDIN_FILENO 0
# define STDOUT_FILENO 1
# define STDERR_FILENO 2
# endif
2012-11-28 20:38:02 +04:00
2012-09-05 13:37:39 +04:00
using namespace clang ;
namespace cling {
2016-08-30 02:03:02 +03:00
class MetaProcessor : : RedirectOutput {
2016-08-31 00:06:03 +03:00
static int dupOnce ( int Fd , int & Bak ) {
2016-12-15 16:32:50 +03:00
// Flush now or can drop the buffer when dup2 is called with Fd later.
2016-08-31 00:06:03 +03:00
// This seems only neccessary when piping stdout or stderr, but do it
// for ttys to avoid over complicated code for minimal benefit.
: : fflush ( Fd = = STDOUT_FILENO ? stdout : stderr ) ;
2016-12-15 16:32:50 +03:00
2016-08-31 00:06:03 +03:00
if ( Bak = = kInvalidFD )
Bak = : : dup ( Fd ) ;
2016-08-30 02:03:02 +03:00
2016-08-31 00:06:03 +03:00
return Bak ;
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
struct Redirect {
int FD ;
MetaProcessor : : RedirectionScope Scope ;
bool Close ;
Redirect ( std : : string file , bool append , RedirectionScope S , int * Baks ) :
FD ( - 1 ) , Scope ( S ) , Close ( false ) {
if ( S & kSTDSTRM ) {
// Remove the flag from Scope, we don't need it anymore
Scope = RedirectionScope ( Scope & ~ kSTDSTRM ) ;
if ( file = = " &1 " )
FD = dupOnce ( STDOUT_FILENO , Baks [ 0 ] ) ;
else if ( file = = " &2 " )
FD = dupOnce ( STDERR_FILENO , Baks [ 1 ] ) ;
// Close = false; Parent manages lifetime
if ( FD ! = - 1 )
return ;
llvm_unreachable ( " kSTDSTRM passed for unknown stream " ) ;
}
const int Perm = 0644 ;
# ifdef LLVM_ON_WIN32
const int Mode = _O_CREAT | _O_WRONLY | ( append ? _O_APPEND : _O_TRUNC ) ;
FD = : : _open ( file . c_str ( ) , Mode , Perm ) ;
# else
const int Mode = O_CREAT | O_WRONLY | ( append ? O_APPEND : O_TRUNC ) ;
FD = : : open ( file . c_str ( ) , Mode , Perm ) ;
# endif
if ( FD = = - 1 ) {
: : perror ( " Redirect::open " ) ;
return ;
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
Close = true ;
if ( append )
: : lseek ( FD , 0 , SEEK_END ) ;
}
~ Redirect ( ) {
if ( Close )
: : close ( FD ) ;
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
} ;
typedef std : : vector < std : : unique_ptr < Redirect > > RedirectStack ;
enum { kNumRedirects = 2 , kInvalidFD = - 1 } ;
RedirectStack m_Stack ;
int m_Bak [ kNumRedirects ] ;
int m_CurStdOut ;
# ifdef LLVM_ON_WIN32
// After a redirection from stdout into stderr then undirecting stdout, the
// console will loose line-buffering. To get arround this we test if stdout
// is a tty during construction, and if so mark the case when stdout has
// returned from a redirection into stderr, then handle it ~RedirectOutput.
// We need two bits for 3 possible states.
unsigned m_TTY : 2 ;
# else
const bool m_TTY ;
# endif
// Exception safe push routine
int push ( Redirect * R ) {
std : : unique_ptr < Redirect > Re ( R ) ;
const int FD = R - > FD ;
m_Stack . emplace_back ( Re . get ( ) ) ;
Re . release ( ) ;
return FD ;
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
// Call ::dup2 and report errMsg on failure
bool dup2 ( int oldfd , int newfd , const char * errMsg ) {
if ( : : dup2 ( oldfd , newfd ) = = kInvalidFD ) {
: : perror ( errMsg ) ;
return false ;
}
return true ;
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
// Restore stdstream from backup and close the backup
2017-02-08 04:00:54 +03:00
void close ( int & oldfd , int newfd ) {
2016-12-14 20:13:03 +03:00
assert ( ( newfd = = STDOUT_FILENO | | newfd = = STDERR_FILENO ) & & " Not std FD " ) ;
2016-08-31 00:06:03 +03:00
assert ( oldfd = = m_Bak [ newfd = = STDERR_FILENO ] & & " Not backup FD " ) ;
if ( oldfd ! = kInvalidFD ) {
dup2 ( oldfd , newfd , " RedirectOutput::close " ) ;
: : close ( oldfd ) ;
2017-02-08 04:00:54 +03:00
oldfd = kInvalidFD ;
2016-08-30 02:03:02 +03:00
}
}
2016-08-31 00:06:03 +03:00
int restore ( int FD , FILE * F , MetaProcessor : : RedirectionScope Flag ,
2017-02-08 04:00:54 +03:00
int & bakFD ) {
2016-08-31 00:06:03 +03:00
// If no backup, we have never redirected the file, so nothing to restore
if ( bakFD ! = kInvalidFD ) {
// Find the last redirect for the scope, and restore redirection to it
for ( RedirectStack : : const_reverse_iterator it = m_Stack . rbegin ( ) ,
e = m_Stack . rend ( ) ;
it ! = e ; + + it ) {
const Redirect * R = ( * it ) . get ( ) ;
if ( R - > Scope & Flag ) {
dup2 ( R - > FD , FD , " RedirectOutput::restore " ) ;
return R - > FD ;
}
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
// No redirection for this scope, restore to backup
2017-02-08 04:00:54 +03:00
fflush ( F ) ;
close ( bakFD , FD ) ;
2016-08-30 02:03:02 +03:00
}
2017-02-08 04:00:54 +03:00
return kInvalidFD ;
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
public :
RedirectOutput ( ) : m_CurStdOut ( kInvalidFD ) ,
m_TTY ( : : isatty ( STDOUT_FILENO ) ? 1 : 0 ) {
for ( unsigned i = 0 ; i < kNumRedirects ; + + i )
m_Bak [ i ] = kInvalidFD ;
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
~ RedirectOutput ( ) {
close ( m_Bak [ 0 ] , STDOUT_FILENO ) ;
close ( m_Bak [ 1 ] , STDERR_FILENO ) ;
while ( ! m_Stack . empty ( ) )
m_Stack . pop_back ( ) ;
# ifdef LLVM_ON_WIN32
// State 2, was tty to begin with, then redirected to stderr and back.
if ( m_TTY = = 2 )
: : freopen ( " CON " , " w " , stdout ) ;
2017-02-08 04:00:54 +03:00
# else
// If redirection took place without writing anything to the terminal
// beforehand (--nologo) then the dup2 relinking stdout will have caused
// it to be re-opened without line buffering.
if ( m_TTY )
: : setvbuf ( stdout , NULL , _IOLBF , BUFSIZ ) ;
2016-08-31 00:06:03 +03:00
# endif
2016-08-30 02:03:02 +03:00
}
2016-08-31 00:06:03 +03:00
void redirect ( llvm : : StringRef file , bool apnd ,
MetaProcessor : : RedirectionScope scope ) {
if ( file . empty ( ) ) {
// Unredirection, remove last redirection state(s) for given scope(s)
if ( m_Stack . empty ( ) ) {
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < " No redirections left to remove \n " ;
2016-08-31 00:06:03 +03:00
return ;
2014-01-20 16:51:51 +04:00
}
2016-08-31 00:06:03 +03:00
MetaProcessor : : RedirectionScope lScope = scope ;
SmallVector < RedirectStack : : iterator , 2 > Remove ;
for ( auto it = m_Stack . rbegin ( ) , e = m_Stack . rend ( ) ; it ! = e ; + + it ) {
Redirect * R = ( * it ) . get ( ) ;
const unsigned Match = R - > Scope & lScope ;
if ( Match ) {
# ifdef LLVM_ON_WIN32
// stdout back from stderr, fix up our console output on destruction
if ( m_TTY & & R - > FD = = m_Bak [ 1 ] & & scope & kSTDOUT )
m_TTY = 2 ;
# endif
// Clear the flag so restore below will ignore R for scope
R - > Scope = MetaProcessor : : RedirectionScope ( R - > Scope & ~ Match ) ;
// If no scope left, then R should be removed
if ( ! R - > Scope ) {
// standard [24.4.1/1] says &*(reverse_iterator(i)) == &*(i - 1)
Remove . push_back ( std : : next ( it ) . base ( ) ) ;
}
// Clear match to reduce lScope (kSTDBOTH -> kSTDOUT or kSTDERR)
lScope = MetaProcessor : : RedirectionScope ( lScope & ~ Match ) ;
// If nothing to match anymore, then we're done
if ( ! lScope )
break ;
}
}
// std::vector::erase invalidates iterators at or after the point of
// the erase, so if we reverse iterate on Remove everything is fine
for ( auto it = Remove . rbegin ( ) , e = Remove . rend ( ) ; it ! = e ; + + it )
m_Stack . erase ( * it ) ;
} else {
// Add new redirection state
if ( push ( new Redirect ( file . str ( ) , apnd , scope , m_Bak ) ) ! = kInvalidFD ) {
// Save a backup for the scope(s), if not already done
if ( scope & MetaProcessor : : kSTDOUT )
dupOnce ( STDOUT_FILENO , m_Bak [ 0 ] ) ;
if ( scope & MetaProcessor : : kSTDERR )
dupOnce ( STDERR_FILENO , m_Bak [ 1 ] ) ;
} else
return ; // Failure
2014-01-20 16:51:51 +04:00
}
2016-08-31 00:06:03 +03:00
if ( scope & MetaProcessor : : kSTDOUT )
m_CurStdOut =
restore ( STDOUT_FILENO , stdout , MetaProcessor : : kSTDOUT , m_Bak [ 0 ] ) ;
if ( scope & MetaProcessor : : kSTDERR )
restore ( STDERR_FILENO , stderr , MetaProcessor : : kSTDERR , m_Bak [ 1 ] ) ;
2013-12-18 18:51:27 +04:00
}
2016-08-31 00:06:03 +03:00
void resetStdOut ( bool toBackup = false ) {
// When not outputing to a TTY there is no need to unredirect as
// TerminalDisplay handles writing to the console FD already.
if ( ! m_TTY )
return ;
if ( toBackup ) {
2017-02-08 04:00:54 +03:00
if ( m_Bak [ 0 ] ! = kInvalidFD ) {
fflush ( stdout ) ;
dup2 ( m_Bak [ 0 ] , STDOUT_FILENO , " RedirectOutput::resetStdOut " ) ;
}
2016-08-31 00:06:03 +03:00
} else if ( m_CurStdOut ! = kInvalidFD )
2017-02-08 04:00:54 +03:00
dup2 ( m_CurStdOut , STDOUT_FILENO , " RedirectOutput::resetStdOut " ) ;
2016-08-31 00:06:03 +03:00
}
2015-08-06 15:39:46 +03:00
2016-08-31 00:06:03 +03:00
bool empty ( ) const {
return m_Stack . empty ( ) ;
2014-01-14 21:25:43 +04:00
}
2016-08-31 00:06:03 +03:00
} ;
MetaProcessor : : MaybeRedirectOutputRAII : : MaybeRedirectOutputRAII (
MetaProcessor & P ) :
m_MetaProcessor ( P ) {
if ( m_MetaProcessor . m_RedirectOutput )
m_MetaProcessor . m_RedirectOutput - > resetStdOut ( true ) ;
2014-01-14 21:25:43 +04:00
}
2016-08-31 00:06:03 +03:00
MetaProcessor : : MaybeRedirectOutputRAII : : ~ MaybeRedirectOutputRAII ( ) {
if ( m_MetaProcessor . m_RedirectOutput )
m_MetaProcessor . m_RedirectOutput - > resetStdOut ( ) ;
2014-01-20 16:51:51 +04:00
}
2014-01-14 21:25:43 +04:00
2014-08-04 06:05:42 +04:00
MetaProcessor : : MetaProcessor ( Interpreter & interp , raw_ostream & outs )
2014-02-25 17:11:10 +04:00
: m_Interp ( interp ) , m_Outs ( & outs ) {
2012-09-05 13:37:39 +04:00
m_InputValidator . reset ( new InputValidator ( ) ) ;
2012-12-01 04:45:43 +04:00
m_MetaParser . reset ( new MetaParser ( new MetaSema ( interp , * this ) ) ) ;
2012-09-05 13:37:39 +04:00
}
2016-07-15 16:47:37 +03:00
MetaProcessor : : ~ MetaProcessor ( ) {
}
2012-09-05 13:37:39 +04:00
2017-06-06 18:23:41 +03:00
int MetaProcessor : : process ( llvm : : StringRef input_line ,
2013-06-10 17:14:36 +04:00
Interpreter : : CompilationResult & compRes ,
2017-05-02 12:19:14 +03:00
Value * result ,
bool disableValuePrinting /* = false */ ) {
2013-06-10 17:14:36 +04:00
if ( result )
2014-02-27 01:37:16 +04:00
* result = Value ( ) ;
2013-05-24 19:50:13 +04:00
compRes = Interpreter : : kSuccess ;
2012-10-29 18:23:53 +04:00
int expectedIndent = m_InputValidator - > getExpectedIndent ( ) ;
2014-08-04 06:05:42 +04:00
2013-05-24 19:50:13 +04:00
if ( expectedIndent )
compRes = Interpreter : : kMoreInputExpected ;
2017-06-06 18:23:41 +03:00
if ( input_line . empty ( ) | |
( input_line . size ( ) = = 1 & & input_line . front ( ) = = ' \n ' ) ) {
// just a blank line, nothing to do.
2012-10-29 18:23:53 +04:00
return expectedIndent ;
2012-09-05 13:37:39 +04:00
}
2017-06-06 18:23:41 +03:00
2012-09-05 13:37:39 +04:00
// Check for and handle meta commands.
2012-12-01 04:45:43 +04:00
m_MetaParser - > enterNewInputLine ( input_line ) ;
2013-05-24 19:50:13 +04:00
MetaSema : : ActionResult actionResult = MetaSema : : AR_Success ;
2016-07-03 05:35:49 +03:00
if ( ! m_InputValidator - > inBlockComment ( ) & &
m_MetaParser - > isMetaCommand ( actionResult , result ) ) {
2012-12-06 15:47:24 +04:00
if ( m_MetaParser - > isQuitRequested ( ) )
return - 1 ;
2013-05-24 19:50:13 +04:00
if ( actionResult ! = MetaSema : : AR_Success )
compRes = Interpreter : : kFailure ;
2014-05-29 18:59:34 +04:00
// ExpectedIndent might have changed after meta command.
return m_InputValidator - > getExpectedIndent ( ) ;
2012-09-05 13:37:39 +04:00
}
// Check if the current statement is now complete. If not, return to
// prompt for more.
2012-12-01 04:45:43 +04:00
if ( m_InputValidator - > validate ( input_line ) = = InputValidator : : kIncomplete ) {
2013-05-24 19:50:13 +04:00
compRes = Interpreter : : kMoreInputExpected ;
2012-09-05 13:37:39 +04:00
return m_InputValidator - > getExpectedIndent ( ) ;
}
// We have a complete statement, compile and execute it.
2016-07-12 04:32:59 +03:00
std : : string input ;
m_InputValidator - > reset ( & input ) ;
2012-12-06 14:40:20 +04:00
// if (m_Options.RawInput)
// compResLocal = m_Interp.declare(input);
// else
2017-05-02 12:19:14 +03:00
compRes = m_Interp . process ( input , result , /*Transaction*/ nullptr ,
disableValuePrinting ) ;
2012-09-05 13:37:39 +04:00
return 0 ;
}
2012-12-06 15:47:24 +04:00
void MetaProcessor : : cancelContinuation ( ) const {
2012-12-04 12:05:33 +04:00
m_InputValidator - > reset ( ) ;
}
2012-12-06 15:47:24 +04:00
int MetaProcessor : : getExpectedIndent ( ) const {
return m_InputValidator - > getExpectedIndent ( ) ;
2012-09-05 13:37:39 +04:00
}
2016-12-07 09:34:16 +03:00
static Interpreter : : CompilationResult reportIOErr ( llvm : : StringRef File ,
const char * What ) {
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < " Error in cling::MetaProcessor: "
2016-12-07 09:34:16 +03:00
" cannot " < < What < < " input: ' " < < File < < " ' \n " ;
return Interpreter : : kFailure ;
}
2012-10-30 17:40:25 +04:00
Interpreter : : CompilationResult
MetaProcessor : : readInputFromFile ( llvm : : StringRef filename ,
2014-05-19 18:34:21 +04:00
Value * result ,
2016-12-07 09:35:33 +03:00
size_t posOpenCurly ,
bool lineByLine ) {
2012-11-09 14:54:07 +04:00
2016-12-07 09:34:16 +03:00
// FIXME: This will fail for Unicode BOMs (and seems really weird)
2012-11-21 00:21:29 +04:00
{
// check that it's not binary:
std : : ifstream in ( filename . str ( ) . c_str ( ) , std : : ios : : in | std : : ios : : binary ) ;
2016-12-07 09:34:16 +03:00
if ( in . fail ( ) )
return reportIOErr ( filename , " open " ) ;
2012-11-21 00:21:29 +04:00
char magic [ 1024 ] = { 0 } ;
in . read ( magic , sizeof ( magic ) ) ;
size_t readMagic = in . gcount ( ) ;
2016-07-27 02:24:36 +03:00
// Binary files < 300 bytes are rare, and below newlines etc make the
// heuristic unreliable.
2016-12-07 09:34:16 +03:00
if ( ! in . fail ( ) & & readMagic > = 300 ) {
2013-11-21 20:52:57 +04:00
llvm : : StringRef magicStr ( magic , in . gcount ( ) ) ;
2013-09-19 19:05:28 +04:00
llvm : : sys : : fs : : file_magic fileType
2013-11-21 20:52:57 +04:00
= llvm : : sys : : fs : : identify_magic ( magicStr ) ;
2016-12-07 09:34:16 +03:00
if ( fileType ! = llvm : : sys : : fs : : file_magic : : unknown )
return reportIOErr ( filename , " read from binary " ) ;
2012-11-21 00:21:29 +04:00
unsigned printable = 0 ;
2012-11-21 14:51:41 +04:00
for ( size_t i = 0 ; i < readMagic ; + + i )
2012-11-21 00:21:29 +04:00
if ( isprint ( magic [ i ] ) )
+ + printable ;
if ( 10 * printable < 5 * readMagic ) {
// 50% printable for ASCII files should be a safe guess.
2016-12-07 09:34:16 +03:00
return reportIOErr ( filename , " won't read from likely binary " ) ;
2012-11-21 00:21:29 +04:00
}
}
}
2012-10-30 17:40:25 +04:00
std : : ifstream in ( filename . str ( ) . c_str ( ) ) ;
2016-12-07 09:34:16 +03:00
if ( in . fail ( ) )
return reportIOErr ( filename , " open " ) ;
2012-11-09 14:54:07 +04:00
in . seekg ( 0 , std : : ios : : end ) ;
2016-12-07 09:34:16 +03:00
if ( in . fail ( ) )
return reportIOErr ( filename , " seek " ) ;
2012-11-09 14:54:07 +04:00
size_t size = in . tellg ( ) ;
2016-12-07 09:34:16 +03:00
if ( in . fail ( ) )
return reportIOErr ( filename , " tell " ) ;
2012-11-09 14:54:07 +04:00
in . seekg ( 0 ) ;
2016-12-07 09:34:16 +03:00
if ( in . fail ( ) )
return reportIOErr ( filename , " rewind " ) ;
std : : string content ( size , ' ' ) ;
2014-08-04 06:05:42 +04:00
in . read ( & content [ 0 ] , size ) ;
2016-12-07 09:34:16 +03:00
if ( in . fail ( ) )
return reportIOErr ( filename , " read " ) ;
2012-11-09 14:54:07 +04:00
2017-07-04 14:28:51 +03:00
static const char whitespace [ ] = " \t \r \n " ;
if ( content . length ( ) > 2 & & content [ 0 ] = = ' # ' & & content [ 1 ] = = ' ! ' ) {
// Convert shebang line to comment. That's nice because it doesn't
// change the content size, leaving posOpenCurly untouched.
content [ 0 ] = ' / ' ;
content [ 1 ] = ' / ' ;
}
2016-07-27 02:24:36 +03:00
if ( posOpenCurly ! = ( size_t ) - 1 & & ! content . empty ( ) ) {
assert ( content [ posOpenCurly ] = = ' { '
& & " No curly at claimed position of opening curly! " ) ;
// hide the curly brace:
content [ posOpenCurly ] = ' ' ;
// and the matching closing '}'
size_t posCloseCurly = content . find_last_not_of ( whitespace ) ;
if ( posCloseCurly ! = std : : string : : npos ) {
if ( content [ posCloseCurly ] = = ' ; ' & & content [ posCloseCurly - 1 ] = = ' } ' ) {
content [ posCloseCurly - - ] = ' ' ; // replace ';' and enter next if
}
if ( content [ posCloseCurly ] = = ' } ' ) {
content [ posCloseCurly ] = ' ' ; // replace '}'
} else {
std : : string : : size_type posBlockClose = content . find_last_of ( ' } ' ) ;
if ( posBlockClose ! = std : : string : : npos ) {
content [ posBlockClose ] = ' ' ; // replace '}'
2015-06-08 12:14:41 +03:00
}
2016-07-27 02:24:36 +03:00
std : : string : : size_type posComment
= content . find_first_not_of ( whitespace , posBlockClose ) ;
if ( posComment ! = std : : string : : npos
& & content [ posComment ] = = ' / ' & & content [ posComment + 1 ] = = ' / ' ) {
// More text (comments) are okay after the last '}', but
// we can not easily find it to remove it (so we need to upgrade
// this code to better handle the case with comments or
// preprocessor code before and after the leading { and
// trailing })
while ( posComment < = posCloseCurly ) {
content [ posComment + + ] = ' ' ; // replace '}' and comment
2012-11-09 14:54:07 +04:00
}
2016-07-27 02:24:36 +03:00
} else {
content [ posCloseCurly ] = ' { ' ;
// By putting the '{' back, we keep the code as consistent as
// the user wrote it ... but we should still warn that we not
// goint to treat this file an unamed macro.
2016-09-10 22:04:39 +03:00
cling : : errs ( )
2016-07-27 02:24:36 +03:00
< < " Warning in cling::MetaProcessor: can not find the closing '}', "
< < llvm : : sys : : path : : filename ( filename )
< < " is not handled as an unamed script! \n " ;
} // did not find "//"
} // remove comments after the trailing '}'
} // find '}'
} // ignore outermost block
2012-11-09 14:54:07 +04:00
2016-12-07 09:34:16 +03:00
m_CurrentlyExecutingFile = filename ;
2012-11-21 00:21:29 +04:00
bool topmost = ! m_TopExecutingFile . data ( ) ;
if ( topmost )
m_TopExecutingFile = m_CurrentlyExecutingFile ;
2016-12-07 09:49:22 +03:00
2016-12-07 09:35:33 +03:00
content . insert ( 0 , " #line 2 \" " + filename . str ( ) + " \" \n " ) ;
2014-05-19 17:54:04 +04:00
// We don't want to value print the results of a unnamed macro.
2016-12-07 09:35:33 +03:00
if ( content . back ( ) ! = ' ; ' )
content . append ( " ; " ) ;
Interpreter : : CompilationResult ret = Interpreter : : kSuccess ;
if ( lineByLine ) {
int rslt = 0 ;
std : : string line ;
std : : stringstream ss ( content ) ;
while ( std : : getline ( ss , line , ' \n ' ) ) {
2017-06-06 18:23:41 +03:00
rslt = process ( line , ret , result ) ;
2016-12-07 09:35:33 +03:00
if ( ret = = Interpreter : : kFailure )
break ;
}
if ( rslt ) {
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < " Error in cling::MetaProcessor: file "
2016-12-07 09:35:33 +03:00
< < llvm : : sys : : path : : filename ( filename )
< < " is incomplete (missing parenthesis or similar)! \n " ;
}
} else
ret = m_Interp . process ( content , result ) ;
2016-12-07 09:49:22 +03:00
2012-11-21 00:21:29 +04:00
m_CurrentlyExecutingFile = llvm : : StringRef ( ) ;
if ( topmost )
m_TopExecutingFile = llvm : : StringRef ( ) ;
2012-10-30 17:40:25 +04:00
return ret ;
}
2016-08-30 02:03:02 +03:00
void MetaProcessor : : setStdStream ( llvm : : StringRef file , RedirectionScope scope ,
bool append ) {
assert ( ( scope & kSTDOUT | | scope & kSTDERR ) & & " Invalid RedirectionScope " ) ;
if ( ! m_RedirectOutput )
m_RedirectOutput . reset ( new RedirectOutput ) ;
2016-08-31 00:06:03 +03:00
m_RedirectOutput - > redirect ( file , append , scope ) ;
if ( m_RedirectOutput - > empty ( ) )
m_RedirectOutput . reset ( ) ;
2013-12-18 18:51:27 +04:00
}
2015-01-21 18:51:20 +03:00
void MetaProcessor : : registerUnloadPoint ( const Transaction * T ,
llvm : : StringRef filename ) {
m_MetaParser - > getActions ( ) . registerUnloadPoint ( T , filename ) ;
}
2012-10-30 17:40:25 +04:00
} // end namespace cling