Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

String Stack Calc Laravel Package

ardiakov/string-stack-calc

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require ardiakov/string-stack-calc
    
    • Ensure your project uses Symfony 3.4–4.0 (or Laravel 5.5–6.x with Symfony compatibility).
  2. Service Registration: The package provides a StringStackCalculator service. Register it in your Laravel config/app.php under bindings or use dependency injection directly:

    $calculator = app('StringStackCalculator');
    
  3. First Use Case: Parse and evaluate a simple arithmetic expression passed as a string:

    $result = $calculator->calculate('2 + 3 * (4 - 1)');
    // Returns: 11 (2 + (3 * 3))
    
  4. Key Classes:

    • StringStackCalculator: Main service for parsing/evaluating expressions.
    • Token: Represents tokens (numbers, operators, parentheses) in the parser.
    • Parser: Converts infix notation (e.g., 2+3) to postfix (Reverse Polish Notation).

Implementation Patterns

Core Workflow

  1. Input Handling:

    • Accept strings like "5 * (10 - 2) / 3".
    • Sanitize input (trim whitespace, validate characters) before parsing.
  2. Parsing Pipeline:

    $tokens = $calculator->tokenize('3 + 4 * 2');
    // Returns: [Token('3'), Token('+'), Token('4'), Token('*'), Token('2')]
    
    $postfix = $calculator->parseToPostfix($tokens);
    // Converts to: [Token('3'), Token('4'), Token('2'), Token('*'), Token('+')]
    
  3. Evaluation:

    $result = $calculator->evaluatePostfix($postfix);
    // Returns: 11 (3 + (4 * 2))
    
  4. Integration with Laravel:

    • Service Provider: Bind the calculator to the container in AppServiceProvider:
      public function register() {
          $this->app->bind('StringStackCalculator', function ($app) {
              return new \Ardiakov\StringStackCalc\StringStackCalculator();
          });
      }
      
    • Facade (Optional): Create a facade for cleaner syntax:
      // app/Facades/StringCalc.php
      namespace App\Facades;
      use Illuminate\Support\Facades\Facade;
      class StringCalc extends Facade {
          protected static function getFacadeAccessor() { return 'StringStackCalculator'; }
      }
      
      Usage:
      $result = StringCalc::calculate('5 / 2');
      
  5. Validation Layer: Wrap calculations in a validator to handle edge cases:

    public function safeCalculate(string $expression): ?float {
        try {
            return $this->calculate($expression);
        } catch (\InvalidArgumentException $e) {
            Log::error("Invalid expression: {$expression}");
            return null;
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Operator Precedence:

    • The package follows standard precedence (* before +), but no custom operators are supported out-of-the-box.
    • Workaround: Extend Parser to add new operators (e.g., ^ for exponentiation).
  2. Floating-Point Precision:

    • Results may have floating-point inaccuracies (e.g., 0.1 + 0.20.30000000000000004).
    • Tip: Round results or use bcmath for financial calculations:
      $result = bcdiv($calculator->calculate('0.1 + 0.2'), 1, 10);
      
  3. Memory Limits:

    • Complex expressions (e.g., deeply nested parentheses) may hit PHP’s stack limit.
    • Debugging: Use set_time_limit() or break expressions into smaller steps.
  4. Error Handling:

    • Throws InvalidArgumentException for malformed input (e.g., "2 + *").
    • Tip: Catch exceptions and return user-friendly messages:
      try {
          $result = $calculator->calculate($expression);
      } catch (\InvalidArgumentException $e) {
          return "Error: {$e->getMessage()}";
      }
      
  5. Symfony Dependency:

    • The package uses Symfony’s DependencyInjection and Config. If using Laravel, avoid Symfony 5+ to prevent version conflicts.

Extension Points

  1. Custom Functions:

    • Override StringStackCalculator to add functions (e.g., sin, log):
      class ExtendedCalculator extends StringStackCalculator {
          protected function evaluatePostfix(array $postfix) {
              $stack = [];
              foreach ($postfix as $token) {
                  if ($token->isNumber()) {
                      $stack[] = $token->value;
                  } elseif ($token->value === 'sin') {
                      $stack[] = sin(array_pop($stack));
                  }
                  // ... handle other operators
              }
              return array_pop($stack);
          }
      }
      
  2. Tokenization:

    • Extend Token or Parser to support variables (e.g., "2 * $x"). Requires a symbol table.
  3. Unit Testing:

    • Test edge cases:
      $this->assertEquals(0, $calculator->calculate(''));
      $this->assertEquals(4, $calculator->calculate('2 + 2'));
      $this->expectException(InvalidArgumentException::class);
      $calculator->calculate('2 +');
      

Configuration Quirks

  • No Config File: The package has no config/ directory. All behavior is hardcoded in the StringStackCalculator class.
  • Locale: Assumes English operators (+, -, *, /). For other locales (e.g., × instead of *), override the tokenize() method.

Debugging Tips

  1. Inspect Tokens:
    $tokens = $calculator->tokenize('3 + 4 * 2');
    dd($tokens); // Debug token stream
    
  2. Postfix Output:
    $postfix = $calculator->parseToPostfix($tokens);
    dd($postfix); // Verify RPN conversion
    
  3. Stack Simulation: Manually simulate the evaluation stack to trace issues:
    $stack = [];
    foreach ($postfix as $token) {
        if ($token->isNumber()) $stack[] = $token->value;
        elseif ($token->isOperator()) {
            $b = array_pop($stack);
            $a = array_pop($stack);
            $stack[] = $a . $token->value . $b; // Log intermediate steps
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
babenkoivan/elastic-client
innmind/static-analysis
innmind/coding-standard
datacore/hub-sdk
alengo/sulu-http-cache-bundle
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity