Skip to content

compiler: add fixnums Word{64,32,16,8}, Int{64,32,16,8} - #276

Open
doyougnu wants to merge 2 commits into
gelisam:mainfrom
doyougnu:prims/add-bitops
Open

compiler: add fixnums Word{64,32,16,8}, Int{64,32,16,8}#276
doyougnu wants to merge 2 commits into
gelisam:mainfrom
doyougnu:prims/add-bitops

Conversation

@doyougnu

@doyougnu doyougnu commented Oct 20, 2025

Copy link
Copy Markdown
Collaborator

and example/fixnums.kl

todos:

  • bit level ops
  • .kl file that does bounds checking over the primitive types that this pr adds
  • .kl file that demonstrates numeric operations
  • No more todos
  • update documentation
  • rebase and squash

@doyougnu doyougnu self-assigned this Oct 20, 2025
@doyougnu

Copy link
Copy Markdown
Collaborator Author

after this a good issue to tackle would be #58

Comment thread src/Expander/Primitives.hs Outdated
@doyougnu

Copy link
Copy Markdown
Collaborator Author

I'd also like to do the bounds checking of the fixnums by wrapping them in a macro but I'm not sure exactly how to do that. So a (the Word8 x) would have a check that the x is not larger than 0xFF and not lower than 0. Inserting these checks is for sure slower than building them into the compiler but I think that's fine for a prototype and a good dog fooding opportunity.

@gelisam

gelisam commented Oct 25, 2025

Copy link
Copy Markdown
Owner

+1,332 −101

oh no that one is even bigger than the other MR 😩

I'll never manage to get through both of those in their entirety. should we try splitting them into smaller MRs, or just merge them as-is and hope for the best?

Comment thread examples/fixnum.kl Outdated
Comment thread examples/fixnum.kl Outdated
Comment thread examples/fixnum.kl Outdated
Comment thread src/Parser.hs Outdated
@doyougnu

Copy link
Copy Markdown
Collaborator Author

+1,332 −101

oh no that one is even bigger than the other MR 😩

I'll never manage to get through both of those in their entirety. should we try splitting them into smaller MRs, or just merge them as-is and hope for the best?

I'm sorry!! Yes I had a 8 hour flight and then a 13 hour flight to Singapore for ICFP so I just decided to add them all. I'll keep it small next time

@gelisam

gelisam commented Nov 3, 2025

Copy link
Copy Markdown
Owner

So a (the Word8 x) would have a check that the x is not larger than 0xFF and not lower than 0.

Ah, I think I finally understand the confusion! The the macro is intended to be a type annotation, not a coercion.

Comment thread src/Core.hs
| SyntaxPatternWord64 Ident Var
| SyntaxPatternWord32 Ident Var
| SyntaxPatternWord16 Ident Var
| SyntaxPatternWord8 Ident Var

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

we should really prioritize #184, you are wasting effort adding features to a deprecated system!

@doyougnu

doyougnu commented Nov 19, 2025

Copy link
Copy Markdown
Collaborator Author

@gelisam I'm stuck on the remaining 4 failing examples :/ if these are intractable then perhaps it does make sense to add sized literals like 42u8 ala rust

@gelisam

gelisam commented Nov 24, 2025

Copy link
Copy Markdown
Owner

examples/integer-syntax.kl successfully recognizes that the 2 at the macro's call site is syntactically an integer. At this point, the piece of syntax has no meaning, so it does not yet make sense to ask whether it has type Integer or Word8. Then, the macro constructs calculates (+ 2 2) in phase 1 and returns the code 4, which is ambiguous. The fix is to add a type signature around the result of the macro, not around the 2:

(example
  (the Integer (gotta-be-integer 2)))

@gelisam

gelisam commented Nov 26, 2025

Copy link
Copy Markdown
Owner

examples/pmatch.kl seems pretty redundant; it implements nested pattern-matching as a macro, but the case primitive now supports pattern-matching out of the box. in any case, the fix for the ambiguous part seems pretty straightforward:

