]> git.tdb.fi Git - libs/datafile.git/blob - source/parser.cpp
Respect the TMPDIR environment variable when creating data packs
[libs/datafile.git] / source / parser.cpp
1 #include <msp/strings/format.h>
2 #include "binaryparser.h"
3 #include "except.h"
4 #include "jsonparser.h"
5 #include "parser.h"
6 #include "statement.h"
7 #include "textparser.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace DataFile {
13
14 Parser::Parser(IO::Base &i, const string &s):
15         in(i),
16         main_src(s),
17         src(s),
18         good(true)
19 {
20         char c = in.peek();
21         if(c=='{' || c=='[')
22                 mode = new JsonParser(in, src);
23         else
24                 mode = new TextParser(in, src);
25 }
26
27 Parser::~Parser()
28 {
29         delete mode;
30 }
31
32 Statement Parser::parse(bool raw)
33 {
34         if(!good)
35                 throw logic_error("Parser::parse() !good");
36
37         try
38         {
39                 while(1)
40                 {
41                         Statement st = mode->parse();
42                         if(!st.keyword.compare(0, 2, "__"))
43                         {
44                                 st.control = true;
45                                 process_control_statement(st);
46                         }
47
48                         if(raw || !st.control)
49                                 return st;
50                         else if(!good)  // This will occur with an __end statement
51                                 return Statement();
52                 }
53         }
54         catch(const exception &e)
55         {
56                 good = false;
57                 if(dynamic_cast<const data_error *>(&e))
58                         throw;
59                 else
60                         throw data_error(src, in.get_line_number(), e);
61         }
62 }
63
64 void Parser::process_control_statement(const Statement &st)
65 {
66         if(st.keyword=="__bin")
67         {
68                 delete mode;
69                 mode = new BinaryParser(in, src);
70
71                 while(in.peek()=='\n')
72                         in.get();
73         }
74         else if(st.keyword=="__text")
75         {
76                 delete mode;
77                 mode = new TextParser(in, src);
78         }
79         else if(st.keyword=="__z")
80                 in.set_decompress();
81         else if(st.keyword=="__src")
82         {
83                 string s = st.args[0].get<string>();
84                 if(s.empty())
85                         src = main_src;
86                 else
87                         src = format("%s[%s]", main_src, s);
88         }
89         else if(st.keyword=="__end")
90                 good = false;
91         else
92                 mode->process_control_statement(st);
93 }
94
95 const StatementKey *Parser::peek(unsigned level)
96 {
97         while(good)
98         {
99                 const StatementKey *key = mode->peek(level);
100                 if(key && !key->keyword.compare(0, 2, "__"))
101                         process_control_statement(mode->parse());
102                 else
103                         return key;
104         }
105
106         return 0;
107 }
108
109 bool Parser::parse_and_load(unsigned level, Loader &ldr, const LoaderAction &act)
110 {
111         // Peek first to get any control statements processed
112         peek(level);
113         return mode->parse_and_load(level, ldr, act);
114 }
115
116 } // namespace DataFile
117 } // namespace Msp