diff --git a/monticore-generator/src/main/java/de/monticore/MontiCoreScript.java b/monticore-generator/src/main/java/de/monticore/MontiCoreScript.java index 5202c8ff3b..d9a4e9c1ed 100644 --- a/monticore-generator/src/main/java/de/monticore/MontiCoreScript.java +++ b/monticore-generator/src/main/java/de/monticore/MontiCoreScript.java @@ -806,12 +806,14 @@ protected void decorateWithTraverser(ASTCDCompilationUnit cd, public void decorateWithInterpreter(List cds, ASTCDCompilationUnit decoratedCD, GlobalExtensionManagement glex) { + + ASTService astService = new ASTService(cds.get(0)); VisitorService visitorService = new VisitorService(cds.get(0)); InterpreterInterfaceDecorator interpreterInterfaceDecorator = new InterpreterInterfaceDecorator(glex, visitorService); interpreterInterfaceDecorator.decorate(cds.get(0), decoratedCD); - InterpreterDecorator interpreterDecorator = new InterpreterDecorator(glex, visitorService); + InterpreterDecorator interpreterDecorator = new InterpreterDecorator(glex, astService, visitorService); interpreterDecorator.decorate(cds.get(0), decoratedCD); ASTEvaluateDecorator evaluateDecorator = new ASTEvaluateDecorator(glex, visitorService); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/SymbolTableConstants.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/SymbolTableConstants.java index a182ef2a91..8eb9ef6007 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/SymbolTableConstants.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/SymbolTableConstants.java @@ -88,7 +88,7 @@ private SymbolTableConstants() { public static final String I_STEREOTYPE_REFERENCE = "de.monticore.symboltable.stereotypes.IStereotypeReference"; - public static final String INTERPRETER_VALUE = "de.monticore.interpreter.Value"; + public static final String INTERPRETER_VALUE = "de.monticore.interpreter.MIValue"; /** * attribute names diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/ASTEvaluateDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/ASTEvaluateDecorator.java index aab35bc66d..7fe335d1f1 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/ASTEvaluateDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/ASTEvaluateDecorator.java @@ -1,6 +1,8 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.codegen.cd2java.interpreter; +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.cd4code._util.ICD4CodeTypeDispatcher; import de.monticore.cd4codebasis._ast.ASTCDMethod; import de.monticore.cd4codebasis._ast.ASTCDParameter; import de.monticore.cdbasis._ast.*; @@ -35,9 +37,10 @@ public ASTEvaluateDecorator(GlobalExtensionManagement glex, public void decorate(ASTCDCompilationUnit input, ASTCDCompilationUnit decoratedCD) { ASTCDPackage astPackage = getPackage(input, decoratedCD, ASTConstants.AST_PACKAGE); + ICD4CodeTypeDispatcher dispatcher = CD4CodeMill.typeDispatcher(); astPackage.streamCDElements() - .filter(e -> e instanceof ASTCDClass) - .map(e -> (ASTCDClass) e) + .filter(dispatcher::isCDBasisASTCDClass) + .map(dispatcher::asCDBasisASTCDClass) .forEach(t -> t.addAllCDMembers(decorate(t))); } @@ -74,7 +77,7 @@ protected ASTCDMethod createEvaluateInterpreterMethod(ASTCDType cdType) { protected ASTCDMethod createEvaluateInterpreterSuperMethod(ASTCDType cdType) { ASTCDParameter parameter = cdParameterFacade.createParameter( - mcTypeFacade.createQualifiedType(InterpreterConstants.MODELINTERPRETER_FULLNAME), + mcTypeFacade.createQualifiedType(InterpreterConstants.IMODELINTERPRETER_FULLNAME), "interpreter"); ASTCDMethod method = cdMethodFacade.createMethod( PUBLIC.build(), InterpreterConstants.VALUE_FULLNAME, "evaluate", parameter); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/InterpreterConstants.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/InterpreterConstants.java index 4d77a01605..72348ad70b 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/InterpreterConstants.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/InterpreterConstants.java @@ -8,15 +8,20 @@ public final class InterpreterConstants { public static final String INTERPRET_METHOD_NAME = "interpret"; public static final String MODELINTERPRETER_FULLNAME = "de.monticore.interpreter.ModelInterpreter"; + public static final String IMODELINTERPRETER_FULLNAME = "de.monticore.interpreter.IModelInterpreter"; + + public static final String INTERPRETER_SCOPE_FULLNAME = "de.monticore.interpreter.MIScope"; - public static final String VALUE_FULLNAME = "de.monticore.interpreter.Value"; + public static final String VALUE_FULLNAME = "de.monticore.interpreter.MIValue"; + public static final String FUNCTION_VALUE_FULLNAME = "de.monticore.interpreter.values.FunctionMIValue"; - public static final String NOT_A_VALUE_FULLNAME = "de.monticore.interpreter.values.NotAValue"; public static final String NODE_TYPE = "de.monticore.ast.ASTNode"; public static final String NODE_PARAMETER = "node"; public static final String SYMBOL_FULLNAME = "de.monticore.symboltable.ISymbol"; + public static final String VARIABLE_SYMBOL_FULLNAME = "de.monticore.symbols.basicsymbols._symboltable.VariableSymbol"; + public static final String FUNCTION_SYMBOL_FULLNAME = "de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol"; } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/InterpreterDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/InterpreterDecorator.java index 00a3220062..4c32a6112d 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/InterpreterDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/interpreter/InterpreterDecorator.java @@ -9,6 +9,7 @@ import de.monticore.cdbasis._ast.*; import de.monticore.cdbasis._symboltable.CDTypeSymbol; import de.monticore.codegen.cd2java.AbstractCreator; +import de.monticore.codegen.cd2java._ast.ast_class.ASTService; import de.monticore.codegen.cd2java._visitor.VisitorConstants; import de.monticore.codegen.cd2java._visitor.VisitorService; import de.monticore.codegen.cd2java.methods.MethodDecorator; @@ -17,6 +18,7 @@ import de.monticore.generating.templateengine.TemplateHookPoint; import de.monticore.symbols.basicsymbols._symboltable.DiagramSymbol; import de.monticore.types.mcbasictypes._ast.ASTMCReturnType; +import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.util.ArrayList; import java.util.List; @@ -28,13 +30,17 @@ public class InterpreterDecorator extends AbstractCreator { + + protected final ASTService astService; - protected final VisitorService service; + protected final VisitorService visitorService; public InterpreterDecorator(GlobalExtensionManagement glex, - VisitorService service) { + ASTService astService, + VisitorService visitorService) { super(glex); - this.service = service; + this.astService = astService; + this.visitorService = visitorService; } public void decorate(ASTCDCompilationUnit input, @@ -48,7 +54,7 @@ public void decorate(ASTCDCompilationUnit input, public ASTCDClass decorate(ASTCDCompilationUnit input) { return CD4CodeMill.cDClassBuilder() .setModifier(PUBLIC.build()) - .setName(service.getInterpreterSimpleName()) + .setName(visitorService.getInterpreterSimpleName()) .setCDInterfaceUsage(getSuperInterface()) .addAllCDMembers(getInterpreterAttributes()) .addAllCDMembers(getConstructors()) @@ -62,7 +68,7 @@ public List getConstructors() { ASTCDParameter parameter = cdParameterFacade.createParameter( MODELINTERPRETER_FULLNAME, "realThis"); - String interpreterName = service.getInterpreterSimpleName(); + String interpreterName = visitorService.getInterpreterSimpleName(); ASTCDConstructor constructorNoParams = cdConstructorFacade .createConstructor(PUBLIC.build(), interpreterName); ASTCDConstructor constructorRealThis = cdConstructorFacade @@ -71,9 +77,9 @@ public List getConstructors() { List names = new ArrayList<>(); List types = new ArrayList<>(); - for (DiagramSymbol symbol : service.getSuperCDsTransitive()) { - names.add(service.getInterpreterSimpleName(symbol)); - types.add(service.getInterpreterFullName(symbol)); + for (DiagramSymbol symbol : visitorService.getSuperCDsTransitive()) { + names.add(visitorService.getInterpreterSimpleName(symbol)); + types.add(visitorService.getInterpreterFullName(symbol)); } replaceTemplate(EMPTY_BODY, constructorRealThis, @@ -90,25 +96,29 @@ public List getInterpretMethods() { ASTMCReturnType returnType = CD4CodeMill.mCReturnTypeBuilder() .setMCType(mcTypeFacade.createQualifiedType(VALUE_FULLNAME)).build(); - for (CDTypeSymbol typeSymbol : service.getAllCDTypes()) { + for (CDTypeSymbol typeSymbol : visitorService.getAllCDTypes()) { if (typeSymbol.isIsClass() || typeSymbol.isIsInterface()) { ASTCDParameter parameter = cdParameterFacade - .createParameter(service.createASTFullName(typeSymbol), NODE_PARAMETER); + .createParameter(visitorService.createASTFullName(typeSymbol), NODE_PARAMETER); ASTCDMethod method = cdMethodFacade.createMethod( PUBLIC.build(), returnType, "interpret", parameter); - this.replaceTemplate( - EMPTY_BODY, method, new StringHookPoint("return node.evaluate(getRealThis());")); + + String errorCode = astService.getGeneratedErrorCode(typeSymbol.getFullName()); + + this.replaceTemplate(EMPTY_BODY, method, + new TemplateHookPoint("interpreter.NoImplementation", + typeSymbol.getFullName(), errorCode)); methods.add(method); } } - for (DiagramSymbol diagramSymbol : service.getSuperCDsTransitive()) { - if (diagramSymbol != service.getCDSymbol()) { - String interpreterName = uncapFirst(service.getInterpreterSimpleName(diagramSymbol)); - for (CDTypeSymbol typeSymbol : service.getAllCDTypes(diagramSymbol)) { + for (DiagramSymbol diagramSymbol : visitorService.getSuperCDsTransitive()) { + if (diagramSymbol != visitorService.getCDSymbol()) { + String interpreterName = uncapFirst(visitorService.getInterpreterSimpleName(diagramSymbol)); + for (CDTypeSymbol typeSymbol : visitorService.getAllCDTypes(diagramSymbol)) { if (typeSymbol.isIsClass() || typeSymbol.isIsInterface()) { ASTCDParameter parameter = cdParameterFacade - .createParameter(service.createASTFullName(typeSymbol), NODE_PARAMETER); + .createParameter(visitorService.createASTFullName(typeSymbol), NODE_PARAMETER); ASTCDMethod method = cdMethodFacade.createMethod( PUBLIC.build(), returnType, "interpret", parameter); this.replaceTemplate( @@ -126,29 +136,55 @@ EMPTY_BODY, method, new StringHookPoint( public List createMapMembers() { List members = new ArrayList<>(); - - members.add(cdAttributeFacade.createAttribute( - PROTECTED.build(), - mcTypeFacade.createMapTypeOf(SYMBOL_FULLNAME, VALUE_FULLNAME), - "contextMap")); - - ASTCDParameter symbolParameter = cdParameterFacade.createParameter(SYMBOL_FULLNAME, "symbol"); - ASTCDParameter valueParameter = cdParameterFacade.createParameter(VALUE_FULLNAME, "value"); - ASTCDMethod storeMethod = cdMethodFacade.createMethod( - PUBLIC.build(), "store", symbolParameter, valueParameter); - this.replaceTemplate(EMPTY_BODY, storeMethod, new StringHookPoint("getRealThis().getContextMap().put(symbol, value);")); - members.add(storeMethod); - - ASTCDMethod loadMethod = cdMethodFacade.createMethod(PUBLIC.build(), VALUE_FULLNAME, "load", symbolParameter); - this.replaceTemplate(EMPTY_BODY, loadMethod, new StringHookPoint("return getRealThis().getContextMap().get(symbol);")); - members.add(loadMethod); - - ASTCDMethod getter = cdMethodFacade.createMethod( - PUBLIC.build(), - mcTypeFacade.createMapTypeOf(SYMBOL_FULLNAME, VALUE_FULLNAME), - "getContextMap"); - this.replaceTemplate(EMPTY_BODY, getter, new StringHookPoint("return this.contextMap;")); - members.add(getter); + + ASTMCType scopeStackType = mcTypeFacade.createBasicGenericTypeOf("java.util.Stack", INTERPRETER_SCOPE_FULLNAME); + + members.add(cdAttributeFacade.createAttribute(PROTECTED.build(), scopeStackType, "scopeCallstack")); + +// ASTCDMethod declareFuncMethod = cdMethodFacade.createMethod( +// PUBLIC.build(), "declareFunction", functionSymbolParameter, functionValueParameter); +// this.replaceTemplate(EMPTY_BODY, declareFuncMethod, new StringHookPoint("getRealThis().getCurrentScope().declareFunction(symbol, value);")); +// members.add(declareFuncMethod); +// +// ASTCDMethod loadFuncMethod = cdMethodFacade.createMethod(PUBLIC.build(), VALUE_FULLNAME, "loadFunction", functionSymbolParameter); +// this.replaceTemplate(EMPTY_BODY, loadFuncMethod, new StringHookPoint("return getRealThis().getCurrentScope().loadFunction(symbol);")); +// members.add(loadFuncMethod); +// +// ASTCDMethod declareVarMethod = cdMethodFacade.createMethod( +// PUBLIC.build(), "declareVariable", variableSymbolParameter, optionalValueParameter); +// this.replaceTemplate(EMPTY_BODY, declareVarMethod, new StringHookPoint("getRealThis().getCurrentScope().declareVariable(symbol, value);")); +// members.add(declareVarMethod); +// +// ASTCDMethod loadVarMethod = cdMethodFacade.createMethod(PUBLIC.build(), VALUE_FULLNAME, +// "loadVariable", variableSymbolParameter); +// this.replaceTemplate(EMPTY_BODY, loadVarMethod, new StringHookPoint("return getRealThis().getCurrentScope().loadVariable(symbol);")); +// members.add(loadVarMethod); +// +// ASTCDMethod storeVarMethod = cdMethodFacade.createMethod( +// PUBLIC.build(), "storeVariable", variableSymbolParameter, valueParameter); +// this.replaceTemplate(EMPTY_BODY, storeVarMethod, new StringHookPoint("getRealThis().getCurrentScope().storeVariable(symbol, value);")); +// members.add(storeVarMethod); +// +// ASTCDMethod getter = cdMethodFacade.createMethod( +// PUBLIC.build(), +// mcTypeFacade.createQualifiedType(INTERPRETER_SCOPE_FULLNAME), +// "getCurrentScope"); +// this.replaceTemplate(EMPTY_BODY, getter, new StringHookPoint("return getRealThis().scopeCallstack.peek();")); +// members.add(getter); +// +// ASTCDParameter scopeParameter = cdParameterFacade.createParameter(INTERPRETER_SCOPE_FULLNAME, "scope"); +// ASTCDMethod pushScopeMethod = cdMethodFacade.createMethod(PUBLIC.build(), "pushScope", scopeParameter); +// this.replaceTemplate(EMPTY_BODY, pushScopeMethod, new StringHookPoint("getRealThis().scopeCallstack.push(scope);")); +// members.add(pushScopeMethod); +// +// ASTCDMethod popScopeMethod = cdMethodFacade.createMethod(PUBLIC.build(), "popScope"); +// this.replaceTemplate(EMPTY_BODY, popScopeMethod, new StringHookPoint("getRealThis().scopeCallstack.pop();")); +// members.add(popScopeMethod); + + ASTCDMethod getScopeCallstackMethod = cdMethodFacade.createMethod(PUBLIC.build(), scopeStackType, + "getScopeCallstack"); + this.replaceTemplate(EMPTY_BODY, getScopeCallstackMethod, new StringHookPoint("return scopeCallstack;")); + members.add(getScopeCallstackMethod); return members; } @@ -163,24 +199,24 @@ public List getRealThisComponents() { "realThis"); components.add(realThisAttribute); - MethodDecorator methodDecorator = new MethodDecorator(glex, service); + MethodDecorator methodDecorator = new MethodDecorator(glex, visitorService); components.addAll(methodDecorator.decorate(realThisAttribute)); return components; } public List getInterpreterAttributes() { - return service.getSuperCDsTransitive() + return visitorService.getSuperCDsTransitive() .stream() .map(s -> cdAttributeFacade.createAttribute( - PROTECTED.build(), service.getInterpreterType(s), - uncapFirst(service.getInterpreterSimpleName(s)))) + PROTECTED.build(), visitorService.getInterpreterType(s), + uncapFirst(visitorService.getInterpreterSimpleName(s)))) .collect(Collectors.toList()); } public ASTCDInterfaceUsage getSuperInterface() { return CDInterfaceUsageFacade.getInstance() - .createCDInterfaceUsage(service.getInterpreterInterfaceSimpleName()); + .createCDInterfaceUsage(visitorService.getInterpreterInterfaceSimpleName()); } protected String uncapFirst(String s) { diff --git a/monticore-generator/src/main/resources/_symboltable/serialization/symbolDeSer/Deserialize4SymbolDeSer.ftl b/monticore-generator/src/main/resources/_symboltable/serialization/symbolDeSer/Deserialize4SymbolDeSer.ftl index 81faa30695..7c394ea029 100644 --- a/monticore-generator/src/main/resources/_symboltable/serialization/symbolDeSer/Deserialize4SymbolDeSer.ftl +++ b/monticore-generator/src/main/resources/_symboltable/serialization/symbolDeSer/Deserialize4SymbolDeSer.ftl @@ -11,7 +11,7 @@ ${tc.signature("symTabMill", "symbolFullName", "symbolSimpleName","symbolRuleAtt } if (symbolJson.hasArrayMember(de.monticore.symboltable.serialization.JsonDeSers.STEREO_INFO)) { for (de.monticore.symboltable.serialization.json.JsonElement stereoinfoJson : symbolJson.getArrayMember(de.monticore.symboltable.serialization.JsonDeSers.STEREO_INFO)) { - java.util.Map.Entry> stereoinfo = de.monticore.symboltable.stereotypes.StereoinfoDeSer.deserialize(stereoinfoJson, scope); + java.util.Map.Entry> stereoinfo = de.monticore.symboltable.stereotypes.StereoinfoDeSer.deserialize(stereoinfoJson, scope); if (stereoinfo.getValue().isPresent()) { builder.addStereoinfo(stereoinfo.getKey(), stereoinfo.getValue().get()); } else { diff --git a/monticore-generator/src/main/resources/interpreter/ConstructorNoParams.ftl b/monticore-generator/src/main/resources/interpreter/ConstructorNoParams.ftl index 21493050e3..5e8edee364 100644 --- a/monticore-generator/src/main/resources/interpreter/ConstructorNoParams.ftl +++ b/monticore-generator/src/main/resources/interpreter/ConstructorNoParams.ftl @@ -1,7 +1,8 @@ <#-- (c) https://github.com/MontiCore/monticore --> ${tc.signature("names", "types")} -this.contextMap = new java.util.HashMap<>(); +this.scopeCallstack = new Stack(); +this.scopeCallstack.push(new de.monticore.interpreter.MIScope()); this.setRealThis(this); <#list names as name> this.${name?uncap_first} = new ${types[name?index]}(this); diff --git a/monticore-generator/src/main/resources/interpreter/NoImplementation.ftl b/monticore-generator/src/main/resources/interpreter/NoImplementation.ftl new file mode 100644 index 0000000000..1f38bd05eb --- /dev/null +++ b/monticore-generator/src/main/resources/interpreter/NoImplementation.ftl @@ -0,0 +1,6 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("name", "errorCode")} + +String errorMsg = "0x57086${errorCode} Interpreter was not implemented for ${name}"; +de.se_rwth.commons.logging.Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); +return new de.monticore.interpreter.values.ErrorMIValue(errorMsg); \ No newline at end of file diff --git a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecoratorTest.java b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecoratorTest.java index 9fb5b8f90d..689af615d7 100644 --- a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecoratorTest.java +++ b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecoratorTest.java @@ -48,7 +48,7 @@ public class SymbolBuilderDecoratorTest extends DecoratorTestCase { private static final String I_STEREOTYPE_REF = "de.monticore.symboltable.stereotypes.IStereotypeReference"; - private static final String VALUE = "de.monticore.interpreter.Value"; + private static final String VALUE = "de.monticore.interpreter.MIValue"; @BeforeEach public void setup() { diff --git a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecoratorTest.java b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecoratorTest.java index 0ef717575e..393e7fb1d0 100644 --- a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecoratorTest.java +++ b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecoratorTest.java @@ -65,7 +65,7 @@ public class SymbolDecoratorTest extends DecoratorTestCase { private static final String I_STEREOTYPE_REF = "de.monticore.symboltable.stereotypes.IStereotypeReference"; - private static final String VALUE = "de.monticore.interpreter.Value"; + private static final String VALUE = "de.monticore.interpreter.MIValue"; private static final String I_AUTOMATON_SCOPE = "de.monticore.codegen.symboltable.automatonsymbolcd._symboltable.IAutomatonSymbolCDScope"; diff --git a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolSurrogateBuilderDecoratorTest.java b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolSurrogateBuilderDecoratorTest.java index 8f54255ab6..aa4afa9e8b 100644 --- a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolSurrogateBuilderDecoratorTest.java +++ b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolSurrogateBuilderDecoratorTest.java @@ -44,7 +44,7 @@ public class SymbolSurrogateBuilderDecoratorTest extends DecoratorTestCase { private static final String I_STEREOTYPE_REF = "de.monticore.symboltable.stereotypes.IStereotypeReference"; - private static final String VALUE = "de.monticore.interpreter.Value"; + private static final String VALUE = "de.monticore.interpreter.MIValue"; @BeforeEach public void setUp() { diff --git a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolSurrogateDecoratorTest.java b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolSurrogateDecoratorTest.java index d381157c19..7fc585280e 100644 --- a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolSurrogateDecoratorTest.java +++ b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolSurrogateDecoratorTest.java @@ -50,7 +50,7 @@ public class SymbolSurrogateDecoratorTest extends DecoratorTestCase { private static final String I_STEREOTYPE_REF = "de.monticore.symboltable.stereotypes.IStereotypeReference"; - private static final String VALUE = "de.monticore.interpreter.Value"; + private static final String VALUE = "de.monticore.interpreter.MIValue"; private static final String I_AUTOMATON_SCOPE = "de.monticore.codegen.symboltable.automatonsymbolcd._symboltable.IAutomatonSymbolCDScope"; diff --git a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/interpreter/InterpreterDecoratorTest.java b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/interpreter/InterpreterDecoratorTest.java index 70e02545fc..ab77c3e529 100644 --- a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/interpreter/InterpreterDecoratorTest.java +++ b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/interpreter/InterpreterDecoratorTest.java @@ -7,16 +7,18 @@ import de.monticore.cdbasis._ast.ASTCDClass; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.codegen.cd2java.DecoratorTestCase; +import de.monticore.codegen.cd2java._ast.ast_class.ASTService; import de.monticore.codegen.cd2java._visitor.VisitorService; import de.monticore.types.mcbasictypes._ast.ASTMCObjectType; import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; import de.monticore.types.mccollectiontypes._ast.ASTMCMapType; +import de.monticore.types.mcsimplegenerictypes._ast.ASTMCBasicGenericType; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -25,7 +27,6 @@ public class InterpreterDecoratorTest extends DecoratorTestCase { - protected ASTCDCompilationUnit originalCompilationUnit; protected ASTCDClass decoratedClass; @@ -33,16 +34,17 @@ public class InterpreterDecoratorTest extends DecoratorTestCase { @BeforeEach public void before() { originalCompilationUnit = this.parse("de", "monticore", "codegen", "ast", "Automaton"); + ASTService astService = new ASTService(originalCompilationUnit); VisitorService visitorService = new VisitorService(originalCompilationUnit); this.glex.setGlobalValue("service", new VisitorService(originalCompilationUnit)); - InterpreterDecorator decorator = new InterpreterDecorator(this.glex, visitorService); + InterpreterDecorator decorator = new InterpreterDecorator(this.glex, astService, visitorService); this.decoratedClass = decorator.decorate(originalCompilationUnit); } @Test public void testMethodCount() { - assertEquals(5, decoratedClass.getCDMethodList().size()); + assertEquals(3, decoratedClass.getCDMethodList().size()); } @Test @@ -53,14 +55,14 @@ public void testConstructors() { assertTrue(constructors.get(0).getCDParameterList().isEmpty()); assertEquals( - 1, - constructors.get(1).getCDParameterList().size()); + 1, + constructors.get(1).getCDParameterList().size()); assertEquals( - "realThis", - constructors.get(1).getCDParameter(0).getName()); + "realThis", + constructors.get(1).getCDParameter(0).getName()); assertEquals( - InterpreterConstants.MODELINTERPRETER_FULLNAME, - constructors.get(1).getCDParameter(0).getMCType().printType()); + InterpreterConstants.MODELINTERPRETER_FULLNAME, + constructors.get(1).getCDParameter(0).getMCType().printType()); } @Test @@ -70,8 +72,8 @@ public void testSuperInterfaces() { assertEquals(1, interfaces.size()); assertEquals( - "IAutomatonInterpreter", - ((ASTMCQualifiedType) interfaces.get(0)).getMCQualifiedName().getQName()); + "IAutomatonInterpreter", + ((ASTMCQualifiedType) interfaces.get(0)).getMCQualifiedName().getQName()); } @Test @@ -81,29 +83,26 @@ public void testClassAttributes() { assertEquals(3, attributes.size()); assertEquals( - "lexicalsInterpreter", - attributes.get(0).getName()); + "lexicalsInterpreter", + attributes.get(0).getName()); assertEquals( - "de.monticore.codegen.ast.lexicals._visitor.ILexicalsInterpreter", - attributes.get(0).getMCType().printType()); + "de.monticore.codegen.ast.lexicals._visitor.ILexicalsInterpreter", + attributes.get(0).getMCType().printType()); assertEquals( - "realThis", - attributes.get(1).getName()); + "realThis", + attributes.get(1).getName()); assertEquals( - InterpreterConstants.MODELINTERPRETER_FULLNAME, - attributes.get(1).getMCType().printType()); + InterpreterConstants.MODELINTERPRETER_FULLNAME, + attributes.get(1).getMCType().printType()); assertEquals( - "contextMap", - attributes.get(2).getName()); - assertInstanceOf(ASTMCMapType.class, attributes.get(2).getMCType()); - assertEquals( - InterpreterConstants.SYMBOL_FULLNAME, - ((ASTMCMapType) attributes.get(2).getMCType()).getMCTypeArgument(0).printType()); + "scopeCallstack", + attributes.get(2).getName()); + assertInstanceOf(ASTMCBasicGenericType.class, attributes.get(2).getMCType()); assertEquals( - InterpreterConstants.VALUE_FULLNAME, - ((ASTMCMapType) attributes.get(2).getMCType()).getMCTypeArgument(1).printType()); + "java.util.Stack<"+InterpreterConstants.INTERPRETER_SCOPE_FULLNAME+">", + attributes.get(2).getMCType().printType()); } @Test @@ -118,8 +117,8 @@ public void testRealThisMethods() { assertTrue(getMethod.getCDParameterList().isEmpty()); assertEquals( - InterpreterConstants.MODELINTERPRETER_FULLNAME, - getMethod.getMCReturnType().printType()); + InterpreterConstants.MODELINTERPRETER_FULLNAME, + getMethod.getMCReturnType().printType()); Optional optSetMethod = decoratedClass.getCDMethodList() .stream() @@ -131,70 +130,29 @@ public void testRealThisMethods() { assertEquals(1, setMethod.getCDParameterList().size()); assertEquals( - InterpreterConstants.MODELINTERPRETER_FULLNAME, - setMethod.getCDParameter(0).getMCType().printType()); + InterpreterConstants.MODELINTERPRETER_FULLNAME, + setMethod.getCDParameter(0).getMCType().printType()); assertEquals( - "realThis", - setMethod.getCDParameter(0).getName()); + "realThis", + setMethod.getCDParameter(0).getName()); assertTrue(setMethod.getMCReturnType().isPresentMCVoidType()); } @Test - public void testContextMethods() { - Optional optStoreMethod = decoratedClass.getCDMethodList() - .stream() - .filter(m -> m.getName().equals("store")) - .findAny(); - - assertTrue(optStoreMethod.isPresent()); - ASTCDMethod storeMethod = optStoreMethod.get(); - - assertTrue(storeMethod.getMCReturnType().isPresentMCVoidType()); - assertEquals(2, storeMethod.getCDParameterList().size()); - assertEquals("symbol", storeMethod.getCDParameter(0).getName()); - assertEquals( - InterpreterConstants.SYMBOL_FULLNAME, - storeMethod.getCDParameter(0).getMCType().printType()); - assertEquals("value", storeMethod.getCDParameter(1).getName()); - assertEquals( - InterpreterConstants.VALUE_FULLNAME, - storeMethod.getCDParameter(1).getMCType().printType()); - - Optional optLoadMethod = decoratedClass.getCDMethodList() + public void testScopeCallstackMethod() { + Optional optScopeCallstackMethod = decoratedClass.getCDMethodList() .stream() - .filter(m -> m.getName().equals("load")) + .filter(m -> m.getName().equals("getScopeCallstack")) .findAny(); - assertTrue(optLoadMethod.isPresent()); - ASTCDMethod loadMethod = optLoadMethod.get(); + assertTrue(optScopeCallstackMethod.isPresent()); + ASTCDMethod scopeCallstackMethod = optScopeCallstackMethod.get(); - assertEquals( - InterpreterConstants.VALUE_FULLNAME, - loadMethod.getMCReturnType().printType()); - assertEquals(1, loadMethod.getCDParameterList().size()); - assertEquals( - InterpreterConstants.SYMBOL_FULLNAME, - loadMethod.getCDParameter(0).getMCType().printType()); - assertEquals( - "symbol", - loadMethod.getCDParameter(0).getName()); - - Optional optGetMap = decoratedClass.getCDMethodList() - .stream() - .filter(m -> m.getName().equals("getContextMap")) - .findAny(); - - assertTrue(optGetMap.isPresent()); - ASTCDMethod getMapMethod = optGetMap.get(); - - assertTrue(getMapMethod.getCDParameterList().isEmpty()); - assertInstanceOf(ASTMCMapType.class, getMapMethod.getMCReturnType().getMCType()); - assertEquals( - InterpreterConstants.SYMBOL_FULLNAME, - ((ASTMCMapType) getMapMethod.getMCReturnType().getMCType()).getMCTypeArgument(0).printType()); - assertEquals( - InterpreterConstants.VALUE_FULLNAME, - ((ASTMCMapType) getMapMethod.getMCReturnType().getMCType()).getMCTypeArgument(1).printType()); + ASTMCGenericType returnTypeType = (ASTMCGenericType)scopeCallstackMethod.getMCReturnType().getMCType(); + assertEquals("java.util.Stack", returnTypeType.printWithoutTypeArguments()); + assertEquals(InterpreterConstants.INTERPRETER_SCOPE_FULLNAME, + returnTypeType.getMCTypeArgument(0).printType()); + assertTrue(scopeCallstackMethod.getCDParameterList().isEmpty()); } @Test @@ -219,4 +177,4 @@ public void after() { Log.getFindings().clear(); } -} +} \ No newline at end of file diff --git a/monticore-grammar/build.gradle b/monticore-grammar/build.gradle index 7a02502748..f77649049d 100644 --- a/monticore-grammar/build.gradle +++ b/monticore-grammar/build.gradle @@ -76,7 +76,7 @@ dependencies { api project(':monticore-runtime') implementation "com.google.guava:guava:$guava_version" implementation "org.apache.commons:commons-lang3:$commons_lang3_version" - + testImplementation "de.monticore:class2mc:$previous_mc_version" testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_version" testImplementation "org.junit.jupiter:junit-jupiter-params:$junit_version" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junit_version" diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreter.java index a15c38bec7..2833c3df16 100644 --- a/monticore-grammar/src/main/java/de/monticore/expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreter.java +++ b/monticore-grammar/src/main/java/de/monticore/expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreter.java @@ -1,20 +1,25 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.expressions.assignmentexpressions._visitor; -import de.monticore.expressions.assignmentexpressions.AssignmentExpressionsMill; import de.monticore.expressions.assignmentexpressions._ast.*; +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.interpreter.InterpreterUtils; import de.monticore.interpreter.ModelInterpreter; -import de.monticore.interpreter.Value; -import de.monticore.interpreter.ValueFactory; -import de.monticore.interpreter.values.NotAValue; -import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.WriteableMIValue; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.types.check.SymTypeExpression; import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.util.TypeVisitorOperatorCalculator; import de.se_rwth.commons.logging.Log; import java.util.Optional; import static de.monticore.expressions.assignmentexpressions._ast.ASTConstantsAssignmentExpressions.*; +import static de.monticore.interpreter.MIValueFactory.createValue; public class AssignmentExpressionsInterpreter extends AssignmentExpressionsInterpreterTOP { @@ -28,1318 +33,387 @@ public AssignmentExpressionsInterpreter() { //i++ @Override - public Value interpret(ASTIncSuffixExpression n) { - String expr = AssignmentExpressionsMill.prettyPrint(n.getExpression(), false); - Optional symbol = ((IBasicSymbolsScope) n.getEnclosingScope()).resolveVariable(expr); - if (symbol.isPresent()) { - Value value = load(symbol.get()); - if (value.isInt()) { - Value res = ValueFactory.createValue(value.asInt() + 1); - store(symbol.get(), res); - return res; - } else if (value.isChar()) { - Value res = ValueFactory.createValue(value.asChar() + 1); - store(symbol.get(), res); - return res; - } else if (value.isLong()) { - Value res = ValueFactory.createValue(value.asLong() + 1); - store(symbol.get(), res); - return res; - } else if (value.isFloat()) { - Value res = ValueFactory.createValue(value.asFloat() + 1); - store(symbol.get(), res); - return (res); - } else if (value.isDouble()) { - Value res = ValueFactory.createValue(value.asDouble() + 1); - store(symbol.get(), res); - return (res); - } else { - Log.error("Suffix incrementation operation is not suitable for this type."); + public MIValue interpret(ASTIncSuffixExpression n) { + ASTExpression expr = n.getExpression(); + SymTypeExpression type = TypeCheck3.typeOf(expr); + MIValue value = n.getExpression().evaluate(getRealThis()); + + if (value.isFlowControlSignal()) return value; + if (!value.isWriteable()) { + String errorMsg = "0x57094 Expected an LValue. Got " + value.printType() + " (" + value.printValue() + ")."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + WriteableMIValue variable = (WriteableMIValue)value; + + if (type.isPrimitive()) { + MIValue previousValue = variable.getMIValue(); + String primitive = type.asPrimitive().getPrimitiveName(); + if (primitive.equals(BasicSymbolsMill.BYTE)) { + MIValue res = createValue((byte)(variable.asByte() + 1)); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.SHORT)) { + MIValue res = createValue((short)(variable.asShort() + 1)); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.CHAR)) { + MIValue res = createValue((char)(variable.asChar() + 1)); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.INT)) { + MIValue res = createValue(variable.asInt() + 1); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.LONG)) { + MIValue res = createValue(variable.asLong() + 1L); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.FLOAT)) { + MIValue res = createValue(variable.asFloat() + 1.0f); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.DOUBLE)) { + MIValue res = createValue(variable.asDouble() + 1.0); + variable.write(res); + return previousValue; } } - return new NotAValue(); + String errorMsg = "0x57023 Suffix incrementation operation with operand of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } //++i @Override - public Value interpret(ASTIncPrefixExpression n) { - String expr = AssignmentExpressionsMill.prettyPrint(n.getExpression(), false); - Optional symbol = ((IBasicSymbolsScope) n.getEnclosingScope()).resolveVariable(expr); - if (symbol.isPresent()) { - Value value = load(symbol.get()); - if (value.isInt()) { - Value res = ValueFactory.createValue(value.asInt() + 1); - store(symbol.get(), res); - return (res); - } else if (value.isChar()) { - Value res = ValueFactory.createValue(value.asChar() + 1); - store(symbol.get(), res); - return (res); - } else if (value.isLong()) { - Value res = ValueFactory.createValue(value.asLong() + 1); - store(symbol.get(), res); - return (res); - - } else if (value.isFloat()) { - Value res = ValueFactory.createValue(value.asFloat() + 1); - store(symbol.get(), res); - return (res); - } else if (value.isDouble()) { - Value res = ValueFactory.createValue(value.asDouble() + 1); - store(symbol.get(), res); - return (res); - } else { - Log.error("Prefix incrementation operation is not suitable for this type."); + public MIValue interpret(ASTIncPrefixExpression n) { + ASTExpression expr = n.getExpression(); + SymTypeExpression type = TypeCheck3.typeOf(expr); + MIValue value = n.getExpression().evaluate(getRealThis()); + + if (value.isFlowControlSignal()) return value; + if (!value.isWriteable()) { + String errorMsg = "0x57095 Expected an LValue. Got " + value.printType() + " (" + value.printValue() + ")."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + WriteableMIValue variable = (WriteableMIValue)value; + + if (type.isPrimitive()) { + String primitive = type.asPrimitive().getPrimitiveName(); + if (primitive.equals(BasicSymbolsMill.BYTE)) { + MIValue res = createValue((byte)(value.asByte() + 1)); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.SHORT)) { + MIValue res = createValue((short)(value.asShort() + 1)); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.CHAR)) { + MIValue res = createValue((char)(value.asChar() + 1)); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.INT)) { + MIValue res = createValue(value.asInt() + 1); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.LONG)) { + MIValue res = createValue(value.asLong() + 1); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.FLOAT)) { + MIValue res = createValue(value.asFloat() + 1); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.DOUBLE)) { + MIValue res = createValue(value.asDouble() + 1); + variable.write(res); + return res; } } - return new NotAValue(); + String errorMsg = "0x57025 Prefix incrementation operation with operand of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } //i-- @Override - public Value interpret(ASTDecSuffixExpression n) { - String expr = AssignmentExpressionsMill.prettyPrint(n.getExpression(), false); - Optional symbol = ((IBasicSymbolsScope) n.getEnclosingScope()).resolveVariable(expr); - if (symbol.isPresent()) { - Value value = load(symbol.get()); - if (value.isInt()) { - Value res = ValueFactory.createValue(value.asInt() - 1); - store(symbol.get(), res); - return (res); - } else if (value.isChar()) { - Value res = ValueFactory.createValue(value.asChar() - 1); - store(symbol.get(), res); - return (res); - } else if (value.isLong()) { - Value res = ValueFactory.createValue(value.asLong() - 1); - store(symbol.get(), res); - return (res); - - } else if (value.isFloat()) { - Value res = ValueFactory.createValue(value.asFloat() - 1); - store(symbol.get(), res); - return (res); - } else if (value.isDouble()) { - Value res = ValueFactory.createValue(value.asDouble() - 1); - store(symbol.get(), res); - return (res); - } else { - Log.error("Suffix decremental operation is not suitable for this type."); + public MIValue interpret(ASTDecSuffixExpression n) { + ASTExpression expr = n.getExpression(); + SymTypeExpression type = TypeCheck3.typeOf(expr); + MIValue value = n.getExpression().evaluate(getRealThis()); + + if (value.isFlowControlSignal()) return value; + if (!value.isWriteable()) { + String errorMsg = "0x57096 Expected an LValue. Got " + value.printType() + " (" + value.printValue() + ")."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + WriteableMIValue variable = (WriteableMIValue)value; + if (type.isPrimitive()) { + MIValue previousValue = variable.getMIValue(); + String primitive = type.asPrimitive().getPrimitiveName(); + if (primitive.equals(BasicSymbolsMill.BYTE)) { + MIValue res = createValue((byte)(value.asByte() - 1)); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.SHORT)) { + MIValue res = createValue((short)(value.asShort() - 1)); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.CHAR)) { + MIValue res = createValue((char)(value.asChar() - 1)); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.INT)) { + MIValue res = createValue(value.asInt() - 1); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.LONG)) { + MIValue res = createValue(value.asLong() - 1); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.FLOAT)) { + MIValue res = createValue(value.asFloat() - 1); + variable.write(res); + return previousValue; + } else if (primitive.equals(BasicSymbolsMill.DOUBLE)) { + MIValue res = createValue(value.asDouble() - 1); + variable.write(res); + return previousValue; } } - return new NotAValue(); + String errorMsg = "0x57027 Suffix decrementation operation with operand of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } //--i @Override - public Value interpret(ASTDecPrefixExpression n) { - String expr = AssignmentExpressionsMill.prettyPrint(n.getExpression(), false); - Optional symbol = ((IBasicSymbolsScope) n.getEnclosingScope()).resolveVariable(expr); - if (symbol.isPresent()) { - Value value = load(symbol.get()); - if (value.isInt()) { - Value res = ValueFactory.createValue(value.asInt() - 1); - store(symbol.get(), res); - return (res); - } else if (value.isChar()) { - Value res = ValueFactory.createValue(value.asChar() - 1); - store(symbol.get(), res); - return (res); - } else if (value.isLong()) { - Value res = ValueFactory.createValue(value.asLong() - 1); - store(symbol.get(), res); - return (res); - - } else if (value.isFloat()) { - Value res = ValueFactory.createValue(value.asFloat() - 1); - store(symbol.get(), res); - return (res); - } else if (value.isDouble()) { - Value res = ValueFactory.createValue(value.asDouble() - 1); - store(symbol.get(), res); - return (res); - } else { - Log.error("Prefix decremental operation is not suitable for this type."); + public MIValue interpret(ASTDecPrefixExpression n) { + ASTExpression expr = n.getExpression(); + SymTypeExpression type = TypeCheck3.typeOf(expr); + MIValue value = n.getExpression().evaluate(getRealThis()); + + if (value.isFlowControlSignal()) return value; + if (!value.isWriteable()) { + String errorMsg = "0x57097 Expected an LValue. Got " + value.printType() + " (" + value.printValue() + ")."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + WriteableMIValue variable = (WriteableMIValue)value; + + if (type.isPrimitive()) { + String primitive = type.asPrimitive().getPrimitiveName(); + if (primitive.equals(BasicSymbolsMill.BYTE)) { + MIValue res = createValue((byte)(value.asByte() - 1)); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.SHORT)) { + MIValue res = createValue((short)(value.asShort() - 1)); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.CHAR)) { + MIValue res = createValue((char)(value.asChar() - 1)); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.INT)) { + MIValue res = createValue(value.asInt() - 1); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.LONG)) { + MIValue res = createValue(value.asLong() - 1); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.FLOAT)) { + MIValue res = createValue(value.asFloat() - 1); + variable.write(res); + return res; + } else if (primitive.equals(BasicSymbolsMill.DOUBLE)) { + MIValue res = createValue(value.asDouble() - 1); + variable.write(res); + return res; } } - return new NotAValue(); + String errorMsg = "0x57029 Prefix decrementation operation with operand of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTAssignmentExpression n) { - String leftExpression = AssignmentExpressionsMill.prettyPrint(n.getLeft(), false); - Optional leftSymbol = ((IBasicSymbolsScope) n.getEnclosingScope()).resolveVariable(leftExpression); - - if (leftSymbol.isPresent()) { - Value rightValue = n.getRight().evaluate(getRealThis()); - int operator = n.getOperator(); - - switch (operator) { - case AND_EQUALS: { //bitwise and - Value leftValue = load(leftSymbol.get()); - if (!(rightValue.isInt() || rightValue.isLong() || rightValue.isChar())) { - Log.error("&= operation is not suitable for these types."); - } else if (!(leftValue.isInt() || leftValue.isLong() || leftValue.isChar())) { - Log.error("&= operation is not suitable for these types."); - } - - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() & rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() & rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() & rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() & rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() & rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() & rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() & rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() & rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() & rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } - - case EQUALS: { - VariableSymbol symbol = leftSymbol.get(); - - if (SymTypeRelations.isString(symbol.getType()) && rightValue.isString()) { - store(leftSymbol.get(), rightValue); - } else if (SymTypeRelations.isBoolean(symbol.getType()) && rightValue.isBoolean()) { - store(leftSymbol.get(), rightValue); - } else if (SymTypeRelations.isChar(symbol.getType()) && rightValue.isChar()) { - store(leftSymbol.get(), rightValue); - } else if (SymTypeRelations.isInt(symbol.getType()) && rightValue.isInt()) { - store(leftSymbol.get(), rightValue); - } else if (SymTypeRelations.isLong(symbol.getType()) && rightValue.isLong()) { - store(leftSymbol.get(), rightValue); - } else if (SymTypeRelations.isFloat(symbol.getType()) && rightValue.isFloat()) { - store(leftSymbol.get(), rightValue); - } else if (SymTypeRelations.isDouble(symbol.getType()) && rightValue.isDouble()) { - store(leftSymbol.get(), rightValue); - } else if (rightValue.isObject()) { - store(leftSymbol.get(), rightValue); - } else { - Log.error("The interpreter only allows = operation for operands of the same type."); - } - break; - } + public MIValue interpret(ASTAssignmentExpression n) { + ASTExpression leftExpr = n.getLeft(); + SymTypeExpression leftType = TypeCheck3.typeOf(leftExpr); + MIValue leftValue = n.getLeft().evaluate(getRealThis()); + + if (!leftValue.isWriteable()) { + String errorMsg = "0x57098 Expected an LValue. Got " + leftValue.printType() + + " (" + leftValue.printValue() + ")."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + WriteableMIValue variable = (WriteableMIValue)leftValue; + + int operator = n.getOperator(); - case GTGTEQUALS: { //bitwise rightValue shift - Value leftValue = load(leftSymbol.get()); - if (!(rightValue.isInt() || rightValue.isLong() || rightValue.isChar())) { - Log.error(">>= operation is not suitable for these types."); - } else if (!(leftValue.isChar() || leftValue.isInt() || leftValue.isLong())) { - Log.error(">>= operation is not suitable for these types."); - } - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() >> rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() >> rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() >> rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() >> rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() >> rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() >> rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() >> rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() >> rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() >> rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } + MIValue rightValue = n.getRight().evaluate(getRealThis()); + if (rightValue.isFlowControlSignal()) return rightValue; + + SymTypeExpression rightType = TypeCheck3.typeOf(n.getRight()); + + // normal assignment without operation + if (operator == EQUALS) { + if (leftType.deepEquals(rightType)) { + variable.write(rightValue); + return rightValue; + } + + if (!SymTypeRelations.isCompatible(leftType, rightType)) { + String errorMsg = "0x57031 A value of type " + rightType.print() + " can not be writen to a variable of type " + leftType.print() + "."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + if (leftType.isPrimitive() && rightType.isPrimitive()) { + rightValue = InterpreterUtils.convertToPrimitiveImplicit(leftType.asPrimitive().getPrimitiveName(), rightValue); + } else { + String errorMsg = "0x57032 The implicit conversion from " + rightType.print() + " to " + leftType.print() + " is not supported."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + variable.write(rightValue); + return rightValue; + } + + if (leftValue.isFlowControlSignal()) return leftValue; + + MIValue resultValue; + SymTypeExpression resultType; + + switch (operator) { + case AND_EQUALS: { //bitwise and + resultType = TypeVisitorOperatorCalculator.binaryAnd(leftType, rightType).get(); + resultValue = InterpreterUtils.calcBitwiseLogicalOp(leftValue, rightValue, resultType, + (a, b) -> a & b, (a, b) -> a & b, (a, b) -> a & b, + "0x57042 Bitwise And Assignment"); + break; + } - case GTGTGTEQUALS: { //bitwise rightValue shift - Value leftValue = load(leftSymbol.get()); - if (!(rightValue.isInt() || rightValue.isLong() || rightValue.isChar())) { - Log.error(">>>= operation is not suitable for these types."); - } else if (!(leftValue.isInt() || leftValue.isLong() || leftValue.isChar())) { - Log.error(">>>= operation is not suitable for these types."); - } - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() >>> rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() >>> rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() >>> rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() >>> rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() >>> rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() >>> rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() >>> rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() >>> rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() >>> rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } + case GTGTEQUALS: { //bitwise rightValue shift + resultType = TypeVisitorOperatorCalculator.signedRightShift(leftType, rightType).get(); + resultValue = InterpreterUtils.calcShift(leftValue, rightValue, resultType, + (a, b) -> a >> b, (a, b) -> a >> b, + "0x57043 Bitwise Right Shift Assignment"); + break; + } - case LTLTEQUALS: { - Value leftValue = load(leftSymbol.get()); - if (!(rightValue.isInt() || rightValue.isLong() || rightValue.isChar())) { - Log.error("<<= operation is not suitable for these types."); - } else if (!(leftValue.isInt() || leftValue.isLong() || leftValue.isChar())) { - Log.error("<<= operation is not suitable for these types."); - } - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() << rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() << rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() << rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() << rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() << rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() << rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() << rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() << rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() << rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } + case GTGTGTEQUALS: { //bitwise rightValue shift + resultType = TypeVisitorOperatorCalculator.unsignedRightShift(leftType, rightType).get(); + resultValue = InterpreterUtils.calcShift(leftValue, rightValue, resultType, + (a, b) -> a >>> b, (a, b) -> a >>> b, + "0x57044 Logical Right Shift Assignment"); + break; + } - case MINUSEQUALS: { - Value leftValue = load(leftSymbol.get()); - if (rightValue.isObject() || rightValue.isString() || rightValue.isBoolean()) { - Log.error("-= operation is not suitable for these types."); - } else if (leftValue.isObject() || leftValue.isString() || leftValue.isBoolean()) { - Log.error("-= operation is not suitable for these types."); - } - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() - rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() - rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asInt() - rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asInt() - rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() - rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() - rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() - rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asLong() - rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asLong() - rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() - rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() - rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() - rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asChar() - rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asChar() - rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() - rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isFloat()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asFloat() - rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asFloat() - rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asFloat() - rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asFloat() - rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asFloat() - rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isDouble()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asDouble() - rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asDouble() - rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asDouble() - rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asDouble() - rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asDouble() - rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } + case LTLTEQUALS: { + resultType = TypeVisitorOperatorCalculator.leftShift(leftType, rightType).get(); + resultValue = InterpreterUtils.calcShift(leftValue, rightValue, resultType, + (a, b) -> a << b, (a, b) -> a << b, + "0x57045 Bitwise Left Shift Assignment"); + break; + } - case PERCENTEQUALS: { - Value leftValue = load(leftSymbol.get()); - if (rightValue.isObject() || rightValue.isString() || rightValue.isBoolean()) { - Log.error("%= operation is not suitable for these types."); - } else if (leftValue.isObject() || leftValue.isString() || leftValue.isBoolean()) { - Log.error("%= operation is not suitable for these types."); - } - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() % rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() % rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asInt() % rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asInt() % rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() % rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() % rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() % rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asLong() % rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asLong() % rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() % rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isFloat()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asFloat() % rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asFloat() % rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asFloat() % rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asFloat() % rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asFloat() % rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isDouble()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asDouble() % rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asDouble() % rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asDouble() % rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asDouble() % rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asDouble() % rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() % rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() % rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asChar() % rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asChar() % rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() % rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } + case MINUSEQUALS: { + resultType = TypeVisitorOperatorCalculator.minus(leftType, rightType).get(); + resultValue = InterpreterUtils.calcOp(leftValue, rightValue, resultType, + (a, b) -> a - b, (a, b) -> a - b, (a, b) -> a - b, (a, b) -> a - b, + "0x57046 Minus Assignment"); + break; + } - case PIPEEQUALS: { - Value leftValue = load(leftSymbol.get()); - if (!(rightValue.isInt() || rightValue.isLong() || rightValue.isChar())) { - Log.error("|= operation is not suitable for these types."); - } else if (!(leftValue.isChar() || leftValue.isInt() || leftValue.isLong())) { - Log.error("|= operation is not suitable for these types."); - } - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() | rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() | rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() | rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() | rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() | rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() | rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() | rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() | rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() | rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } + case PERCENTEQUALS: { + resultType = TypeVisitorOperatorCalculator.modulo(leftType, rightType).get(); + resultValue = InterpreterUtils.calcOp(leftValue, rightValue, resultType, + (a, b) -> a % b, (a, b) -> a % b, (a, b) -> a % b, (a, b) -> a % b, + "0x57047 Modulo Assignment"); + break; + } - case PLUSEQUALS: { - Value leftValue = load(leftSymbol.get()); + case PIPEEQUALS: { + resultType = TypeVisitorOperatorCalculator.binaryOr(leftType, rightType).get(); + resultValue = InterpreterUtils.calcBitwiseLogicalOp(leftValue, rightValue, resultType, + (a, b) -> a | b, (a, b) -> a | b, (a, b) -> a | b, + "0x57048 Bitwise Or Assignment"); + break; + } - if (leftValue.isString()) { - if (rightValue.isString()) { - Value res = ValueFactory.createValue(leftValue.asString() + rightValue.asString()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asString() + rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asString() + rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asString() + rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asString() + rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asString() + rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isBoolean()) { - Value res = ValueFactory.createValue(leftValue.asString() + rightValue.asBoolean()); - store(leftSymbol.get(), res); - return (res); - } - } else if (leftValue.isBoolean() || leftValue.isObject() || rightValue.isObject()) { - Log.error("+= operation is not suitable for these types."); - } else if (leftValue.isChar()) { - if (rightValue.isString()) { - Value res = ValueFactory.createValue(leftValue.asChar() + rightValue.asString()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() + rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() + rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() + rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asChar() + rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asChar() + rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isBoolean()) { - Log.error("+= operation is not suitable for these types."); - } - } else if (leftValue.isInt()) { - if (rightValue.isString()) { - Value res = ValueFactory.createValue(leftValue.asInt() + rightValue.asString()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() + rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() + rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() + rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asInt() + rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asInt() + rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isBoolean()) { - Log.error("+= operation is not suitable for these types."); - } - } else if (leftValue.isLong()) { - if (rightValue.isString()) { - Value res = ValueFactory.createValue(leftValue.asLong() + rightValue.asString()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() + rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() + rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() + rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asLong() + rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asLong() + rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isBoolean()) { - Log.error("+= operation is not suitable for these types."); - } - } else if (leftValue.isFloat()) { - if (rightValue.isString()) { - Value res = ValueFactory.createValue(leftValue.asFloat() + rightValue.asString()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asFloat() + rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asFloat() + rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asFloat() + rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asFloat() + rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asFloat() + rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isBoolean()) { - Log.error("+= operation is not suitable for these types."); - } - } else if (leftValue.isDouble()) { - if (rightValue.isString()) { - Value res = ValueFactory.createValue(leftValue.asDouble() + rightValue.asString()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asDouble() + rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asDouble() + rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asDouble() + rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asDouble() + rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asDouble() + rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } else if (rightValue.isBoolean()) { - Log.error("+= operation is not suitable for these types."); - } - } - break; - } + case PLUSEQUALS: { + resultType = TypeVisitorOperatorCalculator.plus(leftType, rightType).get(); + resultValue = InterpreterUtils.calcOp(leftValue, rightValue, resultType, + Integer::sum, Long::sum, Float::sum, Double::sum, + "0x57049 Plus Assignment"); + break; + } - case ROOFEQUALS: { //XOR - Value leftValue = load(leftSymbol.get()); - if (!(rightValue.isInt() || rightValue.isLong() || rightValue.isChar())) { - Log.error("^= operation is not suitable for these types."); - } else if (!(leftValue.isChar() || leftValue.isInt() || leftValue.isLong())) { - Log.error("^= operation is not suitable for these types."); - } - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() ^ rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() ^ rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() ^ rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() ^ rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() ^ rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() ^ rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() ^ rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() ^ rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() ^ rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } + case ROOFEQUALS: { //XOR + resultType = TypeVisitorOperatorCalculator.binaryXor(leftType, rightType).get(); + resultValue = InterpreterUtils.calcBitwiseLogicalOp(leftValue, rightValue, resultType, + (a, b) -> a ^ b, (a, b) -> a ^ b, (a, b) -> a ^ b, + "0x57050 Bitwise Xor Assignment"); + break; + } - case SLASHEQUALS: { - Value leftValue = load(leftSymbol.get()); - if (rightValue.isObject() || rightValue.isString() || rightValue.isBoolean()) { - Log.error("/= operation is not suitable for these types."); - } else if (leftValue.isObject() || leftValue.isString() || leftValue.isBoolean()) { - Log.error("/= operation is not suitable for these types."); - } else if (leftValue.isLong()) { - if (rightValue.asDouble() == 0) { - Log.error("Division by 0 is not supported."); - } - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() / rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() / rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asLong() / rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asLong() / rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() / rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } else if (leftValue.isInt()) { - if (rightValue.asDouble() == 0) { - Log.error("Division by 0 is not supported."); - } - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() / rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() / rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asInt() / rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asInt() / rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() / rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } else if (leftValue.isChar()) { - if (rightValue.asDouble() == 0) { - Log.error("Division by 0 is not supported."); - } - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() / rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() / rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asChar() / rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asChar() / rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() / rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } else if (leftValue.isFloat()) { - if (rightValue.asDouble() == 0) { - Log.error("Division by 0 is not supported."); - } - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asFloat() / rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asFloat() / rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asFloat() / rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asFloat() / rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asFloat() / rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } else if (leftValue.isDouble()) { - if (rightValue.asDouble() == 0) { - Log.error("Division by 0 is not supported."); - } - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asDouble() / rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asDouble() / rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asDouble() / rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asDouble() / rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asDouble() / rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } + case SLASHEQUALS: { + resultType = TypeVisitorOperatorCalculator.divide(leftType, rightType).get(); + if (resultType.isPrimitive()) { + String resultPrimitive = resultType.asPrimitive().getPrimitiveName(); + + if (rightValue.asDouble() == 0.0) { + String errorMsg = "0x57033 Division by zero is undefined"; + Log.error(errorMsg, n.getRight().get_SourcePositionStart(), n.getRight().get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + resultValue = InterpreterUtils.calcOpPrimitive(leftValue, rightValue, resultPrimitive, + (a, b) -> a / b, (a, b) -> a / b, (a, b) -> a / b, (a, b) -> a / b, + "0x57051 Division Assignment"); break; } + String errorMsg = "0x57034 Division Assignment operation with result of type " + resultType + " is not supported."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } - case (STAREQUALS): { - Value leftValue = load(leftSymbol.get()); - if (rightValue.isObject() || rightValue.isString() || rightValue.isBoolean()) { - Log.error("*= operation is not suitable for these types."); - } else if (leftValue.isObject() || leftValue.isString() || leftValue.isBoolean()) { - Log.error("*= operation is not suitable for these types."); - } - if (leftValue.isLong()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asLong() * rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asLong() * rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asLong() * rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asLong() * rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asLong() * rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isInt()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asInt() * rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asInt() * rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asInt() * rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asInt() * rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asInt() * rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isChar()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asChar() * rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asChar() * rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asChar() * rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asChar() * rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asChar() * rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isFloat()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asFloat() * rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asFloat() * rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asFloat() * rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asFloat() * rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asFloat() * rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - if (leftValue.isDouble()) { - if (rightValue.isInt()) { - Value res = ValueFactory.createValue(leftValue.asDouble() * rightValue.asInt()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isLong()) { - Value res = ValueFactory.createValue(leftValue.asDouble() * rightValue.asLong()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isFloat()) { - Value res = ValueFactory.createValue(leftValue.asDouble() * rightValue.asFloat()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isDouble()) { - Value res = ValueFactory.createValue(leftValue.asDouble() * rightValue.asDouble()); - store(leftSymbol.get(), res); - return (res); - } - if (rightValue.isChar()) { - Value res = ValueFactory.createValue(leftValue.asDouble() * rightValue.asChar()); - store(leftSymbol.get(), res); - return (res); - } - } - break; - } - default: - Log.error("Operator is not defined."); + case STAREQUALS: { + resultType = TypeVisitorOperatorCalculator.multiply(leftType, rightType).get(); + resultValue = InterpreterUtils.calcOp(leftValue, rightValue, resultType, + (a, b) -> a * b, (a, b) -> a * b, (a, b) -> a * b, (a, b) -> a * b, + "0x57052 Multiplication Assignment"); + break; } + default: + String errorMsg = "0x57035 Operator is not defined"; + Log.error(errorMsg, n.getLeft().get_SourcePositionEnd(), n.getRight().get_SourcePositionStart()); + return new ErrorMIValue(errorMsg); + } + + if (resultValue.isFlowControlSignal()) return resultValue; + + if (leftType.deepEquals(resultType)) { + // nothing left to do + } else if (leftType.isPrimitive() && resultType.isPrimitive()) { + resultValue = InterpreterUtils.convertToPrimitiveExplicit(resultType.asPrimitive().getPrimitiveName(), + leftType.asPrimitive().getPrimitiveName(), resultValue); + } else { + String errorMsg = "0x57036 Cast from " + resultType.print() + " to " + leftType.print() + " is not supported."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } - return new NotAValue(); + + if (resultValue.isFlowControlSignal()) return resultValue; + + variable.write(resultValue); + return resultValue; } } diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/commonexpressions/_visitor/CommonExpressionsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/expressions/commonexpressions/_visitor/CommonExpressionsInterpreter.java index f80ebc505f..27dfa4f0f0 100644 --- a/monticore-grammar/src/main/java/de/monticore/expressions/commonexpressions/_visitor/CommonExpressionsInterpreter.java +++ b/monticore-grammar/src/main/java/de/monticore/expressions/commonexpressions/_visitor/CommonExpressionsInterpreter.java @@ -1,19 +1,31 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.expressions.commonexpressions._visitor; -import de.monticore.expressions.commonexpressions.CommonExpressionsMill; import de.monticore.expressions.commonexpressions._ast.*; +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; import de.monticore.expressions.expressionsbasis._ast.ASTLiteralExpression; +import de.monticore.interpreter.InterpreterUtils; +import de.monticore.interpreter.MIValue; import de.monticore.interpreter.ModelInterpreter; -import de.monticore.interpreter.Value; -import de.monticore.interpreter.values.NotAValue; -import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; -import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.JavaNonStaticMethodMIValue; +import de.monticore.interpreter.values.JavaStaticMethodMIValue; +import de.monticore.interpreter.values.ObjectMIValue; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symboltable.ISymbol; +import de.monticore.symboltable.modifiers.StaticAccessModifier; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypePrimitive; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.TypeCheck3; import de.se_rwth.commons.logging.Log; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; -import static de.monticore.interpreter.ValueFactory.createValue; +import static de.monticore.interpreter.MIValueFactory.createValue; public class CommonExpressionsInterpreter extends CommonExpressionsInterpreterTOP { @@ -26,229 +38,319 @@ public CommonExpressionsInterpreter(ModelInterpreter realThis) { } @Override - public Value interpret(ASTPlusExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - - if (left.isString() || right.isString()) { - return createValue(left.asString() + right.asString()); - } else if (left.isBoolean() || right.isBoolean() || left.isObject() || right.isObject()) { - Log.error("Plus operation is not applicable for these types."); - } else if (left.isDouble() || right.isDouble()) { - return createValue(left.asDouble() + right.asDouble()); - } else if (left.isFloat() || right.isFloat()) { - return createValue(left.asFloat() + right.asFloat()); - } else if (left.isLong() || right.isLong()) { - return createValue(left.asLong() + right.asLong()); - } else if (left.isInt() || right.isInt() || left.isChar() || right.isChar()) { - return createValue(left.asInt() + right.asInt()); - } - return new NotAValue(); + public MIValue interpret(ASTPlusExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression type = TypeCheck3.typeOf(node); + return InterpreterUtils.calcOp(left, right, type, Integer::sum, Long::sum, Float::sum, Double::sum, "0x57037 Plus"); } @Override - public Value interpret(ASTMinusExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - return compare(left, right); + public MIValue interpret(ASTMinusExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression type = TypeCheck3.typeOf(node); + return InterpreterUtils.calcOp(left, right, type, (a, b) -> a - b, (a, b) -> a - b, + (a, b) -> a - b, (a, b) -> a - b, "0x57038 Minus"); } @Override - public Value interpret(ASTMultExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - - if (left.isString() || right.isString() || left.isBoolean() || - right.isBoolean() || left.isObject() || right.isObject()) { - Log.error("Minus operation is not applicable for these types."); - } else if (left.isDouble() || right.isDouble()) { - return createValue(left.asDouble() * right.asDouble()); - } else if (left.isFloat() || right.isFloat()) { - return createValue(left.asFloat() * right.asFloat()); - } else if (left.isLong() || right.isLong()) { - return createValue(left.asLong() * right.asLong()); - } else if (left.isInt() || right.isInt() || left.isChar() || right.isChar()) { - return createValue(left.asInt() * right.asInt()); - } - return new NotAValue(); + public MIValue interpret(ASTMultExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression type = TypeCheck3.typeOf(node); + return InterpreterUtils.calcOp(left, right, type, (a, b) -> a * b, (a, b) -> a * b, + (a, b) -> a * b, (a, b) -> a * b, "0x57039 Multiplication"); } @Override - public Value interpret(ASTDivideExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - - if (left.isString() || right.isString() || left.isBoolean() || - right.isBoolean() || left.isObject() || right.isObject()) { - Log.error("Minus operation is not applicable for these types."); - return new NotAValue(); - } - - if (right.asDouble() == 0) { - Log.error("Division by Zero is not defined."); - return new NotAValue(); + public MIValue interpret(ASTDivideExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression type = TypeCheck3.typeOf(node); + if (type.isPrimitive()) { + String resultPrimitive = type.asPrimitive().getPrimitiveName(); + + if (right.asDouble() == 0.0) { + String errorMsg = "0x57004 Division by zero is undefined"; + Log.error(errorMsg, node.getRight().get_SourcePositionStart(), node.getRight().get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + return InterpreterUtils.calcOpPrimitive(left, right, resultPrimitive, + (a, b) -> a / b, (a, b) -> a / b, (a, b) -> a / b, (a, b) -> a / b, + "0x57040 Division"); } - if (left.isDouble() || right.isDouble()) { - return createValue(left.asDouble() / right.asDouble()); - } else if (left.isFloat() || right.isFloat()) { - return createValue(left.asFloat() / right.asFloat()); - } else if (left.isLong() || right.isLong()) { - return createValue(left.asLong() / right.asLong()); - } else if (left.isInt() || right.isInt() || left.isChar() || right.isChar()) { - return createValue(left.asInt() / right.asInt()); - } - - return new NotAValue(); + String errorMsg = "0x57005 Division operation with result of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTModuloExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - - if (left.isString() || right.isString() || left.isBoolean() || - right.isBoolean() || left.isObject() || right.isObject()) { - Log.error("Minus operation is not applicable for these types."); - } else if (left.isDouble() || right.isDouble()) { - return createValue(left.asDouble() % right.asDouble()); - } else if (left.isFloat() || right.isFloat()) { - return createValue(left.asFloat() % right.asFloat()); - } else if (left.isLong() || right.isLong()) { - return createValue(left.asLong() % right.asLong()); - } else if (left.isInt() || right.isInt() || left.isChar() || right.isChar()) { - return createValue(left.asInt() % right.asInt()); - } - return new NotAValue(); + public MIValue interpret(ASTModuloExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression type = TypeCheck3.typeOf(node); + return InterpreterUtils.calcOp(left, right, type, (a, b) -> a % b, (a, b) -> a % b, + (a, b) -> a % b, (a, b) -> a % b, "0x57041 Modulo"); } @Override - public Value interpret(ASTMinusPrefixExpression node) { - Value expr = node.getExpression().evaluate(getRealThis()); - - if (expr.isObject() || expr.isBoolean() || expr.isString()) { - Log.error("Minus Prefix operation is not applicable for these types."); - } else if (expr.isInt()) { - return createValue(-expr.asInt()); - } else if (expr.isLong()) { - return createValue(-expr.asLong()); - } else if (expr.isDouble()) { - return createValue(-expr.asDouble()); - } else if (expr.isFloat()) { - return createValue(-expr.asFloat()); - } else if (expr.isChar()) { - return createValue(-expr.asChar()); - } - return new NotAValue(); - } + public MIValue interpret(ASTMinusPrefixExpression node) { + MIValue value = node.getExpression().evaluate(getRealThis()); + if (value.isFlowControlSignal()) + return value; + + SymTypeExpression type = TypeCheck3.typeOf(node); + if (type.isPrimitive()) { + String primitive = type.asPrimitive().getPrimitiveName(); + + if (primitive.equals(BasicSymbolsMill.BYTE)) { + return createValue(-value.asByte()); + } + else if (primitive.equals(BasicSymbolsMill.SHORT)) { + return createValue(-value.asShort()); + } + else if (primitive.equals(BasicSymbolsMill.CHAR)) { + return createValue(-value.asChar()); + } + else if (primitive.equals(BasicSymbolsMill.INT)) { + return createValue(-value.asInt()); + } + else if (primitive.equals(BasicSymbolsMill.LONG)) { + return createValue(-value.asLong()); + } + else if (primitive.equals(BasicSymbolsMill.FLOAT)) { + return createValue(-value.asFloat()); + } + else if (primitive.equals(BasicSymbolsMill.DOUBLE)) { + return createValue(-value.asDouble()); + } + } - @Override - public Value interpret(ASTPlusPrefixExpression node) { - Value expr = node.getExpression().evaluate(getRealThis()); - - if (expr.isObject() || expr.isBoolean() || expr.isString()) { - Log.error("Plus Prefix operation is not applicable for these types."); - } else if (expr.isInt()) { - return createValue(expr.asInt()); - } else if (expr.isLong()) { - return createValue(+expr.asLong()); - } else if (expr.isDouble()) { - return createValue(+expr.asDouble()); - } else if (expr.isFloat()) { - return createValue(+expr.asFloat()); - } else if (expr.isChar()) { - return createValue(+expr.asChar()); - } - return new NotAValue(); + String errorMsg = "0x57006 Minus Prefix operation with result of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTEqualsExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - - if (left.isBoolean() && right.isBoolean()) { - return createValue(left.asBoolean() == right.asBoolean()); + public MIValue interpret(ASTPlusPrefixExpression node) { + MIValue value = node.getExpression().evaluate(getRealThis()); + if (value.isFlowControlSignal()) + return value; + + SymTypeExpression type = TypeCheck3.typeOf(node); + if (type.isPrimitive() && (type.asPrimitive().isNumericType() || type.asPrimitive().isIntegralType())) { + return value; } - Value result = compare(left, right); - return result instanceof NotAValue ? result : createValue(result.asDouble() == 0); + + String errorMsg = "0x57007 Minus Prefix operation with result of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTNotEqualsExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - - if (left.isBoolean() && right.isBoolean()) { - return createValue(left.asBoolean() != right.asBoolean()); + public MIValue interpret(ASTEqualsExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression leftType = TypeCheck3.typeOf(node.getLeft()); + SymTypeExpression rightType = TypeCheck3.typeOf(node.getRight()); + if (leftType.isPrimitive() && rightType.isPrimitive()) { + return isEqual(leftType.asPrimitive(), left, rightType.asPrimitive(), right); } - Value result = compare(left, right); - return result instanceof NotAValue ? result : createValue(compare(left, right).asDouble() != 0); + + String errorMsg = "0x57008 Equality operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTGreaterThanExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - Value result = compare(left, right); - return result instanceof NotAValue ? result : createValue(compare(left, right).asDouble() > 0); + public MIValue interpret(ASTNotEqualsExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression leftType = TypeCheck3.typeOf(node.getLeft()); + SymTypeExpression rightType = TypeCheck3.typeOf(node.getRight()); + if (leftType.isPrimitive() && rightType.isPrimitive()) { + MIValue result = isEqual(leftType.asPrimitive(), left, rightType.asPrimitive(), right); + if (result.isFlowControlSignal()) + return result; + + return createValue(!result.asBoolean()); + } + + String errorMsg = "0x57009 Inequality operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTLessThanExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - Value result = compare(left, right); - return result instanceof NotAValue ? result : createValue(compare(left, right).asDouble() < 0); + public MIValue interpret(ASTGreaterThanExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression leftType = TypeCheck3.typeOf(node.getLeft()); + SymTypeExpression rightType = TypeCheck3.typeOf(node.getRight()); + if (leftType.isPrimitive() && rightType.isPrimitive()) { + MIValue result = subtract(leftType.asPrimitive(), left, rightType.asPrimitive(), right); + if (result.isFlowControlSignal()) + return result; + + return createValue(result.asDouble() > 0.0); + } + + String errorMsg = "0x57010 Greater than operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTGreaterEqualExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - Value result = compare(left, right); - return result instanceof NotAValue ? result : createValue(compare(left, right).asDouble() >= 0); + public MIValue interpret(ASTLessThanExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression leftType = TypeCheck3.typeOf(node.getLeft()); + SymTypeExpression rightType = TypeCheck3.typeOf(node.getRight()); + if (leftType.isPrimitive() && rightType.isPrimitive()) { + MIValue result = subtract(leftType.asPrimitive(), left, rightType.asPrimitive(), right); + if (result.isFlowControlSignal()) + return result; + + return createValue(result.asDouble() < 0.0); + } + + String errorMsg = "0x57011 Less than operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTLessEqualExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); - Value result = compare(left, right); - return result instanceof NotAValue ? result : createValue(compare(left, right).asDouble() <= 0); + public MIValue interpret(ASTGreaterEqualExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression leftType = TypeCheck3.typeOf(node.getLeft()); + SymTypeExpression rightType = TypeCheck3.typeOf(node.getRight()); + if (leftType.isPrimitive() && rightType.isPrimitive()) { + MIValue result = subtract(leftType.asPrimitive(), left, rightType.asPrimitive(), right); + if (result.isFlowControlSignal()) + return result; + + return createValue(result.asDouble() >= 0.0); + } + + String errorMsg = "0x57012Greater equal operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } - public Value compare(Value left, Value right) { - if (left.isString() || right.isString() || left.isBoolean() || - right.isBoolean() || left.isObject() || right.isObject()) { - Log.error("Operation is not applicable for these types."); - } else if (left.isDouble() || right.isDouble()) { - return createValue(left.asDouble() - right.asDouble()); - } else if (left.isFloat() || right.isFloat()) { - return createValue(left.asFloat() - right.asFloat()); - } else if (left.isLong() || right.isLong()) { - return createValue(left.asLong() - right.asLong()); - } else if (left.isInt() || right.isInt() || left.isChar() || right.isChar()) { - return createValue(left.asInt() - right.asInt()); + @Override + public MIValue interpret(ASTLessEqualExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression leftType = TypeCheck3.typeOf(node.getLeft()); + SymTypeExpression rightType = TypeCheck3.typeOf(node.getRight()); + if (leftType.isPrimitive() && rightType.isPrimitive()) { + MIValue result = subtract(leftType.asPrimitive(), left, rightType.asPrimitive(), right); + if (result.isFlowControlSignal()) + return result; + + return createValue(result.asDouble() <= 0.0); } - return new NotAValue(); + + String errorMsg = "0x57013 Less equal operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } //~ -> behaves as a bitwise complement @Override - public Value interpret(ASTBooleanNotExpression node) { - Value res = node.getExpression().evaluate(getRealThis()); - - if (res.isFloat() || res.isObject() || res.isString() || res.isDouble() || res.isBoolean()) { - Log.error("Logical Not operation is not applicable for these types."); - } else if (res.isChar()) { - return createValue(~res.asChar()); - } else if (res.isInt()) { - return createValue(~res.asInt()); - } else if (res.isLong()) { - return createValue(~res.asLong()); - } - return new NotAValue(); + public MIValue interpret(ASTBooleanNotExpression node) { + MIValue value = node.getExpression().evaluate(getRealThis()); + if (value.isFlowControlSignal()) + return value; + + SymTypeExpression type = TypeCheck3.typeOf(node.getExpression()); + if (type.isPrimitive() && type.asPrimitive().isIntegralType()) { + String primitive = type.asPrimitive().getPrimitiveName(); + if (primitive.equals(BasicSymbolsMill.BYTE)) { + return createValue(~value.asByte()); + } + else if (primitive.equals(BasicSymbolsMill.SHORT)) { + return createValue(~value.asShort()); + } + else if (primitive.equals(BasicSymbolsMill.CHAR)) { + return createValue(~value.asChar()); + } + else if (primitive.equals(BasicSymbolsMill.INT)) { + return createValue(~value.asInt()); + } + else if (primitive.equals(BasicSymbolsMill.LONG)) { + return createValue(~value.asLong()); + } + } + + String errorMsg = "0x57014 Bitwise Not operation with operand of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } /*=================================================================*/ @@ -256,66 +358,273 @@ public Value interpret(ASTBooleanNotExpression node) { /*=================================================================*/ @Override - public Value interpret(ASTLogicalNotExpression node) { - Value res = node.getExpression().evaluate(getRealThis()); + public MIValue interpret(ASTLogicalNotExpression node) { + MIValue value = node.getExpression().evaluate(getRealThis()); + if (value.isFlowControlSignal()) + return value; - if (res.isBoolean()) { - return createValue(!res.asBoolean()); + SymTypeExpression type = TypeCheck3.typeOf(node.getExpression()); + + if (value.isBoolean()) { + return createValue(!value.asBoolean()); } - Log.error("Logical Not operation is not applicable for these types."); - return new NotAValue(); + + String errorMsg = "0x57015 Logical Not operation with operand of type '" + type.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTBooleanAndOpExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); + public MIValue interpret(ASTBooleanAndOpExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression leftType = TypeCheck3.typeOf(node.getLeft()); + SymTypeExpression rightType = TypeCheck3.typeOf(node.getRight()); if (left.isBoolean() && right.isBoolean()) { return createValue(left.asBoolean() && right.asBoolean()); } - Log.error("Logical And operation is not applicable."); - return new NotAValue(); + + String errorMsg = "0x57016 Logical And operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTBooleanOrOpExpression node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); + public MIValue interpret(ASTBooleanOrOpExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + if (left.isFlowControlSignal()) + return left; + if (right.isFlowControlSignal()) + return right; + + SymTypeExpression leftType = TypeCheck3.typeOf(node.getLeft()); + SymTypeExpression rightType = TypeCheck3.typeOf(node.getRight()); if (left.isBoolean() && right.isBoolean()) { return createValue(left.asBoolean() || right.asBoolean()); } - Log.error("Logical Or operation is not applicable."); - return new NotAValue(); + + String errorMsg = "0x57017 Logical Or operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); } @Override - public Value interpret(ASTBracketExpression node) { + public MIValue interpret(ASTBracketExpression node) { return node.getExpression().evaluate(getRealThis()); } @Override - public Value interpret(ASTConditionalExpression node) { - Value condition = node.getCondition().evaluate(getRealThis()); - if (!condition.isBoolean()) { - Log.error("Condition of Ternary Operator has to be a Boolean Type"); - return new NotAValue(); - } + public MIValue interpret(ASTConditionalExpression node) { + MIValue condition = node.getCondition().evaluate(getRealThis()); + if (condition.isFlowControlSignal()) + return condition; + return condition.asBoolean() ? node.getTrueExpression().evaluate(getRealThis()) : node.getFalseExpression().evaluate(getRealThis()); } @Override - public Value interpret(ASTFieldAccessExpression node) { - String expression = CommonExpressionsMill.prettyPrint(node, false); - Optional symbol = ((IBasicSymbolsScope) node.getEnclosingScope()).resolveVariable(expression); - return symbol.map(this::load).orElse(new NotAValue()); + public MIValue interpret(ASTFieldAccessExpression node) { + SymTypeExpression type = TypeCheck3.typeOf(node); + Optional symbolOptional = type.getSourceInfo().getSourceSymbol(); + // TODO Definition of Classes with Attributes/Methods in Model + if (symbolOptional.isEmpty()) { + String errorMsg = "0x57018 Field Access operation expected a symbol as source."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + else { + // Java Method/Attribute + ISymbol symbol = symbolOptional.get(); + if (symbol.getAccessModifier().getDimensionToModifierMap() + .getOrDefault(StaticAccessModifier.DIMENSION, + StaticAccessModifier.NON_STATIC) == StaticAccessModifier.STATIC) { + // static + + // get Java-Class from symbol + String fieldName = symbol.getName(); + String fullName = symbol.getFullName(); + String className = fullName.substring(0, (fullName.length() + - fieldName.length() - 1)); + Class classType; + try { + classType = Class.forName(className); + } + catch (ClassNotFoundException e) { + String errorMsg = "0x57018 Failed to load class '" + className + "'."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + if (type.isFunctionType()) { + // static method + return new JavaStaticMethodMIValue(classType, fieldName); + } + else { + // static attribute + return InterpreterUtils.getStaticObjectAttribute(classType, fieldName); + } + + } + else { + // non-static + MIValue leftValue = node.getExpression().evaluate(getRealThis()); + if (!leftValue.isObject()) { + String errorMsg = "0x57019 The Field Access operation expected an object as left side."; + Log.error(errorMsg, node.getExpression().get_SourcePositionStart(), node.getExpression().get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + // If class-declarations are supported this needs to be expanded + if (type.isFunctionType()) { + // non-static method + FunctionSymbol funcSymbol = (FunctionSymbol) symbol; + String name = funcSymbol.getName(); + return new JavaNonStaticMethodMIValue(leftValue.asObject(), name); + } + else { + // non-static attribute + return InterpreterUtils.getNonStaticObjectAttribute((ObjectMIValue) leftValue, node.getName()); + } + } + } } @Override - public Value interpret(ASTLiteralExpression node) { + public MIValue interpret(ASTLiteralExpression node) { return node.getLiteral().evaluate(getRealThis()); } + + @Override + public MIValue interpret(ASTCallExpression node) { + // evaluate expression that gives lambda/function + // get original parent scope of lambda/function declaration + // create Scope with parent and arguments + // evaluate arguments in current scope & put into new scope + MIValue value = node.getExpression().evaluate(getRealThis()); + if (!value.isFunction()) { + String errorMsg = "0x57021 Call expression expected a function but got " + TypeCheck3.typeOf(node.getExpression()).print() + "."; + Log.error(errorMsg, node.getExpression().get_SourcePositionStart(), node.getExpression().get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + List args = new ArrayList<>(); + for (ASTExpression argument : node.getArguments().getExpressionList()) { + args.add(argument.evaluate(getRealThis())); + } + + // cast needed in case of subtyping + SymTypeExpression returnType = TypeCheck3.typeOf(node); + MIValue returnValue = value.asFunction().execute(getRealThis(), args); + return InterpreterUtils.convertImplicit(returnType, returnValue); + } + + // helper + + protected SymTypePrimitive getCompatibleType(SymTypePrimitive type1, SymTypePrimitive type2) { + return SymTypeRelations.isCompatible(type1, type2) + ? type1 + : ( + SymTypeRelations.isCompatible(type2, type1) + ? type2 + : null + ); + } + + /** + * Checks whether the left and right value are equal. + */ + protected MIValue isEqual(SymTypePrimitive leftType, MIValue left, SymTypePrimitive rightType, MIValue right) { + SymTypePrimitive compatibleType = getCompatibleType(leftType, rightType); + if (compatibleType == null) { + String errorMsg = "0x57000 Equality operation with operands ot type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + String primitive = compatibleType.getPrimitiveName(); + if (primitive.equals(BasicSymbolsMill.BOOLEAN)) { + return createValue(left.asBoolean() == right.asBoolean()); + } + else if (primitive.equals(BasicSymbolsMill.BYTE)) { + return createValue(left.asByte() == right.asByte()); + } + else if (primitive.equals(BasicSymbolsMill.SHORT)) { + return createValue(left.asShort() == right.asShort()); + } + else if (primitive.equals(BasicSymbolsMill.CHAR)) { + return createValue(left.asChar() == right.asChar()); + } + else if (primitive.equals(BasicSymbolsMill.INT)) { + return createValue(left.asInt() == right.asInt()); + } + else if (primitive.equals(BasicSymbolsMill.LONG)) { + return createValue(left.asLong() == right.asLong()); + } + else if (primitive.equals(BasicSymbolsMill.FLOAT)) { + return createValue(left.asFloat() == right.asFloat()); + } + else if (primitive.equals(BasicSymbolsMill.DOUBLE)) { + return createValue(left.asDouble() == right.asDouble()); + } + + String errorMsg = "0x57001 Equality operator with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not implemented."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + /** + * Subtracts the right value from the left value while minding the types + */ + protected MIValue subtract(SymTypePrimitive leftType, MIValue left, SymTypePrimitive rightType, MIValue right) { + SymTypePrimitive compatibleType = getCompatibleType(leftType, rightType); + if (compatibleType == null) { + String errorMsg = "0x57002 Greater or Lesser operation with operands ot type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + String primitive = compatibleType.getPrimitiveName(); + if (primitive.equals(BasicSymbolsMill.BYTE)) { + return createValue(left.asByte() - right.asByte()); + } + else if (primitive.equals(BasicSymbolsMill.SHORT)) { + return createValue(left.asShort() - right.asShort()); + } + else if (primitive.equals(BasicSymbolsMill.CHAR)) { + return createValue(left.asChar() - right.asChar()); + } + else if (primitive.equals(BasicSymbolsMill.INT)) { + return createValue(left.asInt() - right.asInt()); + } + else if (primitive.equals(BasicSymbolsMill.LONG)) { + return createValue(left.asLong() - right.asLong()); + } + else if (primitive.equals(BasicSymbolsMill.FLOAT)) { + return createValue(left.asFloat() - right.asFloat()); + } + else if (primitive.equals(BasicSymbolsMill.DOUBLE)) { + return createValue(left.asDouble() - right.asDouble()); + } + + String errorMsg = "0x57003 Greater or Lesser operation with operands of type '" + leftType.print() + + "' and '" + rightType.print() + "' is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + } \ No newline at end of file diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/_visitor/ExpressionsBasisInterpreter.java b/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/_visitor/ExpressionsBasisInterpreter.java index 543b0ac8af..f941bb489e 100644 --- a/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/_visitor/ExpressionsBasisInterpreter.java +++ b/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/_visitor/ExpressionsBasisInterpreter.java @@ -4,10 +4,14 @@ import de.monticore.expressions.expressionsbasis._ast.ASTLiteralExpression; import de.monticore.expressions.expressionsbasis._ast.ASTNameExpression; import de.monticore.interpreter.ModelInterpreter; -import de.monticore.interpreter.Value; -import de.monticore.interpreter.values.NotAValue; -import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.VariableMIValue; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.logging.Log; import java.util.Optional; @@ -22,16 +26,29 @@ public ExpressionsBasisInterpreter(ModelInterpreter realThis) { } @Override - public Value interpret(ASTNameExpression n) { - Optional symbol = ((IBasicSymbolsScope) n.getEnclosingScope()).resolveVariable(n.getName()); - if (symbol.isPresent()) { - return load(symbol.get()); + public MIValue interpret(ASTNameExpression n) { + SymTypeExpression type = TypeCheck3.typeOf(n); + if (type.isFunctionType() && type.asFunctionType().hasSymbol()) { + Optional symbol = type.getSourceInfo().getSourceSymbol().map(s -> (FunctionSymbol)s); + if (symbol.isEmpty()) { + String errorMsg = "0x57053 Cannot resolve function '" + n.getName() + "'."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + return loadFunction(symbol.get()); } - return new NotAValue(); + + Optional symbol = type.getSourceInfo().getSourceSymbol().map(s -> (VariableSymbol)s); + if (symbol.isEmpty()) { + String errorMsg = "0x57054 Cannot resolve variable '" + n.getName() + "'."; + Log.error(errorMsg, n.get_SourcePositionStart(), n.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + return new VariableMIValue(getCurrentScope(), symbol.get()); } @Override - public Value interpret(ASTLiteralExpression n) { + public MIValue interpret(ASTLiteralExpression n) { return n.getLiteral().evaluate(getRealThis()); } diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_visitor/LambdaExpressionsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_visitor/LambdaExpressionsInterpreter.java new file mode 100644 index 0000000000..471eca2500 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_visitor/LambdaExpressionsInterpreter.java @@ -0,0 +1,38 @@ +package de.monticore.expressions.lambdaexpressions._visitor; + +import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaExpression; +import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaExpressionBody; +import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaParameter; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.values.ModelFunctionMIValue; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; + +import java.util.ArrayList; +import java.util.List; + +public class LambdaExpressionsInterpreter extends LambdaExpressionsInterpreterTOP { + + public LambdaExpressionsInterpreter() { + super(); + } + + public LambdaExpressionsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + @Override + public MIValue interpret(ASTLambdaExpressionBody node) { + return node.getExpression().evaluate(getRealThis()); + } + + @Override + public MIValue interpret(ASTLambdaExpression node) { + List parameterSymbols = new ArrayList<>(); + for (ASTLambdaParameter parameter : node.getLambdaParameters().getLambdaParameterList()) { + parameterSymbols.add(parameter.getSymbol()); + } + return new ModelFunctionMIValue(getRealThis().getCurrentScope(), parameterSymbols, node.getLambdaBody()); + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/uglyexpressions/_visitor/UglyExpressionsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/expressions/uglyexpressions/_visitor/UglyExpressionsInterpreter.java new file mode 100644 index 0000000000..f32b49f1e3 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/expressions/uglyexpressions/_visitor/UglyExpressionsInterpreter.java @@ -0,0 +1,169 @@ +package de.monticore.expressions.uglyexpressions._visitor; + +import de.monticore.expressions.uglyexpressions._ast.ASTClassCreator; +import de.monticore.expressions.uglyexpressions._ast.ASTCreatorExpression; +import de.monticore.expressions.uglyexpressions._ast.ASTTypeCastExpression; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.MIValueFactory; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.VoidMIValue; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symboltable.ISymbol; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.logging.Log; + +import java.util.Optional; + +public class UglyExpressionsInterpreter extends UglyExpressionsInterpreterTOP { + + public UglyExpressionsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + public UglyExpressionsInterpreter() { + super(); + } + + @Override + public MIValue interpret(ASTTypeCastExpression node) { + SymTypeExpression afterType = TypeCheck3.symTypeFromAST(node.getMCType()); + SymTypeExpression beforeType = TypeCheck3.typeOf(node.getExpression()); + + MIValue value = node.getExpression().evaluate(getRealThis()); + + if (afterType.isGenericType() || beforeType.isGenericType()) { + String errorMsg = "0x57089 Explicit casts with generic types are not supported yet."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + if (afterType.isPrimitive() && beforeType.isPrimitive()) { + return convertPrimitive(beforeType.asPrimitive().getPrimitiveName(), + afterType.asPrimitive().getPrimitiveName(), value); + } + + if (afterType.isObjectType() && beforeType.isObjectType()) { + Class afterClassType; + try { + afterClassType = Class.forName(afterType.printFullName()); + } catch (ClassNotFoundException e) { + String errorMsg = "0x57089 Failed to load class '" + afterType.printFullName() + "'."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + if (!afterClassType.isInstance(value.asObject())) { + String errorMsg = "0x57090 Failed to explicitly cast object from '" + value.asObject().getClass().getName() + + "' to '" + afterType.printFullName() + "'."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + return value; + } + + String errorMsg = "0x57055 Type Cast operation from " + beforeType.print() + " to " + afterType.print() + + " is not supported."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + public MIValue convertPrimitive(String fromType, String toType, MIValue value) { + if (toType.equals(BasicSymbolsMill.BOOLEAN) || fromType.equals(BasicSymbolsMill.BOOLEAN)) { + String errorMsg = "0x57056 Cast to or from boolean is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + if (toType.equals(BasicSymbolsMill.BYTE)) { + if (fromType.equals(BasicSymbolsMill.DOUBLE)) { + return MIValueFactory.createValue((byte)value.asDouble()); + } else if (fromType.equals(BasicSymbolsMill.FLOAT)) { + return MIValueFactory.createValue((byte)value.asFloat()); + } else if (fromType.equals(BasicSymbolsMill.LONG)) { + return MIValueFactory.createValue((byte)value.asLong()); + } else if (fromType.equals(BasicSymbolsMill.INT)) { + return MIValueFactory.createValue((byte)value.asInt()); + } else if (fromType.equals(BasicSymbolsMill.SHORT)) { + return MIValueFactory.createValue((byte)value.asShort()); + } else if (fromType.equals(BasicSymbolsMill.CHAR)) { + return MIValueFactory.createValue((byte)value.asChar()); + } + return MIValueFactory.createValue(value.asByte()); + } else if (toType.equals(BasicSymbolsMill.SHORT)) { + if (fromType.equals(BasicSymbolsMill.DOUBLE)) { + return MIValueFactory.createValue((short)value.asDouble()); + } else if (fromType.equals(BasicSymbolsMill.FLOAT)) { + return MIValueFactory.createValue((short)value.asFloat()); + } else if (fromType.equals(BasicSymbolsMill.LONG)) { + return MIValueFactory.createValue((short)value.asLong()); + } else if (fromType.equals(BasicSymbolsMill.INT)) { + return MIValueFactory.createValue((short)value.asInt()); + } else if (fromType.equals(BasicSymbolsMill.CHAR)) { + return MIValueFactory.createValue((short)value.asChar()); + } + return MIValueFactory.createValue(value.asShort()); + } else if (toType.equals(BasicSymbolsMill.CHAR)) { + if (fromType.equals(BasicSymbolsMill.DOUBLE)) { + return MIValueFactory.createValue((char)value.asDouble()); + } else if (fromType.equals(BasicSymbolsMill.FLOAT)) { + return MIValueFactory.createValue((char)value.asFloat()); + } else if (fromType.equals(BasicSymbolsMill.LONG)) { + return MIValueFactory.createValue((char)value.asLong()); + } else if (fromType.equals(BasicSymbolsMill.INT)) { + return MIValueFactory.createValue((char)value.asInt()); + } else if (fromType.equals(BasicSymbolsMill.SHORT)) { + return MIValueFactory.createValue((char)value.asShort()); + } else if (fromType.equals(BasicSymbolsMill.BYTE)) { + return MIValueFactory.createValue((char)value.asByte()); + } + return MIValueFactory.createValue(value.asChar()); + } else if (toType.equals(BasicSymbolsMill.INT)) { + if (fromType.equals(BasicSymbolsMill.DOUBLE)) { + return MIValueFactory.createValue((int)value.asDouble()); + } else if (fromType.equals(BasicSymbolsMill.FLOAT)) { + return MIValueFactory.createValue((int)value.asFloat()); + } else if (fromType.equals(BasicSymbolsMill.LONG)) { + return MIValueFactory.createValue((int)value.asLong()); + } + return MIValueFactory.createValue(value.asInt()); + } else if (toType.equals(BasicSymbolsMill.LONG)) { + if (fromType.equals(BasicSymbolsMill.DOUBLE)) { + return MIValueFactory.createValue((long)value.asDouble()); + } else if (fromType.equals(BasicSymbolsMill.FLOAT)) { + return MIValueFactory.createValue((long)value.asFloat()); + } + return MIValueFactory.createValue(value.asLong()); + } else if (toType.equals(BasicSymbolsMill.FLOAT)) { + if (fromType.equals(BasicSymbolsMill.DOUBLE)) { + return MIValueFactory.createValue((float)value.asDouble()); + } + return MIValueFactory.createValue(value.asFloat()); + + } else if (toType.equals(BasicSymbolsMill.DOUBLE)) { + return MIValueFactory.createValue(value.asDouble()); + } + + String errorMsg = "0x57057 Cast from " + fromType + " to " + toType + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + @Override + public MIValue interpret(ASTCreatorExpression node) { + return node.getCreator().evaluate(getRealThis()); + } + + @Override + public MIValue interpret(ASTClassCreator node) { + SymTypeExpression type = TypeCheck3.symTypeFromAST(node.getMCType()); + Optional optSymbol = type.getSourceInfo().getSourceSymbol(); + if (optSymbol.isEmpty()) { + String errorMsg = "0x57081 Failed to load Symbol for Class."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + return new VoidMIValue(); + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/Interpreter.md b/monticore-grammar/src/main/java/de/monticore/interpreter/Interpreter.md new file mode 100644 index 0000000000..a073051dd6 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/Interpreter.md @@ -0,0 +1,190 @@ + + + + +An Interpreter evaluates a model without the need of compilation. +E.g., an expression interpreter will evaluate the expression `1 + 3` +to the value `4`. + +In MontiCore an Interpreter can be used for, e.g., +* Read-eval-print loop (REPL) +* Custom interactions with model elements at runtime, e.g., + filtering a list of car objects to only display red cars. + +## Given infrastructure in MontiCore + +* [IModelInterpreter](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/IModelInterpreter.java) + (offers `interpret` to evaluate an `ASTNode` to a value) + * [ModelInterpreter](ModelInterpreter.java) + (default Implementation; + allows storing/loading of variables and functions) +* [MIValue](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/MIValue.java) + (represents values as a result of interpretation) + * [MIValueFactory](MIValueFactory.java) + (Factory to create MIValues) + * [BooleanMIValue](values/BooleanMIValue.java) + (represents a `boolean` value) + * [ByteMIValue](values/ByteMIValue.java) + (represents a `byte` value) + * [ShortMIValue](values/ShortMIValue.java) + (represents a `short` value) + * [CharMIValue](values/CharMIValue.java) + (represents a `char` value) + * [IntMIValue](values/IntMIValue.java) + (represents an `int` value) + * [LongMIValue](values/LongMIValue.java) + (represents a `long` value) + * [FloatMIValue](values/FloatMIValue.java) + (represents a `float` value) + * [DoubleMIValue](values/DoubleMIValue.java) + (represents a `double` value) + * [ObjectMIValue](values/ObjectMIValue.java) + (represents a Java `Object` value, including subclasses) + * [FunctionMIValue](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/values/FunctionMIValue.java) + (represents function values, they can be executed) + * [ModelFunctionMIValue](values/ModelFunctionMIValue.java) + (represents a function defined by an ASTNode) + * [JavaNonStaticMethodMIValue](values/JavaNonStaticMethodMIValue.java) + (represents a non-static method of a Java class) + * [JavaStaticMethodMIValue](values/JavaStaticMethodMIValue.java) + (represents a static method of a Java class) + * [WriteableMIValue](values/WriteableMIValue.java) + (represents an LValue; a value can be assigned, e.g., `a` in `a = 2;`) + * [VariableMIValue](values/VariableMIValue.java) + (represents the value of a VariableSymbol) + * [JavaAttributeMIValue](values/JavaAttributeMIValue.java) + (represents the value of a Java `Object`'s attribute, e.g, `p.name`) + * [VoidMIValue](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/values/VoidMIValue.java) + (represents the lack of a value, e.g., interpretation of a statement) + * [ErrorMIValue](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/values/ErrorMIValue.java) + (represents an error during execution, e.g., interpretation of `1/0`) + * [MIFlowControlSignal](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/values/MIFlowControlSignal.java) + (represents transfer of control in the execution flow) + * [ReturnMIValue](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/values/MIReturnSignal.java) + (represents transfer of control due to a `return` statement, + contains the value returned) + * [BreakMIValue](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/values/MIBreakSignal.java) + (represents transfer of control due to a `break` statement) + * [ContinueMIValue](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/values/MIContinueSignal.java) + (represents transfer of control due to a `continue` statement) +* [IMIScope](../../../../../../../monticore-runtime/src/main/java/de/monticore/interpreter/IMIScope.java) + (represents a scope of execution of the interpreter) + * [MIScope](MIScope.java) + (implementation; contains local variables/functions) +* [MIForIterator](iterators/MIForIterator.java) + (internal representation of an iterator of a for-loop, + can execute the body of the loop) + * [MICommonForIterator](iterators/MICommonForIterator.java) + (represents the common for iterator, e.g, `int i = 5; i < 10; i++`) + * [MIForEachIterator](iterators/MIForEachIterator.java) + (represents the iterator of a for-each loop, e.g, `Person p : persons`) +* [InterpreterUtils](InterpreterUtils.java) + (internal utility class for interpreter visitors; offers, e.g., casting of values) +* Interpreter Visitors contain the evaluation logic for each type of `ASTNode` + of their corresponding grammar component. + * Expressions + * [AssignmentExpressionsInterpreter](../expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreter.java) + * BitExpressionsInterpreter is currently not implemented. + * [CommonExpressionsInterpreter](../expressions/commonexpressions/_visitor/CommonExpressionsInterpreter.java) + * [ExpressionBasisInterpreter](../expressions/expressionsbasis/_visitor/ExpressionsBasisInterpreter.java) + * JavaClassExpressionsInterpreter is currently not implemented. + * [LambdaExpressionsInterpreter](../expressions/lambdaexpressions/_visitor/LambdaExpressionsInterpreter.java) + * [OCLExpressionsInterpreter](../ocl/oclexpressions/_visitor/OCLExpressionsInterpreter.java) + is mostly unimplemented. + * OptionalOperatorsInterpreter is currently not implemented. + * RegularExpressionsInterpreter is currently not implemented. + * [SetExpressionsInterpreter](../ocl/setexpressions/_visitor/SetExpressionsInterpreter.java) + * StreamExpressionsInterpreter is currently no implemented. + * TupleExpressionsInterpreter is currently not implemented. + * [UglyExpressionsInterpreter](../expressions/uglyexpressions/_visitor/UglyExpressionsInterpreter.java) + is currently not implemented fully. + * Literals + * [MCCommonLiteralsInterpreter](../literals/mccommonliterals/_visitor/MCCommonLiteralsInterpreter.java) + * JavaLiteralsInterpreter is currently not implemented. + * Statements + * MCArrayStatementsInterpreter is currently not implemented. + * [MCCommonStatementsInterpreter](../statements/mccommonstatements/_visitor/MCCommonStatementsInterpreter.java) + * [MCLowLevelStatementsInterpreter](../statements/mclowlevelstatements/_visitor/MCLowLevelStatementsInterpreter.java) + is mostly unimplemented + * [MCReturnStatementsInterpreter](../statements/mcreturnstatements/_visitor/MCReturnStatementsInterpreter.java) + * [MCVarDeclarationStatemensInterpreter](../statements/mcvardeclarationstatements/_visitor/MCVarDeclarationStatementsInterpreter.java) + +## How to Interpret a Model + +The interpreter is a collection of visitors traversing the AST. +The [ModelInterpreter](ModelInterpreter.java) +can be used to evaluate an `ASTNode`; +The `ASTNode` has to have a corresponding symbol table, +and has to be of a valid model (check using CoCos). + +Create a new Interpreter of your language and use +`ASTNode::evaluate` to calculate a value; +```java +ASTNode expr = parseAndCreateSymTabAndRunCoCos("1 + 3"); +ModelInterpreter interpreter = new MyLangInterpreter(); +MIValue result = expr.evaluate(interpreter); +// check that no error occurred with isError(), +// error will be logged already +if (result.isInt()) { + System.out.println("1 + 3 = " + result.asInt()); +} +``` + +## How to store/load variables/functions (to be) used in the interpreter + +To use custom values during interpretation, +first, add the corresponding symbols (VariableSymbol/FunctionSymbol) +to the symbol table, as they have to be available for the CoCos to pass. + +Afterwards, set the values in the interpreter accordingly; +```java +// add j to the symbol table +ModelInterpreter interpreter = new MyLangInterpreter(); +// add the variable to the interpreters current scope +interpreter.declareVariable(jSymbol, MIValueFactory.createValue(2)); +ASTNode statement = parseAndCreateSymTabAndRunCoCos("int i = j++;"); +statement.evaluate(interpreter); // simply returns void +VariableSymbol iSymbol = // resolve for "i" in the model's scope +int i = interpreter.loadVariable(iSymbol).asInt(); // i == 2 +int j = interpreter.loadVariable(jSymbol).asInt(); // j == 3 +// j is already in the interpreter's scope, +// use 'store' to set a new value +interpreter.storeVariable(jSymbol, MIValueFactory.createValue(4)); +``` + +## Sandboxing – How to use Java Classes in the Interpreter + +Simply initialize Class2MC and Java classes can be used with the interpreter. + +_But is it safe?_ +__No! Adding Class2MC allows the execution of arbitrary code!__ + +One should consider +* setting the predicate of the Class2MCResolver + to filter out all classes not explicitly allowed. + * currently, this cannot filter attributes/methods +* Use a CoCo to check for whether all model elements are allowed. + +A safer Approach is to +1. _NOT_ initialize Class2MC +2. add all allowed symbols to the symbol table +3. use `declareVariable`/`declareFunction` to set the values +4. interpret using this limited, but safe(r), set of symbols + +Regarding static symbols; +If JavaInteroperability is used with static variables/methods, +then global values can be changed, +which in turn can influence the execution of the current program, +or different interpreters might influence each other. +In most cases, it is recommended to not allow access to static symbols. + +## Further Information + +* [Project root: MontiCore @github](https://github.com/MontiCore/monticore) +* [MontiCore documentation](https://www.monticore.de/) +* [**List of languages**](https://github.com/MontiCore/monticore/blob/opendev/docs/Languages.md) +* [**MontiCore Core Grammar Library**](https://github.com/MontiCore/monticore/blob/opendev/monticore-grammar/src/main/grammars/de/monticore/Grammars.md) +* [TypeSystem documentation](../types3/TypeSystem3.md) +* [Best Practices](https://github.com/MontiCore/monticore/blob/opendev/docs/BestPractices.md) +* [Publications about MBSE and MontiCore](https://www.se-rwth.de/publications/) +* [Licence definition](https://github.com/MontiCore/monticore/blob/master/00.org/Licenses/LICENSE-MONTICORE-3-LEVEL.md) diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/InterpreterUtils.java b/monticore-grammar/src/main/java/de/monticore/interpreter/InterpreterUtils.java new file mode 100644 index 0000000000..b99bb55732 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/InterpreterUtils.java @@ -0,0 +1,679 @@ +package de.monticore.interpreter; + +import de.monticore.interpreter.values.BooleanMIValue; +import de.monticore.interpreter.values.ByteMIValue; +import de.monticore.interpreter.values.CharMIValue; +import de.monticore.interpreter.values.DoubleMIValue; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.FloatMIValue; +import de.monticore.interpreter.values.IntMIValue; +import de.monticore.interpreter.values.JavaAttributeMIValue; +import de.monticore.interpreter.values.LongMIValue; +import de.monticore.interpreter.values.ObjectMIValue; +import de.monticore.interpreter.values.ShortMIValue; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.SymTypeRelations; +import de.se_rwth.commons.logging.Log; + +import java.lang.reflect.Field; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.BinaryOperator; + +import static de.monticore.interpreter.MIValueFactory.createValue; + +/** + * Utility class for the interpreter. + * Contains methods for implict/explicit casts, conversion from Object to + * MIValue or MIValue to object, and the calculation of binary operations. + */ +public class InterpreterUtils { + + // todo use SymTypeExpression, not string for resultType + // todo opName is not the name, but errorcode+name -> split! + public static MIValue calcOpPrimitive(MIValue v1, MIValue v2, + String resultType, BinaryOperator opInt, + BinaryOperator opLong, BinaryOperator opFloat, + BinaryOperator opDouble, String opName) { + + try { + switch (resultType) { + case BasicSymbolsMill.INT: + return createValue((int) opInt.apply(v1.asInt(), v2.asInt())); + case BasicSymbolsMill.LONG: + return createValue((long) opLong.apply(v1.asLong(), v2.asLong())); + case BasicSymbolsMill.FLOAT: + return createValue((float) opFloat.apply(v1.asFloat(), v2.asFloat())); + case BasicSymbolsMill.DOUBLE: + return createValue((double) opDouble.apply(v1.asDouble(), v2.asDouble())); + } + } + catch (Exception e) { + // e.g., ArithmeticException 1/0 + Log.error("0x58110 exception occured during interpretation of the " + + opName + " operator", e); + return new ErrorMIValue(e); + } + + String errorMsg = opName + " operation with result of type " + resultType + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + public static MIValue calcBitwiseOpPrimitive(MIValue v1, MIValue v2, + String resultType, BinaryOperator opInt, + BinaryOperator opLong, String opName) { + switch (resultType) { + case BasicSymbolsMill.INT: + return createValue((int) opInt.apply(v1.asInt(), v2.asInt())); + case BasicSymbolsMill.LONG: + return createValue((long) opLong.apply(v1.asLong(), v2.asLong())); + } + String errorMsg = opName + " operation with result of type " + resultType + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + public static MIValue calcBitwiseLogicalOpPrimitive(MIValue v1, MIValue v2, + String resultType, BinaryOperator opBool, + BinaryOperator opInt, BinaryOperator opLong, + String opName) { + switch (resultType) { + case BasicSymbolsMill.BOOLEAN: + return createValue((boolean) opBool.apply(v1.asBoolean(), v2.asBoolean())); + case BasicSymbolsMill.INT: + return createValue((int) opInt.apply(v1.asInt(), v2.asInt())); + case BasicSymbolsMill.LONG: + return createValue((long) opLong.apply(v1.asLong(), v2.asLong())); + } + String errorMsg = opName + " operation with result of type " + resultType + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + public static MIValue calcShiftPrimitive(MIValue v1, MIValue v2, + String resultType, BiFunction opInt, + BinaryOperator opLong, String opName) { + switch (resultType) { + case BasicSymbolsMill.INT: + return createValue((int) opInt.apply(v1.asInt(), v2.asLong())); + case BasicSymbolsMill.LONG: + return createValue((long) opLong.apply(v1.asLong(), v2.asLong())); + } + String errorMsg = opName + " operation with result of type " + resultType + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + /** + * Calculates the result of a binary operation with the given result type by + * using the given lambdas for the calculation. Operation should support + * int, long, float {@literal &} double. + * + * @param v1 left operand + * @param v2 right operand + * @param resultType result type of the operation + * @param opInt lambda for int operation + * @param opLong lambda for long operation + * @param opFloat lambda for float operation + * @param opDouble lambda for double operation + * @param opName Name of the operation (for error messages) + * @return Result of the operation or an error value if the type is not supported. + */ + public static MIValue calcOp(MIValue v1, MIValue v2, + SymTypeExpression resultType, BinaryOperator opInt, + BinaryOperator opLong, BinaryOperator opFloat, + BinaryOperator opDouble, String opName) { + if (resultType.isPrimitive()) { + return calcOpPrimitive(v1, v2, resultType.asPrimitive().getPrimitiveName(), opInt, opLong, opFloat, opDouble, opName); + } + + String errorMsg = opName + " operation with result of type " + + resultType.printFullName() + + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + /** + * Calculates the result of a bitwise binary operation with the given result type by using + * the given lambdas for the calculation. Operation should support int {@literal &} long. + * + * @param v1 left operand + * @param v2 right operand + * @param resultType result type of the operation + * @param opInt lambda for int operation + * @param opLong lambda for long operation + * @param opName Name of the operation (for error messages) + * @return Result of the operation or an error value if the type is not supported. + */ + public static MIValue calcBitwiseOp(MIValue v1, MIValue v2, + SymTypeExpression resultType, BinaryOperator opInt, + BinaryOperator opLong, String opName) { + if (resultType.isPrimitive()) { + return calcBitwiseOpPrimitive(v1, v2, resultType.asPrimitive().getPrimitiveName(), opInt, opLong, opName); + } + + String errorMsg = opName + " operation with result of type " + + resultType.printFullName() + + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + /** + * Calculates the result of a bitwise or logical binary operation with the + * given result type by using the given lambdas for the calculation. + * Operation should support boolean, int {@literal &} long. + * + * @param v1 left operand + * @param v2 right operand + * @param resultType result type of the operation + * @param opInt lambda for int operation + * @param opLong lambda for long operation + * @param opName Name of the operation (for error messages) + * @return Result of the operation or an error value if the type is not supported. + */ + public static MIValue calcBitwiseLogicalOp(MIValue v1, MIValue v2, + SymTypeExpression resultType, + BinaryOperator opBool, BinaryOperator opInt, + BinaryOperator opLong, String opName) { + if (resultType.isPrimitive()) { + return calcBitwiseLogicalOpPrimitive(v1, v2, + resultType.asPrimitive().getPrimitiveName(), opBool, opInt, + opLong, opName); + } + + String errorMsg = opName + " operation with result of type " + resultType + + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + /** + * Calculates the result of a shift-like operation with the + * given result type by using the given lambdas for the calculation. + * Shift operations always support up to long for the right side. + * + * @param v1 left operand + * @param v2 right operand + * @param resultType result type of the operation + * @param opInt lambda for int operation + * @param opLong lambda for long operation + * @param opName Name of the operation (for error messages) + * @return Result of the operation or an error value if the type is not supported. + */ + public static MIValue calcShift(MIValue v1, MIValue v2, + SymTypeExpression resultType, + BiFunction opInt, + BinaryOperator opLong, String opName) { + if (resultType.isPrimitive()) { + return calcShiftPrimitive(v1, v2, + resultType.asPrimitive().getPrimitiveName(), opInt, opLong, + opName); + } + + String errorMsg = opName + " operation with result of type " + resultType + + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + /** + * Applies an explicit cast on primitive to target primitive type. + * + * @return converted MIValue or ErrorMIValue if the cast is not supported or + * not possible. + */ + public static MIValue convertToPrimitiveExplicit(String from, String to, + MIValue value) { + if (to.equals(BasicSymbolsMill.BOOLEAN) || from.equals(BasicSymbolsMill.BOOLEAN)) { + String errorMsg = "0x57060 Cast to or from boolean is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + if (to.equals(BasicSymbolsMill.BYTE)) { + switch (from) { + case BasicSymbolsMill.DOUBLE: + return createValue((byte) value.asDouble()); + case BasicSymbolsMill.FLOAT: + return createValue((byte) value.asFloat()); + case BasicSymbolsMill.LONG: + return createValue((byte) value.asLong()); + case BasicSymbolsMill.INT: + return createValue((byte) value.asInt()); + case BasicSymbolsMill.SHORT: + return createValue((byte) value.asShort()); + case BasicSymbolsMill.CHAR: + return createValue((byte) value.asChar()); + default: + return createValue(value.asByte()); + } + + } + else if (to.equals(BasicSymbolsMill.SHORT)) { + switch (from) { + case BasicSymbolsMill.DOUBLE: + return createValue((short) value.asDouble()); + case BasicSymbolsMill.FLOAT: + return createValue((short) value.asFloat()); + case BasicSymbolsMill.LONG: + return createValue((short) value.asLong()); + case BasicSymbolsMill.INT: + return createValue((short) value.asInt()); + case BasicSymbolsMill.CHAR: + return createValue((short) value.asChar()); + default: + return createValue(value.asShort()); + } + + } + else if (to.equals(BasicSymbolsMill.CHAR)) { + switch (from) { + case BasicSymbolsMill.DOUBLE: + return createValue((char) value.asDouble()); + case BasicSymbolsMill.FLOAT: + return createValue((char) value.asFloat()); + case BasicSymbolsMill.LONG: + return createValue((char) value.asLong()); + case BasicSymbolsMill.INT: + return createValue((char) value.asInt()); + case BasicSymbolsMill.SHORT: + return createValue((char) value.asShort()); + case BasicSymbolsMill.BYTE: + return createValue((char) value.asByte()); + default: + return createValue(value.asChar()); + } + + } + else if (to.equals(BasicSymbolsMill.INT)) { + switch (from) { + case BasicSymbolsMill.DOUBLE: + return createValue((int) value.asDouble()); + case BasicSymbolsMill.FLOAT: + return createValue((int) value.asFloat()); + case BasicSymbolsMill.LONG: + return createValue((int) value.asLong()); + default: + return createValue(value.asInt()); + } + + } + else if (to.equals(BasicSymbolsMill.LONG)) { + if (from.equals(BasicSymbolsMill.DOUBLE)) { + return createValue((long) value.asDouble()); + } + else if (from.equals(BasicSymbolsMill.FLOAT)) { + return createValue((long) value.asFloat()); + } + return createValue(value.asLong()); + + } + else if (to.equals(BasicSymbolsMill.FLOAT)) { + if (from.equals(BasicSymbolsMill.DOUBLE)) { + return createValue((float) value.asDouble()); + } + return createValue(value.asFloat()); + + } + else if (to.equals(BasicSymbolsMill.DOUBLE)) { + return createValue(value.asDouble()); + } + + String errorMsg = "0x57061 Cast from " + from + " to " + to + + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + /** + * Applies an implicit cast on primitive to target primitive type + * + * @return converted MIValue or ErrorMIValue if the cast is not supported or + * not possible. + * + * todo replace String with SymTypeExpression for targetType + */ + public static MIValue convertToPrimitiveImplicit(String targetType, + MIValue value) { + if (value.isError()) { + return value; + } + else if (targetType.equals(BasicSymbolsMill.BYTE)) { + return createValue(value.asByte()); + } + else if (targetType.equals(BasicSymbolsMill.SHORT)) { + return createValue(value.asShort()); + } + else if (targetType.equals(BasicSymbolsMill.CHAR)) { + return createValue(value.asChar()); + } + else if (targetType.equals(BasicSymbolsMill.INT)) { + return createValue(value.asInt()); + } + else if (targetType.equals(BasicSymbolsMill.LONG)) { + return createValue(value.asLong()); + } + else if (targetType.equals(BasicSymbolsMill.FLOAT)) { + return createValue(value.asFloat()); + } + else if (targetType.equals(BasicSymbolsMill.DOUBLE)) { + return createValue(value.asDouble()); + } + + String errorMsg = "0x57062 Implicit cast to " + targetType + + " is not supported."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + /** + * Applies an implicit cast on value to targetType. + * Allows casts of boxtypes and primitives. + * + * @return converted MIValue or ErrorMIValue if the cast is not supported or + * not possible. + */ + public static MIValue convertImplicit(SymTypeExpression targetType, + MIValue value) { + if (value.isError()) { + return value; + } + else if (targetType.isPrimitive()) { + value = unboxType(value); + return convertToPrimitiveImplicit( + targetType.asPrimitive().getPrimitiveName(), value + ); + } + else if (isBoxType(targetType)) { + SymTypeExpression unboxedType = SymTypeRelations.unbox(targetType); + value = convertToPrimitiveImplicit( + unboxedType.asPrimitive().getPrimitiveName(), value + ); + value = boxValue(value, targetType); + return value; + } + else { + // value may be primitive with targetType Object; int -> Integer -> Object + if (value.isPrimitive()) { + value = boxValue(value); + } + return value; + } + } + + /** + * Creates an AttributeMIValue for a non-static attribute of a java-object. + * + * @param object Java-Object as MIValue + * @return Value of the attribute as MIValue converted to the given type. + * ErrorMIValue if the attribute does not exist or is not accessible. + */ + public static MIValue getNonStaticObjectAttribute(ObjectMIValue object, + String attributeName) { + Field attribute; + try { + attribute = object.asObject().getClass().getField(attributeName); + } + catch (NoSuchFieldException e) { + String errorMsg = "0x57063 Tried to access attribute '" + attributeName + + "' of class '" + object.getClass().getName() + + "'. No such attribute exists."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + return new JavaAttributeMIValue(Optional.of(object.asObject()), attribute); + } + + /** + * Creates an AttributeMIValue for a non-static attribute of a java-object. + * + * @param classObject Java-Class + * @return Value of the attribute as MIValue converted to the given type. + * ErrorMIValue if the attribute does not exist or is not accessible. + */ + public static MIValue getStaticObjectAttribute(Class classObject, + String attributeName) { + Field attribute; + try { + attribute = classObject.getField(attributeName); + } + catch (NoSuchFieldException e) { + String errorMsg = "0x57063 Tried to access attribute '" + attributeName + + "' of class '" + classObject.getName() + + "'. No such attribute exists."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + return new JavaAttributeMIValue(Optional.empty(), attribute); + } + + /** + * Gets the corresponding java type for a given MIValue. + */ + public static Class typeOfValue(MIValue value) { + if (value.isBoolean()) { + return boolean.class; + } + else if (value.isChar()) { + return char.class; + } + else if (value.isByte()) { + return byte.class; + } + else if (value.isShort()) { + return short.class; + } + else if (value.isInt()) { + return int.class; + } + else if (value.isLong()) { + return long.class; + } + else if (value.isFloat()) { + return float.class; + } + else if (value.isDouble()) { + return double.class; + } + else if (value.isObject()) { + return value.asObject().getClass(); + } + // Functions are not allowed + String errorMsg = "0x57066 Failed to get java type of " + value.printType() + + "."; + Log.error(errorMsg); + return null; + } + + /** + * Converts a MIValue to a java object. + */ + public static Object valueToObject(MIValue value) { + if (value.isBoolean()) { + return value.asBoolean(); + } + else if (value.isChar()) { + return value.asChar(); + } + else if (value.isByte()) { + return value.asByte(); + } + else if (value.isShort()) { + return value.asShort(); + } + else if (value.isInt()) { + return value.asInt(); + } + else if (value.isLong()) { + return value.asLong(); + } + else if (value.isFloat()) { + return value.asFloat(); + } + else if (value.isDouble()) { + return value.asDouble(); + } + else if (value.isObject()) { + return value.asObject(); + } + // Functions are not allowed + String errorMsg = "0x57067 Failed to convert MIValue of type " + + value.printType() + " to a java object."; + Log.error(errorMsg); + return null; + } + + /** + * Converts a java object to a MIValue. + * Boxtypes are converted to their corresponding primitive type. + */ + public static MIValue objectToValue(Object object) { + if (object instanceof Boolean) { + return new BooleanMIValue((Boolean) object); + } + else if (object instanceof Character) { + return new CharMIValue((Character) object); + } + else if (object instanceof Byte) { + return new ByteMIValue((Byte) object); + } + else if (object instanceof Short) { + return new ShortMIValue((Short) object); + } + else if (object instanceof Integer) { + return new IntMIValue((Integer) object); + } + else if (object instanceof Long) { + return new LongMIValue((Long) object); + } + else if (object instanceof Float) { + return new FloatMIValue((Float) object); + } + else if (object instanceof Double) { + return new DoubleMIValue((Double) object); + } + + return new ObjectMIValue(object); + } + + /** + * Checks if SymTypeExpression is a boxtype + */ + public static boolean isBoxType(SymTypeExpression type) { + return !type.isPrimitive() && ( + SymTypeRelations.isNumericType(type) + || SymTypeRelations.isBoolean(type) + ); + } + + /** + * Unboxes a value if it is a boxtype. + */ + public static MIValue unboxType(MIValue value) { + if (!value.isObject()) + return value; + + Object obj = value.asObject(); + if (obj instanceof Integer) { + return new IntMIValue((Integer) obj); + } + else if (obj instanceof Long) { + return new LongMIValue((Long) obj); + } + else if (obj instanceof Float) { + return new FloatMIValue((Float) obj); + } + else if (obj instanceof Double) { + return new DoubleMIValue((Double) obj); + } + else if (obj instanceof Character) { + return new CharMIValue((Character) obj); + } + else if (obj instanceof Byte) { + return new ByteMIValue((Byte) obj); + } + else if (obj instanceof Short) { + return new ShortMIValue((Short) obj); + } + + return value; + } + + /** + * Converts a MIValue into its equivalent Boxtype + */ + public static MIValue boxValue(MIValue value) { + if (!value.isPrimitive()) { + return value; + } + + if (value.isBoolean()) { + return MIValueFactory.createValue((Boolean) value.asBoolean()); + } + else if (value.isChar()) { + return MIValueFactory.createValue((Character) value.asChar()); + } + else if (value.isByte()) { + return MIValueFactory.createValue((Byte) value.asByte()); + } + else if (value.isShort()) { + return MIValueFactory.createValue((Short) value.asShort()); + } + else if (value.isInt()) { + return MIValueFactory.createValue((Integer) value.asInt()); + } + else if (value.isLong()) { + return MIValueFactory.createValue((Long) value.asLong()); + } + else if (value.isFloat()) { + return MIValueFactory.createValue((Float) value.asFloat()); + } + else if (value.isDouble()) { + return MIValueFactory.createValue((Double) value.asDouble()); + } + + return value; + } + + /** + * Converts a value to the given box type. + * + * @return Boxed value wrapped in an ObjectMIValue + */ + public static MIValue boxValue(MIValue value, SymTypeExpression boxType) { + if (SymTypeRelations.isInt(boxType)) { + return MIValueFactory.createValue(Integer.valueOf(value.asInt())); + } + else if (SymTypeRelations.isLong(boxType)) { + return MIValueFactory.createValue(Long.valueOf(value.asLong())); + } + else if (SymTypeRelations.isFloat(boxType)) { + return MIValueFactory.createValue(Float.valueOf(value.asFloat())); + } + else if (SymTypeRelations.isDouble(boxType)) { + return MIValueFactory.createValue(Double.valueOf(value.asDouble())); + } + else if (SymTypeRelations.isChar(boxType)) { + return MIValueFactory.createValue(Character.valueOf(value.asChar())); + } + else if (SymTypeRelations.isByte(boxType)) { + return MIValueFactory.createValue(Byte.valueOf(value.asByte())); + } + else if (SymTypeRelations.isShort(boxType)) { + return MIValueFactory.createValue(Short.valueOf(value.asShort())); + } + else if (SymTypeRelations.isBoolean(boxType)) { + return MIValueFactory.createValue(Boolean.valueOf(value.asBoolean())); + } + + String errorMsg = "0x57084 Tried to convert to unknown boxed type."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/MIScope.java b/monticore-grammar/src/main/java/de/monticore/interpreter/MIScope.java new file mode 100644 index 0000000000..b110fcf4f0 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/MIScope.java @@ -0,0 +1,98 @@ +package de.monticore.interpreter; + +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.FunctionMIValue; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.se_rwth.commons.logging.Log; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class MIScope implements IMIScope { + + protected Map functionMap = new HashMap<>(); + protected Map> variableMap = new HashMap<>(); + + protected Optional parent; + + public MIScope() { + this.parent = Optional.empty(); + } + + public MIScope(MIScope parent) { + this.parent = Optional.of(parent); + } + + public MIScope clone() { + MIScope clone = new MIScope(); + clone.parent = parent; + clone.variableMap = new HashMap<>(variableMap); + clone.functionMap = new HashMap<>(functionMap); + return clone; + } + + public void declareFunction(FunctionSymbol symbol, FunctionMIValue value) { + if (functionMap.containsKey(symbol)) { + Log.error("0x57068 Function was already declared"); + } + this.functionMap.put(symbol, value); + } + + public MIValue loadFunction(FunctionSymbol symbol) { + if (functionMap.containsKey(symbol)) { + return functionMap.get(symbol); + } + + if (parent.isPresent()) { + return parent.get().loadFunction(symbol); + } + + String errorMsg = "0x57069 Failed to load Function by Symbol. Could not find Symbol in the current or any parent scope"; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + public void declareVariable(VariableSymbol symbol, Optional value) { + if (variableMap.containsKey(symbol)) { + Log.error("0x57070 Variable was already declared"); + } + this.variableMap.put(symbol, value); + } + + public MIValue loadVariable(VariableSymbol symbol) { + Optional value = variableMap.get(symbol); + if (value != null) { + if (value.isPresent()) { + return value.get(); + } + else { + String errorMsg = "0x57087 Failed to load Variable by Symbol. Variable was declared but never initialized."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + } + + if (parent.isPresent()) { + return parent.get().loadVariable(symbol); + } + + String errorMsg = "0x57071 Failed to load Variable by Symbol. Could not find Symbol in the current or any parent scope"; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + public void storeVariable(VariableSymbol symbol, MIValue value) { + if (variableMap.containsKey(symbol)) { + variableMap.put(symbol, Optional.of(value)); + } + else if (parent.isPresent()) { + parent.get().storeVariable(symbol, value); + } + else { + Log.error("0x57072 Failed to store Value in Symbol. Could not find Symbol in the current or any parent scope"); + } + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/MIValueFactory.java b/monticore-grammar/src/main/java/de/monticore/interpreter/MIValueFactory.java new file mode 100644 index 0000000000..7b5e344309 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/MIValueFactory.java @@ -0,0 +1,52 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.interpreter; + +import de.monticore.interpreter.values.BooleanMIValue; +import de.monticore.interpreter.values.ByteMIValue; +import de.monticore.interpreter.values.CharMIValue; +import de.monticore.interpreter.values.DoubleMIValue; +import de.monticore.interpreter.values.FloatMIValue; +import de.monticore.interpreter.values.IntMIValue; +import de.monticore.interpreter.values.LongMIValue; +import de.monticore.interpreter.values.ObjectMIValue; +import de.monticore.interpreter.values.ShortMIValue; + +public class MIValueFactory { + + public static MIValue createValue(short value) { + return new ShortMIValue(value); + } + + public static MIValue createValue(int value) { + return new IntMIValue(value); + } + + public static MIValue createValue(double value) { + return new DoubleMIValue(value); + } + + public static MIValue createValue(float value) { + return new FloatMIValue(value); + } + + public static MIValue createValue(long value) { + return new LongMIValue(value); + } + + public static MIValue createValue(boolean value) { + return new BooleanMIValue(value); + } + + public static MIValue createValue(char value) { + return new CharMIValue(value); + } + + public static MIValue createValue(byte value) { + return new ByteMIValue(value); + } + + public static MIValue createValue(Object value) { + return new ObjectMIValue(value); + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/ModelInterpreter.java b/monticore-grammar/src/main/java/de/monticore/interpreter/ModelInterpreter.java new file mode 100644 index 0000000000..e7df6fe2f8 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/ModelInterpreter.java @@ -0,0 +1,70 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.interpreter; + +import de.monticore.interpreter.values.FunctionMIValue; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; + +import java.util.Optional; +import java.util.Stack; + +public interface ModelInterpreter extends IModelInterpreter { + + void setRealThis(ModelInterpreter realThis); + + ModelInterpreter getRealThis(); + + Stack getScopeCallstack(); + + default MIScope getCurrentScope() { + return getRealThis().getScopeCallstack().peek(); + } + + /* + TODO Explicit cast is needed because: + Short version: Dependencies between symbols, scopes, functions & interpreter + Long version: + ModelFunctionMIValue has VariableSymbols as attributes + -> ModelFunctionMIValue must be in mc-grammar + MIScope uses Variable-/FunctionSymbol + -> must be in mc-grammar + ModelFunctionMIValue uses 'pushScope(MIScope)'; + IModelInterpreter must in mc-rte and has 'MIValue interpret()' + -> MIValue must be in mc-rte; + MIValue has 'FunctionMIValue asFunction()' + -> FunctionMIValue must be in mc-rte + FunctionMIValue needs 'execute(IModelInterpreter)' + -> ModelFunctionMIValue must use IModelInterpreter + -> ModelInterpreter needs 'pushScope(MIScope)' + MIScope cant be accessed -> IMIScope + IMIscope cant access Variable-/FunctionSymbol -> explicit cast + */ + default void pushScope(IMIScope scope) { + getRealThis().getScopeCallstack().push((MIScope) scope); + } + + default void popScope() { + getRealThis().getScopeCallstack().pop(); + } + + default void declareFunction(FunctionSymbol symbol, FunctionMIValue value) { + getCurrentScope().declareFunction(symbol, value); + } + + default MIValue loadFunction(FunctionSymbol symbol) { + return getCurrentScope().loadFunction(symbol); + } + + default void declareVariable(VariableSymbol symbol, Optional value) { + getCurrentScope().declareVariable(symbol, value); + } + + default MIValue loadVariable(VariableSymbol symbol) { + return getCurrentScope().loadVariable(symbol); + } + + default void storeVariable(VariableSymbol symbol, MIValue value) { + getCurrentScope().storeVariable(symbol, value); + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MICommonForIterator.java b/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MICommonForIterator.java new file mode 100644 index 0000000000..b2dc319fc0 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MICommonForIterator.java @@ -0,0 +1,75 @@ +package de.monticore.interpreter.iterators; + +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.MIValueFactory; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.values.VoidMIValue; +import de.monticore.statements.mccommonstatements._ast.ASTForInit; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCStatement; + +import java.util.List; +import java.util.Optional; + +public class MICommonForIterator implements MIForIterator { + + protected Optional initNode; + + protected Optional condition; + + protected List expressions; + + public MICommonForIterator(Optional initNode, Optional condition, List expressions) { + this.initNode = initNode; + this.condition = condition; + this.expressions = expressions; + } + + @Override + public MIValue execute(ModelInterpreter interpreter, ASTMCStatement body) { + if (initNode.isPresent()) { + MIValue result = initNode.get().evaluate(interpreter); + if (result.isFlowControlSignal()) + return result; + } + + MIValue conditionResult = checkCondition(interpreter); + while (conditionResult.isBoolean() && conditionResult.asBoolean()) { + MIValue statementResult = body.evaluate(interpreter); + if (statementResult.isBreak()) + break; + if (statementResult.isFlowControlSignal() && !statementResult.isContinue()) + return statementResult; + + MIValue incrementResult = increment(interpreter); + if (incrementResult.isFlowControlSignal()) { + return incrementResult; + } + + conditionResult = checkCondition(interpreter); + } + + return conditionResult.isFlowControlSignal() ? conditionResult : new VoidMIValue(); + } + + // helper + + protected MIValue checkCondition(ModelInterpreter interpreter) { + if (condition.isPresent()) { + return condition.get().evaluate(interpreter); + } + else { + return MIValueFactory.createValue(true); + } + } + + protected MIValue increment(ModelInterpreter interpreter) { + for (ASTExpression expression : expressions) { + MIValue result = expression.evaluate(interpreter); + if (result.isError()) + return result; + } + return new VoidMIValue(); + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MIForEachIterator.java b/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MIForEachIterator.java new file mode 100644 index 0000000000..8cd5b898f4 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MIForEachIterator.java @@ -0,0 +1,50 @@ +package de.monticore.interpreter.iterators; + +import de.monticore.interpreter.InterpreterUtils; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.MIValueFactory; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.values.VoidMIValue; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCStatement; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.types.check.SymTypeExpression; + +import java.util.Iterator; +import java.util.Optional; + +public class MIForEachIterator implements MIForIterator { + + protected VariableSymbol symbol; + + protected Iterator iterator; + + public MIForEachIterator(VariableSymbol symbol, Iterator iterator) { + this.symbol = symbol; + this.iterator = iterator; + } + + @Override + public MIValue execute(ModelInterpreter interpreter, ASTMCStatement body) { + if (!iterator.hasNext()) + return new VoidMIValue(); + + interpreter.declareVariable(symbol, Optional.empty()); + do { + SymTypeExpression targetType = symbol.getType(); + Object nextValue = iterator.next(); + MIValue convertedValue = InterpreterUtils.convertImplicit(targetType, MIValueFactory.createValue(nextValue)); + interpreter.storeVariable(symbol, convertedValue); + + MIValue statementResult = body.evaluate(interpreter); + if (statementResult.isContinue()) + continue; + if (statementResult.isBreak()) + break; + if (statementResult.isFlowControlSignal()) + return statementResult; + } while (iterator.hasNext()); + + return new VoidMIValue(); + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MIForIterator.java b/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MIForIterator.java new file mode 100644 index 0000000000..a952834d07 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/iterators/MIForIterator.java @@ -0,0 +1,12 @@ +package de.monticore.interpreter.iterators; + +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCStatement; + +@FunctionalInterface +public interface MIForIterator { + + MIValue execute(ModelInterpreter interpreter, ASTMCStatement body); + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/BooleanValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/BooleanMIValue.java similarity index 52% rename from monticore-runtime/src/main/java/de/monticore/interpreter/values/BooleanValue.java rename to monticore-grammar/src/main/java/de/monticore/interpreter/values/BooleanMIValue.java index fe04113cbf..f1bea9eae1 100644 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/BooleanValue.java +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/BooleanMIValue.java @@ -1,13 +1,13 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.interpreter.values; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; -public class BooleanValue implements Value { +public class BooleanMIValue implements MIValue { protected boolean value; - public BooleanValue(boolean value){ + public BooleanMIValue(boolean value) { this.value = value; } @@ -16,13 +16,23 @@ public boolean isBoolean() { return true; } + @Override + public boolean isPrimitive() { + return true; + } + @Override public boolean asBoolean() { return value; } @Override - public String asString() { + public String printType() { + return "Boolean"; + } + + @Override + public String printValue() { return String.valueOf(value); } } diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/ByteMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/ByteMIValue.java new file mode 100644 index 0000000000..068a355578 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/ByteMIValue.java @@ -0,0 +1,63 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIValue; + +public class ByteMIValue implements MIValue { + + protected byte value; + + public ByteMIValue(byte value) { + this.value = value; + } + + @Override + public boolean isPrimitive() { + return true; + } + + @Override + public boolean isByte() { + return true; + } + + @Override + public byte asByte() { + return value; + } + + @Override + public short asShort() { + return value; + } + + @Override + public int asInt() { + return value; + } + + @Override + public long asLong() { + return value; + } + + @Override + public float asFloat() { + return value; + } + + @Override + public double asDouble() { + return value; + } + + @Override + public String printType() { + return "Byte"; + } + + @Override + public String printValue() { + return String.valueOf(value); + } + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/CharValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/CharMIValue.java similarity index 62% rename from monticore-runtime/src/main/java/de/monticore/interpreter/values/CharValue.java rename to monticore-grammar/src/main/java/de/monticore/interpreter/values/CharMIValue.java index 120f6a8470..f15c9ff43f 100644 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/CharValue.java +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/CharMIValue.java @@ -1,17 +1,21 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.interpreter.values; -import de.monticore.interpreter.Value; -import de.se_rwth.commons.logging.Log; +import de.monticore.interpreter.MIValue; -public class CharValue implements Value { +public class CharMIValue implements MIValue { protected char value; - public CharValue(char value){ + public CharMIValue(char value) { this.value = value; } + @Override + public boolean isPrimitive() { + return true; + } + @Override public boolean isChar() { return true; @@ -27,11 +31,6 @@ public double asDouble() { return value; } - @Override - public String asString() { - return Character.toString(value); - } - @Override public char asChar() { return value; @@ -47,4 +46,14 @@ public float asFloat() { return value; } + @Override + public String printType() { + return "Char"; + } + + @Override + public String printValue() { + return String.valueOf(value); + } + } diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/DoubleMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/DoubleMIValue.java new file mode 100644 index 0000000000..4be5aff72d --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/DoubleMIValue.java @@ -0,0 +1,39 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIValue; + +public class DoubleMIValue implements MIValue { + + protected double value; + + public DoubleMIValue(double value) { + this.value = value; + } + + @Override + public boolean isPrimitive() { + return true; + } + + @Override + public boolean isDouble() { + return true; + } + + @Override + public double asDouble() { + return value; + } + + @Override + public String printType() { + return "Double"; + } + + @Override + public String printValue() { + return String.valueOf(value); + } + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/FloatValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/FloatMIValue.java similarity index 56% rename from monticore-runtime/src/main/java/de/monticore/interpreter/values/FloatValue.java rename to monticore-grammar/src/main/java/de/monticore/interpreter/values/FloatMIValue.java index 93f3fc783a..2ced7647e9 100644 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/FloatValue.java +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/FloatMIValue.java @@ -1,24 +1,24 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.interpreter.values; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; -public class FloatValue implements Value { +public class FloatMIValue implements MIValue { protected float value; - public FloatValue(float value) { + public FloatMIValue(float value) { this.value = value; } @Override - public boolean isFloat() { + public boolean isPrimitive() { return true; } @Override - public int asInt() { - return (int) value; + public boolean isFloat() { + return true; } @Override @@ -27,17 +27,17 @@ public double asDouble() { } @Override - public String asString() { - return Float.toString(value); + public float asFloat() { + return value; } @Override - public long asLong() { - return (long) value; + public String printType() { + return "Float"; } @Override - public float asFloat() { - return value; + public String printValue() { + return String.valueOf(value) + "f"; } } diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/IntValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/IntMIValue.java similarity index 59% rename from monticore-runtime/src/main/java/de/monticore/interpreter/values/IntValue.java rename to monticore-grammar/src/main/java/de/monticore/interpreter/values/IntMIValue.java index 1bc312aec8..f5a9d1160e 100644 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/IntValue.java +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/IntMIValue.java @@ -1,16 +1,21 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.interpreter.values; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; -public class IntValue implements Value { +public class IntMIValue implements MIValue { protected int value; - public IntValue(int value) { + public IntMIValue(int value) { this.value = value; } + @Override + public boolean isPrimitive() { + return true; + } + @Override public boolean isInt() { return true; @@ -26,11 +31,6 @@ public double asDouble() { return value; } - @Override - public String asString() { - return Integer.toString(value); - } - @Override public long asLong() { return value; @@ -40,4 +40,14 @@ public long asLong() { public float asFloat() { return value; } + + @Override + public String printType() { + return "Integer"; + } + + @Override + public String printValue() { + return String.valueOf(value); + } } diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaAttributeMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaAttributeMIValue.java new file mode 100644 index 0000000000..9e76102afa --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaAttributeMIValue.java @@ -0,0 +1,70 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.InterpreterUtils; +import de.monticore.interpreter.MIValue; +import de.se_rwth.commons.logging.Log; + +import java.lang.reflect.Field; +import java.util.Optional; + +public class JavaAttributeMIValue extends WriteableMIValue { + + /** + * if null, this represents a static attribute; + * concept taken from Java Reflection API + */ + Object obj; + + Field attribute; + + Optional innerValue = Optional.empty(); + + public JavaAttributeMIValue(Optional obj, Field attribute) { + this.obj = obj.orElse(null); + this.attribute = attribute; + } + + @Override + public void write(MIValue value) { + try { + attribute.set(obj, InterpreterUtils.valueToObject(value)); + innerValue = Optional.of(value); + } + catch (IllegalAccessException e) { + String errorMsg = "0x57094 Failed to assign value " + + value.printType() + "(" + value.printValue() + ")" + + " to attribute '" + attribute.getName() + "'" + + " of class '" + attribute.getDeclaringClass().getName() + "'."; + Log.error(errorMsg); + } + } + + @Override + public MIValue getMIValue() { + if (!innerValue.isPresent()) { + try { + innerValue = Optional.of( + InterpreterUtils.objectToValue(attribute.get(obj))); + } + catch (IllegalAccessException e) { + String errorMsg = "0x57093 Failed to access attribute '" + + attribute.getName() + "' of class '" + + attribute.getDeclaringClass().getName() + "'."; + Log.error(errorMsg); + innerValue = Optional.of(new ErrorMIValue(errorMsg)); + } + } + + return innerValue.get(); + } + + @Override + public String printType() { + return "Java-Field"; + } + + @Override + public String printValue() { + return getMIValue().printType() + " (" + getMIValue().printValue() + ")"; + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaNonStaticMethodMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaNonStaticMethodMIValue.java new file mode 100644 index 0000000000..511580ab73 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaNonStaticMethodMIValue.java @@ -0,0 +1,81 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.IModelInterpreter; +import de.monticore.interpreter.InterpreterUtils; +import de.monticore.interpreter.MIValue; +import de.se_rwth.commons.logging.Log; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.stream.Collectors; + +// TODO change to getting method by SymType +public class JavaNonStaticMethodMIValue implements FunctionMIValue { + + Object object; + String methodName; + + public JavaNonStaticMethodMIValue(Object object, String methodName) { + this.object = object; + this.methodName = methodName; + } + + @Override + public MIValue execute(IModelInterpreter interpreter, List arguments) { + List> argumentTypes = arguments.stream() + .map(InterpreterUtils::typeOfValue) + .collect(Collectors.toList()); + + Method method; + try { + method = object.getClass().getDeclaredMethod(methodName, argumentTypes.toArray(new Class[0])); + } + catch (NoSuchMethodException e) { + StringBuilder sb = new StringBuilder(); + sb.append("0x57059 Failed to find method '") + .append(methodName) + .append("' in class '") + .append(object.getClass().getName()) + .append("' with arguments of type ("); + for (int i = 0; i < argumentTypes.size(); i++) { + sb.append(argumentTypes.get(i).toString()); + if (i < argumentTypes.size() - 1) { + sb.append(", "); + } + } + sb.append(")."); + Log.error(sb.toString()); + return new ErrorMIValue(sb.toString()); + } + + Object[] argumentObjects = arguments.stream().map(InterpreterUtils::valueToObject).toArray(); + + Object returnObject; + try { + returnObject = method.invoke(object, argumentObjects); + } + catch (IllegalAccessException e) { + String errorMsg = e.getMessage(); + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + catch (InvocationTargetException e) { + String errorMsg = e.getMessage(); + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + return InterpreterUtils.objectToValue(returnObject); + } + + @Override + public String printType() { + return "Java-Method"; + } + + @Override + public String printValue() { + return object.getClass().getName() + "." + methodName; + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaStaticMethodMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaStaticMethodMIValue.java new file mode 100644 index 0000000000..e013f8b472 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/JavaStaticMethodMIValue.java @@ -0,0 +1,79 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.IModelInterpreter; +import de.monticore.interpreter.InterpreterUtils; +import de.monticore.interpreter.MIValue; +import de.se_rwth.commons.logging.Log; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.stream.Collectors; + +// TODO change to getting method by SymType +public class JavaStaticMethodMIValue implements FunctionMIValue { + + Class classType; + String functionName; + + public JavaStaticMethodMIValue(Class classType, String methodName) { + this.classType = classType; + this.functionName = methodName; + } + + @Override + public MIValue execute(IModelInterpreter interpreter, List arguments) { + List> argumentTypes = arguments.stream() + .map(InterpreterUtils::typeOfValue) + .collect(Collectors.toList()); + + Method function; + try { + function = classType.getDeclaredMethod(functionName, argumentTypes.toArray(new Class[0])); + } + catch (NoSuchMethodException e) { + StringBuilder sb = new StringBuilder(); + sb.append("0x57058 Failed to find static function '") + .append(functionName) + .append("' in class '") + .append(classType.getName()) + .append("' with arguments of type ("); + for (int i = 0; i < argumentTypes.size(); i++) { + sb.append(argumentTypes.get(i).toString()); + if (i < argumentTypes.size() - 1) { + sb.append(", "); + } + } + sb.append(")."); + Log.error(sb.toString()); + return new ErrorMIValue(sb.toString()); + } + + Object[] argumentObjects = arguments.stream().map(InterpreterUtils::valueToObject).toArray(); + + Object returnObject; + try { + returnObject = function.invoke(null, argumentObjects); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + catch (InvocationTargetException e) { + String errorMsg = e.getMessage(); + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + return InterpreterUtils.objectToValue(returnObject); + } + + @Override + public String printType() { + return "Java-Function"; + } + + @Override + public String printValue() { + return classType.getName() + "." + functionName; + } +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/LongValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/LongMIValue.java similarity index 58% rename from monticore-runtime/src/main/java/de/monticore/interpreter/values/LongValue.java rename to monticore-grammar/src/main/java/de/monticore/interpreter/values/LongMIValue.java index 1876f67a89..875ec87b36 100644 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/LongValue.java +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/LongMIValue.java @@ -1,24 +1,24 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.interpreter.values; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; -public class LongValue implements Value { +public class LongMIValue implements MIValue { protected long value; - public LongValue(long value) { + public LongMIValue(long value) { this.value = value; } @Override - public boolean isLong() { + public boolean isPrimitive() { return true; } @Override - public int asInt() { - return (int) value; + public boolean isLong() { + return true; } @Override @@ -26,11 +26,6 @@ public double asDouble() { return value; } - @Override - public String asString() { - return Long.toString(value); - } - @Override public long asLong() { return value; @@ -40,4 +35,14 @@ public long asLong() { public float asFloat() { return value; } + + @Override + public String printType() { + return "Long"; + } + + @Override + public String printValue() { + return String.valueOf(value) + "L"; + } } diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/ModelFunctionMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/ModelFunctionMIValue.java new file mode 100644 index 0000000000..9eff449deb --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/ModelFunctionMIValue.java @@ -0,0 +1,59 @@ +package de.monticore.interpreter.values; + +import de.monticore.ast.ASTNode; +import de.monticore.interpreter.IModelInterpreter; +import de.monticore.interpreter.InterpreterUtils; +import de.monticore.interpreter.MIScope; +import de.monticore.interpreter.MIValue; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.types.check.SymTypeExpression; + +import java.util.List; +import java.util.Optional; + +public class ModelFunctionMIValue implements FunctionMIValue { + + protected MIScope parentScope; + protected List parameterSymbols; + protected ASTNode body; + + public ModelFunctionMIValue(MIScope parentScope, List parameterSymbols, ASTNode body) { + this.parentScope = parentScope; + this.parameterSymbols = parameterSymbols; + this.body = body; + } + + @Override + public MIValue execute(IModelInterpreter interpreter, List arguments) { + MIScope newScope = new MIScope(parentScope); + + for (int i = 0; i < parameterSymbols.size(); i++) { + VariableSymbol parameterSymbol = parameterSymbols.get(i); + SymTypeExpression paramType = parameterSymbol.getType(); + + MIValue argument = arguments.get(i); + argument = InterpreterUtils.convertImplicit(paramType, argument); + if (argument.isError()) + return argument; + + newScope.declareVariable(parameterSymbol, Optional.of(argument)); + } + + interpreter.pushScope(newScope); + MIValue result = body.evaluate(interpreter); + interpreter.popScope(); + + return result; + } + + @Override + public String printType() { + return "Model-Function"; + } + + @Override + public String printValue() { + return "implemenation(" + body.get_SourcePositionStart().toString() + ")"; + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/ObjectMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/ObjectMIValue.java new file mode 100644 index 0000000000..156764ce6b --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/ObjectMIValue.java @@ -0,0 +1,36 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIValue; + +public class ObjectMIValue implements MIValue { + + protected Object value; + + public ObjectMIValue(Object value) { + this.value = value; + } + + @Override + public boolean isObject() { + return true; + } + + @Override + public Object asObject() { + return value; + } + + @Override + public String printType() { + String typeStr = value != null + ? value.getClass().getTypeName() + : "null"; + return "Object(" + typeStr + ")"; + } + + @Override + public String printValue() { + return String.valueOf(value); + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/ShortMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/ShortMIValue.java new file mode 100644 index 0000000000..3848937484 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/ShortMIValue.java @@ -0,0 +1,58 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIValue; + +public class ShortMIValue implements MIValue { + + protected short value; + + public ShortMIValue(short value) { + this.value = value; + } + + @Override + public boolean isPrimitive() { + return true; + } + + @Override + public boolean isShort() { + return true; + } + + @Override + public short asShort() { + return value; + } + + @Override + public int asInt() { + return value; + } + + @Override + public long asLong() { + return value; + } + + @Override + public float asFloat() { + return value; + } + + @Override + public double asDouble() { + return value; + } + + @Override + public String printType() { + return "short"; + } + + @Override + public String printValue() { + return String.valueOf(value); + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/VariableMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/VariableMIValue.java new file mode 100644 index 0000000000..0fc640fe78 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/VariableMIValue.java @@ -0,0 +1,45 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIScope; +import de.monticore.interpreter.MIValue; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; + +import java.util.Optional; + +public class VariableMIValue extends WriteableMIValue { + + protected MIScope scope; + protected VariableSymbol symbol; + + protected Optional innerValue = Optional.empty(); + + public VariableMIValue(MIScope scope, VariableSymbol symbol) { + this.scope = scope; + this.symbol = symbol; + } + + @Override + public void write(MIValue value) { + scope.storeVariable(symbol, value); + innerValue = Optional.of(value); + } + + @Override + public MIValue getMIValue() { + if (!innerValue.isPresent()) { + innerValue = Optional.of(scope.loadVariable(symbol)); + } + + return innerValue.get(); + } + + @Override + public String printType() { + return "Variable"; + } + + @Override + public String printValue() { + return getMIValue().printType() + " (" + getMIValue().printValue() + ")"; + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/interpreter/values/WriteableMIValue.java b/monticore-grammar/src/main/java/de/monticore/interpreter/values/WriteableMIValue.java new file mode 100644 index 0000000000..ef462f491d --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/interpreter/values/WriteableMIValue.java @@ -0,0 +1,167 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIValue; + +public abstract class WriteableMIValue implements MIValue { + + @Override + public boolean isWriteable() { + return true; + } + + public abstract void write(MIValue value); + + public abstract MIValue getMIValue(); + + @Override + public boolean isPrimitive() { + + return getMIValue().isPrimitive(); + } + + @Override + public boolean isBoolean() { + return getMIValue().isBoolean(); + } + + @Override + public boolean isByte() { + return getMIValue().isByte(); + } + + @Override + public boolean isChar() { + return getMIValue().isChar(); + } + + @Override + public boolean isShort() { + return getMIValue().isShort(); + } + + @Override + public boolean isInt() { + return getMIValue().isInt(); + } + + @Override + public boolean isLong() { + return getMIValue().isLong(); + } + + @Override + public boolean isFloat() { + return getMIValue().isFloat(); + } + + @Override + public boolean isDouble() { + return getMIValue().isDouble(); + } + + @Override + public boolean isObject() { + return getMIValue().isObject(); + } + + @Override + public boolean isFunction() { + return getMIValue().isFunction(); + } + + @Override + public boolean isVoid() { + return getMIValue().isVoid(); + } + + @Override + public boolean isSIUnit() { + return getMIValue().isSIUnit(); + } + + @Override + public boolean isFlowControlSignal() { + return getMIValue().isFlowControlSignal(); + } + + @Override + public boolean isError() { + return getMIValue().isError(); + } + + @Override + public boolean isBreak() { + return getMIValue().isBreak(); + } + + @Override + public boolean isContinue() { + return getMIValue().isContinue(); + } + + @Override + public boolean isReturn() { + return getMIValue().isReturn(); + } + + @Override + public boolean asBoolean() { + return getMIValue().asBoolean(); + } + + @Override + public byte asByte() { + return getMIValue().asByte(); + } + + @Override + public char asChar() { + return getMIValue().asChar(); + } + + @Override + public short asShort() { + return getMIValue().asShort(); + } + + @Override + public int asInt() { + return getMIValue().asInt(); + } + + @Override + public long asLong() { + return getMIValue().asLong(); + } + + @Override + public float asFloat() { + return getMIValue().asFloat(); + } + + @Override + public double asDouble() { + return getMIValue().asDouble(); + } + + @Override + public FunctionMIValue asFunction() { + return getMIValue().asFunction(); + } + + @Override + public Object asObject() { + return getMIValue().asObject(); + } + + @Override + public MIValue asReturnValue() { + return getMIValue().asReturnValue(); + } + + @Override + public String asError() { + return getMIValue().asError(); + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/literals/mccommonliterals/_visitor/MCCommonLiteralsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/literals/mccommonliterals/_visitor/MCCommonLiteralsInterpreter.java index e96fa4d954..b049567759 100644 --- a/monticore-grammar/src/main/java/de/monticore/literals/mccommonliterals/_visitor/MCCommonLiteralsInterpreter.java +++ b/monticore-grammar/src/main/java/de/monticore/literals/mccommonliterals/_visitor/MCCommonLiteralsInterpreter.java @@ -2,9 +2,12 @@ package de.monticore.literals.mccommonliterals._visitor; import de.monticore.interpreter.ModelInterpreter; -import de.monticore.interpreter.Value; -import de.monticore.interpreter.ValueFactory; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.values.ErrorMIValue; import de.monticore.literals.mccommonliterals._ast.*; +import de.se_rwth.commons.logging.Log; + +import static de.monticore.interpreter.MIValueFactory.createValue; public class MCCommonLiteralsInterpreter extends MCCommonLiteralsInterpreterTOP { @@ -17,63 +20,58 @@ public MCCommonLiteralsInterpreter(ModelInterpreter realThis) { } @Override - public Value interpret(ASTNullLiteral node){ - return ValueFactory.createValue(null); - } - - @Override - public Value interpret(ASTBooleanLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTBooleanLiteral node){ + return createValue(node.getValue()); } @Override - public Value interpret(ASTCharLiteral node) { - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTCharLiteral node) { + return createValue(node.getValue()); } @Override - public Value interpret(ASTStringLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTStringLiteral node){ + return createValue(node.getValue()); } @Override - public Value interpret(ASTNatLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTNatLiteral node){ + return createValue(node.getValue()); } @Override - public Value interpret(ASTSignedNatLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTSignedNatLiteral node){ + return createValue(node.getValue()); } @Override - public Value interpret(ASTBasicLongLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTBasicLongLiteral node){ + return createValue(node.getValue()); } @Override - public Value interpret(ASTSignedBasicLongLiteral node) { - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTSignedBasicLongLiteral node) { + return createValue(node.getValue()); } @Override - public Value interpret(ASTBasicFloatLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTBasicFloatLiteral node){ + return createValue(node.getValue()); } @Override - public Value interpret(ASTSignedBasicFloatLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTSignedBasicFloatLiteral node){ + return createValue(node.getValue()); } @Override - public Value interpret(ASTBasicDoubleLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTBasicDoubleLiteral node){ + return createValue(node.getValue()); } @Override - public Value interpret(ASTSignedBasicDoubleLiteral node){ - return ValueFactory.createValue(node.getValue()); + public MIValue interpret(ASTSignedBasicDoubleLiteral node){ + return createValue(node.getValue()); } diff --git a/monticore-grammar/src/main/java/de/monticore/literals/mcjavaliterals/_visitor/MCJavaLiteralsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/literals/mcjavaliterals/_visitor/MCJavaLiteralsInterpreter.java index c50c29ad11..99b5794185 100644 --- a/monticore-grammar/src/main/java/de/monticore/literals/mcjavaliterals/_visitor/MCJavaLiteralsInterpreter.java +++ b/monticore-grammar/src/main/java/de/monticore/literals/mcjavaliterals/_visitor/MCJavaLiteralsInterpreter.java @@ -2,10 +2,10 @@ package de.monticore.literals.mcjavaliterals._visitor; import de.monticore.interpreter.ModelInterpreter; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.literals.mcjavaliterals._ast.*; -import static de.monticore.interpreter.ValueFactory.createValue; +import static de.monticore.interpreter.MIValueFactory.createValue; public class MCJavaLiteralsInterpreter extends MCJavaLiteralsInterpreterTOP { @@ -18,22 +18,22 @@ public MCJavaLiteralsInterpreter(ModelInterpreter realThis) { } @Override - public Value interpret(ASTIntLiteral node) { + public MIValue interpret(ASTIntLiteral node) { return createValue(node.getValue()); } @Override - public Value interpret(ASTLongLiteral node) { + public MIValue interpret(ASTLongLiteral node) { return createValue(node.getValue()); } @Override - public Value interpret(ASTFloatLiteral node) { + public MIValue interpret(ASTFloatLiteral node) { return createValue(node.getValue()); } @Override - public Value interpret(ASTDoubleLiteral node) { + public MIValue interpret(ASTDoubleLiteral node) { return createValue(node.getValue()); } } diff --git a/monticore-grammar/src/main/java/de/monticore/ocl/oclexpressions/_visitor/OCLExpressionsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/ocl/oclexpressions/_visitor/OCLExpressionsInterpreter.java new file mode 100644 index 0000000000..90247bbfc0 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/ocl/oclexpressions/_visitor/OCLExpressionsInterpreter.java @@ -0,0 +1,41 @@ +package de.monticore.ocl.oclexpressions._visitor; + +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.ocl.oclexpressions._ast.ASTIfThenElseExpression; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.logging.Log; + +public class OCLExpressionsInterpreter extends OCLExpressionsInterpreterTOP { + + public OCLExpressionsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + public OCLExpressionsInterpreter() { + super(); + } + + @Override + public MIValue interpret(ASTIfThenElseExpression expr) { + SymTypeExpression condType = TypeCheck3.typeOf(expr.getCondition()); + if (!(condType.isPrimitive() && condType.asPrimitive().getPrimitiveName().equals(BasicSymbolsMill.BOOLEAN))) { + String errorMsg = "0x57074 The condition of the IfThenElseExpression was expected to be a boolean but was a " + condType.print() + "."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + MIValue conditionValue = expr.getCondition().evaluate(getRealThis()); + if (conditionValue.isFlowControlSignal()) return conditionValue; + + if (conditionValue.asBoolean()) { + return expr.getThenExpression().evaluate(getRealThis()); + } else { + return expr.getElseExpression().evaluate(getRealThis()); + } + } + +} diff --git a/monticore-grammar/src/main/java/de/monticore/ocl/setexpressions/_visitor/SetExpressionsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/ocl/setexpressions/_visitor/SetExpressionsInterpreter.java new file mode 100644 index 0000000000..3f56e8bac9 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/ocl/setexpressions/_visitor/SetExpressionsInterpreter.java @@ -0,0 +1,180 @@ +package de.monticore.ocl.setexpressions._visitor; + +import de.monticore.interpreter.*; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.VoidMIValue; +import de.monticore.ocl.setexpressions._ast.*; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.logging.Log; + +import java.util.*; + +public class SetExpressionsInterpreter extends SetExpressionsInterpreterTOP { + + public SetExpressionsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + public SetExpressionsInterpreter() { + super(); + } + + @Override + public MIValue interpret(ASTSetValueItem node) { + return node.getExpression().evaluate(getRealThis()); + } + + @Override + public MIValue interpret(ASTSetValueRange node) { + MIValue lowerValue = node.getLowerBound().evaluate(getRealThis()); + MIValue upperValue = node.getUpperBound().evaluate(getRealThis()); + SymTypeExpression lowerType = TypeCheck3.typeOf(node.getLowerBound()); + SymTypeExpression upperType = TypeCheck3.typeOf(node.getUpperBound()); + Optional rangeType = SymTypeRelations.leastUpperBound(lowerType, upperType); + if (rangeType.isEmpty() || rangeType.get().isObscureType() + || !rangeType.get().isPrimitive() || !rangeType.get().asPrimitive().isIntegralType()) { + String errorMsg = "0x57076 Failed to get common type of SetValueRange."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + List values = new ArrayList<>(); + for (long l = lowerValue.asLong(); l <= upperValue.asLong(); l++) { + values.add(InterpreterUtils.convertToPrimitiveExplicit(BasicSymbolsMill.LONG, + rangeType.get().asPrimitive().getPrimitiveName(), MIValueFactory.createValue(l))); + } + + return MIValueFactory.createValue(values); + } + + @Override + public MIValue interpret(ASTSetEnumeration node) { + Collection result; + if (node.isList()) { + result = new ArrayList<>(); + } else { + result = new HashSet<>(); + } + + for (ASTSetCollectionItem setItem : node.getSetCollectionItemList()) { + MIValue element = setItem.evaluate(getRealThis()); + if (setItem instanceof ASTSetValueItem) { + result.add(InterpreterUtils.valueToObject(element)); + } else if (setItem instanceof ASTSetValueRange){ + for (MIValue value : (Collection)element.asObject()) { + result.add(InterpreterUtils.valueToObject(value)); + } + } + } + return MIValueFactory.createValue(result); + } + + @Override + public MIValue interpret(ASTGeneratorDeclaration node) { + String errorMsg = "0x57080 ASTGeneratorDeclaration should not be evaluated directly."; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + @Override + public MIValue interpret(ASTSetVariableDeclaration node) { + MIValue value = node.getExpression().evaluate(getRealThis()); + if (value.isFlowControlSignal()) return value; + + // should already be declared at start of SetComprehension + storeVariable(node.getSymbol(), value); + return new VoidMIValue(); + } + + private MIValue evaluateSetComprehensionItems(ASTSetComprehension node, int idx, Collection results) { + if (idx >= node.getSetComprehensionItemList().size()) { + MIValue result = node.getLeft().evaluate(getRealThis()); + if (result.isFlowControlSignal()) return result; + results.add(InterpreterUtils.valueToObject(result)); + return new VoidMIValue(); + } + ASTSetComprehensionItem item = node.getSetComprehensionItemList().get(idx); + if (item.isPresentGeneratorDeclaration()) { + ASTGeneratorDeclaration generatorDeclaration = item.getGeneratorDeclaration(); + MIValue collection = generatorDeclaration.getExpression().evaluate(getRealThis()); + if (collection.isFlowControlSignal()) return collection; + + Collection values = (Collection)collection.asObject(); + for (Object obj : values) { + storeVariable(generatorDeclaration.getSymbol(), + InterpreterUtils.objectToValue(obj)); + MIValue result = evaluateSetComprehensionItems(node, idx + 1, results); + if (result.isFlowControlSignal()) return result; + } + return MIValueFactory.createValue(results); + + } else if (item.isPresentExpression()) { + MIValue filterValue = item.getExpression().evaluate(getRealThis()); + if (filterValue.isFlowControlSignal()) return filterValue; + if (!filterValue.isBoolean()) { + String errorMsg = "0x57078 SetComprehensionItem of type Expression should return a Boolean. Got " + + filterValue.printType() + " (" + filterValue.printValue() + ")."; + Log.error(errorMsg, item.getExpression().get_SourcePositionStart(), item.getExpression().get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + if (!filterValue.asBoolean()) { + return new VoidMIValue(); + } + return evaluateSetComprehensionItems(node, idx+1, results); + + } else if (item.isPresentSetVariableDeclaration()) { + item.getSetVariableDeclaration().evaluate(getRealThis()); + return evaluateSetComprehensionItems(node, idx+1, results); + } + + String errorMsg = "0x57079 Encountered unexpected type of SetComprehensionItem."; + Log.error(errorMsg, item.get_SourcePositionStart(), item.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + @Override + public MIValue interpret(ASTSetComprehension node) { + Collection results; + if (node.isList()) { + results = new ArrayList<>(); + } else { + results = new HashSet<>(); + } + + MIScope scope = new MIScope(getRealThis().getCurrentScope()); + pushScope(scope); + for (ASTSetComprehensionItem item : node.getSetComprehensionItemList()) { + if (item.isPresentSetVariableDeclaration()) { + ASTSetVariableDeclaration variableDeclaration = item.getSetVariableDeclaration(); + declareVariable(variableDeclaration.getSymbol(), Optional.empty()); + } else if (item.isPresentGeneratorDeclaration()) { + ASTGeneratorDeclaration generatorDeclaration = item.getGeneratorDeclaration(); + declareVariable(generatorDeclaration.getSymbol(), Optional.empty()); + } + } + MIValue result = evaluateSetComprehensionItems(node, 0, results); + popScope(); + if (result.isFlowControlSignal()) return result; + return MIValueFactory.createValue(results); + } + + @Override + public MIValue interpret(ASTSetComprehensionItem node) { + if (node.isPresentExpression()) { + return node.getExpression().evaluate(getRealThis()); + } else if (node.isPresentSetVariableDeclaration()) { + ASTSetVariableDeclaration variableDeclaration = node.getSetVariableDeclaration(); + MIValue value = variableDeclaration.getExpression().evaluate(getRealThis()); + if (value.isFlowControlSignal()) return value; + getRealThis().declareVariable(variableDeclaration.getSymbol(), Optional.of(value)); + return new VoidMIValue(); + } + + String errorMsg = "0x57077 Unexpected type of ASTSetComprehensionItem"; + Log.error(errorMsg, node.get_SourcePositionStart(), node.get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/statements/mccommonstatements/_visitor/MCCommonStatementsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/statements/mccommonstatements/_visitor/MCCommonStatementsInterpreter.java new file mode 100644 index 0000000000..fdbb164b78 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/statements/mccommonstatements/_visitor/MCCommonStatementsInterpreter.java @@ -0,0 +1,247 @@ +package de.monticore.statements.mccommonstatements._visitor; + +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.interpreter.MIScope; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.MIValueFactory; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.iterators.MICommonForIterator; +import de.monticore.interpreter.iterators.MIForEachIterator; +import de.monticore.interpreter.iterators.MIForIterator; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.MIBreakSignal; +import de.monticore.interpreter.values.VoidMIValue; +import de.monticore.statements.mccommonstatements._ast.ASTBreakStatement; +import de.monticore.statements.mccommonstatements._ast.ASTCommonForControl; +import de.monticore.statements.mccommonstatements._ast.ASTDoWhileStatement; +import de.monticore.statements.mccommonstatements._ast.ASTEmptyStatement; +import de.monticore.statements.mccommonstatements._ast.ASTEnhancedForControl; +import de.monticore.statements.mccommonstatements._ast.ASTExpressionStatement; +import de.monticore.statements.mccommonstatements._ast.ASTForInit; +import de.monticore.statements.mccommonstatements._ast.ASTForInitByExpressions; +import de.monticore.statements.mccommonstatements._ast.ASTForStatement; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mccommonstatements._ast.ASTIfStatement; +import de.monticore.statements.mccommonstatements._ast.ASTMCJavaBlock; +import de.monticore.statements.mccommonstatements._ast.ASTWhileStatement; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCBlockStatement; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.se_rwth.commons.logging.Log; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +public class MCCommonStatementsInterpreter extends MCCommonStatementsInterpreterTOP { + + public MCCommonStatementsInterpreter() { + super(); + } + + public MCCommonStatementsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + @Override + public MIValue interpret(ASTMCJavaBlock node) { + MIScope scope = new MIScope(getRealThis().getCurrentScope()); + pushScope(scope); + + for (ASTMCBlockStatement statement : node.getMCBlockStatementList()) { + MIValue result = statement.evaluate(getRealThis()); + if (result.isFlowControlSignal()) { + popScope(); + return result; + } + } + + popScope(); + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTIfStatement node) { + MIValue condition = node.getCondition().evaluate(getRealThis()); + if (condition.isFlowControlSignal()) + return condition; + + if (condition.asBoolean()) { + MIValue result = node.getThenStatement().evaluate(getRealThis()); + if (result.isFlowControlSignal()) + return result; + } + else if (node.isPresentElseStatement()) { + MIValue result = node.getElseStatement().evaluate(getRealThis()); + if (result.isFlowControlSignal()) + return result; + } + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTWhileStatement node) { + MIScope scope = new MIScope(getRealThis().getCurrentScope()); + pushScope(scope); + + MIValue condition = node.getCondition().evaluate(getRealThis()); + while (condition.isBoolean() && condition.asBoolean()) { + MIValue result = node.getMCStatement().evaluate(getRealThis()); + if (result.isBreak()) + break; + if (result.isContinue()) + continue; + if (result.isFlowControlSignal()) { + popScope(); + return result; + } + + condition = node.getCondition().evaluate(getRealThis()); + } + + popScope(); + if (!condition.isBoolean()) { + String errorMsg = "0x57009 While condition must be of type boolean. Got " + condition.printType() + + " (" + condition.printValue() + ")."; + Log.error(errorMsg, node.getCondition().get_SourcePositionStart(), node.getCondition().get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + else if (condition.isFlowControlSignal()) { + return condition; + } + else { + return new VoidMIValue(); + } + } + + @Override + public MIValue interpret(ASTDoWhileStatement node) { + MIScope scope = new MIScope(getRealThis().getCurrentScope()); + pushScope(scope); + + MIValue condition = MIValueFactory.createValue(true); + while (condition.isBoolean() && condition.asBoolean()) { + MIValue result = node.getMCStatement().evaluate(getRealThis()); + if (result.isBreak()) + break; + if (result.isContinue()) + continue; + if (result.isFlowControlSignal()) { + popScope(); + return result; + } + + condition = node.getCondition().evaluate(getRealThis()); + } + + popScope(); + if (!condition.isBoolean()) { + String errorMsg = "0x57009 While condition must be of type boolean. Got " + condition.printType() + + " (" + condition.printValue() + ")."; + Log.error(errorMsg, node.getCondition().get_SourcePositionStart(), node.getCondition().get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + else if (condition.isFlowControlSignal()) { + return condition; + } + else { + return new VoidMIValue(); + } + } + + @Override + public MIValue interpret(ASTEmptyStatement node) { + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTExpressionStatement node) { + MIValue result = node.getExpression().evaluate(getRealThis()); + if (result.isFlowControlSignal()) + return result; + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTForStatement node) { + MIScope scope = new MIScope(getRealThis().getCurrentScope()); + pushScope(scope); + + MIValue control = node.getForControl().evaluate(getRealThis()); + if (control.isFlowControlSignal()) { + popScope(); + return control; + } + + MIForIterator controlIterator = (MIForIterator) control.asObject(); + + MIValue result = controlIterator.execute(getRealThis(), node.getMCStatement()); + popScope(); + return result.isFlowControlSignal() ? result : new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTCommonForControl node) { + Optional initNode = node.isPresentForInit() ? Optional.of(node.getForInit()) : Optional.empty(); + Optional condition = node.isPresentCondition() ? Optional.of(node.getCondition()) : Optional.empty(); + List expressions = node.getExpressionList(); + MICommonForIterator iterator = new MICommonForIterator(initNode, condition, expressions); + return MIValueFactory.createValue(iterator); + } + + @Override + public MIValue interpret(ASTForInit node) { + if (node.isPresentForInitByExpressions()) { + return node.getForInitByExpressions().evaluate(getRealThis()); + } + else if (node.isPresentLocalVariableDeclaration()) { + return node.getLocalVariableDeclaration().evaluate(getRealThis()); + } + + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTForInitByExpressions node) { + for (ASTExpression expression : node.getExpressionList()) { + MIValue result = expression.evaluate(getRealThis()); + if (result.isFlowControlSignal()) + return result; + } + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTEnhancedForControl node) { + MIValue collectionValue = node.getExpression().evaluate(getRealThis()); + if (collectionValue.isFlowControlSignal()) + return collectionValue; + + if (!(collectionValue.asObject() instanceof Collection)) { + String errorMsg = "0x57082 Expected a collection in for-each loop. Got " + collectionValue.printType() + + " (" + collectionValue.printValue() + ")."; + Log.error(errorMsg, node.getExpression().get_SourcePositionStart(), node.getExpression().get_SourcePositionEnd()); + return new ErrorMIValue(errorMsg); + } + + Collection collection = (Collection) (collectionValue.asObject()); + VariableSymbol symbol = node.getFormalParameter().getDeclarator().getSymbol(); + MIForIterator iterator = new MIForEachIterator(symbol, collection.iterator()); + return MIValueFactory.createValue(iterator); + } + + @Override + public MIValue interpret(ASTFormalParameter node) { + MIValue result = node.getDeclarator().evaluate(getRealThis()); + if (result.isFlowControlSignal()) { + return result; + } + else { + return new VoidMIValue(); + } + } + + @Override + public MIValue interpret(ASTBreakStatement node) { + return new MIBreakSignal(); + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/statements/mclowlevelstatements/_visitor/MCLowLevelStatementsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/statements/mclowlevelstatements/_visitor/MCLowLevelStatementsInterpreter.java new file mode 100644 index 0000000000..3b752f11af --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/statements/mclowlevelstatements/_visitor/MCLowLevelStatementsInterpreter.java @@ -0,0 +1,28 @@ +package de.monticore.statements.mclowlevelstatements._visitor; + +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.MIContinueSignal; +import de.monticore.statements.mclowlevelstatements._ast.ASTContinueStatement; +import de.se_rwth.commons.logging.Log; + +public class MCLowLevelStatementsInterpreter extends MCLowLevelStatementsInterpreterTOP { + + public MCLowLevelStatementsInterpreter() {} + + public MCLowLevelStatementsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + @Override + public MIValue interpret(ASTContinueStatement node) { + if (node.isPresentLabel()) { + String errorMsg = "0x57085 Labels are not supported for Continue Statements."; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + return new MIContinueSignal(); + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/statements/mcreturnstatements/_visitor/MCReturnStatementsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/statements/mcreturnstatements/_visitor/MCReturnStatementsInterpreter.java new file mode 100644 index 0000000000..6355e58201 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/statements/mcreturnstatements/_visitor/MCReturnStatementsInterpreter.java @@ -0,0 +1,27 @@ +package de.monticore.statements.mcreturnstatements._visitor; + +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.values.MIReturnSignal; +import de.monticore.statements.mcreturnstatements._ast.ASTReturnStatement; + +public class MCReturnStatementsInterpreter extends MCReturnStatementsInterpreterTOP { + + public MCReturnStatementsInterpreter() {} + + public MCReturnStatementsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + @Override + public MIValue interpret(ASTReturnStatement node) { + if (node.isPresentExpression()) { + MIValue returnValue = node.getExpression().evaluate(getRealThis()); + if (returnValue.isFlowControlSignal()) return returnValue; + + return new MIReturnSignal(returnValue); + } else { + return new MIReturnSignal(); + } + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/statements/mcvardeclarationstatements/_visitor/MCVarDeclarationStatementsInterpreter.java b/monticore-grammar/src/main/java/de/monticore/statements/mcvardeclarationstatements/_visitor/MCVarDeclarationStatementsInterpreter.java new file mode 100644 index 0000000000..8d3a64c8c3 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/statements/mcvardeclarationstatements/_visitor/MCVarDeclarationStatementsInterpreter.java @@ -0,0 +1,50 @@ +package de.monticore.statements.mcvardeclarationstatements._visitor; + +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.interpreter.values.VoidMIValue; +import de.monticore.statements.mcvardeclarationstatements._ast.*; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; + +import java.util.Optional; + +public class MCVarDeclarationStatementsInterpreter extends MCVarDeclarationStatementsInterpreterTOP { + + public MCVarDeclarationStatementsInterpreter() {} + + public MCVarDeclarationStatementsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + @Override + public MIValue interpret(ASTLocalVariableDeclarationStatement node) { + MIValue result = node.getLocalVariableDeclaration().evaluate(getRealThis()); + if (result.isError()) return result; + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTLocalVariableDeclaration node) { + for (ASTVariableDeclarator declarator : node.getVariableDeclaratorList()) { + MIValue result = declarator.evaluate(getRealThis()); + if (result.isError()) return result; + } + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTVariableDeclarator node) { + VariableSymbol symbol = node.getDeclarator().getSymbol(); + if (node.isPresentVariableInit()) { + MIValue initialValue = node.getVariableInit().evaluate(getRealThis()); + if (initialValue.isError()) return initialValue; + getRealThis().declareVariable(symbol, Optional.of(initialValue)); + } + return new VoidMIValue(); + } + + @Override + public MIValue interpret(ASTSimpleInit node) { + return node.getExpression().evaluate(getRealThis()); + } +} diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/BasicSymbolsStereoinfoDeSer.java b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/BasicSymbolsStereoinfoDeSer.java index 4e0a99dea7..630dc88d7d 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/BasicSymbolsStereoinfoDeSer.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/BasicSymbolsStereoinfoDeSer.java @@ -1,7 +1,7 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.symbols.basicsymbols._symboltable; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.symboltable.IScope; import de.monticore.symboltable.serialization.json.JsonElement; import de.monticore.symboltable.stereotypes.IStereotypeReference; @@ -22,7 +22,7 @@ public static void init() { } @Override - protected Map.Entry> doDeserialize(JsonElement json, + protected Map.Entry> doDeserialize(JsonElement json, IScope enclosingScope) { if (json.getAsJsonObject().hasMember(STEREO_VALUE)) { Log.errorInternal( diff --git a/monticore-grammar/src/test/grammars/de/monticore/statements/CombineStatementsWithExpressions.mc4 b/monticore-grammar/src/test/grammars/de/monticore/statements/CombineStatementsWithExpressions.mc4 new file mode 100644 index 0000000000..a8b17a13e9 --- /dev/null +++ b/monticore-grammar/src/test/grammars/de/monticore/statements/CombineStatementsWithExpressions.mc4 @@ -0,0 +1,13 @@ +/* (c) https://github.com/MontiCore/monticore */ + +package de.monticore.statements; + +grammar CombineStatementsWithExpressions + extends MCCommonStatements, + MCReturnStatements, + MCLowLevelStatements, + de.monticore.expressions.CombineExpressionsWithLiterals { + + start MCBlockStatement; + +} \ No newline at end of file diff --git a/monticore-grammar/src/test/java/de/monticore/AbstractInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/AbstractInterpreterTest.java new file mode 100644 index 0000000000..8b43af7c46 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/AbstractInterpreterTest.java @@ -0,0 +1,176 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore; + +import de.monticore.antlr4.MCConcreteParser; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.ModelInterpreter; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.util.*; +import de.monticore.visitor.ITraverser; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeEach; + +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Abstract class for interpreter tests. + * Supplies utils for comparing MIValues and loading functions/variables. + * Implementations need to initialize the parserSupplier, resetMill and + * initMill-attributes and implement the setupSymbolTableCompleter method. + */ +public abstract class AbstractInterpreterTest { + + protected static final double delta = 0.00001; + + protected Type4Ast type4Ast; + + protected ITraverser typeMapTraverser; + + @Deprecated + protected ITraverser scopeGenitor; + + protected ITraverser symbolTableCompleter; + + protected MCConcreteParser parser; + protected ModelInterpreter interpreter; + + protected Supplier parserSupplier; + protected Runnable resetMill; + protected Runnable initMill; + + + @BeforeEach + public void init() { + LogStub.init(); + Log.clearFindings(); + Log.enableFailQuick(false); + + resetMill.run(); + initMill.run(); + BasicSymbolsMill.initializePrimitives(); + SymTypeRelations.init(); + WithinScopeBasicSymbolsResolver.init(); + WithinTypeBasicSymbolsResolver.init(); + TypeVisitorOperatorCalculator.init(); + DefsTypesForTests.setup(); + parser = parserSupplier.get(); + MapBasedTypeCheck3 tc3 = CombineExpressionsWithLiteralsTypeTraverserFactory + .initTypeCheck3(); + type4Ast = tc3.getType4Ast(); + typeMapTraverser = tc3.getTypeTraverser(); + setupSymbolTableCompleter(typeMapTraverser, type4Ast); + } + + protected abstract void setupSymbolTableCompleter(ITraverser typeMapTraverser, Type4Ast type4Ast); + + protected Type4Ast getType4Ast() { + return type4Ast; + } + + protected ITraverser getSymbolTableCompleter() { + return symbolTableCompleter; + } + + /** + * @return all findings as one String + */ + protected static String getAllFindingsAsString() { + return Log.getFindings().stream() + .map(Finding::buildMsg) + .collect(Collectors.joining(System.lineSeparator())) + ; + } + + + /** + * Loads variable by full qualified name. + * @param name full qualified name + * @return stored MIValue or ErrorMIValue if not declared/initialized + */ + public MIValue loadVariable(String name) { + VariableSymbol symbol = BasicSymbolsMill.globalScope() + .resolveVariable(name).get(); + return interpreter.loadVariable(symbol); + } + + /** + * Loads function by full qualified name. + * @param name full qualified name + * @return stored FunctionMIValue or ErrorMIValue if not declared + */ + public MIValue loadFunction(String name) { + FunctionSymbol symbol = BasicSymbolsMill.globalScope() + .resolveFunction(name).get(); + return interpreter.loadFunction(symbol); + } + + /** + * Compares two MIValues based on type and value. + * @param expected + * @param actual + */ + public void assertValueEquals(MIValue expected, MIValue actual) { + // if you join the ifs with && you can't tell missing comparison implementations for a new value + // from value mismatches apart + if (expected.isVoid()) { + if (actual.isVoid()) return; + + } else if (expected.isError()) { + if (actual.isError() && expected.asError().equals(actual.asError())) return; + } else if (expected.isBreak()) { + if (actual.isBreak()) return; + } else if (expected.isContinue()) { + if (actual.isContinue()) return; + } else if (expected.isReturn()) { + if (actual.isReturn()) { + assertValueEquals(expected.asReturnValue(), actual.asReturnValue()); + return; + } + + } else if (expected.isBoolean()) { + if (actual.isBoolean() && expected.asBoolean() == actual.asBoolean()) return; + } else if (expected.isByte()) { + if (actual.isByte() && expected.asByte() == actual.asByte()) return; + } else if (expected.isShort()) { + if (actual.isShort() && expected.asShort() == actual.asShort()) return; + } else if (expected.isChar()) { + if (actual.isChar() && expected.asChar() == actual.asChar()) return; + } else if (expected.isInt()) { + if (actual.isInt() && expected.asInt() == actual.asInt()) return; + } else if (expected.isLong()) { + if (actual.isLong() && expected.asLong() == actual.asLong()) return; + + } else if (expected.isFloat()) { + if (actual.isFloat() && expected.asFloat() + delta > actual.asFloat() + && expected.asFloat() - delta < actual.asFloat()) return; + } else if (expected.isDouble()) { + if (actual.isDouble() && expected.asDouble() + delta > actual.asDouble() + && expected.asDouble() - delta < actual.asDouble()) return; + + } else if (expected.isFunction()) { + if (actual.isFunction() && expected.asFunction().equals(actual.asFunction())) return; + } else if (expected.isObject()) { + if (actual.isObject() && expected.asObject().equals(actual.asObject())) return; + + } else { + Log.error("Trying to compare unsupported MIValue type '" + + expected.printType() + "'."); + fail(); + } + + fail("Expected " + expected.printType() + " (" + expected.printValue() + + ") but got " + actual.printType() + " (" + actual.printValue() + + ")."); + + } + +} diff --git a/monticore-grammar/src/test/java/de/monticore/expressions/AbstractExpressionInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/expressions/AbstractExpressionInterpreterTest.java new file mode 100644 index 0000000000..cc1bc19642 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/expressions/AbstractExpressionInterpreterTest.java @@ -0,0 +1,256 @@ +package de.monticore.expressions; + +import de.monticore.AbstractInterpreterTest; +import de.monticore.expressions.combineexpressionswithliterals.CombineExpressionsWithLiteralsMill; +import de.monticore.expressions.combineexpressionswithliterals._ast.ASTFoo; +import de.monticore.expressions.combineexpressionswithliterals._parser.CombineExpressionsWithLiteralsParser; +import de.monticore.expressions.combineexpressionswithliterals._symboltable.ICombineExpressionsWithLiteralsArtifactScope; +import de.monticore.expressions.combineexpressionswithliterals._visitor.CombineExpressionsWithLiteralsInterpreter; +import de.monticore.expressions.combineexpressionswithliterals._visitor.CombineExpressionsWithLiteralsTraverser; +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.expressions.lambdaexpressions._symboltable.LambdaExpressionsSTCompleteTypes2; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.ocl.oclexpressions.symboltable.OCLExpressionsSymbolTableCompleter; +import de.monticore.ocl.setexpressions.symboltable.SetExpressionsSymbolTableCompleter; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.types.check.IDerive; +import de.monticore.types.check.ISynthesize; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.check.types3wrapper.TypeCheck3AsIDerive; +import de.monticore.types.check.types3wrapper.TypeCheck3AsISynthesize; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.visitor.ITraverser; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; + +import java.io.IOException; +import java.util.Optional; + +import static de.monticore.interpreter.MIValueFactory.createValue; +import static de.monticore.types3.util.DefsTypesForTests.inScope; +import static de.monticore.types3.util.DefsTypesForTests.variable; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Abstract class for tests that use CombineExpressionsWithLiterals and + * only contain expressions. + * Creates a variable for each primitive type:
+ * boolean b = true;
+ * char c = 'a';
+ * byte by = 3;
+ * short s = 256;
+ * int i = 1;
+ * long l = 5L;
+ * float f = 1.5f;
+ * double d = 3.14;
+ */ +public class AbstractExpressionInterpreterTest extends AbstractInterpreterTest { + + @Override + @BeforeEach + public void init() { + parserSupplier = CombineExpressionsWithLiteralsMill::parser; + resetMill = CombineExpressionsWithLiteralsMill::reset; + initMill = CombineExpressionsWithLiteralsMill::init; + + super.init(); + + interpreter = new CombineExpressionsWithLiteralsInterpreter(); + + try { + initBool(); + initChar(); + initByte(); + initShort(); + initInt(); + initLong(); + initFloat(); + initDouble(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + + protected void initBool() throws IOException { + VariableSymbol varSymbol = variable("b", SymTypeExpressionFactory + .createPrimitive("boolean")); + inScope(CombineExpressionsWithLiteralsMill.globalScope(), varSymbol); + interpreter.declareVariable(varSymbol, Optional.of(createValue(true))); + } + + protected void initChar() throws IOException { + VariableSymbol varSymbol = variable("c", SymTypeExpressionFactory + .createPrimitive("char")); + inScope(CombineExpressionsWithLiteralsMill.globalScope(), varSymbol); + interpreter.declareVariable(varSymbol, Optional.of(createValue('a'))); + } + + protected void initByte() throws IOException { + VariableSymbol varSymbol = variable("by", SymTypeExpressionFactory + .createPrimitive("byte")); + inScope(CombineExpressionsWithLiteralsMill.globalScope(), varSymbol); + interpreter.declareVariable(varSymbol, Optional.of(createValue((byte)3))); + } + + protected void initShort() throws IOException { + VariableSymbol varSymbol = variable("s", SymTypeExpressionFactory + .createPrimitive("short")); + inScope(CombineExpressionsWithLiteralsMill.globalScope(), varSymbol); + interpreter.declareVariable(varSymbol, Optional.of(createValue((short)256))); + } + + protected void initInt() throws IOException { + VariableSymbol varSymbol = variable("i", SymTypeExpressionFactory + .createPrimitive("int")); + inScope(CombineExpressionsWithLiteralsMill.globalScope(), varSymbol); + interpreter.declareVariable(varSymbol, Optional.of(createValue(1))); + } + + protected void initLong() throws IOException { + VariableSymbol varSymbol = variable("l", SymTypeExpressionFactory + .createPrimitive("long")); + inScope(CombineExpressionsWithLiteralsMill.globalScope(), varSymbol); + interpreter.declareVariable(varSymbol, Optional.of(createValue(5L))); + } + + protected void initFloat() throws IOException { + VariableSymbol varSymbol = variable("f", SymTypeExpressionFactory + .createPrimitive("float")); + inScope(CombineExpressionsWithLiteralsMill.globalScope(), varSymbol); + interpreter.declareVariable(varSymbol, Optional.of(createValue(1.5f))); + } + + protected void initDouble() throws IOException { + VariableSymbol varSymbol = variable("d", SymTypeExpressionFactory + .createPrimitive("double")); + inScope(CombineExpressionsWithLiteralsMill.globalScope(), varSymbol); + interpreter.declareVariable(varSymbol, Optional.of(createValue(3.14))); + } + + /** + * Interprets expression and checks if the result is as expected. + * Fails if parsing, interpretation or comparison fails. + * @param expr Expression to interpret + * @param expected Expected result of expression + */ + protected void testValidExpression(String expr, MIValue expected) { + Log.clearFindings(); + MIValue interpretationResult = null; + try { + interpretationResult = parseExpressionAndInterpret(expr); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + assertNotNull(interpretationResult); + if (!Log.getFindings().isEmpty()) { + Log.printFindings(); + fail(); + } + assertValueEquals(expected, interpretationResult); + assertTrue(Log.getFindings().isEmpty()); + } + + /** + * Tries to parse and interpret invalid expression. + * Fails if parsing and interpretation succeed. + * @param expr Invalid expression to check + */ + protected void testInvalidExpression(String expr) { + Log.clearFindings(); + MIValue interpretationResult; + + try { + interpretationResult = parseExpressionAndInterpret(expr); + } catch (IOException | AssertionError e) { + return; + } + + assertNotNull(interpretationResult); + + if (Log.getFindings().isEmpty() && !interpretationResult.isError()) { + fail("Expected an error but interpretation succeeded with result of " + + interpretationResult.printType() + + " (" + interpretationResult.printValue() + ")."); + } + + assertFalse(Log.getFindings().isEmpty()); + assertTrue(interpretationResult.isError()); + } + + /** + * Parses and interprets an expression. + * @param expr Expression to parse and interpret + * @return result of interpretation + * @throws IOException if parsing throws IOException + */ + protected MIValue parseExpressionAndInterpret(String expr) throws IOException { + Optional astExpression = + ((CombineExpressionsWithLiteralsParser)parser) + .parse_StringExpression(expr); + assertTrue(astExpression.isPresent(), getAllFindingsAsString()); + + ASTExpression ast = astExpression.get(); + generateScopes(ast); + SymTypeExpression type = TypeCheck3.typeOf(ast); + if (type.isObscureType()) { + String errorMsg = "Invalid Model: " + expr; + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + return ast.evaluate(interpreter); + } + + /** + * Generates Model for a single Expression so the Symboltable and + * scopes are build correctly + * @param expr Expression to generate model for + */ + protected void generateScopes(ASTExpression expr) { + // create a root + ASTFoo rootNode = CombineExpressionsWithLiteralsMill.fooBuilder() + .setExpression(expr) + .build(); + ICombineExpressionsWithLiteralsArtifactScope rootScope = + CombineExpressionsWithLiteralsMill.scopesGenitorDelegator() + .createFromAST(rootNode); + + rootScope.setName("fooRoot"); + // complete the symbol table + expr.accept(getSymbolTableCompleter()); + } + + protected void setupSymbolTableCompleter( + ITraverser typeMapTraverser, Type4Ast type4Ast) { + CombineExpressionsWithLiteralsTraverser combinedScopesCompleter = + CombineExpressionsWithLiteralsMill.traverser(); + IDerive deriver = new TypeCheck3AsIDerive(); + ISynthesize synthesizer = new TypeCheck3AsISynthesize(); + combinedScopesCompleter.add4LambdaExpressions( + new LambdaExpressionsSTCompleteTypes2( + typeMapTraverser, + getType4Ast() + ) + ); + OCLExpressionsSymbolTableCompleter oclExprCompleter = + new OCLExpressionsSymbolTableCompleter(); + oclExprCompleter.setDeriver(deriver); + oclExprCompleter.setSynthesizer(synthesizer); + combinedScopesCompleter.add4OCLExpressions(oclExprCompleter); + combinedScopesCompleter.setOCLExpressionsHandler(oclExprCompleter); + + SetExpressionsSymbolTableCompleter setExprCompleter = + new SetExpressionsSymbolTableCompleter(); + setExprCompleter.setDeriver(deriver); + setExprCompleter.setSynthesizer(synthesizer); + combinedScopesCompleter.add4SetExpressions(setExprCompleter); + combinedScopesCompleter.setSetExpressionsHandler(setExprCompleter); + + symbolTableCompleter = combinedScopesCompleter; + scopeGenitor = combinedScopesCompleter; + } + +} diff --git a/monticore-grammar/src/test/java/de/monticore/expressions/AbstractInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/expressions/AbstractInterpreterTest.java index bf6067edec..a2d8d6b561 100644 --- a/monticore-grammar/src/test/java/de/monticore/expressions/AbstractInterpreterTest.java +++ b/monticore-grammar/src/test/java/de/monticore/expressions/AbstractInterpreterTest.java @@ -6,8 +6,8 @@ import de.monticore.expressions.combineexpressionswithliterals._parser.CombineExpressionsWithLiteralsParser; import de.monticore.expressions.combineexpressionswithliterals._symboltable.CombineExpressionsWithLiteralsScopesGenitorDelegator; import de.monticore.expressions.combineexpressionswithliterals._visitor.CombineExpressionsWithLiteralsInterpreter; -import de.monticore.interpreter.Value; -import de.monticore.interpreter.values.NotAValue; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.values.ErrorMIValue; import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpressionFactory; @@ -200,9 +200,9 @@ protected void initString() throws IOException { interpreter.interpret(ast); } - protected void testValidExpression(String expr, Value expected) { + protected void testValidExpression(String expr, MIValue expected) { Log.clearFindings(); - Value interpretationResult = null; + MIValue interpretationResult = null; try { interpretationResult = parseExpressionAndInterpret(expr); } catch (IOException e) { @@ -228,9 +228,6 @@ protected void testValidExpression(String expr, Value expected) { } else if (expected.isChar()) { assertTrue(interpretationResult.isChar()); assertEquals(interpretationResult.asChar(), expected.asChar()); - } else if (expected.isString()) { - assertTrue(interpretationResult.isString()); - assertEquals(interpretationResult.asString(), expected.asString()); } else if (expected.isObject()) { assertTrue(interpretationResult.isObject()); assertEquals(interpretationResult.asObject(), expected.asObject()); @@ -240,7 +237,7 @@ protected void testValidExpression(String expr, Value expected) { protected void testInvalidExpression(String expr) { Log.clearFindings(); - Value interpretationResult = null; + MIValue interpretationResult = null; try { interpretationResult = parseExpressionAndInterpret(expr); } catch (IOException e) { @@ -248,10 +245,10 @@ protected void testInvalidExpression(String expr) { } assertNotNull(interpretationResult); assertEquals(Log.getFindings().size(), 1); - assertInstanceOf(NotAValue.class, interpretationResult); + assertInstanceOf(ErrorMIValue.class, interpretationResult); } - protected Value parseExpressionAndInterpret(String expr) throws IOException { + protected MIValue parseExpressionAndInterpret(String expr) throws IOException { final Optional optAST = parser.parse_String("bar " + expr); assertTrue(optAST.isPresent()); final ASTFoo ast = optAST.get(); diff --git a/monticore-grammar/src/test/java/de/monticore/expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreterTest.java index 826ac66bdf..381bf5645a 100644 --- a/monticore-grammar/src/test/java/de/monticore/expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreterTest.java +++ b/monticore-grammar/src/test/java/de/monticore/expressions/assignmentexpressions/_visitor/AssignmentExpressionsInterpreterTest.java @@ -1,711 +1,904 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.expressions.assignmentexpressions._visitor; -import de.monticore.expressions.AbstractInterpreterTest; -import de.monticore.interpreter.Value; +import de.monticore.expressions.AbstractExpressionInterpreterTest; +import de.monticore.interpreter.MIValue; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import java.util.stream.Stream; -import static java.util.Objects.isNull; import static org.junit.jupiter.params.provider.Arguments.arguments; -import static de.monticore.interpreter.ValueFactory.createValue; +import static de.monticore.interpreter.MIValueFactory.createValue; -public class AssignmentExpressionsInterpreterTest extends AbstractInterpreterTest { +/** + * Tests for all AssignmentExpressions with primitive types + */ +public class AssignmentExpressionsInterpreterTest extends AbstractExpressionInterpreterTest { protected static Stream incSuffixExpression() { return Stream.of( - arguments("b++", null, BOOL), - arguments("i++", createValue(2), INT), - arguments("l++", createValue(6L), LONG), - arguments("f++", createValue(2.5f), FLOAT), - arguments("d++", createValue(4.14), DOUBLE), - arguments("c++", createValue(98), CHAR), - arguments("s++", null, STRING)); + arguments("b++", null), + arguments("by++", createValue((byte)3)), + arguments("s++", createValue((short)256)), + arguments("c++", createValue('a')), + arguments("i++", createValue(1)), + arguments("l++", createValue(5L)), + arguments("f++", createValue(1.5f)), + arguments("d++", createValue(3.14))); } protected static Stream incPrefixExpression() { return Stream.of( - arguments("++b", null, BOOL), - arguments("++i", createValue(2), INT), - arguments("++l", createValue(6L), LONG), - arguments("++f", createValue(2.5f), FLOAT), - arguments("++d", createValue(4.14), DOUBLE), - arguments("++c", createValue(98), CHAR), - arguments("++s", null, STRING)); + arguments("++b", null), + arguments("++by", createValue((byte)4)), + arguments("++s", createValue((short)257)), + arguments("++c", createValue('b')), + arguments("++i", createValue(2)), + arguments("++l", createValue(6L)), + arguments("++f", createValue(2.5f)), + arguments("++d", createValue(4.14))); } protected static Stream decSuffixExpression() { return Stream.of( - arguments("c--", createValue(96), CHAR), - arguments("s--", null, STRING), - arguments("i--", createValue(0), INT), - arguments("l--", createValue(4L), LONG), - arguments("f--", createValue(0.5f), FLOAT), - arguments("d--", createValue(2.14), DOUBLE), - arguments("b--", null, BOOL)); + arguments("b--", null), + arguments("by--", createValue((byte)3)), + arguments("s--", createValue((short)256)), + arguments("c--", createValue('a')), + arguments("i--", createValue(1)), + arguments("l--", createValue(5L)), + arguments("f--", createValue(1.5f)), + arguments("d--", createValue(3.14))); } protected static Stream decPrefixExpression() { return Stream.of( - arguments("--c", createValue(96), CHAR), - arguments("--s", null, STRING), - arguments("--i", createValue(0), INT), - arguments("--l", createValue(4L), LONG), - arguments("--f", createValue(0.5f), FLOAT), - arguments("--d", createValue(2.14), DOUBLE), - arguments("--b", null, BOOL)); + arguments("--b", null), + arguments("--by", createValue((byte)2)), + arguments("--s", createValue((short)255)), + arguments("--c", createValue('`')), + arguments("--i", createValue(0)), + arguments("--l", createValue(4L)), + arguments("--f", createValue(0.5f)), + arguments("--d", createValue(2.14))); } protected static Stream andEqualsExpression() { return Stream.of( - arguments("b &= false", null, BOOL), - arguments("b &= 1", null, BOOL), - arguments("b &= 2L", null, BOOL), - arguments("b &= 1.5f", null, BOOL), - arguments("b &= 3.14", null, BOOL), - arguments("b &= 'c'", null, BOOL), - arguments("b &= \"test\"", null, BOOL), - - arguments("i &= false", null, INT), - arguments("i &= 1", createValue(1), INT), - arguments("i &= 2L", createValue(0L), INT), - arguments("i &= 1.5f", null, INT), - arguments("i &= 3.14", null, INT), - arguments("i &= 'a'", createValue(1), INT), - arguments("i &= \"test\"", null, INT), - - arguments("l &= false", null, LONG), - arguments("l &= 1", createValue(1L), LONG), - arguments("l &= 2L", createValue(0L), LONG), - arguments("l &= 1.5f", null, LONG), - arguments("l &= 3.14", null, LONG), - arguments("l &= 'a'", createValue(1L), LONG), - arguments("l &= \"test\"", null, LONG), - - arguments("f &= false", null, FLOAT), - arguments("f &= 1", null, FLOAT), - arguments("f &= 2L", null, FLOAT), - arguments("f &= 1.5f", null, FLOAT), - arguments("f &= 3.14", null, FLOAT), - arguments("f &= 'a'", null, FLOAT), - arguments("f &= \"test\"", null, FLOAT), - - arguments("d &= false", null, DOUBLE), - arguments("d &= 1", null, DOUBLE), - arguments("d &= 2L", null, DOUBLE), - arguments("d &= 1.5f", null, DOUBLE), - arguments("d &= 3.14", null, DOUBLE), - arguments("d &= 'a'", null, DOUBLE), - arguments("d &= \"test\"", null, DOUBLE), - - arguments("c &= false", null, CHAR), - arguments("c &= 1", createValue(1), CHAR), - arguments("c &= 2L", createValue(0L), CHAR), - arguments("c &= 1.5f", null, CHAR), - arguments("c &= 3.14", null, CHAR), - arguments("c &= 'a'", createValue(97), CHAR), - arguments("c &= \"test\"", null, CHAR), - - arguments("s &= false", null, STRING), - arguments("s &= 1", null, STRING), - arguments("s &= 2L", null, STRING), - arguments("s &= 1.5f", null, STRING), - arguments("s &= 3.14", null, STRING), - arguments("s &= 'a'", null, STRING), - arguments("s &= \"test\"", null, STRING)); + arguments("b &= true", createValue(true)), + arguments("b &= (byte)3", null), + arguments("b &= (short)256", null), + arguments("b &= 'c'", null), + arguments("b &= 1", null), + arguments("b &= 2L", null), + arguments("b &= 1.5f", null), + arguments("b &= 3.14", null), + + arguments("by &= false", null), + arguments("by &= (byte)3", createValue((byte)3)), + arguments("by &= (short)256", createValue((byte)256)), + arguments("by &= 'a'", createValue((byte)1)), + arguments("by &= 1", createValue((byte)1)), + arguments("by &= 2L", createValue((byte)2L)), + arguments("by &= 1.5f", null), + arguments("by &= 3.14", null), + + arguments("s &= false", null), + arguments("s &= (byte)3", createValue((short)0)), + arguments("s &= (short)256", createValue((short)256)), + arguments("s &= 'a'", createValue((short)0)), + arguments("s &= 1", createValue((short)0)), + arguments("s &= 2L", createValue((short)0L)), + arguments("s &= 1.5f", null), + arguments("s &= 3.14", null), + + arguments("c &= false", null), + arguments("c &= (byte)3", createValue((char)1)), + arguments("c &= (short)256", createValue((char)0)), + arguments("c &= 'a'", createValue('a')), + arguments("c &= 1", createValue((char)1)), + arguments("c &= 2L", createValue((char)0L)), + arguments("c &= 1.5f", null), + arguments("c &= 3.14", null), + + arguments("i &= false", null), + arguments("i &= (byte)3", createValue(1)), + arguments("i &= (short)256", createValue(0)), + arguments("i &= 'a'", createValue(1)), + arguments("i &= 1", createValue(1)), + arguments("i &= 2L", createValue(0)), + arguments("i &= 1.5f", null), + arguments("i &= 3.14", null), + + arguments("l &= false", null), + arguments("l &= (byte)3", createValue(1L)), + arguments("l &= (short)256", createValue(0L)), + arguments("l &= 'a'", createValue(1L)), + arguments("l &= 1", createValue(1L)), + arguments("l &= 4L", createValue(4L)), + arguments("l &= 1.5f", null), + arguments("l &= 3.14", null), + + arguments("f &= false", null), + arguments("f &= (byte)3", null), + arguments("f &= (short)256", null), + arguments("f &= 1", null), + arguments("f &= 2L", null), + arguments("f &= 1.5f", null), + arguments("f &= 3.14", null), + arguments("f &= 'a'", null), + + arguments("d &= false", null), + arguments("d &= (byte)3", null), + arguments("d &= (short)256", null), + arguments("d &= 'a'", null), + arguments("d &= 1", null), + arguments("d &= 2L", null), + arguments("d &= 1.5f", null), + arguments("d &= 3.14", null) + ); } protected static Stream gTGTEqualsExpression() { return Stream.of( - arguments("b >>= false", null, BOOL), - arguments("b >>= 1", null, BOOL), - arguments("b >>= 2L", null, BOOL), - arguments("b >>= 1.5f", null, BOOL), - arguments("b >>= 3.14", null, BOOL), - arguments("b >>= 'a'", null, BOOL), - arguments("b >>= \"test\"", null, BOOL), - - arguments("i >>= false", null, INT), - arguments("i >>= 1", createValue(0), INT), - arguments("i >>= 2L", createValue(0), INT), - arguments("i >>= 1.5f", null, INT), - arguments("i >>= 3.14", null, INT), - arguments("i >>= 'a'", createValue(0), INT), - arguments("i >>= \"test\"", null, INT), - - arguments("l >>= false", null, LONG), - arguments("l >>= 1", createValue(2L), LONG), - arguments("l >>= 2L", createValue(1L), LONG), - arguments("l >>= 1.5f", null, LONG), - arguments("l >>= 3.14", null, LONG), - arguments("l >>= 'a'", createValue(0L), LONG), - arguments("l >>= \"test\"", null, LONG), - - arguments("f >>= false", null, FLOAT), - arguments("f >>= 1", null, FLOAT), - arguments("f >>= 2L", null, FLOAT), - arguments("f >>= 1.5f", null, FLOAT), - arguments("f >>= 3.14", null, FLOAT), - arguments("f >>= 'a'", null, FLOAT), - arguments("f >>= \"test\"", null, FLOAT), - - arguments("d >>= false", null, DOUBLE), - arguments("d >>= 1", null, DOUBLE), - arguments("d >>= 2L", null, DOUBLE), - arguments("d >>= 1.5f", null, DOUBLE), - arguments("d >>= 3.14", null, DOUBLE), - arguments("d >>= 'a'", null, DOUBLE), - arguments("d >>= \"test\"", null, DOUBLE), - - arguments("c >>= false", null, CHAR), - arguments("c >>= 1", createValue(48), CHAR), - arguments("c >>= 2L", createValue(24), CHAR), - arguments("c >>= 1.5f", null, CHAR), - arguments("c >>= 3.14", null, CHAR), - arguments("c >>= 'a'", createValue(48), CHAR), - arguments("c >>= \"test\"", null, CHAR), - - arguments("s >>= false", null, STRING), - arguments("s >>= 1", null, STRING), - arguments("s >>= 2L", null, STRING), - arguments("s >>= 1.5f", null, STRING), - arguments("s >>= 3.14", null, STRING), - arguments("s >>= 'a'", null, STRING), - arguments("s >>= \"test\"", null, STRING)); + arguments("b >>= false", null), + arguments("b >>= (byte)3", null), + arguments("b >>= (short)256", null), + arguments("b >>= 'a'", null), + arguments("b >>= 1", null), + arguments("b >>= 2L", null), + arguments("b >>= 1.5f", null), + arguments("b >>= 3.14", null), + + arguments("by >>= false", null), + arguments("by >>= (byte)3", createValue((byte)0)), + arguments("by >>= (short)256", createValue((byte)3)), + arguments("by >>= 'a'", createValue((byte)1)), + arguments("by >>= 1", createValue((byte)1)), + arguments("by >>= 2L", createValue((byte)0)), + arguments("by >>= 1.5f", null), + arguments("by >>= 3.14", null), + + arguments("s >>= false", null), + arguments("s >>= (byte)3", createValue((short)32)), + arguments("s >>= (short)256", createValue((short)256)), + arguments("s >>= 'a'", createValue((short)128)), + arguments("s >>= 1", createValue((short)128)), + arguments("s >>= 2L", createValue((short)64)), + arguments("s >>= 1.5f", null), + arguments("s >>= 3.14", null), + + arguments("c >>= false", null), + arguments("c >>= (byte)3", createValue((char)12)), + arguments("c >>= (short)256", createValue('a')), + arguments("c >>= 'a'", createValue((char)48)), + arguments("c >>= 1", createValue((char)48)), + arguments("c >>= 2L", createValue((char)24)), + arguments("c >>= 1.5f", null), + arguments("c >>= 3.14", null), + + arguments("i >>= false", null), + arguments("i >>= (byte)3", createValue(0)), + arguments("i >>= (short)256", createValue(1)), + arguments("i >>= 'a'", createValue(0)), + arguments("i >>= 1", createValue(0)), + arguments("i >>= 2L", createValue(0)), + arguments("i >>= 1.5f", null), + arguments("i >>= 3.14", null), + + arguments("l >>= false", null), + arguments("l >>= (byte)3", createValue(0L)), + arguments("l >>= (short)256", createValue(5L)), + arguments("l >>= 1", createValue(2L)), + arguments("l >>= 2L", createValue(1L)), + arguments("l >>= 1.5f", null), + arguments("l >>= 3.14", null), + arguments("l >>= 'a'", createValue(0L)), + + arguments("f >>= false", null), + arguments("f >>= (byte)3", null), + arguments("f >>= (short)256", null), + arguments("f >>= 'a'", null), + arguments("f >>= 1", null), + arguments("f >>= 2L", null), + arguments("f >>= 1.5f", null), + arguments("f >>= 3.14", null), + + arguments("d >>= false", null), + arguments("d >>= (byte)3", null), + arguments("d >>= (short)256", null), + arguments("d >>= 'a'", null), + arguments("d >>= 1", null), + arguments("d >>= 2L", null), + arguments("d >>= 1.5f", null), + arguments("d >>= 3.14", null)); + } protected static Stream gTGTGTEqualsExpression() { return Stream.of( - arguments("b >>>= false", null, BOOL), - arguments("b >>>= 1", null, BOOL), - arguments("b >>>= 2L", null, BOOL), - arguments("b >>>= 1.5f", null, BOOL), - arguments("b >>>= 3.14", null, BOOL), - arguments("b >>>= 'a'", null, BOOL), - arguments("b >>>= \"test\"", null, BOOL), - - arguments("i >>>= false", null, INT), - arguments("i >>>= 1", createValue(0), INT), - arguments("i >>>= 2L", createValue(0), INT), - arguments("i >>>= 1.5f", null, INT), - arguments("i >>>= 3.14", null, INT), - arguments("i >>>= 'a'", createValue(0), INT), - arguments("i >>>= \"test\"", null, INT), - - arguments("l >>>= false", null, LONG), - arguments("l >>>= 1", createValue(2L), LONG), - arguments("l >>>= 2L", createValue(1L), LONG), - arguments("l >>>= 1.5f", null, LONG), - arguments("l >>>= 3.14", null, LONG), - arguments("l >>>= 'a'", createValue(0L), LONG), - arguments("l >>>= \"test\"", null, LONG), - - arguments("f >>>= false", null, FLOAT), - arguments("f >>>= 1", null, FLOAT), - arguments("f >>>= 2L", null, FLOAT), - arguments("f >>>= 1.5f", null, FLOAT), - arguments("f >>>= 3.14", null, FLOAT), - arguments("f >>>= 'a'", null, FLOAT), - arguments("f >>>= \"test\"", null, FLOAT), - - arguments("d >>>= false", null, DOUBLE), - arguments("d >>>= 1", null, DOUBLE), - arguments("d >>>= 2L", null, DOUBLE), - arguments("d >>>= 1.5f", null, DOUBLE), - arguments("d >>>= 3.14", null, DOUBLE), - arguments("d >>>= 'a'", null, DOUBLE), - arguments("d >>>= \"test\"", null, DOUBLE), - - arguments("c >>>= false", null, CHAR), - arguments("c >>>= 1", createValue(48), CHAR), - arguments("c >>>= 2L", createValue(24), CHAR), - arguments("c >>>= 1.5f", null, CHAR), - arguments("c >>>= 3.14", null, CHAR), - arguments("c >>>= 'a'", createValue(48), CHAR), - arguments("c >>>= \"test\"", null, CHAR), - - arguments("s >>>= false", null, STRING), - arguments("s >>>= 1", null, STRING), - arguments("s >>>= 2L", null, STRING), - arguments("s >>>= 1.5f", null, STRING), - arguments("s >>>= 3.14", null, STRING), - arguments("s >>>= 'a'", null, STRING), - arguments("s >>>= \"test\"", null, STRING)); + arguments("b >>>= false", null), + arguments("b >>>= (byte)3", null), + arguments("b >>>= (short)256", null), + arguments("b >>>= 'a'", null), + arguments("b >>>= 1", null), + arguments("b >>>= 2L", null), + arguments("b >>>= 1.5f", null), + arguments("b >>>= 3.14", null), + + arguments("by >>>= false", null), + arguments("by >>>= (byte)3", createValue((byte)0)), + arguments("by >>>= (short)256", createValue((byte)3)), + arguments("by >>>= 'a'", createValue((byte)1)), + arguments("by >>>= 1", createValue((byte)1)), + arguments("by >>>= 2L", createValue((byte)0)), + arguments("by >>>= 1.5f", null), + arguments("by >>>= 3.14", null), + + arguments("s >>>= false", null), + arguments("s >>>= (byte)3", createValue((short)32)), + arguments("s >>>= (short)256", createValue((short)256)), + arguments("s >>>= 'a'", createValue((short)128)), + arguments("s >>>= 1", createValue((short)128)), + arguments("s >>>= 2L", createValue((short)64)), + arguments("s >>>= 1.5f", null), + arguments("s >>>= 3.14", null), + + arguments("c >>>= false", null), + arguments("c >>>= (byte)3", createValue((char)12)), + arguments("c >>>= (short)256", createValue('a')), + arguments("c >>>= 'a'", createValue((char)48)), + arguments("c >>>= 1", createValue((char)48)), + arguments("c >>>= 2L", createValue((char)24)), + arguments("c >>>= 1.5f", null), + arguments("c >>>= 3.14", null), + + arguments("i >>>= false", null), + arguments("i >>>= (byte)3", createValue(0)), + arguments("i >>>= (short)256", createValue(1)), + arguments("i >>>= 'a'", createValue(0)), + arguments("i >>>= 1", createValue(0)), + arguments("i >>>= 2L", createValue(0)), + arguments("i >>>= 1.5f", null), + arguments("i >>>= 3.14", null), + + arguments("l >>>= false", null), + arguments("l >>>= (byte)3", createValue(0L)), + arguments("l >>>= (short)256", createValue(5L)), + arguments("l >>>= 'a'", createValue(0L)), + arguments("l >>>= 1", createValue(2L)), + arguments("l >>>= 2L", createValue(1L)), + arguments("l >>>= 1.5f", null), + arguments("l >>>= 3.14", null), + + arguments("f >>>= false", null), + arguments("f >>>= (byte)3", null), + arguments("f >>>= (short)256", null), + arguments("f >>>= 'a'", null), + arguments("f >>>= 1", null), + arguments("f >>>= 2L", null), + arguments("f >>>= 1.5f", null), + arguments("f >>>= 3.14", null), + + arguments("d >>>= false", null), + arguments("d >>>= (byte)3", null), + arguments("d >>>= (short)256", null), + arguments("d >>>= 'a'", null), + arguments("d >>>= 1", null), + arguments("d >>>= 2L", null), + arguments("d >>>= 1.5f", null), + arguments("d >>>= 3.14", null) + ); } protected static Stream lTLTEqualsExpression() { return Stream.of( - arguments("b <<= false", null, BOOL), - arguments("b <<= 1", null, BOOL), - arguments("b <<= 2L", null, BOOL), - arguments("b <<= 1.5f", null, BOOL), - arguments("b <<= 3.14", null, BOOL), - arguments("b <<= 'a'", null, BOOL), - arguments("b <<= \"test\"", null, BOOL), - - arguments("i <<= false", null, INT), - arguments("i <<= 1", createValue(2), INT), - arguments("i <<= 2L", createValue(4), INT), - arguments("i <<= 1.5f", null, INT), - arguments("i <<= 3.14", null, INT), - arguments("i <<= 'a'", createValue(2), INT), - arguments("i <<= \"test\"", null, INT), - - arguments("l <<= false", null, LONG), - arguments("l <<= 1", createValue(10L), LONG), - arguments("l <<= 2L", createValue(20L), LONG), - arguments("l <<= 1.5f", null, LONG), - arguments("l <<= 3.14", null, LONG), - arguments("l <<= 'a'", createValue(42949672960L), LONG), - arguments("l <<= \"test\"", null, LONG), - - arguments("f <<= false", null, FLOAT), - arguments("f <<= 1", null, FLOAT), - arguments("f <<= 2L", null, FLOAT), - arguments("f <<= 1.5f", null, FLOAT), - arguments("f <<= 3.14", null, FLOAT), - arguments("f <<= 'a'", null, FLOAT), - arguments("f <<= \"test\"", null, FLOAT), - - arguments("d <<= false", null, DOUBLE), - arguments("d <<= 1", null, DOUBLE), - arguments("d <<= 2L", null, DOUBLE), - arguments("d <<= 1.5f", null, DOUBLE), - arguments("d <<= 3.14", null, DOUBLE), - arguments("d <<= 'a'", null, DOUBLE), - arguments("d <<= \"test\"", null, DOUBLE), - - arguments("c <<= false", null, CHAR), - arguments("c <<= 1", createValue(194), CHAR), - arguments("c <<= 2L", createValue(388), CHAR), - arguments("c <<= 1.5f", null, CHAR), - arguments("c <<= 3.14", null, CHAR), - arguments("c <<= 'a'", createValue(194), CHAR), - arguments("c <<= \"test\"", null, CHAR), - - arguments("s <<= false", null, STRING), - arguments("s <<= 1", null, STRING), - arguments("s <<= 2L", null, STRING), - arguments("s <<= 1.5f", null, STRING), - arguments("s <<= 3.14", null, STRING), - arguments("s <<= 'a'", null, STRING), - arguments("s <<= \"test\"", null, STRING)); + arguments("b <<= false", null), + arguments("b <<= (byte)3", null), + arguments("b <<= (short)256", null), + arguments("b <<= 'a'", null), + arguments("b <<= 1", null), + arguments("b <<= 2L", null), + arguments("b <<= 1.5f", null), + arguments("b <<= 3.14", null), + + arguments("by <<= false", null), + arguments("by <<= (byte)3", createValue((byte)24)), + arguments("by <<= (short)256", createValue((byte)3)), + arguments("by <<= 'a'", createValue((byte)6)), + arguments("by <<= 1", createValue((byte)6)), + arguments("by <<= 2L", createValue((byte)12)), + arguments("by <<= 1.5f", null), + arguments("by <<= 3.14", null), + + arguments("s <<= false", null), + arguments("s <<= (byte)3", createValue((short)2048)), + arguments("s <<= (short)256", createValue((short)256)), + arguments("s <<= 'a'", createValue((short)512)), + arguments("s <<= 1", createValue((short)512)), + arguments("s <<= 2L", createValue((short)1024)), + arguments("s <<= 1.5f", null), + arguments("s <<= 3.14", null), + + arguments("c <<= false", null), + arguments("c <<= (byte)3", createValue((char)776)), + arguments("c <<= (short)256", createValue('a')), + arguments("c <<= 'a'", createValue((char)194)), + arguments("c <<= 1", createValue((char)194)), + arguments("c <<= 2L", createValue((char)388)), + arguments("c <<= 1.5f", null), + arguments("c <<= 3.14", null), + + arguments("i <<= false", null), + arguments("i <<= (byte)3", createValue(8)), + arguments("i <<= (short)256", createValue(1)), + arguments("i <<= 'a'", createValue(2)), + arguments("i <<= 1", createValue(2)), + arguments("i <<= 2L", createValue(4)), + arguments("i <<= 1.5f", null), + arguments("i <<= 3.14", null), + + arguments("l <<= false", null), + arguments("l <<= (byte)3", createValue(40L)), + arguments("l <<= (short)256", createValue(5L)), + arguments("l <<= 'a'", createValue(42949672960L)), + arguments("l <<= 1", createValue(10L)), + arguments("l <<= 2L", createValue(20L)), + arguments("l <<= 1.5f", null), + arguments("l <<= 3.14", null), + + arguments("f <<= false", null), + arguments("f <<= (byte)3", null), + arguments("f <<= (short)256", null), + arguments("f <<= 'a'", null), + arguments("f <<= 1", null), + arguments("f <<= 2L", null), + arguments("f <<= 1.5f", null), + arguments("f <<= 3.14", null), + + arguments("d <<= false", null), + arguments("d <<= (byte)3", null), + arguments("d <<= (short)256", null), + arguments("d <<= 'a'", null), + arguments("d <<= 1", null), + arguments("d <<= 2L", null), + arguments("d <<= 1.5f", null), + arguments("d <<= 3.14", null) + ); } protected static Stream minusEqualsExpression() { return Stream.of( - arguments("b -= false", null, BOOL), - arguments("b -= 1", null, BOOL), - arguments("b -= 2L", null, BOOL), - arguments("b -= 1.5f", null, BOOL), - arguments("b -= 3.14", null, BOOL), - arguments("b -= 'a'", null, BOOL), - arguments("b -= \"test\"", null, BOOL), - - arguments("i -= false", null, INT), - arguments("i -= 1", createValue(0), INT), - arguments("i -= 2L", createValue(-1L), INT), - arguments("i -= 1.5f", createValue(-.5f), INT), - arguments("i -= 3.14", createValue(-2.14), INT), - arguments("i -= 'a'", createValue(-96), INT), - arguments("i -= \"test\"", null, INT), - - arguments("l -= false", null, LONG), - arguments("l -= 1", createValue(4L), LONG), - arguments("l -= 2L", createValue(3L), LONG), - arguments("l -= 1.5f", createValue(3.5f), LONG), - arguments("l -= 3.14", createValue(1.86), LONG), - arguments("l -= 'a'", createValue(-92L), LONG), - arguments("l -= \"test\"", null, LONG), - - arguments("f -= false", null, FLOAT), - arguments("f -= 1", createValue(0.5f), FLOAT), - arguments("f -= 2L", createValue(-0.5f), FLOAT), - arguments("f -= 1.2f", createValue(.3f), FLOAT), - arguments("f -= 3.14", createValue(-1.64), FLOAT), - arguments("f -= 'a'", createValue(-95.5f), FLOAT), - arguments("f -= \"test\"", null, FLOAT), - - arguments("d -= false", null, DOUBLE), - arguments("d -= 1", createValue(2.14), DOUBLE), - arguments("d -= 2L", createValue(1.14), DOUBLE), - arguments("d -= 1.5f", createValue(1.64), DOUBLE), - arguments("d -= 3.04", createValue(.1), DOUBLE), - arguments("d -= 'a'", createValue(-93.86), DOUBLE), - arguments("d -= \"test\"", null, DOUBLE), - - arguments("c -= false", null, CHAR), - arguments("c -= 1", createValue(96), CHAR), - arguments("c -= 2L", createValue(95L), CHAR), - arguments("c -= 1.5f", createValue(95.5f), CHAR), - arguments("c -= 3.14", createValue(93.86), CHAR), - arguments("c -= 'a'", createValue(0), CHAR), - arguments("c -= \"test\"", null, CHAR), - - arguments("s -= false", null, STRING), - arguments("s -= 1", null, STRING), - arguments("s -= 2L", null, STRING), - arguments("s -= 1.5f", null, STRING), - arguments("s -= 3.14", null, STRING), - arguments("s -= 'a'", null, STRING), - arguments("s -= \"test\"", null, STRING)); + arguments("b -= false", null), + arguments("b -= (byte)3", null), + arguments("b -= (short)256", null), + arguments("b -= 'a'", null), + arguments("b -= 1", null), + arguments("b -= 2L", null), + arguments("b -= 1.5f", null), + arguments("b -= 3.14", null), + + arguments("by -= false", null), + arguments("by -= (byte)3", createValue((byte)0)), + arguments("by -= (short)256", createValue((byte)3)), + arguments("by -= 'a'", createValue((byte)-94)), + arguments("by -= 1", createValue((byte)2)), + arguments("by -= 2L", createValue((byte)1)), + arguments("by -= 1.5f", createValue((byte)1)), + arguments("by -= 3.14", createValue((byte)0)), + + arguments("s -= false", null), + arguments("s -= (byte)3", createValue((short)253)), + arguments("s -= (short)256", createValue((short)0)), + arguments("s -= 'a'", createValue((short)159)), + arguments("s -= 1", createValue((short)255)), + arguments("s -= 2L", createValue((short)254)), + arguments("s -= 1.5f", createValue((short)254)), + arguments("s -= 3.14", createValue((short)252)), + + arguments("c -= false", null), + arguments("c -= (byte)3", createValue((char)94)), + arguments("c -= (short)256", createValue((char)-159)), + arguments("c -= 'a'", createValue((char)0)), + arguments("c -= 1", createValue((char)96)), + arguments("c -= 2L", createValue((char)95)), + arguments("c -= 1.5f", createValue((char)95.5f)), + arguments("c -= 3.14", createValue((char)93.86)), + + arguments("i -= false", null), + arguments("i -= (byte)3", createValue(-2)), + arguments("i -= (short)256", createValue(-255)), + arguments("i -= 'a'", createValue(-96)), + arguments("i -= 1", createValue(0)), + arguments("i -= 2L", createValue(-1)), + arguments("i -= 1.5f", createValue(0)), + arguments("i -= 3.14", createValue(-2)), + + arguments("l -= false", null), + arguments("l -= (byte)3", createValue(2L)), + arguments("l -= (short)256", createValue(-251L)), + arguments("l -= 'a'", createValue(-92L)), + arguments("l -= 1", createValue(4L)), + arguments("l -= 2L", createValue(3L)), + arguments("l -= 1.5f", createValue(3L)), + arguments("l -= 3.14", createValue(1L)), + + arguments("f -= false", null), + arguments("f -= (byte)3", createValue(-1.5f)), + arguments("f -= (short)256", createValue(-254.5f)), + arguments("f -= 'a'", createValue(-95.5f)), + arguments("f -= 1", createValue(0.5f)), + arguments("f -= 2L", createValue(-0.5f)), + arguments("f -= 1.2f", createValue(.3f)), + arguments("f -= 3.14", createValue(-1.64f)), + + arguments("d -= false", null), + arguments("d -= (byte)3", createValue(0.14)), + arguments("d -= (short)256", createValue(-252.86)), + arguments("d -= 'a'", createValue(-93.86)), + arguments("d -= 1", createValue(2.14)), + arguments("d -= 2L", createValue(1.14)), + arguments("d -= 1.5f", createValue(1.64)), + arguments("d -= 3.04", createValue(.1)) + ); } protected static Stream percentEqualsExpression() { return Stream.of( - arguments("b %= false", null, BOOL), - arguments("b %= 1", null, BOOL), - arguments("b %= 2L", null, BOOL), - arguments("b %= 1.5f", null, BOOL), - arguments("b %= 3.14", null, BOOL), - arguments("b %= 'a'", null, BOOL), - arguments("b %= \"test\"", null, BOOL), - - arguments("i %= false", null, INT), - arguments("i %= 1", createValue(0), INT), - arguments("i %= 2L", createValue(1L), INT), - arguments("i %= 1.5f", createValue(1f), INT), - arguments("i %= 3.14", createValue(1.), INT), - arguments("i %= 'a'", createValue(1), INT), - arguments("i %= \"test\"", null, INT), - - arguments("l %= false", null, LONG), - arguments("l %= 1", createValue(0L), LONG), - arguments("l %= 2L", createValue(1L), LONG), - arguments("l %= 1.5f", createValue(0.5f), LONG), - arguments("l %= 3.14", createValue(1.86), LONG), - arguments("l %= 'a'", createValue(5L), LONG), - arguments("l %= \"test\"", null, LONG), - - arguments("f %= false", null, FLOAT), - arguments("f %= 1", createValue(0.5f), FLOAT), - arguments("f %= 2L", createValue(1.5f), FLOAT), - arguments("f %= 1.5f", createValue(0f), FLOAT), - arguments("f %= 3.14", createValue(1.5), FLOAT), - arguments("f %= 'a'", createValue(1.5f), FLOAT), - arguments("f %= \"test\"", null, FLOAT), - - arguments("d %= false", null, DOUBLE), - arguments("d %= 1", createValue(0.14), DOUBLE), - arguments("d %= 2L", createValue(1.14), DOUBLE), - arguments("d %= 1.5f", createValue(0.14), DOUBLE), - arguments("d %= 3.14", createValue(0.), DOUBLE), - arguments("d %= 'a'", createValue(3.14), DOUBLE), - arguments("d %= \"test\"", null, DOUBLE), - - arguments("c %= false", null, CHAR), - arguments("c %= 1", createValue(0), CHAR), - arguments("c %= 2L", createValue(1L), CHAR), - arguments("c %= 1.5f", createValue(1f), CHAR), - arguments("c %= 3.14", createValue(2.8), CHAR), - arguments("c %= 'a'", createValue(0), CHAR), - arguments("c %= \"test\"", null, CHAR), - - arguments("s %= false", null, STRING), - arguments("s %= 1", null, STRING), - arguments("s %= 2L", null, STRING), - arguments("s %= 1.5f", null, STRING), - arguments("s %= 3.14", null, STRING), - arguments("s %= 'a'", null, STRING), - arguments("s %= \"test\"", null, STRING)); + arguments("b %= false", null), + arguments("b %= (byte)3", null), + arguments("b %= (short)256", null), + arguments("b %= 'a'", null), + arguments("b %= 1", null), + arguments("b %= 2L", null), + arguments("b %= 1.5f", null), + arguments("b %= 3.14", null), + + arguments("by %= false", null), + arguments("by %= (byte)3", createValue((byte)0)), + arguments("by %= (short)256", createValue((byte)3)), + arguments("by %= 'a'", createValue((byte)3)), + arguments("by %= 1", createValue((byte)0)), + arguments("by %= 2L", createValue((byte)1)), + arguments("by %= 1.5f", createValue((byte)0)), + arguments("by %= 3.14", createValue((byte)3)), + + arguments("s %= false", null), + arguments("s %= (byte)3", createValue((short)1)), + arguments("s %= (short)256", createValue((short)0)), + arguments("s %= 'a'", createValue((short)62)), + arguments("s %= 1", createValue((short)0)), + arguments("s %= 2L", createValue((short)0)), + arguments("s %= 1.5f", createValue((short)1)), + arguments("s %= 3.14", createValue((short)1)), + + arguments("c %= false", null), + arguments("c %= (byte)3", createValue((char)1)), + arguments("c %= (short)256", createValue('a')), + arguments("c %= 'a'", createValue((char)0)), + arguments("c %= 1", createValue((char)0)), + arguments("c %= 2L", createValue((char)1)), + arguments("c %= 1.5f", createValue((char)1)), + arguments("c %= 3.14", createValue((char)2)), + + arguments("i %= false", null), + arguments("i %= (byte)3", createValue(1)), + arguments("i %= (short)256", createValue(1)), + arguments("i %= 'a'", createValue(1)), + arguments("i %= 1", createValue(0)), + arguments("i %= 2L", createValue(1)), + arguments("i %= 1.5f", createValue(1)), + arguments("i %= 3.14", createValue(1)), + + arguments("l %= false", null), + arguments("l %= (byte)3", createValue(2L)), + arguments("l %= (short)256", createValue(5L)), + arguments("l %= 'a'", createValue(5L)), + arguments("l %= 1", createValue(0L)), + arguments("l %= 4L", createValue(1L)), + arguments("l %= 1.5f", createValue(0L)), + arguments("l %= 3.14", createValue(1L)), + + arguments("f %= false", null), + arguments("f %= (byte)3", createValue(1.5f)), + arguments("f %= (short)256", createValue(1.5f)), + arguments("f %= 'a'", createValue(1.5f)), + arguments("f %= 1", createValue(0.5f)), + arguments("f %= 2L", createValue(1.5f)), + arguments("f %= 1.5f", createValue(0.0f)), + arguments("f %= 3.14", createValue(1.5f)), + + arguments("d %= false", null), + arguments("d %= (byte)3", createValue(0.14)), + arguments("d %= (short)256", createValue(3.14)), + arguments("d %= 'a'", createValue(3.14)), + arguments("d %= 1", createValue(0.14)), + arguments("d %= 2L", createValue(1.14)), + arguments("d %= 1.5f", createValue(0.14)), + arguments("d %= 3.04", createValue(0.1)) + ); } protected static Stream pipeEqualsExpression() { return Stream.of( - arguments("b |= false", null, BOOL), - arguments("b |= 1", null, BOOL), - arguments("b |= 2L", null, BOOL), - arguments("b |= 1.5f", null, BOOL), - arguments("b |= 3.14", null, BOOL), - arguments("b |= 'a'", null, BOOL), - arguments("b |= \"test\"", null, BOOL), - - arguments("i |= false", null, INT), - arguments("i |= 1", createValue(1), INT), - arguments("i |= 2L", createValue(3L), INT), - arguments("i |= 1.5f", null, INT), - arguments("i |= 3.14", null, INT), - arguments("i |= 'a'", createValue(97), INT), - arguments("i |= \"test\"", null, INT), - - arguments("l |= false", null, LONG), - arguments("l |= 1", createValue(5L), LONG), - arguments("l |= 2L", createValue(7L), LONG), - arguments("l |= 1.5f", null, LONG), - arguments("l |= 3.14", null, LONG), - arguments("l |= 'a'", createValue(101L), LONG), - arguments("l |= \"test\"", null, LONG), - - arguments("f |= false", null, FLOAT), - arguments("f |= 1", null, FLOAT), - arguments("f |= 2L", null, FLOAT), - arguments("f |= 1.5f", null, FLOAT), - arguments("f |= 3.14", null, FLOAT), - arguments("f |= 'a'", null, FLOAT), - arguments("f |= \"test\"", null, FLOAT), - - arguments("d |= false", null, DOUBLE), - arguments("d |= 1", null, DOUBLE), - arguments("d |= 2L", null, DOUBLE), - arguments("d |= 1.5f", null, DOUBLE), - arguments("d |= 3.14", null, DOUBLE), - arguments("d |= 'a'", null, DOUBLE), - arguments("d |= \"test\"", null, DOUBLE), - - arguments("c |= false", null, CHAR), - arguments("c |= 1", createValue(97), CHAR), - arguments("c |= 2L", createValue(99L), CHAR), - arguments("c |= 1.5f", null, CHAR), - arguments("c |= 3.14", null, CHAR), - arguments("c |= 'a'", createValue(97), CHAR), - arguments("c |= \"test\"", null, CHAR), - - arguments("s |= false", null, STRING), - arguments("s |= 1", null, STRING), - arguments("s |= 2L", null, STRING), - arguments("s |= 1.5f", null, STRING), - arguments("s |= 3.14", null, STRING), - arguments("s |= 'a'", null, STRING), - arguments("s |= \"test\"", null, STRING)); + arguments("b |= true", createValue(true)), + arguments("b |= (byte)3", null), + arguments("b |= (short)256", null), + arguments("b |= 'c'", null), + arguments("b |= 1", null), + arguments("b |= 2L", null), + arguments("b |= 1.5f", null), + arguments("b |= 3.14", null), + + arguments("by |= false", null), + arguments("by |= (byte)3", createValue((byte)3)), + arguments("by |= (short)256", createValue((byte)259)), + arguments("by |= 'a'", createValue((byte)99)), + arguments("by |= 1", createValue((byte)3)), + arguments("by |= 2L", createValue((byte)3)), + arguments("by |= 1.5f", null), + arguments("by |= 3.14", null), + + arguments("s |= false", null), + arguments("s |= (byte)3", createValue((short)259)), + arguments("s |= (short)256", createValue((short)256)), + arguments("s |= 'a'", createValue((short)353)), + arguments("s |= 1", createValue((short)257)), + arguments("s |= 2L", createValue((short)258)), + arguments("s |= 1.5f", null), + arguments("s |= 3.14", null), + + arguments("c |= false", null), + arguments("c |= (byte)3", createValue((char)99)), + arguments("c |= (short)256", createValue((char)353)), + arguments("c |= 'a'", createValue('a')), + arguments("c |= 1", createValue((char)97)), + arguments("c |= 2L", createValue((char)99)), + arguments("c |= 1.5f", null), + arguments("c |= 3.14", null), + + arguments("i |= false", null), + arguments("i |= (byte)3", createValue(3)), + arguments("i |= (short)256", createValue(257)), + arguments("i |= 'a'", createValue(97)), + arguments("i |= 1", createValue(1)), + arguments("i |= 2L", createValue(3)), + arguments("i |= 1.5f", null), + arguments("i |= 3.14", null), + + arguments("l |= false", null), + arguments("l |= (byte)3", createValue(7L)), + arguments("l |= (short)256", createValue(261L)), + arguments("l |= 'a'", createValue(101L)), + arguments("l |= 1", createValue(5L)), + arguments("l |= 4L", createValue(5L)), + arguments("l |= 1.5f", null), + arguments("l |= 3.14", null), + + arguments("f |= false", null), + arguments("f |= (byte)3", null), + arguments("f |= (short)256", null), + arguments("f |= 'a'", null), + arguments("f |= 1", null), + arguments("f |= 2L", null), + arguments("f |= 1.5f", null), + arguments("f |= 3.14", null), + + arguments("d |= false", null), + arguments("d |= (byte)3", null), + arguments("d |= (short)256", null), + arguments("d |= 'a'", null), + arguments("d |= 1", null), + arguments("d |= 2L", null), + arguments("d |= 1.5f", null), + arguments("d |= 3.14", null) + ); } protected static Stream plusEqualsExpression() { return Stream.of( - arguments("b += false", null, BOOL), - arguments("b += 1", null, BOOL), - arguments("b += 2L", null, BOOL), - arguments("b += 1.5f", null, BOOL), - arguments("b += 3.14", null, BOOL), - arguments("b += 'a'", null, BOOL), - arguments("b += \"test\"", null, BOOL), - - arguments("i += false", null, INT), - arguments("i += 1", createValue(2), INT), - arguments("i += 2L", createValue(3L), INT), - arguments("i += 1.5f", createValue(2.5f), INT), - arguments("i += 3.14", createValue(4.14), INT), - arguments("i += 'a'", createValue(98), INT), - arguments("i += \"test\"", null, INT), - - arguments("l += false", null, LONG), - arguments("l += 1", createValue(6L), LONG), - arguments("l += 2L", createValue(7L), LONG), - arguments("l += 1.5f", createValue(6.5f), LONG), - arguments("l += 3.14", createValue(8.14), LONG), - arguments("l += 'a'", createValue(102L), LONG), - arguments("l += \"test\"", null, LONG), - - arguments("f += false", null, FLOAT), - arguments("f += 1", createValue(2.5f), FLOAT), - arguments("f += 2L", createValue(3.5f), FLOAT), - arguments("f += 1.5f", createValue(3.0f), FLOAT), - arguments("f += 3.14", createValue(4.64), FLOAT), - arguments("f += 'a'", createValue(98.5f), FLOAT), - arguments("f += \"test\"", null, FLOAT), - - arguments("d += false", null, DOUBLE), - arguments("d += 1", createValue(4.14), DOUBLE), - arguments("d += 2L", createValue(5.14), DOUBLE), - arguments("d += 1.5f", createValue(4.64), DOUBLE), - arguments("d += 3.14", createValue(6.28), DOUBLE), - arguments("d += 'a'", createValue(100.14), DOUBLE), - arguments("d += \"test\"", null, DOUBLE), - - arguments("c += false", null, CHAR), - arguments("c += 1", createValue(98), CHAR), - arguments("c += 2L", createValue(99L), CHAR), - arguments("c += 1.5f", createValue(98.5f), CHAR), - arguments("c += 3.14", createValue(100.14), CHAR), - arguments("c += 'a'", createValue(194), CHAR), - arguments("c += \"test\"", null, CHAR), - - arguments("s += false", createValue("hellofalse"), STRING), - arguments("s += 1", createValue("hello1"), STRING), - arguments("s += 2L", createValue("hello2"), STRING), - arguments("s += 1.5f", createValue("hello1.5"), STRING), - arguments("s += 3.14", createValue("hello3.14"), STRING), - arguments("s += 'a'", createValue("helloa"), STRING), - arguments("s += \"test\"", createValue("hellotest"), STRING)); + arguments("b += false", null), + arguments("b += (byte)3", null), + arguments("b += (short)256", null), + arguments("b += 1", null), + arguments("b += 2L", null), + arguments("b += 1.5f", null), + arguments("b += 3.14", null), + arguments("b += 'a'", null), + + arguments("by += false", null), + arguments("by += (byte)3", createValue((byte)6)), + arguments("by += (short)256", createValue((byte)3)), + arguments("by += 'a'", createValue((byte)100)), + arguments("by += 1", createValue((byte)4)), + arguments("by += 2L", createValue((byte)5)), + arguments("by += 1.5f", createValue((byte)4)), + arguments("by += 3.14", createValue((byte)6)), + + arguments("s += false", null), + arguments("s += (byte)3", createValue((short)259)), + arguments("s += (short)256", createValue((short)512)), + arguments("s += 'a'", createValue((short)353)), + arguments("s += 1", createValue((short)257)), + arguments("s += 2L", createValue((short)258)), + arguments("s += 1.5f", createValue((short)257)), + arguments("s += 3.14", createValue((short)259)), + + arguments("c += false", null), + arguments("c += (byte)3", createValue('d')), + arguments("c += (short)256", createValue((char)353)), + arguments("c += 'a'", createValue((char)194)), + arguments("c += 1", createValue((char)98)), + arguments("c += 2L", createValue((char)99)), + arguments("c += 1.5f", createValue((char)98)), + arguments("c += 3.14", createValue((char)100)), + + arguments("i += false", null), + arguments("i += (byte)3", createValue(4)), + arguments("i += (short)256", createValue(257)), + arguments("i += 'a'", createValue(98)), + arguments("i += 1", createValue(2)), + arguments("i += 2L", createValue(3)), + arguments("i += 1.5f", createValue(2)), + arguments("i += 3.14", createValue(4)), + + arguments("l += false", null), + arguments("l += (byte)3", createValue(8L)), + arguments("l += (short)256", createValue(261L)), + arguments("l += 'a'", createValue(102L)), + arguments("l += 1", createValue(6L)), + arguments("l += 2L", createValue(7L)), + arguments("l += 1.5f", createValue(6L)), + arguments("l += 3.14", createValue(8L)), + + arguments("f += false", null), + arguments("f += (byte)3", createValue(4.5f)), + arguments("f += (short)256", createValue(257.5f)), + arguments("f += 1", createValue(2.5f)), + arguments("f += 2L", createValue(3.5f)), + arguments("f += 1.5f", createValue(3.0f)), + arguments("f += 3.14", createValue(4.64f)), + arguments("f += 'a'", createValue(98.5f)), + + arguments("d += false", null), + arguments("d += (byte)3", createValue(6.14)), + arguments("d += (short)256", createValue(259.14)), + arguments("d += 'a'", createValue(100.14)), + arguments("d += 1", createValue(4.14)), + arguments("d += 2L", createValue(5.14)), + arguments("d += 1.5f", createValue(4.64)), + arguments("d += 3.14", createValue(6.28)) + ); } protected static Stream roofEqualsExpression() { return Stream.of( - arguments("b ^= false", null, BOOL), - arguments("b ^= 1", null, BOOL), - arguments("b ^= 2L", null, BOOL), - arguments("b ^= 1.5f", null, BOOL), - arguments("b ^= 3.14", null, BOOL), - arguments("b ^= 'a'", null, BOOL), - arguments("b ^= \"test\"", null, BOOL), - - arguments("i ^= false", null, INT), - arguments("i ^= 3", createValue(2), INT), - arguments("i ^= 4L", createValue(5L), INT), - arguments("i ^= 1.5f", null, INT), - arguments("i ^= 3.14", null, INT), - arguments("i ^= 'a'", createValue(96), INT), - arguments("i ^= \"test\"", null, INT), - - arguments("l ^= false", null, LONG), - arguments("l ^= 1", createValue(4L), LONG), - arguments("l ^= 2L", createValue(7L), LONG), - arguments("l ^= 1.5f", null, LONG), - arguments("l ^= 3.14", null, LONG), - arguments("l ^= 'a'", createValue(100L), LONG), - arguments("l ^= \"test\"", null, LONG), - - arguments("f ^= false", null, FLOAT), - arguments("f ^= 1", null, FLOAT), - arguments("f ^= 2L", null, FLOAT), - arguments("f ^= 1.5f", null, FLOAT), - arguments("f ^= 3.14", null, FLOAT), - arguments("f ^= 'a'", null, FLOAT), - arguments("f ^= \"test\"", null, FLOAT), - - arguments("d ^= false", null, DOUBLE), - arguments("d ^= 1", null, DOUBLE), - arguments("d ^= 2L", null, DOUBLE), - arguments("d ^= 1.5f", null, DOUBLE), - arguments("d ^= 3.14", null, DOUBLE), - arguments("d ^= 'a'", null, DOUBLE), - arguments("d ^= \"test\"", null, DOUBLE), - - arguments("c ^= false", null, CHAR), - arguments("c ^= 1", createValue(96), CHAR), - arguments("c ^= 2L", createValue(99L), CHAR), - arguments("c ^= 1.5f", null, CHAR), - arguments("c ^= 3.14", null, CHAR), - arguments("c ^= 'a'", createValue(0), CHAR), - arguments("c ^= \"test\"", null, CHAR), - - arguments("s ^= false", null, STRING), - arguments("s ^= 1", null, STRING), - arguments("s ^= 2L", null, STRING), - arguments("s ^= 1.5f", null, STRING), - arguments("s ^= 3.14", null, STRING), - arguments("s ^= 'a'", null, STRING), - arguments("s ^= \"test\"", null, STRING)); + arguments("b ^= false", createValue(true)), + arguments("b ^= (byte)3", null), + arguments("b ^= (short)256", null), + arguments("b ^= 'c'", null), + arguments("b ^= 1", null), + arguments("b ^= 2L", null), + arguments("b ^= 1.5f", null), + arguments("b ^= 3.14", null), + + arguments("by ^= false", null), + arguments("by ^= (byte)3", createValue((byte)0)), + arguments("by ^= (short)256", createValue((byte)259)), + arguments("by ^= 'a'", createValue((byte)98)), + arguments("by ^= 1", createValue((byte)2)), + arguments("by ^= 2L", createValue((byte)1)), + arguments("by ^= 1.5f", null), + arguments("by ^= 3.14", null), + + arguments("s ^= false", null), + arguments("s ^= (byte)3", createValue((short)259)), + arguments("s ^= (short)256", createValue((short)0)), + arguments("s ^= 'a'", createValue((short)353)), + arguments("s ^= 1", createValue((short)257)), + arguments("s ^= 2L", createValue((short)258)), + arguments("s ^= 1.5f", null), + arguments("s ^= 3.14", null), + + arguments("c ^= false", null), + arguments("c ^= (byte)3", createValue((char)98)), + arguments("c ^= (short)256", createValue((char)353)), + arguments("c ^= 'a'", createValue((char)0)), + arguments("c ^= 1", createValue((char)96)), + arguments("c ^= 2L", createValue((char)99)), + arguments("c ^= 1.5f", null), + arguments("c ^= 3.14", null), + + arguments("i ^= false", null), + arguments("i ^= (byte)3", createValue(2)), + arguments("i ^= (short)256", createValue(257)), + arguments("i ^= 'a'", createValue(96)), + arguments("i ^= 1", createValue(0)), + arguments("i ^= 2L", createValue(3)), + arguments("i ^= 1.5f", null), + arguments("i ^= 3.14", null), + + arguments("l ^= false", null), + arguments("l ^= (byte)3", createValue(6L)), + arguments("l ^= (short)256", createValue(261L)), + arguments("l ^= 'a'", createValue(100L)), + arguments("l ^= 1", createValue(4L)), + arguments("l ^= 4L", createValue(1L)), + arguments("l ^= 1.5f", null), + arguments("l ^= 3.14", null), + + arguments("f ^= false", null), + arguments("f ^= (byte)3", null), + arguments("f ^= (short)256", null), + arguments("f ^= 'a'", null), + arguments("f ^= 1", null), + arguments("f ^= 2L", null), + arguments("f ^= 1.5f", null), + arguments("f ^= 3.14", null), + + arguments("d ^= false", null), + arguments("d ^= (byte)3", null), + arguments("d ^= (short)256", null), + arguments("d ^= 'a'", null), + arguments("d ^= 1", null), + arguments("d ^= 2L", null), + arguments("d ^= 1.5f", null), + arguments("d ^= 3.14", null) + ); } protected static Stream slashEqualsExpression() { return Stream.of( - arguments("b /= false", null, BOOL), - arguments("b /= 1", null, BOOL), - arguments("b /= 2L", null, BOOL), - arguments("b /= 1.5f", null, BOOL), - arguments("b /= 3.14", null, BOOL), - arguments("b /= 'a'", null, BOOL), - arguments("b /= \"test\"", null, BOOL), - - arguments("i /= false", null, INT), - arguments("i /= 0.25f", createValue(4.f), INT), - arguments("i /= 0.4", createValue(2.5), INT), - arguments("i /= 2", createValue(0), INT), - arguments("i /= 5L", createValue(0L), INT), - arguments("i /= 'A'", createValue(0), INT), - arguments("i /= \"test\"", null, INT), - - arguments("l /= false", null, LONG), - arguments("l /= 1.25f", createValue(4.f), LONG), - arguments("l /= 0.4", createValue(12.5), LONG), - arguments("l /= 2", createValue(2L), LONG), - arguments("l /= 5L", createValue(1L), LONG), - arguments("l /= 'A'", createValue(0L), LONG), - arguments("l /= \"test\"", null, LONG), - - arguments("f /= false", null, FLOAT), - arguments("f /= 3", createValue(.5f), FLOAT), - arguments("f /= 2L", createValue(0.75f), FLOAT), - arguments("f /= 0.025f", createValue(60.f), FLOAT), - arguments("f /= 2.5", createValue(.6), FLOAT), - arguments("f /= 'A'", createValue(0.0230769f), FLOAT), - arguments("f /= \"test\"", null, FLOAT), - - arguments("d /= false", null, DOUBLE), - arguments("d /= 1", createValue(3.14), DOUBLE), - arguments("d /= 2L", createValue(1.57), DOUBLE), - arguments("d /= 1.57f", createValue(2.), DOUBLE), - arguments("d /= 0.02", createValue(157.), DOUBLE), - arguments("d /= 'A'", createValue(0.048307692307), DOUBLE), - arguments("d /= \"test\"", null, DOUBLE), - - arguments("c /= false", null, CHAR), - arguments("c /= 1", createValue(97), CHAR), - arguments("c /= 97L", createValue(1L), CHAR), - arguments("c /= 0.25f", createValue(388.f), CHAR), - arguments("c /= 0.4", createValue(242.5), CHAR), - arguments("c /= 'A'", createValue(1), CHAR), - arguments("c /= \"test\"", null, CHAR), - - arguments("s /= false", null, STRING), - arguments("s /= 1", null, STRING), - arguments("s /= 2L", null, STRING), - arguments("s /= 1.5f", null, STRING), - arguments("s /= 3.14", null, STRING), - arguments("s /= 'a'", null, STRING), - arguments("s /= \"test\"", null, STRING)); + arguments("b /= false", null), + arguments("b /= (byte)3", null), + arguments("b /= (short)256", null), + arguments("b /= 'a'", null), + arguments("b /= 1", null), + arguments("b /= 2L", null), + arguments("b /= 1.5f", null), + arguments("b /= 3.14", null), + + arguments("by /= false", null), + arguments("by /= (byte)3", createValue((byte)1)), + arguments("by /= (short)256", createValue((byte)0)), + arguments("by /= 'a'", createValue((byte)0)), + arguments("by /= 1", createValue((byte)3)), + arguments("by /= 2L", createValue((byte)1)), + arguments("by /= 1.5f", createValue((byte)2)), + arguments("by /= 3.14", createValue((byte)0)), + + arguments("s /= false", null), + arguments("s /= (byte)3", createValue((short)85)), + arguments("s /= (short)256", createValue((short)1)), + arguments("s /= 'a'", createValue((short)2)), + arguments("s /= 1", createValue((short)256)), + arguments("s /= 2L", createValue((short)128)), + arguments("s /= 1.5f", createValue((short)170)), + arguments("s /= 3.14", createValue((short)81)), + + arguments("c /= false", null), + arguments("c /= (byte)3", createValue((char)32)), + arguments("c /= (short)256", createValue((char)0)), + arguments("c /= 'a'", createValue((char)1)), + arguments("c /= 1", createValue('a')), + arguments("c /= 2L", createValue((char)48)), + arguments("c /= 1.5f", createValue((char)64)), + arguments("c /= 3.14", createValue((char)30)), + + arguments("i /= false", null), + arguments("i /= (byte)3", createValue(0)), + arguments("i /= (short)256", createValue(0)), + arguments("i /= 'a'", createValue(0)), + arguments("i /= 1", createValue(1)), + arguments("i /= 2L", createValue(0)), + arguments("i /= 1.5f", createValue(0)), + arguments("i /= 3.14", createValue(0)), + + arguments("l /= false", null), + arguments("l /= (byte)3", createValue(1L)), + arguments("l /= (short)256", createValue(0L)), + arguments("l /= 'a'", createValue(0L)), + arguments("l /= 1", createValue(5L)), + arguments("l /= 2L", createValue(2L)), + arguments("l /= 1.5f", createValue(3L)), + arguments("l /= 3.14", createValue(1L)), + + arguments("f /= false", null), + arguments("f /= (byte)3", createValue(0.5f)), + arguments("f /= (short)256", createValue(0.005859375f)), + arguments("f /= 'a'", createValue(0.0154639175f)), + arguments("f /= 1", createValue(1.5f)), + arguments("f /= 2L", createValue(0.75f)), + arguments("f /= 1.5f", createValue(1.0f)), + arguments("f /= 3.14", createValue(0.477707f)), + + arguments("d /= false", null), + arguments("d /= (byte)3", createValue(1.046666666)), + arguments("d /= (short)256", createValue(0.012265625)), + arguments("d /= 'a'", createValue(0.032371134)), + arguments("d /= 1", createValue(3.14)), + arguments("d /= 2L", createValue(1.57)), + arguments("d /= 1.5f", createValue(2.09333333)), + arguments("d /= 3.14", createValue(1.0)) + ); } protected static Stream starEqualsExpression() { return Stream.of( - arguments("b *= false", null, BOOL), - arguments("b *= 1", null, BOOL), - arguments("b *= 2L", null, BOOL), - arguments("b *= 1.5f", null, BOOL), - arguments("b *= 3.14", null, BOOL), - arguments("b *= 'a'", null, BOOL), - arguments("b *= \"test\"", null, BOOL), - - arguments("i *= false", null, INT), - arguments("i *= 0.25f", createValue(0.25f), INT), - arguments("i *= 4.5", createValue(4.5), INT), - arguments("i *= 2", createValue(2), INT), - arguments("i *= 2L", createValue(2L), INT), - arguments("i *= 'A'", createValue(65), INT), - arguments("i *= \"test\"", null, INT), - - arguments("l *= false", null, LONG), - arguments("l *= 0.5f", createValue(2.5f), LONG), - arguments("l *= 0.2", createValue(1.), LONG), - arguments("l *= 2", createValue(10L), LONG), - arguments("l *= 10L", createValue(50L), LONG), - arguments("l *= 'A'", createValue(325L), LONG), - arguments("l *= \"test\"", null, LONG), - - arguments("f *= false", null, FLOAT), - arguments("f *= 3", createValue(4.5f), FLOAT), - arguments("f *= 2L", createValue(3f), FLOAT), - arguments("f *= 0.5f", createValue(.75f), FLOAT), - arguments("f *= 0.5", createValue(.75), FLOAT), - arguments("f *= 'A'", createValue(97.5f), FLOAT), - arguments("f *= \"test\"", null, FLOAT), - - arguments("d *= false", null, DOUBLE), - arguments("d *= 1", createValue(3.14), DOUBLE), - arguments("d *= 2L", createValue(6.28), DOUBLE), - arguments("d *= 0.5f", createValue(1.57), DOUBLE), - arguments("d *= 0.5", createValue(1.57), DOUBLE), - arguments("d *= 'A'", createValue(204.1), DOUBLE), - arguments("d *= \"test\"", null, DOUBLE), - - arguments("c *= false", null, CHAR), - arguments("c *= 2", createValue(194), CHAR), - arguments("c *= 2L", createValue(194L), CHAR), - arguments("c *= 0.25f", createValue(24.25f), CHAR), - arguments("c *= 0.5", createValue(48.5), CHAR), - arguments("c *= 'A'", createValue(6305), CHAR), - arguments("c *= \"test\"", null, CHAR), - - arguments("s *= false", null, STRING), - arguments("s *= 1", null, STRING), - arguments("s *= 2L", null, STRING), - arguments("s *= 1.5f", null, STRING), - arguments("s *= 3.14", null, STRING), - arguments("s *= 'a'", null, STRING), - arguments("s *= \"test\"", null, STRING)); + arguments("b *= false", null), + arguments("b *= (byte)3", null), + arguments("b *= (short)256", null), + arguments("b *= 'a'", null), + arguments("b *= 1", null), + arguments("b *= 2L", null), + arguments("b *= 1.5f", null), + arguments("b *= 3.14", null), + + arguments("by *= false", null), + arguments("by *= (byte)3", createValue((byte)9)), + arguments("by *= (short)256", createValue((byte)0)), + arguments("by *= 'a'", createValue((byte)35)), + arguments("by *= 1", createValue((byte)3)), + arguments("by *= 2L", createValue((byte)6)), + arguments("by *= 1.5f", createValue((byte)4)), + arguments("by *= 3.14", createValue((byte)9)), + + arguments("s *= false", null), + arguments("s *= (byte)3", createValue((short)768)), + arguments("s *= (short)256", createValue((short)0)), + arguments("s *= 'a'", createValue((short)24832)), + arguments("s *= 1", createValue((short)256)), + arguments("s *= 2L", createValue((short)512)), + arguments("s *= 1.5f", createValue((short)384)), + arguments("s *= 3.14", createValue((short)803)), + + arguments("c *= false", null), + arguments("c *= (byte)3", createValue((char)291)), + arguments("c *= (short)256", createValue((char)24832)), + arguments("c *= 'a'", createValue((char)9409)), + arguments("c *= 1", createValue((char)97)), + arguments("c *= 2L", createValue((char)194)), + arguments("c *= 1.5f", createValue((char)145.5f)), + arguments("c *= 3.14", createValue((char)304.58)), + + arguments("i *= false", null), + arguments("i *= (byte)3", createValue(3)), + arguments("i *= (short)256", createValue(256)), + arguments("i *= 'a'", createValue(97)), + arguments("i *= 1", createValue(1)), + arguments("i *= 2L", createValue(2)), + arguments("i *= 1.5f", createValue(1)), + arguments("i *= 3.14", createValue(3)), + + arguments("l *= false", null), + arguments("l *= (byte)3", createValue(15L)), + arguments("l *= (short)256", createValue(1280L)), + arguments("l *= 'a'", createValue(485L)), + arguments("l *= 1", createValue(5L)), + arguments("l *= 2L", createValue(10L)), + arguments("l *= 1.5f", createValue(7L)), + arguments("l *= 3.14", createValue(15L)), + + arguments("f *= false", null), + arguments("f *= (byte)3", createValue(4.5f)), + arguments("f *= (short)256", createValue(384.0f)), + arguments("f *= 'a'", createValue(145.5f)), + arguments("f *= 1", createValue(1.5f)), + arguments("f *= 2L", createValue(3.0f)), + arguments("f *= 1.5f", createValue(2.25f)), + arguments("f *= 3.14", createValue(4.71f)), + + arguments("d *= false", null), + arguments("d *= (byte)3", createValue(9.42)), + arguments("d *= (short)256", createValue(803.84)), + arguments("d *= 'a'", createValue(304.58)), + arguments("d *= 1", createValue(3.14)), + arguments("d *= 2L", createValue(6.28)), + arguments("d *= 1.5f", createValue(4.71)), + arguments("d *= 3.14", createValue(9.8596)) + ); } @ParameterizedTest @@ -714,14 +907,13 @@ protected static Stream starEqualsExpression() { "decPrefixExpression", "andEqualsExpression", "gTGTEqualsExpression", "gTGTGTEqualsExpression", "lTLTEqualsExpression", "minusEqualsExpression", "percentEqualsExpression", "pipeEqualsExpression", "plusEqualsExpression", - "roofEqualsExpression", "slashEqualsExpression", "starEqualsExpression" + "roofEqualsExpression", "slashEqualsExpression", "starEqualsExpression" }) - public void testInterpreter(String expression, Value result, int types) { - init(types); - if (isNull(result)) { - testInvalidExpression(expression); - } else { - testValidExpression(expression, result); - } + public void testInterpreter(String expression, MIValue result) { + if (result == null) { + testInvalidExpression(expression); + } else { + testValidExpression(expression, result); + } } } diff --git a/monticore-grammar/src/test/java/de/monticore/expressions/combineexpressionswithliterals/_visitor/CombineExpressionsWithLiteralsInterpreter.java b/monticore-grammar/src/test/java/de/monticore/expressions/combineexpressionswithliterals/_visitor/CombineExpressionsWithLiteralsInterpreter.java index 6b65b90b87..7bc245bb6e 100644 --- a/monticore-grammar/src/test/java/de/monticore/expressions/combineexpressionswithliterals/_visitor/CombineExpressionsWithLiteralsInterpreter.java +++ b/monticore-grammar/src/test/java/de/monticore/expressions/combineexpressionswithliterals/_visitor/CombineExpressionsWithLiteralsInterpreter.java @@ -3,7 +3,7 @@ import de.monticore.expressions.combineexpressionswithliterals._ast.ASTFoo; import de.monticore.interpreter.ModelInterpreter; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; public class CombineExpressionsWithLiteralsInterpreter extends CombineExpressionsWithLiteralsInterpreterTOP { public CombineExpressionsWithLiteralsInterpreter() { @@ -15,7 +15,7 @@ public CombineExpressionsWithLiteralsInterpreter(ModelInterpreter realThis) { } @Override - public Value interpret(ASTFoo node) { + public MIValue interpret(ASTFoo node) { return node.getExpression().evaluate(getRealThis()); } diff --git a/monticore-grammar/src/test/java/de/monticore/expressions/commonexpressions/_visitor/CommonExpressionsInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/expressions/commonexpressions/_visitor/CommonExpressionsInterpreterTest.java index 3b596d8883..3050cffa20 100644 --- a/monticore-grammar/src/test/java/de/monticore/expressions/commonexpressions/_visitor/CommonExpressionsInterpreterTest.java +++ b/monticore-grammar/src/test/java/de/monticore/expressions/commonexpressions/_visitor/CommonExpressionsInterpreterTest.java @@ -1,17 +1,11 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.expressions.commonexpressions._visitor; -import de.monticore.expressions.AbstractInterpreterTest; -import de.monticore.interpreter.ValueFactory; -import org.junit.jupiter.api.BeforeEach; +import de.monticore.expressions.AbstractExpressionInterpreterTest; +import de.monticore.interpreter.MIValueFactory; import org.junit.jupiter.api.Test; -public class CommonExpressionsInterpreterTest extends AbstractInterpreterTest { - - @BeforeEach - public void before() { - init(127); - } +public class CommonExpressionsInterpreterTest extends AbstractExpressionInterpreterTest { @Test public void testInterpretPlusExpression() { @@ -26,61 +20,56 @@ public void testInterpretPlusExpression() { testInvalidExpression("1.5 + false"); testInvalidExpression("true + 'a'"); testInvalidExpression("'a' + false"); - testValidExpression("true + \"a\"", ValueFactory.createValue("truea")); - testValidExpression("\"a\" + false", ValueFactory.createValue("afalse")); - - testValidExpression("1 + 2", ValueFactory.createValue(3)); - testValidExpression("1L + 2", ValueFactory.createValue(3L)); - testValidExpression("1 + 2L", ValueFactory.createValue(3L)); - testValidExpression("1.5f + 2", ValueFactory.createValue(3.5f)); - testValidExpression("1 + 1.2f", ValueFactory.createValue(2.2f)); - testValidExpression("1.5 + 2", ValueFactory.createValue(3.5)); - testValidExpression("1 + 1.2", ValueFactory.createValue(2.2)); - testValidExpression("'a' + 2", ValueFactory.createValue(99)); - testValidExpression("1 + 'a'", ValueFactory.createValue(98)); - testValidExpression("\"a\" + 2", ValueFactory.createValue("a2")); - testValidExpression("1 + \"a\"", ValueFactory.createValue("1a")); - - testValidExpression("1L + 2L", ValueFactory.createValue(3L)); - testValidExpression("1.2f + 2L", ValueFactory.createValue(3.2f)); - testValidExpression("1L + 1.5f", ValueFactory.createValue(2.5f)); - testValidExpression("1L + 1.2", ValueFactory.createValue(2.2)); - testValidExpression("1.5 + 2L", ValueFactory.createValue(3.5)); - testValidExpression("1L + 'a'", ValueFactory.createValue(98L)); - testValidExpression("'a' + 2L", ValueFactory.createValue(99L)); - testValidExpression("1L + \"a\"", ValueFactory.createValue("1a")); - testValidExpression("\"a\" + 2L", ValueFactory.createValue("a2")); - - testValidExpression("1.2f + 1.5f", ValueFactory.createValue(2.7f)); - testValidExpression("1.2 + 1.5f", ValueFactory.createValue(2.7)); - testValidExpression("1.2f + 1.5", ValueFactory.createValue(2.7)); - testValidExpression("'a' + 1.5f", ValueFactory.createValue(98.5f)); - testValidExpression("1.2f + 'a'", ValueFactory.createValue(98.2f)); - testValidExpression("\"a\" + 1.5f", ValueFactory.createValue("a1.5")); - testValidExpression("1.2f + \"a\"", ValueFactory.createValue("1.2a")); - - testValidExpression("1.2 + 1.5", ValueFactory.createValue(2.7)); - testValidExpression("'a' + 1.5", ValueFactory.createValue(98.5)); - testValidExpression("1.2 + 'a'", ValueFactory.createValue(98.2)); - testValidExpression("\"a\" + 1.5", ValueFactory.createValue("a1.5")); - testValidExpression("1.2 + \"a\"", ValueFactory.createValue("1.2a")); - - testValidExpression("'a' + 'a'", ValueFactory.createValue(194)); - testValidExpression("\"a\" + 'b'", ValueFactory.createValue("ab")); - testValidExpression("'c' + \"a\"", ValueFactory.createValue("ca")); - - testValidExpression("\"a\" + \"b\"", ValueFactory.createValue("ab")); + + testValidExpression("1 + 2", MIValueFactory.createValue(3)); + testValidExpression("1L + 2", MIValueFactory.createValue(3L)); + testValidExpression("1 + 2L", MIValueFactory.createValue(3L)); + testValidExpression("1.5f + 2", MIValueFactory.createValue(3.5f)); + testValidExpression("1 + 1.2f", MIValueFactory.createValue(2.2f)); + testValidExpression("1.5 + 2", MIValueFactory.createValue(3.5)); + testValidExpression("1 + 1.2", MIValueFactory.createValue(2.2)); + testValidExpression("'a' + 2", MIValueFactory.createValue(99)); + testValidExpression("1 + 'a'", MIValueFactory.createValue(98)); + + testValidExpression("1L + 2L", MIValueFactory.createValue(3L)); + testValidExpression("1.2f + 2L", MIValueFactory.createValue(3.2f)); + testValidExpression("1L + 1.5f", MIValueFactory.createValue(2.5f)); + testValidExpression("1L + 1.2", MIValueFactory.createValue(2.2)); + testValidExpression("1.5 + 2L", MIValueFactory.createValue(3.5)); + testValidExpression("1L + 'a'", MIValueFactory.createValue(98L)); + testValidExpression("'a' + 2L", MIValueFactory.createValue(99L)); + + testValidExpression("1.2f + 1.5f", MIValueFactory.createValue(2.7f)); + testValidExpression("1.2 + 1.5f", MIValueFactory.createValue(2.7)); + testValidExpression("1.2f + 1.5", MIValueFactory.createValue(2.7)); + testValidExpression("'a' + 1.5f", MIValueFactory.createValue(98.5f)); + testValidExpression("1.2f + 'a'", MIValueFactory.createValue(98.2f)); + + testValidExpression("1.2 + 1.5", MIValueFactory.createValue(2.7)); + testValidExpression("'a' + 1.5", MIValueFactory.createValue(98.5)); + testValidExpression("1.2 + 'a'", MIValueFactory.createValue(98.2)); + + testValidExpression("'a' + 'a'", MIValueFactory.createValue(194)); } @Test public void testInterpretBracketExpression() { - testValidExpression("(true)", ValueFactory.createValue(true)); - testValidExpression("(1)", ValueFactory.createValue(1)); - testValidExpression("(2L)", ValueFactory.createValue(2L)); - testValidExpression("(2.5f)", ValueFactory.createValue(2.5f)); - testValidExpression("(3.14)", ValueFactory.createValue(3.14)); - testValidExpression("('a')", ValueFactory.createValue('a')); - testValidExpression("(\"abc\")", ValueFactory.createValue("abc")); + testValidExpression("(true)", MIValueFactory.createValue(true)); + testValidExpression("(1)", MIValueFactory.createValue(1)); + testValidExpression("(2L)", MIValueFactory.createValue(2L)); + testValidExpression("(2.5f)", MIValueFactory.createValue(2.5f)); + testValidExpression("(3.14)", MIValueFactory.createValue(3.14)); + testValidExpression("('a')", MIValueFactory.createValue('a')); + } + + @Test + public void testInterpretMinusPrefixExpression() { + testInvalidExpression("-(true)"); + testValidExpression("-(1)", MIValueFactory.createValue(-1)); + testValidExpression("-(2L)", MIValueFactory.createValue(-2L)); + testValidExpression("-(2.5f)", MIValueFactory.createValue(-2.5f)); + testValidExpression("-(3.14)", MIValueFactory.createValue(-3.14)); + testValidExpression("-('a')", MIValueFactory.createValue(-'a')); } @Test @@ -96,50 +85,37 @@ public void testInterpretMinusExpression() { testInvalidExpression("1.5 - false"); testInvalidExpression("true - 'a'"); testInvalidExpression("'a' - false"); - testInvalidExpression("true - \"a\""); - testInvalidExpression("\"a\" - false"); - - testValidExpression("1 - 2", ValueFactory.createValue(-1)); - testValidExpression("1L - 2", ValueFactory.createValue(-1L)); - testValidExpression("1 - 2L", ValueFactory.createValue(-1L)); - testValidExpression("1.5f - 2", ValueFactory.createValue(-0.5f)); - testValidExpression("1 - 1.2f", ValueFactory.createValue(-0.2f)); - testValidExpression("1.5 - 2", ValueFactory.createValue(-0.5)); - testValidExpression("1 - 1.2", ValueFactory.createValue(-0.2)); - testValidExpression("'a' - 2", ValueFactory.createValue(95)); - testValidExpression("1 - 'a'", ValueFactory.createValue(-96)); - testInvalidExpression("\"a\" - 2"); - testInvalidExpression("1 - \"a\""); - - testValidExpression("1L - 2L", ValueFactory.createValue(-1L)); - testValidExpression("1.2f - 2L", ValueFactory.createValue(-0.8f)); - testValidExpression("1L - 1.5f", ValueFactory.createValue(-0.5f)); - testValidExpression("1L - 1.2", ValueFactory.createValue(-0.2)); - testValidExpression("1.5 - 2L", ValueFactory.createValue(-0.5)); - testValidExpression("1L - 'a'", ValueFactory.createValue(-96L)); - testValidExpression("'a' - 2L", ValueFactory.createValue(95L)); - testInvalidExpression("1L - \"a\""); - testInvalidExpression("\"a\" - 2L"); - - testValidExpression("1.2f - 1.5f", ValueFactory.createValue(-0.3f)); - testValidExpression("1.2 - 1.5f", ValueFactory.createValue(-0.3)); - testValidExpression("1.2f - 1.5", ValueFactory.createValue(-0.3)); - testValidExpression("'a' - 1.5f", ValueFactory.createValue(95.5f)); - testValidExpression("1.2f - 'a'", ValueFactory.createValue(-95.8f)); - testInvalidExpression("\"a\" - 1.5f"); - testInvalidExpression("1.2f - \"a\""); - - testValidExpression("1.2 - 1.5", ValueFactory.createValue(-0.3)); - testValidExpression("'a' - 1.5", ValueFactory.createValue(95.5)); - testValidExpression("1.2 - 'a'", ValueFactory.createValue(-95.8)); - testInvalidExpression("\"a\" - 1.5"); - testInvalidExpression("1.2 - \"a\""); - - testValidExpression("'a' - 'a'", ValueFactory.createValue(0)); - testInvalidExpression("\"a\" - 'a'"); - testInvalidExpression("'a' - \"a\""); - - testInvalidExpression("\"a\" - \"a\""); + + + testValidExpression("1 - 2", MIValueFactory.createValue(-1)); + testValidExpression("1L - 2", MIValueFactory.createValue(-1L)); + testValidExpression("1 - 2L", MIValueFactory.createValue(-1L)); + testValidExpression("1.5f - 2", MIValueFactory.createValue(-0.5f)); + testValidExpression("1 - 1.2f", MIValueFactory.createValue(-0.2f)); + testValidExpression("1.5 - 2", MIValueFactory.createValue(-0.5)); + testValidExpression("1 - 1.2", MIValueFactory.createValue(-0.2)); + testValidExpression("'a' - 2", MIValueFactory.createValue(95)); + testValidExpression("1 - 'a'", MIValueFactory.createValue(-96)); + + testValidExpression("1L - 2L", MIValueFactory.createValue(-1L)); + testValidExpression("1.2f - 2L", MIValueFactory.createValue(-0.8f)); + testValidExpression("1L - 1.5f", MIValueFactory.createValue(-0.5f)); + testValidExpression("1L - 1.2", MIValueFactory.createValue(-0.2)); + testValidExpression("1.5 - 2L", MIValueFactory.createValue(-0.5)); + testValidExpression("1L - 'a'", MIValueFactory.createValue(-96L)); + testValidExpression("'a' - 2L", MIValueFactory.createValue(95L)); + + testValidExpression("1.2f - 1.5f", MIValueFactory.createValue(-0.3f)); + testValidExpression("1.2 - 1.5f", MIValueFactory.createValue(-0.3)); + testValidExpression("1.2f - 1.5", MIValueFactory.createValue(-0.3)); + testValidExpression("'a' - 1.5f", MIValueFactory.createValue(95.5f)); + testValidExpression("1.2f - 'a'", MIValueFactory.createValue(-95.8f)); + + testValidExpression("1.2 - 1.5", MIValueFactory.createValue(-0.3)); + testValidExpression("'a' - 1.5", MIValueFactory.createValue(95.5)); + testValidExpression("1.2 - 'a'", MIValueFactory.createValue(-95.8)); + + testValidExpression("'a' - 'a'", MIValueFactory.createValue(0)); } @Test @@ -155,50 +131,36 @@ public void testInterpretMultExpression() { testInvalidExpression("1.5 * false"); testInvalidExpression("true * 'a'"); testInvalidExpression("'a' * false"); - testInvalidExpression("true * \"a\""); - testInvalidExpression("\"a\" * false"); - - testValidExpression("1 * 2", ValueFactory.createValue(2)); - testValidExpression("1L * 2", ValueFactory.createValue(2L)); - testValidExpression("1 * 2L", ValueFactory.createValue(2L)); - testValidExpression("1.5f * 2", ValueFactory.createValue(3.f)); - testValidExpression("1 * 1.2f", ValueFactory.createValue(1.2f)); - testValidExpression("1.5 * 2", ValueFactory.createValue(3.)); - testValidExpression("1 * 1.2", ValueFactory.createValue(1.2)); - testValidExpression("'a' * 2", ValueFactory.createValue(194)); - testValidExpression("1 * 'a'", ValueFactory.createValue(97)); - testInvalidExpression("\"a\" * 2"); - testInvalidExpression("1 * \"a\""); - - testValidExpression("1L * 2L", ValueFactory.createValue(2L)); - testValidExpression("1.2f * 2L", ValueFactory.createValue(2.4f)); - testValidExpression("1L * 1.5f", ValueFactory.createValue(1.5f)); - testValidExpression("1L * 1.2", ValueFactory.createValue(1.2)); - testValidExpression("1.5 * 2L", ValueFactory.createValue(3.0)); - testValidExpression("1L * 'a'", ValueFactory.createValue(97L)); - testValidExpression("'a' * 2L", ValueFactory.createValue(194L)); - testInvalidExpression("1L * \"a\""); - testInvalidExpression("\"a\" * 2L"); - - testValidExpression("1.2f * 1.5f", ValueFactory.createValue(1.8f)); - testValidExpression("1.2 * 1.5f", ValueFactory.createValue(1.8)); - testValidExpression("1.2f * 1.5", ValueFactory.createValue(1.8)); - testValidExpression("'a' * 1.5f", ValueFactory.createValue(145.5f)); - testValidExpression("1.2f * 'a'", ValueFactory.createValue(116.4f)); - testInvalidExpression("\"a\" * 1.5f"); - testInvalidExpression("1.2f * \"a\""); - - testValidExpression("1.2 * 1.5", ValueFactory.createValue(1.8)); - testValidExpression("'a' * 1.5", ValueFactory.createValue(145.5)); - testValidExpression("1.2 * 'a'", ValueFactory.createValue(116.4)); - testInvalidExpression("\"a\" * 1.5"); - testInvalidExpression("1.2 * \"a\""); - - testValidExpression("'a' * 'a'", ValueFactory.createValue(9409)); - testInvalidExpression("\"a\" * 'a'"); - testInvalidExpression("'a' * \"a\""); - - testInvalidExpression("\"a\" * \"a\""); + + testValidExpression("1 * 2", MIValueFactory.createValue(2)); + testValidExpression("1L * 2", MIValueFactory.createValue(2L)); + testValidExpression("1 * 2L", MIValueFactory.createValue(2L)); + testValidExpression("1.5f * 2", MIValueFactory.createValue(3.f)); + testValidExpression("1 * 1.2f", MIValueFactory.createValue(1.2f)); + testValidExpression("1.5 * 2", MIValueFactory.createValue(3.)); + testValidExpression("1 * 1.2", MIValueFactory.createValue(1.2)); + testValidExpression("'a' * 2", MIValueFactory.createValue(194)); + testValidExpression("1 * 'a'", MIValueFactory.createValue(97)); + + testValidExpression("1L * 2L", MIValueFactory.createValue(2L)); + testValidExpression("1.2f * 2L", MIValueFactory.createValue(2.4f)); + testValidExpression("1L * 1.5f", MIValueFactory.createValue(1.5f)); + testValidExpression("1L * 1.2", MIValueFactory.createValue(1.2)); + testValidExpression("1.5 * 2L", MIValueFactory.createValue(3.0)); + testValidExpression("1L * 'a'", MIValueFactory.createValue(97L)); + testValidExpression("'a' * 2L", MIValueFactory.createValue(194L)); + + testValidExpression("1.2f * 1.5f", MIValueFactory.createValue(1.8f)); + testValidExpression("1.2 * 1.5f", MIValueFactory.createValue(1.8)); + testValidExpression("1.2f * 1.5", MIValueFactory.createValue(1.8)); + testValidExpression("'a' * 1.5f", MIValueFactory.createValue(145.5f)); + testValidExpression("1.2f * 'a'", MIValueFactory.createValue(116.4f)); + + testValidExpression("1.2 * 1.5", MIValueFactory.createValue(1.8)); + testValidExpression("'a' * 1.5", MIValueFactory.createValue(145.5)); + testValidExpression("1.2 * 'a'", MIValueFactory.createValue(116.4)); + + testValidExpression("'a' * 'a'", MIValueFactory.createValue(9409)); } @Test @@ -214,50 +176,36 @@ public void testInterpretDivideExpression() { testInvalidExpression("1.5 / false"); testInvalidExpression("true / 'a'"); testInvalidExpression("'a' / false"); - testInvalidExpression("true / \"a\""); - testInvalidExpression("\"a\" / false"); - - testValidExpression("1 / 2", ValueFactory.createValue(0)); - testValidExpression("1L / 2", ValueFactory.createValue(0L)); - testValidExpression("1 / 2L", ValueFactory.createValue(0L)); - testValidExpression("1.5f / 2", ValueFactory.createValue(0.75f)); - testValidExpression("3 / 1.5f", ValueFactory.createValue(2.f)); - testValidExpression("1.5 / 2", ValueFactory.createValue(0.75)); - testValidExpression("3 / 1.5", ValueFactory.createValue(2.)); - testValidExpression("'a' / 2", ValueFactory.createValue(48)); - testValidExpression("1 / 'a'", ValueFactory.createValue(0)); - testInvalidExpression("\"a\" / 2"); - testInvalidExpression("1 / \"a\""); - - testValidExpression("1L / 2L", ValueFactory.createValue(0L)); - testValidExpression("1.2f / 2L", ValueFactory.createValue(0.6f)); - testValidExpression("3L / 1.5f", ValueFactory.createValue(2.f)); - testValidExpression("3L / 1.5", ValueFactory.createValue(2.)); - testValidExpression("3.0 / 2L", ValueFactory.createValue(1.5)); - testValidExpression("1L / 'a'", ValueFactory.createValue(0L)); - testValidExpression("'a' / 2L", ValueFactory.createValue(48L)); - testInvalidExpression("1L / \"a\""); - testInvalidExpression("\"a\" / 2L"); - - testValidExpression("1.2f / 1.5f", ValueFactory.createValue(0.8f)); - testValidExpression("1.2 / 1.5f", ValueFactory.createValue(0.8)); - testValidExpression("1.2f / 1.5", ValueFactory.createValue(0.8)); - testValidExpression("'a' / 0.5f", ValueFactory.createValue(194.f)); - testValidExpression("194.0f / 'a'", ValueFactory.createValue(2.f)); - testInvalidExpression("\"a\" / 1.5f"); - testInvalidExpression("1.2f / \"a\""); - - testValidExpression("1.2 / 1.5", ValueFactory.createValue(0.8)); - testValidExpression("'a' / 2.0", ValueFactory.createValue(48.5)); - testValidExpression("97.0 / 'a'", ValueFactory.createValue(1.)); - testInvalidExpression("\"a\" / 1.5"); - testInvalidExpression("1.2 / \"a\""); - - testValidExpression("'a' / 'a'", ValueFactory.createValue(1)); - testInvalidExpression("\"a\" / 'a'"); - testInvalidExpression("'a' / \"a\""); - - testInvalidExpression("\"a\" / \"a\""); + + testValidExpression("1 / 2", MIValueFactory.createValue(0)); + testValidExpression("1L / 2", MIValueFactory.createValue(0L)); + testValidExpression("1 / 2L", MIValueFactory.createValue(0L)); + testValidExpression("1.5f / 2", MIValueFactory.createValue(0.75f)); + testValidExpression("3 / 1.5f", MIValueFactory.createValue(2.f)); + testValidExpression("1.5 / 2", MIValueFactory.createValue(0.75)); + testValidExpression("3 / 1.5", MIValueFactory.createValue(2.)); + testValidExpression("'a' / 2", MIValueFactory.createValue(48)); + testValidExpression("1 / 'a'", MIValueFactory.createValue(0)); + + testValidExpression("1L / 2L", MIValueFactory.createValue(0L)); + testValidExpression("1.2f / 2L", MIValueFactory.createValue(0.6f)); + testValidExpression("3L / 1.5f", MIValueFactory.createValue(2.f)); + testValidExpression("3L / 1.5", MIValueFactory.createValue(2.)); + testValidExpression("3.0 / 2L", MIValueFactory.createValue(1.5)); + testValidExpression("1L / 'a'", MIValueFactory.createValue(0L)); + testValidExpression("'a' / 2L", MIValueFactory.createValue(48L)); + + testValidExpression("1.2f / 1.5f", MIValueFactory.createValue(0.8f)); + testValidExpression("1.2 / 1.5f", MIValueFactory.createValue(0.8)); + testValidExpression("1.2f / 1.5", MIValueFactory.createValue(0.8)); + testValidExpression("'a' / 0.5f", MIValueFactory.createValue(194.f)); + testValidExpression("194.0f / 'a'", MIValueFactory.createValue(2.f)); + + testValidExpression("1.2 / 1.5", MIValueFactory.createValue(0.8)); + testValidExpression("'a' / 2.0", MIValueFactory.createValue(48.5)); + testValidExpression("97.0 / 'a'", MIValueFactory.createValue(1.)); + + testValidExpression("'a' / 'a'", MIValueFactory.createValue(1)); testInvalidExpression("1 / 0"); testInvalidExpression("'a' / 0"); @@ -280,55 +228,41 @@ public void testInterpretModuloExpression() { testInvalidExpression("1.5 % false"); testInvalidExpression("true % 'a'"); testInvalidExpression("'a' % false"); - testInvalidExpression("true % \"a\""); - testInvalidExpression("\"a\" % false"); - - testValidExpression("1 % 2", ValueFactory.createValue(1)); - testValidExpression("1L % 2", ValueFactory.createValue(1L)); - testValidExpression("1 % 2L", ValueFactory.createValue(1L)); - testValidExpression("1.5f % 2", ValueFactory.createValue(1.5f)); - testValidExpression("1 % 1.2f", ValueFactory.createValue(1.0f)); - testValidExpression("1.5 % 2", ValueFactory.createValue(1.5)); - testValidExpression("1 % 1.2", ValueFactory.createValue(1.0)); - testValidExpression("'a' % 2", ValueFactory.createValue(1)); - testValidExpression("1 % 'a'", ValueFactory.createValue(1)); - testInvalidExpression("\"a\" % 2"); - testInvalidExpression("1 % \"a\""); - - testValidExpression("1L % 2L", ValueFactory.createValue(1L)); - testValidExpression("1.2f % 2L", ValueFactory.createValue(1.2f)); - testValidExpression("1L % 1.5f", ValueFactory.createValue(1.0f)); - testValidExpression("1L % 1.2", ValueFactory.createValue(1.0)); - testValidExpression("1.5 % 2L", ValueFactory.createValue(1.5)); - testValidExpression("1L % 'a'", ValueFactory.createValue(1L)); - testValidExpression("'a' % 2L", ValueFactory.createValue(1L)); - testInvalidExpression("1L % \"a\""); - testInvalidExpression("\"a\" % 2L"); - - testValidExpression("1.2f % 1.5f", ValueFactory.createValue(1.2f)); - testValidExpression("1.2 % 1.5f", ValueFactory.createValue(1.2)); - testValidExpression("1.2f % 1.5", ValueFactory.createValue(1.2)); - testValidExpression("'a' % 1.5f", ValueFactory.createValue(1.0f)); - testValidExpression("1.2f % 'a'", ValueFactory.createValue(1.2f)); - testInvalidExpression("\"a\" % 1.5f"); - testInvalidExpression("1.2f % \"a\""); - - testValidExpression("1.2 % 1.5", ValueFactory.createValue(1.2)); - testValidExpression("'a' % 1.5", ValueFactory.createValue(1.0)); - testValidExpression("1.2 % 'a'", ValueFactory.createValue(1.2)); - testInvalidExpression("\"a\" % 1.5"); - testInvalidExpression("1.2 % \"a\""); - - testValidExpression("'a' % 'a'", ValueFactory.createValue(0)); - testInvalidExpression("\"a\" % 'a'"); - testInvalidExpression("'a' % \"a\""); - - testInvalidExpression("\"a\" % \"a\""); + + testValidExpression("1 % 2", MIValueFactory.createValue(1)); + testValidExpression("1L % 2", MIValueFactory.createValue(1L)); + testValidExpression("1 % 2L", MIValueFactory.createValue(1L)); + testValidExpression("1.5f % 2", MIValueFactory.createValue(1.5f)); + testValidExpression("1 % 1.2f", MIValueFactory.createValue(1.0f)); + testValidExpression("1.5 % 2", MIValueFactory.createValue(1.5)); + testValidExpression("1 % 1.2", MIValueFactory.createValue(1.0)); + testValidExpression("'a' % 2", MIValueFactory.createValue(1)); + testValidExpression("1 % 'a'", MIValueFactory.createValue(1)); + + testValidExpression("1L % 2L", MIValueFactory.createValue(1L)); + testValidExpression("1.2f % 2L", MIValueFactory.createValue(1.2f)); + testValidExpression("1L % 1.5f", MIValueFactory.createValue(1.0f)); + testValidExpression("1L % 1.2", MIValueFactory.createValue(1.0)); + testValidExpression("1.5 % 2L", MIValueFactory.createValue(1.5)); + testValidExpression("1L % 'a'", MIValueFactory.createValue(1L)); + testValidExpression("'a' % 2L", MIValueFactory.createValue(1L)); + + testValidExpression("1.2f % 1.5f", MIValueFactory.createValue(1.2f)); + testValidExpression("1.2 % 1.5f", MIValueFactory.createValue(1.2)); + testValidExpression("1.2f % 1.5", MIValueFactory.createValue(1.2)); + testValidExpression("'a' % 1.5f", MIValueFactory.createValue(1.0f)); + testValidExpression("1.2f % 'a'", MIValueFactory.createValue(1.2f)); + + testValidExpression("1.2 % 1.5", MIValueFactory.createValue(1.2)); + testValidExpression("'a' % 1.5", MIValueFactory.createValue(1.0)); + testValidExpression("1.2 % 'a'", MIValueFactory.createValue(1.2)); + + testValidExpression("'a' % 'a'", MIValueFactory.createValue(0)); } @Test public void testInterpretEqualsExpression() { - testValidExpression("true == false", ValueFactory.createValue(false)); + testValidExpression("true == false", MIValueFactory.createValue(false)); testInvalidExpression("true == 1"); testInvalidExpression("1 == false"); testInvalidExpression("true == 1L"); @@ -339,55 +273,41 @@ public void testInterpretEqualsExpression() { testInvalidExpression("1.5 == false"); testInvalidExpression("true == 'a'"); testInvalidExpression("'a' == false"); - testInvalidExpression("true == \"a\""); - testInvalidExpression("\"a\" == false"); - - testValidExpression("1 == 2", ValueFactory.createValue(false)); - testValidExpression("1L == 2", ValueFactory.createValue(false)); - testValidExpression("1 == 2L", ValueFactory.createValue(false)); - testValidExpression("1.5f == 2", ValueFactory.createValue(false)); - testValidExpression("1 == 1.2f", ValueFactory.createValue(false)); - testValidExpression("1.5 == 2", ValueFactory.createValue(false)); - testValidExpression("1 == 1.2", ValueFactory.createValue(false)); - testValidExpression("'a' == 2", ValueFactory.createValue(false)); - testValidExpression("1 == 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" == 2"); - testInvalidExpression("1 == \"a\""); - - testValidExpression("1L == 2L", ValueFactory.createValue(false)); - testValidExpression("1.2f == 2L", ValueFactory.createValue(false)); - testValidExpression("1L == 1.5f", ValueFactory.createValue(false)); - testValidExpression("1L == 1.2", ValueFactory.createValue(false)); - testValidExpression("1.5 == 2L", ValueFactory.createValue(false)); - testValidExpression("1L == 'a'", ValueFactory.createValue(false)); - testValidExpression("'a' == 2L", ValueFactory.createValue(false)); - testInvalidExpression("1L == \"a\""); - testInvalidExpression("\"a\" == 2L"); - - testValidExpression("1.2f == 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2 == 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2f == 1.5", ValueFactory.createValue(false)); - testValidExpression("'a' == 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2f == 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" == 1.5f"); - testInvalidExpression("1.2f == \"a\""); - - testValidExpression("1.2 == 1.5", ValueFactory.createValue(false)); - testValidExpression("'a' == 1.5", ValueFactory.createValue(false)); - testValidExpression("1.2 == 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" == 1.5"); - testInvalidExpression("1.2 == \"a\""); - - testValidExpression("'a' == 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" == 'a'"); - testInvalidExpression("'a' == \"a\""); - - testInvalidExpression("\"a\" == \"a\""); + + testValidExpression("1 == 2", MIValueFactory.createValue(false)); + testValidExpression("1L == 2", MIValueFactory.createValue(false)); + testValidExpression("1 == 2L", MIValueFactory.createValue(false)); + testValidExpression("1.5f == 2", MIValueFactory.createValue(false)); + testValidExpression("1 == 1.2f", MIValueFactory.createValue(false)); + testValidExpression("1.5 == 2", MIValueFactory.createValue(false)); + testValidExpression("1 == 1.2", MIValueFactory.createValue(false)); + testValidExpression("'a' == 2", MIValueFactory.createValue(false)); + testValidExpression("1 == 'a'", MIValueFactory.createValue(false)); + + testValidExpression("1L == 2L", MIValueFactory.createValue(false)); + testValidExpression("1.2f == 2L", MIValueFactory.createValue(false)); + testValidExpression("1L == 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1L == 1.2", MIValueFactory.createValue(false)); + testValidExpression("1.5 == 2L", MIValueFactory.createValue(false)); + testValidExpression("1L == 'a'", MIValueFactory.createValue(false)); + testValidExpression("'a' == 2L", MIValueFactory.createValue(false)); + + testValidExpression("1.2f == 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2 == 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2f == 1.5", MIValueFactory.createValue(false)); + testValidExpression("'a' == 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2f == 'a'", MIValueFactory.createValue(false)); + + testValidExpression("1.2 == 1.5", MIValueFactory.createValue(false)); + testValidExpression("'a' == 1.5", MIValueFactory.createValue(false)); + testValidExpression("1.2 == 'a'", MIValueFactory.createValue(false)); + + testValidExpression("'a' == 'a'", MIValueFactory.createValue(true)); } @Test public void testInterpretNotEqualsExpression() { - testValidExpression("true != false", ValueFactory.createValue(true)); + testValidExpression("true != false", MIValueFactory.createValue(true)); testInvalidExpression("true != 1"); testInvalidExpression("1 != false"); testInvalidExpression("true != 1L"); @@ -398,50 +318,36 @@ public void testInterpretNotEqualsExpression() { testInvalidExpression("1.5 != false"); testInvalidExpression("true != 'a'"); testInvalidExpression("'a' != false"); - testInvalidExpression("true != \"a\""); - testInvalidExpression("\"a\" != false"); - - testValidExpression("1 != 2", ValueFactory.createValue(true)); - testValidExpression("1L != 2", ValueFactory.createValue(true)); - testValidExpression("1 != 2L", ValueFactory.createValue(true)); - testValidExpression("1.5f != 2", ValueFactory.createValue(true)); - testValidExpression("1 != 1.2f", ValueFactory.createValue(true)); - testValidExpression("1.5 != 2", ValueFactory.createValue(true)); - testValidExpression("1 != 1.2", ValueFactory.createValue(true)); - testValidExpression("'a' != 2", ValueFactory.createValue(true)); - testValidExpression("1 != 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" != 2"); - testInvalidExpression("1 != \"a\""); - - testValidExpression("1L != 2L", ValueFactory.createValue(true)); - testValidExpression("1.2f != 2L", ValueFactory.createValue(true)); - testValidExpression("1L != 1.5f", ValueFactory.createValue(true)); - testValidExpression("1L != 1.2", ValueFactory.createValue(true)); - testValidExpression("1.5 != 2L", ValueFactory.createValue(true)); - testValidExpression("1L != 'a'", ValueFactory.createValue(true)); - testValidExpression("'a' != 2L", ValueFactory.createValue(true)); - testInvalidExpression("1L != \"a\""); - testInvalidExpression("\"a\" != 2L"); - - testValidExpression("1.2f != 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2 != 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2f != 1.5", ValueFactory.createValue(true)); - testValidExpression("'a' != 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2f != 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" != 1.5f"); - testInvalidExpression("1.2f != \"a\""); - - testValidExpression("1.2 != 1.5", ValueFactory.createValue(true)); - testValidExpression("'a' != 1.5", ValueFactory.createValue(true)); - testValidExpression("1.2 != 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" != 1.5"); - testInvalidExpression("1.2 != \"a\""); - - testValidExpression("'a' != 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" != 'a'"); - testInvalidExpression("'a' != \"a\""); - - testInvalidExpression("\"a\" != \"a\""); + + testValidExpression("1 != 2", MIValueFactory.createValue(true)); + testValidExpression("1L != 2", MIValueFactory.createValue(true)); + testValidExpression("1 != 2L", MIValueFactory.createValue(true)); + testValidExpression("1.5f != 2", MIValueFactory.createValue(true)); + testValidExpression("1 != 1.2f", MIValueFactory.createValue(true)); + testValidExpression("1.5 != 2", MIValueFactory.createValue(true)); + testValidExpression("1 != 1.2", MIValueFactory.createValue(true)); + testValidExpression("'a' != 2", MIValueFactory.createValue(true)); + testValidExpression("1 != 'a'", MIValueFactory.createValue(true)); + + testValidExpression("1L != 2L", MIValueFactory.createValue(true)); + testValidExpression("1.2f != 2L", MIValueFactory.createValue(true)); + testValidExpression("1L != 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1L != 1.2", MIValueFactory.createValue(true)); + testValidExpression("1.5 != 2L", MIValueFactory.createValue(true)); + testValidExpression("1L != 'a'", MIValueFactory.createValue(true)); + testValidExpression("'a' != 2L", MIValueFactory.createValue(true)); + + testValidExpression("1.2f != 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2 != 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2f != 1.5", MIValueFactory.createValue(true)); + testValidExpression("'a' != 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2f != 'a'", MIValueFactory.createValue(true)); + + testValidExpression("1.2 != 1.5", MIValueFactory.createValue(true)); + testValidExpression("'a' != 1.5", MIValueFactory.createValue(true)); + testValidExpression("1.2 != 'a'", MIValueFactory.createValue(true)); + + testValidExpression("'a' != 'a'", MIValueFactory.createValue(false)); } @Test @@ -457,50 +363,36 @@ public void testInterpretLessThanExpression() { testInvalidExpression("1.5 < false"); testInvalidExpression("true < 'a'"); testInvalidExpression("'a' < false"); - testInvalidExpression("true < \"a\""); - testInvalidExpression("\"a\" < false"); - - testValidExpression("1 < 2", ValueFactory.createValue(true)); - testValidExpression("1L < 2", ValueFactory.createValue(true)); - testValidExpression("1 < 2L", ValueFactory.createValue(true)); - testValidExpression("1.5f < 2", ValueFactory.createValue(true)); - testValidExpression("1 < 1.2f", ValueFactory.createValue(true)); - testValidExpression("1.5 < 2", ValueFactory.createValue(true)); - testValidExpression("1 < 1.2", ValueFactory.createValue(true)); - testValidExpression("'a' < 2", ValueFactory.createValue(false)); - testValidExpression("1 < 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" < 2"); - testInvalidExpression("1 < \"a\""); - - testValidExpression("1L < 2L", ValueFactory.createValue(true)); - testValidExpression("1.2f < 2L", ValueFactory.createValue(true)); - testValidExpression("1L < 1.5f", ValueFactory.createValue(true)); - testValidExpression("1L < 1.2", ValueFactory.createValue(true)); - testValidExpression("1.5 < 2L", ValueFactory.createValue(true)); - testValidExpression("1L < 'a'", ValueFactory.createValue(true)); - testValidExpression("'a' < 2L", ValueFactory.createValue(false)); - testInvalidExpression("1L < \"a\""); - testInvalidExpression("\"a\" < 2L"); - - testValidExpression("1.2f < 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2 < 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2f < 1.5", ValueFactory.createValue(true)); - testValidExpression("'a' < 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2f < 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" < 1.5f"); - testInvalidExpression("1.2f < \"a\""); - - testValidExpression("1.2 < 1.5", ValueFactory.createValue(true)); - testValidExpression("'a' < 1.5", ValueFactory.createValue(false)); - testValidExpression("1.2 < 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" < 1.5"); - testInvalidExpression("1.2 < \"a\""); - - testValidExpression("'a' < 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" < 'a'"); - testInvalidExpression("'a' < \"a\""); - - testInvalidExpression("\"a\" < \"a\""); + + testValidExpression("1 < 2", MIValueFactory.createValue(true)); + testValidExpression("1L < 2", MIValueFactory.createValue(true)); + testValidExpression("1 < 2L", MIValueFactory.createValue(true)); + testValidExpression("1.5f < 2", MIValueFactory.createValue(true)); + testValidExpression("1 < 1.2f", MIValueFactory.createValue(true)); + testValidExpression("1.5 < 2", MIValueFactory.createValue(true)); + testValidExpression("1 < 1.2", MIValueFactory.createValue(true)); + testValidExpression("'a' < 2", MIValueFactory.createValue(false)); + testValidExpression("1 < 'a'", MIValueFactory.createValue(true)); + + testValidExpression("1L < 2L", MIValueFactory.createValue(true)); + testValidExpression("1.2f < 2L", MIValueFactory.createValue(true)); + testValidExpression("1L < 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1L < 1.2", MIValueFactory.createValue(true)); + testValidExpression("1.5 < 2L", MIValueFactory.createValue(true)); + testValidExpression("1L < 'a'", MIValueFactory.createValue(true)); + testValidExpression("'a' < 2L", MIValueFactory.createValue(false)); + + testValidExpression("1.2f < 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2 < 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2f < 1.5", MIValueFactory.createValue(true)); + testValidExpression("'a' < 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2f < 'a'", MIValueFactory.createValue(true)); + + testValidExpression("1.2 < 1.5", MIValueFactory.createValue(true)); + testValidExpression("'a' < 1.5", MIValueFactory.createValue(false)); + testValidExpression("1.2 < 'a'", MIValueFactory.createValue(true)); + + testValidExpression("'a' < 'a'", MIValueFactory.createValue(false)); } @Test @@ -516,50 +408,36 @@ public void testInterpretGreaterThanExpression() { testInvalidExpression("1.5 > false"); testInvalidExpression("true > 'a'"); testInvalidExpression("'a' > false"); - testInvalidExpression("true > \"a\""); - testInvalidExpression("\"a\" > false"); - - testValidExpression("1 > 2", ValueFactory.createValue(false)); - testValidExpression("1L > 2", ValueFactory.createValue(false)); - testValidExpression("1 > 2L", ValueFactory.createValue(false)); - testValidExpression("1.5f > 2", ValueFactory.createValue(false)); - testValidExpression("1 > 1.2f", ValueFactory.createValue(false)); - testValidExpression("1.5 > 2", ValueFactory.createValue(false)); - testValidExpression("1 > 1.2", ValueFactory.createValue(false)); - testValidExpression("'a' > 2", ValueFactory.createValue(true)); - testValidExpression("1 > 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" > 2"); - testInvalidExpression("1 > \"a\""); - - testValidExpression("1L > 2L", ValueFactory.createValue(false)); - testValidExpression("1.2f > 2L", ValueFactory.createValue(false)); - testValidExpression("1L > 1.5f", ValueFactory.createValue(false)); - testValidExpression("1L > 1.2", ValueFactory.createValue(false)); - testValidExpression("1.5 > 2L", ValueFactory.createValue(false)); - testValidExpression("1L > 'a'", ValueFactory.createValue(false)); - testValidExpression("'a' > 2L", ValueFactory.createValue(true)); - testInvalidExpression("1L > \"a\""); - testInvalidExpression("\"a\" > 2L"); - - testValidExpression("1.2f > 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2 > 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2f > 1.5", ValueFactory.createValue(false)); - testValidExpression("'a' > 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2f > 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" > 1.5f"); - testInvalidExpression("1.2f > \"a\""); - - testValidExpression("1.2 > 1.5", ValueFactory.createValue(false)); - testValidExpression("'a' > 1.5", ValueFactory.createValue(true)); - testValidExpression("1.2 > 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" > 1.5"); - testInvalidExpression("1.2 > \"a\""); - - testValidExpression("'a' > 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" > 'a'"); - testInvalidExpression("'a' > \"a\""); - - testInvalidExpression("\"a\" > \"a\""); + + testValidExpression("1 > 2", MIValueFactory.createValue(false)); + testValidExpression("1L > 2", MIValueFactory.createValue(false)); + testValidExpression("1 > 2L", MIValueFactory.createValue(false)); + testValidExpression("1.5f > 2", MIValueFactory.createValue(false)); + testValidExpression("1 > 1.2f", MIValueFactory.createValue(false)); + testValidExpression("1.5 > 2", MIValueFactory.createValue(false)); + testValidExpression("1 > 1.2", MIValueFactory.createValue(false)); + testValidExpression("'a' > 2", MIValueFactory.createValue(true)); + testValidExpression("1 > 'a'", MIValueFactory.createValue(false)); + + testValidExpression("1L > 2L", MIValueFactory.createValue(false)); + testValidExpression("1.2f > 2L", MIValueFactory.createValue(false)); + testValidExpression("1L > 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1L > 1.2", MIValueFactory.createValue(false)); + testValidExpression("1.5 > 2L", MIValueFactory.createValue(false)); + testValidExpression("1L > 'a'", MIValueFactory.createValue(false)); + testValidExpression("'a' > 2L", MIValueFactory.createValue(true)); + + testValidExpression("1.2f > 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2 > 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2f > 1.5", MIValueFactory.createValue(false)); + testValidExpression("'a' > 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2f > 'a'", MIValueFactory.createValue(false)); + + testValidExpression("1.2 > 1.5", MIValueFactory.createValue(false)); + testValidExpression("'a' > 1.5", MIValueFactory.createValue(true)); + testValidExpression("1.2 > 'a'", MIValueFactory.createValue(false)); + + testValidExpression("'a' > 'a'", MIValueFactory.createValue(false)); } @Test @@ -575,50 +453,36 @@ public void testInterpretGreaterEqualExpression() { testInvalidExpression("1.5 >= false"); testInvalidExpression("true >= 'a'"); testInvalidExpression("'a' >= false"); - testInvalidExpression("true >= \"a\""); - testInvalidExpression("\"a\" >= false"); - - testValidExpression("1 >= 2", ValueFactory.createValue(false)); - testValidExpression("1L >= 2", ValueFactory.createValue(false)); - testValidExpression("1 >= 2L", ValueFactory.createValue(false)); - testValidExpression("1.5f >= 2", ValueFactory.createValue(false)); - testValidExpression("1 >= 1.2f", ValueFactory.createValue(false)); - testValidExpression("1.5 >= 2", ValueFactory.createValue(false)); - testValidExpression("1 >= 1.2", ValueFactory.createValue(false)); - testValidExpression("'a' >= 2", ValueFactory.createValue(true)); - testValidExpression("1 >= 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" >= 2"); - testInvalidExpression("1 >= \"a\""); - - testValidExpression("1L >= 2L", ValueFactory.createValue(false)); - testValidExpression("1.2f >= 2L", ValueFactory.createValue(false)); - testValidExpression("1L >= 1.5f", ValueFactory.createValue(false)); - testValidExpression("1L >= 1.2", ValueFactory.createValue(false)); - testValidExpression("1.5 >= 2L", ValueFactory.createValue(false)); - testValidExpression("1L >= 'a'", ValueFactory.createValue(false)); - testValidExpression("'a' >= 2L", ValueFactory.createValue(true)); - testInvalidExpression("1L >= \"a\""); - testInvalidExpression("\"a\" >= 2L"); - - testValidExpression("1.2f >= 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2 >= 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2f >= 1.5", ValueFactory.createValue(false)); - testValidExpression("'a' >= 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2f >= 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" >= 1.5f"); - testInvalidExpression("1.2f >= \"a\""); - - testValidExpression("1.2 >= 1.5", ValueFactory.createValue(false)); - testValidExpression("'a' >= 1.5", ValueFactory.createValue(true)); - testValidExpression("1.2 >= 'a'", ValueFactory.createValue(false)); - testInvalidExpression("\"a\" >= 1.5"); - testInvalidExpression("1.2 >= \"a\""); - - testValidExpression("'a' >= 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" >= 'a'"); - testInvalidExpression("'a' >= \"a\""); - - testInvalidExpression("\"a\" >= \"a\""); + + testValidExpression("1 >= 2", MIValueFactory.createValue(false)); + testValidExpression("1L >= 2", MIValueFactory.createValue(false)); + testValidExpression("1 >= 2L", MIValueFactory.createValue(false)); + testValidExpression("1.5f >= 2", MIValueFactory.createValue(false)); + testValidExpression("1 >= 1.2f", MIValueFactory.createValue(false)); + testValidExpression("1.5 >= 2", MIValueFactory.createValue(false)); + testValidExpression("1 >= 1.2", MIValueFactory.createValue(false)); + testValidExpression("'a' >= 2", MIValueFactory.createValue(true)); + testValidExpression("1 >= 'a'", MIValueFactory.createValue(false)); + + testValidExpression("1L >= 2L", MIValueFactory.createValue(false)); + testValidExpression("1.2f >= 2L", MIValueFactory.createValue(false)); + testValidExpression("1L >= 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1L >= 1.2", MIValueFactory.createValue(false)); + testValidExpression("1.5 >= 2L", MIValueFactory.createValue(false)); + testValidExpression("1L >= 'a'", MIValueFactory.createValue(false)); + testValidExpression("'a' >= 2L", MIValueFactory.createValue(true)); + + testValidExpression("1.2f >= 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2 >= 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2f >= 1.5", MIValueFactory.createValue(false)); + testValidExpression("'a' >= 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2f >= 'a'", MIValueFactory.createValue(false)); + + testValidExpression("1.2 >= 1.5", MIValueFactory.createValue(false)); + testValidExpression("'a' >= 1.5", MIValueFactory.createValue(true)); + testValidExpression("1.2 >= 'a'", MIValueFactory.createValue(false)); + + testValidExpression("'a' >= 'a'", MIValueFactory.createValue(true)); } @Test @@ -634,85 +498,69 @@ public void testInterpretLessEqualExpression() { testInvalidExpression("1.5 <= false"); testInvalidExpression("true <= 'a'"); testInvalidExpression("'a' <= false"); - testInvalidExpression("true <= \"a\""); - testInvalidExpression("\"a\" <= false"); - - testValidExpression("1 <= 2", ValueFactory.createValue(true)); - testValidExpression("1L <= 2", ValueFactory.createValue(true)); - testValidExpression("1 <= 2L", ValueFactory.createValue(true)); - testValidExpression("1.5f <= 2", ValueFactory.createValue(true)); - testValidExpression("1 <= 1.2f", ValueFactory.createValue(true)); - testValidExpression("1.5 <= 2", ValueFactory.createValue(true)); - testValidExpression("1 <= 1.2", ValueFactory.createValue(true)); - testValidExpression("'a' <= 2", ValueFactory.createValue(false)); - testValidExpression("1 <= 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" <= 2"); - testInvalidExpression("1 <= \"a\""); - - testValidExpression("1L <= 2L", ValueFactory.createValue(true)); - testValidExpression("1.2f <= 2L", ValueFactory.createValue(true)); - testValidExpression("1L <= 1.5f", ValueFactory.createValue(true)); - testValidExpression("1L <= 1.2", ValueFactory.createValue(true)); - testValidExpression("1.5 <= 2L", ValueFactory.createValue(true)); - testValidExpression("1L <= 'a'", ValueFactory.createValue(true)); - testValidExpression("'a' <= 2L", ValueFactory.createValue(false)); - testInvalidExpression("1L <= \"a\""); - testInvalidExpression("\"a\" <= 2L"); - - testValidExpression("1.2f <= 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2 <= 1.5f", ValueFactory.createValue(true)); - testValidExpression("1.2f <= 1.5", ValueFactory.createValue(true)); - testValidExpression("'a' <= 1.5f", ValueFactory.createValue(false)); - testValidExpression("1.2f <= 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" <= 1.5f"); - testInvalidExpression("1.2f <= \"a\""); - - testValidExpression("1.2 <= 1.5", ValueFactory.createValue(true)); - testValidExpression("'a' <= 1.5", ValueFactory.createValue(false)); - testValidExpression("1.2 <= 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" <= 1.5"); - testInvalidExpression("1.2 <= \"a\""); - - testValidExpression("'a' <= 'a'", ValueFactory.createValue(true)); - testInvalidExpression("\"a\" <= 'a'"); - testInvalidExpression("'a' <= \"a\""); - - testInvalidExpression("\"a\" <= \"a\""); + + testValidExpression("1 <= 2", MIValueFactory.createValue(true)); + testValidExpression("1L <= 2", MIValueFactory.createValue(true)); + testValidExpression("1 <= 2L", MIValueFactory.createValue(true)); + testValidExpression("1.5f <= 2", MIValueFactory.createValue(true)); + testValidExpression("1 <= 1.2f", MIValueFactory.createValue(true)); + testValidExpression("1.5 <= 2", MIValueFactory.createValue(true)); + testValidExpression("1 <= 1.2", MIValueFactory.createValue(true)); + testValidExpression("'a' <= 2", MIValueFactory.createValue(false)); + testValidExpression("1 <= 'a'", MIValueFactory.createValue(true)); + + testValidExpression("1L <= 2L", MIValueFactory.createValue(true)); + testValidExpression("1.2f <= 2L", MIValueFactory.createValue(true)); + testValidExpression("1L <= 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1L <= 1.2", MIValueFactory.createValue(true)); + testValidExpression("1.5 <= 2L", MIValueFactory.createValue(true)); + testValidExpression("1L <= 'a'", MIValueFactory.createValue(true)); + testValidExpression("'a' <= 2L", MIValueFactory.createValue(false)); + + testValidExpression("1.2f <= 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2 <= 1.5f", MIValueFactory.createValue(true)); + testValidExpression("1.2f <= 1.5", MIValueFactory.createValue(true)); + testValidExpression("'a' <= 1.5f", MIValueFactory.createValue(false)); + testValidExpression("1.2f <= 'a'", MIValueFactory.createValue(true)); + + testValidExpression("1.2 <= 1.5", MIValueFactory.createValue(true)); + testValidExpression("'a' <= 1.5", MIValueFactory.createValue(false)); + testValidExpression("1.2 <= 'a'", MIValueFactory.createValue(true)); + + testValidExpression("'a' <= 'a'", MIValueFactory.createValue(true)); } @Test public void testInterpretBooleanNotExpression() { testInvalidExpression("~true"); - testValidExpression("~1", ValueFactory.createValue(-2)); - testValidExpression("~-5", ValueFactory.createValue(4)); - testValidExpression("~708", ValueFactory.createValue(-709)); - testValidExpression("~1L", ValueFactory.createValue(-2L)); - testValidExpression("~-5L", ValueFactory.createValue(4L)); - testValidExpression("~708L", ValueFactory.createValue(-709L)); + testValidExpression("~1", MIValueFactory.createValue(-2)); + testValidExpression("~-5", MIValueFactory.createValue(4)); + testValidExpression("~708", MIValueFactory.createValue(-709)); + testValidExpression("~1L", MIValueFactory.createValue(-2L)); + testValidExpression("~-5L", MIValueFactory.createValue(4L)); + testValidExpression("~708L", MIValueFactory.createValue(-709L)); testInvalidExpression("~1.2f"); testInvalidExpression("~1.5"); - testValidExpression("~'a'", ValueFactory.createValue(-98)); - testInvalidExpression("~\"a\""); + testValidExpression("~'a'", MIValueFactory.createValue(-98)); } @Test public void testInterpretLogicalNotExpression() { - testValidExpression("!true", ValueFactory.createValue(false)); - testValidExpression("!false", ValueFactory.createValue(true)); + testValidExpression("!true", MIValueFactory.createValue(false)); + testValidExpression("!false", MIValueFactory.createValue(true)); testInvalidExpression("!1"); testInvalidExpression("!1L"); testInvalidExpression("!1.2f"); testInvalidExpression("!1.5"); testInvalidExpression("!'a'"); - testInvalidExpression("!\"a\""); } @Test public void testInterpretLogicalAndOpExpression() { - testValidExpression("true && true", ValueFactory.createValue(true)); - testValidExpression("false && false", ValueFactory.createValue(false)); - testValidExpression("true && false", ValueFactory.createValue(false)); - testValidExpression("false && true", ValueFactory.createValue(false)); + testValidExpression("true && true", MIValueFactory.createValue(true)); + testValidExpression("false && false", MIValueFactory.createValue(false)); + testValidExpression("true && false", MIValueFactory.createValue(false)); + testValidExpression("false && true", MIValueFactory.createValue(false)); testInvalidExpression("true && 1"); testInvalidExpression("1 && false"); testInvalidExpression("true && 1L"); @@ -723,8 +571,6 @@ public void testInterpretLogicalAndOpExpression() { testInvalidExpression("1.5 && false"); testInvalidExpression("true && 'a'"); testInvalidExpression("'a' && false"); - testInvalidExpression("true && \"a\""); - testInvalidExpression("\"a\" && false"); testInvalidExpression("1 && 2"); testInvalidExpression("1L && 2"); @@ -735,8 +581,6 @@ public void testInterpretLogicalAndOpExpression() { testInvalidExpression("1 && 1.2"); testInvalidExpression("'a' && 2"); testInvalidExpression("1 && 'a'"); - testInvalidExpression("\"a\" && 2"); - testInvalidExpression("1 && \"a\""); testInvalidExpression("1L && 2L"); testInvalidExpression("1.2f && 2L"); @@ -745,36 +589,26 @@ public void testInterpretLogicalAndOpExpression() { testInvalidExpression("1.5 && 2L"); testInvalidExpression("1L && 'a'"); testInvalidExpression("'a' && 2L"); - testInvalidExpression("1L && \"a\""); - testInvalidExpression("\"a\" && 2L"); testInvalidExpression("1.2f && 1.5f"); testInvalidExpression("1.2 && 1.5f"); testInvalidExpression("1.2f && 1.5"); testInvalidExpression("'a' && 1.5f"); testInvalidExpression("1.2f && 'a'"); - testInvalidExpression("\"a\" && 1.5f"); - testInvalidExpression("1.2f && \"a\""); testInvalidExpression("1.2 && 1.5"); testInvalidExpression("'a' && 1.5"); testInvalidExpression("1.2 && 'a'"); - testInvalidExpression("\"a\" && 1.5"); - testInvalidExpression("1.2 && \"a\""); testInvalidExpression("'a' && 'a'"); - testInvalidExpression("\"a\" && 'a'"); - testInvalidExpression("'a' && \"a\""); - - testInvalidExpression("\"a\" && \"a\""); } @Test public void testInterpretLogicalOrOpExpression() { - testValidExpression("true || true", ValueFactory.createValue(true)); - testValidExpression("false || false", ValueFactory.createValue(false)); - testValidExpression("true || false", ValueFactory.createValue(true)); - testValidExpression("false || true", ValueFactory.createValue(true)); + testValidExpression("true || true", MIValueFactory.createValue(true)); + testValidExpression("false || false", MIValueFactory.createValue(false)); + testValidExpression("true || false", MIValueFactory.createValue(true)); + testValidExpression("false || true", MIValueFactory.createValue(true)); testInvalidExpression("true || 1"); testInvalidExpression("1 || false"); testInvalidExpression("true || 1L"); @@ -785,8 +619,6 @@ public void testInterpretLogicalOrOpExpression() { testInvalidExpression("1.5 || false"); testInvalidExpression("true || 'a'"); testInvalidExpression("'a' || false"); - testInvalidExpression("true || \"a\""); - testInvalidExpression("\"a\" || false"); testInvalidExpression("1 || 2"); testInvalidExpression("1L || 2"); @@ -797,8 +629,6 @@ public void testInterpretLogicalOrOpExpression() { testInvalidExpression("1 || 1.2"); testInvalidExpression("'a' || 2"); testInvalidExpression("1 || 'a'"); - testInvalidExpression("\"a\" || 2"); - testInvalidExpression("1 || \"a\""); testInvalidExpression("1L || 2L"); testInvalidExpression("1.2f || 2L"); @@ -807,40 +637,33 @@ public void testInterpretLogicalOrOpExpression() { testInvalidExpression("1.5 || 2L"); testInvalidExpression("1L || 'a'"); testInvalidExpression("'a' || 2L"); - testInvalidExpression("1L || \"a\""); - testInvalidExpression("\"a\" || 2L"); testInvalidExpression("1.2f || 1.5f"); testInvalidExpression("1.2 || 1.5f"); testInvalidExpression("1.2f || 1.5"); testInvalidExpression("'a' || 1.5f"); testInvalidExpression("1.2f || 'a'"); - testInvalidExpression("\"a\" || 1.5f"); - testInvalidExpression("1.2f || \"a\""); testInvalidExpression("1.2 || 1.5"); testInvalidExpression("'a' || 1.5"); testInvalidExpression("1.2 || 'a'"); - testInvalidExpression("\"a\" || 1.5"); - testInvalidExpression("1.2 || \"a\""); testInvalidExpression("'a' || 'a'"); - testInvalidExpression("\"a\" || 'a'"); - testInvalidExpression("'a' || \"a\""); - - testInvalidExpression("\"a\" || \"a\""); } @Test public void testConditionalExpression() { - testValidExpression("(true) ? 1 : 2", ValueFactory.createValue(1)); - testValidExpression("5 <= 10%5 || !true && true ? (3 + 2 * 2) / 14.0 : ((1 > 2L) && ('z' <= 15.243f))", ValueFactory.createValue(false)); + testValidExpression("(true) ? 1 : 2", MIValueFactory.createValue(1)); + + // has result of union-type + testValidExpression("5 <= 10%5 || !true && true ? (3 + 2 * 2) / 14.0 : ((1 > 2L) && ('z' <= 15.243f))", + MIValueFactory.createValue(false)); } @Test public void testCombinedExpressions() { - testValidExpression("((1 > 2L) && ('z' <= 15.243f)) || true", ValueFactory.createValue(true)); - testValidExpression("(3 + 2 * 2) / 14.0", ValueFactory.createValue(0.5)); - testValidExpression("true && false || !true", ValueFactory.createValue(false)); + testValidExpression("((1 > 2L) && ('z' <= 15.243f)) || true", MIValueFactory.createValue(true)); + testValidExpression("(3 + 2 * 2) / 14.0", MIValueFactory.createValue(0.5)); + testValidExpression("true && false || !true", MIValueFactory.createValue(false)); } } diff --git a/monticore-grammar/src/test/java/de/monticore/expressions/lambdaexpressions/LambdaExpressionsInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/expressions/lambdaexpressions/LambdaExpressionsInterpreterTest.java new file mode 100644 index 0000000000..b3f58c4344 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/expressions/lambdaexpressions/LambdaExpressionsInterpreterTest.java @@ -0,0 +1,42 @@ +package de.monticore.expressions.lambdaexpressions; + +import de.monticore.expressions.AbstractExpressionInterpreterTest; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import org.junit.jupiter.api.Test; + +import static de.monticore.interpreter.MIValueFactory.createValue; + +public class LambdaExpressionsInterpreterTest extends AbstractExpressionInterpreterTest { + + @Test + public void testSimpleLambda() { + // testValidExpression("(() -> \"a\"+1)()", createValue("a1")); + // #0 : 0x57037 Plus operation with result of type R"(a)(.*)" is not supported. + // This default method is called and the we get an error + // /** + // * Am I primitive? (such as "int") + // * (default: no) + // */ + // public boolean isPrimitive() { + // return false; + // } + + // testValidExpression("(() -> a+1)()", createValue("1")); + // #0 : StringReader:<1,7> - StringReader:<1,8>: 0xFD118 could not find symbol for expression "a" + // #1 : Invalid Model: (() -> a+1)() + + //testValidExpression("(() -> \"a\"+1)()", createValue("a1")); + testValidExpression("(() -> 1)()", createValue(1)); + testValidExpression("(() -> () -> 2)()()", createValue(2)); + testValidExpression("((long a) -> a + 1)(41L)", createValue(42L)); + + testValidExpression("((long a) -> (byte b) -> a + b)(41L)((byte)28)", createValue(69L)); + testValidExpression("((long a, byte b) -> a + b)(41L,(byte)28)", createValue(69L)); + + testValidExpression("(() -> () -> (int a) -> () -> () -> a)()()(42)()()", createValue(42)); + + testValidExpression("((byte b) -> (char c) -> b + c)((byte)25)('a') == 'z'", createValue(true)); + } + +} + diff --git a/monticore-grammar/src/test/java/de/monticore/expressions/streamexpressions/parser/StreamExpressionsInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/expressions/streamexpressions/parser/StreamExpressionsInterpreterTest.java new file mode 100644 index 0000000000..69d603d075 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/expressions/streamexpressions/parser/StreamExpressionsInterpreterTest.java @@ -0,0 +1,17 @@ +package de.monticore.expressions.streamexpressions.parser; + +import de.monticore.expressions.AbstractExpressionInterpreterTest; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static de.monticore.interpreter.MIValueFactory.createValue; + +public class StreamExpressionsInterpreterTest extends AbstractExpressionInterpreterTest { + + @Test + public void testSimpleLambda() throws IOException { + testValidExpression("(() -> 1)()", createValue(1)); + } + +} diff --git a/monticore-grammar/src/test/java/de/monticore/ocl/setexpressions/_visitor/SetExpressionsInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/ocl/setexpressions/_visitor/SetExpressionsInterpreterTest.java new file mode 100644 index 0000000000..3f4337cd9a --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/ocl/setexpressions/_visitor/SetExpressionsInterpreterTest.java @@ -0,0 +1,43 @@ +package de.monticore.ocl.setexpressions._visitor; + +import de.monticore.expressions.AbstractExpressionInterpreterTest; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Set; + +import static de.monticore.interpreter.MIValueFactory.createValue; + +public class SetExpressionsInterpreterTest extends AbstractExpressionInterpreterTest { + + @Test + public void testInterpretSetEnumerationExpression() { + testInvalidExpression("1..2"); + + testValidExpression("[1..7]", + createValue(List.of(1, 2, 3, 4, 5, 6, 7))); + testValidExpression("{1..10}", + createValue(Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))); + } + + @Test + public void testInterpretSetComprehensionExpression() { + testInvalidExpression("{| x in [1..2]}"); + testInvalidExpression("{x | }"); + testInvalidExpression("{x | x in [1..2], x = x}"); + + testValidExpression("{x | x in [1..3]}", createValue(Set.of(1, 2, 3))); + testValidExpression("[x * x | x in [1..3]]", + createValue(List.of(1, 4, 9))); + + testValidExpression("{x | x in [1..3], x % 2 == 1}", + createValue(Set.of(1, 3))); + + testValidExpression("{x * y | x in [1..3], y in [1..2], x != y}", + createValue(Set.of(2, 3, 6))); + + testValidExpression("{y | x in [1..3], int y = x * x * x}", + createValue(Set.of(1, 8, 27))); + } + +} diff --git a/monticore-grammar/src/test/java/de/monticore/statements/AbstractStatementInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/statements/AbstractStatementInterpreterTest.java new file mode 100644 index 0000000000..066fef2ea7 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/statements/AbstractStatementInterpreterTest.java @@ -0,0 +1,182 @@ +package de.monticore.statements; + +import de.monticore.AbstractInterpreterTest; +import de.monticore.expressions.lambdaexpressions._symboltable.LambdaExpressionsSTCompleteTypes2; +import de.monticore.interpreter.MIValue; +import de.monticore.ocl.oclexpressions.symboltable.OCLExpressionsSymbolTableCompleter; +import de.monticore.ocl.setexpressions.symboltable.SetExpressionsSymbolTableCompleter; +import de.monticore.statements.combinestatementswithexpressions.CombineStatementsWithExpressionsMill; +import de.monticore.statements.combinestatementswithexpressions._parser.CombineStatementsWithExpressionsParser; +import de.monticore.statements.combinestatementswithexpressions._symboltable.ICombineStatementsWithExpressionsArtifactScope; +import de.monticore.statements.combinestatementswithexpressions._visitor.CombineStatementsWithExpressionsInterpreter; +import de.monticore.statements.combinestatementswithexpressions._visitor.CombineStatementsWithExpressionsTraverser; +import de.monticore.statements.mccommonstatements._symboltable.MCCommonStatementsSymTabCompletion; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCBlockStatement; +import de.monticore.statements.mcvardeclarationstatements._symboltable.MCVarDeclarationStatementsSymTabCompletion; +import de.monticore.symbols.oosymbols.OOSymbolsMill; +import de.monticore.types.check.IDerive; +import de.monticore.types.check.ISynthesize; +import de.monticore.types.check.types3wrapper.TypeCheck3AsIDerive; +import de.monticore.types.check.types3wrapper.TypeCheck3AsISynthesize; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.util.DefsTypesForTests; +import de.monticore.visitor.ITraverser; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.BeforeEach; + +import java.io.IOException; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Abstract class for tests that use CombineStatementsWithExpressions. + */ +public abstract class AbstractStatementInterpreterTest extends AbstractInterpreterTest { + + @Override + @BeforeEach + public void init() { + parserSupplier = CombineStatementsWithExpressionsMill::parser; + resetMill = CombineStatementsWithExpressionsMill::reset; + initMill = CombineStatementsWithExpressionsMill::init; + + super.init(); + + interpreter = new CombineStatementsWithExpressionsInterpreter(); + } + + /** + * Parses and interprets a given model. + * @param model model to parse and interpret + * @return result of interpretation + */ + protected MIValue testValidModel(String model) { + Log.clearFindings(); + Optional astNodeOpt = Optional.empty(); + try { + astNodeOpt = ((CombineStatementsWithExpressionsParser)parser).parse_String(model); + } catch (IOException e) { + System.out.println(e.getMessage()); + fail(); + } + + if (!Log.getFindings().isEmpty()) { + Log.printFindings(); + fail(); + } + assertTrue(astNodeOpt.isPresent()); + + OOSymbolsMill.reset(); + OOSymbolsMill.init(); + CombineStatementsWithExpressionsMill.reset(); + CombineStatementsWithExpressionsMill.init(); + CombineStatementsWithExpressionsMill.globalScope().clear(); + + DefsTypesForTests.setup(); + + ICombineStatementsWithExpressionsArtifactScope rootScope = + CombineStatementsWithExpressionsMill.scopesGenitorDelegator() + .createFromAST(astNodeOpt.get()); + + rootScope.setName("root"); + + astNodeOpt.get().accept(getSymbolTableCompleter()); + + MIValue interpretationResult = astNodeOpt.get().evaluate(interpreter); + + assertNotNull(interpretationResult); + if (!Log.getFindings().isEmpty()) { + Log.printFindings(); + fail(); + } + + assertTrue(interpretationResult.isReturn() || interpretationResult.isVoid()); + if (interpretationResult.isReturn()) { + interpretationResult = interpretationResult.asReturnValue(); + } + + return interpretationResult; + } + + protected void setupSymbolTableCompleter( + ITraverser typeMapTraverser, Type4Ast type4Ast) { + CombineStatementsWithExpressionsTraverser combinedScopesCompleter = + CombineStatementsWithExpressionsMill.traverser(); + IDerive deriver = new TypeCheck3AsIDerive(); + ISynthesize synthesizer = new TypeCheck3AsISynthesize(); + combinedScopesCompleter.add4LambdaExpressions( + new LambdaExpressionsSTCompleteTypes2( + typeMapTraverser, + getType4Ast() + ) + ); + OCLExpressionsSymbolTableCompleter oclExprCompleter = + new OCLExpressionsSymbolTableCompleter(); + oclExprCompleter.setDeriver(deriver); + oclExprCompleter.setSynthesizer(synthesizer); + combinedScopesCompleter.add4OCLExpressions(oclExprCompleter); + combinedScopesCompleter.setOCLExpressionsHandler(oclExprCompleter); + + SetExpressionsSymbolTableCompleter setExprCompleter = + new SetExpressionsSymbolTableCompleter(); + setExprCompleter.setDeriver(deriver); + setExprCompleter.setSynthesizer(synthesizer); + combinedScopesCompleter.add4SetExpressions(setExprCompleter); + + MCVarDeclarationStatementsSymTabCompletion varDeclCompleter = + new MCVarDeclarationStatementsSymTabCompletion(); + combinedScopesCompleter.add4MCVarDeclarationStatements(varDeclCompleter); + + MCCommonStatementsSymTabCompletion commonStmtCompleter = + new MCCommonStatementsSymTabCompletion(); + combinedScopesCompleter.add4MCCommonStatements(commonStmtCompleter); + + combinedScopesCompleter.setSetExpressionsHandler(setExprCompleter); + symbolTableCompleter = combinedScopesCompleter; + scopeGenitor = combinedScopesCompleter; + } + + protected void testInvalidModel(String model) { + Log.clearFindings(); + Optional astNodeOpt = Optional.empty(); + try { + astNodeOpt = ((CombineStatementsWithExpressionsParser)parser).parse_String(model); + } catch (IOException e) { + System.out.println(e.getMessage()); + return; + } + + if (!Log.getFindings().isEmpty() || !astNodeOpt.isPresent()) { + return; + } + + OOSymbolsMill.reset(); + OOSymbolsMill.init(); + CombineStatementsWithExpressionsMill.reset(); + CombineStatementsWithExpressionsMill.init(); + CombineStatementsWithExpressionsMill.globalScope().clear(); + + DefsTypesForTests.setup(); + + ICombineStatementsWithExpressionsArtifactScope rootScope = + CombineStatementsWithExpressionsMill.scopesGenitorDelegator() + .createFromAST(astNodeOpt.get()); + + rootScope.setName("root"); + + astNodeOpt.get().accept(getSymbolTableCompleter()); + + MIValue interpretationResult = astNodeOpt.get().evaluate(interpreter); + + assertNotNull(interpretationResult); // this should not happen even if the model is invalid + if (!Log.getFindings().isEmpty()) { + return; + } + + fail("Expected an error but interpretation succeeded with result of " + + interpretationResult.printType() + " (" + + interpretationResult.printValue() + ")."); + } + +} diff --git a/monticore-grammar/src/test/java/de/monticore/statements/combinestatementswithexpressions/_visitor/CombineStatementsWithExpressionsInterpreter.java b/monticore-grammar/src/test/java/de/monticore/statements/combinestatementswithexpressions/_visitor/CombineStatementsWithExpressionsInterpreter.java new file mode 100644 index 0000000000..ff1f20fc77 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/statements/combinestatementswithexpressions/_visitor/CombineStatementsWithExpressionsInterpreter.java @@ -0,0 +1,17 @@ +package de.monticore.statements.combinestatementswithexpressions._visitor; + +import de.monticore.interpreter.ModelInterpreter; + +public class CombineStatementsWithExpressionsInterpreter extends CombineStatementsWithExpressionsInterpreterTOP { + + public CombineStatementsWithExpressionsInterpreter() { + super(); + } + + public CombineStatementsWithExpressionsInterpreter(ModelInterpreter realThis) { + super(realThis); + } + + + +} diff --git a/monticore-grammar/src/test/java/de/monticore/statements/combinestatementswithexpressions/_visitor/CombineStatementsWithExpressionsInterpreterTest.java b/monticore-grammar/src/test/java/de/monticore/statements/combinestatementswithexpressions/_visitor/CombineStatementsWithExpressionsInterpreterTest.java new file mode 100644 index 0000000000..bef7f503a8 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/statements/combinestatementswithexpressions/_visitor/CombineStatementsWithExpressionsInterpreterTest.java @@ -0,0 +1,172 @@ +package de.monticore.statements.combinestatementswithexpressions._visitor; + +import de.monticore.interpreter.MIValue; +import de.monticore.statements.AbstractStatementInterpreterTest; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static de.monticore.interpreter.MIValueFactory.createValue; + +public class CombineStatementsWithExpressionsInterpreterTest + extends AbstractStatementInterpreterTest { + + @Test + public void testVarDeclarationStatement() { + testValidModel("int i = 0;"); + assertValueEquals(createValue(0), loadVariable("i")); + + testValidModel("int j = 1, k = 2;"); + assertValueEquals(createValue(1), loadVariable("j")); + assertValueEquals(createValue(2), loadVariable("k")); + } + + @Test + public void testJavaBlockStatement() { + MIValue result = testValidModel( + "{ \n" + + " int i = 0; \n" + + " int j = 1; \n" + + " { \n" + + " int k = 2 * j; \n" + + " k += 40; \n" + + " j = k; \n" + + " } \n" + + " return [i, j]; \n" + + "} " + ); + assertValueEquals(createValue(List.of(0, 42)), result); + } + + @Test + public void testCommonWhileStatement() { + MIValue result = testValidModel( + "{ \n" + + " int i = 255, count = 0; \n" + + " while (i != 0) { \n" + + " i /= 2; \n" + + " count++; \n" + + " } \n" + + " return count; \n" + + "} " + ); + assertValueEquals(createValue(8), result); + + testInvalidModel("while (2);"); + } + + @Test + public void testCommonDoWhileStatement() { + MIValue result = testValidModel( + "{ \n" + + " int i = 0, count = 0; \n" + + " do { \n" + + " i /= 2; \n" + + " count++; \n" + + " } while (false); \n" + + " return count; \n" + + "} " + ); + assertValueEquals(createValue(1), result); + + testInvalidModel("do; while (2);"); + } + + @Test + public void testCommonForStatement() { + MIValue result = testValidModel( + "{ \n" + + " int count = 0; \n" + + " for (int i = 0; i < 10; i++) { \n" + + " count++; \n" + + " } \n" + + " return count; \n" + + "} " + ); + assertValueEquals(createValue(10), result); + + testInvalidModel("for (;);"); + } + + @Test + public void testForEachStatement() { + MIValue result = testValidModel( + "{ \n" + + " int sum = 0; \n" + + " for (int i : [1..4]) { \n" + + " sum += i; \n" + + " } \n" + + " return sum; \n" + + "}" + ); + assertValueEquals(createValue(10), result); + + testInvalidModel("for (int i : 1);"); + } + + @Test + public void testContinueStatement() { + MIValue result = testValidModel( + "{ \n" + + " int count = 0; \n" + + " for (int i = 0; i < 10; i++) { \n" + + " if (i % 2 != 0) { \n" + + " continue; \n" + + " } \n" + + " count++; \n" + + " } \n" + + " return count; \n" + + "} " + ); + assertValueEquals(createValue(5), result); + + } + + @Test + public void testBreakStatement() { + MIValue result = testValidModel( + "{ \n" + + " int count = 0; \n" + + " for (int i = 0; i < 10; i++) { \n" + + " count++; \n" + + " if (i > 5) { \n" + + " break; \n" + + " } \n" + + " } \n" + + " return count; \n" + + "} " + ); + assertValueEquals(createValue(7), result); + } + + @Test + public void testLeibnizEfficiency() { + long startTime = System.nanoTime(); + MIValue result = testValidModel( + "{ \n" + + " double pi = 1; \n" + + " double x = 1; \n" + + " for (int i = 2; i < 100002; i++) { \n" + + " x = x * -1; \n" + + " pi = pi + x / (2 * i - 1); \n" + + " } \n" + + " pi = pi * 4; \n" + + " return pi; \n" + + "} " + ); + System.out.println(result.asDouble()); + long endTime = System.nanoTime(); + System.out.println("Elapsed time: " + ((endTime - startTime) / 1000000) + " ms"); + /* Iterations | Elapsed Time + ------------|-------------- + 100 | 1266 ms + 1k | 1300 ms + 10k | 1371 ms + 100k | 1792 ms + 1M | 3581 ms + 10M | 19059 ms + 100M | 171227 ms + */ + } + +} diff --git a/monticore-grammar/src/test/java/de/monticore/symbols/basicsymbols/_symboltable/BasicSymbolsStereoinfoDeSerTest.java b/monticore-grammar/src/test/java/de/monticore/symbols/basicsymbols/_symboltable/BasicSymbolsStereoinfoDeSerTest.java index c90ac866cb..5390807d86 100644 --- a/monticore-grammar/src/test/java/de/monticore/symbols/basicsymbols/_symboltable/BasicSymbolsStereoinfoDeSerTest.java +++ b/monticore-grammar/src/test/java/de/monticore/symbols/basicsymbols/_symboltable/BasicSymbolsStereoinfoDeSerTest.java @@ -1,7 +1,7 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.symbols.basicsymbols._symboltable; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.monticore.symboltable.serialization.json.JsonElement; import de.monticore.symboltable.serialization.json.JsonElementFactory; @@ -88,7 +88,7 @@ void shouldDeserializeStereoInfoWithoutValueInOtherPackage() { BasicSymbolsMill.globalScope().addSubScope(artifactScope); // When - Map.Entry> deserialized = + Map.Entry> deserialized = StereoinfoDeSer.deserialize(jsonStereoInfo, BasicSymbolsMill.globalScope()); // Then @@ -119,7 +119,7 @@ void shouldDeserializeStereoInfoWithoutValueInSamePackage() { commonScope.add(stereoSym); // When - Map.Entry> deserialized = + Map.Entry> deserialized = StereoinfoDeSer.deserialize(jsonStereoInfo, commonScope); // Then diff --git a/monticore-grammar/src/test/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbolSurrogateTest.java b/monticore-grammar/src/test/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbolSurrogateTest.java index 662dcf3393..19294ddc81 100644 --- a/monticore-grammar/src/test/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbolSurrogateTest.java +++ b/monticore-grammar/src/test/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbolSurrogateTest.java @@ -2,7 +2,7 @@ package de.monticore.symbols.basicsymbols._symboltable; import de.monticore.ast.ASTNode; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.monticore.symboltable.IScope; import de.monticore.symboltable.ISymbol; @@ -330,7 +330,7 @@ public IScope getEnclosingScope() { public void setAccessModifier(AccessModifier accessModifier) { } @Override - public Map> getStereoinfo() { + public Map> getStereoinfo() { return null; } @Override diff --git a/monticore-grammar/src/test/java/de/monticore/types3/AbstractTypeTest.java b/monticore-grammar/src/test/java/de/monticore/types3/AbstractTypeTest.java index da6d4c0122..195a3dc14f 100644 --- a/monticore-grammar/src/test/java/de/monticore/types3/AbstractTypeTest.java +++ b/monticore-grammar/src/test/java/de/monticore/types3/AbstractTypeTest.java @@ -6,8 +6,8 @@ import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; - import java.util.stream.Collectors; /** @@ -17,6 +17,17 @@ @Deprecated(forRemoval = true) public class AbstractTypeTest { + @BeforeEach + public void initLog() { + LogStub.init(); + Log.enableFailQuick(false); + } + + protected static void assertNoFindings() { + Assertions.assertTrue(Log.getFindings().isEmpty(), "Expected no Log findings, but got:" + + System.lineSeparator() + getAllFindingsAsString()); + } + /** * @return all findings as one String */ @@ -27,10 +38,6 @@ protected static String getAllFindingsAsString() { ; } - protected static void assertNoFindings() { - MCAssertions.assertNoFindings(); - } - @BeforeEach public void initAbstract() { defaultInitAbstract(); diff --git a/monticore-grammar/src/test/java/de/monticore/types3/AbstractTypeVisitorTest.java b/monticore-grammar/src/test/java/de/monticore/types3/AbstractTypeVisitorTest.java index 54beb7b225..b1ba336eb7 100644 --- a/monticore-grammar/src/test/java/de/monticore/types3/AbstractTypeVisitorTest.java +++ b/monticore-grammar/src/test/java/de/monticore/types3/AbstractTypeVisitorTest.java @@ -198,6 +198,7 @@ protected void generateScopes(ASTExpression expr) { ICombineExpressionsWithLiteralsArtifactScope rootScope = CombineExpressionsWithLiteralsMill.scopesGenitorDelegator() .createFromAST(rootNode); + rootScope.setName("fooRoot"); // complete the symbol table expr.accept(getSymbolTableCompleter()); diff --git a/monticore-runtime/src/main/java/de/monticore/ast/ASTNode.java b/monticore-runtime/src/main/java/de/monticore/ast/ASTNode.java index 8d9dcebbc0..263fd730d4 100644 --- a/monticore-runtime/src/main/java/de/monticore/ast/ASTNode.java +++ b/monticore-runtime/src/main/java/de/monticore/ast/ASTNode.java @@ -2,8 +2,8 @@ package de.monticore.ast; -import de.monticore.interpreter.ModelInterpreter; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.IModelInterpreter; +import de.monticore.interpreter.MIValue; import de.monticore.symboltable.IScope; import de.monticore.visitor.ITraverser; import de.se_rwth.commons.SourcePosition; @@ -679,7 +679,7 @@ default void accept (ITraverser visitor) { visitor.handle(this); } - default Value evaluate(ModelInterpreter interpreter) { + default MIValue evaluate(IModelInterpreter interpreter) { return interpreter.interpret(this); } } diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/IMIScope.java b/monticore-runtime/src/main/java/de/monticore/interpreter/IMIScope.java new file mode 100644 index 0000000000..6a2773a974 --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/IMIScope.java @@ -0,0 +1,4 @@ +package de.monticore.interpreter; + +public interface IMIScope { +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/IModelInterpreter.java b/monticore-runtime/src/main/java/de/monticore/interpreter/IModelInterpreter.java new file mode 100644 index 0000000000..7a7f4959ed --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/IModelInterpreter.java @@ -0,0 +1,19 @@ +package de.monticore.interpreter; + +import de.monticore.ast.ASTNode; +import de.monticore.interpreter.values.ErrorMIValue; +import de.se_rwth.commons.logging.Log; + +public interface IModelInterpreter { + + default MIValue interpret(ASTNode n) { + String errorMsg = "0x57073 No implementation of ASTNode of type " + n.toString(); + Log.error(errorMsg); + return new ErrorMIValue(errorMsg); + } + + void popScope(); + + void pushScope(IMIScope scope); + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/MIValue.java b/monticore-runtime/src/main/java/de/monticore/interpreter/MIValue.java new file mode 100644 index 0000000000..28ca221588 --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/MIValue.java @@ -0,0 +1,164 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.interpreter; + +import de.monticore.interpreter.values.FunctionMIValue; +import de.se_rwth.commons.logging.Log; + +public interface MIValue { + + default boolean isWriteable() { + return false; + } + + default boolean isPrimitive() { + return false; + } + + default boolean isBoolean() { + return false; + } + + default boolean isByte() { + return false; + } + + default boolean isChar() { + return false; + } + + default boolean isShort() { + return false; + } + + default boolean isInt() { + return false; + } + + default boolean isLong() { + return false; + } + + default boolean isFloat() { + return false; + } + + default boolean isDouble() { + return false; + } + + default boolean isObject() { + return false; + } + + default boolean isFunction() { + return false; + } + + default boolean isVoid() { + return false; + } + + default boolean isSIUnit() { + return false; + } + + default boolean isFlowControlSignal() { + return false; + } + + default boolean isError() { + return false; + } + + default boolean isBreak() { + return false; + } + + default boolean isContinue() { + return false; + } + + default boolean isReturn() { + return false; + } + + default boolean asBoolean() { + Log.error("0x31251 Type boolean is not applicable for " + printType() + " (" + printValue() + ")."); + return false; + } + + default byte asByte() { + Log.error("0x31252 Type byte is not applicable for " + printType() + " (" + printValue() + ")."); + return 0; + } + + default char asChar() { + Log.error("0x31253 Type char is not applicable for " + printType() + " (" + printValue() + ")."); + return '\0'; + } + + default short asShort() { + Log.error("0x31254 Type short is not applicable for " + printType() + " (" + printValue() + ")."); + return 0; + } + + default int asInt() { + Log.error("0x31255 Type int is not applicable for " + printType() + " (" + printValue() + ")."); + return 0; + } + + default long asLong() { + Log.error("0x31256 Type long is not applicable for " + printType() + " (" + printValue() + ")."); + return 0L; + } + + default float asFloat() { + Log.error("0x31257 Type float is not applicable for " + printType() + " (" + printValue() + ")."); + return 0.0f; + } + + default double asDouble() { + Log.error("0x31258 Type double is not applicable for " + printType() + " (" + printValue() + ")."); + return 0.0; + } + + default FunctionMIValue asFunction() { + Log.error("0x57099 Type function is not applicable for " + printType() + " (" + printValue() + ")."); + return null; + } + + default Object asObject() { + Log.error("0x31259 Type object is not applicable for " + printType() + " (" + printValue() + ")."); + return null; + } + + default String asError() { + Log.error("0x57092 Type Error is not applicable for " + printType() + " (" + printValue() + ")."); + return null; + } + + default MIValue asReturnValue() { + Log.error("0x57083 Type ReturnValue is not applicable for " + + printType() + + " (" + printValue() + ")." + ); + return null; + } + + /** + * Print the type of the MIValue in human-readable form + */ + default String printType() { + Log.error("0x31260 printType is not applicable for '" + getClass().getName() + "'."); + return "UnknownType"; + } + + /** + * Print the value in human-readable form + */ + default String printValue() { + Log.error("0x31261 printValue is not applicable for '" + getClass().getName() + "'."); + return "UnknownValue"; + } + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/ModelInterpreter.java b/monticore-runtime/src/main/java/de/monticore/interpreter/ModelInterpreter.java deleted file mode 100644 index d135abcbba..0000000000 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/ModelInterpreter.java +++ /dev/null @@ -1,31 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.interpreter; - -import de.monticore.ast.ASTNode; -import de.monticore.interpreter.values.NotAValue; -import de.monticore.symboltable.ISymbol; - -import java.util.LinkedHashMap; -import java.util.Map; - -public interface ModelInterpreter { - - default Value interpret(ASTNode n) { - return new NotAValue(); - } - - void setRealThis(ModelInterpreter realThis); - - ModelInterpreter getRealThis(); - - Map getContextMap(); - - default Value load(ISymbol s){ - return getRealThis().load(s); - } - - default void store (ISymbol n, Value res){ - getRealThis().store(n,res); - } - -} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/Value.java b/monticore-runtime/src/main/java/de/monticore/interpreter/Value.java deleted file mode 100644 index f72509d91f..0000000000 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/Value.java +++ /dev/null @@ -1,80 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.interpreter; - -import de.se_rwth.commons.logging.Log; - -public interface Value { - - default boolean isBoolean() { - return false; - } - - default boolean isInt() { - return false; - } - - default boolean isLong() { - return false; - } - - default boolean isFloat() { - return false; - } - - default boolean isDouble() { - return false; - } - - default boolean isChar() { - return false; - } - - default boolean isString() { - return false; - } - - - default boolean isObject() { - return false; - } - - default boolean asBoolean() { - Log.error("0x31251 Type boolean is not applicable for result value."); - return false; - } - - default int asInt() { - Log.error("0x31252 Type int is not applicable for result value."); - return 0; - } - - default double asDouble() { - Log.error("0x31253 Type double is not applicable for result value."); - return 0.0; - } - - default String asString() { - Log.error("0x31254 Type String is not applicable for result value."); - return ""; - } - - default char asChar() { - Log.error("0x31255 Type char is not applicable for result value."); - return '\u0000'; - } - - default Object asObject() { - Log.error("0x31256 Type Object is not applicable for result value."); - return new Object(); - } - - default long asLong() { - Log.error("0x31257 Type long is not applicable for result value."); - return 0L; - } - - default float asFloat() { - Log.error("0x31258 Type float is not applicable for result value."); - return 0.0f; - } -} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/ValueFactory.java b/monticore-runtime/src/main/java/de/monticore/interpreter/ValueFactory.java deleted file mode 100644 index d57dc6781c..0000000000 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/ValueFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.interpreter; - -import de.monticore.interpreter.values.*; - -public class ValueFactory { - - public static Value createValue(int Value) { - return new IntValue(Value); - } - - public static Value createValue(double Value) { - return new DoubleValue(Value); - } - - public static Value createValue(float Value) { - return new FloatValue(Value); - } - - public static Value createValue(long Value) { - return new LongValue(Value); - } - - public static Value createValue(boolean Value) { - return new BooleanValue(Value); - } - - public static Value createValue(char Value) { - return new CharValue(Value); - } - - public static Value createValue(String Value) { - return new StringValue(Value); - } - - public static Value createValue(Object Value) { - return new ObjectValue(Value); - } - -} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/DoubleValue.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/DoubleValue.java deleted file mode 100644 index 99d24ab8f3..0000000000 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/DoubleValue.java +++ /dev/null @@ -1,44 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.interpreter.values; - -import de.monticore.interpreter.Value; -import de.se_rwth.commons.logging.Log; - -public class DoubleValue implements Value { - - protected double value; - - public DoubleValue(double value) { - this.value = value; - } - - @Override - public boolean isDouble() { - return true; - } - - @Override - public int asInt() { - return (int) value; - } - - @Override - public double asDouble() { - return value; - } - - @Override - public String asString() { - return Double.toString(value); - } - - @Override - public long asLong() { - return (long) value; - } - - @Override - public float asFloat() { - return (float) value; - } -} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/ErrorMIValue.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/ErrorMIValue.java new file mode 100644 index 0000000000..f4c967cc98 --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/values/ErrorMIValue.java @@ -0,0 +1,53 @@ +package de.monticore.interpreter.values; + +import java.util.Optional; + +public class ErrorMIValue implements MIFlowControlSignal { + + protected Optional message; + + protected Optional exception; + + public ErrorMIValue(String message) { + this.message = Optional.of(message); + this.exception = Optional.empty(); + } + + public ErrorMIValue(Exception exception) { + this.message = Optional.empty(); + this.exception = Optional.of(exception); + } + + @Override + public boolean isError() { + return true; + } + + @Override + public String asError() { + return getMessage(); + } + + @Override + public String printType() { + return "Error"; + } + + @Override + public String printValue() { + return getMessage(); + } + + // helper + + protected String getMessage() { + if (message.isPresent()) { + return message.get(); + } + else { + return exception.get().getClass().getTypeName() + + " occured: " + exception.get().getMessage(); + } + } + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/FunctionMIValue.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/FunctionMIValue.java new file mode 100644 index 0000000000..56b372d64c --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/values/FunctionMIValue.java @@ -0,0 +1,23 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.IModelInterpreter; +import de.monticore.interpreter.MIValue; + +import java.util.List; + +@FunctionalInterface +public interface FunctionMIValue extends MIValue { + + @Override + default boolean isFunction() { + return true; + } + + @Override + default FunctionMIValue asFunction() { + return this; + } + + MIValue execute(IModelInterpreter interpreter, List arguments); + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIBreakSignal.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIBreakSignal.java new file mode 100644 index 0000000000..01364e8c63 --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIBreakSignal.java @@ -0,0 +1,20 @@ +package de.monticore.interpreter.values; + +public class MIBreakSignal implements MIFlowControlSignal { + + @Override + public boolean isBreak() { + return true; + } + + @Override + public String printType() { + return "Break-Signal"; + } + + @Override + public String printValue() { + return ""; + } + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIContinueSignal.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIContinueSignal.java new file mode 100644 index 0000000000..1fcc5aab79 --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIContinueSignal.java @@ -0,0 +1,20 @@ +package de.monticore.interpreter.values; + +public class MIContinueSignal implements MIFlowControlSignal { + + @Override + public boolean isContinue() { + return true; + } + + @Override + public String printType() { + return "Continue"; + } + + @Override + public String printValue() { + return ""; + } + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIFlowControlSignal.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIFlowControlSignal.java new file mode 100644 index 0000000000..ee57a0bb93 --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIFlowControlSignal.java @@ -0,0 +1,12 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIValue; + +public interface MIFlowControlSignal extends MIValue { + + @Override + default boolean isFlowControlSignal() { + return true; + } + +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIReturnSignal.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIReturnSignal.java new file mode 100644 index 0000000000..4500c2070d --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/values/MIReturnSignal.java @@ -0,0 +1,36 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIValue; + +public class MIReturnSignal implements MIFlowControlSignal { + + MIValue value; + + public MIReturnSignal() { + this.value = new VoidMIValue(); + } + + public MIReturnSignal(MIValue value) { + this.value = value; + } + + @Override + public boolean isReturn() { + return true; + } + + @Override + public MIValue asReturnValue() { + return value; + } + + @Override + public String printType() { + return "Return-Signal"; + } + + @Override + public String printValue() { + return value.printType() + "(" + value.printValue() + ")"; + } +} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/NotAValue.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/NotAValue.java deleted file mode 100644 index 54d67cd1f7..0000000000 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/NotAValue.java +++ /dev/null @@ -1,6 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.interpreter.values; - -import de.monticore.interpreter.Value; - -public class NotAValue implements Value {} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/ObjectValue.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/ObjectValue.java deleted file mode 100644 index 01a4f7a3c6..0000000000 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/ObjectValue.java +++ /dev/null @@ -1,23 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.interpreter.values; - -import de.monticore.interpreter.Value; - -public class ObjectValue implements Value { - - protected Object value; - - public ObjectValue(Object value) { - this.value = value; - } - - @Override - public boolean isObject() { - return true; - } - - @Override - public Object asObject() { - return value; - } -} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/StringValue.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/StringValue.java deleted file mode 100644 index c71b192b1c..0000000000 --- a/monticore-runtime/src/main/java/de/monticore/interpreter/values/StringValue.java +++ /dev/null @@ -1,33 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.interpreter.values; - -import de.monticore.interpreter.Value; - -public class StringValue implements Value { - - protected String value; - - public StringValue(String value) { - this.value = value; - } - - @Override - public boolean isString() { - return true; - } - - @Override - public boolean isObject() { - return true; - } - - @Override - public String asString() { - return value; - } - - @Override - public Object asObject() { - return value; - } -} diff --git a/monticore-runtime/src/main/java/de/monticore/interpreter/values/VoidMIValue.java b/monticore-runtime/src/main/java/de/monticore/interpreter/values/VoidMIValue.java new file mode 100644 index 0000000000..970378b336 --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/interpreter/values/VoidMIValue.java @@ -0,0 +1,22 @@ +package de.monticore.interpreter.values; + +import de.monticore.interpreter.MIValue; + +public class VoidMIValue implements MIValue { + + @Override + public boolean isVoid() { + return true; + } + + @Override + public String printType() { + return "Void"; + } + + @Override + public String printValue() { + return ""; + } + +} diff --git a/monticore-runtime/src/main/java/de/monticore/symboltable/ISymbol.java b/monticore-runtime/src/main/java/de/monticore/symboltable/ISymbol.java index 96f1ee1b3a..95dea55be6 100644 --- a/monticore-runtime/src/main/java/de/monticore/symboltable/ISymbol.java +++ b/monticore-runtime/src/main/java/de/monticore/symboltable/ISymbol.java @@ -3,7 +3,7 @@ import com.google.common.collect.ImmutableList; import de.monticore.ast.ASTNode; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.symboltable.modifiers.BasicAccessModifier; import de.monticore.symboltable.stereotypes.IStereotypeReference; @@ -68,7 +68,7 @@ default AccessModifier getAccessModifier() { * The keys of the map reference {@link IStereotypeSymbol}s, while the values * reference the optionally associated stereovalue. */ - Map> getStereoinfo(); + Map> getStereoinfo(); boolean isPresentAstNode(); diff --git a/monticore-runtime/src/main/java/de/monticore/symboltable/SymbolWithScopeOfUnknownKind.java b/monticore-runtime/src/main/java/de/monticore/symboltable/SymbolWithScopeOfUnknownKind.java index 55c52ecb80..5ded13eb24 100644 --- a/monticore-runtime/src/main/java/de/monticore/symboltable/SymbolWithScopeOfUnknownKind.java +++ b/monticore-runtime/src/main/java/de/monticore/symboltable/SymbolWithScopeOfUnknownKind.java @@ -3,7 +3,7 @@ import java.util.*; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.symboltable.stereotypes.IStereotypeReference; import de.monticore.visitor.ITraverser; @@ -20,7 +20,7 @@ public class SymbolWithScopeOfUnknownKind implements IScopeSpanningSymbol { protected AccessModifier accessModifier = AccessModifier.ALL_INCLUSION; - protected Map> stereoinfo = new LinkedHashMap<>(); + protected Map> stereoinfo = new HashMap<>(); protected String fullName; @@ -98,7 +98,7 @@ public String getPackageName() { } @Override - public Map> getStereoinfo() { + public Map> getStereoinfo() { return this.stereoinfo; } diff --git a/monticore-runtime/src/main/java/de/monticore/symboltable/SymbolWithScopeOfUnknownKindBuilder.java b/monticore-runtime/src/main/java/de/monticore/symboltable/SymbolWithScopeOfUnknownKindBuilder.java index 325f1b8bfb..a5a78d1262 100644 --- a/monticore-runtime/src/main/java/de/monticore/symboltable/SymbolWithScopeOfUnknownKindBuilder.java +++ b/monticore-runtime/src/main/java/de/monticore/symboltable/SymbolWithScopeOfUnknownKindBuilder.java @@ -1,12 +1,11 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.symboltable; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.symboltable.stereotypes.IStereotypeReference; import de.se_rwth.commons.logging.Log; import de.monticore.ast.ASTNode; - import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; @@ -22,7 +21,7 @@ public class SymbolWithScopeOfUnknownKindBuilder { protected AccessModifier accessModifier; - protected Map> stereoinfo = new LinkedHashMap<>(); + protected Map> stereoinfo = new LinkedHashMap<>(); protected IScope enclosingScope; @@ -86,7 +85,7 @@ public AccessModifier getAccessModifier() { return this.accessModifier; } - public Map> getStereoinfo() { + public Map> getStereoinfo() { return this.stereoinfo; } @@ -119,7 +118,7 @@ public SymbolWithScopeOfUnknownKindBuilder setAccessModifier(AccessModifier acce } public SymbolWithScopeOfUnknownKindBuilder setStereoinfo( - Map> stereoinfo) { + Map> stereoinfo) { this.stereoinfo = stereoinfo; return this.realBuilder; @@ -131,7 +130,7 @@ public SymbolWithScopeOfUnknownKindBuilder addStereoinfo(IStereotypeReference st } public SymbolWithScopeOfUnknownKindBuilder addStereoinfo(IStereotypeReference stereotype, - Value stereovalue) { + MIValue stereovalue) { this.stereoinfo.put(stereotype, Optional.of(stereovalue)); return this.realBuilder; } diff --git a/monticore-runtime/src/main/java/de/monticore/symboltable/stereotypes/StereoinfoDeSer.java b/monticore-runtime/src/main/java/de/monticore/symboltable/stereotypes/StereoinfoDeSer.java index b7c3cf7dc2..c1380e8da8 100644 --- a/monticore-runtime/src/main/java/de/monticore/symboltable/stereotypes/StereoinfoDeSer.java +++ b/monticore-runtime/src/main/java/de/monticore/symboltable/stereotypes/StereoinfoDeSer.java @@ -1,7 +1,7 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.symboltable.stereotypes; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.symboltable.IScope; import de.monticore.symboltable.serialization.JsonPrinter; import de.monticore.symboltable.serialization.json.JsonElement; @@ -64,7 +64,7 @@ protected static StereoinfoDeSer getInstance() { * See {@link StereoinfoDeSer} on how to configure how this facade behaves. */ public static String printAsJson( - Map.Entry> stereoinfo) { + Map.Entry> stereoinfo) { return printAsJson(stereoinfo.getKey(), stereoinfo.getValue()); } @@ -74,12 +74,12 @@ public static String printAsJson( *

* See {@link StereoinfoDeSer} on how to configure how this facade behaves. */ - public static String printAsJson(IStereotypeReference stereotype, Optional value) { + public static String printAsJson(IStereotypeReference stereotype, Optional value) { return getInstance().doPrintAsJson(stereotype, value); } - protected String doPrintAsJson(IStereotypeReference stereotype, Optional value) { + protected String doPrintAsJson(IStereotypeReference stereotype, Optional value) { if (value.isPresent()) { Log.errorInternal( "0x82401 Internal error: The serialization of values for symbolic stereotypes is not yet " + @@ -110,14 +110,14 @@ protected String doPrintAsJson(IStereotypeReference stereotype, Optional *

* See {@link StereoinfoDeSer} on how to configure how this facade behaves. */ - public static Map.Entry> deserialize( + public static Map.Entry> deserialize( JsonElement json, IScope enclosingScope) { return getInstance().doDeserialize(json, enclosingScope); } @SuppressWarnings("unused") - protected Map.Entry> doDeserialize(JsonElement json, + protected Map.Entry> doDeserialize(JsonElement json, IScope enclosingScope) { Log.errorInternal( "0x82402 Internal error: The deserialization of stereotype annotations is not supported by " + diff --git a/monticore-runtime/src/test/java/de/monticore/symboltable/stereotypes/StereoinfoDeSerTest.java b/monticore-runtime/src/test/java/de/monticore/symboltable/stereotypes/StereoinfoDeSerTest.java index 869af0ed19..a0ecd806cf 100644 --- a/monticore-runtime/src/test/java/de/monticore/symboltable/stereotypes/StereoinfoDeSerTest.java +++ b/monticore-runtime/src/test/java/de/monticore/symboltable/stereotypes/StereoinfoDeSerTest.java @@ -2,7 +2,7 @@ package de.monticore.symboltable.stereotypes; import de.monticore.ast.ASTNode; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import de.monticore.symboltable.IScope; import de.monticore.symboltable.modifiers.AccessModifier; import de.se_rwth.commons.logging.LogStub; @@ -71,7 +71,7 @@ public IScope getEnclosingScope() { public void setAccessModifier(AccessModifier accessModifier) { } @Override - public Map> getStereoinfo() { + public Map> getStereoinfo() { return Map.of(); } diff --git a/monticore-test/01.experiments/interpreter/src/main/grammars/SimpleEquations.mc4 b/monticore-test/01.experiments/interpreter/src/main/grammars/SimpleEquations.mc4 index b7a6eb7159..8b84a06743 100644 --- a/monticore-test/01.experiments/interpreter/src/main/grammars/SimpleEquations.mc4 +++ b/monticore-test/01.experiments/interpreter/src/main/grammars/SimpleEquations.mc4 @@ -1,20 +1,33 @@ /* (c) https://github.com/MontiCore/monticore */ -grammar SimpleEquations extends Numerals { +grammar SimpleEquations extends Numerals, de.monticore.symbols.BasicSymbols { - Program = (Statement ";")* (Expression ";")? ; + symbol scope SimpleEquationCompilationUnit = Name "{" ProgramBlock (FunctionDefinition)* "}"; + scope ProgramBlock = (Statement ";")+ (Expression ";")? ; + FunctionBlock = (Statement ";")+ (Expression ";")? ; interface Statement; interface Expression; + FunctionCall implements Expression, Statement = Name "(" ArgList ")"; + ArgList = (args:Expression ("," args:Expression)*)?; + + symbol scope FunctionDefinition implements Function, Statement = returnType:Name "func" name:Name FormalParameters "{" FunctionBlock "}"; + FormalParameters = "(" FormalParameterListing? ")"; + FormalParameterListing = (VariableAsParameter | ",")+; + VariableAsParameter implements Variable = type:Name Name; + PlusEquation implements Expression = left:Expression "+" right:Expression; MinusEquation implements Expression = left:Expression "-" right:Expression; MultiplyEquation implements Expression = left:Expression "*" right:Expression; DivideEquation implements Expression = left:Expression "/" right:Expression; + GreaterThanExpression implements Expression = left:Expression ">" right:Expression; - symbol VariableDefinition implements Statement = "var" Name "=" value:Expression; + symbol VariableDefinition implements Statement, Variable = type:Name Name "=" value:Expression; VariableUsage implements Statement = Name "=" value:Expression; PrintStatement implements Statement = "print" "(" Expression ")"; + IfStatement implements Statement = "if" "(" condition:Expression ")" "{" thenBlock:ProgramBlock "}" ("else" "{" elseBlock:ProgramBlock "}")?; + ReturnStatement implements Statement = "return" Expression; NameExpression implements Expression = Name; NumberExpression implements Expression = Number; diff --git a/monticore-test/01.experiments/interpreter/src/main/java/numerals/_visitor/NumeralsInterpreter.java b/monticore-test/01.experiments/interpreter/src/main/java/numerals/_visitor/NumeralsInterpreter.java index 96ec00da88..02c2442871 100644 --- a/monticore-test/01.experiments/interpreter/src/main/java/numerals/_visitor/NumeralsInterpreter.java +++ b/monticore-test/01.experiments/interpreter/src/main/java/numerals/_visitor/NumeralsInterpreter.java @@ -1,9 +1,9 @@ /* (c) https://github.com/MontiCore/monticore */ package numerals._visitor; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.MIValueFactory; import de.monticore.interpreter.ModelInterpreter; -import de.monticore.interpreter.Value; -import de.monticore.interpreter.ValueFactory; import numerals._ast.ASTFloat; import numerals._ast.ASTInteger; @@ -13,16 +13,16 @@ public NumeralsInterpreter(ModelInterpreter realThis) { super(realThis); } - public Value interpret(ASTFloat node) { - return ValueFactory.createValue((float) + public MIValue interpret(ASTFloat node) { + return MIValueFactory.createValue((float) (Integer.parseInt(node.getPre()) + - Integer.parseInt(node.getPost()) * Math.pow(10, -node.getPost().length())) - * (node.isNegative() ? -1 : 1)); + Integer.parseInt(node.getPost()) * Math.pow(10, -node.getPost().length())) + * (node.isNegative() ? -1 : 1)); } - public Value interpret(ASTInteger node) { - return ValueFactory.createValue( + public MIValue interpret(ASTInteger node) { + return MIValueFactory.createValue( Integer.parseInt(node.getDigits()) * (node.isNegative() ? -1 : 1)); } -} +} \ No newline at end of file diff --git a/monticore-test/01.experiments/interpreter/src/main/java/simpleequations/_symboltable/SimpleEquationsScopesGenitorDelegator.java b/monticore-test/01.experiments/interpreter/src/main/java/simpleequations/_symboltable/SimpleEquationsScopesGenitorDelegator.java new file mode 100644 index 0000000000..13728cda97 --- /dev/null +++ b/monticore-test/01.experiments/interpreter/src/main/java/simpleequations/_symboltable/SimpleEquationsScopesGenitorDelegator.java @@ -0,0 +1,20 @@ +package simpleequations._symboltable; + +public class SimpleEquationsScopesGenitorDelegator extends SimpleEquationsScopesGenitorDelegatorTOP{ + + @Override + public simpleequations._symboltable.ISimpleEquationsArtifactScope createFromAST (simpleequations._ast.ASTSimpleEquationCompilationUnit rootNode) { + simpleequations._symboltable.ISimpleEquationsArtifactScope as = symbolTable.createFromAST(rootNode); + //only add this here + as.setName(rootNode.getName()); + //until here + if (as.isPresentName()){ + if (!as.getPackageName().isEmpty()){ + globalScope.addLoadedFile(as.getPackageName() + "." + as.getName()); + } else { + globalScope.addLoadedFile(as.getName()); + } + } + return as; + } +} diff --git a/monticore-test/01.experiments/interpreter/src/main/java/simpleequations/_visitor/SimpleEquationsInterpreter.java b/monticore-test/01.experiments/interpreter/src/main/java/simpleequations/_visitor/SimpleEquationsInterpreter.java index c65567d3df..580e987720 100644 --- a/monticore-test/01.experiments/interpreter/src/main/java/simpleequations/_visitor/SimpleEquationsInterpreter.java +++ b/monticore-test/01.experiments/interpreter/src/main/java/simpleequations/_visitor/SimpleEquationsInterpreter.java @@ -1,10 +1,24 @@ /* (c) https://github.com/MontiCore/monticore */ package simpleequations._visitor; -import de.monticore.interpreter.Value; -import de.monticore.interpreter.ValueFactory; -import de.monticore.interpreter.values.NotAValue; +import de.monticore.interpreter.MIScope; +import de.monticore.interpreter.MIValue; +import de.monticore.interpreter.MIValueFactory; +import de.monticore.interpreter.values.ErrorMIValue; +import de.monticore.interpreter.values.MIReturnSignal; +import de.monticore.interpreter.values.ModelFunctionMIValue; +import de.monticore.interpreter.values.VoidMIValue; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpressionFactory; import simpleequations._ast.*; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Stack; +import java.util.stream.Collectors; public class SimpleEquationsInterpreter extends SimpleEquationsInterpreterTOP { @@ -12,85 +26,222 @@ public SimpleEquationsInterpreter() { super(); } - public Value interpret(ASTProgram node) { - node.forEachStatements(s -> s.evaluate(getRealThis())); + + public MIValue interpret(ASTSimpleEquationCompilationUnit node) { + MIValue result; + for(ASTFunctionDefinition method : node.getFunctionDefinitionList()){ + method.evaluate(getRealThis()); + } + + result = node.getProgramBlock().evaluate(getRealThis()); + if(result.isError()){ + return new ErrorMIValue("Error ASTSimpleEquationCompilationUnit wrong return type from ASTProgramBlock"); + } + return result; + } + + public MIValue interpret(ASTProgramBlock node) { + MIValue result = new ErrorMIValue("Error ASTProgram node"); + + for (ASTStatement s : node.getStatementList()) { + result = s.evaluate(getRealThis()); + if (result.isReturn()) { + return result; + } + } if (node.isPresentExpression()) { return node.getExpression().evaluate(getRealThis()); } - return new NotAValue(); + return result; } - public Value interpret(ASTPlusEquation node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); + public MIValue interpret(ASTPlusEquation node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); if (left.isInt() && right.isInt()) { - return ValueFactory.createValue(left.asInt() + right.asInt()); - } - return ValueFactory.createValue(left.asFloat() + right.asFloat()); + return MIValueFactory.createValue(left.asInt() + right.asInt()); + } + return MIValueFactory.createValue(left.asFloat() + right.asFloat()); } - public Value interpret(ASTMinusEquation node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); + public MIValue interpret(ASTMinusEquation node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); if (left.isInt() && right.isInt()) { - return ValueFactory.createValue(left.asInt() - right.asInt()); + return MIValueFactory.createValue(left.asInt() - right.asInt()); } - return ValueFactory.createValue(left.asFloat() - right.asFloat()); + return MIValueFactory.createValue(left.asFloat() - right.asFloat()); } - public Value interpret(ASTMultiplyEquation node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); + public MIValue interpret(ASTMultiplyEquation node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); if (left.isInt() && right.isInt()) { - return ValueFactory.createValue(left.asInt() * right.asInt()); + return MIValueFactory.createValue(left.asInt() * right.asInt()); } - return ValueFactory.createValue(left.asFloat() * right.asFloat()); + return MIValueFactory.createValue(left.asFloat() * right.asFloat()); } - public Value interpret(ASTDivideEquation node) { - Value left = node.getLeft().evaluate(getRealThis()); - Value right = node.getRight().evaluate(getRealThis()); + public MIValue interpret(ASTDivideEquation node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); if (left.isInt() && right.isInt()) { - return ValueFactory.createValue(left.asInt() / right.asInt()); + return MIValueFactory.createValue(left.asInt() / right.asInt()); + } + return MIValueFactory.createValue(left.asFloat() / right.asFloat()); + } + + public MIValue interpret(ASTGreaterThanExpression node) { + MIValue left = node.getLeft().evaluate(getRealThis()); + MIValue right = node.getRight().evaluate(getRealThis()); + + if (left.isInt() && right.isInt()) { + return MIValueFactory.createValue(left.asInt() > right.asInt()); + } + return MIValueFactory.createValue(left.asFloat() > right.asFloat()); + } + + public MIValue interpret(ASTVariableDefinition node) { + MIValue value = node.getValue().evaluate(getRealThis()); + getRealThis().declareVariable(node.getSymbol(), Optional.of(value)); + return value; + } + + public MIValue interpret(ASTVariableUsage node) { + MIValue value = node.getValue().evaluate(getRealThis()); + Optional symbols = node.getEnclosingScope().resolveVariable(node.getName()); + + if (symbols.isPresent()) { + getRealThis().storeVariable(symbols.get(), value); + } else { + throw new RuntimeException("CRITICAL: Variable '" + node.getName() + "' not found in scope!"); + } + + return value; + } + + public MIValue interpret(ASTPrintStatement node) { + MIValue output = node.getExpression().evaluate(getRealThis()); + + //if (output.isInt()) { + // System.out.println(output.asInt()); + //} else if (output.isFloat()) { + // System.out.println(output.asFloat()); + //} + + return output; + } + + public MIValue interpret(ASTNameExpression node) { + Optional typeVars = node.getEnclosingScope().resolveVariable(node.getName()); + + if (!typeVars.isEmpty()) { + return getRealThis().loadVariable(typeVars.get()); + } else { + throw new RuntimeException("0x57071: Variable '" + node.getName() + "' not found."); } - return ValueFactory.createValue(left.asFloat() / right.asFloat()); } - public Value interpret(ASTVariableDefinition node) { - Value value = node.getValue().evaluate(getRealThis()); - getRealThis().store(node.getSymbol(), value); - return new NotAValue(); + public MIValue interpret(ASTFunctionDefinition node) { + //this must be init to create int types + BasicSymbolsMill.initializePrimitives(); + + FunctionSymbol funcSym = node.getSymbol(); + + //set return type of function like specified (only primitive allowed) + funcSym.setType(SymTypeExpressionFactory.createPrimitive(node.getReturnType())); + + List parameterSymbols = node.getFormalParameters() + .getFormalParameterListing() + .streamVariableAsParameters() + .map(ASTVariableAsParameter::getSymbol) + .collect(Collectors.toList()); + + //set types of the parameters + for (VariableSymbol param : parameterSymbols) { + String typeName = param.getType() != null ? param.getType().print() : "int"; + param.setType(SymTypeExpressionFactory.createPrimitive(typeName)); + } + + ModelFunctionMIValue functionValue = new ModelFunctionMIValue( + getRealThis().getCurrentScope(), + parameterSymbols, + node.getFunctionBlock() + ); + + getRealThis().declareFunction(funcSym, functionValue); + return new VoidMIValue(); } - public Value interpret(ASTVariableUsage node) { - var symbol = node.getEnclosingScope().resolveVariableDefinition(node.getName()); - Value value = node.getValue().evaluate(getRealThis()); - symbol.ifPresent(s -> getRealThis().store(s, value)); - return new NotAValue(); + public MIValue interpret(ASTFunctionBlock node){ + MIValue result = new ErrorMIValue("Error ASTFunctionBlock node"); + for (ASTStatement s : node.getStatementList()) { + result = s.evaluate(getRealThis()); + if (result.isReturn()) { + return result; + } + } + if (node.isPresentExpression()) { + return node.getExpression().evaluate(getRealThis()); + } + return result; } - public Value interpret(ASTPrintStatement node) { - Value output = node.getExpression().evaluate(getRealThis()); + public MIValue interpret(ASTFunctionCall node) { + Optional functionSymbol = node.getEnclosingScope().resolveFunction(node.getName()); + + if (functionSymbol.isPresent()) { + MIValue funcValue = getRealThis().loadFunction(functionSymbol.get()); + + if (funcValue instanceof ModelFunctionMIValue) { + ModelFunctionMIValue modelFunc = (ModelFunctionMIValue) funcValue; - if (output.isInt()) { - System.out.println(output.asInt()); - } else if (output.isFloat()) { - System.out.println(output.asFloat()); + List args = new ArrayList<>(); + for (ASTExpression expr : node.getArgList().getArgsList()) { + args.add(expr.evaluate(getRealThis())); + } + + MIValue result = modelFunc.execute(getRealThis(), args); + + while (result.isReturn()){ + result = result.asReturnValue(); + } + return result; + } } - return new NotAValue(); + return new ErrorMIValue("Function '" + node.getName() + "' not found."); } - public Value interpret(ASTNameExpression node) { - var optSymbol = node.getEnclosingScope().resolveVariableDefinition(node.getName()); - return optSymbol.map(getRealThis()::load).orElse(new NotAValue()); + public MIValue interpret(ASTIfStatement node) { + MIValue condition = node.getCondition().evaluate(getRealThis()); + if (condition.asBoolean()) { + MIValue returnValue = node.getThenBlock().evaluate(getRealThis()); + return returnValue; + } else if (node.isPresentElseBlock()) { + MIValue returnValue = node.getElseBlock().evaluate(getRealThis()); + return returnValue; + } + return new ErrorMIValue("IfStatement no branch executed"); + } + + public MIValue interpret(ASTVariableAsParameter node) { + return new ErrorMIValue("Error ASTVariableAsParameter node"); + } + + public MIValue interpret(ASTReturnStatement node) { + MIValue value = node.getExpression().evaluate(getRealThis()); + if(value.isError()){ + return new ErrorMIValue("error in return statement"); + } + return new MIReturnSignal(value); } - public Value interpret(ASTNumberExpression node) { + public MIValue interpret(ASTNumberExpression node) { return node.getNumber().evaluate(getRealThis()); } -} +} \ No newline at end of file diff --git a/monticore-test/01.experiments/interpreter/src/test/java/simpleequations/_visitor/SimpleEquationsInterpreterTest.java b/monticore-test/01.experiments/interpreter/src/test/java/simpleequations/_visitor/SimpleEquationsInterpreterTest.java index 2d750570f6..69b19dc2c2 100644 --- a/monticore-test/01.experiments/interpreter/src/test/java/simpleequations/_visitor/SimpleEquationsInterpreterTest.java +++ b/monticore-test/01.experiments/interpreter/src/test/java/simpleequations/_visitor/SimpleEquationsInterpreterTest.java @@ -1,15 +1,13 @@ /* (c) https://github.com/MontiCore/monticore */ package simpleequations._visitor; -import de.monticore.interpreter.Value; +import de.monticore.interpreter.MIValue; import org.junit.jupiter.api.Test; import simpleequations.SimpleEquationsMill; -import simpleequations._ast.ASTProgram; +import simpleequations._ast.ASTSimpleEquationCompilationUnit; import simpleequations._parser.SimpleEquationsParser; import simpleequations._symboltable.SimpleEquationsScopesGenitorDelegator; - import java.io.IOException; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -22,21 +20,76 @@ public void test() throws IOException { SimpleEquationsInterpreter interpreter = new SimpleEquationsInterpreter(); SimpleEquationsScopesGenitorDelegator delegator = SimpleEquationsMill.scopesGenitorDelegator(); - ASTProgram program = parser.parse_StringProgram("var a=3.5; var b=4; print(a); var c=a+b; c;").get(); + ASTSimpleEquationCompilationUnit program = parser.parse_StringSimpleEquationCompilationUnit("" + + "Program {" + + " int a = 3; " + + " int b = 3; " + + " int result = func1(a, b);" + + " print(result);" + + " int func func1(int a, int b){ " + + " int c = a; " + + " if( b > 0 ){ " + + " b = b - 1; " + + " a = a;" + + " c = a * 3; " + + " int d = func1(c, b);" + + " return d;" + + " } else { " + + " return a;" + + " };" + + " }"+ + "}").get(); + delegator.createFromAST(program); + MIValue functionResult = interpreter.interpret(program); + assertTrue(functionResult.isInt()); + assertEquals(81, functionResult.asInt()); + + //test recursive method definition + //program = parser.parse_StringSimpleEquationCompilationUnit("" + + // "Program {" + + // "int a = 3;" + + // "int b = 3;" + + // "int func func1(int a, int b){" + + // " int func func1(int a, int b) {" + + // " return a + b;" + + // " };" + + // " a = a * a;" + + // " b = b * b;" + + // " return func1(a,b);" + + // "};" + + // "int result = func1(a,b); " + + // "print(result);" + // "}").get(); + //delegator.createFromAST(program); + //MIValue recursiveResult = interpreter.interpret(program); + //assertTrue(recursiveResult.isInt()); + //assertEquals(18, recursiveResult.asInt() ); + + + program = parser.parse_StringSimpleEquationCompilationUnit("" + + "Program {" + + " var a=3.5; " + + " var b=4; " + + " print(a); " + + " var c=a+b; " + + " c;" + + "}").get(); delegator.createFromAST(program); - Value result = interpreter.interpret(program); + MIValue result = interpreter.interpret(program); assertTrue(result.isFloat()); - assertEquals(result.asFloat(), 7.5f, 0.0001f); + assertEquals(7.5f, result.asFloat(), 0.0001f); SimpleEquationsMill.reset(); SimpleEquationsMill.init(); interpreter = new SimpleEquationsInterpreter(); - program = parser.parse_StringProgram( - "var a = 40; " + - "a = 45;" + - "a;").get(); + program = parser.parse_StringSimpleEquationCompilationUnit( + "Program {" + + " var a = 40; " + + " a = 45;" + + " a;" + + "}").get(); delegator.createFromAST(program); result = interpreter.interpret(program); diff --git a/monticore-test/01.experiments/runtimeOnly/build.gradle b/monticore-test/01.experiments/runtimeOnly/build.gradle index 3acc2b7b8e..2d1ae52ff9 100644 --- a/monticore-test/01.experiments/runtimeOnly/build.gradle +++ b/monticore-test/01.experiments/runtimeOnly/build.gradle @@ -3,6 +3,7 @@ description = 'Experiments: runtimeOnly' dependencies { implementation project(path: ':monticore-runtime') + implementation project(path: ':monticore-grammar') } /*