Skip to content

Commit

Permalink
Load variable type info from DDMs (#352)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusAmshove authored Aug 15, 2023
2 parents cfbb1d3 + a1dcc8f commit 916a8ba
Show file tree
Hide file tree
Showing 14 changed files with 482 additions and 41 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/gradle-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:
with:
fetch-depth: 0

- name: Set up JDK 11
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 11
java-version: 17

- name: Grant execute permission for gradlew
run: chmod +x gradlew
Expand All @@ -42,10 +42,10 @@ jobs:
with:
fetch-depth: 0

- name: Set up JDK 11
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 11
java-version: 17

- name: Cache SonarCloud packages
uses: actions/cache@v2
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ jobs:
with:
fetch-depth: 0

- name: Set up JDK 11
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 11
java-version: 17

- name: Grant execute permission for gradlew
run: chmod +x gradlew
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sonar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ jobs:
git checkout ${{ github.event.workflow_run.head_branch }}
git clean -ffdx && git reset --hard HEAD
- name: Set up JDK 11
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: 11
java-version: 17
distribution: 'temurin'

- name: SonarCloud Scan on PR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public non-sealed interface IVariableNode extends IReferencableNode, IParameterD

default boolean isArray()
{
return dimensions() != null && dimensions().size() > 0;
var dimensions = dimensions();
return dimensions != null && !dimensions.isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1224,11 +1224,6 @@ private void addTargetToRedefine(Iterable<IVariableNode> possibleVariables, Rede

private void checkRedefineLength(IRedefinitionNode redefinitionNode)
{
if (redefinitionNode.isInView())
{
return;
}

var target = redefinitionNode.target();

if (target instanceof ITypedVariableNode typedTarget && typedTarget.type() == null)
Expand Down Expand Up @@ -1302,10 +1297,7 @@ private int calculateVariableLengthInBytes(IVariableNode target)
var groupLength = 0;
for (var member : groupNode.variables())
{
if (!member.isInView())
{
groupLength += calculateVariableLengthInBytes(member);
}
groupLength += calculateVariableLengthInBytes(member);
}

return groupLength;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,20 @@ public static ParserDiagnostic unresolvedReference(ITokenNode node)
);
}

public static ParserDiagnostic unresolvedDdmField(ITokenNode node)
{
return unresolvedDdmField(node, node.token().symbolName());
}

public static ParserDiagnostic unresolvedDdmField(ITokenNode node, String fieldName)
{
return ParserDiagnostic.create(
"Unresolved DDM field: %s".formatted(fieldName),
node.token(),
ParserError.UNRESOLVED_REFERENCE
);
}

public static ParserDiagnostic arrayDimensionMustBeConstOrInitialized(ITokenNode token)
{
return ParserDiagnostic.create(
Expand Down Expand Up @@ -321,6 +335,15 @@ public static IDiagnostic typeCantHaveLength(ITypedVariableNode typeNode, int...
);
}

public static IDiagnostic unresolvedDdm(SyntaxToken token)
{
return ParserDiagnostic.create(
"Could not resolve DDM %s".formatted(token.symbolName()),
token,
ParserError.UNRESOLVED_IMPORT
);
}

public static IDiagnostic unresolvedExternalModule(SyntaxToken token)
{
return ParserDiagnostic.create(
Expand Down
143 changes: 133 additions & 10 deletions libs/natparse/src/main/java/org/amshove/natparse/parsing/ViewParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
import org.amshove.natparse.natural.DataFormat;
import org.amshove.natparse.natural.IArrayDimension;
import org.amshove.natparse.natural.ITokenNode;
import org.amshove.natparse.natural.ddm.FieldType;
import org.amshove.natparse.natural.ddm.IGroupField;

import java.util.Map;

class ViewParser extends AbstractParser<ViewNode>
{

private final Map<String, VariableNode> declaredVariables;
private ViewNode view;

ViewParser(IModuleProvider moduleProvider, Map<String, VariableNode> declaredVariables)
{
Expand All @@ -31,7 +34,7 @@ protected ViewNode parseInternal()
var identifierNode = consumeMandatoryIdentifierTokenNode(viewVariable);
viewVariable.setDeclaration(identifierNode);

var view = new ViewNode(viewVariable);
view = new ViewNode(viewVariable);

consumeMandatory(view, SyntaxKind.VIEW);
consumeOptionally(view, SyntaxKind.OF);
Expand All @@ -43,13 +46,17 @@ protected ViewNode parseInternal()
{
var ddm = moduleProvider.findDdm(targetDdm.symbolName());
view.setDdm(ddm);
if (ddm == null && !targetDdm.symbolName().startsWith("&"))
{
report(ParserErrors.unresolvedDdm(targetDdm));
}
}

while (peekKind(SyntaxKind.NUMBER_LITERAL) && peek().intValue() > view.level())
{
try
{
view.addVariable(variable());
view.addVariable(variable(null));
}
catch (ParseError e)
{
Expand All @@ -69,7 +76,7 @@ protected ViewNode parseInternal()
}
}

private VariableNode variable() throws ParseError
private VariableNode variable(GroupNode enclosingGroup) throws ParseError
{
var variable = new VariableNode();
var level = consumeMandatory(variable, SyntaxKind.NUMBER_LITERAL);
Expand Down Expand Up @@ -98,7 +105,7 @@ private VariableNode variable() throws ParseError
if (peek().kind() == SyntaxKind.NUMBER_LITERAL || (peek().kind().isIdentifier() && isVariableDeclared(peek().symbolName())))
{
addArrayDimensions(variable);
var typedDdmArrayVariable = typedVariableFromDdm(variable);
var typedDdmArrayVariable = typedVariableFromDdm(variable, enclosingGroup);
consumeMandatory(typedDdmArrayVariable, SyntaxKind.RPAREN);
return typedDdmArrayVariable;
}
Expand All @@ -111,7 +118,7 @@ private VariableNode variable() throws ParseError
return group(variable);
}

return typedVariableFromDdm(variable);
return typedVariableFromDdm(variable, enclosingGroup);
}

private TypedVariableNode typedVariable(VariableNode variable) throws ParseError
Expand Down Expand Up @@ -200,29 +207,145 @@ private GroupNode group(VariableNode variable) throws ParseError
}
}

var nestedVariable = variable();
var nestedVariable = variable(group);
group.addVariable(nestedVariable);
}

if (group.variables().size() == 0)
if (group.variables().isEmpty())
{
report(ParserErrors.emptyGroupVariable(group));
}

return group;
}

private VariableNode typedVariableFromDdm(VariableNode variable)
// This is used when there is no type specified in the view.
// Type is loaded from DDM.
private VariableNode typedVariableFromDdm(VariableNode variable, GroupNode enclosingGroup)
{
// unresolved DDM
if (view.ddm() == null)
{
return variable;
}

var typedVariable = new TypedVariableNode(variable);

checkVariableTypeAgainstDdm(typedVariable);
var isCountVariable = variable.name().startsWith("C*");
var fieldName = isCountVariable ? variable.name().substring(2) : variable.name();
var ddmField = view.ddm().findField(fieldName);

if (ddmField == null)
{
if (!isCountVariable)
{
report(ParserErrors.unresolvedDdmField(variable.identifierNode()));
}
else
{
report(ParserErrors.unresolvedDdmField(variable.identifierNode(), fieldName));
}

return variable;
}

if (isCountVariable)
{
return typedCountVariable(typedVariable);
}

if (ddmField.fieldType() == FieldType.GROUP)
{
return typedVariable;
}

var type = new VariableType();
type.setFormat(ddmField.format());
type.setLength(ddmField.length());
typedVariable.setType(type);

if (ddmField.level() > 1
// if the variable already has a dimension explicitly specified we don't need to take it from the group
&& typedVariable.dimensions.isEmpty()
// if the user specified the periodic group explicitly, the dimensions will be passed down. No need to add the periodic dimension
&& (enclosingGroup == null || !enclosingGroup.isArray()))
{
for (var field : view.ddm().fields())
{
if (field instanceof IGroupField group
&& group.fieldType() == FieldType.PERIODIC
&& group.members().contains(ddmField))
{
var dimension = new ArrayDimension();
dimension.setLowerBound(1);
dimension.setUpperBound(199);
typedVariable.addDimension(dimension);
break;
}
}
}

if (typedVariable.dimensions.isEmpty() && // no dimensions explicitly given
(ddmField.fieldType() == FieldType.MULTIPLE || ddmField.fieldType() == FieldType.PERIODIC))
{
var dimension = new ArrayDimension();
dimension.setLowerBound(1);
dimension.setUpperBound(199);
typedVariable.addDimension(dimension);
}

return typedVariable;
}

private TypedVariableNode typedCountVariable(TypedVariableNode typedVariable)
{
var countType = new VariableType();
countType.setLength(4);
countType.setFormat(DataFormat.INTEGER);
typedVariable.setType(countType);
return typedVariable;
}

private void checkVariableTypeAgainstDdm(TypedVariableNode typed)
{
// TODO
if (view.ddm() == null)
{
return;
}

var ddmField = view.ddm().findField(typed.name());
if (ddmField == null)
{
return;
}

if (ddmField.format() == null || ddmField.format() == DataFormat.NONE)
{
return;
}

if (typed.type() == null)
{
return;
}

if ((ddmField.format() == DataFormat.LOGIC && typed.type().format() == DataFormat.LOGIC)
|| (ddmField.format() == DataFormat.DATE && typed.type().format() == DataFormat.DATE)
|| (ddmField.format() == DataFormat.TIME && typed.type().format() == DataFormat.TIME))
{
// It would complain about length 0 (Natural) vs length 1 (Adabas)
return;
}

if (ddmField.format() != typed.type().format())
{
report(ParserErrors.typeMismatch("Type mismatch: Variable has format %s but DDM field has format %s".formatted(typed.type().format(), ddmField.format()), typed));
}

if (ddmField.length() != typed.type().length())
{
report(ParserErrors.typeMismatch("Type mismatch: Variable (format %s) has length %f but DDM field (format %s) has length %f".formatted(typed.type().format(), typed.type().length(), ddmField.format(), ddmField.length()), typed));
}
}

private double getLengthFromDataType(String dataType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ public IDataDefinitionModule parseDdm(String content)
}

var field = parseField(scanner);
if (field.fieldType() == FieldType.GROUP)
if ((field.fieldType() == FieldType.GROUP || field.fieldType() == FieldType.PERIODIC)
&& field.descriptor() != DescriptorType.SUPERDESCRIPTOR)
{
var groupField = new GroupField(field);
scanner.advance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ public DdmField parse(LinewiseTextScanner scanner)
var descriptorType = parseDescriptorType(fieldLine);
var remark = parseRemark(fieldLine);

var length = fieldType == FieldType.GROUP || fieldType == FieldType.PERIODIC
var length = descriptorType == DescriptorType.NONE && (fieldType == FieldType.GROUP || fieldType == FieldType.PERIODIC)
? 0
: parseLength(scanner);
var dataFormat = fieldType == FieldType.GROUP || fieldType == FieldType.PERIODIC
var dataFormat = descriptorType == DescriptorType.NONE && (fieldType == FieldType.GROUP || fieldType == FieldType.PERIODIC)
? DataFormat.NONE
: parseFormat(fieldLine);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class GroupField extends DdmField implements IGroupField
GroupField(DdmField field)
{
super(field);
if (field.fieldType() != FieldType.GROUP)
if (field.fieldType() != FieldType.GROUP && field.fieldType() != FieldType.PERIODIC)
{
throw new NaturalParseException(String.format("Cannot promote field of type %s to GroupField", field.fieldType()));
}
Expand Down
Loading

0 comments on commit 916a8ba

Please sign in to comment.