2 * Process the jswrap input files and generate output.
3 * Copyright (c) 1998 New Generation Software (NGS) Oy
5 * Author: Markku Rossi <mtr@ngs.fi>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jswrap/process.js,v $
31 * Constants and definitions.
53 function is_type_token (token
)
55 return (token
== tCSTRING
|| token
== tDOUBLE
|| token
== tINT
56 || token
== tSTRING
|| token
== tVOID
);
59 function is_copy_type_token (token
)
61 return (token
== tIN
|| token
== tOUT
|| token
== tINOUT
);
64 function typename (token
)
66 if (token
== tCSTRING
)
68 else if (token
== tDOUBLE
)
70 else if (token
== tINT
)
72 else if (token
== tSTRING
)
74 else if (token
== tVOID
)
76 else if (token
== tIN
)
78 else if (token
== tOUT
)
80 else if (token
== tINOUT
)
86 function c_typename (token
)
88 if (token
== tCSTRING
)
90 else if (token
== tDOUBLE
)
92 else if (token
== tINT
)
94 else if (token
== tVOID
)
96 else if (token
== tOUT
|| token
== tINOUT
)
102 function jsint_typename (token
)
104 if (token
== tCSTRING
)
106 else if (token
== tDOUBLE
)
108 else if (token
== tINT
)
110 else if (token
== tSTRING
)
116 valid_c_identifier_re
= new RegExp ("^[A-Za-z_][A-Za-z_0-9]*$");
118 end_brace_re
= new RegExp ("^}[ \t]*$");
124 /* The input file line number. */
138 System
.print (program
, ": processing file `", input_file
,
139 "', header=`", header_file
,
140 "', output=`", output_file
,
141 "', reentrant=", opt_reentrant
, "\n");
145 /* Open input file. */
146 ifp
= new File (input_file
);
149 System
.error (program
, ": couldn't open input file `", input_file
,
150 "': ", System
.strerror (System
.errno
), "\n");
154 /* Create output files. */
156 ofp_c
= new File (output_file
);
157 if (!ofp_c
.open ("w"))
159 System
.error (program
, ": couldn't create output file `", output_file
,
160 "': ", System
.strerror (System
.errno
), "\n");
164 ofp_h
= new File (header_file
);
165 if (!ofp_h
.open ("w"))
168 File
.remove (output_file
);
170 System
.error (program
, ": couldn't create header file `", header_file
,
171 "': ", System
.strerror (System
.errno
), "\n");
177 ofp_js
= new File (js_file
);
178 if (!ofp_js
.open ("w"))
182 File
.remove (output_file
);
183 File
.remove (header_file
);
185 System
.error (program
, ": couldn't create JS file `", js_file
,
186 "': ", System
.strerror (System
.errno
), "\n");
191 /* Parse the input. */
202 * The Func class to hold function definitions.
211 function Func
$generate_js ()
213 this.code
= new String ("function " + this.name
+ " (");
215 for (i
= 0; i
< this.args
.length
; i
++)
217 this.code
.append (this.args
[i
].name
);
218 if (i
+ 1 < this.args
.length
)
219 this.code
.append (", ");
221 this.code
.append (")\n{");
222 this.code
.append (this.body
);
223 this.code
.append ("}\n");
225 Func
.prototype.generate_js
= Func
$generate_js
;
227 function Func
$print_js (stream
)
229 stream
.write (this.code
);
231 Func
.prototype.print_js
= Func
$print_js
;
233 function Func
$print_h (stream
, header
)
236 stream
.write (c_typename (this.return_type
) + this.name
+ " (");
240 /* The first argument is the interpreter handle. */
241 stream
.write ("\n\tJSInterpPtr interp");
242 if (this.args
.length
> 0)
247 for (i
= 0; i
< this.args
.length
; i
++)
249 stream
.write ("\n\t");
250 if (this.args
[i
].type
== tSTRING
)
252 stream
.write ("unsigned char *"
253 + c_typename (this.args
[i
].copy_type
)
254 + this.args
[i
].name
+ ",\n\t"
256 + c_typename (this.args
[i
].copy_type
)
257 + this.args
[i
].name
+ "_len");
261 stream
.write (c_typename (this.args
[i
].type
)
262 + c_typename (this.args
[i
].copy_type
));
263 stream
.write (this.args
[i
].name
);
266 if (i
+ 1 < this.args
.length
)
269 stream
.write ("\n\t)");
276 Func
.prototype.print_h
= Func
$print_h
;
278 function Func
$print_c (stream
)
281 this.dump_bc (stream
);
283 this.print_h (stream
, false);
285 stream
.write ("{\n");
288 stream
.write (" JSInterpPtr interp = jswrap_interp;\n");
290 stream
.write (" JSVirtualMachine *vm = interp->vm;\n");
292 stream
.write (" JSNode argv["
293 + (this.args
.length
+ 1).toString ()
295 stream
.write (" int result;\n");
297 if (this.return_type
== tCSTRING
)
298 stream
.write (" char *cp;\n");
302 /* Argument count. */
303 stream
.write (" argv[0].type = JS_INTEGER;\n");
304 stream
.write (" argv[0].u.vinteger = "
305 + this.args
.length
.toString ()
310 /* Construct the argv array. */
311 for (i
= 0; i
< this.args
.length
; i
++)
313 var arg
= this.args
[i
];
318 var argnum
= (i
+ 1).toString ();
320 if (arg
.copy_type
== tOUT
)
322 stream
.write (" argv[" + argnum
+ "].type = JS_UNDEFINED;\n");
326 if (arg
.copy_type
== tINOUT
)
329 if (arg
.type
== tCSTRING
)
331 stream
.write (" js_vm_make"
332 + (arg
.staticp
? "_static" : "")
333 + "_string (vm, &argv["
335 + cspec
+ arg
.name
+ ", strlen ("
336 + cspec
+ arg
.name
+ "));\n");
338 else if (arg
.type
== tDOUBLE
)
340 stream
.write (" argv[" + argnum
+ "].type = JS_FLOAT;\n");
341 stream
.write (" argv[" + argnum
+ "].u.vfloat = "
342 + cspec
+ arg
.name
+ ";\n");
344 else if (arg
.type
== tINT
)
346 stream
.write (" argv[" + argnum
+ "].type = JS_INTEGER;\n");
347 stream
.write (" argv[" + argnum
+ "].u.vinteger = "
348 + cspec
+ arg
.name
+ ";\n");
350 else if (arg
.type
== tSTRING
)
352 stream
.write (" js_vm_make_static_string (vm, &argv["
354 + cspec
+ arg
.name
+ ", "
355 + cspec
+ arg
.name
+ "_len);\n");
362 /* Call the function. */
367 result = js_vm_apply (vm, \"" + this.name
+ "\", NULL, "
368 + (i
+ 1).toString () + ", argv);
371 JSNode *n = &vm->globals[js_vm_intern (vm, \"" + this.name
+ "\")];
373 if (n->type != JS_FUNC)
375 JSByteCode *bc = js_bc_read_data (" + this.name
+ "_bc,
376 sizeof (" + this.name
+ "_bc));
377 result = js_vm_execute (vm, bc);
381 jswrap_error (interp, \"initialization of function`"
382 + this.name
+ "' failed\");
385 jswrap_error (interp, \"execution of function `"
386 + this.name
+ "' failed\");
390 /* Handle out and inout parameters. */
391 for (i
= 0; i
< this.args
.length
; i
++)
393 var arg
= this.args
[i
];
394 if (arg
.copy_type
== tIN
)
397 var spos
= (this.args
.length
- i
).toString ();
399 /* Check that we have there a correct type. */
401 if ((vm->sp - " + spos
+ ")->type != " + jsint_typename (arg
.type
) + ")
402 jswrap_error (interp,
403 \"wrong return type for argument `"
404 + arg
.name
+ "' of function `" + this.name
+ "'\");
407 /* Handle the different types. */
408 if (arg
.type
== tCSTRING
)
411 *" + arg
.name
+ " = (char *) js_vm_alloc (vm, (vm->sp - "
412 + spos
+ ")->u.vstring->len + 1);
413 memcpy (*" + arg
.name
+ ", (vm->sp - " + spos
+ ")->u.vstring->data,
414 (vm->sp - " + spos
+ ")->u.vstring->len);
415 " + arg
.name
+ "[(vm->sp - " + spos
+ ")->u.vstring->len] = '\\0';
418 else if (arg
.type
== tDOUBLE
)
421 *" + arg
.name
+ " = (vm->sp - " + spos
+ ")->u.vfloat;\n");
423 else if (arg
.type
== tINT
)
426 *" + arg
.name
+ " = (vm->sp - " + spos
+ ")->u.vinteger;\n");
428 else if (arg
.type
== tSTRING
)
431 *" + arg
.name
+ " = (vm->sp - " + spos
+ ")->u.vstring->data;
432 *" + arg
.name
+ "_len = (vm->sp - " + spos
+ ")->u.vstring->len;
437 /* Handle the function return value. */
438 if (this.return_type
!= tVOID
)
440 /* Check that the code returned correct type. */
442 if (vm->exec_result.type != " + jsint_typename (this.return_type
) + ")
443 jswrap_error (interp, \"return type mismatch in function `"
448 /* Handle the different types. */
449 if (this.return_type
== tCSTRING
)
452 cp = (char *) js_vm_alloc (vm, vm->exec_result.u.vstring->len + 1);
453 memcpy (cp, vm->exec_result.u.vstring->data, vm->exec_result.u.vstring->len);
454 cp[vm->exec_result.u.vstring->len] = '\\0';
459 else if (this.return_type
== tDOUBLE
)
460 stream
.write (" return vm->exec_result.u.vfloat;\n");
461 else if (this.return_type
== tINT
)
462 stream
.write (" return vm->exec_result.u.vinteger;\n");
465 stream
.write ("}\n");
467 Func
.prototype.print_c
= Func
$print_c
;
469 function Func
$compile ()
471 /* Create the byte-code for this function. */
476 flags
|= JSC
$FLAG_VERBOSE
;
479 flags
|= JSC
$FLAG_GENERATE_DEBUG_INFO
;
481 flags
|= (JSC
$FLAG_OPTIMIZE_PEEPHOLE
482 | JSC
$FLAG_OPTIMIZE_JUMPS
483 | JSC
$FLAG_OPTIMIZE_BC_SIZE
);
485 flags
|= JSC
$FLAG_WARN_MASK
;
489 this.bc
= JSC
$compile_string (this.code
, flags
, null, null);
493 System
.error (error
, "\n");
497 Func
.prototype.compile
= Func
$compile
;
499 function Func
$dump_bc (stream
)
501 stream
.write ("\nstatic unsigned char " + this.name
+ "_bc[] = {");
504 for (i
= 0; i
< this.bc
.length
; i
++)
507 stream
.write ("\n ");
509 var item
= this.bc
[i
].toString (16);
510 if (item
.length
== 1)
513 stream
.write (" 0x" + item
+ ",");
516 stream
.write ("\n};\n");
518 Func
.prototype.dump_bc
= Func
$dump_bc
;
521 * The Argument class to hold function argument definitions.
527 this.copy_type
= tIN
;
528 this.staticp
= false;
533 function Argument
$print ()
535 System
.print (typename (this.copy_type
), " ", typename (this.type
),
538 Argument
.prototype.print
= Argument
$print
;
543 * The .jsw file parsing.
553 while ((token
= get_token ()) != tEOF
)
555 if (token
!= tFUNCTION
)
560 /* Possible return type. */
561 token
= get_token ();
562 if (is_type_token (token
))
564 if (token
== tSTRING
)
566 System
.error (input_file
, ":", linenum
,
567 ": the function return value can't be `string'\n");
571 func
.return_type
= token
;
573 token
= get_token ();
576 func
.return_type
= tVOID
;
578 /* The name of the function. */
579 if (token
!= tIDENTIFIER
)
582 if (!valid_c_identifier_re
.test (token_value
))
584 System
.error (input_file
, ":", linenum
,
585 ": function name is not a valid C identifier `",
590 func
.name
= token_value
;
593 token
= get_token ();
597 var args
= new Array ();
599 token
= get_token ();
600 while (token
!= #')')
602 var arg
= new Argument ();
604 while (token
!= tIDENTIFIER
)
609 if (is_type_token (token
))
611 else if (is_copy_type_token (token
))
612 arg
.copy_type
= token
;
613 else if (token
== tSTATIC
)
618 token
= get_token ();
621 if (!valid_c_identifier_re
.test (token_value
))
623 System
.error (input_file
, ":", linenum
,
624 ": argument name is not a valid C identifier `",
628 arg
.name
= token_value
;
630 /* Check some validity conditions. */
633 System
.error (input_file
, ":", linenum
,
634 ": no type specified for argument `",
640 if (arg
.type
!= tCSTRING
&& arg
.type
!= tSTRING
)
642 System
.error (input_file
, ":", linenum
,
643 ": type `static' can only be used with `cstring' and `string' arguments\n");
646 if (arg
.copy_type
== tOUT
)
647 System
.error (input_file
, ":", linenum
,
648 ": warning: type `static' is meaningful only with `in' and `inout' arguments\n");
653 token
= get_token ();
655 token
= get_token ();
660 /* The opening '{' of the function body. */
661 token
= get_token ();
665 /* Get the function body. */
666 var code
= new String ("");
669 var line
= ifp
.readln ();
674 if (end_brace_re
.test (line
))
677 code
.append (line
+ "\n");
683 // func.print_js (ofp_js);
684 func
.print_h (ofp_h
, true);
685 func
.print_c (ofp_c
);
691 function get_token ()
695 while ((ch
= ifp
.readByte ()) != -1)
697 if (ch
== #' ' || ch
== #'\t' || ch
== #'\v' || ch
== #'\r'
707 token_linenum
= linenum
;
709 if (ch
== #'/' && peek_char () == #'*')
711 /* Multi line comment. */
713 while ((ch
= ifp
.readByte ()) != -1
714 && (ch
!= #'*' || peek_char () != #'/'))
718 /* Consume the peeked #'/' character. */
722 /* Identifiers and keywords. */
723 else if (JSC
$lexer_is_identifier_letter (ch
))
726 var id
= String
.fromCharCode (ch
);
728 while ((ch
= ifp
.readByte ()) != -1
729 && (JSC
$lexer_is_identifier_letter (ch
)
730 || JSC
$lexer_is_decimal_digit (ch
)))
731 id
.append (File
.byteToString (ch
));
735 if (id
== "function")
739 else if (id
== "cstring")
741 else if (id
== "double")
743 else if (id
== "int")
745 else if (id
== "string")
747 else if (id
== "void")
751 else if (id
== "out")
753 else if (id
== "inout")
755 else if (id
== "static")
760 /* It really is an identifier. */
766 /* Just return the character as-is. */
775 function peek_char ()
777 var ch
= ifp
.readByte ();
783 function syntax_error ()
785 System
.error (input_file
, ":", linenum
, ": syntax error\n");
793 /* The header file. */
796 header_banner (stream
);
798 var ppname
= path_to_ppname (header_file
);
799 stream
.write ("\n#ifndef " + ppname
800 + "\n#define " + ppname
+ "\n");
804 header_banner (stream
);
805 stream
.write ("\n#include <jsint.h>\n");
811 * This global interpreter handle can be removed with " + program
+ "'s
812 * option -r, --reentrant.
815 stream
.write ("extern JSInterpPtr jswrap_interp;\n");
818 if (opt_no_error_handler
)
821 /* Prototype for the error handler of the JS runtime errors. */
823 stream
.write ("void jswrap_error (JSInterpPtr interp, char *error);\n");
827 /* Define the default jswrap_error() function. */
830 * This is the default error handler for the JS runtime errors. The default
831 * handler can be removed with " + program
+ "'s option -n, --no-error-handler.
832 * In this case, your code must define the handler function.
837 jswrap_error (JSInterpPtr interp, char *error)
841 fprintf (stderr, \"JS runtime error: %s\", error);
843 cp = js_error_message (interp);
845 fprintf (stderr, \": %s\", cp);
846 fprintf (stderr, \"\\n\");
856 * The global function definitions.
861 function header_banner (stream
)
863 stream
.write ("/* This file is automatically generated from `"
864 + input_file
+ "' by " + program
+ ". */\n");
867 path_to_ppname_re
= new RegExp ("[^A-Za-z_0-9]", "g");
869 function path_to_ppname (path
)
871 var str
= path
.toUpperCase ().replace (path_to_ppname_re
, "_");
872 if (#'0' <= str
[0] && str
[0] <= #'9')
880 /* The header file. */
882 stream
.write ("\n#endif /* not " + path_to_ppname (header_file
) + " */\n");