2000-01-11 00:22:43 +03:00
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape Public
// License Version 1.1 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of
// the License at http://www.mozilla.org/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 1998 Netscape Communications Corporation. All
// Rights Reserved.
//
// JS2 shell.
//
2001-02-09 22:11:04 +03:00
# ifdef _WIN32
// Turn off warnings about identifiers too long in browser information
# pragma warning(disable: 4786)
# endif
2000-06-24 04:50:59 +04:00
# if 1
2000-06-24 06:53:29 +04:00
# define DEBUGGER_FOO
2000-06-24 02:27:17 +04:00
# define INTERPRET_INPUT
# else
# undef DEBUGGER_FOO
# undef INTERPRET_INPUT
# endif
2001-02-08 09:01:54 +03:00
# include <algorithm>
2000-04-07 06:58:01 +04:00
# include <assert.h>
2000-01-11 00:22:43 +03:00
# include "world.h"
2000-04-06 06:59:16 +04:00
# include "interpreter.h"
2000-04-21 04:37:51 +04:00
# include "icodegenerator.h"
2000-04-06 06:59:16 +04:00
2000-06-24 02:27:17 +04:00
# ifdef DEBUGGER_FOO
2000-04-29 04:23:06 +04:00
# include "debugger.h"
2000-06-24 02:27:17 +04:00
# endif
2000-04-18 04:17:34 +04:00
2000-04-07 03:47:33 +04:00
# if defined(XP_MAC) && !defined(XP_MAC_MPW)
2000-01-11 00:22:43 +03:00
# include <SIOUX.h>
# include <MacTypes.h>
2000-04-18 04:51:53 +04:00
static char * mac_argv [ ] = { " js2 " , 0 } ;
static void initConsole ( StringPtr consoleName ,
const char * startupMessage ,
int & argc , char * * & argv )
{
SIOUXSettings . autocloseonquit = false ;
SIOUXSettings . asktosaveonclose = false ;
SIOUXSetTitle ( consoleName ) ;
// Set up a buffer for stderr (otherwise it's a pig).
static char buffer [ BUFSIZ ] ;
setvbuf ( stderr , buffer , _IOLBF , BUFSIZ ) ;
JavaScript : : stdOut < < startupMessage ;
argc = 1 ;
argv = mac_argv ;
}
2000-04-19 06:09:06 +04:00
2000-04-07 03:47:33 +04:00
# endif
2000-01-11 00:22:43 +03:00
2000-04-18 04:51:53 +04:00
namespace JavaScript {
2000-04-21 04:04:14 +04:00
namespace Shell {
2000-04-26 09:37:00 +04:00
using namespace ICG ;
using namespace JSTypes ;
using namespace Interpreter ;
// Interactively read a line from the input stream in and put it into
// s. Return false if reached the end of input before reading anything.
2000-05-12 09:15:52 +04:00
static bool promptLine ( LineReader & inReader , string & s , const char * prompt )
2000-04-26 09:37:00 +04:00
{
if ( prompt ) {
stdOut < < prompt ;
2000-05-12 09:15:52 +04:00
# ifdef XP_MAC_MPW
2000-04-26 09:37:00 +04:00
// Print a CR after the prompt because MPW grabs the entire
// line when entering an interactive command.
stdOut < < ' \n ' ;
2000-05-12 09:15:52 +04:00
# endif
2000-04-21 04:04:14 +04:00
}
2000-04-26 09:37:00 +04:00
return inReader . readLine ( s ) ! = 0 ;
}
2000-06-24 09:25:33 +04:00
World world ;
2000-04-26 09:37:00 +04:00
2000-06-24 02:27:17 +04:00
/* "filename" of the console */
const String ConsoleName = widenCString ( " <console> " ) ;
2000-05-09 09:46:26 +04:00
const bool showTokens = false ;
2000-04-26 09:37:00 +04:00
2000-06-24 02:27:17 +04:00
# ifdef DEBUGGER_FOO
Reader * sourceReader ; /* Reader for console file */
static
const Reader * ResolveFile ( const String & fileName )
{
if ( fileName = = ConsoleName )
return sourceReader ;
else
2000-07-12 03:08:03 +04:00
{
stdErr < < " Could not locate source for file ' " < < fileName < < " ' \n " ;
2000-06-24 02:27:17 +04:00
return 0 ;
2000-07-12 03:08:03 +04:00
}
2000-06-24 02:27:17 +04:00
}
JavaScript : : Debugger : : Shell jsd ( world , stdin , JavaScript : : stdOut ,
JavaScript : : stdOut , & ResolveFile ) ;
# endif
2000-05-09 03:12:10 +04:00
2000-08-03 03:09:29 +04:00
static JSValue print ( Context * , const JSValues & argv )
2000-05-09 23:01:00 +04:00
{
size_t n = argv . size ( ) ;
2000-06-24 02:27:17 +04:00
if ( n > 1 ) { // the 'this' parameter is un-interesting
2000-06-22 02:32:21 +04:00
stdOut < < argv [ 1 ] ;
for ( size_t i = 2 ; i < n ; + + i )
2000-05-09 23:01:00 +04:00
stdOut < < ' ' < < argv [ i ] ;
}
stdOut < < " \n " ;
return kUndefinedValue ;
}
2000-08-03 03:09:29 +04:00
static JSValue dump ( Context * , const JSValues & argv )
2000-06-28 22:41:30 +04:00
{
size_t n = argv . size ( ) ;
if ( n > 1 ) { // the 'this' parameter is un-interesting
if ( argv [ 1 ] . isFunction ( ) ) {
JSFunction * f = static_cast < JSFunction * > ( argv [ 1 ] . function ) ;
if ( f - > isNative ( ) )
stdOut < < " Native function " ;
else
stdOut < < * f - > getICode ( ) ;
}
else
stdOut < < " Not a function " ;
}
stdOut < < " \n " ;
return kUndefinedValue ;
}
2000-06-24 09:25:33 +04:00
2000-06-24 09:36:09 +04:00
inline char narrow ( char16 ch ) { return char ( ch ) ; }
2000-07-13 04:14:54 +04:00
static JSValue load ( Context * cx , const JSValues & argv )
2000-06-24 09:25:33 +04:00
{
2000-07-12 03:49:20 +04:00
2000-07-12 00:54:06 +04:00
JSValue result ;
2000-06-24 09:25:33 +04:00
size_t n = argv . size ( ) ;
2000-07-12 03:49:20 +04:00
if ( n > 1 ) {
2000-06-24 09:25:33 +04:00
for ( size_t i = 1 ; i < n ; + + i ) {
2001-02-23 03:23:53 +03:00
JSValue val = argv [ i ] . toString ( cx ) ;
2000-06-24 09:25:33 +04:00
if ( val . isString ( ) ) {
2001-01-02 22:49:16 +03:00
JSString & fileName = * val . string ;
2000-06-24 09:25:33 +04:00
std : : string str ( fileName . length ( ) , char ( ) ) ;
std : : transform ( fileName . begin ( ) , fileName . end ( ) , str . begin ( ) , narrow ) ;
FILE * f = fopen ( str . c_str ( ) , " r " ) ;
if ( f ) {
2000-07-13 04:14:54 +04:00
result = cx - > readEvalFile ( f , fileName ) ;
2000-06-24 09:25:33 +04:00
fclose ( f ) ;
}
}
}
}
2000-07-12 00:54:06 +04:00
return result ;
2000-05-09 03:12:10 +04:00
}
2000-12-15 04:38:40 +03:00
static JSValue loadxml ( Context * cx , const JSValues & argv )
{
JSValue result ;
size_t n = argv . size ( ) ;
if ( n > 1 ) {
for ( size_t i = 1 ; i < n ; + + i ) {
2001-02-23 03:23:53 +03:00
JSValue val = argv [ i ] . toString ( cx ) ;
2000-12-15 04:38:40 +03:00
if ( val . isString ( ) ) {
2001-01-02 22:49:16 +03:00
JSString & fileName = * val . string ;
2000-12-15 04:38:40 +03:00
std : : string str ( fileName . length ( ) , char ( ) ) ;
std : : transform ( fileName . begin ( ) , fileName . end ( ) , str . begin ( ) , narrow ) ;
2001-01-20 02:56:37 +03:00
ICodeModule * icm = cx - > loadClass ( str . c_str ( ) ) ;
if ( icm )
result = JSValue ( new JSFunction ( icm ) ) ;
2000-12-15 04:38:40 +03:00
}
}
}
return result ;
}
2000-11-03 05:42:01 +03:00
static bool goGeorge = false ;
2000-11-07 04:09:45 +03:00
static JSValue george ( Context * , const JSValues & )
2000-11-03 05:42:01 +03:00
{
goGeorge = ! goGeorge ;
return JSValue ( new JSString ( goGeorge ? " George is going " : " George is taking a break " ) ) ;
}
2000-07-14 05:46:14 +04:00
#if 0 // need a XP version of this, rip off from Monkey?
2000-07-14 05:00:53 +04:00
# include <sys/timeb.h>
static JSValue time ( Context * cx , const JSValues & argv )
{
struct _timeb timebuffer ;
_ftime ( & timebuffer ) ;
return JSValue ( ( double ) timebuffer . time * 1000 + timebuffer . millitm ) ;
}
2000-07-14 05:46:14 +04:00
# endif
2000-07-14 05:00:53 +04:00
2000-10-10 02:21:26 +04:00
/**
* Poor man ' s instruction tracing facility .
*/
class Tracer : public Context : : Listener {
typedef InstructionStream : : difference_type InstructionOffset ;
void listen ( Context * context , Context : : Event event )
{
2000-11-03 05:42:01 +03:00
if ( goGeorge & & ( event & Context : : EV_STEP ) ) {
2000-10-10 02:21:26 +04:00
ICodeModule * iCode = context - > getICode ( ) ;
JSValues & registers = context - > getRegisters ( ) ;
InstructionIterator pc = context - > getPC ( ) ;
InstructionOffset offset = ( pc - iCode - > its_iCode - > begin ( ) ) ;
printFormat ( stdOut , " trace [%02u:%04u]: " ,
iCode - > mID , offset ) ;
Instruction * i = * pc ;
stdOut < < * i ;
if ( i - > op ( ) ! = BRANCH & & i - > count ( ) > 0 ) {
stdOut < < " [ " ;
i - > printOperands ( stdOut , registers ) ;
stdOut < < " ] \n " ;
} else {
stdOut < < ' \n ' ;
}
}
}
} ;
2000-11-03 05:42:01 +03:00
# define HAVE_GEORGE_TRACE_IT
2000-10-21 04:30:23 +04:00
//#define TEST_XML_LOADER
2000-10-10 02:21:26 +04:00
2000-04-26 09:37:00 +04:00
static void readEvalPrint ( FILE * in , World & world )
{
2000-07-21 05:16:49 +04:00
JSScope global ;
2000-06-24 09:25:33 +04:00
Context cx ( world , & global ) ;
2000-06-24 02:27:17 +04:00
# ifdef DEBUGGER_FOO
jsd . attachToContext ( & cx ) ;
# endif
2000-07-18 00:39:19 +04:00
global . defineNativeFunction ( world . identifiers [ " print " ] , print ) ;
global . defineNativeFunction ( world . identifiers [ " dump " ] , dump ) ;
global . defineNativeFunction ( world . identifiers [ " load " ] , load ) ;
2000-12-15 04:38:40 +03:00
global . defineNativeFunction ( world . identifiers [ " loadxml " ] , loadxml ) ;
2000-11-03 05:42:01 +03:00
global . defineNativeFunction ( world . identifiers [ " george " ] , george ) ;
2000-07-18 00:39:19 +04:00
// global.defineNativeFunction(world.identifiers["time"], time);
2000-05-18 04:01:33 +04:00
2000-04-26 09:37:00 +04:00
String buffer ;
string line ;
LineReader inReader ( in ) ;
2000-10-10 02:21:26 +04:00
# ifdef HAVE_GEORGE_TRACE_IT
Tracer * george = new Tracer ( ) ;
cx . addListener ( george ) ;
# endif
2000-10-19 03:37:44 +04:00
# ifdef TEST_XML_LOADER
cx . loadClass ( " class.xml " ) ;
# endif
2000-05-12 09:15:52 +04:00
while ( promptLine ( inReader , line , buffer . empty ( ) ? " js> " : " > " ) ) {
2000-04-26 09:37:00 +04:00
appendChars ( buffer , line . data ( ) , line . size ( ) ) ;
try {
Arena a ;
2000-06-24 02:27:17 +04:00
Parser p ( world , a , buffer , ConsoleName ) ;
2000-04-26 09:37:00 +04:00
if ( showTokens ) {
Lexer & l = p . lexer ;
while ( true ) {
const Token & t = l . get ( true ) ;
if ( t . hasKind ( Token : : end ) )
break ;
stdOut < < ' ' ;
t . print ( stdOut , true ) ;
2000-04-21 04:04:14 +04:00
}
2000-05-24 05:51:32 +04:00
stdOut < < ' \n ' ;
2000-04-26 09:37:00 +04:00
} else {
2000-05-24 05:51:32 +04:00
StmtNode * parsedStatements = p . parseProgram ( ) ;
ASSERT ( p . lexer . peek ( true ) . hasKind ( Token : : end ) ) ;
2000-05-12 07:26:43 +04:00
{
2000-06-01 07:31:17 +04:00
PrettyPrinter f ( stdOut , 30 ) ;
2000-05-12 07:26:43 +04:00
{
PrettyPrinter : : Block b ( f , 2 ) ;
2000-05-24 05:51:32 +04:00
f < < " Program = " ;
2000-05-12 07:26:43 +04:00
f . linearBreak ( 1 ) ;
2000-05-24 05:51:32 +04:00
StmtNode : : printStatements ( f , parsedStatements ) ;
2000-05-12 07:26:43 +04:00
}
f . end ( ) ;
}
2000-05-24 05:51:32 +04:00
stdOut < < ' \n ' ;
2000-06-24 02:27:17 +04:00
# ifdef INTERPRET_INPUT
# ifdef DEBUGGER_FOO
sourceReader = & ( p . lexer . reader ) ;
# endif
// Generate code for parsedStatements, which is a linked
// list of zero or more statements
2000-07-12 03:49:20 +04:00
ICodeModule * icm = cx . genCode ( parsedStatements , ConsoleName ) ;
2000-06-24 09:25:33 +04:00
if ( icm ) {
2000-08-05 00:37:42 +04:00
# ifdef SHOW_ICODE
stdOut < < * icm ;
# endif
2000-06-24 09:25:33 +04:00
JSValue result = cx . interpret ( icm , JSValues ( ) ) ;
stdOut < < " result = " < < result < < " \n " ;
delete icm ;
}
2000-05-18 04:01:33 +04:00
# endif
2000-04-26 09:37:00 +04:00
}
clear ( buffer ) ;
} catch ( Exception & e ) {
/* If we got a syntax error on the end of input,
* then wait for a continuation
* of input rather than printing the error message . */
if ( ! ( e . hasKind ( Exception : : syntaxError ) & &
e . lineNum & & e . pos = = buffer . size ( ) & &
2000-06-24 02:27:17 +04:00
e . sourceFile = = ConsoleName ) ) {
2000-04-26 09:37:00 +04:00
stdOut < < ' \n ' < < e . fullMessage ( ) ;
2000-04-21 04:04:14 +04:00
clear ( buffer ) ;
2000-01-11 00:22:43 +03:00
}
}
2000-04-21 04:04:14 +04:00
}
2000-04-26 09:37:00 +04:00
stdOut < < ' \n ' ;
}
2000-04-28 04:11:18 +04:00
2000-10-21 04:30:23 +04:00
//#define HAVE_GEORGE_TRACE_IT
2000-06-16 05:37:47 +04:00
char * tests [ ] = {
2000-10-23 23:39:55 +04:00
# ifdef NEW_PARSER
2000-11-09 00:05:58 +03:00
" function f(a,b,|'x' 'y' c=0) { return a+b+c; } print(f(1,2,x:3), 'should be 6'); return; " ,
2000-10-23 23:39:55 +04:00
# endif
2000-06-16 05:37:47 +04:00
" function fact(n) { if (n > 1) return n * fact(n-1); else return 1; } print(fact(6), \" should be 720 \" ); return; " ,
2000-07-06 22:26:26 +04:00
" a = { f1: 1, f2: 2}; print(a.f2++, \" should be 2 \" ); print(a.f2 <<= 1, \" should be 6 \" ); return; " ,
2001-02-14 21:30:03 +03:00
" class A { static var b = 3; static function s() { return b++; }function x() { return \" Ax \" ; } function y() { return \" Ay \" ; } } var a:A = new A; print(A.s(), \" should be 3 \" ); print(A.b, \" should be 4 \" ); return; " ,
2000-07-19 00:53:03 +04:00
" class B extends A { function x() { return \" Bx \" ; } } var b:B = new B; print(b.x(), \" should be Bx \" ); print(b.y(), \" should be Ay \" ); return; "
2000-06-16 05:37:47 +04:00
} ;
2000-06-24 05:04:58 +04:00
static void testCompile ( )
2000-06-16 05:37:47 +04:00
{
JSScope glob ;
Context cx ( world , & glob ) ;
2000-10-19 03:37:44 +04:00
# ifdef HAVE_GEORGE_TRACE_IT
Tracer * george = new Tracer ( ) ;
cx . addListener ( george ) ;
# endif
2000-07-18 00:39:19 +04:00
glob . defineNativeFunction ( world . identifiers [ " print " ] , print ) ;
2000-06-24 06:53:29 +04:00
for ( uint i = 0 ; i < sizeof ( tests ) / sizeof ( char * ) ; i + + ) {
2000-06-16 05:37:47 +04:00
String testScript = widenCString ( tests [ i ] ) ;
Arena a ;
Parser p ( world , a , testScript , widenCString ( " testCompile " ) ) ;
StmtNode * parsedStatements = p . parseProgram ( ) ;
2001-02-02 04:04:22 +03:00
ICodeGenerator icg ( & cx , NULL , NULL , ICodeGenerator : : kIsTopLevel , & Void_Type ) ;
2000-06-22 02:32:21 +04:00
StmtNode * s = parsedStatements ;
while ( s ) {
icg . genStmt ( s ) ;
s = s - > next ;
2000-06-16 05:37:47 +04:00
}
2001-02-02 04:04:22 +03:00
JSValue result = cx . interpret ( icg . complete ( ) , JSValues ( ) ) ;
2000-11-07 01:57:10 +03:00
stdOut < < " result = " < < result < < " \n " ;
2000-06-16 05:37:47 +04:00
}
}
2000-04-28 05:43:03 +04:00
2000-05-06 07:31:35 +04:00
2000-10-19 03:37:44 +04:00
2000-04-21 04:04:14 +04:00
} /* namespace Shell */
} /* namespace JavaScript */
2000-04-07 06:58:01 +04:00
2000-04-26 09:37:00 +04:00
2000-06-24 06:53:29 +04:00
# if defined(XP_MAC) && !defined(XP_MAC_MPW)
2000-04-25 06:58:30 +04:00
int main ( int argc , char * * argv )
2000-01-11 00:22:43 +03:00
{
initConsole ( " \ pJavaScript Shell " , " Welcome to the js2 shell. \n " , argc , argv ) ;
2000-06-24 06:53:29 +04:00
# else
int main ( int , char * * )
{
# endif
2000-04-29 04:29:56 +04:00
using namespace JavaScript ;
using namespace Shell ;
2000-10-19 03:37:44 +04:00
2000-06-24 06:53:29 +04:00
# if 1
2000-06-16 05:37:47 +04:00
testCompile ( ) ;
2000-06-24 06:53:29 +04:00
# endif
2000-04-29 04:23:06 +04:00
readEvalPrint ( stdin , world ) ;
2000-10-19 03:37:44 +04:00
2000-04-05 01:38:25 +04:00
return 0 ;
2000-04-21 04:04:14 +04:00
// return ProcessArgs(argv + 1, argc - 1);
2000-01-11 00:22:43 +03:00
}