|
7 | 7 | /**********************************************************************/ |
8 | 8 |
|
9 | 9 | #include "ParsedJITTensor.h" |
| 10 | +#include "SwiftExpressionParser.h" |
10 | 11 | #include "SwiftUtils.h" |
11 | 12 | #include "MooseError.h" |
12 | 13 | #include "gtest/gtest.h" |
@@ -201,3 +202,109 @@ TEST(ParsedTensorTest, Parse) |
201 | 202 | check2("a:=sin(x^2); a + 2*a + 3*a", "x", "12*x*cos(x^2)", true); |
202 | 203 | check2("a:=sin(x^2); a + 2*a + 3*a", "x", "12*x*cos(x^2)", false); |
203 | 204 | } |
| 205 | + |
| 206 | +TEST(ParsedTensorTest, Substitute) |
| 207 | +{ |
| 208 | + SwiftExpressionParser::Parser parser; |
| 209 | + |
| 210 | + // Test basic variable substitution |
| 211 | + { |
| 212 | + auto expr = parser.parse("x + y"); |
| 213 | + ASSERT_TRUE(expr != nullptr); |
| 214 | + |
| 215 | + auto replacement = parser.parse("2*z"); |
| 216 | + ASSERT_TRUE(replacement != nullptr); |
| 217 | + |
| 218 | + auto substituted = expr->substitute("x", replacement); |
| 219 | + EXPECT_EQ(substituted->toString(), "((2.000000 * z) + y)"); |
| 220 | + } |
| 221 | + { |
| 222 | + auto expr = parser.parse("x * y"); |
| 223 | + ASSERT_TRUE(expr != nullptr); |
| 224 | + |
| 225 | + auto replacement = parser.parse("2+z"); |
| 226 | + ASSERT_TRUE(replacement != nullptr); |
| 227 | + |
| 228 | + auto substituted = expr->substitute("x", replacement); |
| 229 | + EXPECT_EQ(substituted->toString(), "((2.000000 + z) * y)"); |
| 230 | + } |
| 231 | + |
| 232 | + // Test substitution in nested expressions |
| 233 | + { |
| 234 | + auto expr = parser.parse("sin(x) + cos(x) * x"); |
| 235 | + ASSERT_TRUE(expr != nullptr); |
| 236 | + |
| 237 | + auto replacement = parser.parse("y^2"); |
| 238 | + ASSERT_TRUE(replacement != nullptr); |
| 239 | + |
| 240 | + auto substituted = expr->substitute("x", replacement); |
| 241 | + EXPECT_EQ(substituted->toString(), |
| 242 | + "(sin((y ^ 2.000000)) + (cos((y ^ 2.000000)) * (y ^ 2.000000)))"); |
| 243 | + } |
| 244 | + |
| 245 | + // Test substitution in let expressions without shadowing |
| 246 | + { |
| 247 | + auto expr = parser.parse("a := x + 1; a * x"); |
| 248 | + ASSERT_TRUE(expr != nullptr); |
| 249 | + |
| 250 | + auto replacement = parser.parse("y + z"); |
| 251 | + ASSERT_TRUE(replacement != nullptr); |
| 252 | + |
| 253 | + auto substituted = expr->substitute("x", replacement); |
| 254 | + // Should substitute x in both the binding and the body |
| 255 | + EXPECT_EQ(substituted->toString(), "a:=((y + z) + 1.000000); (a * (y + z))"); |
| 256 | + } |
| 257 | + |
| 258 | + // Test substitution with variable shadowing |
| 259 | + { |
| 260 | + auto expr = parser.parse("a := x + 1; a * x"); |
| 261 | + ASSERT_TRUE(expr != nullptr); |
| 262 | + |
| 263 | + auto replacement = parser.parse("y + z"); |
| 264 | + ASSERT_TRUE(replacement != nullptr); |
| 265 | + |
| 266 | + auto substituted = expr->substitute("a", replacement); |
| 267 | + // Should NOT substitute 'a' anywhere because the binding defines 'a' (shadowing) |
| 268 | + EXPECT_EQ(substituted->toString(), "a:=(x + 1.000000); (a * x)"); |
| 269 | + } |
| 270 | + |
| 271 | + // Test that substitution doesn't affect unrelated variables |
| 272 | + { |
| 273 | + auto expr = parser.parse("x + y + z"); |
| 274 | + ASSERT_TRUE(expr != nullptr); |
| 275 | + |
| 276 | + auto replacement = parser.parse("42"); |
| 277 | + ASSERT_TRUE(replacement != nullptr); |
| 278 | + |
| 279 | + auto substituted = expr->substitute("y", replacement); |
| 280 | + EXPECT_EQ(substituted->toString(), "((x + 42.000000) + z)"); |
| 281 | + } |
| 282 | + |
| 283 | + // Test substitution in complex let expressions with multiple bindings |
| 284 | + { |
| 285 | + auto expr = parser.parse("a := x; b := a + 1; b * x"); |
| 286 | + ASSERT_TRUE(expr != nullptr); |
| 287 | + |
| 288 | + auto replacement = parser.parse("2*z"); |
| 289 | + ASSERT_TRUE(replacement != nullptr); |
| 290 | + |
| 291 | + auto substituted = expr->substitute("x", replacement); |
| 292 | + // x should be substituted in first binding and in body, but not in second binding (uses 'a') |
| 293 | + EXPECT_EQ(substituted->toString(), |
| 294 | + "a:=(2.000000 * z); b:=(a + 1.000000); (b * (2.000000 * z))"); |
| 295 | + } |
| 296 | + |
| 297 | + // Test substitution preserves expression structure |
| 298 | + { |
| 299 | + auto expr = parser.parse("r := x^2 + y^2; sqrt(r) + r"); |
| 300 | + ASSERT_TRUE(expr != nullptr); |
| 301 | + |
| 302 | + auto replacement = parser.parse("t + 1"); |
| 303 | + ASSERT_TRUE(replacement != nullptr); |
| 304 | + |
| 305 | + auto substituted = expr->substitute("x", replacement); |
| 306 | + // x should be substituted but local variable r should still be referenced |
| 307 | + EXPECT_EQ(substituted->toString(), |
| 308 | + "r:=(((t + 1.000000) ^ 2.000000) + (y ^ 2.000000)); (sqrt(r) + r)"); |
| 309 | + } |
| 310 | +} |
0 commit comments