Beispiel #1
0
			public Evaluator(Regex reg, string replacement, SourceCodeDescriptor sourceCodeDesc, DObject self, Dictionary<string, object> definedVariables)
			{
				this.reg = reg;
				this.definedVariables = definedVariables;
				this.replacement = replacement;
				this.sourceCodeDesc = sourceCodeDesc;
				this.count = 0;
				this.self = self;
			}
Beispiel #2
0
		/// <summary>
		/// Takes a regular expression <paramref name="pattern"/> and one of <paramref name="replacement"/> or 
		/// <paramref name="callback"/>. Performs replacing on <paramref name="data"/>, which can be
		/// <see cref="PhpArray"/>, in other cases it is converted to string.
		/// If <paramref name="data"/> is <see cref="PhpArray"/>, every value is converted to string and
		/// replacement is performed in place in this array.
		/// Either <paramref name="replacement"/> or <paramref name="callback"/> should be null.
		/// </summary>
		/// <param name="self">Instance of object that called the replace method (replace pattern may contain $this)</param>
		/// <param name="definedVariables">Array with local variables - can be used by replace pattern</param>
		/// <param name="pattern">Regular expression to search.</param>
		/// <param name="replacement">Regular replacement expression. Should be null if callback is specified.</param>
		/// <param name="callback">Callback function that should be called to make replacements. Should be null
		/// if replacement is specified.</param>
		/// <param name="data">Array or string where pattern is searched.</param>
		/// <param name="limit">Max count of replacements for each item in subject.</param>
		/// <param name="descriptor"><see cref="SourceCodeDescriptor"/> for possible lambda function creation.</param>
		/// <param name="count">Cumulated number of replacements.</param>
		/// <returns></returns>
		private static object SimpleReplace(DObject self, Dictionary<string, object> definedVariables, object pattern, 
			string replacement, PhpCallback callback, object data, int limit, SourceCodeDescriptor descriptor, ref int count)
		{
			Debug.Assert(limit >= -1);

			// exactly one of replacement or callback is valid:
			Debug.Assert(replacement != null ^ callback != null);

			PerlRegExpConverter converter = ConvertPattern(pattern, replacement);
			if (converter == null) return null;

			// get types of data we need:
			PhpArray data_array = data as PhpArray;
			string data_string = (data_array == null) ? ConvertData(data, converter) : null;

			// data comprising of a single string:
            if (data_array == null)
            {
                return ReplaceInternal(self, definedVariables, converter, callback, data_string, limit, descriptor, ref count);
            }
            else
            {
                // data is array, process each item:
                var enumerator = data_array.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    enumerator.CurrentValue = ReplaceInternal(self, definedVariables, converter, callback,
                        ConvertData(enumerator.CurrentValue, converter), limit, descriptor, ref count);
                }
                enumerator.Dispose();

                // return array with items replaced:
                return data;
            }
		}
Beispiel #3
0
        internal void PostCompile(SourceCodeDescriptor descriptor)
        {
            module_builder.Bake();
            Bake();

            // TODO: analyzer.GetTypeDependencies();
            var dependentTypes = new List<KeyValuePair<string, DTypeDesc>>(bakedTypes != null ? bakedTypes.Length : 0);
            if (bakedTypes != null)
                foreach (var type in bakedTypes)
                {
                    // add base as this type dependency:
                    AddDependentType(type.Value, dependentTypes, type.Value.Base);

                    // do the same for type.Value.Interfaces
                    var ifaces = type.Value.Interfaces;
                    if (ifaces != null && ifaces.Length > 0)
                        for (int i = 0; i < ifaces.Length; i++)
                            AddDependentType(type.Value, dependentTypes, ifaces[i]);
                }

            //
            module = assembly_builder.TransientAssembly.AddModule(module_builder, dependentTypes, sourceUnit.Code, descriptor);
        }
