├── LICENSE.txt ├── README.md ├── clox ├── clox_diff.patch ├── example.lox ├── failures ├── getc_test.lox ├── jlox ├── jlox_diff.patch ├── lox.lox ├── sum.lox ├── test.py └── test ├── assignment ├── associativity.lox ├── global.lox ├── grouping.lox ├── infix_operator.lox ├── local.lox ├── prefix_operator.lox ├── syntax.lox ├── to_this.lox └── undefined.lox ├── benchmark ├── binary_trees.lox ├── equality.lox ├── fib.lox ├── invocation.lox ├── method_call.lox ├── properties.lox └── string_equality.lox ├── block ├── empty.lox └── scope.lox ├── bool ├── equality.lox └── not.lox ├── call ├── bool.lox ├── nil.lox ├── num.lox ├── object.lox └── string.lox ├── class ├── empty.lox ├── inherit_self.lox ├── inherited_method.lox ├── local_inherit_self.lox ├── local_reference_self.lox └── reference_self.lox ├── closure ├── assign_to_closure.lox ├── assign_to_shadowed_later.lox ├── close_over_function_parameter.lox ├── close_over_later_variable.lox ├── close_over_method_parameter.lox ├── closed_closure_in_function.lox ├── nested_closure.lox ├── open_closure_in_function.lox ├── reference_closure_multiple_times.lox ├── reuse_closure_slot.lox ├── shadow_closure_with_local.lox ├── unused_closure.lox └── unused_later_closure.lox ├── comments ├── line_at_eof.lox ├── only_line_comment.lox ├── only_line_comment_and_line.lox └── unicode.lox ├── constructor ├── empty_file.lox ├── expressions ├── evaluate.lox └── parse.lox ├── field ├── call_function_field.lox ├── call_nonfunction_field.lox ├── get_and_set_method.lox ├── get_on_bool.lox ├── get_on_class.lox ├── get_on_function.lox ├── get_on_nil.lox ├── get_on_num.lox ├── get_on_string.lox ├── many.lox ├── method.lox ├── method_binds_this.lox ├── on_instance.lox ├── set_evaluation_order.lox ├── set_on_bool.lox ├── set_on_class.lox ├── set_on_function.lox ├── set_on_nil.lox ├── set_on_num.lox ├── set_on_string.lox └── undefined.lox ├── for ├── class_in_body.lox ├── closure_in_body.lox ├── fun_in_body.lox ├── return_closure.lox ├── return_inside.lox ├── scope.lox ├── statement_condition.lox ├── statement_increment.lox ├── statement_initializer.lox ├── syntax.lox └── var_in_body.lox ├── function ├── body_must_be_block.lox ├── empty_body.lox ├── extra_arguments.lox ├── local_mutual_recursion.lox ├── local_recursion.lox ├── missing_arguments.lox ├── missing_comma_in_parameters.lox ├── mutual_recursion.lox ├── parameters.lox ├── print.lox ├── recursion.lox ├── too_many_arguments.lox └── too_many_parameters.lox ├── if ├── class_in_else.lox ├── class_in_then.lox ├── dangling_else.lox ├── else.lox ├── fun_in_else.lox ├── fun_in_then.lox ├── if.lox ├── truth.lox ├── var_in_else.lox └── var_in_then.lox ├── inheritance ├── inherit_from_function.lox ├── inherit_from_nil.lox ├── inherit_from_number.lox ├── inherit_methods.lox ├── parenthesized_superclass.lox └── set_fields_from_base_class.lox ├── limit ├── loop_too_large.lox ├── no_reuse_constants.lox ├── stack_overflow.lox ├── too_many_constants.lox ├── too_many_locals.lox └── too_many_upvalues.lox ├── logical_operator ├── and.lox ├── and_truth.lox ├── or.lox └── or_truth.lox ├── method ├── arity.lox ├── empty_block.lox ├── extra_arguments.lox ├── missing_arguments.lox ├── not_found.lox ├── refer_to_name.lox ├── too_many_arguments.lox └── too_many_parameters.lox ├── nil └── literal.lox ├── number ├── decimal_point_at_eof.lox ├── leading_dot.lox ├── literals.lox └── trailing_dot.lox ├── operator ├── add.lox ├── add_bool_nil.lox ├── add_bool_num.lox ├── add_bool_string.lox ├── add_nil_nil.lox ├── add_num_nil.lox ├── add_string_nil.lox ├── comparison.lox ├── divide.lox ├── divide_nonnum_num.lox ├── divide_num_nonnum.lox ├── equals.lox ├── equals_class.lox ├── equals_method.lox ├── greater_nonnum_num.lox ├── greater_num_nonnum.lox ├── greater_or_equal_nonnum_num.lox ├── greater_or_equal_num_nonnum.lox ├── less_nonnum_num.lox ├── less_num_nonnum.lox ├── less_or_equal_nonnum_num.lox ├── less_or_equal_num_nonnum.lox ├── multiply.lox ├── multiply_nonnum_num.lox ├── multiply_num_nonnum.lox ├── negate.lox ├── negate_nonnum.lox ├── not.lox ├── not_class.lox ├── not_equals.lox ├── subtract.lox ├── subtract_nonnum_num.lox └── subtract_num_nonnum.lox ├── precedence.lox ├── print └── missing_argument.lox ├── regression └── 40.lox ├── return ├── after_else.lox ├── after_if.lox ├── after_while.lox ├── at_top_level.lox ├── in_function.lox ├── in_method.lox └── return_nil_if_no_value.lox ├── scanning ├── identifiers.lox ├── keywords.lox ├── numbers.lox ├── punctuators.lox ├── strings.lox └── whitespace.lox ├── string ├── error_after_multiline.lox ├── literals.lox ├── multiline.lox └── unterminated.lox ├── super ├── bound_method.lox ├── call_other_method.lox ├── call_same_method.lox ├── closure.lox ├── constructor.lox ├── extra_arguments.lox ├── indirectly_inherited.lox ├── missing_arguments.lox ├── no_superclass_bind.lox ├── no_superclass_call.lox ├── no_superclass_method.lox ├── parenthesized.lox ├── reassign_superclass.lox ├── super_at_top_level.lox ├── super_in_closure_in_inherited_method.lox ├── super_in_inherited_method.lox ├── super_in_top_level_function.lox ├── super_without_dot.lox ├── super_without_name.lox └── this_in_superclass_method.lox ├── this ├── closure.lox ├── nested_class.lox ├── nested_closure.lox ├── this_at_top_level.lox ├── this_in_method.lox └── this_in_top_level_function.lox ├── unexpected_character.lox ├── variable ├── collide_with_parameter.lox ├── duplicate_local.lox ├── duplicate_parameter.lox ├── early_bound.lox ├── in_middle_of_block.lox ├── in_nested_block.lox ├── local_from_method.lox ├── redeclare_global.lox ├── redefine_global.lox ├── scope_reuse_in_different_blocks.lox ├── shadow_and_local.lox ├── shadow_global.lox ├── shadow_local.lox ├── undefined_global.lox ├── undefined_local.lox ├── uninitialized.lox ├── unreached_undefined.lox ├── use_false_as_var.lox ├── use_global_in_initializer.lox ├── use_local_in_initializer.lox ├── use_nil_as_var.lox └── use_this_as_var.lox └── while ├── class_in_body.lox ├── closure_in_body.lox ├── fun_in_body.lox ├── return_closure.lox ├── return_inside.lox ├── syntax.lox └── var_in_body.lox /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ben Hoyt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | LoxLox 3 | ====== 4 | 5 | LoxLox is an interpreter for [Crafting Interpreters'](http://www.craftinginterpreters.com/) [Lox](http://www.craftinginterpreters.com/the-lox-language.html) language written in ... Lox. 6 | 7 | Below are a few notes about running LoxLox, but you can [**read more about LoxLox here**](https://benhoyt.com/writings/loxlox/). 8 | 9 | 10 | ## How to run LoxLox 11 | 12 | First clone the LoxLox repo as well as the Crafting Interpreters one: 13 | 14 | ``` 15 | $ git clone https://github.com/benhoyt/loxlox 16 | $ git clone https://github.com/munificent/craftinginterpreters 17 | ``` 18 | 19 | ### JLox 20 | 21 | Then patch the Crafting Interpreters repo to add the required builtins to JLox (`getc`, `chr`, etc) and build JLox: 22 | 23 | ``` 24 | $ cd craftinginterpreters 25 | $ git apply ../loxlox/jlox_diff.patch 26 | $ make jlox 27 | $ cd ../loxlox 28 | ``` 29 | 30 | Now you're ready to run LoxLox (input is passed to LoxLox on stdin): 31 | 32 | ``` 33 | $ 34 | $ ./jlox lox.lox < example.lox 35 | 1 36 | 4 37 | 9 38 | 16 39 | Waddles quacks 40 | 6 41 | 105 42 | $ ./jlox lox.lox < sum.lox 43 | 4.99995E9 44 | $ echo 'print "Hello world!";' | ./jlox lox.lox 45 | Hello world! 46 | ``` 47 | 48 | ### CLox 49 | 50 | Thanks to [gloria-mundi](https://github.com/gloria-mundi)'s [patch](https://github.com/benhoyt/loxlox/blob/master/clox_diff.patch), you can now even run LoxLox under CLox. Patch the Crafting Interpreters repo in much the same way as above: 51 | 52 | ``` 53 | $ cd ../craftinginterpreters 54 | $ git apply ../loxlox/clox_diff.patch 55 | $ make clox 56 | $ cd ../loxlox 57 | ``` 58 | 59 | You should now be able to run the examples the same way as above, but replace `./jlox` with `./clox`. It's about 6x as fast -- see the [benchmarks](https://github.com/benhoyt/loxlox/pull/3)! 60 | 61 | 62 | ## Running the tests 63 | 64 | To run the Lox test suite under LoxLox, use this command: 65 | 66 | ``` 67 | $ python3 test.py 68 | ``` 69 | 70 | Note that several tests will fail. That's expected -- the code works; the remaining failures are only from differences in the runtime error messages between JLox and LoxLox. 71 | 72 | To run the tests and diff against the git-committed failures file (should be no diffs): 73 | 74 | ``` 75 | $ python3 test.py > failures 76 | $ git diff failures 77 | ``` 78 | 79 | 80 | ## Contact me 81 | 82 | [Contact me](https://benhoyt.com/) if you have any feedback or suggestions. And if you get LoxLox to run under LoxLox ... mind blown. 83 | -------------------------------------------------------------------------------- /clox: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ../craftinginterpreters/clox $@ 3 | -------------------------------------------------------------------------------- /clox_diff.patch: -------------------------------------------------------------------------------- 1 | diff --git a/c/compiler.c b/c/compiler.c 2 | index 463bea79..a170ff52 100644 3 | --- a/c/compiler.c 4 | +++ b/c/compiler.c 5 | @@ -262,19 +262,24 @@ static void emitReturn() { 6 | } 7 | //< Compiling Expressions emit-return 8 | //> Compiling Expressions make-constant 9 | -static uint8_t makeConstant(Value value) { 10 | +static int makeConstant(Value value) { 11 | int constant = addConstant(currentChunk(), value); 12 | - if (constant > UINT8_MAX) { 13 | + if (constant > 0x7fff) { 14 | error("Too many constants in one chunk."); 15 | return 0; 16 | } 17 | 18 | - return (uint8_t)constant; 19 | + return constant; 20 | } 21 | //< Compiling Expressions make-constant 22 | +static void emitConstantIndex(int index) { 23 | + if (index < 0x80) emitByte(index); 24 | + else emitBytes(index >> 8 | 0x80, index & 0xff); 25 | +} 26 | //> Compiling Expressions emit-constant 27 | static void emitConstant(Value value) { 28 | - emitBytes(OP_CONSTANT, makeConstant(value)); 29 | + emitByte(OP_CONSTANT); 30 | + emitConstantIndex(makeConstant(value)); 31 | } 32 | //< Compiling Expressions emit-constant 33 | //> Jumping Back and Forth patch-jump 34 | @@ -411,7 +416,7 @@ static void parsePrecedence(Precedence precedence); 35 | 36 | //< Compiling Expressions forward-declarations 37 | //> Global Variables identifier-constant 38 | -static uint8_t identifierConstant(Token* name) { 39 | +static int identifierConstant(Token* name) { 40 | return makeConstant(OBJ_VAL(copyString(name->start, 41 | name->length))); 42 | } 43 | @@ -531,7 +536,7 @@ static void declareVariable() { 44 | } 45 | //< Local Variables declare-variable 46 | //> Global Variables parse-variable 47 | -static uint8_t parseVariable(const char* errorMessage) { 48 | +static int parseVariable(const char* errorMessage) { 49 | consume(TOKEN_IDENTIFIER, errorMessage); 50 | //> Local Variables parse-local 51 | 52 | @@ -552,7 +557,7 @@ static void markInitialized() { 53 | } 54 | //< Local Variables mark-initialized 55 | //> Global Variables define-variable 56 | -static void defineVariable(uint8_t global) { 57 | +static void defineVariable(int global) { 58 | //> Local Variables define-variable 59 | if (current->scopeDepth > 0) { 60 | //> define-local 61 | @@ -562,7 +567,8 @@ static void defineVariable(uint8_t global) { 62 | } 63 | 64 | //< Local Variables define-variable 65 | - emitBytes(OP_DEFINE_GLOBAL, global); 66 | + emitByte(OP_DEFINE_GLOBAL); 67 | + emitConstantIndex(global); 68 | } 69 | //< Global Variables define-variable 70 | //> Calls and Functions argument-list 71 | @@ -630,19 +636,22 @@ static void call(bool canAssign) { 72 | //> Classes and Instances compile-dot 73 | static void dot(bool canAssign) { 74 | consume(TOKEN_IDENTIFIER, "Expect property name after '.'."); 75 | - uint8_t name = identifierConstant(&parser.previous); 76 | + int name = identifierConstant(&parser.previous); 77 | 78 | if (canAssign && match(TOKEN_EQUAL)) { 79 | expression(); 80 | - emitBytes(OP_SET_PROPERTY, name); 81 | + emitByte(OP_SET_PROPERTY); 82 | + emitConstantIndex(name); 83 | //> Methods and Initializers parse-call 84 | } else if (match(TOKEN_LEFT_PAREN)) { 85 | uint8_t argCount = argumentList(); 86 | - emitBytes(OP_INVOKE, name); 87 | + emitByte(OP_INVOKE); 88 | + emitConstantIndex(name); 89 | emitByte(argCount); 90 | //< Methods and Initializers parse-call 91 | } else { 92 | - emitBytes(OP_GET_PROPERTY, name); 93 | + emitByte(OP_GET_PROPERTY); 94 | + emitConstantIndex(name); 95 | } 96 | } 97 | //< Classes and Instances compile-dot 98 | @@ -754,14 +763,18 @@ static void namedVariable(Token name, bool canAssign) { 99 | emitBytes(OP_SET_GLOBAL, arg); 100 | */ 101 | //> Local Variables emit-set 102 | - emitBytes(setOp, (uint8_t)arg); 103 | + emitByte(setOp); 104 | + if (setOp == OP_SET_GLOBAL) emitConstantIndex(arg); 105 | + else emitByte(arg); 106 | //< Local Variables emit-set 107 | } else { 108 | /* Global Variables named-variable < Local Variables emit-get 109 | emitBytes(OP_GET_GLOBAL, arg); 110 | */ 111 | //> Local Variables emit-get 112 | - emitBytes(getOp, (uint8_t)arg); 113 | + emitByte(getOp); 114 | + if (getOp == OP_GET_GLOBAL) emitConstantIndex(arg); 115 | + else emitByte(arg); 116 | //< Local Variables emit-get 117 | } 118 | //< named-variable 119 | @@ -797,7 +810,7 @@ static void super_(bool canAssign) { 120 | //< super-errors 121 | consume(TOKEN_DOT, "Expect '.' after 'super'."); 122 | consume(TOKEN_IDENTIFIER, "Expect superclass method name."); 123 | - uint8_t name = identifierConstant(&parser.previous); 124 | + int name = identifierConstant(&parser.previous); 125 | //> super-get 126 | 127 | namedVariable(syntheticToken("this"), false); 128 | @@ -810,11 +823,13 @@ static void super_(bool canAssign) { 129 | if (match(TOKEN_LEFT_PAREN)) { 130 | uint8_t argCount = argumentList(); 131 | namedVariable(syntheticToken("super"), false); 132 | - emitBytes(OP_SUPER_INVOKE, name); 133 | + emitByte(OP_SUPER_INVOKE); 134 | + emitConstantIndex(name); 135 | emitByte(argCount); 136 | } else { 137 | namedVariable(syntheticToken("super"), false); 138 | - emitBytes(OP_GET_SUPER, name); 139 | + emitByte(OP_GET_SUPER); 140 | + emitConstantIndex(name); 141 | } 142 | //< super-invoke 143 | } 144 | @@ -1056,7 +1071,7 @@ static void function(FunctionType type) { 145 | if (current->function->arity > 255) { 146 | errorAtCurrent("Can't have more than 255 parameters."); 147 | } 148 | - uint8_t constant = parseVariable("Expect parameter name."); 149 | + int constant = parseVariable("Expect parameter name."); 150 | defineVariable(constant); 151 | } while (match(TOKEN_COMMA)); 152 | } 153 | @@ -1070,7 +1085,8 @@ static void function(FunctionType type) { 154 | emitBytes(OP_CONSTANT, makeConstant(OBJ_VAL(function))); 155 | */ 156 | //> Closures emit-closure 157 | - emitBytes(OP_CLOSURE, makeConstant(OBJ_VAL(function))); 158 | + emitByte(OP_CLOSURE); 159 | + emitConstantIndex(makeConstant(OBJ_VAL(function))); 160 | //< Closures emit-closure 161 | //> Closures capture-upvalues 162 | 163 | @@ -1084,7 +1100,7 @@ static void function(FunctionType type) { 164 | //> Methods and Initializers method 165 | static void method() { 166 | consume(TOKEN_IDENTIFIER, "Expect method name."); 167 | - uint8_t constant = identifierConstant(&parser.previous); 168 | + int constant = identifierConstant(&parser.previous); 169 | //> method-body 170 | 171 | //< method-body 172 | @@ -1104,7 +1120,8 @@ static void method() { 173 | //> method-body 174 | function(type); 175 | //< method-body 176 | - emitBytes(OP_METHOD, constant); 177 | + emitByte(OP_METHOD); 178 | + emitConstantIndex(constant); 179 | } 180 | //< Methods and Initializers method 181 | //> Classes and Instances class-declaration 182 | @@ -1113,10 +1130,11 @@ static void classDeclaration() { 183 | //> Methods and Initializers class-name 184 | Token className = parser.previous; 185 | //< Methods and Initializers class-name 186 | - uint8_t nameConstant = identifierConstant(&parser.previous); 187 | + int nameConstant = identifierConstant(&parser.previous); 188 | declareVariable(); 189 | 190 | - emitBytes(OP_CLASS, nameConstant); 191 | + emitByte(OP_CLASS); 192 | + emitConstantIndex(nameConstant); 193 | defineVariable(nameConstant); 194 | 195 | //> Methods and Initializers create-class-compiler 196 | @@ -1180,7 +1198,7 @@ static void classDeclaration() { 197 | //< Classes and Instances class-declaration 198 | //> Calls and Functions fun-declaration 199 | static void funDeclaration() { 200 | - uint8_t global = parseVariable("Expect function name."); 201 | + int global = parseVariable("Expect function name."); 202 | markInitialized(); 203 | function(TYPE_FUNCTION); 204 | defineVariable(global); 205 | @@ -1188,7 +1206,7 @@ static void funDeclaration() { 206 | //< Calls and Functions fun-declaration 207 | //> Global Variables var-declaration 208 | static void varDeclaration() { 209 | - uint8_t global = parseVariable("Expect variable name."); 210 | + int global = parseVariable("Expect variable name."); 211 | 212 | if (match(TOKEN_EQUAL)) { 213 | expression(); 214 | diff --git a/c/debug.c b/c/debug.c 215 | index 488e22d1..26b1df2a 100644 216 | --- a/c/debug.c 217 | +++ b/c/debug.c 218 | @@ -16,27 +16,34 @@ void disassembleChunk(Chunk* chunk, const char* name) { 219 | offset = disassembleInstruction(chunk, offset); 220 | } 221 | } 222 | +static int readConstantIndex(Chunk *chunk, int *offset) { 223 | + int constant = chunk->code[(*offset)++]; 224 | + if (!(constant & 0x80)) return constant; 225 | + return (constant & 0x7f) << 8 | chunk->code[(*offset)++]; 226 | +} 227 | //> constant-instruction 228 | static int constantInstruction(const char* name, Chunk* chunk, 229 | int offset) { 230 | - uint8_t constant = chunk->code[offset + 1]; 231 | + int newOffset = offset + 1; 232 | + int constant = readConstantIndex(chunk, &newOffset); 233 | printf("%-16s %4d '", name, constant); 234 | printValue(chunk->constants.values[constant]); 235 | printf("'\n"); 236 | //> return-after-operand 237 | - return offset + 2; 238 | + return newOffset; 239 | //< return-after-operand 240 | } 241 | //< constant-instruction 242 | //> Methods and Initializers invoke-instruction 243 | static int invokeInstruction(const char* name, Chunk* chunk, 244 | int offset) { 245 | - uint8_t constant = chunk->code[offset + 1]; 246 | - uint8_t argCount = chunk->code[offset + 2]; 247 | + int argOffset = offset + 1; 248 | + int constant = readConstantIndex(chunk, &argOffset); 249 | + uint8_t argCount = chunk->code[argOffset]; 250 | printf("%-16s (%d args) %4d '", name, argCount, constant); 251 | printValue(chunk->constants.values[constant]); 252 | printf("'\n"); 253 | - return offset + 3; 254 | + return argOffset + 1; 255 | } 256 | //< Methods and Initializers invoke-instruction 257 | //> simple-instruction 258 | @@ -183,7 +190,7 @@ int disassembleInstruction(Chunk* chunk, int offset) { 259 | //> Closures disassemble-closure 260 | case OP_CLOSURE: { 261 | offset++; 262 | - uint8_t constant = chunk->code[offset++]; 263 | + int constant = readConstantIndex(chunk, &offset); 264 | printf("%-16s %4d ", "OP_CLOSURE", constant); 265 | printValue(chunk->constants.values[constant]); 266 | printf("\n"); 267 | diff --git a/c/vm.c b/c/vm.c 268 | index fde80702..139895e8 100644 269 | --- a/c/vm.c 270 | +++ b/c/vm.c 271 | @@ -4,6 +4,7 @@ 272 | //< Types of Values include-stdarg 273 | //> vm-include-stdio 274 | #include 275 | +#include 276 | //> Strings vm-include-string 277 | #include 278 | //< Strings vm-include-string 279 | @@ -31,6 +32,27 @@ static Value clockNative(int argCount, Value* args) { 280 | return NUMBER_VAL((double)clock() / CLOCKS_PER_SEC); 281 | } 282 | //< Calls and Functions clock-native 283 | +static Value getcNative(int argCount, Value* args) { 284 | + int res = getchar(); 285 | + if (res == EOF) res = -1; 286 | + return NUMBER_VAL((double)res); 287 | +} 288 | +static Value chrNative(int argCount, Value* args) { 289 | + if (argCount != 1 || !IS_NUMBER(args[0])) return NIL_VAL; 290 | + char *s = ALLOCATE(char, 2); 291 | + s[0] = (char) AS_NUMBER(args[0]); 292 | + s[1] = '\0'; 293 | + return OBJ_VAL(takeString(s, 1)); 294 | +} 295 | +static Value exitNative(int argCount, Value* args) { 296 | + if (argCount != 1 || !IS_NUMBER(args[0])) return NIL_VAL; 297 | + exit((int) AS_NUMBER(args[0])); 298 | +} 299 | +static Value printErrorNative(int argCount, Value* args) { 300 | + if (argCount != 1 || !IS_STRING(args[0])) return NIL_VAL; 301 | + fprintf(stderr, "%s\n", AS_CSTRING(args[0])); 302 | + return NIL_VAL; 303 | +} 304 | //> reset-stack 305 | static void resetStack() { 306 | vm.stackTop = vm.stack; 307 | @@ -129,6 +151,10 @@ void initVM() { 308 | //> Calls and Functions define-native-clock 309 | 310 | defineNative("clock", clockNative); 311 | + defineNative("getc", getcNative); 312 | + defineNative("chr", chrNative); 313 | + defineNative("exit", exitNative); 314 | + defineNative("print_error", printErrorNative); 315 | //< Calls and Functions define-native-clock 316 | } 317 | 318 | @@ -418,7 +444,9 @@ static InterpretResult run() { 319 | */ 320 | //> Closures read-constant 321 | #define READ_CONSTANT() \ 322 | - (frame->closure->function->chunk.constants.values[READ_BYTE()]) 323 | + (frame->closure->function->chunk.constants.values[ \ 324 | + *frame->ip & 0x80 ? READ_SHORT() & 0x7fff : READ_BYTE() \ 325 | + ]) 326 | //< Closures read-constant 327 | 328 | //< Calls and Functions run 329 | diff --git a/c/vm.h b/c/vm.h 330 | index c1804516..edbbd977 100644 331 | --- a/c/vm.h 332 | +++ b/c/vm.h 333 | @@ -21,7 +21,7 @@ 334 | #define STACK_MAX 256 335 | */ 336 | //> Calls and Functions frame-max 337 | -#define FRAMES_MAX 64 338 | +#define FRAMES_MAX 128 339 | #define STACK_MAX (FRAMES_MAX * UINT8_COUNT) 340 | //< Calls and Functions frame-max 341 | //> Calls and Functions call-frame 342 | -------------------------------------------------------------------------------- /example.lox: -------------------------------------------------------------------------------- 1 | for (var i = 1; i < 5; i = i + 1) { 2 | print i * i; 3 | } 4 | 5 | class Duck { 6 | init(name) { 7 | this.name = name; 8 | } 9 | 10 | quack() { 11 | print this.name + " quacks"; 12 | } 13 | } 14 | 15 | var duck = Duck("Waddles"); 16 | duck.quack(); 17 | 18 | fun make_adder(n) { 19 | fun adder(i) { 20 | return n + i; 21 | } 22 | return adder; 23 | } 24 | var add5 = make_adder(5); 25 | print add5(1); 26 | print add5(100); 27 | -------------------------------------------------------------------------------- /failures: -------------------------------------------------------------------------------- 1 | 2 | PASS: test/assignment/associativity.lox 3 | PASS: test/assignment/global.lox 4 | PASS: test/assignment/grouping.lox 5 | PASS: test/assignment/infix_operator.lox 6 | PASS: test/assignment/local.lox 7 | PASS: test/assignment/prefix_operator.lox 8 | PASS: test/assignment/syntax.lox 9 | PASS: test/assignment/to_this.lox 10 | PASS: test/assignment/undefined.lox 11 | PASS: test/block/empty.lox 12 | PASS: test/block/scope.lox 13 | PASS: test/bool/equality.lox 14 | PASS: test/bool/not.lox 15 | FAIL: test/call/bool.lox 16 | Expected runtime error "Can only call functions and classes." and got: 17 | Only instances have properties. 18 | 19 | FAIL: test/call/nil.lox 20 | Expected runtime error "Can only call functions and classes." and got: 21 | Only instances have properties. 22 | 23 | FAIL: test/call/num.lox 24 | Expected runtime error "Can only call functions and classes." and got: 25 | Only instances have properties. 26 | 27 | FAIL: test/call/object.lox 28 | Expected runtime error "Can only call functions and classes." and got: 29 | Undefined property 'arity'. 30 | 31 | FAIL: test/call/string.lox 32 | Expected runtime error "Can only call functions and classes." and got: 33 | Only instances have properties. 34 | 35 | FAIL: test/class/empty.lox 36 | Expected output "Foo" on line 3 and got "LoxClass instance". 37 | 38 | PASS: test/class/inherit_self.lox 39 | PASS: test/class/inherited_method.lox 40 | PASS: test/class/local_inherit_self.lox 41 | FAIL: test/class/local_reference_self.lox 42 | Expected output "Foo" on line 7 and got "LoxClass instance". 43 | 44 | FAIL: test/class/reference_self.lox 45 | Expected output "Foo" on line 8 and got "LoxClass instance". 46 | 47 | PASS: test/closure/assign_to_closure.lox 48 | PASS: test/closure/assign_to_shadowed_later.lox 49 | PASS: test/closure/close_over_function_parameter.lox 50 | PASS: test/closure/close_over_later_variable.lox 51 | PASS: test/closure/close_over_method_parameter.lox 52 | PASS: test/closure/closed_closure_in_function.lox 53 | PASS: test/closure/nested_closure.lox 54 | PASS: test/closure/open_closure_in_function.lox 55 | PASS: test/closure/reference_closure_multiple_times.lox 56 | PASS: test/closure/reuse_closure_slot.lox 57 | PASS: test/closure/shadow_closure_with_local.lox 58 | PASS: test/closure/unused_closure.lox 59 | PASS: test/closure/unused_later_closure.lox 60 | PASS: test/comments/line_at_eof.lox 61 | PASS: test/comments/only_line_comment.lox 62 | PASS: test/comments/only_line_comment_and_line.lox 63 | PASS: test/comments/unicode.lox 64 | PASS: test/constructor/arguments.lox 65 | FAIL: test/constructor/call_init_early_return.lox 66 | Expected output "Foo instance" on line 11 and got "LoxInstance instance". 67 | 68 | FAIL: test/constructor/call_init_explicitly.lox 69 | Expected output "Foo instance" on line 12 and got "LoxInstance instance". 70 | 71 | FAIL: test/constructor/default.lox 72 | Expected output "Foo instance" on line 4 and got "LoxInstance instance". 73 | 74 | PASS: test/constructor/default_arguments.lox 75 | FAIL: test/constructor/early_return.lox 76 | Expected output "Foo instance" on line 10 and got "LoxInstance instance". 77 | 78 | PASS: test/constructor/extra_arguments.lox 79 | PASS: test/constructor/init_not_method.lox 80 | PASS: test/constructor/missing_arguments.lox 81 | FAIL: test/constructor/return_in_nested_function.lox 82 | Expected output "Foo instance" on line 10 and got "LoxInstance instance". 83 | 84 | PASS: test/constructor/return_value.lox 85 | PASS: test/empty_file.lox 86 | PASS: test/field/call_function_field.lox 87 | FAIL: test/field/call_nonfunction_field.lox 88 | Expected runtime error "Can only call functions and classes." and got: 89 | Only instances have properties. 90 | 91 | PASS: test/field/get_and_set_method.lox 92 | PASS: test/field/get_on_bool.lox 93 | FAIL: test/field/get_on_class.lox 94 | Expected runtime error "Only instances have properties." and got: 95 | Undefined property 'get'. 96 | 97 | FAIL: test/field/get_on_function.lox 98 | Expected runtime error "Only instances have properties." and got: 99 | Undefined property 'get'. 100 | 101 | PASS: test/field/get_on_nil.lox 102 | PASS: test/field/get_on_num.lox 103 | PASS: test/field/get_on_string.lox 104 | PASS: test/field/many.lox 105 | PASS: test/field/method.lox 106 | PASS: test/field/method_binds_this.lox 107 | PASS: test/field/on_instance.lox 108 | PASS: test/field/set_evaluation_order.lox 109 | FAIL: test/field/set_on_bool.lox 110 | Expected runtime error "Only instances have fields." and got: 111 | Only instances have properties. 112 | 113 | FAIL: test/field/set_on_class.lox 114 | Expected runtime error "Only instances have fields." and got: 115 | Undefined property 'set'. 116 | 117 | FAIL: test/field/set_on_function.lox 118 | Expected runtime error "Only instances have fields." and got: 119 | Undefined property 'set'. 120 | 121 | FAIL: test/field/set_on_nil.lox 122 | Expected runtime error "Only instances have fields." and got: 123 | Only instances have properties. 124 | 125 | FAIL: test/field/set_on_num.lox 126 | Expected runtime error "Only instances have fields." and got: 127 | Only instances have properties. 128 | 129 | FAIL: test/field/set_on_string.lox 130 | Expected runtime error "Only instances have fields." and got: 131 | Only instances have properties. 132 | 133 | PASS: test/field/undefined.lox 134 | PASS: test/for/class_in_body.lox 135 | PASS: test/for/closure_in_body.lox 136 | PASS: test/for/fun_in_body.lox 137 | PASS: test/for/return_closure.lox 138 | PASS: test/for/return_inside.lox 139 | PASS: test/for/scope.lox 140 | PASS: test/for/statement_condition.lox 141 | PASS: test/for/statement_increment.lox 142 | PASS: test/for/statement_initializer.lox 143 | PASS: test/for/syntax.lox 144 | PASS: test/for/var_in_body.lox 145 | PASS: test/function/body_must_be_block.lox 146 | PASS: test/function/empty_body.lox 147 | PASS: test/function/extra_arguments.lox 148 | PASS: test/function/local_mutual_recursion.lox 149 | PASS: test/function/local_recursion.lox 150 | PASS: test/function/missing_arguments.lox 151 | PASS: test/function/missing_comma_in_parameters.lox 152 | PASS: test/function/mutual_recursion.lox 153 | PASS: test/function/parameters.lox 154 | FAIL: test/function/print.lox 155 | Expected output "" on line 2 and got "LoxFunction instance". 156 | Expected output "" on line 4 and got "Builtin0 instance". 157 | 158 | PASS: test/function/recursion.lox 159 | PASS: test/function/too_many_arguments.lox 160 | PASS: test/function/too_many_parameters.lox 161 | PASS: test/if/class_in_else.lox 162 | PASS: test/if/class_in_then.lox 163 | PASS: test/if/dangling_else.lox 164 | PASS: test/if/else.lox 165 | PASS: test/if/fun_in_else.lox 166 | PASS: test/if/fun_in_then.lox 167 | PASS: test/if/if.lox 168 | PASS: test/if/truth.lox 169 | PASS: test/if/var_in_else.lox 170 | PASS: test/if/var_in_then.lox 171 | FAIL: test/inheritance/inherit_from_function.lox 172 | Expected runtime error "Superclass must be a class." and got: 173 | Undefined property 'findMethod'. 174 | 175 | FAIL: test/inheritance/inherit_from_nil.lox 176 | Expected runtime error "Superclass must be a class." and got: 177 | Only instances have properties. 178 | 179 | FAIL: test/inheritance/inherit_from_number.lox 180 | Expected runtime error "Superclass must be a class." and got: 181 | Only instances have properties. 182 | 183 | PASS: test/inheritance/inherit_methods.lox 184 | PASS: test/inheritance/parenthesized_superclass.lox 185 | PASS: test/inheritance/set_fields_from_base_class.lox 186 | PASS: test/logical_operator/and.lox 187 | PASS: test/logical_operator/and_truth.lox 188 | PASS: test/logical_operator/or.lox 189 | PASS: test/logical_operator/or_truth.lox 190 | PASS: test/method/arity.lox 191 | PASS: test/method/empty_block.lox 192 | PASS: test/method/extra_arguments.lox 193 | PASS: test/method/missing_arguments.lox 194 | PASS: test/method/not_found.lox 195 | PASS: test/method/refer_to_name.lox 196 | PASS: test/method/too_many_arguments.lox 197 | PASS: test/method/too_many_parameters.lox 198 | PASS: test/nil/literal.lox 199 | PASS: test/number/decimal_point_at_eof.lox 200 | PASS: test/number/leading_dot.lox 201 | PASS: test/number/literals.lox 202 | PASS: test/number/trailing_dot.lox 203 | PASS: test/operator/add.lox 204 | PASS: test/operator/add_bool_nil.lox 205 | PASS: test/operator/add_bool_num.lox 206 | PASS: test/operator/add_bool_string.lox 207 | PASS: test/operator/add_nil_nil.lox 208 | PASS: test/operator/add_num_nil.lox 209 | PASS: test/operator/add_string_nil.lox 210 | PASS: test/operator/comparison.lox 211 | PASS: test/operator/divide.lox 212 | PASS: test/operator/divide_nonnum_num.lox 213 | PASS: test/operator/divide_num_nonnum.lox 214 | PASS: test/operator/equals.lox 215 | PASS: test/operator/equals_class.lox 216 | PASS: test/operator/equals_method.lox 217 | PASS: test/operator/greater_nonnum_num.lox 218 | PASS: test/operator/greater_num_nonnum.lox 219 | PASS: test/operator/greater_or_equal_nonnum_num.lox 220 | PASS: test/operator/greater_or_equal_num_nonnum.lox 221 | PASS: test/operator/less_nonnum_num.lox 222 | PASS: test/operator/less_num_nonnum.lox 223 | PASS: test/operator/less_or_equal_nonnum_num.lox 224 | PASS: test/operator/less_or_equal_num_nonnum.lox 225 | PASS: test/operator/multiply.lox 226 | PASS: test/operator/multiply_nonnum_num.lox 227 | PASS: test/operator/multiply_num_nonnum.lox 228 | PASS: test/operator/negate.lox 229 | PASS: test/operator/negate_nonnum.lox 230 | PASS: test/operator/not.lox 231 | PASS: test/operator/not_class.lox 232 | PASS: test/operator/not_equals.lox 233 | PASS: test/operator/subtract.lox 234 | PASS: test/operator/subtract_nonnum_num.lox 235 | PASS: test/operator/subtract_num_nonnum.lox 236 | PASS: test/precedence.lox 237 | PASS: test/print/missing_argument.lox 238 | PASS: test/regression/40.lox 239 | PASS: test/return/after_else.lox 240 | PASS: test/return/after_if.lox 241 | PASS: test/return/after_while.lox 242 | PASS: test/return/at_top_level.lox 243 | PASS: test/return/in_function.lox 244 | PASS: test/return/in_method.lox 245 | PASS: test/return/return_nil_if_no_value.lox 246 | PASS: test/string/error_after_multiline.lox 247 | PASS: test/string/literals.lox 248 | PASS: test/string/multiline.lox 249 | PASS: test/string/unterminated.lox 250 | PASS: test/super/bound_method.lox 251 | PASS: test/super/call_other_method.lox 252 | PASS: test/super/call_same_method.lox 253 | PASS: test/super/closure.lox 254 | PASS: test/super/constructor.lox 255 | PASS: test/super/extra_arguments.lox 256 | PASS: test/super/indirectly_inherited.lox 257 | PASS: test/super/missing_arguments.lox 258 | PASS: test/super/no_superclass_bind.lox 259 | PASS: test/super/no_superclass_call.lox 260 | PASS: test/super/no_superclass_method.lox 261 | PASS: test/super/parenthesized.lox 262 | PASS: test/super/reassign_superclass.lox 263 | PASS: test/super/super_at_top_level.lox 264 | PASS: test/super/super_in_closure_in_inherited_method.lox 265 | PASS: test/super/super_in_inherited_method.lox 266 | PASS: test/super/super_in_top_level_function.lox 267 | PASS: test/super/super_without_dot.lox 268 | PASS: test/super/super_without_name.lox 269 | PASS: test/super/this_in_superclass_method.lox 270 | PASS: test/this/closure.lox 271 | FAIL: test/this/nested_class.lox 272 | Expected output "Outer instance" on line 3 and got "LoxInstance instance". 273 | Expected output "Outer instance" on line 6 and got "LoxInstance instance". 274 | Expected output "Inner instance" on line 10 and got "LoxInstance instance". 275 | 276 | PASS: test/this/nested_closure.lox 277 | PASS: test/this/this_at_top_level.lox 278 | PASS: test/this/this_in_method.lox 279 | PASS: test/this/this_in_top_level_function.lox 280 | PASS: test/unexpected_character.lox 281 | PASS: test/variable/collide_with_parameter.lox 282 | PASS: test/variable/duplicate_local.lox 283 | PASS: test/variable/duplicate_parameter.lox 284 | PASS: test/variable/early_bound.lox 285 | PASS: test/variable/in_middle_of_block.lox 286 | PASS: test/variable/in_nested_block.lox 287 | PASS: test/variable/local_from_method.lox 288 | PASS: test/variable/redeclare_global.lox 289 | PASS: test/variable/redefine_global.lox 290 | PASS: test/variable/scope_reuse_in_different_blocks.lox 291 | PASS: test/variable/shadow_and_local.lox 292 | PASS: test/variable/shadow_global.lox 293 | PASS: test/variable/shadow_local.lox 294 | PASS: test/variable/undefined_global.lox 295 | PASS: test/variable/undefined_local.lox 296 | PASS: test/variable/uninitialized.lox 297 | PASS: test/variable/unreached_undefined.lox 298 | PASS: test/variable/use_false_as_var.lox 299 | PASS: test/variable/use_global_in_initializer.lox 300 | PASS: test/variable/use_local_in_initializer.lox 301 | PASS: test/variable/use_nil_as_var.lox 302 | PASS: test/variable/use_this_as_var.lox 303 | PASS: test/while/class_in_body.lox 304 | PASS: test/while/closure_in_body.lox 305 | PASS: test/while/fun_in_body.lox 306 | PASS: test/while/return_closure.lox 307 | PASS: test/while/return_inside.lox 308 | PASS: test/while/syntax.lox 309 | PASS: test/while/var_in_body.lox 310 | 207 tests passed. 27 tests failed. 311 | -------------------------------------------------------------------------------- /getc_test.lox: -------------------------------------------------------------------------------- 1 | var done = false; 2 | while (!done) { 3 | var c = getc(); 4 | if (c >= 0) { 5 | print c; 6 | } else { 7 | done = true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /jlox: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | java -cp ../craftinginterpreters/build/java com.craftinginterpreters.lox.Lox $@ 3 | -------------------------------------------------------------------------------- /jlox_diff.patch: -------------------------------------------------------------------------------- 1 | diff --git a/java/com/craftinginterpreters/lox/Interpreter.java b/java/com/craftinginterpreters/lox/Interpreter.java 2 | index 823503f4..8c638059 100644 3 | --- a/java/com/craftinginterpreters/lox/Interpreter.java 4 | +++ b/java/com/craftinginterpreters/lox/Interpreter.java 5 | @@ -2,6 +2,10 @@ 6 | package com.craftinginterpreters.lox; 7 | //> Statements and State import-list 8 | 9 | +import java.io.IOException; 10 | +import java.io.InputStreamReader; 11 | +import java.nio.charset.StandardCharsets; 12 | + 13 | //> Functions import-array-list 14 | import java.util.ArrayList; 15 | //< Functions import-array-list 16 | @@ -35,6 +39,9 @@ class Interpreter implements Expr.Visitor, 17 | 18 | //< Statements and State environment-field 19 | //> Functions interpreter-constructor 20 | + 21 | + private InputStreamReader getcStream = new InputStreamReader(System.in, StandardCharsets.UTF_8); 22 | + 23 | Interpreter() { 24 | globals.define("clock", new LoxCallable() { 25 | @Override 26 | @@ -49,8 +56,74 @@ class Interpreter implements Expr.Visitor, 27 | @Override 28 | public String toString() { return ""; } 29 | }); 30 | + 31 | + globals.define("getc", new LoxCallable() { 32 | + @Override 33 | + public int arity() { return 0; } 34 | + 35 | + @Override 36 | + public Object call(Interpreter interpreter, 37 | + List arguments) { 38 | + try { 39 | + int c = getcStream.read(); 40 | + if (c < 0) { 41 | + return (double)-1; 42 | + } 43 | + return (double)c; 44 | + } catch (IOException error) { 45 | + return (double)-1; 46 | + } 47 | + } 48 | + 49 | + @Override 50 | + public String toString() { return ""; } 51 | + }); 52 | + 53 | + globals.define("chr", new LoxCallable() { 54 | + @Override 55 | + public int arity() { return 1; } 56 | + 57 | + @Override 58 | + public Object call(Interpreter interpreter, 59 | + List arguments) { 60 | + return Character.toString((char)(double)arguments.get(0)); 61 | + } 62 | + 63 | + @Override 64 | + public String toString() { return ""; } 65 | + }); 66 | + 67 | + globals.define("exit", new LoxCallable() { 68 | + @Override 69 | + public int arity() { return 1; } 70 | + 71 | + @Override 72 | + public Object call(Interpreter interpreter, 73 | + List arguments) { 74 | + System.exit((int)(double)arguments.get(0)); 75 | + return null; 76 | + } 77 | + 78 | + @Override 79 | + public String toString() { return ""; } 80 | + }); 81 | + 82 | + globals.define("print_error", new LoxCallable() { 83 | + @Override 84 | + public int arity() { return 1; } 85 | + 86 | + @Override 87 | + public Object call(Interpreter interpreter, 88 | + List arguments) { 89 | + System.err.println((String)arguments.get(0)); 90 | + return null; 91 | + } 92 | + 93 | + @Override 94 | + public String toString() { return ""; } 95 | + }); 96 | } 97 | - 98 | + 99 | //< Functions interpreter-constructor 100 | /* Evaluating Expressions interpret < Statements and State interpret 101 | void interpret(Expr expression) { // [void] 102 | -------------------------------------------------------------------------------- /sum.lox: -------------------------------------------------------------------------------- 1 | var sum = 0; 2 | for (var i = 0; i < 100000; i = i + 1) { 3 | sum = sum + i; 4 | } 5 | print sum; 6 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # NOTE: this was originally copied from the github.com/munificent/craftinginterpreters 4 | # repo and modified slightly (but I think those tests are run using Dart now, not Python). 5 | 6 | from __future__ import print_function 7 | 8 | from collections import defaultdict 9 | from os import listdir 10 | from os.path import abspath, basename, dirname, isdir, isfile, join, realpath, relpath, splitext 11 | import re 12 | from subprocess import Popen, PIPE 13 | import sys 14 | 15 | # Runs the tests. 16 | REPO_DIR = dirname(realpath(__file__)) 17 | 18 | OUTPUT_EXPECT = re.compile(r'// expect: ?(.*)') 19 | ERROR_EXPECT = re.compile(r'// (Error.*)') 20 | ERROR_LINE_EXPECT = re.compile(r'// \[((java|c) )?line (\d+)\] (Error.*)') 21 | RUNTIME_ERROR_EXPECT = re.compile(r'// expect runtime error: (.+)') 22 | SYNTAX_ERROR_RE = re.compile(r'\[.*line (\d+)\] (Error.+)') 23 | STACK_TRACE_RE = re.compile(r'\[line (\d+)\]') 24 | NONTEST_RE = re.compile(r'// nontest') 25 | 26 | passed = 0 27 | failed = 0 28 | num_skipped = 0 29 | expectations = 0 30 | 31 | interpreter = None 32 | filter_path = None 33 | 34 | INTERPRETERS = {} 35 | C_SUITES = [] 36 | JAVA_SUITES = [] 37 | 38 | 39 | class Interpreter: 40 | def __init__(self, name, language, args, tests): 41 | self.name = name 42 | self.language = language 43 | self.args = args 44 | self.tests = tests 45 | 46 | 47 | def c_interpreter(name, tests): 48 | if name == 'clox': 49 | path = 'build/cloxd' 50 | else: 51 | path = 'build/' + name 52 | 53 | INTERPRETERS[name] = Interpreter(name, 'c', [path], tests) 54 | C_SUITES.append(name) 55 | 56 | 57 | def java_interpreter(name, tests): 58 | if name == 'jlox': 59 | dir = '../craftinginterpreters/build/java' 60 | else: 61 | dir = '../craftinginterpreters/build/gen/' + name 62 | 63 | INTERPRETERS[name] = Interpreter(name, 'java', 64 | ['java', '-cp', dir, 'com.craftinginterpreters.lox.Lox', 'lox.lox'], tests) 65 | JAVA_SUITES.append(name) 66 | 67 | 68 | java_interpreter('jlox', { 69 | 'test': 'pass', 70 | 71 | # These are just for earlier chapters. 72 | 'test/scanning': 'skip', 73 | 'test/expressions': 'skip', 74 | 75 | # No hardcoded limits in jlox. 76 | 'test/limit/loop_too_large.lox': 'skip', 77 | 'test/limit/no_reuse_constants.lox': 'skip', 78 | 'test/limit/too_many_constants.lox': 'skip', 79 | 'test/limit/too_many_locals.lox': 'skip', 80 | 'test/limit/too_many_upvalues.lox': 'skip', 81 | 82 | # Rely on JVM for stack overflow checking. 83 | 'test/limit/stack_overflow.lox': 'skip', 84 | }) 85 | 86 | java_interpreter('chap04_scanning', { 87 | # No interpreter yet. 88 | 'test': 'skip', 89 | 90 | 'test/scanning': 'pass' 91 | }) 92 | 93 | # No test for chapter 5. It just has a hardcoded main() in AstPrinter. 94 | 95 | java_interpreter('chap06_parsing', { 96 | # No real interpreter yet. 97 | 'test': 'skip', 98 | 99 | 'test/expressions/parse.lox': 'pass' 100 | }) 101 | 102 | java_interpreter('chap07_evaluating', { 103 | # No real interpreter yet. 104 | 'test': 'skip', 105 | 106 | 'test/expressions/evaluate.lox': 'pass' 107 | }) 108 | 109 | java_interpreter('chap08_statements', { 110 | 'test': 'pass', 111 | 112 | # These are just for earlier chapters. 113 | 'test/scanning': 'skip', 114 | 'test/expressions': 'skip', 115 | 116 | # No hardcoded limits in jlox. 117 | 'test/limit/loop_too_large.lox': 'skip', 118 | 'test/limit/no_reuse_constants.lox': 'skip', 119 | 'test/limit/too_many_constants.lox': 'skip', 120 | 'test/limit/too_many_locals.lox': 'skip', 121 | 'test/limit/too_many_upvalues.lox': 'skip', 122 | 123 | # Rely on JVM for stack overflow checking. 124 | 'test/limit/stack_overflow.lox': 'skip', 125 | 126 | # No control flow. 127 | 'test/block/empty.lox': 'skip', 128 | 'test/for': 'skip', 129 | 'test/if': 'skip', 130 | 'test/logical_operator': 'skip', 131 | 'test/while': 'skip', 132 | 'test/variable/unreached_undefined.lox': 'skip', 133 | 134 | # No functions. 135 | 'test/call': 'skip', 136 | 'test/closure': 'skip', 137 | 'test/function': 'skip', 138 | 'test/operator/not.lox': 'skip', 139 | 'test/regression/40.lox': 'skip', 140 | 'test/return': 'skip', 141 | 'test/unexpected_character.lox': 'skip', 142 | 143 | # Broken because we haven't fixed it yet by detecting the error. 144 | 'test/return/at_top_level.lox': 'skip', 145 | 'test/variable/use_local_in_initializer.lox': 'skip', 146 | 147 | # No resolution. 148 | 'test/closure/assign_to_shadowed_later.lox': 'skip', 149 | 'test/function/local_mutual_recursion.lox': 'skip', 150 | 'test/variable/collide_with_parameter.lox': 'skip', 151 | 'test/variable/duplicate_local.lox': 'skip', 152 | 'test/variable/duplicate_parameter.lox': 'skip', 153 | 'test/variable/early_bound.lox': 'skip', 154 | 155 | # No classes. 156 | 'test/assignment/to_this.lox': 'skip', 157 | 'test/call/object.lox': 'skip', 158 | 'test/class': 'skip', 159 | 'test/closure/close_over_method_parameter.lox': 'skip', 160 | 'test/constructor': 'skip', 161 | 'test/field': 'skip', 162 | 'test/inheritance': 'skip', 163 | 'test/method': 'skip', 164 | 'test/number/decimal_point_at_eof.lox': 'skip', 165 | 'test/number/trailing_dot.lox': 'skip', 166 | 'test/operator/equals_class.lox': 'skip', 167 | 'test/operator/equals_method.lox': 'skip', 168 | 'test/operator/not_class.lox': 'skip', 169 | 'test/super': 'skip', 170 | 'test/this': 'skip', 171 | 'test/return/in_method.lox': 'skip', 172 | 'test/variable/local_from_method.lox': 'skip', 173 | }) 174 | 175 | java_interpreter('chap09_control', { 176 | 'test': 'pass', 177 | 178 | # These are just for earlier chapters. 179 | 'test/scanning': 'skip', 180 | 'test/expressions': 'skip', 181 | 182 | # No hardcoded limits in jlox. 183 | 'test/limit/loop_too_large.lox': 'skip', 184 | 'test/limit/no_reuse_constants.lox': 'skip', 185 | 'test/limit/too_many_constants.lox': 'skip', 186 | 'test/limit/too_many_locals.lox': 'skip', 187 | 'test/limit/too_many_upvalues.lox': 'skip', 188 | 189 | # Rely on JVM for stack overflow checking. 190 | 'test/limit/stack_overflow.lox': 'skip', 191 | 192 | # No functions. 193 | 'test/call': 'skip', 194 | 'test/closure': 'skip', 195 | 'test/for/closure_in_body.lox': 'skip', 196 | 'test/for/return_closure.lox': 'skip', 197 | 'test/for/return_inside.lox': 'skip', 198 | 'test/for/syntax.lox': 'skip', 199 | 'test/function': 'skip', 200 | 'test/operator/not.lox': 'skip', 201 | 'test/regression/40.lox': 'skip', 202 | 'test/return': 'skip', 203 | 'test/unexpected_character.lox': 'skip', 204 | 'test/while/closure_in_body.lox': 'skip', 205 | 'test/while/return_closure.lox': 'skip', 206 | 'test/while/return_inside.lox': 'skip', 207 | 208 | # Broken because we haven't fixed it yet by detecting the error. 209 | 'test/return/at_top_level.lox': 'skip', 210 | 'test/variable/use_local_in_initializer.lox': 'skip', 211 | 212 | # No resolution. 213 | 'test/closure/assign_to_shadowed_later.lox': 'skip', 214 | 'test/function/local_mutual_recursion.lox': 'skip', 215 | 'test/variable/collide_with_parameter.lox': 'skip', 216 | 'test/variable/duplicate_local.lox': 'skip', 217 | 'test/variable/duplicate_parameter.lox': 'skip', 218 | 'test/variable/early_bound.lox': 'skip', 219 | 220 | # No classes. 221 | 'test/assignment/to_this.lox': 'skip', 222 | 'test/call/object.lox': 'skip', 223 | 'test/class': 'skip', 224 | 'test/closure/close_over_method_parameter.lox': 'skip', 225 | 'test/constructor': 'skip', 226 | 'test/field': 'skip', 227 | 'test/inheritance': 'skip', 228 | 'test/method': 'skip', 229 | 'test/number/decimal_point_at_eof.lox': 'skip', 230 | 'test/number/trailing_dot.lox': 'skip', 231 | 'test/operator/equals_class.lox': 'skip', 232 | 'test/operator/equals_method.lox': 'skip', 233 | 'test/operator/not_class.lox': 'skip', 234 | 'test/super': 'skip', 235 | 'test/this': 'skip', 236 | 'test/return/in_method.lox': 'skip', 237 | 'test/variable/local_from_method.lox': 'skip', 238 | }) 239 | 240 | java_interpreter('chap10_functions', { 241 | 'test': 'pass', 242 | 243 | # These are just for earlier chapters. 244 | 'test/scanning': 'skip', 245 | 'test/expressions': 'skip', 246 | 247 | # No hardcoded limits in jlox. 248 | 'test/limit/loop_too_large.lox': 'skip', 249 | 'test/limit/no_reuse_constants.lox': 'skip', 250 | 'test/limit/too_many_constants.lox': 'skip', 251 | 'test/limit/too_many_locals.lox': 'skip', 252 | 'test/limit/too_many_upvalues.lox': 'skip', 253 | 254 | # Rely on JVM for stack overflow checking. 255 | 'test/limit/stack_overflow.lox': 'skip', 256 | 257 | # Broken because we haven't fixed it yet by detecting the error. 258 | 'test/return/at_top_level.lox': 'skip', 259 | 'test/variable/use_local_in_initializer.lox': 'skip', 260 | 261 | # No resolution. 262 | 'test/closure/assign_to_shadowed_later.lox': 'skip', 263 | 'test/function/local_mutual_recursion.lox': 'skip', 264 | 'test/variable/collide_with_parameter.lox': 'skip', 265 | 'test/variable/duplicate_local.lox': 'skip', 266 | 'test/variable/duplicate_parameter.lox': 'skip', 267 | 'test/variable/early_bound.lox': 'skip', 268 | 269 | # No classes. 270 | 'test/assignment/to_this.lox': 'skip', 271 | 'test/call/object.lox': 'skip', 272 | 'test/class': 'skip', 273 | 'test/closure/close_over_method_parameter.lox': 'skip', 274 | 'test/constructor': 'skip', 275 | 'test/field': 'skip', 276 | 'test/inheritance': 'skip', 277 | 'test/method': 'skip', 278 | 'test/number/decimal_point_at_eof.lox': 'skip', 279 | 'test/number/trailing_dot.lox': 'skip', 280 | 'test/operator/equals_class.lox': 'skip', 281 | 'test/operator/equals_method.lox': 'skip', 282 | 'test/operator/not_class.lox': 'skip', 283 | 'test/super': 'skip', 284 | 'test/this': 'skip', 285 | 'test/return/in_method.lox': 'skip', 286 | 'test/variable/local_from_method.lox': 'skip', 287 | }) 288 | 289 | java_interpreter('chap11_resolving', { 290 | 'test': 'pass', 291 | 292 | # These are just for earlier chapters. 293 | 'test/scanning': 'skip', 294 | 'test/expressions': 'skip', 295 | 296 | # No hardcoded limits in jlox. 297 | 'test/limit/loop_too_large.lox': 'skip', 298 | 'test/limit/no_reuse_constants.lox': 'skip', 299 | 'test/limit/too_many_constants.lox': 'skip', 300 | 'test/limit/too_many_locals.lox': 'skip', 301 | 'test/limit/too_many_upvalues.lox': 'skip', 302 | 303 | # Rely on JVM for stack overflow checking. 304 | 'test/limit/stack_overflow.lox': 'skip', 305 | 306 | # No classes. 307 | 'test/assignment/to_this.lox': 'skip', 308 | 'test/call/object.lox': 'skip', 309 | 'test/class': 'skip', 310 | 'test/closure/close_over_method_parameter.lox': 'skip', 311 | 'test/constructor': 'skip', 312 | 'test/field': 'skip', 313 | 'test/inheritance': 'skip', 314 | 'test/method': 'skip', 315 | 'test/number/decimal_point_at_eof.lox': 'skip', 316 | 'test/number/trailing_dot.lox': 'skip', 317 | 'test/operator/equals_class.lox': 'skip', 318 | 'test/operator/equals_method.lox': 'skip', 319 | 'test/operator/not_class.lox': 'skip', 320 | 'test/super': 'skip', 321 | 'test/this': 'skip', 322 | 'test/return/in_method.lox': 'skip', 323 | 'test/variable/local_from_method.lox': 'skip', 324 | }) 325 | 326 | java_interpreter('chap12_classes', { 327 | 'test': 'pass', 328 | 329 | # These are just for earlier chapters. 330 | 'test/scanning': 'skip', 331 | 'test/expressions': 'skip', 332 | 333 | # No hardcoded limits in jlox. 334 | 'test/limit/loop_too_large.lox': 'skip', 335 | 'test/limit/no_reuse_constants.lox': 'skip', 336 | 'test/limit/too_many_constants.lox': 'skip', 337 | 'test/limit/too_many_locals.lox': 'skip', 338 | 'test/limit/too_many_upvalues.lox': 'skip', 339 | 340 | # Rely on JVM for stack overflow checking. 341 | 'test/limit/stack_overflow.lox': 'skip', 342 | 343 | # No inheritance. 344 | 'test/class/local_inherit_self.lox': 'skip', 345 | 'test/class/inherit_self.lox': 'skip', 346 | 'test/class/inherited_method.lox': 'skip', 347 | 'test/inheritance': 'skip', 348 | 'test/super': 'skip', 349 | }) 350 | 351 | java_interpreter('chap13_inheritance', { 352 | 'test': 'pass', 353 | 354 | # These are just for earlier chapters. 355 | 'test/scanning': 'skip', 356 | 'test/expressions': 'skip', 357 | 358 | # No hardcoded limits in jlox. 359 | 'test/limit/loop_too_large.lox': 'skip', 360 | 'test/limit/no_reuse_constants.lox': 'skip', 361 | 'test/limit/too_many_constants.lox': 'skip', 362 | 'test/limit/too_many_locals.lox': 'skip', 363 | 'test/limit/too_many_upvalues.lox': 'skip', 364 | 365 | # Rely on JVM for stack overflow checking. 366 | 'test/limit/stack_overflow.lox': 'skip', 367 | }) 368 | 369 | c_interpreter('clox', { 370 | 'test': 'pass', 371 | 372 | # These are just for earlier chapters. 373 | 'test/scanning': 'skip', 374 | 'test/expressions': 'skip' 375 | }) 376 | 377 | # TODO: Other chapters. 378 | 379 | c_interpreter('chap17_compiling', { 380 | # No real interpreter yet. 381 | 'test': 'skip', 382 | 383 | 'test/expressions/evaluate.lox': 'pass', 384 | }) 385 | 386 | c_interpreter('chap18_types', { 387 | # No real interpreter yet. 388 | 'test': 'skip', 389 | 390 | 'test/expressions/evaluate.lox': 'pass', 391 | }) 392 | 393 | c_interpreter('chap19_strings', { 394 | # No real interpreter yet. 395 | 'test': 'skip', 396 | 397 | 'test/expressions/evaluate.lox': 'pass', 398 | }) 399 | 400 | c_interpreter('chap20_hash', { 401 | # No real interpreter yet. 402 | 'test': 'skip', 403 | 404 | 'test/expressions/evaluate.lox': 'pass', 405 | }) 406 | 407 | c_interpreter('chap21_global', { 408 | 'test': 'pass', 409 | 410 | # These are just for earlier chapters. 411 | 'test/scanning': 'skip', 412 | 'test/expressions': 'skip', 413 | 414 | # No control flow. 415 | 'test/block/empty.lox': 'skip', 416 | 'test/for': 'skip', 417 | 'test/if': 'skip', 418 | 'test/limit/loop_too_large.lox': 'skip', 419 | 'test/logical_operator': 'skip', 420 | 'test/variable/unreached_undefined.lox': 'skip', 421 | 'test/while': 'skip', 422 | 423 | # No blocks. 424 | 'test/assignment/local.lox': 'skip', 425 | 'test/variable/in_middle_of_block.lox': 'skip', 426 | 'test/variable/in_nested_block.lox': 'skip', 427 | 'test/variable/scope_reuse_in_different_blocks.lox': 'skip', 428 | 'test/variable/shadow_and_local.lox': 'skip', 429 | 'test/variable/undefined_local.lox': 'skip', 430 | 431 | # No local variables. 432 | 'test/block/scope.lox': 'skip', 433 | 'test/variable/duplicate_local.lox': 'skip', 434 | 'test/variable/shadow_global.lox': 'skip', 435 | 'test/variable/shadow_local.lox': 'skip', 436 | 'test/variable/use_local_in_initializer.lox': 'skip', 437 | 438 | # No functions. 439 | 'test/call': 'skip', 440 | 'test/closure': 'skip', 441 | 'test/function': 'skip', 442 | 'test/limit/no_reuse_constants.lox': 'skip', 443 | 'test/limit/stack_overflow.lox': 'skip', 444 | 'test/limit/too_many_constants.lox': 'skip', 445 | 'test/limit/too_many_locals.lox': 'skip', 446 | 'test/limit/too_many_upvalues.lox': 'skip', 447 | 'test/regression/40.lox': 'skip', 448 | 'test/return': 'skip', 449 | 'test/unexpected_character.lox': 'skip', 450 | 'test/variable/collide_with_parameter.lox': 'skip', 451 | 'test/variable/duplicate_parameter.lox': 'skip', 452 | 'test/variable/early_bound.lox': 'skip', 453 | 454 | # No classes. 455 | 'test/assignment/to_this.lox': 'skip', 456 | 'test/class': 'skip', 457 | 'test/constructor': 'skip', 458 | 'test/field': 'skip', 459 | 'test/inheritance': 'skip', 460 | 'test/method': 'skip', 461 | 'test/number/decimal_point_at_eof.lox': 'skip', 462 | 'test/number/trailing_dot.lox': 'skip', 463 | 'test/operator/equals_class.lox': 'skip', 464 | 'test/operator/equals_method.lox': 'skip', 465 | 'test/operator/not.lox': 'skip', 466 | 'test/operator/not_class.lox': 'skip', 467 | 'test/super': 'skip', 468 | 'test/this': 'skip', 469 | 'test/variable/local_from_method.lox': 'skip', 470 | }) 471 | 472 | c_interpreter('chap22_local', { 473 | 'test': 'pass', 474 | 475 | # These are just for earlier chapters. 476 | 'test/scanning': 'skip', 477 | 'test/expressions': 'skip', 478 | 479 | # No control flow. 480 | 'test/block/empty.lox': 'skip', 481 | 'test/for': 'skip', 482 | 'test/if': 'skip', 483 | 'test/limit/loop_too_large.lox': 'skip', 484 | 'test/logical_operator': 'skip', 485 | 'test/variable/unreached_undefined.lox': 'skip', 486 | 'test/while': 'skip', 487 | 488 | # No functions. 489 | 'test/call': 'skip', 490 | 'test/closure': 'skip', 491 | 'test/function': 'skip', 492 | 'test/limit/no_reuse_constants.lox': 'skip', 493 | 'test/limit/stack_overflow.lox': 'skip', 494 | 'test/limit/too_many_constants.lox': 'skip', 495 | 'test/limit/too_many_locals.lox': 'skip', 496 | 'test/limit/too_many_upvalues.lox': 'skip', 497 | 'test/regression/40.lox': 'skip', 498 | 'test/return': 'skip', 499 | 'test/unexpected_character.lox': 'skip', 500 | 'test/variable/collide_with_parameter.lox': 'skip', 501 | 'test/variable/duplicate_parameter.lox': 'skip', 502 | 'test/variable/early_bound.lox': 'skip', 503 | 504 | # No classes. 505 | 'test/assignment/to_this.lox': 'skip', 506 | 'test/class': 'skip', 507 | 'test/constructor': 'skip', 508 | 'test/field': 'skip', 509 | 'test/inheritance': 'skip', 510 | 'test/method': 'skip', 511 | 'test/number/decimal_point_at_eof.lox': 'skip', 512 | 'test/number/trailing_dot.lox': 'skip', 513 | 'test/operator/equals_class.lox': 'skip', 514 | 'test/operator/equals_method.lox': 'skip', 515 | 'test/operator/not.lox': 'skip', 516 | 'test/operator/not_class.lox': 'skip', 517 | 'test/super': 'skip', 518 | 'test/this': 'skip', 519 | 'test/variable/local_from_method.lox': 'skip', 520 | }) 521 | 522 | c_interpreter('chap23_jumping', { 523 | 'test': 'pass', 524 | 525 | # These are just for earlier chapters. 526 | 'test/scanning': 'skip', 527 | 'test/expressions': 'skip', 528 | 529 | # No functions. 530 | 'test/call': 'skip', 531 | 'test/closure': 'skip', 532 | 'test/for/closure_in_body.lox': 'skip', 533 | 'test/for/return_closure.lox': 'skip', 534 | 'test/for/return_inside.lox': 'skip', 535 | 'test/for/syntax.lox': 'skip', 536 | 'test/function': 'skip', 537 | 'test/limit/no_reuse_constants.lox': 'skip', 538 | 'test/limit/stack_overflow.lox': 'skip', 539 | 'test/limit/too_many_constants.lox': 'skip', 540 | 'test/limit/too_many_locals.lox': 'skip', 541 | 'test/limit/too_many_upvalues.lox': 'skip', 542 | 'test/regression/40.lox': 'skip', 543 | 'test/return': 'skip', 544 | 'test/unexpected_character.lox': 'skip', 545 | 'test/variable/collide_with_parameter.lox': 'skip', 546 | 'test/variable/duplicate_parameter.lox': 'skip', 547 | 'test/variable/early_bound.lox': 'skip', 548 | 'test/while/closure_in_body.lox': 'skip', 549 | 'test/while/return_closure.lox': 'skip', 550 | 'test/while/return_inside.lox': 'skip', 551 | 552 | # No classes. 553 | 'test/assignment/to_this.lox': 'skip', 554 | 'test/class': 'skip', 555 | 'test/constructor': 'skip', 556 | 'test/field': 'skip', 557 | 'test/inheritance': 'skip', 558 | 'test/method': 'skip', 559 | 'test/number/decimal_point_at_eof.lox': 'skip', 560 | 'test/number/trailing_dot.lox': 'skip', 561 | 'test/operator/equals_class.lox': 'skip', 562 | 'test/operator/equals_method.lox': 'skip', 563 | 'test/operator/not.lox': 'skip', 564 | 'test/operator/not_class.lox': 'skip', 565 | 'test/super': 'skip', 566 | 'test/this': 'skip', 567 | 'test/variable/local_from_method.lox': 'skip', 568 | }) 569 | 570 | c_interpreter('chap24_calls', { 571 | 'test': 'pass', 572 | 573 | # These are just for earlier chapters. 574 | 'test/scanning': 'skip', 575 | 'test/expressions': 'skip', 576 | 577 | # No closures. 578 | 'test/closure': 'skip', 579 | 'test/for/closure_in_body.lox': 'skip', 580 | 'test/for/return_closure.lox': 'skip', 581 | 'test/function/local_recursion.lox': 'skip', 582 | 'test/limit/too_many_upvalues.lox': 'skip', 583 | 'test/regression/40.lox': 'skip', 584 | 'test/while/closure_in_body.lox': 'skip', 585 | 'test/while/return_closure.lox': 'skip', 586 | 587 | # No classes. 588 | 'test/assignment/to_this.lox': 'skip', 589 | 'test/call/object.lox': 'skip', 590 | 'test/class': 'skip', 591 | 'test/constructor': 'skip', 592 | 'test/field': 'skip', 593 | 'test/inheritance': 'skip', 594 | 'test/method': 'skip', 595 | 'test/number/decimal_point_at_eof.lox': 'skip', 596 | 'test/number/trailing_dot.lox': 'skip', 597 | 'test/operator/equals_class.lox': 'skip', 598 | 'test/operator/equals_method.lox': 'skip', 599 | 'test/operator/not.lox': 'skip', 600 | 'test/operator/not_class.lox': 'skip', 601 | 'test/return/in_method.lox': 'skip', 602 | 'test/super': 'skip', 603 | 'test/this': 'skip', 604 | 'test/variable/local_from_method.lox': 'skip', 605 | }) 606 | 607 | c_interpreter('chap25_closures', { 608 | 'test': 'pass', 609 | 610 | # These are just for earlier chapters. 611 | 'test/scanning': 'skip', 612 | 'test/expressions': 'skip', 613 | 614 | # No classes. 615 | 'test/assignment/to_this.lox': 'skip', 616 | 'test/call/object.lox': 'skip', 617 | 'test/class': 'skip', 618 | 'test/closure/close_over_method_parameter.lox': 'skip', 619 | 'test/constructor': 'skip', 620 | 'test/field': 'skip', 621 | 'test/inheritance': 'skip', 622 | 'test/method': 'skip', 623 | 'test/number/decimal_point_at_eof.lox': 'skip', 624 | 'test/number/trailing_dot.lox': 'skip', 625 | 'test/operator/equals_class.lox': 'skip', 626 | 'test/operator/equals_method.lox': 'skip', 627 | 'test/operator/not.lox': 'skip', 628 | 'test/operator/not_class.lox': 'skip', 629 | 'test/return/in_method.lox': 'skip', 630 | 'test/super': 'skip', 631 | 'test/this': 'skip', 632 | 'test/variable/local_from_method.lox': 'skip', 633 | }) 634 | 635 | c_interpreter('chap26_garbage', { 636 | 'test': 'pass', 637 | 638 | # These are just for earlier chapters. 639 | 'test/scanning': 'skip', 640 | 'test/expressions': 'skip', 641 | 642 | # No classes. 643 | 'test/assignment/to_this.lox': 'skip', 644 | 'test/call/object.lox': 'skip', 645 | 'test/class': 'skip', 646 | 'test/closure/close_over_method_parameter.lox': 'skip', 647 | 'test/constructor': 'skip', 648 | 'test/field': 'skip', 649 | 'test/inheritance': 'skip', 650 | 'test/method': 'skip', 651 | 'test/number/decimal_point_at_eof.lox': 'skip', 652 | 'test/number/trailing_dot.lox': 'skip', 653 | 'test/operator/equals_class.lox': 'skip', 654 | 'test/operator/equals_method.lox': 'skip', 655 | 'test/operator/not.lox': 'skip', 656 | 'test/operator/not_class.lox': 'skip', 657 | 'test/return/in_method.lox': 'skip', 658 | 'test/super': 'skip', 659 | 'test/this': 'skip', 660 | 'test/variable/local_from_method.lox': 'skip', 661 | }) 662 | 663 | c_interpreter('chap27_classes', { 664 | 'test': 'pass', 665 | 666 | # These are just for earlier chapters. 667 | 'test/scanning': 'skip', 668 | 'test/expressions': 'skip', 669 | 670 | # No inheritance. 671 | 'test/class/local_inherit_self.lox': 'skip', 672 | 'test/class/inherit_self.lox': 'skip', 673 | 'test/class/inherited_method.lox': 'skip', 674 | 'test/inheritance': 'skip', 675 | 'test/super': 'skip', 676 | 677 | # No methods. 678 | 'test/assignment/to_this.lox': 'skip', 679 | 'test/class/local_reference_self.lox': 'skip', 680 | 'test/class/reference_self.lox': 'skip', 681 | 'test/closure/close_over_method_parameter.lox': 'skip', 682 | 'test/constructor': 'skip', 683 | 'test/field/get_and_set_method.lox': 'skip', 684 | 'test/field/method.lox': 'skip', 685 | 'test/field/method_binds_this.lox': 'skip', 686 | 'test/method': 'skip', 687 | 'test/operator/equals_class.lox': 'skip', 688 | 'test/operator/equals_method.lox': 'skip', 689 | 'test/return/in_method.lox': 'skip', 690 | 'test/this': 'skip', 691 | 'test/variable/local_from_method.lox': 'skip', 692 | }) 693 | 694 | c_interpreter('chap28_methods', { 695 | 'test': 'pass', 696 | 697 | # These are just for earlier chapters. 698 | 'test/scanning': 'skip', 699 | 'test/expressions': 'skip', 700 | 701 | # No inheritance. 702 | 'test/class/local_inherit_self.lox': 'skip', 703 | 'test/class/inherit_self.lox': 'skip', 704 | 'test/class/inherited_method.lox': 'skip', 705 | 'test/inheritance': 'skip', 706 | 'test/super': 'skip', 707 | }) 708 | 709 | c_interpreter('chap29_superclasses', { 710 | 'test': 'pass', 711 | 712 | # These are just for earlier chapters. 713 | 'test/scanning': 'skip', 714 | 'test/expressions': 'skip', 715 | }) 716 | 717 | c_interpreter('chap30_optimization', { 718 | 'test': 'pass', 719 | 720 | # These are just for earlier chapters. 721 | 'test/scanning': 'skip', 722 | 'test/expressions': 'skip', 723 | }) 724 | 725 | class Test: 726 | def __init__(self, path): 727 | self.path = path 728 | self.output = [] 729 | self.compile_errors = set() 730 | self.runtime_error_line = 0 731 | self.runtime_error_message = None 732 | self.exit_code = 0 733 | self.failures = [] 734 | 735 | 736 | def parse(self): 737 | global num_skipped 738 | global expectations 739 | 740 | # Get the path components. 741 | parts = self.path.split('/') 742 | subpath = "" 743 | state = None 744 | 745 | # Figure out the state of the test. We don't break out of this loop because 746 | # we want lines for more specific paths to override more general ones. 747 | for part in parts: 748 | if subpath: subpath += '/' 749 | subpath += part 750 | 751 | if subpath in interpreter.tests: 752 | state = interpreter.tests[subpath] 753 | 754 | if not state: 755 | print('Unknown test state for "{}".'.format(self.path)) 756 | if state == 'skip': 757 | num_skipped += 1 758 | return False 759 | # TODO: State for tests that should be run but are expected to fail? 760 | 761 | line_num = 1 762 | with open(self.path, 'r') as file: 763 | for line in file: 764 | match = OUTPUT_EXPECT.search(line) 765 | if match: 766 | self.output.append((match.group(1), line_num)) 767 | expectations += 1 768 | 769 | match = ERROR_EXPECT.search(line) 770 | if match and not self.compile_errors: 771 | self.compile_errors.add(match.group(1)) 772 | 773 | # If we expect a compile error, it should exit with EX_DATAERR. 774 | self.exit_code = 65 775 | expectations += 1 776 | 777 | match = ERROR_LINE_EXPECT.search(line) 778 | if match: 779 | # The two interpreters are slightly different in terms of which 780 | # cascaded errors may appear after an initial compile error because 781 | # their panic mode recovery is a little different. To handle that, 782 | # the tests can indicate if an error line should only appear for a 783 | # certain interpreter. 784 | language = match.group(2) 785 | if (not language or language == interpreter.language) and not self.compile_errors: 786 | self.compile_errors.add(match.group(4)) 787 | 788 | # If we expect a compile error, it should exit with EX_DATAERR. 789 | self.exit_code = 65 790 | expectations += 1 791 | 792 | match = RUNTIME_ERROR_EXPECT.search(line) 793 | if match: 794 | self.runtime_error_line = line_num 795 | self.runtime_error_message = match.group(1) 796 | # If we expect a runtime error, it should exit with EX_SOFTWARE. 797 | self.exit_code = 70 798 | expectations += 1 799 | 800 | match = NONTEST_RE.search(line) 801 | if match: 802 | # Not a test file at all, so ignore it. 803 | return False 804 | 805 | line_num += 1 806 | 807 | 808 | # If we got here, it's a valid test. 809 | return True 810 | 811 | 812 | def run(self): 813 | # Invoke the interpreter and run the test. 814 | args = interpreter.args[:] 815 | proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, text=True) 816 | 817 | with open(self.path) as f: 818 | lox_input = f.read() 819 | 820 | out, err = proc.communicate(lox_input) 821 | self.validate(proc.returncode, out, err) 822 | 823 | 824 | def validate(self, exit_code, out, err): 825 | if self.compile_errors and self.runtime_error_message: 826 | self.fail("Test error: Cannot expect both compile and runtime errors.") 827 | return 828 | 829 | out = out.replace('\r\n', '\n') 830 | err = err.replace('\r\n', '\n') 831 | 832 | error_lines = err.split('\n') 833 | 834 | # Validate that an expected runtime error occurred. 835 | if self.runtime_error_message: 836 | self.validate_runtime_error(error_lines) 837 | else: 838 | self.validate_compile_errors(error_lines) 839 | 840 | self.validate_exit_code(exit_code, error_lines) 841 | self.validate_output(out) 842 | 843 | 844 | def validate_runtime_error(self, error_lines): 845 | if len(error_lines) < 2: 846 | self.fail('Expected runtime error "{0}" and got none.', 847 | self.runtime_error_message) 848 | return 849 | 850 | # Skip any compile errors. This can happen if there is a compile error in 851 | # a module loaded by the module being tested. 852 | line = 0 853 | while SYNTAX_ERROR_RE.search(error_lines[line]): 854 | line += 1 855 | 856 | if error_lines[line] != self.runtime_error_message: 857 | self.fail('Expected runtime error "{0}" and got:', 858 | self.runtime_error_message) 859 | self.fail(error_lines[line]) 860 | 861 | # Make sure the stack trace has the right line. Skip over any lines that 862 | # come from builtin libraries. 863 | match = False 864 | stack_lines = error_lines[line + 1:] 865 | for stack_line in stack_lines: 866 | match = STACK_TRACE_RE.search(stack_line) 867 | if match: break 868 | 869 | if not match: 870 | self.fail('Expected stack trace and got:') 871 | for stack_line in stack_lines: 872 | self.fail(stack_line) 873 | else: 874 | pass 875 | # stack_line = int(match.group(1)) 876 | # if stack_line != self.runtime_error_line: 877 | # self.fail('Expected runtime error on line {0} but was on line {1}.', 878 | # self.runtime_error_line, stack_line) 879 | 880 | 881 | def validate_compile_errors(self, error_lines): 882 | # Validate that every compile error was expected. 883 | found_errors = set() 884 | num_unexpected = 0 885 | for line in error_lines: 886 | match = SYNTAX_ERROR_RE.search(line) 887 | if match: 888 | error = match.group(2) 889 | if error in self.compile_errors: 890 | found_errors.add(error) 891 | else: 892 | if num_unexpected < 10: 893 | self.fail('Unexpected error:') 894 | self.fail(line) 895 | num_unexpected += 1 896 | elif line != '': 897 | if num_unexpected < 10: 898 | self.fail('Unexpected output on stderr:') 899 | self.fail(line) 900 | num_unexpected += 1 901 | 902 | if num_unexpected > 10: 903 | self.fail('(truncated ' + str(num_unexpected - 10) + ' more...)') 904 | 905 | # Validate that every expected error occurred. 906 | for error in self.compile_errors - found_errors: 907 | self.fail('Missing expected error: {0}', error) 908 | 909 | 910 | def validate_exit_code(self, exit_code, error_lines): 911 | if exit_code == self.exit_code: return 912 | 913 | if len(error_lines) > 10: 914 | error_lines = error_lines[0:10] 915 | error_lines.append('(truncated...)') 916 | self.fail('Expected return code {0} and got {1}. Stderr:', 917 | self.exit_code, exit_code) 918 | self.failures += error_lines 919 | 920 | 921 | def validate_output(self, out): 922 | # Remove the trailing last empty line. 923 | out_lines = out.split('\n') 924 | if out_lines[-1] == '': 925 | del out_lines[-1] 926 | 927 | index = 0 928 | for line in out_lines: 929 | if index >= len(self.output): 930 | self.fail('Got output "{0}" when none was expected.', line) 931 | elif self.output[index][0] != line: 932 | self.fail('Expected output "{0}" on line {1} and got "{2}".', 933 | self.output[index][0], self.output[index][1], line) 934 | index += 1 935 | 936 | while index < len(self.output): 937 | self.fail('Missing expected output "{0}" on line {1}.', 938 | self.output[index][0], self.output[index][1]) 939 | index += 1 940 | 941 | 942 | def fail(self, message, *args): 943 | if args: 944 | message = message.format(*args) 945 | self.failures.append(message) 946 | 947 | 948 | def supports_ansi(): 949 | return sys.platform != 'win32' and sys.stdout.isatty() 950 | 951 | 952 | def color_text(text, color): 953 | """Converts text to a string and wraps it in the ANSI escape sequence for 954 | color, if supported.""" 955 | 956 | if not supports_ansi(): 957 | return str(text) 958 | 959 | return color + str(text) + '\033[0m' 960 | 961 | 962 | def green(text): return color_text(text, '\033[32m') 963 | def pink(text): return color_text(text, '\033[91m') 964 | def red(text): return color_text(text, '\033[31m') 965 | def yellow(text): return color_text(text, '\033[33m') 966 | def gray(text): return color_text(text, '\033[1;30m') 967 | 968 | 969 | def walk(dir, callback): 970 | """ 971 | Walks [dir], and executes [callback] on each file. 972 | """ 973 | 974 | dir = abspath(dir) 975 | for file in sorted(listdir(dir)): 976 | nfile = join(dir, file) 977 | if isdir(nfile): 978 | walk(nfile, callback) 979 | else: 980 | callback(nfile) 981 | 982 | 983 | def print_line(line=None): 984 | if supports_ansi(): 985 | # Erase the line. 986 | print('\033[2K', end='') 987 | # Move the cursor to the beginning. 988 | print('\r', end='') 989 | else: 990 | print() 991 | if line: 992 | print(line, end='') 993 | sys.stdout.flush() 994 | 995 | 996 | def run_script(path): 997 | if "benchmark" in path: return 998 | 999 | global passed 1000 | global failed 1001 | global num_skipped 1002 | 1003 | if (splitext(path)[1] != '.lox'): 1004 | return 1005 | 1006 | # Check if we are just running a subset of the tests. 1007 | if filter_path: 1008 | this_test = relpath(path, join(REPO_DIR, 'test')) 1009 | if not this_test.startswith(filter_path): 1010 | return 1011 | 1012 | # Make a nice short path relative to the working directory. 1013 | 1014 | # Normalize it to use "/" since, among other things, the interpreters expect 1015 | # the argument to use that. 1016 | path = relpath(path).replace("\\", "/") 1017 | 1018 | # Read the test and parse out the expectations. 1019 | test = Test(path) 1020 | 1021 | if not test.parse(): 1022 | # It's a skipped or non-test file. 1023 | return 1024 | 1025 | test.run() 1026 | 1027 | # Display the results. 1028 | if len(test.failures) == 0: 1029 | passed += 1 1030 | print_line(green('PASS') + ': ' + path) 1031 | else: 1032 | failed += 1 1033 | print_line(red('FAIL') + ': ' + path) 1034 | print('') 1035 | for failure in test.failures: 1036 | print(' ' + pink(failure)) 1037 | 1038 | 1039 | def run_suite(name): 1040 | global interpreter 1041 | global passed 1042 | global failed 1043 | global num_skipped 1044 | global expectations 1045 | 1046 | interpreter = INTERPRETERS[name] 1047 | 1048 | passed = 0 1049 | failed = 0 1050 | num_skipped = 0 1051 | expectations = 0 1052 | 1053 | walk(join(REPO_DIR, 'test'), run_script) 1054 | print_line() 1055 | 1056 | if failed == 0: 1057 | print('All ' + green(passed) + ' tests passed (' + str(expectations) + 1058 | ' expectations).') 1059 | else: 1060 | print(green(passed) + ' tests passed. ' + red(failed) + ' tests failed.') 1061 | 1062 | return failed == 0 1063 | 1064 | 1065 | def run_suites(names): 1066 | any_failed = False 1067 | for name in names: 1068 | print('=== {} ==='.format(name)) 1069 | if not run_suite(name): 1070 | any_failed = True 1071 | 1072 | if any_failed: 1073 | sys.exit(1) 1074 | 1075 | 1076 | def main(argv): 1077 | global filter_path 1078 | 1079 | if len(argv) < 1 or len(argv) > 2: 1080 | print('Usage: test.py [filter]') 1081 | sys.exit(1) 1082 | 1083 | if len(argv) == 2: 1084 | filter_path = argv[1] 1085 | 1086 | if not run_suite('jlox'): 1087 | sys.exit(1) 1088 | 1089 | 1090 | if __name__ == '__main__': 1091 | main(sys.argv) 1092 | -------------------------------------------------------------------------------- /test/assignment/associativity.lox: -------------------------------------------------------------------------------- 1 | var a = "a"; 2 | var b = "b"; 3 | var c = "c"; 4 | 5 | // Assignment is right-associative. 6 | a = b = c; 7 | print a; // expect: c 8 | print b; // expect: c 9 | print c; // expect: c 10 | -------------------------------------------------------------------------------- /test/assignment/global.lox: -------------------------------------------------------------------------------- 1 | var a = "before"; 2 | print a; // expect: before 3 | 4 | a = "after"; 5 | print a; // expect: after 6 | 7 | print a = "arg"; // expect: arg 8 | print a; // expect: arg 9 | -------------------------------------------------------------------------------- /test/assignment/grouping.lox: -------------------------------------------------------------------------------- 1 | var a = "a"; 2 | (a) = "value"; // Error at '=': Invalid assignment target. 3 | -------------------------------------------------------------------------------- /test/assignment/infix_operator.lox: -------------------------------------------------------------------------------- 1 | var a = "a"; 2 | var b = "b"; 3 | a + b = "value"; // Error at '=': Invalid assignment target. 4 | -------------------------------------------------------------------------------- /test/assignment/local.lox: -------------------------------------------------------------------------------- 1 | { 2 | var a = "before"; 3 | print a; // expect: before 4 | 5 | a = "after"; 6 | print a; // expect: after 7 | 8 | print a = "arg"; // expect: arg 9 | print a; // expect: arg 10 | } 11 | -------------------------------------------------------------------------------- /test/assignment/prefix_operator.lox: -------------------------------------------------------------------------------- 1 | var a = "a"; 2 | !a = "value"; // Error at '=': Invalid assignment target. 3 | -------------------------------------------------------------------------------- /test/assignment/syntax.lox: -------------------------------------------------------------------------------- 1 | // Assignment on RHS of variable. 2 | var a = "before"; 3 | var c = a = "var"; 4 | print a; // expect: var 5 | print c; // expect: var 6 | -------------------------------------------------------------------------------- /test/assignment/to_this.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | Foo() { 3 | this = "value"; // Error at '=': Invalid assignment target. 4 | } 5 | } 6 | 7 | Foo(); 8 | -------------------------------------------------------------------------------- /test/assignment/undefined.lox: -------------------------------------------------------------------------------- 1 | unknown = "what"; // expect runtime error: Undefined variable 'unknown'. 2 | -------------------------------------------------------------------------------- /test/benchmark/binary_trees.lox: -------------------------------------------------------------------------------- 1 | class Tree { 2 | init(item, depth) { 3 | this.item = item; 4 | this.depth = depth; 5 | if (depth > 0) { 6 | var item2 = item + item; 7 | depth = depth - 1; 8 | this.left = Tree(item2 - 1, depth); 9 | this.right = Tree(item2, depth); 10 | } else { 11 | this.left = nil; 12 | this.right = nil; 13 | } 14 | } 15 | 16 | check() { 17 | if (this.left == nil) { 18 | return this.item; 19 | } 20 | 21 | return this.item + this.left.check() - this.right.check(); 22 | } 23 | } 24 | 25 | var minDepth = 4; 26 | var maxDepth = 12; 27 | var stretchDepth = maxDepth + 1; 28 | 29 | var start = clock(); 30 | 31 | print "stretch tree of depth:"; 32 | print stretchDepth; 33 | print "check:"; 34 | print Tree(0, stretchDepth).check(); 35 | 36 | var longLivedTree = Tree(0, maxDepth); 37 | 38 | // iterations = 2 ** maxDepth 39 | var iterations = 1; 40 | var d = 0; 41 | while (d < maxDepth) { 42 | iterations = iterations * 2; 43 | d = d + 1; 44 | } 45 | 46 | var depth = minDepth; 47 | while (depth < stretchDepth) { 48 | var check = 0; 49 | var i = 1; 50 | while (i <= iterations) { 51 | check = check + Tree(i, depth).check() + Tree(-i, depth).check(); 52 | i = i + 1; 53 | } 54 | 55 | print "num trees:"; 56 | print iterations * 2; 57 | print "depth:"; 58 | print depth; 59 | print "check:"; 60 | print check; 61 | 62 | iterations = iterations / 4; 63 | depth = depth + 2; 64 | } 65 | 66 | print "long lived tree of depth:"; 67 | print maxDepth; 68 | print "check:"; 69 | print longLivedTree.check(); 70 | print "elapsed:"; 71 | print clock() - start; 72 | -------------------------------------------------------------------------------- /test/benchmark/equality.lox: -------------------------------------------------------------------------------- 1 | var i = 0; 2 | 3 | var loopStart = clock(); 4 | 5 | while (i < 10000000) { 6 | i = i + 1; 7 | 8 | 1; 1; 1; 2; 1; nil; 1; "str"; 1; true; 9 | nil; nil; nil; 1; nil; "str"; nil; true; 10 | true; true; true; 1; true; false; true; "str"; true; nil; 11 | "str"; "str"; "str"; "stru"; "str"; 1; "str"; nil; "str"; true; 12 | } 13 | 14 | var loopTime = clock() - loopStart; 15 | 16 | var start = clock(); 17 | 18 | i = 0; 19 | while (i < 10000000) { 20 | i = i + 1; 21 | 22 | 1 == 1; 1 == 2; 1 == nil; 1 == "str"; 1 == true; 23 | nil == nil; nil == 1; nil == "str"; nil == true; 24 | true == true; true == 1; true == false; true == "str"; true == nil; 25 | "str" == "str"; "str" == "stru"; "str" == 1; "str" == nil; "str" == true; 26 | } 27 | 28 | var elapsed = clock() - start; 29 | print "loop"; 30 | print loopTime; 31 | print "elapsed"; 32 | print elapsed; 33 | print "equals"; 34 | print elapsed - loopTime; 35 | -------------------------------------------------------------------------------- /test/benchmark/fib.lox: -------------------------------------------------------------------------------- 1 | fun fib(n) { 2 | if (n < 2) return n; 3 | return fib(n - 2) + fib(n - 1); 4 | } 5 | 6 | var start = clock(); 7 | print fib(30) == 832040; 8 | print clock() - start; 9 | -------------------------------------------------------------------------------- /test/benchmark/invocation.lox: -------------------------------------------------------------------------------- 1 | // This benchmark stresses just method invocation. 2 | 3 | class Foo { 4 | method0() {} 5 | method1() {} 6 | method2() {} 7 | method3() {} 8 | method4() {} 9 | method5() {} 10 | method6() {} 11 | method7() {} 12 | method8() {} 13 | method9() {} 14 | method10() {} 15 | method11() {} 16 | method12() {} 17 | method13() {} 18 | method14() {} 19 | method15() {} 20 | method16() {} 21 | method17() {} 22 | method18() {} 23 | method19() {} 24 | method20() {} 25 | method21() {} 26 | method22() {} 27 | method23() {} 28 | method24() {} 29 | method25() {} 30 | method26() {} 31 | method27() {} 32 | method28() {} 33 | method29() {} 34 | } 35 | 36 | var foo = Foo(); 37 | var start = clock(); 38 | var i = 0; 39 | while (i < 500000) { 40 | foo.method0(); 41 | foo.method1(); 42 | foo.method2(); 43 | foo.method3(); 44 | foo.method4(); 45 | foo.method5(); 46 | foo.method6(); 47 | foo.method7(); 48 | foo.method8(); 49 | foo.method9(); 50 | foo.method10(); 51 | foo.method11(); 52 | foo.method12(); 53 | foo.method13(); 54 | foo.method14(); 55 | foo.method15(); 56 | foo.method16(); 57 | foo.method17(); 58 | foo.method18(); 59 | foo.method19(); 60 | foo.method20(); 61 | foo.method21(); 62 | foo.method22(); 63 | foo.method23(); 64 | foo.method24(); 65 | foo.method25(); 66 | foo.method26(); 67 | foo.method27(); 68 | foo.method28(); 69 | foo.method29(); 70 | i = i + 1; 71 | } 72 | 73 | print clock() - start; 74 | -------------------------------------------------------------------------------- /test/benchmark/method_call.lox: -------------------------------------------------------------------------------- 1 | class Toggle { 2 | init(startState) { 3 | this.state = startState; 4 | } 5 | 6 | value() { return this.state; } 7 | 8 | activate() { 9 | this.state = !this.state; 10 | return this; 11 | } 12 | } 13 | 14 | class NthToggle < Toggle { 15 | init(startState, maxCounter) { 16 | super.init(startState); 17 | this.countMax = maxCounter; 18 | this.count = 0; 19 | } 20 | 21 | activate() { 22 | this.count = this.count + 1; 23 | if (this.count >= this.countMax) { 24 | super.activate(); 25 | this.count = 0; 26 | } 27 | 28 | return this; 29 | } 30 | } 31 | 32 | var start = clock(); 33 | var n = 100000; 34 | var val = true; 35 | var toggle = Toggle(val); 36 | 37 | for (var i = 0; i < n; i = i + 1) { 38 | val = toggle.activate().value(); 39 | val = toggle.activate().value(); 40 | val = toggle.activate().value(); 41 | val = toggle.activate().value(); 42 | val = toggle.activate().value(); 43 | val = toggle.activate().value(); 44 | val = toggle.activate().value(); 45 | val = toggle.activate().value(); 46 | val = toggle.activate().value(); 47 | val = toggle.activate().value(); 48 | } 49 | 50 | print toggle.value(); 51 | 52 | val = true; 53 | var ntoggle = NthToggle(val, 3); 54 | 55 | for (var i = 0; i < n; i = i + 1) { 56 | val = ntoggle.activate().value(); 57 | val = ntoggle.activate().value(); 58 | val = ntoggle.activate().value(); 59 | val = ntoggle.activate().value(); 60 | val = ntoggle.activate().value(); 61 | val = ntoggle.activate().value(); 62 | val = ntoggle.activate().value(); 63 | val = ntoggle.activate().value(); 64 | val = ntoggle.activate().value(); 65 | val = ntoggle.activate().value(); 66 | } 67 | 68 | print ntoggle.value(); 69 | print clock() - start; 70 | -------------------------------------------------------------------------------- /test/benchmark/properties.lox: -------------------------------------------------------------------------------- 1 | // This benchmark stresses both field and method lookup. 2 | 3 | class Foo { 4 | init() { 5 | this.field0 = 1; 6 | this.field1 = 1; 7 | this.field2 = 1; 8 | this.field3 = 1; 9 | this.field4 = 1; 10 | this.field5 = 1; 11 | this.field6 = 1; 12 | this.field7 = 1; 13 | this.field8 = 1; 14 | this.field9 = 1; 15 | this.field10 = 1; 16 | this.field11 = 1; 17 | this.field12 = 1; 18 | this.field13 = 1; 19 | this.field14 = 1; 20 | this.field15 = 1; 21 | this.field16 = 1; 22 | this.field17 = 1; 23 | this.field18 = 1; 24 | this.field19 = 1; 25 | this.field20 = 1; 26 | this.field21 = 1; 27 | this.field22 = 1; 28 | this.field23 = 1; 29 | this.field24 = 1; 30 | this.field25 = 1; 31 | this.field26 = 1; 32 | this.field27 = 1; 33 | this.field28 = 1; 34 | this.field29 = 1; 35 | } 36 | 37 | method0() { return this.field0; } 38 | method1() { return this.field1; } 39 | method2() { return this.field2; } 40 | method3() { return this.field3; } 41 | method4() { return this.field4; } 42 | method5() { return this.field5; } 43 | method6() { return this.field6; } 44 | method7() { return this.field7; } 45 | method8() { return this.field8; } 46 | method9() { return this.field9; } 47 | method10() { return this.field10; } 48 | method11() { return this.field11; } 49 | method12() { return this.field12; } 50 | method13() { return this.field13; } 51 | method14() { return this.field14; } 52 | method15() { return this.field15; } 53 | method16() { return this.field16; } 54 | method17() { return this.field17; } 55 | method18() { return this.field18; } 56 | method19() { return this.field19; } 57 | method20() { return this.field20; } 58 | method21() { return this.field21; } 59 | method22() { return this.field22; } 60 | method23() { return this.field23; } 61 | method24() { return this.field24; } 62 | method25() { return this.field25; } 63 | method26() { return this.field26; } 64 | method27() { return this.field27; } 65 | method28() { return this.field28; } 66 | method29() { return this.field29; } 67 | } 68 | 69 | var foo = Foo(); 70 | var start = clock(); 71 | var i = 0; 72 | while (i < 500000) { 73 | foo.method0(); 74 | foo.method1(); 75 | foo.method2(); 76 | foo.method3(); 77 | foo.method4(); 78 | foo.method5(); 79 | foo.method6(); 80 | foo.method7(); 81 | foo.method8(); 82 | foo.method9(); 83 | foo.method10(); 84 | foo.method11(); 85 | foo.method12(); 86 | foo.method13(); 87 | foo.method14(); 88 | foo.method15(); 89 | foo.method16(); 90 | foo.method17(); 91 | foo.method18(); 92 | foo.method19(); 93 | foo.method20(); 94 | foo.method21(); 95 | foo.method22(); 96 | foo.method23(); 97 | foo.method24(); 98 | foo.method25(); 99 | foo.method26(); 100 | foo.method27(); 101 | foo.method28(); 102 | foo.method29(); 103 | i = i + 1; 104 | } 105 | 106 | print clock() - start; 107 | -------------------------------------------------------------------------------- /test/benchmark/string_equality.lox: -------------------------------------------------------------------------------- 1 | var a1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1"; 2 | var a2 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2"; 3 | var a3 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3"; 4 | var a4 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4"; 5 | var a5 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa5"; 6 | var a6 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa6"; 7 | var a7 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa7"; 8 | var a8 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa8"; 9 | 10 | var i = 0; 11 | 12 | var loopStart = clock(); 13 | 14 | while (i < 100000) { 15 | i = i + 1; 16 | 17 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 18 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 19 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 20 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 21 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 22 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 23 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 24 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 25 | 26 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 27 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 28 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 29 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 30 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 31 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 32 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 33 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 34 | 35 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 36 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 37 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 38 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 39 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 40 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 41 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 42 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 43 | 44 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 45 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 46 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 47 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 48 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 49 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 50 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 51 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 52 | 53 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 54 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 55 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 56 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 57 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 58 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 59 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 60 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 61 | 62 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 63 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 64 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 65 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 66 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 67 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 68 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 69 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 70 | 71 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 72 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 73 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 74 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 75 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 76 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 77 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 78 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 79 | 80 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 81 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 82 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 83 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 84 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 85 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 86 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 87 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 88 | 89 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 90 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 91 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 92 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 93 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 94 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 95 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 96 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 97 | 98 | a1; a1; a1; a2; a1; a3; a1; a4; a1; a5; a1; a6; a1; a7; a1; a8; 99 | a2; a1; a2; a2; a2; a3; a2; a4; a2; a5; a2; a6; a2; a7; a2; a8; 100 | a3; a1; a3; a2; a3; a3; a3; a4; a3; a5; a3; a6; a3; a7; a3; a8; 101 | a4; a1; a4; a2; a4; a3; a4; a4; a4; a5; a4; a6; a4; a7; a4; a8; 102 | a5; a1; a5; a2; a5; a3; a5; a4; a5; a5; a5; a6; a5; a7; a5; a8; 103 | a6; a1; a6; a2; a6; a3; a6; a4; a6; a5; a6; a6; a6; a7; a6; a8; 104 | a7; a1; a7; a2; a7; a3; a7; a4; a7; a5; a7; a6; a7; a7; a7; a8; 105 | a8; a1; a8; a2; a8; a3; a8; a4; a8; a5; a8; a6; a8; a7; a8; a8; 106 | } 107 | 108 | var loopTime = clock() - loopStart; 109 | 110 | var start = clock(); 111 | 112 | i = 0; 113 | while (i < 100000) { 114 | i = i + 1; 115 | 116 | // 1 == 1; 1 == 2; 1 == nil; 1 == "str"; 1 == true; 117 | // nil == nil; nil == 1; nil == "str"; nil == true; 118 | // true == true; true == 1; true == false; true == "str"; true == nil; 119 | // "str" == "str"; "str" == "stru"; "str" == 1; "str" == nil; "str" == true; 120 | 121 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 122 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 123 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 124 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 125 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 126 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 127 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 128 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 129 | 130 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 131 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 132 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 133 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 134 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 135 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 136 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 137 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 138 | 139 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 140 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 141 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 142 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 143 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 144 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 145 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 146 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 147 | 148 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 149 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 150 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 151 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 152 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 153 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 154 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 155 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 156 | 157 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 158 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 159 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 160 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 161 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 162 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 163 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 164 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 165 | 166 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 167 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 168 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 169 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 170 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 171 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 172 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 173 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 174 | 175 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 176 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 177 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 178 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 179 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 180 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 181 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 182 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 183 | 184 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 185 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 186 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 187 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 188 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 189 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 190 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 191 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 192 | 193 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 194 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 195 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 196 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 197 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 198 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 199 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 200 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 201 | 202 | a1 == a1; a1 == a2; a1 == a3; a1 == a4; a1 == a5; a1 == a6; a1 == a7; a1 == a8; 203 | a2 == a1; a2 == a2; a2 == a3; a2 == a4; a2 == a5; a2 == a6; a2 == a7; a2 == a8; 204 | a3 == a1; a3 == a2; a3 == a3; a3 == a4; a3 == a5; a3 == a6; a3 == a7; a3 == a8; 205 | a4 == a1; a4 == a2; a4 == a3; a4 == a4; a4 == a5; a4 == a6; a4 == a7; a4 == a8; 206 | a5 == a1; a5 == a2; a5 == a3; a5 == a4; a5 == a5; a5 == a6; a5 == a7; a5 == a8; 207 | a6 == a1; a6 == a2; a6 == a3; a6 == a4; a6 == a5; a6 == a6; a6 == a7; a6 == a8; 208 | a7 == a1; a7 == a2; a7 == a3; a7 == a4; a7 == a5; a7 == a6; a7 == a7; a7 == a8; 209 | a8 == a1; a8 == a2; a8 == a3; a8 == a4; a8 == a5; a8 == a6; a8 == a7; a8 == a8; 210 | 211 | } 212 | 213 | var elapsed = clock() - start; 214 | print "loop"; 215 | print loopTime; 216 | print "elapsed"; 217 | print elapsed; 218 | print "equals"; 219 | print elapsed - loopTime; 220 | -------------------------------------------------------------------------------- /test/block/empty.lox: -------------------------------------------------------------------------------- 1 | {} // By itself. 2 | 3 | // In a statement. 4 | if (true) {} 5 | if (false) {} else {} 6 | 7 | print "ok"; // expect: ok 8 | -------------------------------------------------------------------------------- /test/block/scope.lox: -------------------------------------------------------------------------------- 1 | var a = "outer"; 2 | 3 | { 4 | var a = "inner"; 5 | print a; // expect: inner 6 | } 7 | 8 | print a; // expect: outer 9 | -------------------------------------------------------------------------------- /test/bool/equality.lox: -------------------------------------------------------------------------------- 1 | print true == true; // expect: true 2 | print true == false; // expect: false 3 | print false == true; // expect: false 4 | print false == false; // expect: true 5 | 6 | // Not equal to other types. 7 | print true == 1; // expect: false 8 | print false == 0; // expect: false 9 | print true == "true"; // expect: false 10 | print false == "false"; // expect: false 11 | print false == ""; // expect: false 12 | 13 | print true != true; // expect: false 14 | print true != false; // expect: true 15 | print false != true; // expect: true 16 | print false != false; // expect: false 17 | 18 | // Not equal to other types. 19 | print true != 1; // expect: true 20 | print false != 0; // expect: true 21 | print true != "true"; // expect: true 22 | print false != "false"; // expect: true 23 | print false != ""; // expect: true 24 | -------------------------------------------------------------------------------- /test/bool/not.lox: -------------------------------------------------------------------------------- 1 | print !true; // expect: false 2 | print !false; // expect: true 3 | print !!true; // expect: true 4 | -------------------------------------------------------------------------------- /test/call/bool.lox: -------------------------------------------------------------------------------- 1 | true(); // expect runtime error: Can only call functions and classes. 2 | -------------------------------------------------------------------------------- /test/call/nil.lox: -------------------------------------------------------------------------------- 1 | nil(); // expect runtime error: Can only call functions and classes. 2 | -------------------------------------------------------------------------------- /test/call/num.lox: -------------------------------------------------------------------------------- 1 | 123(); // expect runtime error: Can only call functions and classes. 2 | -------------------------------------------------------------------------------- /test/call/object.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | var foo = Foo(); 4 | foo(); // expect runtime error: Can only call functions and classes. 5 | -------------------------------------------------------------------------------- /test/call/string.lox: -------------------------------------------------------------------------------- 1 | "str"(); // expect runtime error: Can only call functions and classes. 2 | -------------------------------------------------------------------------------- /test/class/empty.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | print Foo; // expect: Foo 4 | -------------------------------------------------------------------------------- /test/class/inherit_self.lox: -------------------------------------------------------------------------------- 1 | class Foo < Foo {} // expect runtime error: Undefined variable 'Foo'. 2 | -------------------------------------------------------------------------------- /test/class/inherited_method.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | inFoo() { 3 | print "in foo"; 4 | } 5 | } 6 | 7 | class Bar < Foo { 8 | inBar() { 9 | print "in bar"; 10 | } 11 | } 12 | 13 | class Baz < Bar { 14 | inBaz() { 15 | print "in baz"; 16 | } 17 | } 18 | 19 | var baz = Baz(); 20 | baz.inFoo(); // expect: in foo 21 | baz.inBar(); // expect: in bar 22 | baz.inBaz(); // expect: in baz 23 | -------------------------------------------------------------------------------- /test/class/local_inherit_self.lox: -------------------------------------------------------------------------------- 1 | { 2 | class Foo < Foo {} // Error at 'Foo': Cannot read local variable in its own initializer. 3 | } 4 | // [c line 5] Error at end: Expect '}' after block. 5 | -------------------------------------------------------------------------------- /test/class/local_reference_self.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | returnSelf() { 3 | return Foo; 4 | } 5 | } 6 | 7 | print Foo().returnSelf(); // expect: Foo 8 | -------------------------------------------------------------------------------- /test/class/reference_self.lox: -------------------------------------------------------------------------------- 1 | { 2 | class Foo { 3 | returnSelf() { 4 | return Foo; 5 | } 6 | } 7 | 8 | print Foo().returnSelf(); // expect: Foo 9 | } 10 | -------------------------------------------------------------------------------- /test/closure/assign_to_closure.lox: -------------------------------------------------------------------------------- 1 | var f; 2 | var g; 3 | 4 | { 5 | var local = "local"; 6 | fun f_() { 7 | print local; 8 | local = "after f"; 9 | print local; 10 | } 11 | f = f_; 12 | 13 | fun g_() { 14 | print local; 15 | local = "after g"; 16 | print local; 17 | } 18 | g = g_; 19 | } 20 | 21 | f(); 22 | // expect: local 23 | // expect: after f 24 | 25 | g(); 26 | // expect: after f 27 | // expect: after g 28 | -------------------------------------------------------------------------------- /test/closure/assign_to_shadowed_later.lox: -------------------------------------------------------------------------------- 1 | var a = "global"; 2 | 3 | { 4 | fun assign() { 5 | a = "assigned"; 6 | } 7 | 8 | var a = "inner"; 9 | assign(); 10 | print a; // expect: inner 11 | } 12 | 13 | print a; // expect: assigned 14 | -------------------------------------------------------------------------------- /test/closure/close_over_function_parameter.lox: -------------------------------------------------------------------------------- 1 | var f; 2 | 3 | fun foo(param) { 4 | fun f_() { 5 | print param; 6 | } 7 | f = f_; 8 | } 9 | foo("param"); 10 | 11 | f(); // expect: param 12 | -------------------------------------------------------------------------------- /test/closure/close_over_later_variable.lox: -------------------------------------------------------------------------------- 1 | // This is a regression test. There was a bug where if an upvalue for an 2 | // earlier local (here "a") was captured *after* a later one ("b"), then it 3 | // would crash because it walked to the end of the upvalue list (correct), but 4 | // then didn't handle not finding the variable. 5 | 6 | fun f() { 7 | var a = "a"; 8 | var b = "b"; 9 | fun g() { 10 | print b; // expect: b 11 | print a; // expect: a 12 | } 13 | g(); 14 | } 15 | f(); 16 | -------------------------------------------------------------------------------- /test/closure/close_over_method_parameter.lox: -------------------------------------------------------------------------------- 1 | var f; 2 | 3 | class Foo { 4 | method(param) { 5 | fun f_() { 6 | print param; 7 | } 8 | f = f_; 9 | } 10 | } 11 | 12 | Foo().method("param"); 13 | f(); // expect: param 14 | -------------------------------------------------------------------------------- /test/closure/closed_closure_in_function.lox: -------------------------------------------------------------------------------- 1 | var f; 2 | 3 | { 4 | var local = "local"; 5 | fun f_() { 6 | print local; 7 | } 8 | f = f_; 9 | } 10 | 11 | f(); // expect: local 12 | -------------------------------------------------------------------------------- /test/closure/nested_closure.lox: -------------------------------------------------------------------------------- 1 | var f; 2 | 3 | fun f1() { 4 | var a = "a"; 5 | fun f2() { 6 | var b = "b"; 7 | fun f3() { 8 | var c = "c"; 9 | fun f4() { 10 | print a; 11 | print b; 12 | print c; 13 | } 14 | f = f4; 15 | } 16 | f3(); 17 | } 18 | f2(); 19 | } 20 | f1(); 21 | 22 | f(); 23 | // expect: a 24 | // expect: b 25 | // expect: c 26 | -------------------------------------------------------------------------------- /test/closure/open_closure_in_function.lox: -------------------------------------------------------------------------------- 1 | { 2 | var local = "local"; 3 | fun f() { 4 | print local; // expect: local 5 | } 6 | f(); 7 | } 8 | -------------------------------------------------------------------------------- /test/closure/reference_closure_multiple_times.lox: -------------------------------------------------------------------------------- 1 | var f; 2 | 3 | { 4 | var a = "a"; 5 | fun f_() { 6 | print a; 7 | print a; 8 | } 9 | f = f_; 10 | } 11 | 12 | f(); 13 | // expect: a 14 | // expect: a 15 | -------------------------------------------------------------------------------- /test/closure/reuse_closure_slot.lox: -------------------------------------------------------------------------------- 1 | { 2 | var f; 3 | 4 | { 5 | var a = "a"; 6 | fun f_() { print a; } 7 | f = f_; 8 | } 9 | 10 | { 11 | // Since a is out of scope, the local slot will be reused by b. Make sure 12 | // that f still closes over a. 13 | var b = "b"; 14 | f(); // expect: a 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/closure/shadow_closure_with_local.lox: -------------------------------------------------------------------------------- 1 | { 2 | var foo = "closure"; 3 | fun f() { 4 | { 5 | print foo; // expect: closure 6 | var foo = "shadow"; 7 | print foo; // expect: shadow 8 | } 9 | print foo; // expect: closure 10 | } 11 | f(); 12 | } 13 | -------------------------------------------------------------------------------- /test/closure/unused_closure.lox: -------------------------------------------------------------------------------- 1 | // This is a regression test. There was a bug where the VM would try to close 2 | // an upvalue even if the upvalue was never created because the codepath for 3 | // the closure was not executed. 4 | 5 | { 6 | var a = "a"; 7 | if (false) { 8 | fun foo() { a; } 9 | } 10 | } 11 | 12 | // If we get here, we didn't segfault when a went out of scope. 13 | print "ok"; // expect: ok 14 | -------------------------------------------------------------------------------- /test/closure/unused_later_closure.lox: -------------------------------------------------------------------------------- 1 | // This is a regression test. When closing upvalues for discarded locals, it 2 | // wouldn't make sure it discarded the upvalue for the correct stack slot. 3 | // 4 | // Here we create two locals that can be closed over, but only the first one 5 | // actually is. When "b" goes out of scope, we need to make sure we don't 6 | // prematurely close "a". 7 | var closure; 8 | 9 | { 10 | var a = "a"; 11 | 12 | { 13 | var b = "b"; 14 | fun returnA() { 15 | return a; 16 | } 17 | 18 | closure = returnA; 19 | 20 | if (false) { 21 | fun returnB() { 22 | return b; 23 | } 24 | } 25 | } 26 | 27 | print closure(); // expect: a 28 | } 29 | -------------------------------------------------------------------------------- /test/comments/line_at_eof.lox: -------------------------------------------------------------------------------- 1 | print "ok"; // expect: ok 2 | // comment -------------------------------------------------------------------------------- /test/comments/only_line_comment.lox: -------------------------------------------------------------------------------- 1 | // comment -------------------------------------------------------------------------------- /test/comments/only_line_comment_and_line.lox: -------------------------------------------------------------------------------- 1 | // comment 2 | -------------------------------------------------------------------------------- /test/comments/unicode.lox: -------------------------------------------------------------------------------- 1 | // Unicode characters are allowed in comments. 2 | // 3 | // Latin 1 Supplement: £§¶ÜÞ 4 | // Latin Extended-A: ĐĦŋœ 5 | // Latin Extended-B: ƂƢƩǁ 6 | // Other stuff: ឃᢆ᯽₪ℜ↩⊗┺░ 7 | // Emoji: ☃☺♣ 8 | 9 | print "ok"; // expect: ok 10 | -------------------------------------------------------------------------------- /test/constructor/arguments.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init(a, b) { 3 | print "init"; // expect: init 4 | this.a = a; 5 | this.b = b; 6 | } 7 | } 8 | 9 | var foo = Foo(1, 2); 10 | print foo.a; // expect: 1 11 | print foo.b; // expect: 2 12 | -------------------------------------------------------------------------------- /test/constructor/call_init_early_return.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init() { 3 | print "init"; 4 | return; 5 | print "nope"; 6 | } 7 | } 8 | 9 | var foo = Foo(); // expect: init 10 | print foo.init(); // expect: init 11 | // expect: Foo instance 12 | -------------------------------------------------------------------------------- /test/constructor/call_init_explicitly.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init(arg) { 3 | print "Foo.init(" + arg + ")"; 4 | this.field = "init"; 5 | } 6 | } 7 | 8 | var foo = Foo("one"); // expect: Foo.init(one) 9 | foo.field = "field"; 10 | 11 | var foo2 = foo.init("two"); // expect: Foo.init(two) 12 | print foo2; // expect: Foo instance 13 | 14 | // Make sure init() doesn't create a fresh instance. 15 | print foo.field; // expect: init 16 | -------------------------------------------------------------------------------- /test/constructor/default.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | var foo = Foo(); 4 | print foo; // expect: Foo instance 5 | -------------------------------------------------------------------------------- /test/constructor/default_arguments.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | var foo = Foo(1, 2, 3); // expect runtime error: Expected 0 arguments but got 3. 4 | -------------------------------------------------------------------------------- /test/constructor/early_return.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init() { 3 | print "init"; 4 | return; 5 | print "nope"; 6 | } 7 | } 8 | 9 | var foo = Foo(); // expect: init 10 | print foo; // expect: Foo instance 11 | -------------------------------------------------------------------------------- /test/constructor/extra_arguments.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init(a, b) { 3 | this.a = a; 4 | this.b = b; 5 | } 6 | } 7 | 8 | var foo = Foo(1, 2, 3, 4); // expect runtime error: Expected 2 arguments but got 4. -------------------------------------------------------------------------------- /test/constructor/init_not_method.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init(arg) { 3 | print "Foo.init(" + arg + ")"; 4 | this.field = "init"; 5 | } 6 | } 7 | 8 | fun init() { 9 | print "not initializer"; 10 | } 11 | 12 | init(); // expect: not initializer 13 | -------------------------------------------------------------------------------- /test/constructor/missing_arguments.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init(a, b) {} 3 | } 4 | 5 | var foo = Foo(1); // expect runtime error: Expected 2 arguments but got 1. 6 | -------------------------------------------------------------------------------- /test/constructor/return_in_nested_function.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init() { 3 | fun init() { 4 | return "bar"; 5 | } 6 | print init(); // expect: bar 7 | } 8 | } 9 | 10 | print Foo(); // expect: Foo instance 11 | -------------------------------------------------------------------------------- /test/constructor/return_value.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | init() { 3 | return "result"; // Error at 'return': Cannot return a value from an initializer. 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/empty_file.lox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benhoyt/loxlox/78949f75626837f3247aae6ddfb44aed1d0fb7e9/test/empty_file.lox -------------------------------------------------------------------------------- /test/expressions/evaluate.lox: -------------------------------------------------------------------------------- 1 | // Note: This is just for the expression evaluating chapter which evaluates an 2 | // expression directly. 3 | (5 - (3 - 1)) + -1 4 | // expect: 2 5 | -------------------------------------------------------------------------------- /test/expressions/parse.lox: -------------------------------------------------------------------------------- 1 | // Note: This is just for the expression parsing chapter which prints the AST. 2 | (5 - (3 - 1)) + -1 3 | // expect: (+ (group (- 5.0 (group (- 3.0 1.0)))) (- 1.0)) 4 | -------------------------------------------------------------------------------- /test/field/call_function_field.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | fun bar() { 4 | print "bar"; 5 | } 6 | 7 | var foo = Foo(); 8 | foo.bar = bar; 9 | 10 | foo.bar(); // expect: bar 11 | -------------------------------------------------------------------------------- /test/field/call_nonfunction_field.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | var foo = Foo(); 4 | foo.bar = "not fn"; 5 | 6 | foo.bar(); // expect runtime error: Can only call functions and classes. 7 | -------------------------------------------------------------------------------- /test/field/get_and_set_method.lox: -------------------------------------------------------------------------------- 1 | // Bound methods have identity equality. 2 | class Foo { 3 | method() { 4 | print "method"; 5 | } 6 | other() { 7 | print "other"; 8 | } 9 | } 10 | 11 | var foo = Foo(); 12 | var method = foo.method; 13 | 14 | // Setting a property shadows the instance method. 15 | foo.method = foo.other; 16 | foo.method(); // expect: other 17 | 18 | // The old method handle still points to the original method. 19 | method(); // expect: method 20 | -------------------------------------------------------------------------------- /test/field/get_on_bool.lox: -------------------------------------------------------------------------------- 1 | true.foo; // expect runtime error: Only instances have properties. 2 | -------------------------------------------------------------------------------- /test/field/get_on_class.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | Foo.bar; // expect runtime error: Only instances have properties. 3 | -------------------------------------------------------------------------------- /test/field/get_on_function.lox: -------------------------------------------------------------------------------- 1 | fun foo() {} 2 | 3 | foo.bar; // expect runtime error: Only instances have properties. 4 | -------------------------------------------------------------------------------- /test/field/get_on_nil.lox: -------------------------------------------------------------------------------- 1 | nil.foo; // expect runtime error: Only instances have properties. 2 | -------------------------------------------------------------------------------- /test/field/get_on_num.lox: -------------------------------------------------------------------------------- 1 | 123.foo; // expect runtime error: Only instances have properties. 2 | -------------------------------------------------------------------------------- /test/field/get_on_string.lox: -------------------------------------------------------------------------------- 1 | "str".foo; // expect runtime error: Only instances have properties. 2 | -------------------------------------------------------------------------------- /test/field/many.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | var foo = Foo(); 4 | fun setFields() { 5 | foo.bilberry = "bilberry"; 6 | foo.lime = "lime"; 7 | foo.elderberry = "elderberry"; 8 | foo.raspberry = "raspberry"; 9 | foo.gooseberry = "gooseberry"; 10 | foo.longan = "longan"; 11 | foo.mandarine = "mandarine"; 12 | foo.kiwifruit = "kiwifruit"; 13 | foo.orange = "orange"; 14 | foo.pomegranate = "pomegranate"; 15 | foo.tomato = "tomato"; 16 | foo.banana = "banana"; 17 | foo.juniper = "juniper"; 18 | foo.damson = "damson"; 19 | foo.blackcurrant = "blackcurrant"; 20 | foo.peach = "peach"; 21 | foo.grape = "grape"; 22 | foo.mango = "mango"; 23 | foo.redcurrant = "redcurrant"; 24 | foo.watermelon = "watermelon"; 25 | foo.plumcot = "plumcot"; 26 | foo.papaya = "papaya"; 27 | foo.cloudberry = "cloudberry"; 28 | foo.rambutan = "rambutan"; 29 | foo.salak = "salak"; 30 | foo.physalis = "physalis"; 31 | foo.huckleberry = "huckleberry"; 32 | foo.coconut = "coconut"; 33 | foo.date = "date"; 34 | foo.tamarind = "tamarind"; 35 | foo.lychee = "lychee"; 36 | foo.raisin = "raisin"; 37 | foo.apple = "apple"; 38 | foo.avocado = "avocado"; 39 | foo.nectarine = "nectarine"; 40 | foo.pomelo = "pomelo"; 41 | foo.melon = "melon"; 42 | foo.currant = "currant"; 43 | foo.plum = "plum"; 44 | foo.persimmon = "persimmon"; 45 | foo.olive = "olive"; 46 | foo.cranberry = "cranberry"; 47 | foo.boysenberry = "boysenberry"; 48 | foo.blackberry = "blackberry"; 49 | foo.passionfruit = "passionfruit"; 50 | foo.mulberry = "mulberry"; 51 | foo.marionberry = "marionberry"; 52 | foo.plantain = "plantain"; 53 | foo.lemon = "lemon"; 54 | foo.yuzu = "yuzu"; 55 | foo.loquat = "loquat"; 56 | foo.kumquat = "kumquat"; 57 | foo.salmonberry = "salmonberry"; 58 | foo.tangerine = "tangerine"; 59 | foo.durian = "durian"; 60 | foo.pear = "pear"; 61 | foo.cantaloupe = "cantaloupe"; 62 | foo.quince = "quince"; 63 | foo.guava = "guava"; 64 | foo.strawberry = "strawberry"; 65 | foo.nance = "nance"; 66 | foo.apricot = "apricot"; 67 | foo.jambul = "jambul"; 68 | foo.grapefruit = "grapefruit"; 69 | foo.clementine = "clementine"; 70 | foo.jujube = "jujube"; 71 | foo.cherry = "cherry"; 72 | foo.feijoa = "feijoa"; 73 | foo.jackfruit = "jackfruit"; 74 | foo.fig = "fig"; 75 | foo.cherimoya = "cherimoya"; 76 | foo.pineapple = "pineapple"; 77 | foo.blueberry = "blueberry"; 78 | foo.jabuticaba = "jabuticaba"; 79 | foo.miracle = "miracle"; 80 | foo.dragonfruit = "dragonfruit"; 81 | foo.satsuma = "satsuma"; 82 | foo.tamarillo = "tamarillo"; 83 | foo.honeydew = "honeydew"; 84 | } 85 | 86 | setFields(); 87 | 88 | fun printFields() { 89 | print foo.apple; // expect: apple 90 | print foo.apricot; // expect: apricot 91 | print foo.avocado; // expect: avocado 92 | print foo.banana; // expect: banana 93 | print foo.bilberry; // expect: bilberry 94 | print foo.blackberry; // expect: blackberry 95 | print foo.blackcurrant; // expect: blackcurrant 96 | print foo.blueberry; // expect: blueberry 97 | print foo.boysenberry; // expect: boysenberry 98 | print foo.cantaloupe; // expect: cantaloupe 99 | print foo.cherimoya; // expect: cherimoya 100 | print foo.cherry; // expect: cherry 101 | print foo.clementine; // expect: clementine 102 | print foo.cloudberry; // expect: cloudberry 103 | print foo.coconut; // expect: coconut 104 | print foo.cranberry; // expect: cranberry 105 | print foo.currant; // expect: currant 106 | print foo.damson; // expect: damson 107 | print foo.date; // expect: date 108 | print foo.dragonfruit; // expect: dragonfruit 109 | print foo.durian; // expect: durian 110 | print foo.elderberry; // expect: elderberry 111 | print foo.feijoa; // expect: feijoa 112 | print foo.fig; // expect: fig 113 | print foo.gooseberry; // expect: gooseberry 114 | print foo.grape; // expect: grape 115 | print foo.grapefruit; // expect: grapefruit 116 | print foo.guava; // expect: guava 117 | print foo.honeydew; // expect: honeydew 118 | print foo.huckleberry; // expect: huckleberry 119 | print foo.jabuticaba; // expect: jabuticaba 120 | print foo.jackfruit; // expect: jackfruit 121 | print foo.jambul; // expect: jambul 122 | print foo.jujube; // expect: jujube 123 | print foo.juniper; // expect: juniper 124 | print foo.kiwifruit; // expect: kiwifruit 125 | print foo.kumquat; // expect: kumquat 126 | print foo.lemon; // expect: lemon 127 | print foo.lime; // expect: lime 128 | print foo.longan; // expect: longan 129 | print foo.loquat; // expect: loquat 130 | print foo.lychee; // expect: lychee 131 | print foo.mandarine; // expect: mandarine 132 | print foo.mango; // expect: mango 133 | print foo.marionberry; // expect: marionberry 134 | print foo.melon; // expect: melon 135 | print foo.miracle; // expect: miracle 136 | print foo.mulberry; // expect: mulberry 137 | print foo.nance; // expect: nance 138 | print foo.nectarine; // expect: nectarine 139 | print foo.olive; // expect: olive 140 | print foo.orange; // expect: orange 141 | print foo.papaya; // expect: papaya 142 | print foo.passionfruit; // expect: passionfruit 143 | print foo.peach; // expect: peach 144 | print foo.pear; // expect: pear 145 | print foo.persimmon; // expect: persimmon 146 | print foo.physalis; // expect: physalis 147 | print foo.pineapple; // expect: pineapple 148 | print foo.plantain; // expect: plantain 149 | print foo.plum; // expect: plum 150 | print foo.plumcot; // expect: plumcot 151 | print foo.pomegranate; // expect: pomegranate 152 | print foo.pomelo; // expect: pomelo 153 | print foo.quince; // expect: quince 154 | print foo.raisin; // expect: raisin 155 | print foo.rambutan; // expect: rambutan 156 | print foo.raspberry; // expect: raspberry 157 | print foo.redcurrant; // expect: redcurrant 158 | print foo.salak; // expect: salak 159 | print foo.salmonberry; // expect: salmonberry 160 | print foo.satsuma; // expect: satsuma 161 | print foo.strawberry; // expect: strawberry 162 | print foo.tamarillo; // expect: tamarillo 163 | print foo.tamarind; // expect: tamarind 164 | print foo.tangerine; // expect: tangerine 165 | print foo.tomato; // expect: tomato 166 | print foo.watermelon; // expect: watermelon 167 | print foo.yuzu; // expect: yuzu 168 | } 169 | 170 | printFields(); 171 | -------------------------------------------------------------------------------- /test/field/method.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | bar(arg) { 3 | print arg; 4 | } 5 | } 6 | 7 | var bar = Foo().bar; 8 | print "got method"; // expect: got method 9 | bar("arg"); // expect: arg 10 | -------------------------------------------------------------------------------- /test/field/method_binds_this.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | sayName() { 3 | print this.name; 4 | } 5 | } 6 | 7 | var foo1 = Foo(); 8 | foo1.name = "foo1"; 9 | 10 | var foo2 = Foo(); 11 | foo2.name = "foo2"; 12 | 13 | // Store the method reference on another object. 14 | foo2.fn = foo1.sayName; 15 | // Still retains original receiver. 16 | foo2.fn(); // expect: foo1 17 | -------------------------------------------------------------------------------- /test/field/on_instance.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | var foo = Foo(); 4 | 5 | print foo.bar = "bar value"; // expect: bar value 6 | print foo.baz = "baz value"; // expect: baz value 7 | 8 | print foo.bar; // expect: bar value 9 | print foo.baz; // expect: baz value 10 | -------------------------------------------------------------------------------- /test/field/set_evaluation_order.lox: -------------------------------------------------------------------------------- 1 | undefined1.bar // expect runtime error: Undefined variable 'undefined1'. 2 | = undefined2; -------------------------------------------------------------------------------- /test/field/set_on_bool.lox: -------------------------------------------------------------------------------- 1 | true.foo = "value"; // expect runtime error: Only instances have fields. 2 | -------------------------------------------------------------------------------- /test/field/set_on_class.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | Foo.bar = "value"; // expect runtime error: Only instances have fields. 3 | -------------------------------------------------------------------------------- /test/field/set_on_function.lox: -------------------------------------------------------------------------------- 1 | fun foo() {} 2 | 3 | foo.bar = "value"; // expect runtime error: Only instances have fields. 4 | -------------------------------------------------------------------------------- /test/field/set_on_nil.lox: -------------------------------------------------------------------------------- 1 | nil.foo = "value"; // expect runtime error: Only instances have fields. 2 | -------------------------------------------------------------------------------- /test/field/set_on_num.lox: -------------------------------------------------------------------------------- 1 | 123.foo = "value"; // expect runtime error: Only instances have fields. 2 | -------------------------------------------------------------------------------- /test/field/set_on_string.lox: -------------------------------------------------------------------------------- 1 | "str".foo = "value"; // expect runtime error: Only instances have fields. 2 | -------------------------------------------------------------------------------- /test/field/undefined.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | var foo = Foo(); 3 | 4 | foo.bar; // expect runtime error: Undefined property 'bar'. 5 | -------------------------------------------------------------------------------- /test/for/class_in_body.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'class': Expect expression. 2 | for (;;) class Foo {} 3 | -------------------------------------------------------------------------------- /test/for/closure_in_body.lox: -------------------------------------------------------------------------------- 1 | var f1; 2 | var f2; 3 | var f3; 4 | 5 | for (var i = 1; i < 4; i = i + 1) { 6 | var j = i; 7 | fun f() { print j; } 8 | 9 | if (j == 1) f1 = f; 10 | else if (j == 2) f2 = f; 11 | else f3 = f; 12 | } 13 | 14 | f1(); // expect: 1 15 | f2(); // expect: 2 16 | f3(); // expect: 3 17 | -------------------------------------------------------------------------------- /test/for/fun_in_body.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'fun': Expect expression. 2 | for (;;) fun foo() {} 3 | -------------------------------------------------------------------------------- /test/for/return_closure.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | for (;;) { 3 | var i = "i"; 4 | fun g() { print i; } 5 | return g; 6 | } 7 | } 8 | 9 | var h = f(); 10 | h(); // expect: i 11 | -------------------------------------------------------------------------------- /test/for/return_inside.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | for (;;) { 3 | var i = "i"; 4 | return i; 5 | } 6 | } 7 | 8 | print f(); 9 | // expect: i 10 | -------------------------------------------------------------------------------- /test/for/scope.lox: -------------------------------------------------------------------------------- 1 | { 2 | var i = "before"; 3 | 4 | // New variable is in inner scope. 5 | for (var i = 0; i < 1; i = i + 1) { 6 | print i; // expect: 0 7 | 8 | // Loop body is in second inner scope. 9 | var i = -1; 10 | print i; // expect: -1 11 | } 12 | } 13 | 14 | { 15 | // New variable shadows outer variable. 16 | for (var i = 0; i > 0; i = i + 1) {} 17 | 18 | // Goes out of scope after loop. 19 | var i = "after"; 20 | print i; // expect: after 21 | 22 | // Can reuse an existing variable. 23 | for (i = 0; i < 1; i = i + 1) { 24 | print i; // expect: 0 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/for/statement_condition.lox: -------------------------------------------------------------------------------- 1 | // [line 3] Error at '{': Expect expression. 2 | // [line 3] Error at ')': Expect ';' after expression. 3 | for (var a = 1; {}; a = a + 1) {} 4 | -------------------------------------------------------------------------------- /test/for/statement_increment.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at '{': Expect expression. 2 | for (var a = 1; a < 2; {}) {} 3 | -------------------------------------------------------------------------------- /test/for/statement_initializer.lox: -------------------------------------------------------------------------------- 1 | // [line 3] Error at '{': Expect expression. 2 | // [line 3] Error at ')': Expect ';' after expression. 3 | for ({}; a < 2; a = a + 1) {} 4 | -------------------------------------------------------------------------------- /test/for/syntax.lox: -------------------------------------------------------------------------------- 1 | // Single-expression body. 2 | for (var c = 0; c < 3;) print c = c + 1; 3 | // expect: 1 4 | // expect: 2 5 | // expect: 3 6 | 7 | // Block body. 8 | for (var a = 0; a < 3; a = a + 1) { 9 | print a; 10 | } 11 | // expect: 0 12 | // expect: 1 13 | // expect: 2 14 | 15 | // No clauses. 16 | fun foo() { 17 | for (;;) return "done"; 18 | } 19 | print foo(); // expect: done 20 | 21 | // No variable. 22 | var i = 0; 23 | for (; i < 2; i = i + 1) print i; 24 | // expect: 0 25 | // expect: 1 26 | 27 | // No condition. 28 | fun bar() { 29 | for (var i = 0;; i = i + 1) { 30 | print i; 31 | if (i >= 2) return; 32 | } 33 | } 34 | bar(); 35 | // expect: 0 36 | // expect: 1 37 | // expect: 2 38 | 39 | // No increment. 40 | for (var i = 0; i < 2;) { 41 | print i; 42 | i = i + 1; 43 | } 44 | // expect: 0 45 | // expect: 1 46 | 47 | // Statement bodies. 48 | for (; false;) if (true) 1; else 2; 49 | for (; false;) while (true) 1; 50 | for (; false;) for (;;) 1; 51 | -------------------------------------------------------------------------------- /test/for/var_in_body.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'var': Expect expression. 2 | for (;;) var foo; 3 | -------------------------------------------------------------------------------- /test/function/body_must_be_block.lox: -------------------------------------------------------------------------------- 1 | // [line 3] Error at '123': Expect '{' before function body. 2 | // [c line 4] Error at end: Expect '}' after block. 3 | fun f() 123; 4 | -------------------------------------------------------------------------------- /test/function/empty_body.lox: -------------------------------------------------------------------------------- 1 | fun f() {} 2 | print f(); // expect: nil 3 | -------------------------------------------------------------------------------- /test/function/extra_arguments.lox: -------------------------------------------------------------------------------- 1 | fun f(a, b) { 2 | print a; 3 | print b; 4 | } 5 | 6 | f(1, 2, 3, 4); // expect runtime error: Expected 2 arguments but got 4. 7 | -------------------------------------------------------------------------------- /test/function/local_mutual_recursion.lox: -------------------------------------------------------------------------------- 1 | { 2 | fun isEven(n) { 3 | if (n == 0) return true; 4 | return isOdd(n - 1); // expect runtime error: Undefined variable 'isOdd'. 5 | } 6 | 7 | fun isOdd(n) { 8 | return isEven(n - 1); 9 | } 10 | 11 | isEven(4); 12 | } 13 | -------------------------------------------------------------------------------- /test/function/local_recursion.lox: -------------------------------------------------------------------------------- 1 | { 2 | fun fib(n) { 3 | if (n < 2) return n; 4 | return fib(n - 1) + fib(n - 2); 5 | } 6 | 7 | print fib(8); // expect: 21 8 | } 9 | -------------------------------------------------------------------------------- /test/function/missing_arguments.lox: -------------------------------------------------------------------------------- 1 | fun f(a, b) {} 2 | 3 | f(1); // expect runtime error: Expected 2 arguments but got 1. 4 | -------------------------------------------------------------------------------- /test/function/missing_comma_in_parameters.lox: -------------------------------------------------------------------------------- 1 | // [line 3] Error at 'c': Expect ')' after parameters. 2 | // [c line 4] Error at end: Expect '}' after block. 3 | fun foo(a, b c, d, e, f) {} 4 | -------------------------------------------------------------------------------- /test/function/mutual_recursion.lox: -------------------------------------------------------------------------------- 1 | fun isEven(n) { 2 | if (n == 0) return true; 3 | return isOdd(n - 1); 4 | } 5 | 6 | fun isOdd(n) { 7 | return isEven(n - 1); 8 | } 9 | 10 | print isEven(4); // expect: true 11 | print isOdd(3); // expect: true 12 | -------------------------------------------------------------------------------- /test/function/parameters.lox: -------------------------------------------------------------------------------- 1 | fun f0() { return 0; } 2 | print f0(); // expect: 0 3 | 4 | fun f1(a) { return a; } 5 | print f1(1); // expect: 1 6 | 7 | fun f2(a, b) { return a + b; } 8 | print f2(1, 2); // expect: 3 9 | 10 | fun f3(a, b, c) { return a + b + c; } 11 | print f3(1, 2, 3); // expect: 6 12 | 13 | fun f4(a, b, c, d) { return a + b + c + d; } 14 | print f4(1, 2, 3, 4); // expect: 10 15 | 16 | fun f5(a, b, c, d, e) { return a + b + c + d + e; } 17 | print f5(1, 2, 3, 4, 5); // expect: 15 18 | 19 | fun f6(a, b, c, d, e, f) { return a + b + c + d + e + f; } 20 | print f6(1, 2, 3, 4, 5, 6); // expect: 21 21 | 22 | fun f7(a, b, c, d, e, f, g) { return a + b + c + d + e + f + g; } 23 | print f7(1, 2, 3, 4, 5, 6, 7); // expect: 28 24 | 25 | fun f8(a, b, c, d, e, f, g, h) { return a + b + c + d + e + f + g + h; } 26 | print f8(1, 2, 3, 4, 5, 6, 7, 8); // expect: 36 27 | -------------------------------------------------------------------------------- /test/function/print.lox: -------------------------------------------------------------------------------- 1 | fun foo() {} 2 | print foo; // expect: 3 | 4 | print clock; // expect: 5 | -------------------------------------------------------------------------------- /test/function/recursion.lox: -------------------------------------------------------------------------------- 1 | fun fib(n) { 2 | if (n < 2) return n; 3 | return fib(n - 1) + fib(n - 2); 4 | } 5 | 6 | print fib(8); // expect: 21 7 | -------------------------------------------------------------------------------- /test/function/too_many_arguments.lox: -------------------------------------------------------------------------------- 1 | foo(1, 2, 3, 4, 5, 6, 7, 8, 9); // Error at '9': Cannot have more than 8 arguments. 2 | -------------------------------------------------------------------------------- /test/function/too_many_parameters.lox: -------------------------------------------------------------------------------- 1 | // 9 parameters. 2 | fun f(a, b, c, d, e, f, g, h, i) {} // Error at 'i': Cannot have more than 8 parameters. 3 | -------------------------------------------------------------------------------- /test/if/class_in_else.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'class': Expect expression. 2 | if (true) "ok"; else class Foo {} 3 | -------------------------------------------------------------------------------- /test/if/class_in_then.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'class': Expect expression. 2 | if (true) class Foo {} 3 | -------------------------------------------------------------------------------- /test/if/dangling_else.lox: -------------------------------------------------------------------------------- 1 | // A dangling else binds to the right-most if. 2 | if (true) if (false) print "bad"; else print "good"; // expect: good 3 | if (false) if (true) print "bad"; else print "bad"; 4 | -------------------------------------------------------------------------------- /test/if/else.lox: -------------------------------------------------------------------------------- 1 | // Evaluate the 'else' expression if the condition is false. 2 | if (true) print "good"; else print "bad"; // expect: good 3 | if (false) print "bad"; else print "good"; // expect: good 4 | 5 | // Allow block body. 6 | if (false) nil; else { print "block"; } // expect: block 7 | -------------------------------------------------------------------------------- /test/if/fun_in_else.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'fun': Expect expression. 2 | if (true) "ok"; else fun foo() {} 3 | -------------------------------------------------------------------------------- /test/if/fun_in_then.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'fun': Expect expression. 2 | if (true) fun foo() {} 3 | -------------------------------------------------------------------------------- /test/if/if.lox: -------------------------------------------------------------------------------- 1 | // Evaluate the 'then' expression if the condition is true. 2 | if (true) print "good"; // expect: good 3 | if (false) print "bad"; 4 | 5 | // Allow block body. 6 | if (true) { print "block"; } // expect: block 7 | 8 | // Assignment in if condition. 9 | var a = false; 10 | if (a = true) print a; // expect: true 11 | -------------------------------------------------------------------------------- /test/if/truth.lox: -------------------------------------------------------------------------------- 1 | // False and nil are false. 2 | if (false) print "bad"; else print "false"; // expect: false 3 | if (nil) print "bad"; else print "nil"; // expect: nil 4 | 5 | // Everything else is true. 6 | if (true) print true; // expect: true 7 | if (0) print 0; // expect: 0 8 | if ("") print "empty"; // expect: empty 9 | -------------------------------------------------------------------------------- /test/if/var_in_else.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'var': Expect expression. 2 | if (true) "ok"; else var foo; 3 | -------------------------------------------------------------------------------- /test/if/var_in_then.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'var': Expect expression. 2 | if (true) var foo; 3 | -------------------------------------------------------------------------------- /test/inheritance/inherit_from_function.lox: -------------------------------------------------------------------------------- 1 | fun foo() {} 2 | 3 | class Subclass < foo {} // expect runtime error: Superclass must be a class. 4 | -------------------------------------------------------------------------------- /test/inheritance/inherit_from_nil.lox: -------------------------------------------------------------------------------- 1 | var Nil = nil; 2 | class Foo < Nil {} // expect runtime error: Superclass must be a class. 3 | -------------------------------------------------------------------------------- /test/inheritance/inherit_from_number.lox: -------------------------------------------------------------------------------- 1 | var Number = 123; 2 | class Foo < Number {} // expect runtime error: Superclass must be a class. 3 | -------------------------------------------------------------------------------- /test/inheritance/inherit_methods.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | methodOnFoo() { print "foo"; } 3 | override() { print "foo"; } 4 | } 5 | 6 | class Bar < Foo { 7 | methodOnBar() { print "bar"; } 8 | override() { print "bar"; } 9 | } 10 | 11 | var bar = Bar(); 12 | bar.methodOnFoo(); // expect: foo 13 | bar.methodOnBar(); // expect: bar 14 | bar.override(); // expect: bar 15 | -------------------------------------------------------------------------------- /test/inheritance/parenthesized_superclass.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | // [line 4] Error at '(': Expect superclass name. 4 | class Bar < (Foo) {} 5 | -------------------------------------------------------------------------------- /test/inheritance/set_fields_from_base_class.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | foo(a, b) { 3 | this.field1 = a; 4 | this.field2 = b; 5 | } 6 | 7 | fooPrint() { 8 | print this.field1; 9 | print this.field2; 10 | } 11 | } 12 | 13 | class Bar < Foo { 14 | bar(a, b) { 15 | this.field1 = a; 16 | this.field2 = b; 17 | } 18 | 19 | barPrint() { 20 | print this.field1; 21 | print this.field2; 22 | } 23 | } 24 | 25 | var bar = Bar(); 26 | bar.foo("foo 1", "foo 2"); 27 | bar.fooPrint(); 28 | // expect: foo 1 29 | // expect: foo 2 30 | 31 | bar.bar("bar 1", "bar 2"); 32 | bar.barPrint(); 33 | // expect: bar 1 34 | // expect: bar 2 35 | 36 | bar.fooPrint(); 37 | // expect: bar 1 38 | // expect: bar 2 39 | -------------------------------------------------------------------------------- /test/limit/no_reuse_constants.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | 0; 1; 2; 3; 4; 5; 6; 7; 3 | 8; 9; 10; 11; 12; 13; 14; 15; 4 | 16; 17; 18; 19; 20; 21; 22; 23; 5 | 24; 25; 26; 27; 28; 29; 30; 31; 6 | 32; 33; 34; 35; 36; 37; 38; 39; 7 | 40; 41; 42; 43; 44; 45; 46; 47; 8 | 48; 49; 50; 51; 52; 53; 54; 55; 9 | 56; 57; 58; 59; 60; 61; 62; 63; 10 | 64; 65; 66; 67; 68; 69; 70; 71; 11 | 72; 73; 74; 75; 76; 77; 78; 79; 12 | 80; 81; 82; 83; 84; 85; 86; 87; 13 | 88; 89; 90; 91; 92; 93; 94; 95; 14 | 96; 97; 98; 99; 100; 101; 102; 103; 15 | 104; 105; 106; 107; 108; 109; 110; 111; 16 | 112; 113; 114; 115; 116; 117; 118; 119; 17 | 120; 121; 122; 123; 124; 125; 126; 127; 18 | 128; 129; 130; 131; 132; 133; 134; 135; 19 | 136; 137; 138; 139; 140; 141; 142; 143; 20 | 144; 145; 146; 147; 148; 149; 150; 151; 21 | 152; 153; 154; 155; 156; 157; 158; 159; 22 | 160; 161; 162; 163; 164; 165; 166; 167; 23 | 168; 169; 170; 171; 172; 173; 174; 175; 24 | 176; 177; 178; 179; 180; 181; 182; 183; 25 | 184; 185; 186; 187; 188; 189; 190; 191; 26 | 192; 193; 194; 195; 196; 197; 198; 199; 27 | 200; 201; 202; 203; 204; 205; 206; 207; 28 | 208; 209; 210; 211; 212; 213; 214; 215; 29 | 216; 217; 218; 219; 220; 221; 222; 223; 30 | 224; 225; 226; 227; 228; 229; 230; 231; 31 | 232; 233; 234; 235; 236; 237; 238; 239; 32 | 240; 241; 242; 243; 244; 245; 246; 247; 33 | 248; 249; 250; 251; 252; 253; 254; 255; 34 | 35 | 1; // Error at '1': Too many constants in one chunk. 36 | } 37 | -------------------------------------------------------------------------------- /test/limit/stack_overflow.lox: -------------------------------------------------------------------------------- 1 | fun foo() { 2 | var a1; 3 | var a2; 4 | var a3; 5 | var a4; 6 | var a5; 7 | var a6; 8 | var a7; 9 | var a8; 10 | var a9; 11 | var a10; 12 | var a11; 13 | var a12; 14 | var a13; 15 | var a14; 16 | var a15; 17 | var a16; 18 | foo(); // expect runtime error: Stack overflow. 19 | } 20 | 21 | foo(); 22 | -------------------------------------------------------------------------------- /test/limit/too_many_constants.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | 0; 1; 2; 3; 4; 5; 6; 7; 3 | 8; 9; 10; 11; 12; 13; 14; 15; 4 | 16; 17; 18; 19; 20; 21; 22; 23; 5 | 24; 25; 26; 27; 28; 29; 30; 31; 6 | 32; 33; 34; 35; 36; 37; 38; 39; 7 | 40; 41; 42; 43; 44; 45; 46; 47; 8 | 48; 49; 50; 51; 52; 53; 54; 55; 9 | 56; 57; 58; 59; 60; 61; 62; 63; 10 | 64; 65; 66; 67; 68; 69; 70; 71; 11 | 72; 73; 74; 75; 76; 77; 78; 79; 12 | 80; 81; 82; 83; 84; 85; 86; 87; 13 | 88; 89; 90; 91; 92; 93; 94; 95; 14 | 96; 97; 98; 99; 100; 101; 102; 103; 15 | 104; 105; 106; 107; 108; 109; 110; 111; 16 | 112; 113; 114; 115; 116; 117; 118; 119; 17 | 120; 121; 122; 123; 124; 125; 126; 127; 18 | 128; 129; 130; 131; 132; 133; 134; 135; 19 | 136; 137; 138; 139; 140; 141; 142; 143; 20 | 144; 145; 146; 147; 148; 149; 150; 151; 21 | 152; 153; 154; 155; 156; 157; 158; 159; 22 | 160; 161; 162; 163; 164; 165; 166; 167; 23 | 168; 169; 170; 171; 172; 173; 174; 175; 24 | 176; 177; 178; 179; 180; 181; 182; 183; 25 | 184; 185; 186; 187; 188; 189; 190; 191; 26 | 192; 193; 194; 195; 196; 197; 198; 199; 27 | 200; 201; 202; 203; 204; 205; 206; 207; 28 | 208; 209; 210; 211; 212; 213; 214; 215; 29 | 216; 217; 218; 219; 220; 221; 222; 223; 30 | 224; 225; 226; 227; 228; 229; 230; 231; 31 | 232; 233; 234; 235; 236; 237; 238; 239; 32 | 240; 241; 242; 243; 244; 245; 246; 247; 33 | 248; 249; 250; 251; 252; 253; 254; 255; 34 | 35 | "oops"; // Error at '"oops"': Too many constants in one chunk. 36 | } 37 | -------------------------------------------------------------------------------- /test/limit/too_many_locals.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | // var v00; First slot already taken. 3 | 4 | var v01; var v02; var v03; var v04; var v05; var v06; var v07; 5 | var v08; var v09; var v0a; var v0b; var v0c; var v0d; var v0e; var v0f; 6 | 7 | var v10; var v11; var v12; var v13; var v14; var v15; var v16; var v17; 8 | var v18; var v19; var v1a; var v1b; var v1c; var v1d; var v1e; var v1f; 9 | 10 | var v20; var v21; var v22; var v23; var v24; var v25; var v26; var v27; 11 | var v28; var v29; var v2a; var v2b; var v2c; var v2d; var v2e; var v2f; 12 | 13 | var v30; var v31; var v32; var v33; var v34; var v35; var v36; var v37; 14 | var v38; var v39; var v3a; var v3b; var v3c; var v3d; var v3e; var v3f; 15 | 16 | var v40; var v41; var v42; var v43; var v44; var v45; var v46; var v47; 17 | var v48; var v49; var v4a; var v4b; var v4c; var v4d; var v4e; var v4f; 18 | 19 | var v50; var v51; var v52; var v53; var v54; var v55; var v56; var v57; 20 | var v58; var v59; var v5a; var v5b; var v5c; var v5d; var v5e; var v5f; 21 | 22 | var v60; var v61; var v62; var v63; var v64; var v65; var v66; var v67; 23 | var v68; var v69; var v6a; var v6b; var v6c; var v6d; var v6e; var v6f; 24 | 25 | var v70; var v71; var v72; var v73; var v74; var v75; var v76; var v77; 26 | var v78; var v79; var v7a; var v7b; var v7c; var v7d; var v7e; var v7f; 27 | 28 | var v80; var v81; var v82; var v83; var v84; var v85; var v86; var v87; 29 | var v88; var v89; var v8a; var v8b; var v8c; var v8d; var v8e; var v8f; 30 | 31 | var v90; var v91; var v92; var v93; var v94; var v95; var v96; var v97; 32 | var v98; var v99; var v9a; var v9b; var v9c; var v9d; var v9e; var v9f; 33 | 34 | var va0; var va1; var va2; var va3; var va4; var va5; var va6; var va7; 35 | var va8; var va9; var vaa; var vab; var vac; var vad; var vae; var vaf; 36 | 37 | var vb0; var vb1; var vb2; var vb3; var vb4; var vb5; var vb6; var vb7; 38 | var vb8; var vb9; var vba; var vbb; var vbc; var vbd; var vbe; var vbf; 39 | 40 | var vc0; var vc1; var vc2; var vc3; var vc4; var vc5; var vc6; var vc7; 41 | var vc8; var vc9; var vca; var vcb; var vcc; var vcd; var vce; var vcf; 42 | 43 | var vd0; var vd1; var vd2; var vd3; var vd4; var vd5; var vd6; var vd7; 44 | var vd8; var vd9; var vda; var vdb; var vdc; var vdd; var vde; var vdf; 45 | 46 | var ve0; var ve1; var ve2; var ve3; var ve4; var ve5; var ve6; var ve7; 47 | var ve8; var ve9; var vea; var veb; var vec; var ved; var vee; var vef; 48 | 49 | var vf0; var vf1; var vf2; var vf3; var vf4; var vf5; var vf6; var vf7; 50 | var vf8; var vf9; var vfa; var vfb; var vfc; var vfd; var vfe; var vff; 51 | 52 | var oops; // Error at 'oops': Too many local variables in function. 53 | } 54 | -------------------------------------------------------------------------------- /test/limit/too_many_upvalues.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | var v00; var v01; var v02; var v03; var v04; var v05; var v06; var v07; 3 | var v08; var v09; var v0a; var v0b; var v0c; var v0d; var v0e; var v0f; 4 | 5 | var v10; var v11; var v12; var v13; var v14; var v15; var v16; var v17; 6 | var v18; var v19; var v1a; var v1b; var v1c; var v1d; var v1e; var v1f; 7 | 8 | var v20; var v21; var v22; var v23; var v24; var v25; var v26; var v27; 9 | var v28; var v29; var v2a; var v2b; var v2c; var v2d; var v2e; var v2f; 10 | 11 | var v30; var v31; var v32; var v33; var v34; var v35; var v36; var v37; 12 | var v38; var v39; var v3a; var v3b; var v3c; var v3d; var v3e; var v3f; 13 | 14 | var v40; var v41; var v42; var v43; var v44; var v45; var v46; var v47; 15 | var v48; var v49; var v4a; var v4b; var v4c; var v4d; var v4e; var v4f; 16 | 17 | var v50; var v51; var v52; var v53; var v54; var v55; var v56; var v57; 18 | var v58; var v59; var v5a; var v5b; var v5c; var v5d; var v5e; var v5f; 19 | 20 | var v60; var v61; var v62; var v63; var v64; var v65; var v66; var v67; 21 | var v68; var v69; var v6a; var v6b; var v6c; var v6d; var v6e; var v6f; 22 | 23 | var v70; var v71; var v72; var v73; var v74; var v75; var v76; var v77; 24 | var v78; var v79; var v7a; var v7b; var v7c; var v7d; var v7e; var v7f; 25 | 26 | fun g() { 27 | var v80; var v81; var v82; var v83; var v84; var v85; var v86; var v87; 28 | var v88; var v89; var v8a; var v8b; var v8c; var v8d; var v8e; var v8f; 29 | 30 | var v90; var v91; var v92; var v93; var v94; var v95; var v96; var v97; 31 | var v98; var v99; var v9a; var v9b; var v9c; var v9d; var v9e; var v9f; 32 | 33 | var va0; var va1; var va2; var va3; var va4; var va5; var va6; var va7; 34 | var va8; var va9; var vaa; var vab; var vac; var vad; var vae; var vaf; 35 | 36 | var vb0; var vb1; var vb2; var vb3; var vb4; var vb5; var vb6; var vb7; 37 | var vb8; var vb9; var vba; var vbb; var vbc; var vbd; var vbe; var vbf; 38 | 39 | var vc0; var vc1; var vc2; var vc3; var vc4; var vc5; var vc6; var vc7; 40 | var vc8; var vc9; var vca; var vcb; var vcc; var vcd; var vce; var vcf; 41 | 42 | var vd0; var vd1; var vd2; var vd3; var vd4; var vd5; var vd6; var vd7; 43 | var vd8; var vd9; var vda; var vdb; var vdc; var vdd; var vde; var vdf; 44 | 45 | var ve0; var ve1; var ve2; var ve3; var ve4; var ve5; var ve6; var ve7; 46 | var ve8; var ve9; var vea; var veb; var vec; var ved; var vee; var vef; 47 | 48 | var vf0; var vf1; var vf2; var vf3; var vf4; var vf5; var vf6; var vf7; 49 | var vf8; var vf9; var vfa; var vfb; var vfc; var vfd; var vfe; var vff; 50 | 51 | var oops; 52 | 53 | fun h() { 54 | v00; v01; v02; v03; v04; v05; v06; v07; 55 | v08; v09; v0a; v0b; v0c; v0d; v0e; v0f; 56 | 57 | v10; v11; v12; v13; v14; v15; v16; v17; 58 | v18; v19; v1a; v1b; v1c; v1d; v1e; v1f; 59 | 60 | v20; v21; v22; v23; v24; v25; v26; v27; 61 | v28; v29; v2a; v2b; v2c; v2d; v2e; v2f; 62 | 63 | v30; v31; v32; v33; v34; v35; v36; v37; 64 | v38; v39; v3a; v3b; v3c; v3d; v3e; v3f; 65 | 66 | v40; v41; v42; v43; v44; v45; v46; v47; 67 | v48; v49; v4a; v4b; v4c; v4d; v4e; v4f; 68 | 69 | v50; v51; v52; v53; v54; v55; v56; v57; 70 | v58; v59; v5a; v5b; v5c; v5d; v5e; v5f; 71 | 72 | v60; v61; v62; v63; v64; v65; v66; v67; 73 | v68; v69; v6a; v6b; v6c; v6d; v6e; v6f; 74 | 75 | v70; v71; v72; v73; v74; v75; v76; v77; 76 | v78; v79; v7a; v7b; v7c; v7d; v7e; v7f; 77 | 78 | v80; v81; v82; v83; v84; v85; v86; v87; 79 | v88; v89; v8a; v8b; v8c; v8d; v8e; v8f; 80 | 81 | v90; v91; v92; v93; v94; v95; v96; v97; 82 | v98; v99; v9a; v9b; v9c; v9d; v9e; v9f; 83 | 84 | va0; va1; va2; va3; va4; va5; va6; va7; 85 | va8; va9; vaa; vab; vac; vad; vae; vaf; 86 | 87 | vb0; vb1; vb2; vb3; vb4; vb5; vb6; vb7; 88 | vb8; vb9; vba; vbb; vbc; vbd; vbe; vbf; 89 | 90 | vc0; vc1; vc2; vc3; vc4; vc5; vc6; vc7; 91 | vc8; vc9; vca; vcb; vcc; vcd; vce; vcf; 92 | 93 | vd0; vd1; vd2; vd3; vd4; vd5; vd6; vd7; 94 | vd8; vd9; vda; vdb; vdc; vdd; vde; vdf; 95 | 96 | ve0; ve1; ve2; ve3; ve4; ve5; ve6; ve7; 97 | ve8; ve9; vea; veb; vec; ved; vee; vef; 98 | 99 | vf0; vf1; vf2; vf3; vf4; vf5; vf6; vf7; 100 | vf8; vf9; vfa; vfb; vfc; vfd; vfe; vff; 101 | 102 | oops; // Error at 'oops': Too many closure variables in function. 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /test/logical_operator/and.lox: -------------------------------------------------------------------------------- 1 | // Note: These tests implicitly depend on ints being truthy. 2 | 3 | // Return the first non-true argument. 4 | print false and 1; // expect: false 5 | print true and 1; // expect: 1 6 | print 1 and 2 and false; // expect: false 7 | 8 | // Return the last argument if all are true. 9 | print 1 and true; // expect: true 10 | print 1 and 2 and 3; // expect: 3 11 | 12 | // Short-circuit at the first false argument. 13 | var a = "before"; 14 | var b = "before"; 15 | (a = true) and 16 | (b = false) and 17 | (a = "bad"); 18 | print a; // expect: true 19 | print b; // expect: false 20 | -------------------------------------------------------------------------------- /test/logical_operator/and_truth.lox: -------------------------------------------------------------------------------- 1 | // False and nil are false. 2 | print false and "bad"; // expect: false 3 | print nil and "bad"; // expect: nil 4 | 5 | // Everything else is true. 6 | print true and "ok"; // expect: ok 7 | print 0 and "ok"; // expect: ok 8 | print "" and "ok"; // expect: ok 9 | -------------------------------------------------------------------------------- /test/logical_operator/or.lox: -------------------------------------------------------------------------------- 1 | // Note: These tests implicitly depend on ints being truthy. 2 | 3 | // Return the first true argument. 4 | print 1 or true; // expect: 1 5 | print false or 1; // expect: 1 6 | print false or false or true; // expect: true 7 | 8 | // Return the last argument if all are false. 9 | print false or false; // expect: false 10 | print false or false or false; // expect: false 11 | 12 | // Short-circuit at the first true argument. 13 | var a = "before"; 14 | var b = "before"; 15 | (a = false) or 16 | (b = true) or 17 | (a = "bad"); 18 | print a; // expect: false 19 | print b; // expect: true 20 | -------------------------------------------------------------------------------- /test/logical_operator/or_truth.lox: -------------------------------------------------------------------------------- 1 | // False and nil are false. 2 | print false or "ok"; // expect: ok 3 | print nil or "ok"; // expect: ok 4 | 5 | // Everything else is true. 6 | print true or "ok"; // expect: true 7 | print 0 or "ok"; // expect: 0 8 | print "s" or "ok"; // expect: s 9 | -------------------------------------------------------------------------------- /test/method/arity.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | method0() { return "no args"; } 3 | method1(a) { return a; } 4 | method2(a, b) { return a + b; } 5 | method3(a, b, c) { return a + b + c; } 6 | method4(a, b, c, d) { return a + b + c + d; } 7 | method5(a, b, c, d, e) { return a + b + c + d + e; } 8 | method6(a, b, c, d, e, f) { return a + b + c + d + e + f; } 9 | method7(a, b, c, d, e, f, g) { return a + b + c + d + e + f + g; } 10 | method8(a, b, c, d, e, f, g, h) { return a + b + c + d + e + f + g + h; } 11 | } 12 | 13 | var foo = Foo(); 14 | print foo.method0(); // expect: no args 15 | print foo.method1(1); // expect: 1 16 | print foo.method2(1, 2); // expect: 3 17 | print foo.method3(1, 2, 3); // expect: 6 18 | print foo.method4(1, 2, 3, 4); // expect: 10 19 | print foo.method5(1, 2, 3, 4, 5); // expect: 15 20 | print foo.method6(1, 2, 3, 4, 5, 6); // expect: 21 21 | print foo.method7(1, 2, 3, 4, 5, 6, 7); // expect: 28 22 | print foo.method8(1, 2, 3, 4, 5, 6, 7, 8); // expect: 36 23 | -------------------------------------------------------------------------------- /test/method/empty_block.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | bar() {} 3 | } 4 | 5 | print Foo().bar(); // expect: nil 6 | -------------------------------------------------------------------------------- /test/method/extra_arguments.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | method(a, b) { 3 | print a; 4 | print b; 5 | } 6 | } 7 | 8 | Foo().method(1, 2, 3, 4); // expect runtime error: Expected 2 arguments but got 4. 9 | -------------------------------------------------------------------------------- /test/method/missing_arguments.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | method(a, b) {} 3 | } 4 | 5 | Foo().method(1); // expect runtime error: Expected 2 arguments but got 1. 6 | -------------------------------------------------------------------------------- /test/method/not_found.lox: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | Foo().unknown(); // expect runtime error: Undefined property 'unknown'. 4 | -------------------------------------------------------------------------------- /test/method/refer_to_name.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | method() { 3 | print method; // expect runtime error: Undefined variable 'method'. 4 | } 5 | } 6 | 7 | Foo().method(); 8 | -------------------------------------------------------------------------------- /test/method/too_many_arguments.lox: -------------------------------------------------------------------------------- 1 | true.method(1, 2, 3, 4, 5, 6, 7, 8, 9); // Error at '9': Cannot have more than 8 arguments. 2 | -------------------------------------------------------------------------------- /test/method/too_many_parameters.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | // 9 parameters. 3 | method(a, b, c, d, e, f, g, h, i) {} // Error at 'i': Cannot have more than 8 parameters. 4 | } 5 | -------------------------------------------------------------------------------- /test/nil/literal.lox: -------------------------------------------------------------------------------- 1 | print nil; // expect: nil 2 | -------------------------------------------------------------------------------- /test/number/decimal_point_at_eof.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at end: Expect property name after '.'. 2 | 123. -------------------------------------------------------------------------------- /test/number/leading_dot.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at '.': Expect expression. 2 | .123; 3 | -------------------------------------------------------------------------------- /test/number/literals.lox: -------------------------------------------------------------------------------- 1 | print 123; // expect: 123 2 | print 987654; // expect: 987654 3 | print 0; // expect: 0 4 | print -0; // expect: -0 5 | 6 | print 123.456; // expect: 123.456 7 | print -0.001; // expect: -0.001 8 | -------------------------------------------------------------------------------- /test/number/trailing_dot.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at ';': Expect property name after '.'. 2 | 123.; 3 | -------------------------------------------------------------------------------- /test/operator/add.lox: -------------------------------------------------------------------------------- 1 | print 123 + 456; // expect: 579 2 | print "str" + "ing"; // expect: string 3 | -------------------------------------------------------------------------------- /test/operator/add_bool_nil.lox: -------------------------------------------------------------------------------- 1 | true + nil; // expect runtime error: Operands must be two numbers or two strings. 2 | -------------------------------------------------------------------------------- /test/operator/add_bool_num.lox: -------------------------------------------------------------------------------- 1 | true + 123; // expect runtime error: Operands must be two numbers or two strings. 2 | -------------------------------------------------------------------------------- /test/operator/add_bool_string.lox: -------------------------------------------------------------------------------- 1 | true + "s"; // expect runtime error: Operands must be two numbers or two strings. 2 | -------------------------------------------------------------------------------- /test/operator/add_nil_nil.lox: -------------------------------------------------------------------------------- 1 | nil + nil; // expect runtime error: Operands must be two numbers or two strings. 2 | -------------------------------------------------------------------------------- /test/operator/add_num_nil.lox: -------------------------------------------------------------------------------- 1 | 1 + nil; // expect runtime error: Operands must be two numbers or two strings. 2 | -------------------------------------------------------------------------------- /test/operator/add_string_nil.lox: -------------------------------------------------------------------------------- 1 | "s" + nil; // expect runtime error: Operands must be two numbers or two strings. 2 | -------------------------------------------------------------------------------- /test/operator/comparison.lox: -------------------------------------------------------------------------------- 1 | print 1 < 2; // expect: true 2 | print 2 < 2; // expect: false 3 | print 2 < 1; // expect: false 4 | 5 | print 1 <= 2; // expect: true 6 | print 2 <= 2; // expect: true 7 | print 2 <= 1; // expect: false 8 | 9 | print 1 > 2; // expect: false 10 | print 2 > 2; // expect: false 11 | print 2 > 1; // expect: true 12 | 13 | print 1 >= 2; // expect: false 14 | print 2 >= 2; // expect: true 15 | print 2 >= 1; // expect: true 16 | 17 | // Zero and negative zero compare the same. 18 | print 0 < -0; // expect: false 19 | print -0 < 0; // expect: false 20 | print 0 > -0; // expect: false 21 | print -0 > 0; // expect: false 22 | print 0 <= -0; // expect: true 23 | print -0 <= 0; // expect: true 24 | print 0 >= -0; // expect: true 25 | print -0 >= 0; // expect: true 26 | -------------------------------------------------------------------------------- /test/operator/divide.lox: -------------------------------------------------------------------------------- 1 | print 8 / 2; // expect: 4 2 | print 12.34 / 12.34; // expect: 1 3 | -------------------------------------------------------------------------------- /test/operator/divide_nonnum_num.lox: -------------------------------------------------------------------------------- 1 | "1" / 1; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/divide_num_nonnum.lox: -------------------------------------------------------------------------------- 1 | 1 / "1"; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/equals.lox: -------------------------------------------------------------------------------- 1 | print nil == nil; // expect: true 2 | 3 | print true == true; // expect: true 4 | print true == false; // expect: false 5 | 6 | print 1 == 1; // expect: true 7 | print 1 == 2; // expect: false 8 | 9 | print "str" == "str"; // expect: true 10 | print "str" == "ing"; // expect: false 11 | 12 | print nil == false; // expect: false 13 | print false == 0; // expect: false 14 | print 0 == "0"; // expect: false 15 | -------------------------------------------------------------------------------- /test/operator/equals_class.lox: -------------------------------------------------------------------------------- 1 | // Bound methods have identity equality. 2 | class Foo {} 3 | class Bar {} 4 | 5 | print Foo == Foo; // expect: true 6 | print Foo == Bar; // expect: false 7 | print Bar == Foo; // expect: false 8 | print Bar == Bar; // expect: true 9 | 10 | print Foo == "Foo"; // expect: false 11 | print Foo == nil; // expect: false 12 | print Foo == 123; // expect: false 13 | print Foo == true; // expect: false 14 | -------------------------------------------------------------------------------- /test/operator/equals_method.lox: -------------------------------------------------------------------------------- 1 | // Bound methods have identity equality. 2 | class Foo { 3 | method() {} 4 | } 5 | 6 | var foo = Foo(); 7 | var fooMethod = foo.method; 8 | 9 | // Same bound method. 10 | print fooMethod == fooMethod; // expect: true 11 | 12 | // Different closurizations. 13 | print foo.method == foo.method; // expect: false 14 | -------------------------------------------------------------------------------- /test/operator/greater_nonnum_num.lox: -------------------------------------------------------------------------------- 1 | "1" > 1; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/greater_num_nonnum.lox: -------------------------------------------------------------------------------- 1 | 1 > "1"; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/greater_or_equal_nonnum_num.lox: -------------------------------------------------------------------------------- 1 | "1" >= 1; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/greater_or_equal_num_nonnum.lox: -------------------------------------------------------------------------------- 1 | 1 >= "1"; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/less_nonnum_num.lox: -------------------------------------------------------------------------------- 1 | "1" < 1; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/less_num_nonnum.lox: -------------------------------------------------------------------------------- 1 | 1 < "1"; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/less_or_equal_nonnum_num.lox: -------------------------------------------------------------------------------- 1 | "1" <= 1; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/less_or_equal_num_nonnum.lox: -------------------------------------------------------------------------------- 1 | 1 <= "1"; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/multiply.lox: -------------------------------------------------------------------------------- 1 | print 5 * 3; // expect: 15 2 | print 12.34 * 0.3; // expect: 3.702 3 | -------------------------------------------------------------------------------- /test/operator/multiply_nonnum_num.lox: -------------------------------------------------------------------------------- 1 | "1" * 1; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/multiply_num_nonnum.lox: -------------------------------------------------------------------------------- 1 | 1 * "1"; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/negate.lox: -------------------------------------------------------------------------------- 1 | print -(3); // expect: -3 2 | print --(3); // expect: 3 3 | print ---(3); // expect: -3 4 | -------------------------------------------------------------------------------- /test/operator/negate_nonnum.lox: -------------------------------------------------------------------------------- 1 | -"s"; // expect runtime error: Operand must be a number. 2 | -------------------------------------------------------------------------------- /test/operator/not.lox: -------------------------------------------------------------------------------- 1 | print !true; // expect: false 2 | print !false; // expect: true 3 | print !!true; // expect: true 4 | 5 | print !123; // expect: false 6 | print !0; // expect: false 7 | 8 | print !nil; // expect: true 9 | 10 | print !""; // expect: false 11 | 12 | fun foo() {} 13 | print !foo; // expect: false 14 | -------------------------------------------------------------------------------- /test/operator/not_class.lox: -------------------------------------------------------------------------------- 1 | class Bar {} 2 | print !Bar; // expect: false 3 | print !Bar(); // expect: false 4 | -------------------------------------------------------------------------------- /test/operator/not_equals.lox: -------------------------------------------------------------------------------- 1 | print nil != nil; // expect: false 2 | 3 | print true != true; // expect: false 4 | print true != false; // expect: true 5 | 6 | print 1 != 1; // expect: false 7 | print 1 != 2; // expect: true 8 | 9 | print "str" != "str"; // expect: false 10 | print "str" != "ing"; // expect: true 11 | 12 | print nil != false; // expect: true 13 | print false != 0; // expect: true 14 | print 0 != "0"; // expect: true 15 | -------------------------------------------------------------------------------- /test/operator/subtract.lox: -------------------------------------------------------------------------------- 1 | print 4 - 3; // expect: 1 2 | print 1.2 - 1.2; // expect: 0 3 | -------------------------------------------------------------------------------- /test/operator/subtract_nonnum_num.lox: -------------------------------------------------------------------------------- 1 | "1" - 1; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/operator/subtract_num_nonnum.lox: -------------------------------------------------------------------------------- 1 | 1 - "1"; // expect runtime error: Operands must be numbers. 2 | -------------------------------------------------------------------------------- /test/precedence.lox: -------------------------------------------------------------------------------- 1 | // * has higher precedence than +. 2 | print 2 + 3 * 4; // expect: 14 3 | 4 | // * has higher precedence than -. 5 | print 20 - 3 * 4; // expect: 8 6 | 7 | // / has higher precedence than +. 8 | print 2 + 6 / 3; // expect: 4 9 | 10 | // / has higher precedence than -. 11 | print 2 - 6 / 3; // expect: 0 12 | 13 | // < has higher precedence than ==. 14 | print false == 2 < 1; // expect: true 15 | 16 | // > has higher precedence than ==. 17 | print false == 1 > 2; // expect: true 18 | 19 | // <= has higher precedence than ==. 20 | print false == 2 <= 1; // expect: true 21 | 22 | // >= has higher precedence than ==. 23 | print false == 1 >= 2; // expect: true 24 | 25 | // 1 - 1 is not space-sensitive. 26 | print 1 - 1; // expect: 0 27 | print 1 -1; // expect: 0 28 | print 1- 1; // expect: 0 29 | print 1-1; // expect: 0 30 | 31 | // Using () for grouping. 32 | print (2 * (6 - (2 + 2))); // expect: 4 33 | -------------------------------------------------------------------------------- /test/print/missing_argument.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at ';': Expect expression. 2 | print; 3 | -------------------------------------------------------------------------------- /test/regression/40.lox: -------------------------------------------------------------------------------- 1 | fun caller(g) { 2 | g(); 3 | // g should be a function, not nil. 4 | print g == nil; // expect: false 5 | } 6 | 7 | fun callCaller() { 8 | var capturedVar = "before"; 9 | var a = "a"; 10 | 11 | fun f() { 12 | // Commenting the next line out prevents the bug! 13 | capturedVar = "after"; 14 | 15 | // Returning anything also fixes it, even nil: 16 | //return nil; 17 | } 18 | 19 | caller(f); 20 | } 21 | 22 | callCaller(); 23 | -------------------------------------------------------------------------------- /test/return/after_else.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | if (false) "no"; else return "ok"; 3 | } 4 | 5 | print f(); // expect: ok 6 | -------------------------------------------------------------------------------- /test/return/after_if.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | if (true) return "ok"; 3 | } 4 | 5 | print f(); // expect: ok 6 | -------------------------------------------------------------------------------- /test/return/after_while.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | while (true) return "ok"; 3 | } 4 | 5 | print f(); // expect: ok 6 | -------------------------------------------------------------------------------- /test/return/at_top_level.lox: -------------------------------------------------------------------------------- 1 | return "wat"; // Error at 'return': Cannot return from top-level code. 2 | -------------------------------------------------------------------------------- /test/return/in_function.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | return "ok"; 3 | print "bad"; 4 | } 5 | 6 | print f(); // expect: ok 7 | -------------------------------------------------------------------------------- /test/return/in_method.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | method() { 3 | return "ok"; 4 | print "bad"; 5 | } 6 | } 7 | 8 | print Foo().method(); // expect: ok 9 | -------------------------------------------------------------------------------- /test/return/return_nil_if_no_value.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | return; 3 | print "bad"; 4 | } 5 | 6 | print f(); // expect: nil 7 | -------------------------------------------------------------------------------- /test/scanning/identifiers.lox: -------------------------------------------------------------------------------- 1 | andy formless fo _ _123 _abc ab123 2 | abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_ 3 | 4 | // expect: IDENTIFIER andy null 5 | // expect: IDENTIFIER formless null 6 | // expect: IDENTIFIER fo null 7 | // expect: IDENTIFIER _ null 8 | // expect: IDENTIFIER _123 null 9 | // expect: IDENTIFIER _abc null 10 | // expect: IDENTIFIER ab123 null 11 | // expect: IDENTIFIER abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_ null 12 | // expect: EOF null 13 | -------------------------------------------------------------------------------- /test/scanning/keywords.lox: -------------------------------------------------------------------------------- 1 | and class else false for fun if nil or return super this true var while 2 | 3 | // expect: AND and null 4 | // expect: CLASS class null 5 | // expect: ELSE else null 6 | // expect: FALSE false null 7 | // expect: FOR for null 8 | // expect: FUN fun null 9 | // expect: IF if null 10 | // expect: NIL nil null 11 | // expect: OR or null 12 | // expect: RETURN return null 13 | // expect: SUPER super null 14 | // expect: THIS this null 15 | // expect: TRUE true null 16 | // expect: VAR var null 17 | // expect: WHILE while null 18 | // expect: EOF null 19 | -------------------------------------------------------------------------------- /test/scanning/numbers.lox: -------------------------------------------------------------------------------- 1 | 123 2 | 123.456 3 | .456 4 | 123. 5 | 6 | // expect: NUMBER 123 123.0 7 | // expect: NUMBER 123.456 123.456 8 | // expect: DOT . null 9 | // expect: NUMBER 456 456.0 10 | // expect: NUMBER 123 123.0 11 | // expect: DOT . null 12 | // expect: EOF null 13 | -------------------------------------------------------------------------------- /test/scanning/punctuators.lox: -------------------------------------------------------------------------------- 1 | (){};,+-*!===<=>=!=<>/. 2 | 3 | // expect: LEFT_PAREN ( null 4 | // expect: RIGHT_PAREN ) null 5 | // expect: LEFT_BRACE { null 6 | // expect: RIGHT_BRACE } null 7 | // expect: SEMICOLON ; null 8 | // expect: COMMA , null 9 | // expect: PLUS + null 10 | // expect: MINUS - null 11 | // expect: STAR * null 12 | // expect: BANG_EQUAL != null 13 | // expect: EQUAL_EQUAL == null 14 | // expect: LESS_EQUAL <= null 15 | // expect: GREATER_EQUAL >= null 16 | // expect: BANG_EQUAL != null 17 | // expect: LESS < null 18 | // expect: GREATER > null 19 | // expect: SLASH / null 20 | // expect: DOT . null 21 | // expect: EOF null 22 | -------------------------------------------------------------------------------- /test/scanning/strings.lox: -------------------------------------------------------------------------------- 1 | "" 2 | "string" 3 | 4 | // expect: STRING "" 5 | // expect: STRING "string" string 6 | // expect: EOF null -------------------------------------------------------------------------------- /test/scanning/whitespace.lox: -------------------------------------------------------------------------------- 1 | space tabs newlines 2 | 3 | 4 | 5 | 6 | end 7 | 8 | // expect: IDENTIFIER space null 9 | // expect: IDENTIFIER tabs null 10 | // expect: IDENTIFIER newlines null 11 | // expect: IDENTIFIER end null 12 | // expect: EOF null 13 | -------------------------------------------------------------------------------- /test/string/error_after_multiline.lox: -------------------------------------------------------------------------------- 1 | // Tests that we correctly track the line info across multiline strings. 2 | var a = "1 3 | 2 4 | 3 5 | "; 6 | 7 | err; // // expect runtime error: Undefined variable 'err'. -------------------------------------------------------------------------------- /test/string/literals.lox: -------------------------------------------------------------------------------- 1 | print "(" + "" + ")"; // expect: () 2 | print "a string"; // expect: a string 3 | 4 | // Non-ASCII. 5 | print "A~¶Þॐஃ"; // expect: A~¶Þॐஃ 6 | -------------------------------------------------------------------------------- /test/string/multiline.lox: -------------------------------------------------------------------------------- 1 | var a = "1 2 | 2 3 | 3"; 4 | print a; 5 | // expect: 1 6 | // expect: 2 7 | // expect: 3 8 | -------------------------------------------------------------------------------- /test/string/unterminated.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error: Unterminated string. 2 | "this string has no close quote -------------------------------------------------------------------------------- /test/super/bound_method.lox: -------------------------------------------------------------------------------- 1 | class A { 2 | method(arg) { 3 | print "A.method(" + arg + ")"; 4 | } 5 | } 6 | 7 | class B < A { 8 | getClosure() { 9 | return super.method; 10 | } 11 | 12 | method(arg) { 13 | print "B.method(" + arg + ")"; 14 | } 15 | } 16 | 17 | 18 | var closure = B().getClosure(); 19 | closure("arg"); // expect: A.method(arg) 20 | -------------------------------------------------------------------------------- /test/super/call_other_method.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | foo() { 3 | print "Base.foo()"; 4 | } 5 | } 6 | 7 | class Derived < Base { 8 | bar() { 9 | print "Derived.bar()"; 10 | super.foo(); 11 | } 12 | } 13 | 14 | Derived().bar(); 15 | // expect: Derived.bar() 16 | // expect: Base.foo() 17 | -------------------------------------------------------------------------------- /test/super/call_same_method.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | foo() { 3 | print "Base.foo()"; 4 | } 5 | } 6 | 7 | class Derived < Base { 8 | foo() { 9 | print "Derived.foo()"; 10 | super.foo(); 11 | } 12 | } 13 | 14 | Derived().foo(); 15 | // expect: Derived.foo() 16 | // expect: Base.foo() 17 | -------------------------------------------------------------------------------- /test/super/closure.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | toString() { return "Base"; } 3 | } 4 | 5 | class Derived < Base { 6 | getClosure() { 7 | fun closure() { 8 | return super.toString(); 9 | } 10 | return closure; 11 | } 12 | 13 | toString() { return "Derived"; } 14 | } 15 | 16 | var closure = Derived().getClosure(); 17 | print closure(); // expect: Base 18 | -------------------------------------------------------------------------------- /test/super/constructor.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | init(a, b) { 3 | print "Base.init(" + a + ", " + b + ")"; 4 | } 5 | } 6 | 7 | class Derived < Base { 8 | init() { 9 | print "Derived.init()"; 10 | super.init("a", "b"); 11 | } 12 | } 13 | 14 | Derived(); 15 | // expect: Derived.init() 16 | // expect: Base.init(a, b) 17 | -------------------------------------------------------------------------------- /test/super/extra_arguments.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | foo(a, b) { 3 | print "Base.foo(" + a + ", " + b + ")"; 4 | } 5 | } 6 | 7 | class Derived < Base { 8 | foo() { 9 | print "Derived.foo()"; // expect: Derived.foo() 10 | super.foo("a", "b", "c", "d"); // expect runtime error: Expected 2 arguments but got 4. 11 | } 12 | } 13 | 14 | Derived().foo(); 15 | -------------------------------------------------------------------------------- /test/super/indirectly_inherited.lox: -------------------------------------------------------------------------------- 1 | class A { 2 | foo() { 3 | print "A.foo()"; 4 | } 5 | } 6 | 7 | class B < A {} 8 | 9 | class C < B { 10 | foo() { 11 | print "C.foo()"; 12 | super.foo(); 13 | } 14 | } 15 | 16 | C().foo(); 17 | // expect: C.foo() 18 | // expect: A.foo() 19 | -------------------------------------------------------------------------------- /test/super/missing_arguments.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | foo(a, b) { 3 | print "Base.foo(" + a + ", " + b + ")"; 4 | } 5 | } 6 | 7 | class Derived < Base { 8 | foo() { 9 | super.foo(1); // expect runtime error: Expected 2 arguments but got 1. 10 | } 11 | } 12 | 13 | Derived().foo(); 14 | -------------------------------------------------------------------------------- /test/super/no_superclass_bind.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | foo() { 3 | super.doesNotExist; // Error at 'super': Cannot use 'super' in a class with no superclass. 4 | } 5 | } 6 | 7 | Base().foo(); 8 | -------------------------------------------------------------------------------- /test/super/no_superclass_call.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | foo() { 3 | super.doesNotExist(1); // Error at 'super': Cannot use 'super' in a class with no superclass. 4 | } 5 | } 6 | 7 | Base().foo(); 8 | -------------------------------------------------------------------------------- /test/super/no_superclass_method.lox: -------------------------------------------------------------------------------- 1 | class Base {} 2 | 3 | class Derived < Base { 4 | foo() { 5 | super.doesNotExist(1); // expect runtime error: Undefined property 'doesNotExist'. 6 | } 7 | } 8 | 9 | Derived().foo(); 10 | -------------------------------------------------------------------------------- /test/super/parenthesized.lox: -------------------------------------------------------------------------------- 1 | class A { 2 | method() {} 3 | } 4 | 5 | class B < A { 6 | method() { 7 | // [line 8] Error at ')': Expect '.' after 'super'. 8 | (super).method(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/super/reassign_superclass.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | method() { 3 | print "Base.method()"; 4 | } 5 | } 6 | 7 | class Derived < Base { 8 | method() { 9 | super.method(); 10 | } 11 | } 12 | 13 | class OtherBase { 14 | method() { 15 | print "OtherBase.method()"; 16 | } 17 | } 18 | 19 | var derived = Derived(); 20 | derived.method(); // expect: Base.method() 21 | Base = OtherBase; 22 | derived.method(); // expect: Base.method() 23 | -------------------------------------------------------------------------------- /test/super/super_at_top_level.lox: -------------------------------------------------------------------------------- 1 | super.foo; // Error at 'super': Cannot use 'super' outside of a class. 2 | super.foo("bar"); // Error at 'super': Cannot use 'super' outside of a class. 3 | -------------------------------------------------------------------------------- /test/super/super_in_closure_in_inherited_method.lox: -------------------------------------------------------------------------------- 1 | class A { 2 | say() { 3 | print "A"; 4 | } 5 | } 6 | 7 | class B < A { 8 | getClosure() { 9 | fun closure() { 10 | super.say(); 11 | } 12 | return closure; 13 | } 14 | 15 | say() { 16 | print "B"; 17 | } 18 | } 19 | 20 | class C < B { 21 | say() { 22 | print "C"; 23 | } 24 | } 25 | 26 | C().getClosure()(); // expect: A 27 | -------------------------------------------------------------------------------- /test/super/super_in_inherited_method.lox: -------------------------------------------------------------------------------- 1 | class A { 2 | say() { 3 | print "A"; 4 | } 5 | } 6 | 7 | class B < A { 8 | test() { 9 | super.say(); 10 | } 11 | 12 | say() { 13 | print "B"; 14 | } 15 | } 16 | 17 | class C < B { 18 | say() { 19 | print "C"; 20 | } 21 | } 22 | 23 | C().test(); // expect: A 24 | -------------------------------------------------------------------------------- /test/super/super_in_top_level_function.lox: -------------------------------------------------------------------------------- 1 | fun foo() { 2 | super.bar(); // Error at 'super': Cannot use 'super' outside of a class. 3 | } 4 | -------------------------------------------------------------------------------- /test/super/super_without_dot.lox: -------------------------------------------------------------------------------- 1 | class A {} 2 | 3 | class B < A { 4 | method() { 5 | // [line 6] Error at ';': Expect '.' after 'super'. 6 | super; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/super/super_without_name.lox: -------------------------------------------------------------------------------- 1 | class A {} 2 | 3 | class B < A { 4 | method() { 5 | super.; // Error at ';': Expect superclass method name. 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/super/this_in_superclass_method.lox: -------------------------------------------------------------------------------- 1 | class Base { 2 | init(a) { 3 | this.a = a; 4 | } 5 | } 6 | 7 | class Derived < Base { 8 | init(a, b) { 9 | super.init(a); 10 | this.b = b; 11 | } 12 | } 13 | 14 | var derived = Derived("a", "b"); 15 | print derived.a; // expect: a 16 | print derived.b; // expect: b 17 | -------------------------------------------------------------------------------- /test/this/closure.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | getClosure() { 3 | fun closure() { 4 | return this.toString(); 5 | } 6 | return closure; 7 | } 8 | 9 | toString() { return "Foo"; } 10 | } 11 | 12 | var closure = Foo().getClosure(); 13 | print closure(); // expect: Foo 14 | -------------------------------------------------------------------------------- /test/this/nested_class.lox: -------------------------------------------------------------------------------- 1 | class Outer { 2 | method() { 3 | print this; // expect: Outer instance 4 | 5 | fun f() { 6 | print this; // expect: Outer instance 7 | 8 | class Inner { 9 | method() { 10 | print this; // expect: Inner instance 11 | } 12 | } 13 | 14 | Inner().method(); 15 | } 16 | f(); 17 | } 18 | } 19 | 20 | Outer().method(); 21 | -------------------------------------------------------------------------------- /test/this/nested_closure.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | getClosure() { 3 | fun f() { 4 | fun g() { 5 | fun h() { 6 | return this.toString(); 7 | } 8 | return h; 9 | } 10 | return g; 11 | } 12 | return f; 13 | } 14 | 15 | toString() { return "Foo"; } 16 | } 17 | 18 | var closure = Foo().getClosure(); 19 | print closure()()(); // expect: Foo 20 | -------------------------------------------------------------------------------- /test/this/this_at_top_level.lox: -------------------------------------------------------------------------------- 1 | this; // Error at 'this': Cannot use 'this' outside of a class. 2 | -------------------------------------------------------------------------------- /test/this/this_in_method.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | bar() { return this; } 3 | baz() { return "baz"; } 4 | } 5 | 6 | print Foo().bar().baz(); // expect: baz 7 | -------------------------------------------------------------------------------- /test/this/this_in_top_level_function.lox: -------------------------------------------------------------------------------- 1 | fun foo() { 2 | this; // Error at 'this': Cannot use 'this' outside of a class. 3 | } 4 | -------------------------------------------------------------------------------- /test/unexpected_character.lox: -------------------------------------------------------------------------------- 1 | // [line 3] Error: Unexpected character. 2 | // [java line 3] Error at 'b': Expect ')' after arguments. 3 | foo(a | b); 4 | -------------------------------------------------------------------------------- /test/variable/collide_with_parameter.lox: -------------------------------------------------------------------------------- 1 | fun foo(a) { 2 | var a; // Error at 'a': Variable with this name already declared in this scope. 3 | } 4 | -------------------------------------------------------------------------------- /test/variable/duplicate_local.lox: -------------------------------------------------------------------------------- 1 | { 2 | var a = "value"; 3 | var a = "other"; // Error at 'a': Variable with this name already declared in this scope. 4 | } 5 | -------------------------------------------------------------------------------- /test/variable/duplicate_parameter.lox: -------------------------------------------------------------------------------- 1 | fun foo(arg, 2 | arg) { // Error at 'arg': Variable with this name already declared in this scope. 3 | "body"; 4 | } 5 | -------------------------------------------------------------------------------- /test/variable/early_bound.lox: -------------------------------------------------------------------------------- 1 | var a = "outer"; 2 | { 3 | fun foo() { 4 | print a; 5 | } 6 | 7 | foo(); // expect: outer 8 | var a = "inner"; 9 | foo(); // expect: outer 10 | } 11 | -------------------------------------------------------------------------------- /test/variable/in_middle_of_block.lox: -------------------------------------------------------------------------------- 1 | { 2 | var a = "a"; 3 | print a; // expect: a 4 | var b = a + " b"; 5 | print b; // expect: a b 6 | var c = a + " c"; 7 | print c; // expect: a c 8 | var d = b + " d"; 9 | print d; // expect: a b d 10 | } 11 | -------------------------------------------------------------------------------- /test/variable/in_nested_block.lox: -------------------------------------------------------------------------------- 1 | { 2 | var a = "outer"; 3 | { 4 | print a; // expect: outer 5 | } 6 | } -------------------------------------------------------------------------------- /test/variable/local_from_method.lox: -------------------------------------------------------------------------------- 1 | var foo = "variable"; 2 | 3 | class Foo { 4 | method() { 5 | print foo; 6 | } 7 | } 8 | 9 | Foo().method(); // expect: variable 10 | -------------------------------------------------------------------------------- /test/variable/redeclare_global.lox: -------------------------------------------------------------------------------- 1 | var a = "1"; 2 | var a; 3 | print a; // expect: nil 4 | -------------------------------------------------------------------------------- /test/variable/redefine_global.lox: -------------------------------------------------------------------------------- 1 | var a = "1"; 2 | var a = "2"; 3 | print a; // expect: 2 4 | -------------------------------------------------------------------------------- /test/variable/scope_reuse_in_different_blocks.lox: -------------------------------------------------------------------------------- 1 | { 2 | var a = "first"; 3 | print a; // expect: first 4 | } 5 | 6 | { 7 | var a = "second"; 8 | print a; // expect: second 9 | } 10 | -------------------------------------------------------------------------------- /test/variable/shadow_and_local.lox: -------------------------------------------------------------------------------- 1 | { 2 | var a = "outer"; 3 | { 4 | print a; // expect: outer 5 | var a = "inner"; 6 | print a; // expect: inner 7 | } 8 | } -------------------------------------------------------------------------------- /test/variable/shadow_global.lox: -------------------------------------------------------------------------------- 1 | var a = "global"; 2 | { 3 | var a = "shadow"; 4 | print a; // expect: shadow 5 | } 6 | print a; // expect: global 7 | -------------------------------------------------------------------------------- /test/variable/shadow_local.lox: -------------------------------------------------------------------------------- 1 | { 2 | var a = "local"; 3 | { 4 | var a = "shadow"; 5 | print a; // expect: shadow 6 | } 7 | print a; // expect: local 8 | } 9 | -------------------------------------------------------------------------------- /test/variable/undefined_global.lox: -------------------------------------------------------------------------------- 1 | print notDefined; // expect runtime error: Undefined variable 'notDefined'. 2 | -------------------------------------------------------------------------------- /test/variable/undefined_local.lox: -------------------------------------------------------------------------------- 1 | { 2 | print notDefined; // expect runtime error: Undefined variable 'notDefined'. 3 | } 4 | -------------------------------------------------------------------------------- /test/variable/uninitialized.lox: -------------------------------------------------------------------------------- 1 | var a; 2 | print a; // expect: nil 3 | -------------------------------------------------------------------------------- /test/variable/unreached_undefined.lox: -------------------------------------------------------------------------------- 1 | if (false) { 2 | print notDefined; 3 | } 4 | 5 | print "ok"; // expect: ok 6 | -------------------------------------------------------------------------------- /test/variable/use_false_as_var.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'false': Expect variable name. 2 | var false = "value"; 3 | -------------------------------------------------------------------------------- /test/variable/use_global_in_initializer.lox: -------------------------------------------------------------------------------- 1 | var a = "value"; 2 | var a = a; 3 | print a; // expect: value 4 | -------------------------------------------------------------------------------- /test/variable/use_local_in_initializer.lox: -------------------------------------------------------------------------------- 1 | var a = "outer"; 2 | { 3 | var a = a; // Error at 'a': Cannot read local variable in its own initializer. 4 | } 5 | -------------------------------------------------------------------------------- /test/variable/use_nil_as_var.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'nil': Expect variable name. 2 | var nil = "value"; 3 | -------------------------------------------------------------------------------- /test/variable/use_this_as_var.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'this': Expect variable name. 2 | var this = "value"; 3 | -------------------------------------------------------------------------------- /test/while/class_in_body.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'class': Expect expression. 2 | while (true) class Foo {} 3 | -------------------------------------------------------------------------------- /test/while/closure_in_body.lox: -------------------------------------------------------------------------------- 1 | var f1; 2 | var f2; 3 | var f3; 4 | 5 | var i = 1; 6 | while (i < 4) { 7 | var j = i; 8 | fun f() { print j; } 9 | 10 | if (j == 1) f1 = f; 11 | else if (j == 2) f2 = f; 12 | else f3 = f; 13 | 14 | i = i + 1; 15 | } 16 | 17 | f1(); // expect: 1 18 | f2(); // expect: 2 19 | f3(); // expect: 3 20 | -------------------------------------------------------------------------------- /test/while/fun_in_body.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'fun': Expect expression. 2 | while (true) fun foo() {} 3 | -------------------------------------------------------------------------------- /test/while/return_closure.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | while (true) { 3 | var i = "i"; 4 | fun g() { print i; } 5 | return g; 6 | } 7 | } 8 | 9 | var h = f(); 10 | h(); // expect: i 11 | -------------------------------------------------------------------------------- /test/while/return_inside.lox: -------------------------------------------------------------------------------- 1 | fun f() { 2 | while (true) { 3 | var i = "i"; 4 | return i; 5 | } 6 | } 7 | 8 | print f(); 9 | // expect: i 10 | -------------------------------------------------------------------------------- /test/while/syntax.lox: -------------------------------------------------------------------------------- 1 | // Single-expression body. 2 | var c = 0; 3 | while (c < 3) print c = c + 1; 4 | // expect: 1 5 | // expect: 2 6 | // expect: 3 7 | 8 | // Block body. 9 | var a = 0; 10 | while (a < 3) { 11 | print a; 12 | a = a + 1; 13 | } 14 | // expect: 0 15 | // expect: 1 16 | // expect: 2 17 | 18 | // Statement bodies. 19 | while (false) if (true) 1; else 2; 20 | while (false) while (true) 1; 21 | while (false) for (;;) 1; 22 | -------------------------------------------------------------------------------- /test/while/var_in_body.lox: -------------------------------------------------------------------------------- 1 | // [line 2] Error at 'var': Expect expression. 2 | while (true) var foo; 3 | --------------------------------------------------------------------------------