about summary refs log blame commit diff
path: root/src/libexpr/parser.cc
blob: 167c34bd83e48222450f7d500d84a5e6af26b401 (plain) (tree)
1
2
3
4
5
6
7
8
9



                      
                  

                   
                   
                    

 
                 
 
                
                    


                    
 
            
 










                                                                        
 


                                                                              
     








                                                                         

 

                                                             
 








                                      
    


                                     
 











                                                         

                                                                   
                   




                                                                         

















                                                                    
                                                      






                                                                 
#include <sstream>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "aterm.hh"
#include "parser.hh"


struct ParseData 
{
    Expr result;
    string basePath;
    string location;
    string error;
};

extern "C" {

#include "parser-tab.h"
#include "lexer-tab.h"
    
    /* Callbacks for getting from C to C++.  Due to a (small) bug in the
       GLR code of Bison we cannot currently compile the parser as C++
       code. */
   
    void setParseResult(ParseData * data, ATerm t)
    {
        data->result = t;
    }

    ATerm absParsedPath(ParseData * data, ATerm t)
    {
        return string2ATerm(absPath(aterm2String(t), data->basePath).c_str());
    }
    
    void parseError(ParseData * data, char * error, int line, int column)
    {
        data->error = (format("%1%, at line %2%, column %3%, of %4%")
            % error % line % column % data->location).str();
    }
        
    int yyparse(yyscan_t scanner, ParseData * data);
}


static Expr parse(const char * text, const string & location,
    const Path & basePath)
{
    yyscan_t scanner;
    ParseData data;
    data.basePath = basePath;
    data.location = location;

    yylex_init(&scanner);
    yy_scan_string(text, scanner);
    int res = yyparse(scanner, &data);
    yylex_destroy(scanner);
    
    if (res) throw Error(data.error);

    return data.result;
}


Expr parseExprFromFile(Path path)
{
    assert(path[0] == '/');

#if 0
    /* Perhaps this is already an imploded parse tree? */
    Expr e = ATreadFromNamedFile(path.c_str());
    if (e) return e;
#endif

    /* If `path' is a symlink, follow it.  This is so that relative
       path references work. */
    struct stat st;
    if (lstat(path.c_str(), &st))
        throw SysError(format("getting status of `%1%'") % path);
    if (S_ISLNK(st.st_mode)) path = absPath(readLink(path), dirOf(path));

    /* If `path' refers to a directory, append `/default.nix'. */
    if (stat(path.c_str(), &st))
        throw SysError(format("getting status of `%1%'") % path);
    if (S_ISDIR(st.st_mode))
        path = canonPath(path + "/default.nix");

    /* Read the input file.  We can't use SGparseFile() because it's
       broken, so we read the input ourselves and call
       SGparseString(). */
    AutoCloseFD fd = open(path.c_str(), O_RDONLY);
    if (fd == -1) throw SysError(format("opening `%1%'") % path);

    if (fstat(fd, &st) == -1)
        throw SysError(format("statting `%1%'") % path);

    char text[st.st_size + 1];
    readFull(fd, (unsigned char *) text, st.st_size);
    text[st.st_size] = 0;

    return parse(text, "`" + path + "'", dirOf(path));
}


Expr parseExprFromString(const string & s, const Path & basePath)
{
    return parse(s.c_str(), "(string)", basePath);
}