From 135af2cc4972493ee9b005f07009ab10c33ddab0 Mon Sep 17 00:00:00 2001 From: codex Date: Fri, 29 Aug 2025 17:43:07 -0500 Subject: [PATCH] Interpreter: support implicit multiplication (adjacency) and allow whitespace; update Coco/R frames path casing; add tests for implicit multiplication and function calls; fix project reference casing in tests. --- .../{CsMic.Core.csproj => CSMic.Core.csproj} | 2 +- src/Core/cocor/Interpreter.atg | 16 +++++++++++++- ...ry.csproj => CSMic.StandardLibrary.csproj} | 0 src/Tests/CSMic.Tests.csproj | 4 ++-- src/Tests/InputInterpreterTests.cs | 21 +++++++++++++++++++ src/Tests/TrigonometryFunctionsTests.cs | 9 +++++++- 6 files changed, 47 insertions(+), 5 deletions(-) rename src/Core/{CsMic.Core.csproj => CSMic.Core.csproj} (91%) rename src/StandardLibrary/{CsMic.StandardLibrary.csproj => CSMic.StandardLibrary.csproj} (100%) diff --git a/src/Core/CsMic.Core.csproj b/src/Core/CSMic.Core.csproj similarity index 91% rename from src/Core/CsMic.Core.csproj rename to src/Core/CSMic.Core.csproj index e5cce08..b298d89 100644 --- a/src/Core/CsMic.Core.csproj +++ b/src/Core/CSMic.Core.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Core/cocor/Interpreter.atg b/src/Core/cocor/Interpreter.atg index 2a641ba..b693d6e 100644 --- a/src/Core/cocor/Interpreter.atg +++ b/src/Core/cocor/Interpreter.atg @@ -58,6 +58,19 @@ bool IsArrayCall() return false; } +// Implicit multiplication detection: the next token starts a Factor +bool IsImplicitMul() +{ + // Allow whitespace between tokens; scanner already skips it + // A Factor/Value can start with: '(', identifier (incl. function/array), number, hex, or binary + if (la.kind == _LPAREN) return true; + if (la.kind == _identifier) return true; + if (la.kind == _number) return true; + if (la.kind == _hex) return true; + if (la.kind == _binary) return true; + return false; +} + /* * Character sets and tokens */ @@ -132,7 +145,8 @@ Term = (. decimal r1 = 0; r = 0; .) Factor - { '*' Factor (. r *= r1; .) + { IF(IsImplicitMul()) Factor (. r *= r1; .) + | '*' Factor (. r *= r1; .) | '/' Factor (. r /= r1; .) | '%' Term (. r %= r1; .) } diff --git a/src/StandardLibrary/CsMic.StandardLibrary.csproj b/src/StandardLibrary/CSMic.StandardLibrary.csproj similarity index 100% rename from src/StandardLibrary/CsMic.StandardLibrary.csproj rename to src/StandardLibrary/CSMic.StandardLibrary.csproj diff --git a/src/Tests/CSMic.Tests.csproj b/src/Tests/CSMic.Tests.csproj index 77961d7..40e8a85 100644 --- a/src/Tests/CSMic.Tests.csproj +++ b/src/Tests/CSMic.Tests.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/src/Tests/InputInterpreterTests.cs b/src/Tests/InputInterpreterTests.cs index db0356c..c02af6f 100644 --- a/src/Tests/InputInterpreterTests.cs +++ b/src/Tests/InputInterpreterTests.cs @@ -158,4 +158,25 @@ public class InputInterpreterTests _interp.Interpret("3+3"); Assert.That(_interp.LastExecutionTime, Is.GreaterThanOrEqualTo(TimeSpan.Zero)); } + + [Test] + public void ImplicitMultiplication_Basic() + { + AssertSuccess(_interp.Interpret("2(3+1)"), 8, _interp); + } + + [Test] + public void ImplicitMultiplication_WithVariableAndParens() + { + AssertSuccess(_interp.Interpret("x :: 3"), 3, _interp); + AssertSuccess(_interp.Interpret("2x"), 6, _interp); + AssertSuccess(_interp.Interpret("(x+1)(x-1)"), 8, _interp); + } + + [Test] + public void ImplicitMultiplication_ChainedParens() + { + AssertSuccess(_interp.Interpret("x :: 4"), 4, _interp); + AssertSuccess(_interp.Interpret("3(x)(2)"), 24, _interp); + } } diff --git a/src/Tests/TrigonometryFunctionsTests.cs b/src/Tests/TrigonometryFunctionsTests.cs index 4c2665f..4486d2d 100644 --- a/src/Tests/TrigonometryFunctionsTests.cs +++ b/src/Tests/TrigonometryFunctionsTests.cs @@ -63,6 +63,14 @@ public class TrigonometryFunctionsTests AssertApprox(_interp.Interpret("atan(1)"), 0.7853981633974483m, 0.0000000000001m, _interp); AssertApprox(_interp.Interpret("atan2(1, 0)"), 1.5707963267948966m, 0.0000000000001m, _interp); } + + [Test] + public void ImplicitMultiplication_WithFunctions() + { + AssertSuccess(_interp.Interpret("2sin(0)"), 0m, _interp); + AssertSuccess(_interp.Interpret("2 sin(0)"), 0m, _interp); + AssertApprox(_interp.Interpret("2sin(pi/2)"), 2m, 0.0000000000001m, _interp); + } } public class HyperbolicTrigFunctionsTests @@ -95,4 +103,3 @@ public class HyperbolicTrigFunctionsTests AssertSuccess(_interp.Interpret("atanh(0)"), 0m, _interp); } } -