Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fully support DISPLAY statement #488

Merged
merged 11 commits into from
Aug 1, 2024
2 changes: 1 addition & 1 deletion docs/implemented-statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ partial - partially implemented to prevent false positives (14)
| DEFINE WORK FILE | :white_check_mark: |
| DELETE | :x: |
| DELETE (SQL) | partial |
| DISPLAY | :x: |
| DISPLAY | :white_check_mark: |
| DIVIDE | :white_check_mark: |
| DOWNLOAD PC FILE | :white_check_mark: |
| EJECT | :white_check_mark: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public static SyntaxKind getKeyword(String possibleKeyword)
case "calling" -> SyntaxKind.CALLING;
case "callnat" -> SyntaxKind.CALLNAT;
case "cap" -> SyntaxKind.CAP;
case "capt" -> SyntaxKind.CAPT;
case "captioned" -> SyntaxKind.CAPTIONED;
case "case" -> SyntaxKind.CASE;
case "cc" -> SyntaxKind.CC;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ public enum SyntaxKind
CABINET(true, false, false),
CALLING(true, false, false),
CAP(true, false, false),
CAPT(true, false, false),
CAPTIONED(true, false, false),
CASE(true, false, false),
CC(true, false, false),
Expand Down Expand Up @@ -820,6 +821,7 @@ public boolean isAttribute()
this == PM ||
this == PS ||
this == SB ||
this == SF ||
this == SG ||
this == TC ||
this == TCU ||
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.amshove.natparse.natural;

public interface IDisplayNode extends IStatementNode, ICanHaveReportSpecification
public interface IDisplayNode extends IOutputStatementNode, ICanHaveReportSpecification
{}
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
package org.amshove.natparse.natural;

import org.amshove.natparse.ReadOnlyList;
import org.amshove.natparse.natural.output.IOutputElementNode;

public interface IInputStatementNode extends IStatementNode
{
ReadOnlyList<IOutputElementNode> operands();

ReadOnlyList<IAttributeNode> statementAttributes();
}
public interface IInputStatementNode extends IOutputStatementNode
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.amshove.natparse.natural;

import org.amshove.natparse.ReadOnlyList;
import org.amshove.natparse.natural.output.IOutputElementNode;

