Skip to content

Commit

Permalink
Fully support DISPLAY statement (#488)
Browse files Browse the repository at this point in the history
Co-authored-by: Markus Amshove <scm@amshove.org>
  • Loading branch information
Claes65 and MarkusAmshove committed Aug 1, 2024
1 parent 2d592db commit 9debe20
Show file tree
Hide file tree
Showing 16 changed files with 201 additions and 132 deletions.
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

0 comments on commit 9debe20

Please sign in to comment.