5 // Chris Bacon (chrisbacon76@gmail.com)
7 // Copyright (C) 2010 Chris Bacon
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
34 using Mono.CodeContracts.Rewrite.Ast;
36 namespace Mono.CodeContracts.Rewrite.AstVisitors {
37 class CompileVisitor : ExprVisitor {
39 public CompileVisitor (ILProcessor il, Dictionary<Expr, Instruction> instructionLookup)
40 : this (il, instructionLookup, il.Append)
44 public CompileVisitor (ILProcessor il, Dictionary<Expr, Instruction> instructionLookup, Action<Instruction> fnEmit)
47 this.instructionLookup = instructionLookup;
51 private ILProcessor il;
52 private Dictionary<Expr, Instruction> instructionLookup;
53 private Action<Instruction> fnEmit;
55 private void Emit (Expr originalExpr, Instruction inst)
57 Instruction originalInst;
58 if (this.instructionLookup != null) {
59 // TODO: Doesn't handle inherited contracts - need to check what to do in this case.
60 if (this.instructionLookup.TryGetValue (originalExpr, out originalInst)) {
61 inst.SequencePoint = originalInst.SequencePoint;
67 private void Emit (Expr originalExpr, Func<Instruction> fnCreateInstruction)
69 Instruction inst = fnCreateInstruction();
70 this.Emit (originalExpr, inst);
73 private void Emit (Expr originalExpr, Func<IEnumerable<Instruction>> fnCreateInstruction)
75 throw new NotImplementedException ();
78 protected override Expr VisitNop (ExprNop e)
80 var instNop = this.il.Create (OpCodes.Nop);
81 this.Emit (e, instNop);
85 protected override Expr VisitLoadArg (ExprLoadArg e)
91 return this.il.Create (OpCodes.Ldarg_0);
93 return this.il.Create (OpCodes.Ldarg_1);
95 return this.il.Create (OpCodes.Ldarg_2);
97 return this.il.Create (OpCodes.Ldarg_3);
100 return this.il.Create (OpCodes.Ldarg_S, (byte) index);
102 return this.il.Create (OpCodes.Ldarg, index);
105 // Required due to bug in compiler
106 throw new NotSupportedException();
112 protected override Expr VisitLoadConstant (ExprLoadConstant e)
114 this.Emit (e, () => {
117 return this.il.Create (OpCodes.Ldnull);
119 Type vType = v.GetType ();
120 TypeCode vTypeCode = Type.GetTypeCode (vType);
126 return this.il.Create (OpCodes.Ldc_I4_M1);
128 return this.il.Create (OpCodes.Ldc_I4_0);
130 return this.il.Create (OpCodes.Ldc_I4_1);
132 return this.il.Create (OpCodes.Ldc_I4_2);
134 return this.il.Create (OpCodes.Ldc_I4_3);
136 return this.il.Create (OpCodes.Ldc_I4_4);
138 return this.il.Create (OpCodes.Ldc_I4_5);
140 return this.il.Create (OpCodes.Ldc_I4_6);
142 return this.il.Create (OpCodes.Ldc_I4_7);
144 return this.il.Create (OpCodes.Ldc_I4_8);
146 if (value >= -128 && value <= 127) {
147 return this.il.Create (OpCodes.Ldc_I4_S, (sbyte) value);
149 return this.il.Create (OpCodes.Ldc_I4, value);
152 // Required due to bug in compiler
153 throw new NotSupportedException();
154 case TypeCode.Single:
155 return this.il.Create (OpCodes.Ldc_R4, (float) v);
156 case TypeCode.Double:
157 return this.il.Create (OpCodes.Ldc_R8, (double) v);
158 case TypeCode.String:
159 return this.il.Create (OpCodes.Ldstr, (string) v);
161 throw new NotSupportedException ("Cannot handle constant: " + vTypeCode);
163 // Required due to bug in compiler
164 throw new NotSupportedException();
170 private Expr VisitBinary (ExprBinaryOp e, Func<Instruction> fnCreateIl)
173 this.Visit (e.Right);
174 var inst = fnCreateIl ();
179 protected override Expr VisitCompareLessThan (ExprCompareLessThan e)
181 return this.VisitBinary (e, () => this.il.Create (e.IsSigned ? OpCodes.Clt : OpCodes.Clt_Un));
184 protected override Expr VisitCompareGreaterThan (ExprCompareGreaterThan e)
186 return this.VisitBinary (e, () => this.il.Create (e.IsSigned ? OpCodes.Cgt : OpCodes.Cgt_Un));
189 protected override Expr VisitCompareEqual (ExprCompareEqual e)
191 return this.VisitBinary (e, () => this.il.Create (OpCodes.Ceq));
194 protected override Expr VisitAdd (ExprAdd e)
196 return this.VisitBinary (e, () => {
198 return this.il.Create (OpCodes.Add);
200 return this.il.Create (e.IsSigned ? OpCodes.Add_Ovf : OpCodes.Add_Ovf_Un);
205 protected override Expr VisitSub (ExprSub e)
207 return this.VisitBinary (e, () => {
209 return this.il.Create (OpCodes.Sub);
211 return this.il.Create (e.IsSigned ? OpCodes.Sub_Ovf : OpCodes.Sub_Ovf_Un);
216 protected override Expr VisitCall (ExprCall e)
218 foreach (var param in e.Parameters) {
221 var instCall = this.il.Create (OpCodes.Call, e.Method);
222 this.Emit (e, instCall);
226 protected override Expr VisitReturn (ExprReturn e)
228 var instReturn = this.il.Create (OpCodes.Ret);
229 this.Emit (e, instReturn);
233 protected override Expr VisitBox (ExprBox e)
235 this.Visit (e.ExprToBox);
236 var instBox = this.il.Create (OpCodes.Box, e.ReturnType);
237 this.Emit (e, instBox);
241 protected override Expr VisitConv (ExprConv e)
243 this.Visit (e.ExprToConvert);
244 Instruction instConv;
245 switch (e.ConvToType) {
247 instConv = this.il.Create (OpCodes.Conv_I4);
250 instConv = this.il.Create (OpCodes.Conv_I8);
253 throw new NotSupportedException ("Cannot conv to: " + e.ConvToType);
255 this.Emit (e, instConv);