~ubuntu-branches/ubuntu/warty/aqsis/warty

« back to all changes in this revision

Viewing changes to libslparse/typecheck.cpp

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2004-08-24 07:25:04 UTC
  • Revision ID: james.westby@ubuntu.com-20040824072504-zf993vnevvisdsvb
Tags: upstream-0.9.1
ImportĀ upstreamĀ versionĀ 0.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
////---------------------------------------------------------------------
 
2
////    Class definition file:  TYPECHECK.CPP
 
3
////    Associated header file: PARSENODE.H
 
4
////
 
5
////    Author:                                 Paul C. Gregory
 
6
////    Creation date:                  25/11/99
 
7
////---------------------------------------------------------------------
 
8
 
 
9
#include        "aqsis.h"
 
10
#include        "parsenode.h"
 
11
 
 
12
START_NAMESPACE( Aqsis )
 
13
 
 
14
///---------------------------------------------------------------------
 
15
/// CqParseNodeFunctionCall::TypeCheck
 
16
/// Do a type check based on suitable types requested, and add a cast if required.
 
17
/// Uses all possible functions listed to try to fund a suitable candidate.
 
18
 
 
19
TqInt   CqParseNodeFunctionCall::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
20
{
 
21
    TqInt NewType = Type_Nil;
 
22
    TqInt cSpecifiedArgs = 0;
 
23
 
 
24
    TqInt* aArgTypes = new TqInt[ m_aFuncRef.size() ];
 
25
    std::vector<CqFuncDef*> aFuncs;
 
26
 
 
27
    CqString strMyName = strName();
 
28
 
 
29
    // Prepare the error string.
 
30
    CqString strErr( strFileName() );
 
31
    strErr += " : ";
 
32
    strErr += CqString( LineNo() );
 
33
    strErr += " : ";
 
34
    strErr += strMyName;
 
35
    strErr += " : ";
 
36
    CqString strErrDesc = "Valid function declaration not found : ";
 
37
 
 
38
    // First discard any function possibilities which don't have the correct number of arguments.
 
39
    // Find out how many arguments have been specified.
 
40
    CqParseNode* pArg = m_pChild;
 
41
    while ( pArg != 0 )
 
42
    {
 
43
        cSpecifiedArgs++;
 
44
        pArg = pArg->pNext();
 
45
    }
 
46
 
 
47
    TqUint i;
 
48
    for ( i = 0; i < m_aFuncRef.size(); i++ )
 
49
    {
 
50
        aFuncs.push_back( CqFuncDef::GetFunctionPtr( m_aFuncRef[ i ] ) );
 
51
        if ( aFuncs[ i ] != 0 )
 
52
        {
 
53
            TqInt cArgs = aFuncs[ i ] ->cTypeSpecLength();
 
54
            if ( ( cArgs > 0 ) &&
 
55
                    ( ( !aFuncs[ i ] ->fVarying() && cArgs != cSpecifiedArgs ) ||
 
56
                      ( aFuncs[ i ] ->fVarying() && cSpecifiedArgs < cArgs ) ) )
 
57
            {
 
58
                m_aFuncRef.erase( m_aFuncRef.begin() + i );
 
59
                aFuncs.erase( aFuncs.begin() + i );
 
60
                i--;
 
61
            }
 
62
        }
 
63
    }
 
64
 
 
65
    // If we have eliminated all possibilities, then we have an error.
 
66
    if ( m_aFuncRef.size() == 0 )
 
67
    {
 
68
        strErr += "Arguments to function not valid : ";
 
69
        throw( strErr );
 
70
        return ( Type_Nil );
 
71
    }
 
72
 
 
73
    // Then typecheck the arguments.
 
74
    pArg = m_pChild;
 
75
    TqUint iArg = 0;
 
76
    TqBool fVarLen = TqFalse;
 
77
    while ( pArg != 0 )
 
78
    {
 
79
        CqParseNode * pNext = pArg->pNext();
 
80
        // Build an array of possible types.
 
81
        TqInt ctypes = 0;
 
82
        for ( i = 0; i < m_aFuncRef.size(); i++ )
 
83
        {
 
84
            if ( aFuncs[ i ] != 0 )
 
85
            {
 
86
                if ( aFuncs[ i ] ->cTypeSpecLength() <= iArg || ( aFuncs[ i ] ->fVarying() && aFuncs[ i ] ->cTypeSpecLength() == iArg ) )
 
87
                {
 
88
                    if ( aFuncs[ i ] ->cTypeSpecLength() >= iArg && aFuncs[ i ] ->fVarying() )
 
89
                        fVarLen = TqTrue;
 
90
                    continue;
 
91
                }
 
92
                else
 
93
                {
 
94
                    aArgTypes[ i ] = aFuncs[ i ] ->aTypeSpec() [ iArg ];
 
95
                    ctypes++;
 
96
                }
 
97
            }
 
98
        }
 
99
 
 
100
        // If we have no valid types to check, it must be a variable length function.
 
101
        if ( ctypes == 0 )
 
102
        {
 
103
            pArg->TypeCheck( pAllTypes(), Type_Last - 1, TqTrue );
 
104
            break;
 
105
        }
 
106
        // Now type check the argument
 
107
        TqInt ArgType = pArg->TypeCheck( aArgTypes, ctypes, TqTrue );
 
108
        // If no valid function exists for the argument, then this is an error.
 
109
        if ( ArgType == Type_Nil && !fVarLen )
 
110
        {
 
111
            strErr += strErrDesc;
 
112
            throw( strErr );
 
113
            return ( Type_Nil );
 
114
        }
 
115
        else if ( ArgType != Type_Nil )
 
116
            pArg->TypeCheck( &ArgType, 1 );     // Now do a real typecast
 
117
 
 
118
        // Check the list of possibles, and remove any that don't take the returned argument at the current point in the
 
119
        // argument list.
 
120
        for ( i = 0; i < m_aFuncRef.size(); i++ )
 
121
        {
 
122
            if ( strlen( aFuncs[ i ] ->strParams() ) <= iArg || aFuncs[ i ] ->strParams() [ iArg ] == '*' )
 
123
                continue;
 
124
 
 
125
            TqInt type = aFuncs[ i ] ->aTypeSpec() [ iArg ];
 
126
            if ( ( type & Type_Mask ) != ( ArgType & Type_Mask ) )
 
127
            {
 
128
                m_aFuncRef.erase( m_aFuncRef.begin() + i );
 
129
                aFuncs.erase( aFuncs.begin() + i );
 
130
                i--;
 
131
            }
 
132
            else
 
133
            {
 
134
                // If we have an upper case type in the function declaration, then we need an actual variable.
 
135
                if ( type & Type_Variable && !pArg->IsVariableRef() )
 
136
                {
 
137
                    strErrDesc = "Argument ";
 
138
                    strErrDesc += static_cast<TqInt>( iArg );
 
139
                    strErrDesc += " must be a variable";
 
140
                    m_aFuncRef.erase( m_aFuncRef.begin() + i );
 
141
                    aFuncs.erase( aFuncs.begin() + i );
 
142
                    i--;
 
143
                }
 
144
            }
 
145
        }
 
146
        pArg = pNext;
 
147
        iArg++;
 
148
    }
 
149
 
 
150
 
 
151
    // Check if any of the remaining functions return the correct type.
 
152
    for ( i = 0; i < m_aFuncRef.size(); i++ )
 
153
    {
 
154
        if ( aFuncs[ i ] != 0 )
 
155
        {
 
156
            TqInt j;
 
157
            for ( j = 0; j < Count; j++ )
 
158
            {
 
159
                if ( aFuncs[ i ] ->Type() == pTypes[ j ] )
 
160
                {
 
161
                    // Set the selected function declaration as top.
 
162
                    m_aFuncRef[ 0 ] = m_aFuncRef[ i ];
 
163
                    return ( pTypes[ j ] );
 
164
                }
 
165
            }
 
166
        }
 
167
    }
 
168
 
 
169
    // If we got here, we must cast the return value to a suitable type.
 
170
    for ( i = 0; i < m_aFuncRef.size(); i++ )
 
171
    {
 
172
        if ( aFuncs[ i ] != 0 )
 
173
        {
 
174
            TqInt j;
 
175
            for ( j = 0; j < Count; j++ )
 
176
            {
 
177
                if ( ( NewType = FindCast( aFuncs[ i ] ->Type(), pTypes, Count ) ) != Type_Nil )
 
178
                {
 
179
                    // Set the selected function declaration as top.
 
180
                    m_aFuncRef[ 0 ] = m_aFuncRef[ i ];
 
181
                    // Add a cast to the new type.
 
182
                    CqParseNode* pCast = new CqParseNodeCast( NewType );
 
183
                    LinkParent( pCast );
 
184
                    return ( NewType );
 
185
                }
 
186
            }
 
187
        }
 
188
    }
 
189
 
 
190
    strErr += strErrDesc;
 
191
    throw( strErr );
 
192
    return ( Type_Nil );
 
193
}
 
