Пример #1
0
        /// <summary>
        /// The argument <paramref name="completeSource" /> determines whether the source code
        /// is complete PHP script file, which is a case in dynamic includ in Silverlight
        /// </summary>
        public TransientCompilationUnit Build(string /*!*/ sourceCode, SourceCodeDescriptor descriptor,
                                              EvalKinds kind, CompilationContext /*!*/ context, ScriptContext /*!*/ scriptContext,
                                              DTypeDesc referringType, NamingContext namingContext, bool completeSource)
        {
            PhpSourceFile source_file = new PhpSourceFile(context.Config.Compiler.SourceRoot,
                                                          RelativePath.ParseCanonical(descriptor.ContainingSourcePath));

            Encoding encoding = context.Config.Globalization.PageEncoding;

            TransientCompilationUnit result = new TransientCompilationUnit
                                                  (sourceCode, source_file, encoding, namingContext, descriptor.Line, descriptor.Column, completeSource);

            if (!result.PreCompile(context, scriptContext, descriptor, kind, referringType))
            {
                return(null);
            }

            DefineGlobalType(((TransientModuleBuilder)result.ModuleBuilder).AssemblyBuilder.RealModuleBuilder);
            if (!result.Compile(context, kind))
            {
                return(null);
            }

            BakeGlobals();
            result.PostCompile(descriptor);
            return(result);
        }
Пример #2
0
        /// <summary>
        /// Called before 'Compile' to initialize module &amp; assembly builders, so they can be used by the caller.
        /// </summary>
        internal bool PreCompile(CompilationContext /*!*/ context, ScriptContext /*!*/ scriptContext,
                                 SourceCodeDescriptor descriptor, EvalKinds kind, DTypeDesc referringType)
        {
            Debug.Assert(descriptor.Line == this.sourceUnit.Line);
            Debug.Assert(descriptor.Column == this.sourceUnit.Column);

            this.resolvingScriptContext = scriptContext;
            this.referringType          = referringType;

            // TODO: isDynamic is tricky...
            //  .. we need to define module_builder before any type/etc.. is reduced from the parser
            //  .. but we don't know whether it will be dynamic in advance!

            this.assembly_builder = scriptContext.ApplicationContext.TransientAssemblyBuilder;
            this.module_builder   = assembly_builder.DefineModule(this, context.Config.Compiler.Debug,
                                                                  descriptor.ContainingTransientModuleId, kind, descriptor.ContainingSourcePath);
            this.module   = module_builder;
            this.evalKind = kind;

            sourceUnit.Parse(
                context.Errors, this,
                context.Config.Compiler.LanguageFeatures);

            if (context.Errors.AnyFatalError)
            {
                return(false);
            }

            // any declaration implies non-dynamicity:
            // TODO: this mode needs to be checked...
            // isDynamic = types == null && functions == null && constants == null;

            return(true);
        }
Пример #3
0
        public TransientModuleBuilder /*!*/ DefineModule(TransientCompilationUnit /*!*/ compilationUnit, bool debuggable,
                                                         int containerId, EvalKinds kind, string sourcePath)
        {
            InitializeRealAssembly(debuggable);
            Debug.Assert(this.debuggable == debuggable);

            return(TransientAssembly.DefineModule(this, compilationUnit, containerId, kind, sourcePath));
        }
Пример #4
0
        /// <summary>
        /// Creates a node representing an eval-like construct (eval, assert, deferred type).
        /// </summary>
        /// <param name="position">Position.</param>
        /// <param name="code">Source code.</param>
        /// <param name="currentNamespace">Current namespace to be passed into the transient compilation unit.</param>
        /// <param name="aliases">Aliases to be passed into the transient compilation unit.</param>
        /// <remarks>
        /// Creates a node which actually doesn't exist in the source code but represents a piece of code
        /// which compilation has been deferred to the run-time. It is used for example when
        /// a class is declared to be child of a unknown class or interface.
        /// </remarks>
        public EvalEx(Position position, string code, QualifiedName?currentNamespace, Dictionary <string, QualifiedName> aliases)
            : base(position)
        {
            this.kind = EvalKinds.SyntheticEval;
            this.code = new StringLiteral(position, code);

            this.currentNamespace = currentNamespace;
            this.aliases          = aliases;
        }
Пример #5
0
        /// <summary>
        /// Used by the builder.
        /// </summary>
        public TransientModule(int id, EvalKinds kind, TransientCompilationUnit /*!*/ unit, TransientAssembly /*!*/ scriptAssembly,
                               TransientModule containingModule, string sourcePath)
            : base(unit, scriptAssembly)
        {
            Debug.Assert(unit != null && scriptAssembly != null);

            this.id               = id;
            this.sourcePath       = sourcePath;
            this.kind             = kind;
            this.containingModule = containingModule;
        }
