1 /* --------------------------------------------------------------------------
2 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
3 
4 CppAD is distributed under the terms of the
5              Eclipse Public License Version 2.0.
6 
7 This Source Code may also be made available under the following
8 Secondary License when the conditions for such availability set forth
9 in the Eclipse Public License, Version 2.0 are satisfied:
10       GNU General Public License, Version 2.0 or later.
11 ---------------------------------------------------------------------------- */
12 
13 # include <cppad/cppad.hpp>
14 
json_lexer(void)15 bool json_lexer(void)
16 {   bool ok = true;
17     typedef CppAD::graph::graph_op_enum graph_op_enum;
18     using CppAD::local::graph::op_name2enum;
19     //
20     // match_any_string
21     std::string match_any_string = "";
22     //
23     // An AD graph example
24     // node_1 : p[0]
25     // node_2 : x[0]
26     // node_3 : x[1]
27     // node_4 : -2.0
28     // node_5 : p[0] + x[0] + x[1]
29     // node_6 : (p[0] + x[0] + x[1]) * (p[0] + x[0] + x[1])
30     // y[0] = (p[0] + x[0] + x[1]) * (p[0] + x[0] + x[1])
31     // use single quote to avoid having to escape double quote
32     std::string graph =
33         "{\n"
34         "   'op_define_vec'  : [ 3, [\n"
35         "       { 'op_code':1, 'name':'add', 'n_arg':2 } ,\n"
36         "       { 'op_code':2, 'name':'mul', 'n_arg':2 } ,\n"
37         "       { 'op_code':3, 'name':'sum'            } ]\n"
38         "   ],\n"
39         "   'n_dynamic_ind'  : 1,\n"
40         "   'n_variable_ind' : 2,\n"
41         "   'constant_vec'   : [ 1, [ -2.0 ] ],\n"
42         "   'op_usage_vec'   : [ 2, [\n"
43         "       [ 3, 1, 3, [1, 2, 3] ] ,\n"
44         "       [ 2, 5, 5 ] ] \n"
45         "   ],\n"
46         "   'dependent_vec'   : [ 1, [6] ]\n"
47         "}\n";
48     // Convert the single quote to double quote
49     for(size_t i = 0; i < graph.size(); ++i)
50         if( graph[i] == '\'' ) graph[i] = '"';
51     //
52     // json_lexer constructor checks for { at beginning
53     CppAD::local::graph::json_lexer json_lexer(graph);
54     // -----------------------------------------------------------------------
55     // op_define_vec
56     json_lexer.check_next_string("op_define_vec");
57     json_lexer.check_next_char(':');
58     json_lexer.check_next_char('[');
59     //
60     // n_define
61     json_lexer.next_non_neg_int();
62     size_t n_define = json_lexer.token2size_t();
63     json_lexer.check_next_char(',');
64     json_lexer.check_next_char('[');
65     CppAD::vector<graph_op_enum> op_code2enum(1);
66     for(size_t i = 0; i < n_define; ++i)
67     {   json_lexer.check_next_char('{');
68         //
69         // op_code
70         json_lexer.check_next_string("op_code");
71         json_lexer.check_next_char(':');
72         json_lexer.next_non_neg_int();
73 # ifndef NDEBUG
74         size_t op_code = json_lexer.token2size_t();
75         assert( op_code == op_code2enum.size() );
76 # endif
77         json_lexer.check_next_char(',');
78         //
79         // name
80         json_lexer.check_next_string("name");
81         json_lexer.check_next_char(':');
82         json_lexer.check_next_string(match_any_string);
83         std::string   name   = json_lexer.token();
84         graph_op_enum op_enum = op_name2enum[name];
85         //
86         // op_code2enum
87         op_code2enum.push_back(op_enum);
88         //
89         if( op_enum != CppAD::graph::sum_graph_op )
90         {   json_lexer.check_next_char(',');
91             //
92             // n_arg
93             json_lexer.check_next_string("n_arg");
94             json_lexer.check_next_char(':');
95             json_lexer.next_non_neg_int();
96             ok &= json_lexer.token2size_t() == 2;
97         }
98         //
99         json_lexer.check_next_char('}');
100         if( i + 1 == n_define )
101             json_lexer.check_next_char(']');
102         else
103             json_lexer.check_next_char(',');
104     }
105     json_lexer.check_next_char(']');
106     json_lexer.check_next_char(',');
107     // -----------------------------------------------------------------------
108     // n_dynamic_ind
109     json_lexer.check_next_string("n_dynamic_ind");
110     json_lexer.check_next_char(':');
111     json_lexer.next_non_neg_int();
112     size_t n_dynamic_ind = json_lexer.token2size_t();
113     json_lexer.check_next_char(',');
114     //
115     ok &= n_dynamic_ind == 1;
116     // -----------------------------------------------------------------------
117     // n_variable_ind
118     json_lexer.check_next_string("n_variable_ind");
119     json_lexer.check_next_char(':');
120     json_lexer.next_non_neg_int();
121     size_t n_variable_ind = json_lexer.token2size_t();
122     json_lexer.check_next_char(',');
123     //
124     ok &= n_variable_ind == 2;
125     // -----------------------------------------------------------------------
126     // constant_vec
127     json_lexer.check_next_string("constant_vec");
128     json_lexer.check_next_char(':');
129     json_lexer.check_next_char('[');
130     json_lexer.next_non_neg_int();
131     size_t n_constant = json_lexer.token2size_t();
132     CppAD::vector<double> constant_vec(n_constant);
133     json_lexer.check_next_char(',');
134     //
135     // [ first_constant, ... , last_constant ]
136     json_lexer.check_next_char('[');
137     for(size_t i = 0; i < n_constant; ++i)
138     {   json_lexer.next_float();
139         constant_vec[i] = json_lexer.token2double();
140         //
141         if( i + 1 == n_constant )
142             json_lexer.check_next_char(']');
143         else
144             json_lexer.check_next_char(',');
145     }
146     //
147     json_lexer.check_next_char(']');
148     json_lexer.check_next_char(',');
149     //
150     ok &= constant_vec.size() == 1;
151     ok &= constant_vec[0] == -2.0;
152     // -----------------------------------------------------------------------
153     // op_usage_vec
154     json_lexer.check_next_string("op_usage_vec");
155     //
156     json_lexer.check_next_char(':');
157     json_lexer.check_next_char('[');
158     //
159     json_lexer.next_non_neg_int();
160     size_t n_usage = json_lexer.token2size_t();
161     CppAD::vector<graph_op_enum> operator_vec(n_usage);
162     //
163     json_lexer.check_next_char(',');
164     //
165     // [ first_operator, ... , last_operator ]
166     json_lexer.check_next_char('[');
167     for(size_t i = 0; i < n_usage; ++i)
168     {   // start next operator
169         json_lexer.check_next_char('[');
170         graph_op_enum op_usage;
171         //
172         // op_code
173         json_lexer.next_non_neg_int();
174         size_t op_code   = json_lexer.token2size_t();
175         //
176         // op_enum
177         op_usage = op_code2enum[op_code];
178         json_lexer.check_next_char(',');
179         //
180         size_t n_result, n_arg;
181         if( op_usage != CppAD::graph::sum_graph_op )
182         {   n_result = 1;
183             n_arg    = 2;
184         }
185         else
186         {   // n_result
187             json_lexer.next_non_neg_int();
188             n_result = json_lexer.token2size_t();
189             json_lexer.check_next_char(',');
190             ok &= n_result == 1;
191             //
192             // n_arg
193             json_lexer.next_non_neg_int();
194             n_arg = json_lexer.token2size_t();
195             json_lexer.check_next_char(',');
196             json_lexer.check_next_char('[');
197             ok &= n_arg == 3;
198             //
199         }
200         ok &= n_result == 1;
201         CppAD::vector<size_t> arg_node(0);
202         // first_arg_node, ... , last_arg_node
203         for(size_t j = 0; j < n_arg; ++j)
204         {   // next argument node
205             json_lexer.next_non_neg_int();
206             size_t argument_node = json_lexer.token2size_t();
207             arg_node.push_back( argument_node );
208             //
209             if( j + 1 == n_arg )
210                 json_lexer.check_next_char(']');
211             else
212                 json_lexer.check_next_char(',');
213         }
214         if( op_usage == CppAD::graph::sum_graph_op )
215         {
216             json_lexer.check_next_char(']');
217             ok &= arg_node.size() == 3;
218             ok &= arg_node[0] == 1;
219             ok &= arg_node[1] == 2;
220             ok &= arg_node[2] == 3;
221         }
222         else
223         {   ok &= arg_node.size() == 2;
224             ok &= arg_node[0] == 5;
225             ok &= arg_node[1] == 5;
226         }
227         //
228         // end of this operator
229         operator_vec[i] = op_usage;
230         //
231         if( i + 1 == n_usage )
232             json_lexer.check_next_char(']');
233         else
234             json_lexer.check_next_char(',');
235 
236     }
237     json_lexer.check_next_char(']');
238     //
239     json_lexer.check_next_char(',');
240     //
241     ok &= operator_vec.size() == 2;
242     //
243     graph_op_enum op_enum = operator_vec[0];
244     ok &= op_enum == CppAD::graph::sum_graph_op;
245     //
246     op_enum   = operator_vec[1];
247     ok &= op_enum == CppAD::graph::mul_graph_op;
248     // -----------------------------------------------------------------------
249     // dependent_vec
250     json_lexer.check_next_string("dependent_vec");
251     json_lexer.check_next_char(':');
252     json_lexer.check_next_char('[');
253     json_lexer.next_non_neg_int();
254     size_t n_dependent = json_lexer.token2size_t();
255     CppAD::vector<size_t> dependent_vec(n_dependent);
256     //
257     json_lexer.check_next_char(',');
258     //
259     // [ first_dependent, ... , last_dependent ]
260     json_lexer.check_next_char('[');
261     for(size_t i = 0; i < n_dependent; ++i)
262     {   json_lexer.next_float();
263         dependent_vec[i] = json_lexer.token2size_t();
264         //
265         if( i + 1 == n_dependent )
266             json_lexer.check_next_char(']');
267         else
268             json_lexer.check_next_char(',');
269     }
270     //
271     json_lexer.check_next_char(']');
272     //
273     ok &= dependent_vec.size() == 1;
274     ok &= dependent_vec[0] == 6;
275     // -----------------------------------------------------------------------
276     // }
277     json_lexer.check_next_char('}');
278     //
279     return ok;
280 }
281