194
 
 
195
 
 
196
///---------------------------------------------------------------------
 
197
/// CqParseNodeFunctionCall::CheckArgCast
 
198
/// Check if it is possible to convert the arguments passed to this function
 
199
/// into valid arguments for any of its function declarations.
 
200
 
 
201
void CqParseNodeFunctionCall::CheckArgCast( std::vector<TqInt>& aRes )
 
202
{
 
203
    // Find out how many arguments have been specified.
 
204
    TqUint cArgs = 0;
 
205
    std::vector<TqInt> aArgTypes;
 
206
    CqParseNode* pArg = m_pChild;
 
207
    while ( pArg != 0 )
 
208
    {
 
209
        cArgs++;
 
210
        aArgTypes.push_back( pArg->ResType() );
 
211
        pArg = pArg->pNext();
 
212
    }
 
213
 
 
214
    // For each posible declaration...
 
215
    TqUint i;
 
216
    for ( i = 0; i < aRes.size(); i++ )
 
217
    {
 
218
        CqFuncDef* pFuncDef = CqFuncDef::GetFunctionPtr( m_aFuncRef[ aRes[ i ] ] );
 
219
        if ( pFuncDef == 0 ) continue;
 
220
 
 
221
        // ...build a list of variable types from its parameter type string.
 
222
        std::vector<TqInt>& aTypes = pFuncDef->aTypeSpec();
 
223
 
 
224
        // Check the number of arguments first.
 
225
        if ( ( aTypes.size() != cArgs && !pFuncDef->fVarying() ) ||
 
226
                aTypes.size() > cArgs )
 
227
        {
 
228
            aRes.erase( aRes.begin() + i );
 
229
            i--;
 
230
            continue;
 
231
        }
 
232
 
 
233
        // Now check through to see if the specified arguments can be converted to the required ones.
 
234
        TqBool  fValid = TqTrue;
 
235
        TqUint j;
 
236
        for ( j = 0; j < aTypes.size(); j++ )
 
237
            if ( FindCast( aArgTypes[ j ], &aTypes[ j ], 1 ) == Type_Nil ) fValid = TqFalse;
 
238
 
 
239
        // If we have found a match, return it.
 
240
        if ( !fValid )
 
241
        {
 
242
            aRes.erase( aRes.begin() + i );
 
243
            i--;
 
244
        }
 
245
    }
 
246
}
 