Пример #6
0
		internal TransientModuleBuilder(int id, EvalKinds kind, TransientCompilationUnit/*!*/ compilationUnit,
			TransientAssemblyBuilder/*!*/ assemblyBuilder, TransientModule containingModule, string sourcePath)
            : base(id, kind, compilationUnit, assemblyBuilder.TransientAssembly, containingModule, sourcePath)
		{
			this.assemblyBuilder = assemblyBuilder;

			if (!compilationUnit.IsDynamic)
			{
				this.globalBuilder = assemblyBuilder.RealModuleBuilder.DefineType(MakeName("<Global>", true),
					TypeAttributes.SpecialName | TypeAttributes.Class | TypeAttributes.Public);
			}
			else
			{
				this.globalBuilder = null;
			}
		}
Пример #7
0
        internal TransientModuleBuilder(int id, EvalKinds kind, TransientCompilationUnit /*!*/ compilationUnit,
                                        TransientAssemblyBuilder /*!*/ assemblyBuilder, TransientModule containingModule, string sourcePath)
            : base(id, kind, compilationUnit, assemblyBuilder.TransientAssembly, containingModule, sourcePath)
        {
            this.assemblyBuilder = assemblyBuilder;

            if (!compilationUnit.IsDynamic)
            {
                this.globalBuilder = assemblyBuilder.RealModuleBuilder.DefineType(MakeName("<Global>", true),
                                                                                  TypeAttributes.SpecialName | TypeAttributes.Class | TypeAttributes.Public);
            }
            else
            {
                this.globalBuilder = null;
            }
        }
Пример #8
0
        public static object Eval(
            string code,
            bool synthetic,
            ScriptContext context,
            Dictionary <string, object> definedVariables,
            DObject self,
            DTypeDesc referringType,
            string callerRelativeSourcePath,
            int line,
            int column,
            int containerId,
            NamingContext namingContext)
        {
            EvalKinds kind = synthetic ? EvalKinds.SyntheticEval : EvalKinds.ExplicitEval;

            return(EvalInternal("", code, "", kind, context, definedVariables, self, referringType,
                                new SourceCodeDescriptor(callerRelativeSourcePath, containerId, line, column), false, namingContext));
        }
Пример #9
0
 /// <summary>
 /// Creates a node representing an eval or assert constructs.
 /// </summary>
 /// <param name="position">Position.</param>
 /// <param name="code">Source code expression.</param>
 /// <param name="isAssert">Whether the node represents an assert construct.</param>
 public EvalEx(Position position, Expression /*!*/ code, bool isAssert)
     : base(position)
 {
     this.kind = (isAssert) ? EvalKinds.Assert : EvalKinds.ExplicitEval;
     this.code = code;
 }
Пример #10
0
		/// <summary>
		/// Compiles the transient unit. 'PreCompile' should be called first!
		/// </summary>
		internal bool Compile(CompilationContext/*!*/ context, EvalKinds kind)
		{
			Analyzer analyzer = null;

			try
			{
				analyzer = new Analyzer(context);

				// perform pre-analysis on types and functions:
				if (types != null)
					analyzer.PreAnalyze(types.Values);

				if (functions != null)
					analyzer.PreAnalyze(functions.Values);

				// perform member analysis on types and functions:
				if (types != null)
					analyzer.AnalyzeMembers(types.Values);
				if (functions != null)
					analyzer.AnalyzeMembers(functions.Values);
				
				if (context.Errors.AnyFatalError) return false;

				// perform full analysis:
				analyzer.Analyze(sourceUnit);

				if (context.Errors.AnyFatalError) return false;

				// perform post analysis:
				analyzer.PostAnalyze();
			}
			catch (CompilerException)
			{
				return false;
			}
			finally
			{
				resolvingScriptContext = null;
				referringType = null;
			}

			// do not emit anything if there was parse/analysis error:
			if (context.Errors.AnyError) return false;

			DefineBuilders();

			// define constructed types:
			analyzer.DefineConstructedTypeBuilders();

			CodeGenerator cg = new CodeGenerator(context);
			sourceUnit.Emit(cg);
			return true;
		}
Пример #11
0
		public TransientModuleBuilder/*!*/ DefineModule(TransientCompilationUnit/*!*/ compilationUnit, bool debuggable,
			int containerId, EvalKinds kind, string sourcePath)
		{
			InitializeRealAssembly(debuggable);
			Debug.Assert(this.debuggable == debuggable);

			return TransientAssembly.DefineModule(this, compilationUnit, containerId, kind, sourcePath);
		}
