├── .gitignore ├── README.md ├── example ├── Sample.class └── Sample.java ├── jvmmathlang-catalog-java11.properties ├── pom.xml └── src └── main ├── assembly ├── distribution.xml └── native-image.properties └── java ├── grammer ├── Math.g4 ├── Math.tokens ├── MathBaseListener.java ├── MathLexer.java ├── MathLexer.tokens ├── MathListener.java └── MathParser.java ├── jvmmathlang └── truffle │ ├── JvmMathLang.java │ ├── JvmMathLangContext.java │ ├── JvmMathLangMain.java │ ├── JvmMathLangTypes.java │ └── MathParseTreeListener.java └── nodes ├── AsyncJvmMathLangNode.java ├── BinaryNode.java ├── JvmMathLangNode.java ├── JvmMathLangRootNode.java ├── ParenJvmMathLangNode.java ├── literal ├── BigDecimalNode.java ├── BigDecimalTruffleObject.java └── LongNode.java ├── ops ├── AddNode.java ├── DivNode.java ├── MulNode.java └── SubNode.java └── uml.puml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | target/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JVM Math language 2 | 3 | ## What is this? 4 | 5 | This is a language implementation of simple arithmetic operations for GraalVM. You can install this language into your GraalVM. 6 | 7 | Of course this is implemented with Truffle API. This program can execute four arithmetic operations. You can use numbers, +, -, *, /, "()". Additionally "->" for running in another thread. 8 | 9 | * Lexer, Parser: ANTLR 4.7 10 | * AST Interpreter: Truffle in GraalVM 20.3.0 11 | 12 | ## Usage 13 | 14 | ### Install 15 | 16 | #### Local Install 17 | 18 | Just run `mvn package` & `gu install -L target/jvmmathlang-0.1.0-component.jar`. 19 | With `gu list`, you can see the JVM Math Lang component as follows. 20 | 21 | ``` 22 | $ gu list 23 | ComponentId Version Component name Origin 24 | -------------------------------------------------------------------------------- 25 | js 20.3.0 Graal.js 26 | jvmmathlang 1.0.0 JVM Math Lang github.com 27 | graalvm 20.3.0 GraalVM Core 28 | ``` 29 | 30 | #### From Component Catalog 31 | 32 | I also provide the component catalog for this language. Just run `gu install -C https://raw.githubusercontent.com/jyukutyo/JVM-Math-Language/master/jvmmathlang-catalog-java11.properties jvmmathlang`. Currently it is only for GraalVM 20.3.0 and 20.2.0. 33 | 34 | ### Run Sample Code 35 | 36 | ``` 37 | $ cd example 38 | $ javac Sample.java 39 | $ java Sample 40 | inputed String: (1+2)*3 41 | add(long, long) 42 | 9 43 | ``` 44 | 45 | ## Details 46 | 47 | In DevoxxUS 2017 I heard Oleg Šelajev's "How to Create a New JVM Language". He doesn't publish his code, so I wrote code and created a similar language. 48 | 49 | ## Publishing 50 | 51 | * GraalVMで使われている、他言語をJVM上に実装する仕組みを学ぼう (Japanese, a session at JJUG Night Seminar on 27th Feb 2019) 52 | https://www.slideshare.net/jyukutyo/graalvmjvm 53 | 54 | * オレオレJVM言語を作ってみる (Japanese, a session at JJUG CCC 2017 Fall on 18th Nov 2017) 55 | https://www.slideshare.net/jyukutyo/jjug-ccc-2017-fall-jvm -------------------------------------------------------------------------------- /example/Sample.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jyukutyo/JVM-Math-Language/b76c9cfa6de68f04aee1fb7979cacb1d6470f06a/example/Sample.class -------------------------------------------------------------------------------- /example/Sample.java: -------------------------------------------------------------------------------- 1 | import org.graalvm.polyglot.*; 2 | 3 | class Sample { 4 | public static void main(String... args) { 5 | try (var context = Context.newBuilder("jvmmathlang").build()) { 6 | Value answer = context.eval("jvmmathlang", "(1+2)*3"); 7 | System.out.println(answer); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /jvmmathlang-catalog-java11.properties: -------------------------------------------------------------------------------- 1 | # 20.3.0 Release 2 | org.graalvm.20.3.0_linux_amd64=GraalVM 20.3.0 linux/amd64 3 | org.graalvm.20.3.0_windows_amd64=GraalVM 20.3.0 windows/amd64 4 | org.graalvm.20.3.0_macos_amd64=GraalVM 20.3.0 macos/amd64 5 | 6 | Component.20.3.0_linux_amd64.org.graalvm.jvmmathlang=https://github.com/jyukutyo/JVM-Math-Language/releases/download/1.0.0/jvmmathlang-1.0.0-component.jar 7 | Component.20.3.0_linux_amd64.org.graalvm.jvmmathlang-hash=ceb05504f90709d5827fc7dfd092047fc300a586d7cf7e1df1b2aca1a52e451a 8 | Component.20.3.0_linux_amd64.org.graalvm.jvmmathlang-Bundle-Name=JVM Math Lang 9 | Component.20.3.0_linux_amd64.org.graalvm.jvmmathlang-Bundle-Symbolic-Name=jvmmathlang 10 | Component.20.3.0_linux_amd64.org.graalvm.jvmmathlang-Bundle-Version=20.3.0 11 | Component.20.3.0_linux_amd64.org.graalvm.jvmmathlang-Bundle-RequireCapability=org.graalvm; filter:="(&(graalvm_version=20.3.0)(java_version=11))" 12 | Component.20.3.0_linux_amd64.org.graalvm.jvmmathlang-x-GraalVM-Polyglot-Part=True 13 | Component.20.3.0_linux_amd64.org.graalvm.jvmmathlang-x-GraalVM-Working-Directories=languages/jvmmathlang 14 | 15 | Component.20.3.0_windows_amd64.org.graalvm.jvmmathlang=https://github.com/jyukutyo/JVM-Math-Language/releases/download/1.0.0/jvmmathlang-1.0.0-component.jar 16 | Component.20.3.0_windows_amd64.org.graalvm.jvmmathlang-hash=ceb05504f90709d5827fc7dfd092047fc300a586d7cf7e1df1b2aca1a52e451a 17 | Component.20.3.0_windows_amd64.org.graalvm.jvmmathlang-Bundle-Name=JVM Math Lang 18 | Component.20.3.0_windows_amd64.org.graalvm.jvmmathlang-Bundle-Symbolic-Name=jvmmathlang 19 | Component.20.3.0_windows_amd64.org.graalvm.jvmmathlang-Bundle-Version=20.3.0 20 | Component.20.3.0_windows_amd64.org.graalvm.jvmmathlang-Bundle-RequireCapability=org.graalvm; filter:="(&(graalvm_version=20.3.0)(java_version=11))" 21 | Component.20.3.0_windows_amd64.org.graalvm.jvmmathlang-x-GraalVM-Polyglot-Part=True 22 | Component.20.3.0_windows_amd64.org.graalvm.jvmmathlang-x-GraalVM-Working-Directories=languages/jvmmathlang 23 | 24 | Component.20.3.0_macos_amd64.org.graalvm.jvmmathlang=https://github.com/jyukutyo/JVM-Math-Language/releases/download/1.0.0/jvmmathlang-1.0.0-component.jar 25 | Component.20.3.0_macos_amd64.org.graalvm.jvmmathlang-hash=ceb05504f90709d5827fc7dfd092047fc300a586d7cf7e1df1b2aca1a52e451a 26 | Component.20.3.0_macos_amd64.org.graalvm.jvmmathlang-Bundle-Name=JVM Math Lang 27 | Component.20.3.0_macos_amd64.org.graalvm.jvmmathlang-Bundle-Symbolic-Name=jvmmathlang 28 | Component.20.3.0_macos_amd64.org.graalvm.jvmmathlang-Bundle-Version=20.3.0 29 | Component.20.3.0_macos_amd64.org.graalvm.jvmmathlang-Bundle-RequireCapability=org.graalvm; filter:="(&(graalvm_version=20.3.0)(java_version=11))" 30 | Component.20.3.0_macos_amd64.org.graalvm.jvmmathlang-x-GraalVM-Polyglot-Part=True 31 | Component.20.3.0_macos_amd64.org.graalvm.jvmmathlang-x-GraalVM-Working-Directories=languages/jvmmathlang 32 | 33 | # 20.2.0 Release 34 | org.graalvm.20.2.0_linux_amd64=GraalVM 20.2.0 linux/amd64 35 | org.graalvm.20.2.0_windows_amd64=GraalVM 20.2.0 windows/amd64 36 | org.graalvm.20.2.0_macos_amd64=GraalVM 20.2.0 macos/amd64 37 | 38 | Component.20.2.0_linux_amd64.org.graalvm.jvmmathlang=https://github.com/jyukutyo/JVM-Math-Language/releases/download/1.0.0/jvmmathlang-1.0.0-component.jar 39 | Component.20.2.0_linux_amd64.org.graalvm.jvmmathlang-hash=ceb05504f90709d5827fc7dfd092047fc300a586d7cf7e1df1b2aca1a52e451a 40 | Component.20.2.0_linux_amd64.org.graalvm.jvmmathlang-Bundle-Name=JVM Math Lang 41 | Component.20.2.0_linux_amd64.org.graalvm.jvmmathlang-Bundle-Symbolic-Name=jvmmathlang 42 | Component.20.2.0_linux_amd64.org.graalvm.jvmmathlang-Bundle-Version=20.2.0 43 | Component.20.2.0_linux_amd64.org.graalvm.jvmmathlang-Bundle-RequireCapability=org.graalvm; filter:="(&(graalvm_version=20.2.0)(java_version=11))" 44 | Component.20.2.0_linux_amd64.org.graalvm.jvmmathlang-x-GraalVM-Polyglot-Part=True 45 | Component.20.2.0_linux_amd64.org.graalvm.jvmmathlang-x-GraalVM-Working-Directories=languages/jvmmathlang 46 | 47 | Component.20.2.0_windows_amd64.org.graalvm.jvmmathlang=https://github.com/jyukutyo/JVM-Math-Language/releases/download/1.0.0/jvmmathlang-1.0.0-component.jar 48 | Component.20.2.0_windows_amd64.org.graalvm.jvmmathlang-hash=ceb05504f90709d5827fc7dfd092047fc300a586d7cf7e1df1b2aca1a52e451a 49 | Component.20.2.0_windows_amd64.org.graalvm.jvmmathlang-Bundle-Name=JVM Math Lang 50 | Component.20.2.0_windows_amd64.org.graalvm.jvmmathlang-Bundle-Symbolic-Name=jvmmathlang 51 | Component.20.2.0_windows_amd64.org.graalvm.jvmmathlang-Bundle-Version=20.2.0 52 | Component.20.2.0_windows_amd64.org.graalvm.jvmmathlang-Bundle-RequireCapability=org.graalvm; filter:="(&(graalvm_version=20.2.0)(java_version=11))" 53 | Component.20.2.0_windows_amd64.org.graalvm.jvmmathlang-x-GraalVM-Polyglot-Part=True 54 | Component.20.2.0_windows_amd64.org.graalvm.jvmmathlang-x-GraalVM-Working-Directories=languages/jvmmathlang 55 | 56 | Component.20.2.0_macos_amd64.org.graalvm.jvmmathlang=https://github.com/jyukutyo/JVM-Math-Language/releases/download/1.0.0/jvmmathlang-1.0.0-component.jar 57 | Component.20.2.0_macos_amd64.org.graalvm.jvmmathlang-hash=ceb05504f90709d5827fc7dfd092047fc300a586d7cf7e1df1b2aca1a52e451a 58 | Component.20.2.0_macos_amd64.org.graalvm.jvmmathlang-Bundle-Name=JVM Math Lang 59 | Component.20.2.0_macos_amd64.org.graalvm.jvmmathlang-Bundle-Symbolic-Name=jvmmathlang 60 | Component.20.2.0_macos_amd64.org.graalvm.jvmmathlang-Bundle-Version=20.2.0 61 | Component.20.2.0_macos_amd64.org.graalvm.jvmmathlang-Bundle-RequireCapability=org.graalvm; filter:="(&(graalvm_version=20.2.0)(java_version=11))" 62 | Component.20.2.0_macos_amd64.org.graalvm.jvmmathlang-x-GraalVM-Polyglot-Part=True 63 | Component.20.2.0_macos_amd64.org.graalvm.jvmmathlang-x-GraalVM-Working-Directories=languages/jvmmathlang 64 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.jyukutyo 6 | jvmmathlang 7 | 1.0.0 8 | jar 9 | 10 | jvmmathlang 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 11 16 | ${java.version} 17 | ${java.version} 18 | jvmmathlang 19 | 20.3.0 20 | 21 | 22 | 23 | 24 | 25 | org.apache.maven.plugins 26 | maven-compiler-plugin 27 | 3.8.1 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-jar-plugin 32 | 3.2.0 33 | 34 | ${project.artifactId} 35 | 36 | 37 | 38 | org.apache.maven.plugins 39 | maven-assembly-plugin 40 | 3.3.0 41 | 42 | 43 | src/main/assembly/distribution.xml 44 | 45 | 46 | 47 | JVM Math Lang 48 | ${bundle.symbolic.name} 49 | ${project.version} 50 | org.graalvm; filter:="(java_version=11)" 51 | True 52 | 53 | 54 | 55 | 56 | 57 | make-assembly 58 | package 59 | 60 | single 61 | 62 | 63 | 64 | 65 | 66 | net.nicoulaj.maven.plugins 67 | checksum-maven-plugin 68 | 1.9 69 | 70 | 71 | SHA-256 72 | 73 | 74 | 75 | ${project.build.directory} 76 | 77 | ${project.artifactId}-${project.version}-component.jar 78 | 79 | 80 | 81 | 82 | 83 | 84 | package 85 | 86 | files 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | org.antlr 97 | antlr4-runtime 98 | 4.7 99 | 100 | 101 | org.graalvm.truffle 102 | truffle-api 103 | ${target.graalvm.version} 104 | 105 | 106 | org.graalvm.truffle 107 | truffle-dsl-processor 108 | ${target.graalvm.version} 109 | provided 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /src/main/assembly/distribution.xml: -------------------------------------------------------------------------------- 1 | 4 | component 5 | 6 | jar 7 | 8 | false 9 | 10 | 11 | languages${file.separator}${bundle.symbolic.name} 12 | ${project.build.directory}${file.separator}${project.artifactId}.jar 13 | 14 | 15 | languages${file.separator}${bundle.symbolic.name} 16 | ${project.basedir}${file.separator}src${file.separator}main${file.separator}assembly${file.separator}native-image.properties 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/assembly/native-image.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jyukutyo/JVM-Math-Language/b76c9cfa6de68f04aee1fb7979cacb1d6470f06a/src/main/assembly/native-image.properties -------------------------------------------------------------------------------- /src/main/java/grammer/Math.g4: -------------------------------------------------------------------------------- 1 | grammar Math; 2 | 3 | prog 4 | : expr (EOF | NEWLINE) 5 | ; 6 | 7 | 8 | expr 9 | : '(' expr ')' #parensExpr 10 | | functionName '('argument? (',' argument)* ')' #invoke 11 | | '->' expr #asyncExpr 12 | | left=expr op=('*'|'/') right=expr #infixExpr 13 | | left=expr op=('+'|'-') right=expr #infixExpr 14 | | value=NUM #numberExpr 15 | ; 16 | 17 | functionName: ID; 18 | argument: expr; 19 | 20 | ID 21 | : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* 22 | ; 23 | 24 | 25 | OP_ADD: '+'; 26 | OP_SUB: '-'; 27 | OP_MUL: '*'; 28 | OP_DIV: '/'; 29 | 30 | NUM: [0-9]+ ('.' [0-9]+)?; 31 | WS: [ \t]+ -> skip; 32 | COMMA: ','; 33 | 34 | NEWLINE: '\r'? '\n'; -------------------------------------------------------------------------------- /src/main/java/grammer/Math.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | T__1=2 3 | T__2=3 4 | ID=4 5 | OP_ADD=5 6 | OP_SUB=6 7 | OP_MUL=7 8 | OP_DIV=8 9 | NUM=9 10 | WS=10 11 | COMMA=11 12 | NEWLINE=12 13 | '('=1 14 | ')'=2 15 | '->'=3 16 | '+'=5 17 | '-'=6 18 | '*'=7 19 | '/'=8 20 | ','=11 21 | -------------------------------------------------------------------------------- /src/main/java/grammer/MathBaseListener.java: -------------------------------------------------------------------------------- 1 | // Generated from Math.g4 by ANTLR 4.7 2 | package grammer; 3 | 4 | import org.antlr.v4.runtime.ParserRuleContext; 5 | import org.antlr.v4.runtime.tree.ErrorNode; 6 | import org.antlr.v4.runtime.tree.TerminalNode; 7 | 8 | /** 9 | * This class provides an empty implementation of {@link MathListener}, 10 | * which can be extended to create a listener which only needs to handle a subset 11 | * of the available methods. 12 | */ 13 | public class MathBaseListener implements MathListener { 14 | /** 15 | * {@inheritDoc} 16 | * 17 | *

