From 28842ef20d7ca734327608ad27836d0673ee0513 Mon Sep 17 00:00:00 2001 From: Tammo Ippen Date: Wed, 26 Aug 2015 11:04:32 +0200 Subject: [PATCH] Initial commit! --- .gitignore | 9 + README.md | 1 + pom.xml | 235 +++++++ src/main/grammars/org/nest/NESTML.mc4 | 93 +++ src/main/grammars/org/nest/SPL.mc4 | 87 +++ .../grammars/org/nest/commons/Commons.mc4 | 31 + .../nest/cli/CLIConfigurationExecutor.java | 127 ++++ .../java/org/nest/cli/NESTMLFrontend.java | 158 +++++ .../org/nest/cli/NESTMLToolConfiguration.java | 74 +++ .../NESTML2NESTCodeGenerator.java | 173 ++++++ .../NESTML2NESTTypeConverter.java | 60 ++ .../nest/codegeneration/NESTMLBuffers.java | 163 +++++ .../codegeneration/NESTMLDeclarations.java | 198 ++++++ .../codegeneration/NESTMLDynamicsPrinter.java | 68 ++ .../codegeneration/NESTMLFunctionPrinter.java | 118 ++++ .../org/nest/codegeneration/NESTMLInputs.java | 59 ++ .../nest/codegeneration/NESTMLOutputs.java | 65 ++ .../codegeneration/SPL2NESTCodeGenerator.java | 63 ++ .../org/nest/codegeneration/SPLForNodes.java | 63 ++ .../nest/codegeneration/SPLFunctionCalls.java | 17 + .../SPLVariableGetterSetterHelper.java | 102 +++ .../converters/IReferenceConverter.java | 21 + .../IdempotentReferenceConverter.java | 40 ++ .../converters/NESTReferenceConverter.java | 168 +++++ .../CommonNESTMLSymbolTableCreator.java | 92 +++ .../_symboltable/NESTMLCoCosManager.java | 136 ++++ .../nestml/_symboltable/NESTMLLanguage.java | 97 +++ .../NESTMLMethodSignaturePredicate.java | 57 ++ .../_symboltable/NESTMLModelLoader.java | 64 ++ .../_symboltable/NESTMLRootCreator.java | 31 + .../_symboltable/NESTMLScopeCreator.java | 73 +++ .../NESTMLSymbolTableCreator.java | 493 +++++++++++++++ .../nest/nestml/cocos/AliasHasNoSetter.java | 99 +++ .../org/nest/nestml/cocos/AliasHasOneVar.java | 25 + .../nestml/cocos/AliasInNonAliasDecl.java | 97 +++ .../cocos/BooleanInvariantExpressions.java | 54 ++ .../nestml/cocos/ComponentHasNoDynamics.java | 31 + .../nest/nestml/cocos/ComponentNoInput.java | 26 + .../nest/nestml/cocos/ComponentNoOutput.java | 28 + .../nestml/cocos/CorrectReturnValues.java | 104 ++++ .../nestml/cocos/CurrentInputIsNotInhExc.java | 25 + .../cocos/DynamicsTimeStepParameter.java | 62 ++ .../cocos/FunctionHasReturnStatement.java | 130 ++++ .../cocos/InvalidTypesInDeclaration.java | 108 ++++ .../MemberVariableDefinedMultipleTimes.java | 67 ++ ...berVariablesInitialisedInCorrectOrder.java | 134 ++++ .../cocos/MultipleFunctionDeclarations.java | 73 +++ .../nestml/cocos/MultipleInhExcInput.java | 40 ++ .../nest/nestml/cocos/MultipleOutputs.java | 34 + .../nestml/cocos/NESTFunctionNameChecker.java | 36 ++ .../cocos/NESTGetterSetterFunctionNames.java | 95 +++ .../nestml/cocos/NeuronNeedsDynamics.java | 30 + .../nest/nestml/cocos/NeuronWithoutInput.java | 28 + .../nestml/cocos/NeuronWithoutOutput.java | 27 + .../cocos/TypeIsDeclaredMultipleTimes.java | 47 ++ .../nest/nestml/cocos/UsesOnlyComponents.java | 47 ++ .../nestml/cocos/spl/BufferNotAssignable.java | 36 ++ .../nestml/nestml/_ast/ASTBodyDecorator.java | 243 ++++++++ .../prettyprinter/NESTMLPrettyPrinter.java | 431 +++++++++++++ .../NESTMLPrettyPrinterFactory.java | 13 + .../java/org/nest/ode/ModelConverter.java | 79 +++ .../org/nest/ode/ODE2SympyCodeGenerator.java | 72 +++ .../org/nest/ode/Sympy2NESTMLConverter.java | 44 ++ .../org/nest/ode/SympyLine2ASTConverter.java | 30 + .../java/org/nest/ode/SympyOutputReader.java | 30 + .../nest/spl/_symboltable/SPLLanguage.java | 60 ++ .../cocos/CheckMultipleSignsBeforeFactor.java | 119 ++++ .../org/nest/spl/cocos/CodeAfterReturn.java | 124 ++++ .../nest/spl/cocos/FunctionDoesntExist.java | 74 +++ .../org/nest/spl/cocos/IllegalExpression.java | 185 ++++++ .../org/nest/spl/cocos/IllegalVarInFor.java | 58 ++ .../org/nest/spl/cocos/VarHasTypeName.java | 50 ++ .../cocos/VariableDefinedMultipleTimes.java | 82 +++ .../nest/spl/cocos/VariableDoesNotExist.java | 143 +++++ .../cocos/VariableNotDefinedBeforeUse.java | 95 +++ .../ExpressionsPrettyPrinter.java | 234 +++++++ .../spl/prettyprinter/SPLPrettyPrinter.java | 290 +++++++++ .../SPLPrettyPrinterFactory.java | 20 + .../CommonSPLSymbolTableCreator.java | 37 ++ .../nest/spl/symboltable/SPLCoCosManager.java | 119 ++++ .../nest/spl/symboltable/SPLModelLoader.java | 70 +++ .../nest/spl/symboltable/SPLScopeCreator.java | 69 ++ .../symboltable/SPLSymbolTableCreator.java | 115 ++++ .../ExpressionTypeCalculator.java | 290 +++++++++ .../symboltable/typechecking/TypeChecker.java | 80 +++ .../nest/symboltable/ScopeCreatorBase.java | 75 +++ .../predefined/PredefinedFunctionFactory.java | 106 ++++ .../predefined/PredefinedTypesFactory.java | 116 ++++ .../PredefinedVariablesFactory.java | 48 ++ .../symbols/NESTMLMethodSymbol.java | 102 +++ .../symbols/NESTMLMethodSymbolKind.java | 22 + .../symbols/NESTMLNeuronSymbol.java | 64 ++ .../symbols/NESTMLNeuronSymbolKind.java | 22 + .../symboltable/symbols/NESTMLTypeSymbol.java | 57 ++ .../symbols/NESTMLTypeSymbolKind.java | 22 + .../symbols/NESTMLUsageSymbol.java | 36 ++ .../symbols/NESTMLUsageSymbolKind.java | 22 + .../symbols/NESTMLVariableSymbol.java | 99 +++ .../symbols/NESTMLVariableSymbolKind.java | 22 + .../NESTMLNeuronSymbolReference.java | 54 ++ .../references/NESTMLTypeSymbolReference.java | 55 ++ src/main/java/org/nest/utils/ASTNodes.java | 96 +++ .../java/org/nest/utils/CachedResolver.java | 40 ++ src/main/java/org/nest/utils/LogHelper.java | 73 +++ .../java/org/nest/utils/NESTMLSymbols.java | 64 ++ .../org/nest/utils/PrettyPrinterBase.java | 60 ++ .../org/nest/nestml/MemberDeclaration.ftl | 12 + .../nest/nestml/buffer/CurrentBufferFill.ftl | 9 + .../nest/nestml/buffer/SpikeBufferFill.ftl | 43 ++ .../org/nest/nestml/function/Calibrate.ftl | 32 + .../function/DynamicsImplementation.ftl | 14 + .../org/nest/nestml/function/Invariant.ftl | 12 + .../nestml/function/MemberInitialization.ftl | 19 + .../function/MemberVariableGetterSetter.ftl | 26 + .../nest/nestml/function/MinDelayDynamics.ftl | 3 + .../nestml/function/ReadFromDictionary.ftl | 30 + .../nest/nestml/function/RecordCallback.ftl | 20 + .../nest/nestml/function/SetOldAliasState.ftl | 12 + .../nestml/function/StructGetterSetter.ftl | 13 + .../nest/nestml/function/TimestepDynamics.ftl | 13 + .../nestml/function/WriteInDictionary.ftl | 18 + .../org/nest/nestml/module/Bootstrap.ftl | 44 ++ .../org/nest/nestml/module/Configure.ftl | 200 ++++++ .../org/nest/nestml/module/Makefile.ftl | 57 ++ .../org/nest/nestml/module/ModuleClass.ftl | 107 ++++ .../org/nest/nestml/module/ModuleHeader.ftl | 108 ++++ .../org/nest/nestml/module/SLI_Init.ftl | 29 + .../org/nest/nestml/neuron/NeuronClass.ftl | 239 +++++++ .../org/nest/nestml/neuron/NeuronHeader.ftl | 426 +++++++++++++ .../resources/org/nest/ode/SympySolver.ftl | 102 +++ .../resources/org/nest/spl/Assignment.ftl | 25 + src/main/resources/org/nest/spl/Block.ftl | 10 + .../org/nest/spl/CompoundStatement.ftl | 16 + .../resources/org/nest/spl/Declaration.ftl | 18 + .../resources/org/nest/spl/ForStatement.ftl | 14 + .../resources/org/nest/spl/FunctionCall.ftl | 10 + .../resources/org/nest/spl/IfStatement.ftl | 27 + .../org/nest/spl/ReturnStatement.ftl | 11 + .../resources/org/nest/spl/SimpleStmt.ftl | 10 + .../resources/org/nest/spl/SmallStatement.ftl | 18 + src/main/resources/org/nest/spl/Statement.ftl | 11 + .../resources/org/nest/spl/WhileStatement.ftl | 10 + src/main/resources/org/nest/spl/expr/Expr.ftl | 9 + .../cli/CLIConfigurationExecutorTest.java | 28 + .../java/org/nest/cli/NESTMLFrontendTest.java | 104 ++++ .../GenerateNESTModelsTest.java | 49 ++ .../codegeneration/GenerationTestBase.java | 156 +++++ .../NESTML2NESTCodeGeneratorTest.java | 61 ++ .../NESTML2NESTWithODECodeGeneratorTest.java | 27 + .../integration/NESTMLCompilationTest.java | 24 + .../nest/nestml/cocos/NESTMLCoCosTest.java | 587 ++++++++++++++++++ .../nestml/parsing/NESTMLParsingTest.java | 68 ++ .../NESTMLPrettyPrinterTest.java | 91 +++ .../symboltable/NESTMLCoCosManagerTest.java | 145 +++++ .../symboltable/NESTMLSymbolTableTest.java | 199 ++++++ .../java/org/nest/ode/ModelConverterTest.java | 96 +++ .../nest/ode/ODE2SympyCodeGeneratorTest.java | 68 ++ src/test/java/org/nest/ode/ScopeMock.java | 83 +++ .../nest/ode/Sympy2NESTMLConverterTest.java | 24 + .../nest/ode/SympyLine2ASTConverterTest.java | 30 + .../org/nest/ode/SympyOutputReaderTest.java | 24 + .../org/nest/ode/parsing/ODEParsingTest.java | 79 +++ .../java/org/nest/spl/cocos/SPLCoCosTest.java | 243 ++++++++ .../SPL2NESTCodeGeneratorTest.java | 95 +++ .../spl/parsing/SPLExpressionParsingTest.java | 58 ++ .../org/nest/spl/parsing/SPLParsingTest.java | 55 ++ .../ExpressionsPrettyPrinterTest.java | 42 ++ .../prettyprinter/SPLPrettyPrinterTest.java | 1 + .../spl/symboltable/SPLCoCosManagerTest.java | 80 +++ .../spl/symboltable/SPLSymbolTableTest.java | 60 ++ .../ExpressionTypeCalculatorTest.java | 257 ++++++++ .../codegeneration/iaf_neuron_module.nestml | 96 +++ .../iaf_neuron_ode_module.nestml | 98 +++ .../iaf_psc_alpha_module.nestml | 132 ++++ .../iaf_psc_delta_module.nestml | 94 +++ .../codegeneration/iaf_psc_exp_module.nestml | 98 +++ .../iaf_psc_exp_multisynapse_module.nestml | 97 +++ .../codegeneration/iaf_tum_2000_module.nestml | 112 ++++ src/test/resources/integration/nest.nestml | 207 ++++++ .../nestml/cocos/aliasMultipleVars.nestml | 18 + .../org/nest/nestml/cocos/aliasSetter.nestml | 18 + .../nest/nestml/cocos/codeAfterReturn.nestml | 13 + .../nestml/cocos/componentWithDynamics.nestml | 6 + .../nestml/cocos/componentWithInput.nestml | 9 + .../nestml/cocos/componentWithOutput.nestml | 5 + .../org/nest/nestml/cocos/emptyNeuron.nestml | 4 + .../nest/nestml/cocos/funNotDefined.nestml | 13 + .../nestml/cocos/functionWithOutReturn.nestml | 17 + .../cocos/functionsWithWrongReturns.nestml | 25 + .../org/nest/nestml/cocos/getterSetter.nestml | 33 + .../cocos/illegalNumberExpressions.nestml | 42 ++ .../cocos/illegalStringExpressions.nestml | 27 + .../nestml/cocos/inputTypeForCurrent.nestml | 12 + .../nestml/cocos/invalidTypeInDecl.nestml | 23 + .../invariants/invalidInvariantType.nestml | 28 + .../invariants/validInvariantType.nestml | 27 + .../cocos/memberVarDefinedInWrongOrder.nestml | 18 + .../nestml/cocos/multipleAliasVars.nestml | 11 + .../cocos/multipleDynamicsNeuron.nestml | 9 + .../cocos/multipleFunctionDeclarations.nestml | 33 + .../nestml/cocos/multipleInhExcInInput.nestml | 12 + .../nest/nestml/cocos/multipleOutputs.nestml | 11 + .../nestml/cocos/multipleTypesDeclared.nestml | 11 + .../org/nest/nestml/cocos/nestFunName.nestml | 30 + .../nest/nestml/cocos/nestmlPackage.nestml | 3 + .../org/nest/nestml/cocos/paramExpr.nestml | 17 + .../nest/nestml/cocos/reassignBuffer.nestml | 11 + .../nestml/cocos/reassignParaInternal.nestml | 18 + .../cocos/splInFunctions/invalidMethod.nestml | 78 +++ .../cocos/splInFunctions/validMethod.nestml | 31 + .../nest/nestml/cocos/timestepDynamics.nestml | 17 + .../nestml/cocos/typenameAsVarName.nestml | 20 + .../invalidModelUndefinedValues.nestml | 33 + .../validModelUndefinedValues.nestml | 29 + .../cocos/useAliasInNonAliasDecl.nestml | 13 + .../useComponents/importedComponent.nestml | 9 + .../cocos/useComponents/importedNeuron.nestml | 9 + .../cocos/useComponents/invalidUsage.nestml | 15 + .../cocos/useComponents/validUsage.nestml | 32 + .../org/nest/nestml/cocos/validImports.nestml | 7 + .../cocos/varDefinedMultipleTimes.nestml | 13 + .../cocos/varDefinedMultipleTimesLocal.nestml | 35 ++ .../nest/nestml/cocos/varNotDefined.nestml | 11 + .../cocos/varNotDefinedBeforeUse.nestml | 11 + .../nestml/cocos/varNotDefinedInTest.nestml | 10 + .../nest/nestml/cocos/varWithTypeName.nestml | 12 + .../parsing/aneuronWithUseAndCode.nestml | 23 + .../nest/nestml/parsing/emptyComponent.nestml | 5 + .../nest/nestml/parsing/emptyFuncWPars.nestml | 27 + .../nest/nestml/parsing/emptyFunction.nestml | 18 + .../nest/nestml/parsing/emptyNeuron.nestml | 14 + .../nest/nestml/parsing/emptyPackage.nestml | 3 + .../nestml/parsing/functionWithReturn.nestml | 28 + .../nest/nestml/parsing/headerInNeuron.nestml | 22 + .../org/nest/nestml/parsing/iaf_neuron.nestml | 98 +++ .../nest/nestml/parsing/iaf_tum_2000.nestml | 112 ++++ .../org/nest/nestml/parsing/imports.nestml | 7 + .../nestml/parsing/nestCodeInNeuron.nestml | 22 + .../parsing/neuronWithEmptyComponent.nestml | 20 + .../nest/nestml/parsing/neuronWithUse.nestml | 22 + .../nest/nestml/parsing/neuronWithVars.nestml | 34 + .../parsing/neuronWithVarsAndDynamics.nestml | 60 ++ .../parsing/referenceInnerComponent.nestml | 32 + .../nest/nestml/symboltable/iaf_neuron.nestml | 121 ++++ .../symboltable/importedComponent.nestml | 9 + .../nestml/symboltable/importingNeuron.nestml | 32 + .../org/nest/ode/solution.matrix.tmp | 9 + .../spl/cocos/assignmentOfRightType.simple | 11 + .../cocos/codeAfterEmbeddedReturningIf.simple | 17 + .../org/nest/spl/cocos/codeAfterReturn.simple | 7 + .../spl/cocos/codeAfterReturningFor.simple | 14 + .../spl/cocos/codeAfterReturningIf.simple | 12 + .../spl/cocos/codeAfterReturningWhile.simple | 16 + .../spl/cocos/expressionsInForMatchVar.simple | 6 + .../org/nest/spl/cocos/funNotDefined.simple | 6 + .../spl/cocos/illegalNumberExpressions.simple | 29 + .../spl/cocos/illegalStringExpressions.simple | 17 + .../org/nest/spl/cocos/illegalVarInFor.simple | 5 + .../org/nest/spl/cocos/multipleSigns.simple | 9 + .../spl/cocos/varDefinedMultipleTimes.simple | 18 + .../org/nest/spl/cocos/varNotDefined.simple | 6 + .../spl/cocos/varNotDefinedBeforeUse.simple | 13 + .../nest/spl/cocos/varNotDefinedInTest.simple | 7 + .../org/nest/spl/cocos/varWithTypeName.simple | 3 + .../org/nest/spl/codegeneration/decl.simple | 46 ++ .../spl/codegeneration/declAndAssign.simple | 3 + .../nest/spl/codegeneration/emptyBlock.simple | 3 + .../nest/spl/codegeneration/funCall.simple | 8 + .../spl/codegeneration/mathExpressions.simple | 7 + .../spl/codegeneration/returnInFor.simple | 10 + .../spl/codegeneration/returnInWhile.simple | 13 + .../nest/spl/codegeneration/simpleFor.simple | 17 + .../nest/spl/codegeneration/simpleIf.simple | 7 + .../spl/codegeneration/simpleIfElif.simple | 11 + .../codegeneration/simpleIfElifElse.simple | 13 + .../spl/codegeneration/simpleIfElse.simple | 10 + .../spl/codegeneration/simpleReturns.simple | 26 + .../spl/codegeneration/simpleWhile.simple | 8 + .../spl/parsing/complexExpressions.simple | 8 + .../parsing/complexExpressionsWithOde.simple | 13 + .../org/nest/spl/parsing/decl.simple | 9 + .../org/nest/spl/parsing/declAndAssign.simple | 5 + .../org/nest/spl/parsing/emptyBlock.simple | 3 + .../org/nest/spl/parsing/funCall.simple | 7 + .../nest/spl/parsing/mathExpressions.simple | 8 + .../modelContainingAllLanguageElements.simple | 100 +++ .../org/nest/spl/parsing/returnInFor.simple | 10 + .../org/nest/spl/parsing/returnInWhile.simple | 13 + .../org/nest/spl/parsing/simpleFor.simple | 17 + .../org/nest/spl/parsing/simpleIf.simple | 7 + .../org/nest/spl/parsing/simpleIfElif.simple | 11 + .../nest/spl/parsing/simpleIfElifElse.simple | 13 + .../org/nest/spl/parsing/simpleIfElse.simple | 10 + .../org/nest/spl/parsing/simpleReturns.simple | 26 + .../org/nest/spl/parsing/simpleWhile.simple | 8 + .../org/nest/spl/symboltable/decl.simple | 12 + .../spl/symboltable/mathExpressions.simple | 21 + 297 files changed, 17061 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/grammars/org/nest/NESTML.mc4 create mode 100644 src/main/grammars/org/nest/SPL.mc4 create mode 100644 src/main/grammars/org/nest/commons/Commons.mc4 create mode 100644 src/main/java/org/nest/cli/CLIConfigurationExecutor.java create mode 100644 src/main/java/org/nest/cli/NESTMLFrontend.java create mode 100644 src/main/java/org/nest/cli/NESTMLToolConfiguration.java create mode 100644 src/main/java/org/nest/codegeneration/NESTML2NESTCodeGenerator.java create mode 100644 src/main/java/org/nest/codegeneration/NESTML2NESTTypeConverter.java create mode 100644 src/main/java/org/nest/codegeneration/NESTMLBuffers.java create mode 100644 src/main/java/org/nest/codegeneration/NESTMLDeclarations.java create mode 100644 src/main/java/org/nest/codegeneration/NESTMLDynamicsPrinter.java create mode 100644 src/main/java/org/nest/codegeneration/NESTMLFunctionPrinter.java create mode 100644 src/main/java/org/nest/codegeneration/NESTMLInputs.java create mode 100644 src/main/java/org/nest/codegeneration/NESTMLOutputs.java create mode 100644 src/main/java/org/nest/codegeneration/SPL2NESTCodeGenerator.java create mode 100644 src/main/java/org/nest/codegeneration/SPLForNodes.java create mode 100644 src/main/java/org/nest/codegeneration/SPLFunctionCalls.java create mode 100644 src/main/java/org/nest/codegeneration/SPLVariableGetterSetterHelper.java create mode 100644 src/main/java/org/nest/codegeneration/converters/IReferenceConverter.java create mode 100644 src/main/java/org/nest/codegeneration/converters/IdempotentReferenceConverter.java create mode 100644 src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java create mode 100644 src/main/java/org/nest/nestml/_symboltable/CommonNESTMLSymbolTableCreator.java create mode 100644 src/main/java/org/nest/nestml/_symboltable/NESTMLCoCosManager.java create mode 100644 src/main/java/org/nest/nestml/_symboltable/NESTMLLanguage.java create mode 100644 src/main/java/org/nest/nestml/_symboltable/NESTMLMethodSignaturePredicate.java create mode 100644 src/main/java/org/nest/nestml/_symboltable/NESTMLModelLoader.java create mode 100644 src/main/java/org/nest/nestml/_symboltable/NESTMLRootCreator.java create mode 100644 src/main/java/org/nest/nestml/_symboltable/NESTMLScopeCreator.java create mode 100644 src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java create mode 100644 src/main/java/org/nest/nestml/cocos/AliasHasNoSetter.java create mode 100644 src/main/java/org/nest/nestml/cocos/AliasHasOneVar.java create mode 100644 src/main/java/org/nest/nestml/cocos/AliasInNonAliasDecl.java create mode 100644 src/main/java/org/nest/nestml/cocos/BooleanInvariantExpressions.java create mode 100644 src/main/java/org/nest/nestml/cocos/ComponentHasNoDynamics.java create mode 100644 src/main/java/org/nest/nestml/cocos/ComponentNoInput.java create mode 100644 src/main/java/org/nest/nestml/cocos/ComponentNoOutput.java create mode 100644 src/main/java/org/nest/nestml/cocos/CorrectReturnValues.java create mode 100644 src/main/java/org/nest/nestml/cocos/CurrentInputIsNotInhExc.java create mode 100644 src/main/java/org/nest/nestml/cocos/DynamicsTimeStepParameter.java create mode 100644 src/main/java/org/nest/nestml/cocos/FunctionHasReturnStatement.java create mode 100644 src/main/java/org/nest/nestml/cocos/InvalidTypesInDeclaration.java create mode 100644 src/main/java/org/nest/nestml/cocos/MemberVariableDefinedMultipleTimes.java create mode 100644 src/main/java/org/nest/nestml/cocos/MemberVariablesInitialisedInCorrectOrder.java create mode 100644 src/main/java/org/nest/nestml/cocos/MultipleFunctionDeclarations.java create mode 100644 src/main/java/org/nest/nestml/cocos/MultipleInhExcInput.java create mode 100644 src/main/java/org/nest/nestml/cocos/MultipleOutputs.java create mode 100644 src/main/java/org/nest/nestml/cocos/NESTFunctionNameChecker.java create mode 100644 src/main/java/org/nest/nestml/cocos/NESTGetterSetterFunctionNames.java create mode 100644 src/main/java/org/nest/nestml/cocos/NeuronNeedsDynamics.java create mode 100644 src/main/java/org/nest/nestml/cocos/NeuronWithoutInput.java create mode 100644 src/main/java/org/nest/nestml/cocos/NeuronWithoutOutput.java create mode 100644 src/main/java/org/nest/nestml/cocos/TypeIsDeclaredMultipleTimes.java create mode 100644 src/main/java/org/nest/nestml/cocos/UsesOnlyComponents.java create mode 100644 src/main/java/org/nest/nestml/cocos/spl/BufferNotAssignable.java create mode 100644 src/main/java/org/nest/nestml/nestml/_ast/ASTBodyDecorator.java create mode 100644 src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java create mode 100644 src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterFactory.java create mode 100644 src/main/java/org/nest/ode/ModelConverter.java create mode 100644 src/main/java/org/nest/ode/ODE2SympyCodeGenerator.java create mode 100644 src/main/java/org/nest/ode/Sympy2NESTMLConverter.java create mode 100644 src/main/java/org/nest/ode/SympyLine2ASTConverter.java create mode 100644 src/main/java/org/nest/ode/SympyOutputReader.java create mode 100644 src/main/java/org/nest/spl/_symboltable/SPLLanguage.java create mode 100644 src/main/java/org/nest/spl/cocos/CheckMultipleSignsBeforeFactor.java create mode 100644 src/main/java/org/nest/spl/cocos/CodeAfterReturn.java create mode 100644 src/main/java/org/nest/spl/cocos/FunctionDoesntExist.java create mode 100644 src/main/java/org/nest/spl/cocos/IllegalExpression.java create mode 100644 src/main/java/org/nest/spl/cocos/IllegalVarInFor.java create mode 100644 src/main/java/org/nest/spl/cocos/VarHasTypeName.java create mode 100644 src/main/java/org/nest/spl/cocos/VariableDefinedMultipleTimes.java create mode 100644 src/main/java/org/nest/spl/cocos/VariableDoesNotExist.java create mode 100644 src/main/java/org/nest/spl/cocos/VariableNotDefinedBeforeUse.java create mode 100644 src/main/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinter.java create mode 100644 src/main/java/org/nest/spl/prettyprinter/SPLPrettyPrinter.java create mode 100644 src/main/java/org/nest/spl/prettyprinter/SPLPrettyPrinterFactory.java create mode 100644 src/main/java/org/nest/spl/symboltable/CommonSPLSymbolTableCreator.java create mode 100644 src/main/java/org/nest/spl/symboltable/SPLCoCosManager.java create mode 100644 src/main/java/org/nest/spl/symboltable/SPLModelLoader.java create mode 100644 src/main/java/org/nest/spl/symboltable/SPLScopeCreator.java create mode 100644 src/main/java/org/nest/spl/symboltable/SPLSymbolTableCreator.java create mode 100644 src/main/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculator.java create mode 100644 src/main/java/org/nest/spl/symboltable/typechecking/TypeChecker.java create mode 100644 src/main/java/org/nest/symboltable/ScopeCreatorBase.java create mode 100644 src/main/java/org/nest/symboltable/predefined/PredefinedFunctionFactory.java create mode 100644 src/main/java/org/nest/symboltable/predefined/PredefinedTypesFactory.java create mode 100644 src/main/java/org/nest/symboltable/predefined/PredefinedVariablesFactory.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLMethodSymbol.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLMethodSymbolKind.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLNeuronSymbol.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLNeuronSymbolKind.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLTypeSymbol.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLTypeSymbolKind.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLUsageSymbol.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLUsageSymbolKind.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLVariableSymbol.java create mode 100644 src/main/java/org/nest/symboltable/symbols/NESTMLVariableSymbolKind.java create mode 100644 src/main/java/org/nest/symboltable/symbols/references/NESTMLNeuronSymbolReference.java create mode 100644 src/main/java/org/nest/symboltable/symbols/references/NESTMLTypeSymbolReference.java create mode 100644 src/main/java/org/nest/utils/ASTNodes.java create mode 100644 src/main/java/org/nest/utils/CachedResolver.java create mode 100644 src/main/java/org/nest/utils/LogHelper.java create mode 100644 src/main/java/org/nest/utils/NESTMLSymbols.java create mode 100644 src/main/java/org/nest/utils/PrettyPrinterBase.java create mode 100644 src/main/resources/org/nest/nestml/MemberDeclaration.ftl create mode 100644 src/main/resources/org/nest/nestml/buffer/CurrentBufferFill.ftl create mode 100644 src/main/resources/org/nest/nestml/buffer/SpikeBufferFill.ftl create mode 100644 src/main/resources/org/nest/nestml/function/Calibrate.ftl create mode 100644 src/main/resources/org/nest/nestml/function/DynamicsImplementation.ftl create mode 100644 src/main/resources/org/nest/nestml/function/Invariant.ftl create mode 100644 src/main/resources/org/nest/nestml/function/MemberInitialization.ftl create mode 100644 src/main/resources/org/nest/nestml/function/MemberVariableGetterSetter.ftl create mode 100644 src/main/resources/org/nest/nestml/function/MinDelayDynamics.ftl create mode 100644 src/main/resources/org/nest/nestml/function/ReadFromDictionary.ftl create mode 100644 src/main/resources/org/nest/nestml/function/RecordCallback.ftl create mode 100644 src/main/resources/org/nest/nestml/function/SetOldAliasState.ftl create mode 100644 src/main/resources/org/nest/nestml/function/StructGetterSetter.ftl create mode 100644 src/main/resources/org/nest/nestml/function/TimestepDynamics.ftl create mode 100644 src/main/resources/org/nest/nestml/function/WriteInDictionary.ftl create mode 100644 src/main/resources/org/nest/nestml/module/Bootstrap.ftl create mode 100644 src/main/resources/org/nest/nestml/module/Configure.ftl create mode 100644 src/main/resources/org/nest/nestml/module/Makefile.ftl create mode 100644 src/main/resources/org/nest/nestml/module/ModuleClass.ftl create mode 100644 src/main/resources/org/nest/nestml/module/ModuleHeader.ftl create mode 100644 src/main/resources/org/nest/nestml/module/SLI_Init.ftl create mode 100644 src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl create mode 100644 src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl create mode 100644 src/main/resources/org/nest/ode/SympySolver.ftl create mode 100644 src/main/resources/org/nest/spl/Assignment.ftl create mode 100644 src/main/resources/org/nest/spl/Block.ftl create mode 100644 src/main/resources/org/nest/spl/CompoundStatement.ftl create mode 100644 src/main/resources/org/nest/spl/Declaration.ftl create mode 100644 src/main/resources/org/nest/spl/ForStatement.ftl create mode 100644 src/main/resources/org/nest/spl/FunctionCall.ftl create mode 100644 src/main/resources/org/nest/spl/IfStatement.ftl create mode 100644 src/main/resources/org/nest/spl/ReturnStatement.ftl create mode 100644 src/main/resources/org/nest/spl/SimpleStmt.ftl create mode 100644 src/main/resources/org/nest/spl/SmallStatement.ftl create mode 100644 src/main/resources/org/nest/spl/Statement.ftl create mode 100644 src/main/resources/org/nest/spl/WhileStatement.ftl create mode 100644 src/main/resources/org/nest/spl/expr/Expr.ftl create mode 100644 src/test/java/org/nest/cli/CLIConfigurationExecutorTest.java create mode 100644 src/test/java/org/nest/cli/NESTMLFrontendTest.java create mode 100644 src/test/java/org/nest/codegeneration/GenerateNESTModelsTest.java create mode 100644 src/test/java/org/nest/codegeneration/GenerationTestBase.java create mode 100644 src/test/java/org/nest/codegeneration/NESTML2NESTCodeGeneratorTest.java create mode 100644 src/test/java/org/nest/codegeneration/NESTML2NESTWithODECodeGeneratorTest.java create mode 100644 src/test/java/org/nest/integration/NESTMLCompilationTest.java create mode 100644 src/test/java/org/nest/nestml/cocos/NESTMLCoCosTest.java create mode 100644 src/test/java/org/nest/nestml/parsing/NESTMLParsingTest.java create mode 100644 src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java create mode 100644 src/test/java/org/nest/nestml/symboltable/NESTMLCoCosManagerTest.java create mode 100644 src/test/java/org/nest/nestml/symboltable/NESTMLSymbolTableTest.java create mode 100644 src/test/java/org/nest/ode/ModelConverterTest.java create mode 100644 src/test/java/org/nest/ode/ODE2SympyCodeGeneratorTest.java create mode 100644 src/test/java/org/nest/ode/ScopeMock.java create mode 100644 src/test/java/org/nest/ode/Sympy2NESTMLConverterTest.java create mode 100644 src/test/java/org/nest/ode/SympyLine2ASTConverterTest.java create mode 100644 src/test/java/org/nest/ode/SympyOutputReaderTest.java create mode 100644 src/test/java/org/nest/ode/parsing/ODEParsingTest.java create mode 100644 src/test/java/org/nest/spl/cocos/SPLCoCosTest.java create mode 100644 src/test/java/org/nest/spl/codegeneration/SPL2NESTCodeGeneratorTest.java create mode 100644 src/test/java/org/nest/spl/parsing/SPLExpressionParsingTest.java create mode 100644 src/test/java/org/nest/spl/parsing/SPLParsingTest.java create mode 100644 src/test/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinterTest.java create mode 100644 src/test/java/org/nest/spl/prettyprinter/SPLPrettyPrinterTest.java create mode 100644 src/test/java/org/nest/spl/symboltable/SPLCoCosManagerTest.java create mode 100644 src/test/java/org/nest/spl/symboltable/SPLSymbolTableTest.java create mode 100644 src/test/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculatorTest.java create mode 100644 src/test/resources/codegeneration/iaf_neuron_module.nestml create mode 100644 src/test/resources/codegeneration/iaf_neuron_ode_module.nestml create mode 100644 src/test/resources/codegeneration/iaf_psc_alpha_module.nestml create mode 100644 src/test/resources/codegeneration/iaf_psc_delta_module.nestml create mode 100644 src/test/resources/codegeneration/iaf_psc_exp_module.nestml create mode 100644 src/test/resources/codegeneration/iaf_psc_exp_multisynapse_module.nestml create mode 100644 src/test/resources/codegeneration/iaf_tum_2000_module.nestml create mode 100644 src/test/resources/integration/nest.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/aliasMultipleVars.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/aliasSetter.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/codeAfterReturn.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/componentWithDynamics.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/componentWithInput.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/componentWithOutput.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/emptyNeuron.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/funNotDefined.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/functionWithOutReturn.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/functionsWithWrongReturns.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/getterSetter.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/illegalNumberExpressions.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/illegalStringExpressions.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/inputTypeForCurrent.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/invalidTypeInDecl.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/invariants/invalidInvariantType.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/invariants/validInvariantType.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/memberVarDefinedInWrongOrder.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/multipleAliasVars.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/multipleDynamicsNeuron.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/multipleFunctionDeclarations.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/multipleInhExcInInput.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/multipleOutputs.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/multipleTypesDeclared.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/nestFunName.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/nestmlPackage.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/paramExpr.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/reassignBuffer.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/reassignParaInternal.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/splInFunctions/invalidMethod.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/splInFunctions/validMethod.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/timestepDynamics.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/typenameAsVarName.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/undefinedVariables/invalidModelUndefinedValues.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/undefinedVariables/validModelUndefinedValues.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/useAliasInNonAliasDecl.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/useComponents/importedComponent.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/useComponents/importedNeuron.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/useComponents/invalidUsage.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/useComponents/validUsage.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/validImports.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/varDefinedMultipleTimes.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/varDefinedMultipleTimesLocal.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/varNotDefined.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/varNotDefinedBeforeUse.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/varNotDefinedInTest.nestml create mode 100644 src/test/resources/org/nest/nestml/cocos/varWithTypeName.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/aneuronWithUseAndCode.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/emptyComponent.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/emptyFuncWPars.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/emptyFunction.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/emptyNeuron.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/emptyPackage.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/functionWithReturn.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/headerInNeuron.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/iaf_neuron.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/iaf_tum_2000.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/imports.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/nestCodeInNeuron.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/neuronWithEmptyComponent.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/neuronWithUse.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/neuronWithVars.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/neuronWithVarsAndDynamics.nestml create mode 100644 src/test/resources/org/nest/nestml/parsing/referenceInnerComponent.nestml create mode 100644 src/test/resources/org/nest/nestml/symboltable/iaf_neuron.nestml create mode 100644 src/test/resources/org/nest/nestml/symboltable/importedComponent.nestml create mode 100644 src/test/resources/org/nest/nestml/symboltable/importingNeuron.nestml create mode 100644 src/test/resources/org/nest/ode/solution.matrix.tmp create mode 100644 src/test/resources/org/nest/spl/cocos/assignmentOfRightType.simple create mode 100644 src/test/resources/org/nest/spl/cocos/codeAfterEmbeddedReturningIf.simple create mode 100644 src/test/resources/org/nest/spl/cocos/codeAfterReturn.simple create mode 100644 src/test/resources/org/nest/spl/cocos/codeAfterReturningFor.simple create mode 100644 src/test/resources/org/nest/spl/cocos/codeAfterReturningIf.simple create mode 100644 src/test/resources/org/nest/spl/cocos/codeAfterReturningWhile.simple create mode 100644 src/test/resources/org/nest/spl/cocos/expressionsInForMatchVar.simple create mode 100644 src/test/resources/org/nest/spl/cocos/funNotDefined.simple create mode 100644 src/test/resources/org/nest/spl/cocos/illegalNumberExpressions.simple create mode 100644 src/test/resources/org/nest/spl/cocos/illegalStringExpressions.simple create mode 100644 src/test/resources/org/nest/spl/cocos/illegalVarInFor.simple create mode 100644 src/test/resources/org/nest/spl/cocos/multipleSigns.simple create mode 100644 src/test/resources/org/nest/spl/cocos/varDefinedMultipleTimes.simple create mode 100644 src/test/resources/org/nest/spl/cocos/varNotDefined.simple create mode 100644 src/test/resources/org/nest/spl/cocos/varNotDefinedBeforeUse.simple create mode 100644 src/test/resources/org/nest/spl/cocos/varNotDefinedInTest.simple create mode 100644 src/test/resources/org/nest/spl/cocos/varWithTypeName.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/decl.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/declAndAssign.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/emptyBlock.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/funCall.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/mathExpressions.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/returnInFor.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/returnInWhile.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/simpleFor.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/simpleIf.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/simpleIfElif.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/simpleIfElifElse.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/simpleIfElse.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/simpleReturns.simple create mode 100644 src/test/resources/org/nest/spl/codegeneration/simpleWhile.simple create mode 100644 src/test/resources/org/nest/spl/parsing/complexExpressions.simple create mode 100644 src/test/resources/org/nest/spl/parsing/complexExpressionsWithOde.simple create mode 100644 src/test/resources/org/nest/spl/parsing/decl.simple create mode 100644 src/test/resources/org/nest/spl/parsing/declAndAssign.simple create mode 100644 src/test/resources/org/nest/spl/parsing/emptyBlock.simple create mode 100644 src/test/resources/org/nest/spl/parsing/funCall.simple create mode 100644 src/test/resources/org/nest/spl/parsing/mathExpressions.simple create mode 100644 src/test/resources/org/nest/spl/parsing/modelContainingAllLanguageElements.simple create mode 100644 src/test/resources/org/nest/spl/parsing/returnInFor.simple create mode 100644 src/test/resources/org/nest/spl/parsing/returnInWhile.simple create mode 100644 src/test/resources/org/nest/spl/parsing/simpleFor.simple create mode 100644 src/test/resources/org/nest/spl/parsing/simpleIf.simple create mode 100644 src/test/resources/org/nest/spl/parsing/simpleIfElif.simple create mode 100644 src/test/resources/org/nest/spl/parsing/simpleIfElifElse.simple create mode 100644 src/test/resources/org/nest/spl/parsing/simpleIfElse.simple create mode 100644 src/test/resources/org/nest/spl/parsing/simpleReturns.simple create mode 100644 src/test/resources/org/nest/spl/parsing/simpleWhile.simple create mode 100644 src/test/resources/org/nest/spl/symboltable/decl.simple create mode 100644 src/test/resources/org/nest/spl/symboltable/mathExpressions.simple diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..0f8a070a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.settings/ +target/ +.idea/ + +.DS_Store +.project +.classpath +*~ +*.iml diff --git a/README.md b/README.md new file mode 100644 index 000000000..b691f412d --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# NESTML - The NEST Modelling Language diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..7ff43b83b --- /dev/null +++ b/pom.xml @@ -0,0 +1,235 @@ + + 4.0.0 + + + + nestml + nestml-core + 0.0.3-SNAPSHOT + + + + + 18.0 + 1.3 + 4.11 + + + 4.5 + 4.1.6 + 4.1.6 + + + 3.2 + 2.5.1 + 2.4 + + + grammars + symbols + models + + + 1.8 + 2.6 + 1.1.2 + 2.3.7 + + UTF-8 + UTF-8 + + + + + nestml-core + http://lab11.se.rwth-aachen.de/nexus/service/local/repositories/se-sites/content/monticore/${project.version}/ + 2013 + + + Department of Software Engineering, RWTH Aachen University + http://www.se-rwth.de/ + + + + + Developer + monticore-dev@se-rwth.de + + + + + Trac + https://sselab.de/lab2/private/trac/MontiCore/ + + + + + + + + + + + + + + de.monticore.mojo + monticore-maven-plugin + ${mc4.maven.generator} + + false + + + + + generate + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler.plugin} + + ${java.version} + ${java.version} + + + + + org.apache.maven.plugins + maven-release-plugin + ${release.plugin} + + monticore-@{project.version} + + + + + maven-source-plugin + ${source.plugin} + + + package + + jar-no-fork + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.5.4 + + + jar-with-dependencies + + + + true + org.nest.cli.NESTMLFrontend + + + + + + assemble-all + package + + single + + + + + + + + + + + + ch.qos.logback + logback-classic + ${logback.version} + + + + com.google.guava + guava + ${guava.version} + + + + commons-cli + commons-cli + ${commons.cli.version} + + + + + + org.antlr + antlr4-runtime + ${antlr.version} + + + + de.monticore + monticore-runtime + ${monticore.runtime} + + + + de.monticore + monticore-grammar + ${monticore.runtime} + + + + de.monticore + monticore-grammar + ${monticore.runtime} + ${grammars.classifier} + + + + + junit + junit + ${junit.version} + test + + + + de.monticore + monticore-runtime + ${monticore.runtime} + test-jar + test + + + + org.codehaus.groovy + groovy + ${groovy.version} + + + + + diff --git a/src/main/grammars/org/nest/NESTML.mc4 b/src/main/grammars/org/nest/NESTML.mc4 new file mode 100644 index 000000000..5c5ab9733 --- /dev/null +++ b/src/main/grammars/org/nest/NESTML.mc4 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest; + +grammar NESTML extends org.nest.SPL { + + /** ASTNESTMLCompilationUnit represents the complete entire file with neuron and component models. + @attribute packageName The qualified name to artifact + @attribute Import List of imported elements + @attribute Neuron The neuron representation + @attribute Component The component representation + */ + NESTMLCompilationUnit = "package" packageName:QualifiedName + BLOCK_OPEN + (Import | NEWLINE)* + (Neuron | Component | NEWLINE)* + BLOCK_CLOSE; + + /** ASTImport represents the import line. Can be the qualified name oder a wirldcard import. + @attribute qualifiedName The qualified name to artifact + @attribute star Optional wildcard + */ + Import = "import" QualifiedName ([star:".*"])? (";")?; + + Neuron = "neuron" Name Body; + + Component = "component" Name Body; + + interface BodyElement; + + Body = BLOCK_OPEN ( NEWLINE | BodyElement)* BLOCK_CLOSE; + + USE_Stmt implements BodyElement = "use" name:QualifiedName "as" alias:Name; + + Var_Block implements BodyElement = + (["state"]|["parameter"]|["internal"]) + BLOCK_OPEN + (AliasDecl (";" AliasDecl)* (";")? | NEWLINE)* + BLOCK_CLOSE; + + AliasDecl = ([hide:"-"])? (["alias"])? Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + + Input implements BodyElement = "input" + BLOCK_OPEN + (InputLine | NEWLINE)* + BLOCK_CLOSE; + + InputLine = + Name + ("<" sizeParameter:Name ">")? + "<-" InputType* + (["spike"] | ["current"]); + + InputType = (["inhibitory"] | ["excitatory"]); + + Output implements BodyElement = + "output" BLOCK_OPEN (["spike"] | ["current"]) ; + + Structure implements BodyElement = "structure" + BLOCK_OPEN + (StructureLine | NEWLINE)* + BLOCK_CLOSE; + + StructureLine = compartments:QualifiedName ("-" compartments:QualifiedName)*; + + // TODO model it better + Function implements BodyElement = + "function" Name "(" Parameters? ")" (returnType:QualifiedName | PrimitiveType)? + BLOCK_OPEN + Block + BLOCK_CLOSE; + + // e.g. first: current time, second: min delay in ms + // e.g. first: current time, second: timestep in ms + Dynamics implements BodyElement = "dynamics" (MinDelay | TimeStep) + "(" Parameters? ")" + BLOCK_OPEN // Todo remove me. It is not the way for modular extension + Block + BLOCK_CLOSE; + + + MinDelay = "minDelay"; + + TimeStep = "timestep"; + + Parameters = Parameter ("," Parameter)*; + + Parameter = Name type:QualifiedName; + +} diff --git a/src/main/grammars/org/nest/SPL.mc4 b/src/main/grammars/org/nest/SPL.mc4 new file mode 100644 index 000000000..38f0ee617 --- /dev/null +++ b/src/main/grammars/org/nest/SPL.mc4 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest; + +grammar SPL extends org.nest.commons.Commons { + + SPLFile = ModuleDefinitionStatement Block; + + ModuleDefinitionStatement = "module" moduleName:QualifiedName; + + Block = ( Stmt | NEWLINE )*; + + Stmt = Simple_Stmt | Compound_Stmt; + + Compound_Stmt = IF_Stmt + | FOR_Stmt + | WHILE_Stmt; + + Simple_Stmt = Small_Stmt (";" Small_Stmt)* (";")?; + + Small_Stmt = Assignment + | FunctionCall + | Declaration + | ReturnStmt + | OdeDeclaration; + + OdeDeclaration = + "ODE" BLOCK_OPEN (NEWLINE)* + Eq (NEWLINE)* + ODE (NEWLINE)* + BLOCK_CLOSE; + + Eq = lhsVariable:Name "===" rhs:Expr; + ODE = "d/dt" lhsVariable:Name "===" rhs:Expr; + + Assignment = variableName:QualifiedName "=" Expr; + + // inherited PrimitiveType must be used here because otherwise the parser cannot distinguish between fqn: boolean and "keyword" boolean + Declaration = + vars:Name ("," vars:Name)* + (type:QualifiedName | primitiveType:PrimitiveType) + ("<" sizeParameter:Name ">")? + ( "=" Expr )? ; + + ReturnStmt = "return" Expr?; + + IF_Stmt = IF_Clause + ELIF_Clause* + (ELSE_Clause)? + BLOCK_CLOSE; + IF_Clause = "if" Expr BLOCK_OPEN Block; + + ELIF_Clause = "elif" Expr BLOCK_OPEN Block; + + ELSE_Clause = "else" BLOCK_OPEN Block; + + FOR_Stmt = "for" var:Name "in" from:Expr "..." to:Expr ("step" step:SignedNumericLiteral)? BLOCK_OPEN Block BLOCK_CLOSE; + + WHILE_Stmt = "while" Expr BLOCK_OPEN Block BLOCK_CLOSE; + + Expr = (unaryPlus:["+"] | unaryMinus:["-"] | unaryTilde:["~"]) term:Expr + | "not" Expr // TODO not explicit? + | base:Expr pow:["**"] exponent:Expr // TODO make right assoc keyword asap + | left:Expr (timesOp:["*"] | divOp:["/"] | moduloOp:["%"]) right:Expr + | left:Expr (plusOp:["+"] | minusOp:["-"]) right:Expr + | left:Expr (shiftLeft:["<<"] | shiftRight:[">>"]) right:Expr + | left:Expr bitAnd:["&"] right:Expr + | left:Expr bitOr:["|"] right:Expr + | left:Expr bitXor:["^"] right:Expr + | left:Expr (lt:["<"] | le:["<="] | eq:["=="] | ne:["!="] | ne2:["<>"] | ge:[">="] | gt:[">"]) right:Expr + | left:Expr logicalAnd:["and"] right:Expr + | left:Expr logicalOr:["or"] right:Expr + | FunctionCall + | BooleanLiteral // true & false; + | NumericLiteral type:QualifiedName? + | StringLiteral + | ["inf"] + | QualifiedName + | leftParentheses:"(" Expr rightParentheses:")"; + + FunctionCall = QualifiedName "(" ArgList ")"; + + ArgList = (args:Expr ("," args:Expr)*)?; +} diff --git a/src/main/grammars/org/nest/commons/Commons.mc4 b/src/main/grammars/org/nest/commons/Commons.mc4 new file mode 100644 index 000000000..67f88d575 --- /dev/null +++ b/src/main/grammars/org/nest/commons/Commons.mc4 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.commons; + +grammar Commons extends de.monticore.types.Types { + + token SL_COMMENT = + "#" (~('\n' | + '\r' ) + )* + ('\n' | + '\r' ('\n' )? + )? + : {_channel = HIDDEN; + if (getCompiler() != null) { + de.monticore.ast.Comment _comment = new de.monticore.ast.Comment(getText()); + _comment.set_SourcePositionStart(new de.se_rwth.commons.SourcePosition(getLine(), getCharPositionInLine())); + _comment.set_SourcePositionEnd(getCompiler().computeEndPosition(getToken())); + getCompiler().addComment(_comment); + }}; + + token NEWLINE = ('\r' '\n' | '\r' | '\n' ); + token WS = (' ' | '\t'):{_channel = HIDDEN;}; + + BLOCK_OPEN = ":"; + BLOCK_CLOSE = "end"; + +} diff --git a/src/main/java/org/nest/cli/CLIConfigurationExecutor.java b/src/main/java/org/nest/cli/CLIConfigurationExecutor.java new file mode 100644 index 000000000..1f03f8096 --- /dev/null +++ b/src/main/java/org/nest/cli/CLIConfigurationExecutor.java @@ -0,0 +1,127 @@ +package org.nest.cli; + +import com.google.common.collect.Lists; +import de.monticore.cocos.CoCoLog; +import de.se_rwth.commons.logging.Log; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._cocos.NESTMLCoCoChecker; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml._symboltable.NESTMLCoCosManager; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.utils.LogHelper; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +public class CLIConfigurationExecutor { + + private static final String LOG_NAME = CLIConfigurationExecutor.class.getName(); + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + public CLIConfigurationExecutor() { + Log.enableFailQuick(false); + } + + public boolean execute(final NESTMLToolConfiguration nestmlToolConfiguration) { + List nestmlModelFilenames = collectNestmlModelFilenames(nestmlToolConfiguration.getInputBasePath()); + handleCollectedModels(nestmlModelFilenames, nestmlToolConfiguration); + + return true; + } + + private List collectNestmlModelFilenames(final String inputPath) { + List filenames = Lists.newArrayList(); + try { + Files.list(new File(inputPath).toPath()) + .forEach(file -> filenames.add(file.getFileName().toString())); + } + catch (IOException e) { + final String msg = "There is a problem to process NESTML models in the folder: " + inputPath; + Log.error(msg, e); + throw new RuntimeException(msg, e); + } + Log.info("NESTML models found: #" + filenames.size(), LOG_NAME); + return filenames; + } + + private void handleCollectedModels( + final List nestmlModelFilenames, + final NESTMLToolConfiguration nestmlToolConfiguration) { + for (final String modelName:nestmlModelFilenames) { + handleSingleModel(modelName, nestmlToolConfiguration); + } + + } + + private void handleSingleModel(final String modelName, final NESTMLToolConfiguration nestmlToolConfiguration) { + parseWithOptionalCocosCheck(modelName, nestmlToolConfiguration); + Log.info("Processed model: " + modelName, LOG_NAME); + } + + private void parseWithOptionalCocosCheck(final String modelName, final NESTMLToolConfiguration nestmlToolConfiguration) { + final NESTMLCompilationUnitMCParser nestmlParser = NESTMLParserFactory + .createNESTMLCompilationUnitMCParser(); + try { + final Optional root = nestmlParser.parse(nestmlToolConfiguration.getInputBasePath() + + File.separator + modelName); + if (root.isPresent()) { + if (nestmlToolConfiguration.isCheckCoCos()) { + checkCocosForModel(modelName, nestmlToolConfiguration, root); + + } + + } + else { + Log.error("There is a problem with the model: " + modelName + ". It will be skipped."); + } + + } + catch (IOException e) { + Log.error("Skips the procession of the model: " + modelName, e); + } + + } + + private void checkCocosForModel( + final String modelName, + final NESTMLToolConfiguration toolConfiguration, + final Optional root) { + final NESTMLScopeCreator scopeCreator = new NESTMLScopeCreator( + toolConfiguration.getModelPath(), typesFactory); + + scopeCreator.runSymbolTableCreator(root.get()); + + final NESTMLCoCosManager nestmlCoCosManager + = new NESTMLCoCosManager( + root.get(), + scopeCreator.getTypesFactory()); + + final NESTMLCoCoChecker cocosChecker = nestmlCoCosManager.createDefaultChecker(); + + checkNESTMLCocos(root, cocosChecker); + evaluateCocosLog(modelName, LogHelper.getFindingsByPrefix("NESTML_", CoCoLog.getFindings())); + } + + private void checkNESTMLCocos(Optional root, NESTMLCoCoChecker cocosChecker) { + CoCoLog.getFindings().clear(); + cocosChecker.checkAll(root.get()); + } + + private void evaluateCocosLog(String modelName, Collection nestmlErrorFindings) { + if (nestmlErrorFindings.isEmpty()) { + Log.info(modelName + " contains no errors", LOG_NAME); + } + else { + Log.warn(modelName + " contains the following errors: "); + nestmlErrorFindings.forEach(Log::warn); + } + } + +} diff --git a/src/main/java/org/nest/cli/NESTMLFrontend.java b/src/main/java/org/nest/cli/NESTMLFrontend.java new file mode 100644 index 000000000..bbe608509 --- /dev/null +++ b/src/main/java/org/nest/cli/NESTMLFrontend.java @@ -0,0 +1,158 @@ +package org.nest.cli; + +import com.google.common.base.Joiner; +import de.se_rwth.commons.logging.Log; +import org.apache.commons.cli.*; + +/** + * Created by user on 22.05.15. + */ +public class NESTMLFrontend { + + private final static String LOGGER_NAME = NESTMLFrontend.class.getName(); + + public static final String RUNNING_MODE = "runningMode"; + + public static final String HELP_ARGUMENT = "help"; + + public static final String INPUT_MODELS = "input"; + + public static final String MODEL_PATH = "modelPath"; + + public static final String TARGET_PATH = "target"; + + private final Options options = new Options(); + private final HelpFormatter formatter = new HelpFormatter(); + + protected NESTMLFrontend() { + //"mode", true, "Chose the working mode. Possible options are: parse, check, generate"); + options.addOption(Option.builder(RUNNING_MODE) + .longOpt(RUNNING_MODE) + .hasArgs() + .numberOfArgs(1) + .desc("With the 'parseAndCheck' context conditions for NESTML are activated.") + .build()); + + options.addOption(Option.builder(INPUT_MODELS) + .longOpt(INPUT_MODELS) + .hasArgs() + .numberOfArgs(1) + .desc("Defines the path to input models. E.g. --" + INPUT_MODELS + " ./") + .build()); + + options.addOption(Option.builder(MODEL_PATH) + .longOpt(MODEL_PATH) + .hasArgs() + .numberOfArgs(1) + .desc("Defines the path to input models. E.g. --" + MODEL_PATH + " ./") + .build()); + + options.addOption(Option.builder(TARGET_PATH) + .longOpt(TARGET_PATH) + .hasArgs() + .numberOfArgs(1) + .desc("Defines the path where generated artifacts are stored. E.g. --" + TARGET_PATH + " ./") + .build()); + + options.addOption(Option.builder(HELP_ARGUMENT) + .longOpt(HELP_ARGUMENT) + .build()); + + } + + public static void main(String[] args) { + final NESTMLFrontend nestmlFrontend = new NESTMLFrontend(); + nestmlFrontend.handleCLIArguments(args); + + } + + public void handleCLIArguments(String[] args) { + NESTMLToolConfiguration nestmlToolConfiguration = createCLIConfiguration(args); + + } + + public NESTMLToolConfiguration createCLIConfiguration(String[] args) { + final CommandLine commandLineParameters = parseCLIArguments(args); + + interpretHelpArgument(commandLineParameters); + + boolean isCheckCocos = interpretRunningModeArgument(commandLineParameters); + final String inputModelPath = interpretInputModelsPathArgument(commandLineParameters); + final String modelPath = interpretModelPathArgument(commandLineParameters); + final String targetPath = interpretTargetPathArgument(commandLineParameters); + + final NESTMLToolConfiguration nestmlToolConfiguration = new NESTMLToolConfiguration + .Builder() + .withCoCos(isCheckCocos) + .withInputBasePath(inputModelPath) + .withModelPath(modelPath) + .withTargetPath(targetPath) + .build(); + return nestmlToolConfiguration; + } + + public CommandLine parseCLIArguments(String[] args) { + final CommandLineParser commandLineParser = new DefaultParser(); + final CommandLine commandLineParameters; + + try { + commandLineParameters = commandLineParser.parse(options, args); + } + catch (ParseException e) { + final String msg = "Cannot parse CLI arguments: " + Joiner.on(" ").join(args) + "\nThe reason: " + e.getMessage(); + formatter.printHelp(msg, options); + throw new RuntimeException(e); + } + return commandLineParameters; + } + + public void interpretHelpArgument(CommandLine cmd) { + if (cmd.hasOption(HELP_ARGUMENT)) { + formatter.printHelp("NESTML frontend", options ); + } + } + + public boolean interpretRunningModeArgument(final CommandLine cmd) { + boolean isCheckCocos = false; + if (cmd.hasOption(RUNNING_MODE)) { + Log.info("'" + RUNNING_MODE + "' option is set to: " + cmd.getOptionValue(RUNNING_MODE), LOGGER_NAME); + if (cmd.getOptionValue(RUNNING_MODE).equals("parseAndCheck")) { + Log.info("NESTML models will be parsed and checked.", LOGGER_NAME); + isCheckCocos = true; + } + + } + else { + Log.info("'" + RUNNING_MODE + "' is set to 'parse' only configuration", LOGGER_NAME); + } + return isCheckCocos; + } + + public String interpretInputModelsPathArgument(final CommandLine cmd) { + return interpretPathArgument(cmd, INPUT_MODELS); + } + + public String interpretModelPathArgument(final CommandLine cmd) { + return interpretPathArgument(cmd, MODEL_PATH); + } + + public String interpretTargetPathArgument(final CommandLine cmd) { + return interpretPathArgument(cmd, TARGET_PATH); + } + + private String interpretPathArgument(CommandLine cmd, String argumentName) { + if (cmd.hasOption(argumentName)) { + + Log.info("'" + argumentName + "' option is set to: " + cmd.getOptionValue(argumentName), LOGGER_NAME); + return cmd.getOptionValue(argumentName); + + } + else { + Log.info("Uses current folder as " + argumentName + " value", LOGGER_NAME); + return "./"; + } + + } + +} + diff --git a/src/main/java/org/nest/cli/NESTMLToolConfiguration.java b/src/main/java/org/nest/cli/NESTMLToolConfiguration.java new file mode 100644 index 000000000..f890c319c --- /dev/null +++ b/src/main/java/org/nest/cli/NESTMLToolConfiguration.java @@ -0,0 +1,74 @@ +package org.nest.cli; + +/** + * Created by user on 05.06.15. + */ +public class NESTMLToolConfiguration { + private final boolean checkCoCos; + + + private final String inputBasePath; + private final String targetPath; + private final String modelPath; + + private NESTMLToolConfiguration(final Builder builder) { + this.checkCoCos = builder.checkCoCos; + this.inputBasePath = builder.inputBasePath; + this.modelPath = builder.modelPath; + this.targetPath = builder.targetPath; + } + + public boolean isCheckCoCos() { + return checkCoCos; + } + + public String getInputBasePath() { + return inputBasePath; + } + + public String getModelPath() { + return modelPath; + } + + public String getTargetPath() { + return targetPath; + } + + public static class Builder { + private boolean checkCoCos = false; + private String inputBasePath; + private String targetPath; + private String modelPath; + + public Builder withCoCos() { + this.checkCoCos = true; + return this; + } + + public Builder withCoCos(boolean checkCoCos) { + this.checkCoCos = checkCoCos; + return this; + } + + public Builder withInputBasePath(final String inputBasePath) { + this.inputBasePath = inputBasePath; + return this; + } + + public Builder withModelPath(final String modelPath) { + this.modelPath = modelPath; + return this; + } + + public Builder withTargetPath(final String targetPath) { + this.targetPath = targetPath; + return this; + } + + public NESTMLToolConfiguration build() { + return new NESTMLToolConfiguration(this); + } + + } + +} diff --git a/src/main/java/org/nest/codegeneration/NESTML2NESTCodeGenerator.java b/src/main/java/org/nest/codegeneration/NESTML2NESTCodeGenerator.java new file mode 100644 index 000000000..efe68f155 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/NESTML2NESTCodeGenerator.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import de.monticore.generating.GeneratorEngine; +import de.monticore.generating.GeneratorSetup; +import de.monticore.generating.templateengine.GlobalExtensionManagement; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTNeuronList; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Wrapps the logic how to generateSympyODEAnalyzer C++ implementation from a NESTML model? + * @author plotnikov + * @since 0.0.1 + */ +public class NESTML2NESTCodeGenerator { + + public static void generateHeader(final GlobalExtensionManagement glex, + final ASTNESTMLCompilationUnit compilationUnit, + final PredefinedTypesFactory typesFactory, + final File outputDirectory) { + final String moduleName = Names.getQualifiedName(compilationUnit.getPackageName().getParts()); + + final GeneratorSetup setup = new GeneratorSetup(outputDirectory); + setup.setGlex(glex); + + final GeneratorEngine generator = new GeneratorEngine(setup); + + for (ASTNeuron neuron : compilationUnit.getNeurons()) { + setNeuronGenerationParameter(glex, typesFactory, neuron, moduleName); + final Path outputFile = Paths.get(Names.getPathFromPackage(moduleName), neuron.getName() + ".h"); + + // TODO: how do I find out the call was successful? + generator.generate("org.nest.nestml.neuron.NeuronHeader", outputFile, neuron); + } + + + } + + public static void generateClassImplementation(final GlobalExtensionManagement glex, + final PredefinedTypesFactory typesFactory, + final ASTNESTMLCompilationUnit compilationUnit, + final File outputDirectory) { + final String moduleName = Names.getQualifiedName(compilationUnit.getPackageName().getParts()); + + final GeneratorSetup setup = new GeneratorSetup(outputDirectory); + setup.setGlex(glex); + + final GeneratorEngine generator = new GeneratorEngine(setup); + + final ASTNeuronList neurons = compilationUnit.getNeurons(); + for (ASTNeuron neuron : neurons) { + setNeuronGenerationParameter(glex, typesFactory, neuron, moduleName); + final Path classImplementationFile = Paths.get(Names.getPathFromPackage(moduleName), neuron.getName() + ".cpp"); + // TODO: how do I find out the call was successful? + generator.generate( + "org.nest.nestml.neuron.NeuronClass", + classImplementationFile, + neuron); + } + + } + + public static void generateCodeForModelIntegrationInNest(final GlobalExtensionManagement glex, + final ASTNESTMLCompilationUnit compilationUnit, + final File outputDirectory) { + final String fullName = Names.getQualifiedName(compilationUnit.getPackageName().getParts()); + final String moduleName = Names.getSimpleName(fullName); + + final ASTNeuronList neurons = compilationUnit.getNeurons(); + final List neuronModelNames = neurons + .stream() + .map(ASTNeuron::getName) + .collect(Collectors.toList()); + + final GeneratorSetup setup = new GeneratorSetup(outputDirectory); + setup.setTracing(false); + + glex.setGlobalValue("moduleName", moduleName); + glex.setGlobalValue("packageName", fullName); + glex.setGlobalValue("neuronModelNames", neuronModelNames); + + setup.setGlex(glex); + + final GeneratorEngine generator = new GeneratorEngine(setup); + + final Path makefileFile = Paths.get(Names.getPathFromPackage(fullName), "Makefile.am"); + generator.generate( + "org.nest.nestml.module.Makefile", + makefileFile, + compilationUnit); + + final Path bootstrappingFile = Paths.get(Names.getPathFromPackage(fullName), "bootstrap.sh"); + generator.generate( + "org.nest.nestml.module.Bootstrap", + bootstrappingFile, + compilationUnit); + + final Path configureFile = Paths.get(Names.getPathFromPackage(fullName), "configure.ac"); + generator.generate( + "org.nest.nestml.module.Configure", + configureFile, + compilationUnit); + + final Path moduleClass = Paths.get(Names.getPathFromPackage(fullName), moduleName + "Config.cpp"); + generator.generate( + "org.nest.nestml.module.ModuleClass", + moduleClass, + compilationUnit); + + final Path moduleHeader = Paths.get(Names.getPathFromPackage(fullName), moduleName + "Config.h"); + generator.generate( + "org.nest.nestml.module.ModuleHeader", + moduleHeader, + compilationUnit); + + final Path sliInitFile = Paths.get(Names.getPathFromPackage(fullName), "sli", moduleName.toLowerCase() + "-init"); + generator.generate( + "org.nest.nestml.module.SLI_Init", + sliInitFile, + compilationUnit); + } + + private static void setNeuronGenerationParameter( + final GlobalExtensionManagement glex, + final PredefinedTypesFactory typesFactory, + final ASTNeuron neuron, + final String moduleName) { + final String guard = (moduleName + "." + neuron.getName()).replace(".", "_"); + glex.setGlobalValue("guard", guard); + glex.setGlobalValue("simpleNeuronName", neuron.getName()); + + final String nspPrefix = convertToCppNamespaceConvention(moduleName); + final NESTMLFunctionPrinter functionPrinter = new NESTMLFunctionPrinter(typesFactory); + final NESTMLDeclarations declarations = new NESTMLDeclarations(typesFactory); + final NESTMLDynamicsPrinter dynamicsHelper = new NESTMLDynamicsPrinter(typesFactory); + + glex.setGlobalValue("declarations", new NESTMLDeclarations(typesFactory) ); + glex.setGlobalValue("assignmentHelper", new SPLVariableGetterSetterHelper()); + glex.setGlobalValue("typesFactory", typesFactory); + glex.setGlobalValue("functionPrinter", functionPrinter); + glex.setGlobalValue("declarations", declarations); + glex.setGlobalValue("dynamicsHelper", dynamicsHelper); + glex.setGlobalValue("bufferHelper", new NESTMLBuffers(typesFactory)); + + glex.setGlobalValue("nspPrefix", nspPrefix); + glex.setGlobalValue("outputEvent", NESTMLOutputs.printOutputEvent(neuron)); + glex.setGlobalValue("isOutputEventPresent", NESTMLOutputs.isOutputEventPresent(neuron)); + glex.setGlobalValue("isSpikeInput", NESTMLInputs.isSpikeInput(neuron)); + glex.setGlobalValue("isCurrentInput", NESTMLInputs.isCurrentInput(neuron)); + glex.setGlobalValue("body", new ASTBodyDecorator(neuron.getBody())); + + } + + private static String convertToCppNamespaceConvention(String fqnName) { + return fqnName.replace(".", "::"); + } + +} + diff --git a/src/main/java/org/nest/codegeneration/NESTML2NESTTypeConverter.java b/src/main/java/org/nest/codegeneration/NESTML2NESTTypeConverter.java new file mode 100644 index 000000000..c8451808c --- /dev/null +++ b/src/main/java/org/nest/codegeneration/NESTML2NESTTypeConverter.java @@ -0,0 +1,60 @@ + +package org.nest.codegeneration; + +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +/** + * Converts NESTML types to the + * + * @author plotnikov + * @since 0.0.1 + */ +public class NESTML2NESTTypeConverter { + final PredefinedTypesFactory typesFactory; + + public NESTML2NESTTypeConverter(PredefinedTypesFactory typesFactory) { + this.typesFactory = typesFactory; + } + + public String convert(final NESTMLTypeSymbol nestmlType) { + return doConvert(nestmlType); + } + + public String doConvert(final NESTMLTypeSymbol nestmlType) { + if (typesFactory.getStringType().equals(nestmlType)) { + return "std::string"; + } + + if (typesFactory.getVoidType().equals(nestmlType)) { + return "void"; + } + + if (typesFactory.getBufferType().equals(nestmlType)) { + return "nest::RingBuffer"; + } + + if (typesFactory.getBooleanType().equals(nestmlType)) { + return "bool"; + } + + if (nestmlType.getType() == NESTMLTypeSymbol.Type.UNIT) { + return "nest::double_t"; + } + + if (typesFactory.getRealType().equals(nestmlType)) { + return "nest::double_t"; + } + + if (typesFactory.getIntegerType().equals(nestmlType)) { + return "int"; + } + + if (nestmlType.getName().contains("Time")) { + return "nest::Time"; + } + final String name = nestmlType.getName(); + + return name.replaceAll("\\.", "::"); + } +} diff --git a/src/main/java/org/nest/codegeneration/NESTMLBuffers.java b/src/main/java/org/nest/codegeneration/NESTMLBuffers.java new file mode 100644 index 000000000..65cb06c37 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/NESTMLBuffers.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import de.monticore.symboltable.Scope; +import org.nest.nestml._ast.ASTInputLine; +import org.nest.nestml._ast.ASTInputType; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +/** + * Todo: refactor + * grammar: + * {@code + * InputLine = Name "<-" InputType* ([spike:"spike"]|[current:"current"]); + * InputType = (["inhibitory"]|["excitatory"]); + * } + * + * @author plotnikov + * @since 0.0.1 + */ +@SuppressWarnings("unused") +public class NESTMLBuffers { + + private final PredefinedTypesFactory typesFactory; + + private final NESTML2NESTTypeConverter nestml2NESTTypeConverter; + + public NESTMLBuffers(PredefinedTypesFactory typesFactory) { + this.typesFactory = typesFactory; + nestml2NESTTypeConverter = new NESTML2NESTTypeConverter(typesFactory); + } + public boolean isInhibitory(final ASTInputLine buffer) { + boolean isInhibitory = false, isExcitatory = false; + for (final ASTInputType inputType:buffer.getInputTypes()) { + if (inputType.isInhibitory()) { + isInhibitory = true; + } + if (inputType.isExcitatory()) { + isExcitatory = true; + } + } + if ( !isInhibitory && !isExcitatory ) { // defulat + return true; + } else { + return isInhibitory; + } + + } + + public boolean isExcitatory(final ASTInputLine buffer) { + boolean isInhibitory = false, isExcitatory = false; + for (final ASTInputType inputType:buffer.getInputTypes()) { + if (inputType.isInhibitory()) { + isInhibitory = true; + } + if (inputType.isExcitatory()) { + isExcitatory = true; + } + } + if ( !isInhibitory && !isExcitatory ) { // default + return true; + } else { + return isExcitatory; + } + } + public String printBufferGetter(final ASTInputLine astInputLine, boolean isInStruct) { + checkArgument(astInputLine.getEnclosingScope().isPresent(), ""); + final Scope scope = astInputLine.getEnclosingScope().get(); + final NESTMLVariableSymbol buffer = resolveVariable(astInputLine.getName(), scope); + + final StringBuilder functionDeclaration = new StringBuilder(); + functionDeclaration.append("inline "); + + if (buffer.getArraySizeParameter().isPresent()) { + functionDeclaration.append("std::vector< "); + functionDeclaration.append(nestml2NESTTypeConverter.convert(buffer.getType())); + functionDeclaration.append(" > &"); + } + else { + functionDeclaration.append(nestml2NESTTypeConverter.convert(buffer.getType()) + "&"); + } + + functionDeclaration.append(" get_"+astInputLine.getName() + "() {"); + + if (isInStruct) { + functionDeclaration.append("return " + astInputLine.getName() + "_; "); + } + else { + functionDeclaration.append("return B_.get_" + astInputLine.getName() + "(); "); + } + + functionDeclaration.append("}"); + return functionDeclaration.toString(); + } + + public String printBufferDeclaration(final ASTInputLine astInputLine) { + checkArgument(astInputLine.getEnclosingScope().isPresent(), ""); + final Scope scope = astInputLine.getEnclosingScope().get(); + final NESTMLVariableSymbol buffer = resolveVariable(astInputLine.getName(), scope); + + String bufferType; + if (buffer.getArraySizeParameter().isPresent()) { + bufferType = "std::vector< " + nestml2NESTTypeConverter.convert(buffer.getType()) + " >"; + } + else { + bufferType = nestml2NESTTypeConverter.convert(buffer.getType()); + } + bufferType = bufferType.replace(".", "::"); // TODO review + + final StringBuilder bufferDeclaration = new StringBuilder(); + + bufferDeclaration.append(bufferType).append(" "); + bufferDeclaration.append(astInputLine.getName() + "_"); + bufferDeclaration.append("//!< Buffer incoming " + buffer.getType().getName() + "s through delay, as sum\n"); + + return bufferDeclaration.toString(); + } + + public String printBufferTypesVariables(final ASTInputLine astInputLine) { + checkArgument(astInputLine.getEnclosingScope().isPresent(), ""); + + final StringBuilder declaration = new StringBuilder(); + declaration.append("std::vector receptor_types_").append(astInputLine.getName()); + return declaration.toString(); + } + + public String printBufferInitialization(final ASTInputLine astInputLine) { + return "get_" + astInputLine.getName() + "().clear(); //includes resize"; + } + + public String vectorParameter(final ASTInputLine astInputLine) { + checkArgument(astInputLine.getEnclosingScope().isPresent(), ""); + final Scope scope = astInputLine.getEnclosingScope().get(); + final NESTMLVariableSymbol buffer = resolveVariable(astInputLine.getName(), scope); + checkState(buffer.getArraySizeParameter().isPresent(), "Cannot resolve the variable: " + astInputLine.getName()); + return buffer.getArraySizeParameter().get() + "_"; + } + + // TODO duplicate + private NESTMLVariableSymbol resolveVariable(final String variableName, final Scope scope) { + final Optional variableSymbol = scope.resolve( + variableName, NESTMLVariableSymbol.KIND); + checkState(variableSymbol.isPresent(), "Cannot resolve the variable: " + variableName); + return variableSymbol.get(); + } + + public boolean isVector(final ASTInputLine astInputLine) { + checkArgument(astInputLine.getEnclosingScope().isPresent(), ""); + final Scope scope = astInputLine.getEnclosingScope().get(); + final NESTMLVariableSymbol buffer = resolveVariable(astInputLine.getName(), scope); + + return buffer.getArraySizeParameter().isPresent(); + } +} diff --git a/src/main/java/org/nest/codegeneration/NESTMLDeclarations.java b/src/main/java/org/nest/codegeneration/NESTMLDeclarations.java new file mode 100644 index 000000000..b9f5ab004 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/NESTMLDeclarations.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import com.google.common.collect.Lists; +import de.monticore.symboltable.Scope; +import de.monticore.symboltable.Symbol; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.spl._ast.ASTAssignment; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; +import org.nest.utils.CachedResolver; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +/** + * TODO + * + * @author plotnikov + * @since 0.0.1 + */ +@SuppressWarnings({"unused"}) // the class is used from templates +public class NESTMLDeclarations { + private final PredefinedTypesFactory typesFactory; + + final private CachedResolver cachedResolver = new CachedResolver(); + + private final NESTML2NESTTypeConverter nestml2NESTTypeConverter; + + private final NESTML2NESTTypeConverter typeConverter; + + public NESTMLDeclarations(PredefinedTypesFactory typesFactory) { + this.typesFactory = typesFactory; + nestml2NESTTypeConverter = new NESTML2NESTTypeConverter(typesFactory); + typeConverter = new NESTML2NESTTypeConverter(typesFactory); + } + + public String getType(final ASTDeclaration astDeclaration) { + checkArgument(astDeclaration.getEnclosingScope().isPresent()); + + final Scope scope = astDeclaration.getEnclosingScope().get(); + final String declarationTypeName = printDeclarationTypeName(astDeclaration); + + Optional declarationTypeSymbol = cachedResolver.resolveAndCache(scope, declarationTypeName); + checkState(declarationTypeSymbol.isPresent(), "Cannot resolve the NESTML type: " + declarationTypeName); + + return new NESTML2NESTTypeConverter(typesFactory).convert(declarationTypeSymbol.get()); + } + + private String printDeclarationTypeName(ASTDeclaration astDeclaration) { + if (astDeclaration.getPrimitiveType().isPresent()) { + return astDeclaration.getPrimitiveType().get().toString(); + } + else if (astDeclaration.getType().isPresent()) { + final String typeName = Names.getQualifiedName(astDeclaration.getType().get().getParts()); + return typeName; + } + throw new RuntimeException("Impossible by the grammar definition. One of alternatives must be used;"); + } + + public List getVariables(final ASTDeclaration astDeclaration) { + return astDeclaration.getVars(); + } + + public boolean isVectorType(final ASTAliasDecl astAliasDecl) { + return astAliasDecl.getDeclaration().getSizeParameter().isPresent(); + } + + public String getDeclarationType(final ASTDeclaration astDeclaration) { + checkArgument(astDeclaration.getEnclosingScope().isPresent()); + + final Scope scope = astDeclaration.getEnclosingScope().get(); + final String typeName = computeDeclarationTypeName(astDeclaration); + + Optional typeSymbol = scope.resolve(typeName, NESTMLTypeSymbol.KIND); + checkState(typeSymbol.isPresent(), "Cannot resolve the type: " + typeName); + + + if (astDeclaration.getSizeParameter().isPresent()) { + return "std::vector< " + nestml2NESTTypeConverter.convert(typeSymbol.get()) + " > "; + } + else { + return nestml2NESTTypeConverter.convert(typeSymbol.get()); + } + } + + private String computeDeclarationTypeName(ASTDeclaration astDeclaration) { + if (astDeclaration.getPrimitiveType().isPresent()) { + return astDeclaration.getPrimitiveType().get().toString(); // TODO it is not really portable + } + else if (astDeclaration.getType().isPresent()) { + final String typeName = Names.getQualifiedName(astDeclaration.getType().get().getParts()); + return typeName; + } + throw new RuntimeException("Impossible by the grammar definition. One of alternatives muste be used;"); + } + + public String getType(final ASTAliasDecl astAliasDecl) { + return getDeclarationType(astAliasDecl.getDeclaration()); + } + + public List getVariables(final ASTAliasDecl astAliasDecl) { + checkArgument(astAliasDecl.getEnclosingScope().isPresent(), "Alias has no assigned scope."); + final Scope scope = astAliasDecl.getEnclosingScope().get(); + final ASTDeclaration decl = astAliasDecl.getDeclaration(); + + final String typeName = Names.getQualifiedName(decl.getType().get().getParts()); + final Optional type = cachedResolver.resolveAndCache(scope, typeName); + if (type.isPresent()) { + final List variables = Lists.newArrayList(); + + for (String variableName : decl.getVars()) { + final Optional currVar = scope.resolve(variableName, NESTMLVariableSymbol.KIND); + checkState(currVar.isPresent(), "Cannot resolve the variable: " + variableName); + variables.add(currVar.get()); + } + + return variables; + } + else { + throw new RuntimeException("Cannot resolve the type: " + decl.getType().get()); + } + + } + + public String getAliasOrigin(final ASTAliasDecl astAliasDecl) { + checkArgument(astAliasDecl.getEnclosingScope().isPresent(), "No scope. Run symbol table creator"); + final Scope scope = astAliasDecl.getEnclosingScope().get(); + final ASTDeclaration decl = astAliasDecl.getDeclaration(); + final String typeName = Names.getQualifiedName(decl.getType().get().getParts()); + final Optional type = cachedResolver.resolveAndCache(scope, typeName); + if (type.isPresent()) { + final List variables = Lists.newArrayList(); + + for (String var : decl.getVars()) { + final Optional currVar = scope.resolve(var, NESTMLVariableSymbol.KIND); + variables.add(currVar.get()); + } + + if (!variables.isEmpty()) { + final NESTMLVariableSymbol first = variables.get(0); + switch (first.getBlockType()) { + case STATE: + return "S_"; + case PARAMETER: + return "P_"; + case INTERNAL: + return "V_"; + default: + return ""; + } + + } + + } + else { + throw new RuntimeException("Cannot resolve the type: " + typeName); + } + return ""; + } + + public String getDomainFromType(final NESTMLTypeSymbol type) { + checkNotNull(type); + + if (type.getType().equals(NESTMLTypeSymbol.Type.UNIT)) { + return "nest::double_t"; + } + else { + return typeConverter.convert(type); + } + + } + + public boolean isVectorLHS(final ASTAssignment astAssignment) { + checkArgument(astAssignment.getEnclosingScope().isPresent(), + "No scope. Run symbol table creator"); + final Scope scope = astAssignment.getEnclosingScope().get(); + final String lhsVarName = Names.getQualifiedName(astAssignment.getVariableName().getParts()); + final Optional lhsVarSymbol + = scope.resolve(lhsVarName, NESTMLVariableSymbol.KIND); + + checkState(lhsVarSymbol.isPresent(), "Cannot resolve the name: " + lhsVarName); + return lhsVarSymbol.get().getArraySizeParameter().isPresent(); + } + + +} diff --git a/src/main/java/org/nest/codegeneration/NESTMLDynamicsPrinter.java b/src/main/java/org/nest/codegeneration/NESTMLDynamicsPrinter.java new file mode 100644 index 000000000..682d6195f --- /dev/null +++ b/src/main/java/org/nest/codegeneration/NESTMLDynamicsPrinter.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import com.google.common.collect.Lists; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTDynamics; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.utils.NESTMLSymbols; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +/** + * Prints the dynamics function. + * + * @author plotnikov + * @since 0.0.1 + */ +@SuppressWarnings("unused") +public class NESTMLDynamicsPrinter { + + public static final String DEFAULT_DYNAMICS_NAME = "dynamics"; + + public final PredefinedTypesFactory typesFactory; + + public NESTMLDynamicsPrinter(PredefinedTypesFactory typesFactory) { + this.typesFactory = typesFactory; + } + + public String printDynamicsType(final ASTDynamics dynamics) { + checkArgument(dynamics.getEnclosingScope().isPresent()); + final Scope scope = dynamics.getEnclosingScope().get(); + + List parameters = Lists.newArrayList(); + for (int i = 0; i < dynamics.getParameters().get().getParameters().size(); ++i) { + String parameterTypeFqn = Names.getQualifiedName(dynamics.getParameters().get().getParameters().get(i).getType().getParts()); + parameters.add(parameterTypeFqn); + } + + Optional dynamicsSymbol = NESTMLSymbols.resolveMethod(scope, DEFAULT_DYNAMICS_NAME, parameters); + checkState(dynamicsSymbol.isPresent(), "Cannot resolve neuron's dynamic: " + DEFAULT_DYNAMICS_NAME); + + String typeName = new NESTML2NESTTypeConverter(typesFactory).convert(dynamicsSymbol.get().getParameterTypes().get(0)); + return typeName.replace(".", "::"); + } + + public String printParameterName(final ASTDynamics dynamics) { + checkArgument(dynamics.getEnclosingScope().isPresent()); + final Scope scope = dynamics.getEnclosingScope().get(); + + List parameterNames = Lists.newArrayList(); + for (int i = 0; i < dynamics.getParameters().get().getParameters().size(); ++i) { + parameterNames.add(dynamics.getParameters().get().getParameters().get(i).getName()); + } + + return parameterNames.get(0); + } + +} diff --git a/src/main/java/org/nest/codegeneration/NESTMLFunctionPrinter.java b/src/main/java/org/nest/codegeneration/NESTMLFunctionPrinter.java new file mode 100644 index 000000000..9fcfcd1a3 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/NESTMLFunctionPrinter.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTFunction; +import org.nest.nestml._ast.ASTParameter; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.utils.CachedResolver; +import org.nest.utils.NESTMLSymbols; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +/** + * Prints regular functions + * + * @author plotnikov + * @since 0.0.1 + */ +@SuppressWarnings("unused") // class is used from templates +public class NESTMLFunctionPrinter { + + private final PredefinedTypesFactory typesFactory; + + public NESTMLFunctionPrinter(PredefinedTypesFactory typesFactory) { + this.typesFactory = typesFactory; + } + + public String printFunctionDeclaration(final ASTFunction astFunction) { + checkArgument(astFunction.getEnclosingScope().isPresent(), "Function: " + astFunction.getName() + " has no scope."); + final Scope scope = astFunction.getEnclosingScope().get(); + final CachedResolver cachedResolver = new CachedResolver(); + + // TODO names and concept is misleading + List parameterNestmlTypes = Lists.newArrayList(); + List parameterNestTypes = Lists.newArrayList(); + for (int i = 0; i < astFunction.getParameters().get().getParameters().size(); ++i) { + String parameterTypeFqn = Names.getQualifiedName(astFunction.getParameters().get().getParameters().get(i).getType().getParts()); + Optional parameterType = cachedResolver.resolveAndCache(scope, parameterTypeFqn); + checkState(parameterType.isPresent(), + "Cannot resolve the parameter type: " + parameterTypeFqn + ". In function: " + astFunction + .getName()); + parameterNestmlTypes.add(parameterTypeFqn); + parameterNestTypes.add(new NESTML2NESTTypeConverter(typesFactory).convert(parameterType.get())); + } + + final Optional method = NESTMLSymbols.resolveMethod(scope, astFunction.getName(), parameterNestmlTypes); + + final StringBuilder declaration = new StringBuilder(); + if (method.isPresent()) { + final String returnType = new NESTML2NESTTypeConverter(typesFactory).convert(method.get().getReturnType()).replace( + ".", "::"); + declaration.append(returnType); + declaration.append(" "); + declaration.append(astFunction.getName() + "("); + declaration.append(Joiner.on(", ").join(parameterNestTypes)); + declaration.append(")\n"); + } + else { + throw new RuntimeException("Cannot resolve the method " + astFunction.getName() + Joiner.on(", ").join(parameterNestmlTypes)); + } + // TODO + return declaration.toString(); + } + + public String printFunctionDefinition(final ASTFunction astFunction, final String namespace) { + checkArgument(astFunction.getEnclosingScope().isPresent(), "Function: " + astFunction.getName() + " has no scope."); + final Scope scope = astFunction.getEnclosingScope().get(); + final CachedResolver cachedResolver = new CachedResolver(); + + // TODO names and concept is misleading + List parameterNestmlTypes = Lists.newArrayList(); + List parameterNestTypes = Lists.newArrayList(); + for (int i = 0; i < astFunction.getParameters().get().getParameters().size(); ++i) { + final ASTParameter functionParameter = astFunction.getParameters().get().getParameters().get(i); + String parameterTypeFqn = Names.getQualifiedName(functionParameter.getType().getParts()); + Optional parameterType = cachedResolver.resolveAndCache(scope, parameterTypeFqn); + checkState(parameterType.isPresent(), + "Cannot resolve the parameter type: " + parameterTypeFqn + ". In function: " + astFunction + .getName()); + parameterNestmlTypes.add(parameterTypeFqn); + parameterNestTypes.add(new NESTML2NESTTypeConverter(typesFactory).convert(parameterType.get()) + " " + functionParameter.getName()); // TODO misleading name + } + + final Optional method = NESTMLSymbols.resolveMethod(scope, astFunction.getName(), parameterNestmlTypes); + + final StringBuilder declaration = new StringBuilder(); + if (method.isPresent()) { + final String returnType = new NESTML2NESTTypeConverter(typesFactory).convert(method.get().getReturnType()).replace( + ".", "::"); + declaration.append(returnType); + declaration.append(" "); + if (!namespace.isEmpty()) { + declaration.append(namespace).append("::"); + } + + declaration.append(astFunction.getName() + "("); + declaration.append(Joiner.on(", ").join(parameterNestTypes)); + declaration.append(")\n"); + } + else { + throw new RuntimeException("Cannot resolve the method " + astFunction.getName() + Joiner.on(", ").join(parameterNestmlTypes)); + } + return declaration.toString(); + } +} diff --git a/src/main/java/org/nest/codegeneration/NESTMLInputs.java b/src/main/java/org/nest/codegeneration/NESTMLInputs.java new file mode 100644 index 000000000..d2c8a72f7 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/NESTMLInputs.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import de.monticore.ast.ASTNode; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTBody; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._ast.ASTInputLine; +import org.nest.nestml._ast.ASTNeuron; + +import java.util.List; +import java.util.Optional; + +/** + * Computes the type of the output for neurons and neuron components. + * + * @author plotnikov + * @since 0.0.1 + */ +public class NESTMLInputs { + public static boolean isSpikeInput(final ASTNode node) { + final ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(getBodyNode(node)); + final List neuronInputLines = bodyDecorator.getInputLines(); + Optional inputSpikeCandidate = neuronInputLines + .stream() + .filter(ASTInputLine::isSpike) + .findFirst(); + return inputSpikeCandidate.isPresent(); + } + + public static boolean isCurrentInput(final ASTNode node) { + final ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(getBodyNode(node)); + final List neuronInputLines = bodyDecorator.getInputLines(); + Optional inputSpikeCandidate = neuronInputLines + .stream() + .filter(ASTInputLine::isCurrent) + .findFirst(); + return inputSpikeCandidate.isPresent(); + } + + private static ASTBody getBodyNode(ASTNode node) { + ASTBody bodyElement;// TODO probably introduce a grammar rule for this + if (node instanceof ASTComponent) { + bodyElement = ((ASTComponent) node).getBody(); + } + else if (node instanceof ASTNeuron) { + bodyElement = ((ASTNeuron) node).getBody(); + } + else { + throw new RuntimeException("Unexpected instance of the neuron element"); + } + return bodyElement; + } + +} diff --git a/src/main/java/org/nest/codegeneration/NESTMLOutputs.java b/src/main/java/org/nest/codegeneration/NESTMLOutputs.java new file mode 100644 index 000000000..661fc0f86 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/NESTMLOutputs.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import de.monticore.ast.ASTNode; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTBody; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTOutput; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Computes the type of the output for neurons and neuron components. + * + * @author plotnikov + * @since 0.0.1 + */ +public class NESTMLOutputs { + public static boolean isOutputEventPresent(final ASTNode node) { + final ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(getBodyNode(node)); + return !bodyDecorator.getOutputs().isEmpty(); + } + + public static String printOutputEvent(final ASTNode node) { + final ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(getBodyNode(node)); + final List neuronOutputs = bodyDecorator.getOutputs(); + if (!neuronOutputs.isEmpty()) { + ASTOutput output = neuronOutputs.get(0); + + if (output.isSpike()) { + return "nest::SpikeEvent"; + } + else if (output.isCurrent()) { + return "nest::CurrentEvent"; + } + else { + throw new RuntimeException("Unexpected output type. Must be current or spike."); + } + } + else { + return "none"; + } + } + + private static ASTBody getBodyNode(ASTNode node) { + ASTBody bodyElement;// TODO probably introduce a grammar rule for this + if (node instanceof ASTComponent) { + bodyElement = ((ASTComponent) node).getBody(); + } + else if (node instanceof ASTNeuron) { + bodyElement = ((ASTNeuron) node).getBody(); + } + else { + throw new RuntimeException("Unexpected instance of the neuron element"); + } + return bodyElement; + } +} diff --git a/src/main/java/org/nest/codegeneration/SPL2NESTCodeGenerator.java b/src/main/java/org/nest/codegeneration/SPL2NESTCodeGenerator.java new file mode 100644 index 000000000..2f8b8093e --- /dev/null +++ b/src/main/java/org/nest/codegeneration/SPL2NESTCodeGenerator.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import de.monticore.generating.GeneratorEngine; +import de.monticore.generating.GeneratorSetup; +import de.monticore.generating.templateengine.GlobalExtensionManagement; +import org.nest.spl._ast.ASTAssignment; +import org.nest.spl._ast.ASTBlock; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.spl.prettyprinter.ExpressionsPrettyPrinter; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.io.File; +import java.nio.file.Path; + +/** + * TODO + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since 0.0.1 + */ +public class SPL2NESTCodeGenerator { + public static final String DECLARATION_TEMPLATE = "org.nest.spl.Declaration"; + public static final String ASSIGNMENT_TEMPLATE = "org.nest.spl.Assignment"; + public static final String BLOCK_TEMPLATE = "org.nest.spl.Block"; + + final private GlobalExtensionManagement glex; + private final GeneratorSetup setup; + private final GeneratorEngine generator; + + public SPL2NESTCodeGenerator( + final GlobalExtensionManagement glex, + final PredefinedTypesFactory typesFactory, + final File outputDirectory) { + this.glex = glex; + this.setup = new GeneratorSetup(outputDirectory); + + final ExpressionsPrettyPrinter prettyPrinter = new ExpressionsPrettyPrinter(); + glex.setGlobalValue("assignmentHelper", new SPLVariableGetterSetterHelper()); + glex.setGlobalValue("declarations", new NESTMLDeclarations(typesFactory) ); + glex.setGlobalValue("expressionsPrinter", prettyPrinter); + glex.setGlobalValue("forDeclarationHelper", new SPLForNodes()); + + setup.setGlex(glex); + generator = new GeneratorEngine(setup); + } + + public void handle(final ASTDeclaration astDeclaration, final Path outputFile) { + generator.generate(DECLARATION_TEMPLATE, outputFile, astDeclaration); + } + + public void handle(final ASTAssignment astAssignment, final Path outputFile) { + generator.generate(ASSIGNMENT_TEMPLATE, outputFile, astAssignment); + } + + public void handle(ASTBlock astBlock, Path outputFile) { + generator.generate(BLOCK_TEMPLATE, outputFile, astBlock); + } +} diff --git a/src/main/java/org/nest/codegeneration/SPLForNodes.java b/src/main/java/org/nest/codegeneration/SPLForNodes.java new file mode 100644 index 000000000..a1ea1cee7 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/SPLForNodes.java @@ -0,0 +1,63 @@ +package org.nest.codegeneration; + +import de.monticore.literals.literals._ast.ASTSignedNumericLiteral; +import de.monticore.prettyprint.IndentPrinter; +import de.monticore.types.prettyprint.TypesPrettyPrinterConcreteVisitor; +import org.nest.spl._ast.ASTFOR_Stmt; + +import java.math.BigDecimal; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +/** + * TODO + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since TODO + */ +@SuppressWarnings({"unused"}) // the class is used from templates +public class SPLForNodes { + + private static final String LOG_NAME = SPLForNodes.class.getName(); + + public String printComparisonOperator(final ASTFOR_Stmt ast) { + Optional step = ast.getStep(); + if (!step.isPresent()) { + return "<"; + } + else { + final String stepAsString = createPrettyPrinterForTypes().prettyprint(step.get()); + final BigDecimal stepV = new BigDecimal(stepAsString); + if (stepV.compareTo(BigDecimal.ZERO) < 0) { + return ">"; + } + else if (stepV.compareTo(BigDecimal.ZERO) > 0) { + return "<"; + } + else { + checkState(false, "The stepsize cannot be 0"); + } + } + + throw new RuntimeException("Cannot determine which comparison operator to use"); + } + + public String printStep(final ASTFOR_Stmt ast) { + Optional step = ast.getStep(); + if (!step.isPresent()) { + return "1"; + } + else { + return createPrettyPrinterForTypes().prettyprint(step.get()); + } + + } + + private TypesPrettyPrinterConcreteVisitor createPrettyPrinterForTypes() { + final IndentPrinter printer = new IndentPrinter(); + return new TypesPrettyPrinterConcreteVisitor(printer); + } +} diff --git a/src/main/java/org/nest/codegeneration/SPLFunctionCalls.java b/src/main/java/org/nest/codegeneration/SPLFunctionCalls.java new file mode 100644 index 000000000..7e28fc760 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/SPLFunctionCalls.java @@ -0,0 +1,17 @@ +package org.nest.codegeneration; + +import de.se_rwth.commons.Names; +import org.nest.spl._ast.ASTFunctionCall; + +/** + * TODO + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since TODO + */ +public class SPLFunctionCalls { + public String printFunctionName(final ASTFunctionCall astFunctionCall) { + return Names.getQualifiedName(astFunctionCall.getQualifiedName().getParts()); + } +} diff --git a/src/main/java/org/nest/codegeneration/SPLVariableGetterSetterHelper.java b/src/main/java/org/nest/codegeneration/SPLVariableGetterSetterHelper.java new file mode 100644 index 000000000..833ffca0d --- /dev/null +++ b/src/main/java/org/nest/codegeneration/SPLVariableGetterSetterHelper.java @@ -0,0 +1,102 @@ +package org.nest.codegeneration; + +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.spl._ast.ASTAssignment; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; +import org.nest.utils.ASTNodes; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +/** + * Computes how the setter call looks like + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since TODO + */ +@SuppressWarnings("unused") // methods are called from templates +public class SPLVariableGetterSetterHelper { + + /** + * Checks if the assignment + */ + public boolean isLocal(final ASTAssignment astAssignment) { + checkArgument(astAssignment.getEnclosingScope().isPresent()); + final Scope scope = astAssignment.getEnclosingScope().get(); + + final String variableName = Names.getQualifiedName(astAssignment.getVariableName().getParts()); + final Optional variableSymbol = scope.resolve(variableName, NESTMLVariableSymbol.KIND); + checkState(variableSymbol.isPresent(), "Cannot resolve the spl variable: " + variableName); + + // TODO does it make sense for the nestml? + if (variableSymbol.get().getBlockType().equals(NESTMLVariableSymbol.BlockType.LOCAL)) { + return true; + } + else { + return false; + } + + } + + /** + * Returns the textual representation of the setter invocation + */ + public String printVariableName(final ASTAssignment astAssignment) { + return Names.getQualifiedName(astAssignment.getVariableName().getParts()); + } + + + /** + * Returns the textual representation of the setter invocation + */ + public String printSetterName(final ASTAssignment astAssignment) { + final String variableName = Names.getQualifiedName(astAssignment.getVariableName().getParts()); + return "set_" + variableName; + } + + /** + * Returns the textual representation of the setter invocation + */ + public String printGetterName(final ASTAssignment astAssignment) { + final String variableName = Names.getQualifiedName(astAssignment.getVariableName().getParts()); + return "get_" + variableName; + } + + public boolean isVector(final ASTAssignment astAssignment) { + checkArgument(astAssignment.getEnclosingScope().isPresent()); + final Scope scope = astAssignment.getEnclosingScope().get(); + + final String variableName = Names.getQualifiedName(astAssignment.getVariableName().getParts()); + final Optional variableSymbol = scope.resolve(variableName, NESTMLVariableSymbol.KIND); + checkState(variableSymbol.isPresent(), "Cannot resolve the spl variable: " + variableName); + + + if (variableSymbol.get().getArraySizeParameter().isPresent()) { + return true; + } + // TODO to complex logic, refactor + final Optional arrayVariable = ASTNodes.getVariablesNamesFromAst(astAssignment.getExpr()) + .stream() + .filter( + variableNameInExpression -> { + final Optional variableSymbolExpr = scope + .resolve(variableNameInExpression, NESTMLVariableSymbol.KIND); + checkState(variableSymbolExpr.isPresent(), + "Cannot resolve the spl variable: " + variableNameInExpression); + if (variableSymbolExpr.get().getArraySizeParameter().isPresent()) { + return true; + } + else { + return false; + } + } + ).findFirst(); + + return arrayVariable.isPresent(); + } + +} diff --git a/src/main/java/org/nest/codegeneration/converters/IReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/IReferenceConverter.java new file mode 100644 index 000000000..8c1985bde --- /dev/null +++ b/src/main/java/org/nest/codegeneration/converters/IReferenceConverter.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration.converters; + +import de.monticore.types.types._ast.ASTQualifiedName; +import org.nest.spl._ast.ASTFunctionCall; + +public interface IReferenceConverter { + + String convertFunctionCall(final ASTFunctionCall astFunctionCall); + + String convertNameReference(final ASTQualifiedName astQualifiedName); + + String convertConstant(final String constantName); + + boolean needsArguments(final ASTFunctionCall astFunctionCall); + +} diff --git a/src/main/java/org/nest/codegeneration/converters/IdempotentReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/IdempotentReferenceConverter.java new file mode 100644 index 000000000..818cb774d --- /dev/null +++ b/src/main/java/org/nest/codegeneration/converters/IdempotentReferenceConverter.java @@ -0,0 +1,40 @@ +package org.nest.codegeneration.converters; + +import de.monticore.types.types._ast.ASTQualifiedName; +import de.se_rwth.commons.Names; +import org.nest.spl._ast.ASTFunctionCall; + +/** + * Created by user on 29.05.15. + */ +public class IdempotentReferenceConverter implements IReferenceConverter { + + @Override + public String convertFunctionCall( + final ASTFunctionCall astFunctionCall) { + final StringBuilder result = new StringBuilder(); + result.append(Names.getQualifiedName(astFunctionCall.getQualifiedName().getParts())); + + if (needsArguments(astFunctionCall)) { + result.append("(%s)"); + } + else { + result.append("()"); + } + return result.toString(); + } + + @Override + public String convertNameReference(final ASTQualifiedName astQualifiedName) { + return Names.getQualifiedName(astQualifiedName.getParts()); + } + + @Override + public String convertConstant(final String constantName) { + return constantName; + } + + @Override public boolean needsArguments(ASTFunctionCall astFunctionCall) { + return astFunctionCall.getArgList().getArgs().size() > 0; + } +} diff --git a/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java new file mode 100644 index 000000000..eaaee6426 --- /dev/null +++ b/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java @@ -0,0 +1,168 @@ +package org.nest.codegeneration.converters; + +import de.monticore.symboltable.Scope; +import de.monticore.types.types._ast.ASTQualifiedName; +import de.se_rwth.commons.Names; +import org.nest.spl._ast.ASTFunctionCall; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; +import org.nest.utils.ASTNodes; +import org.nest.utils.NESTMLSymbols; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +/** + * TODO + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since TODO + */ +public class NESTReferenceConverter implements IReferenceConverter { + + private final PredefinedTypesFactory typesFactory; + + public NESTReferenceConverter(final PredefinedTypesFactory typesFactory) { + this.typesFactory = typesFactory; + } + + @Override + public String convertFunctionCall( + final ASTFunctionCall astFunctionCall) { + checkState(astFunctionCall.getEnclosingScope().isPresent(), "No scope assigned. Run SymbolTable creator."); + + final Scope scope = astFunctionCall.getEnclosingScope().get(); + final String functionName = Names.getQualifiedName(astFunctionCall.getQualifiedName().getParts()); + + if ("and".equals(functionName)) { + return "&&"; + } + + if ("or".equals(functionName)) { + return "||"; + } + + // Time.resolution() -> + // nestml::Time::get_resolution().get_ms + if ("resolution".equals(functionName)) { + return "nest::Time::get_resolution().get_ms()"; + } + // Time.steps -> + // nest::Time(nest::Time::ms( args )).get_steps()); + if ("steps".equals(functionName)) { + return "nest::Time(nest::Time::ms(%s)).get_steps()"; + } + + if ("pow".equals(functionName)) { + return "std::pow(%s)"; + } + + if ("exp".equals(functionName)) { + return "std::exp(%s)"; + } + + if ("expm1".equals(functionName)) { + return "numerics::expm1(%s)"; + } + + if (functionName.contains("emitSpike")) { + final String emitStatements = "set_spiketime(nest::Time::step(origin.get_steps()+lag+1));\n" + + "nest::SpikeEvent se;\n" + + "network()->send(*this, se, lag);"; + return emitStatements; + } + + final List callTypes = ASTNodes.getArgumentsTypes(astFunctionCall, typesFactory); + final Optional functionSymbol + = NESTMLSymbols.resolveMethod(scope, functionName, callTypes); + if (functionSymbol.isPresent() && functionSymbol.get().getDeclaringType() != null) { // TODO smell + + if (functionSymbol.get().getDeclaringType().getName().equals("Buffer")) { + final NESTMLVariableSymbol variableSymbol = resolveVariable( + Names.getQualifier(functionName), scope); + + + if (functionSymbol.get().getName().equals("getSum")) { + if (variableSymbol.getArraySizeParameter().isPresent()) { + final String calleeObject = Names.getQualifier(functionName); + return "get_" + calleeObject + "()[i].get_value(lag)"; + } + else { + final String calleeObject = Names.getQualifier(functionName); + return "get_" + calleeObject + "().get_value(lag)"; + } + + } + + } + + } + + return functionName; + } + + private NESTMLVariableSymbol resolveVariable(final String variableName, final Scope scope) { + final Optional variableSymbol = scope.resolve( + variableName, NESTMLVariableSymbol.KIND); + checkState(variableSymbol.isPresent(), "Cannot resolve the variable: " + variableName); + return variableSymbol.get(); + } + + @Override + public String convertNameReference(final ASTQualifiedName astQualifiedName) { + checkArgument(astQualifiedName.getEnclosingScope().isPresent(), "No scope is assigned. Please, build the symbol " + + "table before calling this function."); + final String name = Names.getQualifiedName(astQualifiedName.getParts()); + final Scope scope = astQualifiedName.getEnclosingScope().get(); + if ("E".equals(name)) { + return "numerics::e"; + } + else { + final Optional variableSymbol = scope.resolve(name, NESTMLVariableSymbol.KIND); + + checkState(variableSymbol.isPresent(), "Cannot resolve the variable: " + name); + + if (variableSymbol.get().getBlockType().equals(NESTMLVariableSymbol.BlockType.LOCAL)) { + return name; + } + else { + if (variableSymbol.get().getArraySizeParameter().isPresent()) { + return "get_" + name + "()[i]"; + } + else { + return "get_" + name + "()"; + } + + } + + } + + } + + @Override + public String convertConstant(final String constantName) { + if ("inf".equals(constantName)) { + return "std::numeric_limits::infinity()"; + } + else { + return constantName; + } + } + + @Override + public boolean needsArguments(final ASTFunctionCall astFunctionCall) { + final String functionName = Names.getQualifiedName(astFunctionCall.getQualifiedName().getParts()); + if (functionName.contains("emitSpike")) { // TODO it cannot work! + return false; + } + else { + return true; + } + } + +} diff --git a/src/main/java/org/nest/nestml/_symboltable/CommonNESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/CommonNESTMLSymbolTableCreator.java new file mode 100644 index 000000000..c3db2a217 --- /dev/null +++ b/src/main/java/org/nest/nestml/_symboltable/CommonNESTMLSymbolTableCreator.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml._symboltable; + +import com.google.common.base.Preconditions; +import de.monticore.symboltable.CommonSymbolTableCreator; +import de.monticore.symboltable.MutableScope; +import de.monticore.symboltable.ResolverConfiguration; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._ast.ASTVar_Block; +import org.nest.nestml._symboltable.NESTMLSymbolTableCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The implementation of the symboltable creator. + * Implements required methods to compute packagename, current alias declaration + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class CommonNESTMLSymbolTableCreator extends CommonSymbolTableCreator implements + NESTMLSymbolTableCreator { + private String packageName = ""; + private ASTNESTMLCompilationUnit root; + private final PredefinedTypesFactory predefinedTypesFactory; + private Optional astAliasDeclaration = Optional.empty(); + private Optional astVariableBlockType = Optional.empty(); + + public CommonNESTMLSymbolTableCreator( + final ResolverConfiguration resolverConfig, + final MutableScope enclosingScope, + final PredefinedTypesFactory predefinedTypesFactory) { + super(resolverConfig, enclosingScope); + this.predefinedTypesFactory = predefinedTypesFactory; + } + + @Override + public PredefinedTypesFactory getPredefinedTypesFactory() { + return predefinedTypesFactory; + } + + @Override + public void setPackageName(String packageName) { + checkNotNull(packageName); + + this.packageName = packageName; + } + + @Override + public void setRoot(ASTNESTMLCompilationUnit root) { + this.root = root; + } + + @Override + public ASTNESTMLCompilationUnit getRoot() { + return root; + } + + @Override + public String getPackageName() { + Preconditions.checkState(packageName != null, "Package name is used before it is set by the visit method"); + return packageName; + } + + @Override + public void setAliasDeclaration(final Optional astAliasDeclaration) { + this.astAliasDeclaration = astAliasDeclaration; + } + + @Override + public Optional getAliasDeclaration() { + return astAliasDeclaration; + } + + @Override public void setVariableBlockType(Optional variableBlockType) { + astVariableBlockType = variableBlockType; + } + + @Override public Optional getVariableBlockType() { + return astVariableBlockType; + } + +} diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLCoCosManager.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLCoCosManager.java new file mode 100644 index 000000000..a499e8381 --- /dev/null +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLCoCosManager.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml._symboltable; + +import org.nest.nestml.cocos.*; +import org.nest.nestml.cocos.spl.BufferNotAssignable; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._cocos.*; +import org.nest.spl.cocos.VarHasTypeName; +import org.nest.spl._cocos.SPLASTDeclarationCoCo; +import org.nest.spl.symboltable.SPLCoCosManager; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +/** + * This class is responsible for the instantiation of the NESTML context conditions. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLCoCosManager { + + private final ASTNESTMLCompilationUnit astNestmlCompilationUnit; + private final PredefinedTypesFactory predefinedTypesFactory; + + public NESTMLCoCosManager(final ASTNESTMLCompilationUnit astNestmlCompilationUnit, + PredefinedTypesFactory predefinedTypesFactory) { + this.astNestmlCompilationUnit = astNestmlCompilationUnit; + this.predefinedTypesFactory = predefinedTypesFactory; + } + + /** + * @return A checker with all NESTML context conditions + */ + public NESTMLCoCoChecker createDefaultChecker() { + final NESTMLCoCoChecker nestmlCoCoChecker = new NESTMLCoCoChecker(); + + final AliasHasNoSetter aliasHasNoSetter = new AliasHasNoSetter(astNestmlCompilationUnit); + nestmlCoCoChecker.addCoCo(aliasHasNoSetter); + + final AliasHasOneVar aliasHasOneVar = new AliasHasOneVar(); + nestmlCoCoChecker.addCoCo(aliasHasOneVar); + + final AliasInNonAliasDecl aliasInNonAliasDecl = new AliasInNonAliasDecl(); + + nestmlCoCoChecker.addCoCo((NESTMLASTComponentCoCo) aliasInNonAliasDecl); + nestmlCoCoChecker.addCoCo((NESTMLASTNeuronCoCo) aliasInNonAliasDecl); + + final ComponentHasNoDynamics componentHasNoDynamics = new ComponentHasNoDynamics(); + nestmlCoCoChecker.addCoCo(componentHasNoDynamics); + + final ComponentNoInput componentNoInput = new ComponentNoInput(); + nestmlCoCoChecker.addCoCo(componentNoInput); + + final ComponentNoOutput componentNoOutput = new ComponentNoOutput(); + nestmlCoCoChecker.addCoCo(componentNoOutput); + + final CurrentInputIsNotInhExc currentInputIsNotInhExc = new CurrentInputIsNotInhExc(); + nestmlCoCoChecker.addCoCo(currentInputIsNotInhExc); + + final DynamicsTimeStepParameter dynamicsTimeStepParameter = new DynamicsTimeStepParameter(); + nestmlCoCoChecker.addCoCo(dynamicsTimeStepParameter); + + final FunctionHasReturnStatement functionHasReturnStatement + = new FunctionHasReturnStatement(predefinedTypesFactory); + nestmlCoCoChecker.addCoCo(functionHasReturnStatement); + + final InvalidTypesInDeclaration invalidTypesInDeclaration + = new InvalidTypesInDeclaration(); + nestmlCoCoChecker.addCoCo((NESTMLASTUSE_StmtCoCo) invalidTypesInDeclaration); + nestmlCoCoChecker.addCoCo((NESTMLASTFunctionCoCo) invalidTypesInDeclaration); + nestmlCoCoChecker.addCoCo((SPLASTDeclarationCoCo) invalidTypesInDeclaration); + + final MemberVariableDefinedMultipleTimes memberVariableDefinedMultipleTimes + = new MemberVariableDefinedMultipleTimes(); + nestmlCoCoChecker.addCoCo((NESTMLASTComponentCoCo) memberVariableDefinedMultipleTimes); + nestmlCoCoChecker.addCoCo((NESTMLASTNeuronCoCo) memberVariableDefinedMultipleTimes); + + final MemberVariablesInitialisedInCorrectOrder memberVariablesInitialisedInCorrectOrder + = new MemberVariablesInitialisedInCorrectOrder(); + nestmlCoCoChecker.addCoCo(memberVariablesInitialisedInCorrectOrder); + + final MultipleFunctionDeclarations multipleFunctionDeclarations + = new MultipleFunctionDeclarations(); + nestmlCoCoChecker.addCoCo((NESTMLASTComponentCoCo) multipleFunctionDeclarations); + nestmlCoCoChecker.addCoCo((NESTMLASTNeuronCoCo) multipleFunctionDeclarations); + + final MultipleInhExcInput multipleInhExcInput = new MultipleInhExcInput(); + nestmlCoCoChecker.addCoCo(multipleInhExcInput); + + final MultipleOutputs multipleOutputs = new MultipleOutputs(); + nestmlCoCoChecker.addCoCo(multipleOutputs); + + final NESTFunctionNameChecker functionNameChecker = new NESTFunctionNameChecker(); + nestmlCoCoChecker.addCoCo(functionNameChecker); + + final NESTGetterSetterFunctionNames nestGetterSetterFunctionNames = new NESTGetterSetterFunctionNames(); + nestmlCoCoChecker.addCoCo(nestGetterSetterFunctionNames); + + final NeuronNeedsDynamics neuronNeedsDynamics = new NeuronNeedsDynamics(); + nestmlCoCoChecker.addCoCo(neuronNeedsDynamics); + + final NeuronWithoutInput neuronWithoutInput = new NeuronWithoutInput(); + nestmlCoCoChecker.addCoCo(neuronWithoutInput); + + final NeuronWithoutOutput neuronWithoutOutput = new NeuronWithoutOutput(); + nestmlCoCoChecker.addCoCo(neuronWithoutOutput); + + final CorrectReturnValues correctReturnValues = new CorrectReturnValues(predefinedTypesFactory); + nestmlCoCoChecker.addCoCo(correctReturnValues); + + final TypeIsDeclaredMultipleTimes typeIsDeclaredMultipleTimes = new TypeIsDeclaredMultipleTimes(); + nestmlCoCoChecker.addCoCo((NESTMLASTComponentCoCo) typeIsDeclaredMultipleTimes); + nestmlCoCoChecker.addCoCo((NESTMLASTNeuronCoCo) typeIsDeclaredMultipleTimes); + + // TODO + // UsesOnlyComponents + final BufferNotAssignable bufferNotAssignable = new BufferNotAssignable(); + nestmlCoCoChecker.addCoCo(bufferNotAssignable); + + final VarHasTypeName varHasTypeName = new VarHasTypeName(); + nestmlCoCoChecker.addCoCo(varHasTypeName); + + return nestmlCoCoChecker; + } + + public NESTMLCoCoChecker createNESTMLCheckerWithSPLCocos() { + final NESTMLCoCoChecker nestmlChecker = createDefaultChecker(); + new SPLCoCosManager(predefinedTypesFactory).addSPLCocosToNESTMLChecker(nestmlChecker); + return nestmlChecker; + } + +} diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLLanguage.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLLanguage.java new file mode 100644 index 000000000..9f61936b5 --- /dev/null +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLLanguage.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml._symboltable; + +import de.monticore.CommonModelNameCalculator; +import de.monticore.symboltable.MutableScope; +import de.monticore.symboltable.ResolverConfiguration; +import de.monticore.symboltable.SymbolKind; +import de.monticore.symboltable.resolving.CommonResolvingFilter; +import de.se_rwth.commons.Names; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.*; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.Optional.empty; + +/** + * Frontend for the Simple Programming Language (SPL) + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLLanguage extends NESTMLLanguageTOP { + + public static final String FILE_ENDING = "nestml"; + + final PredefinedTypesFactory typesFactory; + + /** + * {@inheritDoc} + */ + public NESTMLLanguage(final PredefinedTypesFactory typesFactory) { + super("NESTML Language", FILE_ENDING); + this.typesFactory = typesFactory; + + addResolver(CommonResolvingFilter.create(NESTMLNeuronSymbol.class, NESTMLNeuronSymbol.KIND)); + addResolver(CommonResolvingFilter.create(NESTMLTypeSymbol.class, NESTMLTypeSymbol.KIND)); + addResolver(CommonResolvingFilter.create(NESTMLMethodSymbol.class, NESTMLMethodSymbol.KIND)); + addResolver(CommonResolvingFilter.create(NESTMLVariableSymbol.class, NESTMLVariableSymbol.KIND)); + addResolver(CommonResolvingFilter.create(NESTMLUsageSymbol.class, NESTMLUsageSymbol.KIND)); + + setModelNameCalculator(new CommonModelNameCalculator() { + @Override public Optional calculateModelName(String name, SymbolKind kind) { + if (kind.isKindOf(NESTMLNeuronSymbol.KIND)) { + return Optional.of(calculateModelName(name)); + } + else { + return empty(); + } + } + + /** + * Neuron Models are placed in a file. The neuron which are defined in them are resolved by their names, but there is + * no artifact for it, but neuron is defined in a file defined by the fqn prefix. + * TODO: it is a big hack for now! wait for the correct implementation in the ST infrastructure + */ + public String calculateModelName(String name) { + checkArgument(!isNullOrEmpty(name)); + + // a.b.nestmlfile.IaFNeuron => a.b.nestmlfile is the artifact name + if (isQualifiedName(name)) { + // each model must be loaded at most once. cache every candidate and return for ever subsequent call an invalid + // name + return Names.getQualifier(name); + } + + return name; + } + + private boolean isQualifiedName(String name) { + return name.contains("."); + } + }); + } + + /** + * {@inheritDoc} + */ + @Override + protected NESTMLModelLoader provideModelLoader() { + return new NESTMLModelLoader(this); + } + + @Override + public Optional getSymbolTableCreator( + ResolverConfiguration resolverConfiguration, MutableScope mutableScope) { + return Optional.of(new CommonNESTMLSymbolTableCreator(resolverConfiguration, mutableScope, new PredefinedTypesFactory())); + } + +} diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLMethodSignaturePredicate.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLMethodSignaturePredicate.java new file mode 100644 index 000000000..197afbb33 --- /dev/null +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLMethodSignaturePredicate.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml._symboltable; + +import de.monticore.symboltable.Symbol; +import de.monticore.symboltable.SymbolPredicate; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; + +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Strings.emptyToNull; +import static java.util.Objects.requireNonNull; + +public class NESTMLMethodSignaturePredicate implements SymbolPredicate { + + private final String expectedMethodName; + private final List expectedParameterTypes = new ArrayList<>(); + + public NESTMLMethodSignaturePredicate(final String methodName, + final List parameters) { + this.expectedMethodName = requireNonNull(emptyToNull(methodName)); + + expectedParameterTypes.addAll(parameters); + + } + + @Override + public boolean apply(final Symbol symbol) { + if ((symbol != null) && + symbol.isKindOf(NESTMLMethodSymbol.KIND) && + (symbol instanceof NESTMLMethodSymbol)) { + final NESTMLMethodSymbol methodSymbol = (NESTMLMethodSymbol) symbol; + + if (methodSymbol.getName().equals(expectedMethodName) && + (methodSymbol.getParameterTypes().size() == expectedParameterTypes.size())) { + for (int i=0; i < methodSymbol.getParameterTypes().size(); i++) { + final String expectedType = expectedParameterTypes.get(i); + final String actualType = methodSymbol.getParameterTypes().get(i).getFullName(); + + if (!actualType.equals(expectedType)) { + return false; + } + } + + return true; + } + + } + + return false; + } + +} diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLModelLoader.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLModelLoader.java new file mode 100644 index 000000000..27a34f19a --- /dev/null +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLModelLoader.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml._symboltable; + +import de.monticore.modelloader.ModelingLanguageModelLoader; +import de.monticore.symboltable.ArtifactScope; +import de.monticore.symboltable.MutableScope; +import de.monticore.symboltable.ResolverConfiguration; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.logging.Log; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; + +import static de.se_rwth.commons.logging.Log.debug; + +/** + * Creates symbol table for the {@code NESTMLLanguage} from the parsed model. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLModelLoader extends ModelingLanguageModelLoader { + + public NESTMLModelLoader(NESTMLLanguage language) { + super(language); + } + + @Override + protected void createSymbolTableFromAST( + final ASTNESTMLCompilationUnit ast, + final String modelName, + final MutableScope enclosingScope, + final ResolverConfiguration resolverConfiguration) { + final NESTMLSymbolTableCreator symbolTableCreator = getModelingLanguage().getSymbolTableCreator + (resolverConfiguration, enclosingScope).orElse(null); + + if (symbolTableCreator != null) { + debug("Start creation of symbol table for model \"" + modelName + "\".", + NESTMLModelLoader.class.getSimpleName()); + final Scope scope = symbolTableCreator.createFromAST(ast); + + if (!(scope instanceof ArtifactScope)) { + Log.warn("Top scope of model " + modelName + " is expected to be a compilation scope, but" + + " is scope \"" + scope.getName() + "\""); + } + + debug("Created symbol table for model \"" + modelName + "\".", + NESTMLModelLoader.class.getSimpleName()); + } + else { + Log.warn("No symbol created, because '" + getModelingLanguage().getName() + + "' does not define a symbol table creator."); + } + + } + + @Override + public NESTMLLanguage getModelingLanguage() { + return (NESTMLLanguage) super.getModelingLanguage(); + } +} diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLRootCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLRootCreator.java new file mode 100644 index 000000000..164954e79 --- /dev/null +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLRootCreator.java @@ -0,0 +1,31 @@ +package org.nest.nestml._symboltable; + +import de.se_rwth.commons.logging.Log; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; + +import java.io.IOException; +import java.util.Optional; + +/** + * Created by user on 3/26/15. + */ +public class NESTMLRootCreator { + /** + * Parses the model and returns ast. + * @throws java.io.IOException + */ + public static Optional getAstRoot(String modelPath) { + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory + .createNESTMLCompilationUnitMCParser(); + try { + return p.parse(modelPath); + } + catch (IOException e) { + Log.error("Cannot parse the model: " + modelPath, e); + + } + return Optional.empty(); + } +} diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLScopeCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLScopeCreator.java new file mode 100644 index 000000000..6e52972c5 --- /dev/null +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLScopeCreator.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml._symboltable; + +import de.monticore.io.paths.ModelPath; +import de.monticore.symboltable.GlobalScope; +import de.monticore.symboltable.ResolverConfiguration; +import de.monticore.symboltable.Scope; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.symboltable.ScopeCreatorBase; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.nio.file.Paths; + +/** + * Creates a artifact scope, build the symbol table and adds predifined types. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLScopeCreator extends ScopeCreatorBase { + final static String LOG_NAME = NESTMLScopeCreator.class.getName(); + + private final NESTMLSymbolTableCreator symbolTableCreator; + + @Override + public String getLogger() { + return LOG_NAME; + } + + public PredefinedTypesFactory getTypesFactory() { + return typesFactory; + } + + public GlobalScope getGlobalScope() { + return globalScope; + } + + final GlobalScope globalScope; + + public NESTMLScopeCreator( + final String modelPathAsString, + final PredefinedTypesFactory typesFactory) { + super(typesFactory); + + final ModelPath modelPath = new ModelPath(Paths.get(modelPathAsString)); + + final NESTMLLanguage nestmlLanguages = new NESTMLLanguage(typesFactory); + + final ResolverConfiguration resolverConfiguration = new ResolverConfiguration(); + resolverConfiguration.addTopScopeResolvers(nestmlLanguages.getResolvers()); + + globalScope = new GlobalScope(modelPath, nestmlLanguages.getModelLoader(), resolverConfiguration); + addPredefinedTypes(globalScope); + addPredefinedFunctions(globalScope); + addPredefinedVariables(globalScope); + + symbolTableCreator = new CommonNESTMLSymbolTableCreator(resolverConfiguration, globalScope, typesFactory); + + } + + public Scope runSymbolTableCreator(final ASTNESTMLCompilationUnit compilationUnit) { + return symbolTableCreator.createFromAST(compilationUnit); + } + + + + +} diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java new file mode 100644 index 000000000..152476864 --- /dev/null +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java @@ -0,0 +1,493 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml._symboltable; + +import de.monticore.symboltable.*; +import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; +import org.nest.nestml._ast.*; +import org.nest.nestml._visitor.NESTMLVisitor; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.spl._ast.ASTCompound_Stmt; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.symboltable.symbols.*; +import org.nest.symboltable.symbols.references.NESTMLNeuronSymbolReference; +import org.nest.symboltable.symbols.references.NESTMLTypeSymbolReference; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkState; +import static de.se_rwth.commons.logging.Log.info; +import static de.se_rwth.commons.logging.Log.warn; +import static java.util.Objects.requireNonNull; +import static java.util.Optional.empty; +import static org.nest.symboltable.symbols.NESTMLNeuronSymbol.Type.COMPONENT; +import static org.nest.symboltable.symbols.NESTMLNeuronSymbol.Type.NEURON; + +/** + * Visitor that creates symbols that handles nestml models.. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public interface NESTMLSymbolTableCreator extends SymbolTableCreator, NESTMLVisitor { + + String LOGGER_NAME = NESTMLSymbolTableCreator.class.getName(); + + PredefinedTypesFactory getPredefinedTypesFactory(); + + void setPackageName(String packageName); + + void setRoot(final ASTNESTMLCompilationUnit compilationUnitAst); + + ASTNESTMLCompilationUnit getRoot(); + + String getPackageName(); + + void setAliasDeclaration(final Optional astAliasDeclaration); + + Optional getAliasDeclaration(); + + void setVariableBlockType(final Optional variableBlockType ); + + Optional getVariableBlockType(); + + /** + * Creates the symbol table starting from the rootNode and returns the first scope + * that was created. + * + * @param rootNode the root node + * @return the first scope that was created + */ + default Scope createFromAST(final ASTNESTMLNode rootNode) { + requireNonNull(rootNode); + rootNode.accept(this); + return getFirstCreatedScope(); + } + + + default void visit(final ASTNESTMLCompilationUnit compilationUnitAst) { + final String fullName = Names.getQualifiedName(compilationUnitAst.getPackageName().getParts()); + final String packageName = Names.getQualifier(fullName); + + setRoot(compilationUnitAst); + setPackageName(packageName); + + final List imports = computeImportStatements(compilationUnitAst); + + final MutableScope artifactScope = new ArtifactScope(empty(), fullName, imports); + putOnStack(artifactScope); + + info("Adds an artifact scope for the NESTML model file: " + fullName, LOGGER_NAME); + } + + default List computeImportStatements(ASTNESTMLCompilationUnit compilationUnitAst) { + final List imports = new ArrayList<>(); + if(compilationUnitAst.getImports() != null) { + + compilationUnitAst.getImports().stream().forEach(importStatement -> { + final String importAsString = Names.getQualifiedName(importStatement.getQualifiedName().getParts()); + imports.add(new ImportStatement(importAsString, importStatement.isStar())); + }); + } + return imports; + } + + default void endVisit(final ASTNESTMLCompilationUnit compilationUnitAst) { + final String fullName = Names.getQualifiedName(compilationUnitAst.getPackageName().getParts()); + + removeCurrentScope(); + + setEnclosingScopeOfNodes(compilationUnitAst); + info("Finishes handling and sets scopes on all ASTs for the artifact: " + fullName, LOGGER_NAME); + } + + default void visit(final ASTNeuron neuronAst) { + info("Processes the neuron: " + neuronAst.getName(), LOGGER_NAME); + + final NESTMLNeuronSymbol neuronSymbol = new NESTMLNeuronSymbol(neuronAst.getName(), NEURON); + + putInScopeAndLinkWithAst(neuronSymbol, neuronAst); + + info("Adds a neuron symbol: " + neuronSymbol.getFullName(), LOGGER_NAME); + } + + default void endVisit(final ASTNeuron neuron) { + removeCurrentScope(); + info(LOGGER_NAME, "Finishes handling of the neuron: " + neuron.getName()); + } + + default void visit(final ASTComponent componentAst) { + info("Processes the component: " + componentAst.getName(), LOGGER_NAME); + final NESTMLNeuronSymbol componentSymbol = new NESTMLNeuronSymbol(componentAst.getName(), COMPONENT); + + putInScopeAndLinkWithAst(componentSymbol, componentAst); + + info("Adds a component symbol for the component: " + componentSymbol.getFullName(), LOGGER_NAME); + } + + default void endVisit(final ASTComponent componentAst) { + removeCurrentScope(); + info("Finishes handling of the component: " + componentAst.getName(), LOGGER_NAME); + } + + /** + * + * {@code + * Grammar + * USE_Stmt implements BodyElement = "use" name:QualifiedName "as" alias:Name; + * + * Model: + * ... + * neuron iaf_neuron: + * use TestComponent as TestRef + * ... + * } + * + * + */ + default void visit(final ASTUSE_Stmt useAst) { + checkState(this.currentScope().isPresent()); + final Optional currentTypeSymbol = computeNeuronSymbolIfExists(this.currentScope().get()); + checkState(currentTypeSymbol.isPresent(), "This statement is defined in a nestml type."); + + final String referencedTypeName = Names.getQualifiedName(useAst.getName().getParts()); + + final String aliasFqn = useAst.getAlias(); + + // TODO it is not a reference, but a delegate + final NESTMLNeuronSymbolReference referencedType + = new NESTMLNeuronSymbolReference(referencedTypeName, NEURON, this.currentScope().get()); + referencedType.setAstNode(useAst); + final NESTMLUsageSymbol usageSymbol = new NESTMLUsageSymbol(aliasFqn, referencedType); + putInScope(usageSymbol); + + info("Handles an use statement: use " + referencedTypeName + " as " + aliasFqn, LOGGER_NAME); + } + + + // TODO: use the visitor approach + @SuppressWarnings("unchecked") // It is OK to suppress this warning, since it is checked in the if block + default Optional computeNeuronSymbolIfExists(final Scope mutableScope) { + if (mutableScope.getSpanningSymbol().isPresent() && + mutableScope.getSpanningSymbol().get() instanceof NESTMLNeuronSymbol) { + + return (Optional) mutableScope.getSpanningSymbol(); + } + else if (mutableScope.getEnclosingScope().isPresent()) { + return computeNeuronSymbolIfExists(mutableScope.getEnclosingScope().get()); + } + else { + return empty(); + } + + } + + default void endVisit(final ASTUSE_Stmt useAst) { + //removeCurrentScope(); + } + + /** + * {@code + * Grammar: + * AliasDecl = ([hide:"-"])? ([alias:"alias"])? Declaration;} + * Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expression )?; + * + * Model: + */ + default void visit(final ASTAliasDecl aliasDeclAst) { + checkState(this.currentScope().isPresent()); + + final String msg = "Begins handling of an alias declaration: " + aliasDeclAst.get_SourcePositionStart(); + info(msg, LOGGER_NAME); + setAliasDeclaration(Optional.of(aliasDeclAst)); + + } + + default void endVisit(final ASTAliasDecl aliasDeclAst) { + final String msg = "Ends handling of an alias declaration: " + aliasDeclAst.get_SourcePositionStart(); + info(msg, LOGGER_NAME); + setAliasDeclaration(empty()); + } + + /** + * {@code + * Grammar: + * InputLine = + * Name + * ("<" sizeParameter:Name ">")? + * "<-" InputType* + * (["spike"] | ["current"]); + * + * Model: + * alias V_m mV[testSize] = y3 + E_L + * } + */ + default void visit(final ASTInputLine inputLineAst) { + checkState(this.currentScope().isPresent()); + final Optional currentTypeSymbol = computeNeuronSymbolIfExists(this.currentScope().get()); + checkState(currentTypeSymbol.isPresent(), "This statement is defined in a nestml type."); + + final NESTMLTypeSymbol bufferType = getPredefinedTypesFactory().getBufferType(); + + final NESTMLVariableSymbol var = new NESTMLVariableSymbol(inputLineAst.getName()); + + var.setType(bufferType); + var.setDeclaringType(currentTypeSymbol.get()); + var.setAlias(false); + var.setHidden(false); + + var.setBlockType(NESTMLVariableSymbol.BlockType.BUFFER); + + if (inputLineAst.getSizeParameter().isPresent()) { + var.setArraySizeParameter(inputLineAst.getSizeParameter().get()); + } + + putInScopeAndLinkWithAst(var, inputLineAst); + info("Creates new symbol for the input buffer: " + var, LOGGER_NAME); + } + + + default void visit(final ASTFunction funcAst) { + checkState(this.currentScope().isPresent()); + final Optional currentTypeSymbol = computeNeuronSymbolIfExists(this.currentScope().get()); + checkState(currentTypeSymbol.isPresent(), "This statement is defined in a nestml type."); + + info(LOGGER_NAME, "Begins processing of the function: " + funcAst.getName()); + + NESTMLMethodSymbol methodSymbol = new NESTMLMethodSymbol(funcAst.getName()); + + methodSymbol.setDeclaringType(currentTypeSymbol.get()); + methodSymbol.setDynamics(false); + methodSymbol.setMinDelay(false); + methodSymbol.setTimeStep(false); + + putInScopeAndLinkWithAst(methodSymbol, funcAst); + + // Parameters + if (funcAst.getParameters().isPresent()) { + for (ASTParameter p : funcAst.getParameters().get().getParameters()) { + NESTMLTypeSymbol type = new NESTMLTypeSymbolReference( + p.getType().toString(), + NESTMLTypeSymbol.Type.PRIMITIVE, + this.currentScope().get()); + + methodSymbol.addParameterType(type); + + // add a var entry for method body + NESTMLVariableSymbol var =new NESTMLVariableSymbol(p.getName()); + var.setAstNode(p); + var.setType(type); + var.setAlias(false); + var.setHidden(false); + var.setDeclaringType(null); + var.setBlockType(NESTMLVariableSymbol.BlockType.LOCAL); + putInScopeAndLinkWithAst(var, p); + + } + + } + // return type + if (funcAst.getReturnType().isPresent()) { + final String returnTypeName = Names.getQualifiedName(funcAst.getReturnType().get().getParts()); + NESTMLTypeSymbol returnType = new NESTMLTypeSymbolReference( + returnTypeName, + NESTMLTypeSymbol.Type.PRIMITIVE, + currentScope().get()); + methodSymbol.setReturnType(returnType); + } + else { + methodSymbol.setReturnType(getPredefinedTypesFactory().getVoidType()); + } + + } + + default void endVisit(final ASTFunction funcAst) { + removeCurrentScope(); + info("Ends processing of the function: " + funcAst.getName(), LOGGER_NAME); + } + + default void visit(final ASTDynamics dynamicsAst) { + checkState(this.currentScope().isPresent()); + final Optional currentTypeSymbol = computeNeuronSymbolIfExists(this.currentScope().get()); + checkState(currentTypeSymbol.isPresent(), "This statement is defined in a nestml type."); + + final NESTMLMethodSymbol methodEntry = new NESTMLMethodSymbol("dynamics"); + + methodEntry.setDeclaringType(currentTypeSymbol.get()); + methodEntry.setDynamics(true); + methodEntry.setMinDelay(dynamicsAst.getMinDelay().isPresent()); + methodEntry.setTimeStep(dynamicsAst.getTimeStep().isPresent()); + + putInScopeAndLinkWithAst(methodEntry, dynamicsAst); + + // Parameters + if (dynamicsAst.getParameters().isPresent()) { + for (ASTParameter p : dynamicsAst.getParameters().get().getParameters()) { + NESTMLTypeSymbol type = new NESTMLTypeSymbolReference( + p.getType().toString(), + NESTMLTypeSymbol.Type.PRIMITIVE, + currentScope().get()); + + methodEntry.addParameterType(type); + + // add a var entry for method body + NESTMLVariableSymbol var = new NESTMLVariableSymbol(p.getName()); + var.setAstNode(p); + var.setType(type); + var.setAlias(false); + var.setHidden(false); + var.setDeclaringType(null); // TODO set to optional + var.setBlockType(NESTMLVariableSymbol.BlockType.LOCAL); + putInScopeAndLinkWithAst(var, p); + } + + } + + // return type + methodEntry.setReturnType(getPredefinedTypesFactory().getVoidType()); + + } + + + @Override + default void endVisit(final ASTDynamics de) { + removeCurrentScope(); + info("Ends processing of the dynamics: ", LOGGER_NAME); + } + + + @Override + default void visit(final ASTVar_Block astVarBlock) { + setVariableBlockType(Optional.of(astVarBlock)); + } + + @Override + default void endVisit(final ASTVar_Block astVarBlock) { + setVariableBlockType(empty()); + } + + + @Override + default void visit(final ASTCompound_Stmt astCompoundStmt) { + // TODO reuse SPLVisitor + final CommonScope shadowingScope = new CommonScope(true); + putOnStack(shadowingScope); + info("Spans block scope.", LOGGER_NAME); + } + + @Override + default void endVisit(final ASTCompound_Stmt astCompoundStmt) { + // TODO reuse SPLVisitor + removeCurrentScope(); + info("Removes block scope.", LOGGER_NAME); + } + + // TODO replication, refactor it + @Override + default void visit(final ASTDeclaration astDeclaration) { + final Optional currentTypeSymbol = computeNeuronSymbolIfExists( + this.currentScope().get()); + checkState(currentTypeSymbol.isPresent(), "This statement is defined in a nestml type."); + + final Optional aliasDeclAst = getAliasDeclaration(); + + if (aliasDeclAst.isPresent()) { + Optional blockAst = getVariableBlockType(); + + checkState(blockAst.isPresent(), "Declaration is not inside a block."); + + if (blockAst.get().isState()) { + addVariablesFromDeclaration( + astDeclaration, + currentTypeSymbol, + aliasDeclAst, + NESTMLVariableSymbol.BlockType.STATE); + } + else if (blockAst.get().isParameter()) { + addVariablesFromDeclaration( + astDeclaration, + currentTypeSymbol, + aliasDeclAst, + NESTMLVariableSymbol.BlockType.PARAMETER); + } + else if (blockAst.get().isInternal()) { + addVariablesFromDeclaration( + astDeclaration, + currentTypeSymbol, + aliasDeclAst, + NESTMLVariableSymbol.BlockType.INTERNAL); + } + else { + addVariablesFromDeclaration( + astDeclaration, + currentTypeSymbol, + aliasDeclAst, + NESTMLVariableSymbol.BlockType.LOCAL); + } + + + } + else { // the declaration is defined inside a method + addVariablesFromDeclaration( + astDeclaration, + currentTypeSymbol, + aliasDeclAst, + NESTMLVariableSymbol.BlockType.LOCAL); + + } + + } + + default void addVariablesFromDeclaration( + final ASTDeclaration astDeclaration, + final Optional currentTypeSymbol, + final Optional aliasDeclAst, + final NESTMLVariableSymbol.BlockType blockType) { + final String typeName = astDeclaration.getType().get().toString(); + + for (String varName : astDeclaration.getVars()) { // multiple vars in one decl possible + final Optional typeCandidate + = getPredefinedTypesFactory().getPredefinedTypeIfExists(typeName); + + if (typeCandidate.isPresent()) { + final NESTMLVariableSymbol var = new NESTMLVariableSymbol(varName); + + var.setAstNode(astDeclaration); + var.setType(typeCandidate.get()); + var.setDeclaringType(currentTypeSymbol.get()); + + if (aliasDeclAst.isPresent()) { + var.setAlias(aliasDeclAst.get().isAlias()); + var.setHidden(aliasDeclAst.get().isHide()); + } + else { + var.setAlias(false); + var.setHidden(false); + } + + if (astDeclaration.getSizeParameter().isPresent()) { + var.setArraySizeParameter(astDeclaration.getSizeParameter().get()); + } + + var.setBlockType(blockType); + putInScopeAndLinkWithAst(var, astDeclaration); + + info("Adds new variable '" + var.getFullName() + "'.", LOGGER_NAME); + } + else { + warn("The variable " + varName + " at " + astDeclaration.get_SourcePositionStart() + + " is ignored. Its type is " + typeName + "it either a unit, nor a predefined."); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/AliasHasNoSetter.java b/src/main/java/org/nest/nestml/cocos/AliasHasNoSetter.java new file mode 100644 index 000000000..2f8b3c287 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/AliasHasNoSetter.java @@ -0,0 +1,99 @@ +package org.nest.nestml.cocos; + + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._cocos.NESTMLASTAliasDeclCoCo; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.utils.NESTMLSymbols; + +import java.util.Optional; + +public class AliasHasNoSetter implements NESTMLASTAliasDeclCoCo { + + + public static final String ERROR_CODE = "NESTML_ALIAS_HAS_NO_SETTER"; + private final ASTNESTMLCompilationUnit astNestmlCompilationUnit; + + + public AliasHasNoSetter(final ASTNESTMLCompilationUnit astNestmlCompilationUnit) { + this.astNestmlCompilationUnit = astNestmlCompilationUnit; + } + + + @Override + public void check(ASTAliasDecl alias) { + if (alias.isAlias() && alias.getDeclaration() != null) { + + final ASTDeclaration decl = alias.getDeclaration(); + final Optional scope = decl.getEnclosingScope(); + Preconditions.checkState(scope.isPresent(), "No scope is assigned to the node: " + decl); + + if (decl.getVars().size() == 1) { + String aliasVar = decl.getVars().get(0); + + // TODO + //ASTParameter para = NESTMLNodeFactory.createASTParameter( + // "v", LiteralsNodeFactory.createASTDottedName(decl + // .getType().getNames())); + String varTypeName = Names.getQualifiedName(decl.getType().get().getParts()); + + + final Optional enclosingScope = decl.getEnclosingScope(); + + Preconditions.checkState(enclosingScope.isPresent(), "No scope assigned to the node: " + decl); + final String setterName = "set_" + aliasVar; + + Optional setter = NESTMLSymbols.resolveMethod(enclosingScope.get(), setterName, Lists.newArrayList(varTypeName)); + + if (!setter.isPresent()) { + final String msg = "Alias-variable '" + aliasVar + + "' needs a setter-function: set_" + aliasVar + + "(v " + decl.getType().get().toString() + ")"; + + CoCoLog.error(ERROR_CODE, + msg, + alias.get_SourcePositionStart()); + } + else { + + if (setter.get().getParameterTypes().size() == 1) { + NESTMLTypeSymbol setterType = setter.get().getParameterTypes().get(0); + + if (!setterType.getName().endsWith(decl.getType().get().toString())) { + final String msg = "Alias-variable '" + aliasVar + + "' needs a setter-function: set_" + aliasVar + + "(v " + decl.getType().get().toString() + ")"; + + CoCoLog.error(ERROR_CODE, + msg, + alias.get_SourcePositionStart()); + } + } + else { + // TODO check it + final String msg = "Alias-variable '" + aliasVar + + "' needs a setter-function: set_" + aliasVar + + "(v " + decl.getType().get().toString() + ")"; + CoCoLog.error(ERROR_CODE, + msg, + alias.get_SourcePositionStart()); + + } + + } + + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/AliasHasOneVar.java b/src/main/java/org/nest/nestml/cocos/AliasHasOneVar.java new file mode 100644 index 000000000..78b3ef5e5 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/AliasHasOneVar.java @@ -0,0 +1,25 @@ +package org.nest.nestml.cocos; + + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._cocos.NESTMLASTAliasDeclCoCo; + +public class AliasHasOneVar implements NESTMLASTAliasDeclCoCo { + + public static final String ERROR_CODE = "NESTML_ALIAS_HAS_ONE_VAR"; + + @Override + public void check(final ASTAliasDecl decl) { + if (decl.isAlias()) { + if (decl.getDeclaration().getVars().size() != 1) { + final String msg = "'alias' declarations must only declare one variable."; + + CoCoLog.error(ERROR_CODE, msg, decl.get_SourcePositionStart()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/AliasInNonAliasDecl.java b/src/main/java/org/nest/nestml/cocos/AliasInNonAliasDecl.java new file mode 100644 index 000000000..bf7179dd3 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/AliasInNonAliasDecl.java @@ -0,0 +1,97 @@ +package org.nest.nestml.cocos; + +import de.monticore.cocos.CoCoLog; +import de.monticore.types.types._ast.ASTQualifiedName; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._cocos.NESTMLASTComponentCoCo; +import org.nest.nestml._cocos.NESTMLASTNeuronCoCo; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkState; +import static de.monticore.utils.ASTNodes.getSuccessors; + +// TODO write a corresponding test +public class AliasInNonAliasDecl implements NESTMLASTNeuronCoCo, NESTMLASTComponentCoCo { + + public static final String ERROR_CODE = "NESTML_ALIAS_IN_NON_ALIAS_DECL"; + + @Override + public void check(ASTComponent astComponent) { + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(astComponent.getBody()); + final Optional componentSymbol + = (Optional) astComponent.getSymbol(); + checkState(componentSymbol.isPresent()); + checkAllAliasesInNeuron(astBodyDecorator, componentSymbol.get()); + } + + + @Override + public void check(ASTNeuron astNeuron) { + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(astNeuron.getBody()); + final Optional neuronSymbol + = (Optional) astNeuron.getSymbol(); + checkState(neuronSymbol.isPresent()); + checkAllAliasesInNeuron(astBodyDecorator, neuronSymbol.get()); + } + + public void checkAllAliasesInNeuron( + final ASTBodyDecorator astBodyDecorator, + final NESTMLNeuronSymbol neuronSymbol) { + astBodyDecorator.getInternals().forEach(astFunction -> checkAlias(astFunction, + neuronSymbol)); + astBodyDecorator.getStates().forEach(astFunction -> checkAlias(astFunction, + neuronSymbol)); + astBodyDecorator.getParameters().forEach(astFunction -> checkAlias(astFunction, + neuronSymbol)); + } + + public void checkAlias(final ASTAliasDecl alias, final NESTMLNeuronSymbol neuronSymbol) { + if (!alias.isAlias() && alias.getDeclaration().exprIsPresent()) { + final ASTDeclaration decl = alias.getDeclaration(); + Optional used; + + final List variables + = getSuccessors(decl.getExpr().get(), ASTQualifiedName.class); + // TODO Review the "reflection code" + for (final ASTQualifiedName atomFqn : variables) { + final String fullName = Names.getQualifiedName(atomFqn.getParts()); + + final Optional stentry = neuronSymbol.getVariableByName(fullName); + if (stentry.isPresent()) { + used = stentry; + } + else { + continue; + } + + if (!used.isPresent()) { // should not happen, but makes compiler + continue; + } + + // used is set here + if (used.get().isAlias()) { + final String msg = "Alias variable '" + + used.get().getName() + + "' cannot be used in default-value declaration of non-alias variables."; + CoCoLog.error( + ERROR_CODE, + msg, + decl.get_SourcePositionStart()); + } + + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/BooleanInvariantExpressions.java b/src/main/java/org/nest/nestml/cocos/BooleanInvariantExpressions.java new file mode 100644 index 000000000..a0363ee5b --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/BooleanInvariantExpressions.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml.cocos; + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._cocos.NESTMLASTAliasDeclCoCo; +import org.nest.spl._ast.ASTExpr; +import org.nest.spl.symboltable.typechecking.ExpressionTypeCalculator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +/** + * Frontend for the Simple Programming Language (SPL) + * + * @author (last commit) plotnikov + * @version $$Revision$$, 06.07.2015 + * @since 0.0.2 + */ +public class BooleanInvariantExpressions implements NESTMLASTAliasDeclCoCo { + + public static final String ERROR_CODE = "NESTML_INVARIANTS_WITH_CORRECT_VARIABLES"; + + private final PredefinedTypesFactory predefinedTypesFactory; + + public BooleanInvariantExpressions(PredefinedTypesFactory predefinedTypesFactory) { + this.predefinedTypesFactory = predefinedTypesFactory; + } + + public void check(final ASTAliasDecl alias) { + final ExpressionTypeCalculator expressionTypeCalculator = new ExpressionTypeCalculator( + predefinedTypesFactory); + + for (final ASTExpr invariantExpr:alias.getInvariants()) { + final NESTMLTypeSymbol expressionType = expressionTypeCalculator.computeType(invariantExpr); + + if (!expressionType.equals(predefinedTypesFactory.getBooleanType())) { + final String msg = "The type of the invariant expression must be boolean and not: " + + expressionType; + CoCoLog.error( + ERROR_CODE, + msg, + invariantExpr.get_SourcePositionStart()); + } + + } + + } + + +} diff --git a/src/main/java/org/nest/nestml/cocos/ComponentHasNoDynamics.java b/src/main/java/org/nest/nestml/cocos/ComponentHasNoDynamics.java new file mode 100644 index 000000000..0b01c3620 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/ComponentHasNoDynamics.java @@ -0,0 +1,31 @@ +package org.nest.nestml.cocos; + + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._cocos.NESTMLASTComponentCoCo; + +public class ComponentHasNoDynamics implements NESTMLASTComponentCoCo { + + + public static final String ERROR_CODE = "NESTML_COMPONENT_HAS_NO_DYNAMICS"; + + public void check(ASTComponent comp) { + if (comp.getBody() != null) { + ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(comp.getBody()); + + if (!bodyDecorator.getDynamics().isEmpty()) { + final String msg = "Components do not have dynamics function."; + CoCoLog.error( + ERROR_CODE, + msg, + comp.get_SourcePositionStart()); + } + + } + + } + + +} diff --git a/src/main/java/org/nest/nestml/cocos/ComponentNoInput.java b/src/main/java/org/nest/nestml/cocos/ComponentNoInput.java new file mode 100644 index 000000000..5dfb4da12 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/ComponentNoInput.java @@ -0,0 +1,26 @@ +package org.nest.nestml.cocos; + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._cocos.NESTMLASTComponentCoCo; + +public class ComponentNoInput implements NESTMLASTComponentCoCo { + + public static final String ERROR_CODE = "NESTML_COMPONENT_NO_INPUT"; + + @Override + public void check(ASTComponent comp) { + ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(comp.getBody()); + + if (bodyDecorator.getInputLines() != null) { // TODO null check makes no sense + if (!bodyDecorator.getInputLines().isEmpty()) { + final String msg = "Components cannot have inputs, since they are no elements of a neuronal network."; + CoCoLog.error(ERROR_CODE, msg, comp.get_SourcePositionStart()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/ComponentNoOutput.java b/src/main/java/org/nest/nestml/cocos/ComponentNoOutput.java new file mode 100644 index 000000000..f11c43605 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/ComponentNoOutput.java @@ -0,0 +1,28 @@ +package org.nest.nestml.cocos; + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._cocos.NESTMLASTComponentCoCo; + +public class ComponentNoOutput implements NESTMLASTComponentCoCo { + + public static final String ERROR_CODE = "NESTML_COMPONENT_NO_OUPUT"; + + @Override + public void check(ASTComponent comp) { + if (comp.getBody() != null) { + ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(comp.getBody()); + if (bodyDecorator.getOutputs() != null) { + if (!bodyDecorator.getOutputs().isEmpty()) { + final String msg = "Components do not have outputs, only neurons have outputs."; + CoCoLog.error(ERROR_CODE, msg, comp.get_SourcePositionStart()); + } + + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/CorrectReturnValues.java b/src/main/java/org/nest/nestml/cocos/CorrectReturnValues.java new file mode 100644 index 000000000..c1f12fa91 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/CorrectReturnValues.java @@ -0,0 +1,104 @@ +package org.nest.nestml.cocos; + +import com.google.common.base.Preconditions; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import org.nest.nestml._ast.ASTFunction; +import org.nest.nestml._cocos.NESTMLASTFunctionCoCo; +import org.nest.spl._ast.ASTReturnStmt; +import org.nest.spl.symboltable.typechecking.ExpressionTypeCalculator; +import org.nest.spl.symboltable.typechecking.TypeChecker; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.utils.ASTNodes; + +import java.util.List; +import java.util.Optional; + +public class CorrectReturnValues implements NESTMLASTFunctionCoCo { + + public static final String ERROR_CODE = "SPL_CORRECT_RETURN_VALUES"; + + private final PredefinedTypesFactory predefinedTypesFactory; + + public CorrectReturnValues(PredefinedTypesFactory predefinedTypesFactory) { + this.predefinedTypesFactory = predefinedTypesFactory; + } + + public void check(final ASTFunction fun) { + Preconditions.checkState(fun.getEnclosingScope().isPresent(), + "Function: " + fun.getName() + " has no scope assigned. "); + final Scope scope = fun.getEnclosingScope().get(); + // get return type + final Optional mEntry = scope.resolve(fun.getName(), NESTMLMethodSymbol.KIND); + Preconditions.checkState(mEntry.isPresent(), "Cannot resolve the method: " + fun.getName()); + final NESTMLTypeSymbol functionReturnType = mEntry.get().getReturnType(); + + // get all return statements in block + final List returns = ASTNodes.getReturnStatements(fun.getBlock()); + + final TypeChecker tc = new TypeChecker(predefinedTypesFactory); + + for (ASTReturnStmt r : returns) { + // no return expression + if (r.getExpr().isPresent() && !tc.checkVoid(functionReturnType)) { + // void return value + final String msg = "Function '" + fun.getName() + + "' must return a result of type " + + functionReturnType.getName() + "."; + CoCoLog.error(ERROR_CODE, msg, r.get_SourcePositionStart()); + + } + + if (r.getExpr().isPresent()) { + final ExpressionTypeCalculator typeCalculator = new ExpressionTypeCalculator( + predefinedTypesFactory); + final NESTMLTypeSymbol returnExpressionType = typeCalculator.computeType(r.getExpr().get()); + + if (tc.checkVoid(functionReturnType) && !tc.checkVoid(returnExpressionType)) { + // should return nothing, but does not + final String msg = "Function '" + fun.getName() + + "' must not return a result." + + functionReturnType.getName() + "."; + CoCoLog.error(ERROR_CODE, msg, r.get_SourcePositionStart()); + } + // same type is ok (e.g. string, boolean,integer, real,...) + if (tc.checkString(functionReturnType) && !tc.checkString(returnExpressionType)) { + // should return string, but does not + final String msg = "Function '" + fun.getName() + + "' must return a result of type " + + functionReturnType.getName() + "."; + CoCoLog.error(ERROR_CODE, msg, r.get_SourcePositionStart()); + } + if (tc.checkBoolean(functionReturnType) && !tc.checkBoolean(returnExpressionType)) { + // should return bool, but does not + final String msg = "Function '" + fun.getName() + + "' must return a result of type " + + functionReturnType.getName() + "."; + CoCoLog.error(ERROR_CODE, msg, r.get_SourcePositionStart()); + } + if (tc.checkUnit(functionReturnType) && !tc.checkUnit(returnExpressionType)) { + // should return numeric, but does not + final String msg = "Function '" + fun.getName() + + "' must return a result of type " + + functionReturnType.getName() + "."; + CoCoLog.error(ERROR_CODE, msg, r.get_SourcePositionStart()); + } + // real rType and integer eType is ok, since more general + // integer rType and real eType is not ok + final String msg = "Cannot convert from " + + returnExpressionType.getName() + + " (type of return expression) to " + + functionReturnType.getName() + + " (return type), since the first is real " + + "domain and the second is in the integer domain " + + "and conversion reduces the precision."; + CoCoLog.error(ERROR_CODE, msg, r.get_SourcePositionStart()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/CurrentInputIsNotInhExc.java b/src/main/java/org/nest/nestml/cocos/CurrentInputIsNotInhExc.java new file mode 100644 index 000000000..595974b4f --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/CurrentInputIsNotInhExc.java @@ -0,0 +1,25 @@ +package org.nest.nestml.cocos; + + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTInputLine; +import org.nest.nestml._cocos.NESTMLASTInputLineCoCo; + +public class CurrentInputIsNotInhExc implements NESTMLASTInputLineCoCo { + + public static final String ERROR_CODE = "NESTML_CURRENT_INPUT_IS_NOT_INH_EXC"; + + @Override + public void check(ASTInputLine inputLine) { + if (inputLine != null && inputLine.isCurrent() + && inputLine.getInputTypes() != null) { + if (!inputLine.getInputTypes().isEmpty()) { + final String msg = "Current input can neither be inhibitory nor excitatory."; + CoCoLog.error(ERROR_CODE, msg, inputLine.get_SourcePositionStart()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/DynamicsTimeStepParameter.java b/src/main/java/org/nest/nestml/cocos/DynamicsTimeStepParameter.java new file mode 100644 index 000000000..925f6efd7 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/DynamicsTimeStepParameter.java @@ -0,0 +1,62 @@ +package org.nest.nestml.cocos; + +import com.google.common.base.Preconditions; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTDynamics; +import org.nest.nestml._ast.ASTParameter; +import org.nest.nestml._cocos.NESTMLASTDynamicsCoCo; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +public class DynamicsTimeStepParameter implements NESTMLASTDynamicsCoCo { + public static final String ERROR_CODE = "NESTML_DYNAMICS_TIME_STEP_PARAMETER"; + + public void check(ASTDynamics dyn) { + checkArgument(dyn.getEnclosingScope().isPresent(), "No scope assigned. Please run SymbolTableCreator"); + final Scope scope = dyn.getEnclosingScope().get(); + + if (dyn.getTimeStep().isPresent()) { + if (dyn.getParameters().isPresent() + && dyn.getParameters().get().getParameters() != null) { + + if (dyn.getParameters().get().getParameters().size() != 1) { + final String msg = "Timestep-dynamics need exactly 1 parameter of type ."; + CoCoLog.error( + ERROR_CODE, + msg, + dyn.get_SourcePositionStart()); + + } else { // 1 parameters + // start time: ms or ms + final ASTParameter first = dyn.getParameters().get().getParameters().get(0); + + final String typeName = Names.getQualifiedName(first.getType().getParts()); + final Optional type = scope.resolve(typeName, NESTMLTypeSymbol.KIND); + + Preconditions.checkState(type.isPresent(), "Cannot find the type: " + typeName); + // TODO fix the implicit type. its fqn contains the artifact fqn prefix + if (!type.get().getName().endsWith("ms")) { + final String msg = "The timestep-dynamics parameter needs to be of type "; + CoCoLog.error(ERROR_CODE, msg, first.get_SourcePositionStart()); + + } + + + } + + } + else { + final String msg = "Timestep-dynamics need exactly 1 parameter of type ."; + CoCoLog.error(ERROR_CODE, msg, dyn.get_SourcePositionStart()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/FunctionHasReturnStatement.java b/src/main/java/org/nest/nestml/cocos/FunctionHasReturnStatement.java new file mode 100644 index 000000000..f88d7f5e8 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/FunctionHasReturnStatement.java @@ -0,0 +1,130 @@ +package org.nest.nestml.cocos; + +import com.google.common.base.Preconditions; +import de.monticore.ast.ASTNode; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTFunction; +import org.nest.nestml._cocos.NESTMLASTFunctionCoCo; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.spl._ast.*; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Checks that a function with a return value has a returning block of code. If + * the return statements of its block have the correct type is checked with + * another coco. + * + * @author Tammo Ippen + */ +public class FunctionHasReturnStatement implements NESTMLASTFunctionCoCo { + + public static final String ERROR_CODE = "NESTML_FUNCTION_HAS_RETURN_STATEMENT"; + + private final PredefinedTypesFactory predefinedTypesFactory; + + public FunctionHasReturnStatement(PredefinedTypesFactory predefinedTypesFactory) { + this.predefinedTypesFactory = predefinedTypesFactory; + } + + @Override + public void check(final ASTFunction fun) { + checkArgument(fun.getEnclosingScope().isPresent(), "No scope is assigned. Run symbol table creator."); + final Scope scope = fun.getEnclosingScope().get(); + + if (fun.getReturnType().isPresent()) { + // check if void type is stated + final String typeName = Names.getQualifiedName(fun.getReturnType().get().getParts()); + Optional rType = scope.resolve(typeName, NESTMLTypeSymbol.KIND); + Preconditions.checkState(rType.isPresent(), "Cannot resolve the type: " + typeName); + + // TODO fix the problem with the FQN of the predefined types + if (rType.get().getFullName().equals(predefinedTypesFactory.getVoidType().getName())) { + return; + } + + // non void return type + // if block not returning: + if (isReturnBlock(fun.getBlock()) == null) { + final String msg = "Function '" + fun.getName() + + "' must return a result of type '" + + fun.getReturnType().get().toString(); + CoCoLog.error( + ERROR_CODE, + msg, + fun.get_SourcePositionStart()); + } + + } + + } + + protected ASTNode isReturnBlock(final ASTBlock block) { + + // Block = Stmt* + for (ASTStmt stmt : block.getStmts()) { + + // Stmt = Simple_Stmt | Compound_Stmt; + if (stmt.getSimple_Stmt().isPresent() && stmt.getSimple_Stmt().get().getSmall_Stmts() != null) { + // Simple_Stmt = Small_Stmt (options {greedy=true;}:";" Small_Stmt)* (";")?; + for (ASTSmall_Stmt small : stmt.getSimple_Stmt().get().getSmall_Stmts()) { + // Small_Stmt = (DottedName "=") => Assignment | + // FunctionCall | Declaration | ReturnStmt; + if (small.getReturnStmt().isPresent()) { + // return found! + return small.getReturnStmt().get(); + } + } + } else if (stmt.getCompound_Stmt().isPresent()) { + ASTNode r = isReturnCompound(stmt.getCompound_Stmt().get()); + if (r != null) { + return r; + } + } + } + return null; + } + + private ASTNode isReturnCompound(ASTCompound_Stmt compound) { + // Compound_Stmt = IF_Stmt | FOR_Stmt | WHILE_Stmt; + if (compound.getIF_Stmt().isPresent()) { + return isIFReturn(compound.getIF_Stmt().get()); + } else if (compound.getFOR_Stmt().isPresent() + && isReturnBlock(compound.getFOR_Stmt().get().getBlock()) != null) { + return compound.getFOR_Stmt().get(); + } else if (compound.getWHILE_Stmt().isPresent() + && isReturnBlock(compound.getWHILE_Stmt().get().getBlock()) != null) { + return compound.getWHILE_Stmt().get(); + } + + return null; + } + + private ASTNode isIFReturn(ASTIF_Stmt ifStmt) { + // 1) need an else block + if (ifStmt.getELSE_Clause() == null) { + return null; + } + + // 2) all if/elif/else blocks need to be returning + boolean allReturn = true; + allReturn = allReturn && isReturnBlock(ifStmt.getIF_Clause().getBlock()) != null; + if (ifStmt.getELSE_Clause().isPresent()) { + allReturn = allReturn + && isReturnBlock(ifStmt.getELSE_Clause().get().getBlock()) != null; + } else { + return null; + } + + for (ASTELIF_Clause elif : ifStmt.getELIF_Clauses()) { + allReturn = allReturn && isReturnBlock(elif.getBlock()) != null; + } + return allReturn ? ifStmt : null; + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/InvalidTypesInDeclaration.java b/src/main/java/org/nest/nestml/cocos/InvalidTypesInDeclaration.java new file mode 100644 index 000000000..6c4718092 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/InvalidTypesInDeclaration.java @@ -0,0 +1,108 @@ +package org.nest.nestml.cocos; + + +import com.google.common.base.Preconditions; +import de.monticore.ast.ASTCNode; +import de.monticore.ast.ASTNode; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.*; +import org.nest.nestml._cocos.NESTMLASTAliasDeclCoCo; +import org.nest.nestml._cocos.NESTMLASTFunctionCoCo; +import org.nest.nestml._cocos.NESTMLASTUSE_StmtCoCo; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.spl._cocos.SPLASTDeclarationCoCo; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.utils.ASTNodes; + +import java.util.Optional; + +import static org.abego.treelayout.internal.util.Contract.checkState; + +public class InvalidTypesInDeclaration implements + NESTMLASTUSE_StmtCoCo, + SPLASTDeclarationCoCo, + NESTMLASTFunctionCoCo { + + public static final String ERROR_CODE = "NESTML_INVALID_TYPES_DECLARATION"; + + + @Override + public void check(ASTDeclaration decl) { + + if (decl.getType().isPresent()) { + String typeName = Names.getQualifiedName(decl.getType().get().getParts()); + + final Optional enclosingScope = decl.getEnclosingScope(); + Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + decl); + Optional type = enclosingScope.get().resolve(typeName, NESTMLTypeSymbol.KIND); + checkIfValidType(decl, typeName, type); + + } + + } + + @Override + public void check(ASTFunction fun) { + String typeName; + // check parameter types + if (fun.getParameters().isPresent()) { + for (ASTParameter par : fun.getParameters().get().getParameters()) { + typeName = Names.getQualifiedName(par.getType().getParts()); + + Optional enclosingScope = fun.getEnclosingScope(); + Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + fun); + Optional type = enclosingScope.get().resolve(typeName, NESTMLTypeSymbol.KIND); + + checkIfValidType(fun, typeName, type); + + } + + // check return type + if (fun.getReturnType().isPresent()) { + typeName = Names.getQualifiedName(fun.getReturnType().get().getParts()); + + final Optional enclosingScope = fun.getEnclosingScope(); + Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + fun); + final Optional type = enclosingScope.get().resolve(typeName, NESTMLTypeSymbol.KIND); + checkIfValidType(fun, typeName, type); + + //doCheck(type.get(), fun.getReturnType().get(), true); + } + } + + } + + public void checkIfValidType(ASTNode decl, String typeName, Optional type) { + if (!type.isPresent() || type.isPresent() && type.get().getName().endsWith("Logger")) { + final String msgPredefined = "The type '%s' is a neuron/component. No neurons/components allowed " + + "in this place. Use the use-statement."; + CoCoLog.error( + ERROR_CODE, + String.format(msgPredefined, typeName), + decl.get_SourcePositionStart()); + } + } + + @Override + public void check(ASTUSE_Stmt astUseStmt) { + String typeName = Names.getQualifiedName(astUseStmt.getName().getParts()); + Optional enclosingScope = astUseStmt.getEnclosingScope(); + checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node at: " + astUseStmt.get_SourcePositionStart()); + Optional type = enclosingScope.get().resolve(typeName, NESTMLNeuronSymbol.KIND); + + if (!type.isPresent()) { + final String msgPredefined = "The type '%s' is a neuron/component. No neurons/components allowed " + + "in this place. Use the use-statement."; + CoCoLog.error( + ERROR_CODE, + String.format(msgPredefined, typeName), + astUseStmt.get_SourcePositionStart()); + } + + } + + +} diff --git a/src/main/java/org/nest/nestml/cocos/MemberVariableDefinedMultipleTimes.java b/src/main/java/org/nest/nestml/cocos/MemberVariableDefinedMultipleTimes.java new file mode 100644 index 000000000..e730a5ab1 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/MemberVariableDefinedMultipleTimes.java @@ -0,0 +1,67 @@ +package org.nest.nestml.cocos; + + +import com.google.common.collect.Maps; +import de.monticore.cocos.CoCoLog; +import de.se_rwth.commons.SourcePosition; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTBody; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._cocos.NESTMLASTComponentCoCo; +import org.nest.nestml._cocos.NESTMLASTNeuronCoCo; +import org.nest.spl._ast.ASTDeclaration; + +import java.util.Map; + +/** + * This context condition checks, whether the state/parameter/internal-variables + * of a component/neuron is not defined multiple times. + * + * E.g. in the following case x defined twice and results in an error + * neuron NeuronInTest: + * state: x mV end + * parameter: x real end + * end + * + * @author Tammo Ippen + */ +public class MemberVariableDefinedMultipleTimes implements NESTMLASTNeuronCoCo, + NESTMLASTComponentCoCo { + + public static final String ERROR_CODE = "NESTML_MEMBER_VARIABLE_DEFINED_MULTIPLE_TIMES"; + + public void check(ASTComponent comp) { + check(comp.getBody()); + } + + public void check(ASTNeuron neuron) { + check(neuron.getBody()); + } + + private void check(ASTBody body) { + ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(body); + Map varNames = Maps.newHashMap(); + bodyDecorator.getStates().forEach(aliasDecl -> addNames(varNames, aliasDecl.getDeclaration())); + bodyDecorator.getParameters().forEach(aliasDecl -> addNames(varNames, aliasDecl.getDeclaration())); + bodyDecorator.getInternals().forEach(aliasDecl -> addNames(varNames, aliasDecl.getDeclaration())); + } + + private void addNames(Map names, ASTDeclaration decl) { + for (String var : decl.getVars()) { + if (names.containsKey(var)) { + final String msg = "Variable '" + var + "' defined previously defined i line: " + + names.get(var).getLine() + ":" + names.get(var).getColumn(); + + CoCoLog.error(ERROR_CODE, msg, decl.get_SourcePositionStart()); + + } + else { + names.put(var, decl.get_SourcePositionStart()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/MemberVariablesInitialisedInCorrectOrder.java b/src/main/java/org/nest/nestml/cocos/MemberVariablesInitialisedInCorrectOrder.java new file mode 100644 index 000000000..6905d9423 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/MemberVariablesInitialisedInCorrectOrder.java @@ -0,0 +1,134 @@ +package org.nest.nestml.cocos; + +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.monticore.types.types._ast.ASTQualifiedName; +import de.monticore.utils.ASTNodes; +import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._cocos.NESTMLASTAliasDeclCoCo; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.spl._ast.ASTExpr; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkState; + +public class MemberVariablesInitialisedInCorrectOrder implements NESTMLASTAliasDeclCoCo { + + public static final String ERROR_CODE = "NESTML_MEMBER_VARIABLES_INITIALISED_IN_CORRECT_ORDER"; + + /** + * AliasDecl = ([hide:"-"])? ([alias:"alias"])? Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + * Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + * + * @param alias + */ + public void check(final ASTAliasDecl alias) { + final Optional enclosingScope = alias.getEnclosingScope(); + checkState(enclosingScope.isPresent(), + "There is no scope assigned to the AST node: " + alias); + ASTDeclaration declaration = alias.getDeclaration(); + + if (declaration.getExpr().isPresent() && declaration.getVars().size() > 0) { + final String lhsVariableName = declaration.getVars().get(0); // has at least one declaration + + final Optional lhsSymbol = enclosingScope.get().resolve( + lhsVariableName, + NESTMLVariableSymbol.KIND); // TODO use cached version + + checkState(lhsSymbol.isPresent(), "Variable '" + lhsVariableName + "' is not defined"); + + final List variablesNames + = ASTNodes.getSuccessors(declaration.getExpr().get(), ASTQualifiedName.class); + + for (ASTQualifiedName variableFqnAst : variablesNames) { + final String rhsVariableName = Names.getQualifiedName(variableFqnAst.getParts()); + Optional rhsSymbol = enclosingScope.get().resolve( + rhsVariableName, + NESTMLVariableSymbol.KIND); + + if (!rhsSymbol.isPresent()) { // actually redudant and it is should be checked through another CoCo + final String msg = "Variable '" + rhsVariableName + "' is undefined." + "<" + + variableFqnAst.get_SourcePositionStart() + "," + variableFqnAst.get_SourcePositionEnd() + ">"; + Log.warn(msg); + return; + } + else { // + // not local, e.g. a variable in one of the blocks: state, parameter, or internal + // both of same decl type + checkIfDefinedInCorrectOrder(lhsSymbol.get(), rhsSymbol.get()); + + } + + } + + for (ASTExpr aliasExpression:alias.getInvariants()) { + final List namesInInvariant + = ASTNodes.getSuccessors(aliasExpression, ASTQualifiedName.class); + + for (ASTQualifiedName variableFqnAst : namesInInvariant) { + final String rhsVariableName = Names.getQualifiedName(variableFqnAst.getParts()); + Optional variableSymbol = enclosingScope.get().resolve( + rhsVariableName, + NESTMLVariableSymbol.KIND); + + if (!variableSymbol.isPresent()) { // actually redudant and it is should be checked through another CoCo + final String msg = "Variable '" + rhsVariableName + "' is undefined." + "<" + + variableFqnAst.get_SourcePositionStart() + "," + variableFqnAst.get_SourcePositionEnd() + ">"; + Log.warn(msg); + return; + } + else { // + // not local, e.g. a variable in one of the blocks: state, parameter, or internal + // both of same decl type + checkIfDefinedInCorrectOrder(lhsSymbol.get(), variableSymbol.get()); + + } + + } + + } + + } + + } + + protected void checkIfDefinedInCorrectOrder( + final NESTMLVariableSymbol lhsSymbol, + final NESTMLVariableSymbol rhsSymbol) { + if (rhsSymbol.getDeclaringType().getName() + .equals(lhsSymbol.getDeclaringType().getName())) { + // same var - block? => used must be in + // previous line + if (rhsSymbol.getBlockType() == lhsSymbol.getBlockType()) { + // same block not parameter block + if (rhsSymbol.getSourcePosition().getLine() > + lhsSymbol.getSourcePosition().getLine()) { + final String msg = "Variable '" + + rhsSymbol.getName() + + "' must be declared before it can be used in declaration of '" + + lhsSymbol.getName() + "'."; + CoCoLog.error(ERROR_CODE, msg, rhsSymbol.getSourcePosition()); + + } + } + if (rhsSymbol.getBlockType() != lhsSymbol.getBlockType() && + rhsSymbol.getBlockType() != NESTMLVariableSymbol.BlockType.PARAMETER) { + final String msg = "Variable '" + + rhsSymbol.getName() + + "' must be declared in the parameter block to be used at this place. '" + + lhsSymbol.getName() + "'."; + CoCoLog.error(ERROR_CODE, msg, rhsSymbol.getSourcePosition()); + } + + } + + } + + + +} diff --git a/src/main/java/org/nest/nestml/cocos/MultipleFunctionDeclarations.java b/src/main/java/org/nest/nestml/cocos/MultipleFunctionDeclarations.java new file mode 100644 index 000000000..9b2660a84 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/MultipleFunctionDeclarations.java @@ -0,0 +1,73 @@ +package org.nest.nestml.cocos; + +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.resolving.ResolvedSeveralEntriesException; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._ast.ASTFunction; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTParameter; +import org.nest.nestml._cocos.NESTMLASTComponentCoCo; +import org.nest.nestml._cocos.NESTMLASTNeuronCoCo; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkState; + +public class MultipleFunctionDeclarations implements NESTMLASTNeuronCoCo, NESTMLASTComponentCoCo { + + public static final String ERROR_CODE = "NESTML_MULTIPLE_FUNCTIONS_DECLARATIONS"; + + + @Override public void check(ASTComponent astComponent) { + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(astComponent.getBody()); + final Optional componentSymbol + = (Optional) astComponent.getSymbol(); + checkState(componentSymbol.isPresent()); + astBodyDecorator.getFunctions().forEach(astFunction -> checkFunctionName(astFunction, + componentSymbol.get())); + } + + + @Override public void check(ASTNeuron astNeuron) { + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(astNeuron.getBody()); + final Optional neuronSymbol + = (Optional) astNeuron.getSymbol(); + checkState(neuronSymbol.isPresent()); + astBodyDecorator.getFunctions().forEach(astFunction -> checkFunctionName(astFunction, neuronSymbol.get())); + } + + private void checkFunctionName( + final ASTFunction astFunction, + final NESTMLNeuronSymbol neuronSymbol) { + + String funname = astFunction.getName(); + + final ASTParameter[] params; + if (astFunction.getParameters().isPresent() + && astFunction.getParameters().get().getParameters().size() > 0) { + params = astFunction.getParameters().get().getParameters().toArray(); + } else { + params = new ASTParameter[0]; + } + + + try { + // throws a ResolvedSeveralEntriesException exception in case the name is unambiguous + neuronSymbol.getMethodByName(funname); + + + } + catch (ResolvedSeveralEntriesException e) { + final String msg = "The function '" + funname + "' with " + + params.length + + " parameter(s) is defined multiple times."; + CoCoLog.error( + ERROR_CODE, + msg, + astFunction.get_SourcePositionStart()); + } + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/MultipleInhExcInput.java b/src/main/java/org/nest/nestml/cocos/MultipleInhExcInput.java new file mode 100644 index 000000000..d73541a45 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/MultipleInhExcInput.java @@ -0,0 +1,40 @@ +package org.nest.nestml.cocos; + + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTInputLine; +import org.nest.nestml._ast.ASTInputType; +import org.nest.nestml._cocos.NESTMLASTInputLineCoCo; + +public class MultipleInhExcInput implements NESTMLASTInputLineCoCo { + + public static final String ERROR_CODE = "NESTML_MULTIPLE_INH_EXC_INPUT"; + + public void check(ASTInputLine inputLine) { + if (inputLine != null && inputLine.isSpike() + && inputLine.getInputTypes() != null) { + // get number of inh, exc keywords + int inh = 0, exc = 0; + for (ASTInputType inputType : inputLine.getInputTypes()) { + if (inputType.isInhibitory()) { + ++inh; + } else if (inputType.isExcitatory()) { + ++exc; + } + } + + if (inh > 1) { + final String msg = "Multiple occurrences of the keyword 'inhibitory' are not allowed."; + CoCoLog.error(ERROR_CODE, msg, inputLine.get_SourcePositionStart()); + } + + if (exc > 1) { + final String msg = "Multiple occurrences of the keyword 'excitatory' are not allowed."; + CoCoLog.error(ERROR_CODE, msg, inputLine.get_SourcePositionStart()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/MultipleOutputs.java b/src/main/java/org/nest/nestml/cocos/MultipleOutputs.java new file mode 100644 index 000000000..b2062db09 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/MultipleOutputs.java @@ -0,0 +1,34 @@ +package org.nest.nestml.cocos; + +import com.google.common.base.Preconditions; +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTOutput; +import org.nest.nestml._cocos.NESTMLASTNeuronCoCo; + +import java.util.List; + +public class MultipleOutputs implements NESTMLASTNeuronCoCo { + + public static final String ERROR_CODE = "NESTML_MULTIPLE_OUTPUTS"; + + public void check(ASTNeuron neuron) { + Preconditions.checkNotNull(neuron); + Preconditions.checkNotNull(neuron.getBody()); + + + ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(neuron.getBody()); + final List outputs = bodyDecorator.getOutputs(); + + if (outputs.size() > 1) { + final String msg = "Neurons have at most one output and not " + outputs.size() + "."; + CoCoLog.error( + ERROR_CODE, + msg, + neuron.get_SourcePositionStart()); + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/NESTFunctionNameChecker.java b/src/main/java/org/nest/nestml/cocos/NESTFunctionNameChecker.java new file mode 100644 index 000000000..b3b5764fa --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/NESTFunctionNameChecker.java @@ -0,0 +1,36 @@ +package org.nest.nestml.cocos; + + +import com.google.common.collect.ImmutableSet; +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTFunction; +import org.nest.nestml._cocos.NESTMLASTFunctionCoCo; + +import java.util.Set; + +public class NESTFunctionNameChecker implements NESTMLASTFunctionCoCo { + + public static final String ERROR_CODE = "NESTML_F"; + + private Set nestFunNames = ImmutableSet.of( + "update", "calibrate", "handle", "connect_sender", "check_connection", "get_status", "set_status", + "init_state_", "init_buffers_"); + + public void check(ASTFunction fun) { + if (fun != null && fun.getName() != null) { + final String funName = fun.getName(); + + if (nestFunNames.contains(funName)) { + final String msg = "The function-name '" + funName + + "' is already used by NEST. Please use another name."; + CoCoLog.error( + ERROR_CODE, + msg, + fun.get_SourcePositionStart()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/NESTGetterSetterFunctionNames.java b/src/main/java/org/nest/nestml/cocos/NESTGetterSetterFunctionNames.java new file mode 100644 index 000000000..af3e7b56e --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/NESTGetterSetterFunctionNames.java @@ -0,0 +1,95 @@ +package org.nest.nestml.cocos; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTFunction; +import org.nest.nestml._cocos.NESTMLASTFunctionCoCo; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; +import org.nest.utils.NESTMLSymbols; + +import java.util.List; +import java.util.Optional; + +public class NESTGetterSetterFunctionNames implements NESTMLASTFunctionCoCo { + + + public static final String ERROR_CODE = "NESTML_GETTER_SETTER_FUNCTION_NAMES"; + + public void check(final ASTFunction fun) { + String funName = fun.getName(); + + final Optional enclosingScope = fun.getEnclosingScope(); + Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + fun.getName()); + + NESTMLMethodSymbol me = getMethodEntry(fun, enclosingScope.get()); + + if (me.getDeclaringNeuron().getType() == NESTMLNeuronSymbol.Type.COMPONENT + && funName.equals("get_instance") + && me.getParameterTypes().size() == 0) { + + final String msg = "The function '" + + funName + + "' is going to be generated. Please use another name."; + CoCoLog.error(ERROR_CODE, msg, fun.get_SourcePositionStart()); + return; + } + + if (funName.startsWith("get_") || funName.startsWith("set_")) { + String varName = funName.substring(4); + + Optional var = enclosingScope.get().resolve(varName, NESTMLVariableSymbol.KIND) ; + + if (var.isPresent()) { + + if (funName.startsWith("set_") + && me.getParameterTypes().size() == 1 + && !var.get().isAlias()) { + final String msg = "The function '" + funName + + "' is going to be generated, since" + + " there is a variable called '" + varName + + "'."; + CoCoLog.error(ERROR_CODE, msg, fun.get_SourcePositionStart()); + } + + if (funName.startsWith("get_") + && me.getParameterTypes().size() == 0) { + final String msg = "The function '" + funName + + "' is going to be generated, since" + + " there is a variable called '" + varName + + "'."; + CoCoLog.error(ERROR_CODE, msg, fun.get_SourcePositionStart()); + } + + } + + } + + } + + private NESTMLMethodSymbol getMethodEntry(final ASTFunction fun, final Scope scope) { + Optional me; + + if (!fun.getParameters().isPresent()) { + me = NESTMLSymbols.resolveMethod(scope, fun.getName(), Lists.newArrayList()); + } + else { + List parameters = Lists.newArrayList(); + for (int i = 0; i < fun.getParameters().get().getParameters().size(); ++i) { + String parameterTypeFqn = Names.getQualifiedName(fun.getParameters().get().getParameters().get(i).getType().getParts()); + parameters.add(parameterTypeFqn); + } + + me = NESTMLSymbols.resolveMethod(scope, fun.getName(), parameters); + } + + Preconditions.checkState(me.isPresent(), "Cannot resolve the method: " + fun.getName()); + return me.get(); + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/NeuronNeedsDynamics.java b/src/main/java/org/nest/nestml/cocos/NeuronNeedsDynamics.java new file mode 100644 index 000000000..2c3197fb2 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/NeuronNeedsDynamics.java @@ -0,0 +1,30 @@ +package org.nest.nestml.cocos; + + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._cocos.NESTMLASTNeuronCoCo; + +public class NeuronNeedsDynamics implements NESTMLASTNeuronCoCo { + + + public static final String ERROR_CODE = "NESTML_NEURON_NEEDS_DYNAMICS"; + + public void check(ASTNeuron neuron) { + ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(neuron.getBody()); + + if (bodyDecorator.getDynamics().isEmpty()) { + final String msg = "Neurons need at least one dynamics function."; + CoCoLog.error(ERROR_CODE, msg, neuron.get_SourcePositionStart()); + } + + if (bodyDecorator.getDynamics().size() > 1) { + final String msg = "Neurons need at most one dynamics function."; + CoCoLog.error(ERROR_CODE, msg, neuron.get_SourcePositionStart()); + } + + } + + +} diff --git a/src/main/java/org/nest/nestml/cocos/NeuronWithoutInput.java b/src/main/java/org/nest/nestml/cocos/NeuronWithoutInput.java new file mode 100644 index 000000000..47b9db0c6 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/NeuronWithoutInput.java @@ -0,0 +1,28 @@ +package org.nest.nestml.cocos; + + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTInputLine; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._cocos.NESTMLASTNeuronCoCo; + +import java.util.List; + +public class NeuronWithoutInput implements NESTMLASTNeuronCoCo { + + public static final String ERROR_CODE = "NESTML_NEURON_WITHOUT_INPUT"; + + public void check(ASTNeuron neuron) { + ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(neuron.getBody()); + + List inputs = bodyDecorator.getInputLines(); + + if (inputs.isEmpty()) { + final String msg = "Neurons need some inputs."; + CoCoLog.error(ERROR_CODE, msg, neuron.get_SourcePositionStart()); + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/NeuronWithoutOutput.java b/src/main/java/org/nest/nestml/cocos/NeuronWithoutOutput.java new file mode 100644 index 000000000..2e67b987c --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/NeuronWithoutOutput.java @@ -0,0 +1,27 @@ +package org.nest.nestml.cocos; + +import de.monticore.cocos.CoCoLog; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTOutput; +import org.nest.nestml._cocos.NESTMLASTNeuronCoCo; + +import java.util.List; + +public class NeuronWithoutOutput implements NESTMLASTNeuronCoCo { + + public static final String ERROR_CODE = "NESTML_NEURON_WITHOUT_OUTPUT"; + + public void check(ASTNeuron neuron) { + final ASTBodyDecorator bodyDecorator = new ASTBodyDecorator(neuron.getBody()); + + final List inputs = bodyDecorator.getOutputs(); + + if (inputs.isEmpty()) { + final String msg = "Neurons need some outputs."; + CoCoLog.error(ERROR_CODE, msg, neuron.get_SourcePositionStart()); + } + + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/TypeIsDeclaredMultipleTimes.java b/src/main/java/org/nest/nestml/cocos/TypeIsDeclaredMultipleTimes.java new file mode 100644 index 000000000..8fd782a96 --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/TypeIsDeclaredMultipleTimes.java @@ -0,0 +1,47 @@ +package org.nest.nestml.cocos; + + +import de.monticore.ast.ASTCNode; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.monticore.symboltable.resolving.ResolvedSeveralEntriesException; +import org.nest.nestml._ast.ASTComponent; +import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._cocos.NESTMLASTComponentCoCo; +import org.nest.nestml._cocos.NESTMLASTNeuronCoCo; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import static com.google.common.base.Preconditions.checkArgument; + +public class TypeIsDeclaredMultipleTimes implements NESTMLASTComponentCoCo, NESTMLASTNeuronCoCo { + + public static final String ERROR_CODE = "NESTML_TYPES_DECLARED_MULTIPLE_TIMES"; + + public void check(final ASTNeuron neuron) { + check(neuron.getName(), neuron); + } + + public void check(final ASTComponent comp) { + if (comp != null && comp.getName() != null) { + check(comp.getName(), comp); + } + + } + + private void check(String name, ASTCNode node) { + checkArgument(node.getEnclosingScope().isPresent(), "No scope assigned. Please run symbol table creator"); + try { + + // TODO refactor, document + node.getEnclosingScope().get().resolve(name, NESTMLNeuronSymbol.KIND); + } + catch (ResolvedSeveralEntriesException e) { + final String msg = "The type '" + name + "' is defined multiple times."; + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionEnd()); + } + + } + +} + diff --git a/src/main/java/org/nest/nestml/cocos/UsesOnlyComponents.java b/src/main/java/org/nest/nestml/cocos/UsesOnlyComponents.java new file mode 100644 index 000000000..3d0604b8f --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/UsesOnlyComponents.java @@ -0,0 +1,47 @@ +package org.nest.nestml.cocos; + + +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.ASTUSE_Stmt; +import org.nest.nestml._cocos.NESTMLASTUSE_StmtCoCo; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +public class UsesOnlyComponents implements NESTMLASTUSE_StmtCoCo { + + public final static String ERROR_CODE = "NESTML_USES_ONLY_COMPONENTS"; + + + public void check(ASTUSE_Stmt use) { + checkArgument(use.getEnclosingScope().isPresent(), "No scope was assigned. Please, run symboltable creator."); + final String typeName = Names.getQualifiedName(use.getName().getParts()); + + final Scope scope = use.getEnclosingScope().get(); + + final Optional predefinedType = scope.resolve(typeName, NESTMLTypeSymbol.KIND); + + if (predefinedType.isPresent()) { + final String msg = "Only components can be used by neurons/components and not " + typeName + " of the type: " + + predefinedType.get().getType() + " ."; + CoCoLog.error(ERROR_CODE, msg); + } + + final Optional neuronType = scope.resolve(typeName, NESTMLNeuronSymbol.KIND); + + if (neuronType.isPresent() && !neuronType.get().getType().equals(NESTMLNeuronSymbol.Type.COMPONENT)) { + final String msg = "Only components can be used by components and not " + typeName + " that is a neuron, not a " + + "component"; + + CoCoLog.error(ERROR_CODE, msg); + } + // Undefined type of the name + } + +} diff --git a/src/main/java/org/nest/nestml/cocos/spl/BufferNotAssignable.java b/src/main/java/org/nest/nestml/cocos/spl/BufferNotAssignable.java new file mode 100644 index 000000000..0a6b802fc --- /dev/null +++ b/src/main/java/org/nest/nestml/cocos/spl/BufferNotAssignable.java @@ -0,0 +1,36 @@ +package org.nest.nestml.cocos.spl; + +import com.google.common.base.Preconditions; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; +import org.nest.spl._ast.ASTAssignment; +import org.nest.spl._cocos.SPLASTAssignmentCoCo; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.Optional; + +public class BufferNotAssignable implements SPLASTAssignmentCoCo { + + public static final String ERROR_CODE = "NESTML_SPL_BUFFER_NOT_ASSIGNABLE"; + + public void check(final ASTAssignment assignment) { + final Optional enclosingScope = assignment.getEnclosingScope(); + Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + assignment); + final String varName = Names.getQualifiedName(assignment.getVariableName().getParts()); + + Optional var = enclosingScope.get().resolve(varName, NESTMLVariableSymbol.KIND); + + if (!var.isPresent()) { + Log.warn("Cannot resolve the variable: " + varName + " . Thereofore, the coco is skipped."); + } + else if (var.get().getBlockType() == NESTMLVariableSymbol.BlockType.BUFFER) { + + final String msg = "Buffer '" + var.get().getName() + "' cannot be reassigned."; + CoCoLog.error(ERROR_CODE, msg, assignment.get_SourcePositionStart()); + } + + } + +} diff --git a/src/main/java/org/nest/nestml/nestml/_ast/ASTBodyDecorator.java b/src/main/java/org/nest/nestml/nestml/_ast/ASTBodyDecorator.java new file mode 100644 index 000000000..c5ba2dd47 --- /dev/null +++ b/src/main/java/org/nest/nestml/nestml/_ast/ASTBodyDecorator.java @@ -0,0 +1,243 @@ +package org.nest.nestml._ast; + +import com.google.common.collect.ImmutableList; +import org.nest.nestml._visitor.NESTMLInheritanceVisitor; +import org.nest.spl._ast.ASTOdeDeclaration; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.util.stream.Collectors.toList; + +/** + * Provides convenient functions to statically type interfaces astnodes resulting from the Body-grammar + * production. + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + */ +public class ASTBodyDecorator extends ASTBody { + + public static final String MISSING_DYNAMICS_ERROR = + "There is no dynamics in the NESTML model. This error should be catched by " + + "the context conditions.lease check you tool configuration and enable context conditions.!"; + + private final ASTBody body; + + public ASTBodyDecorator(ASTBody body) { + checkNotNull(body); + + this.body = body; + } + + public List getFunctions() { + List result = body.getBodyElements().stream() + .filter(be -> be instanceof ASTFunction) + .map(be -> (ASTFunction) be) + .collect(Collectors.toList()); + + return ImmutableList.copyOf(result); + } + + public List getDynamics() { + List result = body.getBodyElements().stream().filter(be -> be instanceof ASTDynamics) + .map(be -> (ASTDynamics) be).collect(Collectors.toList()); + + return ImmutableList.copyOf(result); + } + + public Optional getStateBlock() { + return body.getBodyElements().stream() + .filter(be -> be instanceof ASTVar_Block && ((ASTVar_Block) be).isState()) + .findFirst(); + } + + public Optional getParameterBlock() { + return body.getBodyElements().stream() + .filter(be -> be instanceof ASTVar_Block && ((ASTVar_Block) be).isParameter()) + .findFirst(); + } + + public List getStates() { + List result = new ArrayList(); + + body.getBodyElements().stream().filter(be -> be instanceof ASTVar_Block).forEach(be -> { + ASTVar_Block block = (ASTVar_Block) be; + if (block.isState()) { + for (ASTAliasDecl ad : block.getAliasDecls()) { + result.add(ad); + } + } + }); + + return ImmutableList.copyOf(result); + } + + @SuppressWarnings("unused") // used in templates + public List getAliasStates() { + return getStates().stream().filter(decl->decl.isAlias()).collect(toList()); + } + + @SuppressWarnings("unused") // used in templates + public List getNonAliasStates() { + + return getStates().stream().filter(v->!v.isAlias()).collect(toList()); + } + + public List getParameters() { + List result = new ArrayList(); + + body.getBodyElements().stream().filter(be -> be instanceof ASTVar_Block).forEach(be -> { + ASTVar_Block block = (ASTVar_Block) be; + if (block.isParameter()) { + result.addAll(block.getAliasDecls().stream().collect(Collectors.toList())); + } + }); + + return ImmutableList.copyOf(result); + } + + public List getAliasParameters() { + + return getParameters().stream().filter(decl -> decl.isAlias()).collect(toList()); + } + + @SuppressWarnings("unused") // used in templates + public List getNonAliasParameters() { + + return getParameters().stream().filter(decl -> !decl.isAlias()).collect(toList()); + } + + public List getInternals() { + List result = new ArrayList(); + + body.getBodyElements().stream().filter(be -> be instanceof ASTVar_Block).forEach(be -> { + ASTVar_Block block = (ASTVar_Block) be; + + if (block.isInternal()) { + for (ASTAliasDecl ad : block.getAliasDecls()) { + result.add(ad); + } + } + }); + + return ImmutableList.copyOf(result); + } + + public void addToInternalBlock(final ASTAliasDecl astAliasDecl) { + body.getBodyElements().stream().filter(variableBlock -> variableBlock instanceof ASTVar_Block).forEach(be -> { + + ASTVar_Block block = (ASTVar_Block) be; + + if (block.isInternal()) { + block.getAliasDecls().add(astAliasDecl); + } + + }); + + } + + private static class OdeDefinitionCollector implements NESTMLInheritanceVisitor { + + private Optional astOdeDeclaration = Optional.empty(); + + @Override + public void visit(final ASTOdeDeclaration astOdeDeclarationNode) { + this.astOdeDeclaration = Optional.of(astOdeDeclarationNode); + } + + public Optional collect(final ASTNESTMLNode astNestmlBase) { + astNestmlBase.accept(this); + return astOdeDeclaration; + } + + public Optional getAstOdeDeclaration() { + return astOdeDeclaration; + } + + } + + /** + * TODO rework: ODE is not a body element + * @return + */ + public Optional getOdeDefinition() { + // It is ensured through cocos that there is exactly one dynamics + final Optional astDynamics = findDynamics(); + checkState(astDynamics.isPresent(), MISSING_DYNAMICS_ERROR); + + final OdeDefinitionCollector odeDefinitionCollector = new OdeDefinitionCollector(); + Optional foundOdeDeclaration = odeDefinitionCollector.collect(astDynamics.get()); + + return foundOdeDeclaration; + } + + private Optional findDynamics() { + return body.getBodyElements().stream() + .filter(be -> be instanceof ASTDynamics) + .findFirst(); + } + + @SuppressWarnings("unchecked") + public List getAliasInternals() { + return getInternals().stream().filter(decl -> decl.isAlias()).collect(toList()); + } + + @SuppressWarnings("unchecked") + public List getNonAliasInternals() { + + return getInternals().stream().filter(decl -> !decl.isAlias()).collect(toList()); + } + + public List getUses() { + List result = body.getBodyElements().stream() + .filter(be -> be instanceof ASTUSE_Stmt) + .map(be -> (ASTUSE_Stmt) be) + .collect(Collectors.toList()); + + return ImmutableList.copyOf(result); + } + + public List getInputLines() { + List result = new ArrayList(); + + for (ASTBodyElement be : body.getBodyElements()) { + if (be instanceof ASTInput) { + ASTInput in = (ASTInput) be; + for (ASTInputLine inline : in.getInputLines()) { + result.add(inline); + } + } + } + + return ImmutableList.copyOf(result); + } + + public List getOutputs() { + List result = body.getBodyElements().stream() + .filter(be -> be instanceof ASTOutput) + .map(be -> (ASTOutput) be) + .collect(Collectors.toList()); + + return ImmutableList.copyOf(result); + } + + public List getStructure() { + List result = new ArrayList(); + + for (ASTBodyElement be : body.getBodyElements()) { + if (be instanceof ASTStructure) { + ASTStructure st = (ASTStructure) be; + for (ASTStructureLine stline : st.getStructureLines()) { + result.add(stline); + } + } + } + + return ImmutableList.copyOf(result); + } +} diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java new file mode 100644 index 000000000..811668f10 --- /dev/null +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java @@ -0,0 +1,431 @@ +package org.nest.nestml.prettyprinter; + +import de.monticore.prettyprint.IndentPrinter; +import de.monticore.types.prettyprint.TypesPrettyPrinterConcreteVisitor; +import de.monticore.types.types._ast.ASTQualifiedName; +import de.monticore.types.types._ast.ASTQualifiedNameList; +import de.se_rwth.commons.Names; +import org.nest.nestml._ast.*; +import org.nest.nestml._visitor.NESTMLVisitor; +import org.nest.spl.prettyprinter.ExpressionsPrettyPrinter; +import org.nest.spl.prettyprinter.SPLPrettyPrinter; +import org.nest.spl.prettyprinter.SPLPrettyPrinterFactory; +import org.nest.spl._ast.*; +import org.nest.utils.PrettyPrinterBase; + +import java.util.Optional; + +/** + * Provides convenient functions to statically type interfaces astnodes resulting from the Body-grammar + * production. + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + */ +public class NESTMLPrettyPrinter extends PrettyPrinterBase implements NESTMLVisitor { + + private final ExpressionsPrettyPrinter expressionsPrettyPrinter; + + protected NESTMLPrettyPrinter(final ExpressionsPrettyPrinter expressionsPrettyPrinter) { + this.expressionsPrettyPrinter = expressionsPrettyPrinter; + } + + + /** + * NESTMLCompilationUnit = "package" packageName:QualifiedName + * BLOCK_OPEN + * (Import | NEWLINE)* + * (Neuron | Component | SL_COMMENT | NEWLINE)* + * BLOCK_CLOSE (SL_COMMENT | NEWLINE)*; + */ + @Override + public void visit(final ASTNESTMLCompilationUnit node) { + print("package "); + println(Names.getQualifiedName(node.getPackageName().getParts()) + BLOCK_OPEN); + indent(); + } + + @Override + public void endVisit(final ASTNESTMLCompilationUnit node) { + unindent(); + println("end"); + } + + /** + * Grammar: + * Import = "import" QualifiedName ([star:".*"])? (";")?; + */ + @Override + public void visit(final ASTImport astImport) { + final String importName = Names.getQualifiedName(astImport.getQualifiedName().getParts()); + print("import " + importName); + if (astImport.isStar()) { + print(".*"); + } + println(); + } + + /** + * Grammar: + * Neuron = "neuron" Name Body; + */ + @Override + public void visit(final ASTNeuron astNeuron) { + print("neuron " + astNeuron.getName()); + } + + /** + * Grammar: + * Neuron = "neuron" Name Body; + */ + @Override + public void visit(final ASTComponent astComponent) { + print("component " + astComponent.getName()); + } + + /** + * Grammar: + * Body = BLOCK_OPEN ( SL_COMMENT | NEWLINE | BodyElement)* BLOCK_CLOSE; + */ + @Override + public void visit(final ASTBody astBody) { + println(BLOCK_OPEN); + indent(); + } + + /** + * Grammar: + * Body = BLOCK_OPEN ( SL_COMMENT | NEWLINE | BodyElement)* BLOCK_CLOSE; + */ + @Override + public void endVisit(final ASTBody astBody) { + unindent(); + println(BLOCK_CLOSE); + } + + /** + * USE_Stmt implements BodyElement = "use" name:QualifiedName "as" alias:Name; + */ + @Override + public void visit(final ASTUSE_Stmt astUseStmt) { + final String referencedName = Names.getQualifiedName(astUseStmt.getName().getParts()); + println("use " + referencedName + " as " + astUseStmt.getAlias()); + } + + /** + * Var_Block implements BodyElement = + * ([state:"state"]|[para:"parameter"]|[internal:"internal"]) + * BLOCK_OPEN + * (AliasDecl (";" AliasDecl)* (";")? + * | SL_COMMENT | NEWLINE)* + * BLOCK_CLOSE; + */ + @Override + public void visit(final ASTVar_Block astVarBlock) { + printVariableBlockHeader(astVarBlock); + indent(); + } + + private void printVariableBlockHeader(final ASTVar_Block astVarBlock) { + if (astVarBlock.isState()) { + println("state" + BLOCK_OPEN); + } + else if (astVarBlock.isInternal()) { + println("internal" + BLOCK_OPEN); + } + else if (astVarBlock.isParameter()) { + println("parameter" + BLOCK_OPEN); + } + + } + + @Override + public void endVisit(final ASTVar_Block astVarBlock) { + unindent(); + println(BLOCK_CLOSE); + } + + /** + * AliasDecl = ([hide:"-"])? ([alias:"alias"])? Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + */ + @Override + public void visit(final ASTAliasDecl astAliasDecl) { + printAliasPrefix(astAliasDecl); + printDeclarationStatement(astAliasDecl); + printInvariants(astAliasDecl); + + } + + private void printAliasPrefix(ASTAliasDecl astAliasDecl) { + if (astAliasDecl.isHide()) { + print("- "); + } + if (astAliasDecl.isAlias()) { + print("alias "); + } + } + + private void printDeclarationStatement(ASTAliasDecl astAliasDecl) { + final SPLPrettyPrinter splPrettyPrinter = SPLPrettyPrinterFactory.createDefaultPrettyPrinter(getIndentionLevel()); + splPrettyPrinter.printDeclaration(astAliasDecl.getDeclaration()); // TODO refactor as soon a the visitor is + // generated + print(splPrettyPrinter.getResult()); + } + + + private void printInvariants(final ASTAliasDecl astAliasDecl) { + if (astAliasDecl.getInvariants().size() > 0) { + print("[ "); + for (int invariantIndex = 0; invariantIndex < astAliasDecl.getInvariants().size(); ++invariantIndex) { + final ASTExpr astInvariant = astAliasDecl.getInvariants().get(invariantIndex); + print(expressionsPrettyPrinter.print(astInvariant)); + boolean isLastInvariant = (invariantIndex + 1) == astAliasDecl.getInvariants().size(); + if (!isLastInvariant) { + print("; "); + } + + } + + println(" ]"); + + } + } + + /** + * Grammar: + * AliasDecl = ([hide:"-"])? ([alias:"alias"])? Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + */ + @Override + public void endVisit(final ASTAliasDecl astAliasDecl) { + println(); + } + + /** + * Grammar: + * Input implements BodyElement = "input" + * BLOCK_OPEN + * (InputLine | SL_COMMENT | NEWLINE)* + * BLOCK_CLOSE; + */ + @Override + public void visit(final ASTInput astInput) { + println("input" + BLOCK_OPEN); + indent(); + } + + /** + * Grammar: + * Input implements BodyElement = "input" + * BLOCK_OPEN + * (InputLine | SL_COMMENT | NEWLINE)* + * BLOCK_CLOSE; + */ + @Override + public void endVisit(final ASTInput astInput) { + unindent(); + println(BLOCK_CLOSE); + } + + /** + * grammar + * InputLine = Name "<-" InputType* ([spike:"spike"]|[current:"current"]); + * InputType = (["inhibitory"]|["excitatory"]); + */ + @Override + public void visit(final ASTInputLine astInputLine) { + print(astInputLine.getName() + " <- "); + printInputTypes(astInputLine.getInputTypes()); + printOutputType(astInputLine); + println(); + } + + private void printInputTypes(final ASTInputTypeList inputTypes) { + for (ASTInputType inputType:inputTypes) { + if (inputType.isInhibitory()) { + print("inhibitory "); + } + else { + print("excitatory "); + } + + } + + } + + private void printOutputType(final ASTInputLine astInputLine) { + if (astInputLine.isSpike()) { + print("spike"); + } + else { + print("current"); + } + + } + + /** + * Output implements BodyElement = + * "output" BLOCK_OPEN ([spike:"spike"]|[current:"current"]) ; + */ + @Override + public void visit(final ASTOutput astOutput) { + print("output: "); + if (astOutput.isSpike()) { + print("spike"); + } + else { + print("current"); + } + + println(); + } + + /** + * Grammar: + * Structure implements BodyElement = "structure" + * BLOCK_OPEN + * (StructureLine | SL_COMMENT | NEWLINE)* + * BLOCK_CLOSE; + */ + @Override + public void visit(final ASTStructure astStructure) { + println("structure" + BLOCK_OPEN); + indent(); + } + + @Override + public void endVisit(final ASTStructure astStructure) { + unindent(); + println(BLOCK_CLOSE); + } + + /** + * StructureLine = compartments:QualifiedName ("-" compartments:QualifiedName)*; + */ + @Override + public void visit(final ASTStructureLine astStructureLine) { + final ASTQualifiedNameList compartments = astStructureLine.getCompartments(); + for (int curCompartmentsIndex = 0; curCompartmentsIndex < compartments.size(); ++ curCompartmentsIndex) { + final ASTQualifiedName compartmentName = compartments.get(curCompartmentsIndex); + boolean isLastCompartment = (curCompartmentsIndex + 1) == compartments.size(); + print(Names.getQualifiedName(compartmentName.getParts()) + " "); + if (!isLastCompartment) { + print("- "); + } + + } + + } + + /** + * Function implements BodyElement = + "function" Name "(" Parameters? ")" (returnType:QualifiedName | PrimitiveType)? + BLOCK_OPEN + Block + BLOCK_CLOSE; + */ + @Override + public void visit(final ASTFunction astFunction) { + print("function " + astFunction.getName()); + printParameters(astFunction.getParameters()); + printOptionalReturnValue(astFunction); + println(BLOCK_OPEN); + indent(); + printSplBlock(astFunction.getBlock()); + unindent(); + println(BLOCK_CLOSE); + + } + + private void printParameters(Optional functionParameters) { + print("("); + if (functionParameters.isPresent()) { + final ASTParameterList astParameters = functionParameters.get().getParameters(); + for (int curParameterIndex = 0; curParameterIndex < astParameters.size(); ++curParameterIndex) { + boolean isLastParameter = (curParameterIndex + 1) == astParameters.size(); + final ASTParameter curParameter = astParameters.get(curParameterIndex); + print(curParameter.getName() + " " + Names.getQualifiedName(curParameter.getType().getParts())); + if (!isLastParameter) { + print(", "); + } + + } + + } + print(")"); + } + + private void printOptionalReturnValue(final ASTFunction astFunction) { + if (astFunction.getReturnType().isPresent()) { + print(Names.getQualifiedName(astFunction.getReturnType().get().getParts())); + } + else if (astFunction.getPrimitiveType().isPresent()) { + print(createPrettyPrinterForTypes().prettyprint(astFunction.getPrimitiveType().get())); + } + + } + + + private void printSplBlock(final ASTBlock astBlock) { + final SPLPrettyPrinter splPrettyPrinter = SPLPrettyPrinterFactory.createDefaultPrettyPrinter(getIndentionLevel()); + + astBlock.accept(splPrettyPrinter); + + print(splPrettyPrinter.getResult()); + } + + /** + * + * Dynamics implements BodyElement = "dynamics" (MinDelay | TimeStep) + * "(" Parameters? ")" + * BLOCK_OPEN // Todo remove me. It is not the way for modular extension + * Block + * BLOCK_CLOSE; + * MinDelay = "minDelay"; + * TimeStep = "timestep"; + */ + @Override + public void visit(final ASTDynamics astDynamics) { + printDynamicsName(astDynamics); + printParameters(astDynamics.getParameters()); + printDynamicsBody(astDynamics); + } + + private void printDynamicsName(ASTDynamics astDynamics) { + print("dynamics "); + if (astDynamics.getMinDelay().isPresent()) { + print("minDelay"); + } + else { + print("timestep"); + } + } + + private void printDynamicsBody(ASTDynamics astDynamics) { + println(BLOCK_OPEN); + indent(); + printSplBlock(astDynamics.getBlock()); + unindent(); + println(); + println(BLOCK_CLOSE); + } + + @Override + public void visit(ASTEq node) { + + } + + @Override + public void visit(ASTODE node) { + + } + + @Override + public void visit(ASTOdeDeclaration node) { + + } + + private TypesPrettyPrinterConcreteVisitor createPrettyPrinterForTypes() { + final IndentPrinter printer = new IndentPrinter(); + return new TypesPrettyPrinterConcreteVisitor(printer); + } +} diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterFactory.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterFactory.java new file mode 100644 index 000000000..af78cb6d4 --- /dev/null +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterFactory.java @@ -0,0 +1,13 @@ +package org.nest.nestml.prettyprinter; + +import org.nest.spl.prettyprinter.ExpressionsPrettyPrinter; + +/** + * Created by user on 09.06.15. + */ +public class NESTMLPrettyPrinterFactory { + public static NESTMLPrettyPrinter createNESTMLPrettyPrinter() { + return new NESTMLPrettyPrinter(new ExpressionsPrettyPrinter()); + } + +} diff --git a/src/main/java/org/nest/ode/ModelConverter.java b/src/main/java/org/nest/ode/ModelConverter.java new file mode 100644 index 000000000..328246632 --- /dev/null +++ b/src/main/java/org/nest/ode/ModelConverter.java @@ -0,0 +1,79 @@ +package org.nest.ode; + +import org.apache.commons.io.FileUtils; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml.prettyprinter.NESTMLPrettyPrinter; +import org.nest.nestml.prettyprinter.NESTMLPrettyPrinterFactory; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Optional; + +/** + * Created by user on 12.06.15. + */ +public class ModelConverter { + + public static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory.createNESTMLCompilationUnitMCParser(); + + final Sympy2NESTMLConverter sympy2NESTMLConverter = new Sympy2NESTMLConverter(); + + public void addPropagatorMatrixAndPrint( + final String pathToModel, + final String pathToMatrix, + final String outputPath) { + final Optional root = parseModel(pathToModel); + + final List propagatorMatrix = sympy2NESTMLConverter.convertMatrixFile2NESTML(pathToMatrix); + + addVariablesToInternalBlock(root, propagatorMatrix); + + final NESTMLScopeCreator nestmlScopeCreator = new NESTMLScopeCreator( + TEST_MODEL_PATH, typesFactory); + nestmlScopeCreator.runSymbolTableCreator(root.get()); + printModelToFile(root.get(), outputPath); + } + + private void printModelToFile( + final ASTNESTMLCompilationUnit astNestmlCompilationUnit, + final String outputPath) { + final NESTMLPrettyPrinter prettyPrinter = NESTMLPrettyPrinterFactory.createNESTMLPrettyPrinter(); + astNestmlCompilationUnit.accept(prettyPrinter); + + final File prettyPrintedModelFile = new File(outputPath); + try { + FileUtils.write(prettyPrintedModelFile, prettyPrinter.getResult()); + } + catch (IOException e) { + throw new RuntimeException("Cannot write the prettyprinted model to the file: " + outputPath, e); + } + } + + private void addVariablesToInternalBlock(Optional root, + List propagatorMatrix) { + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(root.get().getNeurons().get(0).getBody()); + propagatorMatrix.forEach(astBodyDecorator::addToInternalBlock); + } + + private Optional parseModel(String pathToModel) { + try { + return p.parse(pathToModel); + } + catch (final IOException e) { + throw new RuntimeException("Cannot parse the NESTML model: " + pathToModel, e); + } + + } + +} diff --git a/src/main/java/org/nest/ode/ODE2SympyCodeGenerator.java b/src/main/java/org/nest/ode/ODE2SympyCodeGenerator.java new file mode 100644 index 000000000..3eb3c287b --- /dev/null +++ b/src/main/java/org/nest/ode/ODE2SympyCodeGenerator.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.ode; + +import com.google.common.collect.Lists; +import de.monticore.generating.GeneratorEngine; +import de.monticore.generating.GeneratorSetup; +import de.monticore.generating.templateengine.GlobalExtensionManagement; +import org.nest.spl.prettyprinter.ExpressionsPrettyPrinter; +import org.nest.spl._ast.ASTOdeDeclaration; +import org.nest.utils.ASTNodes; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Wrapps the logic how to generateSympyODEAnalyzer C++ implementation from a NESTML model? + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since 0.0.1 + */ +public class ODE2SympyCodeGenerator { + + public static void generateSympyODEAnalyzer(GlobalExtensionManagement glex, + ASTOdeDeclaration odeDeclaration, + File outputDirectory, + String neuronName) { + final GeneratorSetup setup = new GeneratorSetup(outputDirectory); + + final ExpressionsPrettyPrinter expressionsPrettyPrinter = new ExpressionsPrettyPrinter(); + glex.setGlobalValue("ode", odeDeclaration.getODEs()); + glex.setGlobalValue("eq", odeDeclaration.getEq()); + glex.setGlobalValue("expressionsPrettyPrinter", expressionsPrettyPrinter); + expressionsPrettyPrinter.print(odeDeclaration.getODEs().getRhs()); + + setup.setGlex(glex); + setup.setTracing(false); // python comments are not java comments + + final GeneratorEngine generator = new GeneratorEngine(setup); + + final Path solverFilePath = Paths.get(outputDirectory.getPath(), neuronName + "Solver.py"); + + // TODO: filter out E + final List variables = filterConstantVariables(ASTNodes.getVariablesNamesFromAst(odeDeclaration)); + glex.setGlobalValue("variables", variables); + + // TODO: how do I find out the call was successful? + generator.generate( + "org.nest.ode.SympySolver", + solverFilePath, + odeDeclaration); + } + + /** + * Filters mathematical constants like Pi, E, ... + */ + private static List filterConstantVariables(final List variablesNames) { + final List result = Lists.newArrayList(); + result.addAll(variablesNames.stream().filter(variable -> !variable.equals("E")) + .collect(Collectors.toList())); + + return result; + } + +} + diff --git a/src/main/java/org/nest/ode/Sympy2NESTMLConverter.java b/src/main/java/org/nest/ode/Sympy2NESTMLConverter.java new file mode 100644 index 000000000..cab5d7d6a --- /dev/null +++ b/src/main/java/org/nest/ode/Sympy2NESTMLConverter.java @@ -0,0 +1,44 @@ +package org.nest.ode; + +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._ast.NESTMLNodeFactory; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.spl._ast.SPLNodeFactory; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Created by user on 20.05.15. + */ +public class Sympy2NESTMLConverter { + + private final SympyOutputReader sympyOutputReader; + + private final SympyLine2ASTConverter line2ASTConverter; + + public Sympy2NESTMLConverter() { + this.sympyOutputReader = new SympyOutputReader(); + this.line2ASTConverter = new SympyLine2ASTConverter(); + } + + public List convertMatrixFile2NESTML(final String filename) { + final List linesAsStrings = sympyOutputReader.readMatrixElementsFromFile(filename); + final List propagationElements + = linesAsStrings.stream().map(line2ASTConverter::convert).collect(Collectors.toList()); + + return propagationElements.stream().map(this::convertToAlias).collect(Collectors.toList()); + } + + private ASTAliasDecl convertToAlias(ASTDeclaration astDeclaration) { + final ASTAliasDecl astAliasDecl = NESTMLNodeFactory.createASTAliasDecl(); + + astAliasDecl.setDeclaration(astDeclaration); + astAliasDecl.setAlias(false); + astAliasDecl.setHide(false); + astAliasDecl.setInvariants(SPLNodeFactory.createASTExprList()); + + return astAliasDecl; + } + +} diff --git a/src/main/java/org/nest/ode/SympyLine2ASTConverter.java b/src/main/java/org/nest/ode/SympyLine2ASTConverter.java new file mode 100644 index 000000000..b3afb6343 --- /dev/null +++ b/src/main/java/org/nest/ode/SympyLine2ASTConverter.java @@ -0,0 +1,30 @@ +package org.nest.ode; + +import de.monticore.antlr4.MCConcreteParser; +import org.nest.nestml._parser.DeclarationMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.spl._ast.ASTDeclaration; + +import java.io.IOException; +import java.io.StringReader; + +public class SympyLine2ASTConverter { + private final DeclarationMCParser parser; + + public SympyLine2ASTConverter() { + this.parser = NESTMLParserFactory.createDeclarationMCParser(); + this.parser.setParserTarget(MCConcreteParser.ParserExecution.EOF); + } + + public ASTDeclaration convert(String sympyExpression) { + + try { + return parser.parse(new StringReader(sympyExpression)).get(); + } + catch (IOException e) { + throw new RuntimeException("Cannot parse the line: " + sympyExpression); + } + + } + +} diff --git a/src/main/java/org/nest/ode/SympyOutputReader.java b/src/main/java/org/nest/ode/SympyOutputReader.java new file mode 100644 index 000000000..04a0322d8 --- /dev/null +++ b/src/main/java/org/nest/ode/SympyOutputReader.java @@ -0,0 +1,30 @@ +package org.nest.ode; + +import com.google.common.collect.Lists; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Created by user on 20.05.15. + */ +public class SympyOutputReader { + + public List readMatrixElementsFromFile(final String filename) { + List matrixElements; + try { + matrixElements = Files.lines(new File(filename).toPath()) + .filter(line -> !line.isEmpty()) + .collect(Collectors.toList()); + return matrixElements; + } + catch (IOException e) { + throw new RuntimeException("Cannot find or read the file with propagator matrix.", e); + } + + } + +} diff --git a/src/main/java/org/nest/spl/_symboltable/SPLLanguage.java b/src/main/java/org/nest/spl/_symboltable/SPLLanguage.java new file mode 100644 index 000000000..9f923a798 --- /dev/null +++ b/src/main/java/org/nest/spl/_symboltable/SPLLanguage.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl._symboltable; + +import de.monticore.modelloader.ModelingLanguageModelLoader; +import de.monticore.symboltable.MutableScope; +import de.monticore.symboltable.ResolverConfiguration; +import de.monticore.symboltable.resolving.CommonResolvingFilter; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl.symboltable.*; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.Optional; + +/** + * Frontend for the Simple Programming Language (SPL) + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class SPLLanguage extends org.nest.spl._symboltable.SPLLanguageTOP { + + public static final String FILE_ENDING = "simple"; + + final PredefinedTypesFactory typesFactory; + + /** + * {@inheritDoc} + */ + public SPLLanguage(final PredefinedTypesFactory typesFactory) { + super("SPL Language", FILE_ENDING); // TODO what is the top level in this case? + this.typesFactory = typesFactory; + } + + /** + * {@inheritDoc} + */ + @Override + public Optional getSymbolTableCreator(ResolverConfiguration resolverConfiguration, MutableScope enclosingScope) { + return Optional.of(new CommonSPLSymbolTableCreator(resolverConfiguration, enclosingScope, typesFactory)); + } + + @Override protected void initResolvingFilters() { + super.initResolvingFilters(); + addResolver(CommonResolvingFilter.create(NESTMLTypeSymbol.class, NESTMLTypeSymbol.KIND)); + addResolver(CommonResolvingFilter.create(NESTMLVariableSymbol.class, NESTMLVariableSymbol.KIND)); + addResolver(CommonResolvingFilter.create(NESTMLMethodSymbol.class, NESTMLMethodSymbol.KIND)); + } + + @Override protected ModelingLanguageModelLoader provideModelLoader() { + return new org.nest.spl.symboltable.SPLModelLoader(this); + } +} diff --git a/src/main/java/org/nest/spl/cocos/CheckMultipleSignsBeforeFactor.java b/src/main/java/org/nest/spl/cocos/CheckMultipleSignsBeforeFactor.java new file mode 100644 index 000000000..8c1078062 --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/CheckMultipleSignsBeforeFactor.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import de.monticore.ast.ASTCList; +import de.monticore.ast.ASTCNode; +import de.monticore.cocos.CoCoLog; +import org.nest.spl._ast.ASTBlock; +import org.nest.spl._ast.ASTExpr; +import org.nest.spl._cocos.SPLASTBlockCoCo; +import org.nest.spl._cocos.SPLASTExprCoCo; +import org.nest.utils.ASTNodes; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Forbids expressions like: ---a + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class CheckMultipleSignsBeforeFactor implements SPLASTExprCoCo, SPLASTBlockCoCo { + + public static final String ERROR_CODE = "MULTIPLE_SIGNS_BEFORE_FACTOR"; + + private static final String ERROR_MSG_FORMAT = + "Factor has too many signs in front of it: %s."; + + private Optional root = Optional.empty(); + + @Override + public void check(ASTBlock node) { + //root = Optional.of(node); + } + + // TODO reactivate this condition later + public void check(ASTExpr factor) { + //checkState(root.isPresent()); + /*Optional parentOfFactor = ASTNodes.getParent(factor, root.get()); + checkState(parentOfFactor.isPresent()); + + + if (!(parentOfFactor.get() instanceof ASTExpr) && + !(parentOfFactor.get() instanceof ASTCList)) { // top-level factor + List signs = Lists.newArrayList(); + int plus = 0, minus = 0, tilde = 0; + getSigns(factor, signs); + for (Sign sign : signs) { + switch (sign) { + case PLUS: + ++plus; + break; + case MINUS: + ++minus; + break; + case TILDE: + ++tilde; + break; + default: + break; + } + } + if (plus > 1 || minus > 1 || tilde > 1 || (plus > 0 && minus > 0)) { + CoCoLog.error(ERROR_CODE, + String.format(ERROR_MSG_FORMAT, Joiner.on("").join(signs)), // TODO must be possible to compute information about signs + factor.get_SourcePositionStart()); + } + }*/ + + } + + /** + * Recursively insert signes into the list s. + */ + private List getSigns(ASTExpr f, List s) { + if (f.getTerm().isPresent()) { + if (f.isUnaryPlus()) { + s.add(Sign.PLUS); + } + if (f.isUnaryMinus()) { + s.add(Sign.MINUS); + } + if (f.isUnaryTilde()) { + s.add(Sign.TILDE); + } + + return getSigns(f.getTerm().get(), s); + } + else { + return s; + } + + } + + enum Sign { + PLUS("+"), MINUS("-"), TILDE("~"); + + public final String sign; + + Sign(String s) { + this.sign = s; + } + + public String toString() { + return this.sign; + } + } + +} diff --git a/src/main/java/org/nest/spl/cocos/CodeAfterReturn.java b/src/main/java/org/nest/spl/cocos/CodeAfterReturn.java new file mode 100644 index 000000000..a6df67da8 --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/CodeAfterReturn.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import de.monticore.ast.ASTNode; +import de.monticore.cocos.CoCoLog; +import de.se_rwth.commons.SourcePosition; +import org.nest.spl._ast.*; +import org.nest.spl._cocos.SPLASTBlockCoCo; + +/** + * Checks that that there is no statements after the return statement. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class CodeAfterReturn implements SPLASTBlockCoCo { + public static final String ERROR_CODE = "SPL_CODE_AFTER_RETURN"; + + @Override + public void check(ASTBlock block) { + // && TODO isToplevelBlock(block) + if (!block.getStmts().isEmpty()) { + isReturnBlock(block); + } + + } + + protected ASTNode isReturnBlock(ASTBlock block) { + ASTNode r = null; + + // Block = Stmt* + for (ASTStmt stmt : block.getStmts()) { + // error, if already found return and have a next stmt + if (r != null) { + if (r instanceof ASTReturnStmt) { + addReport( + "Code after the a return statement is not reachable!", + r.get_SourcePositionStart()); + } else if (r instanceof ASTIF_Stmt) { + addReport( + "Code after the a returning if-statement is not reachable!", + r.get_SourcePositionStart()); + } else if (r instanceof ASTFOR_Stmt) { + addReport( + "Code after the a returning for-statement is not reachable!", + r.get_SourcePositionStart()); + } else if (r instanceof ASTWHILE_Stmt) { + addReport( + "Code after the a returning while-statement is not reachable!", + r.get_SourcePositionStart()); + } + + return r; + } + // Stmt = Simple_Stmt | Compound_Stmt; + if (stmt.getSimple_Stmt().isPresent() && + stmt.getSimple_Stmt().get().getSmall_Stmts().size() > 0) { + // Simple_Stmt = Small_Stmt (Small_Stmt)* (";")?; + for (ASTSmall_Stmt small : stmt.getSimple_Stmt().get().getSmall_Stmts()) { + // error, if return found in line and new small found + if (r != null) { + addReport("Code after a return statement is not reachable!", + r.get_SourcePositionStart()); + return r; + } + // Small_Stmt = (DottedName "=") => Assignment | + // FunctionCall | Declaration | ReturnStmt; + if (small.getReturnStmt().isPresent()) { + // return found! + r = small.getReturnStmt().get(); + } + } + } + else if (stmt.getCompound_Stmt().isPresent()) { + r = isReturnCompound(stmt.getCompound_Stmt().get()); + } + } + return r; + } + + private ASTNode isReturnCompound(ASTCompound_Stmt compound) { + // Compound_Stmt = IF_Stmt | FOR_Stmt | WHILE_Stmt; + if (compound.getIF_Stmt().isPresent()) { + return isIFReturn(compound.getIF_Stmt().get()); + } + else if (compound.getFOR_Stmt().isPresent() + && isReturnBlock(compound.getFOR_Stmt().get().getBlock()) != null) { + return compound.getFOR_Stmt().get(); + } + else if (compound.getWHILE_Stmt().isPresent() + && isReturnBlock(compound.getWHILE_Stmt().get().getBlock()) != null) { + return compound.getWHILE_Stmt().get(); + } + + return null; + } + + private ASTNode isIFReturn(ASTIF_Stmt ifStmt) { + // 1) need an else block + if (!ifStmt.getELSE_Clause().isPresent()) { + return null; + } + + // 2) all if/elif/else blocks need to be returning + boolean allReturn = true; + allReturn = allReturn && isReturnBlock(ifStmt.getIF_Clause().getBlock()) != null; + // TODO ifStmt.getELSE_Clause() is an optional, handle it correctly + allReturn = allReturn + && isReturnBlock(ifStmt.getELSE_Clause().get().getBlock()) != null; + for (ASTELIF_Clause elif : ifStmt.getELIF_Clauses()) { + allReturn = allReturn && isReturnBlock(elif.getBlock()) != null; + } + return allReturn ? ifStmt : null; + } + + private void addReport(String s, SourcePosition sourcePositionStart) { + CoCoLog.error(ERROR_CODE, s, sourcePositionStart); + } +} diff --git a/src/main/java/org/nest/spl/cocos/FunctionDoesntExist.java b/src/main/java/org/nest/spl/cocos/FunctionDoesntExist.java new file mode 100644 index 000000000..98989a24f --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/FunctionDoesntExist.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.spl._ast.ASTExpr; +import org.nest.spl._ast.ASTFunctionCall; +import org.nest.spl._cocos.SPLASTFunctionCallCoCo; +import org.nest.spl.symboltable.typechecking.ExpressionTypeCalculator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.utils.NESTMLSymbols; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Checks that methods are defined and used with correct types. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class FunctionDoesntExist implements SPLASTFunctionCallCoCo { + public static final String ERROR_CODE = "SPL_FUNCTION_DOESNT_EXIST"; + private static final String ERROR_MSG_FORMAT = "The function '%s' is not defined"; + private final PredefinedTypesFactory predefinedTypesFactory; + + public FunctionDoesntExist(PredefinedTypesFactory predefinedTypesFactory) { + this.predefinedTypesFactory = predefinedTypesFactory; + } + + @Override + public void check(final ASTFunctionCall funcall) { + checkArgument(funcall.getEnclosingScope().isPresent(), "No scope assigned. run symboltable creator."); + final Scope scope = funcall.getEnclosingScope().get(); + + final String methodName = Names.getQualifiedName(funcall.getQualifiedName().getParts()); + + final ExpressionTypeCalculator expressionTypeCalculator = new ExpressionTypeCalculator( + predefinedTypesFactory); + + final List argTypeNames = Lists.newArrayList(); + + for (int i = 0; i < funcall.getArgList().getArgs().size(); ++i) { + final ASTExpr arg = funcall.getArgList().getArgs().get(i); + final NESTMLTypeSymbol argType = expressionTypeCalculator.computeType(arg); + argTypeNames.add(argType.getName()); + } + + final Optional method + = NESTMLSymbols.resolveMethod(scope, methodName, argTypeNames); + + if (!method.isPresent()) { + CoCoLog.error( + ERROR_CODE, + String.format(ERROR_MSG_FORMAT, methodName) + + " with the signature '" + Joiner.on(",").join(argTypeNames)+ "'", + funcall.get_SourcePositionStart()); + } + + } + +} diff --git a/src/main/java/org/nest/spl/cocos/IllegalExpression.java b/src/main/java/org/nest/spl/cocos/IllegalExpression.java new file mode 100644 index 000000000..5710d8487 --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/IllegalExpression.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import com.google.common.base.Preconditions; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.monticore.symboltable.Symbol; +import de.se_rwth.commons.Names; +import org.nest.spl._ast.*; +import org.nest.spl._cocos.*; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; +import org.nest.spl.symboltable.typechecking.ExpressionTypeCalculator; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Check that the type of the loop variable is an integer. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class IllegalExpression implements + SPLASTIF_ClauseCoCo, + SPLASTFOR_StmtCoCo, + SPLASTWHILE_StmtCoCo, + SPLASTAssignmentCoCo, + SPLASTDeclarationCoCo, + SPLASTELIF_ClauseCoCo + +{ + public static final String ERROR_CODE = "SPL_ILLEGAL_EXPRESSION"; + + private final ExpressionTypeCalculator typeCalculator; + + private final PredefinedTypesFactory predefinedTypesFactory; + + public IllegalExpression(final PredefinedTypesFactory predefinedTypesFactory) { + typeCalculator = new ExpressionTypeCalculator(predefinedTypesFactory); + this.predefinedTypesFactory = predefinedTypesFactory; + } + + + @Override + public void check(final ASTAssignment node) { + // TODO + } + + @Override + public void check(final ASTDeclaration node) { + checkArgument(node.getEnclosingScope().isPresent(), "No scope assigned. Please, run symboltable creator."); + final Scope scope = node.getEnclosingScope().get(); + + // compute the symbol of the var from the declaration. + // take an arbitrary var since the variables in the declaration + // share the same type + + if (node.getExpr().isPresent()) { + final String varNameFromDeclaration = node.getVars().get(0); + final String declarationTypeName = getDeclarationTypeName(node); + final Optional varType = scope.resolve(varNameFromDeclaration, + NESTMLVariableSymbol.KIND); + Preconditions.checkState(varType.isPresent(), "Cannot resolve the type of the variable: " + varNameFromDeclaration); + + NESTMLTypeSymbol initializerExpressionType; + + NESTMLTypeSymbol variableDeclarationType; + try { + initializerExpressionType = typeCalculator.computeType(node.getExpr().get()); + variableDeclarationType = predefinedTypesFactory.getType(declarationTypeName); + // TODO write a helper get assignable + if (!isCompatible(variableDeclarationType, initializerExpressionType)) { + final String msg = "Cannot initialize variable with an expression of type: " + + varNameFromDeclaration + " with the type " + initializerExpressionType + + node.get_SourcePositionStart(); + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionStart()); + } + } + catch (RuntimeException e) { + final String msg = "Cannot determine the type of the initializer expression at " + + node.get_SourcePositionStart() + " Reason: " + e.getMessage(); + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionStart()); + } + + } + + } + + + + private String getDeclarationTypeName(final ASTDeclaration declaration) { + if (declaration.getPrimitiveType().isPresent()) { + return "boolean"; + } + if (declaration.getType().isPresent()) { + return Names.getQualifiedName(declaration.getType().get().getParts()); + } + throw new RuntimeException("Declaration has not type! Impossible through the grammar."); + } + + @Override + public void check(final ASTELIF_Clause node) { + try { + if (!typeCalculator.computeType(node.getExpr()).equals(predefinedTypesFactory.getBooleanType())) { + final String msg = "Cannot use non boolean expression in an if statement " + + "@" + node.get_SourcePositionStart(); + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionStart()); + } + } + catch (RuntimeException e) { + final String msg = "Cannot initialize variable with an expression of type: " + + "@" + node.get_SourcePositionStart(); + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionStart()); + } + } + + @Override + public void check(final ASTFOR_Stmt node) { + // TODO + } + + @Override + public void check(final ASTIF_Clause node) { + try { + if (!typeCalculator.computeType(node.getExpr()).equals(predefinedTypesFactory.getBooleanType())) { + final String msg = "Cannot use non boolean expression in an if statement " + + "@" + node.get_SourcePositionStart(); + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionStart()); + } + } + catch (RuntimeException e) { + final String msg = "Cannot use the expression in the if clause. " + e.getMessage() + + "@" + node.get_SourcePositionStart(); + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionStart()); + } + + } + + @Override + public void check(final ASTWHILE_Stmt node) { + try { + if (!typeCalculator.computeType(node.getExpr()).equals(predefinedTypesFactory.getBooleanType())) { + final String msg = "Cannot use non boolean expression in a while statement " + + "@" + node.get_SourcePositionStart(); + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionStart()); + } + } + catch (RuntimeException e) { + final String msg = "Cannot initialize variable with an expression of type: " + + "@" + node.get_SourcePositionStart(); + CoCoLog.error(ERROR_CODE, msg, node.get_SourcePositionStart()); + } + + + } + + private boolean isCompatible(final NESTMLTypeSymbol lhsType, final NESTMLTypeSymbol rhsType) { + if (lhsType.equals(rhsType)) { + return true; + } + else if (lhsType.equals(predefinedTypesFactory.getRealType()) && + rhsType.equals(predefinedTypesFactory.getIntegerType())) { + return true; + } + else if (lhsType.equals(predefinedTypesFactory.getIntegerType()) && rhsType.getType().equals(NESTMLTypeSymbol.Type.UNIT) || + rhsType.equals(predefinedTypesFactory.getIntegerType()) && lhsType.getType().equals(NESTMLTypeSymbol.Type.UNIT)) { + return true; + } + else if (lhsType.equals(predefinedTypesFactory.getRealType()) && rhsType.getType().equals(NESTMLTypeSymbol.Type.UNIT) || + rhsType.equals(predefinedTypesFactory.getRealType()) && lhsType.getType().equals(NESTMLTypeSymbol.Type.UNIT)) { + return true; + } + + return false; + } + +} diff --git a/src/main/java/org/nest/spl/cocos/IllegalVarInFor.java b/src/main/java/org/nest/spl/cocos/IllegalVarInFor.java new file mode 100644 index 000000000..cbfe7ffc8 --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/IllegalVarInFor.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import com.google.common.base.Preconditions; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import org.nest.spl._ast.ASTFOR_Stmt; +import org.nest.spl._cocos.SPLASTFOR_StmtCoCo; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; +import org.nest.spl.symboltable.typechecking.TypeChecker; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Check that the type of the loop variable is an integer. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class IllegalVarInFor implements SPLASTFOR_StmtCoCo { + public static final String ERROR_CODE = "SPL_ILLEGAL_VAR_IN_FOR"; + + private static final String ERROR_MSG_FORMAT = "The type of the iterator in a for-loop must be numeric and not: '%s' ."; + + private final PredefinedTypesFactory predefinedTypesFactory; + + public IllegalVarInFor(PredefinedTypesFactory predefinedTypesFactory) { + this.predefinedTypesFactory = predefinedTypesFactory; + } + + @Override + public void check(final ASTFOR_Stmt astfor) { + checkArgument(astfor.getEnclosingScope().isPresent(), "No scope assigned. Please, run symboltable creator."); + final Scope scope = astfor.getEnclosingScope().get(); + + String iterName = astfor.getVar(); + + Optional iter = scope.resolve(iterName, NESTMLVariableSymbol.KIND); + Preconditions.checkState(iter.isPresent()); + TypeChecker tc = new TypeChecker(predefinedTypesFactory); + if (!tc.checkNumber(iter.get().getType())) { + CoCoLog.error( + ERROR_CODE, + String.format(ERROR_MSG_FORMAT, iter.get().getType()), + astfor.get_SourcePositionEnd()); + } + + } + +} diff --git a/src/main/java/org/nest/spl/cocos/VarHasTypeName.java b/src/main/java/org/nest/spl/cocos/VarHasTypeName.java new file mode 100644 index 000000000..16b032114 --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/VarHasTypeName.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.spl._cocos.SPLASTDeclarationCoCo; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Checks that the variable name is not a type name, e.g. integer integer = 1. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class VarHasTypeName implements SPLASTDeclarationCoCo { + public static final String ERROR_CODE = "SPL_VARIABLE_HAS_TYPE_NAME"; + private static final String ERROR_MSG_FORMAT = "Variable '%s' cannot have the same name as a type."; + + @Override + public void check(final ASTDeclaration astDeclaration) { + checkArgument(astDeclaration.getEnclosingScope().isPresent(), "Declaration hast no scope. Run symboltable creator."); + final Scope scope = astDeclaration.getEnclosingScope().get(); + + for (String var : astDeclaration.getVars()) { + // tries to resolve the variable name as type. if it is possible, then the variable name clashes with type name is reported as an error + final Optional res = scope.resolve(var, NESTMLTypeSymbol.KIND); + + // could resolve type as variable, report an error + if (res.isPresent()) { + CoCoLog.error( + ERROR_CODE, + String.format(ERROR_MSG_FORMAT, var), + astDeclaration.get_SourcePositionEnd()); + } + + } + + } + +} diff --git a/src/main/java/org/nest/spl/cocos/VariableDefinedMultipleTimes.java b/src/main/java/org/nest/spl/cocos/VariableDefinedMultipleTimes.java new file mode 100644 index 000000000..8cac569f2 --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/VariableDefinedMultipleTimes.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import com.google.common.collect.Maps; +import de.monticore.cocos.CoCoLog; +import de.se_rwth.commons.SourcePosition; +import org.nest.spl._ast.ASTBlock; +import org.nest.spl._ast.ASTSmall_Stmt; +import org.nest.spl._ast.ASTStmt; +import org.nest.spl._cocos.SPLASTBlockCoCo; + +import java.util.Map; + +/** + * Checks that a referenced variable is also declared. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class VariableDefinedMultipleTimes implements SPLASTBlockCoCo { + public static final String ERROR_CODE = "SPL_VARIABLE_EXISTS_MULTIPLE_TIMES"; + private static final String ERROR_MSG_FORMAT = "The variable %s defined multiple times."; + + private final Map names = Maps.newHashMap(); + + @Override + public void check(ASTBlock block) { + if (block != null && block.getStmts() != null) { + resetNames(); + additionalNames(block); + doCheck(block); + } + } + + public void additionalNames(ASTBlock block) { + } + + /** + * TODO refactor it as the inspection suppose + * + * @param block + */ + protected void doCheck(ASTBlock block) { + for (ASTStmt stmt : block.getStmts()) { + if (stmt.getSimple_Stmt().isPresent() && stmt.getSimple_Stmt().get().getSmall_Stmts() != null) { + for (ASTSmall_Stmt small : stmt.getSimple_Stmt().get().getSmall_Stmts()) { + if (small.getDeclaration().isPresent()) { + for (String var : small.getDeclaration().get().getVars()) { + addVariable(var, small.getDeclaration().get().get_SourcePositionStart(), getNames()); + } + } + } + } + } + } + + protected Map getNames() { + return names; + } + + protected void resetNames() { + names.clear(); + } + + protected void addVariable(String name, SourcePosition sourcePosition, Map names) { + if (names.containsKey(name)) { + CoCoLog.error( + ERROR_CODE, // TODO better error message + String.format(ERROR_MSG_FORMAT, name), + sourcePosition); + + } else { + names.put(name, sourcePosition); + } + } + +} diff --git a/src/main/java/org/nest/spl/cocos/VariableDoesNotExist.java b/src/main/java/org/nest/spl/cocos/VariableDoesNotExist.java new file mode 100644 index 000000000..362e00263 --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/VariableDoesNotExist.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import com.google.common.collect.Lists; +import de.monticore.ast.ASTCNode; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.monticore.types.types._ast.ASTQualifiedName; +import de.monticore.utils.ASTNodes; +import de.se_rwth.commons.Names; +import org.nest.spl._ast.*; +import org.nest.spl._cocos.*; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Checks that a referenced variable is also declared. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class VariableDoesNotExist implements + SPLASTAssignmentCoCo, + SPLASTFunctionCallCoCo, + SPLASTDeclarationCoCo, + SPLASTReturnStmtCoCo, + SPLASTCompound_StmtCoCo { + + public static final String ERROR_CODE = "SPL_DOES_NOT_VARIABLE_EXIST"; + private static final String ERROR_MSG_FORMAT = "The variable %s is not defined in %s."; + + /** + * Checks if the expression contains an undeclared variable. + * @param expr Expression to check. + */ + private void checkExpression(final ASTExpr expr) { + checkState(expr.getEnclosingScope().isPresent()); + final Scope scope = expr.getEnclosingScope().get(); + final List variables = ASTNodes.getSuccessors(expr, ASTQualifiedName.class); + final List functionCallAsts = ASTNodes.getSuccessors(expr, ASTFunctionCall.class); + final List functionNames = Lists.newArrayList(); + + functionCallAsts.stream().forEach(functionCallAst -> + functionNames.add(Names.getQualifiedName(functionCallAst.getQualifiedName().getParts())) + ); + + for (final ASTQualifiedName variable:variables) { + final String variableName = Names.getQualifiedName(variable.getParts()); + if (isVariableName(functionNames, variableName)) { + // todo refactor me + final Optional variableSymbol + = scope.resolve(variableName, NESTMLVariableSymbol.KIND); + final Optional functionSymbol + = scope.resolve(variableName, NESTMLMethodSymbol.KIND); + if (!variableSymbol.isPresent() && !functionSymbol.isPresent()) { + CoCoLog.error( + ERROR_CODE, + String.format(ERROR_MSG_FORMAT, variableName, scope.getName().orElse("")), + variable.get_SourcePositionStart()); + } + + } + + } + + } + + private boolean isVariableName(List functionNames, String variableName) { + return !functionNames.contains(variableName); + } + + @Override + public void check(ASTCompound_Stmt node) { + if (node.getIF_Stmt().isPresent()) { + checkExpression(node.getIF_Stmt().get().getIF_Clause().getExpr()); + } + else if (node.getFOR_Stmt().isPresent()) { + checkVariableByName(node.getFOR_Stmt().get().getVar(), node); + } + else if (node.getWHILE_Stmt().isPresent()) { + checkExpression(node.getWHILE_Stmt().get().getExpr()); + } + else { + // cannot happen. the grammar doesn't contain other alternatives. + checkState(false); + } + + } + + private void checkVariableByName(final String fqn, final ASTCNode node) { + checkState(node.getEnclosingScope().isPresent()); + final Scope scope = node.getEnclosingScope().get(); + Optional variableSymbol = scope.resolve(fqn, NESTMLVariableSymbol.KIND); + if (!variableSymbol.isPresent()) { + CoCoLog.error( + ERROR_CODE, + String.format(ERROR_MSG_FORMAT, fqn, scope.getName().orElse("")), + node.get_SourcePositionStart()); + } + + } + + + @Override + public void check(final ASTAssignment astAssignment) { + checkExpression(astAssignment.getExpr()); + } + + @Override + public void check(final ASTDeclaration astDeclaration) { + if (astDeclaration.getExpr().isPresent()) { + checkExpression(astDeclaration.getExpr().get()); + } + + } + + @Override + public void check(final ASTFunctionCall astFunctionCall) { + for (int i = 0; i< astFunctionCall.getArgList().getArgs().size(); ++i) { + checkExpression(astFunctionCall.getArgList().getArgs().get(i)); + } + + } + + @Override + public void check(final ASTReturnStmt astReturnStmt) { + if (astReturnStmt.getExpr().isPresent()) { + checkExpression(astReturnStmt.getExpr().get()); + } + + } + +} diff --git a/src/main/java/org/nest/spl/cocos/VariableNotDefinedBeforeUse.java b/src/main/java/org/nest/spl/cocos/VariableNotDefinedBeforeUse.java new file mode 100644 index 000000000..c596f36eb --- /dev/null +++ b/src/main/java/org/nest/spl/cocos/VariableNotDefinedBeforeUse.java @@ -0,0 +1,95 @@ +package org.nest.spl.cocos; + + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import de.monticore.ast.ASTNode; +import de.monticore.cocos.CoCoLog; +import de.monticore.symboltable.Scope; +import de.monticore.types.types._ast.ASTQualifiedName; +import de.monticore.utils.ASTNodes; +import de.se_rwth.commons.Names; +import org.nest.spl._ast.ASTAssignment; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.spl._ast.ASTFOR_Stmt; +import org.nest.spl._cocos.SPLASTAssignmentCoCo; +import org.nest.spl._cocos.SPLASTDeclarationCoCo; +import org.nest.spl._cocos.SPLASTFOR_StmtCoCo; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +public class VariableNotDefinedBeforeUse implements + SPLASTAssignmentCoCo, + SPLASTDeclarationCoCo, + SPLASTFOR_StmtCoCo { + + public static final String ERROR_CODE = "SPL_VARIABLE_NOT_DEFINED_BEFORE_USE"; + private static final String ERROR_MSG_FORMAT = "Variable '%s' not defined yet. It is defined at line '%d'"; + + @Override + public void check(final ASTFOR_Stmt forstmt) { + String fullName = forstmt.getVar(); + check(fullName, forstmt); + } + + @Override + public void check(final ASTAssignment assignment) { + String fullName = Names.getQualifiedName(assignment.getVariableName().getParts()); + check(fullName, assignment); + } + + @Override + public void check(final ASTDeclaration decl) { + if (decl.getExpr().isPresent()) { + final List varsOfCurrentDecl = Lists.newArrayList(decl.getVars()); + final List variablesNamesRHS = ASTNodes.getSuccessors(decl.getExpr().get(), ASTQualifiedName.class); + + // check, if variable of the left side is used in the right side, e.g. in decl-vars + // e.g. x real = 2 * x + for (ASTQualifiedName variableName: variablesNamesRHS) { + final String varRHS = Names.getQualifiedName(variableName.getParts()); + if (varsOfCurrentDecl.contains(varRHS)) { + final String logMsg = "Cannot use variable '%s' in the assignment of its own declaration."; + CoCoLog.error( + ERROR_CODE, + String.format(logMsg, varRHS), + decl.get_SourcePositionStart()); + } + else if (variableName.get_SourcePositionStart().compareTo(decl.get_SourcePositionStart()) > 0) { + // y real = 5 * x + // x integer = 1 + final String logMsg = "Cannot use variable '%s' before its usage" + + "."; + CoCoLog.error( + ERROR_CODE, + String.format(logMsg, Names.getQualifiedName(variableName.getParts())), + decl.get_SourcePositionStart()); + } + + } + + } + + } + + protected void check(final String varName, final ASTNode node) { + checkArgument(node.getEnclosingScope().isPresent(), "No scope assigned. Please, run symboltable creator."); + final Scope scope = node.getEnclosingScope().get(); + + Optional varOptional = scope.resolve(varName, NESTMLVariableSymbol.KIND); + Preconditions.checkState(varOptional.isPresent(), "Variable " + varName + " couldn't be resolved."); + // exists + if (node.get_SourcePositionStart().compareTo(varOptional.get().getSourcePosition()) < 0) { + CoCoLog.error( + ERROR_CODE, + String.format(ERROR_MSG_FORMAT, varName, varOptional.get().getSourcePosition().getLine()), + node.get_SourcePositionEnd()); + } + + } + +} diff --git a/src/main/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinter.java b/src/main/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinter.java new file mode 100644 index 000000000..6cce9ef71 --- /dev/null +++ b/src/main/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinter.java @@ -0,0 +1,234 @@ +package org.nest.spl.prettyprinter; + +import de.monticore.prettyprint.IndentPrinter; +import de.monticore.types.prettyprint.TypesPrettyPrinterConcreteVisitor; +import de.monticore.types.types._ast.ASTQualifiedName; +import org.nest.codegeneration.converters.IReferenceConverter; +import org.nest.codegeneration.converters.IdempotentReferenceConverter; +import org.nest.spl._ast.ASTExpr; +import org.nest.spl._ast.ASTExprList; +import org.nest.spl._ast.ASTFunctionCall; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Converts SPL expression sublanguage to the executable platform dependent code. + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since TODO + */ +public class ExpressionsPrettyPrinter { + + final IReferenceConverter referenceConverter; + + public ExpressionsPrettyPrinter() { + this.referenceConverter = new IdempotentReferenceConverter(); + } + + public ExpressionsPrettyPrinter(final IReferenceConverter referenceConverter) { + this.referenceConverter = referenceConverter; + } + + public String print(final ASTExpr expr) { + checkNotNull(expr); + + if (expr.getNumericLiteral().isPresent()) { // number + return typesPrinter().prettyprint(expr.getNumericLiteral().get()); + } + if (expr.isInf()) { + return handleConstant("inf"); + } + else if (expr.getStringLiteral().isPresent()) { // string + return typesPrinter().prettyprint(expr.getStringLiteral().get()); + } + else if (expr.getBooleanLiteral().isPresent()) { // boolean + return typesPrinter().prettyprint(expr.getBooleanLiteral().get()); + } + else if (expr.getQualifiedName().isPresent()) { // var + return handleQualifiedName(expr.getQualifiedName().get()); + } + else if (expr.getFunctionCall().isPresent()) { // function + final ASTFunctionCall astFunctionCall = expr.getFunctionCall().get(); + return printMethodCall(astFunctionCall); + + } + else if (expr.isUnaryPlus()) { + return "(" + "+" + print(expr.getTerm().get()) + ")"; + } + else if (expr.isUnaryMinus()) { + return "(" + "-" + print(expr.getTerm().get()) + ")"; + } + else if (expr.isUnaryTilde()) { + return "(" + "~" + print(expr.getTerm().get()) + ")"; + } + else if (expr.leftParenthesesIsPresent() && expr.leftParenthesesIsPresent()) { + return "(" + print(expr.getExpr().get()) + ")"; + } + else if (expr.isPlusOp() || expr.isMinusOp() || expr.isTimesOp() || expr.isDivOp()) { + final StringBuilder expression = new StringBuilder(); + final String leftOperand = print(expr.getLeft().get()); + final String rightOperand = print(expr.getRight().get()); + expression.append(leftOperand); + expression.append(getArithmeticOperator(expr)); + expression.append(rightOperand); + return expression.toString(); + } + else if (expr.isPow()) { + final StringBuilder expression = new StringBuilder(); + final String leftOperand = print(expr.getBase().get()); + final String rightOperand = print(expr.getExponent().get()); + expression.append(leftOperand).append("**").append(rightOperand); + return expression.toString(); + } + else if (expr.isShiftLeft() || + expr.isShiftRight() || + expr.isModuloOp() || + expr.isBitAnd() || + expr.isBitOr() || + expr.isBitXor()) { + final StringBuilder expression = new StringBuilder(); + final String leftOperand = print(expr.getLeft().get()); + final String rightOperand = print(expr.getRight().get()); + expression.append(leftOperand); + expression.append(printBitOperator(expr)); + expression.append(rightOperand); + return expression.toString(); + } + // left:Expr (lt:["<"] | le:["<="] | eq:["=="] | ne:["!="] | ne2:["<>"] | ge:[">="] | gt:[">"]) right:Expr + else if (expr.isLt() || expr.isLe() || expr.isEq() || expr.isNe() || expr.isNe2() || expr.isGe() || expr.isGt()) { + final StringBuilder expression = new StringBuilder(); + final String leftOperand = print(expr.getLeft().get()); + final String rightOperand = print(expr.getRight().get()); + expression.append(leftOperand).append(printComparisonOperator(expr)).append(rightOperand); + return expression.toString(); + } + else if (expr.isLogicalOr()) { + final StringBuilder expression = new StringBuilder(); + final String leftOperand = print(expr.getLeft().get()); + final String rightOperand = print(expr.getRight().get()); + expression.append("(").append(leftOperand).append(")"); + expression.append(" or "); + expression.append("(").append(rightOperand).append(")"); + return expression.toString(); + } + else if (expr.isLogicalAnd()) { + final StringBuilder expression = new StringBuilder(); + final String leftOperand = print(expr.getLeft().get()); + final String rightOperand = print(expr.getRight().get()); + expression.append("(").append(leftOperand).append(")"); + expression.append(" and "); + expression.append("(").append(rightOperand).append(")"); + return expression.toString(); + } + final String errorMsg = "Cannot determine the type of the Expression-Node @{" + expr.get_SourcePositionStart() + + ", " + expr.get_SourcePositionEnd() + "}"; + + throw new RuntimeException(errorMsg); + } + + public String printMethodCall(final ASTFunctionCall astFunctionCall) { + final String nestFunctionName = referenceConverter.convertFunctionCall(astFunctionCall); + + if (referenceConverter.needsArguments(astFunctionCall)) { + final StringBuilder argsListAsString = printFunctionCallArguments(astFunctionCall); + return String.format(nestFunctionName, argsListAsString); + } + else { + return nestFunctionName; + } + } + + public StringBuilder printFunctionCallArguments(final ASTFunctionCall astFunctionCall) { + final StringBuilder argsListAsString = new StringBuilder(); + + final ASTExprList functionArgs = astFunctionCall.getArgList().getArgs(); + for (int i = 0; i < functionArgs.size(); ++i) { + boolean isLastArgument = (i+1) == functionArgs.size(); + if (!isLastArgument) { + argsListAsString.append(print(functionArgs.get(i))); + argsListAsString.append(", "); + } + else { + // last argument, don't append ',' + argsListAsString.append(print(functionArgs.get(i))); + } + + } + return argsListAsString; + } + + protected String handleConstant(final String constantName) { + return referenceConverter.convertConstant(constantName); + } + + protected String handleQualifiedName(final ASTQualifiedName astVariableName) { + return referenceConverter.convertNameReference(astVariableName); + } + + private String printComparisonOperator(final ASTExpr expr) { + if (expr.isLt()) { + return "<"; + } + if (expr.isLe()) { + return "<="; + } + if (expr.isEq()) { + return "=="; + } + if (expr.isNe() || expr.isNe2()) { + return "!="; + } + if (expr.isGe()) { + return ">="; + } + if (expr.isGt()) { + return ">"; + } + throw new RuntimeException("Cannot determine comparison operator"); + } + + private String printBitOperator(final ASTExpr expr) { + if (expr.isShiftLeft()) { + return "<<"; + } + if (expr.isShiftRight()) { + return ">>"; + } + if (expr.isModuloOp()) { + return "%"; + } + if (expr.isBitAnd()) { + return "&"; + } + if (expr.isBitOr()) { + return "|"; + } + if (expr.isBitXor()) { + return "^"; + } + + throw new RuntimeException("Cannot determine mathematical operator"); + } + + private String getArithmeticOperator(final ASTExpr expr) { + if (expr.isPlusOp()) { + return "+"; + } + if(expr.isMinusOp()) { + return "-"; + } + if (expr.isTimesOp()) { + return "*"; + } + if (expr.isDivOp()) { + return "/"; + } + throw new RuntimeException("Cannot determine mathematical operator"); + } + + private TypesPrettyPrinterConcreteVisitor typesPrinter() { + final IndentPrinter printer = new IndentPrinter(); + return new TypesPrettyPrinterConcreteVisitor(printer); + } +} diff --git a/src/main/java/org/nest/spl/prettyprinter/SPLPrettyPrinter.java b/src/main/java/org/nest/spl/prettyprinter/SPLPrettyPrinter.java new file mode 100644 index 000000000..dedf09594 --- /dev/null +++ b/src/main/java/org/nest/spl/prettyprinter/SPLPrettyPrinter.java @@ -0,0 +1,290 @@ +package org.nest.spl.prettyprinter; + +import de.monticore.prettyprint.IndentPrinter; +import de.monticore.types.prettyprint.TypesPrettyPrinterConcreteVisitor; +import de.se_rwth.commons.Names; +import org.nest.spl._ast.*; +import org.nest.spl._visitor.SPLVisitor; +import org.nest.utils.PrettyPrinterBase; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkState; +import static de.se_rwth.commons.Names.getQualifiedName; + +/** + * Provides convenient functions to statically type interfaces astnodes resulting from the Body-grammar + * production. + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + */ +public class SPLPrettyPrinter extends PrettyPrinterBase implements SPLVisitor { + + private final ExpressionsPrettyPrinter expressionsPrettyPrinter; + + + protected SPLPrettyPrinter(final ExpressionsPrettyPrinter expressionsPrettyPrinter) { + this.expressionsPrettyPrinter = expressionsPrettyPrinter; + } + + public void print(final ASTSPLNode node) { + node.accept(this); + } + + /** + * Grammar + * SPLFile = ModuleDefinitionStatement Block; + */ + @Override + public void visit(final ASTSPLFile astFile) { + // at the moment do nothing + } + + /** + * ModuleDefinitionStatement = "module" moduleName:QualifiedName; + */ + @Override + public void visit(final ASTModuleDefinitionStatement node) { + final String moduleName = getQualifiedName(node.getModuleName().getParts()); + println("module " + moduleName); + } + + /** + * Grammar: + * IF_Stmt = IF_Clause + * ELIF_Clause* + * (ELSE_Clause)? + * BLOCK_CLOSE; + */ + @Override + public void endVisit(final ASTIF_Stmt node) { + println(BLOCK_CLOSE); + } + + /** + * Grammar: + * IF_Clause = "if" Expr BLOCK_OPEN Block; + */ + @Override + public void visit(final ASTIF_Clause astIfClause) { + print("if" + " "); + final String conditionExpression = expressionsPrettyPrinter.print(astIfClause.getExpr()); + println(conditionExpression + BLOCK_OPEN); + indent(); + } + + @Override + public void endVisit(final ASTIF_Clause astIfClause) { + unindent(); + } + + /** + * ELIF_Clause = "elif" Expr BLOCK_OPEN Block; + */ + @Override + public void visit(final ASTELIF_Clause astElifNode) { + print("elif" + " "); + final String conditionExpression = expressionsPrettyPrinter.print(astElifNode.getExpr()); + println(conditionExpression + BLOCK_OPEN); + indent(); + } + + @Override + public void endVisit(final ASTELIF_Clause astElifNode) { + unindent(); + } + + /** + * Grammar: + * ELSE_Clause = "else" BLOCK_OPEN Block; + */ + @Override + public void visit(final ASTELSE_Clause astElseClause) { + println("else:"); + indent(); + } + + @Override + public void endVisit(final ASTELSE_Clause astElseClause) { + unindent(); + } + + /** + * Small_Stmt = Assignment + * | FunctionCall + * | Declaration + * | ReturnStmt; + */ + @Override + public void visit(final ASTSmall_Stmt astSmallStmt ) { + if (astSmallStmt.getAssignment().isPresent()) { + printAssignment(astSmallStmt.getAssignment().get()); + } else if (astSmallStmt.getFunctionCall().isPresent()) { + printFunctionCall(astSmallStmt.getFunctionCall().get()); + } else if (astSmallStmt.getDeclaration().isPresent()) { + printDeclaration(astSmallStmt.getDeclaration().get()); + } else if (astSmallStmt.getReturnStmt().isPresent()) { + printReturnStatement(astSmallStmt.getReturnStmt().get()); + } + + } + + + /** + * Small_Stmt = Assignment + * | FunctionCall + * | Declaration + * | ReturnStmt; + */ + @Override + public void endVisit(final ASTSmall_Stmt astSmallStmt ) { + println(); + } + + /** + * Grammar: + * Assignment = variableName:QualifiedName "=" Expr; + */ + public void printAssignment(final ASTAssignment astAssignment) { + final String lhsVariableName = Names.getQualifiedName(astAssignment.getVariableName().getParts()); + final String rhsOfAssignment = expressionsPrettyPrinter.print(astAssignment.getExpr()); + println(lhsVariableName + " = " + rhsOfAssignment); + } + + /** + * Grammar: + * FunctionCall = QualifiedName "(" ArgList ")"; + * ArgList = (args:Expr ("," args:Expr)*)?; + */ + public void printFunctionCall(final ASTFunctionCall astFunctionCall) { + final String functionName = Names.getQualifiedName(astFunctionCall.getQualifiedName().getParts()); + print(functionName + "("); + final ASTExprList functionArguments = astFunctionCall.getArgList().getArgs(); + for (int argumentIndex = 0; argumentIndex < functionArguments.size(); ++argumentIndex) { + boolean isLastFunctionArgument = (argumentIndex + 1) == functionArguments.size(); + final ASTExpr currentArgument = functionArguments.get(argumentIndex); + print(expressionsPrettyPrinter.print(currentArgument)); + if (!isLastFunctionArgument) { + print(", "); + } + + } + print(")"); + println(); + } + + /** + * ReturnStmt = "return" Expr?; + */ + public void printReturnStatement(final ASTReturnStmt astReturnStmt) { + + if (astReturnStmt.getExpr().isPresent()) { + final String returnExpressionAsString = expressionsPrettyPrinter.print(astReturnStmt.getExpr().get()); + println("return " + returnExpressionAsString); + } + else { + println("return"); + } + + } + + /** + * Grammar + * Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + */ + public void printDeclaration(final ASTDeclaration astDeclaration) { + printDeclarationVariables(astDeclaration); + printDeclarationType(astDeclaration); + printOptionalInitializationExpression(astDeclaration); + } + + private void printDeclarationVariables(final ASTDeclaration astDeclaration) { + final List variableNames = astDeclaration.getVars(); + for (int variableIndex = 0; variableIndex < variableNames.size(); ++ variableIndex) { + boolean isLastVariableInDeclaration = (variableIndex + 1) == variableNames.size(); + + print(variableNames.get(variableIndex)); + if (!isLastVariableInDeclaration) { + print(", "); + } + + } + + print(" "); + } + + private void printDeclarationType(final ASTDeclaration astDeclaration) { + // print the type of the declaration. it is either a primitive type or a reference type + if (astDeclaration.getPrimitiveType().isPresent()) { + + print(createPrettyPrinterForTypes().prettyprint(astDeclaration.getPrimitiveType().get())); + } + else if (astDeclaration.getType().isPresent()) { + print(Names.getQualifiedName(astDeclaration.getType().get().getParts())); + } + else { + checkState(false, "Should be impossible through the grammar definition."); + } + + } + + + + private void printOptionalInitializationExpression(final ASTDeclaration astDeclaration) { + if (astDeclaration.getExpr().isPresent()) { + print(" = " + expressionsPrettyPrinter.print(astDeclaration.getExpr().get())); + } + + } + + /** + * Grammar: + * FOR_Stmt = "for" var:Name "in" from:Expr "..." to:Expr ("step" step:SignedNumericLiteral)? + * BLOCK_OPEN Block BLOCK_CLOSE; + */ + @Override public void visit(final ASTFOR_Stmt astForStmt) { + print("for "); + print(astForStmt.getVar()); + print(" in "); + print(expressionsPrettyPrinter.print(astForStmt.getFrom())); + print(" ... "); + print(expressionsPrettyPrinter.print(astForStmt.getTo())); + if (astForStmt.getStep().isPresent()) { + print(" step "); + print(createPrettyPrinterForTypes().prettyprint(astForStmt.getStep().get())); + } + println(BLOCK_OPEN); + indent(); + } + + @Override + public void endVisit(final ASTFOR_Stmt node) { + unindent(); + println(BLOCK_CLOSE); + } + + /** + * Grammar: + * WHILE_Stmt = "while" Expr BLOCK_OPEN Block BLOCK_CLOSE; + */ + @Override + public void visit(final ASTWHILE_Stmt astWhileStmt) { + print("while "); + print(expressionsPrettyPrinter.print(astWhileStmt.getExpr())); + println(BLOCK_OPEN); + indent(); + } + + @Override + public void endVisit(final ASTWHILE_Stmt node) { + unindent(); + println(BLOCK_CLOSE); + } + + private TypesPrettyPrinterConcreteVisitor createPrettyPrinterForTypes() { + final IndentPrinter printer = new IndentPrinter(); + return new TypesPrettyPrinterConcreteVisitor(printer); + } + +} diff --git a/src/main/java/org/nest/spl/prettyprinter/SPLPrettyPrinterFactory.java b/src/main/java/org/nest/spl/prettyprinter/SPLPrettyPrinterFactory.java new file mode 100644 index 000000000..b1a5b944c --- /dev/null +++ b/src/main/java/org/nest/spl/prettyprinter/SPLPrettyPrinterFactory.java @@ -0,0 +1,20 @@ +package org.nest.spl.prettyprinter; + +/** + * Created by user on 09.06.15. + */ +public class SPLPrettyPrinterFactory { + public static SPLPrettyPrinter createDefaultPrettyPrinter() { + return new SPLPrettyPrinter(new ExpressionsPrettyPrinter()); + + } + + public static SPLPrettyPrinter createDefaultPrettyPrinter(int indentionLevel) { + final SPLPrettyPrinter splPrettyPrinter = + new SPLPrettyPrinter(new ExpressionsPrettyPrinter()); + splPrettyPrinter.setIndentionLevel(indentionLevel); + return splPrettyPrinter; + + } + +} diff --git a/src/main/java/org/nest/spl/symboltable/CommonSPLSymbolTableCreator.java b/src/main/java/org/nest/spl/symboltable/CommonSPLSymbolTableCreator.java new file mode 100644 index 000000000..7400b27bc --- /dev/null +++ b/src/main/java/org/nest/spl/symboltable/CommonSPLSymbolTableCreator.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable; + +import de.monticore.symboltable.CommonSymbolTableCreator; +import de.monticore.symboltable.MutableScope; +import de.monticore.symboltable.ResolverConfiguration; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +/** + * TODO why must I write this class?. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class CommonSPLSymbolTableCreator extends CommonSymbolTableCreator implements SPLSymbolTableCreator { + + private final PredefinedTypesFactory predefinedTypesFactory; + + public CommonSPLSymbolTableCreator( + final ResolverConfiguration resolverConfig, + final MutableScope enclosingScope, + final PredefinedTypesFactory predefinedTypesFactory) { + super(resolverConfig, enclosingScope); + this.predefinedTypesFactory = predefinedTypesFactory; + } + + @Override + public PredefinedTypesFactory getTypesFactory() { + return predefinedTypesFactory; + } + +} diff --git a/src/main/java/org/nest/spl/symboltable/SPLCoCosManager.java b/src/main/java/org/nest/spl/symboltable/SPLCoCosManager.java new file mode 100644 index 000000000..77577382b --- /dev/null +++ b/src/main/java/org/nest/spl/symboltable/SPLCoCosManager.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable; + +import org.nest.nestml._cocos.NESTMLCoCoChecker; +import org.nest.spl.cocos.*; +import org.nest.spl._cocos.*; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +/** + * This class is responsible for the instantiation of the NESTML context conditions. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class SPLCoCosManager { + + private final PredefinedTypesFactory predefinedTypesFactory; + + public SPLCoCosManager(PredefinedTypesFactory predefinedTypesFactory) { + this.predefinedTypesFactory = predefinedTypesFactory; + } + + /** + * @return A checker with all SPL context conditions + */ + public SPLCoCoChecker createDefaultChecker() { + final SPLCoCoChecker splCoCoChecker = new SPLCoCoChecker(); + + createCoCosForSPL(splCoCoChecker); + return splCoCoChecker; + } + + public void createCoCosForSPL(SPLCoCoChecker splCoCoChecker) { + final VariableDoesNotExist variableExists = new VariableDoesNotExist(); + splCoCoChecker.addCoCo((SPLASTCompound_StmtCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTFunctionCallCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTReturnStmtCoCo) variableExists); + + final VariableDefinedMultipleTimes variableDefinedMultipleTimes = new VariableDefinedMultipleTimes(); + splCoCoChecker.addCoCo(variableDefinedMultipleTimes); + + final VarHasTypeName varHasTypeName = new VarHasTypeName(); + splCoCoChecker.addCoCo(varHasTypeName); + + final VariableNotDefinedBeforeUse variableNotDefinedBeforeUse = new VariableNotDefinedBeforeUse(); + + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) variableNotDefinedBeforeUse); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) variableNotDefinedBeforeUse); + splCoCoChecker.addCoCo((SPLASTFOR_StmtCoCo) variableNotDefinedBeforeUse); + + final IllegalVarInFor illegalVarInFor = new IllegalVarInFor(predefinedTypesFactory); + splCoCoChecker.addCoCo(illegalVarInFor); + + final IllegalExpression illegalExpression = new IllegalExpression(predefinedTypesFactory); + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTELIF_ClauseCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTFOR_StmtCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTIF_ClauseCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTWHILE_StmtCoCo) illegalExpression); + + final CodeAfterReturn codeAfterReturn = new CodeAfterReturn(); + splCoCoChecker.addCoCo(codeAfterReturn); + + final FunctionDoesntExist functionDoesntExist = new FunctionDoesntExist(predefinedTypesFactory); + splCoCoChecker.addCoCo(functionDoesntExist); + + final CheckMultipleSignsBeforeFactor checkMultipleSignsBeforeFactor + = new CheckMultipleSignsBeforeFactor(); + splCoCoChecker.addCoCo((SPLASTBlockCoCo) checkMultipleSignsBeforeFactor); + splCoCoChecker.addCoCo((SPLASTBlockCoCo) checkMultipleSignsBeforeFactor); + } + + public void addSPLCocosToNESTMLChecker(NESTMLCoCoChecker splCoCoChecker) { + final VariableDoesNotExist variableExists = new VariableDoesNotExist(); + splCoCoChecker.addCoCo((SPLASTCompound_StmtCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTFunctionCallCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTReturnStmtCoCo) variableExists); + + final VariableDefinedMultipleTimes variableDefinedMultipleTimes + = new VariableDefinedMultipleTimes(); + splCoCoChecker.addCoCo(variableDefinedMultipleTimes); + + final VarHasTypeName varHasTypeName = new VarHasTypeName(); + splCoCoChecker.addCoCo(varHasTypeName); + + final IllegalVarInFor illegalVarInFor = new IllegalVarInFor(predefinedTypesFactory); + splCoCoChecker.addCoCo(illegalVarInFor); + + final IllegalExpression illegalExpression = new IllegalExpression(predefinedTypesFactory); + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTELIF_ClauseCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTFOR_StmtCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTIF_ClauseCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTWHILE_StmtCoCo) illegalExpression); + + final CodeAfterReturn codeAfterReturn = new CodeAfterReturn(); + splCoCoChecker.addCoCo(codeAfterReturn); + + final FunctionDoesntExist functionDoesntExist = new FunctionDoesntExist(predefinedTypesFactory); + splCoCoChecker.addCoCo(functionDoesntExist); + + final CheckMultipleSignsBeforeFactor checkMultipleSignsBeforeFactor + = new CheckMultipleSignsBeforeFactor(); + splCoCoChecker.addCoCo((SPLASTBlockCoCo) checkMultipleSignsBeforeFactor); + splCoCoChecker.addCoCo((SPLASTExprCoCo) checkMultipleSignsBeforeFactor); + } + +} diff --git a/src/main/java/org/nest/spl/symboltable/SPLModelLoader.java b/src/main/java/org/nest/spl/symboltable/SPLModelLoader.java new file mode 100644 index 000000000..94f69fb3d --- /dev/null +++ b/src/main/java/org/nest/spl/symboltable/SPLModelLoader.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable; + +import de.monticore.symboltable.ArtifactScope; +import de.monticore.symboltable.MutableScope; +import de.monticore.symboltable.ResolverConfiguration; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._symboltable.SPLLanguage; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.isNullOrEmpty; +import static de.se_rwth.commons.logging.Log.info; +import static de.se_rwth.commons.logging.Log.warn; + +/** + * Creates symbol table for the {@code SPLLanguage} from the parsed model. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class SPLModelLoader extends org.nest.spl._symboltable.SPLModelLoader { + + public static final String LOGGER_NAME = SPLModelLoader.class.getName(); + + public SPLModelLoader(final SPLLanguage modelingLanguage) { + super(modelingLanguage); + } + + @Override + protected void createSymbolTableFromAST( + final ASTSPLFile ast, + final String modelName, + final MutableScope enclosingScope, + final ResolverConfiguration resolverConfiguration) { + + final Optional symbolTableCreator + = getModelingLanguage().getSymbolTableCreator(resolverConfiguration, enclosingScope); + + if (symbolTableCreator.isPresent()) { + final String msg = "Start creation of symbol table for model \"" + modelName + "\"."; + info(msg, LOGGER_NAME); + final Scope scope = symbolTableCreator.get().createFromAST(ast); + + if (!(scope instanceof ArtifactScope)) { + warn("Top scope of model " + modelName + " is expected to be a compilation scope, but" + + " is scope \"" + scope.getName() + "\""); + } + + info(LOGGER_NAME, "Created symbol table for model \"" + modelName + "\"."); + } + else { + warn("No symbol created, because '" + getModelingLanguage().getName() + + "' does not define a symbol table creator."); + } + + } + public SPLLanguage getModelingLanguage() { + return super.getModelingLanguage(); + } +} diff --git a/src/main/java/org/nest/spl/symboltable/SPLScopeCreator.java b/src/main/java/org/nest/spl/symboltable/SPLScopeCreator.java new file mode 100644 index 000000000..cc1686e03 --- /dev/null +++ b/src/main/java/org/nest/spl/symboltable/SPLScopeCreator.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable; + +import de.monticore.io.paths.ModelPath; +import de.monticore.symboltable.GlobalScope; +import de.monticore.symboltable.ResolverConfiguration; +import de.monticore.symboltable.Scope; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._symboltable.SPLLanguage; +import org.nest.symboltable.ScopeCreatorBase; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.nio.file.Paths; + +/** + * TODO: Write me! + * + * @author plotnikov + * @since 0.0.2 + */ +public class SPLScopeCreator extends ScopeCreatorBase { + + private static final String LOGGER_NAME = SPLScopeCreator.class.getName(); + + private final GlobalScope globalScope; + + final SPLSymbolTableCreator symbolTableCreator; + + public GlobalScope getGlobalScope() { + return globalScope; + } + + public SPLScopeCreator( + final String modelPathAsString, + final PredefinedTypesFactory typesFactory) { + super(typesFactory); + + final ModelPath modelPath = new ModelPath(Paths.get(modelPathAsString)); + + final SPLLanguage splLanguage = new SPLLanguage(typesFactory); + + final ResolverConfiguration resolverConfiguration = new ResolverConfiguration(); + resolverConfiguration.addTopScopeResolvers(splLanguage.getResolvers()); + + globalScope = new GlobalScope(modelPath, splLanguage.getModelLoader(), resolverConfiguration); + + addPredefinedTypes(globalScope); + addPredefinedFunctions(globalScope); + addPredefinedVariables(globalScope); + + symbolTableCreator = new CommonSPLSymbolTableCreator( + resolverConfiguration, globalScope, typesFactory); + + } + + public Scope runSymbolTableCreator(final ASTSPLFile compilationUnit) { + return symbolTableCreator.createFromAST(compilationUnit); + } + + @Override + public String getLogger() { + return LOGGER_NAME; + } + +} diff --git a/src/main/java/org/nest/spl/symboltable/SPLSymbolTableCreator.java b/src/main/java/org/nest/spl/symboltable/SPLSymbolTableCreator.java new file mode 100644 index 000000000..9c1f535fe --- /dev/null +++ b/src/main/java/org/nest/spl/symboltable/SPLSymbolTableCreator.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable; + +import de.monticore.symboltable.*; +import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; +import org.nest.spl._ast.*; +import org.nest.spl._visitor.SPLVisitor; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.ArrayList; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + +/** + * Visitor that creates symbols for SPLTypes, SPLVariables from an SPL model. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +interface SPLSymbolTableCreator extends SymbolTableCreator, SPLVisitor { + + String LOGGER_NAME = SPLSymbolTableCreator.class.getName(); + + PredefinedTypesFactory getTypesFactory(); + /** + * Creates the symbol table starting from the rootNode and returns the first scope + * that was created. + * + * @param rootNode the root node + * @return the first scope that was created + */ + default Scope createFromAST(final ASTSPLNode rootNode) { + requireNonNull(rootNode); + rootNode.accept(this); + return getFirstCreatedScope(); + } + + @Override + default void visit(final ASTSPLFile ast) { + final String fullName = Names.getQualifiedName(ast.getModuleDefinitionStatement().getModuleName().getParts()); + final String packageName = Names.getQualifier(fullName); + final String modelName = Names.getSimpleName(fullName); + + final MutableScope artifactScope = new ArtifactScope(Optional.empty(), packageName + "." + modelName, new ArrayList<>()); + putOnStack(artifactScope); + ast.setEnclosingScope(artifactScope); + + final String msg = String.format("Adds new scope for the separate SPL model: %s", modelName); + Log.info(msg, LOGGER_NAME); + } + + @Override + default void endVisit(final ASTSPLFile root) { + removeCurrentScope(); + + setEnclosingScopeOfNodes(root); + Log.info("Sets scopes on all ASTs.", LOGGER_NAME); + } + + @Override + default void visit(final ASTCompound_Stmt astCompoundStmt) { + final CommonScope shadowingScope = new CommonScope(true); + putOnStack(shadowingScope); + + } + + @Override + default void endVisit(final ASTCompound_Stmt astCompoundStmt) { + removeCurrentScope(); + } + + @Override + default void visit(final ASTDeclaration astDeclaration) { + for (String variableName : astDeclaration.getVars()) { + NESTMLVariableSymbol variable = new NESTMLVariableSymbol(variableName); + String typeName = computeTypeName(astDeclaration); + variable.setAstNode(astDeclaration); + variable.setType(getTypesFactory().getType(typeName)); // if exists better choice? + + // handle ST infrastructure + putInScopeAndLinkWithAst(variable, astDeclaration); + + Log.info("Creates a variable: " + variableName + " with the type: " + typeName, LOGGER_NAME); + } + + } + + /** + * Computes the typename for the declaration ast. It is defined in one of the grammar + * alternatives. + */ + default String computeTypeName(final ASTDeclaration astDeclaration) { + String typeName = null; + if (astDeclaration.getType().isPresent()) { + typeName = astDeclaration.getType().get().toString(); + } + else if (astDeclaration.getPrimitiveType().isPresent()) { + typeName = astDeclaration.getPrimitiveType().get().toString(); + } + else { + checkState(false, "Is not possible through the grammar construction."); + } + return typeName; + } + +} diff --git a/src/main/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculator.java b/src/main/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculator.java new file mode 100644 index 000000000..2f6c4c8bc --- /dev/null +++ b/src/main/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculator.java @@ -0,0 +1,290 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable.typechecking; + +import com.google.common.base.Preconditions; +import de.monticore.cocos.CoCoLog; +import de.monticore.literals.literals._ast.ASTDoubleLiteral; +import de.monticore.literals.literals._ast.ASTIntLiteral; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; +import org.nest.spl.prettyprinter.SPLPrettyPrinter; +import org.nest.spl.prettyprinter.SPLPrettyPrinterFactory; +import org.nest.spl._ast.ASTExpr; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +/** + * Compute the type of an expression by an recursive algorithm. + * + * @author plotnikov + * @since 0.0.1 + */ +public class ExpressionTypeCalculator { + + public static final String ERROR_CODE = "SPL_EXPRESSION_TYPE_ERROR"; + + private final PredefinedTypesFactory typesFactory; + + public ExpressionTypeCalculator(PredefinedTypesFactory typesFactory) { + this.typesFactory = typesFactory; + } + + public NESTMLTypeSymbol computeType(final ASTExpr expr) { + Preconditions.checkNotNull(expr); + checkArgument(expr.getEnclosingScope().isPresent(), "No scope assigned. Please, run symboltable creator."); + final Scope scope = expr.getEnclosingScope().get(); + + if (expr.leftParenthesesIsPresent()) { + return computeType(expr.getExpr().get()); + } + else if (expr.getNumericLiteral().isPresent()) { // number + if (expr.getNumericLiteral().get() instanceof ASTDoubleLiteral) { + return typesFactory.getRealType(); + } + else if (expr.getNumericLiteral().get() instanceof ASTIntLiteral) { + return typesFactory.getIntegerType(); + } + + } + else if(expr.isInf()) { + return typesFactory.getRealType(); + } + else if (expr.getStringLiteral().isPresent()) { // string + return typesFactory.getStringType(); + } + else if (expr.getBooleanLiteral().isPresent()) { // boolean + return typesFactory.getBooleanType(); + } + else if (expr.getQualifiedName().isPresent()) { // var + final String varName = Names.getQualifiedName(expr.getQualifiedName().get().getParts()); + final Optional var = scope.resolve(varName, NESTMLVariableSymbol.KIND); + + if (var.isPresent()) { + return var.get().getType(); + } + else { + Log.warn("ExpressionCalculator cannot resolve the type of the variable: " + varName); + // TODO handle it correctly + } + } + else if (expr.getFunctionCall().isPresent()) { // function + final String functionName = Names.getQualifiedName(expr.getFunctionCall().get().getQualifiedName().getParts()); + + // TODO: use the helper to query function by parameters + //final Object[] params = atom.getFunctionCall().getArgList().getArgs().toArray(); + final Optional methodSymbol = scope.resolve(functionName, + NESTMLMethodSymbol.KIND); + Preconditions.checkState(methodSymbol.isPresent(), "Cannot resolve the method: " + + functionName); + + if (new TypeChecker(typesFactory).checkVoid(methodSymbol.get().getReturnType())) { + final String errorMsg = "Function '%s' with returntype 'Void' cannot be used in expressions."; + CoCoLog.error( + ERROR_CODE, + String.format(errorMsg, functionName), + expr.get_SourcePositionEnd()); + } + + return methodSymbol.get().getReturnType(); + } + // TODO expr.leftParenthesesIsPresent must be handled + else if (expr.getTerm().isPresent()) { // TODO it is a hack. the code with isUnaryPlus must work + NESTMLTypeSymbol type = computeType(expr.getTerm().get()); + if (isNumeric(type)) { + return type; + } + else { + final String errorMsg = "Cannot perform math operation on the not numeric type @<" + expr.get_SourcePositionStart() + + ", " + expr.get_SourcePositionStart() + ">"; + + throw new RuntimeException(errorMsg); + } + } + else if (expr.isPlusOp()) { + final NESTMLTypeSymbol lhsType = computeType(expr.getLeft().get()); + final NESTMLTypeSymbol rhsType = computeType(expr.getRight().get()); + + // String concatenation has a prio. If one of the operands is a string, the remaining sub-expression becomes a string + if ((lhsType.equals(typesFactory.getStringType()) || + rhsType.equals(typesFactory.getStringType())) && + (!rhsType.equals(typesFactory.getVoidType()) && + !lhsType.equals(typesFactory.getVoidType()))) { + return typesFactory.getStringType(); + } + if (isNumeric(lhsType) && isNumeric(rhsType)) { + // in this case, neither of the sides is a String + if ((lhsType.equals(typesFactory.getRealType()) || lhsType.getType().equals(NESTMLTypeSymbol.Type.UNIT)) || + (rhsType.equals(typesFactory.getRealType()) || rhsType.getType().equals(NESTMLTypeSymbol.Type.UNIT))) { + return typesFactory.getRealType(); + } + // e.g. both are integers, but check to be sure + if (lhsType.equals(typesFactory.getIntegerType()) || + rhsType.equals(typesFactory.getIntegerType())) { + return typesFactory.getIntegerType(); + } + + final String errorMsg = "Cannot determine the type of the operation with types: " + lhsType + + ", " + rhsType + " at " + expr.get_SourcePositionStart() + ">"; + + throw new RuntimeException(errorMsg); + } + // in this case, neither of the sides is a String + if (lhsType.equals(typesFactory.getRealType()) || + rhsType.equals(typesFactory.getRealType())) { + return typesFactory.getRealType(); + } + // e.g. both are integers, but check to be sure + if (lhsType.equals(typesFactory.getIntegerType()) || + rhsType.equals(typesFactory.getIntegerType())) { + return typesFactory.getIntegerType(); + } + + // TODO should be not possible + final String errorMsg = "Cannot determine the type of the Expression-Node @<" + expr.get_SourcePositionStart() + + ", " + expr.get_SourcePositionStart() + ">"; + + throw new RuntimeException(errorMsg); + } + else if (expr.isMinusOp() || expr.isTimesOp() || expr.isDivOp()) { + + + final NESTMLTypeSymbol lhsType = computeType(expr.getLeft().get()); + final NESTMLTypeSymbol rhsType = computeType(expr.getRight().get()); + + if (isNumeric(lhsType) && isNumeric(rhsType)) { + if (lhsType.equals(typesFactory.getRealType()) || + rhsType.equals(typesFactory.getRealType()) || + lhsType.getType().equals(NESTMLTypeSymbol.Type.UNIT) || + rhsType.getType().equals(NESTMLTypeSymbol.Type.UNIT)) { + return typesFactory.getRealType(); + } + // e.g. both are integers, but check to be sure + if (lhsType.equals(typesFactory.getIntegerType()) || + rhsType.equals(typesFactory.getIntegerType())) { + return typesFactory.getIntegerType(); + } + + final String errorMsg = "Cannot determine the type of the Expression-Node @<" + + expr.get_SourcePositionStart() + ", " + expr.get_SourcePositionEnd(); + + throw new RuntimeException(errorMsg); + } + else { + final String errorMsg = "Cannot determine the type of the Expression-Node at" + + expr.get_SourcePositionStart() + ", " + expr.get_SourcePositionEnd() ; + throw new RuntimeException(errorMsg); + } + + } + else if (expr.isPow()) { + Preconditions.checkState(expr.getBase().isPresent()); + Preconditions.checkState(expr.getExponent().isPresent()); + final NESTMLTypeSymbol baseType = computeType(expr.getBase().get()); + final NESTMLTypeSymbol exponentType = computeType(expr.getExponent().get()); + + if (!baseType.equals(typesFactory.getStringType()) && + !exponentType.equals(typesFactory.getStringType()) && + !baseType.equals(typesFactory.getBooleanType()) && + !exponentType.equals(typesFactory.getBooleanType()) && + !baseType.equals(typesFactory.getVoidType()) && + !exponentType.equals(typesFactory.getVoidType())) { + return typesFactory.getRealType(); + } + else { + + SPLPrettyPrinter prettyPrinter = SPLPrettyPrinterFactory.createDefaultPrettyPrinter(); + expr.accept(prettyPrinter); + final String errorMsg = "Cannot determine the type of the expression " + prettyPrinter.getResult() +" @<" + expr + .get_SourcePositionStart() + ", " + expr.get_SourcePositionStart() + ">"; + throw new RuntimeException(errorMsg); + } + + } + else if (expr.isShiftLeft() || + expr.isShiftRight() || + expr.isModuloOp() || + expr.isBitAnd() || + expr.isBitOr() || + expr.isBitAnd()) { + Preconditions.checkState(expr.getLeft().isPresent()); + Preconditions.checkState(expr.getRight().isPresent()); + + final NESTMLTypeSymbol lhsType = computeType(expr.getLeft().get()); + final NESTMLTypeSymbol rhsType = computeType(expr.getRight().get()); + + if (lhsType.equals(typesFactory.getIntegerType()) && + rhsType.equals(typesFactory.getIntegerType())) { + return typesFactory.getIntegerType(); + } + else { + final String errorMsg = "This operation expects both operands of the type integer @<" + expr.get_SourcePositionStart() + + ", " + expr.get_SourcePositionStart() + ">"; + + throw new RuntimeException(errorMsg); + } + } + else if (expr.isLt() || expr.isLe() || expr.isEq() || expr.isNe() || expr.isNe2() || expr.isGe() || expr.isGt()) { + final NESTMLTypeSymbol lhsType = computeType(expr.getLeft().get()); + final NESTMLTypeSymbol rhsType = computeType(expr.getRight().get()); + + if (isNumeric(lhsType) && isNumeric(rhsType)) { + return typesFactory.getBooleanType(); + } + else { + final String errorMsg = "This operation expects both operands of a numeric type @<" + expr.get_SourcePositionStart() + + ", " + expr.get_SourcePositionStart() + ">"; + + throw new RuntimeException(errorMsg); + } + } + + if (expr.getExpr().isPresent()) { + computeType(expr.getExpr().get()); + } + else if (expr.isLogicalAnd() || expr.isLogicalOr()) { + final NESTMLTypeSymbol lhsType = computeType(expr.getLeft().get()); + final NESTMLTypeSymbol rhsType = computeType(expr.getRight().get()); + if (lhsType.equals(typesFactory.getBooleanType()) && + rhsType.equals(typesFactory.getBooleanType())) { + return typesFactory.getBooleanType(); + } + else { + final String errorMsg = "Both operands of the logical expression must be boolean " + + "' @" + expr.get_SourcePositionStart() ; + + throw new RuntimeException(errorMsg); + } + + } + + SPLPrettyPrinter printer = SPLPrettyPrinterFactory.createDefaultPrettyPrinter(); + printer.print(expr); + final String errorMsg = "Cannot determine the type of the Expression-Node '" + printer.getResult() + + "' @" + expr.get_SourcePositionStart() ; + + throw new RuntimeException(errorMsg); + } + + /** + * Checks if the type is a numeric type, e.g. Integer or Real. + */ + private boolean isNumeric(NESTMLTypeSymbol type) { + return type.equals(typesFactory.getIntegerType()) || + type.equals(typesFactory.getRealType()) || + type.getType().equals(NESTMLTypeSymbol.Type.UNIT); + + } + +} diff --git a/src/main/java/org/nest/spl/symboltable/typechecking/TypeChecker.java b/src/main/java/org/nest/spl/symboltable/typechecking/TypeChecker.java new file mode 100644 index 000000000..c97151514 --- /dev/null +++ b/src/main/java/org/nest/spl/symboltable/typechecking/TypeChecker.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable.typechecking; + +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.logging.Log; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +/** + * Helper routine to calculate the category of the particular type. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class TypeChecker { + private final PredefinedTypesFactory predefinedTypesFactory; + + public TypeChecker(PredefinedTypesFactory predefinedTypesFactory) { + this.predefinedTypesFactory = predefinedTypesFactory; + } + + /** + * Checks that the {@code type} is a numeric type {@code Integer} or {@code Real}. + */ + public boolean checkNumber(NESTMLTypeSymbol type) { + return checkInteger(type) || checkReal(type); + } + + /** + * Checks that the {@code type} is an {@code Integer}. + */ + public boolean checkInteger(NESTMLTypeSymbol u) { + if (u != null) { + return u.getName().equals(predefinedTypesFactory.getIntegerType().getName()); + } + return false; + } + + /** + * Checks that the {@code type} is an {@code real}. + */ + public boolean checkReal(NESTMLTypeSymbol u) { + if (u != null) { + return u.getName().equals(predefinedTypesFactory.getRealType().getName()); + } + return false; + } + + public boolean checkVoid(NESTMLTypeSymbol type) { + if (type != null) { + return type.getName().equals(predefinedTypesFactory.getVoidType().getName()); + } + return false; + } + + public boolean checkString(NESTMLTypeSymbol type) { + if (type != null) { + return type.getName().equals(predefinedTypesFactory.getStringType().getName()); + } + return false; + } + + public boolean checkBoolean(NESTMLTypeSymbol type) { + if (type != null) { + return type.getName().equals(predefinedTypesFactory.getBooleanType().getName()); + } + return false; + } + + public boolean checkUnit(NESTMLTypeSymbol rType) { + Log.warn("!!!!!!!! boolean checkUnit(NESTMLTypeSymbol rType) unimplemented"); + return false; + } + +} diff --git a/src/main/java/org/nest/symboltable/ScopeCreatorBase.java b/src/main/java/org/nest/symboltable/ScopeCreatorBase.java new file mode 100644 index 000000000..7ab44ccbe --- /dev/null +++ b/src/main/java/org/nest/symboltable/ScopeCreatorBase.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable; + +import de.monticore.symboltable.GlobalScope; +import de.se_rwth.commons.logging.Log; +import org.nest.spl.symboltable.SPLScopeCreator; +import org.nest.symboltable.predefined.PredefinedFunctionFactory; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.predefined.PredefinedVariablesFactory; + +/** + * TODO + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since TODO + */ +public abstract class ScopeCreatorBase { + + protected final PredefinedTypesFactory typesFactory; + protected final PredefinedFunctionFactory functionFactory; + protected final PredefinedVariablesFactory variablesFactory; + + public abstract String getLogger(); + + public ScopeCreatorBase(final PredefinedTypesFactory typesFactory) { + this.typesFactory = typesFactory; + this.functionFactory = new PredefinedFunctionFactory(typesFactory); + this.variablesFactory = new PredefinedVariablesFactory(typesFactory); + } + + public PredefinedTypesFactory getTypesFactory() { + return typesFactory; + } + + public void addPredefinedTypes(final GlobalScope globalScope) { + typesFactory.getTypes().forEach( + type -> { + globalScope.define(type); + final String typeLogMsg = "Adds new implicit type declaration: %s"; + Log.info(String.format(typeLogMsg, type.getName()), getLogger()); + } + ); + } + + public void addPredefinedFunctions(final GlobalScope globalScope) { + + functionFactory.getMethodSymbols().forEach( + method -> { + globalScope.define(method); + final String methodLogMsg = String + .format("Adds new implicit method declaration: %s", method.getName()); + Log.info(methodLogMsg, getLogger()); + } + ); + } + + public void addPredefinedVariables(final GlobalScope globalScope) { + + variablesFactory.gerVariables().forEach( + variable -> { + globalScope.define(variable); + final String methodLogMsg = String + .format("Adds new implicit variable declaration: %s", variable.getName()); + Log.info(methodLogMsg, getLogger()); + } + ); + + } + +} diff --git a/src/main/java/org/nest/symboltable/predefined/PredefinedFunctionFactory.java b/src/main/java/org/nest/symboltable/predefined/PredefinedFunctionFactory.java new file mode 100644 index 000000000..9e144d3c2 --- /dev/null +++ b/src/main/java/org/nest/symboltable/predefined/PredefinedFunctionFactory.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.predefined; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import de.se_rwth.commons.Names; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; + +import java.util.Map; +import java.util.Set; + +/** + * Defines a set with implicit type functions, like {@code print, pow, ...} + * + * @author plotnikov + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class PredefinedFunctionFactory { + private static final String TIME_RESOLUTION = "Time.resolution"; + private static final String TIME_STEPS = "Time.steps"; + private static final String EMIT_SPIKE = "Spiking.emitSpike"; + private static final String PRINT = "print"; + private static final String PRINTLN = "println"; + private static final String POW = "pow"; + private static final String EXP = "exp"; + private static final String LOGGER_INFO = "Logger.info"; + private static final String RANDOM = "random"; + private static final String RANDOM_INT = "randomInt"; + private static final String EXPM1 = "expm1"; + + private final Map name2FunctionSymbol = Maps.newHashMap(); + + public PredefinedFunctionFactory(PredefinedTypesFactory typesFactory) { + + final NESTMLMethodSymbol timeSteps = createFunctionSymbol(TIME_STEPS); + timeSteps.addParameterType(typesFactory.getType("ms")); + timeSteps.setReturnType(typesFactory.getIntegerType()); + name2FunctionSymbol.put(TIME_STEPS, timeSteps); + + final NESTMLMethodSymbol emitSpike = createFunctionSymbol(EMIT_SPIKE); + emitSpike.setReturnType(typesFactory.getRealType()); + name2FunctionSymbol.put(EMIT_SPIKE, emitSpike); + + // create + final NESTMLMethodSymbol printMethod = createFunctionSymbol(PRINT); + printMethod.addParameterType(typesFactory.getStringType()); + printMethod.setReturnType(typesFactory.getVoidType()); + name2FunctionSymbol.put(PRINT, printMethod); + + final NESTMLMethodSymbol printlnMethod = createFunctionSymbol(PRINTLN); + printlnMethod.setReturnType(typesFactory.getVoidType()); + name2FunctionSymbol.put(PRINTLN, printlnMethod); + + final NESTMLMethodSymbol powMethod = createFunctionSymbol(POW); + powMethod.addParameterType(typesFactory.getRealType()); // base + powMethod.addParameterType(typesFactory.getRealType()); // exp + powMethod.setReturnType(typesFactory.getRealType()); + name2FunctionSymbol.put(POW, powMethod); + + final NESTMLMethodSymbol expMethod = createFunctionSymbol(EXP); + expMethod.addParameterType(typesFactory.getRealType()); // base + expMethod.setReturnType(typesFactory.getRealType()); + name2FunctionSymbol.put(EXP, expMethod); + + final NESTMLMethodSymbol loggerInfoMethod = createFunctionSymbol(LOGGER_INFO); + loggerInfoMethod.addParameterType(typesFactory.getStringType()); + loggerInfoMethod.setReturnType(typesFactory.getVoidType()); + name2FunctionSymbol.put(LOGGER_INFO, loggerInfoMethod); + + final NESTMLMethodSymbol randomMethod = createFunctionSymbol(RANDOM); + randomMethod.setReturnType(typesFactory.getRealType()); + name2FunctionSymbol.put(RANDOM, randomMethod); + + final NESTMLMethodSymbol randomIntMethod = createFunctionSymbol(RANDOM_INT); + randomIntMethod.setReturnType(typesFactory.getIntegerType()); + name2FunctionSymbol.put(RANDOM_INT, randomIntMethod); + + final NESTMLMethodSymbol timeResolution = createFunctionSymbol(TIME_RESOLUTION); + timeResolution.setReturnType(typesFactory.getRealType()); + name2FunctionSymbol.put(TIME_RESOLUTION, timeResolution); + + final NESTMLMethodSymbol expm1 = createFunctionSymbol(EXPM1); + expm1.addParameterType(typesFactory.getRealType()); + expm1.setReturnType(typesFactory.getRealType()); + name2FunctionSymbol.put(EXPM1, expm1); + + } + + private static NESTMLMethodSymbol createFunctionSymbol(final String functionName) { + final String packageName = Names.getQualifier(functionName); + final String simpleFunctionName = Names.getSimpleName(functionName); + final NESTMLMethodSymbol functionSymbol = new NESTMLMethodSymbol(simpleFunctionName); + functionSymbol.setPackageName(packageName); + return functionSymbol; + } + + public Set getMethodSymbols() { + return ImmutableSet.copyOf(name2FunctionSymbol.values()); + } + +} diff --git a/src/main/java/org/nest/symboltable/predefined/PredefinedTypesFactory.java b/src/main/java/org/nest/symboltable/predefined/PredefinedTypesFactory.java new file mode 100644 index 000000000..f3b6a2299 --- /dev/null +++ b/src/main/java/org/nest/symboltable/predefined/PredefinedTypesFactory.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.predefined; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +/** + * Creates implicit types like boolean and nestml specific types like Logger + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class PredefinedTypesFactory { + + private final static Map implicitTypes = Maps.newHashMap(); + + public PredefinedTypesFactory() { + registerType("mV", NESTMLTypeSymbol.Type.UNIT); + registerType("pA", NESTMLTypeSymbol.Type.UNIT); + registerType("pF", NESTMLTypeSymbol.Type.UNIT); + registerType("pF", NESTMLTypeSymbol.Type.UNIT); + registerType("ms", NESTMLTypeSymbol.Type.UNIT); + registerType("mm", NESTMLTypeSymbol.Type.UNIT); + + registerType("real", NESTMLTypeSymbol.Type.PRIMITIVE); + registerType("integer", NESTMLTypeSymbol.Type.PRIMITIVE); + registerType("boolean", NESTMLTypeSymbol.Type.PRIMITIVE); + registerType("string", NESTMLTypeSymbol.Type.PRIMITIVE); + registerType("void", NESTMLTypeSymbol.Type.PRIMITIVE); + + registerBufferType(); + } + + private void registerBufferType() { + final NESTMLTypeSymbol bufferType + = new NESTMLTypeSymbol("Buffer", NESTMLTypeSymbol.Type.PRIMITIVE); + implicitTypes.put("Buffer", bufferType); + + final NESTMLMethodSymbol getSumMethod = new NESTMLMethodSymbol("getSum"); + getSumMethod.addParameterType(getPredefinedTypeIfExists("ms").get()); // TODO smell + getSumMethod.setReturnType(getRealType()); + + getSumMethod.setDeclaringType(bufferType); + bufferType.addBuiltInMethod(getSumMethod); + } + + public NESTMLTypeSymbol getBooleanType() { + return implicitTypes.get("boolean"); + } + + // predefined types + public NESTMLTypeSymbol getVoidType() { + return implicitTypes.get("void"); + } + + public NESTMLTypeSymbol getStringType() { + return implicitTypes.get("string"); + } + + public NESTMLTypeSymbol getRealType() { + return implicitTypes.get("real"); + } + + public NESTMLTypeSymbol getIntegerType() { + return implicitTypes.get("integer"); + } + + public NESTMLTypeSymbol getBufferType() { + return implicitTypes.get("Buffer"); + } + + + private NESTMLTypeSymbol registerType(String modelName, NESTMLTypeSymbol.Type type) { + NESTMLTypeSymbol typeSymbol = new NESTMLTypeSymbol(modelName, type); + typeSymbol.setPackageName(""); + implicitTypes.put(modelName, typeSymbol); + return typeSymbol; + } + + public Collection getTypes() { + return ImmutableList.copyOf(implicitTypes.values()); + } + + public NESTMLTypeSymbol getType(final String typeName) { + Optional predefinedType = getPredefinedTypeIfExists(typeName); + if (predefinedType.isPresent()) { + return predefinedType.get(); + } + else { + throw new RuntimeException("Cannot resolve the predefined type: " + typeName); + } + } + + public Optional getPredefinedTypeIfExists(final String typeName) { + + if (implicitTypes.containsKey(typeName)) { + return Optional.of(implicitTypes.get(typeName)); + } + else { + return Optional.empty(); + } + + } + +} diff --git a/src/main/java/org/nest/symboltable/predefined/PredefinedVariablesFactory.java b/src/main/java/org/nest/symboltable/predefined/PredefinedVariablesFactory.java new file mode 100644 index 000000000..db4cf59be --- /dev/null +++ b/src/main/java/org/nest/symboltable/predefined/PredefinedVariablesFactory.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.predefined; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.Map; +import java.util.Set; + +/** + * Defines a set with implicit type functions, like {@code print, pow, ...} + * + * @author plotnikov + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class PredefinedVariablesFactory { + private static final String E_CONSTANT = "E"; + private static final NESTMLNeuronSymbol predefinedComponent = new NESTMLNeuronSymbol("Math", + NESTMLNeuronSymbol.Type.COMPONENT); + + private final Map name2VariableSymbol = Maps.newHashMap(); + + public PredefinedVariablesFactory(PredefinedTypesFactory predefinedTypesFactory) { + registerVariable(E_CONSTANT, predefinedTypesFactory.getType("real")); + + } + + private void registerVariable( + final String variableName, final NESTMLTypeSymbol type) { + final NESTMLVariableSymbol variableSymbol = new NESTMLVariableSymbol(variableName); + variableSymbol.setDeclaringType(predefinedComponent); + variableSymbol.setType(type); + name2VariableSymbol.put(variableName, variableSymbol); + } + + public Set gerVariables() { + return ImmutableSet.copyOf(name2VariableSymbol.values()); + } + +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLMethodSymbol.java b/src/main/java/org/nest/symboltable/symbols/NESTMLMethodSymbol.java new file mode 100644 index 000000000..4783a5f32 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLMethodSymbol.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import de.monticore.symboltable.CommonScopeSpanningSymbol; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents functions, e.g. dynamics, getter/setter, and predefined functions like pow. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLMethodSymbol extends CommonScopeSpanningSymbol { + + public final static NESTMLMethodSymbolKind KIND = new NESTMLMethodSymbolKind(); + + protected NESTMLTypeSymbol returnType; + + protected NESTMLNeuronSymbol declaringNeuron; + + protected NESTMLTypeSymbol declaringType; + + protected List parameters = new ArrayList(); + + protected boolean isDynamics = false; + + protected boolean isTimeStep = false; + + protected boolean isMinDelay = false; + + public NESTMLMethodSymbol(String name) { + super(name, KIND); + } + + @Override + public String toString() { + return "NESTMLMethodSymbol(" + getName() + ", #Parameters = " + getParameterTypes().size() + ")"; + } + + public NESTMLTypeSymbol getReturnType() { + return returnType; + } + + public void setReturnType(NESTMLTypeSymbol returnType) { + this.returnType = returnType; + } + + public NESTMLNeuronSymbol getDeclaringNeuron() { + return declaringNeuron; + } + + public void setDeclaringType(NESTMLNeuronSymbol declaringType) { + this.declaringNeuron = declaringType; + } + + public NESTMLTypeSymbol getDeclaringType() { + return declaringType; + } + + public void setDeclaringType(NESTMLTypeSymbol declaringType) { + this.declaringType = declaringType; + } + + public List getParameterTypes() { + return parameters; + } + + public void addParameterType(NESTMLTypeSymbol parameter) { + this.parameters.add(parameter); + } + + public boolean isDynamics() { + return isDynamics; + } + + public void setDynamics(boolean isDynamics) { + this.isDynamics = isDynamics; + } + + public boolean isTimeStep() { + return isTimeStep; + } + + public void setTimeStep(boolean isTimeStep) { + this.isTimeStep = isTimeStep; + } + + public boolean isMinDelay() { + return isMinDelay; + } + + public void setMinDelay(boolean isMinDelay) { + this.isMinDelay = isMinDelay; + } +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLMethodSymbolKind.java b/src/main/java/org/nest/symboltable/symbols/NESTMLMethodSymbolKind.java new file mode 100644 index 000000000..b8c559f84 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLMethodSymbolKind.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import de.monticore.symboltable.SymbolKind; + +/** + * KIND Class for the {@code NESTMLMethodSymbol}. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLMethodSymbolKind extends SymbolKind { + + protected NESTMLMethodSymbolKind() { + } + +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLNeuronSymbol.java b/src/main/java/org/nest/symboltable/symbols/NESTMLNeuronSymbol.java new file mode 100644 index 000000000..9cb49f9cb --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLNeuronSymbol.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import de.monticore.symboltable.CommonScopeSpanningSymbol; +import de.monticore.symboltable.Symbol; +import org.nest.nestml._symboltable.NESTMLMethodSignaturePredicate; + +import java.util.List; +import java.util.Optional; + +/** + * Represents the entire neuron, e.g. iaf_neuron. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLNeuronSymbol extends CommonScopeSpanningSymbol { + + public final static NESTMLNeuronSymbolKind KIND = new NESTMLNeuronSymbolKind(); + + private final Type type; + + public NESTMLNeuronSymbol(final String name, final Type type) { + super(name, KIND); + this.type = type; + } + + public Type getType() { + return type; + } + + @Override + public String toString() { + return "NESTMLNeuronSymbol(" + getFullName() + "," + type + ")"; + } + + public Optional getVariableByName(String variableName) { + return spannedScope.resolveLocally(variableName, NESTMLVariableSymbol.KIND); + } + + public Optional getMethodByName(String methodName) { + return getMethodByName(methodName, Lists.newArrayList()); + } + + @SuppressWarnings("unchecked") // Resolving filter does the type checking + public Optional getMethodByName(String methodName, List parameters) { + final Optional result + = spannedScope.resolve(new NESTMLMethodSignaturePredicate(methodName, parameters)); + if (result.isPresent()) { + Preconditions.checkState(result.get() instanceof NESTMLMethodSymbol); + } + + return (Optional) result; + } + + public enum Type { NEURON, COMPONENT } +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLNeuronSymbolKind.java b/src/main/java/org/nest/symboltable/symbols/NESTMLNeuronSymbolKind.java new file mode 100644 index 000000000..7f2656f08 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLNeuronSymbolKind.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import de.monticore.symboltable.SymbolKind; + +/** + * KIND Class for the {@code NESTMLTypeSymbolKind}. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLNeuronSymbolKind extends SymbolKind { + + protected NESTMLNeuronSymbolKind() { + } + +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLTypeSymbol.java b/src/main/java/org/nest/symboltable/symbols/NESTMLTypeSymbol.java new file mode 100644 index 000000000..b00ce0139 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLTypeSymbol.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import com.google.common.collect.Lists; +import de.monticore.symboltable.CommonSymbol; + +import java.util.Collection; +import java.util.Optional; + +import static java.util.Optional.empty; + +/** + * Represents an entire neuron or component. E.g. for + * + * {@code neuron A: end} + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLTypeSymbol extends CommonSymbol { + + public final static NESTMLTypeSymbolKind KIND = new NESTMLTypeSymbolKind(); + + private final static Collection builtInMethods = Lists.newArrayList(); + + private final Type type; + + public NESTMLTypeSymbol(final String name, final Type type) { + super(name, KIND); + this.type = type; + } + + public Type getType() { + return type; + } + + public void addBuiltInMethod(final NESTMLMethodSymbol builtInMethod) { + builtInMethods.add(builtInMethod); + } + + public Optional getBuiltInMethod(final String methodName) { + // TODO signature must be considered + return builtInMethods.stream().filter(method -> method.getName().equals(methodName)).findFirst(); + } + + @Override + public String toString() { + return "NESTMLTypeSymbol(" + getFullName() + "," + type + ")"; + } + + public enum Type { UNIT, PRIMITIVE} +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLTypeSymbolKind.java b/src/main/java/org/nest/symboltable/symbols/NESTMLTypeSymbolKind.java new file mode 100644 index 000000000..0f776829b --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLTypeSymbolKind.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import de.monticore.symboltable.SymbolKind; + +/** + * KIND Class for the {@code NESTMLTypeSymbolKind}. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLTypeSymbolKind extends SymbolKind { + + protected NESTMLTypeSymbolKind() { + } + +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLUsageSymbol.java b/src/main/java/org/nest/symboltable/symbols/NESTMLUsageSymbol.java new file mode 100644 index 000000000..7051cbcdc --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLUsageSymbol.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import de.monticore.symboltable.CommonSymbol; + +/** + * Represents the entire neuron, e.g. iaf_neuron. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLUsageSymbol extends CommonSymbol { + public final static NESTMLUsageSymbolKind KIND = new NESTMLUsageSymbolKind(); + private final String usageName; + private final NESTMLNeuronSymbol referencedSymbol; + + public NESTMLUsageSymbol(final String usageName, final NESTMLNeuronSymbol referencedSymbol) { + super(usageName, KIND); + this.referencedSymbol = referencedSymbol; + this.usageName = usageName; + } + + @Override + public String toString() { + return "NESTMLUsageSymbol(" + getFullName() + ")"; + } + + public NESTMLNeuronSymbol getReferencedSymbol() { + return referencedSymbol; + } +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLUsageSymbolKind.java b/src/main/java/org/nest/symboltable/symbols/NESTMLUsageSymbolKind.java new file mode 100644 index 000000000..51f25ee68 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLUsageSymbolKind.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import de.monticore.symboltable.SymbolKind; + +/** + * KIND Class for the {@code NESTMLTypeSymbolKind}. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLUsageSymbolKind extends SymbolKind { + + protected NESTMLUsageSymbolKind() { + } + +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLVariableSymbol.java b/src/main/java/org/nest/symboltable/symbols/NESTMLVariableSymbol.java new file mode 100644 index 000000000..d5c689669 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLVariableSymbol.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import de.monticore.symboltable.CommonSymbol; + +import java.util.Optional; + +import static java.util.Optional.empty; + +/** + * Represents variables in neuron and functions. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLVariableSymbol extends CommonSymbol { + + public enum BlockType {STATE, PARAMETER, INTERNAL, LOCAL, BUFFER} + + public static final NESTMLVariableSymbolKind KIND = new NESTMLVariableSymbolKind(); + + private NESTMLTypeSymbol type; + + private NESTMLNeuronSymbol declaringType; + + private boolean isAlias; + + private boolean isHidden; + + private BlockType blockType; + + private Optional arraySizeParameter = empty(); + + public Optional getArraySizeParameter() { + return arraySizeParameter; + } + + public void setArraySizeParameter(String arraySizeParameter) { + this.arraySizeParameter = Optional.of(arraySizeParameter); + } + + public NESTMLVariableSymbol(String name) { + super(name, KIND); + setBlockType(BlockType.LOCAL); + } + + @Override + public String toString() { + return "NESTMLVariableSymbol(" + getName() + ", " + getType() + ", " + + getBlockType() + "," + arraySizeParameter + ")"; + } + + public NESTMLTypeSymbol getType() { + return type; + } + + public void setType(NESTMLTypeSymbol type) { + this.type = type; + } + + public void setDeclaringType(NESTMLNeuronSymbol declaringType) { + this.declaringType = declaringType; + } + + public NESTMLNeuronSymbol getDeclaringType() { + return declaringType; + } + + + public boolean isAlias() { + return isAlias; + } + + public void setAlias(boolean isAlias) { + this.isAlias = isAlias; + } + + public BlockType getBlockType() { + return blockType; + } + + public void setBlockType(BlockType blockType) { + this.blockType = blockType; + } + + public boolean isHidden() { + return isHidden; + } + + public void setHidden(boolean isHidden) { + this.isHidden = isHidden; + } + +} diff --git a/src/main/java/org/nest/symboltable/symbols/NESTMLVariableSymbolKind.java b/src/main/java/org/nest/symboltable/symbols/NESTMLVariableSymbolKind.java new file mode 100644 index 000000000..e8c810bd9 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/NESTMLVariableSymbolKind.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols; + +import de.monticore.symboltable.SymbolKind; + +/** + * KIND Class for the {@code NESTMLVariableSymbol}. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLVariableSymbolKind extends SymbolKind { + + protected NESTMLVariableSymbolKind() { + } + +} diff --git a/src/main/java/org/nest/symboltable/symbols/references/NESTMLNeuronSymbolReference.java b/src/main/java/org/nest/symboltable/symbols/references/NESTMLNeuronSymbolReference.java new file mode 100644 index 000000000..8349cdd49 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/references/NESTMLNeuronSymbolReference.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols.references; + +import de.monticore.symboltable.Scope; +import de.monticore.symboltable.references.CommonSymbolReference; +import de.monticore.symboltable.references.SymbolReference; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; + +/** + * Represents a reference to a nestml type. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLNeuronSymbolReference extends NESTMLNeuronSymbol implements SymbolReference { + + private final SymbolReference typeReference; + + public NESTMLNeuronSymbolReference(final String name, NESTMLNeuronSymbol.Type type, Scope definingScopeOfReference) { + super(name, type); + typeReference = new CommonSymbolReference<>(name, NESTMLNeuronSymbol.KIND, definingScopeOfReference); + } + + @Override + public NESTMLNeuronSymbol getReferencedSymbol() { + return typeReference.getReferencedSymbol(); + } + + @Override + public boolean existsReferencedSymbol() { + return typeReference.existsReferencedSymbol(); + } + + @Override public boolean isReferencedSymbolLoaded() { + return typeReference.isReferencedSymbolLoaded(); + } + + @Override + public String getName() { + return typeReference.getReferencedSymbol().getName(); + } + + @Override + public Type getType() { + return typeReference.getReferencedSymbol().getType(); + } + + +} diff --git a/src/main/java/org/nest/symboltable/symbols/references/NESTMLTypeSymbolReference.java b/src/main/java/org/nest/symboltable/symbols/references/NESTMLTypeSymbolReference.java new file mode 100644 index 000000000..a1d82e597 --- /dev/null +++ b/src/main/java/org/nest/symboltable/symbols/references/NESTMLTypeSymbolReference.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.symboltable.symbols.references; + +import de.monticore.symboltable.Scope; +import de.monticore.symboltable.references.CommonSymbolReference; +import de.monticore.symboltable.references.SymbolReference; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +/** + * Represents a reference to a nestml type. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLTypeSymbolReference extends NESTMLTypeSymbol implements + SymbolReference { + + private final SymbolReference typeReference; + + public NESTMLTypeSymbolReference(final String name, Type type, Scope definingScopeOfReference) { + super(name, type); + typeReference = new CommonSymbolReference<>(name, NESTMLTypeSymbol.KIND, definingScopeOfReference); + } + + @Override + public NESTMLTypeSymbol getReferencedSymbol() { + return typeReference.getReferencedSymbol(); + } + + @Override + public boolean existsReferencedSymbol() { + return typeReference.existsReferencedSymbol(); + } + + @Override public boolean isReferencedSymbolLoaded() { + return typeReference.isReferencedSymbolLoaded(); + } + + @Override + public String getName() { + return typeReference.getReferencedSymbol().getName(); + } + + @Override + public Type getType() { + return typeReference.getReferencedSymbol().getType(); + } + + +} diff --git a/src/main/java/org/nest/utils/ASTNodes.java b/src/main/java/org/nest/utils/ASTNodes.java new file mode 100644 index 000000000..9d0cbd91d --- /dev/null +++ b/src/main/java/org/nest/utils/ASTNodes.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.utils; + +import com.google.common.collect.Lists; +import de.se_rwth.commons.Names; +import org.nest.nestml._visitor.NESTMLInheritanceVisitor; +import org.nest.spl._ast.*; +import org.nest.spl._visitor.SPLInheritanceVisitor; +import org.nest.spl.symboltable.typechecking.ExpressionTypeCalculator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import java.util.Collection; +import java.util.List; + +/** + * Helper class containing common operations concerning ASTNodes + * + * @author Sebastian Oberhoff + */ +public final class ASTNodes { + + private ASTNodes() { + // noninstantiable + } + + public static List getVariablesNamesFromAst(final ASTSPLNode astNode) { + final FQNCollector fqnCollector = new FQNCollector(); + astNode.accept(fqnCollector); + return fqnCollector.getVariableNames(); + } + + private final static class SPLNodesCollector implements SPLInheritanceVisitor { + + private List returnStmts = Lists.newArrayList(); + + public void startVisitor(ASTBlock blockAst) { + blockAst.accept(this); + } + + @Override + public void visit(ASTReturnStmt astReturnStmt) { + returnStmts.add(astReturnStmt); + } + + public List getReturnStmts() { + return returnStmts; + } + } + + public static List getReturnStatements(ASTBlock blockAst) { + final SPLNodesCollector splNodesCollector = new SPLNodesCollector(); + splNodesCollector.startVisitor(blockAst); + return splNodesCollector.getReturnStmts(); + } + + static final class FQNCollector implements NESTMLInheritanceVisitor { + public List getVariableNames() { + return variableNames; + } + + final private List variableNames = Lists.newArrayList(); + + @Override + public void visit(final ASTExpr astExpr) { + if (astExpr.getQualifiedName().isPresent()) { + final String variableName = Names.getQualifiedName(astExpr.getQualifiedName().get().getParts()); + variableNames.add(variableName); + + } + + } + + } + + public static List getArgumentsTypes( + final ASTFunctionCall astFunctionCall, + final PredefinedTypesFactory typesFactory) { + final List argTypeNames = Lists.newArrayList(); + + final ExpressionTypeCalculator typeCalculator = new ExpressionTypeCalculator(typesFactory); + + for (int i = 0; i < astFunctionCall.getArgList().getArgs().size(); ++i) { + final ASTExpr arg = astFunctionCall.getArgList().getArgs().get(i); + final NESTMLTypeSymbol argType = typeCalculator.computeType(arg); + argTypeNames.add(argType.getName()); + } + + return argTypeNames; + } + +} diff --git a/src/main/java/org/nest/utils/CachedResolver.java b/src/main/java/org/nest/utils/CachedResolver.java new file mode 100644 index 000000000..d723514f6 --- /dev/null +++ b/src/main/java/org/nest/utils/CachedResolver.java @@ -0,0 +1,40 @@ +package org.nest.utils; + +import com.google.common.collect.Maps; +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.logging.Log; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import java.util.Map; +import java.util.Optional; + +/** + * Resolves the symbol by name if not already resolved. + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since 0.0.1 + */ +public class CachedResolver { + private static final String LOG_NAME = CachedResolver.class.getName(); + final Map cache = Maps.newHashMap(); + + /** + * Resolves the symbol by name if not already resolved. + * @return + */ + public Optional resolveAndCache(Scope scope, String typeName) { + if (cache.containsKey(typeName)) { + Log.trace("Uses the cached symbol version: " + typeName, LOG_NAME); + return Optional.of(cache.get(typeName)); + } + else { + Optional typeSymbol = scope.resolve(typeName, NESTMLTypeSymbol.KIND); + if (typeSymbol.isPresent()) { + cache.put(typeName, typeSymbol.get()); + } + return typeSymbol; + } + + } +} diff --git a/src/main/java/org/nest/utils/LogHelper.java b/src/main/java/org/nest/utils/LogHelper.java new file mode 100644 index 000000000..6a6898d0f --- /dev/null +++ b/src/main/java/org/nest/utils/LogHelper.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.utils; + +import com.google.common.collect.Lists; +import de.monticore.cocos.CoCoFinding; +import de.monticore.cocos.CoCoLog; + +import java.util.Collection; + +/** + * Provides convenient method to work with error messages coming from {@code Log}. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class LogHelper { + /** + * + * @return Number of {@code errorCode}s occurrences in {@code findings} + */ + public static Integer countOccurrences(String errorCode, Collection findings) { + Long occurrences = findings.stream().filter(error -> error.getCode().equals(errorCode)).count(); + // it is unlikely that the number of issues is greater than the domain of int! Integer result = 0; + return safeLongToInt(occurrences); + + } + + /** + * + * @return Number of {@code errorCode}s occurrences in {@code findings} + */ + public static Integer countOccurrencesByPrefix(String errorCode, Collection findings) { + Long occurrences = findings.stream().filter(error -> error.getCode().startsWith(errorCode)).count(); + // it is unlikely that the number of issues is greater than the domain of int! Integer result = 0; + return safeLongToInt(occurrences); + + } + + + /** + * + * @return Number of {@code errorCode}s occurrences in {@code findings} + */ + public static Collection getFindingsByPrefix(String prefix, Collection findings) { + final Collection result = Lists.newArrayList(); + findings.forEach(e -> { + if (e.getCode().startsWith(prefix)) { + result.add(e.getCode() + ":" + e.getMsg() + ":" + e.getSourcePosition()); + } + }); + // it is unlikely that the number of issues is greater than the domain of int! Integer result = 0; + return result; + + } + + /** + * Converts long value to int under the conditions that the long value is representable + * as an int. + * @throws IllegalArgumentException if the {@l} is greater than the biggest int + */ + private static int safeLongToInt(long l) { + if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { + throw new IllegalArgumentException + (l + " cannot be cast to int without changing its value."); + } + return (int) l; + } +} diff --git a/src/main/java/org/nest/utils/NESTMLSymbols.java b/src/main/java/org/nest/utils/NESTMLSymbols.java new file mode 100644 index 000000000..cf5ee1f8e --- /dev/null +++ b/src/main/java/org/nest/utils/NESTMLSymbols.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.utils; + +import de.monticore.symboltable.Scope; +import de.se_rwth.commons.Names; +import org.nest.nestml._symboltable.NESTMLMethodSignaturePredicate; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.List; +import java.util.Optional; + +/** + * Provides convenience methods + * + * @author (last commit) $Author$ + * @version $Revision$, $Date$ + * @since 0.0.1 + */ +public class NESTMLSymbols { + + public static Optional resolveMethod( + final Scope scope, + final String methodName, + final List parameters) { + // it is OK. The cast is secured through the symboltable infrastructure + @SuppressWarnings("unchecked") + final Optional standAloneFunction = (Optional) + scope.resolve(new NESTMLMethodSignaturePredicate(methodName, parameters)); + + final String calleeVariableNameCandidate = Names.getQualifier(methodName); + final String simpleMethodName = Names.getSimpleName(methodName); + + if (!calleeVariableNameCandidate.isEmpty()) { + final Optional calleeVariableSymbol + = scope.resolve(calleeVariableNameCandidate, NESTMLVariableSymbol.KIND); + if (calleeVariableSymbol.isPresent()) { + + final Optional builtInMethod + = calleeVariableSymbol.get().getType().getBuiltInMethod(simpleMethodName); // TODO parameters are not considered! + if (standAloneFunction.isPresent() && builtInMethod.isPresent()) { + final String errorDescription = "Unambiguous function exception. Function '" + + simpleMethodName + "'. Can be resolved as a standalone function and as a method of: '" + + calleeVariableSymbol + "' variable."; + + throw new RuntimeException(errorDescription); + } + + if (builtInMethod.isPresent()) { + return builtInMethod; + } + + } + + } + + return standAloneFunction; + } + +} diff --git a/src/main/java/org/nest/utils/PrettyPrinterBase.java b/src/main/java/org/nest/utils/PrettyPrinterBase.java new file mode 100644 index 000000000..c1b637817 --- /dev/null +++ b/src/main/java/org/nest/utils/PrettyPrinterBase.java @@ -0,0 +1,60 @@ +package org.nest.utils; + +/** + * Created by user on 31.05.15. + */ +public class PrettyPrinterBase { + protected static final String BLOCK_CLOSE = "end"; + + protected static final String BLOCK_OPEN = ":"; + + private String result = ""; + + private int indentionLevel = 0; + + private String indent = ""; + + public void setIndentionLevel(int indentionLevel) { + this.indentionLevel = indentionLevel; + } + + public int getIndentionLevel() { + return indentionLevel; + } + + public void print(String s) { + result += (indent + s); + indent = ""; + } + + public void println() { + println(""); + } + + public void println(String s) { + result += (indent + s + "\n"); + indent = ""; + calcIndention(); + } + + public void calcIndention() { + indent = ""; + for (int i = 0; i < indentionLevel; i++) { + indent += " "; + } + } + + public void indent() { + indentionLevel++; + calcIndention(); + } + + public void unindent() { + indentionLevel--; + calcIndention(); + } + + public String getResult() { + return result; + } +} diff --git a/src/main/resources/org/nest/nestml/MemberDeclaration.ftl b/src/main/resources/org/nest/nestml/MemberDeclaration.ftl new file mode 100644 index 000000000..76dfd3edf --- /dev/null +++ b/src/main/resources/org/nest/nestml/MemberDeclaration.ftl @@ -0,0 +1,12 @@ +<#-- + Generates C++ declaration + @grammar: Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTDeclaration + @param tc templatecontroller + @result TODO +--> +<#assign declarationType = declarations.getDeclarationType(ast)> + +<#list ast.getVars() as variableName> +${declarationType} ${variableName}_; + diff --git a/src/main/resources/org/nest/nestml/buffer/CurrentBufferFill.ftl b/src/main/resources/org/nest/nestml/buffer/CurrentBufferFill.ftl new file mode 100644 index 000000000..113bf50f4 --- /dev/null +++ b/src/main/resources/org/nest/nestml/buffer/CurrentBufferFill.ftl @@ -0,0 +1,9 @@ +<#-- + @param ast ASTInputLine + @param tc templatecontroller + @result TODO +--> +<#if ast.isCurrent()> +get_${ast.getName()}().add_value(e.get_rel_delivery_steps( network()->get_slice_origin()), + weight * current ); + diff --git a/src/main/resources/org/nest/nestml/buffer/SpikeBufferFill.ftl b/src/main/resources/org/nest/nestml/buffer/SpikeBufferFill.ftl new file mode 100644 index 000000000..322133353 --- /dev/null +++ b/src/main/resources/org/nest/nestml/buffer/SpikeBufferFill.ftl @@ -0,0 +1,43 @@ +<#-- + @param ast ASTInputLine + @grammar + InputLine = + Name + ("<" sizeParameter:Name ">")? + "<-" InputType* + (["spike"] | ["current"]); + + InputType = (["inhibitory"] | ["excitatory"]); + @result +--> +<#if ast.isSpike()> + // TODO do i need this? + //get_${ast.getName()}().add_value(e.get_rel_delivery_steps( network()->get_slice_origin()), + // weight * multiplicity ); + <#if bufferHelper.isVector(ast)> + for (size_t i=0; i < P_.${bufferHelper.vectorParameter(ast)}; i++) + { + if (B_.receptor_types_${ast.getName()}[i] == e.get_rport()) { + get_${ast.getName()}()[i].add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), + e.get_weight() * e.get_multiplicity()); + } + + } + <#else> + + <#if bufferHelper.isExcitatory(ast)> + if ( weight >= 0.0 ) // excitatory + { + get_${ast.getName()}().add_value(e.get_rel_delivery_steps( network()->get_slice_origin()), + weight * multiplicity ); + } + + <#if bufferHelper.isInhibitory(ast)> + if ( weight < 0.0 ) // inhibitory + { + get_${ast.getName()}().add_value(e.get_rel_delivery_steps( network()->get_slice_origin()), + weight * multiplicity ); + } + + + diff --git a/src/main/resources/org/nest/nestml/function/Calibrate.ftl b/src/main/resources/org/nest/nestml/function/Calibrate.ftl new file mode 100644 index 000000000..c084aa4a0 --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/Calibrate.ftl @@ -0,0 +1,32 @@ +<#-- + Generates C++ declaration + @grammar: AliasDecl = ([hide:"-"])? ([alias:"alias"])? + Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTAliasDecl + @param tc templatecontroller + @result TODO +--> +<#list declarations.getVariables(ast) as var> +<#if declarations.isVectorType(ast)> +for (size_t i=0; i < get_num_of_receptors(); i++) { + get_${var.getName()}()[i] = + <#if ast.getDeclaration().getExpr().isPresent()> + ${tc.include("org.nest.spl.expr.Expr", ast.getDeclaration().getExpr().get())} + <#else> + 0 + + ; +} +<#else> +set_${var.getName()}( + <#if ast.getDeclaration().getExpr().isPresent()> + ${tc.include("org.nest.spl.expr.Expr", ast.getDeclaration().getExpr().get())} + <#else> + 0 + ); + + + + + diff --git a/src/main/resources/org/nest/nestml/function/DynamicsImplementation.ftl b/src/main/resources/org/nest/nestml/function/DynamicsImplementation.ftl new file mode 100644 index 000000000..15933159e --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/DynamicsImplementation.ftl @@ -0,0 +1,14 @@ +<#-- + Generates C++ declaration + @grammar: Dynamics implements BodyElement = "dynamics" (MinDelay | TimeStep) + "(" Parameters? ")" + BLOCK_OPEN Block BLOCK_CLOSE; + @param ast ASTDynamics + @param tc templatecontroller + @result TODO +--> +<#if ast.getMinDelay().isPresent()> +${tc.include("org.nest.nestml.function.MinDelayDynamics", ast)} +<#elseif ast.getTimeStep().isPresent()> +${tc.include("org.nest.nestml.function.TimestepDynamics", ast)} + \ No newline at end of file diff --git a/src/main/resources/org/nest/nestml/function/Invariant.ftl b/src/main/resources/org/nest/nestml/function/Invariant.ftl new file mode 100644 index 000000000..c461d33f5 --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/Invariant.ftl @@ -0,0 +1,12 @@ +<#-- + Generates C++ declaration + @grammar: AliasDecl = ([hide:"-"])? ([alias:"alias"])? + Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTAliasDecl + @param tc templatecontroller + @result TODO +--> +if ( !(${tc.include("org.nest.spl.expr.Expr", ast)}) ) { + throw nest::BadProperty("Message"); +} \ No newline at end of file diff --git a/src/main/resources/org/nest/nestml/function/MemberInitialization.ftl b/src/main/resources/org/nest/nestml/function/MemberInitialization.ftl new file mode 100644 index 000000000..ffed20653 --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/MemberInitialization.ftl @@ -0,0 +1,19 @@ +<#-- + Generates C++ declaration + @grammar: Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTDeclaration + @param tc templatecontroller + @result TODO +--> + +<#-- : C_ (250.0 ), // pF--> +<#assign start=""> + +<#list ast.getDeclaration().getVars() as varname> + <#if ast.getDeclaration().getExpr().isPresent()> + ${start} ${varname}_( ${tc.include("org.nest.spl.expr.Expr", ast.getDeclaration().getExpr().get())} ) // ${ast.getDeclaration().getType()} + <#else> + ${start} ${varname}_() // ${ast.getDeclaration().getType()} + + <#assign start=","> + diff --git a/src/main/resources/org/nest/nestml/function/MemberVariableGetterSetter.ftl b/src/main/resources/org/nest/nestml/function/MemberVariableGetterSetter.ftl new file mode 100644 index 000000000..7d1fe5cc6 --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/MemberVariableGetterSetter.ftl @@ -0,0 +1,26 @@ +<#-- + Generates C++ declaration + @grammar: AliasDecl = ([hide:"-"])? ([alias:"alias"])? + Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTAliasDecl + @param tc templatecontroller + @result TODO +--> +<#list declarations.getVariables(ast) as var> + <#if !var.isAlias()> + inline ${declarations.getType(ast)} get_${var.getName()}() const { + return ${declarations.getAliasOrigin(ast)}.get_${var.getName()}() ; + } + <#else> + inline ${declarations.getType(ast)} get_${var.getName()}() const { + return ${tc.include("org.nest.spl.expr.Expr", ast.getDeclaration().getExpr().get())}; + } + + <#if !var.isAlias()> + inline void set_${var.getName()}(const ${declarations.getType(ast)} v) { + ${declarations.getAliasOrigin(ast)}.set_${var.getName()}( v ) ; + } + + + diff --git a/src/main/resources/org/nest/nestml/function/MinDelayDynamics.ftl b/src/main/resources/org/nest/nestml/function/MinDelayDynamics.ftl new file mode 100644 index 000000000..bf07eb162 --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/MinDelayDynamics.ftl @@ -0,0 +1,3 @@ +assert(to >= 0 && (delay) from < Scheduler::get_min_delay()); +assert(from < to); +// blaa \ No newline at end of file diff --git a/src/main/resources/org/nest/nestml/function/ReadFromDictionary.ftl b/src/main/resources/org/nest/nestml/function/ReadFromDictionary.ftl new file mode 100644 index 000000000..8cf6ec6ca --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/ReadFromDictionary.ftl @@ -0,0 +1,30 @@ +<#-- + Generates C++ declaration + @grammar: AliasDecl = ([hide:"-"])? ([alias:"alias"])? + Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTAliasDecl + @param tc templatecontroller + @result TODO +--> +<#list declarations.getVariables(ast) as var> +<#if !ast.isHide()> +<#if !var.isAlias()> +${declarations.getType(ast)} tmp_${var.getName()}; +if (updateValue<${declarations.getType(ast)}>(d, "${var.getName()}", tmp_${var.getName()})) { + set_${var.getName()}(tmp_${var.getName()}); +} +<#else> +${declarations.getType(ast)} tmp_${var.getName()}; +if (updateValue<${declarations.getType(ast)}>(d, "${var.getName()}", tmp_${var.getName()})) { + set_${var.getName()}(tmp_${var.getName()}); +} +else { + set_${var.getName()}(old_${var.getName()}); +} + +<#else> +// do not update ${var.getName()}, since it is hidden + + + diff --git a/src/main/resources/org/nest/nestml/function/RecordCallback.ftl b/src/main/resources/org/nest/nestml/function/RecordCallback.ftl new file mode 100644 index 000000000..5dfcd51a9 --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/RecordCallback.ftl @@ -0,0 +1,20 @@ +<#-- + Generates C++ declaration + @grammar: AliasDecl = ([hide:"-"])? ([alias:"alias"])? + Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTAliasDecl + @param tc templatecontroller + @result TODO +--> +<#list declarations.getVariables(ast) as var> + <#assign varDomain = declarations.getDomainFromType(var.getType())> + + <#if varDomain == "nest::double_t" && !ast.isHide()> + insert_("${var.getName()}", &${nspPrefix}::${simpleNeuronName}::get_${var.getName()}); + <#else> + // ignores the ${var.getName()} with the domain type ${varDomain} + + + + diff --git a/src/main/resources/org/nest/nestml/function/SetOldAliasState.ftl b/src/main/resources/org/nest/nestml/function/SetOldAliasState.ftl new file mode 100644 index 000000000..11e99281e --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/SetOldAliasState.ftl @@ -0,0 +1,12 @@ +<#-- + Generates C++ declaration + @grammar: AliasDecl = ([hide:"-"])? ([alias:"alias"])? + Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTAliasDecl + @param tc templatecontroller + @result TODO +--> +<#list declarations.getVariables(ast) as var> +${declarations.getType(ast)} old_${var.getName()} = get_${var.getName()}(); + diff --git a/src/main/resources/org/nest/nestml/function/StructGetterSetter.ftl b/src/main/resources/org/nest/nestml/function/StructGetterSetter.ftl new file mode 100644 index 000000000..7ca9641cc --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/StructGetterSetter.ftl @@ -0,0 +1,13 @@ +<#-- + Generates C++ declaration + @grammar: AliasDecl = ([hide:"-"])? ([alias:"alias"])? + Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTAliasDecl + @param tc templatecontroller + @result TODO +--> +<#list declarations.getVariables(ast) as var> +inline ${declarations.getType(ast)} get_${var.getName()}() const { return ${var.getName()}_ ; } +inline void set_${var.getName()}(const ${declarations.getType(ast)} v) { ${var.getName()}_ = v ; } + diff --git a/src/main/resources/org/nest/nestml/function/TimestepDynamics.ftl b/src/main/resources/org/nest/nestml/function/TimestepDynamics.ftl new file mode 100644 index 000000000..dd38c2974 --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/TimestepDynamics.ftl @@ -0,0 +1,13 @@ +<#--Dynamics implements BodyElement = "dynamics" (MinDelay | TimeStep) "(" Parameter ")" + BLOCK_OPEN! Block BLOCK_CLOSE!;--> +assert(to >= 0 && (nest::delay) from < nest::Scheduler::get_min_delay()); +assert(from < to); + +${dynamicsHelper.printDynamicsType(ast)} ${dynamicsHelper.printParameterName(ast)}; +for ( nest::long_t lag = from ; lag < to ; ++lag ) { + +${dynamicsHelper.printParameterName(ast)} = nest::Time(nest::Time::step( lag )).get_ms() + origin.get_ms(); +${tc.include("org.nest.spl.Block", ast.getBlock())} +// voltage logging +B_.logger_.record_data(origin.get_steps()+lag); +} diff --git a/src/main/resources/org/nest/nestml/function/WriteInDictionary.ftl b/src/main/resources/org/nest/nestml/function/WriteInDictionary.ftl new file mode 100644 index 000000000..2602118fc --- /dev/null +++ b/src/main/resources/org/nest/nestml/function/WriteInDictionary.ftl @@ -0,0 +1,18 @@ +<#-- + Generates C++ declaration + @grammar: AliasDecl = ([hide:"-"])? ([alias:"alias"])? + Declaration ("[" invariants:Expr (";" invariants:Expr)* "]")?; + Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; + @param ast ASTAliasDecl + @param tc templatecontroller + @result TODO +--> +<#list declarations.getVariables(ast) as var> + +<#if !ast.isHide()> +def<${declarations.getType(ast)}>(d, "${var.getName()}", get_${var.getName()}()); +<#else> +// do not export ${var.getName()}, since it is hidden + + + diff --git a/src/main/resources/org/nest/nestml/module/Bootstrap.ftl b/src/main/resources/org/nest/nestml/module/Bootstrap.ftl new file mode 100644 index 000000000..1aacb6585 --- /dev/null +++ b/src/main/resources/org/nest/nestml/module/Bootstrap.ftl @@ -0,0 +1,44 @@ +#!/bin/sh + +echo "Bootstrapping ${moduleName}" + +if test -d autom4te.cache ; then +# we must remove this cache, because it +# may screw up things if configure is run for +# different platforms. +echo " -> Removing old automake cache ..." +rm -rf autom4te.cache +fi + +echo " -> Running aclocal ..." +aclocal + +echo " -> Running libtoolize ..." +if [ `uname -s` = Darwin ] ; then +# libtoolize is glibtoolize on OSX +LIBTOOLIZE=glibtoolize +else +LIBTOOLIZE=libtoolize +fi + +libtool_major=`$LIBTOOLIZE --version | head -n1 | cut -d\) -f2 | cut -d\. -f1` +$LIBTOOLIZE --force --copy --ltdl + +echo " -> Re-running aclocal ..." +if test $libtool_major -le 2; then +aclocal --force +else +aclocal --force -I $(pwd)/libltdl/m4 +fi + +echo " -> Running autoconf ..." +autoconf + +# autoheader must run before automake +echo " -> Running autoheader ..." +autoheader + +echo " -> Running automake ..." +automake --foreign --add-missing --force-missing --copy + +echo "Done." diff --git a/src/main/resources/org/nest/nestml/module/Configure.ftl b/src/main/resources/org/nest/nestml/module/Configure.ftl new file mode 100644 index 000000000..ef30fe889 --- /dev/null +++ b/src/main/resources/org/nest/nestml/module/Configure.ftl @@ -0,0 +1,200 @@ +<#assign lowerModuleName = moduleName?lower_case> +<#assign upperModuleName = moduleName?upper_case> +AC_PREREQ(2.52) + + +AC_INIT(${lowerModuleName}, 1.0, nest_user@nest-initiative.org) + +# These variables are exported to include/config.h +${upperModuleName}_MAJOR=1 +${upperModuleName}_MINOR=0 +${upperModuleName}_PATCHLEVEL=0 + +# Exporting source and build directories requires full path names. +# Thus we have to expand. +# Here, we are in top build dir, since source dir must exist, we can just +# move there and call pwd +if test "x$srcdir" = x ; then +PKGSRCDIR=`pwd` +else +PKGSRCDIR=`cd $srcdir && pwd` +fi +PKGBUILDDIR=`pwd` + +# If this is not called, install-sh will be put into .. by bootstrap.sh +# moritz, 06-26-06 +AC_CONFIG_AUX_DIR(.) + +AM_INIT_AUTOMAKE(nest, $${upperModuleName}_VERSION) + +# obtain host system type; HEP 2004-12-20 +AC_CANONICAL_HOST + +# ------------------------------------------------------------------------ +# Handle options +# +# NOTE: No programs/compilations must be run in this section; +# otherwise CFLAGS and CXXFLAGS may take on funny default +# values. +# HEP 2004-12-20 +# ------------------------------------------------------------------------ + +# nest-config +NEST_CONFIG=`which nest-config` +AC_ARG_WITH(nest,[ --with-nest=script nest-config script including path], +[ +if test "$withval" != yes; then +NEST_CONFIG=$withval +else +AC_MSG_ERROR([--with-nest-config expects the nest-config script as argument. See README for details.]) +fi +]) + +# ------------------------------------------- +# END Handle options +# ------------------------------------------- + + +# does nest-config work +AC_MSG_CHECKING([for nest-config ]) +AC_CHECK_FILE($NEST_CONFIG, HAVE_NEST=yes, +AC_MSG_ERROR([No usable nest-config was found. You may want to use --with-nest-config.])) +AC_MSG_RESULT(found) + +# the following will crash if nest-config does not run +# careful, lines below must not break +AC_MSG_CHECKING([for NEST directory information ]) +NEST_PREFIX=`$NEST_CONFIG --prefix` +NEST_CPPFLAGS=`$NEST_CONFIG --cflags` +NEST_COMPILER=`$NEST_CONFIG --compiler` +if test $prefix = NONE; then prefix=`$NEST_CONFIG --prefix`; fi +AC_MSG_RESULT($NEST_CPPFLAGS) + +# Set the platform-dependent compiler flags based on the canonical +# host string. These flags are placed in AM_{C,CXX}FLAGS. If +# {C,CXX}FLAGS are given as environment variables, then they are +# appended to the set of automatically chosen flags. After +# {C,CXX}FLAGS have been read out, they must be cleared, since +# system-dependent defaults will otherwise be placed into the +# Makefiles. HEP 2004-12-20. + +# Before we can determine the proper compiler flags, we must know +# which compiler we are using. Since the pertaining AC macros run the +# compiler and set CFLAGS, CXXFLAGS to system-dependent values, we +# need to save command line/enviroment settings of these variables +# first. AC_AIX must run before the compiler is run, so we must run it +# here. +# HEP 2004-12-21 + +${upperModuleName}_SAVE_CXXFLAGS=$CXXFLAGS + +# Must first check if we are on AIX +AC_AIX + +# Check for C++ compiler, looking for the same compiler +# used with NEST +AC_PROG_CXX([ $NEST_COMPILER ]) + +# the following is makeshift, should have the macro set proper +# MYMODULE_SET_CXXFLAGS +AM_CXXFLAGS=$${upperModuleName}_SAVE_CXXFLAGS +CXXFLAGS= + +## Configure C environment + +AC_PROG_LD +AC_PROG_INSTALL + +AC_LIBLTDL_CONVENIENCE ## put libltdl into a convenience library +AC_PROG_LIBTOOL ## use libtool +AC_CONFIG_SUBDIRS(libltdl) ## also configure subdir containing libltdl + +#-- Set the language to C++ +AC_LANG_CPLUSPLUS + +#-- Look for programs needed in the Makefile +AC_PROG_CXXCPP +AM_PROG_LIBTOOL +AC_PATH_PROGS([MAKE],[gmake make],[make]) + +# --------------------------------------------------------------- +# Configure directories to be built +# --------------------------------------------------------------- + +PKGDATADIR=$datadir/$PACKAGE +PKGDOCDIR=$datadir/doc/$PACKAGE + +# set up directories from which to build help +# second line replaces space with colon as separator +HELPDIRS="$PKGSRCDIR $PKGSRCDIR/sli" +HELPDIRS=`echo $HELPDIRS | tr " " ":"` + +#-- Replace these variables in *.in +AC_SUBST(HAVE_NEST) +AC_SUBST(NEST_CONFIG) +AC_SUBST(NEST_CPPFLAGS) +AC_SUBST(NEST_COMPILER) +AC_SUBST(NEST_PREFIX) +AC_SUBST(HELPDIRS) +AC_SUBST(PKGSRCDIR) +AC_SUBST(PKGBUILDDIR) +AC_SUBST(PKGDATADIR) +AC_SUBST(PKGDOCDIR) +AC_SUBST(KERNEL) +AC_SUBST(HOST) +AC_SUBST(SED) +AC_SUBST(LD) +AC_SUBST(host_os) +AC_SUBST(host_cpu) +AC_SUBST(host_vendor) +AC_SUBST(AS) +AC_SUBST(CXX) +AC_SUBST(AR) +AC_SUBST(ARFLAGS) +AC_SUBST(CXX_AR) +AC_SUBST(AM_CXXFLAGS) +AC_SUBST(AM_CFLAGS) +AC_SUBST(MAKE) +AC_SUBST(MAKE_FLAGS) +AC_SUBST(INCLTDL) +AC_SUBST(LIBLTDL) + +AM_CONFIG_HEADER(${lowerModuleName}_config.h:${lowerModuleName}_config.h.in) +AC_CONFIG_FILES(Makefile) + +# ----------------------------------------------- +# Create output +# ----------------------------------------------- +AC_OUTPUT + + +# ----------------------------------------------- +# Report, after output at end of configure run +# Must come after AC_OUTPUT, so that it is +# displayed after libltdl has been configured +# ----------------------------------------------- + +echo +echo "-------------------------------------------------------" +echo "${moduleName} Configuration Summary" +echo "-------------------------------------------------------" +echo +echo "C++ compiler : $CXX" +echo "C++ compiler flags : $AM_CXXFLAGS" +echo "NEST compiler flags : $NEST_CPPFLAGS" + +# these variables will still contain '${"$" + "{prefix}"}' +# we want to have the versions where this is resolved, too: +eval eval eval PKGDOCDIR_AS_CONFIGURED=$PKGDOCDIR +eval eval eval PKGDATADIR_AS_CONFIGURED=$PKGDATADIR + +echo +echo "-------------------------------------------------------" +echo +echo "You can build and install ${moduleName} now, using" +echo " make" +echo " make install" +echo +echo "${moduleName} will be installed to:" +echo -n " "; eval eval echo "$libdir" +echo diff --git a/src/main/resources/org/nest/nestml/module/Makefile.ftl b/src/main/resources/org/nest/nestml/module/Makefile.ftl new file mode 100644 index 000000000..b51241539 --- /dev/null +++ b/src/main/resources/org/nest/nestml/module/Makefile.ftl @@ -0,0 +1,57 @@ +<#assign lowerModuleName = moduleName?lower_case> +# Automake file for external dynamic modules for NEST +# +# Hans Ekkehard Plesser, April 2008 +# Automake file for the Developer Module +# +# lib${lowerModuleName} is built as a normal, installable library. +# It will be installed to $prefix/lib by make install. +# +# Headers from this directory are not to be installed upon +# make install. They are therefore included in _SOURCES. + + +# 1. Exchange "my" in "mymodule" with the name of your model below +# (ten locations). +# 2. Add all .cpp and .h files from your code as *_SOURCES. Header files +# are given only so that they will be included in the tarball if you +# run "make dist" on your module. +# 3. The mymodule* stuff creates a module that can be loaded at runtime. +# It is called mymodule.so. +# 4. The libmymodule* stuff creates a library against which NEST can be +# linked. + +libdir= @libdir@/nest + +lib_LTLIBRARIES= ${lowerModuleName}.la lib${lowerModuleName}.la + +${lowerModuleName}_la_CXXFLAGS= @AM_CXXFLAGS@ +${lowerModuleName}_la_SOURCES= ${lowerModuleName}Config.cpp ${lowerModuleName}Config.h \ +<#list neuronModelNames as name> + ${name}.cpp ${name}.h \ + + # last line cannot be empty, since the last \ of the sources + +${lowerModuleName}_la_LDFLAGS= -module + +lib${lowerModuleName}_la_CXXFLAGS= $(${lowerModuleName}_la_CXXFLAGS) -DLINKED_MODULE +lib${lowerModuleName}_la_SOURCES= $(${lowerModuleName}_la_SOURCES) + +MAKEFLAGS= @MAKE_FLAGS@ + +AM_CPPFLAGS= @NEST_CPPFLAGS@ \ + @INCLTDL@ + +.PHONY: install-slidoc + +#nobase_pkgdata_DATA=\ +# sli/${lowerModuleName}-init.sli + +install-slidoc: + NESTRCFILENAME=/dev/null $(DESTDIR)$(NEST_PREFIX)/bin/sli --userargs="@HELPDIRS@" $(NEST_PREFIX)/share/nest/sli/install-help.sli + +install-data-hook: install-exec install-slidoc + +EXTRA_DIST= sli + +AUTOMAKE_OPTIONS = subdir-objects diff --git a/src/main/resources/org/nest/nestml/module/ModuleClass.ftl b/src/main/resources/org/nest/nestml/module/ModuleClass.ftl new file mode 100644 index 000000000..cf3d641f4 --- /dev/null +++ b/src/main/resources/org/nest/nestml/module/ModuleClass.ftl @@ -0,0 +1,107 @@ +/* +* ${moduleName}.cpp +* +* This file is part of NEST. +* +* Copyright (C) 2004 The NEST Initiative +* +* NEST is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* NEST is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with NEST. If not, see . +* +*/ +<#assign lowerModuleName = moduleName?lower_case> +// include necessary NEST headers +#include "config.h" +#include "network.h" +#include "model.h" +#include "dynamicloader.h" +#include "genericmodel.h" +#include "booldatum.h" +#include "integerdatum.h" +#include "tokenarray.h" +#include "exceptions.h" +#include "sliexceptions.h" +#include "nestmodule.h" + +// include headers with your own stuff +#include "${moduleName}Config.h" +<#list neuronModelNames as name> + #include "${name}.h" + +// -- Interface to dynamic module loader --------------------------------------- + +/* +* The dynamic module loader must be able to find your module. +* You make the module known to the loader by defining an instance of your +* module class in global scope. This instance must have the name +* +* _LTX_mod +* +* The dynamicloader can then load modulename and search for symbol "mod" in it. +*/ + +${lowerModuleName}::${moduleName} ${lowerModuleName}_LTX_mod; + +// -- DynModule functions ------------------------------------------------------ + +${lowerModuleName}::${moduleName}::${moduleName}() +{ +#ifdef LINKED_MODULE +// register this module at the dynamic loader +// this is needed to allow for linking in this module at compile time +// all registered modules will be initialized by the main app's dynamic loader +nest::DynamicLoaderModule::registerLinkedModule(this); +#endif +} + +${lowerModuleName}::${moduleName}::~${moduleName}() +{} + +const std::string ${lowerModuleName}::${moduleName}::name(void) const +{ + return std::string("${moduleName}"); // Return name of the module +} + +const std::string ${lowerModuleName}::${moduleName}::commandstring(void) const +{ + // Instruct the interpreter to load ${lowerModuleName}-init.sli + //return std::string("(${lowerModuleName}-init) run"); // currently not working + return std::string(""); +} + +void ${lowerModuleName}::${moduleName}::init(SLIInterpreter *i, nest::Network*) +{ + <#list neuronModelNames as name> + <#assign fqnName = packageName + "." + name> + nest::register_model<${fqnName?replace(".", "::")}>(nest::NestModule::get_network(), + "${fqnName?replace(".", "_")}"); + + + + /* Register a synapse type. + Give synapse type as template argument and the name as second argument. + The first argument is always a reference to the network. + */ + //nest::register_prototype_connection(nest::NestModule::get_network(), + // "drop_odd_synapse"); + + /* Register a SLI function. + The first argument is the function name for SLI, the second a pointer to + the function object. If you do not want to overload the function in SLI, + you do not need to give the mangled name. If you give a mangled name, you + should define a type trie in the mymodule-init.sli file. + */ + //i->createcommand("StepPatternConnect_Vi_i_Vi_i_l", + // &stepPatternConnect_Vi_i_Vi_i_lFunction); + +} // ${moduleName}::init() diff --git a/src/main/resources/org/nest/nestml/module/ModuleHeader.ftl b/src/main/resources/org/nest/nestml/module/ModuleHeader.ftl new file mode 100644 index 000000000..9ed481945 --- /dev/null +++ b/src/main/resources/org/nest/nestml/module/ModuleHeader.ftl @@ -0,0 +1,108 @@ +<#assign lowerModuleName = moduleName?lower_case> +<#assign upperModuleName = moduleName?upper_case> +/* +* ${moduleName}.h +* +* This file is part of NEST. +* +* Copyright (C) 2004 The NEST Initiative +* +* NEST is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* NEST is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with NEST. If not, see . +* +*/ + +#ifndef ${upperModuleName}_H +#define ${upperModuleName}_H + +#include "dynmodule.h" + +namespace nest +{ +class Network; +} + +// Put your stuff into your own namespace. +namespace ${lowerModuleName} { + +/** +* Class defining your model. +* @note For each model, you must define one such class, with a unique name. +*/ +class ${moduleName} : public DynModule +{ +public: + +// Interface functions ------------------------------------------ + +/** +* @note The constructor registers the module with the dynamic loader. +* Initialization proper is performed by the init() method. +*/ +${moduleName}(); + +/** +* @note The destructor does not do much in modules. Proper "downrigging" +* is the responsibility of the unregister() method. +*/ +~${moduleName}(); + +/** +* Initialize module by registering models with the network. +* @param SLIInterpreter* SLI interpreter +* @param nest::Network* Network with which to register models +* @note Parameter Network is needed for historical compatibility +* only. +*/ +void init(SLIInterpreter*, nest::Network*); + +/** +* Return the name of your model. +*/ +const std::string name(void) const; + +/** +* Return the name of a sli file to execute when mymodule is loaded. +* This mechanism can be used to define SLI commands associated with your +* module, in particular, set up type tries for functions you have defined. +*/ +const std::string commandstring(void) const; + +public: + +// Classes implementing your functions ----------------------------- + +/** +* Implement a function for a step-pattern-based connection. +* @note What this function does is described in the SLI documentation +* in the cpp file. +* @note The mangled name indicates this function expects the following +* arguments on the stack (bottom first): vector of int, int, +* vector of int, int. +* @note You must define a member object in your module class +* of the function class. execute() is later invoked on this +* member. +*/ +/* +class StepPatternConnect_Vi_i_Vi_i_lFunction: public SLIFunction +{ +public: +void execute(SLIInterpreter *) const; +}; + +StepPatternConnect_Vi_i_Vi_i_lFunction stepPatternConnect_Vi_i_Vi_i_lFunction;*/ +}; +} // namespace ${lowerModuleName} + +#endif +/* #ifndef ${upperModuleName}_H */ \ No newline at end of file diff --git a/src/main/resources/org/nest/nestml/module/SLI_Init.ftl b/src/main/resources/org/nest/nestml/module/SLI_Init.ftl new file mode 100644 index 000000000..c08307515 --- /dev/null +++ b/src/main/resources/org/nest/nestml/module/SLI_Init.ftl @@ -0,0 +1,29 @@ +<#assign lowerModuleName = moduleName?lower_case> +/* +* ${lowerModuleName}-init.sli +* +* This file is part of NEST. +* +* Copyright (C) 2004 The NEST Initiative +* +* NEST is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* NEST is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with NEST. If not, see . +* +*/ + +/* +* Initialization file for ${moduleName}. +* Run automatically when ${moduleName} is loaded. +*/ + +M_DEBUG (${lowerModuleName}.sli) (Initializing SLI support for ${moduleName}.) message \ No newline at end of file diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl new file mode 100644 index 000000000..244a23569 --- /dev/null +++ b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl @@ -0,0 +1,239 @@ +/* +* ${ast.getName()}.cpp +* +* This file is part of NEST. +* +* Copyright (C) 2004 The NEST Initiative +* +* NEST is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* NEST is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with NEST. If not, see . +* +*/ + +#include "exceptions.h" +#include "network.h" +#include "dict.h" +#include "integerdatum.h" +#include "doubledatum.h" +#include "dictutils.h" +#include "numerics.h" +#include "universal_data_logger_impl.h" + +#include + +// TODO it cannot work with several neurons +#include "${simpleNeuronName}.h" + +/* ---------------------------------------------------------------- +* Recordables map +* ---------------------------------------------------------------- */ +nest::RecordablesMap<${nspPrefix}::${simpleNeuronName}> ${nspPrefix}::${simpleNeuronName}::recordablesMap_; + +namespace nest +{ + // Override the create() method with one call to RecordablesMap::insert_() + // for each quantity to be recorded. + template <> + void RecordablesMap<${nspPrefix}::${simpleNeuronName}>::create() + { + // use standard names whereever you can for consistency! + <#list body.getStates() as state> + ${tc.include("org.nest.nestml.function.RecordCallback", state)} + + } +} + +/* ---------------------------------------------------------------- +* Default constructors defining default parameters and state +* ---------------------------------------------------------------- */ +<#assign start=""> +${nspPrefix}::${simpleNeuronName}::Parameters_::Parameters_(): +<#list body.getNonAliasParameters() as parameter> + ${start} ${tc.include("org.nest.nestml.function.MemberInitialization", parameter)} + <#assign start=","> + +{} + +<#assign start=""> +${nspPrefix}::${simpleNeuronName}::State_::State_(): +<#list body.getNonAliasStates() as state> + ${start} ${tc.include("org.nest.nestml.function.MemberInitialization", state)} + <#assign start=","> + +{} + +/* ---------------------------------------------------------------- +* Parameter and state extractions and manipulation functions +* ---------------------------------------------------------------- */ + +void +${nspPrefix}::${simpleNeuronName}::Parameters_::get(DictionaryDatum &d) const +{ + <#list body.getNonAliasParameters() as parameter> + ${tc.include("org.nest.nestml.function.WriteInDictionary", parameter)} + +} + +void +${nspPrefix}::${simpleNeuronName}::Parameters_::set(const DictionaryDatum& d) +{ + <#list body.getNonAliasParameters() as parameter> + ${tc.include("org.nest.nestml.function.ReadFromDictionary", parameter)} + + + <#list body.getNonAliasParameters() as parameter> + <#list parameter.getInvariants() as invariant> + ${tc.include("org.nest.nestml.function.Invariant", invariant)} + + + +} + +void +${nspPrefix}::${simpleNeuronName}::State_::get(DictionaryDatum &d) const +{ + <#list body.getNonAliasStates() as state> + ${tc.include("org.nest.nestml.function.WriteInDictionary", state)} + +} + +void +${nspPrefix}::${simpleNeuronName}::State_::set(const DictionaryDatum& d) +{ + <#list body.getNonAliasStates() as state> + ${tc.include("org.nest.nestml.function.ReadFromDictionary", state)} + +} + +${nspPrefix}::${simpleNeuronName}::Buffers_::Buffers_(${ast.getName()} &n) +: logger_(n) +{} + +${nspPrefix}::${simpleNeuronName}::Buffers_::Buffers_(const Buffers_ &, ${ast.getName()} &n) +: logger_(n) +{} + +/* ---------------------------------------------------------------- +* Default and copy constructor for node +* ---------------------------------------------------------------- */ +// TODO inner components +${nspPrefix}::${simpleNeuronName}::${simpleNeuronName}() +: Archiving_Node(), +P_(), +S_(), +B_(*this) +{ + recordablesMap_.create(); +} + +${nspPrefix}::${simpleNeuronName}::${simpleNeuronName}(const ${simpleNeuronName}& n) + : Archiving_Node(n), + P_(n.P_), + S_(n.S_), + B_(n.B_, *this) +{} + +/* ---------------------------------------------------------------- +* Node initialization functions +* ---------------------------------------------------------------- */ + +void +${nspPrefix}::${simpleNeuronName}::init_state_(const Node& proto) +{ // TODO inner components + const ${ast.getName()}& pr = downcast<${ast.getName()}>(proto); + S_ = pr.S_; +} +void +${nspPrefix}::${simpleNeuronName}::init_buffers_() +{ + <#list body.getInputLines() as input> + ${bufferHelper.printBufferInitialization(input)} + + B_.logger_.reset(); // includes resize + Archiving_Node::clear_history(); +} + +void +${nspPrefix}::${simpleNeuronName}::calibrate() +{ // TODO init internal variables + B_.logger_.init(); + + ${tc.include("org.nest.nestml.function.Calibrate", body.getNonAliasInternals())} + + <#list body.getInputLines() as inputLine> + <#if bufferHelper.isVector(inputLine)> + B_.receptor_types_${inputLine.getName()}.resize(P_.${bufferHelper.vectorParameter(inputLine)}); + for (size_t i=0; i < P_.${bufferHelper.vectorParameter(inputLine)}; i++) + { + B_.receptor_types_${inputLine.getName()}[i] = i+1; + } + + + + +} + +/* ---------------------------------------------------------------- +* Update and spike handling functions +* ---------------------------------------------------------------- */ + + +void +${nspPrefix}::${simpleNeuronName}::update(nest::Time const & origin, const nest::long_t from, const nest::long_t to) +{ + <#list body.getDynamics() as dynamic> + ${tc.include("org.nest.nestml.function.DynamicsImplementation", dynamic)} + +} + +// Do not move this function as inline to h-file. It depends on +// universal_data_logger_impl.h being included here. +void +${nspPrefix}::${simpleNeuronName}::handle(nest::DataLoggingRequest& e) +{ + B_.logger_.handle(e); +} + +<#list body.getFunctions() as function> +${functionPrinter.printFunctionDefinition(function, nspPrefix + "::" + simpleNeuronName)} +{ + ${tc.include("org.nest.spl.Block", function.getBlock())} +} + + +<#if isSpikeInput> +void +${nspPrefix}::${simpleNeuronName}::handle(nest::SpikeEvent &e) +{ + assert(e.get_delay() > 0); + + const double_t weight = e.get_weight(); + const double_t multiplicity = e.get_multiplicity(); + ${tc.include("org.nest.nestml.buffer.SpikeBufferFill", body.getInputLines())} +} + + +<#if isCurrentInput> +void +${nspPrefix}::${simpleNeuronName}::handle(nest::CurrentEvent& e) +{ + assert(e.get_delay() > 0); + + const double_t current=e.get_current(); + const double_t weight=e.get_weight(); + + // add weighted current; HEP 2002-10-04 + ${tc.include("org.nest.nestml.buffer.CurrentBufferFill", body.getInputLines())} +} + + diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl new file mode 100644 index 000000000..39421e4cd --- /dev/null +++ b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl @@ -0,0 +1,426 @@ +<#-- + @param ast ASTNeuron + @param tc templatecontroller + @result CPP Class +--> + +/* +* ${simpleNeuronName}.h +* +* This file is part of NEST. +* +* Copyright (C) 2004 The NEST Initiative +* +* NEST is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* NEST is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with NEST. If not, see . +* +*/ + + +#ifndef ${guard} +#define ${guard} + +#include "nest.h" +#include "event.h" +#include "archiving_node.h" +#include "connection.h" +#include "universal_data_logger.h" +#include "dictdatum.h" + +<#list nspPrefix?split("::") as nsp> +namespace ${nsp} { + + +/* BeginDocumentation +Name: ${simpleNeuronName} . + +Description: +Empty. TODO + +Parameters: + +Remarks: +Empty + +References: +Empty + +Sends: ${outputEvent} + +Receives: <#if isSpikeInput>Spike, <#if isCurrentInput>Current, DataLoggingRequest + +Author: +TODO + +SeeAlso: +Empty +*/ +class ${simpleNeuronName} : public nest::Archiving_Node +{ + public: + /** + * The constructor is only used to create the model prototype in the model manager. + */ + ${simpleNeuronName}(); + + /** + * The copy constructor is used to create model copies and instances of the model. + * @node The copy constructor needs to initialize the parameters and the state. + * Initialization of buffers and interal variables is deferred to + * @c init_buffers_() and @c calibrate(). + */ + ${simpleNeuronName}(const ${simpleNeuronName}&); + + /** + * Import sets of overloaded virtual functions. + * This is necessary to ensure proper overload and overriding resolution. + * @see http://www.gotw.ca/gotw/005.htm. + */ + using nest::Node::handles_test_event; + using nest::Node::handle; + + <#if isOutputEventPresent> + /** + * Used to validate that we can send ${outputEvent} to desired target:port. + */ + nest::port send_test_event(nest::Node& target, nest::rport receptor_type, nest::synindex, bool); + + + /** + * @defgroup mynest_handle Functions handling incoming events. + * We tell nest that we can handle incoming events of various types by + * defining @c handle() and @c connect_sender() for the given event. + * @{ + */ + <#if isSpikeInput> + void handle(nest::SpikeEvent &); //! accept spikes + + <#if isCurrentInput> + void handle(nest::CurrentEvent &); //! accept input current + + void handle(nest::DataLoggingRequest &);//! allow recording with multimeter + + <#if isSpikeInput> + nest::port handles_test_event(nest::SpikeEvent&, nest::port); + + <#if isCurrentInput> + nest::port handles_test_event(nest::CurrentEvent&, nest::port); + + nest::port handles_test_event(nest::DataLoggingRequest&, nest::port); + /** @} */ + + // SLI communication functions: + void get_status(DictionaryDatum &) const; + void set_status(const DictionaryDatum &); + + // Generate function header + <#list body.getFunctions() as function> + ${functionPrinter.printFunctionDeclaration(function)} ; + + + <#list body.getStates() as state> + ${tc.include("org.nest.nestml.function.MemberVariableGetterSetter", state)} + + + <#list body.getParameters() as parameter> + ${tc.include("org.nest.nestml.function.MemberVariableGetterSetter", parameter)} + + + <#list body.getInternals() as internal> + ${tc.include("org.nest.nestml.function.MemberVariableGetterSetter", internal)} + + + <#list body.getInputLines() as inputLine> + ${bufferHelper.printBufferGetter(inputLine, false)}; + + + private: + + //! Reset parameters and state of neuron. + + //! Reset state of neuron. + void init_state_(const Node& proto); + + //! Reset internal buffers of neuron. + void init_buffers_(); + + //! Initialize auxiliary quantities, leave parameters and state untouched. + void calibrate(); + + //! Take neuron through given time interval + void update(nest::Time const &, const nest::long_t, const nest::long_t); + + // The next two classes need to be friends to access the State_ class/member + friend class nest::RecordablesMap<${simpleNeuronName}>; + friend class nest::UniversalDataLogger<${simpleNeuronName}>; + + /** + * Dynamic state of the neuron. + * + * These are the state variables that are advanced in time by calls to + * @c update(). In many models, some or all of them can be set by the user + * through @c SetStatus. The state variables are initialized from the model + * prototype when the node is created. State variables are reset by @c ResetNetwork. + * + * @note State_ need neither copy constructor nor @c operator=(), since + * all its members are copied properly by the default copy constructor + * and assignment operator. Important: + * - If State_ contained @c Time members, you need to define the + * assignment operator to recalibrate all members of type @c Time . You + * may also want to define the assignment operator. + * - If State_ contained members that cannot copy themselves, such + * as C-style arrays, you need to define the copy constructor and + * assignment operator to copy those members. + */ + struct State_ { + <#list body.getNonAliasStates() as aliasDecl> + ${tc.include("org.nest.nestml.MemberDeclaration", aliasDecl.getDeclaration())} + + State_(); + + /** Store state values in dictionary. */ + void get(DictionaryDatum&) const; + + /** + * Set state values from dictionary. + */ + void set(const DictionaryDatum&); + + <#list body.getNonAliasStates() as aliasDecl> + ${tc.include("org.nest.nestml.function.StructGetterSetter", aliasDecl)} + + }; + + /** + * Free parameters of the neuron. + * + * These are the parameters that can be set by the user through @c SetStatus. + * They are initialized from the model prototype when the node is created. + * Parameters do not change during calls to @c update() and are not reset by + * @c ResetNetwork. + * + * @note Parameters_ need neither copy constructor nor @c operator=(), since + * all its members are copied properly by the default copy constructor + * and assignment operator. Important: + * - If Parameters_ contained @c Time members, you need to define the + * assignment operator to recalibrate all members of type @c Time . You + * may also want to define the assignment operator. + * - If Parameters_ contained members that cannot copy themselves, such + * as C-style arrays, you need to define the copy constructor and + * assignment operator to copy those members. + */ + struct Parameters_ { + <#list body.getNonAliasParameters() as aliasDecl> + ${tc.include("org.nest.nestml.MemberDeclaration", aliasDecl.getDeclaration())} + + /** Initialize parameters to their default values. */ + Parameters_(); + + /** Store parameter values in dictionary. */ + void get(DictionaryDatum&) const; + + /** Set parameter values from dictionary. */ + void set(const DictionaryDatum&); + + ${tc.include("org.nest.nestml.function.StructGetterSetter", body.getNonAliasParameters())} + }; + + /** + * Internal variables of the neuron. + * These variables must be initialized by @c calibrate, which is called before + * the first call to @c update() upon each call to @c Simulate. + * @node Variables_ needs neither constructor, copy constructor or assignment operator, + * since it is initialized by @c calibrate(). If Variables_ has members that + * cannot destroy themselves, Variables_ will need a destructor. + */ + struct Variables_ { + <#list body.getNonAliasInternals() as aliasDecl> + ${tc.include("org.nest.nestml.MemberDeclaration", aliasDecl.getDeclaration())} + + <#list body.getNonAliasInternals() as internal> + ${tc.include("org.nest.nestml.function.StructGetterSetter", internal)} + + }; + + /** + * Buffers of the neuron. + * Ususally buffers for incoming spikes and data logged for analog recorders. + * Buffers must be initialized by @c init_buffers_(), which is called before + * @c calibrate() on the first call to @c Simulate after the start of NEST, + * ResetKernel or ResetNetwork. + * @node Buffers_ needs neither constructor, copy constructor or assignment operator, + * since it is initialized by @c init_nodes_(). If Buffers_ has members that + * cannot destroy themselves, Buffers_ will need a destructor. + */ + struct Buffers_ { + Buffers_(${simpleNeuronName}&); + Buffers_(const Buffers_ &, ${simpleNeuronName}&); + <#list body.getInputLines() as inputLine> + ${bufferHelper.printBufferGetter(inputLine, true)} + + + /** Logger for all analog data */ + nest::UniversalDataLogger<${simpleNeuronName}> logger_; + + <#list body.getInputLines() as inputLine> + ${bufferHelper.printBufferDeclaration(inputLine)}; + + + <#list body.getInputLines() as inputLine> + ${bufferHelper.printBufferTypesVariables(inputLine)}; + + }; + + /** + * @defgroup pif_members Member variables of neuron model. + * Each model neuron should have precisely the following four data members, + * which are one instance each of the parameters, state, buffers and variables + * structures. Experience indicates that the state and variables member should + * be next to each other to achieve good efficiency (caching). + * @note Devices require one additional data member, an instance of the @c Device + * child class they belong to. + * @{ + */ + Parameters_ P_; //!< Free parameters. + State_ S_; //!< Dynamic state. + Variables_ V_; //!< Internal Variables + Buffers_ B_; //!< Buffers. + + //! Mapping of recordables names to access functions + static nest::RecordablesMap<${simpleNeuronName}> recordablesMap_; + + +/** @} */ +}; /* neuron ${simpleNeuronName} */ + +<#list nspPrefix?split("::") as nsp> +} /* namespace ${nsp} */ + + + +<#if isOutputEventPresent> +inline +nest::port ${nspPrefix}::${simpleNeuronName}::send_test_event(nest::Node& target, nest::rport receptor_type, nest::synindex, bool) +{ + // You should usually not change the code in this function. + // It confirms that the target of connection @c c accepts @c ${outputEvent} on + // the given @c receptor_type. + ${outputEvent} e; + e.set_sender(*this); + + return target.handles_test_event(e, receptor_type); +} + + + +<#if isSpikeInput> +inline +nest::port ${nspPrefix}::${simpleNeuronName}::handles_test_event(nest::SpikeEvent&, nest::port receptor_type) +{ + // You should usually not change the code in this function. + // It confirms to the connection management system that we are able + // to handle @c SpikeEvent on port 0. You need to extend the function + // if you want to differentiate between input ports. + if (receptor_type != 0) + throw nest::UnknownReceptorType(receptor_type, get_name()); + return 0; +} + + +<#if isCurrentInput> +inline +nest::port ${nspPrefix}::${simpleNeuronName}::handles_test_event(nest::CurrentEvent&, nest::port receptor_type) +{ + // You should usually not change the code in this function. + // It confirms to the connection management system that we are able + // to handle @c CurrentEvent on port 0. You need to extend the function + // if you want to differentiate between input ports. + if (receptor_type != 0) + throw nest::UnknownReceptorType(receptor_type, get_name()); + return 0; +} + +inline +nest::port ${nspPrefix}::${simpleNeuronName}::handles_test_event(nest::DataLoggingRequest& dlr, +nest::port receptor_type) +{ + // You should usually not change the code in this function. + // It confirms to the connection management system that we are able + // to handle @c DataLoggingRequest on port 0. + // The function also tells the built-in UniversalDataLogger that this node + // is recorded from and that it thus needs to collect data during simulation. + if (receptor_type != 0) + throw nest::UnknownReceptorType(receptor_type, get_name()); + + return B_.logger_.connect_logging_device(dlr, recordablesMap_); +} + +// TODO call get_status on used or internal components +inline +void ${nspPrefix}::${simpleNeuronName}::get_status(DictionaryDatum &d) const +{ + P_.get(d); + <#list body.getAliasParameters() as parameter> + ${tc.include("org.nest.nestml.function.WriteInDictionary", parameter)} + + S_.get(d); + + <#list body.getAliasStates() as state> + ${tc.include("org.nest.nestml.function.WriteInDictionary", state)} + + (*d)[nest::names::recordables] = recordablesMap_.get_list(); +} + +// TODO call set_status on used or internal components +inline +void ${nspPrefix}::${simpleNeuronName}::set_status(const DictionaryDatum &d) +{ + <#list body.getAliasParameters() as parameter> + ${tc.include("org.nest.nestml.function.SetOldAliasState", parameter)} + + <#list body.getAliasStates() as state> + ${tc.include("org.nest.nestml.function.SetOldAliasState", state)} + + + Parameters_ ptmp = P_; // temporary copy in case of errors + ptmp.set(d); // throws if BadProperty + + // alias setter-functions perform the set on the member-variable P_, hence + // we swap ptmp and P_ and 're-swap' afterwards. + std::swap(P_, ptmp); + + <#list body.getAliasParameters() as parameter> + ${tc.include("org.nest.nestml.function.ReadFromDictionary", parameter)} + + + State_ stmp = S_; // temporary copy in case of errors + stmp.set(d); // throws if BadProperty + + // alias setter-functions perform the set on the member-variable S_, hence + // we swap stmp and S_ and 're-swap' afterwards. + // P_ and ptmp stay swaped, since the alias might access parameters + std::swap(S_, stmp); + <#list body.getAliasStates() as state> + ${tc.include("org.nest.nestml.function.ReadFromDictionary", state)} + + // 're-swap' when everything is ok (TODO: check for tests) + std::swap(P_, ptmp); + std::swap(S_, stmp); + + // if we get here, temporaries contain consistent set of properties + P_ = ptmp; + S_ = stmp; +}; + +#endif +/* #ifndef ${guard} */ diff --git a/src/main/resources/org/nest/ode/SympySolver.ftl b/src/main/resources/org/nest/ode/SympySolver.ftl new file mode 100644 index 000000000..06bf62425 --- /dev/null +++ b/src/main/resources/org/nest/ode/SympySolver.ftl @@ -0,0 +1,102 @@ +from sympy import * +from sympy.matrices import zeros +import numpy +from numpy.random import randint + +a, h = symbols('a, h') +<#compress> +<#assign separator = ""> +<#list variables as variable>${separator} ${variable} <#assign separator = ","> = <#assign separator = ""> symbols('<#list variables as variable> ${separator} ${variable} <#assign separator = ","> ') + + +rhs = ${expressionsPrettyPrinter.print(ode.getRhs())} +${eq.getLhsVariable()} = ${expressionsPrettyPrinter.print(eq.getRhs())} + +firstDev = diff(rhs, ${ode.getLhsVariable()}) +secondDev = diff(firstDev, ${ode.getLhsVariable()}) +Ordnung = None + +if secondDev == 0: + print 'We have a linear differential equation!' + order = None + tmp_diffs = [${eq.getLhsVariable()}, diff(${eq.getLhsVariable()},t)] + a_1 = solve(tmp_diffs[1] - a*${eq.getLhsVariable()}, a) + SUM = tmp_diffs[1] - a_1[0] * ${eq.getLhsVariable()} + if SUM == 0: + order = 1 + else: + for n in range(2, 10): + tmp_diffs.append(diff(${eq.getLhsVariable()}, t, n)) + X = zeros(n) + Y = zeros(n, 1) + found = False + for k in range(0, 100): # tries + for i in range(0, n): + substitute = i+k + Y[i] = tmp_diffs[n].subs(t, substitute) + for j in range(0, n): + X[i, j] = tmp_diffs[j].subs(t, substitute) + print "Try if X is invertable:" + print X + d = det(X) + print "det(X) = " + str(d) + if d != 0: + found = True + break + if not found: + print 'We have a problem' + exit(1) + VecA = X.inv() * Y + SUM = 0 + for k in range(0, n): + SUM += VecA[k]*diff(${eq.getLhsVariable()}, t, k) + SUM -= tmp_diffs[n] + print "SUM = " + str(simplify(SUM)) + if simplify(SUM) == sympify(0): + order = n + break + + if order is None: + print 'We have a problem' + exit(1) + + if order == 1: + A = Matrix([[a_1[0], 0], + [1/C_m, -1/Tau]]) + elif order == 2: + # VecA only if Ordnung 2 or larger + solutionpq = -VecA[1]/2 + sqrt(VecA[1]**2 / 4 + VecA[0]) + print simplify(VecA) + A = Matrix([[VecA[1]+solutionpq, 0, 0 ], + [1, -solutionpq, 0 ], + [0, 1/C_m, -1/Tau]]) + elif order > 2: + A = zeros(order) + A[order-1, order-1] = -1/tau_in + A[order-1, order-2] = 1/C_m + for j in range(0, order-1): + A[0, j] = VecA[order-j-1] + for i in range(1,order-1): + A[i,i-1]=1 + + print simplify(A) + #exit(0) + print("Compute propagatormatrix...") + propogatorMatrix = simplify(exp(A*h)) + print "Propagatormatrix:" + print propogatorMatrix + + if order == 2: + print 'Solution matrix is printed into solution.matrix.tmp' + f = open('solution.matrix.tmp', 'w') + f.write("P00 real = " + str(propogatorMatrix[0, 0]) + "# P00\n") + f.write("P01 real = " + str(propogatorMatrix[0, 1]) + "# P01\n") + f.write("P02 real = " + str(propogatorMatrix[0, 2]) + "# P02\n") + f.write("P10 real = " + str(propogatorMatrix[1, 0]) + "# P10\n") + f.write("P11 real = " + str(propogatorMatrix[1, 1]) + "# P11\n") + f.write("P12 real = " + str(propogatorMatrix[1, 2]) + "# P12\n") + f.write("P20 real = " + str(propogatorMatrix[2, 0]) + "# P20\n") + f.write("P21 real = " + str(propogatorMatrix[2, 1]) + "# P21\n") + f.write("P22 real = " + str(propogatorMatrix[2, 2]) + "# P22\n") +else: + print 'Not a linear differential equation' diff --git a/src/main/resources/org/nest/spl/Assignment.ftl b/src/main/resources/org/nest/spl/Assignment.ftl new file mode 100644 index 000000000..76f74a5e8 --- /dev/null +++ b/src/main/resources/org/nest/spl/Assignment.ftl @@ -0,0 +1,25 @@ +<#-- + Generates C++ declaration + @grammar: Assignment = variableName:QualifiedName "=" Expr; + @param ast ASTAssignment + @param tc templatecontroller + @result TODO +--> +<#if assignmentHelper.isLocal(ast)> +${assignmentHelper.printVariableName(ast)} = ${tc.include("org.nest.spl.expr.Expr", ast.getExpr())}; +<#else> + + <#if assignmentHelper.isVector(ast) || declarations.isVectorLHS(ast)> + for (size_t i=0; i < get_num_of_receptors(); i++) { + <#if declarations.isVectorLHS(ast)> + ${assignmentHelper.printGetterName(ast)}()[i] = ${tc.include("org.nest.spl.expr.Expr", ast.getExpr())}; + <#else> + ${assignmentHelper.printSetterName(ast)}(${tc.include("org.nest.spl.expr.Expr", ast.getExpr())}); + + + } + <#else> + ${assignmentHelper.printSetterName(ast)}(${tc.include("org.nest.spl.expr.Expr", ast.getExpr())}); + + + diff --git a/src/main/resources/org/nest/spl/Block.ftl b/src/main/resources/org/nest/spl/Block.ftl new file mode 100644 index 000000000..aa3cc64ae --- /dev/null +++ b/src/main/resources/org/nest/spl/Block.ftl @@ -0,0 +1,10 @@ +<#-- + Handles a complex block statement + @grammar: Block = ( Stmt | SL_COMMENT | NEWLINE )*; + @param ast ASTBlock + @param tc templatecontroller + @result TODO +--> +<#list ast.getStmts() as statement> + ${tc.include("org.nest.spl.Statement", statement)} + \ No newline at end of file diff --git a/src/main/resources/org/nest/spl/CompoundStatement.ftl b/src/main/resources/org/nest/spl/CompoundStatement.ftl new file mode 100644 index 000000000..4d9cb5e92 --- /dev/null +++ b/src/main/resources/org/nest/spl/CompoundStatement.ftl @@ -0,0 +1,16 @@ +<#-- + @grammar: Compound_Stmt = IF_Stmt + | FOR_Stmt + | WHILE_Stmt; + + @param ast ASTCompound_Stmt + @param tc templatecontroller + @result TODO +--> +<#if ast.getIF_Stmt().isPresent()> +${tc.include("org.nest.spl.IfStatement", ast.getIF_Stmt().get())} +<#elseif ast.getFOR_Stmt().isPresent()> +${tc.include("org.nest.spl.ForStatement", ast.getFOR_Stmt().get())} +<#elseif ast.getWHILE_Stmt().isPresent()> +${tc.include("org.nest.spl.WhileStatement", ast.getWHILE_Stmt().get())} + \ No newline at end of file diff --git a/src/main/resources/org/nest/spl/Declaration.ftl b/src/main/resources/org/nest/spl/Declaration.ftl new file mode 100644 index 000000000..1ea0a56a8 --- /dev/null +++ b/src/main/resources/org/nest/spl/Declaration.ftl @@ -0,0 +1,18 @@ +<#-- + Generates C++ declaration + @grammar: + Declaration = + vars:Name ("," vars:Name)* + (type:QualifiedName | primitiveType:PrimitiveType) + ("<" sizeParameter:Name ">")? + ( "=" Expr )? ; + @param ast ASTDeclaration +--> +<#assign declarationType = declarations.getDeclarationType(ast)> + +<#list declarations.getVariables(ast) as variableName> + ${declarationType} ${variableName} + <#if ast.getExpr().isPresent()> + = ${tc.include("org.nest.spl.expr.Expr", ast.getExpr().get())} + ; + diff --git a/src/main/resources/org/nest/spl/ForStatement.ftl b/src/main/resources/org/nest/spl/ForStatement.ftl new file mode 100644 index 000000000..3b6f825de --- /dev/null +++ b/src/main/resources/org/nest/spl/ForStatement.ftl @@ -0,0 +1,14 @@ +<#-- + Generates C++ declaration + @grammar: FOR_Stmt = "for" var:Name "in" from:Expr "..." to:Expr ("step" step:SignedNumericLiteral)? BLOCK_OPEN Block BLOCK_CLOSE; + @param ast ASTFOR_Stmt + @param tc templatecontroller + @result TODO +--> +for( ${ast.getVar()} = ${tc.include("org.nest.spl.expr.Expr", ast.getFrom())} ; + ${ast.getVar()} ${forDeclarationHelper.printComparisonOperator(ast)}${tc.include("org.nest.spl.expr.Expr", ast.getTo())} ; + ${ast.getVar()} += ${forDeclarationHelper.printStep(ast)} ) +{ + ${tc.include("org.nest.spl.Block", ast.getBlock())} +} /* for end */ + diff --git a/src/main/resources/org/nest/spl/FunctionCall.ftl b/src/main/resources/org/nest/spl/FunctionCall.ftl new file mode 100644 index 000000000..08321bc3f --- /dev/null +++ b/src/main/resources/org/nest/spl/FunctionCall.ftl @@ -0,0 +1,10 @@ +<#-- + Generates C++ declaration + @grammar: FunctionCall = QualifiedName "(" ArgList ")"; + ArgList = (args:Expr ("," args:Expr)*)?; + @param ast ASTFunctionCall + @param tc templatecontroller + @result TODO +--> +${expressionsPrinter.printMethodCall(ast)}; + diff --git a/src/main/resources/org/nest/spl/IfStatement.ftl b/src/main/resources/org/nest/spl/IfStatement.ftl new file mode 100644 index 000000000..e671ea0fa --- /dev/null +++ b/src/main/resources/org/nest/spl/IfStatement.ftl @@ -0,0 +1,27 @@ +<#-- + Generates C++ declaration + @grammar: IF_Stmt = IF_Clause + ELIF_Clause* + (ELSE_Clause)? + BLOCK_CLOSE; + IF_Clause = "if" Expr BLOCK_OPEN Block; + ELIF_Clause = "elif" Expr BLOCK_OPEN Block; + + @param ast ASTIF_Stmt + @param tc templatecontroller + @result TODO +--> + +if (${tc.include("org.nest.spl.expr.Expr", ast.getIF_Clause().getExpr())}) { +${tc.include("org.nest.spl.Block", ast.getIF_Clause().getBlock())} +<#list ast.getELIF_Clauses() as elif> +else if(${tc.include("org.nest.spl.expr.Expr", elif.getExpr())}) { +${tc.include("org.nest.spl.Block", elif.getBlock())} + +<#if ast.getELSE_Clause().isPresent()> +} +else { +${tc.include("org.nest.spl.Block", ast.getELSE_Clause().get().getBlock())} + +} /* if end */ + diff --git a/src/main/resources/org/nest/spl/ReturnStatement.ftl b/src/main/resources/org/nest/spl/ReturnStatement.ftl new file mode 100644 index 000000000..b4009fd8a --- /dev/null +++ b/src/main/resources/org/nest/spl/ReturnStatement.ftl @@ -0,0 +1,11 @@ +<#-- + @grammar: + @param ast ASTStmt ReturnStmt = "return" Expr?; + @param tc templatecontroller + @result TODO +--> +<#if ast.getExpr().isPresent()> +return ${tc.include("org.nest.spl.expr.Expr", ast.getExpr().get())}; +<#elseif ast.getCompound_Stmt().isPresent()> +return ; + \ No newline at end of file diff --git a/src/main/resources/org/nest/spl/SimpleStmt.ftl b/src/main/resources/org/nest/spl/SimpleStmt.ftl new file mode 100644 index 000000000..b721f869a --- /dev/null +++ b/src/main/resources/org/nest/spl/SimpleStmt.ftl @@ -0,0 +1,10 @@ +<#-- + Handles a complex block statement + @grammar: Simple_Stmt = Small_Stmt (";" Small_Stmt)* (";")?; + @param ast ASTSimple_Stmt + @param tc templatecontroller + @result TODO +--> +<#list ast.getSmall_Stmts() as smallStatement> +${tc.include("org.nest.spl.SmallStatement", smallStatement)} + \ No newline at end of file diff --git a/src/main/resources/org/nest/spl/SmallStatement.ftl b/src/main/resources/org/nest/spl/SmallStatement.ftl new file mode 100644 index 000000000..b21f04d44 --- /dev/null +++ b/src/main/resources/org/nest/spl/SmallStatement.ftl @@ -0,0 +1,18 @@ +<#-- + @grammar: Small_Stmt = Assignment + | FunctionCall + | Declaration + | ReturnStmt; + @param ast ASTSmall_Stmt + @param tc templatecontroller + @result TODO +--> +<#if ast.getAssignment().isPresent()> +${tc.include("org.nest.spl.Assignment", ast.getAssignment().get())} +<#elseif ast.getFunctionCall().isPresent()> +${tc.include("org.nest.spl.FunctionCall", ast.getFunctionCall().get())} +<#elseif ast.getDeclaration().isPresent()> +${tc.include("org.nest.spl.Declaration", ast.getDeclaration().get())} +<#elseif ast.getReturnStmt().isPresent()> +${tc.include("org.nest.spl.ReturnStatement", ast.getReturnStmt().get())} + \ No newline at end of file diff --git a/src/main/resources/org/nest/spl/Statement.ftl b/src/main/resources/org/nest/spl/Statement.ftl new file mode 100644 index 000000000..bf07bea2a --- /dev/null +++ b/src/main/resources/org/nest/spl/Statement.ftl @@ -0,0 +1,11 @@ +<#-- + @grammar: Stmt = Simple_Stmt ((SL_COMMENT | NEWLINE)* | EOF) | Compound_Stmt; + @param ast ASTStmt + @param tc templatecontroller + @result TODO +--> +<#if ast.getSimple_Stmt().isPresent()> +${tc.include("org.nest.spl.SimpleStmt", ast.getSimple_Stmt().get())} +<#elseif ast.getCompound_Stmt().isPresent()> +${tc.include("org.nest.spl.CompoundStatement", ast.getCompound_Stmt().get())} + \ No newline at end of file diff --git a/src/main/resources/org/nest/spl/WhileStatement.ftl b/src/main/resources/org/nest/spl/WhileStatement.ftl new file mode 100644 index 000000000..9a5be468d --- /dev/null +++ b/src/main/resources/org/nest/spl/WhileStatement.ftl @@ -0,0 +1,10 @@ +<#-- + Generates C++ declaration + @grammar: WHILE_Stmt = "while" Expr BLOCK_OPEN Block BLOCK_CLOSE; + @param ast ASTWHILE_Stmt + @param tc templatecontroller + @result TODO +--> +while(${tc.include("org.nest.spl.expr.Expr", ast.getExpr())}) { +${tc.include("org.nest.spl.Block", ast.getBlock())} +} /* while end */ \ No newline at end of file diff --git a/src/main/resources/org/nest/spl/expr/Expr.ftl b/src/main/resources/org/nest/spl/expr/Expr.ftl new file mode 100644 index 000000000..4af0129b9 --- /dev/null +++ b/src/main/resources/org/nest/spl/expr/Expr.ftl @@ -0,0 +1,9 @@ +<#-- + Converts an Expr-Node + + @param ast ASTExpr + @param tc templatecontroller + @result TODO +--> +${expressionsPrinter.print(ast)} + diff --git a/src/test/java/org/nest/cli/CLIConfigurationExecutorTest.java b/src/test/java/org/nest/cli/CLIConfigurationExecutorTest.java new file mode 100644 index 000000000..4c6a49339 --- /dev/null +++ b/src/test/java/org/nest/cli/CLIConfigurationExecutorTest.java @@ -0,0 +1,28 @@ +package org.nest.cli; + +import org.junit.Test; + +/** + * Created by user on 05.06.15. + */ +public class CLIConfigurationExecutorTest { + private static final String TEST_INPUT_PATH = "src/test/resources/codegeneration"; + private static final String TEST_MODEL_PATH = "src/test/resources/"; + private static final String TARGET_FOLDER = "target"; + private final NESTMLToolConfiguration testConfig; + private final CLIConfigurationExecutor executor = new CLIConfigurationExecutor(); + public CLIConfigurationExecutorTest() { + testConfig = new NESTMLToolConfiguration.Builder() + .withCoCos() + .withInputBasePath(TEST_INPUT_PATH) + .withModelPath(TEST_MODEL_PATH) + .withTargetPath(TARGET_FOLDER) + .build(); + } + + @Test + public void testExecutionTestConfiguration() { + executor.execute(testConfig); + } + +} diff --git a/src/test/java/org/nest/cli/NESTMLFrontendTest.java b/src/test/java/org/nest/cli/NESTMLFrontendTest.java new file mode 100644 index 000000000..ee9b27c6a --- /dev/null +++ b/src/test/java/org/nest/cli/NESTMLFrontendTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.cli; + +import org.apache.commons.cli.CommandLine; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Tests various modis of the {@code NESTMLFrontend} class. For this, several combinations of + * CLI parameters also invalid combination are provided to the frontend. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLFrontendTest { + private final NESTMLFrontend nestmlFrontend = new NESTMLFrontend(); + + @Test + public void testCreationOfConfiguration() throws Exception { + + final String testInputModelsPath = "testInputModelsPath"; + final String testModelPath = "testModelPath"; + final String targetPath = "targetPath"; + + final NESTMLToolConfiguration testant = nestmlFrontend.createCLIConfiguration(new String[] { + "--runningMode", "parseAndCheck", + "--input", testInputModelsPath, + "--modelPath", testModelPath, + "--target", targetPath + }); + + assertEquals(true, testant.isCheckCoCos()); + assertEquals(testInputModelsPath, testant.getInputBasePath()); + assertEquals(testModelPath, testant.getModelPath()); + assertEquals(targetPath, testant.getTargetPath()); + } + + @Test + public void testInvokeFrontendViaMain() throws Exception { + NESTMLFrontend.main(new String[]{"--runningMode", "parseAndCheck", ""}); + } + + @Test + public void testHelpMessageViaCLI() throws Exception { + NESTMLFrontend.main(new String[]{"--help"}); + } + + @Test(expected = RuntimeException.class) + public void testInvalidOptions() { + CommandLine cliArguments = nestmlFrontend.parseCLIArguments(new String[] { "--runningMode"}); + nestmlFrontend.interpretRunningModeArgument(cliArguments); + } + + @Test + public void testParseMode() throws Exception { + CommandLine cliArguments = nestmlFrontend.parseCLIArguments(new String[] { "--runningMode", "parseAndCheck" }); + boolean testant = nestmlFrontend.interpretRunningModeArgument(cliArguments); + assertTrue(testant); + + cliArguments = nestmlFrontend.parseCLIArguments(new String[] { "--runningMode", "parse" }); + testant = nestmlFrontend.interpretRunningModeArgument(cliArguments); + assertFalse(testant); + + cliArguments = nestmlFrontend.parseCLIArguments(new String[] { }); + testant = nestmlFrontend.interpretRunningModeArgument(cliArguments); + assertFalse(testant); + + ; + } + + @Test + public void testInputModelPath() throws Exception { + final String inputModelsPath = "./testModels"; + CommandLine cliArguments = nestmlFrontend.parseCLIArguments(new String[] { "--input", inputModelsPath}); + final String testant = nestmlFrontend.interpretInputModelsPathArgument(cliArguments); + assertEquals(inputModelsPath, testant); + + } + + @Test + public void testModelPath() throws Exception { + final String inputModelsPath = "./testModelPath"; + CommandLine cliArguments = nestmlFrontend.parseCLIArguments(new String[] { "--modelPath", inputModelsPath}); + final String testant = nestmlFrontend.interpretModelPathArgument(cliArguments); + assertEquals(inputModelsPath, testant); + + } + + @Test + public void testInputPath() throws Exception { + final String inputModelsPath = "./testTargetPath"; + CommandLine cliArguments = nestmlFrontend.parseCLIArguments(new String[] { "--target", inputModelsPath}); + final String testant = nestmlFrontend.interpretTargetPathArgument(cliArguments); + assertEquals(inputModelsPath, testant); + + } + +} diff --git a/src/test/java/org/nest/codegeneration/GenerateNESTModelsTest.java b/src/test/java/org/nest/codegeneration/GenerateNESTModelsTest.java new file mode 100644 index 000000000..c40cb4a5b --- /dev/null +++ b/src/test/java/org/nest/codegeneration/GenerateNESTModelsTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import com.google.common.collect.Lists; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + +/** + * Generates entire NEST implementation for several NESTML models. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class GenerateNESTModelsTest extends GenerationTestBase { + private static final String INTEGRATION_MODEL_PATH = "src/test/resources/integration"; + + private static final String OUTPUT_FOLDER = "target"; + + private final List nestmlModels = Lists.newArrayList( + "src/test/resources/integration/nest.nestml"); + + @Override + protected String getModelPath() { + return INTEGRATION_MODEL_PATH; + } + + @Test + public void testHeaderGenerator() throws IOException { + nestmlModels.forEach(this::generateHeader); + } + + @Test + public void testImplementationGenerator() throws IOException { + nestmlModels.forEach(this::generateClassImplementation); + } + + @Test + public void testGenerateCodeForModelIntegrationInNest() throws IOException { + nestmlModels.forEach(this::generateCodeForModelIntegrationInNest); + } + +} diff --git a/src/test/java/org/nest/codegeneration/GenerationTestBase.java b/src/test/java/org/nest/codegeneration/GenerationTestBase.java new file mode 100644 index 000000000..7e8ebd4c2 --- /dev/null +++ b/src/test/java/org/nest/codegeneration/GenerationTestBase.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import de.monticore.cocos.CoCoLog; +import de.monticore.generating.templateengine.GlobalExtensionManagement; +import de.se_rwth.commons.logging.Log; +import org.junit.Before; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._cocos.NESTMLCoCoChecker; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml._symboltable.NESTMLCoCosManager; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.codegeneration.converters.NESTReferenceConverter; +import org.nest.spl.prettyprinter.ExpressionsPrettyPrinter; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.utils.LogHelper; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +/** + * Base class for the NEST generator tests. + * Provides the methods to generate header, cpp implementation and boostraping. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public abstract class GenerationTestBase { + + private static final String OUTPUT_FOLDER = "target"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + private final NESTMLScopeCreator nestmlScopeCreator + = new NESTMLScopeCreator(getModelPath(), typesFactory); // must be called in order to build the symbol table + + protected abstract String getModelPath(); + @Before + public void setup() { + Log.enableFailQuick(false); + CoCoLog.getFindings().clear(); + } + + protected void generateHeader(final String modelPath) { + final GlobalExtensionManagement glex = createGLEXConfiguration(); + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory + .createNESTMLCompilationUnitMCParser(); + final Optional root; + try { + root = p.parse(modelPath); + assertTrue(root.isPresent()); + nestmlScopeCreator.runSymbolTableCreator(root.get()); + final File outputFolder = new File(OUTPUT_FOLDER); + + NESTML2NESTCodeGenerator.generateHeader(glex, root.get(), + nestmlScopeCreator.getTypesFactory(), outputFolder); + } + catch (IOException e) { // lambda functions doesn't support checked exceptions + throw new RuntimeException(e); + } + + } + + protected void generateClassImplementation(final String MODEL_FILE_PATH) { + final GlobalExtensionManagement glex = createGLEXConfiguration(); + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory.createNESTMLCompilationUnitMCParser(); + final Optional root; + try { + root = p.parse(MODEL_FILE_PATH); + + assertTrue(root.isPresent()); + + nestmlScopeCreator.runSymbolTableCreator(root.get()); + + final File outputFolder = new File(OUTPUT_FOLDER); + + NESTML2NESTCodeGenerator.generateClassImplementation(glex, + nestmlScopeCreator.getTypesFactory(), root.get(), outputFolder); + } + catch (IOException e) { // lambda functions doesn't support checked exceptions + throw new RuntimeException(e); + } + + } + + protected void generateCodeForModelIntegrationInNest(final String modelFile) { + final GlobalExtensionManagement glex = createGLEXConfiguration(); + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory.createNESTMLCompilationUnitMCParser(); + final Optional root; + try { + root = p.parse(modelFile); + assertTrue(root.isPresent()); + + nestmlScopeCreator.runSymbolTableCreator(root.get()); + + final File outputFolder = new File(OUTPUT_FOLDER); + + NESTML2NESTCodeGenerator.generateCodeForModelIntegrationInNest(glex, root.get(), outputFolder); + } + catch (IOException e) { // lambda functions doesn't support checked exceptions + throw new RuntimeException(e); + } + + } + + protected GlobalExtensionManagement createGLEXConfiguration() { + final GlobalExtensionManagement glex = new GlobalExtensionManagement(); + + final NESTReferenceConverter converter = new NESTReferenceConverter(typesFactory); + + // TODO resolve this circular dependency + final ExpressionsPrettyPrinter expressionsPrinter = new ExpressionsPrettyPrinter(converter); + + glex.setGlobalValue("expressionsPrinter", expressionsPrinter); + glex.setGlobalValue("functionCallConverter", converter); // TODO better name + return glex; + } + + public void checkCocos(String modelFilePath) { + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory.createNESTMLCompilationUnitMCParser(); + final Optional root; + try { + root = p.parse(modelFilePath); + assertTrue(root.isPresent()); + + nestmlScopeCreator.runSymbolTableCreator(root.get()); + final NESTMLCoCoChecker checker + = new NESTMLCoCosManager(root.get(), nestmlScopeCreator.getTypesFactory()). + createNESTMLCheckerWithSPLCocos(); + checker.checkAll(root.get()); + + Collection errorFindings + = LogHelper.getFindingsByPrefix("NESTML_", CoCoLog.getFindings()); + errorFindings.addAll(LogHelper.getFindingsByPrefix("SPL_", CoCoLog.getFindings())); + errorFindings.forEach(System.out::println); + // TODO reactivate me + assertTrue("Models contain unexpected errors: " + errorFindings.size(), + errorFindings.isEmpty()); + + } + catch (IOException e) { // lambda functions doesn't support checked exceptions + throw new RuntimeException(e); + } + + } +} diff --git a/src/test/java/org/nest/codegeneration/NESTML2NESTCodeGeneratorTest.java b/src/test/java/org/nest/codegeneration/NESTML2NESTCodeGeneratorTest.java new file mode 100644 index 000000000..995d6df15 --- /dev/null +++ b/src/test/java/org/nest/codegeneration/NESTML2NESTCodeGeneratorTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +import com.google.common.collect.Lists; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + + +/** + * Generates entire NEST implementation for several NESTML models. + * + * @author plotnikov + * @since 0.0.1 + */ +public class NESTML2NESTCodeGeneratorTest extends GenerationTestBase { + private static final String TEST_MODEL_PATH = "src/test/resources/"; + + private final List nestmlModels = Lists.newArrayList( + /*"src/test/resources/codegeneration/iaf_neuron_module.nestml", + // TODO "src/test/resources/codegeneration/iaf_neuron_ode_module.nestml", + "src/test/resources/codegeneration/iaf_tum_2000_module.nestml", + "src/test/resources/codegeneration/iaf_psc_alpha_module.nestml", + "src/test/resources/codegeneration/iaf_psc_exp_module.nestml", + "src/test/resources/codegeneration/iaf_psc_delta_module.nestml",*/ + "src/test/resources/codegeneration/iaf_psc_exp_multisynapse_module.nestml" + ); + + @Override + protected String getModelPath() { + return TEST_MODEL_PATH; + } + + @Test + public void checkCocosOnModels() throws IOException { + // TODO: filters ode model that uses undefined variables + nestmlModels.stream().filter(model -> !model.equals("src/test/resources/codegeneration/iaf_neuron_ode_module.nestml")).forEach(this::checkCocos); + } + + @Test + public void testHeaderGenerator() throws IOException { + nestmlModels.forEach(this::generateHeader); + } + + @Test + public void testImplementationGenerator() throws IOException { + nestmlModels.forEach(this::generateClassImplementation); + } + + @Test + public void testGenerateCodeForModelIntegrationInNest() throws IOException { + nestmlModels.forEach(this::generateCodeForModelIntegrationInNest); + } + + +} diff --git a/src/test/java/org/nest/codegeneration/NESTML2NESTWithODECodeGeneratorTest.java b/src/test/java/org/nest/codegeneration/NESTML2NESTWithODECodeGeneratorTest.java new file mode 100644 index 000000000..4c6b9c5db --- /dev/null +++ b/src/test/java/org/nest/codegeneration/NESTML2NESTWithODECodeGeneratorTest.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.codegeneration; + +/** + * TODO + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTML2NESTWithODECodeGeneratorTest extends GenerationTestBase { + + private static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final String OUTPUT_FOLDER = "target"; + + private final static String GENERATED_MATRIX_PATH = "src/test/resources/org/nest/ode/solution.matrix.tmp"; + + @Override + protected String getModelPath() { + return TEST_MODEL_PATH; + } +} diff --git a/src/test/java/org/nest/integration/NESTMLCompilationTest.java b/src/test/java/org/nest/integration/NESTMLCompilationTest.java new file mode 100644 index 000000000..32de88f08 --- /dev/null +++ b/src/test/java/org/nest/integration/NESTMLCompilationTest.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.integration; + +import org.junit.Test; + +/** + * Runs the codegenerator and compiles the resulting code. Afterthat, check is the make commomand + * run successfully. + * + * @author plotnikov + * @since 0.0.2 + */ +public class NESTMLCompilationTest { + + @Test + public void testCompilationOfTheGeneratedCode() { + final String compilationCommand = "make"; + } + +} diff --git a/src/test/java/org/nest/nestml/cocos/NESTMLCoCosTest.java b/src/test/java/org/nest/nestml/cocos/NESTMLCoCosTest.java new file mode 100644 index 000000000..b9be558ce --- /dev/null +++ b/src/test/java/org/nest/nestml/cocos/NESTMLCoCosTest.java @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml.cocos; + +import de.monticore.cocos.CoCoLog; +import de.se_rwth.commons.Names; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nest.nestml.cocos.spl.BufferNotAssignable; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._cocos.*; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.spl.cocos.VarHasTypeName; +import org.nest.spl._cocos.SPLASTDeclarationCoCo; +import org.nest.spl.symboltable.SPLCoCosManager; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.utils.LogHelper; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.nest.nestml._symboltable.NESTMLRootCreator.getAstRoot; +import static org.nest.utils.LogHelper.countOccurrences; + +/** + * Test every context context conditions. For each implemented context condition there is one model that contains exactly one tested error. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLCoCosTest { + + public static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final String TEST_MODELS_FOLDER = "src/test/resources/org/nest/nestml/cocos/"; + + private NESTMLCoCoChecker nestmlCoCoChecker; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + private NESTMLScopeCreator scopeCreator = new NESTMLScopeCreator(TEST_MODEL_PATH, typesFactory); + + @BeforeClass + public static void initLog() { + CoCoLog.setDelegateToLog(false); + } + + @Before + public void setup() { + CoCoLog.getFindings().clear(); + nestmlCoCoChecker = new NESTMLCoCoChecker(); + + } + + @After + public void printErrorMessage() { + CoCoLog.getFindings().forEach(e -> System.out.println("Error found: " + e)); + } + + @Test + public void testResolvingOfPredefinedTypes() { + // just take an arbitrary nestml model with an import: nestml* + final Optional ast = getAstRoot( + TEST_MODELS_FOLDER + "functionWithOutReturn.nestml"); + assertTrue(ast.isPresent()); + + scopeCreator.getTypesFactory().getTypes().forEach(type -> { + Optional predefinedType = scopeCreator.getGlobalScope() + .resolve(Names.getSimpleName(type.getName()), NESTMLTypeSymbol.KIND); + assertTrue("Cannot resolve the predefined type: " + type.getFullName(), + predefinedType.isPresent()); + }); + } + + @Test + public void testAliasHasNoSetter() { + final Optional root = getAstRoot(TEST_MODELS_FOLDER + "aliasSetter.nestml"); + assertTrue(root.isPresent()); + + scopeCreator.runSymbolTableCreator(root.get()); + + final AliasHasNoSetter aliasHasNoSetter = new AliasHasNoSetter(root.get()); + nestmlCoCoChecker.addCoCo(aliasHasNoSetter); + nestmlCoCoChecker.checkAll(root.get()); + + Integer errorsFound = countOccurrences(AliasHasNoSetter.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(2), errorsFound); + } + + @Test + public void testAliasHasOneVar() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "aliasMultipleVars.nestml"); + assertTrue(ast.isPresent()); + + final AliasHasOneVar aliasHasOneVar = new AliasHasOneVar(); + nestmlCoCoChecker.addCoCo(aliasHasOneVar); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(AliasHasOneVar.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testAliasInNonAliasDecl() { + final Optional ast = getAstRoot( + TEST_MODELS_FOLDER + "useAliasInNonAliasDecl.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final AliasInNonAliasDecl aliasInNonAliasDecl = new AliasInNonAliasDecl(); + nestmlCoCoChecker.addCoCo((NESTMLASTComponentCoCo) aliasInNonAliasDecl); + nestmlCoCoChecker.addCoCo((NESTMLASTNeuronCoCo) aliasInNonAliasDecl); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(AliasInNonAliasDecl.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testComponentHasNoDynamics() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "componentWithDynamics.nestml"); + assertTrue(ast.isPresent()); + + final ComponentHasNoDynamics componentHasNoDynamics = new ComponentHasNoDynamics(); + nestmlCoCoChecker.addCoCo(componentHasNoDynamics); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(ComponentHasNoDynamics.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testComponentNoInput() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "componentWithInput.nestml"); + assertTrue(ast.isPresent()); + + final ComponentNoInput componentNoInput = new ComponentNoInput(); + nestmlCoCoChecker.addCoCo(componentNoInput); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(ComponentNoInput.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testComponentNoOutput() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "componentWithOutput.nestml"); + assertTrue(ast.isPresent()); + + final ComponentNoOutput componentNoOutput = new ComponentNoOutput(); + nestmlCoCoChecker.addCoCo(componentNoOutput); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(ComponentNoOutput.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testCorrectReturnValues() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + + "functionsWithWrongReturns.nestml"); + assertTrue(ast.isPresent()); + + scopeCreator.runSymbolTableCreator(ast.get()); + + final CorrectReturnValues correctReturnValues + = new CorrectReturnValues(scopeCreator.getTypesFactory()); + nestmlCoCoChecker.addCoCo(correctReturnValues); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(CorrectReturnValues.ERROR_CODE, CoCoLog.getFindings()); + CoCoLog.getFindings().forEach(f -> System.out.println(f.getCode() + ":" + f.getMsg())); + // TODO check if this does make sense? + assertEquals(Integer.valueOf(10), errorsFound); + } + + @Test + public void testCurrentInputIsNotInhExc() { + final Optional ast = getAstRoot( + TEST_MODELS_FOLDER + "inputTypeForCurrent.nestml"); + assertTrue(ast.isPresent()); + + final CurrentInputIsNotInhExc currentInputIsNotInhExc = new CurrentInputIsNotInhExc(); + nestmlCoCoChecker.addCoCo(currentInputIsNotInhExc); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(CurrentInputIsNotInhExc.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(3), errorsFound); + } + + @Test + public void testDynamicsTimeStepParameter() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "timestepDynamics.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final DynamicsTimeStepParameter dynamicsTimeStepParameter = new DynamicsTimeStepParameter(); + nestmlCoCoChecker.addCoCo(dynamicsTimeStepParameter); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(DynamicsTimeStepParameter.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(3), errorsFound); + } + + @Test + public void testFunctionHasReturnStatement() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "functionWithOutReturn.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final FunctionHasReturnStatement functionHasReturnStatement = new FunctionHasReturnStatement( + scopeCreator.getTypesFactory()); + nestmlCoCoChecker.addCoCo(functionHasReturnStatement); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(FunctionHasReturnStatement.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testInvalidTypesInDeclaration() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "invalidTypeInDecl.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final InvalidTypesInDeclaration invalidTypesInDeclaration = new InvalidTypesInDeclaration(); + + nestmlCoCoChecker.addCoCo((NESTMLASTUSE_StmtCoCo) invalidTypesInDeclaration); + nestmlCoCoChecker.addCoCo((NESTMLASTFunctionCoCo) invalidTypesInDeclaration); + nestmlCoCoChecker.addCoCo((SPLASTDeclarationCoCo) invalidTypesInDeclaration); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(InvalidTypesInDeclaration.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(6), errorsFound); + } + + @Test + public void testMemberVariableDefinedMultipleTimes() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "varDefinedMultipleTimes.nestml"); + assertTrue(ast.isPresent()); + + final MemberVariableDefinedMultipleTimes memberVariableDefinedMultipleTimes = new MemberVariableDefinedMultipleTimes(); + + nestmlCoCoChecker.addCoCo((NESTMLASTComponentCoCo) memberVariableDefinedMultipleTimes); + nestmlCoCoChecker.addCoCo((NESTMLASTNeuronCoCo) memberVariableDefinedMultipleTimes); + + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(MemberVariableDefinedMultipleTimes.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testMemberVariablesInitialisedInCorrectOrder() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "memberVarDefinedInWrongOrder.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + final MemberVariablesInitialisedInCorrectOrder memberVariablesInitialisedInCorrectOrder + = new MemberVariablesInitialisedInCorrectOrder(); + + nestmlCoCoChecker.addCoCo(memberVariablesInitialisedInCorrectOrder); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(MemberVariablesInitialisedInCorrectOrder.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(3), errorsFound); + } + + @Test + public void testMultipleFunctionsDeclarations() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "multipleFunctionDeclarations.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final MultipleFunctionDeclarations multipleFunctionDeclarations + = new MultipleFunctionDeclarations(); + nestmlCoCoChecker.addCoCo((NESTMLASTComponentCoCo) multipleFunctionDeclarations); + nestmlCoCoChecker.addCoCo((NESTMLASTNeuronCoCo) multipleFunctionDeclarations); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(MultipleFunctionDeclarations.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(6), errorsFound); + } + + @Test + public void testMultipleInhExcInput() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "multipleInhExcInInput.nestml"); + assertTrue(ast.isPresent()); + + final MultipleInhExcInput multipleInhExcInput = new MultipleInhExcInput(); + nestmlCoCoChecker.addCoCo(multipleInhExcInput); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(MultipleInhExcInput.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(4), errorsFound); + } + + @Test + public void testMultipleOutputs() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "multipleOutputs.nestml"); + assertTrue(ast.isPresent()); + + final MultipleOutputs multipleOutputs = new MultipleOutputs(); + nestmlCoCoChecker.addCoCo(multipleOutputs); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(MultipleOutputs.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testFunctionNameChecker() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "nestFunName.nestml"); + assertTrue(ast.isPresent()); + + final NESTFunctionNameChecker functionNameChecker = new NESTFunctionNameChecker(); + nestmlCoCoChecker.addCoCo(functionNameChecker); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(NESTFunctionNameChecker.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(9), errorsFound); + } + + @Test + public void testNESTGetterSetterFunctionNames() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "getterSetter.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final NESTGetterSetterFunctionNames nestGetterSetterFunctionNames = new NESTGetterSetterFunctionNames(); + nestmlCoCoChecker.addCoCo(nestGetterSetterFunctionNames); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(NESTGetterSetterFunctionNames.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(4), errorsFound); + } + + @Test + public void testNeuronNeedsDynamicsWithNoDynamics() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "emptyNeuron.nestml"); + assertTrue(ast.isPresent()); + + final NeuronNeedsDynamics neuronNeedsDynamics = new NeuronNeedsDynamics(); + nestmlCoCoChecker.addCoCo(neuronNeedsDynamics); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(NeuronNeedsDynamics.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testNeuronNeedsDynamicsWithMultipleDynamics() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "multipleDynamicsNeuron.nestml"); + assertTrue(ast.isPresent()); + + final NeuronNeedsDynamics neuronNeedsDynamics = new NeuronNeedsDynamics(); + nestmlCoCoChecker.addCoCo(neuronNeedsDynamics); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(NeuronNeedsDynamics.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testNeuronWithoutInput() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "emptyNeuron.nestml"); + assertTrue(ast.isPresent()); + + final NeuronWithoutInput neuronNeedsDynamics = new NeuronWithoutInput(); + nestmlCoCoChecker.addCoCo(neuronNeedsDynamics); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(NeuronWithoutInput.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testNeuronWithoutOutput() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "emptyNeuron.nestml"); + assertTrue(ast.isPresent()); + + final NeuronWithoutOutput neuronWithoutOutput = new NeuronWithoutOutput(); + nestmlCoCoChecker.addCoCo(neuronWithoutOutput); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(NeuronWithoutOutput.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testTypesDeclaredMultipleTimes() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "multipleTypesDeclared.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final TypeIsDeclaredMultipleTimes typeIsDeclaredMultipleTimes = new TypeIsDeclaredMultipleTimes(); + nestmlCoCoChecker.addCoCo((NESTMLASTComponentCoCo) typeIsDeclaredMultipleTimes); + nestmlCoCoChecker.addCoCo((NESTMLASTNeuronCoCo) typeIsDeclaredMultipleTimes); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(TypeIsDeclaredMultipleTimes.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(2), errorsFound); + } + + @Test + public void testUsesOnlyComponents() { + + final UsesOnlyComponents usesOnlyComponents = new UsesOnlyComponents(); + nestmlCoCoChecker.addCoCo(usesOnlyComponents); + + String pathToValidModel = TEST_MODELS_FOLDER + "useComponents/validUsage.nestml"; + checkModelAndAssertNoErrors( + pathToValidModel, + nestmlCoCoChecker, + "NESTML_"); + + String pathToInvalidModel = TEST_MODELS_FOLDER + "useComponents/invalidUsage.nestml"; + checkModelAndAssertWithErrors( + pathToInvalidModel, + nestmlCoCoChecker, + "NESTML_", + 2); + } + + @Test + public void testBufferNotAssignable() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "reassignBuffer.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final BufferNotAssignable bufferNotAssignable = new BufferNotAssignable(); + // TODO: rewrite: Must be possible: wait for the visitor that visits super types + nestmlCoCoChecker.addCoCo(bufferNotAssignable); + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(BufferNotAssignable.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testSplCocosInNestml() { + final NESTMLCoCoChecker nestmlCoCoCheckerWithSPLCocos = new NESTMLCoCoChecker(); + final SPLCoCosManager splCoCosManager = new SPLCoCosManager(scopeCreator.getTypesFactory()); + splCoCosManager.addSPLCocosToNESTMLChecker(nestmlCoCoCheckerWithSPLCocos); + + String pathToValidModel = TEST_MODELS_FOLDER + "splInFunctions/validMethod.nestml"; + checkModelAndAssertNoErrors( + pathToValidModel, + nestmlCoCoCheckerWithSPLCocos, + "SPL_"); + + String pathToInvalidModel = TEST_MODELS_FOLDER + "splInFunctions/invalidMethod.nestml"; + checkModelAndAssertWithErrors( + pathToInvalidModel, + nestmlCoCoCheckerWithSPLCocos, + "SPL_", + 18); + } + + @Test + public void testVarHasTypeName() { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "varWithTypeName.nestml"); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + final VarHasTypeName varHasTypeName = new VarHasTypeName(); + nestmlCoCoChecker.addCoCo(varHasTypeName); + + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(VarHasTypeName.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(2), errorsFound); + } + + @Test + public void testUsageIncorrectOrder() { + String pathToValidModel = TEST_MODELS_FOLDER + "undefinedVariables/validModelUndefinedValues.nestml"; + checkModelAndAssertNoErrors( + pathToValidModel, + nestmlCoCoChecker, + MemberVariablesInitialisedInCorrectOrder.ERROR_CODE); + + final MemberVariablesInitialisedInCorrectOrder memberVariablesInitialisedInCorrectOrder + = new MemberVariablesInitialisedInCorrectOrder(); + nestmlCoCoChecker.addCoCo(memberVariablesInitialisedInCorrectOrder); + + String pathToInvalidModel = TEST_MODELS_FOLDER + "undefinedVariables/invalidModelUndefinedValues.nestml"; + checkModelAndAssertWithErrors( + pathToInvalidModel, + nestmlCoCoChecker, + MemberVariablesInitialisedInCorrectOrder.ERROR_CODE, + 3); + + } + + @Test + public void testSplInFunctions() { + final NESTMLCoCoChecker nestmlCoCoCheckerWithSPLCocos = new NESTMLCoCoChecker(); + final SPLCoCosManager splCoCosManager = new SPLCoCosManager(scopeCreator.getTypesFactory()); + splCoCosManager.addSPLCocosToNESTMLChecker(nestmlCoCoCheckerWithSPLCocos); + + String pathToValidModel = TEST_MODELS_FOLDER + "splInFunctions/validMethod.nestml"; + checkModelAndAssertNoErrors( + pathToValidModel, + nestmlCoCoCheckerWithSPLCocos, + "SPL_"); + + String pathToInvalidModel = TEST_MODELS_FOLDER + "splInFunctions/invalidMethod.nestml"; + checkModelAndAssertWithErrors( + pathToInvalidModel, + nestmlCoCoCheckerWithSPLCocos, + "SPL_", + 18); + + } + + @Test + public void testInvalidInvariantExpressionType() { + final BooleanInvariantExpressions booleanInvariantExpressions + = new BooleanInvariantExpressions(scopeCreator.getTypesFactory()); + nestmlCoCoChecker.addCoCo(booleanInvariantExpressions); + + String pathToValidModel = TEST_MODELS_FOLDER + "invariants/validInvariantType.nestml"; + checkModelAndAssertNoErrors( + pathToValidModel, + nestmlCoCoChecker, + BooleanInvariantExpressions.ERROR_CODE); + + String pathToInvalidModel = TEST_MODELS_FOLDER + "invariants/invalidInvariantType.nestml"; + checkModelAndAssertWithErrors( + pathToInvalidModel, + nestmlCoCoChecker, + BooleanInvariantExpressions.ERROR_CODE, + 2); + + } + + private void checkModelAndAssertNoErrors( + final String pathToModel, + final NESTMLCoCoChecker nestmlCoCoChecker, + final String expectedErrorCode) { + final Optional ast = getAstRoot(pathToModel); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + nestmlCoCoChecker.checkAll(ast.get()); + + int errorsFound = LogHelper.countOccurrencesByPrefix(expectedErrorCode, CoCoLog.getFindings()); + assertEquals(0, errorsFound); + + } + + private void checkModelAndAssertWithErrors( + final String pathToModel, + final NESTMLCoCoChecker nestmlCoCoChecker, + final String expectedErrorCode, + final Integer expectedNumberCount) { + final Optional ast = getAstRoot(pathToModel); + assertTrue(ast.isPresent()); + scopeCreator.runSymbolTableCreator(ast.get()); + + nestmlCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = LogHelper.countOccurrencesByPrefix(expectedErrorCode, + CoCoLog.getFindings()); + assertEquals(expectedNumberCount, errorsFound); + + } + +} diff --git a/src/test/java/org/nest/nestml/parsing/NESTMLParsingTest.java b/src/test/java/org/nest/nestml/parsing/NESTMLParsingTest.java new file mode 100644 index 000000000..292481c78 --- /dev/null +++ b/src/test/java/org/nest/nestml/parsing/NESTMLParsingTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml.parsing; + +import de.se_rwth.commons.logging.Log; +import org.junit.Test; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +/** + * Tests whether the nestml model can be parsed + */ +public class NESTMLParsingTest { + + private final static String PARSABLE_MODELS_FOLDER = "src/test/resources/org/nest/nestml/parsing"; + private final static String COCOS_MODELS_FOLDER = "src/test/resources/org/nest/nestml/cocos"; + private final static String LOG_NAME = NESTMLParsingTest.class.getName(); + private final NESTMLCompilationUnitMCParser parser; + + public NESTMLParsingTest() { + parser = NESTMLParserFactory.createNESTMLCompilationUnitMCParser(); + } + + @Test + public void testParsableModels() throws IOException { + + for (File file: new File(PARSABLE_MODELS_FOLDER).listFiles()) { + Log.trace(String.format("Processes the following file: %s", file.getAbsolutePath()), LOG_NAME); + + Optional ast = parser.parse(file.getAbsolutePath()); + assertTrue(ast.isPresent()); + } + + } + + @Test + public void testModelsForCocos() throws IOException { + for (File file : new File(COCOS_MODELS_FOLDER).listFiles()) { + if (!file.isDirectory()) { + Log.trace(String.format("Processes the following file: %s", file.getAbsolutePath()), LOG_NAME); + + Optional ast = parser.parse(file.getAbsolutePath()); + assertTrue(ast.isPresent()); + + } + } + + } + + @Test + public void testModelWithODE() throws IOException { + Optional ast = parser.parse("src/test/resources/codegeneration/iaf_neuron_ode_module.nestml"); + assertTrue(ast.isPresent()); + } + +} diff --git a/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java b/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java new file mode 100644 index 000000000..87de3d444 --- /dev/null +++ b/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java @@ -0,0 +1,91 @@ +package org.nest.nestml.prettyprinter; + +import de.se_rwth.commons.logging.Log; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +/** + * Created by user on 29.05.15. + */ +public class NESTMLPrettyPrinterTest { + private final NESTMLCompilationUnitMCParser nestmlParser = NESTMLParserFactory + .createNESTMLCompilationUnitMCParser(); + private static final String TEST_MODEL_PATH = "src/test/resources/"; + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + private Optional parseStringAsSPLFile(final String fileAsString) throws IOException { + + return nestmlParser.parse(new StringReader(fileAsString)); + } + + @BeforeClass + public static void BeforeTestsuite() { + Log.enableFailQuick(false); + } + + @Test + public void testThatPrettyPrinterProducesParsableOutput() throws IOException { + parseAndCheckNestmlModel("src/test/resources/org/nest/nestml/parsing/iaf_neuron.nestml"); + } + + @Test + public void testAllModelsForCocos() throws IOException { + parseAllNESTMLModelsFromFolder("src/test/resources/org/nest/nestml/cocos"); + + } + + @Test + public void testAllModelsForParsing() throws IOException { + parseAllNESTMLModelsFromFolder("src/test/resources/org/nest/nestml/parsing"); + + } + + @Test + public void testAllModelsForCodegeneration() throws IOException { + parseAllNESTMLModelsFromFolder("src/test/resources/codegeneration"); + + } + + private void parseAllNESTMLModelsFromFolder(final String folderPath) throws IOException { + final File parserModelsFolder = new File(folderPath); + + for (File splModelFile : parserModelsFolder.listFiles()) { + if (!splModelFile.isDirectory()) { + parseAndCheckNestmlModel(splModelFile.getPath()); + + } + + } + + } + + private void parseAndCheckNestmlModel(String pathToModel) throws IOException { + System.out.println("Handles the model: " + pathToModel); + + final NESTMLPrettyPrinter splPrettyPrinter = NESTMLPrettyPrinterFactory.createNESTMLPrettyPrinter(); + final Optional splModelRoot = nestmlParser.parse(pathToModel); + assertTrue("Cannot parse the model: " + pathToModel, splModelRoot.isPresent()); + + NESTMLScopeCreator nestmlScopeCreator = new NESTMLScopeCreator(TEST_MODEL_PATH, typesFactory); + nestmlScopeCreator.runSymbolTableCreator(splModelRoot.get()); + splModelRoot.get().accept(splPrettyPrinter); + + System.out.println(splPrettyPrinter.getResult()); + + final Optional prettyPrintedRoot = parseStringAsSPLFile(splPrettyPrinter.getResult()); + assertTrue(prettyPrintedRoot.isPresent()); + } + +} diff --git a/src/test/java/org/nest/nestml/symboltable/NESTMLCoCosManagerTest.java b/src/test/java/org/nest/nestml/symboltable/NESTMLCoCosManagerTest.java new file mode 100644 index 000000000..13e146d07 --- /dev/null +++ b/src/test/java/org/nest/nestml/symboltable/NESTMLCoCosManagerTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml.symboltable; + +import de.monticore.cocos.CoCoLog; +import de.se_rwth.commons.logging.Log; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._cocos.NESTMLCoCoChecker; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml._symboltable.NESTMLCoCosManager; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Optional; + +import static org.nest.utils.LogHelper.getFindingsByPrefix; + +/** + * Iterates through good models and checks that there is no errors in log. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLCoCosManagerTest { + + public static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + @BeforeClass + public static void initLog() { + Log.enableFailQuick(false); + } + + /** + * Parses the model and returns ast. + * + * @throws java.io.IOException + */ + private Optional getAstRoot(String modelPath) throws IOException { + NESTMLCompilationUnitMCParser p = NESTMLParserFactory.createNESTMLCompilationUnitMCParser(); + Optional ast = p.parse(modelPath); + Assert.assertTrue(ast.isPresent()); + return ast; + } + + @Before + public void setup() { + CoCoLog.getFindings().clear(); + } + + + @Test + public void testGoodModels() throws IOException { + final File modelsFolder = new File(TEST_MODEL_PATH + "/org/nest/nestml/parsing"); + + final String packageName = "org.nest.nestml.parsing"; + + for (final File file : modelsFolder.listFiles()) { + System.out.println("NESTMLCoCosManagerTest.testGoodModels: " + file); + + final String modelName = removeFileExtension(file.getName(), "nestml"); + final Optional root = getAstRoot(file.getPath()); + Assert.assertTrue(root.isPresent()); + + final NESTMLScopeCreator scopeCreator = new NESTMLScopeCreator( + TEST_MODEL_PATH, typesFactory); + scopeCreator.runSymbolTableCreator(root.get()); + + final String fqnModelName = packageName + "." + modelName; + System.out.println("NESTMLCoCosManagerTest.testGoodModels: " + fqnModelName); + + checkNESTMLCocosOnly(file, root, scopeCreator); + checkNESTMLWithSPLCocos(file, root, scopeCreator); + + } + + Collection nestmlErrorFindings = getFindingsByPrefix("NESTML_", CoCoLog.getFindings()); + nestmlErrorFindings.forEach(System.out::println); + Assert.assertTrue("Models contain unexpected errors: " + nestmlErrorFindings.size(), + nestmlErrorFindings.isEmpty()); + } + + public void checkNESTMLCocosOnly(File file, Optional root, + NESTMLScopeCreator nestmlScopeCreator) { + final NESTMLCoCosManager nestmlCoCosManager = new NESTMLCoCosManager(root.get(), + nestmlScopeCreator.getTypesFactory()); + final NESTMLCoCoChecker checker = nestmlCoCosManager.createDefaultChecker(); + checker.checkAll(root.get()); + + Collection nestmlErrorFindings = getFindingsByPrefix("NESTML_", + CoCoLog.getFindings()); + nestmlErrorFindings.forEach(System.out::println); + Assert.assertTrue( + "The model: " + file.getPath() + "Models contain unexpected errors: " + nestmlErrorFindings + .size(), + nestmlErrorFindings.isEmpty()); + } + + public void checkNESTMLWithSPLCocos( + final File file, + final Optional root, + final NESTMLScopeCreator nestmlScopeCreator) { + final NESTMLCoCosManager nestmlCoCosManager = new NESTMLCoCosManager(root.get(), + nestmlScopeCreator.getTypesFactory()); + final NESTMLCoCoChecker checker = nestmlCoCosManager.createNESTMLCheckerWithSPLCocos(); + checker.checkAll(root.get()); + + Collection nestmlErrorFindings = getFindingsByPrefix("NESTML_", + CoCoLog.getFindings()); + final StringBuilder errorDetailsBuilder = new StringBuilder(); + nestmlErrorFindings.forEach(error -> errorDetailsBuilder.append(error).append("\n")); + final String msg = "The model: " + file.getPath() + "Models contain unexpected errors: " + + nestmlErrorFindings.size(); + Assert.assertTrue( + msg, + nestmlErrorFindings.isEmpty()); + } + + /** + * Given the filename, e.g test.nestml; and an extension, nestml, returns the simple name, e.g. test + * + */ + private String removeFileExtension(String name, String nestml) { + if (nestml.startsWith(".")) { + return name.substring(0, name.indexOf(nestml)); + } else { + return name.substring(0, name.indexOf("." + nestml)); + } + + } + +} diff --git a/src/test/java/org/nest/nestml/symboltable/NESTMLSymbolTableTest.java b/src/test/java/org/nest/nestml/symboltable/NESTMLSymbolTableTest.java new file mode 100644 index 000000000..49806ea70 --- /dev/null +++ b/src/test/java/org/nest/nestml/symboltable/NESTMLSymbolTableTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.nestml.symboltable; + +import de.monticore.symboltable.Scope; +import de.monticore.symboltable.ScopeSpanningSymbol; +import org.junit.Test; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTBodyElement; +import org.nest.nestml._ast.ASTFunction; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLNeuronSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.symbols.NESTMLUsageSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.io.IOException; +import java.util.Collection; +import java.util.Optional; + +import static org.junit.Assert.*; + +/** + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class NESTMLSymbolTableTest { + + private static final String TEST_MODEL_PATH = "src/test/resources/"; + private static final String MODEL_FILE_NAME = "src/test/resources/org/nest/nestml/symboltable/" + + "iaf_neuron.nestml"; + private static final String USING_NEURON_FILE = "src/test/resources/org/nest/nestml/symboltable/" + + "importingNeuron.nestml"; + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + private final NESTMLScopeCreator scopeCreator = new NESTMLScopeCreator(TEST_MODEL_PATH, typesFactory); + private final Scope globalScope = scopeCreator.getGlobalScope(); + + @Test + public void testCreationOfSymtabAndResolvingOfSymbols() throws IOException { + final ASTNESTMLCompilationUnit root = getNestmlRootFromFilename(MODEL_FILE_NAME); + final Scope modelScope = scopeCreator.runSymbolTableCreator(root); + + Collection nestmlTypes = modelScope.resolveLocally(NESTMLNeuronSymbol.KIND); + assertEquals(2, nestmlTypes.size()); + + final Optional neuronTypeOptional = modelScope.resolve( + "iaf_neuron", + NESTMLNeuronSymbol.KIND); + assertTrue(neuronTypeOptional.isPresent()); + + final Optional testComponentOptional = modelScope.resolve( + "TestComponent", + NESTMLNeuronSymbol.KIND); + assertTrue(testComponentOptional.isPresent()); + + final Optional testComponentFromGlobalScope = globalScope.resolve( + "org.nest.nestml.symboltable.iaf_neuron.TestComponent", NESTMLNeuronSymbol.KIND); + assertTrue(testComponentFromGlobalScope.isPresent()); + } + + @Test + public void testResolvingFromSeparateBlocks() throws IOException { + final ASTNESTMLCompilationUnit root = getNestmlRootFromFilename(MODEL_FILE_NAME); + assertEquals(1, root.getNeurons().size()); + + scopeCreator.runSymbolTableCreator(root); + + final PredefinedTypesFactory predefinedTypesFactory = scopeCreator.getTypesFactory(); + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(root.getNeurons().get(0).getBody()); + + final Optional neuronState = astBodyDecorator.getStateBlock(); + assertTrue(neuronState.isPresent()); + + // retrieve state block + final Scope stateScope = neuronState.get().getEnclosingScope().get(); + Optional y0Symbol = stateScope.resolve("y0", NESTMLVariableSymbol.KIND); + assertTrue(y0Symbol.isPresent()); + + // retrieve parameter block + final Scope parameterScope = astBodyDecorator.getParameterBlock().get().getEnclosingScope().get(); + assertSame(stateScope, parameterScope); + assertTrue(parameterScope.resolve("y0", NESTMLVariableSymbol.KIND).isPresent()); + assertTrue(parameterScope.resolve("C_m", NESTMLVariableSymbol.KIND).isPresent()); + + // retrieve dynamics block + final Scope dynamicsScope = astBodyDecorator.getDynamics().get(0).getBlock().getEnclosingScope().get(); + + final Optional newVarInMethodSymbol + = dynamicsScope.resolve("newVarInMethod", NESTMLVariableSymbol.KIND); + assertTrue(newVarInMethodSymbol.isPresent()); + assertTrue(newVarInMethodSymbol.get().getType().equals(predefinedTypesFactory.getRealType())); + + + } + + @Test + public void testShadowingOfVariablesInMethods() throws IOException { + final ASTNESTMLCompilationUnit root = getNestmlRootFromFilename(MODEL_FILE_NAME); + assertEquals(1, root.getNeurons().size()); + + scopeCreator.runSymbolTableCreator(root); + + final PredefinedTypesFactory predefinedTypesFactory = scopeCreator.getTypesFactory(); + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(root.getNeurons().get(0).getBody()); + + final Optional neuronState = astBodyDecorator.getStateBlock(); + assertTrue(neuronState.isPresent()); + final Optional testVarFromParameter = + neuronState.get().getEnclosingScope().get().resolve("scopeTestVar", + NESTMLVariableSymbol.KIND); + + // check the symbol from parameter block + assertTrue(testVarFromParameter.isPresent()); + assertTrue(testVarFromParameter.get().getType().equals(predefinedTypesFactory.getStringType())); + + // check the symbol in function block + final Optional scopeTestingFunction = astBodyDecorator + .getFunctions() + .stream() + .filter(astFunction -> astFunction.getName().equals("scopeTestingFunction")) + .findFirst(); + + assertTrue(scopeTestingFunction.isPresent()); + final Optional testVarFromFunction = + scopeTestingFunction.get().getBlock().getEnclosingScope().get().resolve("scopeTestVar", NESTMLVariableSymbol.KIND); + assertTrue(testVarFromFunction.isPresent()); + assertTrue(testVarFromFunction.get().getType().equals(predefinedTypesFactory.getIntegerType())); + + // retrieve the if block and resolve it from there + // TODO it should not be a correct solution + final Optional testVarFromIfBlock = + scopeTestingFunction.get() + .getBlock() + .getStmts().get(1) // retrieves the second statement from function + .getCompound_Stmt().get() + .getIF_Stmt().get() + .getIF_Clause() + .getBlock() + .getStmts().get(0) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getDeclaration().get() + .getEnclosingScope().get() + .resolve("scopeTestVar", NESTMLVariableSymbol.KIND); + + assertTrue(testVarFromIfBlock.isPresent()); + assertTrue(testVarFromIfBlock.get().getType().equals(predefinedTypesFactory.getRealType())); + } + + @Test + public void testPredefinedVariables() throws IOException { + final ASTNESTMLCompilationUnit root = getNestmlRootFromFilename(MODEL_FILE_NAME); + final Scope modelScope = scopeCreator.runSymbolTableCreator(root); + + final Optional fromGlobalScope + = globalScope.resolve("E", NESTMLVariableSymbol.KIND); + assertTrue(fromGlobalScope.isPresent()); + + + final Optional fromModelScope + = modelScope.resolve("E", NESTMLVariableSymbol.KIND); + assertTrue(fromModelScope.isPresent()); + } + + public ASTNESTMLCompilationUnit getNestmlRootFromFilename(final String modelFilename) throws IOException { + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory + .createNESTMLCompilationUnitMCParser(); + final Optional root = p.parse(modelFilename); + assertTrue(root.isPresent()); + return root.get(); + } + + @Test + public void testResolvingSeparateModels() throws IOException { + final ASTNESTMLCompilationUnit root = getNestmlRootFromFilename(USING_NEURON_FILE); + final Scope modelScope = scopeCreator.runSymbolTableCreator(root); + final Optional usingNeuronSymbol = modelScope + .resolve("org.nest.nestml.symboltable.importingNeuron.UsingNeuron", NESTMLNeuronSymbol.KIND); + assertTrue(usingNeuronSymbol.isPresent()); + final Scope neuronScope = usingNeuronSymbol.get().getSpannedScope(); + + final Optional usageSymbol = neuronScope + .resolve("TestReference", NESTMLUsageSymbol.KIND); + assertTrue(usageSymbol.isPresent()); + + final NESTMLNeuronSymbol componentSymbol = usageSymbol.get().getReferencedSymbol(); + assertEquals(NESTMLNeuronSymbol.Type.COMPONENT, componentSymbol.getType()); + } + +} diff --git a/src/test/java/org/nest/ode/ModelConverterTest.java b/src/test/java/org/nest/ode/ModelConverterTest.java new file mode 100644 index 000000000..ca0fc3196 --- /dev/null +++ b/src/test/java/org/nest/ode/ModelConverterTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.ode; + +import de.se_rwth.commons.logging.Log; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTAliasDecl; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml.prettyprinter.NESTMLPrettyPrinter; +import org.nest.nestml.prettyprinter.NESTMLPrettyPrinterFactory; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Tests how the pyhton output is processed in the NESTML tooling. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class ModelConverterTest { + private final static String GENERATED_MATRIX_PATH = "src/test/resources/org/nest/ode/solution.matrix.tmp"; + + private static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final String MODEL_FILE_PATH = "src/test/resources/codegeneration/iaf_neuron_ode_module.nestml"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + @BeforeClass + public static void initLog() { + Log.enableFailQuick(false); + + } + + @Test + public void testResolvingProblem() throws Exception { + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory + .createNESTMLCompilationUnitMCParser(); + final Optional root = p.parse(MODEL_FILE_PATH); + assertTrue(root.isPresent()); + + final Sympy2NESTMLConverter sympy2NESTMLConverter = new Sympy2NESTMLConverter(); + final List testant = sympy2NESTMLConverter.convertMatrixFile2NESTML(GENERATED_MATRIX_PATH); + assertEquals(9, testant.size()); + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(root.get().getNeurons().get(0).getBody()); + + testant.forEach(astBodyDecorator::addToInternalBlock); + + final NESTMLScopeCreator nestmlScopeCreator = new NESTMLScopeCreator( + TEST_MODEL_PATH, typesFactory); + nestmlScopeCreator.runSymbolTableCreator(root.get()); + + printTransformedModel(root); + + Optional p30 = astBodyDecorator + .getInternals().get(0) + .getEnclosingScope().get() + .resolve("P30", NESTMLVariableSymbol.KIND); + assertTrue(p30.isPresent()); + + Optional p01 = astBodyDecorator + .getInternals().get(0) + .getEnclosingScope().get() + .resolve("P01", NESTMLVariableSymbol.KIND); + assertTrue(p01.isPresent()); + } + + private void printTransformedModel(final Optional root) { + final NESTMLPrettyPrinter nestmlPrettyPrinter = NESTMLPrettyPrinterFactory.createNESTMLPrettyPrinter(); + root.get().accept(nestmlPrettyPrinter); + System.out.println(nestmlPrettyPrinter.getResult()); + } + + @Test + public void testAddingPropagatorMatrix() { + final ModelConverter modelConverter = new ModelConverter(); + modelConverter.addPropagatorMatrixAndPrint(MODEL_FILE_PATH, GENERATED_MATRIX_PATH, "target/tmp.nestml"); + } + + +} diff --git a/src/test/java/org/nest/ode/ODE2SympyCodeGeneratorTest.java b/src/test/java/org/nest/ode/ODE2SympyCodeGeneratorTest.java new file mode 100644 index 000000000..35a665045 --- /dev/null +++ b/src/test/java/org/nest/ode/ODE2SympyCodeGeneratorTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.ode; + +import de.monticore.generating.templateengine.GlobalExtensionManagement; +import de.se_rwth.commons.Names; +import org.junit.Test; +import org.nest.nestml._ast.ASTBodyDecorator; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._parser.NESTMLCompilationUnitMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml._symboltable.NESTMLScopeCreator; +import org.nest.spl._ast.ASTOdeDeclaration; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.io.File; +import java.io.IOException; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +/** + * TODO + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class ODE2SympyCodeGeneratorTest { + private static final String TEST_MODEL_PATH = "src/test/resources/"; + + public static final String MODEL_FILE_PATH = "src/test/resources/codegeneration/iaf_neuron_ode_module.nestml"; + + private static final String OUTPUT_FOLDER = "target"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + @Test + public void generateSympyScript() throws IOException { + final GlobalExtensionManagement glex = createGLEXConfiguration(); + final NESTMLCompilationUnitMCParser p = NESTMLParserFactory + .createNESTMLCompilationUnitMCParser(); + final Optional root = p.parse(MODEL_FILE_PATH); + + assertTrue(root.isPresent()); + final String packageName = Names.getQualifiedName(root.get().getPackageName().getParts()); + + final NESTMLScopeCreator nestmlScopeCreator = new NESTMLScopeCreator( + TEST_MODEL_PATH, typesFactory); + nestmlScopeCreator.runSymbolTableCreator(root.get()); + + final File outputFolder = new File(OUTPUT_FOLDER + File.separator + Names.getPathFromPackage(packageName)); + + final ASTBodyDecorator astBodyDecorator = new ASTBodyDecorator(root.get().getNeurons().get(0).getBody()); + final Optional odeDeclaration = astBodyDecorator.getOdeDefinition(); + + assertTrue(odeDeclaration.isPresent()); + ODE2SympyCodeGenerator.generateSympyODEAnalyzer(glex, odeDeclaration.get(), outputFolder, "iaf_neuron"); + } + + private GlobalExtensionManagement createGLEXConfiguration() { + return new GlobalExtensionManagement(); + } + +} diff --git a/src/test/java/org/nest/ode/ScopeMock.java b/src/test/java/org/nest/ode/ScopeMock.java new file mode 100644 index 000000000..7f6ccaba5 --- /dev/null +++ b/src/test/java/org/nest/ode/ScopeMock.java @@ -0,0 +1,83 @@ +package org.nest.ode; + +import de.monticore.ast.ASTNode; +import de.monticore.symboltable.*; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.monticore.symboltable.resolving.ResolvingFilter; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Created by user on 20.05.15. + */ +public class ScopeMock implements Scope { + + @Override public Optional getName() { + return Optional.of("TestScope"); + } + + @Override public Optional getEnclosingScope() { + return null; + } + + @Override public List getSubScopes() { + return null; + } + + @Override public Optional resolve(String s, SymbolKind symbolKind) { + return null; + } + + @Override public Optional resolve(String s, SymbolKind symbolKind, + AccessModifier accessModifier) { + return null; + } + + @Override public Collection resolveMany(String name, SymbolKind kind) { + return null; + } + + @Override public Optional resolveLocally(String s, SymbolKind symbolKind) { + + return null; + } + + @Override public List resolveLocally(SymbolKind symbolKind) { + return null; + } + + @Override public Optional resolve(SymbolPredicate symbolPredicate) { + return null; + } + + @Override public List getSymbols() { + return null; + } + + @Override public int getSymbolsSize() { + return 0; + } + + @Override public boolean definesNameSpace() { + return false; + } + + @Override public boolean isShadowingScope() { + return false; + } + + @Override public Optional getSpanningSymbol() { + return null; + } + + @Override public Set> getResolvingFilters() { + return null; + } + + @Override public Optional getAstNode() { + return null; + } +} diff --git a/src/test/java/org/nest/ode/Sympy2NESTMLConverterTest.java b/src/test/java/org/nest/ode/Sympy2NESTMLConverterTest.java new file mode 100644 index 000000000..46fec8aa8 --- /dev/null +++ b/src/test/java/org/nest/ode/Sympy2NESTMLConverterTest.java @@ -0,0 +1,24 @@ +package org.nest.ode; + +import org.junit.Test; +import org.nest.nestml._ast.ASTAliasDecl; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Created by user on 20.05.15. + */ +public class Sympy2NESTMLConverterTest { + private final static String GENERATED_MATRIX_PATH = "src/test/resources/org/nest/ode/solution.matrix.tmp"; + + @Test + public void testConvertMatrixFile() throws Exception { + final Sympy2NESTMLConverter sympy2NESTMLConverter = new Sympy2NESTMLConverter(); + final List testant = sympy2NESTMLConverter.convertMatrixFile2NESTML(GENERATED_MATRIX_PATH); + assertEquals(9, testant.size()); + } + +} diff --git a/src/test/java/org/nest/ode/SympyLine2ASTConverterTest.java b/src/test/java/org/nest/ode/SympyLine2ASTConverterTest.java new file mode 100644 index 000000000..924dd8510 --- /dev/null +++ b/src/test/java/org/nest/ode/SympyLine2ASTConverterTest.java @@ -0,0 +1,30 @@ +package org.nest.ode; + +import de.se_rwth.commons.logging.Log; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nest.spl._ast.ASTDeclaration; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class SympyLine2ASTConverterTest { + + @BeforeClass + public static void disableFailQuick() { + Log.enableFailQuick(false); + } + + @Test + public void testConvertLine2AST() { + final SympyLine2ASTConverter converter = new SympyLine2ASTConverter(); + final String testExpr = "P00 real = -Tau*tau_in*(Tau*h*exp(h/Tau) + Tau*tau_in*exp(h/Tau) - Tau*tau_in*exp" + + "(h/tau_in) - " + + "h*tau_in*exp(h/Tau))*exp(-h/tau_in - h/Tau)/(C*(Tau**2 - 2*Tau*tau_in + tau_in**2)) # PXX"; + final ASTDeclaration testant = converter.convert(testExpr); + assertNotNull(testant); + assertEquals(1, testant.getVars().size()); + assertEquals("P00", testant.getVars().get(0)); + } + +} diff --git a/src/test/java/org/nest/ode/SympyOutputReaderTest.java b/src/test/java/org/nest/ode/SympyOutputReaderTest.java new file mode 100644 index 000000000..449d63f49 --- /dev/null +++ b/src/test/java/org/nest/ode/SympyOutputReaderTest.java @@ -0,0 +1,24 @@ +package org.nest.ode; + +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Created by user on 20.05.15. + */ +public class SympyOutputReaderTest { + private final static String GENERATED_MATRIX_PATH = "src/test/resources/org/nest/ode/solution.matrix.tmp"; + + @Test + public void testReadMatrixEntriesFromFile() throws Exception { + final SympyOutputReader sympyOutputReader = new SympyOutputReader(); + List testant = sympyOutputReader.readMatrixElementsFromFile(GENERATED_MATRIX_PATH); + + assertEquals(9, testant.size()); + + } + +} diff --git a/src/test/java/org/nest/ode/parsing/ODEParsingTest.java b/src/test/java/org/nest/ode/parsing/ODEParsingTest.java new file mode 100644 index 000000000..fca0e40e2 --- /dev/null +++ b/src/test/java/org/nest/ode/parsing/ODEParsingTest.java @@ -0,0 +1,79 @@ +package org.nest.ode.parsing; + +import de.monticore.antlr4.MCConcreteParser; +import de.se_rwth.commons.logging.Log; +import org.antlr.v4.runtime.RecognitionException; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nest.nestml._parser.EqMCParser; +import org.nest.nestml._parser.NESTMLParserFactory; +import org.nest.nestml._parser.ODEMCParser; +import org.nest.nestml._parser.OdeDeclarationMCParser; +import org.nest.spl._ast.ASTEq; +import org.nest.spl._ast.ASTODE; +import org.nest.spl._ast.ASTOdeDeclaration; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +public class ODEParsingTest { + + @BeforeClass + public static void disableFailQuick() { + Log.enableFailQuick(false); + } + + public Optional parseOde(String input) throws RecognitionException, IOException { + ODEMCParser parser = NESTMLParserFactory.createODEMCParser(); + + parser.setParserTarget(MCConcreteParser.ParserExecution.EOF); + Optional res = parser.parse(new StringReader(input)); + return res; + } + + public Optional parseEq(String input) throws RecognitionException, IOException { + EqMCParser parser = NESTMLParserFactory.createEqMCParser(); + + parser.setParserTarget(MCConcreteParser.ParserExecution.EOF); + Optional res = parser.parse(new StringReader(input)); + return res; + } + + + public Optional parseOdeDeclaration(String input) throws RecognitionException, IOException { + OdeDeclarationMCParser parser = NESTMLParserFactory.createOdeDeclarationMCParser(); + + parser.setParserTarget(MCConcreteParser.ParserExecution.EOF); + return parser.parse(new StringReader(input)); + } + + @Test + public void testOdeDefinition() throws IOException { + final String odeDeclarationAsString = + "ODE:\n" + + " I === w * (E/tau_in) * t * exp(-1/tau_in*t)\n" + + " d/dt V === -1/Tau * V + 1/C*I\n" + + "end"; + Optional res = parseOdeDeclaration(odeDeclarationAsString); + assertTrue(res.isPresent()); + } + + @Test + public void testOde() throws IOException { + Optional res = parseOde("d/dt V === -1/Tau * V + 1/C*I"); + assertTrue(res.isPresent()); + + } + + @Test + public void testEq() throws IOException { + Optional res = parseEq("I === w * (E/tau_in) * t * exp(-1/tau_in*t)"); + assertTrue(res.isPresent()); + + } + + +} diff --git a/src/test/java/org/nest/spl/cocos/SPLCoCosTest.java b/src/test/java/org/nest/spl/cocos/SPLCoCosTest.java new file mode 100644 index 000000000..ffadca60a --- /dev/null +++ b/src/test/java/org/nest/spl/cocos/SPLCoCosTest.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.cocos; + +import de.monticore.cocos.CoCoLog; +import org.junit.*; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._cocos.*; +import org.nest.spl._parser.SPLFileMCParser; +import org.nest.spl._parser.SPLParserFactory; +import org.nest.spl.symboltable.SPLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.utils.LogHelper; + +import java.io.IOException; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.nest.utils.LogHelper.countOccurrences; + +/** + * Test every context context conditions. For each implemented context condition there is one model that contains exactly one tested error. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class SPLCoCosTest { + + public static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final String TEST_MODELS_FOLDER = "src/test/resources/org/nest/spl/cocos/"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + final SPLScopeCreator splScopeCreator = new SPLScopeCreator(TEST_MODEL_PATH, typesFactory); + + private SPLCoCoChecker splCoCoChecker; + /** + * Parses the model and returns ast. + * @throws java.io.IOException + */ + private Optional getAstRoot(String modelPath) throws IOException { + SPLFileMCParser p = SPLParserFactory.createSPLFileMCParser(); + Optional ast = p.parse(modelPath); + assertTrue(ast.isPresent()); + return ast; + } + + @BeforeClass + public static void initLog() { + CoCoLog.setDelegateToLog(false); + } + + @Before + public void setup() { + CoCoLog.getFindings().clear(); + splCoCoChecker = new SPLCoCoChecker(); + } + + @After + public void printErrorMessage() { + CoCoLog.getFindings().forEach(e -> System.out.println("Error found: " + e)); + } + + @Test + public void testVariableDoesNotExist() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "varNotDefined.simple"); + Assert.assertTrue(ast.isPresent()); + splScopeCreator.runSymbolTableCreator(ast.get()); + + final VariableDoesNotExist variableExists = new VariableDoesNotExist(); + splCoCoChecker.addCoCo((SPLASTCompound_StmtCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTFunctionCallCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTReturnStmtCoCo) variableExists); + + splCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(VariableDoesNotExist.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(2), errorsFound); + } + + @Test + public void testVarNotDefinedInTest() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "varNotDefinedInTest.simple"); + Assert.assertTrue(ast.isPresent()); + splScopeCreator.runSymbolTableCreator(ast.get()); + + final VariableDoesNotExist variableExists = new VariableDoesNotExist(); + splCoCoChecker.addCoCo((SPLASTCompound_StmtCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTFunctionCallCoCo) variableExists); + splCoCoChecker.addCoCo((SPLASTReturnStmtCoCo) variableExists); + + splCoCoChecker.checkAll(ast.get()); + + final Integer errorsFound = countOccurrences(VariableDoesNotExist.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(2), errorsFound); + } + + @Test + public void testVarDefinedMultipleTimes() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "varDefinedMultipleTimes.simple"); + Assert.assertTrue(ast.isPresent()); + + final VariableDefinedMultipleTimes variableDefinedMultipleTimes = new VariableDefinedMultipleTimes(); + splCoCoChecker.addCoCo(variableDefinedMultipleTimes); + + splCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(VariableDefinedMultipleTimes.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testVarHasTypeName() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "varWithTypeName.simple"); + Assert.assertTrue(ast.isPresent()); + splScopeCreator.runSymbolTableCreator(ast.get()); + + final VarHasTypeName varHasTypeName = new VarHasTypeName(); + splCoCoChecker.addCoCo(varHasTypeName); + + splCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(VarHasTypeName.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testVariableIsNotDefinedBeforeUse() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "varNotDefinedBeforeUse.simple"); + Assert.assertTrue(ast.isPresent()); + splScopeCreator.runSymbolTableCreator(ast.get()); + + final VariableNotDefinedBeforeUse variableNotDefinedBeforeUse = new VariableNotDefinedBeforeUse(); + + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) variableNotDefinedBeforeUse); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) variableNotDefinedBeforeUse); + splCoCoChecker.addCoCo((SPLASTFOR_StmtCoCo) variableNotDefinedBeforeUse); + + splCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(VariableNotDefinedBeforeUse.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(5), errorsFound); + } + + @Test + public void testIllegalVarInFor() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "illegalVarInFor.simple"); + Assert.assertTrue(ast.isPresent()); + splScopeCreator.runSymbolTableCreator(ast.get()); + + final IllegalVarInFor illegalVarInFor = new IllegalVarInFor(splScopeCreator.getTypesFactory()); + splCoCoChecker.addCoCo(illegalVarInFor); + + splCoCoChecker.checkAll(ast.get()); + + Integer errorsFound = countOccurrences(IllegalVarInFor.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testIllegalExpression() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "illegalNumberExpressions.simple"); + Assert.assertTrue(ast.isPresent()); + splScopeCreator.runSymbolTableCreator(ast.get()); + + final IllegalExpression illegalExpression = new IllegalExpression(splScopeCreator.getTypesFactory()); + splCoCoChecker.addCoCo((SPLASTAssignmentCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTDeclarationCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTELIF_ClauseCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTFOR_StmtCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTIF_ClauseCoCo) illegalExpression); + splCoCoChecker.addCoCo((SPLASTWHILE_StmtCoCo) illegalExpression); + splCoCoChecker.checkAll(ast.get()); + + final Integer errorsFound = countOccurrences(IllegalExpression.ERROR_CODE, + CoCoLog.getFindings()); + CoCoLog.getFindings().forEach(f -> System.out.println("DEBUG: " + f.getCode() + ":" + f.getMsg()) ); + // TODO must be 14 + assertEquals(Integer.valueOf(10), errorsFound); + } + + @Test + public void testCodeAfterReturn() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "codeAfterReturn.simple"); + Assert.assertTrue(ast.isPresent()); + + final CodeAfterReturn codeAfterReturn = new CodeAfterReturn(); + splCoCoChecker.addCoCo(codeAfterReturn); + + splCoCoChecker.checkAll(ast.get()); + + final Integer errorsFound = countOccurrences(CodeAfterReturn.ERROR_CODE, CoCoLog.getFindings()); + assertEquals(Integer.valueOf(1), errorsFound); + } + + @Test + public void testFunctionExists() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "funNotDefined.simple"); + Assert.assertTrue(ast.isPresent()); + splScopeCreator.runSymbolTableCreator(ast.get()); + + final FunctionDoesntExist functionDoesntExist = new FunctionDoesntExist( + splScopeCreator.getTypesFactory()); + splCoCoChecker.addCoCo(functionDoesntExist); + + splCoCoChecker.checkAll(ast.get()); + + final Integer errorsFound = countOccurrences(FunctionDoesntExist.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(3), errorsFound); + } + + // TODO + //@Test + public void testCheckMultipleSignsBeforeFactor() throws IOException { + final Optional ast = getAstRoot(TEST_MODELS_FOLDER + "multipleSigns.simple"); + Assert.assertTrue(ast.isPresent()); + + final CheckMultipleSignsBeforeFactor checkMultipleSignsBeforeFactor = new CheckMultipleSignsBeforeFactor(); + splCoCoChecker.addCoCo((SPLASTBlockCoCo) checkMultipleSignsBeforeFactor); + splCoCoChecker.addCoCo((SPLASTExprCoCo) checkMultipleSignsBeforeFactor); + + splCoCoChecker.checkAll(ast.get()); + + final Integer errorsFound = countOccurrences(CheckMultipleSignsBeforeFactor.ERROR_CODE, + CoCoLog.getFindings()); + assertEquals(Integer.valueOf(4), errorsFound); + } + +} diff --git a/src/test/java/org/nest/spl/codegeneration/SPL2NESTCodeGeneratorTest.java b/src/test/java/org/nest/spl/codegeneration/SPL2NESTCodeGeneratorTest.java new file mode 100644 index 000000000..7d488f929 --- /dev/null +++ b/src/test/java/org/nest/spl/codegeneration/SPL2NESTCodeGeneratorTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.codegeneration; + +import de.monticore.generating.templateengine.GlobalExtensionManagement; +import org.junit.Assert; +import org.junit.Test; +import org.nest.codegeneration.NESTMLDeclarations; +import org.nest.codegeneration.SPL2NESTCodeGenerator; +import org.nest.spl._ast.ASTAssignment; +import org.nest.spl._ast.ASTBlock; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._parser.SPLFileMCParser; +import org.nest.spl._parser.SPLParserFactory; +import org.nest.spl.symboltable.SPLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +public class SPL2NESTCodeGeneratorTest { + + private static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final String OUTPUT_FOLDER = "target"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + private GlobalExtensionManagement createGLEXConfiguration() { + + return new GlobalExtensionManagement(); + } + + @Test + public void invokeSPL2NESTGenerator() throws IOException { + final SPLFileMCParser p = SPLParserFactory.createSPLFileMCParser(); + final File outputFolder = new File(OUTPUT_FOLDER); + final String packageName = "org.nest.spl.codegeneration"; + final String modelName = "decl"; + final String fullQualifiedModelname = packageName + "." + modelName; + final Path outputFile = Paths.get(fullQualifiedModelname.replaceAll("\\.", File.separator)); + + Optional root = p.parse(TEST_MODEL_PATH + File.separator + fullQualifiedModelname.replaceAll("\\.", File.separator) + ".simple"); + Assert.assertTrue(root.isPresent()); + + final SPLScopeCreator splScopeCreator = new SPLScopeCreator(TEST_MODEL_PATH, typesFactory); + splScopeCreator.runSymbolTableCreator(root.get()); + + final GlobalExtensionManagement glex = createGLEXConfiguration(); + final SPL2NESTCodeGenerator generator = new SPL2NESTCodeGenerator(glex, typesFactory, outputFolder); + final NESTMLDeclarations declarations = new NESTMLDeclarations(splScopeCreator.getTypesFactory()); + glex.setGlobalValue("declarations", declarations); + + // tests code generation for a spldeclaration + final Optional wahrDeclaration = root.get() + .getBlock().getStmts().get(0) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getDeclaration(); + assertTrue(wahrDeclaration.isPresent()); + generator.handle(wahrDeclaration.get(), outputFile); + + // tests code generation for a spldeclaration with an expression + final Optional realDeclaration = root.get() + .getBlock().getStmts().get(2) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getDeclaration(); + assertTrue(realDeclaration.isPresent()); + generator.handle(realDeclaration.get(), outputFile); + + // tests code generation for an assignment + final Optional intVarAssignment = root.get() + .getBlock().getStmts().get(3) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + assertTrue(intVarAssignment.isPresent()); + generator.handle(intVarAssignment.get(), outputFile); + + // tests code generation for the entire Block + final ASTBlock block = root.get().getBlock(); + generator.handle(block, outputFile); + } + +} diff --git a/src/test/java/org/nest/spl/parsing/SPLExpressionParsingTest.java b/src/test/java/org/nest/spl/parsing/SPLExpressionParsingTest.java new file mode 100644 index 000000000..6264afc56 --- /dev/null +++ b/src/test/java/org/nest/spl/parsing/SPLExpressionParsingTest.java @@ -0,0 +1,58 @@ +package org.nest.spl.parsing; + +import de.monticore.antlr4.MCConcreteParser; +import de.monticore.prettyprint.IndentPrinter; +import de.monticore.types.prettyprint.TypesPrettyPrinterConcreteVisitor; +import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; +import org.antlr.v4.runtime.RecognitionException; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nest.spl._ast.ASTExpr; +import org.nest.spl._parser.ExprMCParser; +import org.nest.spl._parser.SPLParserFactory; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class SPLExpressionParsingTest { + + @BeforeClass + public static void disableFailQuick() { + Log.enableFailQuick(false); + } + + public Optional parse(String input) throws RecognitionException, IOException { + ExprMCParser parser = SPLParserFactory.createExprMCParser(); + parser.setParserTarget(MCConcreteParser.ParserExecution.EOF); + Optional res = parser.parse(new StringReader(input)); + return res; + } + + @Test + public void testPlus() throws IOException { + Optional res = parse("-a"); + assertTrue(res.isPresent()); + assertEquals("a", Names.getQualifiedName(res.get().getTerm().get().getQualifiedName().get().getParts())); + assertTrue(res.get().isUnaryMinus()); + + } + + + @Test + public void testNumber() throws IOException { + Optional res = parse("-11"); + //System.out.println(createPrettyPrinterForTypes().prettyprint(res.get().getTerm().get())); + assertTrue(res.get().isUnaryMinus()); + + } + + private TypesPrettyPrinterConcreteVisitor createPrettyPrinterForTypes() { + final IndentPrinter printer = new IndentPrinter(); + return new TypesPrettyPrinterConcreteVisitor(printer); + } +} diff --git a/src/test/java/org/nest/spl/parsing/SPLParsingTest.java b/src/test/java/org/nest/spl/parsing/SPLParsingTest.java new file mode 100644 index 000000000..eae7743fb --- /dev/null +++ b/src/test/java/org/nest/spl/parsing/SPLParsingTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.parsing; + +import de.se_rwth.commons.logging.Log; +import org.junit.Test; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._parser.SPLFileMCParser; +import org.nest.spl._parser.SPLParserFactory; + +import java.io.File; +import java.io.IOException; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +/** + * Tests whether the model can be parsed or not + */ +public class SPLParsingTest { + private final static String MODELS_PARSABLE_FOLDER = "src/test/resources/org/nest/spl/parsing"; + private final static String MODELS_COCOS_FOLDER = "src/test/resources/org/nest/spl/cocos"; + private final static String LOG_NAME = SPLParsingTest.class.getName(); + private final SPLFileMCParser parser; + + public SPLParsingTest() { + parser = SPLParserFactory.createSPLFileMCParser(); + } + + @Test + public void testParsableModels() throws IOException { + for (File file: new File(MODELS_PARSABLE_FOLDER).listFiles()) { + Log.trace("Processes the following file: %s" + file.getAbsolutePath(), LOG_NAME); + + Optional ast = parser.parse(file.getAbsolutePath()); + assertTrue(ast.isPresent()); + } + + } + + @Test + public void testModelsForCocos() throws IOException { + for (File file: new File(MODELS_COCOS_FOLDER).listFiles()) { + Log.trace("Processes the following file: %s" + file.getAbsolutePath(), LOG_NAME); + + Optional ast = parser.parse(file.getAbsolutePath()); + assertTrue(ast.isPresent()); + } + + } + +} diff --git a/src/test/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinterTest.java b/src/test/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinterTest.java new file mode 100644 index 000000000..a23dc7b94 --- /dev/null +++ b/src/test/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinterTest.java @@ -0,0 +1,42 @@ +package org.nest.spl.prettyprinter; + +import org.junit.Test; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._parser.SPLFileMCParser; +import org.nest.spl._parser.SPLParserFactory; +import org.nest.spl.symboltable.SPLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; + +import java.io.IOException; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +/** + * Created by user on 02.06.15. + */ +public class ExpressionsPrettyPrinterTest { + private final SPLFileMCParser splFileParser = SPLParserFactory.createSPLFileMCParser(); + private final ExpressionsPrettyPrinter expressionsPrettyPrinter = new ExpressionsPrettyPrinter(); + private static final String TEST_MODEL_PATH = "src/test/resources/"; + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + @Test + public void testThatPrettyPrinterProducesParsableOutput() throws IOException { + + final Optional root = splFileParser.parse + ("src/test/resources/org/nest/spl/parsing/complexExpressions.simple"); + assertTrue(root.isPresent()); + + // TODO write frontend manager for the cocos and check them on the model + SPLScopeCreator splScopeCreator = new SPLScopeCreator(TEST_MODEL_PATH, typesFactory); + splScopeCreator.runSymbolTableCreator(root.get());// do I need symbol table for the pretty printer + System.out.println(expressionsPrettyPrinter + .print(root.get().getBlock().getStmts().get(4).getSimple_Stmt().get() + .getSmall_Stmts().get(0).getDeclaration().get().getExpr().get())); + // TODO + //System.out.println(expressionsPrettyPrinter.print(root.get().getBlock().getStmts().get(6).getSimple_Stmt().get() + // .getSmall_Stmts().get(0).getDeclaration().get().getExpr().get())); + + } +} diff --git a/src/test/java/org/nest/spl/prettyprinter/SPLPrettyPrinterTest.java b/src/test/java/org/nest/spl/prettyprinter/SPLPrettyPrinterTest.java new file mode 100644 index 000000000..4be5081bf --- /dev/null +++ b/src/test/java/org/nest/spl/prettyprinter/SPLPrettyPrinterTest.java @@ -0,0 +1 @@ +package org.nest.spl.prettyprinter; import org.junit.Test; import org.nest.spl._ast.ASTSPLFile; import org.nest.spl._parser.SPLFileMCParser; import org.nest.spl._parser.SPLParserFactory; import org.nest.spl.symboltable.SPLScopeCreator; import org.nest.symboltable.predefined.PredefinedTypesFactory; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.Optional; import static org.junit.Assert.assertTrue; /** * Checks that the pretty printed result can be parsed again. A comparison on the AST level could be implemented in * the future. * @author (last commit) $Author$ * @version $Revision$, $Date$ */ public class SPLPrettyPrinterTest { private final SPLFileMCParser splFileParser = SPLParserFactory.createSPLFileMCParser(); private final ExpressionsPrettyPrinter prettyPrinter = new ExpressionsPrettyPrinter(); private static final String TEST_MODEL_PATH = "src/test/resources/"; private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); private final SPLScopeCreator splScopeCreator = new SPLScopeCreator( TEST_MODEL_PATH, typesFactory); private Optional parseStringAsSPLFile(final String fileAsString) throws IOException { return splFileParser.parse(new StringReader(fileAsString)); } @Test public void testThatPrettyPrinterProducesParsableOutput() throws IOException { final SPLPrettyPrinter splPrettyPrinter = new SPLPrettyPrinter(prettyPrinter); final Optional root = splFileParser.parse ("src/test/resources/org/nest/spl/parsing/modelContainingAllLanguageElements.simple"); assertTrue(root.isPresent()); // TODO write frontend manager for the cocos and check them on the model splScopeCreator.runSymbolTableCreator(root.get()); root.get().accept(splPrettyPrinter); // starts prettyPrinter System.out.println(splPrettyPrinter.getResult()); Optional prettyPrintedRoot = parseStringAsSPLFile(splPrettyPrinter.getResult()); assertTrue(prettyPrintedRoot.isPresent()); } @Test public void testAllModelsForParser() throws IOException { parseAllSPLModelsFromFolder("src/test/resources/org/nest/spl/parsing"); } @Test public void testAllModelsForCocos() throws IOException { parseAllSPLModelsFromFolder("src/test/resources/org/nest/spl/cocos"); } private void parseAllSPLModelsFromFolder(final String folderPath) throws IOException { final File parserModelsFolder = new File(folderPath); for (File splModelFile : parserModelsFolder.listFiles()) { System.out.println("Handles the model: " + splModelFile.getPath()); final SPLPrettyPrinter splPrettyPrinter = new SPLPrettyPrinter(prettyPrinter); final Optional splModelRoot = splFileParser.parse(splModelFile.getPath()); assertTrue("Cannot parse the model: " + splModelFile.getName(), splModelRoot.isPresent()); splScopeCreator.runSymbolTableCreator(splModelRoot.get()); splModelRoot.get().accept(splPrettyPrinter); System.out.println(splPrettyPrinter.getResult()); Optional prettyPrintedRoot = parseStringAsSPLFile(splPrettyPrinter.getResult()); assertTrue(prettyPrintedRoot.isPresent()); } } } \ No newline at end of file diff --git a/src/test/java/org/nest/spl/symboltable/SPLCoCosManagerTest.java b/src/test/java/org/nest/spl/symboltable/SPLCoCosManagerTest.java new file mode 100644 index 000000000..38148ca3b --- /dev/null +++ b/src/test/java/org/nest/spl/symboltable/SPLCoCosManagerTest.java @@ -0,0 +1,80 @@ +package org.nest.spl.symboltable; + +import de.monticore.cocos.CoCoLog; +import de.se_rwth.commons.logging.Log; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._cocos.SPLCoCoChecker; +import org.nest.spl._parser.SPLFileMCParser; +import org.nest.spl._parser.SPLParserFactory; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.utils.LogHelper; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Optional; + +/** + * Created by user on 16.06.15. + */ +public class SPLCoCosManagerTest { + public static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + private final SPLScopeCreator scopeCreator = new SPLScopeCreator(TEST_MODEL_PATH, typesFactory); + @BeforeClass + public static void initLog() { + Log.enableFailQuick(false); + } + + @Before + public void setup() { + CoCoLog.getFindings().clear(); + } + + @Test + public void testSPLGoodModels() throws IOException { + final File modelsFolder = new File(TEST_MODEL_PATH + "/org/nest/spl/parsing"); + + + for (File file : modelsFolder.listFiles()) { + System.out.println("SPLCoCosManagerTest.testGoodModels: " + file.getName()); + final ASTSPLFile root = getAstRoot(file.getPath()); + scopeCreator.runSymbolTableCreator(root); + + final SPLCoCosManager splCoCosManager = new SPLCoCosManager(scopeCreator.getTypesFactory()); + final SPLCoCoChecker checker = splCoCosManager.createDefaultChecker(); + checker.checkAll(root); + Collection splErrorFindings = LogHelper.getFindingsByPrefix("NESTML_", CoCoLog.getFindings()); + final StringBuilder errors = new StringBuilder(); + + splErrorFindings.forEach(e -> { + errors.append(e + "\n"); + }); + + final String errorDescription = "Model contain unexpected errors: " + splErrorFindings.size() + + " The model: " + file.getPath() + " The errors are: " + errors; + Assert.assertTrue(errorDescription, splErrorFindings.isEmpty() ); + + } + + } + + /** + * Parses the model and returns ast. + * + * @throws java.io.IOException + */ + private ASTSPLFile getAstRoot(String modelPath) throws IOException { + SPLFileMCParser p = SPLParserFactory.createSPLFileMCParser(); + + final Optional ast = p.parse(modelPath); + Assert.assertTrue(ast.isPresent()); + return ast.get(); + } + +} diff --git a/src/test/java/org/nest/spl/symboltable/SPLSymbolTableTest.java b/src/test/java/org/nest/spl/symboltable/SPLSymbolTableTest.java new file mode 100644 index 000000000..fafc6b6e1 --- /dev/null +++ b/src/test/java/org/nest/spl/symboltable/SPLSymbolTableTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable; + +import de.monticore.symboltable.GlobalScope; +import org.junit.Test; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._parser.SPLFileMCParser; +import org.nest.spl._parser.SPLParserFactory; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLMethodSymbol; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; +import org.nest.symboltable.symbols.NESTMLVariableSymbol; + +import java.io.IOException; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +/** + * Test resolving of variables and functions from a SPL program. + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class SPLSymbolTableTest { + public static final String TEST_MODEL_PATH = "src/test/resources/"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + @Test + public void testCreationOfSymtabAndResolvingOfSymbols() throws IOException { + + final SPLFileMCParser p = SPLParserFactory.createSPLFileMCParser(); + final Optional root = p.parse( + "src/test/resources/org/nest/spl/symboltable/decl.simple"); + assertTrue(root.isPresent()); + + + SPLScopeCreator splScopeCreator = new SPLScopeCreator(TEST_MODEL_PATH, typesFactory); + splScopeCreator.runSymbolTableCreator(root.get()); + + final GlobalScope globalScope = splScopeCreator.getGlobalScope(); + globalScope.resolve("Time.steps", NESTMLMethodSymbol.KIND); + Optional variable = globalScope.resolve("org.nest.spl.symboltable.decl.decl", NESTMLVariableSymbol.KIND); + assertTrue(variable.isPresent()); + + // resolve implicit types + for (NESTMLTypeSymbol type: splScopeCreator.getTypesFactory().getTypes()) { + Optional resolvedType = globalScope.resolve(type.getFullName(), NESTMLTypeSymbol.KIND); + assertTrue("Cannot resolve the type: " + type.getFullName(), resolvedType.isPresent()); + } + + } + +} diff --git a/src/test/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculatorTest.java b/src/test/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculatorTest.java new file mode 100644 index 000000000..cf30450ab --- /dev/null +++ b/src/test/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculatorTest.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) RWTH Aachen. All rights reserved. + * + * http://www.se-rwth.de/ + */ +package org.nest.spl.symboltable.typechecking; + +import org.junit.Assert; +import org.junit.Test; +import org.nest.spl._ast.ASTAssignment; +import org.nest.spl._ast.ASTDeclaration; +import org.nest.spl._ast.ASTSPLFile; +import org.nest.spl._parser.SPLFileMCParser; +import org.nest.spl._parser.SPLParserFactory; +import org.nest.spl.symboltable.SPLScopeCreator; +import org.nest.symboltable.predefined.PredefinedTypesFactory; +import org.nest.symboltable.symbols.NESTMLTypeSymbol; + +import java.io.IOException; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Test the functioning of the expression pretty printer + * + * @author (last commit) $$Author$$ + * @version $$Revision$$, $$Date$$ + * @since 0.0.1 + */ +public class ExpressionTypeCalculatorTest { + + public static final String TEST_MODEL_PATH = "src/test/resources/"; + + public static final String TEST_MODEL = "src/test/resources/org/nest/spl/symboltable/mathExpressions.simple"; + + private static final PredefinedTypesFactory typesFactory = new PredefinedTypesFactory(); + + @Test + public void testTypeCalculation() throws IOException { + final SPLFileMCParser p = SPLParserFactory.createSPLFileMCParser(); + final Optional root = p.parse(TEST_MODEL); + assertTrue(root.isPresent()); + + final SPLScopeCreator scopeCreator = new SPLScopeCreator(TEST_MODEL_PATH, typesFactory); + scopeCreator.runSymbolTableCreator(root.get()); + + final ExpressionTypeCalculator calculator = new ExpressionTypeCalculator(typesFactory); + + // Retrieves line: b = 1.0 + final Optional bDeclaration = root.get() + .getBlock().getStmts().get(1) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getDeclaration(); + Assert.assertTrue(bDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfB = calculator.computeType(bDeclaration.get().getExpr().get()); + Assert.assertNotNull(typeOfB); + Assert.assertEquals(typesFactory.getRealType(), typeOfB); + + // Retrieves line: c = 1 + final Optional cDeclaration = root.get() + .getBlock().getStmts().get(2) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(cDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfC = calculator.computeType(cDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfC); + Assert.assertEquals(typesFactory.getIntegerType(), typeOfC); + + // Retrieves line: d = "test" + final Optional dDeclaration = root.get() + .getBlock().getStmts().get(3) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(dDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfD = calculator.computeType(dDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfD); + Assert.assertEquals(typesFactory.getStringType(), typeOfD); + + // Retrieves line: e = 1 + 1 + final Optional eDeclaration = root.get() + .getBlock().getStmts().get(4) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(dDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfE = calculator.computeType(eDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfE); + Assert.assertEquals(typesFactory.getIntegerType(), typeOfE); + + // Retrieves line: f = 1 + 1.0 + final Optional fDeclaration = root.get() + .getBlock().getStmts().get(5) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(dDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfF = calculator.computeType(fDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfF); + Assert.assertEquals(typesFactory.getRealType(), typeOfF); + + // Retrieves line: f = 1.0 + 1 + final Optional gDeclaration = root.get() + .getBlock().getStmts().get(6) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(dDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfG = calculator.computeType(gDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfG); + Assert.assertEquals(typesFactory.getRealType(), typeOfG); + + // Retrieves line: f = 1.0 + 1 + final Optional hDeclaration = root.get() + .getBlock().getStmts().get(7) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(dDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfH = calculator.computeType(hDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfH); + Assert.assertEquals(typesFactory.getRealType(), typeOfH); + + // Retrieves line: i = ~1 + final Optional iDeclaration = root.get() + .getBlock().getStmts().get(8) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(iDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfI = calculator.computeType(iDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfI); + Assert.assertEquals(typesFactory.getIntegerType(), typeOfI); + + // Retrieves line: j = ~b, b is a string + final Optional jDeclaration = root.get() + .getBlock().getStmts().get(10) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(jDeclaration.isPresent()); + + try { + calculator.computeType(jDeclaration.get().getExpr()); + fail(); + } + catch (RuntimeException e) { + // expects an type computation exception + } + + // Retrieves line: l = 1 ** 2.5 + final Optional kDeclaration = root.get() + .getBlock().getStmts().get(11) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(iDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfK = calculator.computeType(kDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfK); + Assert.assertEquals(typesFactory.getRealType(), typeOfK); + + // Retrieves line: m = 1 ** d, b is a string + final Optional mDeclaration = root.get() + .getBlock().getStmts().get(12) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(mDeclaration.isPresent()); + + try { + calculator.computeType(mDeclaration.get().getExpr()); + fail(); + } + catch (RuntimeException e) { + // expects an type computation exception + } + + // Retrieves line: o = 1 - 1 + final Optional oDeclaration = root.get(). + getBlock().getStmts().get(13) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(oDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfO = calculator.computeType(oDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfO); + Assert.assertEquals(typesFactory.getIntegerType(), typeOfO); + + // Retrieves line: p = 1 - 1.0 + final Optional pDeclaration = root.get() + .getBlock().getStmts().get(14) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(pDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfP = calculator.computeType(pDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfP); + Assert.assertEquals(typesFactory.getRealType(), typeOfP); + + // Retrieves line: r = 1 - d, b is a string + final Optional rDeclaration = root.get() + .getBlock().getStmts().get(15) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(rDeclaration.isPresent()); + + try { + calculator.computeType(rDeclaration.get().getExpr()); + fail(); + } + catch (RuntimeException e) { + // expects an type computation exception + } + + // Retrieves line: t = true + final Optional sDeclaration = root.get() + .getBlock().getStmts().get(16) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getAssignment(); + Assert.assertTrue(sDeclaration.isPresent()); + + final NESTMLTypeSymbol typeOfS = calculator.computeType(sDeclaration.get().getExpr()); + Assert.assertNotNull(typeOfS); + Assert.assertEquals(typesFactory.getBooleanType(), typeOfS); + + final Optional P11exAST = root.get() + .getBlock().getStmts().get(19) + .getSimple_Stmt().get() + .getSmall_Stmts().get(0) + .getDeclaration(); + Assert.assertTrue(P11exAST.isPresent()); + + final NESTMLTypeSymbol P11exType = calculator.computeType(P11exAST.get().getExpr().get()); + Assert.assertNotNull(P11exType); + Assert.assertEquals(typesFactory.getRealType(), P11exType); + + } + + +} diff --git a/src/test/resources/codegeneration/iaf_neuron_module.nestml b/src/test/resources/codegeneration/iaf_neuron_module.nestml new file mode 100644 index 000000000..b812e57d6 --- /dev/null +++ b/src/test/resources/codegeneration/iaf_neuron_module.nestml @@ -0,0 +1,96 @@ +package codegeneration.iaf_neuron_module: + + neuron iaf_neuron: + state: + - y0, y1, y2, y3 mV [y1 > 0; y2 > 0] + - r integer + # Membrane potential. + alias V_m mV = y3 + E_L + end + + parameter: + # Capacity of the membrane. + C_m pF = 250 [C_m > 0] + # Membrane time constant. + tau_m ms = 10 [tau_m > 0] + # Time constant of synaptic current. + tau_syn ms = 2 + # Refractory period. + t_ref ms = 2 + # Resting potential. + E_L mV = -70 + - delta_V_reset mV = -70 - E_L + -Theta mV = -55 - E_L + # External current. + I_e pA = 0 + + # some aliases + # Threshold. + alias V_th mV = Theta + E_L + # Reset value of the membrane potential. + alias V_reset mV = delta_V_reset + E_L [V_reset >= Theta] + end + + internal: + h ms = resolution() + P11 real = exp(-h / tau_syn) + P22 real = P11 + P33 real = exp(-h / tau_m) + P21 real = h * P11 + P30 real = 1 / C_m * (1 - P33) * tau_m + P31 real = 1 / C_m * ((P11 - P33) / (-1/tau_syn - -1/tau_m) - h * P11) / (-1/tau_m - -1/tau_syn) + P32 real = 1 / C_m * (P33 - P11) / (-1/tau_m - -1/tau_syn) + + PSCInitialValue mV = 1 * E / tau_syn + RefractoryCounts integer = steps(t_ref) + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + if r == 0: # not refractory + y3 = P30 * (y0 + I_e) + P31 * y1 + P32 * y2 + P33 * y3 + else: + r = r - 1 + end + + # alpha shape PSCs + y2 = P21 * y1 + P22 * y2 + y1 = y1 * P11 + + # Apply spikes delivered in this step: The spikes arriving at T+1 have an + # immediate effect on the state of the neuron + y1 = y1 + PSCInitialValue * spikeBuffer.getSum(t) + + # threshold crossing + if y3 >= Theta: + r = RefractoryCounts + y3 = delta_V_reset + + emitSpike() + end + + # set new input current + y0 = currentBuffer.getSum(t); + end + + function set_V_th(v mV): + Theta = v - E_L + end + + function set_V_reset(v mV): + delta_V_reset = v - E_L + end + + function set_V_m(v mV): + y3 = v - E_L + end + + end + +end diff --git a/src/test/resources/codegeneration/iaf_neuron_ode_module.nestml b/src/test/resources/codegeneration/iaf_neuron_ode_module.nestml new file mode 100644 index 000000000..e6772a4c5 --- /dev/null +++ b/src/test/resources/codegeneration/iaf_neuron_ode_module.nestml @@ -0,0 +1,98 @@ +package codegeneration.iaf_neuron_ode_module: + + neuron iaf_neuron_ode_neuron: + + state: + - y0, y1, y2, V mV [y1 > 0; y2 > 0] # TODO - sollen nicht getrackt werden + - r integer + # Membrane potential. + alias V_m mV = V + E_L + end + + parameter: + # Capacity of the membrane + + C_m pF = 250pF [C_m > 0] + # Membrane time constant. + Tau ms = 10 [Tau > 0] + # Time constant of synaptic current. + tau_in ms = 2 + # Refractory period. + t_ref ms = 2 s + # Resting potential. + E_L mV = -70 + -delta_V_reset mV = -70 - E_L + -Theta mV = -55 - E_L + + # External current. + I_e pA = 0 # special + + # some aliases + # Threshold. + alias V_th mV = Theta + E_L + # Reset value of the membrane potential. + alias V_reset mV = delta_V_reset + E_L + # invariant V_reset >= Theta + end + + internal: + h ms = resolution() + P30 real = 1 / C_m * (1 - P22) * tau_in + + PSCInitialValue mV = 1 * E / tau_in + RefractoryCounts integer = steps(t_ref) + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + + if r == 0: # not refractory + ODE: + I_shape === w * (E/tau_in) * t * exp(-1/tau_in*t) + d/dt V === -1/Tau * V + 1/C_m*I_shape + end + V = P30 * (y0 + I_e) + P20 * y1 + P21 * y2 + P22 * V + else: + r = r - 1 + end + + # alpha shape PSCs + y2 = P10 * y1 + P11 * y2 + y1 = y1 * P00 + + # Apply spikes delivered in this step: The spikes arriving at T+1 have an + # immediate effect on the state of the neuron + y1 = y1 + PSCInitialValue * spikeBuffer.getSum(t) + + # threshold crossing + if V >= Theta: + r = RefractoryCounts + V = delta_V_reset + + emitSpike() + end + + # set new input current + y0 = currentBuffer.getSum(t); + end + + function set_V_th(v mV): + Theta = v - E_L + end + + function set_V_reset(v mV): + delta_V_reset = v - E_L + end + + function set_V_m(v mV): + V = v - E_L + end + end +end + diff --git a/src/test/resources/codegeneration/iaf_psc_alpha_module.nestml b/src/test/resources/codegeneration/iaf_psc_alpha_module.nestml new file mode 100644 index 000000000..ff42977f1 --- /dev/null +++ b/src/test/resources/codegeneration/iaf_psc_alpha_module.nestml @@ -0,0 +1,132 @@ +package codegeneration.iaf_psc_alpha_module: + + neuron iaf_psc_alpha_neuron: + + state: + y0, y1_ex, y2_ex, y1_in, y2_in, y3 real = 0; + alias V_m real = y3 + U0 + - r integer = 0; + end + + function set_V_m(v real): + y3 = v + U0 + end + + parameter: + # Membrane time constant in ms + Tau ms = 10 + # Membrane capacitance in pF + C pF = 250 + # Refractory period in ms + TauR ms = 2 + # Resting potential in mV. + U0 mV = -70 + # External current in pA + I_e pA = 0; + # Reset value of the membrane potential + alias V_reset real = -70 - U0; + # Threshold, RELATIVE TO RESTING POTENTIAL(!). + # I.e. the real threshold is (U0_+Theta_) + alias Theta real = -55 - U0; + # Lower bound, RELATIVE TO RESTING POTENTIAL(!). + # I.e. the real lower bound is (LowerBound_+U0_). + LowerBound real = inf; + # Time constant of excitatory synaptic current in ms. + tau_ex ms = 2; + # Time constant of inhibitory synaptic current in ms. + tau_in ms = 2; + end + + function set_V_reset(v real): + V_reset = v - U0 + end + + function set_Theta(v real): + Theta = v - U0 + end + + internal: + h ms = resolution() + + EPSCInitialValue real = 1.0 * E/tau_ex; + IPSCInitialValue real = 1.0 * E/tau_in; + RefractoryCounts integer = steps(TauR) + + P30 real = -Tau/C * expm1(-h / Tau) + P33 real = pow(E, -h/Tau) + + P11_ex real = pow(E, -h/tau_ex) + P21_ex real = h * P11_ex + P22_ex real = h * P11_ex + P31_ex real = 1/C * ((P11_ex - P33)/(-1/tau_ex - -1/Tau)- h*P11_ex) /(-1/Tau - -1/tau_ex); + P32_ex real = 1 / C * (P33 - P11_ex)/(-1/Tau - -1/tau_ex) + P11_in real = pow(E, -h/tau_in) + P21_in real = h * P11_in + P22_in real = pow(E, -h/tau_in) + P31_in real = 1/C * ((P11_in - P33)/(-1/tau_in- -1/Tau)- h*P11_in)/(-1/Tau - -1/tau_in); + P32_in real = 1/C*(P33 - P11_in)/(-1/Tau - -1/tau_in); + + expm1_tau_m real = expm1(-h/Tau); + + weighted_spikes_ex real; + weighted_spikes_in real; + end + + input: + spikeBufferInh <- inhibitory spike + spikeBufferExc <- excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + if r == 0: + # neuron not refractory + y3 = P30*(y0 + I_e) + P31_ex * y1_ex + P32_ex * y2_ex + P31_in * y1_in + P32_in * y2_in + expm1_tau_m * y3 + y3; + + # lower bound of membrane potential + if y3 < LowerBound: + y3 = LowerBound + end + else: # neuron is absolute refractory + r = r - 1; + end + # alpha shape EPSCs + y2_ex = P21_ex * y1_ex + P22_ex * y2_ex; + y1_ex = y1_ex * P11_ex; + + # Apply spikes delivered in this step; spikes arriving at T+1 have + # an immediate effect on the state of the neuron + weighted_spikes_ex = spikeBufferExc.getSum(); + y1_ex = y1_ex + EPSCInitialValue * weighted_spikes_ex; + + # alpha shape EPSCs + y2_in = P21_in * y1_in + P22_in * y2_in; + y1_in = y1_in * P11_in; + + # Apply spikes delivered in this step; spikes arriving at T+1 have + # an immediate effect on the state of the neuron + weighted_spikes_in = spikeBufferInh.getSum(); + y1_in = y1_in + IPSCInitialValue * weighted_spikes_in; + + # threshold crossing + if y3 >= Theta: + r = RefractoryCounts; + y3 = V_reset; + # A supra-threshold membrane potential should never be observable. + # The reset at the time of threshold crossing enables accurate integration + # independent of the computation step size, see [2,3] for details. + # TODO why does it work iaf_neuron and not in this + emitSpike() + end + + # set new input current + y0 = currentBuffer.getSum(t); + + end + + end + +end + diff --git a/src/test/resources/codegeneration/iaf_psc_delta_module.nestml b/src/test/resources/codegeneration/iaf_psc_delta_module.nestml new file mode 100644 index 000000000..2b6043412 --- /dev/null +++ b/src/test/resources/codegeneration/iaf_psc_delta_module.nestml @@ -0,0 +1,94 @@ +package codegeneration.iaf_psc_delta_module: + + neuron iaf_psc_delta_neuron: + + state: + y0 real = 0.0 + y3 real = 0.0 #!< This is the membrane potential RELATIVE TO RESTING POTENTIAL. + + - r integer = 0 #//!< Number of refractory steps remaining + + # Accumulate spikes arriving during refractory period, discounted for + # decay until end of refractory period. + refr_spikes_buffer real = 0; + end + + parameter: + # Membrane time constant in ms. + tau_m ms = 10.0 + # Membrane capacitance in pF + c_m pF = 250.0 + # Refractory period in ms. + t_ref ms = 2.0 + # Resting potential in mV. + E_L mV = -70.0 + # External DC current + I_e pA = 0.0 + # Threshold, RELATIVE TO RESTING POTENTAIL(!). + # I.e. the real threshold is (U0_+V_th_). */ + V_th mV = -55 - E_L + # Lower bound, RELATIVE TO RESTING POTENTAIL(!). + # I.e. the real lower bound is (V_min+V_th). */ + V_min real = -inf; + # reset value of the membrane potential + V_reset real = -70.0-E_L; + with_refr_input boolean = false #!< spikes arriving during refractory period are counted + + end + + internal: + h ms = resolution() + P33 real = exp(-h/tau_m) + P30 real = 1 / c_m * (1.0 - P33) * tau_m + RefractoryCounts real = steps(t_ref) [RefractoryCounts >= 0] + end + + input: + spikeBufferInh <- inhibitory spike + spikeBufferExc <- excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + if r == 0: # neuron not refractory + y3 = P30*(y0 + I_e) + P33*y3 + spikeBufferInh.getSum() + + # if we have accumulated spikes from refractory period, + # add and reset accumulator + if with_refr_input and refr_spikes_buffer != 0.0: + y3 = y3 + refr_spikes_buffer + refr_spikes_buffer = 0.0 + end + + # lower bound of membrane potential + if y3 < V_min: + y3 = V_min + end + else: # neuron is absolute refractory + # read spikes from buffer and accumulate them, discounting + # for decay until end of refractory period + if with_refr_input: + refr_spikes_buffer = refr_spikes_buffer + spikeBufferInh.getSum() * exp(-r * h / tau_m) + else: + spikeBufferInh.getSum() # clear buffer entry, ignore spike + r = r - 1 + end + end + + # threshold crossing + if y3 >= V_th: + r = RefractoryCounts + y3 = V_reset + + # EX: must compute spike time + emitSpike() + end + + end + + end + +end + diff --git a/src/test/resources/codegeneration/iaf_psc_exp_module.nestml b/src/test/resources/codegeneration/iaf_psc_exp_module.nestml new file mode 100644 index 000000000..029fc23c1 --- /dev/null +++ b/src/test/resources/codegeneration/iaf_psc_exp_module.nestml @@ -0,0 +1,98 @@ +package codegeneration.iaf_psc_exp_module: + + neuron iaf_psc_exp_neuron: + state: + i_0 real = 0.0 # synaptic stepwise constant input current, variable 0 + i_1 real = 0.0 # presynaptic stepwise constant input current + i_syn_ex real = 0.0 # postsynaptic current for exc. inputs, variable 1 + i_syn_in real = 0.0 # postsynaptic current for inh. inputs, variable 1 + V_m real = 0.0 # membrane potential, variable 2 + - r_ref integer = 0 # absolute refractory counter (no membrane potential propagation) + end + + parameter: + Tau ms = 10.0 + C ms = 250.0 + t_ref ms = 2.0 + U0 mV = -70.0 + I_e pA = 0.0 + alias Theta mV = -55.0 - U0 # relative U0 + alias V_reset mV = -70.0 - U0 # in mV + tau_ex ms = 2.0 + tau_in ms = 2.0 + end + + function set_V_reset(v mV): + V_reset = v - U0 + end + + function set_Theta(v mV): + Theta = v - U0 + end + + + internal: + h ms = resolution() + # these P are independent + P11ex real = exp(-h/tau_ex) + P11in real = exp(-h/tau_in) + P22 real = exp(-h/Tau) + P20 real = Tau/C*(1.0 - P22) + + # these depend on the above. Please do not change the order. + P21ex real = Tau/(C*(1.0-Tau/tau_ex)) * P11ex * (1.0 - exp(h*(1.0/tau_ex-1.0/Tau))) + P21in real = Tau/(C*(1.0-Tau/tau_in)) * P11in * (1.0 - exp(h*(1.0/tau_in-1.0/Tau))) + + weighted_spikes_ex real + weighted_spikes_in real + + - RefractoryCounts integer = steps(t_ref) + end + + input: + spikeBufferInh <- inhibitory spike + spikeBufferExc <- excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + if r_ref == 0: # neuron not refractory, so evolve V + V_m = V_m*P22 + i_syn_ex*P21ex + i_syn_in*P21in + (I_e+i_0)*P20 + else: + r_ref = r_ref - 1 # neuron is absolute refractory + end + + # exponential decaying PSCs + i_syn_ex = i_syn_ex * P11ex; + i_syn_in = i_syn_in * P11in; + + # add evolution of presynaptic input current + i_syn_ex = i_syn_ex + (1.0 - P11ex) * i_1; + + # the spikes arriving at T+1 have an immediate effect on the state of the neuron + weighted_spikes_ex = spikeBufferExc.getSum() + weighted_spikes_in = spikeBufferInh.getSum() + + i_syn_ex = i_syn_ex + weighted_spikes_ex + i_syn_in = i_syn_in + weighted_spikes_in + + if V_m >= Theta: # threshold crossing + r_ref = RefractoryCounts + V_m = V_reset + + emitSpike() + end + + # TODO this must be represented + # S_.i_0_ = B_.currents_[0].get_value(lag); + # S_.i_1_ = B_.currents_[1].get_value(lag); + i_0 = currentBuffer.getSum(t) + i_1 = currentBuffer.getSum(t) + end + + end + +end + diff --git a/src/test/resources/codegeneration/iaf_psc_exp_multisynapse_module.nestml b/src/test/resources/codegeneration/iaf_psc_exp_multisynapse_module.nestml new file mode 100644 index 000000000..55f5a7dd5 --- /dev/null +++ b/src/test/resources/codegeneration/iaf_psc_exp_multisynapse_module.nestml @@ -0,0 +1,97 @@ +package codegeneration.iaf_psc_exp_multisynapse_module: + neuron iaf_psc_exp_multisynapse_neuron: + state: + - i_syn real = 0 + - i_0 real = 0.0 + V_m real = 0.0 + - r_ref integer = 0 + end + + parameter: + - num_of_receptors integer = 1 + + # Membrane time constant + Tau ms = 10.0 + + # Membrane capacitance + C pF = 250.0 + + # Refractory period + t_ref ms = 2.0 + + # Resting potential + U0 mV = -70 + + # External current in + I_e pA = 0 + + # Reset value of the membrane potential + alias V_reset mV = -70 - U0 + + alias Theta mV = -55.0 - U0 # Threshold, RELATIVE TO RESTING POTENTIAL(!). + # I.e. the real threshold is (U0_+Theta_). + + # Time constants of synaptic currents + tau_syn ms; + + # boolean flag which indicates whether the neuron has connections + has_connections boolean = false + + # This is the current in a time step. This is only here to allow logging + currentValue pA = 0 + end + + function set_V_reset(v mV): + V_reset = v - U0 + end + + function set_Theta(v mV): + Theta = v - U0 + end + + internal: + h ms = resolution() + P11_syn real = -h / tau_syn + P21_syn real = Tau/(C*(1.0-Tau/tau_syn)) * P11_syn * (1.0 - exp(h*(1.0/tau_syn-1.0/Tau))); + P20 real = exp(-h/Tau) + P22 real = Tau/C*(1.0 - P22); + RefractoryCounts real = steps(t_ref) [RefractoryCounts >= 0] + end + + input: + spikeBufferInh <- inhibitory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + if r_ref == 0: # neuron not refractory, so evolve V + V_m = V_m * P22 + (I_e + i_0) * P20 # not sure about this + currentValue = 0.0 + V_m = V_m + P21_syn*i_syn + currentValue = currentValue + i_syn # not sure about this + else: + r_ref = r_ref - 1 # neuron is absolute refractory + end + + i_syn = i_syn * P11_syn; + # collect spikes + i_syn = i_syn + spikeBufferInh.getSum() # not sure about this + + if V_m >= Theta: # threshold crossing + r_ref = RefractoryCounts + V_m = V_reset + + emitSpike() + end + + # set new input current + i_0 = currentBuffer.getSum() + + end + + end + +end + diff --git a/src/test/resources/codegeneration/iaf_tum_2000_module.nestml b/src/test/resources/codegeneration/iaf_tum_2000_module.nestml new file mode 100644 index 000000000..0f03fe66f --- /dev/null +++ b/src/test/resources/codegeneration/iaf_tum_2000_module.nestml @@ -0,0 +1,112 @@ +package codegeneration.iaf_tum_2000: + + neuron iaf_tum_2000_neuron: + state: + i_0 mV + i_syn_ex mV + i_syn_in mV + # membrane potential relative to zero + delta_V_m mV + + - r_abs integer + - r_tot integer + + # alias for the actual membrane potential + alias V_m mV = E_L + delta_V_m + end + + parameter: + # Membrane time constant. + tau_m ms = 10.0 + # Membrane capacitance. + C_m pF = 250.0 + # Refractory period + t_ref_abs ms = 2.0 + # Refractory period + t_ref_tot ms = 2.0 + # Resting potential + E_L mV = -70.0 + # relative threshold + delta_V_th mV = 15.0 + # relative reset value + delta_V_reset mV = 0.0 + # External current + I_e pA = 0.0 + # Time constant of excitatory synaptic current + tau_syn_ex ms = 2.0 + # Time constant of inhibitory synaptic current + tau_syn_in ms = 2.0 + + # alias for the actual threshold + alias V_th mV = E_L + delta_V_th + # alias for the actual reset value + alias V_reset mV = E_L + delta_V_reset + end + + internal: + h ms = resolution() + + P11ex real = pow(E, (-h / tau_syn_ex)) + P11in real = pow(E, (-h / tau_syn_in)) + P22 real = pow(E, (-h / tau_m)) + P21ex real = tau_m / (C_m * (1.0 - tau_m / tau_syn_ex)) * P11ex * (1.0 - pow(E, h * (1.0 / tau_syn_ex - 1.0 / tau_m))) + P21in real = tau_m / (C_m * (1.0 - tau_m / tau_syn_in)) * P11in * (1.0 - pow(E, h * (1.0 / tau_syn_in - 1.0 / tau_m))) + P20 real = tau_m / C_m * (1.0 - P22) + + RefrCountAbs integer = steps(t_ref_abs) + RefrCountTot integer = steps(t_ref_tot) + end + + input: + inhBuffer <- inhibitory spike + excBuffer1 <- excitatory spike + excBuffer2 <- excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + + if r_abs == 0: # neuron not refractory, so evolve V + delta_V_m = delta_V_m * P22 + i_syn_ex * P21ex + i_syn_in * P21in + (I_e + i_0) * P20 + else: + r_abs = r_abs - 1 # neuron is absolute refractory + end + + # exponential decaying PSCs + i_syn_ex = i_syn_ex * P11ex + i_syn_in = i_syn_in * P11in + i_syn_ex = i_syn_ex + excBuffer1.getSum(t) # the spikes arriving at T+1 have an + i_syn_in = i_syn_in + inhBuffer.getSum(t) # the spikes arriving at T+1 have an + # immediate effect on the state of the neuron + + if r_tot == 0: + if V_m >= V_th: # threshold crossing + r_abs = RefrCountAbs + r_tot = RefrCountTot + V_m = V_reset + + emitSpike() + end + else: + r_tot = r_tot - 1 + end + + i_0 = currentBuffer.getSum(t) + end + + function set_V_th(v mV): + delta_V_th = v - E_L + end + + function set_V_reset(v mV): + delta_V_reset = v - E_L + end + + function set_V_m(v mV): + delta_V_m = v - E_L + end + end + +end diff --git a/src/test/resources/integration/nest.nestml b/src/test/resources/integration/nest.nestml new file mode 100644 index 000000000..05c5f8bc1 --- /dev/null +++ b/src/test/resources/integration/nest.nestml @@ -0,0 +1,207 @@ +package nest: + + neuron iaf_neuron: + state: + - y0, y1, y2, y3 mV [y1 > 0; y2 > 0] # TODO - sollen nicht getrackt werden + - r integer + # Membrane potential. + alias V_m mV = y3 + E_L + end + + parameter: + /* Capacity of the + membrane.*/ + + C_m pF = 250pF [C_m > 0] + # Membrane time constant. + tau_m ms = 10 [tau_m > 0] + # Time constant of synaptic current. + tau_syn ms = 2 + # Refractory period. + t_ref ms = 2 s + # Resting potential. + E_L mV = -70 + - delta_V_reset mV = -70 - E_L + -Theta mV = -55 - E_L + # External current. + I_e pA = 0 + + # some aliases + # Threshold. + alias V_th mV = Theta + E_L + # Reset value of the membrane potential. + alias V_reset mV = delta_V_reset + E_L + # invariant V_reset >= Theta + end + + internal: + h ms = Time.resolution() + P11 real = E ** (-h / tau_syn) + P22 real = P11 + P33 real = E ** (-h / tau_m) + P21 real = h * P11 + P30 real = 1 / C_m * (1 - P33) * tau_m + P31 real = 1 / C_m * ((P11 - P33) / (-1/tau_syn - -1/tau_m) - h * P11) / (-1/tau_m - -1/tau_syn) + P32 real = 1 / C_m * (P33 - P11) / (-1/tau_m - -1/tau_syn) + + PSCInitialValue mV = 1 * E / tau_syn + RefractoryCounts integer = Time.steps(t_ref) + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + if r == 0: # not refractory + y3 = P30 * (y0 + I_e) + P31 * y1 + P32 * y2 + P33 * y3 + else: + r = r - 1 + end + + # alpha shape PSCs + y2 = P21 * y1 + P22 * y2 + y1 = y1 * P11 + + # Apply spikes delivered in this step: The spikes arriving at T+1 have an + # immediate effect on the state of the neuron + y1 = y1 + PSCInitialValue * spikeBuffer.getSum(t) + + # threshold crossing + if y3 >= Theta: + r = RefractoryCounts + y3 = delta_V_reset + + Spiking.emitSpike() + end + + # set new input current + y0 = currentBuffer.getSum(t); + end + + function set_V_th(v mV): + Theta = v - E_L + end + + function set_V_reset(v mV): + delta_V_reset = v - E_L + end + + function set_V_m(v mV): + y3 = v - E_L + end + end + + neuron iaf_tum_2000: + state: + i_0 mV + i_syn_ex mV + i_syn_in mV + # membrane potential relative to zero + delta_V_m mV + + - r_abs integer + - r_tot integer + + # alias for the actual membrane potential + alias V_m mV = E_L + delta_V_m + end + + parameter: + # Membrane time constant. + tau_m ms = 10.0 + # Membrane capacitance. + C_m pF = 250.0 + # Refractory period + t_ref_abs ms = 2.0 + # Refractory period + t_ref_tot ms = 2.0 + # Resting potential + E_L mV = -70.0 + # relative threshold + delta_V_th mV = 15.0 + # relative reset value + delta_V_reset mV = 0.0 + # External current + I_e pA = 0.0 + # Time constant of excitatory synaptic current + tau_syn_ex ms = 2.0 + # Time constant of inhibitory synaptic current + tau_syn_in ms = 2.0 + + # alias for the actual threshold + alias V_th mV = E_L + delta_V_th + # alias for the actual reset value + alias V_reset mV = E_L + delta_V_reset + end + + internal: + h ms = Time.resolution() + + P11ex real = pow(E, (-h / tau_syn_ex)) + P11in real = pow(E, (-h / tau_syn_in)) + P22 real = pow(E, (-h / tau_m)) + P21ex real = tau_m / (C_m * (1.0 - tau_m / tau_syn_ex)) * P11ex * (1.0 - pow(E, h * (1.0 / tau_syn_ex - 1.0 / tau_m))) + P21in real = tau_m / (C_m * (1.0 - tau_m / tau_syn_in)) * P11in * (1.0 - pow(E, h * (1.0 / tau_syn_in - 1.0 / tau_m))) + P20 real = tau_m / C_m * (1.0 - P22) + + RefrCountAbs integer = Time.steps(t_ref_abs) + RefrCountTot integer = Time.steps(t_ref_tot) + end + + input: + inhBuffer <- inhibitory spike + excBuffer1 <- excitatory spike + excBuffer2 <- excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + + if r_abs == 0: # neuron not refractory, so evolve V + delta_V_m = delta_V_m * P22 + i_syn_ex * P21ex + i_syn_in * P21in + (I_e + i_0) * P20 + else: + r_abs = r_abs - 1 # neuron is absolute refractory + end + + # exponential decaying PSCs + i_syn_ex = i_syn_ex * P11ex + i_syn_in = i_syn_in * P11in + i_syn_ex = i_syn_ex + excBuffer1.getSum(t) # the spikes arriving at T+1 have an + i_syn_in = i_syn_in + inhBuffer.getSum(t) # the spikes arriving at T+1 have an + # immediate effect on the state of the neuron + + if r_tot == 0: + if V_m >= V_th: # threshold crossing + r_abs = RefrCountAbs + r_tot = RefrCountTot + V_m = V_reset + + Spiking.emitSpike() + end + else: + r_tot = r_tot - 1 + end + + i_0 = currentBuffer.getSum(t) + end + + function set_V_th(v mV): + delta_V_th = v - E_L + end + + function set_V_reset(v mV): + delta_V_reset = v - E_L + end + + function set_V_m(v mV): + delta_V_m = v - E_L + end + end +end + diff --git a/src/test/resources/org/nest/nestml/cocos/aliasMultipleVars.nestml b/src/test/resources/org/nest/nestml/cocos/aliasMultipleVars.nestml new file mode 100644 index 000000000..d82b7461b --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/aliasMultipleVars.nestml @@ -0,0 +1,18 @@ +package org.nest.nestml.cocos.aliasMultipleVars: + + component AliasSetter: + parameter: + x integer = 5 + alias y, g integer = -x + alias z real = x * y + end + + function set_y(v real): + x = -v + end + + function set_z(): + end + + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/aliasSetter.nestml b/src/test/resources/org/nest/nestml/cocos/aliasSetter.nestml new file mode 100644 index 000000000..ac8fe9fe1 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/aliasSetter.nestml @@ -0,0 +1,18 @@ +package org.nest.nestml.cocos.aliasSetter: + + component AliasSetter: + parameter: + x integer = 5 + alias y integer = -x + alias z real = x * y + end + + function set_y(v real): + x = -v + end + + function set_z(): + end + + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/codeAfterReturn.nestml b/src/test/resources/org/nest/nestml/cocos/codeAfterReturn.nestml new file mode 100644 index 000000000..a060db291 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/codeAfterReturn.nestml @@ -0,0 +1,13 @@ +package org.nest.nestml.cocos.codeAfterReturn: + + component Simple: + + + function foo() real: + return 15.5 + + Logger.info("me is after return") + end + end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/componentWithDynamics.nestml b/src/test/resources/org/nest/nestml/cocos/componentWithDynamics.nestml new file mode 100644 index 000000000..b1174ce54 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/componentWithDynamics.nestml @@ -0,0 +1,6 @@ +package org.nest.nestml.cocos.componentWithDynamics: + component CompWithDynamics: + dynamics timestep (t ms): + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/componentWithInput.nestml b/src/test/resources/org/nest/nestml/cocos/componentWithInput.nestml new file mode 100644 index 000000000..dfc7bbbc4 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/componentWithInput.nestml @@ -0,0 +1,9 @@ +package org.nest.nestml.cocos.componentWithInput: + + component ComponentWithInput: + input: + buff <- spike + end + end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/componentWithOutput.nestml b/src/test/resources/org/nest/nestml/cocos/componentWithOutput.nestml new file mode 100644 index 000000000..d184eea0c --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/componentWithOutput.nestml @@ -0,0 +1,5 @@ +package org.nest.nestml.cocos.componentWithOutput: + component CompWithOutput: + output: spike + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/emptyNeuron.nestml b/src/test/resources/org/nest/nestml/cocos/emptyNeuron.nestml new file mode 100644 index 000000000..1943228e5 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/emptyNeuron.nestml @@ -0,0 +1,4 @@ +package org.nest.nestml.cocos.emptyNeuron: + neuron EmptyNeuron: + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/funNotDefined.nestml b/src/test/resources/org/nest/nestml/cocos/funNotDefined.nestml new file mode 100644 index 000000000..844b0388f --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/funNotDefined.nestml @@ -0,0 +1,13 @@ +package notDefined: + + neuron NeuronFunCall: + function foo(): + bar() /* not defined */ + EmptyNeuron.bar() + # not defined + NeuronInTest.foo(2) # not defined with parameter + + end + end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/functionWithOutReturn.nestml b/src/test/resources/org/nest/nestml/cocos/functionWithOutReturn.nestml new file mode 100644 index 000000000..cfcfb57b9 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/functionWithOutReturn.nestml @@ -0,0 +1,17 @@ +package org.nest.nestml.cocos.functionWithOutReturn: + + component FuncWithOutReturn: + + function empty1(x mV) real: + if x > 0: + return x * 2 + end + + end + + function empty2(x mV) void: + + end + end + +end diff --git a/src/test/resources/org/nest/nestml/cocos/functionsWithWrongReturns.nestml b/src/test/resources/org/nest/nestml/cocos/functionsWithWrongReturns.nestml new file mode 100644 index 000000000..0967334a7 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/functionsWithWrongReturns.nestml @@ -0,0 +1,25 @@ +package functionWithWrongReturns: + import nestml.* + import units.unitless.* + component WrongReturns: + function foo1(): + return 3 + end + + function foo2() real: + return + end + + function foo3() string: + return 4 + end + + function foo4() boolean: + return "hi" + end + + function foo5() integer: + return 3.5 + end + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/getterSetter.nestml b/src/test/resources/org/nest/nestml/cocos/getterSetter.nestml new file mode 100644 index 000000000..cbb82828c --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/getterSetter.nestml @@ -0,0 +1,33 @@ +package org.nest.nestml.cocos.getterSetter: + + component GetSet: + internal: + a mV + alias b integer + end + + function get_a() mV: # error + end + + function set_a(x real): # error + end + + function set_a(): # no error + end + + function get_b(): # error + end + + function get_b(x mV, bs integer): # no error + end + + function set_b(): # no error + end + + function set_b(x mV): # no error + end + + function get_instance(): + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/illegalNumberExpressions.nestml b/src/test/resources/org/nest/nestml/cocos/illegalNumberExpressions.nestml new file mode 100644 index 000000000..5944e453a --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/illegalNumberExpressions.nestml @@ -0,0 +1,42 @@ +package illegalExpression: + + import nestml.* + import units.unitless.* + + component IllegalNumberExpressions: + + internal: + b boolean = true + + end + + function foo(): + bar real = b ** 4 + + foo integer = 3*b*6/b + + foobar integer = 3.0 << 4 >> 2.0 + + barfoo integer = 3.2 & 5 & 6.4 + + bafoo integer = 3.2 | 5 | 6.4 + + barfo integer = 3.2 ^ 5 ^ 6.4 + + if foo: + + elif bar(): + + elif b < 7: + + elif "abc" > "bca": # ok? + + end + end + + function bar() integer: + return 0 + end + end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/illegalStringExpressions.nestml b/src/test/resources/org/nest/nestml/cocos/illegalStringExpressions.nestml new file mode 100644 index 000000000..5f665d367 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/illegalStringExpressions.nestml @@ -0,0 +1,27 @@ +package illegalExpression: + + component IllegalStringExpressions: + internal: + i IllegalNumberExpressions + end + + function foo(): + # no error + bar string = (5) + "Hallo Welt!" + # error + foo string = "Hello" * 5 + # error + foobar string = "Hello" | 6 + # error + barfoo string = "Hello" ** 3 + # error + barbar string = "" + 3 - "!" + + # error + foofoo string = "" + i + + correct string = "Hello " + (3 * 4.0)**6 + " " + "Welt!" + end + end + +end diff --git a/src/test/resources/org/nest/nestml/cocos/inputTypeForCurrent.nestml b/src/test/resources/org/nest/nestml/cocos/inputTypeForCurrent.nestml new file mode 100644 index 000000000..29873e292 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/inputTypeForCurrent.nestml @@ -0,0 +1,12 @@ +package org.nest.nestml.cocos.inputTypeForCurrent: + neuron InhExcTypeForCurrent: + input: + inhBuffer <- inhibitory current + excBuffer <- excitatory current + inhExcBuffer <- inhibitory excitatory current + end + + dynamics timestep(t ms): + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/invalidTypeInDecl.nestml b/src/test/resources/org/nest/nestml/cocos/invalidTypeInDecl.nestml new file mode 100644 index 000000000..ec8049544 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/invalidTypeInDecl.nestml @@ -0,0 +1,23 @@ +package org.nest.nestml.cocos.invalidTypeInDecl: + + component Test: + end + + component InvalidTypes: + use Test as TestRef + + state: + a Test # error 1 + alias b TestRef # error 2 + c boolean + d string + l Logger # TODO better error description + end + + function foo(bar Test) TestRef: # error 3, 4 + n org.nest.nestml.parsing.iaf_neuron.iaf_neuron + + end + end + +end diff --git a/src/test/resources/org/nest/nestml/cocos/invariants/invalidInvariantType.nestml b/src/test/resources/org/nest/nestml/cocos/invariants/invalidInvariantType.nestml new file mode 100644 index 000000000..d8c895aac --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/invariants/invalidInvariantType.nestml @@ -0,0 +1,28 @@ +package org.nest.nestml.cocos.undefinedVariables.invalidInvariantType: + + neuron testNeuron: + state: + stateVar1 real = 1.0 + stateVar2 real = 1.0 [stateVar1] + stateVar2 real = 1.0 [2+2] + end + + parameter: + end + + internal: + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + + end + end +end + diff --git a/src/test/resources/org/nest/nestml/cocos/invariants/validInvariantType.nestml b/src/test/resources/org/nest/nestml/cocos/invariants/validInvariantType.nestml new file mode 100644 index 000000000..67216affd --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/invariants/validInvariantType.nestml @@ -0,0 +1,27 @@ +package org.nest.nestml.cocos.undefinedVariables.validInvariantType: + + neuron testNeuron: + state: + stateVar1 boolean = false + stateVar2 real = 1.0 [stateVar1] + end + + parameter: + end + + internal: + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + + end + end +end + diff --git a/src/test/resources/org/nest/nestml/cocos/memberVarDefinedInWrongOrder.nestml b/src/test/resources/org/nest/nestml/cocos/memberVarDefinedInWrongOrder.nestml new file mode 100644 index 000000000..8b448e3cc --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/memberVarDefinedInWrongOrder.nestml @@ -0,0 +1,18 @@ +package org.nest.nestml.cocos.memberVarDefinedInWrongOrder: + component CompMembers: + state: + alias foo real = 13 * test # error 1 test is internal variable + bar real = test + 1.1 * P2 # error 2 test is internal variable + + end + + internal: + test real = 13 + end + + parameter: + P1 real = 2 + P2 # error: P2 is undefined at this place + P2 real = 2 * P1 + P2 # P3 is undefined at this place + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/multipleAliasVars.nestml b/src/test/resources/org/nest/nestml/cocos/multipleAliasVars.nestml new file mode 100644 index 000000000..d71837be6 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/multipleAliasVars.nestml @@ -0,0 +1,11 @@ +package aliasP: + + import units.unitless.* + + neuron EmptyNeuron: + state: + alias x, y , z real = 3 + end + end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/multipleDynamicsNeuron.nestml b/src/test/resources/org/nest/nestml/cocos/multipleDynamicsNeuron.nestml new file mode 100644 index 000000000..88d25ea80 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/multipleDynamicsNeuron.nestml @@ -0,0 +1,9 @@ +package org.nest.nestml.cocos.multipleDynamicsNeuron: + neuron MultipleDynamicsNeuron: + dynamics timestep(t ms): + end + + dynamics minDelay(t ms): + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/multipleFunctionDeclarations.nestml b/src/test/resources/org/nest/nestml/cocos/multipleFunctionDeclarations.nestml new file mode 100644 index 000000000..c26889142 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/multipleFunctionDeclarations.nestml @@ -0,0 +1,33 @@ +package org.nest.nestml.cocos.multipleFunctionDeclarations: + + neuron MultipleFunctionsNeuron: + + function empty1() : + + end + + function empty1() : + + end + + function empty1(x mV) : + + end + + function empty1(x pA) : + + end + + function empty1(x pA, y mV) : + + end + + function empty1(x mV, y pA) : + + end + + dynamics timestep(t ms): + end + end + +end diff --git a/src/test/resources/org/nest/nestml/cocos/multipleInhExcInInput.nestml b/src/test/resources/org/nest/nestml/cocos/multipleInhExcInInput.nestml new file mode 100644 index 000000000..4f1019f4f --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/multipleInhExcInInput.nestml @@ -0,0 +1,12 @@ +package org.nest.nestml.cocos.multipleInhExcInInput: + neuron MultipleInhExc: + input: + inhBuffer <- inhibitory inhibitory spike + excBuffer <- excitatory excitatory excitatory spike + inhExcBuffer <- inhibitory excitatory inhibitory excitatory spike + end + + dynamics timestep(t ms): + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/multipleOutputs.nestml b/src/test/resources/org/nest/nestml/cocos/multipleOutputs.nestml new file mode 100644 index 000000000..fb4bb03c5 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/multipleOutputs.nestml @@ -0,0 +1,11 @@ +package org.nest.nestml.cocos.multipleOutputs: + neuron OutputsNeuron: + output: spike + output: current + end + + component OutputsComponent: + output: spike + output: current + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/multipleTypesDeclared.nestml b/src/test/resources/org/nest/nestml/cocos/multipleTypesDeclared.nestml new file mode 100644 index 000000000..e95e395d2 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/multipleTypesDeclared.nestml @@ -0,0 +1,11 @@ +package org.nest.nestml.cocos.multipleTypesDeclared: + + neuron Foo: + dynamics timestep(t ms): + end + end + + component Foo: + end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/nestFunName.nestml b/src/test/resources/org/nest/nestml/cocos/nestFunName.nestml new file mode 100644 index 000000000..22107c33e --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/nestFunName.nestml @@ -0,0 +1,30 @@ +package org.nest.nestml.cocos.nestFunName: + component Blaa: + function update(): + end + + function calibrate(t ms): + end + + function handle(r real): + end + + function connect_sender(i integer): + end + + function check_connection(): + end + + function get_status(): + end + + function set_status(): + end + + function init_state_(): + end + + function init_buffers_(): + end + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/nestmlPackage.nestml b/src/test/resources/org/nest/nestml/cocos/nestmlPackage.nestml new file mode 100644 index 000000000..f173dc6fe --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/nestmlPackage.nestml @@ -0,0 +1,3 @@ +package nestml: + # empty +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/paramExpr.nestml b/src/test/resources/org/nest/nestml/cocos/paramExpr.nestml new file mode 100644 index 000000000..e105cb811 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/paramExpr.nestml @@ -0,0 +1,17 @@ +package paras: + component ParaExpr: + # TODO: forbid keywords as variable name per coco + function foo(str string, int1 integer, r real): + end + + function bar(): + foo("Hallo Welt!", 23, 0.5) + + foo(23, "Hallo Welt!", 0.5) + + foo("Hallo Welt!", 0.5, 23) + + foo("Hallo Welt!", 23, "Hallo Welt!") + end + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/reassignBuffer.nestml b/src/test/resources/org/nest/nestml/cocos/reassignBuffer.nestml new file mode 100644 index 000000000..3271ddf70 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/reassignBuffer.nestml @@ -0,0 +1,11 @@ +package useAliasInNonAliasDecl.nestml.reassignBuffer: + neuron ReassignBuffer: + input: + testBuffer <- spike + end + + dynamics timestep(t ms): + testBuffer = 15 + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/reassignParaInternal.nestml b/src/test/resources/org/nest/nestml/cocos/reassignParaInternal.nestml new file mode 100644 index 000000000..70de08e7f --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/reassignParaInternal.nestml @@ -0,0 +1,18 @@ +package reassign: + neuron Reassigner: + parameter: + a integer = 10 + end + internal: + b real = 0.23 + end + + function foo(): + b = a * 12.7 + end + + dynamics timestep(t ms): + a = 10 | 2 + end + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/splInFunctions/invalidMethod.nestml b/src/test/resources/org/nest/nestml/cocos/splInFunctions/invalidMethod.nestml new file mode 100644 index 000000000..e887adae9 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/splInFunctions/invalidMethod.nestml @@ -0,0 +1,78 @@ +package org.nest.nestml.cocos.splInFunctions.invalidMethod: + + neuron testNeuron: + state: + end + + parameter: + end + + internal: + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + return + + multipleSigns integer = +++2 # TODO doesn't work since not activated + # error: code after return + bar() # error 1 /* not defined */ + random(2) # error 2 not defined with parameter + + b boolean = true + + bar real = b ** 4 # error 3: boolean cannot be used as a base + + foo integer = 3*b*6/b # error 4: boolean as a factor in devision + + foobar integer = 3.0 << 4 >> 2.0 # error 5+6: no shift operation on float values + + barfoo integer = 3.2 & 5 & 6.4 # error 6+7 no bit operation on float values + + bafoo integer = 3.2 | 5 | 6.4 # error 8+9 no bit operation on float values + + barfo integer = 3.2 ^ 5 ^ 6.4 # error 10+11 no bit operation on float values + + if foo: # 13 integer is not a valid boolean expression + + elif randomInt(): # 14 integer which is the return value of randomInt is not a valid boolean expression + + elif b < 7: # 15 cannot compare boolean to integer + + elif "abc" > "bca": # ok? 16 no comparison + + end + + # error 17 + foo2 string = "Hello" * 5 + # error 18 + barfoo2 string = "Hello" ** 3 + + i void + # error 19 + foofoo2 string = "" + i + + x3 boolean + for x3 in 1 ... 5 : # error: boolean in for step + + end + + real real = 0.0 + #x3 boolean # x3 is already defined. # TODO doesn't work + + xxx real = 2 * xxx # TODO it should produce an error + + # for a in 1 ... 10 step 1: # TODO it should work + # blaa + # end + end + + end +end + diff --git a/src/test/resources/org/nest/nestml/cocos/splInFunctions/validMethod.nestml b/src/test/resources/org/nest/nestml/cocos/splInFunctions/validMethod.nestml new file mode 100644 index 000000000..c2dff4d10 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/splInFunctions/validMethod.nestml @@ -0,0 +1,31 @@ +package org.nest.nestml.cocos.splInFunctions.validMethod: + + neuron testNeuron: + state: + test1 real = 1.0 + end + + parameter: + end + + internal: + end + + input: + end + + output: spike + + dynamics timestep(t ms): + + multipleSigns integer = 2 + random() + return + end + + function random() integer: + end + + end +end + diff --git a/src/test/resources/org/nest/nestml/cocos/timestepDynamics.nestml b/src/test/resources/org/nest/nestml/cocos/timestepDynamics.nestml new file mode 100644 index 000000000..843262b80 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/timestepDynamics.nestml @@ -0,0 +1,17 @@ +package org.nest.nestml.cocos.timestepDynamics: + + neuron TimestepNeuron1: + dynamics timestep(t real): + end + end + + neuron TimestepNeuron2: + dynamics timestep(): + end + end + + neuron TimestepNeuron3: + dynamics timestep(t1 real, t2 integer): + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/typenameAsVarName.nestml b/src/test/resources/org/nest/nestml/cocos/typenameAsVarName.nestml new file mode 100644 index 000000000..1b99590af --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/typenameAsVarName.nestml @@ -0,0 +1,20 @@ +package org.nest.nestml.parsing.typenameAsVarName: + + neuron iaf_neuron: + state: + integer integer = 1 + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + end + + end +end + diff --git a/src/test/resources/org/nest/nestml/cocos/undefinedVariables/invalidModelUndefinedValues.nestml b/src/test/resources/org/nest/nestml/cocos/undefinedVariables/invalidModelUndefinedValues.nestml new file mode 100644 index 000000000..559993367 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/undefinedVariables/invalidModelUndefinedValues.nestml @@ -0,0 +1,33 @@ +package org.nest.nestml.cocos.undefinedVariables.invalidModelUndefinedValues: + + neuron testNeuron: + state: + stateVar1 real = 1.0 [stateVar2 > 0] + stateVar2 real = 1.0 + internalVar1 # Error parameterVar1 cannot be used in state block + + + end + + parameter: + # Error parameter can only use another parameter in correct order + parameterVar1 real = stateVar1 + end + + internal: + internalVar1 real = 1.0 + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + + end + + end +end + diff --git a/src/test/resources/org/nest/nestml/cocos/undefinedVariables/validModelUndefinedValues.nestml b/src/test/resources/org/nest/nestml/cocos/undefinedVariables/validModelUndefinedValues.nestml new file mode 100644 index 000000000..cbc02b377 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/undefinedVariables/validModelUndefinedValues.nestml @@ -0,0 +1,29 @@ +package org.nest.nestml.cocos.undefinedVariables.validModelUndefinedValues: + + neuron testNeuron: + state: + test1 real = 1 [test1 > parameterVar1] + end + + parameter: + parameterVar1 real = 1 + parameterVar2 real = parameterVar1 + end + + internal: + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + + end + + end +end + diff --git a/src/test/resources/org/nest/nestml/cocos/useAliasInNonAliasDecl.nestml b/src/test/resources/org/nest/nestml/cocos/useAliasInNonAliasDecl.nestml new file mode 100644 index 000000000..b55a09b03 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/useAliasInNonAliasDecl.nestml @@ -0,0 +1,13 @@ +package org.nest.nestml.cocos.useAliasInNonAliasDecl: + component AliasInDecl: + parameter: + alias three integer = 3 # should be an error? + + threePlusFour integer = three + 4 + end + + function set_three(v integer): + + end + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/useComponents/importedComponent.nestml b/src/test/resources/org/nest/nestml/cocos/useComponents/importedComponent.nestml new file mode 100644 index 000000000..973596cd2 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/useComponents/importedComponent.nestml @@ -0,0 +1,9 @@ +package org.nest.nestml.cocos.useComponents.importedComponent: + + component ImportedComponent: + function testFunction(): + end + end + +end + diff --git a/src/test/resources/org/nest/nestml/cocos/useComponents/importedNeuron.nestml b/src/test/resources/org/nest/nestml/cocos/useComponents/importedNeuron.nestml new file mode 100644 index 000000000..6e0446d39 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/useComponents/importedNeuron.nestml @@ -0,0 +1,9 @@ +package org.nest.nestml.cocos.useComponents.importedNeuron: + + neuron ImportedNeuron: + function testFunction(): + end + end + +end + diff --git a/src/test/resources/org/nest/nestml/cocos/useComponents/invalidUsage.nestml b/src/test/resources/org/nest/nestml/cocos/useComponents/invalidUsage.nestml new file mode 100644 index 000000000..b31bee7d1 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/useComponents/invalidUsage.nestml @@ -0,0 +1,15 @@ +package org.nest.nestml.cocos.useComponents.invalidUsage: + + import org.nest.nestml.parsing.iaf_neuron.iaf_neuron + + neuron UsesNeuron: + use iaf_neuron as blaa + + dynamics timestep(t ms): + end + end + + component UsesUnit: + use integer as blub + end +end diff --git a/src/test/resources/org/nest/nestml/cocos/useComponents/validUsage.nestml b/src/test/resources/org/nest/nestml/cocos/useComponents/validUsage.nestml new file mode 100644 index 000000000..fac431462 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/useComponents/validUsage.nestml @@ -0,0 +1,32 @@ +package org.nest.nestml.cocos.useComponents.importingNeuron: + + import org.nest.nestml.cocos.useComponents.importedComponent.ImportedComponent + + neuron UsingNeuron: + use ImportedComponent as TestReference + + state: + end + + parameter: + end + + internal: + + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + TestReference.testFunction() + end + + end + +end + diff --git a/src/test/resources/org/nest/nestml/cocos/validImports.nestml b/src/test/resources/org/nest/nestml/cocos/validImports.nestml new file mode 100644 index 000000000..9ee27fdaa --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/validImports.nestml @@ -0,0 +1,7 @@ +package validImports: + + import bullshit.* + + component ValidNeuron: + end +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/varDefinedMultipleTimes.nestml b/src/test/resources/org/nest/nestml/cocos/varDefinedMultipleTimes.nestml new file mode 100644 index 000000000..c6be96ef8 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/varDefinedMultipleTimes.nestml @@ -0,0 +1,13 @@ +package org.nest.nestml.cocos.varDefinedMultipleTimes: + + neuron NeuronInTest: + state: + x mV + end + + parameter: + x real = x * 2 + end + end + +end diff --git a/src/test/resources/org/nest/nestml/cocos/varDefinedMultipleTimesLocal.nestml b/src/test/resources/org/nest/nestml/cocos/varDefinedMultipleTimesLocal.nestml new file mode 100644 index 000000000..df3ee392a --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/varDefinedMultipleTimesLocal.nestml @@ -0,0 +1,35 @@ +package notDefined: + + neuron NeuronMultipleLocal: + + state: + x pA + end + + function foo(): + z mV + if 1>0 : + x mV + z mV + x mV + end + end + + function bar(x real, z real): + x mV + while true: + z mV + end + end + + dynamics timestep (t ms): + t mV + h integer + for h in 0 ... 10: + t ms + end + end + + end + +end diff --git a/src/test/resources/org/nest/nestml/cocos/varNotDefined.nestml b/src/test/resources/org/nest/nestml/cocos/varNotDefined.nestml new file mode 100644 index 000000000..37d87ca3a --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/varNotDefined.nestml @@ -0,0 +1,11 @@ +package notDefined: + + import units.unitless.* + + neuron EmptyNeuron: + state: + x real = 3 * y + end + end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/varNotDefinedBeforeUse.nestml b/src/test/resources/org/nest/nestml/cocos/varNotDefinedBeforeUse.nestml new file mode 100644 index 000000000..b059fdb95 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/varNotDefinedBeforeUse.nestml @@ -0,0 +1,11 @@ +package notDefined: + + component NeuronLocalVarNotDefinedYet: + function foo(): + y real = 5 * x + x = 13 + x real = 2 * x + end + end + +end diff --git a/src/test/resources/org/nest/nestml/cocos/varNotDefinedInTest.nestml b/src/test/resources/org/nest/nestml/cocos/varNotDefinedInTest.nestml new file mode 100644 index 000000000..e6b49c2e8 --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/varNotDefinedInTest.nestml @@ -0,0 +1,10 @@ +package notDefined: + + neuron NeuronInTest: + function foo(): + if x: + end + end + end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/cocos/varWithTypeName.nestml b/src/test/resources/org/nest/nestml/cocos/varWithTypeName.nestml new file mode 100644 index 000000000..6c9add19a --- /dev/null +++ b/src/test/resources/org/nest/nestml/cocos/varWithTypeName.nestml @@ -0,0 +1,12 @@ +package org.nest.nestml.cocos.varWithTypeName: + + component B: + state: + real real = 15.0 + end + + dynamics timestep (t ms): + string string = "a" + end + end +end diff --git a/src/test/resources/org/nest/nestml/parsing/aneuronWithUseAndCode.nestml b/src/test/resources/org/nest/nestml/parsing/aneuronWithUseAndCode.nestml new file mode 100644 index 000000000..5fe945b98 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/aneuronWithUseAndCode.nestml @@ -0,0 +1,23 @@ +package org.nest.nestml.parsing.aneuronWithUseAndCode: + + import empty.* + + neuron Neuron1234: + + function foobar(): + EmptyFunctionNeuron.empty() + end + + dynamics timestep(t ms): + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/emptyComponent.nestml b/src/test/resources/org/nest/nestml/parsing/emptyComponent.nestml new file mode 100644 index 000000000..cdb26dd45 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/emptyComponent.nestml @@ -0,0 +1,5 @@ +package org.nest.nestml.parsing.emptyComponent: + + component EmptyComponent:end + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/parsing/emptyFuncWPars.nestml b/src/test/resources/org/nest/nestml/parsing/emptyFuncWPars.nestml new file mode 100644 index 000000000..6cf2e23a2 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/emptyFuncWPars.nestml @@ -0,0 +1,27 @@ +package org.nest.nestml.parsing.emptyFuncWPars: + + + neuron EmptyFuncWParsNeuron: + function empty1(x mV) : + + end + + function empty2(x pA, y mV) : + + end + + function empty3(x pF, y pA) mV : + return 0 + end + + dynamics timestep(t ms): + end + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/emptyFunction.nestml b/src/test/resources/org/nest/nestml/parsing/emptyFunction.nestml new file mode 100644 index 000000000..dc557f6f2 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/emptyFunction.nestml @@ -0,0 +1,18 @@ +package org.nest.nestml.parsing.emptyFunction: + + neuron EmptyFunctionNeuron: + function empty() : + + end + + dynamics timestep(t ms): + end + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/emptyNeuron.nestml b/src/test/resources/org/nest/nestml/parsing/emptyNeuron.nestml new file mode 100644 index 000000000..14b5d30e5 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/emptyNeuron.nestml @@ -0,0 +1,14 @@ +package org.nest.nestml.parsing.emptyNeuron: + + neuron EmptyNeuron: + dynamics minDelay(t ms): + end + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/emptyPackage.nestml b/src/test/resources/org/nest/nestml/parsing/emptyPackage.nestml new file mode 100644 index 000000000..ad8acacbf --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/emptyPackage.nestml @@ -0,0 +1,3 @@ +package org.nest.nestml.parsing.emptyPackage: + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/parsing/functionWithReturn.nestml b/src/test/resources/org/nest/nestml/parsing/functionWithReturn.nestml new file mode 100644 index 000000000..9105846b5 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/functionWithReturn.nestml @@ -0,0 +1,28 @@ +package org.nest.nestml.parsing.functionWithReturn: + + component Functions: + function empty1() : + if 2 == 1: + return + end + end + + function empty2() mV: + if 2 == 1: + return 12.3 + else: + return -12.3 + end + end + + function empty3() boolean: + return 2 == 4/2 + end + + function empty4() string: + return "|" + " " + "blaaa" + end + + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/headerInNeuron.nestml b/src/test/resources/org/nest/nestml/parsing/headerInNeuron.nestml new file mode 100644 index 000000000..18686d8ef --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/headerInNeuron.nestml @@ -0,0 +1,22 @@ +package org.nest.nestml.parsing.headerInNeuron: + + neuron EmptyHeaderNeuron: + # TODO not working yet + #_NEST_HEADER_: + # #include + + # #define TRUE 1 + # _END_ + + dynamics timestep(t ms): + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/iaf_neuron.nestml b/src/test/resources/org/nest/nestml/parsing/iaf_neuron.nestml new file mode 100644 index 000000000..b463d7fdf --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/iaf_neuron.nestml @@ -0,0 +1,98 @@ +package org.nest.nestml.parsing.iaf_neuron: + + neuron iaf_neuron: + state: + - y0, y1, y2, y3 mV[ y1 > 0; y2 > 0] + - r integer + # Membrane potential. + alias V_m mV = y3 + E_L + end + + parameter: + /* Capacity of the + membrane.*/ + + C_m pF = 250pF * 20 uF [C_m > 0] + # Membrane time constant. + tau_m ms = 10 [tau_m > 0] + # Time constant of synaptic current. + tau_syn ms = 2 + # Refractory period. + t_ref ms = 2 s + # Resting potential. + E_L mV = -70 + - delta_V_reset mV = -70 - E_L + -Theta mV = -55 - E_L + # External current. + I_e pA = 0 + + # some aliases + # Threshold. + alias V_th mV = Theta + E_L + # Reset value of the membrane potential. + alias V_reset mV = delta_V_reset + E_L + # TODO: invariant V_reset >= Theta + end + + internal: + h ms = Time.resolution() + P11 real = pow(E, (-h / tau_syn)) + P22 real = P11 + P33 real = pow(E, (-h / tau_m)) + P21 real = h * P11 + P30 real = 1 / C_m * (1 - P33) * tau_m + P31 real = 1 / C_m * ((P11 - P33) / (-1/tau_syn - -1/tau_m) - h * P11) / (-1/tau_m - -1/tau_syn) + P32 real = 1 / C_m * (P33 - P11) / (-1/tau_m - -1/tau_syn) + + PSCInitialValue mV = 1 * E / tau_syn + RefractoryCounts integer = Time.steps(t_ref) + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + if r == 0: # not refractory + y3 = P30 * (y0 + I_e) + P31 * y1 + P32 * y2 + P33 * y3 + else: + r = r - 1 + end + + # alpha shape PSCs + y2 = P21 * y1 + P22 * y2 + y1 = y1 * P11 + + # Apply spikes delivered in this step: The spikes arriving at T+1 have an + # immediate effect on the state of the neuron + y1 = y1 + PSCInitialValue * spikeBuffer.getSum(t) + + # threshold crossing + if y3 >= Theta: + r = RefractoryCounts + y3 = delta_V_reset + + Spiking.emitSpike() + end + + # set new input current + y0 = currentBuffer.getSum(t); + end + + function set_V_th(v mV): + Theta = v - E_L + end + + function set_V_reset(v mV): + delta_V_reset = v - E_L + end + + function set_V_m(v mV): + y3 = v - E_L + end + end +end + diff --git a/src/test/resources/org/nest/nestml/parsing/iaf_tum_2000.nestml b/src/test/resources/org/nest/nestml/parsing/iaf_tum_2000.nestml new file mode 100644 index 000000000..783ec2c9f --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/iaf_tum_2000.nestml @@ -0,0 +1,112 @@ +package org.nest.nestml.parsing.iaf_tum_2000: + + + neuron iaf_tum_2000: + state: + i_0 mV + i_syn_ex mV + i_syn_in mV + # membrane potential relative to zero + delta_V_m mV + + r_abs integer + r_tot integer + + # alias for the actual membrane potential + alias V_m mV = E_L + delta_V_m + end + + parameter: + # Membrane time constant. + tau_m ms = 10.0 + # Membrane capacitance. + C_m pF = 250.0 + # Refractory period + t_ref_abs ms = 2.0 + # Refractory period + t_ref_tot ms = 2.0 + # Resting potential + E_L mV = -70.0 + # relative threshold + delta_V_th mV = 15.0 + # relative reset value + delta_V_reset mV = 0.0 + # External current + I_e pA = 0.0 + # Time constant of excitatory synaptic current + tau_syn_ex ms = 2.0 + # Time constant of inhibitory synaptic current + tau_syn_in ms = 2.0 + + # alias for the actual threshold + alias V_th mV = E_L + delta_V_th + # alias for the actual reset value + alias V_reset mV = E_L + delta_V_reset + end + + internal: + h ms = Time.resolution() + + P11ex real = E ** (-h / tau_syn_ex) + P11in real = E ** (-h / tau_syn_in) + P22 real = E ** (-h / tau_m) + P21ex real = tau_m / (C_m * (1.0 - tau_m / tau_syn_ex)) * P11ex * (1.0 - E ** (h * (1.0 / tau_syn_ex - 1.0 / tau_m))) + P21in real = tau_m / (C_m * (1.0 - tau_m / tau_syn_in)) * P11in * (1.0 - E ** (h * (1.0 / tau_syn_in - 1.0 / tau_m))) + P20 real = tau_m / C_m * (1.0 - P22) + + RefrCountAbs integer = Time.steps(t_ref_abs) + RefrCountTot integer = Time.steps(t_ref_tot) + end + + input: + inhBuffer <- inhibitory spike + excBuffer <- excitatory spike + currentsBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + + if r_abs == 0: # neuron not refractory, so evolve V + delta_V_m = delta_V_m * P22 + i_syn_ex * P21ex + i_syn_in * P21in + (I_e + i_0) * P20 + else: + r_abs = r_abs - 1 # neuron is absolute refractory + end + + # exponential decaying PSCs + i_syn_ex = i_syn_ex * P11ex + i_syn_in = i_syn_in * P11in + i_syn_ex = i_syn_ex + excBuffer.getSum(t) # the spikes arriving at T+1 have an + i_syn_in = i_syn_in + inhBuffer.getSum(t) # the spikes arriving at T+1 have an + # immediate effect on the state of the neuron + + if r_tot == 0: + if V_m >= V_th: # threshold crossing + r_abs = RefrCountAbs + r_tot = RefrCountTot + V_m = V_reset + + Spiking.emitSpike() + end + else: + r_tot = r_tot - 1 + end + + i_0 = currentsBuffer.getSum(t) + end + + function set_V_th(v mV): + delta_V_th = v - E_L + end + + function set_V_reset(v mV): + delta_V_reset = v - E_L + end + + function set_V_m(v mV): + delta_V_m = v - E_L + end + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/imports.nestml b/src/test/resources/org/nest/nestml/parsing/imports.nestml new file mode 100644 index 000000000..944c3b942 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/imports.nestml @@ -0,0 +1,7 @@ +package org.nest.nestml.parsing.imports: + + import empty.EmptyNeuron + import empty.EmptyComponent; + import header.* + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/parsing/nestCodeInNeuron.nestml b/src/test/resources/org/nest/nestml/parsing/nestCodeInNeuron.nestml new file mode 100644 index 000000000..dc386f7ef --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/nestCodeInNeuron.nestml @@ -0,0 +1,22 @@ +package org.nest.nestml.parsing.nestCodeInNeuron: + + neuron EmptyCodeNeuron: + + /*function blaa(): + //_NEST_CODE_: + # int x = 3; + # x = x + 5; + //_END_ + end*/ + + dynamics timestep(t ms): + end + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/neuronWithEmptyComponent.nestml b/src/test/resources/org/nest/nestml/parsing/neuronWithEmptyComponent.nestml new file mode 100644 index 000000000..a5daeacf4 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/neuronWithEmptyComponent.nestml @@ -0,0 +1,20 @@ +package org.nest.nestml.parsing.neuronWithEmptyComponent: + + component SomaComonent: + end + + neuron SomaNeuron: + + use SomaComonent as soma + + dynamics timestep(t ms): + end + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/neuronWithUse.nestml b/src/test/resources/org/nest/nestml/parsing/neuronWithUse.nestml new file mode 100644 index 000000000..41a76adbe --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/neuronWithUse.nestml @@ -0,0 +1,22 @@ +package org.nest.nestml.parsing.neuronWithUse: + + component EmptyComponent: + + + end + + neuron AliasNeuron: + use EmptyComponent as Soma + + dynamics timestep(t ms): + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/neuronWithVars.nestml b/src/test/resources/org/nest/nestml/parsing/neuronWithVars.nestml new file mode 100644 index 000000000..9b9034044 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/neuronWithVars.nestml @@ -0,0 +1,34 @@ +package org.nest.nestml.parsing.neuronWithVars: + + neuron VarsNeuron: + state: + vM mV + x mV + abc mm + end + + parameter: + radius mm = 5 + alias diameter mm = 2 * radius + end + + internal: + y, z real = 0 + end + + dynamics timestep(t ms): + end + + function set_diameter(v mm): + radius = v / 2 + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/neuronWithVarsAndDynamics.nestml b/src/test/resources/org/nest/nestml/parsing/neuronWithVarsAndDynamics.nestml new file mode 100644 index 000000000..a7ee20fe6 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/neuronWithVarsAndDynamics.nestml @@ -0,0 +1,60 @@ +package org.nest.nestml.parsing.neuronWithVarsAndDynamics: + + import vars.VarsNeuron + + neuron DynamicsNeuron: + state: + vM mV + x mV + end + + parameter: + radius mm = 5 + alias diameter mm = 2 * radius + end + + internal: + y, z real = 0 + s real = 0 + end + + function foo(x ms): + x = x * 2 + end + + dynamics timestep (t ms): + abc real = 9.4563 + if abc > y: + vM = y * 3 + s ** 5 + elif abc == y: + nestml.Logger.info("Elif!") + else: + nestml.Logger.info("Else!") + end + x = VarsNeuron.y + while false: + nestml.Logger.warning("Impossible!") + end + i integer + for i in 0 ... 10 step 2: + nestml.Logger.info("Possible! " + i) + end + for i in 5 ... 0 step -1: + nestml.Logger.info("Possible! " + i) + end + end + + + function set_diameter(v mm): + radius = v / 2 + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end + +end diff --git a/src/test/resources/org/nest/nestml/parsing/referenceInnerComponent.nestml b/src/test/resources/org/nest/nestml/parsing/referenceInnerComponent.nestml new file mode 100644 index 000000000..70d8feee8 --- /dev/null +++ b/src/test/resources/org/nest/nestml/parsing/referenceInnerComponent.nestml @@ -0,0 +1,32 @@ +package org.nest.nestml.parsing.referenceInnerComponent: + + import units.unitless.* + + component SomaComponent: + parameter: + diameter5 integer = 5 + end + function helloWorld(): + end + end + + neuron TestSoma: + + use SomaComponent as soma + + function testHelloWorld(): + #soma.helloWorld(); + #Logger.info("Diameter = " + soma.diameter5) + end + + dynamics timestep(t ms): + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + end +end diff --git a/src/test/resources/org/nest/nestml/symboltable/iaf_neuron.nestml b/src/test/resources/org/nest/nestml/symboltable/iaf_neuron.nestml new file mode 100644 index 000000000..17a3f8788 --- /dev/null +++ b/src/test/resources/org/nest/nestml/symboltable/iaf_neuron.nestml @@ -0,0 +1,121 @@ +package org.nest.nestml.symboltable.iaf_neuron: + + component TestComponent: + end + + neuron iaf_neuron: + use TestComponent as TestRef + + state: + - y0 mV + - y1 mV + - y2 mV + - y3 mV + - r integer + # Membrane potential. + alias V_m mV = y3 + E_L + end + + parameter: + # Capacity of the membrane + C_m pF = 250 + # Membrane time constant. + tau_m ms = 10 + # Time constant of synaptic current. + tau_syn ms = 2 + # Refractory period. + t_ref ms = 2 + # Resting potential. + E_L mV = -70 + - delta_V_reset mV = -70 - E_L + -Theta mV = -55 - E_L + # External current. + I_e pA = 0 + + # some aliases + # Threshold. + alias V_th mV = Theta + E_L + # Reset value of the membrane potential. + alias V_reset mV = delta_V_reset + E_L + # invariant V_reset >= Theta + + # tests the correct scoping rules + scopeTestVar string = 0 + end + + internal: + h ms = Time.resolution() + P11 real = E ** (-h / tau_syn) + P22 real = P11 + P33 real = E ** (-h / tau_m) + P21 real = h * P11 + P30 real = 1 / C_m * (1 - P33) * tau_m + P31 real = 1 / C_m * ((P11 - P33) / (-1/tau_syn - -1/tau_m) - h * P11) / (-1/tau_m - -1/tau_syn) + P32 real = 1 / C_m * (P33 - P11) / (-1/tau_m - -1/tau_syn) + + PSCInitialValue mV = 1 * E / tau_syn + RefractoryCounts integer = Time.steps(t_ref) + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + if r == 0: # not refractory + y3 = P30 * (y0 + I_e) + P31 * y1 + P32 * y2 + P33 * y3 + else: + r = r - 1 + end + + # alpha shape PSCs + y2 = P21 * y1 + P22 * y2 + y1 = y1 * P11 + + # Apply spikes delivered in this step: The spikes arriving at T+1 have an + # immediate effect on the state of the neuron + y1 = y1 + PSCInitialValue * spikeBuffer.getSum(t) + + # threshold crossing + if y3 >= Theta: + + r = RefractoryCounts + y3 = delta_V_reset + + Spiking.emitSpike() + end + + # set new input current + y0 = currentBuffer.getSum(t); + + newVarInMethod real = 1.0 + end + + function set_V_th(v mV): + Theta = v - E_L + end + + function set_V_reset(v mV): + delta_V_reset = v - E_L + end + + function set_V_m(v mV): + y3 = v - E_L + end + + function set_V_m(v mV): + y3 = v - E_L + end + + function scopeTestingFunction(v mV): + scopeTestVar integer = 0 + if true: + scopeTestVar real = 0.0 + end + end + end +end + diff --git a/src/test/resources/org/nest/nestml/symboltable/importedComponent.nestml b/src/test/resources/org/nest/nestml/symboltable/importedComponent.nestml new file mode 100644 index 000000000..4dbc6e6d8 --- /dev/null +++ b/src/test/resources/org/nest/nestml/symboltable/importedComponent.nestml @@ -0,0 +1,9 @@ +package org.nest.nestml.symboltable.importedComponent: + + component ImportedComponent: + function testFunction(): + end + end + +end + diff --git a/src/test/resources/org/nest/nestml/symboltable/importingNeuron.nestml b/src/test/resources/org/nest/nestml/symboltable/importingNeuron.nestml new file mode 100644 index 000000000..1b7a5b89e --- /dev/null +++ b/src/test/resources/org/nest/nestml/symboltable/importingNeuron.nestml @@ -0,0 +1,32 @@ +package org.nest.nestml.symboltable.importingNeuron: + + import org.nest.nestml.symboltable.importedComponent.ImportedComponent + + neuron UsingNeuron: + use ImportedComponent as TestReference + + state: + end + + parameter: + end + + internal: + + end + + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end + + output: spike + + dynamics timestep(t ms): + TestReference.testFunction() + end + + end + +end + diff --git a/src/test/resources/org/nest/ode/solution.matrix.tmp b/src/test/resources/org/nest/ode/solution.matrix.tmp new file mode 100644 index 000000000..769f3fa5e --- /dev/null +++ b/src/test/resources/org/nest/ode/solution.matrix.tmp @@ -0,0 +1,9 @@ +P00 real = exp(-h/tau_in)# P00 +P01 real = 0# P01 +P02 real = 0# P02 +P10 real = h*exp(-h/tau_in)# P10 +P11 real = exp(-h/tau_in)# P11 +P12 real = 0# P12 +P20 real = -Tau*tau_in*(Tau*h*exp(h/Tau) + Tau*tau_in*exp(h/Tau) - Tau*tau_in*exp(h/tau_in) - h*tau_in*exp(h/Tau))*exp(-h/tau_in - h/Tau)/(C_m*(Tau**2 - 2*Tau*tau_in + tau_in**2))# P20 +P21 real = -Tau*tau_in*(exp(h/Tau) - exp(h/tau_in))*exp(-h/tau_in - h/Tau)/(C_m*(Tau - tau_in))# P21 +P22 real = exp(-h/Tau)# P22 diff --git a/src/test/resources/org/nest/spl/cocos/assignmentOfRightType.simple b/src/test/resources/org/nest/spl/cocos/assignmentOfRightType.simple new file mode 100644 index 000000000..1ad08b02b --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/assignmentOfRightType.simple @@ -0,0 +1,11 @@ +module org.nest.spl.cocos.assignmentOfRightType + +notBool real = 1 > 3 + +notReal integer = 5.5 + +notReal = 17.4 + +notInt boolean = 15 + +notBool = false \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/codeAfterEmbeddedReturningIf.simple b/src/test/resources/org/nest/spl/cocos/codeAfterEmbeddedReturningIf.simple new file mode 100644 index 000000000..2e5d33835 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/codeAfterEmbeddedReturningIf.simple @@ -0,0 +1,17 @@ +module org.nest.spl.cocos.codeAfterEmbeddedReturningIf + +x, y real +x = 1 +y = 2 +while x <= 10 : + if x > 4: + return x + else: + return y + end + + y = x*2 + x = x+1 +end + +print("x = " + x) \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/codeAfterReturn.simple b/src/test/resources/org/nest/spl/cocos/codeAfterReturn.simple new file mode 100644 index 000000000..4245d7fd8 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/codeAfterReturn.simple @@ -0,0 +1,7 @@ +module org.nest.spl.cocos.codeAfterReturn + +a integer = 15 + +return a + +a = a + 12 \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/codeAfterReturningFor.simple b/src/test/resources/org/nest/spl/cocos/codeAfterReturningFor.simple new file mode 100644 index 000000000..a3bbb41c4 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/codeAfterReturningFor.simple @@ -0,0 +1,14 @@ +module org.nest.spl.cocos.codeAfterReturningFor + +x, y real +for x in 1 ... 5 : + if x > 4: + return x + end + + y = x*2 + + return y +end + +print("x = " + x) \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/codeAfterReturningIf.simple b/src/test/resources/org/nest/spl/cocos/codeAfterReturningIf.simple new file mode 100644 index 000000000..d8a733714 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/codeAfterReturningIf.simple @@ -0,0 +1,12 @@ +module org.nest.spl.cocos.codeAfterReturningIf +x integer = 12 + +if 12 == 3: + return 13 +elif 12 <> 3: + return true +else: + return false +end + +print("x = " + x) \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/codeAfterReturningWhile.simple b/src/test/resources/org/nest/spl/cocos/codeAfterReturningWhile.simple new file mode 100644 index 000000000..4021ae2a9 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/codeAfterReturningWhile.simple @@ -0,0 +1,16 @@ +module org.nest.spl.cocos.codeAfterReturningWhile + +x, y real +x = 1 +y = 2 +while x <= 10 : + if x > 4: + return x + end + + y = x*2 + x = x+1 + return y +end + +print("x = " + x) \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/expressionsInForMatchVar.simple b/src/test/resources/org/nest/spl/cocos/expressionsInForMatchVar.simple new file mode 100644 index 000000000..2d8ba43e9 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/expressionsInForMatchVar.simple @@ -0,0 +1,6 @@ +module org.nest.spl.cocos.expressionsInForMatchVar + +i integer +for i in 2.3 ... 15.6 step 0.1: + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/funNotDefined.simple b/src/test/resources/org/nest/spl/cocos/funNotDefined.simple new file mode 100644 index 000000000..768a406c1 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/funNotDefined.simple @@ -0,0 +1,6 @@ +module org.nest.spl.cocos.funNotDefined + +bar() /* not defined */ +EmptyNeuron.bar() #TODO implement a resolving mechanism +# not defined +random(2) # not defined with parameter \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/illegalNumberExpressions.simple b/src/test/resources/org/nest/spl/cocos/illegalNumberExpressions.simple new file mode 100644 index 000000000..5248badd6 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/illegalNumberExpressions.simple @@ -0,0 +1,29 @@ +module org.nest.spl.cocos.illegalNumberExpressions + +b boolean = true + +bar real = b ** 4 # error 1: boolean cannot be used as a base + +foo integer = 3*b*6/b # error 2: boolean as a factor in devision + +foobar integer = 3.0 << 4 >> 2.0 # error 3+4: no shift operation on float values + +barfoo integer = 3.2 & 5 & 6.4 # error 5+6 no bit operation on float values + +bafoo integer = 3.2 | 5 | 6.4 # error 7+8 no bit operation on float values + +barfo integer = 3.2 ^ 5 ^ 6.4 # error 9+10 no bit operation on float values + +if foo: # 11 integer is not a valid boolean expression + +elif randomInt(): # 12 integer which is the return value of randomInt is not a valid boolean expression + +elif b < 7: # 13 cannot compare boolean to integer + +elif "abc" > "bca": # ok? 14 no comparison + +end + +# TODO refactor it into good models +if true and true: +end diff --git a/src/test/resources/org/nest/spl/cocos/illegalStringExpressions.simple b/src/test/resources/org/nest/spl/cocos/illegalStringExpressions.simple new file mode 100644 index 000000000..ee286979f --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/illegalStringExpressions.simple @@ -0,0 +1,17 @@ +module org.nest.spl.cocos.illegalStringExpressions +# no error +bar string = (5) + "Hallo Welt!" +# error +foo string = "Hello" * 5 +# error +#foobar string = "Hello" | 6 +# error +barfoo string = "Hello" ** 3 +# error +barbar string = "" + 3 - "!" + +i void +# error +foofoo string = "" + i + +correct string = "Hello " + (3 * 4.0)**6 + " " + "Welt!" diff --git a/src/test/resources/org/nest/spl/cocos/illegalVarInFor.simple b/src/test/resources/org/nest/spl/cocos/illegalVarInFor.simple new file mode 100644 index 000000000..37ca04f4c --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/illegalVarInFor.simple @@ -0,0 +1,5 @@ +module org.nest.spl.cocos.illegalVarInFor +x boolean +for x in 1 ... 5 : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/multipleSigns.simple b/src/test/resources/org/nest/spl/cocos/multipleSigns.simple new file mode 100644 index 000000000..903bfe5d8 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/multipleSigns.simple @@ -0,0 +1,9 @@ +module org.nest.spl.cocos.multipleSigns + +f real = +-2 + +b real = +++2 + +c real = --2 + +d real = ~~2 \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/varDefinedMultipleTimes.simple b/src/test/resources/org/nest/spl/cocos/varDefinedMultipleTimes.simple new file mode 100644 index 000000000..5cdea44dd --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/varDefinedMultipleTimes.simple @@ -0,0 +1,18 @@ +module org.nest.spl.cocos.varDefinedMultipleTimes +z real +if 1>0 : + x real + z real + x real +end + +x real +while true: + z real +end + +t real +h integer +for h in 0 ... 10: + t integer +end diff --git a/src/test/resources/org/nest/spl/cocos/varNotDefined.simple b/src/test/resources/org/nest/spl/cocos/varNotDefined.simple new file mode 100644 index 000000000..306a9fe68 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/varNotDefined.simple @@ -0,0 +1,6 @@ +module org.nest.spl.cocos.varNotDefined +x real = 3 * y + +for a in 1 ... 10 step 1: +# blaa +end diff --git a/src/test/resources/org/nest/spl/cocos/varNotDefinedBeforeUse.simple b/src/test/resources/org/nest/spl/cocos/varNotDefinedBeforeUse.simple new file mode 100644 index 000000000..5772c8058 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/varNotDefinedBeforeUse.simple @@ -0,0 +1,13 @@ +module org.nest.spl.cocos.varNotDefinedBeforeUse +y real = 5 * x + +x = 13 + +for x in 1 ... 10 step 1: +# blaa +end + +x = 2; + +x real = 2 * x + diff --git a/src/test/resources/org/nest/spl/cocos/varNotDefinedInTest.simple b/src/test/resources/org/nest/spl/cocos/varNotDefinedInTest.simple new file mode 100644 index 000000000..5b9c409c6 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/varNotDefinedInTest.simple @@ -0,0 +1,7 @@ +module org.nest.spl.cocos.varNotDefinedInTest + +if x: +end + +while y: +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/cocos/varWithTypeName.simple b/src/test/resources/org/nest/spl/cocos/varWithTypeName.simple new file mode 100644 index 000000000..fc83e9c53 --- /dev/null +++ b/src/test/resources/org/nest/spl/cocos/varWithTypeName.simple @@ -0,0 +1,3 @@ +module org.nest.spl.cocos.varWithTypeName +real real = 15 +v integer = 11 \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/decl.simple b/src/test/resources/org/nest/spl/codegeneration/decl.simple new file mode 100644 index 000000000..98a805689 --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/decl.simple @@ -0,0 +1,46 @@ +module org.nest.spl.parsing.decl + +wahr1, wahr2 boolean = true +intVar integer = 1 +realDeclration real = 1+2/3+(intVar) +intVar = 2 + +if 2 < 3 : +elif 4>6 : +else: +end + +if 4 < 5 : + +elif wahr1 : + +else : + +end + +x, y real +for x in 1 ... 5 : + if x > 4: + return x + end + + y = x*2 +end + +# Tests how the function call generation is handled +println(); +pow(x2, y2) + +Logger.info("" + 3+4**6) + +x2, y2 real +x2 = 1 +y2 = 2 +while x2 <= 10 : + if x2 > 4: + return x2 + end + + y2 = x2*2 + x2 = x2+1 +end diff --git a/src/test/resources/org/nest/spl/codegeneration/declAndAssign.simple b/src/test/resources/org/nest/spl/codegeneration/declAndAssign.simple new file mode 100644 index 000000000..5c62d89cf --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/declAndAssign.simple @@ -0,0 +1,3 @@ +module org.nest.spl.parsing.declAndAssign + +x real = 4 \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/emptyBlock.simple b/src/test/resources/org/nest/spl/codegeneration/emptyBlock.simple new file mode 100644 index 000000000..964c40006 --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/emptyBlock.simple @@ -0,0 +1,3 @@ +module org.nest.spl.parsing.emptyBlock + + diff --git a/src/test/resources/org/nest/spl/codegeneration/funCall.simple b/src/test/resources/org/nest/spl/codegeneration/funCall.simple new file mode 100644 index 000000000..1547c827e --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/funCall.simple @@ -0,0 +1,8 @@ +module org.nest.spl.parsing.funCall + +a, b real = 0 + +println(); +pow(a, b) + +Logger.info("" + 3+4**6) \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/mathExpressions.simple b/src/test/resources/org/nest/spl/codegeneration/mathExpressions.simple new file mode 100644 index 000000000..e066074fd --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/mathExpressions.simple @@ -0,0 +1,7 @@ +module org.nest.spl.mathExpression + +a integer = 2 + +# TODO should work print("" + (2+3-4*5/6.** -random()) % 0x23p2) +print("" + (2+3-4*5/6 - random()) % 0x23p2) +print("" + ((( a | (-3+6%2) & ~(0x4fa) | 0x23 ^ 12) >> 2) << 2)) diff --git a/src/test/resources/org/nest/spl/codegeneration/returnInFor.simple b/src/test/resources/org/nest/spl/codegeneration/returnInFor.simple new file mode 100644 index 000000000..0f5abe2ec --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/returnInFor.simple @@ -0,0 +1,10 @@ +module org.nest.spl.parsing.returnInFor + +x, y real +for x in 1 ... 5 : + if x > 4: + return x + end + + y = x*2 +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/returnInWhile.simple b/src/test/resources/org/nest/spl/codegeneration/returnInWhile.simple new file mode 100644 index 000000000..c36fd5b4f --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/returnInWhile.simple @@ -0,0 +1,13 @@ +module org.nest.spl.parsing.returnInWhile + +x, y real +x = 1 +y = 2 +while x <= 10 : + if x > 4: + return x + end + + y = x*2 + x = x+1 +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/simpleFor.simple b/src/test/resources/org/nest/spl/codegeneration/simpleFor.simple new file mode 100644 index 000000000..4562fdf78 --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/simpleFor.simple @@ -0,0 +1,17 @@ +module org.nest.spl.parsing.simpleFor + +x real +for x in 1 ... 5 : + +end + +for x in 1 ... 5 : +end + +for x in 1 ... 5 step 2: + +end + +for x in 1 ... -5.6 step 0.1: + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/simpleIf.simple b/src/test/resources/org/nest/spl/codegeneration/simpleIf.simple new file mode 100644 index 000000000..247b117df --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/simpleIf.simple @@ -0,0 +1,7 @@ +module org.nest.spl.parsing.simpleIf +if 2 < 3 : +end + +if 2 < 3 : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/simpleIfElif.simple b/src/test/resources/org/nest/spl/codegeneration/simpleIfElif.simple new file mode 100644 index 000000000..55bbac965 --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/simpleIfElif.simple @@ -0,0 +1,11 @@ +module org.nest.spl.parsing.simpleIfElif + +if 2 < 3 : +elif 4 >= 6 : +end + +if 2 <= 3 : + +elif 4<>6 : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/simpleIfElifElse.simple b/src/test/resources/org/nest/spl/codegeneration/simpleIfElifElse.simple new file mode 100644 index 000000000..59780e20c --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/simpleIfElifElse.simple @@ -0,0 +1,13 @@ +module org.nest.spl.parsing.simpleIfElifElse +if 2 < 3 : +elif 4>6 : +else: +end + +if 2 < 3 : + +elif 4>6 : + +else : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/simpleIfElse.simple b/src/test/resources/org/nest/spl/codegeneration/simpleIfElse.simple new file mode 100644 index 000000000..99e814034 --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/simpleIfElse.simple @@ -0,0 +1,10 @@ +module org.nest.spl.parsing.simpleIfElse +if 2 >= 3 : +else : +end + +if 2 != 3 : + +else : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/simpleReturns.simple b/src/test/resources/org/nest/spl/codegeneration/simpleReturns.simple new file mode 100644 index 000000000..75447dd12 --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/simpleReturns.simple @@ -0,0 +1,26 @@ +module org.nest.spl.parsing.simpleReturns + +if true: + return +end + +if false: + return 3 +end + + +if 3 >= 6: + print("Hello!") +else: + return 15 +end + +if 4 <> 12: + return 12 +elif 4 == 12: + print("What just happend?") +else: + return false +end + +return true \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/codegeneration/simpleWhile.simple b/src/test/resources/org/nest/spl/codegeneration/simpleWhile.simple new file mode 100644 index 000000000..548e52150 --- /dev/null +++ b/src/test/resources/org/nest/spl/codegeneration/simpleWhile.simple @@ -0,0 +1,8 @@ +module org.nest.spl.parsing.simpleWhile + +while true: + +end + +while false: +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/complexExpressions.simple b/src/test/resources/org/nest/spl/parsing/complexExpressions.simple new file mode 100644 index 000000000..1e4c07587 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/complexExpressions.simple @@ -0,0 +1,8 @@ +module org.nest.spl.parsing.complexExpressions +C_m pF = 250.0 +tau_m ms = 10.0 +tau_syn_ex ms = 2.0 +#P11ex real = E ** (-h / tau_syn_ex) TODO +# TODO P21ex real = tau_m / (C_m * (1.0 - tau_m / tau_syn_ex)) * P11ex * (1.0 - pow(E, (h * (1.0 / tau_syn_ex - 1.0 / tau_m)))) +t_ref ms = 2 s +RefractoryCounts integer = Time.steps(t_ref) diff --git a/src/test/resources/org/nest/spl/parsing/complexExpressionsWithOde.simple b/src/test/resources/org/nest/spl/parsing/complexExpressionsWithOde.simple new file mode 100644 index 000000000..829bd7a9f --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/complexExpressionsWithOde.simple @@ -0,0 +1,13 @@ +module org.nest.spl.parsing.complexExpressionsWithOde +tau_in real +t real +C_m real +I real +w real +V real +Tau real + +ODE: + I === w * (E/tau_in) * t * exp(-1/tau_in*t) + d/dt V === -1/Tau * V + 1/C_m*I +end diff --git a/src/test/resources/org/nest/spl/parsing/decl.simple b/src/test/resources/org/nest/spl/parsing/decl.simple new file mode 100644 index 000000000..306a08064 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/decl.simple @@ -0,0 +1,9 @@ +module org.nest.spl.parsing.decl + +wahr boolean = true + +x real = 3; y real = 4; z real = 16.8 + +f real = -2e12 + +a, b, c real diff --git a/src/test/resources/org/nest/spl/parsing/declAndAssign.simple b/src/test/resources/org/nest/spl/parsing/declAndAssign.simple new file mode 100644 index 000000000..e5b67e330 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/declAndAssign.simple @@ -0,0 +1,5 @@ +module org.nest.spl.parsing.declAndAssign + +x real = 4 + +org.nest.spl.parsing.declAndAssign.x = 5 diff --git a/src/test/resources/org/nest/spl/parsing/emptyBlock.simple b/src/test/resources/org/nest/spl/parsing/emptyBlock.simple new file mode 100644 index 000000000..964c40006 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/emptyBlock.simple @@ -0,0 +1,3 @@ +module org.nest.spl.parsing.emptyBlock + + diff --git a/src/test/resources/org/nest/spl/parsing/funCall.simple b/src/test/resources/org/nest/spl/parsing/funCall.simple new file mode 100644 index 000000000..5b38b4a6d --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/funCall.simple @@ -0,0 +1,7 @@ +module org.nest.spl.parsing.funCall + +a, b real = 0 + +println(); pow(a, b) + +Logger.info("" + 3+4*6) # TODO Logger.info("" + 3+4**6) should work diff --git a/src/test/resources/org/nest/spl/parsing/mathExpressions.simple b/src/test/resources/org/nest/spl/parsing/mathExpressions.simple new file mode 100644 index 000000000..88a6d2de4 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/mathExpressions.simple @@ -0,0 +1,8 @@ +module org.nest.spl.mathExpression + +a integer = 2 + +# TODO should work print("" + (2+3-4*5/6.** -random()) % 0x23p2) +# print("" + (2+3-4*5/6)) + +# print("" + ((( a | (-3+6%2) & ~(0x4fa) | 0x23 ^ 12) >> 2) << 2)) diff --git a/src/test/resources/org/nest/spl/parsing/modelContainingAllLanguageElements.simple b/src/test/resources/org/nest/spl/parsing/modelContainingAllLanguageElements.simple new file mode 100644 index 000000000..851f38de0 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/modelContainingAllLanguageElements.simple @@ -0,0 +1,100 @@ +module org.nest.spl.parsing.decl + +x real = -3.0 +y boolean = true +z integer = 16 + +pow(x, -1) + +print("" + 1) + + +x1, y1 real +for x1 in 1 ... 5 : + if x1 > 4: + return x1 + end + + y1 = x1*2 +end + +x2, y2 real +while x2 <= 10 : + if x2 > 4: + return x2 + end + + y2 = x2*2 + x2 = x2+1 +end + + +for x in 1 ... 5 : + if x2 > 4: + return x2 + end +end + +for x in 1 ... 5 : +end + +for x in 1 ... 5 step 2: + +end + +for x in 1 ... -5.6 step 0.1: + +end + +if 2 < 3 : + aa, bb integer = 1 + aa = bb +elif 4>6 : +else: +end + +if 2 < 3 : + +elif 4>6 : + +else : + +end + +if true: + return +end + +if false: + return 3 +end + + +if 3 >= 6: + cc, dd integer = 1 + cc = dd + print("Hello!") +else: + return 15 +end + +if 4 <> 12: + + return 12 +elif 4 == 12: + print("What just happend?") +else: + return false +end + +return true + +while true: + +end + +while false: +end + +zz real = pow(x, -1) + diff --git a/src/test/resources/org/nest/spl/parsing/returnInFor.simple b/src/test/resources/org/nest/spl/parsing/returnInFor.simple new file mode 100644 index 000000000..0f5abe2ec --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/returnInFor.simple @@ -0,0 +1,10 @@ +module org.nest.spl.parsing.returnInFor + +x, y real +for x in 1 ... 5 : + if x > 4: + return x + end + + y = x*2 +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/returnInWhile.simple b/src/test/resources/org/nest/spl/parsing/returnInWhile.simple new file mode 100644 index 000000000..c36fd5b4f --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/returnInWhile.simple @@ -0,0 +1,13 @@ +module org.nest.spl.parsing.returnInWhile + +x, y real +x = 1 +y = 2 +while x <= 10 : + if x > 4: + return x + end + + y = x*2 + x = x+1 +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/simpleFor.simple b/src/test/resources/org/nest/spl/parsing/simpleFor.simple new file mode 100644 index 000000000..4562fdf78 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/simpleFor.simple @@ -0,0 +1,17 @@ +module org.nest.spl.parsing.simpleFor + +x real +for x in 1 ... 5 : + +end + +for x in 1 ... 5 : +end + +for x in 1 ... 5 step 2: + +end + +for x in 1 ... -5.6 step 0.1: + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/simpleIf.simple b/src/test/resources/org/nest/spl/parsing/simpleIf.simple new file mode 100644 index 000000000..247b117df --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/simpleIf.simple @@ -0,0 +1,7 @@ +module org.nest.spl.parsing.simpleIf +if 2 < 3 : +end + +if 2 < 3 : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/simpleIfElif.simple b/src/test/resources/org/nest/spl/parsing/simpleIfElif.simple new file mode 100644 index 000000000..55bbac965 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/simpleIfElif.simple @@ -0,0 +1,11 @@ +module org.nest.spl.parsing.simpleIfElif + +if 2 < 3 : +elif 4 >= 6 : +end + +if 2 <= 3 : + +elif 4<>6 : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/simpleIfElifElse.simple b/src/test/resources/org/nest/spl/parsing/simpleIfElifElse.simple new file mode 100644 index 000000000..59780e20c --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/simpleIfElifElse.simple @@ -0,0 +1,13 @@ +module org.nest.spl.parsing.simpleIfElifElse +if 2 < 3 : +elif 4>6 : +else: +end + +if 2 < 3 : + +elif 4>6 : + +else : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/simpleIfElse.simple b/src/test/resources/org/nest/spl/parsing/simpleIfElse.simple new file mode 100644 index 000000000..99e814034 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/simpleIfElse.simple @@ -0,0 +1,10 @@ +module org.nest.spl.parsing.simpleIfElse +if 2 >= 3 : +else : +end + +if 2 != 3 : + +else : + +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/simpleReturns.simple b/src/test/resources/org/nest/spl/parsing/simpleReturns.simple new file mode 100644 index 000000000..75447dd12 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/simpleReturns.simple @@ -0,0 +1,26 @@ +module org.nest.spl.parsing.simpleReturns + +if true: + return +end + +if false: + return 3 +end + + +if 3 >= 6: + print("Hello!") +else: + return 15 +end + +if 4 <> 12: + return 12 +elif 4 == 12: + print("What just happend?") +else: + return false +end + +return true \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/simpleWhile.simple b/src/test/resources/org/nest/spl/parsing/simpleWhile.simple new file mode 100644 index 000000000..548e52150 --- /dev/null +++ b/src/test/resources/org/nest/spl/parsing/simpleWhile.simple @@ -0,0 +1,8 @@ +module org.nest.spl.parsing.simpleWhile + +while true: + +end + +while false: +end \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/symboltable/decl.simple b/src/test/resources/org/nest/spl/symboltable/decl.simple new file mode 100644 index 000000000..a3d22cf1f --- /dev/null +++ b/src/test/resources/org/nest/spl/symboltable/decl.simple @@ -0,0 +1,12 @@ +module org.nest.spl.symboltable.decl + +decl real = 0 + +if true: + decl integer = 0 +end + +println(); +pow(a, b) + +Logger.info("" + 3+4**6) diff --git a/src/test/resources/org/nest/spl/symboltable/mathExpressions.simple b/src/test/resources/org/nest/spl/symboltable/mathExpressions.simple new file mode 100644 index 000000000..512a9e3a4 --- /dev/null +++ b/src/test/resources/org/nest/spl/symboltable/mathExpressions.simple @@ -0,0 +1,21 @@ +module org.nest.spl.symboltable.mathExpression +a real = ((( 1.0 | (-3+6%2) & ~(0x4fa) | 0x23 ^ 12) >> 2) << 2) +b real = 1.0 +c = 1 +d = "test" +e = 1 + 1 +f = 1 + 1.0 +g = 1.0 + 1 +h = 1 + 1 + 1 + 1 + 1.0 +i = ~1 +j = ~b +k = ~d +l = 1 ** 2.5 +m = 1 ** d +o = 1 - 1 +p = 1 - 1.0 +r = 1 - d +s = true +h ms +tau_syn_ex ms = 2.0 +P11ex real = pow(1.0, 1.0) # TODO **,h / pow(E, (-h / tau_syn_ex))