Permalink
Browse files

check array indices as a separate step (so it also runs for unityscri…

…pt);

extract most SlicingExpression handling out of ProcessMethodBodies;
  • Loading branch information...
1 parent 3862e61 commit 75796ae0befcee96fda8e5bc45e3fba9a3b57154 @bamboo committed May 4, 2012
@@ -6,7 +6,7 @@ public static class AstNodePredicates
{
public static bool IsComplexSlicing(this SlicingExpression node)
{
- return node.Indices.Any(AstUtil.IsComplexSlice);
+ return node.Indices.Any(IsComplexSlice);
}
public static bool IsTargetOfAssignment(this Expression node)
@@ -16,5 +16,12 @@ public static bool IsTargetOfAssignment(this Expression node)
return false;
return node == parentExpression.Left && AstUtil.IsAssignment(parentExpression);
}
+
+ public static bool IsComplexSlice(Slice slice)
+ {
+ return slice.End != null
+ || slice.Step != null
+ || slice.Begin == OmittedExpression.Default;
+ }
}
}
@@ -80,13 +80,6 @@ public static string GetMethodNameForOperator(UnaryOperatorType op)
return "op_" + op;
}
- public static bool IsComplexSlice(Slice slice)
- {
- return slice.End != null
- || slice.Step != null
- || slice.Begin == OmittedExpression.Default;
- }
-
public static Node GetMemberAnchor(Node node)
{
var member = node as MemberReferenceExpression;
@@ -447,6 +447,7 @@
<Compile Include="Steps\CheckMembersProtectionLevel.cs" />
<Compile Include="Steps\CheckMemberTypes.cs" />
<Compile Include="Steps\CheckNeverUsedMembers.cs" />
+ <Compile Include="Steps\CheckSlicingExpressions.cs" />
<Compile Include="Steps\ClosureSignatureInferrer.cs" />
<Compile Include="Steps\ConstantFolding.cs" />
<Compile Include="Steps\ContextAnnotations.cs" />
@@ -455,6 +456,7 @@
<Compile Include="Steps\EmitAssembly.cs" />
<Compile Include="Steps\EntityPredicates.cs" />
<Compile Include="Steps\ExpandAstLiterals.cs" />
+ <Compile Include="Steps\ExpandComplexSlicingExpressions.cs" />
<Compile Include="Steps\ExpandDuckTypedExpressions.cs" />
<Compile Include="Steps\ExpandPropertiesAndEvents.cs" />
<Compile Include="Steps\ExpandVarArgsMethodInvocations.cs" />
@@ -481,6 +483,7 @@
<Compile Include="Steps\MacroProcessing\NodeGeneratorExpander.cs" />
<Compile Include="Steps\MacroProcessing\TypeMemberStatementBubbler.cs" />
<Compile Include="Steps\MergePartialTypes.cs" />
+ <Compile Include="Steps\MethodTrackingVisitorCompilerStep.cs" />
<Compile Include="Steps\NormalizeExpressions.cs" />
<Compile Include="Steps\NormalizeIterationStatements.cs" />
<Compile Include="Steps\NormalizeStatementModifiers.cs" />
@@ -649,6 +652,7 @@
<Compile Include="TypeSystem\Services\MetadataUtil.cs" />
<Compile Include="TypeSystem\Services\NameResolutionService.cs" />
<Compile Include="TypeSystem\Services\RuntimeMethodCache.cs" />
+ <Compile Include="TypeSystem\Services\TypeChecker.cs" />
<Compile Include="TypeSystem\Services\TypeCompatibilityRules.cs" />
<Compile Include="TypeSystem\Services\TypeSystemServices.cs" />
<Compile Include="TypeSystem\TypeCollector.cs" />
@@ -26,16 +26,17 @@
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
+using Boo.Lang.Compiler.Steps;
+
namespace Boo.Lang.Compiler.Pipelines
{
- using Boo.Lang.Compiler.Steps;
-
public class CheckForErrors : ResolveExpressions
{
public CheckForErrors()
{
- this.BreakOnErrors = false;
- this.Add(new StricterErrorChecking());
+ BreakOnErrors = false;
+ Add(new CheckSlicingExpressions());
+ Add(new StricterErrorChecking());
}
}
}
@@ -47,12 +47,15 @@ public Compile()
Add(new VerifyExtensionMethods());
Add(new CheckIdentifiers());
+ Add(new CheckSlicingExpressions());
Add(new StricterErrorChecking());
Add(new DetectNotImplementedFeatureUsage());
Add(new CheckAttributesUsage());
-
+
Add(new ExpandDuckTypedExpressions());
+ Add(new ExpandComplexSlicingExpressions());
+
Add(new ProcessAssignmentsToValueTypeMembers());
Add(new ExpandPropertiesAndEvents());
@@ -0,0 +1,69 @@
+using Boo.Lang.Compiler.Ast;
+using Boo.Lang.Compiler.TypeSystem;
+using Boo.Lang.Compiler.TypeSystem.Services;
+using Boo.Lang.Environments;
+
+namespace Boo.Lang.Compiler.Steps
+{
+ public class CheckSlicingExpressions : AbstractFastVisitorCompilerStep
+ {
+ public override void OnSlicingExpression(SlicingExpression node)
+ {
+ base.OnSlicingExpression(node);
+
+ var arrayType = GetExpressionType(node.Target) as IArrayType;
+ if (arrayType == null)
+ return;
+
+ if (arrayType.Rank != node.Indices.Count)
+ Error(CompilerErrorFactory.InvalidArrayRank(node, node.Target.ToCodeString(), arrayType.Rank, node.Indices.Count));
+ }
+
+ public override void OnSlice(Slice node)
+ {
+ base.OnSlice(node);
+
+ if (TypeSystemServices.IsDuckTyped((Expression) node.ParentNode))
+ return;
+
+ AssertInt(node.Begin);
+ AssertOptionalInt(node.End);
+ if (node.Step != null)
+ CompilerErrorFactory.NotImplemented(node.Step, "slicing step");
+ }
+
+ private void AssertInt(Expression e)
+ {
+ AssertExpressionTypeIsCompatibleWith(TypeSystemServices.IntType, e);
+ }
+
+ private void AssertExpressionTypeIsCompatibleWith(IType expectedType, Expression e)
+ {
+ TypeChecker.AssertTypeCompatibility(e, expectedType, GetExpressionType(e));
+ }
+
+ private void AssertOptionalInt(Expression e)
+ {
+ if (IsNotOmitted(e))
+ AssertInt(e);
+ }
+
+ private static bool IsNotOmitted(Expression e)
+ {
+ return e != null && e != OmittedExpression.Default;
+ }
+
+ private TypeChecker TypeChecker
+ {
+ get { return _typeChecker.Instance; }
+ }
+
+ public override void Dispose()
+ {
+ _typeChecker = new EnvironmentProvision<TypeChecker>();
+ base.Dispose();
+ }
+
+ private EnvironmentProvision<TypeChecker> _typeChecker;
+ }
+}
@@ -0,0 +1,193 @@
+using System.Linq;
+using Boo.Lang.Compiler.Ast;
+using Boo.Lang.Compiler.TypeSystem;
+using Boo.Lang.Compiler.TypeSystem.Internal;
+using Boo.Lang.Compiler.TypeSystem.Services;
+using Boo.Lang.Environments;
+
+namespace Boo.Lang.Compiler.Steps
+{
+ public class ExpandComplexSlicingExpressions : MethodTrackingVisitorCompilerStep
+ {
+ public override void OnSlicingExpression(SlicingExpression node)
+ {
+ base.OnSlicingExpression(node);
+
+ if (!node.IsComplexSlicing())
+ return;
+
+ if (node.IsTargetOfAssignment())
+ return;
+
+ CompleteOmittedExpressions(node);
+ ExpandComplexSlicing(node);
+ }
+
+ void CompleteOmittedExpressions(SlicingExpression node)
+ {
+ foreach (var index in node.Indices.Where(slice => slice.Begin == OmittedExpression.Default))
+ index.Begin = CodeBuilder.CreateIntegerLiteral(0);
+ }
+
+ private void ExpandComplexSlicing(SlicingExpression node)
+ {
+ var targetType = GetExpressionType(node.Target);
+ if (IsString(targetType))
+ BindComplexStringSlicing(node);
+ else if (IsList(targetType))
+ BindComplexListSlicing(node);
+ else if (targetType.IsArray)
+ BindComplexArraySlicing(node);
+ else
+ NotImplemented(node, "complex slicing for anything but lists, arrays and strings");
+ }
+
+ private bool IsString(IType targetType)
+ {
+ return TypeSystemServices.StringType == targetType;
+ }
+
+ private bool IsList(IType targetType)
+ {
+ return IsAssignableFrom(TypeSystemServices.ListType, targetType);
+ }
+
+ void BindComplexListSlicing(SlicingExpression node)
+ {
+ var slice = node.Indices[0];
+
+ MethodInvocationExpression mie = null;
+ if (slice.End == null || slice.End == OmittedExpression.Default)
+ {
+ mie = CodeBuilder.CreateMethodInvocation(node.Target, MethodCache.List_GetRange1);
+ mie.Arguments.Add(slice.Begin);
+ }
+ else
+ {
+ mie = CodeBuilder.CreateMethodInvocation(node.Target, MethodCache.List_GetRange2);
+ mie.Arguments.Add(slice.Begin);
+ mie.Arguments.Add(slice.End);
+ }
+ node.ParentNode.Replace(node, mie);
+ }
+
+ void BindComplexArraySlicing(SlicingExpression node)
+ {
+ if (node.Indices.Count > 1)
+ {
+ MethodInvocationExpression mie = null;
+ var collapse = new ArrayLiteralExpression();
+ var ranges = new ArrayLiteralExpression();
+ for (int i = 0; i < node.Indices.Count; i++)
+ {
+ ranges.Items.Add(node.Indices[i].Begin);
+ if (node.Indices[i].End == null ||
+ node.Indices[i].End == OmittedExpression.Default)
+ {
+ var end = new BinaryExpression(BinaryOperatorType.Addition,
+ node.Indices[i].Begin,
+ new IntegerLiteralExpression(1));
+ ranges.Items.Add(end);
+ BindExpressionType(end, GetExpressionType(node.Indices[i].Begin));
+ collapse.Items.Add(new BoolLiteralExpression(true));
+ }
+ else
+ {
+ ranges.Items.Add(node.Indices[i].End);
+ collapse.Items.Add(new BoolLiteralExpression(false));
+ }
+ }
+ mie = CodeBuilder.CreateMethodInvocation(MethodCache.RuntimeServices_GetMultiDimensionalRange1, node.Target, ranges);
+ mie.Arguments.Add(collapse);
+
+ BindExpressionType(ranges, TypeSystemServices.Map(typeof(int[])));
+ BindExpressionType(collapse, TypeSystemServices.Map(typeof(bool[])));
+ node.ParentNode.Replace(node, mie);
+ }
+ else
+ {
+ Slice slice = node.Indices[0];
+ MethodInvocationExpression mie = null;
+
+ if (null == slice.End || slice.End == OmittedExpression.Default)
+ {
+ mie = CodeBuilder.CreateMethodInvocation(MethodCache.RuntimeServices_GetRange1, node.Target, slice.Begin);
+ }
+ else
+ {
+ mie = CodeBuilder.CreateMethodInvocation(MethodCache.RuntimeServices_GetRange2, node.Target, slice.Begin, slice.End);
+ }
+ node.ParentNode.Replace(node, mie);
+ }
+ }
+
+ static bool NeedsNormalization(Expression index)
+ {
+ return index.NodeType != NodeType.IntegerLiteralExpression || ((IntegerLiteralExpression) index).Value < 0;
+ }
+
+ void BindComplexStringSlicing(SlicingExpression node)
+ {
+ var slice = node.Indices[0];
+
+ MethodInvocationExpression mie = null;
+
+ if (null == slice.End || slice.End == OmittedExpression.Default)
+ {
+ if (NeedsNormalization(slice.Begin))
+ {
+ mie = CodeBuilder.CreateEvalInvocation(node.LexicalInfo);
+ mie.ExpressionType = TypeSystemServices.StringType;
+
+ InternalLocal temp = DeclareTempLocal(TypeSystemServices.StringType);
+ mie.Arguments.Add(
+ CodeBuilder.CreateAssignment(
+ CodeBuilder.CreateReference(temp),
+ node.Target));
+
+ mie.Arguments.Add(
+ CodeBuilder.CreateMethodInvocation(
+ CodeBuilder.CreateReference(temp),
+ MethodCache.String_Substring_Int,
+ CodeBuilder.CreateMethodInvocation(
+ MethodCache.RuntimeServices_NormalizeStringIndex,
+ CodeBuilder.CreateReference(temp),
+ slice.Begin)));
+ }
+ else
+ {
+ mie = CodeBuilder.CreateMethodInvocation(node.Target, MethodCache.String_Substring_Int, slice.Begin);
+ }
+ }
+ else
+ {
+ mie = CodeBuilder.CreateMethodInvocation(MethodCache.RuntimeServices_Mid, node.Target, slice.Begin, slice.End);
+ }
+
+ node.ParentNode.Replace(node, mie);
+ }
+
+ static bool IsAssignableFrom(IType expectedType, IType actualType)
+ {
+ return TypeCompatibilityRules.IsAssignableFrom(expectedType, actualType);
+ }
+
+ protected InternalLocal DeclareTempLocal(IType localType)
+ {
+ return CodeBuilder.DeclareTempLocal(CurrentMethod, localType);
+ }
+
+ protected RuntimeMethodCache MethodCache
+ {
+ get { return _methodCache.Instance; }
+ }
+
+ public override void Dispose()
+ {
+ _methodCache = new EnvironmentProvision<RuntimeMethodCache>();
+ base.Dispose();
+ }
+
+ private EnvironmentProvision<RuntimeMethodCache> _methodCache;
+ }
+}
Oops, something went wrong.

0 comments on commit 75796ae

Please sign in to comment.