1717
1818#include "jerryscript.h"
1919#include "jerryscript-port.h"
20+ #include "jerryscript-port-default.h"
2021
2122#include "cli.h"
2223
3334
3435static uint8_t input_buffer [ JERRY_BUFFER_SIZE ];
3536static uint32_t output_buffer [ JERRY_BUFFER_SIZE / 4 ];
37+ static const char * output_file_name_p = "js.snapshot" ;
38+
39+ /**
40+ * Check whether JerryScript has a requested feature enabled or not. If not,
41+ * print a warning message.
42+ *
43+ * @return the status of the feature.
44+ */
45+ static bool
46+ check_feature (jerry_feature_t feature , /**< feature to check */
47+ const char * option ) /**< command line option that triggered this check */
48+ {
49+ if (!jerry_is_feature_enabled (feature ))
50+ {
51+ jerry_port_default_set_log_level (JERRY_LOG_LEVEL_WARNING );
52+ jerry_port_log (JERRY_LOG_LEVEL_WARNING , "Ignoring '%s' option because this feature is disabled!\n" , option );
53+ return false;
54+ }
55+ return true;
56+ } /* check_feature */
57+
58+ /**
59+ * Utility method to check and print error in the given cli state.
60+ *
61+ * @return true - if any error is detected
62+ * false - if there is no error in the cli state
63+ */
64+ static bool
65+ check_cli_error (const cli_state_t * const cli_state_p )
66+ {
67+ if (cli_state_p -> error != NULL )
68+ {
69+ if (cli_state_p -> arg != NULL )
70+ {
71+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: %s %s\n" , cli_state_p -> error , cli_state_p -> arg );
72+ }
73+ else
74+ {
75+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: %s\n" , cli_state_p -> error );
76+ }
77+
78+ return true;
79+ }
80+
81+ return false;
82+ } /* check_cli_error */
3683
3784/**
3885 * Loading a single file into the memory.
@@ -73,6 +120,227 @@ read_file (uint8_t *input_pos_p, /**< next position in the input buffer */
73120 return bytes_read ;
74121} /* read_file */
75122
123+ /**
124+ * Generate command line option IDs
125+ */
126+ typedef enum
127+ {
128+ OPT_GENERATE_HELP ,
129+ OPT_GENERATE_CONTEXT ,
130+ OPT_GENERATE_SHOW_OP ,
131+ OPT_GENERATE_LITERAL_LIST ,
132+ OPT_GENERATE_LITERAL_C ,
133+ OPT_GENERATE_OUT ,
134+ } generate_opt_id_t ;
135+
136+ /**
137+ * Generate command line options
138+ */
139+ static const cli_opt_t generate_opts [] =
140+ {
141+ CLI_OPT_DEF (.id = OPT_GENERATE_HELP , .opt = "h" , .longopt = "help" ,
142+ .help = "print this help and exit" ),
143+ CLI_OPT_DEF (.id = OPT_GENERATE_SHOW_OP , .longopt = "show-opcodes" ,
144+ .help = "print generated opcodes" ),
145+ CLI_OPT_DEF (.id = OPT_GENERATE_CONTEXT , .opt = "c" , .longopt = "context" ,
146+ .meta = "MODE" ,
147+ .help = "specify the execution context of the snapshot: "
148+ "global or eval (default: global)." ),
149+ CLI_OPT_DEF (.id = OPT_GENERATE_LITERAL_LIST , .longopt = "save-literals-list-format" ,
150+ .meta = "FILE" ,
151+ .help = "export literals found in parsed JS input (in list format)" ),
152+ CLI_OPT_DEF (.id = OPT_GENERATE_LITERAL_C , .longopt = "save-literals-c-format" ,
153+ .meta = "FILE" ,
154+ .help = "export literals found in parsed JS input (in C source format)" ),
155+ CLI_OPT_DEF (.id = OPT_GENERATE_OUT , .opt = "o" , .meta = "FILE" ,
156+ .help = "specify output file name (default: js.snapshot)" ),
157+ CLI_OPT_DEF (.id = CLI_OPT_DEFAULT , .meta = "FILE" ,
158+ .help = "input snapshot file" )
159+ };
160+
161+ /**
162+ * Process 'generate' command.
163+ *
164+ * @return error code (0 - no error)
165+ */
166+ static int
167+ process_generate (cli_state_t * cli_state_p , /**< cli state */
168+ int argc , /**< number of arguments */
169+ char * prog_name_p ) /**< program name */
170+ {
171+ (void ) argc ;
172+
173+ bool is_save_literals_mode_in_c_format = false;
174+ bool is_snapshot_mode_for_global = true;
175+ jerry_init_flag_t flags = JERRY_INIT_EMPTY ;
176+
177+ uint32_t number_of_files = 0 ;
178+ uint8_t * source_p = input_buffer ;
179+ size_t source_length = 0 ;
180+ const char * save_literals_file_name_p = NULL ;
181+
182+ cli_change_opts (cli_state_p , generate_opts );
183+
184+ for (int id = cli_consume_option (cli_state_p ); id != CLI_OPT_END ; id = cli_consume_option (cli_state_p ))
185+ {
186+ switch (id )
187+ {
188+ case OPT_GENERATE_HELP :
189+ {
190+ cli_help (prog_name_p , "generate" , generate_opts );
191+ return JERRY_STANDALONE_EXIT_CODE_OK ;
192+ }
193+ case OPT_GENERATE_OUT :
194+ {
195+ output_file_name_p = cli_consume_string (cli_state_p );
196+ break ;
197+ }
198+ case OPT_GENERATE_LITERAL_LIST :
199+ case OPT_GENERATE_LITERAL_C :
200+ {
201+ if (save_literals_file_name_p != NULL )
202+ {
203+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: literal file name already specified" );
204+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
205+ }
206+
207+ is_save_literals_mode_in_c_format = (id == OPT_GENERATE_LITERAL_C );
208+ save_literals_file_name_p = cli_consume_string (cli_state_p );
209+ break ;
210+ }
211+ case OPT_GENERATE_SHOW_OP :
212+ {
213+ if (check_feature (JERRY_FEATURE_PARSER_DUMP , cli_state_p -> arg ))
214+ {
215+ jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG );
216+ flags |= JERRY_INIT_SHOW_OPCODES ;
217+ }
218+ break ;
219+ }
220+ case OPT_GENERATE_CONTEXT :
221+ {
222+ const char * mode_str_p = cli_consume_string (cli_state_p );
223+
224+ if (cli_state_p -> error != NULL )
225+ {
226+ break ;
227+ }
228+
229+ if (!strcmp ("global" , mode_str_p ))
230+ {
231+ is_snapshot_mode_for_global = true;
232+ }
233+ else if (!strcmp ("eval" , mode_str_p ))
234+ {
235+ is_snapshot_mode_for_global = false;
236+ }
237+ else
238+ {
239+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Incorrect argument for context mode: %s\n" , mode_str_p );
240+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
241+ }
242+ break ;
243+ }
244+ case CLI_OPT_DEFAULT :
245+ {
246+ const char * file_name_p = cli_consume_string (cli_state_p );
247+
248+ if (cli_state_p -> error == NULL )
249+ {
250+ source_length = read_file (source_p , file_name_p );
251+
252+ if (source_length == 0 )
253+ {
254+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Input file is empty\n" );
255+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
256+ }
257+
258+ number_of_files ++ ;
259+ }
260+ break ;
261+ }
262+ default :
263+ {
264+ cli_state_p -> error = "Internal error" ;
265+ break ;
266+ }
267+ }
268+ }
269+
270+ if (check_cli_error (cli_state_p ))
271+ {
272+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
273+ }
274+
275+ if (number_of_files != 1 )
276+ {
277+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: No input file specified!\n" );
278+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
279+ }
280+
281+ jerry_init (flags );
282+
283+ if (!jerry_is_valid_utf8_string (source_p , (jerry_size_t ) source_length ))
284+ {
285+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: Input must be a valid UTF-8 string.\n" );
286+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
287+ }
288+
289+ size_t snapshot_size = jerry_parse_and_save_snapshot ((jerry_char_t * ) source_p ,
290+ source_length ,
291+ is_snapshot_mode_for_global ,
292+ false,
293+ output_buffer ,
294+ sizeof (output_buffer ) / sizeof (uint32_t ));
295+ if (snapshot_size == 0 )
296+ {
297+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: Generating snapshot failed!\n" );
298+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
299+ }
300+
301+ FILE * snapshot_file_p = fopen (output_file_name_p , "w" );
302+ if (snapshot_file_p == NULL )
303+ {
304+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: Unable to write snapshot file: '%s'\n" , output_file_name_p );
305+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
306+ }
307+
308+ fwrite (output_buffer , sizeof (uint8_t ), snapshot_size , snapshot_file_p );
309+ fclose (snapshot_file_p );
310+
311+ printf ("Created snapshot file: '%s' (%lu bytes)\n" , output_file_name_p , (unsigned long ) snapshot_size );
312+
313+ if (save_literals_file_name_p != NULL )
314+ {
315+ const size_t literal_buffer_size = jerry_parse_and_save_literals ((jerry_char_t * ) source_p ,
316+ source_length ,
317+ false,
318+ output_buffer ,
319+ sizeof (output_buffer ) / sizeof (uint32_t ),
320+ is_save_literals_mode_in_c_format );
321+ if (literal_buffer_size == 0 )
322+ {
323+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: Literal saving failed!\n" );
324+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
325+ }
326+
327+ FILE * literal_file_p = fopen (save_literals_file_name_p , "w" );
328+
329+ if (literal_file_p == NULL )
330+ {
331+ jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: Unable to write literal file: '%s'\n" , save_literals_file_name_p );
332+ return JERRY_STANDALONE_EXIT_CODE_FAIL ;
333+ }
334+
335+ fwrite (output_buffer , sizeof (uint8_t ), literal_buffer_size , literal_file_p );
336+ fclose (literal_file_p );
337+
338+ printf ("Created literal file: '%s' (%lu bytes)\n" , save_literals_file_name_p , (unsigned long ) literal_buffer_size );
339+ }
340+
341+ return 0 ;
342+ } /* process_generate */
343+
76344/**
77345 * Merge command line option IDs
78346 */
@@ -90,7 +358,7 @@ static const cli_opt_t merge_opts[] =
90358 CLI_OPT_DEF (.id = OPT_MERGE_HELP , .opt = "h" , .longopt = "help" ,
91359 .help = "print this help and exit" ),
92360 CLI_OPT_DEF (.id = OPT_MERGE_OUT , .opt = "o" ,
93- .help = "specify output file name (default: merged .snapshot)" ),
361+ .help = "specify output file name (default: js .snapshot)" ),
94362 CLI_OPT_DEF (.id = CLI_OPT_DEFAULT , .meta = "FILE" ,
95363 .help = "input snapshot files, minimum two" )
96364};
@@ -111,7 +379,6 @@ process_merge (cli_state_t *cli_state_p, /**< cli state */
111379
112380 cli_change_opts (cli_state_p , merge_opts );
113381
114- const char * output_file_name_p = "merged.snapshot" ;
115382 const uint32_t * merge_buffers [argc ];
116383 size_t merge_buffer_sizes [argc ];
117384 uint32_t number_of_files = 0 ;
@@ -160,17 +427,8 @@ process_merge (cli_state_t *cli_state_p, /**< cli state */
160427 }
161428 }
162429
163- if (cli_state_p -> error != NULL )
430+ if (check_cli_error ( cli_state_p ) )
164431 {
165- if (cli_state_p -> arg != NULL )
166- {
167- jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: %s %s\n" , cli_state_p -> error , cli_state_p -> arg );
168- }
169- else
170- {
171- jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: %s\n" , cli_state_p -> error );
172- }
173-
174432 return JERRY_STANDALONE_EXIT_CODE_FAIL ;
175433 }
176434
@@ -238,6 +496,7 @@ print_commands (char *prog_name_p) /**< program name */
238496 cli_help (prog_name_p , NULL , main_opts );
239497
240498 printf ("\nAvailable commands:\n"
499+ " generate\n"
241500 " merge\n"
242501 "\nPassing -h or --help after a command displays its help.\n" );
243502} /* print_commands */
@@ -275,6 +534,10 @@ main (int argc, /**< number of arguments */
275534 {
276535 return process_merge (& cli_state , argc , argv [0 ]);
277536 }
537+ else if (!strcmp ("generate" , command_p ))
538+ {
539+ return process_generate (& cli_state , argc , argv [0 ]);
540+ }
278541
279542 jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: unknown command: %s\n\n" , command_p );
280543 print_commands (argv [0 ]);
@@ -289,17 +552,8 @@ main (int argc, /**< number of arguments */
289552 }
290553 }
291554
292- if (cli_state . error != NULL )
555+ if (check_cli_error ( & cli_state ) )
293556 {
294- if (cli_state .arg != NULL )
295- {
296- jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: %s %s\n" , cli_state .error , cli_state .arg );
297- }
298- else
299- {
300- jerry_port_log (JERRY_LOG_LEVEL_ERROR , "Error: %s\n" , cli_state .error );
301- }
302-
303557 return JERRY_STANDALONE_EXIT_CODE_FAIL ;
304558 }
305559
0 commit comments