|
4 | 4 | #include "ast_declpass.hpp" |
5 | 5 | #include "type/ast_types.hpp" |
6 | 6 |
|
| 7 | +#include "symbol/package.hpp" |
| 8 | + |
7 | 9 |
|
8 | 10 | const TxField* TxFieldDefiningNode::resolve_field() { |
9 | 11 | ASSERT( this->is_context_set(), "Declaration pass has not been run (lexctx not set) before resolving " << this ); |
@@ -141,3 +143,88 @@ void TxFieldDefiningNode::verification_pass() const { |
141 | 143 | // TODO: check that constructor function type has void return value |
142 | 144 | } |
143 | 145 | } |
| 146 | + |
| 147 | + |
| 148 | + |
| 149 | +void TxLocalFieldDefNode::declare_field( TxScopeSymbol* scope, TxDeclarationFlags declFlags, TxFieldStorage storage ) { |
| 150 | + this->declaration = scope->declare_field( this->fieldName->str(), this, declFlags, storage, TxIdentifier() ); |
| 151 | +} |
| 152 | + |
| 153 | + |
| 154 | +void TxNonLocalFieldDefNode::declare_field( TxScopeSymbol* scope, TxDeclarationFlags declFlags, TxFieldStorage storage ) { |
| 155 | + std::string declName = this->fieldName->str(); |
| 156 | + if ( declName == "self" ) { |
| 157 | + // handle constructor declaration |
| 158 | + if ( storage != TXS_INSTANCEMETHOD ) |
| 159 | + CERROR( this, "Illegal declaration name for non-constructor member: " << declName ); |
| 160 | + declName = CONSTR_IDENT; |
| 161 | + declFlags = declFlags | TXD_CONSTRUCTOR; |
| 162 | + } |
| 163 | + else if ( declName == CONSTR_IDENT ) { // built-in |
| 164 | + ASSERT( declFlags & TXD_BUILTIN, "Built-in flag not set: " << declFlags << " at " << this << " in " << this->context().scope() ); |
| 165 | + if ( declFlags & TXD_INITIALIZER ) { |
| 166 | + ASSERT( storage == TXS_STATIC, |
| 167 | + "Initializer not a static field: " << storage << " at " << this << " in " << this->context().scope() ); |
| 168 | + } |
| 169 | + else { |
| 170 | + ASSERT( declFlags & TXD_CONSTRUCTOR, "Constructor flag not set: " << declFlags << " at " << this << " in " << this->context().scope() ); |
| 171 | + ASSERT( storage == TXS_INSTANCEMETHOD, |
| 172 | + "Constructor not an instance method: " << storage << " at " << this << " in " << this->context().scope() ); |
| 173 | + } |
| 174 | + } |
| 175 | + |
| 176 | + // Note: Field is processed in the 'outer' scope and not in the 'inner' scope of its declaration. |
| 177 | + this->declaration = scope->declare_field( declName, this, declFlags, storage, TxIdentifier() ); |
| 178 | +} |
| 179 | + |
| 180 | +bool TxNonLocalFieldDefNode::is_main_signature_valid( const TxActualType* funcType ) const { |
| 181 | + auto retType = funcType->return_type(); |
| 182 | + bool retOk = bool( retType->get_type_class() == TXTC_VOID |
| 183 | + || retType->is_a( *this->context().package()->registry().get_builtin_type( TXBT_INTEGER ) ) ); |
| 184 | + if ( !retOk ) |
| 185 | + CERROR( this, "main() method has non-integer return type (must be void or integer): " << retType ); |
| 186 | + |
| 187 | + auto & argTypes = funcType->argument_types(); |
| 188 | + if ( argTypes.size() == 0 ) |
| 189 | + return retOk; |
| 190 | + else if ( argTypes.size() == 1 ) { |
| 191 | + const TxActualType* argsType = argTypes.at( 0 ); |
| 192 | + if ( argsType->get_type_class() == TXTC_REFERENCE ) { |
| 193 | + auto targetType = argsType->target_type(); |
| 194 | + if ( targetType->get_type_class() == TXTC_ARRAY ) { |
| 195 | + auto elemType = targetType->element_type(); |
| 196 | + if ( elemType->get_type_class() == TXTC_REFERENCE ) { |
| 197 | + auto elemTargetType = elemType->target_type(); |
| 198 | + if ( elemTargetType->get_type_class() == TXTC_ARRAY ) { |
| 199 | + auto elemTargetElemType = elemTargetType->element_type(); |
| 200 | + if ( elemTargetElemType->is_builtin( TXBT_UBYTE ) ) |
| 201 | + return retOk; |
| 202 | + } |
| 203 | + } |
| 204 | + } |
| 205 | + } |
| 206 | + CERROR( this, "main() method has invalid argument [required signature is main() or main( &[]&[]UByte )] : " << argsType ); |
| 207 | + } |
| 208 | + else |
| 209 | + CERROR( this, "main() method has too many arguments [required signature is main() or main( &[]&[]UByte )]" ); |
| 210 | + return false; |
| 211 | +} |
| 212 | + |
| 213 | +void TxNonLocalFieldDefNode::resolution_pass() { |
| 214 | + TxFieldDefiningNode::resolution_pass(); |
| 215 | + |
| 216 | + // handle main() function declarations: |
| 217 | + if ( this->fieldName->str() == "main" ) { |
| 218 | + auto funcField = this->field(); |
| 219 | + if ( funcField->qtype()->get_type_class() == TXTC_FUNCTION ) { |
| 220 | + // verify main program function candidate |
| 221 | + if ( !( funcField->get_storage() == TXS_GLOBAL || funcField->get_storage() == TXS_STATIC ) ) |
| 222 | + CERROR( this, "main() method must have global or static storage: " << funcField->get_storage() ); |
| 223 | + if ( is_main_signature_valid( funcField->qtype().type() ) ) { |
| 224 | + // register main program function candidate |
| 225 | + this->context().package()->registerMainFunc( this->declaration ); |
| 226 | + } |
| 227 | + } |
| 228 | + // non-function symbols declared with the name 'main' are allowed |
| 229 | + } |
| 230 | +} |
0 commit comments