/// <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); }
/// <summary> /// Called before 'Compile' to initialize module & 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); }
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)); }
/// <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; }
/// <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; }
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; } }
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; } }
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)); }
/// <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; }
/// <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; }
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); }
/// <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; }
/// <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)); }
/// <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; }
/// <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; }
/// <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); }
/// <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); }
/// <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; }
/// <summary> /// Called before 'Compile' to initialize module & 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; }
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)); }
/// <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; }