diff --git a/src/main/kotlin/table/FunctionTable.kt b/src/main/kotlin/table/FunctionTable.kt index f4d46cd..ac58649 100644 --- a/src/main/kotlin/table/FunctionTable.kt +++ b/src/main/kotlin/table/FunctionTable.kt @@ -32,9 +32,9 @@ import function.builtin.predicate.EQUAL import function.builtin.predicate.GENSYM_EQUAL import function.builtin.predicate.LISTP import function.builtin.predicate.NULL -import function.builtin.predicate.NumericEqual import function.builtin.predicate.NUMERIC_GREATER import function.builtin.predicate.NUMERIC_LESS +import function.builtin.predicate.NumericEqual import function.builtin.special.AND import function.builtin.special.CASE import function.builtin.special.COND @@ -42,9 +42,9 @@ import function.builtin.special.DEFINE_SPECIAL import function.builtin.special.DEFMACRO import function.builtin.special.DEFUN import function.builtin.special.IF -import function.builtin.special.Lambda import function.builtin.special.LET import function.builtin.special.LET_STAR +import function.builtin.special.Lambda import function.builtin.special.OR import function.builtin.special.PROGN import function.builtin.special.QUOTE diff --git a/src/main/kotlin/token/AtSign.java b/src/main/kotlin/token/AtSign.java deleted file mode 100644 index 0f045d0..0000000 --- a/src/main/kotlin/token/AtSign.java +++ /dev/null @@ -1,22 +0,0 @@ -package token; - -import file.FilePosition; -import sexpression.AtSignExpression; -import sexpression.SExpression; - -import java.util.function.Supplier; - -public class AtSign extends Token { - - public AtSign(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - Token nextToken = getNextToken.get(); - SExpression argument = nextToken.parseSExpression(getNextToken); - - return new AtSignExpression(argument); - } -} diff --git a/src/main/kotlin/token/AtSign.kt b/src/main/kotlin/token/AtSign.kt new file mode 100644 index 0000000..1eb8cc9 --- /dev/null +++ b/src/main/kotlin/token/AtSign.kt @@ -0,0 +1,15 @@ +package token + +import file.FilePosition +import sexpression.AtSignExpression +import sexpression.SExpression + +class AtSign(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token): SExpression { + val nextToken = getNextToken() + val argument = nextToken.parseSExpression(getNextToken) + + return AtSignExpression(argument) + } +} diff --git a/src/main/kotlin/token/Backquote.java b/src/main/kotlin/token/Backquote.java deleted file mode 100644 index 427f4e8..0000000 --- a/src/main/kotlin/token/Backquote.java +++ /dev/null @@ -1,22 +0,0 @@ -package token; - -import file.FilePosition; -import sexpression.BackquoteExpression; -import sexpression.SExpression; - -import java.util.function.Supplier; - -public class Backquote extends Token { - - public Backquote(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - Token nextToken = getNextToken.get(); - SExpression argument = nextToken.parseSExpression(getNextToken); - - return new BackquoteExpression(argument); - } -} diff --git a/src/main/kotlin/token/Backquote.kt b/src/main/kotlin/token/Backquote.kt new file mode 100644 index 0000000..e889c9b --- /dev/null +++ b/src/main/kotlin/token/Backquote.kt @@ -0,0 +1,15 @@ +package token + +import file.FilePosition +import sexpression.BackquoteExpression +import sexpression.SExpression + +class Backquote(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token): SExpression { + val nextToken = getNextToken() + val argument = nextToken.parseSExpression(getNextToken) + + return BackquoteExpression(argument) + } +} diff --git a/src/main/kotlin/token/Comma.java b/src/main/kotlin/token/Comma.java deleted file mode 100644 index 5944e84..0000000 --- a/src/main/kotlin/token/Comma.java +++ /dev/null @@ -1,22 +0,0 @@ -package token; - -import file.FilePosition; -import sexpression.CommaExpression; -import sexpression.SExpression; - -import java.util.function.Supplier; - -public class Comma extends Token { - - public Comma(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - Token nextToken = getNextToken.get(); - SExpression argument = nextToken.parseSExpression(getNextToken); - - return new CommaExpression(argument); - } -} diff --git a/src/main/kotlin/token/Comma.kt b/src/main/kotlin/token/Comma.kt new file mode 100644 index 0000000..3af3c7f --- /dev/null +++ b/src/main/kotlin/token/Comma.kt @@ -0,0 +1,15 @@ +package token + +import file.FilePosition +import sexpression.CommaExpression +import sexpression.SExpression + +class Comma(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token): SExpression { + val nextToken = getNextToken() + val argument = nextToken.parseSExpression(getNextToken) + + return CommaExpression(argument) + } +} diff --git a/src/main/kotlin/token/Eof.java b/src/main/kotlin/token/Eof.java deleted file mode 100644 index a308db7..0000000 --- a/src/main/kotlin/token/Eof.java +++ /dev/null @@ -1,33 +0,0 @@ -package token; - -import error.LineColumnException; -import file.FilePosition; -import sexpression.SExpression; - -import java.util.function.Supplier; - -public class Eof extends Token { - - public Eof(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - throw new EofEncounteredException(getPosition()); - } - - public static class EofEncounteredException extends LineColumnException { - - private static final long serialVersionUID = 1L; - - public EofEncounteredException(FilePosition position) { - super(position); - } - - @Override - public String getMessagePrefix() { - return "end-of-file encountered"; - } - } -} diff --git a/src/main/kotlin/token/Eof.kt b/src/main/kotlin/token/Eof.kt new file mode 100644 index 0000000..4aa5fe3 --- /dev/null +++ b/src/main/kotlin/token/Eof.kt @@ -0,0 +1,17 @@ +package token + +import error.LineColumnException +import file.FilePosition +import sexpression.SExpression + +class Eof(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token): SExpression { + throw EofEncounteredException(position) + } + + class EofEncounteredException(position: FilePosition) : LineColumnException(position) { + override val messagePrefix: String + get() = "end-of-file encountered" + } +} diff --git a/src/main/kotlin/token/Identifier.java b/src/main/kotlin/token/Identifier.java deleted file mode 100644 index 402be86..0000000 --- a/src/main/kotlin/token/Identifier.java +++ /dev/null @@ -1,19 +0,0 @@ -package token; - -import file.FilePosition; -import sexpression.SExpression; -import sexpression.Symbol; - -import java.util.function.Supplier; - -public class Identifier extends Token { - - public Identifier(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - return new Symbol(getText()); - } -} diff --git a/src/main/kotlin/token/Identifier.kt b/src/main/kotlin/token/Identifier.kt new file mode 100644 index 0000000..68b8385 --- /dev/null +++ b/src/main/kotlin/token/Identifier.kt @@ -0,0 +1,9 @@ +package token + +import file.FilePosition +import sexpression.Symbol + +class Identifier(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token) = Symbol(text) +} diff --git a/src/main/kotlin/token/LeftParenthesis.java b/src/main/kotlin/token/LeftParenthesis.java deleted file mode 100644 index c63a5b6..0000000 --- a/src/main/kotlin/token/LeftParenthesis.java +++ /dev/null @@ -1,20 +0,0 @@ -package token; - -import file.FilePosition; -import sexpression.SExpression; - -import java.util.function.Supplier; - -public class LeftParenthesis extends Token { - - public LeftParenthesis(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - Token nextToken = getNextToken.get(); - - return nextToken.parseListTail(getNextToken).invoke(); - } -} diff --git a/src/main/kotlin/token/LeftParenthesis.kt b/src/main/kotlin/token/LeftParenthesis.kt new file mode 100644 index 0000000..9c9df18 --- /dev/null +++ b/src/main/kotlin/token/LeftParenthesis.kt @@ -0,0 +1,13 @@ +package token + +import file.FilePosition +import sexpression.SExpression + +class LeftParenthesis(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token): SExpression { + val nextToken = getNextToken() + + return nextToken.parseListTail(getNextToken).invoke() + } +} diff --git a/src/main/kotlin/token/Number.java b/src/main/kotlin/token/Number.java deleted file mode 100644 index 8c78eb1..0000000 --- a/src/main/kotlin/token/Number.java +++ /dev/null @@ -1,19 +0,0 @@ -package token; - -import file.FilePosition; -import sexpression.LispNumber; -import sexpression.SExpression; - -import java.util.function.Supplier; - -public class Number extends Token { - - public Number(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - return new LispNumber(getText()); - } -} diff --git a/src/main/kotlin/token/Number.kt b/src/main/kotlin/token/Number.kt new file mode 100644 index 0000000..660c39f --- /dev/null +++ b/src/main/kotlin/token/Number.kt @@ -0,0 +1,9 @@ +package token + +import file.FilePosition +import sexpression.LispNumber + +class Number(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token) = LispNumber(text) +} diff --git a/src/main/kotlin/token/QuoteMark.java b/src/main/kotlin/token/QuoteMark.java deleted file mode 100644 index b3b706c..0000000 --- a/src/main/kotlin/token/QuoteMark.java +++ /dev/null @@ -1,25 +0,0 @@ -package token; - -import file.FilePosition; -import sexpression.Cons; -import sexpression.SExpression; -import sexpression.Symbol; - -import java.util.function.Supplier; - -import static sexpression.Nil.NIL; - -public class QuoteMark extends Token { - - public QuoteMark(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - Token nextToken = getNextToken.get(); - SExpression argument = nextToken.parseSExpression(getNextToken); - - return new Cons(Symbol.createQuote(), new Cons(argument, NIL)); - } -} diff --git a/src/main/kotlin/token/QuoteMark.kt b/src/main/kotlin/token/QuoteMark.kt new file mode 100644 index 0000000..a6df641 --- /dev/null +++ b/src/main/kotlin/token/QuoteMark.kt @@ -0,0 +1,17 @@ +package token + +import file.FilePosition +import sexpression.Cons +import sexpression.Nil.NIL +import sexpression.SExpression +import sexpression.Symbol + +class QuoteMark(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token): SExpression { + val nextToken = getNextToken() + val argument = nextToken.parseSExpression(getNextToken) + + return Cons(Symbol.createQuote(), Cons(argument, NIL)) + } +} diff --git a/src/main/kotlin/token/QuotedString.java b/src/main/kotlin/token/QuotedString.java deleted file mode 100644 index 153f5dd..0000000 --- a/src/main/kotlin/token/QuotedString.java +++ /dev/null @@ -1,19 +0,0 @@ -package token; - -import file.FilePosition; -import sexpression.LispString; -import sexpression.SExpression; - -import java.util.function.Supplier; - -public class QuotedString extends Token { - - public QuotedString(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - return new LispString(getText()); - } -} diff --git a/src/main/kotlin/token/QuotedString.kt b/src/main/kotlin/token/QuotedString.kt new file mode 100644 index 0000000..84b92f5 --- /dev/null +++ b/src/main/kotlin/token/QuotedString.kt @@ -0,0 +1,9 @@ +package token + +import file.FilePosition +import sexpression.LispString + +class QuotedString(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token) = LispString(text) +} diff --git a/src/main/kotlin/token/RightParenthesis.java b/src/main/kotlin/token/RightParenthesis.java deleted file mode 100644 index f702288..0000000 --- a/src/main/kotlin/token/RightParenthesis.java +++ /dev/null @@ -1,48 +0,0 @@ -package token; - -import error.LineColumnException; -import file.FilePosition; -import recursion.TailCall; -import sexpression.Cons; -import sexpression.SExpression; - -import java.util.function.Supplier; - -import static recursion.TailCalls.done; -import static sexpression.Nil.NIL; - -public class RightParenthesis extends Token { - - public RightParenthesis(String text, FilePosition position) { - super(text, position); - } - - @Override - public SExpression parseSExpression(Supplier getNextToken) { - throw new StartsWithRightParenthesisException(getPosition()); - } - - @Override - protected TailCall parseListTail(Supplier getNextToken) { - return done(NIL); - } - - @Override - protected TailCall parseListTailRecursive(Cons start, Cons end, Supplier getNextToken) { - return done(start); - } - - public static class StartsWithRightParenthesisException extends LineColumnException { - - private static final long serialVersionUID = 1L; - - public StartsWithRightParenthesisException(FilePosition position) { - super(position); - } - - @Override - public String getMessagePrefix() { - return "expression begins with ')'"; - } - } -} diff --git a/src/main/kotlin/token/RightParenthesis.kt b/src/main/kotlin/token/RightParenthesis.kt new file mode 100644 index 0000000..e8432ba --- /dev/null +++ b/src/main/kotlin/token/RightParenthesis.kt @@ -0,0 +1,29 @@ +package token + +import error.LineColumnException +import file.FilePosition +import recursion.TailCall +import recursion.TailCalls.done +import sexpression.Cons +import sexpression.Nil.NIL +import sexpression.SExpression + +class RightParenthesis(text: String, position: FilePosition) : Token(text, position) { + + override fun parseSExpression(getNextToken: () -> Token): SExpression { + throw StartsWithRightParenthesisException(position) + } + + override fun parseListTail(getNextToken: () -> Token): TailCall { + return done(NIL) + } + + override fun parseListTailRecursive(start: Cons, end: Cons, getNextToken: () -> Token): TailCall { + return done(start) + } + + class StartsWithRightParenthesisException(position: FilePosition) : LineColumnException(position) { + override val messagePrefix: String + get() = "expression begins with ')'" + } +} diff --git a/src/main/kotlin/token/Token.java b/src/main/kotlin/token/Token.java deleted file mode 100644 index ba316ef..0000000 --- a/src/main/kotlin/token/Token.java +++ /dev/null @@ -1,55 +0,0 @@ -package token; - -import file.FilePosition; -import recursion.TailCall; -import sexpression.Cons; -import sexpression.SExpression; - -import java.util.function.Supplier; - -import static recursion.TailCalls.tailCall; -import static sexpression.Nil.NIL; - -public abstract class Token { - - private String text; - private FilePosition position; - - public Token(String text, FilePosition position) { - this.text = text; - this.position = position; - } - - public String getText() { - return text; - } - - public FilePosition getPosition() { - return position; - } - - // -------------------------------------------------------------------------------------------- - // s-expression - // ::= NUMBER | IDENTIFIER | STRING | QUOTE_MARK s-expression | LEFT_PAREN list-tail - // - // list-tail - // ::= RIGHT_PAREN | s-expression list-tail - // -------------------------------------------------------------------------------------------- - - public abstract SExpression parseSExpression(Supplier getNextToken); - - protected TailCall parseListTail(Supplier getNextToken) { - Cons firstCons = new Cons(parseSExpression(getNextToken), NIL); - Token next = getNextToken.get(); - - return tailCall(() -> next.parseListTailRecursive(firstCons, firstCons, getNextToken)); - } - - protected TailCall parseListTailRecursive(Cons start, Cons end, Supplier getNextToken) { - Cons newEnd = new Cons(parseSExpression(getNextToken), NIL); - Token next = getNextToken.get(); - end.setRest(newEnd); - - return tailCall(() -> next.parseListTailRecursive(start, newEnd, getNextToken)); - } -} diff --git a/src/main/kotlin/token/Token.kt b/src/main/kotlin/token/Token.kt new file mode 100644 index 0000000..2fa2f44 --- /dev/null +++ b/src/main/kotlin/token/Token.kt @@ -0,0 +1,36 @@ +package token + +import file.FilePosition +import recursion.TailCall +import recursion.TailCalls.tailCall +import sexpression.Cons +import sexpression.Nil.NIL +import sexpression.SExpression + +abstract class Token(val text: String, val position: FilePosition) { + + // -------------------------------------------------------------------------------------------- + // s-expression + // ::= NUMBER | IDENTIFIER | STRING | QUOTE_MARK s-expression | LEFT_PAREN list-tail + // + // list-tail + // ::= RIGHT_PAREN | s-expression list-tail + // -------------------------------------------------------------------------------------------- + + abstract fun parseSExpression(getNextToken: () -> Token): SExpression + + open fun parseListTail(getNextToken: () -> Token): TailCall { + val firstCons = Cons(parseSExpression(getNextToken), NIL) + val next = getNextToken() + + return tailCall { next.parseListTailRecursive(firstCons, firstCons, getNextToken) } + } + + protected open fun parseListTailRecursive(start: Cons, end: Cons, getNextToken: () -> Token): TailCall { + val newEnd = Cons(parseSExpression(getNextToken), NIL) + val next = getNextToken() + end.rest = newEnd + + return tailCall { next.parseListTailRecursive(start, newEnd, getNextToken) } + } +} diff --git a/src/test/kotlin/parser/LispParserTest.kt b/src/test/kotlin/parser/LispParserTest.kt index fb38768..c55d684 100644 --- a/src/test/kotlin/parser/LispParserTest.kt +++ b/src/test/kotlin/parser/LispParserTest.kt @@ -1,7 +1,6 @@ package parser import error.LispException -import error.Severity.ERROR import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Assertions.fail