Forum | Documentation | Website | Blog

Skip to content
Snippets Groups Projects
c_struct_spec.cr 5.73 KiB
Newer Older
require "../../spec_helper"

CodeGenStructString = "lib LibFoo; struct Bar; x : Int32; y : Float32; end; end"

describe "Code gen: struct" do
  it "codegens struct property default value" do
    run("#{CodeGenStructString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.x").to_i.should eq(0)
  end

  it "codegens struct property setter" do
    run("#{CodeGenStructString}; bar = LibFoo::Bar.new; bar.y = 2.5_f32; bar.y").to_f32.should eq(2.5)
  it "codegens struct property setter via pointer" do
    run("#{CodeGenStructString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.y = 2.5_f32; bar.value.y").to_f32.should eq(2.5)
  it "codegens struct property setter via pointer" do
    run("#{CodeGenStructString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.y = 2.5_f32; bar.value.y").to_f32.should eq(2.5)
  end

  it "codegens set struct value with constant" do
    run("#{CodeGenStructString}; CONST = 1; bar = LibFoo::Bar.new; bar.x = CONST; bar.x").to_i.should eq(1)
  end

  it "codegens union inside struct" do
    run("
      lib LibFoo
        union Bar
          x : Int32
          y : Int64
        end

        struct Baz
          lala : Bar
        end
      end

      a = Pointer(LibFoo::Baz).malloc(1_u64)
      a.value.lala.x = 10
      a.value.lala.x
      ").to_i.should eq(10)
  end

  it "codegens struct get inside struct" do
    run("
      lib LibC
        struct Bar
          y : Int32
        end

        struct Foo
          x : Int32
          bar : Bar
        end
      end

      foo = Pointer(LibC::Foo).malloc(1_u64)
      ((foo as Int32*) + 1_i64).value = 2
      ").to_i.should eq(2)
  end

  it "codegens struct set inside struct" do
    run("
      lib LibC
        struct Bar
          y : Int32
        end

        struct Foo
          x : Int32
          bar : Bar
        end
      end

      foo = Pointer(LibC::Foo).malloc(1_u64)
      bar = LibC::Bar.new
      ").to_i.should eq(2)
  end

  it "codegens pointer malloc of struct" do
    run("
      lib LibC
        struct Foo
          x : Int32
        end
      end

      p = Pointer(LibC::Foo).malloc(1_u64)
      p.value.x = 1
      p.value.x
      ").to_i.should eq(1)
  end

  it "passes struct to method (1)" do
    run("
      lib LibC
      f1 = LibC::Foo.new
      f1.x = 1

      f2 = foo(f1)

      f1.x
      ").to_i.should eq(1)
  end

  it "passes struct to method (2)" do
    run("
      lib LibC
      f1 = LibC::Foo.new
      f1.x = 1

      f2 = foo(f1)
      f2.x
      ").to_i.should eq(2)
  end

  it "codegens struct access with -> and then ." do
    run("
      lib LibC
        struct ScalarEvent
          x : Int32
        end

        union EventData
          scalar : ScalarEvent
        end

        struct Event
          data : EventData
        end
      end

      e = Pointer(LibC::Event).malloc(1_u64)
      ").to_i.should eq(0)
  end

  it "yields struct via ->" do
    run("
      lib LibC
        struct ScalarEvent
          x : Int32
        end

        union EventData
          scalar : ScalarEvent
        end

        struct Event
          data : EventData
        end
      end

      def foo
        e = Pointer(LibC::Event).malloc(1_u64)
      end

      foo do |data|
        data.scalar.x
      end
      ").to_i.should eq(0)
  end
  it "codegens assign struct to union" do
    run("
      lib LibFoo
        struct Coco
          x : Int32
        end
      end

      x = LibFoo::Coco.new
      c = x || 0
      c.is_a?(LibFoo::Coco)
    ").to_b.should be_true
  end

  it "codegens passing pointerof(struct) to fun" do
    run("
      lib LibC
      fun foo(x : LibC::Foo*) : Int32
      f = LibC::Foo.new
      f.a = 1

      foo pointerof(f)
      ").to_i.should eq(1)
  end
  it "builds struct setter with fun type (1)" do
      lib LibC
      foo = LibC::Foo.new
  it "builds struct setter with fun type (2)" do
      lib LibC
      foo = Pointer(LibC::Foo).malloc(1)
  it "allows forward declarations" do
      lib LibC
        struct A; end
        struct B; end

        struct A
          x : B*
          y : Int32
        end

        struct B
          x : A*
          y : Int32
        end
      end

      a = LibC::A.new
      b = Pointer(LibC::B).malloc(1_u64)
      b.value.y = 2
      a.x = b

      a.y + a.x.value.y
      )).to_i.should eq(3)
  end

  it "allows using named arguments for new" do
    run(%(
      lib LibC
      point = LibC::Point.new x: 1, y: 2
      point.x + point.y
      )).to_i.should eq(3)
  end

  it "returns big struct" do
    build(%(
      lib LibC
        struct Big
          x : Int64
          y : Int64
          z : Int32
        end

        fun foo(y : Int32) : Big
      end

      s = LibC.foo(1)

  it "does to_s" do
    run(%(
      require "prelude"

      lib LibFoo
        struct Point
          x, y : Int32
        end
      end

      point = LibFoo::Point.new x: 1, y: 2
      point.to_s
      )).to_string.should eq("LibFoo::Point(@x=1, @y=2)")
  end