The default implementation does nothing.

18 | */ 19 | @Override public void enterProg(MathParser.ProgContext ctx) { } 20 | /** 21 | * {@inheritDoc} 22 | * 23 | *

The default implementation does nothing.

24 | */ 25 | @Override public void exitProg(MathParser.ProgContext ctx) { } 26 | /** 27 | * {@inheritDoc} 28 | * 29 | *

The default implementation does nothing.

30 | */ 31 | @Override public void enterAsyncExpr(MathParser.AsyncExprContext ctx) { } 32 | /** 33 | * {@inheritDoc} 34 | * 35 | *

The default implementation does nothing.

36 | */ 37 | @Override public void exitAsyncExpr(MathParser.AsyncExprContext ctx) { } 38 | /** 39 | * {@inheritDoc} 40 | * 41 | *

The default implementation does nothing.

42 | */ 43 | @Override public void enterInfixExpr(MathParser.InfixExprContext ctx) { } 44 | /** 45 | * {@inheritDoc} 46 | * 47 | *

The default implementation does nothing.

48 | */ 49 | @Override public void exitInfixExpr(MathParser.InfixExprContext ctx) { } 50 | /** 51 | * {@inheritDoc} 52 | * 53 | *

The default implementation does nothing.

54 | */ 55 | @Override public void enterNumberExpr(MathParser.NumberExprContext ctx) { } 56 | /** 57 | * {@inheritDoc} 58 | * 59 | *

The default implementation does nothing.

60 | */ 61 | @Override public void exitNumberExpr(MathParser.NumberExprContext ctx) { } 62 | /** 63 | * {@inheritDoc} 64 | * 65 | *

The default implementation does nothing.

66 | */ 67 | @Override public void enterInvoke(MathParser.InvokeContext ctx) { } 68 | /** 69 | * {@inheritDoc} 70 | * 71 | *

The default implementation does nothing.

72 | */ 73 | @Override public void exitInvoke(MathParser.InvokeContext ctx) { } 74 | /** 75 | * {@inheritDoc} 76 | * 77 | *

The default implementation does nothing.

78 | */ 79 | @Override public void enterParensExpr(MathParser.ParensExprContext ctx) { } 80 | /** 81 | * {@inheritDoc} 82 | * 83 | *

The default implementation does nothing.

84 | */ 85 | @Override public void exitParensExpr(MathParser.ParensExprContext ctx) { } 86 | /** 87 | * {@inheritDoc} 88 | * 89 | *

The default implementation does nothing.

90 | */ 91 | @Override public void enterFunctionName(MathParser.FunctionNameContext ctx) { } 92 | /** 93 | * {@inheritDoc} 94 | * 95 | *

The default implementation does nothing.

96 | */ 97 | @Override public void exitFunctionName(MathParser.FunctionNameContext ctx) { } 98 | /** 99 | * {@inheritDoc} 100 | * 101 | *

The default implementation does nothing.

102 | */ 103 | @Override public void enterArgument(MathParser.ArgumentContext ctx) { } 104 | /** 105 | * {@inheritDoc} 106 | * 107 | *

The default implementation does nothing.

108 | */ 109 | @Override public void exitArgument(MathParser.ArgumentContext ctx) { } 110 | 111 | /** 112 | * {@inheritDoc} 113 | * 114 | *

The default implementation does nothing.

115 | */ 116 | @Override public void enterEveryRule(ParserRuleContext ctx) { } 117 | /** 118 | * {@inheritDoc} 119 | * 120 | *

The default implementation does nothing.

121 | */ 122 | @Override public void exitEveryRule(ParserRuleContext ctx) { } 123 | /** 124 | * {@inheritDoc} 125 | * 126 | *

The default implementation does nothing.

127 | */ 128 | @Override public void visitTerminal(TerminalNode node) { } 129 | /** 130 | * {@inheritDoc} 131 | * 132 | *

The default implementation does nothing.

133 | */ 134 | @Override public void visitErrorNode(ErrorNode node) { } 135 | } -------------------------------------------------------------------------------- /src/main/java/grammer/MathLexer.java: -------------------------------------------------------------------------------- 1 | // Generated from Math.g4 by ANTLR 4.7 2 | package grammer; 3 | import org.antlr.v4.runtime.Lexer; 4 | import org.antlr.v4.runtime.CharStream; 5 | import org.antlr.v4.runtime.Token; 6 | import org.antlr.v4.runtime.TokenStream; 7 | import org.antlr.v4.runtime.*; 8 | import org.antlr.v4.runtime.atn.*; 9 | import org.antlr.v4.runtime.dfa.DFA; 10 | import org.antlr.v4.runtime.misc.*; 11 | 12 | @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) 13 | public class MathLexer extends Lexer { 14 | static { RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); } 15 | 16 | protected static final DFA[] _decisionToDFA; 17 | protected static final PredictionContextCache _sharedContextCache = 18 | new PredictionContextCache(); 19 | public static final int 20 | T__0=1, T__1=2, T__2=3, ID=4, OP_ADD=5, OP_SUB=6, OP_MUL=7, OP_DIV=8, 21 | NUM=9, WS=10, COMMA=11, NEWLINE=12; 22 | public static String[] channelNames = { 23 | "DEFAULT_TOKEN_CHANNEL", "HIDDEN" 24 | }; 25 | 26 | public static String[] modeNames = { 27 | "DEFAULT_MODE" 28 | }; 29 | 30 | public static final String[] ruleNames = { 31 | "T__0", "T__1", "T__2", "ID", "OP_ADD", "OP_SUB", "OP_MUL", "OP_DIV", 32 | "NUM", "WS", "COMMA", "NEWLINE" 33 | }; 34 | 35 | private static final String[] _LITERAL_NAMES = { 36 | null, "'('", "')'", "'->'", null, "'+'", "'-'", "'*'", "'/'", null, null, 37 | "','" 38 | }; 39 | private static final String[] _SYMBOLIC_NAMES = { 40 | null, null, null, null, "ID", "OP_ADD", "OP_SUB", "OP_MUL", "OP_DIV", 41 | "NUM", "WS", "COMMA", "NEWLINE" 42 | }; 43 | public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); 44 | 45 | /** 46 | * @deprecated Use {@link #VOCABULARY} instead. 47 | */ 48 | @Deprecated 49 | public static final String[] tokenNames; 50 | static { 51 | tokenNames = new String[_SYMBOLIC_NAMES.length]; 52 | for (int i = 0; i < tokenNames.length; i++) { 53 | tokenNames[i] = VOCABULARY.getLiteralName(i); 54 | if (tokenNames[i] == null) { 55 | tokenNames[i] = VOCABULARY.getSymbolicName(i); 56 | } 57 | 58 | if (tokenNames[i] == null) { 59 | tokenNames[i] = ""; 60 | } 61 | } 62 | } 63 | 64 | @Override 65 | @Deprecated 66 | public String[] getTokenNames() { 67 | return tokenNames; 68 | } 69 | 70 | @Override 71 | 72 | public Vocabulary getVocabulary() { 73 | return VOCABULARY; 74 | } 75 | 76 | 77 | public MathLexer(CharStream input) { 78 | super(input); 79 | _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); 80 | } 81 | 82 | @Override 83 | public String getGrammarFileName() { return "Math.g4"; } 84 | 85 | @Override 86 | public String[] getRuleNames() { return ruleNames; } 87 | 88 | @Override 89 | public String getSerializedATN() { return _serializedATN; } 90 | 91 | @Override 92 | public String[] getChannelNames() { return channelNames; } 93 | 94 | @Override 95 | public String[] getModeNames() { return modeNames; } 96 | 97 | @Override 98 | public ATN getATN() { return _ATN; } 99 | 100 | public static final String _serializedATN = 101 | "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\16L\b\1\4\2\t\2\4"+ 102 | "\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+ 103 | "\13\4\f\t\f\4\r\t\r\3\2\3\2\3\3\3\3\3\4\3\4\3\4\3\5\3\5\7\5%\n\5\f\5\16"+ 104 | "\5(\13\5\3\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\n\6\n\63\n\n\r\n\16\n\64\3"+ 105 | "\n\3\n\6\n9\n\n\r\n\16\n:\5\n=\n\n\3\13\6\13@\n\13\r\13\16\13A\3\13\3"+ 106 | "\13\3\f\3\f\3\r\5\rI\n\r\3\r\3\r\2\2\16\3\3\5\4\7\5\t\6\13\7\r\b\17\t"+ 107 | "\21\n\23\13\25\f\27\r\31\16\3\2\6\5\2C\\aac|\6\2\62;C\\aac|\3\2\62;\4"+ 108 | "\2\13\13\"\"\2Q\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3"+ 109 | "\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2"+ 110 | "\2\27\3\2\2\2\2\31\3\2\2\2\3\33\3\2\2\2\5\35\3\2\2\2\7\37\3\2\2\2\t\""+ 111 | "\3\2\2\2\13)\3\2\2\2\r+\3\2\2\2\17-\3\2\2\2\21/\3\2\2\2\23\62\3\2\2\2"+ 112 | "\25?\3\2\2\2\27E\3\2\2\2\31H\3\2\2\2\33\34\7*\2\2\34\4\3\2\2\2\35\36\7"+ 113 | "+\2\2\36\6\3\2\2\2\37 \7/\2\2 !\7@\2\2!\b\3\2\2\2\"&\t\2\2\2#%\t\3\2\2"+ 114 | "$#\3\2\2\2%(\3\2\2\2&$\3\2\2\2&\'\3\2\2\2\'\n\3\2\2\2(&\3\2\2\2)*\7-\2"+ 115 | "\2*\f\3\2\2\2+,\7/\2\2,\16\3\2\2\2-.\7,\2\2.\20\3\2\2\2/\60\7\61\2\2\60"+ 116 | "\22\3\2\2\2\61\63\t\4\2\2\62\61\3\2\2\2\63\64\3\2\2\2\64\62\3\2\2\2\64"+ 117 | "\65\3\2\2\2\65<\3\2\2\2\668\7\60\2\2\679\t\4\2\28\67\3\2\2\29:\3\2\2\2"+ 118 | ":8\3\2\2\2:;\3\2\2\2;=\3\2\2\2<\66\3\2\2\2<=\3\2\2\2=\24\3\2\2\2>@\t\5"+ 119 | "\2\2?>\3\2\2\2@A\3\2\2\2A?\3\2\2\2AB\3\2\2\2BC\3\2\2\2CD\b\13\2\2D\26"+ 120 | "\3\2\2\2EF\7.\2\2F\30\3\2\2\2GI\7\17\2\2HG\3\2\2\2HI\3\2\2\2IJ\3\2\2\2"+ 121 | "JK\7\f\2\2K\32\3\2\2\2\t\2&\64:'=3 16 | '+'=5 17 | '-'=6 18 | '*'=7 19 | '/'=8 20 | ','=11 21 | -------------------------------------------------------------------------------- /src/main/java/grammer/MathListener.java: -------------------------------------------------------------------------------- 1 | // Generated from Math.g4 by ANTLR 4.7 2 | package grammer; 3 | import org.antlr.v4.runtime.tree.ParseTreeListener; 4 | 5 | /** 6 | * This interface defines a complete listener for a parse tree produced by 7 | * {@link MathParser}. 8 | */ 9 | public interface MathListener extends ParseTreeListener { 10 | /** 11 | * Enter a parse tree produced by {@link MathParser#prog}. 12 | * @param ctx the parse tree 13 | */ 14 | void enterProg(MathParser.ProgContext ctx); 15 | /** 16 | * Exit a parse tree produced by {@link MathParser#prog}. 17 | * @param ctx the parse tree 18 | */ 19 | void exitProg(MathParser.ProgContext ctx); 20 | /** 21 | * Enter a parse tree produced by the {@code asyncExpr} 22 | * labeled alternative in {@link MathParser#expr}. 23 | * @param ctx the parse tree 24 | */ 25 | void enterAsyncExpr(MathParser.AsyncExprContext ctx); 26 | /** 27 | * Exit a parse tree produced by the {@code asyncExpr} 28 | * labeled alternative in {@link MathParser#expr}. 29 | * @param ctx the parse tree 30 | */ 31 | void exitAsyncExpr(MathParser.AsyncExprContext ctx); 32 | /** 33 | * Enter a parse tree produced by the {@code infixExpr} 34 | * labeled alternative in {@link MathParser#expr}. 35 | * @param ctx the parse tree 36 | */ 37 | void enterInfixExpr(MathParser.InfixExprContext ctx); 38 | /** 39 | * Exit a parse tree produced by the {@code infixExpr} 40 | * labeled alternative in {@link MathParser#expr}. 41 | * @param ctx the parse tree 42 | */ 43 | void exitInfixExpr(MathParser.InfixExprContext ctx); 44 | /** 45 | * Enter a parse tree produced by the {@code numberExpr} 46 | * labeled alternative in {@link MathParser#expr}. 47 | * @param ctx the parse tree 48 | */ 49 | void enterNumberExpr(MathParser.NumberExprContext ctx); 50 | /** 51 | * Exit a parse tree produced by the {@code numberExpr} 52 | * labeled alternative in {@link MathParser#expr}. 53 | * @param ctx the parse tree 54 | */ 55 | void exitNumberExpr(MathParser.NumberExprContext ctx); 56 | /** 57 | * Enter a parse tree produced by the {@code invoke} 58 | * labeled alternative in {@link MathParser#expr}. 59 | * @param ctx the parse tree 60 | */ 61 | void enterInvoke(MathParser.InvokeContext ctx); 62 | /** 63 | * Exit a parse tree produced by the {@code invoke} 64 | * labeled alternative in {@link MathParser#expr}. 65 | * @param ctx the parse tree 66 | */ 67 | void exitInvoke(MathParser.InvokeContext ctx); 68 | /** 69 | * Enter a parse tree produced by the {@code parensExpr} 70 | * labeled alternative in {@link MathParser#expr}. 71 | * @param ctx the parse tree 72 | */ 73 | void enterParensExpr(MathParser.ParensExprContext ctx); 74 | /** 75 | * Exit a parse tree produced by the {@code parensExpr} 76 | * labeled alternative in {@link MathParser#expr}. 77 | * @param ctx the parse tree 78 | */ 79 | void exitParensExpr(MathParser.ParensExprContext ctx); 80 | /** 81 | * Enter a parse tree produced by {@link MathParser#functionName}. 82 | * @param ctx the parse tree 83 | */ 84 | void enterFunctionName(MathParser.FunctionNameContext ctx); 85 | /** 86 | * Exit a parse tree produced by {@link MathParser#functionName}. 87 | * @param ctx the parse tree 88 | */ 89 | void exitFunctionName(MathParser.FunctionNameContext ctx); 90 | /** 91 | * Enter a parse tree produced by {@link MathParser#argument}. 92 | * @param ctx the parse tree 93 | */ 94 | void enterArgument(MathParser.ArgumentContext ctx); 95 | /** 96 | * Exit a parse tree produced by {@link MathParser#argument}. 97 | * @param ctx the parse tree 98 | */ 99 | void exitArgument(MathParser.ArgumentContext ctx); 100 | } -------------------------------------------------------------------------------- /src/main/java/grammer/MathParser.java: -------------------------------------------------------------------------------- 1 | // Generated from Math.g4 by ANTLR 4.7 2 | package grammer; 3 | import org.antlr.v4.runtime.atn.*; 4 | import org.antlr.v4.runtime.dfa.DFA; 5 | import org.antlr.v4.runtime.*; 6 | import org.antlr.v4.runtime.misc.*; 7 | import org.antlr.v4.runtime.tree.*; 8 | import java.util.List; 9 | import java.util.Iterator; 10 | import java.util.ArrayList; 11 | 12 | @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) 13 | public class MathParser extends Parser { 14 | static { RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); } 15 | 16 | protected static final DFA[] _decisionToDFA; 17 | protected static final PredictionContextCache _sharedContextCache = 18 | new PredictionContextCache(); 19 | public static final int 20 | T__0=1, T__1=2, T__2=3, ID=4, OP_ADD=5, OP_SUB=6, OP_MUL=7, OP_DIV=8, 21 | NUM=9, WS=10, COMMA=11, NEWLINE=12; 22 | public static final int 23 | RULE_prog = 0, RULE_expr = 1, RULE_functionName = 2, RULE_argument = 3; 24 | public static final String[] ruleNames = { 25 | "prog", "expr", "functionName", "argument" 26 | }; 27 | 28 | private static final String[] _LITERAL_NAMES = { 29 | null, "'('", "')'", "'->'", null, "'+'", "'-'", "'*'", "'/'", null, null, 30 | "','" 31 | }; 32 | private static final String[] _SYMBOLIC_NAMES = { 33 | null, null, null, null, "ID", "OP_ADD", "OP_SUB", "OP_MUL", "OP_DIV", 34 | "NUM", "WS", "COMMA", "NEWLINE" 35 | }; 36 | public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); 37 | 38 | /** 39 | * @deprecated Use {@link #VOCABULARY} instead. 40 | */ 41 | @Deprecated 42 | public static final String[] tokenNames; 43 | static { 44 | tokenNames = new String[_SYMBOLIC_NAMES.length]; 45 | for (int i = 0; i < tokenNames.length; i++) { 46 | tokenNames[i] = VOCABULARY.getLiteralName(i); 47 | if (tokenNames[i] == null) { 48 | tokenNames[i] = VOCABULARY.getSymbolicName(i); 49 | } 50 | 51 | if (tokenNames[i] == null) { 52 | tokenNames[i] = ""; 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | @Deprecated 59 | public String[] getTokenNames() { 60 | return tokenNames; 61 | } 62 | 63 | @Override 64 | 65 | public Vocabulary getVocabulary() { 66 | return VOCABULARY; 67 | } 68 | 69 | @Override 70 | public String getGrammarFileName() { return "Math.g4"; } 71 | 72 | @Override 73 | public String[] getRuleNames() { return ruleNames; } 74 | 75 | @Override 76 | public String getSerializedATN() { return _serializedATN; } 77 | 78 | @Override 79 | public ATN getATN() { return _ATN; } 80 | 81 | public MathParser(TokenStream input) { 82 | super(input); 83 | _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); 84 | } 85 | public static class ProgContext extends ParserRuleContext { 86 | public ExprContext expr() { 87 | return getRuleContext(ExprContext.class,0); 88 | } 89 | public TerminalNode EOF() { return getToken(MathParser.EOF, 0); } 90 | public TerminalNode NEWLINE() { return getToken(MathParser.NEWLINE, 0); } 91 | public ProgContext(ParserRuleContext parent, int invokingState) { 92 | super(parent, invokingState); 93 | } 94 | @Override public int getRuleIndex() { return RULE_prog; } 95 | @Override 96 | public void enterRule(ParseTreeListener listener) { 97 | if ( listener instanceof MathListener ) ((MathListener)listener).enterProg(this); 98 | } 99 | @Override 100 | public void exitRule(ParseTreeListener listener) { 101 | if ( listener instanceof MathListener ) ((MathListener)listener).exitProg(this); 102 | } 103 | } 104 | 105 | public final ProgContext prog() throws RecognitionException { 106 | ProgContext _localctx = new ProgContext(_ctx, getState()); 107 | enterRule(_localctx, 0, RULE_prog); 108 | int _la; 109 | try { 110 | enterOuterAlt(_localctx, 1); 111 | { 112 | setState(8); 113 | expr(0); 114 | setState(9); 115 | _la = _input.LA(1); 116 | if ( !(_la==EOF || _la==NEWLINE) ) { 117 | _errHandler.recoverInline(this); 118 | } 119 | else { 120 | if ( _input.LA(1)==Token.EOF ) matchedEOF = true; 121 | _errHandler.reportMatch(this); 122 | consume(); 123 | } 124 | } 125 | } 126 | catch (RecognitionException re) { 127 | _localctx.exception = re; 128 | _errHandler.reportError(this, re); 129 | _errHandler.recover(this, re); 130 | } 131 | finally { 132 | exitRule(); 133 | } 134 | return _localctx; 135 | } 136 | 137 | public static class ExprContext extends ParserRuleContext { 138 | public ExprContext(ParserRuleContext parent, int invokingState) { 139 | super(parent, invokingState); 140 | } 141 | @Override public int getRuleIndex() { return RULE_expr; } 142 | 143 | public ExprContext() { } 144 | public void copyFrom(ExprContext ctx) { 145 | super.copyFrom(ctx); 146 | } 147 | } 148 | public static class AsyncExprContext extends ExprContext { 149 | public ExprContext expr() { 150 | return getRuleContext(ExprContext.class,0); 151 | } 152 | public AsyncExprContext(ExprContext ctx) { copyFrom(ctx); } 153 | @Override 154 | public void enterRule(ParseTreeListener listener) { 155 | if ( listener instanceof MathListener ) ((MathListener)listener).enterAsyncExpr(this); 156 | } 157 | @Override 158 | public void exitRule(ParseTreeListener listener) { 159 | if ( listener instanceof MathListener ) ((MathListener)listener).exitAsyncExpr(this); 160 | } 161 | } 162 | public static class InfixExprContext extends ExprContext { 163 | public ExprContext left; 164 | public Token op; 165 | public ExprContext right; 166 | public List expr() { 167 | return getRuleContexts(ExprContext.class); 168 | } 169 | public ExprContext expr(int i) { 170 | return getRuleContext(ExprContext.class,i); 171 | } 172 | public InfixExprContext(ExprContext ctx) { copyFrom(ctx); } 173 | @Override 174 | public void enterRule(ParseTreeListener listener) { 175 | if ( listener instanceof MathListener ) ((MathListener)listener).enterInfixExpr(this); 176 | } 177 | @Override 178 | public void exitRule(ParseTreeListener listener) { 179 | if ( listener instanceof MathListener ) ((MathListener)listener).exitInfixExpr(this); 180 | } 181 | } 182 | public static class NumberExprContext extends ExprContext { 183 | public Token value; 184 | public TerminalNode NUM() { return getToken(MathParser.NUM, 0); } 185 | public NumberExprContext(ExprContext ctx) { copyFrom(ctx); } 186 | @Override 187 | public void enterRule(ParseTreeListener listener) { 188 | if ( listener instanceof MathListener ) ((MathListener)listener).enterNumberExpr(this); 189 | } 190 | @Override 191 | public void exitRule(ParseTreeListener listener) { 192 | if ( listener instanceof MathListener ) ((MathListener)listener).exitNumberExpr(this); 193 | } 194 | } 195 | public static class InvokeContext extends ExprContext { 196 | public FunctionNameContext functionName() { 197 | return getRuleContext(FunctionNameContext.class,0); 198 | } 199 | public List argument() { 200 | return getRuleContexts(ArgumentContext.class); 201 | } 202 | public ArgumentContext argument(int i) { 203 | return getRuleContext(ArgumentContext.class,i); 204 | } 205 | public InvokeContext(ExprContext ctx) { copyFrom(ctx); } 206 | @Override 207 | public void enterRule(ParseTreeListener listener) { 208 | if ( listener instanceof MathListener ) ((MathListener)listener).enterInvoke(this); 209 | } 210 | @Override 211 | public void exitRule(ParseTreeListener listener) { 212 | if ( listener instanceof MathListener ) ((MathListener)listener).exitInvoke(this); 213 | } 214 | } 215 | public static class ParensExprContext extends ExprContext { 216 | public ExprContext expr() { 217 | return getRuleContext(ExprContext.class,0); 218 | } 219 | public ParensExprContext(ExprContext ctx) { copyFrom(ctx); } 220 | @Override 221 | public void enterRule(ParseTreeListener listener) { 222 | if ( listener instanceof MathListener ) ((MathListener)listener).enterParensExpr(this); 223 | } 224 | @Override 225 | public void exitRule(ParseTreeListener listener) { 226 | if ( listener instanceof MathListener ) ((MathListener)listener).exitParensExpr(this); 227 | } 228 | } 229 | 230 | public final ExprContext expr() throws RecognitionException { 231 | return expr(0); 232 | } 233 | 234 | private ExprContext expr(int _p) throws RecognitionException { 235 | ParserRuleContext _parentctx = _ctx; 236 | int _parentState = getState(); 237 | ExprContext _localctx = new ExprContext(_ctx, _parentState); 238 | ExprContext _prevctx = _localctx; 239 | int _startState = 2; 240 | enterRecursionRule(_localctx, 2, RULE_expr, _p); 241 | int _la; 242 | try { 243 | int _alt; 244 | enterOuterAlt(_localctx, 1); 245 | { 246 | setState(33); 247 | _errHandler.sync(this); 248 | switch (_input.LA(1)) { 249 | case T__0: 250 | { 251 | _localctx = new ParensExprContext(_localctx); 252 | _ctx = _localctx; 253 | _prevctx = _localctx; 254 | 255 | setState(12); 256 | match(T__0); 257 | setState(13); 258 | expr(0); 259 | setState(14); 260 | match(T__1); 261 | } 262 | break; 263 | case ID: 264 | { 265 | _localctx = new InvokeContext(_localctx); 266 | _ctx = _localctx; 267 | _prevctx = _localctx; 268 | setState(16); 269 | functionName(); 270 | setState(17); 271 | match(T__0); 272 | setState(19); 273 | _errHandler.sync(this); 274 | _la = _input.LA(1); 275 | if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__0) | (1L << T__2) | (1L << ID) | (1L << NUM))) != 0)) { 276 | { 277 | setState(18); 278 | argument(); 279 | } 280 | } 281 | 282 | setState(25); 283 | _errHandler.sync(this); 284 | _la = _input.LA(1); 285 | while (_la==COMMA) { 286 | { 287 | { 288 | setState(21); 289 | match(COMMA); 290 | setState(22); 291 | argument(); 292 | } 293 | } 294 | setState(27); 295 | _errHandler.sync(this); 296 | _la = _input.LA(1); 297 | } 298 | setState(28); 299 | match(T__1); 300 | } 301 | break; 302 | case T__2: 303 | { 304 | _localctx = new AsyncExprContext(_localctx); 305 | _ctx = _localctx; 306 | _prevctx = _localctx; 307 | setState(30); 308 | match(T__2); 309 | setState(31); 310 | expr(4); 311 | } 312 | break; 313 | case NUM: 314 | { 315 | _localctx = new NumberExprContext(_localctx); 316 | _ctx = _localctx; 317 | _prevctx = _localctx; 318 | setState(32); 319 | ((NumberExprContext)_localctx).value = match(NUM); 320 | } 321 | break; 322 | default: 323 | throw new NoViableAltException(this); 324 | } 325 | _ctx.stop = _input.LT(-1); 326 | setState(43); 327 | _errHandler.sync(this); 328 | _alt = getInterpreter().adaptivePredict(_input,4,_ctx); 329 | while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { 330 | if ( _alt==1 ) { 331 | if ( _parseListeners!=null ) triggerExitRuleEvent(); 332 | _prevctx = _localctx; 333 | { 334 | setState(41); 335 | _errHandler.sync(this); 336 | switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) { 337 | case 1: 338 | { 339 | _localctx = new InfixExprContext(new ExprContext(_parentctx, _parentState)); 340 | ((InfixExprContext)_localctx).left = _prevctx; 341 | pushNewRecursionContext(_localctx, _startState, RULE_expr); 342 | setState(35); 343 | if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); 344 | setState(36); 345 | ((InfixExprContext)_localctx).op = _input.LT(1); 346 | _la = _input.LA(1); 347 | if ( !(_la==OP_MUL || _la==OP_DIV) ) { 348 | ((InfixExprContext)_localctx).op = (Token)_errHandler.recoverInline(this); 349 | } 350 | else { 351 | if ( _input.LA(1)==Token.EOF ) matchedEOF = true; 352 | _errHandler.reportMatch(this); 353 | consume(); 354 | } 355 | setState(37); 356 | ((InfixExprContext)_localctx).right = expr(4); 357 | } 358 | break; 359 | case 2: 360 | { 361 | _localctx = new InfixExprContext(new ExprContext(_parentctx, _parentState)); 362 | ((InfixExprContext)_localctx).left = _prevctx; 363 | pushNewRecursionContext(_localctx, _startState, RULE_expr); 364 | setState(38); 365 | if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); 366 | setState(39); 367 | ((InfixExprContext)_localctx).op = _input.LT(1); 368 | _la = _input.LA(1); 369 | if ( !(_la==OP_ADD || _la==OP_SUB) ) { 370 | ((InfixExprContext)_localctx).op = (Token)_errHandler.recoverInline(this); 371 | } 372 | else { 373 | if ( _input.LA(1)==Token.EOF ) matchedEOF = true; 374 | _errHandler.reportMatch(this); 375 | consume(); 376 | } 377 | setState(40); 378 | ((InfixExprContext)_localctx).right = expr(3); 379 | } 380 | break; 381 | } 382 | } 383 | } 384 | setState(45); 385 | _errHandler.sync(this); 386 | _alt = getInterpreter().adaptivePredict(_input,4,_ctx); 387 | } 388 | } 389 | } 390 | catch (RecognitionException re) { 391 | _localctx.exception = re; 392 | _errHandler.reportError(this, re); 393 | _errHandler.recover(this, re); 394 | } 395 | finally { 396 | unrollRecursionContexts(_parentctx); 397 | } 398 | return _localctx; 399 | } 400 | 401 | public static class FunctionNameContext extends ParserRuleContext { 402 | public TerminalNode ID() { return getToken(MathParser.ID, 0); } 403 | public FunctionNameContext(ParserRuleContext parent, int invokingState) { 404 | super(parent, invokingState); 405 | } 406 | @Override public int getRuleIndex() { return RULE_functionName; } 407 | @Override 408 | public void enterRule(ParseTreeListener listener) { 409 | if ( listener instanceof MathListener ) ((MathListener)listener).enterFunctionName(this); 410 | } 411 | @Override 412 | public void exitRule(ParseTreeListener listener) { 413 | if ( listener instanceof MathListener ) ((MathListener)listener).exitFunctionName(this); 414 | } 415 | } 416 | 417 | public final FunctionNameContext functionName() throws RecognitionException { 418 | FunctionNameContext _localctx = new FunctionNameContext(_ctx, getState()); 419 | enterRule(_localctx, 4, RULE_functionName); 420 | try { 421 | enterOuterAlt(_localctx, 1); 422 | { 423 | setState(46); 424 | match(ID); 425 | } 426 | } 427 | catch (RecognitionException re) { 428 | _localctx.exception = re; 429 | _errHandler.reportError(this, re); 430 | _errHandler.recover(this, re); 431 | } 432 | finally { 433 | exitRule(); 434 | } 435 | return _localctx; 436 | } 437 | 438 | public static class ArgumentContext extends ParserRuleContext { 439 | public ExprContext expr() { 440 | return getRuleContext(ExprContext.class,0); 441 | } 442 | public ArgumentContext(ParserRuleContext parent, int invokingState) { 443 | super(parent, invokingState); 444 | } 445 | @Override public int getRuleIndex() { return RULE_argument; } 446 | @Override 447 | public void enterRule(ParseTreeListener listener) { 448 | if ( listener instanceof MathListener ) ((MathListener)listener).enterArgument(this); 449 | } 450 | @Override 451 | public void exitRule(ParseTreeListener listener) { 452 | if ( listener instanceof MathListener ) ((MathListener)listener).exitArgument(this); 453 | } 454 | } 455 | 456 | public final ArgumentContext argument() throws RecognitionException { 457 | ArgumentContext _localctx = new ArgumentContext(_ctx, getState()); 458 | enterRule(_localctx, 6, RULE_argument); 459 | try { 460 | enterOuterAlt(_localctx, 1); 461 | { 462 | setState(48); 463 | expr(0); 464 | } 465 | } 466 | catch (RecognitionException re) { 467 | _localctx.exception = re; 468 | _errHandler.reportError(this, re); 469 | _errHandler.recover(this, re); 470 | } 471 | finally { 472 | exitRule(); 473 | } 474 | return _localctx; 475 | } 476 | 477 | public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { 478 | switch (ruleIndex) { 479 | case 1: 480 | return expr_sempred((ExprContext)_localctx, predIndex); 481 | } 482 | return true; 483 | } 484 | private boolean expr_sempred(ExprContext _localctx, int predIndex) { 485 | switch (predIndex) { 486 | case 0: 487 | return precpred(_ctx, 3); 488 | case 1: 489 | return precpred(_ctx, 2); 490 | } 491 | return true; 492 | } 493 | 494 | public static final String _serializedATN = 495 | "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\16\65\4\2\t\2\4\3"+ 496 | "\t\3\4\4\t\4\4\5\t\5\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\5\3\26"+ 497 | "\n\3\3\3\3\3\7\3\32\n\3\f\3\16\3\35\13\3\3\3\3\3\3\3\3\3\3\3\5\3$\n\3"+ 498 | "\3\3\3\3\3\3\3\3\3\3\3\3\7\3,\n\3\f\3\16\3/\13\3\3\4\3\4\3\5\3\5\3\5\2"+ 499 | "\3\4\6\2\4\6\b\2\5\3\3\16\16\3\2\t\n\3\2\7\b\2\67\2\n\3\2\2\2\4#\3\2\2"+ 500 | "\2\6\60\3\2\2\2\b\62\3\2\2\2\n\13\5\4\3\2\13\f\t\2\2\2\f\3\3\2\2\2\r\16"+ 501 | "\b\3\1\2\16\17\7\3\2\2\17\20\5\4\3\2\20\21\7\4\2\2\21$\3\2\2\2\22\23\5"+ 502 | "\6\4\2\23\25\7\3\2\2\24\26\5\b\5\2\25\24\3\2\2\2\25\26\3\2\2\2\26\33\3"+ 503 | "\2\2\2\27\30\7\r\2\2\30\32\5\b\5\2\31\27\3\2\2\2\32\35\3\2\2\2\33\31\3"+ 504 | "\2\2\2\33\34\3\2\2\2\34\36\3\2\2\2\35\33\3\2\2\2\36\37\7\4\2\2\37$\3\2"+ 505 | "\2\2 !\7\5\2\2!$\5\4\3\6\"$\7\13\2\2#\r\3\2\2\2#\22\3\2\2\2# \3\2\2\2"+ 506 | "#\"\3\2\2\2$-\3\2\2\2%&\f\5\2\2&\'\t\3\2\2\',\5\4\3\6()\f\4\2\2)*\t\4"+ 507 | "\2\2*,\5\4\3\5+%\3\2\2\2+(\3\2\2\2,/\3\2\2\2-+\3\2\2\2-.\3\2\2\2.\5\3"+ 508 | "\2\2\2/-\3\2\2\2\60\61\7\6\2\2\61\7\3\2\2\2\62\63\5\4\3\2\63\t\3\2\2\2"+ 509 | "\7\25\33#+-"; 510 | public static final ATN _ATN = 511 | new ATNDeserializer().deserialize(_serializedATN.toCharArray()); 512 | static { 513 | _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; 514 | for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { 515 | _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); 516 | } 517 | } 518 | } -------------------------------------------------------------------------------- /src/main/java/jvmmathlang/truffle/JvmMathLang.java: -------------------------------------------------------------------------------- 1 | package jvmmathlang.truffle; 2 | 3 | import java.io.IOException; 4 | import java.nio.ByteBuffer; 5 | 6 | import com.oracle.truffle.api.CallTarget; 7 | import com.oracle.truffle.api.Truffle; 8 | import com.oracle.truffle.api.TruffleLanguage; 9 | import com.oracle.truffle.api.source.Source; 10 | import grammer.MathLexer; 11 | import grammer.MathParser; 12 | import nodes.JvmMathLangRootNode; 13 | import org.antlr.v4.runtime.CharStream; 14 | import org.antlr.v4.runtime.CodePointBuffer; 15 | import org.antlr.v4.runtime.CodePointCharStream; 16 | import org.antlr.v4.runtime.CommonTokenStream; 17 | import org.antlr.v4.runtime.tree.ParseTreeWalker; 18 | 19 | /** 20 | * run code with ANTLR and Truffle. 21 | */ 22 | @TruffleLanguage.Registration( 23 | id = "jvmmathlang", 24 | name = "JVM Math Language", 25 | version = "0.0.2") 26 | public class JvmMathLang extends TruffleLanguage { 27 | 28 | @Override 29 | protected JvmMathLangContext createContext(Env env) { 30 | return new JvmMathLangContext(); 31 | } 32 | 33 | @Override 34 | protected CallTarget parse(ParsingRequest request) throws Exception { 35 | JvmMathLangRootNode main = parseSource(request.getSource()); 36 | return Truffle.getRuntime().createCallTarget(main); 37 | } 38 | 39 | private JvmMathLangRootNode parseSource(Source source) throws IOException { 40 | // get user input 41 | String input = source.getCharacters().toString(); 42 | 43 | System.out.println("inputed String: " + input); 44 | 45 | // convert user input to ANTLR character stream 46 | // java.lang.UnsupportedOperationException causes when use CharBuffer 47 | CharStream charStream = CodePointCharStream.fromBuffer( 48 | CodePointBuffer.withBytes( 49 | ByteBuffer.wrap( 50 | input.getBytes()))); 51 | 52 | // lexing 53 | MathLexer mathLexer = new MathLexer(charStream); 54 | CommonTokenStream tokenStream = new CommonTokenStream(mathLexer); 55 | 56 | // parsing 57 | MathParser mathParser = new MathParser(tokenStream); 58 | MathParser.ProgContext prog = mathParser.prog(); 59 | 60 | // creates Truffle nodes from ANTLR parse result 61 | ParseTreeWalker treeWalker = new ParseTreeWalker(); 62 | MathParseTreeListener listener = new MathParseTreeListener(); 63 | treeWalker.walk(listener, prog); 64 | 65 | return listener.getRoot(this); 66 | } 67 | 68 | protected boolean isObjectOfLanguage(Object object) { 69 | // return true if this language can deal with such object in "native way" 70 | return false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/jvmmathlang/truffle/JvmMathLangContext.java: -------------------------------------------------------------------------------- 1 | package jvmmathlang.truffle; 2 | 3 | public class JvmMathLangContext { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/jvmmathlang/truffle/JvmMathLangMain.java: -------------------------------------------------------------------------------- 1 | package jvmmathlang.truffle; 2 | 3 | import java.io.IOException; 4 | import java.util.Scanner; 5 | 6 | import com.oracle.truffle.api.Truffle; 7 | import org.graalvm.polyglot.Context; 8 | import org.graalvm.polyglot.Source; 9 | import org.graalvm.polyglot.Value; 10 | 11 | /** 12 | * Main class. 13 | * 14 | *

