2000-01-10 21:22:43 +00: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.
//
2000-06-24 00:50:59 +00:00
# if 1
2000-06-24 02:53:29 +00:00
# define DEBUGGER_FOO
2000-06-23 22:27:17 +00:00
# define INTERPRET_INPUT
# else
# undef DEBUGGER_FOO
# undef INTERPRET_INPUT
# endif
2000-04-07 02:58:01 +00:00
# include <assert.h>
2000-01-10 21:22:43 +00:00
# include "world.h"
2000-04-06 02:59:16 +00:00
# include "interpreter.h"
2000-04-21 00:37:51 +00:00
# include "icodegenerator.h"
2000-04-06 02:59:16 +00:00
2000-06-23 22:27:17 +00:00
# ifdef DEBUGGER_FOO
2000-04-29 00:23:06 +00:00
# include "debugger.h"
2000-06-23 22:27:17 +00:00
# endif
2000-04-18 00:17:34 +00:00
2000-04-06 23:47:33 +00:00
# if defined(XP_MAC) && !defined(XP_MAC_MPW)
2000-01-10 21:22:43 +00:00
# include <SIOUX.h>
# include <MacTypes.h>
2000-04-18 00:51:53 +00: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 02:09:06 +00:00
2000-04-06 23:47:33 +00:00
# endif
2000-01-10 21:22:43 +00:00
2000-04-18 00:51:53 +00:00
namespace JavaScript {
2000-04-21 00:04:14 +00:00
namespace Shell {
2000-04-26 05:37:00 +00: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 05:15:52 +00:00
static bool promptLine ( LineReader & inReader , string & s , const char * prompt )
2000-04-26 05:37:00 +00:00
{
if ( prompt ) {
stdOut < < prompt ;
2000-05-12 05:15:52 +00:00
# ifdef XP_MAC_MPW
2000-04-26 05:37:00 +00:00
// Print a CR after the prompt because MPW grabs the entire
// line when entering an interactive command.
stdOut < < ' \n ' ;
2000-05-12 05:15:52 +00:00
# endif
2000-04-21 00:04:14 +00:00
}
2000-04-26 05:37:00 +00:00
return inReader . readLine ( s ) ! = 0 ;
}
2000-06-24 05:25:33 +00:00
World world ;
JSScope global ;
2000-04-26 05:37:00 +00:00
2000-06-23 22:27:17 +00:00
/* "filename" of the console */
const String ConsoleName = widenCString ( " <console> " ) ;
2000-05-09 05:46:26 +00:00
const bool showTokens = false ;
2000-04-26 05:37:00 +00:00
2000-06-23 22:27:17 +00: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-11 23:08:03 +00:00
{
stdErr < < " Could not locate source for file ' " < < fileName < < " ' \n " ;
2000-06-23 22:27:17 +00:00
return 0 ;
2000-07-11 23:08:03 +00:00
}
2000-06-23 22:27:17 +00:00
}
JavaScript : : Debugger : : Shell jsd ( world , stdin , JavaScript : : stdOut ,
JavaScript : : stdOut , & ResolveFile ) ;
# endif
2000-05-08 23:12:10 +00:00
2000-05-09 19:01:00 +00:00
static JSValue print ( const JSValues & argv )
{
size_t n = argv . size ( ) ;
2000-06-23 22:27:17 +00:00
if ( n > 1 ) { // the 'this' parameter is un-interesting
2000-06-21 22:32:21 +00:00
stdOut < < argv [ 1 ] ;
for ( size_t i = 2 ; i < n ; + + i )
2000-05-09 19:01:00 +00:00
stdOut < < ' ' < < argv [ i ] ;
}
stdOut < < " \n " ;
return kUndefinedValue ;
}
2000-06-28 18:41:30 +00:00
static JSValue dump ( const JSValues & argv )
{
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 05:25:33 +00:00
2000-06-24 05:36:09 +00:00
inline char narrow ( char16 ch ) { return char ( ch ) ; }
2000-06-24 05:25:33 +00:00
static JSValue load ( const JSValues & argv )
{
2000-07-11 23:49:20 +00:00
2000-07-11 20:54:06 +00:00
JSValue result ;
2000-06-24 05:25:33 +00:00
size_t n = argv . size ( ) ;
2000-07-11 23:49:20 +00:00
if ( n > 1 ) {
ASSERT ( argv [ 0 ] . isObject ( ) ) ;
JSScope * scope = dynamic_cast < JSScope * > ( argv [ 0 ] . object ) ;
ASSERT ( scope ) ;
2000-06-24 05:25:33 +00:00
for ( size_t i = 1 ; i < n ; + + i ) {
JSValue val = argv [ i ] . toString ( ) ;
if ( val . isString ( ) ) {
2000-07-11 23:49:20 +00:00
Context cx ( world , scope ) ;
2000-06-24 05:25:33 +00:00
String fileName ( * val . string ) ;
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-11 23:49:20 +00:00
result = cx . readEvalFile ( f , fileName ) ;
2000-06-24 05:25:33 +00:00
fclose ( f ) ;
}
}
}
}
2000-07-11 20:54:06 +00:00
return result ;
2000-05-08 23:12:10 +00:00
}
2000-04-26 05:37:00 +00:00
static void readEvalPrint ( FILE * in , World & world )
{
2000-06-24 05:25:33 +00:00
Context cx ( world , & global ) ;
2000-06-23 22:27:17 +00:00
# ifdef DEBUGGER_FOO
jsd . attachToContext ( & cx ) ;
# endif
2000-06-24 05:25:33 +00:00
global . defineNativeFunction ( world . identifiers [ widenCString ( " print " ) ] , print ) ;
2000-06-28 18:41:30 +00:00
global . defineNativeFunction ( world . identifiers [ widenCString ( " dump " ) ] , dump ) ;
2000-06-24 05:25:33 +00:00
global . defineNativeFunction ( world . identifiers [ widenCString ( " load " ) ] , load ) ;
2000-05-18 00:01:33 +00:00
2000-04-26 05:37:00 +00:00
String buffer ;
string line ;
LineReader inReader ( in ) ;
2000-05-12 05:15:52 +00:00
while ( promptLine ( inReader , line , buffer . empty ( ) ? " js> " : " > " ) ) {
2000-04-26 05:37:00 +00:00
appendChars ( buffer , line . data ( ) , line . size ( ) ) ;
try {
Arena a ;
2000-06-23 22:27:17 +00:00
Parser p ( world , a , buffer , ConsoleName ) ;
2000-04-26 05:37:00 +00: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 00:04:14 +00:00
}
2000-05-24 01:51:32 +00:00
stdOut < < ' \n ' ;
2000-04-26 05:37:00 +00:00
} else {
2000-05-24 01:51:32 +00:00
StmtNode * parsedStatements = p . parseProgram ( ) ;
ASSERT ( p . lexer . peek ( true ) . hasKind ( Token : : end ) ) ;
2000-05-12 03:26:43 +00:00
{
2000-06-01 03:31:17 +00:00
PrettyPrinter f ( stdOut , 30 ) ;
2000-05-12 03:26:43 +00:00
{
PrettyPrinter : : Block b ( f , 2 ) ;
2000-05-24 01:51:32 +00:00
f < < " Program = " ;
2000-05-12 03:26:43 +00:00
f . linearBreak ( 1 ) ;
2000-05-24 01:51:32 +00:00
StmtNode : : printStatements ( f , parsedStatements ) ;
2000-05-12 03:26:43 +00:00
}
f . end ( ) ;
}
2000-05-24 01:51:32 +00:00
stdOut < < ' \n ' ;
2000-06-23 22:27:17 +00: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-11 23:49:20 +00:00
ICodeModule * icm = cx . genCode ( parsedStatements , ConsoleName ) ;
2000-06-24 05:25:33 +00:00
if ( icm ) {
JSValue result = cx . interpret ( icm , JSValues ( ) ) ;
stdOut < < " result = " < < result < < " \n " ;
delete icm ;
}
2000-05-18 00:01:33 +00:00
# endif
2000-04-26 05:37:00 +00: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-23 22:27:17 +00:00
e . sourceFile = = ConsoleName ) ) {
2000-04-26 05:37:00 +00:00
stdOut < < ' \n ' < < e . fullMessage ( ) ;
2000-04-21 00:04:14 +00:00
clear ( buffer ) ;
2000-01-10 21:22:43 +00:00
}
}
2000-04-21 00:04:14 +00:00
}
2000-04-26 05:37:00 +00:00
stdOut < < ' \n ' ;
}
2000-04-28 00:11:18 +00:00
2000-04-29 00:23:06 +00:00
2000-04-28 13:31:39 +00:00
/**
* Poor man ' s instruction tracing facility .
*/
class Tracer : public Context : : Listener {
typedef InstructionStream : : difference_type InstructionOffset ;
2000-05-12 01:20:34 +00:00
void listen ( Context * context , Context : : Event event )
2000-04-28 13:31:39 +00:00
{
2000-05-12 01:20:34 +00:00
if ( event & Context : : EV_STEP ) {
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 ) ;
2000-05-04 22:42:49 +00:00
2000-05-12 01:20:34 +00:00
Instruction * i = * pc ;
stdOut < < * i ;
if ( i - > op ( ) ! = BRANCH & & i - > count ( ) > 0 ) {
stdOut < < " [ " ;
i - > printOperands ( stdOut , registers ) ;
stdOut < < " ] \n " ;
} else {
stdOut < < ' \n ' ;
}
2000-04-28 13:31:39 +00:00
}
}
} ;
2000-05-08 23:12:10 +00:00
2000-06-16 01:37:47 +00:00
char * tests [ ] = {
" function fact(n) { if (n > 1) return n * fact(n-1); else return 1; } print(fact(6), \" should be 720 \" ); return; " ,
2000-07-06 18:26:26 +00:00
" a = { f1: 1, f2: 2}; print(a.f2++, \" should be 2 \" ); print(a.f2 <<= 1, \" should be 6 \" ); return; " ,
2000-07-10 23:18:07 +00:00
" class A { static var b = 3; static function s() { return b++; } } var a:A = new A; print(a.s(), \" should be 3 \" ); print(A.b, \" should be 4 \" ); return; "
2000-06-16 01:37:47 +00:00
} ;
2000-06-24 01:04:58 +00:00
static void testCompile ( )
2000-06-16 01:37:47 +00:00
{
JSScope glob ;
Context cx ( world , & glob ) ;
StringAtom & printName = world . identifiers [ widenCString ( " print " ) ] ;
glob . defineNativeFunction ( printName , print ) ;
2000-06-24 02:53:29 +00:00
for ( uint i = 0 ; i < sizeof ( tests ) / sizeof ( char * ) ; i + + ) {
2000-06-16 01:37:47 +00:00
String testScript = widenCString ( tests [ i ] ) ;
Arena a ;
Parser p ( world , a , testScript , widenCString ( " testCompile " ) ) ;
StmtNode * parsedStatements = p . parseProgram ( ) ;
2000-06-20 22:45:45 +00:00
ICodeGenerator icg ( & world , & glob ) ;
2000-06-21 22:32:21 +00:00
StmtNode * s = parsedStatements ;
while ( s ) {
icg . genStmt ( s ) ;
s = s - > next ;
2000-06-16 01:37:47 +00:00
}
cx . interpret ( icg . complete ( ) , JSValues ( ) ) ;
}
}
2000-04-28 01:43:03 +00:00
2000-05-06 03:31:35 +00:00
2000-04-21 00:04:14 +00:00
} /* namespace Shell */
} /* namespace JavaScript */
2000-04-07 02:58:01 +00:00
2000-04-26 05:37:00 +00:00
2000-06-24 02:53:29 +00:00
# if defined(XP_MAC) && !defined(XP_MAC_MPW)
2000-04-25 02:58:30 +00:00
int main ( int argc , char * * argv )
2000-01-10 21:22:43 +00:00
{
initConsole ( " \ pJavaScript Shell " , " Welcome to the js2 shell. \n " , argc , argv ) ;
2000-06-24 02:53:29 +00:00
# else
int main ( int , char * * )
{
# endif
2000-04-29 00:29:56 +00:00
using namespace JavaScript ;
using namespace Shell ;
2000-06-24 02:53:29 +00:00
# if 1
2000-06-16 01:37:47 +00:00
testCompile ( ) ;
2000-06-24 02:53:29 +00:00
# endif
2000-04-29 00:23:06 +00:00
readEvalPrint ( stdin , world ) ;
2000-04-04 21:38:25 +00:00
return 0 ;
2000-04-21 00:04:14 +00:00
// return ProcessArgs(argv + 1, argc - 1);
2000-01-10 21:22:43 +00:00
}