1 : #include <sstream>
2 :
3 : #include <sys/types.h>
4 : #include <sys/stat.h>
5 : #include <fcntl.h>
6 : #include <unistd.h>
7 :
8 : #include "aterm.hh"
9 : #include "parser.hh"
10 : #include "nixexpr-ast.hh"
11 :
12 :
13 : struct ParseData
14 : {
15 : Expr result;
16 : Path basePath;
17 : Path path;
18 : string error;
19 : };
20 :
21 :
22 : extern "C" {
23 :
24 : #include "parser-tab.h"
25 : #include "lexer-tab.h"
26 :
27 : /* Callbacks for getting from C to C++. Due to a (small) bug in the
28 : GLR code of Bison we cannot currently compile the parser as C++
29 : code. */
30 :
31 : void setParseResult(ParseData * data, ATerm t)
32 23 : {
33 23 : data->result = t;
34 : }
35 :
36 : ATerm absParsedPath(ParseData * data, ATerm t)
37 19 : {
38 19 : return toATerm(absPath(aterm2String(t), data->basePath));
39 : }
40 :
41 : void parseError(ParseData * data, char * error, int line, int column)
42 0 : {
43 0 : data->error = (format("%1%, at `%2%':%3%:%4%")
44 : % error % data->path % line % column).str();
45 : }
46 :
47 : ATerm fixAttrs(int recursive, ATermList as)
48 32 : {
49 32 : ATermList bs = ATempty, cs = ATempty;
50 32 : ATermList * is = recursive ? &cs : &bs;
51 150 : for (ATermIterator i(as); i; ++i) {
52 118 : ATermList names;
53 118 : Expr src;
54 118 : ATerm pos;
55 118 : if (matchInherit(*i, src, names, pos)) {
56 6 : bool fromScope = matchScope(src);
57 22 : for (ATermIterator j(names); j; ++j) {
58 16 : Expr rhs = fromScope ? makeVar(*j) : makeSelect(src, *j);
59 16 : *is = ATinsert(*is, makeBind(*j, rhs, pos));
60 : }
61 112 : } else bs = ATinsert(bs, *i);
62 : }
63 32 : if (recursive)
64 8 : return makeRec(bs, cs);
65 : else
66 24 : return makeAttrs(bs);
67 : }
68 :
69 : const char * getPath(ParseData * data)
70 141 : {
71 141 : return data->path.c_str();
72 : }
73 :
74 : int yyparse(yyscan_t scanner, ParseData * data);
75 : }
76 :
77 :
78 : static Expr parse(EvalState & state,
79 : const char * text, const Path & path,
80 : const Path & basePath)
81 23 : {
82 23 : yyscan_t scanner;
83 115 : ParseData data;
84 23 : data.basePath = basePath;
85 23 : data.path = path;
86 :
87 23 : yylex_init(&scanner);
88 23 : yy_scan_string(text, scanner);
89 23 : int res = yyparse(scanner, &data);
90 23 : yylex_destroy(scanner);
91 :
92 23 : if (res) throw Error(data.error);
93 :
94 23 : try {
95 23 : checkVarDefs(state.primOps, data.result);
96 1 : } catch (Error & e) {
97 1 : throw Error(format("%1%, in `%2%'") % e.msg() % path);
98 : }
99 :
100 22 : return data.result;
101 : }
102 :
103 :
104 : Expr parseExprFromFile(EvalState & state, Path path)
105 11 : {
106 11 : SwitchToOriginalUser sw;
107 :
108 11 : assert(path[0] == '/');
109 :
110 : #if 0
111 : /* Perhaps this is already an imploded parse tree? */
112 : Expr e = ATreadFromNamedFile(path.c_str());
113 : if (e) return e;
114 : #endif
115 :
116 : /* If `path' is a symlink, follow it. This is so that relative
117 : path references work. */
118 11 : struct stat st;
119 11 : if (lstat(path.c_str(), &st))
120 0 : throw SysError(format("getting status of `%1%'") % path);
121 11 : if (S_ISLNK(st.st_mode)) path = absPath(readLink(path), dirOf(path));
122 :
123 : /* If `path' refers to a directory, append `/default.nix'. */
124 11 : if (stat(path.c_str(), &st))
125 0 : throw SysError(format("getting status of `%1%'") % path);
126 11 : if (S_ISDIR(st.st_mode))
127 0 : path = canonPath(path + "/default.nix");
128 :
129 : /* Read the input file. We can't use SGparseFile() because it's
130 : broken, so we read the input ourselves and call
131 : SGparseString(). */
132 11 : AutoCloseFD fd = open(path.c_str(), O_RDONLY);
133 11 : if (fd == -1) throw SysError(format("opening `%1%'") % path);
134 :
135 11 : if (fstat(fd, &st) == -1)
136 0 : throw SysError(format("statting `%1%'") % path);
137 :
138 11 : char text[st.st_size + 1];
139 11 : readFull(fd, (unsigned char *) text, st.st_size);
140 11 : text[st.st_size] = 0;
141 :
142 11 : return parse(state, text, path, dirOf(path));
143 : }
144 :
145 :
146 : Expr parseExprFromString(EvalState & state,
147 : const string & s, const Path & basePath)
148 12 : {
149 12 : return parse(state, s.c_str(), "(string)", basePath);
150 : }
|