Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hexadecimal literals for Byte #814

Open
jiribenes opened this issue Feb 4, 2025 · 2 comments
Open

Add hexadecimal literals for Byte #814

jiribenes opened this issue Feb 4, 2025 · 2 comments
Labels
feature New feature or request good first issue Good for newcomers

Comments

@jiribenes
Copy link
Contributor

Format: '0x' <hexa> <hexa> where <hexa> ::= 0 | 1 | ... | a | A | b | B | ... | f | F.
Note that it's only for bytes, i.e. values between 0x00 (0) and 0xFF (255) that have the Byte type, everything else should fail.
Specifically, this notation is not for integers of type Int, it's just for us being able to write 0xEF directly instead of relying on 239.toByte.

@jiribenes jiribenes added feature New feature or request good first issue Good for newcomers labels Feb 4, 2025
@jiribenes
Copy link
Contributor Author

jiribenes commented Feb 7, 2025

I'm setting this as a good first issue, so here's a walkthrough.
Note that it might be better to split this up into a few PRs :)

  1. Go to the Lexer, and add a new TokenKind for Byte literals
    enum TokenKind {
    // literals
    case Integer(n: Long)
    case Float(d: Double)
    case Str(s: String, multiline: Boolean)
    case Chr(c: Int)
    ,
  2. then search for where we parse the Integer TokenKind and adapt the code. Also take a look at the existing hexadecimal declaration corresponding to <hexa> above in the grammar ,
  3. then add a corresponding test to LexerTests https://github.com/effekt-lang/effekt/blob/f4c840f3f4d6047410b5897bbd30fb4bdce61360/effekt/jvm/src/test/scala/effekt/LexerTests.scala .
  4. Define a Byte literal in the Source.Tree:
    // Smart Constructors for literals
    // -------------------------------
    def UnitLit(): Literal = Literal((), symbols.builtins.TUnit)
    def IntLit(value: Long): Literal = Literal(value, symbols.builtins.TInt)
    def BooleanLit(value: Boolean): Literal = Literal(value, symbols.builtins.TBoolean)
    def DoubleLit(value: Double): Literal = Literal(value, symbols.builtins.TDouble)
    def StringLit(value: String): Literal = Literal(value, symbols.builtins.TString)
    def CharLit(value: Int): Literal = Literal(value, symbols.builtins.TChar)
    ,
  5. then parse it in the parser:
    def literal(): Literal =
    nonterminal:
    peek.kind match {
    case Integer(v) => skip(); IntLit(v)
    case Float(v) => skip(); DoubleLit(v)
    case Str(s, multiline) => skip(); StringLit(s)
    case Chr(c) => skip(); CharLit(c)
    case `true` => skip(); BooleanLit(true)
    case `false` => skip(); BooleanLit(false)
    case t if isUnitLiteral => skip(); skip(); UnitLit()
    case t => fail("Expected a literal")
    }
    (don't forget to change isLiteral too!) ,
  6. then add a corresponding test to RecursiveDescentTests
    class RecursiveDescentTests extends munit.FunSuite {
    .
  7. Compile the whole project, run the Effekt executable, try using 0x... and fixing the found bugs.
  8. then a few examples into examples/pos to ensure it doesn't break again.
  9. ideally, as a last step, try to make the lexer less brittle by it being able to parse (and discard) invalid expressions like 0x, 0xF, 0xFFFF, 0xabracadabra

@jiribenes
Copy link
Contributor Author

Also, please remember to update the show instance for Byte to better reflect the new syntax:

extern pure def show(value: Byte): String =
js "'' + ${value}"
chez "(string ${value})"
llvm """
%z = call %Pos @c_bytearray_show_Byte(i8 ${value})
ret %Pos %z
"""
vm "effekt::show(Byte)"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

1 participant