From fba537ce443e02d320d4ebb0b62eaf0dd9c1eb89 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Mon, 7 Jun 2021 14:19:38 +0800 Subject: [PATCH 01/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/spirit/code/tools/core/ElementSelector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java b/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java index e22c6909..df900b83 100644 --- a/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java +++ b/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java @@ -5,17 +5,17 @@ import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.gitee.spirit.core.api.ElementVisiter; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.compile.CoreCompiler; -import com.gitee.spirit.core.compile.DefaultElementVisiter; import com.gitee.spirit.core.element.entity.Element; @Component public class ElementSelector extends CoreCompiler { @Autowired - public DefaultElementVisiter visiter; + public ElementVisiter visiter; public IType findElementAndGetType(IClass clazz, Integer lineNumber) { // TODO -- Gitee From 35ece7d92acd161455a0c55215e3dea0e37f9752 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Mon, 7 Jun 2021 15:04:24 +0800 Subject: [PATCH 02/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/{ModifierEnum.java => AccessLevelEnum.java} | 8 ++++---- .../java/com/gitee/spirit/core/clazz/entity/IType.java | 10 +++++----- .../com/gitee/spirit/core/clazz/utils/TypeBuilder.java | 6 +++--- .../com/gitee/spirit/core/compile/AppTypeFactory.java | 4 ++-- .../spirit/core/compile/action/InvokeVisitAction.java | 2 +- .../core/compile/derivator/DefaultVariableTracker.java | 8 +++++--- .../core/compile/linker/AdaptiveClassLinker.java | 10 +++++----- 7 files changed, 25 insertions(+), 23 deletions(-) rename spirit-common/src/main/java/com/gitee/spirit/common/enums/{ModifierEnum.java => AccessLevelEnum.java} (44%) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/ModifierEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/AccessLevelEnum.java similarity index 44% rename from spirit-common/src/main/java/com/gitee/spirit/common/enums/ModifierEnum.java rename to spirit-common/src/main/java/com/gitee/spirit/common/enums/AccessLevelEnum.java index 7ce3dd8c..50db1fd9 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/enums/ModifierEnum.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/AccessLevelEnum.java @@ -2,15 +2,15 @@ package com.gitee.spirit.common.enums; import java.lang.reflect.Modifier; -public enum ModifierEnum { +public enum AccessLevelEnum { - THIS(Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE), // - SUPER(Modifier.PUBLIC | Modifier.PROTECTED), // + PRIVATE(Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE), // + PROTECTED(Modifier.PUBLIC | Modifier.PROTECTED), // PUBLIC(Modifier.PUBLIC);// public int value; - private ModifierEnum(int value) { + private AccessLevelEnum(int value) { this.value = value; } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java index d626d1d5..609e76f0 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java @@ -5,7 +5,7 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; -import com.gitee.spirit.common.enums.ModifierEnum; +import com.gitee.spirit.common.enums.AccessLevelEnum; import com.gitee.spirit.common.utils.SpringUtils; import com.gitee.spirit.core.api.TypeFactory; import com.gitee.spirit.core.clazz.utils.TypeRegistry; @@ -62,13 +62,13 @@ public class IType { return factory.create(getTargetName()); } - public IType withSuperModifiers() { - this.setModifiers(ModifierEnum.SUPER.value); + public IType withProtected() { + this.setModifiers(AccessLevelEnum.PROTECTED.value); return this; } - public IType withThisModifiers() { - this.setModifiers(ModifierEnum.THIS.value); + public IType withPrivate() { + this.setModifiers(AccessLevelEnum.PRIVATE.value); return this; } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeBuilder.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeBuilder.java index 417d3b8c..324189a5 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeBuilder.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeBuilder.java @@ -3,7 +3,7 @@ package com.gitee.spirit.core.clazz.utils; import java.util.ArrayList; import java.util.Collections; -import com.gitee.spirit.common.enums.ModifierEnum; +import com.gitee.spirit.common.enums.AccessLevelEnum; import com.gitee.spirit.common.enums.PrimitiveEnum; import com.gitee.spirit.core.clazz.entity.IType; @@ -21,7 +21,7 @@ public class TypeBuilder { type.setNull(isNull); type.setWildcard(isWildcard); type.setNative(isNative); - type.setModifiers(ModifierEnum.PUBLIC.value); + type.setModifiers(AccessLevelEnum.PUBLIC.value); type.setGenericTypes(new ArrayList<>()); return type; } @@ -37,7 +37,7 @@ public class TypeBuilder { type.setNull(false); type.setWildcard(false); type.setNative(false); - type.setModifiers(ModifierEnum.PUBLIC.value); + type.setModifiers(AccessLevelEnum.PUBLIC.value); type.setGenericTypes(new ArrayList<>()); return type; } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java index abfd7d31..bf4a000d 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java @@ -8,7 +8,7 @@ import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; -import com.gitee.spirit.common.enums.ModifierEnum; +import com.gitee.spirit.common.enums.AccessLevelEnum; import com.gitee.spirit.common.enums.PrimitiveEnum; import com.gitee.spirit.core.api.TypeDerivator; import com.gitee.spirit.core.clazz.AbstractTypeFactory; @@ -44,7 +44,7 @@ public class AppTypeFactory extends AbstractTypeFactory { type.setNull(false); type.setWildcard(false); type.setNative(!classLoader.contains(TypeUtils.getTargetName(className))); - type.setModifiers(ModifierEnum.PUBLIC.value); + type.setModifiers(AccessLevelEnum.PUBLIC.value); return type; } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java index 57c59d8c..45cf7495 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java @@ -50,7 +50,7 @@ public class InvokeVisitAction extends AbstractAppElementAction { } else if (token.isLocalMethod()) { String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitMethod(clazz.getType().withThisModifiers(), memberName, parameterTypes); + IType returnType = linker.visitMethod(clazz.getType().withPrivate(), memberName, parameterTypes); token.setAttr(Attribute.TYPE, returnType); } else if (token.isVisitField()) { diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java index b8e81a7c..95145b26 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.enums.KeywordEnum; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.VariableTracker; +import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IMethod; import com.gitee.spirit.core.clazz.entity.IParameter; import com.gitee.spirit.core.clazz.entity.IType; @@ -27,10 +28,11 @@ public class DefaultVariableTracker implements VariableTracker { } public IType findTypeByKeyword(VisitContext context, String variableName) { + IClass clazz = context.clazz; if (KeywordEnum.isSuper(variableName)) { - return context.clazz.getSuperType().withSuperModifiers(); + return clazz.getSuperType().withProtected(); } else if (KeywordEnum.isThis(variableName)) { - return context.clazz.getType().withThisModifiers(); + return clazz.getType().withPrivate(); } return null; } @@ -55,7 +57,7 @@ public class DefaultVariableTracker implements VariableTracker { public IType findTypeByInherit(VisitContext context, String variableName) { try { - return linker.visitField(context.clazz.getType().withThisModifiers(), variableName);// 从本身和父类里面寻找,父类可能是native的 + return linker.visitField(context.clazz.getType().withPrivate(), variableName);// 从本身和父类里面寻找,父类可能是native的 } catch (NoSuchFieldException e) { return null; } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index 29e85c32..091ce065 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -9,7 +9,7 @@ import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import com.gitee.spirit.common.enums.KeywordEnum; -import com.gitee.spirit.common.enums.ModifierEnum; +import com.gitee.spirit.common.enums.AccessLevelEnum; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.TypeFactory; import com.gitee.spirit.core.clazz.entity.IType; @@ -66,11 +66,11 @@ public class AdaptiveClassLinker implements ClassLinker { } int modifiers = type.getModifiers(); - if (modifiers == ModifierEnum.THIS.value || modifiers == ModifierEnum.SUPER.value) { - superType.setModifiers(ModifierEnum.SUPER.value); + if (modifiers == AccessLevelEnum.PRIVATE.value || modifiers == AccessLevelEnum.PROTECTED.value) { + superType.setModifiers(AccessLevelEnum.PROTECTED.value); - } else if (modifiers == ModifierEnum.PUBLIC.value) { - superType.setModifiers(ModifierEnum.PUBLIC.value); + } else if (modifiers == AccessLevelEnum.PUBLIC.value) { + superType.setModifiers(AccessLevelEnum.PUBLIC.value); } return superType; -- Gitee From 65fe1884cf0754ccff1e02b2bc3c18d46fc6019c Mon Sep 17 00:00:00 2001 From: chenT Date: Mon, 7 Jun 2021 20:21:16 +0800 Subject: [PATCH 03/83] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E5=87=BAResult=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/common/entity/Result.java | 55 +++-- .../gitee/spirit/common/enums/StateEnum.java | 8 + .../com/gitee/spirit/core/api/CharAction.java | 24 +- .../gitee/spirit/core/api/CharsHandler.java | 20 +- .../core/lexer/AbstractCharsHandler.java | 68 +++--- .../core/lexer/AbstractCursorLexer.java | 64 +++--- .../spirit/core/lexer/AbstractLexer.java | 216 +++++++++--------- .../spirit/core/lexer/AliasCharsHandler.java | 120 +++++----- .../gitee/spirit/core/lexer/CoreLexer.java | 68 +++--- .../core/lexer/action/BorderAction.java | 109 ++++----- .../core/lexer/action/RegionAction.java | 210 ++++++++--------- .../spirit/core/lexer/action/SpaceAction.java | 56 ++--- .../core/lexer/action/SymbolAction.java | 88 +++---- .../spirit/core/lexer/entity/CommonState.java | 5 - 14 files changed, 561 insertions(+), 550 deletions(-) rename spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/entity/CommonResult.java => spirit-common/src/main/java/com/gitee/spirit/common/entity/Result.java (37%) create mode 100644 spirit-common/src/main/java/com/gitee/spirit/common/enums/StateEnum.java delete mode 100644 spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/entity/CommonState.java diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/entity/CommonResult.java b/spirit-common/src/main/java/com/gitee/spirit/common/entity/Result.java similarity index 37% rename from spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/entity/CommonResult.java rename to spirit-common/src/main/java/com/gitee/spirit/common/entity/Result.java index 6e5f7572..22d35ab3 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/entity/CommonResult.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/entity/Result.java @@ -1,24 +1,31 @@ -package com.gitee.spirit.core.lexer.entity; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CommonResult { - - public CommonState state; - public Object value; - - public CommonResult(Object value) { - this.value = value; - } - - @SuppressWarnings("unchecked") - public T get() { - return (T) value; - } - -} +package com.gitee.spirit.common.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Result { + + public Integer code; + public String message; + public Object data; + + public Result(Integer code, Object data) { + this.code = code; + this.data = data; + } + + public Result(Object value) { + this.code = 200; + this.data = value; + } + + @SuppressWarnings("unchecked") + public T get() { + return (T) data; + } + +} diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/StateEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/StateEnum.java new file mode 100644 index 00000000..7fbd28df --- /dev/null +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/StateEnum.java @@ -0,0 +1,8 @@ +package com.gitee.spirit.common.enums; + +public enum StateEnum { + CONTINUE, // + SKIP, // + RESET, // + BREAK // +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/api/CharAction.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/api/CharAction.java index 4bf23399..cf60a8bd 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/api/CharAction.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/api/CharAction.java @@ -1,12 +1,12 @@ -package com.gitee.spirit.core.api; - -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CommonResult; - -public interface CharAction { - - boolean isTrigger(CharEvent event); - - CommonResult handle(CharEvent event); - -} +package com.gitee.spirit.core.api; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.core.lexer.entity.CharEvent; + +public interface CharAction { + + boolean isTrigger(CharEvent event); + + Result handle(CharEvent event); + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/api/CharsHandler.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/api/CharsHandler.java index 61d5e3f2..4484e4b2 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/api/CharsHandler.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/api/CharsHandler.java @@ -1,10 +1,10 @@ -package com.gitee.spirit.core.api; - -import com.gitee.spirit.core.lexer.entity.CharsContext; -import com.gitee.spirit.core.lexer.entity.CommonResult; - -public interface CharsHandler { - - CommonResult handle(CharsContext context, StringBuilder builder); - -} +package com.gitee.spirit.core.api; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.core.lexer.entity.CharsContext; + +public interface CharsHandler { + + Result handle(CharsContext context, StringBuilder builder); + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCharsHandler.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCharsHandler.java index 7b80d6a4..0fb24dd4 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCharsHandler.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCharsHandler.java @@ -1,34 +1,34 @@ -package com.gitee.spirit.core.lexer; - -import com.gitee.spirit.core.api.CharAction; -import com.gitee.spirit.core.api.CharsHandler; -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CharsContext; -import com.gitee.spirit.core.lexer.entity.CommonResult; -import com.gitee.spirit.core.lexer.entity.CommonState; - -public abstract class AbstractCharsHandler implements CharsHandler, CharAction { - - @Override - public CommonResult handle(CharsContext context, StringBuilder builder) { - for (context.index = 0; context.index < builder.length(); context.index++) { - CharEvent event = new CharEvent(context, builder.charAt(context.index)); - if (this.isTrigger(event)) { - CommonResult result = this.handle(event); - if (result != null) { - if (result.state == CommonState.RESET) { - context.index = 0; - } else if (result.state == CommonState.BREAK) { - break; - } - } - } - } - return buildResult(context, builder); - } - - public CommonResult buildResult(CharsContext context, StringBuilder builder) { - return new CommonResult(builder); - } - -} +package com.gitee.spirit.core.lexer; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.common.enums.StateEnum; +import com.gitee.spirit.core.api.CharAction; +import com.gitee.spirit.core.api.CharsHandler; +import com.gitee.spirit.core.lexer.entity.CharEvent; +import com.gitee.spirit.core.lexer.entity.CharsContext; + +public abstract class AbstractCharsHandler implements CharsHandler, CharAction { + + @Override + public Result handle(CharsContext context, StringBuilder builder) { + for (context.index = 0; context.index < builder.length(); context.index++) { + CharEvent event = new CharEvent(context, builder.charAt(context.index)); + if (this.isTrigger(event)) { + Result result = this.handle(event); + if (result != null) { + if (result.code == StateEnum.RESET.ordinal()) { + context.index = 0; + } else if (result.code == StateEnum.BREAK.ordinal()) { + break; + } + } + } + } + return buildResult(context, builder); + } + + public Result buildResult(CharsContext context, StringBuilder builder) { + return new Result(builder); + } + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java index 84deb6f4..ff2e6b52 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java @@ -1,32 +1,32 @@ -package com.gitee.spirit.core.lexer; - -import com.gitee.spirit.common.utils.LineUtils; -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CommonResult; -import com.gitee.spirit.core.lexer.entity.LexerContext; - -public abstract class AbstractCursorLexer extends AbstractLexer { - - @Override - public CommonResult handle(CharEvent event) { - LexerContext context = (LexerContext) event.context; - char ch = event.ch; - if ((context.startIndex < 0 && isContinuous(ch)) || isRefreshed(ch)) { - context.startIndex = context.index; - } - CommonResult result = super.handle(event); - if (!isContinuous(ch)) { - context.startIndex = -1; - } - return result; - } - - public boolean isContinuous(char ch) { - return LineUtils.isLetter(ch) || ch == '@' || ch == '.'; - } - - public boolean isRefreshed(char ch) { - return ch == '.'; - } - -} +package com.gitee.spirit.core.lexer; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.common.utils.LineUtils; +import com.gitee.spirit.core.lexer.entity.CharEvent; +import com.gitee.spirit.core.lexer.entity.LexerContext; + +public abstract class AbstractCursorLexer extends AbstractLexer { + + @Override + public Result handle(CharEvent event) { + LexerContext context = (LexerContext) event.context; + char ch = event.ch; + if ((context.startIndex < 0 && isContinuous(ch)) || isRefreshed(ch)) { + context.startIndex = context.index; + } + Result result = super.handle(event); + if (!isContinuous(ch)) { + context.startIndex = -1; + } + return result; + } + + public boolean isContinuous(char ch) { + return LineUtils.isLetter(ch) || ch == '@' || ch == '.'; + } + + public boolean isRefreshed(char ch) { + return ch == '.'; + } + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractLexer.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractLexer.java index 0c7f1f7f..47779d14 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractLexer.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractLexer.java @@ -1,108 +1,108 @@ -package com.gitee.spirit.core.lexer; - -import java.util.Arrays; -import java.util.List; - -import org.springframework.beans.factory.annotation.Autowired; - -import com.gitee.spirit.common.pattern.AccessPattern; -import com.gitee.spirit.common.pattern.LiteralPattern; -import com.gitee.spirit.core.api.Lexer; -import com.gitee.spirit.core.api.LexerAction; -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CharsContext; -import com.gitee.spirit.core.lexer.entity.CommonResult; -import com.gitee.spirit.core.lexer.entity.CommonState; -import com.gitee.spirit.core.lexer.entity.LexerContext; -import com.gitee.spirit.core.lexer.entity.Region; -import com.gitee.spirit.core.lexer.utils.RegionUtils; -import com.gitee.spirit.core.lexer.utils.RegionUtils.completedRegion; - -public abstract class AbstractLexer extends AbstractCharsHandler implements Lexer { - - @Autowired - public List actions; - - @Override - public boolean isTrigger(CharEvent event) { - LexerContext context = (LexerContext) event.context; - List regions = context.regions; - if (regions != null && !regions.isEmpty()) { - for (int index = regions.size() - 1; index >= 0; index--) { - Region existRegion = regions.get(index); - if (existRegion.contains(context.index)) { - return false; - } else if (context.index >= existRegion.endIndex) { - return true; - } - } - } - return true; - } - - @Override - public CommonResult handle(CharEvent event) { - LexerContext context = (LexerContext) event.context; - for (LexerAction action : actions) { - if (action.isTrigger(event)) { - CommonResult result = action.handle(event); - if (result != null) { - if (result.value != null) { - if (result.value instanceof Region) { - appendRegion(context, result.get()); - - } else if (result.value instanceof List) { - List regions = result.get(); - regions.forEach(region -> appendRegion(context, region)); - } - } - if (result.state == CommonState.SKIP) { - break; - } else if (result.state == CommonState.RESET || result.state == CommonState.BREAK) { - return result; - } - } - } - } - return null; - } - - public void appendRegion(LexerContext context, Region region) { - List regions = context.regions; - if (regions.isEmpty()) { - regions.add(region); - } else { - for (int index = regions.size() - 1; index >= 0; index--) { - Region existRegion = regions.get(index); - if (region.isOverlap(existRegion)) { - throw new RuntimeException("There are overlapping regions!"); - } - if (region.isAfter(existRegion)) { - regions.add(index + 1, region); - break; - } - } - } - } - - @Override - public CommonResult buildResult(CharsContext context, StringBuilder builder) { - LexerContext lexerContext = (LexerContext) context; - // 使用标记收集算法后,补全未标记的部分 - List regions = RegionUtils.completeRegions(builder, lexerContext.regions); - List words = RegionUtils.subRegions(builder, regions, this::addToWords); - return new CommonResult(words); - } - - public void addToWords(List words, Region region, String text) { - if (region instanceof completedRegion) { - if (text.indexOf(".") > 0 && !LiteralPattern.isDouble(text) && !AccessPattern.isAccessPath(text)) { - List subWords = Arrays.asList(text.replaceAll("\\.", " .").split(" ")); - words.addAll(subWords); - return; - } - } - words.add(text); - } - -} +package com.gitee.spirit.core.lexer; + +import java.util.Arrays; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.common.enums.StateEnum; +import com.gitee.spirit.common.pattern.AccessPattern; +import com.gitee.spirit.common.pattern.LiteralPattern; +import com.gitee.spirit.core.api.Lexer; +import com.gitee.spirit.core.api.LexerAction; +import com.gitee.spirit.core.lexer.entity.CharEvent; +import com.gitee.spirit.core.lexer.entity.CharsContext; +import com.gitee.spirit.core.lexer.entity.LexerContext; +import com.gitee.spirit.core.lexer.entity.Region; +import com.gitee.spirit.core.lexer.utils.RegionUtils; +import com.gitee.spirit.core.lexer.utils.RegionUtils.completedRegion; + +public abstract class AbstractLexer extends AbstractCharsHandler implements Lexer { + + @Autowired + public List actions; + + @Override + public boolean isTrigger(CharEvent event) { + LexerContext context = (LexerContext) event.context; + List regions = context.regions; + if (regions != null && !regions.isEmpty()) { + for (int index = regions.size() - 1; index >= 0; index--) { + Region existRegion = regions.get(index); + if (existRegion.contains(context.index)) { + return false; + } else if (context.index >= existRegion.endIndex) { + return true; + } + } + } + return true; + } + + @Override + public Result handle(CharEvent event) { + LexerContext context = (LexerContext) event.context; + for (LexerAction action : actions) { + if (action.isTrigger(event)) { + Result result = action.handle(event); + if (result != null) { + if (result.data != null) { + if (result.data instanceof Region) { + appendRegion(context, result.get()); + + } else if (result.data instanceof List) { + List regions = result.get(); + regions.forEach(region -> appendRegion(context, region)); + } + } + if (result.code == StateEnum.SKIP.ordinal()) { + break; + } else if (result.code == StateEnum.RESET.ordinal() || result.code == StateEnum.BREAK.ordinal()) { + return result; + } + } + } + } + return null; + } + + public void appendRegion(LexerContext context, Region region) { + List regions = context.regions; + if (regions.isEmpty()) { + regions.add(region); + } else { + for (int index = regions.size() - 1; index >= 0; index--) { + Region existRegion = regions.get(index); + if (region.isOverlap(existRegion)) { + throw new RuntimeException("There are overlapping regions!"); + } + if (region.isAfter(existRegion)) { + regions.add(index + 1, region); + break; + } + } + } + } + + @Override + public Result buildResult(CharsContext context, StringBuilder builder) { + LexerContext lexerContext = (LexerContext) context; + // 使用标记收集算法后,补全未标记的部分 + List regions = RegionUtils.completeRegions(builder, lexerContext.regions); + List words = RegionUtils.subRegions(builder, regions, this::addToWords); + return new Result(words); + } + + public void addToWords(List words, Region region, String text) { + if (region instanceof completedRegion) { + if (text.indexOf(".") > 0 && !LiteralPattern.isDouble(text) && !AccessPattern.isAccessPath(text)) { + List subWords = Arrays.asList(text.replaceAll("\\.", " .").split(" ")); + words.addAll(subWords); + return; + } + } + words.add(text); + } + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AliasCharsHandler.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AliasCharsHandler.java index 705c55cb..8651203b 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AliasCharsHandler.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AliasCharsHandler.java @@ -1,60 +1,60 @@ -package com.gitee.spirit.core.lexer; - -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.utils.LineUtils; -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CharsContext; -import com.gitee.spirit.core.lexer.entity.CommonResult; - -@Component -public class AliasCharsHandler extends AbstractCharsHandler { - - public String replace(String code, String alias, String className) { - AliasCharsContext context = new AliasCharsContext(); - StringBuilder builder = new StringBuilder(code); - context.builder = builder; - context.alias = alias; - context.className = className; - CommonResult result = handle(context, builder); - builder = (StringBuilder) result.value; - return builder.toString(); - } - - @Override - public boolean isTrigger(CharEvent event) { - AliasCharsContext context = (AliasCharsContext) event.context; - StringBuilder builder = context.builder; - String alias = context.alias; - char ch = event.ch; - if (ch == '"') { - context.index = LineUtils.findEndIndex(builder, context.index, '"', '"'); - } else if (ch == alias.charAt(0) && !LineUtils.isLetter(builder.charAt(context.index - 1))) { - return true; - } - return false; - } - - @Override - public CommonResult handle(CharEvent event) { - AliasCharsContext context = (AliasCharsContext) event.context; - StringBuilder builder = context.builder; - String alias = context.alias; - String className = context.className; - int endIndex = context.index + alias.length(); - if (endIndex <= builder.length()) { - String text = builder.substring(context.index, endIndex); - if (alias.equals(text)) { - if (endIndex == builder.length() || !LineUtils.isLetter(builder.charAt(endIndex))) { - builder.replace(context.index, endIndex, className); - } - } - } - return null; - } - - public static class AliasCharsContext extends CharsContext { - public String alias; - public String className; - } -} +package com.gitee.spirit.core.lexer; + +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.common.utils.LineUtils; +import com.gitee.spirit.core.lexer.entity.CharEvent; +import com.gitee.spirit.core.lexer.entity.CharsContext; + +@Component +public class AliasCharsHandler extends AbstractCharsHandler { + + public String replace(String code, String alias, String className) { + AliasCharsContext context = new AliasCharsContext(); + StringBuilder builder = new StringBuilder(code); + context.builder = builder; + context.alias = alias; + context.className = className; + Result result = handle(context, builder); + builder = (StringBuilder) result.data; + return builder.toString(); + } + + @Override + public boolean isTrigger(CharEvent event) { + AliasCharsContext context = (AliasCharsContext) event.context; + StringBuilder builder = context.builder; + String alias = context.alias; + char ch = event.ch; + if (ch == '"') { + context.index = LineUtils.findEndIndex(builder, context.index, '"', '"'); + } else if (ch == alias.charAt(0) && !LineUtils.isLetter(builder.charAt(context.index - 1))) { + return true; + } + return false; + } + + @Override + public Result handle(CharEvent event) { + AliasCharsContext context = (AliasCharsContext) event.context; + StringBuilder builder = context.builder; + String alias = context.alias; + String className = context.className; + int endIndex = context.index + alias.length(); + if (endIndex <= builder.length()) { + String text = builder.substring(context.index, endIndex); + if (alias.equals(text)) { + if (endIndex == builder.length() || !LineUtils.isLetter(builder.charAt(endIndex))) { + builder.replace(context.index, endIndex, className); + } + } + } + return null; + } + + public static class AliasCharsContext extends CharsContext { + public String alias; + public String className; + } +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/CoreLexer.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/CoreLexer.java index 856e79e7..c1308ec2 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/CoreLexer.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/CoreLexer.java @@ -1,34 +1,34 @@ -package com.gitee.spirit.core.lexer; - -import java.util.List; - -import org.springframework.stereotype.Component; - -import com.gitee.spirit.core.lexer.action.BorderAction; -import com.gitee.spirit.core.lexer.entity.CommonResult; -import com.gitee.spirit.core.lexer.entity.LexerContext; - -import cn.hutool.core.lang.Assert; - -@Component -public class CoreLexer extends AbstractCursorLexer { - - @Override - public List getWords(String text) { - Assert.notBlank(text, "Text cannot be blank!"); - StringBuilder builder = new StringBuilder(text.trim()); - LexerContext context = new LexerContext(builder); - CommonResult result = handle(context, builder); - return result.get(); - } - - @Override - public List getSubWords(String text, Character... splitChars) { - Assert.notBlank(text, "Text cannot be blank!"); - StringBuilder builder = new StringBuilder(text.trim()); - LexerContext context = new LexerContext(builder, BorderAction.BORDER_PROFILE, splitChars); - CommonResult result = handle(context, builder); - return result.get(); - } - -} +package com.gitee.spirit.core.lexer; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.core.lexer.action.BorderAction; +import com.gitee.spirit.core.lexer.entity.LexerContext; + +import cn.hutool.core.lang.Assert; + +@Component +public class CoreLexer extends AbstractCursorLexer { + + @Override + public List getWords(String text) { + Assert.notBlank(text, "Text cannot be blank!"); + StringBuilder builder = new StringBuilder(text.trim()); + LexerContext context = new LexerContext(builder); + Result result = handle(context, builder); + return result.get(); + } + + @Override + public List getSubWords(String text, Character... splitChars) { + Assert.notBlank(text, "Text cannot be blank!"); + StringBuilder builder = new StringBuilder(text.trim()); + LexerContext context = new LexerContext(builder, BorderAction.BORDER_PROFILE, splitChars); + Result result = handle(context, builder); + return result.get(); + } + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/BorderAction.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/BorderAction.java index fc428be5..9254bd1c 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/BorderAction.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/BorderAction.java @@ -1,54 +1,55 @@ -package com.gitee.spirit.core.lexer.action; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CommonResult; -import com.gitee.spirit.core.lexer.entity.CommonState; -import com.gitee.spirit.core.lexer.entity.LexerContext; -import com.gitee.spirit.core.lexer.entity.Region; - -@Component -@Order(-100) -public class BorderAction extends RegionAction { - - public static final String BORDER_PROFILE = "BORDER_PROFILE"; - - @Override - public boolean isTrigger(CharEvent event) { - LexerContext context = (LexerContext) event.context; - return BORDER_PROFILE.equals(context.profile) && super.isTrigger(event); - } - - @Override - public CommonResult pushStack(CharEvent event, List regions) { - LexerContext context = (LexerContext) event.context; - StringBuilder builder = context.builder; - List splitChars = context.splitChars; - - List borderRegions = new ArrayList<>(); - for (Region region : regions) { - char startChar = builder.charAt(region.startIndex); - char endChar = builder.charAt(region.endIndex - 1); - if (splitChars.contains(startChar) && splitChars.contains(endChar)) { - borderRegions.add(new Region(region.startIndex, region.startIndex + 1)); - borderRegions.add(new Region(region.endIndex - 1, region.endIndex)); - } - } - - context.profile = null; - if (!borderRegions.isEmpty()) { - int borderIndex = borderRegions.get(0).startIndex; - context.index = borderIndex; - if (borderIndex > 0) { - borderRegions.add(0, new Region(0, borderIndex)); - } - } - return new CommonResult(CommonState.SKIP, borderRegions); - } - -} +package com.gitee.spirit.core.lexer.action; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.common.enums.StateEnum; +import com.gitee.spirit.core.lexer.entity.CharEvent; +import com.gitee.spirit.core.lexer.entity.LexerContext; +import com.gitee.spirit.core.lexer.entity.Region; + +@Component +@Order(-100) +public class BorderAction extends RegionAction { + + public static final String BORDER_PROFILE = "BORDER_PROFILE"; + + @Override + public boolean isTrigger(CharEvent event) { + LexerContext context = (LexerContext) event.context; + return BORDER_PROFILE.equals(context.profile) && super.isTrigger(event); + } + + @Override + public Result pushStack(CharEvent event, List regions) { + LexerContext context = (LexerContext) event.context; + StringBuilder builder = context.builder; + List splitChars = context.splitChars; + + List borderRegions = new ArrayList<>(); + for (Region region : regions) { + char startChar = builder.charAt(region.startIndex); + char endChar = builder.charAt(region.endIndex - 1); + if (splitChars.contains(startChar) && splitChars.contains(endChar)) { + borderRegions.add(new Region(region.startIndex, region.startIndex + 1)); + borderRegions.add(new Region(region.endIndex - 1, region.endIndex)); + } + } + + context.profile = null; + if (!borderRegions.isEmpty()) { + int borderIndex = borderRegions.get(0).startIndex; + context.index = borderIndex; + if (borderIndex > 0) { + borderRegions.add(0, new Region(0, borderIndex)); + } + } + + return new Result(StateEnum.SKIP.ordinal(), borderRegions); + } + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java index b7d15fd5..b30beecb 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java @@ -1,105 +1,105 @@ -package com.gitee.spirit.core.lexer.action; - -import java.util.List; - -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.pattern.TypePattern; -import com.gitee.spirit.common.utils.ListUtils; -import com.gitee.spirit.core.api.LexerAction; -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CommonResult; -import com.gitee.spirit.core.lexer.entity.CommonState; -import com.gitee.spirit.core.lexer.entity.LexerContext; -import com.gitee.spirit.core.lexer.entity.Region; -import com.gitee.spirit.core.lexer.utils.RegionUtils; - -@Component -@Order(-80) -public class RegionAction implements LexerAction { - - @Override - public boolean isTrigger(CharEvent event) { - LexerContext context = (LexerContext) event.context; - StringBuilder builder = context.builder; - char ch = event.ch; - - if (context.index == builder.length() - 1) { - return false; - - } else if (ch == '"' || ch == '\'' || ch == '{' || ch == '(' || ch == '[') { - return true; - - } else if (ch == '<') { - if (context.startIndex >= 0) { - char d = builder.charAt(context.startIndex); - if (d >= 'A' && d <= 'Z') { - return true; - } - } - } - - return false; - } - - @Override - public CommonResult handle(CharEvent event) { - LexerContext context = (LexerContext) event.context; - StringBuilder builder = context.builder; - char ch = event.ch; - - if (ch == '"') { - Region region = RegionUtils.findRegion(builder, context.index, '"', '"'); - return pushStack(event, ListUtils.toListNonNull(region)); - - } else if (ch == '\'') { - Region region = RegionUtils.findRegion(builder, context.index, '\'', '\''); - return pushStack(event, ListUtils.toListNonNull(region)); - - } else if (ch == '{') { - Region region = RegionUtils.findRegion(builder, context.index, '{', '}'); - return pushStack(event, ListUtils.toListNonNull(region)); - - } else if (ch == '(') { - Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; - Region region1 = RegionUtils.findRegion(builder, context.index, '(', ')'); - return pushStack(event, ListUtils.toListNonNull(region0, region1)); - - } else if (ch == '[') { - Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; - if (region0 != null && !TypePattern.isTypePrefix(RegionUtils.subRegion(builder, region0))) { - region0 = null; - } - Region region1 = RegionUtils.findRegion(builder, context.index, '[', ']'); - Region region2 = null; - if (region0 != null) { - if (isCharAt(builder, region1.endIndex, '{')) { - region2 = RegionUtils.findRegion(builder, region1.endIndex, '{', '}'); - - } else if (isCharAt(builder, region1.endIndex, ' ') && isCharAt(builder, region1.endIndex + 1, '{')) { - region2 = RegionUtils.findRegion(builder, region1.endIndex + 1, '{', '}'); - } - } - return pushStack(event, ListUtils.toListNonNull(region0, region1, region2)); - - } else if (ch == '<') { - Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; - Region region1 = RegionUtils.findRegion(builder, context.index, '<', '>'); - Region region2 = isCharAt(builder, region1.endIndex, '(') ? RegionUtils.findRegion(builder, region1.endIndex, '(', ')') : null; - return pushStack(event, ListUtils.toListNonNull(region0, region1, region2)); - } - - throw new RuntimeException("Unhandled branch!"); - } - - public CommonResult pushStack(CharEvent event, List regions) { - Region mergedRegion = RegionUtils.mergeRegions(regions); - return new CommonResult(CommonState.SKIP, mergedRegion); - } - - public boolean isCharAt(StringBuilder builder, int index, char ch) { - return index < builder.length() && builder.charAt(index) == ch; - } - -} +package com.gitee.spirit.core.lexer.action; + +import java.util.List; + +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.common.enums.StateEnum; +import com.gitee.spirit.common.pattern.TypePattern; +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.api.LexerAction; +import com.gitee.spirit.core.lexer.entity.CharEvent; +import com.gitee.spirit.core.lexer.entity.LexerContext; +import com.gitee.spirit.core.lexer.entity.Region; +import com.gitee.spirit.core.lexer.utils.RegionUtils; + +@Component +@Order(-80) +public class RegionAction implements LexerAction { + + @Override + public boolean isTrigger(CharEvent event) { + LexerContext context = (LexerContext) event.context; + StringBuilder builder = context.builder; + char ch = event.ch; + + if (context.index == builder.length() - 1) { + return false; + + } else if (ch == '"' || ch == '\'' || ch == '{' || ch == '(' || ch == '[') { + return true; + + } else if (ch == '<') { + if (context.startIndex >= 0) { + char d = builder.charAt(context.startIndex); + if (d >= 'A' && d <= 'Z') { + return true; + } + } + } + + return false; + } + + @Override + public Result handle(CharEvent event) { + LexerContext context = (LexerContext) event.context; + StringBuilder builder = context.builder; + char ch = event.ch; + + if (ch == '"') { + Region region = RegionUtils.findRegion(builder, context.index, '"', '"'); + return pushStack(event, ListUtils.toListNonNull(region)); + + } else if (ch == '\'') { + Region region = RegionUtils.findRegion(builder, context.index, '\'', '\''); + return pushStack(event, ListUtils.toListNonNull(region)); + + } else if (ch == '{') { + Region region = RegionUtils.findRegion(builder, context.index, '{', '}'); + return pushStack(event, ListUtils.toListNonNull(region)); + + } else if (ch == '(') { + Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; + Region region1 = RegionUtils.findRegion(builder, context.index, '(', ')'); + return pushStack(event, ListUtils.toListNonNull(region0, region1)); + + } else if (ch == '[') { + Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; + if (region0 != null && !TypePattern.isTypePrefix(RegionUtils.subRegion(builder, region0))) { + region0 = null; + } + Region region1 = RegionUtils.findRegion(builder, context.index, '[', ']'); + Region region2 = null; + if (region0 != null) { + if (isCharAt(builder, region1.endIndex, '{')) { + region2 = RegionUtils.findRegion(builder, region1.endIndex, '{', '}'); + + } else if (isCharAt(builder, region1.endIndex, ' ') && isCharAt(builder, region1.endIndex + 1, '{')) { + region2 = RegionUtils.findRegion(builder, region1.endIndex + 1, '{', '}'); + } + } + return pushStack(event, ListUtils.toListNonNull(region0, region1, region2)); + + } else if (ch == '<') { + Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; + Region region1 = RegionUtils.findRegion(builder, context.index, '<', '>'); + Region region2 = isCharAt(builder, region1.endIndex, '(') ? RegionUtils.findRegion(builder, region1.endIndex, '(', ')') : null; + return pushStack(event, ListUtils.toListNonNull(region0, region1, region2)); + } + + throw new RuntimeException("Unhandled branch!"); + } + + public Result pushStack(CharEvent event, List regions) { + Region mergedRegion = RegionUtils.mergeRegions(regions); + return new Result(StateEnum.SKIP.ordinal(), mergedRegion); + } + + public boolean isCharAt(StringBuilder builder, int index, char ch) { + return index < builder.length() && builder.charAt(index) == ch; + } + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/SpaceAction.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/SpaceAction.java index 4ec74c14..08ea0a4c 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/SpaceAction.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/SpaceAction.java @@ -1,28 +1,28 @@ -package com.gitee.spirit.core.lexer.action; - -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.core.api.LexerAction; -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CommonResult; -import com.gitee.spirit.core.lexer.entity.CommonState; -import com.gitee.spirit.core.lexer.entity.LexerContext; -import com.gitee.spirit.core.lexer.entity.Region; - -@Component -@Order(-40) -public class SpaceAction implements LexerAction { - - @Override - public boolean isTrigger(CharEvent event) { - return event.ch == ' '; - } - - @Override - public CommonResult handle(CharEvent event) { - LexerContext context = (LexerContext) event.context; - return new CommonResult(CommonState.SKIP, new Region(context.index, context.index + 1)); - } - -} +package com.gitee.spirit.core.lexer.action; + +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.common.enums.StateEnum; +import com.gitee.spirit.core.api.LexerAction; +import com.gitee.spirit.core.lexer.entity.CharEvent; +import com.gitee.spirit.core.lexer.entity.LexerContext; +import com.gitee.spirit.core.lexer.entity.Region; + +@Component +@Order(-40) +public class SpaceAction implements LexerAction { + + @Override + public boolean isTrigger(CharEvent event) { + return event.ch == ' '; + } + + @Override + public Result handle(CharEvent event) { + LexerContext context = (LexerContext) event.context; + return new Result(StateEnum.SKIP.ordinal(), new Region(context.index, context.index + 1)); + } + +} diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/SymbolAction.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/SymbolAction.java index 943352f1..3a82e857 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/SymbolAction.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/SymbolAction.java @@ -1,45 +1,45 @@ -package com.gitee.spirit.core.lexer.action; - -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.enums.SymbolEnum; -import com.gitee.spirit.core.api.LexerAction; -import com.gitee.spirit.core.lexer.entity.CharEvent; -import com.gitee.spirit.core.lexer.entity.CommonResult; -import com.gitee.spirit.core.lexer.entity.CommonState; -import com.gitee.spirit.core.lexer.entity.LexerContext; -import com.gitee.spirit.core.lexer.entity.Region; - -@Component -@Order(-60) -public class SymbolAction implements LexerAction { - - @Override - public boolean isTrigger(CharEvent event) { - return SymbolEnum.isSymbolChar(event.ch); - } - - @Override - public CommonResult handle(CharEvent event) { - LexerContext context = (LexerContext) event.context; - StringBuilder builder = context.builder; - - if (context.index + 1 < builder.length()) { - String str = builder.substring(context.index, context.index + 2); - if (SymbolEnum.isDoubleSymbol(str)) { - Region region = new Region(context.index, context.index + 2); - return new CommonResult(CommonState.SKIP, region); - } - } - - String str = builder.substring(context.index, context.index + 1); - if (SymbolEnum.isSingleSymbol(str)) { - Region region = new Region(context.index, context.index + 1); - return new CommonResult(CommonState.SKIP, region); - } - - throw new RuntimeException("Unhandled branch!"); - } - +package com.gitee.spirit.core.lexer.action; + +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.entity.Result; +import com.gitee.spirit.common.enums.StateEnum; +import com.gitee.spirit.common.enums.SymbolEnum; +import com.gitee.spirit.core.api.LexerAction; +import com.gitee.spirit.core.lexer.entity.CharEvent; +import com.gitee.spirit.core.lexer.entity.LexerContext; +import com.gitee.spirit.core.lexer.entity.Region; + +@Component +@Order(-60) +public class SymbolAction implements LexerAction { + + @Override + public boolean isTrigger(CharEvent event) { + return SymbolEnum.isSymbolChar(event.ch); + } + + @Override + public Result handle(CharEvent event) { + LexerContext context = (LexerContext) event.context; + StringBuilder builder = context.builder; + + if (context.index + 1 < builder.length()) { + String str = builder.substring(context.index, context.index + 2); + if (SymbolEnum.isDoubleSymbol(str)) { + Region region = new Region(context.index, context.index + 2); + return new Result(StateEnum.SKIP.ordinal(), region); + } + } + + String str = builder.substring(context.index, context.index + 1); + if (SymbolEnum.isSingleSymbol(str)) { + Region region = new Region(context.index, context.index + 1); + return new Result(StateEnum.SKIP.ordinal(), region); + } + + throw new RuntimeException("Unhandled branch!"); + } + } \ No newline at end of file diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/entity/CommonState.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/entity/CommonState.java deleted file mode 100644 index 60d2103d..00000000 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/entity/CommonState.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gitee.spirit.core.lexer.entity; - -public enum CommonState { - CONTINUE, SKIP, RESET, BREAK -} -- Gitee From e2534121a3cf6fed737b824aab5a7a78b6cb195a Mon Sep 17 00:00:00 2001 From: chenT Date: Mon, 7 Jun 2021 20:32:46 +0800 Subject: [PATCH 04/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/constants/AppConfig.java | 21 -- .../spirit/common/constants/Argument.java | 13 + .../spirit/common/constants/DefaultValue.java | 9 + .../spirit/common/utils/ConfigUtils.java | 144 +++++----- .../core/element/DefaultDocumentReader.java | 216 +++++++-------- .../code/tools/service/MethodService.java | 250 +++++++++--------- 6 files changed, 327 insertions(+), 326 deletions(-) delete mode 100644 spirit-common/src/main/java/com/gitee/spirit/common/constants/AppConfig.java create mode 100644 spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java create mode 100644 spirit-common/src/main/java/com/gitee/spirit/common/constants/DefaultValue.java diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/AppConfig.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/AppConfig.java deleted file mode 100644 index 1d0e8408..00000000 --- a/spirit-common/src/main/java/com/gitee/spirit/common/constants/AppConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gitee.spirit.common.constants; - -public interface AppConfig { - - public static interface Argument { - String INPUT = "input"; - String OUTPUT = "output"; - String CLASSPATHS = "classpaths"; - String LANG_PACKAGE = "langPackage"; - String UTIL_PACKAGE = "utilPackage"; - String FILE_EXTENSION = "fileExtension"; - String DEBUG = "debug"; - } - - public static interface DefaultValue { - String CHARSET = "UTF-8"; - String FILE_EXTENSION = "sp"; - boolean DEBUG = true; - } - -} diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java new file mode 100644 index 00000000..ee8a3ce5 --- /dev/null +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java @@ -0,0 +1,13 @@ +package com.gitee.spirit.common.constants; + +public interface Argument { + + String INPUT = "input"; + String OUTPUT = "output"; + String CLASSPATHS = "classpaths"; + String LANG_PACKAGE = "langPackage"; + String UTIL_PACKAGE = "utilPackage"; + String FILE_EXTENSION = "fileExtension"; + String DEBUG = "debug"; + +} \ No newline at end of file diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/DefaultValue.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/DefaultValue.java new file mode 100644 index 00000000..44774d15 --- /dev/null +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/DefaultValue.java @@ -0,0 +1,9 @@ +package com.gitee.spirit.common.constants; + +public interface DefaultValue { + + String CHARSET = "UTF-8"; + String FILE_EXTENSION = "sp"; + boolean DEBUG = true; + +} \ No newline at end of file diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ConfigUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ConfigUtils.java index 5d2c19ce..3e08b88d 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ConfigUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ConfigUtils.java @@ -1,72 +1,72 @@ -package com.gitee.spirit.common.utils; - -import org.springframework.context.EnvironmentAware; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.constants.AppConfig.Argument; -import com.gitee.spirit.common.constants.AppConfig.DefaultValue; - -@Component -public class ConfigUtils implements EnvironmentAware { - - public static Environment environment; - - @Override - public void setEnvironment(Environment environment) { - ConfigUtils.environment = environment; - } - - public static boolean contains(String key) { - return environment.containsProperty(key); - } - - public static String getProperty(String key) { - return environment.getProperty(key); - } - - public static String getProperty(String key, String defaultValue) { - return environment.getProperty(key, defaultValue); - } - - public static Boolean getProperty(String key, Boolean defaultValue) { - return environment.containsProperty(key) ? environment.getProperty(key, Boolean.class) : defaultValue; - } - - public static Integer getProperty(String key, Integer defaultValue) { - return environment.containsProperty(key) ? environment.getProperty(key, Integer.class) : defaultValue; - } - - public static Long getProperty(String key, Long defaultValue) { - return environment.containsProperty(key) ? environment.getProperty(key, Long.class) : defaultValue; - } - - public static String getInputPath() { - return ConfigUtils.getProperty(Argument.INPUT); - } - - public static String getOutputPath() { - return ConfigUtils.getProperty(Argument.OUTPUT); - } - - public static String getClasspaths() { - return ConfigUtils.getProperty(Argument.CLASSPATHS); - } - - public static String getLangPackage() { - return ConfigUtils.getProperty(Argument.LANG_PACKAGE); - } - - public static String getUtilPackage() { - return ConfigUtils.getProperty(Argument.UTIL_PACKAGE); - } - - public static String getFileExtension() { - return ConfigUtils.getProperty(Argument.FILE_EXTENSION, DefaultValue.FILE_EXTENSION); - } - - public static boolean isDebug() { - return ConfigUtils.getProperty(Argument.DEBUG, DefaultValue.DEBUG); - } - -} +package com.gitee.spirit.common.utils; + +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.constants.Argument; +import com.gitee.spirit.common.constants.DefaultValue; + +@Component +public class ConfigUtils implements EnvironmentAware { + + public static Environment environment; + + @Override + public void setEnvironment(Environment environment) { + ConfigUtils.environment = environment; + } + + public static boolean contains(String key) { + return environment.containsProperty(key); + } + + public static String getProperty(String key) { + return environment.getProperty(key); + } + + public static String getProperty(String key, String defaultValue) { + return environment.getProperty(key, defaultValue); + } + + public static Boolean getProperty(String key, Boolean defaultValue) { + return environment.containsProperty(key) ? environment.getProperty(key, Boolean.class) : defaultValue; + } + + public static Integer getProperty(String key, Integer defaultValue) { + return environment.containsProperty(key) ? environment.getProperty(key, Integer.class) : defaultValue; + } + + public static Long getProperty(String key, Long defaultValue) { + return environment.containsProperty(key) ? environment.getProperty(key, Long.class) : defaultValue; + } + + public static String getInputPath() { + return ConfigUtils.getProperty(Argument.INPUT); + } + + public static String getOutputPath() { + return ConfigUtils.getProperty(Argument.OUTPUT); + } + + public static String getClasspaths() { + return ConfigUtils.getProperty(Argument.CLASSPATHS); + } + + public static String getLangPackage() { + return ConfigUtils.getProperty(Argument.LANG_PACKAGE); + } + + public static String getUtilPackage() { + return ConfigUtils.getProperty(Argument.UTIL_PACKAGE); + } + + public static String getFileExtension() { + return ConfigUtils.getProperty(Argument.FILE_EXTENSION, DefaultValue.FILE_EXTENSION); + } + + public static boolean isDebug() { + return ConfigUtils.getProperty(Argument.DEBUG, DefaultValue.DEBUG); + } + +} diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java index 664ad9ec..a7457610 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java @@ -1,108 +1,108 @@ -package com.gitee.spirit.core.element; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.constants.AppConfig.DefaultValue; -import com.gitee.spirit.common.utils.ConfigUtils; -import com.gitee.spirit.common.utils.LineUtils; -import com.gitee.spirit.common.utils.ListUtils; -import com.gitee.spirit.core.api.DocumentReader; -import com.gitee.spirit.core.api.ElementBuilder; -import com.gitee.spirit.core.element.entity.Document; -import com.gitee.spirit.core.element.entity.Element; -import com.gitee.spirit.core.element.entity.Line; -import com.gitee.spirit.core.element.entity.Statement; - -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.StrUtil; - -@Component -public class DefaultDocumentReader implements DocumentReader { - - @Autowired - public ElementBuilder builder; - - @Override - public Document read(String fileName, InputStream input) { - Document document = new Document(fileName); - List lines = IoUtil.readLines(input, DefaultValue.CHARSET, new ArrayList()); - doReadLines(document, lines); - if (ConfigUtils.isDebug()) { - document.debug(); - } - return document; - } - - public void doReadLines(Document document, List lines) { - Stack> stack = new Stack<>(); - stack.push(document); - for (int index = 0; index < lines.size(); index++) { - String text = lines.get(index); - Line line = new Line(index + 1, text); - if (line.isIgnore()) { - continue; - } - Element element = builder.build(line); - // what like "var = {" - if (mergeLinesIfPossible(document, lines, index, element)) { - index--; - continue; - } - // what like "if xxx : xxx : xxx" - List sublines = splitLineIfPossible(element); - if (sublines != null && !sublines.isEmpty()) { - lines.remove(index); - lines.addAll(index, sublines); - index--; - - } else { - if (line.isEnding()) { - stack.pop(); - } - stack.peek().add(element); - if (line.hasChild()) { - stack.push(element.children); - } - } - } - } - - public boolean mergeLinesIfPossible(Document document, List lines, int startIndex, Element element) { - if (element.isStructAssign()) { - StringBuilder builder = new StringBuilder(lines.get(startIndex)); - for (int index = startIndex + 1; index < lines.size(); index++) { - builder.append(StrUtil.removeAny(lines.get(index), "\t").trim()); - int end = LineUtils.findEndIndex(builder, 0, '{', '}'); - if (end != -1) { - ListUtils.removeByIndex(lines, startIndex, index + 1); - lines.add(startIndex, builder.toString()); - return true; - } - } - } - return false; - } - - public List splitLineIfPossible(Element element) { - if (element.isIf() || element.isFor() || element.isForIn() || element.isWhile()) { - if (element.contains(":")) { - String indent = element.getIndent(); - List subLines = new ArrayList<>(); - List statements = element.splitStmt(":"); - subLines.add(indent + statements.get(0).toString() + " {"); - for (int index = 1; index < statements.size(); index++) { - subLines.add(indent + "\t" + statements.get(index).toString()); - } - subLines.add(indent + "}"); - return subLines; - } - } - return null; - } -} +package com.gitee.spirit.core.element; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.constants.DefaultValue; +import com.gitee.spirit.common.utils.ConfigUtils; +import com.gitee.spirit.common.utils.LineUtils; +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.api.DocumentReader; +import com.gitee.spirit.core.api.ElementBuilder; +import com.gitee.spirit.core.element.entity.Document; +import com.gitee.spirit.core.element.entity.Element; +import com.gitee.spirit.core.element.entity.Line; +import com.gitee.spirit.core.element.entity.Statement; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; + +@Component +public class DefaultDocumentReader implements DocumentReader { + + @Autowired + public ElementBuilder builder; + + @Override + public Document read(String fileName, InputStream input) { + Document document = new Document(fileName); + List lines = IoUtil.readLines(input, DefaultValue.CHARSET, new ArrayList()); + doReadLines(document, lines); + if (ConfigUtils.isDebug()) { + document.debug(); + } + return document; + } + + public void doReadLines(Document document, List lines) { + Stack> stack = new Stack<>(); + stack.push(document); + for (int index = 0; index < lines.size(); index++) { + String text = lines.get(index); + Line line = new Line(index + 1, text); + if (line.isIgnore()) { + continue; + } + Element element = builder.build(line); + // what like "var = {" + if (mergeLinesIfPossible(document, lines, index, element)) { + index--; + continue; + } + // what like "if xxx : xxx : xxx" + List sublines = splitLineIfPossible(element); + if (sublines != null && !sublines.isEmpty()) { + lines.remove(index); + lines.addAll(index, sublines); + index--; + + } else { + if (line.isEnding()) { + stack.pop(); + } + stack.peek().add(element); + if (line.hasChild()) { + stack.push(element.children); + } + } + } + } + + public boolean mergeLinesIfPossible(Document document, List lines, int startIndex, Element element) { + if (element.isStructAssign()) { + StringBuilder builder = new StringBuilder(lines.get(startIndex)); + for (int index = startIndex + 1; index < lines.size(); index++) { + builder.append(StrUtil.removeAny(lines.get(index), "\t").trim()); + int end = LineUtils.findEndIndex(builder, 0, '{', '}'); + if (end != -1) { + ListUtils.removeByIndex(lines, startIndex, index + 1); + lines.add(startIndex, builder.toString()); + return true; + } + } + } + return false; + } + + public List splitLineIfPossible(Element element) { + if (element.isIf() || element.isFor() || element.isForIn() || element.isWhile()) { + if (element.contains(":")) { + String indent = element.getIndent(); + List subLines = new ArrayList<>(); + List statements = element.splitStmt(":"); + subLines.add(indent + statements.get(0).toString() + " {"); + for (int index = 1; index < statements.size(); index++) { + subLines.add(indent + "\t" + statements.get(index).toString()); + } + subLines.add(indent + "}"); + return subLines; + } + } + return null; + } +} diff --git a/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/service/MethodService.java b/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/service/MethodService.java index e336d806..f0318659 100644 --- a/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/service/MethodService.java +++ b/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/service/MethodService.java @@ -1,125 +1,125 @@ -package com.gitee.spirit.code.tools.service; - -import java.io.StringReader; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.gitee.spirit.code.tools.core.CustomClassLoader; -import com.gitee.spirit.code.tools.core.ElementSelector; -import com.gitee.spirit.code.tools.pojo.MethodInfo; -import com.gitee.spirit.common.constants.AppConfig.DefaultValue; -import com.gitee.spirit.common.utils.LineUtils; -import com.gitee.spirit.core.api.ClassLinker; -import com.gitee.spirit.core.clazz.entity.IClass; -import com.gitee.spirit.core.clazz.entity.IMethod; -import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.element.entity.Line; - -import cn.hutool.core.io.IoUtil; - -@Service -public class MethodService { - - @Autowired - public CustomClassLoader loader; - @Autowired - public ElementSelector selector; - @Autowired - public ClassLinker linker; - - public List getMethodInfos(String filePath, String content, Integer lineNumber) { - - // 删除后面的行,将该行进行补全,然后截断,剩下待推导部分 - Map result = completeCode(content, lineNumber); - content = result.get("content"); - String incompleteName = result.get("incompleteName"); - - // 根据文件名,获取className - String className = loader.getName(filePath); - // 找到对应class,并找到印记,获取推导出的类型,并返回所有该类型的方法信息 - IClass clazz = loader.loadClass(className, IoUtil.toStream(content, DefaultValue.CHARSET)); - IType type = selector.findElementAndGetType(clazz, lineNumber); - Object clazzObj = linker.toClass(type); - - List methodInfos = new ArrayList<>(); - if (clazzObj instanceof IClass) { - for (IMethod method : ((IClass) clazzObj).methods) { - if (method.getName().startsWith(incompleteName)) { - methodInfos.add(createMethodInfo(method, incompleteName)); - } - } - } else if (clazzObj instanceof Class) { - for (Method method : ((Class) clazzObj).getMethods()) { - if (method.getName().startsWith(incompleteName)) { - methodInfos.add(createMethodInfo(method, incompleteName)); - } - } - } - return methodInfos; - } - - public Map completeCode(String content, Integer lineNumber) { - Map result = new HashMap<>(); - List lines = IoUtil.readLines(new StringReader(content), new ArrayList()); - String line = lines.get(lineNumber - 1); - if (line.contains("@")) { - String indent = new Line(line).getIndent();// 缩进 - line = line.trim(); - int index = line.indexOf('@'); - line = line.substring(0, index + 1); - for (int idx = index - 1; idx >= 0; idx--) { - char c = line.charAt(idx); - if (c == '(' || c == '[' || c == '{' || c == '<') { - boolean isMatch = matches(line, idx, c); - if (!isMatch) { - line = line.substring(idx + 1); - } - } else if (c == ',') { - line = line.substring(idx + 1); - } - } - String incompleteName = line.substring(line.lastIndexOf('.') + 1, line.lastIndexOf('@')); - result.put("incompleteName", incompleteName); - line = line.substring(0, line.lastIndexOf('.')); - if (!line.startsWith("return")) { - line = "return " + line; - } - lines.set(lineNumber - 1, indent + line); - - } else { - throw new RuntimeException("No symbol '@' found!"); - } - StringBuilder builder = new StringBuilder(); - lines.forEach(line0 -> builder.append(line0 + "\n")); - result.put("content", builder.toString()); - return result; - } - - public boolean matches(String line, int index, char leftChar) { - char rigthChar = LineUtils.flipChar(leftChar); - int end = LineUtils.findEndIndex(line, index, leftChar, rigthChar); - return end != -1; - } - - public MethodInfo createMethodInfo(IMethod method, String incompleteName) { - String tipText = method.toString(); - String actualText = method.toSimpleString(); - if (actualText.startsWith(incompleteName)) { - actualText = actualText.replace(incompleteName, ""); - } - return new MethodInfo(tipText, actualText); - } - - public MethodInfo createMethodInfo(Method method, String incompleteName) { - String tipText = method.toString(); - String actualText = method.toString(); - return new MethodInfo(tipText, actualText); - } - -} +package com.gitee.spirit.code.tools.service; + +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.gitee.spirit.code.tools.core.CustomClassLoader; +import com.gitee.spirit.code.tools.core.ElementSelector; +import com.gitee.spirit.code.tools.pojo.MethodInfo; +import com.gitee.spirit.common.constants.DefaultValue; +import com.gitee.spirit.common.utils.LineUtils; +import com.gitee.spirit.core.api.ClassLinker; +import com.gitee.spirit.core.clazz.entity.IClass; +import com.gitee.spirit.core.clazz.entity.IMethod; +import com.gitee.spirit.core.clazz.entity.IType; +import com.gitee.spirit.core.element.entity.Line; + +import cn.hutool.core.io.IoUtil; + +@Service +public class MethodService { + + @Autowired + public CustomClassLoader loader; + @Autowired + public ElementSelector selector; + @Autowired + public ClassLinker linker; + + public List getMethodInfos(String filePath, String content, Integer lineNumber) { + + // 删除后面的行,将该行进行补全,然后截断,剩下待推导部分 + Map result = completeCode(content, lineNumber); + content = result.get("content"); + String incompleteName = result.get("incompleteName"); + + // 根据文件名,获取className + String className = loader.getName(filePath); + // 找到对应class,并找到印记,获取推导出的类型,并返回所有该类型的方法信息 + IClass clazz = loader.loadClass(className, IoUtil.toStream(content, DefaultValue.CHARSET)); + IType type = selector.findElementAndGetType(clazz, lineNumber); + Object clazzObj = linker.toClass(type); + + List methodInfos = new ArrayList<>(); + if (clazzObj instanceof IClass) { + for (IMethod method : ((IClass) clazzObj).methods) { + if (method.getName().startsWith(incompleteName)) { + methodInfos.add(createMethodInfo(method, incompleteName)); + } + } + } else if (clazzObj instanceof Class) { + for (Method method : ((Class) clazzObj).getMethods()) { + if (method.getName().startsWith(incompleteName)) { + methodInfos.add(createMethodInfo(method, incompleteName)); + } + } + } + return methodInfos; + } + + public Map completeCode(String content, Integer lineNumber) { + Map result = new HashMap<>(); + List lines = IoUtil.readLines(new StringReader(content), new ArrayList()); + String line = lines.get(lineNumber - 1); + if (line.contains("@")) { + String indent = new Line(line).getIndent();// 缩进 + line = line.trim(); + int index = line.indexOf('@'); + line = line.substring(0, index + 1); + for (int idx = index - 1; idx >= 0; idx--) { + char c = line.charAt(idx); + if (c == '(' || c == '[' || c == '{' || c == '<') { + boolean isMatch = matches(line, idx, c); + if (!isMatch) { + line = line.substring(idx + 1); + } + } else if (c == ',') { + line = line.substring(idx + 1); + } + } + String incompleteName = line.substring(line.lastIndexOf('.') + 1, line.lastIndexOf('@')); + result.put("incompleteName", incompleteName); + line = line.substring(0, line.lastIndexOf('.')); + if (!line.startsWith("return")) { + line = "return " + line; + } + lines.set(lineNumber - 1, indent + line); + + } else { + throw new RuntimeException("No symbol '@' found!"); + } + StringBuilder builder = new StringBuilder(); + lines.forEach(line0 -> builder.append(line0 + "\n")); + result.put("content", builder.toString()); + return result; + } + + public boolean matches(String line, int index, char leftChar) { + char rigthChar = LineUtils.flipChar(leftChar); + int end = LineUtils.findEndIndex(line, index, leftChar, rigthChar); + return end != -1; + } + + public MethodInfo createMethodInfo(IMethod method, String incompleteName) { + String tipText = method.toString(); + String actualText = method.toSimpleString(); + if (actualText.startsWith(incompleteName)) { + actualText = actualText.replace(incompleteName, ""); + } + return new MethodInfo(tipText, actualText); + } + + public MethodInfo createMethodInfo(Method method, String incompleteName) { + String tipText = method.toString(); + String actualText = method.toString(); + return new MethodInfo(tipText, actualText); + } + +} -- Gitee From eae6df94cbe2c31a79fc760a44cdafe3389ace21 Mon Sep 17 00:00:00 2001 From: chenT Date: Mon, 7 Jun 2021 22:05:42 +0800 Subject: [PATCH 05/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/enums/OperatorEnum.java | 108 +++++ .../spirit/common/enums/SeparatorEnum.java | 43 ++ .../gitee/spirit/common/enums/SymbolEnum.java | 227 +++------- .../action/AbstractSemanticParser.java | 85 ++-- .../element/action/DefaultTreeBuilder.java | 270 +++++------ .../spirit/core/element/frame/Semantic.java | 424 +++++++++--------- .../spirit/core/element/utils/StmtFormat.java | 192 ++++---- 7 files changed, 687 insertions(+), 662 deletions(-) create mode 100644 spirit-common/src/main/java/com/gitee/spirit/common/enums/OperatorEnum.java create mode 100644 spirit-common/src/main/java/com/gitee/spirit/common/enums/SeparatorEnum.java diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/OperatorEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/OperatorEnum.java new file mode 100644 index 00000000..f83529fb --- /dev/null +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/OperatorEnum.java @@ -0,0 +1,108 @@ +package com.gitee.spirit.common.enums; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public enum OperatorEnum { + + INCREASE("++", OperatorTypeEnum.ARITHMETIC, 40, OperandEnum.LEFT), // + DECREASE("--", OperatorTypeEnum.ARITHMETIC, 40, OperandEnum.LEFT), // + NEGATE("!", OperatorTypeEnum.LOGICAL, 40, OperandEnum.RIGHT), // + MULTIPLY("*", OperatorTypeEnum.ARITHMETIC, 35, OperandEnum.BINARY), // + DIVIDE("/", OperatorTypeEnum.ARITHMETIC, 35, OperandEnum.BINARY), // + REMIND("%", OperatorTypeEnum.ARITHMETIC, 35, OperandEnum.BINARY), // + ADD("+", OperatorTypeEnum.ARITHMETIC, 30, OperandEnum.BINARY), // + SUBTRACT("-", OperatorTypeEnum.ARITHMETIC, 30, OperandEnum.MULTIPLE), // + LEFT_SHIFT("<<", OperatorTypeEnum.BITWISE, 25, OperandEnum.BINARY), // + RIGHT_SHIFT(">>", OperatorTypeEnum.BITWISE, 25, OperandEnum.BINARY), // + BITWISE_NOT("~", OperatorTypeEnum.BITWISE, 20, OperandEnum.RIGHT), // + BITWISE_AND("&", OperatorTypeEnum.BITWISE, 20, OperandEnum.BINARY), // + BITWISE_OR("|", OperatorTypeEnum.BITWISE, 20, OperandEnum.BINARY), // + BITWISE_XOR("^", OperatorTypeEnum.BITWISE, 20, OperandEnum.BINARY), // + EQUAL("==", OperatorTypeEnum.RELATION, 15, OperandEnum.BINARY), // + UNEQUAL("!=", OperatorTypeEnum.RELATION, 15, OperandEnum.BINARY), // + LESS_EQUAL("<=", OperatorTypeEnum.RELATION, 15, OperandEnum.BINARY), // + MORE_EQUAL(">=", OperatorTypeEnum.RELATION, 15, OperandEnum.BINARY), // + LESS("<", OperatorTypeEnum.RELATION, 15, OperandEnum.BINARY), // + MORE(">", OperatorTypeEnum.RELATION, 15, OperandEnum.BINARY), // + AND("&&", OperatorTypeEnum.LOGICAL, 10, OperandEnum.BINARY), // + OR("||", OperatorTypeEnum.LOGICAL, 10, OperandEnum.BINARY), // + QUESTION_MARK("?", OperatorTypeEnum.CONDITIONAL, 5, OperandEnum.BINARY), // + ASSIGN("=", OperatorTypeEnum.ASSIGN, 5, OperandEnum.BINARY); // + + public static final Map OPERATOR_MAP = new ConcurrentHashMap<>(); + + static { + for (OperatorEnum operatorEnum : values()) { + OPERATOR_MAP.put(operatorEnum.value, operatorEnum); + } + } + + public static boolean isOperator(String value) { + return OPERATOR_MAP.containsKey(value); + } + + public static OperatorEnum getOperator(String value) { + return OPERATOR_MAP.get(value); + } + + public static int getPriority(String value) { + return isOperator(value) ? getOperator(value).priority : -1; + } + + public static boolean isArithmetic(String value) { + return isOperator(value) && getOperator(value).category == OperatorTypeEnum.ARITHMETIC; + } + + public static boolean isBitwise(String value) { + return isOperator(value) && getOperator(value).category == OperatorTypeEnum.BITWISE; + } + + public static boolean isRelation(String value) { + return isOperator(value) && getOperator(value).category == OperatorTypeEnum.RELATION; + } + + public static boolean isLogical(String value) { + return isOperator(value) && getOperator(value).category == OperatorTypeEnum.LOGICAL; + } + + public static boolean isConditional(String value) { + return isOperator(value) && getOperator(value).category == OperatorTypeEnum.CONDITIONAL; + } + + public static boolean isAssign(String value) { + return isOperator(value) && getOperator(value).category == OperatorTypeEnum.ASSIGN; + } + + // 符号值 + public String value; + // 类别:算术运算符,位运算符,关系运算符,逻辑运算,条件运算符,赋值运算符 + public OperatorTypeEnum category; + // 优先级 + public int priority; + // 操作数:左元,右元,二元,多义 + public OperandEnum operand; + + private OperatorEnum(String value, OperatorTypeEnum category, int priority, OperandEnum operand) { + this.value = value; + this.category = category; + this.priority = priority; + this.operand = operand; + } + + public enum OperatorTypeEnum { + ARITHMETIC, // 计算 + BITWISE, // 移位 + RELATION, // 关系 + LOGICAL, // 逻辑 + CONDITIONAL, // 条件 + ASSIGN // 赋值 + } + + public enum OperandEnum { + LEFT, // 左元 + RIGHT, // 右元 + BINARY, // 二元 + MULTIPLE // 多义 + } +} diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/SeparatorEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/SeparatorEnum.java new file mode 100644 index 00000000..606850d6 --- /dev/null +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/SeparatorEnum.java @@ -0,0 +1,43 @@ +package com.gitee.spirit.common.enums; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public enum SeparatorEnum { + + LEFT_PARENTHESIS("("), // + RIGHT_PARENTHESIS(")"), // + LEFT_ANGLE_BRACKET("<"), // + RIGHT_ANGLE_BRACKET(">"), // + LEFT_SQUARE_BRACKET("["), // + RIGHT_SQUARE_BRACKET("]"), // + LEFT_CURLY_BRACKET("{"), // + RIGHT_CURLY_BRACKET("}"), // + COLON(":"), // + DOUBLE_COLON("::"), // + COMMA(","), // + SEMICOLON(";"); // + + public static final Map SEPARATOR_MAP = new ConcurrentHashMap<>(); + + static { + for (SeparatorEnum separatorEnum : values()) { + SEPARATOR_MAP.put(separatorEnum.value, separatorEnum); + } + } + + public static boolean isSeparator(String value) { + return SEPARATOR_MAP.containsKey(value); + } + + public static SeparatorEnum getSeparator(String value) { + return SEPARATOR_MAP.get(value); + } + + public String value; + + private SeparatorEnum(String value) { + this.value = value; + } + +} diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/SymbolEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/SymbolEnum.java index 4b6e943e..b817bc37 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/enums/SymbolEnum.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/SymbolEnum.java @@ -1,177 +1,50 @@ -package com.gitee.spirit.common.enums; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public enum SymbolEnum { - - INCREASE("++", SymbolTypeEnum.OPERATOR, OperatorEnum.ARITHMETIC, 40, OperandEnum.LEFT), - DECREASE("--", SymbolTypeEnum.OPERATOR, OperatorEnum.ARITHMETIC, 40, OperandEnum.LEFT), - NEGATE("!", SymbolTypeEnum.OPERATOR, OperatorEnum.LOGICAL, 40, OperandEnum.RIGHT), - MULTIPLY("*", SymbolTypeEnum.OPERATOR, OperatorEnum.ARITHMETIC, 35, OperandEnum.BINARY), - DIVIDE("/", SymbolTypeEnum.OPERATOR, OperatorEnum.ARITHMETIC, 35, OperandEnum.BINARY), - REMIND("%", SymbolTypeEnum.OPERATOR, OperatorEnum.ARITHMETIC, 35, OperandEnum.BINARY), - ADD("+", SymbolTypeEnum.OPERATOR, OperatorEnum.ARITHMETIC, 30, OperandEnum.BINARY), - SUBTRACT("-", SymbolTypeEnum.OPERATOR, OperatorEnum.ARITHMETIC, 30, OperandEnum.MULTIPLE), - LEFT_SHIFT("<<", SymbolTypeEnum.OPERATOR, OperatorEnum.BITWISE, 25, OperandEnum.BINARY), - RIGHT_SHIFT(">>", SymbolTypeEnum.OPERATOR, OperatorEnum.BITWISE, 25, OperandEnum.BINARY), - BITWISE_NOT("~", SymbolTypeEnum.OPERATOR, OperatorEnum.BITWISE, 20, OperandEnum.RIGHT), - BITWISE_AND("&", SymbolTypeEnum.OPERATOR, OperatorEnum.BITWISE, 20, OperandEnum.BINARY), - BITWISE_OR("|", SymbolTypeEnum.OPERATOR, OperatorEnum.BITWISE, 20, OperandEnum.BINARY), - BITWISE_XOR("^", SymbolTypeEnum.OPERATOR, OperatorEnum.BITWISE, 20, OperandEnum.BINARY), - EQUAL("==", SymbolTypeEnum.OPERATOR, OperatorEnum.RELATION, 15, OperandEnum.BINARY), - UNEQUAL("!=", SymbolTypeEnum.OPERATOR, OperatorEnum.RELATION, 15, OperandEnum.BINARY), - LESS_EQUAL("<=", SymbolTypeEnum.OPERATOR, OperatorEnum.RELATION, 15, OperandEnum.BINARY), - MORE_EQUAL(">=", SymbolTypeEnum.OPERATOR, OperatorEnum.RELATION, 15, OperandEnum.BINARY), - LESS("<", SymbolTypeEnum.OPERATOR, OperatorEnum.RELATION, 15, OperandEnum.BINARY), - MORE(">", SymbolTypeEnum.OPERATOR, OperatorEnum.RELATION, 15, OperandEnum.BINARY), - AND("&&", SymbolTypeEnum.OPERATOR, OperatorEnum.LOGICAL, 10, OperandEnum.BINARY), - OR("||", SymbolTypeEnum.OPERATOR, OperatorEnum.LOGICAL, 10, OperandEnum.BINARY), - QUESTION_MARK("?", SymbolTypeEnum.OPERATOR, OperatorEnum.CONDITIONAL, 5, OperandEnum.BINARY), - ASSIGN("=", SymbolTypeEnum.OPERATOR, OperatorEnum.ASSIGN, 5, OperandEnum.BINARY), - - LEFT_PARENTHESIS("(", SymbolTypeEnum.SEPARATOR, null, 0, null), // - RIGHT_PARENTHESIS(")", SymbolTypeEnum.SEPARATOR, null, 0, null), // - LEFT_ANGLE_BRACKET("<", SymbolTypeEnum.SEPARATOR, null, 0, null), // - RIGHT_ANGLE_BRACKET(">", SymbolTypeEnum.SEPARATOR, null, 0, null), // - LEFT_SQUARE_BRACKET("[", SymbolTypeEnum.SEPARATOR, null, 0, null), // - RIGHT_SQUARE_BRACKET("]", SymbolTypeEnum.SEPARATOR, null, 0, null), // - LEFT_CURLY_BRACKET("{", SymbolTypeEnum.SEPARATOR, null, 0, null), // - RIGHT_CURLY_BRACKET("}", SymbolTypeEnum.SEPARATOR, null, 0, null), // - COLON(":", SymbolTypeEnum.SEPARATOR, null, 0, null), // - DOUBLE_COLON("::", SymbolTypeEnum.SEPARATOR, null, 0, null), // - COMMA(",", SymbolTypeEnum.SEPARATOR, null, 0, null), // - SEMICOLON(";", SymbolTypeEnum.SEPARATOR, null, 0, null); // - - public static final char[] SYMBOL_CHARS = new char[] { '+', '-', '!', '*', '/', '%', '<', '>', '~', '&', '|', '^', '=', '?', // - '(', ')', '[', ']', '{', '}', ':', ',', ';' }; - - public static final Map SINGLE_SYMBOL = new ConcurrentHashMap<>(); - - public static final Map DOUBLE_SYMBOL = new ConcurrentHashMap<>(); - - public static final Map OPERATOR_MAP = new ConcurrentHashMap<>(); - - public static final Map SEPARATOR_MAP = new ConcurrentHashMap<>(); - - static { - for (SymbolEnum symbolEnum : values()) { - if (symbolEnum.value.length() == 1) { - SINGLE_SYMBOL.put(symbolEnum.value, symbolEnum); - } else if (symbolEnum.value.length() == 2) { - DOUBLE_SYMBOL.put(symbolEnum.value, symbolEnum); - } - if (symbolEnum.type == SymbolTypeEnum.OPERATOR) { - OPERATOR_MAP.put(symbolEnum.value, symbolEnum); - } else if (symbolEnum.type == SymbolTypeEnum.SEPARATOR) { - SEPARATOR_MAP.put(symbolEnum.value, symbolEnum); - } - } - } - - public static boolean isSymbolChar(char c) { - for (char ch : SYMBOL_CHARS) { - if (ch == c) { - return true; - } - } - return false; - } - - public static boolean isSingleSymbol(String value) { - return SINGLE_SYMBOL.containsKey(value); - } - - public static boolean isDoubleSymbol(String value) { - return DOUBLE_SYMBOL.containsKey(value); - } - - public static boolean isSymbol(String value) { - return OPERATOR_MAP.containsKey(value) || SEPARATOR_MAP.containsKey(value); - } - - public static boolean isOperator(String value) { - return OPERATOR_MAP.containsKey(value); - } - - public static boolean isSeparator(String value) { - return SEPARATOR_MAP.containsKey(value); - } - - public static SymbolEnum getOperator(String value) { - return OPERATOR_MAP.get(value); - } - - public static SymbolEnum getSeparator(String value) { - return SEPARATOR_MAP.get(value); - } - - public static int getPriority(String value) { - return isOperator(value) ? getOperator(value).priority : -1; - } - - public static boolean isArithmetic(String value) { - return isOperator(value) && getOperator(value).category == OperatorEnum.ARITHMETIC; - } - - public static boolean isBitwise(String value) { - return isOperator(value) && getOperator(value).category == OperatorEnum.BITWISE; - } - - public static boolean isRelation(String value) { - return isOperator(value) && getOperator(value).category == OperatorEnum.RELATION; - } - - public static boolean isLogical(String value) { - return isOperator(value) && getOperator(value).category == OperatorEnum.LOGICAL; - } - - public static boolean isConditional(String value) { - return isOperator(value) && getOperator(value).category == OperatorEnum.CONDITIONAL; - } - - public static boolean isAssign(String value) { - return isOperator(value) && getOperator(value).category == OperatorEnum.ASSIGN; - } - - // 符号值 - public String value; - // 类型,操作符,还是分隔符 - public SymbolTypeEnum type; - // 类别:算术运算符,位运算符,关系运算符,逻辑运算,条件运算符,赋值运算符 - public OperatorEnum category; - // 优先级 - public int priority; - // 操作数:左元,右元,二元,多义 - public OperandEnum operand; - - private SymbolEnum(String value, SymbolTypeEnum type, OperatorEnum category, int priority, OperandEnum operand) { - this.value = value; - this.type = type; - this.category = category; - this.priority = priority; - this.operand = operand; - } - - public enum SymbolTypeEnum { - OPERATOR, // 操作符 - SEPARATOR // 分隔符 - } - - public enum OperatorEnum { - ARITHMETIC, // 计算 - BITWISE, // 移位 - RELATION, // 关系 - LOGICAL, // 逻辑 - CONDITIONAL, // 条件 - ASSIGN // 赋值 - } - - public enum OperandEnum { - LEFT, // 左元 - RIGHT, // 右元 - BINARY, // 二元 - MULTIPLE // 多义 - } - -} +package com.gitee.spirit.common.enums; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import cn.hutool.core.util.ArrayUtil; + +public enum SymbolEnum { + ; + public static final Map SINGLE_SYMBOL = new ConcurrentHashMap<>(); + public static final Map DOUBLE_SYMBOL = new ConcurrentHashMap<>(); + public static final char[] SYMBOL_CHARS = new char[] { '+', '-', '!', '*', '/', '%', '<', '>', '~', '&', '|', '^', '=', '?', // + '(', ')', '[', ']', '{', '}', ':', ',', ';' }; + + static { + for (OperatorEnum operatorEnum : OperatorEnum.values()) { + if (operatorEnum.value.length() == 1) { + SINGLE_SYMBOL.put(operatorEnum.value, operatorEnum.value); + + } else if (operatorEnum.value.length() == 2) { + DOUBLE_SYMBOL.put(operatorEnum.value, operatorEnum.value); + } + } + for (SeparatorEnum separatorEnum : SeparatorEnum.values()) { + if (separatorEnum.value.length() == 1) { + SINGLE_SYMBOL.put(separatorEnum.value, separatorEnum.value); + + } else if (separatorEnum.value.length() == 2) { + DOUBLE_SYMBOL.put(separatorEnum.value, separatorEnum.value); + } + } + } + + public static boolean isSymbolChar(char c) { + return ArrayUtil.contains(SYMBOL_CHARS, c); + } + + public static boolean isSingleSymbol(String value) { + return SINGLE_SYMBOL.containsKey(value); + } + + public static boolean isDoubleSymbol(String value) { + return DOUBLE_SYMBOL.containsKey(value); + } + + public static boolean isSymbol(String value) { + return OperatorEnum.isOperator(value) || SeparatorEnum.isSeparator(value); + } + +} diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/AbstractSemanticParser.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/AbstractSemanticParser.java index 0828e53f..1db1e3ea 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/AbstractSemanticParser.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/AbstractSemanticParser.java @@ -1,42 +1,43 @@ -package com.gitee.spirit.core.element.action; - -import com.gitee.spirit.common.enums.KeywordEnum; -import com.gitee.spirit.common.enums.SymbolEnum; -import com.gitee.spirit.common.pattern.AccessPattern; -import com.gitee.spirit.common.pattern.CommonPattern; -import com.gitee.spirit.common.pattern.LiteralPattern; -import com.gitee.spirit.common.pattern.TypePattern; -import com.gitee.spirit.core.api.SemanticParser; - -public abstract class AbstractSemanticParser implements SemanticParser { - - public boolean isAccessPath(String word) { - return !LiteralPattern.isDouble(word) && AccessPattern.isAccessPath(word); - } - - public boolean isAnnotation(String word) { - return CommonPattern.isAnnotation(word); - } - - public boolean isKeyword(String word) { - return KeywordEnum.isKeyword(word); - } - - public boolean isOperator(String word) { - return SymbolEnum.isOperator(word); - } - - public boolean isSeparator(String word) { - return SymbolEnum.isSeparator(word); - } - - @Override - public boolean isType(String word) { - return TypePattern.isAnyType(word); - } - - public boolean isVariable(String word) { - return LiteralPattern.isConstVariable(word) || CommonPattern.isVariable(word); - } - -} +package com.gitee.spirit.core.element.action; + +import com.gitee.spirit.common.enums.KeywordEnum; +import com.gitee.spirit.common.enums.OperatorEnum; +import com.gitee.spirit.common.enums.SeparatorEnum; +import com.gitee.spirit.common.pattern.AccessPattern; +import com.gitee.spirit.common.pattern.CommonPattern; +import com.gitee.spirit.common.pattern.LiteralPattern; +import com.gitee.spirit.common.pattern.TypePattern; +import com.gitee.spirit.core.api.SemanticParser; + +public abstract class AbstractSemanticParser implements SemanticParser { + + public boolean isAccessPath(String word) { + return !LiteralPattern.isDouble(word) && AccessPattern.isAccessPath(word); + } + + public boolean isAnnotation(String word) { + return CommonPattern.isAnnotation(word); + } + + public boolean isKeyword(String word) { + return KeywordEnum.isKeyword(word); + } + + public boolean isOperator(String word) { + return OperatorEnum.isOperator(word); + } + + public boolean isSeparator(String word) { + return SeparatorEnum.isSeparator(word); + } + + @Override + public boolean isType(String word) { + return TypePattern.isAnyType(word); + } + + public boolean isVariable(String word) { + return LiteralPattern.isConstVariable(word) || CommonPattern.isVariable(word); + } + +} diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java index 41afc737..49ebcb92 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java @@ -1,135 +1,135 @@ -package com.gitee.spirit.core.element.action; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.PriorityQueue; -import java.util.Queue; -import java.util.stream.Collectors; - -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.constants.Attribute; -import com.gitee.spirit.common.enums.SymbolEnum; -import com.gitee.spirit.common.enums.SymbolEnum.OperandEnum; -import com.gitee.spirit.common.utils.ListUtils; -import com.gitee.spirit.core.element.entity.Node; -import com.gitee.spirit.core.element.entity.SyntaxTree; -import com.gitee.spirit.core.element.entity.Token; -import com.gitee.spirit.core.element.utils.PriorityNode; -import com.gitee.spirit.core.element.utils.PriorityNode.PriorityComparator; - -@Component -public class DefaultTreeBuilder extends AbstractTreeBuilder { - - @Override - public List buildNodes(List tokens) { - final List nodes = new ArrayList<>(); - ListUtils.visit(tokens, (index, token) -> { - if (token.hasSubStmt()) {// 嵌套语法树 - SyntaxTree syntaxTree = buildTree(token.getValue()); - token = new Token(token.tokenType, syntaxTree, token.attributes); - } - nodes.add(new Node(index, token)); - }); - Queue> queue = getPriorityQueue(tokens); - List newNodes = gatherNodesByQueue(queue, nodes); - return newNodes; - } - - public Queue> getPriorityQueue(List tokens) { - Queue> queue = new PriorityQueue<>(16, new PriorityComparator()); - for (int index = 0; index < tokens.size(); index++) { - Token currentToken = tokens.get(index); - Token nextToken = index + 1 < tokens.size() ? tokens.get(index + 1) : null; - int priority = -1; - OperandEnum operand = null; - - if (currentToken.isVisit()) { - priority = 55; - operand = OperandEnum.LEFT; - - } else if (currentToken.isType()) { - if (nextToken != null && (nextToken.isVariable() || nextToken.isLocalMethod())) { - priority = 50; - operand = OperandEnum.RIGHT; - } - - } else if (currentToken.isOperator()) { - String value = currentToken.toString(); - SymbolEnum symbol = SymbolEnum.getOperator(value); - priority = symbol.priority; - operand = symbol.operand; - - } else if (currentToken.isCast()) { - priority = 35; - operand = OperandEnum.RIGHT; - - } else if (currentToken.isInstanceof()) { - priority = 20; - operand = OperandEnum.BINARY; - } - - if (priority > 0) { - queue.add(new PriorityNode(priority, index)); - currentToken.setAttr(Attribute.OPERAND, operand); - } - } - return queue; - } - - public List gatherNodesByQueue(Queue> queue, List nodes) { - while (!queue.isEmpty()) { - PriorityNode priorityNode = queue.poll(); - int index = priorityNode.item; - Node node = nodes.get(index); - Token currentToken = node.token; - resetOperandIfMultiple(nodes, index, currentToken);// 如果是多义的操作符,则进行判断后,确定真正的操作数 - - OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); - if (operandEnum == OperandEnum.LEFT) { - Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); - node.prev = lastNode; - nodes.set(lastNode.index, null); - - } else if (operandEnum == OperandEnum.RIGHT) { - Node nextNode = ListUtils.findOneByIndex(nodes, index + 1, nodes.size(), Objects::nonNull); - node.next = nextNode; - nodes.set(nextNode.index, null); - - } else if (operandEnum == OperandEnum.BINARY) { - Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); - node.prev = lastNode; - nodes.set(lastNode.index, null); - - Node nextNode = ListUtils.findOneByIndex(nodes, index + 1, nodes.size(), Objects::nonNull); - node.next = nextNode; - nodes.set(nextNode.index, null); - - } else { - throw new RuntimeException("Unable to know the operand of the symbol!"); - } - } - return nodes.stream().filter(Objects::nonNull).collect(Collectors.toList());// 过滤掉所有null - } - - public void resetOperandIfMultiple(List nodes, int index, Token currentToken) { - OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); - if (operandEnum == OperandEnum.MULTIPLE) { - Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); - String value = currentToken.toString(); - if (SymbolEnum.SUBTRACT.value.equals(value)) {// 100 + (-10) // var = -1 - if (lastNode != null) { - if (lastNode.isMounted() || (lastNode.token.isNumber() || lastNode.token.isVariable())) { - currentToken.setAttr(Attribute.OPERAND, OperandEnum.BINARY); - } else { - currentToken.setAttr(Attribute.OPERAND, OperandEnum.RIGHT); - } - } else { - currentToken.setAttr(Attribute.OPERAND, OperandEnum.RIGHT); - } - } - } - } - -} +package com.gitee.spirit.core.element.action; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.constants.Attribute; +import com.gitee.spirit.common.enums.OperatorEnum; +import com.gitee.spirit.common.enums.OperatorEnum.OperandEnum; +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.element.entity.Node; +import com.gitee.spirit.core.element.entity.SyntaxTree; +import com.gitee.spirit.core.element.entity.Token; +import com.gitee.spirit.core.element.utils.PriorityNode; +import com.gitee.spirit.core.element.utils.PriorityNode.PriorityComparator; + +@Component +public class DefaultTreeBuilder extends AbstractTreeBuilder { + + @Override + public List buildNodes(List tokens) { + final List nodes = new ArrayList<>(); + ListUtils.visit(tokens, (index, token) -> { + if (token.hasSubStmt()) {// 嵌套语法树 + SyntaxTree syntaxTree = buildTree(token.getValue()); + token = new Token(token.tokenType, syntaxTree, token.attributes); + } + nodes.add(new Node(index, token)); + }); + Queue> queue = getPriorityQueue(tokens); + List newNodes = gatherNodesByQueue(queue, nodes); + return newNodes; + } + + public Queue> getPriorityQueue(List tokens) { + Queue> queue = new PriorityQueue<>(16, new PriorityComparator()); + for (int index = 0; index < tokens.size(); index++) { + Token currentToken = tokens.get(index); + Token nextToken = index + 1 < tokens.size() ? tokens.get(index + 1) : null; + int priority = -1; + OperandEnum operand = null; + + if (currentToken.isVisit()) { + priority = 55; + operand = OperandEnum.LEFT; + + } else if (currentToken.isType()) { + if (nextToken != null && (nextToken.isVariable() || nextToken.isLocalMethod())) { + priority = 50; + operand = OperandEnum.RIGHT; + } + + } else if (currentToken.isOperator()) { + String value = currentToken.toString(); + OperatorEnum operator = OperatorEnum.getOperator(value); + priority = operator.priority; + operand = operator.operand; + + } else if (currentToken.isCast()) { + priority = 35; + operand = OperandEnum.RIGHT; + + } else if (currentToken.isInstanceof()) { + priority = 20; + operand = OperandEnum.BINARY; + } + + if (priority > 0) { + queue.add(new PriorityNode(priority, index)); + currentToken.setAttr(Attribute.OPERAND, operand); + } + } + return queue; + } + + public List gatherNodesByQueue(Queue> queue, List nodes) { + while (!queue.isEmpty()) { + PriorityNode priorityNode = queue.poll(); + int index = priorityNode.item; + Node node = nodes.get(index); + Token currentToken = node.token; + resetOperandIfMultiple(nodes, index, currentToken);// 如果是多义的操作符,则进行判断后,确定真正的操作数 + + OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); + if (operandEnum == OperandEnum.LEFT) { + Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); + node.prev = lastNode; + nodes.set(lastNode.index, null); + + } else if (operandEnum == OperandEnum.RIGHT) { + Node nextNode = ListUtils.findOneByIndex(nodes, index + 1, nodes.size(), Objects::nonNull); + node.next = nextNode; + nodes.set(nextNode.index, null); + + } else if (operandEnum == OperandEnum.BINARY) { + Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); + node.prev = lastNode; + nodes.set(lastNode.index, null); + + Node nextNode = ListUtils.findOneByIndex(nodes, index + 1, nodes.size(), Objects::nonNull); + node.next = nextNode; + nodes.set(nextNode.index, null); + + } else { + throw new RuntimeException("Unable to know the operand of the symbol!"); + } + } + return nodes.stream().filter(Objects::nonNull).collect(Collectors.toList());// 过滤掉所有null + } + + public void resetOperandIfMultiple(List nodes, int index, Token currentToken) { + OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); + if (operandEnum == OperandEnum.MULTIPLE) { + Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); + String value = currentToken.toString(); + if (OperatorEnum.SUBTRACT.value.equals(value)) {// 100 + (-10) // var = -1 + if (lastNode != null) { + if (lastNode.isMounted() || (lastNode.token.isNumber() || lastNode.token.isVariable())) { + currentToken.setAttr(Attribute.OPERAND, OperandEnum.BINARY); + } else { + currentToken.setAttr(Attribute.OPERAND, OperandEnum.RIGHT); + } + } else { + currentToken.setAttr(Attribute.OPERAND, OperandEnum.RIGHT); + } + } + } + } + +} diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java index 283b48e8..245d559a 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java @@ -1,212 +1,212 @@ -package com.gitee.spirit.core.element.frame; - -import java.util.Map; - -import com.gitee.spirit.common.enums.KeywordEnum; -import com.gitee.spirit.common.enums.SymbolEnum; -import com.gitee.spirit.common.enums.TokenTypeEnum; - -public abstract class Semantic extends Attributes { - - public TokenTypeEnum tokenType; - - public Semantic(TokenTypeEnum tokenType, Map attributes) { - super(attributes); - this.tokenType = tokenType; - } - - public boolean isAccessPath() { - return tokenType == TokenTypeEnum.ACCESS_PATH; - } - - public boolean isAnnotation() { - return tokenType == TokenTypeEnum.ANNOTATION; - } - - public boolean isKeyword() { - return tokenType == TokenTypeEnum.KEYWORD; - } - - public boolean isOperator() { - return tokenType == TokenTypeEnum.OPERATOR; - } - - public boolean isSeparator() { - return tokenType == TokenTypeEnum.SEPARATOR; - } - - public boolean isType() { - return tokenType == TokenTypeEnum.TYPE; - } - - public boolean isArrayInit() { - return tokenType == TokenTypeEnum.ARRAY_INIT; - } - - public boolean isTypeInit() { - return tokenType == TokenTypeEnum.TYPE_INIT; - } - - public boolean isNull() { - return tokenType == TokenTypeEnum.NULL; - } - - public boolean isBoolean() { - return tokenType == TokenTypeEnum.BOOLEAN; - } - - public boolean isChar() { - return tokenType == TokenTypeEnum.CHAR; - } - - public boolean isInt() { - return tokenType == TokenTypeEnum.INT; - } - - public boolean isLong() { - return tokenType == TokenTypeEnum.LONG; - } - - public boolean isDouble() { - return tokenType == TokenTypeEnum.DOUBLE; - } - - public boolean isString() { - return tokenType == TokenTypeEnum.STRING; - } - - public boolean isList() { - return tokenType == TokenTypeEnum.LIST; - } - - public boolean isMap() { - return tokenType == TokenTypeEnum.MAP; - } - - public boolean isSubexpress() { - return tokenType == TokenTypeEnum.SUBEXPRESS; - } - - public boolean isCast() { - return tokenType == TokenTypeEnum.CAST; - } - - public boolean isVariable() { - return tokenType == TokenTypeEnum.VARIABLE; - } - - public boolean isLocalMethod() { - return tokenType == TokenTypeEnum.LOCAL_METHOD; - } - - public boolean isVisitField() { - return tokenType == TokenTypeEnum.VISIT_FIELD; - } - - public boolean isVisitMethod() { - return tokenType == TokenTypeEnum.VISIT_METHOD; - } - - public boolean isVisitIndex() { - return tokenType == TokenTypeEnum.VISIT_INDEX; - } - - public boolean isPrefix() { - return tokenType == TokenTypeEnum.PREFIX; - } - - public boolean isCustomPrefix() { - return tokenType == TokenTypeEnum.CUSTOM_PREFIX; - } - - public boolean isCustomSuffix() { - return tokenType == TokenTypeEnum.CUSTOM_SUFFIX; - } - - public boolean isCustomExpress() { - return tokenType == TokenTypeEnum.CUSTOM_EXPRESS; - } - - public boolean isInit() { - return isArrayInit() || isTypeInit(); - } - - public boolean isLiteral() { - return isNull() || isBoolean() || isChar() || isInt() || isLong() || isDouble() || isString() || isList() || isMap(); - } - - public boolean isNumber() { - return isInt() || isLong() || isDouble(); - } - - public boolean isAccess() { - return isLocalMethod() || isVisitField() || isVisitMethod() || isVisitIndex(); - } - - public boolean isInvoke() { - return isTypeInit() || isLocalMethod() || isVisitMethod(); - } - - public boolean isVisit() { - return isVisitField() || isVisitMethod() || isVisitIndex(); - } - - public boolean hasSubStmt() { - return isList() || isMap() || isSubexpress() || isInvoke(); - } - - public boolean isModifier() { - return isKeyword() && KeywordEnum.isModifier(getValue()); - } - - public boolean isInstanceof() { - return isKeyword() && KeywordEnum.INSTANCEOF.value.equals(getValue().toString()); - } - - public boolean isArithmetic() { - return isOperator() && SymbolEnum.isArithmetic(getValue().toString()); - } - - public boolean isBitwise() { - return isOperator() && SymbolEnum.isBitwise(getValue().toString()); - } - - public boolean isRelation() { - return isOperator() && SymbolEnum.isRelation(getValue().toString()); - } - - public boolean isLogical() { - return isOperator() && SymbolEnum.isLogical(getValue().toString()); - } - - public boolean isAssign() { - return isOperator() && SymbolEnum.isAssign(getValue().toString()); - } - - public boolean isEquals() { - return isOperator() && SymbolEnum.EQUAL.value.equals(getValue()); - } - - public boolean isUnequals() { - return isOperator() && SymbolEnum.UNEQUAL.value.equals(getValue()); - } - - public boolean isShift() { - return isOperator() && (SymbolEnum.LEFT_SHIFT.value.equals(getValue()) || SymbolEnum.RIGHT_SHIFT.value.equals(getValue())); - } - - public boolean isNegate() { - return isOperator() && SymbolEnum.NEGATE.value.equals(getValue()); - } - - public boolean isLogicAnd() { - return isOperator() && SymbolEnum.AND.value.equals(getValue()); - } - - public boolean isLogicOr() { - return isOperator() && SymbolEnum.OR.value.equals(getValue()); - } - - public abstract T getValue(); - -} +package com.gitee.spirit.core.element.frame; + +import java.util.Map; + +import com.gitee.spirit.common.enums.KeywordEnum; +import com.gitee.spirit.common.enums.OperatorEnum; +import com.gitee.spirit.common.enums.TokenTypeEnum; + +public abstract class Semantic extends Attributes { + + public TokenTypeEnum tokenType; + + public Semantic(TokenTypeEnum tokenType, Map attributes) { + super(attributes); + this.tokenType = tokenType; + } + + public boolean isAccessPath() { + return tokenType == TokenTypeEnum.ACCESS_PATH; + } + + public boolean isAnnotation() { + return tokenType == TokenTypeEnum.ANNOTATION; + } + + public boolean isKeyword() { + return tokenType == TokenTypeEnum.KEYWORD; + } + + public boolean isOperator() { + return tokenType == TokenTypeEnum.OPERATOR; + } + + public boolean isSeparator() { + return tokenType == TokenTypeEnum.SEPARATOR; + } + + public boolean isType() { + return tokenType == TokenTypeEnum.TYPE; + } + + public boolean isArrayInit() { + return tokenType == TokenTypeEnum.ARRAY_INIT; + } + + public boolean isTypeInit() { + return tokenType == TokenTypeEnum.TYPE_INIT; + } + + public boolean isNull() { + return tokenType == TokenTypeEnum.NULL; + } + + public boolean isBoolean() { + return tokenType == TokenTypeEnum.BOOLEAN; + } + + public boolean isChar() { + return tokenType == TokenTypeEnum.CHAR; + } + + public boolean isInt() { + return tokenType == TokenTypeEnum.INT; + } + + public boolean isLong() { + return tokenType == TokenTypeEnum.LONG; + } + + public boolean isDouble() { + return tokenType == TokenTypeEnum.DOUBLE; + } + + public boolean isString() { + return tokenType == TokenTypeEnum.STRING; + } + + public boolean isList() { + return tokenType == TokenTypeEnum.LIST; + } + + public boolean isMap() { + return tokenType == TokenTypeEnum.MAP; + } + + public boolean isSubexpress() { + return tokenType == TokenTypeEnum.SUBEXPRESS; + } + + public boolean isCast() { + return tokenType == TokenTypeEnum.CAST; + } + + public boolean isVariable() { + return tokenType == TokenTypeEnum.VARIABLE; + } + + public boolean isLocalMethod() { + return tokenType == TokenTypeEnum.LOCAL_METHOD; + } + + public boolean isVisitField() { + return tokenType == TokenTypeEnum.VISIT_FIELD; + } + + public boolean isVisitMethod() { + return tokenType == TokenTypeEnum.VISIT_METHOD; + } + + public boolean isVisitIndex() { + return tokenType == TokenTypeEnum.VISIT_INDEX; + } + + public boolean isPrefix() { + return tokenType == TokenTypeEnum.PREFIX; + } + + public boolean isCustomPrefix() { + return tokenType == TokenTypeEnum.CUSTOM_PREFIX; + } + + public boolean isCustomSuffix() { + return tokenType == TokenTypeEnum.CUSTOM_SUFFIX; + } + + public boolean isCustomExpress() { + return tokenType == TokenTypeEnum.CUSTOM_EXPRESS; + } + + public boolean isInit() { + return isArrayInit() || isTypeInit(); + } + + public boolean isLiteral() { + return isNull() || isBoolean() || isChar() || isInt() || isLong() || isDouble() || isString() || isList() || isMap(); + } + + public boolean isNumber() { + return isInt() || isLong() || isDouble(); + } + + public boolean isAccess() { + return isLocalMethod() || isVisitField() || isVisitMethod() || isVisitIndex(); + } + + public boolean isInvoke() { + return isTypeInit() || isLocalMethod() || isVisitMethod(); + } + + public boolean isVisit() { + return isVisitField() || isVisitMethod() || isVisitIndex(); + } + + public boolean hasSubStmt() { + return isList() || isMap() || isSubexpress() || isInvoke(); + } + + public boolean isModifier() { + return isKeyword() && KeywordEnum.isModifier(getValue()); + } + + public boolean isInstanceof() { + return isKeyword() && KeywordEnum.INSTANCEOF.value.equals(getValue().toString()); + } + + public boolean isArithmetic() { + return isOperator() && OperatorEnum.isArithmetic(getValue().toString()); + } + + public boolean isBitwise() { + return isOperator() && OperatorEnum.isBitwise(getValue().toString()); + } + + public boolean isRelation() { + return isOperator() && OperatorEnum.isRelation(getValue().toString()); + } + + public boolean isLogical() { + return isOperator() && OperatorEnum.isLogical(getValue().toString()); + } + + public boolean isAssign() { + return isOperator() && OperatorEnum.isAssign(getValue().toString()); + } + + public boolean isEquals() { + return isOperator() && OperatorEnum.EQUAL.value.equals(getValue()); + } + + public boolean isUnequals() { + return isOperator() && OperatorEnum.UNEQUAL.value.equals(getValue()); + } + + public boolean isShift() { + return isOperator() && (OperatorEnum.LEFT_SHIFT.value.equals(getValue()) || OperatorEnum.RIGHT_SHIFT.value.equals(getValue())); + } + + public boolean isNegate() { + return isOperator() && OperatorEnum.NEGATE.value.equals(getValue()); + } + + public boolean isLogicAnd() { + return isOperator() && OperatorEnum.AND.value.equals(getValue()); + } + + public boolean isLogicOr() { + return isOperator() && OperatorEnum.OR.value.equals(getValue()); + } + + public abstract T getValue(); + +} diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtFormat.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtFormat.java index 581a846e..ee1cae82 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtFormat.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtFormat.java @@ -1,96 +1,96 @@ -package com.gitee.spirit.core.element.utils; - -import java.util.List; - -import com.gitee.spirit.common.constants.Attribute; -import com.gitee.spirit.common.enums.TokenTypeEnum; -import com.gitee.spirit.common.enums.SymbolEnum.OperandEnum; -import com.gitee.spirit.core.element.entity.Statement; -import com.gitee.spirit.core.element.entity.Token; - -public class StmtFormat { - - public static List format(Statement statement) { - - List tokens = statement.copyTokens(); - - for (int index = tokens.size() - 1; index >= 1; index--) { - tokens.add(index, new Token(TokenTypeEnum.SEPARATOR, " ")); - } - - for (int index = 0; index < tokens.size(); index++) { - Token token = tokens.get(index); - if (token.isSeparator() && " ".equals(token.toString())) { - Token lastToken = tokens.get(index - 1); - Token nextToken = tokens.get(index + 1); - // 处理上一节点 - boolean isFinish = dealLastToken(tokens, index, lastToken, nextToken); - if (isFinish) { - continue; - } - // 处理下一节点 - dealNextToken(tokens, index, lastToken, nextToken); - } - } - - return tokens; - } - - public static boolean dealLastToken(List tokens, int index, Token lastToken, Token nextToken) { - if (lastToken.isOperator()) { - if ("!".equals(lastToken.toString())) { - tokens.remove(index); - return true; - - } else if ("-".equals(lastToken.toString())) { - OperandEnum operandEnum = lastToken.attr(Attribute.OPERAND); - if (operandEnum == OperandEnum.RIGHT) { - tokens.remove(index); - return true; - } - } - - } else if (lastToken.isSeparator()) { - if ("[".equals(lastToken.toString()) || "(".equals(lastToken.toString()) || "<".equals(lastToken.toString())) { - tokens.remove(index); - return true; - } - - } else if (lastToken.isCustomPrefix()) { - tokens.remove(index); - return true; - } - - return false; - } - - public static void dealNextToken(List tokens, int index, Token lastToken, Token nextToken) { - if (nextToken.isOperator()) { - if ("++".equals(nextToken.toString()) || "--".equals(nextToken.toString())) { - OperandEnum operandEnum = nextToken.attr(Attribute.OPERAND); - if (operandEnum == OperandEnum.LEFT) { - tokens.remove(index); - return; - } - } - - } else if (nextToken.isSeparator()) { - if ("[".equals(nextToken.toString()) || "]".equals(nextToken.toString()) || // - "(".equals(nextToken.toString()) || ")".equals(nextToken.toString()) || // - "<".equals(nextToken.toString()) || ">".equals(nextToken.toString()) || // - ",".equals(nextToken.toString()) || ";".equals(nextToken.toString())) { - tokens.remove(index); - return; - } - - } else if (nextToken.isVisit()) { - tokens.remove(index); - return; - - } else if (nextToken.isCustomSuffix()) { - tokens.remove(index); - return; - } - } - -} +package com.gitee.spirit.core.element.utils; + +import java.util.List; + +import com.gitee.spirit.common.constants.Attribute; +import com.gitee.spirit.common.enums.OperatorEnum.OperandEnum; +import com.gitee.spirit.common.enums.TokenTypeEnum; +import com.gitee.spirit.core.element.entity.Statement; +import com.gitee.spirit.core.element.entity.Token; + +public class StmtFormat { + + public static List format(Statement statement) { + + List tokens = statement.copyTokens(); + + for (int index = tokens.size() - 1; index >= 1; index--) { + tokens.add(index, new Token(TokenTypeEnum.SEPARATOR, " ")); + } + + for (int index = 0; index < tokens.size(); index++) { + Token token = tokens.get(index); + if (token.isSeparator() && " ".equals(token.toString())) { + Token lastToken = tokens.get(index - 1); + Token nextToken = tokens.get(index + 1); + // 处理上一节点 + boolean isFinish = dealLastToken(tokens, index, lastToken, nextToken); + if (isFinish) { + continue; + } + // 处理下一节点 + dealNextToken(tokens, index, lastToken, nextToken); + } + } + + return tokens; + } + + public static boolean dealLastToken(List tokens, int index, Token lastToken, Token nextToken) { + if (lastToken.isOperator()) { + if ("!".equals(lastToken.toString())) { + tokens.remove(index); + return true; + + } else if ("-".equals(lastToken.toString())) { + OperandEnum operandEnum = lastToken.attr(Attribute.OPERAND); + if (operandEnum == OperandEnum.RIGHT) { + tokens.remove(index); + return true; + } + } + + } else if (lastToken.isSeparator()) { + if ("[".equals(lastToken.toString()) || "(".equals(lastToken.toString()) || "<".equals(lastToken.toString())) { + tokens.remove(index); + return true; + } + + } else if (lastToken.isCustomPrefix()) { + tokens.remove(index); + return true; + } + + return false; + } + + public static void dealNextToken(List tokens, int index, Token lastToken, Token nextToken) { + if (nextToken.isOperator()) { + if ("++".equals(nextToken.toString()) || "--".equals(nextToken.toString())) { + OperandEnum operandEnum = nextToken.attr(Attribute.OPERAND); + if (operandEnum == OperandEnum.LEFT) { + tokens.remove(index); + return; + } + } + + } else if (nextToken.isSeparator()) { + if ("[".equals(nextToken.toString()) || "]".equals(nextToken.toString()) || // + "(".equals(nextToken.toString()) || ")".equals(nextToken.toString()) || // + "<".equals(nextToken.toString()) || ">".equals(nextToken.toString()) || // + ",".equals(nextToken.toString()) || ";".equals(nextToken.toString())) { + tokens.remove(index); + return; + } + + } else if (nextToken.isVisit()) { + tokens.remove(index); + return; + + } else if (nextToken.isCustomSuffix()) { + tokens.remove(index); + return; + } + } + +} -- Gitee From 17b49553c3715644d37b8b0c7f5a639cd4ca21eb Mon Sep 17 00:00:00 2001 From: chenT Date: Mon, 7 Jun 2021 22:06:13 +0800 Subject: [PATCH 06/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/spirit/common/enums/SymbolEnum.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/SymbolEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/SymbolEnum.java index b817bc37..9159bfb1 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/enums/SymbolEnum.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/SymbolEnum.java @@ -31,8 +31,8 @@ public enum SymbolEnum { } } - public static boolean isSymbolChar(char c) { - return ArrayUtil.contains(SYMBOL_CHARS, c); + public static boolean isSymbolChar(char ch) { + return ArrayUtil.contains(SYMBOL_CHARS, ch); } public static boolean isSingleSymbol(String value) { -- Gitee From 81dab500780a3d8ab9b22f7fef94e303c6f40ce4 Mon Sep 17 00:00:00 2001 From: chenT Date: Mon, 7 Jun 2021 22:39:24 +0800 Subject: [PATCH 07/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/output/java/ExtImportSelector.java | 14 +++++++------ .../output/java/utils/ReflectUtils.java | 21 ------------------- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java index a02ec925..5e16ab76 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java @@ -6,7 +6,6 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.core.clazz.AbstractImportSelector; import com.gitee.spirit.core.clazz.utils.TypeUtils; -import com.gitee.spirit.output.java.utils.ReflectUtils; @Component @Order(-80) @@ -22,15 +21,18 @@ public class ExtImportSelector extends AbstractImportSelector { @Override public String findClassName(String simpleName) { - return ReflectUtils.getClassName(TypeUtils.getTargetName(simpleName), TypeUtils.isArray(simpleName)); + String targetName = TypeUtils.getTargetName(simpleName); + boolean isArray = TypeUtils.isArray(simpleName); + Class clazz = loader.loadClass("java.lang." + targetName); + if (clazz != null) { + return isArray ? "[L" + clazz.getName() + ";" : clazz.getName(); + } + return null; } @Override public boolean shouldImport(String selfClassName, String className) { - if (super.shouldImport(selfClassName, className)) { - return !className.startsWith("java.lang."); - } - return false; + return super.shouldImport(selfClassName, className) && !className.startsWith("java.lang."); } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/utils/ReflectUtils.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/utils/ReflectUtils.java index 834bb3fd..10796ec7 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/utils/ReflectUtils.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/utils/ReflectUtils.java @@ -25,27 +25,6 @@ public class ReflectUtils { } } - public static Class getClass(String className) { - try { - return Class.forName(className); - - } catch (ClassNotFoundException e) { - throw new RuntimeException("The class was not found!className:[" + className + "]"); - } - } - - public static String getClassName(String targetName, boolean isArray) { - try { - Class clazz = ReflectUtils.getClass("java.lang." + targetName); - if (clazz != null) { - return isArray ? "[L" + clazz.getName() + ";" : clazz.getName(); - } - } catch (Exception e) { - // ignore - } - return null; - } - public static Field getDeclaredField(Class clazz, String fieldName) { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { -- Gitee From 349243c3177b41444486de56e664b75217bc9db6 Mon Sep 17 00:00:00 2001 From: chenT Date: Mon, 7 Jun 2021 23:56:35 +0800 Subject: [PATCH 08/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/enums/PrimitiveEnum.java | 179 +++++++++------- .../spirit/core/clazz/frame/ImportEntity.java | 2 +- .../spirit/core/clazz/utils/TypeUtils.java | 200 +++++++++--------- .../spirit/output/java/ExtImportSelector.java | 9 +- 4 files changed, 210 insertions(+), 180 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/PrimitiveEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/PrimitiveEnum.java index 68002473..fc3efe35 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/enums/PrimitiveEnum.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/PrimitiveEnum.java @@ -1,81 +1,98 @@ -package com.gitee.spirit.common.enums; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import cn.hutool.core.lang.Assert; - -public enum PrimitiveEnum { - - VOID("void", "void", "void", true/* primitive */, false), // - BOOLEAN("boolean", "boolean", "boolean", true/* primitive */, false), // - CHAR("char", "char", "char", true/* primitive */, false), // - BYTE("byte", "byte", "byte", true/* primitive */, false), // - SHORT("short", "short", "short", true/* primitive */, false), // - INT("int", "int", "int", true/* primitive */, false), // - LONG("long", "long", "long", true/* primitive */, false), // - FLOAT("float", "float", "float", true/* primitive */, false), // - DOUBLE("double", "double", "double", true/* primitive */, false), // - - BOOLEAN_ARRAY("[Z", "boolean[]", "boolean[]", false, true/* array */), // - CHAR_ARRAY("[C", "char[]", "char[]", false, true/* array */), // - BYTE_ARRAY("[B", "byte[]", "byte[]", false, true/* array */), // - SHORT_ARRAY("[S", "short[]", "short[]", false, true/* array */), // - INT_ARRAY("[I", "int[]", "int[]", false, true/* array */), // - LONG_ARRAY("[J", "long[]", "long[]", false, true/* array */), // - FLOAT_ARRAY("[F", "float[]", "float[]", false, true/* array */), // - DOUBLE_ARRAY("[D", "double[]", "double[]", false, true/* array */); // - - public static final String PRIMITIVE_ENUM = "void|boolean|char|byte|short|int|long|float|double"; - - public static final Map CLASS_NAME_MAPPING = new ConcurrentHashMap<>(); - public static final Map SIMPLE_NAME_MAPPING = new ConcurrentHashMap<>(); - - static { - for (PrimitiveEnum primitiveEnum : values()) { - CLASS_NAME_MAPPING.put(primitiveEnum.className, primitiveEnum); - SIMPLE_NAME_MAPPING.put(primitiveEnum.simpleName, primitiveEnum); - } - } - - public static boolean isPrimitive(String className) { - return CLASS_NAME_MAPPING.containsKey(className) && CLASS_NAME_MAPPING.get(className).isPrimitive; - } - - public static boolean isPrimitiveArray(String className) { - return CLASS_NAME_MAPPING.containsKey(className) && CLASS_NAME_MAPPING.get(className).isArray; - } - - public static boolean isPrimitiveBySimple(String simpleName) { - return SIMPLE_NAME_MAPPING.containsKey(simpleName) && SIMPLE_NAME_MAPPING.get(simpleName).isPrimitive; - } - - public static boolean isPrimitiveArrayBySimple(String simpleName) { - return SIMPLE_NAME_MAPPING.containsKey(simpleName) && SIMPLE_NAME_MAPPING.get(simpleName).isArray; - } - - public static String getPrimitiveArrayTargetName(String className) { - Assert.isTrue(isPrimitiveArray(className), "Class name must be a primitive array!"); - String simpleName = CLASS_NAME_MAPPING.get(className).simpleName; - return simpleName.substring(0, simpleName.length() - 2); - } - - public static String tryGetClassName(String simpleName) { - return SIMPLE_NAME_MAPPING.containsKey(simpleName) ? SIMPLE_NAME_MAPPING.get(simpleName).className : null; - } - - public String className; - public String simpleName; - public String typeName; - public boolean isPrimitive; - public boolean isArray; - - private PrimitiveEnum(String className, String simpleName, String typeName, boolean isPrimitive, boolean isArray) { - this.className = className; - this.simpleName = simpleName; - this.typeName = typeName; - this.isPrimitive = isPrimitive; - this.isArray = isArray; - } - -} +package com.gitee.spirit.common.enums; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import cn.hutool.core.lang.Assert; + +public enum PrimitiveEnum { + + VOID("void", "void", "void", true/* primitive */, false), // + BOOLEAN("boolean", "boolean", "boolean", true/* primitive */, false), // + CHAR("char", "char", "char", true/* primitive */, false), // + BYTE("byte", "byte", "byte", true/* primitive */, false), // + SHORT("short", "short", "short", true/* primitive */, false), // + INT("int", "int", "int", true/* primitive */, false), // + LONG("long", "long", "long", true/* primitive */, false), // + FLOAT("float", "float", "float", true/* primitive */, false), // + DOUBLE("double", "double", "double", true/* primitive */, false), // + + BOOLEAN_ARRAY("[Z", "boolean[]", "boolean[]", false, true/* array */), // + CHAR_ARRAY("[C", "char[]", "char[]", false, true/* array */), // + BYTE_ARRAY("[B", "byte[]", "byte[]", false, true/* array */), // + SHORT_ARRAY("[S", "short[]", "short[]", false, true/* array */), // + INT_ARRAY("[I", "int[]", "int[]", false, true/* array */), // + LONG_ARRAY("[J", "long[]", "long[]", false, true/* array */), // + FLOAT_ARRAY("[F", "float[]", "float[]", false, true/* array */), // + DOUBLE_ARRAY("[D", "double[]", "double[]", false, true/* array */); // + + public static final Map CLASS_NAME_MAPPING = new ConcurrentHashMap<>(); + public static final Map SIMPLE_NAME_MAPPING = new ConcurrentHashMap<>(); + public static final String PRIMITIVE_ENUM = "void|boolean|char|byte|short|int|long|float|double"; + + static { + for (PrimitiveEnum primitiveEnum : values()) { + CLASS_NAME_MAPPING.put(primitiveEnum.className, primitiveEnum); + SIMPLE_NAME_MAPPING.put(primitiveEnum.simpleName, primitiveEnum); + } + bindPrimitive(BOOLEAN, BOOLEAN_ARRAY); + bindPrimitive(CHAR, CHAR_ARRAY); + bindPrimitive(BYTE, BYTE_ARRAY); + bindPrimitive(SHORT, SHORT_ARRAY); + bindPrimitive(INT, INT_ARRAY); + bindPrimitive(LONG, LONG_ARRAY); + bindPrimitive(FLOAT, FLOAT_ARRAY); + bindPrimitive(DOUBLE, DOUBLE_ARRAY); + } + + public static void bindPrimitive(PrimitiveEnum primitive, PrimitiveEnum primitiveArray) { + primitive.pointer = primitiveArray; + primitiveArray.pointer = primitive; + } + + public static boolean isPrimitive(String className) { + return CLASS_NAME_MAPPING.containsKey(className) && CLASS_NAME_MAPPING.get(className).isPrimitive; + } + + public static boolean isPrimitiveArray(String className) { + return CLASS_NAME_MAPPING.containsKey(className) && CLASS_NAME_MAPPING.get(className).isArray; + } + + public static boolean isPrimitiveBySimple(String simpleName) { + return SIMPLE_NAME_MAPPING.containsKey(simpleName) && SIMPLE_NAME_MAPPING.get(simpleName).isPrimitive; + } + + public static boolean isPrimitiveArrayBySimple(String simpleName) { + return SIMPLE_NAME_MAPPING.containsKey(simpleName) && SIMPLE_NAME_MAPPING.get(simpleName).isArray; + } + + public static String getTargetName(String className) { + Assert.isTrue(isPrimitiveArray(className), "Class name must be a primitive array!"); + return CLASS_NAME_MAPPING.get(className).pointer.className; + } + + public static String getArrayName(String className) { + Assert.isTrue(isPrimitive(className), "Class name must be a primitive!"); + return CLASS_NAME_MAPPING.get(className).pointer.className; + } + + public static String findClassName(String simpleName) { + return SIMPLE_NAME_MAPPING.containsKey(simpleName) ? SIMPLE_NAME_MAPPING.get(simpleName).className : null; + } + + public String className; + public String simpleName; + public String typeName; + public boolean isPrimitive; + public boolean isArray; + public PrimitiveEnum pointer; + + private PrimitiveEnum(String className, String simpleName, String typeName, boolean isPrimitive, boolean isArray) { + this.className = className; + this.simpleName = simpleName; + this.typeName = typeName; + this.isPrimitive = isPrimitive; + this.isArray = isArray; + } + +} diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java index 99b00f53..d14a0312 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java @@ -60,7 +60,7 @@ public abstract class ImportEntity extends AnnotationEntity { boolean isArray = TypeUtils.isArray(simpleName); // 1.如果是基本类型,基本类型数组 - String className = PrimitiveEnum.tryGetClassName(simpleName); + String className = PrimitiveEnum.findClassName(simpleName); // 2.首先先去引入里面找 if (className == null) { diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java index 9b901d35..e3b5419d 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java @@ -1,95 +1,105 @@ -package com.gitee.spirit.core.clazz.utils; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - -import com.gitee.spirit.common.enums.PrimitiveEnum; -import com.google.common.base.CharMatcher; -import com.google.common.base.Splitter; - -import cn.hutool.core.lang.Assert; - -public class TypeUtils { - - public static String getPackage(String className) { - return className.substring(0, className.lastIndexOf(".")); - } - - public static boolean isSamePackage(String className1, String className2) { - String packageStr1 = className1.substring(0, className1.lastIndexOf('.')); - String packageStr2 = className2.substring(0, className2.lastIndexOf('.')); - return packageStr1.equals(packageStr2); - } - - public static boolean matchPackages(String className, String... scanPackages) { - if (scanPackages == null || scanPackages.length == 0) { - return true; - } - for (String scanPackage : scanPackages) { - if (StringUtils.isNotBlank(scanPackage)) { - if (className.startsWith(scanPackage + ".") || className.equals(scanPackage)) { - return true; - } - } - } - return false; - } - - public static List splitName(String simpleName) { - List names = Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(simpleName); - return new ArrayList<>(names); - } - - public static boolean isArray(String name) {// className or simpleName or typeName - return name.startsWith("[") || name.endsWith("[]"); - } - - public static String getTargetName(String name) {// className or simpleName or typeName - // 泛型 - if (name.contains("<") && name.endsWith(">")) { - return name.substring(0, name.indexOf('<')); - } - // 内部类 - if (name.contains(".") && name.contains("$")) { - name = name.replaceAll("\\$", "."); - } - // 数组 - if (!isArray(name)) { - return name; - - } else if (name.startsWith("[L") && name.endsWith(";")) { - return name.substring(2, name.length() - 1); - - } else if (name.endsWith("[]")) { - return name.replace("[]", ""); - - } else if (name.startsWith("[")) { - // [Z 转换成 boolean - String targetName = PrimitiveEnum.getPrimitiveArrayTargetName(name); - Assert.notEmpty(targetName, "Target name cannot be empty!"); - return targetName; - } - - throw new RuntimeException("Failed to get target name!"); - } - - public static String getLastName(String className) { - className = getTargetName(className); - return className.substring(className.lastIndexOf(".") + 1); - } - - public static String getSimpleName(String className) { - return getLastName(className) + (isArray(className) ? "[]" : ""); - } - - public static String getTypeName(String className) { - return getTargetName(className) + (isArray(className) ? "[]" : ""); - } - - public static String getClassName(boolean isArray, String className) { - return !isArray ? className : "[L" + className + ";"; - } - -} +package com.gitee.spirit.core.clazz.utils; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +import com.gitee.spirit.common.enums.PrimitiveEnum; +import com.google.common.base.CharMatcher; +import com.google.common.base.Splitter; + +import cn.hutool.core.lang.Assert; + +public class TypeUtils { + + public static String getPackage(String className) { + return className.substring(0, className.lastIndexOf(".")); + } + + public static boolean isSamePackage(String className1, String className2) { + String packageStr1 = className1.substring(0, className1.lastIndexOf('.')); + String packageStr2 = className2.substring(0, className2.lastIndexOf('.')); + return packageStr1.equals(packageStr2); + } + + public static boolean matchPackages(String className, String... scanPackages) { + if (scanPackages == null || scanPackages.length == 0) { + return true; + } + for (String scanPackage : scanPackages) { + if (StringUtils.isNotBlank(scanPackage)) { + if (className.startsWith(scanPackage + ".") || className.equals(scanPackage)) { + return true; + } + } + } + return false; + } + + public static List splitName(String simpleName) { + List names = Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(simpleName); + return new ArrayList<>(names); + } + + public static boolean isArray(String name) {// className or simpleName or typeName + return name.startsWith("[") || name.endsWith("[]"); + } + + public static String getTargetName(String name) {// className or simpleName or typeName + // 泛型 + if (name.contains("<") && name.endsWith(">")) { + return name.substring(0, name.indexOf('<')); + } + // 内部类 + if (name.contains(".") && name.contains("$")) { + name = name.replaceAll("\\$", "."); + } + // 数组 + if (!isArray(name)) { + return name; + + } else if (name.startsWith("[L") && name.endsWith(";")) { + return name.substring(2, name.length() - 1); + + } else if (name.endsWith("[]")) { + return name.replace("[]", ""); + + } else if (name.startsWith("[")) { + // [Z 转换成 boolean + String targetName = PrimitiveEnum.getTargetName(name); + Assert.notEmpty(targetName, "Target name cannot be empty!"); + return targetName; + } + + throw new RuntimeException("Failed to get target name!"); + } + + public static String getArrayName(String className) { + if (isArray(className)) { + return className; + } + if (PrimitiveEnum.isPrimitive(className)) { + return PrimitiveEnum.getArrayName(className); + } + return "[L" + className + ";"; + } + + public static String getLastName(String className) { + className = getTargetName(className); + return className.substring(className.lastIndexOf(".") + 1); + } + + public static String getSimpleName(String className) { + return getLastName(className) + (isArray(className) ? "[]" : ""); + } + + public static String getTypeName(String className) { + return getTargetName(className) + (isArray(className) ? "[]" : ""); + } + + public static String getClassName(boolean isArray, String className) { + return !isArray ? className : "[L" + className + ";"; + } + +} diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java index 5e16ab76..eda5cd19 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java @@ -23,9 +23,12 @@ public class ExtImportSelector extends AbstractImportSelector { public String findClassName(String simpleName) { String targetName = TypeUtils.getTargetName(simpleName); boolean isArray = TypeUtils.isArray(simpleName); - Class clazz = loader.loadClass("java.lang." + targetName); - if (clazz != null) { - return isArray ? "[L" + clazz.getName() + ";" : clazz.getName(); + String className = "java.lang." + targetName; + if (loader.contains(className)) { + Class clazz = loader.loadClass(className); + if (clazz != null) { + return isArray ? TypeUtils.getArrayName(className) : clazz.getName(); + } } return null; } -- Gitee From 11cb5889ae2f03b1ae35f24cfada82a51904abe2 Mon Sep 17 00:00:00 2001 From: chenT Date: Tue, 8 Jun 2021 00:12:20 +0800 Subject: [PATCH 09/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/utils/TypeRegistry.java | 44 +++++++------------ .../spirit/core/clazz/utils/TypeUtils.java | 8 ++-- .../spirit/output/java/ExtImportSelector.java | 8 +--- 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeRegistry.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeRegistry.java index 83c6285a..922711c6 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeRegistry.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeRegistry.java @@ -1,5 +1,8 @@ package com.gitee.spirit.core.clazz.utils; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import com.gitee.spirit.common.enums.PrimitiveEnum; import com.gitee.spirit.common.utils.ConfigUtils; import com.gitee.spirit.core.clazz.entity.IType; @@ -45,6 +48,8 @@ public class TypeRegistry { public static final IType NULL; public static final IType WILDCARD; + public static final Map BOX_TYPE_MAPPING = new ConcurrentHashMap<>(); + static { VOID = TypeBuilder.build(PrimitiveEnum.VOID); BOOLEAN = TypeBuilder.build(PrimitiveEnum.BOOLEAN); @@ -86,37 +91,20 @@ public class TypeRegistry { STRING_ARRAY = TypeBuilder.build("[L" + langPackage + "String;", "String[]", langPackage + "String[]", false, true/* array */, false, false, true); NULL = TypeBuilder.build(langPackage + "Object", "Object", langPackage + "Object", false, false, true/* null */, false, true); WILDCARD = TypeBuilder.build(langPackage + "Object", "Object", langPackage + "Object", false, false, false, true/* wildcard */, true); + + BOX_TYPE_MAPPING.put(VOID.getClassName(), VOID_BOX); + BOX_TYPE_MAPPING.put(BOOLEAN.getClassName(), BOOLEAN_BOX); + BOX_TYPE_MAPPING.put(CHAR.getClassName(), CHAR_BOX); + BOX_TYPE_MAPPING.put(BYTE.getClassName(), BYTE_BOX); + BOX_TYPE_MAPPING.put(SHORT.getClassName(), SHORT_BOX); + BOX_TYPE_MAPPING.put(INT.getClassName(), INT_BOX); + BOX_TYPE_MAPPING.put(LONG.getClassName(), LONG_BOX); + BOX_TYPE_MAPPING.put(FLOAT.getClassName(), FLOAT_BOX); + BOX_TYPE_MAPPING.put(DOUBLE.getClassName(), DOUBLE_BOX); } public static IType getBoxType(String className) { - if (VOID.getClassName().equals(className)) { - return VOID_BOX; - - } else if (BOOLEAN.getClassName().equals(className)) { - return BOOLEAN_BOX; - - } else if (CHAR.getClassName().equals(className)) { - return CHAR_BOX; - - } else if (BYTE.getClassName().equals(className)) { - return BYTE_BOX; - - } else if (SHORT.getClassName().equals(className)) { - return SHORT_BOX; - - } else if (INT.getClassName().equals(className)) { - return INT_BOX; - - } else if (LONG.getClassName().equals(className)) { - return LONG_BOX; - - } else if (FLOAT.getClassName().equals(className)) { - return FLOAT_BOX; - - } else if (DOUBLE.getClassName().equals(className)) { - return DOUBLE_BOX; - } - return null; + return BOX_TYPE_MAPPING.get(className); } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java index e3b5419d..3d5ba320 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java @@ -85,6 +85,10 @@ public class TypeUtils { return "[L" + className + ";"; } + public static String getClassName(boolean isArray, String className) { + return isArray ? getArrayName(className) : className; + } + public static String getLastName(String className) { className = getTargetName(className); return className.substring(className.lastIndexOf(".") + 1); @@ -98,8 +102,4 @@ public class TypeUtils { return getTargetName(className) + (isArray(className) ? "[]" : ""); } - public static String getClassName(boolean isArray, String className) { - return !isArray ? className : "[L" + className + ";"; - } - } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java index eda5cd19..e2e76281 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtImportSelector.java @@ -24,13 +24,7 @@ public class ExtImportSelector extends AbstractImportSelector { String targetName = TypeUtils.getTargetName(simpleName); boolean isArray = TypeUtils.isArray(simpleName); String className = "java.lang." + targetName; - if (loader.contains(className)) { - Class clazz = loader.loadClass(className); - if (clazz != null) { - return isArray ? TypeUtils.getArrayName(className) : clazz.getName(); - } - } - return null; + return loader.contains(className) ? TypeUtils.getClassName(isArray, className) : null; } @Override -- Gitee From d9d99acd442025b76b7bc70cee73aa8cce332764 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 13:10:23 +0800 Subject: [PATCH 10/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/api/TypeDerivator.java | 6 +- .../compile/derivator/AppTypeDerivator.java | 56 ++++++++++--------- .../core/compile/linker/AppMethodMatcher.java | 2 +- .../output/java/linker/ExtMethodMatcher.java | 2 +- 4 files changed, 36 insertions(+), 30 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java index f3d8028c..d67ce0fd 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java @@ -4,10 +4,10 @@ import com.gitee.spirit.core.clazz.entity.IType; public interface TypeDerivator { - IType populate(IType instanceType, IType targetType); - - Integer getAbstractScore(IType abstractType, IType targetType); + Integer getAbstractDegree(IType abstractType, IType targetType); boolean isMoreAbstract(IType abstractType, IType targetType); + IType populate(IType instanceType, IType targetType); + } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 7f0a8eae..0878356d 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -20,40 +20,32 @@ public class AppTypeDerivator implements TypeDerivator { public ClassLinker linker; @Override - public IType populate(IType instanceType, IType targetType) {// 根据全局类型,进行填充 - return TypeVisiter.visit(targetType, eachType -> { - if (eachType.isTypeVariable()) { - int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); - Assert.isTrue(index >= 0, "Index of type variable less than 0!"); - Assert.isTrue(instanceType.isGenericType(), "Type must be a generic type!"); - return TypeBuilder.copy(instanceType.getGenericTypes().get(index)); - } - return eachType; - }); - } - - @Override - public Integer getAbstractScore(IType abstractType, IType targetType) { + public Integer getAbstractDegree(IType abstractType, IType targetType) { if (abstractType == null || targetType == null) { return null; } - if (abstractType.isNull()) {// null类型不能比任何类型抽象 + // null类型不能比任何类型抽象 + if (abstractType.isNull()) { return null; } - if (targetType.isNull()) {// 任何类型都能比null抽象 + // 任何类型都能比null抽象 + if (targetType.isNull()) { return 0; } - if (targetType.equals(abstractType)) {// 这个方法还要判断泛型 + // 这个方法还要判断泛型 + if (targetType.equals(abstractType)) { return 0; } - Integer score = getAbstractScore(abstractType, linker.getSuperType(targetType.toBox()));// 这个方法中,还要考虑到自动拆组包 - if (score != null) { - return score - 1; + // 这个方法中,还要考虑到自动拆组包 + Integer degree = getAbstractDegree(abstractType, linker.getSuperType(targetType.toBox())); + if (degree != null) { + return degree - 1; } - for (IType interfaceType : linker.getInterfaceTypes(targetType)) {// 接口 - Integer score1 = getAbstractScore(abstractType, interfaceType); - if (score1 != null) { - return score1 - 1; + // 接口 + for (IType interfaceType : linker.getInterfaceTypes(targetType)) { + Integer degree1 = getAbstractDegree(abstractType, interfaceType); + if (degree1 != null) { + return degree1 - 1; } } return null; @@ -61,7 +53,21 @@ public class AppTypeDerivator implements TypeDerivator { @Override public boolean isMoreAbstract(IType abstractType, IType targetType) { - return getAbstractScore(abstractType, targetType) != null; + return getAbstractDegree(abstractType, targetType) != null; + } + + @Override + public IType populate(IType instanceType, IType targetType) { + // 根据全局类型,进行填充 + return TypeVisiter.visit(targetType, eachType -> { + if (eachType.isTypeVariable()) { + int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); + Assert.isTrue(index >= 0, "Index of type variable less than 0!"); + Assert.isTrue(instanceType.isGenericType(), "Type must be a generic type!"); + return TypeBuilder.copy(instanceType.getGenericTypes().get(index)); + } + return eachType; + }); } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java index 2acc259f..eea64688 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java @@ -25,7 +25,7 @@ public class AppMethodMatcher { for (IType parameterType : parameterTypes) { IParameter parameter = method.parameters.get(index++); IType methodParameterType = derivator.populate(type, parameter.getType()); - Integer scope = derivator.getAbstractScore(methodParameterType, parameterType); + Integer scope = derivator.getAbstractDegree(methodParameterType, parameterType); if (scope != null) { finalScore += scope; } else { diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java index d60f5784..47d7b356 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java @@ -44,7 +44,7 @@ public class ExtMethodMatcher { nativeParameterType = nativeParameterType.toTarget(); } nativeParameterType = derivator.populateParameter(type, parameterType, nativeParameterType);// 填充类型里的泛型参数 - Integer scope = derivator.getAbstractScore(nativeParameterType, parameterType); + Integer scope = derivator.getAbstractDegree(nativeParameterType, parameterType); if (scope != null) { finalScore += scope; } else { -- Gitee From 822dea783c99373001935a5511a579c609ad9d2f Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 13:15:39 +0800 Subject: [PATCH 11/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/compile/derivator/AppTypeDerivator.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 0878356d..5195aab6 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -37,15 +37,15 @@ public class AppTypeDerivator implements TypeDerivator { return 0; } // 这个方法中,还要考虑到自动拆组包 - Integer degree = getAbstractDegree(abstractType, linker.getSuperType(targetType.toBox())); - if (degree != null) { - return degree - 1; + Integer superTypeDegree = getAbstractDegree(abstractType, linker.getSuperType(targetType.toBox())); + if (superTypeDegree != null) { + return superTypeDegree - 1; } // 接口 for (IType interfaceType : linker.getInterfaceTypes(targetType)) { - Integer degree1 = getAbstractDegree(abstractType, interfaceType); - if (degree1 != null) { - return degree1 - 1; + Integer interfaceTypeDegree = getAbstractDegree(abstractType, interfaceType); + if (interfaceTypeDegree != null) { + return interfaceTypeDegree - 1; } } return null; -- Gitee From 8563f19930463f9369f87481f0937b1361ffb9c5 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 13:26:10 +0800 Subject: [PATCH 12/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/compile/derivator/DefaultVariableTracker.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java index 95145b26..cb92ab7d 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java @@ -57,7 +57,8 @@ public class DefaultVariableTracker implements VariableTracker { public IType findTypeByInherit(VisitContext context, String variableName) { try { - return linker.visitField(context.clazz.getType().withPrivate(), variableName);// 从本身和父类里面寻找,父类可能是native的 + // 从本身和父类里面寻找,父类可能是native的 + return linker.visitField(context.clazz.getType().withPrivate(), variableName); } catch (NoSuchFieldException e) { return null; } -- Gitee From 6705c6414678f7b91df2a88f47a22393727c4b04 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 14:16:33 +0800 Subject: [PATCH 13/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/constants/Argument.java | 2 - .../spirit/common/constants/Attribute.java | 5 - .../spirit/common/constants/DefaultValue.java | 2 - .../spirit/common/constants/Dictionary.java | 8 ++ .../spirit/common/enums/KeywordEnum.java | 11 +-- .../gitee/spirit/core/clazz/entity/IType.java | 13 +++ .../derivator/DefaultVariableTracker.java | 7 +- .../compile/linker/AdaptiveClassLinker.java | 91 ++++++++----------- 8 files changed, 66 insertions(+), 73 deletions(-) create mode 100644 spirit-common/src/main/java/com/gitee/spirit/common/constants/Dictionary.java diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java index ee8a3ce5..ba96bbd6 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java @@ -1,7 +1,6 @@ package com.gitee.spirit.common.constants; public interface Argument { - String INPUT = "input"; String OUTPUT = "output"; String CLASSPATHS = "classpaths"; @@ -9,5 +8,4 @@ public interface Argument { String UTIL_PACKAGE = "utilPackage"; String FILE_EXTENSION = "fileExtension"; String DEBUG = "debug"; - } \ No newline at end of file diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Attribute.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Attribute.java index 8afd1580..bc3c7c8d 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Attribute.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Attribute.java @@ -1,17 +1,12 @@ package com.gitee.spirit.common.constants; public interface Attribute { - String SIMPLE_NAME = "SIMPLE_NAME"; // 类名 String MEMBER_NAME = "MEMBER_NAME"; // 字段名或者方法名 - String OPERAND = "OPERAND"; // 操作数 String TREE_ID = "TREE_ID"; // 树节点id - String POSITION = "POSITION"; // 在语句中的位置 String LENGTH = "LENGTH"; // 字符串的宽度 - String TYPE = "TYPE"; // 类型 String DERIVED = "DERIVED"; // 是否声明 - } diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/DefaultValue.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/DefaultValue.java index 44774d15..fb950cf2 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/constants/DefaultValue.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/DefaultValue.java @@ -1,9 +1,7 @@ package com.gitee.spirit.common.constants; public interface DefaultValue { - String CHARSET = "UTF-8"; String FILE_EXTENSION = "sp"; boolean DEBUG = true; - } \ No newline at end of file diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Dictionary.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Dictionary.java new file mode 100644 index 00000000..09f8962b --- /dev/null +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Dictionary.java @@ -0,0 +1,8 @@ +package com.gitee.spirit.common.constants; + +public interface Dictionary { + String SUPER = "super"; + String THIS = "this"; + String LENGTH = "length"; + String EMPTY = "empty"; +} diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/KeywordEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/KeywordEnum.java index 65d0d191..b6296137 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/enums/KeywordEnum.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/KeywordEnum.java @@ -75,19 +75,10 @@ public enum KeywordEnum { } public static boolean isKeywordVariable(String value) { - return KeywordEnum.SUPER.value.equals(value) || KeywordEnum.THIS.value.equals(value); - } - - public static boolean isSuper(String value) { - return KeywordEnum.SUPER.value.equals(value); - } - - public static boolean isThis(String value) { - return KeywordEnum.THIS.value.equals(value); + return SUPER.value.equals(value) || THIS.value.equals(value); } public String value; - public KeywordTypeEnum type; private KeywordEnum(String value, KeywordTypeEnum type) { diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java index 609e76f0..e0850a18 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java @@ -72,6 +72,19 @@ public class IType { return this; } + public IType lowerAccessLevel() { + if (modifiers == AccessLevelEnum.PRIVATE.value) { + modifiers = AccessLevelEnum.PROTECTED.value; + + } else if (modifiers == AccessLevelEnum.PROTECTED.value) { + modifiers = AccessLevelEnum.PROTECTED.value; + + } else if (modifiers == AccessLevelEnum.PUBLIC.value) { + modifiers = AccessLevelEnum.PUBLIC.value; + } + return this; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof IType)) { diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java index cb92ab7d..49d6a8ce 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultVariableTracker.java @@ -3,7 +3,7 @@ package com.gitee.spirit.core.compile.derivator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.gitee.spirit.common.enums.KeywordEnum; +import com.gitee.spirit.common.constants.Dictionary; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.VariableTracker; import com.gitee.spirit.core.clazz.entity.IClass; @@ -29,9 +29,10 @@ public class DefaultVariableTracker implements VariableTracker { public IType findTypeByKeyword(VisitContext context, String variableName) { IClass clazz = context.clazz; - if (KeywordEnum.isSuper(variableName)) { + if (Dictionary.SUPER.equals(variableName)) { return clazz.getSuperType().withProtected(); - } else if (KeywordEnum.isThis(variableName)) { + + } else if (Dictionary.THIS.equals(variableName)) { return clazz.getType().withPrivate(); } return null; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index 091ce065..4f4cbec8 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -2,14 +2,14 @@ package com.gitee.spirit.core.compile.linker; import java.util.ArrayList; import java.util.List; -import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; +import com.gitee.spirit.common.constants.Dictionary; import com.gitee.spirit.common.enums.KeywordEnum; -import com.gitee.spirit.common.enums.AccessLevelEnum; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.TypeFactory; import com.gitee.spirit.core.clazz.entity.IType; @@ -21,101 +21,92 @@ import cn.hutool.core.lang.Assert; @Component public class AdaptiveClassLinker implements ClassLinker { - public static final String ARRAY_LENGTH = "length"; - @Autowired - public TypeFactory factory; + @Qualifier("appClassLinker") + public ClassLinker appClassLinker; @Autowired - public Map linkers; + @Qualifier("extClassLinker") + public ClassLinker extClassLinker; + @Autowired + public TypeFactory factory; - public ClassLinker getLinker(IType type) { - if (!type.isNative()) { - return linkers.get("appClassLinker"); - } else { - return linkers.get("extClassLinker"); - } + public ClassLinker chooseLinker(IType type) { + return !type.isNative() ? appClassLinker : extClassLinker; } @Override public T toClass(IType type) { - return getLinker(type).toClass(type); + return chooseLinker(type).toClass(type); } @Override public int getTypeVariableIndex(IType type, String genericName) { - return getLinker(type).getTypeVariableIndex(type, genericName); + return chooseLinker(type).getTypeVariableIndex(type, genericName); } @Override public IType getSuperType(IType type) { + // 原始类型没有父类 if (type.isPrimitive()) { return null; } - + // 数组的父类是Object if (type.isArray()) { return TypeRegistry.OBJECT; } - + // Object已经没有父类了 if (TypeRegistry.OBJECT.equals(type)) { return null; } - - IType superType = getLinker(type).getSuperType(type);// 如果不存在父类,则返回Object + // 如果不存在显示的父类,则返回Object + IType superType = chooseLinker(type).getSuperType(type); if (superType == null) { return TypeRegistry.OBJECT; } - - int modifiers = type.getModifiers(); - if (modifiers == AccessLevelEnum.PRIVATE.value || modifiers == AccessLevelEnum.PROTECTED.value) { - superType.setModifiers(AccessLevelEnum.PROTECTED.value); - - } else if (modifiers == AccessLevelEnum.PUBLIC.value) { - superType.setModifiers(AccessLevelEnum.PUBLIC.value); - } - - return superType; + // 降低访问权限 + return superType.lowerAccessLevel(); } @Override public List getInterfaceTypes(IType type) { + // 原始类型没有接口 if (type.isPrimitive()) { return new ArrayList<>(); } + // 数组类型没有接口 if (type.isArray()) { return new ArrayList<>(); } - return getLinker(type).getInterfaceTypes(type); + return chooseLinker(type).getInterfaceTypes(type); } @Override public IType visitField(IType type, String fieldName) throws NoSuchFieldException { Assert.notNull(type, "Type cannot be null!"); Assert.notEmpty(fieldName, "Field name cannot be empty!"); - - if (KeywordEnum.CLASS.value.equals(fieldName)) {// xxx.class class是关键字 + // xxx.class class是关键字 + if (KeywordEnum.CLASS.value.equals(fieldName)) { return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); } - - if (type.isPrimitive()) {// 原始类型没有属性和方法 + // 原始类型没有属性和方法 + if (type.isPrimitive()) { throw new RuntimeException("The primitive type has no field!"); } - - if (type.isArray() && ARRAY_LENGTH.equals(fieldName)) {// 访问数组length直接返回int类型 + // 访问数组length直接返回int类型 + if (type.isArray() && Dictionary.LENGTH.equals(fieldName)) { return TypeRegistry.INT; } - - IType returnType = getLinker(type).visitField(type, fieldName);// 向上遍历推导 + // 向上遍历推导 + IType returnType = chooseLinker(type).visitField(type, fieldName); if (returnType == null) { IType superType = getSuperType(type); if (superType != null) { return visitField(superType, fieldName); } } - if (returnType == null) { throw new NoSuchFieldException(String.format("No such field!className:%s, fieldName:%s", type.getClassName(), fieldName)); } - return returnType; } @@ -123,35 +114,33 @@ public class AdaptiveClassLinker implements ClassLinker { public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { Assert.notNull(type, "Type cannot be null!"); Assert.notEmpty(methodName, "Method name cannot be empty!"); - - if (KeywordEnum.SUPER.value.equals(methodName) || KeywordEnum.THIS.value.equals(methodName)) {// super()和this()指代父类或者本身的构造函数,返回这个类本身 + // super()和this()指代父类或者本身的构造函数,返回这个类本身 + if (Dictionary.SUPER.equals(methodName) || Dictionary.THIS.equals(methodName)) { return type; } - - if (type.isPrimitive()) {// 原始类型没有属性和方法 + // 原始类型没有属性和方法 + if (type.isPrimitive()) { throw new RuntimeException("The primitive type has no method!"); } - - if (type.isArray()) {// 原始类型没有属性和方法 + // 原始类型没有属性和方法 + if (type.isArray()) { throw new RuntimeException("Array has no method!"); } - - if (TypeRegistry.OBJECT.equals(type) && KeywordEnum.EMPTY.value.equals(methodName)) {// 如果已经推导到Object,并且方法名是empty的话,则直接返回布尔类型 + // 如果已经推导到Object,并且方法名是empty的话,则直接返回布尔类型 + if (TypeRegistry.OBJECT.equals(type) && Dictionary.EMPTY.equals(methodName)) { return TypeRegistry.BOOLEAN; } - - IType returnType = getLinker(type).visitMethod(type, methodName, parameterTypes);// 向上遍历推导 + // 向上遍历推导 + IType returnType = chooseLinker(type).visitMethod(type, methodName, parameterTypes); if (returnType == null) { IType superType = getSuperType(type); if (superType != null) { return visitMethod(superType, methodName, parameterTypes); } } - if (returnType == null) { throw new NoSuchMethodException(String.format("No such method!className:%s, methodName:%s", type.getClassName(), methodName)); } - return returnType; } -- Gitee From 0154d771ba4aeee0eff947b68817bf4b1f1fdd21 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 15:03:37 +0800 Subject: [PATCH 14/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/constants/Dictionary.java | 1 + .../compile/linker/AdaptiveClassLinker.java | 27 +++++++------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Dictionary.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Dictionary.java index 09f8962b..1d4eb84b 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Dictionary.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Dictionary.java @@ -1,6 +1,7 @@ package com.gitee.spirit.common.constants; public interface Dictionary { + String CLASS = "class"; String SUPER = "super"; String THIS = "this"; String LENGTH = "length"; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index 4f4cbec8..6e7ad6cb 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -9,7 +9,6 @@ import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Dictionary; -import com.gitee.spirit.common.enums.KeywordEnum; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.TypeFactory; import com.gitee.spirit.core.clazz.entity.IType; @@ -69,12 +68,8 @@ public class AdaptiveClassLinker implements ClassLinker { @Override public List getInterfaceTypes(IType type) { - // 原始类型没有接口 - if (type.isPrimitive()) { - return new ArrayList<>(); - } - // 数组类型没有接口 - if (type.isArray()) { + // 原始类型和数组类型没有接口 + if (type.isPrimitive() || type.isArray()) { return new ArrayList<>(); } return chooseLinker(type).getInterfaceTypes(type); @@ -84,13 +79,13 @@ public class AdaptiveClassLinker implements ClassLinker { public IType visitField(IType type, String fieldName) throws NoSuchFieldException { Assert.notNull(type, "Type cannot be null!"); Assert.notEmpty(fieldName, "Field name cannot be empty!"); - // xxx.class class是关键字 - if (KeywordEnum.CLASS.value.equals(fieldName)) { + // obj.class class是关键字 + if (Dictionary.CLASS.equals(fieldName)) { return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); } // 原始类型没有属性和方法 if (type.isPrimitive()) { - throw new RuntimeException("The primitive type has no field!"); + throw new RuntimeException("The primitive type has no other field!"); } // 访问数组length直接返回int类型 if (type.isArray() && Dictionary.LENGTH.equals(fieldName)) { @@ -114,18 +109,14 @@ public class AdaptiveClassLinker implements ClassLinker { public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { Assert.notNull(type, "Type cannot be null!"); Assert.notEmpty(methodName, "Method name cannot be empty!"); + // 原始类型和数组类型没有方法 + if (type.isPrimitive() || type.isArray()) { + throw new RuntimeException("This type has no method!"); + } // super()和this()指代父类或者本身的构造函数,返回这个类本身 if (Dictionary.SUPER.equals(methodName) || Dictionary.THIS.equals(methodName)) { return type; } - // 原始类型没有属性和方法 - if (type.isPrimitive()) { - throw new RuntimeException("The primitive type has no method!"); - } - // 原始类型没有属性和方法 - if (type.isArray()) { - throw new RuntimeException("Array has no method!"); - } // 如果已经推导到Object,并且方法名是empty的话,则直接返回布尔类型 if (TypeRegistry.OBJECT.equals(type) && Dictionary.EMPTY.equals(methodName)) { return TypeRegistry.BOOLEAN; -- Gitee From cf3444ccb2e12474cb2cfda657f78f8943d299ad Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 15:08:40 +0800 Subject: [PATCH 15/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compile/linker/AdaptiveClassLinker.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index 6e7ad6cb..2f7a54d3 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -79,17 +79,25 @@ public class AdaptiveClassLinker implements ClassLinker { public IType visitField(IType type, String fieldName) throws NoSuchFieldException { Assert.notNull(type, "Type cannot be null!"); Assert.notEmpty(fieldName, "Field name cannot be empty!"); - // obj.class class是关键字 - if (Dictionary.CLASS.equals(fieldName)) { - return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); - } // 原始类型没有属性和方法 if (type.isPrimitive()) { - throw new RuntimeException("The primitive type has no other field!"); + if (Dictionary.CLASS.equals(fieldName)) { + return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); + } else { + throw new RuntimeException("The primitive type has no other fields!"); + } } // 访问数组length直接返回int类型 - if (type.isArray() && Dictionary.LENGTH.equals(fieldName)) { - return TypeRegistry.INT; + if (type.isArray()) { + if (Dictionary.LENGTH.equals(fieldName)) { + return TypeRegistry.INT; + } else { + throw new RuntimeException("The array type has no other fields"); + } + } + // obj.class class是关键字 + if (Dictionary.CLASS.equals(fieldName)) { + return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); } // 向上遍历推导 IType returnType = chooseLinker(type).visitField(type, fieldName); -- Gitee From c92f9f0a413ca5e0d95d2f0ffb90b0bf58193fa2 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 15:42:38 +0800 Subject: [PATCH 16/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compile/linker/AdaptiveClassLinker.java | 51 ++++++----------- .../core/compile/linker/ArrayClassLinker.java | 50 +++++++++++++++++ .../compile/linker/PrimitiveClassLinker.java | 55 +++++++++++++++++++ 3 files changed, 121 insertions(+), 35 deletions(-) create mode 100644 spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java create mode 100644 spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index 2f7a54d3..6f9a6f1e 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -1,6 +1,5 @@ package com.gitee.spirit.core.compile.linker; -import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; @@ -20,6 +19,12 @@ import cn.hutool.core.lang.Assert; @Component public class AdaptiveClassLinker implements ClassLinker { + @Autowired + @Qualifier("primitiveClassLinker") + public ClassLinker primitiveClassLinker; + @Autowired + @Qualifier("arrayClassLinker") + public ClassLinker arrayClassLinker; @Autowired @Qualifier("appClassLinker") public ClassLinker appClassLinker; @@ -30,7 +35,15 @@ public class AdaptiveClassLinker implements ClassLinker { public TypeFactory factory; public ClassLinker chooseLinker(IType type) { - return !type.isNative() ? appClassLinker : extClassLinker; + if (type.isPrimitive()) { + return primitiveClassLinker; + } else if (type.isArray()) { + return arrayClassLinker; + } else if (!type.isNative()) { + return appClassLinker; + } else { + return extClassLinker; + } } @Override @@ -45,14 +58,6 @@ public class AdaptiveClassLinker implements ClassLinker { @Override public IType getSuperType(IType type) { - // 原始类型没有父类 - if (type.isPrimitive()) { - return null; - } - // 数组的父类是Object - if (type.isArray()) { - return TypeRegistry.OBJECT; - } // Object已经没有父类了 if (TypeRegistry.OBJECT.equals(type)) { return null; @@ -60,7 +65,7 @@ public class AdaptiveClassLinker implements ClassLinker { // 如果不存在显示的父类,则返回Object IType superType = chooseLinker(type).getSuperType(type); if (superType == null) { - return TypeRegistry.OBJECT; + return type.isPrimitive() ? null : TypeRegistry.OBJECT; } // 降低访问权限 return superType.lowerAccessLevel(); @@ -68,10 +73,6 @@ public class AdaptiveClassLinker implements ClassLinker { @Override public List getInterfaceTypes(IType type) { - // 原始类型和数组类型没有接口 - if (type.isPrimitive() || type.isArray()) { - return new ArrayList<>(); - } return chooseLinker(type).getInterfaceTypes(type); } @@ -79,22 +80,6 @@ public class AdaptiveClassLinker implements ClassLinker { public IType visitField(IType type, String fieldName) throws NoSuchFieldException { Assert.notNull(type, "Type cannot be null!"); Assert.notEmpty(fieldName, "Field name cannot be empty!"); - // 原始类型没有属性和方法 - if (type.isPrimitive()) { - if (Dictionary.CLASS.equals(fieldName)) { - return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); - } else { - throw new RuntimeException("The primitive type has no other fields!"); - } - } - // 访问数组length直接返回int类型 - if (type.isArray()) { - if (Dictionary.LENGTH.equals(fieldName)) { - return TypeRegistry.INT; - } else { - throw new RuntimeException("The array type has no other fields"); - } - } // obj.class class是关键字 if (Dictionary.CLASS.equals(fieldName)) { return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); @@ -117,10 +102,6 @@ public class AdaptiveClassLinker implements ClassLinker { public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { Assert.notNull(type, "Type cannot be null!"); Assert.notEmpty(methodName, "Method name cannot be empty!"); - // 原始类型和数组类型没有方法 - if (type.isPrimitive() || type.isArray()) { - throw new RuntimeException("This type has no method!"); - } // super()和this()指代父类或者本身的构造函数,返回这个类本身 if (Dictionary.SUPER.equals(methodName) || Dictionary.THIS.equals(methodName)) { return type; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java new file mode 100644 index 00000000..ba23e9de --- /dev/null +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java @@ -0,0 +1,50 @@ +package com.gitee.spirit.core.compile.linker; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.constants.Dictionary; +import com.gitee.spirit.core.api.ClassLinker; +import com.gitee.spirit.core.clazz.entity.IType; +import com.gitee.spirit.core.clazz.utils.TypeRegistry; + +@Component +public class ArrayClassLinker implements ClassLinker { + + @Override + public T toClass(IType type) { + throw new RuntimeException("This method is not supported!"); + } + + @Override + public int getTypeVariableIndex(IType type, String genericName) { + throw new RuntimeException("This method is not supported!"); + } + + @Override + public IType getSuperType(IType type) { + return TypeRegistry.OBJECT; + } + + @Override + public List getInterfaceTypes(IType type) { + return new ArrayList<>(); + } + + @Override + public IType visitField(IType type, String fieldName) throws NoSuchFieldException { + if (Dictionary.LENGTH.equals(fieldName)) { + return TypeRegistry.INT; + } else { + throw new RuntimeException("The array type has no other fields"); + } + } + + @Override + public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { + throw new RuntimeException("The array type has no method!"); + } + +} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java new file mode 100644 index 00000000..b06d4f87 --- /dev/null +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java @@ -0,0 +1,55 @@ +package com.gitee.spirit.core.compile.linker; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.constants.Dictionary; +import com.gitee.spirit.core.api.ClassLinker; +import com.gitee.spirit.core.api.TypeFactory; +import com.gitee.spirit.core.clazz.entity.IType; +import com.gitee.spirit.core.clazz.utils.TypeRegistry; + +@Component +public class PrimitiveClassLinker implements ClassLinker { + + @Autowired + public TypeFactory factory; + + @Override + public T toClass(IType type) { + throw new RuntimeException("This method is not supported!"); + } + + @Override + public int getTypeVariableIndex(IType type, String genericName) { + throw new RuntimeException("This method is not supported!"); + } + + @Override + public IType getSuperType(IType type) { + return null; + } + + @Override + public List getInterfaceTypes(IType type) { + return new ArrayList<>(); + } + + @Override + public IType visitField(IType type, String fieldName) throws NoSuchFieldException { + if (Dictionary.CLASS.equals(fieldName)) { + return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); + } else { + throw new RuntimeException("The primitive type has no other fields!"); + } + } + + @Override + public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { + throw new RuntimeException("The primitive type has no method!"); + } + +} -- Gitee From f84118bf12c73a5e7d15b500b00f7351b254f194 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 15:46:28 +0800 Subject: [PATCH 17/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/compile/linker/AdaptiveClassLinker.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index 6f9a6f1e..e55fa091 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -20,14 +20,11 @@ import cn.hutool.core.lang.Assert; public class AdaptiveClassLinker implements ClassLinker { @Autowired - @Qualifier("primitiveClassLinker") - public ClassLinker primitiveClassLinker; + public PrimitiveClassLinker primitiveClassLinker; @Autowired - @Qualifier("arrayClassLinker") - public ClassLinker arrayClassLinker; + public ArrayClassLinker arrayClassLinker; @Autowired - @Qualifier("appClassLinker") - public ClassLinker appClassLinker; + public AppClassLinker appClassLinker; @Autowired @Qualifier("extClassLinker") public ClassLinker extClassLinker; -- Gitee From abda1604a36d02d6fd928083d783fe8d94d21a74 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 17:47:03 +0800 Subject: [PATCH 18/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/spirit/common/entity}/MappableList.java | 2 +- .../java/com/gitee/spirit/common/entity}/PriorityNode.java | 2 +- .../gitee/spirit/core/element/action/DefaultTreeBuilder.java | 4 ++-- .../java/com/gitee/spirit/core/element/frame/TokenBox.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename {spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils => spirit-common/src/main/java/com/gitee/spirit/common/entity}/MappableList.java (97%) rename {spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils => spirit-common/src/main/java/com/gitee/spirit/common/entity}/PriorityNode.java (96%) diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/MappableList.java b/spirit-common/src/main/java/com/gitee/spirit/common/entity/MappableList.java similarity index 97% rename from spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/MappableList.java rename to spirit-common/src/main/java/com/gitee/spirit/common/entity/MappableList.java index 9f4b7b32..81e3eb3e 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/MappableList.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/entity/MappableList.java @@ -1,4 +1,4 @@ -package com.gitee.spirit.core.element.utils; +package com.gitee.spirit.common.entity; import java.util.Collection; import java.util.Iterator; diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/PriorityNode.java b/spirit-common/src/main/java/com/gitee/spirit/common/entity/PriorityNode.java similarity index 96% rename from spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/PriorityNode.java rename to spirit-common/src/main/java/com/gitee/spirit/common/entity/PriorityNode.java index b6996329..04fb56bd 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/PriorityNode.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/entity/PriorityNode.java @@ -1,4 +1,4 @@ -package com.gitee.spirit.core.element.utils; +package com.gitee.spirit.common.entity; import java.util.Comparator; import java.util.PriorityQueue; diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java index 49ebcb92..de5258cb 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java @@ -10,14 +10,14 @@ import java.util.stream.Collectors; import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; +import com.gitee.spirit.common.entity.PriorityNode; +import com.gitee.spirit.common.entity.PriorityNode.PriorityComparator; import com.gitee.spirit.common.enums.OperatorEnum; import com.gitee.spirit.common.enums.OperatorEnum.OperandEnum; import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.core.element.entity.Node; import com.gitee.spirit.core.element.entity.SyntaxTree; import com.gitee.spirit.core.element.entity.Token; -import com.gitee.spirit.core.element.utils.PriorityNode; -import com.gitee.spirit.core.element.utils.PriorityNode.PriorityComparator; @Component public class DefaultTreeBuilder extends AbstractTreeBuilder { diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java index 847d1b5a..c247cf97 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java @@ -3,11 +3,11 @@ package com.gitee.spirit.core.element.frame; import java.util.ArrayList; import java.util.List; +import com.gitee.spirit.common.entity.MappableList; import com.gitee.spirit.common.enums.TokenTypeEnum; import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.common.utils.Splitter; import com.gitee.spirit.core.element.entity.Token; -import com.gitee.spirit.core.element.utils.MappableList; import cn.hutool.core.util.ArrayUtil; -- Gitee From 7dcf06c6f22ef7457bb5e64495a76d60999d541a Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 8 Jun 2021 17:56:29 +0800 Subject: [PATCH 19/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/entity/IClass.java | 4 ++- .../spirit/core/clazz/utils/TypeUtils.java | 26 ------------------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java index 86691861..bb1725d5 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java @@ -12,6 +12,8 @@ import com.gitee.spirit.core.clazz.frame.ImportEntity; import com.gitee.spirit.core.clazz.utils.TypeUtils; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Token; +import com.google.common.base.CharMatcher; +import com.google.common.base.Splitter; import cn.hutool.core.lang.Assert; @@ -59,7 +61,7 @@ public class IClass extends ImportEntity { public int getTypeVariableIndex(String genericName) { String simpleName = getTypeToken().toString(); // 这样分割,是有风险的,不过一般来说,类型说明里面不会再有嵌套 - List names = TypeUtils.splitName(simpleName); + List names = new ArrayList<>(Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(simpleName)); names.remove(0); int index = 0; for (String name : names) { diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java index 3d5ba320..bbfc23be 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java @@ -1,13 +1,6 @@ package com.gitee.spirit.core.clazz.utils; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - import com.gitee.spirit.common.enums.PrimitiveEnum; -import com.google.common.base.CharMatcher; -import com.google.common.base.Splitter; import cn.hutool.core.lang.Assert; @@ -23,25 +16,6 @@ public class TypeUtils { return packageStr1.equals(packageStr2); } - public static boolean matchPackages(String className, String... scanPackages) { - if (scanPackages == null || scanPackages.length == 0) { - return true; - } - for (String scanPackage : scanPackages) { - if (StringUtils.isNotBlank(scanPackage)) { - if (className.startsWith(scanPackage + ".") || className.equals(scanPackage)) { - return true; - } - } - } - return false; - } - - public static List splitName(String simpleName) { - List names = Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(simpleName); - return new ArrayList<>(names); - } - public static boolean isArray(String name) {// className or simpleName or typeName return name.startsWith("[") || name.endsWith("[]"); } -- Gitee From 7d98a792977d40c83e2617f71112cae6e6b57f28 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 11:37:18 +0800 Subject: [PATCH 20/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/clazz/AbstractTypeFactory.java | 4 +- .../gitee/spirit/core/clazz/entity/IType.java | 4 +- .../{TypeRegistry.java => CommonTypes.java} | 2 +- .../spirit/core/compile/AppTypeFactory.java | 26 +++++----- .../core/compile/DefaultClassVisiter.java | 8 +-- .../compile/action/InvokeVisitAction.java | 20 ++++---- .../compile/action/VariableTrackAction.java | 22 ++++---- .../compile/derivator/FragmentDeducer.java | 4 +- .../compile/linker/AdaptiveClassLinker.java | 14 +++--- .../core/compile/linker/ArrayClassLinker.java | 6 +-- .../compile/linker/PrimitiveClassLinker.java | 4 +- .../core/element/utils/StmtVisiter.java | 16 ++++-- .../spirit/output/java/ExtTypeFactory.java | 4 +- .../action/AbstractTreeElementAction.java | 9 ++-- .../output/java/action/CommonAction.java | 50 +++++++++---------- .../output/java/action/EmptyAction.java | 12 ++--- .../java/action/StringEqualsAction.java | 4 +- 17 files changed, 104 insertions(+), 105 deletions(-) rename spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/{TypeRegistry.java => CommonTypes.java} (99%) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractTypeFactory.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractTypeFactory.java index bd2e8ca7..44b73f45 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractTypeFactory.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractTypeFactory.java @@ -10,7 +10,7 @@ import com.gitee.spirit.core.api.SemanticParser; import com.gitee.spirit.core.api.TypeFactory; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import cn.hutool.core.lang.Assert; @@ -33,7 +33,7 @@ public abstract class AbstractTypeFactory implements TypeFactory { @Override public IType createTypeVariable(String genericName) {// T or K - IType type = create(TypeRegistry.OBJECT.getClassName()); + IType type = create(CommonTypes.OBJECT.getClassName()); type.setGenericName(genericName); return type; } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java index e0850a18..219f2c44 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java @@ -8,7 +8,7 @@ import org.apache.commons.lang3.StringUtils; import com.gitee.spirit.common.enums.AccessLevelEnum; import com.gitee.spirit.common.utils.SpringUtils; import com.gitee.spirit.core.api.TypeFactory; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.clazz.utils.TypeUtils; import lombok.Getter; @@ -49,7 +49,7 @@ public class IType { } public IType toBox() { - IType boxType = TypeRegistry.getBoxType(getClassName()); + IType boxType = CommonTypes.getBoxType(getClassName()); return boxType != null ? boxType : this; } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeRegistry.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/CommonTypes.java similarity index 99% rename from spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeRegistry.java rename to spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/CommonTypes.java index 922711c6..c2c4b55b 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeRegistry.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/CommonTypes.java @@ -7,7 +7,7 @@ import com.gitee.spirit.common.enums.PrimitiveEnum; import com.gitee.spirit.common.utils.ConfigUtils; import com.gitee.spirit.core.clazz.entity.IType; -public class TypeRegistry { +public class CommonTypes { public static final IType VOID; public static final IType BOOLEAN; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java index bf4a000d..9fdf42e3 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java @@ -14,7 +14,7 @@ import com.gitee.spirit.core.api.TypeDerivator; import com.gitee.spirit.core.clazz.AbstractTypeFactory; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.clazz.utils.TypeUtils; import com.gitee.spirit.core.compile.derivator.FragmentDeducer; import com.gitee.spirit.core.element.entity.Statement; @@ -66,7 +66,7 @@ public class AppTypeFactory extends AbstractTypeFactory { if (token.value instanceof String) {// String // String[] //? //T,K String simpleName = token.getValue(); if ("?".equals(simpleName)) { - return TypeRegistry.WILDCARD;// ? + return CommonTypes.WILDCARD;// ? } if (clazz.getTypeVariableIndex(simpleName) >= 0) { return createTypeVariable(simpleName);// T or K @@ -96,19 +96,19 @@ public class AppTypeFactory extends AbstractTypeFactory { public IType getValueType(IClass clazz, Token token) { if (token.isBoolean()) { - return TypeRegistry.BOOLEAN; + return CommonTypes.BOOLEAN; } else if (token.isChar()) { - return TypeRegistry.CHAR; + return CommonTypes.CHAR; } else if (token.isInt()) { - return TypeRegistry.INT; + return CommonTypes.INT; } else if (token.isLong()) { - return TypeRegistry.LONG; + return CommonTypes.LONG; } else if (token.isDouble()) { - return TypeRegistry.DOUBLE; + return CommonTypes.DOUBLE; } else if (token.isNull()) { - return TypeRegistry.NULL; + return CommonTypes.NULL; } else if (token.isString()) { - return TypeRegistry.STRING; + return CommonTypes.STRING; } else if (token.isList()) { return getListType(clazz, token); } else if (token.isMap()) { @@ -120,7 +120,7 @@ public class AppTypeFactory extends AbstractTypeFactory { public IType getListType(IClass clazz, Token token) { Statement statement = token.getValue(); List statements = statement.subStmt(1, statement.size() - 1).splitStmt(","); - return create(TypeRegistry.LIST.getClassName(), getGenericType(clazz, statements)); + return create(CommonTypes.LIST.getClassName(), getGenericType(clazz, statements)); } public IType getMapType(IClass clazz, Token token) { @@ -132,13 +132,13 @@ public class AppTypeFactory extends AbstractTypeFactory { keyStatements.add(subStatements.get(0)); valueStatements.add(subStatements.get(1)); } - return create(TypeRegistry.MAP.getClassName(), getGenericType(clazz, keyStatements), getGenericType(clazz, valueStatements)); + return create(CommonTypes.MAP.getClassName(), getGenericType(clazz, keyStatements), getGenericType(clazz, valueStatements)); } public IType getGenericType(IClass clazz, List statements) { // 如果没有元素,则返回Object类型 if (statements.size() == 0) { - return TypeRegistry.OBJECT; + return CommonTypes.OBJECT; } IType genericType = null; for (Statement statement : statements) { @@ -151,7 +151,7 @@ public class AppTypeFactory extends AbstractTypeFactory { genericType = boxType; } else if (!derivator.isMoreAbstract(genericType, boxType)) {// 不同则使用Object - genericType = TypeRegistry.OBJECT; + genericType = CommonTypes.OBJECT; break; } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisiter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisiter.java index 0ce28f12..64fdc16d 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisiter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisiter.java @@ -21,7 +21,7 @@ import com.gitee.spirit.core.clazz.entity.IParameter; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.clazz.entity.IVariable; import com.gitee.spirit.core.clazz.frame.MemberEntity; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; @@ -108,14 +108,14 @@ public class DefaultClassVisiter implements ClassVisiter { visitChildElements(context, method.element); // 判断方法的语法 if (method.element.isFunc()) { - return context.returnType != null ? context.returnType : TypeRegistry.VOID; + return context.returnType != null ? context.returnType : CommonTypes.VOID; } else if (method.element.isDeclareFunc()) { // 获取声明的类型 IType declaredType = factory.create(clazz, method.element.get(0)); // 如果这个方法有方法体 if (method.element.hasChild()) { - IType returnType = context.returnType != null ? context.returnType : TypeRegistry.VOID; + IType returnType = context.returnType != null ? context.returnType : CommonTypes.VOID; // 进行类型校验 if (!derivator.isMoreAbstract(declaredType, returnType)) { throw new RuntimeException("The derived type does not match the declared type!"); @@ -159,7 +159,7 @@ public class DefaultClassVisiter implements ClassVisiter { if (derivator.isMoreAbstract(variable.getType(), context.returnType)) { context.returnType = variable.getType(); } else { - context.returnType = TypeRegistry.OBJECT; + context.returnType = CommonTypes.OBJECT; } } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java index 45cf7495..c5594649 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java @@ -33,10 +33,10 @@ public class InvokeVisitAction extends AbstractAppElementAction { @Override public void visitElement(VisitContext context, Element element) { IClass clazz = context.clazz; - StmtVisiter.visit(element, stmt -> { - for (int index = 0; index < stmt.size(); index++) { + StmtVisiter.forEachStmt(element, statement -> { + for (int index = 0; index < statement.size(); index++) { try { - Token token = stmt.get(index); + Token token = statement.get(index); if (token.attr(Attribute.TYPE) != null) { continue; } @@ -48,25 +48,25 @@ public class InvokeVisitAction extends AbstractAppElementAction { Statement subStatement = token.getValue(); token.setAttr(Attribute.TYPE, deducer.derive(clazz, subStatement.subStmt("(", ")"))); - } else if (token.isLocalMethod()) { + } else if (token.isVisitField()) { + IType type = statement.get(index - 1).attr(Attribute.TYPE); String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitMethod(clazz.getType().withPrivate(), memberName, parameterTypes); + IType returnType = linker.visitField(type, memberName); token.setAttr(Attribute.TYPE, returnType); - } else if (token.isVisitField()) { - IType type = stmt.get(index - 1).attr(Attribute.TYPE); + } else if (token.isLocalMethod()) { String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitField(type, memberName); + IType returnType = linker.visitMethod(clazz.getType().withPrivate(), memberName, parameterTypes); token.setAttr(Attribute.TYPE, returnType); } else if (token.isVisitMethod()) { - IType type = stmt.get(index - 1).attr(Attribute.TYPE); + IType type = statement.get(index - 1).attr(Attribute.TYPE); String memberName = token.attr(Attribute.MEMBER_NAME); IType returnType = linker.visitMethod(type, memberName, parameterTypes); token.setAttr(Attribute.TYPE, returnType); } else if (token.isVisitIndex()) {// what like "[0]" - IType type = stmt.get(index - 1).attr(Attribute.TYPE); + IType type = statement.get(index - 1).attr(Attribute.TYPE); type = type.toTarget();// 转换数组类型为目标类型 token.setAttr(Attribute.TYPE, type); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/VariableTrackAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/VariableTrackAction.java index dc4f126b..cfcf4532 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/VariableTrackAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/VariableTrackAction.java @@ -23,18 +23,16 @@ public class VariableTrackAction extends AbstractAppElementAction { @Override public void visitElement(VisitContext context, Element element) { - StmtVisiter.visit(element, stmt -> { - stmt.forEach(token -> { - if (token.attr(Attribute.TYPE) != null) { - return; - } - if (token.isVariable() || (token.isKeyword() && KeywordEnum.isKeywordVariable(token.getValue()))) { - String variableName = token.toString(); - IType type = tracker.findVariableType(context, variableName); - Assert.notNull(type, "Variable must be declared!variableName:" + variableName); - token.setAttr(Attribute.TYPE, type); - } - }); + StmtVisiter.forEachToken(element, token -> { + if (token.attr(Attribute.TYPE) != null) { + return; + } + if (token.isVariable() || (token.isKeyword() && KeywordEnum.isKeywordVariable(token.getValue()))) { + String variableName = token.toString(); + IType type = tracker.findVariableType(context, variableName); + Assert.notNull(type, "Variable must be declared!variableName:" + variableName); + token.setAttr(Attribute.TYPE, type); + } }); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/FragmentDeducer.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/FragmentDeducer.java index 31be8e53..98ce6c69 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/FragmentDeducer.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/FragmentDeducer.java @@ -9,7 +9,7 @@ import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.core.api.TreeBuilder; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.element.entity.Node; import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; @@ -41,7 +41,7 @@ public class FragmentDeducer { // 如果是逻辑判断,或者类型判断关键字 if (token.isLogical() || token.isRelation() || token.isInstanceof()) { - return TypeRegistry.BOOLEAN; + return CommonTypes.BOOLEAN; } else if (token.isArithmetic() || token.isBitwise()) { // 先取左边的,再取右边的 diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index e55fa091..f0af70de 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -11,7 +11,7 @@ import com.gitee.spirit.common.constants.Dictionary; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.TypeFactory; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import cn.hutool.core.lang.Assert; @@ -56,13 +56,13 @@ public class AdaptiveClassLinker implements ClassLinker { @Override public IType getSuperType(IType type) { // Object已经没有父类了 - if (TypeRegistry.OBJECT.equals(type)) { + if (CommonTypes.OBJECT.equals(type)) { return null; } // 如果不存在显示的父类,则返回Object IType superType = chooseLinker(type).getSuperType(type); if (superType == null) { - return type.isPrimitive() ? null : TypeRegistry.OBJECT; + return type.isPrimitive() ? null : CommonTypes.OBJECT; } // 降低访问权限 return superType.lowerAccessLevel(); @@ -79,9 +79,8 @@ public class AdaptiveClassLinker implements ClassLinker { Assert.notEmpty(fieldName, "Field name cannot be empty!"); // obj.class class是关键字 if (Dictionary.CLASS.equals(fieldName)) { - return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); + return factory.create(CommonTypes.CLASS.getClassName(), type.toBox()); } - // 向上遍历推导 IType returnType = chooseLinker(type).visitField(type, fieldName); if (returnType == null) { IType superType = getSuperType(type); @@ -104,10 +103,9 @@ public class AdaptiveClassLinker implements ClassLinker { return type; } // 如果已经推导到Object,并且方法名是empty的话,则直接返回布尔类型 - if (TypeRegistry.OBJECT.equals(type) && Dictionary.EMPTY.equals(methodName)) { - return TypeRegistry.BOOLEAN; + if (CommonTypes.OBJECT.equals(type) && Dictionary.EMPTY.equals(methodName)) { + return CommonTypes.BOOLEAN; } - // 向上遍历推导 IType returnType = chooseLinker(type).visitMethod(type, methodName, parameterTypes); if (returnType == null) { IType superType = getSuperType(type); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java index ba23e9de..064cb428 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java @@ -8,7 +8,7 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Dictionary; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; @Component public class ArrayClassLinker implements ClassLinker { @@ -25,7 +25,7 @@ public class ArrayClassLinker implements ClassLinker { @Override public IType getSuperType(IType type) { - return TypeRegistry.OBJECT; + return CommonTypes.OBJECT; } @Override @@ -36,7 +36,7 @@ public class ArrayClassLinker implements ClassLinker { @Override public IType visitField(IType type, String fieldName) throws NoSuchFieldException { if (Dictionary.LENGTH.equals(fieldName)) { - return TypeRegistry.INT; + return CommonTypes.INT; } else { throw new RuntimeException("The array type has no other fields"); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java index b06d4f87..1a505bcf 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java @@ -10,7 +10,7 @@ import com.gitee.spirit.common.constants.Dictionary; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.TypeFactory; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; @Component public class PrimitiveClassLinker implements ClassLinker { @@ -41,7 +41,7 @@ public class PrimitiveClassLinker implements ClassLinker { @Override public IType visitField(IType type, String fieldName) throws NoSuchFieldException { if (Dictionary.CLASS.equals(fieldName)) { - return factory.create(TypeRegistry.CLASS.getClassName(), type.toBox()); + return factory.create(CommonTypes.CLASS.getClassName(), type.toBox()); } else { throw new RuntimeException("The primitive type has no other fields!"); } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java index aa0808a5..aef17f3a 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java @@ -1,21 +1,29 @@ package com.gitee.spirit.core.element.utils; +import java.util.function.Consumer; + import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; public class StmtVisiter { - public static void visit(Statement statement, Consumer consumer) { + public static void forEachStmt(Statement statement, Consumer consumer) { for (Token token : statement) { if (token.hasSubStmt()) { - visit(token.getValue(), consumer); + forEachStmt(token.getValue(), consumer); } } consumer.accept(statement); } - public static interface Consumer { - void accept(T t); + public static void forEachToken(Statement statement, Consumer consumer) { + for (Token token : statement) { + if (token.hasSubStmt()) { + forEachToken(token.getValue(), consumer); + } else { + consumer.accept(token); + } + } } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeFactory.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeFactory.java index 7ee2b860..14079a8e 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeFactory.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeFactory.java @@ -11,7 +11,7 @@ import java.util.List; import org.springframework.stereotype.Component; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.compile.AppTypeFactory; @Component @@ -36,7 +36,7 @@ public class ExtTypeFactory extends AppTypeFactory { return create((Class) nativeType); } else if (nativeType instanceof WildcardType) {// ? - return TypeRegistry.WILDCARD; + return CommonTypes.WILDCARD; } else if (nativeType instanceof TypeVariable) {// T or K return createTypeVariable(nativeType.toString()); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java index 6c329e00..ce97cf2b 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java @@ -29,12 +29,11 @@ public abstract class AbstractTreeElementAction extends AbstractExtElementAction @Override public void visitElement(VisitContext context, Element element) { - IClass clazz = context.clazz; - StmtVisiter.visit(element, stmt -> { - for (int index = 0; index < stmt.size(); index++) { - Token token = stmt.get(index); + StmtVisiter.forEachStmt(element, statement -> { + for (int index = 0; index < statement.size(); index++) { + Token token = statement.get(index); if (isTrigger(token)) { - visit(clazz, stmt, index, token); + visit(context.clazz, statement, index, token); } } }); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java index 941a030d..56208162 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java @@ -20,34 +20,32 @@ public class CommonAction extends AbstractExtElementAction { @Override public void visitElement(VisitContext context, Element element) { IClass clazz = context.clazz; - StmtVisiter.visit(element, stmt -> { - stmt.forEach(token -> { - if (token.isArrayInit()) {// String[10] => new String[10] - Statement subStatement = token.getValue(); - subStatement.add(0, new Token(TokenTypeEnum.KEYWORD, "new")); - - } else if (token.isTypeInit()) {// User() => new User() - Statement subStatement = token.getValue(); - subStatement.add(0, new Token(TokenTypeEnum.KEYWORD, "new")); - - } else if (token.isList()) {// ["value"] => Lists.of("value"); - Statement subStatement = token.getValue(); - subStatement.set(0, new Token(TokenTypeEnum.CUSTOM_PREFIX, "Lists.of(")); - subStatement.set(subStatement.size() - 1, new Token(TokenTypeEnum.CUSTOM_SUFFIX, ")")); - clazz.addImport(Lists.class.getName()); - - } else if (token.isMap()) {// {"key":"value"} => Maps.of("key","value"); - Statement subStatement = token.getValue(); - for (Token subToken : subStatement) { - if (subToken.isSeparator() && ":".equals(subToken.toString())) { - subToken.value = ","; - } + StmtVisiter.forEachToken(element, token -> { + if (token.isArrayInit()) {// String[10] => new String[10] + Statement subStatement = token.getValue(); + subStatement.add(0, new Token(TokenTypeEnum.KEYWORD, "new")); + + } else if (token.isTypeInit()) {// User() => new User() + Statement subStatement = token.getValue(); + subStatement.add(0, new Token(TokenTypeEnum.KEYWORD, "new")); + + } else if (token.isList()) {// ["value"] => Lists.of("value"); + Statement subStatement = token.getValue(); + subStatement.set(0, new Token(TokenTypeEnum.CUSTOM_PREFIX, "Lists.of(")); + subStatement.set(subStatement.size() - 1, new Token(TokenTypeEnum.CUSTOM_SUFFIX, ")")); + clazz.addImport(Lists.class.getName()); + + } else if (token.isMap()) {// {"key":"value"} => Maps.of("key","value"); + Statement subStatement = token.getValue(); + for (Token subToken : subStatement) { + if (subToken.isSeparator() && ":".equals(subToken.toString())) { + subToken.value = ","; } - subStatement.set(0, new Token(TokenTypeEnum.CUSTOM_PREFIX, "Maps.of(")); - subStatement.set(subStatement.size() - 1, new Token(TokenTypeEnum.CUSTOM_SUFFIX, ")")); - clazz.addImport(Maps.class.getName()); } - }); + subStatement.set(0, new Token(TokenTypeEnum.CUSTOM_PREFIX, "Maps.of(")); + subStatement.set(subStatement.size() - 1, new Token(TokenTypeEnum.CUSTOM_SUFFIX, ")")); + clazz.addImport(Maps.class.getName()); + } }); } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java index 079468f1..18528f97 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java @@ -18,14 +18,12 @@ public class EmptyAction extends AbstractExtElementAction { @Override public void visitElement(VisitContext context, Element element) { IClass clazz = context.clazz; - StmtVisiter.visit(element, stmt -> { - stmt.forEach(token -> { - if (token.isLocalMethod()) {// empty(str) - if (KeywordEnum.EMPTY.value.equals(token.attr(Attribute.MEMBER_NAME))) { - clazz.addStaticImport(Emptys.class.getName() + ".empty"); - } + StmtVisiter.forEachToken(element, token -> { + if (token.isLocalMethod()) {// empty(str) + if (KeywordEnum.EMPTY.value.equals(token.attr(Attribute.MEMBER_NAME))) { + clazz.addStaticImport(Emptys.class.getName() + ".empty"); } - }); + } }); } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/StringEqualsAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/StringEqualsAction.java index 357363c2..c9acef62 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/StringEqualsAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/StringEqualsAction.java @@ -11,7 +11,7 @@ import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.common.enums.TokenTypeEnum; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeRegistry; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; import com.gitee.spirit.output.java.utils.TypeUtils; @@ -45,7 +45,7 @@ public class StringEqualsAction extends AbstractTreeElementAction { String format = currentToken.isEquals() ? FORMAT : "!" + FORMAT; String text = String.format(format, prevStatement, nextStatement); Token expressToken = new Token(TokenTypeEnum.CUSTOM_EXPRESS, text); - expressToken.setAttr(Attribute.TYPE, TypeRegistry.BOOLEAN); + expressToken.setAttr(Attribute.TYPE, CommonTypes.BOOLEAN); expressToken.setAttr(Attribute.TREE_ID, currentToken.attr(Attribute.TREE_ID)); statement.replaceTokens(start, end, expressToken); clazz.addImport(StringUtils.class.getName()); -- Gitee From 4cd920c624c8cc90b9b721d537e35b6249b2f032 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 11:40:16 +0800 Subject: [PATCH 21/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/spirit/core/element/utils/StmtVisiter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java index aef17f3a..729160d1 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java @@ -20,9 +20,8 @@ public class StmtVisiter { for (Token token : statement) { if (token.hasSubStmt()) { forEachToken(token.getValue(), consumer); - } else { - consumer.accept(token); } + consumer.accept(token); } } -- Gitee From a81f55dba28e805164f1ac295933fa483d4b9bd6 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 12:42:38 +0800 Subject: [PATCH 22/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/spirit/output/java/action/EmptyAction.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java index 18528f97..7a9fbbbd 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java @@ -5,7 +5,6 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.common.enums.KeywordEnum; -import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.utils.StmtVisiter; @@ -17,11 +16,10 @@ public class EmptyAction extends AbstractExtElementAction { @Override public void visitElement(VisitContext context, Element element) { - IClass clazz = context.clazz; StmtVisiter.forEachToken(element, token -> { if (token.isLocalMethod()) {// empty(str) if (KeywordEnum.EMPTY.value.equals(token.attr(Attribute.MEMBER_NAME))) { - clazz.addStaticImport(Emptys.class.getName() + ".empty"); + context.clazz.addStaticImport(Emptys.class.getName() + ".empty"); } } }); -- Gitee From 65dbd9611bf3ef789b6ff2d2156169e1ff0d428e Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 14:41:49 +0800 Subject: [PATCH 23/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/utils/TypeBuilder.java | 3 +- .../spirit/core/clazz/utils/TypeVisiter.java | 32 +++++++++---------- .../compile/derivator/AppTypeDerivator.java | 2 +- .../core/compile/linker/AppClassLinker.java | 3 +- .../spirit/output/java/ExtTypeDerivator.java | 4 +-- .../output/java/linker/ExtClassLinker.java | 2 +- 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeBuilder.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeBuilder.java index 324189a5..58704191 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeBuilder.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeBuilder.java @@ -9,8 +9,7 @@ import com.gitee.spirit.core.clazz.entity.IType; public class TypeBuilder { - public static IType build(String className, String simpleName, String typeName, boolean isPrimitive, boolean isArray, boolean isNull, boolean isWildcard, - boolean isNative) { + public static IType build(String className, String simpleName, String typeName, boolean isPrimitive, boolean isArray, boolean isNull, boolean isWildcard, boolean isNative) { IType type = new IType(); type.setClassName(className); type.setSimpleName(simpleName); diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java index 4879d55b..19a87b2d 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java @@ -7,28 +7,26 @@ import java.util.List; import com.gitee.spirit.core.clazz.entity.IType; import com.google.common.base.Joiner; +import cn.hutool.core.lang.Assert; + public class TypeVisiter { - public static IType visit(IType targetType, Consumer consumer) { - // 如果为空,不进行遍历 - if (targetType == null) { - return targetType; - } - // 拷贝一份 - targetType = TypeBuilder.copy(targetType); - targetType = (IType) consumer.accept(targetType); - // 拷贝一份,注意不可修改集合 - List genericTypes = new ArrayList<>(targetType.getGenericTypes()); - for (int index = 0; index < genericTypes.size(); index++) { - IType genericType = genericTypes.get(index); - genericType = visit(genericType, consumer); + public static IType forEachType(IType targetType, Consumer consumer) { + Assert.notNull(targetType, "Target Type cannot be null!"); + + IType newType = TypeBuilder.copy(targetType); + newType = (IType) consumer.accept(newType); + + List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); + for (int index = 0; index < newGenericTypes.size(); index++) { + IType genericType = forEachType(newGenericTypes.get(index), consumer); if (genericType != null) { - genericTypes.set(index, genericType); + newGenericTypes.set(index, genericType); } } - // 重置 - targetType.setGenericTypes(Collections.unmodifiableList(genericTypes)); - return targetType; + newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); + + return newType; } public static IType visit(IType referType, IType targetType, Consumer0 consumer) { diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 5195aab6..40056ec5 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -59,7 +59,7 @@ public class AppTypeDerivator implements TypeDerivator { @Override public IType populate(IType instanceType, IType targetType) { // 根据全局类型,进行填充 - return TypeVisiter.visit(targetType, eachType -> { + return TypeVisiter.forEachType(targetType, eachType -> { if (eachType.isTypeVariable()) { int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); Assert.isTrue(index >= 0, "Index of type variable less than 0!"); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java index b60a6f42..461ccf7a 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java @@ -48,7 +48,8 @@ public class AppClassLinker implements ClassLinker { @Override public IType getSuperType(IType type) { IClass clazz = toClass(type); - return derivator.populate(type, clazz.getSuperType()); + IType superType = clazz.getSuperType(); + return superType != null ? derivator.populate(type, superType) : null; } @Override diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java index 0e266bf2..4fa4e1c6 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java @@ -20,7 +20,7 @@ public class ExtTypeDerivator extends AppTypeDerivator { @Override public IType populate(IType type, IType targetType) {// 根据全局类型,进行填充 - return TypeVisiter.visit(targetType, eachType -> { + return TypeVisiter.forEachType(targetType, eachType -> { if (eachType.isTypeVariable()) { int index = linker.getTypeVariableIndex(type, eachType.getGenericName()); if (index >= 0) { @@ -75,7 +75,7 @@ public class ExtTypeDerivator extends AppTypeDerivator { } public IType populateReturnType(Map qualifyingTypes, IType targetType) { - return TypeVisiter.visit(targetType, eachType -> { + return TypeVisiter.forEachType(targetType, eachType -> { if (eachType.isTypeVariable()) { return qualifyingTypes.get(targetType.getGenericName()); } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java index 8cd030b0..6a284a01 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java @@ -62,7 +62,7 @@ public class ExtClassLinker implements ClassLinker { Class clazz = toClass(type); Type nativeSuperType = clazz.getGenericSuperclass(); IType superType = nativeSuperType != null ? factory.create(nativeSuperType) : null; - return derivator.populate(type, superType); + return superType != null ? derivator.populate(type, superType) : null; } @Override -- Gitee From cdc43ffce36ed716d0d8c2c83d204c0c42e2efa4 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 15:47:33 +0800 Subject: [PATCH 24/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/utils/TypeVisiter.java | 34 ++++++++----------- .../spirit/output/java/ExtTypeDerivator.java | 2 +- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java index 19a87b2d..1576cef2 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java @@ -13,10 +13,9 @@ public class TypeVisiter { public static IType forEachType(IType targetType, Consumer consumer) { Assert.notNull(targetType, "Target Type cannot be null!"); - - IType newType = TypeBuilder.copy(targetType); - newType = (IType) consumer.accept(newType); - + // 拷贝一份 + IType newType = (IType) consumer.accept(TypeBuilder.copy(targetType)); + // 拷贝一份,注意不可修改集合 List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); for (int index = 0; index < newGenericTypes.size(); index++) { IType genericType = forEachType(newGenericTypes.get(index), consumer); @@ -25,30 +24,25 @@ public class TypeVisiter { } } newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); - return newType; } - public static IType visit(IType referType, IType targetType, Consumer0 consumer) { - // 如果为空,不进行遍历 - if (targetType == null) { - return targetType; - } + public static IType forEachType(IType referType, IType targetType, Consumer0 consumer) { + Assert.notNull(targetType, "Target Type cannot be null!"); // 拷贝一份 - targetType = TypeBuilder.copy(targetType); - targetType = (IType) consumer.accept(referType, targetType); + IType newType = (IType) consumer.accept(referType, TypeBuilder.copy(targetType)); + // 参考的泛型参数 + List referGenericTypes = referType.getGenericTypes(); // 拷贝一份,注意不可修改集合 - List genericTypes = new ArrayList<>(targetType.getGenericTypes()); - for (int index = 0; index < genericTypes.size(); index++) { - IType genericType = genericTypes.get(index); - genericType = visit(referType.getGenericTypes().get(index), genericType, consumer); + List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); + for (int index = 0; index < newGenericTypes.size(); index++) { + IType genericType = forEachType(referGenericTypes.get(index), newGenericTypes.get(index), consumer); if (genericType != null) { - genericTypes.set(index, genericType); + newGenericTypes.set(index, genericType); } } - // 重置 - targetType.setGenericTypes(Collections.unmodifiableList(genericTypes)); - return targetType; + newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); + return newType; } public static String visitName(IType targetType, Consumer consumer) { diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java index 4fa4e1c6..eddb45b3 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java @@ -45,7 +45,7 @@ public class ExtTypeDerivator extends AppTypeDerivator { } public IType populateQualifying(IType parameterType, IType targetType, Map qualifyingTypes) { - return TypeVisiter.visit(parameterType, targetType, (referType, eachType) -> { + return TypeVisiter.forEachType(parameterType, targetType, (referType, eachType) -> { if (eachType.isTypeVariable()) { String genericName = eachType.getGenericName(); if (qualifyingTypes.containsKey(genericName)) {// 如果已经存在了,则必须统一 -- Gitee From 9989bcb65deaa13d9721885428dd152a2e20f388 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 15:54:16 +0800 Subject: [PATCH 25/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/clazz/utils/TypeVisiter.java | 12 +++++------- .../com/gitee/spirit/core/compile/AutoImporter.java | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java index 1576cef2..92a6224f 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java @@ -45,17 +45,15 @@ public class TypeVisiter { return newType; } - public static String visitName(IType targetType, Consumer consumer) { - if (targetType == null) { - return null; - } + public static String forEachTypeName(IType targetType, Consumer consumer) { + Assert.notNull(targetType, "Target Type cannot be null!"); String finalName = (String) consumer.accept(targetType); if (targetType.isGenericType()) { - List strs = new ArrayList<>(); + List typeNames = new ArrayList<>(); for (IType genericType : targetType.getGenericTypes()) { - strs.add(visitName(genericType, consumer)); + typeNames.add(forEachTypeName(genericType, consumer)); } - finalName = finalName + "<" + Joiner.on(", ").join(strs) + ">"; + finalName = finalName + "<" + Joiner.on(", ").join(typeNames) + ">"; } return finalName; } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java index 6261b9c4..4147d169 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java @@ -75,7 +75,7 @@ public class AutoImporter { } public String getFinalName(IClass clazz, IType type) { - return TypeVisiter.visitName(type, eachType -> { + return TypeVisiter.forEachTypeName(type, eachType -> { if (!clazz.addImport(eachType.getClassName())) { return eachType.getTypeName(); } -- Gitee From 8fe0248c064dc161458a24e877d8407c4f199837 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 16:07:55 +0800 Subject: [PATCH 26/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java index 92a6224f..dc6e8559 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java @@ -47,15 +47,15 @@ public class TypeVisiter { public static String forEachTypeName(IType targetType, Consumer consumer) { Assert.notNull(targetType, "Target Type cannot be null!"); - String finalName = (String) consumer.accept(targetType); + String typeName = (String) consumer.accept(targetType); if (targetType.isGenericType()) { List typeNames = new ArrayList<>(); for (IType genericType : targetType.getGenericTypes()) { typeNames.add(forEachTypeName(genericType, consumer)); } - finalName = finalName + "<" + Joiner.on(", ").join(typeNames) + ">"; + typeName = typeName + "<" + Joiner.on(", ").join(typeNames) + ">"; } - return finalName; + return typeName; } public static interface Consumer { -- Gitee From 9f643377f6306ad9a0e52125227aabda438fa883 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 16:29:37 +0800 Subject: [PATCH 27/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/utils/TypeUtils.java | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java index bbfc23be..6071dbdb 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeUtils.java @@ -2,8 +2,6 @@ package com.gitee.spirit.core.clazz.utils; import com.gitee.spirit.common.enums.PrimitiveEnum; -import cn.hutool.core.lang.Assert; - public class TypeUtils { public static String getPackage(String className) { @@ -16,11 +14,23 @@ public class TypeUtils { return packageStr1.equals(packageStr2); } - public static boolean isArray(String name) {// className or simpleName or typeName + /** + * 通过名称判断是否数组 + * + * @param name className or simpleName or typeName + * @return + */ + public static boolean isArray(String name) { return name.startsWith("[") || name.endsWith("[]"); } - public static String getTargetName(String name) {// className or simpleName or typeName + /** + * 获取目标名称。如果是数组,能够获取数组内类型的名称。 + * + * @param name className or simpleName or typeName + * @return + */ + public static String getTargetName(String name) { // 泛型 if (name.contains("<") && name.endsWith(">")) { return name.substring(0, name.indexOf('<')); @@ -30,23 +40,21 @@ public class TypeUtils { name = name.replaceAll("\\$", "."); } // 数组 - if (!isArray(name)) { - return name; + if (isArray(name)) { + if (name.startsWith("[L") && name.endsWith(";")) { + return name.substring(2, name.length() - 1); - } else if (name.startsWith("[L") && name.endsWith(";")) { - return name.substring(2, name.length() - 1); + } else if (name.endsWith("[]")) { + return name.replace("[]", ""); - } else if (name.endsWith("[]")) { - return name.replace("[]", ""); + } else if (PrimitiveEnum.isPrimitiveArray(name)) { + return PrimitiveEnum.getTargetName(name); - } else if (name.startsWith("[")) { - // [Z 转换成 boolean - String targetName = PrimitiveEnum.getTargetName(name); - Assert.notEmpty(targetName, "Target name cannot be empty!"); - return targetName; + } else { + throw new RuntimeException("Unhandled branch!"); + } } - - throw new RuntimeException("Failed to get target name!"); + return name; } public static String getArrayName(String className) { -- Gitee From 4a949897b5ae14f0e12ab8e1b7eeabe37cf9ebb0 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 9 Jun 2021 16:50:48 +0800 Subject: [PATCH 28/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/element/action/DefaultSemanticParser.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java index df9d47f2..11488448 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java @@ -121,14 +121,14 @@ public class DefaultSemanticParser extends AbstractSemanticParser { return word.contains("<") || word.contains(">") ? getStatement(true, word) : word; } else if (token.isArrayInit() || token.isList() || token.isMap() || token.isSubexpress() || token.isInvoke()) { - return getStatement(false, word);// 拆分数组是为了更好的添加new这个关键字 + // 拆分数组是为了更好的添加new这个关键字 + return getStatement(false, word); } return word; } public Statement getStatement(boolean insideType, String word) { - List words = insideType ? lexer.getSubWords(word, '<', '>') - : lexer.getSubWords(word, '(', ')', '[', ']', '{', '}'); + List words = insideType ? lexer.getSubWords(word, '<', '>') : lexer.getSubWords(word, '(', ')', '[', ']', '{', '}'); List tokens = getTokens(new SemanticContext(true, insideType), words); Assert.notNull(tokens, "Tokens cannot be null!"); return new Statement(tokens); -- Gitee From d8b1843e67bae9aa4f812998851e20940729b3cf Mon Sep 17 00:00:00 2001 From: chenT Date: Sat, 19 Jun 2021 21:12:43 +0800 Subject: [PATCH 29/83] =?UTF-8?q?=E6=8A=BD=E8=B1=A1=E5=87=BA=E8=AF=AD?= =?UTF-8?q?=E5=8F=A5=E6=8E=A8=E5=AF=BC=E5=99=A8=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/api/StatementDeducer.java | 10 ++++ .../spirit/core/compile/AppTypeFactory.java | 24 ++++----- .../core/compile/DefaultElementVisiter.java | 6 +-- .../compile/action/ExpressDeclareAction.java | 11 ++-- .../compile/action/InvokeVisitAction.java | 12 ++--- ...ucer.java => DefaultStatementDeducer.java} | 52 +++++++------------ .../element/action/DefaultTreeBuilder.java | 10 ++-- .../core/element/utils/NodeVisiter.java | 29 +++++++++++ .../action/AbstractTreeElementAction.java | 8 +-- .../output/java/action/StatementAction.java | 12 ++--- 10 files changed, 98 insertions(+), 76 deletions(-) create mode 100644 spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/StatementDeducer.java rename spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/{FragmentDeducer.java => DefaultStatementDeducer.java} (39%) create mode 100644 spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisiter.java diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/StatementDeducer.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/StatementDeducer.java new file mode 100644 index 00000000..e81fc042 --- /dev/null +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/StatementDeducer.java @@ -0,0 +1,10 @@ +package com.gitee.spirit.core.api; + +import com.gitee.spirit.core.clazz.entity.IType; +import com.gitee.spirit.core.element.entity.Statement; + +public interface StatementDeducer { + + IType derive(Statement statement); + +} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java index 9fdf42e3..2f002920 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java @@ -10,13 +10,13 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.common.enums.AccessLevelEnum; import com.gitee.spirit.common.enums.PrimitiveEnum; +import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.api.TypeDerivator; import com.gitee.spirit.core.clazz.AbstractTypeFactory; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.clazz.utils.TypeUtils; -import com.gitee.spirit.core.compile.derivator.FragmentDeducer; import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; @@ -29,7 +29,7 @@ public class AppTypeFactory extends AbstractTypeFactory { @Autowired public AppClassLoader classLoader; @Autowired - public FragmentDeducer deducer; + public StatementDeducer deducer; @Autowired public TypeDerivator derivator; @@ -57,7 +57,7 @@ public class AppTypeFactory extends AbstractTypeFactory { return create(clazz, (String) token.attr(Attribute.SIMPLE_NAME)); } else if (token.isLiteral()) {// 1, 1.1, "xxxx" - return getValueType(clazz, token); + return getValueType(token); } return null; } @@ -94,7 +94,7 @@ public class AppTypeFactory extends AbstractTypeFactory { return genericTypes; } - public IType getValueType(IClass clazz, Token token) { + public IType getValueType(Token token) { if (token.isBoolean()) { return CommonTypes.BOOLEAN; } else if (token.isChar()) { @@ -110,20 +110,20 @@ public class AppTypeFactory extends AbstractTypeFactory { } else if (token.isString()) { return CommonTypes.STRING; } else if (token.isList()) { - return getListType(clazz, token); + return getListType(token); } else if (token.isMap()) { - return getMapType(clazz, token); + return getMapType(token); } return null; } - public IType getListType(IClass clazz, Token token) { + public IType getListType(Token token) { Statement statement = token.getValue(); List statements = statement.subStmt(1, statement.size() - 1).splitStmt(","); - return create(CommonTypes.LIST.getClassName(), getGenericType(clazz, statements)); + return create(CommonTypes.LIST.getClassName(), getGenericType(statements)); } - public IType getMapType(IClass clazz, Token token) { + public IType getMapType(Token token) { Statement statement = token.getValue(); List keyStatements = new ArrayList<>(); List valueStatements = new ArrayList<>(); @@ -132,17 +132,17 @@ public class AppTypeFactory extends AbstractTypeFactory { keyStatements.add(subStatements.get(0)); valueStatements.add(subStatements.get(1)); } - return create(CommonTypes.MAP.getClassName(), getGenericType(clazz, keyStatements), getGenericType(clazz, valueStatements)); + return create(CommonTypes.MAP.getClassName(), getGenericType(keyStatements), getGenericType(valueStatements)); } - public IType getGenericType(IClass clazz, List statements) { + public IType getGenericType(List statements) { // 如果没有元素,则返回Object类型 if (statements.size() == 0) { return CommonTypes.OBJECT; } IType genericType = null; for (Statement statement : statements) { - IType boxType = deducer.derive(clazz, statement).toBox(); + IType boxType = deducer.derive(statement).toBox(); if (genericType == null) { genericType = boxType; continue; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisiter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisiter.java index 959a73a3..d6b569f2 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisiter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisiter.java @@ -8,9 +8,9 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.core.api.ElementAction; import com.gitee.spirit.core.api.ElementVisiter; +import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.clazz.entity.IVariable; import com.gitee.spirit.core.compile.action.AbstractAppElementAction; -import com.gitee.spirit.core.compile.derivator.FragmentDeducer; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; @@ -22,7 +22,7 @@ public class DefaultElementVisiter implements ElementVisiter { @Autowired public List actions; @Autowired - public FragmentDeducer deducer; + public StatementDeducer deducer; @Override public IVariable visitElement(VisitContext context, Element element) { @@ -51,7 +51,7 @@ public class DefaultElementVisiter implements ElementVisiter { } else if (element.isReturn()) { Statement statement = element.subStmt(1, element.size()); IVariable variable = new IVariable(null); - variable.setType(deducer.derive(context.clazz, statement)); + variable.setType(deducer.derive(statement)); return variable; } return null; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java index 96ebb0c2..4c49e1f5 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java @@ -7,11 +7,10 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.core.api.ElementBuilder; import com.gitee.spirit.core.api.ElementVisiter; +import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.api.VariableTracker; -import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.clazz.entity.IVariable; -import com.gitee.spirit.core.compile.derivator.FragmentDeducer; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; @@ -28,7 +27,7 @@ public class ExpressDeclareAction extends AbstractAppElementAction { @Autowired public InvokeVisitAction invokeAction; @Autowired - public FragmentDeducer deducer; + public StatementDeducer deducer; @Autowired public ElementBuilder builder; @Autowired @@ -36,7 +35,6 @@ public class ExpressDeclareAction extends AbstractAppElementAction { @Override public void visitElement(VisitContext context, Element element) { - IClass clazz = context.clazz; if (element.isAssign()) {// text = "abc" Token varToken = element.get(0); // 如果是字段声明,则不用进行上下文推导 @@ -47,7 +45,7 @@ public class ExpressDeclareAction extends AbstractAppElementAction { Element subElement = new Element(statement); variableAction.visitElement(context, subElement); invokeAction.visitElement(context, subElement); - type = deducer.derive(clazz, statement); + type = deducer.derive(statement); // 标记类型是否经过推导而来 varToken.setAttr(Attribute.DERIVED, true); } @@ -58,13 +56,12 @@ public class ExpressDeclareAction extends AbstractAppElementAction { @Override public void visitMethodScope(VisitContext context, Element element) { - IClass clazz = context.clazz; if (element.isForIn()) {// for item in list { Statement statement = element.subStmt(3, element.size() - 1); Element subElement = new Element(statement); variableAction.visitElement(context, subElement); invokeAction.visitElement(context, subElement); - IType type = deducer.derive(clazz, statement); + IType type = deducer.derive(statement); // 获取数组内部类型和泛型类型 type = type.isArray() ? type.toTarget() : type.getGenericTypes().get(0); Token varToken = element.get(1); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java index c5594649..d41bf1d1 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java @@ -9,10 +9,10 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.core.api.ClassLinker; +import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.api.TypeFactory; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.compile.derivator.FragmentDeducer; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; @@ -26,7 +26,7 @@ public class InvokeVisitAction extends AbstractAppElementAction { @Autowired public TypeFactory factory; @Autowired - public FragmentDeducer deducer; + public StatementDeducer deducer; @Autowired public ClassLinker linker; @@ -40,13 +40,13 @@ public class InvokeVisitAction extends AbstractAppElementAction { if (token.attr(Attribute.TYPE) != null) { continue; } - List parameterTypes = token.isInvoke() ? getParameterTypes(clazz, token) : null; + List parameterTypes = token.isInvoke() ? getParameterTypes(token) : null; if (token.isType() || token.isArrayInit() || token.isTypeInit() || token.isCast() || token.isLiteral()) { token.setAttr(Attribute.TYPE, factory.create(clazz, token)); } else if (token.isSubexpress()) { Statement subStatement = token.getValue(); - token.setAttr(Attribute.TYPE, deducer.derive(clazz, subStatement.subStmt("(", ")"))); + token.setAttr(Attribute.TYPE, deducer.derive(subStatement.subStmt("(", ")"))); } else if (token.isVisitField()) { IType type = statement.get(index - 1).attr(Attribute.TYPE); @@ -78,13 +78,13 @@ public class InvokeVisitAction extends AbstractAppElementAction { }); } - public List getParameterTypes(IClass clazz, Token token) { + public List getParameterTypes(Token token) { List parameterTypes = new ArrayList<>(); Statement statement = token.getValue(); if (statement.size() > 3) { List subStatements = statement.subStmt(2, statement.size() - 1).splitStmt(","); for (Statement subStatement : subStatements) { - IType parameterType = deducer.derive(clazz, subStatement); + IType parameterType = deducer.derive(subStatement); parameterTypes.add(parameterType); } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/FragmentDeducer.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java similarity index 39% rename from spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/FragmentDeducer.java rename to spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java index 98ce6c69..3ba34fd4 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/FragmentDeducer.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java @@ -6,54 +6,42 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.api.TreeBuilder; -import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.element.entity.Node; import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; +import com.gitee.spirit.core.element.utils.NodeVisiter; + +import cn.hutool.core.lang.Assert; @Component -public class FragmentDeducer { +public class DefaultStatementDeducer implements StatementDeducer { @Autowired public TreeBuilder builder; - public IType derive(IClass clazz, Statement statement) { + @Override + public IType derive(Statement statement) { List nodes = builder.buildNodes(statement); - for (Node node : nodes) { - IType type = getTypeByNode(clazz, node); - if (type != null) { - return type; + IType type = (IType) NodeVisiter.forEachNode(nodes, node -> { + Token token = node.token; + if (token.attr(Attribute.TYPE) != null) { + return token.attr(Attribute.TYPE); } - } - throw new RuntimeException("Unhandled branch!"); - } - - public static IType getTypeByNode(IClass clazz, Node node) { - Token token = node.token; - - // 如果有类型直接返回 - if (token.attr(Attribute.TYPE) != null) { - return token.attr(Attribute.TYPE); - } + if (token.isLogical() || token.isRelation() || token.isInstanceof()) { + return CommonTypes.BOOLEAN; - // 如果是逻辑判断,或者类型判断关键字 - if (token.isLogical() || token.isRelation() || token.isInstanceof()) { - return CommonTypes.BOOLEAN; - - } else if (token.isArithmetic() || token.isBitwise()) { - // 先取左边的,再取右边的 - if (node.prev != null) { - return getTypeByNode(clazz, node.prev); - - } else if (node.next != null) { - return getTypeByNode(clazz, node.next); + } else if (token.isArithmetic() || token.isBitwise()) { + return ListUtils.toListNonNull(node.prev, node.next); } - } - - return null; + return null; + }); + Assert.notNull(type, "Type cannot be null!"); + return type; } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java index de5258cb..b5c18d0e 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java @@ -26,7 +26,7 @@ public class DefaultTreeBuilder extends AbstractTreeBuilder { public List buildNodes(List tokens) { final List nodes = new ArrayList<>(); ListUtils.visit(tokens, (index, token) -> { - if (token.hasSubStmt()) {// 嵌套语法树 + if (token.hasSubStmt()) { SyntaxTree syntaxTree = buildTree(token.getValue()); token = new Token(token.tokenType, syntaxTree, token.attributes); } @@ -56,8 +56,7 @@ public class DefaultTreeBuilder extends AbstractTreeBuilder { } } else if (currentToken.isOperator()) { - String value = currentToken.toString(); - OperatorEnum operator = OperatorEnum.getOperator(value); + OperatorEnum operator = OperatorEnum.getOperator(currentToken.toString()); priority = operator.priority; operand = operator.operand; @@ -84,7 +83,8 @@ public class DefaultTreeBuilder extends AbstractTreeBuilder { int index = priorityNode.item; Node node = nodes.get(index); Token currentToken = node.token; - resetOperandIfMultiple(nodes, index, currentToken);// 如果是多义的操作符,则进行判断后,确定真正的操作数 + // 如果是多义的操作符,则进行判断后,确定真正的操作数 + resetOperandIfMultiple(nodes, index, currentToken); OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); if (operandEnum == OperandEnum.LEFT) { @@ -118,7 +118,7 @@ public class DefaultTreeBuilder extends AbstractTreeBuilder { if (operandEnum == OperandEnum.MULTIPLE) { Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); String value = currentToken.toString(); - if (OperatorEnum.SUBTRACT.value.equals(value)) {// 100 + (-10) // var = -1 + if ("-".equals(value)) {// 100 + (-10) // var = -1 if (lastNode != null) { if (lastNode.isMounted() || (lastNode.token.isNumber() || lastNode.token.isVariable())) { currentToken.setAttr(Attribute.OPERAND, OperandEnum.BINARY); diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisiter.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisiter.java new file mode 100644 index 00000000..e341a310 --- /dev/null +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisiter.java @@ -0,0 +1,29 @@ +package com.gitee.spirit.core.element.utils; + +import java.util.List; + +import com.gitee.spirit.core.element.entity.Node; + +public class NodeVisiter { + + public static Object forEachNode(List nodes, Consumer consumer) { + for (Node node : nodes) { + Object result = forEachNode(node, consumer); + if (result != null) { + return result; + } + } + throw new RuntimeException("There is no return value!"); + } + + @SuppressWarnings("unchecked") + public static Object forEachNode(Node node, Consumer consumer) { + Object result = consumer.accept(node); + return result != null && result instanceof List ? forEachNode((List) result, consumer) : result; + } + + public static interface Consumer { + Object accept(T t); + } + +} diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java index ce97cf2b..a05b0f7b 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java @@ -5,9 +5,9 @@ import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; +import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.compile.derivator.FragmentDeducer; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; @@ -25,7 +25,7 @@ public abstract class AbstractTreeElementAction extends AbstractExtElementAction public static final String NEXT_TYPE = "NEXT_TYPE"; @Autowired - public FragmentDeducer deducer; + public StatementDeducer deducer; @Override public void visitElement(VisitContext context, Element element) { @@ -48,7 +48,7 @@ public abstract class AbstractTreeElementAction extends AbstractExtElementAction public void visitPrev(IClass clazz, Statement statement, int index, Token token, Map context) { int start = TreeUtils.findStart(statement, index); Statement prevStatement = statement.subStmt(start, index); - IType prevType = deducer.derive(clazz, prevStatement); + IType prevType = deducer.derive(prevStatement); context.put(START, start); context.put(PREV_STATEMENT, prevStatement); context.put(PREV_TYPE, prevType); @@ -58,7 +58,7 @@ public abstract class AbstractTreeElementAction extends AbstractExtElementAction public void visitNext(IClass clazz, Statement statement, int index, Token token, Map context) { int end = TreeUtils.findEnd(statement, index); Statement nextStatement = statement.subStmt(index + 1, end); - IType nextType = deducer.derive(clazz, nextStatement); + IType nextType = deducer.derive(nextStatement); context.put(END, end); context.put(NEXT_STATEMENT, nextStatement); context.put(NEXT_TYPE, nextType); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/StatementAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/StatementAction.java index 84658ef2..ad3098a8 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/StatementAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/StatementAction.java @@ -12,11 +12,11 @@ import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.common.enums.KeywordEnum; import com.gitee.spirit.common.enums.TokenTypeEnum; import com.gitee.spirit.core.api.ElementBuilder; +import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IField; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.compile.AutoImporter; -import com.gitee.spirit.core.compile.derivator.FragmentDeducer; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; @@ -31,7 +31,7 @@ public class StatementAction extends AbstractExtElementAction { @Autowired public ElementBuilder builder; @Autowired - public FragmentDeducer deducer; + public StatementDeducer deducer; @Autowired public AutoImporter importer; @@ -77,7 +77,7 @@ public class StatementAction extends AbstractExtElementAction { } else if (element.isIf() || element.isWhile()) {// if s { // while s { Statement statement = element.subStmt(1, element.size() - 1); - IType type = deducer.derive(clazz, statement); + IType type = deducer.derive(statement); if (TypeUtils.isString(type)) { String text = String.format("StringUtils.isNotEmpty(%s)", statement); element.replaceTokens(1, element.size() - 1, new Token(TokenTypeEnum.CUSTOM_EXPRESS, text)); @@ -95,10 +95,8 @@ public class StatementAction extends AbstractExtElementAction { if (clazz.getField("logger") == null) { clazz.addImport(Logger.class.getName()); clazz.addImport(LoggerFactory.class.getName()); - Element loggerElement = builder - .build("Logger logger = LoggerFactory.getLogger(" + clazz.getSimpleName() + ".class)"); - loggerElement.addModifiers(KeywordEnum.PUBLIC.value, KeywordEnum.STATIC.value, - JavaBuilder.FINAL_KEYWORD); + Element loggerElement = builder.build("Logger logger = LoggerFactory.getLogger(" + clazz.getSimpleName() + ".class)"); + loggerElement.addModifiers(KeywordEnum.PUBLIC.value, KeywordEnum.STATIC.value, JavaBuilder.FINAL_KEYWORD); IField field = new IField(new ArrayList<>(), loggerElement); clazz.fields.add(0, field); } -- Gitee From a71ac528d1c17298853c98168692a6ac66e181af Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Mon, 28 Jun 2021 16:47:21 +0800 Subject: [PATCH 30/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/spirit/common/utils/ListUtils.java | 2 +- .../compile/derivator/DefaultStatementDeducer.java | 2 +- .../gitee/spirit/core/lexer/action/RegionAction.java | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java index 74b1c9bf..44560259 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java @@ -10,7 +10,7 @@ import cn.hutool.core.lang.Assert; public class ListUtils { @SafeVarargs - public static List toListNonNull(T... items) { + public static List asListNonNull(T... items) { if (items == null || items.length == 0) { return new ArrayList(); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java index 3ba34fd4..ea6435eb 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java @@ -36,7 +36,7 @@ public class DefaultStatementDeducer implements StatementDeducer { return CommonTypes.BOOLEAN; } else if (token.isArithmetic() || token.isBitwise()) { - return ListUtils.toListNonNull(node.prev, node.next); + return ListUtils.asListNonNull(node.prev, node.next); } return null; }); diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java index b30beecb..7e8fb8db 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java @@ -51,20 +51,20 @@ public class RegionAction implements LexerAction { if (ch == '"') { Region region = RegionUtils.findRegion(builder, context.index, '"', '"'); - return pushStack(event, ListUtils.toListNonNull(region)); + return pushStack(event, ListUtils.asListNonNull(region)); } else if (ch == '\'') { Region region = RegionUtils.findRegion(builder, context.index, '\'', '\''); - return pushStack(event, ListUtils.toListNonNull(region)); + return pushStack(event, ListUtils.asListNonNull(region)); } else if (ch == '{') { Region region = RegionUtils.findRegion(builder, context.index, '{', '}'); - return pushStack(event, ListUtils.toListNonNull(region)); + return pushStack(event, ListUtils.asListNonNull(region)); } else if (ch == '(') { Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; Region region1 = RegionUtils.findRegion(builder, context.index, '(', ')'); - return pushStack(event, ListUtils.toListNonNull(region0, region1)); + return pushStack(event, ListUtils.asListNonNull(region0, region1)); } else if (ch == '[') { Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; @@ -81,13 +81,13 @@ public class RegionAction implements LexerAction { region2 = RegionUtils.findRegion(builder, region1.endIndex + 1, '{', '}'); } } - return pushStack(event, ListUtils.toListNonNull(region0, region1, region2)); + return pushStack(event, ListUtils.asListNonNull(region0, region1, region2)); } else if (ch == '<') { Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; Region region1 = RegionUtils.findRegion(builder, context.index, '<', '>'); Region region2 = isCharAt(builder, region1.endIndex, '(') ? RegionUtils.findRegion(builder, region1.endIndex, '(', ')') : null; - return pushStack(event, ListUtils.toListNonNull(region0, region1, region2)); + return pushStack(event, ListUtils.asListNonNull(region0, region1, region2)); } throw new RuntimeException("Unhandled branch!"); -- Gitee From 8a56b554fac3a0e2cd6c5882e6ab2c8fb15c35e8 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 29 Jun 2021 15:27:57 +0800 Subject: [PATCH 31/83] =?UTF-8?q?=E6=9B=B4=E6=94=B9ide=E4=B8=BAidea,?= =?UTF-8?q?=E5=B9=B6=E6=B7=BB=E5=8A=A0ignore=E9=85=8D=E7=BD=AE=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 131 ++++++++++++++++++ .../lib/spirit-code-tools-2.1.30.jar.asc | 14 -- 2 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 .gitignore delete mode 100644 spirit-tools/spirit-code-tools/spirit/lib/spirit-code-tools-2.1.30.jar.asc diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..14ba5ea7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,131 @@ +/.idea/.gitignore +/.idea/compiler.xml +/.idea/encodings.xml +/.idea/jarRepositories.xml +/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml +/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml +/.idea/libraries/Maven__cn_hutool_hutool_all_5_5_1.xml +/.idea/libraries/Maven__com_fasterxml_classmate_1_3_4.xml +/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_10_1.xml +/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_10_1.xml +/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_10_1.xml +/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_10_1.xml +/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_10_1.xml +/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_10_1.xml +/.idea/libraries/Maven__com_google_code_findbugs_jsr305_3_0_2.xml +/.idea/libraries/Maven__com_google_errorprone_error_prone_annotations_2_3_4.xml +/.idea/libraries/Maven__com_google_guava_failureaccess_1_0_1.xml +/.idea/libraries/Maven__com_google_guava_guava_29_0_jre.xml +/.idea/libraries/Maven__com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava.xml +/.idea/libraries/Maven__com_google_j2objc_j2objc_annotations_1_3.xml +/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_4_0.xml +/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml +/.idea/libraries/Maven__commons_io_commons_io_2_8_0.xml +/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_1.xml +/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml +/.idea/libraries/Maven__jakarta_validation_jakarta_validation_api_2_0_1.xml +/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_2.xml +/.idea/libraries/Maven__javax_annotation_jsr250_api_1_0.xml +/.idea/libraries/Maven__javax_enterprise_cdi_api_1_0.xml +/.idea/libraries/Maven__javax_inject_javax_inject_1.xml +/.idea/libraries/Maven__junit_junit_3_8_1.xml +/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_9_10.xml +/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_9_10.xml +/.idea/libraries/Maven__net_minidev_accessors_smart_1_2.xml +/.idea/libraries/Maven__net_minidev_json_smart_2_3.xml +/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_8_1.xml +/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_9.xml +/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_12_1.xml +/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_12_1.xml +/.idea/libraries/Maven__org_apache_maven_maven_aether_provider_3_0.xml +/.idea/libraries/Maven__org_apache_maven_maven_artifact_3_6_0.xml +/.idea/libraries/Maven__org_apache_maven_maven_core_3_0.xml +/.idea/libraries/Maven__org_apache_maven_maven_model_3_6_0.xml +/.idea/libraries/Maven__org_apache_maven_maven_model_builder_3_0.xml +/.idea/libraries/Maven__org_apache_maven_maven_plugin_api_3_6_0.xml +/.idea/libraries/Maven__org_apache_maven_maven_repository_metadata_3_0.xml +/.idea/libraries/Maven__org_apache_maven_maven_settings_3_0.xml +/.idea/libraries/Maven__org_apache_maven_maven_settings_builder_3_0.xml +/.idea/libraries/Maven__org_apache_maven_plugin_tools_maven_plugin_annotations_3_5.xml +/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_29.xml +/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_9_0_29.xml +/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_29.xml +/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml +/.idea/libraries/Maven__org_assertj_assertj_core_3_13_2.xml +/.idea/libraries/Maven__org_checkerframework_checker_qual_2_11_1.xml +/.idea/libraries/Maven__org_codehaus_plexus_plexus_classworlds_2_5_2.xml +/.idea/libraries/Maven__org_codehaus_plexus_plexus_component_annotations_1_5_5.xml +/.idea/libraries/Maven__org_codehaus_plexus_plexus_interpolation_1_14.xml +/.idea/libraries/Maven__org_codehaus_plexus_plexus_utils_3_1_0.xml +/.idea/libraries/Maven__org_eclipse_sisu_org_eclipse_sisu_inject_0_3_3.xml +/.idea/libraries/Maven__org_eclipse_sisu_org_eclipse_sisu_plexus_0_3_3.xml +/.idea/libraries/Maven__org_hamcrest_hamcrest_2_1.xml +/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_18_Final.xml +/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_2_Final.xml +/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_5_2.xml +/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_5_2.xml +/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_5_2.xml +/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_5_2.xml +/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_5_2.xml +/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_5_2.xml +/.idea/libraries/Maven__org_mockito_mockito_core_3_1_0.xml +/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_1_0.xml +/.idea/libraries/Maven__org_objenesis_objenesis_2_6.xml +/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml +/.idea/libraries/Maven__org_ow2_asm_asm_5_0_4.xml +/.idea/libraries/Maven__org_projectlombok_lombok_1_18_16.xml +/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml +/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_29.xml +/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_25.xml +/.idea/libraries/Maven__org_sonatype_aether_aether_api_1_7.xml +/.idea/libraries/Maven__org_sonatype_aether_aether_impl_1_7.xml +/.idea/libraries/Maven__org_sonatype_aether_aether_spi_1_7.xml +/.idea/libraries/Maven__org_sonatype_aether_aether_util_1_7.xml +/.idea/libraries/Maven__org_sonatype_plexus_plexus_cipher_1_4.xml +/.idea/libraries/Maven__org_sonatype_plexus_plexus_sec_dispatcher_1_3.xml +/.idea/libraries/Maven__org_sonatype_sisu_sisu_guice_noaop_2_1_7.xml +/.idea/libraries/Maven__org_sonatype_sisu_sisu_inject_bean_1_4_2.xml +/.idea/libraries/Maven__org_sonatype_sisu_sisu_inject_plexus_1_4_2.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_validation_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_aop_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_beans_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_context_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_core_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_expression_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_jcl_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_test_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_web_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_springframework_spring_webmvc_5_2_2_RELEASE.xml +/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_6_3.xml +/.idea/libraries/Maven__org_yaml_snakeyaml_1_25.xml +/.idea/misc.xml +/.idea/modules.xml +/spirit-tools/spirit-code-tools/spirit-code-tools.iml +/spirit-common/spirit-common.iml +/spirit-core/spirit-core.iml +/spirit-core/spirit-core-class/spirit-core-class.iml +/spirit-core/spirit-core-compile/spirit-core-compile.iml +/spirit-core/spirit-core-element/spirit-core-element.iml +/spirit-core/spirit-core-lexer/spirit-core-lexer.iml +/spirit-example/spirit-example.iml +/spirit-example/spirit-example-common/spirit-example-common.iml +/spirit-example/spirit-example-plugin/spirit-example-plugin.iml +/spirit-tools/spirit-maven-plugin/spirit-maven-plugin.iml +/spirit-output/spirit-output.iml +/spirit-output/spirit-output-java/spirit-output-java.iml +/spirit-parent.iml +/spirit-starter/spirit-starter.iml +/spirit-starter/spirit-starter-java/spirit-starter-java.iml +/spirit-stdlib/spirit-stdlib.iml +/spirit-tools/spirit-tools.iml +/.idea/vcs.xml diff --git a/spirit-tools/spirit-code-tools/spirit/lib/spirit-code-tools-2.1.30.jar.asc b/spirit-tools/spirit-code-tools/spirit/lib/spirit-code-tools-2.1.30.jar.asc deleted file mode 100644 index caf6f3f9..00000000 --- a/spirit-tools/spirit-code-tools/spirit/lib/spirit-code-tools-2.1.30.jar.asc +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQGzBAABCAAdFiEEqOc4k/2bIzSwX8nzS1qmeLEMVg4FAmClx6sACgkQS1qmeLEM -Vg4yNAwArJA1kdmxLSFxYqtva6vcqGzlast8XWT1PiJSsO0Wg+OVh5l+M6+AUEH/ -A78wDU7DGiKpdbkS45sJc5W1LDoS27UWBV7CtKogaetRJFypqLDri19fhnWxB8M+ -8mpgYbPLEqgzK6QJiB7r9kdxOf0ejl9gwEPIJSbb5igyNOiILJwzOyZXsnj9DcXr -EdhCyQ2JDXjugCgUQ3Kn/tMTpMIUWdzHZEjrQWh58GuQJwgffNULRul4FYfqjIra -4hcCnpn7MjWV6frzJSH1YFoRSBjWZsLKVm8IY840ZAlQgvqC2uiVySWSgCGOm9cX -I9tbZ/DMybtnO/71thrLQE1cyT6QFZ1y7gE5eC/FqPEsNWGa/fngY4i2oG8V+05h -iLqMrr0mH7eJy0srFJd6JzitkZyKZtYYzd220Yraruw0ZbP5DygG4NspE0EzJWY8 -+ERsssYG7nJXfC5931dAeTf9jsg+7TBXCfYIjcyMMvhb/nhXci/dFW/s27nYJNwE -h1NgDiAp -=GuoG ------END PGP SIGNATURE----- -- Gitee From b93c1899c94b0fa661c75d7c453ffbc3c9d309c5 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 29 Jun 2021 15:45:41 +0800 Subject: [PATCH 32/83] =?UTF-8?q?=E6=9B=B4=E6=94=B9ide=E4=B8=BAidea,?= =?UTF-8?q?=E5=B9=B6=E6=B7=BB=E5=8A=A0ignore=E9=85=8D=E7=BD=AE=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 14ba5ea7..6e65d52e 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,12 @@ /spirit-stdlib/spirit-stdlib.iml /spirit-tools/spirit-tools.iml /.idea/vcs.xml +/spirit-common/target/classes/com/gitee/spirit/common/ +/spirit-core/spirit-core-class/target/classes/com/gitee/spirit/core/ +/spirit-core/spirit-core-compile/target/classes/com/gitee/spirit/core/ +/spirit-core/spirit-core-element/target/ +/spirit-core/spirit-core-lexer/target/ +/spirit-tools/spirit-maven-plugin/target/classes/com/gitee/spirit/maven/plugin/ +/spirit-output/spirit-output-java/target/classes/com/gitee/spirit/output/java/ +/spirit-starter/spirit-starter-java/target/classes/ +/spirit-stdlib/target/classes/com/gitee/spirit/stdlib/ -- Gitee From 3a338c410a06ba209a49566b7e3d72e64cccb109 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 29 Jun 2021 17:07:16 +0800 Subject: [PATCH 33/83] =?UTF-8?q?=E6=9B=B4=E6=94=B9ide=E4=B8=BAidea,?= =?UTF-8?q?=E5=B9=B6=E6=B7=BB=E5=8A=A0ignore=E9=85=8D=E7=BD=AE=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/compile/AppClassLoader.java | 62 ++-- .../core/compile/AppImportSelector.java | 20 +- .../spirit/core/compile/AppTypeFactory.java | 264 +++++++++--------- .../derivator/DefaultStatementDeducer.java | 44 +-- 4 files changed, 195 insertions(+), 195 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppClassLoader.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppClassLoader.java index c44d4e0e..4a284237 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppClassLoader.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppClassLoader.java @@ -20,36 +20,36 @@ import com.gitee.spirit.core.clazz.entity.IClass; @DependsOn("configUtils") public class AppClassLoader extends AbstractURLClassLoader { - @Autowired - public Compiler compiler; - @Autowired - public AutoImporter importer; - @Autowired - public ClassVisiter visiter; - - @Override - public List getAllClasses() { - if (super.getAllClasses().size() == 0) { - List names = getNames(); - names.forEach(name -> loadClass(name)); - List classes = super.getAllClasses(); - visitClasses(classes); - return classes; - } - return super.getAllClasses(); - } - - @Override - public IClass defineClass(String name, URL resource) { - Map classes = compiler.compile(name, URLFileUtils.asStream(resource)); - this.classes.putAll(classes); - return classes.get(name); - } - - public void visitClasses(List classes) { - classes.forEach(clazz -> importer.autoImport(clazz)); - classes.forEach(clazz -> visiter.prepareForVisit(clazz)); - classes.forEach(clazz -> visiter.visitClass(clazz)); - } + @Autowired + public Compiler compiler; + @Autowired + public AutoImporter importer; + @Autowired + public ClassVisiter visitor; + + @Override + public List getAllClasses() { + if (super.getAllClasses().size() == 0) { + List names = getNames(); + names.forEach(this::loadClass); + List classes = super.getAllClasses(); + visitClasses(classes); + return classes; + } + return super.getAllClasses(); + } + + @Override + public IClass defineClass(String name, URL resource) { + Map classes = compiler.compile(name, URLFileUtils.asStream(resource)); + this.classes.putAll(classes); + return classes.get(name); + } + + public void visitClasses(List classes) { + classes.forEach(clazz -> importer.autoImport(clazz)); + classes.forEach(clazz -> visitor.prepareForVisit(clazz)); + classes.forEach(clazz -> visitor.visitClass(clazz)); + } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppImportSelector.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppImportSelector.java index 5a4861d3..20c27913 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppImportSelector.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppImportSelector.java @@ -11,17 +11,17 @@ import com.gitee.spirit.core.clazz.AbstractImportSelector; @Order(-100) public class AppImportSelector extends AbstractImportSelector { - @Autowired - public AppClassLoader loader; + @Autowired + public AppClassLoader loader; - @Override - public boolean canHandle(String className) { - return loader.contains(className); - } + @Override + public boolean canHandle(String className) { + return loader.contains(className); + } - @Override - public String findClassName(String simpleName) { - return ListUtils.findOne(loader.getNames(), className -> className.endsWith("." + simpleName)); - } + @Override + public String findClassName(String simpleName) { + return ListUtils.findOne(loader.getNames(), className -> className.endsWith("." + simpleName)); + } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java index 2f002920..0af214d1 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java @@ -26,137 +26,137 @@ import cn.hutool.core.lang.Assert; @Component public class AppTypeFactory extends AbstractTypeFactory { - @Autowired - public AppClassLoader classLoader; - @Autowired - public StatementDeducer deducer; - @Autowired - public TypeDerivator derivator; - - @Override - public IType create(String className) {// 一般来说,className可以直接反应出大部分属性 - IType type = new IType(); - type.setClassName(className); - type.setSimpleName(TypeUtils.getSimpleName(className)); - type.setTypeName(TypeUtils.getTypeName(className)); - type.setPrimitive(PrimitiveEnum.isPrimitive(className)); - type.setArray(TypeUtils.isArray(className)); - type.setNull(false); - type.setWildcard(false); - type.setNative(!classLoader.contains(TypeUtils.getTargetName(className))); - type.setModifiers(AccessLevelEnum.PUBLIC.value); - return type; - } - - @Override - public IType create(IClass clazz, Token token) { - if (token.isType()) { - return doCreate(clazz, token); - - } else if (token.isAnnotation() || token.isArrayInit() || token.isTypeInit() || token.isCast()) { - return create(clazz, (String) token.attr(Attribute.SIMPLE_NAME)); - - } else if (token.isLiteral()) {// 1, 1.1, "xxxx" - return getValueType(token); - } - return null; - } - - public IType doCreate(IClass clazz, Token token) { - if (token.value instanceof String) {// String // String[] //? //T,K - String simpleName = token.getValue(); - if ("?".equals(simpleName)) { - return CommonTypes.WILDCARD;// ? - } - if (clazz.getTypeVariableIndex(simpleName) >= 0) { - return createTypeVariable(simpleName);// T or K - } - return create(clazz.findClassName(simpleName)); - - } else if (token.value instanceof Statement) { - Statement statement = token.getValue(); // List // Class - String simpleName = statement.getStr(0); - IType type = create(clazz.findClassName(simpleName)); - type.setGenericTypes(getGenericTypes(clazz, statement)); - return type; - } - throw new RuntimeException("Unknown token value type!"); - } - - public List getGenericTypes(IClass clazz, Statement statement) { - List genericTypes = new ArrayList<>(); - for (int i = 1; i < statement.size(); i++) { - Token token = statement.get(i); - if (token.isType()) { - genericTypes.add(create(clazz, token)); - } - } - return genericTypes; - } - - public IType getValueType(Token token) { - if (token.isBoolean()) { - return CommonTypes.BOOLEAN; - } else if (token.isChar()) { - return CommonTypes.CHAR; - } else if (token.isInt()) { - return CommonTypes.INT; - } else if (token.isLong()) { - return CommonTypes.LONG; - } else if (token.isDouble()) { - return CommonTypes.DOUBLE; - } else if (token.isNull()) { - return CommonTypes.NULL; - } else if (token.isString()) { - return CommonTypes.STRING; - } else if (token.isList()) { - return getListType(token); - } else if (token.isMap()) { - return getMapType(token); - } - return null; - } - - public IType getListType(Token token) { - Statement statement = token.getValue(); - List statements = statement.subStmt(1, statement.size() - 1).splitStmt(","); - return create(CommonTypes.LIST.getClassName(), getGenericType(statements)); - } - - public IType getMapType(Token token) { - Statement statement = token.getValue(); - List keyStatements = new ArrayList<>(); - List valueStatements = new ArrayList<>(); - for (Statement subStatement : statement.subStmt(1, statement.size() - 1).splitStmt(",")) { - List subStatements = subStatement.splitStmt(":"); - keyStatements.add(subStatements.get(0)); - valueStatements.add(subStatements.get(1)); - } - return create(CommonTypes.MAP.getClassName(), getGenericType(keyStatements), getGenericType(valueStatements)); - } - - public IType getGenericType(List statements) { - // 如果没有元素,则返回Object类型 - if (statements.size() == 0) { - return CommonTypes.OBJECT; - } - IType genericType = null; - for (Statement statement : statements) { - IType boxType = deducer.derive(statement).toBox(); - if (genericType == null) { - genericType = boxType; - continue; - } - if (derivator.isMoreAbstract(boxType, genericType)) {// 更抽象则替换 - genericType = boxType; - - } else if (!derivator.isMoreAbstract(genericType, boxType)) {// 不同则使用Object - genericType = CommonTypes.OBJECT; - break; - } - } - Assert.notNull(genericType, "Generic type cannot be null!"); - return genericType; - } + @Autowired + public AppClassLoader classLoader; + @Autowired + public StatementDeducer deducer; + @Autowired + public TypeDerivator derivator; + + @Override + public IType create(String className) {// 一般来说,className可以直接反应出大部分属性 + IType type = new IType(); + type.setClassName(className); + type.setSimpleName(TypeUtils.getSimpleName(className)); + type.setTypeName(TypeUtils.getTypeName(className)); + type.setPrimitive(PrimitiveEnum.isPrimitive(className)); + type.setArray(TypeUtils.isArray(className)); + type.setNull(false); + type.setWildcard(false); + type.setNative(!classLoader.contains(TypeUtils.getTargetName(className))); + type.setModifiers(AccessLevelEnum.PUBLIC.value); + return type; + } + + @Override + public IType create(IClass clazz, Token token) { + if (token.isType()) { + return doCreate(clazz, token); + + } else if (token.isAnnotation() || token.isArrayInit() || token.isTypeInit() || token.isCast()) { + return create(clazz, (String) token.attr(Attribute.SIMPLE_NAME)); + + } else if (token.isLiteral()) {// 1, 1.1, "xxxx" + return getValueType(token); + } + return null; + } + + public IType doCreate(IClass clazz, Token token) { + if (token.value instanceof String) {// String // String[] //? //T,K + String simpleName = token.getValue(); + if ("?".equals(simpleName)) { + return CommonTypes.WILDCARD;// ? + } + if (clazz.getTypeVariableIndex(simpleName) >= 0) { + return createTypeVariable(simpleName);// T or K + } + return create(clazz.findClassName(simpleName)); + + } else if (token.value instanceof Statement) { + Statement statement = token.getValue(); // List // Class + String simpleName = statement.getStr(0); + IType type = create(clazz.findClassName(simpleName)); + type.setGenericTypes(getGenericTypes(clazz, statement)); + return type; + } + throw new RuntimeException("Unknown token value type!"); + } + + public List getGenericTypes(IClass clazz, Statement statement) { + List genericTypes = new ArrayList<>(); + for (int i = 1; i < statement.size(); i++) { + Token token = statement.get(i); + if (token.isType()) { + genericTypes.add(create(clazz, token)); + } + } + return genericTypes; + } + + public IType getValueType(Token token) { + if (token.isBoolean()) { + return CommonTypes.BOOLEAN; + } else if (token.isChar()) { + return CommonTypes.CHAR; + } else if (token.isInt()) { + return CommonTypes.INT; + } else if (token.isLong()) { + return CommonTypes.LONG; + } else if (token.isDouble()) { + return CommonTypes.DOUBLE; + } else if (token.isNull()) { + return CommonTypes.NULL; + } else if (token.isString()) { + return CommonTypes.STRING; + } else if (token.isList()) { + return getListType(token); + } else if (token.isMap()) { + return getMapType(token); + } + return null; + } + + public IType getListType(Token token) { + Statement statement = token.getValue(); + List statements = statement.subStmt(1, statement.size() - 1).splitStmt(","); + return create(CommonTypes.LIST.getClassName(), getGenericType(statements)); + } + + public IType getMapType(Token token) { + Statement statement = token.getValue(); + List keyStatements = new ArrayList<>(); + List valueStatements = new ArrayList<>(); + for (Statement subStatement : statement.subStmt(1, statement.size() - 1).splitStmt(",")) { + List subStatements = subStatement.splitStmt(":"); + keyStatements.add(subStatements.get(0)); + valueStatements.add(subStatements.get(1)); + } + return create(CommonTypes.MAP.getClassName(), getGenericType(keyStatements), getGenericType(valueStatements)); + } + + public IType getGenericType(List statements) { + // 如果没有元素,则返回Object类型 + if (statements.size() == 0) { + return CommonTypes.OBJECT; + } + IType genericType = null; + for (Statement statement : statements) { + IType boxType = deducer.derive(statement).toBox(); + if (genericType == null) { + genericType = boxType; + continue; + } + if (derivator.isMoreAbstract(boxType, genericType)) {// 更抽象则替换 + genericType = boxType; + + } else if (!derivator.isMoreAbstract(genericType, boxType)) {// 不同则使用Object + genericType = CommonTypes.OBJECT; + break; + } + } + Assert.notNull(genericType, "Generic type cannot be null!"); + return genericType; + } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java index ea6435eb..d095cf11 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java @@ -21,27 +21,27 @@ import cn.hutool.core.lang.Assert; @Component public class DefaultStatementDeducer implements StatementDeducer { - @Autowired - public TreeBuilder builder; - - @Override - public IType derive(Statement statement) { - List nodes = builder.buildNodes(statement); - IType type = (IType) NodeVisiter.forEachNode(nodes, node -> { - Token token = node.token; - if (token.attr(Attribute.TYPE) != null) { - return token.attr(Attribute.TYPE); - } - if (token.isLogical() || token.isRelation() || token.isInstanceof()) { - return CommonTypes.BOOLEAN; - - } else if (token.isArithmetic() || token.isBitwise()) { - return ListUtils.asListNonNull(node.prev, node.next); - } - return null; - }); - Assert.notNull(type, "Type cannot be null!"); - return type; - } + @Autowired + public TreeBuilder builder; + + @Override + public IType derive(Statement statement) { + List nodes = builder.buildNodes(statement); + IType type = (IType) NodeVisiter.forEachNode(nodes, node -> { + Token token = node.token; + if (token.attr(Attribute.TYPE) != null) { + return token.attr(Attribute.TYPE); + } + if (token.isLogical() || token.isRelation() || token.isInstanceof()) { + return CommonTypes.BOOLEAN; + + } else if (token.isArithmetic() || token.isBitwise()) { + return ListUtils.asListNonNull(node.prev, node.next); + } + return null; + }); + Assert.notNull(type, "Type cannot be null!"); + return type; + } } -- Gitee From 034f158fc3ca56c42934e724199a32ef5f50352d Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 29 Jun 2021 17:16:50 +0800 Subject: [PATCH 34/83] =?UTF-8?q?=E6=9B=B4=E6=94=B9ide=E4=B8=BAidea,?= =?UTF-8?q?=E5=B9=B6=E6=B7=BB=E5=8A=A0ignore=E9=85=8D=E7=BD=AE=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/compile/linker/AppClassLinker.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java index 461ccf7a..e8d832e8 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java @@ -26,7 +26,7 @@ public class AppClassLinker implements ClassLinker { @Autowired public AppClassLoader classLoader; @Autowired - public ClassVisiter visiter; + public ClassVisiter visitor; @Autowired public TypeDerivator derivator; @Autowired @@ -67,7 +67,7 @@ public class AppClassLinker implements ClassLinker { IClass clazz = toClass(type); IField field = clazz.getField(fieldName); if (field != null) { - return derivator.populate(type, visiter.visitMember(clazz, field)); + return derivator.populate(type, visitor.visitMember(clazz, field)); } return null; } @@ -78,7 +78,7 @@ public class AppClassLinker implements ClassLinker { List methods = clazz.getMethods(methodName); IMethod method = ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); if (method != null) { - return derivator.populate(type, visiter.visitMember(clazz, method)); + return derivator.populate(type, visitor.visitMember(clazz, method)); } return null; } -- Gitee From 9cbdeed769459fbf4886ea950030eb14d5c16e2a Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 30 Jun 2021 14:54:17 +0800 Subject: [PATCH 35/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9visiter=E4=B8=BAvisitor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../gitee/spirit/common/utils/ListUtils.java | 336 +++++++++--------- .../spirit/core/clazz/utils/TypeVisiter.java | 69 ---- .../spirit/core/clazz/utils/TypeVisitor.java | 69 ++++ .../{ClassVisiter.java => ClassVisitor.java} | 2 +- ...lementVisiter.java => ElementVisitor.java} | 22 +- .../spirit/core/compile/AppClassLoader.java | 4 +- .../spirit/core/compile/AutoImporter.java | 4 +- .../core/compile/DefaultClassVisiter.java | 181 ---------- .../core/compile/DefaultClassVisitor.java | 181 ++++++++++ ...isiter.java => DefaultElementVisitor.java} | 132 +++---- .../compile/action/ExpressDeclareAction.java | 6 +- .../compile/action/InvokeVisitAction.java | 4 +- .../compile/action/VariableTrackAction.java | 4 +- .../compile/derivator/AppTypeDerivator.java | 4 +- .../derivator/DefaultStatementDeducer.java | 4 +- .../core/compile/linker/AppClassLinker.java | 4 +- .../core/element/utils/NodeVisiter.java | 29 -- .../core/element/utils/NodeVisitor.java | 29 ++ .../core/element/utils/StmtVisiter.java | 28 -- .../core/element/utils/StmtVisitor.java | 28 ++ .../spirit/output/java/ExtTypeDerivator.java | 8 +- .../action/AbstractTreeElementAction.java | 4 +- .../output/java/action/CommonAction.java | 4 +- .../output/java/action/EmptyAction.java | 4 +- .../code/tools/core/ElementSelector.java | 6 +- 26 files changed, 584 insertions(+), 583 deletions(-) delete mode 100644 spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java create mode 100644 spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java rename spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/{ClassVisiter.java => ClassVisitor.java} (90%) rename spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/{ElementVisiter.java => ElementVisitor.java} (85%) delete mode 100644 spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisiter.java create mode 100644 spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java rename spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/{DefaultElementVisiter.java => DefaultElementVisitor.java} (91%) delete mode 100644 spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisiter.java create mode 100644 spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisitor.java delete mode 100644 spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java create mode 100644 spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisitor.java diff --git a/.gitignore b/.gitignore index 6e65d52e..3919d549 100644 --- a/.gitignore +++ b/.gitignore @@ -138,3 +138,4 @@ /spirit-output/spirit-output-java/target/classes/com/gitee/spirit/output/java/ /spirit-starter/spirit-starter-java/target/classes/ /spirit-stdlib/target/classes/com/gitee/spirit/stdlib/ +/.idea/uiDesigner.xml diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java index 44560259..0084271f 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java @@ -9,173 +9,173 @@ import cn.hutool.core.lang.Assert; public class ListUtils { - @SafeVarargs - public static List asListNonNull(T... items) { - if (items == null || items.length == 0) { - return new ArrayList(); - } - List list = new ArrayList(items.length); - for (T item : items) { - if (item != null) { - list.add(item); - } - } - return list; - } - - public static int indexOf(List list, int fromIndex, Matcher matcher) { - for (int index = fromIndex; index < list.size(); index++) { - T item = list.get(index); - if (matcher.accept(item)) { - return index; - } - } - return -1; - } - - public static int indexOf(List list, Matcher matcher) { - return indexOf(list, 0, matcher); - } - - public static int lastIndexOf(List list, Matcher matcher) { - int lastIndex = -1; - for (int index = 0; index < list.size(); index++) { - T item = list.get(index); - if (matcher.accept(item)) { - lastIndex = index > lastIndex ? index : lastIndex; - } - } - return lastIndex; - } - - public static void removeByIndex(List list, int fromIndex, int toIndex) { - for (int index = toIndex - 1; index >= fromIndex; index--) { - list.remove(index); - } - } - - public static T remove(List list, Matcher matcher) { - Iterator iterable = list.iterator(); - while (iterable.hasNext()) { - T item = iterable.next(); - if (matcher.accept(item)) { - iterable.remove(); - return item; - } - } - return null; - } - - public static T findOneByIndex(List list, int fromIndex, int toIndex, Matcher matcher) { - int step = toIndex >= fromIndex ? 1 : -1; - for (int index = fromIndex; index != toIndex; index += step) { - T item = list.get(index); - if (matcher.accept(item)) { - return item; - } - } - return null; - } - - public static T findOne(Iterable collection, Matcher matcher) { - return CollUtil.findOne(collection, item -> matcher.accept(item)); - } - - public static List findAll(List list, Matcher matcher) { - return CollUtil.filterNew(list, item -> matcher.accept(item)); - } - - public static T findOneByScore(Iterable collection, Selector selector) { - Integer maxScore = null; - T finalItem = null; - for (T item : collection) { - Integer score = selector.accept(item); - if (score != null) { - Assert.isFalse(maxScore != null && maxScore.intValue() == score.intValue(), "The score cannot be the same!"); - if (maxScore == null || score > maxScore) { - maxScore = score; - finalItem = item; - } - } - } - return finalItem; - } - - public static List filterStoppable(List list, Matcher matcher) { - List items = new ArrayList<>(); - Iterator iterable = list.iterator(); - while (iterable.hasNext()) { - T item = iterable.next(); - if (matcher.accept(item)) { - items.add(item); - iterable.remove(); - } else { - break; - } - } - return items; - } - - @SuppressWarnings("unchecked") - public static List filterStoppable(List list, Matcher matcher, Factory factory) { - List items = filterStoppable(list, matcher); - List list0 = new ArrayList<>(); - items.forEach(item -> list0.add((V) factory.accept(item))); - return list0; - } - - public static void visit(List list, Visiter visiter) { - for (int index = 0; index < list.size(); index++) { - visiter.accept(index, list.get(index)); - } - } - - @SuppressWarnings("unchecked") - public static V collectOne(List list, Factory factory) { - for (T item : list) { - Object object = factory.accept(item); - if (object != null) { - return (V) object; - } - } - return null; - } - - @SuppressWarnings("unchecked") - public static V collectOne(List list, Matcher matcher, Factory factory) { - for (T item : list) { - if (matcher.accept(item)) { - return (V) factory.accept(item); - } - } - return null; - } - - @SuppressWarnings("unchecked") - public static List collectAll(List list, Matcher matcher, Factory factory) { - List list0 = new ArrayList<>(); - for (T item : list) { - if (matcher.accept(item)) { - list0.add((V) factory.accept(item)); - } - } - return list0; - } - - public static interface Matcher { - boolean accept(T t); - } - - public static interface Factory { - Object accept(T t); - } - - public static interface Visiter { - void accept(int index, T t); - } - - public static interface Selector { - Integer accept(T t); - } + @SafeVarargs + public static List asListNonNull(T... items) { + if (items == null || items.length == 0) { + return new ArrayList<>(); + } + List list = new ArrayList<>(items.length); + for (T item : items) { + if (item != null) { + list.add(item); + } + } + return list; + } + + public static int indexOf(List list, int fromIndex, Matcher matcher) { + for (int index = fromIndex; index < list.size(); index++) { + T item = list.get(index); + if (matcher.accept(item)) { + return index; + } + } + return -1; + } + + public static int indexOf(List list, Matcher matcher) { + return indexOf(list, 0, matcher); + } + + public static int lastIndexOf(List list, Matcher matcher) { + int lastIndex = -1; + for (int index = 0; index < list.size(); index++) { + T item = list.get(index); + if (matcher.accept(item)) { + lastIndex = index > lastIndex ? index : lastIndex; + } + } + return lastIndex; + } + + public static void removeByIndex(List list, int fromIndex, int toIndex) { + for (int index = toIndex - 1; index >= fromIndex; index--) { + list.remove(index); + } + } + + public static T remove(List list, Matcher matcher) { + Iterator iterable = list.iterator(); + while (iterable.hasNext()) { + T item = iterable.next(); + if (matcher.accept(item)) { + iterable.remove(); + return item; + } + } + return null; + } + + public static T findOneByIndex(List list, int fromIndex, int toIndex, Matcher matcher) { + int step = toIndex >= fromIndex ? 1 : -1; + for (int index = fromIndex; index != toIndex; index += step) { + T item = list.get(index); + if (matcher.accept(item)) { + return item; + } + } + return null; + } + + public static T findOne(Iterable collection, Matcher matcher) { + return CollUtil.findOne(collection, item -> matcher.accept(item)); + } + + public static List findAll(List list, Matcher matcher) { + return CollUtil.filterNew(list, item -> matcher.accept(item)); + } + + public static T findOneByScore(Iterable collection, Selector selector) { + Integer maxScore = null; + T finalItem = null; + for (T item : collection) { + Integer score = selector.accept(item); + if (score != null) { + Assert.isFalse(maxScore != null && maxScore.intValue() == score.intValue(), "The score cannot be the same!"); + if (maxScore == null || score > maxScore) { + maxScore = score; + finalItem = item; + } + } + } + return finalItem; + } + + public static List filterStoppable(List list, Matcher matcher) { + List items = new ArrayList<>(); + Iterator iterable = list.iterator(); + while (iterable.hasNext()) { + T item = iterable.next(); + if (matcher.accept(item)) { + items.add(item); + iterable.remove(); + } else { + break; + } + } + return items; + } + + @SuppressWarnings("unchecked") + public static List filterStoppable(List list, Matcher matcher, Factory factory) { + List items = filterStoppable(list, matcher); + List list0 = new ArrayList<>(); + items.forEach(item -> list0.add((V) factory.accept(item))); + return list0; + } + + public static void visit(List list, Visitor visitor) { + for (int index = 0; index < list.size(); index++) { + visitor.accept(index, list.get(index)); + } + } + + @SuppressWarnings("unchecked") + public static V collectOne(List list, Factory factory) { + for (T item : list) { + Object object = factory.accept(item); + if (object != null) { + return (V) object; + } + } + return null; + } + + @SuppressWarnings("unchecked") + public static V collectOne(List list, Matcher matcher, Factory factory) { + for (T item : list) { + if (matcher.accept(item)) { + return (V) factory.accept(item); + } + } + return null; + } + + @SuppressWarnings("unchecked") + public static List collectAll(List list, Matcher matcher, Factory factory) { + List list0 = new ArrayList<>(); + for (T item : list) { + if (matcher.accept(item)) { + list0.add((V) factory.accept(item)); + } + } + return list0; + } + + public interface Matcher { + boolean accept(T t); + } + + public interface Factory { + Object accept(T t); + } + + public interface Visitor { + void accept(int index, T t); + } + + public interface Selector { + Integer accept(T t); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java deleted file mode 100644 index dc6e8559..00000000 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisiter.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.gitee.spirit.core.clazz.utils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.gitee.spirit.core.clazz.entity.IType; -import com.google.common.base.Joiner; - -import cn.hutool.core.lang.Assert; - -public class TypeVisiter { - - public static IType forEachType(IType targetType, Consumer consumer) { - Assert.notNull(targetType, "Target Type cannot be null!"); - // 拷贝一份 - IType newType = (IType) consumer.accept(TypeBuilder.copy(targetType)); - // 拷贝一份,注意不可修改集合 - List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); - for (int index = 0; index < newGenericTypes.size(); index++) { - IType genericType = forEachType(newGenericTypes.get(index), consumer); - if (genericType != null) { - newGenericTypes.set(index, genericType); - } - } - newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); - return newType; - } - - public static IType forEachType(IType referType, IType targetType, Consumer0 consumer) { - Assert.notNull(targetType, "Target Type cannot be null!"); - // 拷贝一份 - IType newType = (IType) consumer.accept(referType, TypeBuilder.copy(targetType)); - // 参考的泛型参数 - List referGenericTypes = referType.getGenericTypes(); - // 拷贝一份,注意不可修改集合 - List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); - for (int index = 0; index < newGenericTypes.size(); index++) { - IType genericType = forEachType(referGenericTypes.get(index), newGenericTypes.get(index), consumer); - if (genericType != null) { - newGenericTypes.set(index, genericType); - } - } - newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); - return newType; - } - - public static String forEachTypeName(IType targetType, Consumer consumer) { - Assert.notNull(targetType, "Target Type cannot be null!"); - String typeName = (String) consumer.accept(targetType); - if (targetType.isGenericType()) { - List typeNames = new ArrayList<>(); - for (IType genericType : targetType.getGenericTypes()) { - typeNames.add(forEachTypeName(genericType, consumer)); - } - typeName = typeName + "<" + Joiner.on(", ").join(typeNames) + ">"; - } - return typeName; - } - - public static interface Consumer { - Object accept(T t); - } - - public static interface Consumer0 { - Object accept(T t, T t1); - } - -} diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java new file mode 100644 index 00000000..b7bea972 --- /dev/null +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java @@ -0,0 +1,69 @@ +package com.gitee.spirit.core.clazz.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.gitee.spirit.core.clazz.entity.IType; +import com.google.common.base.Joiner; + +import cn.hutool.core.lang.Assert; + +public class TypeVisitor { + + public static IType forEachType(IType targetType, Consumer consumer) { + Assert.notNull(targetType, "Target Type cannot be null!"); + // 拷贝一份 + IType newType = (IType) consumer.accept(TypeBuilder.copy(targetType)); + // 拷贝一份,注意不可修改集合 + List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); + for (int index = 0; index < newGenericTypes.size(); index++) { + IType genericType = forEachType(newGenericTypes.get(index), consumer); + if (genericType != null) { + newGenericTypes.set(index, genericType); + } + } + newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); + return newType; + } + + public static IType forEachType(IType referType, IType targetType, Consumer0 consumer) { + Assert.notNull(targetType, "Target Type cannot be null!"); + // 拷贝一份 + IType newType = (IType) consumer.accept(referType, TypeBuilder.copy(targetType)); + // 参考的泛型参数 + List referGenericTypes = referType.getGenericTypes(); + // 拷贝一份,注意不可修改集合 + List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); + for (int index = 0; index < newGenericTypes.size(); index++) { + IType genericType = forEachType(referGenericTypes.get(index), newGenericTypes.get(index), consumer); + if (genericType != null) { + newGenericTypes.set(index, genericType); + } + } + newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); + return newType; + } + + public static String forEachTypeName(IType targetType, Consumer consumer) { + Assert.notNull(targetType, "Target Type cannot be null!"); + String typeName = (String) consumer.accept(targetType); + if (targetType.isGenericType()) { + List typeNames = new ArrayList<>(); + for (IType genericType : targetType.getGenericTypes()) { + typeNames.add(forEachTypeName(genericType, consumer)); + } + typeName = typeName + "<" + Joiner.on(", ").join(typeNames) + ">"; + } + return typeName; + } + + public interface Consumer { + Object accept(T t); + } + + public interface Consumer0 { + Object accept(T t, T t1); + } + +} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassVisiter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassVisitor.java similarity index 90% rename from spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassVisiter.java rename to spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassVisitor.java index 33038f35..228dfc1c 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassVisiter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassVisitor.java @@ -4,7 +4,7 @@ import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.clazz.frame.MemberEntity; -public interface ClassVisiter { +public interface ClassVisitor { void prepareForVisit(IClass clazz); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ElementVisiter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ElementVisitor.java similarity index 85% rename from spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ElementVisiter.java rename to spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ElementVisitor.java index 0a837a60..226262b1 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ElementVisiter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ElementVisitor.java @@ -1,11 +1,11 @@ -package com.gitee.spirit.core.api; - -import com.gitee.spirit.core.clazz.entity.IVariable; -import com.gitee.spirit.core.compile.entity.VisitContext; -import com.gitee.spirit.core.element.entity.Element; - -public interface ElementVisiter { - - IVariable visitElement(VisitContext context, Element element); - -} +package com.gitee.spirit.core.api; + +import com.gitee.spirit.core.clazz.entity.IVariable; +import com.gitee.spirit.core.compile.entity.VisitContext; +import com.gitee.spirit.core.element.entity.Element; + +public interface ElementVisitor { + + IVariable visitElement(VisitContext context, Element element); + +} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppClassLoader.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppClassLoader.java index 4a284237..96476db2 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppClassLoader.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppClassLoader.java @@ -10,7 +10,7 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import com.gitee.spirit.common.utils.URLFileUtils; -import com.gitee.spirit.core.api.ClassVisiter; +import com.gitee.spirit.core.api.ClassVisitor; import com.gitee.spirit.core.api.Compiler; import com.gitee.spirit.core.clazz.AbstractURLClassLoader; import com.gitee.spirit.core.clazz.entity.IClass; @@ -25,7 +25,7 @@ public class AppClassLoader extends AbstractURLClassLoader { @Autowired public AutoImporter importer; @Autowired - public ClassVisiter visitor; + public ClassVisitor visitor; @Override public List getAllClasses() { diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java index 4147d169..a3e9e1f2 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java @@ -15,7 +15,7 @@ import com.gitee.spirit.core.api.ElementBuilder; import com.gitee.spirit.core.api.SemanticParser; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.utils.TypeVisiter; +import com.gitee.spirit.core.clazz.utils.TypeVisitor; import com.gitee.spirit.core.element.entity.Element; @Component @@ -75,7 +75,7 @@ public class AutoImporter { } public String getFinalName(IClass clazz, IType type) { - return TypeVisiter.forEachTypeName(type, eachType -> { + return TypeVisitor.forEachTypeName(type, eachType -> { if (!clazz.addImport(eachType.getClassName())) { return eachType.getTypeName(); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisiter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisiter.java deleted file mode 100644 index 64fdc16d..00000000 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisiter.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.gitee.spirit.core.compile; - -import java.util.List; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.enums.TokenTypeEnum; -import com.gitee.spirit.common.utils.ListUtils; -import com.gitee.spirit.common.utils.ObjectUtils; -import com.gitee.spirit.core.api.ClassVisiter; -import com.gitee.spirit.core.api.ElementBuilder; -import com.gitee.spirit.core.api.ElementVisiter; -import com.gitee.spirit.core.api.TypeDerivator; -import com.gitee.spirit.core.api.TypeFactory; -import com.gitee.spirit.core.clazz.entity.IAnnotation; -import com.gitee.spirit.core.clazz.entity.IClass; -import com.gitee.spirit.core.clazz.entity.IField; -import com.gitee.spirit.core.clazz.entity.IMethod; -import com.gitee.spirit.core.clazz.entity.IParameter; -import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.clazz.entity.IVariable; -import com.gitee.spirit.core.clazz.frame.MemberEntity; -import com.gitee.spirit.core.clazz.utils.CommonTypes; -import com.gitee.spirit.core.compile.entity.VisitContext; -import com.gitee.spirit.core.element.entity.Element; -import com.gitee.spirit.core.element.entity.Statement; -import com.gitee.spirit.core.element.entity.Token; - -import cn.hutool.core.lang.Assert; - -@Component -public class DefaultClassVisiter implements ClassVisiter { - - @Autowired - public TypeFactory factory; - @Autowired - public ElementBuilder builder; - @Autowired - public ElementVisiter visiter; - @Autowired - public TypeDerivator derivator; - - @Override - public void prepareForVisit(IClass clazz) { - // 访问类型 - clazz.setType(factory.create(clazz, clazz.getTypeToken())); - // 访问方法入参 - clazz.methods.forEach(method -> visitParameters(clazz, method)); - } - - @Override - public void visitClass(IClass clazz) { - Assert.notNull(clazz.getType(), "Please invoke the method [prepareForVisit] first!"); - // 访问注解 - visitAnnotations(clazz, clazz.annotations); - clazz.fields.forEach(field -> visitAnnotations(clazz, field.annotations)); - clazz.methods.forEach(method -> visitAnnotations(clazz, method.annotations)); - // 访问成员 - clazz.fields.forEach(field -> visitMember(clazz, field)); - clazz.methods.forEach(method -> visitMember(clazz, method)); - } - - public void visitAnnotations(IClass clazz, List annotations) { - annotations.forEach(annotation -> annotation.setType(factory.create(clazz, annotation.token))); - } - - public void visitParameters(IClass clazz, IMethod method) { - // User() // invoke() - Token methodToken = method.element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); - Statement statement = methodToken.getValue(); - List statements = statement.subStmt("(", ")").splitStmt(","); - for (Statement parameterStmt : statements) { - List annotations = ListUtils.filterStoppable(parameterStmt, token -> token.isAnnotation(), token -> new IAnnotation(token)); - IParameter parameter = new IParameter(annotations, builder.build(parameterStmt)); - parameter.setType(factory.create(clazz, parameterStmt.get(0))); - method.parameters.add(parameter); - } - } - - @Override - public IType visitMember(IClass clazz, MemberEntity member) { - ObjectUtils.lock(member); // 防止循环依赖 - IType type = member.getType(); - if (type == null) { - if (member instanceof IField) { - type = visitField(clazz, (IField) member); - - } else if (member instanceof IMethod) { - type = visitMethod(clazz, (IMethod) member); - } - Assert.notNull(type, "Failed to derive member type!"); - member.setType(type); - } - ObjectUtils.unlock(member); - return type; - } - - public IType visitField(IClass clazz, IField field) { - IVariable variable = visiter.visitElement(new VisitContext(clazz, field), field.element); - return variable.getType(); - } - - public IType visitMethod(IClass clazz, IMethod method) { - // 方法上下文 - VisitContext context = new VisitContext(clazz, method); - // 访问方法体内容 - visitChildElements(context, method.element); - // 判断方法的语法 - if (method.element.isFunc()) { - return context.returnType != null ? context.returnType : CommonTypes.VOID; - - } else if (method.element.isDeclareFunc()) { - // 获取声明的类型 - IType declaredType = factory.create(clazz, method.element.get(0)); - // 如果这个方法有方法体 - if (method.element.hasChild()) { - IType returnType = context.returnType != null ? context.returnType : CommonTypes.VOID; - // 进行类型校验 - if (!derivator.isMoreAbstract(declaredType, returnType)) { - throw new RuntimeException("The derived type does not match the declared type!"); - } - } - // 最终返回声明的类型 - return declaredType; - } - throw new RuntimeException("Unsupported syntax!"); - } - - public void visitChildElements(VisitContext context, Element father) { - - // 遍历所有子元素 - List elements = father.children; - if (elements == null || elements.size() == 0) { - return; - } - - for (int index = 0; index < elements.size(); index++) { - Element element = elements.get(index); - // 提前将深度加一,以获得正确的blockId - if (element.children.size() > 0) { - context.increaseDepth(); - } - // 对该元素进行分析 - IVariable variable = visiter.visitElement(context, element); - // 如果该元素不是return语句,并且变量不为空,则将变量添加到上下文中 - if (!element.isReturn() && variable != null) { - variable.blockId = context.getBlockId(); - context.variables.add(variable); - - } else if (element.isReturn() && variable != null) { - // 如果上下文中还没有返回类型,则将变量的类型,作为返回类型 - if (context.returnType == null) { - context.returnType = variable.getType(); - } else { - // 如果有多个返回类型,则使用最抽象的那个 - if (!variable.getType().isNull()) { - // 注意:任何类型都是null的抽象,null不能是任何类型的抽象 - if (derivator.isMoreAbstract(variable.getType(), context.returnType)) { - context.returnType = variable.getType(); - } else { - context.returnType = CommonTypes.OBJECT; - } - } - } - } - - // 如果return语句后面还有语句,则抛出异常 - if (element.isReturn() && index != elements.size() - 1) { - throw new RuntimeException("The method body does not end with a return statement!"); - } - - // 遍历子节点 - if (element.children.size() > 0) { - visitChildElements(context, element); - context.increaseCount(); - context.decreaseDepth(); - } - } - } -} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java new file mode 100644 index 00000000..0593f0f9 --- /dev/null +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java @@ -0,0 +1,181 @@ +package com.gitee.spirit.core.compile; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.enums.TokenTypeEnum; +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.common.utils.ObjectUtils; +import com.gitee.spirit.core.api.ClassVisitor; +import com.gitee.spirit.core.api.ElementBuilder; +import com.gitee.spirit.core.api.ElementVisitor; +import com.gitee.spirit.core.api.TypeDerivator; +import com.gitee.spirit.core.api.TypeFactory; +import com.gitee.spirit.core.clazz.entity.IAnnotation; +import com.gitee.spirit.core.clazz.entity.IClass; +import com.gitee.spirit.core.clazz.entity.IField; +import com.gitee.spirit.core.clazz.entity.IMethod; +import com.gitee.spirit.core.clazz.entity.IParameter; +import com.gitee.spirit.core.clazz.entity.IType; +import com.gitee.spirit.core.clazz.entity.IVariable; +import com.gitee.spirit.core.clazz.frame.MemberEntity; +import com.gitee.spirit.core.clazz.utils.CommonTypes; +import com.gitee.spirit.core.compile.entity.VisitContext; +import com.gitee.spirit.core.element.entity.Element; +import com.gitee.spirit.core.element.entity.Statement; +import com.gitee.spirit.core.element.entity.Token; + +import cn.hutool.core.lang.Assert; + +@Component +public class DefaultClassVisitor implements ClassVisitor { + + @Autowired + public TypeFactory factory; + @Autowired + public ElementBuilder builder; + @Autowired + public ElementVisitor visitor; + @Autowired + public TypeDerivator derivator; + + @Override + public void prepareForVisit(IClass clazz) { + // 访问类型 + clazz.setType(factory.create(clazz, clazz.getTypeToken())); + // 访问方法入参 + clazz.methods.forEach(method -> visitParameters(clazz, method)); + } + + @Override + public void visitClass(IClass clazz) { + Assert.notNull(clazz.getType(), "Please invoke the method [prepareForVisit] first!"); + // 访问注解 + visitAnnotations(clazz, clazz.annotations); + clazz.fields.forEach(field -> visitAnnotations(clazz, field.annotations)); + clazz.methods.forEach(method -> visitAnnotations(clazz, method.annotations)); + // 访问成员 + clazz.fields.forEach(field -> visitMember(clazz, field)); + clazz.methods.forEach(method -> visitMember(clazz, method)); + } + + public void visitAnnotations(IClass clazz, List annotations) { + annotations.forEach(annotation -> annotation.setType(factory.create(clazz, annotation.token))); + } + + public void visitParameters(IClass clazz, IMethod method) { + // User() // invoke() + Token methodToken = method.element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); + Statement statement = methodToken.getValue(); + List statements = statement.subStmt("(", ")").splitStmt(","); + for (Statement parameterStmt : statements) { + List annotations = ListUtils.filterStoppable(parameterStmt, token -> token.isAnnotation(), token -> new IAnnotation(token)); + IParameter parameter = new IParameter(annotations, builder.build(parameterStmt)); + parameter.setType(factory.create(clazz, parameterStmt.get(0))); + method.parameters.add(parameter); + } + } + + @Override + public IType visitMember(IClass clazz, MemberEntity member) { + ObjectUtils.lock(member); // 防止循环依赖 + IType type = member.getType(); + if (type == null) { + if (member instanceof IField) { + type = visitField(clazz, (IField) member); + + } else if (member instanceof IMethod) { + type = visitMethod(clazz, (IMethod) member); + } + Assert.notNull(type, "Failed to derive member type!"); + member.setType(type); + } + ObjectUtils.unlock(member); + return type; + } + + public IType visitField(IClass clazz, IField field) { + IVariable variable = visitor.visitElement(new VisitContext(clazz, field), field.element); + return variable.getType(); + } + + public IType visitMethod(IClass clazz, IMethod method) { + // 方法上下文 + VisitContext context = new VisitContext(clazz, method); + // 访问方法体内容 + visitChildElements(context, method.element); + // 判断方法的语法 + if (method.element.isFunc()) { + return context.returnType != null ? context.returnType : CommonTypes.VOID; + + } else if (method.element.isDeclareFunc()) { + // 获取声明的类型 + IType declaredType = factory.create(clazz, method.element.get(0)); + // 如果这个方法有方法体 + if (method.element.hasChild()) { + IType returnType = context.returnType != null ? context.returnType : CommonTypes.VOID; + // 进行类型校验 + if (!derivator.isMoreAbstract(declaredType, returnType)) { + throw new RuntimeException("The derived type does not match the declared type!"); + } + } + // 最终返回声明的类型 + return declaredType; + } + throw new RuntimeException("Unsupported syntax!"); + } + + public void visitChildElements(VisitContext context, Element father) { + + // 遍历所有子元素 + List elements = father.children; + if (elements == null || elements.size() == 0) { + return; + } + + for (int index = 0; index < elements.size(); index++) { + Element element = elements.get(index); + // 提前将深度加一,以获得正确的blockId + if (element.children.size() > 0) { + context.increaseDepth(); + } + // 对该元素进行分析 + IVariable variable = visitor.visitElement(context, element); + // 如果该元素不是return语句,并且变量不为空,则将变量添加到上下文中 + if (!element.isReturn() && variable != null) { + variable.blockId = context.getBlockId(); + context.variables.add(variable); + + } else if (element.isReturn() && variable != null) { + // 如果上下文中还没有返回类型,则将变量的类型,作为返回类型 + if (context.returnType == null) { + context.returnType = variable.getType(); + } else { + // 如果有多个返回类型,则使用最抽象的那个 + if (!variable.getType().isNull()) { + // 注意:任何类型都是null的抽象,null不能是任何类型的抽象 + if (derivator.isMoreAbstract(variable.getType(), context.returnType)) { + context.returnType = variable.getType(); + } else { + context.returnType = CommonTypes.OBJECT; + } + } + } + } + + // 如果return语句后面还有语句,则抛出异常 + if (element.isReturn() && index != elements.size() - 1) { + throw new RuntimeException("The method body does not end with a return statement!"); + } + + // 遍历子节点 + if (element.children.size() > 0) { + visitChildElements(context, element); + context.increaseCount(); + context.decreaseDepth(); + } + } + } +} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisiter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisitor.java similarity index 91% rename from spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisiter.java rename to spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisitor.java index d6b569f2..4e5dfba6 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisiter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisitor.java @@ -1,66 +1,66 @@ -package com.gitee.spirit.core.compile; - -import java.util.List; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.constants.Attribute; -import com.gitee.spirit.core.api.ElementAction; -import com.gitee.spirit.core.api.ElementVisiter; -import com.gitee.spirit.core.api.StatementDeducer; -import com.gitee.spirit.core.clazz.entity.IVariable; -import com.gitee.spirit.core.compile.action.AbstractAppElementAction; -import com.gitee.spirit.core.compile.entity.VisitContext; -import com.gitee.spirit.core.element.entity.Element; -import com.gitee.spirit.core.element.entity.Statement; -import com.gitee.spirit.core.element.entity.Token; - -@Component -public class DefaultElementVisiter implements ElementVisiter { - - @Autowired - public List actions; - @Autowired - public StatementDeducer deducer; - - @Override - public IVariable visitElement(VisitContext context, Element element) { - try { - for (ElementAction action : actions) { - action.visitElement(context, element); - } - return getVariableIfPossible(context, element); - - } catch (Exception e) { - element.debug(); - throw new RuntimeException("Failed to derive element!", e); - } - } - - public IVariable getVariableIfPossible(VisitContext context, Element element) { - if (element.isAssign()) { - return createVariable(element.get(0)); - - } else if (element.isDeclare() || element.isDeclareAssign() || element.isForIn()) { - return createVariable(element.get(1)); - - } else if (element.isCatch()) { - return createVariable(element.get(3)); - - } else if (element.isReturn()) { - Statement statement = element.subStmt(1, element.size()); - IVariable variable = new IVariable(null); - variable.setType(deducer.derive(statement)); - return variable; - } - return null; - } - - public IVariable createVariable(Token varToken) { - IVariable variable = new IVariable(varToken); - variable.setType(varToken.attr(Attribute.TYPE)); - return variable; - } - -} +package com.gitee.spirit.core.compile; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.constants.Attribute; +import com.gitee.spirit.core.api.ElementAction; +import com.gitee.spirit.core.api.ElementVisitor; +import com.gitee.spirit.core.api.StatementDeducer; +import com.gitee.spirit.core.clazz.entity.IVariable; +import com.gitee.spirit.core.compile.action.AbstractAppElementAction; +import com.gitee.spirit.core.compile.entity.VisitContext; +import com.gitee.spirit.core.element.entity.Element; +import com.gitee.spirit.core.element.entity.Statement; +import com.gitee.spirit.core.element.entity.Token; + +@Component +public class DefaultElementVisitor implements ElementVisitor { + + @Autowired + public List actions; + @Autowired + public StatementDeducer deducer; + + @Override + public IVariable visitElement(VisitContext context, Element element) { + try { + for (ElementAction action : actions) { + action.visitElement(context, element); + } + return getVariableIfPossible(context, element); + + } catch (Exception e) { + element.debug(); + throw new RuntimeException("Failed to derive element!", e); + } + } + + public IVariable getVariableIfPossible(VisitContext context, Element element) { + if (element.isAssign()) { + return createVariable(element.get(0)); + + } else if (element.isDeclare() || element.isDeclareAssign() || element.isForIn()) { + return createVariable(element.get(1)); + + } else if (element.isCatch()) { + return createVariable(element.get(3)); + + } else if (element.isReturn()) { + Statement statement = element.subStmt(1, element.size()); + IVariable variable = new IVariable(null); + variable.setType(deducer.derive(statement)); + return variable; + } + return null; + } + + public IVariable createVariable(Token varToken) { + IVariable variable = new IVariable(varToken); + variable.setType(varToken.attr(Attribute.TYPE)); + return variable; + } + +} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java index 4c49e1f5..a6f399af 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.core.api.ElementBuilder; -import com.gitee.spirit.core.api.ElementVisiter; +import com.gitee.spirit.core.api.ElementVisitor; import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.api.VariableTracker; import com.gitee.spirit.core.clazz.entity.IType; @@ -31,7 +31,7 @@ public class ExpressDeclareAction extends AbstractAppElementAction { @Autowired public ElementBuilder builder; @Autowired - public ElementVisiter visiter; + public ElementVisitor visitor; @Override public void visitElement(VisitContext context, Element element) { @@ -74,7 +74,7 @@ public class ExpressDeclareAction extends AbstractAppElementAction { Statement subStatement = statement.subStmt(1, statement.indexOf(";")); if (subStatement.size() > 0) { Element subElement = builder.build(subStatement); - IVariable variable = visiter.visitElement(context, subElement); + IVariable variable = visitor.visitElement(context, subElement); if (variable != null) { variable.blockId = context.getBlockId(); context.variables.add(variable); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java index d41bf1d1..67229a52 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java @@ -17,7 +17,7 @@ import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; -import com.gitee.spirit.core.element.utils.StmtVisiter; +import com.gitee.spirit.core.element.utils.StmtVisitor; @Component @Order(-40) @@ -33,7 +33,7 @@ public class InvokeVisitAction extends AbstractAppElementAction { @Override public void visitElement(VisitContext context, Element element) { IClass clazz = context.clazz; - StmtVisiter.forEachStmt(element, statement -> { + StmtVisitor.forEachStmt(element, statement -> { for (int index = 0; index < statement.size(); index++) { try { Token token = statement.get(index); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/VariableTrackAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/VariableTrackAction.java index cfcf4532..e374063b 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/VariableTrackAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/VariableTrackAction.java @@ -10,7 +10,7 @@ import com.gitee.spirit.core.api.VariableTracker; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; -import com.gitee.spirit.core.element.utils.StmtVisiter; +import com.gitee.spirit.core.element.utils.StmtVisitor; import cn.hutool.core.lang.Assert; @@ -23,7 +23,7 @@ public class VariableTrackAction extends AbstractAppElementAction { @Override public void visitElement(VisitContext context, Element element) { - StmtVisiter.forEachToken(element, token -> { + StmtVisitor.forEachToken(element, token -> { if (token.attr(Attribute.TYPE) != null) { return; } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 40056ec5..2119c38b 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -8,7 +8,7 @@ import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.TypeDerivator; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.clazz.utils.TypeBuilder; -import com.gitee.spirit.core.clazz.utils.TypeVisiter; +import com.gitee.spirit.core.clazz.utils.TypeVisitor; import cn.hutool.core.lang.Assert; @@ -59,7 +59,7 @@ public class AppTypeDerivator implements TypeDerivator { @Override public IType populate(IType instanceType, IType targetType) { // 根据全局类型,进行填充 - return TypeVisiter.forEachType(targetType, eachType -> { + return TypeVisitor.forEachType(targetType, eachType -> { if (eachType.isTypeVariable()) { int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); Assert.isTrue(index >= 0, "Index of type variable less than 0!"); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java index d095cf11..6c960cf5 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/DefaultStatementDeducer.java @@ -14,7 +14,7 @@ import com.gitee.spirit.core.clazz.utils.CommonTypes; import com.gitee.spirit.core.element.entity.Node; import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; -import com.gitee.spirit.core.element.utils.NodeVisiter; +import com.gitee.spirit.core.element.utils.NodeVisitor; import cn.hutool.core.lang.Assert; @@ -27,7 +27,7 @@ public class DefaultStatementDeducer implements StatementDeducer { @Override public IType derive(Statement statement) { List nodes = builder.buildNodes(statement); - IType type = (IType) NodeVisiter.forEachNode(nodes, node -> { + IType type = (IType) NodeVisitor.forEachNode(nodes, node -> { Token token = node.token; if (token.attr(Attribute.TYPE) != null) { return token.attr(Attribute.TYPE); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java index e8d832e8..7c05857f 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.core.api.ClassLinker; -import com.gitee.spirit.core.api.ClassVisiter; +import com.gitee.spirit.core.api.ClassVisitor; import com.gitee.spirit.core.api.TypeDerivator; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IField; @@ -26,7 +26,7 @@ public class AppClassLinker implements ClassLinker { @Autowired public AppClassLoader classLoader; @Autowired - public ClassVisiter visitor; + public ClassVisitor visitor; @Autowired public TypeDerivator derivator; @Autowired diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisiter.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisiter.java deleted file mode 100644 index e341a310..00000000 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisiter.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gitee.spirit.core.element.utils; - -import java.util.List; - -import com.gitee.spirit.core.element.entity.Node; - -public class NodeVisiter { - - public static Object forEachNode(List nodes, Consumer consumer) { - for (Node node : nodes) { - Object result = forEachNode(node, consumer); - if (result != null) { - return result; - } - } - throw new RuntimeException("There is no return value!"); - } - - @SuppressWarnings("unchecked") - public static Object forEachNode(Node node, Consumer consumer) { - Object result = consumer.accept(node); - return result != null && result instanceof List ? forEachNode((List) result, consumer) : result; - } - - public static interface Consumer { - Object accept(T t); - } - -} diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisitor.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisitor.java new file mode 100644 index 00000000..91558a90 --- /dev/null +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/NodeVisitor.java @@ -0,0 +1,29 @@ +package com.gitee.spirit.core.element.utils; + +import java.util.List; + +import com.gitee.spirit.core.element.entity.Node; + +public class NodeVisitor { + + public static Object forEachNode(List nodes, Consumer consumer) { + for (Node node : nodes) { + Object result = forEachNode(node, consumer); + if (result != null) { + return result; + } + } + throw new RuntimeException("There is no return value!"); + } + + @SuppressWarnings("unchecked") + public static Object forEachNode(Node node, Consumer consumer) { + Object result = consumer.accept(node); + return result instanceof List ? forEachNode((List) result, consumer) : result; + } + + public interface Consumer { + Object accept(T t); + } + +} diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java deleted file mode 100644 index 729160d1..00000000 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisiter.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gitee.spirit.core.element.utils; - -import java.util.function.Consumer; - -import com.gitee.spirit.core.element.entity.Statement; -import com.gitee.spirit.core.element.entity.Token; - -public class StmtVisiter { - - public static void forEachStmt(Statement statement, Consumer consumer) { - for (Token token : statement) { - if (token.hasSubStmt()) { - forEachStmt(token.getValue(), consumer); - } - } - consumer.accept(statement); - } - - public static void forEachToken(Statement statement, Consumer consumer) { - for (Token token : statement) { - if (token.hasSubStmt()) { - forEachToken(token.getValue(), consumer); - } - consumer.accept(token); - } - } - -} diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisitor.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisitor.java new file mode 100644 index 00000000..e5e525cd --- /dev/null +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/utils/StmtVisitor.java @@ -0,0 +1,28 @@ +package com.gitee.spirit.core.element.utils; + +import java.util.function.Consumer; + +import com.gitee.spirit.core.element.entity.Statement; +import com.gitee.spirit.core.element.entity.Token; + +public class StmtVisitor { + + public static void forEachStmt(Statement statement, Consumer consumer) { + for (Token token : statement) { + if (token.hasSubStmt()) { + forEachStmt(token.getValue(), consumer); + } + } + consumer.accept(statement); + } + + public static void forEachToken(Statement statement, Consumer consumer) { + for (Token token : statement) { + if (token.hasSubStmt()) { + forEachToken(token.getValue(), consumer); + } + consumer.accept(token); + } + } + +} diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java index eddb45b3..56b751af 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.clazz.utils.TypeBuilder; -import com.gitee.spirit.core.clazz.utils.TypeVisiter; +import com.gitee.spirit.core.clazz.utils.TypeVisitor; import com.gitee.spirit.core.compile.derivator.AppTypeDerivator; @Component @@ -20,7 +20,7 @@ public class ExtTypeDerivator extends AppTypeDerivator { @Override public IType populate(IType type, IType targetType) {// 根据全局类型,进行填充 - return TypeVisiter.forEachType(targetType, eachType -> { + return TypeVisitor.forEachType(targetType, eachType -> { if (eachType.isTypeVariable()) { int index = linker.getTypeVariableIndex(type, eachType.getGenericName()); if (index >= 0) { @@ -45,7 +45,7 @@ public class ExtTypeDerivator extends AppTypeDerivator { } public IType populateQualifying(IType parameterType, IType targetType, Map qualifyingTypes) { - return TypeVisiter.forEachType(parameterType, targetType, (referType, eachType) -> { + return TypeVisitor.forEachType(parameterType, targetType, (referType, eachType) -> { if (eachType.isTypeVariable()) { String genericName = eachType.getGenericName(); if (qualifyingTypes.containsKey(genericName)) {// 如果已经存在了,则必须统一 @@ -75,7 +75,7 @@ public class ExtTypeDerivator extends AppTypeDerivator { } public IType populateReturnType(Map qualifyingTypes, IType targetType) { - return TypeVisiter.forEachType(targetType, eachType -> { + return TypeVisitor.forEachType(targetType, eachType -> { if (eachType.isTypeVariable()) { return qualifyingTypes.get(targetType.getGenericName()); } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java index a05b0f7b..fc60fe0d 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/AbstractTreeElementAction.java @@ -12,7 +12,7 @@ import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; -import com.gitee.spirit.core.element.utils.StmtVisiter; +import com.gitee.spirit.core.element.utils.StmtVisitor; import com.gitee.spirit.output.java.utils.TreeUtils; public abstract class AbstractTreeElementAction extends AbstractExtElementAction { @@ -29,7 +29,7 @@ public abstract class AbstractTreeElementAction extends AbstractExtElementAction @Override public void visitElement(VisitContext context, Element element) { - StmtVisiter.forEachStmt(element, statement -> { + StmtVisitor.forEachStmt(element, statement -> { for (int index = 0; index < statement.size(); index++) { Token token = statement.get(index); if (isTrigger(token)) { diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java index 56208162..f59789cf 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java @@ -9,7 +9,7 @@ import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Statement; import com.gitee.spirit.core.element.entity.Token; -import com.gitee.spirit.core.element.utils.StmtVisiter; +import com.gitee.spirit.core.element.utils.StmtVisitor; import com.gitee.spirit.stdlib.Lists; import com.gitee.spirit.stdlib.Maps; @@ -20,7 +20,7 @@ public class CommonAction extends AbstractExtElementAction { @Override public void visitElement(VisitContext context, Element element) { IClass clazz = context.clazz; - StmtVisiter.forEachToken(element, token -> { + StmtVisitor.forEachToken(element, token -> { if (token.isArrayInit()) {// String[10] => new String[10] Statement subStatement = token.getValue(); subStatement.add(0, new Token(TokenTypeEnum.KEYWORD, "new")); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java index 7a9fbbbd..ca68bd6e 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java @@ -7,7 +7,7 @@ import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.common.enums.KeywordEnum; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; -import com.gitee.spirit.core.element.utils.StmtVisiter; +import com.gitee.spirit.core.element.utils.StmtVisitor; import com.gitee.spirit.stdlib.Emptys; @Component @@ -16,7 +16,7 @@ public class EmptyAction extends AbstractExtElementAction { @Override public void visitElement(VisitContext context, Element element) { - StmtVisiter.forEachToken(element, token -> { + StmtVisitor.forEachToken(element, token -> { if (token.isLocalMethod()) {// empty(str) if (KeywordEnum.EMPTY.value.equals(token.attr(Attribute.MEMBER_NAME))) { context.clazz.addStaticImport(Emptys.class.getName() + ".empty"); diff --git a/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java b/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java index df900b83..5771c741 100644 --- a/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java +++ b/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java @@ -5,7 +5,7 @@ import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.gitee.spirit.core.api.ElementVisiter; +import com.gitee.spirit.core.api.ElementVisitor; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.compile.CoreCompiler; @@ -15,13 +15,13 @@ import com.gitee.spirit.core.element.entity.Element; public class ElementSelector extends CoreCompiler { @Autowired - public ElementVisiter visiter; + public ElementVisitor visitor; public IType findElementAndGetType(IClass clazz, Integer lineNumber) { // TODO // Element element = findElement(Arrays.asList(clazz.element), lineNumber); // if (element != null) { -// IVariable variable = visiter.getVariableIfPossible(clazz, element); +// IVariable variable = visitor.getVariableIfPossible(clazz, element); // return variable.getType(); // } return null; -- Gitee From 8ee0e909cfea0d493539cf13aee50ef0349bf8cd Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 30 Jun 2021 15:21:50 +0800 Subject: [PATCH 36/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/common/utils/ListUtils.java | 10 +- .../spirit/core/clazz/utils/TypeVisitor.java | 8 +- .../spirit/core/compile/AutoImporter.java | 115 ++++++++---------- .../core/compile/DefaultClassVisitor.java | 3 +- .../core/compile/linker/AppClassLinker.java | 106 ++++++++-------- .../code/tools/core/ElementSelector.java | 3 +- 6 files changed, 116 insertions(+), 129 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java index 0084271f..931d1d94 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java @@ -42,16 +42,14 @@ public class ListUtils { for (int index = 0; index < list.size(); index++) { T item = list.get(index); if (matcher.accept(item)) { - lastIndex = index > lastIndex ? index : lastIndex; + lastIndex = Math.max(index, lastIndex); } } return lastIndex; } public static void removeByIndex(List list, int fromIndex, int toIndex) { - for (int index = toIndex - 1; index >= fromIndex; index--) { - list.remove(index); - } + list.subList(fromIndex, toIndex).clear(); } public static T remove(List list, Matcher matcher) { @@ -78,11 +76,11 @@ public class ListUtils { } public static T findOne(Iterable collection, Matcher matcher) { - return CollUtil.findOne(collection, item -> matcher.accept(item)); + return CollUtil.findOne(collection, matcher::accept); } public static List findAll(List list, Matcher matcher) { - return CollUtil.filterNew(list, item -> matcher.accept(item)); + return CollUtil.filterNew(list, matcher::accept); } public static T findOneByScore(Iterable collection, Selector selector) { diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java index b7bea972..ca6b885e 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java @@ -19,9 +19,7 @@ public class TypeVisitor { List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); for (int index = 0; index < newGenericTypes.size(); index++) { IType genericType = forEachType(newGenericTypes.get(index), consumer); - if (genericType != null) { - newGenericTypes.set(index, genericType); - } + newGenericTypes.set(index, genericType); } newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); return newType; @@ -37,9 +35,7 @@ public class TypeVisitor { List newGenericTypes = new ArrayList<>(newType.getGenericTypes()); for (int index = 0; index < newGenericTypes.size(); index++) { IType genericType = forEachType(referGenericTypes.get(index), newGenericTypes.get(index), consumer); - if (genericType != null) { - newGenericTypes.set(index, genericType); - } + newGenericTypes.set(index, genericType); } newType.setGenericTypes(Collections.unmodifiableList(newGenericTypes)); return newType; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java index a3e9e1f2..8b7dc348 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java @@ -1,10 +1,6 @@ package com.gitee.spirit.core.compile; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -21,66 +17,63 @@ import com.gitee.spirit.core.element.entity.Element; @Component public class AutoImporter { - public static final String STRING_REGEX = "(?<=\").*?(?=\")";// 把字符串都替换掉 - public static final Pattern TYPE_PATTERN = Pattern.compile("(\\b[A-Z]+\\w+\\b)");// 间接排除了泛型类型T + public static final String STRING_REGEX = "(?<=\").*?(?=\")";// 把字符串都替换掉 + public static final Pattern TYPE_PATTERN = Pattern.compile("(\\b[A-Z]+\\w+\\b)");// 间接排除了泛型类型T - @Autowired - public ElementBuilder builder; - @Autowired - public SemanticParser parser; + @Autowired + public ElementBuilder builder; + @Autowired + public SemanticParser parser; - public void autoImport(IClass clazz) { - Set classNames = dependencies(clazz); - classNames.forEach(className -> clazz.addImport(className)); - } + public void autoImport(IClass clazz) { + Set classNames = dependencies(clazz); + classNames.forEach(clazz::addImport); + } - /** - * -这里不使用document对象的原因是,它包含多个类型,扫描之后,无法区分一个引用类型是归属哪个类的 - * - * @param clazz - * @return - */ - public Set dependencies(IClass clazz) { - Set classNames = new HashSet(); - // 将注解转成字符串,并重新构建Element对象 - List elements = new ArrayList<>(); - clazz.annotations.forEach((annotation) -> elements.add(builder.build(annotation.toString()))); - visitElements(clazz, classNames, elements); - // 遍历class内容 - visitElements(clazz, classNames, Arrays.asList(clazz.element)); - // 排除了自身 - classNames.remove(clazz.getClassName()); - return classNames; - } + /** + * 这里不使用document对象的原因是,它包含多个类型,扫描之后,无法区分一个引用类型是归属哪个类的 + */ + public Set dependencies(IClass clazz) { + Set classNames = new HashSet<>(); + // 将注解转成字符串,并重新构建Element对象 + List elements = new ArrayList<>(); + clazz.annotations.forEach((annotation) -> elements.add(builder.build(annotation.toString()))); + visitElements(clazz, classNames, elements); + // 遍历class内容 + visitElements(clazz, classNames, Collections.singletonList(clazz.element)); + // 排除了自身 + classNames.remove(clazz.getClassName()); + return classNames; + } - public void visitElements(IClass clazz, Set classNames, List elements) { - for (Element element : elements) { - String line = element.line.text; - // 剔除掉字符串 - line = line.replaceAll(STRING_REGEX, "").trim(); - // 进行正则匹配 - Matcher matcher = TYPE_PATTERN.matcher(line); - while (matcher.find() && matcher.groupCount() > 0) { - String targetName = matcher.group(matcher.groupCount() - 1); - if (parser.isType(targetName)) { - String className = clazz.findClassName(targetName); - classNames.add(className); - } - } - // 处理子节点 - if (element.hasChild()) { - visitElements(clazz, classNames, element.children); - } - } - } + public void visitElements(IClass clazz, Set classNames, List elements) { + for (Element element : elements) { + String line = element.line.text; + // 剔除掉字符串 + line = line.replaceAll(STRING_REGEX, "").trim(); + // 进行正则匹配 + Matcher matcher = TYPE_PATTERN.matcher(line); + while (matcher.find() && matcher.groupCount() > 0) { + String targetName = matcher.group(matcher.groupCount() - 1); + if (parser.isType(targetName)) { + String className = clazz.findClassName(targetName); + classNames.add(className); + } + } + // 处理子节点 + if (element.hasChild()) { + visitElements(clazz, classNames, element.children); + } + } + } - public String getFinalName(IClass clazz, IType type) { - return TypeVisitor.forEachTypeName(type, eachType -> { - if (!clazz.addImport(eachType.getClassName())) { - return eachType.getTypeName(); - } - return eachType.toString(); - }); - } + public String getFinalName(IClass clazz, IType type) { + return TypeVisitor.forEachTypeName(type, eachType -> { + if (!clazz.addImport(eachType.getClassName())) { + return eachType.getTypeName(); + } + return eachType.toString(); + }); + } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java index 0593f0f9..9c164f92 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java @@ -2,6 +2,7 @@ package com.gitee.spirit.core.compile; import java.util.List; +import com.gitee.spirit.core.element.frame.Semantic; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -71,7 +72,7 @@ public class DefaultClassVisitor implements ClassVisitor { Statement statement = methodToken.getValue(); List statements = statement.subStmt("(", ")").splitStmt(","); for (Statement parameterStmt : statements) { - List annotations = ListUtils.filterStoppable(parameterStmt, token -> token.isAnnotation(), token -> new IAnnotation(token)); + List annotations = ListUtils.filterStoppable(parameterStmt, Semantic::isAnnotation, IAnnotation::new); IParameter parameter = new IParameter(annotations, builder.build(parameterStmt)); parameter.setType(factory.create(clazz, parameterStmt.get(0))); method.parameters.add(parameter); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java index 7c05857f..71902686 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java @@ -23,64 +23,64 @@ import cn.hutool.core.lang.Assert; @Order(-100) public class AppClassLinker implements ClassLinker { - @Autowired - public AppClassLoader classLoader; - @Autowired - public ClassVisitor visitor; - @Autowired - public TypeDerivator derivator; - @Autowired - public AppMethodMatcher matcher; + @Autowired + public AppClassLoader classLoader; + @Autowired + public ClassVisitor visitor; + @Autowired + public TypeDerivator derivator; + @Autowired + public AppMethodMatcher matcher; - @Override - @SuppressWarnings("unchecked") - public T toClass(IType type) { - Assert.isTrue(!type.isArray(), "Array has no class!");// 这里认为数组没有class,也不应该有 - return (T) classLoader.loadClass(type.getClassName()); - } + @Override + @SuppressWarnings("unchecked") + public T toClass(IType type) { + Assert.isTrue(!type.isArray(), "Array has no class!");// 这里认为数组没有class,也不应该有 + return (T) classLoader.loadClass(type.getClassName()); + } - @Override - public int getTypeVariableIndex(IType type, String genericName) { - IClass clazz = toClass(type); - return clazz.getTypeVariableIndex(genericName); - } + @Override + public int getTypeVariableIndex(IType type, String genericName) { + IClass clazz = toClass(type); + return clazz.getTypeVariableIndex(genericName); + } - @Override - public IType getSuperType(IType type) { - IClass clazz = toClass(type); - IType superType = clazz.getSuperType(); - return superType != null ? derivator.populate(type, superType) : null; - } + @Override + public IType getSuperType(IType type) { + IClass clazz = toClass(type); + IType superType = clazz.getSuperType(); + return superType != null ? derivator.populate(type, superType) : null; + } - @Override - public List getInterfaceTypes(IType type) { - IClass clazz = toClass(type); - List interfaceTypes = new ArrayList<>(); - for (IType interfaceType : clazz.getInterfaceTypes()) { - interfaceTypes.add(derivator.populate(type, interfaceType)); - } - return interfaceTypes; - } + @Override + public List getInterfaceTypes(IType type) { + IClass clazz = toClass(type); + List interfaceTypes = new ArrayList<>(); + for (IType interfaceType : clazz.getInterfaceTypes()) { + interfaceTypes.add(derivator.populate(type, interfaceType)); + } + return interfaceTypes; + } - @Override - public IType visitField(IType type, String fieldName) throws NoSuchFieldException { - IClass clazz = toClass(type); - IField field = clazz.getField(fieldName); - if (field != null) { - return derivator.populate(type, visitor.visitMember(clazz, field)); - } - return null; - } + @Override + public IType visitField(IType type, String fieldName) { + IClass clazz = toClass(type); + IField field = clazz.getField(fieldName); + if (field != null) { + return derivator.populate(type, visitor.visitMember(clazz, field)); + } + return null; + } - @Override - public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { - IClass clazz = toClass(type); - List methods = clazz.getMethods(methodName); - IMethod method = ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); - if (method != null) { - return derivator.populate(type, visitor.visitMember(clazz, method)); - } - return null; - } + @Override + public IType visitMethod(IType type, String methodName, List parameterTypes) { + IClass clazz = toClass(type); + List methods = clazz.getMethods(methodName); + IMethod method = ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); + if (method != null) { + return derivator.populate(type, visitor.visitMember(clazz, method)); + } + return null; + } } diff --git a/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java b/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java index 5771c741..6a8b3897 100644 --- a/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java +++ b/spirit-tools/spirit-code-tools/src/main/java/com/gitee/spirit/code/tools/core/ElementSelector.java @@ -28,8 +28,7 @@ public class ElementSelector extends CoreCompiler { } public Element findElement(List elements, Integer lineNumber) { - for (int index = 0; index < elements.size(); index++) { - Element element = elements.get(index); + for (Element element : elements) { if (element.line.number == lineNumber) { return element; } -- Gitee From 244ecf7e3430809b2cba82450aee628057329055 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 30 Jun 2021 16:03:36 +0800 Subject: [PATCH 37/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/element/DefaultDocumentReader.java | 152 +++++++++--------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java index a7457610..0bea1b27 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java @@ -25,84 +25,84 @@ import cn.hutool.core.util.StrUtil; @Component public class DefaultDocumentReader implements DocumentReader { - @Autowired - public ElementBuilder builder; + @Autowired + public ElementBuilder builder; - @Override - public Document read(String fileName, InputStream input) { - Document document = new Document(fileName); - List lines = IoUtil.readLines(input, DefaultValue.CHARSET, new ArrayList()); - doReadLines(document, lines); - if (ConfigUtils.isDebug()) { - document.debug(); - } - return document; - } + @Override + public Document read(String fileName, InputStream input) { + List lines = IoUtil.readLines(input, DefaultValue.CHARSET, new ArrayList<>()); + Document document = doReadLines(new Document(fileName), lines); + if (ConfigUtils.isDebug()) { + document.debug(); + } + return document; + } - public void doReadLines(Document document, List lines) { - Stack> stack = new Stack<>(); - stack.push(document); - for (int index = 0; index < lines.size(); index++) { - String text = lines.get(index); - Line line = new Line(index + 1, text); - if (line.isIgnore()) { - continue; - } - Element element = builder.build(line); - // what like "var = {" - if (mergeLinesIfPossible(document, lines, index, element)) { - index--; - continue; - } - // what like "if xxx : xxx : xxx" - List sublines = splitLineIfPossible(element); - if (sublines != null && !sublines.isEmpty()) { - lines.remove(index); - lines.addAll(index, sublines); - index--; + public Document doReadLines(Document document, List lines) { + Stack> stack = new Stack<>(); + stack.push(document); + for (int index = 0; index < lines.size(); index++) { + String text = lines.get(index); + Line line = new Line(index + 1, text); + if (line.isIgnore()) { + continue; + } + Element element = builder.build(line); + // what like "var = {" + if (mergeLinesIfPossible(document, lines, index, element)) { + index--; + continue; + } + // what like "if xxx : xxx : xxx" + List subLines = splitLineIfPossible(element); + if (subLines != null && !subLines.isEmpty()) { + lines.remove(index); + lines.addAll(index, subLines); + index--; + continue; + } + //do read line + if (line.isEnding()) { + stack.pop(); + } + stack.peek().add(element); + if (line.hasChild()) { + stack.push(element.children); + } + } + return document; + } - } else { - if (line.isEnding()) { - stack.pop(); - } - stack.peek().add(element); - if (line.hasChild()) { - stack.push(element.children); - } - } - } - } + public boolean mergeLinesIfPossible(Document document, List lines, int startIndex, Element element) { + if (element.isStructAssign()) { + StringBuilder builder = new StringBuilder(lines.get(startIndex)); + for (int index = startIndex + 1; index < lines.size(); index++) { + builder.append(StrUtil.removeAny(lines.get(index), "\t").trim()); + int end = LineUtils.findEndIndex(builder, 0, '{', '}'); + if (end != -1) { + ListUtils.removeByIndex(lines, startIndex, index + 1); + lines.add(startIndex, builder.toString()); + return true; + } + } + } + return false; + } - public boolean mergeLinesIfPossible(Document document, List lines, int startIndex, Element element) { - if (element.isStructAssign()) { - StringBuilder builder = new StringBuilder(lines.get(startIndex)); - for (int index = startIndex + 1; index < lines.size(); index++) { - builder.append(StrUtil.removeAny(lines.get(index), "\t").trim()); - int end = LineUtils.findEndIndex(builder, 0, '{', '}'); - if (end != -1) { - ListUtils.removeByIndex(lines, startIndex, index + 1); - lines.add(startIndex, builder.toString()); - return true; - } - } - } - return false; - } - - public List splitLineIfPossible(Element element) { - if (element.isIf() || element.isFor() || element.isForIn() || element.isWhile()) { - if (element.contains(":")) { - String indent = element.getIndent(); - List subLines = new ArrayList<>(); - List statements = element.splitStmt(":"); - subLines.add(indent + statements.get(0).toString() + " {"); - for (int index = 1; index < statements.size(); index++) { - subLines.add(indent + "\t" + statements.get(index).toString()); - } - subLines.add(indent + "}"); - return subLines; - } - } - return null; - } + public List splitLineIfPossible(Element element) { + if (element.isIf() || element.isFor() || element.isForIn() || element.isWhile()) { + if (element.contains(":")) { + String indent = element.getIndent(); + List subLines = new ArrayList<>(); + List statements = element.splitStmt(":"); + subLines.add(indent + statements.get(0).toString() + " {"); + for (int index = 1; index < statements.size(); index++) { + subLines.add(indent + "\t" + statements.get(index).toString()); + } + subLines.add(indent + "}"); + return subLines; + } + } + return null; + } } -- Gitee From aae1388cd162946f6a5e99bdd3155342891a73f6 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 30 Jun 2021 18:34:37 +0800 Subject: [PATCH 38/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/clazz/AbstractURLClassLoader.java | 138 +++++++++--------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java index 833186b1..28c06266 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java @@ -3,13 +3,7 @@ package com.gitee.spirit.core.clazz; import java.io.File; import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; @@ -23,70 +17,70 @@ import cn.hutool.core.lang.Assert; public abstract class AbstractURLClassLoader extends AbstractClassLoader implements InitializingBean { - public Map urls = new LinkedHashMap<>(); - public Map classes = new LinkedHashMap<>(); - - @Override - public void afterPropertiesSet() throws Exception { - String inputPath = ConfigUtils.getInputPath(); - String extension = ConfigUtils.getFileExtension(); - Collection files = FileUtils.listFiles(new File(inputPath), new String[] { extension }, true); - List urlList = new ArrayList<>(); - files.forEach(file -> urlList.add(URLFileUtils.toURL(file))); - File directory = new File(inputPath); - Assert.isTrue(directory.isDirectory(), "The input path must be a directory!"); - URL inputUrl = URLFileUtils.toURL(directory); - urlList.forEach(url -> { - String name = url.toString().replace(inputUrl.toString(), "").replaceAll("/", "."); - if (name.endsWith("." + extension)) { - name = name.substring(0, name.lastIndexOf('.')); - } - urls.put(name, url); - classes.put(name, null); - }); - } - - @Override - public List getResources(String name) { - return Arrays.asList(urls.get(name)); - } - - @Override - public List getNames() { - return new ArrayList<>(classes.keySet()); - } - - @Override - public boolean contains(String name) { - return classes.containsKey(name); - } - - @Override - public IClass loadClass(String name) { - if (contains(name)) { - IClass clazz = classes.get(name); - if (clazz == null) { - clazz = classes.put(name, super.loadClass(name)); - } - return clazz; - } else { - throw new RuntimeException("The class was not found!name:" + name); - } - } - - @Override - public List getAllClasses() { - return classes.values().stream().filter(Objects::nonNull).collect(Collectors.toList()); - } - - @Override - public URL getResource(String name) { - return urls.get(name); - } - - public void clear() { - classes.clear(); - urls.keySet().forEach(name -> classes.put(name, null)); - } + public Map urls = new LinkedHashMap<>(); + public Map classes = new LinkedHashMap<>(); + + @Override + public void afterPropertiesSet() { + String inputPath = ConfigUtils.getInputPath(); + String extension = ConfigUtils.getFileExtension(); + Collection files = FileUtils.listFiles(new File(inputPath), new String[]{extension}, true); + List urlList = new ArrayList<>(); + files.forEach(file -> urlList.add(URLFileUtils.toURL(file))); + File directory = new File(inputPath); + Assert.isTrue(directory.isDirectory(), "The input path must be a directory!"); + URL inputUrl = URLFileUtils.toURL(directory); + urlList.forEach(url -> { + String name = url.toString().replace(inputUrl.toString(), "").replaceAll("/", "."); + if (name.endsWith("." + extension)) { + name = name.substring(0, name.lastIndexOf('.')); + } + urls.put(name, url); + classes.put(name, null); + }); + } + + @Override + public List getResources(String name) { + return Collections.singletonList(urls.get(name)); + } + + @Override + public List getNames() { + return new ArrayList<>(classes.keySet()); + } + + @Override + public boolean contains(String name) { + return classes.containsKey(name); + } + + @Override + public IClass loadClass(String name) { + if (contains(name)) { + IClass clazz = classes.get(name); + if (clazz == null) { + clazz = classes.put(name, super.loadClass(name)); + } + return clazz; + } else { + throw new RuntimeException("The class was not found!name:" + name); + } + } + + @Override + public List getAllClasses() { + return classes.values().stream().filter(Objects::nonNull).collect(Collectors.toList()); + } + + @Override + public URL getResource(String name) { + return urls.get(name); + } + + public void clear() { + classes.clear(); + urls.keySet().forEach(name -> classes.put(name, null)); + } } -- Gitee From de6c92e2cdeb87a77237f7c36fe0ddeb8b00f7f5 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Wed, 30 Jun 2021 22:10:48 +0800 Subject: [PATCH 39/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/constants/Argument.java | 14 +-- .../spirit/common/utils/ConfigUtils.java | 88 ++++++------- .../spirit/output/java/ExtClassLoader.java | 2 +- .../maven/plugin/SpiritCompileMojo.java | 116 +++++++++--------- 4 files changed, 110 insertions(+), 110 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java index ba96bbd6..224e402e 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java @@ -1,11 +1,11 @@ package com.gitee.spirit.common.constants; public interface Argument { - String INPUT = "input"; - String OUTPUT = "output"; - String CLASSPATHS = "classpaths"; - String LANG_PACKAGE = "langPackage"; - String UTIL_PACKAGE = "utilPackage"; - String FILE_EXTENSION = "fileExtension"; - String DEBUG = "debug"; + String INPUT_PATH = "input"; + String OUTPUT_PATH = "output"; + String CLASS_PATHS = "classPaths"; + String LANG_PACKAGE = "langPackage"; + String UTIL_PACKAGE = "utilPackage"; + String FILE_EXTENSION = "fileExtension"; + String DEBUG = "debug"; } \ No newline at end of file diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ConfigUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ConfigUtils.java index 3e08b88d..a8cbb618 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ConfigUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ConfigUtils.java @@ -10,63 +10,63 @@ import com.gitee.spirit.common.constants.DefaultValue; @Component public class ConfigUtils implements EnvironmentAware { - public static Environment environment; + public static Environment environment; - @Override - public void setEnvironment(Environment environment) { - ConfigUtils.environment = environment; - } + @Override + public void setEnvironment(Environment environment) { + ConfigUtils.environment = environment; + } - public static boolean contains(String key) { - return environment.containsProperty(key); - } + public static boolean contains(String key) { + return environment.containsProperty(key); + } - public static String getProperty(String key) { - return environment.getProperty(key); - } + public static String getProperty(String key) { + return environment.getProperty(key); + } - public static String getProperty(String key, String defaultValue) { - return environment.getProperty(key, defaultValue); - } + public static String getProperty(String key, String defaultValue) { + return environment.getProperty(key, defaultValue); + } - public static Boolean getProperty(String key, Boolean defaultValue) { - return environment.containsProperty(key) ? environment.getProperty(key, Boolean.class) : defaultValue; - } + public static Boolean getProperty(String key, Boolean defaultValue) { + return environment.containsProperty(key) ? environment.getProperty(key, Boolean.class) : defaultValue; + } - public static Integer getProperty(String key, Integer defaultValue) { - return environment.containsProperty(key) ? environment.getProperty(key, Integer.class) : defaultValue; - } + public static Integer getProperty(String key, Integer defaultValue) { + return environment.containsProperty(key) ? environment.getProperty(key, Integer.class) : defaultValue; + } - public static Long getProperty(String key, Long defaultValue) { - return environment.containsProperty(key) ? environment.getProperty(key, Long.class) : defaultValue; - } + public static Long getProperty(String key, Long defaultValue) { + return environment.containsProperty(key) ? environment.getProperty(key, Long.class) : defaultValue; + } - public static String getInputPath() { - return ConfigUtils.getProperty(Argument.INPUT); - } + public static String getInputPath() { + return ConfigUtils.getProperty(Argument.INPUT_PATH); + } - public static String getOutputPath() { - return ConfigUtils.getProperty(Argument.OUTPUT); - } + public static String getOutputPath() { + return ConfigUtils.getProperty(Argument.OUTPUT_PATH); + } - public static String getClasspaths() { - return ConfigUtils.getProperty(Argument.CLASSPATHS); - } + public static String getClassPaths() { + return ConfigUtils.getProperty(Argument.CLASS_PATHS); + } - public static String getLangPackage() { - return ConfigUtils.getProperty(Argument.LANG_PACKAGE); - } + public static String getLangPackage() { + return ConfigUtils.getProperty(Argument.LANG_PACKAGE); + } - public static String getUtilPackage() { - return ConfigUtils.getProperty(Argument.UTIL_PACKAGE); - } + public static String getUtilPackage() { + return ConfigUtils.getProperty(Argument.UTIL_PACKAGE); + } - public static String getFileExtension() { - return ConfigUtils.getProperty(Argument.FILE_EXTENSION, DefaultValue.FILE_EXTENSION); - } + public static String getFileExtension() { + return ConfigUtils.getProperty(Argument.FILE_EXTENSION, DefaultValue.FILE_EXTENSION); + } - public static boolean isDebug() { - return ConfigUtils.getProperty(Argument.DEBUG, DefaultValue.DEBUG); - } + public static boolean isDebug() { + return ConfigUtils.getProperty(Argument.DEBUG, DefaultValue.DEBUG); + } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java index ceecadcf..e47049d8 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java @@ -26,7 +26,7 @@ public class ExtClassLoader extends AbstractClassLoader> implements Ini @Override public void afterPropertiesSet() throws Exception { - String classpathsStr = ConfigUtils.getClasspaths(); + String classpathsStr = ConfigUtils.getClassPaths(); if (StringUtils.isNotBlank(classpathsStr)) { List classpaths = Splitter.on(",").trimResults().splitToList(classpathsStr); loader = ReflectUtils.getClassLoader(classpaths); diff --git a/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java b/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java index 8103597a..c34f673d 100644 --- a/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java +++ b/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java @@ -17,69 +17,69 @@ import com.google.common.base.Joiner; @Mojo(name = "compile", defaultPhase = LifecyclePhase.NONE, requiresDependencyResolution = ResolutionScope.COMPILE) public class SpiritCompileMojo extends AbstractMojo { - @Parameter(defaultValue = "${project}") - public MavenProject project; - @Parameter - private String inputPath; - @Parameter - private String outputPath; - @Parameter - private String langPackage; - @Parameter - private String utilPackage; + @Parameter(defaultValue = "${project}") + public MavenProject project; + @Parameter + private String inputPath; + @Parameter + private String outputPath; + @Parameter + private String langPackage; + @Parameter + private String utilPackage; - public void execute() throws MojoExecutionException, MojoFailureException { - try { - if (inputPath == null) { - inputPath = project.getResources().get(0).getDirectory(); - inputPath = inputPath.endsWith("\\resources") ? inputPath + "\\sources" : inputPath + "/sources"; - } - outputPath = outputPath == null ? project.getBuild().getSourceDirectory() : outputPath; + public void execute() throws MojoExecutionException, MojoFailureException { + try { + if (inputPath == null) { + inputPath = project.getResources().get(0).getDirectory(); + inputPath = inputPath.endsWith("\\resources") ? inputPath + "\\sources" : inputPath + "/sources"; + } + outputPath = outputPath == null ? project.getBuild().getSourceDirectory() : outputPath; - getLog().info(""); - getLog().info("-----------------------[ inputPath, outputPath ]------------------------"); - getLog().info(inputPath); - getLog().info(outputPath); - getLog().info(""); + getLog().info(""); + getLog().info("-----------------------[ inputPath, outputPath ]------------------------"); + getLog().info(inputPath); + getLog().info(outputPath); + getLog().info(""); - getLog().info("-----------------------------[ classpaths ]-----------------------------"); - List classpaths = project.getCompileClasspathElements(); - classpaths.add(project.getBuild().getTestOutputDirectory()); - classpaths.forEach(getLog()::info); - getLog().info(""); + getLog().info("-----------------------------[ classPaths ]-----------------------------"); + List classPaths = project.getCompileClasspathElements(); + classPaths.add(project.getBuild().getTestOutputDirectory()); + classPaths.forEach(getLog()::info); + getLog().info(""); - langPackage = langPackage == null ? "java.lang" : langPackage; - utilPackage = utilPackage == null ? "java.util" : utilPackage; + langPackage = langPackage == null ? "java.lang" : langPackage; + utilPackage = utilPackage == null ? "java.util" : utilPackage; - JavaStarter.main(new String[] { // - "--input=" + inputPath, // - "--output=" + outputPath, // - "--classpaths=" + Joiner.on(", ").join(classpaths), // - "--langPackage=" + langPackage, // - "--utilPackage=" + utilPackage // - }); + JavaStarter.main(new String[]{ // + "--input=" + inputPath, // + "--output=" + outputPath, // + "--classPaths=" + Joiner.on(", ").join(classPaths), // + "--langPackage=" + langPackage, // + "--utilPackage=" + utilPackage // + }); - } catch (Exception e) { - e.printStackTrace(); - } - } + } catch (Exception e) { + e.printStackTrace(); + } + } - public static void main(String[] args) throws ClassNotFoundException { - String userHome = System.getProperty("user.home"); - String inputPath = "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\src\\main\\resources\\sources"; - String outputPath = "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\src\\main\\java"; - String classpaths = "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\target\\classes, "; - classpaths += userHome + "\\.m2\\repository\\com\\gitee\\chentaoah\\spirit-example-common\\2.1.30\\spirit-example-common-2.1.30.jar, "; - classpaths += userHome + "\\.m2\\repository\\com\\gitee\\chentaoah\\spirit-stdlib\\2.1.30\\spirit-stdlib-2.1.30.jar, "; - classpaths += userHome + "\\.m2\\repository\\org\\slf4j\\slf4j-api\\1.7.25\\slf4j-api-1.7.25.jar, "; - classpaths += userHome + "\\.m2\\repository\\org\\apache\\commons\\commons-lang3\\3.9\\commons-lang3-3.9.jar, "; - classpaths += "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\target\\test-classes"; - JavaStarter.main(new String[] { // - "--input=" + inputPath, // - "--output=" + outputPath, // - "--classpaths=" + classpaths, // - "--langPackage=" + "java.lang", // - "--utilPackage=" + "java.util" // - }); - } + public static void main(String[] args) { + String userHome = System.getProperty("user.home"); + String inputPath = "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\src\\main\\resources\\sources"; + String outputPath = "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\src\\main\\java"; + String classPaths = "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\target\\classes, "; + classPaths += userHome + "\\.m2\\repository\\com\\gitee\\chentaoah\\spirit-example-common\\2.1.30\\spirit-example-common-2.1.30.jar, "; + classPaths += userHome + "\\.m2\\repository\\com\\gitee\\chentaoah\\spirit-stdlib\\2.1.30\\spirit-stdlib-2.1.30.jar, "; + classPaths += userHome + "\\.m2\\repository\\org\\slf4j\\slf4j-api\\1.7.25\\slf4j-api-1.7.25.jar, "; + classPaths += userHome + "\\.m2\\repository\\org\\apache\\commons\\commons-lang3\\3.9\\commons-lang3-3.9.jar, "; + classPaths += "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\target\\test-classes"; + JavaStarter.main(new String[]{ // + "--input=" + inputPath, // + "--output=" + outputPath, // + "--classPaths=" + classPaths, // + "--langPackage=" + "java.lang", // + "--utilPackage=" + "java.util" // + }); + } } -- Gitee From 14db72e0d9e930b18a33b6ed5550396ac4d74a65 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Wed, 30 Jun 2021 22:21:29 +0800 Subject: [PATCH 40/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/spirit/common/constants/Argument.java | 4 ++-- .../gitee/spirit/maven/plugin/SpiritCompileMojo.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java index 224e402e..c9e90e0b 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/constants/Argument.java @@ -1,8 +1,8 @@ package com.gitee.spirit.common.constants; public interface Argument { - String INPUT_PATH = "input"; - String OUTPUT_PATH = "output"; + String INPUT_PATH = "inputPath"; + String OUTPUT_PATH = "outputPath"; String CLASS_PATHS = "classPaths"; String LANG_PACKAGE = "langPackage"; String UTIL_PACKAGE = "utilPackage"; diff --git a/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java b/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java index c34f673d..8d70e3a2 100644 --- a/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java +++ b/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java @@ -28,7 +28,7 @@ public class SpiritCompileMojo extends AbstractMojo { @Parameter private String utilPackage; - public void execute() throws MojoExecutionException, MojoFailureException { + public void execute() { try { if (inputPath == null) { inputPath = project.getResources().get(0).getDirectory(); @@ -52,8 +52,8 @@ public class SpiritCompileMojo extends AbstractMojo { utilPackage = utilPackage == null ? "java.util" : utilPackage; JavaStarter.main(new String[]{ // - "--input=" + inputPath, // - "--output=" + outputPath, // + "--inputPath=" + inputPath, // + "--outputPath=" + outputPath, // "--classPaths=" + Joiner.on(", ").join(classPaths), // "--langPackage=" + langPackage, // "--utilPackage=" + utilPackage // @@ -75,8 +75,8 @@ public class SpiritCompileMojo extends AbstractMojo { classPaths += userHome + "\\.m2\\repository\\org\\apache\\commons\\commons-lang3\\3.9\\commons-lang3-3.9.jar, "; classPaths += "D:\\Work\\CloudSpace\\spirit\\spirit-example\\spirit-example-plugin\\target\\test-classes"; JavaStarter.main(new String[]{ // - "--input=" + inputPath, // - "--output=" + outputPath, // + "--inputPath=" + inputPath, // + "--outputPath=" + outputPath, // "--classPaths=" + classPaths, // "--langPackage=" + "java.lang", // "--utilPackage=" + "java.util" // -- Gitee From 55d6f66fc05dd96939ba5ee3784af8740a17bbae Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Thu, 1 Jul 2021 12:46:29 +0800 Subject: [PATCH 41/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/common/utils/ListUtils.java | 118 ++++------ .../gitee/spirit/common/utils/Splitter.java | 62 ++--- .../gitee/spirit/core/api/ClassResolver.java | 4 +- .../core/clazz/DefaultClassResolver.java | 196 ++++++++-------- .../core/clazz/frame/AnnotationEntity.java | 2 +- .../core/compile/DefaultClassVisitor.java | 2 +- .../core/element/DefaultDocumentReader.java | 2 +- .../element/action/DefaultTreeBuilder.java | 217 +++++++++--------- .../spirit/core/element/entity/Document.java | 27 ++- .../spirit/core/element/entity/Element.java | 93 ++++---- .../spirit/core/element/entity/Modifiers.java | 3 +- .../spirit/core/element/entity/Statement.java | 56 ++--- .../spirit/core/element/frame/TokenBox.java | 4 +- 13 files changed, 390 insertions(+), 396 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java index 931d1d94..3612e6d8 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java @@ -1,7 +1,6 @@ package com.gitee.spirit.common.utils; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import cn.hutool.core.collection.CollUtil; @@ -23,56 +22,45 @@ public class ListUtils { return list; } - public static int indexOf(List list, int fromIndex, Matcher matcher) { - for (int index = fromIndex; index < list.size(); index++) { - T item = list.get(index); - if (matcher.accept(item)) { + public static int indexOf(List list, int fromIndex, int toIndex, Matcher matcher) { + int step = toIndex >= fromIndex ? 1 : -1; + for (int index = fromIndex; index != toIndex; index += step) { + if (matcher.accept(list.get(index))) { return index; } } return -1; } + public static int seekIndexOf(List list, int fromIndex, int toIndex, Matcher matcher) { + int index = indexOf(list, fromIndex, toIndex, item -> !matcher.accept(item)); + return index == -1 ? toIndex : index; + } + + public static int indexOf(List list, int fromIndex, Matcher matcher) { + return indexOf(list, fromIndex, list.size(), matcher); + } + public static int indexOf(List list, Matcher matcher) { - return indexOf(list, 0, matcher); + return indexOf(list, 0, list.size(), matcher); } public static int lastIndexOf(List list, Matcher matcher) { - int lastIndex = -1; - for (int index = 0; index < list.size(); index++) { - T item = list.get(index); - if (matcher.accept(item)) { - lastIndex = Math.max(index, lastIndex); - } - } - return lastIndex; + return indexOf(list, list.size() - 1, -1, matcher); } - public static void removeByIndex(List list, int fromIndex, int toIndex) { - list.subList(fromIndex, toIndex).clear(); + public static T removeOne(List list, Matcher matcher) { + int index = indexOf(list, matcher); + return index >= 0 ? list.remove(index) : null; } - public static T remove(List list, Matcher matcher) { - Iterator iterable = list.iterator(); - while (iterable.hasNext()) { - T item = iterable.next(); - if (matcher.accept(item)) { - iterable.remove(); - return item; - } - } - return null; + public static void removeAllByIndex(List list, int fromIndex, int toIndex) { + list.subList(fromIndex, toIndex).clear(); } public static T findOneByIndex(List list, int fromIndex, int toIndex, Matcher matcher) { - int step = toIndex >= fromIndex ? 1 : -1; - for (int index = fromIndex; index != toIndex; index += step) { - T item = list.get(index); - if (matcher.accept(item)) { - return item; - } - } - return null; + int index = indexOf(list, fromIndex, toIndex, matcher); + return index >= 0 ? list.get(index) : null; } public static T findOne(Iterable collection, Matcher matcher) { @@ -83,6 +71,28 @@ public class ListUtils { return CollUtil.filterNew(list, matcher::accept); } + public static List seekAll(List list, Matcher matcher) { + int index = seekIndexOf(list, 0, list.size(), matcher); + List view = list.subList(0, index); + List items = new ArrayList<>(view); + view.clear(); + return items; + } + + @SuppressWarnings("unchecked") + public static List seekAll(List list, Matcher matcher, Factory factory) { + List items = seekAll(list, matcher); + List list0 = new ArrayList<>(); + items.forEach(item -> list0.add((V) factory.accept(item))); + return list0; + } + + public static void visit(List list, Visitor visitor) { + for (int index = 0; index < list.size(); index++) { + visitor.accept(index, list.get(index)); + } + } + public static T findOneByScore(Iterable collection, Selector selector) { Integer maxScore = null; T finalItem = null; @@ -99,35 +109,6 @@ public class ListUtils { return finalItem; } - public static List filterStoppable(List list, Matcher matcher) { - List items = new ArrayList<>(); - Iterator iterable = list.iterator(); - while (iterable.hasNext()) { - T item = iterable.next(); - if (matcher.accept(item)) { - items.add(item); - iterable.remove(); - } else { - break; - } - } - return items; - } - - @SuppressWarnings("unchecked") - public static List filterStoppable(List list, Matcher matcher, Factory factory) { - List items = filterStoppable(list, matcher); - List list0 = new ArrayList<>(); - items.forEach(item -> list0.add((V) factory.accept(item))); - return list0; - } - - public static void visit(List list, Visitor visitor) { - for (int index = 0; index < list.size(); index++) { - visitor.accept(index, list.get(index)); - } - } - @SuppressWarnings("unchecked") public static V collectOne(List list, Factory factory) { for (T item : list) { @@ -149,17 +130,6 @@ public class ListUtils { return null; } - @SuppressWarnings("unchecked") - public static List collectAll(List list, Matcher matcher, Factory factory) { - List list0 = new ArrayList<>(); - for (T item : list) { - if (matcher.accept(item)) { - list0.add((V) factory.accept(item)); - } - } - return list0; - } - public interface Matcher { boolean accept(T t); } diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/Splitter.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/Splitter.java index 45c47e8a..61b59e30 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/Splitter.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/Splitter.java @@ -7,36 +7,36 @@ import cn.hutool.core.collection.CollUtil; public class Splitter { - public static List> splitByMatcherTrim(List list, Matcher matcher) { - int[] indexs = CollUtil.indexOfAll(list, item -> matcher.accept(item)); - List> subLists = new ArrayList<>(); - int lastIndex = 0; - for (int index : indexs) { - if (index > lastIndex) { - subLists.add(new ArrayList<>(list.subList(lastIndex, index))); - } - lastIndex = index + 1; - } - if (lastIndex != list.size()) { - subLists.add(new ArrayList<>(list.subList(lastIndex, list.size()))); - } - return subLists; - } - - @SuppressWarnings("unchecked") - public static List splitByMatcherTrim(List list, Matcher matcher, Factory> factory) { - List> subLists = splitByMatcherTrim(list, matcher); - List anotherList = new ArrayList<>(); - subLists.forEach(subList -> anotherList.add((V) factory.accept(subList))); - return anotherList; - } - - public static interface Matcher { - boolean accept(T t); - } - - public static interface Factory { - Object accept(T t); - } + public static List> splitByMatcherTrim(List list, Matcher matcher) { + int[] indexes = CollUtil.indexOfAll(list, matcher::accept); + List> subLists = new ArrayList<>(); + int lastIndex = 0; + for (int index : indexes) { + if (index > lastIndex) { + subLists.add(new ArrayList<>(list.subList(lastIndex, index))); + } + lastIndex = index + 1; + } + if (lastIndex != list.size()) { + subLists.add(new ArrayList<>(list.subList(lastIndex, list.size()))); + } + return subLists; + } + + @SuppressWarnings("unchecked") + public static List splitByMatcherTrim(List list, Matcher matcher, Factory> factory) { + List> subLists = splitByMatcherTrim(list, matcher); + List anotherList = new ArrayList<>(); + subLists.forEach(subList -> anotherList.add((V) factory.accept(subList))); + return anotherList; + } + + public interface Matcher { + boolean accept(T t); + } + + public interface Factory { + Object accept(T t); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassResolver.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassResolver.java index 9d7c1ac0..6eb213ff 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassResolver.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassResolver.java @@ -7,6 +7,8 @@ import com.gitee.spirit.core.element.entity.Document; public interface ClassResolver { - Map resolve(String packageStr, Document document); + Map resolve(String packageStr, Document document); + + Document getDocument(IClass clazz); } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java index 2a97973a..a4524e05 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -23,98 +24,107 @@ import com.gitee.spirit.core.element.entity.Element; @Component public class DefaultClassResolver implements ClassResolver { - @Autowired - public ElementBuilder builder; - - @Override - public Map resolve(String packageStr, Document document) { - - Map classes = new LinkedHashMap<>(); - - List imports = new ArrayList<>(); - List annotations = new ArrayList<>(); - IClass mainClass = null; - List fields = new ArrayList<>(); - List methods = new ArrayList<>(); - - for (Element element : document) { - if (element.isImport()) { - imports.add(new Import(element)); - - } else if (element.isAnnotation()) { - annotations.add(new IAnnotation(element.get(0))); - - } else if (element.isDeclare() || element.isDeclareAssign() || element.isAssign()) { - element.addModifiers(KeywordEnum.PUBLIC.value, KeywordEnum.STATIC.value); - fields.add(new IField(copyAnnotations(annotations), element)); - - } else if (element.isDeclareFunc() || element.isFunc()) { - element.addModifiers(KeywordEnum.PUBLIC.value, KeywordEnum.STATIC.value); - methods.add(new IMethod(copyAnnotations(annotations), element)); - - } else if (element.isInterface() || element.isAbstract()) { - // 接口和抽象类,只允许出现一个主类 - mainClass = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); - initClass(mainClass, packageStr, fields, methods); - readRootElement(mainClass); - classes.put(mainClass.getClassName(), mainClass); - - } else if (element.isClass()) { - // 这里可能出现泛型,但是文件名一般是simpleName - String simpleName = element.getKeywordParam(KeywordEnum.CLASS.value).toString(); - // 声明一个类型时,泛型参数不能多层嵌套 - String targetName = TypeUtils.getTargetName(simpleName); - if (document.fileName.equals(targetName)) { - mainClass = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); - initClass(mainClass, packageStr, fields, methods); - readRootElement(mainClass); - classes.put(mainClass.getClassName(), mainClass); - - } else { - IClass clazz = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); - initClass(clazz, packageStr, new ArrayList<>(), new ArrayList<>()); - readRootElement(clazz); - classes.put(clazz.getClassName(), clazz); - } - } - } - - // 如果不存在主类的声明,则虚拟一个Element - if (mainClass == null) { - Element element = builder.build("class " + document.fileName + " {"); - mainClass = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); - initClass(mainClass, packageStr, fields, methods); - classes.put(mainClass.getClassName(), mainClass); - } - - return classes; - } - - public List copyAnnotations(List annotations) { - List newAnnotations = new ArrayList<>(annotations); - annotations.clear(); - return newAnnotations; - } - - public void initClass(IClass clazz, String packageStr, List fields, List methods) { - clazz.packageStr = packageStr; - clazz.fields = fields; - clazz.methods = methods; - } - - public void readRootElement(IClass clazz) { - List annotations = new ArrayList<>(); - for (Element element : clazz.element.children) { - if (element.isAnnotation()) { - annotations.add(new IAnnotation(element.get(0))); - - } else if (element.isDeclare() || element.isDeclareAssign() || element.isAssign()) { - clazz.fields.add(new IField(copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value))); - - } else if (element.isDeclareFunc() || element.isFunc()) { - clazz.methods.add(new IMethod(copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value))); - } - } - } + @Autowired + public ElementBuilder builder; + public Map classDocumentMap = new ConcurrentHashMap<>(); + + @Override + public Map resolve(String packageStr, Document document) { + + Map classes = new LinkedHashMap<>(); + + List imports = new ArrayList<>(); + List annotations = new ArrayList<>(); + IClass mainClass = null; + List fields = new ArrayList<>(); + List methods = new ArrayList<>(); + + for (Element element : document) { + if (element.isImport()) { + imports.add(new Import(element)); + + } else if (element.isAnnotation()) { + annotations.add(new IAnnotation(element.get(0))); + + } else if (element.isDeclare() || element.isDeclareAssign() || element.isAssign()) { + element.addModifiers(KeywordEnum.PUBLIC.value, KeywordEnum.STATIC.value); + fields.add(new IField(copyAnnotations(annotations), element)); + + } else if (element.isDeclareFunc() || element.isFunc()) { + element.addModifiers(KeywordEnum.PUBLIC.value, KeywordEnum.STATIC.value); + methods.add(new IMethod(copyAnnotations(annotations), element)); + + } else if (element.isInterface() || element.isAbstract()) { + // 接口和抽象类,只允许出现一个主类 + mainClass = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); + initClass(mainClass, packageStr, fields, methods); + readRootElement(mainClass); + classes.put(mainClass.getClassName(), mainClass); + + } else if (element.isClass()) { + // 这里可能出现泛型,但是文件名一般是simpleName + String simpleName = element.getKeywordParam(KeywordEnum.CLASS.value).toString(); + // 声明一个类型时,泛型参数不能多层嵌套 + String targetName = TypeUtils.getTargetName(simpleName); + if (document.fileName.equals(targetName)) { + mainClass = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); + initClass(mainClass, packageStr, fields, methods); + readRootElement(mainClass); + classes.put(mainClass.getClassName(), mainClass); + + } else { + IClass clazz = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); + initClass(clazz, packageStr, new ArrayList<>(), new ArrayList<>()); + readRootElement(clazz); + classes.put(clazz.getClassName(), clazz); + } + } + } + + // 如果不存在主类的声明,则虚拟一个Element + if (mainClass == null) { + Element element = builder.build("class " + document.fileName + " {"); + mainClass = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); + initClass(mainClass, packageStr, fields, methods); + classes.put(mainClass.getClassName(), mainClass); + } + + //进行关系绑定 + classes.values().forEach(clazz -> classDocumentMap.put(clazz, document)); + + return classes; + } + + @Override + public Document getDocument(IClass clazz) { + return classDocumentMap.get(clazz); + } + + public List copyAnnotations(List annotations) { + List newAnnotations = new ArrayList<>(annotations); + annotations.clear(); + return newAnnotations; + } + + public void initClass(IClass clazz, String packageStr, List fields, List methods) { + clazz.packageStr = packageStr; + clazz.fields = fields; + clazz.methods = methods; + } + + public void readRootElement(IClass clazz) { + List annotations = new ArrayList<>(); + for (Element element : clazz.element.children) { + if (element.isAnnotation()) { + annotations.add(new IAnnotation(element.get(0))); + + } else if (element.isDeclare() || element.isDeclareAssign() || element.isAssign()) { + clazz.fields.add(new IField(copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value))); + + } else if (element.isDeclareFunc() || element.isFunc()) { + clazz.methods.add(new IMethod(copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value))); + } + } + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotationEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotationEntity.java index 29785e1e..35b8879e 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotationEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotationEntity.java @@ -21,7 +21,7 @@ public abstract class AnnotationEntity extends ElementEntity { } public IAnnotation removeAnnotation(String className) { - return ListUtils.remove(annotations, annotation -> annotation.getType().getClassName().equals(className)); + return ListUtils.removeOne(annotations, annotation -> annotation.getType().getClassName().equals(className)); } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java index 9c164f92..70fb103e 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultClassVisitor.java @@ -72,7 +72,7 @@ public class DefaultClassVisitor implements ClassVisitor { Statement statement = methodToken.getValue(); List statements = statement.subStmt("(", ")").splitStmt(","); for (Statement parameterStmt : statements) { - List annotations = ListUtils.filterStoppable(parameterStmt, Semantic::isAnnotation, IAnnotation::new); + List annotations = ListUtils.seekAll(parameterStmt, Semantic::isAnnotation, IAnnotation::new); IParameter parameter = new IParameter(annotations, builder.build(parameterStmt)); parameter.setType(factory.create(clazz, parameterStmt.get(0))); method.parameters.add(parameter); diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java index 0bea1b27..2629c7a1 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultDocumentReader.java @@ -80,7 +80,7 @@ public class DefaultDocumentReader implements DocumentReader { builder.append(StrUtil.removeAny(lines.get(index), "\t").trim()); int end = LineUtils.findEndIndex(builder, 0, '{', '}'); if (end != -1) { - ListUtils.removeByIndex(lines, startIndex, index + 1); + ListUtils.removeAllByIndex(lines, startIndex, index + 1); lines.add(startIndex, builder.toString()); return true; } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java index b5c18d0e..97b7b218 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java @@ -22,114 +22,113 @@ import com.gitee.spirit.core.element.entity.Token; @Component public class DefaultTreeBuilder extends AbstractTreeBuilder { - @Override - public List buildNodes(List tokens) { - final List nodes = new ArrayList<>(); - ListUtils.visit(tokens, (index, token) -> { - if (token.hasSubStmt()) { - SyntaxTree syntaxTree = buildTree(token.getValue()); - token = new Token(token.tokenType, syntaxTree, token.attributes); - } - nodes.add(new Node(index, token)); - }); - Queue> queue = getPriorityQueue(tokens); - List newNodes = gatherNodesByQueue(queue, nodes); - return newNodes; - } - - public Queue> getPriorityQueue(List tokens) { - Queue> queue = new PriorityQueue<>(16, new PriorityComparator()); - for (int index = 0; index < tokens.size(); index++) { - Token currentToken = tokens.get(index); - Token nextToken = index + 1 < tokens.size() ? tokens.get(index + 1) : null; - int priority = -1; - OperandEnum operand = null; - - if (currentToken.isVisit()) { - priority = 55; - operand = OperandEnum.LEFT; - - } else if (currentToken.isType()) { - if (nextToken != null && (nextToken.isVariable() || nextToken.isLocalMethod())) { - priority = 50; - operand = OperandEnum.RIGHT; - } - - } else if (currentToken.isOperator()) { - OperatorEnum operator = OperatorEnum.getOperator(currentToken.toString()); - priority = operator.priority; - operand = operator.operand; - - } else if (currentToken.isCast()) { - priority = 35; - operand = OperandEnum.RIGHT; - - } else if (currentToken.isInstanceof()) { - priority = 20; - operand = OperandEnum.BINARY; - } - - if (priority > 0) { - queue.add(new PriorityNode(priority, index)); - currentToken.setAttr(Attribute.OPERAND, operand); - } - } - return queue; - } - - public List gatherNodesByQueue(Queue> queue, List nodes) { - while (!queue.isEmpty()) { - PriorityNode priorityNode = queue.poll(); - int index = priorityNode.item; - Node node = nodes.get(index); - Token currentToken = node.token; - // 如果是多义的操作符,则进行判断后,确定真正的操作数 - resetOperandIfMultiple(nodes, index, currentToken); - - OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); - if (operandEnum == OperandEnum.LEFT) { - Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); - node.prev = lastNode; - nodes.set(lastNode.index, null); - - } else if (operandEnum == OperandEnum.RIGHT) { - Node nextNode = ListUtils.findOneByIndex(nodes, index + 1, nodes.size(), Objects::nonNull); - node.next = nextNode; - nodes.set(nextNode.index, null); - - } else if (operandEnum == OperandEnum.BINARY) { - Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); - node.prev = lastNode; - nodes.set(lastNode.index, null); - - Node nextNode = ListUtils.findOneByIndex(nodes, index + 1, nodes.size(), Objects::nonNull); - node.next = nextNode; - nodes.set(nextNode.index, null); - - } else { - throw new RuntimeException("Unable to know the operand of the symbol!"); - } - } - return nodes.stream().filter(Objects::nonNull).collect(Collectors.toList());// 过滤掉所有null - } - - public void resetOperandIfMultiple(List nodes, int index, Token currentToken) { - OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); - if (operandEnum == OperandEnum.MULTIPLE) { - Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); - String value = currentToken.toString(); - if ("-".equals(value)) {// 100 + (-10) // var = -1 - if (lastNode != null) { - if (lastNode.isMounted() || (lastNode.token.isNumber() || lastNode.token.isVariable())) { - currentToken.setAttr(Attribute.OPERAND, OperandEnum.BINARY); - } else { - currentToken.setAttr(Attribute.OPERAND, OperandEnum.RIGHT); - } - } else { - currentToken.setAttr(Attribute.OPERAND, OperandEnum.RIGHT); - } - } - } - } + @Override + public List buildNodes(List tokens) { + final List nodes = new ArrayList<>(); + ListUtils.visit(tokens, (index, token) -> { + if (token.hasSubStmt()) { + SyntaxTree syntaxTree = buildTree(token.getValue()); + token = new Token(token.tokenType, syntaxTree, token.attributes); + } + nodes.add(new Node(index, token)); + }); + Queue> queue = getPriorityQueue(tokens); + return gatherNodesByQueue(queue, nodes); + } + + public Queue> getPriorityQueue(List tokens) { + Queue> queue = new PriorityQueue<>(16, new PriorityComparator<>()); + for (int index = 0; index < tokens.size(); index++) { + Token currentToken = tokens.get(index); + Token nextToken = index + 1 < tokens.size() ? tokens.get(index + 1) : null; + int priority = -1; + OperandEnum operand = null; + + if (currentToken.isVisit()) { + priority = 55; + operand = OperandEnum.LEFT; + + } else if (currentToken.isType()) { + if (nextToken != null && (nextToken.isVariable() || nextToken.isLocalMethod())) { + priority = 50; + operand = OperandEnum.RIGHT; + } + + } else if (currentToken.isOperator()) { + OperatorEnum operator = OperatorEnum.getOperator(currentToken.toString()); + priority = operator.priority; + operand = operator.operand; + + } else if (currentToken.isCast()) { + priority = 35; + operand = OperandEnum.RIGHT; + + } else if (currentToken.isInstanceof()) { + priority = 20; + operand = OperandEnum.BINARY; + } + + if (priority > 0) { + queue.add(new PriorityNode<>(priority, index)); + currentToken.setAttr(Attribute.OPERAND, operand); + } + } + return queue; + } + + public List gatherNodesByQueue(Queue> queue, List nodes) { + while (!queue.isEmpty()) { + PriorityNode priorityNode = queue.poll(); + int index = priorityNode.item; + Node node = nodes.get(index); + Token currentToken = node.token; + // 如果是多义的操作符,则进行判断后,确定真正的操作数 + resetOperandIfMultiple(nodes, index, currentToken); + + OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); + if (operandEnum == OperandEnum.LEFT) { + Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); + node.prev = lastNode; + nodes.set(Objects.requireNonNull(lastNode).index, null); + + } else if (operandEnum == OperandEnum.RIGHT) { + Node nextNode = ListUtils.findOneByIndex(nodes, index + 1, nodes.size(), Objects::nonNull); + node.next = nextNode; + nodes.set(Objects.requireNonNull(nextNode).index, null); + + } else if (operandEnum == OperandEnum.BINARY) { + Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); + node.prev = lastNode; + nodes.set(Objects.requireNonNull(lastNode).index, null); + + Node nextNode = ListUtils.findOneByIndex(nodes, index + 1, nodes.size(), Objects::nonNull); + node.next = nextNode; + nodes.set(Objects.requireNonNull(nextNode).index, null); + + } else { + throw new RuntimeException("Unable to know the operand of the symbol!"); + } + } + return nodes.stream().filter(Objects::nonNull).collect(Collectors.toList());// 过滤掉所有null + } + + public void resetOperandIfMultiple(List nodes, int index, Token currentToken) { + OperandEnum operandEnum = currentToken.attr(Attribute.OPERAND); + if (operandEnum == OperandEnum.MULTIPLE) { + Node lastNode = ListUtils.findOneByIndex(nodes, index - 1, -1, Objects::nonNull); + String value = currentToken.toString(); + if ("-".equals(value)) {// 100 + (-10) // var = -1 + if (lastNode != null) { + if (lastNode.isMounted() || (lastNode.token.isNumber() || lastNode.token.isVariable())) { + currentToken.setAttr(Attribute.OPERAND, OperandEnum.BINARY); + } else { + currentToken.setAttr(Attribute.OPERAND, OperandEnum.RIGHT); + } + } else { + currentToken.setAttr(Attribute.OPERAND, OperandEnum.RIGHT); + } + } + } + } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Document.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Document.java index 7f74795a..bb36c37e 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Document.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Document.java @@ -1,21 +1,34 @@ package com.gitee.spirit.core.element.entity; import java.util.ArrayList; +import java.util.List; +import cn.hutool.core.collection.CollUtil; +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.element.frame.Syntactic; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor -@SuppressWarnings("serial") public class Document extends ArrayList { - public String fileName; + public String fileName; - public void debug() { - for (Element element : this) { - element.debug(); - } - } + public List findElements(Element element) { + int index = ListUtils.indexOf(this, element::equals); + if (index >= 0) { + int startIndex = ListUtils.seekIndexOf(this, index - 1, -1, Syntactic::isAnnotation); + int endIndex = ListUtils.indexOf(this, index + 1, size(), Syntactic::isEnd); + return new ArrayList<>(subList(startIndex + 1, endIndex + 1)); + } + throw new RuntimeException("The element was not found!"); + } + + public void debug() { + for (Element element : this) { + element.debug(); + } + } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Element.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Element.java index bd4a80e0..a0aa020d 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Element.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Element.java @@ -9,62 +9,61 @@ import com.gitee.spirit.core.element.frame.Syntactic; public class Element extends Syntactic { - public Line line; - public Modifiers modifiers; - public SyntaxTree syntaxTree; - public List children = new ArrayList<>(); + public Line line; + public Modifiers modifiers; + public SyntaxTree syntaxTree; + public List children = new ArrayList<>(); - public Element(Line line, Modifiers modifiers, Statement statement, SyntaxEnum syntax, SyntaxTree syntaxTree) { - super(syntax, statement); - this.line = line; - this.modifiers = modifiers; - this.syntaxTree = syntaxTree; - } + public Element(Line line, Modifiers modifiers, Statement statement, SyntaxEnum syntax, SyntaxTree syntaxTree) { + super(syntax, statement); + this.line = line; + this.modifiers = modifiers; + this.syntaxTree = syntaxTree; + } - public Element(Statement statement) { - super(null, statement); - } + public Element(Statement statement) { + super(null, statement); + } - public String getIndent() { - return line.getIndent(); - } + public String getIndent() { + return line.getIndent(); + } - public boolean hasChild() { - return line.hasChild() || children.size() > 0; - } + public boolean hasChild() { + return line.hasChild() || children.size() > 0; + } - public boolean isModified(String keyword) { - return modifiers.containsKeyword(keyword); - } + public boolean isModified(String keyword) { + return modifiers.containsKeyword(keyword); + } - public Element addModifiers(String... keywords) { - for (int i = keywords.length - 1; i >= 0; i--) { - modifiers.addKeywordAtFirst(keywords[i]); - } - return this; - } + public Element addModifiers(String... keywords) { + for (int i = keywords.length - 1; i >= 0; i--) { + modifiers.addKeywordAtFirst(keywords[i]); + } + return this; + } - public Element replaceModifier(String keyword, String newKeyword) { - modifiers.replaceKeyword(keyword, newKeyword); - return this; - } + public Element replaceModifier(String keyword, String newKeyword) { + modifiers.replaceKeyword(keyword, newKeyword); + return this; + } - public Element insertModifier(String keyword, String newKeyword) { - modifiers.insertKeywordAfter(keyword, newKeyword); - return this; - } + public Element insertModifier(String keyword, String newKeyword) { + modifiers.insertKeywordAfter(keyword, newKeyword); + return this; + } - @Override - public String toString() { - return modifiers == null || modifiers.size() == 0 ? super.toString() : modifiers + " " + super.toString(); - } + @Override + public String toString() { + return modifiers == null || modifiers.size() == 0 ? super.toString() : modifiers + " " + super.toString(); + } - public void debug() { - System.out.println(line.text + LineUtils.getSpaces(100 - line.text.length()) + ">>> " + syntax + " " - + super.debugTokens()); - for (Element element : children) { - element.debug(); - } - } + public void debug() { + System.out.println(line.text + LineUtils.getSpaces(100 - line.text.length()) + ">>> " + syntax + " " + super.debugTokens()); + for (Element element : children) { + element.debug(); + } + } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Modifiers.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Modifiers.java index 6b17d57d..21f03f45 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Modifiers.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Modifiers.java @@ -4,12 +4,13 @@ import java.util.List; import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.core.element.frame.KeywordTokenBox; +import com.gitee.spirit.core.element.frame.Semantic; import com.google.common.base.Joiner; public class Modifiers extends KeywordTokenBox { public Modifiers(List tokens) { - super(ListUtils.filterStoppable(tokens, token -> token.isModifier())); + super(ListUtils.seekAll(tokens, Semantic::isModifier)); } @Override diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Statement.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Statement.java index 72f5e509..d0ead9c3 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Statement.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Statement.java @@ -9,33 +9,33 @@ import com.google.common.base.Joiner; public class Statement extends KeywordTokenBox { - public Statement(List tokens) { - super(tokens); - } - - public Statement subStmt(int fromIndex, int toIndex) { - return new Statement(subTokens(fromIndex, toIndex)); - } - - public Statement subStmt(String fromStr, String toStr) { - return subStmt(indexOf(fromStr) + 1, lastIndexOf(toStr)); - } - - public List splitStmt(String separator) { - return Splitter.splitByMatcherTrim(this, token -> isSymbol(token) && separator.equals(token.toString()), list -> new Statement(list)); - } - - @Override - public String toString() { - return Joiner.on("").join(StmtFormat.format(this)); - } - - public String debugTokens() { - StringBuilder builder = new StringBuilder(); - for (Token token : this) { - builder.append(token.debug() + " "); - } - return builder.toString().trim(); - } + public Statement(List tokens) { + super(tokens); + } + + public Statement subStmt(int fromIndex, int toIndex) { + return new Statement(subTokens(fromIndex, toIndex)); + } + + public Statement subStmt(String fromStr, String toStr) { + return subStmt(indexOf(fromStr) + 1, lastIndexOf(toStr)); + } + + public List splitStmt(String separator) { + return Splitter.splitByMatcherTrim(this, token -> isSymbol(token) && separator.equals(token.toString()), Statement::new); + } + + @Override + public String toString() { + return Joiner.on("").join(StmtFormat.format(this)); + } + + public String debugTokens() { + StringBuilder builder = new StringBuilder(); + for (Token token : this) { + builder.append(token.debug()).append(" "); + } + return builder.toString().trim(); + } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java index c247cf97..dba091b1 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java @@ -38,7 +38,7 @@ public class TokenBox extends MappableList { } public void replaceTokens(int fromIndex, int toIndex, Token token) { - ListUtils.removeByIndex(this, fromIndex, toIndex); + ListUtils.removeAllByIndex(this, fromIndex, toIndex); add(fromIndex, token); } @@ -51,7 +51,7 @@ public class TokenBox extends MappableList { } public List splitTokens(String separator) { - return Splitter.splitByMatcherTrim(this, token -> isSymbol(token) && separator.equals(token.toString()), list -> new TokenBox(list)); + return Splitter.splitByMatcherTrim(this, token -> isSymbol(token) && separator.equals(token.toString()), TokenBox::new); } public int indexOf(String str) { -- Gitee From 6612f9a0f5c9e43d87e6c664e04a5ebfb486d732 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Thu, 1 Jul 2021 13:20:53 +0800 Subject: [PATCH 42/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/api/ClassResolver.java | 2 +- .../core/clazz/DefaultClassResolver.java | 5 +++- .../spirit/core/compile/AutoImporter.java | 28 +++++++++---------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassResolver.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassResolver.java index 6eb213ff..721643e7 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassResolver.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassResolver.java @@ -9,6 +9,6 @@ public interface ClassResolver { Map resolve(String packageStr, Document document); - Document getDocument(IClass clazz); + Document findDocument(IClass clazz); } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java index a4524e05..b00f45a0 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java @@ -87,6 +87,9 @@ public class DefaultClassResolver implements ClassResolver { mainClass = new IClass(imports, copyAnnotations(annotations), element.addModifiers(KeywordEnum.PUBLIC.value)); initClass(mainClass, packageStr, fields, methods); classes.put(mainClass.getClassName(), mainClass); + //追加到文档中 + document.add(element); + document.add(builder.build("}")); } //进行关系绑定 @@ -96,7 +99,7 @@ public class DefaultClassResolver implements ClassResolver { } @Override - public Document getDocument(IClass clazz) { + public Document findDocument(IClass clazz) { return classDocumentMap.get(clazz); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java index 8b7dc348..311a3d21 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java @@ -4,6 +4,8 @@ import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.gitee.spirit.core.api.ClassResolver; +import com.gitee.spirit.core.element.entity.Document; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -17,11 +19,13 @@ import com.gitee.spirit.core.element.entity.Element; @Component public class AutoImporter { - public static final String STRING_REGEX = "(?<=\").*?(?=\")";// 把字符串都替换掉 - public static final Pattern TYPE_PATTERN = Pattern.compile("(\\b[A-Z]+\\w+\\b)");// 间接排除了泛型类型T + // 把字符串都替换掉 + public static final String STRING_REGEX = "(?<=\").*?(?=\")"; + // 间接排除了泛型类型T + public static final Pattern TYPE_PATTERN = Pattern.compile("(\\b[A-Z]+\\w+\\b)"); @Autowired - public ElementBuilder builder; + public ClassResolver resolver; @Autowired public SemanticParser parser; @@ -30,23 +34,17 @@ public class AutoImporter { classNames.forEach(clazz::addImport); } - /** - * 这里不使用document对象的原因是,它包含多个类型,扫描之后,无法区分一个引用类型是归属哪个类的 - */ public Set dependencies(IClass clazz) { + Document document = resolver.findDocument(clazz); + List elements = document.findElements(clazz.element); Set classNames = new HashSet<>(); - // 将注解转成字符串,并重新构建Element对象 - List elements = new ArrayList<>(); - clazz.annotations.forEach((annotation) -> elements.add(builder.build(annotation.toString()))); - visitElements(clazz, classNames, elements); - // 遍历class内容 - visitElements(clazz, classNames, Collections.singletonList(clazz.element)); - // 排除了自身 + visitElements(clazz, elements, classNames); + // 排除自身 classNames.remove(clazz.getClassName()); return classNames; } - public void visitElements(IClass clazz, Set classNames, List elements) { + public void visitElements(IClass clazz, List elements, Set classNames) { for (Element element : elements) { String line = element.line.text; // 剔除掉字符串 @@ -62,7 +60,7 @@ public class AutoImporter { } // 处理子节点 if (element.hasChild()) { - visitElements(clazz, classNames, element.children); + visitElements(clazz, element.children, classNames); } } } -- Gitee From 110dd923fdde16ad672dac9ac2caba38b9ed3189 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Thu, 1 Jul 2021 14:35:18 +0800 Subject: [PATCH 43/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/function/Function.java | 25 +++++++ .../gitee/spirit/common/utils/ListUtils.java | 69 +++++++------------ .../gitee/spirit/common/utils/Splitter.java | 15 ++-- .../element/action/DefaultTreeBuilder.java | 2 +- .../spirit/core/element/entity/Statement.java | 2 +- .../spirit/core/element/frame/TokenBox.java | 2 +- 6 files changed, 56 insertions(+), 59 deletions(-) create mode 100644 spirit-common/src/main/java/com/gitee/spirit/common/function/Function.java diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/function/Function.java b/spirit-common/src/main/java/com/gitee/spirit/common/function/Function.java new file mode 100644 index 00000000..68ec22fd --- /dev/null +++ b/spirit-common/src/main/java/com/gitee/spirit/common/function/Function.java @@ -0,0 +1,25 @@ +package com.gitee.spirit.common.function; + +public class Function { + + public interface Matcher { + boolean accept(T t); + } + + public interface Consumer { + Object accept(T t); + } + + public interface Factory { + Object accept(T t); + } + + public interface Visitor { + void accept(int index, T t); + } + + public interface Scorer { + Integer accept(T t); + } + +} diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java index 3612e6d8..110934e6 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java @@ -1,28 +1,23 @@ package com.gitee.spirit.common.utils; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; +import com.gitee.spirit.common.function.Function; public class ListUtils { - @SafeVarargs public static List asListNonNull(T... items) { - if (items == null || items.length == 0) { - return new ArrayList<>(); - } - List list = new ArrayList<>(items.length); - for (T item : items) { - if (item != null) { - list.add(item); - } - } - return list; + Assert.notNull(items, "The parameter items cannot be null!"); + return Arrays.stream(items).filter(Objects::nonNull).collect(Collectors.toList()); } - public static int indexOf(List list, int fromIndex, int toIndex, Matcher matcher) { + public static int indexOf(List list, int fromIndex, int toIndex, Function.Matcher matcher) { int step = toIndex >= fromIndex ? 1 : -1; for (int index = fromIndex; index != toIndex; index += step) { if (matcher.accept(list.get(index))) { @@ -32,24 +27,24 @@ public class ListUtils { return -1; } - public static int seekIndexOf(List list, int fromIndex, int toIndex, Matcher matcher) { + public static int seekIndexOf(List list, int fromIndex, int toIndex, Function.Matcher matcher) { int index = indexOf(list, fromIndex, toIndex, item -> !matcher.accept(item)); return index == -1 ? toIndex : index; } - public static int indexOf(List list, int fromIndex, Matcher matcher) { + public static int indexOf(List list, int fromIndex, Function.Matcher matcher) { return indexOf(list, fromIndex, list.size(), matcher); } - public static int indexOf(List list, Matcher matcher) { + public static int indexOf(List list, Function.Matcher matcher) { return indexOf(list, 0, list.size(), matcher); } - public static int lastIndexOf(List list, Matcher matcher) { + public static int lastIndexOf(List list, Function.Matcher matcher) { return indexOf(list, list.size() - 1, -1, matcher); } - public static T removeOne(List list, Matcher matcher) { + public static T removeOne(List list, Function.Matcher matcher) { int index = indexOf(list, matcher); return index >= 0 ? list.remove(index) : null; } @@ -58,20 +53,20 @@ public class ListUtils { list.subList(fromIndex, toIndex).clear(); } - public static T findOneByIndex(List list, int fromIndex, int toIndex, Matcher matcher) { + public static T findOneByIndex(List list, int fromIndex, int toIndex, Function.Matcher matcher) { int index = indexOf(list, fromIndex, toIndex, matcher); return index >= 0 ? list.get(index) : null; } - public static T findOne(Iterable collection, Matcher matcher) { + public static T findOne(Iterable collection, Function.Matcher matcher) { return CollUtil.findOne(collection, matcher::accept); } - public static List findAll(List list, Matcher matcher) { + public static List findAll(List list, Function.Matcher matcher) { return CollUtil.filterNew(list, matcher::accept); } - public static List seekAll(List list, Matcher matcher) { + public static List seekAll(List list, Function.Matcher matcher) { int index = seekIndexOf(list, 0, list.size(), matcher); List view = list.subList(0, index); List items = new ArrayList<>(view); @@ -80,24 +75,24 @@ public class ListUtils { } @SuppressWarnings("unchecked") - public static List seekAll(List list, Matcher matcher, Factory factory) { + public static List seekAll(List list, Function.Matcher matcher, Function.Factory factory) { List items = seekAll(list, matcher); List list0 = new ArrayList<>(); items.forEach(item -> list0.add((V) factory.accept(item))); return list0; } - public static void visit(List list, Visitor visitor) { + public static void visitAll(List list, Function.Visitor visitor) { for (int index = 0; index < list.size(); index++) { visitor.accept(index, list.get(index)); } } - public static T findOneByScore(Iterable collection, Selector selector) { + public static T findOneByScore(Iterable collection, Function.Scorer scorer) { Integer maxScore = null; T finalItem = null; for (T item : collection) { - Integer score = selector.accept(item); + Integer score = scorer.accept(item); if (score != null) { Assert.isFalse(maxScore != null && maxScore.intValue() == score.intValue(), "The score cannot be the same!"); if (maxScore == null || score > maxScore) { @@ -110,9 +105,9 @@ public class ListUtils { } @SuppressWarnings("unchecked") - public static V collectOne(List list, Factory factory) { + public static V collectOne(List list, Function.Consumer consumer) { for (T item : list) { - Object object = factory.accept(item); + Object object = consumer.accept(item); if (object != null) { return (V) object; } @@ -121,29 +116,13 @@ public class ListUtils { } @SuppressWarnings("unchecked") - public static V collectOne(List list, Matcher matcher, Factory factory) { + public static V collectOne(List list, Function.Matcher matcher, Function.Consumer consumer) { for (T item : list) { if (matcher.accept(item)) { - return (V) factory.accept(item); + return (V) consumer.accept(item); } } return null; } - public interface Matcher { - boolean accept(T t); - } - - public interface Factory { - Object accept(T t); - } - - public interface Visitor { - void accept(int index, T t); - } - - public interface Selector { - Integer accept(T t); - } - } diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/Splitter.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/Splitter.java index 61b59e30..a9886f6a 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/Splitter.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/Splitter.java @@ -4,10 +4,11 @@ import java.util.ArrayList; import java.util.List; import cn.hutool.core.collection.CollUtil; +import com.gitee.spirit.common.function.Function; public class Splitter { - public static List> splitByMatcherTrim(List list, Matcher matcher) { + public static List> split(List list, Function.Matcher matcher) { int[] indexes = CollUtil.indexOfAll(list, matcher::accept); List> subLists = new ArrayList<>(); int lastIndex = 0; @@ -24,19 +25,11 @@ public class Splitter { } @SuppressWarnings("unchecked") - public static List splitByMatcherTrim(List list, Matcher matcher, Factory> factory) { - List> subLists = splitByMatcherTrim(list, matcher); + public static List split(List list, Function.Matcher matcher, Function.Factory> factory) { + List> subLists = split(list, matcher); List anotherList = new ArrayList<>(); subLists.forEach(subList -> anotherList.add((V) factory.accept(subList))); return anotherList; } - public interface Matcher { - boolean accept(T t); - } - - public interface Factory { - Object accept(T t); - } - } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java index 97b7b218..716c0c3b 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultTreeBuilder.java @@ -25,7 +25,7 @@ public class DefaultTreeBuilder extends AbstractTreeBuilder { @Override public List buildNodes(List tokens) { final List nodes = new ArrayList<>(); - ListUtils.visit(tokens, (index, token) -> { + ListUtils.visitAll(tokens, (index, token) -> { if (token.hasSubStmt()) { SyntaxTree syntaxTree = buildTree(token.getValue()); token = new Token(token.tokenType, syntaxTree, token.attributes); diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Statement.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Statement.java index d0ead9c3..a388e9ed 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Statement.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Statement.java @@ -22,7 +22,7 @@ public class Statement extends KeywordTokenBox { } public List splitStmt(String separator) { - return Splitter.splitByMatcherTrim(this, token -> isSymbol(token) && separator.equals(token.toString()), Statement::new); + return Splitter.split(this, token -> isSymbol(token) && separator.equals(token.toString()), Statement::new); } @Override diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java index dba091b1..18fe5898 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/TokenBox.java @@ -51,7 +51,7 @@ public class TokenBox extends MappableList { } public List splitTokens(String separator) { - return Splitter.splitByMatcherTrim(this, token -> isSymbol(token) && separator.equals(token.toString()), TokenBox::new); + return Splitter.split(this, token -> isSymbol(token) && separator.equals(token.toString()), TokenBox::new); } public int indexOf(String str) { -- Gitee From a2e144379173289352aacc6610feed40798e0eb8 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Thu, 1 Jul 2021 14:36:06 +0800 Subject: [PATCH 44/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/spirit/common/function/Function.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/function/Function.java b/spirit-common/src/main/java/com/gitee/spirit/common/function/Function.java index 68ec22fd..4312a01b 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/function/Function.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/function/Function.java @@ -1,24 +1,24 @@ package com.gitee.spirit.common.function; -public class Function { +public interface Function { - public interface Matcher { + interface Matcher { boolean accept(T t); } - public interface Consumer { + interface Consumer { Object accept(T t); } - public interface Factory { + interface Factory { Object accept(T t); } - public interface Visitor { + interface Visitor { void accept(int index, T t); } - public interface Scorer { + interface Scorer { Integer accept(T t); } -- Gitee From 8ebc021facdb83e553435ba847a8a2e35f3d0d31 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Thu, 1 Jul 2021 14:45:19 +0800 Subject: [PATCH 45/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/enums/PrimitiveEnum.java | 174 +++++++++--------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/PrimitiveEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/PrimitiveEnum.java index fc3efe35..763e9ee6 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/enums/PrimitiveEnum.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/PrimitiveEnum.java @@ -7,92 +7,92 @@ import cn.hutool.core.lang.Assert; public enum PrimitiveEnum { - VOID("void", "void", "void", true/* primitive */, false), // - BOOLEAN("boolean", "boolean", "boolean", true/* primitive */, false), // - CHAR("char", "char", "char", true/* primitive */, false), // - BYTE("byte", "byte", "byte", true/* primitive */, false), // - SHORT("short", "short", "short", true/* primitive */, false), // - INT("int", "int", "int", true/* primitive */, false), // - LONG("long", "long", "long", true/* primitive */, false), // - FLOAT("float", "float", "float", true/* primitive */, false), // - DOUBLE("double", "double", "double", true/* primitive */, false), // - - BOOLEAN_ARRAY("[Z", "boolean[]", "boolean[]", false, true/* array */), // - CHAR_ARRAY("[C", "char[]", "char[]", false, true/* array */), // - BYTE_ARRAY("[B", "byte[]", "byte[]", false, true/* array */), // - SHORT_ARRAY("[S", "short[]", "short[]", false, true/* array */), // - INT_ARRAY("[I", "int[]", "int[]", false, true/* array */), // - LONG_ARRAY("[J", "long[]", "long[]", false, true/* array */), // - FLOAT_ARRAY("[F", "float[]", "float[]", false, true/* array */), // - DOUBLE_ARRAY("[D", "double[]", "double[]", false, true/* array */); // - - public static final Map CLASS_NAME_MAPPING = new ConcurrentHashMap<>(); - public static final Map SIMPLE_NAME_MAPPING = new ConcurrentHashMap<>(); - public static final String PRIMITIVE_ENUM = "void|boolean|char|byte|short|int|long|float|double"; - - static { - for (PrimitiveEnum primitiveEnum : values()) { - CLASS_NAME_MAPPING.put(primitiveEnum.className, primitiveEnum); - SIMPLE_NAME_MAPPING.put(primitiveEnum.simpleName, primitiveEnum); - } - bindPrimitive(BOOLEAN, BOOLEAN_ARRAY); - bindPrimitive(CHAR, CHAR_ARRAY); - bindPrimitive(BYTE, BYTE_ARRAY); - bindPrimitive(SHORT, SHORT_ARRAY); - bindPrimitive(INT, INT_ARRAY); - bindPrimitive(LONG, LONG_ARRAY); - bindPrimitive(FLOAT, FLOAT_ARRAY); - bindPrimitive(DOUBLE, DOUBLE_ARRAY); - } - - public static void bindPrimitive(PrimitiveEnum primitive, PrimitiveEnum primitiveArray) { - primitive.pointer = primitiveArray; - primitiveArray.pointer = primitive; - } - - public static boolean isPrimitive(String className) { - return CLASS_NAME_MAPPING.containsKey(className) && CLASS_NAME_MAPPING.get(className).isPrimitive; - } - - public static boolean isPrimitiveArray(String className) { - return CLASS_NAME_MAPPING.containsKey(className) && CLASS_NAME_MAPPING.get(className).isArray; - } - - public static boolean isPrimitiveBySimple(String simpleName) { - return SIMPLE_NAME_MAPPING.containsKey(simpleName) && SIMPLE_NAME_MAPPING.get(simpleName).isPrimitive; - } - - public static boolean isPrimitiveArrayBySimple(String simpleName) { - return SIMPLE_NAME_MAPPING.containsKey(simpleName) && SIMPLE_NAME_MAPPING.get(simpleName).isArray; - } - - public static String getTargetName(String className) { - Assert.isTrue(isPrimitiveArray(className), "Class name must be a primitive array!"); - return CLASS_NAME_MAPPING.get(className).pointer.className; - } - - public static String getArrayName(String className) { - Assert.isTrue(isPrimitive(className), "Class name must be a primitive!"); - return CLASS_NAME_MAPPING.get(className).pointer.className; - } - - public static String findClassName(String simpleName) { - return SIMPLE_NAME_MAPPING.containsKey(simpleName) ? SIMPLE_NAME_MAPPING.get(simpleName).className : null; - } - - public String className; - public String simpleName; - public String typeName; - public boolean isPrimitive; - public boolean isArray; - public PrimitiveEnum pointer; - - private PrimitiveEnum(String className, String simpleName, String typeName, boolean isPrimitive, boolean isArray) { - this.className = className; - this.simpleName = simpleName; - this.typeName = typeName; - this.isPrimitive = isPrimitive; - this.isArray = isArray; - } + VOID("void", "void", "void", true, false), // + BOOLEAN("boolean", "boolean", "boolean", true, false), // + CHAR("char", "char", "char", true, false), // + BYTE("byte", "byte", "byte", true, false), // + SHORT("short", "short", "short", true, false), // + INT("int", "int", "int", true, false), // + LONG("long", "long", "long", true, false), // + FLOAT("float", "float", "float", true, false), // + DOUBLE("double", "double", "double", true, false), // + + BOOLEAN_ARRAY("[Z", "boolean[]", "boolean[]", false, true), // + CHAR_ARRAY("[C", "char[]", "char[]", false, true), // + BYTE_ARRAY("[B", "byte[]", "byte[]", false, true), // + SHORT_ARRAY("[S", "short[]", "short[]", false, true), // + INT_ARRAY("[I", "int[]", "int[]", false, true), // + LONG_ARRAY("[J", "long[]", "long[]", false, true), // + FLOAT_ARRAY("[F", "float[]", "float[]", false, true), // + DOUBLE_ARRAY("[D", "double[]", "double[]", false, true); // + + public static final Map CLASS_NAME_MAPPING = new ConcurrentHashMap<>(); + public static final Map SIMPLE_NAME_MAPPING = new ConcurrentHashMap<>(); + public static final String PRIMITIVE_ENUM = "void|boolean|char|byte|short|int|long|float|double"; + + static { + for (PrimitiveEnum primitiveEnum : values()) { + CLASS_NAME_MAPPING.put(primitiveEnum.className, primitiveEnum); + SIMPLE_NAME_MAPPING.put(primitiveEnum.simpleName, primitiveEnum); + } + bindPrimitive(BOOLEAN, BOOLEAN_ARRAY); + bindPrimitive(CHAR, CHAR_ARRAY); + bindPrimitive(BYTE, BYTE_ARRAY); + bindPrimitive(SHORT, SHORT_ARRAY); + bindPrimitive(INT, INT_ARRAY); + bindPrimitive(LONG, LONG_ARRAY); + bindPrimitive(FLOAT, FLOAT_ARRAY); + bindPrimitive(DOUBLE, DOUBLE_ARRAY); + } + + public static void bindPrimitive(PrimitiveEnum primitive, PrimitiveEnum primitiveArray) { + primitive.pointer = primitiveArray; + primitiveArray.pointer = primitive; + } + + public static boolean isPrimitive(String className) { + return CLASS_NAME_MAPPING.containsKey(className) && CLASS_NAME_MAPPING.get(className).isPrimitive; + } + + public static boolean isPrimitiveArray(String className) { + return CLASS_NAME_MAPPING.containsKey(className) && CLASS_NAME_MAPPING.get(className).isArray; + } + + public static boolean isPrimitiveBySimple(String simpleName) { + return SIMPLE_NAME_MAPPING.containsKey(simpleName) && SIMPLE_NAME_MAPPING.get(simpleName).isPrimitive; + } + + public static boolean isPrimitiveArrayBySimple(String simpleName) { + return SIMPLE_NAME_MAPPING.containsKey(simpleName) && SIMPLE_NAME_MAPPING.get(simpleName).isArray; + } + + public static String getTargetName(String className) { + Assert.isTrue(isPrimitiveArray(className), "Class name must be a primitive array!"); + return CLASS_NAME_MAPPING.get(className).pointer.className; + } + + public static String getArrayName(String className) { + Assert.isTrue(isPrimitive(className), "Class name must be a primitive!"); + return CLASS_NAME_MAPPING.get(className).pointer.className; + } + + public static String findClassName(String simpleName) { + return SIMPLE_NAME_MAPPING.containsKey(simpleName) ? SIMPLE_NAME_MAPPING.get(simpleName).className : null; + } + + public String className; + public String simpleName; + public String typeName; + public boolean isPrimitive; + public boolean isArray; + public PrimitiveEnum pointer; + + private PrimitiveEnum(String className, String simpleName, String typeName, boolean isPrimitive, boolean isArray) { + this.className = className; + this.simpleName = simpleName; + this.typeName = typeName; + this.isPrimitive = isPrimitive; + this.isArray = isArray; + } } -- Gitee From 985cf7c91de682634aad5cafaf7525557cd8facf Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Thu, 1 Jul 2021 15:41:01 +0800 Subject: [PATCH 46/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/clazz/utils/TypeVisitor.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java index ca6b885e..876b2e03 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/utils/TypeVisitor.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import com.gitee.spirit.common.function.Function; import com.gitee.spirit.core.clazz.entity.IType; import com.google.common.base.Joiner; @@ -11,7 +12,7 @@ import cn.hutool.core.lang.Assert; public class TypeVisitor { - public static IType forEachType(IType targetType, Consumer consumer) { + public static IType forEachType(IType targetType, Function.Consumer consumer) { Assert.notNull(targetType, "Target Type cannot be null!"); // 拷贝一份 IType newType = (IType) consumer.accept(TypeBuilder.copy(targetType)); @@ -25,7 +26,7 @@ public class TypeVisitor { return newType; } - public static IType forEachType(IType referType, IType targetType, Consumer0 consumer) { + public static IType forEachType(IType referType, IType targetType, Consumer consumer) { Assert.notNull(targetType, "Target Type cannot be null!"); // 拷贝一份 IType newType = (IType) consumer.accept(referType, TypeBuilder.copy(targetType)); @@ -41,7 +42,7 @@ public class TypeVisitor { return newType; } - public static String forEachTypeName(IType targetType, Consumer consumer) { + public static String forEachTypeName(IType targetType, Function.Consumer consumer) { Assert.notNull(targetType, "Target Type cannot be null!"); String typeName = (String) consumer.accept(targetType); if (targetType.isGenericType()) { @@ -55,10 +56,6 @@ public class TypeVisitor { } public interface Consumer { - Object accept(T t); - } - - public interface Consumer0 { Object accept(T t, T t1); } -- Gitee From 65b8b6184eae25a8e12dbe59c858a3f98506c131 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Thu, 1 Jul 2021 18:37:51 +0800 Subject: [PATCH 47/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/output/java/ExtClassLoader.java | 114 ++++---- .../gitee/spirit/output/java/JavaBuilder.java | 250 +++++++++--------- 2 files changed, 182 insertions(+), 182 deletions(-) diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java index e47049d8..64315e89 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java @@ -22,70 +22,70 @@ import com.google.common.base.Splitter; @DependsOn("configUtils") public class ExtClassLoader extends AbstractClassLoader> implements InitializingBean { - public ClassLoader loader; + public ClassLoader loader; - @Override - public void afterPropertiesSet() throws Exception { - String classpathsStr = ConfigUtils.getClassPaths(); - if (StringUtils.isNotBlank(classpathsStr)) { - List classpaths = Splitter.on(",").trimResults().splitToList(classpathsStr); - loader = ReflectUtils.getClassLoader(classpaths); - } else { - loader = this.getClass().getClassLoader(); - } - } + @Override + public void afterPropertiesSet() { + String classPathsStr = ConfigUtils.getClassPaths(); + if (StringUtils.isNotBlank(classPathsStr)) { + List classPaths = Splitter.on(",").trimResults().splitToList(classPathsStr); + loader = ReflectUtils.getClassLoader(classPaths); + } else { + loader = this.getClass().getClassLoader(); + } + } - @Override - public List getResources(String name) { - try { - List urls = new ArrayList<>(); - Enumeration enumeration = loader.getResources(name); - while (enumeration.hasMoreElements()) { - URL url = (URL) enumeration.nextElement(); - urls.add(url); - } - return urls; - } catch (IOException e) { - throw new RuntimeException(e); - } - } + @Override + public List getResources(String name) { + try { + List urls = new ArrayList<>(); + Enumeration enumeration = loader.getResources(name); + while (enumeration.hasMoreElements()) { + URL url = enumeration.nextElement(); + urls.add(url); + } + return urls; + } catch (IOException e) { + throw new RuntimeException(e); + } + } - @Override - public List getNames() { - throw new RuntimeException("This method is not supported!"); - } + @Override + public List getNames() { + throw new RuntimeException("This method is not supported!"); + } - @Override - public boolean contains(String name) { - try { - return loadClass(name) != null; - } catch (Exception e) { - return false; - } - } + @Override + public boolean contains(String name) { + try { + return loadClass(name) != null; + } catch (Exception e) { + return false; + } + } - @Override - public Class loadClass(String name) { - try { - return loader.loadClass(name); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } + @Override + public Class loadClass(String name) { + try { + return loader.loadClass(name); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } - @Override - public List> getAllClasses() { - throw new RuntimeException("This method is not supported!"); - } + @Override + public List> getAllClasses() { + throw new RuntimeException("This method is not supported!"); + } - @Override - public URL getResource(String name) { - return loader.getResource(name); - } + @Override + public URL getResource(String name) { + return loader.getResource(name); + } - @Override - public Class defineClass(String name, URL resource) { - throw new RuntimeException("This method is not supported!"); - } + @Override + public Class defineClass(String name, URL resource) { + throw new RuntimeException("This method is not supported!"); + } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/JavaBuilder.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/JavaBuilder.java index 35dd4180..f2bf6e17 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/JavaBuilder.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/JavaBuilder.java @@ -21,130 +21,130 @@ import com.gitee.spirit.output.java.action.AbstractExtElementAction; @Component public class JavaBuilder implements CodeBuilder { - public static final String IMPLEMENTS_KEYWORD = "implements"; - public static final String SYNCHRONIZED_KEYWORD = "synchronized"; - public static final String FINAL_KEYWORD = "final"; - - @Autowired - public AutoImporter importer; - @Autowired - public List actions; - - @Override - public String build(IClass clazz) { - String body = buildBody(clazz); - String head = buildHead(clazz); - return new StringBuilder().append(head).append(body).toString(); - } - - public String buildHead(IClass clazz) { - StringBuilder builder = new StringBuilder(); - // package - builder.append(String.format("package %s;\n\n", clazz.packageStr)); - // import - List imports = clazz.getImports(); - imports.forEach((imp) -> builder.append(imp.element + ";\n")); - // static import - List staticImports = clazz.getStaticImports(); - staticImports.forEach((imp) -> builder.append(imp.element + ";\n")); - if (imports.size() > 0 || staticImports.size() > 0) { - builder.append("\n"); - } - // annotation - clazz.annotations.forEach((annotation) -> builder.append(annotation + "\n")); - return builder.toString(); - } - - public String buildBody(IClass clazz) { - StringBuilder classStr = new StringBuilder(); - // 处理一部分关键字 - clazz.element.insertKeywordAfter(KeywordEnum.ABSTRACT.value, KeywordEnum.CLASS.value); - clazz.element.replaceKeyword(KeywordEnum.IMPLS.value, JavaBuilder.IMPLEMENTS_KEYWORD); - classStr.append(clazz.element + "\n\n"); - // 当构建方法体时,需要动态引入一些类型和字段,所以先构建方法体 - String methodsStr = buildMethods(clazz); - String fieldsStr = buildFields(clazz); - classStr.append(fieldsStr).append(methodsStr).append("}\n"); - return classStr.toString(); - } - - public String buildFields(IClass clazz) { - // fields - StringBuilder fieldsStr = new StringBuilder(); - // public static type + element - for (IField field : clazz.fields) { - // annotation - field.annotations.forEach((annotation) -> fieldsStr.append("\t" + annotation + "\n")); - field.element.replaceModifier(KeywordEnum.CONST.value, JavaBuilder.FINAL_KEYWORD); - fieldsStr.append("\t" + convert(clazz, field, field.element) + "\n"); - } - if (fieldsStr.length() > 0) { - fieldsStr.append("\n"); - } - return fieldsStr.toString(); - } - - public String buildMethods(IClass clazz) { - // 当构建方法体时,需要动态引入一些类型和字段,所以先构建方法体 - StringBuilder methodsStr = new StringBuilder(); - // public static type + element - for (IMethod method : clazz.methods) { - // annotation - method.annotations.forEach((annotation) -> methodsStr.append("\t" + annotation + "\n")); - - Element element = method.element; - // 静态主方法 - if (method.isStatic() && "main".equals(method.getName())) { - methodsStr.append("\tpublic static void main(String[] args) {\n"); - - } else {// public User() // public static synchronized String methodName() - // 替换关键字 - element.replaceModifier(KeywordEnum.SYNCH.value, JavaBuilder.SYNCHRONIZED_KEYWORD); - if (element.isDeclareFunc()) { - // 抽象类型的没有方法体的方法,需要加上abstract关键字 - if (clazz.isAbstract() && !method.isStatic() && !element.hasChild()) { - element.insertModifier(KeywordEnum.PUBLIC.value, KeywordEnum.ABSTRACT.value); - } - - if (element.hasChild()) { - methodsStr.append("\t" + element + "\n"); - } else { - methodsStr.append("\t" + element + ";\n\n"); - } - - } else if (element.isFunc()) { - if (method.isInit()) { - element.removeKeyword(KeywordEnum.FUNC.value); - } else { - element.replaceKeyword(KeywordEnum.FUNC.value, importer.getFinalName(clazz, method.getType())); - } - methodsStr.append("\t" + element + "\n"); - } - } - // 方法体可能没有内容,但是这并不意味着这个方法没有被实现 - if (element.hasChild()) { - convertMethodElement(methodsStr, "\t\t", clazz, method, method.element); - methodsStr.append("\t}\n\n"); - } - } - return methodsStr.toString(); - } - - public void convertMethodElement(StringBuilder builder, String indent, IClass clazz, IMethod method, - Element father) { - for (Element element : father.children) { - builder.append(indent + convert(clazz, method, element) + "\n"); - if (element.hasChild()) { - convertMethodElement(builder, indent + "\t", clazz, method, element); - } - } - } - - public Element convert(IClass clazz, MemberEntity member, Element element) { - for (ElementAction action : actions) { - action.visitElement(new VisitContext(clazz, member), element); - } - return element; - } + public static final String IMPLEMENTS_KEYWORD = "implements"; + public static final String SYNCHRONIZED_KEYWORD = "synchronized"; + public static final String FINAL_KEYWORD = "final"; + + @Autowired + public AutoImporter importer; + @Autowired + public List actions; + + @Override + public String build(IClass clazz) { + String body = buildBody(clazz); + String head = buildHead(clazz); + return new StringBuilder().append(head).append(body).toString(); + } + + public String buildHead(IClass clazz) { + StringBuilder builder = new StringBuilder(); + // package + builder.append(String.format("package %s;\n\n", clazz.packageStr)); + // import + List imports = clazz.getImports(); + imports.forEach((imp) -> builder.append(imp.element + ";\n")); + // static import + List staticImports = clazz.getStaticImports(); + staticImports.forEach((imp) -> builder.append(imp.element + ";\n")); + if (imports.size() > 0 || staticImports.size() > 0) { + builder.append("\n"); + } + // annotation + clazz.annotations.forEach((annotation) -> builder.append(annotation + "\n")); + return builder.toString(); + } + + public String buildBody(IClass clazz) { + StringBuilder classStr = new StringBuilder(); + // 处理一部分关键字 + clazz.element.insertKeywordAfter(KeywordEnum.ABSTRACT.value, KeywordEnum.CLASS.value); + clazz.element.replaceKeyword(KeywordEnum.IMPLS.value, JavaBuilder.IMPLEMENTS_KEYWORD); + classStr.append(clazz.element + "\n\n"); + // 当构建方法体时,需要动态引入一些类型和字段,所以先构建方法体 + String methodsStr = buildMethods(clazz); + String fieldsStr = buildFields(clazz); + classStr.append(fieldsStr).append(methodsStr).append("}\n"); + return classStr.toString(); + } + + public String buildFields(IClass clazz) { + // fields + StringBuilder fieldsStr = new StringBuilder(); + // public static type + element + for (IField field : clazz.fields) { + // annotation + field.annotations.forEach((annotation) -> fieldsStr.append("\t" + annotation + "\n")); + field.element.replaceModifier(KeywordEnum.CONST.value, JavaBuilder.FINAL_KEYWORD); + fieldsStr.append("\t" + convert(clazz, field, field.element) + "\n"); + } + if (fieldsStr.length() > 0) { + fieldsStr.append("\n"); + } + return fieldsStr.toString(); + } + + public String buildMethods(IClass clazz) { + // 当构建方法体时,需要动态引入一些类型和字段,所以先构建方法体 + StringBuilder methodsStr = new StringBuilder(); + // public static type + element + for (IMethod method : clazz.methods) { + // annotation + method.annotations.forEach((annotation) -> methodsStr.append("\t" + annotation + "\n")); + + Element element = method.element; + // 静态主方法 + if (method.isStatic() && "main".equals(method.getName())) { + methodsStr.append("\tpublic static void main(String[] args) {\n"); + + } else {// public User() // public static synchronized String methodName() + // 替换关键字 + element.replaceModifier(KeywordEnum.SYNCH.value, JavaBuilder.SYNCHRONIZED_KEYWORD); + if (element.isDeclareFunc()) { + // 抽象类型的没有方法体的方法,需要加上abstract关键字 + if (clazz.isAbstract() && !method.isStatic() && !element.hasChild()) { + element.insertModifier(KeywordEnum.PUBLIC.value, KeywordEnum.ABSTRACT.value); + } + + if (element.hasChild()) { + methodsStr.append("\t" + element + "\n"); + } else { + methodsStr.append("\t" + element + ";\n\n"); + } + + } else if (element.isFunc()) { + if (method.isInit()) { + element.removeKeyword(KeywordEnum.FUNC.value); + } else { + element.replaceKeyword(KeywordEnum.FUNC.value, importer.getFinalName(clazz, method.getType())); + } + methodsStr.append("\t" + element + "\n"); + } + } + // 方法体可能没有内容,但是这并不意味着这个方法没有被实现 + if (element.hasChild()) { + convertMethodElement(methodsStr, "\t\t", clazz, method, method.element); + methodsStr.append("\t}\n\n"); + } + } + return methodsStr.toString(); + } + + public void convertMethodElement(StringBuilder builder, String indent, IClass clazz, IMethod method, + Element father) { + for (Element element : father.children) { + builder.append(indent + convert(clazz, method, element) + "\n"); + if (element.hasChild()) { + convertMethodElement(builder, indent + "\t", clazz, method, element); + } + } + } + + public Element convert(IClass clazz, MemberEntity member, Element element) { + for (ElementAction action : actions) { + action.visitElement(new VisitContext(clazz, member), element); + } + return element; + } } -- Gitee From 6988251cb6c35cafe09361f6949719dfed3be1ef Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Thu, 1 Jul 2021 18:39:04 +0800 Subject: [PATCH 48/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/spirit/core/clazz/frame/ImportEntity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java index d14a0312..21d14758 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java @@ -32,7 +32,7 @@ public abstract class ImportEntity extends AnnotationEntity { } public List getAliasImports() { - return imports.stream().filter(import0 -> import0.hasAlias()).collect(Collectors.toList()); + return imports.stream().filter(Import::hasAlias).collect(Collectors.toList()); } public List getStaticImports() { @@ -92,7 +92,7 @@ public abstract class ImportEntity extends AnnotationEntity { // 2.如果引入了,则不必引入了 Import import0 = findImport(targetName); if (import0 != null) { - return !import0.hasAlias() ? true : false; + return !import0.hasAlias(); } // 3.如果存在简称相同的,则也不能引入 @@ -132,7 +132,7 @@ public abstract class ImportEntity extends AnnotationEntity { public boolean shouldImport(String selfClassName, String className) { List selectors = SpringUtils.getBeans(ImportSelector.class); Boolean flag = ListUtils.collectOne(selectors, selector -> selector.canHandle(className), selector -> selector.shouldImport(selfClassName, className)); - return flag == null ? true : flag; + return flag == null || flag; } public abstract String getClassName(); -- Gitee From 1befa21633db72f53dcb75739f2d10ba2d98b7d4 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Thu, 1 Jul 2021 22:04:46 +0800 Subject: [PATCH 49/83] =?UTF-8?q?=E5=B0=86staticImport=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E5=87=BA=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=B9=B6=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E5=A4=A7=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/clazz/DefaultClassResolver.java | 1 + .../spirit/core/clazz/entity/Import.java | 46 ++-- .../spirit/core/clazz/frame/ImportEntity.java | 214 ++++++++---------- .../spirit/core/compile/AutoImporter.java | 1 - .../spirit/output/api/ImportManager.java | 16 ++ .../output/java/DefaultImportManager.java | 47 ++++ .../gitee/spirit/output/java/JavaBuilder.java | 34 +-- .../output/java/action/EmptyAction.java | 25 +- .../output/java/entity/StaticImport.java | 17 ++ 9 files changed, 232 insertions(+), 169 deletions(-) create mode 100644 spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/api/ImportManager.java create mode 100644 spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/DefaultImportManager.java create mode 100644 spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/StaticImport.java diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java index b00f45a0..d047fd47 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/DefaultClassResolver.java @@ -26,6 +26,7 @@ public class DefaultClassResolver implements ClassResolver { @Autowired public ElementBuilder builder; + public Map classDocumentMap = new ConcurrentHashMap<>(); @Override diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/Import.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/Import.java index 1d162e52..a9accbfc 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/Import.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/Import.java @@ -6,36 +6,32 @@ import com.gitee.spirit.core.element.entity.Element; public class Import extends ElementEntity { - public Import(Element element) { - super(element); - } + public Import(Element element) { + super(element); + } - public String getClassName() { - return element.getStr(1); - } + public String getClassName() { + return element.getStr(1); + } - public String getLastName() { - return TypeUtils.getLastName(getClassName()); - } + public String getLastName() { + return TypeUtils.getLastName(getClassName()); + } - public boolean hasAlias() { - return element.contains(2); - } + public boolean hasAlias() { + return element.contains(2); + } - public String getAlias() { - return hasAlias() ? element.getStr(2) : null; - } + public String getAlias() { + return hasAlias() ? element.getStr(2) : null; + } - public boolean matchSimpleName(String simpleName) { - return !hasAlias() ? getLastName().equals(simpleName) : getAlias().equals(simpleName); - } + public boolean matchSourceName(String sourceName) { + return getClassName().equals(sourceName); + } - public boolean matchClassName(String className) { - return getClassName().equals(className); - } - - public boolean matchStaticSourceName(String staticSourceName) { - return element.getStr(2).equals(staticSourceName); - } + public boolean matchLastName(String lastName) { + return !hasAlias() ? getLastName().equals(lastName) : getAlias().equals(lastName); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java index 21d14758..cc2e2638 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java @@ -18,123 +18,101 @@ import cn.hutool.core.lang.Assert; public abstract class ImportEntity extends AnnotationEntity { - public List imports; - public List staticImports; - - public ImportEntity(List imports, List annotations, Element element) { - super(annotations, element); - this.imports = imports != null ? new ArrayList<>(imports) : new ArrayList<>(); - this.staticImports = new ArrayList<>(); - } - - public List getImports() { - return imports.stream().filter(import0 -> !import0.hasAlias()).collect(Collectors.toList()); - } - - public List getAliasImports() { - return imports.stream().filter(Import::hasAlias).collect(Collectors.toList()); - } - - public List getStaticImports() { - return staticImports; - } - - public Import findImport(String className) { - return ListUtils.findOne(imports, import0 -> import0.matchClassName(className)); - } - - public Import findImportByLastName(String simpleName) { - return ListUtils.findOne(imports, import0 -> import0.matchSimpleName(simpleName)); - } - - public Import findStaticImport(String staticSourceName) { - return ListUtils.findOne(staticImports, import0 -> import0.matchStaticSourceName(staticSourceName)); - } - - public String findClassName(String simpleName) { - // 校验 - Assert.notContain(simpleName, ".", "Simple name cannot contains \".\""); - - // 如果传进来是个数组,那么处理一下 - String targetName = TypeUtils.getTargetName(simpleName); - boolean isArray = TypeUtils.isArray(simpleName); - - // 1.如果是基本类型,基本类型数组 - String className = PrimitiveEnum.findClassName(simpleName); - - // 2.首先先去引入里面找 - if (className == null) { - Import import0 = findImportByLastName(targetName); - className = import0 != null ? import0.getClassName() : null; - className = className != null ? TypeUtils.getClassName(isArray, className) : null; - } - - // 3.使用类加载器,进行查询 - if (className == null) { - className = findClassNameByLoader(targetName); - className = className != null ? TypeUtils.getClassName(isArray, className) : null; - } - - Assert.notNull(className, "No import info found!simpleName:[" + simpleName + "]"); - return className; - } - - public boolean addImport(String className) { - // 如果是数组,则把修饰符号去掉 - String targetName = TypeUtils.getTargetName(className); - String lastName = TypeUtils.getLastName(className); - - // 1. 原始类型不添加 - if (PrimitiveEnum.isPrimitive(targetName)) { - return true; - } - - // 2.如果引入了,则不必引入了 - Import import0 = findImport(targetName); - if (import0 != null) { - return !import0.hasAlias(); - } - - // 3.如果存在简称相同的,则也不能引入 - Import import1 = findImportByLastName(lastName); - if (import1 != null) { - return false; - } - - // 4.基础类型或拓展类型不添加 - if (!shouldImport(getClassName(), targetName)) { - return true; - } - - // 构建一个行元素 - ElementBuilder builder = SpringUtils.getBean(ElementBuilder.class); - imports.add(new Import(builder.build("import " + targetName))); - return true; - } - - public boolean addStaticImport(String staticSourceName) { - // 如果已经有了,直接返回true - Import import0 = findStaticImport(staticSourceName); - if (import0 != null) { - return true; - } - // 构建一个行元素 - ElementBuilder builder = SpringUtils.getBean(ElementBuilder.class); - staticImports.add(new Import(builder.build("import static " + staticSourceName))); - return true; - } - - public String findClassNameByLoader(String simpleName) { - List selectors = SpringUtils.getBeans(ImportSelector.class); - return ListUtils.collectOne(selectors, selector -> selector.findClassName(simpleName)); - } - - public boolean shouldImport(String selfClassName, String className) { - List selectors = SpringUtils.getBeans(ImportSelector.class); - Boolean flag = ListUtils.collectOne(selectors, selector -> selector.canHandle(className), selector -> selector.shouldImport(selfClassName, className)); - return flag == null || flag; - } - - public abstract String getClassName(); + public List imports; + + public ImportEntity(List imports, List annotations, Element element) { + super(annotations, element); + this.imports = imports != null ? new ArrayList<>(imports) : new ArrayList<>(); + } + + public List getImports() { + return ListUtils.findAll(imports, import0 -> !import0.hasAlias()); + } + + public List getAliasImports() { + return ListUtils.findAll(imports, Import::hasAlias); + } + + public Import findImport(String className) { + return ListUtils.findOne(imports, import0 -> import0.matchSourceName(className)); + } + + public Import findImportByLastName(String simpleName) { + return ListUtils.findOne(imports, import0 -> import0.matchLastName(simpleName)); + } + + public String findClassName(String simpleName) { + // 校验 + Assert.notContain(simpleName, ".", "Simple name cannot contains \".\""); + + // 如果传进来是个数组,那么处理一下 + String targetName = TypeUtils.getTargetName(simpleName); + boolean isArray = TypeUtils.isArray(simpleName); + + // 1.如果是基本类型,基本类型数组 + String className = PrimitiveEnum.findClassName(simpleName); + + // 2.首先先去引入里面找 + if (className == null) { + Import import0 = findImportByLastName(targetName); + className = import0 != null ? import0.getClassName() : null; + className = className != null ? TypeUtils.getClassName(isArray, className) : null; + } + + // 3.使用类加载器,进行查询 + if (className == null) { + className = findClassNameByLoader(targetName); + className = className != null ? TypeUtils.getClassName(isArray, className) : null; + } + + Assert.notNull(className, "No import info found!simpleName:[" + simpleName + "]"); + return className; + } + + public boolean addImport(String className) { + // 如果是数组,则把修饰符号去掉 + String targetName = TypeUtils.getTargetName(className); + String lastName = TypeUtils.getLastName(className); + + // 1. 原始类型不添加 + if (PrimitiveEnum.isPrimitive(targetName)) { + return true; + } + + // 2.如果引入了,则不必引入了 + Import import0 = findImport(targetName); + if (import0 != null) { + return !import0.hasAlias(); + } + + // 3.如果存在简称相同的,则也不能引入 + Import import1 = findImportByLastName(lastName); + if (import1 != null) { + return false; + } + + // 4.基础类型或拓展类型不添加 + if (!shouldImport(getClassName(), targetName)) { + return true; + } + + // 构建一个行元素 + ElementBuilder builder = SpringUtils.getBean(ElementBuilder.class); + imports.add(new Import(builder.build("import " + targetName))); + return true; + } + + public String findClassNameByLoader(String simpleName) { + List selectors = SpringUtils.getBeans(ImportSelector.class); + return ListUtils.collectOne(selectors, selector -> selector.findClassName(simpleName)); + } + + public boolean shouldImport(String selfClassName, String className) { + List selectors = SpringUtils.getBeans(ImportSelector.class); + Boolean flag = ListUtils.collectOne(selectors, selector -> selector.canHandle(className), selector -> selector.shouldImport(selfClassName, className)); + return flag == null || flag; + } + + public abstract String getClassName(); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java index 311a3d21..ef6a4754 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java @@ -9,7 +9,6 @@ import com.gitee.spirit.core.element.entity.Document; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.gitee.spirit.core.api.ElementBuilder; import com.gitee.spirit.core.api.SemanticParser; import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/api/ImportManager.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/api/ImportManager.java new file mode 100644 index 00000000..14b31181 --- /dev/null +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/api/ImportManager.java @@ -0,0 +1,16 @@ +package com.gitee.spirit.output.api; + +import com.gitee.spirit.core.clazz.entity.IClass; +import com.gitee.spirit.output.java.entity.StaticImport; + +import java.util.List; + +public interface ImportManager { + + List getStaticImports(IClass clazz); + + StaticImport findStaticImport(IClass clazz, String sourceName); + + boolean addStaticImport(IClass clazz, String sourceName); + +} diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/DefaultImportManager.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/DefaultImportManager.java new file mode 100644 index 00000000..8525683a --- /dev/null +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/DefaultImportManager.java @@ -0,0 +1,47 @@ +package com.gitee.spirit.output.java; + +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.api.ElementBuilder; +import com.gitee.spirit.core.clazz.entity.IClass; +import com.gitee.spirit.output.api.ImportManager; +import com.gitee.spirit.output.java.entity.StaticImport; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Component +public class DefaultImportManager implements ImportManager { + + public Map> classStaticImportsMap = new ConcurrentHashMap<>(); + + @Autowired + public ElementBuilder builder; + + @Override + public List getStaticImports(IClass clazz) { + return classStaticImportsMap.computeIfAbsent(clazz, clazz1 -> new ArrayList<>()); + } + + @Override + public StaticImport findStaticImport(IClass clazz, String sourceName) { + List staticImports = getStaticImports(clazz); + return ListUtils.findOne(staticImports, staticImport -> staticImport.matchSourceName(sourceName)); + } + + @Override + public boolean addStaticImport(IClass clazz, String sourceName) { + StaticImport staticImport = findStaticImport(clazz, sourceName); + if (staticImport != null) { + return true; + } + List staticImports = getStaticImports(clazz); + staticImports.add(new StaticImport(builder.build("import static " + sourceName))); + return true; + } + + +} diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/JavaBuilder.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/JavaBuilder.java index f2bf6e17..9cab9e08 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/JavaBuilder.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/JavaBuilder.java @@ -1,7 +1,10 @@ package com.gitee.spirit.output.java; import java.util.List; +import java.util.Map; +import com.gitee.spirit.output.api.ImportManager; +import com.gitee.spirit.output.java.entity.StaticImport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -25,6 +28,8 @@ public class JavaBuilder implements CodeBuilder { public static final String SYNCHRONIZED_KEYWORD = "synchronized"; public static final String FINAL_KEYWORD = "final"; + @Autowired + public ImportManager manager; @Autowired public AutoImporter importer; @Autowired @@ -34,7 +39,7 @@ public class JavaBuilder implements CodeBuilder { public String build(IClass clazz) { String body = buildBody(clazz); String head = buildHead(clazz); - return new StringBuilder().append(head).append(body).toString(); + return head + body; } public String buildHead(IClass clazz) { @@ -43,15 +48,15 @@ public class JavaBuilder implements CodeBuilder { builder.append(String.format("package %s;\n\n", clazz.packageStr)); // import List imports = clazz.getImports(); - imports.forEach((imp) -> builder.append(imp.element + ";\n")); + imports.forEach((imp) -> builder.append(imp.element).append(";\n")); // static import - List staticImports = clazz.getStaticImports(); - staticImports.forEach((imp) -> builder.append(imp.element + ";\n")); + List staticImports = manager.getStaticImports(clazz); + staticImports.forEach((imp) -> builder.append(imp.element).append(";\n")); if (imports.size() > 0 || staticImports.size() > 0) { builder.append("\n"); } // annotation - clazz.annotations.forEach((annotation) -> builder.append(annotation + "\n")); + clazz.annotations.forEach((annotation) -> builder.append(annotation).append("\n")); return builder.toString(); } @@ -60,7 +65,7 @@ public class JavaBuilder implements CodeBuilder { // 处理一部分关键字 clazz.element.insertKeywordAfter(KeywordEnum.ABSTRACT.value, KeywordEnum.CLASS.value); clazz.element.replaceKeyword(KeywordEnum.IMPLS.value, JavaBuilder.IMPLEMENTS_KEYWORD); - classStr.append(clazz.element + "\n\n"); + classStr.append(clazz.element).append("\n\n"); // 当构建方法体时,需要动态引入一些类型和字段,所以先构建方法体 String methodsStr = buildMethods(clazz); String fieldsStr = buildFields(clazz); @@ -74,9 +79,9 @@ public class JavaBuilder implements CodeBuilder { // public static type + element for (IField field : clazz.fields) { // annotation - field.annotations.forEach((annotation) -> fieldsStr.append("\t" + annotation + "\n")); + field.annotations.forEach((annotation) -> fieldsStr.append("\t").append(annotation).append("\n")); field.element.replaceModifier(KeywordEnum.CONST.value, JavaBuilder.FINAL_KEYWORD); - fieldsStr.append("\t" + convert(clazz, field, field.element) + "\n"); + fieldsStr.append("\t").append(convert(clazz, field, field.element)).append("\n"); } if (fieldsStr.length() > 0) { fieldsStr.append("\n"); @@ -90,7 +95,7 @@ public class JavaBuilder implements CodeBuilder { // public static type + element for (IMethod method : clazz.methods) { // annotation - method.annotations.forEach((annotation) -> methodsStr.append("\t" + annotation + "\n")); + method.annotations.forEach((annotation) -> methodsStr.append("\t").append(annotation).append("\n")); Element element = method.element; // 静态主方法 @@ -107,9 +112,9 @@ public class JavaBuilder implements CodeBuilder { } if (element.hasChild()) { - methodsStr.append("\t" + element + "\n"); + methodsStr.append("\t").append(element).append("\n"); } else { - methodsStr.append("\t" + element + ";\n\n"); + methodsStr.append("\t").append(element).append(";\n\n"); } } else if (element.isFunc()) { @@ -118,7 +123,7 @@ public class JavaBuilder implements CodeBuilder { } else { element.replaceKeyword(KeywordEnum.FUNC.value, importer.getFinalName(clazz, method.getType())); } - methodsStr.append("\t" + element + "\n"); + methodsStr.append("\t").append(element).append("\n"); } } // 方法体可能没有内容,但是这并不意味着这个方法没有被实现 @@ -130,10 +135,9 @@ public class JavaBuilder implements CodeBuilder { return methodsStr.toString(); } - public void convertMethodElement(StringBuilder builder, String indent, IClass clazz, IMethod method, - Element father) { + public void convertMethodElement(StringBuilder builder, String indent, IClass clazz, IMethod method, Element father) { for (Element element : father.children) { - builder.append(indent + convert(clazz, method, element) + "\n"); + builder.append(indent).append(convert(clazz, method, element)).append("\n"); if (element.hasChild()) { convertMethodElement(builder, indent + "\t", clazz, method, element); } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java index ca68bd6e..9de5874c 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/EmptyAction.java @@ -1,5 +1,7 @@ package com.gitee.spirit.output.java.action; +import com.gitee.spirit.output.api.ImportManager; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -14,15 +16,18 @@ import com.gitee.spirit.stdlib.Emptys; @Order(-100) public class EmptyAction extends AbstractExtElementAction { - @Override - public void visitElement(VisitContext context, Element element) { - StmtVisitor.forEachToken(element, token -> { - if (token.isLocalMethod()) {// empty(str) - if (KeywordEnum.EMPTY.value.equals(token.attr(Attribute.MEMBER_NAME))) { - context.clazz.addStaticImport(Emptys.class.getName() + ".empty"); - } - } - }); - } + @Autowired + public ImportManager manager; + + @Override + public void visitElement(VisitContext context, Element element) { + StmtVisitor.forEachToken(element, token -> { + if (token.isLocalMethod()) {// empty(str) + if (KeywordEnum.EMPTY.value.equals(token.attr(Attribute.MEMBER_NAME))) { + manager.addStaticImport(context.clazz, Emptys.class.getName() + ".empty"); + } + } + }); + } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/StaticImport.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/StaticImport.java new file mode 100644 index 00000000..d8c891fe --- /dev/null +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/StaticImport.java @@ -0,0 +1,17 @@ +package com.gitee.spirit.output.java.entity; + +import com.gitee.spirit.core.clazz.entity.Import; +import com.gitee.spirit.core.element.entity.Element; + +public class StaticImport extends Import { + + public StaticImport(Element element) { + super(element); + } + + @Override + public boolean matchSourceName(String sourceName) { + return element.getStr(2).equals(sourceName); + } + +} -- Gitee From 2631a95d4c64a8281a54985ce45841eab6b34129 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Thu, 1 Jul 2021 22:16:49 +0800 Subject: [PATCH 50/83] =?UTF-8?q?=E8=B0=83=E6=95=B4gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 20 +++++++++++-------- .../output/java/DefaultImportManager.java | 1 - 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 3919d549..0caf2122 100644 --- a/.gitignore +++ b/.gitignore @@ -129,13 +129,17 @@ /spirit-stdlib/spirit-stdlib.iml /spirit-tools/spirit-tools.iml /.idea/vcs.xml -/spirit-common/target/classes/com/gitee/spirit/common/ -/spirit-core/spirit-core-class/target/classes/com/gitee/spirit/core/ -/spirit-core/spirit-core-compile/target/classes/com/gitee/spirit/core/ -/spirit-core/spirit-core-element/target/ +/spirit-stdlib/target/ +/spirit-common/target/ /spirit-core/spirit-core-lexer/target/ -/spirit-tools/spirit-maven-plugin/target/classes/com/gitee/spirit/maven/plugin/ -/spirit-output/spirit-output-java/target/classes/com/gitee/spirit/output/java/ -/spirit-starter/spirit-starter-java/target/classes/ -/spirit-stdlib/target/classes/com/gitee/spirit/stdlib/ +/spirit-core/spirit-core-element/target/ +/spirit-core/spirit-core-class/target/ +/spirit-core/spirit-core-compile/target/ +/spirit-output/spirit-output-java/target/ +/spirit-starter/spirit-starter-java/target/ +/spirit-tools/spirit-code-tools/target/ +/spirit-tools/spirit-maven-plugin/target/ +/spirit-example/spirit-example-common/target/ +/spirit-example/spirit-example-plugin/target/ /.idea/uiDesigner.xml + diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/DefaultImportManager.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/DefaultImportManager.java index 8525683a..43f42260 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/DefaultImportManager.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/DefaultImportManager.java @@ -17,7 +17,6 @@ import java.util.concurrent.ConcurrentHashMap; public class DefaultImportManager implements ImportManager { public Map> classStaticImportsMap = new ConcurrentHashMap<>(); - @Autowired public ElementBuilder builder; -- Gitee From b41dfcdcf5ee6044b68185a6ec1384ed40d0816f Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Thu, 1 Jul 2021 22:27:51 +0800 Subject: [PATCH 51/83] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E7=9A=84=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java b/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java index 8d70e3a2..419f42ec 100644 --- a/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java +++ b/spirit-tools/spirit-maven-plugin/src/main/java/com/gitee/spirit/maven/plugin/SpiritCompileMojo.java @@ -3,8 +3,6 @@ package com.gitee.spirit.maven.plugin; import java.util.List; import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -- Gitee From 9f7af7caeb6a29c7a8dbf28350277a1d69cca3ab Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Fri, 2 Jul 2021 00:15:07 +0800 Subject: [PATCH 52/83] =?UTF-8?q?=E6=B7=BB=E5=8A=A0import=E7=9A=84?= =?UTF-8?q?=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/clazz/frame/ImportEntity.java | 6 ++++-- .../java/com/gitee/spirit/example/block/Block.java | 10 +++++----- .../com/gitee/spirit/example/subexpress/Express.java | 4 ++-- .../java/com/gitee/spirit/example/syntax/Syntax.java | 6 +++--- .../main/java/com/gitee/spirit/example/type/Type.java | 10 +++++----- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java index cc2e2638..4fc1b835 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java @@ -1,8 +1,8 @@ package com.gitee.spirit.core.clazz.frame; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; import com.gitee.spirit.common.enums.PrimitiveEnum; import com.gitee.spirit.common.utils.ListUtils; @@ -26,7 +26,9 @@ public abstract class ImportEntity extends AnnotationEntity { } public List getImports() { - return ListUtils.findAll(imports, import0 -> !import0.hasAlias()); + List importsToSort = ListUtils.findAll(imports, import0 -> !import0.hasAlias()); + importsToSort.sort(Comparator.comparing(Import::getClassName)); + return importsToSort; } public List getAliasImports() { diff --git a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/block/Block.java b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/block/Block.java index ddc2e8a2..be9c5fbd 100644 --- a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/block/Block.java +++ b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/block/Block.java @@ -1,13 +1,13 @@ package com.gitee.spirit.example.block; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.gitee.spirit.stdlib.Lists; import com.gitee.spirit.stdlib.Maps; +import java.util.List; import java.util.Map; import java.util.Map.Entry; -import com.gitee.spirit.stdlib.Lists; -import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static com.gitee.spirit.stdlib.Emptys.empty; public class Block { diff --git a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/subexpress/Express.java b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/subexpress/Express.java index 49a552ef..a71a50db 100644 --- a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/subexpress/Express.java +++ b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/subexpress/Express.java @@ -1,10 +1,10 @@ package com.gitee.spirit.example.subexpress; +import com.gitee.spirit.stdlib.Lists; +import java.util.List; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.gitee.spirit.stdlib.Lists; -import java.util.List; import static com.gitee.spirit.stdlib.Emptys.empty; public class Express { diff --git a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/syntax/Syntax.java b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/syntax/Syntax.java index 91c00a3f..af38091f 100644 --- a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/syntax/Syntax.java +++ b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/syntax/Syntax.java @@ -1,11 +1,11 @@ package com.gitee.spirit.example.syntax; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.gitee.spirit.stdlib.Lists; -import java.util.List; import com.gitee.spirit.stdlib.Maps; +import java.util.List; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Syntax { diff --git a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/type/Type.java b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/type/Type.java index cfb508de..83d441fd 100644 --- a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/type/Type.java +++ b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/type/Type.java @@ -1,17 +1,17 @@ package com.gitee.spirit.example.type; -import java.util.HashMap; import com.gitee.spirit.example.ClassGenericTest; -import com.gitee.spirit.example.MyTest; import com.gitee.spirit.example.GenericType; +import com.gitee.spirit.example.MyTest; import com.gitee.spirit.example.clazz.ServiceImpl; import com.gitee.spirit.example.process.Main; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.gitee.spirit.stdlib.Lists; -import java.util.List; import com.gitee.spirit.stdlib.Maps; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Deprecated public class Type { -- Gitee From aeaa89af3190f9e9fd6025b55d745070f6d16936 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Fri, 2 Jul 2021 15:45:41 +0800 Subject: [PATCH 53/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/entity/IAnnotation.java | 13 +++++++--- .../spirit/core/clazz/entity/IVariable.java | 24 +++++++++-------- .../spirit/core/clazz/frame/TokenEntity.java | 26 ++++++------------- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java index e88e16d7..2dba389e 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java @@ -1,12 +1,19 @@ package com.gitee.spirit.core.clazz.entity; +import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.core.clazz.frame.TokenEntity; import com.gitee.spirit.core.element.entity.Token; public class IAnnotation extends TokenEntity { - public IAnnotation(Token token) { - super(token); - } + public IAnnotation(Token token) { + super(token); + } + public String getName() { + if (token.isAnnotation()) { + return token.attr(Attribute.SIMPLE_NAME); + } + throw new RuntimeException("The token is not an annotation!"); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java index 70c09e93..92537bd9 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java @@ -5,18 +5,20 @@ import com.gitee.spirit.core.element.entity.Token; public class IVariable extends TokenEntity { - public String blockId; + public String blockId; - public IVariable(Token token) { - super(token); - } + public IVariable(Token token) { + super(token); + } - @Override - public String getName() { - if (token == null) { - return "NO_NAME"; - } - return super.getName(); - } + public String getName() { + if (token == null) { + return "NO_NAME"; + } + if (token.isVariable()) { + return token.toString(); + } + throw new RuntimeException("The token is not a variable!"); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/TokenEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/TokenEntity.java index 811d5304..999ccb57 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/TokenEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/TokenEntity.java @@ -5,25 +5,15 @@ import com.gitee.spirit.core.element.entity.Token; public abstract class TokenEntity extends TypeEntity { - public Token token; + public Token token; - public TokenEntity(Token token) { - this.token = token; - } + public TokenEntity(Token token) { + this.token = token; + } - public String getName() { - if (token.isAnnotation()) { - return token.attr(Attribute.SIMPLE_NAME); - - } else if (token.isVariable()) { - return token.toString(); - } - throw new RuntimeException("Unsupported semantics!semantics:" + token.tokenType); - } - - @Override - public String toString() { - return token.toString(); - } + @Override + public String toString() { + return token.toString(); + } } -- Gitee From 4228215b1633a2b142d7582df47b8f9497819d8b Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Fri, 2 Jul 2021 18:15:39 +0800 Subject: [PATCH 54/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/entity/IClass.java | 158 +++++++++--------- .../spirit/core/clazz/entity/IField.java | 22 +-- .../spirit/core/clazz/entity/IMethod.java | 76 ++++----- 3 files changed, 128 insertions(+), 128 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java index bb1725d5..addab73f 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java @@ -19,84 +19,84 @@ import cn.hutool.core.lang.Assert; public class IClass extends ImportEntity { - public String packageStr; - public List fields; - public List methods; - - public IClass(List imports, List annotations, Element element) { - super(imports, annotations, element); - } - - public boolean isInterface() { - return element.isInterface(); - } - - public boolean isAbstract() { - return element.isAbstract(); - } - - public boolean isClass() { - return element.isClass(); - } - - public Token getTypeToken() { - Token token = null; - if (isInterface()) { - token = element.getKeywordParam(KeywordEnum.INTERFACE.value); - } else if (isAbstract() || isClass()) { - token = element.getKeywordParam(KeywordEnum.CLASS.value, KeywordEnum.ABSTRACT.value); - } - Assert.isTrue(token != null && token.isType(), "Cannot get type token of class!"); - return token; - } - - public String getSimpleName() { - return TypeUtils.getTargetName(getTypeToken().toString()); - } - - public String getClassName() { - return packageStr + "." + getSimpleName(); - } - - public int getTypeVariableIndex(String genericName) { - String simpleName = getTypeToken().toString(); - // 这样分割,是有风险的,不过一般来说,类型说明里面不会再有嵌套 - List names = new ArrayList<>(Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(simpleName)); - names.remove(0); - int index = 0; - for (String name : names) { - if (name.equals(genericName)) { - return index; - } - index++; - } - return -1; - } - - public IType getSuperType() {// 注意:这里返回的是Super - Token token = element.getKeywordParam(KeywordEnum.EXTENDS.value);// 这里返回的,可以是泛型格式,而不是className - if (token != null) { - TypeFactory factory = SpringUtils.getBean(TypeFactory.class); - return factory.create(this, token); - } - return null; - } - - public List getInterfaceTypes() { - List interfaces = new ArrayList<>(); - TypeFactory factory = SpringUtils.getBean(TypeFactory.class); - for (Token token : element.getKeywordParams(KeywordEnum.IMPLS.value)) { - interfaces.add(factory.create(this, token)); - } - return interfaces; - } - - public IField getField(String fieldName) { - return ListUtils.findOne(fields, field -> field.getName().equals(fieldName)); - } - - public List getMethods(String methodName) { - return methods.stream().filter(method -> method.getName().equals(methodName)).collect(Collectors.toList()); - } + public String packageStr; + public List fields; + public List methods; + + public IClass(List imports, List annotations, Element element) { + super(imports, annotations, element); + } + + public boolean isInterface() { + return element.isInterface(); + } + + public boolean isAbstract() { + return element.isAbstract(); + } + + public boolean isClass() { + return element.isClass(); + } + + public Token getTypeToken() { + Token token = null; + if (isInterface()) { + token = element.getKeywordParam(KeywordEnum.INTERFACE.value); + } else if (isAbstract() || isClass()) { + token = element.getKeywordParam(KeywordEnum.CLASS.value, KeywordEnum.ABSTRACT.value); + } + Assert.isTrue(token != null && token.isType(), "Cannot get type token of class!"); + return token; + } + + public String getSimpleName() { + return TypeUtils.getTargetName(getTypeToken().toString()); + } + + public String getClassName() { + return packageStr + "." + getSimpleName(); + } + + public int getTypeVariableIndex(String genericName) { + String simpleName = getTypeToken().toString(); + // 这样分割,是有风险的,不过一般来说,类型说明里面不会再有嵌套 + List names = new ArrayList<>(Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(simpleName)); + names.remove(0); + int index = 0; + for (String name : names) { + if (name.equals(genericName)) { + return index; + } + index++; + } + return -1; + } + + public IType getSuperType() {// 注意:这里返回的是Super + Token token = element.getKeywordParam(KeywordEnum.EXTENDS.value);// 这里返回的,可以是泛型格式,而不是className + if (token != null) { + TypeFactory factory = SpringUtils.getBean(TypeFactory.class); + return factory.create(this, token); + } + return null; + } + + public List getInterfaceTypes() { + List interfaces = new ArrayList<>(); + TypeFactory factory = SpringUtils.getBean(TypeFactory.class); + for (Token token : element.getKeywordParams(KeywordEnum.IMPLS.value)) { + interfaces.add(factory.create(this, token)); + } + return interfaces; + } + + public IField getField(String fieldName) { + return ListUtils.findOne(fields, field -> field.getName().equals(fieldName)); + } + + public List getMethods(String methodName) { + return ListUtils.findAll(methods, method -> method.getName().equals(methodName)); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java index e5b6bcef..4cb5399e 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java @@ -7,18 +7,18 @@ import com.gitee.spirit.core.element.entity.Element; public class IField extends MemberEntity { - public IField(List annotations, Element element) { - super(annotations, element); - } + public IField(List annotations, Element element) { + super(annotations, element); + } - public String getName() { - if (element.isDeclare() || element.isDeclareAssign()) { - return element.getStr(1); + public String getName() { + if (element.isDeclare() || element.isDeclareAssign()) { + return element.getStr(1); - } else if (element.isAssign()) { - return element.getStr(0); - } - throw new RuntimeException("Unsupported syntax!syntax:" + element.syntax); - } + } else if (element.isAssign()) { + return element.getStr(0); + } + throw new RuntimeException("Unsupported syntax!syntax:" + element.syntax); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java index f730dd4b..9dd3a1d1 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java @@ -12,43 +12,43 @@ import com.google.common.base.Joiner; public class IMethod extends MemberEntity { - public List parameters = new ArrayList<>(); - - public IMethod(List annotations, Element element) { - super(annotations, element); - } - - public String getName() { - Token methodToken = element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); - if (methodToken.isTypeInit()) { - return methodToken.attr(Attribute.SIMPLE_NAME); - - } else if (methodToken.isLocalMethod()) { - return methodToken.attr(Attribute.MEMBER_NAME); - } - throw new RuntimeException("Unsupported syntax!syntax:" + element.syntax); - } - - public boolean isInit() { - Token methodToken = element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); - if (methodToken.isTypeInit()) { - return true; - - } else if (methodToken.isLocalMethod()) { - return false; - } - throw new RuntimeException("Unsupported syntax!syntax:" + element.syntax); - } - - @Override - public String toString() { - return getName() + "(" + Joiner.on(", ").join(parameters) + ")"; - } - - public String toSimpleString() { - List names = new ArrayList<>(); - parameters.forEach(parameter -> names.add(parameter.getName())); - return getName() + "(" + Joiner.on(", ").join(names) + ")"; - } + public List parameters = new ArrayList<>(); + + public IMethod(List annotations, Element element) { + super(annotations, element); + } + + public String getName() { + Token methodToken = element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); + if (methodToken.isTypeInit()) { + return methodToken.attr(Attribute.SIMPLE_NAME); + + } else if (methodToken.isLocalMethod()) { + return methodToken.attr(Attribute.MEMBER_NAME); + } + throw new RuntimeException("The token is not a method!"); + } + + public boolean isInit() { + Token methodToken = element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); + if (methodToken.isTypeInit()) { + return true; + + } else if (methodToken.isLocalMethod()) { + return false; + } + throw new RuntimeException("The token is not a method!"); + } + + @Override + public String toString() { + return getName() + "(" + Joiner.on(", ").join(parameters) + ")"; + } + + public String toSimpleString() { + List names = new ArrayList<>(); + parameters.forEach(parameter -> names.add(parameter.getName())); + return getName() + "(" + Joiner.on(", ").join(names) + ")"; + } } -- Gitee From 7d8949349126aa3defdc7078afea7e5182902826 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Fri, 2 Jul 2021 18:22:30 +0800 Subject: [PATCH 55/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/frame/ElementEntity.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ElementEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ElementEntity.java index 3804745f..834952b1 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ElementEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ElementEntity.java @@ -4,10 +4,15 @@ import com.gitee.spirit.core.element.entity.Element; public abstract class ElementEntity extends TypeEntity { - public Element element; + public Element element; - public ElementEntity(Element element) { - this.element = element; - } + public ElementEntity(Element element) { + this.element = element; + } + + @Override + public String toString() { + return element.toString(); + } } -- Gitee From 98f52943cf7dbd5b58be937f1aac9a50d4fbf73d Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Fri, 2 Jul 2021 18:28:30 +0800 Subject: [PATCH 56/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../output/java/utils/ReflectUtils.java | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/utils/ReflectUtils.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/utils/ReflectUtils.java index 10796ec7..d6230e34 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/utils/ReflectUtils.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/utils/ReflectUtils.java @@ -11,51 +11,51 @@ import java.util.List; public class ReflectUtils { - @SuppressWarnings("deprecation") - public static ClassLoader getClassLoader(List classpaths) { - try { - URL urls[] = new URL[classpaths.size()]; - for (int i = 0; i < classpaths.size(); ++i) { - urls[i] = new File(classpaths.get(i)).toURL(); - } - return new URLClassLoader(urls, ReflectUtils.class.getClassLoader()); - - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static Field getDeclaredField(Class clazz, String fieldName) { - Field[] fields = clazz.getDeclaredFields(); - for (Field field : fields) { - if (field.getName().equals(fieldName)) { - return field; - } - } - return null; - } - - public static boolean isIndefinite(Method method) { - Parameter[] parameters = method.getParameters(); - if (parameters != null && parameters.length > 0) { - Parameter lastParameter = parameters[parameters.length - 1]; - return lastParameter.toString().contains("..."); - } - return false; - } - - public static boolean isIndefinite(Parameter lastParameter) { - return lastParameter.toString().contains("..."); - } - - public static boolean isAccessible(Member member, int... modifiers) { - int mod = member.getModifiers(); - for (int modifier : modifiers) { - if ((mod & modifier) != 0) { - return true; - } - } - return false; - } + @SuppressWarnings("deprecation") + public static ClassLoader getClassLoader(List classPaths) { + try { + URL[] urls = new URL[classPaths.size()]; + for (int i = 0; i < classPaths.size(); ++i) { + urls[i] = new File(classPaths.get(i)).toURL(); + } + return new URLClassLoader(urls, ReflectUtils.class.getClassLoader()); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static Field getDeclaredField(Class clazz, String fieldName) { + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (field.getName().equals(fieldName)) { + return field; + } + } + return null; + } + + public static boolean isIndefinite(Method method) { + Parameter[] parameters = method.getParameters(); + if (parameters != null && parameters.length > 0) { + Parameter lastParameter = parameters[parameters.length - 1]; + return lastParameter.toString().contains("..."); + } + return false; + } + + public static boolean isIndefinite(Parameter lastParameter) { + return lastParameter.toString().contains("..."); + } + + public static boolean isAccessible(Member member, int... modifiers) { + int mod = member.getModifiers(); + for (int modifier : modifiers) { + if ((mod & modifier) != 0) { + return true; + } + } + return false; + } } -- Gitee From 1decd90e26da8e80180cdcdf2ef59dc10a44c7bc Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Fri, 2 Jul 2021 20:50:23 +0800 Subject: [PATCH 57/83] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=BB=A7=E6=89=BF?= =?UTF-8?q?=E5=85=B3=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/entity/IAnnotation.java | 4 ++- .../spirit/core/clazz/entity/IClass.java | 5 ++- .../spirit/core/clazz/entity/IField.java | 1 + .../spirit/core/clazz/entity/IMethod.java | 1 + .../spirit/core/clazz/entity/IParameter.java | 32 ++++++++++--------- .../spirit/core/clazz/entity/IVariable.java | 4 ++- ...tationEntity.java => AnnotatedEntity.java} | 4 +-- ...mportEntity.java => ImportableEntity.java} | 4 +-- .../spirit/core/clazz/frame/MemberEntity.java | 14 ++++---- .../spirit/core/clazz/frame/NamedEntity.java | 7 ++++ 10 files changed, 45 insertions(+), 31 deletions(-) rename spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/{AnnotationEntity.java => AnnotatedEntity.java} (84%) rename spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/{ImportEntity.java => ImportableEntity.java} (96%) create mode 100644 spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/NamedEntity.java diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java index 2dba389e..7f406532 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java @@ -1,15 +1,17 @@ package com.gitee.spirit.core.clazz.entity; import com.gitee.spirit.common.constants.Attribute; +import com.gitee.spirit.core.clazz.frame.NamedEntity; import com.gitee.spirit.core.clazz.frame.TokenEntity; import com.gitee.spirit.core.element.entity.Token; -public class IAnnotation extends TokenEntity { +public class IAnnotation extends TokenEntity implements NamedEntity { public IAnnotation(Token token) { super(token); } + @Override public String getName() { if (token.isAnnotation()) { return token.attr(Attribute.SIMPLE_NAME); diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java index addab73f..082e1d2d 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java @@ -2,13 +2,12 @@ package com.gitee.spirit.core.clazz.entity; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import com.gitee.spirit.common.enums.KeywordEnum; import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.common.utils.SpringUtils; import com.gitee.spirit.core.api.TypeFactory; -import com.gitee.spirit.core.clazz.frame.ImportEntity; +import com.gitee.spirit.core.clazz.frame.ImportableEntity; import com.gitee.spirit.core.clazz.utils.TypeUtils; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Token; @@ -17,7 +16,7 @@ import com.google.common.base.Splitter; import cn.hutool.core.lang.Assert; -public class IClass extends ImportEntity { +public class IClass extends ImportableEntity { public String packageStr; public List fields; diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java index 4cb5399e..3f19c986 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java @@ -11,6 +11,7 @@ public class IField extends MemberEntity { super(annotations, element); } + @Override public String getName() { if (element.isDeclare() || element.isDeclareAssign()) { return element.getStr(1); diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java index 9dd3a1d1..29976d3b 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java @@ -18,6 +18,7 @@ public class IMethod extends MemberEntity { super(annotations, element); } + @Override public String getName() { Token methodToken = element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); if (methodToken.isTypeInit()) { diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IParameter.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IParameter.java index a2645cb4..916714b6 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IParameter.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IParameter.java @@ -2,25 +2,27 @@ package com.gitee.spirit.core.clazz.entity; import java.util.List; -import com.gitee.spirit.core.clazz.frame.AnnotationEntity; +import com.gitee.spirit.core.clazz.frame.AnnotatedEntity; +import com.gitee.spirit.core.clazz.frame.NamedEntity; import com.gitee.spirit.core.element.entity.Element; -public class IParameter extends AnnotationEntity { +public class IParameter extends AnnotatedEntity implements NamedEntity { - public IParameter(List annotations, Element element) { - super(annotations, element); - } + public IParameter(List annotations, Element element) { + super(annotations, element); + } - public String getName() { - if (element.isDeclare()) { - return element.getStr(1); - } - throw new RuntimeException("Unsupported syntax!syntax:" + element.syntax); - } + @Override + public String getName() { + if (element.isDeclare()) { + return element.getStr(1); + } + throw new RuntimeException("Unsupported syntax!syntax:" + element.syntax); + } - @Override - public String toString() { - return element.toString(); - } + @Override + public String toString() { + return element.toString(); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java index 92537bd9..b8628891 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java @@ -1,9 +1,10 @@ package com.gitee.spirit.core.clazz.entity; +import com.gitee.spirit.core.clazz.frame.NamedEntity; import com.gitee.spirit.core.clazz.frame.TokenEntity; import com.gitee.spirit.core.element.entity.Token; -public class IVariable extends TokenEntity { +public class IVariable extends TokenEntity implements NamedEntity { public String blockId; @@ -11,6 +12,7 @@ public class IVariable extends TokenEntity { super(token); } + @Override public String getName() { if (token == null) { return "NO_NAME"; diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotationEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotatedEntity.java similarity index 84% rename from spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotationEntity.java rename to spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotatedEntity.java index 35b8879e..735d87d4 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotationEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/AnnotatedEntity.java @@ -7,11 +7,11 @@ import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.core.clazz.entity.IAnnotation; import com.gitee.spirit.core.element.entity.Element; -public abstract class AnnotationEntity extends ElementEntity { +public abstract class AnnotatedEntity extends ElementEntity { public List annotations; - public AnnotationEntity(List annotations, Element element) { + public AnnotatedEntity(List annotations, Element element) { super(element); this.annotations = annotations != null ? new ArrayList<>(annotations) : new ArrayList<>(); } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportableEntity.java similarity index 96% rename from spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java rename to spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportableEntity.java index 4fc1b835..e8742731 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/ImportableEntity.java @@ -16,11 +16,11 @@ import com.gitee.spirit.core.element.entity.Element; import cn.hutool.core.lang.Assert; -public abstract class ImportEntity extends AnnotationEntity { +public abstract class ImportableEntity extends AnnotatedEntity { public List imports; - public ImportEntity(List imports, List annotations, Element element) { + public ImportableEntity(List imports, List annotations, Element element) { super(annotations, element); this.imports = imports != null ? new ArrayList<>(imports) : new ArrayList<>(); } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/MemberEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/MemberEntity.java index 248fc350..8bb16a39 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/MemberEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/MemberEntity.java @@ -6,14 +6,14 @@ import com.gitee.spirit.common.enums.KeywordEnum; import com.gitee.spirit.core.clazz.entity.IAnnotation; import com.gitee.spirit.core.element.entity.Element; -public abstract class MemberEntity extends AnnotationEntity { +public abstract class MemberEntity extends AnnotatedEntity implements NamedEntity { - public MemberEntity(List annotations, Element element) { - super(annotations, element); - } + public MemberEntity(List annotations, Element element) { + super(annotations, element); + } - public boolean isStatic() { - return element.isModified(KeywordEnum.STATIC.value); - } + public boolean isStatic() { + return element.isModified(KeywordEnum.STATIC.value); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/NamedEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/NamedEntity.java new file mode 100644 index 00000000..eec66b5d --- /dev/null +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/NamedEntity.java @@ -0,0 +1,7 @@ +package com.gitee.spirit.core.clazz.frame; + +public interface NamedEntity { + + String getName(); + +} -- Gitee From c3e7405f5df6849f4ebebe32e669c10bd01091b7 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Fri, 2 Jul 2021 21:11:56 +0800 Subject: [PATCH 58/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/clazz/entity/IType.java | 172 +++++++++--------- .../core/element/frame/KeywordTokenBox.java | 124 ++++++------- 2 files changed, 145 insertions(+), 151 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java index 219f2c44..256fc948 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java @@ -25,94 +25,88 @@ import lombok.NonNull; @AllArgsConstructor public class IType { - private String className; - private String simpleName; - private String typeName; - private String genericName;// T K - private boolean isPrimitive;// 是否原始类型 - private boolean isArray;// 是否数组 - private boolean isNull;// 是否空值 - private boolean isWildcard;// 是否“?” - private boolean isNative;// 是否本地类型 - private int modifiers;// 进行位运算后得到的修饰符 - - @NonNull - @Builder.Default - private List genericTypes = new ArrayList<>();// 泛型参数 - - public boolean isTypeVariable() { - return StringUtils.isNotEmpty(genericName); - } - - public boolean isGenericType() { - return genericTypes != null && genericTypes.size() > 0; - } - - public IType toBox() { - IType boxType = CommonTypes.getBoxType(getClassName()); - return boxType != null ? boxType : this; - } - - public String getTargetName() {// 返回真正的className,包括数组中的 - return TypeUtils.getTargetName(getClassName()); - } - - public IType toTarget() { - TypeFactory factory = SpringUtils.getBean(TypeFactory.class); - return factory.create(getTargetName()); - } - - public IType withProtected() { - this.setModifiers(AccessLevelEnum.PROTECTED.value); - return this; - } - - public IType withPrivate() { - this.setModifiers(AccessLevelEnum.PRIVATE.value); - return this; - } - - public IType lowerAccessLevel() { - if (modifiers == AccessLevelEnum.PRIVATE.value) { - modifiers = AccessLevelEnum.PROTECTED.value; - - } else if (modifiers == AccessLevelEnum.PROTECTED.value) { - modifiers = AccessLevelEnum.PROTECTED.value; - - } else if (modifiers == AccessLevelEnum.PUBLIC.value) { - modifiers = AccessLevelEnum.PUBLIC.value; - } - return this; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof IType)) { - return false; - } - IType typeToMatch = (IType) obj; - boolean flag = getClassName().equals(typeToMatch.getClassName()); - if (flag) { - int count = 0; - for (IType genericType : getGenericTypes()) { - if (!genericType.equals(typeToMatch.getGenericTypes().get(count++))) { - flag = false; - break; - } - } - } - return flag; - } - - @Override - public String toString() {// 只打印当前类型的信息,不包括泛型 - if (isWildcard()) { - return "?"; - } - if (isTypeVariable()) { - return getGenericName(); - } - return getSimpleName(); - } + private String className; + private String simpleName; + private String typeName; + private String genericName;// T K + private boolean isPrimitive;// 是否原始类型 + private boolean isArray;// 是否数组 + private boolean isNull;// 是否空值 + private boolean isWildcard;// 是否“?” + private boolean isNative;// 是否本地类型 + private int modifiers;// 进行位运算后得到的修饰符 + + @NonNull + @Builder.Default + private List genericTypes = new ArrayList<>();// 泛型参数 + + public boolean isTypeVariable() { + return StringUtils.isNotEmpty(genericName); + } + + public boolean isGenericType() { + return genericTypes != null && genericTypes.size() > 0; + } + + public IType toBox() { + IType boxType = CommonTypes.getBoxType(getClassName()); + return boxType != null ? boxType : this; + } + + public String getTargetName() {// 返回真正的className,包括数组中的 + return TypeUtils.getTargetName(getClassName()); + } + + public IType toTarget() { + TypeFactory factory = SpringUtils.getBean(TypeFactory.class); + return factory.create(getTargetName()); + } + + public IType withProtected() { + this.setModifiers(AccessLevelEnum.PROTECTED.value); + return this; + } + + public IType withPrivate() { + this.setModifiers(AccessLevelEnum.PRIVATE.value); + return this; + } + + public IType lowerAccessLevel() { + if (modifiers == AccessLevelEnum.PRIVATE.value) { + modifiers = AccessLevelEnum.PROTECTED.value; + } + return this; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IType)) { + return false; + } + IType typeToMatch = (IType) obj; + boolean flag = getClassName().equals(typeToMatch.getClassName()); + if (flag) { + int count = 0; + for (IType genericType : getGenericTypes()) { + if (!genericType.equals(typeToMatch.getGenericTypes().get(count++))) { + flag = false; + break; + } + } + } + return flag; + } + + @Override + public String toString() {// 只打印当前类型的信息,不包括泛型 + if (isWildcard()) { + return "?"; + } + if (isTypeVariable()) { + return getGenericName(); + } + return getSimpleName(); + } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/KeywordTokenBox.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/KeywordTokenBox.java index a1697af6..ad546dbe 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/KeywordTokenBox.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/KeywordTokenBox.java @@ -11,76 +11,76 @@ import cn.hutool.core.lang.Assert; public abstract class KeywordTokenBox extends TokenBox { - public KeywordTokenBox(List tokens) { - super(tokens); - } + public KeywordTokenBox(List tokens) { + super(tokens); + } - public int indexOfKeyword(String keyword) { - return ListUtils.indexOf(this, token -> token.isKeyword() && keyword.equals(token.toString())); - } + public int indexOfKeyword(String keyword) { + return ListUtils.indexOf(this, token -> token.isKeyword() && keyword.equals(token.toString())); + } - public boolean containsKeyword(String keyword) { - return indexOfKeyword(keyword) != -1; - } + public boolean containsKeyword(String keyword) { + return indexOfKeyword(keyword) != -1; + } - public void removeKeyword(String keyword) { - int index = indexOfKeyword(keyword); - if (index != -1) { - remove(index); - } - } + public void removeKeyword(String keyword) { + int index = indexOfKeyword(keyword); + if (index != -1) { + remove(index); + } + } - public void replaceKeyword(String keyword, String newKeyword) { - int index = indexOfKeyword(keyword); - if (index != -1) { - set(index, new Token(TokenTypeEnum.KEYWORD, newKeyword)); - } - } + public void replaceKeyword(String keyword, String newKeyword) { + int index = indexOfKeyword(keyword); + if (index != -1) { + set(index, new Token(TokenTypeEnum.KEYWORD, newKeyword)); + } + } - public void addKeywordAtFirst(String keyword) { - add(0, new Token(TokenTypeEnum.KEYWORD, keyword)); - } + public void addKeywordAtFirst(String keyword) { + add(0, new Token(TokenTypeEnum.KEYWORD, keyword)); + } - public void addKeyword(String keyword) { - add(new Token(TokenTypeEnum.KEYWORD, keyword)); - } + public void addKeyword(String keyword) { + add(new Token(TokenTypeEnum.KEYWORD, keyword)); + } - public void insertKeywordAfter(String keyword, String newKeyword) { - int index = indexOfKeyword(keyword); - if (index != -1) { - add(index + 1, new Token(TokenTypeEnum.KEYWORD, newKeyword)); - } - } + public void insertKeywordAfter(String keyword, String newKeyword) { + int index = indexOfKeyword(keyword); + if (index != -1) { + add(index + 1, new Token(TokenTypeEnum.KEYWORD, newKeyword)); + } + } - public int findKeywordEnd(int index) { - int endIndex = ListUtils.indexOf(this, index + 1, token -> token.isKeyword() || (token.isSeparator() && !",".equals(token.toString()))); - if (endIndex == -1) { - return size(); - } - return endIndex + 1; - } + public int findKeywordEnd(int index) { + int endIndex = ListUtils.indexOf(this, index + 1, token -> token.isKeyword() || (token.isSeparator() && !",".equals(token.toString()))); + if (endIndex == -1) { + return size(); + } + return endIndex + 1; + } - public Token getKeywordParam(String... keywords) { - for (String keyword : keywords) { - int index = indexOfKeyword(keyword); - if (index != -1 && contains(index + 1)) { - return get(index + 1); - } - } - return null; - } + public Token getKeywordParam(String... keywords) { + for (String keyword : keywords) { + int index = indexOfKeyword(keyword); + if (index != -1 && contains(index + 1)) { + return get(index + 1); + } + } + return null; + } - public List getKeywordParams(String keyword) { - List params = new ArrayList<>(); - int index = indexOfKeyword(keyword); - if (index != -1) { - int endIndex = findKeywordEnd(index); - List tokenBoxs = new TokenBox(subTokens(index + 1, endIndex)).splitTokens(","); - for (TokenBox tokenBox : tokenBoxs) { - Assert.isTrue(tokenBox.size() == 1, "The size must be 1!"); - params.add(tokenBox.get(0)); - } - } - return params; - } + public List getKeywordParams(String keyword) { + List params = new ArrayList<>(); + int index = indexOfKeyword(keyword); + if (index != -1) { + int endIndex = findKeywordEnd(index); + List tokenBoxes = new TokenBox(subTokens(index + 1, endIndex)).splitTokens(","); + for (TokenBox tokenBox : tokenBoxes) { + Assert.isTrue(tokenBox.size() == 1, "The size must be 1!"); + params.add(tokenBox.get(0)); + } + } + return params; + } } -- Gitee From 48fc6510f4fb53a50c7bd1026cb912dbc7cb07e9 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Fri, 2 Jul 2021 21:44:19 +0800 Subject: [PATCH 59/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/spirit/common/utils/ListUtils.java | 16 ++++++++++------ .../spirit/core/element/entity/Element.java | 5 ++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java index 110934e6..33f1aed9 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java @@ -1,9 +1,7 @@ package com.gitee.spirit.common.utils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.function.Consumer; import java.util.stream.Collectors; import cn.hutool.core.collection.CollUtil; @@ -12,6 +10,7 @@ import com.gitee.spirit.common.function.Function; public class ListUtils { + @SafeVarargs public static List asListNonNull(T... items) { Assert.notNull(items, "The parameter items cannot be null!"); return Arrays.stream(items).filter(Objects::nonNull).collect(Collectors.toList()); @@ -88,10 +87,10 @@ public class ListUtils { } } - public static T findOneByScore(Iterable collection, Function.Scorer scorer) { + public static T findOneByScore(Iterable iterable, Function.Scorer scorer) { Integer maxScore = null; T finalItem = null; - for (T item : collection) { + for (T item : iterable) { Integer score = scorer.accept(item); if (score != null) { Assert.isFalse(maxScore != null && maxScore.intValue() == score.intValue(), "The score cannot be the same!"); @@ -125,4 +124,9 @@ public class ListUtils { return null; } + public static void reverse(List list, Consumer consumer) { + Collections.reverse(list); + list.forEach(consumer); + } + } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Element.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Element.java index a0aa020d..4f99ab77 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Element.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Element.java @@ -5,6 +5,7 @@ import java.util.List; import com.gitee.spirit.common.enums.SyntaxEnum; import com.gitee.spirit.common.utils.LineUtils; +import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.core.element.frame.Syntactic; public class Element extends Syntactic { @@ -38,9 +39,7 @@ public class Element extends Syntactic { } public Element addModifiers(String... keywords) { - for (int i = keywords.length - 1; i >= 0; i--) { - modifiers.addKeywordAtFirst(keywords[i]); - } + ListUtils.reverse(ListUtils.asListNonNull(keywords), keyword -> modifiers.addKeywordAtFirst(keyword)); return this; } -- Gitee From 36bf6334eb531e0ecb97ab4ddbeacf53bf0c7d49 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Fri, 2 Jul 2021 22:26:08 +0800 Subject: [PATCH 60/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/entity/IMethod.java | 27 ++++++-------- .../spirit/core/element/frame/Attributes.java | 37 ++++++++++++------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java index 29976d3b..0446e65a 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java @@ -3,6 +3,7 @@ package com.gitee.spirit.core.clazz.entity; import java.util.ArrayList; import java.util.List; +import cn.hutool.core.lang.Assert; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.common.enums.TokenTypeEnum; import com.gitee.spirit.core.clazz.frame.MemberEntity; @@ -18,27 +19,21 @@ public class IMethod extends MemberEntity { super(annotations, element); } - @Override - public String getName() { + public Token getMethodToken() { Token methodToken = element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); - if (methodToken.isTypeInit()) { - return methodToken.attr(Attribute.SIMPLE_NAME); + Assert.notNull(methodToken, "The method token cannot be null!"); + return methodToken; + } - } else if (methodToken.isLocalMethod()) { - return methodToken.attr(Attribute.MEMBER_NAME); - } - throw new RuntimeException("The token is not a method!"); + @Override + public String getName() { + Token methodToken = getMethodToken(); + return methodToken.attr(Attribute.SIMPLE_NAME, Attribute.MEMBER_NAME); } public boolean isInit() { - Token methodToken = element.findOneTokenOf(TokenTypeEnum.TYPE_INIT, TokenTypeEnum.LOCAL_METHOD); - if (methodToken.isTypeInit()) { - return true; - - } else if (methodToken.isLocalMethod()) { - return false; - } - throw new RuntimeException("The token is not a method!"); + Token methodToken = getMethodToken(); + return methodToken.isTypeInit(); } @Override diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Attributes.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Attributes.java index cd5e17ce..1940598f 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Attributes.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Attributes.java @@ -1,26 +1,35 @@ package com.gitee.spirit.core.element.frame; +import com.gitee.spirit.common.utils.ListUtils; + +import java.util.Arrays; import java.util.Map; public abstract class Attributes { - public Map attributes; + public Map attributes; + + public Attributes(Map attributes) { + this.attributes = attributes; + } - public Attributes(Map attributes) { - this.attributes = attributes; - } + public void setAttr(String attribute, Object value) { + attributes.put(attribute, value); + } - @SuppressWarnings("unchecked") - public T attr(String attribute) { - return (T) attributes.get(attribute); - } + @SuppressWarnings("unchecked") + public T attr(String attribute) { + return (T) attributes.get(attribute); + } - public boolean attr(String attribute, boolean defaultValue) { - return (boolean) attributes.getOrDefault(attribute, defaultValue); - } + @SuppressWarnings("unchecked") + public T attr(String... attributes) { + String attribute = ListUtils.findOne(Arrays.asList(attributes), this.attributes::containsKey); + return attribute != null ? (T) this.attributes.get(attribute) : null; + } - public void setAttr(String attribute, Object value) { - attributes.put(attribute, value); - } + public boolean attr(String attribute, boolean defaultValue) { + return (boolean) attributes.getOrDefault(attribute, defaultValue); + } } -- Gitee From 10f057749cc5d9de983d3a491b7ad7a26f332a43 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Fri, 2 Jul 2021 23:36:45 +0800 Subject: [PATCH 61/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/common/utils/ListUtils.java | 8 +++-- .../spirit/core/clazz/entity/IClass.java | 29 +++++-------------- .../spirit/core/element/entity/Document.java | 2 +- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java index 33f1aed9..bc2b644a 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java @@ -17,6 +17,10 @@ public class ListUtils { } public static int indexOf(List list, int fromIndex, int toIndex, Function.Matcher matcher) { + if (fromIndex < 0 || fromIndex >= list.size()) { + return -1; + } + Assert.isTrue(toIndex >= -1 && toIndex <= list.size(), "The toIndex must be in range!"); int step = toIndex >= fromIndex ? 1 : -1; for (int index = fromIndex; index != toIndex; index += step) { if (matcher.accept(list.get(index))) { @@ -26,7 +30,7 @@ public class ListUtils { return -1; } - public static int seekIndexOf(List list, int fromIndex, int toIndex, Function.Matcher matcher) { + public static int indexOfUnmatched(List list, int fromIndex, int toIndex, Function.Matcher matcher) { int index = indexOf(list, fromIndex, toIndex, item -> !matcher.accept(item)); return index == -1 ? toIndex : index; } @@ -66,7 +70,7 @@ public class ListUtils { } public static List seekAll(List list, Function.Matcher matcher) { - int index = seekIndexOf(list, 0, list.size(), matcher); + int index = indexOfUnmatched(list, 0, list.size(), matcher); List view = list.subList(0, index); List items = new ArrayList<>(view); view.clear(); diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java index 082e1d2d..258da1e2 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java @@ -39,14 +39,10 @@ public class IClass extends ImportableEntity { } public Token getTypeToken() { - Token token = null; - if (isInterface()) { - token = element.getKeywordParam(KeywordEnum.INTERFACE.value); - } else if (isAbstract() || isClass()) { - token = element.getKeywordParam(KeywordEnum.CLASS.value, KeywordEnum.ABSTRACT.value); - } - Assert.isTrue(token != null && token.isType(), "Cannot get type token of class!"); - return token; + Assert.isTrue(isInterface() || isAbstract() || isClass(), "The class type is wrong!"); + Token typeToken = element.getKeywordParam(KeywordEnum.INTERFACE.value, KeywordEnum.CLASS.value, KeywordEnum.ABSTRACT.value); + Assert.isTrue(typeToken != null && typeToken.isType(), "Cannot get type token of class!"); + return typeToken; } public String getSimpleName() { @@ -57,19 +53,10 @@ public class IClass extends ImportableEntity { return packageStr + "." + getSimpleName(); } - public int getTypeVariableIndex(String genericName) { - String simpleName = getTypeToken().toString(); - // 这样分割,是有风险的,不过一般来说,类型说明里面不会再有嵌套 - List names = new ArrayList<>(Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(simpleName)); - names.remove(0); - int index = 0; - for (String name : names) { - if (name.equals(genericName)) { - return index; - } - index++; - } - return -1; + public int getTypeVariableIndex(String genericName) {// 这样分割,是有风险的,不过一般来说,类型说明里面不会再有嵌套 + List names = Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(getTypeToken().toString()); + int index = ListUtils.indexOf(names, 1, names.size(), name -> name.equals(genericName)); + return index >= 1 ? index - 1 : -1; } public IType getSuperType() {// 注意:这里返回的是Super diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Document.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Document.java index bb36c37e..bbc9e648 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Document.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/Document.java @@ -18,7 +18,7 @@ public class Document extends ArrayList { public List findElements(Element element) { int index = ListUtils.indexOf(this, element::equals); if (index >= 0) { - int startIndex = ListUtils.seekIndexOf(this, index - 1, -1, Syntactic::isAnnotation); + int startIndex = ListUtils.indexOfUnmatched(this, index - 1, -1, Syntactic::isAnnotation); int endIndex = ListUtils.indexOf(this, index + 1, size(), Syntactic::isEnd); return new ArrayList<>(subList(startIndex + 1, endIndex + 1)); } -- Gitee From e7ed7b3111a08de40f59bb0321a4b9a3017a39c6 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Fri, 2 Jul 2021 23:44:31 +0800 Subject: [PATCH 62/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/spirit/core/clazz/entity/IClass.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java index 258da1e2..2df65beb 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IClass.java @@ -1,6 +1,7 @@ package com.gitee.spirit.core.clazz.entity; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import com.gitee.spirit.common.enums.KeywordEnum; @@ -55,8 +56,8 @@ public class IClass extends ImportableEntity { public int getTypeVariableIndex(String genericName) {// 这样分割,是有风险的,不过一般来说,类型说明里面不会再有嵌套 List names = Splitter.on(CharMatcher.anyOf("<,>")).trimResults().splitToList(getTypeToken().toString()); - int index = ListUtils.indexOf(names, 1, names.size(), name -> name.equals(genericName)); - return index >= 1 ? index - 1 : -1; + names = names.size() > 1 ? names.subList(1, names.size()) : Collections.emptyList(); + return ListUtils.indexOf(names, 0, names.size(), name -> name.equals(genericName)); } public IType getSuperType() {// 注意:这里返回的是Super -- Gitee From 157013127d8e525d8c69792a1a0431784be6fa85 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Mon, 5 Jul 2021 22:00:27 +0800 Subject: [PATCH 63/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/api/ClassLoader.java | 2 +- .../core/clazz/AbstractClassLoader.java | 2 -- .../core/clazz/AbstractImportSelector.java | 14 ++++---------- .../core/clazz/AbstractURLClassLoader.java | 9 ++------- .../spirit/output/java/ExtClassLoader.java | 19 ++----------------- 5 files changed, 9 insertions(+), 37 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassLoader.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassLoader.java index 2dee29a1..53a8a98a 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassLoader.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/api/ClassLoader.java @@ -5,7 +5,7 @@ import java.util.List; public interface ClassLoader { - List getResources(String name); + URL getResource(String name); List getNames(); diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractClassLoader.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractClassLoader.java index 942999bc..7098f6a0 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractClassLoader.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractClassLoader.java @@ -12,8 +12,6 @@ public abstract class AbstractClassLoader implements ClassLoader { return defineClass(name, resource); } - public abstract URL getResource(String name); - public abstract T defineClass(String name, URL resource); } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractImportSelector.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractImportSelector.java index f565437c..e018699e 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractImportSelector.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractImportSelector.java @@ -5,15 +5,9 @@ import com.gitee.spirit.core.clazz.utils.TypeUtils; public abstract class AbstractImportSelector implements ImportSelector { - @Override - public boolean shouldImport(String selfClassName, String className) { - if (selfClassName.equals(className)) { - return false; - } - if (TypeUtils.isSamePackage(selfClassName, className)) { - return false; - } - return true; - } + @Override + public boolean shouldImport(String selfClassName, String className) { + return !(selfClassName.equals(className) || TypeUtils.isSamePackage(selfClassName, className)); + } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java index 28c06266..b33a9626 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java @@ -41,8 +41,8 @@ public abstract class AbstractURLClassLoader extends AbstractClassLoader } @Override - public List getResources(String name) { - return Collections.singletonList(urls.get(name)); + public URL getResource(String name) { + return urls.get(name); } @Override @@ -73,11 +73,6 @@ public abstract class AbstractURLClassLoader extends AbstractClassLoader return classes.values().stream().filter(Objects::nonNull).collect(Collectors.toList()); } - @Override - public URL getResource(String name) { - return urls.get(name); - } - public void clear() { classes.clear(); urls.keySet().forEach(name -> classes.put(name, null)); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java index 64315e89..74672452 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtClassLoader.java @@ -36,18 +36,8 @@ public class ExtClassLoader extends AbstractClassLoader> implements Ini } @Override - public List getResources(String name) { - try { - List urls = new ArrayList<>(); - Enumeration enumeration = loader.getResources(name); - while (enumeration.hasMoreElements()) { - URL url = enumeration.nextElement(); - urls.add(url); - } - return urls; - } catch (IOException e) { - throw new RuntimeException(e); - } + public URL getResource(String name) { + return loader.getResource(name); } @Override @@ -78,11 +68,6 @@ public class ExtClassLoader extends AbstractClassLoader> implements Ini throw new RuntimeException("This method is not supported!"); } - @Override - public URL getResource(String name) { - return loader.getResource(name); - } - @Override public Class defineClass(String name, URL resource) { throw new RuntimeException("This method is not supported!"); -- Gitee From f75361c30207e734e7bae26bf84c15ff53b11237 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Mon, 5 Jul 2021 22:31:12 +0800 Subject: [PATCH 64/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/clazz/AbstractURLClassLoader.java | 15 +++-------- .../spirit/core/clazz/entity/IAnnotation.java | 7 +++-- .../spirit/core/clazz/entity/IField.java | 1 + .../spirit/core/clazz/entity/IParameter.java | 7 +++-- .../spirit/core/compile/AutoImporter.java | 27 ++++++------------- 5 files changed, 18 insertions(+), 39 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java index b33a9626..c40fc8ba 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/AbstractURLClassLoader.java @@ -32,9 +32,7 @@ public abstract class AbstractURLClassLoader extends AbstractClassLoader URL inputUrl = URLFileUtils.toURL(directory); urlList.forEach(url -> { String name = url.toString().replace(inputUrl.toString(), "").replaceAll("/", "."); - if (name.endsWith("." + extension)) { - name = name.substring(0, name.lastIndexOf('.')); - } + name = name.endsWith("." + extension) ? name.substring(0, name.lastIndexOf('.')) : name; urls.put(name, url); classes.put(name, null); }); @@ -57,15 +55,8 @@ public abstract class AbstractURLClassLoader extends AbstractClassLoader @Override public IClass loadClass(String name) { - if (contains(name)) { - IClass clazz = classes.get(name); - if (clazz == null) { - clazz = classes.put(name, super.loadClass(name)); - } - return clazz; - } else { - throw new RuntimeException("The class was not found!name:" + name); - } + Assert.isTrue(contains(name), "The class was not found!name:" + name); + return classes.computeIfAbsent(name, super::loadClass); } @Override diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java index 7f406532..3a0213e5 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IAnnotation.java @@ -1,5 +1,6 @@ package com.gitee.spirit.core.clazz.entity; +import cn.hutool.core.lang.Assert; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.core.clazz.frame.NamedEntity; import com.gitee.spirit.core.clazz.frame.TokenEntity; @@ -13,9 +14,7 @@ public class IAnnotation extends TokenEntity implements NamedEntity { @Override public String getName() { - if (token.isAnnotation()) { - return token.attr(Attribute.SIMPLE_NAME); - } - throw new RuntimeException("The token is not an annotation!"); + Assert.isTrue(token.isAnnotation(), "The token is not an annotation!"); + return token.attr(Attribute.SIMPLE_NAME); } } diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java index 3f19c986..2d8b7423 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IField.java @@ -2,6 +2,7 @@ package com.gitee.spirit.core.clazz.entity; import java.util.List; +import cn.hutool.core.lang.Assert; import com.gitee.spirit.core.clazz.frame.MemberEntity; import com.gitee.spirit.core.element.entity.Element; diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IParameter.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IParameter.java index 916714b6..7617b986 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IParameter.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IParameter.java @@ -2,6 +2,7 @@ package com.gitee.spirit.core.clazz.entity; import java.util.List; +import cn.hutool.core.lang.Assert; import com.gitee.spirit.core.clazz.frame.AnnotatedEntity; import com.gitee.spirit.core.clazz.frame.NamedEntity; import com.gitee.spirit.core.element.entity.Element; @@ -14,10 +15,8 @@ public class IParameter extends AnnotatedEntity implements NamedEntity { @Override public String getName() { - if (element.isDeclare()) { - return element.getStr(1); - } - throw new RuntimeException("Unsupported syntax!syntax:" + element.syntax); + Assert.isTrue(element.isDeclare(), "Unsupported syntax!syntax:" + element.syntax); + return element.getStr(1); } @Override diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java index ef6a4754..ebd8b320 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AutoImporter.java @@ -17,11 +17,9 @@ import com.gitee.spirit.core.element.entity.Element; @Component public class AutoImporter { - - // 把字符串都替换掉 - public static final String STRING_REGEX = "(?<=\").*?(?=\")"; - // 间接排除了泛型类型T - public static final Pattern TYPE_PATTERN = Pattern.compile("(\\b[A-Z]+\\w+\\b)"); + + public static final String STRING_REGEX = "(?<=\").*?(?=\")";// 把字符串都替换掉 + public static final Pattern TYPE_PATTERN = Pattern.compile("(\\b[A-Z]+\\w+\\b)");// 间接排除了泛型类型T @Autowired public ClassResolver resolver; @@ -38,18 +36,15 @@ public class AutoImporter { List elements = document.findElements(clazz.element); Set classNames = new HashSet<>(); visitElements(clazz, elements, classNames); - // 排除自身 - classNames.remove(clazz.getClassName()); + classNames.remove(clazz.getClassName());// 排除自身 return classNames; } public void visitElements(IClass clazz, List elements, Set classNames) { for (Element element : elements) { String line = element.line.text; - // 剔除掉字符串 - line = line.replaceAll(STRING_REGEX, "").trim(); - // 进行正则匹配 - Matcher matcher = TYPE_PATTERN.matcher(line); + line = line.replaceAll(STRING_REGEX, "").trim(); // 剔除掉字符串 + Matcher matcher = TYPE_PATTERN.matcher(line); // 进行正则匹配 while (matcher.find() && matcher.groupCount() > 0) { String targetName = matcher.group(matcher.groupCount() - 1); if (parser.isType(targetName)) { @@ -57,20 +52,14 @@ public class AutoImporter { classNames.add(className); } } - // 处理子节点 - if (element.hasChild()) { + if (element.hasChild()) {// 处理子节点 visitElements(clazz, element.children, classNames); } } } public String getFinalName(IClass clazz, IType type) { - return TypeVisitor.forEachTypeName(type, eachType -> { - if (!clazz.addImport(eachType.getClassName())) { - return eachType.getTypeName(); - } - return eachType.toString(); - }); + return TypeVisitor.forEachTypeName(type, eachType -> !clazz.addImport(eachType.getClassName()) ? eachType.getTypeName() : eachType.toString()); } } -- Gitee From 55e22baac993fe8d241a9b59fd4d3114c55735f7 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Mon, 5 Jul 2021 22:48:15 +0800 Subject: [PATCH 65/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/clazz/entity/IVariable.java | 10 +-- .../core/compile/DefaultElementVisitor.java | 73 ++++++++++--------- .../core/compile/entity/NullVariable.java | 17 +++++ 3 files changed, 57 insertions(+), 43 deletions(-) create mode 100644 spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/entity/NullVariable.java diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java index b8628891..9e4fa067 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IVariable.java @@ -1,5 +1,6 @@ package com.gitee.spirit.core.clazz.entity; +import cn.hutool.core.lang.Assert; import com.gitee.spirit.core.clazz.frame.NamedEntity; import com.gitee.spirit.core.clazz.frame.TokenEntity; import com.gitee.spirit.core.element.entity.Token; @@ -14,13 +15,8 @@ public class IVariable extends TokenEntity implements NamedEntity { @Override public String getName() { - if (token == null) { - return "NO_NAME"; - } - if (token.isVariable()) { - return token.toString(); - } - throw new RuntimeException("The token is not a variable!"); + Assert.isTrue(token.isVariable(), "The token is not a variable!"); + return token.toString(); } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisitor.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisitor.java index 4e5dfba6..9b21bfac 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisitor.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/DefaultElementVisitor.java @@ -2,6 +2,7 @@ package com.gitee.spirit.core.compile; import java.util.List; +import com.gitee.spirit.core.compile.entity.NullVariable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -19,48 +20,48 @@ import com.gitee.spirit.core.element.entity.Token; @Component public class DefaultElementVisitor implements ElementVisitor { - @Autowired - public List actions; - @Autowired - public StatementDeducer deducer; + @Autowired + public List actions; + @Autowired + public StatementDeducer deducer; - @Override - public IVariable visitElement(VisitContext context, Element element) { - try { - for (ElementAction action : actions) { - action.visitElement(context, element); - } - return getVariableIfPossible(context, element); + @Override + public IVariable visitElement(VisitContext context, Element element) { + try { + for (ElementAction action : actions) { + action.visitElement(context, element); + } + return getVariableIfPossible(context, element); - } catch (Exception e) { - element.debug(); - throw new RuntimeException("Failed to derive element!", e); - } - } + } catch (Exception e) { + element.debug(); + throw new RuntimeException("Failed to derive element!", e); + } + } - public IVariable getVariableIfPossible(VisitContext context, Element element) { - if (element.isAssign()) { - return createVariable(element.get(0)); + public IVariable getVariableIfPossible(VisitContext context, Element element) { + if (element.isAssign()) { + return createVariable(element.get(0)); - } else if (element.isDeclare() || element.isDeclareAssign() || element.isForIn()) { - return createVariable(element.get(1)); + } else if (element.isDeclare() || element.isDeclareAssign() || element.isForIn()) { + return createVariable(element.get(1)); - } else if (element.isCatch()) { - return createVariable(element.get(3)); + } else if (element.isCatch()) { + return createVariable(element.get(3)); - } else if (element.isReturn()) { - Statement statement = element.subStmt(1, element.size()); - IVariable variable = new IVariable(null); - variable.setType(deducer.derive(statement)); - return variable; - } - return null; - } + } else if (element.isReturn()) { + Statement statement = element.subStmt(1, element.size()); + IVariable variable = new NullVariable(); + variable.setType(deducer.derive(statement)); + return variable; + } + return null; + } - public IVariable createVariable(Token varToken) { - IVariable variable = new IVariable(varToken); - variable.setType(varToken.attr(Attribute.TYPE)); - return variable; - } + public IVariable createVariable(Token varToken) { + IVariable variable = new IVariable(varToken); + variable.setType(varToken.attr(Attribute.TYPE)); + return variable; + } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/entity/NullVariable.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/entity/NullVariable.java new file mode 100644 index 00000000..424bce2f --- /dev/null +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/entity/NullVariable.java @@ -0,0 +1,17 @@ +package com.gitee.spirit.core.compile.entity; + +import com.gitee.spirit.core.clazz.entity.IVariable; +import com.gitee.spirit.core.element.entity.Token; + +public class NullVariable extends IVariable { + + public NullVariable() { + super(null); + } + + @Override + public String getName() { + return "NO_NAME"; + } + +} -- Gitee From 3a42e82603a7e1d5bebe158f494291cc7a0607c2 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Mon, 5 Jul 2021 23:09:35 +0800 Subject: [PATCH 66/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/spirit/core/clazz/frame/TypeEntity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/TypeEntity.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/TypeEntity.java index 210978eb..b2741b1f 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/TypeEntity.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/frame/TypeEntity.java @@ -9,6 +9,5 @@ import lombok.Setter; @Getter @Setter public abstract class TypeEntity { - @NonNull private IType type; } -- Gitee From 646cec399fbf601e41e2a1ed379c0acc7bb241c7 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Wed, 7 Jul 2021 00:02:37 +0800 Subject: [PATCH 67/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/enums/TokenTypeEnum.java | 1 + .../spirit/common/pattern/CommonPattern.java | 108 ++++--- .../spirit/common/pattern/TypePattern.java | 135 ++++---- .../core/element/DefaultElementBuilder.java | 6 +- .../element/action/DefaultSemanticParser.java | 258 +++++++-------- .../spirit/core/element/frame/Semantic.java | 304 +++++++++--------- .../core/lexer/AbstractCursorLexer.java | 38 +-- .../spirit/core/lexer/AbstractLexer.java | 155 +++++---- .../core/lexer/action/RegionAction.java | 163 +++++----- .../spirit/core/lexer/utils/RegionUtils.java | 96 +++--- 10 files changed, 639 insertions(+), 625 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/TokenTypeEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/TokenTypeEnum.java index dcfc6850..a336708f 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/enums/TokenTypeEnum.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/TokenTypeEnum.java @@ -9,6 +9,7 @@ public enum TokenTypeEnum { TYPE, // Horse ARRAY_INIT, // Horse[1] TYPE_INIT, // Horse() + TYPE_BUILDER_INIT, // Horse{} NULL, // null BOOLEAN, // true CHAR, // 'c' diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/pattern/CommonPattern.java b/spirit-common/src/main/java/com/gitee/spirit/common/pattern/CommonPattern.java index 977f437d..782e7b06 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/pattern/CommonPattern.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/pattern/CommonPattern.java @@ -6,57 +6,61 @@ import com.gitee.spirit.common.enums.TokenTypeEnum; public class CommonPattern { - public static final Pattern ANNOTATION_PATTERN = Pattern.compile("^@[A-Z]+\\w+(\\([\\s\\S]+\\))?$"); - public static final Pattern SUBEXPRESS_PATTERN = Pattern.compile("^\\([\\s\\S]+\\)$"); - public static final Pattern VARIABLE_PATTERN = Pattern.compile("^[a-z]+\\w*$"); - public static final Pattern PREFIX_PATTERN = Pattern.compile("^(\\.)?\\w+$"); - - public static boolean isAnnotation(String word) { - return ANNOTATION_PATTERN.matcher(word).matches(); - } - - public static boolean isSubexpress(String word) { - return SUBEXPRESS_PATTERN.matcher(word).matches(); - } - - public static boolean isVariable(String word) { - return VARIABLE_PATTERN.matcher(word).matches(); - } - - public static boolean isPrefix(String word) { - return PREFIX_PATTERN.matcher(word).matches(); - } - - public static TokenTypeEnum getSubexpressTokenType(String word) { - if (isSubexpress(word)) { - return TypePattern.isAnyType(CommonPattern.getSubexpressValue(word)) ? TokenTypeEnum.CAST : TokenTypeEnum.SUBEXPRESS; - } - return null; - } - - public static String getAnnotationName(String word) { - if (word.contains("(")) { - word = word.substring(0, word.indexOf('(')); - } - return word.substring(word.indexOf('@') + 1); - } - - public static String getSubexpressValue(String word) { - return word.substring(1, word.length() - 1); - } - - public static String getPrefix(String word) { - int start = word.startsWith(".") ? 1 : 0; - int end = word.length(); - if (word.contains("[")) { - int index = word.indexOf("["); - end = index < end ? index : end; - } - if (word.contains("(")) { - int index = word.indexOf("("); - end = index < end ? index : end; - } - return word.substring(start, end); - } + public static final Pattern ANNOTATION_PATTERN = Pattern.compile("^@[A-Z]+\\w+(\\([\\s\\S]+\\))?$"); + public static final Pattern SUBEXPRESS_PATTERN = Pattern.compile("^\\([\\s\\S]+\\)$"); + public static final Pattern VARIABLE_PATTERN = Pattern.compile("^[a-z]+\\w*$"); + public static final Pattern PREFIX_PATTERN = Pattern.compile("^(\\.)?\\w+$"); + + public static boolean isAnnotation(String word) { + return ANNOTATION_PATTERN.matcher(word).matches(); + } + + public static boolean isSubexpress(String word) { + return SUBEXPRESS_PATTERN.matcher(word).matches(); + } + + public static boolean isVariable(String word) { + return VARIABLE_PATTERN.matcher(word).matches(); + } + + public static boolean isPrefix(String word) { + return PREFIX_PATTERN.matcher(word).matches(); + } + + public static TokenTypeEnum getSubexpressTokenType(String word) { + if (isSubexpress(word)) { + return TypePattern.isAnyType(CommonPattern.getSubexpressValue(word)) ? TokenTypeEnum.CAST : TokenTypeEnum.SUBEXPRESS; + } + return null; + } + + public static String getAnnotationName(String word) { + if (word.contains("(")) { + word = word.substring(0, word.indexOf('(')); + } + return word.substring(word.indexOf('@') + 1); + } + + public static String getSubexpressValue(String word) { + return word.substring(1, word.length() - 1); + } + + public static String getPrefix(String word) { + int start = word.startsWith(".") ? 1 : 0; + int end = word.length(); + if (word.contains("{")) { + int index = word.indexOf("{"); + end = Math.min(index, end); + } + if (word.contains("[")) { + int index = word.indexOf("["); + end = Math.min(index, end); + } + if (word.contains("(")) { + int index = word.indexOf("("); + end = Math.min(index, end); + } + return word.substring(start, end); + } } diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/pattern/TypePattern.java b/spirit-common/src/main/java/com/gitee/spirit/common/pattern/TypePattern.java index bb4b3d1f..141fa286 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/pattern/TypePattern.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/pattern/TypePattern.java @@ -7,68 +7,77 @@ import com.gitee.spirit.common.enums.TokenTypeEnum; public class TypePattern { - public static final Pattern TYPE_PATTERN = Pattern.compile("^[A-Z]+\\w*$"); - public static final Pattern TYPE_ARRAY_PATTERN = Pattern.compile("^[A-Z]+\\w*\\[\\]$"); - public static final Pattern GENERIC_TYPE_PATTERN = Pattern.compile("^[A-Z]+\\w*<[\\s\\S]+>$"); - - public static final Pattern PRIMITIVE_ARRAY_SIZE_INIT_PATTERN = Pattern.compile("^(" + PrimitiveEnum.PRIMITIVE_ENUM + ")\\[\\d+\\]$"); - public static final Pattern PRIMITIVE_ARRAY_LITERAL_INIT_PATTERN = Pattern.compile("^(" + PrimitiveEnum.PRIMITIVE_ENUM + ")\\[\\]\\{[\\s\\S]*\\}$"); - public static final Pattern TYPE_ARRAY_SIZE_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*\\[\\d+\\]$"); - public static final Pattern TYPE_ARRAY_LITERAL_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*\\[\\]\\{[\\s\\S]*\\}$"); - public static final Pattern TYPE_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*(<[\\s\\S]+>)?\\([\\s\\S]*\\)$"); - - public static boolean isTypePrefix(String word) { - return PrimitiveEnum.isPrimitiveBySimple(word) || isType(word); - } - - public static boolean isType(String word) { - return !LiteralPattern.isConstVariable(word) && TYPE_PATTERN.matcher(word).matches(); - } - - public static boolean isTypeArray(String word) { - return TYPE_ARRAY_PATTERN.matcher(word).matches(); - } - - public static boolean isGenericType(String word) { - return GENERIC_TYPE_PATTERN.matcher(word).matches(); - } - - public static boolean isPrimitiveArraySizeInit(String word) { - return PRIMITIVE_ARRAY_SIZE_INIT_PATTERN.matcher(word).matches(); - } - - public static boolean isPrimitiveArrayLiteralInit(String word) { - return PRIMITIVE_ARRAY_LITERAL_INIT_PATTERN.matcher(word).matches(); - } - - public static boolean isTypeArraySizeInit(String word) { - return TYPE_ARRAY_SIZE_INIT_PATTERN.matcher(word).matches(); - } - - public static boolean isTypeArrayLiteralInit(String word) { - return TYPE_ARRAY_LITERAL_INIT_PATTERN.matcher(word).matches(); - } - - public static boolean isTypeInit(String word) { - return TYPE_INIT_PATTERN.matcher(word).matches(); - } - - public static boolean isAnyType(String word) { - return !LiteralPattern.isConstVariable(word) && (PrimitiveEnum.isPrimitiveBySimple(word) || PrimitiveEnum.isPrimitiveArrayBySimple(word) || isType(word) - || isTypeArray(word) || isGenericType(word)); - } - - public static TokenTypeEnum getTokenType(String word) { - if (isPrimitiveArraySizeInit(word) || isPrimitiveArrayLiteralInit(word)) { - return TokenTypeEnum.ARRAY_INIT; - - } else if (isTypeArraySizeInit(word) || isTypeArrayLiteralInit(word)) { - return TokenTypeEnum.ARRAY_INIT; - - } else if (isTypeInit(word)) { - return TokenTypeEnum.TYPE_INIT; - } - return null; - } + public static final Pattern TYPE_PATTERN = Pattern.compile("^[A-Z]+\\w*$"); + public static final Pattern TYPE_ARRAY_PATTERN = Pattern.compile("^[A-Z]+\\w*\\[\\]$"); + public static final Pattern GENERIC_TYPE_PATTERN = Pattern.compile("^[A-Z]+\\w*<[\\s\\S]+>$"); + + public static final Pattern PRIMITIVE_ARRAY_SIZE_INIT_PATTERN = Pattern.compile("^(" + PrimitiveEnum.PRIMITIVE_ENUM + ")\\[\\d+\\]$"); + public static final Pattern PRIMITIVE_ARRAY_LITERAL_INIT_PATTERN = Pattern.compile("^(" + PrimitiveEnum.PRIMITIVE_ENUM + ")\\[\\]\\{[\\s\\S]*\\}$"); + public static final Pattern TYPE_ARRAY_SIZE_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*\\[\\d+\\]$"); + public static final Pattern TYPE_ARRAY_LITERAL_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*\\[\\]\\{[\\s\\S]*\\}$"); + public static final Pattern TYPE_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*(<[\\s\\S]+>)?\\([\\s\\S]*\\)$"); + public static final Pattern TYPE_BUILDER_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*(<[\\s\\S]+>)?\\{[\\s\\S]*\\}$"); + + public static boolean isTypePrefix(String word) { + return PrimitiveEnum.isPrimitiveBySimple(word) || isType(word); + } + + public static boolean isType(String word) { + return !LiteralPattern.isConstVariable(word) && TYPE_PATTERN.matcher(word).matches(); + } + + public static boolean isTypeArray(String word) { + return TYPE_ARRAY_PATTERN.matcher(word).matches(); + } + + public static boolean isGenericType(String word) { + return GENERIC_TYPE_PATTERN.matcher(word).matches(); + } + + public static boolean isPrimitiveArraySizeInit(String word) { + return PRIMITIVE_ARRAY_SIZE_INIT_PATTERN.matcher(word).matches(); + } + + public static boolean isPrimitiveArrayLiteralInit(String word) { + return PRIMITIVE_ARRAY_LITERAL_INIT_PATTERN.matcher(word).matches(); + } + + public static boolean isTypeArraySizeInit(String word) { + return TYPE_ARRAY_SIZE_INIT_PATTERN.matcher(word).matches(); + } + + public static boolean isTypeArrayLiteralInit(String word) { + return TYPE_ARRAY_LITERAL_INIT_PATTERN.matcher(word).matches(); + } + + public static boolean isTypeInit(String word) { + return TYPE_INIT_PATTERN.matcher(word).matches(); + } + + private static boolean isTypeBuilderInit(String word) { + return TYPE_BUILDER_INIT_PATTERN.matcher(word).matches(); + } + + public static boolean isAnyType(String word) { + return !LiteralPattern.isConstVariable(word) && (PrimitiveEnum.isPrimitiveBySimple(word) || PrimitiveEnum.isPrimitiveArrayBySimple(word) || isType(word) + || isTypeArray(word) || isGenericType(word)); + } + + public static TokenTypeEnum getTokenType(String word) { + if (isPrimitiveArraySizeInit(word) || isPrimitiveArrayLiteralInit(word)) { + return TokenTypeEnum.ARRAY_INIT; + + } else if (isTypeArraySizeInit(word) || isTypeArrayLiteralInit(word)) { + return TokenTypeEnum.ARRAY_INIT; + + } else if (isTypeInit(word)) { + return TokenTypeEnum.TYPE_INIT; + + } else if (isTypeBuilderInit(word)) { + return TokenTypeEnum.TYPE_BUILDER_INIT; + } + return null; + } + } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultElementBuilder.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultElementBuilder.java index 787b5a6c..fb74e9b3 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultElementBuilder.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/DefaultElementBuilder.java @@ -45,8 +45,7 @@ public class DefaultElementBuilder implements ElementBuilder { Modifiers modifiers = new Modifiers(tokens); Statement statement = new Statement(tokens); SyntaxResult result = syntaxParser.parseSyntax(tokens, statement); - Element element = new Element(line, modifiers, statement, result.syntax, result.syntaxTree); - return element; + return new Element(line, modifiers, statement, result.syntax, result.syntaxTree); } catch (Exception e) { line.debug(); @@ -58,8 +57,7 @@ public class DefaultElementBuilder implements ElementBuilder { public Element build(Statement statement) { Assert.notEmpty(statement, "Statement cannot be empty!"); SyntaxResult result = syntaxParser.parseSyntax(statement.list, statement); - Element element = new Element(null, null, statement, result.syntax, result.syntaxTree); - return element; + return new Element(null, null, statement, result.syntax, result.syntaxTree); } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java index 11488448..61c362f4 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java @@ -22,134 +22,134 @@ import cn.hutool.core.lang.Assert; @Component public class DefaultSemanticParser extends AbstractSemanticParser { - @Autowired - public Lexer lexer; - - @Override - public List getTokens(SemanticContext context, List words) { - context.words = words; - List tokens = new ArrayList<>(); - for (context.index = 0; context.index < words.size(); context.index++) { - Token token = getToken(context, words.get(context.index)); - tokens.add(token); - } - return tokens; - } - - @Override - public Token getToken(SemanticContext context, String word) { - Token token = new Token(); - - token.tokenType = getTokenType(context, word); - Assert.notNull(token.tokenType, "Token type cannot be null!word:[" + word + "]"); - - token.value = getTokenValue(token, word); - Assert.notNull(token.value, "Token value cannot be null!word:[" + word + "]"); - - setTokenAttributes(token, word); - return token; - } - - public TokenTypeEnum getTokenType(SemanticContext context, String word) { - if (!context.subStatement) { - return getCommonTokenType(context, word); - } else { - if (context.insideType) { - if ("<".equals(word) || ">".equals(word)) { - return TokenTypeEnum.SEPARATOR; - - } else if ("?".equals(word)) { - return TokenTypeEnum.TYPE; - } - } - if (context.index == 0 && CommonPattern.isPrefix(word)) { - return TokenTypeEnum.PREFIX; - } - return getCommonTokenType(context, word); - } - } - - public TokenTypeEnum getCommonTokenType(SemanticContext context, String word) { - if (isAccessPath(word)) { - return TokenTypeEnum.ACCESS_PATH; - - } else if (isAnnotation(word)) { - return TokenTypeEnum.ANNOTATION; - - } else if (isKeyword(word)) { - return TokenTypeEnum.KEYWORD; - - } else if (isOperator(word)) { - return TokenTypeEnum.OPERATOR; - - } else if (isSeparator(word)) { - return TokenTypeEnum.SEPARATOR; - - } else if (isType(word)) { - return TokenTypeEnum.TYPE; - } - - TokenTypeEnum tokenType = TypePattern.getTokenType(word); - if (tokenType != null) { - return tokenType; - } - - tokenType = LiteralPattern.getTokenType(word); - if (tokenType != null) { - return tokenType; - } - - tokenType = CommonPattern.getSubexpressTokenType(word); - if (tokenType != null) { - return tokenType; - } - - if (isVariable(word)) { - return TokenTypeEnum.VARIABLE; - } - - tokenType = AccessPattern.getTokenType(word); - if (tokenType != null) { - return tokenType; - } - - return null; - } - - public Object getTokenValue(Token token, String word) { - if (token.isType()) { - return word.contains("<") || word.contains(">") ? getStatement(true, word) : word; - - } else if (token.isArrayInit() || token.isList() || token.isMap() || token.isSubexpress() || token.isInvoke()) { - // 拆分数组是为了更好的添加new这个关键字 - return getStatement(false, word); - } - return word; - } - - public Statement getStatement(boolean insideType, String word) { - List words = insideType ? lexer.getSubWords(word, '<', '>') : lexer.getSubWords(word, '(', ')', '[', ']', '{', '}'); - List tokens = getTokens(new SemanticContext(true, insideType), words); - Assert.notNull(tokens, "Tokens cannot be null!"); - return new Statement(tokens); - } - - public void setTokenAttributes(Token token, String word) { - if (token.isAnnotation()) { - token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getAnnotationName(word)); - - } else if (token.isArrayInit()) { - token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getPrefix(word) + "[]"); - - } else if (token.isTypeInit()) { - token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getPrefix(word)); - - } else if (token.isCast()) { - token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getSubexpressValue(word)); - - } else if (token.isAccess()) { - token.setAttr(Attribute.MEMBER_NAME, CommonPattern.getPrefix(word)); - } - } + @Autowired + public Lexer lexer; + + @Override + public List getTokens(SemanticContext context, List words) { + context.words = words; + List tokens = new ArrayList<>(); + for (context.index = 0; context.index < words.size(); context.index++) { + Token token = getToken(context, words.get(context.index)); + tokens.add(token); + } + return tokens; + } + + @Override + public Token getToken(SemanticContext context, String word) { + Token token = new Token(); + + token.tokenType = getTokenType(context, word); + Assert.notNull(token.tokenType, "Token type cannot be null!word:[" + word + "]"); + + token.value = getTokenValue(token, word); + Assert.notNull(token.value, "Token value cannot be null!word:[" + word + "]"); + + setTokenAttributes(token, word); + return token; + } + + public TokenTypeEnum getTokenType(SemanticContext context, String word) { + if (!context.subStatement) { + return getCommonTokenType(context, word); + } else { + if (context.insideType) { + if ("<".equals(word) || ">".equals(word)) { + return TokenTypeEnum.SEPARATOR; + + } else if ("?".equals(word)) { + return TokenTypeEnum.TYPE; + } + } + if (context.index == 0 && CommonPattern.isPrefix(word)) { + return TokenTypeEnum.PREFIX; + } + return getCommonTokenType(context, word); + } + } + + public TokenTypeEnum getCommonTokenType(SemanticContext context, String word) { + if (isAccessPath(word)) { + return TokenTypeEnum.ACCESS_PATH; + + } else if (isAnnotation(word)) { + return TokenTypeEnum.ANNOTATION; + + } else if (isKeyword(word)) { + return TokenTypeEnum.KEYWORD; + + } else if (isOperator(word)) { + return TokenTypeEnum.OPERATOR; + + } else if (isSeparator(word)) { + return TokenTypeEnum.SEPARATOR; + + } else if (isType(word)) { + return TokenTypeEnum.TYPE; + } + + TokenTypeEnum tokenType = TypePattern.getTokenType(word); + if (tokenType != null) { + return tokenType; + } + + tokenType = LiteralPattern.getTokenType(word); + if (tokenType != null) { + return tokenType; + } + + tokenType = CommonPattern.getSubexpressTokenType(word); + if (tokenType != null) { + return tokenType; + } + + if (isVariable(word)) { + return TokenTypeEnum.VARIABLE; + } + + tokenType = AccessPattern.getTokenType(word); + if (tokenType != null) { + return tokenType; + } + + return null; + } + + public Object getTokenValue(Token token, String word) { + if (token.isType()) { + return word.contains("<") || word.contains(">") ? getStatement(true, word) : word; + + } else if (token.isArrayInit() || token.isList() || token.isMap() || token.isSubexpress() || token.isInvoke()) { + // 拆分数组是为了更好的添加new这个关键字 + return getStatement(false, word); + } + return word; + } + + public Statement getStatement(boolean insideType, String word) { + List words = insideType ? lexer.getSubWords(word, '<', '>') : lexer.getSubWords(word, '(', ')', '[', ']', '{', '}'); + List tokens = getTokens(new SemanticContext(true, insideType), words); + Assert.notNull(tokens, "Tokens cannot be null!"); + return new Statement(tokens); + } + + public void setTokenAttributes(Token token, String word) { + if (token.isAnnotation()) { + token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getAnnotationName(word)); + + } else if (token.isArrayInit()) { + token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getPrefix(word) + "[]"); + + } else if (token.isTypeInit() || token.isTypeBuilderInit()) { + token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getPrefix(word)); + + } else if (token.isCast()) { + token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getSubexpressValue(word)); + + } else if (token.isAccess()) { + token.setAttr(Attribute.MEMBER_NAME, CommonPattern.getPrefix(word)); + } + } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java index 245d559a..82a2f1b2 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java @@ -8,205 +8,209 @@ import com.gitee.spirit.common.enums.TokenTypeEnum; public abstract class Semantic extends Attributes { - public TokenTypeEnum tokenType; + public TokenTypeEnum tokenType; - public Semantic(TokenTypeEnum tokenType, Map attributes) { - super(attributes); - this.tokenType = tokenType; - } + public Semantic(TokenTypeEnum tokenType, Map attributes) { + super(attributes); + this.tokenType = tokenType; + } - public boolean isAccessPath() { - return tokenType == TokenTypeEnum.ACCESS_PATH; - } + public boolean isAccessPath() { + return tokenType == TokenTypeEnum.ACCESS_PATH; + } - public boolean isAnnotation() { - return tokenType == TokenTypeEnum.ANNOTATION; - } + public boolean isAnnotation() { + return tokenType == TokenTypeEnum.ANNOTATION; + } - public boolean isKeyword() { - return tokenType == TokenTypeEnum.KEYWORD; - } + public boolean isKeyword() { + return tokenType == TokenTypeEnum.KEYWORD; + } - public boolean isOperator() { - return tokenType == TokenTypeEnum.OPERATOR; - } + public boolean isOperator() { + return tokenType == TokenTypeEnum.OPERATOR; + } - public boolean isSeparator() { - return tokenType == TokenTypeEnum.SEPARATOR; - } + public boolean isSeparator() { + return tokenType == TokenTypeEnum.SEPARATOR; + } - public boolean isType() { - return tokenType == TokenTypeEnum.TYPE; - } + public boolean isType() { + return tokenType == TokenTypeEnum.TYPE; + } - public boolean isArrayInit() { - return tokenType == TokenTypeEnum.ARRAY_INIT; - } + public boolean isArrayInit() { + return tokenType == TokenTypeEnum.ARRAY_INIT; + } - public boolean isTypeInit() { - return tokenType == TokenTypeEnum.TYPE_INIT; - } + public boolean isTypeInit() { + return tokenType == TokenTypeEnum.TYPE_INIT; + } - public boolean isNull() { - return tokenType == TokenTypeEnum.NULL; - } + public boolean isTypeBuilderInit() { + return tokenType == TokenTypeEnum.TYPE_BUILDER_INIT; + } - public boolean isBoolean() { - return tokenType == TokenTypeEnum.BOOLEAN; - } + public boolean isNull() { + return tokenType == TokenTypeEnum.NULL; + } - public boolean isChar() { - return tokenType == TokenTypeEnum.CHAR; - } + public boolean isBoolean() { + return tokenType == TokenTypeEnum.BOOLEAN; + } - public boolean isInt() { - return tokenType == TokenTypeEnum.INT; - } + public boolean isChar() { + return tokenType == TokenTypeEnum.CHAR; + } - public boolean isLong() { - return tokenType == TokenTypeEnum.LONG; - } + public boolean isInt() { + return tokenType == TokenTypeEnum.INT; + } - public boolean isDouble() { - return tokenType == TokenTypeEnum.DOUBLE; - } + public boolean isLong() { + return tokenType == TokenTypeEnum.LONG; + } - public boolean isString() { - return tokenType == TokenTypeEnum.STRING; - } + public boolean isDouble() { + return tokenType == TokenTypeEnum.DOUBLE; + } - public boolean isList() { - return tokenType == TokenTypeEnum.LIST; - } + public boolean isString() { + return tokenType == TokenTypeEnum.STRING; + } - public boolean isMap() { - return tokenType == TokenTypeEnum.MAP; - } + public boolean isList() { + return tokenType == TokenTypeEnum.LIST; + } - public boolean isSubexpress() { - return tokenType == TokenTypeEnum.SUBEXPRESS; - } + public boolean isMap() { + return tokenType == TokenTypeEnum.MAP; + } - public boolean isCast() { - return tokenType == TokenTypeEnum.CAST; - } + public boolean isSubexpress() { + return tokenType == TokenTypeEnum.SUBEXPRESS; + } - public boolean isVariable() { - return tokenType == TokenTypeEnum.VARIABLE; - } + public boolean isCast() { + return tokenType == TokenTypeEnum.CAST; + } - public boolean isLocalMethod() { - return tokenType == TokenTypeEnum.LOCAL_METHOD; - } + public boolean isVariable() { + return tokenType == TokenTypeEnum.VARIABLE; + } - public boolean isVisitField() { - return tokenType == TokenTypeEnum.VISIT_FIELD; - } + public boolean isLocalMethod() { + return tokenType == TokenTypeEnum.LOCAL_METHOD; + } - public boolean isVisitMethod() { - return tokenType == TokenTypeEnum.VISIT_METHOD; - } + public boolean isVisitField() { + return tokenType == TokenTypeEnum.VISIT_FIELD; + } - public boolean isVisitIndex() { - return tokenType == TokenTypeEnum.VISIT_INDEX; - } + public boolean isVisitMethod() { + return tokenType == TokenTypeEnum.VISIT_METHOD; + } - public boolean isPrefix() { - return tokenType == TokenTypeEnum.PREFIX; - } + public boolean isVisitIndex() { + return tokenType == TokenTypeEnum.VISIT_INDEX; + } - public boolean isCustomPrefix() { - return tokenType == TokenTypeEnum.CUSTOM_PREFIX; - } + public boolean isPrefix() { + return tokenType == TokenTypeEnum.PREFIX; + } - public boolean isCustomSuffix() { - return tokenType == TokenTypeEnum.CUSTOM_SUFFIX; - } + public boolean isCustomPrefix() { + return tokenType == TokenTypeEnum.CUSTOM_PREFIX; + } - public boolean isCustomExpress() { - return tokenType == TokenTypeEnum.CUSTOM_EXPRESS; - } + public boolean isCustomSuffix() { + return tokenType == TokenTypeEnum.CUSTOM_SUFFIX; + } - public boolean isInit() { - return isArrayInit() || isTypeInit(); - } + public boolean isCustomExpress() { + return tokenType == TokenTypeEnum.CUSTOM_EXPRESS; + } - public boolean isLiteral() { - return isNull() || isBoolean() || isChar() || isInt() || isLong() || isDouble() || isString() || isList() || isMap(); - } + public boolean isInit() { + return isArrayInit() || isTypeInit(); + } - public boolean isNumber() { - return isInt() || isLong() || isDouble(); - } + public boolean isLiteral() { + return isNull() || isBoolean() || isChar() || isInt() || isLong() || isDouble() || isString() || isList() || isMap(); + } - public boolean isAccess() { - return isLocalMethod() || isVisitField() || isVisitMethod() || isVisitIndex(); - } + public boolean isNumber() { + return isInt() || isLong() || isDouble(); + } - public boolean isInvoke() { - return isTypeInit() || isLocalMethod() || isVisitMethod(); - } + public boolean isAccess() { + return isLocalMethod() || isVisitField() || isVisitMethod() || isVisitIndex(); + } - public boolean isVisit() { - return isVisitField() || isVisitMethod() || isVisitIndex(); - } + public boolean isInvoke() { + return isTypeInit() || isLocalMethod() || isVisitMethod(); + } - public boolean hasSubStmt() { - return isList() || isMap() || isSubexpress() || isInvoke(); - } + public boolean isVisit() { + return isVisitField() || isVisitMethod() || isVisitIndex(); + } - public boolean isModifier() { - return isKeyword() && KeywordEnum.isModifier(getValue()); - } + public boolean hasSubStmt() { + return isList() || isMap() || isSubexpress() || isInvoke(); + } - public boolean isInstanceof() { - return isKeyword() && KeywordEnum.INSTANCEOF.value.equals(getValue().toString()); - } + public boolean isModifier() { + return isKeyword() && KeywordEnum.isModifier(getValue()); + } - public boolean isArithmetic() { - return isOperator() && OperatorEnum.isArithmetic(getValue().toString()); - } + public boolean isInstanceof() { + return isKeyword() && KeywordEnum.INSTANCEOF.value.equals(getValue().toString()); + } - public boolean isBitwise() { - return isOperator() && OperatorEnum.isBitwise(getValue().toString()); - } + public boolean isArithmetic() { + return isOperator() && OperatorEnum.isArithmetic(getValue().toString()); + } - public boolean isRelation() { - return isOperator() && OperatorEnum.isRelation(getValue().toString()); - } + public boolean isBitwise() { + return isOperator() && OperatorEnum.isBitwise(getValue().toString()); + } - public boolean isLogical() { - return isOperator() && OperatorEnum.isLogical(getValue().toString()); - } + public boolean isRelation() { + return isOperator() && OperatorEnum.isRelation(getValue().toString()); + } - public boolean isAssign() { - return isOperator() && OperatorEnum.isAssign(getValue().toString()); - } + public boolean isLogical() { + return isOperator() && OperatorEnum.isLogical(getValue().toString()); + } - public boolean isEquals() { - return isOperator() && OperatorEnum.EQUAL.value.equals(getValue()); - } + public boolean isAssign() { + return isOperator() && OperatorEnum.isAssign(getValue().toString()); + } - public boolean isUnequals() { - return isOperator() && OperatorEnum.UNEQUAL.value.equals(getValue()); - } + public boolean isEquals() { + return isOperator() && OperatorEnum.EQUAL.value.equals(getValue()); + } - public boolean isShift() { - return isOperator() && (OperatorEnum.LEFT_SHIFT.value.equals(getValue()) || OperatorEnum.RIGHT_SHIFT.value.equals(getValue())); - } + public boolean isUnequals() { + return isOperator() && OperatorEnum.UNEQUAL.value.equals(getValue()); + } - public boolean isNegate() { - return isOperator() && OperatorEnum.NEGATE.value.equals(getValue()); - } + public boolean isShift() { + return isOperator() && (OperatorEnum.LEFT_SHIFT.value.equals(getValue()) || OperatorEnum.RIGHT_SHIFT.value.equals(getValue())); + } - public boolean isLogicAnd() { - return isOperator() && OperatorEnum.AND.value.equals(getValue()); - } + public boolean isNegate() { + return isOperator() && OperatorEnum.NEGATE.value.equals(getValue()); + } - public boolean isLogicOr() { - return isOperator() && OperatorEnum.OR.value.equals(getValue()); - } + public boolean isLogicAnd() { + return isOperator() && OperatorEnum.AND.value.equals(getValue()); + } - public abstract T getValue(); + public boolean isLogicOr() { + return isOperator() && OperatorEnum.OR.value.equals(getValue()); + } + + public abstract T getValue(); } diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java index ff2e6b52..6f37f72f 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java @@ -7,26 +7,26 @@ import com.gitee.spirit.core.lexer.entity.LexerContext; public abstract class AbstractCursorLexer extends AbstractLexer { - @Override - public Result handle(CharEvent event) { - LexerContext context = (LexerContext) event.context; - char ch = event.ch; - if ((context.startIndex < 0 && isContinuous(ch)) || isRefreshed(ch)) { - context.startIndex = context.index; - } - Result result = super.handle(event); - if (!isContinuous(ch)) { - context.startIndex = -1; - } - return result; - } + @Override + public Result handle(CharEvent event) { + LexerContext context = (LexerContext) event.context; + char ch = event.ch; + if ((context.startIndex < 0 && isContinuous(ch)) || isRefreshed(ch)) { + context.startIndex = context.index; + } + Result result = super.handle(event); + if (!isContinuous(ch)) { + context.startIndex = -1; + } + return result; + } - public boolean isContinuous(char ch) { - return LineUtils.isLetter(ch) || ch == '@' || ch == '.'; - } + public boolean isContinuous(char ch) { + return LineUtils.isLetter(ch) || ch == '@' || ch == '.' || ch == '$'; + } - public boolean isRefreshed(char ch) { - return ch == '.'; - } + public boolean isRefreshed(char ch) { + return ch == '.'; + } } diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractLexer.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractLexer.java index 47779d14..3e0dd8c0 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractLexer.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractLexer.java @@ -20,89 +20,88 @@ import com.gitee.spirit.core.lexer.utils.RegionUtils.completedRegion; public abstract class AbstractLexer extends AbstractCharsHandler implements Lexer { - @Autowired - public List actions; + @Autowired + public List actions; - @Override - public boolean isTrigger(CharEvent event) { - LexerContext context = (LexerContext) event.context; - List regions = context.regions; - if (regions != null && !regions.isEmpty()) { - for (int index = regions.size() - 1; index >= 0; index--) { - Region existRegion = regions.get(index); - if (existRegion.contains(context.index)) { - return false; - } else if (context.index >= existRegion.endIndex) { - return true; - } - } - } - return true; - } + @Override + public boolean isTrigger(CharEvent event) { + LexerContext context = (LexerContext) event.context; + List regions = context.regions; + if (regions != null && !regions.isEmpty()) { + for (int index = regions.size() - 1; index >= 0; index--) { + Region existRegion = regions.get(index); + if (existRegion.contains(context.index)) { + return false; + } else if (context.index >= existRegion.endIndex) { + return true; + } + } + } + return true; + } - @Override - public Result handle(CharEvent event) { - LexerContext context = (LexerContext) event.context; - for (LexerAction action : actions) { - if (action.isTrigger(event)) { - Result result = action.handle(event); - if (result != null) { - if (result.data != null) { - if (result.data instanceof Region) { - appendRegion(context, result.get()); + @Override + public Result handle(CharEvent event) { + LexerContext context = (LexerContext) event.context; + for (LexerAction action : actions) { + if (action.isTrigger(event)) { + Result result = action.handle(event); + if (result != null) { + if (result.data != null) { + if (result.data instanceof Region) { + appendRegion(context, result.get()); - } else if (result.data instanceof List) { - List regions = result.get(); - regions.forEach(region -> appendRegion(context, region)); - } - } - if (result.code == StateEnum.SKIP.ordinal()) { - break; - } else if (result.code == StateEnum.RESET.ordinal() || result.code == StateEnum.BREAK.ordinal()) { - return result; - } - } - } - } - return null; - } + } else if (result.data instanceof List) { + List regions = result.get(); + regions.forEach(region -> appendRegion(context, region)); + } + } + if (result.code == StateEnum.SKIP.ordinal()) { + break; + } else if (result.code == StateEnum.RESET.ordinal() || result.code == StateEnum.BREAK.ordinal()) { + return result; + } + } + } + } + return null; + } - public void appendRegion(LexerContext context, Region region) { - List regions = context.regions; - if (regions.isEmpty()) { - regions.add(region); - } else { - for (int index = regions.size() - 1; index >= 0; index--) { - Region existRegion = regions.get(index); - if (region.isOverlap(existRegion)) { - throw new RuntimeException("There are overlapping regions!"); - } - if (region.isAfter(existRegion)) { - regions.add(index + 1, region); - break; - } - } - } - } + public void appendRegion(LexerContext context, Region region) { + List regions = context.regions; + if (regions.isEmpty()) { + regions.add(region); + return; + } + for (int index = regions.size() - 1; index >= 0; index--) { + Region existRegion = regions.get(index); + if (region.isOverlap(existRegion)) { + throw new RuntimeException("There are overlapping regions!"); + } + if (region.isAfter(existRegion)) { + regions.add(index + 1, region); + break; + } + } + } - @Override - public Result buildResult(CharsContext context, StringBuilder builder) { - LexerContext lexerContext = (LexerContext) context; - // 使用标记收集算法后,补全未标记的部分 - List regions = RegionUtils.completeRegions(builder, lexerContext.regions); - List words = RegionUtils.subRegions(builder, regions, this::addToWords); - return new Result(words); - } + @Override + public Result buildResult(CharsContext context, StringBuilder builder) { + LexerContext lexerContext = (LexerContext) context; + List regions = RegionUtils.completeRegions(builder, lexerContext.regions);// 使用标记收集算法后,补全未标记的部分 + List words = RegionUtils.subRegions(builder, regions, this::addToWords); + return new Result(words); + } - public void addToWords(List words, Region region, String text) { - if (region instanceof completedRegion) { - if (text.indexOf(".") > 0 && !LiteralPattern.isDouble(text) && !AccessPattern.isAccessPath(text)) { - List subWords = Arrays.asList(text.replaceAll("\\.", " .").split(" ")); - words.addAll(subWords); - return; - } - } - words.add(text); - } + public void addToWords(List words, Region region, String text) { + if (region instanceof completedRegion) { + if (text.indexOf(".") > 0 && !LiteralPattern.isDouble(text) && !AccessPattern.isAccessPath(text)) { + List subWords = Arrays.asList(text.replaceAll("\\.", " .").split(" ")); + words.addAll(subWords); + return; + } + } + words.add(text); + } } diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java index 7e8fb8db..0db8b6c4 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/action/RegionAction.java @@ -19,87 +19,86 @@ import com.gitee.spirit.core.lexer.utils.RegionUtils; @Order(-80) public class RegionAction implements LexerAction { - @Override - public boolean isTrigger(CharEvent event) { - LexerContext context = (LexerContext) event.context; - StringBuilder builder = context.builder; - char ch = event.ch; - - if (context.index == builder.length() - 1) { - return false; - - } else if (ch == '"' || ch == '\'' || ch == '{' || ch == '(' || ch == '[') { - return true; - - } else if (ch == '<') { - if (context.startIndex >= 0) { - char d = builder.charAt(context.startIndex); - if (d >= 'A' && d <= 'Z') { - return true; - } - } - } - - return false; - } - - @Override - public Result handle(CharEvent event) { - LexerContext context = (LexerContext) event.context; - StringBuilder builder = context.builder; - char ch = event.ch; - - if (ch == '"') { - Region region = RegionUtils.findRegion(builder, context.index, '"', '"'); - return pushStack(event, ListUtils.asListNonNull(region)); - - } else if (ch == '\'') { - Region region = RegionUtils.findRegion(builder, context.index, '\'', '\''); - return pushStack(event, ListUtils.asListNonNull(region)); - - } else if (ch == '{') { - Region region = RegionUtils.findRegion(builder, context.index, '{', '}'); - return pushStack(event, ListUtils.asListNonNull(region)); - - } else if (ch == '(') { - Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; - Region region1 = RegionUtils.findRegion(builder, context.index, '(', ')'); - return pushStack(event, ListUtils.asListNonNull(region0, region1)); - - } else if (ch == '[') { - Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; - if (region0 != null && !TypePattern.isTypePrefix(RegionUtils.subRegion(builder, region0))) { - region0 = null; - } - Region region1 = RegionUtils.findRegion(builder, context.index, '[', ']'); - Region region2 = null; - if (region0 != null) { - if (isCharAt(builder, region1.endIndex, '{')) { - region2 = RegionUtils.findRegion(builder, region1.endIndex, '{', '}'); - - } else if (isCharAt(builder, region1.endIndex, ' ') && isCharAt(builder, region1.endIndex + 1, '{')) { - region2 = RegionUtils.findRegion(builder, region1.endIndex + 1, '{', '}'); - } - } - return pushStack(event, ListUtils.asListNonNull(region0, region1, region2)); - - } else if (ch == '<') { - Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; - Region region1 = RegionUtils.findRegion(builder, context.index, '<', '>'); - Region region2 = isCharAt(builder, region1.endIndex, '(') ? RegionUtils.findRegion(builder, region1.endIndex, '(', ')') : null; - return pushStack(event, ListUtils.asListNonNull(region0, region1, region2)); - } - - throw new RuntimeException("Unhandled branch!"); - } - - public Result pushStack(CharEvent event, List regions) { - Region mergedRegion = RegionUtils.mergeRegions(regions); - return new Result(StateEnum.SKIP.ordinal(), mergedRegion); - } - - public boolean isCharAt(StringBuilder builder, int index, char ch) { - return index < builder.length() && builder.charAt(index) == ch; - } + @Override + public boolean isTrigger(CharEvent event) { + LexerContext context = (LexerContext) event.context; + StringBuilder builder = context.builder; + char ch = event.ch; + + if (context.index == builder.length() - 1) { + return false; + + } else if (ch == '"' || ch == '\'' || ch == '{' || ch == '(' || ch == '[') { + return true; + + } else if (ch == '<') { + if (context.startIndex >= 0) { + char d = builder.charAt(context.startIndex); + if (d >= 'A' && d <= 'Z') { + return true; + } + } + } + + return false; + } + + @Override + public Result handle(CharEvent event) { + LexerContext context = (LexerContext) event.context; + StringBuilder builder = context.builder; + char ch = event.ch; + + if (ch == '"') { + Region region = RegionUtils.findRegion(builder, context.index, '"', '"'); + return pushStack(event, ListUtils.asListNonNull(region)); + + } else if (ch == '\'') { + Region region = RegionUtils.findRegion(builder, context.index, '\'', '\''); + return pushStack(event, ListUtils.asListNonNull(region)); + + } else if (ch == '{') { + Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; + Region region1 = RegionUtils.findRegion(builder, context.index, '{', '}'); + return pushStack(event, ListUtils.asListNonNull(region0, region1)); + + } else if (ch == '(') { + Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; + Region region1 = RegionUtils.findRegion(builder, context.index, '(', ')'); + return pushStack(event, ListUtils.asListNonNull(region0, region1)); + + } else if (ch == '[') { + Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; + region0 = region0 != null && TypePattern.isTypePrefix(RegionUtils.subRegion(builder, region0)) ? region0 : null; + Region region1 = RegionUtils.findRegion(builder, context.index, '[', ']'); + Region region2 = null; + if (region0 != null) { + if (isCharAt(builder, region1.endIndex, '{')) { + region2 = RegionUtils.findRegion(builder, region1.endIndex, '{', '}'); + + } else if (isCharAt(builder, region1.endIndex, ' ') && isCharAt(builder, region1.endIndex + 1, '{')) { + region2 = RegionUtils.findRegion(builder, region1.endIndex + 1, '{', '}'); + } + } + return pushStack(event, ListUtils.asListNonNull(region0, region1, region2)); + + } else if (ch == '<') { + Region region0 = context.startIndex >= 0 ? new Region(context.startIndex, context.index) : null; + Region region1 = RegionUtils.findRegion(builder, context.index, '<', '>'); + Region region2 = isCharAt(builder, region1.endIndex, '(') ? RegionUtils.findRegion(builder, region1.endIndex, '(', ')') : null; + return pushStack(event, ListUtils.asListNonNull(region0, region1, region2)); + } + + throw new RuntimeException("Unhandled branch!"); + } + + public boolean isCharAt(StringBuilder builder, int index, char ch) { + return index < builder.length() && builder.charAt(index) == ch; + } + + public Result pushStack(CharEvent event, List regions) { + Region mergedRegion = RegionUtils.mergeRegions(regions); + return new Result(StateEnum.SKIP.ordinal(), mergedRegion); + } } diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/utils/RegionUtils.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/utils/RegionUtils.java index a66e023c..d5a93e10 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/utils/RegionUtils.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/utils/RegionUtils.java @@ -13,59 +13,59 @@ import cn.hutool.core.lang.Assert; public class RegionUtils { - public static Region findRegion(StringBuilder builder, int fromIndex, char leftChar, char rightChar) { - int endIndex = LineUtils.findEndIndex(builder, fromIndex, leftChar, rightChar); - return endIndex != -1 ? new Region(fromIndex, endIndex + 1) : null; - } + public static Region findRegion(StringBuilder builder, int fromIndex, char leftChar, char rightChar) { + int endIndex = LineUtils.findEndIndex(builder, fromIndex, leftChar, rightChar); + return endIndex != -1 ? new Region(fromIndex, endIndex + 1) : null; + } - public static String subRegion(StringBuilder builder, Region region) { - return builder.substring(region.startIndex, region.endIndex); - } + public static String subRegion(StringBuilder builder, Region region) { + return builder.substring(region.startIndex, region.endIndex); + } - public static Region mergeRegions(List regions) { - Assert.notEmpty(regions, "The regions cannot be empty!"); - Region startRegion = ListUtils.findOneByScore(regions, region -> 0 - region.startIndex); - Region endRegion = ListUtils.findOneByScore(regions, region -> region.endIndex); - return new Region(startRegion.startIndex, endRegion.endIndex); - } + public static Region mergeRegions(List regions) { + Assert.notEmpty(regions, "The regions cannot be empty!"); + Region startRegion = ListUtils.findOneByScore(regions, region -> -region.startIndex); + Region endRegion = ListUtils.findOneByScore(regions, region -> region.endIndex); + return new Region(startRegion.startIndex, endRegion.endIndex); + } - public static List completeRegions(StringBuilder builder, List regions) { - List completedRegions = new ArrayList<>(); - int lastIndex = 0; - for (Region region : regions) { - if (region.startIndex > lastIndex) { - Region newRegion = new completedRegion(lastIndex, region.startIndex); - completedRegions.add(newRegion); - } - completedRegions.add(region); - lastIndex = region.endIndex; - } - if (lastIndex < builder.length()) { - Region newRegion = new completedRegion(lastIndex, builder.length()); - completedRegions.add(newRegion); - } - return completedRegions; - } + public static List completeRegions(StringBuilder builder, List regions) { + List completedRegions = new ArrayList<>(); + int lastIndex = 0; + for (Region region : regions) { + if (region.startIndex > lastIndex) { + Region newRegion = new completedRegion(lastIndex, region.startIndex); + completedRegions.add(newRegion); + } + completedRegions.add(region); + lastIndex = region.endIndex; + } + if (lastIndex < builder.length()) { + Region newRegion = new completedRegion(lastIndex, builder.length()); + completedRegions.add(newRegion); + } + return completedRegions; + } - public static List subRegions(StringBuilder builder, List regions, Consumer consumer) { - List words = new ArrayList<>(); - for (Region region : regions) { - String text = subRegion(builder, region); - if (StringUtils.isNotBlank(text)) { - consumer.accept(words, region, text.trim()); - } - } - return words; - } + public static List subRegions(StringBuilder builder, List regions, Consumer consumer) { + List words = new ArrayList<>(); + for (Region region : regions) { + String text = subRegion(builder, region); + if (StringUtils.isNotBlank(text)) { + consumer.accept(words, region, text.trim()); + } + } + return words; + } - public static interface Consumer { - void accept(List words, Region region, String text); - } + public interface Consumer { + void accept(List words, Region region, String text); + } - public static class completedRegion extends Region { - public completedRegion(int startIndex, int endIndex) { - super(startIndex, endIndex); - } - } + public static class completedRegion extends Region { + public completedRegion(int startIndex, int endIndex) { + super(startIndex, endIndex); + } + } } -- Gitee From 7d8fbdb6bee3bb259b69b4f458c64efe9bb27915 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 7 Jul 2021 11:12:03 +0800 Subject: [PATCH 68/83] =?UTF-8?q?=E6=94=AF=E6=8C=81builder=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E8=AF=8D=E6=B3=95=E5=92=8C=E8=AF=AD=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/common/enums/TokenTypeEnum.java | 3 +- .../spirit/common/pattern/TypePattern.java | 18 +- .../element/action/DefaultSemanticParser.java | 2 +- .../spirit/core/element/frame/Semantic.java | 8 +- .../core/lexer/AbstractCursorLexer.java | 2 +- .../spirit/core/lexer/test/LexerTest.java | 824 ++++++++++-------- 6 files changed, 468 insertions(+), 389 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/enums/TokenTypeEnum.java b/spirit-common/src/main/java/com/gitee/spirit/common/enums/TokenTypeEnum.java index a336708f..6d22e65d 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/enums/TokenTypeEnum.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/enums/TokenTypeEnum.java @@ -9,7 +9,8 @@ public enum TokenTypeEnum { TYPE, // Horse ARRAY_INIT, // Horse[1] TYPE_INIT, // Horse() - TYPE_BUILDER_INIT, // Horse{} + TYPE_BUILDER, // Horse{} + TYPE_SMART_BUILDER, // ${} NULL, // null BOOLEAN, // true CHAR, // 'c' diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/pattern/TypePattern.java b/spirit-common/src/main/java/com/gitee/spirit/common/pattern/TypePattern.java index 141fa286..51696480 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/pattern/TypePattern.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/pattern/TypePattern.java @@ -16,7 +16,8 @@ public class TypePattern { public static final Pattern TYPE_ARRAY_SIZE_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*\\[\\d+\\]$"); public static final Pattern TYPE_ARRAY_LITERAL_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*\\[\\]\\{[\\s\\S]*\\}$"); public static final Pattern TYPE_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*(<[\\s\\S]+>)?\\([\\s\\S]*\\)$"); - public static final Pattern TYPE_BUILDER_INIT_PATTERN = Pattern.compile("^[A-Z]+\\w*(<[\\s\\S]+>)?\\{[\\s\\S]*\\}$"); + public static final Pattern TYPE_BUILDER_PATTERN = Pattern.compile("^[A-Z]+\\w*(<[\\s\\S]+>)?\\{[\\s\\S]*\\}$"); + public static final Pattern TYPE_SMART_BUILDER_PATTERN = Pattern.compile("\\$\\{[\\s\\S]*\\}$"); public static boolean isTypePrefix(String word) { return PrimitiveEnum.isPrimitiveBySimple(word) || isType(word); @@ -54,8 +55,12 @@ public class TypePattern { return TYPE_INIT_PATTERN.matcher(word).matches(); } - private static boolean isTypeBuilderInit(String word) { - return TYPE_BUILDER_INIT_PATTERN.matcher(word).matches(); + public static boolean isTypeBuilder(String word) { + return TYPE_BUILDER_PATTERN.matcher(word).matches(); + } + + public static boolean isTypeSmartBuilder(String word) { + return TYPE_SMART_BUILDER_PATTERN.matcher(word).matches(); } public static boolean isAnyType(String word) { @@ -73,8 +78,11 @@ public class TypePattern { } else if (isTypeInit(word)) { return TokenTypeEnum.TYPE_INIT; - } else if (isTypeBuilderInit(word)) { - return TokenTypeEnum.TYPE_BUILDER_INIT; + } else if (isTypeBuilder(word)) { + return TokenTypeEnum.TYPE_BUILDER; + + }else if (isTypeSmartBuilder(word)) { + return TokenTypeEnum.TYPE_SMART_BUILDER; } return null; } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java index 61c362f4..940e935d 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java @@ -141,7 +141,7 @@ public class DefaultSemanticParser extends AbstractSemanticParser { } else if (token.isArrayInit()) { token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getPrefix(word) + "[]"); - } else if (token.isTypeInit() || token.isTypeBuilderInit()) { + } else if (token.isTypeInit() || token.isTypeBuilder()) { token.setAttr(Attribute.SIMPLE_NAME, CommonPattern.getPrefix(word)); } else if (token.isCast()) { diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java index 82a2f1b2..296e1213 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/frame/Semantic.java @@ -47,8 +47,12 @@ public abstract class Semantic extends Attributes { return tokenType == TokenTypeEnum.TYPE_INIT; } - public boolean isTypeBuilderInit() { - return tokenType == TokenTypeEnum.TYPE_BUILDER_INIT; + public boolean isTypeBuilder() { + return tokenType == TokenTypeEnum.TYPE_BUILDER; + } + + public boolean isTypeSmartBuilder() { + return tokenType == TokenTypeEnum.TYPE_SMART_BUILDER; } public boolean isNull() { diff --git a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java index 6f37f72f..bf56ee2c 100644 --- a/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java +++ b/spirit-core/spirit-core-lexer/src/main/java/com/gitee/spirit/core/lexer/AbstractCursorLexer.java @@ -22,7 +22,7 @@ public abstract class AbstractCursorLexer extends AbstractLexer { } public boolean isContinuous(char ch) { - return LineUtils.isLetter(ch) || ch == '@' || ch == '.' || ch == '$'; + return LineUtils.isLetter(ch) || ch == '@' || ch == '$' || ch == '.'; } public boolean isRefreshed(char ch) { diff --git a/spirit-core/spirit-core-lexer/src/test/java/com/gitee/spirit/core/lexer/test/LexerTest.java b/spirit-core/spirit-core-lexer/src/test/java/com/gitee/spirit/core/lexer/test/LexerTest.java index 0e5469a4..9d84dcad 100644 --- a/spirit-core/spirit-core-lexer/src/test/java/com/gitee/spirit/core/lexer/test/LexerTest.java +++ b/spirit-core/spirit-core-lexer/src/test/java/com/gitee/spirit/core/lexer/test/LexerTest.java @@ -19,384 +19,450 @@ import lombok.extern.slf4j.Slf4j; @DisplayName("词法测试") public class LexerTest { - @Autowired - public Lexer lexer; - - @Test - @DisplayName("STRING") - public void test0000() { - String text = "name = \"Jessie\""; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "name"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "\"Jessie\""); - } - - @Test - @DisplayName("CHAR") - public void test0001() { - String text = "ch = 'c'"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "ch"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "'c'"); - } - - @Test - @DisplayName("MAP") - public void test0002() { - String text = "horse = {\"name\" : \"Jessie\"}"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "horse"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "{\"name\" : \"Jessie\"}"); - } - - @Test - @DisplayName("MAP_SUBWORDS") - public void test0003() { - String text = "{\"name\" : \"Jessie\"}"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 5); - int count = 0; - assertEquals(words.get(count++), "{"); - assertEquals(words.get(count++), "\"name\""); - assertEquals(words.get(count++), ":"); - assertEquals(words.get(count++), "\"Jessie\""); - assertEquals(words.get(count++), "}"); - } - - @Test - @DisplayName("MAP_COMPLEX_NESTING") - public void test0004() { - String text = "{\"horse\" : {\"name\" : \"Jessie\"}}"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 5); - int count = 0; - assertEquals(words.get(count++), "{"); - assertEquals(words.get(count++), "\"horse\""); - assertEquals(words.get(count++), ":"); - assertEquals(words.get(count++), "{\"name\" : \"Jessie\"}"); - assertEquals(words.get(count++), "}"); - } - - @Test - @DisplayName("METHOD") - public void test0005() { - String text = "func call() {"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "func"); - assertEquals(words.get(count++), "call()"); - assertEquals(words.get(count++), "{"); - } - - @Test - @DisplayName("METHOD_SUBWORDS") - public void test0006() { - String text = "call(name, age)"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 6); - int count = 0; - assertEquals(words.get(count++), "call"); - assertEquals(words.get(count++), "("); - assertEquals(words.get(count++), "name"); - assertEquals(words.get(count++), ","); - assertEquals(words.get(count++), "age"); - assertEquals(words.get(count++), ")"); - } - - @Test - @DisplayName("LIST") - public void test0007() { - String text = "horses = [horse0, horse1, horse2]"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "horses"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "[horse0, horse1, horse2]"); - } - - @Test - @DisplayName("LIST_SUBWORDS") - public void test0008() { - String text = "[horse0, horse1, horse2]"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 7); - int count = 0; - assertEquals(words.get(count++), "["); - assertEquals(words.get(count++), "horse0"); - assertEquals(words.get(count++), ","); - assertEquals(words.get(count++), "horse1"); - assertEquals(words.get(count++), ","); - assertEquals(words.get(count++), "horse2"); - assertEquals(words.get(count++), "]"); - } - - @Test - @DisplayName("LIST_COMPLEX_NESTING") - public void test0009() { - String text = "[[horse0], horse1, horse2]"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 7); - int count = 0; - assertEquals(words.get(count++), "["); - assertEquals(words.get(count++), "[horse0]"); - assertEquals(words.get(count++), ","); - assertEquals(words.get(count++), "horse1"); - assertEquals(words.get(count++), ","); - assertEquals(words.get(count++), "horse2"); - assertEquals(words.get(count++), "]"); - } - - @Test - @DisplayName("ARRAY_SIZE_INIT") - public void test0010() { - String text = "horses = Horse[1]"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "horses"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "Horse[1]"); - } - - @Test - @DisplayName("ARRAY_SIZE_INIT_SUBWORDS") - public void test0011() { - String text = "Horse[1]"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 4); - int count = 0; - assertEquals(words.get(count++), "Horse"); - assertEquals(words.get(count++), "["); - assertEquals(words.get(count++), "1"); - assertEquals(words.get(count++), "]"); - } - - @Test - @DisplayName("ARRAY_LITERAL_INIT") - public void test0012() { - String text = "horses = Horse[]{horse}"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "horses"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "Horse[]{horse}"); - } - - @Test - @DisplayName("ARRAY_LITERAL_INIT_SUBWORDS") - public void test0013() { - String text = "Horse[]{horse}"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 6); - int count = 0; - assertEquals(words.get(count++), "Horse"); - assertEquals(words.get(count++), "["); - assertEquals(words.get(count++), "]"); - assertEquals(words.get(count++), "{"); - assertEquals(words.get(count++), "horse"); - assertEquals(words.get(count++), "}"); - } - - @Test - @DisplayName("ARRAY_VISIT_INDEX") - public void test0014() { - String text = "horse = horses[0]"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 4); - int count = 0; - assertEquals(words.get(count++), "horse"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "horses"); - assertEquals(words.get(count++), "[0]"); - } - - @Test - @DisplayName("ARRAY_VISIT_INDEX_SUBWORDS") - public void test0015() { - String text = "horses[0]"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 4); - int count = 0; - assertEquals(words.get(count++), "horses"); - assertEquals(words.get(count++), "["); - assertEquals(words.get(count++), "0"); - assertEquals(words.get(count++), "]"); - } - - @Test - @DisplayName("GENERIC_TYPE") - public void test0016() { - String text = "class Horse {"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "class"); - assertEquals(words.get(count++), "Horse"); - assertEquals(words.get(count++), "{"); - } - - @Test - @DisplayName("GENERIC_TYPE_SUBWORDS") - public void test0017() { - String text = "Horse"; - List words = lexer.getSubWords(text, '<', '>'); - log.info(words.toString()); - assertTrue(words.size() == 6); - int count = 0; - assertEquals(words.get(count++), "Horse"); - assertEquals(words.get(count++), "<"); - assertEquals(words.get(count++), "T"); - assertEquals(words.get(count++), ","); - assertEquals(words.get(count++), "K"); - assertEquals(words.get(count++), ">"); - } - - @Test - @DisplayName("GENERIC_TYPE_COMPLEX_NESTING") - public void test0018() { - String text = "Horse, Object>"; - List words = lexer.getSubWords(text, '<', '>'); - log.info(words.toString()); - assertTrue(words.size() == 6); - int count = 0; - assertEquals(words.get(count++), "Horse"); - assertEquals(words.get(count++), "<"); - assertEquals(words.get(count++), "Horse"); - assertEquals(words.get(count++), ","); - assertEquals(words.get(count++), "Object"); - assertEquals(words.get(count++), ">"); - } - - @Test - @DisplayName("GENERIC_TYPE_INIT") - public void test0019() { - String text = "horse = Horse()"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "horse"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "Horse()"); - } - - @Test - @DisplayName("GENERIC_TYPE_INIT_SUBWORDS") - public void test0020() { - String text = "Horse()"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "Horse"); - assertEquals(words.get(count++), "("); - assertEquals(words.get(count++), ")"); - } - - @Test - @DisplayName("GENERIC_TYPE_INIT_COMPLEX_NESTING") - public void test0021() { - String text = "Horse, Object>()"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "Horse, Object>"); - assertEquals(words.get(count++), "("); - assertEquals(words.get(count++), ")"); - } - - @Test - @DisplayName("MY_TEST") - public void test0022() { - String text = "xxxxG_Alias=\"Clock moved backwards.G_Alias to generate id for %d milliseconds\""; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 3); - int count = 0; - assertEquals(words.get(count++), "xxxxG_Alias"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "\"Clock moved backwards.G_Alias to generate id for %d milliseconds\""); - } - - @Test - @DisplayName("MY_TEST1") - public void test0023() { - String text = "if s==\"hello\"{"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 5); - int count = 0; - assertEquals(words.get(count++), "if"); - assertEquals(words.get(count++), "s"); - assertEquals(words.get(count++), "=="); - assertEquals(words.get(count++), "\"hello\""); - assertEquals(words.get(count++), "{"); - } - - @Test - @DisplayName("MY_TEST2") - public void test0024() { - String text = "b=father.child.father.child.father.name"; - List words = lexer.getWords(text); - log.info(words.toString()); - assertTrue(words.size() == 8); - int count = 0; - assertEquals(words.get(count++), "b"); - assertEquals(words.get(count++), "="); - assertEquals(words.get(count++), "father"); - assertEquals(words.get(count++), ".child"); - assertEquals(words.get(count++), ".father"); - assertEquals(words.get(count++), ".child"); - assertEquals(words.get(count++), ".father"); - assertEquals(words.get(count++), ".name"); - } - - @Test - @DisplayName("MY_TEST3") - public void test0025() { - String text = ".format(\"Clock moved backwards.Refusing to generate id for %d milliseconds\", lastTimestamp - timestamp)"; - List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); - log.info(words.toString()); - assertTrue(words.size() == 8); - int count = 0; - assertEquals(words.get(count++), ".format"); - assertEquals(words.get(count++), "("); - assertEquals(words.get(count++), "\"Clock moved backwards.Refusing to generate id for %d milliseconds\""); - assertEquals(words.get(count++), ","); - assertEquals(words.get(count++), "lastTimestamp"); - assertEquals(words.get(count++), "-"); - assertEquals(words.get(count++), "timestamp"); - assertEquals(words.get(count++), ")"); - } + @Autowired + public Lexer lexer; + + @Test + @DisplayName("STRING") + public void test0000() { + String text = "name = \"Jessie\""; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "name"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "\"Jessie\""); + } + + @Test + @DisplayName("CHAR") + public void test0001() { + String text = "ch = 'c'"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "ch"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "'c'"); + } + + @Test + @DisplayName("MAP") + public void test0002() { + String text = "horse = {\"name\" : \"Jessie\"}"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "horse"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "{\"name\" : \"Jessie\"}"); + } + + @Test + @DisplayName("MAP_SUBWORDS") + public void test0003() { + String text = "{\"name\" : \"Jessie\"}"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 5); + int count = 0; + assertEquals(words.get(count++), "{"); + assertEquals(words.get(count++), "\"name\""); + assertEquals(words.get(count++), ":"); + assertEquals(words.get(count++), "\"Jessie\""); + assertEquals(words.get(count++), "}"); + } + + @Test + @DisplayName("MAP_COMPLEX_NESTING") + public void test0004() { + String text = "{\"horse\" : {\"name\" : \"Jessie\"}}"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 5); + int count = 0; + assertEquals(words.get(count++), "{"); + assertEquals(words.get(count++), "\"horse\""); + assertEquals(words.get(count++), ":"); + assertEquals(words.get(count++), "{\"name\" : \"Jessie\"}"); + assertEquals(words.get(count++), "}"); + } + + @Test + @DisplayName("METHOD") + public void test0005() { + String text = "func call() {"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "func"); + assertEquals(words.get(count++), "call()"); + assertEquals(words.get(count++), "{"); + } + + @Test + @DisplayName("METHOD_SUBWORDS") + public void test0006() { + String text = "call(name, age)"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 6); + int count = 0; + assertEquals(words.get(count++), "call"); + assertEquals(words.get(count++), "("); + assertEquals(words.get(count++), "name"); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "age"); + assertEquals(words.get(count++), ")"); + } + + @Test + @DisplayName("LIST") + public void test0007() { + String text = "horses = [horse0, horse1, horse2]"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "horses"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "[horse0, horse1, horse2]"); + } + + @Test + @DisplayName("LIST_SUBWORDS") + public void test0008() { + String text = "[horse0, horse1, horse2]"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 7); + int count = 0; + assertEquals(words.get(count++), "["); + assertEquals(words.get(count++), "horse0"); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "horse1"); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "horse2"); + assertEquals(words.get(count++), "]"); + } + + @Test + @DisplayName("LIST_COMPLEX_NESTING") + public void test0009() { + String text = "[[horse0], horse1, horse2]"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 7); + int count = 0; + assertEquals(words.get(count++), "["); + assertEquals(words.get(count++), "[horse0]"); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "horse1"); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "horse2"); + assertEquals(words.get(count++), "]"); + } + + @Test + @DisplayName("ARRAY_SIZE_INIT") + public void test0010() { + String text = "horses = Horse[1]"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "horses"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "Horse[1]"); + } + + @Test + @DisplayName("ARRAY_SIZE_INIT_SUBWORDS") + public void test0011() { + String text = "Horse[1]"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 4); + int count = 0; + assertEquals(words.get(count++), "Horse"); + assertEquals(words.get(count++), "["); + assertEquals(words.get(count++), "1"); + assertEquals(words.get(count++), "]"); + } + + @Test + @DisplayName("ARRAY_LITERAL_INIT") + public void test0012() { + String text = "horses = Horse[]{horse}"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "horses"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "Horse[]{horse}"); + } + + @Test + @DisplayName("ARRAY_LITERAL_INIT_SUBWORDS") + public void test0013() { + String text = "Horse[]{horse}"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 6); + int count = 0; + assertEquals(words.get(count++), "Horse"); + assertEquals(words.get(count++), "["); + assertEquals(words.get(count++), "]"); + assertEquals(words.get(count++), "{"); + assertEquals(words.get(count++), "horse"); + assertEquals(words.get(count++), "}"); + } + + @Test + @DisplayName("ARRAY_VISIT_INDEX") + public void test0014() { + String text = "horse = horses[0]"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 4); + int count = 0; + assertEquals(words.get(count++), "horse"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "horses"); + assertEquals(words.get(count++), "[0]"); + } + + @Test + @DisplayName("ARRAY_VISIT_INDEX_SUBWORDS") + public void test0015() { + String text = "horses[0]"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 4); + int count = 0; + assertEquals(words.get(count++), "horses"); + assertEquals(words.get(count++), "["); + assertEquals(words.get(count++), "0"); + assertEquals(words.get(count++), "]"); + } + + @Test + @DisplayName("GENERIC_TYPE") + public void test0016() { + String text = "class Horse {"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "class"); + assertEquals(words.get(count++), "Horse"); + assertEquals(words.get(count++), "{"); + } + + @Test + @DisplayName("GENERIC_TYPE_SUBWORDS") + public void test0017() { + String text = "Horse"; + List words = lexer.getSubWords(text, '<', '>'); + log.info(words.toString()); + assertTrue(words.size() == 6); + int count = 0; + assertEquals(words.get(count++), "Horse"); + assertEquals(words.get(count++), "<"); + assertEquals(words.get(count++), "T"); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "K"); + assertEquals(words.get(count++), ">"); + } + + @Test + @DisplayName("GENERIC_TYPE_COMPLEX_NESTING") + public void test0018() { + String text = "Horse, Object>"; + List words = lexer.getSubWords(text, '<', '>'); + log.info(words.toString()); + assertTrue(words.size() == 6); + int count = 0; + assertEquals(words.get(count++), "Horse"); + assertEquals(words.get(count++), "<"); + assertEquals(words.get(count++), "Horse"); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "Object"); + assertEquals(words.get(count++), ">"); + } + + @Test + @DisplayName("GENERIC_TYPE_INIT") + public void test0019() { + String text = "horse = Horse()"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "horse"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "Horse()"); + } + + @Test + @DisplayName("GENERIC_TYPE_INIT_SUBWORDS") + public void test0020() { + String text = "Horse()"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "Horse"); + assertEquals(words.get(count++), "("); + assertEquals(words.get(count++), ")"); + } + + @Test + @DisplayName("GENERIC_TYPE_INIT_COMPLEX_NESTING") + public void test0021() { + String text = "Horse, Object>()"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "Horse, Object>"); + assertEquals(words.get(count++), "("); + assertEquals(words.get(count++), ")"); + } + + @Test + @DisplayName("MY_TEST") + public void test0022() { + String text = "xxxxG_Alias=\"Clock moved backwards.G_Alias to generate id for %d milliseconds\""; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "xxxxG_Alias"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "\"Clock moved backwards.G_Alias to generate id for %d milliseconds\""); + } + + @Test + @DisplayName("MY_TEST1") + public void test0023() { + String text = "if s==\"hello\"{"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 5); + int count = 0; + assertEquals(words.get(count++), "if"); + assertEquals(words.get(count++), "s"); + assertEquals(words.get(count++), "=="); + assertEquals(words.get(count++), "\"hello\""); + assertEquals(words.get(count++), "{"); + } + + @Test + @DisplayName("MY_TEST2") + public void test0024() { + String text = "b=father.child.father.child.father.name"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 8); + int count = 0; + assertEquals(words.get(count++), "b"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "father"); + assertEquals(words.get(count++), ".child"); + assertEquals(words.get(count++), ".father"); + assertEquals(words.get(count++), ".child"); + assertEquals(words.get(count++), ".father"); + assertEquals(words.get(count++), ".name"); + } + + @Test + @DisplayName("MY_TEST3") + public void test0025() { + String text = ".format(\"Clock moved backwards.Refusing to generate id for %d milliseconds\", lastTimestamp - timestamp)"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 8); + int count = 0; + assertEquals(words.get(count++), ".format"); + assertEquals(words.get(count++), "("); + assertEquals(words.get(count++), "\"Clock moved backwards.Refusing to generate id for %d milliseconds\""); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "lastTimestamp"); + assertEquals(words.get(count++), "-"); + assertEquals(words.get(count++), "timestamp"); + assertEquals(words.get(count++), ")"); + } + + @Test + @DisplayName("builder模式") + public void test0026() { + String text = "user = User{name = \"chen\", age = \"30\"}"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "user"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "User{name = \"chen\", age = \"30\"}"); + } + + @Test + @DisplayName("builder模式") + public void test0027() { + String text = "User{name = \"chen\", age = \"30\"}"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 10); + int count = 0; + assertEquals(words.get(count++), "User"); + assertEquals(words.get(count++), "{"); + assertEquals(words.get(count++), "name"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "\"chen\""); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "age"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "\"30\""); + assertEquals(words.get(count++), "}"); + } + + @Test + @DisplayName("builder模式") + public void test0028() { + String text = "user = ${name = \"chen\", age = \"30\"}"; + List words = lexer.getWords(text); + log.info(words.toString()); + assertTrue(words.size() == 3); + int count = 0; + assertEquals(words.get(count++), "user"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "${name = \"chen\", age = \"30\"}"); + } + + @Test + @DisplayName("builder模式") + public void test0029() { + String text = "${name = \"chen\", age = \"30\"}"; + List words = lexer.getSubWords(text, '(', ')', '[', ']', '{', '}'); + log.info(words.toString()); + assertTrue(words.size() == 10); + int count = 0; + assertEquals(words.get(count++), "$"); + assertEquals(words.get(count++), "{"); + assertEquals(words.get(count++), "name"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "\"chen\""); + assertEquals(words.get(count++), ","); + assertEquals(words.get(count++), "age"); + assertEquals(words.get(count++), "="); + assertEquals(words.get(count++), "\"30\""); + assertEquals(words.get(count++), "}"); + } } -- Gitee From a3873fb77a82cdaa1069f824a9462b4c8379e7b5 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 7 Jul 2021 15:31:14 +0800 Subject: [PATCH 69/83] =?UTF-8?q?=E6=94=AF=E6=8C=81builder=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spirit/core/compile/AppTypeFactory.java | 3 +- .../compile/action/InvokeVisitAction.java | 118 +++++++++--------- .../element/action/DefaultSemanticParser.java | 8 +- .../core/element/entity/SemanticContext.java | 16 +-- .../spirit/core/lexer/test/SemanticTest.java | 16 +++ spirit-example/spirit-example-common/pom.xml | 6 + .../java/com/gitee/spirit/example/User.java | 15 +++ .../com/gitee/spirit/example/type/Type.java | 3 + .../com.gitee.spirit.example/type/Type.sp | 4 + .../output/java/action/BuilderAction.java | 50 ++++++++ .../output/java/action/CommonAction.java | 57 ++++----- spirit/lib/spirit-code-tools-2.1.30.jar | Bin 16744 -> 14892 bytes spirit/lib/spirit-common-2.1.30.jar | Bin 42000 -> 48304 bytes spirit/lib/spirit-core-class-2.1.30.jar | Bin 41680 -> 40725 bytes spirit/lib/spirit-core-compile-2.1.30.jar | Bin 46046 -> 47270 bytes spirit/lib/spirit-core-element-2.1.30.jar | Bin 51217 -> 49539 bytes spirit/lib/spirit-core-lexer-2.1.30.jar | Bin 27550 -> 25747 bytes spirit/lib/spirit-output-java-2.1.30.jar | Bin 34820 -> 38940 bytes spirit/lib/spirit-starter-java-2.1.30.jar | Bin 6559 -> 6481 bytes spirit/lib/spirit-stdlib-2.1.30.jar | Bin 5837 -> 5761 bytes 20 files changed, 192 insertions(+), 104 deletions(-) create mode 100644 spirit-example/spirit-example-common/src/main/java/com/gitee/spirit/example/User.java create mode 100644 spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/BuilderAction.java diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java index 0af214d1..befcd0ac 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/AppTypeFactory.java @@ -53,7 +53,8 @@ public class AppTypeFactory extends AbstractTypeFactory { if (token.isType()) { return doCreate(clazz, token); - } else if (token.isAnnotation() || token.isArrayInit() || token.isTypeInit() || token.isCast()) { + } else if (token.isAnnotation() || token.isArrayInit() || + token.isTypeInit() || token.isTypeBuilder() || token.isCast()) { return create(clazz, (String) token.attr(Attribute.SIMPLE_NAME)); } else if (token.isLiteral()) {// 1, 1.1, "xxxx" diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java index 67229a52..9af7e500 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java @@ -23,72 +23,72 @@ import com.gitee.spirit.core.element.utils.StmtVisitor; @Order(-40) public class InvokeVisitAction extends AbstractAppElementAction { - @Autowired - public TypeFactory factory; - @Autowired - public StatementDeducer deducer; - @Autowired - public ClassLinker linker; + @Autowired + public TypeFactory factory; + @Autowired + public StatementDeducer deducer; + @Autowired + public ClassLinker linker; - @Override - public void visitElement(VisitContext context, Element element) { - IClass clazz = context.clazz; - StmtVisitor.forEachStmt(element, statement -> { - for (int index = 0; index < statement.size(); index++) { - try { - Token token = statement.get(index); - if (token.attr(Attribute.TYPE) != null) { - continue; - } - List parameterTypes = token.isInvoke() ? getParameterTypes(token) : null; - if (token.isType() || token.isArrayInit() || token.isTypeInit() || token.isCast() || token.isLiteral()) { - token.setAttr(Attribute.TYPE, factory.create(clazz, token)); + @Override + public void visitElement(VisitContext context, Element element) { + IClass clazz = context.clazz; + StmtVisitor.forEachStmt(element, statement -> { + for (int index = 0; index < statement.size(); index++) { + try { + Token token = statement.get(index); + if (token.attr(Attribute.TYPE) != null) { + continue; + } + List parameterTypes = token.isInvoke() ? getParameterTypes(token) : null; + if (token.isType() || token.isArrayInit() || token.isTypeInit() || token.isTypeBuilder() || token.isCast() || token.isLiteral()) { + token.setAttr(Attribute.TYPE, factory.create(clazz, token)); - } else if (token.isSubexpress()) { - Statement subStatement = token.getValue(); - token.setAttr(Attribute.TYPE, deducer.derive(subStatement.subStmt("(", ")"))); + } else if (token.isSubexpress()) { + Statement subStatement = token.getValue(); + token.setAttr(Attribute.TYPE, deducer.derive(subStatement.subStmt("(", ")"))); - } else if (token.isVisitField()) { - IType type = statement.get(index - 1).attr(Attribute.TYPE); - String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitField(type, memberName); - token.setAttr(Attribute.TYPE, returnType); + } else if (token.isVisitField()) { + IType type = statement.get(index - 1).attr(Attribute.TYPE); + String memberName = token.attr(Attribute.MEMBER_NAME); + IType returnType = linker.visitField(type, memberName); + token.setAttr(Attribute.TYPE, returnType); - } else if (token.isLocalMethod()) { - String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitMethod(clazz.getType().withPrivate(), memberName, parameterTypes); - token.setAttr(Attribute.TYPE, returnType); + } else if (token.isLocalMethod()) { + String memberName = token.attr(Attribute.MEMBER_NAME); + IType returnType = linker.visitMethod(clazz.getType().withPrivate(), memberName, parameterTypes); + token.setAttr(Attribute.TYPE, returnType); - } else if (token.isVisitMethod()) { - IType type = statement.get(index - 1).attr(Attribute.TYPE); - String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitMethod(type, memberName, parameterTypes); - token.setAttr(Attribute.TYPE, returnType); + } else if (token.isVisitMethod()) { + IType type = statement.get(index - 1).attr(Attribute.TYPE); + String memberName = token.attr(Attribute.MEMBER_NAME); + IType returnType = linker.visitMethod(type, memberName, parameterTypes); + token.setAttr(Attribute.TYPE, returnType); - } else if (token.isVisitIndex()) {// what like "[0]" - IType type = statement.get(index - 1).attr(Attribute.TYPE); - type = type.toTarget();// 转换数组类型为目标类型 - token.setAttr(Attribute.TYPE, type); - } + } else if (token.isVisitIndex()) {// what like "[0]" + IType type = statement.get(index - 1).attr(Attribute.TYPE); + type = type.toTarget();// 转换数组类型为目标类型 + token.setAttr(Attribute.TYPE, type); + } - } catch (NoSuchFieldException | NoSuchMethodException e) { - throw new RuntimeException("Link failed for class member!", e); - } - } - }); - } + } catch (NoSuchFieldException | NoSuchMethodException e) { + throw new RuntimeException("Link failed for class member!", e); + } + } + }); + } - public List getParameterTypes(Token token) { - List parameterTypes = new ArrayList<>(); - Statement statement = token.getValue(); - if (statement.size() > 3) { - List subStatements = statement.subStmt(2, statement.size() - 1).splitStmt(","); - for (Statement subStatement : subStatements) { - IType parameterType = deducer.derive(subStatement); - parameterTypes.add(parameterType); - } - } - return parameterTypes; - } + public List getParameterTypes(Token token) { + List parameterTypes = new ArrayList<>(); + Statement statement = token.getValue(); + if (statement.size() > 3) { + List subStatements = statement.subStmt(2, statement.size() - 1).splitStmt(","); + for (Statement subStatement : subStatements) { + IType parameterType = deducer.derive(subStatement); + parameterTypes.add(parameterType); + } + } + return parameterTypes; + } } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java index 940e935d..14759521 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/action/DefaultSemanticParser.java @@ -51,9 +51,7 @@ public class DefaultSemanticParser extends AbstractSemanticParser { } public TokenTypeEnum getTokenType(SemanticContext context, String word) { - if (!context.subStatement) { - return getCommonTokenType(context, word); - } else { + if (context.subStatement) { if (context.insideType) { if ("<".equals(word) || ">".equals(word)) { return TokenTypeEnum.SEPARATOR; @@ -65,8 +63,8 @@ public class DefaultSemanticParser extends AbstractSemanticParser { if (context.index == 0 && CommonPattern.isPrefix(word)) { return TokenTypeEnum.PREFIX; } - return getCommonTokenType(context, word); } + return getCommonTokenType(context, word); } public TokenTypeEnum getCommonTokenType(SemanticContext context, String word) { @@ -120,7 +118,7 @@ public class DefaultSemanticParser extends AbstractSemanticParser { if (token.isType()) { return word.contains("<") || word.contains(">") ? getStatement(true, word) : word; - } else if (token.isArrayInit() || token.isList() || token.isMap() || token.isSubexpress() || token.isInvoke()) { + } else if (token.isArrayInit() || token.isTypeBuilder() || token.isList() || token.isMap() || token.isSubexpress() || token.isInvoke()) { // 拆分数组是为了更好的添加new这个关键字 return getStatement(false, word); } diff --git a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/SemanticContext.java b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/SemanticContext.java index 11fd30d4..eda424cf 100644 --- a/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/SemanticContext.java +++ b/spirit-core/spirit-core-element/src/main/java/com/gitee/spirit/core/element/entity/SemanticContext.java @@ -11,14 +11,14 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class SemanticContext { - public List words; - public int index = -1; - public boolean subStatement = false; - public boolean insideType = false; + public List words; + public int index = -1; + public boolean subStatement = false; + public boolean insideType = false; - public SemanticContext(boolean subStatement, boolean insideType) { - this.subStatement = subStatement; - this.insideType = insideType; - } + public SemanticContext(boolean subStatement, boolean insideType) { + this.subStatement = subStatement; + this.insideType = insideType; + } } diff --git a/spirit-core/spirit-core-element/src/test/java/com/gitee/spirit/core/lexer/test/SemanticTest.java b/spirit-core/spirit-core-element/src/test/java/com/gitee/spirit/core/lexer/test/SemanticTest.java index 42a94fc0..9d7fa49f 100644 --- a/spirit-core/spirit-core-element/src/test/java/com/gitee/spirit/core/lexer/test/SemanticTest.java +++ b/spirit-core/spirit-core-element/src/test/java/com/gitee/spirit/core/lexer/test/SemanticTest.java @@ -220,4 +220,20 @@ public class SemanticTest { assertTrue(statement.get(0).isPrefix()); } + @Test + @DisplayName("builder模式") + public void test0025() { + String text = "User{name = \"chen\", age = \"30\"}"; + Token token = parser.getToken(new SemanticContext(), text); + assertTrue(token.isTypeBuilder()); + } + + @Test + @DisplayName("builder模式") + public void test0026() { + String text = "${name = \"chen\", age = \"30\"}"; + Token token = parser.getToken(new SemanticContext(), text); + assertTrue(token.isTypeSmartBuilder()); + } + } diff --git a/spirit-example/spirit-example-common/pom.xml b/spirit-example/spirit-example-common/pom.xml index 75950c72..ee1143e6 100644 --- a/spirit-example/spirit-example-common/pom.xml +++ b/spirit-example/spirit-example-common/pom.xml @@ -27,5 +27,11 @@ commons-lang3 ${lang3.version} + + + org.projectlombok + lombok + ${lombok.version} + \ No newline at end of file diff --git a/spirit-example/spirit-example-common/src/main/java/com/gitee/spirit/example/User.java b/spirit-example/spirit-example-common/src/main/java/com/gitee/spirit/example/User.java new file mode 100644 index 00000000..e5dfd9f2 --- /dev/null +++ b/spirit-example/spirit-example-common/src/main/java/com/gitee/spirit/example/User.java @@ -0,0 +1,15 @@ +package com.gitee.spirit.example; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class User { + private String name; + private Integer age; +} diff --git a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/type/Type.java b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/type/Type.java index 83d441fd..bfc1b77d 100644 --- a/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/type/Type.java +++ b/spirit-example/spirit-example-plugin/src/main/java/com/gitee/spirit/example/type/Type.java @@ -3,6 +3,7 @@ package com.gitee.spirit.example.type; import com.gitee.spirit.example.ClassGenericTest; import com.gitee.spirit.example.GenericType; import com.gitee.spirit.example.MyTest; +import com.gitee.spirit.example.User; import com.gitee.spirit.example.clazz.ServiceImpl; import com.gitee.spirit.example.process.Main; import com.gitee.spirit.stdlib.Lists; @@ -107,6 +108,8 @@ public class Type { Map objvar = Maps.of("name", "chen", "age", 18, "from", "China", "brother", Lists.of("wanhao", "chenzhe")); String str0 = objvar.toString(); logger.info(str0); + User user = User.builder().name("chen").age(18).build(); + logger.info(user.getName()); } public String testParam(@Deprecated String str, Object obj) { diff --git a/spirit-example/spirit-example-plugin/src/main/resources/sources/com.gitee.spirit.example/type/Type.sp b/spirit-example/spirit-example-plugin/src/main/resources/sources/com.gitee.spirit.example/type/Type.sp index c6e11fed..49d7c0a8 100644 --- a/spirit-example/spirit-example-plugin/src/main/resources/sources/com.gitee.spirit.example/type/Type.sp +++ b/spirit-example/spirit-example-plugin/src/main/resources/sources/com.gitee.spirit.example/type/Type.sp @@ -3,6 +3,7 @@ import java.util.HashMap import com.gitee.spirit.example.ClassGenericTest import com.gitee.spirit.example.MyTest import com.gitee.spirit.example.GenericType +import com.gitee.spirit.example.User const NUMBER = 100.0 const NAME = "chentao" @@ -138,6 +139,9 @@ class Type { } str0 = objvar.toString() print str0 + + user = User{name="chen",age=18} + print user.getName() } func testParam(@Deprecated String str, Object obj){ diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/BuilderAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/BuilderAction.java new file mode 100644 index 00000000..8cf776de --- /dev/null +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/BuilderAction.java @@ -0,0 +1,50 @@ +package com.gitee.spirit.output.java.action; + +import cn.hutool.core.lang.Assert; +import com.gitee.spirit.common.constants.Attribute; +import com.gitee.spirit.common.enums.TokenTypeEnum; +import com.gitee.spirit.core.compile.entity.VisitContext; +import com.gitee.spirit.core.element.entity.Element; +import com.gitee.spirit.core.element.entity.Statement; +import com.gitee.spirit.core.element.entity.Token; +import com.gitee.spirit.core.element.utils.StmtVisitor; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Order(-120) +public class BuilderAction extends AbstractExtElementAction { + + @Override + public void visitElement(VisitContext context, Element element) { + StmtVisitor.forEachToken(element, token -> { + if (token.isTypeBuilder()) {//User{name="chen",age=18} => User.builder().name("chen").age(18).build() + //append type name + StringBuilder builder = new StringBuilder(); + builder.append((String) token.attr(Attribute.SIMPLE_NAME)); + //append .builder() + builder.append(".builder()"); + //append .property() + Statement statement = token.getValue(); + Statement subStatement = statement.subStmt("{", "}"); + List subStatements = subStatement.splitStmt(","); + for (Statement eachStmt : subStatements) { + if (eachStmt.contains("=")) { + List eachStmts = eachStmt.splitStmt("="); + Assert.isTrue(eachStmts.size() == 2, "The size must be 2!"); + String property = eachStmts.get(0).toString(); + String value = eachStmts.get(1).toString(); + builder.append(".").append(property).append("(").append(value).append(")"); + } + } + //append .build() + builder.append(".build()"); + statement.clear(); + statement.add(new Token(TokenTypeEnum.CUSTOM_EXPRESS, builder.toString())); + } + }); + } + +} diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java index f59789cf..dcfc4a1d 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/action/CommonAction.java @@ -17,36 +17,31 @@ import com.gitee.spirit.stdlib.Maps; @Order(-80) public class CommonAction extends AbstractExtElementAction { - @Override - public void visitElement(VisitContext context, Element element) { - IClass clazz = context.clazz; - StmtVisitor.forEachToken(element, token -> { - if (token.isArrayInit()) {// String[10] => new String[10] - Statement subStatement = token.getValue(); - subStatement.add(0, new Token(TokenTypeEnum.KEYWORD, "new")); - - } else if (token.isTypeInit()) {// User() => new User() - Statement subStatement = token.getValue(); - subStatement.add(0, new Token(TokenTypeEnum.KEYWORD, "new")); - - } else if (token.isList()) {// ["value"] => Lists.of("value"); - Statement subStatement = token.getValue(); - subStatement.set(0, new Token(TokenTypeEnum.CUSTOM_PREFIX, "Lists.of(")); - subStatement.set(subStatement.size() - 1, new Token(TokenTypeEnum.CUSTOM_SUFFIX, ")")); - clazz.addImport(Lists.class.getName()); - - } else if (token.isMap()) {// {"key":"value"} => Maps.of("key","value"); - Statement subStatement = token.getValue(); - for (Token subToken : subStatement) { - if (subToken.isSeparator() && ":".equals(subToken.toString())) { - subToken.value = ","; - } - } - subStatement.set(0, new Token(TokenTypeEnum.CUSTOM_PREFIX, "Maps.of(")); - subStatement.set(subStatement.size() - 1, new Token(TokenTypeEnum.CUSTOM_SUFFIX, ")")); - clazz.addImport(Maps.class.getName()); - } - }); - } + @Override + public void visitElement(VisitContext context, Element element) { + StmtVisitor.forEachToken(element, token -> { + if (token.isArrayInit() || token.isTypeInit()) {// String[10] => new String[10] // User() => new User() + Statement subStatement = token.getValue(); + subStatement.add(0, new Token(TokenTypeEnum.KEYWORD, "new")); + + } else if (token.isList()) {// ["value"] => Lists.of("value"); + Statement subStatement = token.getValue(); + subStatement.set(0, new Token(TokenTypeEnum.CUSTOM_PREFIX, "Lists.of(")); + subStatement.set(subStatement.size() - 1, new Token(TokenTypeEnum.CUSTOM_SUFFIX, ")")); + context.clazz.addImport(Lists.class.getName()); + + } else if (token.isMap()) {// {"key":"value"} => Maps.of("key","value"); + Statement subStatement = token.getValue(); + for (Token subToken : subStatement) { + if (subToken.isSeparator() && ":".equals(subToken.toString())) { + subToken.value = ","; + } + } + subStatement.set(0, new Token(TokenTypeEnum.CUSTOM_PREFIX, "Maps.of(")); + subStatement.set(subStatement.size() - 1, new Token(TokenTypeEnum.CUSTOM_SUFFIX, ")")); + context.clazz.addImport(Maps.class.getName()); + } + }); + } } diff --git a/spirit/lib/spirit-code-tools-2.1.30.jar b/spirit/lib/spirit-code-tools-2.1.30.jar index 370886d2196f366afa4e95a528d3339b4262f634..185b2a25b517bed1ee2fc9046f1b470d9cd718fe 100644 GIT binary patch delta 5397 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 diff --git a/spirit/lib/spirit-common-2.1.30.jar b/spirit/lib/spirit-common-2.1.30.jar index ccc62a18030c1582b8d0d9f3df19a3e0d1f9b34f..2109e2776d25a41823c01fc72977f1dcbef72490 100644 GIT binary patch delta 36324 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

jN6bZfJx;-(Y=w$W}1Ls><= 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 MB*eh5VkL+N010!4*Z=?k delta 30099 zcmZsi1yEegwzhG1cM0wqT!Op1ySqDsyGw9)mq7-12<`!b1h)VIfA@ z?dqAT*}JP(uU_kUd-ZO7gh=`VfvYSB355U#2L}hn(LADheoND;4F(2goQx}=EA%X3WIjQ;!EADpcCXSpy)xAfxSp-J=7=M^hm*Cp<$`u?; zSq>KN-_Ln}*1viHg9H21Lvl4GWP9OA@;vF^<`>nUCY2DJ@oy^&&Vl~^TlM{}e}5=a zi$n?WOdK7Z+)dnVoE%yH^SnQ|27wFyz4bRZ@88xNg8zSh)1`igK!XIm|K}Ql{%=bP zDfG8BhLlJDGup?|)2FxhjvB$iz!?8@1NcWbBF@gtX7(m-ZsAD^azmfcBEDDERo&M3 z{vy*ryY_tFpE+`ZMrbC7MNvRYCv{AuvJ*_;qthRz5Uwq%d zoP&qpp3x)FQQ$(QjI{8L2q(i{L5#CUzE$v2GUp+54{MB5Q`f7!08)3>Ehe~%cI1*; z&yIz@kj`rzgGR&`PZ=IZD^-I7BJrP0t#uarI{e&C8`@WYw|?OO>S;3j)^=O+amdnbW+8VJbgbZktUZ ziYUAwr%wu>f890GvAa+%OPdk1_dO z&5*8Oz`$BCQVZxv-fa()+7Cnrn+NIf*6{f>^I(GV!x zwSl%>a})caUuj&r|A;85{L8`1WQ)7ztIn(u=dOcUv8LNuGyb=Her%?A`ePEH0Y8z} zoC=;meWBY#jW&X>T$>#+pi1kA5%4wF4YXi%JyGtqapQ1B!r~cGarS9Ix#~u?efvI|7MG zd#BW*6QQ0VO)m!o zcVMdN*@BojJ(G~2R$?`3=sewcp?18zdgfp=wnyikd_h)#;HY>p6Bbf2e;dAdlA`Dm zMHc|A_C`8R-?*+ z%JfW+P<JTJ z#GrzK`D@4hhGu1G%(7-#5uh6@b)uZvRCYHSv*)lc-J)YEdRc^=oOI&w(X#DhR+h5? zOPYk(KoKX?50kPL`_&}&eQsz=+NK38?(8k9dN)FZM?zj5KzvFK5s*)d?cRzF_(qoK zpx|g)8jAYs;mADTTo7VlI3&!`8!&&x8r5AcB?S2b_A< zD>Y&Xr0B7D0AFut4mJ|!j?zPK2c@a<6$i2K7)#h85P=%Fp5tUu@NHOUu|44ldlDB< z{yUPO(U{vqS;9JN^{y6QVEmCscMvZAUFlJ{$Z<}q4THdeM#z?9_fljAZ+G#Y#*5^L z9iQPCA$?%Yo|m`U*v~7RNl%6!SOC4KzLGtI?uy+205R#d7%}ON1$5|-i|gUVK;N^U zgg-9W{h`AdnRG&tv*h9x8;rfpP%@>NZnM9OTFF;1BW%=*UiZrTBn-g~OPI1_H+$`m zsgdQ#=X{x1lS%Gv<17L?a?p-1_!#V%OD%&$@#@rB5%Yre{_R@QYl8`y!x1KOeKzfT%z|>pSNv&UPja6g6U2##MEh zHnX^4;fCU?%Q{!wlu`#7P5w5qY*blS)0DJNX$3ZR09Nx9V6+GG1sr7fK$;N0)H=q& zS)tFB4TJH3N#BI?3;{@Hzr`ljX?@l`cdWo2FtsZ}e7^@C==t%Z{e4`!H9nP&zYfln zkD7Q_DVdQ&Z`A__9h1+NX`a@nz7-E0=P(u*^w%75wDnkoDZz3*7ws;J5%X3>0Am|% zOv>9d7e$8M50rAR3i+`tlV#KK7etn|&RrA7I;KdwEK;p&z?$Q$uejQ_5qG@X9h}fT z;BtDq()o_9CMsuA^>7lWw2B2BqB&xyB*`$lO$dm>wZBU%zzQYVkqhP)Lxb_7uKO6h!kKazVLG9krxVsFMGXmkx@Ucq|M?vYv zK}H3|tQk;dy}5x1!I$BF_~m*?e^Kx$AqOal1s0P7SPm#I@00g`mSBYf^7jzNb1En{ z#4?%!m^M_tk`^Zp;qS++waAl;0Jd%SB~_&eR25tk?`(?QN89f_>*1UP#f(g)uH??T z=RDm|X_`S&d=a_CLr7TJrgRAk#IXv5BT^FA_kYb03T{&3o?rPiFjI z82Vq_qVjaM1%HQ+Ht;_=^Plvg_|7_>7XJ$%v$F31GTK*FH~&?5IS01Nm)6^bWlI2F z6RqVl9`sd9yx3av8q+xSoYt>x$Oq+J@c~~rP$NI^*Y88Z%*5GtFR-K4#74p*Qj^5F zfJ=+~>((au<9H8N?1E{JGI&^*laTR;aV&tP?c)M3srY?88PWHzan0YR(_XQc(v>FT z47OJg2TeFqkNrnQZWPNL=+u<5JCYB+(d#g4Z+l(~;G-vGuVsc7roi*Qz-D>dEtCbR zyznSGUJT!I-ezTI_1DIPk1HsveknasdYiR{`0w>X;m`g%0)hKu|_dkKs0NNN~48T z3S?;jx}#rej$!FZT+WFEX<_30*s(kNrklNep{o^MqSvg>`QzRCCb0SK<>8qW%yCBw zA2JiZnA8Oyn3;NojN$(r6zkOSph%s(zgrY1l?gyK1*c=ifz(d9!kg4D?fBw+6&9Ng zmhaj_(0{Mr0NpqPX%E$i->(TaODT|1$Pu<%wPZ@2FT-4(&osi3HS8Kwzis=G2# zpS5C7VMSyu*ZG5>?V||nf|4a>jof6kd#6jGA60K|-0TbuLAj!tU4o# zc&Qe-4C0Z(i_6lhp;~#H9Og9SX&iMVw7jN^N6-?~)h2&vD#~@W*&I+8+lBQRwRm}- zy$N8Wom{uMC^sWV@_Z?GlTRQw=96o?8WaE+gK{}GB8~m}rd$fcjT6vP zHKa;&pLyI%4FtQ|3p2z8DeXD*3%%o)RDFX*w7ht8qyefvrE}0j~qiPj<+HwciM+ z*~Zk@V*N6LhHDl@2MTq8FAvFxQi(yhOVWBrPHS;WZG;$FI&WybV91Qv=8%=uiX$@w z6tt2NJ}(|~Q0GS=38}$)oWt4J2g2lAWGf1V9BcP%yq*D6^~E~OLz9TRI*))GWZ}XE z#jP0oIEjiAP6x?Zk8^7h0xF}8KpTL0m3NaHXKqo&I2gM$^yc&h0oTxU>U944@_EZu zwY|2^9_WB3fkhov!JCYQXm2@*n61d}ZRml=MzMW{;S20}qwn5tw=4IEYR?%tW^O~K z3R&%*R`*}c5|hgcv3PeMXY(@UcCVRx$*7af(;S`W=$!aJrcEZBFSt<;qB{Zn^tKvZ zFY0L#O~y?Lax190eR`F?$P|mqnKDY|B$kdnr&AXf1Y&>*`#x^WRc9o|%!Pgwq-;SN z9gE$!YFU)#Sg1R7GVYrzhNhrg4^tULPLW*(M;DiYE&8Cz@1N8C2)w(uR$;i**nWFN z5?_Ij^7Kzo0cSgep8p25TTBB8d;j(os(1`@7m)?73SPW`W;o-a8m38yVL#{zJecAp z2_Z1ZKWy8trB7nrkM`#(zw0IZoZ>=Zp!8Ci(5XD6e<4g@YA^VMuO-#fK!tKUn<44} zZoZgpWl6{kg?p7yE5E9U7W8JKdaGZ==hq`_eI7!mFlR?H`FQ(bLOuZcEG!On2LG+{ zUaNAw)3qRJ*X4XVpKA75RdWYWFL#*-dQqr2DSZsa1kbMARpHm8?VpUP2G&v(q z#!u9nHz=E+{Cg#0D_oq|#l)v4JMrqZtL{(J$Hkud#quzf=0oai@v0qi1vVQ)V)Ags z?Z@<}YKT8~?Dzx?jL-oC1dq&5V;mw}lG z<);+sXz5@uVuGa32U;y*zTu9@2H2fUOEfLRWAX5>fQt)=;0*4}_Yf`JLAIzn=$l4ha+3=*0U20x*RKYw~PA#at6L%@(O z`w;U@ys^Wwr}m1oLy(zpppP2?M;DnR5uaKowIoOsJGY>543>A5r^xpUBR|MFDBY&^ zCv8Fs26S6bs5^{Kb_LL%FH*vXNS-U9gp1+;^81%B3DXruj2`v3(L)A5B!&Vsd^t-! zjvN}V4VRO5+AQvY&i$Wbg!N%BewWk3G}tnTPw0=svm5Tgg{~qJ;6E6hixl|*#+S4e z7I=LBD$oCn=KqHMQ&A>y)A#Jj2l0OW4f}JF2!MCpF6QKDX=6nx;%epLVBzTguPmCL zET-{sj6SeEfH0Fmo@dd760;g%5c2GJq6waR0uWi&zDg4On7X6;7 zGw!S`|D4Cy#}|ko6#eSPnnCd3=1tNB0SE^x$?sJps_4h{@*p@zc+M&5(iDV8@gYE* zjkEM8{5S!kx$US=%kD@k!~|QRH3MwHon|+FdqpNf1cGv*n6+^N>pB{W@SI(3X7P1a zv!`8mg$)Dvd>eXRCHXK%poRG6VJia?_Op+>c*x}fpz#BB5ZT;SNe7AZcxL{nz>ezJ zpa4eZtGZeMuZIPt2$z*8#+>GCCldflZYrsqP7c0B^NmE_a%wDr9oHp7Cz`#(Tm5%8 zfB7{wtgX+_q$elNPh+~&KA_T3tdTm@aq$U?;2gtMN<=vQw;^5fPlaJxgU|g0wG`>e zvV~+d&|i}npzA-ZAm~duVu7N&Rkm@iErZu%L9J2ijfouy9g`?$bm>O#X_^Y|pVRUm z$NaNJz)Lv7g9;4>#*dh4OiS`NNl&z40ar}up#SX406WvkApUO5Pz1Cz!oJUJ`1>XF z|Cw2F3riCZdv{F}dyoHNr1Yd&#dqf(?W0@3fs%Mh^}e@k!9}IaZEX1#_Q^Ds&2Z`) zqk_yD*XGyAzlbynj={Mla3&uJ%z8Y`nQgd71>@!cI$IYhHEul5iycdZy_(Z)g{8u$ z^O$Iq)8k`wIs)q5snl<2n{~hOP!l~24EtT>e{dpz0anFhin^U`&isVC+1S1kw~q8N z7+p}}7$+_%-sX+v>@bwm=AlB`^*^Arp(-nhZINe)M6A(w`G#O?wc^3{8BxV*ofs}p z7>|}pjvG@~PT}}BD6@yzLjTJ1*Oxv5G$aEw<~MTtW(sAzv&vw%KtFi}YDj9}ZLGr~ z&Nu$8@53|Ho-V^azsE8@&DsY*{voA*n(x17pc#_s5bAvf&Jn@D*#1pQ-xDza=?+?$ zQdnbec0u-o*Db{mw%D;;sHUZw&tM_Rk_3cFDQTK;3si9?oNMu2gjn%)MkW5iy;tF_ zN7_n8H;^}Cw>L8vDfZ4KM>o?w99|bMhclagR&S5@4SnGL5x6Sy+c~s~6oeyVAmWks zFA~-*cq14W;!SZshutNjy3wEksb;KSZ&@SEIH`xJHg?$T`W| z!s;l^^m6;nH!@UE%%os4u0D;5;bY@3v)-^G!OQMkxLUgL8qk_+ex{5&B(d(&t#H`K17E$DZKxyj-N6CR@C&1bX7jI{^W3Y0^fS}8Bm==!K+iE60$BLLE}sDVO)x)&ayo7VSdx(*3Rd!asBbi@`(*gMvG<8_&FASbwqx32d^CVoo#Kp zaJXK=fcgC+Cj6MGV?9GQz)$pgVWDdAxo&tskje1MN0gP{JBts$i#v#MwV zzjRJ{o0Q{*t}!2n&$t2c&e!JgnvKJ*dbxaI3mw^@u++#5S9emi8c>Z?!0OlhJt4as zza;}_8g$39TS0EHvZ=F>tE7_)PGa}lgf(;D9^10)bq>xl^)DP{fS7ya5}y*s&#O$# zs_e&dPgE{3A#&1ml{?uX4bDt)QV8;Fyorb=+6eYbL#rB>cuH9QA&3a3qQl|RaLHJ^ z#b~LbXVKG(qEm1#22ncTfz{ji1PF&=2N7sCzp}j^&oorYs^FC7$q8&~wE{-8 znq_*1{_rd@Jw6!y9aFRx?@*#xhE)OAma2%B_0|O_d6+`xQ}I_MYCZQQ@vr?obIw20 zieonYJa!b*1X=O$oPs{*u8v&C*9E){O5ezKv^=BM@Mxu;030qvHX0Ujk3()`bGuIp zc@t9R9$&i4!fAc%Y8jG;*Lq18R?3h zh2E(Zov|4s1A_L6Sn3y&6gRjqi&`qwD--+qRYllFg`=VhMXglt$iT7TYnWc$uZM5^ z&*5HoSb$)S3_#jL1KUeX#F+l%)#rmS4k90_9$S)E^g&81x+vbtv@D=|D?A@rG!is$ z8_{wCR~~QkcTul$+7suZ{c-0WOzHA`JKi(o=BbR-)|jYvYrjvCnMhXlnp zNnhjUDpJ_Ra!Owm-!w(UJn54)bwGEJ+Pm1^LjVI~dAEX@lLL#DjeBY>9s1u*|Lst8K)Qy3-g`C)ujd@HSINI%iCoA$fgKa$nak3_9Sas zwAtkG($s1u*XO9)YKxcS`6uA58=N)%oO5Q^5TWFOKD42UGUvJ3r?8mvIg*~FN?Y?P zK7z((aC7AnpgvR`;q=kJV#g2Ljvz3N1C{e7O%g+Ra)4#Qw|r1tMMXs;$;5xm)qcxZ zpEi?mO>x>eCt<{nFk#Jj*1>AM@*4^VoE2kR6A&SVo5?X+4`H|Cr8;D|yJrULCWCQ? z#3vrXEk84z&!?HH%l505!dS{)e->KK=bA$0>Tk#;089AMsIRV!BKGkS)5uEN9xIvc zj}aPv^bV$HZduxAQ(p95Phl1by32=yEj(tSEDAVRI{Hsb%~^2UbQz~V?1yenO_yu^D8I$;QEaxJzo!G*rCz0hENQ2o zF|0M~0MzMn0JFLQO*5m*fbA4~)7kSN z3fD+^NRfW2Z%>%+-7vU(!qJcNA6z!lRC7{$7btR?BOvC7&6rd_Zx{w&EL+;oE zmOhpu?jfWiuF!Jj)NL9t@_lUZcx!2^VsV)vGBT9Z`_Z(2HAi9c4Eu>sgFkI{iQi(@ z8<3ZM?-&MM;FGb0BYH1^ifZPVilLWLQDKJpdFjhsQ+RR6OVxLBzJs=)$#f>ovQ2}8 zzzFGU+~Qx@^g`Uk6O>-xv|_*971Z8Mx}87N>=%d}Gq*OE5~_H^GF2^kl{!wUOHy>S z9!p6yw8$Ho=obo4>Cip|^`_NoJZ0UcDgesl&V2~*ml&4r_79Da=&QVgTSEQ$_ak5} zXU2C^%n_aQ5~AOW+QReU=6cq4hM6TjueOZ5-!xWIBoAY^E#KxK&}&I2tY-FUNV2VCOqM7 zq%);#8fTa4=k{IjKF`f*>-X#4FK#e7+EMbIK}LE!HM$O3G$m|# zxV};{rkCarnVo`h?-?`>TmG&eA0q(6)WU&3AD>(I#0*{enPBS9Iya2GraW`n@e!~m z?M@WiM}BTZ=Ddia#+e=|w4 zx;NDDl!Fnwn*M~PWVrJ_3}tn!RxtSf)tR2aZTwpt7H~TX%UjP9*h;%JH^KEf4VL z9HMidmD|A(7dXb4ONi3xDmHl6G-%S&q09}_SE(X5?CJRr;asN%9QzEE>~wlp<0G>) ze%PZLngA@?WQvFk2~OGK4S@g=@Foj`@}{{aH?C$k4~%1OGRxjvD=Y4;F8y^uX-BU* z@I$U|Uxu*h^lwR+8E9*n=C-J8d`j%_$??gA=YO5#7hnnTQo%?_!@J1uz~GhBb;=p~ z+v1*4M9iQ+enKBoXl`O%A$vh`yuFmeLr_{yOM44D=A{fK?F{Qv(Ch+y+CgE95|~b_ z1(|@OKY{ZKa|cAMjvGx_Y~U_jkqrxkg)puml1DB@J=hwNEvvciBTdllniR^KuoA)O zaw16%8gt^nz&|obBs2HybuNuGsw8@{nJ$?bP{ye>rW#QwN8>hDp2I}<&LxWp-ME2p zK3FppQnY@4g#Y8g1=R0;==;8JA^k4K{@aB?bWmhp-}9>PJ6(KymuTdv%1H14N=Xwl zcPCe$f5An(!n7>}8(yx`d3jgs=`=3wxi4ErzWqrV8Js9;Jt~@*_6Ix7l-lhYpJT|I zqT$kz$kU?l7J->rKaad0U@l|8haklgli=uZtXx=~@0fq3J)=kXSa1X0d+Gid3qcjSn*H@bE7dJt2G~FmEVo}1p!k;0wy?tR ze}E1L4-NrEX%bCFEBlFhJPavoYB)=V6{JYbVq(mWX$8OV&30L{t_u_lDhgrP787rw zZ*6V$Y|=e9)$7vhvN^Z4s}a0E?7<`Rm!7^qcs+W#-+IgS``&ZZ<8u{CQvlu=1ufvb z4GaB19=Jc6>evl144S+&6L~E~6CNQfe$)Z)5XPNm5g%g_1QGRNOgBjUA{^+U%l?kD z&Ge$E-G@sL*aoHSC7Ny(Ks|DeEff8O`!!3n;@r(J)#v;Uyjmu&@q2s;eTctEiB{ZR z)G~j%Z1i8Tn7rngVU9fyzMzi96TM*{!V+=2_)Akmj!gq{*-XCiIPOd_%fpV<1F1cAzG1`;5cuL>J+hJC)DL)!viz-JZEIXs$4e)bm*8eYz9fkTxhH;28m`} zaIG-IbY@(*tuT4pT)Kx{P_3{->i0nzK$*eXT~H!$d@y&gDGyjRSbMlSu*PYkcmyf{ z;t$sDcmslfS%bMFS7cUW@NQgVV!6u*z=S=MnL{`?<}r%gY0N|aguL8k#9!VC2DwaV zhoT9axp`z$5{_*ku#85`lYz$6sGym1u`lF0^XLuNpLcRztCm=qL0X|^InO2_RGLPgI z8jwTxIn@;bt#e;oM4XS`pK}=9;Wk#^KNwD;sXfYu3!rR%63^9|A{i@uj0{C<9W0C& z?Hj7ls~ihAzlBb$oZTNdLH7$8^E}R zJxLkXhToqYgN){lq2tCn^w9L7u4r$m;YbqZO8j%@^%aqr3MFoALq(*WY$t|J6H0c{ zm$nK&%m8@7A!R;{fr%hZsSl4L^Kx#*c9<<5^%3Iq$$B$rq!fs6G`xb5f+ydYU5w3_ z64*ilL@l<^l(OZTW^u%Ko)Rrt83BaY%B;v^-pB|aPW-9s+bM^Is!M#25DlQ8M}Az( zgfm$nBejz1=?wtwvqGdyKx?kyc@vtnQ)oi9BrErc-4O74bkm9lQDC4}%`3E9pj z7HfmjWA8+rIe8)#06aSzKW@53a70fK%vh`3)*L_jYPmp&W&ioAnNXseso5+k0mi~3 z$KCff-@h-UZegAy%UyEd95Cqeq z>u~K|D$zriW59o^8SeXa9^s^#ktCqwU~F)qN%mv_f4;jobW7hoc;qB{o=XiPQeB4Q zb7hKWbqW%2^pu!^7vTFnf`3FRf?^vrh9&Aw8Q3?%vUPJ>B(q@syW5{p2HI{=ds#&t z-->hTu%rR}**Jeen_ZHCl%WY5@p$o;{RyVQK!v=X@soFJ^h&08UGz$pcTY5TCTM(^ zP@#K#I7gv-WLQsO!+sYB(}}~SCb~VxJ2KiU+dCuLD+e?^4DgfhUKxIt-*DVT!Tia6 z1&&F|c}0#%%5{Z~>6Hzd9NvUbA+M&!yGwEyGBZ~Zq0EVnfv-$2rcQ0>r(lM-QcC5{ zQ+~moTN*Rr2YYtpm3nz~85hEh2jIX?UByc4H9}{XT)^|7_BZK`5(>Ufvd0jGADN?& zsPv&~ux?ksi@f&uuU?IVbg*=1AF=aE$9E{zimbJR*I6YACZ(dW;-mZ>DC3jpRAnYF z?IrO=2Fz$V3+*Gqcp1cORT%eaZyPe&yiYcPoi43L9ZbB>vS@Pv1qJ7|@2Z-NRqA{;BoU@N|OPMlqnPCND z?afi3kx*&zT;KG5{2b;96GV+jdP>j%aT#7n=qx8vy73;v1MCM$vXU6t~Z4=zU1ssJ~EXu zf$_86*;QqLL8e(M%#{3MUB{2Y@CC1bwG)3@kbqXV5xs~b*uK0tW0ZlS@!p0 zO_^$i<(8mePZ?+`Y}GLvVjPd`(m~rSoTkdkQoiLY-3*CzY1>vl5&q3$P8pAygKq?} zd}69r)tIe7##4Klyb?|8BVBcQRYBV_oc2mXnUhn>y4m6g6L;uLsTJa;5Z>gLR?@J zDQG#+s0!uOMOlOC!9_ZPIpC-Xcyfa3)#3^lKCui?LjHzwFZqft&&B$Qb)=sR+@P8f zJiUiJ#0G{7W3Hz&$T%Vx5#AO_pJ)y84vYC@D^l*h{}xKJ@N2-4EIbspep|S;c{9^O7=i;s_3&?@?~L!p#zPoicJ|tYs8kaOxm_+<;|6< zEGYs3cCw2)`{X6e=$?VRF-jWHRo>jA(s)vNoKJaVH*+e2HQXS$%ATQmjalAo)`ZUw znPXM2(&VREc^w|me$hGC0o~StK?Pu?7s}fPKGkXv=F_H->9n5UyB-KSn>7yp4b9lx zmoReI4)?u$rB>%tG{fk9<W@Xx*2>z-+6UX3mW zP4ySlKM4FE&i%jIfcIGA^YXhk(0GSg5|^ioz`=RFmF zO>w#yb8-uH!!AB_VPS(lNN?6#I6wez2>0ZrM>|`a<#>JUH@d3}GtS_4zeKQnZT53a zyFY{9>wAN5f773Z3nN)jDR7PmTner9{Zjm70dWL7<$~Yz=@bjk@{#0^Vg5P%|7Zga zwD;1Y=gLF)A3e4AzB9@Cx3HDe3r61U@YB3~S_*zAOpWA+Z*o%3#`poR39^K*br7^#TWNobN`$jFp^1Ztn}hI_z~uB);Fc6^*_<4?U}!G+3I-hIScrV}Hm8fp6YTza})UhnGB$vO@w+Yczf|p8l@iA~_W+F)|MKdMW zkp;`hC%^IO082;a`HhXxc%^PqYqO~FGn()YX167|0nq3t%N(*h45mlQ;(?_sZ`3k- zPB@M`ZE=ei(gsJcY8Lhue-!@ztYIY)Sx6DI+JtdOPX*HipP+4D7Xfc}a$FHODA(0n@Vz-kOlqKs z<<~KvOK>4s_8Q}1vek@J`s$dA`@|J)Ft5yV9wjz%N>#co*g=h^tqEMZxR%yc0VkdC z$6Hhz3&@qT!?4<=*7PC|`Alq$TR>!;w)%ZV`lMQPQij40EMZ$r1{%BbA+@>D@9tl* zaKrSL&&2B>ftP;g?r18jA2nO@l>BL!<+z%fUBY%;i0f)C?u|>|SM%a`+~K3QwE{Fa zL3go$LHws=)DJ(%qtEQ**j|Q__M&(@pe#T-Y;uo%;2kWfXD3t{@>oXTjwLCxTsI_v4B0K-U_6jBhTKx!m*^=C!qoX zUz8Rjp-HZHDFXemNX;(y0(1Lmyq_pzQGwY?Z1++9BEd?(vSu4!bb>ScWh|B8Z{YVc z1)1hpE@^>_5Rp(btbUr?js3iqvxr3K-f?S)5RecBW_QK?D#3D7frkB9AjV7R&%Ly) zw3k%DECApQb}*=43%Yl7VFfw@s+atdNA5dTBUCTdrNif53RcF;uzoL{r~Lk?{(I=a z{smNMN$5bzOG-K6yInfr&MVA>vx?mE0-q~4xOccAmtv05&ScALvKcTdT0q5$I3LJz0P9BH}Q3I#D4cPA^aL>Mnn zsHIXV&C#5#Je-qpjGY-y7?#^w^3pcDLY8qPxXd)z)n9dKRy{*24U zL~`Mmr{yrT!RF4Lvl6J?p|Ec6Qx^;cyCn$+A*Q8kDcfo3`97S4`c}5AB@xHTO?EV6 z8Q=l8rQst+j3g|d=(z*rc~N~mE38_waIVLhxLFsk2u*;BAEgc7T1#1x-G%L9>*vGt zW8%_470!(d3_JK~6)-Oy+dYjyBiJ$Ks%urh5o@&Yk#kLEeXXddBr4lEITGMS zENx_Dz(O^F-+JQPjy>=9TUK06poqwQg)$URCTQ3(hm9d*IdJ%XsfW3X{Fs5jW^`%7vvWg) z$F-^LgU@oD6^G(k+_rX_iyj{=85#&5f&FCBE0V3J-Hu$&BhfmWP@I zt4nTTo46Biir4y~0ldxerZmCf{v3Cr;n*r;7`3V}ixgBg9KkCUj=B=1>(JDMvXX+w zlqqZa^JAXjkaa~2KkW;d(i955gfD_a(P=V>kc??4Wz9FQ9z+)7%S!1xYUO|@)E}(B ztQj24W08;#i*Q0#S;ejd#5YG6&N;Z!#sFAO!V(vXO`&QFWmSM~Ot*TDw`;m)p7WBjk=AgJ+&+8XMm+=uS)uF?2Wnm# z2AAzNGg9FM{1QJhJ=uZZv%9N{==3(`HkPdGZP__$MsoE?l(-Tsi6_9RI2;bN#IoYj zshP?=%W3k;zMR@V*L!sIMMWF-YB2Eb#!bL{TDh1shvlGGk+U7zDXs%J$~0MyPHbT6 zT$|Y?Th}x69>(8zDY5)U?&$7_L4+eCP-{_|50pTq^VOcGh(V$CRaa4)7m?VDL7}sy zhH+`?N?Rv6*F zFT_%?53wPw_u)&1UwTC5LL*n?!nTjM0Z&4;0E<3Zc;cWJk>M=7_eSEJkXP`9aqvYe z{e{-N6TE&+&Iz5%UQZy$>k<3nrN5=2!IZpCa8~n=Xv;++jx0OCbho9DWj;r?UjFQq z-4&n3XtAv`dRHO2Wep#u?e|6a z=y_g@18#K~Q5-V?qs7MQRs_Mu8snVwq3LCdm(UD7i-eV{D?&#pg)^=WFMZ#PuK!Bx{-`SIg$O zqAySwS?}-we(^mB$a3yRg@db3;&D-;>r~&+;qdY#Gv>?Y)*%sDFfL|_=m~!9D-*}3 z?>EvDFie|xa2`&Z7;sX%R>qG)KrLgE*9OA{6GlI{u8M~Fp45p?xUMRS&ytIm3Pf^! zKy-z}EXuZ}!T7RscWh&gJ4eiqxGQVb(d>4-M%uju*xxej*(Im{a;iYA9!Xe9z?C}& z&W)lPpM<5n5Wsvs{Fcx6QIB%yCU5&yPlknC+M+oX0T>yxBnj>D3yh?2<%JcAzH!7m z#ZxepDjQL*)k3@cW1;MN_<=5|rZpzow?*x;--I8(0h&fNf?Mm;wU4T40x2A`=|l%> zuDGhf#oHMNT|xOC>ApK(Ti%j zI)hbg-SI+!a`LF(pfivG8*L^gam_WlJQYMHFZV(_j|J!O!E+)+r|6x>&|9drp_Gl^ z<4v4LuoA&JhUFtnQeOXZ-ap6xZ`p?N_kH7GfewPGciG1JUIzQu5#D#%2BYTVVCrO_ zn%|5A$WwDrdN0)mGXMBm@7^tshl2iHnOm8j=hKF$_jpp)1k&G9t%{Y*N=iKi+ZFDP zoH?Z_CxOtrnmhU|Aw@Y_D>swsHtROyGqcts92oeBLKdoz1#vMBO0+?jK}R)5GLFd6 zfe&Sew&L9@3NuN-hlfva!;s{eiPbhnYXQ9YMi;e%oO~mIIbPWwFlF03Y;mW`rysr}tv;vXQdx{*-Zhuzq195Fh&c>;7BDAk zZJP7~E7wT7!!t2$c`NuhhVFX8uEwhh_0DYR7oAa!hZosMzq1cAbEbVqZe%4#$^n>c zm4^P~mz-ti_^=VSgo+Bw0kf{QYwqp8ceC|Ao)HfLy>mQS2G~xi6Mrv9mQU#<9I&ua zGAF4>|5R>!nh_Ml8998u5h0}edy6s0&evx{o z*@CIXZ0%Di?`_`)yhFYfB7u-I3Ba2V_}T%!uNveH>(Hc3Jsug6qgio01re;|V@wns zS&WK4_z<2CH~b?_d%sZ85mr&+KAS!jA-rkiFzHw;mvCtQwt50$Y5}@Xct7A#@aSP> zoZgCYqYy@rG(66=?ZAjP$FoR)>t(#xZkjxUdpamE2oDPeE{Qr9S5r7WYX2!(#s?a!Ar$K{|0HE>jW~ z&jxZpo7GVq@G*N(tbOLh)5aYQwZ~V0)ih|bNdOOJv87dp$`3u!Rl1+iP&acyB*@oR9X7FvP-b!2z7WatUrj36bCaG6B5xnOu}r^xZn(G5TRJ#&JXPi`Y~8!ZNB6r zWLFYBWizSATtfADO}Sx8G?dQUlgVwG8b2h&G8sT~&@DLv4G5EGgzBMk`)Gi!VA}i%3Hp=zS7i*FCBQrhwYpVHD+DHFHvR$ zbHoYVMT-W12`70&O#KTp+0vO>KNiop=Yt#waN%BA@4sbI^eHQu3r2U5wUvlVn6h`T3BE zVP1{ItmT|(66kJWS)7gnEtd3^G%+qdE6;hhie>|z*HhbkaK-u4j#%S@;}q%?e5R5j#jSc0bZIdoMbcN`2g19 zR!pafaZ-?yUP-fY7*y8aM_ws8*{p7+G}lXXo9pDD@c<_Y9T; zJ7i-8cM-fmva7icg1dsZ@3|}9gS_rNQaU0r8-X3ttL`B6Gp^N;q1w4P86lk5AExb6 zK2#idjIL9h=4X8NqH7#}#nZ7FF8FtNgre_3b!Qn;lc%@PA<#j&TtzOz;zVia(#&NylBGW^!_@lX<{S;>D%vYcuwd4<2-D$~CDt|?`i zmECsCpKv&3F`H(IG#Z#E$Zo5gB5^mM9{*`PYNW0+1#f&vz;|7um$~Dl{ASJQ1e$~M z)UIaDUgGuxAV^tluNq@J|Ne`x1{zFMjmJiv(oW`qQl>vWsoPQ*$sVWMK(JLMEfa}F zi*p!DuHlTsRh4-ayIwLtmirv0r-E|xScYnLq;4W%g;@`pDK-6==QFPT*nsH*i#2qU#*u>QoZP6e(75Rm!{f&_W+#n}{J%EVZKhbEK7 z>&;u-dsF0&WF~yMv2c%&I z-qF1jHbjeJD|IJLP9PLqKA4O)xd$8AkmXUKaip zE*upcoc7)|Y@EWTd(Qgh$7Gx}KWH7Cculs>7(g5J<*9IJNtg4EJ%e8Y6X7M$HGWk% z^a5BhIJ4|jJlfi)Wn8u>&&`b8C@Io5>X(u+&hiUuk=f;#gfKnDufp?XfZeNWeTJ@v zAjFaci!}$-M2TGmJ>+F=qjor%X5({}Rm4^vJ(yD?xJ+mQsP@n$YlN}4X;O1J#YyxG zq<~_9V;7o5qy}rcI@@~vJnUwUF1I@*A%h;~ZIIk%h{e`1tld}FnZ!cPfTq<}hn?$M(p$?4gy)8j ziX?9dm_WySH^rGX0S(2tK*JWV<7yfkJ_mrU$I(FeLSy-YPd1lY_WKLXBKVqfl-lZ6 zO2lnJm_~OwJ6wqfSod+$cOqiJUmR`aLdGzqCU|5M#M9V%T>vMU%I&9{nI+{fM!XVh zwF@YhnHkGvwObPz(-RrxZAwY0Dl7u*<`{#Nv#OMC>T%@Y@h5_lj6yBJ`My=SliL6? zPfWjxp!bD_?}k1G87^Z-xgqpIRf>F8yqWvPb+=TR-5_uEr3%|jRE}rhYxXrk#hc+6 zbZUb!)y_zkgkpz*Or+A%MijTXG0zVcj$M+UIm%}+X8-^lNJd#!2lG);HXgP6C;?G7e4tQ2xp%`V!f$9Tg=i9QDVc1bFixVWhe=6RanKIKus29oY zVMrCH`HuN7WQ*P9#u!ovg9!4*Ve^4`Y z5ELCuZGRAonPfm!60EMJ_n|3Let(0#t@J3Qt;;%h5rs>;2MTkX_^<8g#_rZ!0ro7$ z^fKYOTy`bZhQtei4qJ@jB$1wWx2Cqlu%?PAzx_t7#>GgNI;YQA;A#4%)H_(RZRWHS=|eOqchsh z>|@Yd_t6~)2;bfQoZ9{Q#d<4lm}sz@H|fm)G#}_tv%xiKpZE)J8TOAk#B-bQR){ON zForj21K_#j8!=PG=gu%;Q0tx$e@>T}+MY+f8?|CCdHY7kFY7!Y#ZtbcsD&EVU@Lhk zu{6K=3o+`-MwW1KkRmP9ZqKG{ zz&J0`O>B0vr^q6Eu}#TW)i6_2=FDJk%Aco>S+Tzsn;-n|6#!JY8&)PAXb*?dT!+bJ zlS6Y$>bd5UoQeO($>qY%!MOr?XtbzyMx|Syj33h55la|C5`+2qB$Brg^L1m1#I7 z?tO10K(*YluGDBuKD10|qYz4TkQ){JE-i}*=Q*X6_s0@Qzy1_zP5wS}8e0$EM zqDNgK)71p|BqRxtziSO=&X_5?)u5l0k^02|z??Y7c2?lDs2J_d?@a4z&^8MFYI%69 zw|=7frg?Avr*IzV+mD5wxSwS*B}Z)8i$-1MG^MX}T0@kPCoM(Dm%XXPrjub> z$ZbS(gfZsHrg4>oHyjP|s*5~Ck(buIK)XDfle$iV>5TWIjRbqhn?*ZQ6w3)K9v0Ii z0HIdR#%QUT9Jxw1QI(AXIYHe$up?r_0JT~v; zJO>Y6QrnMwilBrD_$`en<5$61=@7iYFEA~sJutmp!^3!9@`-7RAgSKCm=foH;<{O~ z>-C2@36P*R%P0B$`Zh;3F{T=sSjU97fX0j?=L3kG&S-xgrAGF@2IylXAUlLd64ttP zGoX8!YII-Sd%iKsnsSC&kTyZy9&YVll#f7Le@p^v`^Rkb54eZ*~Ylv&Rjr>bzjFt^6Q zwgeluXV}4xL_V}XP(lwylOD&HmDtc=U?mnvJH|0|Go~6 zrV#!on&SBi`n{MmJRQydw}uMT-#LIDU3FN92E1>1T*t0CBw=|<=mzM_{FzdiHgw?P znfw@ZYUB-*8krUWsrPV$FD<#!d@rQ&Cz)T9vkXM>w9syU+RoVKFDiOkL)l>_U{{@7 zb7)kUCk8(NfkW%M2B*9HbvJiRGpTsM@@M#9a?oFu2O4jpi9=epau#c%=hr*5>TYNP zKU?dj)fpF8mbD-&?-?v>c(oQ;N3>N5wiZnVTfd2ra@58zJe@r=D|jhUue)3sfL6bfOVdBsT8#%VY2R(OU2ha6TThRX-ae&YP<|&77#uvIuaUg)MbZ#pu=%QIKv)plS~o?LF{9K-5`Ec zvFnJL#-eVouO#!Ot|*}HD-y7rvM>Y!yN>-40JkqQPtb$QbS^fz_yjzIp#sjJOzd5+ zvDP;M`H{`t1)GJjy5d3KDx-qzR4H$V0m0SjSb;@h8Du{Mw(}L z$E@C59Us4@_&W1Z1bq|3QzB_u=GO(Pi63S}H%mfUT&b50J>#9c!YicqV@QpH>^aulUILrbzx8-H)=cXgDOTa)6jmLCQeLz~m_4c8{y3BX#?sD_f>dNt)$W zzBzuPLh&upIwPXpvd3I^VbI|FJ73>oz$$Saj^?uWIH9TfX8Diu@VGl0M?`&et=5&% zf!7xJ0-K5nvVS!xT}=N)27uBgEHK?Ogx_#ax6d>MIB3EX!Jl?6%q%}Jf@7gDLUIs{ zqhvQ|!=pb^U$ldLm&P%=Jx~&bU0kE0Pw&8gdjNc^@ShM9Gsvt1Pp~Hvg9HMC<^QpK zf4}qQbUc0Z=RAeoamF*Jf#+xSI_bEc5|QS{)$BS*B(kQqM>3`sRNa3WnN!6Uu%ASw z;-}&fN)VB8@Z>hP)ue?gI3%PhIb$}I=|tly32dDqHo9Ut$vnn`QT6~(xG zS9X7Qo9W!?eCP?dTybxj<`orqK>eV(fkA6`<$x>FGfC{RO1{>E8z9))FkY3gl`u#hgi4wiPICL z@W_28lf>lJnfPuIE}>R#v_x^7i?zUEKz|&MwZPu~cEg-ri`{_vy-oySN@W}$MSrw{ zL%fG%M1#T`>bHrx(bjE!wrVbH?YbMT^z-bl@`3lMTu{gx@k@r_9K)bCLkaaNB?%G84f+6swJkDg!o7SKL#ecz8e67x$@E3k;!|P(3TI!jE z^aiyy`$@C50Fg;JcTtQ*!L_|h`;%b0g#+RrF|Gp}E*u;oAPBRKe`7D*l5&u0=Y zJ?AgcU;*Br_exaoj_h|*SzNt-Ih?`?OZeXJ$EW-11E~RI@~xTjZj%+z_E{fHvnS2Y zqKq7^YNz(lJZO-3wBY#$Gfi!g(y>+q)(|ed?|dcNe|AZELAtZ;tW42nm)+Yty%6%f z6aJK)te0%&B}{2qZ1b}NMPyQiwtZI$t^JjCp$WjAhZAZxM@*}6j3^=l3C8dfh!VU;F&B<8H_}Grr)ZHcC4USW|Q4+E(W}prYL8; zSdD|UhkLU*1vat6F3O>edFYN6Q%0K1YZx!f(s!vF9(+7YFBPbBYo_N%v$Tl68JM|w zo$LbA06^NcpO-IoyzMq7Jgu6GMlV*@kHg{7CI>&s8}dq?>aP`!{_KuV9Sz*Rmf^$3 zkEXqVFK_Wl-*+9PX?r=%H%E)PUT}>+$@IpbuyTr{ZgzOO#%$^!FPvej{<~b#JAZ=8 zd@*O=UTp4q*Zw9+50=-aaUJ2Az2LF;@W=pgpnl(3WtmcaIChwFq@HB+IgUHJGUCH9 zx1CwVK{}+G${ki%sjP7fs6978Nw@BZiJJZh%D|=+;#OOaYqLTvO+xiaZ4|VTT)~Sq zTS83O-rKa$tPvDp7cx*)5{bQtwsJc02E|BR4^MWUsJ<2IpV>fkn>%WAS?T+g78Yp$b)LLezTUQB zk8-#+O7OK`n}{MOJYUB8il8HRT^QA{h>WJs9t9A1XniFjGIg|kMU2uJz6$CSCK4Go zMho@k-!J&ENp!EdKXZg~+ZwXk#mnu3v|3oOGMgX%tC;R$b6ErSp>SPRNb;34pf02+ zHC#aP%j5=U>1=WMi{`U(h6XDSrMLouPulsiz2cH-+{g5lR{^!Qwlj`0H8H3ttfd6M zxIgC)aiFj=z9JSXAJRgR);PFuL#d+ElHQ+-!mU~0c-!|@8)fLenBv=g2q-CTFFoRb za=9tNqb|fWqW(06tz@AOk|esG0l;m==U>E?@y$`LpwWu2Vknbfg05D(S6A}qjH6Oq z1HnWYZ3VTPctMhFbFoZWNK-0Px=5GwMonD!Yl@fh4K9k)pB$Z{+%)guL_tU1SH7WF z^)w_{Xx1CX$M{QvmJ{0kn%Z@IFj|Ildil=R47j2OBvJ#L?0Pij=P0_769CcAlpOK7 z1@!{nMXHxS=6z_tj4f<4jztk-5W{elmpF1IeZd^zs}oZ5nEN7(Y* zUA$7Fl0%jtdRoVZ_bfN)b2wmng>T_wT9mX&UI}}{=rp_K3b(j}yXmK7`D_i?C_0@MZK2PWDTT&Hk z4Dtu(0&=C^6PEHpjr2nmCKWx%xd#>zw!NxcOQ(7BzX&FK?pf>xHAHLo9>^t`)sX=C zH(PzAo5~8I?HbEU&3w@SD8m`SgZUWGhESDhE{8dkMyEID;(xu9CasU46n*eNr_-!s z*h8G_lh5o7hBKnH30uff7A_4ymM1?hy5dapF^dwVh4Ybl*zUT)$UwafMyD2~L8HBY zxjO2b$VC*rO~%ZZcFN$7Uv+|Vs(H_l70B7yYxFj>^OMsKFY#6pV10y7D0qVlk@HrT z&raHClpr)}Z;NT+x^OR4u0cz0VLE=h?rzi9<@@30{Ab_WWgpbwYvPbo0Uv-3sGOZR zg2Q);X^7LI(J~cFG4<9!1lS{=wm)Qha(U%%4T8?8S4;aWshk^TG$D&ML-xk$1%Hyc zW*Ya9n~vNp-b3#!0RDQsQqxj@l%vv%fI5`*7#34^YmRfAG4Wb-!roqg#OKm(OEhEU z^O@S#<%Gq(a$S0|!HCa;-PVIpo9A`G7}}V{J!@UMw*JWN`oqeX9$eE1yL)OII)r2{ zp1DumUk0|+i|xv5Ghb<%Cf;G44V(n1)7h6hWxP5+F1Z#a1)xTB%Efvk2YV1vdq6o4 z+mal-jI>@@8+89D*Ky_U+QqgRql3NK+g*r9issgT^g#JOi{g?7B9VZs- zVc-KC>aT00>fk7XGS&0}p|nLWUxL#~qizHy4Y|y5orE$bt&x{)H5&Bh&@Eu=WoX(0J>pj-{MAkoCKkTG3l87e)D0trfYGowOPe?WOE| zlJ=paEx9H->pYRcBl;2z)=vpuiL*txg!lT^zQ_&6BT#3Zwb^F^G6EL^h_xj z+uoQTP6M{_v&Ke#sxEq;Uk`jO-xo=2S2i@-pB(vGRg1QR6s>G-j#j*1bS|*jUA`~D z@T7okT2Ph*#4u;}z%{MKhLr?kJm7F&M%F`Ft{ z9Evg;UEG?$9eqlJn1W8(G$orN8ov7r*8n`j3?6NEA|`FI(x!bt8dp3_efU02HtXlm z4@uud0${DbC|9#ZL&LaQ3%wRgAEAV)pBKdyg3Ot0w?flBFZBPY=s*I$c;4!-;{TNo z-D!sz08L)PN}Rngzf31^h8m%^syto7nzsYGRAriNQky+~{=9q&~*qudiNy#N=mfx+(Z> z{$eRjBE_n_y|U_>ia~kvv@tOI*x9kpW z)-1mb)fw2sv@4EekVh&k;;P~MqKsZnAUngQ%z65*1>Mxeia5Is#Ob0f5@>Q0o;~wD z@3jn`3A>!+i;>sx-zkC-k3Gk*t8&ynhcXp&*IWBy}#twtTL*>1`z3o)?$ip%{?c|NFeOijg-S<36>HbyfHI zMS;#chi-yjiaNHdVOqb)miF_knrNqt0T6rpS;5QqTmlEId82*-KQel6hVznt#I6sz zTx zh$vmbtS8TF-aX|GJU_kt8DT=9A|m;i{-gQlq4)pF{^@1I5^hRJ3BqYTdI29?@HPda zhKyV@*F=Vf$J78;yApE|m2_|lZ7mO7i4kuH)RqxC!GF2;%NcqNj?-V=pYv5={T9nh zmXYnm8x;`4!ccM(_MV6Po!k)P3?H`lB)$Ip`8?C%-tyg5Z-*p+uC(zoEh|b9dZx6F zM(W~}oZe9>WzUV75Hr<$CyG~<#&ktsQQ9={mRX-gbM|l_VIx)%XQBpB&j5oOwD@os zRMtDd31u9#Zl%E2!?(McFEtdu#O@Dd-b$fiVsk-MsJ(sh=+FAs`u`nxA5$uzz%U;V z()X}Wz=8AH0nOfE*KYvo?}`qTKr%ICK!f%>bwW+BXG*u0T$dnUF>$_8hd%fyUh7Ti z2fF@_Y{>eY*+vF~c-Tfex6Pl0NjE%tomY$*?=y}gNzc^fGk4K;u7+1Pb+X#hVPrn| zYZ?F5&bloGc2s3}|2+AYB^?Wy(arn5-Z(dNbM(E!hA{TwV2%-mKU3j1E4>(tZ-C7} zzWA$ZVkqtJE-e1Ij?DhhS2F#s*t{BFuvA!oc&@(JhOL)f=J|pke<{?fe$0MZ=px!_ z*9U3v?k}T!nDK#Q9ShmtY`#8v*Xez?qvbhlB;$cDZPgp+R@)IzbJgQyMdfVT zboYo<>KWdsC~XddnMuc-oxf6R9rOTiX|!t?60 z%fwS0wFBjl3p9Hg`vwhaR?Y44o&EhGJk`mc({ZI=hrK>C9~YR}PAr@D2T@(639l&!kVzHfb&kN?Z%<651G>sbmbvE#W1da zfg+J$+skS~T{3Zogq`CwW;Ci;0ff1F{BweOqSTJYO^S}~RD^2N-hmYn5R!}bgl@1K z{6+g)(UFCAq!pT7;`Al!WN*zv1rPZ;w%fd{M~;#+1CpaQW_ZRU{wGQ zUe%kGWmO|&;JBhF6V+U1Yn_45aF|WpMBURo<>>u35~_hH(h>++!*PtHfK#ZIHl!?( zd1)H9=BC#NZ*$zn50*2Q_=KkHOD)T&hDIC4kf@poU@R^&7QfnkonT7#9ju|-B_O}Q zX@CFOUhq%{M=||%#@Z2sYU=))Q>rde6CZz5O(U(%2BjdukHjXB|EJ+$<}}?wo)5L( zD7|vJUY(73OC9O5wVv-iPHvsEMx*aplMWcv8?{;Bd`cr@ zyv37Se(W!*YTV4VYtlu_Gl(oW;u>0cAej<`ke@cPm@m15Pl7-cJ*dgFw{1i(`_EG& zs$^czzt)C$v8~A01dfCoH%bR@&F`&f_oP{Kb3Zp z5>2;;CKsS+-LPZ3rZc}EAtIHaoD`+5*6*A7boA+lIFM`4ppp4)XCn~%NCo!ep&pk6 zL-9o=U)#rJMyP4v$S2sYFWtGUQnIX*Q>X*PTJ9mnXX3~U0L?9V*T*Vc9QlQ_8fUZ_ z2UbcYff6+uOa-@5y#Q!6o=i2h8t&JW9uTf5H8lG2{RwX*MlMUQzV8AP;@?U{cE$2( zVWZ*llp)_r@g{Vgi&I@G9BKFZ)pN}IMsb9b4~Ry)jXC)RlAge+T_p((p%3E8z|lG) zXCkLT##L=XzPUVRXq6EQNc4hQiEBwq> z?iM8TPI08>#&8I74OO=`tdH} zVeg1oDCj}PsTwYNSc8f)?nA1Z7a|S2Tmlu)Bj}g}(Ff7dhTUDuBq@)RPu^Q~B$%D{ z8Zd<}Z9KM@2KGEy7%HCXE7o-uUc+(sT79*P9OX1D>7|#GxsTuNxaY3tAs@5#l_WtS zLM>5(iy_04<&|V3_^yYUv#8E6mG{~zelFwZo8AtZTfNX!cs8^U4)Gm$DThtspVDk3 zLs^y-;=}O0GP%M_Jul@b`Y#ze`h+*y--x$}rA9XQiSo0z1`t_1Jb84V@6Ug}+uo3# zG?RgM?guc2`)^P^@TFaR9VQ?#;f*?`CEnnJJd`H_WRj!EoHK06Yle9}72Q`Kf~g7X z(#2rpp{1fi`d*10v@|ws*9q%iV(tj23m(iKx6Y)0y}&%fJgc4A_VgUY*mHqnx$nGd z54Bu1__XivaO*?bMb=RjLTW2so=4PW0zoJqWdz(T{eY1_T=sb*O)LT6XyM&D& zLxUmO3WZ`hrS!)-HTCB@#q`(RDuQwzn}p#Qn}nU<=tNJk^rNrtx|LfaI^Bb?w=QPS zoleovA*sV4yF4ktUe4BaH&>U9w1_|K`a$1~cOS4w{Yeb=9E_oK$8BnF{# zZMr)_UdJXw*YyF>uKHz6t?l%4=~kEB?lPj@FgwXfME(CBZkw!YQ^SNF26W#m;aHu@^!|EUPm*>EEpChr~>5F_;I50drNC; zaA%6a`0*FO$P6dScI5R5JqojObK7Ei;mY^OYghZsTRHYOUv={2I!HdD_m09gT%S>T zUsLr83S7|tG$^XCY0My;JoWEg-ul(z2G4q;ZOk6za8wZj=pdd&TNmm;B9E0P$HPM* zA7LNB*u>jTSxfoG#$U)+$j=mmAHx?q9=FEV8~4qTPd^4rI?Xi6G={SGeUj-XQ~ymO zsS@s{PEM4>(O|VWlFpK%%eYHxR)Z1dX0wHb&`+~$%Vnt1$WsgEK_WFP zln1w05bULVfI>WVBJB*73=J;qBCH~8=6?MC=G=-D6`{No4Hqnf{sa@f_ge3j*z-KJ z-oJe>eoUl(xJHsgd!9$YN{)mgZ{{6-i+h%R7Z&m2XoY5`T0xh3+o%3s$jRo8jNzLV z+rH=-CIe~LK#2d%3xe}IIq!KI4pHlXo^V`^+nfPNjK zKShC%Oh4%vnULK*6o7{4XeF>Y(uQ8VGl76UM~=Qh?MG?;to$^z8bN+gaDo)Q;>~=k zg*CH{aalc&udR7oJ!-q2UQs=ZFkQu)C3UapdION#9=Wx5{=uAW!2z(*unOoVwlw3_ zULOeZ0=O9HRn<#)1=fpLPwp67hZdagMT00nF*}MNxP0L)!H)noW!?W0(0}>5I zNy@{@g+l;^8`G*hQ7rHv$ObJF#-`i;RdlF95a45|aF8C_FL+lHRP-OhL{vK@UI-{8 zH}GKpA3`(dy9!0Qr1qBQUcLs3#goLN>$3Vf0LNCF1k0w?1> zmRn;hCFJaWjH>{ne*WjTKdQEYDgOSTLmY^20{u$ypUSeOl@dZBK>{I3F@Ync$WKj+ z;3k2`CITRO+3zNn3PLEyrzV1D71{nH4@g=@2vzf&5DdTyH2RzPGr0Nqv6&2bU4~5h z-+FRn|0o9Ws2MY`yZo_S2-cG-U{at{IT83i5gz4#c0ZPoJ1!@LDuMz+LSz2theuUs zp@0t1)Ii4yItFRVSqWt6u{+rQnE)}_2&g<9wAx(`Q-b9%b?UylYtAd5kEcnyoAc158j|XDuDh> zfu{;IK*(y$C(7s51~~uW5B{I;uY>WVi=!|m@Mk?T*`Ean!1V|IcsL9P+%24sCEZCI@(o5&sA740K-;7s11@QNmZ@C z^?weDF7gL=Sn~fD_vIRrC%d1c0JHx==Rxsgw`l9{u6+)e`{#qpwEqYY{8#SKJGudVw~rRGZ?2(;7^>w{~Gul z+2l_H;rRZRhXkCUhx=FNbHtB7Wl~A}BNLA5$pHcsYruNynCI9FY=7vf|N2qLi@#Ap zfRN3&PXy0!2q1X=AmEbzM+iLC-vA9j@rK_s>UqB3pZ)J4^JI&NC+5F)JWql9(+(5W ze?-7iJ!S*~MH{f6w0fRs^yhlWPy_R40Or>Io}&NDJA!~<{zLsJ&A)m7Z^WMm1wF>c z{qxE9Coz5G3P}aLX(D-=Gr~25P-+%n4($KVm*)W)!vBzh|L6O|T0c@FQvDkk1T^}) zcb~^8aQ#8kYWt)fIB?_tGi{!G#901dac&39sTO+bujlTeKjn;g{UhhuRCzK{47`^@ z`hYd30J6!T0;9qE*W-Tr{FL(NJ`EM{H!D=2OvCSopTBYcoCgb`V9sRmb)-+S4#4}A eR`e4&LlYJjEVxwWF% zXYOF`^k2x){{P4gZ5{qPg`(Bb-xiDYAN%Orng3<3fA5F$ANv_v>3ewmm!3rbqo=Wr zlev@oe;I)Ae+*#apl|)xE&scG{#SozCvz*uzs&zzM?a_h*9HIC`j;A5>$@1+{1@Wi zyZtxfPu-yXL-MqSW}lnYx79cMF9Wdr-v;)05hNj$y%(R#4KviY(kH< zGGMDVqX^ltkUI@Ub+88$kYrILG{PVCfnVnhWGEG~8-5|?c=|Ek_VVuW3&1YG-gh3r z6y~SYS`hPKu@p(aI|j|5iXF{uKVlNS13P-{Da?UM$^e(Nu=hq?JPg<{%?!l_hZ zB}_SNR}IhHGh>A)3EmW%Op+Gm$Ii<(o%3(E{N@%u$E%1%$p=kLOj?D5;ih8}qmvp* zW4DduBz0{M9{bLdKPb6F4p$wqX@7ji!VGY>)sDj|7AS60pL#nni5r;<|_T^=nmE zqlM+{QgfX})#BWeN|1nom~cfE_?o1r+10v=XO4>StGBHS+cH?gPR#q37t>Wo%~RLG zNJa=8FuNoOGqZk7cm@mk%6_lLM*f~5*6qvwFiYu5K^|TU+8**VF=t^>i>`N~<9{HlVhw^_gfhTaZNt8jJ1&NoJg@ zf!Bqq&qhC{A~LwH)K!1YFc;eQb0JEtHRJ=1DKBt6GfnSeoDpVM0j9adfIC63TE zb%IW0*0!-?0~!rPg_{8vxNTI!l_!deOasy;a!rXb1g_g`qWVf*B_x|$=NCkc4Zi3k zB~4V~tlsQT+>xRwPgN)IWm>gPy=PG`L~3a!JbiLhECX}hD3%FiEd4weam#9e+DF#g ziG-8pb_#P?*}iDihPWTHY*&QICZt8uwSoa0ZROaJ8V-9l`m3bBcV-0%sv&neT@bX= z!45AVjg4@7zX_9Ysx)2!nm%!)T1c85{X!xy5DT&*dy>;c$vT7!CN3!h8aYG}3?jr2 zGY$#@75}X^I(}v|WUG(FviF$(hEu*~=3d z(N1?K2N`CE)%VF4*DZ2svgFG-8FAfj0{4Q0-bfOaCN1KxsANLjG9H?Yo5M${!B2Tnv#A)npQ^DX0)vB!5>Vx z;4N2}xND5Cnf4%=Ox7SR`uxB$ICT@1XX-FDLC|2@n9W23M%5x8tVet;Bi+c9+oGe) z5L0=%0cL5L64%gDxf>PHBQSYz@Nv5buS)NZpLulVZouE=dveAZO7@LAiRBn}qo+i= z1aM`CbFNKszv-W*Z&*kS>)x>4{s_F^Fmg?kM|*X}{iTQfYjnI@&FbWMLG{KK_gC*X z=gx3e++T*rES5wu!_y685CrSUBJU)`MYX0yo`f@s5?G@xmP+PLQ)N%*1DZ9b zzBD+=Q<6fGH@H;fOQ9zWq5#?_(H4iB|CseCUw0!kapD>pklZlvC}S@YLfukOu?%Kc zMlCrpC?+o<51$7uccheTPEbmXqTyWQ5RrE}sdb0!T^Pi1f}|dER>F;gI$Nh@3s`VQ zi~d%FA*{u`*H{!_W&~eI;dm@agxb#U3W)_#1;akc_MR$UaJ{i?K9Dh)1ym<}(iU`pnHSrmw5_&8tOD8HFxF z5$Z|pCW%xy)K-)Pvy~RFL^7d~8rGyDOe~Pr$b=a)416h_XF*P|;y6gbrC<0#Itq4w z1EF5=rpurMQ6?VmGFjR=BUOuRy0SqK4R)4+vk%)VC6b4QjQtR16Yg|qg1IfEl6=2x zanvl9xp@yxPOJ=}h&w-m3Nt_MZLO7>qlONL>Z$Nyh63A2p53)L?j@~F^}v}-{9}$9 zGMVI{z9`9JP*G9IM^I54I?IKGm>snf7A&jyd0LG4vb)A60wS9QzEhs2*o<)IyBv0t%s^ZFwoFD%+}yYP<|} z7XucHA?yi0W;SlMLwJs3ZVf|zUM*(M5kj=5JBH+lu!BKH^vM3aO5~~XZi?4DE5hpr(@*Ag% zukwt(3ZR;g;YV(^3Up&#F9GBQU7fsAJ}8Q>3@lN%00mMVun8|5KUq<3?-F$~&lYd- zgIic^`Al$n%4n*pf3ipU@lI^)kxY(hQgyv}vuA-$NjNg4dbos-XSVDq(1*75w@yep zawL@)}&YxL4h_gYQfe6}$PT zDL?I9BLrZD@aMuuSU`6L!Ry;sUGn)db$Z}Wd1VY#f3qYNPTI;ZS1SE{$ySTiQyI7j zQ@Du6xNpktjg0}bTOvq8+@04uzSbrt6^pL6HQwjB0F0w7c!-ESb|$?Np+0%?c&mLM zoQ@xxN`QIk@&KSZHu%98c;^S$Daij2khn*y4)(TN;!F!gkDpKrz*LLCv`bV91gIpB z_*ynmKFe>*ina@u>DOUT3b#+)>DzFE=NWCMUq&ukRod%dPcVhNE~bM$g>JtPwrPgY zqL*|$XkkxBiy*5X<%SovC)}yn8R;y6n4ZL;R`XoT&w))d*0xev*@H$B7?E@~Q@-I} zHKx5%d_Gtt!3T3-4r1K46=;xO)ze{*87|hxLq8*Ouo%GwQ4lreUgZ{KOF0v&8WG5? zHBbg*8d}Ywbr0g4n-Jdh)g1?I_fS9H0V1U!!i!mOHH4o3CADlL214A?(9eNxJGk@! zBys&kLTKyk@K-n?b;vL(CSDy(4EqIVVi=5ZJb4T90Tv2wKav@xOX*5kzUUw=YRAEL zlKBqh4lK2b{X^!7q(pLJXLOQiop%0}7pkRhz%6GU`^7bn(K3shZ8_%BJi3j`U?N6! zIp6}tLf|R>M5929m3P)$%{#)iq4ao#E(W8-Yj77~g zP5SLXIigRxh%Y#xd_vu{WR(ed=r~6Kk{yW`373>{d(wf;aB|N@9h)2(cRo%hdUtNy zjqY+zQo6QTil6o^hGM(6lTLrquD)4@K3J^o{@mcyGSn1p-!;Tcn2?E6=&vE1gErE{ zk73?Ch^g96Il)Q#A*)9QS{ia{hmK~*<{VK``dVFl+6m^W@WI2+amNg5S25s`_?<8Q)*BEnfnt}~Kl`O`_lPnL@PWLTv*{WvS&l@ihT0t#n&Ls6D}74gWh--R zT4BodTas0D;1YD5O!s8T*YLsTdki>kO$zv$1s)iK8LCba=8>~)fMr}4W z^?F6U-{2Q?->IBLdg_=SL`~l_aE2XS=n#&R!$u}}jyhuQHXSd!j*MQ;a<=gS*+cN- zNA!688d?YUaM7Tt(bPM~_ju5*8lHUzL#TNb^v%dg^7?;#AVE`wq1aTYnRtr^iRB~T zVO`ei%*rjv&FWd&x#gDc8p2kC$p+Nq4H;Ho@#=fa_G6tnqvn)9OY!$nV`sBjD^Y`% zm30i2$I)RwI`}NP26b^4e>n-0XtD~TV*XY|see{)tXWNOEbGQpT?(OFsUWMalnZ4$ z=N!cXYQHPJJZ7Aav_&JY!wBmdR%*5YkwQi}72irjy-YNp?++)=BbwpPlYNk2=^3mN z`{6{jH92Yu|K6wB^AG$kOs% z@&)ua8r>hbL$pZBURo=CpW^12=c@VQvZ_uvN2J)-Tx^*Xe=vnveMad=a4%EP>FW^(fj10CMBa#^>+ z-@xQo6kc|_67$_6s^AU-nj-7r%a&0>?eZ7yiPWxVfnf-pIeWjB))+ceBP<>e z)?X66bwBN|3a>}$cV0Ut&J$-Kadr2xJq+6JZ5A_gPg5mr(Pd7Xj^>=3m~cv|asWqL zoEo{Y66G}Fci?iSgnGVfiU~emXh`tzq-;@?04};hMPHt)sqzJkUX|@Vp02|U;pL3^orRtqAa z+Y@QBSWTq+8Rz@}8RM79)thved$Pwr@96>^bLqQj7yKQB@!mSGAgm!$4w+0N*HPg~ zQW_Ke*nc5F0bZPknuSC!mu`gj02ZYaXGgv?!G-g{}**v^SqFGdJKmU$I;cwZ*KT$ky1CuJ8E~rN$sMO64NY z!@l6GMt=>sW#d%p6!w1YilgNvgfsEFM#zHJWKTa`8(?sWQaVjTU}N%O9bg#RB(Tx< z;vTq>&J@dnsT+G%3S}885zN%fgtL#oNkeF{*=t+4BjBwM%U*yEWVd2LG9%RI;@+wh{g# z+xcgrEh$b?w(l##@Gng$nj$E|y|W*%r-sP;())uWWj8>(I;Y_k-m&$mJtcDkqII6PzD@B|Koa^J+g5 zq5#=DOq3=z_>&z`3xp6QZjZSr{Z>aJhcR)=h6`)pz8;oO79$!K7^{R7QWNHD-$tmUN)IJC+jEY5&FoJf3bc}b7M z>YX{Sct1_!K2m0LB}V5)80Cu>32Owui*y`x`f@KUb)Y?KMe_PNlUW^=pVMb_4zv++W4>cfkeW!J=P$ z3JmH~a5Vo>aR17T{#$M?Zu&DfiZIk&)>P5t|BPf!H#N8(jxLNq8FaZQ8Mz-HPb$f( zS!=s{=5`I}Mb5CUAat#l2kiF}JYoCc?bG!Qpmo4JH~|J&0Il%Rg(7g(j8Ro`P^B$C z0wa>@F6uMTf0wY8YDpIqCph`5IS)wzB-}o%4asjp5Qgf{Z)bWd#3fg*#98nbfR}iM49qOFGSZ37>XN z9HPHFuAK4xjBEGY^!{XC%jp~u0=IGL1PN|N`n6X1m?UeL{N;r3Ozao-Z$AE&TYu-{ zAk`NflusT)f8rm^|B;V>COiM>gz($g*gEMuncLd@;{+&b+s@OY@LUeh75P~k!(c=@ zdqoy*ru(^Jrz_~^DZKy(BXptsS0B7CDG+16 zw7nBOwq!4e7v9C47}@g&^)WCelhu2`ApG;}Y^q^LnNn$6a^9K|`DtLh{slKEBZhb0 zy4Tl*yXJk|+m;R3*3%ALT=B&cfCgkZB3^wU!y*ak*cT4*~q8W(swO62mr%iq>6u#U5i> z7g8hrVV0(7<~@Ox0h`6J|$>c&{;b zABjOblQA|cW&L%ZT3yrV$Sk{jkh_IYM5?9y>>KFTJNC0weGLF z^>?kKseOao`82ylzyJV@|3|G;(RVP{H?T7Pht4Ui+aNO_@JtnDP_ILqo9CgdppbW* z4AOO?Dhq^4B<0`El)@jFH`pV$WH=u`Z+!|xOzG;9S*9OOUtK4QL2WTxG` zKfgS1`5vt}$qzf=vTV54`Gd1?J6(?i#hBRCaJrrEgawqq$gs)Zoan^l&GLp#5oHUR z=ip<|%zv=bBH1zibxKsvr(nTR~b0uhC;Zf1FiVesW2G7SI;$D?1#@U2~z$B@b zlVO;wGoro~=&K&fEJzE{7VeRAL^e)b+!znS7!B1vz$dYX(bAG)c_Qmd)LJ<32S;TT ziW)x!t;PfscOnFSquSt+Bf^c)P9tNx)3m25@kkwt3<2G+uRYww1PV@?`ufa@u502` z9*O^QWLQGlzfm-haTyjG6)+lT6bRUx0V*m1ASaqYIX@!4_$wTJ1~^w;rN*SyX#y zk$t6hA|#-zCcgY@phJPeNAM|nxV81s&!l76zB|@-)#s=JCIODStxsqT9OAE9@^}3i z6c-gr1P1`v{lr@T*K7MvU{KK3+S=CUclhM^4+Tng_re}T9sWjDRh8695C&Xme!>sE zz$%>>&*dUTyegA8k{oA67Hyx|)S0}T+$16z3fx%qvg+nh^FAt za{rxfZ7w2v=E+2KDcW;o7SD=F>`+E1+7rsSsdqaqvK5eO-B|Ek= z)0H;Sep7eMoc-pUGH#t%INk)~saK(GZHr^zoTqTNByz$KKam!#dYfGf!~9r7bG>_k z5^X9}dyd-rVIT)l4s3}eC{>QN_H%(v$@jDM%1&jAk{31>_-o{rVX5qZBsR~n`2v%? zX^hFZ`P5n_5t|-zH5^Gr8fi6Q(A{5L#Ij8o(W~?GF4-Y8bESEe>fvi4>`F6RPKSi) z=#F{;KhPq0h8k0kFuiAkTZ|nX(qOgbEscsJshezeMkht{8ntPSCTJs;nu{ho(%&f`At1o0aTKbF^exyhf%rnh1DaI3x z)AiEz>RVHP*u|TNn?nggsbqiOovly8W`YKMmmc1}DUJTNlLM8=!uc^c+kHd6E!oU6 z1pOWpjq`*Qy5=&)e9KwP0W(Az=^sat28!#>x^QeYx}eXrTts#*AU+%^7I`FTlDw`> zvPN?5r6S7Tcs8~Q)OYGIL5EM$W-$Zc|54%t=i zXZ}mWR0&7Hcs=9^{=LP*u#Kf$1us@Ss!v>eHpXvhsF{KpX?D8UN31NK+Ds2a6Om~p zVKtAPvs1U(*8~)+(Fc)>SKkxs@w{mUR)@QVt;1vlhb`F3z7MIO z#eN{^1S)%lAXe>ROC8rP{8SJv#EZ2M!%a$$<0M^7nwNuqX>DoRZ+7e!wbQmgth9^p?uq0UhAgg6CuKHZ1jG;LukH zYOFqBPvjCxNRd;gn?TT!D7s|s8NYUz`=aBgI`%_)A^j{_X~!}xU^}EEZ_7u6OtD%f zc}Ller7U<^$yDyDU_|sMTei^Vj{O3DP>p{Nq?ssU)?`sBD6rKB#Pp9d+f_QvV20Ers3& zQ06QlCh58Z5L%w#Bj)PjJ&dLEY}bBTHiAvG$0bgkeGT||S-uC5Y)_PwHp}JFL}xq` z8sn}GmjJ2N9sMN*)^TWT6hRD`HYnmaDrBv7n#PiRPV zbUZqwIkbH~T)nK08c7WOY=yO38Zwd`es{AlOWp`O2t>S zn?NP9qVB#YscQ@{%2q2l&-WFgOt9TbR}RU*hS>vZ)G3pc1}%0??J20;#+`Py#`g+PtgLUhG>s&=4?>I_8I>Vr|~bZ_P@XMZ@&3~ z4SYI_ET4`e?SFI{e}{bH)^@fIPKw4>#)eL||EPztmg|V_qesXj!P%uCAn@@M4Z!9c zOPC?Z$`une#X*k5;c}Sp#u@bP@kZ(M1Iijf?Saz^J%0>P-q>{cSxoPGrvP{4Rna%kLk;65XL>U4#Yr<;8)T$0gQJB3`#^8Izd z#(+*{q^aB@D*Hpof}+zoVvIi(GNVDtokCrmyo4KhNqh);@Z$`!Uv=ox4$dgzt66S( zsd(rN2#`Fxc3szJ=3s%leOqnnRkRVK<0fC5D1B+%kw zx}8xx!UM1)S*JGS(oy!ays^Nn>BaSGO@MbDZFB+0zx>g!?bE5!cV^UyXB&Gx1ho;x zcC$O_#Xc2+oOw#a$hu$U(-}42nbo~Pw2$jn66pGg(7QVFKi#f+zPr(FJH~f!><_;g zb>id4-tcb>hrr+L_9s0<$lUDuV3yp>Y6x(X?Bh&1y5pzV@ect%3z4MT$@h^NH`)QZ z?knPqmT+vEQr@U@kAzH%KXdE80Eu49(WLgDNFsfoQ2nkD!DxDbh^aeVz=+}{IE2Pc zxtoFXeelch!U%!067;%#@Y+_!V!y?V+~n*Rn&U$=>;PM#<;YzS!KOPF^D~iJRoRvM zD#FT`^zy7oOPFONZ=0(qwb`9g8%qs(#QFVp+(WucTsNLWps|k*)7j?^EG?F2T!_6s6&3Rrh+Y}b5)2XXP z=_)=<+_}Ag)7U)wGj+tpm69Rnk4svQ3x+HuD3l_BlsrfT1($*U_sGW@s(rZXf*Qv1YL{-Up4wUP%MS0J^2omwYk~|2F)-=3? zqGC~bqNKse)9!_a<@%y45Hq+K2;N6?BQ2V1Tb;$2MqQ(%2g8ux+>=-52WX1orl8jo zx4kW-+%m#JX%N%tK~wV{D&+mY$L{g1g0mFGJjHS}&k!)mlAm1I z^B5qYWjo;yHXE^5g1c#Eh1_;23`t-Zqlp*SKxbZ+%DLU-{x(9 zZFp6T`JmZw2P;0)g?d|{)l!jktkSzadrg>Y?Fhvmh<5qeKk!O!a~x3-2^)-0A00Gl zcg-uBB9BmUA*}t1U5<3fyXjvCfGAW#CWI=ujWNZ%`VM9x+1eBr_Ca`Z=cQdRJGGtS%z zDwdHSME8<8+QT)%&FwovY?cU{1FtCDV77B^M)?VM!9St5VbphsEGVA|Q@-7P*&8NM zzN2^*m$3c%Y-Sgsu*~Wf5uBR}6mH~cg==Ub;&+AKnrqA8!Bq#&gm#9?!8Vz0`I%nh zpJ?5Nde|s11OiRpyNojex2c|iKgf4wp*|wJ$)Bk{ig&J_!IS7fe+_h_aQl6ebW`a4 zW(Qq1Z?4YDhh<<>I`y<$W}%gSRbU%QQ5pF{OiD2^O^HIfZy($woJ1R@Oew@GtFLUu zdobW6<26&IyhXE; z{`iVRaB+UWLN6S@mpV&_mOj;rMA#yg6)GW=W|X9`gG0=sbi)O1nBqt~E>O&?4ga_t zOT(d@b&d{%Jdf&VapGf9BQVT3p@|)}xn}b2Ir8j6oS2#Y>+w8tzzwmnl;XbM#y#gs zMix+h$B1c&*#e`u6Jt8W<=jw=+Rd(wN1g!gDgHU$@yYQitsKEE@-5RZ;FrX{*z6AtEjhWp$}03KZ5f;Zs$hLf1Goc_w-J|Y#4SvOBv&m}c!{lz{j_&e^VV6>l}+Sp>I>>HTtJPB zTjP2p6xcX(N#en}oh!|$!%2IO0+JI%CmW74=ds<8Ul~d)i*@8Bh(mDjps@w>xI4~@ zRokiib8+me1yMDaO(LMk8dxd`DzK%E=KA3$@Dvr7ZM> zi*|o*MjNbC=$FM6QqY5WZix3cS}vm#ItXN0?gzIQ-X)|D&rfAqT9Gq@@Aj>1vcb7L z>7r*B4X}UhW2iQQf;!Or1QAB6vUW}Eb*;x(IMrE@mX$KRygUsdRksz&#l_kDZ{@bL zbrjk;D=On`e0a1U(I?G%6o&!3tPS#2HG4&Ei^F%eOOCrh4P6>}ptn?*Q&+u}@-L@tU6(yJLEoH52W7lO4`y(h@Om z3sW(;oxoqSfoo_?`)|^@Jmh5E!E zMrC3N8;myxIdXrEAM%3-vZkcD&k^vJn6eFG z8#JbQN%%})g zzW8z$FKgv4Cm`oU9U&}a99KadIA>p+i_gGHZ%!>1Q)N^PDOY1sLO%CFE=U{9mQhPu zjnxVnuOaoDqj8zD{c7IhM!VvRASt|1<<2-;#MDwPY_q_yZ_6eW z=D9yF(`E=uN+`|gp+w&YQF&^T(uc+6elp;XSWc78>kUY_mNu}~jTlyk&g|#ZLpp17 z?Go@v+G$UMSqi3_rIlOYil4LJ3XmV8;(V<|G$fn?*RGrjm!V<{OR6WUlkc0%x-X~+ z(Q7@{<)7_!Z+2Mr)Lv#YVQ;T)Hb9j!*$`LO5bS>?o@1Zi`>gpd$RhH66eV1cu4){>n<2?X-emwDF7_R zcF;67#dBQ|2b6eL{Vf0!LhN&(H)YEQg^kMyV%Wors4u-FTP+rI&ncK=n@CoW;$>q! zv-TWPS#f&hm)|!V`>YiOEwqLC?O5RbOSA`)&&hE{#In;He_7JgzE9i1w6qtWIjO54 zj+Y>hS7jP&vUYo8zL(FvmtSl3PW!!fTBPL^(=J$QeMe1vxj@-jHbT#rN=EfZ95@Gc zBfzN3pXY$Duzpd4ozP>+HhD1U6spZ9?KN&%G(Ld-u|J>PJ51&PYVhcgR}_+;bM=jc z3LUf}(tU;V@Ikp2tvRkq;cJe4|FhwJMvppUA=4Wno{OpO;PMCbZy)-vp7P&)Xs_!= zp~+7;b{??GSlYvM(O(}kP)8HhoF zRS+MS6ycufb*!IHVeN#Z9@oqSCJG__yo_PoIzfvBgy(@eHX0e7OSO@KP7fuWJ}j%-V&zQ zy<-Bi9lCFiO2;~Yi*7QCQg{!v!$@UWO0?9O3M26Ui@&(E=_JLu*;d* zQcXTvJZmO$cc0m8E^K4@u^qZc;lO!FU(@-SSAwa~j(|B)oJO1+5^uA`#ts{ov0 zdt!*pI%q6g?bF@~EKbK2E7F~pw8t22qm>5g@>qZ?&(5Q3a*E6o=%TNYv7xk zC^|2;s+#^%`EX9@zMSq9@B>yqwUY2XRFBD&r6D333@8Wju4{+vcnq3#=4B8*NF&b| z>OxR+Thz@PKF+PtkM=*WvN@UQ3L?yJMbEQTtQFTq z5PYUEs2~7?*_rQY=$x^z$^A*K=hNqWfg!8>nq|Zi?k{5DiDF4q6O1ndZ|~yC<+p%38ttgk7ztX4aNXgDE3jll~o{U6oCHei?QcwO#*aIL2B3t+=~{Zkq2&E|sWf zq0&6#1E=4sdU2h?t`CU?hzmpurX}c|Q?UM6DRf0{v~kd)pqXH!!>d0(Auis~&N8c` zctbQq{M&dTd5v>n*U4@A4AESEJqA0;mV{7%J|&)P@a(?P<7r4B*cdOHi;5f13b<{3 z;SOuSa(YIJnDe_8oKny?kX}0~1AY6B@)Ymo#)=>>EkY#$rz7`@M3om>GK8{oEqO;5 z;f6DYh-Fqv?sboZEPXXAK`PpccR{cuHjd0_{AII&8?~kSc@QlZtZIT}sh6R&WQFwj z4HhH2klpiHqUjFW?F2fSn&gAqvS8+53NGmAeb4XXXHBNjUFs3+gZ_PTGBQ*MOn|~@5!6bVKIx#+^yGLDs0dT zZK{4<%&WB9UO}P_XtrAKqZv~{WG=LEUH5ECH$2OL<ONRNx$fJX9> zl@KzSZ=|who%L8a_g+P>&Xl#zI0wDFBWoaYY!O!^u)65k{8{~hI^ZfyAn!QlCrOfY zX5%Do%{bv)AxS678!k#jn=syj>riE?1hE$a*1`>{46C^^OCQz=RN=ks9IYb==N>#R zDkJ5&yo%^Skt)y3@l49*HC$wKR)c$iGIK7OgkxGFZ~ENwvP$G@cf7IdGKi$ZxCT-ZvXRPvQn(l@2j+AAIu8T`GRICLo-aKlFzzH! zFzi7#lhc=Sk4tdksB|q{4o_;aQmj@jx^xwH`SuLJMtEYl@n^E|uSV$a=E-qWsk`#i zJfVFi#Qtvx;csm4Z$*_!%5RDbDkvX7(2$Y{Ap9+8_@x(pl(Po2{!OUY{2hceq5gBM zfvq~}-pr#0dGK#OzZk5C!?HN%KQ=z(vwX<%sQ1?5Hq)*$Jslh`U%q=zPj3Hu{{Z)$ zf2N2sOr5c3hys&>&_ZgZwiDJ<*n#z91HA=O1ufRFgPjMm9lf^3Wiodn<}lH;!*v8= z1F?acfTkXq*92+-MFZVJbW`2o0o2qJ??F^Uvzu=X@Q?1`ObkABEHCW4!@_F#>4>GU ze_*UC=&6&mQD$L3`e1rN5)(J&wOZH3v98Lv1yS7BK{=y$kmWE-Svuofm7DK{sv)!L zN;BNByj*2b+S!w?UD0Z&d_dFjQ5sxKV$Xt7|AOkd*v#FbRBIxjn*>!bjier{`|B6& zS+W3XwR%E5y{eTyGeq&Z!NfsWAl958r3yD&ntq@cmA$4i{Y6DS)FP$mnm?E}D7x3S zPJtU`YPkoVu1YT~l7m%FA&kg{k%z>s8ODlu(cP*?L&Ts%7*oYy&l>d+VMqa&LS9w< zgElOgOC!n)`vH{u^de2&M?P1%ES=|gL!FVwXjh8cNt(l=>xQI+jMi|nBQtr2*&b+T zDZyK1M5y(PYxuNv`925M(mk)OUD!nQq#8(1CQJV0Nk8B{0y~iR@H%EWHf(G`&jp zJ(2l#L~RzLIU_k2WuBXgP?sTDQvI-_m(z1QWX?umXNJs~G&S;)_E#ruRt9H{TYkKb zi37zuOMWY?hmIf6b1D#ZY8OusE7nM96!R*OKCN4KfTClM#s+bBU3`c)T<7-orsm`L zNX$4ou^pRiu<%qi|1nzlSaD$NEZXMtrAb!e;({f-F9W`vwJ@Ab`;iNcvL#??S0iY6 zVLRcX#uc&&wK+`JP3pam^~T+lj<~F4MlW__4SHSO>7&Ic3QU%thEeB{8xKX9*4{z1 zNhwlsOqkA*<({Xk?-2lQpPbL{R+2wqir9ps-i&3f*e_(pCvV=@$G{Os%Fx%06gjrv zehn?NNAI@2xFF6@?*8iy;FUGel65m%K?4ucX;|*B=*oy4A?=|T#f%(?B49j;BIi05 z36_P7Kvh5{Hj0T_(g_Hi3H->kkChX{+sEOQXxy^t78S!r;D5C!xHF5t3 zDiA*@(f?W9Xlf~C^^@{@fE?ZBpk^U@-WL#_Lbn@c?O=N6jKE11F`GS2_usX0_AScy z2n@YlFidyb+wV{N7e5bB0ciC;V@8l+AOT|t8pu?ccoN?Hg;Z0 zG2ixMyzPU>(29AVv;a#ksHxRI5IU;1S#8iI6b~3a5 zXBesSqKd4F@_`3P3PWU|Wmkp;YAN7bXTjD>qE|T!Qp!(lP?TWg+dC@7nYLnp-f`u! z{lu5crz9J(URT2RbZ>il;?0B%LA(nIKNFi7kkvxW=?XZzDlFH#O(V(nM`-4TY;ULny%t1u8T023xf9YJE zgI5dam`CIh>y25kAttVFMxhpKNlAM$t}4DOwc{K%hH(KtRei6CHxKhvk0C{+3X!C0 zUgnFw35vH;9rO1`*0T%qDB9H~!X@#=Y}N*$R&@rLc@?WkW-;~a75e+iXxjed!Ouz$ z5}lux4wg>Y$@|NF3a-_?W2e9~j74kJB_b14<@`F3L8>N$aYvVvNfpcC(y+#UJKz*; z7_5lZj^DHyihm?pn-8H(vsNLLI2m3C^`T?FH=p1kI;LB+byg>{V!<#9AzqeV8wP1# zUa@MA7Bxr=8!+L5lV?&%pKBQR;jT05Cd1rPK9rRzn#_)smM~}Q#HWn&WF`e7^ub`G zV~Eg5rX4W9$ny(;KZ>*aieeBd>p61Fe;F~T-U0I~v5!nfvO*!z5|;0QM$#Fe7PK?c zfNkG}UDIMuwYQ*1RS6K0Uw)G7SHHfH^AMR_0jd^vgQSymLy4i`q#GMSm7`w*+GS@*=rA6o)Nv#3SZD&xUaMjcS8~- z?u=%`Pz%kgrXt^whP2(ahP>L*UW1in4<{08-e$h=x2AAk-VJ()a;rhTn%@SmdY0=G zZ6(+-gv{Ad1k4eC#?hsBs_w*=cc&ra9!35tQ{D+bgd7jT0Zd}*<& zL{*t6sbFCCB|TMaNJIucs}M?CIwqGfVC9FX_U_b11eXqS^ek zIu&`wEH76>NF?_McHw{_JGKP%WarixCw>hIl&Z}lj6O^FJrqS^7R;OAev+?pRfLA0 zXa9xa=id(0U?oCs<{d1elQ5{Sp4c%@QfSk(aaExxy+n%JlHHUsg{|k6i=-?P&p$9R z8$u*e4VNL_ELTC5=pgFuQ3X#b8zA5v=rZXt;lNbonX^)+MW&O{jiS=9Yc(^dGc&#q zCV-b3qBu_BYM_lPR!gO;NR3Ja!xfANAtA@L8y~9Gy`Buw8&g?(hauk|QU(l4G z5>-?L!Kv0sFf1tiXlrX0M0arCv^zNQ&HpUobguE$#dxeb=7s4u`CMDfXGl z`HF>Ktc?38n9ISF&U{svh53984#G*K-O|f>RbX?@>h&%EgY@DRA+K&QZbfYSu4?5g z{*HDdRJ+Ep2>i~35qQw_aTCcIxH+vm7bDyx6T1|X2aNfTXDBQ)_?6`sa4ammT>A-E zXaS4L5486(4rUTUz}Y8&N!Kshq3@R%YPk!+Rri*|tRZt~%dw*7R7<<|+`H_)+1&87 z2fY`^nf>iTfdHCAUVbWl&{khsd$!Hg0T6L#wF~PzVDv)3XTF{xeWiQl_Vsx^Qpks< z4~gogsauvw$2EQ&aQB40dyJk!=9NW1;EmiECWV?XVeByef26%*aIS09CcIW`+qP}n zcCupIwr$(CZQHhOtz>1gpXYsN_O6-wo|*cpa#yA9Kgo5SeRdyxbRXR?R(@5UtInVs zV>V9?t9>c3b95nDkf^4PN&_&dnBk$I!?u<<`yl+b1S4Imq^)D4-0f`F`Yzb!_@Weg z6Awk0-u~tVtF)U>t)Mq088|NYMTx}M)8Mr#ajXzA>)`YI?h2%Sz&HA`*fg73_FdTw zzvB&%r!9Ywo^6Jt68b>!vUMB3!tm~SNTiX&x}_U3l?PCM0sci${yl*FGqhl6!5^!B zhw|)ilJc)1Bmd`#Apb7%|C@FZwluQ(4l;iyU6K?gWcvA#xB-Kb6@=mMn(RSMQ%yI` zHqq3Wt?@2HIQCO{#K=i*mD69vv|fLDC*D2#g@p~q7Pq`?vcF_zaDM)4K1eViBCusr zZl19|rV}#2^^1l@ee?Ompp4_G+F*ox!C|Lf^Na_E>$^E-$^)E1{{MT5U|LRy(*7QJBM$%3w zOcUquW0+TnKryF;Ml?Mn$X7BYM->z-EA&l_kV?Skrb`P<6K@OMN4|RoJjdM~3VBC( zef<5n_3MCE?j<{ogdC(hKE&aMD_i<0q}||OS~FiTu3~WV&4-H zh}`iL0j$7q6jAdY5-h7*Et=S^ocU3tE?p$pqpTXdBmLcGyJ26H%T6ocNS*oh6Aq{uSErG4`*dp`~C`r8*ZIJm#V7J9*c z!UfltyYZ(pe5876u?Qg*uOd1^d!GM|$=zli)%(^p;TKw-abqpc7qS`7(8qnlg5O zNUfM%fqJhU1&8vd{d(pMy#1GyiQ^8aI+MZDgC8qD7}P>W#^SL;Q?~E zQZrO(Tt1Wv&xC08hRA$&Gj#-*>KlV|A#Uq5=QQ?NL_vf@IF;s-YBGO2#6>(0}MqLJE;D~d5XbLMeUZkG%9x_)Cq?{HOZtI(;l zXbAU(tng@j_tJ&kUkC_3VNAxRNkwVh-_A%D?^8kqsKYc8G-DO|Pd0!@Bn=>VXApPZ z!_UDFM&+1ujY2VY z-`BC$&)BCdVx_sfK3U^sqnP%wwKLB>{Z-(lM^Q zW31K-Sbt8)nYue2xj< zFqbb|&AaAs;mk)RKZ{zeBM*Xtim*75ihafvyOT~{s^R5JnrPI3HiCpLH%G|UW(7gV zCE}y7EcRkjM|&;WMA9mXAP!c7CY%l_VTRPzrlbl&#R;|e*wm}5ziZ~QGuK8M9+L-` zWu_&WjJwT;TtLz&XktBOkRAa_^3+C(y#z|xA%4_`tRe#SUt^e|r!5Ce$7oyZPO03G zdd-?C#MvBFGXMT^MU)Oq!+=Q;$mL|C_TEOKzC+X2T4_21f1PROhixeeK$`1$3G;bd zFusS^03wj-Cc7Nv7?|!dR0GF-bsPKqmjwIop7)%yn!hJJ^|0$aC>pM8w zf2YR(YMJ}{q^%@H?SB>h7OXpJ8*@v2cYFnM(MU-KK{uH2iFm5gXM;zkVch7 zJI78UTQDlUzRad$3pwLspn9W-vl$uaUi3R1IaGgMkQ*cwsMySA!+zj5f};JP!@d_o zCwF5}&_Ks2*0`rbF){hb%|WLYa6pTodQhZ~ZJ(-ThX!d#+m&1Bd zMh0(ON#3fl92u;yhBo>lbZA)m8Q*EPIS=3RN8309IBR#w(#vJp3Aj(c&=tH&XU6_k z<7h&ia_`G+JNGB512or=3ZO;nL~l)-a4@D1tc2=Ujd<9JSbD*Pk(Ex@2jp-jv^xm% z?2YVAfkb*SDZA|QPcxDB<#&kZpFpHMux*V1R^a{t_zQ>q-9G+lIg7kEvnAgcto8q)Q2ej1)c=a*2^-c6d~m^EQ)6KV zIACUw&`4x*_GHZ5wwFKUl;woUP^r64x0X{Ehr$B7_|12KbaGj>d;l4$uic~(ro@@)%pB+{{z?yfKxt8mn4Y8s+1@%KUQ8|s;6OXGkz5bf!$KbOqs$C z`~ZQ1#vrLOfj|k>aMZrX^b|}irTDU*YyrMytEI?l)nL{fD8nm>b!yS)TvtC8tKp=R z1|{fJ@r@qSJBmAoT&(Vq&ZGOTtgbceaXA$AXYSF=ze){OKW=YZ$K4yQTJ_`j!6z6e zGi7iCmg$Ddr?_nbSj#-?w90NCT(nx;D)MX~R?L~nC}icGuEX%iI!3xinuo+q>b2JJ zL9s)k{iOS%SZCZedSd)H93MzfhqsFt?4TKcL?(XG5U`h{LQ*^;GVC_!D_o8$1whDB ztqpt5W}t`7()sd33rCW*7VObno1qP*`v1n5-t!9@3CR}xigF0sLGoJyJ3Pd#T% z^IomoYXoZ1NKD8dXX=c6YaSpzh&k*2?p%U)hj+FO+9rd(FYq0Uo8=JdKqfkcG%Rnb z(ajl?&`niYdMOuE+(xe#2_QqVT`n;^6bkD*q!V1`8lrojQSQNuJ12M}?>G7g;KwZj z=En~ovkUQM#|1O2&@Sx8-^%zEdSp`I>F)dvF6I*VwhD-LMVX5P?ur5sPQ>RH(-)h- zB@ix7KZa((HB1p)3F+;F7$gcoGv5b96SR9&JH_tSpn2aOq;oSZ8`VReF zd6KNP?Fa?9MzTYFQD{);r?}R1)!oYr5`_wKLMH3#o2_=<4m0ROtm4|1ud{aAoIL?7 zDmuK23r{?@MiZyuKAYfkcu&N+ubQhrx}-m39q2Ypy(#6pCi&wR>Av4vkToQ83SlEF zM4@ex;r6LA1SR_wKk_s<2F@E9Nc$EoHP$ROj53f3<}U|X)$a>NaS+6)rXB}1b!OdH z`{7YGP|#riE4oPi%VZ1v#`$;W{4z)#YKJ)-SeB3wT8zsFFIvgUX?%ExS?fe>1;=lw zBI{J4YR{s1Nt%!KGh>bHC;|x<6uY5*158=DroCL_JnI5K=JQ*}dwQ-8HoT64%bcM~ zZL9{#W2_sg-rwG6a-s;l$2CW{UTE+fcW2;^9#`AXB!XTFtfZoGi47zDl9N4FN{>Qx zyV}@gx_lu~W{&vKN}Y($OL_5L!A0jek<;GZNjUYu2(dUXP*X&ZQx1*p0a(zzV;U|5(n|g0 zYjX}ylO4?>_(E^Mg<_b}q$@#Aa2QmXwrAL6D%Iru7nA*W!}_PmT~&}1w}brn5rOdk zQr1&3b1?g#LVzhXO$VeAbndPe^(qk*uy1K)WG_M`&4j)nT^!Py8X8sX;b4D-8cdyN z!JPT6xky@;FqnX64`&_XuRHET0qbge9lrVrnx3|CUOXGOiJIM?_U$HfRxM;z3QB%* zvNNnDJ%73%vaZkOUQ~NNKzeyRv-!~0*hH83|wt89TI=r6^C{+ON$SvM>tySA8NGpCjXh;h|Kf~Zpp90 zGQ=h`M4!-WHaUJQg=JFosfsae_S(ePIpYK|L_UEy`x|@Y{{3DgPZt?TpS#)McNf5( zlBNpY{7JMXz!PAz0W@;SFx5>feR4^WUN3W$=kl$k+b;%@5Ah5h2Eby@q_MSbBO{1~ zW|QCO3s04iX{^(kV@O_{zecfgvYP9i`<}IHG;^K%pK$0V#m$y(8+$9tFyCvjcAiZb zKM{7c!P%LQIMTxM4c=KeLnO13FU(w8s4C#ebbhmoN4-)fAr=eDXb8d@|fC;OW8cCPwyk^eX zPmeaaDf`RpUAJm&Qe|N<7AW+aBD3L3(VHEj_fWZyZO@L!i^^Rq;+HqS&|fiPjV^4W zD)NULNLsPUfN|6=A^|RvGLG)Ce-(6;pBJ+9e{D;A>~N(m(XRapi6mE<>^Q@$)VOyW z7&8j?nsK&QVDL8cUS_+d9h{c~-%w~aN%S*>e!$2^emzXq_(HB1hw2cXX@uFZAJJ|p zeC;4s6NRt>(2TA?6>9L@w8V%$c%L#*X;7RzX>nN0-v}9&(I~FjW5=F30EVVL|0ZTH zT!CvK3RN&GdV__-VcoOoDczRuFmzIWeg=0`M(^xHW83Vza4@t=j@;ZO2e&wN2DmtN zhP)hQo*Xp@P5?mNFW>#-S-gYiF^+TeB(UKbGU15U;~T-X<=0&pr+-1c`e;2mdnNoc zxMCc`SK6RHkmK|LjOz4(>{HOB`Yp|a^>b9dkkb8HUoHyvf!NgUvIMf$tk#q8nw!1R z%+Bjyx8z70%fD%V!^06C;m;o7`qh1`?Gp+C$CiwtM(%fQU&XBgV@}ChmENJi?b^(^ zb*AoTiA-5lPEBE)TFg8Z=%OOlpbzq-MLDs930>BFA0W%nG`M_n{E%F((895ea>xxu7vZQoF{Tx%a$6b;e}(DCCRIb6?E4!Y(O6k zq|WS@*8-3`Y)^bJ2UGT6Q;bCVC$XR3Hw4**Xo>3D2$!&8iLb;Z zT-qsWbEpwdpDS;lA9Q0rs@B)~nrc3&_+Nc=Lkj+h;2UiL+Hl@Baz*YG*`O8th{%HD zSRGERgUPad`r*su{GdVjVw2CNcIt>;aCP?_Eca>=cmjuhW||}Dh*JmG9mMjAydUGN zBQRw|6x{!tFe>hm%N&>{mw5{lw+oAL#d_MNDccUN8jfa3n=eLWAJIqr`ZS?~r zaubvVX$k0Z9tyOWK4Fg~W*w?DTcEUS=%=VDx8D@SrB1MO=x9e+D8m60Z@G^cFBIx; zvw-uh06;0)uz^>2D}49MeOXq-i@gUD4S>a%Fo^7@`?apdWkN?}a_AQ`HnM8l@!!ZE zUg3Fy#KHAIBW5{gYKEl^U4rtBJX8s|=A_)(@Zw4wc;%EB+qf2y;tWX29tm;7t4`JN zb3@)ISQzbz#AQjL5pk_I^JAvHTJCXe&P1!*{57bd9F|kUtrO(BVZ=%w(7-l z*>J%MB6y)kg+IG7fjbJvEA5l`J*<*=v_OtgKcz<2%Z#~M!ss3DH+^{qQDeOVmb+OD zVArp)gcv7Vc3j@*I)J;tB%3+0qR+^QdekOO6eoG&knj!|GD`By#D~Z{on(_;IT2Si z->>D)<0Yuip0~xTWW)}@E#YX$nfiW-gX5Yi*SEs&Rjd~5m4vs4)Z{)vRN%<5PVO9( zzkpT1R+FBU0CO5JM?R6eeg3QH`1b(#&(N5RsiM*Joy-3DMr3UNfnWUZT=xGYluJ^O zmPMjR^KNIn9A&!z=zsTvIQ1JMX2IX26A{$cug@RD1Enq299Ou!j6y|@6gh` zYMZRwpAS7S_@lqui9Fwfag_E{#vt)NX-!XbO-DKDt!<)q^&B&3(iepW>vmp+1KUEQ zvb@dMn8^UTA;Q)|D1zJqX#llwZ<(9qj?deT@)qclX&jVvUPO~HGy%>-PLC+min7P= zPfR7MCVmTN6&&@|Lpv~uKE@hANWtJpI|AQ!tZKQUT3Di(1EDAO74$H^w3;N-Rbh&v zgE`{Tb9kL1Gkoh86q%AXyG$0?0YIx{NE{paU%mHCKahH_ol zg<*obuV)0;0CXei1g`d*=vuy)M75!JIA*DeGN|B7gL1`dD5y2B<_+tP?<$9$_#e*_F>`!89G&VIh zHLI+zuS<8VEzzjeEy3|oTTwSIU;j4#76WQl%sX6rG#D~~Gw!Dxc6Vg{&UwoAu*UIu zUM={sKIBfzvd;os^VILR(Z;S8PSZIpTH)e;XWTgi>en%D%epNe?6R-TL(sMWN_xGw z^g`j9152~1=ntE?8vwy`IMnr8i;CMP+V+-;8e*H10>^tT419gkHo)b{*GJl^<{v=( zO5}q})hGCob@(ZoY8l>wW3+D2`NZ~eeR8Y^9OHUN#-r?yXk09JOa-io2>5$C&7!qk}E5$mnr>idzb74$p zI5^NJC)9B_tjlJ6e*8x_2k7RKfNBPWyEsD|K$Yp3A)S6Y1}i$SATXnU+Y*}d^Si~g zYZz=yZLMacA8_o{maSVGGkP|%W(UkH4qHR(q>lTHVZ=$H)k_9i1vXv7^hU)>z+b|}N44(- z28fiLQT7(Rwqzl?hv?I4 zD6>8YinmZi6fo#iD-PzxBWj;N45~CK0w9tRRxx8Q(6Pzu)8)+yLb33LbZm88Ei;)( z`Zm<;d8hu-&z6}_4L?441rKRzndG`wa`${roRw$DP<#oYL`rdLDxgp?g{bWxo>bRLb#sV+evkfGY}fsq(=Iky9y;w5#;Qot~fyw zXgInGS&Sx^>vi?o^4lXJ< z+Pd7Wbv?+1}*FMTYdFUU+U% zjdmSss5>L0?)@I5bFe>@KRFnXR3aip{*hCXoa=$I0;1bWl zRozoT=Ix_J`cN3ExxJwHD4vfRQhu!p-`RVC_>;RI^NP47L-8%-n_Z_^e^%XoU`6&B z;RX5trWED;5+5s7)?Le;jDMoP7xNO+S$o1KG&XmqlJCiP0tU~zPzC-{xU=~X?ekIQ z0epQyIp`hT-ua{7Y6CC7Ho zFC&_UcPdwtFb_A{Tr`O3ZQrk;_iJXfskex^6*HF|dYs_PZAqe0Winj*fBCtN2^L&Q^=0 zpKfUCeYjIuoXLF9zhEr&5TkSTnrW3Rac_CDIgD6Ftf^)nr|uYP2|El-OF33=x|c)N zu7x89`M&5VO8BVH)1^W)BQ;bmk}5-mcRDt?qQUY@n6$B#gm!2?77Gqz!&?T*$A<^Z z->d{lH8sw%?@uYA|Z=Bg5lfvvAnQ9aPt=e7Z0a4wCWG2xGHxL2aUQ?Qs!u#5sX-!p%-9nI1GwGzKvfO69E{hl*dbm_ zg#FBheL^Z$U>{Uxv^~m@rS;vC!5zafS!tGturpL6hZPto7{bGcoAt@Yhv&NXWK7I4 z4OY`=0fsvMaO9rnk2NN;+A3RO7yeWD;cw9ht2uo_t<@A!_3TNzszif|#}jm6riy&w zO65C>&GOLZkE6xS_VQNX8l^i3Yna`mw~1E9)9QWWPN|`&R&iZn5pwS4nN>`f=Lu9; zZmLH4C_q2!lX_F*LNNDzw|D68-5dhDVVA45KPy?oj1q+cgxO!18LS9*e$0ITW%d`H zugN7HY6Ns5K-!|aUdCM@k$FyC#WkKTgj5D}Qi{P1^FJ;o>6 z;(jo1l~q(Oq}2YtYcqAj#4y--Pv{+gy;R(jgQK zW_7&Nfg;~ab*VNN^e3$Pm6)nV7vFctt2AjMxo~sLDQ%fg7B(3~Kgm91i0Z_i05~QN zX{wSLj>@>I4QKy$2u{nX=lPVhMP_cW7y9*Za>p~;UvM$J~^g=y5Dxt#`0kdAFvkD1l z#`aA76e&Hy+a&5oBd&I$E8Np&s0Acrmlkj}oQaUHx*aKQ%4+*C+?SuDRmq=I;r-r<%~ zV+ZjE(e(1R_93QVKOIAMJW;5%ajkw|9texg|G2=^PPgPjZaq;Oi`p@J%Q3&JP>Z>` zmy5%*$*|SPkwk-Rd|mtrQtV9zB1Ur5*2^%SpW%F}kUqmPqDXN)7W5L$>40P-R_C(7 zpfkgDd0vO5D?;u!e4Gp#5sm!dD2wGL@hw+?Te5b}Fag5_iC>AlOqM+WvjV-uB=&vj z%uACDerr=2fe*E)_Xc?7#9+9ph(};=fx@c0g{;QvTk{HcA{&XJza%lR#W9H6>w(y+ z)(z<#yS0D(1)t;tJ%j+z>B98nN=~m^GUCK)*vU?ky}rzHm*4IITZpcDsWT)4wGv!0 zQn*J)AuzkCIv43xny6k|%q)Zddr_{88E?N2h~%fwUh16RXHhH2_IJDSNM zbw+5D6)3FobIVMeH1ju>F`k1n*QVX`;w=&=fHN&tEF(v(OxLEvFN}}O?k1)`Wv0C| zTt)dBOklWPnnN7$g&vK*|6Xj9 zB-8iT@Juho3u~9E^#&8z3w{T9cuE}ze>~UIeePgAaq$G=F^J~{uD@D`QkMeupZDo* zkGZ!eGhSj=SbvM<7IrYTPD4>~P-rY9pBcBK!8Ir+=7g<+EW|{QM zE3Z5(YDO(Nc`+~AG^d0%1EWe-znAqZPoaHZ>(0iQ2A?Q zHw-vwD!n~S0y_ThZ$8!0zvY9dOaJ1mlcTeuxEG{@~;q_TM%3JL!q;qlYYruO+;85Q3GJ<9})qvqcJ4y?Csb#3}1z-%W(w0O`!rnj0dc<;+prqoh?)_KqV|bsF3q>*9h%EZWAXJ*r(MkhxHR^3x$4g6x`KF^;v z=2x+-#-QQH{&2bU%6myF5t@~JzowH29>R%y7r-`q5}2h~EH0^=Is?i0%E<=xB5(SI zOXFk_YJ)sr%5P`k5_HoPjz!4^y@D{IuoL;h7U_^)>1U@EzE21kBTr|G&HBWEDm>Ra zLMD6{=12O<6b=oTA%^}6m4o>T@QZF&_j=jCLJx!Yq z;wIu4$fvS05xbdEPzIDlN+qPSQ!`2F31^umR$LI7q`x z+koxEVVH*y?e^JL<;A@h1_=E184F3|qVXR#NebH)b?gf{{mkFpKGsNZX-{N~Crr7IWFTLNK~TV9T|s*j*W<4(b6 zZ;OsKcJ9T3gtM3zPGpjzP4*Sijbqf zHPmCa(-T)iAH%H!xMWLM+`CNLFVr~b=eBB$^u^uCI6C@`)y@reL(@wYhhQp>3FW%G zZ!AV1e{PMug3HdfjFXiboX$Mv6+8iW!3mr8i2cU9Vxltbl5#1o5uSgn(dC^R`cd7O z=;z>?ra~y!tE^S<$;r_^mV5^ocnUf=&zN?CW=imQiPqm56ARU-0rqYVknraLO{WjK zUf11lu3BDueV}nxO8iXQxCe z{5?w$(wa<5!Tikpqvh~P7XBL5vBn%Xe%Nz@*jJ<}qM(p5v0!2_V-^`82`inz<-uVQ zqE-GB5x@AdlnC6@C+J-F@_l}2%W}>*k-l`~hp*|YXrLfC;UlO>&ViIW$tUErvA3Y- z59!PcB76}(ynWO#=aDO=jVmPUJty8#@=ksrkkbUU6gyo<@stm0-r$z6e^uB1?!Nx% z*bHeMF$TZsLx%4P+kXd^g=>CHComuv^zwHsa@ zAHZ7QCN_6F)?gf|!8joaL5^rTl7du)7stp<#&L#4`U*XoXtzzpRbZ#slkQ+p3>*fb z20@mz9oC(+U{c|sQAkzed*KfA#Gu1XTZ?}9d9rmFR@WfaHe%>^a5vpUe-o0X zAvm2T$;>=bTB`0nWtX-Fvul;ngwYM*hI%6ofiBGH+D$~7fIHA^{UI(cEc?E?eCMJll)-3u8;V<{O~P zCOt`wP)9D9YQE`QUO(h7#xB+QD`U^Z8Kid49@9-`h4@tHihQrBNqiXi>W3dJ^=7$K zL`4U;3bf5}kSJy$NR+brO*%!czihrq0q=AFm?#5VJ!fiePjpHq_+EKbs$vzv|$7w=W=5Iz1-Zz`0 z#cM!MFOt)tL#I_Ns~c*)&f}OHqr>?KGgnnaS`yvI^X}`-aRBtA9gd$BWE2Bh7i|!3 zS91U@PiZ`#o8-}{{wdf5jdiqL+!<7u0fA1YguwFv@`v$)=xHh8Bkf1^I{QT{?;z;U_;*;O{zT zIB+a~-;~iop>SPUy5ZFHs!#a?d7~H-+aDnc#snOv=erlzFDGvRwf$oJT4J4 z2*nL=)r&4uN!D1X2%ZPafp&A-{&kwagpK287mDF&V~qU4As3b}JJlvuB4Bk^8~f_Z z99Qnxg|fdS?Dk*m*pipUWbhtih0yb2sEDERUt<3)Ap851{jXcCb&mu@0(D3T#sODowT*DD&6_dk zY1?ESoyvUHn=H2Xj_QFe77kYRW|EoTTLx%JP~b;gidg%Zh;0$~G7iTO{u`Fr|Xk<-FOdO^u!^+9)BbiK_!ad;Rjb7AlJm zE6}qh-R*QYL)Ovtf<(16a}A3{e{sgKxJI@7+?gId4CHBmy$fc4@uH;e^QGXo`)NI> zg`YTilKT@~g%m96^I%Z3@+vA$T1li|Cl_;Wc@zd*cg;8Uyj)l6eN$2IA+k5y zub10(OivV8QwX#1-?--dp63iV3{xT5Re3|hGg13}fmH~(`3mVW0Y4Ua| zh`=++x{2)vdm@m!uggI{bz=cS6HGIIsPt&|X5^&`MhNQh6R5DhY7CHg8p3(r8tybN#IIJe)ogt(JNU z?b_BDYDor*V|K-kFe@d#J$|f|sN?ItB;i<1U#&rzIZoUn*_brGxQIloKaCN5sg~J; zU~XgT2z>63%+%~9CVJ=H@qnQ~OPWF(czWKm$q0z@MJ_|>f>hy*6veyV(EMu$=UIa& z6F`#_f0lLt`i4S03p(NAbDD%ilbDkbdcCqmk5RGm#PZ^#uQ{S}dffE-cUd~{f~qc> zrSzcL+>mKOw-jyOaazLaC*@Xgb%l7wGP~Vj91pdi{Q$7$D^yD2Jk`3{cfBei(`ZWS zF;+|i3JfcRio1p70``M-IW}5 z%E9gp$|&*~t>dBG==ZE-B4zY1z&LcjCg z*07Y|P`iDb8}n*o03Cn}@t$6&;#a~nW!l3N28Tm^_FF}s8rZGV)+g?~Ain4o9% zON5}jA=eCk@J2OR2qePmIoF(t#z13K2CJdGWj0II++c1wTH0VNfj!-vq?4GU;}z7^ znmFZQBX9?P1niY4n}`7W8EtEO~?c{=s>rbA5xgNNh|c0|_eC1dQ-lwmb4YPKNG? z8}ZlfNZj3!B?NDz;h47I9I@B3$eg`C^@7dYxI2drf6Zq}^qziVbO;cWFp63`6P1N9 zsbG$1sm6>|Gh#$WDNYtc<0vJ-8tN+s@2H*8S8AHzJ3O;5Z8UQ9o)KKb4|pGa)9(G$ z*gKOC;o)C*Ep#;SiaxLhxD0>7e8gW{B13L*!C@y}Y1IeN9^`aTKUg+2qOLDYx=C1-a;(ty>)j2S?TREAK-D$|3ER01TSG^@LP=!vQs z^u(r?Ncr6)Muw#XZR7G-44}*gLS9o_^WWDpZgM2|r;a#GQ=RWzcd~2>E7%!`tB6FE zR6UJZD7EI2IO?_!8aJL@?a-jcBl;hSA$WHD3@8&6vRO7{& zrN@%V$jyS%gX@E52h7F{M+TV<#M$v2nb8=kwhZZ*4_^HdTHj-n*OGduW|hMcNVCO<*bDbj7Y4p>rA@`CkJUu|5V$Jh1e(r4}Nd6M0SCl zKAYz%36ds8>`C_6I7(kR+LTvz^dn{nd26aE)8b3KnE4~`B%p<45q=HABpfm4`c{fa zli4-7St&D#=sV(?S+r0dr@v~O1}P}NcIZO9;aJSJ*K~-3P?(VKXFh%c2j zWwJsKp*oO7&HC~7(?1L#g2QB{93%}O-c9qbPj=FO z8jUjNm-dRP8|4#+?N|y1UR)KjcSM7cF7ALethGb5nY(naWw;~v}6Zew#UgXIN9w2 z?f$6UuViZt$&N5(?EQ*q1X@xH*ZCeVbkGXUxFOvq6RiYI5thopkm{4>*N}^0^mP^xnWm> zTCgP$HRxj~iOlE?X~ktgd?+7;JNoYfP0fYGL)vyg(hUZ|_a@M0E-?f!Zx&c|35grv_{fEtlD;@0 zky%fWfB&dBG(JWs{lLJMSf-EP7^D;QE|K31AZL;-2uj%DNGZbxmSRSsXBKi8XggfH zIWKi_tSsTAep9-YEwWGcB_zEob^f);ib?i}qj>`~PE_5K z1>rk``4q$|vmY$pxDys$TC+7G9`nuuh8Sb(P{1>?P59O>NBLNlx6@>3Pk4010g*)F z=UNd!9P%1CYDyv^1HDU_aNOzmhlD>0){MXB1m97-HRvlSpi{9O<=S>EUQ?q?U%Fr* z0O9-s;x%5_$PaBzNxk$}2Y$*B`JG4lQiPJOC9>wgdFe3s$j~3H{wFRjTv}Vvn!$>} z(<)cYZ5olAJ`eJctR)Y+H{QQ8!@mR7e?r)6<>KHS@E<>-(Eq;%l>b|s```4*U%c?Y zB_U0!VJ?Ux=wDS-W=>QfkyiSXdI8YQQ1C|*o`XP~!L7){Lonb(((Uo6Zv68c9h44_ zVzBP4U9_i3*^jx@;;mTgfsc4r?u9Q~yoEPUN!~lA)K$xplqX%|%afOvAKp8jCy_dT zUL0lsSN(hjXMITv7Cp&=VGjto-c7M^2S(n8NcCTdc#sE5?$FUq4A??u?jKL~L-!x# z|JnzCOrHH4A*Orswr2Fz9O~D=irYJvgBM}6&A#TQX9h0qE#%!ZC%k9M?;AUZxQr4b zuJ7d=T$Be2P*<+W=(G+FK^YaBS_j6_87Hl6(^D@-A9(&J2B&?H^hD@Bg8mE~ZssDG z6z6T^Q->o0{EQ(E5hu!9@>=b7%nt3E;=i$NYt*_{%pArLWt)q|~*z@PBK+RCmmof<`(v>AA z3fv4Nc*`wFu0%14s5urpZPGPV)>Y<~9mW!^*BZ-C1GA}1o#%)ieNUeFC=3o0)VG!! z3z-Wt+OsCnij#?iWpiZAfi+uXiG!ryLBq5OIjEf$5D_% zG*M|FRZdusKfw%}AhjfDme&xzEifNukqQr#Ziy?OJ{3o)ZE1{UX3yJLI4IV$K-VlV z4NJ*>QePrTo3I}SpV~|qGfhsKH)am6s(p5qpNi{CZ`ayjkL3{o`n3FXUA9V-8^)uJ zH;H_#JMVSD1KL%~VS27`HcsEPV=6Hw&oS&IOQa;1*ykv2EHI}xaZv)b8t7Et)Z=W` zwU6tgC^=bZb%Ce3v{m)>j{Eg&OMJCffLKiw(-1P@rXwr+d$Vl%doWpG(Q0v`wubr< z8ed&`pi;p!bY*0%Sy_vug>fhzn+Ic z8Bej76Qk%WW4oLgI&b0~A-L=xA7bit9eU+N-{>mMmid7|c_zknoh&bS#EEM|Z(z|l zrF`ra#wIhh-d?aVOiu4DB6kFHh=IB0Ra=~B#B{K#j%}Ld6h0wGZNTbGR->I zl)*M5ZvXbV)KOFZ9@$;RVPv_}!%S6_-_5*@|NzY!(gtg0KK$)3Xxt{pJtWfqRh3!`j#rq!cve$-MctanJx+ zC#^~Nt%shX2MN)RsP27FnLBG-jpe?)%v8HHDdQlfB&|(#BU&E7^3`t(W-~C~=Xz<# zf-67{ccVPxI2ASZ4}W{@156+sNFaO>7kf`Td)7t3OjmXgj;Dyh#o}%>u@Ah-KSDFF z=Ey%Wh=|!XTf$h7Q2+ym%&+KvO-w3Bbjc>+P(hJ{In($)-$dqS-uvG~2E?Ky- zcbA}_d*SfPS$N_6^j%QYgXdmiTGWd{gVjrYrz6@F{RHzOj8);|a+;@Ff;7J=DY06V z{NS+z_p>PNz`HGg!B~x4QK(2<-gOd_r`7X8=RMxl1jFqNL*AUiCz^xBXLrTn=T|!+ z*gPk&v;!MC#T3vz>Y8-=aRBo|xCmNmBc{dwigBnkBR$G3l-{aF5*3EbX==j>Z07*J z2Pb;^d0|Eb4i5qF)z5$qTK0-t$X>n%`Mp9#n8v+w_QE0vbevOq&OCWz6|O6I6f+WBN~sC^%J#e6iiOkc1c+{wDtOSl3{?5E|3?3aqX;dk-x->Wbh~R*m$_(j++|W1vrm ze#(YjO@(fpS5~3UFL2v@vM~z3McySLoj}NWf@dWh$T6A}VR$4Q__wfWWHb?u^U-9g>F z0=BsYhJE!%)UgerUG0s8b!|i4JcBIeWE5^h#d>Tn-vH&pUF112F*y53)a|!dR)%@C z%|Bsa;kw$haaMk_ZNmv18k^au|8(OpKU&+nMf(25;%M#ccJloJ==+0o;Anrm1`wNpbv0uvq!&4G8(I^T87TgA z-ph+DB##iW3bI1u#QXEC$0TCXBceY|=VUDvo=$DyoQVIUwCe$istDsxDaCTs?k+k* z(Yf;vP9x)aMhcvU-W?qv5U7}7aK;(dS)w3dVE4-OD53n95s)!H&r%$XLGo{9b7D$U z9pgwj4$WX>nph5r(2=yuyS>}pd$&0CF*o;ahW-8aec!kH-rN1&_q9%(QS4=N+1ouX{ z6qA!Df4HKgbyb=B$9)ECN4_cZrwDn{r7n9{D`HS?Uk2i z_s#t}qghonZ}FAwpD%g%Opa{r&bxnQ8E#G(Gjp!J)podMdylE%QCB|)ZyoU)MDo_L zY>(sF`Cx&ahr4fJQFrjPF7UNjf^VxIyQ5j(u!WzeB z>cXDcyi6PKK6S8RXUXi8%9faT?fJb+6Q^WOS$19XW$q*0_S!XdvVFP>6D(vZWxa41^6HlczER95?L6VWHK7k7DX&HiU?p)JD3|lKrP@mcuw%h z7_Kw61{`}4@Mbmn?WyP=;Wr37@d#|@1jo=-SSyO3tRMx5;91V&y!3|R9C?+cAHj==deAddKG#zImPNLL3z z@;v0R096FwBryE_v^=0Dv1{UfB92G<2Z@(62%Z@0h2ud-_jU;!jQ0M3W)uLP*G*TO z*IQm8^iDS>wdL|}49+!Tz!M{0$OXzWziQ590>Wr3QDARmL4LiF0`%XB6i?VUvTyH* zx;PHlQVDtp^J5|rcnhGAHi);hG@c5C20ocyeeQvg99J90aghiWd<*<#Fp#BzMN8`~ zE6oK~G1&-Nyqe~~i@9uk3HJ0%bS)V|a^gfuo@a08ar zKqBzlrv}0%)xW@MUgyb!MuX!u3P|uvzz{6WpaEd?Rq&v}@eJdz%mET`(FX&X1uic%nj>=@yB=kBbciOd1x? zdrPC^$@F|vKb$@b30?^CE{WBUHf0QS0$dbz0*rN3zvSA>|8R0)T45~c>{EZ&Naer38U;hGkZQHhOn~iPTww=ay(%5XQCRq)?biZexU*B`Sz4yr&PsaM= zo^w9)x{bBur9eQTfgm9vfmj-b6ff?{n$>}Tfb>5el#fS7L|K4FLROScMnG0VR76Rc zRz~zrW^zJWiiUO$PKt(ddUB>wk$#bB=g^UIYLa5krJ_kud|G@8X7|vMR#JvqLgo_; z2O0^m2&y;ogyJ1a)cxeoC_*en=WfLY0dVynn1k4wShtQhj-P+-_Rlcjn2v5 z!qLL{-;ksI|B)NnIsUsNu>R#51AB`<&YJrlm&Ey(>x`@oJU#zd`9I+y{tqinY@IEf zJ^sxGME_v}Q%3`ve|P2owBE(p!rJNIoDctT{(p;sje)C)?Y|-ZecS&*{2?2(|KL2W zk@?4E4eSie|IG$0|F;eP5)PW*+@|^9fYU!O@J|h!&4R@x{R9N02@C{8^)CVZ&2ypO ztEKG>j7=PA|FKha{I=u(J;u;W||6q@UhA9LHj}_pdilKrrlAeH!qlprRbDRJIX{W*Z1?kb5j%X3C7o z3xk&Vx7Qt5$*SU5Fh)Yafx-t7tBOv*k$%?Ul+|s;GnMSxhQj!f_^ZRovVkEHm231B zkAS=?`4p&Nfkx6K^uc5>ug=s-jMQhc8hoDa8jmBOBbj05AwDDFZ;A5|oNpeus6H_? zVe{*r4-MtEX#g&F1f&_~y+)&=qo?6?C~ecBkfVM_*(p_X0}EAi*;Un99wyt@?9DIy zd0>|(O;9-e*e(z%Fdb!Hv)d=1P6=^sm^~XfP}J#y$Q)b{tLQTSpPRWiq)Q#uvJjr&;(tP z(IO~{CH2Y+;7Hjz*$w{mjQ%_N}-WVSFgJ)3Jod5Wj2{qqrF$_QtujjsLl@=z$E09 zD@>@g^M6^XKxw7YtUCr%c=cyGh=>3TlRd`^fK}WRYpkj$!eHz=RB4fuuWci56D-=K zghdKP+qe}RQU-Ai+VRrSP@Tn3Io2l6Zm4s$*IAk@ldO!F5udc~L^$}qaOZZ(Oh%Zj zUt7`2#9pQ2JjQGK_ZwW;LDu6G2s8hmzZ48b}aHCAbnc@O7w z7^0B;y0#_rzQD!N6=-Jr-MqyR^+IJA>SVvjhKsj2*vRXpXF|64pz5F$HVApt2knj;*ANhwLneY>DKRNxfk={4NE^Eg>5waK&=#XT zDpKX8$Mfrl%z00;ef1Z(XQyWLzj#zOba7khD|hdGoe;TD>>YfI(H<-crt+TWvYhShOzj1s-0KB{2c64@$OrpWx7$JbEHy~Y@APt@js z&!EL)?zU>Z{_%MQ&g?{rKxi9{GlP8slEt9_jFZge+hUS~Kdm?q`F-5tfT9vG_*22T z(iVT8)F(Ue2}CFA3M-Qlr1;u>jdH}t=w7In1J2;@SJw}X;Lh=l> zXG(HSPhDmZ;rvt_xd>;uaE{64LM+~qnHJCR7S^JlIM$)2D&?{3W}BVZ7zRL=5*mI+WCgT zfqs8L#+lZ7N4>%dcVv}CvAk4hV-k>#FoNM0+7^5hjxe(9!019bNV&g2xP*}lf9~RGdN99f6s%BkIZwWjrOF1iPitCe1Etclybm(c=+(9OGQk9(QK2CE-LwNyBNyhmyIm;6k_LwSb zS#dC-@eq_OSi@j#J21!Z7&Rf7LBWWt+-h)I<9E}bpujpQ>G-%y7gNBNtrn-Q zYO)i@E~ngd@;*+gz1s$9A&Ds0L0aITT{^0w=;~RF(%o*(?((hh7J(d+r;4hY6L97& zgtbzFwNCw`FeHi=R_yUCI686%VzBG>NEQ=I$R}B@N79Ci4357B^B0JpzQ&ivY|`#v zCkpvH?P_J5mKd>@B5%&ObvKA)*oCZYF}{BRwQS(jz_jq7KqwzvG)u#LP5Sx+4U#h> z`+N4DPQ^lEQ!5=aq^U!OnQ;#ZOHs5%jRcX&0j?$Uv^3(qq{TS3{r8w(p}7Z7xQ*Hs zvt2FQbMs_gO^C}@V8WO`*cwWXqSj#dZnNo;X}`tOI7 zA4c>nCNEg!G_p-9NVeRmlXH`de`B#Mz3&d$Fi4fwGD=idMHGz;V4~FR zjil7=p8($dMN1*iCsMi4(!79_9-($!(RF3DfvwUN!={`ylu3!SQng3ZRlS3YdbP)c zdbJPIeiZ6hlejhIsyD>pU9@N9Ex1L=n~a{j>xAl6FE@k^P}Kirow->kN?W*2+0(!5 zJ>~+bJfup+Ub~0wUAf2QEoY%P1P@Rk&{a@1b$7S77ni#;ue0%o&*DGprv^its!~X~ zP0Gux$S_*Hi>V%rj1^zQGEjh5mS04@0P&^CUK0Cp5n^x2I*eJYg>>UQQaILwSsLD9 zKe2HqOwKK{WOC@(#7f<`$wPJ&&D7y#eqb>&@C?Nq)HzXeG&Zpsy?g25xh!w1;IW6v z5?USQu)(v5a@WYpy?(}MKs`MZ)8bo$DYT{wzRj&u!*csvl8YUFNIv5;Y&^w0z2nuG zVqTs#d)xg)F}%mJX{*u3EliUbA2z}6tenz28fL3Vh?mo;GPT()Sv$_0@wO-Z6lnE(&gT<;3j$(Cc&jgc*z z;7VxnkHT~M%K?TeN03!Xv-L73KD<01rk3m0WI}o%ZgI>F1*#T?o#vI`iZHDd!-xUNXpJxglffx@#dc*xsik< z6C%(g?macT;kMkvRm8gbxS%G;3}kgey$2iHrqFM7hKNpsy}!8XHayc{(KSR)n=VgQ z-v1<(cBLsoJUn)elHLq)1V=m~#{%VWBWJAr^R$eD_7{rFtO5W%#cj7{L0gaTO%gR51FwdKlqaO= ziHAATzR2Req%7DX%xDLtetNG*RYD=S0w^Z@ue88n;1spp>tJj@y*_BH5JO~j4Yye9 z%kH2O0O)1nzKS(zT?ZMf2xGq(NYunc+e?%Ig^{`dZ{>*_nbY<}ORV-V#>v$98ObYA z_jin5Vp`N;Mh%Zr$>dfP4QHeGrg5rMeDV`?D|tpMg2pp*)i@$nFrMYQH>?FM;pK_< zz{?*BCD`7|B)2T)4-jcREGs|YUm$+Frav9f-(6D%&&BQXhf7NO$k1s1rEB`{>`c+b z$=Yo)&T<=EzS=%)b zp5(bi9KvXSFc{c<aN7v`0R2E%9GFGdI<$cclU`=EfmuaDBt{eEUHd&Y zElY&GlGW_!5`=+6Lp-IUWwaglUCV{DuNOg+0xq3&HgZUCN^-c3IQZ4O?e(=;o{MSg z^H4W8#{%;&qj5G$Z|o}WN~up|&#$M~arVpgPz!hbN>sU7$ThJBDYaJh4*Uc^XHoB= z(0`Emq$|S*GMhY~oc;r`KXLgxV)V78+EgDk8Xi<2AliS4*#Azb{z_?^Re!l*tD(N- zw9GL&D6TtJjLM$xfs3^ekJy5Q>vV=oXa`<|jLU?d^sDELCW`clNNo10M0;L3a>ec*EIw zlL&5hNq7Td8y*y)@drkJ4Ur`PNOV=N%Sm{nXRasBer+Br0=Rp6_aa{a(BIGalT<h)ElwY-HJorZ5yeq7wB{*0_>cR)TtuYMS(#Gk+1m_I z%RrOh7B(m>SyAoLDtup5mLS6`{K11c&9PpFQR5JtGZ^vJkiFDetCJLgDXZABU0ONh z4pu{9@tmcgK%=^aTcLg_Dl)`2k;gDc`e)gyZN{1!Q{^ev;Y+}7o3V0%evKI-L3_Ef2E~w~PmM*utomd)R=zV9ja}IX!9HG;eMTT6P^SDNZgMOcSe2 zs=a=Q%a0p9MXFRwXO@O$=<>CDO3-yAo=a3Lc1bmvD+rHDS=}pIA$lMH+iy~9MP_Je zlP%MxG$Xk{C6@-^JE>?icUz3~vAh%TbTD zjT@WGChJQ8TWNSnPc&>by+oF2_m+xyH47aRO9xxuo$fQEL?T3dz6a^*89?U;)@^Cr z@_iE;-?Buty4lOb6;-=5&yTA`rwkd}&W_FbntF-><_!x>FF}h>`94-mR4;7b)-AyJ z6t0#0)!x2wZMt0vU}Z%XX}c!`m><9<> zjKQdg5%)KZ$#V5RoMhDjCyloA9%$^OO|fl7txEQQtOx@%V(J*8TEnOz2DE)@Qg!YC zF|g09jQyLA(~Qy;4NPj0PvGe3z4mtwOLpw9s8c;vwfC7R9F|B0e$A)1%xBhZqH3}4 zIK@hJyGPtNRy8KARqGrgT$(WcoP7;a9yUT$HHpWn#eyz$h{$*c7MiD{FrH(MGs>*m zmao=MF4HwuuKqP(o7AVb&|&Puq^QH!?-8`vI|r*KvG4Y?<*3deL(v^xJT##%G3(y$ zwN}#!zR6vYX^!UIQ>SinY14|l^v57uhF^IzKQE-}Kod^0TM){2;D~iOEMk{~9_Lw8li=-pmp_KUrR(BfSZQC?#ujlv0&7_^1k7lqUBBj)7m zq2#~DGA(ONUNl^w8M@_JKU-tNG(~rGgrHN}RLyRjUh5%#i!lcrUF#v}8Mh!lZ3-H8 z*uj|fj}S9|+$gDc%$(E{y`mRQRAZf(KQ6HzmN?;LbOO-<9hY#Uf9otPwA7Bkb$^TR z8A~=MktZ*TJSi5`q%hFY;cJ5fLe?uq!!1KsY(c9a8n4)c-`6Trx{|Tdh0(pupE!ld zOz!aY!YiILOiO5W;yo_2>21PJgoeJra*DV?CXil;5*vlJH)#P*&|6Z9kYI8Od2b?C zV9@uYJv$<-QZZNSf>n3^HuIdV#$}!AS6elmi$d+6Y>MRd6OETZj78xwXCZxCC}I(V z5-2pqMp$h)iD76-reeQ^{|sLLv6^CGSyVqkwRVS6XGYH6AG;=32H{o+n)|wS+I1|S zbV|2hn+TC99ldmB`~|_g7k(NvU>hHD`l$~BxNinLK*-mg6~Vh{%X4Z+*Khj)JYWR4 z&&StZj{u-f0La7lrbpn$gXBGcz=sBv0}Xh7-Ff4`c5>$h;@*LP2Mstm`%1Y69|KUj zw+C`BEd!C=yIhl?E_-H~X-RBKf#FTT_612__Ib%p_*U9d;EOkSfZK0c4St7Xo@%zT zPXT^syncvzmZNv!l z4#zUpY-7J2WpZJgb|z@V3Gk z0uQHk!-hY; z;X8_U-}LTdpQmX;^rW#83S%vggCF4s^GD$Jufvevft!Sly`7`8l8Lp6k+a=@l@n}Y>TUb^ z5roYc^dYRFpl)Dxn6-t(Fe!j30{U?`4e*atS`)i|%>d_j} z&}&Ie#kx`yTTI>AelxmIT2F>{%j9|KXY5Q6Qu~7GDpC;hGAdOua=@x6)`@yew0>9o zxnB;whx2(Xy4`1}AiOoGrywAo-ZP*9JvhW)FuOxnc%pp21KU4Q_&Yvf2cylNAJ`Op zv>h1#k71gsfun_ip|#0hp<1$nj2tinO4eMeEj?d4Dnbo z-818CmTxh>2i5u5PTiuZcy^Fl0->6czxBo=7o%l(4Bfs!KG{o4m~s@^R8o(E8|<^6 z^o=(Ij_*vFuhW>m<_HL;YiYe$eWxOua4tA{MDcdO3`_I1rwcxrUB?YuXNkUT1V{nl6TPCEdy4x{@ zUtr~k%?YB+Qe0u?$lnPysn265kaq*xCk)-Bh9_>(e{=Rv{{27B{%+|ZZ6(AJeQ-AS zgR|Tpoc%vEx&C*L%KoDj=5Ax1oFFGPNRKcyLj}OKyvZo)JS!jE3f4gZy}_DaWu1Q^ z47U+^xh%2RwD}I!ZL-ysuBQvhqWTT!QGyQp&~{X2IrXD>SnjnZ?|9tL+s*;0B z%S3p;}S7Fu6S1W=+;l$)1wDLyp8ZTAsmlBR5X2GDFqxp*$!$G zCQTmaeZo{FgN%ONAJnRPkNxA5Y(-T7w51hK`w*ocGgj zUi^vp|Kr8)_W5*c;?(5_5Ar_vLH94U?6(#AXXYqmXX|X@?);aE`NYnAB#^Mf-z=<_ zRjd8338}-JZd6YM>IqOlm(ekn>xw2XsT)@f^`-*hcZ9-Mc{GNO65_nK>Bf$ipCP_l z;gGRQ(lfA6NnG-vDv#R?yd@X(9S%9C2lpRQ3%As;H>^+#H`Ew*R_9GH>k$9yd1&LCE+E>7P_YpxtBOj()Qj2?szH8!1vWw;U44uhMK zSQmrm62Ck;I_^99G_u~sEQ`!H?g7D?&2>!sek2xPE^uvVJ(yo`A;xp%2=&fmO+%K2 zEnhZ5y(bE?cN2{4tpYnsykl7t-(n;brd^A>FK#ntGmBDzYlXGL-RY%=h{x$Y6Q%@S z)8_bBkB7IQYay-#6fUU%U;C`&rkxHreK{d2`t1biHzL*5H)>8zwplJL3Gq`Q?-8;+ zwkQu((2h`u?z5>Zr+ds@cua5BRD;ddVZSacgf3nW|5Hei%}WSl(MYkgKf`$EN;@+GQ{?MD?^>b87ey$G1KO>1+t&V0dx zg2f6JZ0pSJdh?y)2EFj6ntXnHL%)xaSR3qGgAGh8IbGy6XRF7^x>_ZND?$+Zfvt|@ zDrEB7&m#_*u<;fPwIyrIwJFu@i5~ky?^E}&4$hg}>8wd?4)I|0OoLZ#KM;p*d1_~> z!=hr@@oYO&2^+@AY_(KqQQnBDRn~+Fw=CNWFO+UTO&^V1UrPw3D~mMI_OB&p7;Pch z3>~|@%!i&vvY(3dspjg}HnxBmsmIE1OWsQQh`|Z_=PakN?@cM3z>vq2Ahv4MyCy6lJV7` zw1w%$h}(p3$uC~Ml6d~`aPhu{wD#VkgMEt`JQ_sw>i?K!W&s1|Vftmapy;-iCAlMu1BtD1TQhtqF88BTj;GDwzTc#YLHvi>7 zoK0@z206hBTmm|`z{#?PKH||%#3ELQus0#|{ZI@*Jxm6gK0(|tg#?lfBifoc8#Cn+ zw*MOnZ}Bm`1pb2C16eumxjsDU5F@t6H;E3rU7L;YqDTAVe?(7znw-BIqq{LvcJvRM zE)VjbhBkh8szeQbN0uIc*`MNsDaiqTgb_0O+XKu3TDO(1EY(qt39 z@D?nlnK3qp+)?vNDc2`pY7uE9Tdzo}U?fNyEr^fPtZVAdoFy23+5m35`uv0Cti)ug zrJ<$Dq(Aur0;eSF(0qA#Q}~YUrGd+9ZDw@rfydi5G{hl4yYN_oY%qDaBEl~|p(GjE zH~e@A(3kx$ZRi*EYx3lx37u5GfE~ z5a8o4+{rj=g}^@6M0KzTN~AFr%_d-ZEK$)O|ESE-Ny4`Us|PulTEe_5ndjxsj2Je2 z84e1bPI2O@aBzUHV!MiIB1^@ku(jC1Qh04h>EFnQ)vQvP?EO$du*#~N+84xjDTBY! zZ`Hvd1E}3zNY||3H6#JP%^d?C@YK>&kv-JmCB`iPaRw-U-9gV^W{ff0F#LiI_cLaj za7mhT#WaeIRB_mM!Y%FlS?AQ^7W{8?|HSa`=o&T=Z?1nJi}B%J{}Z|bhEC3oAMz~p zKZlW$mDX(+_z`$A*&WVEXiz+Nw>sCF41<+#_zT2UzU07)N3TCdH>OqNaB14b{ZN}r zCA#;A-zh{e;%W+N3*dF1zC52yXX4tz=d0}jVef4TgjU5>SC^XVh=#+?WNpEyutB9* zFd)A=&tX&-bI@a)?4(S%5(~^(%=r;~pkZ&M7gQ=(>CESE(9Bc&op5+Ht|dL!z-xpD zITs9G1m(JBjuKk4)31&9=X8-B`B=mt!I>>(mVxL537$pn^zrSTIF_&DdC5=*WmpiV z1*bMGrDy?$r9bn?GRawMWCvl*{h?ULvjaW^7)2sxu#U|u7tO+Pb2r<>zZ;8iUBC7`D9(U4ogAj@0qg2B{+bXOFHGw8|m9S=T;-V;g z=_jez;~8>{*#iLkEj@qA$ls+$`p#Jh@k4rmKJtzKBt3rxW+K)mHXpN8f74BcPT2u^ z6dqY2AwlzeZr7HUJWX+H0<=Y0L>LuUHtk;W*m0NmwQq*};;0wlAX_%Sh?@B{0L=oUr_*s%-(4~x#Y z0n{!ObKMi|bu0h7OVfE>>YXi=N0QkXXW7;}YeCa0QVKavh4?aNRngQoyp9Kn8TKEs zStKeG#oqLkg)XCY5eHh}ZbKU+%=5{=Y8Uz%JrxMKaY9xEmH2JV>FgiA8Fr=3XKej= zFnkQ!-adRs(8ken!)x()#Ejmt|0M8^Tj2Kuew-X1`1KLZs*gG~J{FgD$9+gNOegPD za(TW{tN?lM2j*}e{^vgh!~fLS|Gzp%vf{*t(xUJnb2%8{B&4u% zj~B*@C@C@^oz_4?sR#-}gN+r#xFWlWmu9b+a*G!D&HMc*!RDt10P#XQ@Wdz=sV1*% zjHG+bbUT^)zW@3K)62Rf#5@P@fc_}BF%k$g@d*#yeQ?$@U(rO5(LHbq1l*5}D+zWp zUh+_v16Qh%Za5<@SRn<{hajrr7W2nCu?oF)Y=ZST*|_9bq&B9BM*`*;GL5XdWXXMbTSRrHI0L zc=`H;B&HBoJN1u2RT45g5#DvKsK$Ac+vbXd!!vYmRR>W>dh{KKATo8RIxGV?osi>q zKfREx!-T8h5l}|hnq$QFJvQfMwW89*T&aAC_hP@~%Jyv8fy^c9>Ups3_lya66=9-s zBGTrqL`6fQR~5id3v=k#Ja7-B0P9Rf*_?Pg-q+8ryD>ryG!QNJk=DxSaaVC>ZPAxi z9L1Kg-hOTOaM4W6-FLf7@b0v?Gbe*i);_1;B2I(oNE5&g)CI>YYL+3GUa0rLdK9gZ-bp=3g@Mr(#yC!?>e- zM}51xG&Nh57H{AuAgJpj7$Y_Kg!ttXN%*G#3Hd;I`E^;=MEZtR88@>z`O5E_>y*_# ztE%g3sWdIc)h*DV6~*xR%?}paSC5?!uMOlp$J6J=+otvS2h-VH$8X13e$yOIm%MN1 z^{B65}Lt9k^ht`2f-0Z$=1-m`p;B}>%T`Ae?0RcaP zi@)XJKkf%Y^P+skh5)(V$%Dtg*)4?TJsJUVpN);(N9N`}7#UzcCp#eaUECqBmASoO z02_H#59;&=km!BTD)jh9Jm%`x%iS%_)Sa7ooE^KnCWVfy%qAwY2hTiT2TO9t&^7cT zTR)|$?@aJ|2jly(e1-N7w0SKFumjsM(L(i(RqLtUf$(kG4^0Lj;_a`-dORTG`HtK3 z?e89QzX4ib@!*78K0k)ur&**S@9IKr)%({~B$Sw9#cwrnUU3qereTB9 z+KsDZx#_7V;(Z?xm(x^>by=V566#&R#V5_Ie2z-vjl;s8M_zBvC$9#5+C!x25R$_1 zwxjc$@in;r&G)Dbg%n@UgV$GZ*BL~00utEj|DZQ7Z z-m-9R3Nwv{Ujie0g%%qNb)p3sjfMvshTIpT7G+c^7rAn-+PoVu>AJ`vX#bQ3@4HOR z0LZ2$3eg6p_*qiWL0d`#Wrr~jo0WV=SwbsU7(hYHObafR1#1#x!GNbAf$|`c&4&1h zT!!%U-+6GRQ37*a*fyOi9%GjuB$%LDzv0^SX zO9CdDD2M`>dySdUJ^maDHrD3qR+CK?H-i587ON@&L@<_dNOXq7$QreN>$A;G;^Ssm z8iK_fGoPpppECN(l|u4`?}@P6cc`qp_;(tPOA8Rt?=d-H=IN6jeJf+E83F6cnZH=Hr)eu!BDQC@ z%5SNZvaRU(o@n5|Da{4SP>9IWyh9-X3eW?eRn>&!N#unrMPkn+kPrpC2Ishl-m6?v)nezmEHY9eyGY> zDKOM{NzE)6#7lvQzpCLy_ZXCz499j74y8taZp_LDsi8((Qy7L&zR)X25$1r^LY*9Kt`jj*1#wV` zQZ$d_1h0vgKtP3g=M<|x=m$ruC^O^Ggz_9oMx%NiH$l35w0XW1)kJeW&W%Q<+Osku znoERwenhfiGUc>c;bYyeN()lj9Rs+q@WaDqQ{c)RuK{J^gsnwQSvI2C^zHVP&FMum z!;c9oZKpPtJ+n(vyzV5-4p!1Sg38)@)pWZKXTVVKUO|>!sZM2v+rlq_szX*axrFb1 z)M@d`(v+}zDYK!`VWy|JCt;InLc>uQ3W-8aHcA$8dnF0P9L*vUdEgdvt8sHo09bEPtDM2LNp}(>e=Y7H)Au0>dA<= zDaK&{<%aTFgN9JDCI@cvxT|cJ8Ic_i?Rp`zkc?UucMQzQo9aMI<;kw6QRPOdu)OKq zpBI?5z*F2gW<2ds3E(QdJiVmMqlQ%0?i-?}1=&XwcdW;7kR4xgs&Zs677sJ_yd z7$kag8{eSZr|-?|0CknUN^?bv*>-*CDLK1-55#%mh10-Y{7jQEFLfkpH(f5XI-=DQ z4Y|m2F+C`oD^@OuF-D_lotF8+VPyTFzZDDleaUk;7M|%aLP-L3t~x?$&=l3p5&m5h z@AHnUzkPa8c^gP;r8^vaZGYtiP#u)=jpRnjp6Lcro$@UtoJ6ZNKuGz zo(ecEuoT$|{L^8{2@kBDxCVgIT^Do8*hS;5p1nXJ+iy!i7%RqYKoe1nf0KSF_EsxSIT$5Zr^DkJGg`_8`X4{ zvM)|;13IA9)?*$dEx!)shsrZZlq%r_!lwuGU4xP8SL0#x7LovNkQm=}K1LAz3j5g*6$qksI4EjJ6QPb--~bBFsz0`5VSjMe@h2#W}|{6Nu0S z7pCUmnnO)OPrC92aEK|iHXf26JuJ}Mfxz8gW_Iu7KWF_jd2ZK>})$I)Is|$}cup@9sg`hpbQ0MQ`Pd7WWT~z97H8ODj0jJj_>;!QV-eJ9M04|pTBp_~!zjU?`_h4Nfc1b?kmW4Ms^^p7>v zg0C8@+n$V(ai6Baj|ypIMku+OB}mcEllFgLh3nBt7H~D}u4P!o=?6!un(JJ<`X_*glD=w6X}7R68ZIoH_CM1TW$= z9Tf47uEtesdUbH3l&?47hJJL+j2W`+*f2tk)Gmrh>6;;(U)!*N{ z`Wyt>KU-4Y)YNR#t15_uan=m2IIr%>plxkfwR2(2P6CmDnZ;4x&zEYq3jME^w+HsC-Be9H<%t3mp&C@bJASM=>?G8FOC;1Is@iM1hL*OLwDr2k z8_40{uPQ1e>=w$wnUIpHWiTo(Eu`hgT;*C+SCCR7`j{&L^!9lBh}PI;c@<+4;Eglw z1NL_Z;aL)8Kz(H>cg$AsD-A269tn=kRChzW8J^P0}<*rb~`lTUwvZh>ErEeckhdNTd9Sv=zj?%b>cqc=H)(f%{t zf+Z+)TZC1UpBMz&9HZ}7fu~P%%A9wwATqFT&aejkV&b5hG@w2#;S}#4D78D_8uUDM z=F4TY7ldm@<<7|Y-!%g8EQz=)>mhv3nRvHUZXKd)YM*%({bkn0sxF8{d3C=`(tBiz zCRm%TDV&&5c&0pfn2EDSwyQeJi5I*MDt#lEAEb}h7(*zImnIwkItCYo^o-$gB8+Xv z6t0xOlBgi;{Vvc{+uTLISAAc~bYqTO$VY(mgqYvg#sDB2&e@fw%zi>OWBNwS`jvFr zB>~|J0m4nBaOb{j$Av3a>vaeI0rM6CFvw4VstI=bmLjRQ6#RkpzrN4(r|tT?Rr{(; zFAerl4R!pmZ2z~qi;Rhlp^4+4b(d@K}87} z2$6I)?!Bc3TuBUGgq@9Px0&8^2r}N+5P-rcvyi=FRhiAH93HcytShe6bUHmgAMk6? zXe1nMx`MCRA{&D=#I~vS5S5=VIon3$S3bsQGGVJNkDJ-ixECmQaFb6>M`DF|vyW$aQ3zo9;U84wf`xivw%oG2oD0MXPq9qfU06)A|~ z(VRRJN@nDK0*S>BOGNgK3zNUawdh?-sUM@KDs!Vnq+91b&%zODK6iMInXsG-o4S>)-9z%Zi#cNo%$ci3h{g|fYxST+Sl2bO%FKCF!_3ho zB^AzOmz5x2o?$1xZzFbhzfkH(K^&!jV$vz`3$Iceor7U-_S`34;Zk%;Bhw&)=q;{; zArV+!>4;Zpq5q5~Pe@)k*ERZFaBo)FEmcIL)qy%syALfP1Xv^mO0p_V^N8J`xW%V` zUh>4+3fQbxpJr;h4NKguxbJv?`(57qQ<(lPX3ezoS(P8ZSm1{Fe=h>7C`$jY&P}$O zg+B5!;#&@hm5D{YNic>n@Tfk{sy+;`4Kg<5Fh4y*h+zzdXLWIN_l>98st%$wyl3fS z{7=cNXX*JOnJBoaIVPJ7)|1VjJy%>j3(QkptyY_??0ik0&s$v{+mqf*b`L!x(;Hy= z$WkHosHG&_e6aYk-wk1Od-3UD_eIU6;^rMYRSw5N~0D3~&+s7=%OG!tCq3zNFs@e7v1|2E0Aq%|Y}#FF}0q z4l4xE=l%){ij@SYV^rEx24w=?r(PVSFs9mKq`b3oJ*=X3w($CJ)1dd6OMaP)_G8l8 zvx4(oM(o(eSi@XG89~`X?JgJu-J~P%V)q{duJ2xMz~0(Y`Fcj{eI@#Rkb0 zK8F_O%UH{Rv0!bwLOWDO{^tYI5S6n$#;OJBs%>eiCxfARKqnif{V+3dv&9yZSBTAs z;{0b!;+PAz$3Y#foriwe-myu1(S=ENQyY7TFr*2lA4BDgfzpfHJi^W%9RdgdPC;Exz?KBHXhNm#=!_Jp8mfS7XRbaVT z3c_yVP79IBDLPyej9V6<(@bm3m!C?mHz1n5tsHlOcIg9lpBug7S;I5qpss&b>jm z-PJRBfrForXXu}G-C{^$fR-BGzJU)Z0j>ezK+2H6GjV1G7r9)|S#XX(9&og6YBNS& zrgZJ6&mIg*XJVY{@^&5js3d;b-{xk0?;~b>ixew#Ps;*)Bgad;@#`?hNKB9Y^#v_X z0}f_f+K_O3Krv>b4P0$es)`jFi*K+WDboI@^RfUbSR{segl{%urO`cOq@l1W95rbp z%!*;UPFN@=tp-46B2H5ue2xKTCPD)V8Unq&Ta$#0R9XlyR1!IlF((RtQ|~o#kIMOV zXspGOhd-&vUGto}37CpQ_e*8bh_YNaPbPQHsb)4&-GmKBM?&%UBlSZHvGoewqfLXQ z(Uc@q<=V>@+>*<98WVGIRkX&ugd@Csb!FwAy+l#R5cbf{p=p^gQ40qag28sgg*6Fq zC9e1^H4r}Df>kc)i_a`x&WEhU(TnQS3^JR=fpx{9mmHD$;4II1$%T7MDcqVT*+$>1 z%*=E77KJAYzAmzp%FtJlKdPP-_xoVc0h$0c^@(ytcihX_t~K`5loows>4jYmHr1kG zmTpc>Rf_9b*ezPM%OsT?Ee$u&F_no0I=18%V&)NO`(vk*sLW|LgEh)z#{>+B19DKK z_7=(C@0u9Oj2kQB4SukTjVLOHdKCUhyF@u*uld1|Qzez?R75l;|5e2#z;*`-(=COn zly7{6v?VIv$+sb?1#AQ6lh`4H1W6^5;kRPb|Bth`3~p;%wnk&-n356B123tswa__=lW4>j*Oh z!jNx(qDcMJs#~b20$zEDGy8fCqgg9-QWWD@HhNb*l|6{AC`&~9U{^}7tvpGNtx9G# z#ag_YMf~*rq-igpzLaRfkiD!upG4F;Z-51MMUQrMl}WuyQIOUivS|0JjiwGrVsqi8 ztXQQr0Hk}Y~eQY(2E$WFbL$Sx%AwYDs{3b&s?`MN_ zYGbI4ERD)eX-s6k8;3}*h0qox^aai);JA9(L7h~li19>hxf>xzm(CX-+oi9<2}Jvw zUKaPRP4{uS;Jou7QNdf=q2j)rXo~msD1pxed(rh1cqMFJwxGQIo|f1}CzCDHq_-lP z)$vN-<3q5#)(i$LWsBMF$OVVKox>NI`tBgTfg17j{nn90LWR!79qlZMs9&q5k(ydqCZXt@$nJVzjKxe+LcM^;MD#vj~ovID}l z16?JAB;3%=%=m+i@ki9bFA5h{-YmcA9M<5VlK~u@IN?!ZX~64cGii+*q_l4flr&^9 zayR?+V~)eESU}6{=05RJzB$Z*oew$=LIU3v%%+|TZcB>fk4gA+EIDJ%)-&lyqt%^K zH*_5kY9Z{={3s79?2iaw;-(D$Zt&WCmmBQ3y-0hp ziig4Amg_^F;zR=~s@fFMu6waPU*u74y@qImCcbrAAI@5*8Ej>-^4cCRe*~;!6^aaY0LLdMjk%OZ*lP7;T^_MB6%S6Rmurb z9xFo*fJgECMt&LNO?d7W;;h52E%k%*WE6c|Hgl5mR`d4b^EMQtL~9<6gR8aTO#NHqb-saW;M%PhZCQ^-{JTHkQn|K{k>jk4>f1WMXpDYx7?{*@5_J?;Hx zLJVusrqc7d?=tw*^Z9Q&68~nRsMuSZ{(~Kyq+%_<@JWcMr*mo6HqiWJt9?Op)Fe`%~x_OC-+o;pKkn-$(E9oMk1ZCUZ!9h-KIBT1Uq>cB|M*VOlL2%1)R80LNWe zu3iI-cXQ)y6k(?|?L+uU^4;5~8O`1IyhbGo`Kp6eHP6x8ko4tD$tN*zkvk}ib{kvU zv})h+UFJa<5pmc?c8258$r-H^+DdJE`g)sI>!ZNmA?;!y(QtEhoJSQ>(bVLf9?^pO zK%woUdZDL!afeW}n1HVv%rgKt1b2juek$P)m|MJIXG;e#%T^X9O7h(5;CLcdxY*>P)}He{C;3)FU#4HKw0lKE{t|oHjYpkZ zkpCfiDC{jyGj_7nipwon!7s<>G8E&u=<*g_eo1C4J!$SNSu|-{i8)3op5X^uPr4raT6mIL(YfGs7 z8%amZaGJBGI90W(t_VQ&jGK|W6>i#!)b)k1{+76zC!$zYZ3M;Pw&*8!g+}ZC=L^c| zl=$nP1x{4^S%ljV4LuhBpES7 z5IQVO66HiVOcbCDWTf%_R8*4bx%h;qnsb{$0T(aN#_@@ZMMkQ(Tu+Lnnd{N;B&H@M z+z(w3cH8dLp4a^EPY^h}JOO;>mDD_A<%4pLxMk2h#jPyBZ|1I-@EJ%U^A zt8)dMGscoUSO%*S*@r1hiKvuhd<1$;RhJ@~5c1)S#uS~Y22*LS^{je6^8M&h5eNMz zoC=#Nm6}@`2fT4cT6qYyssk>ysmA5yN~s*3?Q~sQ9%J-F2A-`FKpVLu`@#Gwy7yv} zPJ3#z8K^w^T|OgAJyG}8vE4Zu7j%R*1UtEM!QyVFsBF#xgAr4Q_RhQ0oX0hU05{m2vG7wSs$Vum`6~MF>V?PwVR%S zPz~1Fm{_(3ad&ZsM)b|Vid!&L!hKZyU+FatV*{1}te`gWOa*28}#Qc7jpbwh=?`DvJ#7}w zZfM6tJ7&^cby}fWhICv>(B1$fTyfLnI2KWWw4KX9@H8O)ZFj zCpt2LtMi}|<5-*tky)Mzv(23lPbA*prW53GiAaxmM5!IEqvp|@zSe0jFr|l0Zq$YR zs5}`U_!PfuZA_4d8b32>ciRQMH^O^i3PHoD5g>8oWKbdSmk1H{gdj1ByhU?>x_Kn{ z8SmkPR+8w^|ND&O8n5$tghyW9d`Pn+5E(0uDjzrEeGoqWatc7TDzh!zpp0INzaVNu znKT;4#B!3yX7r$xAw!>pY=OqanvrKxmTuA{?G#3iS41TKsYkWapU*!Q9}_p^h~WWR zt(XIo%sE(nL>(qEhn^zYs#nO)gc@gfyic-k%<_X(EH9HL4e5o1g;)vs^ECwiG9XMo zEQN%h_$w^ony^s#eN9asAIX44dkBW@^!2wk)JhNx)3_z-Ic`}kbB#G7ap8pzIz96R z_UutM@n%i0m_c<*E*-*f3;I1J5$S%7#2>H!;!ghkR`<`FpeoLc+RWz-unYIg7mokJ ziW4z4Gjz52H`)1rCba%dbRi@`U$a}iOd+NtD-#Q;Bl)f+Ui@&mH8i2h;aWIsPiuZbMr#~9UZNG@fZYb3A zF)Sk13VO$w2EYbhOBwb_d3!y?KySW%l|*m0q#7)K9KPiBNe|^w*}(46ZOI6o1_CwT zU%AkKE!W`a&oB|{A22=u9jYT<*ywJ%E)IA7(DmmWNbZ>*{0IO~#}Y`028q}NCKJp> zT@|_Th?d{{tHC9nLfI4d%R%BjL3hVOPw_b1R~E8T#h3#i!Gq6n{DVG-Ymfdb5QPAp|dt?#4Mt-XY4tyv+In<@PN{4Ux+XY zl2v%v%lCz)tzU}#Xc=eQlWQ41al0HaSQ&v1&WNw-+>}a14pdb>2bGS^ksaRgZ(TAb zOY=7tlYJM|p0;XTSTPGus6t2h{PXegOEvoqhXfeq9K$)Meq;_!LfjfuJ8#(buDG06 z1how(TnJbinr7(7^h@Y~CCJwZ&FwaO&(uh=)8>ZH_N_s? zi*D}mKbFjKDogB;f>TO$xt|IM~xfD1w;P7<-o|XYo z7J0@vZ5A5YYQp8krf94_OEx#n$wT}8E5f{+4!^VWV;0xs$z*a$X#8z?jFca5W2|6! zqYVf3wuj1X<=h%dPRnMY1yPU`>$s6yaRgzxht?pginHo#uvAx1)iR%Q%w|yG=6#QW zTBVK-bE}c+QF2XuODmuB+1jX*`0m)~3!W+)cneXH(|&vewgzb|H6=dJFoTNYu--Dg z8AjVMMstO)WgiYBG+VBB!m?Wjk%L^3erF@oJ!7Z*zKzOr47nd z7uM)aJ?-s)jq%hlwqBD~dzOq#hBbXvVXhD6KFiQ?7rB1>Zi`u8gYF#vh7GD$CaTu3 zSp(ceR*6Q(c2osxCcl(J!2XbWItq;O&p$ky(egXRNtL9GOr;q5_ zDmEzz4Xa>RUiHUqUhpr>kZLze`Ve)_et*uZ9{6HK+{Eo{>1=$TF^ILr4jn) z6gu4?L5AbmG_+O%vy2Kw0Yf)8!k>W+xu7$oD$=Oo{KTkTHzJz**%FC7Pi2^#$%Q$x zyD>*q9G3$&lWks)d0ZQ}ouSYrPtEJBBZG`LgglLPa=~U;_s&VEGHX^>>cMSESIU*D zom&AL`=cg1emO_z`(}0$@pwIrRC)+*Gk?Ej0=J^RAHVCGDV<|7M1!AC@BhZs&X9Mr1p6-YqtM@%wc@m^6?@W@8qSa-Pj~pa{U_F^__MRn=mKW zS3bvs(K!=-@gbw%D=hn?si<29UzOsbDsl1&@ zF7)nkYZfiWXe^N2RnF)*3SJ@bF3Pf+o^L146HacJ4q{7J$_}+l8js(E5ru$?ItLPD zxgbSPEFZSO1UZ{2Uv&*vgv!klp-y=tnGTyD&8jf{EO=8tf~nypPGPK28JBc537Mpq zy>!`5nj4}%&a$3C7&YVbI`-I=*gaayCK8>BJ44Hui1Qurl!+5)0ZRk2=)@N*Pg|$w z5zxME{mw`sM}WM;1p_n7RH}2+qT2UW7hUBLp_ME_0`@ z*+yZdW0Xn*!iT58Fnin8|umm!1#6iYyb_mGrbM){+@XJO0% zauE#e!k7ZHh;6~2sUpyAI<-w>-f)~GPB?fcSHz_OBn z_RZQ0m6I<^-L(*Tv@|sWjUs?%LYN&R2U1!=dK9S$jVnCfn9Iu%)+RIJVV`XyX5R4& z?G4)*5brDm5y6NUXOJb6oFi9KCrmXDZnCcz#}Q%*qrJ2dua9d_&ITzqUz9gQ?FN2r z;BKV=&A7e}>rx7WJ8`~7l?&{cHoE0|_>Pb%C4-XNzR@8E7R#O8cbFUXJy4x6BcV<( z%v~dJm=}zWEUGM^{tf^YXOvTdrspYjOtq*)^zfCu3>SH9ox~JT=C=YfwX)kRHD|o; z5%qFzY>5z^LRElh`%|q*Ydnv32{i53=4O*xs*lF(7TzcgNYd=y8q385yb%dKv3Qtx zozT604G`Io{6IZpN%VCUo0Ja*dDNgDT8%2B;k{N`DfPszsKwCK$dygZ+Ff!g#)K<9 z&Gx`4(Q3qMj9y|}SPO>z)N+De?8?RblKf-*_O9=3T_P;0CV2#j@oP4FqS*>-1|qe@ zCBmeI)$#0!h`Mt1&1U9H7c#!Sl)m}J5>jy)mJB9oXX$Sx)m59ZfU}?W0#g-LYq3L} z*tTQj>H^V<7A6y#CPQ4oZRDmVM-tYm48q?fBJj&3A~uzYO8riU9A(D~!RD+}X48vL z7lQ?_$*b=p`MF`Potct~Dpdrx+7Qj7l_c^jm&&JFiaC@seTje3^}tz~y!|;`(AOEn zt9yS|`m;=Ve$5hS_fxeAFu$CV(RG>^>4l-0ic*-TEt_XPHpiW0(Kbi0)xw!@q-vt9 zu!62=pwd?uET?2;Urg4LIcEiBR|xb>3_OOpJ-`^fChgKTfqhz`z+NYmS?z+39a#aA z2u=I!e%k?NL;XQI@(_H5Ra1bTuB7pWk)}2af56enaNbv1ZMUC`_IBOEb*HQvC+)DR z15S1HUFV||9YAx+V|4My)?l&`=6ozmp9Q6f?LqE*{8d@|duII4oO!(OjvMl`vi6sR z{(n;o`A=o-bME!;e1;??-M{z@eDle6rSyYJXP?=!2bE|l<~ADzz(7a|w*dhrcHXqY z*xfw+GVx2d6beE(#k0j;EX&p^gXJ1hQfL;>!%?>PG#5{|-;cMiJJ=j|K%fPIChvVs zdcPKdH9R@< zgs2dIm*SM!5$RjnR@9805ceCgG8r!a_8dQ1qJoC5;ec}pD*C>PDMkAdPprGmO`_&~ z6s(byE;YVHbum^#3O%G?hocWJPNKvhAA$WMI2*OuZRJ52uHe+{A)qGQ(2?DcrSU%h zykrXx1T6PtJ%8+H))=kBc7KS$qnu^bPvOB1&yQJ*W&5m0k?41+eN|2mTY00B69o~a zL;Km!+h0Zt{C+~UkX( zJKgO5Mf{{lLx@L^vKNw=pJOQ)M9|i}m3FZbX2R;$q63D;JsTZUrw&0X8)n+-gka^~ zT`c%yL64jOWa0*}|D$)`jj%SjYt^vZPW$}P=*^OOFL=09;> zp6(@c{M-RUf9`<)pH)fzJx%>TIRA?^@^6R>HDG+u7V+Qp-0Bl9z7mT-6TyPyALtcC zBpDEe=Yl8rljY4?@z_v|_FPT1@!$q*EjHIQa$j<9)TxKi+H zvtqYNY9mH{Y`Fa3zWnf>{?@U4!#moigCoqWqYAWo83-WS3gaBz=NzAG26u#ZxA3q= zYV^ohxOHpw5{KBLw%j7uN1JRHZh`(hhNs7Gf(VR$4`zeSNN&##;a5D*!$`fiH4*TWBoa9dapUPDSar1w z{EnnQ5F}X9AB00N2P6+L=nK1G9hwlN{2cshUQT7|QzYfbI0B#(T4O>-X_>i@ktF-Smf&iooMj(f{I?Zrs97M0EnI|Y61sK1Wu z4)@r8iJabEGaZoucDh2q%4Kp9o<8U8HV}5j5ufby!0|TKBASpM$&$-sRiHG7u104_ ziGLds<+0%gKU}x(Gta95YFoIAQIZ97^_>I^_`9zNNUiUlh4I6DiH`ih!Y@-w_~t{H ziVs0Zt&H<3bySg5i18T*r`n8Jvvi7&n$l7P4|^anqS&9`jC*YVo}YDUg`EwfSZ;Qn z=P+h`MG0p;P%yM{)1FMFV3oZ^lq^W5s)Wm60NR^57mdmjM#J!-g!eV=;xsxo^#vlC zZQ{uG!gOpHUEN|LDnpWXZw$J~X(3q}mb+-fi5$jhaT<1yZWsTu%zAT3tZ3H|^T>d^ z7nJNq=X-;~SfK!If%$P!)(Y)nhx)L>Nr*U#13WN$$<5?PL z2HaD3aMAdErB?fA8|Z46C&)j>+cD2f1R}`4IF*+TFQ_Dvx_Quxod3da1GcwwcCRVVa(Jf~%e!AxfM!cIC+a^eVl{W&;^v$9;0ol2noX2yd^HV4t z4L>DMTwDN>%|~;X2;ibaOxVsmkikn>38+4Kr0FW!KW`Bk<^;;(Z^u_}C&!ADO_$lZ zqA$)~afhyI6sId?@o8bkX{k^DY%`wLW8JfOjETA4^X9G^Q04B5J!j)B+lPA0?V0m| z*0rSNHliR05}vM*8NOl(7}{IRJJMIp-zZ-!->|;w3^M|ym%3y0C4>B;w@)7F3FdEj z!v8!x1_1=l9#P*bb{VrNVP2b-6FkY zMzj#xilhKemu^NhNrOs(y}pl4u`*J$rAoqg3t^Fi@X{jw&!uh?Uqo!Qla@7OM*i*! z9-+2Ws|Xxe)ZoQ8nE6_jN0z%D1UILGP{s?DPB3A<_9i#ChY3ZJ5bVQ4E<=%dCq3gm zFG?N+Ewc6z_Cd~>)~chcuBl$Zro*YK-dx?RO}a$?B&X|qR?-`w$6D=W39V4+sZ8NS z!M+kXdDRf0+&q5-;%F&8or?x*iv9x=Ub_Ow ziMN*^&+^R%WuM3`p57IQ9i$Vp5!~85)F4VmCzcVWI8|?YI{YYZ&{4`NpH?a zb!)x5KK8wGik260&^#&%Tr~Py5aEzfZDyEs2R)b=nGwaxMKY7$8vqrXGmYKLJ`=T= zMLNccZ*WSy%)N!3RJ)`s%}bsJK~tLyE;q_4XA{{R8sO|&{(88fGqZe0!3F?%vC@--&SXsGIgaDKyrn;>pmZZ}KPc_4!6dW|*Z*@o>b z7Ftn!=wuJ@6f$9pe3|9CU@M+qB=dt?U}t460F)N4m0WtYibk&!y23g&wl3%4I29fC zDIvWhraZi`O@l)1!~7_K4>U_3~v5x2|F9;uYUoPG+LyYf4OVya00 z*~VL+n;7U|C&358Fk>s`LuOTUraN{I+JAu;Rkk31KBLMdV84GcZ%2xQU$DQ%UK^iP zOXZ!4d^c~%&XI@jk0>OUtpmfgd(#?n&f?;sVVLKgxsT^UkMkPg+efm%3YAy=<@ZlO`8jk!G7?sctfcE)xyD`hy&jx@%6 z__lUOtypnfooC4%Qz!WtLxmGgl5?+41>QzEEJ}2sE@r+mUbD@oNWMf#sA z{qM#lV?Q~!W6O>t>3G2>e_;9P%QjvU&~XQ(ALXx7RhsztH!f`XOR=#KrXz{5?$1Oh zHc)Takqz-}m~IdbEsFRdY-8lSN>(fZFCfg-ZR6y2pd!r|Lb8>Gz`cjaFn;yK=X?5T z{@PDbSYn(WjaU)0@@%@bTll&iQrO_WN|wBwISN%+wKGjNHI~vwEPggtv2fhyPzWnf zTDZ8*XYfW(>2UwO+#Z&8+@a7usM{5`9GoMWk@1&M))#zw_1CF(#I>QG+b>ydM@XR3 zui|#Mk^RL4^a(fjwBWK6-Ze!u8nSR2^3oczxn(ZKF`RljMRo&Min71GQ$)Ucq-C9;cf_S8-fV5B3o>^Y(_RWB#zhT3_0o4&cw=+bVZP6g=cMr$4jGgeFcncj$3Q)X!q_= zMDY3DYq5~U@3V}Yjjl@N4NH5X^L!7Zb#`BbCXZjhw>>6D{Z}KaeKVu}|*h z)!p&#TmL3}wRubEt{&h8YpVw+26(}iW8&>`h~Jfkw>R^E>(|C6fZwz4) zDIOfQHwDcfAg<}FG+3M}Fgaze!aGFktuyF}{!8^HIAXf=u_J;~)kkm;Q`ILt^rFK*2 zgzadBYS@v?I#b>ub-l^jY=tUI-fD;6g~kHaT9Gf?nt+ST*ogvCMDhG+wnju9s&B1e z-s6cvY#=~J-^)QFpj$u`OQJ{_cl1KG$an$XtvGaF@{C>H>^d6Z>yQ|_h)2{aWUPuU zTf|LSB~vu_dh~GiC52f@6PtUsmGa^BIe36lJY8`69$ z{>Er<%t)ySX=;r9nItgO3;_8um_iv}D+A!n6X03m;&=|N4cn#_|MExJi>(^dc{WOyC9*YUsWmg1srArF ziZM);-;|CU30r%bU?op}RJA;7wd3_f?27BVBA|W@fhKcCRv8ed4u65q1|5=RFJ#=RH_}Rzc0;5w7_?0?y}+ z-Z^vmm9uLpIf?T(NfI4%Y0B>k+r&pZ!bXIy^#rxiBWcBk=uBv`N~4%-_pLeGu5C5Z zM8;Htb$b(A1m%vhoOTQZsMf`wJM}ra1JU2-=#-mTtOb(vgC^&i6YRc^;0Mcvo|R>_ zv#Wf=OXuS(EC1#c*1X5mk9<|{^YvI)P}z2WqZO?|=jy2lS0;sAk!LqjTkAaQrYMqc z4SU}}bb9`e&R(bCZM(Mn!bgNqFU=e%O^B0AjtPd$IRIgqDq{1+)v2Z%N5L+7A>*dC0C4JEU*zM!m_d zlRD(<7(8X1)NWf$gl~fnG7lt2iw@r65hbRi86+5_n#klO`KemTTIp7kb>e&^ZVgAp z!C!KL<#LZcR-)nPdw`~T1p<=YemLl$KKR{`;PiD6#=gk#eh(PEGYZ=A63$^cZlG-c zHb-<1OfVi>rW?|49AXxgYGex1J$9VYnT{b|mLu$ zTEP~T5gbtCAs$shZp3Q5fhQ-Lyw`YknL}eo8PG+wR(BQN^~17K&C#8URm&Z1F{j1d zJzN`3kO*5RIB9i7F`Cjap83|MV{6=I^yC-OTQtgcmBvd-IGwX!)8-V1D+(v>#CS}l z%<=1!>w0i?DV3KNnXReeI%gTu=2Snwrn?ne9#8z^I-xa&V($_pv#Rj<;Xuc1i%j_P z=MQ1*8?=jD{(8s9(w3Ru$x_(-dC1k1==;&cuFpdj>WgJ?DvHpV)K9$pV$DwU46xct zEH22BbKA^Aq}()>D+I!6T5}&S;ExM!U*PUdo_?C!4qNVkZzsm1Hvgm9 zfNv=W(fV}tJcn>V&I^8dwtrbPcEii-hI1z=Z1>yV?*rF;G%p8&&PPlRn(^7<3&CzD zP7dl=u+;i!%RCbP)*O;%qQC+Q6CKOFTZ-iJ_J@UG{P@Ig8Tqa zFr9%*o?`;h>S2_>J3a){Z#Zu9T|yrL>TmzjC;od>{%5@IdxSrj`m7~if3h_HZ>vvY zmZml)|E@k|eKIuvDkK|AH^++R2qF7`@LP-4=Z9>PBCapL*GNscFRY zT38Yo*HrWA$c_Qps4+jqX5CtPX*N7dmwOb-HXH@FJ zMi;ETsI}rM&gaNx%Ed2p&aj{3$A_Cp={EXx`f?xv6I#*QWIsqe**>U5?i66C4}K8{ zKev>Ys@X=;0L!WrEe;MxrWS1gJxQcB*8C)rT%vkh;pf%Mq0ZdD%1k0{dRzX1 z1bGJ2^0M(Eyr69b`5hOn1d1dK&5d$^@ML*1JO~*D0D(tIytTlget~`RVrB6!KhXW` z=*DqIA=gC!Ndu!Z8-Ei_Eh0Zg$!){=1y*$!;N$DRDwJTumdt=OM1uu$-Xn*LpNEw~ zdC#1mRP4X`P|gT8MV_=ts^I0TT%z$wHh@>LkGIIFLxFbgehaZ@TiAO2*M#5S z7sNl8%3er}q0?t-JB9fFCAC%k%O>|f)o`^ZXVeGukBTbY>Scq(6$9td9e+A5wE#5A z+Wap=3Ye=32P+^6fX0qEOttp0s|cgdBCTZthwOE7`qt?#L4&K;h@Hg=V%F*B<758R zCBCb-?Ogk&oq`3++`LcS*tN~{=LG~gQ?PFgDEXQM4@t*wFK-Doc zSM_-oIn8EQPURXKdS#{sTuv5rb5Z{3)(`SzT?mSw8^nAs_j!N&Pit%PHMy7A48kr%Z6i`oXuX+*aCS_jNw1D!%e-PaSNQ{D;b3*-y(N(#_^T<$bNBu~E zA-bUk^nLx_bN@0cui|1XSC9URB%lN|eiiAJcg%)$ZxNu~Lx2$IpBDW~{j9cNNByxe zaC@gYQSO}0TZCoVW(c3fSnRvS5f?Y5M?_!0DQ z9<Z1s`VTWR!!tEg45ol)Gg&SeOakAsJh>R-`#E zoRP>4@3)Ik#_jW1tnzJ%I_Wt7{qu*%t!cky~qyjf51=n@A}!Acc>tPhQ*O@t`b$g zp(CmySCQ2D5DqnQ!$ZXG!yxWU!b4zD7>ZbI31eM?sfxfD^Ww`@S5iI`R+6|C1KJ=A zad@E1QF&@Mh2@{1vF>L)|DaW#U?z3h)HlG!nZV1>)5z!-4?FPAyxFe}Tli7D$xEDi zHzP-HNX9;Fj{{=GxJlZ#dz9bsr+VjehFlSTR;7dtW#NIE zHgU*$G0@W2@1zqHp?nDsv*O=s5;nF(FRpv_o(00drxa9%EPoA?X5+%dZ%aFJ3j)Me zEBqPsqIbx!`J}9!3PnAj^1_q@fdcRm-`@10KXNhYAEAdvG~Ft{YY?Zm@7b2G)J0UP zHWZhwB)3OChWv&l(5gzK^bYj3pd?t0lKUX$Kclv%TwxuFyS*Wbc^?I@obpoS68C;i z`}!>_2Q}tTjLPe-f4YY_dR8P7sdU)F?B4P4cU`{=A{ve35_jB~(Ae2&{Evy}l|GIL z)^#^p^liPt7*VykLqq$+3+$@A4Az-((Y8y8L3b}W7DLQmm;4D@g9Nb75hnNXt^`6P z-@{M@_~N(-dpXl=W3S7NKI*O!jH~9FEx6w$9&Pb7276C`-|CVv4!o%SeD5;Z8?9w%`Cmw~aYJ%6;+%^1I}EP84~%Yn(514ug0NxDg0kNyegXe!)HP!BrC5@*Fy+juDD-S6UcH7d+pF6^G`PTW ziE@XF@hjoSzqrSL58M9?=+mfC;*6h8w^W}2o$0^Ss{W_*Dr@RuVgEnLuiB|Psyf<7 zCsHaBKvYGc0v48oc&DYY(MU9>mIOv2NMj-S>*yD-Q5kO5TB8Tw#uu}PKN*Az#>R{D zhtBdJ1=-nKoUDd0WGGXacSl`3*IO^%5AR#PcMm_BKfXA8>3*CA_<>Nq0u6FdD#L)p zGzK*&=vaIGHH5Ky1%%8|(BBUGsW9c?JfgaXeZG`3V%fF-B4LNxc`Wq$Kk~pYs?)1ao9a1EmAOhWw$$agb<44H#9xOpBWy zR~k}EP!eIUWB`n%au<%O4JlxG-SQL04E#xCE7Xc0NwZv3pr@|FjX;wh!(^0-Fe_ck zToA~Fn{f?(RmD?dU*r~=0)6U*^-zwNitssn4au@pcS!7AFQ$Z6w-s4T?3J++Vir3H z|76&cdg;i;i~+`utLCg_%Ns^xRC8l!mKw5&dQ|I*PLpj)+r)+fBLRl)mJZlB$wukY z#}0q0s4MyIYA!m`pH6jxQs&@@WT=;jR8tIviB7&qjIAZ2)x)c1?5#?#dg9HRqgOhd z-I1)6kG61|joz%5WHzCa@9@rwv%iE3z?%l_U_<^Yee^#sHj0+_Q`ygh=sbcn_76juPgyuN=gbwKaAE=PK`#rD{?C;T?Tl;ku^6V!(EA+9B;vK%qHD6v)A!8 z+ylEh%mcmJ@zfQ0^V>-MZ$KE7!_NQ+EMELc&@HqZj4h0tuUq7{Kan2J+Dx?onQl(@ zOKLkx_*?nQFRqW@2SOhudWK2(dy7H&QE#}q3@r40i*o@=HaBF)foQ58v2g1Eh|X%4 z)Qh`5&2KCmcm&sk7lei~O>_2eMX$xA%1WuvlLX1ht@G4So6k=)?4MPc^ld~O^ioFZ42tfL zcTK#xKgUQfEfwVP5vyldZuHe!#KL}cOZT%dnj0J~ub;NGGDB3$x}bh$7TSw`SWW2q zp%{C*xNo@1k;lzs(IDxbNCiKfhOSlPc_dhaSiJn7?-hn+Ywme~QJW&G)j&N`TWoI2 z3P-h{ru1(S)x&n_?Csnz-e0uWti^XxbVm-}zKrITuSUKcA#cc|Y)Y`*J}xWDaqrl? zAS9-I#6;BAog*0;Z=C}N>q?@6>wx-Vt|fXCdC!asI^?32l_k#T?lpE7U(aCfpPvyl zZ4R>Sa)={`=r}e9js%W5=R~x>;MBlGugDqyWb>|p2(4M%QV9YZ++3hAx(NCmof~PE z1bmIm@$Yvn@PHQAc@=1Tgo@Z_e9&`rNJ-J9Mz@C}UKR9kk6#dz+z>s4qwC{gigo|N zzlG6vPAdA~(bOA*ky6``vne*wGJC zO8y4K=a`ptBAK2`CsUgF>;rx_PW~Qp{uzv7cthKEK7&xiC*A5Vqp1HkQ-%L+oczaj zo$S+K!P(XJf2?kk zwbCasan{wu)*24J%cDbVj~Kr7)BlB6cXZe08ezUR5V?QbxvPHZYT!Pfrksg^2y~^r|T?zf_ljbISLk@%sU_?@zZD3TSSq zoyGSPW27fV6F#yyUwdkRe(ElnQ4B+ZaiR&&Ur7EPuYV$$5GG4}_=#ZdCz5>szma76 z&z@bb_b-DG-}$A2a8>X73t|EnKIjN^MhHP9Ubf#|x_}zfc9?eDUcYoGfu2|tPA}>r z%+P?e2M^Y3U%$>DUs{IP1`Q*Og-DY2D3I(Tj~jiG`Xsc&Qx?-zQ~#vh@r#aNwAHaR z#K07bYEBtlqhmZA>i+t%LOF@)dX6Swh5Acwycv+PcHVPUhg$rNc%#INv}~jn812Rl zt;&NjHgc)fAc)K8b~Sa>_~#O^sS4jwFP~ju%E>wBeLs6Fjg65+pG{QiSr z!n)GD0n+dXAzy*)d|;!$lBnn)!OsyvMK0+6oPLd)yb%a@Lgr)xFDA*X0M1#=9ROUG zW7&Slr->HVRZ0PK@|XmVq#I{@_vVGb)6@A2;+H#(gxs8;BCw*^`q-{tj=W195Y&*+sOzVwI8%YutH2}`c} z1)1omS?mEF@>`DZqsQ|dmlC^W-(qmlKT}JP<`ab)!XTpa_8CKv zVkOm-?4Ts0(HV>OnnuB-^ufVq8>k8r=``qUOHWMSs7+j&jSo60q(+j!(T4Q>&~j=^u_~#A|7myh-$1x!o|!=F|~pQJI5I zfxE(s$&pE&b$1=#B1-0Mv5E2KS0nX!xpIhF!xX>4LaSR_5vgqeTZatoE+2DW;V6=C(bgP1d-b2=Aw4*M;g?_4hvd-|P+{JRa~P z#rCm6(q%AGh87U=0DGYDU`Mb+IZ@cujcuqiS!ElRIOilz$&a^Y)gLI{m|_y*wtc;J zA+;}$V|(}7h+)?Sx#?sO@W4xB$7I#k8~^;&KXnE5u3Jp+t%sX_|2A%PD1K)AnQ7u0 z-zTeTOIK->uXX*)en!yd=8&(_43Acr^xpZbwjqJ(XLW~{mbFGbcFHj_KTKSvV-%*irdRwds|hF5oTg%x*?(Y=X1jm+aTVo3vLG zs$U9w%G=KU79BDZkQb&{{Czt6N)>gL%ZyKD&mUe@ZR)|}=YuwuW%g#DviH^aYyG+C z^U4RmSv;dwH{y@%F5i>;q2+0$%}s81`-N4s{v~-%8gE!_zc|=!s`mY_XaAO8Eoxa| z56h;!zk8dUo7HTpt^27t5-9)s<_E1n5hLnBy?jlrCoel%BWU8cOV{l)z@Lw)5-y0;#aS!(S0)_Jn(eX6JL)P`CXnud1xoy_Gf|s`uN+ zMzxx)3l8hwYccO~>%TA|czIkicOc#*^9VCxZS>KI;O#6Fp5^Iji$a*Kiu(p?9G)zl zWaI!>1b_dB+j5NLq6e3GTQ$n z1}9AA1_s>GWdt4q;=zF`VNM&=nU#a(cqv$xnc(`~N|@mhpNDfIqV{tlLwBJXQp>BA zp6e+d9?AG1PUUGwicbeiVPo8CG3;|=2jCjKm#10K3JwCtSq71 zws1W5JMcu0EM$0K6K*b{z2G~5H{VS|*)g0joZZQ-g}%@xWCnGm&-O%mU+SP9jVw5x6VP zZHW%J?NC`pq1fVpyTL$~4vhCHK_huncc6c9A!dj~{2vAzY`~KM4~$wgY7LeUE(eT% zG9rnmR?+hTk>G3l;pd$I^&BwM1`His!Q=-hr4!7X2p<-L2n`FAqcY@JLb#S1vY;i6 zB)!7Ym2+(UAm8CZl@~SVFiz z>%M2lpOdVHnWRZDiWp~EFs)#FfEa>h$ADHKbEAQdu!L~ieaH!9hdm-z0(R!b zuM60t$Sb**|VhQ2i30xS%>;xqp96kk! z`X*or;pT>sgNxf3@>C#N2R=E5FS~aPIXq?^=wKxg9Da+9FZ+>0EL-b8iBO zRPZ(+zPV#k$f+=sL7U`6aCjR9KON&~~t~ZQHgswr$&X?gkrUV{2m@H?}u6HulE4@xSl;`9F24x@M-Td!}bj zpXcfB`F#vgdIN!@A`kfm9t;*17HrGwSnU=2Yok6G7??#Oj-WQJ?9__@)Fw11q@Q=s>~=dUqba4;~Izozh#XDh!XlQCfd zJQEt62EL+7Si?0yVo3^?ciCO<(5DSoycKrK#{`bTE-*13Qg&=%Y0%Zs;m$SP+WbB`5hl^>` zQ|EEzv4~>&?`aishfRmh@TY4VuzbjnLG77&xn=o5nU_6f0Fh^mKK~u6`@;1YZC0ZJ zUxWHdiQaDd-N1mI9dQ_KIoh9kL(*QKtIWw%0N(bqovcu0T=>Exq(oK)P;h(~mu=Yf zybkrePq5M#CRIl9UBzKnrUTnEYmjWXI#1Tbm`wGU#~G~DFmt^^$c z@T;6T$x>+<_a%_%+T}aVeBNDxkd!zGuYC5Gqb+C{-Td0ty) zprE(pYLOhFIM?0X{oWJ5^C|J`Xt2nUlYr5=7alufaHFDe> zsM=bN7jU}6fFpbaw?#}lIR2=-ponL+G(~N|Xfijv0vZ`cLges?sD=xle6qHTv&~Mp*k+fuQ^y9{qQ8#b(%a(W`SmCud0wEWZOFMd1SM3@ho;*= zZx;XF6(u#>-@y*$m{F{EQfzmZi=u3@1J-$0k0TpNqjewKsY9&|P9F@&Ov^h9cH}2L z@c-KEv88ewNxS{|Q?ILY&*fHRE5AnC_wNPBPxc`ic)o7STwx769(DMBvoM8SBMCqd3f!K(5%=C&~8D=Y8(W;L+JSlT`YBd{qgTh+Lc>Fwt!!g>Ajf--|R~ z9Q(Hh8oU7B94M9nW5sE`Lb&7C)=dGAi5~HfsvUUQ;!y4$CuIpM4Iyh{ESEbln^aF- zf)P05ney$i-k;$A1nd7^^M6D1|A_|3YRu={KenL2zzC7Rz$E?&xM=?qa3w6QOg$Yu z{*8$xTK3u)+L&87=n-MyXu%MAg~IT=Tzf?=CKb^vc9F}pt;@pUtUnT2F{m+6t7;r; zYD$#tH!MHD8K3G^d#s@t2A%6&keoQ5HYNmGCy_#6pG9l}pQibaFS}=e*0&qmBA*Z@ zC_O0V1ZJiV!?JuiNrMbzIZ_7wnd~`8=CFX{0UxZo@24oyl%wxj@rdi!|j@$I3 z8?%#av0;Q#n7F16L*<;f2(D=AFJ`95H&D{COhv+PiFU9@|?G zB*Tv#r*#Fq^~l`}b$(Twh&WZDY&SrRDWTAAQx!f}P2%38LRLSG{wGDXsL&>!BK+Rt zMw-2Wn|~3`1D&D#>2e0PcL`y4V(QQ0`^j_!Ht2)IutLf=UWm@m(Orl$jXbef*&jcd zf+-~LPFiZ9v?Vu7)I$B%F^ojDOhPpjdW1RM2Qo|tq`!pZHGO@pH1mI0sxkrCsn&ml zKv+UCLl{;?Ys-+_gwJ;{ifgB}x6&W0L&4}K=TJJ{p6aBY7g#HjFLZ^*v?J=srV#^S zlWc-$@z@0N6e$z3r0fpHO2QJ;Rzkq3p$1$9&M9MyN)NhipZzY9f-RuaJ3aB-SRFFW zYw}yn^uyMw$V0fXgif^PXd(dSCt5DDk}QwON9>F=)IO@Zad_Hoo3UQ23No=B9D|J3 zjkcjR7E;5OU4w5G?IBf+@K{%SmC;WJE{e!k`;b^9dmSMO8k>EiDKf(}ZgNY1!EI|eo_ACcFvE{rs=@)Kh(sP)%K;$;FaWfupV_lMW&y}-c&|> z=Im8vJ~EE>_o}zuiFbb-%)<%NJ&*SMC1eoG)@2#L)ut|Dr9z677H~7U4zq>*oPGq(A6jM%cR0TGEWbP}c1ZFiypsw`aOrJVlm&znb^0n;TcI?wcNsKIOu3 zoNW@?gJYOsYSpQ1G}rtjKjEZ8=jh}le%~;?)dACY zFgf@61ZQ|(1-}7;Vaipn2f#n*55Df_k@swP`~au8xPu+3#1fSH8iE**k^|#R^x~keuqEPh{8`Gh=nigM9LcFBfj>@xG@oUhBRG#LM_i!PAEU{6 z#z2bMX-kWe#c;aIB-=j(sh=?KG4%UE07Cbtk4&hc zLbpXFs$FEYr4e%CmFs{=f14}2*Z3p;^KTO+r=*I-(u5Sf@-=zhuc-!BucYrGNmitMe^?00x-sF!=4n=V-1#CcOBdj#-Y-Atm2L%jn^~Ljb2c0grSIa01tEiVU z9O5FcGV7HkGN;V2F_vyWW|aLTVA=zFDB)+QW2*;t0ezmjqoVSo@%>t~iqN9c71j5b+%mazIlBPRer6 z^O7D1Zokv|T;8aIc0kkRj9kBNpp~_gXp+C9{je-zKtoeF3*#kwBm=-}`eQ661wnOS z6wnxy+EYRIT^X1#o|f>DBD4WLeokTh-l><_E(XhEYx=Ts?qkUv?(*uM0T(~B6m~8( z^Iez4w?ii?P6(p#d+9on7y(hi$R*F?k0p!&$u0f%H;8}y@bAO^eFvd`8O;CL*40=I z5i}DH|6a=ddr3T5RgX3~t_BuT)Ws!vmmUL9qSC1}#EMF2>;@OsmwQ5Y@(qGVLlBFs zHrnRvihwCpOcJkKz#9%0IuuEtG#PhzcnHL9s+7Qfrs3ojNu4uTJnIaqDaWu@bf%cw z1ktPecN=Fw1*-A7fLccC=G;SN&Dd5}C7NYtbBk@-$jw;q@T$mlfs5*L>(bMosQXz! zlX;!}xlF+Ykj&9;rgcG*%ZDa#?nxV|W$~HZAcxk1$Lr8e@0!>1m}h^t$d{eZOaW{9 zqeX2Or2I^>>w|;wJa9ux=NoTAt^k9qfMQgTSCUDJr4WK^s>u4uZbGCR>HJ0e1MVLe zu^Rr5AO71#=>L-8m*=P%qra#ph!_lv{U79$JR5}#fb%iX_WVfT%;Lcp8jtT9+7Hv2 z-W!`AE231|8oNjqmD({*DVP$I?hu+qgdBy_U*yL>nb2&{(hs{ zRqoz98=HR3<|te{m_E1~t{gW0BwG@snr%FPl-}};Fff$2WVrO>mCazxra__-v0Gr)}fs=lc^BrZ6JCT-aYqB?A zT<;wg#y3k`{iS*00MTp~JrKj;+d1|d(ubBeNFep?N$x#V?X!GQgzjNR?mb4$SnbR> z^@XS8!?5C0PTV9iQ;R4YVZN3h#X>V zA`a`}@u(|RNzF-ex|MdV(rR}kJJoWYxVxKjEZr*cr!cL)(aVocD*!{Asts^9cMrSf znMKWyk3vKGz6$TdYf*ORWYa6hcYbG!ID%VGer`?{I>8hq(x!ndF*kCR-8lucb_OnZ zE_n2pK!q6Qj_*&)(xiF1VKmEuZ}en5-mk1RvEg5&P7k5etNh|NQb04;yusJ~i#DJP zC(+jB0v2e(bLq@Wp%H}#$w__GkCTQnWY&6MtFpQBvMq@x^IhC0n}Fj}@Ez%eh}x+h zWyAY+qTOE#6@m)Rs$J%?b0z>C!mGcA*KjfKnH4RV?C89P!}Qnpk8mSxTcSldp8*LM zo8j5-v$W}54veQ*nvgf3WYkrRyG0#ersMVJLggMi&{cc1_vn0gyL~5>edJy_Polfr zAw-GdCjg?JQ4>j~Bvh%@p&Cc9F{5(Z&!x?UMss$X)*yzxqZAOu%?N-G(L*l{_~k&+ z)1pI6QnS%tOLBJy_oVQCj75VL0>mSZ7gS=>Ww6O6nTd^?u7b4HW!2e#Ug#-Ei}Gs# zRt*PXkTS|AUfc8-$aHoJA%QgS7@n~;B^LmN`^>pBshbNWFQHDx{n;K<;Il0|NoM0r z?Y>N_4dBE?&pBuI6o81X0{0634Y%&;! z^g5VW`!nLJ%E}(JshG~l=QxSCi$&Uz6O&H*XeWzF!jcAmkkj_lF{ovi%HD~*-{XNL z$7_xWY07YDnbD(4pxs4yu~j=!(p^ZX0JDlk{>)}8&U_)ndl;%Vpl0|P;Xy_fxTM+; z)NB*o0RY}w%xN&z9prjM@E+*Z>168;O-ToGo~=UUCRE;}X>+2@Fktm+%f?tl8$B-Z zA6RnOmi@SKByop#2;}N*$cH&I<{)G0i7#_bwA$*w;X3v8G~YjMmdCr4``;hrhW)y48Oy>DnG`Kj+PW_0Koc5e)8@YiGx#cwx|yjIPAz?n+`yZ z9Y4U-d=&I56fdg4eQV6o#@q< z1}a+xuNG@_#Thv6OEd7hVzu4$Ezq%}l`EUGg%WNqq&>>?{lxuT4@Z12wjX;*GmW}jm+ZnSx~=4Tn|vu)SEK|$e-+6pI*^=ygw9LCAdn_qgV zrPcgli?s=-(&J3~`_Yajf9&2Q^Z(%g0Z_mv-o_2WC)&uL^`sxg)QCO~)Q}JUEkwiD z)WVUd!`NqZD7$2kGvP;NJX8~NEc!l4{X-!({<-ayKVmAOKZ~FX%0jsHUQkDCBCKnD zt+BPq=w^*Wx^8SV$1IvhAuEx?aNi||Cvr#TGgKVXJjRF$`{f-@JJUFS7DOQ*09aoX zsY$!@VmW-ho64{`ZcN+i88SY(?z7^(S@>hh%-h^7XU(k_&ZFzTT;|?jeu&O7X3Y_d z#)7>C(bl3f^G@kw6P(ndLTRYKQky#%3{v5z^NITw)ch)Hv2 z$k*mqC{9h(#ov{r#ewcnrWgA3^+j=5&2|ge7kVRyZne`46z;n=SsC# zWe+`YI4m3XL3<@4=!`nOLm7--h9gK6gb#eU zKHpcvH6~Jjd9J|>L~aX$AX+#nL2py7(|9e-gLldge_-Ud?vQm3BGI(i=2|Eb=jZ3& zXF1Q5S~OlxJ}dley@%@Ppa9P=tD~E@z#gJMiR1j$6)Aw+w*4%4`2z6yH7%?MgGd@H z+H4-F+D1T7pB|(%TZS@MH5j>22e;mo07%#|h5if*f6ZtBu%Ovl69&)(ZphTeftUk$ zDgt$!k01=@tlqYYTbEtvm;TP(#ppimhF~M-?${%N=gc~hAhiTQ5B$nBPDAQ$kT<=H zvWeoi((OA@56P8Tz@ESH2zSe>#E_>@Snxq$`s~U#ab=i;z0{e}e(;0Ln*lib!#`EQro0KD0)wInGyc-9Y>KtPIX6CQmfj;I_k|kw zbM!<%0SL%>4ubG*Xy2N=ZH+ms&WB z1eYz+D)x{Ez=yv22@mh-+(xoBsJj2>YiY>tqXra3MXhy1T}T8ZOT!13o!1|d8WWG{ z6z=3KYq(GK$ejnNRAyr<#nj)G^kn!)oh%{eH}7|w$1^!Rsh{0VFHz#}%@TqfRoe~* zTCY8QOYp`JSJ3zc=`LScwI$M#?#ww|a_B;0&5sS`PT{KAS(-C(JV%!GwaLZqN1I_~UIir7cn zET_aO3>=Uq#$_hH&dg$;pFCD|YRa21q*fU41F{$bn!6^tr}-}B$UV2tHJ4^Zof<~> z)gO%$@cjdZsViUB^dk_geM*kuB?ejKooafi@)z(@eg|nMB>di-gMHIcMe#v{O=wj; zl(X;dLMCjryA>Qu@b?PlJ7yMz;vi04K)i8YB&Q_Hu4kNqIW^kcczH)yvLG{UUQ>UJ zHnY@5?npZ82gH2DPxqb21;*JOEBwu9Z!@S}z^U2dBU^$uo7`UPp=cKWL!gTu@Aw082T z)E9kY(a16?wg4z0=y{&n5BOz+BmCa^H(Ef@l!}Ox6ZOk>F3#HLmut^|sM^1LjQl?d z*?)7jf2mrXWO^~{UnYwH0S3nNFID?n`2#37Jcd= z^rr-&JjUu48yg=h?B7At%9D_V(*qG*AOqP)g&z6#j zNoVI85xy^G-Zy(^)|&yC>%v&;(v4D8L@{nY_v!JV-aG4~cGj|i1V%VKYb*6|$_ zjZ!JyaHD;E!uOJUyer%#Cqmn2NuE!#MDY`uq!pVi*)0=VOP|0PzvA?w@HQu{9MjSo zNtZ^Jq<}a}K<76hszD=xNQ?;$2P@;VBA=Ao^&4CKF(FIL80|~9a~;I61X~~Gyl0(3 zcM>j*z-odkvPwi}XMp-*>h7J2M8uo=lMXcJ>&ud0BJD>6XelmTfkoUhS-+6R@9T#8 z+K^cemftKh?&WN@_et^T`0tX)h4GV|brAGpY7RsIpph!ugH3#y?91xvnm<|DGxPcd178$ z-H1?Fr2~I$93fyWC_8Qr`pb`Q|C&)WS;L(i(MdDU1m2&UAbcX}*G~*@|Fb~<>nk8J z{qq0kn+WM$lw{z*zyxr>z*zrXpvLK#e{(4W+GrmuX)XNR4OPWTSXmp27L(JZiUq^2 z$?fsU?W?s7aqf$bI`a1Z`%ASQdVDaL5Kwwfa)o426I(9H&7u|Rv?Wa1bWefXPl4%b z=vH1UjSlk9)d#PjH{YiVfunbhyO}Ouzduu_FyIcTVW?RJ5iV?Mo9yI^_7RE00G}T( zj}fk5FrmC*$KS65HW~Mz$ig?2!*4ze~HFRa|-Lh*f*t>sg=wV;{!UwdbslhbI zau-+CgqyBM*PtPSYkOub!^)bt45lTiJ!LOv2o}>zNfB$Ix7re=q`pA_x$LuFx#Sg- zbO3q{?6D=gggP&am=%>&emTIdN=Xh*|Kx8II`7}WjI%Q-DKxz8!q;;Zkt(!$#clUmN?7nm~3<1IyvzI-VMAs7KvePac@YHU%A(ltvn3hw;BP>$;)?p5j zN5cv5Oj9{XNsUJM*E#y*oY-x`Te5F$^X(Q~E<7%fOKG?axB~4a9iSb59;&G+R!OOG zq2o_F)5(|Vnn1{MBr47^g1f=Qlxn7_`Um*(&&shYMOr=HMT$7I6Kure*sWY9n)4ro=QEqRFq@T(eq z%TW6>L>n>pXY9%?0=DD?FA}7m2PNAttS=kuNoN~jN-iv8t2PuN5unp|fm7hHR+|$l zuxf&?Ym;q7+hI>#!w86U&zzX!mW@BHShHSGIStT~i2WAhNyU|-aR#rtQuEro)8k~5 zpXFk%A{%>K?+y#4hu)EHE*@yLELXn4slw0Nnv? z-2KCLu_0|L#2tV=rY?HVG;VLOvm6M!hiO;NfND2 zyNxL5&BF0pE+VUm6*dK|3#LCpV5iCm3{jG|h^v4jm;t^|x$6=P7+-5ge_M4>T1E-G z=Go*hpGDw|ck4}(DYq5#y?8FY->pt`u|uydJK@~p7BM-C(GxO$MWFt zIGkv1#)(!qavxgbv8b>$lr696Q2Oqb_>~qNe>j0kULGq-{mP8gB(U&LtLpHXy7PpZ zYq^s9>{QmkXb(*aMOvm}Tc++{i#|+hmlBRZSrLG?VAbF}(5*S`)Ejx}XVkX<&IDCV zR4dO0-{G$s^s-_kr0H#OcKkdTZ><{U;Xh=xeqHXJA8bQ8Wa+=9@dG5^lDYF0s4&5a z!VC4{#pbbmQ~ILm@0%!K*rac{x)Z>f zHdq8$(^tb&{GHb|@SSd0fedB!=s=d*FM_R;A zIPyQ;&@_?CNON2yT78m(q1v(|hLP&L2zIO$JO+Kb8Z#3i-O1H6$_1(X38 zG71Hi5R7&6i9FkxZ7B!LgXE0f2h83per`Zdq;;7_5;O-%0kXBDi_1rcGU8x_0KdCS zzV)(bK#e^w93TL~3<`EY_KO>=m&mu-OLbVDSNuIiRbyneMQPk)MUx;XFR8%MyD{u! z4->3`@@_!F7_FU>Sy8zoCbo;qhugPIhqS*o7*`#I11Uk0aguv6ckNE z{Tj)Gv>io^TRUZhP1C0lWBiM|k6sflmV5g>E%&Ye_?8Zdr(YTI-hVZBXm^GgIl>*op zh1i^iONBwUoXDTPFSS>w#MnG8!?Q4EYPRh-)GJ`Klv_-l?T#vnkMc8N8OnB;{a&5n zYvaht2SqYR>+C9+7rJsf`6S?pbrf9s7MXXC@0-5EBYfGgRoztf7SZ{1f@4{O&|(kf zM;R)r>pPwSoterI61kH@g%3m`jcx6DMmOavP(?7BV=bd}cLZd+2W5z@O_GmBl?}g2 zI6a7XY#PoM_J!U~ET>bbp;HDTRDUS3i8^A{5LUJ716RV2OJT0b1p%PlBpGkQTVsmO z$eR^a9@!j)OQs%w6zc!I2^Uss@2TiUm{EB5%XP}8-fiVkc@s-M#mLFK{7Zt$)yxgb z+W^T>uPd~&S}B_lCLxHYUu?v-8_9W8;N#yK=>JAs{|B_IS@kvup#E*}(`qV(GKKuN z)zQeMJNNymXfVH-m|t{4C#C#a z9}`E`K$}9T*vSZ4o#=JAg@y8z*q%`Ah`)ZnyL{Q{ncY*>P8YS2eAEWY`A`%VdbiSs z{n8k7cJGn_&zr8{Uj%P=&5?J zhgS~Y;{3Y8o#k#;N;2i$e1xKxaC@jqdWc5Ry3hu_%|K3w;%ouRcA%bvUUJ6vJ%4c*z& z?@qw=YA2u8rk|%&;58ywYx1QOR^_dt-h_cAQ!~=uN7kR%qVyXzfMYkyN~KE`&CCo9 z%Cv5F$>K1DJh#7fuEI_w*rvaDZJY^+4j$GGCdAIC;!0mkuJwh zGopHrGo=akmlF9bfC-Z?!+Jg9&oa-^op7OB2Ad6_6IADXo)crvg8Q&ZQQifE=B##V z0?xgp;pEA34mWq8C@!()O35!i`KMdtCFF;AZ|CERi6IcL=VdNNo&_d|vfn-m)pwgZlt_ylreFwIz{*xf!ypK<-R~PCy0?Ksbz0OF=fb(!bkIb2Lml;OY0R=lkGL0sY3(ZffgYJeg7^`@smj(39zDR7h>~Q=I9YAd`Q#Grn)# z`G?`0mglw z>c$?cw?7*m`DK*Bc5X${jXe8KOHbnsyH|Zy6@0@X%@qTFWr1mCDUTZ|Dva5AIg%_f zcJGP)<+?apM8^6vQiM+Cf>W0MBlcYNO;Qrvxx$B-g_ig4k|@ueCb;X_FM*W3DDs*= z44M}KbTjqf+$wmGxCrsZW1|NB55F2qR!i-)VV6 zNM^s;>Oax&=IIlz^EMgWI^Om6pkNYi%wf$0S$34blz(RU#`CnEz9a}iu_gCFW(meGmEGoBH-oVcvaf~T-n>!l9{u>m2I+EGYb?23syO~6pQ2{6QhKlFAa+4+11<+MfyB`>ke4)TfMKhY(a| z5day1b_gOJE#h=ReA*}D+~dtk+*8VS_5l=h+32VZ@`@*02YQRy1q$JGd5lqa`$jim zs%+S_*1l8kanU+NmD?wqwG`_x(Gx!aM`doX8Ag24kRy1n;G4ZRB?2S0C4uXJ?ua@f z%=R1W_?No0{(BX;(tY$&dlifdusRw4LJc{jsAUrlKS;-O8_(Yo{=?|7Ieh`c_C7}iM+ z3pAl@n?u|M$)KC|iG41{=hX+c4xDmvGnz@$mar{5xK2%l*Hzhxf?U*=$7kAbGP!Qq zplqhSO7bMN$8D+TF>3iSFKh(Y_|H3G%NIp9r89_Qs2!1i(m53W8x{Ot2to81V^#mR zSC}rbGK6;#J$>tMUb)LOBS#NRL5&0r{|w^8hx6UMuWyjUx*-rB&~N|R8s_rgc-mq#{i;;%~geqAD^1NzA;igW^6j zL>d>hK{d>Wc?rxiGauZm=-n-!gsv{_K?=9yz}v0Yk_i|y5UDUFiO8nJQ-0)LGAJcn z`mj@3`UWpRYw(yez=$+W25;?8hB>98b^(BKw|L(@%{uGGVZ@DzCC|kmIo)GKF7swr z!O8-l8>CWj(UWtbYwNx~p~pezzS>GObImw94ZkUL)b7r?ulKlFZD0HgBfb+gpAAWX zAfF38Z=ZQME<`MV_n41{aYbRix>d#>6ZNDEoSedZ7%RorI7zN0%z_DDuEw6IrJ^L( zmz0G*w*-lWjb(8Aj(xX`(ZAor5_?3^`L`?}{x!N84X@E*a)Uu-YmJKu72h?f^y_t3M~}XTlNRLUO|MP~5ugU2$JG7Ooz+`FwH;;U9de_hW@@4H<887yQe_O43Q%ixzm9URH+T3*XJuxJTCF?YMiibyhHxu$ zaQSBBhDWQbi-)Q0ON4^??c?6V&2pCkOA2KMeF=qJjpB#m8v^CK2>3m;te@}@m1Bip zHF6~*7&%g_r<~zNG&Rc@e3re9iD9s`O3&mE+90m-wIFDW(Oz1(YH71<^h~b@ zD<*LpNqmG|n{HvXoPp8Bkk#Fmx=$2E@7)CSZUxM~59NKypOg0*LyggDYdP$Ic@Ehk zb4gnPFE~L1wwFUSt)%MIIPp9V_ewZPMGCh3V_lE=aUk5?531g$UsVKJy^Co~rHd{< zsHhaAxeGzCoq6U9PX)z+bf&$9EGVebh5%|f7W|4F-N5&khq|*9$^3Yh{n(-1juExj zu0+SSTraLihyC%ERsmZdg;8z5*QE=excIu=bNrsd{cInD(cJc!BFQz!ucKf+CFUe~ zvvX0*NXlm*?jCX4$y4nD3nUN1Azfl;{=b=)o7jb$z?``oNWo#U^38!W5Lr<1{wQym zIgQi8b#r|FP8ok*{|xSV(CAHLp8c17`BveOJEV4%x?M9!=F|4rW3D%V*eKRp5*B?v z27kv~(XKXsP~0}`CNP*!%4BpB(a#syv9xKqV)PrA3J?Nb|0gu5EFo3XQe|O-Etm;T zKzPP>QTACbnrLvX`gC4@XhI3dciT~Qr*lJgt#Z>$aV*M*R8IPKR|jmWS}dN^AHV(u zow!Gy@x}}1Sif-qla>Zh!{#M>@Y3?&-O@VRWKv0XWe2A0vXLZcxOuz-j>=1?(cP8f zGPgQ|ql#liCT(rCYGFXhLBXv&+Lm-C4< zpDMNvW%O@iCM7Zj zC;?vN?EW@6yf-n`Jih72By3lEqg*h!NZ4R_u0rM-vhi*Bpku?{x^DYhde7v8XJ_X)nA39>}M3NjelZ|`g7g9FXx(dRmw z1o4HeZv5YT4Y%tvWxQ7*PcBbTk!8U0y)+iY%`n5RvmP*~QKAV-8VxzwL&{1ZMC(J2 z^pg3km^E6ZQ)O)sa$!s}2$4LXFjx8)AG{{RplV4y2GbBrT-ysY#J*b#L0w6*(1fL? zLw?^D{E`r0ld#VO?3L^?%%|?EG-910QtAF7Px?=V7+6of(IUIrY1sx23#bC+ZEOkE zNcvO{x*O*Sy=;e9h>(~6mvseD=*lK1=sv2a%Elrf+wX)I7#R+Ld<99*h4Nw^yc=_3@4m}`FE*6} zt|9QLVQX*Dvob1G^iR;a5pw#Gfp*wA?fTFIf$*OCI{iIi%k+XSk1ryxl%O9Fy^^{; z5q;3JV*%U!_k|? z7Fh|fZZ!+IjA)L0~bv^Oc07Ms3bkF`B`b!D;MsArLXa|Yjcri-yvC*t=XO7 zY_76d8ukwuKCS`+#+p3tvx^N7RRR!<^X{YG7efTjf?tpIWSSI}v}2CSQm7rA|8w9y z1G)0fIcu?aP|yG_-gpx;EuNZsWX`G81(c$0ADpZ|HDr}h)<4?Gu>+2L%p65U=>&ZE+e93A9 zFafP^MCvA0ixZ@*&v?_c1aO`?H;}u}kQpg?M8kx6`{Ecp`NLN?cQQ;yL&i5WL55|J zXMthV!qEx4`=3z%V4eR4Gsa+lVftqf%HZVv+hCf2Af6m9IB@6r^iCG-i=t*iSq~eZ89KK_>rz>d+HKe zCXHH9Sh#a0v&nke8{ofv6>z*EU)Oz&{>>4jkC>epQ;6h?r+~E2rm$nfFkf$`;#!TA zOgq;36R{OqI*)42MGzV%Z|V(qV%MP(=^uFHfna3@0u!c{6J88Ki6K*#AW7I&%1PR# zU=L_UDjU8WJ=hwxe4?=c6^ARg>@2Wt#?e^RThc~>1<5f<*0f%x+Ras@)i~FsTs54|;yIv#wJ@cw}O=uxw%W0a>p~AA~1EaDw zHEL4dTL(3h^U)+awXd1^ zu2D4Cw)I*Xpf^P3r@KOM$K-f6{4%0$E1v%+rdGs7*Vr}>O+E_MV+%R zEm9sMu=E%y0~oTKh42F=UYkh$hjLdu_hsYTsR!x+^XTKRrFFAGx{DAv?;&FQW>=KmTtfR#EUncQ)eLP9@(bJV~xQ!j{tqjww(+9 zya8{{0PWGIzu@6&ABI0Dl7vlOE6HSUT9@dm&kIRpxq-mnqYFa_Kj`Pa(Y>9I)Tr_e z2Xt51vRNVbLq9l@$jU#tkvArklVZHS2Poh;@3TzNjor{)Ca-@eTah!ABJ@mGxMfD4k z<$=;EaBW1q|1tZV13xXR#1Fyfk5&7m!F#G)Z1neU0quHW zSI}8?)#ZZ+#ik3So7j(G^Y(O>sUt6!8r56eiVn*cv|rMVxH#cj}J68L3v!n#COF7 zjZRTNsL}~EW`~7HyJ7jIp%MV^GpmlP{aroU<}F_LX8ARyl1=6h$gHm z<4zQqTCFOXBQ5F`@L5)>N|N-E2H*H|s!91{S`3fpa{knQ&6bw`VqHkzZD$Y&1zAB$ zrNOgv7K~m+qTiM?PO=ZAA9EPb5V6&??tUg3-t|Zy&2|C4Uf)gw4Gk)ao0}E zU>kI-H|sYk&|BKQ>%t^Yydn75Ta>P(mRirJq%wEMku^urHVh^rx+D*yNAc3x5+0cy z4%U7BF!#{_By>d6nBU$sE_d+eN8;xD=!g68m!7{wWf519cXNp3OQeQS3in~lJkw|R zMTie22gT+bBShb`X1+imKwiz$N}H8~W-#&&6Mph1dpCm@ij}pp5!U_YMpkoX*mLKN zmN=fp>O#>*N3}WbPP6ialbZbxe!SE z`z8?-^w70~TfKY!;ma=$Cl0>)^^Xwh|JLsRPkC3apM!8l|E8;4eQz`VFLO-Y%Eii6 z#KGRx%+vM1nPY0(8sE!>PjV>QU@+y}s_xRkwZz~i8y#yp!lt64!q9y1UiB(l_IXCv z`tj9G$6$$^cMjj%K?tANU-?I#_lpAk0-~KBiGn{BcmJ9mPG$LYzdW{kxPQGKEpG!w z=VuPsV6re~i^7^@amE0k@cI89km?ZJI7Wr7gI{8%o%ZQ%$PkBEHC^5@nh*|WLv%d1 zfV_~J-^63M*!mgosDR`^HE>mT))Fx$db~%fsVDqWZz%^x(~2dKlyT6Ri&AZ{KPcAa zfgJ{0qp4H=70~1JN7e^>1n0U7fu3EosK?M(2kDl64BsUNIS9F4iT5Fyh+YPg<*zSpf$GRM)&F4*gBmq|Mu z)9I9GL#5?vOKWA)w2=#-Dp zW*ski!VAT%Dkue|fx33mCr^+3;ug{ddeNpk+a>*~JJ}R7*WrgOi`K**LGF3gTwzqo zKNE{o&x<_?^N}d>tS+4sv*e*pYPo>sh323h{Uh%T%mFL_iil@e5H$JJ&8=I9(Vkof zSv;5YXanj3xy|nZ8(E0Z=VT@!5$4UAooMochX7W8m{q@3`B<97FCXu z@^`!^wd27GTH#rf&y=o{824Z4LKoef>`sip_q?^z#WecZTJv@_E{T%t{A={o5a0{s z2q)&OZNLD4lS3+VY_#1c@$3y4Z!8M^85A0p%aJq7CSac0O|fF<%}hhUd+@1}*e&^? zr{qlVswC}7sksE9NrC)pOg50c&$_mFP>_3>aO=HTx>B)Junmh3V^px)N86S5Vcp8R z9^?XX!`2k)l7ml0WbT=Ll_`@f%3I}an(bwq?2H#cA8!}W7R?%irR^66y2olTVJ~C~ z5ILVk-^-9RwX&Q)Q?-V<$Y87^$v7U--w-`=iAgKEfz1m@Bby1+zc=~mFEVfk?1W2{ zLek*V6spiI^Rp?fdj?%VDEfT7=G3=(Zo&s|)nMj@B2nNXbFum(2z$PAaDnMW#aYvT z`STr+m-3?Fihs0C+SIX}O!l*B0J*H@t>qmJY&5M9Vk6{aEuhsMQ??9DHuTU|CT$ik z?Mg~(E5iu&6=$6h%)jTy`c3Nbmbe0Jl)&d32M@LouR{Sxs6f1T07?WI-U`Mru}ioO zyk9UZH-p$3LW2L3RFED$iyQs&NlvN9;#-S`l0{=EJ09C(cjfD=!BQt1+qV!m7K8KQ z4n7Wl6R%)kpZlg|cEG3-EDWI`l;aEJUn9i7BgubmONDCGsVly2)1z+E;6M{+|eBO_~rwEV#g2+o{8M?huR; z(?LghGMK2&$a;gBj^)AorY3sE!b;{YW26{tO9#5*iBc2Awh{W1UHK{WYF(vY5WCIy zK??%!C)qRGtuFRnde~3}uXP$V)bv?mLP&^1-C089hZXXe>OUibSXtLa2Gn^#g+Ue- zqh>@a)@JDI1Eyg9^{)T@_5Y8EbOx2bN&))EkHGJtiT7U`Qh=1byMv9{Kj``IBTpS_ef?@yla;oy$~hPxyF_~xpJftqdLfmq)ZALIAP`m3rWEtVst}MXwjaw!0T0y{xvy>I8G(qDgbnC^yTL-naX_ z;S;99^3~Q^tGRHb<#1J|%wqtXholbI!)@?NMQ4Xyq?8zFelG@*m||!>4`~EzI+Vor z!9r|Me!FOx;vBEFmJHcmJ~S-=>K)R60NGQ@e*!F$n8|J$KcM^u^X>uhyMc_XDRw`b zGLI=3A&OIkOc}Rm~SomGWf8N7TM!%+!>JVtcN(im!)Lq zZ{9RzK<(Jy@{&##eFtbPsg#I?l>_J=X)j3YA1IT$MOa1H2OhpkBfrvRohLeyXw5LB z0X2$UMV_cSdq2oYZ6<;>TWN?Y6h|p0B!r)~L(*05jEj~}%4#9`1@$T^u@_s@8MS57 zt)8~a36*5fx|SwLhyQjo>7=Hq(Mgo(0?Mc?tsE8W)TS-M$OiCuToy)(S880Np=I1y zk0pT5yV?%VCDOIcn}}af>H9Wza+_?FQ^qNqAD;2KZoBJ<+!N zP*j_5??NIS_IaqY2Rufl7pc3#N+@a7deMf5r2$K0z_@Wq0j0Jo-Ky+8E^1)fRMY|k!muNBa~`dFwxW0Igh3--D_)d7Ppyu5Mq)KfLCU;DeX*=T8e z!bOX=GGgBBnBKJ9xb46$;vg+f2|!FNBybz{Wc$wOPe3m1tk4g~8}#$(IJ>f0XXfj? z@Levz75Zz-dOLHOh-W-pxg_#_%)hH?MV^zU|7iVsA%QRoLs>11|EwlYWH);j7_o|Jx*f^w$8_Ur8Xjg_xB|fn% z*{j4Yu)9!rM zY#X~cR+b%wc0AIMQ#S#?p=?WG61tz5Mu7VkG76Xzc!}P{q=hlxLKr0Xh~!J(q~?)J zywgVJCgRxt)o*LZHwf*AMp+0}JuR?sYjpzMXz7}1NHGdCO5}?(bqN~-&3v%;oWet} zWwBx}n&cgtMV}i=C!k{F9Y3S7!spJBv>_)l7A{sK1>3H)AE{_NqY^rahoTujUmp`s zk^-o{Nj16p>h{4pZMtP_H$Ic^Y}m@DT^d*SDt%)=Z&EGkqOm$*e`v--A%W*1zN#eT zXFfQvun>l^=%60;=){ubYt_=yCh^FtPfzR*OvOM{kN3f#lUsqqMwlp2M@Tb z0cZOGP1NF6bfdiHWmR3Efk=2*Ueg8ZvLxH!upyk6*e*3c1oXVGh)5 zF&cf;lv*3A_-F2cjD)qcA8!^SPcOieKQNL%IKN6_*RBjZ*crELX)uWL5nptCk67O; zKj=CY96WEybBu48Q7X5%wBs0)9Oj;Aq=E`KSYyAcgMjQ{%Op+vCw5VrE?4Lrur8nD zW!dRlVUcD~2xYMojFUYH+}bFmMglk<>DwZ!evsWtq`WQ#TRSjx78=TeS_1&OAlh9c ziHW8*ov>NDv!LHw!ijEI33<=^bzNGU`C}PToX9@+jhWktsaa|g>r|Y3{@9)!ddi5a z1DYF66jc=M*!di|lO!cq$2+&A@Tbaxo5n61DbxuuJjT*wIl0It)n$1$Te#IQQx=_? zHhZ`RFZ9*V6^%=*foT5HRtjx2hCij;rAKkoq+rk2*9`+l8uT{G zmpUH=cfz5^fS8d*wng>Wk#<6a86c82kPq^qN_Z;Z#e1iqeDF{d_KaAD9Y8Eu;1ml; z%ViTmEzSRo`2FcZ`Aa1 z;&13c1R>A>P(g49I58!8AURQ*CBCGvCkzJ*hpC}{mQR?4)y-^qqjjSt9DmJHN|QYe zF(~lj+GdseTTNs8y5E(%M|=CG$J1t;?dnw~j|&Sa3uFJ>hsou)tH+gF*Av&>g+aC# zOb;>u`zaT7+tCEae=}&i$021e!&4%9%k6GoM<3k#59;b3vtI2x z3BvwIHs(hcM(|SyC32kcjbpe3)Rv10lz-*U^k!N>H)34(eJ+B)O)fs5Xy=dKGY*FT zX|L^j6%2r43&61QAwu9FmXn}gvs821h^ z;I7&664?6yT%sLq?>MjKT0q#|Bf{38I8*JWl%-jL5eLq}mbfhvLrZa|NqYZGLX@M( zO{ZQem6riIR)fxH644n9wi%!~(9LIh+O{1YhD#iOvQ&-ev-bxQNby6l+GHXbA7(Nm)4|m}@NERj9qSVGrzP zvl?;_L-vjzr4|`gKNJ1)raUv6~4rW92XjbGJfv+9hl1 zVul;@oLU#2jc*N9)U9`n-?5AXa})ORpe%nPClT>B7BtC1?AWaRiH^U3OmqXtN_R~o zAyS`{<9fcaW>B{Ub9P6vsu(PnJqA0XTDTAo% zBQlHwVUtSSp?LOyrZ5Z+juq5O&P8oPH^jk4{B1sbRRVtlJ9THTG)!(TOt!FA% z8Sa8g=o2INptnCQ%`)FAf;`g|Wb*C_OD4h=_abHFqrDEqd8$gYKD9>^yWf=F~MWSN>C^DgRwyUMMdu7ds`U5=6QL#I{;d{Vo&WI+hT(DFhaDY zdAVRT+z8DuL5TZVrASD-WX}6$MG!}AO*Dgx5T>F9H=GUdu2VXP-j)jSKy6oKM{UJA z;HF;m159ns$^{HAHFf3@8XJilMnkc1Lu?j0GGaPdI8>UP3_#{f}}~u?(-vDn!p@w9td0gn1tHz*BUDK$Z&iIp5EY{ClSTCt()NB_%rVAni@8b z>x{*a@9jH)1Xm2zHOFz$i+WSSj#?biIER{(3dU^X&kP7PpCrM)Z}FbYbDcDSh06{a zuKF=iGX9WJGCmUcYjE0DKo&G#`5eUwQ(q-ioGczA&m-u4OLBZV_(~aFLXfhi0b?-^ z|CB&ixH-6Z;d}{rJ7BT|q^?amgI)q~|sGmmNPGi#2Tt)Dx` zm@ywksX$z~Fhl7*G5+@;m96B2_@p;Stfh>)JG23@4g+*|+qr<`xE68{d-ggYiV+s> zR$2`hZN3_@3Ouhu;UHgkQ^^LZN)j}YtH!4o*4hc}pyzH`fcO&@!VcaCw~<$*ppkHy>e;|9$u=%7{N@E4>3Da^is&hO&NTo47TEJraeRiTtLrO3kt?$K2Q?1pKFnyr(lE5~{;eAZ$cSD?z&8KFk zdOSW+Dxs?5^h3ElUx|;1MCB;IhSdjvDz(3g)I!Zx`mHw{b(kRETcAQ zb4A@tQL9z)HBwg44PY1vA%!)O9Irwn`Q7-CRYgp~tIM+5l$uvF9?u>nb5J^|a<%+& zP2+F?wSK$s9$bHfg@YdZ`ErC)IY#@i!`sZcE zPky`oLf0&MNLw`xLC7q`$?ARpiu^KK zrtYP3@F0P`)enazGmls2`S_HYHEaumbv?Wb5Uh@M6RBMRGvDX2UkCX@%#E!(q9&1< zRWll@uhgB@dvY5kdp4W}dzF|mQL|P|+yP0@cp4{g(A2KPZ>`6BTB?}V%r^0t=rMzpX!&i>Al>W5>>nLXIHjx0oEfU4W3gAJYrv995g}DS%*RT z`fcPBot(IbMmW+!GdnwgBSheLSYXFnogj7Cwhhr~z;=wsepSO1z z&w9!}(D&R3k%%%tAa_VdCDuSYB9fAc;1j5~>ga#Mx0ja}vjvs(HZdcIcPWQ3rBCI1 zv~)bcp*iDq#nK4*;0E7yK^fB1dgT%aVWVUtLomr|Wu%+d%^#rw`%tA16GImdsNE5B z^NP!hOH37YOtSkLtvi|tdub^<2C1P57>xq5M^i|xvTWATe*W2YX9yhu&ybFx=YPl2(7c06j?^j@}FBA zBdi}HvOstqk|>`7;%+yDHY}_n;p=L7c>#r=pv9>j5m-2par^0?aIyPos{*0rTcJ!7 z-Z=Fccxv!hxL1uPX=k1Guw93V<%v!cB&<9Ynfqx9n1kp{ZP|o9$54dIkyo2aP*SeF+O+z(h?pYK$NnN z2u+D*uoH!4cC>msWUvLM!il3Dz`-MkkS)lNEkdCGS1Ye{((z8aUNtg`sN6{ae}^mJ zj*y>x(qlk|VMsF~o}w9wIHM@li_O zCwloX@0b_BKn0DjaUC3}K;^02s{+kmwS#ya5WQ4#BRl5MJ!p&jepx9HBlcjTxv_pt zpRx!5kt--It*QXv$eFa1JyBL4wvrW4Cb`HA)igBs`nar3o~@cUGlrPK4cmTM{lx`> zWqfGtcoBLma630U)9Q&S?In->LwDZzR2OE~PrU_@*Dco`Go~q-SC^;Y53=xDw|~4= z!ZpW_lOmww5A%Y~u0ZtK_v(mWTZE($QB3bI?s}k2=U7p_|`d8%f6Y{_X8he4(3yhOp-;{myZz{?@t-4 z%dTp<+F!e8_30V>amGy|@Q6ZKr8OO+%Hc_K)rZ}5|16;LnGAJ?cZ2R) z8Dj6}qTNr$ocjDJB&8d#Q%zTXs+v5wrVH{%rZt2penJ2s zP6&!MQXgnx(5C7tzoU9=6yHUe^23}9w|}j_G^rdT2UzwLa1X4hu;~PQODX28u5BxE zEjcECR+z{t|ZOQdz@QvL_?7{3*YoZvze??kD(+&8verz_dUil^Q;F2 z7f-=SntMRqH=X1It7*JG6M(=nU+x)$*TaZ55eLI=q#c`=u3TmECx7E<1a_0F7q53va@_m;zglpHV(sd|FHPkxq9K zqIxwc-1w5HI$zgiHNKXRUp@l(aLAIaqY5g#kmi+6QdKS+2xulfT)qgsv2$<8;>`{* zhMrBe44ap8@&|-(|Czk5brh?ceu7=A<1#y8m5BxW#_o2?Y^@ zE!eQpV0u$$hHTE2BLfLFAs;O?`^LyHrdUcHcF#1w34FiOo>d^*25Sa=SzOu;s(%bw zhCzxnKyC`V@0EnAO!4mWY7VfgMR=Mwjt@p?)Vk?Pr$-s7wG9v~w&jzv-}zq85(FFM z5&Ydmg8O1~!1Uwxo49Lq&*umw5w1$U-kdo4L$mSKmU9SP`kf57yorPRP}N+ z`~RU*Hmcb<;D{mmv-`IWbds0l(G>~m=2jWdb4klkwa~TL!vd91kw$_N#4jCH)la@m zt?85$ZX+Up0S)8`mMix{3|RQ18a-YbYgkjCOOMP=U3!{lTO69Ze|;Xs2>|K#Yk<-2 zNdsN&1Io3kCwD<~Ioc8EHYg2&2(W_UVv6l|4{7Zu6K)@&d;=9=Mhc8}V?)S;9)9|8 ztG>aeuIsOO_$b5dii4CDx_2rnXx$y)-BxDG;`u^Qv2ZVC_k|rN3ue{4)N&00FsZ`stm}VGh zFw!=d5njT*;pH`P<}snJ=M8_@RTpxVj8$$WFumVM#k&*wNe@LC$?Xyufc*(rqG^Ky_|6QXt<5Patb}I zokz6F6ScH#k$Y`1iua9Ms~sAJjioRb0l0+_pKahjg%P`WdOlag%yXLTR>!C{*!qU1 zgiPD%_LJO^6JW*5bHIL!{>c+L-{S|U}L_`dlO3&-GC;UACKSyq`^lulyW`?&xX zhp15L8tf|fvt!^kELuLDzm1Y?h=;`~<{}?sdI{~WNdOkQq0Lwxv z(S&oQ5gHW)>cLYeZH3fjYP)&t>gk~D_E|5=4$nxlg}-a-MlGDPWU{G6C7>K=UpHUr zLt~;&a8yY@^iYf8j1hrB>V?VCJgzT3R zU|+F4a@>Oldl9E7D{My|nG-ud?)J;kB?EcomD<3|(>==@? zZLpIFs!;wH`#ROFRB**G{X_LIHOU1bBZ!oMnTDOsM({*Pt8v?;M}YE4nYi26X;IuQ zmVRr|U%m0~WxWG+8z+OIsT93fzHq!_q!jV<`TQ8I4)CpMI=$GseDd6?KYHp0e1i2L z`4aT$XIAy%XI2b)>6Q*s4v~6^4|>v-1FmhuJ*LajAa{xB%UX0}jzmfa(O$m5r1Vvd zB#YDDQBp~XBH~Sz6AMXI64R)wLuWEsIQ61X=ZG45l#RyO3igVuIf+<%)OO28%F~pX zDg@c~vaNKg14DN!hNAN<_*jY%GOCv=a?KZHwL??gf&=e7baSv{*RA-hyoHbL0Yk2` z3UTYPgi;n0zh+##A0#Ipa4$)IPZ&xUh8&2!M{V(+I&{T1^0Lqk$t_10i4N4+PLK3+ zG1>A+S-Z>9aGhXUG1>6Ud&^>`R46FtT}+&bD+$J#^7$;eiUwLQ21}am_bJV&ffpt) zJt#@P{sed4K&|99(=J{vAw;w%0B9hdH>2El_^&h!NV4OhOr;5>L1Twqv?O42;HrF1 z6M%P8CAGwDk2tY=79qbA}cP9cYh+5b^>q815?m8v7Ke|FTR>1>${rjDlq%uH+2d| zjN0^Hw-g9%_G33E3B`F&rTzowWG9H9Og`G0I0|(Gr%@?a*@>a3!QvN{C>SEeqOAp{ zSp@NJxw!?V4(-{F!55Pj!GNvlhV>NKY;Zh2>_?JHWBq<$ee-J8jzA5zj?iVaa{~)1 zYtB#(*8BaIKsvH9rNIpBEn$SbKO2WfDhUxJHY2%!2=!@uImqEmq^cLo2B|^^8&3&h zAB?Nn@dpWo{-khgPlGXk!qKoqU((Ux#P7Po<{LVVhO4WQ6K$$82)HTC!+}us&D+K9 zTDV5*GB@W?MxCp5Ky^)tmnz}%ULCMS7~DUS7xLs=8cOq+ z3V6fJ_H9#Vc4v228|bWK*GLvqYI8a;imC&J`>L_Ouo>=RjPh9TyXf~AAMs)}Ya#jM z-3M__5UP0>kOTWv13->uJrjt(d#>uHrYI`@My$0>T*T22@mff#T5CTwwH>Rq_(&kK zQ_Zjsu4f(vhjI*djt?y$^Q&gs1nM0aXNY{=>msa3zl^^Sb!qqSk5YIkXMpq%ykt|Zj(Y?VKz z*TM4`A4NUJ@j?H46w~XjR`W+RU*<2o-Fw{z%xyv7FOc6hJOXYsGXe6|YP=VFzNB9pyh zW(iF$LYxCDL8B_aTgb`lvQD_gqvLK5soFfV<@NWZ0$21xjY5GaK@XALjei6!{1PMy zy#^H#%>hIP{H6gnw^uV%Rb^+h(&6^%)nLpyq=9@^+VqE^L&+LnaVxH9XA$Yf4gCHOk?h}*|37Pj zO^||+$u|iX%=DX0#`E9)Bai?`M>#WBO9xXqBUckkv;U53=u{v7E)BS!>3*>7vXBmX ztT$+r!jeOl`j^C!h7+f^l7g%^39vHtth6jT^_`&Cd%bmI<*Hf-bQE#A1<8?ny|;gR z1x7`#&$Q~0>Qw1cywkET4ZgCsubA$J`wjfT9N~*dxo^yYNjw1+a1JJ{5gv@@?)!G0 z7^#!D*&#HciS^gtma@-;5u~?vX+4En#nB@TAr1Dox)tRwQ4kfzls*rJNfminHa>PK{q?zd(B`vS7=IWj+PT8tI zJL;v4F5-b~wwzl+=CaRPVcK{<%6Yu@@0a9X1nju`E#qGl7IHt-Di=xa9IP>x^R+1g(Vy+QB@ zWyhJ9Z%RG3Yhmcj@b1K%<9w21Ud;iaNxUJS-Hek|>uo7rr+lnT%w33knRB_S{8G%o zoA9g9<8N)s##o{5a^4zF!){1e_WicnQXsiUa6zJ3{j%Z5(w?0iC2SGGYdLEsCq>3P zFjFC*&Y(I)R}RPEbDa;v8Gr0b9-NokU=~QgVZRPjvaRToq#2uHW!|M2_8PeRIqO|* zN0$|^r!lOAbGy^G`FfK5;FVQDegtd)91!?S)FFSt403UNWW9`e4Vw*@jNk9%tfcuK z4!I`zW`E4D-GpQm6ngd)9^sRagET2hf?*6O90X;)QT4@f3TUTH%ObnR(Pl|Ox`^>Z zLs^$>i2pUw0KX-%UZ#2mva-&JEJSVuStdHRCe9N#s(R~jUzCsF$eR4unTE9?B$(00 z*XGEc+B;5PtY4Bj8W=P;s`rWU+~3l)r{F&Ni3DTKYI6RC+NXW7~C)+x0hy8A5$Q?TU`CR|qpd%m5 zxnjoRPnhQvI}EF07aPQS{a(}VSZrlu!GhaS&ow- z;O{)``wszWSx`Dr40Ehdzxt=)2XMn!|8PdpI7CuoIjZ1I&#HP9f@qXo8T(47N){U0 zvdq8dEeTF&!}6^fh;pAlxYgWjKKKpnDs+ka2&bSc%&g`PmycEI;tOYtEhN;a`|dsR z#^3-b!A9ebz_=W+RZf`p!yVZOo;{%13GO<_C#grfZW%l`AtI3z5zvftf1<9GMY z{}1K&e++h2osCRv{+;yOsG;*69f|t6riY0+^s`inmB~`j2xz$U2H3g|S#>W`oE?*a z^d!s9(3Jj679p}V?M&zM=L?2<(M*~&H9{G0;caFPinF)57OFW?nY5O>f3lmyglF4i-nQRBOu*;IsRu2~DBlb%8V znWSOs5(vT0z?Gi{iNNHl8^deWZrlfN*EZsl&CuH5$6(5-bPWiyszX}Yx>xPdb6Q3) zpG@4*x0H91dF|~OwShM0PyE#5K{R7t_Z)k)^$I1LpXcd~$9o(P%xg6CF{X8vA*L*6 z#9V{v8qCtx938LBtR4L@%o07e8+4~6qH%xIm4A8012ddZ5_TRys=g)_X*~iPk{nC9 zD-INbf6GRF`U_CRLrcKaQ!abORQ9q~&mVI%1^JXTpat{2KFDOT^=Q$dzN@ylyW}2F zeEni(c&+b?x??{q7sD)|S5oVoJZd>{bXdbpE%ysmRXd__O|8I)?Z4VKsN>Zp)ta-4 z9|IHl8V4Py@zPah(A`V67CG7XN7dZRtb*rJ!9L85)Bp^oEM4cJ23)J%A2J#p`atdY zmGwa_rbsz)Q4aIkr0vU-GDk&40WdxBd@$FhUb|o;nv!LNr=AaL8j+UQ9ShX@C)qcc z86)D@e7|KZik5y)Wh>0U*}e3& z@Zg%^CIEd*JAEuO0eaZJAZQy#E49kcwx&F0Y?kn}K&vO>dFQkdQ+2u2b3azzYUVv+FK;%%?oTTI6LVVeWmj3MtzHv48uP z2uN^Xre9p=r%`mJV5Jv_WGZf$t}G>4=QiU%1Y@-3X*IG6Lxj??jgRv;mxxI#u}TSW zRRQjGaeiB6&v*Y7{X?~0!9_Pz@HiDJ4uCFaV5-IODkA3XbK3!X@Ul;f-=iOAu{g#E zz9L;R$@9gG{K;83%ZnF<8@6i+RP!1A z&JuhYi-l}Q9{d%3Mm1!%I%BryY`3|!*xbM2G*qS$%IZ5j(^>6{`B+I8*2x;`F?VGt z{&jpOdS=hfHus5rfwgv$A$^A9%4|ZFOZ0?!j>KmxY@vp^B3=B01gVF=0}JOu*aM*E z6&-E%OB7IjMP;=I#XQdL`VhL&9N$ql|9eFJqO|0L6LFn=CP?4bdcE+q(E5!a(LUF& zuDjC+CW?NICtK>oY3FnL(UNW!gZZr zk6X`Izrei#m>-ygll!C|@r)DYf;JIyOUM}mL>*#`xUoPJ$L+BR#|fBu1x`xZCnt7m zaS6{iN|`+xOpdSydpNwgr*P^pjG|lLsS8u@|5*F|I|$?aCq9?(i0QwBe{WWh{@ch8 z@PE@fzr(%$YtQQZUwO&@C2VWdSa-qE!266PvqAInlRIA`l1g5(GhH1`Zx9R*!daKH zZmd%|-4TWkX>3U0(7z~er=frkPMLG2Y7lHKKJbT0+hf5Gn{btDTjkgFW`l%dM+M`!Xi!Mrh&S+uhA#!@Kj z9v+-D=uS0!^R{jKhi`tpPf&9%izpqbc!KAo$mS&ESdg7qBt2&W^M!b!{xxTU5{ZRT z7NrUiOM|AT)I^rlEbcUI0S>zbE2&JD-DYI{W87B!2MvI`JaZpeCa2wYbO6$)6!2M6 z-sF%H!!^%xL}#+mglF(1H~a`1dw|z0>c89|15>TfPS1Ur$nJ35R6=(Qw(X?B+BuaQ zqv3aye}XL*DVND;H&1{PZU%k?x|bwBi+Eh9ZBneA&9ULa-3WF6H!IM7@}!z-dDeWx zfVJ%NnH?bS*lesFs?MtGqE&*n=2_%yUu2wFZa4GuGI2L<+NVo~M*)j$IaimZK1)=l z+gFPPGPpbcps;i{O9lRr;ds2w{KQ>qe6>pn+Hup)`4pLqq=B}<&_iVHaorNEjz@z& z_cS4u$YE?*uMMA`yVE*E(Sb47Z)q7uX5O3Zr#2vt#YR>a(W*Iy1Mk4 zINKtn%o8X!l3`aYU_#yr`8eGX*Pz(UZ0#B&D}VWSPip(Ma!KI#HyWD3AP1_i%3y`3 z++cIzKcWTwVGl6;5h=m>DPir`B>h;xn(P`gFT(}Hsk`@ILN#0Xkie_5Z+GF`y)Z}6 zM=6=PgYu)2qnL(ldMx%{22f^%@@J&#a!(Kk>gU?XoS!#5k6({;?3WjBkK|*QbXmch ztSc3-#YG30L-CA8-Yjb4(ArEeidsum`5SNp-aw=4Sf<+H< zTyE}6tMWDcjoG4sa#N6uDmVIoR&weZDxbvjb{FKB9~ruyR)5(ajg1}isV>fdMl!N1 zPh!_S3g^5{Uzu^RtdU5P>PmfBDs}Wj+!@bDSuHWC-cbcmJWG}0v6Zg+r@@BOJ&qp9 zlV@PS3i_~L$ozi)<;l~AH%_SsXrT#Vl36?0RvdORTs>i3IRDnO&$Gq|boU@nhh2~@ zf(g4S6ddY~gcd+&FU4xQpDbfJ z8@E>&;+rMO8~P3NCtD)J$v#R`OT-7Jsc9rN*CZsm_l2{*?;%Lvbt?G*z@Em{o&50| zJc5@ZM?(Lv(tWv>2UGcMwrtQ?RDx_%jcz~dmJz(Hs$2!-9gn^vH4U_X(cW@P@gAo* z+PnOY+4(&vlqttq|hEbopEc>O-|Z1OpM+Xv~^2szgZ*Z`Srm9(DusI44Ml(lbpis zig@f_uBFk3h5UPitxTsWg7ZZ;__lAO2v%(@Ikg7%84$Z)wVL;-&P5AfR;A z{kZKhKwT9HmYtc0(bFlJPjFj)OwQO2HKHHrM9|48T5jb1NcoXoXfe+@;jxXROT@}x z96bG}z}J%xmyk&upj({_Bl1@=zC5QvA{-Ved?tY<#)mj9#&Jn_wEmfp%lH@QMv$IV zf~|@JQPs|_&av|KNP>qH`8AO*XXF@#6z=}YZ#-f}seGL7P|x$KHVq@+STOY>k-0Xo zEH@Z#5|~)<8yhPDDw7YSx)5#rxQ5dH)x2h@Xq;p1&0oMK036j)H#BN~>@r0WG(EaH z7g6Ug;Zx3Gsftxr4S@5}F->#W z0jcOe>)nv45EMkq6eSq4ngmtKFpXD$a5pb&jziDt83v9jIYn1kq|44%U{hQ}Y!3n1 zEA&h~cY;n)o63P5BO6@h9ESST-~AJI_GcI4+1nW7+d_Q5Ir@_#|1_+>u~DAQp=AIq7Q5@LiQ3(neIKmq z*MesnDw;C8JTM4!zvy_4B~uD17Loh^3L7O6)$VbC_D4kCi#D!rAq!A;bBRd@%R%S&t6JutW@8-iyAUO0B!3yd10zY=Z_dt zZBt^Vpnt*)983dp*85bHFIEp;^(9bYl1tvPn)NQ(E@G-m`jo`7VEl|VeLXNk%hGMV zb=^Rmb?Fwb@Q3hds=Tup6*xlX{y3CU`@q$XJ37GTcClJh$LrT?QnKJWKr4XGmEAU- z3=@%r!VXru@hq_R4<2e}#`dmDMXEghf^2FfX^6$v#O?+J=#lBQ6N_wiEg@~lTwS(_ z=FLr;QZA;W+M9H=ki0T4*{?4V6+Fr4pD z+~8AA>^F@|c5SnB4zJ5Tx&8@?X2)p#3K53G#lcBALQh}o`m0*2l=1x$FvqC=d_!6B zve|=VqpSho8yhK8bokEkGI6= z%65K)hEv}zs2PNnCmwfv%w5B5ZqC7^U$BxsD&Rkq%9nhpSwDFWK#uW>sj<&X?**S? z%H%d2HLWf)ZsE^=cVB<9yb&JcLt8^AEa<;6jH3sjX?V&l)?JH$3+y?8v%&ebZXtVB z3*EIv`bM4U-ga3>5IRhWTPEU}p_&OyJHB;RW3QF<7i8_8T2gK$JpMcz1X(UOIOC>c z;eLheVzougTIY{i4MD08s$R!&SXXa@%DZGk!pmv?JM@p@-CE4?0;U2;5GoILw~`g#hmroyg)0n&<$?v(B!NK1!E zcdEn)rIB)ijFfVO(jeU_A)pc>(x4zI1Ed8+kP`hbQ}~$Q_xzV<&&KZQ_q}KLzURE> z_&K{VuKQf(a81cjd!F`&S6U<Yt+vl)YCf5a&snJQu=nd2zu^$OBh|(S*M3gKh>v2GfCXc}JnuP_c(E@Y?3vq#ZOD3te!0!6~sErnupp(d`=zZ%7 zWvyxYZ|&NR(Rz7q1FpO2^&Wu7x5 zFaYhF(CtGNT2X%sc%J!o@w5l8RvMgNkAgM!oZQ-E54@Wo+1_VUy2BqMIMe#C=~k86o8=F1spXGWm@yZi7JXdSUA) z?RPiSyh2qAP31kg2!})0VsO&H#gn&9^XqTQdx?tWXW0#E;p5!EAGyrh*xTT$MI)*u zuhFJOvm(?k^hJhk^u8WP+1Ezue&^9w5F1)9#+70$wQ!k9luU}-u zugz0h_@n6#?Zs4$*bfWD-7h*T7pt#kd4biw;{SlQr+iS6KHxt-Dumv{H^b2zetYn} zY4(x7$6?&Xsbnk2Ds}gY4J)nXq@be~5DWKcn6bL`QN2z@_g3&lBpH}UMZ*P;Gihr_ z@5<%lD)Qx}HMI*p$$UfaIXy#QPD^QQ14aU^3b72nBv+$`IgKdWN!faWbJmw_S@hML-SHNV>wX0Vmy=7I zkFWXYXWcUz6knD7LaL|iur}ws9>2&Hp3G;=PZ(7xZI@`Z?;NFi$Ufl?>y?L_a5{FS zGmSghKlaqpw|e#9_(|{#K~B<@eqZ=-n4+OE*Ionr$ipSF#Raa`ni3?xr$hL24JEC1 zB0ET$0%cE!{NxYw0io*lw$y69yL$ACDQ>Mr6a%93Cd30sUt)n-C1U@oo9(z$<#X)B z0`ueqlqx}ys3w;5d`^o?j>679XH}dl5%t$4nk5dELSMHgy zEld)}eQgpS>zc?|(SXN~N)LIs@^_YX9dO^~sXSp|^^G4~?TlzQolRMSf5r}d`jdBn zwR&G{jx6APLu3+%ytAg*>Odq(JNQYqg*_XBW$nP$N$G2LrGpl1p){9~zJ;}ZLPF=^k_ ze*S4B|DwdYXx6yXPcQdCle!=&VcH-H&r{;dxS_2q-&|sO;bIB*C*2J`4Ylop6%UC3 z<}d-S`es=Iid6V2tlco)OL5e-gLLv6^?O-WxE0N+@U|H_B_sfT4-ycz389OJdKi;{ zgzYCNi3H22{Y{tgUxBN^RLI{HJ*sv#1#>EgJT{Xf64$h7t9g+NlYO#q8G>CLr7wjx zdBeQLLDsOmE?)8k7{~8T!3KBexbezLR=ig1a32vORFn+H6A*X&rP>RpPo?vwW{j<` z%A5SW17p0gn$U-`E0MfibXVPtx_rs(m6AFy(?r>mmSu?eV|8h5c=i)4P3+&(E_c;| z^D&E5QkY3NVuEtQ54guQ-m$}BNb|nNur`D5g@&%Asq;oUh~-GD=h%xnMmWCWbepXN zbw}0aR{4ssXjl(NA>CDl(R~PZQ~c`*d>5X&F7dm&H%ok9kW7Di`*M-7+{VS@vC-iRm7hdA^1WRX<7S1szf>A!?p*n+p)WxjiNS|S{z@2%1Mq{%q-ixI` z$=fFvNVUCP$;F|t?-=YCL$oI3zYZHiW;(Apx0r)j_;8qWaE(Nbx>?8~H!r$G3})94 zBAh@Sa2WR?fwuBCCo5G4GpD|HLr(PzU0ca}IqRyH<1^YOpv373FY>iWgI$V3$9E-; zc=|(Qdq+Q2ju$567>V5;JiO8s8uz-=JS}MM7WU_@toS31eM~Enu$!Sn?vdAT-=~TV zDN)me^N75<7FF~cmCJbkXGmLv8iY-Nfrp2OYCXs=2%c zHeSx2|2rgEx7AZVT*LPSwm2k07&ywQ!DQt;v{jCSbOwE>zYKwo{o-HTH zFk{YrNFdarjMK9{yXaFiD}{JS#2Q7?ERCwDsVk_(an(nZ@`$kcGpwXxh=XX;1rpckU#<+{49WoiTS@)Nc; zh0U>7R_khZ!3I>>{9#Q5c;j!pZgXMITRfg6@}Q_mnHpoz__gx9Xk5`-GNVOx zFLqPed*^PX`^7@$RK+M>ownBpG=nnLPY{vgw~c7pGO6B#)2FV&3?Mpstrj8FFnMjK z(Y-m_Ys@TZ$nsX1qB|^UADTTHWbaw;sQrxHQgdqJ-qwrgi&$CdeWq_ns~-RJR)hx9 zp`Pq|dAN3b1KpPGM~?$ytVQh>+)K}l;7x@Yg>Kc_Ew+IISlee+yAAT=R8}XqM;ADv^(q3 z%hM!9_n6IzF4QmbusE=|@7))K7b12u|Jm9ip49c-3*2%F2UMT-?ntZ`@DJl2lH_J) zm-Eo<4f;6p^!Y>Y<~+MAOmno-H>xYwGbkYVAUBMPIy@wZo(h&V6p6isg$vD>bE_;4 zhv*u$mA%NAq?%^y^uF>vfH- z3+BYa2=9D39%FE9bt@yk9r40Z*CEP+`9uIf20QmfNOG9A;;p?z_hYTol3A=d}Kh3!u>YD+VSPdtCHr{ddO^AZ~`NI_B7 z*-qGh(_=GmBi(`johCDi-D5UbJJGY$$p3$9>N3iO7b;=`jmk5%HE8hF8l^g{j_K^_ znMwrOVt>k4f6`kJix;d_Qq9|2T{{MMl5w|H;%;QN>zVpq{fpVxnzKvR`l%K@j{c&6 z<bIE! z(r1?NznklD9{VJh=ahad|>7aeWYt1$MQZ5s*n&FWZp7iU|9_}BZ!sMT`oN^cQI4NPK zHIr-tdZE|CK+ra7xtP*A2`bs!@poLgdHVX-L9ne8Qe!8|$8 zLTD|6dyHNg2S-_LQ#$Qk(4)TKg|Gq@0#pxv3P2sY1Dq1Rq@_4T_!d29a2`G2 zsN-oef;dex4DrxS_w|}M=EU6CTET|ly2T^sEcKD9g=56+U!=Si?!;BFeJxzN(qdY- z+Mo^&g|rbU{AM5&DetKlB_|@g(N?1GU~a4*7diP}WK%;U73t?*XLgMObo284NC7hO zSWJ)=`xc~}V~e=eRy94L0$bdW*ccxy=Q;f@S+TlF!$h|xj@OM|V_1hB$#D#mTp$)9 zV&tRNmJ_c3z3ZGad^Zh;Xe=gU?1FyS5B=mc^FHo_7CWo_a!~?o%D~Ky1AT;DO~C7t z*@XOt{qnaxmXEZ=Unyq_PD$}oHeHsoa7g&NrCUE>XYbx1&V2 zAG*F#p~B0(j@{x9GFmwf7YK~@9&=;$T*kCfj_qt-xXl47Qh4f@+{OvjhDEjA4?kom zn+U`6AAcy;JkYL6&v!XT$9C3^$|cm0kK7;rBaz-yl*Qt67`TMBlceLCnk3o1(D2WQ z{FqzS0%BFs{fvU5KM3b!pF7b;y!brSa+&_K^34sSw1~O90hN32R6f*C&O60EM>Nwh zuS;8Uto^vM)~q?lmzi827$^n{_Hh_duE<~ZP3DX|)FO9qDY-Jcj`>JFORqJ%O0F1+ zHM2*&GR-%|F)g_(JbVRuZM-fWKjPqF1{CH~Z&}8O_2-WDymQmmz{CQBz-PCtM-+0^ zX27D;9pD8td^0p01R6~sT>bYrp-F;}&jSPN@h4*chawV? zNE$dp&2#>YzVi|qC7M%07$=n60C+AC0E2MJqs1&b!A4k@;~|Rkh)~~J<zG*tkz zqp1R{dHp?3RM|l=7cemW3&VN}f>M_mgmCp_|9^>IMMJoSs3=fI5tZ80{ssrOY8?Q> z3lzyYJ92~SL4Yz;h{0kU#46|#g1?doh0vO13U39#r~o8^GjI%y+@M69zX;d}WAVRF#noZ+%)i5MF%9BDWU;y5}cU- z;;H%nK4YD667`$b}|14s&JNMm3` ze5n8kNYX$cxycY^Wq<5|YI+aY-~j`$0E&jdM*$d34n_5RgZBT7@5xZCu>zu?CL*(z zm$UO}vfiK6kAE~mn3T|BJ!JnYJ1)ZE>P19%(H}8RTYH~$_Lf5v!=D3?TMH$|`IeJ{ zXh0L32%#DolwZ*)1ege;q>3s0GoR1*nL;0~4G0R5$%5%@+MVyzaI$~s^vDfTk@*XZ zhX`;YJ3&A(Of9CxvQ+u2)gOlE%R$SY5&+(FgThr2RW~?^(V9CTvdgGY`kk-vif(3a zZ4_(ZdYAd{($W8zS@(QFRX#NC-}L{AiH-0rW<>EstFej(yk`K2dWGOWC07wyWz;B~ z^IJ{P<*c+u$@#bT6#}yqj6yiSRg)i$i4NdEQP(~;p^`Hyt@ZqDKEKOL3JuS}{X{sz zbNf2atayGK0Qvw1dH`b!r*|(Bt9LfVwz)Ti+#Ay2j5O0e9D0M!G6@51P1)VB| zgIbzFFcs6I>~KD@3Vk951)u0ce0u$$l3mXI+sqp6)v(7Ab{x$>sO8S`nSBneyXOC2XDr8_BAe@7NAq4!D1Hbxn`6vJVAASvX A)Bpeg delta 40116 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 diff --git a/spirit/lib/spirit-core-element-2.1.30.jar b/spirit/lib/spirit-core-element-2.1.30.jar index b232ce3591cfe44ca8da2458c0e4c6452b84f1af..ac7c90dc20376deaa8839b90bea681c393aa1fb3 100644 GIT binary patch delta 32387 zcmZ6yV{~Rs*DV~|b~;Wvwv&!++qRu6HafZDq+{DQJMP%FZJoaF_dVb9d}r)YWB#Zb zyLRm{YSmnG%}V$Q9vlpguP6f!0S5vD0|T<|ex&?{^`l+~1O&wNZ^HoEH(@8RkZ4d# zO)SYwNlvovA2>5e%h5^6fx`1*k%Nh0`l633-(kc&Ox(wiWGK6KDc1{yX&&Pa;-`bU z-8h4SD9S*?{P!#WXEG2NkbfpiC?N;Wa@|dsBK{YyDgFT<4k+EfC;`g+FZzJ8gF9#+ z0UJQM|HUiNAODMtKqew+#Q(hVpHVGfjKFUqP{499xPM2rfC+;CoeKB@_WfU^1Q+-h zEx?uk!G=z72vDSd7G6S%Ys?M@0+Ndb>_a05_Vz8bL{o6+;ddUY44gx|C4OD<3 z|7TX<3j``aM`i8@#%FUVlrRJx_El8WEEpQ-Sea;4$O*J9f4>FDZ85M*79M6QRHQrvMt6ua7Or#(_>Jt8a< zY8b&3N7-dI)jQkho67RxRh!=2Y!f`oeA_vXh=e{M8B)YR=yg|ak~Y#XIaPPJ5Podu zk_Xw8&4GpYJ_P~S9-H7`1+y%)cAy-gu$d4OMyItOy}S7Y*lu4_TECt|3ggmp13rTGf~iADtd|fVq1qHkg)j`aG?fB_Q)#w^Ewp)HL~Ys8 zfUykj$glA7Xg=xDNN!vv6~m!qSz{7TBL<7S7gHmKk&YC)tmUW|)|8UX6?kH6BW4h# zlvLhotkE+lV$`ENZ@%v={F0O^YXi!zCnyWd;jj;gy8tu7}0 z@;PkkhEdWls)$sk%#(sp$Ld?U9IaGVY|+$?J6%FA#-UM3dtHRtek7o~%q5V)lyMi0 z;S2PiJ^r5^0`hmy|93z!qfZMd{kz{QfB}jMfM(D=im)`paj3e``k_7)1UL?q^KB5h zaZRGN;G%?dTu}MUMyol>jaiBf+0;L-dGK~5c0-GQTxHgh7y$Bs-`L)p6O#32>4xuq z{&y*Fmu*+;2mD=cpOb4K&D%Yw^CHppf<%1~F))kUjh2*{h2ImxaD`xSnOP|^So7=h z0YA54UMg|2F(AHt*hq8cb)mxuge7+}jHf^{SOC~0cY<~zeF^XxI=<>if+ z`uSuo?gqQ?5mrV#RxIIaBZ)8NM7f$H1+XqN$uNtk6Qtoq52N3i`81^@B<3X0i(gX- zGvm539iH9umR2|`Mkj7)Y$OsaRmd6FED%YT+E@p2_W+x@@)aQ2i;5*RIj|kPzsIkr zkanDb_r5rA%{gJaTOhM*AmQy5ADYsCKclBGN?3(3lR#KUCuZpL<7Y4c z);Ur%ZDb_WaA${>{jBxgy3-CkfPChFkOuh_W=m!yvVbdaC_Oz~JGg99wv=xw&0Pcq zcflOz&wcbpAASdem8KE_G~n79+BfU3exiwNHe zMjErTP;bn5L;7F~1B&zxz`to<{j! zHqqH>bLo`6G(}O>#%D270@_t|`_$Bd_LvUF0VKt{oX_-ovO`xtRh$r)BDvV|T2_W# zymfeNc=W8lqs|=A`Fqvy>^!T=&%11CTA{orN(t*o`vU zn>dSBnt$(om;tLMlx9z2aEZq=q(%%&rmq^`ym2>euvf_uS~d#!=)Kv7r$J!-?y8@m z1F+1v_w|^95=4)D<;h*?3pF?!tk$A&oWig6eqs@=d-y(I&rp$9>io%N!H;Yxv1QkC z6v2JE`Gi|;C%fzr1*9K1hr?g<>;)HAzB8jDUR}e^-x%6&2u_PdLf;tKshXvVFV&bEiHMFo`d@;a}6T-`0|b!0s!p&cJ^1-NIWmXf33I;Xl!p#L9@BA6|G%lo2Fy03ge3@ z^DXB?dtG(?0^DglS(nX!DG13)7{6Xx9N2V0Ys!4#~sC z)9(P;lc%}FE~&8sp9{1b{8c56!X8oAG659EZr7tHsT}aOj%uj6J)5*ObRc`fTplEH zaBT)Va3U`HzUZdnT21D-f_di38Fk^-U|0^vq~?jC188H|5m`Q@<=v;Ph;uvmrqPKc z)(x?uhLcw0_(B)D02#W_-G6ZotyE{)@}~=&*KY$I1Nj=?%}sDo_9D6NkRWJ4%sT() z3I}R&`eV~I^r;AgYGz9V2sTsN5CbW}xY5ah`OEwPnn*J#ECcelx zMQ6kZ*Y<$HfqdxJW_94@8h>DwbMX2tRI@AR?@V_HlUSkK2KIRrQW07cM3NU(qy<)4 z5bP=^HW|OHGeHphbIgP^yYH`F465uDVdRo_a0@ehgF!$r z#EsC#M)2)QA}uVuwOa93Ye|LW;Ek(ilftz9$L~gBZ6l}&72T?D!-d4!PJ-uMza#*9 z(joIuTUVJRTV}P?a8Q^CG@jat%hX&@o#6{`VIDFbxFya`8?o*QM$_}6gLdc8yS?|||prImgQ3S~G) zdP~eZjnkU`bpgoDj1KOcE*RHIHf5{j83 z>z>G4t-KL=H0>^~`O?EIJb3_kc!)nuV7(lDc{39e{4R|@F3d_2qkos{E_q(~7`_ci zW%D_h_UXUAICcg~pYuQngS)Zmgivbtg0C^2tKtV~EI_q;{Im4`Uf2Jh(8;5FJj)@1 zfIJg}fbawRI2nO8TIc|1Pn9Li&v^P1soQAg=0F%Gr``anAQ1Q3$Y8q^bVjD1T!fbsY_5&`758@O%B2d1i9t(vK-u7Bb>kUT@1tqzpb z=N2vKy~TiwGo5Je7^WsWYFigG)(*#YZN;#-NnK|1W}xkN^IK7B^|b*d-G8IaP2^aQ zTGE-wodMXq@QFw0J}tNl`tLC41oC%29@)*XGFU+5b$tq=N-#d8ITDjRg)Mqkx)>^sdXhJ@bCo+1yKl%fokvA@UXb zv9|kP4SkjK-=9FqvQ&$#`mg<|?8PLOivZt58Sc~zlXIE`%#6rbxJ*^$R2$0|bhpt8 zlt#G7)#7UpXH6e1w8){k%J%oJT7Wk{+W-q_PxQa(iz@~-g$*qdLq#X})%$mKXRu;d z<47J-S(WTk35j=tha?7^$c%{^_uhhGM`ALY2SS;ajUy4I9YLPY=n>bffv@Fv8RXKqyVhKEl!ZuB^=~412n<>- z;}aqo;`+aQ_m_-}a^gPfHOPJ15i|n!)H&hjT)!7{=Rf6ejhv|pyI5=^JINA~ostLH zAr1I5oz#*wZFbZ1u6c8usY;viBm<)H?kv0I;g6*+!=05w%*KNqQc($)mqU}W-k!*xYhu$VLEK$6$JI7nmb`f^l&;Q zrPbo$n1j1p-xa<^(3o7??hRNRoihm`Pr{Me#F%N*JNnUOHJU?G= z_Ddx_oowFLACcb)RMgi4>IB?Ttwk3?UY3c^$_1fipCD4gcX~eGKEB&(hm#aZx1jy{ zE*B>2leV$B>PR4b!;_lLJKR~J~~W^8~fBC8noNXG$=rhtRwlB(Ku>f5Xpo46USwg+3T_ zl?zYd4>`&OT!v8#xfEq(CF%!}s6p8zFTc}^&5fpthMH*jpW%C!lA8}&k@lHupe~Y^ z;-n7}v{ULnv7!KgbM02-wUWL(;|cGc%7#}tKC<4f+V91)cdcWmSC5?2EtN?3VyY6; zIz8N3SG+s?^eF}sKvL$lMhoiR1)&#WYiXx$sytA$L81WP?KEGXka6f2-op*hY_UkD zgmAWHDu_8#KSkcsQVhBFwvXYVcvssL0Ur!u>X%qTqyYf$ffcLW)(5~M?rC~!CIc^- zTz9b!9rhxWl5d;NY@}d>aiq6te)>Dz%f{J*H^#AbOId@*KqY%C*taIXET$MW_4FWh zAF{iOb#BMnH4pzb2bvsNnCR_U<7dx1M^MKj#IaB|hM`0TjApF^#IT4CV)^XC022W*A8M zJZ=*W_X(@1JG%X0LuV@*I3KN{G-As(4c$?hbq|x=LnGb7T!U)M?WNrqRlJP4+f=iaF*Cav)MJW+`sP-x%p)(_ z?`MGNTw}xRl3ntYtX{PeMXi8Lu;jJJA|z&iYU(yNR_=psVWmPzh$tWTW^~MX^7P&!?JD9aAlEMXccTIP zViLahD`^h_4+cTXj;*-jFfHnw2^M0jU%jf?9IZ1pK%boEIee_Wn745y^mpUL3dKsg=xg?;qinvg|=EDjD*&_<5XjI zubpBV-Z9mTkNYa7VG{>)SBNk=C&mM~eNV{^E~PZG`d$NPhtVxxkC$HI1#>v>x3CJoakZ1geF(&TG;qOp zrkVI5kJ!W{_+)qp3`zPV)jg68uNc&&zSmkZJSt)KH=?0xgJ&)>b3kNE zy|l)J`9vm(%+AZ%59O;~6vbt(Wd-U`G?dEvi{T&k4}F}|ZtAg)Fsu11_Z+SXLXE_w zq1xt4uBEM0#vIc-Qxe~Fh1&Dm*<~K?*}|3@=Hcn)Dt>r(^q<_}bWdAguto&N#`m@N ze#bJ0h3KS#=?NIx2;@~kDQ*H(Hd2OhnkpT`wGs)RF>AU-m+bUy^h%YlsCajQc+8>N z0`HrJX0_LpATVl2X8bXRPONAw=u^h8ci&mVXcszlCm+t=`)q49@**U{N64YyKvM41 zD)z>kv-P$ns-WFpkSBX7yY?ATvfTd;%L|4Z%EzaLs$SnawJ-4V1`s0 z+`Md%%5RI6?_3NA{`_(j)szRPEUi;}=I-UUm(kHtp97YX+_w}Ikh9uF@F!iqotZsy z=LKZQb*6FJnEhMJs0L6k zg#?Fy&}hO@FH`O)G%i}hH#SMySO*AGH$B%#IQP%|G<2SMEI5wY<9!Rmb{C(;{pEBY zJN1nEj^q!H>5I6`s3G)4Y)e%bKlk<%sk`Eg?bf?Z48C!+~Z7Qq+n2IYZc8{)_* zd<2bf$-HcOO%fchc>*wj$_cr)g5cMjbIef)?n?;+%MnAQ%*nA@UaTD`#q6(!co>&% z(gdQ6U*H+wq_^88vv60KPfNobRbA8@EmahUz-~QciKNEdx>Gu6RNX$FV=60EInVe~ z3yn$tv3aQKv|B#R)@qJyq9HL(wo#wa1vDy92D_-Q)Ytq}b_TexHjxNvm10B^PimRD zv~{SepQRNTY%L2jw5ICI14#x`@^I6T|#gZ^z#8kIVtmWbc(5)?W96#{}z-7*OB*5 z`y}etz`~K&vBhew+-qvWvi?}Bj(m6ZbHWDc$wMf)*1ZLaG`aH3cWfd$+&5CP414A% z?LKP8dJSQZnAJE|q|=M0^I1|zRd$;PG)Mwl?V0l^AfPJb)4ZXR9VPTgxH*~g3__xguo5?|QJ;;BHZ?ZN!4wmi&XDBT$^(HFL395vdZm0hXSDBELsm25fm#}8X zjqnIp)>wLkz+hceyq^XzxOApo_WMEMd4fW0Me+(%8sV`tNX2Bg56(Qj*u;9`%@Q(m zb$!x!5-^iivRLBU8Baiu2zV>w9scarVvtUgZ^mxulCp1X5O_Jv>iXfI2K5@clsVl~ z{0L!X0tQEJkJ85~3dtml^APVCsY5;G_koV} zTfmP=1iqW0Cq868?yNQT7H6?j#i}favwf?3%s?k!{OZnoS;Bo@l zJs#e?8c0~Fm1X-*V0a*|byj~=&3Ce$5DR1(rz^7fR-)AmZ)uefTG1I~MaFaiET zwp@6T{FaN2wr$awC^u{k$K*?BN9d&pY(VY@OO!_hl?kRut9)7zWFmnmSK&u&Hp=FL z+XpeZux4S7I5CTUs(p6q@xFCwRxY5k^FUdLq;&teoO)?;@$EU<6oW^@q`_tE-O<)P z9NwiTGPEZMOUDa=-MrBgl~G|noUxQg+xC`Ocn;AOXnRy%NN8a%$&zxDokpEZ2@sIc z4B+7o(8>R<8*K&=Un(F^1XyPkryR)c0(PB%bCFb(jwN+J&!w9Sr}*Q%DdHEQJ3@2UK<# z{pdyf+XIgV0>b)N{v-Lve9+)w!2yZ(PavLm_j$DZs}9=zZDJrmp*C({ZWj^&ahw^c zp9w*HhhO;;C9(|*C9(?K*!Y-4_H|A>-)TQXdOdsM%BLhekkG~ZW46mlD}ho#QKcCF z00(KAL3@N&k2=RhQ?}=VJ6?=adl2+g#!X${#L&gd9ZU0KX3)0gBRmd7zxjisff&;C7IS1sFDEe&m(P3f|4H}Sq6=I)1YZCnVb0Zqy>7^!}0eWv8+7N6wO&?@Cke+lzh zcopM%P*vt14AtdrFFVaKV6L|cY^e2Fr$V@$(XHJs%GBmv#E4V6<8;J&jyBxhfSTl2 z_(=vi#eb&CP{vsqxm6irbUBknB^LQ^BClU?dCk>+3}-umUoC1^Tl@Hn^w+td zP1LRHm+Vu;0mL`}?rYBcJ%UpcIZ5hx%un(dPLC57t#myn><@Q$8eYBk!@raOe|{cl z>*tsqN_?#OKkToS^IKm&3?O4oGQ&s5mNK?wt8f(w(Z;?Y%FQ84i%Fl;ET~)(2^@4@ zneuKj);HZnmv`Z}gg_*GgU%Xl6;he+1j}3uV6~3b0{r_U3_ovgHTuY}uQ1)$>+u=p2!=DykJT|Dl3AU=B|?8i zS|Q>mk)5%1F6K1dmsz$D(s?U;Qwv&jdmUmu-)nZ)D``=4kshjCv3NP-_`s{l`(&2v zeKK~W0oX?MKABvDFJlA~qxp+IGw)D^SBKXdP3hZvywi#@aNaE5H5`Aav30NL?FDw77Y0Whoco)l-Ct2G;QxjvR@rmX>I?&o{2N8RY> zj+XF)y}6?wSFlN*18ONWm)%dHqq{|v*vn3w>m{TfcFN%dA~41I5Uo8L3JMQYT^2fe zkx+fLvspiiN(KDJf=`R%o62p2MI!1i()fE$rpYs%tLnMQ_Ub+0%+a4%V04-d+n}0_*Ep8r3VY$20g5??aRZ91ka->7&;%fM{_r0hyM2DV_^Te;Am!_a z0h$!&JYgqK&G^jHN_5GU^`}%8Z4>0-62o>673keQs$oLMtNDs!n#<=+oq!VVh zY0kXH)JP9t6mSn{_DIcAN^G}j7*S{>yvA@8yb>g>Zj)TR#uyTuV@hoI0W_QuN!;1> zktOG-G$USP=Go2#l2$iKcb;Q%qz6dZ^`RxQkx9H>V=sI~l*)%*V~~6YSPAvLDh&HH zjOa9W*|&7r&YFd;o?~KsX6l7m+cemBN!$s}*a|NM+0G@BTKhDq*GX}bCx1VhuZULJ zo9|$S?|>+weo%$sfaWP0kksKd=HfY4Av(s-cfgW;8z9-1TB19pviVK zcMm3u7gnjWlI!=(rf!~|VqR6SqRH>4?)>u&VoywrY))7`Pp?bz%AxT)N+Wjtshp6z zn|f!ol$|0wG_1WMKeWT0qF{>psMO!|n32>Ak+z1B=ZsYK+>(XKfT64rj1Ko+5;|UX5oOk?AsU`M)!4YPadNu#v)NLyw{@$ z<|D;I&8V@#=V?730KL;|Jl%H`qw|oh0GiyUrI};WI+gUqmY#>2X4t z(tr&zl>jO|blW~{UVgOpN*|P))ZLPw<*?X(jz!^9|v5ql-a~lh>#rhbrH~s^ZZUi6P6Wty?$6?XY z2V^dE#kJE6kF8UU&0)^*$G{pm7raNr;gqp=mkHixWJkzXhv=QX(KFG^I(>$Kk%wZ4 zSB>Q*s^1m5-xcFI~oajQF>kG*2STNh;Af#`Ct*K#-IjBSEMSoZ0KvFeAhq)m*p2D$SA; z>Qd{-uK_>>g(&aMU`=BD@l^e z)jQhmq(z2W(HEk){dH(F3?mVLnW(LWMCkwrWv<6)xc|t z4(zyIS+9yxn^xeetw#o&d9x<0iwMuA5l<$+OP#jL(WSB|hm2JtXyH1w>3Hccl zs|`#Qb4QHpgr14S?5~JUN;4#Gc&JhZbipk1}f>IX%3#7i*ChZKW54v;W6DMfx*Gj)>v>6hnSCbZaU&kMzg`vA=TF?uVc8DILfWXJk&T` z<8uIdfc%@Lc-W*s{@UgdkZ@KMdMqhvLgFVCJz6B%y<1`SYlsylCd;Ah)@`X*$NtPa_ z(+J?g8&I=I(-W8-WF4ZKr)>_8|WNau1&&_smtoe$39i3 zkJ&3TQ2`QR+#1g7O>lXYtd{NO;T&Ks_NVMCs5K*G)rqC**w^ZC8Z3-B&FA7y&HYqz z2hk4nNj^sDDTNDh$Y#vM#4;x28kB7&;#^fzqWB=Yex)_9CihIlm zm|ZZNp={1%m(q;YL^%r0{WUH3d%abua%I#G4FSCIriK^)OlYca!d3GQG$^W5T6m7c zsgey^+3}q`UUPX&v~~fxUt^}GigDVqGj;wz95#=MRmr)Ix%2@Wft{7KaNucdaw+UY zP=q74NbabWYm)39;|H%~yC-R|*?#I#)Wu}>=nhrXyiT_8tOuC|5=mL=}z7O3| z>S?sLX-VFTk(I35?rUka8rLoGuN-rGi>pZ+(HJgGZGf7HWfv&EV-@`F5S7Z*w%}FP z@C`%1t?JU*Z1vX3V>|k3RRpS!~#sEU=GzgTDk4{8gOynr&V%6V=bF@B(hB4WeopY!D`fFl`@VK=nhJa^Uo1X&a{E zh0FvMHB?SPCpYW9m;n!o3)vvN*e|-z)|_umE{%d(|cyAP!pbmU>0DaF-+0#W#{BIawEn z>n6|Bp$^E)*&A(IQ-bLrj;A0oFr5;O@v?A+UCjkeMC{xI&6|Br7g(CiVHz;_0wk=* z=1Gz;c5tNeI|sOIWYWv+;k}_9-2uUj$7d2+#J=H1LqcCDhu^s(oN+(aNgLszAE)ke^>}nijZ@J%ggy0nGw)z+ z74iFh@uKS>{nGUD=i_$45?pG^33wKi`N8a=4{NJ}a(+(zKs?ODN``R2ftt_p`&fZ_vw>V3JkN()N^`4T{cHxdm|Z~qkyQ3-K_aoZPh5xzBT{;ULNq{4`o{abRc zUlf3Kk5KuZd1|_yt^mF$;Uzl#5pGm}IsBdp%f5_edejgEo85DK!S11(#Xz1CKX@~P z#bD7m;S~bQ?k0)Bo>26!iR(>if#}}be1pwq>s$F*6HC>x{zMfG;~k)E4N6Hxh3NjV zz#Ybos5IQi&-9jLdWR3_hQSn3ozpLvI$Lx2T0<^>F?iukx+IoFK)UN}i@ZRuxgvSy zZV#4eX`}n19@!E9$$2d+IX2nEIo-R-2kz5=5Yd8vvXkHtG?FlxT!)4Lvu@Gvf_BHw zH3sExDDzEipWVxzF~167SO^}j9pZgEXaHj8ke~nB0RO}N{#*Y0_hwL>$(p6h zU;VEX>0eqXGl&mp(y-IO7sKg7hsg|~uQIgivlbbGgJ^HW6f31JQmx3V3Q(19+8_s~ zBkyqXQ0Z-X{rogJ<>nt6Q|ftBc!%`A^Rz%$&M36o<<8EUn7HJ7nqu|H_RHQ7{Caut z0AbuN!HF{z9~i2Gsz}A9Pe{4yqx_Fdw%T?{wj; zI?7FUZbhB7=JmyphBjKWFgJ==YpSo);;EC>8gs=o!7Q?yn*8pIL%X#6ZS(x&hfK}b zeY-29JjI;+lxCeT4I-mMTZ%&=p#~lct;_5qBI|`toE1~%pQ2Qc0-!GqwYs~Bh(l+ z+dl)=8HC$*q~oE#IkwB&qL4L!MmY8r2((HpolG`PR9I@%Ta=~$$OjFC=Cr}R5&tbmnYnNpM<2;Q?cx&e%pswRC*)BftlCf** zI8<>Gwv*+5Z%T|ilF{H1IAAHx(%r1Xtcn9bKtaBqEgFF85|&)&#}N_CZJ%5#{kb8C zJCi*p!?QnK?k$cxnkg}o83})u+!i%asz`Zh)mPP0CH%noa~&C{;3Q*MiyF%ATfFDu zo3|(9Ta@ypom(J2fBGy=v*-sXPx>6k0t=tcoOy(IYA)zoePn9v3S?)K2bE(I(WArm07dWJaGf4JgzQFXODqE_Xfs zLRE9wYoLaFz(T**f6=t5nw|m?gEavJor!boTU^fE;vtRj+%*uHhnffVq}H3s6J}KS zPU=FE*BWG?3zkE+su!;wo7eJc7@@2zYMOcd?ESvezh2aqRumy=K-@~~Op+ad^3AQH zhAbz{tDcsq#aUL#_7Dsg6kWY&s7$JijY*ZVG9B@K!M}5heFSU z4ZaT!MqA_hr9nz=@e~E8L@M4x{6oL%hukAHpnUoS_-YYvSfNR>sByu=xe)zXAfRxD zM+0s#NX|zrFlc5D)k;!@<=sG6BCZQ@ zIbqYEHw_YsUXtMTBh(lNKm7sV^$!sqM~kd2b1rrUbFi-pVjbQG=2c(w^UZ|Rr4TkU zQnqJw^y|@k{K?CpYH_-LM6g1>*uFOQS=#1k|AOJ$Z$bUALGmT~L1#%eUkd#G@TUR7 zLcBGa#v73Q$)FT)c5iTDlalg_D?F8HjPP;W>{EP3G$xQa2Iv-I;RXe$QS7CG;|bI# z8%KNGV;?JF)1tMh4{K;dHKjdO+yBLImrZqbmKFWuy-MI{6K1|ckq04umA#Hwx>0c9 z9zX6qsHBEkj(VFl@<%c*MHEV;(03M1v_fA^J5W!AD%bW*q>9O*=nymL@Sxc1n;#Oj z2`B&uCDIB~$4oWUV@^=yv9K5=YLyR`(^D*~lCxmwpe~fZ)@Cf&vl&8F>%gepH z3&LJZO71x4EEJY93%H4~hYBB1R_Bs~#Yyhl2#NUL@y#STMno-)E< z@~*8R&t?T(T+r3mf&Q&6fy7a=-w3zwXh$;o=1P zjY6Bhq$J1ZmH1WATb}VsHU$Ov12$`5f|vD*?}~MLg16!2Bd4MVY&nt`Tr(aO)&qLG zPe?!Jnshi?q?3z)yvHZVu$2)I084PU_X!fWCkleREo9G6zOw_OeGT&@umS@qrC&&1 z2yPiZHbVK4w)@};f@j{kM@NhJqqA$AfP6Woz|1jFHCjImVoN z**@&wcl7u0{tzR7h~PAIgiN&M4vU93?$j8O@I(ygJ7m67xMXCjTT%SNWDbK9*L3h+^PSjPaG4DqME1j!^ozFkPTA%ZgP1jHj#$F`fThk?Qpk3B~`Wgo=|ipLp^%tioH5|s+V7ur~hld)Pw zD9wx=cjku)7WlUilV0v5D)sjL#dsv~ruWH!2o)6+;ATDr)ywjg+nBwOzRHK*A)Vg<|afV7ekDy@Lvi1E>sVi=!$23>Li&Ae+MsAmD zfCH8WLHmU`K$f=PCtbJH5>EMxubNi6M_2??h;&=DYhkoU?J2J!_O3#s0qvo!L@9=c zK&n@f}+B|Y&jv2sevj_Jjq zE~V9JNOkrYO*{RL46ebB4z37J$~ED@W5%?)oJ-URpus7y$ULhUp8^ki8jl}#Y`;^* z#5|8;$0whVb8F^9A&C|ME!|hz4N;MByJPo^lUUqH zlh`oxWQ3hYG-i;nL{Dgk&mNMTT#oW*-i)EvA`0xB6cYfexps&a^}Z{8%8t1|*cli3 z4sDXzP0~eAGE* zv;dXvW``KHGS{*vr1L&p#;qko_yt-mq*tb{X4qQvH|*bQG7r7%jRZZiJprU%jj@j( zLEj4ElNnglncu@6>o%*rDyIs_TEn7Du>VhAZvhp@^1KZP2n2V62X_nZ?(XjH?hx4E zu8YG$aCdi?;7-sW!QBZV$+zL&U;fE`&-rHe91c5AS6A0mPxbVa{QM4VXd{W6lpXwj z_JI&Gf+5?w%nx&I$ewFjg%O zGh}0&AxGO~<^6hA!5?SDv~YaYa>+-2F79>gPm4~2)lj1g5*Oyx7j7N==q0x4q$-2 zl_>+GvjwQdL$&yvv>tl2!-dvR(S^1AmsS$EF(P`4bt!%{x_F~1DUe9hLdqiWg%yHM z51CwRyw_|h4WAMeT@`N5I=t_{owcv}?)-c@-^+aQW}rL&Q;@4NU@ZjYYAVd^omMEG zI8n;iR#b5`JXtzt9mfk(nn+Z+AGO=@P9(7}%9Qm6B)4I=A(@uL=X5n6sgM1mu>o0y ziWgH<`45=cQPXS1`45N!bUUsr0!$?D^f=uuRr&}&wq75Jv+KIMk?|I5W<|^=22V$; z&yyog92R-B>F6w;0L0ywKcqiosVl`$EG&N2mJ7{d?<6&TS7nr3SKgLyy)2{M>`tXy zW5-aAt0T<{I*F`IX*kJitV*9-EQDj}GfrnSt>lpUW}(qdUaAX;`P>2hf>O6GhW@@gk|ey_i@>Ei}Sy_9i@I~3Te_bO#1(mvT` zBi4Kveby~(kiQ<~lg_ddg3fwi(90DBn6Toh%eBU8PDPX|B~)y=I3Hv2KGu)Lyd+67 zDbj5VDub%KasYnmI1GLXj-&a;)Z4?yCY{Yw7MlI(NaI|{T zT9K{w@s|3;$Lp&EGk#sib@3eCs;qB>hGA(T8+bO>t$-5B3@(f?{PjZZ;-$@jmkpmh zwv~b^Y3w3`&^@9Kbul=dh5B0Gs5WcjbBcPVs(hn!{kE!s5x!Shrax`r?vMj@YldSv zMcaaZu66;}97znol8{cW7)*F!&e{~#(%`b}qORxhz3N317gCTcIFC9@|3 zVHm&%k44#CsgWC05}D)3AN1V3X>P|6HU*VJuTub1w$Nu#`4dzJ(dIa8mAVGU$%hvg zFNh8#rfjg9v9pXLp6qNXj`KYF-WG8VD6`CZi09^qYzEoXN@0hXRjpUet6)~|#4&^z z0=!ckCD_aS8nGd4LUbW`jKWkuz--*j*}KepG~1b8%)Y)S3oYhsTD;mXMb}0P(pY6@|1}^+w2LL#cip5yigbXlLI^K#l>WvY8lwY zq(P=ncR3fYou;n6`F=KkO^pH z5s-Buf~=)^92tNhz`O{v=BAUJ?ZpdpB)Q436@_x27r#A;hE;cZ#n5EmMwmQ?$)#ga=f)2;!W$4y~0IxpBat?NSvrbp7$nRIQZUhI`AKfvvYcZ9d=-$1 zW72L~DM4f(`1!E^d?24|7h5EjylowRr}$;Vw#d2J{KLZQc~kk4$ha~kjVu>^=FiZl z$P)Mt;+boZ3_){{_FZTtcoJ1^&WCQPLf&3^LRd@rZprsZNU);A9kXS|nt*av%XXY2 z^)4~~FK_`KLP@@9V}71=lcw_GukXs)&TWa%)K|`zeDDVjDZ~9yNMCRE%L&oX*)Yb> z+;rh>IOAR-#Vkjm@gx3Aqi^;cjR|G!So?h^``gP^&KfF1e z#NM@y*!0yZkR%6r6MAm+XaQ`|IX%O|S1~qa3<$%-N+$hV6aUxKqe{=2 zVR0Pfix)yLFJ1_PAGS>$?U^jC-OPdGoPXVu zO(%x=n0zI6OaxEApEykc4@Iuf=f@{Gn!4 zpK%EQSGPMVAndTpYxHsu&vUumqr5kef5oaSeJf*sdQSkUB{u(K7TX_p+;(kQVinw#=F<^9gINrYY5$f0#vpg=r~a&5=+Ji0Z`13CTXIF8grS2o=`3$CD=aBZ@*F7$S^`#MgL%NC7p) z5N)kr`!@GBBt*JW9YIw`lR?f_zrH3mF$9T!{DYX%_qc0voJU^)-Wbz8sX!N&_{X&~ zzi{xSX-O#K4~PZ9i`>z;TRQSa95F8yvL;uUkI3qFs{)O z4m9K6f4nytQhlo$ktV`q!2-<+3TO6VW~E8Pk4Wn>7}tZhpd2~@wfFx}O_LdqI^(U$ z@(F`BdsV+hv4KdJ@%=gK;!mahTb&OO{IL(gTS{^WzdV3{Z7DINfZb&^d_6J5F@MTu znysEL4mF7PKtc!uF}0N6*yO6n$mUzq6)?Ou1f3|%7G|#3pjcf7OrdODLOoPJ8PB-H z`o#Y9ej@dUMv?5S*Itor-C`jaRm`-Y*99aD1LCD#5S=xJ8?I>v<6^+wt-mvDFLvwc}H+h z-x`}9z{%7) zk<%m#WL~~^L3|VL@H9mZa*+4a>SGb7s9ScV%Sk~lxT6`l!m+=Sf(p_*!UTjuYzJ72A+hScs!we+z{Ct-n`ZY7#f&u)!c)^uawFv0v;o z%&r45x&UP8UnOXkB?eXG=I1uvQTui|nu30*2wRd=^Bll-#}CWQGM^iv=`lKFziY^- zwi*k-S2ARF#SJw@ogZnYv=50}(-^yn#^*b`H8}>xUQ1|F^ce&koB80?-Y%0 z(h%|qY=ofea--Cx@HnDre~V50EP6!p@h0|JVg;8p4TKQ&g2fL~62l({^xY=0@5o<2 zVnl?fmv~O!uIpP}r=Rh99a*xh#6sYC0uep{u&r-qs)=5~&N@T71{j@0Y*W8ui;N_tl`f6ILHB#By;zIb)NbZ!^JM|B zMKrDH*C)HZJNOC^EI5FAJD$`|u47_X$7;Es#r^pnlny#vB03j%!4+1@wPH*a-&6Wh zVJF&VGJ^|y_zfV7lbN7Dgi9`(d^#YCQewetW*{v>mXeWmfbtzv#gbQ#k-YaC6v{FM zoU3>e9!fqEngWWR6rC8VYK^n2s1sJ3e9qS0tRio*>go4UrzPa|LQ<^9d4i(m7h$wk%a|{t zOn96;oiANG^J$gzWC|u}Z9I^TvJL5OKys~s+e@W!Heag95MN;>BfP(Cs4q#+Z0Vck zAfwGDJB9$jdDr`GWsd#KF*|7~OsSLq@=&~*-enVt{S*2J(L9a7&JtAWXH=UVu-gE4 zX&{4}aZZS{USX&479J(N-Y~i7S#7(6m1B&efcw`x%&y^SSI_KMd<=aJ z`^8WSnNzZY&Smb|$}b(XS|W52Pj&C}WU@?ZGU?v{O4kfvLKD`jUJz>IR}_(>5Fnvp z99ytt(tUp;lFYdesu|Cb@oV|4Ih^IcoU`r>YOBwburwp?kWto$Qyx|~H^UkEAz&XS zH!{6DhkR=bp*kje>hDuuYB}G$m)dIpL=)z0ROYuLm9AWX?SUXD=#pQ^$(#S8m{gJc zxb>t95W^`#aGdG8An-H8iC(MR&F$q3kHzC3!WQ$5)?@x z8YopnRYrgkD-{>}oubWf zZ@(h?84l=#Lz&U3UH}=Qy3M^?qQcljS6B$3uWRF8aYhmd z-d`IHJH2>i`V#Dn=dhN)X|RSp_?_Sc!oyFgmxOPi_f1tlnO9QSuo+*~bRZR150E80 z5tYMD6>Q3-wbQ@UoWUo!)wNZ&e@rruDtHSJlSp$&{Nd)ww=5dPOFqD&p+htqaw=t2 zJz39rE_@cr>d>~*3!$s@MYjCh>blD-&!{f9nVLi@w*Po{t-;AtDePDHA-ei zW<8vr>+((LQJ(#^AukUcW1TRkd$VdE5kozybyJyIX<&J)K)uW{EACi9a%(ikNMj7( z#3mu?vFWU^?x1d#+>rmgkSP@x^X@%|)pV*?T=HymXGZ0< z;v*hfTA}pIV=0k5A9iv*4RgGx1g-c_HBRjl4U+D{vgL*vp%%zjh3xb+C)&*Ws7~IimS`b4WZMP z_ek&t$a}tGU6df(C9pRnjYy`vRSNj=vqy}1FaYEYv3FENX4j0vcBCUv6J1O(Uo>ds z@ChRmo%~fAOE!r!5(8`6VutLXjYE!vn~TO{Wflm1)m;IIH?7?-t6ni!PcB;vh_S1+ zx6ks0Q`E0EK}w|6nJyy@;J_-c(HU~3<*Ah(w6IIK?1;p^$cs)@>xi~B>&V+y?~tgp zEjMqCwY6O~*oxJ%E*1z}0tZfaMswoVXbu{86mHvhz@h}EwMcvK(l#ySD z(G-btk^9n`2A}BTgVrF`gW4b(z>aEA?cETYfaWE1SApp2^0G7nZ;kMvvR&e3a%464 z2`85XX&F~618vu!C%VQ2WfbjQ4Ly}mTUGY5^T;AgpCE`vQ!#;j7e8NBNv&%Yt7%V1 z4Hlm+d&~OKa2dMyt3zd5f-086E!7smcZaQHea_pCH-L14( z>>HS-l3Xj~?ptjO!^yYg6=^Pyo=CBgn5Wh6`r#?xYHNJ^+UWarzen1pP=}VHuAy~< zw%zo{NQwmhXnK+a>4tf_0wb9n&vYHb-CUP+^<9dK32U26#vY7)F}1q8ewf~l|2ZsQ zGh*wSAgK-qom`)`zI2r9dqAM-f^t*W^lFizq0aCQvObv_qeko({R7@Z4Hr)DmM>In zT}gdaTvBsrqG|nSQdsQ9ksl}@Opc}!rI3qT+P5dv_T5JzY~|7vx>Dr}g(60;GKB?8 z^L)0l*qf5}H~~MnD&3ZDy_5Qj?$dmzU=n50Bni24pgh|hc;|BzO95OlL~3h2geKZE z(wz4g{bq4XZKV`8qVrhvzF7~Jk&Z0>q#z%9Tl&;OgLV6izB3lKVPgn?rU}*e`7f18GYr7A~IRx6BATu z8A4n$904l>WpHBX@{JhralS87=e)Z1S%_HhP=_Ju`$Xs^$Wjs-vn_c1r1S#lAf`-g z5-piq@uu3~HC3IO4yy8yY6g>R`2+Ex0{t37mxeJ^R@MB)1pu!61QrYLy<2*ArVo6v zxCT1C+#;@!-WXNiZUk6uzqFx3^`I zYLWG(I;}rWdYl)L!WsRNOv~r>b?LzChtJqU_*AvwmIus$i0jzo-Rq;ocU4RuEirSw z6Lif_iqiQF3Y|`JN+#2f51OrLLreJsuHiaK^lO-;a{5djF}ve~a(WWcNwL3*QP$2g zHAPX}G=PR!;2cdLaK|W~qW27D?FJLTx@WMtDn%7Fwa1}i5?|&OexyZJ_0_ZkItH63Crno?AUj2pg@t;8^;wzX|hYl zBV#*cM10NkYrE@DOZvC51+XzgJv)~Oz%L$If%m-5feNtv09#iKb4-7Zbqmfz5o4?Z zj@>+J>p9fjqFI&F!VoDdTh%BRpnV+!!p9;DPS_2mO?|XMS!Kb4=({MMzG!tfx2J7v z%ZBbg!GP4q6UyZx&RiZIkGAvd`xEYc{(bMsuJgTN!LA?3J(L~T13YUOVnm7T2g9A{ zFp!_3zL~8N0fNK*VqLmf37m>vfwq)TQ8t}WIYnJVg(XuH6Fe&1a7EEW%?X?vLW4~q z=p`j2G(u^}_N^q%_^8Rw`D)BQvB0y$j(JH9!R=p4TY72rk)glA+H_=>>vzCV!g3%$ zCHD9-+xC7X*!XBYtXn&gjy46UR%%IEA0t~tvb;v^3AFXtSoQbJ82)=rgAH5If8{) zTZd__zM3qnh0ydxMOf5rNJ!j?x^J$-ZmL4p3xgh&xRgdmRHIdO#_nji$FTWlJMbRL zgf*kydVtmw?euy(PDB!2miF-7IWz%o6^T~+Q2S$%G8@w`;&LSJc5xirFi96_!Nbd8 z6_nP9nHl;cuE_}ixq-fGnPVMFW^qkQK8)lC5fR3Lri84;FA_H$7Dc=hA}RIRqv`0J z^8BBB4eH!x-M{J8)-Pv$ED5Q=a`ija+i*6}MFWJ3XXj|oLmEG7k~rZWWFI~LObiJ4 z$;u(em^O}eMbkOvw9&g#x^CMEtP6aL_Z5%E3sUhaM&$xC`}MTjt*w-oL@!O&-jBMK zh`Wlw{fmx3uuTk1y{HS+1Sh6ug*WKeh6Wv|#P_^`uHG?!tWdsyF(^RALQSvcR^v4GtoEDYj)4sn**DjIaxnV(T$g@_wp(@bV&t^ zvXvRl`}xOfk}amu$X+e?*k3k zx3+k5>~{%je_R$0T~Mw$(QD$YM!|hbM8yE<&&!6g8)=2=8z;~s&Oq8em^UF$=D_wY zBXV&#zuwW`>})%fg~g_RK;1g*hHo*-Ld zLV0LUatReon(Iis0YFv5rb?q_gT?RqK7IL?Ftu(1 zvRP3Yt4(32A7od88&uI~LTtVU)es;rgb0ji zMJKml;cNM2+&X^Quan9_#L`3)7s$EK6ADw7~wRtz{Fq=Ns6tiZ9(pIGZ}RXey4O}9z96Uc=EGu zibRhq1NraEd(QK*d8+!edJDJ%TbIqUC;d*X?4LCPDjK8{y9RF*=yBWGnT&&?>3Is<0bc#d1RO6l zT^_DmXDw38?G382m*0j~C?00JF?|y7w;8E;S)j$1+zi`a&4Qiw085}~w(q20-pE+TW zURarl#N_HOb@A`bw|HOu0sz}J5UV2&nE`tQb7Dd^3^(i0*AS-I=8VJ7C2V5Q&;Jn4 zG*&FN&FTZ_C5rpJE$}YP?*Zc5B?j`QCBc=I&91W3jJq&n!LZyAdT+zP*r-z3q><^? zj9_nX+kh%m)|hEuxektO^gZp;(*2fmPsv1r2>)sCo6C9YeYWQr_fPG!&g(CLH{OUn zE{$yAjB6U<3to+(t3em7L4M$%FQl{hJq4s{q;2ySSr|`SFMU+;7I_N;L#d-TNRF^3 zvbCfXEe~?jS-x63&$f_K_+H3wf+jdKJt=Jzv5W7RVJ%Cd>yQoq*z^btOVe zkqq*Z+l#zVUcPqLen>+UWSpQX_*%f0leiZlQsuAHZyDI~GKZlL_>dJ^960~=`f42; z@*yvj3A*;R;p@9J>g(InsuNtZTrR=|D4=N3j3Eyv(y-bgYHe8YlrekdG%Ca!bq^gnUXghkq=}D=&+RtB19ka4o66-*H5(E`fyn zSRL*%;dtec%vRa=G{`WTdB^>OQU>xQXiv2?K3T4SKAsk7xrl#_8rkkPKZlQlvzDT? zbDcI=cvo554{K>h_r{@V_O2}QBgV_s6n@MyMTb|CWd22iYYdngS=lyg>1PLp&J@FR z>PD7GIqvjb?Jz@c0S0`B`8=KkoalaA$hv%8W!Zs8ai+Y`bmBtJVfF(}%{Wk#U3mUt z!){uBaQ%}7B|{fKhrpZ4IVTmWi~Mh23&ZmoBxYmWmT@(5T}A;Z6k{<8KExeT`Ky2W z`g5VSJLjVXCCm52nr3UVFg0>9aXf-hxFgJ!9k&S@xcLiH7{Fwjv%UnMDB3BNH3&hE zF>|PR#ixqhl;a-PL)Z+QZV5GH=t{o$lvNRt1WqTSVZpX-uUvkB8q`Q-qH3i$#F3tz zkZOZzYgErZLxxaFJivgo^%w&>AZP7G^g5~l-L^^$Cg2zATGx|3M9{;ek%9QY4IINye+yiY!EozEYfNke8n|W~#)D-)a68)~XxOeUpm!ec9&JQ|FcVfg$TQZOK(s5vlnUV4> zs0UPnMm#(uaVgoUTqfQdv-YAJ-`hpEk@XoD=F_;Avva{6F_S|dS^4g)P+C+t6q41Z zr7K(?+ec4HiHe#^4lm3|?eCuDdH&p!MzyxLKaO_eXlztbr0d*R+ueB6a2vCZzq+zC zQk&#}|5g>|{A@m-VI{4xU_{0<4NAfzw+A58{%Q#>$YGqt`1&OB3u2UNyUZ6_^x>0F zX?ZSaUnXbtp32h~Ik67X^OD zymS=_UL1T2QVX7JvcyT6<$?RSpn}YwwU4et4E6M|j5(Jl8-is=jmz}++)1t!z5_hDyIAhfGU;5h- zUW^qG#M!lT(;9V0_`T<661Ho0!t?;Nynh-MRYFM^=~vgbFyg4PC~rq>fe9r`Dkf?D zvQxaZ&sWn`_DFmc+qdKg`(u&zv+x&9LLvWKG)(HXxQx*<8(gA*l(1nm9C72y?xK0X z%U(Xaile>6pLqWDKfe~+NKj9nm%Js)nAhT(!H>{<3ajNm9B|^eIfe2nA-P=uK7eeUE z(bSL=8V8EZ!MMC|nBz*5&(x79CNdKca@>)nSqyOU_~PMnxzlbO`Dt6en5-zKi$fWs zcnVVj;oM)cS%>s}ARWTItDs~z057#@4~A%im13~8LS+w!46k0smO#ngBxeTQfp{gg6>b(o4Eds-e5FBCf7QDq~@_27Kta!B1 z4L3v=NEwfcSo*|bexqk5=A{)M-klHX*)8!}W=IV*_DDTB{tpt&L-DJ7fgcHp-*hWn8Vh~ zjO9!) zN9rTWR^4SHwhNy-#%XJM%32@Qr%HqL{L$=*Z(p4EK6NnJ)<+a7U_NkV>?Uz{YwrD{ zx9ptOS1D^fw35Q_9?e1D5V4^*`Q0XWMX5{SD^1C(iNvn~{#x7PB=p;QO?J+u;*lEV zx(x(XFfNU)8!4m+dozu|O>Vr-kng)O{c61bBKk9z@cK~J+-oa*#0N>$hK7Wtzl z#82p7%j9yL|1E~G|FcZ4CoG+XevbTvRCHFe1^a#E!#~Hq5Q}01G(M|hXkz~0fYS!j zQ@%H!eA3v~GLKE=_+~&>+ zmd+ivw%baHn8l~Af7{7A=iP7LUuy;Yyx&%Q!8sF67J<*4HS`Vc-TTZdSGrh~%Y?NS zemM!xot7{~_3^=6z*ZMqnr1CARZgjv+GT4X7e*gD9Yb#>eBxJzrv96hw+wzE>@M&o z;;#J`dAlyq&265R-%AHikUFJs?j)*A3ze3)Lr2yrq7N#pGqNV1BN4;xs&@w5ZefS-@-2M770a?crp@$hFoCK-IYuoM) z2%UR%JWKm4rOKG5>rU-4n(@tZRHL#(RUEDHaQS&xPnCPI4^w%@M zG4+F_w;Y9U0MJ&~rch}3#bD}0VuMm_FT_>fSX^z6TapKcvU+_W2_eCf#p~*+3+2;L zJks|go#uP_zV zbqw3^XI7UL)0;9QZlKa~lnQI6z2)F`k8UzsUAvtwY(WUC%Jb)x={)=7Q)!OhSI}$n zHVszDydBUnDZS0nX-4!BOHW%5A(SW(2r5#dgjNp#MAwx?5&AGwF2c3#CBJVrAyyug>K&LLjKV&nG z8rxn@tSp#T`j8OIbk4O3E;I(#qro8b;wR%GncQ-+> z0kTX{Ctr}d4c__`nC{`4uDX(LdR!V;-p{|SErSy>?_E^#PB)LdLGdfw=E$%(ck~T6w3l_ z^uK@Ue?>6Uh^-XBpXC$rN#>5J;ETkf=@T>nZP!{?STOf`fNdi|sc9mMqOuD8np;I~ z2vuZdj`@bENX_g(m=jBk{j@Lx$&DUHImV|n_MD_EP7H@Bmw$M(nqS)RP zJiUe41iM=Dg5UA}_O$>KQNe+8r~LDZcTjCi1?*axd07RFkrEEk8+QL_{ zvQ1^A(Cp#7o6$$;vOv!&SBTVJ zvMb-)s==5ZOT*Uh(K3Y4F~X4B+DD(%7)>2nq0JF;T7c6>*L1DKsbQY9Wqre>J8c_@ zv?7XaK%8taXLztN30R4=#qDcgu-|AJbx7c)DJ3U9ad%*j&avA!PnYk|8D)nJ{U{;L z{4$32RcJsPCN62WhFiW``H@OzNPUb;23d(l2Hr7(&qq-uryw_r@s2`-C6b<{Vx8{* zBkFI38i4R!nbqtpNU_3VR~jC8#OfbmBY03WZ;WUgN1D`)PS_rCeZ7nwz944 z4%4_tJoMY9y@cyy2pO*&$nj)}6mtO@+6!Y*PlXo_MV4+$S{nuJDS($Db)rciXV>Ia z^0a-@a%{aaR{#L?W_Gt2ABJfrGW+0C-c%cLPJS8w>qC!Okk!eDbcvJ%q=C;ton*yu zAT|!)Ug9<@H99!1Acs1Jx{f3Y>~4}{Dqf7w5_5eI$nOv{aY%-zYNC2fT<|9{t;q6E zNYftPr&NBgj(9*8k&id>M>!$rg)qKBpC_)3#%L#pkORzVN*jf9-6wjcNaO^I5>*E5 z-|q0u;B$STA;TWQzaj17e~F10<42X(pWT9n{?>^*btDI zP?-O3(OaNiBRkQrNMNvE^6vv2EBx<)`r=d=1gvSqc`i&l)`*Wi06z1}fmuoR7e(*{ z1ba38Dq{P+5ubbS-*dm5o6Y}=_^Su7`^CSnDUNGnJ%*&BP9JNzZt|28K3t1$sksP%7#{)^}Q3$G8xOZ>`^3yf&RhpdAF4=uW;~-7XrVVzj#p)&CuY&^a zfC@;{hW`xwv-%kKU%+nkUy=ouD`5eD_Wwh5WJPQASLnJVI9mH}s+0IY;}%LFT{poq z)jtb+G5$prh4AIN6R5NyYPfoHUr2zpslvmxc@lSi3O5i+ZNNXc+T7Ul$uxc=~^o`Ty=5f2I;- z`K!^60GLB6AYDH$6gaaWFnbsu@=@|%US6Vm+1vex6fm{}AM!-{H*3`d=)YO}GXc%t znqVypZa@qS?x%Vd*q@mX{s!i&KLce4sGjA(4Q9tr7c6XUVBGLO8uUB)0r(RBt;dIk zzcdK`|MDRKtJ?{l$#iz&L$VqF%QMz*P53kN^KWHzH+jCm44rt-{Qemw^0)Zrt)5l< zvi~38pZ@p1f=2##6a;KKJ?j=SEx~Vb{dPnB<&ytDB=~PZz=kWBS1KUk;6K{nJ%kTQ z?G5IL0a#WH51bhKM-qQ}&awa1e#z&*l9=hkc$S1rH$J3`|1&GG-4xG*`_m`j@4;;a zKeKT=i2DpwtsYre1Z&(*~ z2mJgh^cO{~6d-et!ZXWj;L%s)K6gMo{Q9|r-)l**CHuRBfa2%tK`Dv~g4H3&gyoMI2*YT?{F-Z=sTDM&*?{m*^=-s``f z00af}&lBP+$UvL&hU4c6{|yi1|Aa(bV7h;!6fpC@(HEHg-`E1o{cmIkVNA4df`tFy zTm5qtJIIfJ&vyJhi(~JH-3Q7{2Qr31^$heph}>B|3YIgC>SvOKiPKH zstFN-0s%!PIw0}`HkD9?koZxFU@u^pcW%mrP*gB(Qi*8Xg#!e@=p$RlO`!ravzM+# zj&i-{Fq^$^LFszO8_YPUP>RFKC*)>jas?LoOWk@uU+&TS(D^1873`Tq8W}>E1i}g; zQ7EPkvmzhb_I@q+&&Fk^#4oYJc||6(e`UPe&H1d%93fXOd9`S^k5o1iMd3k1c%#NrTY?C8{j4QQEt7@l{YU ziB5e`Br`g9o*V|1x#5RBQa`J5r(IYarGS?|W znjkK=T^T^Q;cY$IBR0Y%c5m|!9$f*`GTXrbgsOT0iVoW)td%<*X@fo?pTn~3zG~X2 zz~!#%!$bseMeaypDXzD1{hGgdG|-uK`@GS@-5GvMlE886F6zHz%A#wMlc~YXMys9< zaev~DHi zJ^O|QNanwzRDEyCP`8ezbhw?kW2u#!nn229kGLiQ5C_ArKJ6oLte}opAx-r_$NCD_r8CUT z@p8DHgE?-o)8$X!e|@?xE;e@(tamcYtoSeCl8&vL53U9B0Y7Uou4t}{ulP2w{+_i* z3OzkruhkxTYkU2g#Y%e#yY#v+No#O5i#3rXZKsx=VYfUNxwT;Pg1GG31bO1{hqOnN z8@0w6tzL!JDP)#kL4Rw~n?^7oK6 zV*hyJ@O0}Rx4|A1;r*bKJQzLCs|%I4_Q5}CzXU>Uf@4)zX(Q5`A|lP7F@6f2+09(p>>3i z#(X#-VSzRGalCxTa)fT7lmqT4p@VIx8N5+#9Z^wLR>hN8$xIZ7VU_G;c(4ZWjx6^q zGT14V_^EeEQ33CLDf?qo6I=|37TAi)Rf)8Vr4JY z*rPe@O$#eNNnUQ&v5cwFaVDl2FAma)uwmt{ZX9_GFg5j>GR$fGI!{kvlkJ|H)@yKC zXnxeHfAE+zUNX$-=8p#u);rc*lvFU$-3<&Rq(Cjy!uW*(c6DaIQ(h3ibLtHo_nTDd zjQ{8j`hZ@XJk`+KPQVnHA4?bQiFOS=OZHE?i~g9Lt|i`=hmku#b4!J{Z4#t)N3W%J z$G4+$N42Boie^Qbp>fAOLHm=ZE(G(A))m-#+Njvy=^pq~=f@?$vpT(A=31@9h_VB( z^j8!behSGW;vYEI$15d!0zmw2j$cde;s(rDL}>dLv7VwHKFrs#DMr{Z*U%vhMfXYU zgXQrssF?ZDa?M_V_V#jy@M!CY`BR{D&_A*%3^ zk7l&qp*yn8A@(+ampD-n*bSP2F|N}i^(kJV!z|CL&Z-Qc@Z$p_bBu5G=>k7`)kT6H zZ1my~hd%RY9Yt2}OrGI1LCnXLTkoVy+e#33WvkGwzDfZ0G!_r->sLCjiUzO$6FYg+HTr2pJ`)4a2hzi z?G>^n7_zO~gikA|FeeW0D;!pyqjyd|NWft|Sl%FkDQ@8({Xww__beZ@XA6d>%_V)y zaI3d@j~x_=1`_4~=Q+XCQ-qr z$$&Xm#_{6V?U_kvxt&Gm68)f7^*VHNV&DkEQ9RVr6)efAv^nH!Md536*^1!0#c;4D zJ(Vcp<;TS<^2S~80TRzE8o4O)K^BWC``lZY^hoYqj;l|j1l&%Kx?2WyZ-UfNi!H$wUm_KfJBz^Z9SM!b~1s)!$ z?B2Tc!R=Cg)2*+2GwHPqp}&)Fdwb-yyy@-H*ug9?I&!6|`O!aHu&kd@A)Ba5ZSM;Z zfBYzrpJvhrM)D5FZ_WX0LR#{w3ysbqlkkFG6c9KYH28A}7Vd!?yGPnXmrD{2Sa{$4 zSbqUW*n>ehkj5KWb%)#CgU&6%=wU<8F!lcL17n^|SyUOn=rP*=+eoFRmXURNv~o8Q zB8?8IWDy5%I42uk5acgrkwg6_H2q)3TZiy<-1nEIwgM*#@(?A8<6{6iVFnc7`0rHp z1NY>YhUsj#VR+E-csksx^F=IaS1b2wxnF>Nlh!JT0sc@K4RRso4FhX=n<(=8~1_A3e1{uquXD}jCU7OhhQu2CWEY)&ep z$!bK2mJ~F*g~|$n`5YhOwQnb&^L0mXc-;O0>Hp2@{{iVnTRs5DzvLH8m@0qkZ{pSo zzi1QVs-OWTj%31iwoWcKCXNh7)&@>a$#TqcgFle6;QM1_{n$Q;f-TxYK!6LvgMxxY z3}`=(ni?2*atk}zV+;3y`CuFnz{6CmS$PZ7vp-+Fy&&zQMPm~2%z|Wa2YHEgRA#k5 zE0Py`R2ehraoam}P$M>4^d^zG(kn~WBbR-gyvzXrt|TavZN&cDLYK3?f)u$G4y}EA z_6(;iR9l(dat@2CgBb|gi9i16yw_`yI71y}zT~NuJEQrBKhi#{9w=|PtFmI^jVj*W zVTC>$DM^tiutH0MNM%q3<*Wnf>Tl>rtz*IEP*bp2$&WSf!2emL|5*ayzpDiIpF*gS zjfWEi`5%oie@sDk3JwIM2oD6r@!zBdpx|g>=V;;VA!lc7@?VQpt!Cqds*2{zu|7?4 z)*=f-k5N&8wnat{3>N95Tn0{RLEVG_Tee*y-4S;gvJJ0=cKi8>c{^-(Uraa@uW}hx zsP8n9?i;28 z>!LoarrH_tMnh@Bpd%Vh5p6j|*7+$AL5_vo(LI$yJ5|${LZUrIl@lY+H&;1@%^S!X?{OVAiWKE0wdiIHb4que?QlW}+&<7YqK zicDk-78X*8c{X`za+Q(705CTd@bTPl$Z-k<6Df)ADsMN@#ze|WCyv%wf>ZvH>X|>{ zyU`5KDwvd3{LX9@AGO&SQZAno3ERP6NRQ@xygOkLtU1lGwyqvQ(JGKMtvT$R<9BLN zYK+w4Jk#*lq&FAYaaJ-}qiDZyQ7*f{2^Vg9LY-+N>jxEAlk&*o0f_NRof3M3Q=Zpd zH6@!Yc44Dzg)?fSa2;`e?6O6SRtkG~Gzk5sT%Gc`XsSG_kufJn&>nFCruW#+u5e{9 zqtMXbCJ#Jkt$Q3>GRF|7D8-(MzOpR9<|SkA=bk@U62n}EBMrE$0&JIa_)gLNr16;s z|FqPk<%+H2lV@wD0;C-=oQWJmNms5OS|?q648~VeX5ir$2pt8Y&R86C1qvM`9MgHQ zrIgH=Qj9?7SMwePNW%zftTpr1EMt~V^v%^7;9OJPjL_kx$vn`ES&lFU^6;^)nX_(G z-OpQ8TA%zug($S?;wb%`(&~$W|Ek{2xuY<&u2em@@m4~U0T_kQ-#~NKsRCGb)a^kz z*Pm-qz0kJ?Xki5ULSY03>Y`%Ny#wS;yi4|+@RV=ia#ZUeyI~rp?19A5;S4nTv3TY7 zPCYx=;kooUU?QU!ber>+A5-l_`Y~S;==BvL-&`9@9Jg0RT7m*txoC;h^xZvI&PTNR zW*&PSkHo^=0pf@7q%!k07Qqd^Zz!cA1>0hV|@V$7;wr z!D+J9LK%_pLB2oD(eHhNK)FU;4C;l@apN*ii)1_A!=T!t@ySHMKVU2lAe;WE=52Yr zJnQ}>B9XL0QPgrHl{(&kbXHiGe+_Zt<$Ic!wKaRp$#EPS%~Jwe6Bh&`4ZN%1t!OCEiB%rJUS{ z1ehn@W!xin7-tpqGIeuawm&}biSj-W)q`Ddt7QsGH&`)}#@x4g#Z94AY9%6;q!ov)IaMTj8DC8FhhC-71O z)Y9R9KocTW4iJD5pmd8=1Q3nU8SE2d1MIRuK{7$#3~u8Y?^9tER_n6$a%N&`U|gAQ z(fQ`*ug33STwO0o+5>Xl<`pf)#BH$fo3&`)ifyniRrxe$FIGnJtly>|Plocc`SY%( z@N)-@^%MOqDtpw7wXSSC1tVk(3sKARHN9M%H(pP{KIYTO33Hqg>~4KxK0p-ZNEyP* za9pJEK*VK0|??7b6F4kAQQ&?jV2M=T&WFB?YV|u2(v8%FG6vwC3qrv~t!x>5)b>&vqX$ z$~;!Inj;};G0CG+%B=V0DaH)HFR=z`MX4iI`ocKMZB?F-2=Sq1sg~jsu_L_RJe6D$ zIRzbd?#zj??qaAXTkQw~&GuyA*izGEw#a<#!a^-10H`$QQw8n3pZdNL$cH4UT}d)> z^0Klvb(1!BUC?8jV&BS014(}ndB2$6fF#GC{M-r8F(&Itj-#zI!&xls%I!d9;4E8A zX2QNg6oNrzU_RN-Sum!ll-Y21y#ZKvMIezbvVD^-k^@!f+I<&jyFFRp%9?m+(-&=& zoe^F%008>tfFJti5EMB6t&ntI_%h)Z8KVrvi)<@ImqZ}t7JBnDN%I4{j1DqYJd5S1 z3WdLDDwkynZWNzIf~GC$t*x4i{Gjl--d&p489Lql=?!TS2#@9)D03=>wCcONE6+a^`It&pKU8RZNuXqen zE!$`GQl@cu5W~@B8?^FHA9=(Syg61Kn>{06zna7B#{7}FW&3k6>-be#1;j(nD&+%E zW?vscso48s#qROe}EenCr(m(iuI*f^@gzTCjU4>elH)siBoS* zcvw%$NA7SWVYEsKvm^HobwYVEDsn|h0kkWjgfQv!s+4 zWTlnH3`u-Z>dF}aU{(4#h`43y)u8Y0XSG25V@=oj%LW;`Y+fWjn8Y74DyVlL0N!2_g)T^ICRG#$~##$&riy}^&=xs4#D^>J) zXCzygTqh6=lSn*mB{?K!lFGO(zi0*Rgp;T+#R=@=M)!|D@Z%-)fv2wzWoBd;tv@hD-1uJbAvn2yvGwA`wXu;rO(b>7Y3=0 zqa(F<;8rWTmtq|_ThD=Vl#4vrs|ia1v-0lVT*42HY=Bro`xKGU>?uNu94~vugscw4 zM6P?ne{kkMLF9jN=5HHB3A&tusqL?jL;b5_M1c}x8@Utn+Q9(!j&}AYj?NY)PBwD< zkpn-Fu0UTAL01^8_%eUcpx<%ThTBhb9GXT|j?b{9Lp|Rx5@s|YP zu8gM5em7|6ZoU5HZhanc{CxUuMD55YbHLCAKv#!E^Z!hR8$}Z(BaVI0ionx zw=2A^DIx3W(=v$hxdY>ckn(y8d{{GI;NRiQmM#}4aFFZ#T;tBF>Z^y971wX~hl^%F zuSA>Z0Nc88wQE|Q{wSDdkv=A$`npZ6%)R47HSdsiS7hbS?!`Aox0qammm3B=HtpGB9nkYeAZypqPlT79;+; z0ZiYSXf=wZ4HH$**nz_tq?zljW;He4@fKJVL>7}e+sF};4%>%88!o_6j#*FR5qpK{ zk*q*FDig*7-XAVh&ahlDo$H#QU86xPMoH_KrMRTolFa6$1G{E{u!JLKAncRblzH%K z4nxLGkU1S9_o8zKmJ*l`Mxx0c@v&i1g%fw7PHhsm$UfcR+)}#&NftVh zfrBQYosUqd1RL(xusRDF9V;#3SMx=5`QdWZH0itm2_%_38;6y1Ezzz0*)4tl<0kja z{rNsSs}HnNXEHEgg9_Vbbii<(t|2lkf-X&w;-HU6OQB|9l?v(kobN9VL4d14N@Z;i zh@GSlurBue5x04Vh~00V?RDw1Y13ez%b{&qtn!S%!IMY4>e`i-II4qWy@J2n9NT6* zg#nD%-h?k`%wffx>akD~^Sj5)jx!i;xvO92T=M#IUZJi|?3Y9R6_-pHKTRw&1q@y+NwM~|JAUF>UUJS@)(QZ3k%~(o&S;Ve zExFW#^sZ1(xg>=8vPKw&xPnq4VA-XQJ&KmR!{uNQz8Jgsa8fXiTU1f<2{vj={da?z zCI99qjaZfAs-WrFy33ZrJ7*zO`hs-!v@v6!CmvDlSbL-YrIgQ*cWhd0xJaur2!&u6 zb?L7XROVozDPtH@3S=WVLsMm@#_+U!p{buRrZu7KHxLXO z2h~)Cuf6{i@PC%+|9vfQ;tBx&+hzy&T0{K%#Vm>$^k2)dw+c034h9HlEzvGT0-z4< zuCk2&WoMeeneGw9^n)l535l8ZFd$4a3W3<12v-sgOvERhZ*Sa~Vx|kYV423Ux?tI| znPU6urxj*lFpyI9wzbt&&yDL}RkXIU@^#WZ4jUu{y!qPmk8L)?|9tt}Q~Ld|h6Wu2;F=LgamY@PyTpP?nb;5$Pe75 ze*6r6hqS{u2O0Dn2;w7=7YdGpev0f*fPOj%a)oZ53uh#BIqFY@Fma0nAVA$BHh7gl ziiKqeqWnD-3$rh&=_?ZwJ9!I@EkHe33M1(wHCP(hhLj7v-{`J2coMMmioO2)3e=Og zA1PEdkQ($kiPMA9r+(B|JN|Y7;zR0ZH*uiN;;qfJi+tJ%>@7d|%>MC%SkU&GO&JDO z%W&L(3}cdGTEcTqO4F4LkRp?gY%~|q1SOsQ)546xKpWIFHo4{Pz?3asVk5+c9MvND zh<(qN80NBSpIrRS z&D?%#G?K!m!fn+7Kw3|}U?M$qfkRccPt}52rvxT*))2kcqGmM5tv-l|oyK4#Jy6F= zUBP_c3oRpeMG1Kkv^5YPQuzK$?>e2%9-wUpbY96Rlg;H&^p^?d@Dm14tfs>>^ zdqMV{vRt_Xpnj-~&fYpb<&U4Awc$|X&+cRLy}w*7#rM17^D-APSv5?dW7F<1rfR1T zYEyWo4rghXRn5{#8z0<(E3q^$eWkvj`}9hV*4|~3E;$|6?zi&zhVEXpVbm_%L4L%m zm(aR&{@$t|x*m|_`3k~yxkTc(>x- z{E6|u(N6V2x{2m`!QWzkFrp|C6(#-f0C~ObD*5;mHnFPWU&EGMTj{3&L#+Wmp8vCB zVHpj7^>Dd^CgDg0JHjN5LO2c7v(A<;DFzXz6^D8!&s0i%aT!i_dPy}rqqy#mu_x4` z==6#KATL%u#_LS(DQ6%7m6jx4Q;M=Y?&os-2Bh75ldS9la%~mbPu=Nie0o{+CQMzb_X8j|Hljkg{XgriH&U@R+{gE!Iy zV5}U?U7OmXxtC^5Y`$Ed)u2yE&d=b44|SozkC(AYb5cU3mBpJ_H@0^qXI-CNnPe?v z0O%P)gQhm*B-hPr`!%NswA=A4oZ7sU?VekS2j?*}C92aG(a1tgLQgTsd1?73FEWNAMg85jHYPc3iHqX^+IDS`jm-17}^& z=Xd6ln#qidJEw$5rK#!`uCraHif~(H0Bd}m1>B1VLwd;VZ-dB`EpaI<2Rr%XjxJ_z zQ`v#ko@aHXkh1uI`-P<(b2BGr(aAfJ$%j@ipoD-!38vNd zVlnjG=dGikDY&(nd71e+iMa3%jxS+4V?EfQhv-4zA6-3YK$`_yL3pc9s(tOLPJXPr zym*XWu0(sAnH6nJ?`SAIRs$^@A@(-&V9ys!Sru@ zUp6be-{bU~F<+M<74vS1ENLn$Oni{E2y#Sz!38&eWhi|Mfj!jKRHTx9CvP>L44YYs zQP13zF(GEK9vcaiz*mNvKKs%UHXj0rW``d1?5- z;p?DY?a}MWhuWHK2RCAhFBvy04bgs%V2;h)j;Y~8dtg;3&5dAJ_Ts@XNE z+4e}cnM}7XZ7xd-aH}mA?$GeL&;+D1d!{ZTGgH(RwGOlOWXw-98Pyu}=*=#}JI{)6 zT;A)nO*-w@RKaRH)OhC&W}R)8UF~y14IP z%^2yagib=i3D^EvM4o)^)907Uc@SsHRlb5Ub*jMaXOnvb$S}%b!m&s>; zQasXQQ#lcgf%WnkeuT7FRIlxA6FLqId#i(_#S1wANiF1?RNS9>9mdUW&vQ>?wHjXK zamst)k^iX;I3lh(eVpBn9m!y>s(MU)8U5o_`B6%%}7lSD8%kfx5Bi$ zIK-3rGul!kjBlVd*obG8`S-nD*K-s+xuXyy0)&+q}%|FB-n|D*Mg{yG$NJWX1jtU5R{lGVI{KX$RJCpm1?Exq(g#VlUtg9dp`=lE1U*em-PC3? zfRws%S(2hz@gYZ0G=WJ#H|t9^nX_&JEs1b$QqpPm_Iz`_{`vU+jtFE`c0R|PD+B?n ziKe&^FQ%y#iIY;)NSBQcUlO7Uv5hj&n(4nM4)>ZZe6hv?3NYY3rmfUA7+bn(u?p`y zfxEzzugt&Du-&Xe9kfyRBxyb-whN!YU|vw&Y#zoC&R-j4ykaTJ@p{*h+GGIWJ7;X! zX~>3>1moA5aCfHINejZ14Dn{d=x$qh;5XX9&P*59Tx||mdkAp05AtrIAN$+6w6){6 zimA%z4t3w;0EjswzL!%gbP-|=dbrY*aHjGtMg~)^;D0mGspDn}4~5*}!mlsIC3Y_m z1lG?YR`nrwrl7`Q6~?&^4YyRd8Az<;Rao2q=9*%JyAZ4O^4~pRwBa89c&$_atqbb0 z#TgfzzwhrKs=-1sZ(dJx@L0*|tOE{961W3dpJX*gRy3dQ=~cqnmhh!qiJC zuwi)Hxv1JSz_+aU-0;WyqjwWsX5L|lRDawHRqFG_{OI_lG-Vz#cRF4M?Ac_@iB!)0 zmhSS_eujVa!(uu=Bn!`#0Qf)UBMRopcEvk^Wz)Hv*Oe^RELp z*ueal{CB|H0WHyAn(W_UY>{U4L=03!fL@<_I5EXqgOGK;wFA?yhyZvnUalXDEGeT; zzbuSR#rzg2EH<3&7Rk3|Qs9VS-OctGW76 zx%Uzo(*eJNGkYt-=|}8MzC;A5lLxutmhAtLD!ahrD$HIy&>WQ*hJ@Q(Uv|+6=wf6o zkuD=(lKHgf;IGgg+%S)zo%fef0!ZVp(g}CHM>eoptf3GPN|-L(K@ZM9w(;9&grLfs z((%`n{%Nx1xpR<~zPJ;9n|h66=g3N5nC?!8?KF=hJyuarwu}fGd39%9^qAT~S>GlE zngI-^hj-R>dX~34j-@fNQ(7r%>Qh5YFHulw+ol=41(P0reUh=gNGWG<1CR+F=?1gb zmXqW1WRA!SV8O>cSd4fw3^tzCos|X}h{dJl;4K#g$S3Lev$;!mzwzkdJ5r?L%%>cs zbLA|?5At115R%nVnI9j5jhZ*s(!Li?@R;Z}^M5!*yB$S4PmWJU@pg#*amYAee9TNr z;6)86sI!eB=OeA8{PU4t2*3fA;JQ%34oo><0(lYmHMg8RU$RFnW(3V*!aKp-!DK!d zL%4;)!KWZMB^fgDp*av-;Yqzpj6k%te)-Q^_JNT?>-LHl&*oR0y zM6g8!UR&7~L%+a^`_6JH-$DLX(HVs&L6AScYPsv$$(h-Z zdoSDRv0&Gv;rTswip_sU)mDChVO#l9$n}zounI0| z=0?CmuTV^n*Li$l1E{GBbF$$e=3~Dn(3TSO{2m%`dD>Q4nGb)H-*zI++WCxg!b$e%yfo%PRoC-2*7EJi3B z0NpAkYr-Ao*)`+VBdE)MAL7h(0!L@x>#E|Sxbj6$aImYRB4Z{c#I__<f&)8j0BikZ0Z6tt?}Qn6ZobB|i^M7yY+j_%kZ!dY5__1# z%Bf^NE`Lo5(uxr%`!Kiq>mM}^$CmI180+Jx==8!L9t+~-5iYwZiMUWY4#OQ=fd}r} zcxe?NGUx=O9M{q>NGp<2Dnuin0~<{@=Jm8n2#9M z0Dzh0CHwuMzFptpwhZjq@X)FhlUlAR-GC>|bJh26!}K}Wh!|oY(mGmvD2q&DX$>#sNNlHP z5Eeb&fYGo4|NA*rO=nW0x;DTlu$$5d*g^%K!?Q|}-z}KMKAOZ5N=1q}s{4?N^nQ~H zC*Dkt;^o>s>nO$&o(31r&{g>28g|4>BNV13>xx1=%tHi3Q=$vJcR+ew|AA;3hj+Zd zUE5eBvfIIqVh10eZBY;ogR72U5Bj~xtuo6J++{Jn38m{Jn!>Q#Nvlhb)gJK!u=ja^ zO-S#2?8(v_cq6}%#AikSTOkdrU`Z>rIghEp-d~{Oi&}6uh4fZn00u#FVdPs;ZU6|P zn}>{l@|nrR)VAqv^;~Ir&C7JKT%8g1!5?;m;K-xDxtOac6=LLMzBOA3p9zlEf6HJs&&$C=?Tg#;$ z?}!3eG{Pa0EWs}m95VD!Yz}b^hFC)o`N4kXtkF8@L7{u!Bn$VncNp?qCw_9}FQ8S< zwxB6AsPsEw+9^Mej862Sw0mLN>(Fku`!wnBxQ)|yAK2esa2TTfaRCP4fLRF?Nbphr z=Q^?eF@iIKLluVW&Uprw%k_+~(>mWeypxDED>LJoo-i?im8k*-8j9HCIR}UMjE?Q@ zI`x}P2N=TrMcA>viavsHEbA|Ukud!d^@aFKv+f8Q=UIjVFI!NJvji|V3I&+Qj`&9& zzu0zlp6Hv7bQOQQMq2=-fJ!*vVD|+xgXx@BO34+DXXG z<_paY&w~`CoeqWj$nrlSg*se^`stpJ#(Vd$@DbpzAN31*CS*RyY2lsR!dEjxKfXRz z;zqsrwHa#WaCOjHfMyyT+e+xK9t;;Sho*W{j_pWZv_Eu%E_$gtKf2kziKYc{UJ|Uo zC50OU{S1ATaJRpPcq2mD&y{I-_sGQiI~T6SyNq(`or?NnKW^)p~A zs{Z(h9F;98yyk@%?^$?=E+aWH195r2PqDtX$VBpP2LP*4sEh3@0)!(&WZQ z`}k*T>5t2W3&I?$muj>yV+vQMt0FFTVo%pM8k7`XoC{ZeucSNM)rrB+nKCPnbvAw< zOWQHbv-2%5`jz>6#m&r?x47IU7f#WBXB=rc4M2Dm#Bo&Sr{0ExI5=r~_-_T8drLYK2ri4443X>)-8NkcuVu^nqBpdG5e5+A(k!{MONydxGXKXlC{laW*f8&CJXqB zJNznFQ%X!vymz(HSXanXu!C2RgHNj`C)}J{dX-Hz;#*i-Qb9eRB^aecSs8wJSrG_2 zGeV5Ih{Jo!5_@EZ5}WOkw5n*N)FlWHssW~Dx+~YG?o-q4`7e@|M1s9AOBw}xMPhnR zSmlZYlVwM*x?@C6XI_h46S*pp__K-=ihP#Fxr)LNR%Ja>R8FGoO=$QhqJxFS7t|I6 z(xqaDS#q*llnJbis%Vq(RU)23CRjAa6?GA55=0gQ z$?Zz%ti|o1v9#8DRe%z$f{CG*Re%O#t_`8cx6MI6{PrWMoYddfD6+UO}d z^7thi6q?JFnt3ic{tC8r1oY!(A8p7`@ReG>RFv@9jb_L(tmh z6#AIGX*OD-9XH$8WF7+`S^0xcM=IDj9TZdRDo03j+6VtQ9ea%z?R{BhtIVJ0Df>Z` zqZmftu!L1Hs{;Akw|y_!Lr#O&DElxcZ@-@46TSkqhd+N zTXQ>c$(pLXx0?Og)k^;2cTc`)JJGO8pVYU#Q`CDjy}B};d)0sv?kk>qS-Nr4i=Q&s0Hv~zF2ql56A2iYA55Tf!ZtLGoHWA?po4@h{ER=`}N9>~u^vZq97 zWcLC712FQ-g%P(;QfhEV8ODROWGFPhMTzjjJ;&7-19A_4!=XUFthBSt3Yy0WgAkBv zH>~yw)@y_zt{P#f5=LWZv+Lfm%B*E59W=q2bb0YRrMb&8KuQ}G4VXc1F2{(D&sEGiZ=g+Vp6K8wzGiejeJx+ z!kv{+UtFq)O8?3>Qb3+q#ucdas^f}d$GA%pkWAwK11vRnMC(;&9w#D1Zy>vR-~5H- z8eoYqA+9oHY2sOYSsW-5lT4xHgEb2~$ zQ>KB-PEmi&KYYH`+=)Xj51d_!T4tynS{!AAjg_sTSip|rF_n<+!TtWpn>QPp1* zwQdWDPAs!QU}Hf1ou{&@g+kvR_O|kiAF{Atl1(HK-HLMF9b6VHRY)RR6!ipTP?VAN z|Lf~3fa++Lwu5_cx8Uw>0fM^)hv4q+oZzkpcMIRz?gR@74*5@b5WF zika@7p4r*i*`Drx82H^;G_k^yL`8`E_6N-mNzYVOmH^6;A(LBBno1s6+QtJ$QF!f8 zNj8~v*0MYgo7~hgNbQENBkG+e!Y9}^}R`~Y0E1gH6uiZQ4 z;F(|H2?J2`1AgWQ59vun|7ZM!_Fxth(vs25QtH8ZOGByYTgY9i5^4UhqR>IMuL2cb zRVee%OZY7{%t>MvDS$TcWPzrlW~bSQD2 zI^YvF=V-X|>{1}}Y!g4M|D4ZLzAjO*7}^pGonHjFyd~=W-XTiYBhB0u=BAS$HsApU zR)Rc#UetQCg-cvo8YDi)%>N}p0-xqlYz=@l5lT{O+2E3^qt(k*lFElCsM zJ4-?{l=(MVq6fJ2BQA8q>YwE_;yfm|7{63~_F>!TidDF!jOUIu@$!cg95HkV4`lZv zl$GNHATN>0_OVcQ&l&hu$*=f&R%elTE5mg98NH(vzNFRrkhLJJ)=E`EJ1Zci$Z|7! z2zj?RFfJw4ocQ{N6|!<06!Hc;$41 z`8BnFeWBZg9(Q+Z0~@LO3jpqm4^pxcS99wT0F5Z6H-P*Q!3o|B^Qkr6UONEEILowr z0((;W{btBTUn@%Eu8;M|!&3ZBjhJsp{zBwJ1*iQ;jO7>rQ826QnRxS{xw4F6_wh>d zH2mGO;6tDFPlTzht^flUt}GR++q)dzVowbV!IZvZg>UCY7jwq;M^8k)!~o{G2Y{js zJ`C)?-($r8^`%yK!e#~a;$(C}r~OyJ9=rXlzZ=LF%}ns>73)jD-mfzihL+cWPbmoQ z80wfGr;NEYYc=1wW0HR=cuxWss488-37bg{G}f=fcXbt^o_DTIwT5;zo6XdGqbx&g zS)p2{R$)C~I-l35m9E^awrW{6uU2t>^YG-`MLh4cFQ244JP}kyO#E}r>tOw7#zRWF zx5xGo3=#N8Ic07{pNm${!=UsNz}Alo=w5udCX{ticeX8tKy5fX3IfUm*e29~f}~d<5E=c9LKgjujDTWI zfm@tgo?G}9b_=XGATS2)t+;#Wg*_}0T;I?Z`j1cvxR{_V;6(|ub>L75ps%R!0@vOD zf_$qka0>OUUW|MA1iAQM`r=q>9OU0_x4rWMI;E98&Lj>T$a6<{zVVNGOajH%or zbKYcuCi53+&RrWiOO1hcbh!y<)#?=*;V-6htX~+=tZf9!;%Wr$-wJ3sPv|%cWq-BC zkAJgd6Jr34U|49bo)tGn87~stWJz?;(fuW3=~-*4s#9xXlqGe2Z6+o| z*o=Vq;OUxwujjS@W44CM_-rEBXN296Q9WEZ_#r*|m>-AH3#O^vV`e9J&z% zHJAtG=sEK`51U<|>!B;S&p7B)EEH*#4G|O-TH2aF@=T4qu2VN&-Nsb4B0g(`BoTzk z7zvbD`Mk!TzVK1NG&-G~_1zaj^(NL}fyu_#QEM)zD*=DR2c?$U;sb&zuNBruc+)(&lpRKymEmJXbkEnzcziUn)7G`Yd<7sQjhU3y z>XC$!|NcaYj44lEg-r>DPiUGhy>aA+xz(mrCTEBrG2NWE;*j^kNIhI+7YvGI7dE|a zup1QKF&93)$gqL{^2g8%qh1AAL5j!73#VQt*e>$N@C&P6JJ>FY$LI^MUSe1fP1uE5 zuO2LbBC^{avhvMgpwhcwW^rcNoj`g6e|@xXkP-UmlyF|KDuG`D@wevD*fZ~=LN@JC zo8g~{`~cm8WEV`gZm`ejem{HXP;ZH|Ae#w-MdC61%1QuJB)uGgR&a|X1$ZjgzEqg64CiDV57m(k?Sv&{ zD5E>@H?Ah?@}Z9q@yCY=Q_vKlNwvBr3NJIksI)<2;w8wAwuygkPV2q-yq_F!=}aG- zRVhkZIP3tpm-@`K)BF*ysHsM@9a-=!OSF|PIE|Mf@qGyejtYl2F-|PZ5qnWv!d4IY zzT}RHC!3w5d}%EgHJXg`SWO%l#e8{W7y;SMP z&*iO3`n!iqTo}Hb%;P_K@dp>?B;4ik_&nq2W=u)FzU1+(QEBu!48ZFnXwj7t_ zFt-Zj#LEMX4*O~6x!PX#NG{6!$&%^JNksYdglX}3TRJVHkdbOeU;#A<%iaX-2D&b(E6{I4?8RawKQHCnEP`t zXlb}fcE9=qiNff|o?LmxR$+P@@AOvebwk9EYLNgLORj*%!mIki?!U&|l&W zPIDVU$D~)+QpBjYobPAd+b%3iJf=^Yx`Qgv9)M93(mmU(+N2_DEE=W*niKa?Rnol( zk5Lo_4?oE}v@Ay=g%-5}f-Ra8k5L!WJxqR+l%mM+1YU*ZZj}$z%F*8vP_w=n#_daAf(kQfO7mQyf99$%jk(y)`=?tovib_Wm=}fAaib}eqL$PM5)j;QxsvYiS5ZV>ltf{`~!fu z>>07HOSM>#`vk9{mc!CWiL;to=|jS5pp~;Kk92QLEqKtBz*oY<0|9V+h3+8!hf~aJ z%=zpQM}_CwTK-dj2ZL;l&)dF&fS#0)n40Z5qkx)~o-SO6*yEVoSaMxoH1848^?+O{Xzns+kE+rs`6< z>PhgI?fLgz${&a7%EE~)qp^wVnt;?-nN9Z5z=8Am%wAZxo)9|u5K zr)X<}1k&CG)~@FV-a1~d^cqU<>V+$+XGk!|y@PqSv) zO_Iuq&)kLY8tJ{y>{s+2WJ#woc4CYcDOI7ioy{Kl9ZWjU}_?$i!gNFNR#DL6_i-4E(mJo( zF3bZek>V!bSG_06e>j2bh6;{!D>acT%c;V+U}AK1cCE(z+B6tdmtEdW~Q_rYfZ8K)q*6JBf6yr9x6JYhBr?1Qr1IlH{Oo;%H1Jp9m>Y3e{ zqqF~DKef+`aL6L6yN?NgkoqNX}+)TVz9IL4qjhiTYtg;XqkGhc$Q^n9ijSXaIydy>zE93?X6&2`LSBuTFsW={wEg0 z9bOjg5lHD5jJNyAM~CDdWEgc$@@qO~a5z`e`+J}AsO?lrs3=a-qAl9S)#KFo5^Lsa zo1)dqm8O|LHAl>f;B|Hnl?8sF9WbMvY?|N*wJ4wfS~SdkQ8QEm^z1Q+vksvj?!3)E zsz0iyjIv%BBREZ8?WOBDyH{$2Ibst3g`j@Kzc!;x65B;8`Ab zNEI7OzAz!w>rr>{Mp9tzi-FM=o^UXe7T!ML?Ic<4Ks&IyEsVC?TIE%iJh6|PyCl?n zV9c7n6!6v?Lf*XsgxtnO6U$tY`{wNwagUOJ+A#|~y5)(c<#vdd8Cx_n{?ssJZ@B-7 zhmDZxqjXEK-r+5U@28!`+o9{83xAgAzJfAAs4B=U!^n6-gO6a@0yI}U72y^Q9FNddT(103 zX>q3~lzz_?KX6hgWCcYvFc(LZWa7%&mHwX8l@E7_YY5k4ZnaDXixxPqKxCqQY8;PK zeSr_85SL3fEjuU=H6`<48X&yS(Ol**HDlaLj2y3ju6#^R8!_?1$Y8;X;eYIVh|bFM zURbg56u+%~0H76ynA8^>t{t0O#0IEwrb(`TBj^$e99o$DzEswYspFg>wNPdjU3W`R zVh}pF@_z7i54e>=^T2wK!`#}c6(4!jz6Bu{I_-L{Xf>z%0qfG_DQly zjQG%uJ&r5Of|0SdSNjh1&Mcp4n$*-N+JMfQ&DL1TCZPY(;gOD#N>JN@L*JP7!|9CTv1f;nK<#c&Dt#{fg~s{5jC@Z1-Tk*+ zsVPhw8_e*|;=OY1YJLIa#p8AVqphV#+JQVGFI}(O7M!t*ty?KD`CvC0%nV&KKBAH( ziMjRSe87;`P{25KrNIbtPy9$IJ@vtlaIE7b$12wF7Mf^mx#+XdI_|`-%BcW<)kpQ+ zD8toW;#;umvgL>6I!OJtBt2Ax@VW*F#n+CC!7fk+`a~ZF)TR(N=R<4NFYt5}6^TBM zdgvb+B-oVUf3y?v3Hr$lz6za#MCuN?CueCRq5(LSFh`lY&*AtkV#h6nG{0&>bOT1n zIAoC$Gq=q6jsq*7NTxk=YDAmqD}6p^`AxfKI8t+LXOfC1*#`vT9|!vAhV|_&n@+xk znQYqJY)GS5#f#Iq26Wh(T#A_?o8{T2AM-<4GNY%KrWF@sQVBc781ka{OBvHi@OJWM7H9;pF`6bBIBXqF;wN8bX-42ylACOw4C3Pl_=Y?j4kg zM{i1puJh~E-uB7$*k35o!@-0wEA+g5@3C-@oGXIC-PRrQTEQT7sq$DPwmWmJXCK25 zZy~rkwzt;RlDLp7ut9`d&U?L#_93Q$kbWER;F&Sp_*$5h7XnE`Xw4Gm8zwifUPBx& zL+*Rhjv>1t%%m8B+)|L~SIVGDiZEO9Fk4CwTMCD>Hzu!9s)ebimTCOOk4ckH8$sVCT~U zYIKI*+T~}`d6Zn|C5)(s*^$*BuxN{LLA1(>yc3yn;uZ_|K`?1N{KKezXR(@X>Qx*> zR_;(6|0Gq5AYC&!McPr<*LsO!FHd5}kQ#GspLu2o=<4PXy-#Q6i0`3;acgP5R#hQl zkWVU}582LG7!N_k;Sc95Diod!Vx#!(>0Yg1`^BNny$~JEo1vS~KP0BiKlv3I) z2cC0g!TsAQ(HYpWUT;F|<=K3eA>=g%S#=Q#7_P1~QZ`pScl26WdxEHteKy?26+ol7 zM=49}>k(;=CVVX(<10_H`MpxX@iNTi5a3c~3v%5u!)gdhTiw0Ao9@8!6L%4E)0NlV z{X4wn%?VD<5+t+$uncX`x?5WH@q4&$yFWUnoHak}o?&s+vot`1LDclld?K78%kvYU z+*iq^Dtl9qRXpG0yJsJm3AsaAz`3C>Vm^zU z;gmZl?9Wl_xS z$fW6R?)apNH?CWXg{V|!Jov4$B)w~+XyEV4d3|sE`pnK1TTo$XvjDOl!0ctOr;^5G z9pIJjcje-keY<>Dr#0jHe&LDsLHJs7i8RS>;<@Jw+GODP&+6c}4X+{6P4{*WeQel_p<) zjI5%*rR^--Jh_DybDm`eSdS_-@a8X%4f@Zc4{@ou#|6vK5GY-sb>?rj-Ddfp?}Ymk zZ%W5R5`VjoQE^X=ej*P7@;|jimcje_>CHY@xo=@Yo%e90J!$ng=Qcj8dxd_6E2#pDKh(SNG%a^swKE3`NpjgO>lDnq+J%(oIiwLKd^a> zQYV^ga;>>C&IRp)uQzFNw$9#7@5u5jN-lF($yJ87l~h$IA6AlnEpDwAVv3RN)Gf(H zms;z$V#qA0@d(e>=qhr}!-~+FPr8Irb{21l7{mL4MWI(>zK_8H6OrC_-_ z+{&}C(A;ekS$=i5xt=50z*LiDH++lEb6TuL-k?tY70EXlY6P91-p+`?S(jJ9%~7nF z*X-B?ZmMC=SRLHQ)FmO-(T+%5bDZFej6X>?JvYlFH!dDtRc0u58on*_@7l_S&+5nZ>akEfz(Y!=gI^B;;vb;l=5NAfC|+=tH*KX@$)2K@98^rZuZlv#Wi&lD&EfW)=6w7D(1lJd&+itOlM>Th%@j}XQL=ent5b6l$MZfhhxe_0CeS9h~ycz*a|X7D95iR{dwvF zVGb~#rl=TBrDTjScvd##oMA{y;OsUUd1=oI)LS`)OfGhDvkB=6PjP6yO@;HS46xwZ7LJUJ@WG78uB)#TN(@)MFM(CvJqDyU|U! z?5FEOUg-heN;pk|mO$YWLMW`6+=Kpk5AGPvKLu~7E$l{9cC#9VgT`CD%Nk_GBDrvMAoI_OZn)UEmT9tF9@A)vKhn)CEW?zLxeM|6@c=K$(yH1Cl! z1~S48F$p5oLtVKe*J02?pJ$O);@i!Djolu*UY6aCckZBcGmHp(RFL)CLUx9qzt3ZR z4tV>1Ktz>!CrA1_II?&faK=-6W^hp$zo%R%-2%Eax^t|o+1W8ssKq@`2y-a^`)aoe zJ1GEz&|ao2dZJ>IzcoD1c2CBg2_D?0iTZ{+`5{RyL&94O>!#Fsa;H=8y+x7wi4Dq- z4@xGZC~Yrx!pD@NIh{98%W=Hxu5d>NcwCD!U0OuZ57G@AbrpKtQ8bgol6^kfl;rU@ z{ikDmI3GU5pW9Ytdq#a_v^9q43EMC?E;ceDq`UD}D=Uvn^U=$`t#opu$SAnc( zs){13D_T&`*YWmg@C2hakSt1N=R+_Vmo(n#gM{_IxMR0!{C>n+d2G)KgV{5;ZjT5* zK?yAUej;x8p;>$ohYHTI7S0@kaS$%|Sz7gh9t42>+8_MB3jmpuFn>$wzZ-$RkPC`0 zB1Q(qX3zoKT0y%5bqjTT6Aa&Al;FT4QeB97=mB`h6h<|=_ZZX-^V19d?+aF$J^W}! zWHVAR>^E+F?udV6Xq6NEX#3f(x5*VV#fJ+nH_LfRfE?o1ano|*b-p_V@O>ie-nnIo z_TjEFB#nla9h~t?HY6zAZvL3OXURJlp{~Uo5aH-m0+kGK5F421X2+p5-C2ScSx;dY z7Aj7OFd#y3tll;s;J}PP<0~UwMC6O^uuqFqzqBM^D*iLT&W!}k26yg-uCXfuEjte5lX`$6t7B@jv_I+>HV-|{g@C#}iwVenf^Y}3hy_H^n`?K?>} zcOvklx?fb_@gy=M6|3d$_hd=9=+>kHvJ|J&TxH1sd?w9FYat;~&;DYI1RXI|3ZXpt zu|I~wSL6H>Cm?I{>l{n;3+Q|%nr#m?`?40PypOhe&K~r?ZG2Pzj^d+qFy0Mk2yx%@odftCl30)o%GMQ;ejJD#?j;A%jAv5_y4A-#asanWZph#=oK}$GMQa0*#QJ)ZP`|X|Ffr0KC_Ig4gAPbEzP%Ye#4)vhg-h#a_-~HeS3*)ko`TR#a2CRF!@T8&GNQ%_~pr;^;AyRE>8(U6s?eFDV&} z85Ome5-c%Yvdw{1wS$BdlPlAQ?yfwLjsiq|@mzfFh)N>@gy=u^Tp(5^?PK2n0G ze5iWq7mR!v=fCdBU%qXGl)b5fl)dFd^Naw+SGrpj%=Bq!g|o7ET`5no`lg_V+9bXc z2tfQsh8zAhwplN(<$Ed6becE5j+DmH1Mn$e-WcNU>sJl~<+>^k?*Kav?~wCPCoz_{ zU=ZG)f9BrTO00E=B>>M#)v}lAUoWg0YSINjPlPV0#?e^)^wBEv-}l(kqgLCVEJga1 z$Gg!7<>sn^rSGp0-0-+n=~zs=#77%uJ^=7rxv%w4+GNXdFU(N{yB17Lt?dOA+frWR zF}-g+hLL3)ibQcGIS8^g(itmN+f8$ZDqG3*Oh}}Mye-QLENuc?JULxqs9IG{6`MhP znBW)Cp_t&xlx1w5jJH+>Q%SctL3pHgsTD&78>t?$HkwY;^d2E+ zo|bKG7pf2p;NyWi;}au-;%jRy^U1!H>At#S+2|q0^wu-q9j@%XRC-=9-}e4kN184( zfV&F%jRBTZMU5kNik*s_)VL+Q)N&vD#UNe>_jeN!Y!_p~+2crnOD3(xdZg$hWi)*+ z&o$s}2p?u(U#EsRLKJevh7&<)0T`Mg8rL~sZ6%-4bgW5tRg;p&7vWr74^NBFbusR(%yZuYG+zIdpvx0u_!f7Fo^0{xl{nuPZnyeqJSUx&G<^a}&`2{Jt zV#yXmn8&u?-mkc!vdm`ns^H{&B6PkbSK@QIr$}|nXZcP?&d{K6)m3`R&rr9NGE!|pRBCY5qs zoLhf%tV}Rv0{<(5^gm1Ze}DZco`n*jffjc{)Zeoc%Nf|)8yH%f$XYl#|C^oI4P6YQ zGrb(20hLyH4Nxi;N1w&4{Gk&9OtwCK0hIbG4H1Q6MfJ97@ z?*+_lKL0vjn`T{VrqSFSatj}y+rGz{&spa3W%pN>@zco#g*#<~%I7d?Js>?_%Q1=%jy z9Ru&IY5GNV)7@8lW2O#ivA)(LBUR~5i(yh(>#98>6!gkkOYinLedWSn>p z>sU>(3lA@JH{!8$RihFm8a#PnCM^K>Ty~R8YeOj?Wyb?h_e`V?zgzOO>8x=|7b7q#S;q_6Z+(cIo6!ZV_C$V` zMd;d}+DV&{lwdm!w3_0H?v&Y0jiP?78kG|Lq4ZE=SyEw9JojUab0srFtC{LI({>66 zA1CxUNk&9eZSet^u<0EfOfQ%N6}g^$dKtehwdDhwv3H_#m7cAM#j|m?YdA;4a45mtQ3KYzKyB3{(nw{HAto+I-4xqb~lBil0{kaD2DO{0pg zHrLR+w}d%CM^3~EU?-?)hV$TP!f}!8rx|%($86h5h&-YEVn(G^Rf9*A zmBHSr-N~<0sO$s5^C{L(_*u7~kPN+0)He@4HidZI^AKOD-FaJ@1A;X$O4Zp-lS4f` zvr{yDiLWZF6vCOQZgTi2KSnpe0^tLtdeZG@um=Mape~j)Iv;IFZm2J0@b7Os-(8b; zMmjB3%{Y>aeyw{*fLPs#am$yBCSw6}Rwf;4V2|>#||I}zQm%j#$BxV z!8UxnprmTwL$@X2?BWWw|Ncls5QPwlkil}g!6YXR?a@5(6zMdi)vVb)!R0k?&a#0>8&EM`exTdYw}L{CO}tr>7Zv&Au(IB_*CL% zGtj+ykvz;@41IMS;U`%}UrcT}&;1Vg)YDI!Xbyh!+I@{aS6j{@sz+MQo0g{47KK5m z%Wxc@qv>0&+X+(OZ34B!T{qeeG2#dm=bOfY`Aev4A$URRUcqA=qMsOI02GA?;)=}I zZ$o*97^UHv$u+SykNn^jdwCwY4(8Snek?B$Aw~#1%g!2U3&$inU|1O#lMIFk$D}ST zet&$_`?Y`meI5PtICgRnzZek|qCW$|iDG+kC;OGW*Qet(AW>PyZcYg0nUjesT7*Py z4h!DKV}Jg(w?dU1QtX{$ABigR8s}NOt;5&ta?~f9NAO7kYJZ6BaltL7H<07DYj2cZ zi!Pk;KTeEu)m{BKD4Ke8mT#3GdSbHH-P*}XZ@n_SRTzb4n|QckgWyKLWNm0zeeK<`-_ly<$2{9B#mBILw&_gV+)>LqdYhj~njGN)+y%jSPW~f5*?g zS@YTTxL)+lAnAKV-Km(tGf7&KwUMyMPmWL2Shn!?N0KhbXYz8i=_(SAy_?T^Yx%

DpoC^W`7^BGHKk!75HEtxx%wP{%~}macha6UhhMp zr7TVyN5ue;!Q&9Up{V^3KOVnkp6Tat8Z*q?E*zCW--o?>&1*K?_4MO3GfXF^O*$P( zXAr(pKdRh?J|60G9Eo0ZyXq`8*_{=6@?k>UonL#XVJKzaS7{!bhM@_#@DMC@$r4IB-e?f%ALs8H2a044tun8Qk{)XoX@ zrY2QQNK(VPfcS(df+uGQpH{!+(<(c8pg!3Gw0CG|@jJ?(OzLvl}w@zk?prqjc zx|Yg!ubGJcOwvm|q=E9EFw>@OCFn?f;4Yb)GjaBX;r7WSiD788zj43!R>1Se*Z z#UQ5_OWJm9Y)&YSxDQme=`_w?3V!!}lwXkvrXks%-P7$Hk_%~bxw5fQ*I?Z^RT_>7 zI<~x-TVMCfi zDkrVV)!&3VTwu7C?&;>H#0giwFfzk=)}{`giAXTSF%RBCj0}uX+6(r?XiYFpY1DBl zVi1@*vajWLQ@D+vg-Xg*@T5@xuy!zxi|r?>TP&0P)e((sHBo!bB4YChKq?X>Ks%=zX%8r6@fEmq_j%sp?K4pt#=w8jTu}sj0CNh!D{t z(HG&ieb{oC=cMqI73-u{00uo@u_j2tDpWo%!C4+da)=eLW?mIB%K>4}5UW&jQx(I} zY)T-*?!GFR^W48?vA-aeLeq^W?_HUx7J_$!@Iqc3DSci1^Al?SPY})@=$zuWS^nqz z@2Hj7I0NlezktFjSwY!qjqGfg%z#ovxIn@nOn{oU8wfn(xv)hx{&m6!YLE-MSNaEV zRbhsTAg%gY@L6z2rBuo}=M`f#D)bz8u}fdZztG0wBngDll5!jRt36ms^V5jT~IoU0H@y)$Wf3ve3`A6q^wA9#SANy zWyqtbFEG_WeRj5@WF7AlK=U7YFPlBh!3H2Rurf&^^FT-oVPy;cl!eR2;kmAs`efb{ z_{#6FAS*OAjl^K!BEeHS%9uf*=a4li)b@Q0erX~{*m{?~mzl{rbmmaj+ul33<6zq# zQq6O%knu^Q(n0hZrF)`kXWp!-tnRGo=hPVAUs~GY2`WhC`R- z@wHYnprwk%GnNW%`^5lqrKw;uhG_g1Hbdm}`KyQDL(^Q*UmxK%IrG=n{_sUKAXl(r zD^f9)ja3^A%NsN#8}MSE_H0KSSH=Y-IzI=e_?@J8|1h!F)Krn7`dpk8Bh;&r%KjV@ z`Yzbj(=ID?uQhH)w(O8y{}X{eZk5c%K>ell8fB&cbz2JS`kQfcS}XAefz}*7hpjeI zcX(2FpamAwJ>%Savwj!b;PA!>N%ZpwT$m4|19-K@g! zjR)d@J8`)4MFDW0(f-D^%rA?4bE>NZDNt1VBgb{M zc98agKh4nGy6qkE!ngGnl2@wWsIGKPG{Bkjn_wz-e9EiOz0@DNe+ zm8j<;2p^+be_9*l!rlb|c&Z{ow-xauU8l}V5r(!ON5^32; zFs$9w5Ctq5wdtq;>|3Bg9yqPXbzjt4>nJhlOwUtl8juZo8)mcQM|NxtAcpS|r==5MgezLEB50&K z6Lro@^yWTXL)b3-$$#EkwMm@2D|$a(Xo1&n_abL56*;cyI^8_(_Q*P?R=)RKL-5@s z=lFV?Qw54083Ix*^RO$i8JRq@d}c-Jd6UE7HNg({ntY3Tftl6;^v1n3LPezIS0yR zGq-G?4WH}h+nb?mF!~(a9+_rbaTE&ZCY&`>kTY=`DzBiveM}Et05Yz3zchfD?Up=H zfefcl4(aBO9jDxi`bu*~|Jz+^FcMOFq!!70ief!Zt;EJa^BPNUgI(T6)iKP9#>`|C zMooN|zO#B+xVp|0v5-pKA5l6Zwwgbp9zB$mDm(|gsfB4Jr&lw7G}uoh*mz;uHd1S=r*kn>`PMqm=svr+;`0*#r0McvlyG!g zDA+ai1*O(tXXfmAyEdKh-j8Ref0-~N9&LaaGcW5bCEG0$4=P#Gqg+p~D$N8wW;PCQ zEya({(yVWtUHh}O?Q}Wc2QrY~ptww4{%@DSJEfBi@9vE zl9*J480x;1D0TN_VNTcrxR<3vZ_@TE{HXb{9dp{D%r;pcXbb2FXgGK)YCQ(FvHE?k zoa28uj~i+ZDUBbx<5nGV4{o9qQqVtUlgv9n9XMx*$`4t&>kiRCYmOgj>_(IgOL1?; z+!_v*sy07MWw#_y;~xnKMfG5*+S`irYxI=QIgd}c6IbY~q)TW5%DM0kiho!Tp65%- z^lkVaN6%QN{Rj`d`>f9blfEmSelv2j{}t-n9Q!m=`-jzsv=#J%C^+iaW?@KVbj)s4 zQ2cSA%-TB#BJ=}pgF5%bO@}<|_{1arcn^3Qba#ItabNIMzj&VhC3b_Dpb2#P5R@LN zZ(PyLdG$V2q2W7k0BE~BVHjT~xv}EJp;2%o-oQl~!J^1d6amSGQ3u>C_hE`RZU~{E zoMdr66M`+~05|zB<>5`b;<}@!hHp{G(2%!LOqQz%2ur;!i)**lvv5iup?yd**CL#u zHF$wO;E84QUiE$N_>LsMm*F};JeqE>Iz@ly1Ef_qT{Pma1C~2sEKN6Sm^wT7FLv#< z%p?J!gdSb48J#l2$W8fQ7bjU3U)vxoPG*zm&uUJXb_SGwH3o=XSQUShzs814K48@i zgp>;9l=x|zp%$1SptKJVfKx^U@UwrqxtHwD)ZDNM=Za1&ar6cJ#6ap_J&2NWVq7j ze$95x$W4FX3+_fUFq^2c#v|%t@U`)4Hm2O>$qX!tpzTmQj~I7oo-f&X^=+m&e6(7F zID+Py`j6z8Q)trXTJIL&+DNMB|Jt9wEU2JeI2Pi6S(58GJj(w{+uf2o`&UF=xV8o4 zFWl@p7|8=LY%p*P2#o*52?v63EQx=CFo3r7|6U;P^}jEaSEs^hz~?HQUxI+R)%e&w zpqgKMe?^&J5<$tpL7{rT>SU_%d3XM|1Xh$ zFo67~eq-SM#ennwWx)G~{?)G*Y+o3FZ=@lCf;EUQosqA>2QU0p{012DchM=RX!}>kUiyC}qY%8@@E0xhJMqCFfT&F*K>K-B*NZC5-Bd4xzbCc)Q)~*hKSh$uK~BqW|<+ zw+SDd!|Y!{!oTod z|JP0nG-ySC(fz-TT>pqG@Uu^UX%wXk_l5BH_b~52RG_~Fex11>LTcbgMhu{Q(_gDt zS_eM3LD5U`M#o?GTdNx%9Hrz%AKqly44hkm_x}Lz=K2@_ diff --git a/spirit/lib/spirit-core-lexer-2.1.30.jar b/spirit/lib/spirit-core-lexer-2.1.30.jar index a436ce24fb225add17fb605c8c0c61b2d5ac5609..830f0c64faedf95587940bbb1228801d771a4aee 100644 GIT binary patch delta 16662 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 _00P0eyHi{TmQ&?H}>PpW6 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 LZ>vG$7r*}x`vp%K delta 18505 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 diff --git a/spirit/lib/spirit-output-java-2.1.30.jar b/spirit/lib/spirit-output-java-2.1.30.jar index 27fbaf16f2504919bff9db2aed7b843e20c64ec7..3fa397b174a077260be761f2266e0c7762ec16cf 100644 GIT binary patch delta 34054 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 delta 30203 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 diff --git a/spirit/lib/spirit-starter-java-2.1.30.jar b/spirit/lib/spirit-starter-java-2.1.30.jar index 79efde16956ce537b558f3de6b4147505c25d6ea..b3c1f207ce724aa7bcaec4e139957c1272b083ea 100644 GIT binary patch delta 904 zcmbPle9=fez?+$ci-CiKgW*Bh^Pt~i4x6GG7#LC}ira*1c%HfLea_>o@sp=TdS1Rd zp1zFS)?zA5uA()ph&txq9Sj5N>;LXkfHwtJR z#1aM$29PBam#Z)@D0wvToIIHNpbDZUOEBtyX?I2w=8&A{lj|5QnSqKY?_$&f)6W_0 zz_bQa5VJ|u-O05~@nHHs(+-gM=2^@-9AL&tZUH7R;|}jVW{{H2FNN9|#gKhDxgnN0 z1L&+=hRG)cz3X{T8*(uj3b;MAn_$hd?Vh7~!uHmP$cm2pZ+2KWdCurz%+J5|{o}IP zMm^g<{Ata0wX(3eVA<{=-gU3^nwsi*?zx)t_T1iD^SU-V_~!+^V?N0z+nNqruQqz#)b;dp z(}(EcVgQ9DFxY~Ca&W)`X9+O8bv!azP*m6&T@6qt6oAw`1G1CzbM@0ROHxzO&7K@D zD$U3@nNdt+a=$1KICACzMQnj0GTO-Q07e&zJLF(iFo5hR0jk#pd&W>qnsLKqUokl_ zFHcOG=`Q2sGlHs z{oIrHimObvm5>ArMM_9BUE-bG%cwA!n@?o&DhVENYSWRFX4)(WbhNF0MQ#q7sX@q* e>x$xH7h#|tcd-C(RyL5hAP~y1GBC)CfOr7ub`2!} delta 1000 zcmca;G~ZY}z?+$ci-CiKgTZXm(V(|q)wf14Ffb%c6t@ZSIOlPe`{C0fJuhD!PhUoE zOEDEDSJ4{b(?Op_dcL0d(xWI9RI)c{lOtQi3&|tWQBt3ZJ{B=D1bDM^z|8@g1+jsF zg8^j2#8oQHTNWIhcu^iqeO3iglcgDTz_b^m37BqVv;@<88MVOlD@Hpot<4k!rW=^z z!So}h9n3&OH_v6(;Q%wva0@Vj8TWbbG4lb94pPnFVA%d^_>!^;=)3wlC{@apIO;)yME(M=IBAczv3GUf<%;>359QtM0W$Jyd)*>r`QS z)Owd=b2T-L=3P$V`Xy{N_s{mH6PNt2j-GKxXOqcJW>ByqJOc|>P{aYfx%q%#8>2WQ zlL)g2W?W9T5HSS>%H#qOX~tQTdqgBmK_LSS6gXgkvjiC4Ivxb_lJj%*1H3^daxsA7 z4irr{MWkgPL*>#lOHxxYR0xVnGjdPX6;%L7Pk^X2lNICS35?Q{J4AUD&@Giiv9u7R zP)QTTMie*lqbOfH`M;s(|5KzcgvLZJpz?+o~q*@RNWmp*)az#Kq0OH{|WB>pF diff --git a/spirit/lib/spirit-stdlib-2.1.30.jar b/spirit/lib/spirit-stdlib-2.1.30.jar index 26886e24c740c9c17d8dba186e80d1212bac3d5c..dd30644ca2aebc5d1fdd2a0ebe736d7f69b04898 100644 GIT binary patch delta 854 zcmX@B+o&rZ;LXg!#lXSA!EmeWdC+e$hfUE83=Am~#cjehJkMPBKId`P_{q~EJuhD! zPhUoEYcUljSJ4{b(?Op_dcL0d(xW&lsAO-@Cdamj7m`P$XEK(4EMjB`@MhgwT1G7}y^7HeOuuII0nwYS zm@=5ajHN8LtYF4d&Tuwnld8L$;{+WTrI3A-Bt2_;GSK>TAhu_iEFk7s&wF|!SBn7; z!-c&U>NPB+{kZe^j{BPb5Zu@+bz$3*zz^?B>-IcTZ}GZ#cKdHJ9_gK&`d;S_Gu)fi zy`;!5nP2utzv=2HoBuqP_{6BKEx1QjGwseA$G|v)7q7Q&*sv}1@wv^W{2cxa^mPq!)b;dp(}(EcVgLmhFm!@|a&W)`X9+O8 zbvy#(CFkej)d4gI3P3uZL3N~OmZYY_^|3>(n%pNW&B!--m9PRhI?f79GubjuJ|HTk zjqE0nH(+LhXnr^cWJB>}eGxgZ#{xv8nHDetLtYgaETCY3cnK823xQG(K~lz0DM$zb zr6!3=GZ`>}?3`>aDxm0V?sa;? z#m2xOAkM&`gre#8eD4suL^Y(RTfi7#I>Jira*Eobx!#{qSj#o|mtVr!OP7 zrI-qnt7whz>7dUdJzvj!=~0vlD%l&f$&oGMh2#o z!2q&h;wly9EenoLyeJQ*KC6PL$ZYTcZJ9Ed zz>F0vwya>r3(jyhL7)*qFD`tTunB0}7a+Eu93Ws(Ur>}^kXlrdnOYp%w~_0RgMiC# zhkuC&Z$0k0#S*l#W09F)&bmnbY#ZOa{?l$B-uE`Oh8;eW+$Op9WU$LZu59dWoICRQPuVjkaVjT$v*&skd}R|@=e3oFa9|C^Lq zl81&66ZoB$R)q#0*T-YXamz7E~Q`;GZND149-tlvLnq7#Nl` z>Q25OVypmC6Si46_&rd5I?%-kdqHYuuz-DMD=H3Fc(~W;2^Sj!gMc^#gA$5iH#orx z`$WYQK*4|<*Y+q1jRYnK3YeQAQZvL;keCN)O Date: Wed, 7 Jul 2021 20:19:34 +0800 Subject: [PATCH 70/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spirit/lib/spirit-code-tools-2.1.30.jar | Bin 14892 -> 14889 bytes spirit/lib/spirit-common-2.1.30.jar | Bin 48304 -> 48301 bytes spirit/lib/spirit-core-class-2.1.30.jar | Bin 40725 -> 40722 bytes spirit/lib/spirit-core-compile-2.1.30.jar | Bin 47270 -> 47267 bytes spirit/lib/spirit-core-element-2.1.30.jar | Bin 49539 -> 49534 bytes spirit/lib/spirit-core-lexer-2.1.30.jar | Bin 25747 -> 25744 bytes spirit/lib/spirit-output-java-2.1.30.jar | Bin 38940 -> 38937 bytes spirit/lib/spirit-starter-java-2.1.30.jar | Bin 6481 -> 6478 bytes spirit/lib/spirit-stdlib-2.1.30.jar | Bin 5761 -> 5758 bytes 9 files changed, 0 insertions(+), 0 deletions(-) diff --git a/spirit/lib/spirit-code-tools-2.1.30.jar b/spirit/lib/spirit-code-tools-2.1.30.jar index 185b2a25b517bed1ee2fc9046f1b470d9cd718fe..82b0756e37e7f43564f328015f19458476543e12 100644 GIT binary patch delta 852 zcmZ2eva&=xz?+$ci-CiKgTZIv^Psn1)wf14Ffb%c6t@ZXIOlPe`{C0fJuhD!PhUoE zOEDEDSJ4{b(?Op_dcL0d(xWI9RI)c{lOtQi3&|tWQBt3ZJ{B=D1bDM^z|8@g1+jsF zg8^v6#FeVdY8xL;yeJQ*K7)Car5SZV+{s>yhG4pm(Hu~!+N_iF zn7F|FY9@PT;br$G?`0}v@>#g~B&P%uh%S=czzm{QWZ$!cXi?RFV7{nkH&}j=b}kD@ zT+qOlnG50j%?8ZV*+Altxm$U~8JR?wMKHr z@CNDNVgUIQ=$9a%92~H~Spp1i9S;I|$@#f>bpXwQ0+5c!P#x)+C8?=!ee6)HCfk`v zGjTIcRx}WvoM*xV4w+h@kQGQsf*;LclMe!=@<38@lm9?fbDK&ttzevd(OeTlbplZ8 zEl5gX@?2AXu-PCX9VVaw%9G!lLah4-6v_q($xXI269LCbfSEMo+Q~U)s-Vz%XC}j> z$PAX(GFMUnrL+Le3B4}N3=EvW@N$587Dz8?v}Ofb=LgcJXd%P&mIG{gyoDNAo60V~ z({q5@ez7w!n4xI9CjeG>)ItTM^)*oIJrS@Y=UQ@2HnRka##qWQWs5^aWkBk714V90 z14V2n`&sgUt(d#P%ioTTf#C-~1A{J#6^incH=0?4wE3CKFzr$Wd#KA?cCv&OADgE! GNG$*dyzRUI delta 800 zcmZ2kvZh2lz?+$ci-CiKgW*xx^Pt~i4x6GG7#LC}ira)~c%HfLea_>o@sp=TdS1Rd zp1zFS)?zA5uA()ph&txq9Sj5N>;LXkfHwtJR z#1aM$2B0Mqm#H!Xt(tgF9!z}z^Cn9$>VUYD-5CwRbTy+nnBL0h1g3v6+CXXD$!Sdd zV0HzQJ@Z4Lo?T3ZOpnSo>&j1O1JleBOd$H0YAY`n!gHJ5SvN3)#D8+UX9v-*1pa~f zuSB}R>dVD*SwP~?q-~kS8JR?wMKFV9a+0wrP|f6-#xgQ@CNDN zVu1MZ`Q(en(#A)C3X=14(dB}G!f*i80R;jKZyldamN$_E`_0-!nvrjExQPOoS7jp2 zWXm|Y-cn-ndJ`V7&_1A0AxKDW@=p^U1yJO{OajsBa1O}a)ewa`=G>G0Od8>rB4pu#+mklbW5GZAor`~`08$-iF2f`t3laf2 zYreTM*k>xc{7%ndW?=Zm&cI*>_Zb7jl15Hdh*~v}W(^A&CQePDfbwKnQKiY<7Ca!) tnLyEL+E7uh$xkeVK%zf@qO1l$QO(KrmSQ5TY#?Jrf$$WNlSV=Lk5a$uiH>5Q2|L&gu%o+`5E0BR-%%arIjYcSsv+u%GH^t z7(LgCKTd8Z&VY>{4(0a+Wq(*|dfkruecd~#<tz%a=h25imn- zV=S|~YA;&o{qEEF4hAuvOs=?qOqG~H=5sNPr8wcCm`bM##)TjcFJvPTVXaeTzIUPbrL*mg$v@>%I3 z*?+UgIDY$u(<(Zl;6^p)9>8LxaHQ6URB|(@z5$fYis6h<_-f-`COD{>p=X$x6 z#}}4ZIUn1wm7lk5lKFjEO`0f0xUPA7KD96kn72DaP4?YgizxuE9{85>dg|WcaYv3V z;XL`On=CXN^PlZ8p16!1EruPtlEADTBX5mzgOe4_%;MeeCS}SX-mfct`^l@dO^WynR5nG^ z;14z_Oe=zDj)1S5WI`?@l1hjHCN*=!)U2>FA968E10_CmGoo#TD)8|s6?hQE4eCX7 zm{1FhHp^zaYsi5r0)H`qPm_e<%s3cy8^PwDY)--62d?mgC2%0WH@IJoJCZMFU$aqk zAreo0xZ_sX5CfdL{HT7!<2?!slb}?Jg))y!o|TB$2}$Oj)RJ!7f9BxU+nH!kFu(8 zg@S7cpNBz~PrPPc>!T-B5E6srf1k`#4tS^WI-{D?=IfDA7ycySt;I-4TQh?@HV)0I zqi3!PyO$EgxXQ-m*6-58{t_K*Kg|pI^R&VaF5$Umcbcf+yiSGbv;3qgaBqr*7Hk{d z9O_n>B{#t0t_cl$ym0)gfHgfvR-A`>F&|ocA}A;ggLXXk7@Z6scI)Y;0=Hto;iogh z#V+6c`>ns#y@tv+;L8?N!Gl6hY_8Mk9?y%TOX^kFx#fW*WxZ1=!5@g)RtEH5J|=^$ zk5`@6qOhH-@Wuk$RFk2mMdr;5d|_ep76ql=_zI^pzdOuA;2WApO&}`NQ>4R2)7oEe5x^ zsFG8ZrALgX>%#@`RQvs9PriW_i}J&sR)$oImG;?!n>2HE_SPy^)bBHR)Z5|9AC*aJ-RD{{e)ogi-(i delta 2156 zcmaJ?dr*{B6u;kHSaz3%b#X;tKVVm+06|4TMda0tt3YeGIn?-C%}1lApb<`@jE~7O z6{ItcC6r@f#bbHwBH#mODxGOYNbDb9k&Q)Ij%jI*k10F%ENpx<6Ep1L{?0kS-#O== zy|^CnmPg!NkgxL7F^xvUu9Xfro`hz*7cs_G;;#vM>&8}1u@=VVc3;Z>W^T{apZYgV z%(Exv+NHqs(D8isn60DFJMNkG{n>qgpY^b#q|4#X+5Pg(@U!L*q&I%wB(Z}00L^ep zuNc!X6s!6)mRFZl^;pE`ooDb9#!5-T*rXI;wn~}8oR-r0hK2A*nki1HJVTsH_$(e? zh+qN~H>vf*dEqxcfnO^HvnorN#VR`*PlKvj5_bQhn_Sq|nntplm!=c`wRUT;z-?h` z>D=b*C%-#PK5!v{%nS{TZHH+f= zHhA%4*_+89Wz&=Y#I9Xh!J7xG$aXu@D1NSgxu3xIJ)fx-HZj-RcjkVbT9vY;&$Bkq zA{u~z1s8<>@`8=Tn_9ccU-$2Zc=8u!6QA=)x8GQan^dO%?hc%(OHC8K;}ZFPw7$Pa zvD-Nx;>kXHK~7TcJlmv#d_kmRVlVKD6YJ&Bv*=$@w0@*(X}v7{3}yAx=P|=Yj8hoKy=KWEKSfQfXERZgY zv5zMPZ!sEBcZLX01I8YV^>U+XUbJyYRnsE#xpCylZiy4I5uGxBJ020C6bMl()v%_M zD!hW89Vz4~FNqpLx3|iC{d7Xlv_@0wv0JuZz30bRChqc7Me9>CAo*mDkhzX&yPqRr z?^_TlPz$1mZG>jG1j6Hq28e4T@wHg!A9K)Sg^U=35GSeLzdWfG_^h}BMoQhY!}1e3 z6x6Y!=H^m=#-i~$5*78_nD46~BR+WK&}X@^nwKy_hEjJ7Q9Zd^+SS7u`wr=H6jXsr zFwg?!B_Xh`%m~dLRCYB|%vnYvLkrUHjv%Tu^SK!Yq)88CEJZ=})^ga`I1UU&COGdM zz2uSkgVnxTvplrpPDG1dqx$k}34>qrp_LhMT)Aw&@GQPJdrXW?RtRh>8mv_hXHL?F zB;#uHHwi5|6)mpfNt?{q>?BE1`BO*e$nnf*lBHUxI%&q&JVvC{V9NM+2J11xKpRnC z#41--_=udjq2f+y1WA>*Zn$s+ok5HxD=Iu%Nh2uUZxkc2;LGeNUOs70m&DkYYQ|FE1ZQ$Twpsowu3+!=|gJ8?ags-}-H&m AqW}N^ diff --git a/spirit/lib/spirit-core-class-2.1.30.jar b/spirit/lib/spirit-core-class-2.1.30.jar index cf2f182163307a20c0ff88f309c413ce6a29d21d..45ee5f822038790bccbc976e86a3a45010180f25 100644 GIT binary patch delta 1924 zcmZWqdrVtZ7(e%13LPzL3ze?)S_RYamUUBDl!U~@KlTX52V%sGDQ?L^*qHl6lcC=^;2pQLNxz=&{J!7! z_^dtTjlXWwnb;*veRyeidN#VO2@ zak%t_u85nqC)$foZ~b*KCd$_Kwe6}UxbA`e8$*56s{OH@Lp2p4a*+qP)-xbEf((6Q z@!00;n>EqT)dct?QCu1|RxXRrnOGucxm^C8t4rhyE{{*0S|X3QB4#sjA%&g9Mc6t@ zuHY1E7H}~&M!pt|zm15 z^msPG$lS`8JVEq4S=_?T=l4!B`(1TDh5IKD|Er+Z)1YT()&5q@(goXG2kSV592n9i zk&*$8U#GLP*pTKq%1LDHt2Fe`>6uV!{|tIlNo|kuNeH#y>)RM*{l`OG=yN^%-o%$# z%F6``8O7bpO5&+4wDz-elI0-lZ0hYwmQGQN*?shRGs|B4ByH#?stv46QNlCB3xk*FsjvSlso(%*PUqRwGHCndJ!0C+>%^5WnlrR)gg+ZaQ zUP1VM{f10{CRMFyjsb=cCc2 z#u7{(IF!+_K9b0tlE}Lo*f3)5Q$NJpc@xi4=GglgC4GWWG;%h%TZ? z0$)_(fevpJBUDwo-;!pnF3V^>daAKSGN!;_Y3X-}r9aCQh{=^CQ1K+4HqU z{Q^G5lWsmOb$zy*^cNo%gtA2ngg)z@3xZ~nh}*5F6o&@{yb8MUF~mC%MLmL3zy)Ds zvD!$~*>ZBk$-JE&0e7lMx@R|;?Fc0c9=hpd0kE}dh!)7D1T6_0R;E%4H^#AUk8dckSJeLQ+py%B#^(|CI&Q~^Jz2y z@*b~3ITpwyU+VW=)^a0J}ASHRJ)u?#ETa8l`F zi(wuVxEa#wj%E^`8Pri|9ZXzyjEV1c=~=H`kFLFP8+u)lA(SEMHT?KSrid-8^=n0Z zVJ-yx1V0X$lAt|r0edlH9=A{IdIq3hwj;Dl0-8M`_VBtz8K_)0%rNB?EArb7<$fq$ znf)A!oZM36dmSRx{HLtPS{TQfPSNZ1M$*o!L59f>L~o>BrP}y;cT)NC>6FTct*5`4f8j59rt=6aWAK delta 1832 zcmZWpe@xV67=OR--2rk0cYwzod^v&m8Nb03BEfJYg<&T)y z{dfQmj+3z*TO@1BS}qr}jnbwx+(emV5i>`i!#jw9;}( z`wwcDw1k#FS6GN1Hg| zdsFIouxRw`$0-S)`!RMR6vmIl!MMv0-Uj_}vSxyK4kwuicPQ!+>E|`RNW53lZ<7A# zk*5V8^ymDcTG>23eD`>pIEP~)-w7L?xnBl~*w*|k#neq6DMI4ms__3$8vGm<0WEaM z`97Rg`TC8;>7^AVnUz+72xMYxKKqY0JX`#z7oT)&ws;g=jgQU1~ZnWAe4(q+0$#H#K>*>JDail zr?LBwCnUPx^a3egiU@!7{#q`)l#t&g^RFt< zU?Q}3QJ%GH?`)RdBsG6Ivit z>_|9T*LIXBSZKNzMbGXa$w-|FVVNay#Qttq|-H8T%Oa9+?=j)%*-f{dU{)NBhIj||Dwgy_KN zmdGM-&_p(e=qwaQDHO_3Xk0WJ9WIz9Ga3egWzKA3#^!X22LJPyz%J07d-%`!zVCnD zYgwS5EKsefK=kk?DwT@lciuG5-;WtCA%v8}3S{c8;Fjcw!raTb-}}tos5Rv8*5~aO ze9|;qX--i6#!KdVflc=({%DE_GuMrq2aTR3zlMILEe*R{yHG0-Q-M#VLXBW1blve4p(U72d0vI~*Ggc%P;jQ*&BV z)ZZNTOYAu>ZvGhXGdB}!2dSDUSe?>CfPehkdj%zf%hEccW{)RgLr0!Gk^UvzP z^Vq=qHW`@Nx5t~1#!z;=Hr|n5eB7Jg7iI?W@Evuv!N@<==tRGL?^dE+^xhYq;zrA~ zqrksW2o`9d7`T2E*rFwMGj{?rvGV7&@}D1>H@34qT_L=C6w6_SBw}ileF}D@Hw5WXCT+)*NXRYdLh1^gkaG>K3QR?JK9bY7Uy$ezUJ$R5RS&p5 zKPa3VxeAmw1w!;P>hy+XKjEDEf=!|u{7|gJrbDk;t>Iff2Fev!@iOYfCZv}4Z{pPX zeu;h)j?{R&yD;X@i|$tdr3zM#j9L{7`SQ1!)elHCZyO3Z2g3MCfnB06$Dz;)Z*9t<$)r6$UggdgAWwa~c(UkcTD}WYZCCR`OPoetR;VnE0gHxhcb|JmesmDV8 zwD*B+8YmjNHi4acSj5OqPIHY&w9bUIe@9Y~=K84gEf>&2An!z($E;%TxSd(gyYn#I zeysT#656n3~pkWD_X@eY#8`On1H4IY`_}B3|j+O zNIzoVfabQ9FJrZA#(kPKDA9W_B6idipm)DTtDl`~7qT@CNVJN8kpG__PafbhqpK+(cxF{B->rnC2-eJkIeMqV9vw>ZTj<_gLZf&l0w(^ zFZ~44O9ymZFb)LwHY2@eC=#jK$Q1q4P_iT_S*9$)!)*vuIx&`Z=;oGo6q|8knf61Y zn$H48$IguCbnxLd$E%~?kANn92>q3dnLmYT&j@|Bs?t=T@Z^5B!_NjE#u*E@{s&wT BP(%O# delta 2090 zcmZWp3s6*L6#nmjS$18Pm#i$v)d3V*7TDcPatslf;-Q2hqBs?b;&TKABT%FgoziJ2 zrC+BsQ5=nzupp>7QyMi+Q$C8Od%#EEK}I_E4b-jyBp?0?R8zVrR(oO_Q9 z@VWtR%1oC%^h~GIvEI@;lm)y@2L{l;i{6ET9?w6U(9$QPgM@ zg5GEN9@Hdw;CWR} zhNnEWytiZNr`sg`Xn(|J^9_vm`&bEoGB=y-c)!oR(eJfX;8|Ro@E0Cy^Kv=bA159i zgZ6DpfsA&|h8!K*lpW*9zc9*7H07)BY0>}R^35dUeyj)i->>M@qyLfhkRRGTiQ~wh zyW2##W3!??(f?)Hc{*Q9(NMf}&nXT1Z>FvyUhDn>il@$-M)3m&yC`pK=C_3F9V2T@ z5;w}mr}se&)x`mqu+=M4jd-~}XlhN#ttV!}n8(O?m>;{JbPi7W8wzci=}4$&IC~iJ z$MuTx+i+<0+LDzk-2vV83ipvj5)bfkOZ9C~cmhU(qMwYYSA((fDjCJ1s38iM;uFYj z#OzRUy}>|hR^1rFZ#!Mxd0G+E=yb<}+spwO<2@=J*AnsTF%XK|=IbT`!_x5&o2I^o z&yh<6{P1-hurY(2v5e&Gq}bVWQ*4FHN>{E|wZJ`jk}5e&^fg7QuJ4YYrot}=d& z>X^biWl`LqhV}SKc`b89@?bHdiKNM=SSg2%Oj+M!<;7kV8E(WBoA3 zI2EwXlRDCMY!U&jcc0(gt6@y>X6z*u@Sz@n7Ezm{V0nDJg#B~~pXo39S`uuV3JaVK z9o@aG&$1t{1&TuWPgYS~7z;TIsNT?mTb)-RxE*c~qXN|j&<(1ZClb(}yKvWS0Mr2R zMHTR>k#5kP=PL$t14YjX19q&rS>dsP6zOjcC5qPMkB-_Q-3vxI+Gp(6-AM$*m(Y71 z6EWS;qVTN|q#&hb0(zP{6uu>LxKucnAyUOsG&gMwWAP@&>?&P1%mhBtLWETgAe=&; zR?ArNmV;FGpHTRNIPpW7S=dibrb(YtcSj5&Hqmwp;`}_X{^cA4rtSYl4l~fiv z#$)=MK)5q)Sfy5cbs`eILEtUTB(E($SZr{%s2?N^WK(umqE>`j4I|C_;-td=TY}|C!%_>U?{PV03q@ZrE+deNTAKp|e;Efco0y`?8X9>8PsGzV-;pLU2puQ~} zJ%2;>%5ARdiJheM0^p|a1g}K|rv-|r9sJT9*$CsmUy&n?sBmPmDYZABR6WFCQAdkqf@}X2&0-5>@zcWW}_HRV;up4?e8&)b& znSNsHDhoFnJDWKq;a$GJ#(xVMqv} z;guuW2wag{(3D6>I?&sqAvwXJ2(LLfSzzfZ7mPwPR(`mB=I~70;-E;P(t#N zxf2B>w>1J_dx(uC6|}x!4HE&TGH;>f%B@{^+gbk-7#0-d3d0;CC1AgOM`@{Pp$u#C z8Wn%QArPB@d!jnYgxc@&YnDBChxl_(n=arPutF3R{k?VEPRb!XD%5t88cgV{7HzKC z9y@`-CTjC)cGrj(PSs{9-nBV)>5wDW^20mq17n) z7s}6s0of!Qy!Bze`8-40ufItohOK$D@?CxDK=ow$zI9&ZDC}miK0R*JAd?Q~qn>Zz zNQd#DxOCr7J(={&Lwiv{K!hIi^rW;}zcYUJ);gznEs5<>H&czZ`6EBg*|~6)$|tgbag(q4@Fz)Mfq2>HQ@M7~(oM9p>Jz#vRq+n=FBVHG=MtOE+D**HGT)c!Y$V}EIEw4uCaf(>1FKYeMp!An zEVbeebu)=UlJ?KlRn{0QAJpbR(%TzdtKw3zwr^72MSAzUN&ccSJL-BS{$zLM?zIs& zy%q5n@xq!`Dy;vC2Kf4EtGk|XOKDt54tI`1@}}05nAWvxzLl~E1hF-uH-s*yPf|y# zP3Edj@iH5yr#s0#UHg>jp=$KFmn<3nN`Y%;>bEWa^ixum<73%qwy)E-Qbf7RuIeZi z<&~%1dwe3Jd_X!&mOU!yqXn&ErtL)Wbe(k`aM^a7G@n#Fp?7=i?mLGH_^Ra)0=Bt-GW;$@eedca%TvEM+0a!O}|}`<~z` zFc7Mv+Oc6xIw3~&Y5bnBkIRD`aWA>36Fq-dn0sn;zgj1GIgq2R-ajD*g;|m5bd2>b z9X-j}+V1ZEqvu_LEkf33rHd;}2Cy&HGOysOpVTBwAN{A1Z)sAQf675ajx$0uKA~Vb zYu4YW2t`c&3Zz#;_NHpwUA|>T}slz9?zX3DdOHEdG@`W`58a6Zc_QBZn27GHnu&J@K?A^!bwU)P3p(I z33@`U`t^QhM*b=)j>))Br>qXH>(f_*oi9<>CGWhs3it z%9R95@!#{%Dyz47dz?qLmz-*nvkU4QP8ok^Hcr(g@mTlg?+_ap7nrZe_777d(XEZw+J1_#B)Fr6 zr)}44NQANPIE||T+8_D5LShzlXCsGyifqOfsp-WO>skuiQuj&z{55c%tx(gdu7&GK zp=aC#wXdeN@#o8Gp8XMB9q)F6v^y;lQeUh8rLS)u#WUKuZZMvpN-mhIu`^Iisjf$_ zy*}Dolb<&{#k3YC_r0NtQLAS;r<8w~-O=5Rzml|SDM|wrGS%nKls`59S{`t&rjGZy zb&gs5qO|iHzWnZ3=6rLrWwDYQl}pB_jz%RHF#EdS2vl=&UY?jJb$e9he(PBC);afk z>PALh0e?5Q)IYjoR-m)!wzZkzTDZLA;%0gJjbUN^j5d2Ht{q&i)^w{0SI$_*1fXVcUPqZ8(L&#!e-mGVa=`F?V#ZylLhEZyTXNM7H|D6su< zEqQ{`u_UJ0`8=Duzh5Ip-2GE*aMK%Ft?AM4g2^XYs-h~ayRviVWlnsajNjbdn-%U- z9d4|CSe!CgZ~Rw`O?TM*glwk4@#7hc-pNd91Mf)8i-}{2Qg$aNLY-$L0%r}5AA6>| zWu8flh^Vo9oVIF|=l$Km-=kk7?VDxiTQ<3ya_lMFP5P#{4a1Zb9&8ii=SptrCW>DD zR^RcvjiWC+BZ7Q{s8lLN@nOiLBF(EgEL6<&E3~D@aMzg2 z;AAaG7uf7u5wRAPI~vpq;}tp(40 zvGpvNICFnyf817PVN;f2*QLyb_XZSdaaOBkr+yq)700BpSXz9u>X65z2V^;g&h19y zj%3KVim_%f@VgwFMTvBs8s0RW%dfdtbd38rNnX4@;xD@dW+#q2oG;GxILF|Q*+`Z0 zFLcli4lYJEvVI@?S;zX(MZq&&N&TV?|4&Yp(rj*p9f?@^_UsSk<7b$Mt~YC}aH!7m zXcrM5I(CbvkySINj+eHDprEA9SgX9F>bo+gU)kx3Xe8tLH#X71MD#d#5{9JW3>&lTI& zxanlYP^pzc!t=_ZtE1NK;u}NCJmDGg598y8PPmu*sZ7d7IzGO1t45M+*V%4Y@M+a+ zbOlB<+OsAFA{Zd0gku@VdC9j>wUTGndP?xQ{aQr7f64*B2b95!NP&n%t(`dRXP zt8+i9I?mbV*L4{^tHpfJ!G}XRbe4-l3v`yVLyze!7l!&I6R9}|@oEu+u7!7K>aQrL zpVLi$#uK)Kdf*?XZI$%Ycs{ZF%(GSd&Oo%6Bd^1mmBp+$V`;_^)}QO1sS(mP!@45G za#FfRV@Sco%d^d?k0#W#OSxH1jz$%Isuub^rllgXSDO85gl1A+Zh?yL7Vo^b9EwVw z0t3D!vC?zOJIpAEQ(K@?W2@Wk>z&LpdOFkZ}( zsEX}m*zi;gsoO^EKIZ*UZ-?(2zd~=zLuyR6?zgXX!b^@fyWo{>7d>DQ+3LxS>-8vi zkfpQ_wyp%;uL!6FTpcKV#=x4EZjh#n6@I`@AA$P7f*ErP&DJi&w{l5TFxqrJT>nk8 z%D;fA$d%Z#E?)h{QbN3^ZvLe8X7$FUiopkH(~siJ3-yE?wrGjGSE3Vh8~&>1X{2ky z6U!SRS@Q5)LOEwD=r!*;W@gBEMIzz>r~x{O`OzT zVl8`aVE=0I_cxEl@g_xEa?j|*+GzFJe*oOaty8IgZmj^`@#WP!=pzKmuSKWl=kw}> z5MOeBRnFD7P&Sa1sY3N$mV5)QZvu$y6KW16lZ0$a#9;7 zQ=EMk9Xv{1v0*HkKWJvq*9anc$3yOpZWs&n2jvdA=69`XN6O;qeI?k|vT}UM7iK!R zTYQxRS2oKhmS1#FQ-5W=FkPGz_Ot&)wADhwYmIZnrjKJ8d^v$NxHy2`I4{&+-!eQV4;TeK3eBt-20n2EVM4WG7jT5 ztu)|fe923lk`8LVpBMRupGPAQ;aK2;KOYd>$Vlc3FohfR)lgpyv^P2CCEU2zWsblc zX2loLaN~Y3(g1~JQXmqTEh8Y4fxR+3G`HZ(39Rkluw(1)dRku#iDE{BJw7<{fF{jy z0Ûi>ix-v0jpbB3Vt;Kg|Givh8!bOZ??QA~9I$Jky@KoKDeUgWUlFcteDDmQoo zz^zFEC|1xwbCga60hJ4Bxq*m3niWtp2Wd_M?q zJNl=N6`C&r&3X>hCJhinmH{&AnV{|BAm}6A{&q^>I*|zos-uB}a?g3$M5II@SZNRl z;-Qo9FoLW?K(H7ypj!+3nra}RI#^-tOfw}Q)QE>E_I%I0;ROSc1FyTtA&S!+`#xEL z*s4GN*ngCN{0;hZ084Q=@?rwWEDe}9!M;ix38*8y2NAniGXl*mu%)?{6Unz99R+}| zV}%pcL_i7hgK$BBu2~4uJZ%QAlhFQQIUtQy3jsBHavy^Qnu87~gp2uZp3Irk>d^8V7IezJY z^=BIa2Irk%vylRU8LS9|!Xefi?R{1(K&s+|!MaSo+d8xe#P)FnLjDj~&14^p0d8>} zgl17oK<(Kb_{^wLoo+W)YUcu$~zave#yiE`E77i_;vzHqxb+HTg(W!wlh#gmO-KX2UGm!SpWb4 delta 4926 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 diff --git a/spirit/lib/spirit-core-lexer-2.1.30.jar b/spirit/lib/spirit-core-lexer-2.1.30.jar index 830f0c64faedf95587940bbb1228801d771a4aee..da9efc4f7bdc2acd54da627039a2f3c5d36909b7 100644 GIT binary patch delta 1739 zcmaJ>Z){Ul6upE*^wzd;C#t0ac*}4y? z7+hi`7?QahL!vPxBe$z^#uzgJH6wu<8DioW<2iR-$LkVa(|6we zo!|MLbI-Z&!A0rKi;^Q2kxdq+C<+Tt&BgP#SD#8S#)c*xkM@SY34dLF<&VtTuBg8= zDwRK6-NZMq+HboQzhyss`>VeXdtC9cv++;b&53Ky^R+40eCB3GVzEe>Qq)1Mg$zt# zm|^k*FON-6e&?q9d^6s`B?ZWIN+B|@Nb7m)6r7S;<<_Y=cz_2$ORcm}jii8#`}t$U zNb`+6JOwAYkIXEBXd2`v(PT67Dv4}|>XOM0S~aoG*?cBi-*EWE`op@TWTC6!CxTs# z7X&@#Z&7IddP|)w+oor;u;IGkzuNYzh4^FLKa#&YI%+0+$TU+%Hm!Awc&Bqhq-k=$ zE5fceKf8kb?>%%~__v2Eh5u}?%_MfV(EaQeo*u~|al33^J`b4dUxyk{pU@AygH4TY zeyTmt*|Q}Wi%`U3cdo|KSG-KcCynLX&*5sv=yP|CK%K%x5x*58c0Dt;b7wKmTo^|-3xaod`u)|b+a z1$+zcflxy!XPrS(gY>{Ak@ok@zx_G%g(SxAD{>e+KE6Z7`f4CQ;1g;^{esmrNf&di{y1=alq^&@2kbpf zi+>{WgDPSogDWAhtx8mtOyBSZQM?u_>o6qX6-aJ^**XunMpQxWJu;UaN76_5_Zi5? ztOaEc<%$gHe7}ZBJ$&4zK&-K3J`bBFkz!`k6m z{&oX+2E6e6uvgUg^2~*QUc&pWbILs4j=|CS3z_{iGWu%_EVSQTXCm$5Z=cX!ZCZR!`$DR#{u3tpjx9R-! zMnsz731{UZx_40LT^*u&ZFMD_8Em5H6WHNvn+m97S!v0ihhBV3#;M|0*f^-Zu7#lC zTG6pX2SfQR5>+II3?1v}!PC=HI+lA!blw+7&l(sV(bPM?e{cmWeW4HK>CmVU9MbG7 Qusw`<@kdR%)K9Db0gu_HmjD0& delta 1546 zcmaJ=eN0S z&iVb$JLlffDGpQI5vW&8=}c8sHa~bZxSYLdBElH!9dkSuda(A~_x01;&aYj(GEi3M zFRk_SjH>KHu_f!}%(KCp_I2AJF~C`%-mIpmkS-y@ zRE8pBM~lRGZ0x*;{;wC~KRCFT%vQdJ%pSg8I72YOA5om4t57Dqa4BlmRyZ)nD>hQj zbHXR)2jRFVAv1>{8eM4;bA$1IC5w|iwf2OW?1<@ph3sLoP2w+BHAw#xwZugDPg;q@ zzw+&uzQuBod^m2sK;cl$J2E^RYUJs6MuzyCwlk9E*5~z zo*&{z^R98r9L{*}i8Ft^p3d0sIq-#A0K*+>d@BD~Iu&hiyw^mZ5G$P}x53+=CQH(m z>#l#MF!qfZW_$(l(cl%u!G&G1|95e)*u0J?Tw(p$cX9OoEss}wYa6$g2kNN;b#V*h zvCBb>r5;o2&Bm6hC(-Na-~GQ8$di1i;ukm+cGB)X59`9h;f9t8OJR+WWkfa*l4CJ; z02^C$@jOLz7;4cxxNAdC`W*pA3dcB%wdNWqaQ`z%@iT`nqeWID`DNe{7cYd-);t&u znoIs2y<4cjAhZ)}9?qk?kb?2WnsTU__h6wlmxfIG-wFssiwvD%q$#3{Oa&vAN$td{ zX#a}?e>R^+zBQb&hf=(Z9eMRhn29{3`%ITEcG_h1hh1($rZ6v_nX1;>bEJ6w?Kdu5 zM9~kh!6JkBf&)oc!>)EocoqroaY{l~*Tq3M5*9+VSA#}N7R)Ddf5V6`53BRx zl2wDhBa)%4TNgPV=<3LWAG>X^x4V$q%I(#~r};@19mYG-Wn0mv3STc?g4b{^>kVyL z9zcrCRC)*rXN!}B1%$lc;pU}Dt_;|3PlLZYq_*1W<`tN^8vLEQ6ll2^9eN7|TzErD z3<3u#6GN)Ag1<+j>kNIJE-_Mt3$7}EX?I`Ze68$w<&HB}ZlH>7K+R%sMjg~$q(>J| zY)g;_GvIKK!$U_eeq?g#DJeq2fo@t;Kg Xk9Q>bo!NoV6n^h}*AM$a!4_-Vi^V8{2q^PoGG((yCoMsnTb%@PE-H!09F7zW6va)v4|{tA69rR^D}7a8)@UH9TyPn7>@7AFCs3B|9)Z6CGm5 zb9f*g>&?dZqZ#52PN`51#QVV~&87H}^qO4w{Q&$REtEZ-325X+;BVJKJ~t4K=Ng`Y z(%pQCT+rPQXZRc3*9p(~EDU+_n;2?kRfO)da+QSfr@E_VjNYPkbna?O(;EK2diTHi zei`$Yte$+Zx##@9Q?2qEzs}JJ&G*$JhUXypBez z5u-!%H}N;rY^M0cHca&E)17oKT=pmRJ+*3{9{Gc7do&p1vxm%fiQ8n`%gcdlhvo|o z7=nuHh;X=K`D#z0cja5N{pF}IFf?2E;|VHre-!ym_1ng!`c(msJwh=0q_ZK6gF;kYuLpH zFf{`vgiXXoD3>D}R)?)PKy6szwMpb=lMcQXL|k`|Af8CVZo3vn!X`As6j7vmFf%d* z4`+nZA;Y=090)}yeI%mrDnu5-gCsH{kS-bT0twj;70txE)vj=ZhNigLWPp*njI`uU zU+e)wEeh|ONTc_*u{twjB`L(7 zrK0KzoTsx*;T>KfQ%Ulhcfsi{@kLFTJYLe^6Ovr$ZM4C;?V^ZN)X P0W0V~Nz;CJ2>Jg3YIwRz delta 1599 zcmaJ>e@v8h82`TCm;2#ycS;<0a=hmq$X(=*V|rje6ay3yh@=C>N#v}vRY%zjaWrge zbN%psaK{5~k}QYis7(j*N9wT6&9V%`)tX_mtWh!>F)B7U%Jn?oqoWtM?zZ=NpU?O6 z{Q5la`yT1%NBg<0rbQQoJ)4B z8TRpFK|RCQ^P4Sjhc74NmLDbatn5cKcuw9Sk%g_3TDjoW8-r^~Vgfk2e20z>Za+OO z`~z->miz(7Wr6<~unT{uy+#(i`x*pqxNX8@n3HX=x-cquf4?v)cz0IUa^l}uyG=v( z+m{OTWX=1B$cOhUu95p$>31UR;FAGit(vb)guhmqo=UddV%FLuZjmkb?gy?ODtwqW zhUzAN3zBz>*hEPWdevohB`Yf)-;`fdMTrcIc7Ten4=L7*c>c_u7v~?n98#oTAQH-? z&Gdy7Zk9me=`b2Hx^PLVf{RrJi->3kXV@rK;tgl3W}*rokcD1jvJEQRMS7`A;U*2D z9{7CgVrc9#y6}1R|5lzco+mNZ%NZ+5CS~ls*YBpnrp|TH4+|;j<+#G*CJ}D#a1wGA z6HZtVapJ4v79HBpyjee_VeED)V}+_@V^%?=aX*YN5#-kUGiw`k_#9an+n^%L4!Gbb z16M3D_ob1((es$~l!>ubD&j~kOa*-K)-3U4@Y40)agHt|uT~L%T{c@j1BT*4j*r_F zUgX6(UNFRRL_^op>OXx4Yi!A8%&Q9T&KKb`ZD~}ChHvjcIf@YVz}Fp#d5$**1FbS+ zpJ*8?P=#l2gn`4Q6qb)+f0fVnq64qbO#O)Jy`ksg(~?fM6dZNMC^PZC(^_O|}p* z1xe(K$S}^D+#@1k0<<#-=twwVfwKe{-Z~xx@{;p&^#i;anM9bm7(l)NI`)Q$jLc)G zRC;DfYAU({0Z|!7?#a5MAb(Ew7nNbMVw^mIQF?NRD31cVjdCb97J?KiX(FrxxgV|q z$l!-_Kn`3x`M;p@ryZY~4ElEwn2$^A?clexutzyU5LE-iD3iGd+0F)uH*NUx-#1lcH{C4u5HOufuN zrz=eE2Qq;oYk|}rZm`H}aaoWEmxK({d0wyxAD_tN7zv2k*%H!B8w7#wvz>fYf?omT g-^mTJ%o#xUo@sp=TdS1Rd zp1zFS)?zA5uA()ph&txq9Sj5N>;LXkfHwtJR z#1aM$2B0Mqm#H!>D4BRx0Ytu61Co=)8FfLF8>1<6NY3-gb&Qrw56UL*WYh*x&lv4N zlsZ!|vq{z6$+b-JVER7O4xsSnnasKzAo>KiAQOnb&3m62B)@sDU>_q$pRe$3UKF2A zHWe`iN#uyg)XxRF&DS-=QPqvDRINa2GAoQ^nt^f>j0_A2KZ4X;Wny4RO3cek zEz&EgD1kT}Vm8oLKXDnR3Cxo>iYiR*0WyIitANygZm`G;aajdW95HTx`KFPXfnhZp z1A`HY{g-&b3c2}2CPzx}D1aT}-Bzdybi^W{wRR|qHwyxNXRB9{n}h0z=RuPjVwp35 VYIA|u6-AHB)v?&OZPE diff --git a/spirit/lib/spirit-stdlib-2.1.30.jar b/spirit/lib/spirit-stdlib-2.1.30.jar index dd30644ca2aebc5d1fdd2a0ebe736d7f69b04898..d82243012cee978b4e8d8fda8d6d86400255d0b5 100644 GIT binary patch delta 692 zcmZqF{ih=y;LXg!#lXSA!Qj5|dC=Rh>RTfi7#I>JirWNxobx!#{qSj#o|mtVr!OP7 zrI-qnt7whz>7dUdJzvj!=~0vlD%l&f$&oGMh2#o z!2q;j;!0H}|78;|D1gXMYCv+b6r(Ovz_Q7nj3!L(3n$kzYJ;dXjP@YvEu$}x+HAv= z$poU8v)HkM=;xdfY|O&T?rnAw@L&X~>k+)bi{kvrnL?%@i3LJ3jI$>16_POVU-l>n z=omO)fwKe{-Z~xx@{;p&^#i;anM9bm7(lKCx{Xsb8Dm}9#H5FZfqp%DUH{;}s zBEo#gT7mv)0LoZ_WTYnV5ax*ixejh4kiiewd< z*kh5NH0S`uyx=z6hyeK}HoF-%nl9($bV=))#24B|@M_o@p zH~j!_MkWzvE(VZuW|ce&0?NSw3!Eju@YeCj`Kb zie~m?J7F0nKE}y~qQaB&g?T`JtObhLf<&aWk=+4uIm}cL%@5~*>?of6Kv)jwmq{Wr zObZw%9~4#PL)APv5GeByBx4Mf5rIbO116A#lV6BPD1a;q+bkUX9_Z8QKwFgI z7BMg^X`IahR(Otu8|pfkG0%ez_c}e{Vq;(s5NBXeLeX@4a)GF!JTNYTQkMm6c?y)< p%*eoCfuhEA@&QqIP;79D$uKnt0v&2T`GO$V Date: Wed, 7 Jul 2021 23:43:14 +0800 Subject: [PATCH 71/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/compile/action/InvokeVisitAction.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java index 9af7e500..555fa5f4 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java @@ -32,7 +32,6 @@ public class InvokeVisitAction extends AbstractAppElementAction { @Override public void visitElement(VisitContext context, Element element) { - IClass clazz = context.clazz; StmtVisitor.forEachStmt(element, statement -> { for (int index = 0; index < statement.size(); index++) { try { @@ -42,7 +41,7 @@ public class InvokeVisitAction extends AbstractAppElementAction { } List parameterTypes = token.isInvoke() ? getParameterTypes(token) : null; if (token.isType() || token.isArrayInit() || token.isTypeInit() || token.isTypeBuilder() || token.isCast() || token.isLiteral()) { - token.setAttr(Attribute.TYPE, factory.create(clazz, token)); + token.setAttr(Attribute.TYPE, factory.create(context.clazz, token)); } else if (token.isSubexpress()) { Statement subStatement = token.getValue(); @@ -56,7 +55,7 @@ public class InvokeVisitAction extends AbstractAppElementAction { } else if (token.isLocalMethod()) { String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitMethod(clazz.getType().withPrivate(), memberName, parameterTypes); + IType returnType = linker.visitMethod(context.clazz.getType().withPrivate(), memberName, parameterTypes); token.setAttr(Attribute.TYPE, returnType); } else if (token.isVisitMethod()) { -- Gitee From 25956a92b2a2dc515f55f27b95f2fab8bec6e5cf Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Tue, 13 Jul 2021 00:08:50 +0800 Subject: [PATCH 72/83] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=8E=A8=E5=AF=BC=E5=A4=A7=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/common/utils/ListUtils.java | 9 + .../spirit/core/clazz/entity/IMethod.java | 6 + .../gitee/spirit/core/api/ClassLinker.java | 14 +- .../compile/action/InvokeVisitAction.java | 30 ++- .../compile/linker/AdaptiveClassLinker.java | 189 +++++++++--------- .../core/compile/linker/AppClassLinker.java | 8 + .../core/compile/linker/ArrayClassLinker.java | 71 ++++--- .../compile/linker/PrimitiveClassLinker.java | 77 +++---- .../spirit/output/java/ExtTypeFactory.java | 2 +- .../output/java/linker/ExtClassLinker.java | 175 ++++++++-------- 10 files changed, 326 insertions(+), 255 deletions(-) diff --git a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java index bc2b644a..3b688673 100644 --- a/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java +++ b/spirit-common/src/main/java/com/gitee/spirit/common/utils/ListUtils.java @@ -128,6 +128,15 @@ public class ListUtils { return null; } + @SuppressWarnings("unchecked") + public static List collectAll(List list, Function.Consumer consumer) { + List list0 = new ArrayList<>(); + for (T item : list) { + list0.add((V) consumer.accept(item)); + } + return list0; + } + public static void reverse(List list, Consumer consumer) { Collections.reverse(list); list.forEach(consumer); diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java index 0446e65a..498ec040 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IMethod.java @@ -6,7 +6,9 @@ import java.util.List; import cn.hutool.core.lang.Assert; import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.common.enums.TokenTypeEnum; +import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.core.clazz.frame.MemberEntity; +import com.gitee.spirit.core.clazz.frame.TypeEntity; import com.gitee.spirit.core.element.entity.Element; import com.gitee.spirit.core.element.entity.Token; import com.google.common.base.Joiner; @@ -36,6 +38,10 @@ public class IMethod extends MemberEntity { return methodToken.isTypeInit(); } + public List getParameterTypes() { + return ListUtils.collectAll(parameters, TypeEntity::getType); + } + @Override public String toString() { return getName() + "(" + Joiner.on(", ").join(parameters) + ")"; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassLinker.java index 2b6b33c4..94637f2f 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/ClassLinker.java @@ -6,16 +6,18 @@ import com.gitee.spirit.core.clazz.entity.IType; public interface ClassLinker { - T toClass(IType type); + T toClass(IType type); - int getTypeVariableIndex(IType type, String genericName); + int getTypeVariableIndex(IType type, String genericName); - IType getSuperType(IType type); + IType getSuperType(IType type); - List getInterfaceTypes(IType type); + List getInterfaceTypes(IType type); - IType visitField(IType type, String fieldName) throws NoSuchFieldException; + IType visitField(IType type, String fieldName) throws NoSuchFieldException; - IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException; + IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException; + + List getParameterTypes(IType type, String methodName, List parameterTypes) throws NoSuchMethodException; } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java index 555fa5f4..491db1b7 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java @@ -3,6 +3,8 @@ package com.gitee.spirit.core.compile.action; import java.util.ArrayList; import java.util.List; +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -11,7 +13,6 @@ import com.gitee.spirit.common.constants.Attribute; import com.gitee.spirit.core.api.ClassLinker; import com.gitee.spirit.core.api.StatementDeducer; import com.gitee.spirit.core.api.TypeFactory; -import com.gitee.spirit.core.clazz.entity.IClass; import com.gitee.spirit.core.clazz.entity.IType; import com.gitee.spirit.core.compile.entity.VisitContext; import com.gitee.spirit.core.element.entity.Element; @@ -39,8 +40,14 @@ public class InvokeVisitAction extends AbstractAppElementAction { if (token.attr(Attribute.TYPE) != null) { continue; } + List parameterTypes = token.isInvoke() ? getParameterTypes(token) : null; - if (token.isType() || token.isArrayInit() || token.isTypeInit() || token.isTypeBuilder() || token.isCast() || token.isLiteral()) { + + if (token.isTypeSmartBuilder()) { + token.setAttr(Attribute.TYPE, CommonTypes.NULL); + + } else if (token.isType() || token.isArrayInit() || token.isTypeInit() + || token.isTypeBuilder() || token.isCast() || token.isLiteral()) { token.setAttr(Attribute.TYPE, factory.create(context.clazz, token)); } else if (token.isSubexpress()) { @@ -55,14 +62,21 @@ public class InvokeVisitAction extends AbstractAppElementAction { } else if (token.isLocalMethod()) { String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitMethod(context.clazz.getType().withPrivate(), memberName, parameterTypes); + IType type = context.clazz.getType().withPrivate(); + IType returnType = linker.visitMethod(type, memberName, parameterTypes); token.setAttr(Attribute.TYPE, returnType); + //for smart builder + parameterTypes = linker.getParameterTypes(type, memberName, parameterTypes); + setTypeForSmartBuilder(token, parameterTypes); } else if (token.isVisitMethod()) { IType type = statement.get(index - 1).attr(Attribute.TYPE); String memberName = token.attr(Attribute.MEMBER_NAME); IType returnType = linker.visitMethod(type, memberName, parameterTypes); token.setAttr(Attribute.TYPE, returnType); + //for smart builder + parameterTypes = linker.getParameterTypes(type, memberName, parameterTypes); + setTypeForSmartBuilder(token, parameterTypes); } else if (token.isVisitIndex()) {// what like "[0]" IType type = statement.get(index - 1).attr(Attribute.TYPE); @@ -90,4 +104,14 @@ public class InvokeVisitAction extends AbstractAppElementAction { return parameterTypes; } + public void setTypeForSmartBuilder(Token token, List parameterTypes) { + if (!parameterTypes.isEmpty()) { + if (ListUtils.findOne(parameterTypes, parameterType -> parameterType == CommonTypes.NULL) != null) { + Statement statement = token.getValue(); + List subStatements = statement.subStmt(2, statement.size() - 1).splitStmt(","); + //TODO 这里添加逻辑 + } + } + } + } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index f0af70de..3bdeafe6 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -19,104 +19,109 @@ import cn.hutool.core.lang.Assert; @Component public class AdaptiveClassLinker implements ClassLinker { - @Autowired - public PrimitiveClassLinker primitiveClassLinker; - @Autowired - public ArrayClassLinker arrayClassLinker; - @Autowired - public AppClassLinker appClassLinker; - @Autowired - @Qualifier("extClassLinker") - public ClassLinker extClassLinker; - @Autowired - public TypeFactory factory; + @Autowired + public PrimitiveClassLinker primitiveClassLinker; + @Autowired + public ArrayClassLinker arrayClassLinker; + @Autowired + public AppClassLinker appClassLinker; + @Autowired + @Qualifier("extClassLinker") + public ClassLinker extClassLinker; + @Autowired + public TypeFactory factory; - public ClassLinker chooseLinker(IType type) { - if (type.isPrimitive()) { - return primitiveClassLinker; - } else if (type.isArray()) { - return arrayClassLinker; - } else if (!type.isNative()) { - return appClassLinker; - } else { - return extClassLinker; - } - } + public ClassLinker chooseLinker(IType type) { + if (type.isPrimitive()) { + return primitiveClassLinker; + } else if (type.isArray()) { + return arrayClassLinker; + } else if (!type.isNative()) { + return appClassLinker; + } else { + return extClassLinker; + } + } - @Override - public T toClass(IType type) { - return chooseLinker(type).toClass(type); - } + @Override + public T toClass(IType type) { + return chooseLinker(type).toClass(type); + } - @Override - public int getTypeVariableIndex(IType type, String genericName) { - return chooseLinker(type).getTypeVariableIndex(type, genericName); - } + @Override + public int getTypeVariableIndex(IType type, String genericName) { + return chooseLinker(type).getTypeVariableIndex(type, genericName); + } - @Override - public IType getSuperType(IType type) { - // Object已经没有父类了 - if (CommonTypes.OBJECT.equals(type)) { - return null; - } - // 如果不存在显示的父类,则返回Object - IType superType = chooseLinker(type).getSuperType(type); - if (superType == null) { - return type.isPrimitive() ? null : CommonTypes.OBJECT; - } - // 降低访问权限 - return superType.lowerAccessLevel(); - } + @Override + public IType getSuperType(IType type) { + // Object已经没有父类了 + if (CommonTypes.OBJECT.equals(type)) { + return null; + } + // 如果不存在显示的父类,则返回Object + IType superType = chooseLinker(type).getSuperType(type); + if (superType == null) { + return type.isPrimitive() ? null : CommonTypes.OBJECT; + } + // 降低访问权限 + return superType.lowerAccessLevel(); + } - @Override - public List getInterfaceTypes(IType type) { - return chooseLinker(type).getInterfaceTypes(type); - } + @Override + public List getInterfaceTypes(IType type) { + return chooseLinker(type).getInterfaceTypes(type); + } - @Override - public IType visitField(IType type, String fieldName) throws NoSuchFieldException { - Assert.notNull(type, "Type cannot be null!"); - Assert.notEmpty(fieldName, "Field name cannot be empty!"); - // obj.class class是关键字 - if (Dictionary.CLASS.equals(fieldName)) { - return factory.create(CommonTypes.CLASS.getClassName(), type.toBox()); - } - IType returnType = chooseLinker(type).visitField(type, fieldName); - if (returnType == null) { - IType superType = getSuperType(type); - if (superType != null) { - return visitField(superType, fieldName); - } - } - if (returnType == null) { - throw new NoSuchFieldException(String.format("No such field!className:%s, fieldName:%s", type.getClassName(), fieldName)); - } - return returnType; - } + @Override + public IType visitField(IType type, String fieldName) throws NoSuchFieldException { + Assert.notNull(type, "Type cannot be null!"); + Assert.notEmpty(fieldName, "Field name cannot be empty!"); + // obj.class class是关键字 + if (Dictionary.CLASS.equals(fieldName)) { + return factory.create(CommonTypes.CLASS.getClassName(), type.toBox()); + } + IType returnType = chooseLinker(type).visitField(type, fieldName); + if (returnType == null) { + IType superType = getSuperType(type); + if (superType != null) { + return visitField(superType, fieldName); + } + } + if (returnType == null) { + throw new NoSuchFieldException(String.format("No such field!className:%s, fieldName:%s", type.getClassName(), fieldName)); + } + return returnType; + } - @Override - public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { - Assert.notNull(type, "Type cannot be null!"); - Assert.notEmpty(methodName, "Method name cannot be empty!"); - // super()和this()指代父类或者本身的构造函数,返回这个类本身 - if (Dictionary.SUPER.equals(methodName) || Dictionary.THIS.equals(methodName)) { - return type; - } - // 如果已经推导到Object,并且方法名是empty的话,则直接返回布尔类型 - if (CommonTypes.OBJECT.equals(type) && Dictionary.EMPTY.equals(methodName)) { - return CommonTypes.BOOLEAN; - } - IType returnType = chooseLinker(type).visitMethod(type, methodName, parameterTypes); - if (returnType == null) { - IType superType = getSuperType(type); - if (superType != null) { - return visitMethod(superType, methodName, parameterTypes); - } - } - if (returnType == null) { - throw new NoSuchMethodException(String.format("No such method!className:%s, methodName:%s", type.getClassName(), methodName)); - } - return returnType; - } + @Override + public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { + Assert.notNull(type, "Type cannot be null!"); + Assert.notEmpty(methodName, "Method name cannot be empty!"); + // super()和this()指代父类或者本身的构造函数,返回这个类本身 + if (Dictionary.SUPER.equals(methodName) || Dictionary.THIS.equals(methodName)) { + return type; + } + // 如果已经推导到Object,并且方法名是empty的话,则直接返回布尔类型 + if (CommonTypes.OBJECT.equals(type) && Dictionary.EMPTY.equals(methodName)) { + return CommonTypes.BOOLEAN; + } + IType returnType = chooseLinker(type).visitMethod(type, methodName, parameterTypes); + if (returnType == null) { + IType superType = getSuperType(type); + if (superType != null) { + return visitMethod(superType, methodName, parameterTypes); + } + } + if (returnType == null) { + throw new NoSuchMethodException(String.format("No such method!className:%s, methodName:%s", type.getClassName(), methodName)); + } + return returnType; + } + + @Override + public List getParameterTypes(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { + return chooseLinker(type).getParameterTypes(type, methodName, parameterTypes); + } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java index 71902686..3da98f06 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java @@ -83,4 +83,12 @@ public class AppClassLinker implements ClassLinker { return null; } + @Override + public List getParameterTypes(IType type, String methodName, List parameterTypes) { + IClass clazz = toClass(type); + List methods = clazz.getMethods(methodName); + IMethod method = ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); + return method.getParameterTypes(); + } + } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java index 064cb428..fcd2d88e 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/ArrayClassLinker.java @@ -13,38 +13,43 @@ import com.gitee.spirit.core.clazz.utils.CommonTypes; @Component public class ArrayClassLinker implements ClassLinker { - @Override - public T toClass(IType type) { - throw new RuntimeException("This method is not supported!"); - } - - @Override - public int getTypeVariableIndex(IType type, String genericName) { - throw new RuntimeException("This method is not supported!"); - } - - @Override - public IType getSuperType(IType type) { - return CommonTypes.OBJECT; - } - - @Override - public List getInterfaceTypes(IType type) { - return new ArrayList<>(); - } - - @Override - public IType visitField(IType type, String fieldName) throws NoSuchFieldException { - if (Dictionary.LENGTH.equals(fieldName)) { - return CommonTypes.INT; - } else { - throw new RuntimeException("The array type has no other fields"); - } - } - - @Override - public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { - throw new RuntimeException("The array type has no method!"); - } + @Override + public T toClass(IType type) { + throw new RuntimeException("This method is not supported!"); + } + + @Override + public int getTypeVariableIndex(IType type, String genericName) { + throw new RuntimeException("This method is not supported!"); + } + + @Override + public IType getSuperType(IType type) { + return CommonTypes.OBJECT; + } + + @Override + public List getInterfaceTypes(IType type) { + return new ArrayList<>(); + } + + @Override + public IType visitField(IType type, String fieldName) { + if (Dictionary.LENGTH.equals(fieldName)) { + return CommonTypes.INT; + } else { + throw new RuntimeException("The array type has no other fields"); + } + } + + @Override + public IType visitMethod(IType type, String methodName, List parameterTypes) { + throw new RuntimeException("The array type has no method!"); + } + + @Override + public List getParameterTypes(IType type, String methodName, List parameterTypes) { + throw new RuntimeException("The array type has no method!"); + } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java index 1a505bcf..650f1bd3 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/PrimitiveClassLinker.java @@ -15,41 +15,46 @@ import com.gitee.spirit.core.clazz.utils.CommonTypes; @Component public class PrimitiveClassLinker implements ClassLinker { - @Autowired - public TypeFactory factory; - - @Override - public T toClass(IType type) { - throw new RuntimeException("This method is not supported!"); - } - - @Override - public int getTypeVariableIndex(IType type, String genericName) { - throw new RuntimeException("This method is not supported!"); - } - - @Override - public IType getSuperType(IType type) { - return null; - } - - @Override - public List getInterfaceTypes(IType type) { - return new ArrayList<>(); - } - - @Override - public IType visitField(IType type, String fieldName) throws NoSuchFieldException { - if (Dictionary.CLASS.equals(fieldName)) { - return factory.create(CommonTypes.CLASS.getClassName(), type.toBox()); - } else { - throw new RuntimeException("The primitive type has no other fields!"); - } - } - - @Override - public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { - throw new RuntimeException("The primitive type has no method!"); - } + @Autowired + public TypeFactory factory; + + @Override + public T toClass(IType type) { + throw new RuntimeException("This method is not supported!"); + } + + @Override + public int getTypeVariableIndex(IType type, String genericName) { + throw new RuntimeException("This method is not supported!"); + } + + @Override + public IType getSuperType(IType type) { + return null; + } + + @Override + public List getInterfaceTypes(IType type) { + return new ArrayList<>(); + } + + @Override + public IType visitField(IType type, String fieldName) { + if (Dictionary.CLASS.equals(fieldName)) { + return factory.create(CommonTypes.CLASS.getClassName(), type.toBox()); + } else { + throw new RuntimeException("The primitive type has no other fields!"); + } + } + + @Override + public IType visitMethod(IType type, String methodName, List parameterTypes) { + throw new RuntimeException("The primitive type has no method!"); + } + + @Override + public List getParameterTypes(IType type, String methodName, List parameterTypes) { + throw new RuntimeException("The array type has no method!"); + } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeFactory.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeFactory.java index 14079a8e..051f0868 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeFactory.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeFactory.java @@ -20,7 +20,7 @@ public class ExtTypeFactory extends AppTypeFactory { public IType create(Class clazz) { IType type = create(clazz.getName()); TypeVariable[] typeVariables = clazz.getTypeParameters(); - if (typeVariables != null && typeVariables.length > 0) { + if (typeVariables.length > 0) { List genericTypes = new ArrayList<>(); for (TypeVariable typeVariable : typeVariables) { genericTypes.add(createTypeVariable(typeVariable.toString())); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java index 6a284a01..1c24a205 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java @@ -29,89 +29,96 @@ import cn.hutool.core.lang.Assert; @Order(-80) public class ExtClassLinker implements ClassLinker { - @Autowired - public ExtClassLoader classLoader; - @Autowired - public ExtTypeFactory factory; - @Autowired - public ExtTypeDerivator derivator; - @Autowired - public ExtMethodMatcher matcher; - - @Override - @SuppressWarnings("unchecked") - public T toClass(IType type) { - return (T) classLoader.loadClass(type.getClassName());// 可能是数组 - } - - @Override - public int getTypeVariableIndex(IType type, String genericName) { - Class clazz = toClass(type); - TypeVariable[] typeVariables = clazz.getTypeParameters(); - for (int index = 0; index < typeVariables.length; index++) { - TypeVariable typeVariable = typeVariables[index]; - if (typeVariable.toString().equals(genericName)) { - return index; - } - } - return -1; - } - - @Override - public IType getSuperType(IType type) { - Class clazz = toClass(type); - Type nativeSuperType = clazz.getGenericSuperclass(); - IType superType = nativeSuperType != null ? factory.create(nativeSuperType) : null; - return superType != null ? derivator.populate(type, superType) : null; - } - - @Override - public List getInterfaceTypes(IType type) { - Class clazz = toClass(type); - List interfaceTypes = new ArrayList<>(); - for (Type interfaceType : clazz.getGenericInterfaces()) { - interfaceTypes.add(derivator.populate(type, factory.create(interfaceType))); - } - return interfaceTypes; - } - - @Override - public IType visitField(IType type, String fieldName) throws NoSuchFieldException { - Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!fieldName:" + fieldName); - Class clazz = toClass(type); - Field field = ReflectUtils.getDeclaredField(clazz, fieldName); - if (field != null && ReflectUtils.isAccessible(field, type.getModifiers())) { - return derivator.populate(type, factory.create(field.getGenericType())); - } - return null; - } - - @Override - public IType visitMethod(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { - Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); - Method method = findMethod(type, methodName, parameterTypes); - if (method != null && ReflectUtils.isAccessible(method, type.getModifiers())) { - Map qualifyingTypes = getQualifyingTypes(type, method, parameterTypes); - return derivator.populateReturnType(type, qualifyingTypes, factory.create(method.getGenericReturnType())); - } - return null; - } - - public Method findMethod(IType type, String methodName, List parameterTypes) { - Class clazz = toClass(type); - List methods = ListUtils.findAll(Arrays.asList(clazz.getDeclaredMethods()), method -> methodName.equals(method.getName())); - return ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); - } - - public Map getQualifyingTypes(IType type, Method method, List parameterTypes) { - Map qualifyingTypes = new HashMap<>(); - int size = !ReflectUtils.isIndefinite(method) ? method.getParameterCount() : method.getParameterCount() - 1; - Parameter[] parameters = method.getParameters(); - for (int i = 0; i < size; i++) { - // 根据本地类型创建统一的类型 - derivator.populateQualifying(type, parameterTypes.get(i), factory.create(parameters[i].getParameterizedType()), qualifyingTypes); - } - return qualifyingTypes; - } + @Autowired + public ExtClassLoader classLoader; + @Autowired + public ExtTypeFactory factory; + @Autowired + public ExtTypeDerivator derivator; + @Autowired + public ExtMethodMatcher matcher; + + @Override + @SuppressWarnings("unchecked") + public T toClass(IType type) { + return (T) classLoader.loadClass(type.getClassName());// 可能是数组 + } + + @Override + public int getTypeVariableIndex(IType type, String genericName) { + Class clazz = toClass(type); + TypeVariable[] typeVariables = clazz.getTypeParameters(); + for (int index = 0; index < typeVariables.length; index++) { + TypeVariable typeVariable = typeVariables[index]; + if (typeVariable.toString().equals(genericName)) { + return index; + } + } + return -1; + } + + @Override + public IType getSuperType(IType type) { + Class clazz = toClass(type); + Type nativeSuperType = clazz.getGenericSuperclass(); + IType superType = nativeSuperType != null ? factory.create(nativeSuperType) : null; + return superType != null ? derivator.populate(type, superType) : null; + } + + @Override + public List getInterfaceTypes(IType type) { + Class clazz = toClass(type); + List interfaceTypes = new ArrayList<>(); + for (Type interfaceType : clazz.getGenericInterfaces()) { + interfaceTypes.add(derivator.populate(type, factory.create(interfaceType))); + } + return interfaceTypes; + } + + @Override + public IType visitField(IType type, String fieldName) { + Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!fieldName:" + fieldName); + Class clazz = toClass(type); + Field field = ReflectUtils.getDeclaredField(clazz, fieldName); + if (field != null && ReflectUtils.isAccessible(field, type.getModifiers())) { + return derivator.populate(type, factory.create(field.getGenericType())); + } + return null; + } + + @Override + public IType visitMethod(IType type, String methodName, List parameterTypes) { + Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); + Method method = findMethod(type, methodName, parameterTypes); + if (method != null && ReflectUtils.isAccessible(method, type.getModifiers())) { + Map qualifyingTypes = getQualifyingTypes(type, method, parameterTypes); + return derivator.populateReturnType(type, qualifyingTypes, factory.create(method.getGenericReturnType())); + } + return null; + } + + @Override + public List getParameterTypes(IType type, String methodName, List parameterTypes) { + Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); + Method method = findMethod(type, methodName, parameterTypes); + return ListUtils.collectAll(Arrays.asList(method.getParameterTypes()), clazz -> factory.create(clazz)); + } + + public Method findMethod(IType type, String methodName, List parameterTypes) { + Class clazz = toClass(type); + List methods = ListUtils.findAll(Arrays.asList(clazz.getDeclaredMethods()), method -> methodName.equals(method.getName())); + return ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); + } + + public Map getQualifyingTypes(IType type, Method method, List parameterTypes) { + Map qualifyingTypes = new HashMap<>(); + int size = !ReflectUtils.isIndefinite(method) ? method.getParameterCount() : method.getParameterCount() - 1; + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < size; i++) { + // 根据本地类型创建统一的类型 + derivator.populateQualifying(type, parameterTypes.get(i), factory.create(parameters[i].getParameterizedType()), qualifyingTypes); + } + return qualifyingTypes; + } } -- Gitee From de59ed088ce4e4d92dd9a0d3a29daaa40fe45aa9 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Tue, 13 Jul 2021 22:22:06 +0800 Subject: [PATCH 73/83] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/clazz/entity/IType.java | 7 + .../compile/action/ExpressDeclareAction.java | 2 +- ...Action.java => InvocationVisitAction.java} | 239 +++++++++--------- .../spirit/output/java/ExtTypeDerivator.java | 4 - .../output/java/entity/MatchResult.java | 17 ++ .../output/java/linker/ExtClassLinker.java | 23 +- .../output/java/linker/ExtMethodMatcher.java | 105 +++++--- 7 files changed, 220 insertions(+), 177 deletions(-) rename spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/{InvokeVisitAction.java => InvocationVisitAction.java} (84%) create mode 100644 spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/MatchResult.java diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java index 256fc948..74b343dc 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java @@ -79,6 +79,13 @@ public class IType { return this; } + public boolean similar(IType targetType) { + if (isGenericType()) { + //TODO + } + return false; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof IType)) { diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java index a6f399af..d7864c4a 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/ExpressDeclareAction.java @@ -25,7 +25,7 @@ public class ExpressDeclareAction extends AbstractAppElementAction { @Autowired public VariableTrackAction variableAction; @Autowired - public InvokeVisitAction invokeAction; + public InvocationVisitAction invokeAction; @Autowired public StatementDeducer deducer; @Autowired diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvocationVisitAction.java similarity index 84% rename from spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java rename to spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvocationVisitAction.java index 491db1b7..25a6f86d 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvokeVisitAction.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/action/InvocationVisitAction.java @@ -1,117 +1,122 @@ -package com.gitee.spirit.core.compile.action; - -import java.util.ArrayList; -import java.util.List; - -import com.gitee.spirit.common.utils.ListUtils; -import com.gitee.spirit.core.clazz.utils.CommonTypes; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import com.gitee.spirit.common.constants.Attribute; -import com.gitee.spirit.core.api.ClassLinker; -import com.gitee.spirit.core.api.StatementDeducer; -import com.gitee.spirit.core.api.TypeFactory; -import com.gitee.spirit.core.clazz.entity.IType; -import com.gitee.spirit.core.compile.entity.VisitContext; -import com.gitee.spirit.core.element.entity.Element; -import com.gitee.spirit.core.element.entity.Statement; -import com.gitee.spirit.core.element.entity.Token; -import com.gitee.spirit.core.element.utils.StmtVisitor; - -@Component -@Order(-40) -public class InvokeVisitAction extends AbstractAppElementAction { - - @Autowired - public TypeFactory factory; - @Autowired - public StatementDeducer deducer; - @Autowired - public ClassLinker linker; - - @Override - public void visitElement(VisitContext context, Element element) { - StmtVisitor.forEachStmt(element, statement -> { - for (int index = 0; index < statement.size(); index++) { - try { - Token token = statement.get(index); - if (token.attr(Attribute.TYPE) != null) { - continue; - } - - List parameterTypes = token.isInvoke() ? getParameterTypes(token) : null; - - if (token.isTypeSmartBuilder()) { - token.setAttr(Attribute.TYPE, CommonTypes.NULL); - - } else if (token.isType() || token.isArrayInit() || token.isTypeInit() - || token.isTypeBuilder() || token.isCast() || token.isLiteral()) { - token.setAttr(Attribute.TYPE, factory.create(context.clazz, token)); - - } else if (token.isSubexpress()) { - Statement subStatement = token.getValue(); - token.setAttr(Attribute.TYPE, deducer.derive(subStatement.subStmt("(", ")"))); - - } else if (token.isVisitField()) { - IType type = statement.get(index - 1).attr(Attribute.TYPE); - String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitField(type, memberName); - token.setAttr(Attribute.TYPE, returnType); - - } else if (token.isLocalMethod()) { - String memberName = token.attr(Attribute.MEMBER_NAME); - IType type = context.clazz.getType().withPrivate(); - IType returnType = linker.visitMethod(type, memberName, parameterTypes); - token.setAttr(Attribute.TYPE, returnType); - //for smart builder - parameterTypes = linker.getParameterTypes(type, memberName, parameterTypes); - setTypeForSmartBuilder(token, parameterTypes); - - } else if (token.isVisitMethod()) { - IType type = statement.get(index - 1).attr(Attribute.TYPE); - String memberName = token.attr(Attribute.MEMBER_NAME); - IType returnType = linker.visitMethod(type, memberName, parameterTypes); - token.setAttr(Attribute.TYPE, returnType); - //for smart builder - parameterTypes = linker.getParameterTypes(type, memberName, parameterTypes); - setTypeForSmartBuilder(token, parameterTypes); - - } else if (token.isVisitIndex()) {// what like "[0]" - IType type = statement.get(index - 1).attr(Attribute.TYPE); - type = type.toTarget();// 转换数组类型为目标类型 - token.setAttr(Attribute.TYPE, type); - } - - } catch (NoSuchFieldException | NoSuchMethodException e) { - throw new RuntimeException("Link failed for class member!", e); - } - } - }); - } - - public List getParameterTypes(Token token) { - List parameterTypes = new ArrayList<>(); - Statement statement = token.getValue(); - if (statement.size() > 3) { - List subStatements = statement.subStmt(2, statement.size() - 1).splitStmt(","); - for (Statement subStatement : subStatements) { - IType parameterType = deducer.derive(subStatement); - parameterTypes.add(parameterType); - } - } - return parameterTypes; - } - - public void setTypeForSmartBuilder(Token token, List parameterTypes) { - if (!parameterTypes.isEmpty()) { - if (ListUtils.findOne(parameterTypes, parameterType -> parameterType == CommonTypes.NULL) != null) { - Statement statement = token.getValue(); - List subStatements = statement.subStmt(2, statement.size() - 1).splitStmt(","); - //TODO 这里添加逻辑 - } - } - } - -} +package com.gitee.spirit.core.compile.action; + +import java.util.ArrayList; +import java.util.List; + +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.clazz.utils.CommonTypes; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.gitee.spirit.common.constants.Attribute; +import com.gitee.spirit.core.api.ClassLinker; +import com.gitee.spirit.core.api.StatementDeducer; +import com.gitee.spirit.core.api.TypeFactory; +import com.gitee.spirit.core.clazz.entity.IType; +import com.gitee.spirit.core.compile.entity.VisitContext; +import com.gitee.spirit.core.element.entity.Element; +import com.gitee.spirit.core.element.entity.Statement; +import com.gitee.spirit.core.element.entity.Token; +import com.gitee.spirit.core.element.utils.StmtVisitor; + +@Component +@Order(-40) +public class InvocationVisitAction extends AbstractAppElementAction { + + @Autowired + public TypeFactory factory; + @Autowired + public StatementDeducer deducer; + @Autowired + public ClassLinker linker; + + @Override + public void visitElement(VisitContext context, Element element) { + StmtVisitor.forEachStmt(element, statement -> { + for (int index = 0; index < statement.size(); index++) { + try { + Token token = statement.get(index); + if (token.attr(Attribute.TYPE) != null) { + continue; + } + + List parameterTypes = token.isInvoke() ? getParameterTypes(token) : null; + + if (token.isTypeSmartBuilder()) { + token.setAttr(Attribute.TYPE, CommonTypes.NULL); + + } else if (token.isType() || token.isArrayInit() || token.isTypeInit() + || token.isTypeBuilder() || token.isCast() || token.isLiteral()) { + token.setAttr(Attribute.TYPE, factory.create(context.clazz, token)); + + } else if (token.isSubexpress()) { + Statement subStatement = token.getValue(); + token.setAttr(Attribute.TYPE, deducer.derive(subStatement.subStmt("(", ")"))); + + } else if (token.isVisitField()) { + IType type = statement.get(index - 1).attr(Attribute.TYPE); + String memberName = token.attr(Attribute.MEMBER_NAME); + IType returnType = linker.visitField(type, memberName); + token.setAttr(Attribute.TYPE, returnType); + + } else if (token.isLocalMethod()) { + String memberName = token.attr(Attribute.MEMBER_NAME); + IType type = context.clazz.getType().withPrivate(); + IType returnType = linker.visitMethod(type, memberName, parameterTypes); + token.setAttr(Attribute.TYPE, returnType); + //for smart builder + parameterTypes = linker.getParameterTypes(type, memberName, parameterTypes); + setTypeForSmartBuilder(token.getValue(), parameterTypes); + + } else if (token.isVisitMethod()) { + IType type = statement.get(index - 1).attr(Attribute.TYPE); + String memberName = token.attr(Attribute.MEMBER_NAME); + IType returnType = linker.visitMethod(type, memberName, parameterTypes); + token.setAttr(Attribute.TYPE, returnType); + //for smart builder + parameterTypes = linker.getParameterTypes(type, memberName, parameterTypes); + setTypeForSmartBuilder(token.getValue(), parameterTypes); + + } else if (token.isVisitIndex()) {// what like "[0]" + IType type = statement.get(index - 1).attr(Attribute.TYPE); + type = type.toTarget();// 转换数组类型为目标类型 + token.setAttr(Attribute.TYPE, type); + } + + } catch (NoSuchFieldException | NoSuchMethodException e) { + throw new RuntimeException("Link failed for class member!", e); + } + } + }); + } + + public List getParameterTypes(Token token) { + List parameterTypes = new ArrayList<>(); + Statement statement = token.getValue(); + if (statement.size() > 3) { + List subStatements = statement.subStmt(2, statement.size() - 1).splitStmt(","); + for (Statement subStatement : subStatements) { + IType parameterType = deducer.derive(subStatement); + parameterTypes.add(parameterType); + } + } + return parameterTypes; + } + + public void setTypeForSmartBuilder(Statement statement, List parameterTypes) { + if (!parameterTypes.isEmpty()) { + List statements = statement.subStmt(2, statement.size() - 1).splitStmt(","); + for (int index = 0; index < statements.size(); index++) { + Statement subStatement = statements.get(index); + if (subStatement.size() == 1) { + Token token = subStatement.firstToken(); + if (token.isTypeSmartBuilder()) { + token.setAttr(Attribute.TYPE, parameterTypes.get(index)); + } + } + } + } + } + +} diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java index 56b751af..21059c00 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java @@ -31,10 +31,6 @@ public class ExtTypeDerivator extends AppTypeDerivator { }); } - public IType populateParameter(IType type, IType parameterType, IType targetType) { - return populateQualifying(type, parameterType, targetType, new HashMap<>()); - } - public IType populateQualifying(IType type, IType parameterType, IType targetType, Map qualifyingTypes) { // 先使用类型填充 targetType = populate(type, targetType); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/MatchResult.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/MatchResult.java new file mode 100644 index 00000000..6cfa2b10 --- /dev/null +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/MatchResult.java @@ -0,0 +1,17 @@ +package com.gitee.spirit.output.java.entity; + +import com.gitee.spirit.core.clazz.entity.IType; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MatchResult { + public List parameterTypes; + public Map qualifyingTypes; +} diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java index 1c24a205..d92b935d 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java @@ -11,6 +11,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.gitee.spirit.core.clazz.utils.CommonTypes; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -30,7 +31,7 @@ import cn.hutool.core.lang.Assert; public class ExtClassLinker implements ClassLinker { @Autowired - public ExtClassLoader classLoader; + public ExtClassLoader loader; @Autowired public ExtTypeFactory factory; @Autowired @@ -41,7 +42,7 @@ public class ExtClassLinker implements ClassLinker { @Override @SuppressWarnings("unchecked") public T toClass(IType type) { - return (T) classLoader.loadClass(type.getClassName());// 可能是数组 + return (T) loader.loadClass(type.getClassName());// 可能是数组 } @Override @@ -91,7 +92,7 @@ public class ExtClassLinker implements ClassLinker { Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); Method method = findMethod(type, methodName, parameterTypes); if (method != null && ReflectUtils.isAccessible(method, type.getModifiers())) { - Map qualifyingTypes = getQualifyingTypes(type, method, parameterTypes); + Map qualifyingTypes = matcher.getParameterTypes(type, method, parameterTypes).qualifyingTypes; return derivator.populateReturnType(type, qualifyingTypes, factory.create(method.getGenericReturnType())); } return null; @@ -101,7 +102,10 @@ public class ExtClassLinker implements ClassLinker { public List getParameterTypes(IType type, String methodName, List parameterTypes) { Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); Method method = findMethod(type, methodName, parameterTypes); - return ListUtils.collectAll(Arrays.asList(method.getParameterTypes()), clazz -> factory.create(clazz)); + if (method != null && ReflectUtils.isAccessible(method, type.getModifiers())) { + return matcher.getParameterTypes(type, method, parameterTypes).parameterTypes; + } + return null; } public Method findMethod(IType type, String methodName, List parameterTypes) { @@ -110,15 +114,4 @@ public class ExtClassLinker implements ClassLinker { return ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); } - public Map getQualifyingTypes(IType type, Method method, List parameterTypes) { - Map qualifyingTypes = new HashMap<>(); - int size = !ReflectUtils.isIndefinite(method) ? method.getParameterCount() : method.getParameterCount() - 1; - Parameter[] parameters = method.getParameters(); - for (int i = 0; i < size; i++) { - // 根据本地类型创建统一的类型 - derivator.populateQualifying(type, parameterTypes.get(i), factory.create(parameters[i].getParameterizedType()), qualifyingTypes); - } - return qualifyingTypes; - } - } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java index 47d7b356..eec72798 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java @@ -2,8 +2,12 @@ package com.gitee.spirit.output.java.linker; import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import com.gitee.spirit.output.java.entity.MatchResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -15,45 +19,66 @@ import com.gitee.spirit.output.java.utils.ReflectUtils; @Component public class ExtMethodMatcher { - @Autowired - public ExtTypeFactory factory; - @Autowired - public ExtTypeDerivator derivator; - - public boolean checkParameterCount(Method method, List parameterTypes) { - if (!ReflectUtils.isIndefinite(method) && parameterTypes.size() == method.getParameterCount()) {// 不是不定项,那么参数个数相等 - return true; - - } else if (ReflectUtils.isIndefinite(method) && parameterTypes.size() >= method.getParameterCount() - 1) {// 不定项,则参数大于等于不定项-1 - return true; - } - return false; - } - - public Integer getMethodScore(IType type, Method method, List parameterTypes) { - if (!checkParameterCount(method, parameterTypes)) { - return null; - } - Integer finalScore = 0; - int index = 0; - for (IType parameterType : parameterTypes) { - int idx = index < method.getParameterCount() - 1 ? index : method.getParameterCount() - 1;// 保证索引不会溢出 - Parameter parameter = method.getParameters()[idx];// 分为两种情况,一种是最后一个参数之前的,一种是最后一个参数 - IType nativeParameterType = factory.create(parameter.getParameterizedType());// 获取本地参数类型 - if (idx == method.getParameterCount() - 1 && ReflectUtils.isIndefinite(parameter)) {// 如果最后一个参数,而且是不定项参数,则取数组里的类型 - nativeParameterType = nativeParameterType.toTarget(); - } - nativeParameterType = derivator.populateParameter(type, parameterType, nativeParameterType);// 填充类型里的泛型参数 - Integer scope = derivator.getAbstractDegree(nativeParameterType, parameterType); - if (scope != null) { - finalScore += scope; - } else { - finalScore = null; - break; - } - index++; - } - return finalScore; - } + @Autowired + public ExtTypeFactory factory; + @Autowired + public ExtTypeDerivator derivator; + + public boolean checkParameterCount(Method method, List parameterTypes) { + if (!ReflectUtils.isIndefinite(method) && parameterTypes.size() == method.getParameterCount()) {// 不是不定项,那么参数个数相等 + return true; + } else if (ReflectUtils.isIndefinite(method) && parameterTypes.size() >= method.getParameterCount() - 1) {// 不定项,则参数大于等于不定项-1 + return true; + } + return false; + } + + public MatchResult getParameterTypes(IType type, Method method, List parameterTypes) { + if (!checkParameterCount(method, parameterTypes)) { + return null; + } + List nativeParameterTypes = new ArrayList<>(); + Map qualifyingTypes = new HashMap<>(); + for (int index = 0; index < parameterTypes.size(); index++) { + IType parameterType = parameterTypes.get(index); + //保证索引不会溢出 + int idx = Math.min(index, method.getParameterCount() - 1); + //分为两种情况,一种是最后一个参数之前的,一种是最后一个参数 + Parameter parameter = method.getParameters()[idx]; + //获取本地参数类型 + IType nativeParameterType = factory.create(parameter.getParameterizedType()); + //如果最后一个参数,而且是不定项参数,则取数组里的类型 + if (idx == method.getParameterCount() - 1 && ReflectUtils.isIndefinite(parameter)) { + nativeParameterType = nativeParameterType.toTarget(); + } + //如果结构不同,则直接返回不匹配 + if (!parameterType.similar(nativeParameterType)) { + return null; + } + //填充类型里的泛型参数 + if (!parameterType.isNull()) { + nativeParameterType = derivator.populateQualifying(type, parameterType, nativeParameterType, qualifyingTypes); + } + //添加到待返回的集合中 + nativeParameterTypes.add(nativeParameterType); + } + return new MatchResult(nativeParameterTypes, qualifyingTypes); + } + + public Integer getMethodScore(IType type, Method method, List parameterTypes) { + List nativeParameterTypes = getParameterTypes(type, method, parameterTypes).parameterTypes; + if (nativeParameterTypes == null) { + return null; + } + Integer finalScore = 0; + for (int index = 0; index < parameterTypes.size(); index++) { + Integer scope = derivator.getAbstractDegree(nativeParameterTypes.get(index), parameterTypes.get(index)); + finalScore = scope != null ? finalScore + scope : null; + if (finalScore == null) { + return null; + } + } + return finalScore; + } } -- Gitee From aa5c4822c0f2fcad08b7e950c31d5c3e37d6b29e Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Wed, 14 Jul 2021 19:27:19 +0800 Subject: [PATCH 74/83] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/clazz/entity/IType.java | 23 +--- .../compile/derivator/AppTypeDerivator.java | 100 +++++++-------- .../core/compile/entity/MatchResult.java | 17 +++ .../core/compile/linker/AppClassLinker.java | 4 +- .../core/compile/linker/AppMethodMatcher.java | 74 +++++++---- .../spirit/output/java/ExtTypeDerivator.java | 118 +++++++++--------- .../output/java/entity/MatchResult.java | 2 + .../output/java/linker/ExtClassLinker.java | 18 +-- .../output/java/linker/ExtMethodMatcher.java | 31 +++-- 9 files changed, 217 insertions(+), 170 deletions(-) create mode 100644 spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/entity/MatchResult.java diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java index 74b343dc..226ceb8b 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java @@ -3,6 +3,7 @@ package com.gitee.spirit.core.clazz.entity; import java.util.ArrayList; import java.util.List; +import com.gitee.spirit.core.clazz.utils.TypeVisitor; import org.apache.commons.lang3.StringUtils; import com.gitee.spirit.common.enums.AccessLevelEnum; @@ -79,30 +80,14 @@ public class IType { return this; } - public boolean similar(IType targetType) { - if (isGenericType()) { - //TODO - } - return false; - } - @Override public boolean equals(Object obj) { if (!(obj instanceof IType)) { return false; } - IType typeToMatch = (IType) obj; - boolean flag = getClassName().equals(typeToMatch.getClassName()); - if (flag) { - int count = 0; - for (IType genericType : getGenericTypes()) { - if (!genericType.equals(typeToMatch.getGenericTypes().get(count++))) { - flag = false; - break; - } - } - } - return flag; + String finalName = TypeVisitor.forEachTypeName(this, IType::getTypeName); + String targetFinalName = TypeVisitor.forEachTypeName((IType) obj, IType::getTypeName); + return finalName.equals(targetFinalName); } @Override diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 2119c38b..9543ddfe 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -16,58 +16,58 @@ import cn.hutool.core.lang.Assert; @Component public class AppTypeDerivator implements TypeDerivator { - @Autowired - public ClassLinker linker; + @Autowired + public ClassLinker linker; - @Override - public Integer getAbstractDegree(IType abstractType, IType targetType) { - if (abstractType == null || targetType == null) { - return null; - } - // null类型不能比任何类型抽象 - if (abstractType.isNull()) { - return null; - } - // 任何类型都能比null抽象 - if (targetType.isNull()) { - return 0; - } - // 这个方法还要判断泛型 - if (targetType.equals(abstractType)) { - return 0; - } - // 这个方法中,还要考虑到自动拆组包 - Integer superTypeDegree = getAbstractDegree(abstractType, linker.getSuperType(targetType.toBox())); - if (superTypeDegree != null) { - return superTypeDegree - 1; - } - // 接口 - for (IType interfaceType : linker.getInterfaceTypes(targetType)) { - Integer interfaceTypeDegree = getAbstractDegree(abstractType, interfaceType); - if (interfaceTypeDegree != null) { - return interfaceTypeDegree - 1; - } - } - return null; - } + @Override + public Integer getAbstractDegree(IType abstractType, IType targetType) { + if (abstractType == null || targetType == null) { + return null; + } + // null类型不能比任何类型抽象 + if (abstractType.isNull()) { + return null; + } + // 任何类型都能比null抽象 + if (targetType.isNull()) { + return 0; + } + // 这个方法还要判断泛型 + if (targetType.equals(abstractType)) { + return 0; + } + // 这个方法中,还要考虑到自动拆组包 + Integer superTypeDegree = getAbstractDegree(abstractType, linker.getSuperType(targetType.toBox())); + if (superTypeDegree != null) { + return superTypeDegree - 1; + } + // 接口 + for (IType interfaceType : linker.getInterfaceTypes(targetType)) { + Integer interfaceTypeDegree = getAbstractDegree(abstractType, interfaceType); + if (interfaceTypeDegree != null) { + return interfaceTypeDegree - 1; + } + } + return null; + } - @Override - public boolean isMoreAbstract(IType abstractType, IType targetType) { - return getAbstractDegree(abstractType, targetType) != null; - } + @Override + public boolean isMoreAbstract(IType abstractType, IType targetType) { + return getAbstractDegree(abstractType, targetType) != null; + } - @Override - public IType populate(IType instanceType, IType targetType) { - // 根据全局类型,进行填充 - return TypeVisitor.forEachType(targetType, eachType -> { - if (eachType.isTypeVariable()) { - int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); - Assert.isTrue(index >= 0, "Index of type variable less than 0!"); - Assert.isTrue(instanceType.isGenericType(), "Type must be a generic type!"); - return TypeBuilder.copy(instanceType.getGenericTypes().get(index)); - } - return eachType; - }); - } + @Override + public IType populate(IType instanceType, IType targetType) { + // 根据全局类型,进行填充 + return TypeVisitor.forEachType(targetType, eachType -> { + if (eachType.isTypeVariable()) { + int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); + Assert.isTrue(index >= 0, "Index of type variable less than 0!"); + Assert.isTrue(instanceType.isGenericType(), "Type must be a generic type!"); + return TypeBuilder.copy(instanceType.getGenericTypes().get(index)); + } + return eachType; + }); + } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/entity/MatchResult.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/entity/MatchResult.java new file mode 100644 index 00000000..de8951f8 --- /dev/null +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/entity/MatchResult.java @@ -0,0 +1,17 @@ +package com.gitee.spirit.core.compile.entity; + +import com.gitee.spirit.core.clazz.entity.IMethod; +import com.gitee.spirit.core.clazz.entity.IType; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MatchResult { + public IMethod method; + public List parameterTypes; +} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java index 3da98f06..8908fb28 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java @@ -24,7 +24,7 @@ import cn.hutool.core.lang.Assert; public class AppClassLinker implements ClassLinker { @Autowired - public AppClassLoader classLoader; + public AppClassLoader loader; @Autowired public ClassVisitor visitor; @Autowired @@ -36,7 +36,7 @@ public class AppClassLinker implements ClassLinker { @SuppressWarnings("unchecked") public T toClass(IType type) { Assert.isTrue(!type.isArray(), "Array has no class!");// 这里认为数组没有class,也不应该有 - return (T) classLoader.loadClass(type.getClassName()); + return (T) loader.loadClass(type.getClassName()); } @Override diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java index eea64688..b9e9c675 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java @@ -1,7 +1,12 @@ package com.gitee.spirit.core.compile.linker; +import java.lang.reflect.Method; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.compile.entity.MatchResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -13,26 +18,51 @@ import com.gitee.spirit.core.clazz.entity.IType; @Component public class AppMethodMatcher { - @Autowired - public TypeDerivator derivator; - - public Integer getMethodScore(IType type, IMethod method, List parameterTypes) { - if (method.parameters.size() != parameterTypes.size()) { - return null; - } - Integer finalScore = 0; - int index = 0; - for (IType parameterType : parameterTypes) { - IParameter parameter = method.parameters.get(index++); - IType methodParameterType = derivator.populate(type, parameter.getType()); - Integer scope = derivator.getAbstractDegree(methodParameterType, parameterType); - if (scope != null) { - finalScore += scope; - } else { - finalScore = null; - break; - } - } - return finalScore; - } + @Autowired + public TypeDerivator derivator; + + public boolean checkParameterCount(IMethod method, List parameterTypes) { + return method.parameters.size() == parameterTypes.size(); + } + + public MatchResult getParameterTypes(IType type, IMethod method, List parameterTypes) { + if (!checkParameterCount(method, parameterTypes)) { + return null; + } + List methodParameterTypes = method.getParameterTypes(); + for (int index = 0; index < parameterTypes.size(); index++) { + IType methodParameterType = derivator.populate(type, methodParameterTypes.get(index)); + methodParameterTypes.set(index, methodParameterType); + } + return new MatchResult(method, methodParameterTypes); + } + + public Integer getMethodScore(IType type, IMethod method, List parameterTypes) { + Integer finalScore = 0; + int index = 0; + for (IType parameterType : parameterTypes) { + IParameter parameter = method.parameters.get(index++); + IType methodParameterType = derivator.populate(type, parameter.getType()); + Integer scope = derivator.getAbstractDegree(methodParameterType, parameterType); + if (scope != null) { + finalScore += scope; + } else { + finalScore = null; + break; + } + } + return finalScore; + } + + public MatchResult findMethod(IType type, List methods, List parameterTypes) { +// Map matchResultMap = new HashMap<>(); +// IMethod method = ListUtils.findOneByScore(methods, eachMethod -> { +// MatchResult matchResult = getParameterTypes(type, eachMethod, parameterTypes); +// matchResultMap.put(eachMethod, matchResult); +// return getMethodScore(parameterTypes, matchResult.parameterTypes); +// }); +// return matchResultMap.get(method); + return null; + } + } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java index 21059c00..f3202cae 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java @@ -15,67 +15,71 @@ import com.gitee.spirit.core.compile.derivator.AppTypeDerivator; @Component public class ExtTypeDerivator extends AppTypeDerivator { - @Autowired - public ClassLinker linker; + @Autowired + public ClassLinker linker; - @Override - public IType populate(IType type, IType targetType) {// 根据全局类型,进行填充 - return TypeVisitor.forEachType(targetType, eachType -> { - if (eachType.isTypeVariable()) { - int index = linker.getTypeVariableIndex(type, eachType.getGenericName()); - if (index >= 0) { - return TypeBuilder.copy(type.getGenericTypes().get(index)); - } - } - return eachType; - }); - } + @Override + public IType populate(IType type, IType targetType) {// 根据全局类型,进行填充 + return TypeVisitor.forEachType(targetType, eachType -> { + if (eachType.isTypeVariable()) { + int index = linker.getTypeVariableIndex(type, eachType.getGenericName()); + if (index >= 0) { + return TypeBuilder.copy(type.getGenericTypes().get(index)); + } + } + return eachType; + }); + } - public IType populateQualifying(IType type, IType parameterType, IType targetType, Map qualifyingTypes) { - // 先使用类型填充 - targetType = populate(type, targetType); - // 然后使用参数类型填充 - targetType = populateQualifying(parameterType, targetType, qualifyingTypes); - // 返回类型 - return targetType; - } + public IType populateParameter(IType type, IType parameterType, IType targetType) { + return populateQualifying(type, parameterType, targetType, new HashMap<>()); + } - public IType populateQualifying(IType parameterType, IType targetType, Map qualifyingTypes) { - return TypeVisitor.forEachType(parameterType, targetType, (referType, eachType) -> { - if (eachType.isTypeVariable()) { - String genericName = eachType.getGenericName(); - if (qualifyingTypes.containsKey(genericName)) {// 如果已经存在了,则必须统一 - IType existType = qualifyingTypes.get(genericName); - if (!existType.equals(referType)) { - throw new RuntimeException("Parameter qualification types are not uniform!"); - } - return TypeBuilder.copy(referType); + public IType populateQualifying(IType type, IType parameterType, IType targetType, Map qualifyingTypes) { + // 先使用类型填充 + targetType = populate(type, targetType); + // 然后使用参数类型填充 + targetType = populateQualifying(parameterType, targetType, qualifyingTypes); + // 返回类型 + return targetType; + } - } else { - referType = TypeBuilder.copy(referType); - qualifyingTypes.put(genericName, referType); - return referType; - } - } - return eachType; - }); - } + public IType populateQualifying(IType parameterType, IType targetType, Map qualifyingTypes) { + return TypeVisitor.forEachType(parameterType, targetType, (referType, eachType) -> { + if (eachType.isTypeVariable()) { + String genericName = eachType.getGenericName(); + if (qualifyingTypes.containsKey(genericName)) {// 如果已经存在了,则必须统一 + IType existType = qualifyingTypes.get(genericName); + if (!existType.equals(referType)) { + throw new RuntimeException("Parameter qualification types are not uniform!"); + } + return TypeBuilder.copy(referType); - public IType populateReturnType(IType type, Map qualifyingTypes, IType targetType) { - // 先使用类型填充 - targetType = populate(type, targetType); - // 再用限定类型填充 - targetType = populateReturnType(qualifyingTypes, targetType); - // 返回类型 - return targetType; - } + } else { + referType = TypeBuilder.copy(referType); + qualifyingTypes.put(genericName, referType); + return referType; + } + } + return eachType; + }); + } - public IType populateReturnType(Map qualifyingTypes, IType targetType) { - return TypeVisitor.forEachType(targetType, eachType -> { - if (eachType.isTypeVariable()) { - return qualifyingTypes.get(targetType.getGenericName()); - } - return eachType; - }); - } + public IType populateReturnType(IType type, Map qualifyingTypes, IType targetType) { + // 先使用类型填充 + targetType = populate(type, targetType); + // 再用限定类型填充 + targetType = populateReturnType(qualifyingTypes, targetType); + // 返回类型 + return targetType; + } + + public IType populateReturnType(Map qualifyingTypes, IType targetType) { + return TypeVisitor.forEachType(targetType, eachType -> { + if (eachType.isTypeVariable()) { + return qualifyingTypes.get(targetType.getGenericName()); + } + return eachType; + }); + } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/MatchResult.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/MatchResult.java index 6cfa2b10..3226d9ad 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/MatchResult.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/entity/MatchResult.java @@ -5,6 +5,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.lang.reflect.Method; import java.util.List; import java.util.Map; @@ -12,6 +13,7 @@ import java.util.Map; @NoArgsConstructor @AllArgsConstructor public class MatchResult { + public Method method; public List parameterTypes; public Map qualifyingTypes; } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java index d92b935d..e29db38b 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import com.gitee.spirit.core.clazz.utils.CommonTypes; +import com.gitee.spirit.output.java.entity.MatchResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -90,10 +91,9 @@ public class ExtClassLinker implements ClassLinker { @Override public IType visitMethod(IType type, String methodName, List parameterTypes) { Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); - Method method = findMethod(type, methodName, parameterTypes); - if (method != null && ReflectUtils.isAccessible(method, type.getModifiers())) { - Map qualifyingTypes = matcher.getParameterTypes(type, method, parameterTypes).qualifyingTypes; - return derivator.populateReturnType(type, qualifyingTypes, factory.create(method.getGenericReturnType())); + MatchResult matchResult = findMethod(type, methodName, parameterTypes); + if (matchResult.method != null && ReflectUtils.isAccessible(matchResult.method, type.getModifiers())) { + return derivator.populateReturnType(type, matchResult.qualifyingTypes, factory.create(matchResult.method.getGenericReturnType())); } return null; } @@ -101,17 +101,17 @@ public class ExtClassLinker implements ClassLinker { @Override public List getParameterTypes(IType type, String methodName, List parameterTypes) { Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); - Method method = findMethod(type, methodName, parameterTypes); - if (method != null && ReflectUtils.isAccessible(method, type.getModifiers())) { - return matcher.getParameterTypes(type, method, parameterTypes).parameterTypes; + MatchResult matchResult = findMethod(type, methodName, parameterTypes); + if (matchResult.method != null && ReflectUtils.isAccessible(matchResult.method, type.getModifiers())) { + return matchResult.parameterTypes; } return null; } - public Method findMethod(IType type, String methodName, List parameterTypes) { + public MatchResult findMethod(IType type, String methodName, List parameterTypes) { Class clazz = toClass(type); List methods = ListUtils.findAll(Arrays.asList(clazz.getDeclaredMethods()), method -> methodName.equals(method.getName())); - return ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); + return matcher.findMethod(type, methods, parameterTypes); } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java index eec72798..6d48babb 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java @@ -2,11 +2,9 @@ package com.gitee.spirit.output.java.linker; import java.lang.reflect.Method; import java.lang.reflect.Parameter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.output.java.entity.MatchResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -51,8 +49,10 @@ public class ExtMethodMatcher { if (idx == method.getParameterCount() - 1 && ReflectUtils.isIndefinite(parameter)) { nativeParameterType = nativeParameterType.toTarget(); } + //这里选择强制填充 + nativeParameterType = derivator.populateParameter(type, parameterType, nativeParameterType); //如果结构不同,则直接返回不匹配 - if (!parameterType.similar(nativeParameterType)) { + if (!derivator.isMoreAbstract(nativeParameterType, parameterType)) { return null; } //填充类型里的泛型参数 @@ -62,14 +62,10 @@ public class ExtMethodMatcher { //添加到待返回的集合中 nativeParameterTypes.add(nativeParameterType); } - return new MatchResult(nativeParameterTypes, qualifyingTypes); + return new MatchResult(method, nativeParameterTypes, qualifyingTypes); } - public Integer getMethodScore(IType type, Method method, List parameterTypes) { - List nativeParameterTypes = getParameterTypes(type, method, parameterTypes).parameterTypes; - if (nativeParameterTypes == null) { - return null; - } + public Integer getMethodScore(List parameterTypes, List nativeParameterTypes) { Integer finalScore = 0; for (int index = 0; index < parameterTypes.size(); index++) { Integer scope = derivator.getAbstractDegree(nativeParameterTypes.get(index), parameterTypes.get(index)); @@ -81,4 +77,17 @@ public class ExtMethodMatcher { return finalScore; } + public MatchResult findMethod(IType type, List methods, List parameterTypes) { + Map matchResultMap = new HashMap<>(); + Method method = ListUtils.findOneByScore(methods, eachMethod -> { + MatchResult matchResult = getParameterTypes(type, eachMethod, parameterTypes); + if (matchResult != null) { + matchResultMap.put(eachMethod, matchResult); + return getMethodScore(parameterTypes, matchResult.parameterTypes); + } + return -1; + }); + return matchResultMap.get(method); + } + } -- Gitee From 35a89efb770eaadcbf1eea65158e7d6a3be61c60 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Wed, 14 Jul 2021 22:45:11 +0800 Subject: [PATCH 75/83] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=8E=A8=E5=AF=BC=E5=A4=A7=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/clazz/entity/IType.java | 3 + .../gitee/spirit/core/api/TypeDerivator.java | 10 +++- .../compile/derivator/AppTypeDerivator.java | 58 ++++++++++++++----- .../core/compile/linker/AppClassLinker.java | 14 +++-- .../core/compile/linker/AppMethodMatcher.java | 32 +++++----- .../spirit/output/java/ExtTypeDerivator.java | 12 ++-- .../output/java/linker/ExtClassLinker.java | 4 +- .../output/java/linker/ExtMethodMatcher.java | 20 ++++--- 8 files changed, 94 insertions(+), 59 deletions(-) diff --git a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java index 226ceb8b..8b6109f5 100644 --- a/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java +++ b/spirit-core/spirit-core-class/src/main/java/com/gitee/spirit/core/clazz/entity/IType.java @@ -3,7 +3,10 @@ package com.gitee.spirit.core.clazz.entity; import java.util.ArrayList; import java.util.List; +import com.gitee.spirit.common.utils.ListUtils; import com.gitee.spirit.core.clazz.utils.TypeVisitor; +import com.google.common.base.CharMatcher; +import com.google.common.base.Splitter; import org.apache.commons.lang3.StringUtils; import com.gitee.spirit.common.enums.AccessLevelEnum; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java index d67ce0fd..3f0cbc4b 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java @@ -4,10 +4,14 @@ import com.gitee.spirit.core.clazz.entity.IType; public interface TypeDerivator { - Integer getAbstractDegree(IType abstractType, IType targetType); + IType populate(IType instanceType, IType targetType); - boolean isMoreAbstract(IType abstractType, IType targetType); + boolean similar(IType targetType1, IType targetType2); - IType populate(IType instanceType, IType targetType); + IType findReferenceType(IType targetType, IType referenceType); + + Integer getAbstractDegree(IType abstractType, IType targetType); + + boolean isMoreAbstract(IType abstractType, IType targetType); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 9543ddfe..817bb6bc 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -19,6 +19,51 @@ public class AppTypeDerivator implements TypeDerivator { @Autowired public ClassLinker linker; + @Override + public IType populate(IType instanceType, IType targetType) { + // 根据全局类型,进行填充 + return TypeVisitor.forEachType(targetType, eachType -> { + if (eachType.isTypeVariable()) { + int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); + Assert.isTrue(index >= 0, "Index of type variable less than 0!"); + Assert.isTrue(instanceType.isGenericType(), "Type must be a generic type!"); + return TypeBuilder.copy(instanceType.getGenericTypes().get(index)); + } + return eachType; + }); + } + + @Override + public boolean similar(IType targetType1, IType targetType2) { + String finalName1 = TypeVisitor.forEachTypeName(targetType1, eachType -> ""); + String finalName2 = TypeVisitor.forEachTypeName(targetType2, eachType -> ""); + return finalName1.equals(finalName2); + } + + @Override + public IType findReferenceType(IType targetType, IType referenceType) { + Assert.notNull(targetType, "The target type cannot be null!"); + Assert.notNull(referenceType, "The reference type cannot be null!"); + if (targetType.isNull()) { + return referenceType; + } + if (targetType.getClassName().equals(referenceType.getClassName())) { + Assert.isTrue(similar(targetType, referenceType), "The two types must be structurally similar!"); + return targetType; + } + IType superType = findReferenceType(linker.getSuperType(targetType.toBox()), referenceType); + if (superType != null) { + return superType; + } + for (IType interfaceType : linker.getInterfaceTypes(targetType)) { + interfaceType = findReferenceType(interfaceType, referenceType); + if (interfaceType != null) { + return interfaceType; + } + } + return null; + } + @Override public Integer getAbstractDegree(IType abstractType, IType targetType) { if (abstractType == null || targetType == null) { @@ -56,18 +101,5 @@ public class AppTypeDerivator implements TypeDerivator { return getAbstractDegree(abstractType, targetType) != null; } - @Override - public IType populate(IType instanceType, IType targetType) { - // 根据全局类型,进行填充 - return TypeVisitor.forEachType(targetType, eachType -> { - if (eachType.isTypeVariable()) { - int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); - Assert.isTrue(index >= 0, "Index of type variable less than 0!"); - Assert.isTrue(instanceType.isGenericType(), "Type must be a generic type!"); - return TypeBuilder.copy(instanceType.getGenericTypes().get(index)); - } - return eachType; - }); - } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java index 8908fb28..e9f52474 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppClassLinker.java @@ -3,6 +3,7 @@ package com.gitee.spirit.core.compile.linker; import java.util.ArrayList; import java.util.List; +import com.gitee.spirit.core.compile.entity.MatchResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -76,9 +77,9 @@ public class AppClassLinker implements ClassLinker { public IType visitMethod(IType type, String methodName, List parameterTypes) { IClass clazz = toClass(type); List methods = clazz.getMethods(methodName); - IMethod method = ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); - if (method != null) { - return derivator.populate(type, visitor.visitMember(clazz, method)); + MatchResult matchResult = matcher.findMethod(type, methods, parameterTypes); + if (matchResult != null) { + return derivator.populate(type, visitor.visitMember(clazz, matchResult.method)); } return null; } @@ -87,8 +88,11 @@ public class AppClassLinker implements ClassLinker { public List getParameterTypes(IType type, String methodName, List parameterTypes) { IClass clazz = toClass(type); List methods = clazz.getMethods(methodName); - IMethod method = ListUtils.findOneByScore(methods, eachMethod -> matcher.getMethodScore(type, eachMethod, parameterTypes)); - return method.getParameterTypes(); + MatchResult matchResult = matcher.findMethod(type, methods, parameterTypes); + if (matchResult != null) { + return matchResult.parameterTypes; + } + return null; } } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java index b9e9c675..27664e03 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java @@ -37,32 +37,26 @@ public class AppMethodMatcher { return new MatchResult(method, methodParameterTypes); } - public Integer getMethodScore(IType type, IMethod method, List parameterTypes) { + public Integer getMethodScore(List parameterTypes, List methodParameterTypes) { Integer finalScore = 0; - int index = 0; - for (IType parameterType : parameterTypes) { - IParameter parameter = method.parameters.get(index++); - IType methodParameterType = derivator.populate(type, parameter.getType()); - Integer scope = derivator.getAbstractDegree(methodParameterType, parameterType); - if (scope != null) { - finalScore += scope; - } else { - finalScore = null; - break; + for (int index = 0; index < parameterTypes.size(); index++) { + Integer scope = derivator.getAbstractDegree(methodParameterTypes.get(index), parameterTypes.get(index)); + finalScore = scope != null ? finalScore + scope : null; + if (finalScore == null) { + return null; } } return finalScore; } public MatchResult findMethod(IType type, List methods, List parameterTypes) { -// Map matchResultMap = new HashMap<>(); -// IMethod method = ListUtils.findOneByScore(methods, eachMethod -> { -// MatchResult matchResult = getParameterTypes(type, eachMethod, parameterTypes); -// matchResultMap.put(eachMethod, matchResult); -// return getMethodScore(parameterTypes, matchResult.parameterTypes); -// }); -// return matchResultMap.get(method); - return null; + Map matchResultMap = new HashMap<>(); + IMethod method = ListUtils.findOneByScore(methods, eachMethod -> { + MatchResult matchResult = getParameterTypes(type, eachMethod, parameterTypes); + matchResultMap.put(eachMethod, matchResult); + return getMethodScore(parameterTypes, matchResult.parameterTypes); + }); + return matchResultMap.get(method); } } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java index f3202cae..194db4fd 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java @@ -19,22 +19,18 @@ public class ExtTypeDerivator extends AppTypeDerivator { public ClassLinker linker; @Override - public IType populate(IType type, IType targetType) {// 根据全局类型,进行填充 + public IType populate(IType instanceType, IType targetType) { return TypeVisitor.forEachType(targetType, eachType -> { if (eachType.isTypeVariable()) { - int index = linker.getTypeVariableIndex(type, eachType.getGenericName()); + int index = linker.getTypeVariableIndex(instanceType, eachType.getGenericName()); if (index >= 0) { - return TypeBuilder.copy(type.getGenericTypes().get(index)); + return TypeBuilder.copy(instanceType.getGenericTypes().get(index)); } } return eachType; }); } - public IType populateParameter(IType type, IType parameterType, IType targetType) { - return populateQualifying(type, parameterType, targetType, new HashMap<>()); - } - public IType populateQualifying(IType type, IType parameterType, IType targetType, Map qualifyingTypes) { // 先使用类型填充 targetType = populate(type, targetType); @@ -51,7 +47,7 @@ public class ExtTypeDerivator extends AppTypeDerivator { if (qualifyingTypes.containsKey(genericName)) {// 如果已经存在了,则必须统一 IType existType = qualifyingTypes.get(genericName); if (!existType.equals(referType)) { - throw new RuntimeException("Parameter qualification types are not uniform!"); + throw new IllegalArgumentException("Parameter qualification types are not uniform!"); } return TypeBuilder.copy(referType); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java index e29db38b..a10bca46 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtClassLinker.java @@ -92,7 +92,7 @@ public class ExtClassLinker implements ClassLinker { public IType visitMethod(IType type, String methodName, List parameterTypes) { Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); MatchResult matchResult = findMethod(type, methodName, parameterTypes); - if (matchResult.method != null && ReflectUtils.isAccessible(matchResult.method, type.getModifiers())) { + if (matchResult != null && ReflectUtils.isAccessible(matchResult.method, type.getModifiers())) { return derivator.populateReturnType(type, matchResult.qualifyingTypes, factory.create(matchResult.method.getGenericReturnType())); } return null; @@ -102,7 +102,7 @@ public class ExtClassLinker implements ClassLinker { public List getParameterTypes(IType type, String methodName, List parameterTypes) { Assert.isTrue(type.getModifiers() != 0, "Modifiers for accessible members must be set!methodName:" + methodName); MatchResult matchResult = findMethod(type, methodName, parameterTypes); - if (matchResult.method != null && ReflectUtils.isAccessible(matchResult.method, type.getModifiers())) { + if (matchResult != null && ReflectUtils.isAccessible(matchResult.method, type.getModifiers())) { return matchResult.parameterTypes; } return null; diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java index 6d48babb..c068786a 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java @@ -49,15 +49,17 @@ public class ExtMethodMatcher { if (idx == method.getParameterCount() - 1 && ReflectUtils.isIndefinite(parameter)) { nativeParameterType = nativeParameterType.toTarget(); } - //这里选择强制填充 - nativeParameterType = derivator.populateParameter(type, parameterType, nativeParameterType); - //如果结构不同,则直接返回不匹配 - if (!derivator.isMoreAbstract(nativeParameterType, parameterType)) { + //从继承关系中,找出适当的类型 + parameterType = derivator.findReferenceType(parameterType, nativeParameterType); + //没有找到对应的,则直接返回 + if (parameterType == null) { return null; } - //填充类型里的泛型参数 - if (!parameterType.isNull()) { + //如果因为限定冲突,则直接返回null + try { nativeParameterType = derivator.populateQualifying(type, parameterType, nativeParameterType, qualifyingTypes); + } catch (IllegalArgumentException e) { + return null; } //添加到待返回的集合中 nativeParameterTypes.add(nativeParameterType); @@ -65,10 +67,10 @@ public class ExtMethodMatcher { return new MatchResult(method, nativeParameterTypes, qualifyingTypes); } - public Integer getMethodScore(List parameterTypes, List nativeParameterTypes) { + public Integer getMethodScore(List parameterTypes, List methodParameterTypes) { Integer finalScore = 0; for (int index = 0; index < parameterTypes.size(); index++) { - Integer scope = derivator.getAbstractDegree(nativeParameterTypes.get(index), parameterTypes.get(index)); + Integer scope = derivator.getAbstractDegree(methodParameterTypes.get(index), parameterTypes.get(index)); finalScore = scope != null ? finalScore + scope : null; if (finalScore == null) { return null; @@ -85,7 +87,7 @@ public class ExtMethodMatcher { matchResultMap.put(eachMethod, matchResult); return getMethodScore(parameterTypes, matchResult.parameterTypes); } - return -1; + return null; }); return matchResultMap.get(method); } -- Gitee From fdc49a42513b2cf306b463976183a4d809430a45 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Wed, 14 Jul 2021 23:41:09 +0800 Subject: [PATCH 76/83] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E6=8E=A8=E5=AF=BC=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compile/derivator/AppTypeDerivator.java | 5 +++-- .../compile/linker/AdaptiveClassLinker.java | 22 ++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 817bb6bc..8800cf10 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -42,8 +42,9 @@ public class AppTypeDerivator implements TypeDerivator { @Override public IType findReferenceType(IType targetType, IType referenceType) { - Assert.notNull(targetType, "The target type cannot be null!"); - Assert.notNull(referenceType, "The reference type cannot be null!"); + if (targetType == null || referenceType == null) { + return null; + } if (targetType.isNull()) { return referenceType; } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java index 3bdeafe6..a6d8d4ab 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AdaptiveClassLinker.java @@ -121,7 +121,27 @@ public class AdaptiveClassLinker implements ClassLinker { @Override public List getParameterTypes(IType type, String methodName, List parameterTypes) throws NoSuchMethodException { - return chooseLinker(type).getParameterTypes(type, methodName, parameterTypes); + Assert.notNull(type, "Type cannot be null!"); + Assert.notEmpty(methodName, "Method name cannot be empty!"); + // super()和this()指代父类或者本身的构造函数,返回这个类本身 + if (Dictionary.SUPER.equals(methodName) || Dictionary.THIS.equals(methodName)) { + return parameterTypes; + } + // 如果已经推导到Object,并且方法名是empty的话,则直接返回布尔类型 + if (CommonTypes.OBJECT.equals(type) && Dictionary.EMPTY.equals(methodName)) { + return parameterTypes; + } + List methodParameterTypes = chooseLinker(type).getParameterTypes(type, methodName, parameterTypes); + if (methodParameterTypes == null) { + IType superType = getSuperType(type); + if (superType != null) { + return getParameterTypes(superType, methodName, parameterTypes); + } + } + if (methodParameterTypes == null) { + throw new NoSuchMethodException(String.format("No such method!className:%s, methodName:%s", type.getClassName(), methodName)); + } + return methodParameterTypes; } } -- Gitee From 063805c006869be61c629eca3ce9f9aea20487d3 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Thu, 15 Jul 2021 23:07:30 +0800 Subject: [PATCH 77/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E4=BC=98=E5=8C=96=E5=8C=B9=E9=85=8D=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/spirit/core/api/TypeDerivator.java | 8 +++- .../compile/derivator/AppTypeDerivator.java | 37 +++++++++++++------ .../core/compile/linker/AppMethodMatcher.java | 19 +++------- .../spirit/output/java/ExtTypeDerivator.java | 13 ++----- .../output/java/linker/ExtMethodMatcher.java | 24 +++--------- 5 files changed, 46 insertions(+), 55 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java index 3f0cbc4b..9c277844 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java @@ -2,16 +2,20 @@ package com.gitee.spirit.core.api; import com.gitee.spirit.core.clazz.entity.IType; +import java.util.List; + public interface TypeDerivator { IType populate(IType instanceType, IType targetType); - boolean similar(IType targetType1, IType targetType2); + boolean isSimilar(IType targetType1, IType targetType2); - IType findReferenceType(IType targetType, IType referenceType); + IType findTypeByInherit(IType instanceType, IType targetType); Integer getAbstractDegree(IType abstractType, IType targetType); + Integer getMatchingDegree(List parameterTypes, List methodParameterTypes); + boolean isMoreAbstract(IType abstractType, IType targetType); } diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 8800cf10..77258884 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -12,6 +12,8 @@ import com.gitee.spirit.core.clazz.utils.TypeVisitor; import cn.hutool.core.lang.Assert; +import java.util.List; + @Primary @Component public class AppTypeDerivator implements TypeDerivator { @@ -34,30 +36,30 @@ public class AppTypeDerivator implements TypeDerivator { } @Override - public boolean similar(IType targetType1, IType targetType2) { + public boolean isSimilar(IType targetType1, IType targetType2) { String finalName1 = TypeVisitor.forEachTypeName(targetType1, eachType -> ""); String finalName2 = TypeVisitor.forEachTypeName(targetType2, eachType -> ""); return finalName1.equals(finalName2); } @Override - public IType findReferenceType(IType targetType, IType referenceType) { - if (targetType == null || referenceType == null) { + public IType findTypeByInherit(IType instanceType, IType targetType) { + if (instanceType == null || targetType == null) { return null; } - if (targetType.isNull()) { - return referenceType; - } - if (targetType.getClassName().equals(referenceType.getClassName())) { - Assert.isTrue(similar(targetType, referenceType), "The two types must be structurally similar!"); + if (instanceType.isNull()) { return targetType; } - IType superType = findReferenceType(linker.getSuperType(targetType.toBox()), referenceType); + if (instanceType.getClassName().equals(targetType.getClassName())) { + Assert.isTrue(isSimilar(instanceType, targetType), "The two types must be structurally similar!"); + return instanceType; + } + IType superType = findTypeByInherit(linker.getSuperType(instanceType.toBox()), targetType); if (superType != null) { return superType; } - for (IType interfaceType : linker.getInterfaceTypes(targetType)) { - interfaceType = findReferenceType(interfaceType, referenceType); + for (IType interfaceType : linker.getInterfaceTypes(instanceType)) { + interfaceType = findTypeByInherit(interfaceType, targetType); if (interfaceType != null) { return interfaceType; } @@ -97,6 +99,19 @@ public class AppTypeDerivator implements TypeDerivator { return null; } + @Override + public Integer getMatchingDegree(List parameterTypes, List methodParameterTypes) { + Integer finalDegree = 0; + for (int index = 0; index < parameterTypes.size(); index++) { + Integer degree = getAbstractDegree(methodParameterTypes.get(index), parameterTypes.get(index)); + finalDegree = degree != null ? finalDegree + degree : null; + if (finalDegree == null) { + return null; + } + } + return finalDegree; + } + @Override public boolean isMoreAbstract(IType abstractType, IType targetType) { return getAbstractDegree(abstractType, targetType) != null; diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java index 27664e03..99784822 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java @@ -36,25 +36,16 @@ public class AppMethodMatcher { } return new MatchResult(method, methodParameterTypes); } - - public Integer getMethodScore(List parameterTypes, List methodParameterTypes) { - Integer finalScore = 0; - for (int index = 0; index < parameterTypes.size(); index++) { - Integer scope = derivator.getAbstractDegree(methodParameterTypes.get(index), parameterTypes.get(index)); - finalScore = scope != null ? finalScore + scope : null; - if (finalScore == null) { - return null; - } - } - return finalScore; - } - + public MatchResult findMethod(IType type, List methods, List parameterTypes) { Map matchResultMap = new HashMap<>(); IMethod method = ListUtils.findOneByScore(methods, eachMethod -> { MatchResult matchResult = getParameterTypes(type, eachMethod, parameterTypes); + if (matchResult == null) { + return null; + } matchResultMap.put(eachMethod, matchResult); - return getMethodScore(parameterTypes, matchResult.parameterTypes); + return derivator.getMatchingDegree(parameterTypes, matchResult.parameterTypes); }); return matchResultMap.get(method); } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java index 194db4fd..3fda87b6 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/ExtTypeDerivator.java @@ -1,6 +1,5 @@ package com.gitee.spirit.output.java; -import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; @@ -31,12 +30,9 @@ public class ExtTypeDerivator extends AppTypeDerivator { }); } - public IType populateQualifying(IType type, IType parameterType, IType targetType, Map qualifyingTypes) { - // 先使用类型填充 + public IType populateParameter(IType type, IType parameterType, IType targetType, Map qualifyingTypes) { targetType = populate(type, targetType); - // 然后使用参数类型填充 targetType = populateQualifying(parameterType, targetType, qualifyingTypes); - // 返回类型 return targetType; } @@ -62,15 +58,12 @@ public class ExtTypeDerivator extends AppTypeDerivator { } public IType populateReturnType(IType type, Map qualifyingTypes, IType targetType) { - // 先使用类型填充 targetType = populate(type, targetType); - // 再用限定类型填充 - targetType = populateReturnType(qualifyingTypes, targetType); - // 返回类型 + targetType = populateByQualifying(qualifyingTypes, targetType); return targetType; } - public IType populateReturnType(Map qualifyingTypes, IType targetType) { + public IType populateByQualifying(Map qualifyingTypes, IType targetType) { return TypeVisitor.forEachType(targetType, eachType -> { if (eachType.isTypeVariable()) { return qualifyingTypes.get(targetType.getGenericName()); diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java index c068786a..474365d7 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java @@ -50,14 +50,14 @@ public class ExtMethodMatcher { nativeParameterType = nativeParameterType.toTarget(); } //从继承关系中,找出适当的类型 - parameterType = derivator.findReferenceType(parameterType, nativeParameterType); + parameterType = derivator.findTypeByInherit(parameterType, nativeParameterType); //没有找到对应的,则直接返回 if (parameterType == null) { return null; } //如果因为限定冲突,则直接返回null try { - nativeParameterType = derivator.populateQualifying(type, parameterType, nativeParameterType, qualifyingTypes); + nativeParameterType = derivator.populateParameter(type, parameterType, nativeParameterType, qualifyingTypes); } catch (IllegalArgumentException e) { return null; } @@ -67,27 +67,15 @@ public class ExtMethodMatcher { return new MatchResult(method, nativeParameterTypes, qualifyingTypes); } - public Integer getMethodScore(List parameterTypes, List methodParameterTypes) { - Integer finalScore = 0; - for (int index = 0; index < parameterTypes.size(); index++) { - Integer scope = derivator.getAbstractDegree(methodParameterTypes.get(index), parameterTypes.get(index)); - finalScore = scope != null ? finalScore + scope : null; - if (finalScore == null) { - return null; - } - } - return finalScore; - } - public MatchResult findMethod(IType type, List methods, List parameterTypes) { Map matchResultMap = new HashMap<>(); Method method = ListUtils.findOneByScore(methods, eachMethod -> { MatchResult matchResult = getParameterTypes(type, eachMethod, parameterTypes); - if (matchResult != null) { - matchResultMap.put(eachMethod, matchResult); - return getMethodScore(parameterTypes, matchResult.parameterTypes); + if (matchResult == null) { + return null; } - return null; + matchResultMap.put(eachMethod, matchResult); + return derivator.getMatchingDegree(parameterTypes, matchResult.parameterTypes); }); return matchResultMap.get(method); } -- Gitee From 1680390b6d6ecef03dc6d00e0005a3cfcfe06e24 Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Thu, 15 Jul 2021 23:23:18 +0800 Subject: [PATCH 78/83] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E4=BC=98=E5=8C=96=E5=8C=B9=E9=85=8D=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/spirit/core/api/MethodMatcher.java | 15 +++++++++++++++ .../core/compile/linker/AppMethodMatcher.java | 8 ++++++-- .../output/java/linker/ExtMethodMatcher.java | 6 +++++- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/MethodMatcher.java diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/MethodMatcher.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/MethodMatcher.java new file mode 100644 index 00000000..2b3703f8 --- /dev/null +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/MethodMatcher.java @@ -0,0 +1,15 @@ +package com.gitee.spirit.core.api; + +import com.gitee.spirit.core.clazz.entity.IType; + +import java.util.List; + +public interface MethodMatcher { + + boolean checkParameterCount(M method, List parameterTypes); + + R getParameterTypes(IType type, M method, List parameterTypes); + + R findMethod(IType type, List methods, List parameterTypes); + +} diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java index 99784822..dae226be 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/linker/AppMethodMatcher.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.api.MethodMatcher; import com.gitee.spirit.core.compile.entity.MatchResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -16,15 +17,17 @@ import com.gitee.spirit.core.clazz.entity.IParameter; import com.gitee.spirit.core.clazz.entity.IType; @Component -public class AppMethodMatcher { +public class AppMethodMatcher implements MethodMatcher { @Autowired public TypeDerivator derivator; + @Override public boolean checkParameterCount(IMethod method, List parameterTypes) { return method.parameters.size() == parameterTypes.size(); } + @Override public MatchResult getParameterTypes(IType type, IMethod method, List parameterTypes) { if (!checkParameterCount(method, parameterTypes)) { return null; @@ -36,7 +39,8 @@ public class AppMethodMatcher { } return new MatchResult(method, methodParameterTypes); } - + + @Override public MatchResult findMethod(IType type, List methods, List parameterTypes) { Map matchResultMap = new HashMap<>(); IMethod method = ListUtils.findOneByScore(methods, eachMethod -> { diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java index 474365d7..513be528 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java @@ -5,6 +5,7 @@ import java.lang.reflect.Parameter; import java.util.*; import com.gitee.spirit.common.utils.ListUtils; +import com.gitee.spirit.core.api.MethodMatcher; import com.gitee.spirit.output.java.entity.MatchResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -15,13 +16,14 @@ import com.gitee.spirit.output.java.ExtTypeFactory; import com.gitee.spirit.output.java.utils.ReflectUtils; @Component -public class ExtMethodMatcher { +public class ExtMethodMatcher implements MethodMatcher { @Autowired public ExtTypeFactory factory; @Autowired public ExtTypeDerivator derivator; + @Override public boolean checkParameterCount(Method method, List parameterTypes) { if (!ReflectUtils.isIndefinite(method) && parameterTypes.size() == method.getParameterCount()) {// 不是不定项,那么参数个数相等 return true; @@ -31,6 +33,7 @@ public class ExtMethodMatcher { return false; } + @Override public MatchResult getParameterTypes(IType type, Method method, List parameterTypes) { if (!checkParameterCount(method, parameterTypes)) { return null; @@ -67,6 +70,7 @@ public class ExtMethodMatcher { return new MatchResult(method, nativeParameterTypes, qualifyingTypes); } + @Override public MatchResult findMethod(IType type, List methods, List parameterTypes) { Map matchResultMap = new HashMap<>(); Method method = ListUtils.findOneByScore(methods, eachMethod -> { -- Gitee From d4a412f21bfacb1d0a1f49043423e3e7f64af63f Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Thu, 15 Jul 2021 23:31:09 +0800 Subject: [PATCH 79/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/spirit/core/api/TypeDerivator.java | 2 +- .../spirit/core/compile/derivator/AppTypeDerivator.java | 6 +++--- .../gitee/spirit/output/java/linker/ExtMethodMatcher.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java index 9c277844..18a56076 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/api/TypeDerivator.java @@ -10,7 +10,7 @@ public interface TypeDerivator { boolean isSimilar(IType targetType1, IType targetType2); - IType findTypeByInherit(IType instanceType, IType targetType); + IType upcastTo(IType instanceType, IType targetType); Integer getAbstractDegree(IType abstractType, IType targetType); diff --git a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java index 77258884..a7c04f3c 100644 --- a/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java +++ b/spirit-core/spirit-core-compile/src/main/java/com/gitee/spirit/core/compile/derivator/AppTypeDerivator.java @@ -43,7 +43,7 @@ public class AppTypeDerivator implements TypeDerivator { } @Override - public IType findTypeByInherit(IType instanceType, IType targetType) { + public IType upcastTo(IType instanceType, IType targetType) { if (instanceType == null || targetType == null) { return null; } @@ -54,12 +54,12 @@ public class AppTypeDerivator implements TypeDerivator { Assert.isTrue(isSimilar(instanceType, targetType), "The two types must be structurally similar!"); return instanceType; } - IType superType = findTypeByInherit(linker.getSuperType(instanceType.toBox()), targetType); + IType superType = upcastTo(linker.getSuperType(instanceType.toBox()), targetType); if (superType != null) { return superType; } for (IType interfaceType : linker.getInterfaceTypes(instanceType)) { - interfaceType = findTypeByInherit(interfaceType, targetType); + interfaceType = upcastTo(interfaceType, targetType); if (interfaceType != null) { return interfaceType; } diff --git a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java index 513be528..e847ce80 100644 --- a/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java +++ b/spirit-output/spirit-output-java/src/main/java/com/gitee/spirit/output/java/linker/ExtMethodMatcher.java @@ -53,7 +53,7 @@ public class ExtMethodMatcher implements MethodMatcher { nativeParameterType = nativeParameterType.toTarget(); } //从继承关系中,找出适当的类型 - parameterType = derivator.findTypeByInherit(parameterType, nativeParameterType); + parameterType = derivator.upcastTo(parameterType, nativeParameterType); //没有找到对应的,则直接返回 if (parameterType == null) { return null; -- Gitee From 9b14ae6ae9b51b2ee82b4747effa7331a742cc7d Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Fri, 16 Jul 2021 13:57:02 +0800 Subject: [PATCH 80/83] =?UTF-8?q?=E6=8F=90=E4=BE=9B=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 293fcc3a..64d1ce07 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ public class Main { 3. 将spirit项目中sublime-plugs目录下的所有文件,拷贝到User文件夹中。 -4. 在项目src/main/resources目录下,创建sources子目录。在sources目录下,创建一个文件夹。例如:com.sum.spirit.example。 +4. 在项目src/main/resources目录下,创建sources子目录。在sources目录下,创建一个文件夹。例如:com.gitee.spirit.example。 5. 在文件夹下,创建Main.sp文件,并在sublime中打开,输入如下内容: @@ -101,5 +101,145 @@ public class Main { 2. 执行Maven命令(mvn spirit:compile)并刷新,在src/main/java目录下,即可看到生成的Java代码。 +## 语法说明 +### 类型声明 + +```go +class Horse { + name = "xiaoma" + age = 18 + func Horse(String name, int age) { + this.name = name + this.age = age + } + func bark() { + print "I am xiaoma!" + } +} +``` + +### 赋值语句 + +Spirit编译器会自动推导类型,所以 + +```go +name = "xiaoma" +``` + +等效于 + +```go +String name = "xiaoma" +``` + +### 方法声明 + +Spirit编译器会自动推导类型,所以 + +```go +func getName() { + return name +} +``` + +等效于 + +```go +String getName() { + return name +} +``` + +### 构造方法 + +一般构造方法(省略了new关键字) + +``` +horse1 = Horse("xiaoma", 18) +``` + +builder模式(只要有默认构造方法,可以初始化任意属性,请配合lombok使用) + +``` +horse2 = Horse(name = "laoma", age = 38) +``` + +### 集合声明 + +```go +list = ["xiaoma", "laoma"] +``` + +```go +map = {"xiaoma":horse1, "laoma":horse2} +``` + +### if判断 + +Spirit重载了字符串的“==”操作符,所以 + +```go +if str == "xiaoma" { + print str +} +``` + +等效于 + +```go +if StringUtils.equals(str, "xiaoma") { + print str +} +``` + +### for循环 + +普通 + +```go +for (i=0; i < list.size(); i++) { + print "The item is {}", list.get(i) +} +``` + +快速 + +```go +for str in list { + print "The item is {}", str +} +``` + +### 异常处理 + +```go +try { + throw Exception("Exception occurred!") +} catch Exception e { + error "Exception occurred!", e +} +``` + +### Json构造 + +Spirit的map声明方式,恰好是标准的Json的格式,所以,你可以这样写: + +```go +jsonMap = { + "name":"xiaoma", + "age":18, + "brother":["dama", "zhongma"] + "father":{"laoma":horse2} +} +print JSON.toJSONString(jsonMap) +``` + +## 未来 + +### 智能builder模式 + +```go +list = mapper.selectOneByExample(${name = "xiaoma", age >= 18}) +``` -- Gitee From 3b3f424c33160b4590b5eb8c36918ac500558b4e Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Fri, 16 Jul 2021 14:03:51 +0800 Subject: [PATCH 81/83] =?UTF-8?q?=E6=8F=90=E4=BE=9B=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64d1ce07..541da9d1 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ horse1 = Horse("xiaoma", 18) builder模式(只要有默认构造方法,可以初始化任意属性,请配合lombok使用) ``` -horse2 = Horse(name = "laoma", age = 38) +horse2 = Horse{name = "laoma", age = 38} ``` ### 集合声明 -- Gitee From 41727a071f2f962c6fb358dfddf7533a085e9c94 Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Fri, 16 Jul 2021 14:46:20 +0800 Subject: [PATCH 82/83] =?UTF-8?q?=E6=8F=90=E4=BE=9B=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 541da9d1..32bf378d 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,9 @@ print JSON.toJSONString(jsonMap) ### 智能builder模式 +能够根据上下文,分析出类型,并解析“{}”内的表达式,智能构造实例。 + ```go -list = mapper.selectOneByExample(${name = "xiaoma", age >= 18}) +list = mapper.selectByExample(${name = "xiaoma", age >= 18}) ``` -- Gitee From 7a30e8bf64993590ad8005ed59381d5794a75afc Mon Sep 17 00:00:00 2001 From: "tao.chen1" Date: Fri, 16 Jul 2021 15:07:42 +0800 Subject: [PATCH 83/83] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 32bf378d..4d18c88d 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,7 @@ jsonMap = { print JSON.toJSONString(jsonMap) ``` -## 未来 +## 即将到来 ### 智能builder模式 @@ -245,3 +245,15 @@ print JSON.toJSONString(jsonMap) list = mapper.selectByExample(${name = "xiaoma", age >= 18}) ``` +## 未来 + +1. 支持Lambda表达式 +2. 提供更多sublime插件,增强代码提示。 +3. 考虑支持转译成其他语言(Java以外) + +## 加入我(们) + +如果你对编程,也充满了热忱,想要参与进来,请发送邮件到以下邮箱。 + +邮箱:609580885@qq.com + -- Gitee