~ubuntu-branches/ubuntu/breezy/aqsis/breezy

« back to all changes in this revision

Viewing changes to libslparse/typecheck.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Will Newton
  • Date: 2004-12-07 20:06:49 UTC
  • Revision ID: james.westby@ubuntu.com-20041207200649-fccswkrvp4oc8lmn
Tags: upstream-0.9.3
ImportĀ upstreamĀ versionĀ 0.9.3

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. While doing so, rebuild the params string for the
 
289
        // external declaration in the .slx
 
290
        CqString strArgTypes("");
 
291
    CqParseNode *pArg = m_pChild;
 
292
    while (pArg != NULL)
 
293
    {
 
294
        CqParseNode *pNext = pArg->pNext();
 
295
        pArg->TypeCheck( pAllTypes(), Type_Last - 1 );
 
296
                strArgTypes+=CqParseNode::TypeIdentifier(pArg->ResType());
 
297
        pArg = pNext;
 
298
    };
 
299
 
 
300
        // Store the newly decided parameter list string. This now reflects the actual parameter types 
 
301
        // passed in.
 
302
        m_aFuncDef.SetstrParams(strArgTypes);
 
303
 
 
304
    // If we have no type set yet we take the first type given as an option
 
305
    if(m_aFuncDef.Type() == Type_Nil || !CheckOnly)
 
306
    {
 
307
        // Is Void acceptable, if so we prefer it.
 
308
        int i;
 
309
        for( i=0; i < Count; i++)
 
310
        {
 
311
            if( pTypes[i] == Type_Void)
 
312
                NewType = Type_Void;
 
313
        };
 
314
        // Otherwise we fall back to the first option given
 
315
        if( NewType == Type_Nil )
 
316
            NewType = pTypes[0];
 
317
 
 
318
        m_aFuncDef = CqFuncDef( NewType,
 
319
                                m_aFuncDef.strName(),
 
320
                                "unresolved",
 
321
                                m_aFuncDef.strParams(),
 
322
                                m_aFuncDef.pDefNode(),
 
323
                                m_aFuncDef.pArgs());
 
324
    };
 
325
 
 
326
    return m_aFuncDef.Type();
 
327
}
 
328
 
 
329
 
 
330
///---------------------------------------------------------------------
 
331
/// CqParseNodeVariable::TypeCheck
 
332
/// Do a type check based on suitable types requested, and add a cast in required.
 
333
 
 
334
TqInt   CqParseNodeVariable::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
335
{
 
336
    // Check if the variable type matches any of the requested ones.
 
337
    TqInt       MyType = ( ResType() & Type_Mask );
 
338
    TqInt i;
 
339
    for ( i = 0; i < Count; i++ )
 
340
    {
 
341
        if ( pTypes[ i ] == MyType )
 
342
            return ( MyType );
 
343
    }
 
344
    // If we got here, we are not of the correct type, so find a suitable cast.
 
345
    TqInt NewType = FindCast( MyType, pTypes, Count );
 
346
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
347
    LinkParent( pCast );
 
348
 
 
349
    if ( NewType == Type_Nil && !CheckOnly )
 
350
    {
 
351
        CqString strErr( strFileName() );
 
352
        strErr += " : ";
 
353
        strErr += LineNo();
 
354
        strErr += " : ";
 
355
        strErr += "Cannot convert from type ";
 
356
        strErr += CqParseNode::TypeName( MyType );
 
357
        strErr += " to any of the required types";
 
358
        throw( strErr );
 
359
        return ( Type_Nil );
 
360
    }
 
361
    return ( NewType );
 
362
}
 
363
 
 
364
 
 
365
///---------------------------------------------------------------------
 
366
/// CqParseNodeVariableArray::TypeCheck
 
367
/// Do a type check based on suitable types requested, and add a cast in required.
 
