diff --git a/k-distribution/include/kframework/builtin/domains.md b/k-distribution/include/kframework/builtin/domains.md
index f267314a448..8584edb2dd8 100644
--- a/k-distribution/include/kframework/builtin/domains.md
+++ b/k-distribution/include/kframework/builtin/domains.md
@@ -1119,8 +1119,8 @@ module INT
syntax Int ::= freshInt(Int) [freshGenerator, function, functional]
rule freshInt(I:Int) => I
- syntax Int ::= randInt(Int) [function, hook(INT.rand)]
- syntax K ::= srandInt(Int) [function, hook(INT.srand)]
+ syntax Int ::= randInt(Int) [function, hook(INT.rand), impure]
+ syntax K ::= srandInt(Int) [function, hook(INT.srand), impure]
endmodule
```
diff --git a/k-distribution/tests/regression-new/checks/invalidConstantExp.k b/k-distribution/tests/regression-new/checks/invalidConstantExp.k
new file mode 100644
index 00000000000..61f82c1db44
--- /dev/null
+++ b/k-distribution/tests/regression-new/checks/invalidConstantExp.k
@@ -0,0 +1,6 @@
+module INVALIDCONSTANTEXP
+ imports INT
+
+ rule 0 => 1 /Int 0
+
+endmodule
diff --git a/k-distribution/tests/regression-new/checks/invalidConstantExp.k.out b/k-distribution/tests/regression-new/checks/invalidConstantExp.k.out
new file mode 100644
index 00000000000..879f66bd996
--- /dev/null
+++ b/k-distribution/tests/regression-new/checks/invalidConstantExp.k.out
@@ -0,0 +1,6 @@
+[Error] Compiler: Division by zero.
+ while executing phase "constant expression folding" on sentence at
+ Source(invalidConstantExp.k)
+ Location(4,8,4,21)
+ Source(invalidConstantExp.k)
+ Location(4,13,4,21)
diff --git a/k-distribution/tests/regression-new/constant-folding/1.test b/k-distribution/tests/regression-new/constant-folding/1.test
new file mode 100644
index 00000000000..00750edc07d
--- /dev/null
+++ b/k-distribution/tests/regression-new/constant-folding/1.test
@@ -0,0 +1 @@
+3
diff --git a/k-distribution/tests/regression-new/constant-folding/1.test.out b/k-distribution/tests/regression-new/constant-folding/1.test.out
new file mode 100644
index 00000000000..19e2468eaf1
--- /dev/null
+++ b/k-distribution/tests/regression-new/constant-folding/1.test.out
@@ -0,0 +1,3 @@
+
+ .
+
diff --git a/k-distribution/tests/regression-new/constant-folding/2.test b/k-distribution/tests/regression-new/constant-folding/2.test
new file mode 100644
index 00000000000..b4de3947675
--- /dev/null
+++ b/k-distribution/tests/regression-new/constant-folding/2.test
@@ -0,0 +1 @@
+11
diff --git a/k-distribution/tests/regression-new/constant-folding/2.test.out b/k-distribution/tests/regression-new/constant-folding/2.test.out
new file mode 100644
index 00000000000..19e2468eaf1
--- /dev/null
+++ b/k-distribution/tests/regression-new/constant-folding/2.test.out
@@ -0,0 +1,3 @@
+
+ .
+
diff --git a/k-distribution/tests/regression-new/constant-folding/3.test b/k-distribution/tests/regression-new/constant-folding/3.test
new file mode 100644
index 00000000000..7ed6ff82de6
--- /dev/null
+++ b/k-distribution/tests/regression-new/constant-folding/3.test
@@ -0,0 +1 @@
+5
diff --git a/k-distribution/tests/regression-new/constant-folding/3.test.out b/k-distribution/tests/regression-new/constant-folding/3.test.out
new file mode 100644
index 00000000000..a4072584b3e
--- /dev/null
+++ b/k-distribution/tests/regression-new/constant-folding/3.test.out
@@ -0,0 +1,3 @@
+
+ 5 ~> .
+
diff --git a/k-distribution/tests/regression-new/constant-folding/Makefile b/k-distribution/tests/regression-new/constant-folding/Makefile
new file mode 100644
index 00000000000..d48aaade4fd
--- /dev/null
+++ b/k-distribution/tests/regression-new/constant-folding/Makefile
@@ -0,0 +1,7 @@
+DEF=test
+EXT=test
+TESTDIR=.
+KOMPILE_BACKEND=llvm
+KOMPILE_FLAGS=--syntax-module TEST
+
+include ../../../include/kframework/ktest.mak
diff --git a/k-distribution/tests/regression-new/constant-folding/test.k b/k-distribution/tests/regression-new/constant-folding/test.k
new file mode 100644
index 00000000000..e7bce3a5c30
--- /dev/null
+++ b/k-distribution/tests/regression-new/constant-folding/test.k
@@ -0,0 +1,15 @@
+module TEST
+ imports INT
+ imports STRING
+ imports ID
+
+ syntax Int ::= "foo" | "bar"
+
+ syntax Id ::= "main" [token]
+
+ rule foo => 1 +Int 2 [macro]
+ rule foo => .K
+
+ rule bar => 1 +Int 2 *Int lengthString(Id2String(main) +String substrString("foo", 0, 1)) [macro]
+ rule bar => .K
+endmodule
diff --git a/kernel/src/main/java/org/kframework/backend/kore/KoreBackend.java b/kernel/src/main/java/org/kframework/backend/kore/KoreBackend.java
index c3280e352ea..2b21927f9b5 100644
--- a/kernel/src/main/java/org/kframework/backend/kore/KoreBackend.java
+++ b/kernel/src/main/java/org/kframework/backend/kore/KoreBackend.java
@@ -11,6 +11,7 @@
import org.kframework.compile.Backend;
import org.kframework.compile.ConcretizeCells;
import org.kframework.compile.ConfigurationInfoFromModule;
+import org.kframework.compile.ConstantFolding;
import org.kframework.compile.ExpandMacros;
import org.kframework.compile.GenerateCoverage;
import org.kframework.compile.GeneratedTopFormat;
@@ -141,6 +142,7 @@ public Function steps() {
ResolveFunctionWithConfig transformer = new ResolveFunctionWithConfig(d, true);
return DefinitionTransformer.fromSentenceTransformer((m, s) -> new ExpandMacros(transformer, m, files, kem, kompileOptions, false, excludedModuleTags().contains(Att.CONCRETE())).expand(s), "expand macros").apply(d);
};
+ DefinitionTransformer constantFolding = DefinitionTransformer.fromSentenceTransformer(new ConstantFolding()::fold, "constant expression folding");
Function1 resolveFreshConstants = d -> DefinitionTransformer.from(m -> GeneratedTopFormat.resolve(new ResolveFreshConstants(d, true).resolve(m)), "resolving !Var variables").apply(d);
GenerateCoverage cov = new GenerateCoverage(kompileOptions.coverage, files);
Function1 genCoverage = d -> DefinitionTransformer.fromRuleBodyTransformerWithRule((r, body) -> cov.gen(r, body, d.mainModule()), "generate coverage instrumentation").apply(d);
@@ -160,6 +162,7 @@ public Function steps() {
.andThen(subsortKItem)
.andThen(generateSortPredicateSyntax)
.andThen(generateSortProjections)
+ .andThen(constantFolding)
.andThen(expandMacros)
.andThen(guardOrs)
.andThen(AddImplicitComputationCell::transformDefinition)
diff --git a/kernel/src/main/java/org/kframework/compile/ConstantFolding.java b/kernel/src/main/java/org/kframework/compile/ConstantFolding.java
new file mode 100644
index 00000000000..5fb88fbd94f
--- /dev/null
+++ b/kernel/src/main/java/org/kframework/compile/ConstantFolding.java
@@ -0,0 +1,723 @@
+// Copyright (c) 2021 K Team. All Rights Reserved.
+package org.kframework.compile;
+
+import org.apache.commons.lang3.StringUtils;
+import org.kframework.attributes.Att;
+import org.kframework.builtin.Hooks;
+import org.kframework.definition.Module;
+import org.kframework.definition.Rule;
+import org.kframework.definition.Sentence;
+import org.kframework.kore.K;
+import org.kframework.kore.KApply;
+import org.kframework.kore.KToken;
+import org.kframework.kore.Sort;
+import org.kframework.kore.TransformK;
+import org.kframework.utils.errorsystem.KEMException;
+import org.kframework.utils.StringUtil;
+import org.kframework.mpfr.BigFloat;
+import org.kframework.mpfr.BinaryMathContext;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.kframework.Collections.*;
+import static org.kframework.kore.KORE.*;
+import static org.kframework.definition.Constructors.*;
+
+public class ConstantFolding {
+
+ private static final List hookNamespaces = Arrays.asList(Hooks.BOOL, Hooks.FLOAT, Hooks.INT, Hooks.STRING);
+
+ private K loc;
+
+ void setLoc(K loc) {
+ this.loc = loc;
+ }
+
+ public Sentence fold(Module module, Sentence sentence) {
+ if (sentence instanceof Rule) {
+ Rule r = (Rule)sentence;
+ return Rule(fold(module, r.body(), true), fold(module, r.requires(), false), fold(module, r.ensures(), false), r.att());
+ }
+ return sentence;
+ }
+
+ public K fold(Module module, K body, boolean isBody) {
+ return new RewriteAwareTransformer(isBody) {
+ @Override
+ public K apply(KApply k) {
+ if (isLHS() || !isRHS()) {
+ return super.apply(k);
+ }
+ Att att = module.attributesFor().get(k.klabel()).getOrElse(() -> Att());
+ if (att.contains(Att.HOOK()) && !att.contains(Att.IMPURE())) {
+ String hook = att.get(Att.HOOK());
+ if (hookNamespaces.stream().anyMatch(ns -> hook.startsWith(ns + "."))) {
+ List args = new ArrayList<>();
+ for (K arg : k.items()) {
+ K expanded = apply(arg);
+ if (!(expanded instanceof KToken)) {
+ return super.apply(k);
+ }
+ args.add(expanded);
+ }
+ try {
+ loc = k;
+ return doFolding(hook, args, module.productionsFor().apply(k.klabel().head()).head().substitute(k.klabel().params()).sort(), module);
+ } catch (NoSuchMethodException e) {
+ throw KEMException.internalError("Missing constant-folding implementation for hook " + hook, e);
+ }
+ }
+ }
+ return super.apply(k);
+ }
+ }.apply(body);
+ }
+
+ private Class> classOf(String hook) {
+ switch(hook) {
+ case "BOOL.Bool":
+ return boolean.class;
+ case "FLOAT.Float":
+ return FloatBuiltin.class;
+ case "INT.Int":
+ return BigInteger.class;
+ case "STRING.String":
+ return String.class;
+ default:
+ return String.class;
+ }
+ }
+
+ private Object unwrap(String token, String hook) {
+ switch(hook) {
+ case "BOOL.Bool":
+ return Boolean.valueOf(token);
+ case "FLOAT.Float":
+ return FloatBuiltin.of(token);
+ case "INT.Int":
+ return new BigInteger(token);
+ case "STRING.String":
+ return StringUtil.unquoteKString(token);
+ default:
+ return token;
+ }
+ }
+
+ private K wrap(Object result, Sort sort) {
+ if (result instanceof Boolean) {
+ return KToken(result.toString(), sort);
+ } else if (result instanceof FloatBuiltin) {
+ return KToken(((FloatBuiltin)result).value(), sort);
+ } else if (result instanceof BigInteger) {
+ return KToken(result.toString(), sort);
+ } else if (result instanceof String) {
+ return KToken(StringUtil.enquoteKString((String)result), sort);
+ } else {
+ return KToken(result.toString(), sort);
+ }
+ }
+
+ private K doFolding(String hook, List args, Sort resultSort, Module module) throws NoSuchMethodException {
+ String renamedHook = hook.replace('.', '_');
+ List> paramTypes = new ArrayList<>();
+ List