Пример #12
0
        /// <summary>
        /// Emit call to <see cref="DynamicCode.Assert"/> or <see cref="DynamicCode.Eval"/>.
        /// </summary>
        internal PhpTypeCode EmitEval(EvalKinds kind, Expression/*!*/code, Text.Span span, QualifiedName? currentNamespace, Dictionary<string, QualifiedName> currentAliases)
        {
            Debug.Assert(code != null);

            // LOAD DynamicCode.<Eval | Assert>(<code>, context, definedVariables, self, includer, source, line, column, evalId, naming)
            if (kind == EvalKinds.Assert)
            {
                // an argument of the assert is boxed:
                EmitBoxing(code.Emit(this));
            }
            else if (kind == EvalKinds.SyntheticEval)
            {
                Debug.Assert(code.HasValue());
                Debug.Assert(code.GetValue() is string);

                // an argument of the eval is converted to a string:
                il.Emit(OpCodes.Ldstr, (string)code.GetValue());
                il.Emit(OpCodes.Ldc_I4_1);
            }
            else
            {
                // an argument of the eval is converted to a string:
                EmitConversion(code, PhpTypeCode.String);
                il.Emit(OpCodes.Ldc_I4_0);
            }

            var position = new Text.TextPoint(this.SourceUnit.LineBreaks, span.Start);

            EmitLoadScriptContext();
            EmitLoadRTVariablesTable();
            EmitLoadSelf();
            EmitLoadClassContext();
            EmitEvalInfoPass(position.Line, position.Column);
            EmitNamingContext(currentNamespace, currentAliases, span.Start);

            il.Emit(OpCodes.Call, (kind == EvalKinds.Assert) ? Methods.DynamicCode.Assert : Methods.DynamicCode.Eval);

            return (kind == EvalKinds.Assert) ? PhpTypeCode.Boolean : PhpTypeCode.Object;
        }
Пример #13
0
        /// <summary>
        /// Implements PHP <c>eval</c> construct with given code prefix and suffix.
        /// A result of concatanation prefix + code + suffix is compiled.
        /// Prefix should contain no new line characters.
        /// </summary>
        internal static object EvalInternal(
            string prefix,
            string code,
            string suffix,
            EvalKinds kind,
            ScriptContext /*!*/ scriptContext,
            Dictionary <string, object> localVariables,
            DObject self,
            DTypeDesc referringType,
            SourceCodeDescriptor descriptor,
            bool entireFile,
            NamingContext namingContext)
        {
            Debug.Assert(prefix != null && suffix != null);

            // composes code to be compiled:
            code = String.Concat(prefix, code, suffix);

            TransientAssemblyBuilder assembly_builder = scriptContext.ApplicationContext.TransientAssemblyBuilder;

            // looks up the cache:
            TransientModule module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

            if (module == null)
            {
                // double checked lock,
                // if module != null, it is definitely completed
                // since module is added into TransientAssembly at the end
                // of assembly_builder.Build
                lock (assembly_builder.TransientAssembly)
                {
                    // lookup again, since it could be added into TransientAssembly while lock
                    module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

                    if (module == null)
                    {
                        if (kind == EvalKinds.SyntheticEval)
                        {
                            Debug.WriteLine("SYN EVAL", "Eval cache missed: '{0}'", code.Substring(0, Math.Max(code.IndexOf('{'), 0)).TrimEnd());
                        }
                        else
                        {
                            Debug.WriteLine("EVAL", "Eval cache missed: '{0}'({1},{2})", descriptor.ContainingSourcePath, descriptor.Line, descriptor.Column);
                        }

                        CompilerConfiguration config = new CompilerConfiguration(Configuration.Application);

                        CompilationContext context = new CompilationContext(scriptContext.ApplicationContext, null, config,
                                                                            new EvalErrorSink(-prefix.Length, config.Compiler.DisabledWarnings, config.Compiler.DisabledWarningNumbers),
                                                                            scriptContext.WorkingDirectory);

                        TransientCompilationUnit unit = assembly_builder.Build(code, descriptor, kind, context,
                                                                               scriptContext, referringType, namingContext, entireFile);

                        // compilation failed:
                        if (unit == null)
                        {
                            return(false);
                        }
                        module = unit.TransientModule;
                    }
                }
            }

            // activates unconditionally declared types, functions and constants:
            module.TransientCompilationUnit.Declare(scriptContext);

            return(module.Main(scriptContext, localVariables, self, referringType, true));
        }