368
 
 
369
TqInt   CqParseNodeVariableArray::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
370
{
 
371
    // Check if the child can be made into a float.
 
372
    TqInt aType = Type_Float;
 
373
    if ( m_pChild->TypeCheck( &aType, 1, CheckOnly ) == Type_Nil )
 
374
    {
 
375
        TqInt   IndexType = ( m_pChild->ResType() & Type_Mask );
 
376
        CqString strErr( strFileName() );
 
377
        strErr += " : ";
 
378
        strErr += LineNo();
 
379
        strErr += " : ";
 
380
        strErr += "Array index must be float type : ";
 
381
        strErr += CqParseNode::TypeName( IndexType );
 
382
        throw( strErr );
 
383
        return ( Type_Nil );
 
384
    }
 
385
 
 
386
        // Check if the variable is an array.
 
387
        CqVarDef* pVar=CqVarDef::GetVariablePtr(m_VarRef);
 
388
        // Check if the declaration marked it as an arry
 
389
        if(!(pVar->Type()&Type_Array))
 
390
        {
 
391
        TqInt   myType = ( ResType() & Type_Mask );
 
392
        CqString strErr( strFileName() );
 
393
        strErr += " : ";
 
394
        strErr += LineNo();
 
395
        strErr += " : ";
 
396
        strErr += "Attempt to access array member of non-array type : ";
 
397
        strErr += CqParseNode::TypeName( myType );
 
398
        throw( strErr );
 
399
        return ( Type_Nil );
 
400
        }
 
401
 
 
402
    return ( CqParseNodeVariable::TypeCheck( pTypes, Count, CheckOnly ) );
 
403
}
 
404
 
 
405
 
 
406
///---------------------------------------------------------------------
 
407
/// CqParseNodeAssign::TypeCheck
 
408
/// Do a type check based on suitable types requested, and add a cast in required.
 
409
 
 
410
extern EqShaderType gShaderType;
 
411
 
 
412
TqInt   CqParseNodeAssign::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
413
{
 
414
    // First check if the assign is to a read only variable.
 
415
    if( CqVarDef::GetVariablePtr( m_VarRef ) &&
 
416
            pShaderNode() &&
 
417
            CqVarDef::GetVariablePtr( m_VarRef )->ReadOnly( pShaderNode()->ShaderType() ) )
 
418
    {
 
419
        CqString strErr( strFileName() );
 
420
        strErr += " : ";
 
421
        strErr += LineNo();
 
422
        strErr += " : ";
 
423
        strErr += "Cannot access read only variable '";
 
424
        strErr += CqVarDef::GetVariablePtr( m_VarRef )->strName();
 
425
        strErr += "' in shader type '";
 
426
        strErr += gShaderTypeNames[ pShaderNode()->ShaderType() ];
 
427
        strErr += "'";
 
428
        throw( strErr );
 
429
        return ( Type_Nil );
 
430
    }
 
431
 
 
432
    TqInt       MyType = ( ResType() & Type_Mask );
 
433
    // Type check the assignment expression first.
 
434
    CqParseNode* pExpr = m_pChild;
 
435
    if ( pExpr->TypeCheck( &MyType, 1, CheckOnly ) != MyType )
 
436
        return ( Type_Nil );    // TODO: Should throw an exception here.
 
437
 
 
438
    // Check if the variable type matches any of the requested ones.
 
439
    TqInt i;
 
440
    for ( i = 0; i < Count; i++ )
 
441
    {
 
442
        if ( pTypes[ i ] == MyType )
 
443
            return ( MyType );
 
444
    }
 
445
    // If we got here, we are not of the correct type, so find a suitable cast.
 
446
    TqInt NewType = FindCast( MyType, pTypes, Count );
 
447
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
448
    LinkParent( pCast );
 
449
 
 
450
    if ( NewType == Type_Nil && !CheckOnly )
 
451
    {
 
452
        CqString strErr( strFileName() );
 
453
        strErr += " : ";
 
454
        strErr += LineNo();
 
455
        strErr += " : ";
 
456
        strErr += "Cannot convert from type ";
 
457
        strErr += CqParseNode::TypeName( MyType );
 
458
        strErr += " to any of the required types";
 
459
        throw( strErr );
 
460
        return ( Type_Nil );
 
461
    }
 
462
    return ( NewType );
 
463
}
 
464
 
 
465
 
 
466
///---------------------------------------------------------------------
 
467
/// CqParseNodeAssignArray::TypeCheck
 
468
/// Do a type check based on suitable types requested, and add a cast in required.
 
469
 
 
470
TqInt   CqParseNodeAssignArray::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
471
{
 
472
    // Check if the child can be made into a float.
 
473
    TqInt aType = Type_Float;
 
474
    if ( m_pChild->pNext() ->TypeCheck( &aType, 1, CheckOnly ) == Type_Nil )
 
475
    {
 
476
        TqInt   IndexType = ( m_pChild->pNext() ->ResType() & Type_Mask );
 
477
        CqString strErr( strFileName() );
 
478
        strErr += " : ";
 
479
        strErr += LineNo();
 
480
        strErr += " : ";
 
481
        strErr += "Array index must be float type : ";
 
482
        strErr += CqParseNode::TypeName( IndexType );
 
483
        throw( strErr );
 
484
        return ( Type_Nil );
 
485
    }
 
486
 
 
487
    return ( CqParseNodeAssign::TypeCheck( pTypes, Count, CheckOnly ) );
 
488
}
 