(example (swap-list
           (:: (pair (the Integer 1) '1)
             (:: (pair (the Integer 2) '2)
               (:: (pair (the Integer 3) '3)
                 (nil))))))

Then the only remaining difference in the output is the position within the file where the syntax objects '1, '2, and '3 are found. Which makes sense, because the extra (the Integer we've just added in front has pushed them a few characters to the right. I usually delete the golden file, re-run cabal test, look at the golden file's diff, and I git add the differences if the only difference is the position.

All tests
  Golden tests
    pmatch: FAIL (2.91s)
      Test output was different from 'examples/pmatch.golden'. Output of ["diff","-u","examples/pmatch.golden","/tmp/pmatch1185244-0.actual"]:
      --- examples/pmatch.golden	2025-11-24 01:17:05.078682422 -0500
      +++ /tmp/pmatch1185244-0.actual	2025-11-24 01:17:08.409654303 -0500
      @@ -7,6 +7,6 @@
       (zero) : Nat
       (zero) : Nat
       (add1 (zero)) : Nat
      -(:: (pair #[pmatch.kl:119.34-119.35]<1> 1)
      -    (:: (pair #[pmatch.kl:119.50-119.51]<2> 2)
      -        (:: (pair #[pmatch.kl:119.66-119.67]<3> 3) (nil)))) : (List (Pair Syntax Integer))
      +(:: (pair #[pmatch.kl:120.39-120.40]<1> 1)
      +    (:: (pair #[pmatch.kl:121.41-121.42]<2> 2)
      +        (:: (pair #[pmatch.kl:122.43-122.44]<3> 3) (nil)))) : (List (Pair Syntax Integer))

@gelisam

gelisam commented Nov 26, 2025

Copy link
Copy Markdown
Owner

example/implicit-conversion-test.kl exercises the #lang defined in example/implicit-conversion.kl. It's a language which automatically adds conversion functions where needed, e.g. in

(let-implicit string-length
  (+ 1 "foo"))

the #lang's implementation of function application notices that + expects 2 Integers but "foo" is a String, so it inserts the appropriate conversion function:

(+ 1 (string-length "foo"))

There are two difficulties:

  1. This #lang does not provide the (or rather it uses the for something else), so we can't just write (the Integer 42) instead of 42.
  2. The #lang's implementation of function application must be able to notice that 1 is already a string and thus that no conversion function need to be added around it.

For those two reasons, I think it would make more sense if integer literals were monomorphic in that #lang. To do this, we need to modify examples/implicit-conversion.kl, not examples/implicit-conversion-test.kl. That module defines my-integer-literal, which gets renamed to #%integer-literal during the export, and is thus how integer literals like 42 will get interpreted in this language. Currently it generates a call to #lang "prelude.kl"'s #%integer-literal, which is polymorphic on your branch. So it now needs to add a type ascription around that #%integer-literal call in order to make sure this 42 is inferred to have type Integer:

(define-macro (my-integer-literal n)
  (pure `(reader-pure (the Integer (#%integer-literal ,n)))))

@gelisam

gelisam commented Nov 26, 2025

Copy link
Copy Markdown
Owner

after fixing those 3 tests, the entire test suite succeeds for me. what is the 4th failing test on your side?

@doyougnu

Copy link
Copy Markdown
Collaborator Author

after fixing those 3 tests, the entire test suite succeeds for me. what is the 4th failing test on your side?

Thanks for the help. The last remaining is primitive-documentation but I just have to fill that one out. Yea I got stuck on implicit-conversion. I had changed #%integer-literal like you suggested but I also added ascriptions to integer-literal-test which was throwing errors.

and example/fixnums.kl
and associated operations such as:
- {word|int}{8|16|32|64}{<|>|<=|>=|=}
- {word|int}-compliment,-popcount,->string
- {word|int}{8|16|32|64}->string

and redefine #%integer-literal to not assume an Integer.
@doyougnu
doyougnu marked this pull request as ready for review November 30, 2025 19:08
Type mismatch at not-a-function.kl:3.11-3.13.
Expected (Integer → (?1 → ?2)) but got Integer
Type mismatch at not-a-function.kl:3.24-3.26.
Expected (?1 → (?2 → ?3)) but got Integer

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

since not-a-function.kl specifically annotates that the 42 has type Integer, I don't understand why the error message changed?

this is not a blocker.

Comment thread examples/fixnum.kl
(example (the Int8 256)) -- note no bounds checking with the primitives this is 0
(example (int32-popcount 0xFF)) -- 8
(example (int8-+ 42 50))
(example (int8-compliment 7)) -- will be -8 because 2's complement

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
(example (int8-compliment 7)) -- will be -8 because 2's complement
(example (int8-complement 7)) -- will be -8 because 2's complement

Comment thread examples/primitives-documentation.golden Outdated
Comment thread examples/primitives-documentation.golden Outdated
Comment thread examples/primitives-documentation.golden Outdated
Comment thread examples/primitives-documentation.golden Outdated
Comment thread examples/primitives-documentation.golden Outdated
Comment thread examples/primitives-documentation.golden Outdated
Comment thread examples/primitives-documentation.golden Outdated
Comment thread examples/primitives-documentation.kl Outdated
Comment thread examples/primitives-documentation.kl Outdated
Comment thread examples/primitives-documentation.kl Outdated
Comment thread examples/primitives-documentation.kl Outdated
Comment thread examples/primitives-documentation.kl Outdated
Comment thread examples/primitives-documentation.kl Outdated
Comment thread examples/primitives-documentation.kl Outdated
Comment thread examples/primitives-documentation.kl Outdated
Comment thread src/Syntax/Syntax.hs
| Word64 Word64
| Word32 Word32
| Word16 Word16
| Word8 Word8

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

hmm, I remember we decided that 42 would be a polymorphic syntax which can either have time Int8, Integer, or whatever, depending on the context? If so, it doesn't make sense for ExprF to have a constructor for Int8 etc., as there is no dedicated 42u8 syntax for it. Similarly, there should not be a Syntax-Contents constructor for Int8 either.

❌ this is a blocker

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

(nor a CoreInt8Syntax constructor)

Co-authored-by: Samuel Gélineau <gelisam@gmail.com>
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