1
0
Fork 0

Compare commits

...

71 Commits

Author SHA1 Message Date
Kevin Matz 1c499437d7 ship an example config file 2022-05-13 00:01:26 -04:00
Kevin Matz dd452d5c6c don't ship a server config file 2022-05-13 00:01:01 -04:00
Kevin Matz a34327a874 log correct data type 2022-05-12 23:21:19 -04:00
Kevin Matz c44effaed9 remove confusing comment 2022-05-12 23:20:54 -04:00
Kevin Matz f90bd45e5e rename the config load function 2022-05-12 23:19:40 -04:00
Kevin Matz c392edccf7 uniform logging 2022-05-12 19:53:08 -04:00
Kevin Matz 8b7ecad7bc include LISTENER and WALKER in package 2022-05-12 19:52:38 -04:00
Kevin Matz a2146940f7 use an f string for the error message 2022-05-12 19:16:58 -04:00
Kevin Matz 784f7df603 fix __init__.py for package 2022-05-12 19:16:44 -04:00
Kevin Matz 19de92834d build with ANTLR 4.10.1 2022-05-12 18:20:17 -04:00
Kevin Matz 8056c0098a generate with Antlr 4.9.1 2021-01-28 08:27:31 -05:00
Kevin Matz 5c7a2c937a key combo macros 2020-11-25 09:39:42 -05:00
Kevin Matz 5bf36be3be additional pep8 typing 2020-11-25 09:38:24 -05:00
Kevin Matz c6cba182d3 spell checking 2020-11-25 09:33:34 -05:00
Kevin Matz 75bc47c14e neutral default config 2020-11-23 12:32:27 -05:00
Kevin Matz 9ccf773ebc remove unused imports 2020-11-23 12:32:06 -05:00
Kevin Matz ef37f016d4 pep8 cleanups 2020-11-23 12:31:44 -05:00
Kevin Matz 17081bc219 correct members of the module 2020-11-23 12:28:35 -05:00
Kevin Matz fda1ba596e generated files with ANTLR 4.8 2020-11-22 15:14:44 -05:00
Kevin Matz 457e53109c delay loading config file 2019-11-18 22:23:51 -05:00
Kevin Matz 9532b1c003 move hog class to submodule 2019-11-18 21:49:11 -05:00
Kevin Matz 56ea58d7f8 cleanup logging 2019-11-18 20:07:48 -05:00
Kevin Matz d414c8424c move shell interpreter to own file 2019-11-18 13:22:31 -05:00
Kevin Matz 28c7abf62a initial import 2019-11-18 13:22:00 -05:00
Kevin Matz 62adeda686 update manifest 2019-11-18 13:21:47 -05:00
Kevin Matz 57a432f2bc re-organize file tree 2019-11-18 13:21:36 -05:00
Kevin Matz 7fd48be3bc add note about GOTO restrictions on master 2019-11-17 14:30:25 -05:00
Kevin Matz b8aec65ee7 only use relative imports when a module 2019-11-17 13:27:08 -05:00
Kevin Matz 3d7b0e13b5 correct variable names in error handler 2019-11-17 13:26:31 -05:00
Kevin Matz 232cd9814b tolerate quotes and whitespace 2019-11-17 13:26:00 -05:00
Kevin Matz a33da15c9f sanitize names, not the list 2019-11-17 13:25:18 -05:00
Kevin Matz 8a0a3b739d document with comments 2019-11-17 13:05:13 -05:00
Kevin Matz f9fe9237d0 remove config file from memory 2019-11-17 13:04:54 -05:00
Kevin Matz b095913334 allow exit keyword to be entered case-insensitive 2019-11-17 13:03:38 -05:00
Kevin Matz 92b7be3160 refactor to remove branch. no functional change, better readability 2019-11-17 13:03:04 -05:00
Kevin Matz 49201ce142 rename listener variable for readability 2019-11-17 13:00:37 -05:00
Kevin Matz 57951e2524 allow device names to be quoted 2019-11-17 12:59:32 -05:00
Kevin Matz d69583c60b refactor for multiple devices 2019-11-17 12:36:11 -05:00
Kevin Matz fcc44e6f49 parse text in upper case 2019-11-17 11:48:55 -05:00
Kevin Matz c1a7ad48b2 use intra-package references for imports 2019-11-01 10:25:08 -04:00
Kevin Matz 04994f6804 treat module as a python package 2019-11-01 10:12:50 -04:00
Kevin Matz bc1e5920db cleanup span calculation 2018-10-29 17:19:18 -10:00
Kevin Matz 860088078d allow spans to be bounded by floats 2018-10-29 07:53:49 -10:00
Kevin Matz 31c9c0b5d5 change assert to current master 2018-10-29 07:52:16 -10:00
Kevin Matz 2527b1b0f8 spellcheck the docs 2018-10-29 05:34:14 -10:00
Kevin Matz 39630e9cde better configuration defaults 2018-10-29 05:32:04 -10:00
Kevin Matz 9378112570 change antlr4 includes to specific members 2018-10-29 04:43:04 -10:00
Kevin Matz e7d0a59ccb append the syntaxErrorListener, don’t replace default 2018-10-29 04:42:29 -10:00
Kevin Matz 380621c52b reuse antlr walker objects each parser 2018-10-28 19:40:56 -10:00
Kevin Matz f38e5c77ee allow parser syntax errors to stop parser tree walking 2018-10-28 19:21:19 -10:00
Kevin Matz af2bd818da use standard names for logging 2018-10-28 18:27:25 -04:00
Kevin Matz 006229f0e0 correct logic for asserting current master 2018-10-28 18:20:00 -04:00
Kevin Matz 39410593ee include some comments in the example 2018-10-28 17:52:06 -04:00
Kevin Matz 35475a82e0 allow lines to be empty 2018-10-28 17:47:57 -04:00
Kevin Matz 9e5de3875b scripts are read by line. disallow multi-line comments 2018-10-28 17:41:23 -04:00
Kevin Matz 95b5510e15 provide feedback during WAIT 2018-10-28 17:35:16 -04:00
Kevin Matz 669f4163e9 introduce WAIT macro 2018-10-28 17:27:05 -04:00
Kevin Matz 9fc84b8241 accept EOF as valid reason to end 2018-10-28 17:12:12 -04:00
Kevin Matz b3e7c9c3ef add example baconscript file, with documentation 2018-10-28 17:11:49 -04:00
Kevin Matz 583a3f8a47 demote tree printing to debug logging level 2018-10-28 17:07:20 -04:00
Kevin Matz b807860ab4 FM must have a specified level 2018-10-28 16:59:21 -04:00
Kevin Matz db0f481769 fix inverted logic in RM 2018-10-28 16:58:01 -04:00
Kevin Matz bfe0898f0b cleanup unneeded rule label 2018-10-28 10:06:03 -04:00
Kevin Matz eb9a0b466d reduce parser memory usage by removing labels from unique rules 2018-10-28 10:02:51 -04:00
Kevin Matz 590cb39874 alternative label remove need for ‘op’ token label 2018-10-27 08:38:33 -04:00
Kevin Matz 3b48186a79 ListGo and ListGoto get implemented separately 2018-10-26 16:29:43 -04:00
Kevin Matz 90209dd49a cleanup imports 2018-10-26 16:21:48 -04:00
Kevin Matz 8e7eb1b8f9 use ANTLR alternative labeling to refine parser logic 2018-10-26 16:19:04 -04:00
Kevin Matz 1fa50e0387 use rule labeling to simplify parser 2018-10-26 15:26:18 -04:00
Kevin Matz b114208743 introduce rule labeling to parser 2018-10-26 15:25:35 -04:00
Kevin Matz 8600af3a9c allow script to exit naturally 2018-10-25 18:16:48 -04:00
25 changed files with 3705 additions and 2195 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
*.cfg
# Antlr4
*.interp
*.tokens

View File

@ -1,128 +0,0 @@
/*
The MIT License (MIT)
=====================
Copyright © 2018 Kevin Matz (kevin@company235.com)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
grammar CommentMacro;
/**
** Parser Rules
**/
prog : statement+ EOF ;
statement : macro (':' macro)* NEWLINE?
| NEWLINE
;
macro
: 'GM' master (device)? // Go Master
| 'GM' master SLASH number (device)? // Go Master
| 'HM' master (device)? // Halt Master
| 'AM' master (device)? // Assert Master
| 'RM' master (device)? // Relesae Master
| 'RA' (device)? // Release All
| 'RO' (device)? // Release Others
| 'FM' master SLASH number (time)? (device)? // Fade Master
| 'FGM' number (time)? (device)? // Fade Grand Master
| 'CM' number (device)? // Choose Master
| 'GL' target (device)? // Go List
| 'GL' target SLASH number (device)? // Go List
| 'HL' target (device)? // Halt List
| 'AL' target (device)? // Assert List
| 'RL' target (device)? // Release List
| 'GB' target (device)? // Go Batch
| 'HB' target (device)? // Halt Batch
| 'AB' target (device)? // Assert Batch
| 'RB' target (device)? // Release Batch
| 'GS' target (device)? // Go Scene
| 'HS' target (device)? // Halt Scene
| 'AS' target (device)? // Assert Scene
| 'RS' target (device)? // Release Scene
| 'CP' number (device)? // Change Page
| 'CP' NEXT (device)? // Next Page
| 'CP' PREV (device)? // Prev Page
| 'RV' number (device)? // Recall View
| 'RN' device // Reset Node
| 'GK' target (device)? // Go Keystroke Macro
| 'HK' target (device)? // Halt Keystroke Macro
| 'RK' target (device)? // Stop Keystroke Macro
;
master : (target | CURRENT) ;
time : TIME number ;
device : nodeType number ;
nodeType
: WHOLEHOG
| DP8K
| IOP
;
/** recursive targeting is non-greedy */
target
: ( number | span ) (',' target)*
;
span
: number THRU number
;
number : NUMBER ;
/**
** LEXAR Rules
**/
fragment DIGIT : [0-9] ;
NUMBER : DIGIT+ ('.' DIGIT+)? ;
SLASH : '/' ;
THRU : '>' ;
NEXT : '+' ;
PREV : '-' ;
CURRENT : '*' ;
TIME : 't' ;
WHOLEHOG : [hH] ;
DP8K : [dD] ;
IOP : 'IOP';
NEWLINE : '\r'? '\n' ; // return newlines to parser
WS : [ \t]+ -> skip ; // ignore whitespace
COMMENT // toss c and HTML sytle block comments
: ( '<!--' .*? '-->'
| '/*' .*? '*/'
) -> skip
;
LINE_COMMENT // ignore inline commkents
: ( '//' ~[\r\n]*
| '#' ~[\r\n]*
) -> skip
;

View File