489
 
 
490
 
 
491
///---------------------------------------------------------------------
 
492
/// CqParseNodeOp::TypeCheck
 
493
/// Do a type check based on suitable types requested, and add a cast in required.
 
494
 
 
495
TqInt   CqParseNodeOp::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
496
{
 
497
    // Check if both arguments to the operator match type.
 
498
    CqParseNode * pOperandA = m_pChild;
 
499
    CqParseNode* pOperandB = m_pChild->pNext();
 
500
    assert( pOperandA != 0 && pOperandB != 0 );
 
501
    TqInt TypeA = ( pOperandA->ResType() & Type_Mask );
 
502
    TqInt TypeB = ( pOperandB->ResType() & Type_Mask );
 
503
 
 
504
    // See if they can both be cast to a requested type.
 
505
    TqInt i;
 
506
    for ( i = 0; i < Count; i++ )
 
507
    {
 
508
        if ( FindCast( TypeA, &pTypes[ i ], 1 ) != Type_Nil )
 
509
        {
 
510
            if ( FindCast( TypeB, &pTypes[ i ], 1 ) != Type_Nil )
 
511
            {
 
512
                // Add any cast operators required.
 
513
                pOperandA->TypeCheck( &pTypes[ i ], 1, CheckOnly );
 
514
                pOperandB->TypeCheck( &pTypes[ i ], 1, CheckOnly );
 
515
                return ( pTypes[ i ] );
 
516
            }
 
517
        }
 
518
    }
 
519
 
 
520
    if ( !CheckOnly )
 
521
    {
 
522
        CqString strErr( strFileName() );
 
523
        strErr += " : ";
 
524
        strErr += LineNo();
 
525
        strErr += " : ";
 
526
        strErr += "Cannot find a suitable cast for the operands.";
 
527
        throw( strErr );
 
528
        return ( Type_Nil );
 
529
    }
 
530
 
 
531
    return ( Type_Nil );
 
532
}
 
533
 
 
534
 
 
535
///---------------------------------------------------------------------
 
536
/// CqParseNodeRelOp::TypeCheck
 
537
/// Do a type check based on suitable types requested, and add a cast in required.
 
538
 
 
539
TqInt   CqParseNodeRelOp::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
540
{
 
541
    TqInt RelType;
 
542
    RelType = CqParseNodeOp::TypeCheck( pAllTypes(), Type_Last - 1, CheckOnly );  
 
543
 
 
544
    if( RelType == Type_Nil)
 
545
        return( RelType );
 
546
 
 
547
    // See if float is a requested type.
 
548
    TqInt NewType;
 
549
    if ( ( NewType = FindCast( Type_Float, pTypes, Count ) ) != Type_Nil )
 
550
    {
 
551
        if ( NewType == Type_Float ) return ( Type_Float );
 
552
        else
 
553
        {
 
554
            CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
555
            LinkParent( pCast );
 
556
            return ( NewType );
 
557
        }
 
558
    }
 
559
 
 
560
    if ( !CheckOnly )
 
561
    {
 
562
        CqString strErr( strFileName() );
 
563
        strErr += " : ";
 
564
        strErr += LineNo();
 
565
        strErr += " : ";
 
566
        strErr += "Relational can operators only return float.";
 
567
        throw( strErr );
 
568
        return ( Type_Nil );
 
569
    }
 
570
 
 
571
    return ( Type_Nil );
 
572
}
 
573
 
 
574
 
 
575
///---------------------------------------------------------------------
 
576
/// CqParseNodeUnaryOp::TypeCheck
 
577
/// Do a type check based on suitable types requested, and add a cast in required.
 
578
 
 
579
TqInt   CqParseNodeUnaryOp::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
580
{
 
581
    // Check if the operand can be cast to a requested type.
 
582
    if ( m_pChild != 0 )
 
583
        return ( m_pChild->TypeCheck( pTypes, Count, CheckOnly ) );
 
584
    else
 
585
        return ( Type_Nil );
 
586
}
 
587
 
 
588
 
 
589
///---------------------------------------------------------------------
 
590
/// CqParseNodeOpDot::TypeCheck
 
