/// <summary>
 /// Registers a local variable or a function parameter.
 /// Registering multiple times the same locals or parameters means that recursion is at work. 
 /// </summary>
 /// <param name="local">The local or parameter to register.</param>
 /// <returns>The unitialized <see cref="RefRuntimeObj"/> (undefined).</returns>
 public virtual RefRuntimeObj Register( AccessorLetExpr local )
 {
     Entry e;
     if( _vars.TryGetValue( local, out e ) )
     {
         if( e.O == null ) e.O = new RefRuntimeObj();
         else e = e.Next = new Entry( e.Next, new RefRuntimeObj() );
     }
     else _vars.Add( local, e = new Entry( null, new RefRuntimeObj() ) );
     return e.O;
 }
        public void declaring_while_no_scope_is_opened_is_a_syntax_error()
        {
            StaticScope s = new StaticScope();

            var v = new AccessorLetExpr(SourceLocation.Empty, "V");

            Assert.IsInstanceOf <SyntaxErrorExpr>(s.Declare("toto", v));

            s.OpenScope();
            Assert.AreSame(s.Declare("toto", v), v);
            Assert.AreSame(s.Find("toto"), v);
            CheckClose(s.CloseScope(), "V");

            Assert.IsInstanceOf <SyntaxErrorExpr>(s.Declare("toto", v));
        }
        public void declaring_while_no_scope_is_opened_is_a_syntax_error()
        {
            StaticScope s = new StaticScope();

            var v = new AccessorLetExpr(SourceLocation.Empty, "V");

            s.Declare(v).Should().BeOfType <SyntaxErrorExpr>();

            s.OpenScope();
            s.Declare(v).Should().BeSameAs(v);
            s.Find("V").Should().BeSameAs(v);
            CheckClose(s.CloseScope(), v);

            s.Declare(v).Should().BeOfType <SyntaxErrorExpr>();
        }
        public void redefinition_in_the_same_scope_is_not_allowed_by_default()
        {
            StaticScope s = new StaticScope();

            var v       = new AccessorLetExpr(SourceLocation.Empty, "V");
            var v1      = new AccessorLetExpr(SourceLocation.Empty, "V (redefined)");
            var v2      = new AccessorLetExpr(SourceLocation.Empty, "V (redefined again)");
            var vFailed = new AccessorLetExpr(SourceLocation.Empty, "V (failed)");

            s.OpenScope();

            Assert.AreSame(s.Declare("V", v), v);
            Assert.IsInstanceOf <SyntaxErrorExpr>(s.Declare("V", vFailed));

            s.AllowLocalRedefinition = true;
            Assert.AreSame(s.Declare("V", v1), v1);
            Assert.AreSame(s.Declare("V", v2), v2);

            s.AllowLocalRedefinition = false;
            Assert.IsInstanceOf <SyntaxErrorExpr>(s.Declare("V", vFailed));

            CheckClose(s.CloseScope(), "V", "V (redefined)", "V (redefined again)");
        }
        public void redefinition_in_the_same_scope_is_not_allowed_by_default()
        {
            StaticScope s = new StaticScope();

            var v       = new AccessorLetExpr(SourceLocation.Empty, "V");
            var v1      = new AccessorLetExpr(SourceLocation.Empty, "V");
            var v2      = new AccessorLetExpr(SourceLocation.Empty, "V");
            var vFailed = new AccessorLetExpr(SourceLocation.Empty, "V");

            s.OpenScope();

            s.Declare(v).Should().BeSameAs(v);
            s.Declare(vFailed).Should().BeOfType <SyntaxErrorExpr>();

            s.AllowLocalRedefinition = true;
            s.Declare(v1).Should().BeSameAs(v1);
            s.Declare(v2).Should().BeSameAs(v2);

            s.AllowLocalRedefinition = false;
            s.Declare(vFailed).Should().BeOfType <SyntaxErrorExpr>();

            CheckClose(s.CloseScope(), v, v1, v2);
        }
 Expr TryRegisterFuncParametersAndOpenBody( bool allowNone )
 {
     if( !_parser.Match( JSTokenizerToken.OpenPar ) )
     {
         if( !allowNone ) return new SyntaxErrorExpr( _parser.Location, "Expected '('." );
     }
     else
     {
         string pName;
         while( (pName = _parser.ReadIdentifier()) != null )
         {
             AccessorLetExpr param = new AccessorLetExpr( _parser.PrevNonCommentLocation, pName );
             Expr eRegParam = _scope.Declare( pName, param );
             if( eRegParam is SyntaxErrorExpr ) return eRegParam;
             if( !_parser.Match( JSTokenizerToken.Comma ) ) break;
         }
         if( !_parser.Match( JSTokenizerToken.ClosePar ) ) return new SyntaxErrorExpr( _parser.Location, "Expected ')'." );
     }
     if( !_parser.Match( JSTokenizerToken.OpenCurly ) ) return new SyntaxErrorExpr( _parser.Location, "Expected '{{}'." );
     return null;
 }
 Expr HandleFunction()
 {
     var funcLocation = _parser.PrevNonCommentLocation;
     string name = _parser.ReadIdentifier();
     AccessorLetExpr funcName = null;
     if( name != null )
     {
         funcName = new AccessorLetExpr( _parser.PrevNonCommentLocation, name );
         Expr eRegName = _scope.Declare( name, funcName );
         if( eRegName is SyntaxErrorExpr ) return eRegName;
     }
     IReadOnlyList<AccessorLetExpr> parameters, closures;
     Expr body = HandleFuncParametersAndBody( out parameters, out closures, false );
     var f = new FunctionExpr( funcLocation, parameters, body, closures, funcName );
     if( funcName == null ) return f;
     return new AssignExpr( funcLocation, funcName, f );
 }
 /// <summary>
 /// Gets the current value for a given declaration that must have been registered at least once.
 /// </summary>
 /// <param name="r">The declaration.</param>
 /// <returns>The current <see cref="RefRuntimeObj"/> to consider.</returns>
 public RefRuntimeObj FindRegistered( AccessorLetExpr r )
 {
     Entry e;
     if( _vars.TryGetValue( r, out e ) ) return (e.Next ?? e).O;
     throw new ArgumentException( String.Format( "Unregistered variable '{0}'.", r.Name ) );
 }
 /// <summary>
 /// Unregisters a previously registered local variable, function parameter, or <see cref="Closure"/>.
 /// </summary>
 /// <param name="decl">The declaration to unregister.</param>
 public virtual void Unregister( AccessorLetExpr decl )
 {
     Entry e;
     if( _vars.TryGetValue( decl, out e ) )
     {
         if( e.Next != null )
         {
             e.Next = e.Next.Next;
             return;
         }
         if( e.O != null )
         {
             e.O = null;
             return;
         }
     }
     throw new InvalidOperationException( String.Format( "Unregistering non registered '{0}'.", decl.Name ) );
 }
        public void redefinition_in_the_same_scope_is_not_allowed_by_default()
        {
            StaticScope s = new StaticScope();

            var v = new AccessorLetExpr( SourceLocation.Empty, "V" );
            var v1 = new AccessorLetExpr( SourceLocation.Empty, "V (redefined)" );
            var v2 = new AccessorLetExpr( SourceLocation.Empty, "V (redefined again)" );
            var vFailed = new AccessorLetExpr( SourceLocation.Empty, "V (failed)" );

            s.OpenScope();

            Assert.AreSame( s.Declare( "V", v ), v );
            Assert.IsInstanceOf<SyntaxErrorExpr>( s.Declare( "V", vFailed ) );

            s.AllowLocalRedefinition = true;
            Assert.AreSame( s.Declare( "V", v1 ), v1 );
            Assert.AreSame( s.Declare( "V", v2 ), v2 );

            s.AllowLocalRedefinition = false;
            Assert.IsInstanceOf<SyntaxErrorExpr>( s.Declare( "V", vFailed ) );

            CheckClose( s.CloseScope(), "V", "V (redefined)", "V (redefined again)" );
        }
        public void declaring_while_no_scope_is_opened_is_a_syntax_error()
        {
            StaticScope s = new StaticScope();

            var v = new AccessorLetExpr( SourceLocation.Empty, "V" );
            Assert.IsInstanceOf<SyntaxErrorExpr>( s.Declare( "toto", v ) );

            s.OpenScope();
            Assert.AreSame( s.Declare( "toto", v ), v );
            Assert.AreSame( s.Find( "toto" ), v );
            CheckClose( s.CloseScope(), "V" );

            Assert.IsInstanceOf<SyntaxErrorExpr>( s.Declare( "toto", v ) );
        }