protected static void AddInitializationTo(ICollection<Statement> statements, Expression source, Expression target, TypeExpression targetType, BlockStatement containingBlock) { VccInitializer initializer = source as VccInitializer; if (initializer != null) { VccArrayTypeExpression arrayType = initializer.arrayTypeExpression ?? targetType as VccArrayTypeExpression; if (arrayType != null) { initializer.AddInitializingElementAssignmentsTo(statements, target, arrayType); } else if (initializer.IsOfStructuredType) { VccStructuredTypeDeclaration structType = initializer.GetStructuredTypeDecl(); if (structType != null) initializer.AddInitializingFieldAssignmentsTo(statements, target, structType); } } else { // It is not an initializer // If the expression is a string and the target is a char array, in which case we treat it as an array initializer. VccByteStringLiteral stringLiteral = source as VccByteStringLiteral; VccArrayTypeExpression arrayType = targetType as VccArrayTypeExpression; if (stringLiteral != null && arrayType != null) { string val = stringLiteral.Value as string; if (val != null) { if (arrayType.Size == null) { CompileTimeConstant ctc = new CompileTimeConstant(val.Length + 1, stringLiteral.SourceLocation); ctc.SetContainingExpression(stringLiteral); arrayType.ResetSizeWhenProvidedByInitializer(ctc); } int size = arrayType.SizeAsInt32; VccInitializer newInitializer = VccInitializer.fromStringWithPatchedZeros(val, size, stringLiteral); // No need to assign the array type expression field, because we know the element type is char. if (newInitializer != null) { newInitializer.AddInitializingElementAssignmentsTo(statements, target, arrayType); } } } else { // If the target is a union, we will try to treat the constant as an initializer. CompileTimeConstant ctc = source as CompileTimeConstant; VccUnionDeclaration unionType = MiniResolve(containingBlock.ContainingNamespaceDeclaration, targetType as VccNamedTypeExpression) as VccUnionDeclaration; if (ctc != null && unionType != null) { List<Expression> exprs = new List<Expression> {ctc}; VccInitializer newInitializer = new VccInitializer(exprs, false, source.SourceLocation); newInitializer.SetContainingBlock(containingBlock); newInitializer.AddInitializingFieldAssignmentsTo(statements, target, unionType); } else { // otherwise, generate an assignment. ExpressionStatement elementAssignment = new ExpressionStatement(new Assignment(new TargetExpression(target), source, source.SourceLocation)); elementAssignment.SetContainingBlock(containingBlock); statements.Add(elementAssignment); } } } }
/// <summary> /// Convert a string to an initializer. "12" will be turned to {'1','2'}. Zeros will /// be patched if the length of the string is smaller than size. If the length of the /// string is greater than size, then only the first size of chars will be converted, /// unless if size is zero or less, in which case, the count number of chars will be /// converted. /// </summary> /// <param name="initialValue">The initial string</param> /// <param name="size">The target size</param> /// <param name="parent">The parent expression</param> /// <returns></returns> public static VccInitializer fromStringWithPatchedZeros(string initialValue, int size, Expression parent) { if (initialValue == null) return null; int count = initialValue.Length; if (size <= 0) size = count; char[] charArr = initialValue.ToCharArray(); List<Expression> exprs = new List<Expression>(); VccInitializer result = new VccInitializer(exprs, false, SourceDummy.SourceLocation); for (uint i = 0; i < size; i++) { if (i < count) { sbyte val = (sbyte)charArr[i]; Expression ch = new CompileTimeConstant(val, parent.SourceLocation); ch.SetContainingExpression(parent); exprs.Add(ch); } // If we dont have enough element, we patch zero. It is intentional that no '\0' is added // if size == count. else { Expression zeroPatch = new CompileTimeConstant(0, parent.SourceLocation); zeroPatch.SetContainingExpression(parent); exprs.Add(zeroPatch); } } result.SetContainingExpression(parent); return result; }
internal override void AddInitializingElementAssignmentsTo(ICollection<Statement> statements, Expression array, VccArrayTypeExpression/*?*/ arrTypeExp) { TypeExpression elemTypeExp = null; if (arrTypeExp != null) { elemTypeExp = arrTypeExp.ElementType; } // If we have a multiple dimensional array, and the element is not a VccInitializer, // then we will compute the number of constants needed for array[i], say, x, and bundle // x constant together for array[i], which may be further an array, in which case, the above // process repeat. int i = 0, n = this.expressions.Count; int lengthForFirstDimensionIfNotProvided = 0; bool elementIsVccInitializer = (n == 0) ? true : expressions[0] is VccInitializer; int rownum = 0; // For multidimensional array, // i may be increased by the total number of embedded array elements per loop, rownum always by 1. while (i < n){ Expression arrayLine = array; List<Expression> indices = new List<Expression>(1) {new CompileTimeConstant(rownum++, true, SourceDummy.SourceLocation)}; VccIndexer element = new VccIndexer(arrayLine, indices.AsReadOnly(), SourceDummy.SourceLocation); // Construct the initial value for one element of the array. Expression/*?*/ initialValueForOneElement = null; int sizeOfEmbeddedArrays = arrTypeExp.SizeOfEmbeddedArrays; VccArrayTypeExpression embeddedArrayType = elemTypeExp as VccArrayTypeExpression; //^ assert sizeOfEmbeddedArrays >=0; // TODO: C doesnt allow sizeOfEmbeddedArrays to be zero, in which case we should report an error if (sizeOfEmbeddedArrays ==0 || elementIsVccInitializer || embeddedArrayType == null) { initialValueForOneElement = this.expressions[i++]; } else { List<Expression> exprs = new List<Expression>(sizeOfEmbeddedArrays); for (int j = 0; j < sizeOfEmbeddedArrays; j++) { exprs.Add(i < n ? expressions[i++] : new CompileTimeConstant(0, this.SourceLocation)); } initialValueForOneElement = new VccInitializer(exprs, false, this.SourceLocation); } //^ assert initialValueForOneElement != null; AddInitializationTo(statements, initialValueForOneElement, element, elemTypeExp, this.ContainingBlock); lengthForFirstDimensionIfNotProvided++; } // In C, it is possible to initialize an array when its first dimension's length is not // specified, in which case, the initializer provides information of the length. if (arrTypeExp.Size != null) { arrTypeExp.ResetSizeWhenProvidedByInitializer(new CompileTimeConstant(lengthForFirstDimensionIfNotProvided, arrTypeExp.SourceLocation)); } }
//^ requires template.ContainingBlock != containingBlock; //^ ensures this.containingBlock == containingBlock; /// <summary> /// A copy constructor that allocates an instance that is the same as the given template, except for its containing block. /// </summary> /// <param name="containingBlock">A new value for containing block. This replaces template.ContainingBlock in the resulting copy of template.</param> /// <param name="template">The template to copy.</param> private VccInitializer(BlockStatement containingBlock, VccInitializer template) : base(containingBlock, template) { this.expressions = new List<Expression>(template.expressions.Count); foreach (var expr in template.expressions) this.expressions.Add(expr.MakeCopyFor(containingBlock)); }