591
/// Do a type check based on suitable types requested, and add a cast in required.
 
592
 
 
593
TqInt   CqParseNodeMathOpDot::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
594
{
 
595
    static TqInt aArgTypes[ 3 ] = {Type_Point, Type_Vector, Type_Normal};
 
596
 
 
597
    // Get the argument types.
 
598
    CqParseNode* pOperandA = m_pChild;
 
599
    CqParseNode* pOperandB = m_pChild->pNext();
 
600
    assert( pOperandA != 0 && pOperandB != 0 );
 
601
    TqInt TypeA = ( pOperandA->ResType() & Type_Mask );
 
602
    TqInt TypeB = ( pOperandB->ResType() & Type_Mask );
 
603
 
 
604
    // Dot operator can only take normal/vector/point types, check the
 
605
    // arguments can be made to match this, and always returns a float,
 
606
    // check this is valid.
 
607
 
 
608
    TqInt RetType;
 
609
    if ( ( RetType = FindCast( Type_Float, pTypes, Count ) ) != Type_Nil )
 
610
    {
 
611
        TqBool fValid = TqFalse;
 
612
        TqUint i;
 
613
        for ( i = 0; i < sizeof( aArgTypes ) / sizeof( aArgTypes[ 0 ] ); i++ )
 
614
        {
 
615
            if ( FindCast( TypeA, &aArgTypes[ i ], 1 ) != Type_Nil )
 
616
            {
 
617
                if ( FindCast( TypeB, &aArgTypes[ i ], 1 ) != Type_Nil )
 
618
                {
 
619
                    // Add any cast operators required.
 
620
                    pOperandA->TypeCheck( &aArgTypes[ i ], 1, CheckOnly );
 
621
                    pOperandB->TypeCheck( &aArgTypes[ i ], 1, CheckOnly );
 
622
                    fValid = TqTrue;
 
623
                    break;
 
624
                }
 
625
            }
 
626
        }
 
627
        if ( fValid )
 
628
        {
 
629
            if ( RetType != Type_Float )
 
630
            {
 
631
                CqParseNodeCast * pCast = new CqParseNodeCast( RetType );
 
632
                LinkParent( pCast );
 
633
            }
 
634
            return ( RetType );
 
635
        }
 
636
    }
 
637
 
 
638
    if ( !CheckOnly )
 
639
    {
 
640
        CqString strErr( strFileName() );
 
641
        strErr += " : ";
 
642
        strErr += LineNo();
 
643
        strErr += " : ";
 
644
        strErr += "Cannot find a suitable cast for the operands.";
 
645
        throw( strErr );
 
646
        return ( Type_Nil );
 
647
    }
 
648
 
 
649
    return ( Type_Nil );
 
650
}
 
651
 
 
652
 
 
653
///---------------------------------------------------------------------
 
654
/// CqParseNodeConst::TypeCheck
 
655
/// Perform a typecheck, and add cast if required.
 
656
 
 
657
TqInt CqParseNodeConst::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
658
{
 
659
    // Check if the variable type matches any of the requested ones.
 
660
    TqInt       MyType = ResType();
 
661
    TqInt i;
 
662
    for ( i = 0; i < Count; i++ )
 
663
    {
 
664
        if ( pTypes[ i ] == MyType )
 
665
            return ( MyType );
 
666
    }
 
667
 
 
668
    TqInt NewType = FindCast( MyType, pTypes, Count );
 
669
    // If we got here, we are not of the correct type, so find a suitable cast.
 
670
    if ( !CheckOnly )
 
671
    {
 
672
        CqParseNodeCast * pCast = new CqParseNodeCast( NewType );
 
673
        LinkParent( pCast );
 
674
    }
 
675
 
 
676
    if ( NewType == Type_Nil && !CheckOnly )
 
677
    {
 
678
        CqString strErr( strFileName() );
 
679
        strErr += " : ";
 
680
        strErr += LineNo();
 
681
        strErr += " : ";
 
682
        strErr += "Cannot convert from type ";
 
683
        strErr += CqParseNode::TypeName( MyType );
 
684
        strErr += " to any of the required types";
 
685
        throw( strErr );
 
686
        return ( Type_Nil );
 
687
    }
 
688
    return ( NewType );
 
689
}
 
690
 
 
691
 
 
692
///---------------------------------------------------------------------
 
693
/// CqParseNodeCast::TypeCheck
 
694
/// Do a type check based on suitable types requested, and add a cast in required.
 
