StringOrCompoundInitializerTranslateWorker.java
package dev.civl.abc.transform.common;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.BiFunction;
import dev.civl.abc.ast.node.IF.NodeFactory;
import dev.civl.abc.ast.node.IF.PairNode;
import dev.civl.abc.ast.node.IF.compound.CompoundInitializerNode;
import dev.civl.abc.ast.node.IF.compound.CompoundLiteralObject;
import dev.civl.abc.ast.node.IF.compound.DesignationNode;
import dev.civl.abc.ast.node.IF.compound.LiteralObject;
import dev.civl.abc.ast.node.IF.compound.ScalarLiteralObject;
import dev.civl.abc.ast.node.IF.declaration.InitializerNode;
import dev.civl.abc.ast.node.IF.declaration.VariableDeclarationNode;
import dev.civl.abc.ast.node.IF.expression.CharacterConstantNode;
import dev.civl.abc.ast.node.IF.expression.ConstantNode;
import dev.civl.abc.ast.node.IF.expression.ExpressionNode;
import dev.civl.abc.ast.node.IF.expression.ExpressionNode.ExpressionKind;
import dev.civl.abc.ast.node.IF.expression.IntegerConstantNode;
import dev.civl.abc.ast.node.IF.expression.OperatorNode;
import dev.civl.abc.ast.node.IF.expression.OperatorNode.Operator;
import dev.civl.abc.ast.node.IF.expression.StringLiteralNode;
import dev.civl.abc.ast.node.IF.statement.BlockItemNode;
import dev.civl.abc.ast.node.IF.statement.DeclarationListNode;
import dev.civl.abc.ast.node.IF.statement.StatementNode;
import dev.civl.abc.ast.node.IF.type.BasicTypeNode;
import dev.civl.abc.ast.node.IF.type.TypeNode;
import dev.civl.abc.ast.type.IF.ArrayType;
import dev.civl.abc.ast.type.IF.Field;
import dev.civl.abc.ast.type.IF.IntegerType;
import dev.civl.abc.ast.type.IF.QualifiedObjectType;
import dev.civl.abc.ast.type.IF.StandardBasicType.BasicTypeKind;
import dev.civl.abc.ast.type.IF.StandardSignedIntegerType.SignedIntKind;
import dev.civl.abc.ast.type.IF.StructureOrUnionType;
import dev.civl.abc.ast.type.IF.Type;
import dev.civl.abc.ast.type.IF.Type.TypeKind;
import dev.civl.abc.ast.type.IF.TypeFactory;
import dev.civl.abc.ast.type.IF.UnqualifiedObjectType;
import dev.civl.abc.ast.value.IF.StringValue;
import dev.civl.abc.ast.value.IF.Value;
import dev.civl.abc.config.IF.Configurations.Language;
import dev.civl.abc.err.IF.ABCRuntimeException;
import dev.civl.abc.token.IF.Source;
import dev.civl.abc.token.IF.StringLiteral;
import dev.civl.abc.util.IF.Pair;
/**
* <p>
* This class translates a {@link CompoundInitializerNode} and an expression,
* which represents the object that is being assigned the value specified by the
* compound initializer, to a sequence of scalar assignments.
* </p>
*
* <p>
* <b>Foe example</b> expression : <code>e : struct</code> ,initializer :
* <code>{a, b, c}</code>, the translation result is
* <code>e.0 = a; e.1 = b; e.2 = c;</code>
* </p>
*
* <p>
* Notes:
* <ul>
* <li>This class <b>ASSUMES</b> that the aggregate object that is associated
* with the compound initializer has been set to have its default value if it
* has or is suppose to be treated as having static storage. [DELETE THIS
* ASSUMPTION, I don't think it is true or necessary --sfs]</li>
*
* <li>This class guarantees that the output contains no compound initializer
* node <b>EXCEPT FOR</b> $domain initializers</li>
*
* <li>TODO: this worker currently is used by the {@link SideEffectRemover} due
* to the fact that the side-effect remover has a mature structure for
* traversing a tree and factoring statements from expressions. Semantically,
* this is not a "side-effect removing" transformation, so maybe it should go
* elsewhere. [or maybe the side-effect remover should be renamed "code
* normalizer" or something like that --sfs]</li>
* </ul>
* </p>
*
* @author ziqing
*/
public class StringOrCompoundInitializerTranslateWorker {
/**
* <p>
* A complete access path <code>AP</code> is represented as an array of
* {@link AccessPathNode}s. A {@link AccessPathNode} represents either a field
* access or subscript operation.
*/
public record AccessPathNode(Operator operator, Field field, Integer arrayIndex) {
public enum Operator {
// The field access operator that applies to a (sub-)object and an
// IdentifierExpressionNode
DOT,
// The subscript operator that applies to a (sub-)object and an ExpressionNode
SUBSCRIPT
}
AccessPathNode(Field field) {
this(Operator.DOT, field, null);
assert field != null;
}
AccessPathNode(int index) {
this(Operator.SUBSCRIPT, null, index);
}
}
private NodeFactory nodeFactory;
private TypeFactory typeFactory;
private IntegerType intType;
private BiFunction<Source, Type, VariableDeclarationNode> tmpVarCreator;
private BiFunction<Source, Type, TypeNode> typeNodeCreator;
private Language language;
// constructor
StringOrCompoundInitializerTranslateWorker(NodeFactory nodeFactory,
BiFunction<Source, Type, VariableDeclarationNode> tmpVarCreator,
BiFunction<Source, Type, TypeNode> typeNodeCreator, Language language) {
this.nodeFactory = nodeFactory;
this.typeFactory = nodeFactory.typeFactory();
this.intType = typeFactory.signedIntegerType(SignedIntKind.INT);
this.tmpVarCreator = tmpVarCreator;
this.typeNodeCreator = typeNodeCreator;
this.language = language;
}
/**
* <p>
* translates a {@link CompoundInitializerNode} and an expression, which
* represents the object that is associated to the compound initializer, to a
* sequence of assignments. Note that the assignments are NOT guaranteed
* side-effect free.
* </p>
*
* @param compound a compound initializer
* @param objExpr an expression that represents the object that will be
* initialized by the compound initializer
* @return a list of assignments which deliver the same functionality as the
* compound initializer
*/
List<BlockItemNode> translateCompoundInitializer(CompoundInitializerNode compound, ExpressionNode objExpr) {
LiteralObject lt = compound.getLiteralObject();
return translateInitializerWorker(objExpr, lt);
}
/**
* <p>
* Given an char array expression and a string literal, translates the string
* literal to a sequence of assignments to the array. Note that the assignments
* are NOT guaranteed side-effect free.
* </p>
*
* <p>
* Assuming the array has assigned default value '0's
* </p>
*
* @param stringLit a string literal node
* @param lhs an expression node of array of char type
* @return a list of assignment expressions
*/
List<BlockItemNode> translateStringLiteralInitializer(StringLiteralNode stringLitNode, ExpressionNode lhs) {
StringValue strVal = stringLitNode.getConstantValue();
StringLiteral strLit = strVal.getLiteral();
return translateStringLiteralInitializerWorker(lhs, stringLitNode.getType(), strLit, stringLitNode.getSource());
}
/**
* Translates the initialization 'lhs = litObj' to a sequence of scalar-level
* assignments, breaking CompoundInitializers down to scalar-level.
*
* @param lhs the left-hand side of the initialization
* @param litObj the {@link LiteralObject} representing the initializer value
* @return a sequence of scalar-level assignments that is equivalent to the
* original initialization.
*/
private List<BlockItemNode> translateInitializerWorker(ExpressionNode lhs, LiteralObject litObj) {
ArrayList<Pair<ArrayList<AccessPathNode>, ExpressionNode>> pairs = getAsAccessPathExpressionPairs(litObj);
List<BlockItemNode> result = new ArrayList<>(pairs.size());
for (var pair : pairs) {
var accessPath = pair.left;
ExpressionNode init = pair.right;
ExpressionNode lhsSubObj = lhs;
Type lhsSubObjType = litObj.getType();
for (AccessPathNode apNode : accessPath) {
Pair<ExpressionNode, Type> lhsSubObjAndType = applyAccessPathNode(lhsSubObj, lhsSubObjType, apNode);
// Note that applyAccessPathNode-returned ExpressionNodes may have getType() be
// null.
lhsSubObj = lhsSubObjAndType.left;
lhsSubObjType = lhsSubObjAndType.right;
}
StringLiteral initAsStringLiteral = null;
if (init.expressionKind() == ExpressionKind.CONSTANT) {
Value val = ((ConstantNode) init).getConstantValue();
// if (val != null && val.getType().kind() == TypeKind.BASIC)
// if (val.isZero() == Answer.YES)
// return results; [disagree --sfs]
if (val instanceof StringValue)
initAsStringLiteral = ((StringValue) val).getLiteral();
}
if (initAsStringLiteral != null)
result.addAll(translateStringLiteralInitializerWorker(lhsSubObj.copyWithTypes(), lhsSubObjType,
initAsStringLiteral, init.getSource()));
else {
OperatorNode assignNode = nodeFactory.newOperatorNode(init.getSource(), Operator.ASSIGN,
lhsSubObj.copyWithTypes(), init.copyWithTypes());
assignNode.setInitialType(lhsSubObjType);
result.add(nodeFactory.newExpressionStatementNode(assignNode));
}
}
return result;
}
/**
* Converts a {@link LiteralObject} to a sequence of access-path and
* scalar-level expression pairs. If the LiteralObject is scalar, this function
* returns a pair consists of an empty access-path and
* {@link ScalarLiteralObject#getExpression()}. Otherwise,
* {@link CompoundLiteralObject} is naturally decomposed.
*
* <b>Note that anonymous fields are ignored.</b>
*/
static public ArrayList<Pair<ArrayList<AccessPathNode>, ExpressionNode>> getAsAccessPathExpressionPairs(
LiteralObject litObj) {
ArrayList<Pair<ArrayList<AccessPathNode>, ExpressionNode>> result = new ArrayList<>();
getAsAccessPathExpressionPairsWorker(litObj, result, new ArrayList<>());
return result;
}
static private void getAsAccessPathExpressionPairsWorker(LiteralObject litObj,
ArrayList<Pair<ArrayList<AccessPathNode>, ExpressionNode>> result, ArrayList<AccessPathNode> currentAP) {
if (litObj instanceof CompoundLiteralObject) {
// compound:
CompoundLiteralObject cLitObj = (CompoundLiteralObject) litObj;
int size = cLitObj.size();
Type type = cLitObj.getType().ignoreQualifiersAtomic();
if (type.kind() == TypeKind.ARRAY) {
for (int i = 0; i < size; i++) {
var ap = new ArrayList<>(currentAP);
ap.add(new AccessPathNode(i));
getAsAccessPathExpressionPairsWorker(cLitObj.get(i), result, ap);
}
} else if (type.kind() == TypeKind.STRUCTURE_OR_UNION) {
StructureOrUnionType sType = (StructureOrUnionType) type;
for (int i = 0; i < size; i++) {
LiteralObject val = cLitObj.get(i);
if (val == null)
continue;
var ap = new ArrayList<>(currentAP);
Field field = sType.getField(i);
// For anonymous fields. it's safe to ignore if it has a scalar type:
if (field.isAnonymous() && field.getType().isScalar())
continue;
ap.add(new AccessPathNode(field));
getAsAccessPathExpressionPairsWorker(val, result, ap);
}
}
} else {
// scalar (including $domain type):
result.add(new Pair<>(currentAP, ((ScalarLiteralObject) litObj).getExpression()));
}
}
/**
* Applies an {@link AccessPathNode} to a base expression and generates a new
* AST node representing a sub-object of the base referred by the
* AccessPathNode.
*
* @param base the ASTNode representing the base expression
* @param baseType the Type of the base expression (since the base expression is
* not required to be an original node in AST, the node itself
* may not carry the type)
* @param apNode the {@link AccessPathNode}
*/
private Pair<ExpressionNode, Type> applyAccessPathNode(ExpressionNode base, Type baseType, AccessPathNode apNode) {
Source source = base.getSource();
if (apNode.operator() == AccessPathNode.Operator.DOT) {
Field field = apNode.field();
baseType = field.getType();
if (field.isAnonymous())
return new Pair<>(base, baseType);
base = nodeFactory.newDotNode(source, base.copyWithTypes(),
nodeFactory.newIdentifierNode(source, field.getName()));
} else {
IntegerConstantNode idxNode = nodeFactory.newIntConstantNode(source, apNode.arrayIndex());
idxNode.setInitialType(intType);
base = nodeFactory.newOperatorNode(source, Operator.SUBSCRIPT, base.copyWithTypes(), idxNode);
baseType = baseType.ignoreQualifiersAtomic();
assert baseType.kind() == TypeKind.ARRAY;
baseType = ((ArrayType) baseType).getElementType();
}
base.setInitialType(baseType);
return new Pair<>(base, baseType);
}
/**
* <p>
* Translates a string literal initialization. There are two cases:
* <ul>
* <li>If the initialization has the form:
* <code>char * obj = string-literal</code>, the translation will be as follows:
* <code>
* char tmp[size(string-literal)];
*
* // replacing "obj" with tmp then recursively call this method ...
* obj = tmp;
* </code></li>
* <li>If the initialization has the form:
* <code>char obj[c] = string-literal</code>, where <code>c</code> is either a
* fixed length or absent, the translation will be as follows: <code>
* obj[0] = string-literal[0];
* obj[1] = string-literal[1];
* ...
* </code>, where <code>string-literal[i]</code> means the i-th character in the
* given string literal.</li>
* </ul>
*
* </p>
*
* @param obj the object that will be initialized, suppose to
* either have array-of-char type or pointer-to-char
* type but this node may not have been assigned type
* @param stringLiteralType the type of the string literal expression node. The
* type of this expression after applying all
* conversions reflects the type of the "obj"
* @param strlit the {@link StringLiteral} value of the string
* literal expression
* @param strLitSource the {@link Source} of the string literal expression
* @return a list of translated statements
*/
private List<BlockItemNode> translateStringLiteralInitializerWorker(ExpressionNode obj, Type stringLiteralType,
StringLiteral strlit, Source strLitSource) {
List<BlockItemNode> results = new LinkedList<>();
ExpressionNode newInit;
// at this point, "obj" may not have type but the type of the literal
// object reflects whether the object has array-of-char type or
// pointer-to-char type:
if (stringLiteralType.isScalar()) {
ArrayType charArrayType = typeFactory.arrayType(typeFactory.basicType(BasicTypeKind.CHAR),
nodeFactory.getValueFactory().integerValue(intType, strlit.getNumCharacters()));
// TODO: this temp var needs to go global!
VariableDeclarationNode tmpVarDecl = tmpVarCreator.apply(strLitSource, charArrayType);
results.add(tmpVarDecl);
newInit = nodeFactory.newIdentifierExpressionNode(strLitSource, tmpVarDecl.getIdentifier().copy());
newInit.setInitialType(charArrayType);
results.addAll(translateStringLiteralInitializerWorker(newInit, charArrayType, strlit, strLitSource));
OperatorNode assignNode = nodeFactory.newOperatorNode(newInit.getSource(), Operator.ASSIGN,
obj.copyWithTypes(), newInit.copyWithTypes());
assignNode.setInitialType(obj.getType());
results.add(nodeFactory.newExpressionStatementNode(assignNode));
} else {
// TODO: LEFT OFF HERE FILLING IN TYPES
assert stringLiteralType.kind() == TypeKind.ARRAY;
Type charType = ((ArrayType) stringLiteralType).getElementType();
StringLiteral strLit = strlit;
int size = strLit.getNumCharacters();
for (int i = 0; i < size; i++) {
IntegerConstantNode idxNode = nodeFactory.newIntConstantNode(strLitSource, i);
idxNode.setInitialType(intType);
ExpressionNode subObj = nodeFactory.newOperatorNode(strLitSource, Operator.SUBSCRIPT,
obj.copyWithTypes(), idxNode);
subObj.setInitialType(charType);
CharacterConstantNode charNode = nodeFactory.newCharacterConstantNode(strLitSource,
strLit.getCharacter(i).rawString(), strLit.getCharacter(i));
charNode.setInitialType(charType);
newInit = nodeFactory.newOperatorNode(strLitSource, Operator.ASSIGN, subObj, charNode);
newInit.setInitialType(charType);
results.add(nodeFactory.newExpressionStatementNode(newInit));
}
}
return results;
}
/* *************** methods for setting default values **************** */
/**
* <p>
* Assigns a default value to an object as if the object has static storage
* </p>
*
* @param obj the object that will be assigned
* @param objType the type of the object
* @return a triple that either 1) only contains "after" statements (i.e. no
* expression, no before statements); 2) before statements, translated
* initializer and after statements.
*/
ExprTriple defaultValues(ExpressionNode obj, Type objType) {
Source source = obj.getSource();
// de-qualifiers:
if (objType.kind() == TypeKind.QUALIFIED)
objType = ((QualifiedObjectType) objType).getBaseType();
if (objType.isScalar())
return new ExprTriple(defaultValueOfScalarType(objType, source));
else {
if (objType.kind() == TypeKind.ARRAY)
return defaultValuesToArray(obj, (ArrayType) objType, obj.getSource());
else if (objType.kind() == TypeKind.STRUCTURE_OR_UNION) {
ExprTriple result = new ExprTriple(null);
result.addAllAfter(defaultValuesToStructOrUnion(obj, (StructureOrUnionType) objType));
return result;
} else {
TypeKind kind = objType.kind();
if (kind == TypeKind.DOMAIN || kind == TypeKind.RANGE) {
ConstantNode zero = nodeFactory.newIntConstantNode(source, 0);
zero.setInitialType(intType);
ExpressionNode r = nodeFactory.newRegularRangeNode(source, zero, zero.copyWithTypes());
r.setInitialType(typeFactory.rangeType());
if (kind == TypeKind.DOMAIN) {
List<PairNode<DesignationNode, InitializerNode>> initList = new LinkedList<>();
TypeNode domainTypeNode = nodeFactory.newDomainTypeNode(source);
initList.add(nodeFactory.newPairNode(source, null, r));
r = nodeFactory.newCompoundLiteralNode(source, domainTypeNode,
nodeFactory.newCompoundInitializerNode(source, initList));
r.setInitialType(objType);
}
return new ExprTriple(r);
}
throw new ABCRuntimeException("Unexpected aggregate type kind: " + kind);
}
}
}
/**
* <p>
* This method returns two kinds of default values for arrays (as if the arrays
* have static storage):
* <ul>
* <li>If the current language is CIVL-C language, default values of arrays are
* array lambdas, which can be used to initialize array with either constant or
* variable length.</li>
* <li>Otherwise, to conform C11 standard, no initializer expression but a
* sequence of assignments will be given for initialization of arrays with
* constant length. Attempts to initialize variable size array will be
* reported.</li>
* </ul>
* </p>
*
* @param array an array object
* @param arrType the array type of the object
* @return triple that contains an array lambda expression that is representing
* the default value with a sequence of "before" statements; no "after"
* statement.
*/
private ExprTriple defaultValuesToArray(ExpressionNode arr, ArrayType arrType, Source source) {
if (language == Language.CIVL_C)
return defaultValuesToArrayLambda(arrType, source);
else
return defaultValuesToArrayStrict(arr, arrType, source);
}
/**
* worker method of {@link #defaultValuesToArray(ArrayType, Source)} for
* creating array lambda kind default value
*/
private ExprTriple defaultValuesToArrayLambda(ArrayType arrType, Source source) {
ExprTriple result;
Type baseType = arrType;
ExpressionNode elementDefaultVal;
int dims = arrType.getDimension();
List<VariableDeclarationNode> varDecls = new LinkedList<>();
List<BlockItemNode> before = new LinkedList<BlockItemNode>();
for (int i = 0; i < dims; i++) {
baseType = ((ArrayType) baseType).getElementType();
BasicTypeNode intTypeNode = nodeFactory.newBasicTypeNode(source, BasicTypeKind.INT);
intTypeNode.setType(intType);
varDecls.add(nodeFactory.newVariableDeclarationNode(source, nodeFactory.newIdentifierNode(source, "i" + i),
intTypeNode));
}
if (!baseType.isScalar()) {
VariableDeclarationNode tmpVar = tmpVarCreator.apply(source, baseType);
// tmpVarCreator sets the Type of the new type node
ExprTriple subResult;
elementDefaultVal = nodeFactory.newIdentifierExpressionNode(source, tmpVar.getIdentifier().copy());
elementDefaultVal.setInitialType(baseType);
subResult = defaultValues(elementDefaultVal, baseType);
if (subResult != null) {
before.addAll(subResult.getBefore());
before.add(tmpVar);
if (subResult.getNode() != null)
tmpVar.setInitializer(subResult.getNode());
before.addAll(subResult.getAfter());
} else
before.add(tmpVar);
} else
elementDefaultVal = defaultValueOfScalarType((UnqualifiedObjectType) baseType, source);
ExpressionNode arrLambda = nodeFactory.newArrayLambdaNode(source, typeNodeCreator.apply(source, arrType),
varDecls, null, elementDefaultVal.copyWithTypes());
arrLambda.setInitialType(arrType);
result = new ExprTriple(arrLambda);
result.addAllBefore(before);
return result;
}
/**
* worker method of {@link #defaultValuesToArray(ArrayType, Source)} for
* creating default value strictly conforming C11 standard
*/
private ExprTriple defaultValuesToArrayStrict(ExpressionNode arr, ArrayType arrType, Source source) {
assert !arrType.isVariableLengthArrayType() : "Initializer cannot be used to initialize variable "
+ "length array in C language.\nNote that CIVL-C programs, "
+ "whose source files end with suffix \".cvl\", support such feature.";
assert arrType.isComplete();
Type elementType = arrType.getElementType();
ExpressionNode elementDefaultVal;
List<BlockItemNode> result = new LinkedList<>();
if (!elementType.isScalar()) {
VariableDeclarationNode tmpVar = tmpVarCreator.apply(source, elementType);
ExprTriple subResult;
elementDefaultVal = nodeFactory.newIdentifierExpressionNode(source, tmpVar.getIdentifier().copy());
elementDefaultVal.setInitialType(elementType);
subResult = defaultValues(elementDefaultVal, elementType);
assert subResult.getNode() == null;
assert subResult.getBefore().isEmpty();
result.add(tmpVar);
result.addAll(subResult.getAfter());
} else {
elementDefaultVal = nodeFactory.newIntConstantNode(source, 0);
elementDefaultVal.setInitialType(intType);
}
// make a for-loop to initialize the array:
int size = arrType.getConstantSize().getIntegerValue().intValueExact();
ExpressionNode sizeNode = nodeFactory.newIntConstantNode(source, size);
sizeNode.setInitialType(intType);
// TODO: should sizeNode have type size_t?
VariableDeclarationNode decl = tmpVarCreator.apply(source, intType);
List<VariableDeclarationNode> loopVarDecls = new LinkedList<>();
DeclarationListNode forLoopInit;
ExpressionNode forLoopCond, forLoopId, forLoopInc;
StatementNode forLoopBody;
IntegerConstantNode zeroNode = nodeFactory.newIntConstantNode(source, 0);
zeroNode.setInitialType(intType);
decl.setInitializer(zeroNode);
loopVarDecls.add(decl);
forLoopId = nodeFactory.newIdentifierExpressionNode(source, decl.getIdentifier().copy());
forLoopId.setInitialType(intType);
forLoopInit = nodeFactory.newForLoopInitializerNode(source, loopVarDecls);
forLoopCond = nodeFactory.newOperatorNode(source, Operator.LT, forLoopId, sizeNode);
forLoopCond.setInitialType(intType);
IntegerConstantNode oneNode = nodeFactory.newIntConstantNode(source, 1);
oneNode.setInitialType(intType);
forLoopInc = nodeFactory.newOperatorNode(source, Operator.PLUS, forLoopId.copyWithTypes(), oneNode);
forLoopInc.setInitialType(intType);
forLoopInc = nodeFactory.newOperatorNode(source, Operator.ASSIGN, forLoopId.copyWithTypes(), forLoopInc);
forLoopInc.setInitialType(intType);
OperatorNode subscriptNode = nodeFactory.newOperatorNode(source, Operator.SUBSCRIPT, arr.copyWithTypes(),
forLoopId.copyWithTypes());
subscriptNode.setInitialType(elementType);
OperatorNode assignNode = nodeFactory.newOperatorNode(source, Operator.ASSIGN, subscriptNode,
elementDefaultVal.copyWithTypes());
assignNode.setInitialType(elementType);
forLoopBody = nodeFactory.newExpressionStatementNode(assignNode);
result.add(nodeFactory.newForLoopNode(source, forLoopInit, forLoopCond, forLoopInc, forLoopBody, null));
ExprTriple ret = new ExprTriple(null);
ret.setAfter(result);
return ret;
}
/**
* <p>
* Assigns a default value to an struct or union object as if the object has
* static storage.
* </p>
*
* @param obj a struct or union object
* @param objType the type of the struct or union object
* @return a list of assignment statements that goes "after" the first
* appearance of the given object
*/
private List<BlockItemNode> defaultValuesToStructOrUnion(ExpressionNode obj, StructureOrUnionType objType) {
int numFields = objType.getNumFields();
Source source = obj.getSource();
List<BlockItemNode> results = new LinkedList<>();
if (objType.isUnion())
numFields = 1;
for (int i = 0; i < numFields; i++) {
Field field = objType.getField(i);
ExpressionNode fieldObj;
String fieldName = field.getName();
/*
* C11 Section 6.7.9 semantics 9: Except where explicitly stated otherwise, for
* the purposes of this subclause unnamed members of objects of structure and
* union type do not participate in initialization. Unnamed members of structure
* objects have indeterminate value even after initialization.
*/
if (fieldName == null)
continue;
fieldObj = nodeFactory.newDotNode(source, obj.copyWithTypes(),
nodeFactory.newIdentifierNode(source, fieldName));
Type fieldType = objType.getField(i).getType();
fieldObj.setInitialType(fieldType);
ExprTriple subResult = defaultValues(fieldObj, fieldType);
if (subResult != null) {
results.addAll(subResult.getBefore());
results.addAll(subResult.getAfter());
if (subResult.getNode() != null) {
OperatorNode assignNode = nodeFactory.newOperatorNode(source, Operator.ASSIGN,
fieldObj.copyWithTypes(), subResult.getNode());
assignNode.setInitialType(fieldType);
results.add(nodeFactory.newExpressionStatementNode(assignNode));
}
}
}
return results;
}
/**
* <p>
* returns an expression that represents default value of a scalar type object
* as if the object has static storage
* </p>
*
* @param scalarType the scalar type
* @param source the {@link Source} that is associated to the returned
* expression
* @return an expression that represents default value of a scalar type object
* as if the object has static storage
*/
private ExpressionNode defaultValueOfScalarType(Type scalarType, Source source) {
ExpressionNode result;
switch (scalarType.kind()) {
case BASIC:
case ENUMERATION:
case OTHER_INTEGER:
result = nodeFactory.newIntConstantNode(source, 0);
break;
case POINTER:
case RANGE:
case SCOPE: {
IntegerConstantNode zeroNode = nodeFactory.newIntConstantNode(source, 0);
zeroNode.setInitialType(intType);
result = nodeFactory.newCastNode(source, typeNodeCreator.apply(source, scalarType), zeroNode);
break;
}
case PROCESS:
result = nodeFactory.newProcnullNode(source);
break;
default:
throw new ABCRuntimeException(
"unexpected scalar type kind for inferring its default value : " + scalarType.kind());
}
result.setInitialType(scalarType);
return result;
}
}