/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. */ package org.thingml.compilers.thing.common; import org.sintef.thingml.*; import org.sintef.thingml.constraints.ThingMLHelpers; import org.sintef.thingml.helpers.AnnotatedElementHelper; import org.sintef.thingml.helpers.ThingMLElementHelper; import org.thingml.compilers.Context; import org.thingml.compilers.thing.ThingActionCompiler; import org.thingml.compilers.utils.CharacterEscaper; /** * Created by bmori on 01.12.2014. */ public class CommonThingActionCompiler extends ThingActionCompiler { //ThingML actions that can be compiled the same way for any imperative language like (Java, JS, C) @Override public void generate(SendAction action, StringBuilder builder, Context ctx) {//TODO: this might actually be factorizable if we agree on the methods' signatures to send message builder.append("//Platform-specific action (" + action.getClass().getName() + ") should be refined in a sub-compiler"); } public void traceVariablePre(VariableAssignment action, StringBuilder builder, Context ctx) { } public void traceVariablePost(VariableAssignment action, StringBuilder builder, Context ctx) { } @Override public void generate(VariableAssignment action, StringBuilder builder, Context ctx) { traceVariablePre(action, builder, ctx); if (action.getProperty().getCardinality() != null && action.getIndex() != null) {//this is an array (and we want to affect just one index) for (Expression i : action.getIndex()) { builder.append(ThingMLElementHelper.qname(action.getProperty(), "_") + "_var"); StringBuilder tempBuilder = new StringBuilder(); generate(i, tempBuilder, ctx); builder.append("[" + tempBuilder.toString() + "]"); builder.append(" = "); cast(action.getProperty().getType(), false, action.getExpression(), builder, ctx); //generateMainAndInit(action.getExpression(), builder, ctx); builder.append(";\n"); } } else {//simple variable or we re-affect the whole array if (action.getProperty().eContainer() instanceof Thing) { builder.append(ctx.getContextAnnotation("thisRef")); } builder.append(ThingMLElementHelper.qname(action.getProperty(), "_") + "_var"); builder.append(" = "); cast(action.getProperty().getType(), action.getProperty().isIsArray(), action.getExpression(), builder, ctx); //generateMainAndInit(action.getExpression(), builder, ctx); builder.append(";\n"); } traceVariablePost(action, builder, ctx); } public void cast(Type type, boolean isArray, Expression exp, StringBuilder builder, Context ctx) { generate(exp, builder, ctx); } @Override public void generate(ActionBlock action, StringBuilder builder, Context ctx) { for (Action a : action.getActions()) { generate(a, builder, ctx); } } @Override public void generate(ExternStatement action, StringBuilder builder, Context ctx) { builder.append(action.getStatement()); for (Expression e : action.getSegments()) { generate(e, builder, ctx); } builder.append("\n"); } @Override public void generate(ConditionalAction action, StringBuilder builder, Context ctx) { builder.append("if("); generate(action.getCondition(), builder, ctx); builder.append(") {\n"); generate(action.getAction(), builder, ctx); builder.append("\n}"); if (action.getElseAction() != null) { builder.append(" else {\n"); generate(action.getElseAction(), builder, ctx); builder.append("\n}"); } builder.append("\n"); } @Override public void generate(LoopAction action, StringBuilder builder, Context ctx) { builder.append("while("); generate(action.getCondition(), builder, ctx); builder.append(") {\n"); generate(action.getAction(), builder, ctx); builder.append("\n}\n"); } @Override public void generate(PrintAction action, StringBuilder builder, Context ctx) { builder.append("//Platform-specific action (" + action.getClass() + ") should be refined in a sub-compiler"); } @Override public void generate(ErrorAction action, StringBuilder builder, Context ctx) { builder.append("//Platform-specific action (" + action.getClass() + ") should be refined in a sub-compiler"); } @Override public void generate(ReturnAction action, StringBuilder builder, Context ctx) { builder.append("return "); TypedElement parent = ThingMLHelpers.findContainingFuncOp(action); boolean isArray = false; if (action.getExp() instanceof PropertyReference) { PropertyReference pr = (PropertyReference) action.getExp(); isArray = pr.getProperty().isIsArray() || pr.getProperty().getCardinality() != null; } cast(parent.getType(), isArray, action.getExp(), builder, ctx); builder.append(";\n"); } @Override public void generate(LocalVariable action, StringBuilder builder, Context ctx) { builder.append("//Platform-specific action (" + action.getClass() + ") should be refined in a sub-compiler"); } @Override public void generate(FunctionCallStatement action, StringBuilder builder, Context ctx) { builder.append("//Platform-specific action (" + action.getClass() + ") should be refined in a sub-compiler"); } @Override public void generate(Increment action, StringBuilder builder, Context ctx) { generate(action.getVar(), builder, ctx); builder.append("++;\n"); } @Override public void generate(Decrement action, StringBuilder builder, Context ctx) { generate(action.getVar(), builder, ctx); builder.append("--;\n"); } //ThingML expressions that can be compiled the same way for any imperative language like (Java, JS, C) @Override public void generate(ArrayIndex expression, StringBuilder builder, Context ctx) { generate(expression.getArray(), builder, ctx); builder.append("["); generate(expression.getIndex(), builder, ctx); builder.append("]\n"); } @Override public void generate(OrExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" || "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(AndExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" && "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(LowerExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" < "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(GreaterExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" > "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(LowerOrEqualExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" <= "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(GreaterOrEqualExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" >= "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(EqualsExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" == "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(NotEqualsExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" != "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(PlusExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" + "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(MinusExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" - "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(TimesExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" * "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(DivExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" / "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(ModExpression expression, StringBuilder builder, Context ctx) { generate(expression.getLhs(), builder, ctx); builder.append(" % "); generate(expression.getRhs(), builder, ctx); } @Override public void generate(UnaryMinus expression, StringBuilder builder, Context ctx) { builder.append(" -"); generate(expression.getTerm(), builder, ctx); } @Override public void generate(NotExpression expression, StringBuilder builder, Context ctx) { builder.append(" !("); generate(expression.getTerm(), builder, ctx); builder.append(")"); } @Override public void generate(Reference expression, StringBuilder builder, Context ctx) { String messageName = ""; Message message = null; if (expression.getReference() instanceof ReceiveMessage) { ReceiveMessage rm = (ReceiveMessage) expression.getReference(); message = rm.getMessage(); messageName = message.getName(); } else if (expression.getReference() instanceof Source) { Source source = (Source) expression.getReference(); if (source instanceof SimpleSource) { ReceiveMessage rm = ((SimpleSource) source).getMessage(); message = rm.getMessage(); messageName = source.getName(); } else if (source instanceof SourceComposition) { message = ((SourceComposition) source).getResultMessage(); messageName = source.getName(); } else { throw new UnsupportedOperationException("Source " + source.getClass().getName() + " not supported."); } } else if (expression.getReference() instanceof MessageParameter) { MessageParameter mp = (MessageParameter) expression.getReference(); messageName = mp.getName(); message = mp.getMsgRef(); } else if (expression.getReference() instanceof Variable) { Variable var = (Variable) expression.getReference(); if (var.isIsArray()) { generateReferenceArray(var, builder, ctx); return; } else { throw new UnsupportedOperationException("The variable " + var.getName() + " must be an array."); } } else if (expression.getReference() instanceof Message) { Message msg = (Message) expression.getReference(); messageName = msg.getName(); message = msg; } else { throw new UnsupportedOperationException("Reference " + expression.getReference().getClass().getName() + " not supported."); } generateReference(message, messageName, expression, builder, ctx); } protected void generateReferenceArray(Variable variable, StringBuilder builder, Context context) { builder.append(context.getVariableName(variable) + ".length"); } protected void generateReference(Message message, String messageName, Reference reference, StringBuilder builder, Context ctx) { throw (new UnsupportedOperationException("This part of reference compiler (CommonThingActionCompiler) is platform specific and should be redefined.")); } @Override public void generate(ExpressionGroup expression, StringBuilder builder, Context ctx) { builder.append("("); generate(expression.getExp(), builder, ctx); builder.append(")"); } @Override public void generate(PropertyReference expression, StringBuilder builder, Context ctx) { builder.append("//Platform-specific expression (" + expression.getClass() + ") should be refined in a sub-compiler"); } @Override public void generate(IntegerLiteral expression, StringBuilder builder, Context ctx) { builder.append(expression.getIntValue()); } @Override public void generate(DoubleLiteral expression, StringBuilder builder, Context ctx) { builder.append(expression.getDoubleValue()); } @Override public void generate(StringLiteral expression, StringBuilder builder, Context ctx) { builder.append("\"" + CharacterEscaper.escapeEscapedCharacters(expression.getStringValue()) + "\""); } @Override public void generate(BooleanLiteral expression, StringBuilder builder, Context ctx) { if (expression.isBoolValue()) builder.append("true"); else builder.append("false"); } @Override public void generate(EnumLiteralRef expression, StringBuilder builder, Context ctx) { builder.append("//Platform-specific expression (" + expression.getClass() + ") should be refined in a sub-compiler"); } @Override public void generate(ExternExpression expression, StringBuilder builder, Context ctx) { builder.append(expression.getExpression()); for (Expression e : expression.getSegments()) { generate(e, builder, ctx); } } @Override public void generate(FunctionCallExpression expression, StringBuilder builder, Context ctx) {//TODO: this should actually be factorizable builder.append("//Platform-specific expression (" + expression.getClass() + ") should be refined in a sub-compiler"); } }