695
 
 
696
TqInt   CqParseNodeCast::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
697
{
 
698
    // Perform a typecheck on the cast expression
 
699
    CqParseNode * pExpr = m_pChild;
 
700
    pExpr->TypeCheck( &m_tTo, 1, CheckOnly );
 
701
 
 
702
    // Check the return type, and add another cast if necessary.
 
703
    // Note: We add another cast to allow for forced casts of function return types,
 
704
    // i.e. we want the sl code "Ci=float noise(P)"
 
705
    // to call float noise THEN cast to a color, not call color noise.
 
706
    TqInt i;
 
707
    for ( i = 0; i < Count; i++ )
 
708
        if ( pTypes[ i ] == m_tTo ) return ( m_tTo );
 
709
 
 
710
    TqInt NewType = FindCast( m_tTo, pTypes, Count );
 
711
    if ( NewType == Type_Nil && !CheckOnly )
 
712
    {
 
713
        CqString strErr( strFileName() );
 
714
        strErr += " : ";
 
715
        strErr += LineNo();
 
716
        strErr += " : ";
 
717
        strErr += "Cannot convert from type ";
 
718
        strErr += CqParseNode::TypeName( NewType );
 
719
        strErr += " to any of the required types";
 
720
        throw( strErr );
 
721
        return ( Type_Nil );
 
722
    }
 
723
    else
 
724
    {
 
725
        if ( !CheckOnly )
 
726
        {
 
727
            CqParseNodeCast * pCast = new CqParseNodeCast( NewType );
 
728
            LinkParent( pCast );
 
729
        }
 
730
    }
 
731
 
 
732
    return ( NewType );
 
733
}
 
734
 
 
735
 
 
736
///---------------------------------------------------------------------
 
737
/// CqParseNodeTriple::TypeCheck
 
738
/// Do a type check based on suitable types requested, and add a cast in required.
 
739
 
 
740
TqInt   CqParseNodeTriple::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
741
{
 
742
    static TqInt ExprType = Type_Float;
 
743
    // Perform a typecheck on the three float expressions
 
744
    CqParseNode* pExpr = m_pChild;
 
745
    while ( pExpr != 0 )
 
746
    {
 
747
        pExpr->TypeCheck( &ExprType, 1, CheckOnly );
 
748
        pExpr = pExpr->pNext();
 
749
    }
 
750
    // Check if expecting a triple, if not add a cast
 
751
    TqInt i;
 
752
    for ( i = 0; i < Count; i++ )
 
753
        if ( pTypes[ i ] == Type_Triple ) return ( Type_Triple );
 
754
 
 
755
    // If we got here, we are not of the correct type, so find a suitable cast.
 
756
    TqInt NewType = FindCast( Type_Triple, pTypes, Count );
 
757
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
758
    LinkParent( pCast );
 
759
 
 
760
    if ( NewType == Type_Nil && !CheckOnly )
 
761
    {
 
762
        CqString strErr( strFileName() );
 
763
        strErr += " : ";
 
764
        strErr += LineNo();
 
765
        strErr += " : ";
 
766
        strErr += "Cannot convert from type ";
 
767
        strErr += CqParseNode::TypeName( NewType );
 
768
        strErr += " to any of the required types";
 
769
        throw( strErr );
 
770
        return ( Type_Nil );
 
771
    }
 
772
    return ( NewType );
 
773
}
 
774
 
 
775
 
 
776
///---------------------------------------------------------------------
 
777
/// CqParseNodeHexTuple::TypeCheck
 
778
/// Do a type check based on suitable types requested, and add a cast in required.
 
779
 
 
780
TqInt   CqParseNodeHexTuple::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
781
{
 
782
    static TqInt ExprType = Type_Float;
 
783
    // Perform a typecheck on the three float expressions
 
784
    CqParseNode* pExpr = m_pChild;
 
785
    while ( pExpr != 0 )
 
786
    {
 
787
        pExpr->TypeCheck( &ExprType, 1, CheckOnly );
 
788
        pExpr = pExpr->pNext();
 
789
    }
 
790
    // Check if expecting a sixteentuple, if not add a cast
 
791
    TqInt i;
 
792
    for ( i = 0; i < Count; i++ )
 
793
        if ( pTypes[ i ] == Type_HexTuple ) return ( Type_HexTuple );
 
794
 
 
795
    // If we got here, we are not of the correct type, so find a suitable cast.
 
796
    TqInt NewType = FindCast( Type_Matrix, pTypes, Count );
 
797
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
798
    LinkParent( pCast );
 
799
 
 
800
    if ( NewType == Type_Nil && !CheckOnly )
 
801
    {
 
802
        CqString strErr( strFileName() );
 
803
        strErr += " : ";
 
804
        strErr += LineNo();
 
805
        strErr += " : ";
 
806
        strErr += "Cannot convert from type ";
 
807
        strErr += CqParseNode::TypeName( NewType );
 
808
        strErr += " to any of the required types";
 
809
        throw( strErr );
 
810
        return ( Type_Nil );
 
811
    }
 
812
    return ( NewType );
 
813
}
 
