diff --git a/makina-compiler/.gitignore b/makina-compiler/.gitignore
index 2620c62..b155595 100644
--- a/makina-compiler/.gitignore
+++ b/makina-compiler/.gitignore
@@ -68,7 +68,4 @@ fabric.properties
.idea/httpRequests
# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
-
-# Generated sources
-gen
\ No newline at end of file
+.idea/caches/build_file_checksums.ser
\ No newline at end of file
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makina.interp b/makina-compiler/gen/xyz/colinholzman/makina/makina.interp
new file mode 100644
index 0000000..266e653
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makina.interp
@@ -0,0 +1,52 @@
+token literal names:
+null
+'machine'
+';'
+'initial'
+'state'
+'{'
+'}'
+'.'
+'entry'
+'exit'
+'on'
+'('
+')'
+'->'
+'>'
+null
+null
+null
+
+token symbolic names:
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+ID
+WHITESPACE
+COMMENT
+
+rule names:
+file
+state
+id
+handler
+action
+guard
+target
+
+
+atn:
+[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 19, 88, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 21, 10, 2, 12, 2, 14, 2, 24, 11, 2, 3, 2, 3, 2, 3, 3, 5, 3, 29, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 36, 10, 3, 12, 3, 14, 3, 39, 11, 3, 3, 3, 3, 3, 3, 4, 5, 4, 44, 10, 4, 3, 4, 3, 4, 3, 4, 7, 4, 49, 10, 4, 12, 4, 14, 4, 52, 11, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 65, 10, 5, 3, 5, 5, 5, 68, 10, 5, 3, 5, 5, 5, 71, 10, 5, 3, 5, 5, 5, 74, 10, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 5, 8, 86, 10, 8, 3, 8, 2, 2, 9, 2, 4, 6, 8, 10, 12, 14, 2, 2, 2, 92, 2, 16, 3, 2, 2, 2, 4, 28, 3, 2, 2, 2, 6, 43, 3, 2, 2, 2, 8, 73, 3, 2, 2, 2, 10, 75, 3, 2, 2, 2, 12, 77, 3, 2, 2, 2, 14, 85, 3, 2, 2, 2, 16, 17, 7, 3, 2, 2, 17, 18, 7, 17, 2, 2, 18, 22, 7, 4, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 21, 24, 3, 2, 2, 2, 22, 20, 3, 2, 2, 2, 22, 23, 3, 2, 2, 2, 23, 25, 3, 2, 2, 2, 24, 22, 3, 2, 2, 2, 25, 26, 7, 2, 2, 3, 26, 3, 3, 2, 2, 2, 27, 29, 7, 5, 2, 2, 28, 27, 3, 2, 2, 2, 28, 29, 3, 2, 2, 2, 29, 30, 3, 2, 2, 2, 30, 31, 7, 6, 2, 2, 31, 32, 5, 6, 4, 2, 32, 37, 7, 7, 2, 2, 33, 36, 5, 8, 5, 2, 34, 36, 5, 4, 3, 2, 35, 33, 3, 2, 2, 2, 35, 34, 3, 2, 2, 2, 36, 39, 3, 2, 2, 2, 37, 35, 3, 2, 2, 2, 37, 38, 3, 2, 2, 2, 38, 40, 3, 2, 2, 2, 39, 37, 3, 2, 2, 2, 40, 41, 7, 8, 2, 2, 41, 5, 3, 2, 2, 2, 42, 44, 7, 9, 2, 2, 43, 42, 3, 2, 2, 2, 43, 44, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 50, 7, 17, 2, 2, 46, 47, 7, 9, 2, 2, 47, 49, 7, 17, 2, 2, 48, 46, 3, 2, 2, 2, 49, 52, 3, 2, 2, 2, 50, 48, 3, 2, 2, 2, 50, 51, 3, 2, 2, 2, 51, 7, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 53, 54, 7, 10, 2, 2, 54, 55, 5, 10, 6, 2, 55, 56, 7, 4, 2, 2, 56, 74, 3, 2, 2, 2, 57, 58, 7, 11, 2, 2, 58, 59, 5, 10, 6, 2, 59, 60, 7, 4, 2, 2, 60, 74, 3, 2, 2, 2, 61, 62, 7, 12, 2, 2, 62, 64, 7, 17, 2, 2, 63, 65, 5, 12, 7, 2, 64, 63, 3, 2, 2, 2, 64, 65, 3, 2, 2, 2, 65, 67, 3, 2, 2, 2, 66, 68, 5, 10, 6, 2, 67, 66, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 70, 3, 2, 2, 2, 69, 71, 5, 14, 8, 2, 70, 69, 3, 2, 2, 2, 70, 71, 3, 2, 2, 2, 71, 72, 3, 2, 2, 2, 72, 74, 7, 4, 2, 2, 73, 53, 3, 2, 2, 2, 73, 57, 3, 2, 2, 2, 73, 61, 3, 2, 2, 2, 74, 9, 3, 2, 2, 2, 75, 76, 7, 17, 2, 2, 76, 11, 3, 2, 2, 2, 77, 78, 7, 13, 2, 2, 78, 79, 7, 17, 2, 2, 79, 80, 7, 14, 2, 2, 80, 13, 3, 2, 2, 2, 81, 82, 7, 15, 2, 2, 82, 86, 5, 6, 4, 2, 83, 84, 7, 16, 2, 2, 84, 86, 5, 6, 4, 2, 85, 81, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 86, 15, 3, 2, 2, 2, 13, 22, 28, 35, 37, 43, 50, 64, 67, 70, 73, 85]
\ No newline at end of file
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makina.tokens b/makina-compiler/gen/xyz/colinholzman/makina/makina.tokens
new file mode 100644
index 0000000..b53eb61
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makina.tokens
@@ -0,0 +1,31 @@
+T__0=1
+T__1=2
+T__2=3
+T__3=4
+T__4=5
+T__5=6
+T__6=7
+T__7=8
+T__8=9
+T__9=10
+T__10=11
+T__11=12
+T__12=13
+T__13=14
+ID=15
+WHITESPACE=16
+COMMENT=17
+'machine'=1
+';'=2
+'initial'=3
+'state'=4
+'{'=5
+'}'=6
+'.'=7
+'entry'=8
+'exit'=9
+'on'=10
+'('=11
+')'=12
+'->'=13
+'>'=14
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makinaBaseListener.java b/makina-compiler/gen/xyz/colinholzman/makina/makinaBaseListener.java
new file mode 100644
index 0000000..2d4a386
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makinaBaseListener.java
@@ -0,0 +1,159 @@
+// Generated from /Users/colinholzman/makina/makina-compiler/src/makina.g4 by ANTLR 4.9.1
+package xyz.colinholzman.makina;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ErrorNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * This class provides an empty implementation of {@link makinaListener},
+ * which can be extended to create a listener which only needs to handle a subset
+ * of the available methods.
+ */
+public class makinaBaseListener implements makinaListener {
+ /**
+ * {@inheritDoc}
+ *
+ *
The default implementation does nothing.
+ */
+ @Override public void enterFile(makinaParser.FileContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitFile(makinaParser.FileContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterState(makinaParser.StateContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitState(makinaParser.StateContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterId(makinaParser.IdContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitId(makinaParser.IdContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterEntryHandler(makinaParser.EntryHandlerContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitEntryHandler(makinaParser.EntryHandlerContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterExitHandler(makinaParser.ExitHandlerContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitExitHandler(makinaParser.ExitHandlerContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterEventHandler(makinaParser.EventHandlerContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitEventHandler(makinaParser.EventHandlerContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterAction(makinaParser.ActionContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitAction(makinaParser.ActionContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterGuard(makinaParser.GuardContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitGuard(makinaParser.GuardContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterExternalTransition(makinaParser.ExternalTransitionContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitExternalTransition(makinaParser.ExternalTransitionContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterLocalTransition(makinaParser.LocalTransitionContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitLocalTransition(makinaParser.LocalTransitionContext ctx) { }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterEveryRule(ParserRuleContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitEveryRule(ParserRuleContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void visitTerminal(TerminalNode node) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void visitErrorNode(ErrorNode node) { }
+}
\ No newline at end of file
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makinaBaseVisitor.java b/makina-compiler/gen/xyz/colinholzman/makina/makinaBaseVisitor.java
new file mode 100644
index 0000000..d4440e2
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makinaBaseVisitor.java
@@ -0,0 +1,84 @@
+// Generated from /Users/colinholzman/makina/makina-compiler/src/makina.g4 by ANTLR 4.9.1
+package xyz.colinholzman.makina;
+import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
+
+/**
+ * This class provides an empty implementation of {@link makinaVisitor},
+ * which can be extended to create a visitor which only needs to handle a subset
+ * of the available methods.
+ *
+ * @param The return type of the visit operation. Use {@link Void} for
+ * operations with no return type.
+ */
+public class makinaBaseVisitor extends AbstractParseTreeVisitor implements makinaVisitor {
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitFile(makinaParser.FileContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitState(makinaParser.StateContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitId(makinaParser.IdContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitEntryHandler(makinaParser.EntryHandlerContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitExitHandler(makinaParser.ExitHandlerContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitEventHandler(makinaParser.EventHandlerContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitAction(makinaParser.ActionContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitGuard(makinaParser.GuardContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitExternalTransition(makinaParser.ExternalTransitionContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitLocalTransition(makinaParser.LocalTransitionContext ctx) { return visitChildren(ctx); }
+}
\ No newline at end of file
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.interp b/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.interp
new file mode 100644
index 0000000..4ab03b4
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.interp
@@ -0,0 +1,68 @@
+token literal names:
+null
+'machine'
+';'
+'initial'
+'state'
+'{'
+'}'
+'.'
+'entry'
+'exit'
+'on'
+'('
+')'
+'->'
+'>'
+null
+null
+null
+
+token symbolic names:
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+ID
+WHITESPACE
+COMMENT
+
+rule names:
+T__0
+T__1
+T__2
+T__3
+T__4
+T__5
+T__6
+T__7
+T__8
+T__9
+T__10
+T__11
+T__12
+T__13
+ID
+WHITESPACE
+COMMENT
+
+channel names:
+DEFAULT_TOKEN_CHANNEL
+HIDDEN
+
+mode names:
+DEFAULT_MODE
+
+atn:
+[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 19, 126, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 7, 16, 93, 10, 16, 12, 16, 14, 16, 96, 11, 16, 3, 16, 3, 16, 6, 16, 100, 10, 16, 13, 16, 14, 16, 101, 3, 16, 5, 16, 105, 10, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 7, 18, 115, 10, 18, 12, 18, 14, 18, 118, 11, 18, 3, 18, 5, 18, 121, 10, 18, 3, 18, 3, 18, 3, 18, 3, 18, 2, 2, 19, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 3, 2, 7, 5, 2, 67, 92, 97, 97, 99, 124, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 98, 98, 5, 2, 11, 12, 14, 15, 34, 34, 4, 2, 12, 12, 15, 15, 2, 130, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 3, 37, 3, 2, 2, 2, 5, 45, 3, 2, 2, 2, 7, 47, 3, 2, 2, 2, 9, 55, 3, 2, 2, 2, 11, 61, 3, 2, 2, 2, 13, 63, 3, 2, 2, 2, 15, 65, 3, 2, 2, 2, 17, 67, 3, 2, 2, 2, 19, 73, 3, 2, 2, 2, 21, 78, 3, 2, 2, 2, 23, 81, 3, 2, 2, 2, 25, 83, 3, 2, 2, 2, 27, 85, 3, 2, 2, 2, 29, 88, 3, 2, 2, 2, 31, 104, 3, 2, 2, 2, 33, 106, 3, 2, 2, 2, 35, 110, 3, 2, 2, 2, 37, 38, 7, 111, 2, 2, 38, 39, 7, 99, 2, 2, 39, 40, 7, 101, 2, 2, 40, 41, 7, 106, 2, 2, 41, 42, 7, 107, 2, 2, 42, 43, 7, 112, 2, 2, 43, 44, 7, 103, 2, 2, 44, 4, 3, 2, 2, 2, 45, 46, 7, 61, 2, 2, 46, 6, 3, 2, 2, 2, 47, 48, 7, 107, 2, 2, 48, 49, 7, 112, 2, 2, 49, 50, 7, 107, 2, 2, 50, 51, 7, 118, 2, 2, 51, 52, 7, 107, 2, 2, 52, 53, 7, 99, 2, 2, 53, 54, 7, 110, 2, 2, 54, 8, 3, 2, 2, 2, 55, 56, 7, 117, 2, 2, 56, 57, 7, 118, 2, 2, 57, 58, 7, 99, 2, 2, 58, 59, 7, 118, 2, 2, 59, 60, 7, 103, 2, 2, 60, 10, 3, 2, 2, 2, 61, 62, 7, 125, 2, 2, 62, 12, 3, 2, 2, 2, 63, 64, 7, 127, 2, 2, 64, 14, 3, 2, 2, 2, 65, 66, 7, 48, 2, 2, 66, 16, 3, 2, 2, 2, 67, 68, 7, 103, 2, 2, 68, 69, 7, 112, 2, 2, 69, 70, 7, 118, 2, 2, 70, 71, 7, 116, 2, 2, 71, 72, 7, 123, 2, 2, 72, 18, 3, 2, 2, 2, 73, 74, 7, 103, 2, 2, 74, 75, 7, 122, 2, 2, 75, 76, 7, 107, 2, 2, 76, 77, 7, 118, 2, 2, 77, 20, 3, 2, 2, 2, 78, 79, 7, 113, 2, 2, 79, 80, 7, 112, 2, 2, 80, 22, 3, 2, 2, 2, 81, 82, 7, 42, 2, 2, 82, 24, 3, 2, 2, 2, 83, 84, 7, 43, 2, 2, 84, 26, 3, 2, 2, 2, 85, 86, 7, 47, 2, 2, 86, 87, 7, 64, 2, 2, 87, 28, 3, 2, 2, 2, 88, 89, 7, 64, 2, 2, 89, 30, 3, 2, 2, 2, 90, 94, 9, 2, 2, 2, 91, 93, 9, 3, 2, 2, 92, 91, 3, 2, 2, 2, 93, 96, 3, 2, 2, 2, 94, 92, 3, 2, 2, 2, 94, 95, 3, 2, 2, 2, 95, 105, 3, 2, 2, 2, 96, 94, 3, 2, 2, 2, 97, 99, 7, 98, 2, 2, 98, 100, 10, 4, 2, 2, 99, 98, 3, 2, 2, 2, 100, 101, 3, 2, 2, 2, 101, 99, 3, 2, 2, 2, 101, 102, 3, 2, 2, 2, 102, 103, 3, 2, 2, 2, 103, 105, 7, 98, 2, 2, 104, 90, 3, 2, 2, 2, 104, 97, 3, 2, 2, 2, 105, 32, 3, 2, 2, 2, 106, 107, 9, 5, 2, 2, 107, 108, 3, 2, 2, 2, 108, 109, 8, 17, 2, 2, 109, 34, 3, 2, 2, 2, 110, 111, 7, 49, 2, 2, 111, 112, 7, 49, 2, 2, 112, 116, 3, 2, 2, 2, 113, 115, 10, 6, 2, 2, 114, 113, 3, 2, 2, 2, 115, 118, 3, 2, 2, 2, 116, 114, 3, 2, 2, 2, 116, 117, 3, 2, 2, 2, 117, 120, 3, 2, 2, 2, 118, 116, 3, 2, 2, 2, 119, 121, 7, 15, 2, 2, 120, 119, 3, 2, 2, 2, 120, 121, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 123, 7, 12, 2, 2, 123, 124, 3, 2, 2, 2, 124, 125, 8, 18, 2, 2, 125, 36, 3, 2, 2, 2, 8, 2, 94, 101, 104, 116, 120, 3, 8, 2, 2]
\ No newline at end of file
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.java b/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.java
new file mode 100644
index 0000000..779ab18
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.java
@@ -0,0 +1,151 @@
+// Generated from /Users/colinholzman/makina/makina-compiler/src/makina.g4 by ANTLR 4.9.1
+package xyz.colinholzman.makina;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.misc.*;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
+public class makinaLexer extends Lexer {
+ static { RuntimeMetaData.checkVersion("4.9.1", RuntimeMetaData.VERSION); }
+
+ protected static final DFA[] _decisionToDFA;
+ protected static final PredictionContextCache _sharedContextCache =
+ new PredictionContextCache();
+ public static final int
+ T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9,
+ T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, ID=15, WHITESPACE=16,
+ COMMENT=17;
+ public static String[] channelNames = {
+ "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
+ };
+
+ public static String[] modeNames = {
+ "DEFAULT_MODE"
+ };
+
+ private static String[] makeRuleNames() {
+ return new String[] {
+ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8",
+ "T__9", "T__10", "T__11", "T__12", "T__13", "ID", "WHITESPACE", "COMMENT"
+ };
+ }
+ public static final String[] ruleNames = makeRuleNames();
+
+ private static String[] makeLiteralNames() {
+ return new String[] {
+ null, "'machine'", "';'", "'initial'", "'state'", "'{'", "'}'", "'.'",
+ "'entry'", "'exit'", "'on'", "'('", "')'", "'->'", "'>'"
+ };
+ }
+ private static final String[] _LITERAL_NAMES = makeLiteralNames();
+ private static String[] makeSymbolicNames() {
+ return new String[] {
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, "ID", "WHITESPACE", "COMMENT"
+ };
+ }
+ private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
+ public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+ /**
+ * @deprecated Use {@link #VOCABULARY} instead.
+ */
+ @Deprecated
+ public static final String[] tokenNames;
+ static {
+ tokenNames = new String[_SYMBOLIC_NAMES.length];
+ for (int i = 0; i < tokenNames.length; i++) {
+ tokenNames[i] = VOCABULARY.getLiteralName(i);
+ if (tokenNames[i] == null) {
+ tokenNames[i] = VOCABULARY.getSymbolicName(i);
+ }
+
+ if (tokenNames[i] == null) {
+ tokenNames[i] = "";
+ }
+ }
+ }
+
+ @Override
+ @Deprecated
+ public String[] getTokenNames() {
+ return tokenNames;
+ }
+
+ @Override
+
+ public Vocabulary getVocabulary() {
+ return VOCABULARY;
+ }
+
+
+ public makinaLexer(CharStream input) {
+ super(input);
+ _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+ }
+
+ @Override
+ public String getGrammarFileName() { return "makina.g4"; }
+
+ @Override
+ public String[] getRuleNames() { return ruleNames; }
+
+ @Override
+ public String getSerializedATN() { return _serializedATN; }
+
+ @Override
+ public String[] getChannelNames() { return channelNames; }
+
+ @Override
+ public String[] getModeNames() { return modeNames; }
+
+ @Override
+ public ATN getATN() { return _ATN; }
+
+ public static final String _serializedATN =
+ "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\23~\b\1\4\2\t\2\4"+
+ "\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"+
+ "\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
+ "\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3"+
+ "\4\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\t\3\t\3\t"+
+ "\3\t\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\f\3\f\3\r\3\r\3\16\3\16\3\16"+
+ "\3\17\3\17\3\20\3\20\7\20]\n\20\f\20\16\20`\13\20\3\20\3\20\6\20d\n\20"+
+ "\r\20\16\20e\3\20\5\20i\n\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\7"+
+ "\22s\n\22\f\22\16\22v\13\22\3\22\5\22y\n\22\3\22\3\22\3\22\3\22\2\2\23"+
+ "\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20"+
+ "\37\21!\22#\23\3\2\7\5\2C\\aac|\6\2\62;C\\aac|\3\2bb\5\2\13\f\16\17\""+
+ "\"\4\2\f\f\17\17\2\u0082\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\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\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2"+
+ "\2\2\2!\3\2\2\2\2#\3\2\2\2\3%\3\2\2\2\5-\3\2\2\2\7/\3\2\2\2\t\67\3\2\2"+
+ "\2\13=\3\2\2\2\r?\3\2\2\2\17A\3\2\2\2\21C\3\2\2\2\23I\3\2\2\2\25N\3\2"+
+ "\2\2\27Q\3\2\2\2\31S\3\2\2\2\33U\3\2\2\2\35X\3\2\2\2\37h\3\2\2\2!j\3\2"+
+ "\2\2#n\3\2\2\2%&\7o\2\2&\'\7c\2\2\'(\7e\2\2()\7j\2\2)*\7k\2\2*+\7p\2\2"+
+ "+,\7g\2\2,\4\3\2\2\2-.\7=\2\2.\6\3\2\2\2/\60\7k\2\2\60\61\7p\2\2\61\62"+
+ "\7k\2\2\62\63\7v\2\2\63\64\7k\2\2\64\65\7c\2\2\65\66\7n\2\2\66\b\3\2\2"+
+ "\2\678\7u\2\289\7v\2\29:\7c\2\2:;\7v\2\2;<\7g\2\2<\n\3\2\2\2=>\7}\2\2"+
+ ">\f\3\2\2\2?@\7\177\2\2@\16\3\2\2\2AB\7\60\2\2B\20\3\2\2\2CD\7g\2\2DE"+
+ "\7p\2\2EF\7v\2\2FG\7t\2\2GH\7{\2\2H\22\3\2\2\2IJ\7g\2\2JK\7z\2\2KL\7k"+
+ "\2\2LM\7v\2\2M\24\3\2\2\2NO\7q\2\2OP\7p\2\2P\26\3\2\2\2QR\7*\2\2R\30\3"+
+ "\2\2\2ST\7+\2\2T\32\3\2\2\2UV\7/\2\2VW\7@\2\2W\34\3\2\2\2XY\7@\2\2Y\36"+
+ "\3\2\2\2Z^\t\2\2\2[]\t\3\2\2\\[\3\2\2\2]`\3\2\2\2^\\\3\2\2\2^_\3\2\2\2"+
+ "_i\3\2\2\2`^\3\2\2\2ac\7b\2\2bd\n\4\2\2cb\3\2\2\2de\3\2\2\2ec\3\2\2\2"+
+ "ef\3\2\2\2fg\3\2\2\2gi\7b\2\2hZ\3\2\2\2ha\3\2\2\2i \3\2\2\2jk\t\5\2\2"+
+ "kl\3\2\2\2lm\b\21\2\2m\"\3\2\2\2no\7\61\2\2op\7\61\2\2pt\3\2\2\2qs\n\6"+
+ "\2\2rq\3\2\2\2sv\3\2\2\2tr\3\2\2\2tu\3\2\2\2ux\3\2\2\2vt\3\2\2\2wy\7\17"+
+ "\2\2xw\3\2\2\2xy\3\2\2\2yz\3\2\2\2z{\7\f\2\2{|\3\2\2\2|}\b\22\2\2}$\3"+
+ "\2\2\2\b\2^ehtx\3\b\2\2";
+ public static final ATN _ATN =
+ new ATNDeserializer().deserialize(_serializedATN.toCharArray());
+ static {
+ _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
+ for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
+ _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
+ }
+ }
+}
\ No newline at end of file
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.tokens b/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.tokens
new file mode 100644
index 0000000..b53eb61
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makinaLexer.tokens
@@ -0,0 +1,31 @@
+T__0=1
+T__1=2
+T__2=3
+T__3=4
+T__4=5
+T__5=6
+T__6=7
+T__7=8
+T__8=9
+T__9=10
+T__10=11
+T__11=12
+T__12=13
+T__13=14
+ID=15
+WHITESPACE=16
+COMMENT=17
+'machine'=1
+';'=2
+'initial'=3
+'state'=4
+'{'=5
+'}'=6
+'.'=7
+'entry'=8
+'exit'=9
+'on'=10
+'('=11
+')'=12
+'->'=13
+'>'=14
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makinaListener.java b/makina-compiler/gen/xyz/colinholzman/makina/makinaListener.java
new file mode 100644
index 0000000..cc30b8c
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makinaListener.java
@@ -0,0 +1,120 @@
+// Generated from /Users/colinholzman/makina/makina-compiler/src/makina.g4 by ANTLR 4.9.1
+package xyz.colinholzman.makina;
+import org.antlr.v4.runtime.tree.ParseTreeListener;
+
+/**
+ * This interface defines a complete listener for a parse tree produced by
+ * {@link makinaParser}.
+ */
+public interface makinaListener extends ParseTreeListener {
+ /**
+ * Enter a parse tree produced by {@link makinaParser#file}.
+ * @param ctx the parse tree
+ */
+ void enterFile(makinaParser.FileContext ctx);
+ /**
+ * Exit a parse tree produced by {@link makinaParser#file}.
+ * @param ctx the parse tree
+ */
+ void exitFile(makinaParser.FileContext ctx);
+ /**
+ * Enter a parse tree produced by {@link makinaParser#state}.
+ * @param ctx the parse tree
+ */
+ void enterState(makinaParser.StateContext ctx);
+ /**
+ * Exit a parse tree produced by {@link makinaParser#state}.
+ * @param ctx the parse tree
+ */
+ void exitState(makinaParser.StateContext ctx);
+ /**
+ * Enter a parse tree produced by {@link makinaParser#id}.
+ * @param ctx the parse tree
+ */
+ void enterId(makinaParser.IdContext ctx);
+ /**
+ * Exit a parse tree produced by {@link makinaParser#id}.
+ * @param ctx the parse tree
+ */
+ void exitId(makinaParser.IdContext ctx);
+ /**
+ * Enter a parse tree produced by the {@code entryHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ */
+ void enterEntryHandler(makinaParser.EntryHandlerContext ctx);
+ /**
+ * Exit a parse tree produced by the {@code entryHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ */
+ void exitEntryHandler(makinaParser.EntryHandlerContext ctx);
+ /**
+ * Enter a parse tree produced by the {@code exitHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ */
+ void enterExitHandler(makinaParser.ExitHandlerContext ctx);
+ /**
+ * Exit a parse tree produced by the {@code exitHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ */
+ void exitExitHandler(makinaParser.ExitHandlerContext ctx);
+ /**
+ * Enter a parse tree produced by the {@code eventHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ */
+ void enterEventHandler(makinaParser.EventHandlerContext ctx);
+ /**
+ * Exit a parse tree produced by the {@code eventHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ */
+ void exitEventHandler(makinaParser.EventHandlerContext ctx);
+ /**
+ * Enter a parse tree produced by {@link makinaParser#action}.
+ * @param ctx the parse tree
+ */
+ void enterAction(makinaParser.ActionContext ctx);
+ /**
+ * Exit a parse tree produced by {@link makinaParser#action}.
+ * @param ctx the parse tree
+ */
+ void exitAction(makinaParser.ActionContext ctx);
+ /**
+ * Enter a parse tree produced by {@link makinaParser#guard}.
+ * @param ctx the parse tree
+ */
+ void enterGuard(makinaParser.GuardContext ctx);
+ /**
+ * Exit a parse tree produced by {@link makinaParser#guard}.
+ * @param ctx the parse tree
+ */
+ void exitGuard(makinaParser.GuardContext ctx);
+ /**
+ * Enter a parse tree produced by the {@code externalTransition}
+ * labeled alternative in {@link makinaParser#target}.
+ * @param ctx the parse tree
+ */
+ void enterExternalTransition(makinaParser.ExternalTransitionContext ctx);
+ /**
+ * Exit a parse tree produced by the {@code externalTransition}
+ * labeled alternative in {@link makinaParser#target}.
+ * @param ctx the parse tree
+ */
+ void exitExternalTransition(makinaParser.ExternalTransitionContext ctx);
+ /**
+ * Enter a parse tree produced by the {@code localTransition}
+ * labeled alternative in {@link makinaParser#target}.
+ * @param ctx the parse tree
+ */
+ void enterLocalTransition(makinaParser.LocalTransitionContext ctx);
+ /**
+ * Exit a parse tree produced by the {@code localTransition}
+ * labeled alternative in {@link makinaParser#target}.
+ * @param ctx the parse tree
+ */
+ void exitLocalTransition(makinaParser.LocalTransitionContext ctx);
+}
\ No newline at end of file
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makinaParser.java b/makina-compiler/gen/xyz/colinholzman/makina/makinaParser.java
new file mode 100644
index 0000000..ee7c8f9
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makinaParser.java
@@ -0,0 +1,721 @@
+// Generated from /Users/colinholzman/makina/makina-compiler/src/makina.g4 by ANTLR 4.9.1
+package xyz.colinholzman.makina;
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.misc.*;
+import org.antlr.v4.runtime.tree.*;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
+public class makinaParser extends Parser {
+ static { RuntimeMetaData.checkVersion("4.9.1", RuntimeMetaData.VERSION); }
+
+ protected static final DFA[] _decisionToDFA;
+ protected static final PredictionContextCache _sharedContextCache =
+ new PredictionContextCache();
+ public static final int
+ T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9,
+ T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, ID=15, WHITESPACE=16,
+ COMMENT=17;
+ public static final int
+ RULE_file = 0, RULE_state = 1, RULE_id = 2, RULE_handler = 3, RULE_action = 4,
+ RULE_guard = 5, RULE_target = 6;
+ private static String[] makeRuleNames() {
+ return new String[] {
+ "file", "state", "id", "handler", "action", "guard", "target"
+ };
+ }
+ public static final String[] ruleNames = makeRuleNames();
+
+ private static String[] makeLiteralNames() {
+ return new String[] {
+ null, "'machine'", "';'", "'initial'", "'state'", "'{'", "'}'", "'.'",
+ "'entry'", "'exit'", "'on'", "'('", "')'", "'->'", "'>'"
+ };
+ }
+ private static final String[] _LITERAL_NAMES = makeLiteralNames();
+ private static String[] makeSymbolicNames() {
+ return new String[] {
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, "ID", "WHITESPACE", "COMMENT"
+ };
+ }
+ private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
+ public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+ /**
+ * @deprecated Use {@link #VOCABULARY} instead.
+ */
+ @Deprecated
+ public static final String[] tokenNames;
+ static {
+ tokenNames = new String[_SYMBOLIC_NAMES.length];
+ for (int i = 0; i < tokenNames.length; i++) {
+ tokenNames[i] = VOCABULARY.getLiteralName(i);
+ if (tokenNames[i] == null) {
+ tokenNames[i] = VOCABULARY.getSymbolicName(i);
+ }
+
+ if (tokenNames[i] == null) {
+ tokenNames[i] = "";
+ }
+ }
+ }
+
+ @Override
+ @Deprecated
+ public String[] getTokenNames() {
+ return tokenNames;
+ }
+
+ @Override
+
+ public Vocabulary getVocabulary() {
+ return VOCABULARY;
+ }
+
+ @Override
+ public String getGrammarFileName() { return "makina.g4"; }
+
+ @Override
+ public String[] getRuleNames() { return ruleNames; }
+
+ @Override
+ public String getSerializedATN() { return _serializedATN; }
+
+ @Override
+ public ATN getATN() { return _ATN; }
+
+ public makinaParser(TokenStream input) {
+ super(input);
+ _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+ }
+
+ public static class FileContext extends ParserRuleContext {
+ public TerminalNode ID() { return getToken(makinaParser.ID, 0); }
+ public TerminalNode EOF() { return getToken(makinaParser.EOF, 0); }
+ public List state() {
+ return getRuleContexts(StateContext.class);
+ }
+ public StateContext state(int i) {
+ return getRuleContext(StateContext.class,i);
+ }
+ public FileContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_file; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterFile(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitFile(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitFile(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final FileContext file() throws RecognitionException {
+ FileContext _localctx = new FileContext(_ctx, getState());
+ enterRule(_localctx, 0, RULE_file);
+ int _la;
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(14);
+ match(T__0);
+ setState(15);
+ match(ID);
+ setState(16);
+ match(T__1);
+ setState(20);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ while (_la==T__2 || _la==T__3) {
+ {
+ {
+ setState(17);
+ state();
+ }
+ }
+ setState(22);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ }
+ setState(23);
+ match(EOF);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class StateContext extends ParserRuleContext {
+ public Token initial;
+ public IdContext id() {
+ return getRuleContext(IdContext.class,0);
+ }
+ public List handler() {
+ return getRuleContexts(HandlerContext.class);
+ }
+ public HandlerContext handler(int i) {
+ return getRuleContext(HandlerContext.class,i);
+ }
+ public List state() {
+ return getRuleContexts(StateContext.class);
+ }
+ public StateContext state(int i) {
+ return getRuleContext(StateContext.class,i);
+ }
+ public StateContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_state; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterState(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitState(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitState(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final StateContext state() throws RecognitionException {
+ StateContext _localctx = new StateContext(_ctx, getState());
+ enterRule(_localctx, 2, RULE_state);
+ int _la;
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(26);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==T__2) {
+ {
+ setState(25);
+ ((StateContext)_localctx).initial = match(T__2);
+ }
+ }
+
+ setState(28);
+ match(T__3);
+ setState(29);
+ id();
+ setState(30);
+ match(T__4);
+ setState(35);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__2) | (1L << T__3) | (1L << T__7) | (1L << T__8) | (1L << T__9))) != 0)) {
+ {
+ setState(33);
+ _errHandler.sync(this);
+ switch (_input.LA(1)) {
+ case T__7:
+ case T__8:
+ case T__9:
+ {
+ setState(31);
+ handler();
+ }
+ break;
+ case T__2:
+ case T__3:
+ {
+ setState(32);
+ state();
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ }
+ setState(37);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ }
+ setState(38);
+ match(T__5);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class IdContext extends ParserRuleContext {
+ public Token root;
+ public List ID() { return getTokens(makinaParser.ID); }
+ public TerminalNode ID(int i) {
+ return getToken(makinaParser.ID, i);
+ }
+ public IdContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_id; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterId(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitId(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitId(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final IdContext id() throws RecognitionException {
+ IdContext _localctx = new IdContext(_ctx, getState());
+ enterRule(_localctx, 4, RULE_id);
+ int _la;
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(41);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==T__6) {
+ {
+ setState(40);
+ ((IdContext)_localctx).root = match(T__6);
+ }
+ }
+
+ setState(43);
+ match(ID);
+ setState(48);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ while (_la==T__6) {
+ {
+ {
+ setState(44);
+ match(T__6);
+ setState(45);
+ match(ID);
+ }
+ }
+ setState(50);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class HandlerContext extends ParserRuleContext {
+ public HandlerContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_handler; }
+
+ public HandlerContext() { }
+ public void copyFrom(HandlerContext ctx) {
+ super.copyFrom(ctx);
+ }
+ }
+ public static class EntryHandlerContext extends HandlerContext {
+ public ActionContext action() {
+ return getRuleContext(ActionContext.class,0);
+ }
+ public EntryHandlerContext(HandlerContext ctx) { copyFrom(ctx); }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterEntryHandler(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitEntryHandler(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitEntryHandler(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+ public static class ExitHandlerContext extends HandlerContext {
+ public ActionContext action() {
+ return getRuleContext(ActionContext.class,0);
+ }
+ public ExitHandlerContext(HandlerContext ctx) { copyFrom(ctx); }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterExitHandler(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitExitHandler(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitExitHandler(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+ public static class EventHandlerContext extends HandlerContext {
+ public TerminalNode ID() { return getToken(makinaParser.ID, 0); }
+ public GuardContext guard() {
+ return getRuleContext(GuardContext.class,0);
+ }
+ public ActionContext action() {
+ return getRuleContext(ActionContext.class,0);
+ }
+ public TargetContext target() {
+ return getRuleContext(TargetContext.class,0);
+ }
+ public EventHandlerContext(HandlerContext ctx) { copyFrom(ctx); }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterEventHandler(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitEventHandler(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitEventHandler(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final HandlerContext handler() throws RecognitionException {
+ HandlerContext _localctx = new HandlerContext(_ctx, getState());
+ enterRule(_localctx, 6, RULE_handler);
+ int _la;
+ try {
+ setState(71);
+ _errHandler.sync(this);
+ switch (_input.LA(1)) {
+ case T__7:
+ _localctx = new EntryHandlerContext(_localctx);
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(51);
+ match(T__7);
+ setState(52);
+ action();
+ setState(53);
+ match(T__1);
+ }
+ break;
+ case T__8:
+ _localctx = new ExitHandlerContext(_localctx);
+ enterOuterAlt(_localctx, 2);
+ {
+ setState(55);
+ match(T__8);
+ setState(56);
+ action();
+ setState(57);
+ match(T__1);
+ }
+ break;
+ case T__9:
+ _localctx = new EventHandlerContext(_localctx);
+ enterOuterAlt(_localctx, 3);
+ {
+ setState(59);
+ match(T__9);
+ setState(60);
+ match(ID);
+ setState(62);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==T__10) {
+ {
+ setState(61);
+ guard();
+ }
+ }
+
+ setState(65);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==ID) {
+ {
+ setState(64);
+ action();
+ }
+ }
+
+ setState(68);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==T__12 || _la==T__13) {
+ {
+ setState(67);
+ target();
+ }
+ }
+
+ setState(70);
+ match(T__1);
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class ActionContext extends ParserRuleContext {
+ public TerminalNode ID() { return getToken(makinaParser.ID, 0); }
+ public ActionContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_action; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterAction(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitAction(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitAction(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final ActionContext action() throws RecognitionException {
+ ActionContext _localctx = new ActionContext(_ctx, getState());
+ enterRule(_localctx, 8, RULE_action);
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(73);
+ match(ID);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class GuardContext extends ParserRuleContext {
+ public TerminalNode ID() { return getToken(makinaParser.ID, 0); }
+ public GuardContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_guard; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterGuard(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitGuard(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitGuard(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final GuardContext guard() throws RecognitionException {
+ GuardContext _localctx = new GuardContext(_ctx, getState());
+ enterRule(_localctx, 10, RULE_guard);
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(75);
+ match(T__10);
+ setState(76);
+ match(ID);
+ setState(77);
+ match(T__11);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class TargetContext extends ParserRuleContext {
+ public TargetContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_target; }
+
+ public TargetContext() { }
+ public void copyFrom(TargetContext ctx) {
+ super.copyFrom(ctx);
+ }
+ }
+ public static class ExternalTransitionContext extends TargetContext {
+ public IdContext id() {
+ return getRuleContext(IdContext.class,0);
+ }
+ public ExternalTransitionContext(TargetContext ctx) { copyFrom(ctx); }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterExternalTransition(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitExternalTransition(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitExternalTransition(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+ public static class LocalTransitionContext extends TargetContext {
+ public IdContext id() {
+ return getRuleContext(IdContext.class,0);
+ }
+ public LocalTransitionContext(TargetContext ctx) { copyFrom(ctx); }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).enterLocalTransition(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof makinaListener ) ((makinaListener)listener).exitLocalTransition(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof makinaVisitor ) return ((makinaVisitor extends T>)visitor).visitLocalTransition(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final TargetContext target() throws RecognitionException {
+ TargetContext _localctx = new TargetContext(_ctx, getState());
+ enterRule(_localctx, 12, RULE_target);
+ try {
+ setState(83);
+ _errHandler.sync(this);
+ switch (_input.LA(1)) {
+ case T__12:
+ _localctx = new ExternalTransitionContext(_localctx);
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(79);
+ match(T__12);
+ setState(80);
+ id();
+ }
+ break;
+ case T__13:
+ _localctx = new LocalTransitionContext(_localctx);
+ enterOuterAlt(_localctx, 2);
+ {
+ setState(81);
+ match(T__13);
+ setState(82);
+ id();
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static final String _serializedATN =
+ "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\23X\4\2\t\2\4\3\t"+
+ "\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\3\2\3\2\3\2\3\2\7\2\25\n\2"+
+ "\f\2\16\2\30\13\2\3\2\3\2\3\3\5\3\35\n\3\3\3\3\3\3\3\3\3\3\3\7\3$\n\3"+
+ "\f\3\16\3\'\13\3\3\3\3\3\3\4\5\4,\n\4\3\4\3\4\3\4\7\4\61\n\4\f\4\16\4"+
+ "\64\13\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\5\5A\n\5\3\5\5\5"+
+ "D\n\5\3\5\5\5G\n\5\3\5\5\5J\n\5\3\6\3\6\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3"+
+ "\b\5\bV\n\b\3\b\2\2\t\2\4\6\b\n\f\16\2\2\2\\\2\20\3\2\2\2\4\34\3\2\2\2"+
+ "\6+\3\2\2\2\bI\3\2\2\2\nK\3\2\2\2\fM\3\2\2\2\16U\3\2\2\2\20\21\7\3\2\2"+
+ "\21\22\7\21\2\2\22\26\7\4\2\2\23\25\5\4\3\2\24\23\3\2\2\2\25\30\3\2\2"+
+ "\2\26\24\3\2\2\2\26\27\3\2\2\2\27\31\3\2\2\2\30\26\3\2\2\2\31\32\7\2\2"+
+ "\3\32\3\3\2\2\2\33\35\7\5\2\2\34\33\3\2\2\2\34\35\3\2\2\2\35\36\3\2\2"+
+ "\2\36\37\7\6\2\2\37 \5\6\4\2 %\7\7\2\2!$\5\b\5\2\"$\5\4\3\2#!\3\2\2\2"+
+ "#\"\3\2\2\2$\'\3\2\2\2%#\3\2\2\2%&\3\2\2\2&(\3\2\2\2\'%\3\2\2\2()\7\b"+
+ "\2\2)\5\3\2\2\2*,\7\t\2\2+*\3\2\2\2+,\3\2\2\2,-\3\2\2\2-\62\7\21\2\2."+
+ "/\7\t\2\2/\61\7\21\2\2\60.\3\2\2\2\61\64\3\2\2\2\62\60\3\2\2\2\62\63\3"+
+ "\2\2\2\63\7\3\2\2\2\64\62\3\2\2\2\65\66\7\n\2\2\66\67\5\n\6\2\678\7\4"+
+ "\2\28J\3\2\2\29:\7\13\2\2:;\5\n\6\2;<\7\4\2\2\7\f\2\2>@\7"+
+ "\21\2\2?A\5\f\7\2@?\3\2\2\2@A\3\2\2\2AC\3\2\2\2BD\5\n\6\2CB\3\2\2\2CD"+
+ "\3\2\2\2DF\3\2\2\2EG\5\16\b\2FE\3\2\2\2FG\3\2\2\2GH\3\2\2\2HJ\7\4\2\2"+
+ "I\65\3\2\2\2I9\3\2\2\2I=\3\2\2\2J\t\3\2\2\2KL\7\21\2\2L\13\3\2\2\2MN\7"+
+ "\r\2\2NO\7\21\2\2OP\7\16\2\2P\r\3\2\2\2QR\7\17\2\2RV\5\6\4\2ST\7\20\2"+
+ "\2TV\5\6\4\2UQ\3\2\2\2US\3\2\2\2V\17\3\2\2\2\r\26\34#%+\62@CFIU";
+ public static final ATN _ATN =
+ new ATNDeserializer().deserialize(_serializedATN.toCharArray());
+ static {
+ _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
+ for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
+ _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
+ }
+ }
+}
\ No newline at end of file
diff --git a/makina-compiler/gen/xyz/colinholzman/makina/makinaVisitor.java b/makina-compiler/gen/xyz/colinholzman/makina/makinaVisitor.java
new file mode 100644
index 0000000..e6e438d
--- /dev/null
+++ b/makina-compiler/gen/xyz/colinholzman/makina/makinaVisitor.java
@@ -0,0 +1,78 @@
+// Generated from /Users/colinholzman/makina/makina-compiler/src/makina.g4 by ANTLR 4.9.1
+package xyz.colinholzman.makina;
+import org.antlr.v4.runtime.tree.ParseTreeVisitor;
+
+/**
+ * This interface defines a complete generic visitor for a parse tree produced
+ * by {@link makinaParser}.
+ *
+ * @param The return type of the visit operation. Use {@link Void} for
+ * operations with no return type.
+ */
+public interface makinaVisitor extends ParseTreeVisitor {
+ /**
+ * Visit a parse tree produced by {@link makinaParser#file}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitFile(makinaParser.FileContext ctx);
+ /**
+ * Visit a parse tree produced by {@link makinaParser#state}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitState(makinaParser.StateContext ctx);
+ /**
+ * Visit a parse tree produced by {@link makinaParser#id}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitId(makinaParser.IdContext ctx);
+ /**
+ * Visit a parse tree produced by the {@code entryHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitEntryHandler(makinaParser.EntryHandlerContext ctx);
+ /**
+ * Visit a parse tree produced by the {@code exitHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitExitHandler(makinaParser.ExitHandlerContext ctx);
+ /**
+ * Visit a parse tree produced by the {@code eventHandler}
+ * labeled alternative in {@link makinaParser#handler}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitEventHandler(makinaParser.EventHandlerContext ctx);
+ /**
+ * Visit a parse tree produced by {@link makinaParser#action}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitAction(makinaParser.ActionContext ctx);
+ /**
+ * Visit a parse tree produced by {@link makinaParser#guard}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitGuard(makinaParser.GuardContext ctx);
+ /**
+ * Visit a parse tree produced by the {@code externalTransition}
+ * labeled alternative in {@link makinaParser#target}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitExternalTransition(makinaParser.ExternalTransitionContext ctx);
+ /**
+ * Visit a parse tree produced by the {@code localTransition}
+ * labeled alternative in {@link makinaParser#target}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitLocalTransition(makinaParser.LocalTransitionContext ctx);
+}
\ No newline at end of file
diff --git a/makina-compiler/src/makina.g4 b/makina-compiler/src/makina.g4
index 8eb88fe..b4c6565 100644
--- a/makina-compiler/src/makina.g4
+++ b/makina-compiler/src/makina.g4
@@ -27,7 +27,8 @@ guard
;
target
- : '->' id
+ : '->' id #externalTransition
+ | '>' id #localTransition
;
ID : ('_'|'a'..'z'|'A'..'Z') ('_'|'0'..'9'|'a'..'z'|'A'..'Z')*
diff --git a/makina-compiler/src/xyz/colinholzman/makina/CodeGenerator.kt b/makina-compiler/src/xyz/colinholzman/makina/CodeGenerator.kt
index 49830f9..3a93f40 100644
--- a/makina-compiler/src/xyz/colinholzman/makina/CodeGenerator.kt
+++ b/makina-compiler/src/xyz/colinholzman/makina/CodeGenerator.kt
@@ -55,7 +55,7 @@ class CodeGenerator(val machine: Machine,
private fun generateExitActions(handler: Handler.Event, sourceState: State, activeLeafState: State, output: PrintWriter) {
output.apply {
- if (handler.target.isNotEmpty()) {
+ if (handler.target != null) {
val target = handler.getTargetState(sourceState, machine)
val transition = Transition(activeLeafState, target)
val exitSet = transition.getExitSet()
@@ -71,7 +71,7 @@ class CodeGenerator(val machine: Machine,
private fun generateEntryActions(handler: Handler.Event, sourceState: State, activeLeafState: State, output: PrintWriter) {
output.apply {
- if (handler.target.isNotEmpty()) {
+ if (handler.target != null) {
val target = handler.getTargetState(sourceState, machine)
val transition = Transition(activeLeafState, target)
val entrySet = transition.getEntrySet() + target.getDefaultEntrySet()
diff --git a/makina-compiler/src/xyz/colinholzman/makina/Handler.kt b/makina-compiler/src/xyz/colinholzman/makina/Handler.kt
index 889da4a..c18a94d 100644
--- a/makina-compiler/src/xyz/colinholzman/makina/Handler.kt
+++ b/makina-compiler/src/xyz/colinholzman/makina/Handler.kt
@@ -39,15 +39,15 @@ sealed class Handler(location: SourceLocation): Node(location) {
}
class Event(val id: String, val guard: String? = null,
- val action: String? = null, val target: List = emptyList(),
+ val action: String? = null, val target: Target? = null,
location: SourceLocation = SourceLocation.none): Handler(location) {
fun getTargetState(source: State, machine: Machine): State {
- if (target.isEmpty()) throw RuntimeException("handler doesn't define a transition")
+ if (target == null) throw RuntimeException("handler doesn't define a transition")
//first look in the top level if the target is so specified
- if (target.first() == ".")
- return machine.states.find { it.getFullyQualifiedId() == target } ?:
+ if (target.id.first() == ".")
+ return machine.states.find { it.getFullyQualifiedId() == target.id } ?:
throw RuntimeException("target $target not found at $location")
//then look for the target among the children of the source state,
@@ -57,15 +57,15 @@ sealed class Handler(location: SourceLocation): Node(location) {
while (true) {
//append the scope's fully qualified name to the target
val fullTargetId =
- if (scope == null) listOf(".") + target
- else scope.getFullyQualifiedId() + target
+ if (scope == null) listOf(".") + target.id
+ else scope.getFullyQualifiedId() + target.id
//look for the fully qualified target among the states
val found = machine.states.find { it.getFullyQualifiedId() == fullTargetId }
if (found != null) return found
//if scope is null then we have looked everywhere
- if (scope == null) throw RuntimeException("target $target not found at $location")
+ if (scope == null) throw RuntimeException("target ${target.id} not found at $location")
else scope = scope.parent
}
}
diff --git a/makina-compiler/src/xyz/colinholzman/makina/HandlerVisitor.kt b/makina-compiler/src/xyz/colinholzman/makina/HandlerVisitor.kt
index 2c0327d..1b272f4 100644
--- a/makina-compiler/src/xyz/colinholzman/makina/HandlerVisitor.kt
+++ b/makina-compiler/src/xyz/colinholzman/makina/HandlerVisitor.kt
@@ -13,8 +13,7 @@ class HandlerVisitor: makinaBaseVisitor() {
val event = ctx!!.ID().text
val guard = if (ctx.guard() != null) ctx.guard().ID().text else null
val action = if (ctx.action() != null) ctx.action().ID().text else null
- val target = if (ctx.target() == null) emptyList()
- else ctx.target().id().accept(IdVisitor())
+ val target = if (ctx.target() == null) null else ctx.target().accept(TargetVisitor())
return Handler.Event(event, guard, action, target, SourceLocation.fromParseContext(ctx))
}
}
\ No newline at end of file
diff --git a/makina-compiler/src/xyz/colinholzman/makina/State.kt b/makina-compiler/src/xyz/colinholzman/makina/State.kt
index 58b5a82..96e6678 100644
--- a/makina-compiler/src/xyz/colinholzman/makina/State.kt
+++ b/makina-compiler/src/xyz/colinholzman/makina/State.kt
@@ -172,6 +172,11 @@ class State(val id: String,
}
return null
}
+
+ //returns true if all states are descendants of the same ancestor
+ fun List.areRelated(): Boolean {
+ return map { it.getStateConfiguration().getParentState() }.toSet().size == 1
+ }
}
}
\ No newline at end of file
diff --git a/makina-compiler/src/xyz/colinholzman/makina/StateConfiguration.kt b/makina-compiler/src/xyz/colinholzman/makina/StateConfiguration.kt
index 41478d3..0821436 100644
--- a/makina-compiler/src/xyz/colinholzman/makina/StateConfiguration.kt
+++ b/makina-compiler/src/xyz/colinholzman/makina/StateConfiguration.kt
@@ -33,6 +33,11 @@ data class StateConfiguration(val states: Set) {
return orderedStates.first()
}
+ //Returns the top level state of this configuration
+ fun getParentState(): State {
+ return orderedStates.last()
+ }
+
companion object {
fun List>.groupByIdAndRemoveRedundantHandlers(): Map>> {
return groupBy { it.second.id }.mapValues { entry ->
diff --git a/makina-compiler/src/xyz/colinholzman/makina/Target.kt b/makina-compiler/src/xyz/colinholzman/makina/Target.kt
new file mode 100644
index 0000000..470acd1
--- /dev/null
+++ b/makina-compiler/src/xyz/colinholzman/makina/Target.kt
@@ -0,0 +1,8 @@
+package xyz.colinholzman.makina
+
+data class Target(val id: List = emptyList(), val kind: Kind = Kind.EXTERNAL) {
+ enum class Kind {
+ EXTERNAL,
+ LOCAL
+ }
+}
\ No newline at end of file
diff --git a/makina-compiler/src/xyz/colinholzman/makina/TargetVisitor.kt b/makina-compiler/src/xyz/colinholzman/makina/TargetVisitor.kt
new file mode 100644
index 0000000..815c958
--- /dev/null
+++ b/makina-compiler/src/xyz/colinholzman/makina/TargetVisitor.kt
@@ -0,0 +1,13 @@
+package xyz.colinholzman.makina
+
+class TargetVisitor: makinaBaseVisitor() {
+ override fun visitExternalTransition(ctx: makinaParser.ExternalTransitionContext?): Target {
+ val targetId = ctx!!.id().accept(IdVisitor())
+ return Target(targetId, Target.Kind.EXTERNAL)
+ }
+
+ override fun visitLocalTransition(ctx: makinaParser.LocalTransitionContext?): Target {
+ val targetId = ctx!!.id().accept(IdVisitor())
+ return Target(targetId, Target.Kind.LOCAL)
+ }
+}
\ No newline at end of file
diff --git a/makina-compiler/src/xyz/colinholzman/makina/Transition.kt b/makina-compiler/src/xyz/colinholzman/makina/Transition.kt
index 3ea61c4..a2f3050 100644
--- a/makina-compiler/src/xyz/colinholzman/makina/Transition.kt
+++ b/makina-compiler/src/xyz/colinholzman/makina/Transition.kt
@@ -1,16 +1,37 @@
package xyz.colinholzman.makina
+import xyz.colinholzman.makina.State.Companion.areRelated
import xyz.colinholzman.makina.State.Companion.getLCCA
-data class Transition(val source: State, val target: State) {
+data class Transition(val source: State, val target: State, val kind: Target.Kind = Target.Kind.EXTERNAL) {
init {
if (!source.isLeafState())
throw RuntimeException("source must be a leaf state")
+ if (kind == Target.Kind.LOCAL) {
+ //The UML spec says local transitions can't have the same source and target,
+ //but I don't see why not, Yet...
+ //It seems like a useful way to 'restart' a sub state without triggering
+ //entry and exit actions for all parents
+ //if (source == target)
+ // throw RuntimeException("source must not equal target")
+ if (!listOf(source, target).areRelated())
+ throw RuntimeException("source and target must be related")
+ }
}
fun getEntrySet(): List {
- return (listOf(target) + target.getProperAncestors(listOf(source, target).getLCCA())).reversed()
+ return when (kind) {
+ Target.Kind.EXTERNAL ->
+ (listOf(target) + target.getProperAncestors(listOf(source, target).getLCCA())).reversed()
+ Target.Kind.LOCAL ->
+ TODO("same as for external but not including containing state")
+ }
}
fun getExitSet(): List {
- return listOf(source) + source.getProperAncestors(listOf(source, target).getLCCA())
+ return when (kind) {
+ Target.Kind.EXTERNAL ->
+ listOf(source) + source.getProperAncestors(listOf(source, target).getLCCA())
+ Target.Kind.LOCAL ->
+ TODO("same as for external but not including containing state")
+ }
}
}
\ No newline at end of file
diff --git a/makina-compiler/test/xyz/colinholzman/makina/HandlerTest.kt b/makina-compiler/test/xyz/colinholzman/makina/HandlerTest.kt
index 1bdba0d..6c84241 100644
--- a/makina-compiler/test/xyz/colinholzman/makina/HandlerTest.kt
+++ b/makina-compiler/test/xyz/colinholzman/makina/HandlerTest.kt
@@ -19,7 +19,7 @@ internal class HandlerTest {
val s1 = State("s1")
val s11 = State("s11", parentId = listOf(".", "s1"))
val s12 = State("s12", parentId = listOf(".", "s1"))
- val handler = Handler.Event("foo", target = listOf(".", "s2"))
+ val handler = Handler.Event("foo", target = Target(listOf(".", "s2")))
val s111 = State("s111", parentId = listOf(".", "s1", "s11"), handlers = listOf(handler))
val s2 = State("s2")
val machine = Machine("test", listOf(s1, s11, s12, s111, s2))
@@ -41,25 +41,25 @@ internal class HandlerTest {
@Test
fun getPartiallySpecifiedTargetState() {
- var handler = Handler.Event("foo", target = listOf("s11", "s111"))
+ var handler = Handler.Event("foo", target = Target(listOf("s11", "s111")))
assertEquals(s111, handler.getTargetState(s12, machine))
- handler = Handler.Event("foo", target = listOf("s121"))
+ handler = Handler.Event("foo", target = Target(listOf("s121")))
assertEquals(s121, handler.getTargetState(s12, machine))
- handler = Handler.Event("foo", target = listOf("s3", "s12"))
+ handler = Handler.Event("foo", target = Target(listOf("s3", "s12")))
assertEquals(s3_s12, handler.getTargetState(s1, machine))
- handler = Handler.Event("foo", target = listOf("s12"))
+ handler = Handler.Event("foo", target = Target(listOf("s12")))
assertEquals(s12, handler.getTargetState(s1, machine))
- handler = Handler.Event("foo", target = listOf(".", "s2"))
+ handler = Handler.Event("foo", target = Target(listOf(".", "s2")))
assertEquals(s2, handler.getTargetState(s3, machine))
- handler = Handler.Event("foo", target = listOf("s12"))
+ handler = Handler.Event("foo", target = Target(listOf("s12")))
assertEquals(s12, handler.getTargetState(s11, machine))
- handler = Handler.Event("foo", target = listOf("s1"))
+ handler = Handler.Event("foo", target = Target(listOf("s1")))
assertEquals(s1, handler.getTargetState(s2, machine))
}
}
\ No newline at end of file
diff --git a/makina-compiler/test/xyz/colinholzman/makina/ParseTest.kt b/makina-compiler/test/xyz/colinholzman/makina/ParseTest.kt
index ea27a19..835c762 100644
--- a/makina-compiler/test/xyz/colinholzman/makina/ParseTest.kt
+++ b/makina-compiler/test/xyz/colinholzman/makina/ParseTest.kt
@@ -60,7 +60,14 @@ internal class ParseTest {
@Test
fun testParseTransitionEventHandler() {
val actual = Parse.handler("on Foo -> bar;")
- val expected = Handler.Event("Foo", null, null, listOf("bar"))
+ val expected = Handler.Event("Foo", null, null, Target(listOf("bar")))
+ assertEquals(expected, actual)
+ }
+
+ @Test
+ fun testParseLocalTransitionEventHandler() {
+ val actual = Parse.handler("on Foo > bar;")
+ val expected = Handler.Event("Foo", null, null, Target(listOf("bar"), Target.Kind.LOCAL))
assertEquals(expected, actual)
}