├── .classpath ├── .project ├── .settings ├── org.eclipse.core.resources.prefs └── org.eclipse.jdt.core.prefs ├── LibClass └── org │ └── antlr │ └── runtime │ ├── ANTLRFileStream.class │ ├── ANTLRInputStream.class │ ├── ANTLRReaderStream.class │ ├── ANTLRStringStream.class │ ├── BaseRecognizer.class │ ├── BitSet.class │ ├── BufferedTokenStream.class │ ├── CharStream.class │ ├── CharStreamState.class │ ├── ClassicToken.class │ ├── CommonToken.class │ ├── CommonTokenStream.class │ ├── DFA.class │ ├── EarlyExitException.class │ ├── FailedPredicateException.class │ ├── IntStream.class │ ├── LegacyCommonTokenStream.class │ ├── Lexer.class │ ├── MismatchedNotSetException.class │ ├── MismatchedRangeException.class │ ├── MismatchedSetException.class │ ├── MismatchedTokenException.class │ ├── MismatchedTreeNodeException.class │ ├── MissingTokenException.class │ ├── NoViableAltException.class │ ├── Parser.class │ ├── ParserRuleReturnScope.class │ ├── RecognitionException.class │ ├── RecognizerSharedState.class │ ├── RuleReturnScope.class │ ├── SerializedGrammar$Block.class │ ├── SerializedGrammar$Rule.class │ ├── SerializedGrammar$RuleRef.class │ ├── SerializedGrammar$TokenRef.class │ ├── SerializedGrammar.class │ ├── Token.class │ ├── TokenRewriteStream$DeleteOp.class │ ├── TokenRewriteStream$InsertBeforeOp.class │ ├── TokenRewriteStream$ReplaceOp.class │ ├── TokenRewriteStream$RewriteOperation.class │ ├── TokenRewriteStream.class │ ├── TokenSource.class │ ├── TokenStream.class │ ├── UnbufferedTokenStream.class │ ├── UnwantedTokenException.class │ ├── misc │ ├── DoubleKeyMap.class │ ├── FastQueue.class │ ├── IntArray.class │ ├── LookaheadStream.class │ └── Stats.class │ └── tree │ ├── BaseTree.class │ ├── BaseTreeAdaptor.class │ ├── BufferedTreeNodeStream$StreamIterator.class │ ├── BufferedTreeNodeStream.class │ ├── CommonErrorNode.class │ ├── CommonTree.class │ ├── CommonTreeAdaptor.class │ ├── CommonTreeNodeStream.class │ ├── DOTTreeGenerator.class │ ├── ParseTree.class │ ├── RewriteCardinalityException.class │ ├── RewriteEarlyExitException.class │ ├── RewriteEmptyStreamException.class │ ├── RewriteRuleElementStream.class │ ├── RewriteRuleNodeStream.class │ ├── RewriteRuleSubtreeStream.class │ ├── RewriteRuleTokenStream.class │ ├── Tree.class │ ├── TreeAdaptor.class │ ├── TreeFilter$1.class │ ├── TreeFilter$2.class │ ├── TreeFilter$3.class │ ├── TreeFilter$fptr.class │ ├── TreeFilter.class │ ├── TreeIterator.class │ ├── TreeNodeStream.class │ ├── TreeParser.class │ ├── TreePatternLexer.class │ ├── TreePatternParser.class │ ├── TreeRewriter$1.class │ ├── TreeRewriter$2.class │ ├── TreeRewriter$3.class │ ├── TreeRewriter$fptr.class │ ├── TreeRewriter.class │ ├── TreeRuleReturnScope.class │ ├── TreeVisitor.class │ ├── TreeVisitorAction.class │ ├── TreeWizard$1.class │ ├── TreeWizard$2.class │ ├── TreeWizard$3.class │ ├── TreeWizard$ContextVisitor.class │ ├── TreeWizard$TreePattern.class │ ├── TreeWizard$TreePatternTreeAdaptor.class │ ├── TreeWizard$Visitor.class │ ├── TreeWizard$WildcardTreePattern.class │ └── TreeWizard.class ├── README.md ├── build.xml ├── docs ├── Fel表达式引擎.doc └── updateLog.txt ├── lib ├── antlr-3.4.jar ├── antlr.bat ├── antlrworks-1.4.3.jar ├── asm-3.3.1.jar ├── commons-lang-2.4.jar └── testng-6.0.1.jar ├── src └── com │ └── greenpineyu │ └── fel │ ├── Expression.java │ ├── Fel.java │ ├── FelEngine.java │ ├── FelEngineImpl.java │ ├── common │ ├── ArrayUtils.java │ ├── Callable.java │ ├── Null.java │ ├── NumberUtil.java │ ├── ObjectUtils.java │ ├── ReflectUtil.java │ └── StringUtils.java │ ├── compile │ ├── AbstCompiler.java │ ├── CompileService.java │ ├── ConstExp.java │ ├── ConstExpSrc.java │ ├── FelCompiler.java │ ├── FelCompiler15.java │ ├── FelCompiler16.java │ ├── FelCompilerClassloader.java │ ├── FelJavaFileObject.java │ ├── FelMethod.java │ ├── FileClassLoader.java │ ├── InterpreterSourceBuilder.java │ ├── JavaSource.java │ ├── SourceBuilder.java │ ├── SourceGenerator.java │ ├── SourceGeneratorImpl.java │ ├── VarBuffer.java │ └── java.template │ ├── context │ ├── AbstractContext.java │ ├── ArrayCtx.java │ ├── ArrayCtxImpl.java │ ├── ContextChain.java │ ├── EmptyContext.java │ ├── FelContext.java │ ├── MapContext.java │ └── Var.java │ ├── exception │ ├── CompileException.java │ ├── EvalException.java │ └── ParseException.java │ ├── function │ ├── CommonFunction.java │ ├── Dollar.java │ ├── ErrorValue.java │ ├── FunMgr.java │ ├── Function.java │ ├── JavaMethod.java │ ├── StableFunction.java │ ├── TolerantFunction.java │ └── operator │ │ ├── Add.java │ │ ├── And.java │ │ ├── CollectionGet.java │ │ ├── Cond.java │ │ ├── Div.java │ │ ├── Dot.java │ │ ├── Equal.java │ │ ├── GreaterThan.java │ │ ├── GreaterThenEqual.java │ │ ├── LessThen.java │ │ ├── LessThenEqual.java │ │ ├── Mod.java │ │ ├── Mul.java │ │ ├── NotEqual.java │ │ ├── NotOper.java │ │ ├── Or.java │ │ └── Sub.java │ ├── interpreter │ ├── ConstInterpreter.java │ ├── Interpreter.java │ └── ProxyInterpreter.java │ ├── optimizer │ ├── ConstExpOpti.java │ ├── ConstOpti.java │ ├── Interpreters.java │ ├── Optimizer.java │ └── VarVisitOpti.java │ ├── parser │ ├── AbstFelNode.java │ ├── AbstFelParser.java │ ├── AntlrParser.java │ ├── ConstNode.java │ ├── FelLexer.java │ ├── FelNode.java │ ├── FelParser.java │ ├── FunNode.java │ ├── NodeAdaptor.java │ ├── Parser.java │ ├── Stable.java │ └── VarAstNode.java │ └── security │ ├── ReflectMgr.java │ └── ReflectMgrImpl.java └── test └── com └── greenpineyu └── fel ├── CollectionGetTest.java ├── FelEngineImplTest.java ├── Foo.java ├── JavaMethodTest.java ├── PerformanceTest.java ├── examples └── Example.java └── optimizer └── VarVisitOptiTest.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Fel 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Wed Feb 23 10:52:23 CST 2011 2 | eclipse.preferences.version=1 3 | encoding/=UTF-8 4 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | #Thu Mar 10 15:38:49 CST 2011 2 | eclipse.preferences.version=1 3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.5 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.source=1.5 13 | -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/ANTLRFileStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/ANTLRFileStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/ANTLRInputStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/ANTLRInputStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/ANTLRReaderStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/ANTLRReaderStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/ANTLRStringStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/ANTLRStringStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/BaseRecognizer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/BaseRecognizer.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/BitSet.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/BitSet.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/BufferedTokenStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/BufferedTokenStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/CharStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/CharStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/CharStreamState.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/CharStreamState.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/ClassicToken.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/ClassicToken.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/CommonToken.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/CommonToken.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/CommonTokenStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/CommonTokenStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/DFA.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/DFA.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/EarlyExitException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/EarlyExitException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/FailedPredicateException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/FailedPredicateException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/IntStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/IntStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/LegacyCommonTokenStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/LegacyCommonTokenStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/Lexer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/Lexer.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/MismatchedNotSetException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/MismatchedNotSetException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/MismatchedRangeException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/MismatchedRangeException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/MismatchedSetException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/MismatchedSetException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/MismatchedTokenException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/MismatchedTokenException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/MismatchedTreeNodeException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/MismatchedTreeNodeException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/MissingTokenException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/MissingTokenException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/NoViableAltException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/NoViableAltException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/Parser.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/Parser.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/ParserRuleReturnScope.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/ParserRuleReturnScope.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/RecognitionException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/RecognitionException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/RecognizerSharedState.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/RecognizerSharedState.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/RuleReturnScope.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/RuleReturnScope.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/SerializedGrammar$Block.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/SerializedGrammar$Block.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/SerializedGrammar$Rule.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/SerializedGrammar$Rule.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/SerializedGrammar$RuleRef.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/SerializedGrammar$RuleRef.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/SerializedGrammar$TokenRef.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/SerializedGrammar$TokenRef.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/SerializedGrammar.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/SerializedGrammar.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/Token.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/Token.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/TokenRewriteStream$DeleteOp.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/TokenRewriteStream$DeleteOp.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/TokenRewriteStream$InsertBeforeOp.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/TokenRewriteStream$InsertBeforeOp.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/TokenRewriteStream$ReplaceOp.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/TokenRewriteStream$ReplaceOp.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/TokenRewriteStream$RewriteOperation.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/TokenRewriteStream$RewriteOperation.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/TokenRewriteStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/TokenRewriteStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/TokenSource.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/TokenSource.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/TokenStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/TokenStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/UnbufferedTokenStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/UnbufferedTokenStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/UnwantedTokenException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/UnwantedTokenException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/misc/DoubleKeyMap.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/misc/DoubleKeyMap.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/misc/FastQueue.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/misc/FastQueue.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/misc/IntArray.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/misc/IntArray.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/misc/LookaheadStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/misc/LookaheadStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/misc/Stats.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/misc/Stats.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/BaseTree.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/BaseTree.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/BaseTreeAdaptor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/BaseTreeAdaptor.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/BufferedTreeNodeStream$StreamIterator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/BufferedTreeNodeStream$StreamIterator.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/BufferedTreeNodeStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/BufferedTreeNodeStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/CommonErrorNode.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/CommonErrorNode.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/CommonTree.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/CommonTree.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/CommonTreeAdaptor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/CommonTreeAdaptor.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/CommonTreeNodeStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/CommonTreeNodeStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/DOTTreeGenerator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/DOTTreeGenerator.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/ParseTree.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/ParseTree.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/RewriteCardinalityException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/RewriteCardinalityException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/RewriteEarlyExitException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/RewriteEarlyExitException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/RewriteEmptyStreamException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/RewriteEmptyStreamException.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/RewriteRuleElementStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/RewriteRuleElementStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/RewriteRuleNodeStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/RewriteRuleNodeStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/RewriteRuleSubtreeStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/RewriteRuleSubtreeStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/RewriteRuleTokenStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/RewriteRuleTokenStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/Tree.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/Tree.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeAdaptor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeAdaptor.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeFilter$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeFilter$1.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeFilter$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeFilter$2.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeFilter$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeFilter$3.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeFilter$fptr.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeFilter$fptr.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeFilter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeFilter.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeIterator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeIterator.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeNodeStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeNodeStream.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeParser.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeParser.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreePatternLexer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreePatternLexer.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreePatternParser.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreePatternParser.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeRewriter$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeRewriter$1.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeRewriter$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeRewriter$2.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeRewriter$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeRewriter$3.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeRewriter$fptr.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeRewriter$fptr.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeRewriter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeRewriter.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeRuleReturnScope.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeRuleReturnScope.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeVisitor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeVisitor.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeVisitorAction.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeVisitorAction.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard$1.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard$2.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard$3.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard$ContextVisitor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard$ContextVisitor.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard$TreePattern.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard$TreePattern.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard$TreePatternTreeAdaptor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard$TreePatternTreeAdaptor.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard$Visitor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard$Visitor.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard$WildcardTreePattern.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard$WildcardTreePattern.class -------------------------------------------------------------------------------- /LibClass/org/antlr/runtime/tree/TreeWizard.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/LibClass/org/antlr/runtime/tree/TreeWizard.class -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fast-el 2 | Automatically exported from code.google.com/p/fast-el 3 | Fel是轻量级的高效的表达式计算引擎 4 | Fel在源自于企业项目,设计目标是为了满足不断变化的功能需求和性能需求。 5 | 6 | Fel是开放的,引擎执行中的多个模块都可以扩展或替换。Fel的执行主要是通过函数实现,运算符(+、-等都是Fel函数),所有这些函数都是可以替换的,扩展函数也非常简单。 7 | 8 | Fel有双引擎,同时支持解释执行和编译执行。可以根据性能要求选择执行方式。编译执行就是将表达式编译成字节码(生成java代码和编译模块都是可以扩展和替换的) 9 | 10 | Fel基于Java1.5开发,适用于Java1.5及以上版本。 11 | 12 | 表达式引擎QQ群:75055831,欢迎交流。 13 | 14 | Fel有多快? 15 | 通常情况下,Fel-0.7每秒可以执行千万次表达式(不包含编译时间)。速度是Jexl-2.0的20倍以上。 16 | 17 | 目前还没有发现开源的表达式引擎比Fel快。 18 | 19 | 具体的测试数据请参见http://code.google.com/p/fast-el/wiki/Performance。 20 | 21 | 为何要使用Fel? 22 | Fel语法和API非常简单,语法与Java基本相同,几乎没有学习成本。 23 | 24 | Fel非常快,上面已经做了简单说明。 25 | 26 | Fel整个包只有200多KB。 27 | 28 | Fel可以非常方便的访问数组、集合、Map的元素和对象的属性。 29 | 30 | Fel可以非常方便的调用对象的方法和类方法(如果这些还不够,可以添加自定义函数)。 31 | 32 | Fel支持大数值高精度计算 33 | 34 | Fel有良好的安全管理功能 35 | 36 | 如果Fel不能满足你的要求,扩展和修改Fel很简单。 37 | 38 | Fel不能做什么? 39 | Fel只支持表达式,不支持脚本。 40 | 41 | Fel适用场景: 42 | Fel适合处理海量数据,Fel良好的扩展性可以更好的帮助用户处理数据。 43 | 44 | Fel同样适用于其他需要使用表达式引擎的地方(如果工作流、公式计算、数据有效性校验等等) 45 | 46 | 安装 47 | 1:获取Fel 48 | 项目主页:http://code.google.com/p/fast-el/ 下载地址:http://code.google.com/p/fast-el/downloads/list 49 | 50 | 2:Jdk1.6环境 51 | 使用:将fel.jar加入classpath即可。 构建Fel:下载fel-all.tar.gz,解压后将src作为源码文件夹,并且将lib/antlr-min.jar加入classpath即可。 52 | 53 | 3:Jdk1.5环境: 54 | 与jdk1.6环境下的区别在于,需要添加jdk内置的tools.jar到classpath。 55 | 56 | Fel使用例子: 57 | 1:算术表达式: 58 | FelEngine fel = new FelEngineImpl(); 59 | Object result = fel.eval("5000*12+7500"); 60 | System.out.println(result); 61 | 输出结果:67500 62 | 63 | 2:变量 64 | 使用变量,其代码如下所示: 65 | 66 | FelContext ctx = fel.getContext(); 67 | ctx.set("单价", 5000); 68 | ctx.set("数量", 12); 69 | ctx.set("运费", 7500); 70 | Object result = fel.eval("单价*数量+运费"); 71 | System.out.println(result); 72 | 输出结果:67500 73 | 74 | 3:访问对象属性 75 | 在Fel中,可能非常方便的访问对象属性,示例代码如下所示 76 | 77 | FelEngine fel = new FelEngineImpl(); 78 | FelContext ctx = fel.getContext(); 79 | Foo foo = new Foo(); 80 | ctx.set("foo", foo); 81 | Map m = new HashMap(); 82 | m.put("ElName", "fel"); 83 | ctx.set("m",m); 84 | 85 | //调用foo.getSize()方法。 86 | Object result = fel.eval("foo.size"); 87 | 88 | //调用foo.isSample()方法。 89 | result = fel.eval("foo.sample"); 90 | 91 | //foo没有name、getName、isName方法 92 | //foo.name会调用foo.get("name")方法。 93 | result = fel.eval("foo.name"); 94 | 95 | //m.ElName会调用m.get("ElName"); 96 | result = fel.eval("m.ElName"); 97 | 4:访问数组、集合、Map 98 | FelEngine fel = new FelEngineImpl(); 99 | FelContext ctx = fel.getContext(); 100 | 101 | //数组 102 | int[] intArray = {1,2,3}; 103 | ctx.set("intArray",intArray); 104 | //获取intArray[0] 105 | String exp = "intArray[0]"; 106 | System.out.println(exp+"->"+fel.eval(exp)); 107 | 108 | //List 109 | List list = Arrays.asList(1,2,3); 110 | ctx.set("list",list); 111 | //获取list.get(0) 112 | exp = "list[0]"; 113 | System.out.println(exp+"->"+fel.eval(exp)); 114 | 115 | //集合 116 | Collection coll = Arrays.asList("a","b","c"); 117 | ctx.set("coll",coll); 118 | //获取集合最前面的元素。执行结果为"a" 119 | exp = "coll[0]"; 120 | System.out.println(exp+"->"+fel.eval(exp)); 121 | 122 | //迭代器 123 | Iterator iterator = coll.iterator(); 124 | ctx.set("iterator", iterator); 125 | //获取迭代器最前面的元素。执行结果为"a" 126 | exp = "iterator[0]"; 127 | System.out.println(exp+"->"+fel.eval(exp)); 128 | 129 | //Map 130 | Map m = new HashMap(); 131 | m.put("name", "HashMap"); 132 | ctx.set("map",m); 133 | exp = "map.name"; 134 | System.out.println(exp+"->"+fel.eval(exp)); 135 | 136 | //多维数组 137 | int[][] intArrays= {{11,12},{21,22}}; 138 | ctx.set("intArrays",intArrays); 139 | exp = "intArrays[0][0]"; 140 | System.out.println(exp+"->"+fel.eval(exp)); 141 | 142 | //多维综合体,支持数组、集合的任意组合。 143 | List listArray = new ArrayList(); 144 | listArray.add(new int[]{1,2,3}); 145 | listArray.add(new int[]{4,5,6}); 146 | ctx.set("listArray",listArray); 147 | exp = "listArray[0][0]"; 148 | System.out.println(exp+"->"+fel.eval(exp)); 149 | 5:调用JAVA方法 150 | FelEngine fel = new FelEngineImpl(); 151 | FelContext ctx = fel.getContext(); 152 | ctx.set("out", System.out); 153 | fel.eval("out.println('Hello Everybody'.substring(6))"); 154 | 输出结果:Everybody 155 | 156 | 6:自定义上下文环境 157 | //负责提供气象服务的上下文环境 158 | FelContext ctx = new AbstractConetxt() { 159 | public Object get(Object name) { 160 | if("天气".equals(name)){ 161 | return "晴"; 162 | } 163 | if("温度".equals(name)){ 164 | return 25; 165 | } 166 | return null; 167 | } 168 | }; 169 | FelEngine fel = new FelEngineImpl(ctx); 170 | Object eval = fel.eval("'天气:'+天气+';温度:'+温度"); 171 | System.out.println(eval); 172 | 输出结果:天气:晴;温度:25 173 | 174 | 7:多层上下文环境(命名空间) 175 | FelEngine fel = new FelEngineImpl(); 176 | String costStr = "成本"; 177 | String priceStr="价格"; 178 | FelContext baseCtx = fel.getContext(); 179 | //父级上下文中设置成本和价格 180 | baseCtx.set(costStr, 50); 181 | baseCtx.set(priceStr,100); 182 | 183 | String exp = priceStr+"-"+costStr; 184 | Object baseCost = fel.eval(exp); 185 | System.out.println("期望利润:" + baseCost); 186 | 187 | FelContext ctx = new ContextChain(baseCtx, new MapContext()); 188 | //通货膨胀导致成本增加(子级上下文 中设置成本,会覆盖父级上下文中的成本) 189 | ctx.set(costStr,50+20 ); 190 | Object allCost = fel.eval(exp, ctx); 191 | System.out.println("实际利润:" + allCost); 192 | 输出结果: 193 | 194 | 期望利润:50 195 | 196 | 实际利润:30 197 | 198 | 8:编译执行 199 | FelEngine fel = new FelEngineImpl(); 200 | FelContext ctx = fel.getContext(); 201 | ctx.set("单价", 5000); 202 | ctx.set("数量", 12); 203 | ctx.set("运费", 7500); 204 | Expression exp = fel.compile("单价*数量+运费",ctx); 205 | Object result = exp.eval(ctx); 206 | System.out.println(result); 207 | 执行结果:67500 208 | 209 | 备注:适合处理海量数据,编译执行的速度基本与Java字节码执行速度一样快。 210 | 211 | 9:自定义函数 212 | //定义hello函数 213 | Function fun = new CommonFunction() { 214 | 215 | public String getName() { 216 | return "hello"; 217 | } 218 | 219 | /* 220 | * 调用hello("xxx")时执行的代码 221 | */ 222 | @Override 223 | public Object call(Object[] arguments) { 224 | Object msg = null; 225 | if(arguments!= null && arguments.length>0){ 226 | msg = arguments[0]; 227 | } 228 | return ObjectUtils.toString(msg); 229 | } 230 | 231 | }; 232 | FelEngine e = new FelEngineImpl(); 233 | //添加函数到引擎中。 234 | e.addFun(fun); 235 | String exp = "hello('fel')"; 236 | //解释执行 237 | Object eval = e.eval(exp); 238 | System.out.println("hello "+eval); 239 | //编译执行 240 | Expression compile = e.compile(exp, null); 241 | eval = compile.eval(null); 242 | System.out.println("hello "+eval); 243 | 244 | 执行结果: 245 | 246 | hello fel hello fel 247 | 248 | 10:调用静态方法 249 | 如果你觉得上面的自定义函数也麻烦,Fel提供的$函数可以方便的调用工具类的方法 熟悉jQuery的朋友肯定知道"$"函数的威力。Fel东施效颦,也实现了一个"$"函数,其作用是获取class和创建对象。结合点操作符,可以轻易的调用工具类或对象的方法。 250 | 251 | //调用Math.min(1,2) 252 | FelEngine.instance.eval("$('Math').min(1,2)"); 253 | //调用new Foo().toString(); 254 | FelEngine.instance.eval("$('com.greenpineyu.test.Foo.new').toString()); 255 | 通过"$('class').method"形式的语法,就可以调用任何等三方类包(commons lang等)及自定义工具类的方法,也可以创建对象,调用对象的方法。如果有需要,还可以直接注册Java Method到函数管理器中。 256 | 257 | 11 大数值计算(始于0.9版本) 258 | Fel发布后,有些网友希望提供大数值计算功能,于是,大数值计算功能就有了。例子如下: 259 | 260 | FelEngine fel = FelBuilder.bigNumberEngine(); 261 | String input = "111111111111111111111111111111+22222222222222222222222222222222"; 262 | Object value = fel.eval(input); 263 | Object compileValue = fel.compile(input, fel.getContext()).eval(fel.getContext()); 264 | System.out.println("大数值计算(解释执行):" + value); 265 | System.out.println("大数值计算(编译执行):" + compileValue); 266 | 由上例子可以看出,大数值计算引擎和常规计算引擎在使用方法是相同的。如果表达式数值比较大,要求精度高,可使用大数值计算引擎。不足之处是效率没有常规计算引擎高。 267 | 268 | 安全(始于0.8版本) 269 | 为了防止出现“${'System'}.exit(1)”这样的表达式导致系统崩溃。Fel加入了安全管理器,主要是对方法访问进行控制。安全管理器中通过允许访问的方法列表(白名单)和禁止访问的方法列表(黑名单)来控制方法访问。将"java.lang.System. * "加入到黑名单,表示System类的所有方法都不能访问。将"java.lang.Math. * "加入白名单,表示只能访问Math类中的方法。如果你不喜欢这个安全管理器,可以自己开发一个,非常简单,只需要实现一个方法就可以了。 270 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | clean ${deployDir} folder 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | compile ${srcDir} to ${destClassDir} 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | compile success 35 | 36 | 37 | 38 | 39 | 40 | 41 | jar success 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/Fel表达式引擎.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/docs/Fel表达式引擎.doc -------------------------------------------------------------------------------- /docs/updateLog.txt: -------------------------------------------------------------------------------- 1 | 0.7版本更新: 2 | 1:加入取数组(array[i])和集合值(list[i]、set[i])的功能,并且支持多维数组和多维集合。 3 | 2:加入设置变量类型的功能。 4 | 3:调整FelContext接口,加入getVar和setVar方法。 5 | 3:优化语法分析功能。 6 | 4:对数值型的变量生成的编译代码进行调整。 7 | 8 | 0.7.1版本更新 9 | 1:使用基本数组的Context做为默认的Context,效率大幅提升。 10 | 2:支持8进行和16进制,表达式"0xA"、"0XA"、"012"的执行结果为10。 11 | 3:完善获取变量类型功能,在没有设置变量类型时,返回变量值的类型。 12 | 4:增加函数管理功能及测试用例。用户函数的优先级高于共用函数。 13 | 14 | 0.7.2版本更新 15 | 1:支持注册静态java函数,注册后即可使用。 16 | 2:通过反射调用方法(点操作符),不允许调用没有访问权限的方法。 17 | 3:解决BUG:自定义函数包含大写字母时,执行会出错。 18 | 4:不再支持fun(,,)语法。 19 | 5:不再引用common lang3包。 20 | 6:不再使用ArrayCtxImpl做为默认的Context,以免ArrayCtxImpl被误用。 21 | 7:加入VarVisitOpti(取变量值优化器),可以提高取变量值的效率。 22 | 8:重构代码。 23 | 24 | 25 | -------------------------------------------------------------------------------- /lib/antlr-3.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/lib/antlr-3.4.jar -------------------------------------------------------------------------------- /lib/antlr.bat: -------------------------------------------------------------------------------- 1 | java -classpath antlr-3.4.jar -jar antlrworks-1.4.3.jar -------------------------------------------------------------------------------- /lib/antlrworks-1.4.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/lib/antlrworks-1.4.3.jar -------------------------------------------------------------------------------- /lib/asm-3.3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/lib/asm-3.3.1.jar -------------------------------------------------------------------------------- /lib/commons-lang-2.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/lib/commons-lang-2.4.jar -------------------------------------------------------------------------------- /lib/testng-6.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcxy/fast-el/894414ed2502ce333dcfcb541443de00bb42e927/lib/testng-6.0.1.jar -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/Expression.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel; 2 | 3 | import com.greenpineyu.fel.context.FelContext; 4 | 5 | public interface Expression { 6 | /** 7 | * 求表达式的值 8 | * @param arguments 9 | * @return 10 | */ 11 | Object eval(FelContext context); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/Fel.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel; 2 | 3 | import java.util.Map; 4 | 5 | import com.greenpineyu.fel.context.ArrayCtxImpl; 6 | import com.greenpineyu.fel.context.FelContext; 7 | import com.greenpineyu.fel.context.MapContext; 8 | import com.greenpineyu.fel.context.Var; 9 | 10 | public class Fel { 11 | static FelEngineImpl engine = new FelEngineImpl(); 12 | 13 | public static Object eval(String exp, Var... vars) { 14 | return engine.eval(exp, vars); 15 | } 16 | 17 | public static Object eval(String exp, Map vars) { 18 | FelContext ctx = new MapContext(vars); 19 | return engine.eval(exp, ctx); 20 | } 21 | 22 | public static Expression compile(String exp, Var... vars) { 23 | return engine.compile(exp, vars); 24 | } 25 | 26 | public static Expression compile(String exp, Map vars) { 27 | return engine.compile(exp, new MapContext(vars)); 28 | } 29 | 30 | public static FelEngine newEngine() { 31 | return new FelEngineImpl(); 32 | } 33 | 34 | public static FelContext newContext(String name) { 35 | if ("Array".equalsIgnoreCase(name)) { 36 | return new ArrayCtxImpl(); 37 | } 38 | return new MapContext(); 39 | } 40 | 41 | public static void main(String[] args) { 42 | Object eval = eval("0.1+0.19"); 43 | System.out.println(eval); 44 | System.out.println(0.1 + 0.19); 45 | } 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/FelEngine.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel; 2 | 3 | import com.greenpineyu.fel.compile.CompileService; 4 | import com.greenpineyu.fel.context.FelContext; 5 | import com.greenpineyu.fel.function.FunMgr; 6 | import com.greenpineyu.fel.function.Function; 7 | import com.greenpineyu.fel.optimizer.Optimizer; 8 | import com.greenpineyu.fel.parser.FelNode; 9 | import com.greenpineyu.fel.parser.Parser; 10 | 11 | /** 12 | * 表达式引擎 13 | * 14 | * @author yqs 15 | */ 16 | public interface FelEngine { 17 | 18 | /** 19 | * 默认实例 20 | */ 21 | FelEngine instance = new FelEngineImpl(); 22 | 23 | /** 24 | * 执行表达式,获取结果 25 | * 26 | * @param exp 27 | * @return 28 | */ 29 | Object eval(String exp); 30 | 31 | /** 32 | * 使用指定的引擎上下文执行表达式,获取结果 33 | * 34 | * @param exp 35 | * @param ctx 引擎上下文 36 | * @return 37 | */ 38 | Object eval(String exp, FelContext ctx); 39 | 40 | /** 41 | * 解析表达式为节点 42 | * 43 | * @param exp 44 | * @return 45 | */ 46 | FelNode parse(String exp); 47 | 48 | /** 49 | * 编译表达式 50 | * 51 | * @param exp 52 | * @param ctx 53 | * @param opts 编译优化选项 54 | * @return 55 | */ 56 | Expression compile(String exp, FelContext ctx, Optimizer... opts); 57 | 58 | /** 59 | * @return 引擎执行环境 60 | */ 61 | FelContext getContext(); 62 | 63 | /** 64 | * 添加函数到用户函数库中(执行表达式时,优先从用户函数库中获取函数) 65 | * 66 | * @param fun 67 | * @return 68 | */ 69 | void addFun(Function fun); 70 | 71 | /** 72 | * 获取编译器 73 | * @return 74 | */ 75 | CompileService getCompiler() ; 76 | 77 | 78 | /** 79 | * 设置编译器 80 | * @param compiler 81 | */ 82 | void setCompiler(CompileService compiler); 83 | 84 | 85 | /** 86 | * 获取解析器 87 | * @return 88 | */ 89 | Parser getParser(); 90 | 91 | 92 | /** 93 | * 设置解析器 94 | * @param parser 95 | */ 96 | void setParser(Parser parser); 97 | 98 | 99 | /** 100 | * 获取函数管理器 101 | * @return 102 | */ 103 | FunMgr getFunMgr(); 104 | 105 | 106 | /** 107 | * 设置函数管理器 108 | * @param funMgr 109 | */ 110 | void setFunMgr(FunMgr funMgr); 111 | 112 | 113 | /** 114 | * 设置Context 115 | * @param context 116 | */ 117 | void setContext(FelContext context); 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/FelEngineImpl.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel; 2 | 3 | import com.greenpineyu.fel.compile.CompileService; 4 | import com.greenpineyu.fel.context.FelContext; 5 | import com.greenpineyu.fel.context.MapContext; 6 | import com.greenpineyu.fel.context.Var; 7 | import com.greenpineyu.fel.function.FunMgr; 8 | import com.greenpineyu.fel.function.Function; 9 | import com.greenpineyu.fel.optimizer.Optimizer; 10 | import com.greenpineyu.fel.optimizer.VarVisitOpti; 11 | import com.greenpineyu.fel.parser.AntlrParser; 12 | import com.greenpineyu.fel.parser.FelNode; 13 | import com.greenpineyu.fel.parser.Parser; 14 | 15 | /** 16 | * 执行引擎 17 | * 18 | * @author yqs 19 | * 20 | */ 21 | public class FelEngineImpl implements FelEngine { 22 | 23 | private FelContext context; 24 | 25 | private CompileService compiler; 26 | 27 | private Parser parser; 28 | 29 | private FunMgr funMgr; 30 | 31 | 32 | 33 | public FelEngineImpl(FelContext context) { 34 | this.context = context; 35 | compiler = new CompileService(); 36 | parser = new AntlrParser(this); 37 | this.funMgr=new FunMgr(); 38 | 39 | } 40 | 41 | 42 | public FelEngineImpl() { 43 | // this(new ArrayCtxImpl()); 44 | this(new MapContext()); 45 | } 46 | 47 | @Override 48 | public FelNode parse(String exp) { 49 | return parser.parse(exp); 50 | } 51 | 52 | @Override 53 | public Object eval(String exp) { 54 | return this.eval(exp, this.context); 55 | } 56 | 57 | public Object eval(String exp, Var... vars) { 58 | FelNode node = parse(exp); 59 | Optimizer opt = new VarVisitOpti(vars); 60 | node = opt.call(context, node); 61 | return node.eval(context); 62 | } 63 | 64 | @Override 65 | public Object eval(String exp, FelContext ctx) { 66 | return parse(exp).eval(ctx); 67 | } 68 | 69 | public Expression compile(String exp, Var... vars) { 70 | return compile(exp, null, new VarVisitOpti(vars)); 71 | } 72 | 73 | @Override 74 | public Expression compile(String exp, FelContext ctx, Optimizer... opts) { 75 | if (ctx == null) { 76 | ctx = this.context; 77 | } 78 | FelNode node = parse(exp); 79 | if (opts != null) { 80 | for (Optimizer opt : opts) { 81 | if (opt != null) { 82 | node = opt.call(ctx, node); 83 | } 84 | } 85 | } 86 | return compiler.compile(ctx, node, exp); 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return "FelEngine"; 92 | } 93 | 94 | @Override 95 | public void addFun(Function fun) { 96 | this.funMgr.add(fun); 97 | } 98 | 99 | @Override 100 | public FelContext getContext() { 101 | return this.context; 102 | } 103 | 104 | @Override 105 | public CompileService getCompiler() { 106 | return compiler; 107 | } 108 | 109 | 110 | @Override 111 | public void setCompiler(CompileService compiler) { 112 | this.compiler = compiler; 113 | } 114 | 115 | 116 | @Override 117 | public Parser getParser() { 118 | return parser; 119 | } 120 | 121 | 122 | @Override 123 | public void setParser(Parser parser) { 124 | this.parser = parser; 125 | } 126 | 127 | 128 | @Override 129 | public FunMgr getFunMgr() { 130 | return funMgr; 131 | } 132 | 133 | 134 | @Override 135 | public void setFunMgr(FunMgr funMgr) { 136 | this.funMgr = funMgr; 137 | } 138 | 139 | 140 | @Override 141 | public void setContext(FelContext context) { 142 | this.context = context; 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/common/ArrayUtils.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.common; 2 | 3 | import java.lang.reflect.Array; 4 | 5 | 6 | public class ArrayUtils { 7 | /** 8 | *

