2020-04-06 19:10:07 +00:00
/*
* * scopebarrier . cpp
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2017 ZZYZX
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
# include "dobject.h"
# include "scopebarrier.h"
# include "types.h"
# include "vmintern.h"
// Note: the same object can't be both UI and Play. This is checked explicitly in the field construction and will cause esoteric errors here if found.
int FScopeBarrier : : SideFromFlags ( int flags )
{
if ( flags & VARF_UI )
return Side_UI ;
if ( flags & VARF_Play )
return Side_Play ;
if ( flags & VARF_VirtualScope )
return Side_Virtual ;
if ( flags & VARF_ClearScope )
return Side_Clear ;
return Side_PlainData ;
}
// same as above, but from object flags
int FScopeBarrier : : SideFromObjectFlags ( EScopeFlags flags )
{
if ( flags & Scope_UI )
return Side_UI ;
if ( flags & Scope_Play )
return Side_Play ;
return Side_PlainData ;
}
//
int FScopeBarrier : : FlagsFromSide ( int side )
{
switch ( side )
{
case Side_Play :
return VARF_Play ;
case Side_UI :
return VARF_UI ;
case Side_Virtual :
return VARF_VirtualScope ;
case Side_Clear :
return VARF_ClearScope ;
default :
return 0 ;
}
}
EScopeFlags FScopeBarrier : : ObjectFlagsFromSide ( int side )
{
switch ( side )
{
case Side_Play :
return Scope_Play ;
case Side_UI :
return Scope_UI ;
default :
return Scope_All ;
}
}
// used for errors
const char * FScopeBarrier : : StringFromSide ( int side )
{
switch ( side )
{
case Side_PlainData :
return " data " ;
case Side_UI :
return " ui " ;
case Side_Play :
return " play " ;
case Side_Virtual :
return " virtualscope " ; // should not happen!
case Side_Clear :
return " clearscope " ; // should not happen!
default :
return " unknown " ;
}
}
// this modifies VARF_ flags and sets the side properly.
int FScopeBarrier : : ChangeSideInFlags ( int flags , int side )
{
flags & = ~ ( VARF_UI | VARF_Play | VARF_VirtualScope | VARF_ClearScope ) ;
flags | = FlagsFromSide ( side ) ;
return flags ;
}
// this modifies OF_ flags and sets the side properly.
EScopeFlags FScopeBarrier : : ChangeSideInObjectFlags ( EScopeFlags flags , int side )
{
int f = int ( flags ) ;
f & = ~ ( Scope_UI | Scope_Play ) ;
f | = ObjectFlagsFromSide ( side ) ;
return ( EScopeFlags ) f ;
}
FScopeBarrier : : FScopeBarrier ( )
{
sidefrom = - 1 ;
sidelast = - 1 ;
callable = true ;
readable = true ;
writable = true ;
}
FScopeBarrier : : FScopeBarrier ( int flags1 , int flags2 , const char * name )
{
sidefrom = - 1 ;
sidelast = - 1 ;
callable = true ;
readable = true ;
writable = true ;
AddFlags ( flags1 , flags2 , name ) ;
}
// AddFlags modifies ALLOWED actions by flags1->flags2.
// This is used for comparing a.b.c.d access - if non-allowed field is seen anywhere in the chain, anything after it is non-allowed.
// This struct is used so that the logic is in a single place.
void FScopeBarrier : : AddFlags ( int flags1 , int flags2 , const char * name )
{
// note: if it's already non-readable, don't even try advancing
if ( ! readable )
return ;
// we aren't interested in any other flags
// - update: including VARF_VirtualScope. inside the function itself, we treat it as if it's PlainData.
flags1 & = VARF_UI | VARF_Play ;
flags2 & = VARF_UI | VARF_Play | VARF_ReadOnly ;
if ( sidefrom < 0 ) sidefrom = SideFromFlags ( flags1 ) ;
if ( sidelast < 0 ) sidelast = sidefrom ;
// flags1 = what's trying to access
// flags2 = what's being accessed
int sideto = SideFromFlags ( flags2 ) ;
// plain data inherits whatever scope modifiers that context or field container has.
// i.e. play String bla; is play, and all non-specified methods/fields inside it are play as well.
if ( sideto ! = Side_PlainData )
sidelast = sideto ;
else sideto = sidelast ;
if ( ( sideto = = Side_UI ) & & ( sidefrom ! = Side_UI ) ) // only ui -> ui is readable
{
readable = false ;
if ( name ) readerror . Format ( " Can't read %s field %s from %s context " , StringFromSide ( sideto ) , name , StringFromSide ( sidefrom ) ) ;
}
if ( ! readable )
{
writable = false ;
callable = false ;
if ( name )
{
writeerror . Format ( " Can't write %s field %s from %s context (not readable) " , StringFromSide ( sideto ) , name , StringFromSide ( sidefrom ) ) ;
callerror . Format ( " Can't call %s function %s from %s context (not readable) " , StringFromSide ( sideto ) , name , StringFromSide ( sidefrom ) ) ;
}
return ;
}
if ( writable & & ( sidefrom ! = sideto ) ) // only matching types are writable (plain data implicitly takes context type by default, unless overridden)
{
writable = false ;
if ( name ) writeerror . Format ( " Can't write %s field %s from %s context " , StringFromSide ( sideto ) , name , StringFromSide ( sidefrom ) ) ;
}
if ( callable & & ( sidefrom ! = sideto ) & & ! ( flags2 & VARF_ReadOnly ) ) // readonly on methods is used for plain data stuff that can be called from ui/play context.
{
callable = false ;
if ( name ) callerror . Format ( " Can't call %s function %s from %s context " , StringFromSide ( sideto ) , name , StringFromSide ( sidefrom ) ) ;
}
}
2023-11-07 17:35:11 +00:00
bool FScopeBarrier : : CheckSidesForFunctionPointer ( int from , int to )
{
if ( to = = - 1 ) return true ;
if ( from = = Side_Clear ) from = Side_PlainData ;
return ( ( from = = to ) | | ( from = = Side_PlainData ) ) ;
}
2020-04-06 19:10:07 +00:00
// these are for vmexec.h
void FScopeBarrier : : ValidateNew ( PClass * cls , int outerside )
{
2023-02-11 11:06:58 +00:00
if ( cls - > VMType = = nullptr ) ThrowAbortException ( X_OTHER , " Cannot instantiate invalid class %s " , cls - > TypeName . GetChars ( ) ) ;
2020-04-06 19:10:07 +00:00
int innerside = FScopeBarrier : : SideFromObjectFlags ( cls - > VMType - > ScopeFlags ) ;
if ( ( outerside ! = innerside ) & & ( innerside ! = FScopeBarrier : : Side_PlainData ) ) // "cannot construct ui class ... from data context"
ThrowAbortException ( X_OTHER , " Cannot construct %s class %s from %s context " , FScopeBarrier : : StringFromSide ( innerside ) , cls - > TypeName . GetChars ( ) , FScopeBarrier : : StringFromSide ( outerside ) ) ;
}
void FScopeBarrier : : ValidateCall ( PClass * selftype , VMFunction * calledfunc , int outerside )
{
int innerside = FScopeBarrier : : SideFromObjectFlags ( selftype - > VMType - > ScopeFlags ) ;
if ( ( outerside ! = innerside ) & & ( innerside ! = FScopeBarrier : : Side_PlainData ) )
2023-05-23 21:01:17 +00:00
ThrowAbortException ( X_OTHER , " Cannot call %s function %s from %s context " , FScopeBarrier : : StringFromSide ( innerside ) , calledfunc - > PrintableName , FScopeBarrier : : StringFromSide ( outerside ) ) ;
2020-04-06 19:10:07 +00:00
}