diff --git a/doc/site/style.scss b/doc/site/style.scss index 01cf8cbe..162693ab 100644 --- a/doc/site/style.scss +++ b/doc/site/style.scss @@ -158,13 +158,13 @@ nav { } h2 { - font: normal 24px $header; + font: normal 30px $header; margin: 24px 0 0 0; color: $blue; } h3 { - font: normal 20px $header; + font: normal 24px $header; margin: 24px 0 0 0; color: $blue; } diff --git a/src/wren_common.h b/src/wren_common.h index 26e04f92..bde3d7d9 100644 --- a/src/wren_common.h +++ b/src/wren_common.h @@ -62,28 +62,32 @@ // The maximum number of globals that may be defined at one time. This // limitation comes from the 16 bits used for the arguments to // `CODE_LOAD_GLOBAL` and `CODE_STORE_GLOBAL`. -#define MAX_GLOBALS (65536) +#define MAX_GLOBALS 65536 // The maximum number of arguments that can be passed to a method. Note that // this limitation is hardcoded in other places in the VM, in particular, the // `CODE_CALL_XX` instructions assume a certain maximum number. -#define MAX_PARAMETERS (16) +#define MAX_PARAMETERS 16 // The maximum name of a method, not including the signature. This is an // arbitrary but enforced maximum just so we know how long the method name // strings need to be in the parser. -#define MAX_METHOD_NAME (64) +#define MAX_METHOD_NAME 64 // The maximum length of a method signature. This includes the name, and the // extra spaces added to handle arity, and another byte to terminate the string. #define MAX_METHOD_SIGNATURE (MAX_METHOD_NAME + MAX_PARAMETERS + 1) +// The maximum length of an identifier. The only real reason for this limitation +// is so that error messages mentioning variables can be stack allocated. +#define MAX_VARIABLE_NAME 64 + // The maximum number of fields a class can have, including inherited fields. // This is explicit in the bytecode since `CODE_CLASS` and `CODE_SUBCLASS` take // a single byte for the number of fields. Note that it's 255 and not 256 // because creating a class takes the *number* of fields, not the *highest // field index*. -#define MAX_FIELDS (255) +#define MAX_FIELDS 255 // Assertions are used to validate program invariants. They indicate things the // program expects to be true about its internal state during execution. If an diff --git a/src/wren_compiler.c b/src/wren_compiler.c index 0518e910..3c05aed2 100644 --- a/src/wren_compiler.c +++ b/src/wren_compiler.c @@ -943,6 +943,12 @@ static int declareVariable(Compiler* compiler) { Token* token = &compiler->parser->previous; + if (token->length > MAX_VARIABLE_NAME) + { + error(compiler, "Variable name cannot be longer than %d characters.", + MAX_VARIABLE_NAME); + } + // Top-level global scope. if (compiler->scopeDepth == -1) { diff --git a/src/wren_vm.c b/src/wren_vm.c index 5082041b..4bd4cc97 100644 --- a/src/wren_vm.c +++ b/src/wren_vm.c @@ -950,20 +950,20 @@ static bool runInterpreter(WrenVM* vm) } int numFields = READ_BYTE(); + ObjClass* classObj = wrenNewClass(vm, superclass, numFields, name); // Now that we know the total number of fields, make sure we don't // overflow. if (superclass->numFields + numFields > MAX_FIELDS) { - // TODO: Include class name in message. Mention inheritance. - char message[80]; - snprintf(message, 80, - "A class may not have more than %d fields, including inherited " - "ones.", MAX_FIELDS); + char message[70 + MAX_VARIABLE_NAME]; + snprintf(message, 70 + MAX_VARIABLE_NAME, + "Class '%s' may not have more than %d fields, including inherited " + "ones.", name->value, MAX_FIELDS); RUNTIME_ERROR(message); } - + // Don't pop the superclass and name off the stack until the subclass is // done being created, to make sure it doesn't get collected. DROP(); diff --git a/test/limit/long_variable_name.wren b/test/limit/long_variable_name.wren new file mode 100644 index 00000000..892878fa --- /dev/null +++ b/test/limit/long_variable_name.wren @@ -0,0 +1,2 @@ +var i234567890i234567890i234567890i234567890i234567890i234 = "value" +class c234567890c234567890c234567890c234567890c234567890c234567890c234 {} diff --git a/test/limit/many_inherited_fields.wren b/test/limit/many_inherited_fields.wren index b75632f9..97be268a 100644 --- a/test/limit/many_inherited_fields.wren +++ b/test/limit/many_inherited_fields.wren @@ -136,7 +136,7 @@ class Foo { } } -class Bar is Foo { // expect runtime error: A class may not have more than 255 fields, including inherited ones. +class Bar is Foo { new { super _field129 = 129 @@ -266,15 +266,16 @@ class Bar is Foo { // expect runtime error: A class may not have more than 255 f _field253 = 253 _field254 = 254 _field255 = 255 - _field256 = 256 } bar { IO.print(_field129) - IO.print(_field256) + IO.print(_field255) } } var bar = new Bar -bar.foo -bar.bar +bar.foo // expect: 1 +// expect: 128 +bar.bar // expect: 129 +// expect: 255 diff --git a/test/limit/too_many_inherited_fields.wren b/test/limit/too_many_inherited_fields.wren index 97be268a..cb8f5031 100644 --- a/test/limit/too_many_inherited_fields.wren +++ b/test/limit/too_many_inherited_fields.wren @@ -136,7 +136,7 @@ class Foo { } } -class Bar is Foo { +class Bar is Foo { // expect runtime error: Class 'Bar' may not have more than 255 fields, including inherited ones. new { super _field129 = 129 @@ -266,16 +266,15 @@ class Bar is Foo { _field253 = 253 _field254 = 254 _field255 = 255 + _field256 = 256 } bar { IO.print(_field129) - IO.print(_field255) + IO.print(_field256) } } var bar = new Bar -bar.foo // expect: 1 -// expect: 128 -bar.bar // expect: 129 -// expect: 255 +bar.foo +bar.bar diff --git a/test/limit/variable_name_too_long.wren b/test/limit/variable_name_too_long.wren new file mode 100644 index 00000000..88f4744a --- /dev/null +++ b/test/limit/variable_name_too_long.wren @@ -0,0 +1,2 @@ +var i234567890i234567890i234567890i234567890i234567890i2345 = "value" // expect error +class c234567890c234567890c234567890c234567890c234567890c234567890c2345 {} // expect error