247
 
 
248
 
 
249
///---------------------------------------------------------------------
 
250
/// CqParseNodeFunctionCall::ArgCast
 
251
/// Convert the arguments passed to this function into valid arguments for the specified function declaration.
 
252
 
 
253
void CqParseNodeFunctionCall::ArgCast( TqInt iIndex )
 
254
{
 
255
    // NOTE: It is presumed that CheckArgCast has been called prior to this to
 
256
    // ensure that the argument list can validly be cast the the required parameters.
 
257
 
 
258
    CqFuncDef * pFuncDef = CqFuncDef::GetFunctionPtr( m_aFuncRef[ iIndex ] );
 
259
    if ( pFuncDef == 0 ) return ;
 
260
 
 
261
    // Build a list of variable types from its parameter type string.
 
262
    std::vector<TqInt>& aTypes = pFuncDef->aTypeSpec();
 
263
 
 
264
    // Now convert the arguments to the correct types
 
265
    CqParseNode* pArg = m_pChild;
 
266
    TqUint j = 0;
 
267
    while ( pArg != 0 && j < aTypes.size() )
 
268
    {
 
269
        // Must get the next here incase the check inserts a cast.
 
270
        CqParseNode * pNext = pArg->pNext();
 
271
        pArg->TypeCheck( &aTypes[ j++ ] );
 
272
        pArg = pNext;
 
273
    }
 
274
}
 
275
 
 
276
 
 
277
///---------------------------------------------------------------------
 
278
/// CqParseNodeUnresolvedCall::TypeCheck
 
279
/// This is rather awkward, we will convert to whichever type we are asked
 
280
/// to be, then later when the shader vm parses the .slx we can try and build
 
281
/// a cast then, the same goes for the arguments.
 
282
 
 
283
TqInt   CqParseNodeUnresolvedCall::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
284
{
 
285
    TqInt NewType = Type_Nil;
 
286
 
 
287
    // TypeCheck the args, we don't know what types will be needed
 
288
    // later, so there is little else we can do.
 
289
    CqParseNode *pArg = m_pChild;
 
290
    while (pArg != NULL)
 
291
    {
 
292
        CqParseNode *pNext = pArg->pNext();
 
293
        pArg->TypeCheck( pAllTypes(), Type_Last - 1 );
 
294
        pArg = pNext;
 
295
    };
 
296
 
 
297
    // If we have no type set yet we take the first type given as an option
 
298
    if(m_aFuncDef.Type() == Type_Nil || !CheckOnly)
 
299
    {
 
300
        // Is Void acceptable, if so we prefer it.
 
301
        int i;
 
302
        for( i=0; i < Count; i++)
 
303
        {
 
304
            if( pTypes[i] == Type_Void)
 
305
                NewType = Type_Void;
 
306
        };
 
307
        // Otherwise we fall back to the first option given
 
308
        if( NewType == Type_Nil )
 
309
            NewType = pTypes[0];
 
310
 
 
311
        m_aFuncDef = CqFuncDef( NewType,
 
312
                                m_aFuncDef.strName(),
 
313
                                "unresolved",
 
314
                                m_aFuncDef.strParams(),
 
315
                                m_aFuncDef.pDefNode(),
 
316
                                m_aFuncDef.pArgs());
 
317
    };
 
318
 
 
319
    return m_aFuncDef.Type();
 
320
}
 
