| 6102 | |
| 6103 | |
| 6104 | ResultType Script::DefineClass(LPTSTR aBuf) |
| 6105 | { |
| 6106 | if (mClassObjectCount == MAX_NESTED_CLASSES) |
| 6107 | return ScriptError(_T("This class definition is nested too deep."), aBuf); |
| 6108 | |
| 6109 | LPTSTR cp, class_name = aBuf, base_class_name = nullptr; |
| 6110 | Object *outer_class, *base_class = Object::sClass, *base_prototype = Object::sPrototype; |
| 6111 | Var *class_var; |
| 6112 | ExprTokenType token; |
| 6113 | |
| 6114 | for (cp = aBuf; *cp && !IS_SPACE_OR_TAB(*cp); ++cp); |
| 6115 | size_t class_name_length = cp - aBuf; |
| 6116 | if (*cp) |
| 6117 | { |
| 6118 | *cp = '\0'; // Null-terminate here for class_name. |
| 6119 | cp = omit_leading_whitespace(cp + 1); |
| 6120 | if (_tcsnicmp(cp, _T("extends"), 7) || !IS_SPACE_OR_TAB(cp[7])) |
| 6121 | return ScriptError(_T("Syntax error in class definition."), cp); |
| 6122 | base_class_name = omit_leading_whitespace(cp + 8); |
| 6123 | if (!*base_class_name) |
| 6124 | return ScriptError(_T("Missing class name."), cp); |
| 6125 | base_class = FindClass(base_class_name); |
| 6126 | if (!base_class) |
| 6127 | { |
| 6128 | // This class hasn't been defined yet, but it might be. Automatically create the |
| 6129 | // class, but store it in the "unresolved" list. When its definition is encountered, |
| 6130 | // it will be removed from the list. If any classes remain in the list when the end |
| 6131 | // of the script is reached, an error will be thrown. |
| 6132 | if (mUnresolvedClasses) |
| 6133 | base_class = (Object *)mUnresolvedClasses->GetOwnPropObj(base_class_name); |
| 6134 | else |
| 6135 | mUnresolvedClasses = Object::Create(); |
| 6136 | if (!base_class) |
| 6137 | { |
| 6138 | if ( !(base_prototype = Object::CreatePrototype(base_class_name)) |
| 6139 | || !(base_class = Object::CreateClass(base_prototype)) |
| 6140 | // This property will be removed when the class definition is encountered: |
| 6141 | || !base_class->SetOwnProp(_T("Line"), ((__int64)mCurrFileIndex << 32) | mCombinedLineNumber) |
| 6142 | || !mUnresolvedClasses->SetOwnProp(base_class_name, base_class) ) |
| 6143 | return ScriptError(ERR_OUTOFMEM); |
| 6144 | } |
| 6145 | } |
| 6146 | base_prototype = (Object *)base_class->GetOwnPropObj(_T("Prototype")); |
| 6147 | } |
| 6148 | |
| 6149 | // Validate the name even if this is a nested definition, for consistency. |
| 6150 | if (!Var::ValidateName(class_name, DISPLAY_CLASS_ERROR)) |
| 6151 | return FAIL; |
| 6152 | |
| 6153 | Object *&class_object = mClassObject[mClassObjectCount]; // For convenience. |
| 6154 | class_object = nullptr; |
| 6155 | bool conflict_found = false; |
| 6156 | |
| 6157 | if (mClassObjectCount) // Nested class definition. |
| 6158 | { |
| 6159 | outer_class = mClassObject[mClassObjectCount - 1]; |
| 6160 | if (outer_class->GetOwnProp(token, class_name)) |
| 6161 | { |
no test coverage detected