2020-03-07 21:42:11 +03:00
/*
* Copyright ( c ) 2020 , Andreas Kling < kling @ serenityos . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-03-12 12:51:41 +03:00
# include <AK/ByteBuffer.h>
2020-03-07 21:42:11 +03:00
# include <AK/NonnullOwnPtr.h>
2020-03-26 01:10:29 +03:00
# include <AK/StringBuilder.h>
2020-03-12 12:51:41 +03:00
# include <LibCore/ArgsParser.h>
# include <LibCore/File.h>
2020-03-07 21:42:11 +03:00
# include <LibJS/AST.h>
# include <LibJS/Interpreter.h>
2020-03-11 21:27:43 +03:00
# include <LibJS/Parser.h>
2020-03-26 14:26:11 +03:00
# include <LibJS/Runtime/Array.h>
2020-03-31 20:43:45 +03:00
# include <LibJS/Runtime/Date.h>
2020-04-02 10:54:15 +03:00
# include <LibJS/Runtime/Error.h>
2020-03-26 16:54:43 +03:00
# include <LibJS/Runtime/Function.h>
2020-04-01 19:53:28 +03:00
# include <LibJS/Runtime/GlobalObject.h>
2020-03-16 16:20:30 +03:00
# include <LibJS/Runtime/Object.h>
# include <LibJS/Runtime/PrimitiveString.h>
2020-04-02 20:32:21 +03:00
# include <LibJS/Runtime/Shape.h>
2020-03-16 16:20:30 +03:00
# include <LibJS/Runtime/Value.h>
2020-03-31 14:34:57 +03:00
# include <LibLine/Editor.h>
2020-03-07 21:42:11 +03:00
# include <stdio.h>
2020-04-02 18:52:40 +03:00
Vector < String > repl_statements ;
2020-04-01 22:20:32 +03:00
class ReplObject : public JS : : GlobalObject {
public :
ReplObject ( ) ;
virtual ~ ReplObject ( ) override ;
private :
virtual const char * class_name ( ) const override { return " ReplObject " ; }
static JS : : Value exit_interpreter ( JS : : Interpreter & ) ;
static JS : : Value repl_help ( JS : : Interpreter & ) ;
static JS : : Value load_file ( JS : : Interpreter & ) ;
2020-04-02 18:52:40 +03:00
static JS : : Value save_to_file ( JS : : Interpreter & ) ;
2020-04-01 22:20:32 +03:00
} ;
2020-03-26 01:10:29 +03:00
bool dump_ast = false ;
2020-03-31 20:00:20 +03:00
static OwnPtr < Line : : Editor > editor ;
2020-03-26 01:10:29 +03:00
String read_next_piece ( )
{
StringBuilder piece ;
int level = 0 ;
2020-03-30 21:14:23 +03:00
StringBuilder prompt_builder ;
2020-03-26 01:10:29 +03:00
do {
2020-03-30 21:14:23 +03:00
prompt_builder . clear ( ) ;
prompt_builder . append ( " > " ) ;
for ( auto i = 0 ; i < level ; + + i )
prompt_builder . append ( " " ) ;
2020-03-31 20:00:20 +03:00
String line = editor - > get_line ( prompt_builder . build ( ) ) ;
2020-04-05 00:27:21 +03:00
editor - > add_to_history ( line ) ;
2020-03-26 01:10:29 +03:00
piece . append ( line ) ;
auto lexer = JS : : Lexer ( line ) ;
for ( JS : : Token token = lexer . next ( ) ; token . type ( ) ! = JS : : TokenType : : Eof ; token = lexer . next ( ) ) {
switch ( token . type ( ) ) {
case JS : : TokenType : : BracketOpen :
case JS : : TokenType : : CurlyOpen :
case JS : : TokenType : : ParenOpen :
level + + ;
break ;
case JS : : TokenType : : BracketClose :
case JS : : TokenType : : CurlyClose :
case JS : : TokenType : : ParenClose :
level - - ;
break ;
default :
break ;
}
}
} while ( level > 0 ) ;
return piece . to_string ( ) ;
}
2020-03-26 14:26:11 +03:00
static void print_value ( JS : : Value value , HashTable < JS : : Object * > & seen_objects ) ;
2020-04-01 23:18:47 +03:00
static void print_array ( const JS : : Array & array , HashTable < JS : : Object * > & seen_objects )
2020-03-26 14:26:11 +03:00
{
fputs ( " [ " , stdout ) ;
2020-04-01 23:18:47 +03:00
for ( size_t i = 0 ; i < array . elements ( ) . size ( ) ; + + i ) {
print_value ( array . elements ( ) [ i ] , seen_objects ) ;
if ( i ! = array . elements ( ) . size ( ) - 1 )
2020-03-26 14:26:11 +03:00
fputs ( " , " , stdout ) ;
}
fputs ( " ] " , stdout ) ;
}
2020-04-01 23:18:47 +03:00
static void print_object ( const JS : : Object & object , HashTable < JS : : Object * > & seen_objects )
2020-03-26 14:26:11 +03:00
{
fputs ( " { " , stdout ) ;
2020-04-06 17:53:02 +03:00
for ( size_t i = 0 ; i < object . elements ( ) . size ( ) ; + + i ) {
printf ( " \" \033 [33;1m%zu \033 [0m \" : " , i ) ;
print_value ( object . elements ( ) [ i ] , seen_objects ) ;
if ( i ! = object . elements ( ) . size ( ) - 1 )
fputs ( " , " , stdout ) ;
}
if ( ! object . elements ( ) . is_empty ( ) & & object . shape ( ) . property_count ( ) )
fputs ( " , " , stdout ) ;
2020-03-26 14:26:11 +03:00
size_t index = 0 ;
2020-04-02 20:32:21 +03:00
for ( auto & it : object . shape ( ) . property_table ( ) ) {
2020-03-26 14:26:11 +03:00
printf ( " \" \033 [33;1m%s \033 [0m \" : " , it . key . characters ( ) ) ;
2020-04-02 20:32:21 +03:00
print_value ( object . get_direct ( it . value . offset ) , seen_objects ) ;
2020-04-06 17:53:02 +03:00
if ( index ! = object . shape ( ) . property_count ( ) - 1 )
2020-03-26 14:26:11 +03:00
fputs ( " , " , stdout ) ;
+ + index ;
}
fputs ( " } " , stdout ) ;
}
2020-04-01 23:18:47 +03:00
static void print_function ( const JS : : Object & function , HashTable < JS : : Object * > & )
2020-03-26 16:54:43 +03:00
{
2020-04-01 23:18:47 +03:00
printf ( " \033 [34;1m[%s] \033 [0m " , function . class_name ( ) ) ;
2020-03-26 16:54:43 +03:00
}
2020-04-01 23:18:47 +03:00
static void print_date ( const JS : : Object & date , HashTable < JS : : Object * > & )
2020-03-31 20:43:45 +03:00
{
2020-04-01 23:18:47 +03:00
printf ( " \033 [34;1mDate %s \033 [0m " , static_cast < const JS : : Date & > ( date ) . string ( ) . characters ( ) ) ;
2020-03-31 20:43:45 +03:00
}
2020-04-02 10:54:15 +03:00
static void print_error ( const JS : : Object & object , HashTable < JS : : Object * > & )
{
auto & error = static_cast < const JS : : Error & > ( object ) ;
2020-04-02 16:18:19 +03:00
printf ( " \033 [34;1m[%s] \033 [0m " , error . name ( ) . characters ( ) ) ;
if ( ! error . message ( ) . is_empty ( ) )
printf ( " : %s " , error . message ( ) . characters ( ) ) ;
2020-04-02 10:54:15 +03:00
}
2020-03-26 14:26:11 +03:00
void print_value ( JS : : Value value , HashTable < JS : : Object * > & seen_objects )
{
if ( value . is_object ( ) ) {
2020-04-01 23:18:47 +03:00
if ( seen_objects . contains ( & value . as_object ( ) ) ) {
2020-03-26 14:26:11 +03:00
// FIXME: Maybe we should only do this for circular references,
// not for all reoccurring objects.
2020-04-01 23:18:47 +03:00
printf ( " <already printed Object %p> " , & value . as_object ( ) ) ;
2020-03-26 14:26:11 +03:00
return ;
}
2020-04-01 23:18:47 +03:00
seen_objects . set ( & value . as_object ( ) ) ;
2020-03-26 14:26:11 +03:00
}
if ( value . is_array ( ) )
2020-04-01 23:18:47 +03:00
return print_array ( static_cast < const JS : : Array & > ( value . as_object ( ) ) , seen_objects ) ;
2020-04-01 19:53:28 +03:00
2020-03-31 20:43:45 +03:00
if ( value . is_object ( ) ) {
2020-04-01 23:18:47 +03:00
auto & object = value . as_object ( ) ;
if ( object . is_function ( ) )
2020-03-31 20:43:45 +03:00
return print_function ( object , seen_objects ) ;
2020-04-01 23:18:47 +03:00
if ( object . is_date ( ) )
2020-03-31 20:43:45 +03:00
return print_date ( object , seen_objects ) ;
2020-04-02 10:54:15 +03:00
if ( object . is_error ( ) )
return print_error ( object , seen_objects ) ;
2020-03-31 20:43:45 +03:00
return print_object ( object , seen_objects ) ;
}
2020-03-26 14:26:11 +03:00
if ( value . is_string ( ) )
printf ( " \033 [31;1m " ) ;
else if ( value . is_number ( ) )
printf ( " \033 [35;1m " ) ;
else if ( value . is_boolean ( ) )
printf ( " \033 [32;1m " ) ;
2020-03-26 16:54:43 +03:00
else if ( value . is_null ( ) )
printf ( " \033 [33;1m " ) ;
else if ( value . is_undefined ( ) )
2020-03-26 14:26:11 +03:00
printf ( " \033 [34;1m " ) ;
if ( value . is_string ( ) )
putchar ( ' " ' ) ;
printf ( " %s " , value . to_string ( ) . characters ( ) ) ;
if ( value . is_string ( ) )
putchar ( ' " ' ) ;
printf ( " \033 [0m " ) ;
}
static void print ( JS : : Value value )
{
HashTable < JS : : Object * > seen_objects ;
print_value ( value , seen_objects ) ;
putchar ( ' \n ' ) ;
}
2020-04-01 22:20:32 +03:00
bool file_has_shebang ( AK : : ByteBuffer file_contents )
{
if ( file_contents . size ( ) > = 2 & & file_contents [ 0 ] = = ' # ' & & file_contents [ 1 ] = = ' ! ' )
return true ;
return false ;
}
StringView strip_shebang ( AK : : ByteBuffer file_contents )
{
size_t i = 0 ;
for ( i = 2 ; i < file_contents . size ( ) ; + + i ) {
if ( file_contents [ i ] = = ' \n ' )
break ;
}
return StringView ( ( const char * ) file_contents . data ( ) + i , file_contents . size ( ) - i ) ;
}
2020-04-02 18:52:40 +03:00
bool write_to_file ( const StringView & path )
{
int fd = open_with_path_length ( path . characters_without_null_termination ( ) , path . length ( ) , O_WRONLY | O_CREAT | O_TRUNC , 0666 ) ;
for ( size_t i = 0 ; i < repl_statements . size ( ) ; i + + ) {
auto line = repl_statements [ i ] ;
if ( line . length ( ) & & i ! = repl_statements . size ( ) - 1 ) {
ssize_t nwritten = write ( fd , line . characters ( ) , line . length ( ) ) ;
if ( nwritten < 0 ) {
close ( fd ) ;
return false ;
}
}
if ( i ! = repl_statements . size ( ) - 1 ) {
char ch = ' \n ' ;
ssize_t nwritten = write ( fd , & ch , 1 ) ;
if ( nwritten ! = 1 ) {
perror ( " write " ) ;
close ( fd ) ;
return false ;
}
}
}
close ( fd ) ;
return true ;
}
2020-04-01 22:20:32 +03:00
ReplObject : : ReplObject ( )
{
put_native_function ( " exit " , exit_interpreter ) ;
put_native_function ( " help " , repl_help ) ;
2020-04-04 16:13:53 +03:00
put_native_function ( " load " , load_file , 1 ) ;
put_native_function ( " save " , save_to_file , 1 ) ;
2020-04-01 22:20:32 +03:00
}
ReplObject : : ~ ReplObject ( )
{
}
2020-04-02 18:52:40 +03:00
JS : : Value ReplObject : : save_to_file ( JS : : Interpreter & interpreter )
{
if ( ! interpreter . argument_count ( ) )
return JS : : Value ( false ) ;
String save_path = interpreter . argument ( 0 ) . to_string ( ) ;
StringView path = StringView ( save_path . characters ( ) ) ;
if ( write_to_file ( path ) ) {
return JS : : Value ( true ) ;
}
return JS : : Value ( false ) ;
}
2020-04-01 22:20:32 +03:00
JS : : Value ReplObject : : exit_interpreter ( JS : : Interpreter & interpreter )
{
2020-04-01 23:38:59 +03:00
if ( ! interpreter . argument_count ( ) )
2020-04-01 22:20:32 +03:00
exit ( 0 ) ;
2020-04-01 23:38:59 +03:00
int exit_code = interpreter . argument ( 0 ) . to_number ( ) . as_double ( ) ;
2020-04-01 22:20:32 +03:00
exit ( exit_code ) ;
return JS : : js_undefined ( ) ;
}
JS : : Value ReplObject : : repl_help ( JS : : Interpreter & interpreter )
{
StringBuilder help_text ;
help_text . append ( " REPL commands: \n " ) ;
help_text . append ( " exit(code): exit the REPL with specified code. Defaults to 0. \n " ) ;
help_text . append ( " help(): display this menu \n " ) ;
help_text . append ( " load(files): Accepts file names as params to load into running session. For example repl.load( \" js/1.js \" , \" js/2.js \" , \" js/3.js \" ) \n " ) ;
String result = help_text . to_string ( ) ;
2020-04-04 13:57:37 +03:00
return js_string ( interpreter , result ) ;
2020-04-01 22:20:32 +03:00
}
JS : : Value ReplObject : : load_file ( JS : : Interpreter & interpreter )
{
2020-04-01 23:38:59 +03:00
if ( ! interpreter . argument_count ( ) )
2020-04-01 22:20:32 +03:00
return JS : : Value ( false ) ;
2020-04-01 23:38:59 +03:00
for ( auto & file : interpreter . call_frame ( ) . arguments ) {
2020-04-01 22:20:32 +03:00
String file_name = file . as_string ( ) - > string ( ) ;
auto js_file = Core : : File : : construct ( file_name ) ;
if ( ! js_file - > open ( Core : : IODevice : : ReadOnly ) ) {
fprintf ( stderr , " Failed to open %s: %s \n " , file_name . characters ( ) , js_file - > error_string ( ) ) ;
}
auto file_contents = js_file - > read_all ( ) ;
StringView source ;
if ( file_has_shebang ( file_contents ) ) {
source = strip_shebang ( file_contents ) ;
} else {
source = file_contents ;
}
auto program = JS : : Parser ( JS : : Lexer ( source ) ) . parse_program ( ) ;
if ( dump_ast )
program - > dump ( 0 ) ;
2020-04-05 00:45:13 +03:00
interpreter . run ( * program ) ;
print ( interpreter . last_value ( ) ) ;
2020-04-01 22:20:32 +03:00
}
return JS : : Value ( true ) ;
}
2020-03-26 01:10:29 +03:00
void repl ( JS : : Interpreter & interpreter )
{
while ( true ) {
String piece = read_next_piece ( ) ;
if ( piece . is_empty ( ) )
2020-03-31 14:29:42 +03:00
continue ;
2020-04-02 18:52:40 +03:00
repl_statements . append ( piece ) ;
2020-03-26 01:10:29 +03:00
auto program = JS : : Parser ( JS : : Lexer ( piece ) ) . parse_program ( ) ;
if ( dump_ast )
program - > dump ( 0 ) ;
2020-04-05 00:45:13 +03:00
interpreter . run ( * program ) ;
2020-04-02 10:54:15 +03:00
if ( interpreter . exception ( ) ) {
2020-04-02 16:25:08 +03:00
printf ( " Uncaught exception: " ) ;
2020-04-02 10:54:15 +03:00
print ( interpreter . exception ( ) - > value ( ) ) ;
interpreter . clear_exception ( ) ;
} else {
2020-04-05 00:45:13 +03:00
print ( interpreter . last_value ( ) ) ;
2020-04-02 10:54:15 +03:00
}
2020-03-26 01:10:29 +03:00
}
}
2020-03-09 23:58:27 +03:00
2020-04-05 15:49:46 +03:00
JS : : Value assert_impl ( JS : : Interpreter & interpreter )
{
if ( ! interpreter . argument_count ( ) )
return interpreter . throw_exception < JS : : Error > ( " TypeError " , " No arguments specified " ) ;
auto assertion_value = interpreter . argument ( 0 ) ;
if ( ! assertion_value . is_boolean ( ) )
return interpreter . throw_exception < JS : : Error > ( " TypeError " , " The first argument is not a boolean " ) ;
if ( ! assertion_value . to_boolean ( ) )
return interpreter . throw_exception < JS : : Error > ( " AssertionError " , " The assertion failed! " ) ;
return assertion_value ;
}
2020-03-12 12:51:41 +03:00
int main ( int argc , char * * argv )
2020-03-07 21:42:11 +03:00
{
2020-03-16 21:18:46 +03:00
bool gc_on_every_allocation = false ;
2020-03-20 16:52:27 +03:00
bool print_last_result = false ;
2020-04-05 17:03:12 +03:00
bool syntax_highlight = false ;
2020-04-05 15:49:46 +03:00
bool test_mode = false ;
2020-03-12 12:51:41 +03:00
const char * script_path = nullptr ;
Core : : ArgsParser args_parser ;
2020-03-26 10:03:17 +03:00
args_parser . add_option ( dump_ast , " Dump the AST " , " dump-ast " , ' A ' ) ;
2020-03-24 16:45:41 +03:00
args_parser . add_option ( print_last_result , " Print last result " , " print-last-result " , ' l ' ) ;
2020-03-16 21:18:46 +03:00
args_parser . add_option ( gc_on_every_allocation , " GC on every allocation " , " gc-on-every-allocation " , ' g ' ) ;
2020-04-05 17:03:12 +03:00
args_parser . add_option ( syntax_highlight , " Enable live syntax highlighting " , " syntax-highlight " , ' s ' ) ;
2020-04-05 15:49:46 +03:00
args_parser . add_option ( test_mode , " Run the interpretter with added functionality for the test harness " , " test-mode " , ' t ' ) ;
2020-03-26 01:10:29 +03:00
args_parser . add_positional_argument ( script_path , " Path to script file " , " script " , Core : : ArgsParser : : Required : : No ) ;
2020-03-12 12:51:41 +03:00
args_parser . parse ( argc , argv ) ;
2020-03-26 01:10:29 +03:00
if ( script_path = = nullptr ) {
2020-04-01 22:20:32 +03:00
auto interpreter = JS : : Interpreter : : create < ReplObject > ( ) ;
interpreter - > heap ( ) . set_should_collect_on_every_allocation ( gc_on_every_allocation ) ;
interpreter - > global_object ( ) . put ( " global " , & interpreter - > global_object ( ) ) ;
2020-04-05 15:49:46 +03:00
if ( test_mode ) {
interpreter - > global_object ( ) . put_native_function ( " assert " , assert_impl ) ;
}
2020-04-01 22:20:32 +03:00
2020-03-31 20:00:20 +03:00
editor = make < Line : : Editor > ( ) ;
editor - > initialize ( ) ;
2020-04-05 17:03:12 +03:00
if ( syntax_highlight )
editor - > on_display_refresh = [ ] ( Line : : Editor & editor ) {
editor . strip_styles ( ) ;
StringBuilder builder ;
builder . append ( { editor . buffer ( ) . data ( ) , editor . buffer ( ) . size ( ) } ) ;
// FIXME: The lexer returns weird position information without this
builder . append ( " " ) ;
String str = builder . build ( ) ;
JS : : Lexer lexer ( str , false ) ;
for ( JS : : Token token = lexer . next ( ) ; token . type ( ) ! = JS : : TokenType : : Eof ; token = lexer . next ( ) ) {
auto length = token . value ( ) . length ( ) ;
auto start = token . line_column ( ) - 2 ;
auto end = start + length ;
switch ( token . type ( ) ) {
case JS : : TokenType : : Invalid :
case JS : : TokenType : : Eof :
editor . stylize ( { start , end } , { Line : : Style : : Foreground ( Line : : Style : : Color : : Red ) , Line : : Style : : Underline } ) ;
break ;
case JS : : TokenType : : NumericLiteral :
editor . stylize ( { start , end } , { Line : : Style : : Foreground ( Line : : Style : : Color : : Magenta ) } ) ;
break ;
case JS : : TokenType : : StringLiteral :
case JS : : TokenType : : RegexLiteral :
case JS : : TokenType : : UnterminatedStringLiteral :
editor . stylize ( { start , end } , { Line : : Style : : Foreground ( Line : : Style : : Color : : Red ) } ) ;
break ;
case JS : : TokenType : : BracketClose :
case JS : : TokenType : : BracketOpen :
case JS : : TokenType : : Caret :
case JS : : TokenType : : Comma :
case JS : : TokenType : : CurlyClose :
case JS : : TokenType : : CurlyOpen :
case JS : : TokenType : : ParenClose :
case JS : : TokenType : : ParenOpen :
case JS : : TokenType : : Semicolon :
case JS : : TokenType : : Period :
break ;
case JS : : TokenType : : Ampersand :
case JS : : TokenType : : AmpersandEquals :
case JS : : TokenType : : Asterisk :
case JS : : TokenType : : AsteriskAsteriskEquals :
case JS : : TokenType : : AsteriskEquals :
case JS : : TokenType : : DoubleAmpersand :
case JS : : TokenType : : DoubleAsterisk :
case JS : : TokenType : : DoublePipe :
case JS : : TokenType : : DoubleQuestionMark :
case JS : : TokenType : : Equals :
case JS : : TokenType : : EqualsEquals :
case JS : : TokenType : : EqualsEqualsEquals :
case JS : : TokenType : : ExclamationMark :
case JS : : TokenType : : ExclamationMarkEquals :
case JS : : TokenType : : ExclamationMarkEqualsEquals :
case JS : : TokenType : : GreaterThan :
case JS : : TokenType : : GreaterThanEquals :
case JS : : TokenType : : LessThan :
case JS : : TokenType : : LessThanEquals :
case JS : : TokenType : : Minus :
case JS : : TokenType : : MinusEquals :
case JS : : TokenType : : MinusMinus :
case JS : : TokenType : : Percent :
case JS : : TokenType : : PercentEquals :
case JS : : TokenType : : Pipe :
case JS : : TokenType : : PipeEquals :
case JS : : TokenType : : Plus :
case JS : : TokenType : : PlusEquals :
case JS : : TokenType : : PlusPlus :
case JS : : TokenType : : QuestionMark :
case JS : : TokenType : : QuestionMarkPeriod :
case JS : : TokenType : : ShiftLeft :
case JS : : TokenType : : ShiftLeftEquals :
case JS : : TokenType : : ShiftRight :
case JS : : TokenType : : ShiftRightEquals :
case JS : : TokenType : : Slash :
case JS : : TokenType : : SlashEquals :
case JS : : TokenType : : Tilde :
case JS : : TokenType : : UnsignedShiftRight :
case JS : : TokenType : : UnsignedShiftRightEquals :
editor . stylize ( { start , end } , { Line : : Style : : Foreground ( Line : : Style : : Color : : Magenta ) } ) ;
break ;
case JS : : TokenType : : NullLiteral :
editor . stylize ( { start , end } , { Line : : Style : : Foreground ( Line : : Style : : Color : : Yellow ) , Line : : Style : : Bold } ) ;
break ;
case JS : : TokenType : : BoolLiteral :
editor . stylize ( { start , end } , { Line : : Style : : Foreground ( Line : : Style : : Color : : Green ) , Line : : Style : : Bold } ) ;
break ;
case JS : : TokenType : : Class :
case JS : : TokenType : : Const :
case JS : : TokenType : : Delete :
case JS : : TokenType : : Function :
case JS : : TokenType : : In :
case JS : : TokenType : : Instanceof :
case JS : : TokenType : : Interface :
case JS : : TokenType : : Let :
case JS : : TokenType : : New :
case JS : : TokenType : : Typeof :
case JS : : TokenType : : Var :
case JS : : TokenType : : Void :
editor . stylize ( { start , end } , { Line : : Style : : Foreground ( Line : : Style : : Color : : Blue ) , Line : : Style : : Bold } ) ;
break ;
case JS : : TokenType : : Await :
case JS : : TokenType : : Catch :
case JS : : TokenType : : Do :
case JS : : TokenType : : Else :
case JS : : TokenType : : Finally :
case JS : : TokenType : : For :
case JS : : TokenType : : If :
case JS : : TokenType : : Return :
case JS : : TokenType : : Try :
case JS : : TokenType : : While :
case JS : : TokenType : : Yield :
editor . stylize ( { start , end } , { Line : : Style : : Foreground ( Line : : Style : : Color : : Cyan ) , Line : : Style : : Italic } ) ;
break ;
case JS : : TokenType : : Identifier :
default :
break ;
}
}
} ;
2020-04-01 22:04:51 +03:00
repl ( * interpreter ) ;
2020-03-26 01:10:29 +03:00
} else {
2020-04-01 22:20:32 +03:00
auto interpreter = JS : : Interpreter : : create < JS : : GlobalObject > ( ) ;
interpreter - > heap ( ) . set_should_collect_on_every_allocation ( gc_on_every_allocation ) ;
interpreter - > global_object ( ) . put ( " global " , & interpreter - > global_object ( ) ) ;
2020-04-05 15:49:46 +03:00
if ( test_mode ) {
interpreter - > global_object ( ) . put_native_function ( " assert " , assert_impl ) ;
}
2020-04-01 22:20:32 +03:00
2020-03-26 01:10:29 +03:00
auto file = Core : : File : : construct ( script_path ) ;
if ( ! file - > open ( Core : : IODevice : : ReadOnly ) ) {
fprintf ( stderr , " Failed to open %s: %s \n " , script_path , file - > error_string ( ) ) ;
return 1 ;
}
auto file_contents = file - > read_all ( ) ;
StringView source ;
2020-04-01 22:20:32 +03:00
if ( file_has_shebang ( file_contents ) ) {
source = strip_shebang ( file_contents ) ;
2020-03-26 01:10:29 +03:00
} else {
source = file_contents ;
}
auto program = JS : : Parser ( JS : : Lexer ( source ) ) . parse_program ( ) ;
2020-03-12 12:51:41 +03:00
2020-03-26 01:10:29 +03:00
if ( dump_ast )
program - > dump ( 0 ) ;
2020-03-07 21:42:11 +03:00
2020-04-01 22:04:51 +03:00
auto result = interpreter - > run ( * program ) ;
2020-03-07 21:42:11 +03:00
2020-04-02 17:55:37 +03:00
if ( interpreter - > exception ( ) ) {
printf ( " Uncaught exception: " ) ;
print ( interpreter - > exception ( ) - > value ( ) ) ;
interpreter - > clear_exception ( ) ;
2020-04-03 23:52:49 +03:00
return 1 ;
2020-04-02 17:55:37 +03:00
}
2020-04-03 23:52:49 +03:00
if ( print_last_result )
print ( result ) ;
2020-03-26 01:10:29 +03:00
}
2020-03-08 21:59:59 +03:00
2020-03-07 21:42:11 +03:00
return 0 ;
}