15 | * waiting for user input. 16 | *

17 | */ 18 | public class JvmMathLangMain { 19 | 20 | public static void main(String[] args) throws IOException { 21 | System.out.println("Truffle runtime: " + Truffle.getRuntime().getName()); 22 | 23 | Context context = Context.create("jvmmathlang"); 24 | context.getEngine().getLanguages().forEach((s, l) -> System.out.println("Language: " + l.getName())); 25 | 26 | try (Scanner s = new Scanner(System.in)) { 27 | while (true) { 28 | System.out.print("> "); 29 | String program = s.nextLine().trim(); 30 | 31 | if (program.equalsIgnoreCase("quit")) { 32 | break; 33 | } 34 | 35 | Object answer = runCode(context, program); 36 | System.out.println("answer: " + answer); 37 | System.out.println(); 38 | } 39 | } 40 | } 41 | 42 | private static Object runCode(Context context, String program) throws IOException { 43 | Source source = Source.newBuilder("jvmmathlang", program, "MATH").build(); 44 | Value value = context.eval(source); 45 | return value; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/jvmmathlang/truffle/JvmMathLangTypes.java: -------------------------------------------------------------------------------- 1 | package jvmmathlang.truffle; 2 | 3 | import com.oracle.truffle.api.dsl.TypeSystem; 4 | 5 | /** 6 | * Type definition. 7 | * 8 | *

9 | * define only long so others are treated as general type. 10 | *

11 | */ 12 | @TypeSystem(long.class) 13 | public abstract class JvmMathLangTypes { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/jvmmathlang/truffle/MathParseTreeListener.java: -------------------------------------------------------------------------------- 1 | package jvmmathlang.truffle; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.LinkedList; 5 | 6 | import com.oracle.truffle.api.frame.FrameDescriptor; 7 | import grammer.MathBaseListener; 8 | import grammer.MathLexer; 9 | import grammer.MathParser; 10 | import nodes.AsyncJvmMathLangNode; 11 | import nodes.JvmMathLangNode; 12 | import nodes.JvmMathLangRootNode; 13 | import nodes.ParenJvmMathLangNode; 14 | import nodes.literal.BigDecimalNode; 15 | import nodes.literal.LongNode; 16 | 17 | /** 18 | * Truffle nodes creator. 19 | */ 20 | public class MathParseTreeListener extends MathBaseListener { 21 | 22 | private JvmMathLangNode node; 23 | 24 | private LinkedList mathLangNodes = new LinkedList<>(); 25 | 26 | @Override 27 | public void exitNumberExpr(MathParser.NumberExprContext ctx) { 28 | String text = ctx.value.getText(); 29 | try { 30 | mathLangNodes.push(new LongNode(Long.parseLong(text))); 31 | } catch(NumberFormatException e) { 32 | mathLangNodes.push(new BigDecimalNode(new BigDecimal(text))); 33 | } 34 | } 35 | 36 | @Override 37 | public void exitInfixExpr(MathParser.InfixExprContext ctx) { 38 | JvmMathLangNode right = mathLangNodes.pop(); 39 | JvmMathLangNode left = mathLangNodes.pop(); 40 | 41 | JvmMathLangNode current = null; 42 | switch (ctx.op.getType()) { 43 | case MathLexer.OP_ADD: 44 | current = nodes.ops.AddNodeGen.create(left, right); 45 | break; 46 | case MathLexer.OP_DIV: 47 | current = nodes.ops.DivNodeGen.create(left, right); 48 | break; 49 | case MathLexer.OP_MUL: 50 | current = nodes.ops.MulNodeGen.create(left, right); 51 | break; 52 | case MathLexer.OP_SUB: 53 | current = nodes.ops.SubNodeGen.create(left, right); 54 | break; 55 | } 56 | mathLangNodes.push(current); 57 | } 58 | 59 | @Override 60 | public void exitParensExpr(MathParser.ParensExprContext ctx) { 61 | mathLangNodes.push(new ParenJvmMathLangNode(mathLangNodes.pop())); 62 | } 63 | 64 | @Override 65 | public void exitAsyncExpr(MathParser.AsyncExprContext ctx) { 66 | mathLangNodes.push(new AsyncJvmMathLangNode(mathLangNodes.pop())); 67 | } 68 | 69 | @Override 70 | public void exitProg(MathParser.ProgContext ctx) { 71 | node = mathLangNodes.pop(); 72 | } 73 | 74 | public JvmMathLangRootNode getRoot(JvmMathLang jvmMathLang) { 75 | return new JvmMathLangRootNode(jvmMathLang, new FrameDescriptor(), node, "main"); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/nodes/AsyncJvmMathLangNode.java: -------------------------------------------------------------------------------- 1 | package nodes; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | import java.util.concurrent.ExecutionException; 5 | 6 | import com.oracle.truffle.api.frame.VirtualFrame; 7 | import com.oracle.truffle.api.nodes.NodeInfo; 8 | 9 | @NodeInfo(shortName = "->") 10 | public class AsyncJvmMathLangNode extends JvmMathLangNode { 11 | 12 | @Child private JvmMathLangNode expression; 13 | 14 | public AsyncJvmMathLangNode(JvmMathLangNode node) { 15 | this.expression = node; 16 | } 17 | 18 | @Override 19 | public Object executeGeneric(VirtualFrame frame) { 20 | try { 21 | System.out.println("Running on another thread: " + expression); 22 | return CompletableFuture.supplyAsync(() -> expression.executeGeneric(frame)).get(); 23 | } catch (InterruptedException|ExecutionException e) { 24 | throw new RuntimeException(e); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/nodes/BinaryNode.java: -------------------------------------------------------------------------------- 1 | package nodes; 2 | 3 | import com.oracle.truffle.api.dsl.NodeChild; 4 | import com.oracle.truffle.api.dsl.NodeChildren; 5 | 6 | @NodeChildren({ @NodeChild("leftNode"), @NodeChild("righrNode") }) 7 | public abstract class BinaryNode extends JvmMathLangNode { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/nodes/JvmMathLangNode.java: -------------------------------------------------------------------------------- 1 | package nodes; 2 | 3 | import com.oracle.truffle.api.dsl.TypeSystemReference; 4 | import com.oracle.truffle.api.frame.VirtualFrame; 5 | import com.oracle.truffle.api.nodes.Node; 6 | import com.oracle.truffle.api.nodes.NodeInfo; 7 | import com.oracle.truffle.api.nodes.UnexpectedResultException; 8 | import jvmmathlang.truffle.JvmMathLangTypes; 9 | import jvmmathlang.truffle.JvmMathLangTypesGen; 10 | 11 | @NodeInfo 12 | @TypeSystemReference(JvmMathLangTypes.class) 13 | public abstract class JvmMathLangNode extends Node { 14 | 15 | public abstract Object executeGeneric(VirtualFrame frame); 16 | 17 | public long executeLong(VirtualFrame frame) throws UnexpectedResultException { 18 | return JvmMathLangTypesGen.expectLong(executeGeneric(frame)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/nodes/JvmMathLangRootNode.java: -------------------------------------------------------------------------------- 1 | package nodes; 2 | 3 | import com.oracle.truffle.api.TruffleLanguage; 4 | import com.oracle.truffle.api.frame.FrameDescriptor; 5 | import com.oracle.truffle.api.frame.VirtualFrame; 6 | import com.oracle.truffle.api.nodes.NodeInfo; 7 | import com.oracle.truffle.api.nodes.RootNode; 8 | 9 | @NodeInfo 10 | public class JvmMathLangRootNode extends RootNode { 11 | 12 | /** The function body that is executed, and specialized during execution. */ 13 | private JvmMathLangNode bodyNode; 14 | 15 | /** The name of the function, for printing purposes only. */ 16 | private String name; 17 | 18 | public JvmMathLangRootNode(TruffleLanguage language, FrameDescriptor frameDescriptor, JvmMathLangNode node, String name) { 19 | super(language, frameDescriptor); 20 | this.bodyNode = node; 21 | this.name = name; 22 | } 23 | 24 | @Override 25 | public Object execute(VirtualFrame frame) { 26 | return bodyNode.executeGeneric(frame); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/nodes/ParenJvmMathLangNode.java: -------------------------------------------------------------------------------- 1 | package nodes; 2 | 3 | import com.oracle.truffle.api.frame.VirtualFrame; 4 | import com.oracle.truffle.api.nodes.NodeInfo; 5 | import com.oracle.truffle.api.nodes.UnexpectedResultException; 6 | 7 | @NodeInfo 8 | public class ParenJvmMathLangNode extends JvmMathLangNode { 9 | 10 | @Child private JvmMathLangNode expression; 11 | 12 | public ParenJvmMathLangNode(JvmMathLangNode node) { 13 | this.expression = node; 14 | } 15 | 16 | public void setExpression(JvmMathLangNode node) { 17 | this.expression = node; 18 | } 19 | 20 | @Override 21 | public Object executeGeneric(VirtualFrame frame) { 22 | try { 23 | return this.expression.executeLong(frame); 24 | } catch (UnexpectedResultException e) { 25 | return this.expression.executeGeneric(frame); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/nodes/literal/BigDecimalNode.java: -------------------------------------------------------------------------------- 1 | package nodes.literal; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import com.oracle.truffle.api.frame.VirtualFrame; 6 | import com.oracle.truffle.api.nodes.NodeInfo; 7 | import nodes.JvmMathLangNode; 8 | 9 | @NodeInfo(shortName = "const") 10 | public class BigDecimalNode extends JvmMathLangNode { 11 | 12 | private final BigDecimal value; 13 | 14 | public BigDecimalNode(BigDecimal bigDecimal) { 15 | this.value = bigDecimal; 16 | } 17 | 18 | @Override 19 | public Object executeGeneric(VirtualFrame frame) { 20 | return new BigDecimalTruffleObject(this.value); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/nodes/literal/BigDecimalTruffleObject.java: -------------------------------------------------------------------------------- 1 | package nodes.literal; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import com.oracle.truffle.api.interop.ForeignAccess; 6 | import com.oracle.truffle.api.interop.TruffleObject; 7 | 8 | public class BigDecimalTruffleObject implements TruffleObject { 9 | private final BigDecimal value; 10 | 11 | public BigDecimalTruffleObject(BigDecimal value) { 12 | this.value = value; 13 | } 14 | 15 | public BigDecimal getValue() { 16 | return value; 17 | } 18 | 19 | @Override 20 | public ForeignAccess getForeignAccess() { 21 | return null; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return this.value.toString(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/nodes/literal/LongNode.java: -------------------------------------------------------------------------------- 1 | package nodes.literal; 2 | 3 | import com.oracle.truffle.api.frame.VirtualFrame; 4 | import com.oracle.truffle.api.nodes.NodeInfo; 5 | import nodes.JvmMathLangNode; 6 | 7 | @NodeInfo(shortName = "const") 8 | public class LongNode extends JvmMathLangNode { 9 | 10 | private final long value; 11 | 12 | public LongNode(long l) { 13 | this.value = l; 14 | } 15 | 16 | public long executeLong(VirtualFrame frame) { 17 | return this.value; 18 | } 19 | 20 | @Override 21 | public Object executeGeneric(VirtualFrame frame) { 22 | return this.value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/nodes/ops/AddNode.java: -------------------------------------------------------------------------------- 1 | package nodes.ops; 2 | 3 | 4 | import java.math.BigDecimal; 5 | 6 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 7 | import com.oracle.truffle.api.dsl.Specialization; 8 | import com.oracle.truffle.api.nodes.NodeInfo; 9 | import nodes.BinaryNode; 10 | import nodes.literal.BigDecimalTruffleObject; 11 | 12 | @NodeInfo(shortName = "+") 13 | public abstract class AddNode extends BinaryNode { 14 | 15 | @Specialization(rewriteOn = ArithmeticException.class) 16 | protected long add(long left, long right) { 17 | System.out.println("add(long, long)"); 18 | return Math.addExact(left, right); 19 | } 20 | 21 | @Specialization 22 | @TruffleBoundary 23 | protected BigDecimalTruffleObject add(BigDecimalTruffleObject left, BigDecimalTruffleObject right) { 24 | System.out.println("add(BigDecimal, BigDecimal)"); 25 | return new BigDecimalTruffleObject(left.getValue().add(right.getValue())); 26 | } 27 | 28 | @Specialization 29 | @TruffleBoundary 30 | protected BigDecimalTruffleObject add(Object left, Object right) { 31 | System.out.println("add(Object, Object)"); 32 | BigDecimal l = left instanceof BigDecimalTruffleObject ? ((BigDecimalTruffleObject) left).getValue() : BigDecimal.valueOf((long) left); 33 | BigDecimal r = right instanceof BigDecimalTruffleObject ? ((BigDecimalTruffleObject) right).getValue() : BigDecimal.valueOf((long) right); 34 | return new BigDecimalTruffleObject(l.add(r)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/nodes/ops/DivNode.java: -------------------------------------------------------------------------------- 1 | package nodes.ops; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import com.oracle.truffle.api.dsl.Specialization; 6 | import com.oracle.truffle.api.nodes.NodeInfo; 7 | import nodes.BinaryNode; 8 | import nodes.literal.BigDecimalTruffleObject; 9 | 10 | @NodeInfo(shortName = "/") 11 | public abstract class DivNode extends BinaryNode { 12 | 13 | @Specialization(rewriteOn = ArithmeticException.class) 14 | protected long div(long left, long right) { 15 | long result = left / right; 16 | 17 | // leftがLong.MIN_VALUEでrightが-1だとオーバーフローとなる 18 | if ((left & right & result) < 0) { 19 | throw new ArithmeticException("long overflow"); 20 | } 21 | return result; 22 | } 23 | 24 | @Specialization 25 | protected BigDecimalTruffleObject div(BigDecimalTruffleObject left, BigDecimalTruffleObject right) { 26 | return new BigDecimalTruffleObject(left.getValue().divide(right.getValue())); 27 | } 28 | 29 | @Specialization 30 | protected BigDecimalTruffleObject div(Object left, Object right) { 31 | BigDecimal l = left instanceof BigDecimalTruffleObject ? ((BigDecimalTruffleObject) left).getValue() : BigDecimal.valueOf((long) left); 32 | BigDecimal r = right instanceof BigDecimalTruffleObject ? ((BigDecimalTruffleObject) right).getValue() : BigDecimal.valueOf((long) right); 33 | return new BigDecimalTruffleObject(l.divide(r)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/nodes/ops/MulNode.java: -------------------------------------------------------------------------------- 1 | package nodes.ops; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import com.oracle.truffle.api.dsl.Specialization; 6 | import com.oracle.truffle.api.nodes.NodeInfo; 7 | import nodes.BinaryNode; 8 | import nodes.literal.BigDecimalTruffleObject; 9 | 10 | @NodeInfo(shortName = "*") 11 | public abstract class MulNode extends BinaryNode { 12 | 13 | @Specialization(rewriteOn = ArithmeticException.class) 14 | protected long mul(long left, long right) { 15 | return Math.multiplyExact(left, right); 16 | } 17 | 18 | @Specialization 19 | protected BigDecimalTruffleObject mul(BigDecimalTruffleObject left, BigDecimalTruffleObject right) { 20 | return new BigDecimalTruffleObject(left.getValue().multiply(right.getValue())); 21 | } 22 | 23 | @Specialization 24 | protected BigDecimalTruffleObject mul(Object left, Object right) { 25 | BigDecimal l = left instanceof BigDecimalTruffleObject ? ((BigDecimalTruffleObject) left).getValue() : BigDecimal.valueOf((long) left); 26 | BigDecimal r = right instanceof BigDecimalTruffleObject ? ((BigDecimalTruffleObject) right).getValue() : BigDecimal.valueOf((long) right); 27 | return new BigDecimalTruffleObject(l.multiply(r)); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/nodes/ops/SubNode.java: -------------------------------------------------------------------------------- 1 | package nodes.ops; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import com.oracle.truffle.api.dsl.Specialization; 6 | import com.oracle.truffle.api.nodes.NodeInfo; 7 | import nodes.BinaryNode; 8 | import nodes.literal.BigDecimalTruffleObject; 9 | 10 | @NodeInfo(shortName = "-") 11 | public abstract class SubNode extends BinaryNode { 12 | 13 | @Specialization(rewriteOn = ArithmeticException.class) 14 | protected long sub(long left, long right) { 15 | return Math.subtractExact(left, right); 16 | } 17 | 18 | @Specialization 19 | protected BigDecimalTruffleObject sub(BigDecimalTruffleObject left, BigDecimalTruffleObject right) { 20 | return new BigDecimalTruffleObject(left.getValue().subtract(right.getValue())); 21 | } 22 | 23 | @Specialization 24 | protected BigDecimalTruffleObject sub(Object left, Object right) { 25 | BigDecimal l = left instanceof BigDecimalTruffleObject ? ((BigDecimalTruffleObject) left).getValue() : BigDecimal.valueOf((long) left); 26 | BigDecimal r = right instanceof BigDecimalTruffleObject ? ((BigDecimalTruffleObject) right).getValue() : BigDecimal.valueOf((long) right); 27 | return new BigDecimalTruffleObject(l.subtract(r)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/nodes/uml.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | abstract class JvmMathLangNode 4 | abstract class BinaryNode 5 | abstract class AddNode 6 | abstract class SubNode 7 | abstract class MulNode 8 | abstract class DivNode 9 | 10 | JvmMathLangNode <|-- BinaryNode 11 | BinaryNode <|-- AddNode 12 | BinaryNode <|-- SubNode 13 | BinaryNode <|-- MulNode 14 | BinaryNode <|-- DivNode 15 | 16 | @enduml 17 | 18 | @startuml 19 | 20 | abstract class com.oracle.truffle.api.nodes.Node 21 | abstract class JvmMathLangNode 22 | 23 | com.oracle.truffle.api.nodes.Node <|-- JvmMathLangNode 24 | 25 | @enduml 26 | 27 | @startuml 28 | 29 | abstract class JvmMathLangNode 30 | class BigDecimalNode 31 | class LongNode 32 | class ParenJvmMathLangNode 33 | 34 | JvmMathLangNode <|-- BigDecimalNode 35 | JvmMathLangNode <|-- LongNode 36 | JvmMathLangNode <|-- ParenJvmMathLangNode 37 | 38 | @enduml 39 | 40 | @startuml 41 | 42 | abstract class AddNode 43 | abstract class SubNode 44 | abstract class MulNode 45 | abstract class DivNode 46 | class AddNodeGen 47 | class SubNodeGen 48 | class MulNodeGen 49 | class DivNodeGen 50 | 51 | AddNode <|-- AddNodeGen 52 | SubNode <|-- SubNodeGen 53 | MulNode <|-- MulNodeGen 54 | DivNode <|-- DivNodeGen 55 | 56 | @enduml --------------------------------------------------------------------------------