public interface IOutputStatementNode extends IStatementNode
{
ReadOnlyList<IAttributeNode> statementAttributes();

ReadOnlyList<IOutputElementNode> operands();
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.amshove.natparse.natural;

public interface IPrintNode extends IStatementNode, ICanHaveReportSpecification
public interface IPrintNode extends IOutputStatementNode, ICanHaveReportSpecification
{}
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
package org.amshove.natparse.natural;

import org.amshove.natparse.ReadOnlyList;
import org.amshove.natparse.natural.output.IOutputElementNode;

public interface IWriteNode extends IStatementNode, ICanHaveReportSpecification
{
ReadOnlyList<IAttributeNode> statementAttributes();

ReadOnlyList<IOutputElementNode> operands();
}
public interface IWriteNode extends IOutputStatementNode, ICanHaveReportSpecification
{}
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
package org.amshove.natparse.parsing;

import org.amshove.natparse.lexing.SyntaxToken;
import org.amshove.natparse.natural.IDisplayNode;

import java.util.Optional;

class DisplayNode extends StatementNode implements IDisplayNode, ICanSetReportSpecification
{
private SyntaxToken reportSpecification;

@Override
public Optional<SyntaxToken> reportSpecification()
{
return Optional.ofNullable(reportSpecification);
}

@Override
public void setReportSpecification(SyntaxToken token)
{
reportSpecification = token;
}
}
class DisplayNode extends OutputStatementNode implements IDisplayNode
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.amshove.natparse.parsing;

import org.amshove.natparse.ReadOnlyList;
import org.amshove.natparse.lexing.SyntaxToken;
import org.amshove.natparse.natural.*;
import org.amshove.natparse.natural.output.IOutputElementNode;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

class OutputStatementNode extends StatementNode implements IOutputStatementNode, ICanSetReportSpecification, ICanHaveReportSpecification
{
private SyntaxToken reportSpecification;
private final List<IOutputElementNode> operands = new ArrayList<>();
private IAttributeListNode statementAttributes;

@Override
public Optional<SyntaxToken> reportSpecification()
{
return Optional.ofNullable(reportSpecification);
}

@Override
public void setReportSpecification(SyntaxToken token)
{
reportSpecification = token;
}

@Override
public ReadOnlyList<IOutputElementNode> operands()
{
return ReadOnlyList.from(operands);
}

@Override
public ReadOnlyList<IAttributeNode> statementAttributes()
{
return statementAttributes != null ? statementAttributes.attributes() : ReadOnlyList.empty();
}

void addOperand(IOutputElementNode operand)
{
if (operand == null)
{
// stuff like tab setting, line skip etc.
return;
}

addNode((BaseSyntaxNode) operand);
operands.add(operand);
}

void setAttributes(IAttributeListNode attributes)
{
statementAttributes = attributes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.amshove.natparse.parsing;

import org.amshove.natparse.natural.IPrintNode;

public class PrintNode extends OutputStatementNode implements IPrintNode
{}
Original file line number Diff line number Diff line change
Expand Up @@ -2134,34 +2134,6 @@ private StatementNode examineTranslate(ExamineNode examine) throws ParseError
return examine;
}

private StatementNode display() throws ParseError
{
var display = new DisplayNode();
consumeMandatory(display, SyntaxKind.DISPLAY);

if (consumeOptionally(display, SyntaxKind.LPAREN))
{
if (peek().kind().canBeIdentifier() && peekKind(1, SyntaxKind.RPAREN))
{
var token = consumeMandatoryIdentifier(display);
display.setReportSpecification(token);
}
else
{
// currently consume everything until closing parenthesis to consume things like attribute definition etc.
while (!peekKind(SyntaxKind.RPAREN))
{
consume(display);
}
}
consumeMandatory(display, SyntaxKind.RPAREN);
}

// TODO: Parse options

return display;
}

private StatementNode inputStatement() throws ParseError
{
var input = new InputStatementNode();
Expand Down Expand Up @@ -2299,7 +2271,7 @@ private void checkOutputElementAttributes(IOutputElementNode operand)

private StatementNode write(SyntaxKind statementKind) throws ParseError
{
var write = new WriteNode();
OutputStatementNode write = statementKind == SyntaxKind.WRITE ? new WriteNode() : new PrintNode();
consumeMandatory(write, statementKind);
if (peekKind(SyntaxKind.LPAREN))
{
Expand Down Expand Up @@ -2337,8 +2309,56 @@ private StatementNode write(SyntaxKind statementKind) throws ParseError
return write;
}

private static final Set<SyntaxKind> OPTIONAL_DISPLAY_FLAGS = Set.of(SyntaxKind.NOTITLE, SyntaxKind.NOTIT, SyntaxKind.NOHDR, SyntaxKind.AND, SyntaxKind.GIVE, SyntaxKind.SYSTEM, SyntaxKind.FUNCTIONS);
private static final Set<SyntaxKind> DISPLAY_OUTPUT_FORMATS = Set.of(SyntaxKind.VERT, SyntaxKind.VERTICALLY, SyntaxKind.HORIZ, SyntaxKind.HORIZONTALLY, SyntaxKind.AS, SyntaxKind.CAPT, SyntaxKind.CAPTIONED);

private StatementNode display() throws ParseError
{
var display = new DisplayNode();
consumeMandatory(display, SyntaxKind.DISPLAY);

if (peekKind(SyntaxKind.LPAREN) && !isOutputElementAttribute(peek(1).kind()))
{
consumeMandatory(display, SyntaxKind.LPAREN);
var token = consume(display);
display.setReportSpecification(token);
consumeMandatory(display, SyntaxKind.RPAREN);
}

if (peekKind(SyntaxKind.LPAREN) && isOutputElementAttribute(peek(1).kind()))
{
var attributeList = consumeAttributeList(display);
display.setAttributes(attributeList);
}

while (consumeAnyOptionally(display, OPTIONAL_DISPLAY_FLAGS))
{
// advances automatically
}

while (!isAtEnd() && !isStatementStart())
{
while (consumeAnyOptionally(display, DISPLAY_OUTPUT_FORMATS))
{
// advances automatically
}

if (!(isOperand() || peekKind(SyntaxKind.TAB_SETTING) || peekKind(SyntaxKind.SLASH) || peekKind(SyntaxKind.OPERAND_SKIP)))
{
break;
}

var operand = consumeInputOutputOperand(display);
display.addOperand(operand);
checkOutputElementAttributes(operand);
}

return display;
}

private IOutputElementNode consumeInputOutputOperand(BaseSyntaxNode writeLikeNode) throws ParseError
{

if (peekKind(SyntaxKind.TAB_SETTING))
{
var tab = new TabulatorElementNode();
Expand Down Expand Up @@ -4880,8 +4900,18 @@ private boolean isInputElementAttribute(SyntaxKind kind)
{
return switch (kind)
{
case AD, AL, CD, CV, DF, DL, DY, EM, EMU, FL, HE, IP, NL, PM, SB, SG, ZP -> true;
case AD, AL, CD, CV, DF, DL, DY, EM, EMU, FL, HE, IP, IS, NL, PM, SB, SG, ZP -> true;
default -> false;
};
}

private boolean isOutputElementAttribute(SyntaxKind kind)
{
return switch (kind)
{
case AD, AL, CD, CV, DF, DL, DY, EM, EMU, ES, FC, FL, GC, HC, HW, IC, ICU, IS, LC, LCU, LS, MC, MP, NL, PC, PM, PS, SF, SG, TC, TCU, UC, ZP -> true;
default -> false;
};
}

}
Original file line number Diff line number Diff line change
@@ -1,58 +1,6 @@
package org.amshove.natparse.parsing;

import org.amshove.natparse.ReadOnlyList;
import org.amshove.natparse.lexing.SyntaxToken;
import org.amshove.natparse.natural.*;
import org.amshove.natparse.natural.output.IOutputElementNode;
import org.amshove.natparse.natural.IWriteNode;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

class WriteNode extends StatementNode implements IWriteNode, IPrintNode, ICanSetReportSpecification
{
private SyntaxToken reportSpecification;
private final List<IOutputElementNode> operands = new ArrayList<>();
private IAttributeListNode statementAttributes;

@Override
public Optional<SyntaxToken> reportSpecification()
{
return Optional.ofNullable(reportSpecification);
}

@Override
public void setReportSpecification(SyntaxToken token)
{
reportSpecification = token;
}

@Override
public ReadOnlyList<IOutputElementNode> operands()
{
return ReadOnlyList.from(operands);
}

@Override
public ReadOnlyList<IAttributeNode> statementAttributes()
{
return statementAttributes != null ? statementAttributes.attributes() : ReadOnlyList.empty();
}

void addOperand(IOutputElementNode operand)
{
if (operand == null)
{
// stuff like tab setting, line skip etc.
return;
}

addNode((BaseSyntaxNode) operand);
operands.add(operand);
}

void setAttributes(IAttributeListNode attributes)
{
statementAttributes = attributes;
}
}
class WriteNode extends OutputStatementNode implements IWriteNode
{}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Stream<DynamicTest> recognizeAttributes()
SyntaxKind.PM,
SyntaxKind.PS,
SyntaxKind.SB,
SyntaxKind.SF,
SyntaxKind.SG,
SyntaxKind.TC,
SyntaxKind.TCU,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Iterable<DynamicTest> lexKCheckReservedKeywords()
keywordTest("CALLING", SyntaxKind.CALLING),
keywordTest("CALLNAT", SyntaxKind.CALLNAT),
keywordTest("CAP", SyntaxKind.CAP),
keywordTest("CAPT", SyntaxKind.CAPT),
keywordTest("CAPTIONED", SyntaxKind.CAPTIONED),
keywordTest("CASE", SyntaxKind.CASE),
keywordTest("CC", SyntaxKind.CC),
Expand Down
Loading