osd-contiki/tools/cooja/java/se/sics/cooja/plugins/ScriptParser.java

292 lines
8.2 KiB
Java

/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ScriptParser.java,v 1.4 2009/01/15 13:11:56 fros4943 Exp $
*/
package se.sics.cooja.plugins;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.script.ScriptException;
import org.apache.log4j.Logger;
public class ScriptParser {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(ScriptParser.class);
private long timeoutTime = -1;
private String timeoutCode = null;
private String code = null;
public ScriptParser(String code) throws ScriptSyntaxErrorException {
code = fixNewlines(code);
code = stripMultiLineComments(code);
code = stripSingleLineComments(code);
code = parseTimeout(code);
code = parseTimeoutWithAction(code);
code = replaceYieldThenWaitUntils(code);
code = replaceYields(code);
code = replaceWaitUntils(code);
code = replaceGenerateMessages(code);
this.code = code;
}
private String fixNewlines(String code) {
code = code.replaceAll("\r\n", "\n");
code = "\n" + code + "\n";
return code;
}
private String stripSingleLineComments(String code) {
/* TODO Handle strings */
Pattern pattern = Pattern.compile("//.*\n");
Matcher matcher = pattern.matcher(code);
code = matcher.replaceAll("\n");
return code;
}
private String stripFirstComment(String code) {
int first = code.indexOf('"');
if (first < 0) {
return code;
}
int second = code.indexOf('"', first+1);
code = code.substring(0, first) + code.substring(second+1, code.length());
return code;
}
private String stripMultiLineComments(String code) {
/* TODO Handle strings */
Pattern pattern =
Pattern.compile("/\\*([^*]|[\n]|(\\*+([^*/]|[\n])))*\\*+/");
Matcher matcher = pattern.matcher(code);
while (matcher.find()) {
String match = matcher.group();
int newLines = match.split("\n").length;
String replacement = "";
for (int i=0; i < newLines; i++) {
replacement += "\n";
}
code = matcher.replaceFirst(replacement);
matcher.reset(code);
}
return code;
}
private String parseTimeout(String code) throws ScriptSyntaxErrorException {
Pattern pattern = Pattern.compile(
"TIMEOUT\\(" +
"([0-9]+)" /* timeout */ +
"\\)"
);
Matcher matcher = pattern.matcher(code);
if (!matcher.find()) {
return code;
}
if (timeoutTime > 0) {
throw new ScriptSyntaxErrorException("Only one timeout handler allowed");
}
timeoutTime = Long.parseLong(matcher.group(1));
timeoutCode = ";";
matcher.reset(code);
code = matcher.replaceFirst(";");
matcher.reset(code);
if (matcher.find()) {
throw new ScriptSyntaxErrorException("Only one timeout handler allowed");
}
return code;
}
private String parseTimeoutWithAction(String code) throws ScriptSyntaxErrorException {
Pattern pattern = Pattern.compile(
"TIMEOUT\\(" +
"([0-9]+)" /* timeout */ +
"[\\s]*,[\\s]*" +
"(.*)" /* code */ +
"\\)"
);
Matcher matcher = pattern.matcher(code);
if (!matcher.find()) {
return code;
}
if (timeoutTime > 0) {
throw new ScriptSyntaxErrorException("Only one timeout handler allowed");
}
timeoutTime = Long.parseLong(matcher.group(1));
timeoutCode = matcher.group(2);
matcher.reset(code);
code = matcher.replaceFirst(";");
matcher.reset(code);
if (matcher.find()) {
throw new ScriptSyntaxErrorException("Only one timeout handler allowed");
}
return code;
}
private String replaceYields(String code) throws ScriptSyntaxErrorException {
Pattern pattern = Pattern.compile(
"YIELD\\(\\)"
);
return pattern.matcher(code).replaceAll("SCRIPT_SWITCH()");
}
private String replaceYieldThenWaitUntils(String code) throws ScriptSyntaxErrorException {
Pattern pattern = Pattern.compile(
"YIELD_THEN_WAIT_UNTIL\\(" +
"(.*)" /* expression */ +
"\\)"
);
Matcher matcher = pattern.matcher(code);
while (matcher.find()) {
code = matcher.replaceFirst(
"YIELD(); WAIT_UNTIL(" + matcher.group(1) + ")");
matcher.reset(code);
}
return code;
}
private String replaceWaitUntils(String code) throws ScriptSyntaxErrorException {
Pattern pattern = Pattern.compile(
"WAIT_UNTIL\\(" +
"(.*)" /* expression */ +
"\\)"
);
Matcher matcher = pattern.matcher(code);
while (matcher.find()) {
code = matcher.replaceFirst(
"while (!(" + matcher.group(1) + ")) { " +
" SCRIPT_SWITCH(); " +
"}");
matcher.reset(code);
}
return code;
}
private String replaceGenerateMessages(String code) throws ScriptSyntaxErrorException {
Pattern pattern = Pattern.compile(
"GENERATE_MSG\\(" +
"([0-9]+)" /* timeout */ +
"[\\s]*,[\\s]*" +
"(.*)" /* code */ +
"\\)"
);
Matcher matcher = pattern.matcher(code);
while (matcher.find()) {
long time = Long.parseLong(matcher.group(1));
String msg = matcher.group(2);
code = matcher.replaceFirst(
"log.generateMessage(" + time + "," + msg + ")");
matcher.reset(code);
}
return code;
}
public String getJSCode() {
return
"function SCRIPT_KILL() { " +
" SEMAPHORE_SIM.release(100); " +
" throw('test script killed'); " +
"};\n" +
"function SCRIPT_TIMEOUT() { " +
timeoutCode + "; " +
" log.log('TEST TIMEOUT\\n'); " +
" log.testFailed(); " +
" while (!SHUTDOWN) { " +
" SEMAPHORE_SIM.release(); " +
" SEMAPHORE_SCRIPT.acquire(); " /* SWITCH BLOCKS HERE! */ +
" } " +
" SCRIPT_KILL(); " +
"};\n" +
"function SCRIPT_SWITCH() { " +
" SEMAPHORE_SIM.release(); " +
" SEMAPHORE_SCRIPT.acquire(); " /* SWITCH BLOCKS HERE! */ +
" if (SHUTDOWN) { SCRIPT_KILL(); } " +
" if (TIMEOUT) { SCRIPT_TIMEOUT(); } " +
" msg = new java.lang.String(msg); " +
" node.setMoteMsg(mote, msg); " +
"};\n" +
"function write(mote,msg) { " +
" mote.getInterfaces().getLog().writeString(msg); " +
"};\n" +
"function run() { " +
"SEMAPHORE_SIM.acquire(); " +
"SEMAPHORE_SCRIPT.acquire(); " + /* STARTUP BLOCKS HERE! */
"if (SHUTDOWN) { SCRIPT_KILL(); } " +
"if (TIMEOUT) { SCRIPT_TIMEOUT(); } " +
"msg = new java.lang.String(msg); " +
"node.setMoteMsg(mote, msg); " +
code + "\n" +
"while (true) { SCRIPT_SWITCH(); } " /* SCRIPT ENDED */+
"};";
}
public long getTimeoutTime() {
return timeoutTime;
}
public class ScriptSyntaxErrorException extends ScriptException {
public ScriptSyntaxErrorException(String msg) {
super(msg);
}
}
}