Skip to content

Implementation of the POW (**) Operator#392

Open
tedpatrick wants to merge 11 commits into
mainfrom
pow-pow
Open

Implementation of the POW (**) Operator#392
tedpatrick wants to merge 11 commits into
mainfrom
pow-pow

Conversation

@tedpatrick

@tedpatrick tedpatrick commented Feb 7, 2026

Copy link
Copy Markdown
Contributor

This pull request adds support for the power operator (**) across the SPy virtual machine and its standard numeric types, including both integer and floating-point types. It introduces new operator implementations, updates the operator dispatch tables, and adds comprehensive tests to ensure correct behavior for power operations. Additionally, it improves the atomicity of cache file writes to prevent issues with concurrent access.

Power operator (**) support

  • Added the ** operator to the operator dispatch tables for all relevant numeric types (i8, u8, i32, u32, f32, f64) in spy/vm/modules/operator/binop.py and registered the corresponding implementations. [1] [2] [3] [4] [5] [6] [7] [8] [9]
  • Implemented the w_POW operator dispatch function, which handles the power operation and falls back to __pow__ if available.
  • Added per-type implementations for the power operation in the operator implementation files: w_f32_pow in opimpl_f32.py, w_f64_pow in opimpl_f64.py, and generic integer w_pow in opimpl_int.py. [1] [2] [3]
  • Added C-level implementations for power operations for all relevant numeric types in spy/libspy/include/spy/operator.h and spy/libspy/src/operator.c. [1] [2] [3]

Testing

  • Added comprehensive tests for the ** operator for both integer and floating-point types, including tests for negative bases, zero exponents, and fractional exponents, in spy/tests/compiler/test_int.py and spy/tests/compiler/test_float.py. [1] [2]

Reliability improvements

  • Improved atomicity of cache file writes in spy/analyze/importing.py by writing to a temporary file and renaming it, preventing partial writes in concurrent environments.

@Viriathus1

Copy link
Copy Markdown
Contributor

Hi @tedpatrick, just from a quick glance I noticed you didn't add the operator for the f32 type and also the custom is to add the operator unit tests into the following files test_int.py and test_float.py in that directory.

One other note is the inclusion of the guide to add operators doesn't quite fit the purpose of the docs section in my opinion. I'm sure @antocuni will confirm one or another for that one.

@tedpatrick

tedpatrick commented Apr 11, 2026

Copy link
Copy Markdown
Contributor Author

C layer:

  • spy/libspy/src/operator.c — added spy_operator$f32_pow using powf(x, y)
  • spy/libspy/include/spy/operator.h — added WASM_EXPORT declaration for spy_operator$f32_pow
  • Rebuilt libspy.wasm (debug) so the new symbol is available at runtime

Python layer:

  • spy/vm/modules/operator/opimpl_f32.py — added w_f32_pow delegating to _f32_op_f32(..., "pow")
  • spy/vm/modules/operator/binop.py — registered "**" for f32/f32, and both directions of f32/i32 mixed

Tests:

  • spy/tests/compiler/test_float.py — added test_pow using the float_type fixture (runs for both f32 and f64 across all three backends)
  • spy/tests/compiler/test_int.py — added test_pow and test_pow_negative_base using the int_type fixture (covers i32, u32, i8, u8)
  • spy/tests/compiler/test_pow.py — deleted

@tedpatrick tedpatrick changed the title Implementation of the POW (**) Operator + Guide for Operator Implementation Implementation of the POW (**) Operator Apr 11, 2026
@tedpatrick

Copy link
Copy Markdown
Contributor Author

Closes #175

@Viriathus1 Viriathus1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes on this one. There's a few minor things that still need to be rectified. It needs to conform to Python specs more broadly as described here. The following is currently unaccounted for:

  • For int operands, the result must be a float if the exponent arg is negative.
  • Zero with a negative exponent raises a ZeroDivisionError exception.
  • Negative base with fractional exponent returns a complex number - eg: (-5) ** 0.5 == (1.3691967456605067e-16+2.23606797749979j)

Comment thread spy/libspy/include/spy/operator.h Outdated
Comment thread spy/tests/compiler/test_int.py
Comment thread spy/tests/compiler/test_float.py
@Viriathus1

Copy link
Copy Markdown
Contributor

Hi @tedpatrick, thanks for the changes. I see that you widen the result to f64 for all pow operations involving signed ints. It doesn't exactly match python semantics but I don't see how you could do anything apart from inspecting the rhs W_MetaArg for a concrete value which can only be done when they're blue. This extends to complex number situation as well.

What do you think @antocuni? Union types are probably required here which have yet to be implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants