diff --git a/models/ht_neuron.nestml b/models/ht_neuron.nestml index d47775027..f6555a071 100644 --- a/models/ht_neuron.nestml +++ b/models/ht_neuron.nestml @@ -81,7 +81,7 @@ neuron ht_neuron_nestml: G_NMDA nS G_GABA_A nS G_GABA_B nS - IKNa_D pA + IKNa_D pA = KNa_D_EQ IT_m pA IT_h pA Ih_m pA @@ -97,7 +97,7 @@ neuron ht_neuron_nestml: # The spike current is only activate immediately after a spike. # TODO const double_t I_spike = node.S_.g_spike_ ? -( V - node.P_.E_K ) / node.P_.Tau_spike : 0; - alias I_spike mV = 0 + alias I_spike mV = (g_spike) ? -( V_m - E_K ) / Tau_spike : 0; # intrinsic currents # I_Na(p), m_inf^3 according to Compte et al, J Neurophysiol 2003 89:2707 @@ -188,7 +188,7 @@ neuron ht_neuron_nestml: T_E_rev mV = 0.0mV h_g_peak real = 1.0 h_E_rev mV = -40.0mV - KNa_D_EQ real = 0.001; + KNa_D_EQ pA = 0.001pA; end internal: diff --git a/pom.xml b/pom.xml index 560581c3f..dbd1addbf 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ nestml nestml-core - 0.1.1-SNAPSHOT + 0.1.1 diff --git a/src/main/grammars/org/nest/Commons.mc4 b/src/main/grammars/org/nest/Commons.mc4 index fff05b53c..fa7c41078 100644 --- a/src/main/grammars/org/nest/Commons.mc4 +++ b/src/main/grammars/org/nest/Commons.mc4 @@ -50,6 +50,7 @@ grammar Commons extends de.monticore.types.Types { | logicalNot:["not"] Expr | left:Expr logicalAnd:["and"] right:Expr | left:Expr logicalOr:["or"] right:Expr + | condition:Expr "?" ifTure:Expr ":" ifNot:Expr | FunctionCall | BooleanLiteral // true & false; | NESTMLNumericLiteral diff --git a/src/main/java/org/nest/codegeneration/converters/GSLReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/GSLReferenceConverter.java index d04227b26..cb08f0396 100644 --- a/src/main/java/org/nest/codegeneration/converters/GSLReferenceConverter.java +++ b/src/main/java/org/nest/codegeneration/converters/GSLReferenceConverter.java @@ -24,8 +24,13 @@ public class GSLReferenceConverter implements IReferenceConverter { private static final String INDEX_VARIABLE_POSTFIX = "_INDEX"; + private final boolean isUseUpperBound; private static final Double MAXIMAL_EXPONENT = 10.0; + public GSLReferenceConverter() { + isUseUpperBound = false; // TODO make it parametrizable + } + @Override public String convertBinaryOperator(String binaryOperator) { if (binaryOperator.equals("**")) { @@ -39,8 +44,17 @@ public String convertBinaryOperator(String binaryOperator) { @Override public String convertFunctionCall(final ASTFunctionCall astFunctionCall) { final String functionName = astFunctionCall.getCalleeName(); + if ("exp".equals(functionName)) { - return "std::exp(std::min(%s, " + MAXIMAL_EXPONENT + "))"; + + if (isUseUpperBound) { + return "std::exp(std::min(%s, " + MAXIMAL_EXPONENT + "))"; + } + else { + return "std::exp(%s)"; + + } + } if ("pow".equals(functionName)) { return "pow(%s)"; @@ -56,8 +70,7 @@ public String convertNameReference(final ASTVariable astVariable) { final Scope scope = astVariable.getEnclosingScope().get(); final VariableSymbol variableSymbol = VariableSymbol.resolve(convertDevrivativeNameToSimpleName(astVariable), scope); - if (variableSymbol.getBlockType().equals(VariableSymbol.BlockType.STATE) && - !variableSymbol.isAlias()) { + if (variableSymbol.definedByODE()) { return "y[" + variableName + INDEX_VARIABLE_POSTFIX + "]"; } else { diff --git a/src/main/java/org/nest/nestml/_ast/ASTBody.java b/src/main/java/org/nest/nestml/_ast/ASTBody.java index 9e30be877..71f52ae1a 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTBody.java +++ b/src/main/java/org/nest/nestml/_ast/ASTBody.java @@ -136,6 +136,14 @@ public List getEquations() { } } + @SuppressWarnings("unused") // used in freemarker templates + public List variablesDefinedByODE() { + return getStateSymbols() + .stream() + .filter(VariableSymbol::definedByODE) + .collect(toList()); + } + private Optional findEquationsBlock() { final Optional equations = this.getBodyElements() .stream() @@ -161,7 +169,12 @@ private String printBlockComment(final Optional block) { // STATE variables handling public List getStateSymbols() { - return getVariableSymbols(getDeclarationsFromBlock(ASTVar_Block::isState), getEnclosingScope().get()); + return this.getEnclosingScope().get().resolveLocally(VariableSymbol.KIND) + .stream() + .map(stateSymbol -> (VariableSymbol) stateSymbol) + .filter(VariableSymbol::isState) + .collect(toList()); + } public List getStateAliasSymbols() { diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java index 4bb8c4873..e830fe8ae 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java @@ -164,8 +164,8 @@ private void addDerivedVariable(final ASTEquation ode) { private void assignOdeToVariables(final ASTBody astBody) { if (astBody.getODEBlock().isPresent()) { - astBody.getODEBlock().get().getODEs() - .stream() + astBody.getODEBlock().get() + .getODEs() .forEach(this::addOdeToVariable); } @@ -174,8 +174,8 @@ private void assignOdeToVariables(final ASTBody astBody) { private void addOdeToVariable(final ASTEquation ode) { checkState(this.currentScope().isPresent()); - final Scope scope = currentScope().get(); + final String variableName = convertToSimpleName(ode.getLhs()); final Optional stateVariable = scope.resolve(variableName, VariableSymbol.KIND); diff --git a/src/main/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinter.java b/src/main/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinter.java index 8888af1e2..47e5fba3b 100644 --- a/src/main/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinter.java +++ b/src/main/java/org/nest/spl/prettyprinter/ExpressionsPrettyPrinter.java @@ -133,8 +133,14 @@ else if (expr.isLogicalOr() || expr.isLogicalAnd()) { else if (expr.isLogicalNot()) { return "not " + print(expr.getExpr().get()); } + else if (expr.getCondition().isPresent()) { + final String condition = print(expr.getCondition().get()); + final String ifTrue = print(expr.getIfTure().get()); // guaranteed by grammar + final String ifNot = print(expr.getIfNot().get()); // guaranteed by grammar + return "(" + condition + ")?(" + ifTrue + "):(" + ifNot + ")"; + } - final String errorMsg = "Unsupported grammar element. PrettyPrinter must be fixed " + expr.get_SourcePositionStart() + "}"; + final String errorMsg = "Unsupported grammar element: PrettyPrinter must be fixed " + expr.get_SourcePositionStart(); throw new RuntimeException(errorMsg); } diff --git a/src/main/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculator.java b/src/main/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculator.java index e0d8cc1e9..9c12cdc11 100644 --- a/src/main/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculator.java +++ b/src/main/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculator.java @@ -396,6 +396,30 @@ else if (expr.isLogicalAnd() || expr.isLogicalOr()) { } } + else if (expr.getCondition().isPresent()) { + + final Either condition = computeType(expr.getCondition().get()); + final Either ifTrue = computeType(expr.getIfTure().get()); // guaranteed by the grammar + final Either ifNot = computeType(expr.getIfNot().get()); // guaranteed by the grammar + + if (condition.isError()) { + return condition; + } + if (ifTrue.isError()) { + return ifTrue; + } + + if (ifNot.isError()) { + return ifNot; + } + if (!condition.getValue().equals(getBooleanType())) { + return Either.error("The ternary operator condition must be a boolean: " + ASTUtils.toString(expr) + ". And not a: " + condition.getValue()); + } + if (!isCompatible(ifTrue.getValue(), (ifNot.getValue()))) { + return Either.error("The ternary operator results must be of the same type: " + ASTUtils.toString(expr) + ". And not: " + ifTrue.getValue() + " and " + ifNot.getValue()); + } + return ifTrue; + } final String errorMsg = "This operation for expressions is not supported yet."; diff --git a/src/main/resources/org/nest/nestml/function/GSLDifferentiationFunction.ftl b/src/main/resources/org/nest/nestml/function/GSLDifferentiationFunction.ftl index 69a153aa3..cffdaa293 100644 --- a/src/main/resources/org/nest/nestml/function/GSLDifferentiationFunction.ftl +++ b/src/main/resources/org/nest/nestml/function/GSLDifferentiationFunction.ftl @@ -6,9 +6,10 @@ <#assign ODEs = ast.getEquations()> <#assign index = 0> <#assign indexPostfix = "INDEX"> -<#list ast.getStateNonAliasSymbols() as stateVariable> -const int ${stateVariable.getName()}_${indexPostfix} = ${index}; - <#assign index = index + 1> + +<#list ast.variablesDefinedByODE() as odeVariable> +const int ${odeVariable.getName()}_${indexPostfix} = ${index}; +<#assign index = index + 1> extern "C" inline int diff --git a/src/main/resources/org/nest/spl/ODEDeclaration.ftl b/src/main/resources/org/nest/spl/ODEDeclaration.ftl index 8d0b17e45..1013b7872 100644 --- a/src/main/resources/org/nest/spl/ODEDeclaration.ftl +++ b/src/main/resources/org/nest/spl/ODEDeclaration.ftl @@ -8,23 +8,21 @@ @param stateSize number of the step variables @result TODO --> -<#assign stateSize = body.getStateNonAliasSymbols()?size> +<#assign stateSize = body.getEquations()?size> <#assign indexPostfix = "INDEX"> double step_ = nest::Time::get_resolution().get_ms(); double IntegrationStep_ = nest::Time::get_resolution().get_ms(); double t = 0; -while ( t < step_ ) -{ - double stateVector[${stateSize}]; <#assign index = 0> -<#list body.getStateNonAliasSymbols() as stateVariable> - stateVector[${stateVariable.getName()}_${indexPostfix}] = S_.${stateVariable.getName()}; +<#list body.variablesDefinedByODE() as odeVariable> + stateVector[${odeVariable.getName()}_${indexPostfix}] = S_.${odeVariable.getName()}; <#assign index = index + 1> - +while ( t < step_ ) +{ const int status = gsl_odeiv_evolve_apply( B_.e_, B_.c_, B_.s_, @@ -34,8 +32,9 @@ double stateVector[${stateSize}]; &IntegrationStep_, // integration step size stateVector ); // neuronal state <#assign index = 0> -<#list body.getStateNonAliasSymbols() as stateVariable> - S_.${stateVariable.getName()} = stateVector[${stateVariable.getName()}_${indexPostfix}]; + +} +<#list body.variablesDefinedByODE() as odeVariable> + S_.${odeVariable.getName()} = stateVector[${odeVariable.getName()}_${indexPostfix}]; <#assign index = index + 1> - -} \ No newline at end of file + \ No newline at end of file diff --git a/src/test/java/org/nest/nestml/symboltable/NESTMLSymbolTableTest.java b/src/test/java/org/nest/nestml/symboltable/NESTMLSymbolTableTest.java index 8daac45d5..9196fe29d 100644 --- a/src/test/java/org/nest/nestml/symboltable/NESTMLSymbolTableTest.java +++ b/src/test/java/org/nest/nestml/symboltable/NESTMLSymbolTableTest.java @@ -8,6 +8,7 @@ import com.google.common.collect.Lists; import de.monticore.symboltable.Scope; import de.monticore.symboltable.ScopeSpanningSymbol; +import de.monticore.symboltable.Symbol; import org.junit.Test; import org.nest.base.ModelbasedTest; import org.nest.nestml._ast.*; @@ -55,12 +56,24 @@ public void testCreationOfSymtabAndResolvingOfSymbols() throws IOException { Collection nestmlTypes = modelScope.resolveLocally(NeuronSymbol.KIND); assertEquals(2, nestmlTypes.size()); - final Optional neuronTypeOptional = modelScope.resolve( + final Optional neuronTypeOptional = modelScope.resolve( "iaf_neuron", NeuronSymbol.KIND); assertTrue(neuronTypeOptional.isPresent()); + final Optional y0TVariable = neuronTypeOptional.get().getSpannedScope().resolve("y0", VariableSymbol.KIND); + final Optional y1Varialbe = neuronTypeOptional.get().getSpannedScope().resolve("y1", VariableSymbol.KIND); + assertTrue(y0TVariable.isPresent()); + assertTrue(y0TVariable.get().definedByODE()); - final Optional testComponentOptional = modelScope.resolve( + assertTrue(y1Varialbe.isPresent()); + assertFalse(y1Varialbe.get().definedByODE()); + + // Checks that the derived variable is also resolvable + final Optional Dy0Varialbe = neuronTypeOptional.get().getSpannedScope().resolve("__Dy0", VariableSymbol.KIND); + assertTrue(Dy0Varialbe.isPresent()); + assertTrue(Dy0Varialbe.get().definedByODE()); + + final Optional testComponentOptional = modelScope.resolve( "TestComponent", NeuronSymbol.KIND); assertTrue(testComponentOptional.isPresent()); diff --git a/src/test/java/org/nest/spl/parsing/SPLParserTest.java b/src/test/java/org/nest/spl/parsing/SPLParserTest.java index fd285af3d..ce0e07c11 100644 --- a/src/test/java/org/nest/spl/parsing/SPLParserTest.java +++ b/src/test/java/org/nest/spl/parsing/SPLParserTest.java @@ -32,7 +32,7 @@ public class SPLParserTest extends ModelbasedTest { @Test public void testParsableModels() throws IOException { - final List filenames = collectSPLModelFilenames(TEST_MODEL_PATH); + final List filenames = collectSPLModelFilenames(Paths.get("src/test/resources/org/nest/spl")); filenames.forEach(this::parseAndCheck); } diff --git a/src/test/java/org/nest/spl/prettyprinter/SPLPrettyPrinterTest.java b/src/test/java/org/nest/spl/prettyprinter/SPLPrettyPrinterTest.java index fe215847a..274983bb7 100644 --- a/src/test/java/org/nest/spl/prettyprinter/SPLPrettyPrinterTest.java +++ b/src/test/java/org/nest/spl/prettyprinter/SPLPrettyPrinterTest.java @@ -1 +1 @@ -/* * Copyright (c) 2015 RWTH Aachen. All rights reserved. * * http://www.se-rwth.de/ */ package org.nest.spl.prettyprinter; import org.junit.Test; import org.nest.base.ModelbasedTest; import org.nest.spl._ast.ASTSPLFile; import org.nest.spl._parser.SPLParser; import org.nest.spl._symboltable.SPLLanguage; import java.io.IOException; import java.io.StringReader; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Optional; import static org.junit.Assert.assertTrue; import static org.nest.utils.FilesHelper.collectFiles; /** * Checks that the pretty printed result can be parsed again. * * @author plotnikov */ public class SPLPrettyPrinterTest extends ModelbasedTest { private final SPLParser splFileParser = new SPLParser(); private final ExpressionsPrettyPrinter prettyPrinter = new ExpressionsPrettyPrinter(); private Optional parseStringAsSPLFile(final String fileAsString) throws IOException { return splFileParser.parse(new StringReader(fileAsString)); } @Test public void testThatPrettyPrinterProducesParsableOutput() throws IOException { final SPLPrettyPrinter splPrettyPrinter = new SPLPrettyPrinter(prettyPrinter); final Optional root = splFileParser.parse //("src/test/resources/org/nest/spl/parsing/modelContainingAllLanguageElements.simple"); ("src/test/resources/org/nest/spl/parsing/complexExpressions.simple"); assertTrue(root.isPresent()); root.get().accept(splPrettyPrinter); // starts prettyPrinter Optional prettyPrintedRoot = parseStringAsSPLFile(splPrettyPrinter.getResult()); assertTrue(prettyPrintedRoot.isPresent()); System.out.println(splPrettyPrinter.getResult()); } @Test public void testAllModelsForParser() throws IOException { parseAndCheckSPLModelsFromFolder("src/test/resources/org/nest/spl/parsing"); } @Test public void testAllModelsForCocos() throws IOException { parseAndCheckSPLModelsFromFolder("src/test/resources/org/nest/spl/_cocos"); } private void parseAndCheckSPLModelsFromFolder(final String folderPath) throws IOException { final List splFiles = collectFiles( Paths.get(folderPath), model -> model.endsWith(SPLLanguage.FILE_ENDING)); for (final Path splModelFile : splFiles) { System.out.println("Handles the model: " + splModelFile); final SPLPrettyPrinter splPrettyPrinter = new SPLPrettyPrinter(prettyPrinter); final Optional splModelRoot = splFileParser.parse(splModelFile.toString()); assertTrue("Cannot parse the model: " + splModelFile, splModelRoot.isPresent()); splModelRoot.get().accept(splPrettyPrinter); //System.out.println(splPrettyPrinter.getResult()); Optional prettyPrintedRoot = parseStringAsSPLFile(splPrettyPrinter.getResult()); assertTrue(prettyPrintedRoot.isPresent()); } } } \ No newline at end of file +/* * Copyright (c) 2015 RWTH Aachen. All rights reserved. * * http://www.se-rwth.de/ */ package org.nest.spl.prettyprinter; import org.junit.Test; import org.nest.base.ModelbasedTest; import org.nest.spl._ast.ASTSPLFile; import org.nest.spl._parser.SPLParser; import org.nest.spl._symboltable.SPLLanguage; import java.io.IOException; import java.io.StringReader; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Optional; import static org.junit.Assert.assertTrue; import static org.nest.utils.FilesHelper.collectFiles; /** * Checks that the pretty printed result can be parsed again. * * @author plotnikov */ public class SPLPrettyPrinterTest extends ModelbasedTest { private final SPLParser splFileParser = new SPLParser(); private final ExpressionsPrettyPrinter prettyPrinter = new ExpressionsPrettyPrinter(); private Optional parseStringAsSPLFile(final String fileAsString) throws IOException { return splFileParser.parse(new StringReader(fileAsString)); } @Test public void testThatPrettyPrinterProducesParsableOutput() throws IOException { final SPLPrettyPrinter splPrettyPrinter = new SPLPrettyPrinter(prettyPrinter); final Optional root = splFileParser.parse //("src/test/resources/org/nest/spl/parsing/modelContainingAllLanguageElements.simple"); ("src/test/resources/org/nest/spl/parsing/complexExpressions.simple"); assertTrue(root.isPresent()); root.get().accept(splPrettyPrinter); // starts prettyPrinter Optional prettyPrintedRoot = parseStringAsSPLFile(splPrettyPrinter.getResult()); assertTrue(prettyPrintedRoot.isPresent()); System.out.println(splPrettyPrinter.getResult()); } @Test public void testAllModelsForParser() throws IOException { parseAndCheckSPLModelsFromFolder("src/test/resources/org/nest/spl"); } private void parseAndCheckSPLModelsFromFolder(final String folderPath) throws IOException { final List splFiles = collectFiles( Paths.get(folderPath), model -> model.endsWith(SPLLanguage.FILE_ENDING)); for (final Path splModelFile : splFiles) { System.out.println("Handles the model: " + splModelFile); final SPLPrettyPrinter splPrettyPrinter = new SPLPrettyPrinter(prettyPrinter); final Optional splModelRoot = splFileParser.parse(splModelFile.toString()); assertTrue("Cannot parse the model: " + splModelFile, splModelRoot.isPresent()); splModelRoot.get().accept(splPrettyPrinter); //System.out.println(splPrettyPrinter.getResult()); Optional prettyPrintedRoot = parseStringAsSPLFile(splPrettyPrinter.getResult()); assertTrue(prettyPrintedRoot.isPresent()); } } } \ No newline at end of file diff --git a/src/test/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculatorTest.java b/src/test/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculatorTest.java index 0da06fc9e..6cabaddad 100644 --- a/src/test/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculatorTest.java +++ b/src/test/java/org/nest/spl/symboltable/typechecking/ExpressionTypeCalculatorTest.java @@ -121,6 +121,12 @@ public void testTypeCalculation() throws IOException { // n boolean = not true assertType("n", declarations, getBooleanType()); + + // o1 real = true? 13:14 + assertType("o1", declarations, getIntegerType()); + + // o2 string = true?"test1":"test" + assertType("o2", declarations, getStringType()); } private void assertType(final String variableName, List declarations, final TypeSymbol expectedType) { @@ -159,6 +165,11 @@ public void testNegativeExamples() throws IOException { // n boolean = not 1 assertInvaidType("n", declarations); + //o1 real = 12? 13:14 + assertInvaidType("o1", declarations); + + //o2 real = true?13:"test" + assertInvaidType("o2", declarations); } diff --git a/src/test/resources/org/nest/nestml/symboltable/iaf_neuron.nestml b/src/test/resources/org/nest/nestml/symboltable/iaf_neuron.nestml index 1e517799a..21abcf2f7 100644 --- a/src/test/resources/org/nest/nestml/symboltable/iaf_neuron.nestml +++ b/src/test/resources/org/nest/nestml/symboltable/iaf_neuron.nestml @@ -14,6 +14,11 @@ neuron iaf_neuron: alias V_m mV = y3 + E_L end + equations: + y0' = y0 + 1 + y0'' = y0' + 1 + end + parameter: # Capacity of the membrane C_m pF = 250 diff --git a/src/test/resources/org/nest/spl/_cocos/invalid/mathExpressions.simple b/src/test/resources/org/nest/spl/_cocos/invalid/mathExpressions.simple index 7dca947f2..f8918c2fc 100644 --- a/src/test/resources/org/nest/spl/_cocos/invalid/mathExpressions.simple +++ b/src/test/resources/org/nest/spl/_cocos/invalid/mathExpressions.simple @@ -3,4 +3,6 @@ a real = ((( 1.0 | (-3+6%2) & ~(0x4fa) | 0x23 ^ 12) >> 2) << 2) k integer = ~1.0 m real = 1 ** "a" m1 boolean = "a" and k != 0.0 -n boolean = not 1 \ No newline at end of file +n boolean = not 1 +o1 real = 12? 13:14 +o2 real = true?13:"test" \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/_cocos/valid/mathExpressions.simple b/src/test/resources/org/nest/spl/_cocos/valid/mathExpressions.simple index 78b11d5ea..e1bfc5511 100644 --- a/src/test/resources/org/nest/spl/_cocos/valid/mathExpressions.simple +++ b/src/test/resources/org/nest/spl/_cocos/valid/mathExpressions.simple @@ -12,3 +12,5 @@ P11ex real = pow(1.0, 1.0) # TODO **,h / pow(E, (-h / tau_syn_ex)) tmp string = ("") m boolean = true and l != 0.0 n boolean = not true +o1 real = true? 13:14 +o2 string = true?"test1":"test" \ No newline at end of file diff --git a/src/test/resources/org/nest/spl/parsing/complexExpressions.simple b/src/test/resources/org/nest/spl/parsing/complexExpressions.simple index 081b3e386..12fbe3d89 100644 --- a/src/test/resources/org/nest/spl/parsing/complexExpressions.simple +++ b/src/test/resources/org/nest/spl/parsing/complexExpressions.simple @@ -11,3 +11,4 @@ RefractoryCounts integer = steps(t_ref) # it is a pre-comment 1 print("" + ((( C_m | (-3+6%2) & ~(0x4fa) | 0x23) >> 2) << 2)) # it is a post comment 1 # it is a post commet 2 +tmp real = (11 > 12)?13:14 \ No newline at end of file