321
 
 
322
 
 
323
///---------------------------------------------------------------------
 
324
/// CqParseNodeVariable::TypeCheck
 
325
/// Do a type check based on suitable types requested, and add a cast in required.
 
326
 
 
327
TqInt   CqParseNodeVariable::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
328
{
 
329
    // Check if the variable type matches any of the requested ones.
 
330
    TqInt       MyType = ( ResType() & Type_Mask );
 
331
    TqInt i;
 
332
    for ( i = 0; i < Count; i++ )
 
333
    {
 
334
        if ( pTypes[ i ] == MyType )
 
335
            return ( MyType );
 
336
    }
 
337
    // If we got here, we are not of the correct type, so find a suitable cast.
 
338
    TqInt NewType = FindCast( MyType, pTypes, Count );
 
339
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
340
    LinkParent( pCast );
 
341
 
 
342
    if ( NewType == Type_Nil && !CheckOnly )
 
343
    {
 
344
        CqString strErr( strFileName() );
 
345
        strErr += " : ";
 
346
        strErr += LineNo();
 
347
        strErr += " : ";
 
348
        strErr += "Cannot convert from type ";
 
349
        strErr += CqParseNode::TypeName( MyType );
 
350
        strErr += " to any of the required types";
 
351
        throw( strErr );
 
352
        return ( Type_Nil );
 
353
    }
 
354
    return ( NewType );
 
355
}
 
356
 
 
357
 
 
358
///---------------------------------------------------------------------
 
359
/// CqParseNodeVariableArray::TypeCheck
 
360
/// Do a type check based on suitable types requested, and add a cast in required.
 
361
 
 
362
TqInt   CqParseNodeVariableArray::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
363
{
 
364
    // Check if the child can be made into a float.
 
365
    TqInt aType = Type_Float;
 
366
    if ( m_pChild->TypeCheck( &aType, 1, CheckOnly ) == Type_Nil )
 
367
    {
 
368
        TqInt   IndexType = ( m_pChild->ResType() & Type_Mask );
 
369
        CqString strErr( strFileName() );
 
370
        strErr += " : ";
 
371
        strErr += LineNo();
 
372
        strErr += " : ";
 
373
        strErr += "Array index must be float type : ";
 
374
        strErr += CqParseNode::TypeName( IndexType );
 
375
        throw( strErr );
 
376
        return ( Type_Nil );
 
377
    }
 
378
 
 
379
    return ( CqParseNodeVariable::TypeCheck( pTypes, Count, CheckOnly ) );
 
380
}
 
381
 
 
382
 
 
383
///---------------------------------------------------------------------
 
384
/// CqParseNodeAssign::TypeCheck
 
385
/// Do a type check based on suitable types requested, and add a cast in required.
 
386
 
 
387
extern EqShaderType gShaderType;
 
388
 
 
389
TqInt   CqParseNodeAssign::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
390
{
 
391
    // First check if the assign is to a read only variable.
 
392
    if( CqVarDef::GetVariablePtr( m_VarRef ) &&
 
393
            pShaderNode() &&
 
394
            CqVarDef::GetVariablePtr( m_VarRef )->ReadOnly( pShaderNode()->ShaderType() ) )
 
395
    {
 
396
        CqString strErr( strFileName() );
 
397
        strErr += " : ";
 
398
        strErr += LineNo();
 
399
        strErr += " : ";
 
400
        strErr += "Cannot access read only variable '";
 
401
        strErr += CqVarDef::GetVariablePtr( m_VarRef )->strName();
 
402
        strErr += "' in shader type '";
 
403
        strErr += gShaderTypeNames[ pShaderNode()->ShaderType() ];
 
404
        strErr += "'";
 
405
        throw( strErr );
 
406
        return ( Type_Nil );
 
407
    }
 
408
 
 
409
    TqInt       MyType = ( ResType() & Type_Mask );
 
410
    // Type check the assignment expression first.
 
411
    CqParseNode* pExpr = m_pChild;
 
412
    if ( pExpr->TypeCheck( &MyType, 1, CheckOnly ) != MyType )
 
413
        return ( Type_Nil );    // TODO: Should throw an exception here.
 
414
 
 
415
    // Check if the variable type matches any of the requested ones.
 
416
    TqInt i;
 
417
    for ( i = 0; i < Count; i++ )
 
418
    {
 
419
        if ( pTypes[ i ] == MyType )
 
420
            return ( MyType );
 
421
    }
 
422
    // If we got here, we are not of the correct type, so find a suitable cast.
 
423
    TqInt NewType = FindCast( MyType, pTypes, Count );
 
424
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
425
    LinkParent( pCast );
 
426
 
 
427
    if ( NewType == Type_Nil && !CheckOnly )
 
428
    {
 
429
        CqString strErr( strFileName() );
 
430
        strErr += " : ";
 
431
        strErr += LineNo();
 
432
        strErr += " : ";
 
433
        strErr += "Cannot convert from type ";
 
434
        strErr += CqParseNode::TypeName( MyType );
 
435
        strErr += " to any of the required types";
 
436
        throw( strErr );
 
437
        return ( Type_Nil );
 
438
    }
 
439
    return ( NewType );
 
440
}
 
