Skip to content

Add shift operations for numeric values#995

Draft
abh80 wants to merge 18 commits intonasa:feature/shift-opfrom
abh80:feature/shift-operations
Draft

Add shift operations for numeric values#995
abh80 wants to merge 18 commits intonasa:feature/shift-opfrom
abh80:feature/shift-operations

Conversation

@abh80
Copy link
Copy Markdown
Contributor

@abh80 abh80 commented Apr 24, 2026

Added:

Bit shift operations to numeric values

constant amount = 2
constant value = 8
constant shifted = value << amount  # shifted=22

Closes #922

Tasks

Implementation

  • Token.scala: added LSHIFT and RSHIFT tokens.
  • Lexer.scala: added token parsing for new tokens.
  • Ast.scala:
    • added new trait ShiftType to encapsulate shift types LShift extends ShiftType .....
    • added case class Shift(op: ShiftType) extends Binop to Binop.
  • Parser.scala:
    • added expr binop node creation for new shift tokens.
    • implemented the parsing for shift tokens.
    • implement shift operand parsing with least precedence.
  • analysis/CheckSemantics/CheckExprTypes.scala:
    • added a new helper method convertToInteger for shift operations (ignoring float values).
    • add the new case Ast.Binop.Shift(_).
  • Value.scala:
    • added a new type intShiftOp = (BigInt, Int) => BigInt for shifting.
    • added a new private[analysis] def intShiftOp(op: Value.Binop.intShiftOp)(v: Value) (since generic binop does not support (BigInt, Int) => Bigint))
    • added two new methods to Value: isNegative and isValidShiftAmount to help in Analysis.scala.
    • implement the intShiftOp method in PrimitiveInt, Integer and EnumConstant.
    • added << and >> methods to Value to perform shift operations.
  • Analysis.scala: added lshift and rshift method, using the new methods added to Value.
  • CheckSemantics/EvalConstantExprs.scala: add the new case Ast.Binop.Shift(op) using the new methods added to Analysis.
  • util/Error.scala: Added a new InvalidShiftAmount error to SemanticError.

Tests

  • compiler/tools/fpp-check/test/numeric_shift: added robust test cases including edge cases and error checks.
  • compiler/lib/src/test/input/syntax/lexer/ok/symbols.fpp: added the new <</>> symbols.
  • should reject float-operands.
  • precedence check (1 + 2 << 3 parses as and shift operations must have lowest precedence).
  • should reject negative-shift values.
  • fpp-syntax tests.
  • fpp-to-cpp tests.
  • ValueSpec tests.

Spec:

  • Update 3.2 symbols list
  • Update the 10.1 arithmetic expressions table
  • Update the 10.13. Precedence and Associativity
  • Update the 18.12. Binary Arithmetic Expressions with new examples for this feature

have to address this: #995 (comment)

@abh80
Copy link
Copy Markdown
Contributor Author

abh80 commented Apr 24, 2026

  /** For shifting operations make sure both values are integer */
  private def convertToInteger(loc: Location, t: Type): Result.Result[Type] =
    if (t.isInt) Right(t)
    else if (t.isConvertibleTo(Type.Integer)) Right(Type.Integer)
    else {                                                                                                                                                                                      
      val error = SemanticError.InvalidType(loc, s"cannot convert $t to an integer type")
      Left(error)                                                                                                                                                                               
    } 

The current implementation of int value check is too much permissive, since float is convertible to int. I will completely remove the conditional check. This causes the failure: https://github.com/abh80/fpp/blob/564f25468d2be477626cae34c49a0d5d354327f5/compiler/tools/fpp-check/test/numeric_shift/shift_float_value_error.ref.txt#L1

Edit: Looks like there is another bug

 t <- a.commonType(e.e1.id, e.e2.id, loc)                                                                                 
  _ <- e.op match {
    case Ast.Binop.Shift(_) => convertToInteger(loc, t)                                                                    
    ...
  }

The common type inference automatically promotes to Float even if one value is int which causes misleading error information. However this dosent affect the intended behavior since it's only applicable if both values are integer

@abh80 abh80 changed the base branch from main to feature/shift-op April 24, 2026 09:50
@abh80
Copy link
Copy Markdown
Contributor Author

abh80 commented Apr 25, 2026

@bocchino I have completed the implementation and testing. Can you give the initial review before I start writing the documentation?

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.

Support shift operations for numeric values

1 participant