Exemple #1
0
        /// <summary>
        /// Throws an exception.
        /// </summary>
        /// <param name="thrown">
        /// The object to throw. It's recommended that this be a dictionary with a
        /// "name" parameter at the least.
        /// </param>
        public void throwException( State state, object thrown )
        {
            // We want to have stack traces, so this is necessary... but we also want to
            // throw data objects and not C# objects. So we have to convert back and forth.
            if( !(thrown is CoralException) )
            thrown = new CoralException( thrown );
            var cex = (CoralException)thrown;
            if( cex.trace == null )
            cex.setStackTrace( state );
            thrown = cex.data;

            state.pushAction( new Step( this, st =>
            {
                // We'll want to hold on to the finally runner if there is one. This will
                // let us properly handle nested exceptions.
                Step finallyStep = null;
                st.unwindActions( step => IsTryMarker( step ), this.finallyBlock != null );
                if( this.finallyBlock != null )
                    finallyStep = st.popAction();

                // The except block may have a parameter.
                if( this.exceptIdentifer != null )
                {
                    IScope exceptScope = new ParameterScope( st.scope, new string[] { this.exceptIdentifer } );
                    exceptScope.set( this.exceptIdentifer, thrown );
                    state.pushActionAndScope( new Step( this, a => {}, "except: scope" ), exceptScope );
                }
                this.exceptBlock.run( st );

                if( finallyStep != null )
                {
                    finallyStep.description = "finally block";
                    st.pushAction( finallyStep );
                }
            },
            "throw" )
            );
        }
Exemple #2
0
        public override void run( State state )
        {
            // We execute here by evaulating each of the parameters as well as the source, and then
            // evaluating the source FValue; of course if we don't get an FValue, that's an error.
            state.pushAction( new Step( this, st =>
            {
            // Make sure the FValue isn't an LValue.
            object fvo = st.popResult();
            if( fvo is FValue )
            {
                // Everything's okay
            }
            else if( fvo is LValue )
                fvo = LValue.Deref( st, fvo );
            else
                throw CoralException.GetArg( "Attempted call to non-function" );
            if( fvo == null )
                throw CoralException.GetArg( "Attempted call to null function" );
            FValue fv = (FValue)fvo;

            // Gather arguments before we push any scopes.
            var argsArray = new List<object>();
            if( fv.func != null )
            {
                for( int i=0; i<this.parameters.Length; ++i )
                {
                    object value = LValue.Deref( st );
                    argsArray.Add( value );
                }
            }
            else
            {
                object[] args = this.parameters.Select( n => LValue.Deref( st ) ).ToArray();
                argsArray.AddRange( args );
            }

            // Push on a scope marker so that the function will run in its own scope.
            IScope oldScope;
            if( fv.scope == null )
                oldScope = st.constScope;
            else
                oldScope = fv.scope;
            st.pushActionAndScope( new Step( this, a => {}, ScopeMarker ), new StandardScope( oldScope ) );

            // The actual run action.
            if( fv.func != null )
            {
                // Push on a pusher for a null return value. This is to ensure that calls always return
                // something, for result stack sanity. This won't get executed if the function returns
                // a value on its own.
                st.pushAction( new Step( this, st2 => st2.pushResult( null ), "call: result pusher" ) );

                // Set a second scope with just the parameters.
                IScope callScope = new ParameterScope( st.scope,
                    fv.func.parameters.Union( new string[] { "arguments" } ).ToArray()  );
                st.pushActionAndScope( new Step( this, a => {}, "call: parameter scope" ), callScope );

                callScope.set( "arguments", argsArray );
                for( int i=0; i<argsArray.Count; ++i )
                    if( i < fv.func.parameters.Length )
                    {
                        string name = fv.func.parameters[i];
                        st.scope.set( name, argsArray[i] );
                    }
                    else
                        break;

                // Do the actual function call.
                fv.func.block.run( st );
            }
            else if( fv.metal != null )
            {
                fv.metal( st, argsArray.ToArray() );
            }
            else
                throw CoralException.GetArg( "Attempt to call null function" );
            } ) );
            this.source.run( state );
            foreach( AstNode p in this.parameters )
            p.run( state );
        }