Beispiel #4
0
		/// <summary>
		/// Replaces <paramref name="limit"/> occurences of substrings.
		/// </summary>
		/// <param name="converter">
		/// Converter used for replacement if <paramref name="callback"/> is <B>null</B>.
		/// </param>
		/// <param name="self">Instance of object that called the replace method (replace pattern may contain $this)</param>
		/// <param name="definedVariables">Array with local variables - can be used by replace pattern</param>
		/// <param name="callback">Callback to call for replacement strings.</param>
		/// <param name="str">String to search for matches.</param>
		/// <param name="limit">Max number of replacements performed.</param>
		/// <param name="sourceCodeDesc"><see cref="SourceCodeDescriptor"/> for possible lambda function creation.</param>
		/// <param name="count">Cumulated number of replacements.</param>
		/// <returns></returns>
		private static string ReplaceInternal(DObject self, Dictionary<string, object> definedVariables, PerlRegExpConverter converter, PhpCallback callback,
			string str, int limit, SourceCodeDescriptor sourceCodeDesc, ref int count)
		{
			Debug.Assert(limit >= -1);

			if (callback == null)
			{
				// replace without executing code or counting the number of replacements:
				if ((converter.PerlOptions & PerlRegexOptions.Evaluate) == 0 && count < 0)
					return converter.Regex.Replace(str, converter.DotNetReplaceExpression, limit);

				Evaluator evaluator = new Evaluator(converter.Regex, converter.DotNetReplaceExpression, sourceCodeDesc, self, definedVariables);
				MatchEvaluator match_evaluator;

				if ((converter.PerlOptions & PerlRegexOptions.Evaluate) != 0)
					match_evaluator = new MatchEvaluator(evaluator.ReplaceCodeExecute);
				else
					match_evaluator = new MatchEvaluator(evaluator.ReplaceCount);

				string result = converter.Regex.Replace(str, match_evaluator, limit);
				count += evaluator.Count;
				return result;
			}
			else
			{
                StringBuilder result = new StringBuilder((str != null) ? str.Length : 0);
				int last_index = 0;

				Match m = converter.Regex.Match(str);
				while (m.Success && (limit == -1 || limit-- > 0))
				{
					// append everything from input string to current match
					result.Append(str, last_index, m.Index - last_index);

					// move index after current match
					last_index = m.Index + m.Length;

					PhpArray arr = new PhpArray(m.Groups.Count, 0);
					for (int i = 0; i < m.Groups.Count; i++)
						arr[i] = m.Groups[i].Value;

					// append user callback function result
					string replacement = Core.Convert.ObjectToString(callback.Invoke(arr));
					result.Append(replacement);

					m = m.NextMatch();

					count++;
				}

				// remaining string
				result.Append(str, last_index, str.Length - last_index);
				return result.ToString();
			}
		}
Beispiel #5
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);
		}
Beispiel #6
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;
		}
Beispiel #7
0
		public static bool Assert(
			object assertion,
			ScriptContext context,
			Dictionary<string, object> definedVariables,
			DObject self,
			DTypeDesc includer,
			string containingSourcePath,
			int line,
			int column,
			int containerId,
			NamingContext namingContext)
		{
			object result;
			string code;

			// skips asserts if not active:
			if (!context.Config.Assertion.Active) return true;

			if ((code = PhpVariable.AsString(assertion)) != null)
			{
				// disables error reporting if eval should be quite:
				if (context.Config.Assertion.Quiet) context.DisableErrorReporting();

				SourceCodeDescriptor descriptor = new SourceCodeDescriptor(containingSourcePath, containerId, line, column);

				// evaluates the expression:
				result = EvalInternal("return ", code, ";", EvalKinds.Assert, context, definedVariables, self, includer, descriptor, false, namingContext);

				// restores error reporting if eval have been quite: 
				if (context.Config.Assertion.Quiet) context.EnableErrorReporting();
			}
			else
			{
				result = assertion;
			}

			// checks the result of assertion:
			return CheckAssertion(result, code, context, containingSourcePath, line, column, namingContext);
		}
Beispiel #8
0
		/// <summary>
		/// Compiles a function with a specified parameters and body and adds it to dynamic module. 
		/// </summary>
		/// <param name="parameters">The function's parameters (e.g. <c>"$x, $y = 1, &amp;$z"</c>).</param>
		/// <param name="body">The function's body.</param>
		/// <param name="context">A script context.</param>
		/// <param name="descriptor"></param>
		/// <returns>A name of the created function.</returns>
		/// <exception cref="ArgumentNullException">Any parameter is a <B>null</B> reference.</exception>
		public static string CreateLambdaFunction(string/*!*/ parameters, string/*!*/ body, ScriptContext/*!*/ context,
			SourceCodeDescriptor descriptor)
		{
			if (parameters == null)
				throw new ArgumentNullException("parameters");
			if (body == null)
				throw new ArgumentNullException("body");
			if (context == null)
				throw new ArgumentNullException("context");

			string name = GenerateLambdaName(parameters, body);
            if (context.DeclaredFunctions != null && context.DeclaredFunctions.ContainsKey(name))
                return name;

			string prefix1, prefix2;
			GetLamdaFunctionCodePrefixes(name, parameters, out prefix1, out prefix2);

			context.ClearCapturedSourceCodeDescriptor();
			EvalInternal(prefix2, body, "}", EvalKinds.LambdaFunction, context, null, null, null, descriptor, false, null); // TODO: naming context in lambda function??

			return name;
		}
Beispiel #9
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));
        }
Beispiel #10
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;
		}
Beispiel #11
0
        internal void PostCompile(SourceCodeDescriptor descriptor)
        {
            module_builder.Bake();
            Bake();

            // TODO: analyzer.GetTypeDependencies();
            var dependentTypes = new List<KeyValuePair<string, DTypeDesc>>(bakedTypes != null ? bakedTypes.Length : 0);
            if (bakedTypes != null)
                foreach (var type in bakedTypes)
                {
                    var parent = type.Value.Base;
                    if (parent is PhpTypeDesc && parent.RealType.Module != type.Value.RealType.Module)  // base type if from different module (external dependency)
                        dependentTypes.Add(new KeyValuePair<string, DTypeDesc>(parent.MakeFullName(), parent));

                    // TODO: do the same for type.Value.Interfaces
                }

            //
            module = assembly_builder.TransientAssembly.AddModule(module_builder, dependentTypes, sourceUnit.Code, descriptor);
        }