public GlobalCodeCompiler(GlobalCode /*!*/ ast) { if (!ast.SourceUnit.IsPure) { this.varTable = new VariablesTable(20); this.varTable.SetAllRef(); this.labels = new Dictionary <VariableName, Statement>(); } }
public void TestMissingCollectionsTable() { using (var connection = new SQLiteConnection("Data Source=:memory:")) { connection.Open(); VariablesTable.CreateTable(connection); TypeModel.CreateTable(connection); new Action(() => Database.Open(connection, null, new Type[0], false)) .Should().Throw <IncompatibleDatabaseSchemaException>() .WithMessage("The database is missing the 'isabel_collections' table. The table may have been deleted or this may not even be an IsabelDb file. Are you sure the path is correct?"); } }
/// <summary> /// Initializes a new instance of the GlobalCode class. /// </summary> public GlobalCode(List <Statement> /*!*/ statements, SourceUnit /*!*/ sourceUnit) { Debug.Assert(statements != null && sourceUnit != null); this.sourceUnit = sourceUnit; this.statements = statements; this.prependedInclusion = null; this.AppendedInclusion = null; if (!sourceUnit.CompilationUnit.IsPure) { varTable = new VariablesTable(20); varTable.SetAllRef(); labels = new Dictionary <VariableName, Statement>(); } }
/// <summary> /// Initializes a new instance of the GlobalCode class. /// </summary> public GlobalCode(List<Statement>/*!*/ statements, SourceUnit/*!*/ sourceUnit) { Debug.Assert(statements != null && sourceUnit != null); this.sourceUnit = sourceUnit; this.statements = statements; this.prependedInclusion = null; this.AppendedInclusion = null; if (!sourceUnit.CompilationUnit.IsPure) { varTable = new VariablesTable(20); varTable.SetAllRef(); labels = new Dictionary<VariableName, Statement>(); } }
public void TestOldDatabaseSchema() { using (var connection = new SQLiteConnection("Data Source=:memory:")) { connection.Open(); VariablesTable.CreateTable(connection); TypeModel.CreateTable(connection); CollectionsTable.CreateTable(connection); using (var command = connection.CreateCommand()) { command.CommandText = string.Format("INSERT OR REPLACE INTO {0} (key, value) VALUES (@key, @value)", VariablesTable.TableName); command.Parameters.AddWithValue("@key", VariablesTable.IsabelSchemaVersionKey); command.Parameters.AddWithValue("@value", 0); command.ExecuteNonQuery(); } new Action(() => Database.Open(connection, null, new Type[0], false)) .Should().Throw <IncompatibleDatabaseSchemaException>() .WithMessage("The database was created with an earlier version of IsabelDb (Schema version: 0) and its schema is incompatible to this version."); } }
/// <summary> /// Called when a <see cref="PHP.Core.AST.MethodDecl"/> AST node is entered during the emit phase. /// </summary> public void EnterMethodDeclaration(PhpMethod/*!*/ method) { bool is_optimized = (method.Properties & RoutineProperties.HasUnoptimizedLocals) == 0; bool rt_variables_table = (method.Properties & RoutineProperties.HasRTVariablesTable) != 0; CompilerLocationStack.TypeDeclContext class_context = locationStack.PeekTypeDecl(); CompilerLocationStack.MethodDeclContext md_context = new CompilerLocationStack.MethodDeclContext(); md_context.Type = class_context.Type; md_context.Method = method; // Set whether access to variables should be generated via locals or table md_context.OptimizedLocals = this.OptimizedLocals; OptimizedLocals = is_optimized; // set compile-time variables table: md_context.CurrentVariablesTable = this.currentVariablesTable; currentVariablesTable = method.Builder.LocalVariables; // set compile-time variables table: md_context.CurrentLabels = this.currentLabels; currentLabels = method.Builder.Labels; // Set the valid method to emit the "return" statement md_context.ReturnsPhpReference = this.ReturnsPhpReference; this.ReturnsPhpReference = method.Signature.AliasReturn; // CallSites (same as in TypeDecl, not changed): //md_context.CallSites = callSites; //this.callSites = new Compiler.CodeGenerator.CallSites(/*class_context = TypeContextPlace*/); // create new IL emitter for the method: md_context.IL = il; il = new ILEmitter(method.ArgFullInfo); // set RT variables table place: md_context.RTVariablesTablePlace = RTVariablesTablePlace; if (rt_variables_table) { LocalBuilder var_table_local = il.DeclareLocal(PhpVariable.RTVariablesTableType); if (sourceUnit.SymbolDocumentWriter != null) var_table_local.SetLocalSymInfo("<locals>"); RTVariablesTablePlace = new Place(var_table_local); } else RTVariablesTablePlace = LiteralPlace.Null; // sets ScriptContext and Self places appropriately: md_context.ClassContextPlace = TypeContextPlace; md_context.ScriptContextPlace = ScriptContextPlace; md_context.SelfPlace = SelfPlace; md_context.LateStaticBindTypePlace = LateStaticBindTypePlace; if (method.IsStatic) { ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, FunctionBuilder.ArgContextStatic); SelfPlace = LiteralPlace.Null; } else { ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, FunctionBuilder.ArgContextInstance); if (method.DeclaringPhpType.ProxyFieldInfo != null) { // the real this is not a DObject SelfPlace = new Place(IndexedPlace.ThisArg, method.DeclaringPhpType.ProxyFieldInfo); } else { // the real this is a DObject SelfPlace = IndexedPlace.ThisArg; } } // set Result place and return label: md_context.ResultPlace = ResultPlace; md_context.ReturnLabel = ReturnLabel; ResultPlace = null; LateStaticBindTypePlace = null; // set exception block nesting: md_context.ExceptionBlockNestingLevel = ExceptionBlockNestingLevel; ExceptionBlockNestingLevel = 0; // set current PhpRoutine md_context.PhpRoutine = method; // locationStack.PushMethodDecl(md_context); }
/// <summary> /// Called when a <see cref="PHP.Core.AST.FunctionDecl"/> AST node is left during the emit phase. /// </summary> public void LeaveFunctionDeclaration() { CompilerLocationStack.FunctionDeclContext fd_context = locationStack.PeekFunctionDecl(); locationStack.Pop(); // close CallSites: //this.callSites.Bake(); // restore: this.callSites.PopClassContext();//this.callSites = fd_context.CallSites; this.il = fd_context.IL; this.ScriptContextPlace = fd_context.ScriptContextPlace; this.TypeContextPlace = fd_context.ClassContextPlace; this.LateStaticBindTypePlace = fd_context.LateStaticBindTypePlace; this.SelfPlace = fd_context.SelfPlace; this.ResultPlace = fd_context.ResultPlace; this.ReturnLabel = fd_context.ReturnLabel; this.currentVariablesTable = fd_context.CurrentVariablesTable; this.currentLabels = fd_context.CurrentLabels; this.RTVariablesTablePlace = fd_context.RTVariablesTablePlace; this.OptimizedLocals = fd_context.OptimizedLocals; this.ReturnsPhpReference = fd_context.ReturnsPhpReference; this.ExceptionBlockNestingLevel = fd_context.ExceptionBlockNestingLevel; }
private bool EnterFunctionDeclarationInternal(PhpRoutine/*!*/ function, QualifiedName qualifiedName) { Debug.Assert(function.IsFunction); bool is_optimized = (function.Properties & RoutineProperties.HasUnoptimizedLocals) == 0; bool indirect_local_access = (function.Properties & RoutineProperties.IndirectLocalAccess) != 0; CompilerLocationStack.FunctionDeclContext fd_context = new CompilerLocationStack.FunctionDeclContext(); fd_context.Name = qualifiedName; // Set whether access to variables should be generated via locals or table fd_context.OptimizedLocals = this.OptimizedLocals; this.OptimizedLocals = is_optimized; // Set the valid method to emit the "return" statement fd_context.ReturnsPhpReference = this.ReturnsPhpReference; this.ReturnsPhpReference = function.Signature.AliasReturn; // CallSites fd_context.CallSites = null;//fd_context.CallSites = callSites; //this.callSites = new Compiler.CodeGenerator.CallSitesBuilder( // sourceUnit.CompilationUnit.Module.GlobalType.RealModuleBuilder, // fd_context.Name.ToString(), // LiteralPlace.Null); // keep current site container, just change the class context (to avoid of creating and baking so many types) this.callSites.PushClassContext(LiteralPlace.Null, null); // Set ILEmitter to function's body fd_context.IL = this.il; this.il = new ILEmitter(function.ArgFullInfo); // Set current variables table (at codeGenerator) fd_context.CurrentVariablesTable = this.currentVariablesTable; this.currentVariablesTable = function.Builder.LocalVariables; // Set current variables table (at codeGenerator) fd_context.CurrentLabels = this.currentLabels; this.currentLabels = function.Builder.Labels; // Set place for loading hashtable with variables at runtime fd_context.RTVariablesTablePlace = this.RTVariablesTablePlace; if (indirect_local_access || !is_optimized) { LocalBuilder var_table_local = il.DeclareLocal(PhpVariable.RTVariablesTableType); if (sourceUnit.SymbolDocumentWriter != null) var_table_local.SetLocalSymInfo("<locals>"); this.RTVariablesTablePlace = new Place(var_table_local); } else this.RTVariablesTablePlace = LiteralPlace.Null; // Set ScriptContext fd_context.ScriptContextPlace = this.ScriptContextPlace; this.ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, FunctionBuilder.ArgContext); // Set Class context fd_context.ClassContextPlace = this.TypeContextPlace; this.TypeContextPlace = LiteralPlace.Null; // Set Self fd_context.SelfPlace = this.SelfPlace; this.SelfPlace = LiteralPlace.Null; // Set Static fd_context.LateStaticBindTypePlace = this.LateStaticBindTypePlace; this.LateStaticBindTypePlace = null; // set Result place fd_context.ResultPlace = this.ResultPlace; fd_context.ReturnLabel = this.ReturnLabel; this.ResultPlace = null; // set exception block nesting: fd_context.ExceptionBlockNestingLevel = this.ExceptionBlockNestingLevel; this.ExceptionBlockNestingLevel = 0; // set current PhpRoutine fd_context.PhpRoutine = function; // locationStack.PushFunctionDecl(fd_context); return true; }
/// <summary> /// Called when a <see cref="PHP.Core.AST.GlobalCode"/> AST node is left during the emit phase. /// </summary> public void LeaveGlobalCodeDeclaration() { CompilerLocationStack.GlobalCodeContext gc_context = locationStack.PeekGlobalCode(); locationStack.Pop(); // clear (for convenience): this.sourceUnit = null; // close CallSites: this.callSites.Bake(); // restore: this.callSites = null; this.il = gc_context.IL; this.ScriptContextPlace = gc_context.ScriptContextPlace; this.TypeContextPlace = gc_context.ClassContextPlace; this.LateStaticBindTypePlace = null; this.SelfPlace = gc_context.SelfPlace; this.ResultPlace = gc_context.ResultPlace; this.ReturnLabel = gc_context.ReturnLabel; this.currentVariablesTable = gc_context.CurrentVariablesTable; this.currentLabels = gc_context.CurrentLabels; this.RTVariablesTablePlace = gc_context.RTVariablesTablePlace; this.OptimizedLocals = gc_context.OptimizedLocals; this.ReturnsPhpReference = gc_context.ReturnsPhpReference; this.ExceptionBlockNestingLevel = gc_context.ExceptionBlockNestingLevel; }
///// <summary> ///// Prepares local variable for a store operation. ///// </summary> //internal void StoreLocalPrepare(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) //{ // Debug.Assert(variable == null ^ variableName == null); //} /// <summary> /// Unsets a specified variable. /// </summary> internal void UnsetLocal(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { if (variable.IsPhpReference) { // <variable> = new PhpReference(); il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void); variable.Variable.EmitStore(il); } else { il.Emit(OpCodes.Ldnull); variable.Variable.EmitStore(il); } } else { // CALL Operators.SetVariable(<local variables table>,<name>,null); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Ldloc(variableName); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Call, Methods.Operators.SetVariable); } }
/// <summary> /// Loads and address of a specified variable. /// </summary> internal void LoadLocalAddress(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { if (variable.IsPhpReference) { // LOAD ADDR <variable>.value; variable.Variable.EmitLoad(il); il.Emit(OpCodes.Ldflda, Fields.PhpReference_Value); } else { variable.Variable.EmitLoadAddress(il); } } else { LoadTabledVariableAddress(codeGenerator); } }
internal PhpRoutineBuilder(PhpRoutine/*!*/ routine, Signature signature, TypeSignature typeSignature) { this.routine = routine; this.signature = signature; this.typeSignature = typeSignature; this.localVariables = new VariablesTable(10); this.labels = new Dictionary<VariableName, Statement>(1); }
/// <summary> /// Emits local variable switch and performs a specified operation on each case. /// </summary> /// <param name="codeGenerator">The code generator.</param> /// <param name="method">The operation performed in each case.</param> internal void EmitSwitch(CodeGenerator codeGenerator, SwitchMethod method) { ILEmitter il = codeGenerator.IL; Debug.Assert(method != null); Label default_case = il.DefineLabel(); Label end_label = il.DefineLabel(); LocalBuilder ivar_local = il.GetTemporaryLocal(Types.String[0], true); LocalBuilder non_interned_local = il.DeclareLocal(Types.String[0]); VariablesTable variables = codeGenerator.CurrentVariablesTable; Label[] labels = new Label[variables.Count]; // non_interned_local = <name expression>; EmitName(codeGenerator); il.Stloc(non_interned_local); // ivar_local = String.IsInterned(non_interned_local) il.Ldloc(non_interned_local); il.Emit(OpCodes.Call, Methods.String_IsInterned); il.Stloc(ivar_local); // switch for every compile-time variable: int i = 0; foreach (VariablesTable.Entry variable in variables) { labels[i] = il.DefineLabel(); // IF (ivar_local == <i-th variable name>) GOTO labels[i]; il.Ldloc(ivar_local); il.Emit(OpCodes.Ldstr, variable.VariableName.ToString()); il.Emit(OpCodes.Beq, labels[i]); i++; } // GOTO default_case: il.Emit(OpCodes.Br, default_case); // operation on each variable: i = 0; foreach (VariablesTable.Entry variable in variables) { // labels[i]: il.MarkLabel(labels[i]); // operation: method(codeGenerator, variable, null); // GOTO end; il.Emit(OpCodes.Br, end_label); i++; } // default case - new variable created at runtime: il.MarkLabel(default_case); method(codeGenerator, null, non_interned_local); // END: il.MarkLabel(end_label); }
public bool IsExistInContext(string item) => VariablesTable.ContainsKey(item);
/// <summary> /// Called when a <see cref="PHP.Core.AST.MethodDecl"/> AST node is left during the emit phase. /// </summary> public void LeaveMethodDeclaration() { CompilerLocationStack.MethodDeclContext md_context = locationStack.PeekMethodDecl(); locationStack.Pop(); // restore: //this.callSites = md_context.CallSite; // the same this.il = md_context.IL; this.ScriptContextPlace = md_context.ScriptContextPlace; this.TypeContextPlace = md_context.ClassContextPlace; this.LateStaticBindTypePlace = md_context.LateStaticBindTypePlace; this.SelfPlace = md_context.SelfPlace; this.ResultPlace = md_context.ResultPlace; this.ReturnLabel = md_context.ReturnLabel; this.currentVariablesTable = md_context.CurrentVariablesTable; this.currentLabels = md_context.CurrentLabels; this.RTVariablesTablePlace = md_context.RTVariablesTablePlace; this.OptimizedLocals = md_context.OptimizedLocals; this.ReturnsPhpReference = md_context.ReturnsPhpReference; this.ExceptionBlockNestingLevel = md_context.ExceptionBlockNestingLevel; }
/// <summary> /// Loads a value of a specified variable. If the variable is of type <see cref="PhpReference"/>, it is dereferenced. /// </summary> internal void LoadLocal(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { // LOAD DEREF <variable>; variable.Variable.EmitLoad(il); if (variable.IsPhpReference) il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value); } else { // LOAD Operators.GetVariable[Unchecked](<script context>, <local variables table>, <variable name>); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Ldloc(variableName); if (codeGenerator.ChainBuilder.QuietRead) il.Emit(OpCodes.Call, Methods.Operators.GetVariableUnchecked); else il.Emit(OpCodes.Call, Methods.Operators.GetVariable); } }
/// <summary> /// Obtiene recursivamente la tabla de variables del contexto /// </summary> public Variables.TableVariableModel GetVariablesRecursive() { Variables.TableVariableModel table = new Variables.TableVariableModel(this); // Añade las variables del padre if (Parent != null) { table = Parent.GetVariablesRecursive(); } // Añade / sustituye las variables propias foreach (System.Collections.Generic.KeyValuePair <string, Variables.VariableModel> item in VariablesTable.GetAll()) { table.Add(item.Value); } // Devuelve la colección de tablas return(table); }
/// <summary> /// Loads a specified reference local variable. /// </summary> internal void LoadLocalRef(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { Debug.Assert(variable.IsPhpReference); variable.Variable.EmitLoad(il); } else { codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Ldloc(variableName); il.Emit(OpCodes.Call, Methods.Operators.GetVariableRef); } }
/// <summary> /// Initializes a new instance of the <see cref="PHP.Core.CodeGenerator"/> class. /// </summary> public CodeGenerator(CompilationContext/*!*/ context) { ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgContext); TypeContextPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgIncluder); this.context = context; this.il = null; this.currentVariablesTable = null; this.currentLabels = null; this.locationStack = new CompilerLocationStack(); this.branchingStack = new BranchingStack(this); this.chainBuilder = new ChainBuilder(this); }
/// <summary> /// Stores a reference on the top of the stack to a specified variable. /// </summary> internal void StoreLocalRefAssign(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { Debug.Assert(variable.IsPhpReference); variable.Variable.EmitStore(il); } else { // temp = STACK LocalBuilder temp = il.GetTemporaryLocal(Types.PhpReference[0], true); il.Stloc(temp); // CALL Operators.SetVariableRef(<local variables table>,<name>,temp); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Ldloc(variableName); il.Ldloc(temp); il.Emit(OpCodes.Call, Methods.Operators.SetVariableRef); } }
/// <summary> /// Called when a <see cref="PHP.Core.AST.GlobalCode"/> AST node is entered during the emit phase. /// </summary> public void EnterGlobalCodeDeclaration(VariablesTable variablesTable, Dictionary<VariableName, Statement> labels, CompilationSourceUnit/*!*/ sourceUnit) { CompilerLocationStack.GlobalCodeContext gc_context = new CompilerLocationStack.GlobalCodeContext(); // no need to backup current source unit as it is no longer needed: this.sourceUnit = sourceUnit; // set whether access to variables should be generated via locals or table gc_context.OptimizedLocals = this.OptimizedLocals; this.OptimizedLocals = false; // global code returns object gc_context.ReturnsPhpReference = this.ReturnsPhpReference; this.ReturnsPhpReference = false; // CallSites Debug.Assert(this.callSites == null, "Unclosed CallSite!"); this.callSites = new CallSitesBuilder( sourceUnit.CompilationUnit.Module.GlobalType.RealModuleBuilder, sourceUnit.SourceFile.RelativePath.ToString(), null/*Unknown at compile time*/); // set ILEmitter for global code gc_context.IL = il; il = CompilationUnit.ModuleBuilder.CreateGlobalCodeEmitter(); // set current variables table (at codeGenerator) gc_context.CurrentVariablesTable = currentVariablesTable; currentVariablesTable = variablesTable; // set current labels table (at codeGenerator) gc_context.CurrentLabels = currentLabels; currentLabels = labels; // set OpCode for loading hashtable with variables at runtime gc_context.RTVariablesTablePlace = RTVariablesTablePlace; RTVariablesTablePlace = new IndexedPlace(PlaceHolder.Argument, 1); // set Script Context place gc_context.ScriptContextPlace = ScriptContextPlace; ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgContext); // set Class Context place gc_context.ClassContextPlace = TypeContextPlace; TypeContextPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgIncluder); // set Self place gc_context.SelfPlace = SelfPlace; SelfPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgSelf); // set late static bind place gc_context.LateStaticBindTypePlace = LateStaticBindTypePlace; LateStaticBindTypePlace = null; // set Result place and return label gc_context.ResultPlace = ResultPlace; gc_context.ReturnLabel = ReturnLabel; ResultPlace = null; // set exception block nesting: gc_context.ExceptionBlockNestingLevel = ExceptionBlockNestingLevel; ExceptionBlockNestingLevel = 0; locationStack.PushGlobalCode(gc_context); }