@ -1,207 +0,0 @@
# Generated from CommentMacro.g4 by ANTLR 4.7.1
from antlr4 import *
from io import StringIO
from typing.io import TextIO
import sys
def serializedATN():
with StringIO() as buf:
buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2-")
buf.write("\u0111\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7")
buf.write("\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")
buf.write("\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23")
buf.write("\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30")
buf.write("\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36")
buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%")
buf.write("\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t-\3\2")
buf.write("\3\2\3\3\3\3\3\3\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6\3")
buf.write("\7\3\7\3\7\3\b\3\b\3\b\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13")
buf.write("\3\13\3\13\3\f\3\f\3\f\3\r\3\r\3\r\3\16\3\16\3\16\3\17")
buf.write("\3\17\3\17\3\20\3\20\3\20\3\21\3\21\3\21\3\22\3\22\3\22")
buf.write("\3\23\3\23\3\23\3\24\3\24\3\24\3\25\3\25\3\25\3\26\3\26")
buf.write("\3\26\3\27\3\27\3\27\3\30\3\30\3\30\3\31\3\31\3\31\3\32")
buf.write("\3\32\3\32\3\33\3\33\3\33\3\34\3\34\3\34\3\35\3\35\3\35")
buf.write("\3\36\3\36\3\37\3\37\3 \6 \u00b5\n \r \16 \u00b6\3 \3")
buf.write(" \6 \u00bb\n \r \16 \u00bc\5 \u00bf\n \3!\3!\3\"\3\"\3")
buf.write("#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3)\3)\3*\5")
buf.write("*\u00d6\n*\3*\3*\3+\6+\u00db\n+\r+\16+\u00dc\3+\3+\3,")
buf.write("\3,\3,\3,\3,\3,\7,\u00e7\n,\f,\16,\u00ea\13,\3,\3,\3,")
buf.write("\3,\3,\3,\3,\7,\u00f3\n,\f,\16,\u00f6\13,\3,\3,\5,\u00fa")
buf.write("\n,\3,\3,\3-\3-\3-\3-\7-\u0102\n-\f-\16-\u0105\13-\3-")
buf.write("\3-\7-\u0109\n-\f-\16-\u010c\13-\5-\u010e\n-\3-\3-\4\u00e8")
buf.write("\u00f4\2.\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25")
buf.write("\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+")
buf.write("\27-\30/\31\61\32\63\33\65\34\67\359\36;\37=\2? A!C\"")
buf.write("E#G$I%K&M\'O(Q)S*U+W,Y-\3\2\7\3\2\62;\4\2JJjj\4\2FFff")
buf.write("\4\2\13\13\"\"\4\2\f\f\17\17\2\u011a\2\3\3\2\2\2\2\5\3")
buf.write("\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")
buf.write("\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")
buf.write("\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")
buf.write("\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2")
buf.write("\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3")
buf.write("\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2")
buf.write("\2\2;\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2")
buf.write("\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3")
buf.write("\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y")
buf.write("\3\2\2\2\3[\3\2\2\2\5]\3\2\2\2\7`\3\2\2\2\tc\3\2\2\2\13")
buf.write("f\3\2\2\2\ri\3\2\2\2\17l\3\2\2\2\21o\3\2\2\2\23r\3\2\2")
buf.write("\2\25v\3\2\2\2\27y\3\2\2\2\31|\3\2\2\2\33\177\3\2\2\2")
buf.write("\35\u0082\3\2\2\2\37\u0085\3\2\2\2!\u0088\3\2\2\2#\u008b")
buf.write("\3\2\2\2%\u008e\3\2\2\2\'\u0091\3\2\2\2)\u0094\3\2\2\2")
buf.write("+\u0097\3\2\2\2-\u009a\3\2\2\2/\u009d\3\2\2\2\61\u00a0")
buf.write("\3\2\2\2\63\u00a3\3\2\2\2\65\u00a6\3\2\2\2\67\u00a9\3")
buf.write("\2\2\29\u00ac\3\2\2\2;\u00af\3\2\2\2=\u00b1\3\2\2\2?\u00b4")
buf.write("\3\2\2\2A\u00c0\3\2\2\2C\u00c2\3\2\2\2E\u00c4\3\2\2\2")
buf.write("G\u00c6\3\2\2\2I\u00c8\3\2\2\2K\u00ca\3\2\2\2M\u00cc\3")
buf.write("\2\2\2O\u00ce\3\2\2\2Q\u00d0\3\2\2\2S\u00d5\3\2\2\2U\u00da")
buf.write("\3\2\2\2W\u00f9\3\2\2\2Y\u010d\3\2\2\2[\\\7<\2\2\\\4\3")
buf.write("\2\2\2]^\7I\2\2^_\7O\2\2_\6\3\2\2\2`a\7J\2\2ab\7O\2\2")
buf.write("b\b\3\2\2\2cd\7C\2\2de\7O\2\2e\n\3\2\2\2fg\7T\2\2gh\7")
buf.write("O\2\2h\f\3\2\2\2ij\7T\2\2jk\7C\2\2k\16\3\2\2\2lm\7T\2")
buf.write("\2mn\7Q\2\2n\20\3\2\2\2op\7H\2\2pq\7O\2\2q\22\3\2\2\2")
buf.write("rs\7H\2\2st\7I\2\2tu\7O\2\2u\24\3\2\2\2vw\7E\2\2wx\7O")
buf.write("\2\2x\26\3\2\2\2yz\7I\2\2z{\7N\2\2{\30\3\2\2\2|}\7J\2")
buf.write("\2}~\7N\2\2~\32\3\2\2\2\177\u0080\7C\2\2\u0080\u0081\7")
buf.write("N\2\2\u0081\34\3\2\2\2\u0082\u0083\7T\2\2\u0083\u0084")
buf.write("\7N\2\2\u0084\36\3\2\2\2\u0085\u0086\7I\2\2\u0086\u0087")
buf.write("\7D\2\2\u0087 \3\2\2\2\u0088\u0089\7J\2\2\u0089\u008a")
buf.write("\7D\2\2\u008a\"\3\2\2\2\u008b\u008c\7C\2\2\u008c\u008d")
buf.write("\7D\2\2\u008d$\3\2\2\2\u008e\u008f\7T\2\2\u008f\u0090")
buf.write("\7D\2\2\u0090&\3\2\2\2\u0091\u0092\7I\2\2\u0092\u0093")
buf.write("\7U\2\2\u0093(\3\2\2\2\u0094\u0095\7J\2\2\u0095\u0096")
buf.write("\7U\2\2\u0096*\3\2\2\2\u0097\u0098\7C\2\2\u0098\u0099")
buf.write("\7U\2\2\u0099,\3\2\2\2\u009a\u009b\7T\2\2\u009b\u009c")
buf.write("\7U\2\2\u009c.\3\2\2\2\u009d\u009e\7E\2\2\u009e\u009f")
buf.write("\7R\2\2\u009f\60\3\2\2\2\u00a0\u00a1\7T\2\2\u00a1\u00a2")
buf.write("\7X\2\2\u00a2\62\3\2\2\2\u00a3\u00a4\7T\2\2\u00a4\u00a5")
buf.write("\7P\2\2\u00a5\64\3\2\2\2\u00a6\u00a7\7I\2\2\u00a7\u00a8")
buf.write("\7M\2\2\u00a8\66\3\2\2\2\u00a9\u00aa\7J\2\2\u00aa\u00ab")
buf.write("\7M\2\2\u00ab8\3\2\2\2\u00ac\u00ad\7T\2\2\u00ad\u00ae")
buf.write("\7M\2\2\u00ae:\3\2\2\2\u00af\u00b0\7.\2\2\u00b0<\3\2\2")
buf.write("\2\u00b1\u00b2\t\2\2\2\u00b2>\3\2\2\2\u00b3\u00b5\5=\37")
buf.write("\2\u00b4\u00b3\3\2\2\2\u00b5\u00b6\3\2\2\2\u00b6\u00b4")
buf.write("\3\2\2\2\u00b6\u00b7\3\2\2\2\u00b7\u00be\3\2\2\2\u00b8")
buf.write("\u00ba\7\60\2\2\u00b9\u00bb\5=\37\2\u00ba\u00b9\3\2\2")
buf.write("\2\u00bb\u00bc\3\2\2\2\u00bc\u00ba\3\2\2\2\u00bc\u00bd")
buf.write("\3\2\2\2\u00bd\u00bf\3\2\2\2\u00be\u00b8\3\2\2\2\u00be")
buf.write("\u00bf\3\2\2\2\u00bf@\3\2\2\2\u00c0\u00c1\7\61\2\2\u00c1")
buf.write("B\3\2\2\2\u00c2\u00c3\7@\2\2\u00c3D\3\2\2\2\u00c4\u00c5")
buf.write("\7-\2\2\u00c5F\3\2\2\2\u00c6\u00c7\7/\2\2\u00c7H\3\2\2")
buf.write("\2\u00c8\u00c9\7,\2\2\u00c9J\3\2\2\2\u00ca\u00cb\7v\2")
buf.write("\2\u00cbL\3\2\2\2\u00cc\u00cd\t\3\2\2\u00cdN\3\2\2\2\u00ce")
buf.write("\u00cf\t\4\2\2\u00cfP\3\2\2\2\u00d0\u00d1\7K\2\2\u00d1")
buf.write("\u00d2\7Q\2\2\u00d2\u00d3\7R\2\2\u00d3R\3\2\2\2\u00d4")
buf.write("\u00d6\7\17\2\2\u00d5\u00d4\3\2\2\2\u00d5\u00d6\3\2\2")
buf.write("\2\u00d6\u00d7\3\2\2\2\u00d7\u00d8\7\f\2\2\u00d8T\3\2")
buf.write("\2\2\u00d9\u00db\t\5\2\2\u00da\u00d9\3\2\2\2\u00db\u00dc")
buf.write("\3\2\2\2\u00dc\u00da\3\2\2\2\u00dc\u00dd\3\2\2\2\u00dd")
buf.write("\u00de\3\2\2\2\u00de\u00df\b+\2\2\u00dfV\3\2\2\2\u00e0")
buf.write("\u00e1\7>\2\2\u00e1\u00e2\7#\2\2\u00e2\u00e3\7/\2\2\u00e3")
buf.write("\u00e4\7/\2\2\u00e4\u00e8\3\2\2\2\u00e5\u00e7\13\2\2\2")
buf.write("\u00e6\u00e5\3\2\2\2\u00e7\u00ea\3\2\2\2\u00e8\u00e9\3")
buf.write("\2\2\2\u00e8\u00e6\3\2\2\2\u00e9\u00eb\3\2\2\2\u00ea\u00e8")
buf.write("\3\2\2\2\u00eb\u00ec\7/\2\2\u00ec\u00ed\7/\2\2\u00ed\u00fa")
buf.write("\7@\2\2\u00ee\u00ef\7\61\2\2\u00ef\u00f0\7,\2\2\u00f0")
buf.write("\u00f4\3\2\2\2\u00f1\u00f3\13\2\2\2\u00f2\u00f1\3\2\2")
buf.write("\2\u00f3\u00f6\3\2\2\2\u00f4\u00f5\3\2\2\2\u00f4\u00f2")
buf.write("\3\2\2\2\u00f5\u00f7\3\2\2\2\u00f6\u00f4\3\2\2\2\u00f7")
buf.write("\u00f8\7,\2\2\u00f8\u00fa\7\61\2\2\u00f9\u00e0\3\2\2\2")
buf.write("\u00f9\u00ee\3\2\2\2\u00fa\u00fb\3\2\2\2\u00fb\u00fc\b")
buf.write(",\2\2\u00fcX\3\2\2\2\u00fd\u00fe\7\61\2\2\u00fe\u00ff")
buf.write("\7\61\2\2\u00ff\u0103\3\2\2\2\u0100\u0102\n\6\2\2\u0101")
buf.write("\u0100\3\2\2\2\u0102\u0105\3\2\2\2\u0103\u0101\3\2\2\2")
buf.write("\u0103\u0104\3\2\2\2\u0104\u010e\3\2\2\2\u0105\u0103\3")
buf.write("\2\2\2\u0106\u010a\7%\2\2\u0107\u0109\n\6\2\2\u0108\u0107")
buf.write("\3\2\2\2\u0109\u010c\3\2\2\2\u010a\u0108\3\2\2\2\u010a")
buf.write("\u010b\3\2\2\2\u010b\u010e\3\2\2\2\u010c\u010a\3\2\2\2")
buf.write("\u010d\u00fd\3\2\2\2\u010d\u0106\3\2\2\2\u010e\u010f\3")
buf.write("\2\2\2\u010f\u0110\b-\2\2\u0110Z\3\2\2\2\16\2\u00b6\u00bc")
buf.write("\u00be\u00d5\u00dc\u00e8\u00f4\u00f9\u0103\u010a\u010d")
buf.write("\3\b\2\2")
return buf.getvalue()
class CommentMacroLexer(Lexer):
atn = ATNDeserializer().deserialize(serializedATN())
decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ]
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
T__14 = 15
T__15 = 16
T__16 = 17
T__17 = 18
T__18 = 19
T__19 = 20
T__20 = 21
T__21 = 22
T__22 = 23
T__23 = 24
T__24 = 25
T__25 = 26
T__26 = 27
T__27 = 28
T__28 = 29
NUMBER = 30
SLASH = 31
THRU = 32
NEXT = 33
PREV = 34
CURRENT = 35
TIME = 36
WHOLEHOG = 37
DP8K = 38
IOP = 39
NEWLINE = 40
WS = 41
COMMENT = 42
LINE_COMMENT = 43
channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
modeNames = [ "DEFAULT_MODE" ]
literalNames = [ "<INVALID>",
"':'", "'GM'", "'HM'", "'AM'", "'RM'", "'RA'", "'RO'", "'FM'",
"'FGM'", "'CM'", "'GL'", "'HL'", "'AL'", "'RL'", "'GB'", "'HB'",
"'AB'", "'RB'", "'GS'", "'HS'", "'AS'", "'RS'", "'CP'", "'RV'",
"'RN'", "'GK'", "'HK'", "'RK'", "','", "'/'", "'>'", "'+'",
"'-'", "'*'", "'t'", "'IOP'" ]
symbolicNames = [ "<INVALID>",
"NUMBER", "SLASH", "THRU", "NEXT", "PREV", "CURRENT", "TIME",
"WHOLEHOG", "DP8K", "IOP", "NEWLINE", "WS", "COMMENT", "LINE_COMMENT" ]
ruleNames = [ "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",
"T__14", "T__15", "T__16", "T__17", "T__18", "T__19",
"T__20", "T__21", "T__22", "T__23", "T__24", "T__25",
"T__26", "T__27", "T__28", "DIGIT", "NUMBER", "SLASH",
"THRU", "NEXT", "PREV", "CURRENT", "TIME", "WHOLEHOG",
"DP8K", "IOP", "NEWLINE", "WS", "COMMENT", "LINE_COMMENT" ]
grammarFileName = "CommentMacro.g4"
def __init__(self, input=None, output:TextIO = sys.stdout):
super().__init__(input, output)
self.checkVersion("4.7.1")
self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache())
self._actions = None
self._predicates = None

