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 extends Scope> 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 extends Scope> 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 extends Scope> 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 extends Scope> 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 extends Scope> 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 extends Scope> 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 extends Scope> 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 extends Scope> 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 extends Scope> 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 extends Symbol> 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}_;
+#list>
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 );
+#if>
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>
+ <#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 );
+ }
+ #if>
+ #if>
+#if>
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
+ #if>
+ ;
+}
+<#else>
+set_${var.getName()}(
+ <#if ast.getDeclaration().getExpr().isPresent()>
+ ${tc.include("org.nest.spl.expr.Expr", ast.getDeclaration().getExpr().get())}
+ <#else>
+ 0
+ #if> );
+#if>
+
+
+
+#list>
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)}
+#if>
\ 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()}
+ #if>
+ <#assign start=",">
+#list>
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>
+ <#if !var.isAlias()>
+ inline void set_${var.getName()}(const ${declarations.getType(ast)} v) {
+ ${declarations.getAliasOrigin(ast)}.set_${var.getName()}( v ) ;
+ }
+ #if>
+
+#list>
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()});
+}
+#if>
+<#else>
+// do not update ${var.getName()}, since it is hidden
+#if>
+
+#list>
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}
+ #if>
+
+
+#list>
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()}();
+#list>
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 ; }
+#list>
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
+#if>
+
+#list>
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 \
+#list>
+ # 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"
+#list>
+// -- 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(".", "_")}");
+
+ #list>
+
+ /* 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)}
+ #list>
+ }
+}
+
+/* ----------------------------------------------------------------
+* 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=",">
+#list>
+{}
+
+<#assign start="">
+${nspPrefix}::${simpleNeuronName}::State_::State_():
+<#list body.getNonAliasStates() as state>
+ ${start} ${tc.include("org.nest.nestml.function.MemberInitialization", state)}
+ <#assign start=",">
+#list>
+{}
+
+/* ----------------------------------------------------------------
+* 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)}
+ #list>
+}
+
+void
+${nspPrefix}::${simpleNeuronName}::Parameters_::set(const DictionaryDatum& d)
+{
+ <#list body.getNonAliasParameters() as parameter>
+ ${tc.include("org.nest.nestml.function.ReadFromDictionary", parameter)}
+ #list>
+
+ <#list body.getNonAliasParameters() as parameter>
+ <#list parameter.getInvariants() as invariant>
+ ${tc.include("org.nest.nestml.function.Invariant", invariant)}
+ #list>
+ #list>
+
+}
+
+void
+${nspPrefix}::${simpleNeuronName}::State_::get(DictionaryDatum &d) const
+{
+ <#list body.getNonAliasStates() as state>
+ ${tc.include("org.nest.nestml.function.WriteInDictionary", state)}
+ #list>
+}
+
+void
+${nspPrefix}::${simpleNeuronName}::State_::set(const DictionaryDatum& d)
+{
+ <#list body.getNonAliasStates() as state>
+ ${tc.include("org.nest.nestml.function.ReadFromDictionary", state)}
+ #list>
+}
+
+${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)}
+ #list>
+ 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;
+ }
+ #if>
+
+ #list>
+
+}
+
+/* ----------------------------------------------------------------
+* 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)}
+ #list>
+}
+
+// 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())}
+}
+#list>
+
+<#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>
+
+<#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())}
+}
+#if>
+
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} {
+#list>
+
+/* BeginDocumentation
+Name: ${simpleNeuronName} .
+
+Description:
+Empty. TODO
+
+Parameters:
+
+Remarks:
+Empty
+
+References:
+Empty
+
+Sends: ${outputEvent}
+
+Receives: <#if isSpikeInput>Spike, #if><#if isCurrentInput>Current, #if>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);
+ #if>
+
+ /**
+ * @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>
+ <#if isCurrentInput>
+ void handle(nest::CurrentEvent &); //! accept input current
+ #if>
+ void handle(nest::DataLoggingRequest &);//! allow recording with multimeter
+
+ <#if isSpikeInput>
+ nest::port handles_test_event(nest::SpikeEvent&, nest::port);
+ #if>
+ <#if isCurrentInput>
+ nest::port handles_test_event(nest::CurrentEvent&, nest::port);
+ #if>
+ 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>
+
+ <#list body.getStates() as state>
+ ${tc.include("org.nest.nestml.function.MemberVariableGetterSetter", state)}
+ #list>
+
+ <#list body.getParameters() as parameter>
+ ${tc.include("org.nest.nestml.function.MemberVariableGetterSetter", parameter)}
+ #list>
+
+ <#list body.getInternals() as internal>
+ ${tc.include("org.nest.nestml.function.MemberVariableGetterSetter", internal)}
+ #list>
+
+ <#list body.getInputLines() as inputLine>
+ ${bufferHelper.printBufferGetter(inputLine, false)};
+ #list>
+
+ 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())}
+ #list>
+ 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)}
+ #list>
+ };
+
+ /**
+ * 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())}
+ #list>
+ /** 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>
+ <#list body.getNonAliasInternals() as internal>
+ ${tc.include("org.nest.nestml.function.StructGetterSetter", internal)}
+ #list>
+ };
+
+ /**
+ * 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)}
+ #list>
+
+ /** Logger for all analog data */
+ nest::UniversalDataLogger<${simpleNeuronName}> logger_;
+
+ <#list body.getInputLines() as inputLine>
+ ${bufferHelper.printBufferDeclaration(inputLine)};
+ #list>
+
+ <#list body.getInputLines() as inputLine>
+ ${bufferHelper.printBufferTypesVariables(inputLine)};
+ #list>
+ };
+
+ /**
+ * @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} */
+#list>
+
+
+<#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>
+
+
+<#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>
+
+<#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;
+}
+#if>
+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)}
+ #list>
+ S_.get(d);
+
+ <#list body.getAliasStates() as state>
+ ${tc.include("org.nest.nestml.function.WriteInDictionary", state)}
+ #list>
+ (*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>
+ <#list body.getAliasStates() as state>
+ ${tc.include("org.nest.nestml.function.SetOldAliasState", state)}
+ #list>
+
+ 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)}
+ #list>
+
+ 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)}
+ #list>
+ // '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 = ",">#list> = <#assign separator = ""> symbols('<#list variables as variable> ${separator} ${variable} <#assign separator = ","> #list>')
+#compress>
+
+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())});
+ #if>
+
+ }
+ <#else>
+ ${assignmentHelper.printSetterName(ast)}(${tc.include("org.nest.spl.expr.Expr", ast.getExpr())});
+ #if>
+
+#if>
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)}
+#list>
\ 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())}
+#if>
\ 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())}
+ #if>;
+#list>
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())}
+#list>
+<#if ast.getELSE_Clause().isPresent()>
+}
+else {
+${tc.include("org.nest.spl.Block", ast.getELSE_Clause().get().getBlock())}
+#if>
+} /* 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 ;
+#if>
\ 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)}
+#list>
\ 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())}
+#if>
\ 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())}
+#if>
\ 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