From ef5a8ea38f345232b8877bbf380170778e12693b Mon Sep 17 00:00:00 2001 From: moremagic Date: Wed, 10 Feb 2021 18:28:33 +0900 Subject: [PATCH 01/10] =?UTF-8?q?MyLispPerserTest=E3=81=AE=E7=A2=BA?= =?UTF-8?q?=E8=AA=8D=E9=A0=85=E7=9B=AE=E3=81=AE=E6=BC=8F=E3=82=8C=E3=81=AB?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/mylisp/MyLispParserTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/mylisp/MyLispParserTest.java b/src/test/java/mylisp/MyLispParserTest.java index 874ba9c..fe70385 100644 --- a/src/test/java/mylisp/MyLispParserTest.java +++ b/src/test/java/mylisp/MyLispParserTest.java @@ -76,6 +76,7 @@ public void dotPairParseTest() throws Atom.AtomException { }) void testParse(String test_code, String expected_code) throws Atom.AtomException { Sexp[] ss = MyLispParser.parses(test_code); + assertEquals(1, ss.length); assertEquals(expected_code, ss[0].toString()); } From cbaed1abdccb93fb5b15e0ffe2647c969dcc39f0 Mon Sep 17 00:00:00 2001 From: moremagic Date: Wed, 10 Feb 2021 18:50:24 +0900 Subject: [PATCH 02/10] =?UTF-8?q?apply=20=E3=81=AE=E5=8E=9F=E5=9E=8B?= =?UTF-8?q?=E3=81=A8=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/mylisp/MyLisp.java | 4 ++++ src/test/java/mylisp/MyLispTest.java | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/mylisp/MyLisp.java b/src/main/java/mylisp/MyLisp.java index 524de52..d85b4eb 100644 --- a/src/main/java/mylisp/MyLisp.java +++ b/src/main/java/mylisp/MyLisp.java @@ -211,4 +211,8 @@ public static Sexp apply(Sexp sexp, Map env) throws MyLispExce return ret; } + + public static Sexp apply(Operator proc, Sexp... args) { + return null; + } } diff --git a/src/test/java/mylisp/MyLispTest.java b/src/test/java/mylisp/MyLispTest.java index cc2927d..5ff47ec 100644 --- a/src/test/java/mylisp/MyLispTest.java +++ b/src/test/java/mylisp/MyLispTest.java @@ -1,10 +1,24 @@ package mylisp; +import mylisp.core.Atom; +import mylisp.core.AtomChar; +import mylisp.core.Operator; +import mylisp.core.Sexp; +import mylisp.func.AddFunction; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class MyLispTest { + @Test - public void r5rsTest() { - //TODO: ファイルをどう読み込むのか考え中・・・ + void apply() throws Atom.AtomException { + + Operator op = new AddFunction(); + Sexp[] args = new Sexp[]{Atom.newAtom(3), AtomChar.newAtom(4)}; + Sexp expect = AtomChar.newAtom(7); + + Sexp ret = MyLisp.apply(op, args); + assertEquals(expect, ret); } } From 15854b2206907edfb43f67af770aebad13b48412 Mon Sep 17 00:00:00 2001 From: moremagic Date: Wed, 10 Feb 2021 19:27:53 +0900 Subject: [PATCH 03/10] =?UTF-8?q?TODO=20=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/mylisp/MyLisp.java | 5 ++-- src/main/java/mylisp/core/Operator.java | 1 + src/main/java/mylisp/core/Procedure.java | 6 +++++ src/main/java/mylisp/func/CarProcedure.java | 18 +++++++++++++ src/test/java/mylisp/MyLispTest.java | 15 +++++------ .../java/mylisp/func/CarProcedureTest.java | 27 +++++++++++++++++++ 6 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 src/main/java/mylisp/core/Procedure.java create mode 100644 src/main/java/mylisp/func/CarProcedure.java create mode 100644 src/test/java/mylisp/func/CarProcedureTest.java diff --git a/src/main/java/mylisp/MyLisp.java b/src/main/java/mylisp/MyLisp.java index d85b4eb..5fd3a7e 100644 --- a/src/main/java/mylisp/MyLisp.java +++ b/src/main/java/mylisp/MyLisp.java @@ -4,6 +4,7 @@ import java.io.*; import java.nio.charset.StandardCharsets; +import java.text.ParseException; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; @@ -212,7 +213,7 @@ public static Sexp apply(Sexp sexp, Map env) throws MyLispExce return ret; } - public static Sexp apply(Operator proc, Sexp... args) { - return null; + public static Sexp apply(Procedure proc, Sexp args) { + return proc.apply(args); } } diff --git a/src/main/java/mylisp/core/Operator.java b/src/main/java/mylisp/core/Operator.java index e8a25b2..b37070e 100644 --- a/src/main/java/mylisp/core/Operator.java +++ b/src/main/java/mylisp/core/Operator.java @@ -6,6 +6,7 @@ /** * Operator interface * TODO スペシャルフォームの実行メソッドはapply であるべき + * TODO このInterfaceは廃止予定で全てProcedureに変わる * * @author moremagic */ diff --git a/src/main/java/mylisp/core/Procedure.java b/src/main/java/mylisp/core/Procedure.java new file mode 100644 index 0000000..170f3e2 --- /dev/null +++ b/src/main/java/mylisp/core/Procedure.java @@ -0,0 +1,6 @@ +package mylisp.core; + +public interface Procedure { + String procedureSymbol(); + Sexp apply(Sexp sexp); +} diff --git a/src/main/java/mylisp/func/CarProcedure.java b/src/main/java/mylisp/func/CarProcedure.java new file mode 100644 index 0000000..ee7ced1 --- /dev/null +++ b/src/main/java/mylisp/func/CarProcedure.java @@ -0,0 +1,18 @@ +package mylisp.func; + +import mylisp.core.AbstractOperator; +import mylisp.core.IPair; +import mylisp.core.Procedure; +import mylisp.core.Sexp; + +public class CarProcedure implements Procedure { + @Override + public String procedureSymbol() { + return "car"; + } + + @Override + public Sexp apply(Sexp sexp) { + return null; + } +} diff --git a/src/test/java/mylisp/MyLispTest.java b/src/test/java/mylisp/MyLispTest.java index 5ff47ec..6d53c17 100644 --- a/src/test/java/mylisp/MyLispTest.java +++ b/src/test/java/mylisp/MyLispTest.java @@ -1,10 +1,8 @@ package mylisp; -import mylisp.core.Atom; -import mylisp.core.AtomChar; -import mylisp.core.Operator; -import mylisp.core.Sexp; +import mylisp.core.*; import mylisp.func.AddFunction; +import mylisp.func.CarProcedure; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -14,11 +12,12 @@ public class MyLispTest { @Test void apply() throws Atom.AtomException { - Operator op = new AddFunction(); - Sexp[] args = new Sexp[]{Atom.newAtom(3), AtomChar.newAtom(4)}; - Sexp expect = AtomChar.newAtom(7); + Procedure proc = new CarProcedure(); - Sexp ret = MyLisp.apply(op, args); + Sexp args = MyLispParser.parses("(1 2 3)")[0]; + Sexp expect = MyLispParser.parses("1")[0]; + + Sexp ret = MyLisp.apply(proc, args); assertEquals(expect, ret); } } diff --git a/src/test/java/mylisp/func/CarProcedureTest.java b/src/test/java/mylisp/func/CarProcedureTest.java new file mode 100644 index 0000000..d986da9 --- /dev/null +++ b/src/test/java/mylisp/func/CarProcedureTest.java @@ -0,0 +1,27 @@ +package mylisp.func; + +import mylisp.core.Atom; +import mylisp.core.ConsCell; +import mylisp.core.Procedure; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.*; + +class CarProcedureTest { + + @Test + void procedureSymbol() { + assertEquals("car", new CarProcedure().procedureSymbol()); + } + + @ParameterizedTest + @CsvSource({ + "'1', '2'", + }) + void apply(String first, String second) throws Atom.AtomException { + Procedure proc = new CarProcedure(); + assertEquals(Atom.newAtom(first), proc.apply(new ConsCell(Atom.newAtom(first), Atom.newAtom(second)))); + } +} \ No newline at end of file From ce8dbd8abdae4d74072b7dfe5ff9edcce7cf668a Mon Sep 17 00:00:00 2001 From: moremagic Date: Wed, 10 Feb 2021 23:21:24 +0900 Subject: [PATCH 04/10] =?UTF-8?q?fixup!=20apply=20=E3=81=AE=E5=8E=9F?= =?UTF-8?q?=E5=9E=8B=E3=81=A8=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/mylisp/MyLisp.java | 7 +++- src/main/java/mylisp/MyLispParser.java | 2 +- src/main/java/mylisp/core/AtomNil.java | 5 +++ src/main/java/mylisp/core/ConsCell.java | 11 +++---- src/main/java/mylisp/core/Procedure.java | 8 ++++- src/main/java/mylisp/func/CarProcedure.java | 18 ---------- src/main/java/mylisp/proc/CarProcedure.java | 24 ++++++++++++++ src/main/java/mylisp/proc/CdrProcedure.java | 24 ++++++++++++++ src/test/java/mylisp/MyLispTest.java | 11 +++---- .../java/mylisp/func/CarProcedureTest.java | 27 --------------- .../java/mylisp/proc/CarProcedureTest.java | 33 +++++++++++++++++++ .../java/mylisp/proc/CdrProcedureTest.java | 33 +++++++++++++++++++ 12 files changed, 143 insertions(+), 60 deletions(-) delete mode 100644 src/main/java/mylisp/func/CarProcedure.java create mode 100644 src/main/java/mylisp/proc/CarProcedure.java create mode 100644 src/main/java/mylisp/proc/CdrProcedure.java delete mode 100644 src/test/java/mylisp/func/CarProcedureTest.java create mode 100644 src/test/java/mylisp/proc/CarProcedureTest.java create mode 100644 src/test/java/mylisp/proc/CdrProcedureTest.java diff --git a/src/main/java/mylisp/MyLisp.java b/src/main/java/mylisp/MyLisp.java index 5fd3a7e..74f2461 100644 --- a/src/main/java/mylisp/MyLisp.java +++ b/src/main/java/mylisp/MyLisp.java @@ -213,7 +213,12 @@ public static Sexp apply(Sexp sexp, Map env) throws MyLispExce return ret; } - public static Sexp apply(Procedure proc, Sexp args) { + + public Sexp eval2(Sexp sexp, Map env){ + return null; + } + + public Sexp apply(Procedure proc, Sexp args) throws Procedure.ProcedureException { return proc.apply(args); } } diff --git a/src/main/java/mylisp/MyLispParser.java b/src/main/java/mylisp/MyLispParser.java index 93a635a..c141a43 100644 --- a/src/main/java/mylisp/MyLispParser.java +++ b/src/main/java/mylisp/MyLispParser.java @@ -161,7 +161,7 @@ private static Sexp parseCell(String sCell) throws Atom.AtomException { if (sexpList.isEmpty()) { // () の場合 - return new ConsCell(AtomNil.INSTANCE, AtomNil.INSTANCE); + return new ConsCell(); } else if (sexpList.get(0).toString().equals(Lambda.LAMBDA_SYMBOL)) { IPair cons = (IPair) ConsCell.createConsCell(sexpList.toArray(new Sexp[0])); return new Lambda(cons.getCar(), cons.getCdr()); diff --git a/src/main/java/mylisp/core/AtomNil.java b/src/main/java/mylisp/core/AtomNil.java index 8d020ae..777d12c 100644 --- a/src/main/java/mylisp/core/AtomNil.java +++ b/src/main/java/mylisp/core/AtomNil.java @@ -24,4 +24,9 @@ public Object getValue() { public boolean equals(Object object) { return object instanceof AtomNil; } + + @Override + public String toString() { + return "()"; + } } diff --git a/src/main/java/mylisp/core/ConsCell.java b/src/main/java/mylisp/core/ConsCell.java index 3e1b9c7..fb8a789 100644 --- a/src/main/java/mylisp/core/ConsCell.java +++ b/src/main/java/mylisp/core/ConsCell.java @@ -77,7 +77,7 @@ public Sexp[] getList() { @Override public String toString() { - return "(" + createConsString(this) + ")"; + return String.format("(%s)",createConsString(this)); } @Override @@ -94,15 +94,14 @@ private static String createConsString(IPair cons) { return ""; } - StringBuilder sb = new StringBuilder(); - sb.append(cons.getCar()); if (cons.getCdr() instanceof Atom && cons.getCdr() != AtomNil.INSTANCE) { //Cdr が Atom の場合は Dotpair 表示を行うが Nil の場合は Dotpair 表示を行わない - sb.append(" . ").append(cons.getCdr()); + return String.format("%s . %s", cons.getCar(), cons.getCdr()); } else if (cons.getCdr() instanceof IPair) { - sb.append(" ").append(createConsString((IPair) cons.getCdr())); + return String.format("%s %s", cons.getCar(), createConsString((IPair) cons.getCdr())); + } else{ + return String.format("%s", cons.getCar()); } - return sb.toString(); } diff --git a/src/main/java/mylisp/core/Procedure.java b/src/main/java/mylisp/core/Procedure.java index 170f3e2..96ddc48 100644 --- a/src/main/java/mylisp/core/Procedure.java +++ b/src/main/java/mylisp/core/Procedure.java @@ -2,5 +2,11 @@ public interface Procedure { String procedureSymbol(); - Sexp apply(Sexp sexp); + Sexp apply(Sexp sexp) throws ProcedureException; + + class ProcedureException extends MyLispException { + public ProcedureException(String message) { + super(message); + } + } } diff --git a/src/main/java/mylisp/func/CarProcedure.java b/src/main/java/mylisp/func/CarProcedure.java deleted file mode 100644 index ee7ced1..0000000 --- a/src/main/java/mylisp/func/CarProcedure.java +++ /dev/null @@ -1,18 +0,0 @@ -package mylisp.func; - -import mylisp.core.AbstractOperator; -import mylisp.core.IPair; -import mylisp.core.Procedure; -import mylisp.core.Sexp; - -public class CarProcedure implements Procedure { - @Override - public String procedureSymbol() { - return "car"; - } - - @Override - public Sexp apply(Sexp sexp) { - return null; - } -} diff --git a/src/main/java/mylisp/proc/CarProcedure.java b/src/main/java/mylisp/proc/CarProcedure.java new file mode 100644 index 0000000..09102a7 --- /dev/null +++ b/src/main/java/mylisp/proc/CarProcedure.java @@ -0,0 +1,24 @@ +package mylisp.proc; + +import mylisp.core.IPair; +import mylisp.core.Procedure; +import mylisp.core.Sexp; + +public class CarProcedure implements Procedure { + @Override + public String procedureSymbol() { + return "car"; + } + + @Override + public Sexp apply(Sexp sexp) throws ProcedureException { + checkArgument(sexp); + return ((IPair) sexp).getCar(); + } + + public void checkArgument(Sexp sexp) throws ProcedureException { + if(!(sexp instanceof IPair)){ + throw new ProcedureException(String.format("not array [%s] is not a function [%s]", sexp, procedureSymbol())); + } + } +} diff --git a/src/main/java/mylisp/proc/CdrProcedure.java b/src/main/java/mylisp/proc/CdrProcedure.java new file mode 100644 index 0000000..42dd969 --- /dev/null +++ b/src/main/java/mylisp/proc/CdrProcedure.java @@ -0,0 +1,24 @@ +package mylisp.proc; + +import mylisp.core.IPair; +import mylisp.core.Procedure; +import mylisp.core.Sexp; + +public class CdrProcedure implements Procedure { + @Override + public String procedureSymbol() { + return "cdr"; + } + + @Override + public Sexp apply(Sexp sexp) throws ProcedureException { + checkArgument(sexp); + return ((IPair) sexp).getCdr(); + } + + public void checkArgument(Sexp sexp) throws ProcedureException { + if(!(sexp instanceof IPair)){ + throw new ProcedureException(String.format("not array [%s] is not a function [%s]", sexp, procedureSymbol())); + } + } +} diff --git a/src/test/java/mylisp/MyLispTest.java b/src/test/java/mylisp/MyLispTest.java index 6d53c17..d4ab837 100644 --- a/src/test/java/mylisp/MyLispTest.java +++ b/src/test/java/mylisp/MyLispTest.java @@ -1,8 +1,7 @@ package mylisp; import mylisp.core.*; -import mylisp.func.AddFunction; -import mylisp.func.CarProcedure; +import mylisp.proc.CarProcedure; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -10,14 +9,14 @@ public class MyLispTest { @Test - void apply() throws Atom.AtomException { + void apply() throws Atom.AtomException, Procedure.ProcedureException { Procedure proc = new CarProcedure(); - Sexp args = MyLispParser.parses("(1 2 3)")[0]; - Sexp expect = MyLispParser.parses("1")[0]; + Sexp args = new ConsCell(Atom.newAtom(1), new ConsCell(Atom.newAtom(2), new ConsCell(Atom.newAtom(3), AtomNil.INSTANCE))); + Sexp expect = Atom.newAtom(1); - Sexp ret = MyLisp.apply(proc, args); + Sexp ret = new MyLisp().apply(proc, args); assertEquals(expect, ret); } } diff --git a/src/test/java/mylisp/func/CarProcedureTest.java b/src/test/java/mylisp/func/CarProcedureTest.java deleted file mode 100644 index d986da9..0000000 --- a/src/test/java/mylisp/func/CarProcedureTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package mylisp.func; - -import mylisp.core.Atom; -import mylisp.core.ConsCell; -import mylisp.core.Procedure; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static org.junit.jupiter.api.Assertions.*; - -class CarProcedureTest { - - @Test - void procedureSymbol() { - assertEquals("car", new CarProcedure().procedureSymbol()); - } - - @ParameterizedTest - @CsvSource({ - "'1', '2'", - }) - void apply(String first, String second) throws Atom.AtomException { - Procedure proc = new CarProcedure(); - assertEquals(Atom.newAtom(first), proc.apply(new ConsCell(Atom.newAtom(first), Atom.newAtom(second)))); - } -} \ No newline at end of file diff --git a/src/test/java/mylisp/proc/CarProcedureTest.java b/src/test/java/mylisp/proc/CarProcedureTest.java new file mode 100644 index 0000000..c79165c --- /dev/null +++ b/src/test/java/mylisp/proc/CarProcedureTest.java @@ -0,0 +1,33 @@ +package mylisp.proc; + +import mylisp.MyLispParser; +import mylisp.core.Atom; +import mylisp.core.Procedure; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CarProcedureTest { + + @Test + void procedureSymbol() { + assertEquals("car", new CarProcedure().procedureSymbol()); + } + + @ParameterizedTest + @CsvSource({ + "'(1)', '1'", + "'(1 2)', '1'", + "'(1 2 3)', '1'", + "'((1 2) 3 4 5)', '(1 2)'", + "'(())', '()'", + "'((() ()) ())', '(() ())'", + "'((()) (() ()) ())', '(())'", + }) + void apply(String actual, String expected) throws Atom.AtomException, Procedure.ProcedureException { + Procedure proc = new CarProcedure(); + assertEquals(MyLispParser.parses(expected)[0], proc.apply(MyLispParser.parses(actual)[0])); + } +} \ No newline at end of file diff --git a/src/test/java/mylisp/proc/CdrProcedureTest.java b/src/test/java/mylisp/proc/CdrProcedureTest.java new file mode 100644 index 0000000..5ccccb0 --- /dev/null +++ b/src/test/java/mylisp/proc/CdrProcedureTest.java @@ -0,0 +1,33 @@ +package mylisp.proc; + +import mylisp.MyLispParser; +import mylisp.core.Atom; +import mylisp.core.Procedure; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.*; + +class CdrProcedureTest { + + @Test + void procedureSymbol() { + assertEquals("cdr", new CdrProcedure().procedureSymbol()); + } + + @ParameterizedTest + @CsvSource({ + "'(1)', '()'", + "'(1 2)', '(2)'", + "'(1 2 3)', '(2 3)'", + "'((1 2) 3 4 5)', '(3 4 5)'", + "'(())', '()'", + "'((() ()) ())', '(())'", + "'((()) (() ()) ())', '((() ()) ())'", + }) + void apply(String actual, String expected) throws Atom.AtomException, Procedure.ProcedureException { + Procedure proc = new CdrProcedure(); + assertEquals(MyLispParser.parses(expected)[0], proc.apply(MyLispParser.parses(actual)[0])); + } +} \ No newline at end of file From 7208ca6549dd727f03c4998f121d8ba148d0acad Mon Sep 17 00:00:00 2001 From: moremagic Date: Thu, 11 Feb 2021 00:05:22 +0900 Subject: [PATCH 05/10] =?UTF-8?q?=E3=83=91=E3=83=BC=E3=82=B9=E3=81=97?= =?UTF-8?q?=E3=81=9F=E6=99=82=E3=81=A8=E3=82=B9=E3=83=9A=E3=82=B7=E3=83=A3?= =?UTF-8?q?=E3=83=AB=E3=83=95=E3=82=A9=E3=83=BC=E3=83=A0=E5=AE=9F=E6=96=BD?= =?UTF-8?q?=E5=BE=8C=E3=81=AENil=E3=81=AE=E5=8F=96=E3=82=8A=E6=89=B1?= =?UTF-8?q?=E3=81=84=E3=82=92=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/mylisp/MyLispParser.java | 4 +--- src/main/java/mylisp/core/ConsCell.java | 12 ++++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/mylisp/MyLispParser.java b/src/main/java/mylisp/MyLispParser.java index c141a43..30a4231 100644 --- a/src/main/java/mylisp/MyLispParser.java +++ b/src/main/java/mylisp/MyLispParser.java @@ -66,8 +66,6 @@ private static Sexp parse(String sExps) throws Atom.AtomException { sExps = sExps.trim(); if (sExps.startsWith("(") && sExps.endsWith(")")) { return parseCell(sExps); - } else if (sExps.startsWith("\"")) { - return parseAtomString(sExps); } else if (sExps.startsWith("'")) { Sexp atom = parse(sExps.substring(1)); return new ConsCell(Atom.newAtom("quote"), new ConsCell(atom, AtomNil.INSTANCE)); @@ -161,7 +159,7 @@ private static Sexp parseCell(String sCell) throws Atom.AtomException { if (sexpList.isEmpty()) { // () の場合 - return new ConsCell(); + return AtomNil.INSTANCE; } else if (sexpList.get(0).toString().equals(Lambda.LAMBDA_SYMBOL)) { IPair cons = (IPair) ConsCell.createConsCell(sexpList.toArray(new Sexp[0])); return new Lambda(cons.getCar(), cons.getCdr()); diff --git a/src/main/java/mylisp/core/ConsCell.java b/src/main/java/mylisp/core/ConsCell.java index fb8a789..87663ce 100644 --- a/src/main/java/mylisp/core/ConsCell.java +++ b/src/main/java/mylisp/core/ConsCell.java @@ -77,7 +77,7 @@ public Sexp[] getList() { @Override public String toString() { - return String.format("(%s)",createConsString(this)); + return isNil() ? AtomNil.INSTANCE.toString() : String.format("(%s)", createConsString(this)); } @Override @@ -89,17 +89,17 @@ public boolean equals(Object object) { return false; } - private static String createConsString(IPair cons) { - if (cons.getCar() == AtomNil.INSTANCE) { - return ""; - } + private boolean isNil(){ + return car == AtomNil.INSTANCE && cdr == AtomNil.INSTANCE; + } + private static String createConsString(IPair cons) { if (cons.getCdr() instanceof Atom && cons.getCdr() != AtomNil.INSTANCE) { //Cdr が Atom の場合は Dotpair 表示を行うが Nil の場合は Dotpair 表示を行わない return String.format("%s . %s", cons.getCar(), cons.getCdr()); } else if (cons.getCdr() instanceof IPair) { return String.format("%s %s", cons.getCar(), createConsString((IPair) cons.getCdr())); - } else{ + } else { return String.format("%s", cons.getCar()); } } From 7b6913a2217b1eb7f5a5967669a19ee5e15c2826 Mon Sep 17 00:00:00 2001 From: moremagic Date: Thu, 11 Feb 2021 00:12:52 +0900 Subject: [PATCH 06/10] =?UTF-8?q?fixup!=20TODO=20=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/mylisp/MyLispParser.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/mylisp/MyLispParser.java b/src/main/java/mylisp/MyLispParser.java index 30a4231..e26d47a 100644 --- a/src/main/java/mylisp/MyLispParser.java +++ b/src/main/java/mylisp/MyLispParser.java @@ -6,6 +6,8 @@ import mylisp.core.*; /** + * TODO: あまりにも汚いので整理、再実装をしたい。 + * * @author moremagic */ public class MyLispParser { From 2d540974f7eed9d6bc1c17aa16548b239ccdaf82 Mon Sep 17 00:00:00 2001 From: moremagic Date: Thu, 11 Feb 2021 01:01:00 +0900 Subject: [PATCH 07/10] =?UTF-8?q?eval=E3=81=AE=E9=9B=9B=E5=BD=A2=E3=81=A8?= =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=81=AE=E9=9B=9B=E5=BD=A2=E3=82=92?= =?UTF-8?q?=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/mylisp/MyLisp.java | 1 + src/test/java/mylisp/MyLispTest.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/mylisp/MyLisp.java b/src/main/java/mylisp/MyLisp.java index 74f2461..2147621 100644 --- a/src/main/java/mylisp/MyLisp.java +++ b/src/main/java/mylisp/MyLisp.java @@ -215,6 +215,7 @@ public static Sexp apply(Sexp sexp, Map env) throws MyLispExce public Sexp eval2(Sexp sexp, Map env){ + //TODO 未実装 return null; } diff --git a/src/test/java/mylisp/MyLispTest.java b/src/test/java/mylisp/MyLispTest.java index d4ab837..2b1aaf4 100644 --- a/src/test/java/mylisp/MyLispTest.java +++ b/src/test/java/mylisp/MyLispTest.java @@ -19,4 +19,8 @@ void apply() throws Atom.AtomException, Procedure.ProcedureException { Sexp ret = new MyLisp().apply(proc, args); assertEquals(expect, ret); } + + @Test + void eval2() { + } } From 1811f88cd0ce4e17ff4a976589beccb54bbed8a3 Mon Sep 17 00:00:00 2001 From: moremagic Date: Fri, 12 Feb 2021 15:45:12 +0900 Subject: [PATCH 08/10] =?UTF-8?q?Cdr=20prc=20=E3=81=AE=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/mylisp/proc/CdrProcedureTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/mylisp/proc/CdrProcedureTest.java b/src/test/java/mylisp/proc/CdrProcedureTest.java index 5ccccb0..5f1de1b 100644 --- a/src/test/java/mylisp/proc/CdrProcedureTest.java +++ b/src/test/java/mylisp/proc/CdrProcedureTest.java @@ -1,5 +1,6 @@ package mylisp.proc; +import mylisp.MyLisp; import mylisp.MyLispParser; import mylisp.core.Atom; import mylisp.core.Procedure; @@ -30,4 +31,9 @@ void apply(String actual, String expected) throws Atom.AtomException, Procedure. Procedure proc = new CdrProcedure(); assertEquals(MyLispParser.parses(expected)[0], proc.apply(MyLispParser.parses(actual)[0])); } + + void errorApply(){ + Procedure proc = new CdrProcedure(); + assertThrows(Procedure.ProcedureException.class, () -> proc.apply(MyLispParser.parses("()")[0])); + } } \ No newline at end of file From 37776832cf76224add4a179ae68290385764d556 Mon Sep 17 00:00:00 2001 From: moremagic Date: Fri, 12 Feb 2021 15:45:32 +0900 Subject: [PATCH 09/10] =?UTF-8?q?eval=20=E3=81=AE=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/mylisp/MyLispTest.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/test/java/mylisp/MyLispTest.java b/src/test/java/mylisp/MyLispTest.java index 2b1aaf4..d0f34ad 100644 --- a/src/test/java/mylisp/MyLispTest.java +++ b/src/test/java/mylisp/MyLispTest.java @@ -3,6 +3,11 @@ import mylisp.core.*; import mylisp.proc.CarProcedure; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.HashMap; +import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -20,7 +25,16 @@ void apply() throws Atom.AtomException, Procedure.ProcedureException { assertEquals(expect, ret); } - @Test - void eval2() { + @ParameterizedTest + @CsvSource({ + "'(cdr '((car '(1 2)) 2)', '2'", + }) + void eval2(String value, String expect) throws Atom.AtomException { + Map map = new HashMap<>(); + Sexp sexp = MyLispParser.parses(value)[0]; + + Sexp ret = new MyLisp().eval2(sexp, map); + + assertEquals(MyLispParser.parses(expect)[0], ret); } } From f27093d302520c047e7a62e4e6372f59bb0f65a3 Mon Sep 17 00:00:00 2001 From: moremagic Date: Mon, 15 Feb 2021 19:00:42 +0900 Subject: [PATCH 10/10] =?UTF-8?q?=E5=85=A8=E4=BD=93=E7=9A=84=E3=81=AA?= =?UTF-8?q?=E6=9C=80=E9=81=A9=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/mylisp/MyLisp.java | 112 ++++++++++++++++-- src/main/java/mylisp/MyLispParser.java | 9 +- src/main/java/mylisp/core/ConsCell.java | 30 +++-- src/main/java/mylisp/core/Sexp.java | 6 +- src/test/java/mylisp/MyLispParserTest.java | 25 +++- src/test/java/mylisp/MyLispTest.java | 8 +- src/test/java/mylisp/core/AtomTest.java | 9 ++ src/test/java/mylisp/core/ConsCellTest.java | 66 ++++++++++- .../java/mylisp/proc/CdrProcedureTest.java | 13 +- 9 files changed, 244 insertions(+), 34 deletions(-) diff --git a/src/main/java/mylisp/MyLisp.java b/src/main/java/mylisp/MyLisp.java index 2147621..5ec7833 100644 --- a/src/main/java/mylisp/MyLisp.java +++ b/src/main/java/mylisp/MyLisp.java @@ -1,6 +1,9 @@ package mylisp; import mylisp.core.*; +import mylisp.func.*; +import mylisp.proc.CarProcedure; +import mylisp.proc.CdrProcedure; import java.io.*; import java.nio.charset.StandardCharsets; @@ -175,7 +178,7 @@ public static void tranporin(Sexp sexp, Map env) throws MyLisp /** * TODO: Apply の引数を使用に合わせ、Apply で スペシャルフォームを実施するように作り替える - * + *

* (apply proc arg1 . . . args) 手続き * proc は手続きでなければならず,args はリストでなければな * らない。proc を,リスト (append (list arg1 . . . ) args) @@ -187,8 +190,6 @@ public static void tranporin(Sexp sexp, Map env) throws MyLisp * (f (apply g args))))) * ((compose sqrt *) 12 75) =⇒ 30 * - * - * * @param sexp * @param env * @return @@ -214,12 +215,107 @@ public static Sexp apply(Sexp sexp, Map env) throws MyLispExce } - public Sexp eval2(Sexp sexp, Map env){ - //TODO 未実装 - return null; + /** + * eval + * 参考;https://sicp.iijlab.net/fulltext/x411.html + *

+ * 基本式 + * • 数値のような自己評価式に対してevalは式それ自身を返す. + * • evalは値を得るため, 環境で変数を探す必要がある. + *

+ * 特殊形式 + * • クォート式に対して, evalはクォートされている式を返す. + * • 変数への代入(または変数の定義)は変数に対応づける新しい値を計算するため, evalを再帰的に呼び出す必要がある. 変数の束縛を修正し(または作り出し)て環境を修正する. + * • if式は, 述語が真なら帰結式を評価し, そうでなければ代替式を評価するよう, 要素式の特別な処理を必要とする. + * • lambda式はlambda式が指定したパラメタと本体を, 評価の環境とともに詰め合せ, 作用可能な手続きへ変換する必要がある. + * • begin式は, 要素式の並びを現れる順に評価する必要がある. + * • condによる場合分けはif式の入れ子に変換してから評価する. + *

+ * TODO: SICP 問題4.3(p221) に対応する + * + * @param sexp 評価する式 + * @param env 環境 + * @return 評価された式 + * @throws EvalException 評価時にエラーとなった場合 + */ + public Sexp eval2(Sexp sexp, Map env) throws Procedure.ProcedureException, EvalException { + + //self-evaluating? : 自己評価式(単独で存在しうるAtom)かどうか + //if ((sexp instanceof IPair) && !sexp.isPair()) return eval2(((IPair) sexp).getCar(), env); + if ((sexp instanceof Atom) && !(sexp instanceof AtomSymbol) && !(sexp instanceof AtomPort)) return sexp; + + // valiable? : Symbol だった場合環境から値を探す + if (sexp instanceof AtomSymbol && env.containsKey(sexp)) return env.get(sexp); + + //quoted? : quote かどうか + // TODO: quote を実装する + if (sexp instanceof IPair && sexp.isPair() && ((IPair) sexp).getCar().toString().equals("quote")) { + //cadr を返却する + return eval2(((IPair) ((IPair) sexp).getCdr()).getCar(), env); + } + + //assignment? : set! かどうか + // TODO: set! を実装する + + //difinition? : define かどうか + // TODO: define を実装する + + //if? : if かどうか + //TODO if を実装する + + //lambbda? : lambda かどうか + //TODO lambda を実装する + + //begin? : begin かどうか + //TODO begin を実装する + + //cond? : cond かどうか + //TODO cond を実装する + + + if(sexp instanceof AtomSymbol)return sexp; + + //application? : pairだったら + if (sexp instanceof IPair && sexp.isPair()) { + + Sexp car = eval2(((IPair) sexp).getCar(), env); + return apply((AtomSymbol) car, + listOfValue(((IPair) sexp).getCdr(), env)); + } + + throw new EvalException(String.format("Unknown expression type -- EVAL: %s", sexp)); + } + + + public Sexp listOfValue(Sexp sexp, Map env) throws Procedure.ProcedureException, EvalException { + if (sexp instanceof IPair) { + IPair pair = (IPair) sexp; + + Sexp car = eval2(pair.getCar(), env); + return new ConsCell(car, listOfValue(pair.getCdr(), env)); + } + return sexp; } - public Sexp apply(Procedure proc, Sexp args) throws Procedure.ProcedureException { - return proc.apply(args); + public Sexp apply(AtomSymbol proc, Sexp args) throws Procedure.ProcedureException { + return getSpecialform(proc).apply(args); + } + + private static Procedure getSpecialform(AtomSymbol symbol) throws Procedure.ProcedureException { + Procedure[] procArray = { + new CarProcedure(), + new CdrProcedure() + }; + for (Procedure proc : procArray) { + if (symbol.toString().equals(proc.procedureSymbol())) return proc; + } + throw new Procedure.ProcedureException(String.format("Unknown procedure type -- APPLY: %s", symbol)); + } + + + public static class EvalException extends MyLispException { + public EvalException(String message) { + super(message); + } } } diff --git a/src/main/java/mylisp/MyLispParser.java b/src/main/java/mylisp/MyLispParser.java index e26d47a..b08d7ba 100644 --- a/src/main/java/mylisp/MyLispParser.java +++ b/src/main/java/mylisp/MyLispParser.java @@ -69,8 +69,8 @@ private static Sexp parse(String sExps) throws Atom.AtomException { if (sExps.startsWith("(") && sExps.endsWith(")")) { return parseCell(sExps); } else if (sExps.startsWith("'")) { - Sexp atom = parse(sExps.substring(1)); - return new ConsCell(Atom.newAtom("quote"), new ConsCell(atom, AtomNil.INSTANCE)); + Sexp sexp = parse(sExps.substring(1)); + return new ConsCell(Atom.newAtom("quote"), new ConsCell(sexp, AtomNil.INSTANCE)); } else { return parseAtom(sExps); } @@ -136,10 +136,11 @@ private static Sexp parseCell(String sCell) throws Atom.AtomException { case ")": break label; case "'": { - Sexp atom = parse(sCell.substring(i + 1)); + Sexp atom = parse(sCell.substring(i)); i += getAtomLength(sCell.substring(i + 1)) + 1; - sexpList.add(new ConsCell(Atom.newAtom("quote"), new ConsCell(atom, AtomNil.INSTANCE))); + sexpList.add(atom); + break; } case "\"": { diff --git a/src/main/java/mylisp/core/ConsCell.java b/src/main/java/mylisp/core/ConsCell.java index 87663ce..70a9c01 100644 --- a/src/main/java/mylisp/core/ConsCell.java +++ b/src/main/java/mylisp/core/ConsCell.java @@ -69,15 +69,24 @@ public Sexp[] getList() { ret.add(this.car); if (this.cdr != null && this.cdr != AtomNil.INSTANCE) { - ret.addAll(Arrays.asList(this.cdr.getList())); + ret.addAll(Arrays.asList(cdr.getList())); } return ret.toArray(new Sexp[0]); } + @Override + public boolean isPair() { + return cdr != AtomNil.INSTANCE; + } + @Override public String toString() { - return isNil() ? AtomNil.INSTANCE.toString() : String.format("(%s)", createConsString(this)); + if (isNil()){ + return AtomNil.INSTANCE.toString(); + } else { + return String.format("(%s)", createConsString(this)); + } } @Override @@ -89,7 +98,7 @@ public boolean equals(Object object) { return false; } - private boolean isNil(){ + private boolean isNil() { return car == AtomNil.INSTANCE && cdr == AtomNil.INSTANCE; } @@ -97,11 +106,18 @@ private static String createConsString(IPair cons) { if (cons.getCdr() instanceof Atom && cons.getCdr() != AtomNil.INSTANCE) { //Cdr が Atom の場合は Dotpair 表示を行うが Nil の場合は Dotpair 表示を行わない return String.format("%s . %s", cons.getCar(), cons.getCdr()); - } else if (cons.getCdr() instanceof IPair) { - return String.format("%s %s", cons.getCar(), createConsString((IPair) cons.getCdr())); - } else { - return String.format("%s", cons.getCar()); } + + StringBuilder sb = new StringBuilder(); +Sexp[] buf = cons.getList(); + for (Sexp sexp : cons.getList()) { + if (sexp instanceof ConsCell) { + sb.append(String.format(" %s", ((ConsCell) sexp).toString())); + } else { + sb.append(String.format(" %s", sexp.toString())); + } + } + return sb.toString().trim(); } diff --git a/src/main/java/mylisp/core/Sexp.java b/src/main/java/mylisp/core/Sexp.java index 69203ef..0b39264 100644 --- a/src/main/java/mylisp/core/Sexp.java +++ b/src/main/java/mylisp/core/Sexp.java @@ -7,8 +7,10 @@ */ public interface Sexp { //TODO: ListではなくArray - public Sexp[] getList(); + Sexp[] getList(); + + default boolean isPair(){return false;} @Override - public abstract String toString(); + String toString(); } diff --git a/src/test/java/mylisp/MyLispParserTest.java b/src/test/java/mylisp/MyLispParserTest.java index fe70385..3df06ff 100644 --- a/src/test/java/mylisp/MyLispParserTest.java +++ b/src/test/java/mylisp/MyLispParserTest.java @@ -23,10 +23,21 @@ public void consCellParseTest() throws Atom.AtomException { public void nestConsCellParseTest() throws Atom.AtomException { Sexp[] ret = MyLispParser.parses("(+ 2 (+ 3 4 (+ 5 6)))"); Sexp actual = ret[0]; - Sexp expect = new ConsCell(Atom.newAtom("+"), new ConsCell(Atom.newAtom(2), - new ConsCell(new ConsCell(Atom.newAtom("+"), new ConsCell(Atom.newAtom(3), new ConsCell(Atom.newAtom(4), - new ConsCell(new ConsCell(Atom.newAtom("+"), new ConsCell(Atom.newAtom(5), new ConsCell(Atom.newAtom(6) - , AtomNil.INSTANCE))), AtomNil.INSTANCE)))), AtomNil.INSTANCE))); + + Sexp sexp56 = new ConsCell(Atom.newAtom("+"), + new ConsCell(Atom.newAtom(5), + new ConsCell(Atom.newAtom(6), AtomNil.INSTANCE))); + + Sexp sexp34 = new ConsCell(Atom.newAtom("+"), + new ConsCell(Atom.newAtom(3), + new ConsCell(Atom.newAtom(4), + new ConsCell(sexp56, AtomNil.INSTANCE)))); + + Sexp sexp2 = new ConsCell(Atom.newAtom("+"), + new ConsCell(Atom.newAtom(2), + new ConsCell(sexp34, AtomNil.INSTANCE))); + Sexp expect = sexp2; + assertEquals(actual, expect); } @@ -45,6 +56,8 @@ public void dotPairParseTest() throws Atom.AtomException { @ParameterizedTest @CsvSource({ + "(1 '2 3), (1 (quote 2) 3)", + "(salada 'hoge), (salada (quote hoge))", "(), ()", "(#t), (#t)", "(#f), (#f)", @@ -54,6 +67,9 @@ public void dotPairParseTest() throws Atom.AtomException { "(1 2 3), (1 2 3)", "(+ 2 3), (+ 2 3)", "(quote (eq? a #f)), (quote (eq? a #f))", //quote省略記法(') の指定方法が不明のためとりあえずそのまま + "(1 '2 3), (1 (quote 2) 3)", + "'(1 '2 3), (quote (1 (quote 2) 3))", + "(car '(1 2 3)),(car (quote (1 2 3)))", "'#\\(', '('", "'#\\)', ')'", "'#\\a', 'a'", @@ -63,7 +79,6 @@ public void dotPairParseTest() throws Atom.AtomException { "(if (eq? (< 1 2) #t) (display \"OK\") (display \"NG\")), (if (eq? (< 1 2) #t) (display \"OK\") (display \"NG\"))", "(define (type1 filename) (let ((iport (open-input-file filename))) (let loop ((c (read-char iport))) (cond ((not (eof-object? c)) (display c) (loop (read-char iport))))) (close-input-port iport))), (define (type1 filename) (let ((iport (open-input-file filename))) (let loop ((c (read-char iport))) (cond ((not (eof-object? c)) (display c) (loop (read-char iport))))) (close-input-port iport)))", "(\"aa bb cc & (asdf) '(asdfasd) \' \\\" \" aaa), (\"aa bb cc & (asdf) '(asdfasd) \' \\\" \" aaa)", - "'(1 '2 3), (quote (1 (quote 2) 3))", "(let loop((n1 n) (p n))), (let loop ((n1 n) (p n)))", "(\" a b c '() '(quote) \\\" \" aaa), (\" a b c '() '(quote) \\\" \" aaa)", "('a 'b 'c ('d 'e)), ((quote a) (quote b) (quote c) ((quote d) (quote e)))", diff --git a/src/test/java/mylisp/MyLispTest.java b/src/test/java/mylisp/MyLispTest.java index d0f34ad..3f30065 100644 --- a/src/test/java/mylisp/MyLispTest.java +++ b/src/test/java/mylisp/MyLispTest.java @@ -21,15 +21,17 @@ void apply() throws Atom.AtomException, Procedure.ProcedureException { Sexp args = new ConsCell(Atom.newAtom(1), new ConsCell(Atom.newAtom(2), new ConsCell(Atom.newAtom(3), AtomNil.INSTANCE))); Sexp expect = Atom.newAtom(1); - Sexp ret = new MyLisp().apply(proc, args); + Sexp ret = new MyLisp().apply((AtomSymbol) Atom.newAtom(proc.procedureSymbol()), args); assertEquals(expect, ret); } @ParameterizedTest @CsvSource({ - "'(cdr '((car '(1 2)) 2)', '2'", + "(car '(1)), 1", + "(car '(1 2 3)), 1", + "(cdr '(1 (car '(2 3 4)))), 2", }) - void eval2(String value, String expect) throws Atom.AtomException { + void eval2(String value, String expect) throws Atom.AtomException, Procedure.ProcedureException, MyLisp.EvalException { Map map = new HashMap<>(); Sexp sexp = MyLispParser.parses(value)[0]; diff --git a/src/test/java/mylisp/core/AtomTest.java b/src/test/java/mylisp/core/AtomTest.java index 2b78c65..5f84ad1 100644 --- a/src/test/java/mylisp/core/AtomTest.java +++ b/src/test/java/mylisp/core/AtomTest.java @@ -25,6 +25,7 @@ void newAtomForBoolean(String value) throws Atom.AtomException { void newAtomForBoolean(boolean value) throws Atom.AtomException { Atom expect = Atom.newAtom(value); assertEquals(AtomBoolean.class, expect.getClass()); + assertFalse(expect.isPair()); } @ParameterizedTest @@ -32,6 +33,7 @@ void newAtomForBoolean(boolean value) throws Atom.AtomException { void newAtomforNumber(int value) throws Atom.AtomException { Atom expect = Atom.newAtom(value); assertEquals(AtomNumber.class, expect.getClass()); + assertFalse(expect.isPair()); } @ParameterizedTest @@ -39,6 +41,7 @@ void newAtomforNumber(int value) throws Atom.AtomException { void newAtomforNumber(long value) throws Atom.AtomException { Atom expect = Atom.newAtom(value); assertEquals(AtomNumber.class, expect.getClass()); + assertFalse(expect.isPair()); } @ParameterizedTest @@ -46,6 +49,7 @@ void newAtomforNumber(long value) throws Atom.AtomException { void newAtomForNumber(double value) throws Atom.AtomException { Atom expect = Atom.newAtom(value); assertEquals(AtomNumber.class, expect.getClass()); + assertFalse(expect.isPair()); } @ParameterizedTest @@ -58,6 +62,7 @@ void newAtomForNumber(double value) throws Atom.AtomException { void newAtomForNumber(String value) throws Atom.AtomException { Atom expect = Atom.newAtom(value); assertEquals(AtomNumber.class, expect.getClass()); + assertFalse(expect.isPair()); } @Test @@ -77,6 +82,7 @@ public void write(int b) throws IOException { } }); assertEquals(AtomPort.class, expect_outputstream.getClass()); + assertFalse(expect_inputstream.isPair()); } @ParameterizedTest @@ -91,6 +97,7 @@ public void write(int b) throws IOException { void newAtomString(String value) throws Atom.AtomException { Atom expect = Atom.newAtom(value); assertEquals(AtomString.class, expect.getClass()); + assertFalse(expect.isPair()); } @ParameterizedTest @@ -105,6 +112,7 @@ void newAtomString(String value) throws Atom.AtomException { void newAtomSymbol(String value) throws Atom.AtomException { Atom expect = Atom.newAtom(value); assertEquals(AtomSymbol.class, expect.getClass()); + assertFalse(expect.isPair()); } @ParameterizedTest @@ -125,6 +133,7 @@ void newAtomSymbol(String value) throws Atom.AtomException { void newAtomChar(String value) throws Atom.AtomException { Atom expect = Atom.newAtom(value); assertEquals(AtomChar.class, expect.getClass()); + assertFalse(expect.isPair()); } diff --git a/src/test/java/mylisp/core/ConsCellTest.java b/src/test/java/mylisp/core/ConsCellTest.java index 34255d3..52960ea 100644 --- a/src/test/java/mylisp/core/ConsCellTest.java +++ b/src/test/java/mylisp/core/ConsCellTest.java @@ -14,6 +14,51 @@ class ConsCellTest { + @Test + public void toStringTest1() throws Atom.AtomException { + String expect = "(+ 2 (+ 3 4 (+ 5 6)))"; + + Sexp sexp56 = new ConsCell(Atom.newAtom("+"), + new ConsCell(Atom.newAtom(5), + new ConsCell(Atom.newAtom(6), AtomNil.INSTANCE))); + + Sexp sexp34 = new ConsCell(Atom.newAtom("+"), + new ConsCell(Atom.newAtom(3), + new ConsCell(Atom.newAtom(4), + new ConsCell(sexp56, AtomNil.INSTANCE)))); + + Sexp sexp2 = new ConsCell(Atom.newAtom("+"), + new ConsCell(Atom.newAtom(2), + new ConsCell(sexp34, AtomNil.INSTANCE))); + Sexp actual = sexp2; + + + assertEquals(actual.toString(), expect); + } + + @Test + public void toStringTest2() throws Atom.AtomException { + String expect = "(((+ 1 2) 3 4) 5 6)"; + + Sexp sexp12 = new ConsCell(Atom.newAtom("+"), + new ConsCell(Atom.newAtom(1), + new ConsCell(Atom.newAtom(2), AtomNil.INSTANCE))); + + Sexp sexp34 = new ConsCell(sexp12, + new ConsCell(Atom.newAtom(3), + new ConsCell(Atom.newAtom(4), AtomNil.INSTANCE))); + + Sexp sexp56 = new ConsCell(sexp34, + new ConsCell(Atom.newAtom(5), + new ConsCell(Atom.newAtom(6), AtomNil.INSTANCE))); + + Sexp actual = sexp56; + + + assertEquals(actual.toString(), expect); + } + + @ParameterizedTest @CsvSource({ "'123', '456'", @@ -24,6 +69,7 @@ class ConsCellTest { void getCar(String first, String second) throws Atom.AtomException { ConsCell consCell = new ConsCell(Atom.newAtom(first), Atom.newAtom(second)); assertEquals(Atom.newAtom(first), consCell.getCar()); + assertTrue(consCell.isPair()); } @ParameterizedTest @@ -36,6 +82,8 @@ void getCar(String first, String second) throws Atom.AtomException { void setCar(String value) throws Atom.AtomException { ConsCell consCell = new ConsCell(); consCell.setCar(Atom.newAtom(value)); + + assertFalse(consCell.isPair()); assertEquals(Atom.newAtom(value), consCell.getCar()); } @@ -48,6 +96,8 @@ void setCar(String value) throws Atom.AtomException { }) void getCdr(String first, String second) throws Atom.AtomException { ConsCell consCell = new ConsCell(Atom.newAtom(first), Atom.newAtom(second)); + + assertTrue(consCell.isPair()); assertEquals(Atom.newAtom(second), consCell.getCdr()); } @@ -59,8 +109,12 @@ void getCdr(String first, String second) throws Atom.AtomException { "123", }) void setCdr(String value) throws Atom.AtomException { - ConsCell consCell = new ConsCell(); + ConsCell consCell = new ConsCell(AtomBoolean.newAtom("a"), AtomNil.INSTANCE); + assertFalse(consCell.isPair()); + consCell.setCdr(Atom.newAtom(value)); + + assertTrue(consCell.isPair()); assertEquals(Atom.newAtom(value), consCell.getCdr()); } @@ -84,6 +138,8 @@ void getList(String first, String second) throws Atom.AtomException { consCell.setCdr(new ConsCell(Atom.newAtom(first), consCell.getCdr())); } + assertTrue(consCell.isPair()); + //Sexp の数が一致していることを確認 assertEquals(count + 1, consCell.getList().length); @@ -106,6 +162,8 @@ void testEquals(String first, String second) throws Atom.AtomException { ConsCell a = new ConsCell(Atom.newAtom(first), Atom.newAtom(second)); ConsCell b = new ConsCell(Atom.newAtom(first), Atom.newAtom(second)); + assertTrue(a.isPair()); + assertTrue(b.isPair()); assertNotSame(a, b); assertEquals(a, b); } @@ -119,7 +177,9 @@ void testEquals(String first, String second) throws Atom.AtomException { }) void testDotPairToString(String first, String second) throws Atom.AtomException { ConsCell consCell = new ConsCell(Atom.newAtom(first), Atom.newAtom(second)); - assertEquals( String.format("(%s . %s)", first, second), consCell.toString()); + + assertTrue(consCell.isPair()); + assertEquals(String.format("(%s . %s)", first, second), consCell.toString()); } @ParameterizedTest @@ -133,6 +193,8 @@ void createConsCell(String first, String second) throws Atom.AtomException { ConsCell expect = new ConsCell(Atom.newAtom(first), new ConsCell(Atom.newAtom(second), AtomNil.getInstance())); ConsCell actual = ConsCell.createConsCell(new Sexp[]{Atom.newAtom(first), Atom.newAtom(second)}); + assertTrue(expect.isPair()); + assertTrue(actual.isPair()); assertEquals(expect, actual); } } \ No newline at end of file diff --git a/src/test/java/mylisp/proc/CdrProcedureTest.java b/src/test/java/mylisp/proc/CdrProcedureTest.java index 5f1de1b..f873035 100644 --- a/src/test/java/mylisp/proc/CdrProcedureTest.java +++ b/src/test/java/mylisp/proc/CdrProcedureTest.java @@ -1,14 +1,15 @@ package mylisp.proc; -import mylisp.MyLisp; import mylisp.MyLispParser; import mylisp.core.Atom; import mylisp.core.Procedure; +import mylisp.core.Sexp; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class CdrProcedureTest { @@ -26,10 +27,16 @@ void procedureSymbol() { "'(())', '()'", "'((() ()) ())', '(())'", "'((()) (() ()) ())', '((() ()) ())'", + "(cdr '(1 2 3)),((quote (1 2 3)))", + "(hoge (fuga 1 2 3)),((fuga 1 2 3)))", }) void apply(String actual, String expected) throws Atom.AtomException, Procedure.ProcedureException { Procedure proc = new CdrProcedure(); - assertEquals(MyLispParser.parses(expected)[0], proc.apply(MyLispParser.parses(actual)[0])); + + Sexp actualSexp = MyLispParser.parses(actual)[0]; + Sexp expectSexp = MyLispParser.parses(expected)[0]; + + assertEquals(expectSexp, proc.apply(MyLispParser.parses(actual)[0])); } void errorApply(){