Пример #14
0
		/// <summary>
		/// Creates a node representing an eval-like construct (eval, assert, deferred type).
		/// </summary>
		/// <param name="position">Position.</param>
		/// <param name="code">Source code.</param>
        /// <param name="currentNamespace">Current namespace to be passed into the transient compilation unit.</param>
        /// <param name="aliases">Aliases to be passed into the transient compilation unit.</param>
		/// <remarks>
		/// Creates a node which actually doesn't exist in the source code but represents a piece of code 
		/// which compilation has been deferred to the run-time. It is used for example when
		/// a class is declared to be child of a unknown class or interface.
		/// </remarks>
		public EvalEx(Position position, string code, QualifiedName? currentNamespace, Dictionary<string,QualifiedName> aliases)
			: base(position)
		{
			this.kind = EvalKinds.SyntheticEval;
			this.code = new StringLiteral(position, code);

            this.currentNamespace = currentNamespace;
            this.aliases = aliases;
		}
Пример #15
0
		/// <summary>
		/// Creates a node representing an eval or assert constructs.
		/// </summary>
		/// <param name="position">Position.</param>
		/// <param name="code">Source code expression.</param>
		/// <param name="isAssert">Whether the node represents an assert construct.</param>
		public EvalEx(Position position, Expression/*!*/ code, bool isAssert)
			: base(position)
		{
			this.kind = (isAssert) ? EvalKinds.Assert : EvalKinds.ExplicitEval;
			this.code = code;
		}
Пример #16
0
        /// <summary>
        /// Compiles the transient unit. 'PreCompile' should be called first!
        /// </summary>
        internal bool Compile(CompilationContext /*!*/ context, EvalKinds kind)
        {
            Analyzer analyzer = null;

            try
            {
                analyzer = new Analyzer(context);

                // perform pre-analysis on types and functions:
                if (types != null)
                {
                    analyzer.PreAnalyze(types.Values);
                }

                if (functions != null)
                {
                    analyzer.PreAnalyze(functions.Values);
                }

                // perform member analysis on types and functions:
                if (types != null)
                {
                    analyzer.AnalyzeMembers(types.Values);
                }
                if (functions != null)
                {
                    analyzer.AnalyzeMembers(functions.Values);
                }

                if (context.Errors.AnyFatalError)
                {
                    return(false);
                }

                // perform full analysis:
                analyzer.Analyze(sourceUnit);

                if (context.Errors.AnyFatalError)
                {
                    return(false);
                }

                // perform post analysis:
                analyzer.PostAnalyze();
            }
            catch (CompilerException)
            {
                return(false);
            }
            finally
            {
                resolvingScriptContext = null;
                referringType          = null;
            }

            // do not emit anything if there was parse/analysis error:
            if (context.Errors.AnyError)
            {
                return(false);
            }

            DefineBuilders();

            // define constructed types:
            analyzer.DefineConstructedTypeBuilders();

            CodeGenerator cg = new CodeGenerator(context);

            sourceUnit.Emit(cg);
            return(true);
        }
Пример #17
0
		/// <summary>
		/// Implements PHP <c>eval</c> construct with given code prefix and suffix. 
		/// A result of concatanation prefix + code + suffix is compiled.
		/// Prefix should contain no new line characters.
		/// </summary>
		internal static object EvalInternal(
			string prefix,
			string code,
			string suffix,
			EvalKinds kind,
			ScriptContext/*!*/ scriptContext,
			Dictionary<string, object> localVariables,
			DObject self,
			DTypeDesc referringType,
			SourceCodeDescriptor descriptor,
			bool entireFile, 
			NamingContext namingContext)
		{
			Debug.Assert(prefix != null && suffix != null);

			// composes code to be compiled:
			code = String.Concat(prefix, code, suffix);

			TransientAssemblyBuilder assembly_builder = scriptContext.ApplicationContext.TransientAssemblyBuilder;

			// looks up the cache:
			TransientModule module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

            if (module == null)
                // double checked lock,
                // if module != null, it is definitely completed
                // since module is added into TransientAssembly at the end
                // of assembly_builder.Build
                lock (assembly_builder.TransientAssembly)
                {
                    // lookup again, since it could be added into TransientAssembly while lock
                    module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

                    if (module == null)
                    {
                        if (kind == EvalKinds.SyntheticEval)
                            Debug.WriteLine("SYN EVAL", "Eval cache missed: '{0}'", code.Substring(0, Math.Max(code.IndexOf('{'), 0)).TrimEnd());
                        else
                            Debug.WriteLine("EVAL", "Eval cache missed: '{0}'({1},{2})", descriptor.ContainingSourcePath, descriptor.Line, descriptor.Column);

                        CompilerConfiguration config = new CompilerConfiguration(Configuration.Application);

                        CompilationContext context = new CompilationContext(scriptContext.ApplicationContext, null, config,
                            new EvalErrorSink(-prefix.Length, config.Compiler.DisabledWarnings, config.Compiler.DisabledWarningNumbers),
                            scriptContext.WorkingDirectory);

                        TransientCompilationUnit unit = assembly_builder.Build(code, descriptor, kind, context,
                            scriptContext, referringType, namingContext, entireFile);

                        // compilation failed:
                        if (unit == null) return false;
                        module = unit.TransientModule;
                    }
                }
			
			// activates unconditionally declared types, functions and constants: 
            module.TransientCompilationUnit.Declare(scriptContext);

			return module.Main(scriptContext, localVariables, self, referringType, true);
		}
