| 6350 | |
| 6351 | |
| 6352 | ResultType Script::DefineClassVars(LPTSTR aBuf, bool aStatic) |
| 6353 | { |
| 6354 | Object *class_object = mClassObject[mClassObjectCount - 1]; |
| 6355 | if (!aStatic) |
| 6356 | class_object = (Object *)class_object->GetOwnPropObj(_T("Prototype")); |
| 6357 | |
| 6358 | LPTSTR item, item_end; |
| 6359 | TCHAR orig_char, buf[LINE_SIZE]; |
| 6360 | size_t buf_used = 0; |
| 6361 | ExprTokenType empty_token(_T(""), 0); |
| 6362 | empty_token.symbol = SYM_MISSING; |
| 6363 | |
| 6364 | for (item = omit_leading_whitespace(aBuf); *item;) // FOR EACH COMMA-SEPARATED ITEM IN THE DECLARATION LIST. |
| 6365 | { |
| 6366 | item_end = find_identifier_end(item); |
| 6367 | if (item_end == item) |
| 6368 | return ScriptError(ERR_INVALID_CLASS_VAR, item); |
| 6369 | orig_char = *item_end; |
| 6370 | *item_end = '\0'; // Temporarily terminate. |
| 6371 | ExprTokenType existing; |
| 6372 | auto item_exists = class_object->GetOwnPropType(item); |
| 6373 | bool item_name_has_dot = (orig_char == '.'); |
| 6374 | if (item_name_has_dot) |
| 6375 | { |
| 6376 | *item_end = orig_char; // Undo termination. |
| 6377 | // This is something like "object.key := 5", which is only valid if "object" was |
| 6378 | // previously declared (and will presumably be assigned an object at runtime). |
| 6379 | // Ensure that at least the root class var exists; any further validation would |
| 6380 | // be impossible since the object doesn't exist yet. |
| 6381 | if (item_exists == Object::PropType::None) |
| 6382 | return ScriptError(_T("Unknown class var."), item); |
| 6383 | for (TCHAR *cp; *item_end == '.'; item_end = cp) |
| 6384 | { |
| 6385 | for (cp = item_end + 1; IS_IDENTIFIER_CHAR(*cp); ++cp); |
| 6386 | if (cp == item_end + 1) |
| 6387 | // This '.' wasn't followed by a valid identifier. Leave item_end |
| 6388 | // pointing at '.' and allow the switch() below to report the error. |
| 6389 | break; |
| 6390 | } |
| 6391 | } |
| 6392 | else |
| 6393 | { |
| 6394 | switch (item_exists) |
| 6395 | { |
| 6396 | case Object::PropType::Value: |
| 6397 | case Object::PropType::Object: // Prototype or nested class. |
| 6398 | return ScriptError(ERR_DUPLICATE_DECLARATION, item); |
| 6399 | case Object::PropType::None: |
| 6400 | // Assign class_object[item] := "" to mark it as a value property |
| 6401 | // and allow duplicate declarations to be detected: |
| 6402 | if (!class_object->SetOwnProp(item, empty_token)) |
| 6403 | return ScriptError(ERR_OUTOFMEM); |
| 6404 | // But for PropType::Dynamic, we want this line to assign to the property, so don't overwrite it. |
| 6405 | } |
| 6406 | *item_end = orig_char; // Undo termination. |
| 6407 | } |
| 6408 | size_t name_length = item_end - item; |
| 6409 |
nothing calls this directly
no test coverage detected