441
 
 
442
 
 
443
///---------------------------------------------------------------------
 
444
/// CqParseNodeAssignArray::TypeCheck
 
445
/// Do a type check based on suitable types requested, and add a cast in required.
 
446
 
 
447
TqInt   CqParseNodeAssignArray::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
448
{
 
449
    // Check if the child can be made into a float.
 
450
    TqInt aType = Type_Float;
 
451
    if ( m_pChild->pNext() ->TypeCheck( &aType, 1, CheckOnly ) == Type_Nil )
 
452
    {
 
453
        TqInt   IndexType = ( m_pChild->pNext() ->ResType() & Type_Mask );
 
454
        CqString strErr( strFileName() );
 
455
        strErr += " : ";
 
456
        strErr += LineNo();
 
457
        strErr += " : ";
 
458
        strErr += "Array index must be float type : ";
 
459
        strErr += CqParseNode::TypeName( IndexType );
 
460
        throw( strErr );
 
461
        return ( Type_Nil );
 
462
    }
 
463
 
 
464
    return ( CqParseNodeAssign::TypeCheck( pTypes, Count, CheckOnly ) );
 
465
}
 
466
 
 
467
 
 
468
///---------------------------------------------------------------------
 
469
/// CqParseNodeOp::TypeCheck
 
470
/// Do a type check based on suitable types requested, and add a cast in required.
 
471
 
 
472
TqInt   CqParseNodeOp::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
473
{
 
474
    // Check if both arguments to the operator match type.
 
475
    CqParseNode * pOperandA = m_pChild;
 
476
    CqParseNode* pOperandB = m_pChild->pNext();
 
477
    assert( pOperandA != 0 && pOperandB != 0 );
 
478
    TqInt TypeA = ( pOperandA->ResType() & Type_Mask );
 
479
    TqInt TypeB = ( pOperandB->ResType() & Type_Mask );
 
480
 
 
481
    // See if they can both be cast to a requested type.
 
482
    TqInt i;
 
483
    for ( i = 0; i < Count; i++ )
 
484
    {
 
485
        if ( FindCast( TypeA, &pTypes[ i ], 1 ) != Type_Nil )
 
486
        {
 
487
            if ( FindCast( TypeB, &pTypes[ i ], 1 ) != Type_Nil )
 
488
            {
 
489
                // Add any cast operators required.
 
490
                pOperandA->TypeCheck( &pTypes[ i ], 1, CheckOnly );
 
491
                pOperandB->TypeCheck( &pTypes[ i ], 1, CheckOnly );
 
492
                return ( pTypes[ i ] );
 
493
            }
 
494
        }
 
495
    }
 
496
 
 
497
    if ( !CheckOnly )
 
498
    {
 
499
        CqString strErr( strFileName() );
 
500
        strErr += " : ";
 
501
        strErr += LineNo();
 
502
        strErr += " : ";
 
503
        strErr += "Cannot find a suitable cast for the operands.";
 
504
        throw( strErr );
 
505
        return ( Type_Nil );
 
506
    }
 
507
 
 
508
    return ( Type_Nil );
 
509
}
 
510
 
 
511
 
 
512
///---------------------------------------------------------------------
 
513
/// CqParseNodeRelOp::TypeCheck
 
514
/// Do a type check based on suitable types requested, and add a cast in required.
 
515
 
 
516
TqInt   CqParseNodeRelOp::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
517
{
 
518
    // Type check the operands first.
 
519
    CqParseNode * pExpr1 = m_pChild;
 
520
    CqParseNode* pExpr2 = pExpr1->pNext();
 
521
    pExpr1->TypeCheck( pAllTypes(), Type_Last - 1, CheckOnly );
 
522
    pExpr2->TypeCheck( pAllTypes(), Type_Last - 1, CheckOnly );
 
523
 
 
524
    // See if float is a requested type.
 
525
    TqInt NewType;
 
526
    if ( ( NewType = FindCast( Type_Float, pTypes, Count ) ) != Type_Nil )
 
527
    {
 
528
        if ( NewType == Type_Float ) return ( Type_Float );
 
529
        else
 
530
        {
 
531
            CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
532
            LinkParent( pCast );
 
533
            return ( NewType );
 
534
        }
 
535
    }
 
536
 
 
537
    if ( !CheckOnly )
 
538
    {
 
539
        CqString strErr( strFileName() );
 
540
        strErr += " : ";
 
541
        strErr += LineNo();
 
542
        strErr += " : ";
 
543
        strErr += "Relative operators only return float.";
 
544
        throw( strErr );
 
545
        return ( Type_Nil );
 
546
    }
 
547
 
 
548
    return ( Type_Nil );
 
549
}
 