View File

@ -1,100 +0,0 @@
# Generated from CommentMacro.g4 by ANTLR 4.7.1
from antlr4 import *
if __name__ is not None and "." in __name__:
from .CommentMacroParser import CommentMacroParser
else:
from CommentMacroParser import CommentMacroParser
# This class defines a complete listener for a parse tree produced by CommentMacroParser.
class CommentMacroListener(ParseTreeListener):
# Enter a parse tree produced by CommentMacroParser#prog.
def enterProg(self, ctx:CommentMacroParser.ProgContext):
pass
# Exit a parse tree produced by CommentMacroParser#prog.
def exitProg(self, ctx:CommentMacroParser.ProgContext):
pass
# Enter a parse tree produced by CommentMacroParser#statement.
def enterStatement(self, ctx:CommentMacroParser.StatementContext):
pass
# Exit a parse tree produced by CommentMacroParser#statement.
def exitStatement(self, ctx:CommentMacroParser.StatementContext):
pass
# Enter a parse tree produced by CommentMacroParser#macro.
def enterMacro(self, ctx:CommentMacroParser.MacroContext):
pass
# Exit a parse tree produced by CommentMacroParser#macro.
def exitMacro(self, ctx:CommentMacroParser.MacroContext):
pass
# Enter a parse tree produced by CommentMacroParser#master.
def enterMaster(self, ctx:CommentMacroParser.MasterContext):
pass
# Exit a parse tree produced by CommentMacroParser#master.
def exitMaster(self, ctx:CommentMacroParser.MasterContext):
pass
# Enter a parse tree produced by CommentMacroParser#time.
def enterTime(self, ctx:CommentMacroParser.TimeContext):
pass
# Exit a parse tree produced by CommentMacroParser#time.
def exitTime(self, ctx:CommentMacroParser.TimeContext):
pass
# Enter a parse tree produced by CommentMacroParser#device.
def enterDevice(self, ctx:CommentMacroParser.DeviceContext):
pass
# Exit a parse tree produced by CommentMacroParser#device.
def exitDevice(self, ctx:CommentMacroParser.DeviceContext):
pass
# Enter a parse tree produced by CommentMacroParser#nodeType.
def enterNodeType(self, ctx:CommentMacroParser.NodeTypeContext):
pass
# Exit a parse tree produced by CommentMacroParser#nodeType.
def exitNodeType(self, ctx:CommentMacroParser.NodeTypeContext):
pass
# Enter a parse tree produced by CommentMacroParser#target.
def enterTarget(self, ctx:CommentMacroParser.TargetContext):
pass
# Exit a parse tree produced by CommentMacroParser#target.
def exitTarget(self, ctx:CommentMacroParser.TargetContext):
pass
# Enter a parse tree produced by CommentMacroParser#span.
def enterSpan(self, ctx:CommentMacroParser.SpanContext):
pass
# Exit a parse tree produced by CommentMacroParser#span.
def exitSpan(self, ctx:CommentMacroParser.SpanContext):
pass
# Enter a parse tree produced by CommentMacroParser#number.
def enterNumber(self, ctx:CommentMacroParser.NumberContext):
pass
# Exit a parse tree produced by CommentMacroParser#number.
def exitNumber(self, ctx:CommentMacroParser.NumberContext):
pass

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,4 @@
include comment.py
include CommentMacroLexer.py
include CommentMacroListener.py
include CommentMacroParser.py
include OscCommentMacroListener.py
include LICENSE.md
include README.md
include examples/example.bs
include server.cfg

View File

@ -1,115 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""OscCommentMacroListener.py: Hog 4 comment macro antlr4 listener for OSC."""
__author__ = "Kevin Matz"
__copyright__ = "Copyright 2018, Company 235, LLC"
__credits__ = ["Kevin Matz"]
__license__ = "MIT"
__version__ = "3.9"
__maintainer__ = "Kevin Matz"
__email__ = "kevin@company235.com"
__status__ = "Prototype"
import logging
import OscMacroDefinitions
from CommentMacroParser import CommentMacroParser
from CommentMacroListener import CommentMacroListener
logger = logging.getLogger("CommentMacro")
# https://raw.githubusercontent.com/jszheng/py3antlr4book/master/bin/pygrun
# this is a python version of TestRig
def beautify_lisp_string(in_string):
__author__ = 'jszheng'
indent_size = 2
add_indent = ' ' * indent_size
out_string = in_string[0] # no indent for 1st (
indent = ''
for i in range(1, len(in_string) - 1):
if in_string[i] == '(' and in_string[i + 1] != ' ':
indent += add_indent
out_string += "\n" + indent + '('
elif in_string[i] == ')':
out_string += ')'
if len(indent) > 0:
indent = indent.replace(add_indent, '', 1)
else:
out_string += in_string[i]
return out_string
class OscCommentMacroListener(CommentMacroListener):
def __init__(self, servers):
self.osc = OscMacroDefinitions.HogDevice(servers)
def enterMacro(self, ctx: CommentMacroParser.MacroContext):
ctx.device = None
ctx.number = None
ctx.master = None
ctx.targets = []
ctx.time = None
def exitMacro(self, ctx: CommentMacroParser.MacroContext):
# print the lisp tree of this macro
lisp_tree_str = ctx.toStringTree(recog=ctx.parser)
logger.info(beautify_lisp_string(lisp_tree_str))
# disallow duplicate targets
ctx.targets = set(ctx.targets)
# execute macro from name
name = ctx.children[0].getText()
try:
self.osc.command[name](self, ctx)
except KeyError:
print(name + " macro is not compatable with OSC.")
logger.debug("Exiting Macro")
def enterMaster(self, ctx: CommentMacroParser.MasterContext):
ctx.targets = []
def exitMaster(self, ctx: CommentMacroParser.MasterContext):
ctx.parentCtx.master = ctx
def enterTarget(self, ctx: CommentMacroParser.TargetContext):
ctx.targets = []
def exitTarget(self, ctx: CommentMacroParser.TargetContext):
ctx.parentCtx.targets.extend(ctx.targets) # add to parent targets
def exitNumber(self, ctx: CommentMacroParser.NumberContext):
try:
ctx.value = int(ctx.getText())
except ValueError:
ctx.value = float(ctx.getText())
if isinstance(ctx.parentCtx, CommentMacroParser.TargetContext):
ctx.parentCtx.targets.append(ctx.value)
else:
ctx.parentCtx.number = ctx
def exitSpan(self, ctx: CommentMacroParser.SpanContext):
number1 = ctx.children[0].value
number2 = ctx.children[2].value
if (isinstance(number1, int) and isinstance(number2, int)):
minimum = min(number1, number2)
maximum = max(number1, number2)
for i in (range(minimum, maximum + 1)):
ctx.parentCtx.targets.append(i)
else:
logger.error("ERROR: Spans must be ranged with intigers.")
def exitTime(self, ctx: CommentMacroParser.TimeContext):
ctx.parentCtx.time = ctx
def exitDevice(self, ctx: CommentMacroParser.DeviceContext):
ctx.parentCtx.device = ctx
def exitNodeType(self, ctx: CommentMacroParser.NodeTypeContext):
ctx.parentCtx.type = ctx.getText()

View File

@ -1,251 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""OscMacroDefinitions.py: Hog 4 comment macros in OSC for Python3."""
__author__ = "Kevin Matz"
__copyright__ = "Copyright 2018, Company 235, LLC"
__credits__ = ["Kevin Matz"]
__license__ = "MIT"
__version__ = "3.9"
__maintainer__ = "Kevin Matz"
__email__ = "kevin@company235.com"
__status__ = "Prototype"
import logging
from pythonosc import udp_client
from pythonosc import osc_message_builder
from pythonosc import osc_bundle_builder
from time import sleep
logger = logging.getLogger("CommentMacro")
class HogDevice():
# button state constants
buttonDOWN = 1
buttonUP = 0
def __init__(self, servers):
self.servers = servers
def button_press(self, device, path, delay=0.05):
self.send_message(device, path, HogDevice.buttonDOWN) # button down
sleep(delay)
self.send_message(device, path, HogDevice.buttonUP) # button up
# utility function to send simple messages with one argument
def send_message(self, device, path, arg):
msg = osc_message_builder.OscMessageBuilder(address=path)
msg.add_arg(arg)
self.send(device, msg.build())
# send python-osc messages
def send(self, device, msg):
if device is None:
osc = list(self.servers.values())[0]
else:
if (device.type != 'h'):
logger.error("ERROR: Only Hog type devices are supported.")
return
else:
try:
osc = self.servers[device.number.value]
except KeyError:
logger.error("ERROR: Net# " + str(device.number.value) +
" not found.")
return
try:
osc.send(msg)
except Exception as e:
logger.error(e)
def _master_go(self, ctx):
if ctx.number is not None:
logger.warn("GO MASTER doesn't support goto. " +
"Cue number "+str(ctx.number.value)+" is ignored.")
if (len(ctx.master.targets) == 0):
logger.info("Main GO")
self.osc.button_press(ctx.device, "/hog/hardware/maingo")
return
else:
for i in ctx.master.targets:
if isinstance(i, int) is not True:
logger.warn("GO MASTER macro targets must be intigers. "
+ str(i) + " is not an intigers.")
continue
if (i < 0):
logger.warn("Master "+str(i)+" is not greater than 0.")
continue
master = str(i)
logger.info("GO on master " + master)
self.osc.button_press(ctx.device, "/hog/hardware/go/" + master)
def _master_halt(self, ctx):
if (len(ctx.master.targets) == 0):
logger.info("Main HALT")
self.osc.button_press(ctx.device, "/hog/hardware/mainhalt")
return
else:
for i in ctx.master.targets:
if isinstance(i, int) is not True:
logger.warn("GO MASTER macro targets must be intigers. "
+ str(i) + " is not an intigers.")
continue
if (i < 0):
logger.warn("Master "+str(i)+" is not greater than 0.")
continue
master = str(i)
logger.info("HALT on master " + master)
self.osc.button_press(ctx.device,
"/hog/hardware/pause/" + master)
def _master_assert(self, ctx):
if (len(ctx.master.targets) != 0):
logger.error("ERROR: limited to asserting current master only.")
return
logger.info("ASSERT on current master.")
self.osc.button_press(ctx.device, "/hog/hardware/assert")
def _master_release(self, ctx):
if (len(ctx.master.targets) != 0):
logger.error("ERROR: limited to releasing current master only.")
return
logger.info("RELEASE on current master.")
self.osc.button_press(ctx.device, "/hog/hardware/release")
def _master_fade(self, ctx):
if (ctx.number) is None:
logger.error("ERROR: Missing required argument for LEVEL")
return
else:
level = ctx.number.value
if (level < 0 or level > 100):
logger.error("Level must be between 0 and 100.")
return
if (len(ctx.master.targets) == 0):
logger.error("MASTER FADE doesn't support * current master.")
return
else:
for i in ctx.master.targets:
if isinstance(i, int) is not True:
logger.warn("FADE MASTER macro targets must be intigers. "
+ str(i) + " is not an intigers.")
continue
if (i < 0):
logger.warn("Master "+str(i)+" is not greater than 0.")
continue
master = str(i)
logger.info("Fade Master "+master+" to "+str(level)+"%")
level *= 255 / 100 # percent in Macro, 0>255 in OSC
self.osc.send_message(ctx.device,
"/hog/hardware/fader/" + master,
level)
def _master_fade_grand(self, ctx):
level = ctx.number.value
if (level < 0 or level > 100):
logger.error("Level must be between 0 and 100.")
return
logger.info("Fading Grand Master to " + str(level) + "%")
level *= 255 / 100 # percent in Macro, 0>255 in OSC
self.osc.send_message(ctx.device, "/hog/hardware/fader/0", level)
def _master_choose(self, ctx):
if (ctx.number.value < 0):
logger.error("Master must be greater than 0.")
return
master = str(ctx.number.value)
logger.info("Choose Master " + master)
self.osc.button_press(ctx.device, "/hog/hardware/choose/" + master)
def _release_all(self, ctx):
logger.info("Release All")
self.osc.send_message(ctx.device, "/hog/hardware/pig",
HogDevice.buttonDOWN)
self.osc.button_press(ctx.device, "/hog/hardware/release")
self.osc.send_message(ctx.device, "/hog/hardware/pig",
HogDevice.buttonUP)
def _list_go(self, ctx):
for i in ctx.targets:
if ctx.number is not None:
list = str(i) + "." + str(ctx.number.value)
else:
list = i
logger.info("Go on List " + str(list))
self.osc.send_message(ctx.device, "/hog/playback/go/0", list)
def _list_halt(self, ctx):
for i in ctx.targets:
logger.info("Halting List " + str(i))
self.osc.send_message(ctx.device, "/hog/playback/halt/0", i)
def _list_release(self, ctx):
for i in ctx.targets:
logger.info("Releasing List " + str(i))
self.osc.send_message(ctx.device, "/hog/playback/release/0", i)
def _scene_go(self, ctx):
for i in ctx.targets:
logger.info("Go on Scene " + str(i))
self.osc.send_message(ctx.device, "/hog/playback/go/1", i)
def _scene_halt(self, ctx):
for i in ctx.targets:
logger.info("Halt Scene " + str(i))
self.osc.send_message(ctx.device, "/hog/playback/halt/1", i)
def _scene_release(self, ctx):
for i in ctx.targets:
logger.info("Release Scene " + str(i))
self.osc.send_message(ctx.device, "/hog/playback/release/1", i)
def _macro_go(self, ctx):
for i in ctx.targets:
logger.info("Go on Macro " + str(i))
self.osc.send_message(ctx.device, "/hog/playback/go/2", i)
def _macro_halt(self, ctx):
for i in ctx.targets:
logger.info("Pause Macro " + str(i))
self.osc.send_message(ctx.device, "/hog/playback/halt/2", i)
def _macro_release(self, ctx):
for i in ctx.targets:
logger.info("Stop Macro " + str(i))
self.osc.send_message(ctx.device, "/hog/playback/release/2", i)
def _page_change(self, ctx):
if ctx.number is not None:
logger.error("ERROR: changing page by number is unsupported.")
return
dir = ctx.children[1].getText()
if dir == '+':
logger.info("Next Page")
self.osc.button_press(ctx.device, "/hog/hardware/nextpage")
elif dir == '-':
logger.info("Previous Page")
self.osc.button_press(ctx.device, "/hog/hardware/backpage")
command = {"GM": _master_go,
"HM": _master_halt,
"AM": _master_assert,
"RM": _master_release,
"FM": _master_fade,
"FGM": _master_fade_grand,
"CM": _master_choose,
"RA": _release_all,
"GL": _list_go,
"HL": _list_halt,
"RL": _list_release,
"GS": _scene_go,
"HS": _scene_halt,
"RS": _scene_release,
"GK": _macro_go,
"HK": _macro_halt,
"RK": _macro_release,
"CP": _page_change
}

