diff --git a/.travis.yml b/.travis.yml index f9d4cc3..d14752a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ before_install: env: # Basic KLL Tests - DIR=tests SCRIPT=sanity.bash + - DIR=tests SCRIPT=syntax.bash # Exclusions matrix: diff --git a/README.markdown b/README.markdown index 866f0b2..9bd8c03 100644 --- a/README.markdown +++ b/README.markdown @@ -10,7 +10,7 @@ kll - keyboard layout language KLL Compiler ------------ -Most current version of the [KLL Spec](http://input.club/kll). +Most current version of the [KLL Spec](https://github.com/kiibohd/kll-spec). Uses [funcparserlib](https://code.google.com/p/funcparserlib/) @@ -21,16 +21,25 @@ Usage ### General Usage ```bash -kll.py +kll ``` ### Kiibohd Controller Usage ```bash -kll.py --default --partial --partial --backend kiibohd --templates templates/kiibohdKeymap.h templates/kiibohdDefs.h --outputs generatedKeymap.h kll_defs.h +kll.py --config --base --partial --partial ``` -See `kll.py --help` for the most up to date documentation +See `kll --help` for the most up to date documentation + + +Unit Tests +---------- + +Unit tests can be found in the [tests](tests) directory. +They are run by Travis-CI, but can be useful when testing your own changes. + +Remember to add new tests when adding new features/changes. Patches/Features/Backends diff --git a/common/stage.py b/common/stage.py index feef766..c04b213 100644 --- a/common/stage.py +++ b/common/stage.py @@ -248,6 +248,12 @@ class CompilerConfigurationStage( Stage ): # TODO Detect whether colorization should be used self.color = self.color in ['auto', 'always'] + # Validate if it's a valid emitter + if self.emitter not in self.emitters.emitter_list(): + print( "{0} Invalid emitter '{1}'".format( ERROR, self.emitter ) ) + print( "Valid emitters: {0}".format( self.emitters.emitter_list() ) ) + sys.exit( 2 ) + def command_line_flags( self, parser ): ''' Group parser for command line options @@ -875,16 +881,23 @@ class OperationSpecificsStage( Stage ): ( 'PixelLayerStart', ( r'PL\[', ) ), ( 'Animation', ( r'A"[^"]+"', ) ), ( 'AnimationStart', ( r'A\[', ) ), + ( 'USBCode', ( r'U(("[^"]+")|(0x[0-9a-fA-F]+)|([0-9]+))', ) ), + ( 'USBCodeStart', ( r'U\[', ) ), + ( 'ScanCode', ( r'S((0x[0-9a-fA-F]+)|([0-9]+))', ) ), + ( 'ScanCodeStart', ( r'S\[', ) ), ( 'CodeBegin', ( r'\[', ) ), ( 'CodeEnd', ( r'\]', ) ), ( 'Position', ( r'r?[xyz]:[0-9]+(.[0-9]+)?', ) ), ( 'PixelOperator', ( r'(\+:|-:|>>|<<)', ) ), + ( 'String', ( r'"[^"]*"', ) ), + ( 'Operator', ( r':', ) ), ( 'Comma', ( r',', ) ), ( 'Dash', ( r'-', ) ), ( 'Plus', ( r'\+', ) ), ( 'Parenthesis', ( r'\(|\)', ) ), + ( 'Percent', ( r'0|([1-9][0-9]*)%', ) ), ( 'Number', ( r'-?(0x[0-9a-fA-F]+)|(0|([1-9][0-9]*))', ) ), ( 'Name', ( r'[A-Za-z_][A-Za-z_0-9]*', ) ), ] diff --git a/emitters/emitters.py b/emitters/emitters.py index 2de83d9..014c2d5 100644 --- a/emitters/emitters.py +++ b/emitters/emitters.py @@ -21,6 +21,7 @@ KLL Emitters Container Classes ### Imports ### import emitters.kiibohd.kiibohd as kiibohd +import emitters.none.none as none @@ -58,7 +59,8 @@ class Emitters: # Dictionary of Emitters self.emitters = { - 'kiibohd' : kiibohd.Kiibohd( control ) + 'kiibohd' : kiibohd.Kiibohd( control ), + 'none' : none.Drop( control ) } def emitter_default( self ): diff --git a/emitters/none/__init__.py b/emitters/none/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/emitters/none/none.py b/emitters/none/none.py new file mode 100644 index 0000000..fd05db0 --- /dev/null +++ b/emitters/none/none.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +''' +KLL Data Dropper (Doesn't emit anything) +''' + +# Copyright (C) 2016 by Jacob Alexander +# +# This file is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this file. If not, see . + +### Imports ### + +from common.emitter import Emitter + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +class Drop( Emitter ): + ''' + Doesn't emit at all, just ignores everything + ''' + + def __init__( self, control ): + ''' + Emitter initialization + + @param control: ControlStage object, used to access data from other stages + ''' + Emitter.__init__( self, control ) + + def command_line_args( self, args ): + ''' + Group parser for command line arguments + + @param args: Name space of processed arguments + ''' + + def command_line_flags( self, parser ): + ''' + Group parser for command line options + + @param parser: argparse setup object + ''' + + def output( self ): + ''' + Final Stage of Emitter + + Nothing to do + ''' + + def process( self ): + ''' + Emitter Processing + + Nothing to do, just dropping all the results + ''' + diff --git a/examples/leds.kll b/examples/leds.kll index 2dd51bb..757d7f7 100644 --- a/examples/leds.kll +++ b/examples/leds.kll @@ -44,6 +44,15 @@ A[BLEEdsing, 11, 13-15] <= P[4-10](+32); A[BLEEdsing2, 0] <= PL[0](127, 30, 40), P[5](20, 30, 40); A[BLEEdsing2, 1] <= P[1-20,40](40,50,0x60); +A[BLEEdsing2, 2] <= P[c:0](40,50,0x60); +A[BLEEdsing2, 3] <= P[c:10%](40,50,0x60); +A[BLEEdsing2, 4] <= P[r:10%,c:20](40,50,0x60); +A[BLEEdsing2, 5] <= P[r:i+10%,c:i-20](40,50,0x60); +A[BLEEdsing2, 6] <= P[r:i+10%](40,50,0x60); +A[BLEEdsing2, 7] <= U["A"](40,50,0x60); +A[BLEEdsing2, 8] <= U"B"(40,50,0x60); +A[BLEEdsing2, 9] <= S120(40,50,0x60); +A[BLEEdsing2, 10] <= S[0x10](40,50,0x60); # Animation Triggers myCapability => myFunc( myArg1 : 1, myArg2 : 4 ); diff --git a/kll b/kll index 391c5d7..50d92fc 100755 --- a/kll +++ b/kll @@ -99,7 +99,7 @@ def command_line_args( control ): parser = argparse.ArgumentParser( usage="%(prog)s [options..] [..]", description="KLL Compiler - Generates specified output from KLL .kll files.", - epilog="Example: {0} TODO".format( os.path.basename( sys.argv[0] ) ), + epilog="Example: {0} scan_map.kll".format( os.path.basename( sys.argv[0] ) ), formatter_class=argparse.RawTextHelpFormatter, add_help=False, ) diff --git a/tests/common.bash b/tests/common.bash new file mode 100644 index 0000000..25b0278 --- /dev/null +++ b/tests/common.bash @@ -0,0 +1,63 @@ +#!/bin/bash +# Common functions for running kll unit tests +# Jacob Alexander 2016 + +PASSED=0 +FAILED=0 + +# Results +result() { + echo "--- Results ---" + echo "${PASSED}/$((PASSED+FAILED))" + if (( FAILED == 0 )); then + return 0 + else + return 1 + fi +} + +# Runs a command, increments test passed/failed +# Args: Command +cmd() { + # Run command + echo "CMD: $@" + $@ + local RET=$? + + # Check command + if [[ ${RET} -ne 0 ]]; then + ((FAILED++)) + else + ((PASSED++)) + fi + + return ${RET} +} + +# Run a command multiple times using an array of values +# Arg #1: Base command +# Arg #2: Static arguments +# Arg #3: Static arguments to call when command fails (debug info) +# Arg #4+: Array of variations to swap into the command +cmds() { + local BASE=${1} + shift + local STATIC=${1} + shift + local FAIL_STATIC=${1} + shift + local VARS=${@} # Rest of arguments + + # Base command + echo "BASE CMD: ${BASE} ${STATIC}" + + # Iterate over variations + for var in ${VARS[@]}; do + cmd ${BASE} ${STATIC} ${var} + if [[ $? -ne 0 ]]; then + echo "CMD FAILED - RUNNING DEBUG ARGS - ${BASE} ${FAIL_STATIC} ${var}" + ${BASE} ${FAIL_STATIC} ${var} + fi + done +} + diff --git a/tests/sanity.bash b/tests/sanity.bash index c0cfb11..9bd2004 100755 --- a/tests/sanity.bash +++ b/tests/sanity.bash @@ -1,46 +1,24 @@ #!/bin/bash # Basic sanity check for kll compiler # Currently runs both versions of the compiler -set +x - +# Jacob Alexander 2016 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PASSED=0 -FAILED=0 - -# Results -result() { - echo "--- Results ---" - echo "${PASSED}/$((PASSED+FAILED))" - if (( FAILED == 0 )); then - return 0 - else - return 1 - fi -} - -# Runs a command, increments test passed/failed -# Args: Command -cmd() { - # Run command - echo "CMD: $@" - $@ - - # Check command - if [[ $? -ne 0 ]]; then - ((FAILED++)) - else - ((PASSED++)) - fi -} - +# Common functions +source ${SCRIPT_DIR}/common.bash # Start in kll top-level directory cd ${SCRIPT_DIR}/.. + +## Tests + cmd ./kll.py --version cmd ./kll --version +## Tests complete + + result exit $? diff --git a/tests/syntax.bash b/tests/syntax.bash new file mode 100755 index 0000000..36ecf7c --- /dev/null +++ b/tests/syntax.bash @@ -0,0 +1,47 @@ +#!/bin/bash +# Use example .kll files to check syntax compatibility +# Does not generate code, so resulting datastructures do not necessarily need to functino +# Jacob Alexander 2016 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Common functions +source ${SCRIPT_DIR}/common.bash + +# Start in kll top-level directory +cd ${SCRIPT_DIR}/.. + + +# Args used for each of the tests +ARGS="--emitter none --data-finalization-display" +FAIL_ARGS="--emitter none --token-debug --parser-token-debug --operation-organization-display --data-organization-display --data-finalization-display" + +# Files to check syntax on +FILES=( + examples/assignment.kll + examples/capabilitiesExample.kll + examples/colemak.kll + examples/defaultMapExample.kll + examples/example.kll + examples/hhkbpro2.kll + examples/leds.kll + examples/mapping.kll + examples/md1Map.kll + examples/simple1.kll + examples/simple2.kll + examples/simpleExample.kll + examples/state_scheduling.kll +) + + +## Tests + + +cmds "./kll" "${ARGS}" "${FAIL_ARGS}" ${FILES[@]} + + +## Tests complete + + +result +exit $? +