550
 
 
551
 
 
552
///---------------------------------------------------------------------
 
553
/// CqParseNodeUnaryOp::TypeCheck
 
554
/// Do a type check based on suitable types requested, and add a cast in required.
 
555
 
 
556
TqInt   CqParseNodeUnaryOp::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
557
{
 
558
    // Check if the operand can be cast to a requested type.
 
559
    if ( m_pChild != 0 )
 
560
        return ( m_pChild->TypeCheck( pTypes, Count, CheckOnly ) );
 
561
    else
 
562
        return ( Type_Nil );
 
563
}
 
564
 
 
565
 
 
566
///---------------------------------------------------------------------
 
567
/// CqParseNodeOpDot::TypeCheck
 
568
/// Do a type check based on suitable types requested, and add a cast in required.
 
569
 
 
570
TqInt   CqParseNodeMathOpDot::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
571
{
 
572
    static TqInt aArgTypes[ 3 ] = {Type_Point, Type_Vector, Type_Normal};
 
573
 
 
574
    // Get the argument types.
 
575
    CqParseNode* pOperandA = m_pChild;
 
576
    CqParseNode* pOperandB = m_pChild->pNext();
 
577
    assert( pOperandA != 0 && pOperandB != 0 );
 
578
    TqInt TypeA = ( pOperandA->ResType() & Type_Mask );
 
579
    TqInt TypeB = ( pOperandB->ResType() & Type_Mask );
 
580
 
 
581
    // Dot operator can only take normal/vector/point types, check the
 
582
    // arguments can be made to match this, and always returns a float,
 
583
    // check this is valid.
 
584
 
 
585
    TqInt RetType;
 
586
    if ( ( RetType = FindCast( Type_Float, pTypes, Count ) ) != Type_Nil )
 
587
    {
 
588
        TqBool fValid = TqFalse;
 
589
        TqUint i;
 
590
        for ( i = 0; i < sizeof( aArgTypes ) / sizeof( aArgTypes[ 0 ] ); i++ )
 
591
        {
 
592
            if ( FindCast( TypeA, &aArgTypes[ i ], 1 ) != Type_Nil )
 
593
            {
 
594
                if ( FindCast( TypeB, &aArgTypes[ i ], 1 ) != Type_Nil )
 
595
                {
 
596
                    // Add any cast operators required.
 
597
                    pOperandA->TypeCheck( &aArgTypes[ i ], 1, CheckOnly );
 
598
                    pOperandB->TypeCheck( &aArgTypes[ i ], 1, CheckOnly );
 
599
                    fValid = TqTrue;
 
600
                    break;
 
601
                }
 
602
            }
 
603
        }
 
604
        if ( fValid )
 
605
        {
 
606
            if ( RetType != Type_Float )
 
607
            {
 
608
                CqParseNodeCast * pCast = new CqParseNodeCast( RetType );
 
609
                LinkParent( pCast );
 
610
            }
 
611
            return ( RetType );
 
612
        }
 
613
    }
 
614
 
 
615
    if ( !CheckOnly )
 
616
    {
 
617
        CqString strErr( strFileName() );
 
618
        strErr += " : ";
 
619
        strErr += LineNo();
 
620
        strErr += " : ";
 
621
        strErr += "Cannot find a suitable cast for the operands.";
 
622
        throw( strErr );
 
623
        return ( Type_Nil );
 
624
    }
 
625
 
 
626
    return ( Type_Nil );
 
627
}
 
628
 
 
629
 
 
630
///---------------------------------------------------------------------
 
631
/// CqParseNodeConst::TypeCheck
 
632
/// Perform a typecheck, and add cast if required.
 