View File

@ -2,7 +2,7 @@
A theoretical exercise to control a Hog 4 via OSC, with comment macros.
The comment macro grammar described in `CommentMacro.g4` is based upon the Hog 3.9 manual, Chapter 22.4. The python3 implementation in `OscMacroDefinitions.py` is based on Chapter 24.2 in the same manual.
The comment macro grammar described in `CommentMacro.g4` is based upon the Hog 3.9 manual, Chapter 22.4. The python3 implementation in `OscCommentMacroListener.py` is based on Chapter 24.2 in the same manual.
Some macros are unsupported/unsupportable with this method. Some macro features, like timing, are not yet implemented. Refer to the **Features** table for specific notes.
@ -29,12 +29,14 @@ Edit `server.cfg` to the correct values for your Hog4.
$ ./comment.py
Adding Hog device at net# 1
comment# GL1
(macro GL
(target
(number 1)))
Go on List 1
comment# exit
Goodbye.
```
Run a baconscript file by passing the script file to `comment.py` as standard input.
```bash
$ ./comment.py < example.bs
```
## Developing
@ -53,23 +55,26 @@ $ antlr -Dlanguage=Python3 CommentMacro.g4
## Features
Only features that are supported in both OSC and Comment Macros are able to be
implemented in baconscript. This table lists all comment macros (as of 3.9)
that are implimented in python.
that are implemented in python.
| Grammar Feature | eg. | Supported |
| ----------------|-----|-----------|
| fade times | t5 | no |
| multiple targets | 1,2 | Yes |
| ranges | 1>4 | Yes, integers only |
| ranges | 1>4 | Yes, intervals of 1 |
| multiple macros | GM1:GL3 | Yes |
| network devices | h4 | Yes, H devices only |
| wait times | WAIT1 | BaconScript only; Continue script after n seconds.
Benefiting from the LL(*) parser provided by ANTLR, `multiple targets` and
`ranges` may be combined ad infinitum. This is a known deviation from the
Comment Macro syntax.
### Standard Macros
| Macro | Function | Supported | Notes |
|-------|----------|-----------|-------|
| GM | Go Master | Yes | |
| GM | Go Master | Yes | GOTO on current master only |
| HM | Halt Master | Yes | |
| AM | Assert Master | Partial | on current master only |
| RM | Release Master | Partial | on current master only |
@ -102,12 +107,24 @@ Comment Macro syntax.
| HK | Pause Keystroke Macro | Yes | |
| RK | Stop Keystroke Macro | Yes | . |
### Additional Macros
BaconScript also supports several macros that aren't present on Hog4, but become possible/desirable when wrapping OSC.
| Macro | Function | Notes |
|-------|----------|-------|
| INT | Select an Intensity Pallet | keypress macro |
| POS | Select a Position Pallet | keypress macro |
| COLR | Select a Colour Pallet | keypress macro |
| BEAM | Select a Beam Pallet | keypress macro |
| WAIT | Pause for n seconds | |
| PASS | Null instruction | |
## Future Work
Pleas feel welcome to submit pull requests or patches that enable support for:
* Sending target ranges as OSC arguments
* Hog4 does not support multiple agruments to a single path.
* Hog4 does not support multiple arguments to a single path.
* Send multi-macro line as an OSC batch
* HogOS 3.9 has a bug involving batches. Whereby only every-other member of the batch will be interpreted.
* Timing on master fades

23
__init__.py Normal file
View File

@ -0,0 +1,23 @@
"""Init for the baconscript package."""
from .bacon import (
HogNet,
beautify_lisp_string,
OscCommentMacroListener,
SyntaxErrorListener,
load_servers,
comment,
WALKER,
LISTENER,
)
__all__ = [
"HogNet",
"beautify_lisp_string",
"OscCommentMacroListener",
"SyntaxErrorListener",
"load_servers",
"comment",
"WALKER",
"LISTENER",
]

311
bacon/OscListener.py Normal file
View File

@ -0,0 +1,311 @@
"""OscCommentMacroListener.py: Hog 4 comment macro antlr4 listener for OSC."""
import logging
from time import sleep
from .commentmacro.CommentMacroParser import CommentMacroParser
from .commentmacro.CommentMacroListener import CommentMacroListener
__all__ = [
"beautify_lisp_string",
"OscCommentMacroListener",
]
log = logging.getLogger(__name__)
# https://raw.githubusercontent.com/jszheng/py3antlr4book/master/bin/pygrun
# this is a python version of TestRig
def beautify_lisp_string(in_string):
"""Prety output of a lisp string."""
# __author__ = 'jszheng'
indent_size = 2
add_indent = ' ' * indent_size
out_string = in_string[0] # no indent for 1st (
indent = ''
for i in range(1, len(in_string) - 1):
if in_string[i] == '(' and in_string[i + 1] != ' ':
indent += add_indent
out_string += "\n" + indent + '('
elif in_string[i] == ')':
out_string += ')'
if len(indent) > 0:
indent = indent.replace(add_indent, '', 1)
else:
out_string += in_string[i]
return out_string
class OscCommentMacroListener(CommentMacroListener):
"""antlr4 listener for comment macros."""
def __init__(self):
"""Initialize the listener."""
self.osc = None
def exitWait(self, ctx: CommentMacroParser.WaitContext):
"""On exiting the WAIT macro."""
log.info("Waiting %d seconds.", ctx.number().value)
sleep(ctx.number().value)
def enterStatement(self, ctx: CommentMacroParser.StatementContext):
"""On entering a statement."""
# print the lisp tree of this macro
lisp_tree_str = ctx.toStringTree(recog=ctx.parser)
log.debug(beautify_lisp_string(lisp_tree_str))
def enterTarget(self, ctx: CommentMacroParser.TargetContext):
"""On entering a target."""
ctx.targets = []
def exitTarget(self, ctx: CommentMacroParser.TargetContext):
"""On exiting a target."""
ctx.targets = set(ctx.targets)
if isinstance(ctx.parentCtx, CommentMacroParser.TargetContext):
ctx.parentCtx.targets.extend(ctx.targets) # add to parent targets
def exitNumber(self, ctx: CommentMacroParser.NumberContext):
"""On exiting a number."""
try:
ctx.value = int(ctx.getText())
except ValueError:
ctx.value = float(ctx.getText())
if isinstance(ctx.parentCtx, CommentMacroParser.TargetContext):
ctx.parentCtx.targets.append(ctx.value)
def exitSpan(self, ctx: CommentMacroParser.SpanContext):
"""On exiting a span."""
lower = min(ctx.n1.value, ctx.n2.value)
upper = max(ctx.n1.value, ctx.n2.value)
while lower <= upper:
ctx.parentCtx.targets.append(lower)
lower += 1
def exitMasterGo(self, ctx: CommentMacroParser.MasterGoContext):
"""On exiting a Go macro."""
if ctx.target() is None:
log.info("Main GO")
self.osc.button_press(ctx.device(), "/hog/hardware/maingo")
return
for i in ctx.target().targets:
if isinstance(i, int) is not True:
log.error("GO MASTER macro targets must be intigers.")
continue
if i < 0:
log.error("Master %d is not greater than 0.", i)
continue
master = str(i)
log.info("GO on master %s", master)
self.osc.button_press(ctx.device(), "/hog/hardware/go/" + master)
def exitMasterGoto(self, ctx: CommentMacroParser.MasterGotoContext):
"""On exiting a GOTO macro."""
if ctx.target() is not None:
log.error("ERROR: limited to GOTO on current master only.")
return
log.info("GOTO on current master.")
cue = str(ctx.number().value)
self.osc.button_press(ctx.device(), self.osc.buttonMap["goto"])
self.osc.number_entry(ctx.device(), cue)
self.osc.button_press(ctx.device(), self.osc.buttonMap["enter"])
def exitMasterHalt(self, ctx: CommentMacroParser.MasterHaltContext):
"""On exiting a Master Halt macro."""
if ctx.target() is None:
log.info("Main HALT")
self.osc.button_press(ctx.device(), "/hog/hardware/mainhalt")
return
for i in ctx.target().targets:
if isinstance(i, int) is not True:
log.error("GO MASTER macro targets must be intigers.")
continue
if i < 0:
log.error("Master %d is not greater than 0.", i)
continue
master = str(i)
log.info("HALT on master %s", master)
self.osc.button_press(ctx.device(), "/hog/hardware/pause/"+master)
def exitMasterAssert(self, ctx: CommentMacroParser.MasterAssertContext):
"""On exiting a Master Assert macro."""
if ctx.target() is not None:
log.error("ERROR: limited to asserting current master only.")
return
log.info("ASSERT on current master.")
self.osc.button_press(ctx.device(), "/hog/hardware/assert")
def exitMasterRelease(self, ctx: CommentMacroParser.MasterReleaseContext):
"""On exiting a Master Release macro."""
if ctx.target() is not None:
log.error("ERROR: limited to releasing current master only.")
return
log.info("RELEASE on current master.")
self.osc.button_press(ctx.device(), "/hog/hardware/release")
def exitMasterFade(self, ctx: CommentMacroParser.MasterFadeContext):
"""On exiting a Master Fade macro."""
if ctx.target() is None:
log.error("ERROR: limited to fading specified masters only.")
return
level = ctx.number().value
if (level < 0 or level > 100):
log.error("Level must be between 0 and 100.")
return
for i in ctx.target().targets:
if isinstance(i, int) is not True:
log.error("FADE MASTER macro targets must be intigers.")
continue
if i < 0:
log.error("Master %d is not greater than 0.", i)
continue
master = str(i)
log.info("Fade Master %s to %d", master, level)
level *= 255 / 100 # percent in Macro, 0>255 in OSC
self.osc.send_message(ctx.device(),
"/hog/hardware/fader/" + master,
level)
def exitFadeGrandMaster(self,
ctx: CommentMacroParser.FadeGrandMasterContext):
"""On exiting a GM Fade Macro."""
level = ctx.number().value
if (level < 0 or level > 100):
log.error("Level must be between 0 and 100.")
return
log.info("Fading Grand Master to %d", level)
level *= 255 / 100 # percent in Macro, 0>255 in OSC
self.osc.send_message(ctx.device(), "/hog/hardware/fader/0", level)
def exitMasterChoose(self, ctx: CommentMacroParser.MasterChooseContext):
"""On exiting a Master Choose macro."""
if ctx.number().value < 0:
log.error("Master must be greater than 0.")
return
master = str(ctx.number().value)
log.info("Choose Master %s", master)
self.osc.button_press(ctx.device(), "/hog/hardware/choose/" + master)
def exitReleaseAll(self, ctx: CommentMacroParser.ReleaseAllContext):
"""On exiting a Release All Macro."""
log.info("Release All")
self.osc.send_message(ctx.device(), "/hog/hardware/pig",
self.osc.buttonDOWN)
self.osc.button_press(ctx.device(), "/hog/hardware/release")
self.osc.send_message(ctx.device(), "/hog/hardware/pig",
self.osc.buttonUP)
def exitListGo(self, ctx: CommentMacroParser.ListGoContext):
"""On exiting a List GO macro."""
for i in ctx.target().targets:
log.info("Go on List %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/go/0", i)
def exitListGoto(self, ctx: CommentMacroParser.ListGotoContext):
"""On exiting a GOTO macro."""
for i in ctx.target().targets:
cuelist = str(i) + "." + str(ctx.number().value)
log.info("Go on List %s", cuelist)
self.osc.send_message(ctx.device(), "/hog/playback/go/0", list)
def exitListHalt(self, ctx: CommentMacroParser.ListHaltContext):
"""On exiting a Halt macro."""
for i in ctx.target().targets:
log.info("Halting List %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/halt/0", i)
def exitListRelese(self, ctx: CommentMacroParser.ListReleseContext):
"""On exiting a Release macro."""
for i in ctx.target().targets:
log.info("Releasing List %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/release/0", i)
def exitSceneGo(self, ctx: CommentMacroParser.SceneGoContext):
"""On exiting a Scene GO macro."""
for i in ctx.target().targets:
log.info("Go on Scene %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/go/1", i)
def exitSceneHalt(self, ctx: CommentMacroParser.SceneHaltContext):
"""On exiting a Scene Halt macro."""
for i in ctx.target().targets:
log.info("Halt Scene %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/halt/1", i)
def exitSceneRelease(self, ctx: CommentMacroParser.SceneReleaseContext):
"""On exiting a Scene Release macro."""
for i in ctx.target().targets:
log.info("Release Scene %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/release/1", i)
def exitMacroGo(self, ctx: CommentMacroParser.MacroGoContext):
"""On exiting a Macro GO macro."""
for i in ctx.target().targets:
log.info("Go on Macro %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/go/2", i)
def exitMacroHalt(self, ctx: CommentMacroParser.MacroHaltContext):
"""On exiting a Macro Halt macro."""
for i in ctx.target().targets:
log.info("Pause Macro %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/halt/2", i)
def exitMacroStop(self, ctx: CommentMacroParser.MacroStopContext):
"""On exiting a Macro Stop macro."""
for i in ctx.target().targets:
log.info("Stop Macro %d", i)
self.osc.send_message(ctx.device(), "/hog/playback/release/2", i)
def exitPageNext(self, ctx: CommentMacroParser.PageNextContext):
"""On exiting a Next Page macro."""
log.info("Next Page")
self.osc.button_press(ctx.device(), "/hog/hardware/nextpage")
def exitPagePrev(self, ctx: CommentMacroParser.PagePrevContext):
"""On exiting a Previous Page macro."""
log.info("Prev Page")
self.osc.button_press(ctx.device(), "/hog/hardware/backpage")
def exitSelectIntensity(self,
ctx: CommentMacroParser.SelectIntensityContext):
"""On exiting a Select Intensity macro."""
if ctx.number().value < 0:
log.error("Pallet must be greater than 0.")
return
pallet = str(ctx.number().value)
log.info("Selecting intensity pallet %s", pallet)
self.osc.button_press(ctx.device(), self.osc.buttonMap["intensity"])
self.osc.number_entry(ctx.device(), pallet)
self.osc.button_press(ctx.device(), self.osc.buttonMap["enter"])
def exitSelectPosition(self,
ctx: CommentMacroParser.SelectPositionContext):
"""On exiting a Select Intensity macro."""
if ctx.number().value < 0:
log.error("Pallet must be greater than 0.")
return
pallet = str(ctx.number().value)
log.info("Selecting position pallet %s", pallet)
self.osc.button_press(ctx.device(), self.osc.buttonMap["position"])
self.osc.number_entry(ctx.device(), pallet)
self.osc.button_press(ctx.device(), self.osc.buttonMap["enter"])
def exitSelectColour(self, ctx: CommentMacroParser.SelectColourContext):
"""On exiting a Select Intensity macro."""
if ctx.number().value < 0:
log.error("Pallet must be greater than 0.")
return
pallet = str(ctx.number().value)
log.info("Selecting colour pallet %s", pallet)
self.osc.button_press(ctx.device(), self.osc.buttonMap["colour"])
self.osc.number_entry(ctx.device(), pallet)
self.osc.button_press(ctx.device(), self.osc.buttonMap["enter"])
def exitSelectBeam(self, ctx: CommentMacroParser.SelectBeamContext):
"""On exiting a Select Intensity macro."""
if ctx.number().value < 0:
log.error("Pallet must be greater than 0.")
return
pallet = str(ctx.number().value)
log.info("Selecting beam pallet %s", pallet)
self.osc.button_press(ctx.device(), self.osc.buttonMap["beam"])
self.osc.number_entry(ctx.device(), pallet)
self.osc.button_press(ctx.device(), self.osc.buttonMap["enter"])

28
bacon/__init__.py Normal file
View File

@ -0,0 +1,28 @@
"""Main BaconScript module init."""
from .hog4 import HogNet
from .OscListener import beautify_lisp_string, OscCommentMacroListener
from .script import (
SyntaxErrorListener,
load_servers,
comment,
WALKER,
LISTENER
)
__all__ = [
"HogNet",
]
__all__ += [
"beautify_lisp_string",
"OscCommentMacroListener",
]
__all__ = [
"SyntaxErrorListener",
"load_servers",
"comment",
"WALKER",
"LISTENER",
]

View File

@ -0,0 +1,125 @@
/*
The MIT License (MIT)
=====================
Copyright © 2018 Kevin Matz (kevin@company235.com)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
grammar CommentMacro;
/**
** Parser Rules
**/
prog : statement* EOF;
statement : macro (':' macro)* NEWLINE?
| NEWLINE
;
macro
: 'GM' ( target | '*' ) device? #MasterGo
| 'GM' ( target | '*' ) '/' number device? #MasterGoto
| 'HM' ( target | '*' ) device? #MasterHalt
| 'AM' ( target | '*' ) device? #MasterAssert
| 'RM' ( target | '*' ) device? #MasterRelease
| 'RA' device? #ReleaseAll
| 'RO' device? #ReleaseOthers
| 'FM' ( target | '*' ) '/' number time? device? #MasterFade
| 'FGM' number time? device? #FadeGrandMaster
| 'CM' number device? #MasterChoose
| 'GL' target device? #ListGo
| 'GL' target '/' number device? #ListGoto
| 'HL' target device? #ListHalt
| 'AL' target device? #ListAssert
| 'RL' target device? #ListRelese
| 'GB' target device? #BatchGo
| 'HB' target device? #BatchHalt
| 'AB' target device? #BatchAssert
| 'RB' target device? #BatchRelease
| 'GS' target device? #SceneGo
| 'HS' target device? #SceneHalt
| 'AS' target device? #SceneAssert
| 'RS' target device? #SceneRelease
| 'CP' number device? #PageChange
| 'CP' '+' device? #PageNext
| 'CP' '-' device? #PagePrev
| 'RV' number device? #RecallView
| 'RN' device #NodeReset
| 'GK' target device? #MacroGo
| 'HK' target device? #MacroHalt
| 'RK' target device? #MacroStop
| 'INT' number device? #SelectIntensity
| 'POS' number device? #SelectPosition
| 'COLR' number device? #SelectColour
| 'BEAM' number device? #SelectBeam
| 'WAIT' number #Wait
| 'PASS' #Pass
;
time : TIME number ;
device : nodeType number ;
nodeType
: WHOLEHOG
| DP8K
| IOP
;
/** recursive targeting is non-greedy */
target
: ( number | span ) (',' target)*
;
span
: n1=number THRU n2=number
;
number : NUMBER ;
/**
** LEXAR Rules
**/
fragment DIGIT : [0-9] ;
NUMBER : DIGIT+ ('.' DIGIT+)? ;
THRU : '>' ;
CURRENT : '*' ;
TIME : 't' ;
WHOLEHOG : [hH] ;
DP8K : [dD] ;
IOP : 'IOP';
NEWLINE : '\r'? '\n' ; // return newlines to parser
WS : [ \t]+ -> skip ; // ignore whitespace
COMMENT // ignore inline commkents
: ( '//' ~[\r\n]*
| '#' ~[\r\n]*
) -> skip
;

View File

@ -0,0 +1,201 @@
# Generated from CommentMacro.g4 by ANTLR 4.10.1
from antlr4 import *
from io import StringIO
import sys
if sys.version_info[1] > 5:
from typing import TextIO
else:
from typing.io import TextIO
def serializedATN():
return [
4,0,48,280,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,
2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,
13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,
19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,
26,7,26,2,27,7,27,2,28,7,28,2,29,7,29,2,30,7,30,2,31,7,31,2,32,7,
32,2,33,7,33,2,34,7,34,2,35,7,35,2,36,7,36,2,37,7,37,2,38,7,38,2,
39,7,39,2,40,7,40,2,41,7,41,2,42,7,42,2,43,7,43,2,44,7,44,2,45,7,
45,2,46,7,46,2,47,7,47,2,48,7,48,1,0,1,0,1,1,1,1,1,1,1,2,1,2,1,3,
1,3,1,3,1,4,1,4,1,4,1,5,1,5,1,5,1,6,1,6,1,6,1,7,1,7,1,7,1,8,1,8,
1,8,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,11,1,11,1,11,1,12,1,12,1,12,
1,13,1,13,1,13,1,14,1,14,1,14,1,15,1,15,1,15,1,16,1,16,1,16,1,17,
1,17,1,17,1,18,1,18,1,18,1,19,1,19,1,19,1,20,1,20,1,20,1,21,1,21,
1,21,1,22,1,22,1,22,1,23,1,23,1,23,1,24,1,24,1,25,1,25,1,26,1,26,
1,26,1,27,1,27,1,27,1,28,1,28,1,28,1,29,1,29,1,29,1,30,1,30,1,30,
1,31,1,31,1,31,1,31,1,32,1,32,1,32,1,32,1,33,1,33,1,33,1,33,1,33,
1,34,1,34,1,34,1,34,1,34,1,35,1,35,1,35,1,35,1,35,1,36,1,36,1,36,
1,36,1,36,1,37,1,37,1,38,1,38,1,39,4,39,223,8,39,11,39,12,39,224,
1,39,1,39,4,39,229,8,39,11,39,12,39,230,3,39,233,8,39,1,40,1,40,
1,41,1,41,1,42,1,42,1,43,1,43,1,44,1,44,1,45,1,45,1,45,1,45,1,46,
3,46,250,8,46,1,46,1,46,1,47,4,47,255,8,47,11,47,12,47,256,1,47,
1,47,1,48,1,48,1,48,1,48,5,48,265,8,48,10,48,12,48,268,9,48,1,48,
1,48,5,48,272,8,48,10,48,12,48,275,9,48,3,48,277,8,48,1,48,1,48,
0,0,49,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,
25,13,27,14,29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,45,23,
47,24,49,25,51,26,53,27,55,28,57,29,59,30,61,31,63,32,65,33,67,34,
69,35,71,36,73,37,75,38,77,0,79,39,81,40,83,41,85,42,87,43,89,44,
91,45,93,46,95,47,97,48,1,0,5,1,0,48,57,2,0,72,72,104,104,2,0,68,
68,100,100,2,0,9,9,32,32,2,0,10,10,13,13,286,0,1,1,0,0,0,0,3,1,0,
0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0,0,13,1,0,0,
0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23,1,0,0,
0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,
0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,43,1,0,0,
0,0,45,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,0,0,
0,0,55,1,0,0,0,0,57,1,0,0,0,0,59,1,0,0,0,0,61,1,0,0,0,0,63,1,0,0,
0,0,65,1,0,0,0,0,67,1,0,0,0,0,69,1,0,0,0,0,71,1,0,0,0,0,73,1,0,0,
0,0,75,1,0,0,0,0,79,1,0,0,0,0,81,1,0,0,0,0,83,1,0,0,0,0,85,1,0,0,
0,0,87,1,0,0,0,0,89,1,0,0,0,0,91,1,0,0,0,0,93,1,0,0,0,0,95,1,0,0,
0,0,97,1,0,0,0,1,99,1,0,0,0,3,101,1,0,0,0,5,104,1,0,0,0,7,106,1,
0,0,0,9,109,1,0,0,0,11,112,1,0,0,0,13,115,1,0,0,0,15,118,1,0,0,0,
17,121,1,0,0,0,19,124,1,0,0,0,21,128,1,0,0,0,23,131,1,0,0,0,25,134,
1,0,0,0,27,137,1,0,0,0,29,140,1,0,0,0,31,143,1,0,0,0,33,146,1,0,
0,0,35,149,1,0,0,0,37,152,1,0,0,0,39,155,1,0,0,0,41,158,1,0,0,0,
43,161,1,0,0,0,45,164,1,0,0,0,47,167,1,0,0,0,49,170,1,0,0,0,51,172,
1,0,0,0,53,174,1,0,0,0,55,177,1,0,0,0,57,180,1,0,0,0,59,183,1,0,
0,0,61,186,1,0,0,0,63,189,1,0,0,0,65,193,1,0,0,0,67,197,1,0,0,0,
69,202,1,0,0,0,71,207,1,0,0,0,73,212,1,0,0,0,75,217,1,0,0,0,77,219,
1,0,0,0,79,222,1,0,0,0,81,234,1,0,0,0,83,236,1,0,0,0,85,238,1,0,
0,0,87,240,1,0,0,0,89,242,1,0,0,0,91,244,1,0,0,0,93,249,1,0,0,0,
95,254,1,0,0,0,97,276,1,0,0,0,99,100,5,58,0,0,100,2,1,0,0,0,101,
102,5,71,0,0,102,103,5,77,0,0,103,4,1,0,0,0,104,105,5,47,0,0,105,
6,1,0,0,0,106,107,5,72,0,0,107,108,5,77,0,0,108,8,1,0,0,0,109,110,
5,65,0,0,110,111,5,77,0,0,111,10,1,0,0,0,112,113,5,82,0,0,113,114,
5,77,0,0,114,12,1,0,0,0,115,116,5,82,0,0,116,117,5,65,0,0,117,14,
1,0,0,0,118,119,5,82,0,0,119,120,5,79,0,0,120,16,1,0,0,0,121,122,
5,70,0,0,122,123,5,77,0,0,123,18,1,0,0,0,124,125,5,70,0,0,125,126,
5,71,0,0,126,127,5,77,0,0,127,20,1,0,0,0,128,129,5,67,0,0,129,130,
5,77,0,0,130,22,1,0,0,0,131,132,5,71,0,0,132,133,5,76,0,0,133,24,
1,0,0,0,134,135,5,72,0,0,135,136,5,76,0,0,136,26,1,0,0,0,137,138,
5,65,0,0,138,139,5,76,0,0,139,28,1,0,0,0,140,141,5,82,0,0,141,142,
5,76,0,0,142,30,1,0,0,0,143,144,5,71,0,0,144,145,5,66,0,0,145,32,
1,0,0,0,146,147,5,72,0,0,147,148,5,66,0,0,148,34,1,0,0,0,149,150,
5,65,0,0,150,151,5,66,0,0,151,36,1,0,0,0,152,153,5,82,0,0,153,154,
5,66,0,0,154,38,1,0,0,0,155,156,5,71,0,0,156,157,5,83,0,0,157,40,
1,0,0,0,158,159,5,72,0,0,159,160,5,83,0,0,160,42,1,0,0,0,161,162,
5,65,0,0,162,163,5,83,0,0,163,44,1,0,0,0,164,165,5,82,0,0,165,166,
5,83,0,0,166,46,1,0,0,0,167,168,5,67,0,0,168,169,5,80,0,0,169,48,
1,0,0,0,170,171,5,43,0,0,171,50,1,0,0,0,172,173,5,45,0,0,173,52,
1,0,0,0,174,175,5,82,0,0,175,176,5,86,0,0,176,54,1,0,0,0,177,178,
5,82,0,0,178,179,5,78,0,0,179,56,1,0,0,0,180,181,5,71,0,0,181,182,
5,75,0,0,182,58,1,0,0,0,183,184,5,72,0,0,184,185,5,75,0,0,185,60,
1,0,0,0,186,187,5,82,0,0,187,188,5,75,0,0,188,62,1,0,0,0,189,190,
5,73,0,0,190,191,5,78,0,0,191,192,5,84,0,0,192,64,1,0,0,0,193,194,
5,80,0,0,194,195,5,79,0,0,195,196,5,83,0,0,196,66,1,0,0,0,197,198,
5,67,0,0,198,199,5,79,0,0,199,200,5,76,0,0,200,201,5,82,0,0,201,
68,1,0,0,0,202,203,5,66,0,0,203,204,5,69,0,0,204,205,5,65,0,0,205,
206,5,77,0,0,206,70,1,0,0,0,207,208,5,87,0,0,208,209,5,65,0,0,209,
210,5,73,0,0,210,211,5,84,0,0,211,72,1,0,0,0,212,213,5,80,0,0,213,
214,5,65,0,0,214,215,5,83,0,0,215,216,5,83,0,0,216,74,1,0,0,0,217,
218,5,44,0,0,218,76,1,0,0,0,219,220,7,0,0,0,220,78,1,0,0,0,221,223,
3,77,38,0,222,221,1,0,0,0,223,224,1,0,0,0,224,222,1,0,0,0,224,225,
1,0,0,0,225,232,1,0,0,0,226,228,5,46,0,0,227,229,3,77,38,0,228,227,
1,0,0,0,229,230,1,0,0,0,230,228,1,0,0,0,230,231,1,0,0,0,231,233,
1,0,0,0,232,226,1,0,0,0,232,233,1,0,0,0,233,80,1,0,0,0,234,235,5,
62,0,0,235,82,1,0,0,0,236,237,5,42,0,0,237,84,1,0,0,0,238,239,5,
116,0,0,239,86,1,0,0,0,240,241,7,1,0,0,241,88,1,0,0,0,242,243,7,
2,0,0,243,90,1,0,0,0,244,245,5,73,0,0,245,246,5,79,0,0,246,247,5,
80,0,0,247,92,1,0,0,0,248,250,5,13,0,0,249,248,1,0,0,0,249,250,1,
0,0,0,250,251,1,0,0,0,251,252,5,10,0,0,252,94,1,0,0,0,253,255,7,
3,0,0,254,253,1,0,0,0,255,256,1,0,0,0,256,254,1,0,0,0,256,257,1,
0,0,0,257,258,1,0,0,0,258,259,6,47,0,0,259,96,1,0,0,0,260,261,5,
47,0,0,261,262,5,47,0,0,262,266,1,0,0,0,263,265,8,4,0,0,264,263,
1,0,0,0,265,268,1,0,0,0,266,264,1,0,0,0,266,267,1,0,0,0,267,277,
1,0,0,0,268,266,1,0,0,0,269,273,5,35,0,0,270,272,8,4,0,0,271,270,
1,0,0,0,272,275,1,0,0,0,273,271,1,0,0,0,273,274,1,0,0,0,274,277,
1,0,0,0,275,273,1,0,0,0,276,260,1,0,0,0,276,269,1,0,0,0,277,278,
1,0,0,0,278,279,6,48,0,0,279,98,1,0,0,0,9,0,224,230,232,249,256,
266,273,276,1,6,0,0
]
class CommentMacroLexer(Lexer):
atn = ATNDeserializer().deserialize(serializedATN())
decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ]
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
T__14 = 15
T__15 = 16
T__16 = 17
T__17 = 18
T__18 = 19
T__19 = 20
T__20 = 21
T__21 = 22
T__22 = 23
T__23 = 24
T__24 = 25
T__25 = 26
T__26 = 27
T__27 = 28
T__28 = 29
T__29 = 30
T__30 = 31
T__31 = 32
T__32 = 33
T__33 = 34
T__34 = 35
T__35 = 36
T__36 = 37
T__37 = 38
NUMBER = 39
THRU = 40
CURRENT = 41
TIME = 42
WHOLEHOG = 43
DP8K = 44
IOP = 45
NEWLINE = 46
WS = 47
COMMENT = 48
channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
modeNames = [ "DEFAULT_MODE" ]
literalNames = [ "<INVALID>",
"':'", "'GM'", "'/'", "'HM'", "'AM'", "'RM'", "'RA'", "'RO'",
"'FM'", "'FGM'", "'CM'", "'GL'", "'HL'", "'AL'", "'RL'", "'GB'",
"'HB'", "'AB'", "'RB'", "'GS'", "'HS'", "'AS'", "'RS'", "'CP'",
"'+'", "'-'", "'RV'", "'RN'", "'GK'", "'HK'", "'RK'", "'INT'",
"'POS'", "'COLR'", "'BEAM'", "'WAIT'", "'PASS'", "','", "'>'",
"'*'", "'t'", "'IOP'" ]
symbolicNames = [ "<INVALID>",
"NUMBER", "THRU", "CURRENT", "TIME", "WHOLEHOG", "DP8K", "IOP",
"NEWLINE", "WS", "COMMENT" ]
ruleNames = [ "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",
"T__14", "T__15", "T__16", "T__17", "T__18", "T__19",
"T__20", "T__21", "T__22", "T__23", "T__24", "T__25",
"T__26", "T__27", "T__28", "T__29", "T__30", "T__31",
"T__32", "T__33", "T__34", "T__35", "T__36", "T__37",
"DIGIT", "NUMBER", "THRU", "CURRENT", "TIME", "WHOLEHOG",
"DP8K", "IOP", "NEWLINE", "WS", "COMMENT" ]
grammarFileName = "CommentMacro.g4"
def __init__(self, input=None, output:TextIO = sys.stdout):
super().__init__(input, output)
self.checkVersion("4.10.1")
self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache())
self._actions = None
self._predicates = None

View File

@ -0,0 +1,417 @@
# Generated from CommentMacro.g4 by ANTLR 4.10.1
from antlr4 import *
if __name__ is not None and "." in __name__:
from .CommentMacroParser import CommentMacroParser
else:
from CommentMacroParser import CommentMacroParser
# This class defines a complete listener for a parse tree produced by CommentMacroParser.
class CommentMacroListener(ParseTreeListener):
# Enter a parse tree produced by CommentMacroParser#prog.
def enterProg(self, ctx:CommentMacroParser.ProgContext):
pass
# Exit a parse tree produced by CommentMacroParser#prog.
def exitProg(self, ctx:CommentMacroParser.ProgContext):
pass
# Enter a parse tree produced by CommentMacroParser#statement.
def enterStatement(self, ctx:CommentMacroParser.StatementContext):
pass
# Exit a parse tree produced by CommentMacroParser#statement.
def exitStatement(self, ctx:CommentMacroParser.StatementContext):
pass
# Enter a parse tree produced by CommentMacroParser#MasterGo.
def enterMasterGo(self, ctx:CommentMacroParser.MasterGoContext):
pass
# Exit a parse tree produced by CommentMacroParser#MasterGo.
def exitMasterGo(self, ctx:CommentMacroParser.MasterGoContext):
pass
# Enter a parse tree produced by CommentMacroParser#MasterGoto.
def enterMasterGoto(self, ctx:CommentMacroParser.MasterGotoContext):
pass
# Exit a parse tree produced by CommentMacroParser#MasterGoto.
def exitMasterGoto(self, ctx:CommentMacroParser.MasterGotoContext):
pass
# Enter a parse tree produced by CommentMacroParser#MasterHalt.
def enterMasterHalt(self, ctx:CommentMacroParser.MasterHaltContext):
pass
# Exit a parse tree produced by CommentMacroParser#MasterHalt.
def exitMasterHalt(self, ctx:CommentMacroParser.MasterHaltContext):
pass
# Enter a parse tree produced by CommentMacroParser#MasterAssert.
def enterMasterAssert(self, ctx:CommentMacroParser.MasterAssertContext):
pass
# Exit a parse tree produced by CommentMacroParser#MasterAssert.
def exitMasterAssert(self, ctx:CommentMacroParser.MasterAssertContext):
pass
# Enter a parse tree produced by CommentMacroParser#MasterRelease.
def enterMasterRelease(self, ctx:CommentMacroParser.MasterReleaseContext):
pass
# Exit a parse tree produced by CommentMacroParser#MasterRelease.
def exitMasterRelease(self, ctx:CommentMacroParser.MasterReleaseContext):
pass
# Enter a parse tree produced by CommentMacroParser#ReleaseAll.
def enterReleaseAll(self, ctx:CommentMacroParser.ReleaseAllContext):
pass
# Exit a parse tree produced by CommentMacroParser#ReleaseAll.
def exitReleaseAll(self, ctx:CommentMacroParser.ReleaseAllContext):
pass
# Enter a parse tree produced by CommentMacroParser#ReleaseOthers.
def enterReleaseOthers(self, ctx:CommentMacroParser.ReleaseOthersContext):
pass
# Exit a parse tree produced by CommentMacroParser#ReleaseOthers.
def exitReleaseOthers(self, ctx:CommentMacroParser.ReleaseOthersContext):
pass
# Enter a parse tree produced by CommentMacroParser#MasterFade.
def enterMasterFade(self, ctx:CommentMacroParser.MasterFadeContext):
pass
# Exit a parse tree produced by CommentMacroParser#MasterFade.
def exitMasterFade(self, ctx:CommentMacroParser.MasterFadeContext):
pass
# Enter a parse tree produced by CommentMacroParser#FadeGrandMaster.
def enterFadeGrandMaster(self, ctx:CommentMacroParser.FadeGrandMasterContext):
pass
# Exit a parse tree produced by CommentMacroParser#FadeGrandMaster.
def exitFadeGrandMaster(self, ctx:CommentMacroParser.FadeGrandMasterContext):
pass
# Enter a parse tree produced by CommentMacroParser#MasterChoose.
def enterMasterChoose(self, ctx:CommentMacroParser.MasterChooseContext):
pass
# Exit a parse tree produced by CommentMacroParser#MasterChoose.
def exitMasterChoose(self, ctx:CommentMacroParser.MasterChooseContext):
pass
# Enter a parse tree produced by CommentMacroParser#ListGo.
def enterListGo(self, ctx:CommentMacroParser.ListGoContext):
pass
# Exit a parse tree produced by CommentMacroParser#ListGo.
def exitListGo(self, ctx:CommentMacroParser.ListGoContext):
pass
# Enter a parse tree produced by CommentMacroParser#ListGoto.
def enterListGoto(self, ctx:CommentMacroParser.ListGotoContext):
pass
# Exit a parse tree produced by CommentMacroParser#ListGoto.
def exitListGoto(self, ctx:CommentMacroParser.ListGotoContext):
pass
# Enter a parse tree produced by CommentMacroParser#ListHalt.
def enterListHalt(self, ctx:CommentMacroParser.ListHaltContext):
pass
# Exit a parse tree produced by CommentMacroParser#ListHalt.
def exitListHalt(self, ctx:CommentMacroParser.ListHaltContext):
pass
# Enter a parse tree produced by CommentMacroParser#ListAssert.
def enterListAssert(self, ctx:CommentMacroParser.ListAssertContext):
pass
# Exit a parse tree produced by CommentMacroParser#ListAssert.
def exitListAssert(self, ctx:CommentMacroParser.ListAssertContext):
pass
# Enter a parse tree produced by CommentMacroParser#ListRelese.
def enterListRelese(self, ctx:CommentMacroParser.ListReleseContext):
pass
# Exit a parse tree produced by CommentMacroParser#ListRelese.
def exitListRelese(self, ctx:CommentMacroParser.ListReleseContext):
pass
# Enter a parse tree produced by CommentMacroParser#BatchGo.
def enterBatchGo(self, ctx:CommentMacroParser.BatchGoContext):
pass
# Exit a parse tree produced by CommentMacroParser#BatchGo.
def exitBatchGo(self, ctx:CommentMacroParser.BatchGoContext):
pass
# Enter a parse tree produced by CommentMacroParser#BatchHalt.
def enterBatchHalt(self, ctx:CommentMacroParser.BatchHaltContext):
pass
# Exit a parse tree produced by CommentMacroParser#BatchHalt.
def exitBatchHalt(self, ctx:CommentMacroParser.BatchHaltContext):
pass
# Enter a parse tree produced by CommentMacroParser#BatchAssert.
def enterBatchAssert(self, ctx:CommentMacroParser.BatchAssertContext):
pass
# Exit a parse tree produced by CommentMacroParser#BatchAssert.
def exitBatchAssert(self, ctx:CommentMacroParser.BatchAssertContext):
pass
# Enter a parse tree produced by CommentMacroParser#BatchRelease.
def enterBatchRelease(self, ctx:CommentMacroParser.BatchReleaseContext):
pass
# Exit a parse tree produced by CommentMacroParser#BatchRelease.
def exitBatchRelease(self, ctx:CommentMacroParser.BatchReleaseContext):
pass
# Enter a parse tree produced by CommentMacroParser#SceneGo.
def enterSceneGo(self, ctx:CommentMacroParser.SceneGoContext):
pass
# Exit a parse tree produced by CommentMacroParser#SceneGo.
def exitSceneGo(self, ctx:CommentMacroParser.SceneGoContext):
pass
# Enter a parse tree produced by CommentMacroParser#SceneHalt.
def enterSceneHalt(self, ctx:CommentMacroParser.SceneHaltContext):
pass
# Exit a parse tree produced by CommentMacroParser#SceneHalt.
def exitSceneHalt(self, ctx:CommentMacroParser.SceneHaltContext):
pass
# Enter a parse tree produced by CommentMacroParser#SceneAssert.
def enterSceneAssert(self, ctx:CommentMacroParser.SceneAssertContext):
pass
# Exit a parse tree produced by CommentMacroParser#SceneAssert.
def exitSceneAssert(self, ctx:CommentMacroParser.SceneAssertContext):
pass
# Enter a parse tree produced by CommentMacroParser#SceneRelease.
def enterSceneRelease(self, ctx:CommentMacroParser.SceneReleaseContext):
pass
# Exit a parse tree produced by CommentMacroParser#SceneRelease.
def exitSceneRelease(self, ctx:CommentMacroParser.SceneReleaseContext):
pass
# Enter a parse tree produced by CommentMacroParser#PageChange.
def enterPageChange(self, ctx:CommentMacroParser.PageChangeContext):
pass
# Exit a parse tree produced by CommentMacroParser#PageChange.
def exitPageChange(self, ctx:CommentMacroParser.PageChangeContext):
pass
# Enter a parse tree produced by CommentMacroParser#PageNext.
def enterPageNext(self, ctx:CommentMacroParser.PageNextContext):
pass
# Exit a parse tree produced by CommentMacroParser#PageNext.
def exitPageNext(self, ctx:CommentMacroParser.PageNextContext):
pass
# Enter a parse tree produced by CommentMacroParser#PagePrev.
def enterPagePrev(self, ctx:CommentMacroParser.PagePrevContext):
pass
# Exit a parse tree produced by CommentMacroParser#PagePrev.
def exitPagePrev(self, ctx:CommentMacroParser.PagePrevContext):
pass
# Enter a parse tree produced by CommentMacroParser#RecallView.
def enterRecallView(self, ctx:CommentMacroParser.RecallViewContext):
pass
# Exit a parse tree produced by CommentMacroParser#RecallView.
def exitRecallView(self, ctx:CommentMacroParser.RecallViewContext):
pass
# Enter a parse tree produced by CommentMacroParser#NodeReset.
def enterNodeReset(self, ctx:CommentMacroParser.NodeResetContext):
pass
# Exit a parse tree produced by CommentMacroParser#NodeReset.
def exitNodeReset(self, ctx:CommentMacroParser.NodeResetContext):
pass
# Enter a parse tree produced by CommentMacroParser#MacroGo.
def enterMacroGo(self, ctx:CommentMacroParser.MacroGoContext):
pass
# Exit a parse tree produced by CommentMacroParser#MacroGo.
def exitMacroGo(self, ctx:CommentMacroParser.MacroGoContext):
pass
# Enter a parse tree produced by CommentMacroParser#MacroHalt.
def enterMacroHalt(self, ctx:CommentMacroParser.MacroHaltContext):
pass
# Exit a parse tree produced by CommentMacroParser#MacroHalt.
def exitMacroHalt(self, ctx:CommentMacroParser.MacroHaltContext):
pass
# Enter a parse tree produced by CommentMacroParser#MacroStop.
def enterMacroStop(self, ctx:CommentMacroParser.MacroStopContext):
pass
# Exit a parse tree produced by CommentMacroParser#MacroStop.
def exitMacroStop(self, ctx:CommentMacroParser.MacroStopContext):
pass
# Enter a parse tree produced by CommentMacroParser#SelectIntensity.
def enterSelectIntensity(self, ctx:CommentMacroParser.SelectIntensityContext):
pass
# Exit a parse tree produced by CommentMacroParser#SelectIntensity.
def exitSelectIntensity(self, ctx:CommentMacroParser.SelectIntensityContext):
pass
# Enter a parse tree produced by CommentMacroParser#SelectPosition.
def enterSelectPosition(self, ctx:CommentMacroParser.SelectPositionContext):
pass
# Exit a parse tree produced by CommentMacroParser#SelectPosition.
def exitSelectPosition(self, ctx:CommentMacroParser.SelectPositionContext):
pass
# Enter a parse tree produced by CommentMacroParser#SelectColour.
def enterSelectColour(self, ctx:CommentMacroParser.SelectColourContext):
pass
# Exit a parse tree produced by CommentMacroParser#SelectColour.
def exitSelectColour(self, ctx:CommentMacroParser.SelectColourContext):
pass
# Enter a parse tree produced by CommentMacroParser#SelectBeam.
def enterSelectBeam(self, ctx:CommentMacroParser.SelectBeamContext):
pass
# Exit a parse tree produced by CommentMacroParser#SelectBeam.
def exitSelectBeam(self, ctx:CommentMacroParser.SelectBeamContext):
pass
# Enter a parse tree produced by CommentMacroParser#Wait.
def enterWait(self, ctx:CommentMacroParser.WaitContext):
pass
# Exit a parse tree produced by CommentMacroParser#Wait.
def exitWait(self, ctx:CommentMacroParser.WaitContext):
pass
# Enter a parse tree produced by CommentMacroParser#Pass.
def enterPass(self, ctx:CommentMacroParser.PassContext):
pass
# Exit a parse tree produced by CommentMacroParser#Pass.
def exitPass(self, ctx:CommentMacroParser.PassContext):
pass
# Enter a parse tree produced by CommentMacroParser#time.
def enterTime(self, ctx:CommentMacroParser.TimeContext):
pass
# Exit a parse tree produced by CommentMacroParser#time.
def exitTime(self, ctx:CommentMacroParser.TimeContext):
pass
# Enter a parse tree produced by CommentMacroParser#device.
def enterDevice(self, ctx:CommentMacroParser.DeviceContext):
pass
# Exit a parse tree produced by CommentMacroParser#device.
def exitDevice(self, ctx:CommentMacroParser.DeviceContext):
pass
# Enter a parse tree produced by CommentMacroParser#nodeType.
def enterNodeType(self, ctx:CommentMacroParser.NodeTypeContext):
pass
# Exit a parse tree produced by CommentMacroParser#nodeType.
def exitNodeType(self, ctx:CommentMacroParser.NodeTypeContext):
pass
# Enter a parse tree produced by CommentMacroParser#target.
def enterTarget(self, ctx:CommentMacroParser.TargetContext):
pass
# Exit a parse tree produced by CommentMacroParser#target.
def exitTarget(self, ctx:CommentMacroParser.TargetContext):
pass
# Enter a parse tree produced by CommentMacroParser#span.
def enterSpan(self, ctx:CommentMacroParser.SpanContext):
pass
# Exit a parse tree produced by CommentMacroParser#span.
def exitSpan(self, ctx:CommentMacroParser.SpanContext):
pass
# Enter a parse tree produced by CommentMacroParser#number.
def enterNumber(self, ctx:CommentMacroParser.NumberContext):
pass
# Exit a parse tree produced by CommentMacroParser#number.
def exitNumber(self, ctx:CommentMacroParser.NumberContext):
pass
del CommentMacroParser

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
"""Init for comment macro antlr4."""

121
bacon/hog4.py Normal file
View File

@ -0,0 +1,121 @@
"""hog4.py: Class methods for Hog 4 representation."""
import logging
from time import sleep
from typing import Any, Dict, Union
from pythonosc import udp_client, osc_message_builder, osc_bundle, osc_message
from antlr4 import ParserRuleContext
__all__ = [
"HogNet",
]
log = logging.getLogger(__name__)
class HogNet:
"""Class definition of a hognet participant."""
# button state constants
buttonDOWN = 1
buttonUP = 0
buttonMap: Dict[str, str] = {
"backspace": "/hog/hardware/backspace",
"beam": "/hog/hardware/beam",
"blind": "/hog/hardware/blind",
"clear": "/hog/hardware/clear",
"colour": "/hog/hardware/colour",
"copy": "/hog/hardware/copy",
"cue": "/hog/hardware/cue",
"delete": "/hog/hardware/delete",
"down": "/hog/hardware/down",
"effect": "/hog/hardware/effect",
"enter": "/hog/hardware/enter",
"fan": "/hog/hardware/fan",
"fixture": "/hog/hardware/fixture",
"goto": "/hog/hardware/goto",
"group": "/hog/hardware/group",
"highlight": "/hog/hardware/highlight",
"intensity": "/hog/hardware/intensity",
"left": "/hog/hardware/left",
"list": "/hog/hardware/list",
"live": "/hog/hardware/live",
"macro": "/hog/hardware/macro",
"merge": "/hog/hardware/merge",
"move": "/hog/hardware/move",
"open": "/hog/hardware/open",
"page": "/hog/hardware/page",
"pig": "/hog/hardware/pig",
"position": "/hog/hardware/position",
"record": "/hog/hardware/record",
"right": "/hog/hardware/right",
"scene": "/hog/hardware/scene",
"set": "/hog/hardware/set",
"setup": "/hog/hardware/setup",
"time": "/hog/hardware/time",
"up": "/hog/hardware/up",
"update": "/hog/hardware/update",
".": "/hog/hardware/period",
"@": "/hog/hardware/at",
"-": "/hog/hardware/minus",
"+": "/hog/hardware/plus",
"/": "/hog/hardware/slash",
"0": "/hog/hardware/zero",
"1": "/hog/hardware/one",
"2": "/hog/hardware/two",
"3": "/hog/hardware/three",
"4": "/hog/hardware/four",
"5": "/hog/hardware/five",
"6": "/hog/hardware/six",
"7": "/hog/hardware/seven",
"8": "/hog/hardware/eight",
"9": "/hog/hardware/nine"
}
def __init__(self, servers: Dict[int, object]) -> None:
"""Init method."""
self.servers = servers
def number_entry(self, device: ParserRuleContext,
number: str) -> None:
"""Press digit buttons to make a number."""
for digit in number:
try:
self.button_press(device, self.buttonMap[digit])
except KeyError:
continue
def button_press(self, device: ParserRuleContext,
path: str, delay: float = 0.05) -> None:
"""Button presses are a pair of up/down OSC."""
self.send_message(device, path, self.buttonDOWN)
sleep(delay)
self.send_message(device, path, self.buttonUP)
sleep(delay)
def send_message(self, device: ParserRuleContext,
path: str, arg: Any) -> None:
"""Send a simple OSC message with one argument."""
msg = osc_message_builder.OscMessageBuilder(address=path)
msg.add_arg(arg)
self.send(device, msg.build())
def send(self, device: ParserRuleContext,
msg: Union[osc_message.OscMessage, osc_bundle.OscBundle]) -> None:
"""Send python-osc messages."""
if device is None:
# first configured server
osc: udp_client = list(self.servers.values())[0]
else:
if device.nodeType().getText().lower() != 'h':
log.error("ERROR: Only Hog type devices are supported.")
return
try:
osc = self.servers[device.number().value]
except KeyError:
log.error("ERROR: Net# %d not found.",
device.number().value)
return
try:
osc.send(msg)
except OSError as exception:
log.error(exception)

84
bacon/script.py Normal file
View File

@ -0,0 +1,84 @@
"""comment.py: Hog 4 comment macro interpreter and OSC bridge."""
import configparser
import logging
from typing import Dict
from antlr4 import CommonTokenStream, InputStream, ParseTreeWalker
from antlr4.error.ErrorListener import ErrorListener
from pythonosc import udp_client
from .commentmacro.CommentMacroLexer import CommentMacroLexer
from .commentmacro.CommentMacroParser import CommentMacroParser
from .OscListener import OscCommentMacroListener
__all__ = [
"SyntaxErrorListener",
"load_servers",
"comment",
"WALKER",
"LISTENER",
]
log = logging.getLogger(__name__)
class SyntaxErrorListener(ErrorListener):
"""An error listener that raises SyntaxError exceptions."""
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
raise SyntaxError(f"line {line}:{column} {msg}")
def load_servers(file: str = 'server.cfg') -> Dict[int, object]:
"""Load an ini style configuration file."""
# empty server dictionary
servers: Dict[int, object] = {}
# open config file
config = configparser.ConfigParser(allow_no_value=True)
config.read(file)
# set up each hog device
for name in config.get('network', 'hogs').split(','):
try:
# move to config section
server = config[name.strip().strip('\"')]
# read settings
addr = server.get("ip", fallback="127.0.0.1")
port = server.getint("port", fallback=7001)
net = server.getint("net", fallback=1)
# osc clients are added to the dictionary with the net # as the key
log.info("Adding Hog device at net# %s", net)
servers[net] = udp_client.SimpleUDPClient(addr, port)
except KeyError as exception:
log.error('Error configuring net#%s: %s', net, exception)
continue
return servers
# init reusable walker and listener
WALKER: ParseTreeWalker = ParseTreeWalker()
LISTENER: OscCommentMacroListener = OscCommentMacroListener()
def comment(text: str) -> None:
"""Process comment macro input."""
# force upper case
text = text.upper()
# generate text stream
input_stream = InputStream(text)
# lex the text stream
lexer = CommentMacroLexer(input_stream)
# get token stream from lexer
stream = CommonTokenStream(lexer)
# parse the token steam
parser = CommentMacroParser(stream)
# attach an error handler to the parser
parser._listeners.append(SyntaxErrorListener())
try:
# get tree from parser
tree = parser.prog()
# walk the tree
WALKER.walk(LISTENER, tree)
except SyntaxError as exception:
log.debug(exception)

34
bs.py Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Interactive BaconScript shell."""
import logging
import sys
from .bacon import comment, LISTENER, HogNet, load_servers
logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)
LISTENER.osc = HogNet(load_servers('server.cfg'))
# handle user input if run directly
if __name__ == '__main__':
if len(sys.argv) > 1:
# look for macros passed as arguments
logging.debug("found macro at argv[1]")
comment(sys.argv[1])
else:
# be an interactive shell
while True:
# get user input
try:
TEXT = input("comment# ")
except (KeyboardInterrupt, EOFError):
TEXT = 'exit'
print(TEXT)
# catch exit keyword
if TEXT.lower() == 'exit':
break
# exec user input
comment(TEXT)

View File

@ -1,74 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""comment.py: Hog 4 comment macro interpreter and OSC bridge."""
__author__ = "Kevin Matz"
__copyright__ = "Copyright 2018, Company 235, LLC"
__credits__ = ["Kevin Matz"]
__license__ = "MIT"
__version__ = "3.9"
__maintainer__ = "Kevin Matz"
__email__ = "kevin@company235.com"
__status__ = "Prototype"
import antlr4
import configparser
import logging
import sys
from CommentMacroLexer import CommentMacroLexer
from CommentMacroParser import CommentMacroParser
from OscCommentMacroListener import OscCommentMacroListener
from pythonosc import udp_client
# setup logging
logger = logging.getLogger("CommentMacro")
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler() # create console handler and
ch.setLevel(logging.INFO) # set console log level to INFO
logger.addHandler(ch) # add console log handler
# TODO: refactor this to support multiple net#s
config = configparser.ConfigParser(allow_no_value=True)
config.read('server.cfg') # open config file
servers = {} # init an empty dictionary
server = config['hog4'] # section of config file
net = server.getint("net", 1) # default to net #1
logger.info("Adding Hog device at net# " + str(net))
# osc clients are added to the dictionary with the net # as the key
servers[net] = udp_client.SimpleUDPClient(server.get("ip", "10.0.0.1"),
server.getint("port", 6600))
def comment(text):
input_stream = antlr4.InputStream(text)
lexer = CommentMacroLexer(input_stream)
stream = antlr4.CommonTokenStream(lexer)
parser = CommentMacroParser(stream)
tree = parser.prog()
oscMacro = OscCommentMacroListener(servers)
walker = antlr4.ParseTreeWalker()
walker.walk(oscMacro, tree)
if __name__ == '__main__':
if len(sys.argv) > 1:
logger.debug("found macro at argv[1]")
comment(sys.argv[1])
else:
import readline # for input history and line editing
while True:
try:
text = input("comment# ")
except KeyboardInterrupt:
text = 'exit'
print(text)
if text == 'exit':
sys.exit(0)
else:
comment(text)

13
examples/example.bs Normal file
View File

@ -0,0 +1,13 @@
// example.bs: An example BaconScript file.
CM10
GM*
GM1:AM*:HM3 # use a `:` to separate multiple macros on a single line.
RM*
WAIT1 # sleep for 1 second
RA
FM1/50
FGM20
GL1/5
HS3>5 # do macro on a range of targets
RK2,4,6 # do macro on a comma separated list of targets
CP+

View File

@ -1,4 +1,28 @@
; This file contains the configuration data for HogNet devices.
[network]
; Comma seperated list of config section names.
; The first Hog4 in the list will be the default OSC reciever.
hogs = hog4,hedgehog
; The device is named as a section.
; When adding additional devices, be sure to add the section
; name to the index on line 6.
[example]
; the IPv4 or IPv6 address of the Hog device
ip: 127.0.0.1
; the port which is configured for OSC input
port: 7001
; the net number, which may be called in the comment macro
net: 1
[hog4]
ip: 10.0.0.100
port: 7001
net: 1
ip: 10.235.1.53
port: 7001
net: 53
[hedgehog]
ip: 10.235.1.63
port: 7001
net: 63

28
server.cfg.example Normal file
View File

@ -0,0 +1,28 @@
; This file contains the configuration data for HogNet devices.
[network]
; Comma seperated list of config section names.
; The first Hog4 in the list will be the default OSC reciever.
hogs = hog4,hedgehog
; The device is named as a section.
; When adding additional devices, be sure to add the section
; name to the index on line 6.
[example]
; the IPv4 or IPv6 address of the Hog device
ip: 127.0.0.1
; the port which is configured for OSC input
port: 7001
; the net number, which may be called in the comment macro
net: 1
[hog4]
ip: 10.235.1.53
port: 7001
net: 53
[hedgehog]
ip: 10.235.1.63
port: 7001
net: 63

20
setup.py Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Setup.py: Module install script."""
from setuptools import setup, find_packages
setup(name='baconscript',
version='3.9',
description='Hog 4 comment macro interpreter and OSC bridge.',
url='https://git.company235.com/kevin/baconscript',
author='Kevin Matz',
author_email='kevin@company235.com',
license='MIT',
packages=find_packages(),
install_requires=[
'antlr4-python3-runtime',
'python-osc',
],
zip_safe=False)