
org.bidib.wizard.mvc.script.view.ScriptParser Maven / Gradle / Ivy
package org.bidib.wizard.mvc.script.view;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.bidib.wizard.highlight.BidibScriptScanner;
import org.bidib.wizard.highlight.Scanner;
import org.bidib.wizard.highlight.Token;
import org.bidib.wizard.highlight.TokenTypes;
import org.bidib.wizard.mvc.main.model.Node;
import org.bidib.wizard.script.InitializingCommand;
import org.bidib.wizard.script.ScriptCommand;
import org.bidib.wizard.script.node.AddAspectCommand;
import org.bidib.wizard.script.node.AddMacroStepCommand;
import org.bidib.wizard.script.node.ConfigMacroCommand;
import org.bidib.wizard.script.node.ConfigMacroTimeCommand;
import org.bidib.wizard.script.node.ConfigPortCommand;
import org.bidib.wizard.script.node.ReselectCommand;
import org.bidib.wizard.script.node.ResetCommand;
import org.bidib.wizard.script.node.SelectAccessoryCommand;
import org.bidib.wizard.script.node.SelectMacroCommand;
import org.bidib.wizard.script.node.SetCvCommand;
import org.bidib.wizard.script.node.SetLabelCommand;
import org.bidib.wizard.script.node.SwitchPortType;
import org.bidib.wizard.script.node.WaitCommand;
import org.bidib.wizard.script.node.types.AccessoryTargetType;
import org.bidib.wizard.script.node.types.AnalogPortType;
import org.bidib.wizard.script.node.types.BacklightPortType;
import org.bidib.wizard.script.node.types.CvType;
import org.bidib.wizard.script.node.types.InputPortType;
import org.bidib.wizard.script.node.types.LightPortType;
import org.bidib.wizard.script.node.types.MacroTargetType;
import org.bidib.wizard.script.node.types.MotorPortType;
import org.bidib.wizard.script.node.types.ScriptingTargetType;
import org.bidib.wizard.script.node.types.ServoPortType;
import org.bidib.wizard.script.node.types.SoundPortType;
import org.bidib.wizard.script.node.types.TargetType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ScriptParser {
private static final Logger LOGGER = LoggerFactory.getLogger(ScriptParser.class);
public static final String KEY_SELECTED_NODE = "selectedNode";
public static final String KEY_NODE_LABELS = "nodeLabels";
public static final String KEY_MACRO_LABELS = "macroLabels";
public static final String KEY_ACCESSORY_LABELS = "accessoryLabels";
public static final String KEY_ANALOG_LABELS = "analogLabels";
public static final String KEY_BACKLIGHT_LABELS = "backlightLabels";
public static final String KEY_INPUT_LABELS = "inputLabels";
public static final String KEY_LIGHT_LABELS = "lightLabels";
public static final String KEY_MOTOR_LABELS = "motorLabels";
public static final String KEY_SERVO_LABELS = "servoLabels";
public static final String KEY_SOUND_LABELS = "soundLabels";
public static final String KEY_SWITCH_LABELS = "switchLabels";
public static final String KEY_MAIN_MODEL = "mainModel";
public static final String KEY_SELECTED_MACRO = "selectedMacro";
public static final String KEY_SELECTED_ACCESSORY = "selectedAccessory";
public void parseScript(
String script, final List> scriptCommands, Map context) {
LOGGER.info("Parse the script and create the commands to execute: {}", script);
StringBuffer sb = new StringBuffer(script);
sb.append("\r\n");
String[] lines = sb.toString().split("\n");
BidibScriptScanner scanner = new BidibScriptScanner();
int oldLen = -1;
for (String line : lines) {
LOGGER.info("Current line: {}", line);
try {
if (StringUtils.isNotBlank(line)) {
// TODO I don't know why the next 2 lines are is needed ...
scanner.change(0, 0, (oldLen > -1 ? oldLen : line.length()));
oldLen = line.trim().length();
scanner.change(0, 0, line.length());
scanner.scan(line.toCharArray(), 0, line.length());
for (int i = 0; i < scanner.size(); i++) {
Token t = scanner.getToken(i);
switch (t.symbol.type) {
case TokenTypes.COMMENT:
// comment detected, skip
LOGGER.info("Comment detected, skip processing of line later.");
break;
case TokenTypes.KEYWORD:
case TokenTypes.KEYWORD2:
LOGGER.info("Keyword detected: {}, current i: {}", t.symbol.name, i);
i = processLine(line.trim(), scanner, i, context, scriptCommands);
LOGGER.info("After process line, i: {}", i);
break;
default:
break;
}
// LOGGER.info("Current token: {}", t);
if (TokenTypes.COMMENT == t.symbol.type) {
break;
}
}
}
}
catch (Exception ex) {
LOGGER.warn("Scan line with parser failed: {}", line, ex);
}
}
// intialize the commands
for (ScriptCommand command : scriptCommands) {
if (command instanceof InitializingCommand) {
((InitializingCommand) command).afterPropertiesSet();
}
}
}
private int processLine(
final String line, Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Process the line: {}", line);
int i = index;
Token t = scanner.getToken(index);
switch (t.symbol.name) {
case BidibScriptScanner.KEY_DEFINE:
parseDefine(scanner, index, context, scriptCommands);
break;
case BidibScriptScanner.KEY_SET:
parseSet(scanner, index, context, scriptCommands);
break;
case BidibScriptScanner.KEY_SELECT:
parseSelect(scanner, index, context, scriptCommands);
break;
case BidibScriptScanner.KEY_ADD:
parseAdd(scanner, index, context, scriptCommands);
break;
case BidibScriptScanner.KEY_RESET:
parseReset(scanner, index, context, scriptCommands);
break;
case BidibScriptScanner.KEY_WAIT:
parseWait(scanner, index, context, scriptCommands);
break;
case BidibScriptScanner.KEY_RESELECT:
parseReselect(scanner, index, context, scriptCommands);
break;
case BidibScriptScanner.KEY_CONFIG:
i = parseConfig(scanner, index, context, scriptCommands);
break;
default:
break;
}
return i;
}
private void parseDefine(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Parse 'define'.");
String key = null;
String value = null;
for (int i = index + 1; i < scanner.size(); i++) {
Token token = scanner.getToken(i);
LOGGER.info("Current token symbol: {}, name: {}", token.symbol.type, token.symbol.name);
switch (token.symbol.type) {
case TokenTypes.IDENTIFIER:
key = "%" + token.symbol.name + "%";
break;
case TokenTypes.STRING:
value = token.symbol.name;
if (value != null) {
// replace leading and trailing quotation marks
value = value.replaceAll("\"", "");
}
break;
default:
key = "%" + token.symbol.name + "%";
break;
}
}
LOGGER.info("Add define, key: {}, value: {}", key, value);
if (key != null && value != null) {
context.put(key, value);
}
}
private void parseSet(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Parse 'set'.");
// PortType portType = null;
for (int i = index + 1; i < scanner.size(); i++) {
Token token = scanner.getToken(i);
LOGGER.info("Current index: {}, token symbol: {}, name: {}", i, token.symbol.type, token.symbol.name);
TargetType portType = null;
switch (token.symbol.type) {
case TokenTypes.KEYWORD2:
switch (token.symbol.name) {
case BidibScriptScanner.KEY2_ANALOG:
portType = new AnalogPortType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setLabel(context, ScriptParser.KEY_ANALOG_LABELS, portType.getPortNum(),
portType.getLabel());
break;
case BidibScriptScanner.KEY2_BACKLIGHT:
portType = new BacklightPortType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setLabel(context, ScriptParser.KEY_BACKLIGHT_LABELS, portType.getPortNum(),
portType.getLabel());
break;
case BidibScriptScanner.KEY2_INPUT:
portType = new InputPortType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setLabel(context, ScriptParser.KEY_INPUT_LABELS, portType.getPortNum(), portType.getLabel());
break;
case BidibScriptScanner.KEY2_LIGHT:
portType = new LightPortType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setLabel(context, ScriptParser.KEY_LIGHT_LABELS, portType.getPortNum(), portType.getLabel());
break;
case BidibScriptScanner.KEY2_MOTOR:
portType = new MotorPortType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setLabel(context, ScriptParser.KEY_MOTOR_LABELS, portType.getPortNum(), portType.getLabel());
break;
case BidibScriptScanner.KEY2_SERVO:
portType = new ServoPortType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setLabel(context, ScriptParser.KEY_SERVO_LABELS, portType.getPortNum(), portType.getLabel());
break;
case BidibScriptScanner.KEY2_SOUND:
portType = new SoundPortType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setLabel(context, ScriptParser.KEY_SOUND_LABELS, portType.getPortNum(), portType.getLabel());
break;
case BidibScriptScanner.KEY2_SWITCH:
portType = new SwitchPortType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setLabel(context, ScriptParser.KEY_SWITCH_LABELS, portType.getPortNum(),
portType.getLabel());
break;
case BidibScriptScanner.KEY2_MACRO:
portType = new MacroTargetType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setMacroLabel(context, portType.getPortNum(), portType.getLabel());
break;
case BidibScriptScanner.KEY2_CV:
parseCV(scanner, i, context, scriptCommands);
break;
case BidibScriptScanner.KEY2_ACCESSORY:
portType = new AccessoryTargetType();
parseSetTargetType(scanner, i, context, scriptCommands, portType);
setAccessoryLabel(context, portType.getPortNum(), portType.getLabel());
break;
default:
break;
}
break;
default:
break;
}
}
}
private void parseSelect(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Parse 'select'.");
TargetType targetType = null;
for (int i = index + 1; i < scanner.size(); i++) {
Token token = scanner.getToken(i);
LOGGER.info("Current index: {}, token symbol: {}, name: {}", i, token.symbol.type, token.symbol.name);
switch (token.symbol.type) {
case TokenTypes.KEYWORD2:
switch (token.symbol.name) {
case BidibScriptScanner.KEY2_MACRO:
parseSelectMacro(scanner, i, context, scriptCommands);
// skip further processing of line
i = scanner.size();
break;
case BidibScriptScanner.KEY2_ACCESSORY:
parseSelectAccessory(scanner, i, context, scriptCommands);
// skip further processing of line
i = scanner.size();
break;
default:
break;
}
break;
case TokenTypes.NUMBER:
if (i == 2 && targetType != null) {
// set the port number
targetType.setPortNum(Integer.valueOf(token.symbol.name));
if (targetType.getScriptingTargetType().equals(ScriptingTargetType.MACRO)) {
context.put(KEY_SELECTED_MACRO, targetType);
targetType = null;
}
else if (targetType.getScriptingTargetType().equals(ScriptingTargetType.ACCESSORY)) {
context.put(KEY_SELECTED_ACCESSORY, targetType);
targetType = null;
}
}
break;
case TokenTypes.VARIABLE:
if (i == 2 && targetType != null) {
// set the port number
LOGGER.info("Set the port number based on a variable: {}", token.symbol.name);
String variable = token.symbol.name;
Object value = context.get(variable);
if (value == null) {
// not found -> use the variable
value = variable;
}
// TODO if this should work we must have a map of macro label to macro
if (value instanceof String) {
// get the corresponding macro number
}
targetType.setPortNum(Integer.valueOf(value.toString()));
}
default:
break;
}
}
}
private void parseAdd(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Parse 'add'.");
for (int i = index + 1; i < scanner.size(); i++) {
Token token = scanner.getToken(i);
LOGGER.info("Current index: {}, token symbol: {}, name: {}", i, token.symbol.type, token.symbol.name);
switch (token.symbol.type) {
case TokenTypes.KEYWORD2:
switch (token.symbol.name) {
case BidibScriptScanner.KEY2_STEP:
parseStep(scanner, i, context, scriptCommands);
break;
case BidibScriptScanner.KEY2_ASPECT:
parseAspect(scanner, i, context, scriptCommands);
break;
default:
break;
}
break;
default:
break;
}
}
}
private void parseWait(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Parse 'wait'.");
for (int i = index + 1; i < scanner.size(); i++) {
Token token = scanner.getToken(i);
LOGGER.info("Current index: {}, token symbol: {}, name: {}", i, token.symbol.type, token.symbol.name);
switch (token.symbol.type) {
case TokenTypes.NUMBER:
int waitTime = Integer.parseInt(token.symbol.name);
LOGGER.info("Found wait time: {}", waitTime);
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
scriptCommands.add(new WaitCommand(selectedNode.getUniqueId(), waitTime));
break;
default:
break;
}
}
}
private void parseReset(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Parse 'reset'.");
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
scriptCommands.add(new ResetCommand(selectedNode.getUniqueId()));
}
private void parseReselect(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Parse 'reselect'.");
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
scriptCommands.add(new ReselectCommand(selectedNode.getUniqueId()));
}
private int parseConfig(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
LOGGER.info("Parse 'config'.");
int i = 0;
// evaluate the config command
for (i = index + 1; i < scanner.size(); i++) {
Token token = scanner.getToken(i);
LOGGER.info("parse config type, current index: {}, token symbol: {}, name: {}", i, token.symbol.type,
token.symbol.name);
switch (token.symbol.type) {
case TokenTypes.KEYWORD2:
switch (token.symbol.name) {
case BidibScriptScanner.KEY2_PORT:
// port detected
i += parsePortConfig(scanner, i, context, scriptCommands);
break;
case BidibScriptScanner.KEY2_MACRO:
i += parseMacroConfig(scanner, i, context, scriptCommands);
break;
case BidibScriptScanner.KEY2_MACROTIME:
i += parseMacroTimeConfig(scanner, i, context, scriptCommands);
break;
default:
break;
}
break;
default:
break;
}
}
return i;
}
private int parsePortConfig(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
ConfigPortCommand configPort = new ConfigPortCommand(selectedNode.getUniqueId());
int i = configPort.scan(scanner, index, context);
scriptCommands.add(configPort);
return i;
}
private int parseMacroConfig(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
SelectMacroCommand selectMacroCommand = (SelectMacroCommand) context.get(ScriptParser.KEY_SELECTED_MACRO);
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
ConfigMacroCommand configMacro = new ConfigMacroCommand(selectedNode.getUniqueId());
int i = configMacro.scan(scanner, index, context);
LOGGER.warn("Set the configMacro: {}", configMacro);
selectMacroCommand.setConfigMacro(configMacro);
return i;
}
private int parseMacroTimeConfig(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
SelectMacroCommand selectMacroCommand = (SelectMacroCommand) context.get(ScriptParser.KEY_SELECTED_MACRO);
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
ConfigMacroTimeCommand configMacroTime = new ConfigMacroTimeCommand(selectedNode.getUniqueId());
int i = configMacroTime.scan(scanner, index, context);
LOGGER.warn("Set the configMacroTime: {}", configMacroTime);
selectMacroCommand.setConfigMacroTime(configMacroTime);
return i;
}
private void parseSetTargetType(
Scanner scanner, int index, final Map context,
final List> scriptCommands, TargetType portType) {
for (int i = index + 1; i < scanner.size(); i++) {
Token token = scanner.getToken(i);
LOGGER.info("parse set target type, current index: {}, token symbol: {}, name: {}", i, token.symbol.type,
token.symbol.name);
switch (token.symbol.type) {
case TokenTypes.KEYWORD2:
switch (token.symbol.name) {
case BidibScriptScanner.KEY2_NAME:
// label detected
i += parseLabel(scanner, i, portType, context, scriptCommands);
break;
default:
break;
}
break;
case TokenTypes.NUMBER:
if (i == 2 && portType != null) {
// set the port number
portType.setPortNum(Integer.valueOf(token.symbol.name));
}
break;
default:
break;
}
}
LOGGER.info("Prepared portType: {}", portType);
}
private void parseCV(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
// set CV 70 1
CvType cvType = null;
for (int i = index + 1; i < scanner.size(); i++) {
Token token = scanner.getToken(i);
LOGGER.info("parseCV, current index: {}, token symbol: {}, name: {}", i, token.symbol.type,
token.symbol.name);
switch (token.symbol.type) {
case TokenTypes.NUMBER:
switch (i) {
case 2:
if (cvType == null) {
cvType = new CvType();
}
cvType.setCvNumber(Integer.valueOf(token.symbol.name));
break;
case 3:
cvType.setCvValue(token.symbol.name);
// create the command
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
SetCvCommand command = new SetCvCommand(selectedNode.getUniqueId(), cvType);
scriptCommands.add(command);
break;
default:
break;
}
break;
default:
break;
}
}
}
/**
* Parse the label value and add the SetLabelCommand to the list of scriptCommands.
*
* @param scanner
* the scanner instance
* @param index
* the token index
* @param targetType
* the target type
* @param context
* the context
* @param scriptCommands
* the list of scriptCommands
* @return the next token index to use
*/
private int parseLabel(
Scanner scanner, int index, TargetType targetType, final Map context,
final List> scriptCommands) {
Token token = scanner.getToken(index + 1);
if (token.symbol.type == TokenTypes.OPERATOR) {
String value = null;
token = scanner.getToken(index + 2);
if (token != null) {
switch (token.symbol.type) {
case TokenTypes.VARIABLE:
String variable = token.symbol.name;
value = (String) context.get(variable);
if (value == null) {
// not found -> use the variable
value = variable;
}
break;
default:
value = token.symbol.name;
break;
}
}
else {
LOGGER.info("No label defined. Remove the current label from target.");
}
LOGGER.info("Set the port label: {}", value);
targetType.setLabel(value);
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
// add the command
SetLabelCommand command = new SetLabelCommand(selectedNode.getUniqueId(), targetType);
scriptCommands.add(command);
return index + 2;
}
return index;
}
private void parseStep(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
// add step 1 label=%portA%
// let the command parse the line
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
AddMacroStepCommand macroStep = new AddMacroStepCommand(selectedNode.getUniqueId());
SelectMacroCommand selectMacroCommand = (SelectMacroCommand) context.get(KEY_SELECTED_MACRO);
macroStep.scan(scanner, index, context);
LOGGER.info("Add macro step to selected macro, step: {}", macroStep);
if (selectMacroCommand != null) {
selectMacroCommand.addMacroStep(macroStep);
}
else {
LOGGER.warn("Selected macro is not available in context, add step is skipped: {}", macroStep);
}
}
private void parseSelectMacro(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
// select macro [ 1 | label=%portA% ]
// let the command parse the line
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
SelectMacroCommand selectMacroCommand = new SelectMacroCommand(selectedNode.getUniqueId());
selectMacroCommand.scan(scanner, index, context);
context.put(KEY_SELECTED_MACRO, selectMacroCommand);
LOGGER.info("Add command to script commands: {}", selectMacroCommand);
scriptCommands.add(selectMacroCommand);
}
private void parseSelectAccessory(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
// select select [ 1 | label=%portA% ]
// let the command parse the line
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
SelectAccessoryCommand selectAccessoryCommand = new SelectAccessoryCommand(selectedNode.getUniqueId());
selectAccessoryCommand.scan(scanner, index, context);
// LOGGER.info("Prepared selectAccessoryCommand: {}", selectAccessoryCommand);
context.put(KEY_SELECTED_ACCESSORY, selectAccessoryCommand);
LOGGER.info("Add select accessory command to script commands: {}", selectAccessoryCommand);
scriptCommands.add(selectAccessoryCommand);
}
private void parseAspect(
Scanner scanner, int index, final Map context,
final List> scriptCommands) {
// add aspect 1 macroname=%weiche1Gerade%
// let the command parse the line
Node selectedNode = (Node) context.get(KEY_SELECTED_NODE);
AddAspectCommand aspect = new AddAspectCommand(selectedNode.getUniqueId());
SelectAccessoryCommand selectAccessoryCommand = (SelectAccessoryCommand) context.get(KEY_SELECTED_ACCESSORY);
aspect.scan(scanner, index, context);
LOGGER.info("Add aspect to selected accessory, aspect: {}, selectAccessoryCommand: {}", aspect,
selectAccessoryCommand);
selectAccessoryCommand.addAspect(aspect);
}
private void setMacroLabel(final Map context, int macroNumber, String macroLabel) {
// get the current macro labels from the context and do not fetch from stored labels
Map macroLabels = (Map) context.get(ScriptParser.KEY_MACRO_LABELS);
LOGGER.info("Set the macro label: {}, macroNumber: {}", macroLabel, macroNumber);
macroLabels.put(macroNumber, macroLabel);
}
private void setAccessoryLabel(final Map context, int accessoryNumber, String accessoryLabel) {
// get the current accessory labels from the context and do not fetch from stored labels
Map accessoryLabels = (Map) context.get(ScriptParser.KEY_ACCESSORY_LABELS);
LOGGER.info("Set the accessory label: {}, accessoryNumber: {}", accessoryLabel, accessoryNumber);
accessoryLabels.put(accessoryNumber, accessoryLabel);
}
private void setLabel(final Map context, String contextKey, int portNumber, String portLabel) {
// get the current port labels from the context and do not fetch from stored labels
Map labels = (Map) context.get(contextKey);
LOGGER.info("Set the port label: {}, portNumber: {}", portLabel, portNumber);
labels.put(portNumber, portLabel);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy