SkillAgentSearch skills...

SpacePony

SpacePony is an experimental fork of the Pony programming language. The goal of the fork is to improve the language, especially the FFI capabilities and add more systems programming language features.

Install / Use

/learn @IgorDeepakM/SpacePony
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

SpacePony

SpacePony is an experimental fork of the Pony programming language. The goal of the fork is to improve the FFI capabilities and add more systems programming language features.

Quick start

SpacePony currently doesn't have any official binary releases, however it is easy to clone this repo and build the compiler.

  • First clone this repo in any subdirectory.

Linux/Macos

By default SpacePony uses Clang as the compiler. Also Cmake and Python3 is needed.

  • In the base directory type:
    • make libs build_flags="-j6" (this will build associated libraries such as LLVM, this will take a while. Adjust the -j6 option to the number of cores you want to use)
    • make configure
    • make build

Windows

By default SpacePony uses the MSVC compiler. Also Cmake and Python3 is needed. Everything can be installed using MS Visual Studio. Open a Powershell terminal in order to run the make script, simplest is to open the "Developer PowerShell for VS 202x" where all the compiler stuff is added to the path.

  • In the base directory type:
    • .\make.ps1 libs (this will build associated libraries such as LLVM, this will take a while)
    • .\make.ps1 configure
    • .\make.ps1 build

The compiled output including the ponyc compiler is located in the build/release directory.

Did I miss anything? This guide will tell you more Building from source

Breaking changes from original Pony

  • While SpacePony is compatible with original Pony, it is inevitable that SpacePony and Pony will diverge more and more. Several keywords have been added which might be used in Pony, cannot be used in SpacePony. This is a list of breaking changes that you might need to change in order to adapt Pony source code to SpacePony.

    • The following keywords have been added. They are either in use or reserved for future use.

      • enum
      • comptime
      • asm
      • tuple
      • nhb
      • offsetof
      • sizeof
      • entityif
    • In the class Iter in the package itertools, the method enum was renamed to enumerate because enum is a reserved keyword in SpacePony.

List of additions/changes

Identify SpacePony

  • Added a build flag spacepony in order to identify SpacePony.

    ifdef spacepony then
      env.out.print("This is spacepony")
    else
      env.out.print("This is not spacepony")
    end
    

Pointer

  • The Pointer type can be used everywhere not only as FFI function arguments.

  • It can be initialized using from_usize(addr: USize) in order to initialize a Pointer with any desired number.

    var my_ptr = Pointer[None].from_usize(0x12345678)
    
  • It is possible to obtain the Pointer value as a USize with the usize method. Useful for printing the pointer value for example.

    env.out.print("Address is " + Format.int[USize](ptr.usize(), FormatHex))
    
  • The convert method is made public in order to make it possible to cast one pointer type to another.

    var ptr1: Pointer[MyStruct1] = ...
    var ptr2: Pointer[MyStruct2] = ptr1.convert[MyStruct2]()
    
  • Added to_reftype method to convert the Pointer to the underlying reference type. This is equivalent to the apply method of the NullablePointer type.

    var ptr: Pointer[MyStruct] = ...
    var my_struct: MyStruct = MyStruct_
    try
      my_struct_: MyStruct = ptr.to_reftype()?
    else
      ...
    end
    
  • Added to_reftype_no_check method to convert the Pointer to the underlying reference type without any null pointer check.

    var ptr: Pointer[MyStruct] = ...
    var my_struct: MyStruct = ptr.to_reftype_no_check()
    
  • Added pointer_at_index method in order to obtain a pointer at a specific index. Note that this depends on the type of Pointer.

    var ptr: Pointer[U32] = ...
    var ptr2 = ptr.pointer_at_index(3) // Gives a new pointer with a byte offset of ptr + 4 * 3
    
  • Added from_reftype constructor in order to create a pointer from a class or struct.

    var ptr: Pointer[MyStruct].from_reftype(my_struct)
    
  • Added from_any constructor in order to create a pointer from anything of the desired type. This is like a cast assign.

    var ptr: Pointer[U32].from_any[MyStruct](my_struct)
    
  • A class or a struct can be implicitly converted to a Pointer. A Pointer[None] will accept any class or struct type.

    struct S
    
    ...
    
    let s: S = S
    var ps: Pointer[S] = s
    var ps2: Pointer[None] = s
    
    

addressof

  • addressof can be used everywhere

  • It is possible to use addressof of an FFI function. The type is a bare lambda. This is useful for populating bare lambdas in structs to emulate C++ abstract classes if it is necessary to initialize them in Pony.

    use @FFI_Func[None](x: I32, y: I32)
    
    ...
    
    var f = addressof @FFI_Func
      f(3, 7)
    

Constant values in generics

  • It is possible to use constants (literals) as type arguments in generics, both as type arguments for types and type arguments for functions.

  • Much of the work for constants in generics was done in ponyta (https://github.com/lukecheeseman/ponyta).

    class TT[n: USize, name: String]
      fun get_sum(k: USize): USize =>
        n * k
    
      fun get_name_(): String =>
        name
    
      fun get_sum_const[k: USize](): USize =>
        n * k
    
    ...
    
    var tt: TT[3, "constant string"] = TT[3, "constant string"]
    
  • Default value type arguments are supported, both in function type arguments and class/struct type arguments.

    fun get_sum_const[k: USize = 4](): USize =>
      n * k
    

CFixedSizedArray

  • Added CFixedSizedArray in order to be able to model C fixed sized arrays found in C.

    struct S
    {
      size_t size;
      char buf[512];
    }
    

    Can be modelled in Pony as

    struct S
      var size: USize = 0
      embed buf: CFixedSizedArray[U8, 512] = CFixedSizedArray[U8, 512](0)
    

    make sure to use embed in order to expand the array in the struct. Using var buf: CFixedSizedArray[U8, 512] would be the same char (*buf)[512] and Pony would allocate the fixed sized array on the heap.

    It is possible to emulate a C flexible array member (https://en.wikipedia.org/wiki/Flexible_array_member) that is allocated in C. The Array class can be loaded using the CFixedSizedArray.

    struct S
      var size: USize = 0
      embed buf: CFixedSizedArray[U8, 1] = CFixedSizedArray[U8, 1](0)
    
    ...
    
    var s = @get_struct()
    
    ...
    
    var ar = Array.from_cpointer(s.buf.cpointer(), s.size)
    

offsetof

  • Added offsetof in order to get an offset of a member in a struct or class.

    struct S
      var x: USize
      var y: USize
    
    ...
    
    var s = S
    let off_y = offsetof s.y // Gets the offset of y
    let off_y_2 = offsetof S.y // It is possible to use the type directly as base
    

sizeof

  • Added sizeof operator to obtain the size of any type. Also works on nested types.

    struct S
      var x: USize
      var y: USize
    
    ...
    
    var s = S
    let sz_u32 = sizeof U32 // Any base type can be used
    let sz_s = sizeof s // Gets the size of the struct s
    let sz_s_2 = sizeof S // Type can be used directly as base in a dot expression
    let sz_s_y = sizeof s.y // Size of members can be used
    let sz_s_y_2_ = sizeof S.y // Also with the type directly as base
    
  • Keep in mind that both sizeof and offsetof are not compile time constants, meaning they do not behave like a literal and they can unfortunately not be used as type values in generics. sizeof/offsetof are created during the code generation step becoming a compile time constant in the LLVM code and not before that. The reason for this is the the SpacePony compiler uses LLVM in order build target dependent aggregate types in the code generation pass which is one of the last passes. It is possible to make sizeof and offsetof into a literal but that would require using LLVM to build up the types in earlier passes.

FFI pass by value parameters

  • Structs and classes can be passed as value to FFI functions. Add the annotation \byval\ before the type in the parameter declaration. Annotation was used because it could be easily added without intruding too much on the existing Pony syntax. It also can coexists with other annotations disregarding the order.

  • Note that this needs to be manually added for each CPU and OS target as there is currently no functionality in LLVM that lowers the parameters. For more information read this article. There are currently discussions to add an ABI lowering library to LLVM, [[RFC] An ABI lowering library for LLVM](https://discourse.llvm.org/t/rfc-an-abi-lowering-lib

View on GitHub
GitHub Stars6
CategoryProduct
Updated11h ago
Forks0

Languages

Pony

Security Score

90/100

Audited on Apr 1, 2026

No findings