Checks if an array of Objects is empty or {@code null}.

9 | * 10 | * @param array the array to test 11 | * @return {@code true} if the array is empty or {@code null} 12 | * @since 2.1 13 | */ 14 | public static boolean isEmpty(Object[] array) { 15 | return array == null || array.length == 0; 16 | } 17 | 18 | /** 19 | *

Outputs an array as a String, treating {@code null} as an empty array.

20 | * 21 | *

Multi-dimensional arrays are handled correctly, including 22 | * multi-dimensional primitive arrays.

23 | * 24 | *

The format is that of Java source code, for example {a,b}.

25 | * 26 | * @param array the array to get a toString for, may be {@code null} 27 | * @return a String representation of the array, '{}' if null array input 28 | */ 29 | // public static String toString(Object array) { 30 | // 31 | // return toString(array, "{}"); 32 | // } 33 | // 34 | // /** 35 | // *

Outputs an array as a String handling {@code null}s.

36 | // * 37 | // *

Multi-dimensional arrays are handled correctly, including 38 | // * multi-dimensional primitive arrays.

39 | // * 40 | // *

The format is that of Java source code, for example {a,b}.

41 | // * 42 | // * @param array the array to get a toString for, may be {@code null} 43 | // * @param stringIfNull the String to return if the array is {@code null} 44 | // * @return a String representation of the array 45 | // */ 46 | // public static String toString(Object array, String stringIfNull) { 47 | // if (array == null) { 48 | // return stringIfNull; 49 | // } 50 | // return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString(); 51 | // } 52 | 53 | /** 54 | *

Produces a new array containing the elements between 55 | * the start and end indices.

56 | * 57 | *

The start index is inclusive, the end index exclusive. 58 | * Null array input produces null output.

59 | * 60 | *

The component type of the subarray is always the same as 61 | * that of the input array. Thus, if the input is an array of type 62 | * {@code Date}, the following usage is envisaged:

63 | * 64 | *
 65 |      * Date[] someDates = (Date[])ArrayUtils.subarray(allDates, 2, 5);
 66 |      * 
