public void GenerateScope(Subroutine sub, Scope scope) { // TODO should not rely on block order BasicBlock first_block = null; var exps = new List<Expression>(); CurrentScope = scope; for (int i = 0; i < sub.BasicBlocks.Count; ++i) { var block = sub.BasicBlocks[i]; if (block == null || block.Dead != 0) // TODO enumeration continue; if (block.Scope > scope.Id) { int scopeId = block.Scope; // if scope has no blocks on its own, still needs to // insert inner scopes, so it can't just test whether this // block's scope is directly inside the current scope, but // it must handle the case when a scope is entirely // composed by blocks in inner scopes if (Scopes[scopeId].FirstBlockFor != -1) scopeId = Scopes[scopeId].FirstBlockFor; if (sub.Scopes[scopeId].Outer == scope.Id && !Scopes[scopeId].Used) { Scopes[scopeId].Used = true; if (Scopes[scopeId].Body != null) { if (first_block != null) exps.Add(Expression.Label(Scopes[scopeId].Start)); exps.AddRange(Scopes[scopeId].Body); } if (first_block == null) { first_block = Scopes[block.Scope].FirstBlock; Scopes[block.Scope].FirstBlockFor = scope.Id; } } } else if (block.Scope == scope.Id) { if (first_block == null) first_block = block; else exps.Add(Expression.Label(BlockLabels[block])); GenerateBlock(sub, block, exps); } } List<Expression> body = null; if ((scope.Flags & Scope.SCOPE_EVAL) != 0) { exps.Insert(0, Expression.Call( Expression.Field(Runtime, "CallStack"), typeof(Stack<StackFrame>).GetMethod("Push"), Expression.New( typeof(StackFrame).GetConstructor(new Type[] { typeof(string), typeof(string), typeof(int), typeof(P5Code), typeof(Opcode.ContextValues), typeof(bool)}), Expression.Constant(sub.LexicalStates[scope.LexicalState].Package), Expression.Constant(scope.Start.File), Expression.Constant(scope.Start.Line), Expression.Constant(null, typeof(P5Code)), Expression.Constant((Opcode.ContextValues)scope.Context), Expression.Constant(true) ))); var except = new List<Expression>(); var ex = Expression.Variable(typeof(P5Exception)); for (int j = scope.Opcodes.Count - 1; j >= 0; --j) GenerateOpcodes(sub, scope.Opcodes[j], except); except.Add( Expression.Call( Runtime, typeof(Runtime).GetMethod("SetException"), ex)); GenerateBlock(sub, scope.Exception, except); var block = Expression.TryCatchFinally( Expression.Block(typeof(IP5Any), exps), Expression.Call( Expression.Field(Runtime, "CallStack"), typeof(Stack<StackFrame>).GetMethod("Pop")), Expression.Catch( ex, Expression.Block(typeof(IP5Any), except)) ); body = new List<Expression>(); body.Add(block); } else if (scope.Opcodes.Count > 0) { var fault = new List<Expression>(); for (int j = scope.Opcodes.Count - 1; j >= 0; --j) GenerateOpcodes(sub, scope.Opcodes[j], fault); fault.Add(Expression.Rethrow(typeof(IP5Any))); var block = Expression.TryCatch( Expression.Block(typeof(IP5Any), exps), Expression.Catch( typeof(System.Exception), Expression.Block(typeof(IP5Any), fault))); body = new List<Expression>(); body.Add(block); } else if (first_block != null) body = exps; if (first_block != null) Scopes[scope.Id].Start = BlockLabels[first_block]; Scopes[scope.Id].FirstBlock = first_block; if ((scope.Flags & Scope.SCOPE_VALUE) != 0) ValueBlocks[first_block] = Expression.Block( typeof(IP5Any), body); else Scopes[scope.Id].Body = body; }
public static Scope ReadScope(BinaryReader reader, Subroutine[] subs, Subroutine sub) { var scope = new Scope(); scope.Outer = reader.ReadInt32(); scope.Id = reader.ReadInt32(); scope.Flags = reader.ReadInt32(); scope.Context = reader.ReadInt32(); ReadPos(reader, out scope.Start); ReadPos(reader, out scope.End); scope.LexicalState = reader.ReadInt32(); int exc_idx = reader.ReadInt32(); if (exc_idx >= 0) scope.Exception = sub.BasicBlocks[exc_idx]; int leave_count = reader.ReadInt32(); scope.Opcodes = new List<List<Opcode>>(leave_count); for (int i = 0; i < leave_count; ++i) { int op_count = reader.ReadInt32(); scope.Opcodes.Add(new List<Opcode>(op_count)); for (int j = 0; j < op_count; ++j) scope.Opcodes[i].Add(ReadOpcode(reader, subs, sub)); } return scope; }