Пример #18
0
        /// <summary>
        /// Used by the builder.
        /// </summary>
        public TransientModule(int id, EvalKinds kind, TransientCompilationUnit/*!*/ unit, TransientAssembly/*!*/ scriptAssembly,
            TransientModule containingModule, string sourcePath)
            : base(unit, scriptAssembly)
        {
            Debug.Assert(unit != null && scriptAssembly != null);

            this.id = id;
            this.sourcePath = sourcePath;
            this.kind = kind;
            this.containingModule = containingModule;
        }
Пример #19
0
		/// <summary>
		/// Called before 'Compile' to initialize module &amp; assembly builders, so they can be used by the caller.
		/// </summary>
		internal bool PreCompile(CompilationContext/*!*/ context, ScriptContext/*!*/ scriptContext,
			SourceCodeDescriptor descriptor, EvalKinds kind, DTypeDesc referringType)
		{
			this.resolvingScriptContext = scriptContext;
			this.referringType = referringType;

			// TODO: isDynamic is tricky...
			//  .. we need to define module_builder before any type/etc.. is reduced from the parser
			//  .. but we don't know whether it will be dynamic in advance!

			this.assembly_builder = scriptContext.ApplicationContext.TransientAssemblyBuilder;
			this.module_builder = assembly_builder.DefineModule(this, context.Config.Compiler.Debug,
				descriptor.ContainingTransientModuleId, kind, descriptor.ContainingSourcePath);
			this.module = module_builder;
			this.evalKind = kind;

            sourceUnit.Parse(
                context.Errors, this,
                new Position(descriptor.Line, descriptor.Column, 0, descriptor.Line, descriptor.Column, 0),
                context.Config.Compiler.LanguageFeatures);

			if (context.Errors.AnyFatalError) return false;

			// any declaration implies non-dynamicity:
			// TODO: this mode needs to be checked...
			// isDynamic = types == null && functions == null && constants == null;

			return true;
		}
Пример #20
0
        internal TransientModuleBuilder /*!*/ DefineModule(TransientAssemblyBuilder /*!*/ assemblyBuilder,
                                                           TransientCompilationUnit /*!*/ compilationUnit, int containerId, EvalKinds kind, string sourcePath)
        {
            TransientModule container = GetModule(containerId);

            int new_id;

            rwLock.EnterWriteLock();

            try
            {
                // reserve slot in the module list:
                new_id = modules.Count;
                modules.Add(null);
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return(new TransientModuleBuilder(new_id, kind, compilationUnit, assemblyBuilder, container, sourcePath));
        }
Пример #21
0
		/// <summary>
		/// The argument <paramref name="completeSource" /> determines whether the source code
		/// is complete PHP script file, which is a case in dynamic include in Silverlight
		/// </summary>
		public TransientCompilationUnit Build(string/*!*/ sourceCode, SourceCodeDescriptor descriptor,
			EvalKinds kind, CompilationContext/*!*/ context, ScriptContext/*!*/ scriptContext,
			DTypeDesc referringType, NamingContext namingContext, bool completeSource)
		{
			PhpSourceFile source_file = new PhpSourceFile(context.Config.Compiler.SourceRoot,
				RelativePath.ParseCanonical(descriptor.ContainingSourcePath));

			Encoding encoding = context.Config.Globalization.PageEncoding;

			TransientCompilationUnit result = new TransientCompilationUnit
				(sourceCode, source_file, encoding, namingContext, descriptor.Line, descriptor.Column, completeSource);
			if (!result.PreCompile(context, scriptContext, descriptor, kind, referringType)) return null;

			DefineGlobalType(((TransientModuleBuilder)result.ModuleBuilder).AssemblyBuilder.RealModuleBuilder);
			if (!result.Compile(context, kind)) return null;

			BakeGlobals();
			result.PostCompile(descriptor);
			return result;
		}