633
 
 
634
TqInt CqParseNodeConst::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
635
{
 
636
    // Check if the variable type matches any of the requested ones.
 
637
    TqInt       MyType = ResType();
 
638
    TqInt i;
 
639
    for ( i = 0; i < Count; i++ )
 
640
    {
 
641
        if ( pTypes[ i ] == MyType )
 
642
            return ( MyType );
 
643
    }
 
644
 
 
645
    TqInt NewType = FindCast( MyType, pTypes, Count );
 
646
    // If we got here, we are not of the correct type, so find a suitable cast.
 
647
    if ( !CheckOnly )
 
648
    {
 
649
        CqParseNodeCast * pCast = new CqParseNodeCast( NewType );
 
650
        LinkParent( pCast );
 
651
    }
 
652
 
 
653
    if ( NewType == Type_Nil && !CheckOnly )
 
654
    {
 
655
        CqString strErr( strFileName() );
 
656
        strErr += " : ";
 
657
        strErr += LineNo();
 
658
        strErr += " : ";
 
659
        strErr += "Cannot convert from type ";
 
660
        strErr += CqParseNode::TypeName( MyType );
 
661
        strErr += " to any of the required types";
 
662
        throw( strErr );
 
663
        return ( Type_Nil );
 
664
    }
 
665
    return ( NewType );
 
666
}
 
667
 
 
668
 
 
669
///---------------------------------------------------------------------
 
670
/// CqParseNodeCast::TypeCheck
 
671
/// Do a type check based on suitable types requested, and add a cast in required.
 
672
 
 
673
TqInt   CqParseNodeCast::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
674
{
 
675
    // Perform a typecheck on the cast expression
 
676
    CqParseNode * pExpr = m_pChild;
 
677
    pExpr->TypeCheck( &m_tTo, 1, CheckOnly );
 
678
 
 
679
    // Check the return type, and add another cast if necessary.
 
680
    // Note: We add another cast to allow for forced casts of function return types,
 
681
    // i.e. we want the sl code "Ci=float noise(P)"
 
682
    // to call float noise THEN cast to a color, not call color noise.
 
683
    TqInt i;
 
684
    for ( i = 0; i < Count; i++ )
 
685
        if ( pTypes[ i ] == m_tTo ) return ( m_tTo );
 
686
 
 
687
    TqInt NewType = FindCast( m_tTo, pTypes, Count );
 
688
    if ( NewType == Type_Nil && !CheckOnly )
 
689
    {
 
690
        CqString strErr( strFileName() );
 
691
        strErr += " : ";
 
692
        strErr += LineNo();
 
693
        strErr += " : ";
 
694
        strErr += "Cannot convert from type ";
 
695
        strErr += CqParseNode::TypeName( NewType );
 
696
        strErr += " to any of the required types";
 
697
        throw( strErr );
 
698
        return ( Type_Nil );
 
699
    }
 
700
    else
 
701
    {
 
702
        if ( !CheckOnly )
 
703
        {
 
704
            CqParseNodeCast * pCast = new CqParseNodeCast( NewType );
 
705
            LinkParent( pCast );
 
706
        }
 
707
    }
 
708
 
 
709
    return ( NewType );
 
710
}
 
711
 
 
712
 
 
713
///---------------------------------------------------------------------
 
714
/// CqParseNodeTriple::TypeCheck
 
715
/// Do a type check based on suitable types requested, and add a cast in required.
 
716
 
 
717
TqInt   CqParseNodeTriple::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
718
{
 
719
    static TqInt ExprType = Type_Float;
 
720
    // Perform a typecheck on the three float expressions
 
721
    CqParseNode* pExpr = m_pChild;
 
722
    while ( pExpr != 0 )
 
723
    {
 
724
        pExpr->TypeCheck( &ExprType, 1, CheckOnly );
 
725
        pExpr = pExpr->pNext();
 
726
    }
 
727
    // Check if expecting a triple, if not add a cast
 
728
    TqInt i;
 
729
    for ( i = 0; i < Count; i++ )
 
730
        if ( pTypes[ i ] == Type_Triple ) return ( Type_Triple );
 
731
 
 
732
    // If we got here, we are not of the correct type, so find a suitable cast.
 
733
    TqInt NewType = FindCast( Type_Triple, pTypes, Count );
 
734
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
735
    LinkParent( pCast );
 
736
 
 
737
    if ( NewType == Type_Nil && !CheckOnly )
 
738
    {
 
739
        CqString strErr( strFileName() );
 
740
        strErr += " : ";
 
741
        strErr += LineNo();
 
742
        strErr += " : ";
 
743
        strErr += "Cannot convert from type ";
 
744
        strErr += CqParseNode::TypeName( NewType );
 
745
        strErr += " to any of the required types";
 
746
        throw( strErr );
 
747
        return ( Type_Nil );
 
748
    }
 
749
    return ( NewType );
 
750
}
 
751
 
 
752
 
 
753
///---------------------------------------------------------------------
 
754
/// CqParseNodeHexTuple::TypeCheck
 
755
/// Do a type check based on suitable types requested, and add a cast in required.
 