814
 
 
815
 
 
816
///---------------------------------------------------------------------
 
817
/// CqParseNodeCommFunction::TypeCheck
 
818
 
 
819
TqInt CqParseNodeCommFunction::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
820
{
 
821
    // Check if the variable type matches any of the requested ones.
 
822
    TqInt       MyType = ResType();
 
823
    TqInt i;
 
824
    for ( i = 0; i < Count; i++ )
 
825
    {
 
826
        if ( pTypes[ i ] == MyType )
 
827
            return ( MyType );
 
828
    }
 
829
    // If we got here, we are not of the correct type, so find a suitable cast.
 
830
    TqInt NewType = FindCast( MyType, pTypes, Count );
 
831
    CqParseNodeCast* pCast = new CqParseNodeCast( NewType );
 
832
    LinkParent( pCast );
 
833
 
 
834
    if ( NewType == Type_Nil && !CheckOnly )
 
835
    {
 
836
        CqString strErr( strFileName() );
 
837
        strErr += " : ";
 
838
        strErr += LineNo();
 
839
        strErr += " : ";
 
840
        strErr += "Cannot convert from type ";
 
841
        strErr += CqParseNode::TypeName( MyType );
 
842
        strErr += " to any of the required types";
 
843
        throw( strErr );
 
844
        return ( Type_Nil );
 
845
    }
 
846
    return ( NewType );
 
847
}
 
848
 
 
849
 
 
850
///---------------------------------------------------------------------
 
851
/// CqParseNodeQCond::TypeCheck
 
852
/// Type check the return from a conditional statement and cast the true/false expressions if necessary.
 
853
 
 
854
TqInt   CqParseNodeQCond::TypeCheck( TqInt* pTypes, TqInt Count, TqBool CheckOnly )
 
855
{
 
856
    // Ensure that the conditional expression is type checked.
 
857
    CqParseNode * pCondExp = m_pChild;
 
858
    assert( pCondExp != 0 );
 
859
    pCondExp->TypeCheck( pAllTypes(), Type_Last - 1, CheckOnly );
 
860
 
 
861
    // Check if both expressions match type.
 
862
    CqParseNode * pTrue = m_pChild->pNext();
 
863
    assert( pTrue != 0 );
 
864
    CqParseNode* pFalse = pTrue->pNext();
 
865
    assert( pFalse != 0 );
 
866
 
 
867
    TqInt TypeT = ( pTrue->ResType() & Type_Mask );
 
868
    TqInt TypeF = ( pFalse->ResType() & Type_Mask );
 
869
 
 
870
    // See if they can both be cast to a requested type.
 
871
    TqInt i;
 
872
    for ( i = 0; i < Count; i++ )
 
873
    {
 
874
        if ( FindCast( TypeT, &pTypes[ i ], 1 ) != Type_Nil )
 
875
        {
 
876
            if ( FindCast( TypeF, &pTypes[ i ], 1 ) != Type_Nil )
 
877
            {
 
878
                // Add any cast operators required.
 
879
                pTrue->TypeCheck( &pTypes[ i ], 1, CheckOnly );
 
880
                pFalse->TypeCheck( &pTypes[ i ], 1, CheckOnly );
 
881
                return ( pTypes[ i ] );
 
882
            }
 
883
        }
 
884
    }
 
885
 
 
886
    if ( !CheckOnly )
 
887
    {
 
888
        CqString strErr( strFileName() );
 
889
        strErr += " : ";
 
890
        strErr += LineNo();
 
891
        strErr += " : ";
 
892
        strErr += "Cannot find a suitable cast for the expressions.";
 
893
        throw( strErr );
 
894
        return ( Type_Nil );
 
895
    }
 
896
 
 
897
    return ( Type_Nil );
 
898
}
 
899
 
 
900
 
 
901
END_NAMESPACE( Aqsis )
 
902
//---------------------------------------------------------------------