Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/java/com/scriptbasic/context/ContextBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ private static void createReaderDependentComponents(final SourceReader reader, f
ctx.lexicalAnalyzer = new ScriptBasicLexicalAnalyzer(reader);
ctx.nestedStructureHouseKeeper = new GenericNestedStructureHouseKeeper(ctx.lexicalAnalyzer);
final var commandFactory = new BasicCommandFactory(ctx);
ctx.syntaxAnalyzer = new BasicSyntaxAnalyzer(ctx.lexicalAnalyzer, commandFactory);
ctx.syntaxAnalyzer = new BasicSyntaxAnalyzer(ctx.lexicalAnalyzer, commandFactory,
ctx.nestedStructureHouseKeeper);
}

private static void createReusableComponents(final Context ctx) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,14 @@ public interface NestedStructureHouseKeeper {
*/
<T extends NestedStructure> T pop(Class<T> expectedClass)
throws AnalysisException;

/**
* Check final state of nested structures.
*
* Check if there are no opened nested structures
* or any other pending blocks.
*
* @throws AnalysisException when there are some elements on the stack
*/
void checkFinalState() throws AnalysisException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,11 @@ public <T> boolean match(final Class<T> expectedClass) {
return expectedClass.isAssignableFrom(getElementType());
}
}

@Override
public void checkFinalState() throws AnalysisException {
if (stack.size() > 0) {
throw new BasicSyntaxException("There is at least one opened block on the stack. Block is not properly closed.");
}
}
}
12 changes: 8 additions & 4 deletions src/main/java/com/scriptbasic/syntax/BasicSyntaxAnalyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
public final class BasicSyntaxAnalyzer implements SyntaxAnalyzer {
private final LexicalAnalyzer lexicalAnalyzer;
private final CommandFactory commandFactory;
private LexicalElement lexicalElement;
private final NestedStructureHouseKeeper nestedStructureHouseKeeper;
private LexicalElement lexicalElement;

public BasicSyntaxAnalyzer(final LexicalAnalyzer lexicalAnalyzer, final CommandFactory commandFactory) {
public BasicSyntaxAnalyzer(final LexicalAnalyzer lexicalAnalyzer, final CommandFactory commandFactory,
final NestedStructureHouseKeeper nestedStructureHouseKeeper) {
this.lexicalAnalyzer = lexicalAnalyzer;
this.commandFactory = commandFactory;
this.nestedStructureHouseKeeper = nestedStructureHouseKeeper;
}

private static boolean lineToIgnore(final String lexString) {
public static boolean lineToIgnore(final String lexString) {
return lexString.equals("\n") || lexString.equals("'")
|| lexString.equalsIgnoreCase(ScriptBasicKeyWords.KEYWORD_REM);
}
Expand Down Expand Up @@ -49,11 +52,12 @@ public BuildableProgram analyze() throws AnalysisException {
}
this.lexicalElement = lexicalAnalyzer.peek();
}
nestedStructureHouseKeeper.checkFinalState();
buildableProgram.postprocess();
return buildableProgram;
}

private void consumeIgnoredLine(final LexicalAnalyzer lexicalAnalyzer, String lexString) throws AnalysisException {
public static void consumeIgnoredLine(final LexicalAnalyzer lexicalAnalyzer, String lexString) throws AnalysisException {
while (!lexString.equals("\n")) {
final var le = lexicalAnalyzer.get();
if (le == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,48 @@
import com.scriptbasic.context.Context;
import com.scriptbasic.executors.commands.CommandSelect;
import com.scriptbasic.interfaces.AnalysisException;
import com.scriptbasic.interfaces.BasicSyntaxException;
import com.scriptbasic.interfaces.ScriptBasicKeyWords;
import com.scriptbasic.spi.Command;
import com.scriptbasic.syntax.BasicSyntaxAnalyzer;

public class CommandAnalyzerSelect
extends AbstractCommandAnalyzer
{

public CommandAnalyzerSelect(Context ctx)
{
super(ctx);
}

@Override
public Command analyze() throws AnalysisException {
final var lexicalElement = ctx.lexicalAnalyzer.peek();
// consume optional case statement
if(lexicalElement.isSymbol(ScriptBasicKeyWords.KEYWORD_CASE))
ctx.lexicalAnalyzer.get();
// read expression till end of line
final var expression = analyzeExpression();
consumeEndOfLine();

final var node = new CommandSelect();
node.setExpression(expression);
pushNode(node);

return node;
}
extends AbstractCommandAnalyzer {

public CommandAnalyzerSelect(Context ctx) {
super(ctx);
}

@Override
public Command analyze() throws AnalysisException {
var lexicalElement = ctx.lexicalAnalyzer.peek();
// consume optional case statement
if (lexicalElement.isSymbol(ScriptBasicKeyWords.KEYWORD_CASE))
ctx.lexicalAnalyzer.get();
// read expression till end of line
final var expression = analyzeExpression();
consumeEndOfLine();

final var node = new CommandSelect();
node.setExpression(expression);
pushNode(node);

// next command has to be 'case'
// first skip any comments
lexicalElement = ctx.lexicalAnalyzer.peek();
while (lexicalElement != null && BasicSyntaxAnalyzer.lineToIgnore(lexicalElement.getLexeme())) {
ctx.lexicalAnalyzer.get();
BasicSyntaxAnalyzer.consumeIgnoredLine(ctx.lexicalAnalyzer, lexicalElement.getLexeme());
lexicalElement = ctx.lexicalAnalyzer.peek();
}
if (lexicalElement == null) {
throw new BasicSyntaxException("Preliminary end of file");
}
if (!lexicalElement.isSymbol(ScriptBasicKeyWords.KEYWORD_CASE)) {
throw new BasicSyntaxException("Expected case statement, but found: " + lexicalElement.getLexeme());
}

return node;
}

}
3 changes: 2 additions & 1 deletion src/test/java/com/scriptbasic/testprograms/TestPrograms.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ public void testPrograms() throws Exception {
codeTest("TestEmpty.bas", "");
codeTest("TestPrintHello.bas", "hello");
codeTest("TestIf.bas", "111");
codeTest("TestSelect1.bas", "111111");
codeTest("TestSelect1.bas", "1111111");
codeTest("TestSelect2.bas", "2468");
codeTest("TestSelect3.bas", "0 1 1 2 3 5 8");
testSyntaxFail("TestSelectBadSyntax1.bas");
testSyntaxFail("TestSelectBadSyntax2.bas");
testSyntaxFail("TestSelectBadSyntax3.bas");
testSyntaxFail("TestSelectBadSyntax4.bas");
codeTest("TestBooleanConversions.bas", "111111");
codeTest("TestArrays.bas", "OK");
try {
Expand Down
11 changes: 11 additions & 0 deletions src/test/resources/com/scriptbasic/testprograms/TestSelect1.bas
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,15 @@ case is "1": print "1"
case is "2": print "2"
end select

' Test comments inside select case
select case v
rem comment before first case
case "0": print "0"
rem comment between case
case "1": print "1"
case "2": print "2"
rem comment before end select
end select
rem comment after end select

print "1"
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

select case v
if true then print "1"
end select
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'
' This program is used to test the bad syntax of
' command select case ... end select
' when the 'end select' is missing
'
Comment thread
PetrPytelka marked this conversation as resolved.

select case "1"
case "0": print "0"
case "1": print "1"
case "2": print "2"