756
 
 
757
TqInt   CqParseNodeHexTuple::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
758
{
 
759
    static TqInt ExprType = Type_Float;
 
760
    // Perform a typecheck on the three float expressions
 
761
    CqParseNode* pExpr = m_pChild;
 
762
    while ( pExpr != 0 )
 
763
    {
 
764
        pExpr->TypeCheck( &ExprType, 1, CheckOnly );
 
765
        pExpr = pExpr->pNext();
 
766
    }
 
767
    // Check if expecting a sixteentuple, if not add a cast
 
768
    TqInt i;
 
769
    for ( i = 0; i < Count; i++ )
 
770
        if ( pTypes[ i ] == Type_HexTuple ) return ( Type_HexTuple );
 
771
 
 
772
    // If we got here, we are not of the correct type, so find a suitable cast.
 
773
    TqInt NewType = FindCast( Type_Matrix, pTypes, Count );
 
774
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
775
    LinkParent( pCast );
 
776
 
 
777
    if ( NewType == Type_Nil && !CheckOnly )
 
778
    {
 
779
        CqString strErr( strFileName() );
 
780
        strErr += " : ";
 
781
        strErr += LineNo();
 
782
        strErr += " : ";
 
783
        strErr += "Cannot convert from type ";
 
784
        strErr += CqParseNode::TypeName( NewType );
 
785
        strErr += " to any of the required types";
 
786
        throw( strErr );
 
787
        return ( Type_Nil );
 
788
    }
 
789
    return ( NewType );
 
790
}
 
791
 
 
792
 
 
793
///---------------------------------------------------------------------
 
794
/// CqParseNodeCommFunction::TypeCheck
 
795
 
 
796
TqInt CqParseNodeCommFunction::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
797
{
 
798
    // Check if the variable type matches any of the requested ones.
 
799
    TqInt       MyType = ResType();
 
800
    TqInt i;
 
801
    for ( i = 0; i < Count; i++ )
 
802
    {
 
803
        if ( pTypes[ i ] == MyType )
 
804
            return ( MyType );
 
805
    }
 
806
    // If we got here, we are not of the correct type, so find a suitable cast.
 
807
    TqInt NewType = FindCast( MyType, pTypes, Count );
 
808
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
809
    LinkParent( pCast );
 
810
 
 
811
    if ( NewType == Type_Nil && !CheckOnly )
 
812
    {
 
813
        CqString strErr( strFileName() );
 
814
        strErr += " : ";
 
815
        strErr += LineNo();
 
816
        strErr += " : ";
 
817
        strErr += "Cannot convert from type ";
 
818
        strErr += CqParseNode::TypeName( MyType );
 
819
        strErr += " to any of the required types";
 
820
        throw( strErr );
 
821
        return ( Type_Nil );
 
822
    }
 
823
    return ( NewType );
 
824
}
 
825
 
 
826
 
 
827
///---------------------------------------------------------------------
 
828
/// CqParseNodeQCond::TypeCheck
 
829
/// Type check the return from a conditional statement and cast the true/false expressions if necessary.
 
830
 
 
831
TqInt   CqParseNodeQCond::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
832
{
 
833
    // Ensure that the conditional expression is type checked.
 
834
    CqParseNode * pCondExp = m_pChild;
 
835
    assert( pCondExp != 0 );
 
836
    pCondExp->TypeCheck( pAllTypes(), Type_Last - 1, CheckOnly );
 
837
 
 
838
    // Check if both expressions match type.
 
839
    CqParseNode * pTrue = m_pChild->pNext();
 
840
    assert( pTrue != 0 );
 
841
    CqParseNode* pFalse = pTrue->pNext();
 
842
    assert( pFalse != 0 );
 
843
 
 
844
    TqInt TypeT = ( pTrue->ResType() & Type_Mask );
 
845
    TqInt TypeF = ( pFalse->ResType() & Type_Mask );
 
846
 
 
847
    // See if they can both be cast to a requested type.
 
848
    TqInt i;
 
849
    for ( i = 0; i < Count; i++ )
 
850
    {
 
851
        if ( FindCast( TypeT, &pTypes[ i ], 1 ) != Type_Nil )
 
852
        {
 
853
            if ( FindCast( TypeF, &pTypes[ i ], 1 ) != Type_Nil )
 
854
            {
 
855
                // Add any cast operators required.
 
856
                pTrue->TypeCheck( &pTypes[ i ], 1, CheckOnly );
 
857
                pFalse->TypeCheck( &pTypes[ i ], 1, CheckOnly );
 
858
                return ( pTypes[ i ] );
 
859
            }
 
860
        }
 
861
    }
 
862
 
 
863
    if ( !CheckOnly )
 
864
    {
 
865
        CqString strErr( strFileName() );
 
866
        strErr += " : ";
 
867
        strErr += LineNo();
 
868
        strErr += " : ";
 
869
        strErr += "Cannot find a suitable cast for the expressions.";
 
870
        throw( strErr );
 
871
        return ( Type_Nil );
 
872
    }
 
873
 
 
874
    return ( Type_Nil );
 
875
}
 
876
 
 
877
 
 
878
END_NAMESPACE( Aqsis )
 
879
//---------------------------------------------------------------------