├── .gitignore ├── LICENSE ├── pom.xml ├── readme.md └── src ├── main └── java │ └── jaskell │ ├── croupier │ ├── BinaryRanked.java │ ├── BinaryScaled.java │ ├── Croupier.java │ ├── Damping.java │ ├── FairPoker.java │ ├── Inverted.java │ ├── LiteScaled.java │ ├── Poker.java │ ├── Rank.java │ ├── Ranked.java │ ├── Scale.java │ ├── Scaled.java │ └── ZipScaled.java │ ├── expression │ ├── Add.java │ ├── Binary.java │ ├── Divide.java │ ├── Env.java │ ├── Expression.java │ ├── ExpressionException.java │ ├── Number.java │ ├── Parameter.java │ ├── Product.java │ ├── Quote.java │ ├── Sub.java │ └── parser │ │ ├── A.java │ │ ├── D.java │ │ ├── N.java │ │ ├── P.java │ │ ├── Param.java │ │ ├── Parser.java │ │ ├── Q.java │ │ └── S.java │ ├── parsec │ ├── Ahead.java │ ├── Atom.java │ ├── Attempt.java │ ├── Between.java │ ├── Binder.java │ ├── Ch.java │ ├── ChIn.java │ ├── ChNone.java │ ├── Choice.java │ ├── Combinator.java │ ├── Crlf.java │ ├── Decimal.java │ ├── Digit.java │ ├── EndOfLine.java │ ├── Eof.java │ ├── Eq.java │ ├── Fail.java │ ├── Find.java │ ├── Int.java │ ├── JoinCharacters.java │ ├── JoinText.java │ ├── Many.java │ ├── Many1.java │ ├── ManyTill.java │ ├── NCh.java │ ├── Ne.java │ ├── Neighborhood.java │ ├── Newline.java │ ├── NoWhitespace.java │ ├── NoneOf.java │ ├── One.java │ ├── OneOf.java │ ├── Option.java │ ├── Parsec.java │ ├── ParsecException.java │ ├── Return.java │ ├── SepBy.java │ ├── SepBy1.java │ ├── SimpleState.java │ ├── Skip.java │ ├── Skip1.java │ ├── SkipSpaces.java │ ├── SkipWhitespaces.java │ ├── Space.java │ ├── State.java │ ├── Text.java │ ├── Txt.java │ ├── UDecimal.java │ ├── UInt.java │ ├── Whitespace.java │ └── common │ │ ├── Ahead.java │ │ ├── Atom.java │ │ ├── Attempt.java │ │ ├── Between.java │ │ ├── Binder.java │ │ ├── Ch.java │ │ ├── ChIn.java │ │ ├── ChNone.java │ │ ├── Choice.java │ │ ├── Combinator.java │ │ ├── Crlf.java │ │ ├── Decimal.java │ │ ├── Digit.java │ │ ├── EndOfLine.java │ │ ├── Enumerate.java │ │ ├── Eof.java │ │ ├── Eq.java │ │ ├── Fail.java │ │ ├── Find.java │ │ ├── Int.java │ │ ├── Is.java │ │ ├── JoinCharacters.java │ │ ├── JoinText.java │ │ ├── Letter.java │ │ ├── Many.java │ │ ├── Many1.java │ │ ├── ManyTill.java │ │ ├── NCh.java │ │ ├── Ne.java │ │ ├── Newline.java │ │ ├── NoWhitespace.java │ │ ├── NoneOf.java │ │ ├── One.java │ │ ├── OneOf.java │ │ ├── Option.java │ │ ├── Parsec.java │ │ ├── Return.java │ │ ├── ScNumber.java │ │ ├── SepBy.java │ │ ├── SepBy1.java │ │ ├── SimpleState.java │ │ ├── Skip.java │ │ ├── Skip1.java │ │ ├── Skip1Spaces.java │ │ ├── Skip1Whitespaces.java │ │ ├── SkipSpaces.java │ │ ├── SkipWhitespaces.java │ │ ├── Space.java │ │ ├── State.java │ │ ├── Text.java │ │ ├── Txt.java │ │ ├── TxtState.java │ │ ├── UDecimal.java │ │ ├── UInt.java │ │ └── Whitespace.java │ ├── script │ ├── Directive.java │ └── Parameter.java │ ├── sql │ ├── Alias.java │ ├── And.java │ ├── Binary.java │ ├── Brackets.java │ ├── By.java │ ├── Case.java │ ├── Coalesce.java │ ├── Conflict.java │ ├── CouldAlias.java │ ├── CouldFrom.java │ ├── CouldGroup.java │ ├── CouldHaving.java │ ├── CouldJoin.java │ ├── CouldLimit.java │ ├── CouldOffset.java │ ├── CouldOrder.java │ ├── CouldReturning.java │ ├── CouldUnion.java │ ├── CouldWhere.java │ ├── Count.java │ ├── Cross.java │ ├── Delete.java │ ├── Do.java │ ├── Equal.java │ ├── Exists.java │ ├── From.java │ ├── Full.java │ ├── Func.java │ ├── Great.java │ ├── GreateOrEqual.java │ ├── Group.java │ ├── Having.java │ ├── In.java │ ├── Inner.java │ ├── Insert.java │ ├── Into.java │ ├── IsNotNull.java │ ├── IsNull.java │ ├── JDBCParameter.java │ ├── Join.java │ ├── Left.java │ ├── Less.java │ ├── LessOrEqual.java │ ├── Like.java │ ├── Limit.java │ ├── Literal.java │ ├── Name.java │ ├── Not.java │ ├── NotEqual.java │ ├── Nothing.java │ ├── Offset.java │ ├── On.java │ ├── Or.java │ ├── Order.java │ ├── Predicate.java │ ├── Query.java │ ├── Quot.java │ ├── Returning.java │ ├── Right.java │ ├── SQL.java │ ├── Select.java │ ├── Statement.java │ ├── Sum.java │ ├── Text.java │ ├── ThenSelect.java │ ├── Union.java │ ├── Update.java │ ├── Using.java │ ├── Values.java │ ├── Where.java │ └── With.java │ └── util │ ├── BiConsumer.java │ ├── BiFunction.java │ ├── Consumer.java │ ├── Distance.java │ ├── Function.java │ ├── Function4.java │ ├── Function5.java │ ├── Function6.java │ ├── Function7.java │ ├── Function8.java │ ├── ReTriable.java │ ├── Result.java │ ├── Supplier.java │ ├── TriFunction.java │ ├── Triable.java │ ├── Try.java │ ├── Tuple.java │ ├── Tuple2.java │ ├── Tuple3.java │ ├── Tuple4.java │ ├── Tuple5.java │ ├── Tuple6.java │ ├── Tuple7.java │ ├── Tuple8.java │ └── ZipHelper.java └── test └── java └── jaskell ├── Handler.java ├── Handler2.java ├── croupier └── CroupierTest.java ├── expression ├── ExpressionTest.java └── weak │ ├── Compare.java │ ├── Equals.java │ ├── Great.java │ ├── GreatOrEquals.java │ ├── Less.java │ ├── LessOrEquals.java │ ├── NotEquals.java │ ├── WeakExpressionTest.java │ └── parser │ ├── A.java │ ├── D.java │ ├── Eq.java │ ├── Grt.java │ ├── GrtOrEq.java │ ├── Ls.java │ ├── LsOrEq.java │ ├── N.java │ ├── NotEq.java │ ├── P.java │ ├── Param.java │ ├── Q.java │ ├── S.java │ └── WeakParser.java ├── parsec ├── AheadTest.java ├── AttemptTest.java ├── Base.java ├── BetweenTest.java ├── EofTest.java ├── EqTest.java ├── FindTest.java ├── InjectionTest.java ├── Many1Test.java ├── ManyTest.java ├── ManyTillTest.java ├── NewlineTest.java ├── NoneOfTest.java ├── OneOfTest.java ├── OneTest.java ├── ReturnTest.java ├── SepBy1Test.java ├── SepByTest.java ├── SimpleStateTest.java ├── Skip1Test.java ├── SkipTest.java ├── SpaceTest.java ├── TextTest.java ├── UIntTest.java └── common │ ├── AheadTest.java │ ├── AttemptTest.java │ ├── Base.java │ ├── BetweenTest.java │ ├── EnumerateTest.java │ ├── EofTest.java │ ├── EqTest.java │ ├── FindTest.java │ ├── IntTest.java │ ├── IsTest.java │ ├── Many1Test.java │ ├── ManyTest.java │ ├── ManyTillTest.java │ ├── NewlineTest.java │ ├── NoneOfTest.java │ ├── OneOfTest.java │ ├── OneTest.java │ ├── ReturnTest.java │ ├── SepBy1Test.java │ ├── SepByTest.java │ ├── SimpleStateTest.java │ ├── Skip1Test.java │ ├── SkipTest.java │ ├── SpaceTest.java │ ├── TextTest.java │ └── UIntTest.java ├── sql ├── JoinTest.java ├── SelectTest.java ├── WithTest.java └── WriteTest.java └── util ├── DistanceTest.java ├── ReTriableTest.java └── TryTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | target/ 3 | .idea/ 4 | *.iml 5 | *.class 6 | 7 | # Log file 8 | *.log 9 | 10 | # BlueJ files 11 | *.ctxt 12 | 13 | # Mobile Tools for Java (J2ME) 14 | .mtj.tmp/ 15 | 16 | # Package Files # 17 | *.jar 18 | *.war 19 | *.nar 20 | *.ear 21 | *.zip 22 | *.tar.gz 23 | *.rar 24 | 25 | 26 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 27 | hs_err_pid* 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mars Liu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/jaskell/croupier/Damping.java: -------------------------------------------------------------------------------- 1 | package jaskell.croupier; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.Random; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2023/03/28 18:53 13 | */ 14 | public class Damping implements Poker { 15 | private final Random random; 16 | 17 | public Damping(Random random) { 18 | this.random = random; 19 | } 20 | 21 | @Override 22 | public Optional select(List cards) { 23 | if (cards == null || cards.size() == 0) { 24 | return Optional.empty(); 25 | } 26 | if (cards.size() == 1) { 27 | return Optional.of(0); 28 | } 29 | double range = Math.log(cards.size() + 1); 30 | double value = random.nextDouble() * range; 31 | return Optional.of((int) Math.floor(Math.exp(value)) - 1); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/jaskell/croupier/FairPoker.java: -------------------------------------------------------------------------------- 1 | package jaskell.croupier; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.Random; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2023/03/28 18:53 13 | */ 14 | public class FairPoker implements Poker { 15 | private final Random random; 16 | 17 | public FairPoker(Random random) { 18 | this.random = random; 19 | } 20 | 21 | @Override 22 | public Optional select(List cards) { 23 | if (cards == null || cards.size() == 0) { 24 | return Optional.empty(); 25 | } 26 | return Optional.of(random.nextInt(cards.size())); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/jaskell/croupier/Inverted.java: -------------------------------------------------------------------------------- 1 | package jaskell.croupier; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.Random; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2023/03/28 18:53 13 | */ 14 | class Inverted implements Poker { 15 | private final Random random; 16 | 17 | public Inverted(Random random) { 18 | this.random = random; 19 | } 20 | 21 | @Override 22 | public Optional select(List cards) { 23 | if (cards == null || cards.size() == 0) { 24 | return Optional.empty(); 25 | } 26 | if (cards.size() == 1) { 27 | return Optional.of(0); 28 | } 29 | double range = Math.log(cards.size() + 1); 30 | double value = random.nextFloat() * range; 31 | int score = (cards.size() - (int) Math.floor(Math.exp(value))); 32 | return Optional.of(score); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/jaskell/croupier/Poker.java: -------------------------------------------------------------------------------- 1 | package jaskell.croupier; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | /** 7 | * TODO 8 | * 9 | * @author mars 10 | * @version 1.0.0 11 | * @since 2023/03/28 18:54 12 | */ 13 | public interface Poker { 14 | Optional select(List cards); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/jaskell/croupier/Rank.java: -------------------------------------------------------------------------------- 1 | package jaskell.croupier; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2023/03/28 18:52 9 | */ 10 | public interface Rank { 11 | double rank(T item); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/jaskell/croupier/Ranked.java: -------------------------------------------------------------------------------- 1 | package jaskell.croupier; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import java.util.Random; 7 | 8 | /** 9 | * TODO 10 | * 11 | * @author mars 12 | * @version 1.0.0 13 | * @since 2023/03/28 18:52 14 | */ 15 | public class Ranked implements Poker { 16 | private final Rank rank; 17 | 18 | private final Random random; 19 | 20 | public Ranked(Rank rank, Random random) { 21 | this.rank = rank; 22 | this.random = random; 23 | } 24 | 25 | @Override 26 | public Optional select(List cards) { 27 | if (cards == null || cards.isEmpty()) { 28 | return Optional.empty(); 29 | } 30 | if (cards.size() == 1) { 31 | return Optional.of(0); 32 | } 33 | 34 | List steps = new ArrayList<>(); 35 | steps.add(0d); 36 | for (T card : cards) { 37 | double weight = rank.rank(card); 38 | steps.add(weight + steps.get(steps.size() - 1)); 39 | } 40 | 41 | double score = random.nextDouble() * steps.get(steps.size() - 1); 42 | for (int idx = 0; idx < cards.size(); idx++) { 43 | if (steps.get(idx) <= score && steps.get(idx + 1) > score) { 44 | return Optional.of(idx); 45 | } 46 | } 47 | return Optional.of(cards.size() - 1); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/jaskell/croupier/Scale.java: -------------------------------------------------------------------------------- 1 | package jaskell.croupier; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2023/03/28 18:52 9 | */ 10 | public interface Scale { 11 | int weight(T item); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/jaskell/croupier/Scaled.java: -------------------------------------------------------------------------------- 1 | package jaskell.croupier; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import java.util.Random; 7 | 8 | /** 9 | * TODO 10 | * 11 | * @author mars 12 | * @version 1.0.0 13 | * @since 2023/03/28 18:53 14 | */ 15 | public class Scaled implements Poker { 16 | private final Scale scale; 17 | 18 | private final Random random; 19 | 20 | public Scaled(Scale scale, Random random) { 21 | this.scale = scale; 22 | this.random = random; 23 | } 24 | 25 | @Override 26 | public Optional select(List cards) { 27 | if (cards == null || cards.isEmpty()) { 28 | return Optional.empty(); 29 | } 30 | if (cards.size() == 1) { 31 | return Optional.of(0); 32 | } 33 | 34 | List steps = new ArrayList<>(); 35 | steps.add(0); 36 | for (T card : cards) { 37 | int weight = scale.weight(card); 38 | steps.add(weight + steps.get(steps.size() - 1)); 39 | } 40 | 41 | int score = random.nextInt(steps.get(steps.size() - 1)); 42 | for (int idx = 0; idx < cards.size(); idx++) { 43 | if (steps.get(idx) <= score && steps.get(idx + 1) > score) { 44 | return Optional.of(idx); 45 | } 46 | } 47 | return Optional.of(cards.size() - 1); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Add.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/04 10:57 9 | */ 10 | public class Add extends Binary { 11 | public Add(Expression left, Expression right) { 12 | this.left = left; 13 | this.right = right; 14 | } 15 | 16 | @Override 17 | public double eval(Env env) throws ExpressionException { 18 | return left.eval(env) + right.eval(env); 19 | } 20 | 21 | @Override 22 | public int getPriority() { 23 | return 1; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Binary.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/04 10:52 9 | */ 10 | public abstract class Binary implements Expression { 11 | protected Expression left; 12 | protected Expression right; 13 | 14 | public abstract int getPriority(); 15 | 16 | @Override 17 | public Expression makeAst() { 18 | this.left = this.left.makeAst(); 19 | this.right = this.right.makeAst(); 20 | if (right instanceof Binary) { 21 | Binary r = (Binary) right; 22 | if (this.getPriority() >= r.getPriority()) { 23 | Expression lx = r.left; 24 | this.right = lx; 25 | r.left = this; 26 | return r; 27 | } 28 | } 29 | return this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Divide.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/04 10:57 9 | */ 10 | public class Divide extends Binary { 11 | public Divide(Expression left, Expression right) { 12 | this.left = left; 13 | this.right = right; 14 | } 15 | 16 | @Override 17 | public double eval(Env env) throws ExpressionException { 18 | return left.eval(env) / right.eval(env); 19 | } 20 | 21 | @Override 22 | public int getPriority() { 23 | return 2; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Env.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Optional; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/06/10 18:03 13 | */ 14 | public class Env { 15 | private final Map data = new HashMap<>(); 16 | 17 | public void put(String name, Double value) { 18 | data.put(name, new Number(value)); 19 | } 20 | 21 | public void put(String name, Expression value) { 22 | data.put(name, value); 23 | } 24 | 25 | public Optional get(String name) { 26 | if(data.containsKey(name)){ 27 | return Optional.of(data.get(name)); 28 | } else { 29 | return Optional.empty(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Expression.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/04 10:51 9 | */ 10 | public interface Expression { 11 | double eval(Env env) throws ExpressionException; 12 | Expression makeAst(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/ExpressionException.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/10 18:05 9 | */ 10 | public class ExpressionException extends Exception { 11 | public ExpressionException(String message) { 12 | super(message); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Number.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/04 10:52 9 | */ 10 | public class Number implements Expression { 11 | final private java.lang.Number value; 12 | 13 | public Number(java.lang.Number value) { 14 | this.value = value; 15 | } 16 | 17 | @Override 18 | public double eval(Env env) { 19 | return value.doubleValue(); 20 | } 21 | 22 | @Override 23 | public Expression makeAst() { 24 | return this; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Parameter.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | import java.util.Optional; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/06/10 18:03 11 | */ 12 | public class Parameter implements Expression { 13 | private final String name; 14 | 15 | public Parameter(String name) { 16 | this.name = name; 17 | } 18 | 19 | @Override 20 | public double eval(Env env) throws ExpressionException { 21 | Optional value = env.get(name); 22 | if (value.isPresent()) { 23 | return value.get().eval(env); 24 | } else { 25 | throw new ExpressionException(name + " not found"); 26 | } 27 | } 28 | 29 | @Override 30 | public Expression makeAst() { 31 | return this; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Product.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/04 10:57 9 | */ 10 | public class Product extends Binary { 11 | public Product(Expression left, Expression right) { 12 | this.left = left; 13 | this.right = right; 14 | } 15 | 16 | @Override 17 | public double eval(Env env) throws ExpressionException { 18 | return left.eval(env) * right.eval(env); 19 | } 20 | 21 | @Override 22 | public int getPriority() { 23 | return 2; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Quote.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/04 11:25 9 | */ 10 | public class Quote implements Expression { 11 | private final Expression expression; 12 | 13 | public Quote(Expression expression) { 14 | this.expression = expression; 15 | } 16 | 17 | @Override 18 | public double eval(Env env) throws ExpressionException { 19 | return expression.eval(env); 20 | } 21 | 22 | @Override 23 | public Expression makeAst() { 24 | return new Quote(this.expression.makeAst()); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/Sub.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/04 10:57 9 | */ 10 | public class Sub extends Binary { 11 | public Sub(Expression left, Expression right) { 12 | this.left = left; 13 | this.right = right; 14 | } 15 | 16 | @Override 17 | public double eval(Env env) throws ExpressionException { 18 | return left.eval(env) - right.eval(env); 19 | } 20 | 21 | @Override 22 | public int getPriority() { 23 | return 1; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/parser/A.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.parser; 2 | 3 | import jaskell.expression.Add; 4 | import jaskell.expression.Expression; 5 | import jaskell.parsec.ParsecException; 6 | import jaskell.parsec.common.SkipWhitespaces; 7 | import jaskell.parsec.common.Parsec; 8 | import jaskell.parsec.common.State; 9 | 10 | import java.io.EOFException; 11 | 12 | import static jaskell.parsec.common.Txt.ch; 13 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/06/04 10:56 21 | */ 22 | public class A implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(ch('+')).then(skips); 25 | private final Expression prev; 26 | 27 | public A(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Add parse(State s) throws Exception { 33 | Parsec parser = new Parser(); 34 | op.parse(s); 35 | return new Add(prev, parser.parse(s)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/parser/D.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.parser; 2 | 3 | import static jaskell.parsec.common.Txt.ch; 4 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 5 | 6 | import jaskell.expression.Divide; 7 | import jaskell.expression.Expression; 8 | import jaskell.parsec.ParsecException; 9 | import jaskell.parsec.common.Parsec; 10 | import jaskell.parsec.common.SkipWhitespaces; 11 | import jaskell.parsec.common.State; 12 | 13 | import java.io.EOFException; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/06/04 10:56 21 | */ 22 | public class D implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(ch('/')).then(skips); 25 | private final Expression prev; 26 | 27 | public D(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Divide parse(State s) throws Exception { 33 | Parsec parser = new Parser(); 34 | op.parse(s); 35 | return new Divide(prev, parser.parse(s)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/parser/N.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.parser; 2 | 3 | import jaskell.expression.Expression; 4 | import jaskell.expression.Number; 5 | import jaskell.parsec.ParsecException; 6 | import jaskell.parsec.common.Parsec; 7 | import jaskell.parsec.common.ScNumber; 8 | import jaskell.parsec.common.State; 9 | 10 | import java.io.EOFException; 11 | 12 | 13 | /** 14 | * TODO 15 | * 16 | * @author mars 17 | * @version 1.0.0 18 | * @since 2020/06/04 10:53 19 | */ 20 | public class N implements Parsec { 21 | private final Parsec number = new ScNumber(); 22 | @Override 23 | public Number parse(State s) throws Exception { 24 | String re = number.parse(s); 25 | return new Number(Double.parseDouble(re)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/parser/P.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.parser; 2 | 3 | import static jaskell.parsec.common.Txt.ch; 4 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.Product; 8 | import jaskell.parsec.ParsecException; 9 | import jaskell.parsec.common.Parsec; 10 | import jaskell.parsec.common.SkipWhitespaces; 11 | import jaskell.parsec.common.State; 12 | 13 | import java.io.EOFException; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/06/04 10:56 21 | */ 22 | public class P implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(ch('*')).then(skips); 25 | private final Expression prev; 26 | 27 | public P(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Product parse(State s) throws Exception { 33 | Parsec parser = new Parser(); 34 | op.parse(s); 35 | return new Product(prev, parser.parse(s)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/parser/Param.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.parser; 2 | 3 | import static jaskell.parsec.common.Combinator.attempt; 4 | import static jaskell.parsec.common.Combinator.choice; 5 | import static jaskell.parsec.common.Combinator.many; 6 | import static jaskell.parsec.common.Txt.digit; 7 | import static jaskell.parsec.common.Txt.joining; 8 | import static jaskell.parsec.common.Txt.letter; 9 | 10 | import jaskell.expression.Expression; 11 | import jaskell.expression.Parameter; 12 | import jaskell.parsec.ParsecException; 13 | import jaskell.parsec.common.Parsec; 14 | import jaskell.parsec.common.State; 15 | 16 | import java.io.EOFException; 17 | 18 | /** 19 | * TODO 20 | * 21 | * @author mars 22 | * @version 1.0.0 23 | * @since 2020/06/10 17:54 24 | */ 25 | public class Param implements Parsec { 26 | private final Parsec head = letter(); 27 | 28 | private final Parsec tail = many(choice(attempt(head), digit())).bind(joining()); 29 | 30 | private final Parsec parser = s -> head.parse(s) + tail.parse(s); 31 | 32 | @Override 33 | public Expression parse(State s) throws Exception { 34 | return new Parameter(parser.parse(s)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/parser/Q.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.parser; 2 | 3 | import jaskell.expression.Expression; 4 | import jaskell.expression.Quote; 5 | import jaskell.parsec.ParsecException; 6 | import jaskell.parsec.common.Parsec; 7 | import jaskell.parsec.common.SkipWhitespaces; 8 | import jaskell.parsec.common.State; 9 | 10 | import java.io.EOFException; 11 | 12 | import static jaskell.parsec.common.Txt.ch; 13 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 14 | import static jaskell.parsec.common.Combinator.between; 15 | 16 | /** 17 | * TODO 18 | * 19 | * @author mars 20 | * @version 1.0.0 21 | * @since 2020/06/04 11:31 22 | */ 23 | public class Q implements Parsec { 24 | @Override 25 | public Quote parse(State s) throws Exception { 26 | Parser p = new Parser(); 27 | SkipWhitespaces skips = skipWhiteSpaces(); 28 | Parsec parser = between(ch('(').then(skips), skips.then(ch(')')), p); 29 | return new Quote(parser.parse(s)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/jaskell/expression/parser/S.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.parser; 2 | 3 | import static jaskell.parsec.common.Txt.ch; 4 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.Sub; 8 | import jaskell.parsec.ParsecException; 9 | import jaskell.parsec.common.Parsec; 10 | import jaskell.parsec.common.SkipWhitespaces; 11 | import jaskell.parsec.common.State; 12 | 13 | import java.io.EOFException; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/06/04 10:56 21 | */ 22 | public class S implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(ch('-')).then(skips); 25 | private final Expression prev; 26 | 27 | public S(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Sub parse(State s) throws Exception { 33 | Parsec parser = new Parser(); 34 | op.parse(s); 35 | return new Sub(prev, parser.parse(s)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Ahead.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 16/9/15. 7 | * Ahead look forward state and try to match parser. 8 | * Ahead return the parser data or fail and rollback state whatever 9 | */ 10 | public class Ahead 11 | implements Parsec { 12 | Parsec parser; 13 | 14 | @Override 15 | public T parse(State s) throws EOFException, ParsecException { 16 | Tran tran = s.begin(); 17 | try { 18 | return parser.parse(s); 19 | } finally { 20 | s.rollback(tran); 21 | } 22 | } 23 | 24 | public Ahead(Parsec parser){ 25 | this.parser = parser; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Atom.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * Created by march on 16/9/12. 7 | * static util class for atom parsers. 8 | */ 9 | public class Atom { 10 | public static Parsec one() { 11 | return new One<>(); 12 | } 13 | 14 | public static > Parsec eof() { 15 | return new Eof<>(); 16 | } 17 | 18 | public static Return pack(T value) { 19 | return new Return<>(value); 20 | } 21 | 22 | public static Fail fail(String message, Object...objects) { 23 | return new Fail<>(message, objects); 24 | } 25 | 26 | public static Eq eq(E item) { 27 | return new Eq<>(item); 28 | } 29 | 30 | public static Ne ne(E item) { 31 | return new Ne<>(item); 32 | } 33 | 34 | public static OneOf oneOf(Set data) { 35 | return new OneOf<>(data); 36 | } 37 | 38 | public static NoneOf noneOf(Set data) { 39 | return new NoneOf<>(data); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Attempt.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-03. 7 | * Try 尝试执行给定算子,如果失败,先将state复位,再抛出异常. 8 | */ 9 | public class Attempt 10 | implements Parsec { 11 | private final Parsec parsec; 12 | 13 | @Override 14 | public T parse(State s) throws EOFException, ParsecException { 15 | Tran tran = s.begin(); 16 | try{ 17 | T re = this.parsec.parse(s); 18 | s.commit(tran); 19 | return re; 20 | } catch (Exception e) { 21 | s.rollback(tran); 22 | throw e; 23 | } 24 | } 25 | 26 | public Attempt(Parsec parsec){ 27 | this.parsec = parsec; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Binder.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by Mars Liu on 2016-01-02. 8 | * Binder 为模拟 Monad 的 bind 行为提供接口抽象. 9 | */ 10 | public interface Binder { 11 | Parsec bind(T value) throws EOFException; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Ch.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * Ch 即 char, 是为 Character 特化的 Eq. 8 | */ 9 | public class Ch implements Parsec{ 10 | final private Character chr; 11 | final private boolean caseSensitive; 12 | public Ch(Character chr) { 13 | this.chr = chr; 14 | caseSensitive = true; 15 | } 16 | 17 | public Ch(Character chr, Boolean caseSensitive) { 18 | this.caseSensitive = caseSensitive; 19 | if(caseSensitive){ 20 | this.chr = chr; 21 | }else { 22 | this.chr = chr.toString().toLowerCase().charAt(0); 23 | } 24 | } 25 | 26 | @Override 27 | public Character parse(State s) throws EOFException, ParsecException { 28 | Character c = s.next(); 29 | if (caseSensitive){ 30 | if(chr.equals(c)){ 31 | return c; 32 | } 33 | } else { 34 | Character lc = c.toString().toLowerCase().charAt(0); 35 | if(chr.equals(lc)){ 36 | return c; 37 | } 38 | } 39 | throw s.trap(String.format("expect char %c (case sensitive %b) at %s but %c", 40 | chr, caseSensitive, s.status().toString(), c)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Crlf.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-11. 7 | * Crlf 即 haskell parsec 的 crlf 算子,匹配 \r\n . 8 | */ 9 | public class Crlf 10 | implements Parsec { 11 | @Override 12 | public String parse(State s) 13 | throws EOFException, ParsecException { 14 | new Ch('\r').parse(s); 15 | new Newline().parse(s); 16 | return "\r\n"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Decimal.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-08. 9 | * Decimal 尝试将后续的信息解析为 Decimal ,直到第一个无效信息为止.如果获取的信息不足以组成一个有效的浮点数,抛出异常. 10 | */ 11 | public class Decimal implements Parsec { 12 | 13 | private final Parsec sign = new Ch<>('-'); 14 | private final UDecimal decimal = new UDecimal<>(); 15 | 16 | @Override 17 | 18 | public String parse(State s) 19 | throws EOFException, ParsecException { 20 | if (sign.exec(s).isOk()) { 21 | return "-" + decimal.parse(s); 22 | } else { 23 | return decimal.parse(s); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Digit.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * Digit 判断下一个项是否是一个表示数字的字符.它仅接受 Character/char . 8 | */ 9 | public class Digit 10 | implements Parsec { 11 | @Override 12 | public Character parse(State s) 13 | throws EOFException, ParsecException { 14 | Character re = s.next(); 15 | if (Character.isDigit(re)) { 16 | return re; 17 | } else { 18 | String message = String.format("Expect %c is digit.", re); 19 | throw s.trap(message); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/EndOfLine.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by zhaonf on 16/1/10. 7 | * EndOfLine 尝试匹配 \n\r 或 \n 8 | */ 9 | public class EndOfLine 10 | implements Parsec { 11 | private final Parsec parsec = 12 | new Choice<>(new Text<>("\n"), new Text<>("\r\n")); 13 | @Override 14 | public String parse(State s) 15 | throws EOFException, ParsecException { 16 | return parsec.parse(s); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Eof.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-02. 7 | * Eof 期待 state 的 next 操作取到 eof 状态. 8 | */ 9 | public class Eof implements Parsec { 10 | @Override 11 | public E parse(State s) throws EOFException, ParsecException { 12 | try{ 13 | E re = s.next(); 14 | String message = String.format("Expect eof but %s", re); 15 | throw s.trap(message); 16 | } catch (EOFException e) { 17 | return null; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Eq.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.Objects; 5 | 6 | /** 7 | * Created by Mars Liu on 2016-01-03. 8 | * Eq 即 equal , 判断得到的信息项是否与预期相等. 9 | */ 10 | public class Eq implements Parsec { 11 | private final E item; 12 | @Override 13 | public E parse(State s) throws EOFException, ParsecException { 14 | E re = s.next(); 15 | if (Objects.equals(re, item)){ 16 | return re; 17 | } else { 18 | String message = String.format("Expect %s is equal to %s", re, item); 19 | throw s.trap(message); 20 | } 21 | } 22 | 23 | public Eq(E item){ 24 | this.item = item; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Fail.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * Fail 不改变 state , 直接抛出预设的异常. 8 | */ 9 | public class Fail implements Parsec { 10 | private final String message; 11 | 12 | @Override 13 | public E parse(State s) throws EOFException, ParsecException { 14 | throw s.trap(message); 15 | } 16 | 17 | public Fail(String msg, Object...objects) { 18 | message = String.format(msg, objects); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Find.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by march on 16/9/9. 7 | * Find 算子跳过不匹配的内容,直到匹配成功或者 eof 。 8 | * 如果失败,Find 返回第一次开始尝试的位置和相关的 ParsecException。而非 EOFException 9 | */ 10 | public class Find 11 | implements Parsec { 12 | private final One one; 13 | private final Parsec parser; 14 | @Override 15 | public T parse(State s) throws ParsecException { 16 | Status start = s.status(); 17 | try { 18 | while (true) { 19 | Tran tran = s.begin(); 20 | try { 21 | T re = parser.parse(s); 22 | s.commit(tran); 23 | return re; 24 | } catch (ParsecException e) { 25 | s.rollback(tran); 26 | one.parse(s); 27 | } 28 | } 29 | } catch (EOFException e) { 30 | String message = String.format("Parsec try from %s to end but failed", start); 31 | throw s.trap(message); 32 | } 33 | } 34 | 35 | public Find(Parsec parser) { 36 | this.parser = parser; 37 | this.one = new One<>(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Int.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * Int 算子尝试将后续的信息项组成一个整数,如果获得的信息不足以组成一个整数,抛出异常. 10 | */ 11 | public class Int 12 | implements Parsec { 13 | private final Parsec, Status, Tran> parser = 14 | s -> { 15 | List re = new ArrayList<>(); 16 | Option sign = new Option<>(new Attempt<>(new Ch<>('-'))); 17 | sign.parse(s).ifPresent(re::add); 18 | re.addAll(new Many1(new Digit<>()).parse(s)); 19 | return re; 20 | }; 21 | 22 | @Override 23 | public String parse(State s) 24 | throws EOFException, ParsecException { 25 | List buffer = parser.parse(s); 26 | StringBuilder sb = new StringBuilder(); 27 | buffer.forEach(sb::append); 28 | return sb.toString(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/JoinCharacters.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | /** 8 | * Created by Mars Liu on 2016/9/25. 9 | */ 10 | 11 | public class JoinCharacters 12 | implements Binder, String, Status, Tran> { 13 | public Parsec bind(List value) { 14 | return state -> { 15 | StringBuilder sb = new StringBuilder(); 16 | value.forEach(sb::append); 17 | return sb.toString(); 18 | }; 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/JoinText.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.List; 5 | import java.util.stream.Collector; 6 | 7 | import static java.util.stream.Collectors.joining; 8 | 9 | /** 10 | * Created by Mars Liu on 16/9/13. 11 | * JoinText is a binder. It join Character List to String. 12 | */ 13 | public class JoinText 14 | implements Binder, String, Status, Tran> { 15 | private final String sep; 16 | @Override 17 | public Parsec bind(List value) { 18 | Collector j = sep == null ? joining() : joining(sep); 19 | return state -> value.stream().map(Object::toString).collect(j); 20 | } 21 | 22 | public JoinText() { 23 | sep = null; 24 | } 25 | 26 | public JoinText(String sep) { 27 | this.sep = sep; 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Many.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-03. 9 | * Many 算子匹配给定算子0到多次. 10 | */ 11 | public class Many 12 | implements Parsec, Status, Tran> { 13 | private final Parsec parsec; 14 | 15 | @Override 16 | public List parse(State s) throws EOFException, ParsecException { 17 | List re = new ArrayList<>(); 18 | try{ 19 | while (true){ 20 | re.add(this.parsec.parse(s)); 21 | } 22 | } catch (Exception e){ 23 | return re; 24 | } 25 | } 26 | 27 | public Many(Parsec parsec) { 28 | this.parsec = new Attempt<>(parsec); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Many1.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-03. 9 | * Many1 匹配给定算子 1 到多次. 10 | */ 11 | public class Many1 12 | implements Parsec, Status, Tran> { 13 | private final Parsec parser; 14 | 15 | @Override 16 | public List parse(State s) throws EOFException, ParsecException { 17 | List re = new ArrayList<>(); 18 | re.add(this.parser.parse(s)); 19 | Parsec p = new Attempt<>(parser); 20 | try{ 21 | while (true){ 22 | re.add(p.parse(s)); 23 | } 24 | } catch (Exception e){ 25 | return re; 26 | } 27 | } 28 | 29 | public Many1(Parsec parsec){ 30 | this.parser = parsec; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/ManyTill.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import static jaskell.parsec.Combinator.attempt; 7 | 8 | /** 9 | * Created by Mars Liu on 2016-01-03. 10 | * ManyTil 尝试匹配 parser 0 到多次,直到终结算子成功,它是饥饿模式. 11 | */ 12 | public class ManyTill 13 | implements Parsec, Status, Tran> { 14 | private final Parsec parser; 15 | private final Parsec end; 16 | @Override 17 | public List parse(State s) 18 | throws EOFException, ParsecException { 19 | ArrayList re = new ArrayList<>(); 20 | while (true) { 21 | try { 22 | attempt(end).parse(s); 23 | return re; 24 | } catch (EOFException | ParsecException e) { 25 | re.add(parser.parse(s)); 26 | } 27 | } 28 | } 29 | 30 | public ManyTill(Parsec parser, Parsec end) { 31 | this.parser = new Attempt<>(parser); 32 | this.end = end; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/NCh.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016/9/28. 7 | * Expect State return a char not equals chr. 8 | */ 9 | public class NCh implements Parsec{ 10 | final private Character chr; 11 | final private boolean caseSensitive; 12 | public NCh(Character chr) { 13 | this.chr = chr; 14 | caseSensitive = true; 15 | } 16 | 17 | public NCh(Character chr, Boolean caseSensitive) { 18 | this.caseSensitive = caseSensitive; 19 | if(caseSensitive){ 20 | this.chr = chr; 21 | }else { 22 | this.chr = chr.toString().toLowerCase().charAt(0); 23 | } 24 | } 25 | 26 | @Override 27 | public Character parse(State s) throws EOFException, ParsecException { 28 | Character c = s.next(); 29 | if (caseSensitive){ 30 | if(!chr.equals(c)){ 31 | return c; 32 | } 33 | } else { 34 | Character lc = c.toString().toLowerCase().charAt(0); 35 | if(!chr.equals(lc)){ 36 | return c; 37 | } 38 | } 39 | throw s.trap(String.format("expect any char is not %c (case sensitive %b) at %s but %c", 40 | chr, caseSensitive, s.status().toString(), c)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Ne.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.Objects; 5 | 6 | /** 7 | * Created by Mars Liu on 2016-01-03. 8 | * Ne 即 not equals ,它期待下个信息项与给定值不相等. 9 | */ 10 | public class Ne implements Parsec { 11 | private final E item; 12 | 13 | @Override 14 | public E parse(State s) throws EOFException, ParsecException { 15 | E re = s.next(); 16 | if (Objects.equals(re, item)) { 17 | String message = String.format("Expect a data not Equal %s", item); 18 | throw s.trap(message); 19 | } 20 | return re; 21 | } 22 | 23 | public Ne(E item){ 24 | this.item = item; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Neighborhood.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | /** 4 | * Neighborhood description what the neighborhood content of a point 5 | * The center of neighborhood could be not the point of it, because 6 | * String need top and bottom in indexes range. 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/06/02 11:58 11 | */ 12 | public class Neighborhood { 13 | private int bottom; 14 | private int top; 15 | private String content; 16 | 17 | public int getBottom() { 18 | return bottom; 19 | } 20 | 21 | public void setBottom(int bottom) { 22 | this.bottom = bottom; 23 | } 24 | 25 | public int getTop() { 26 | return top; 27 | } 28 | 29 | public void setTop(int top) { 30 | this.top = top; 31 | } 32 | 33 | public String getContent() { 34 | return content; 35 | } 36 | 37 | public void setContent(String content) { 38 | this.content = content; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Newline.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.concurrent.TransferQueue; 5 | 6 | /** 7 | * Created by Mars Liu . 8 | * Newline 尝试匹配换\n 9 | * ----------------- 10 | */ 11 | public class Newline 12 | implements Parsec { 13 | private final Parsec parser = new Ch<>('\n'); 14 | @Override 15 | public Character parse(State s) 16 | throws EOFException, ParsecException { 17 | return parser.parse(s); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/NoWhitespace.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * Whitespace 匹配空白字符 8 | */ 9 | public class NoWhitespace 10 | implements Parsec{ 11 | @Override 12 | public Character parse(State s) 13 | throws EOFException, ParsecException { 14 | Character re = s.next(); 15 | if (Character.isWhitespace(re)) { 16 | String message = String.format("Expect one char is not whitespace but get %c.", re); 17 | throw s.trap(message); 18 | } else { 19 | return re; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/NoneOf.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.List; 5 | import java.util.Set; 6 | 7 | import static java.util.stream.Collectors.joining; 8 | 9 | /** 10 | * Created by Mars Liu on 2016-01-03. 11 | * NoneOf 即 none of ,它期待得到的信息项与给定的任何项都不匹配,否则返回错误. 12 | */ 13 | public class NoneOf implements 14 | Parsec { 15 | private final Set items; 16 | 17 | @Override 18 | public E parse(State s) throws EOFException, ParsecException { 19 | E re = s.next(); 20 | if(items.contains(re)) { 21 | String message = String.format("expect a item none of [%s] but got %s", 22 | this.items.stream().map(E::toString).collect(joining()), re); 23 | throw s.trap(message); 24 | } 25 | return re; 26 | } 27 | 28 | public NoneOf(Set items){ 29 | this.items = items; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/One.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-02. 7 | * One 成功匹配所有非 eof 的状态.s 8 | */ 9 | public class One implements Parsec { 10 | @Override 11 | public E parse(State s) throws EOFException, ParsecException { 12 | return s.next(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/OneOf.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.Set; 5 | import static java.util.stream.Collectors.joining; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-03. 9 | * OneOf 即 one of ,给定项中任何一个匹配成功即视为成功,否则抛出错误. 10 | */ 11 | public class OneOf implements Parsec { 12 | private final Set items; 13 | 14 | @Override 15 | public E parse(State s) 16 | throws EOFException, ParsecException { 17 | E data = s.next(); 18 | if(items.contains(data)) { 19 | return data; 20 | } 21 | 22 | String message = String.format("Expect %s in [%s]", data, 23 | this.items.stream().map(E::toString).collect(joining(", "))); 24 | throw s.trap(message); 25 | } 26 | 27 | public OneOf(Set items){ 28 | this.items = items; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Option.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.Optional; 5 | 6 | /** 7 | * Created by Mars Liu on 16/9/18. 8 | * Option accept a parsec<E, T, Status, Tran> and 9 | * return new one parsec<Optional<T>, E, Status, Tran>. 10 | * If the parser fail, Option parsec just return option.empty without Exception thrown. 11 | */ 12 | public class Option 13 | implements Parsec, Status, Tran> { 14 | private final Parsec parser; 15 | 16 | public Option(Parsec parser) { 17 | this.parser = parser; 18 | } 19 | 20 | @Override 21 | public Optional parse(State s) 22 | throws EOFException, ParsecException { 23 | Tran tran = s.begin(); 24 | try{ 25 | Optional result = Optional.of(parser.parse(s)); 26 | s.commit(tran); 27 | return result; 28 | } catch (Exception e) { 29 | s.rollback(tran); 30 | return Optional.empty(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Parsec.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import jaskell.util.Try; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-02. 9 | * Parsec defined base functions of parsec parsers. 10 | */ 11 | @FunctionalInterface 12 | public interface Parsec { 13 | T parse(State s) 14 | throws EOFException, ParsecException; 15 | 16 | default Try exec(State s) { 17 | try { 18 | return Try.success(parse(s)); 19 | } catch (Exception e) { 20 | return Try.failure(e); 21 | } 22 | } 23 | 24 | default Parsec bind(Binder binder) { 25 | return s -> { 26 | T value = parse(s); 27 | return binder.bind(value).parse(s); 28 | }; 29 | } 30 | 31 | default Parsec then(Parsec parsec) { 32 | return s -> { 33 | parse(s); 34 | return parsec.parse(s); 35 | }; 36 | } 37 | 38 | default Parsec over(Parsec parsec) { 39 | return s -> { 40 | T value = Parsec.this.parse(s); 41 | parsec.parse(s); 42 | return value; 43 | }; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/ParsecException.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | /** 4 | * Created by march on 16/9/11. 5 | */ 6 | public class ParsecException extends RuntimeException { 7 | private final String message; 8 | private final Object status; 9 | 10 | public ParsecException(Object status, String message) { 11 | super(message); 12 | this.status = status; 13 | this.message = message; 14 | } 15 | 16 | public String getMessage() { 17 | return message; 18 | } 19 | 20 | public Object getStatus() { 21 | return status; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Return.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * Return 不改变 state ,它直接返回预设值. 8 | */ 9 | public class Return implements Parsec { 10 | private final T item; 11 | 12 | @Override 13 | public T parse(State s) 14 | throws EOFException, ParsecException { 15 | return item; 16 | } 17 | 18 | public Return(T item){ 19 | this.item = item; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/SepBy.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-03. 9 | * SepBy 尝试匹配由给定规则分隔开的0到多次重复匹配. 10 | */ 11 | public class SepBy 12 | implements Parsec, Status, Tran>{ 13 | private final Parsec by; 14 | private final Parsec p; 15 | @Override 16 | public List parse(State s) 17 | throws EOFException, ParsecException { 18 | ArrayList re = new ArrayList<>(); 19 | try { 20 | re.add(this.p.parse(s)); 21 | while (true) { 22 | this.by.parse(s); 23 | re.add(this.p.parse(s)); 24 | } 25 | } catch (EOFException|ParsecException e) { 26 | return re; 27 | } 28 | } 29 | public SepBy(Parsec p, Parsec by) { 30 | this.by = new Attempt<>(by); 31 | this.p = new Attempt<>(p); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/SepBy1.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-03. 9 | * SepBy 尝试匹配由给定规则分隔开的1到多次重复匹配. 10 | */ 11 | public class SepBy1 12 | implements Parsec, Status, Tran> { 13 | private final Parsec by; 14 | private final Parsec p; 15 | @Override 16 | public List parse(State s) 17 | throws EOFException, ParsecException { 18 | List re = new ArrayList<>(); 19 | re.add(this.p.parse(s)); 20 | Parsec parser = new Attempt<>(p); 21 | try { 22 | while (true) { 23 | this.by.parse(s); 24 | re.add(parser.parse(s)); 25 | } 26 | } catch (EOFException|ParsecException e) { 27 | return re; 28 | } 29 | } 30 | 31 | public SepBy1(Parsec p, Parsec by) { 32 | this.by = new Attempt<>(by); 33 | this.p = p; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Skip.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * 跳过 0 到多次重复匹配 8 | */ 9 | public class Skip 10 | implements Parsec { 11 | private final Parsec psc; 12 | 13 | @Override 14 | public T parse(State s) 15 | throws EOFException, ParsecException { 16 | Tran tran = null; 17 | try { 18 | while (true) { 19 | tran = s.begin(); 20 | psc.parse(s); 21 | s.commit(tran); 22 | } 23 | } catch (Exception e){ 24 | s.rollback(tran); 25 | } 26 | return null; 27 | } 28 | 29 | public Skip(Parsec psc) { 30 | this.psc = psc; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Skip1.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * 跳过指定算子 1 到多次. 8 | */ 9 | public class Skip1 10 | implements Parsec { 11 | private final Parsec psc; 12 | 13 | @Override 14 | public T parse(State s) throws EOFException, ParsecException { 15 | psc.parse(s); 16 | new Skip<>(psc).parse(s); 17 | return null; 18 | } 19 | 20 | public Skip1(Parsec psc) { 21 | this.psc = psc; 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/SkipSpaces.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.CharArrayReader; 4 | import java.io.EOFException; 5 | 6 | /** 7 | * Created by march on 16/9/12. 8 | * SkipSpaces is a parser skip all spaces. 9 | */ 10 | public class SkipSpaces 11 | implements Parsec { 12 | private final Parsec parser = new Skip<>(new Whitespace<>()); 13 | @Override 14 | public Character parse(State s) 15 | throws EOFException, ParsecException { 16 | return parser.parse(s); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/SkipWhitespaces.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by march on 16/9/12. 7 | * SkipSpaces is a parser skip all whitespaces. 8 | */ 9 | public class SkipWhitespaces 10 | implements Parsec { 11 | private final Parsec parser = new Skip<>(new Whitespace<>()); 12 | @Override 13 | public Character parse(State s) 14 | throws EOFException, ParsecException { 15 | return parser.parse(s); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Space.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * Space 匹配空格 8 | */ 9 | public class Space 10 | implements Parsec{ 11 | @Override 12 | public Character parse(State s) 13 | throws EOFException, ParsecException { 14 | Character re = s.next(); 15 | if (Character.isSpaceChar(re)) { 16 | return re; 17 | } else { 18 | String message = String.format("Expect %c is space.", re); 19 | throw s.trap(message); 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/State.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-02. 7 | * State 是 state 接口规范, parsec 用户可以定义自己的 state 实现. 8 | */ 9 | public interface State { 10 | /** 11 | * @return 总是返回 state 的当前元素,并迭代到下一个位置。如果到达结尾,会抛出 eof。 12 | * @throws java.io.EOFException 到达终结状态时,再调用 next 会抛出 EOF 异常。 13 | */ 14 | E next() throws EOFException; 15 | 16 | /** 17 | * @return 返回当前 state 的状态,对于线性序列,通常即是索引。调用 next 时,会返回这个状态对应的元素。 18 | */ 19 | Status status(); 20 | 21 | /** 22 | * @return 返回一个事务标示,state 应记录和管理这个事务。 23 | */ 24 | Tran begin(); 25 | 26 | /** 27 | * 在很多场合,调用者使用自动生成的事务标示已经足够,但是 jparsec 也提供了显式指定事务标示的接口。 28 | * 在通常的线性序列状态中,通常不需要这样的模式,但是对于具名事务环境,例如一些数据库,可能这种方式 29 | * 是最佳的实践。State 应尽可能的使用给定的标示构造事务,并返回最终得到的事务标示,这表示我们允许 30 | * State 给出与期待不同的事务标示。 31 | * @param tran 接受一个事务标示参数,state 应尽可能使用这个标示生成事务。 32 | * @return 返回一个事务标示,state 应记录和管理这个事务。 33 | */ 34 | Tran begin(Tran tran); 35 | 36 | /** 37 | * @param tran 提交指定的事务号。 38 | */ 39 | void commit(Tran tran); 40 | 41 | /** 42 | * @param tran 回滚指定事务号对应的事务。 43 | */ 44 | void rollback(Tran tran); 45 | 46 | /** 47 | * @param message 接受指定的消息文本,用于构造异常 48 | * @return 总是返回一个 ParsecException 或它的子类。具体的 State 实现者可以提供继承自 ParsecException 的异常。 49 | */ 50 | ParsecException trap(String message); 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/UDecimal.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * UDecimal 尝试将后续信息流解析成一个表示无符号浮点数的字符串,如果匹配失败就抛出异常. 10 | */ 11 | public class UDecimal implements Parsec { 12 | private final Parsec uint = new UInt<>(); 13 | private final Parsec dot = new Ch<>('.'); 14 | 15 | @Override 16 | public String parse(State s) 17 | throws EOFException, ParsecException { 18 | StringBuilder builder = new StringBuilder(); 19 | builder.append(uint.parse(s)); 20 | if (dot.exec(s).isOk()){ 21 | builder.append('.'); 22 | builder.append(uint.parse(s)); 23 | } 24 | return builder.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/UInt.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by Mars Liu on 2016-01-07. 8 | * UInt 尝试将后续信息流解析成一个表示无符号整数的字符串,如果匹配失败就抛出异常. 9 | */ 10 | public class UInt 11 | implements Parsec { 12 | private final Parsec, Status, Tran> parser = new Many1<>(new Digit<>()); 13 | @Override 14 | public String parse(State s) 15 | throws EOFException, ParsecException { 16 | List buffer = parser.parse(s); 17 | StringBuilder sb = new StringBuilder(); 18 | buffer.forEach(sb::append); 19 | return sb.toString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/Whitespace.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-07. 7 | * Whitespace 匹配空白字符 8 | */ 9 | public class Whitespace 10 | implements Parsec{ 11 | @Override 12 | public Character parse(State s) 13 | throws EOFException, ParsecException { 14 | Character re = s.next(); 15 | if (Character.isWhitespace(re)) { 16 | return re; 17 | } else { 18 | String message = String.format("Expect %c is whitespace.", re); 19 | throw s.trap(message); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Ahead.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 16/9/15. 9 | * Ahead look forward state and try to match parser. 10 | * Ahead return the parser data or fail and rollback state whatever 11 | */ 12 | public class Ahead 13 | implements Parsec { 14 | Parsec parser; 15 | 16 | @Override 17 | public T parse(State s) throws Exception { 18 | Integer tran = s.begin(); 19 | try { 20 | return parser.parse(s); 21 | } finally { 22 | s.rollback(tran); 23 | } 24 | } 25 | 26 | public Ahead(Parsec parser){ 27 | this.parser = parser; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Atom.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import java.util.Set; 4 | import java.util.function.Predicate; 5 | 6 | /** 7 | * Created by march on 16/9/12. 8 | * static util class for atom parsers. 9 | */ 10 | public class Atom { 11 | public static One one() { 12 | return new One<>(); 13 | } 14 | 15 | public static Eof eof() { 16 | return new Eof<>(); 17 | } 18 | 19 | public static Return pack(T value) { 20 | return new Return<>(value); 21 | } 22 | 23 | public static Fail 24 | fail(String message, Object...objects) { 25 | return new Fail<>(message, objects); 26 | } 27 | 28 | public static Eq eq(E item) { 29 | return new Eq<>(item); 30 | } 31 | 32 | public static Ne ne(E item) { 33 | return new Ne<>(item); 34 | } 35 | 36 | public static OneOf oneOf(Set data) { 37 | return new OneOf<>(data); 38 | } 39 | 40 | public static NoneOf noneOf(Set data) { 41 | return new NoneOf<>(data); 42 | } 43 | 44 | public static Is is(Predicate predicate) { 45 | return new Is<>(predicate); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Attempt.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-03. 9 | * Try 尝试执行给定算子,如果失败,先将state复位,再抛出异常. 10 | */ 11 | public class Attempt 12 | implements Parsec { 13 | private final Parsec parsec; 14 | 15 | @Override 16 | public T parse(State s) throws Exception { 17 | Integer tran = s.begin(); 18 | try{ 19 | T re = this.parsec.parse(s); 20 | s.commit(tran); 21 | return re; 22 | } catch (Exception e) { 23 | s.rollback(tran); 24 | throw e; 25 | } 26 | } 27 | 28 | public Attempt(Parsec parsec){ 29 | this.parsec = parsec; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Between.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-03. 9 | * Between 算子等效于 open.then(p).over(close); 若 (open, parser, close) 组合子顺序解析成功,返回 parser 的解析结果. 10 | * 遵循 Haskell Parsec 的定义,我们将参数顺序设定为 between(open, close, parser),并提供了 curry 化的 In 子类型. 11 | */ 12 | public class Between implements 13 | Parsec { 14 | private final Parsec open; 15 | private final Parsec close; 16 | private final Parsec parsec; 17 | 18 | @Override 19 | public T parse(State s) 20 | throws Exception { 21 | open.parse(s); 22 | T re = parsec.parse(s); 23 | close.parse(s); 24 | return re; 25 | } 26 | 27 | public Between(Parsec open, 28 | Parsec close, 29 | Parsec parsec) { 30 | this.open = open; 31 | this.close = close; 32 | this.parsec = parsec; 33 | } 34 | 35 | static public class In> { 36 | private final Parsec open; 37 | private final Parsec close; 38 | 39 | public In(Parsec open, Parsec close) { 40 | this.open = open; 41 | this.close = close; 42 | } 43 | 44 | public Parsec pack(Parsec parser) { 45 | return new Between<>(this.open, this.close, parser); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Binder.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import java.io.EOFException; 4 | 5 | /** 6 | * Created by Mars Liu on 2016-01-02. 7 | * Binder 为模拟 Monad 的 bind 行为提供接口抽象. 8 | */ 9 | public interface Binder { 10 | Parsec bind(T value) throws EOFException; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Choice.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by Mars Liu on 2016-01-03. 12 | * Choice 算子是多路分支选择算子, choice 顺序检查所有分路,返回第一个成功的算子的解析结果.如果某个算子解析失败以后没有复位,则将其错误 13 | * 信息抛出.如果所有的分路都解析失败,抛出异常. 14 | */ 15 | public class Choice 16 | implements Parsec { 17 | private final List> parsecs; 18 | 19 | @Override 20 | public T parse(State s) throws Exception { 21 | Exception err = null; 22 | Integer status = s.status(); 23 | for (Parsec psc : this.parsecs) { 24 | try { 25 | return psc.parse(s); 26 | } catch (EOFException | ParsecException e) { 27 | err = e; 28 | if (!s.status().equals(status)) { 29 | throw e; 30 | } 31 | } 32 | } 33 | if(err == null){ 34 | throw s.trap("Choice Error : All parsec parser failed."); 35 | } else { 36 | if(err instanceof EOFException) { 37 | throw (EOFException) err; 38 | } 39 | String message = String.format("Choice Error %s, stop at %s", err, s.status()); 40 | throw s.trap(message); 41 | } 42 | } 43 | 44 | @SafeVarargs 45 | public Choice(Parsec... parsecs) { 46 | this.parsecs = Arrays.asList(parsecs); 47 | } 48 | 49 | public Choice(List> parsecs) { 50 | this.parsecs = new ArrayList<>(parsecs); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Crlf.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-11. 9 | * Crlf 即 haskell parsec 的 crlf 算子,匹配 \r\n . 10 | */ 11 | public class Crlf implements Parsec { 12 | @Override 13 | public String parse(State s) 14 | throws Exception { 15 | new Ch('\r').parse(s); 16 | new Newline().parse(s); 17 | return "\r\n"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Decimal.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-08. 9 | * Decimal 尝试将后续的信息解析为 Decimal ,直到第一个无效信息为止.如果获取的信息不足以组成一个有效的浮点数,抛出异常. 10 | */ 11 | public class Decimal implements Parsec { 12 | private final Parsec sign = new Attempt<>(new Ch('-')); 13 | private final Parsec decimal = new UDecimal(); 14 | 15 | @Override 16 | public String parse(State s) 17 | throws Exception { 18 | if (sign.exec(s).isOk()){ 19 | return "-" + decimal.parse(s); 20 | } else { 21 | return decimal.parse(s); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Digit.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * Digit 判断下一个项是否是一个表示数字的字符.它仅接受 Character/char . 10 | */ 11 | public class Digit 12 | implements Parsec { 13 | @Override 14 | public Character parse(State s) 15 | throws EOFException, ParsecException { 16 | Character re = s.next(); 17 | if (Character.isDigit(re)) { 18 | return re; 19 | } else { 20 | String message = String.format("Expect %c is digit.", re); 21 | throw s.trap(message); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/EndOfLine.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static jaskell.parsec.common.Txt.text; 4 | 5 | import jaskell.parsec.ParsecException; 6 | 7 | import java.io.EOFException; 8 | 9 | /** 10 | * Created by zhaonf on 16/1/10. 11 | * EndOfLine 尝试匹配 \r\n 或 \n 12 | */ 13 | public class EndOfLine 14 | implements Parsec { 15 | private final Parsec parsec = 16 | new Choice<>(new Text("\n"), new Text("\r\n")); 17 | @Override 18 | public String parse(State s) 19 | throws Exception { 20 | return parsec.parse(s); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Eof.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-02. 9 | * Eof 期待 state 的 next 操作取到 eof 状态. 10 | */ 11 | public class Eof implements Parsec { 12 | @Override 13 | public E parse(State s) throws EOFException, ParsecException { 14 | try{ 15 | E re = s.next(); 16 | String message = String.format("Expect eof but %s", re); 17 | throw s.trap(message); 18 | } catch (EOFException e) { 19 | return null; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Eq.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.Objects; 7 | 8 | /** 9 | * Created by Mars Liu on 2016-01-03. 10 | * Eq 即 equal , 判断得到的信息项是否与预期相等. 11 | */ 12 | public class Eq implements Parsec { 13 | private final E item; 14 | @Override 15 | public E parse(State s) throws EOFException, ParsecException { 16 | E re = s.next(); 17 | if (Objects.equals(re, item)){ 18 | return re; 19 | } else { 20 | String message = String.format("Expect %s is equal to %s", re, item); 21 | throw s.trap(message); 22 | } 23 | } 24 | 25 | public Eq(E item){ 26 | this.item = item; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Fail.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * Fail 不改变 state , 直接抛出预设的异常. 10 | */ 11 | public class Fail implements Parsec { 12 | private final String message; 13 | 14 | @Override 15 | public E parse(State s) throws EOFException, ParsecException { 16 | throw s.trap(message); 17 | } 18 | 19 | public Fail(String msg, Object...objects) { 20 | message = String.format(msg, objects); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Find.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by march on 16/9/9. 9 | * Find 算子跳过不匹配的内容,直到匹配成功或者 eof 。 10 | * 如果失败,Find 返回第一次开始尝试的位置和相关的 ParsecException。而非 EOFException 11 | */ 12 | public class Find 13 | implements Parsec { 14 | private final One one; 15 | private final Parsec parser; 16 | @Override 17 | public T parse(State s) throws Exception { 18 | Integer start = s.status(); 19 | try { 20 | while (true) { 21 | Integer tran = s.begin(); 22 | try { 23 | T re = parser.parse(s); 24 | s.commit(tran); 25 | return re; 26 | } catch (ParsecException e) { 27 | s.rollback(tran); 28 | one.parse(s); 29 | } 30 | } 31 | } catch (EOFException e) { 32 | String message = String.format("Parsec try from %s to end but failed", start); 33 | throw s.trap(message); 34 | } 35 | } 36 | 37 | public Find(Parsec parser) { 38 | this.parser = parser; 39 | this.one = new One<>(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Int.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by Mars Liu on 2016-01-07. 11 | * Int 算子尝试将后续的信息项组成一个整数,如果获得的信息不足以组成一个整数,抛出异常. 12 | */ 13 | public class Int implements Parsec { 14 | private final Parsec> parser = 15 | s -> { 16 | List re = new ArrayList<>(); 17 | Option sign = new Option<>(new Attempt<>(new Ch('-'))); 18 | sign.parse(s).ifPresent(re::add); 19 | re.addAll(new Many1<>(new Digit()).parse(s)); 20 | return re; 21 | }; 22 | 23 | @Override 24 | public String parse(State s) 25 | throws Exception { 26 | List buffer = parser.parse(s); 27 | StringBuilder sb = new StringBuilder(); 28 | buffer.forEach(sb::append); 29 | return sb.toString(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Is.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.function.Predicate; 7 | 8 | /** 9 | * TODO 10 | * 11 | * @author mars 12 | * @version 1.0.0 13 | * @since 2020/07/23 14:58 14 | */ 15 | public class Is implements Parsec { 16 | private final Predicate predicate; 17 | 18 | public Is(Predicate predicate) { 19 | this.predicate = predicate; 20 | } 21 | 22 | @Override 23 | public E parse(State s) throws EOFException, ParsecException { 24 | E item = s.next(); 25 | if(predicate.test(item)){ 26 | return item; 27 | } else { 28 | throw s.trap(String.format("expect anything pass the predicate check but %s", item)); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/JoinCharacters.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Mars Liu on 2016/9/25. 7 | */ 8 | 9 | public class JoinCharacters 10 | implements Binder, String> { 11 | public Parsec bind(List value) { 12 | return state -> { 13 | StringBuilder sb = new StringBuilder(); 14 | value.forEach(sb::append); 15 | return sb.toString(); 16 | }; 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/JoinText.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static java.util.stream.Collectors.joining; 4 | 5 | import java.util.List; 6 | import java.util.stream.Collector; 7 | 8 | /** 9 | * Created by Mars Liu on 16/9/13. 10 | * JoinText is a binder. It join Character List to String. 11 | */ 12 | public class JoinText 13 | implements Binder, String> { 14 | private final String sep; 15 | @Override 16 | public Parsec bind(List value) { 17 | Collector j = sep == null ? joining() : joining(sep); 18 | return state -> value.stream().map(Object::toString).collect(j); 19 | } 20 | 21 | public JoinText() { 22 | sep = null; 23 | } 24 | 25 | public JoinText(String sep) { 26 | this.sep = sep; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Letter.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/06/12 19:26 13 | */ 14 | public class Letter implements Parsec { 15 | @Override 16 | public Character parse(State s) throws EOFException, ParsecException { 17 | Character c = s.next(); 18 | if(Character.isLetter(c)){ 19 | return c; 20 | } else { 21 | throw s.trap(String.format("expect a letter but get %c", c)); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Many.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by Mars Liu on 2016-01-03. 11 | * Many 算子匹配给定算子0到多次. 12 | */ 13 | public class Many 14 | implements Parsec> { 15 | private final Parsec parsec; 16 | 17 | @Override 18 | public List parse(State s) throws EOFException, ParsecException { 19 | List re = new ArrayList<>(); 20 | try{ 21 | while (true){ 22 | re.add(this.parsec.parse(s)); 23 | } 24 | } catch (Exception e){ 25 | return re; 26 | } 27 | } 28 | 29 | public Many(Parsec parsec) { 30 | this.parsec = new Attempt<>(parsec); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Many1.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by Mars Liu on 2016-01-03. 11 | * Many1 匹配给定算子 1 到多次. 12 | */ 13 | public class Many1 14 | implements Parsec> { 15 | private final Parsec parser; 16 | 17 | @Override 18 | public List parse(State s) throws Exception { 19 | List re = new ArrayList<>(); 20 | re.add(this.parser.parse(s)); 21 | Parsec p = new Attempt<>(parser); 22 | try{ 23 | while (true){ 24 | re.add(p.parse(s)); 25 | } 26 | } catch (Exception e){ 27 | return re; 28 | } 29 | } 30 | 31 | public Many1(Parsec parsec){ 32 | this.parser = parsec; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/ManyTill.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static jaskell.parsec.common.Combinator.attempt; 4 | 5 | import jaskell.parsec.ParsecException; 6 | 7 | import java.io.EOFException; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * Created by Mars Liu on 2016-01-03. 13 | * ManyTil 尝试匹配 parser 0 到多次,直到终结算子成功,它是饥饿模式. 14 | */ 15 | public class ManyTill 16 | implements Parsec> { 17 | private final Parsec parser; 18 | private final Parsec end; 19 | @Override 20 | public List parse(State s) 21 | throws Exception { 22 | List re = new ArrayList<>(); 23 | while (true) { 24 | try { 25 | attempt(end).parse(s); 26 | return re; 27 | } catch (EOFException | ParsecException e) { 28 | re.add(parser.parse(s)); 29 | } 30 | } 31 | } 32 | 33 | public ManyTill(Parsec parser, Parsec end) { 34 | this.parser = new Attempt<>(parser); 35 | this.end = end; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/NCh.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016/9/28. 9 | * Expect State return a char not equals chr. 10 | */ 11 | public class NCh implements Parsec { 12 | final private Character chr; 13 | final private boolean caseSensitive; 14 | public NCh(Character chr) { 15 | this.chr = chr; 16 | caseSensitive = true; 17 | } 18 | 19 | public NCh(Character chr, Boolean caseSensitive) { 20 | this.caseSensitive = caseSensitive; 21 | if(caseSensitive){ 22 | this.chr = chr; 23 | }else { 24 | this.chr = chr.toString().toLowerCase().charAt(0); 25 | } 26 | } 27 | 28 | @Override 29 | public Character parse(State s) throws EOFException, ParsecException { 30 | Character c = s.next(); 31 | if (caseSensitive){ 32 | if(!chr.equals(c)){ 33 | return c; 34 | } 35 | } else { 36 | Character lc = c.toString().toLowerCase().charAt(0); 37 | if(!chr.equals(lc)){ 38 | return c; 39 | } 40 | } 41 | throw s.trap(String.format("expect any char is not %c (case sensitive %b) at %s but %c", 42 | chr, caseSensitive, s.status().toString(), c)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Ne.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.Objects; 7 | 8 | /** 9 | * Created by Mars Liu on 2016-01-03. 10 | * Ne 即 not equals ,它期待下个信息项与给定值不相等. 11 | */ 12 | public class Ne implements Parsec { 13 | private final E item; 14 | 15 | @Override 16 | public E parse(State s) throws EOFException, ParsecException { 17 | E re = s.next(); 18 | if (Objects.equals(re, item)) { 19 | String message = String.format("Expect a data not Equal %s", item); 20 | throw s.trap(message); 21 | } 22 | return re; 23 | } 24 | 25 | public Ne(E item){ 26 | this.item = item; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Newline.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu . 9 | * Newline 尝试匹配换\n 10 | * ----------------- 11 | */ 12 | public class Newline 13 | implements Parsec { 14 | private final Parsec parser = new Ch('\n'); 15 | @Override 16 | public Character parse(State s) 17 | throws Exception { 18 | return parser.parse(s); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/NoWhitespace.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * Whitespace 匹配空白字符 10 | */ 11 | public class NoWhitespace implements Parsec { 12 | @Override 13 | public Character parse(State s) 14 | throws EOFException, ParsecException { 15 | Character re = s.next(); 16 | if (Character.isWhitespace(re)) { 17 | String message = String.format("Expect one char is not whitespace but get %c.", re); 18 | throw s.trap(message); 19 | } else { 20 | return re; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/NoneOf.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static java.util.stream.Collectors.joining; 4 | 5 | import jaskell.parsec.ParsecException; 6 | 7 | import java.io.EOFException; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by Mars Liu on 2016-01-03. 12 | * NoneOf 即 none of ,它期待得到的信息项与给定的任何项都不匹配,否则返回错误. 13 | */ 14 | public class NoneOf implements 15 | Parsec { 16 | private final Set items; 17 | 18 | @Override 19 | public E parse(State s) throws EOFException, ParsecException { 20 | E re = s.next(); 21 | if(items.contains(re)) { 22 | String message = String.format("expect a item none of [%s] but got %s", 23 | this.items.stream().map(E::toString).collect(joining()), re); 24 | throw s.trap(message); 25 | } 26 | return re; 27 | } 28 | 29 | public NoneOf(Set items){ 30 | this.items = items; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/One.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-02. 9 | * One 成功匹配所有非 eof 的状态.s 10 | */ 11 | public class One implements Parsec { 12 | @Override 13 | public E parse(State s) throws EOFException, ParsecException { 14 | return s.next(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/OneOf.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static java.util.stream.Collectors.joining; 4 | 5 | import jaskell.parsec.ParsecException; 6 | 7 | import java.io.EOFException; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by Mars Liu on 2016-01-03. 12 | * OneOf 即 one of ,给定项中任何一个匹配成功即视为成功,否则抛出错误. 13 | */ 14 | public class OneOf implements Parsec { 15 | private final Set items; 16 | 17 | @Override 18 | public E parse(State s) 19 | throws EOFException, ParsecException { 20 | E data = s.next(); 21 | if(items.contains(data)) { 22 | return data; 23 | } 24 | 25 | String message = String.format("Expect %s in [%s]", data, 26 | this.items.stream().map(E::toString).collect(joining(", "))); 27 | throw s.trap(message); 28 | } 29 | 30 | public OneOf(Set items){ 31 | this.items = items; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Option.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.Optional; 7 | 8 | /** 9 | * Created by Mars Liu on 16/9/18. 10 | * Option accept a parsec<E, T, Status, Tran> and 11 | * return new one parsec<Optional<T>, E, Status, Tran>. 12 | * If the parser fail, Option parsec just return option.empty without Exception thrown. 13 | */ 14 | public class Option 15 | implements Parsec> { 16 | private final Parsec parser; 17 | 18 | public Option(Parsec parser) { 19 | this.parser = new Attempt<>(parser); 20 | } 21 | 22 | @Override 23 | public Optional parse(State s) 24 | throws Exception { 25 | Integer tran = s.begin(); 26 | try{ 27 | Optional result = Optional.of(parser.parse(s)); 28 | s.commit(tran); 29 | return result; 30 | } catch (Exception e) { 31 | s.rollback(tran); 32 | return Optional.empty(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Return.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * Return 不改变 state ,它直接返回预设值. 10 | */ 11 | public class Return implements Parsec { 12 | private final T item; 13 | 14 | @Override 15 | public T parse(State s) 16 | throws EOFException, ParsecException { 17 | return item; 18 | } 19 | public Return(T item){ 20 | this.item = item; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/ScNumber.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | import jaskell.util.Result; 5 | import jaskell.util.Try; 6 | 7 | import java.io.EOFException; 8 | 9 | /** 10 | * ScNumber Parser could parse scientific number text 11 | * 12 | * @author Mars Liu 13 | * @version 1.0.0 14 | * @since 2020/06/05 12:40 15 | */ 16 | public class ScNumber implements Parsec { 17 | private final Decimal decimal = new Decimal(); 18 | private final Parsec ep = new Ch('e', false); 19 | private final Parsec sp = 20 | new Choice<>(new Attempt<>(new Text("+")), new Attempt<>(new Text("-")), new Return<>("")); 21 | private final Parsec np = new UInt(); 22 | 23 | private final Parsec exp = new Attempt<>(s -> ep.parse(s) + sp.parse(s) + np.parse(s)); 24 | 25 | @Override 26 | public String parse(State s) throws Exception { 27 | String mantissa = decimal.parse(s); 28 | return exp.exec(s).flatMap(e -> new Try<>(mantissa + e)).orElse(mantissa); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/SepBy.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by Mars Liu on 2016-01-03. 11 | * SepBy 尝试匹配由给定规则分隔开的0到多次重复匹配. 12 | */ 13 | public class SepBy 14 | implements Parsec> { 15 | private final Parsec by; 16 | private final Parsec p; 17 | @Override 18 | public List parse(State s) 19 | throws Exception { 20 | List re = new ArrayList<>(); 21 | try { 22 | re.add(this.p.parse(s)); 23 | while (true) { 24 | this.by.parse(s); 25 | re.add(this.p.parse(s)); 26 | } 27 | } catch (EOFException| ParsecException e) { 28 | return re; 29 | } 30 | } 31 | public SepBy(Parsec p, Parsec by) { 32 | this.by = new Attempt<>(by); 33 | this.p = new Attempt<>(p); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/SepBy1.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by Mars Liu on 2016-01-03. 11 | * SepBy 尝试匹配由给定规则分隔开的1到多次重复匹配. 12 | */ 13 | public class SepBy1 14 | implements Parsec> { 15 | private final Parsec by; 16 | private final Parsec p; 17 | @Override 18 | public List parse(State s) 19 | throws Exception { 20 | List re = new ArrayList<>(); 21 | re.add(this.p.parse(s)); 22 | Parsec parser = new Attempt<>(p); 23 | try { 24 | while (true) { 25 | this.by.parse(s); 26 | re.add(parser.parse(s)); 27 | } 28 | } catch (EOFException| ParsecException e) { 29 | return re; 30 | } 31 | } 32 | 33 | public SepBy1(Parsec p, Parsec by) { 34 | this.by = new Attempt<>(by); 35 | this.p = p; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Skip.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * 跳过 0 到多次重复匹配 10 | */ 11 | public class Skip 12 | implements Parsec { 13 | private final Parsec psc; 14 | 15 | @Override 16 | public T parse(State s) 17 | throws Exception { 18 | Integer tran = null; 19 | try { 20 | while (true) { 21 | tran = s.begin(); 22 | psc.parse(s); 23 | s.commit(tran); 24 | } 25 | } catch (Exception e){ 26 | s.rollback(tran); 27 | } 28 | return null; 29 | } 30 | 31 | public Skip(Parsec psc) { 32 | this.psc = psc; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Skip1.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * 跳过指定算子 1 到多次. 10 | */ 11 | public class Skip1 12 | implements Parsec { 13 | private final Parsec psc; 14 | private final Parsec skip; 15 | 16 | @Override 17 | public T parse(State s) throws Exception { 18 | psc.parse(s); 19 | skip.parse(s); 20 | return null; 21 | } 22 | 23 | public Skip1(Parsec psc) { 24 | this.psc = psc; 25 | this.skip = new Skip<>(psc); 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Skip1Spaces.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | /** 4 | * Created by march on 16/9/12. 5 | * SkipSpaces is a parser skip all spaces. 6 | */ 7 | public class Skip1Spaces 8 | implements Parsec { 9 | private final Parsec parser = (new Space()).then(new Skip<>(new Space())); 10 | 11 | @Override 12 | public Character parse(State s) 13 | throws Exception { 14 | return parser.parse(s); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Skip1Whitespaces.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | /** 4 | * Created by march on 16/9/12. 5 | * SkipSpaces is a parser skip all whitespaces. 6 | */ 7 | public class Skip1Whitespaces 8 | implements Parsec { 9 | private final Parsec parser = (new Whitespace()).then(new Skip<>(new Whitespace())); 10 | @Override 11 | public Character parse(State s) 12 | throws Exception { 13 | return parser.parse(s); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/SkipSpaces.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by march on 16/9/12. 9 | * SkipSpaces is a parser skip all spaces. 10 | */ 11 | public class SkipSpaces 12 | implements Parsec { 13 | private final Parsec parser = new Skip<>(new Whitespace()); 14 | @Override 15 | public Character parse(State s) 16 | throws Exception { 17 | return parser.parse(s); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/SkipWhitespaces.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by march on 16/9/12. 9 | * SkipSpaces is a parser skip all whitespaces. 10 | */ 11 | public class SkipWhitespaces 12 | implements Parsec { 13 | private final Parsec parser = new Skip<>(new Whitespace()); 14 | @Override 15 | public Character parse(State s) 16 | throws Exception { 17 | return parser.parse(s); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Space.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * Space 匹配空格 10 | */ 11 | public class Space 12 | implements Parsec { 13 | @Override 14 | public Character parse(State s) 15 | throws EOFException, ParsecException { 16 | Character re = s.next(); 17 | if (Character.isSpaceChar(re)) { 18 | return re; 19 | } else { 20 | String message = String.format("Expect %c is space.", re); 21 | throw s.trap(message); 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/State.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | /** 4 | * Common State 是简化的 State 规范,支持整型索引和事务标示 5 | */ 6 | public interface State extends jaskell.parsec.State { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/UDecimal.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * UDecimal 尝试将后续信息流解析成一个表示无符号浮点数的字符串,如果匹配失败就抛出异常. 10 | */ 11 | public class UDecimal 12 | implements Parsec { 13 | private final Parsec uint = new UInt(); 14 | private final Parsec dot = new Attempt<>(new Ch('.')); 15 | 16 | @Override 17 | public String parse(State s) 18 | throws Exception { 19 | StringBuilder builder = new StringBuilder(); 20 | builder.append(uint.parse(s)); 21 | if(dot.exec(s).isOk()){ 22 | builder.append('.'); 23 | builder.append(uint.parse(s)); 24 | } 25 | return builder.toString(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/UInt.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by Mars Liu on 2016-01-07. 10 | * UInt 尝试将后续信息流解析成一个表示无符号整数的字符串,如果匹配失败就抛出异常. 11 | */ 12 | public class UInt 13 | implements Parsec { 14 | private final Parsec> parser = new Many1<>(new Digit()); 15 | @Override 16 | public String parse(State s) 17 | throws Exception { 18 | List buffer = parser.parse(s); 19 | StringBuilder sb = new StringBuilder(); 20 | buffer.forEach(sb::append); 21 | return sb.toString(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/jaskell/parsec/common/Whitespace.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | 5 | import java.io.EOFException; 6 | 7 | /** 8 | * Created by Mars Liu on 2016-01-07. 9 | * Whitespace 匹配空白字符 10 | */ 11 | public class Whitespace 12 | implements Parsec { 13 | @Override 14 | public Character parse(State s) 15 | throws EOFException, ParsecException { 16 | Character re = s.next(); 17 | if (Character.isWhitespace(re)) { 18 | return re; 19 | } else { 20 | String message = String.format("Expect %c is whitespace.", re); 21 | throw s.trap(message); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/script/Directive.java: -------------------------------------------------------------------------------- 1 | package jaskell.script; 2 | 3 | import java.util.List; 4 | 5 | public interface Directive { 6 | String script(); 7 | List> parameters(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/jaskell/script/Parameter.java: -------------------------------------------------------------------------------- 1 | package jaskell.script; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | 7 | public class Parameter implements Directive { 8 | private Optional _value = null; 9 | private Object _key; 10 | private int _order; 11 | private Class _cls; 12 | private String _placeHolder; 13 | 14 | protected Parameter(){} 15 | 16 | public Parameter(String placeHolder, Object key, Class cls){ 17 | this._placeHolder = placeHolder; 18 | _key = key; 19 | _cls = cls; 20 | } 21 | 22 | public T value(){ 23 | return _value.orElse(null); 24 | } 25 | 26 | public void value(T v){ 27 | _value = Optional.ofNullable(v); 28 | } 29 | 30 | public boolean confirmed(){ 31 | return _value != null; 32 | } 33 | 34 | public String placeHolder(){ 35 | return _placeHolder; 36 | } 37 | 38 | public Class valueClass(){ 39 | return _cls; 40 | } 41 | 42 | public Object key(){ 43 | return _key; 44 | } 45 | 46 | public int order(){ 47 | return _order; 48 | } 49 | 50 | public void order(int o){ 51 | this._order = o; 52 | } 53 | 54 | @Override 55 | public String script() { 56 | return _placeHolder; 57 | } 58 | 59 | @Override 60 | public List> parameters() { 61 | List> re = new ArrayList<>(); 62 | re.add(this); 63 | return re; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Alias.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Alias implements Directive, CouldJoin { 9 | Directive _query; 10 | private final Name _name; 11 | 12 | public Alias(String name){ 13 | this._name = new Name(name); 14 | } 15 | 16 | @Override 17 | public String script() { 18 | return String.format("(%s) AS %s", 19 | _query.script(), 20 | _name.script()); 21 | } 22 | 23 | @Override 24 | public List> parameters() { 25 | return _query.parameters(); 26 | } 27 | 28 | public Join join(Directive other){ 29 | Join re = new Join(); 30 | re._prefix = this; 31 | re._join = other; 32 | return re; 33 | } 34 | 35 | public Left left(){ 36 | Left re = new Left(); 37 | re._prefix = this; 38 | return re; 39 | } 40 | 41 | public Right right(){ 42 | Right re = new Right(); 43 | re._prefix = this; 44 | return re; 45 | } 46 | 47 | public Full full(){ 48 | Full re = new Full(); 49 | re._prefix = this; 50 | return re; 51 | } 52 | 53 | public Inner inner(){ 54 | Inner re = new Inner(); 55 | re._prefix = this; 56 | return re; 57 | } 58 | 59 | public Cross cross(){ 60 | Cross re = new Cross(); 61 | re._prefix = this; 62 | return re; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/And.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class And extends Binary { 9 | @Override 10 | protected String operator() { 11 | return " AND "; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Binary.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public abstract class Binary extends Predicate { 9 | Directive _left; 10 | Directive _right; 11 | 12 | protected abstract String operator(); 13 | 14 | @Override 15 | public String script() { 16 | return String.format("%s%s%s", _left.script(), operator(), _right.script()); 17 | } 18 | 19 | @Override 20 | public List> parameters() { 21 | List> re = _left.parameters(); 22 | re.addAll(_right.parameters()); 23 | return re; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Brackets.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Brackets extends Predicate { 9 | Directive _segment; 10 | 11 | @Override 12 | public String script() { 13 | return String.format("(%s)", _segment.script()); 14 | } 15 | 16 | @Override 17 | public List> parameters() { 18 | return _segment.parameters(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldAlias.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/06/10 21:01 11 | */ 12 | public interface CouldAlias extends Directive { 13 | default Alias as(String name){ 14 | Alias re = new Alias(name); 15 | re._query = this; 16 | return re; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldFrom.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/06/10 20:54 11 | */ 12 | public interface CouldFrom extends CouldHaving { 13 | From from(String name); 14 | 15 | From from(Directive f); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldGroup.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/05/15 17:02 11 | */ 12 | public interface CouldGroup extends Directive { 13 | Group group(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldHaving.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/07/09 18:03 11 | */ 12 | public interface CouldHaving extends Directive { 13 | default Having having(Predicate predicate) { 14 | Having re = new Having(predicate); 15 | re._by = this; 16 | return re; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldJoin.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/06/10 20:57 11 | */ 12 | public interface CouldJoin { 13 | Join join(Directive other); 14 | 15 | Left left(); 16 | 17 | Right right(); 18 | 19 | Full full(); 20 | 21 | Inner inner(); 22 | 23 | Cross cross(); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldLimit.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/05/15 17:04 11 | */ 12 | public interface CouldLimit extends Directive { 13 | default Limit limit(int l) { 14 | Limit result = new Limit(l); 15 | result._prefix = this; 16 | return result; 17 | } 18 | 19 | default Limit limit(Directive l) { 20 | Limit result = new Limit(l); 21 | result._prefix = this; 22 | return result; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldOffset.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/05/15 17:04 11 | */ 12 | public interface CouldOffset extends Directive { 13 | default Offset offset(int o) { 14 | Offset result = new Offset(o); 15 | result._prefix = this; 16 | return result; 17 | } 18 | 19 | default Offset offset(Directive o) { 20 | Offset result = new Offset(o); 21 | result._prefix = this; 22 | return result; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldOrder.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/05/15 17:01 11 | */ 12 | public interface CouldOrder extends Directive { 13 | Order order(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldReturning.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | import java.util.Arrays; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * TODO 10 | * 11 | * @author mars 12 | * @version 1.0.0 13 | * @since 2020/07/15 22:18 14 | */ 15 | public interface CouldReturning extends Directive { 16 | default Returning returning() { 17 | Returning result = new Returning(); 18 | result._prefix = this; 19 | return result; 20 | } 21 | 22 | default Returning returning(String fields){ 23 | Returning result = new Returning(fields); 24 | result._prefix = this; 25 | return result; 26 | } 27 | 28 | default Returning returning(String ... fields){ 29 | Returning result = new Returning(fields); 30 | result._prefix = this; 31 | return result; 32 | } 33 | 34 | default Returning returning(Directive... fields){ 35 | Returning result = new Returning(fields); 36 | result._prefix = this; 37 | return result; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldUnion.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/06/10 20:54 11 | */ 12 | public interface CouldUnion extends Directive { 13 | default Union union(String name){ 14 | Union result = new Union(); 15 | result._prefix = this; 16 | return result; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/CouldWhere.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2020/06/10 20:59 9 | */ 10 | public interface CouldWhere { 11 | Where where(Predicate predicate); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Count.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Count extends Literal { 9 | private Name _field = null; 10 | Count(){ 11 | 12 | } 13 | Count(String name){ 14 | _field = new Name(name); 15 | } 16 | Count(Name name){ 17 | _field = name; 18 | } 19 | @Override 20 | public String script() { 21 | if(_field != null) { 22 | return String.format("COUNT(%s)", _field.script()); 23 | }else{ 24 | return "COUNT(*)"; 25 | } 26 | } 27 | 28 | @Override 29 | public List> parameters() { 30 | return _field.parameters(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Cross.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Cross implements Directive { 9 | Directive _prefix; 10 | 11 | public Join join(Directive other){ 12 | Join re = new Join(); 13 | re._prefix = this; 14 | re._join = other; 15 | return re; 16 | } 17 | 18 | @Override 19 | public String script() { 20 | return String.format("%s CROSS", _prefix.script()); 21 | } 22 | 23 | @Override 24 | public List> parameters() { 25 | return _prefix.parameters(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Equal.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Equal extends Binary { 9 | @Override 10 | protected String operator() { 11 | return " = "; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Exists.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | import java.util.Optional; 8 | import java.util.stream.Collectors; 9 | import java.util.stream.Stream; 10 | 11 | public class Exists extends Predicate { 12 | Optional _prefix; 13 | Directive directive; 14 | 15 | Exists(Directive directive){ 16 | _prefix = Optional.empty(); 17 | this.directive = directive; 18 | } 19 | 20 | @Override 21 | public String script() { 22 | if(_prefix.isPresent()) { 23 | return String.format("%s EXISTS(%s)", _prefix.get().script(), directive.script()); 24 | }else { 25 | return String.format("EXISTS(%s)", directive.script()); 26 | } 27 | } 28 | 29 | @Override 30 | public List> parameters() { 31 | if (_prefix.isPresent()){ 32 | return Stream.concat(_prefix.get().parameters().stream(), directive.parameters().stream()) 33 | .collect(Collectors.toList()); 34 | }else { 35 | return directive.parameters(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/From.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2020/06/10 20:55 11 | */ 12 | public interface From extends Directive, CouldUnion, CouldLimit, CouldOffset { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Full.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Full implements Directive { 9 | Directive _prefix; 10 | 11 | public Join join(Directive other){ 12 | Join re = new Join(); 13 | re._prefix = this; 14 | re._join = other; 15 | return re; 16 | } 17 | 18 | @Override 19 | public String script() { 20 | return String.format("%s FULL", _prefix.script()); 21 | } 22 | 23 | @Override 24 | public List> parameters() { 25 | return _prefix.parameters(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Func.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | public class Func extends Literal { 12 | List _args = new ArrayList<>(); 13 | 14 | public Func(String name, Directive ... parameters){ 15 | super(name); 16 | _args.addAll(Arrays.asList(parameters)); 17 | } 18 | 19 | @Override 20 | public String script() { 21 | return String.format("%s(%s)", 22 | super.script(), 23 | _args.stream().map(Directive::script).collect(Collectors.joining(", "))); 24 | } 25 | 26 | @Override 27 | public List> parameters() { 28 | List> re = new ArrayList>(); 29 | _args.forEach(p->re.addAll(p.parameters())); 30 | return re; 31 | } 32 | 33 | public Func arg(Directive a){ 34 | _args.add(a); 35 | return this; 36 | } 37 | 38 | public Func args(Directive ... as){ 39 | _args.addAll(Arrays.asList(as)); 40 | return this; 41 | } 42 | 43 | public static Func max(Directive argument){ 44 | return new Func("MAX", argument); 45 | } 46 | 47 | public static Func min(Directive argument){ 48 | return new Func("MIN", argument); 49 | } 50 | 51 | public static Func avg(Directive argument){ 52 | return new Func("AVGs", argument); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Great.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | public class Great extends Binary { 4 | @Override 5 | protected String operator() { 6 | return " > "; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/GreateOrEqual.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | public class GreateOrEqual extends Binary{ 4 | @Override 5 | protected String operator() { 6 | return " >= "; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Having.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class Having extends Query implements CouldOrder, CouldLimit, CouldOffset { 10 | CouldHaving _by; 11 | Predicate _predicate; 12 | 13 | public Having(Predicate _predicate){ 14 | this._predicate = _predicate; 15 | } 16 | 17 | @Override 18 | public String script() { 19 | return String.format("%s HAVING %s", 20 | _by.script(), 21 | _predicate.script()); 22 | } 23 | 24 | @Override 25 | public List> parameters() { 26 | List> re = new ArrayList>(); 27 | re.addAll(_by.parameters()); 28 | re.addAll(_predicate.parameters()); 29 | return re; 30 | } 31 | 32 | public Order order(){ 33 | Order re = new Order(); 34 | re._prefix = this; 35 | return re; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/In.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class In implements Directive { 9 | Directive _statement; 10 | 11 | In(Directive statement){ 12 | this._statement = statement; 13 | } 14 | 15 | @Override 16 | public String script() { 17 | return String.format("IN (%s)", _statement.script()); 18 | } 19 | 20 | @Override 21 | public List> parameters() { 22 | return _statement.parameters(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Inner.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Inner implements Directive { 9 | Directive _prefix; 10 | 11 | public Join join(Directive other){ 12 | Join re = new Join(); 13 | re._prefix = this; 14 | re._join = other; 15 | return re; 16 | } 17 | 18 | @Override 19 | public String script() { 20 | return String.format("%s INNER", _prefix.script()); 21 | } 22 | 23 | @Override 24 | public List> parameters() { 25 | return _prefix.parameters(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Insert.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class Insert implements Directive { 10 | @Override 11 | public String script() { 12 | return "INSERT"; 13 | } 14 | 15 | @Override 16 | public List> parameters() { 17 | return new ArrayList<>(); 18 | } 19 | 20 | public Into into(String name) { 21 | Into re = new Into(name); 22 | re._prefix = this; 23 | return re; 24 | } 25 | 26 | public Into into(String name, String fields) { 27 | Into re = new Into(name, fields); 28 | re._prefix = this; 29 | return re; 30 | } 31 | 32 | public Into into(String name, String ... fields) { 33 | Into re = new Into(name, fields); 34 | re._prefix = this; 35 | return re; 36 | } 37 | 38 | public Into into(String name, Directive ... fields) { 39 | Into re = new Into(name, fields); 40 | re._prefix = this; 41 | return re; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/IsNotNull.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class IsNotNull extends Predicate { 9 | Directive _prefix; 10 | @Override 11 | public String script() { 12 | return String.format("%s IS NOT NULL", _prefix.script()); 13 | } 14 | 15 | @Override 16 | public List> parameters() { 17 | return _prefix.parameters(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/IsNull.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class IsNull extends Predicate { 9 | Directive _prefix; 10 | @Override 11 | public String script() { 12 | return String.format("%s IS NULL", _prefix.script()); 13 | } 14 | 15 | @Override 16 | public List> parameters() { 17 | return _prefix.parameters(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/JDBCParameter.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Parameter; 4 | 5 | public class JDBCParameter extends Parameter { 6 | // TODO: constructors type safe; 7 | @SuppressWarnings("unchecked") 8 | public JDBCParameter(Object key) { 9 | super("?", key, (Class) Object.class); 10 | } 11 | 12 | public JDBCParameter(Object key, Class cls) { 13 | super("?", key, cls); 14 | } 15 | 16 | public JDBCParameter(String placeHolder, Object key) { 17 | super(placeHolder, key, (Class) Object.class); 18 | } 19 | 20 | public JDBCParameter(String placeHolder, Object key, Class cls) { 21 | super(placeHolder, key, cls); 22 | } 23 | // TODO: value setters type safe; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Left.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Left implements Directive { 9 | Directive _prefix; 10 | 11 | public Join join(Directive other){ 12 | Join re = new Join(); 13 | re._prefix = this; 14 | re._join = other; 15 | return re; 16 | } 17 | 18 | @Override 19 | public String script() { 20 | return String.format("%s LEFT", _prefix.script()); 21 | } 22 | 23 | @Override 24 | public List> parameters() { 25 | return _prefix.parameters(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Less.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | public class Less extends Binary { 4 | @Override 5 | protected String operator() { 6 | return " < "; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/LessOrEqual.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | public class LessOrEqual extends Binary { 4 | @Override 5 | protected String operator() { 6 | return " <= "; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Like.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | public class Like extends Binary { 4 | @Override 5 | protected String operator() { 6 | return " LIKE "; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Limit.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Limit extends Query implements CouldOffset { 9 | Directive _prefix; 10 | Directive _limit; 11 | Limit(int limit){ 12 | this._limit = new Literal(limit); 13 | } 14 | 15 | Limit(Directive limit){ 16 | this._limit = limit; 17 | } 18 | 19 | public Offset offset(int o){ 20 | Offset re = new Offset(o); 21 | re._prefix = this; 22 | return re; 23 | } 24 | 25 | public Offset offset(Directive o){ 26 | Offset re = new Offset(o); 27 | re._prefix = this; 28 | return re; 29 | } 30 | 31 | @Override 32 | public String script() { 33 | return String.format("%s LIMIT %s", _prefix.script(), _limit.script()); 34 | } 35 | 36 | @Override 37 | public List> parameters() { 38 | List> re = _prefix.parameters(); 39 | re.addAll(_limit.parameters()); 40 | return re; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Name.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class Name extends Literal implements CouldAlias { 9 | 10 | protected Name(){} 11 | 12 | public Name(String name) { 13 | _literal = name; 14 | } 15 | 16 | public String name(){ 17 | return _literal; 18 | } 19 | 20 | protected void name(String n){ 21 | _literal = n; 22 | } 23 | 24 | public String escaped() { 25 | return _literal.replace("\"", "\\\""); 26 | } 27 | 28 | public String escaped(Character c) { 29 | return _literal.replace(c.toString(), "\\"+c.toString()); 30 | } 31 | 32 | public String quotedName() { 33 | return String.format("\"%s\"", _literal.replace("\"", "\\\"")); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Not.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Optional; 9 | 10 | public class Not extends Predicate { 11 | Optional _predicate; 12 | Not(Directive predicate){ 13 | _predicate = Optional.of(predicate); 14 | } 15 | 16 | Not(){ 17 | _predicate = Optional.empty(); 18 | } 19 | 20 | @Override 21 | public String script() { 22 | if (_predicate.isPresent()){ 23 | return String.format("NOT(%s)", _predicate.get().script()); 24 | } else { 25 | return "NOT "; 26 | } 27 | } 28 | 29 | @Override 30 | public List> parameters() { 31 | if(_predicate.isPresent()){ 32 | return _predicate.get().parameters(); 33 | } else { 34 | return new ArrayList<>(); 35 | } 36 | } 37 | 38 | public Exists exists(Directive directive) { 39 | Exists re = new Exists(directive); 40 | re._prefix = Optional.of(this); 41 | return re; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/NotEqual.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | public class NotEqual extends Binary{ 4 | @Override 5 | protected String operator() { 6 | return " != "; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Nothing.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Nothing extends Statement { 9 | Directive _prefix; 10 | 11 | @Override 12 | public String script() { 13 | return String.format("%s NOTHING", _prefix.script()); 14 | } 15 | 16 | @Override 17 | public List> parameters() { 18 | return _prefix.parameters(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Offset.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Offset extends Query { 9 | Directive _prefix; 10 | Directive _offset; 11 | Offset(int offset){ 12 | this._offset = new Literal(offset); 13 | } 14 | 15 | Offset(Directive offset){ 16 | this._offset = offset; 17 | } 18 | 19 | @Override 20 | public String script() { 21 | return String.format("%s OFFSET %s", _prefix.script(), _offset.script()); 22 | } 23 | 24 | @Override 25 | public List> parameters() { 26 | List> re = _prefix.parameters(); 27 | re.addAll(_offset.parameters()); 28 | return re; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/On.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class On implements Directive, CouldAlias { 9 | Directive _prefix; 10 | 11 | @Override 12 | public String script() { 13 | return String.format("%s ON", _prefix.script()); 14 | } 15 | 16 | @Override 17 | public List> parameters() { 18 | return _prefix.parameters(); 19 | } 20 | 21 | public Conflict conflict(){ 22 | Conflict re = new Conflict(); 23 | re._prefix = this; 24 | return re; 25 | } 26 | 27 | public Conflict conflict(String names){ 28 | Conflict re = new Conflict(names); 29 | re._prefix = this; 30 | return re; 31 | } 32 | 33 | public Conflict conflict(String ... names){ 34 | Conflict re = new Conflict(names); 35 | re._prefix = this; 36 | return re; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Or.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | 5 | public class Or extends Binary { 6 | @Override 7 | protected String operator() { 8 | return " OR "; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Order.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Order implements Directive { 9 | Directive _prefix; 10 | 11 | @Override 12 | public String script() { 13 | return String.format("%s ORDER", _prefix.script()); 14 | } 15 | 16 | @Override 17 | public List> parameters() { 18 | return _prefix.parameters(); 19 | } 20 | 21 | public By by(String names) { 22 | By re = new By(names); 23 | re._prefix = this; 24 | return re; 25 | } 26 | 27 | public By by(String... names) { 28 | By re = new By(names); 29 | re._prefix = this; 30 | return re; 31 | } 32 | 33 | public By by(Directive... names) { 34 | By re = new By(names); 35 | re._prefix = this; 36 | return re; 37 | } 38 | 39 | public By by(List names) { 40 | By re = new By(names); 41 | re._prefix = this; 42 | return re; 43 | } 44 | 45 | 46 | public static class By extends jaskell.sql.By { 47 | By(String names) { 48 | super(names); 49 | } 50 | 51 | By(String... names) { 52 | super(names); 53 | } 54 | 55 | By(Directive... names) { 56 | super(names); 57 | } 58 | 59 | By(List names) { 60 | super(names); 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Quot.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | public class Quot extends Name { 4 | private final String _left; 5 | private final String _right; 6 | 7 | public Quot(String name) { 8 | super(name); 9 | _left = "\""; 10 | _right = "\""; 11 | } 12 | 13 | public Quot(String l, String name, String r){ 14 | super(name); 15 | this._left = l; 16 | this._right = r; 17 | } 18 | 19 | @Override 20 | public String script() { 21 | return String.format("%s%s%s", this._left, super.escaped(), this._right); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Right.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Right implements Directive{ 9 | Directive _prefix; 10 | 11 | public Join join(Directive other){ 12 | Join re = new Join(); 13 | re._prefix = this; 14 | re._join = other; 15 | return re; 16 | } 17 | 18 | @Override 19 | public String script() { 20 | return String.format("%s RIGHT", _prefix.script()); 21 | } 22 | 23 | @Override 24 | public List> parameters() { 25 | return _prefix.parameters(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Sum.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Parameter; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/05/01 17:09 13 | */ 14 | public class Sum extends Literal { 15 | private Name _field = null; 16 | Sum(){ 17 | 18 | } 19 | Sum(String name){ 20 | _field = new Name(name); 21 | } 22 | Sum(Name name){ 23 | _field = name; 24 | } 25 | @Override 26 | public String script() { 27 | if(_field != null) { 28 | return String.format("SUM(%s)", _field.script()); 29 | }else{ 30 | return "SUM(*)"; 31 | } 32 | } 33 | 34 | @Override 35 | public List> parameters() { 36 | return _field.parameters(); 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Text.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | public class Text extends Literal { 4 | Text(String content){ 5 | _literal = String.format("'%s'", content.replaceAll("'", "''")); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Union.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Union extends Query implements ThenSelect { 9 | Directive _prefix; 10 | Directive _query; 11 | 12 | public Union() { 13 | } 14 | 15 | public Union(Query query) { 16 | this._query = query; 17 | } 18 | 19 | public All all(Query query) { 20 | All re = new All(); 21 | re._prefix = this._prefix; 22 | re._query = query; 23 | return re; 24 | } 25 | 26 | @Override 27 | public String script() { 28 | if (_query == null) { 29 | return String.format("%s UNION", _prefix.script()); 30 | } else { 31 | return String.format("%s UNION %s", _prefix.script(), _query.script()); 32 | } 33 | } 34 | 35 | @Override 36 | public List> parameters() { 37 | List> re = _prefix.parameters(); 38 | re.addAll(_query.parameters()); 39 | return re; 40 | } 41 | 42 | public static class All extends Union implements ThenSelect { 43 | @Override 44 | public String script() { 45 | return String.format("%s UNION ALL %s", _prefix.script(), _query.script()); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Values.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | 4 | import jaskell.script.Directive; 5 | import jaskell.script.Parameter; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | 12 | public class Values extends Statement { 13 | Directive _insert; 14 | List _fields = new ArrayList<>(); 15 | 16 | public Values(String fields){ 17 | _fields.addAll( 18 | Arrays.stream(fields.split(",")).map(String::trim).map(Name::new).collect(Collectors.toList())); 19 | } 20 | 21 | public Values(String ... fields){ 22 | _fields.addAll( 23 | Arrays.stream(fields).map(String::trim).map(Name::new).collect(Collectors.toList())); 24 | } 25 | 26 | public Values(Directive... fields){ 27 | _fields.addAll(Arrays.asList(fields)); 28 | } 29 | 30 | @Override 31 | public String script() { 32 | return String.format("%s VALUES(%s)", 33 | _insert.script(), 34 | _fields.stream().map(Directive::script).collect(Collectors.joining(", "))); 35 | } 36 | 37 | @Override 38 | public List> parameters() { 39 | List> re = _insert.parameters(); 40 | _fields.forEach(field->re.addAll(field.parameters())); 41 | return re; 42 | } 43 | 44 | public On on(){ 45 | On re = new On(); 46 | re._prefix = this; 47 | return re; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/jaskell/sql/Where.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import jaskell.script.Directive; 4 | import jaskell.script.Parameter; 5 | 6 | import java.util.List; 7 | 8 | public class Where extends Query implements CouldOrder, CouldGroup, CouldLimit, CouldOffset, 9 | CouldAlias, CouldHaving, CouldUnion { 10 | Directive _prefix; 11 | Predicate _predicate; 12 | 13 | Where(Predicate predicate){ 14 | this._predicate = predicate; 15 | } 16 | 17 | @Override 18 | public String script() { 19 | return String.format("%s WHERE %s", _prefix.script(), _predicate.script()); 20 | } 21 | 22 | @Override 23 | public List> parameters() { 24 | List> re = _prefix.parameters(); 25 | re.addAll(_predicate.parameters()); 26 | return re; 27 | } 28 | 29 | public Group group() { 30 | Group re = new Group(); 31 | re._prefix = this; 32 | return re; 33 | } 34 | 35 | public Order order() { 36 | Order re = new Order(); 37 | re._prefix = this; 38 | return re; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/jaskell/util/BiConsumer.java: -------------------------------------------------------------------------------- 1 | package jaskell.util; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2023/11/17 14:01 11 | */ 12 | public interface BiConsumer { 13 | /** 14 | * Performs this operation on the given arguments. 15 | * 16 | * @param t the first input argument 17 | * @param u the second input argument 18 | */ 19 | void accept(T t, U u) throws Exception; 20 | 21 | /** 22 | * Returns a composed {@code BiConsumer} that performs, in sequence, this 23 | * operation followed by the {@code after} operation. If performing either 24 | * operation throws an exception, it is relayed to the caller of the 25 | * composed operation. If performing this operation throws an exception, 26 | * the {@code after} operation will not be performed. 27 | * 28 | * @param after the operation to perform after this operation 29 | * @return a composed {@code BiConsumer} that performs in sequence this 30 | * operation followed by the {@code after} operation 31 | * @throws NullPointerException if {@code after} is null 32 | */ 33 | default BiConsumer andThen(BiConsumer after) throws Exception { 34 | Objects.requireNonNull(after); 35 | 36 | return (l, r) -> { 37 | accept(l, r); 38 | after.accept(l, r); 39 | }; 40 | } 41 | 42 | default Consumer curry(T t) { 43 | return (U u) -> accept(t, u); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/jaskell/util/Consumer.java: -------------------------------------------------------------------------------- 1 | package jaskell.util; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author mars 9 | * @version 1.0.0 10 | * @since 2023/11/17 14:01 11 | */ 12 | public interface Consumer { 13 | /** 14 | * Performs this operation on the given arguments. 15 | * 16 | * @param t the first input argument 17 | */ 18 | void accept(T t) throws Exception; 19 | 20 | /** 21 | * Returns a composed {@code BiConsumer} that performs, in sequence, this 22 | * operation followed by the {@code after} operation. If performing either 23 | * operation throws an exception, it is relayed to the caller of the 24 | * composed operation. If performing this operation throws an exception, 25 | * the {@code after} operation will not be performed. 26 | * 27 | * @param after the operation to perform after this operation 28 | * @return a composed {@code BiConsumer} that performs in sequence this 29 | * operation followed by the {@code after} operation 30 | * @throws NullPointerException if {@code after} is null 31 | */ 32 | default Consumer andThen(Consumer after) throws Exception { 33 | Objects.requireNonNull(after); 34 | 35 | return (x) -> { 36 | accept(x); 37 | after.accept(x); 38 | }; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/jaskell/util/Distance.java: -------------------------------------------------------------------------------- 1 | package jaskell.util; 2 | 3 | public class Distance { 4 | public static int levenshtein(String source, String target) { 5 | int src_length = source.length() + 1; 6 | int tgt_length = target.length() + 1; 7 | 8 | if (src_length == 1) { 9 | return tgt_length - 1; 10 | } 11 | 12 | if (tgt_length == 1) { 13 | return src_length - 1; 14 | } 15 | 16 | int[][] matrix = new int[src_length][tgt_length]; 17 | for (int i = 0; i < src_length; i++) { 18 | matrix[i][0] = i; 19 | } 20 | for (int i = 0; i < tgt_length; i++) { 21 | matrix[0][i] = i; 22 | } 23 | 24 | for (int i = 1; i < src_length; i++) { 25 | char src_char = source.charAt(i-1); 26 | for (int j = 1; j < tgt_length; j++) { 27 | char tgt_char = target.charAt(j-1); 28 | int cost = (src_char == tgt_char)?0:1; 29 | int above = matrix[i-1][j]+1; 30 | int left = matrix[i][j-1]+1; 31 | int diag = matrix[i-1][j-1]+cost; 32 | int value = Math.min(above, Math.min(left, diag)); 33 | matrix[i][j] = value; 34 | } 35 | } 36 | return matrix[src_length - 1][tgt_length - 1]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/jaskell/util/Function.java: -------------------------------------------------------------------------------- 1 | package jaskell.util; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2023/11/16 18:42 9 | */ 10 | public interface Function { 11 | U apply(T arg) throws Exception; 12 | 13 | default Try collect(T arg) { 14 | try { 15 | return Try.success(apply(arg)); 16 | } catch (Exception err) { 17 | return Try.failure(err); 18 | } 19 | } 20 | 21 | default Function andThen(Function other) { 22 | return (T arg)-> other.apply(apply(arg)); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/jaskell/util/Supplier.java: -------------------------------------------------------------------------------- 1 | package jaskell.util; 2 | 3 | /** 4 | * TODO 5 | * 6 | * @author mars 7 | * @version 1.0.0 8 | * @since 2023/11/16 18:44 9 | */ 10 | public interface Supplier extends Triable { 11 | T get() throws Exception; 12 | 13 | default Try collect() { 14 | try { 15 | return Try.success(get()); 16 | } catch (Exception e) { 17 | return Try.failure(e); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/jaskell/Handler.java: -------------------------------------------------------------------------------- 1 | package jaskell; 2 | 3 | public interface Handler { 4 | U handle(T arg); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/jaskell/Handler2.java: -------------------------------------------------------------------------------- 1 | package jaskell; 2 | 3 | public interface Handler2 { 4 | long handle(long x, long y); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/Compare.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak; 2 | 3 | import jaskell.expression.Binary; 4 | import jaskell.expression.Env; 5 | import jaskell.expression.Expression; 6 | import jaskell.expression.ExpressionException; 7 | 8 | /** 9 | * TODO 10 | * 11 | * @author mars 12 | * @version 1.0.0 13 | * @since 2020/07/04 17:24 14 | */ 15 | public abstract class Compare extends Binary { 16 | @Override 17 | public int getPriority() { 18 | return 3; 19 | } 20 | 21 | @Override 22 | public double eval(Env env) throws ExpressionException { 23 | if (left instanceof Compare) { 24 | return toInt(((Compare) left).compare(((Compare) left).left, ((Compare) left).right, env) && 25 | compare(((Compare)left).right, right, env)); 26 | } else { 27 | return toInt(compare(left, right, env)); 28 | } 29 | } 30 | 31 | public int toInt(boolean value) { 32 | return value ? 1: 0; 33 | } 34 | 35 | public abstract boolean compare(Expression l, Expression r, Env env) throws ExpressionException; 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/Equals.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak; 2 | 3 | import jaskell.expression.Env; 4 | import jaskell.expression.Expression; 5 | import jaskell.expression.ExpressionException; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/07/04 17:31 13 | */ 14 | public class Equals extends Compare { 15 | public Equals(Expression left, Expression right) { 16 | this.left = left; 17 | this.right = right; 18 | } 19 | 20 | 21 | @Override 22 | public boolean compare(Expression l, Expression r, Env env) throws ExpressionException { 23 | return l.eval(env) == right.eval(env); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/Great.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak; 2 | 3 | import jaskell.expression.Env; 4 | import jaskell.expression.Expression; 5 | import jaskell.expression.ExpressionException; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/07/10 16:45 13 | */ 14 | public class Great extends Compare { 15 | public Great(Expression left, Expression right) { 16 | this.left = left; 17 | this.right = right; 18 | } 19 | 20 | 21 | @Override 22 | public boolean compare(Expression l, Expression r, Env env) throws ExpressionException { 23 | return l.eval(env) > right.eval(env); 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/GreatOrEquals.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak; 2 | 3 | import jaskell.expression.Env; 4 | import jaskell.expression.Expression; 5 | import jaskell.expression.ExpressionException; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/07/10 16:45 13 | */ 14 | public class GreatOrEquals extends Compare { 15 | public GreatOrEquals(Expression left, Expression right) { 16 | this.left = left; 17 | this.right = right; 18 | } 19 | 20 | 21 | @Override 22 | public boolean compare(Expression l, Expression r, Env env) throws ExpressionException { 23 | return l.eval(env) >= right.eval(env); 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/Less.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak; 2 | 3 | import jaskell.expression.Env; 4 | import jaskell.expression.Expression; 5 | import jaskell.expression.ExpressionException; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/07/10 16:45 13 | */ 14 | public class Less extends Compare { 15 | public Less(Expression left, Expression right) { 16 | this.left = left; 17 | this.right = right; 18 | } 19 | 20 | 21 | @Override 22 | public boolean compare(Expression l, Expression r, Env env) throws ExpressionException { 23 | return l.eval(env) < right.eval(env); 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/LessOrEquals.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak; 2 | 3 | import jaskell.expression.Env; 4 | import jaskell.expression.Expression; 5 | import jaskell.expression.ExpressionException; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/07/10 16:45 13 | */ 14 | public class LessOrEquals extends Compare { 15 | public LessOrEquals(Expression left, Expression right) { 16 | this.left = left; 17 | this.right = right; 18 | } 19 | 20 | 21 | @Override 22 | public boolean compare(Expression l, Expression r, Env env) throws ExpressionException { 23 | return l.eval(env) <= right.eval(env); 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/NotEquals.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak; 2 | 3 | import jaskell.expression.Env; 4 | import jaskell.expression.Expression; 5 | import jaskell.expression.ExpressionException; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author mars 11 | * @version 1.0.0 12 | * @since 2020/07/10 16:39 13 | */ 14 | public class NotEquals extends Compare { 15 | public NotEquals(Expression left, Expression right) { 16 | this.left = left; 17 | this.right = right; 18 | } 19 | 20 | @Override 21 | public boolean compare(Expression l, Expression r, Env env) throws ExpressionException { 22 | return l.eval(env) != right.eval(env); 23 | } 24 | } -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/A.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.ch; 4 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 5 | 6 | import jaskell.expression.Add; 7 | import jaskell.expression.Expression; 8 | import jaskell.parsec.ParsecException; 9 | import jaskell.parsec.common.Parsec; 10 | import jaskell.parsec.common.SkipWhitespaces; 11 | import jaskell.parsec.common.State; 12 | 13 | import java.io.EOFException; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/06/04 10:56 21 | */ 22 | public class A implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(ch('+')).then(skips); 25 | private final Expression prev; 26 | 27 | public A(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Add parse(State s) throws Exception { 33 | Parsec parser = new WeakParser(); 34 | op.parse(s); 35 | return new Add(prev, parser.parse(s)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/D.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.ch; 4 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 5 | 6 | import jaskell.expression.Divide; 7 | import jaskell.expression.Expression; 8 | import jaskell.parsec.ParsecException; 9 | import jaskell.parsec.common.Parsec; 10 | import jaskell.parsec.common.SkipWhitespaces; 11 | import jaskell.parsec.common.State; 12 | 13 | import java.io.EOFException; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/06/04 10:56 21 | */ 22 | public class D implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(ch('/')).then(skips); 25 | private final Expression prev; 26 | 27 | public D(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Divide parse(State s) throws Exception { 33 | Parsec parser = new WeakParser(); 34 | op.parse(s); 35 | return new Divide(prev, parser.parse(s)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/Eq.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 4 | import static jaskell.parsec.common.Txt.text; 5 | 6 | import jaskell.expression.parser.Parser; 7 | import jaskell.expression.weak.Equals; 8 | import jaskell.expression.Expression; 9 | import jaskell.parsec.ParsecException; 10 | import jaskell.parsec.common.Parsec; 11 | import jaskell.parsec.common.SkipWhitespaces; 12 | import jaskell.parsec.common.State; 13 | 14 | import java.io.EOFException; 15 | 16 | /** 17 | * TODO 18 | * 19 | * @author mars 20 | * @version 1.0.0 21 | * @since 2020/07/04 17:33 22 | */ 23 | public class Eq implements Parsec { 24 | private final SkipWhitespaces skips = skipWhiteSpaces(); 25 | private final Parsec op = skips.then(text("==")).then(skips); 26 | private final Expression prev; 27 | 28 | public Eq(Expression prev) { 29 | this.prev = prev; 30 | } 31 | 32 | @Override 33 | public Equals parse(State s) throws Exception { 34 | Parsec parser = new WeakParser(); 35 | op.parse(s); 36 | return new Equals(prev, parser.parse(s)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/Grt.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 4 | import static jaskell.parsec.common.Txt.text; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.parser.Parser; 8 | import jaskell.expression.weak.Great; 9 | import jaskell.parsec.ParsecException; 10 | import jaskell.parsec.common.Parsec; 11 | import jaskell.parsec.common.SkipWhitespaces; 12 | import jaskell.parsec.common.State; 13 | 14 | import java.io.EOFException; 15 | 16 | /** 17 | * TODO 18 | * 19 | * @author mars 20 | * @version 1.0.0 21 | * @since 2020/07/10 16:27 22 | */ 23 | public class Grt implements Parsec { 24 | private final SkipWhitespaces skips = skipWhiteSpaces(); 25 | private final Parsec op = skips.then(text(">")).then(skips); 26 | private final Expression prev; 27 | 28 | public Grt(Expression prev) { 29 | this.prev = prev; 30 | } 31 | 32 | @Override 33 | public Great parse(State s) throws Exception { 34 | Parsec parser = new WeakParser(); 35 | op.parse(s); 36 | return new Great(prev, parser.parse(s)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/GrtOrEq.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 4 | import static jaskell.parsec.common.Txt.text; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.parser.Parser; 8 | import jaskell.expression.weak.GreatOrEquals; 9 | import jaskell.parsec.ParsecException; 10 | import jaskell.parsec.common.Parsec; 11 | import jaskell.parsec.common.SkipWhitespaces; 12 | import jaskell.parsec.common.State; 13 | 14 | import java.io.EOFException; 15 | 16 | /** 17 | * TODO 18 | * 19 | * @author mars 20 | * @version 1.0.0 21 | * @since 2020/07/10 16:27 22 | */ 23 | public class GrtOrEq implements Parsec { 24 | private final SkipWhitespaces skips = skipWhiteSpaces(); 25 | private final Parsec op = skips.then(text(">=")).then(skips); 26 | private final Expression prev; 27 | 28 | public GrtOrEq(Expression prev) { 29 | this.prev = prev; 30 | } 31 | 32 | @Override 33 | public GreatOrEquals parse(State s) throws Exception { 34 | Parsec parser = new WeakParser(); 35 | op.parse(s); 36 | return new GreatOrEquals(prev, parser.parse(s)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/Ls.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 4 | import static jaskell.parsec.common.Txt.text; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.weak.Less; 8 | import jaskell.parsec.ParsecException; 9 | import jaskell.parsec.common.Parsec; 10 | import jaskell.parsec.common.SkipWhitespaces; 11 | import jaskell.parsec.common.State; 12 | 13 | import java.io.EOFException; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/07/10 16:27 21 | */ 22 | public class Ls implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(text("<")).then(skips); 25 | private final Expression prev; 26 | 27 | public Ls(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Less parse(State s) throws Exception { 33 | Parsec parser = new WeakParser(); 34 | op.parse(s); 35 | return new Less(prev, parser.parse(s)); 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/LsOrEq.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 4 | import static jaskell.parsec.common.Txt.text; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.parser.Parser; 8 | import jaskell.expression.weak.LessOrEquals; 9 | import jaskell.parsec.ParsecException; 10 | import jaskell.parsec.common.Parsec; 11 | import jaskell.parsec.common.SkipWhitespaces; 12 | import jaskell.parsec.common.State; 13 | 14 | import java.io.EOFException; 15 | 16 | /** 17 | * TODO 18 | * 19 | * @author mars 20 | * @version 1.0.0 21 | * @since 2020/07/10 16:27 22 | */ 23 | public class LsOrEq implements Parsec { 24 | private final SkipWhitespaces skips = skipWhiteSpaces(); 25 | private final Parsec op = skips.then(text("<=")).then(skips); 26 | private final Expression prev; 27 | 28 | public LsOrEq(Expression prev) { 29 | this.prev = prev; 30 | } 31 | 32 | @Override 33 | public LessOrEquals parse(State s) throws Exception { 34 | Parsec parser = new WeakParser(); 35 | op.parse(s); 36 | return new LessOrEquals(prev, parser.parse(s)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/N.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import jaskell.expression.Expression; 4 | import jaskell.expression.Number; 5 | import jaskell.parsec.ParsecException; 6 | import jaskell.parsec.common.Parsec; 7 | import jaskell.parsec.common.ScNumber; 8 | import jaskell.parsec.common.State; 9 | 10 | import java.io.EOFException; 11 | 12 | 13 | /** 14 | * TODO 15 | * 16 | * @author mars 17 | * @version 1.0.0 18 | * @since 2020/06/04 10:53 19 | */ 20 | public class N implements Parsec { 21 | private final Parsec number = new ScNumber(); 22 | @Override 23 | public Number parse(State s) throws Exception { 24 | String re = number.parse(s); 25 | return new Number(Double.parseDouble(re)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/NotEq.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 4 | import static jaskell.parsec.common.Txt.text; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.parser.Parser; 8 | import jaskell.expression.weak.NotEquals; 9 | import jaskell.parsec.ParsecException; 10 | import jaskell.parsec.common.Parsec; 11 | import jaskell.parsec.common.SkipWhitespaces; 12 | import jaskell.parsec.common.State; 13 | 14 | import java.io.EOFException; 15 | 16 | /** 17 | * TODO 18 | * 19 | * @author mars 20 | * @version 1.0.0 21 | * @since 2020/07/10 16:30 22 | */ 23 | public class NotEq implements Parsec { 24 | private final SkipWhitespaces skips = skipWhiteSpaces(); 25 | private final Parsec op = skips.then(text("!=")).then(skips); 26 | private final Expression prev; 27 | 28 | public NotEq(Expression prev) { 29 | this.prev = prev; 30 | } 31 | 32 | @Override 33 | public NotEquals parse(State s) throws Exception { 34 | Parsec parser = new WeakParser(); 35 | op.parse(s); 36 | return new NotEquals(prev, parser.parse(s)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/P.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.ch; 4 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.Product; 8 | import jaskell.parsec.ParsecException; 9 | import jaskell.parsec.common.Parsec; 10 | import jaskell.parsec.common.SkipWhitespaces; 11 | import jaskell.parsec.common.State; 12 | 13 | import java.io.EOFException; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/06/04 10:56 21 | */ 22 | public class P implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(ch('*')).then(skips); 25 | private final Expression prev; 26 | 27 | public P(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Product parse(State s) throws Exception { 33 | Parsec parser = new WeakParser(); 34 | op.parse(s); 35 | return new Product(prev, parser.parse(s)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/Param.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Combinator.attempt; 4 | import static jaskell.parsec.common.Combinator.choice; 5 | import static jaskell.parsec.common.Combinator.many; 6 | import static jaskell.parsec.common.Txt.digit; 7 | import static jaskell.parsec.common.Txt.joining; 8 | import static jaskell.parsec.common.Txt.letter; 9 | 10 | import jaskell.expression.Expression; 11 | import jaskell.expression.Parameter; 12 | import jaskell.parsec.ParsecException; 13 | import jaskell.parsec.common.Parsec; 14 | import jaskell.parsec.common.State; 15 | 16 | import java.io.EOFException; 17 | 18 | /** 19 | * TODO 20 | * 21 | * @author mars 22 | * @version 1.0.0 23 | * @since 2020/06/10 17:54 24 | */ 25 | public class Param implements Parsec { 26 | private final Parsec head = letter(); 27 | 28 | private final Parsec tail = many(choice(attempt(head), digit())).bind(joining()); 29 | 30 | private final Parsec parser = s -> head.parse(s) + tail.parse(s); 31 | 32 | @Override 33 | public Expression parse(State s) throws Exception { 34 | return new Parameter(parser.parse(s)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/Q.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Combinator.between; 4 | import static jaskell.parsec.common.Txt.ch; 5 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 6 | 7 | import jaskell.expression.Expression; 8 | import jaskell.expression.Quote; 9 | import jaskell.parsec.ParsecException; 10 | import jaskell.parsec.common.Parsec; 11 | import jaskell.parsec.common.SkipWhitespaces; 12 | import jaskell.parsec.common.State; 13 | 14 | import java.io.EOFException; 15 | 16 | /** 17 | * TODO 18 | * 19 | * @author mars 20 | * @version 1.0.0 21 | * @since 2020/06/04 11:31 22 | */ 23 | public class Q implements Parsec { 24 | @Override 25 | public Quote parse(State s) throws Exception { 26 | WeakParser p = new WeakParser(); 27 | SkipWhitespaces skips = skipWhiteSpaces(); 28 | Parsec parser = between(ch('(').then(skips), skips.then(ch(')')), p); 29 | return new Quote(parser.parse(s)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/jaskell/expression/weak/parser/S.java: -------------------------------------------------------------------------------- 1 | package jaskell.expression.weak.parser; 2 | 3 | import static jaskell.parsec.common.Txt.ch; 4 | import static jaskell.parsec.common.Txt.skipWhiteSpaces; 5 | 6 | import jaskell.expression.Expression; 7 | import jaskell.expression.Sub; 8 | import jaskell.parsec.ParsecException; 9 | import jaskell.parsec.common.Parsec; 10 | import jaskell.parsec.common.SkipWhitespaces; 11 | import jaskell.parsec.common.State; 12 | 13 | import java.io.EOFException; 14 | 15 | /** 16 | * TODO 17 | * 18 | * @author mars 19 | * @version 1.0.0 20 | * @since 2020/06/04 10:56 21 | */ 22 | public class S implements Parsec { 23 | private final SkipWhitespaces skips = skipWhiteSpaces(); 24 | private final Parsec op = skips.then(ch('-')).then(skips); 25 | private final Expression prev; 26 | 27 | public S(Expression prev) { 28 | this.prev = prev; 29 | } 30 | 31 | @Override 32 | public Sub parse(State s) throws Exception { 33 | Parsec parser = new WeakParser(); 34 | op.parse(s); 35 | return new Sub(prev, parser.parse(s)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/AttemptTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | import static org.junit.jupiter.api.Assertions.*; 10 | 11 | public class AttemptTest extends Base { 12 | 13 | @Test 14 | public void simple() throws Exception { 15 | List data = Arrays.asList("Hello", "World"); 16 | 17 | State state = new SimpleState<>(data); 18 | Integer idx = state.status(); 19 | Attempt attemptIt = new Attempt<>(new Eq<>("Hello")); 20 | 21 | String re = attemptIt.parse(state); 22 | 23 | assertEquals(re, "Hello"); 24 | assertNotEquals(idx, state.status()); 25 | } 26 | 27 | @Test 28 | public void rollback() throws Exception { 29 | List data = Arrays.asList("Hello", "World"); 30 | SimpleState state = new SimpleState<>(data); 31 | Integer idx = state.status(); 32 | Attempt attemptIt = new Attempt<>(new Eq<>("hello")); 33 | 34 | assertThrowsExactly(ParsecException.class, 35 | () -> attemptIt.parse(state), 36 | "Expect a error for Hello."); 37 | assertEquals(idx, state.status()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/Base.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import java.util.stream.Collectors; 4 | import java.util.stream.IntStream; 5 | 6 | /** 7 | * Created by Mars Liu on 2016-01-09. 8 | * Base 为测试类提供共用的工具函数,继承它可以减少重复的代码书写. 9 | */ 10 | public abstract class Base { 11 | State newState(String data) { 12 | return new SimpleState<>(IntStream.range(0, data.length()) 13 | .mapToObj(data::charAt) 14 | .collect(Collectors.toList())); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/BetweenTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | /** 8 | * Between Tester. 9 | * 10 | * @author Mars Liu 11 | * 12 | * 13 | */ 14 | public class BetweenTest extends Base { 15 | 16 | 17 | /** 18 | * Method: script(State s) 19 | */ 20 | @Test 21 | public void simple() throws Exception { 22 | 23 | State state = newState("hello"); 24 | 25 | 26 | Between bmw = new Between<>( 27 | new Eq<>('h'), 28 | new Eq<>('l'), 29 | new Eq<>('e') 30 | ); 31 | 32 | Character c = bmw.parse(state); 33 | assertEquals('e', (char) c); 34 | } 35 | 36 | @Test 37 | public void brackets() throws Exception { 38 | 39 | State state = newState("[hello]"); 40 | 41 | 42 | Parsec parser = new Between<>( 43 | new Ch('['), 44 | new Ch<>(']'), 45 | new Many1<>(new Ne<>(']')) 46 | ).bind(new JoinText<>()); 47 | 48 | String re = parser.parse(state); 49 | assertEquals("hello", re); 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/EofTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertNull; 6 | 7 | /** 8 | * Eof Tester. 9 | * 10 | * @author 11 | * @version 1.0 12 | * @since
一月 9, 2016
13 | */ 14 | public class EofTest extends Base { 15 | 16 | /** 17 | * Method: script(State s) 18 | */ 19 | @Test 20 | public void testEof() throws Exception { 21 | State state = newState("hello"); 22 | 23 | Eof eof = new Eof<>(); 24 | 25 | new Text("hello").parse(state); 26 | Object e = eof.parse(state); 27 | assertNull(e); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/EqTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | 9 | /** 10 | * Eq Tester. 11 | * 12 | * @author 13 | * @version 1.0 14 | * @since
一月 9, 2016
15 | */ 16 | public class EqTest extends Base { 17 | 18 | /** 19 | * Method: script(State s) 20 | */ 21 | @Test 22 | public void testEq() throws Exception { 23 | State state = newState("hello"); 24 | 25 | Eq eq = new Eq<>('h'); 26 | Character c = eq.parse(state); 27 | assertEquals(new Character('h'), c); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/FindTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import org.junit.jupiter.api.BeforeAll; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.assertTrue; 8 | 9 | /** 10 | * Created by march on 16/9/9. 11 | * JUnit tests for Find parser. 12 | */ 13 | public class FindTest extends Base { 14 | private static String data; 15 | 16 | @BeforeAll 17 | public static void before() { 18 | data = "It is a junit test case for find parsec."; 19 | } 20 | 21 | @Test 22 | public void simple() throws Exception { 23 | State state = newState(data); 24 | Parsec parser = new Find<>(new Text<>("find")); 25 | String re = parser.parse(state); 26 | assertEquals("find", re); 27 | } 28 | 29 | @Test 30 | public void failed() throws Exception { 31 | State state = newState(data); 32 | Parsec parser = new Find<>(new Text<>("Fail")); 33 | try { 34 | String re = parser.parse(state); 35 | } catch (Exception e){ 36 | assertTrue(e instanceof ParsecException); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/ManyTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static jaskell.parsec.Atom.eq; 6 | import static jaskell.parsec.Combinator.many; 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Many Tester. 14 | * 15 | * @author Mars Liu 16 | */ 17 | public class ManyTest extends Base { 18 | 19 | 20 | /** 21 | * Method: script(State s) 22 | */ 23 | @Test 24 | public void simple() throws Exception { 25 | State state = newState("hhello"); 26 | 27 | Many m = many(eq('h')); 28 | 29 | List a = m.parse(state); 30 | assertEquals(a.size(), 2); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/ManyTillTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.List; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | /** 11 | * ManyTil Tester. 12 | * 13 | * @author Mars Liu 14 | * @since 2016-09-12 15 | */ 16 | public class ManyTillTest extends Base { 17 | 18 | 19 | /** 20 | * Method: script(State s) 21 | */ 22 | @Test 23 | public void TestManyTill() throws Exception { 24 | State state = newState("hhhhhhlhhhll"); 25 | 26 | ManyTill m = new ManyTill<>( 27 | new Eq<>('h'), 28 | new Eq<>('l') 29 | ); 30 | 31 | List a = m.parse(state); 32 | assertEquals(a.size(), 6); 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/NewlineTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static jaskell.parsec.Txt.ch; 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | 8 | 9 | public class NewlineTest extends Base { 10 | 11 | @Test 12 | public void simpleCrlf() throws Exception { 13 | State state = newState("\r\n"); 14 | Parsec crlf = new Crlf<>(); 15 | 16 | String re = crlf.parse(state); 17 | assertEquals("\r\n", re); 18 | } 19 | 20 | /** 21 | * Method: script(State s) 22 | */ 23 | @Test 24 | public void simpleNl() throws Exception { 25 | State state = newState("\r\n"); 26 | 27 | Parsec enter = new Newline<>(); 28 | 29 | Character c = new Ch('\r').then(enter).parse(state); 30 | 31 | assertEquals(c.charValue(), '\n'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/NoneOfTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static java.util.stream.Collectors.toSet; 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 8 | 9 | 10 | import java.util.stream.Stream; 11 | 12 | public class NoneOfTest extends Base { 13 | 14 | 15 | /** 16 | * Method: script(State s) 17 | */ 18 | @Test 19 | public void simpleOK() throws Exception { 20 | State state = newState("hello"); 21 | 22 | NoneOf noneOf = new NoneOf<>(Stream.of('k', 'o', 'f').collect(toSet())); 23 | Character c = noneOf.parse(state); 24 | 25 | assertEquals(c, new Character('h')); 26 | } 27 | 28 | @Test 29 | public void simpleFail() throws Exception { 30 | NoneOf noneOf = new NoneOf<>(Stream.of('k', 'f', 's').collect(toSet())); 31 | 32 | String content = "sound"; 33 | State state2 = newState(content); 34 | assertThrowsExactly(ParsecException.class, 35 | () -> noneOf.parse(state2), 36 | String.format("Expect none of \"%s\" in \"sound\" failed ", "kfs") 37 | ); 38 | 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/OneOfTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static java.util.stream.Collectors.toSet; 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 8 | 9 | import java.util.Set; 10 | import java.util.stream.Stream; 11 | 12 | public class OneOfTest extends Base { 13 | private final String data = "It is a \"string\" for this unit test"; 14 | 15 | 16 | /** 17 | * Method: script(State s) 18 | */ 19 | @Test 20 | public void simple() throws Exception { 21 | State state = newState("hello"); 22 | 23 | Set buffer = Stream.of('b', 'e', 'h', 'f').collect(toSet()); //IntStream.range(0, 2).mapToObj(data::charAt).collect(toList()); 24 | OneOf oneOf = new OneOf<>(buffer); 25 | 26 | Character c = oneOf.parse(state); 27 | 28 | 29 | assertEquals(new Character('h'), c); 30 | } 31 | 32 | @Test 33 | public void fail() throws Exception { 34 | State state = newState("hello"); 35 | OneOf oneOf = new OneOf<>(Stream.of('d', 'a', 't', 'e').collect(toSet())); 36 | 37 | assertThrowsExactly(ParsecException.class, 38 | () -> oneOf.parse(state), 39 | String.format("Expect none match in %s", "date")); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/OneTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.assertTrue; 8 | 9 | public class OneTest extends Base { 10 | 11 | /** 12 | * Method: script(State s) 13 | */ 14 | @Test 15 | public void testOne() throws Exception { 16 | State state = newState("hello"); 17 | 18 | One one = new One<>(); 19 | 20 | try { 21 | Character c = one.parse(state); 22 | assertEquals('h', (char) c); 23 | } catch (ParsecException e) { 24 | assertTrue(true); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/ReturnTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.math.BigDecimal; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | public class ReturnTest extends Base { 11 | /** 12 | * Method: script(State s) 13 | */ 14 | @Test 15 | public void simple() throws Exception { 16 | State state = newState("Hello World"); 17 | Return returns = new Return<>(new BigDecimal("3.1415926")); 18 | Integer idx = state.status(); 19 | BigDecimal re = returns.parse(state); 20 | assertEquals(re, new BigDecimal("3.1415926")); 21 | assertEquals(state.status(), idx); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/SepBy1Test.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static jaskell.parsec.Combinator.sepBy1; 6 | import static org.junit.jupiter.api.Assertions.*; 7 | 8 | import java.util.List; 9 | 10 | public class SepBy1Test extends Base { 11 | 12 | /** 13 | * Method: script(State s) 14 | */ 15 | @Test 16 | public void TestSepBy1() throws Exception { 17 | State state = newState("hlhlhlhlhlhll"); 18 | 19 | SepBy1 m = 20 | sepBy1(new Ch<>('h'), new Ch<>('l')); 21 | 22 | List a = m.parse(state); 23 | assertEquals(6, a.size()); 24 | 25 | State state1 = newState("hlh,h.hlhlhll"); 26 | 27 | List b = m.parse(state1); 28 | assertEquals(2, b.size()); 29 | 30 | try { 31 | List c = m.parse(state1); 32 | String message = String.format("Expect a exception but %s", c); 33 | fail(message); 34 | } catch (ParsecException e) { 35 | assertTrue(true); 36 | } 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/SepByTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.List; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | public class SepByTest extends Base { 11 | 12 | /** 13 | * Method: script(State s) 14 | */ 15 | @Test 16 | public void TestSepBy() throws Exception { 17 | State state = newState("hlhlhlhlhlhll"); 18 | 19 | SepBy m = new SepBy<>( 20 | new Eq<>('h'), 21 | new Eq<>('l') 22 | ); 23 | 24 | List a = m.parse(state); 25 | assertEquals(a.size(), 6); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/SpaceTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 8 | 9 | public class SpaceTest extends Base { 10 | 11 | 12 | /** 13 | * Method: script(State s) 14 | */ 15 | @Test 16 | public void simpleSpace() throws Exception { 17 | State state = newState(" "); 18 | Parsec s = new Space<>(); 19 | Character a = s.parse(state); 20 | assertEquals(' ', a.charValue()); 21 | } 22 | 23 | @Test 24 | public void fail() throws Exception { 25 | State state = newState("\t"); 26 | Parsec s = new Space<>(); 27 | assertThrowsExactly(ParsecException.class, 28 | () -> s.parse(state), 29 | "Space script tab char should failed."); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/TextTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.EOFException; 7 | 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | public class TextTest extends Base { 11 | 12 | 13 | /** 14 | * Method: script(State s) 15 | */ 16 | @Test 17 | public void simple() throws Exception { 18 | State state = newState("Hello World"); 19 | Text s = new Text<>("Hello World"); 20 | String a = s.parse(state); 21 | assertEquals(a,"Hello World"); 22 | } 23 | 24 | @Test 25 | public void less() throws Exception { 26 | State state = newState("Hello World"); 27 | Text s = new Text<>("Hello"); 28 | String a = s.parse(state); 29 | assertEquals(a,"Hello"); 30 | } 31 | 32 | @Test 33 | public void more() throws Exception { 34 | State state = newState("Hello"); 35 | Text s = new Text<>("Hello world"); 36 | try { 37 | s.parse(state); 38 | fail("expect script failed because test data too large."); 39 | } catch (EOFException e) { 40 | assertTrue(true); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/UIntTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.*; 7 | 8 | public class UIntTest extends Base { 9 | 10 | @Test 11 | public void simple() throws Exception { 12 | State state = newState("23413214"); 13 | 14 | UInt uint = new UInt<>(); 15 | 16 | String s = uint.parse(state); 17 | 18 | assertEquals("23413214", s); 19 | } 20 | 21 | @Test 22 | public void stop() throws Exception { 23 | State state = newState("23413a214"); 24 | 25 | UInt uint = new UInt<>(); 26 | 27 | String s = uint.parse(state); 28 | 29 | assertEquals("23413", s); 30 | } 31 | 32 | @Test 33 | public void fail() throws Exception { 34 | State state = newState("x2344"); 35 | 36 | UInt uint = new UInt<>(); 37 | 38 | assertThrowsExactly(ParsecException.class, 39 | () -> uint.parse(state), 40 | "Expect fail when no digit at start."); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/AttemptTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static jaskell.parsec.common.Atom.eq; 7 | import static org.junit.jupiter.api.Assertions.*; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | public class AttemptTest extends Base { 13 | 14 | @Test 15 | public void simple() throws Exception { 16 | List data = Arrays.asList("Hello", "World"); 17 | 18 | State state = new SimpleState<>(data); 19 | Integer idx = state.status(); 20 | Attempt attemptIt = new Attempt<>(eq("Hello")); 21 | 22 | String re = attemptIt.parse(state); 23 | 24 | assertEquals("Hello", re); 25 | assertNotEquals(idx, state.status()); 26 | } 27 | 28 | @Test 29 | public void rollback() { 30 | List data = Arrays.asList("Hello", "World"); 31 | SimpleState state = new SimpleState<>(data); 32 | Integer idx = state.status(); 33 | Attempt attemptIt = new Attempt<>(new Eq<>("hello")); 34 | 35 | assertThrowsExactly(ParsecException.class, 36 | () -> attemptIt.parse(state), 37 | "Expect a error for Hello."); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/Base.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import java.util.stream.Collectors; 4 | import java.util.stream.IntStream; 5 | 6 | /** 7 | * Created by Mars Liu on 2016-01-09. 8 | * Base 为测试类提供共用的工具函数,继承它可以减少重复的代码书写. 9 | */ 10 | public abstract class Base { 11 | State newState(String data) { 12 | return new SimpleState<>(IntStream.range(0, data.length()) 13 | .mapToObj(data::charAt) 14 | .collect(Collectors.toList())); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/BetweenTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static jaskell.parsec.common.Atom.eq; 6 | import static jaskell.parsec.common.Atom.ne; 7 | import static jaskell.parsec.common.Combinator.between; 8 | import static jaskell.parsec.common.Combinator.many; 9 | import static jaskell.parsec.common.Txt.ch; 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | /** 13 | * Between Tester. 14 | * 15 | * @author Mars Liu 16 | * 17 | * 18 | */ 19 | public class BetweenTest extends Base { 20 | 21 | /** 22 | * Method: script(State s) 23 | */ 24 | @Test 25 | public void simple() throws Exception { 26 | 27 | State state = newState("hello"); 28 | 29 | Parsec bmw = between( 30 | eq('h'), 31 | eq('l'), 32 | eq('e') 33 | ); 34 | 35 | Character c = bmw.parse(state); 36 | assertEquals('e', (char) c); 37 | } 38 | 39 | @Test 40 | public void brackets() throws Exception { 41 | 42 | State state = newState("[hello]"); 43 | 44 | 45 | Parsec parser = between( 46 | ch('['), 47 | ch(']'), 48 | many(ne(']')) 49 | ).bind(new JoinText()); 50 | 51 | String re = parser.parse(state); 52 | assertEquals("hello", re); 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/EofTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertNull; 7 | 8 | /** 9 | * Eof Tester. 10 | * 11 | * @author 12 | * @version 1.0 13 | * @since
一月 9, 2016
14 | */ 15 | public class EofTest extends Base { 16 | 17 | /** 18 | * Method: script(State s) 19 | */ 20 | @Test 21 | public void testEof() throws Exception { 22 | State state = newState("hello"); 23 | 24 | Eof eof = new Eof<>(); 25 | 26 | new Text("hello").parse(state); 27 | Object e = eof.parse(state); 28 | assertNull(e); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/EqTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | /** 8 | * Eq Tester. 9 | * 10 | * @author 11 | * @version 1.0 12 | * @since
一月 9, 2016
13 | */ 14 | public class EqTest extends Base { 15 | 16 | /** 17 | * Method: script(State s) 18 | */ 19 | @Test 20 | public void testEq() throws Exception { 21 | State state = newState("hello"); 22 | 23 | Eq eq = new Eq<>('h'); 24 | Character c = eq.parse(state); 25 | assertEquals(new Character('h'), c); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/FindTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static jaskell.parsec.common.Txt.text; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 6 | 7 | import jaskell.parsec.ParsecException; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.Test; 10 | 11 | 12 | /** 13 | * Created by march on 16/9/9. 14 | * JUnit tests for Find parser. 15 | */ 16 | public class FindTest extends Base { 17 | private static String data; 18 | 19 | @BeforeAll 20 | public static void before() { 21 | data = "It is a junit test case for find parsec."; 22 | } 23 | 24 | @Test 25 | public void simple() throws Exception { 26 | State state = newState(data); 27 | Parsec parser = new Find<>(text("find")); 28 | String re = parser.parse(state); 29 | assertEquals("find", re); 30 | } 31 | 32 | @Test 33 | public void failed() throws Exception { 34 | State state = newState(data); 35 | Parsec parser = new Find<>(new Text("Fail")); 36 | assertThrowsExactly(ParsecException.class, () -> parser.parse(state)); 37 | } 38 | } -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/IsTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.EOFException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 12 | 13 | /** 14 | * TODO 15 | * 16 | * @author mars 17 | * @version 1.0.0 18 | * @since 2020/07/23 15:02 19 | */ 20 | public class IsTest { 21 | @Test 22 | public void testPassed() throws Exception { 23 | Parsec parser = new Is<>(i -> i % 2 == 0); 24 | List buffer = new ArrayList<>(); 25 | buffer.add(2); 26 | State state = new SimpleState<>(buffer); 27 | Integer result = parser.parse(state); 28 | assertEquals(2L, result.longValue()); 29 | } 30 | 31 | @Test 32 | public void testNotPassed() throws EOFException { 33 | Parsec parser = new Is<>(i -> i % 2 == 1); 34 | List buffer = new ArrayList<>(); 35 | buffer.add(2); 36 | State state = new SimpleState<>(buffer); 37 | 38 | assertThrowsExactly(ParsecException.class, 39 | () -> parser.parse(state), 40 | "should run it for never"); 41 | 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/Many1Test.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static jaskell.parsec.common.Txt.joining; 4 | import static jaskell.parsec.common.Atom.eq; 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 7 | 8 | import jaskell.parsec.ParsecException; 9 | import org.junit.jupiter.api.Assertions; 10 | import org.junit.jupiter.api.Test; 11 | 12 | /** 13 | * Many1 Tester. 14 | * 15 | * @author Mars Liu 16 | */ 17 | public class Many1Test extends Base { 18 | 19 | 20 | @Test 21 | public void fail() throws Exception { 22 | State state = newState("ello"); 23 | 24 | Many1 m = new Many1<>( 25 | eq('h') 26 | ); 27 | 28 | assertThrowsExactly(ParsecException.class, 29 | () -> m.parse(state)); 30 | } 31 | 32 | @Test 33 | public void one() throws Exception { 34 | Parsec m = 35 | new Many1<>(new Eq<>('h')).bind(joining()); 36 | State state1 = newState("hello"); 37 | String re = m.parse(state1); 38 | assertEquals("h", re); 39 | } 40 | 41 | @Test 42 | public void all() throws Exception { 43 | Parsec parser = 44 | new Many1<>(new One()).bind(joining()); 45 | State state1 = newState("hello"); 46 | String re = parser.parse(state1); 47 | assertEquals("hello", re); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/ManyTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.List; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | 9 | /** 10 | * Many Tester. 11 | * 12 | * @author Mars Liu 13 | */ 14 | public class ManyTest extends Base { 15 | 16 | 17 | /** 18 | * Method: script(State s) 19 | */ 20 | @Test 21 | public void simple() throws Exception { 22 | State state = newState("hhello"); 23 | 24 | Many m = new Many<>(new Eq<>('h')); 25 | 26 | List a = m.parse(state); 27 | assertEquals(2, a.size()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/ManyTillTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.List; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | /** 11 | * ManyTil Tester. 12 | * 13 | * @author Mars Liu 14 | * @since 2016-09-12 15 | */ 16 | public class ManyTillTest extends Base { 17 | 18 | 19 | /** 20 | * Method: script(State s) 21 | */ 22 | @Test 23 | public void TestManyTill() throws Exception { 24 | State state = newState("hhhhhhlhhhll"); 25 | 26 | ManyTill m = new ManyTill<>( 27 | new Eq<>('h'), 28 | new Eq<>('l') 29 | ); 30 | 31 | List a = m.parse(state); 32 | assertEquals(6, a.size()); 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/NewlineTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static jaskell.parsec.common.Txt.ch; 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | 8 | 9 | public class NewlineTest extends Base { 10 | 11 | @Test 12 | public void simpleCrlf() throws Exception { 13 | State state = newState("\r\n"); 14 | Parsec crlf = new Crlf(); 15 | 16 | String re = crlf.parse(state); 17 | assertEquals("\r\n", re); 18 | } 19 | 20 | /** 21 | * Method: script(State s) 22 | */ 23 | @Test 24 | public void simpleNl() throws Exception { 25 | State state = newState("\r\n"); 26 | 27 | Parsec enter = new Newline(); 28 | 29 | Character c = ch('\r').then(enter).parse(state); 30 | 31 | assertEquals('\n', c.charValue()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/NoneOfTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static java.util.stream.Collectors.toSet; 4 | import static org.junit.jupiter.api.Assertions.*; 5 | 6 | import jaskell.parsec.ParsecException; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.util.stream.Stream; 10 | 11 | public class NoneOfTest extends Base { 12 | 13 | 14 | /** 15 | * Method: script(State s) 16 | */ 17 | @Test 18 | public void simpleOK() throws Exception { 19 | State state = newState("hello"); 20 | 21 | NoneOf noneOf = new NoneOf<>(Stream.of('k', 'o', 'f').collect(toSet())); 22 | Character c = noneOf.parse(state); 23 | 24 | assertEquals(c, new Character('h')); 25 | } 26 | 27 | @Test 28 | public void simpleFail() throws Exception { 29 | NoneOf noneOf = new NoneOf<>(Stream.of('k', 'f', 's').collect(toSet())); 30 | String content = "sound"; 31 | State state2 = newState(content); 32 | assertThrowsExactly(ParsecException.class, 33 | () -> noneOf.parse(state2), 34 | "Expect none of \"%s\" failed"); 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/OneOfTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static java.util.stream.Collectors.toSet; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 6 | 7 | import jaskell.parsec.ParsecException; 8 | import org.junit.jupiter.api.Test; 9 | 10 | 11 | import java.util.Set; 12 | import java.util.stream.Stream; 13 | 14 | public class OneOfTest extends Base { 15 | private final String data = "It is a \"string\" for this unit test"; 16 | 17 | 18 | /** 19 | * Method: script(State s) 20 | */ 21 | @Test 22 | public void simple() throws Exception { 23 | State state = newState("hello"); 24 | 25 | Set buffer = Stream.of('b', 'e', 'h', 'f').collect(toSet()); //IntStream.range(0, 2).mapToObj(data::charAt).collect(toList()); 26 | OneOf oneOf = new OneOf<>(buffer); 27 | 28 | Character c = oneOf.parse(state); 29 | 30 | 31 | assertEquals(new Character('h'), c); 32 | } 33 | 34 | @Test 35 | public void fail() throws Exception { 36 | State state = newState("hello"); 37 | OneOf oneOf = new OneOf<>(Stream.of('d', 'a', 't', 'e').collect(toSet())); 38 | assertThrowsExactly(ParsecException.class, 39 | () -> oneOf.parse(state), 40 | "Expect failed"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/OneTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class OneTest extends Base { 8 | 9 | /** 10 | * Method: script(State s) 11 | */ 12 | @Test 13 | public void testOne() throws Exception { 14 | State state = newState("hello"); 15 | 16 | One one = new One<>(); 17 | 18 | 19 | Character c = one.parse(state); 20 | assertEquals('h', (char) c); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/ReturnTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.math.BigDecimal; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | public class ReturnTest extends Base { 11 | /** 12 | * Method: script(State s) 13 | */ 14 | @Test 15 | public void simple() throws Exception { 16 | State state = newState("Hello World"); 17 | Return returns = new Return<>(new BigDecimal("3.1415926")); 18 | Integer idx = state.status(); 19 | BigDecimal re = returns.parse(state); 20 | assertEquals(new BigDecimal("3.1415926"), re); 21 | assertEquals(idx, state.status()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/SepBy1Test.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static jaskell.parsec.common.Txt.ch; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 6 | 7 | import jaskell.parsec.ParsecException; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import java.util.List; 11 | 12 | public class SepBy1Test extends Base { 13 | 14 | 15 | /** 16 | * Method: script(State s) 17 | */ 18 | @Test 19 | public void TestSepBy1() throws Exception { 20 | State state = newState("hlhlhlhlhlhll"); 21 | 22 | SepBy1 m = 23 | new SepBy1<>(ch('h'), ch('l')); 24 | 25 | List a = m.parse(state); 26 | assertEquals(6, a.size()); 27 | 28 | State state1 = newState("hlh,h.hlhlhll"); 29 | 30 | List b = m.parse(state1); 31 | assertEquals(2, b.size()); 32 | 33 | assertThrowsExactly(ParsecException.class, 34 | () -> m.parse(state1), 35 | "Expect a exception"); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/SepByTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.List; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | public class SepByTest extends Base { 11 | 12 | 13 | /** 14 | * Method: script(State s) 15 | */ 16 | @Test 17 | public void TestSepBy() throws Exception { 18 | State state = newState("hlhlhlhlhlhll"); 19 | 20 | SepBy m = new SepBy<>( 21 | new Eq<>('h'), 22 | new Eq<>('l') 23 | ); 24 | 25 | List a = m.parse(state); 26 | assertEquals(6, a.size()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/SpaceTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import jaskell.parsec.ParsecException; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 8 | 9 | public class SpaceTest extends Base { 10 | 11 | 12 | /** 13 | * Method: script(State s) 14 | */ 15 | @Test 16 | public void simpleSpace() throws Exception { 17 | State state = newState(" "); 18 | Parsec s = new Space(); 19 | Character a = s.parse(state); 20 | assertEquals(' ', a.charValue()); 21 | } 22 | 23 | @Test 24 | public void fail() throws Exception { 25 | State state = newState("\t"); 26 | Parsec s = new Space(); 27 | assertThrowsExactly(ParsecException.class, 28 | () -> s.parse(state), 29 | "Space script tab char should failed."); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/TextTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static jaskell.parsec.common.Txt.text; 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 8 | 9 | import java.io.EOFException; 10 | 11 | public class TextTest extends Base { 12 | 13 | 14 | /** 15 | * Method: script(State s) 16 | */ 17 | @Test 18 | public void simple() throws Exception { 19 | State state = newState("Hello World"); 20 | Text s = new Text("Hello World"); 21 | String a = s.parse(state); 22 | assertEquals("Hello World", a); 23 | } 24 | 25 | @Test 26 | public void less() throws Exception { 27 | State state = newState("Hello World"); 28 | Text s = text("Hello"); 29 | String a = s.parse(state); 30 | assertEquals("Hello", a); 31 | } 32 | 33 | @Test 34 | public void more() throws Exception { 35 | State state = newState("Hello"); 36 | Text s = text("Hello world"); 37 | assertThrowsExactly(EOFException.class, 38 | () -> s.parse(state), 39 | "expect script failed because test data too large."); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/jaskell/parsec/common/UIntTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.parsec.common; 2 | 3 | import static jaskell.parsec.common.Txt.uinteger; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 6 | 7 | import jaskell.parsec.ParsecException; 8 | import org.junit.jupiter.api.Test; 9 | 10 | public class UIntTest extends Base { 11 | 12 | @Test 13 | public void simple() throws Exception { 14 | State state = newState("23413214"); 15 | 16 | UInt uint = uinteger(); 17 | 18 | String s = uint.parse(state); 19 | 20 | assertEquals("23413214", s); 21 | } 22 | 23 | @Test 24 | public void stop() throws Exception { 25 | State state = newState("23413a214"); 26 | 27 | UInt uint = uinteger(); 28 | 29 | String s = uint.parse(state); 30 | 31 | assertEquals("23413", s); 32 | } 33 | 34 | @Test 35 | public void fail() throws Exception { 36 | State state = newState("x2344"); 37 | 38 | UInt uint = new UInt(); 39 | 40 | assertThrowsExactly(ParsecException.class, 41 | () -> uint.parse(state), 42 | "Expect fail when no digit at start."); 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/jaskell/sql/WithTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.sql; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static jaskell.sql.SQL.l; 7 | import static jaskell.sql.SQL.n; 8 | import static jaskell.sql.SQL.select; 9 | import static jaskell.sql.SQL.with; 10 | 11 | 12 | public class WithTest { 13 | 14 | @Test 15 | public void BasicTest0(){ 16 | final String script = 17 | "WITH t1 AS (SELECT n FROM t), t2 AS (SELECT m FROM t) SELECT m * n FROM t1 JOIN t2 ON t1.n != t2.m"; 18 | Query query = with("t1").as(select("n").from("t")) 19 | .cte("t2").as(select("m").from("t")) 20 | .select(l("m * n")).from("t1").join(n("t2")).on(n("t1.n").ne(n("t2.m"))); 21 | Assertions.assertEquals(script, query.script()); 22 | } 23 | 24 | @Test 25 | public void BasicTest1(){ 26 | final String script = 27 | "WITH RECURSIVE t(f) AS (SELECT 1 UNION SELECT f+1 FROM t WHERE f < 100) SELECT f FROM t"; 28 | Query query = with().recursive().name("t(f)") 29 | .as(select(l(1)).union().select(l("f+1")).from("t").where(n("f").lt(100))) 30 | .select("f").from("t"); 31 | Assertions.assertEquals(script, query.script()); 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/jaskell/util/DistanceTest.java: -------------------------------------------------------------------------------- 1 | package jaskell.util; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static jaskell.util.Distance.levenshtein; 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | 8 | public class DistanceTest { 9 | @Test 10 | public void testLevenshtein() { 11 | assertEquals(1, levenshtein("126.com", "127.com")); 12 | assertEquals(1, levenshtein("127.com", "126.com")); 13 | assertEquals(0, levenshtein("hotmail.com", "hotmail.com")); 14 | assertEquals(0, levenshtein("", "")); 15 | assertEquals(8, levenshtein("sina.com", "")); 16 | assertEquals(9, levenshtein("gmail.com", "")); 17 | assertEquals(2, levenshtein("sina.com", "sina.cn")); 18 | assertEquals(1, levenshtein("139.com", ".139.com")); 19 | assertEquals(3, levenshtein("qq.", "qq.com")); 20 | assertEquals(1, levenshtein("gmail.com", "gmail.com.")); 21 | assertEquals(1, levenshtein(".gmail.com", "gmail.com")); 22 | assertEquals(10, levenshtein("ttttattttctg", "tcaaccctaccat")); 23 | } 24 | } 25 | --------------------------------------------------------------------------------