67 | * 68 | * @param the component type of the array 69 | * @param array the array 70 | * @param startIndexInclusive the starting index. Undervalue (<0) 71 | * is promoted to 0, overvalue (>array.length) results 72 | * in an empty array. 73 | * @param endIndexExclusive elements up to endIndex-1 are present in the 74 | * returned subarray. Undervalue (< startIndex) produces 75 | * empty array, overvalue (>array.length) is demoted to 76 | * array length. 77 | * @return a new array containing the elements between 78 | * the start and end indices. 79 | * @since 2.1 80 | */ 81 | public static T[] subarray(T[] array, int startIndexInclusive, int endIndexExclusive) { 82 | if (array == null) { 83 | return null; 84 | } 85 | if (startIndexInclusive < 0) { 86 | startIndexInclusive = 0; 87 | } 88 | if (endIndexExclusive > array.length) { 89 | endIndexExclusive = array.length; 90 | } 91 | int newSize = endIndexExclusive - startIndexInclusive; 92 | Class type = array.getClass().getComponentType(); 93 | if (newSize <= 0) { 94 | @SuppressWarnings("unchecked") // OK, because array is of type T 95 | final T[] emptyArray = (T[]) Array.newInstance(type, 0); 96 | return emptyArray; 97 | } 98 | @SuppressWarnings("unchecked") // OK, because array is of type T 99 | T[] subarray = (T[]) Array.newInstance(type, newSize); 100 | System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); 101 | return subarray; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/common/Callable.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.common; 2 | 3 | /** 4 | * 5 | * 可调用接口 6 | * @author yuqingsong 7 | * 8 | * @param 参数返回值 9 | * @param

参数类型 10 | */ 11 | public interface Callable { 12 | 13 | R call(P... arg); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/common/Null.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.common; 2 | 3 | /** 4 | * 用于表示Null值 5 | * @author yuqingsong 6 | * 7 | */ 8 | public class Null { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/common/ObjectUtils.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.common; 2 | 3 | 4 | public class ObjectUtils { 5 | /** 6 | *

Compares two objects for equality, where either one or both 7 | * objects may be {@code null}.

8 | * 9 | *
10 |      * ObjectUtils.equals(null, null)                  = true
11 |      * ObjectUtils.equals(null, "")                    = false
12 |      * ObjectUtils.equals("", null)                    = false
13 |      * ObjectUtils.equals("", "")                      = true
14 |      * ObjectUtils.equals(Boolean.TRUE, null)          = false
15 |      * ObjectUtils.equals(Boolean.TRUE, "true")        = false
16 |      * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE)  = true
17 |      * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
18 |      * 
19 | * 20 | * @param object1 the first object, may be {@code null} 21 | * @param object2 the second object, may be {@code null} 22 | * @return {@code true} if the values of both objects are the same 23 | */ 24 | public static boolean equals(Object object1, Object object2) { 25 | if (object1 == object2) { 26 | return true; 27 | } 28 | if ((object1 == null) || (object2 == null)) { 29 | return false; 30 | } 31 | return object1.equals(object2); 32 | } 33 | 34 | /** 35 | *

Gets the {@code toString} of an {@code Object} returning 36 | * an empty string ("") if {@code null} input.

37 | * 38 | *
39 |      * ObjectUtils.toString(null)         = ""
40 |      * ObjectUtils.toString("")           = ""
41 |      * ObjectUtils.toString("bat")        = "bat"
42 |      * ObjectUtils.toString(Boolean.TRUE) = "true"
43 |      * 
44 | * 45 | * @see StringUtils#defaultString(String) 46 | * @see String#valueOf(Object) 47 | * @param obj the Object to {@code toString}, may be null 48 | * @return the passed in Object's toString, or nullStr if {@code null} input 49 | * @since 2.0 50 | */ 51 | public static String toString(Object obj) { 52 | return obj == null ? "" : obj.toString(); 53 | } 54 | 55 | /** 56 | *

Compares two objects for inequality, where either one or both 57 | * objects may be {@code null}.

58 | * 59 | *
60 |      * ObjectUtils.notEqual(null, null)                  = false
61 |      * ObjectUtils.notEqual(null, "")                    = true
62 |      * ObjectUtils.notEqual("", null)                    = true
63 |      * ObjectUtils.notEqual("", "")                      = false
64 |      * ObjectUtils.notEqual(Boolean.TRUE, null)          = true
65 |      * ObjectUtils.notEqual(Boolean.TRUE, "true")        = true
66 |      * ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE)  = false
67 |      * ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
68 |      * 
69 | * 70 | * @param object1 the first object, may be {@code null} 71 | * @param object2 the second object, may be {@code null} 72 | * @return {@code false} if the values of both objects are the same 73 | */ 74 | public static boolean notEqual(Object object1, Object object2) { 75 | return ObjectUtils.equals(object1, object2) == false; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/common/ReflectUtil.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.common; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class ReflectUtil { 8 | 9 | /** 10 | * key为基本类型及其包装类型,value为包装类型 11 | */ 12 | static final Map,Class> wrapperCls; 13 | /** 14 | * key为基本类型及其包装类型,value为基本类型 15 | */ 16 | static final Map,Class> primitiveCls; 17 | 18 | static final Map,Class> numberClassMap; 19 | static{ 20 | numberClassMap = wrapperNumberCls(); 21 | primitiveCls = new HashMap, Class>(primitiveNumberCls()); 22 | primitiveCls.put(boolean.class, boolean.class); 23 | primitiveCls.put(Boolean.class, boolean.class); 24 | 25 | wrapperCls = new HashMap, Class>(wrapperNumberCls()); 26 | wrapperCls.put(boolean.class, Boolean.class); 27 | wrapperCls.put(Boolean.class, Boolean.class); 28 | } 29 | 30 | private static Map,Class> primitiveNumberCls() { 31 | Map,Class> map = new HashMap, Class>(); 32 | map.put(byte.class, byte.class); 33 | map.put(Byte.class, byte.class); 34 | 35 | map.put(short.class, short.class); 36 | map.put(Short.class, short.class); 37 | 38 | map.put(int.class, int.class); 39 | map.put(Integer.class, int.class); 40 | 41 | map.put(long.class, long.class); 42 | map.put(Long.class, long.class); 43 | 44 | map.put(float.class, float.class); 45 | map.put(Float.class, float.class); 46 | 47 | map.put(double.class, double.class); 48 | map.put(Double.class, double.class); 49 | 50 | map.put(char.class, char.class); 51 | map.put(Character.class, char.class); 52 | return map; 53 | } 54 | 55 | private static Map,Class> wrapperNumberCls() { 56 | Map,Class> map = new HashMap, Class>(); 57 | map.put(byte.class, Byte.class); 58 | map.put(Byte.class, Byte.class); 59 | 60 | map.put(short.class, Short.class); 61 | map.put(Short.class, Short.class); 62 | 63 | map.put(int.class, Integer.class); 64 | map.put(Integer.class, Integer.class); 65 | 66 | map.put(long.class, Long.class); 67 | map.put(Long.class, Long.class); 68 | 69 | map.put(float.class, Float.class); 70 | map.put(Float.class, Float.class); 71 | 72 | map.put(double.class, Double.class); 73 | map.put(Double.class, Double.class); 74 | 75 | map.put(char.class, Character.class); 76 | map.put(Character.class, Character.class); 77 | return map; 78 | } 79 | 80 | /** 81 | * 是基本类型中的数值类型(包含包装类型) 82 | * @return 83 | */ 84 | public static boolean isPrimitiveOrWrapNumber(Class c){ 85 | return numberClassMap.containsKey(c); 86 | } 87 | public static boolean isPrimitiveNumber(Class c){ 88 | if(c == null){ 89 | return false; 90 | } 91 | return c.isPrimitive()&&(c!=boolean.class); 92 | // return numberClassMap.containsKey(c); 93 | } 94 | 95 | public static Class toWrapperClass(Class c){ 96 | return wrapperCls.get(c); 97 | } 98 | public static Class toPrimitiveClass(Class c){ 99 | return primitiveCls.get(c); 100 | } 101 | 102 | /* 103 | public static void main(String[] args) { 104 | System.out.println((1+"2"+3)); 105 | int[] a = new int[]{5,4,3,2,10,100,1}; 106 | sort(a); 107 | System.out.println(Arrays.toString(a)); 108 | }*/ 109 | 110 | public static void sort(int[] array){ 111 | for (int i = 1; i < array.length; i++) { 112 | int j = i-1; 113 | int current = array[i]; 114 | for(;j>-1&¤t cls,String attr,Class[] paramTypes){ 130 | if(attr == null || "".equals(attr)){ 131 | return null; 132 | } 133 | String firstUpper = String.valueOf(attr.charAt(0)).toUpperCase()+attr.substring(1); 134 | Method[] methods = cls.getMethods(); 135 | 136 | Method finalMethod = null; 137 | String[] methodNames = new String[]{attr,"get"+firstUpper,"is"+firstUpper}; 138 | for (String methodName : methodNames) { 139 | finalMethod = match(methodName, paramTypes, methods); 140 | if(finalMethod!=null){ 141 | break; 142 | } 143 | } 144 | return finalMethod; 145 | 146 | /* 147 | String get = "get"; 148 | finalMethod = match(get, paramTypes, methods, finalMethod); 149 | if(finalMethod!=null){ 150 | return finalMethod; 151 | }*/ 152 | } 153 | 154 | public static Method getMethod(Class cls,String methodName,Class[] paramTypes){ 155 | Method[] methods = cls.getMethods(); 156 | return match(methodName,paramTypes,methods); 157 | 158 | } 159 | private static Method match(String methodName, Class[] paramValueTypes, 160 | Method[] methods) { 161 | Method finalMethod = null; 162 | //方法名称和参数长度核匹配的方法,当不能精确匹配时,返回此方法 163 | Method nameParamLengthEqualsMethod = null; 164 | out:for (Method m : methods) { 165 | String name = m.getName(); 166 | if(name.equals(methodName) ){ 167 | Class[] methodParamTypes = m.getParameterTypes(); 168 | if(methodParamTypes!=null&& paramValueTypes != null){ 169 | if(methodParamTypes.length== paramValueTypes.length){ 170 | if(nameParamLengthEqualsMethod == null){ 171 | nameParamLengthEqualsMethod = m; 172 | } 173 | 174 | //比较参数是否匹配 175 | for (int i = 0; i < methodParamTypes.length; i++) { 176 | Class c1 = methodParamTypes[i]; 177 | Class c2 = paramValueTypes[i]; 178 | if(!isTypeMatch(c1, c2)){ 179 | //如果不匹配,找下一个方法 180 | continue out; 181 | } 182 | } 183 | finalMethod = m; 184 | break; 185 | } 186 | }else if(ArrayUtils.isEmpty(methodParamTypes)&&ArrayUtils.isEmpty(paramValueTypes)){ 187 | //如果参数都为null,认为是方法是匹配的 188 | finalMethod = m; 189 | break; 190 | } 191 | } 192 | } 193 | return finalMethod == null?nameParamLengthEqualsMethod:finalMethod; 194 | } 195 | 196 | public static boolean isTypeMatch(Class c1,Class c2){ 197 | if(c1 == c2||c2==Null.class){ 198 | //当c2为Null.class时,表示参数值是null,null值可以与任何类型匹配类型 199 | return true; 200 | } 201 | Class w1 = ReflectUtil.toWrapperClass(c1); 202 | Class w2 = ReflectUtil.toWrapperClass(c2); 203 | if(w1!=null){ 204 | //可能转换成包装类型 205 | if(w1==w2){ 206 | //查看包装类型是否相等 207 | return true; 208 | } 209 | } 210 | //判断c2是不是c1的子类,如果是,返回true 211 | return c1.isAssignableFrom(c2); 212 | } 213 | 214 | static public String getClassName(Class cls){ 215 | if(cls == null){ 216 | return "null"; 217 | } 218 | return cls.getCanonicalName(); 219 | } 220 | 221 | 222 | } 223 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/common/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.common; 2 | 3 | public class StringUtils { 4 | 5 | /** 6 | * Represents a failed index search. 7 | * @since 2.1 8 | */ 9 | public static final int INDEX_NOT_FOUND = -1; 10 | 11 | public static boolean isEmpty(CharSequence cs) { 12 | return cs == null || cs.length() == 0; 13 | } 14 | 15 | /** 16 | *

Checks if a CharSequence is not empty ("") and not null.

17 | * 18 | *
 19 |     * StringUtils.isNotEmpty(null)      = false
 20 |     * StringUtils.isNotEmpty("")        = false
 21 |     * StringUtils.isNotEmpty(" ")       = true
 22 |     * StringUtils.isNotEmpty("bob")     = true
 23 |     * StringUtils.isNotEmpty("  bob  ") = true
 24 |     * 
25 | * 26 | * @param cs the CharSequence to check, may be null 27 | * @return {@code true} if the CharSequence is not empty and not null 28 | * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) 29 | */ 30 | public static boolean isNotEmpty(CharSequence cs) { 31 | return !StringUtils.isEmpty(cs); 32 | } 33 | 34 | 35 | /** 36 | *

Replaces all occurrences of a String within another String.

37 | * 38 | *

A {@code null} reference passed to this method is a no-op.

39 | * 40 | *
 41 |     * StringUtils.replace(null, *, *)        = null
 42 |     * StringUtils.replace("", *, *)          = ""
 43 |     * StringUtils.replace("any", null, *)    = "any"
 44 |     * StringUtils.replace("any", *, null)    = "any"
 45 |     * StringUtils.replace("any", "", *)      = "any"
 46 |     * StringUtils.replace("aba", "a", null)  = "aba"
 47 |     * StringUtils.replace("aba", "a", "")    = "b"
 48 |     * StringUtils.replace("aba", "a", "z")   = "zbz"
 49 |     * 
50 | * 51 | * @see #replace(String text, String searchString, String replacement, int max) 52 | * @param text text to search and replace in, may be null 53 | * @param searchString the String to search for, may be null 54 | * @param replacement the String to replace it with, may be null 55 | * @return the text with any replacements processed, 56 | * {@code null} if null String input 57 | */ 58 | public static String replace(String text, String searchString, String replacement) { 59 | return replace(text, searchString, replacement, -1); 60 | } 61 | 62 | 63 | /** 64 | *

Replaces a String with another String inside a larger String, 65 | * for the first {@code max} values of the search String.

66 | * 67 | *

A {@code null} reference passed to this method is a no-op.

68 | * 69 | *
 70 |     * StringUtils.replace(null, *, *, *)         = null
 71 |     * StringUtils.replace("", *, *, *)           = ""
 72 |     * StringUtils.replace("any", null, *, *)     = "any"
 73 |     * StringUtils.replace("any", *, null, *)     = "any"
 74 |     * StringUtils.replace("any", "", *, *)       = "any"
 75 |     * StringUtils.replace("any", *, *, 0)        = "any"
 76 |     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
 77 |     * StringUtils.replace("abaa", "a", "", -1)   = "b"
 78 |     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
 79 |     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
 80 |     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
 81 |     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
 82 |     * 
83 | * 84 | * @param text text to search and replace in, may be null 85 | * @param searchString the String to search for, may be null 86 | * @param replacement the String to replace it with, may be null 87 | * @param max maximum number of values to replace, or {@code -1} if no maximum 88 | * @return the text with any replacements processed, 89 | * {@code null} if null String input 90 | */ 91 | public static String replace(String text, String searchString, String replacement, int max) { 92 | if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { 93 | return text; 94 | } 95 | int start = 0; 96 | int end = text.indexOf(searchString, start); 97 | if (end == INDEX_NOT_FOUND) { 98 | return text; 99 | } 100 | int replLength = searchString.length(); 101 | int increase = replacement.length() - replLength; 102 | increase = (increase < 0 ? 0 : increase); 103 | increase *= (max < 0 ? 16 : (max > 64 ? 64 : max)); 104 | StringBuilder buf = new StringBuilder(text.length() + increase); 105 | while (end != INDEX_NOT_FOUND) { 106 | buf.append(text.substring(start, end)).append(replacement); 107 | start = end + replLength; 108 | if (--max == 0) { 109 | break; 110 | } 111 | end = text.indexOf(searchString, start); 112 | } 113 | buf.append(text.substring(start)); 114 | return buf.toString(); 115 | } 116 | 117 | 118 | /** 119 | *

Removes all occurrences of a character from within the source string.

120 | * 121 | *

A {@code null} source string will return {@code null}. 122 | * An empty ("") source string will return the empty string.

123 | * 124 | *
125 |     * StringUtils.remove(null, *)       = null
126 |     * StringUtils.remove("", *)         = ""
127 |     * StringUtils.remove("queued", 'u') = "qeed"
128 |     * StringUtils.remove("queued", 'z') = "queued"
129 |     * 
130 | * 131 | * @param str the source String to search, may be null 132 | * @param remove the char to search for and remove, may be null 133 | * @return the substring with the char removed if found, 134 | * {@code null} if null String input 135 | * @since 2.1 136 | */ 137 | public static String remove(String str, char remove) { 138 | if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { 139 | return str; 140 | } 141 | char[] chars = str.toCharArray(); 142 | int pos = 0; 143 | for (int i = 0; i < chars.length; i++) { 144 | if (chars[i] != remove) { 145 | chars[pos++] = chars[i]; 146 | } 147 | } 148 | return new String(chars, 0, pos); 149 | } 150 | 151 | //----------------------------------------------------------------------- 152 | /** 153 | *

Compares two CharSequences, returning {@code true} if they are equal.

154 | * 155 | *

{@code null}s are handled without exceptions. Two {@code null} 156 | * references are considered to be equal. The comparison is case sensitive.

157 | * 158 | *
159 |     * StringUtils.equals(null, null)   = true
160 |     * StringUtils.equals(null, "abc")  = false
161 |     * StringUtils.equals("abc", null)  = false
162 |     * StringUtils.equals("abc", "abc") = true
163 |     * StringUtils.equals("abc", "ABC") = false
164 |     * 
165 | * 166 | * @see java.lang.String#equals(Object) 167 | * @param cs1 the first CharSequence, may be null 168 | * @param cs2 the second CharSequence, may be null 169 | * @return {@code true} if the CharSequences are equal, case sensitive, or 170 | * both {@code null} 171 | * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) 172 | */ 173 | public static boolean equals(CharSequence cs1, CharSequence cs2) { 174 | return cs1 == null ? cs2 == null : cs1.equals(cs2); 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/AbstCompiler.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.io.UnsupportedEncodingException; 6 | import java.net.URL; 7 | import java.net.URLDecoder; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Set; 13 | import java.util.concurrent.ExecutorService; 14 | import java.util.concurrent.LinkedBlockingQueue; 15 | import java.util.concurrent.ThreadPoolExecutor; 16 | import java.util.concurrent.TimeUnit; 17 | 18 | import com.greenpineyu.fel.Expression; 19 | import com.greenpineyu.fel.common.StringUtils; 20 | 21 | public abstract class AbstCompiler implements FelCompiler { 22 | /* 23 | * 用户编译的classpath 24 | */ 25 | public static final String CLASSPATH; 26 | 27 | /** 28 | * class文件夹 29 | */ 30 | static final String CLASS_DIR; 31 | 32 | private static final String BASE_DIR; 33 | static ClassLoader loader; 34 | static { 35 | CLASSPATH = getClassPath(); 36 | String userDir = System.getProperty("user.dir"); 37 | BASE_DIR = userDir + File.separator + "fel" + File.separator; 38 | CLASS_DIR = BASE_DIR + "classes" + File.separator; 39 | loader = new FileClassLoader(AbstCompiler.class.getClassLoader(), 40 | CLASS_DIR); 41 | createClassDir(); 42 | } 43 | 44 | /** 45 | * Class文件所在文件夹,包含包名 46 | */ 47 | static String getClassPackageDir(String pack) { 48 | return CLASS_DIR + packageToPath(pack) + File.separator; 49 | } 50 | 51 | static String getSrcPackageDir(String pack) { 52 | return BASE_DIR + "src" + File.separator + packageToPath(pack) 53 | + File.separator; 54 | } 55 | 56 | private static String getPath(Class cls) { 57 | String path = ""; 58 | try { 59 | URL location = cls.getProtectionDomain().getCodeSource() 60 | .getLocation(); 61 | path = URLDecoder.decode(location.getFile(), "UTF-8"); 62 | } catch (UnsupportedEncodingException e) { 63 | } 64 | return path; 65 | } 66 | 67 | private static String getClassPath() { 68 | /* 69 | * 将三项添加到classpath 1:lib中的所有jar 2:class目录 3:系统属性:"java.class.path" 70 | */ 71 | Class cls = AbstCompiler.class; 72 | String path = getPath(cls); 73 | boolean isJar = path.endsWith(".jar"); 74 | Set cpSet = new HashSet(); 75 | if (isJar) { 76 | File jarFile = new File(path); 77 | File lib = jarFile.getParentFile(); 78 | if (lib != null) { 79 | cpSet.addAll(getLibJars(jarFile.getParent())); 80 | String web_inf = lib.getParent(); 81 | String classDir = web_inf + File.separator + "classes"; 82 | File classDirfile = new File(classDir); 83 | if (classDirfile != null && classDirfile.exists()) { 84 | cpSet.add(classDir); 85 | } 86 | } 87 | } else { 88 | String classFullName = cls.getName().replaceAll("\\.", "/"); 89 | int index = path.lastIndexOf(classFullName + ".class"); 90 | if (index != -1) { 91 | String classDir = path.substring(0, index); 92 | cpSet.add(classDir); 93 | File classDirFile = new File(classDir); 94 | File web_inf = classDirFile.getParentFile(); 95 | String libDir = web_inf + File.separator + "lib"; 96 | cpSet.addAll(getLibJars(libDir)); 97 | } 98 | } 99 | String systemCp = System.getProperty("java.class.path"); 100 | if (systemCp != null) { 101 | String[] cps = systemCp.split(File.pathSeparator); 102 | if (cps != null) { 103 | cpSet.addAll(Arrays.asList(cps)); 104 | } 105 | } 106 | String cpStr = ""; 107 | for (String c : cpSet) { 108 | cpStr += c + File.pathSeparator; 109 | } 110 | return cpStr; 111 | } 112 | 113 | private static Set getLibJars(String libDir) { 114 | Set jarPathSet = new HashSet(); 115 | File dir = new File(libDir); 116 | if (dir != null && dir.isDirectory()) { 117 | File[] files = dir.listFiles(new FilenameFilter() { 118 | public boolean accept(File dir, String name) { 119 | return name.endsWith(".jar"); 120 | } 121 | }); 122 | for (int i = 0; i < files.length; i++) { 123 | File file = files[i]; 124 | String absolutePath = file.getAbsolutePath(); 125 | jarPathSet.add(absolutePath); 126 | } 127 | } 128 | return jarPathSet; 129 | } 130 | 131 | public Expression compile(JavaSource src) { 132 | Class compile; 133 | try { 134 | compile = this.compileToClass(src); 135 | return compile.newInstance(); 136 | } catch (ClassNotFoundException e1) { 137 | e1.printStackTrace(); 138 | } catch (InstantiationException e) { 139 | e.printStackTrace(); 140 | } catch (IllegalAccessException e) { 141 | e.printStackTrace(); 142 | }finally{ 143 | String className = src.getName(); 144 | String pack = src.getPackageName(); 145 | String srcPackageDir = getSrcPackageDir(pack); 146 | clean(srcPackageDir,getClassPackageDir(pack),className); 147 | } 148 | return null; 149 | } 150 | 151 | 152 | abstract Class compileToClass(JavaSource expr) 153 | throws ClassNotFoundException; 154 | 155 | static void createClassDir() { 156 | new File(CLASS_DIR).mkdirs(); 157 | } 158 | 159 | private static ExecutorService exeService = initThreadPool(); 160 | 161 | private static ExecutorService initThreadPool() { 162 | return new ThreadPoolExecutor(0, 10, 5L, TimeUnit.SECONDS, 163 | new LinkedBlockingQueue()); 164 | } 165 | 166 | void clean(final String srcPackageDir, 167 | final String classPackageDir, final String fileName) { 168 | if (exeService.isShutdown()) { 169 | exeService = initThreadPool(); 170 | } 171 | exeService.execute(new Runnable() { 172 | public void run() { 173 | // 优先级设置成最低 174 | Thread.currentThread().setPriority(Thread.MIN_PRIORITY); 175 | delFile(srcPackageDir, classPackageDir, fileName); 176 | } 177 | }); 178 | // exeService.shutdown(); 179 | } 180 | 181 | void delFile(final String srcPackageDir, final String classPackageDir, 182 | final String fileName) { 183 | String src = srcPackageDir + fileName + ".java"; 184 | deleteFile(src); 185 | String cls = classPackageDir + fileName + ".class"; 186 | deleteFile(cls); 187 | } 188 | 189 | void deleteFile(String src) { 190 | File file = new File(src); 191 | // System.out.println("delete file:"+src); 192 | if (file.exists()) { 193 | file.delete(); 194 | } 195 | } 196 | 197 | 198 | List getCompileOption() { 199 | List options = new ArrayList(); 200 | options.add("-encoding"); 201 | options.add("UTF-8"); 202 | options.add("-d"); 203 | options.add(CLASS_DIR); 204 | 205 | if (StringUtils.isNotEmpty(CLASSPATH)) { 206 | options.add("-classpath"); 207 | options.add(CLASSPATH); 208 | } 209 | return options; 210 | } 211 | 212 | /** 213 | * 将包名转换成包路径 214 | * 215 | * @param packageName 216 | * @return 217 | */ 218 | private static String packageToPath(String packageName) { 219 | String sep = File.separator; 220 | // if (sep.equals("\\")) { 221 | // sep = "\\\\"; 222 | // } 223 | return StringUtils.replace(packageName, ".", sep); 224 | // return packageName.replaceAll("\\.", sep); 225 | } 226 | 227 | } 228 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/CompileService.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import com.greenpineyu.fel.Expression; 4 | import com.greenpineyu.fel.context.FelContext; 5 | import com.greenpineyu.fel.parser.FelNode; 6 | 7 | public class CompileService { 8 | 9 | private SourceGenerator srcGen; 10 | private FelCompiler complier; 11 | 12 | public SourceGenerator getSrcGen() { 13 | return srcGen; 14 | } 15 | 16 | public void setSrcGen(SourceGenerator srcGen) { 17 | this.srcGen = srcGen; 18 | } 19 | 20 | public FelCompiler getComplier() { 21 | return complier; 22 | } 23 | 24 | public void setComplier(FelCompiler complier) { 25 | this.complier = complier; 26 | } 27 | 28 | { 29 | srcGen = new SourceGeneratorImpl(); 30 | String name = getCompilerClassName(); 31 | FelCompiler comp = newCompiler(name); 32 | complier = comp; 33 | } 34 | 35 | private FelCompiler newCompiler(String name) { 36 | FelCompiler comp = null; 37 | try { 38 | @SuppressWarnings("unchecked") 39 | Class cls = (Class) Class.forName(name); 40 | comp = cls.newInstance(); 41 | } catch (ClassNotFoundException e) { 42 | e.printStackTrace(); 43 | } catch (InstantiationException e) { 44 | e.printStackTrace(); 45 | } catch (IllegalAccessException e) { 46 | e.printStackTrace(); 47 | } finally { 48 | } 49 | return comp; 50 | } 51 | 52 | private String getCompilerClassName() { 53 | String version = System.getProperty("java.version"); 54 | String compileClassName = FelCompiler.class.getName(); 55 | if (version != null && version.startsWith("1.5")) { 56 | compileClassName += "15"; 57 | } else { 58 | compileClassName += "16"; 59 | } 60 | return compileClassName; 61 | } 62 | 63 | public Expression compile(FelContext ctx, FelNode node, String originalExp) { 64 | try { 65 | JavaSource src = srcGen.getSource(ctx, node); 66 | if (src instanceof ConstExpSrc) { 67 | ConstExpSrc s = (ConstExpSrc) src; 68 | return s.getValue(); 69 | } 70 | src.setSource("// 表达式:" + originalExp + "\n" + src.getSource()); 71 | // System.out.println("****************\n" + src.getSource()); 72 | return complier.compile(src); 73 | } catch (Exception e) { 74 | e.printStackTrace(); 75 | } 76 | return null; 77 | } 78 | 79 | public static void main(String[] args) { 80 | System.getProperties().list(System.out); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/ConstExp.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import com.greenpineyu.fel.Expression; 4 | import com.greenpineyu.fel.context.FelContext; 5 | 6 | public final class ConstExp implements Expression { 7 | public ConstExp(Object o) { 8 | this.value = o; 9 | } 10 | 11 | private final Object value; 12 | 13 | @Override 14 | public final Object eval(FelContext context) { 15 | return value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/ConstExpSrc.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | /** 4 | * @author yuqingsong 5 | * 6 | */ 7 | public class ConstExpSrc extends JavaSource { 8 | 9 | public ConstExpSrc(Object o) { 10 | this.value = new ConstExp(o); 11 | } 12 | 13 | private final ConstExp value; 14 | 15 | public ConstExp getValue() { 16 | return value; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/FelCompiler.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import com.greenpineyu.fel.Expression; 4 | 5 | public interface FelCompiler { 6 | 7 | /** 8 | * 9 | * 编译代码,并创建Expression 10 | * @param expr 11 | * @return 12 | */ 13 | public Expression compile(JavaSource src); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/FelCompiler15.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.OutputStreamWriter; 9 | import java.io.UnsupportedEncodingException; 10 | import java.util.List; 11 | 12 | import com.greenpineyu.fel.Expression; 13 | import com.sun.tools.javac.Main; 14 | 15 | /** 16 | * jdk1.5环境的编译器实现类 17 | * 18 | * @author yuqingsong 19 | * 20 | */ 21 | public class FelCompiler15 extends AbstCompiler { 22 | 23 | 24 | @Override 25 | Class compileToClass(JavaSource src) throws ClassNotFoundException { 26 | String className = src.getSimpleName(); 27 | String pack = src.getPackageName(); 28 | String srcPackageDir = getSrcPackageDir(pack); 29 | String file = srcPackageDir + className + ".java"; 30 | new File(srcPackageDir).mkdirs(); 31 | String source =src.getSource(); 32 | writeJavaFile(file, source); 33 | 34 | List opt = getCompileOption(); 35 | opt.add(file); 36 | String[] arg = opt.toArray(new String[0]); 37 | 38 | int compile = Main.compile(arg); 39 | if (compile != 0) { 40 | return null; 41 | } 42 | @SuppressWarnings("unchecked") 43 | Class c = (Class) loader.loadClass(src.getName()); 44 | return c; 45 | } 46 | 47 | void writeJavaFile(String file, String source) { 48 | OutputStreamWriter write = null; 49 | try { 50 | BufferedOutputStream os; 51 | os = new BufferedOutputStream(new FileOutputStream(file), 500); 52 | write = new OutputStreamWriter(os, "utf-8"); 53 | write.write(source); 54 | } catch (FileNotFoundException e) { 55 | e.printStackTrace(); 56 | } catch (UnsupportedEncodingException e) { 57 | e.printStackTrace(); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } finally { 61 | if (write != null) { 62 | try { 63 | write.close(); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | } 69 | } 70 | 71 | 72 | 73 | 74 | 75 | public static void main(String[] args) throws InstantiationException, 76 | IllegalAccessException { 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/FelCompiler16.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.net.URI; 6 | import java.net.URISyntaxException; 7 | import java.net.URL; 8 | import java.net.URLClassLoader; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import javax.tools.DiagnosticCollector; 13 | import javax.tools.FileObject; 14 | import javax.tools.ForwardingJavaFileManager; 15 | import javax.tools.JavaCompiler; 16 | import javax.tools.JavaCompiler.CompilationTask; 17 | import javax.tools.JavaFileManager; 18 | import javax.tools.JavaFileObject; 19 | import javax.tools.JavaFileObject.Kind; 20 | import javax.tools.StandardJavaFileManager; 21 | import javax.tools.StandardLocation; 22 | import javax.tools.ToolProvider; 23 | 24 | import com.greenpineyu.fel.Expression; 25 | import com.greenpineyu.fel.exception.CompileException; 26 | 27 | public class FelCompiler16 implements FelCompiler { 28 | private final FelCompilerClassloader classLoader; 29 | 30 | private final JavaCompiler compiler; 31 | 32 | private final List options; 33 | 34 | private DiagnosticCollector diagnostics; 35 | 36 | private final JavaFileManager javaFileManager; 37 | 38 | public FelCompiler16() { 39 | compiler = ToolProvider.getSystemJavaCompiler(); 40 | 41 | if (compiler == null) { 42 | throw new IllegalStateException( 43 | "Cannot find the system Java compiler. " 44 | + "Check that your class path includes tools.jar"); 45 | } 46 | 47 | this.classLoader = new FelCompilerClassloader(this.getClass() 48 | .getClassLoader()); 49 | diagnostics = new DiagnosticCollector(); 50 | final StandardJavaFileManager fileManager = compiler 51 | .getStandardFileManager(diagnostics, null, null); 52 | 53 | ClassLoader loader = this.classLoader.getParent(); 54 | if (loader instanceof URLClassLoader 55 | && (!loader.getClass().getName() 56 | .equals("sun.misc.Launcher$AppClassLoader"))) { 57 | try { 58 | URLClassLoader urlClassLoader = (URLClassLoader) loader; 59 | List path = new ArrayList(); 60 | for (URL url : urlClassLoader.getURLs()) { 61 | File file = new File(url.getFile()); 62 | path.add(file); 63 | } 64 | fileManager.setLocation(StandardLocation.CLASS_PATH, path); 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | 70 | javaFileManager = new ForwardingJavaFileManager( 71 | fileManager) { 72 | @Override 73 | public JavaFileObject getJavaFileForOutput(Location location, 74 | String qualifiedName, Kind kind, FileObject outputFile) 75 | throws IOException { 76 | // 由于编译成功后的bytecode需要放到file中,所以需要将file放到classloader中,以便读取bytecode生成Class对象. 77 | classLoader.add(qualifiedName, outputFile); 78 | return (JavaFileObject) outputFile; 79 | } 80 | }; 81 | this.options = new ArrayList(); 82 | // this.options.add("-O"); 83 | } 84 | 85 | @Override 86 | public Expression compile(JavaSource src) { 87 | 88 | Class compile = compileToClass(src); 89 | try { 90 | return (Expression) compile.newInstance(); 91 | } catch (InstantiationException e) { 92 | e.printStackTrace(); 93 | } catch (IllegalAccessException e) { 94 | e.printStackTrace(); 95 | } 96 | return null; 97 | } 98 | 99 | 100 | public synchronized Class compileToClass(final JavaSource src) { 101 | List compileSrcs = new ArrayList(); 102 | String className = src.getSimpleName(); 103 | final FelJavaFileObject compileSrc = new FelJavaFileObject(className, 104 | src.getSource()); 105 | compileSrcs.add(compileSrc); 106 | final CompilationTask task = compiler.getTask(null, javaFileManager, 107 | diagnostics, options, null, compileSrcs); 108 | final Boolean result = task.call(); 109 | if (result == null || !result.booleanValue()) { 110 | // diagnostics. 111 | // 编译失败 112 | // diagnostics.getDiagnostics() 113 | throw new CompileException(src.getSource() + "\n" 114 | + diagnostics.getDiagnostics().toString()); 115 | } 116 | try { 117 | return loadClass(src.getName()); 118 | } catch (ClassNotFoundException e) { 119 | e.printStackTrace(); 120 | } 121 | return null; 122 | } 123 | 124 | @SuppressWarnings("unchecked") 125 | public Class loadClass(final String qualifiedClassName) 126 | throws ClassNotFoundException { 127 | return (Class) classLoader.loadClass(qualifiedClassName); 128 | } 129 | 130 | static URI toUri(String name) { 131 | try { 132 | return new URI(name); 133 | } catch (URISyntaxException e) { 134 | throw new RuntimeException(e); 135 | } 136 | } 137 | 138 | } 139 | 140 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/FelCompilerClassloader.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import javax.tools.FileObject; 7 | 8 | public final class FelCompilerClassloader extends ClassLoader { 9 | private final Map compileFileMap = new HashMap(); 10 | 11 | public FelCompilerClassloader(ClassLoader parentClassLoader) { 12 | super(parentClassLoader); 13 | } 14 | 15 | 16 | @Override 17 | protected synchronized Class findClass(String qualifiedClassName) throws ClassNotFoundException { 18 | FileObject file = compileFileMap.remove(qualifiedClassName); 19 | if (file != null) { 20 | byte[] bytes = ((FelJavaFileObject) file).getByteCode(); 21 | return defineClass(qualifiedClassName, bytes, 0, bytes.length); 22 | } 23 | return super.findClass(qualifiedClassName); 24 | } 25 | 26 | public void add(String qualifiedClassName, final FileObject javaFile) { 27 | compileFileMap.put(qualifiedClassName, javaFile); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/FelJavaFileObject.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | import java.net.URI; 8 | 9 | import javax.tools.SimpleJavaFileObject; 10 | 11 | /** 12 | * 编译时,用于提供类源码和保存类的字节码 13 | * 14 | * @author yuqingsong 15 | * 16 | */ 17 | public class FelJavaFileObject extends SimpleJavaFileObject { 18 | 19 | // If kind == CLASS, this stores byte code from openOutputStream 20 | private final ByteArrayOutputStream byteCodeOs = new ByteArrayOutputStream(); 21 | 22 | // if kind == SOURCE, this contains the source text 23 | private final CharSequence src; 24 | 25 | public FelJavaFileObject(final String baseName, final CharSequence source) { 26 | super(FelCompiler16.toUri(baseName + ".java"), 27 | Kind.SOURCE); 28 | this.src = source; 29 | } 30 | 31 | FelJavaFileObject(final String name, final Kind kind) { 32 | super(FelCompiler16.toUri(name), kind); 33 | src = null; 34 | } 35 | 36 | public FelJavaFileObject(URI uri, Kind kind) { 37 | super (uri, kind); 38 | src = null; 39 | } 40 | 41 | @Override 42 | public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws UnsupportedOperationException { 43 | if (src == null) { 44 | throw new UnsupportedOperationException(); 45 | } 46 | 47 | return src; 48 | } 49 | 50 | @Override 51 | public InputStream openInputStream() { 52 | return new ByteArrayInputStream(getByteCode()); 53 | } 54 | 55 | @Override 56 | public OutputStream openOutputStream() { 57 | return byteCodeOs; 58 | } 59 | 60 | byte[] getByteCode() { 61 | return byteCodeOs.toByteArray(); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/FelMethod.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import com.greenpineyu.fel.context.FelContext; 4 | import com.greenpineyu.fel.parser.FelNode; 5 | 6 | /** 7 | * 8 | */ 9 | public class FelMethod implements SourceBuilder { 10 | 11 | private Class returnType; 12 | 13 | private String code; 14 | 15 | 16 | public FelMethod(Class returnType,String code){ 17 | this.returnType = returnType; 18 | this.code = code; 19 | } 20 | 21 | 22 | public Class returnType(FelContext ctx, FelNode node) { 23 | return returnType; 24 | } 25 | 26 | 27 | public void setReturnType(Class returnType) { 28 | this.returnType = returnType; 29 | } 30 | 31 | 32 | public String source(FelContext ctx, FelNode node) { 33 | return code; 34 | } 35 | 36 | 37 | public void setCode(String code) { 38 | this.code = code; 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/FileClassLoader.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.IOException; 7 | 8 | public class FileClassLoader extends ClassLoader { 9 | private String dir; 10 | public static final String fileType = ".class"; 11 | 12 | public FileClassLoader(ClassLoader arg0, String dir) { 13 | super(arg0); 14 | this.dir = dir; 15 | } 16 | 17 | public Class findClass(String name) { 18 | byte[] data = loadClassData(name); 19 | return defineClass(name, data, 0, data.length); 20 | } 21 | 22 | public byte[] loadClassData(String name) { 23 | name = name.replaceAll("\\.", "/"); 24 | FileInputStream fis = null; 25 | byte[] data = null; 26 | try { 27 | fis = new FileInputStream(new File(dir + name + fileType)); 28 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 29 | int ch = 0; 30 | while ((ch = fis.read()) != -1) { 31 | baos.write(ch); 32 | } 33 | data = baos.toByteArray(); 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | }finally{ 37 | if(fis!= null){ 38 | try { 39 | fis.close(); 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | } 45 | return data; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/InterpreterSourceBuilder.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import com.greenpineyu.fel.context.AbstractContext; 4 | import com.greenpineyu.fel.context.FelContext; 5 | import com.greenpineyu.fel.interpreter.Interpreter; 6 | import com.greenpineyu.fel.parser.FelNode; 7 | 8 | public class InterpreterSourceBuilder implements SourceBuilder { 9 | 10 | 11 | 12 | 13 | private static final SourceBuilder instance; 14 | 15 | public static SourceBuilder getInstance() { 16 | return instance; 17 | } 18 | 19 | static{ 20 | instance = new InterpreterSourceBuilder(); 21 | } 22 | 23 | 24 | 25 | @Override 26 | public Class returnType(FelContext ctx, FelNode node) { 27 | return AbstractContext.getVarType(node.getInterpreter().interpret(ctx, node)); 28 | } 29 | 30 | /** 31 | * 用户自定义解析器生成的java代码 32 | * 33 | * @param ctx 34 | * @param node 35 | * @return 36 | */ 37 | @Override 38 | public String source(FelContext ctx, FelNode node) { 39 | // 用户设置了解释器 40 | // Interpreter inte = new ProxyInterpreter(node.getInterpreter(), node); 41 | Interpreter inte = node.getInterpreter(); 42 | SourceBuilder nodeBuilder = node.toMethod(ctx); 43 | Class type =nodeBuilder.returnType(ctx, node); 44 | String code = "("+type.getName()+")"; 45 | String varName = VarBuffer.push(inte,Interpreter.class); 46 | String nodeVarName = VarBuffer.push(node, FelNode.class); 47 | code += varName + ".interpret(context," + nodeVarName + ")"; 48 | boolean isNumber = Number.class.isAssignableFrom(type); 49 | if(isNumber){ 50 | code="("+code+").doubleValue()"; 51 | } 52 | return code; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/JavaSource.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | public class JavaSource { 4 | 5 | /** 6 | * 类名,不包含包名 7 | */ 8 | private String simpleName; 9 | 10 | /** 11 | * java源码 12 | */ 13 | private String source; 14 | 15 | /** 16 | * 包名 17 | */ 18 | private String packageName; 19 | 20 | public String getPackageName() { 21 | return packageName; 22 | } 23 | 24 | public void setPackageName(String packageName) { 25 | this.packageName = packageName; 26 | } 27 | 28 | public String getSimpleName() { 29 | return simpleName; 30 | } 31 | 32 | public void setSimpleName(String name) { 33 | this.simpleName = name; 34 | } 35 | 36 | public String getName(){ 37 | return packageName + "." + simpleName; 38 | } 39 | 40 | public String getSource() { 41 | return source; 42 | } 43 | 44 | public void setSource(String source) { 45 | this.source = source; 46 | } 47 | 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/SourceBuilder.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import com.greenpineyu.fel.context.FelContext; 4 | import com.greenpineyu.fel.parser.FelNode; 5 | 6 | /** 7 | * 创建java源码接口,此接口和SourceGenerator的区别在于,后者负责创建整个java类的源码。前者只用了创建表达式的代码片断。 8 | * @author yuqingsong 9 | * 10 | */ 11 | public interface SourceBuilder { 12 | 13 | /** 14 | * 类型 15 | * @param ctx TODO 16 | * @param node TODO 17 | * @return 18 | */ 19 | Class returnType(FelContext ctx, FelNode node); 20 | /** 21 | * 构建源码 22 | * @param node TODO 23 | * @return 24 | */ 25 | String source(FelContext ctx, FelNode node); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/SourceGenerator.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import com.greenpineyu.fel.context.FelContext; 4 | import com.greenpineyu.fel.optimizer.Optimizer; 5 | import com.greenpineyu.fel.parser.FelNode; 6 | 7 | public interface SourceGenerator { 8 | 9 | /** 10 | * 获取表达式JAVA源代码 11 | * @param node TODO 12 | * @return 13 | */ 14 | JavaSource getSource(FelContext ctx, FelNode node); 15 | 16 | void addOpti(Optimizer opti); 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/VarBuffer.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Stack; 6 | import java.util.UUID; 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | 10 | 11 | public class VarBuffer { 12 | static private ThreadLocal> varCodes; 13 | static private ThreadLocal> vars; 14 | static { 15 | varCodes = new ThreadLocal>(); 16 | vars = new ThreadLocal>(); 17 | } 18 | 19 | private static int count; 20 | 21 | /** 22 | * 获取当前线程中的变量代码(类的属性代码)stack 23 | * 24 | * @return 25 | */ 26 | private static Stack getVarCodes(){ 27 | Stack stack = varCodes.get(); 28 | if(stack == null){ 29 | stack = new Stack(); 30 | varCodes.set(stack); 31 | } 32 | return stack; 33 | } 34 | 35 | /** 36 | * 获取当前线程中的保存的对象Map。 37 | * 38 | * @return 39 | */ 40 | private static Map getVars(){ 41 | Map map = vars.get(); 42 | if(map == null){ 43 | map = new HashMap(); 44 | vars.set(map); 45 | } 46 | return map; 47 | } 48 | 49 | /** 50 | * 将变量存入线程 51 | * 52 | * @param attrCode 53 | */ 54 | static public String push(Object var){ 55 | return push(var,var.getClass()); 56 | 57 | } 58 | static public String push(Object var,Class cls){ 59 | String varName = getVarName(); 60 | 61 | String type = cls.getName(); 62 | String varId = UUID.randomUUID().toString(); 63 | 64 | getVars().put(varId, var); 65 | String code = "private static final " + type + " " + varName 66 | +" = ("+type+")"+VarBuffer.class.getSimpleName()+".pop(\""+varId+"\");"; 67 | getVarCodes().push(code); 68 | return varName; 69 | } 70 | 71 | 72 | 73 | synchronized static private String getVarName(){ 74 | return "attr_"+count++; 75 | } 76 | 77 | /** 78 | * 从线程取出变量 79 | * 80 | * @param attrCode 81 | * @return 82 | */ 83 | public static String pop(){ 84 | Stack stack = getVarCodes(); 85 | if(stack.empty()){ 86 | return null; 87 | } 88 | return stack.pop(); 89 | } 90 | 91 | public static Object pop(String name){ 92 | return getVars().remove(name); 93 | } 94 | 95 | private static ThreadLocal tl = new ThreadLocal(); 96 | public static void main(String[] args) { 97 | int i = 100; 98 | ExecutorService pool = Executors.newFixedThreadPool(i); 99 | for (int j = 0; j < i; j++) { 100 | pool.submit(new Runnable() { 101 | 102 | @Override 103 | public void run() { 104 | String name = Thread.currentThread().getName(); 105 | System.out.println("*******************"+name+" start************************"); 106 | tl.set(name); 107 | get(name); 108 | System.out.println("*******************"+name+" end************************"); 109 | 110 | } 111 | 112 | private void get(String name) { 113 | String string = tl.get(); 114 | System.out.println(name+":"+(name == string)); 115 | } 116 | }); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/compile/java.template: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.compile; 2 | 3 | import com.greenpineyu.fel.common.*; 4 | import com.greenpineyu.fel.Expression; 5 | import com.greenpineyu.fel.context.*; 6 | //import org.apache.commons.lang3.ObjectUtils; 7 | //import org.apache.commons.lang3.StringUtils; 8 | 9 | public class ${classname} implements Expression{ 10 | ${attrs} 11 | public Object eval(FelContext context) { 12 | ${localVars} 13 | return ${expression}; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/context/AbstractContext.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.context; 2 | 3 | 4 | import com.greenpineyu.fel.common.ReflectUtil; 5 | 6 | public abstract class AbstractContext implements FelContext{ 7 | 8 | 9 | 10 | // @Override 11 | // public Object get(String name) { 12 | // Var var = this.getVar(name); 13 | // return var==null?null:var.getValue(); 14 | // } 15 | 16 | @Override 17 | public void setVar(Var var) { 18 | // 设置变量值 19 | throw new UnsupportedOperationException(this.getClass().getSimpleName() + "不能存储变量"); 20 | } 21 | 22 | @Override 23 | public void set(String name, Object value) { 24 | this.setVar(new Var(name,value)); 25 | } 26 | 27 | @Override 28 | public Var getVar(String name) { 29 | Object value = get(name); 30 | return new Var(name, value, null); 31 | } 32 | 33 | 34 | public static Class getVarType(String varName, FelContext ctx) { 35 | Var var = ctx.getVar(varName); 36 | return var == null?null:var.getType(); 37 | } 38 | 39 | public static Class getVarType(Object varValue) { 40 | Class type = null; 41 | if (varValue != null) { 42 | type = varValue.getClass(); 43 | } 44 | return getVarType(type); 45 | } 46 | 47 | public static Class getVarType(Class type) { 48 | if(type == null){ 49 | return NULL.getClass(); 50 | } 51 | if(type.isPrimitive()){ 52 | // 基本类型转换成包装类型 53 | type = ReflectUtil.toWrapperClass(type); 54 | } 55 | if(ReflectUtil.isPrimitiveOrWrapNumber(type)){ 56 | return type; 57 | }else if (Number.class.isAssignableFrom(type)) { 58 | type = Number.class; 59 | } 60 | return type; 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/context/ArrayCtx.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.context; 2 | 3 | public interface ArrayCtx extends FelContext { 4 | 5 | /** 6 | * 根据索引获取变量值 7 | * @param i 8 | * @return 9 | */ 10 | Object get(int i); 11 | 12 | /** 13 | * 获取变量的索引 14 | * @param name 15 | * @return 16 | */ 17 | int getIndex(String name); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/context/ArrayCtxImpl.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.context; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class ArrayCtxImpl implements ArrayCtx{ 8 | 9 | 10 | /** 11 | * 保存对象类型的变量,包含数值类型的变量 12 | */ 13 | private Var[] vars = new Var[10]; 14 | 15 | private Map indexMap = new HashMap(); 16 | 17 | public ArrayCtxImpl(){ 18 | } 19 | public ArrayCtxImpl(Map vars){ 20 | if(vars!=null){ 21 | for (Map.Entry e : vars.entrySet()) { 22 | this.set(e.getKey(), e.getValue()); 23 | } 24 | } 25 | } 26 | 27 | @Override 28 | public Object get(int i) { 29 | return vars[i].getValue(); 30 | } 31 | 32 | @Override 33 | public int getIndex(String name) { 34 | Integer i = indexMap.get(name); 35 | return i!=null?i:-1; 36 | } 37 | 38 | 39 | @Override 40 | public Object get(String name) { 41 | Var var = getVar(name); 42 | return var!=null?var.getValue():null; 43 | } 44 | 45 | @Override 46 | public Var getVar(String name) { 47 | int index = getIndex(name); 48 | if(index == -1){ 49 | return null; 50 | } 51 | return vars[index]; 52 | } 53 | 54 | /** 55 | * 获取变量,如果变量不存在,就添加一个新的变量。 56 | * @param name 57 | * @return 58 | */ 59 | private Var getVarWithoutNull(String name){ 60 | Var var = getVar(name); 61 | if(var == null){ 62 | var = new Var(name,null); 63 | setVar(var); 64 | } 65 | return var; 66 | } 67 | 68 | 69 | 70 | /** 71 | * 确保vars.length>minCapacity 72 | * @param minCapacity 73 | */ 74 | public void ensureCapacity(int minCapacity) { 75 | int oldCapacity = vars.length; 76 | if (minCapacity > oldCapacity) { 77 | int newCapacity = (oldCapacity * 3)/2 + 1; 78 | if (newCapacity < minCapacity) 79 | newCapacity = minCapacity; 80 | // minCapacity is usually close to size, so this is a win: 81 | vars = Arrays.copyOf(vars, newCapacity); 82 | } 83 | } 84 | 85 | @Override 86 | public void set(String name, Object value) { 87 | getVarWithoutNull(name).setValue(value); 88 | } 89 | 90 | @Override 91 | public void setVar(Var var) { 92 | int i = addToIndexMap(var.getName()); 93 | if(i getVarType(String varName) { 38 | // return AbstractConetxt.getVarType(varName, this); 39 | // } 40 | 41 | @Override 42 | public Var getVar(String name) { 43 | Var object = current.getVar(name); 44 | if(object != null){ 45 | return object; 46 | } 47 | return parent.getVar(name); 48 | } 49 | 50 | @Override 51 | public void setVar(Var var) { 52 | current.setVar(var); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/context/EmptyContext.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.context; 2 | 3 | /** 4 | * 空执行上下文 5 | * 6 | * @author yuqingsong 7 | * 8 | */ 9 | /* 10 | public class EmptyContext implements FelContext{ 11 | 12 | private static final FelContext instance; 13 | 14 | public static FelContext getInstance() { 15 | return instance; 16 | } 17 | 18 | static{ 19 | instance= new EmptyContext(); 20 | } 21 | 22 | private EmptyContext(){}; 23 | 24 | 25 | @Override 26 | public Object get(String name) { 27 | return null; 28 | } 29 | 30 | @Override 31 | public void set(String name, Object value) { 32 | throw new UnsupportedOperationException("空Context"); 33 | } 34 | 35 | // @Override 36 | // public Class getVarType(String varName) { 37 | // throw new UnsupportedOperationException("空Context"); 38 | // } 39 | 40 | 41 | @Override 42 | public Var getVar(String name) { 43 | throw new UnsupportedOperationException("空Context"); 44 | } 45 | 46 | 47 | @Override 48 | public void setVar(Var var) { 49 | throw new UnsupportedOperationException("空Context"); 50 | 51 | } 52 | 53 | } 54 | */ 55 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/context/FelContext.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.context; 2 | 3 | import com.greenpineyu.fel.common.Null; 4 | 5 | 6 | 7 | public interface FelContext { 8 | 9 | 10 | Null NULL = new Null(); 11 | 12 | /** 13 | * 获取变量值 14 | * 15 | * @param name 16 | * 变量名称 17 | * @return 变量值,如果没有找到变量,返回FelContext.NOT_FOUND 18 | */ 19 | Object get(String name); 20 | 21 | /** 22 | * 设置变量 23 | * 24 | * @param name 25 | * 变量名称 26 | * @param value 27 | * 变量值 28 | */ 29 | void set(String name, Object value); 30 | 31 | Var getVar(String name); 32 | 33 | void setVar(Var var); 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/context/MapContext.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.context; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 8 | * @author yuqingsong 9 | * 10 | */ 11 | /* 12 | * 更合适的实现方式是使用组合,而不是继承,这里继承HashMap是为了提高get方法的效率。 13 | */ 14 | @SuppressWarnings("serial") 15 | public class MapContext extends HashMap implements FelContext { 16 | public MapContext() { 17 | } 18 | 19 | public MapContext(Map map){ 20 | // this.putAll(map); 21 | if(map != null){ 22 | for (Map.Entry e : map.entrySet()) { 23 | String name = e.getKey(); 24 | Object value = e.getValue(); 25 | this.set(name, value); 26 | } 27 | } 28 | } 29 | 30 | @Override 31 | public Object get(String name) { 32 | Var object = super.get(name); 33 | if (object != null) { 34 | // 对象有值,或者包含此变量时,返回object 35 | return object.getValue(); 36 | } 37 | return null; 38 | // map中不包含此变量返回NOT_FOUND 39 | // return NOT_FOUND; 40 | } 41 | 42 | // @Override 43 | // public Class getVarType(String varName) { 44 | // return AbstractConetxt.getVarType(varName,this); 45 | // } 46 | 47 | 48 | @Override 49 | public void set(String name, Object value) { 50 | // 如果变量已经存在,就不再重复创建变量。 51 | Var var = getVar(name); 52 | if (var != null) { 53 | var.setValue(value); 54 | } else { 55 | this.put(name, new Var(name, value)); 56 | } 57 | } 58 | 59 | public static String toString(Object var) { 60 | return var == null ? null : var.toString(); 61 | } 62 | 63 | @Override 64 | public Var getVar(String name) { 65 | return super.get(name); 66 | } 67 | 68 | @Override 69 | public void setVar(Var var) { 70 | super.put(var.getName(), var); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/context/Var.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.context; 2 | 3 | import com.greenpineyu.fel.common.Null; 4 | 5 | /** 6 | * 变量 7 | * @author yuqingsong 8 | * 9 | * @param 变量的类型 10 | */ 11 | public class Var { 12 | 13 | public Var(String name,Object value,Class type){ 14 | this.name = name; 15 | this.value = value; 16 | this.type = type; 17 | // if(type == null){ 18 | // // 如果没有指定type,将type设置成value.getClass。 19 | //// setTypeByValue(value); 20 | // } 21 | } 22 | private Class getTypeByValue() { 23 | return value!=null?value.getClass():Null.class; 24 | // this.type = getTypeByValue; 25 | } 26 | public Var(String name,Object value){ 27 | this(name,value,null); 28 | } 29 | 30 | /** 31 | * 变量名称 32 | */ 33 | private String name; 34 | 35 | /** 36 | * 变量值 37 | */ 38 | private Object value; 39 | 40 | /** 41 | * 变量值 42 | */ 43 | private Class type; 44 | 45 | 46 | public Class getType() { 47 | return type!=null?type:getTypeByValue(); 48 | } 49 | 50 | public void setType(Class type) { 51 | this.type = type; 52 | } 53 | 54 | public String getName() { 55 | return name; 56 | } 57 | 58 | public void setName(String name) { 59 | this.name = name; 60 | } 61 | 62 | public Object getValue() { 63 | return value; 64 | } 65 | 66 | public void setValue(Object value) { 67 | this.value = value; 68 | } 69 | 70 | public static void main(String[] args) { 71 | } 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/exception/CompileException.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class CompileException extends RuntimeException { 5 | public CompileException(String msg) { 6 | super(msg); 7 | } 8 | 9 | public CompileException(String msg, Throwable cause) { 10 | super(msg, cause); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/exception/EvalException.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class EvalException extends RuntimeException { 5 | public EvalException(String msg) { 6 | super(msg); 7 | } 8 | 9 | public EvalException(String msg, Throwable cause) { 10 | super(msg, cause); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/exception/ParseException.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class ParseException extends RuntimeException { 5 | public ParseException(String msg) { 6 | super(msg); 7 | } 8 | 9 | public ParseException(String msg, Throwable cause) { 10 | super(msg, cause); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/CommonFunction.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function; 2 | 3 | import java.util.List; 4 | 5 | import com.greenpineyu.fel.Expression; 6 | import com.greenpineyu.fel.compile.InterpreterSourceBuilder; 7 | import com.greenpineyu.fel.compile.SourceBuilder; 8 | import com.greenpineyu.fel.context.FelContext; 9 | import com.greenpineyu.fel.parser.FelNode; 10 | 11 | /** 12 | * 普通函数 13 | * 14 | * @author yqs 15 | * 16 | */ 17 | public abstract class CommonFunction implements Function { 18 | 19 | /* 20 | * (non-Javadoc) 21 | * 22 | * @see .script.function.Function#call(.script.antlr.AstNode, 23 | * .script.context.ScriptContext) 24 | */ 25 | public Object call(FelNode node, FelContext context) { 26 | // 如果参数中包含表达式,执行表达式。将表达式替换成表达式执行结果。 27 | Object[] children = evalArgs(node, context); 28 | return call(children); 29 | } 30 | 31 | public SourceBuilder toMethod(FelNode node, FelContext ctx) { 32 | return InterpreterSourceBuilder.getInstance(); 33 | } 34 | 35 | 36 | public static Object[] evalArgs(FelNode node, FelContext context) { 37 | Object[] returnMe = null; 38 | List children = node.getChildren(); 39 | if(children!=null&& children.size()>0){ 40 | Object[] args = children.toArray(); 41 | int size = args.length; 42 | returnMe = new Object[size]; 43 | System.arraycopy(args, 0, returnMe, 0, size); 44 | for (int i = 0; i < size; i++) { 45 | Object child = args[i]; 46 | if (child instanceof Expression) { 47 | Expression childExp = ((Expression) child); 48 | returnMe[i] = childExp.eval(context); 49 | } 50 | } 51 | } 52 | return returnMe; 53 | } 54 | 55 | public static void main(String[] args) { 56 | /* 57 | * List list = new ArrayList(); String[] abc = new String[] { "1", "3", 58 | * "4" }; for (int i = 0; i < abc.length; i++) { String string = abc[i]; 59 | * list.add(string); } int time = 1000000; long s1 = 60 | * System.currentTimeMillis(); 61 | * 62 | * for (int i = 0; i < time; i++) { abc.clone(); } long s2 = 63 | * System.currentTimeMillis(); System.out.println("花费的时间:" + (s2 - s1)); 64 | * 65 | * for (int i = 0; i < time; i++) { list.toArray(new Object[0]); } long 66 | * s3 = System.currentTimeMillis(); System.out.println("花费的时间:" + (s3 - 67 | * s2)); 68 | */ 69 | // Object[] returnMe = null; 70 | // Object[] children = node.getChildrenArray(); 71 | // int size = children.length; 72 | // if (size > 0) { 73 | // returnMe = (Object[]) children.clone(); 74 | // for (int i = 0; i < size; i++) { 75 | // Object child = children[i]; 76 | // if (child instanceof Expression) { 77 | // Expression childExp = ((Expression) child); 78 | // returnMe[i] = childExp.eval(context); 79 | // } 80 | // } 81 | // } 82 | // return returnMe; 83 | } 84 | 85 | /** 86 | * 调用函数 87 | * 88 | * @param arguments 89 | * @return 90 | */ 91 | abstract public Object call(Object[] arguments); 92 | } 93 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/Dollar.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function; 2 | 3 | import com.greenpineyu.fel.FelEngine; 4 | import com.greenpineyu.fel.common.StringUtils; 5 | import com.greenpineyu.fel.compile.FelMethod; 6 | import com.greenpineyu.fel.compile.SourceBuilder; 7 | import com.greenpineyu.fel.context.FelContext; 8 | import com.greenpineyu.fel.parser.FelNode; 9 | 10 | /** 11 | * $函数,通过$获取class或者创建对象 ${Math} 结果为 Math.class ${Dollar.new} 结果为 new Dollar() 12 | * 13 | * @author yuqingsong 14 | * 15 | */ 16 | public class Dollar implements Function { 17 | 18 | 19 | @Override 20 | public String getName() { 21 | return "$"; 22 | } 23 | 24 | @Override 25 | public Object call(FelNode node, FelContext context) { 26 | String txt = getChildText(node); 27 | 28 | boolean isNew = isNew(txt); 29 | Class cls = getClass(txt, isNew); 30 | if (isNew) { 31 | Object o = null; 32 | if (cls != null) { 33 | try { 34 | o = cls.newInstance(); 35 | } catch (InstantiationException e) { 36 | e.printStackTrace(); 37 | } catch (IllegalAccessException e) { 38 | e.printStackTrace(); 39 | } 40 | } 41 | return o; 42 | 43 | } else { 44 | return cls; 45 | } 46 | } 47 | 48 | private static final String suffix = ".new"; 49 | 50 | @SuppressWarnings("unused") 51 | private Class getClass(FelNode node) { 52 | String txt = getChildText(node); 53 | boolean isNew = isNew(txt); 54 | return getClass(txt, isNew); 55 | } 56 | 57 | private Class getClass(String txt, boolean isNew) { 58 | String className = txt; 59 | if (isNew) { 60 | className = className.substring(0, txt.length() - suffix.length()); 61 | } 62 | if (className.indexOf(".") == -1) { 63 | className = "java.lang." + className; 64 | } 65 | try { 66 | Class clz = Class.forName(className); 67 | return clz; 68 | } catch (ClassNotFoundException e) { 69 | e.printStackTrace(); 70 | } 71 | return null; 72 | } 73 | 74 | private boolean isNew(String txt) { 75 | boolean isNew = txt.endsWith(suffix); 76 | return isNew; 77 | } 78 | 79 | private String getChildText(FelNode node) { 80 | String txt = node.getChildren().get(0).getText(); 81 | txt = StringUtils.remove(txt, '\''); 82 | txt = StringUtils.remove(txt, '"'); 83 | return txt; 84 | } 85 | 86 | @Override 87 | public SourceBuilder toMethod(FelNode node, FelContext ctx) { 88 | String txt = getChildText(node); 89 | 90 | boolean isNew = isNew(txt); 91 | Class cls = getClass(txt, isNew); 92 | String code = cls.getName(); 93 | if (isNew) { 94 | code = "new " + code + "()"; 95 | } 96 | return new FelMethod(cls, code); 97 | } 98 | 99 | public static void main(String[] args) { 100 | // System.out.println("abc.new".endsWith(".new")); 101 | String exp = "$('Math').max($('Math').min(1,2),3).doubleValue()"; 102 | exp = "$('String.new').concat('abc')"; 103 | Object eval = FelEngine.instance 104 | .eval(exp); 105 | System.out.println(eval); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/ErrorValue.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function; 2 | 3 | import com.greenpineyu.fel.parser.FelNode; 4 | 5 | /** 6 | * 包名 .script.function 7 | * 类名 ERRORVALUE.java 8 | * 创建日期 Oct 27, 20108:56:26 AM 9 | * 作者 10 | * 版权 11 | */ 12 | public class ErrorValue { 13 | 14 | /** 15 | * 错误节点 16 | */ 17 | private FelNode node; 18 | 19 | /** 20 | * 错误信息 21 | */ 22 | private String errorMsg; 23 | 24 | public ErrorValue(FelNode node,String errorMsg){ 25 | this.node = node; 26 | this.errorMsg = errorMsg; 27 | } 28 | 29 | public FelNode getNode() { 30 | return node; 31 | } 32 | 33 | public void setNode(FelNode node) { 34 | this.node = node; 35 | } 36 | 37 | public String getErrorMsg() { 38 | return errorMsg; 39 | } 40 | 41 | public void setErrorMsg(String errorMsg) { 42 | this.errorMsg = errorMsg; 43 | } 44 | 45 | public String toString() { 46 | if (errorMsg != null) { 47 | return errorMsg; 48 | } 49 | return "执行脚本出错"; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/FunMgr.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import com.greenpineyu.fel.function.operator.Add; 7 | import com.greenpineyu.fel.function.operator.CollectionGet; 8 | import com.greenpineyu.fel.function.operator.Cond; 9 | import com.greenpineyu.fel.function.operator.Div; 10 | import com.greenpineyu.fel.function.operator.Dot; 11 | import com.greenpineyu.fel.function.operator.Equal; 12 | import com.greenpineyu.fel.function.operator.GreaterThan; 13 | import com.greenpineyu.fel.function.operator.GreaterThenEqual; 14 | import com.greenpineyu.fel.function.operator.LessThen; 15 | import com.greenpineyu.fel.function.operator.LessThenEqual; 16 | import com.greenpineyu.fel.function.operator.And; 17 | import com.greenpineyu.fel.function.operator.Mod; 18 | import com.greenpineyu.fel.function.operator.Mul; 19 | import com.greenpineyu.fel.function.operator.NotEqual; 20 | import com.greenpineyu.fel.function.operator.NotOper; 21 | import com.greenpineyu.fel.function.operator.Or; 22 | import com.greenpineyu.fel.function.operator.Sub; 23 | 24 | public class FunMgr { 25 | 26 | // private static FunMgr instance = new FunMgr(); 27 | 28 | public FunMgr() { 29 | userFunMap = new HashMap(); 30 | } 31 | 32 | /** 33 | * 用户函数 34 | */ 35 | private Map userFunMap; 36 | 37 | /** 38 | * 共用函数 39 | */ 40 | private Map funcMap; 41 | 42 | { 43 | funcMap = new HashMap(); 44 | 45 | // // 操作符函数 46 | addFun(new Dot()); 47 | // funcMap.put(".", new Dot()); 48 | 49 | addFun(new CollectionGet()); 50 | // funcMap.put(new CollectionGet().instance.getName(), CollectionGet.instance); 51 | 52 | addFun(new Cond()); 53 | // funcMap.put(CondOperator.instance.getName(), CondOperator.instance); 54 | addFun(new Dollar()); 55 | // funcMap.put(Dollar.instance.getName(), Dollar.instance); 56 | addFun(new NotOper()); 57 | // funcMap.put(NotOper.instance.getName(), NotOper.instance); 58 | 59 | addFun(new Add());//+ 60 | addFun(new Sub());//- 61 | // funcMap.put(Add.getInstance().getName(), Add.getInstance());// + 62 | // funcMap.put(Sub.getInstance().getName(), Sub.getInstance());// - 63 | // funcMap.put(EqualsOperator.EQUAL_STR, EqualsOperator.EQUAL);// == 64 | addFun(new Equal());//== 65 | addFun(new NotEqual());//!= 66 | // funcMap.put(EqualsOperator.NOEQUAL_STR, EqualsOperator.NOEQUAL);// != 67 | addFun(new Mul());// * 68 | addFun(new Div());// / 69 | addFun(new Mod());// % 70 | // funcMap.put(MultiplicativeOperator.MUL_STR, MultiplicativeOperator.MUL);// * 71 | // funcMap.put(MultiplicativeOperator.DIV_STR, MultiplicativeOperator.DIV);// / 72 | // funcMap.put(MultiplicativeOperator.MOD_STR, MultiplicativeOperator.MOD);// % 73 | addFun(new LessThen());// < 74 | addFun(new LessThenEqual());// <= 75 | addFun(new GreaterThan());// > 76 | addFun(new GreaterThenEqual());// >= 77 | // funcMap.put(RelationalOperator.LESSTHEN_STR, 78 | // RelationalOperator.LESSTHEN);// < 79 | // funcMap.put(RelationalOperator.GREATERTHAN_STR, 80 | // RelationalOperator.GREATERTHAN);// > 81 | // funcMap.put(RelationalOperator.LESSTHENOREQUALS_STR, 82 | // RelationalOperator.LESSTHENOREQUALS);// <= 83 | // funcMap.put(RelationalOperator.GREATERTHANOREQUALS_STR, 84 | // RelationalOperator.GREATERTHANOREQUALS);// >= 85 | // funcMap.put(LogicalOperator.AND_STR.toLowerCase(), LogicalOperator.AND);// AND 86 | addFun(new And());// && 87 | addFun(new Or());// || 88 | // funcMap.put(LogicalOperator.AND2_STR, LogicalOperator.AND2);// && 89 | // funcMap.put(LogicalOperator.OR_STR.toLowerCase(), LogicalOperator.OR);// OR 90 | // funcMap.put(LogicalOperator.OR2_STR, LogicalOperator.OR2);// || 91 | // funcMap.put(Like.getInstance().getName(), Like.getInstance());// like 92 | // funcMap.put(In.getInstance().getName(), In.getInstance());// in 93 | 94 | 95 | 96 | 97 | } 98 | 99 | private void addFun(Function fun) { 100 | funcMap.put(fun.getName(), fun); 101 | } 102 | 103 | /** 104 | * 获取函数。先从用户函数中取,如没有获取到,再从共用函数中获取。 105 | * @param funName 106 | * @return 107 | */ 108 | public Function getFun(String funName) { 109 | if(funName!=null) { 110 | String newFunName = getLowerCaseName(funName); 111 | Function userFun = userFunMap.get(newFunName); 112 | if(userFun != null){ 113 | return userFun; 114 | } 115 | return funcMap.get(newFunName); 116 | } 117 | return null; 118 | } 119 | 120 | private String getLowerCaseName(String funName) { 121 | return funName.toLowerCase(); 122 | } 123 | 124 | /** 125 | * 添加函数到用户函数库中 126 | * @param fun 127 | */ 128 | public void add(Function fun) { 129 | if (fun != null) { 130 | String name = fun.getName(); 131 | if(name==null || "".equals(name)){ 132 | throw new IllegalArgumentException("函数名称不能为空"); 133 | }else{ 134 | userFunMap.put(getLowerCaseName(name), fun); 135 | } 136 | } 137 | } 138 | 139 | 140 | /** 141 | * 移除用户函数 142 | * @param name 143 | */ 144 | public void remove(String name){ 145 | if (name != null) { 146 | userFunMap.remove(getLowerCaseName(name)); 147 | } 148 | } 149 | 150 | // static public FunMgr getInstance() { 151 | // return instance; 152 | // } 153 | } 154 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/Function.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function; 2 | 3 | import com.greenpineyu.fel.compile.SourceBuilder; 4 | import com.greenpineyu.fel.context.FelContext; 5 | import com.greenpineyu.fel.parser.FelNode; 6 | 7 | /** 8 | * @uml.dependency supplier=".script.context.ScriptContext" 9 | */ 10 | public interface Function { 11 | 12 | /** 13 | * 获取函数的名称 14 | * @return 15 | */ 16 | String getName(); 17 | 18 | /** 19 | * 调用函数 20 | * @param arguments 21 | * @return 22 | */ 23 | Object call(FelNode node, FelContext context); 24 | 25 | 26 | 27 | SourceBuilder toMethod(FelNode node,FelContext ctx); 28 | 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/JavaMethod.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.List; 5 | 6 | import com.greenpineyu.fel.compile.FelMethod; 7 | import com.greenpineyu.fel.compile.SourceBuilder; 8 | import com.greenpineyu.fel.compile.VarBuffer; 9 | import com.greenpineyu.fel.context.FelContext; 10 | import com.greenpineyu.fel.function.operator.Dot; 11 | import com.greenpineyu.fel.parser.FelNode; 12 | 13 | /** 14 | * 15 | * 此类用于保存用户注册的java method。 16 | * 17 | * @author Administrator 18 | * 19 | */ 20 | public class JavaMethod implements Function { 21 | 22 | /** 23 | * 方法名称 24 | */ 25 | private String name; 26 | 27 | /** 28 | * 对象,如果是静态方法,对象为null 29 | */ 30 | private Object obj; 31 | 32 | /** 33 | * java method 34 | */ 35 | private Method method; 36 | 37 | public JavaMethod(String name,Method method,Object obj) { 38 | this.name = name; 39 | this.method = method; 40 | this.obj = obj; 41 | } 42 | 43 | @Override 44 | public Object call(FelNode node, FelContext context) { 45 | // Dot.clearNullNode(node); 46 | Object[] args = CommonFunction.evalArgs(node, context); 47 | return Dot.invoke(obj, method, args); 48 | } 49 | 50 | @Override 51 | public String getName() { 52 | return name; 53 | } 54 | 55 | @Override 56 | public SourceBuilder toMethod(FelNode node, FelContext context) { 57 | StringBuilder code = new StringBuilder(); 58 | String classOrObjCode = getClassOrObjCode(); 59 | code.append(classOrObjCode); 60 | code.append("."); 61 | String methodName = method.getName(); 62 | code.append(methodName); 63 | StringBuilder methodParams = getParamsCode(node, context); 64 | code.append("(").append(methodParams).append(")"); 65 | FelMethod returnMe = new FelMethod(method 66 | .getReturnType(), code.toString()); 67 | return returnMe; 68 | } 69 | 70 | private String getClassOrObjCode() { 71 | if(obj == null){ 72 | Class cls = method.getDeclaringClass(); 73 | return cls.getCanonicalName(); 74 | }else{ 75 | String varName = VarBuffer.push(obj); 76 | return varName; 77 | } 78 | } 79 | 80 | private StringBuilder getParamsCode(FelNode node, FelContext context) { 81 | StringBuilder methodParams = new StringBuilder(); 82 | List params = node.getChildren(); 83 | boolean hasParam = params != null && !params.isEmpty(); 84 | Class[] paramTypes = method.getParameterTypes(); 85 | if (hasParam) { 86 | // 有参数 87 | for (int i = 0; i < paramTypes.length; i++) { 88 | Class paramType = paramTypes[i]; 89 | FelNode p = params.get(i); 90 | String paramCode = Dot.getParamCode(paramType, p, context); 91 | methodParams.append(paramCode); 92 | if(i iterator = node.getChildren().iterator(); iterator 37 | .hasNext();) { 38 | Object child = iterator.next(); 39 | if (child instanceof FelNode) { 40 | FelNode childNode = (FelNode) child; 41 | child = childNode.eval(context); 42 | } 43 | if (child instanceof String) { 44 | if (returnMe == null) { 45 | returnMe = child; 46 | continue; 47 | } 48 | returnMe = returnMe + (String) child; 49 | } 50 | if (child instanceof Number) { 51 | if (returnMe == null) { 52 | returnMe = child; 53 | continue; 54 | } 55 | Number value = (Number) child; 56 | if (returnMe instanceof Number) { 57 | Number r = (Number) returnMe; 58 | returnMe = toDouble(r) + toDouble(value); 59 | }else if(returnMe instanceof String){ 60 | String r = (String) returnMe; 61 | returnMe=r+value; 62 | } 63 | } 64 | } 65 | if(returnMe instanceof Number){ 66 | return NumberUtil.parseNumber(returnMe.toString()); 67 | } 68 | return returnMe; 69 | } 70 | 71 | @Override 72 | public String getName() { 73 | return "+"; 74 | } 75 | 76 | @Override 77 | public FelMethod toMethod(FelNode node, FelContext ctx) { 78 | Class type = null; 79 | List children = node.getChildren(); 80 | StringBuilder sb = new StringBuilder(); 81 | if (children.size() == 2) { 82 | FelNode left = children.get(0); 83 | SourceBuilder lm = left.toMethod(ctx); 84 | appendArg(sb, lm,ctx,left); 85 | Class leftType = lm.returnType(ctx, left); 86 | 87 | FelNode right = children.get(1); 88 | sb.append("+"); 89 | SourceBuilder rm = right.toMethod(ctx); 90 | Class rightType = rm.returnType(ctx, right); 91 | if(CharSequence.class.isAssignableFrom(leftType)){ 92 | type = leftType; 93 | } else if (CharSequence.class.isAssignableFrom(rightType)) { 94 | type = rightType; 95 | }else if(ReflectUtil.isPrimitiveOrWrapNumber(leftType) 96 | &&ReflectUtil.isPrimitiveOrWrapNumber(rightType)){ 97 | type = NumberUtil.arithmeticClass(leftType, rightType); 98 | }else { 99 | //不支持的类型,返回字符串。 100 | type = String.class; 101 | } 102 | appendArg(sb, rm,ctx,right); 103 | 104 | } else if (children.size() == 1) { 105 | FelNode right = children.get(0); 106 | SourceBuilder rm = right.toMethod(ctx); 107 | Class rightType = rm.returnType(ctx, right); 108 | if(ReflectUtil.isPrimitiveOrWrapNumber(rightType)){ 109 | appendArg(sb, rm,ctx,right); 110 | } 111 | type = rightType; 112 | } 113 | 114 | // appendArg(sb, rm,ctx,right); 115 | FelMethod m = new FelMethod(type, sb.toString()); 116 | return m; 117 | } 118 | 119 | 120 | private void appendArg(StringBuilder sb, SourceBuilder argMethod,FelContext ctx,FelNode node) { 121 | Class t = argMethod.returnType(ctx, node); 122 | sb.append("("); 123 | if (ReflectUtil.isPrimitiveOrWrapNumber(t) 124 | || CharSequence.class.isAssignableFrom(t)) { 125 | // 数值型和字符型时,直接添加 126 | sb.append(argMethod.source(ctx, node)); 127 | } else { 128 | sb.append("ObjectUtils.toString(").append(argMethod.source(ctx, node)) 129 | .append(")"); 130 | } 131 | sb.append(")"); 132 | } 133 | 134 | /** 135 | * 加法 136 | * 137 | * @param left 138 | * @param right 139 | * @return 140 | */ 141 | public static Object add(Object left, Object right){ 142 | if(left == null || right == null){ 143 | throw new NullPointerException("调用add()方法出错!,原因:当前参数为空"); 144 | } 145 | try { 146 | if (left instanceof Object[]){ 147 | left = NumberUtil.calArray(left); 148 | } 149 | if (right instanceof Object[]){ 150 | right = NumberUtil.calArray(right); 151 | } 152 | 153 | if (NumberUtil.isFloatingPointNumber(left) || NumberUtil.isFloatingPointNumber(right)) { 154 | double l = NumberUtil.toDouble(left); 155 | double r = NumberUtil.toDouble(right); 156 | return new Double(l + r); 157 | } 158 | 159 | if(left instanceof BigInteger && right instanceof BigInteger){ 160 | BigInteger l = NumberUtil.toBigInteger(left); 161 | BigInteger r = NumberUtil.toBigInteger(right); 162 | return l.add(r); 163 | } 164 | 165 | if(left instanceof BigDecimal || right instanceof BigDecimal){ 166 | BigDecimal l = NumberUtil.toBigDecimal(left); 167 | BigDecimal r = NumberUtil.toBigDecimal(right); 168 | return l.add(r); 169 | } 170 | 171 | if (left instanceof String && right instanceof Date) { 172 | return left + Add.DATE_FORMAT.format((Date) right); 173 | } else if (left instanceof Date && right instanceof String) { 174 | return Add.DATE_FORMAT.format((Date) left) + right; 175 | } 176 | 177 | BigInteger l = NumberUtil.toBigInteger(left); 178 | BigInteger r = NumberUtil.toBigInteger(right); 179 | BigInteger result = l.add(r); 180 | return NumberUtil.narrowBigInteger(left, right, result); 181 | } catch (Exception e) { 182 | return ObjectUtils.toString(left).concat(ObjectUtils.toString(right)); 183 | } 184 | } 185 | 186 | } 187 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/And.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import java.util.List; 4 | 5 | import com.greenpineyu.fel.common.Null; 6 | import com.greenpineyu.fel.common.NumberUtil; 7 | import com.greenpineyu.fel.compile.FelMethod; 8 | import com.greenpineyu.fel.compile.SourceBuilder; 9 | import com.greenpineyu.fel.context.FelContext; 10 | import com.greenpineyu.fel.exception.EvalException; 11 | import com.greenpineyu.fel.function.StableFunction; 12 | import com.greenpineyu.fel.function.TolerantFunction; 13 | import com.greenpineyu.fel.parser.FelNode; 14 | 15 | /** 16 | * 逻辑操作符 17 | */ 18 | public class And extends StableFunction { 19 | 20 | // private final String operator; 21 | // 22 | // private LogicalOperator(String operator) { 23 | // this.operator = operator; 24 | // } 25 | // 26 | // public static final String AND_STR = "AND"; 27 | // public static final String AND2_STR = "&&"; 28 | // public static final String OR_STR = "OR"; 29 | // public static final String OR2_STR = "||"; 30 | // 31 | // public static final LogicalOperator AND; 32 | // public static final LogicalOperator AND2; 33 | // public static final LogicalOperator OR; 34 | // public static final LogicalOperator OR2; 35 | // 36 | // static { 37 | // AND = new LogicalOperator(AND_STR); 38 | // AND2 = new LogicalOperator(AND2_STR); 39 | // OR = new LogicalOperator(OR_STR); 40 | // OR2 = new LogicalOperator(OR2_STR); 41 | // } 42 | 43 | public String toJavaOper() { 44 | // if (AND_STR.equals(this.getName())) { 45 | // return AND2_STR; 46 | // } 47 | // if (OR_STR.equals(this.getName())) { 48 | // return OR2_STR; 49 | // } 50 | return this.getName(); 51 | } 52 | 53 | @Override 54 | public Object call(FelNode node, FelContext context) { 55 | List children = node.getChildren(); 56 | if (children != null && children.size() == 2) { 57 | return logic(context,children); 58 | // Object[] c = children.toArray(); 59 | // if (this == AND || this == AND2) { 60 | // return and(context, c); 61 | // } else if (this == OR || this == OR2) { 62 | // return or(context, c); 63 | // } 64 | // throw new EvalException("未知的逻辑操作符"); 65 | } 66 | throw new EvalException("传入参数数组为空或者参数个数不正确!"); 67 | } 68 | 69 | /** 70 | * AND 和 && 71 | * 72 | * @param left 73 | * @param right 74 | * @return 75 | */ 76 | // private Boolean and(FelContext context, Object[] children) { 77 | // Boolean leftValue = toBoolean(context, children[0]); 78 | // if (!leftValue.booleanValue()) { 79 | // return leftValue; 80 | // } 81 | // return toBoolean(context, children[1]); 82 | // } 83 | 84 | /** 85 | * 求逻辑与(&&) 86 | * @param context 87 | * @param children 88 | * @return 89 | */ 90 | Boolean logic(FelContext context, List children) { 91 | Boolean leftValue = toBoolean(context, children.get(0)); 92 | if (!leftValue.booleanValue()) { 93 | return leftValue; 94 | } 95 | return toBoolean(context, children.get(1)); 96 | } 97 | 98 | // Boolean or(FelContext context, Object[] children) { 99 | // Boolean leftValue = toBoolean(context, children[0]); 100 | // if (leftValue.booleanValue()) { 101 | // return leftValue; 102 | // } 103 | // return toBoolean(context, children[1]); 104 | // } 105 | 106 | Boolean toBoolean(FelContext context, Object node) { 107 | node = TolerantFunction.eval(context, node); 108 | return NumberUtil.toBooleanObj(node); 109 | } 110 | 111 | /** 112 | * AND 和 && 113 | * 114 | * @param left 115 | * @param right 116 | * @return 117 | */ 118 | /* 119 | * private boolean and(Object left, Object right) { boolean l = 120 | * NumberUtil.toBoolean(left); if (!l) { return false; } boolean r = 121 | * NumberUtil.toBoolean(right); if (!r) { return false; } return true; } 122 | */ 123 | 124 | /** 125 | * OR 和 || 126 | * 127 | * @param left 128 | * @param right 129 | * @return 130 | */ 131 | /* 132 | * private boolean or(Object left, Object right) { boolean l = 133 | * NumberUtil.toBoolean(left); if (l) { return true; } boolean r = 134 | * NumberUtil.toBoolean(right); if (r) { return true; } return false; } 135 | */ 136 | 137 | @Override 138 | public String getName() { 139 | return "&&"; 140 | } 141 | 142 | @Override 143 | public FelMethod toMethod(FelNode node, FelContext ctx) { 144 | String code = toBoolean(node, ctx, 0)+this.toJavaOper()+toBoolean(node, ctx, 1); 145 | return new FelMethod(Boolean.class, code); 146 | // List children = node.getChildren(); 147 | // FelNode left = children.get(0); 148 | // FelNode right = children.get(1); 149 | // FelMethod lm = left.toMethod(ctx); 150 | // FelMethod rm = right.toMethod(ctx); 151 | // Class lt = lm.getReturnType(); 152 | // Class rt = rm.getReturnType(); 153 | // 154 | // return null; 155 | } 156 | 157 | public String toBoolean(FelNode node, FelContext ctx, int index) { 158 | List children = node.getChildren(); 159 | FelNode child = children.get(index); 160 | SourceBuilder method = child.toMethod(ctx); 161 | Class type = method.returnType(ctx, child); 162 | if (Boolean.class.isAssignableFrom(type)) { 163 | return "(" + method.source(ctx, child) + ")"; 164 | } 165 | if (String.class.isAssignableFrom(type)) { 166 | return "Boolean.valueOf(" + method.source(ctx, child) + ")"; 167 | } 168 | if (Null.class.isAssignableFrom(type)) { 169 | return "false"; 170 | } 171 | return "false"; 172 | } 173 | 174 | } -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/Cond.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import java.util.List; 4 | 5 | import com.greenpineyu.fel.FelEngine; 6 | import com.greenpineyu.fel.compile.FelMethod; 7 | import com.greenpineyu.fel.compile.SourceBuilder; 8 | import com.greenpineyu.fel.context.FelContext; 9 | import com.greenpineyu.fel.exception.ParseException; 10 | import com.greenpineyu.fel.function.StableFunction; 11 | import com.greenpineyu.fel.parser.FelNode; 12 | 13 | /** 14 | * 三元表达式操作符 15 | * 16 | * @author Administrator 17 | * 18 | */ 19 | public class Cond extends StableFunction { 20 | 21 | 22 | @Override 23 | public Object call(FelNode node, FelContext context) { 24 | List args = ensureValid(node); 25 | //cond ? result1 : result2 26 | FelNode cond = args.get(0); 27 | FelNode result1 = args.get(1); 28 | FelNode result2 = args.get(2); 29 | Object eval = cond.eval(context); 30 | // 当cond是boolean型,并且值是true的,返回result1,否则返回result2 31 | if(eval !=null && eval instanceof Boolean){ 32 | Boolean b = (Boolean)eval; 33 | if(b.booleanValue()){ 34 | return result1.eval(context); 35 | } 36 | } 37 | return result2.eval(context); 38 | } 39 | 40 | @Override 41 | public String getName() { 42 | return "?"; 43 | } 44 | 45 | @Override 46 | public SourceBuilder toMethod(FelNode node, FelContext ctx) { 47 | List args = ensureValid(node); 48 | //cond ? result1 : result2 49 | FelNode cond = args.get(0); 50 | FelNode result1 = args.get(1); 51 | FelNode result2 = args.get(2); 52 | SourceBuilder source = cond.toMethod(ctx); 53 | Class class1 = source.returnType(ctx, cond); 54 | StringBuilder sb = new StringBuilder(); 55 | Class type = null; 56 | SourceBuilder r2 = result2.toMethod(ctx); 57 | if(Boolean.class.isAssignableFrom(class1)|| boolean.class.isAssignableFrom(class1)){ 58 | // FIXME 需要判断两个结果中的父类型 59 | sb.append(source.source(ctx, node)); 60 | sb.append("?"); 61 | SourceBuilder r1 = result1.toMethod(ctx); 62 | type = r1.returnType(ctx, result1); 63 | sb.append(r1.source(ctx, result1)); 64 | sb.append(":"); 65 | sb.append(r2.source(ctx, result2)); 66 | }else{ 67 | sb.append(r2.source(ctx, result2)); 68 | type = r2.returnType(ctx, result2); 69 | } 70 | 71 | return new FelMethod(type, sb.toString()); 72 | } 73 | 74 | private List ensureValid(FelNode node) { 75 | List args = node.getChildren(); 76 | if(args==null||args.size()!=3){ 77 | throw new ParseException("不合法的三元表达式"); 78 | } 79 | return args; 80 | } 81 | 82 | public static void main(String[] args) { 83 | String exp = "true?false?2:3:2"; 84 | System.out.println(!(100%3-39.0<27)); 85 | // Object a =6.7-100>39.6 ? 5==5? 4+5:6-1 : !(100%3-39.0<27) ? 8*2-199: 86 | // 100%3; 87 | // System.out.println(a); 88 | exp = "6.7-100>39.6 ? 5==5? 4+5:6-1 : !(100%3-39.0<27) ? 8*2-199: 100%3"; 89 | eval(exp); 90 | } 91 | 92 | private static void eval(String exp) { 93 | FelEngine fel = FelEngine.instance; 94 | Object result = fel.eval(exp); 95 | System.out.println(result); 96 | result = fel.compile(exp, null).eval(null); 97 | System.out.println(result); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/Div.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import com.greenpineyu.fel.common.NumberUtil; 4 | 5 | public class Div extends Mul { 6 | 7 | @Override 8 | Object calc(double l, double r) { 9 | return NumberUtil.parseNumber(l / r); 10 | } 11 | 12 | @Override 13 | public String getName() { 14 | return "/"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/Equal.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.List; 5 | 6 | import com.greenpineyu.fel.common.Null; 7 | import com.greenpineyu.fel.common.NumberUtil; 8 | import com.greenpineyu.fel.common.ReflectUtil; 9 | import com.greenpineyu.fel.compile.FelMethod; 10 | import com.greenpineyu.fel.compile.SourceBuilder; 11 | import com.greenpineyu.fel.context.FelContext; 12 | import com.greenpineyu.fel.function.StableFunction; 13 | import com.greenpineyu.fel.function.TolerantFunction; 14 | import com.greenpineyu.fel.parser.FelNode; 15 | 16 | public class Equal extends StableFunction { 17 | 18 | public String getName() { 19 | return "=="; 20 | } 21 | 22 | public Object call(FelNode node, FelContext context) { 23 | List children = node.getChildren(); 24 | if (children != null && children.size() == 2) { 25 | Object left = TolerantFunction.eval(context, children.get(0)); 26 | Object right = TolerantFunction.eval(context, children.get(1)); 27 | return Boolean.valueOf(compare(left, right)); 28 | } 29 | throw new NullPointerException("传入参数数组为空或者参数个数不正确!"); 30 | } 31 | 32 | boolean compare(Object left, Object right) { 33 | return equals(left, right); 34 | } 35 | 36 | public static boolean equals(Object left, Object right) { 37 | if (left == null && right == null) { 38 | return true; 39 | } else if (left == null || right == null) { 40 | return false; 41 | } else if (left.getClass().equals(right.getClass())) { 42 | return left.equals(right); 43 | } else if (left instanceof BigDecimal || right instanceof BigDecimal) { 44 | return NumberUtil.toBigDecimal(left).compareTo( 45 | NumberUtil.toBigDecimal(right)) == 0; 46 | } else if (NumberUtil.isFloatingPointNumber(left) 47 | || NumberUtil.isFloatingPointNumber(right)) { 48 | return NumberUtil.toDouble(left) == NumberUtil.toDouble(right); 49 | } else if (left instanceof Number || right instanceof Number 50 | || left instanceof Character || right instanceof Character) { 51 | return NumberUtil.toLong(left) == NumberUtil.toLong(right); 52 | } else if (left instanceof Boolean || right instanceof Boolean) { 53 | return NumberUtil.toBoolean(left) == NumberUtil.toBoolean(right); 54 | } else if (left instanceof String || right instanceof String) { 55 | return left.toString().equals(right.toString()); 56 | } 57 | return left.equals(right); 58 | } 59 | 60 | public FelMethod toMethod(FelNode node, FelContext ctx) { 61 | String operator = this.getName(); 62 | return toMethod(node, ctx, operator); 63 | } 64 | 65 | private FelMethod toMethod(FelNode node, FelContext ctx, String operator) { 66 | StringBuilder sb = buildRelationExpr(node, ctx, operator); 67 | if(sb.length()==0){ 68 | String left = getChildCode(node, ctx,0); 69 | String right = getChildCode(node, ctx, 1); 70 | String toMethod = toMethod(left, right); 71 | sb.append(toMethod); 72 | } 73 | return new FelMethod(Boolean.class, sb.toString()); 74 | } 75 | 76 | String toMethod(String left, String right) { 77 | return "ObjectUtils.equals(" + left + "," + right + ")"; 78 | } 79 | 80 | public static String getChildCode(FelNode node, FelContext ctx,int index) { 81 | List children = node.getChildren(); 82 | FelNode child = children.get(index); 83 | SourceBuilder leftM = child.toMethod(ctx); 84 | String code = "(" + leftM.source(ctx, child) + ")"; 85 | return code; 86 | } 87 | 88 | public static StringBuilder buildRelationExpr(FelNode node, FelContext ctx, 89 | String operator) { 90 | List child = node.getChildren(); 91 | FelNode leftNode = child.get(0); 92 | FelNode rightNode = child.get(1); 93 | SourceBuilder leftM = leftNode.toMethod(ctx); 94 | SourceBuilder rightM = rightNode.toMethod(ctx); 95 | Class leftType = leftM.returnType(ctx, leftNode); 96 | Class rightType = rightM.returnType(ctx, rightNode); 97 | String left = "(" + leftM.source(ctx, leftNode) + ")"; 98 | String right = "(" +rightM.source(ctx, rightNode) + ")"; 99 | 100 | StringBuilder sb = new StringBuilder(); 101 | // 只要有一个是数值型,就将另一个也转成值型。 102 | if(ReflectUtil.isPrimitiveNumber(leftType)&&ReflectUtil.isPrimitiveNumber(leftType)){ 103 | //如果左右都是基本数值类型,直接==运算就行了。 104 | sb.append(left).append(operator).append(right); 105 | }else if (Number.class.isAssignableFrom(leftType)) { 106 | sb.append(left); 107 | sb.append(operator); 108 | appendNumber(rightType, right, sb); 109 | } else if (Number.class.isAssignableFrom(rightType)) { 110 | appendNumber(leftType, left, sb); 111 | sb.append(operator); 112 | sb.append(right); 113 | } else if (Boolean.class.isAssignableFrom(leftType)) { 114 | sb.append(left); 115 | sb.append(operator); 116 | appendBoolean(rightType, right, sb); 117 | } else if (Boolean.class.isAssignableFrom(rightType)) { 118 | appendBoolean(leftType, left, sb); 119 | sb.append(operator); 120 | sb.append(right); 121 | } else if (String.class.isAssignableFrom(leftType)) { 122 | sb.append("StringUtils.equals(" + left + ",ObjectUtils.toString(" 123 | + right + "))"); 124 | } else if (String.class.isAssignableFrom(rightType)) { 125 | sb.append("StringUtils.equals(ObjectUtils.toString(" + right + ")," 126 | + left + ")"); 127 | } 128 | return sb; 129 | } 130 | 131 | static public void appendNumber(Class type, String src, StringBuilder sb) { 132 | if (Number.class.isAssignableFrom(type)) { 133 | // 当type是数值型时,使用toString 134 | sb.append(src); 135 | } else if (String.class.isAssignableFrom(type)) { 136 | // 当type是字符型时,转成double型 137 | sb.append("NumberUtil.toDouble(" + src + ")"); 138 | } else if(Null.class.isAssignableFrom(type)){ 139 | sb.append("Double.MIN_VALUE"); 140 | }else{ 141 | // 当type是Object时,this.equals 142 | // FIXME 143 | } 144 | } 145 | 146 | static public void appendBoolean(Class type, String src, StringBuilder sb) { 147 | if (Boolean.class.isAssignableFrom(type)) { 148 | // 当type是Boolean时,使用toString 149 | sb.append(src); 150 | } else if (String.class.isAssignableFrom(type)) { 151 | // 当type是字符型时,转成double型 152 | sb.append("Boolean.valueOf(" + src + ")"); 153 | } else { 154 | // 当type是Object时,this.equals 155 | // FIXME 156 | } 157 | } 158 | 159 | 160 | } 161 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/GreaterThan.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import com.greenpineyu.fel.common.NumberUtil; 4 | 5 | public class GreaterThan extends LessThen { 6 | 7 | 8 | 9 | @Override 10 | public String getName() { 11 | return ">"; 12 | } 13 | 14 | /** 15 | * 大于 > 16 | * 17 | * @param left 18 | * @param right 19 | * @return 20 | */ 21 | public boolean compare(Object left, Object right) { 22 | if(left == right){ 23 | return false; 24 | } 25 | 26 | if(left == null || right == null){ 27 | return false; 28 | } 29 | 30 | if(left instanceof Number && right instanceof Number){ 31 | return NumberUtil.toDouble((Number)left)>NumberUtil.toDouble((Number)right); 32 | } 33 | 34 | if(left instanceof Comparable && right instanceof Comparable){ 35 | return ((Comparable)left).compareTo(right)>0; 36 | } 37 | // TODO 是返回false还是抛出异常? 38 | return false; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/GreaterThenEqual.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import com.greenpineyu.fel.common.NumberUtil; 4 | 5 | public class GreaterThenEqual extends LessThen { 6 | 7 | @Override 8 | public String getName() { 9 | return ">="; 10 | } 11 | 12 | /** 13 | * 大于等于 14 | * @see com.greenpineyu.fel.function.operator.RelationalOperator#compare(java.lang.Object, java.lang.Object) 15 | */ 16 | @Override 17 | public boolean compare(Object left, Object right) { 18 | if(left == right){ 19 | return true; 20 | } 21 | 22 | if(left == null || right == null){ 23 | return false; 24 | } 25 | 26 | if(left instanceof Number && right instanceof Number){ 27 | return NumberUtil.toDouble((Number)left)>=NumberUtil.toDouble((Number)right); 28 | } 29 | 30 | if(left instanceof Comparable && right instanceof Comparable){ 31 | return ((Comparable)left).compareTo(right)>=0; 32 | } 33 | // TODO 是返回false还是抛出异常? 34 | return false; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/LessThenEqual.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import com.greenpineyu.fel.common.NumberUtil; 4 | 5 | public class LessThenEqual extends LessThen { 6 | 7 | @Override 8 | public String getName() { 9 | return "<="; 10 | } 11 | 12 | /** 13 | * 小于等于 14 | * @see com.greenpineyu.fel.function.operator.RelationalOperator#compare(java.lang.Object, java.lang.Object) 15 | */ 16 | @Override 17 | public boolean compare(Object left, Object right) { 18 | if(left == right){ 19 | return true; 20 | } 21 | 22 | if(left == null || right == null){ 23 | return false; 24 | } 25 | 26 | if(left instanceof Number && right instanceof Number){ 27 | return NumberUtil.toDouble((Number)left)<=NumberUtil.toDouble((Number)right); 28 | } 29 | 30 | if(left instanceof Comparable && right instanceof Comparable){ 31 | return ((Comparable)left).compareTo(right)<=0; 32 | } 33 | // TODO 是返回false还是抛出异常? 34 | return false; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/Mod.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import com.greenpineyu.fel.common.NumberUtil; 4 | 5 | public class Mod extends Mul { 6 | 7 | @Override 8 | Object calc(double l, double r) { 9 | return NumberUtil.parseNumber(l % r); 10 | } 11 | 12 | @Override 13 | public String getName() { 14 | return "%"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/NotEqual.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | public class NotEqual extends Equal { 4 | 5 | @Override 6 | boolean compare(Object left, Object right) { 7 | return equals(left, right)==false; 8 | } 9 | 10 | @Override 11 | String toMethod(String left, String right) { 12 | return "ObjectUtils.notEqual(" + left + "," + right + ")"; 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return "!="; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/NotOper.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import java.util.List; 4 | 5 | import com.greenpineyu.fel.FelEngine; 6 | import com.greenpineyu.fel.compile.SourceBuilder; 7 | import com.greenpineyu.fel.context.FelContext; 8 | import com.greenpineyu.fel.function.StableFunction; 9 | import com.greenpineyu.fel.parser.FelNode; 10 | 11 | /** 12 | * 取反操作符 13 | * 14 | */ 15 | public class NotOper extends StableFunction { 16 | 17 | 18 | @Override 19 | public Object call(FelNode node, FelContext context) { 20 | List children = node.getChildren(); 21 | Object eval = children.get(0).eval(context); 22 | if(eval!=null && eval instanceof Boolean){ 23 | return !(Boolean)eval; 24 | } 25 | return null; 26 | } 27 | 28 | @Override 29 | public String getName() { 30 | return "!"; 31 | } 32 | 33 | @Override 34 | public SourceBuilder toMethod(FelNode node, FelContext ctx) { 35 | return new SourceBuilder() { 36 | 37 | @Override 38 | public String source(FelContext ctx, FelNode node) { 39 | List children = node.getChildren(); 40 | FelNode child = children.get(0); 41 | String src = ""; 42 | SourceBuilder builder = child.toMethod(ctx); 43 | Class returnType = builder.returnType(ctx, child); 44 | if(boolean.class.isAssignableFrom(returnType)||Boolean.class.isAssignableFrom(returnType)){ 45 | src = "!("+builder.source(ctx, child)+")"; 46 | }else{ 47 | // FIXME 抛出编译异常 48 | } 49 | return src; 50 | } 51 | 52 | @Override 53 | public Class returnType(FelContext ctx, FelNode node) { 54 | return Boolean.class; 55 | } 56 | }; 57 | } 58 | 59 | public static void main(String[] args) { 60 | FelEngine fel = FelEngine.instance; 61 | FelContext ctx = fel.getContext(); 62 | ctx.set("b", false); 63 | Object r = fel.compile("!b",ctx).eval(ctx); 64 | System.out.println(r); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/Or.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import java.util.List; 4 | 5 | import com.greenpineyu.fel.context.FelContext; 6 | import com.greenpineyu.fel.parser.FelNode; 7 | 8 | public class Or extends And { 9 | 10 | /** 11 | * 求逻辑或(||) 12 | * @see com.greenpineyu.fel.function.operator.And#logic(com.greenpineyu.fel.context.FelContext, java.util.List) 13 | */ 14 | Boolean logic(FelContext context, List children) { 15 | Boolean leftValue = toBoolean(context, children.get(0)); 16 | if (leftValue.booleanValue()) { 17 | return leftValue; 18 | } 19 | return toBoolean(context, children.get(1)); 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return "||"; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/function/operator/Sub.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.function.operator; 2 | 3 | import java.util.List; 4 | 5 | import com.greenpineyu.fel.common.NumberUtil; 6 | import com.greenpineyu.fel.common.ReflectUtil; 7 | import com.greenpineyu.fel.compile.FelMethod; 8 | import com.greenpineyu.fel.compile.SourceBuilder; 9 | import com.greenpineyu.fel.context.FelContext; 10 | import com.greenpineyu.fel.exception.CompileException; 11 | import com.greenpineyu.fel.exception.EvalException; 12 | import com.greenpineyu.fel.function.StableFunction; 13 | import com.greenpineyu.fel.parser.FelNode; 14 | 15 | public class Sub extends StableFunction { 16 | 17 | 18 | private void appendArg(StringBuilder sb, SourceBuilder argMethod,FelContext ctx,FelNode node) { 19 | Class t = argMethod.returnType(ctx, node); 20 | sb.append("("); 21 | if (ReflectUtil.isPrimitiveOrWrapNumber(t)) { 22 | // 数值型和字符型时,直接添加 23 | sb.append(argMethod.source(ctx, node)); 24 | } else if (CharSequence.class.isAssignableFrom(t)) { 25 | // FIXME 处理1-"1"的 26 | } 27 | sb.append(")"); 28 | } 29 | 30 | public FelMethod toMethod(FelNode node, FelContext ctx) { 31 | List children = node.getChildren(); 32 | StringBuilder sb = new StringBuilder(); 33 | Class type = null; 34 | if (children.size() == 2) { 35 | //left 36 | FelNode left = children.get(0); 37 | SourceBuilder lm = left.toMethod(ctx); 38 | Class leftType = lm.returnType(ctx, left); 39 | appendArg(sb, lm,ctx,left); 40 | 41 | //right 42 | FelNode right = children.get(1); 43 | SourceBuilder rm = right.toMethod(ctx); 44 | Class rightType = rm.returnType(ctx, right); 45 | sb.append("-"); 46 | appendArg(sb, rm,ctx,right); 47 | 48 | //returnType 49 | if(ReflectUtil.isPrimitiveOrWrapNumber(leftType) 50 | &&ReflectUtil.isPrimitiveOrWrapNumber(rightType)){ 51 | type = NumberUtil.arithmeticClass(leftType, rightType); 52 | }else{ 53 | throw new CompileException("不支持的类型["+ReflectUtil.getClassName(leftType) 54 | +"、"+ReflectUtil.getClassName(rightType)+"]。减[-]运算只支持数值类型"); 55 | } 56 | } else if (children.size() == 1) { 57 | FelNode right = children.get(0); 58 | SourceBuilder rm = right.toMethod(ctx); 59 | Class rightType = rm.returnType(ctx, right); 60 | sb.append("-"); 61 | appendArg(sb, rm,ctx,right); 62 | if(ReflectUtil.isPrimitiveOrWrapNumber(rightType)){ 63 | type = rightType; 64 | } 65 | } 66 | // sb.append("-"); 67 | // SourceBuilder rm = right.toMethod(ctx); 68 | // appendArg(sb, rm,ctx,right); 69 | FelMethod m = new FelMethod(type, sb.toString()); 70 | return m; 71 | } 72 | 73 | public String getName() { 74 | return "-"; 75 | } 76 | 77 | public Object call(FelNode node, FelContext context) { 78 | List children = node.getChildren(); 79 | if (children.size() == 2) { 80 | FelNode left = children.get(0); 81 | Object leftValue = left.eval(context); 82 | FelNode right = children.get(1); 83 | Object rightValue = right.eval(context); 84 | if (leftValue instanceof Number && rightValue instanceof Number) { 85 | double l = NumberUtil.toDouble(leftValue); 86 | double r = NumberUtil.toDouble(rightValue); 87 | return NumberUtil.parseNumber(l - r); 88 | // if (NumberUtil.isFloatingPoint(left) 89 | // || NumberUtil.isFloatingPoint(right)) { 90 | // } 91 | // return NumberUtil.parseNumber(((Number) leftValue).longValue() 92 | // - ((Number) rightValue).longValue()); 93 | } 94 | throw new EvalException("执行减法出错,参数必须是数值型"); 95 | } 96 | if (children.size() == 1) { 97 | FelNode right = children.get(0); 98 | Object rightValue = right.eval(context); 99 | if (rightValue instanceof Number) { 100 | if (NumberUtil.isFloatingPoint(rightValue)) { 101 | return NumberUtil.toDouble(rightValue) * -1; 102 | } 103 | return NumberUtil.parseNumber(((Number) rightValue).longValue() * -1); 104 | } 105 | throw new EvalException("执行减法出错,参数必须是数值型"); 106 | } 107 | throw new EvalException("执行减法出错,参数长度必须是1或2"); 108 | } 109 | 110 | public static void main(String[] args) { 111 | int a = -(1); 112 | System.out.println(a); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/interpreter/ConstInterpreter.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.interpreter; 2 | 3 | import com.greenpineyu.fel.context.FelContext; 4 | import com.greenpineyu.fel.parser.FelNode; 5 | 6 | public class ConstInterpreter implements Interpreter { 7 | 8 | private Object value; 9 | 10 | public ConstInterpreter(FelContext context, FelNode node) { 11 | this.value = node.eval(context); 12 | } 13 | 14 | public Object interpret(FelContext context, FelNode node) { 15 | return value; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/interpreter/Interpreter.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.interpreter; 2 | 3 | import com.greenpineyu.fel.context.FelContext; 4 | import com.greenpineyu.fel.parser.FelNode; 5 | 6 | /** 7 | * 解析器,用于解析AstNode的值 8 | * @author yqs 9 | * 10 | */ 11 | public interface Interpreter { 12 | 13 | /** 14 | * @param context 15 | * @return 16 | */ 17 | Object interpret(FelContext context, FelNode node); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/interpreter/ProxyInterpreter.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.interpreter; 2 | 3 | import com.greenpineyu.fel.context.FelContext; 4 | import com.greenpineyu.fel.parser.FelNode; 5 | 6 | /** 7 | * 代理解释器,用于保存节点 8 | * @author yuqingsong 9 | * 10 | */ 11 | public class ProxyInterpreter implements Interpreter{ 12 | 13 | private Interpreter inte; 14 | 15 | private FelNode node; 16 | public ProxyInterpreter(Interpreter inte,FelNode node){ 17 | this.inte = inte; 18 | this.node = node; 19 | } 20 | public Object interpret(FelContext context, FelNode node) { 21 | return inte.interpret(context, this.node); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/optimizer/ConstExpOpti.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.optimizer; 2 | 3 | import com.greenpineyu.fel.common.Null; 4 | import com.greenpineyu.fel.common.ReflectUtil; 5 | import com.greenpineyu.fel.compile.SourceBuilder; 6 | import com.greenpineyu.fel.compile.VarBuffer; 7 | import com.greenpineyu.fel.context.FelContext; 8 | import com.greenpineyu.fel.parser.ConstNode; 9 | import com.greenpineyu.fel.parser.FelNode; 10 | 11 | /** 12 | * 当表达式是常量表达式,对表达式进行优化。 13 | * 14 | * @author yuqingsong 15 | * 16 | */ 17 | public class ConstExpOpti implements Optimizer { 18 | 19 | @Override 20 | public FelNode call(FelContext ctx, FelNode node) { 21 | if (node instanceof ConstNode) { 22 | final Object value = node.eval(ctx); 23 | 24 | // 重新构建常量节点的java源码 25 | node.setSourcebuilder(new SourceBuilder() { 26 | 27 | @Override 28 | public String source(FelContext ctx, FelNode node) { 29 | // Class type = returnType(ctx, node); 30 | return VarBuffer.push(value, Object.class); 31 | } 32 | 33 | @Override 34 | public Class returnType(FelContext ctx, FelNode node) { 35 | if (value != null) { 36 | Class cls = value.getClass(); 37 | if (cls.isPrimitive()) { 38 | return ReflectUtil.toWrapperClass(cls); 39 | } 40 | return cls; 41 | } 42 | return Null.class; 43 | } 44 | }); 45 | } 46 | return node; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/optimizer/ConstOpti.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.optimizer; 2 | 3 | import java.util.List; 4 | 5 | import org.antlr.runtime.CommonToken; 6 | import org.antlr.runtime.Token; 7 | 8 | import com.greenpineyu.fel.context.FelContext; 9 | import com.greenpineyu.fel.function.Function; 10 | import com.greenpineyu.fel.function.operator.And; 11 | import com.greenpineyu.fel.function.operator.Or; 12 | import com.greenpineyu.fel.parser.ConstNode; 13 | import com.greenpineyu.fel.parser.FelNode; 14 | import com.greenpineyu.fel.parser.FunNode; 15 | 16 | /** 17 | * 常量节点优化,优化表达式中的常量部分。 18 | * 表达式:"1+2+var",当var是变量时,可以优化成"3+var";当var是常量,其值为3时,可以优化成"6" 19 | * 20 | * @author yuqingsong 21 | * 22 | */ 23 | public class ConstOpti implements Optimizer { 24 | 25 | 26 | @Override 27 | public FelNode call(FelContext ctx, FelNode node) { 28 | if(node.stable()){ 29 | Object value = node.getInterpreter().interpret(ctx, node); 30 | return newConstNode(node, value); 31 | }else{ 32 | List children = node.getChildren(); 33 | if (children != null) { 34 | // 是否进行过短路优化 35 | boolean isLogicOptimized = false; 36 | if (node instanceof FunNode) { 37 | FunNode n = (FunNode) node; 38 | Function fun = n.getFun(); 39 | if (fun instanceof And) { 40 | List args = node.getChildren(); 41 | FelNode left = args.get(0); 42 | FelNode right = args.get(1); 43 | boolean isOr = fun instanceof Or; 44 | // 短路的判断值,or使用True来判断,and使用false来判断 45 | Boolean result = isOr; 46 | // if (isOr) { 47 | FelNode constNode = toShortCutConst(node, ctx, left, 48 | result); 49 | if (constNode != null) { 50 | return constNode; 51 | } 52 | constNode = toShortCutConst(node, ctx, right, result); 53 | if (constNode != null) { 54 | return constNode; 55 | } 56 | // else if (right.stable()) { 57 | // Object rightValue = node.getInterpreter() 58 | // .interpret(ctx, right); 59 | // if (result.equals(right)) { 60 | // isLogicOptimized = true; 61 | // return newConstNode(node, rightValue); 62 | // } 63 | // } 64 | // }else{ 65 | // if(left.stable()){ 66 | // Object leftValue = 67 | // node.getInterpreter().interpret(ctx, 68 | // left); 69 | // if (Boolean.FALSE.equals(leftValue)) { 70 | // children.remove(1); 71 | // children.set(0, newConstNode(left, leftValue)); 72 | // } 73 | // }else if(right.stable()){ 74 | // Object rightValue = 75 | // node.getInterpreter().interpret(ctx, 76 | // right); 77 | // if(Boolean.FALSE.equals(right)) { 78 | // children.remove(1); 79 | // children.set(0, newConstNode(right, rightValue)); 80 | // } 81 | // } 82 | // } 83 | } 84 | } 85 | if (!isLogicOptimized) { 86 | for (int i = 0; i < children.size(); i++) { 87 | FelNode c = children.get(i); 88 | children.set(i, this.call(ctx, c)); 89 | } 90 | } 91 | } 92 | return node; 93 | } 94 | } 95 | 96 | 97 | private FelNode toShortCutConst(FelNode node, FelContext ctx, FelNode left, 98 | Boolean result) { 99 | FelNode constNode = null; 100 | if (left.stable()) { 101 | Object leftValue = node.getInterpreter().interpret(ctx, left); 102 | if (result.equals(leftValue)) { 103 | constNode = newConstNode(node, leftValue); 104 | } 105 | } 106 | return constNode; 107 | } 108 | 109 | @SuppressWarnings("unused") 110 | private void setConstValue(List children, FelNode left, 111 | Object leftValue) { 112 | children.remove(1); 113 | children.set(0, newConstNode(left, leftValue)); 114 | } 115 | 116 | 117 | private FelNode newConstNode(FelNode node, Object value) { 118 | Token token = new ConstOptToken(node); 119 | token.setText(node.getText()); 120 | return new ConstNode(token, value); 121 | } 122 | 123 | } 124 | 125 | /** 126 | * 常量节点,用于保存原节点 127 | * 128 | * @author yuqingsong 129 | * 130 | */ 131 | @SuppressWarnings("serial") 132 | class ConstOptToken extends CommonToken{ 133 | @SuppressWarnings("unused") 134 | private final FelNode node; 135 | ConstOptToken(FelNode node){ 136 | super(-1,node.getText()); 137 | this.node = node; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/optimizer/Interpreters.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.optimizer; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import com.greenpineyu.fel.context.FelContext; 8 | import com.greenpineyu.fel.interpreter.Interpreter; 9 | import com.greenpineyu.fel.parser.AbstFelNode; 10 | import com.greenpineyu.fel.parser.FelNode; 11 | 12 | 13 | /** 14 | * 设置节点的解释器 15 | * @author yuqingsong 16 | * 17 | */ 18 | public class Interpreters implements Optimizer { 19 | 20 | private Map inteMap; 21 | { 22 | inteMap = new HashMap(); 23 | } 24 | public FelNode call(FelContext ctx,FelNode node) { 25 | List nodes = AbstFelNode.getNodes(node); 26 | for (FelNode n : nodes) { 27 | String text = n.getText(); 28 | Interpreter inte = inteMap.get(text); 29 | if(inte!=null){ 30 | n.setInterpreter(inte); 31 | } 32 | } 33 | return node; 34 | } 35 | 36 | public void add(String name,Interpreter inter){ 37 | inteMap.put(name, inter); 38 | } 39 | 40 | public static void main(String[] args) { 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/optimizer/Optimizer.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.optimizer; 2 | 3 | import com.greenpineyu.fel.context.FelContext; 4 | import com.greenpineyu.fel.parser.FelNode; 5 | 6 | /** 7 | * 优化器 8 | * @author yuqingsong 9 | * 10 | */ 11 | public interface Optimizer { 12 | 13 | 14 | FelNode call(FelContext ctx, FelNode node); 15 | } 16 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/optimizer/VarVisitOpti.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.optimizer; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import com.greenpineyu.fel.compile.InterpreterSourceBuilder; 7 | import com.greenpineyu.fel.compile.SourceBuilder; 8 | import com.greenpineyu.fel.compile.SourceGeneratorImpl; 9 | import com.greenpineyu.fel.compile.VarBuffer; 10 | import com.greenpineyu.fel.context.FelContext; 11 | import com.greenpineyu.fel.context.MapContext; 12 | import com.greenpineyu.fel.context.Var; 13 | import com.greenpineyu.fel.interpreter.Interpreter; 14 | import com.greenpineyu.fel.parser.AbstFelNode; 15 | import com.greenpineyu.fel.parser.FelNode; 16 | import com.greenpineyu.fel.parser.VarAstNode; 17 | 18 | /** 19 | * 对访问节点进行优化,直接从Var中取变量 20 | * 21 | * @author yuqingsong 22 | * 23 | */ 24 | public class VarVisitOpti implements Optimizer { 25 | 26 | /** 27 | * 用于保存变量 28 | */ 29 | private Map varMap; 30 | 31 | 32 | public VarVisitOpti(Var... vars) { 33 | varMap = new MapContext(); 34 | if (vars != null) { 35 | for (Var var : vars) { 36 | if (var != null) { 37 | varMap.put(var.getName(), var); 38 | } 39 | } 40 | } 41 | } 42 | 43 | public VarVisitOpti() { 44 | } 45 | 46 | @Override 47 | public FelNode call(FelContext ctx, FelNode node) { 48 | List nodes = AbstFelNode.getNodes(node, 49 | SourceGeneratorImpl.varsFilter); 50 | for (FelNode varNode : nodes) { 51 | if (varNode instanceof VarAstNode) { 52 | final VarAstNode n = (VarAstNode) varNode; 53 | if (n.isDefaultInterpreter()) { 54 | // 当解释器是自身时,才能进行优化 55 | // 要先设置解释器,原因是createSourceBuilder会使用解释器。 56 | n.setInterpreter(createInterpreter()); 57 | n.setSourcebuilder(createVarSourceBuilder(n)); 58 | } 59 | } 60 | } 61 | return node; 62 | } 63 | 64 | private Interpreter createInterpreter() { 65 | return new Interpreter() { 66 | @Override 67 | public Object interpret(FelContext context, FelNode node) { 68 | Var var = getVar(context, node); 69 | return var != null ? var.getValue() : null; 70 | } 71 | }; 72 | } 73 | 74 | private SourceBuilder createVarSourceBuilder(final VarAstNode n) { 75 | return new SourceBuilder() { 76 | 77 | private String src = null; 78 | private Class returnType = null; 79 | 80 | @Override 81 | public String source(FelContext ctx, FelNode node) { 82 | if (src == null) { 83 | Var var = getVar(ctx, node); 84 | String varFieldName = VarBuffer.push(var); 85 | Class type = returnType(ctx, node); 86 | src = VarAstNode.getVarFullCode(type, varFieldName 87 | + ".getValue()"); 88 | } 89 | return src; 90 | } 91 | 92 | @Override 93 | public Class returnType(FelContext ctx, FelNode node) { 94 | if(returnType == null){ 95 | returnType = InterpreterSourceBuilder.getInstance() 96 | .returnType(ctx, node); 97 | } 98 | return returnType; 99 | } 100 | }; 101 | } 102 | 103 | private Var getVar(FelContext context, FelNode node) { 104 | Var var = null; 105 | if (varMap != null) { 106 | var = varMap.get(node.getText()); 107 | } 108 | if (var == null) { 109 | // 如果varMap中没有节点,从context中取。 110 | var = context.getVar(node.getText()); 111 | } 112 | return var; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/AbstFelNode.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import org.antlr.runtime.Token; 8 | import org.antlr.runtime.tree.CommonTree; 9 | import org.antlr.runtime.tree.Tree; 10 | 11 | import com.greenpineyu.fel.common.Callable; 12 | import com.greenpineyu.fel.compile.SourceBuilder; 13 | import com.greenpineyu.fel.context.FelContext; 14 | import com.greenpineyu.fel.interpreter.Interpreter; 15 | 16 | public abstract class AbstFelNode extends CommonTree implements FelNode, Interpreter { 17 | 18 | /** 19 | * 解析器,用于解析节点的值 20 | */ 21 | protected Interpreter interpreter; 22 | 23 | /** 24 | * 默认的解析器 25 | */ 26 | protected Interpreter defaultInter; 27 | 28 | 29 | protected SourceBuilder builder; 30 | 31 | @Override 32 | @SuppressWarnings("unchecked") 33 | public List getChildren() { 34 | return this.children; 35 | } 36 | 37 | public AbstFelNode(Token token) { 38 | super(token); 39 | } 40 | 41 | public AbstFelNode() { 42 | 43 | } 44 | 45 | { 46 | // 解释器设置成this 47 | this.defaultInter = this; 48 | resetInterpreter(); 49 | // 源码构建器设置成this 50 | // resetSourceBuilder(); 51 | } 52 | 53 | 54 | @SuppressWarnings("unchecked") 55 | public AbstFelNode(CommonTree node) { 56 | super(node); 57 | if (node.getChildren() != null) { 58 | this.children = new ArrayList(node.getChildren()); 59 | for (int i = 0; i < this.children.size(); i++) { 60 | Tree object = (Tree) this.children.get(i); 61 | object.setParent(this); 62 | } 63 | } 64 | } 65 | 66 | 67 | @Override 68 | public String toString() { 69 | return this.getText(); 70 | } 71 | 72 | 73 | 74 | 75 | public void setChild(int index, FelNode node) { 76 | if (node instanceof Tree) { 77 | super.setChild(index, node); 78 | } else { 79 | throw new IllegalArgumentException("类型必须是" + Tree.class); 80 | } 81 | 82 | } 83 | 84 | 85 | 86 | @Override 87 | public Object eval(FelContext context) { 88 | return interpreter.interpret(context, this); 89 | // if (cached) { 90 | // return cacheValue; 91 | // } 92 | // Object eval = interpreter.interpret(context, this); 93 | // if (fixed) { 94 | // cacheValue = eval; 95 | // cached = true; 96 | // } 97 | // return eval; 98 | } 99 | 100 | // abstract public Object evalWithoutCache(FelContext context); 101 | 102 | 103 | public static List getNodes(FelNode node) { 104 | List returnMe = new ArrayList(); 105 | getNodes(node, returnMe,null); 106 | return returnMe; 107 | } 108 | 109 | public static List getNodes(FelNode node,Callable filter) { 110 | List returnMe = new ArrayList(); 111 | getNodes(node, returnMe, filter); 112 | return returnMe; 113 | } 114 | 115 | public static void getNodes(FelNode node, List returnMe,Callable filter) { 116 | if (node != null) { 117 | if(filter==null){ 118 | returnMe.add(node); 119 | }else if (filter.call(node)) { 120 | returnMe.add(node); 121 | } 122 | List nodeChildren = node.getChildren(); 123 | if (nodeChildren != null) { 124 | for (Iterator iterator = nodeChildren.iterator(); iterator.hasNext();) { 125 | try { 126 | FelNode child = iterator.next(); 127 | getNodes(child, returnMe, filter); 128 | } catch (Exception e) { 129 | e.printStackTrace(); 130 | } 131 | } 132 | } 133 | } 134 | } 135 | 136 | 137 | @Override 138 | public Interpreter getInterpreter() { 139 | return this.interpreter; 140 | } 141 | 142 | @Override 143 | public void setInterpreter(Interpreter interpreter) { 144 | this.interpreter = interpreter; 145 | } 146 | 147 | @Override 148 | public void resetInterpreter() { 149 | this.interpreter = this.defaultInter; 150 | } 151 | 152 | /** 153 | * 是否默认的解释器 154 | * 155 | * @return 156 | */ 157 | @Override 158 | public boolean isDefaultInterpreter(){ 159 | return this.interpreter == this.defaultInter; 160 | } 161 | 162 | 163 | 164 | @Override 165 | public Object interpret(FelContext context, FelNode node) { 166 | throw new UnsupportedOperationException("还没有实现[2011-1-13]"); 167 | } 168 | 169 | @Override 170 | public SourceBuilder toMethod(FelContext ctx){ 171 | return this.builder; 172 | } 173 | 174 | @Override 175 | public void setSourcebuilder(SourceBuilder builder) { 176 | this.builder = builder; 177 | } 178 | 179 | @Override 180 | public boolean stable() { 181 | return false; 182 | } 183 | 184 | public boolean isChildrenStable() { 185 | if(this.children!=null){ 186 | // 子节点有一个不是稳定的,就返回false 187 | for (int i = 0; i < children.size(); i++) { 188 | FelNode child = (FelNode) children.get(i); 189 | if(!child.stable()){ 190 | return false; 191 | } 192 | } 193 | } 194 | return true; 195 | } 196 | 197 | 198 | // public void resetSourceBuilder(){ 199 | // this.builder = this; 200 | // } 201 | 202 | 203 | } 204 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/AbstFelParser.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | 4 | import org.antlr.runtime.Parser; 5 | import org.antlr.runtime.RecognitionException; 6 | import org.antlr.runtime.RecognizerSharedState; 7 | import org.antlr.runtime.TokenStream; 8 | 9 | import com.greenpineyu.fel.exception.ParseException; 10 | 11 | public abstract class AbstFelParser extends Parser { 12 | public void emitErrorMessage(String msg) { 13 | throw new ParseException(msg); 14 | } 15 | 16 | public AbstFelParser(TokenStream input) { 17 | super(input); 18 | } 19 | 20 | public AbstFelParser(TokenStream input, RecognizerSharedState state) { 21 | super(input, state); 22 | } 23 | 24 | public void displayRecognitionError(String tokenNames[], RecognitionException e) { 25 | String hdr = getErrorHeader(e); 26 | String msg = getErrorMessage(e, tokenNames); 27 | emitErrorMessage("解析表达式[" + e.input.toString() + "]出错:" + hdr + " " + msg); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/AntlrParser.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.IOException; 5 | import java.util.List; 6 | 7 | import org.antlr.runtime.ANTLRInputStream; 8 | import org.antlr.runtime.CommonTokenStream; 9 | import org.antlr.runtime.ParserRuleReturnScope; 10 | import org.antlr.runtime.RecognitionException; 11 | import org.antlr.runtime.tree.CommonTree; 12 | 13 | import com.greenpineyu.fel.FelEngine; 14 | import com.greenpineyu.fel.common.Callable; 15 | import com.greenpineyu.fel.exception.ParseException; 16 | import com.greenpineyu.fel.function.operator.Dot; 17 | 18 | /** 19 | * 使用Antlr进行语法分析 20 | * @author yuqingsong 21 | * 22 | */ 23 | public class AntlrParser implements Parser { 24 | 25 | public static final Callable funFilter = new Callable() { 26 | @Override 27 | public Boolean call(FelNode... node) { 28 | FelNode n = node[0]; 29 | if(n == null){ 30 | return false; 31 | } 32 | boolean isFun = n instanceof FunNode; 33 | if(isFun){ 34 | if (n instanceof CommonTree) { 35 | CommonTree treeNode = (CommonTree) n; 36 | CommonTree p = treeNode.parent; 37 | if(p!=null){ 38 | if(Dot.DOT.equals(p.getText())){ 39 | // 点运算符后的函数节点不是真正意义上的变量节点。 40 | isFun = p.getChildren().get(0)==n; 41 | } 42 | } 43 | } 44 | } 45 | return isFun; 46 | } 47 | }; 48 | 49 | private FelEngine engine; 50 | 51 | public AntlrParser(FelEngine engine){ 52 | this.engine = engine; 53 | } 54 | 55 | public FelNode parse(String exp) { 56 | if (exp == null || "".equals(exp)) { 57 | return null; 58 | } 59 | ByteArrayInputStream is = new ByteArrayInputStream(exp.getBytes()); 60 | ANTLRInputStream input = null; 61 | try { 62 | input = new ANTLRInputStream(is); 63 | } catch (IOException e) { 64 | e.printStackTrace(); 65 | } 66 | FelLexer lexer = new FelLexer(input); 67 | CommonTokenStream tokens = new CommonTokenStream(lexer); 68 | FelParser parser = new FelParser(tokens); 69 | parser.setTreeAdaptor(new NodeAdaptor()); 70 | ParserRuleReturnScope r = null; 71 | try { 72 | r = parser.program(); 73 | } catch (RecognitionException e) { 74 | throw new ParseException(e.getMessage(), e); 75 | } 76 | if (r != null) { 77 | Object tree = r.getTree(); 78 | if (tree instanceof FelNode) { 79 | initFun((FelNode)tree); 80 | return (FelNode) tree; 81 | } 82 | } 83 | return null; 84 | } 85 | 86 | public void initFun(FelNode node){ 87 | List nodes = AbstFelNode.getNodes(node, funFilter); 88 | if(nodes!=null){ 89 | for (FelNode n : nodes) { 90 | FunNode funNode = (FunNode)n; 91 | funNode.initFun(this.engine.getFunMgr()); 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/ConstNode.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | import org.antlr.runtime.Token; 4 | 5 | import com.greenpineyu.fel.common.Null; 6 | import com.greenpineyu.fel.common.ReflectUtil; 7 | import com.greenpineyu.fel.compile.FelMethod; 8 | import com.greenpineyu.fel.compile.InterpreterSourceBuilder; 9 | import com.greenpineyu.fel.compile.SourceBuilder; 10 | import com.greenpineyu.fel.compile.VarBuffer; 11 | import com.greenpineyu.fel.context.FelContext; 12 | 13 | /** 14 | * 常量节点 15 | * 16 | * @author yqs 17 | * 18 | */ 19 | public class ConstNode extends AbstFelNode { 20 | 21 | private Object value; 22 | 23 | public ConstNode(Token token, Object value) { 24 | super(token); 25 | this.value = value; 26 | } 27 | 28 | public Object interpret(FelContext context, FelNode node) { 29 | return value; 30 | } 31 | 32 | public SourceBuilder toMethod(FelContext ctx) { 33 | if (this.builder != null) { 34 | return this.builder; 35 | } 36 | if (!this.isDefaultInterpreter()) { 37 | return InterpreterSourceBuilder.getInstance(); 38 | } 39 | return new FelMethod(this.getValueType(), this.toJavaSrc(ctx)); 40 | } 41 | 42 | public Class getValueType() { 43 | Class t = null; 44 | if (value == null) { 45 | t = Null.class; 46 | } else { 47 | t = value.getClass(); 48 | } 49 | return t; 50 | } 51 | 52 | public String toJavaSrc(FelContext ctx) { 53 | if (value == null) { 54 | return "null"; 55 | } 56 | if (value instanceof String) { 57 | return "\"" + value + "\""; 58 | } 59 | if (ReflectUtil.isPrimitiveOrWrapNumber(getValueType())) { 60 | return value.toString(); 61 | } 62 | return VarBuffer.push(value); 63 | } 64 | 65 | public boolean stable() { 66 | return true; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/FelNode.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | import java.util.List; 4 | 5 | import org.antlr.runtime.tree.Tree; 6 | 7 | import com.greenpineyu.fel.Expression; 8 | import com.greenpineyu.fel.compile.SourceBuilder; 9 | import com.greenpineyu.fel.context.FelContext; 10 | import com.greenpineyu.fel.interpreter.Interpreter; 11 | 12 | /** 13 | * 解析后的节点,组成表达式的元素都会被解析成节点。 14 | * @author yqs 15 | * 16 | */ 17 | public interface FelNode extends Expression, Tree ,Stable{ 18 | 19 | /** 20 | * 获取子节点 21 | */ 22 | List getChildren(); 23 | 24 | /** 25 | * 重置解释器 26 | * @return 27 | */ 28 | 29 | void resetInterpreter(); 30 | 31 | /** 32 | * 节点中的解释器是否默认的解释器 33 | * @return 34 | */ 35 | boolean isDefaultInterpreter(); 36 | 37 | Interpreter getInterpreter(); 38 | 39 | void setInterpreter(Interpreter interpreter); 40 | 41 | void setSourcebuilder(SourceBuilder builder); 42 | 43 | 44 | SourceBuilder toMethod(FelContext ctx); 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/FunNode.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | import org.antlr.runtime.Token; 4 | import org.antlr.runtime.tree.CommonTree; 5 | 6 | import com.greenpineyu.fel.compile.FelMethod; 7 | import com.greenpineyu.fel.compile.InterpreterSourceBuilder; 8 | import com.greenpineyu.fel.compile.SourceBuilder; 9 | import com.greenpineyu.fel.context.FelContext; 10 | import com.greenpineyu.fel.exception.EvalException; 11 | import com.greenpineyu.fel.function.Function; 12 | import com.greenpineyu.fel.function.FunMgr; 13 | 14 | /** 15 | * 函数节点 16 | * 17 | * @author yqs 18 | * 19 | */ 20 | public class FunNode extends AbstFelNode { 21 | private Function fun; 22 | 23 | public Function getFun() { 24 | return fun; 25 | } 26 | 27 | private static final Function NOT_FOUND_FUN = new Function() { 28 | 29 | @Override 30 | public String getName() { 31 | return "未知函数"; 32 | } 33 | 34 | @Override 35 | public Object call(FelNode node, FelContext context) { 36 | throw new EvalException("找不到函数[" + node.getText() + "]", null); 37 | } 38 | 39 | @Override 40 | public FelMethod toMethod(FelNode node, FelContext ctx) { 41 | return null; 42 | } 43 | }; 44 | 45 | public FunNode(CommonTree node) { 46 | super(node); 47 | } 48 | 49 | public FunNode(Token token) { 50 | super(token); 51 | 52 | } 53 | 54 | // { 55 | // initFun(); 56 | // } 57 | 58 | @Override 59 | public Object interpret(FelContext context, FelNode node) { 60 | return fun.call(this, context); 61 | } 62 | 63 | 64 | public void initFun(FunMgr funMgr) { 65 | fun = funMgr.getFun(getText()); 66 | if (fun == null) { 67 | fun = NOT_FOUND_FUN; 68 | } 69 | } 70 | 71 | @Override 72 | public SourceBuilder toMethod(FelContext ctx) { 73 | if(this.builder!=null){ 74 | return builder; 75 | } 76 | if(!this.isDefaultInterpreter()){ 77 | return InterpreterSourceBuilder.getInstance(); 78 | } 79 | return this.fun.toMethod(this,ctx); 80 | } 81 | 82 | @Override 83 | public boolean stable() { 84 | if(this.fun instanceof Stable){ 85 | // 函数是稳定的,并且参数是稳定的 86 | return ((Stable)fun).stable()&&this.isChildrenStable(); 87 | } 88 | return false; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/NodeAdaptor.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | import org.antlr.runtime.Token; 4 | import org.antlr.runtime.tree.CommonTree; 5 | import org.antlr.runtime.tree.CommonTreeAdaptor; 6 | 7 | import com.greenpineyu.fel.common.NumberUtil; 8 | import com.greenpineyu.fel.compile.SourceBuilder; 9 | import com.greenpineyu.fel.context.FelContext; 10 | 11 | public class NodeAdaptor extends CommonTreeAdaptor { 12 | @Override 13 | public Object create(Token token) { 14 | if (token == null) { 15 | return new AbstFelNode(token){ 16 | 17 | @Override 18 | public SourceBuilder toMethod(FelContext ctx) { 19 | return null; 20 | }}; 21 | } 22 | // System.out.println(token.getText()); 23 | 24 | /* 25 | Dot 26 | LikeIn 27 | Logical 28 | Equals 29 | Relational 30 | Additive 31 | Multiplicative 32 | Identifier 33 | FloatingPointLiteral 34 | CharacterLiteral 35 | StringLiteral 36 | BooleanLiteral 37 | HexLiteral 38 | OctalLiteral 39 | DecimalLiteral 40 | */ 41 | Object returnMe = null; 42 | int type = token.getType(); 43 | String text = token.getText(); 44 | switch (type) { 45 | case FelParser.Identifier: 46 | if("null".equals(text)){ 47 | // returnMe = AbstFelNode.NULL; 48 | returnMe = new ConstNode(token, null); 49 | } else { 50 | returnMe = new VarAstNode(token); 51 | } 52 | break; 53 | 54 | /* 函数、操作符 开始 */ 55 | case FelParser.Dot://. 56 | case FelParser.Additive:// +、- 57 | case FelParser.Multiplicative:// *、/ 58 | case FelParser.Equals:// ==、!= 59 | case FelParser.Relational:// >、<、>=、<= 60 | case FelParser.And:// AND 61 | case FelParser.Or:// OR 62 | case FelParser.Ques: 63 | case FelParser.Bracket: 64 | case FelParser.Not: 65 | returnMe = new FunNode(token); 66 | break; 67 | /* 函数、操作符 结束 */ 68 | 69 | /* 常量开始 */ 70 | case FelParser.DecimalLiteral: 71 | // 数字-10进制 72 | returnMe = NumberUtil.parseNumber(new Long(text)); 73 | break; 74 | case FelParser.HexLiteral: 75 | // 数字-16进制 76 | String num = text; 77 | if(text.startsWith("0x")||text.startsWith("0X")){ 78 | num = text.substring(2); 79 | } 80 | returnMe = NumberUtil.parseNumber(new Long(Long.parseLong(num, 16))); 81 | break; 82 | case FelParser.OctalLiteral: 83 | // 数字-8进制 84 | returnMe = NumberUtil.parseNumber(new Long(Long.parseLong(text, 8))); 85 | break; 86 | 87 | case FelParser.FloatingPointLiteral: 88 | // 浮点型 89 | returnMe = new Double(text); 90 | break; 91 | case FelParser.BooleanLiteral: 92 | // 布尔值 93 | returnMe = Boolean.valueOf(text); 94 | break; 95 | case FelParser.CharacterLiteral: 96 | case FelParser.StringLiteral: 97 | // 字符串 98 | // 出掉字符串两端的单引号和双引号 99 | returnMe = text.substring(1, text.length() - 1); 100 | break; 101 | /* 常量结束 */ 102 | default: 103 | break; 104 | } 105 | if (returnMe == null) { 106 | // 不能正确解析 107 | return CommonTree.INVALID_NODE; 108 | } 109 | if (returnMe instanceof CommonTree) { 110 | return returnMe; 111 | } 112 | return new ConstNode(token, returnMe); 113 | } 114 | 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/Parser.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | /** 4 | * 用于分析表达式 5 | * 6 | * @author yuqingsong 7 | * 8 | */ 9 | public interface Parser { 10 | 11 | /** 12 | * 将表达式解析成节点 13 | * 14 | * @param exp 15 | * @return 16 | */ 17 | FelNode parse(String exp); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/Stable.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | public interface Stable { 4 | 5 | /** 6 | * 此节点的值是否固定不变 7 | * 如果每次求节点值都相同,说明此节点是稳定的。 8 | * @return 9 | */ 10 | boolean stable(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/parser/VarAstNode.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.parser; 2 | 3 | import org.antlr.runtime.Token; 4 | import org.antlr.runtime.tree.CommonTree; 5 | 6 | import com.greenpineyu.fel.common.ReflectUtil; 7 | import com.greenpineyu.fel.compile.InterpreterSourceBuilder; 8 | import com.greenpineyu.fel.compile.SourceBuilder; 9 | import com.greenpineyu.fel.context.AbstractContext; 10 | import com.greenpineyu.fel.context.ArrayCtx; 11 | import com.greenpineyu.fel.context.FelContext; 12 | import com.greenpineyu.fel.function.operator.Dot; 13 | 14 | public class VarAstNode extends AbstFelNode { 15 | private final String text; 16 | 17 | public VarAstNode(Token token) { 18 | super(token); 19 | this.text = token.getText(); 20 | } 21 | 22 | @Override 23 | public String getText() { 24 | return this.text; 25 | } 26 | 27 | @Override 28 | public Object interpret(FelContext context, FelNode node) { 29 | return context.get(text); 30 | } 31 | 32 | public static boolean isVar(FelNode n) { 33 | if (n == null) { 34 | return false; 35 | } 36 | boolean isVar = n instanceof VarAstNode; 37 | if (isVar) { 38 | if (n instanceof CommonTree) { 39 | CommonTree treeNode = (CommonTree) n; 40 | CommonTree p = treeNode.parent; 41 | if (p != null) { 42 | if (Dot.DOT.equals(p.getText())) { 43 | // 点运算符后的变量节点不是真正意义上的变量节点。 44 | isVar = p.getChildren().get(0) == n; 45 | } 46 | } 47 | 48 | } 49 | } 50 | return isVar; 51 | } 52 | 53 | { 54 | this.builder = new SourceBuilder() { 55 | 56 | @Override 57 | public String source(FelContext ctx, FelNode node) { 58 | if(!node.isDefaultInterpreter()){ 59 | // 用户自定义解析器 60 | return InterpreterSourceBuilder.getInstance().source(ctx, node); 61 | } 62 | Class type = returnType(ctx, node); 63 | String varName = node.getText(); 64 | String getVarCode = "context.get(\""+varName+"\")"; 65 | if (ctx instanceof ArrayCtx) { 66 | ArrayCtx c = (ArrayCtx) ctx; 67 | getVarCode = "((context instanceof ArrayCtx)?((ArrayCtx)context).get(" 68 | + c.getIndex(varName) 69 | + "):context.get(\"" 70 | + varName + "\"))"; 71 | } 72 | 73 | String code = getVarFullCode(type, getVarCode); 74 | return code; 75 | } 76 | 77 | @Override 78 | public Class returnType(FelContext ctx, FelNode node) { 79 | Class type = AbstractContext.getVarType(node.getText(),ctx); 80 | if(type == null){ 81 | type = InterpreterSourceBuilder.getInstance().returnType(ctx, node); 82 | } 83 | return type; 84 | } 85 | }; 86 | } 87 | 88 | public static String getVarFullCode(Class type, String getVarCode) { 89 | String typeName = type.getCanonicalName(); 90 | boolean isNumber = Number.class.isAssignableFrom(type); 91 | String code = ""; 92 | if (ReflectUtil.isPrimitiveOrWrapNumber(type)) { 93 | code = "((" + typeName + ")" + getVarCode + ")"; 94 | } else if (isNumber) { 95 | // 当float转double时,会丢失精度 96 | code = "((" + typeName + ")" + getVarCode + ").doubleValue()"; 97 | } else { 98 | code = "((" + typeName + ")" + getVarCode + ")"; 99 | } 100 | return code; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/security/ReflectMgr.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.security; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Set; 5 | 6 | public interface ReflectMgr { 7 | 8 | /** 9 | * 是否允许访问某个方法 10 | * @param m 11 | * @return 12 | */ 13 | boolean isCallable(Method m); 14 | 15 | /** 16 | * 添加可访问的方法 17 | * @param m 18 | */ 19 | void addCallableMethod(Method m); 20 | 21 | void removeCallableMethod(Method m); 22 | 23 | /** 24 | * 添加不可访问的方法 25 | * @param m 26 | */ 27 | void addUncallableMethod(Method m); 28 | 29 | void removeUncallableMethod(Method m); 30 | 31 | Set getCallableMethods(); 32 | 33 | Set getUnCallableMethods(); 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/com/greenpineyu/fel/security/ReflectMgrImpl.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.security; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | public class ReflectMgrImpl implements ReflectMgr { 8 | 9 | private Set callableSet; 10 | private Set uncallableSet; 11 | 12 | { 13 | callableSet = new HashSet(); 14 | uncallableSet = new HashSet(); 15 | } 16 | 17 | /* 18 | * 判断原则,以可访问方法列表为首要依据(包含目标方法表示允许访问,否则不允许),不可访问方法列表为次要依据 19 | * 当允许访问方法列表为空时,以不可访问方法列表为依据。 20 | * 21 | * @see com.greenpineyu.fel.security.ReflectMgr#isCallable(java.lang.reflect.Method) 22 | */ 23 | @Override 24 | public boolean isCallable(Method m) { 25 | if (callableSet.isEmpty()) { 26 | return !uncallableSet.contains(m); 27 | } 28 | return callableSet.contains(m); 29 | } 30 | 31 | @Override 32 | public void addCallableMethod(Method m) { 33 | this.callableSet.add(m); 34 | } 35 | 36 | @Override 37 | public void addUncallableMethod(Method m) { 38 | this.uncallableSet.add(m); 39 | } 40 | 41 | @Override 42 | public void removeCallableMethod(Method m) { 43 | this.callableSet.remove(m); 44 | } 45 | 46 | @Override 47 | public void removeUncallableMethod(Method m) { 48 | this.uncallableSet.remove(m); 49 | 50 | } 51 | 52 | @Override 53 | public Set getCallableMethods() { 54 | return new HashSet(this.callableSet); 55 | } 56 | 57 | @Override 58 | public Set getUnCallableMethods() { 59 | return new HashSet(this.uncallableSet); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /test/com/greenpineyu/fel/CollectionGetTest.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.testng.annotations.DataProvider; 7 | import org.testng.annotations.Test; 8 | 9 | import com.greenpineyu.fel.context.FelContext; 10 | 11 | public class CollectionGetTest { 12 | 13 | Integer index = 1; 14 | 15 | FelEngine engine; 16 | FelContext ctx; 17 | int[] pa = { 1, 2, 3 }; 18 | int[][] pa2 = { { 10, 20 }, { 30, 40 } }; 19 | Integer[] wa = { 11, 22, 33 }; 20 | Integer[][] wa2 = { { 100, 200 }, { 300, 400 } }; 21 | List l = new ArrayList(); 22 | List> ll = new ArrayList>(); 23 | { 24 | engine = new FelEngineImpl(); 25 | ctx = engine.getContext(); 26 | ctx.set("index", index); 27 | ctx.set("pa", pa); 28 | ctx.set("wa", wa); 29 | 30 | ctx.set("pa2", pa2); 31 | 32 | ctx.set("wa2", wa2); 33 | 34 | l.add("a"); 35 | l.add("b"); 36 | ctx.set("l", l); 37 | 38 | ll.add(l); 39 | 40 | ArrayList l2 = new ArrayList(l); 41 | l2.add("c"); 42 | ll.add(l2); 43 | ctx.set("ll", ll); 44 | } 45 | 46 | @Test(dataProvider = "dp") 47 | public void eval(String exp, Object actual) { 48 | FelEngineImplTest.compare(engine.eval(exp), actual); 49 | } 50 | 51 | @Test(dataProvider = "dp") 52 | public void compile(String exp, Object actual) { 53 | Expression expObj = engine.compile(exp, ctx); 54 | FelEngineImplTest.compare(expObj.eval(ctx), actual); 55 | } 56 | 57 | @DataProvider 58 | public Object[][] dp() { 59 | return new Object[][] { { "wa[index]", wa[index] }, { "pa[1]", pa[1] }, 60 | { "pa2[1]", pa2[1] }, { "wa2[index]", wa2[index] }, 61 | { "l[index]", l.get(1) }, { "l[1]", l.get(1) }, 62 | { "ll[1][1]", ll.get(1).get(1) }, }; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /test/com/greenpineyu/fel/Foo.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | public class Foo { 8 | 9 | 10 | private final String name; 11 | 12 | private Foo foo = null; 13 | 14 | 15 | static private Foo[] f = new Foo[]{new Foo("array0"),new Foo("array1")}; 16 | 17 | static private Foo[] fooes = f; 18 | 19 | public Foo[] getFooes() { 20 | return fooes; 21 | } 22 | 23 | public void setFooes(Foo[] fooes) { 24 | this.fooes = fooes; 25 | } 26 | 27 | private boolean beenModified = false; 28 | private String property1 = "some value"; 29 | 30 | public Foo(String name) { 31 | this.name = name; 32 | } 33 | 34 | public Foo() { 35 | this("anonymity"); 36 | } 37 | 38 | public static String sayHello(String str) { 39 | return "hello" + str; 40 | } 41 | 42 | 43 | public class Cheezy { 44 | public Iterator iterator() { 45 | return getCheeseList().iterator(); 46 | } 47 | } 48 | 49 | 50 | public String get(String arg) { 51 | if ("name".equals(arg)) { 52 | return name; 53 | } 54 | return "can't find " + arg; 55 | } 56 | 57 | public String convertBoolean(boolean b) { 58 | return "Boolean : " + b; 59 | } 60 | 61 | public int getCount() { 62 | return 5; 63 | } 64 | 65 | public String contact(String a,String b ,String c,String d){ 66 | return a+b+c+c; 67 | } 68 | // public String contact(String... strs){ 69 | // if(strs!=null){ 70 | // StringBuilder sb = new StringBuilder(); 71 | // for (String s : strs) { 72 | // sb.append(s); 73 | // } 74 | // return sb.toString(); 75 | // } 76 | // return ""; 77 | // } 78 | 79 | public List getCheeseList() { 80 | ArrayList answer = new ArrayList(); 81 | answer.add("cheddar"); 82 | answer.add("edam"); 83 | answer.add("brie"); 84 | return answer; 85 | } 86 | 87 | public Cheezy getCheezy() { 88 | return new Cheezy(); 89 | } 90 | 91 | public boolean isSimple() { 92 | return true; 93 | } 94 | 95 | public int square(int value) { 96 | return value * value; 97 | } 98 | 99 | public boolean getTrueAndModify() { 100 | beenModified = true; 101 | return true; 102 | } 103 | 104 | public boolean getModified() { 105 | return beenModified; 106 | } 107 | 108 | public int getSize() { 109 | return 22; 110 | } 111 | 112 | public String getProperty1() { 113 | return property1; 114 | } 115 | 116 | public void setProperty1(String newValue) { 117 | property1 = newValue; 118 | } 119 | 120 | public Foo getFoo() { 121 | return this.foo; 122 | } 123 | 124 | public void setFoo(Foo foo) { 125 | this.foo = foo; 126 | } 127 | 128 | 129 | @Override 130 | public String toString() { 131 | return this.name; 132 | } 133 | } -------------------------------------------------------------------------------- /test/com/greenpineyu/fel/JavaMethodTest.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.testng.annotations.BeforeTest; 6 | import org.testng.annotations.DataProvider; 7 | import org.testng.annotations.Test; 8 | 9 | import com.greenpineyu.fel.context.FelContext; 10 | import com.greenpineyu.fel.function.JavaMethod; 11 | 12 | public class JavaMethodTest { 13 | 14 | int a = 1; 15 | int b = 2; 16 | 17 | FelEngine engine; 18 | FelContext ctx; 19 | 20 | @BeforeTest 21 | public void init(){ 22 | engine = FelEngine.instance; 23 | } 24 | 25 | @Test(dataProvider = "dp") 26 | public void eval(String exp, Object actual) { 27 | FelEngineImplTest.compare(engine.eval(exp), actual); 28 | } 29 | 30 | @Test(dataProvider = "dp") 31 | public void compile(String exp, Object actual) { 32 | Expression expObj = engine.compile(exp, ctx); 33 | FelEngineImplTest.compare(expObj.eval(ctx), actual); 34 | } 35 | 36 | //public Object eval(FelContext context) { 37 | // 38 | // return com.greenpineyu.fel.JavaMethodTest.staticWithParam((java.lang.Integer)((java.lang.Boolean)((ArrayCtx)context).get(0)),(java.lang.Integer)((java.lang.Boolean)((ArrayCtx)context).get(1))); 39 | // } 40 | 41 | @DataProvider 42 | public Object[][] dp() { 43 | ctx = engine.getContext(); 44 | ctx.set("a", a); 45 | ctx.set("b", b); 46 | try { 47 | 48 | Class[] paramTypes = new Class[]{int.class,int.class}; 49 | Method staticWithoutParam = JavaMethodTest.class 50 | .getMethod("staticWithoutParam"); 51 | engine.getFunMgr() 52 | .add( 53 | new JavaMethod("staticWithoutParam", 54 | staticWithoutParam, null)); 55 | Method staticWithParam = JavaMethodTest.class 56 | .getMethod("staticWithParam",paramTypes); 57 | engine.getFunMgr().add( 58 | new JavaMethod("staticParam", staticWithParam, null)); 59 | 60 | Method noParam = JavaMethodTest.class.getMethod("noParam"); 61 | engine.getFunMgr().add(new JavaMethod("objMehtod", noParam, this)); 62 | Method param = JavaMethodTest.class.getMethod("param",paramTypes); 63 | engine.getFunMgr().add(new JavaMethod("objMethodWithParam", param, this)); 64 | 65 | return new Object[][] { 66 | {"staticWithoutParam()", staticWithoutParam() }, 67 | {"staticParam(a,b)", staticWithParam(a,b)}, 68 | {"objMehtod()", noParam()}, 69 | {"objMethodWithParam(a,b)", param(a,b)}, 70 | }; 71 | } catch (SecurityException e) { 72 | e.printStackTrace(); 73 | } catch (NoSuchMethodException e) { 74 | e.printStackTrace(); 75 | } 76 | return null; 77 | } 78 | 79 | public static String staticWithoutParam() { 80 | return "staticWithoutParam"; 81 | } 82 | 83 | public static int staticWithParam(int a, int b) { 84 | return a + b; 85 | } 86 | 87 | public String noParam() { 88 | return "noParam"; 89 | } 90 | 91 | public int param(int a, int b) { 92 | return staticWithParam(a, b); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /test/com/greenpineyu/fel/optimizer/VarVisitOptiTest.java: -------------------------------------------------------------------------------- 1 | package com.greenpineyu.fel.optimizer; 2 | 3 | import org.testng.annotations.Test; 4 | 5 | import com.greenpineyu.fel.Expression; 6 | import com.greenpineyu.fel.FelEngine; 7 | import com.greenpineyu.fel.context.Var; 8 | 9 | public class VarVisitOptiTest { 10 | 11 | @Test 12 | public void VarVisitOpti() { 13 | FelEngine e = FelEngine.instance; 14 | Expression exp = e.compile("a+a", null, new VarVisitOpti( 15 | new Var("a", 1))); 16 | Object eval = exp.eval(null); 17 | assert ((Number) eval).intValue() == 2; 18 | } 19 | } 20 | --------------------------------------------------------------------------------