Skip to content

Commit

Permalink
Merge branch 'main' of github.com:tamdaz/crygen
Browse files Browse the repository at this point in the history
  • Loading branch information
tamdaz committed Jan 29, 2025
2 parents 5897d3b + 5e9d03b commit 2669cf2
Show file tree
Hide file tree
Showing 3 changed files with 307 additions and 1 deletion.
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ library : [nette/php-generator](https://github.com/nette/php-generator).
- [Todos](#todos)
- [Contributing](#contributing)
- [Contributors](#contributors)
- [Lib C-binding](#lib-c-binding)

## Installation

Expand Down Expand Up @@ -330,6 +331,42 @@ end

> More examples will be added soon.

### Lib C-binding

```crystal
libc_type = CGT::LibC.new("C")
libc_type.add_function("getch", "Int32", [{"arg", "Int32"}])
libc_type.add_function("getpid", "Int32")
libc_type.add_struct("TimeZone", [
{"field_one", "Int32"},
{"field_two", "Int32"},
])
libc_type.add_union("IntOrFloat", [
{"some_int", "Int32"},
{"some_float", "Float64"},
])
puts libc_type.generate
```

Output :

```crystal
lib C
struct TimeZone
field_one : Int32
field_two : Int32
end
union IntOrFloat
some_int : Int32
some_float : Float64
end
fun getch(arg : Int32) : Int32
fun getpid : Int32
end
```

## Usage

This library can be used to save time. In particular, the frameworks have features
Expand All @@ -346,7 +383,7 @@ for generating classes.
- [x] : Add a module
- [x] : Add a struct
- [ ] : Add a macro
- [ ] : Add a lib (C binding)
- [x] : Add a lib (C binding)

Once the todos have been checked, this library will be released.

Expand Down
189 changes: 189 additions & 0 deletions spec/libc_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
require "./spec_helper"

describe Crygen::Types::LibC do
it "creates a C library" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.generate.should eq(<<-CRYSTAL)
lib C
end
CRYSTAL
end

it "creates a C library with one function" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.add_function("getch", "Int32")
libc_type.generate.should eq(<<-CRYSTAL)
lib C
fun getch : Int32
end
CRYSTAL
end

it "creates a C library with one function and a parameter" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.add_function("getch", "Int32", [{"arg", "String"}])
libc_type.generate.should eq(<<-CRYSTAL)
lib C
fun getch(arg : String) : Int32
end
CRYSTAL
end

it "creates a C library with one function and more parameters" do
args = [
{"arg", "String"},
{"value", "Int32"},
]

libc_type = Crygen::Types::LibC.new("C")
libc_type.add_function("getch", "Int32", args)
libc_type.generate.should eq(<<-CRYSTAL)
lib C
fun getch(arg : String, value : Int32) : Int32
end
CRYSTAL
end

it "creates a C library with many functions" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.add_function("getch", "Int32")
libc_type.add_function("time", "Int32")
libc_type.add_function("getpid", "Int32")
libc_type.generate.should eq(<<-CRYSTAL)
lib C
fun getch : Int32
fun time : Int32
fun getpid : Int32
end
CRYSTAL
end

it "creates a C library with one struct" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.add_struct("TimeZone", [
{"field_one", "Int32"},
{"field_two", "Int32"},
])
libc_type.generate.should eq(<<-CRYSTAL)
lib C
struct TimeZone
field_one : Int32
field_two : Int32
end
end
CRYSTAL
end

it "creates a C library with many structs" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.add_struct("TimeZone", [
{"field_one", "Int32"},
{"field_two", "Int32"},
])

libc_type.add_struct("DateTime", [
{"timestamp", "Int64"},
])
libc_type.generate.should eq(<<-CRYSTAL)
lib C
struct TimeZone
field_one : Int32
field_two : Int32
end
struct DateTime
timestamp : Int64
end
end
CRYSTAL
end

it "creates a C library with one union" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.add_union("IntOrFloat", [
{"some_int", "Int32"},
{"some_float", "Float64"},
])
libc_type.generate.should eq(<<-CRYSTAL)
lib C
union IntOrFloat
some_int : Int32
some_float : Float64
end
end
CRYSTAL
end

it "creates a C library with many unions" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.add_union("IntOrFloat", [
{"some_int", "Int32"},
{"some_float", "Float64"},
])
libc_type.add_union("CharOrString", [
{"some_char", "Char"},
{"some_string", "String"},
])
libc_type.generate.should eq(<<-CRYSTAL)
lib C
union IntOrFloat
some_int : Int32
some_float : Float64
end
union CharOrString
some_char : Char
some_string : String
end
end
CRYSTAL
end

it "creates a C library with functions, structs and unions" do
libc_type = Crygen::Types::LibC.new("C")
libc_type.add_function("getch", "Int32")
libc_type.add_function("time", "Int32")
libc_type.add_function("getpid", "Int32")
libc_type.add_struct("TimeZone", [
{"field_one", "Int32"},
{"field_two", "Int32"},
])
libc_type.add_struct("DateTime", [
{"timestamp", "Int64"},
])
libc_type.add_union("IntOrFloat", [
{"some_int", "Int32"},
{"some_float", "Float64"},
])
libc_type.add_union("CharOrString", [
{"some_char", "Char"},
{"some_string", "String"},
])
libc_type.generate.should eq(<<-CRYSTAL)
lib C
struct TimeZone
field_one : Int32
field_two : Int32
end
struct DateTime
timestamp : Int64
end
union IntOrFloat
some_int : Int32
some_float : Float64
end
union CharOrString
some_char : Char
some_string : String
end
fun getch : Int32
fun time : Int32
fun getpid : Int32
end
CRYSTAL
end
end
80 changes: 80 additions & 0 deletions src/types/libc.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
require "./../interfaces/generator"
require "./../types/*"

# A class that generates a C library.
# ```
# libc_type = Crygen::Types::LibC.new("C")
# libc_type.add_function("getch", "Int32")
# libc_type.generate
# ```
# Output :
# ```
# lib C
# fun getch : Int32
# end
# ```
class Crygen::Types::LibC < Crygen::Abstract::GeneratorInterface
alias FieldArray = Array(Tuple(String, String))

@functions = [] of Hash(Symbol, String)
@objects = [] of Tuple(String, Symbol, FieldArray)

def initialize(@name : String); end

# Adds a C function (name and return type).
def add_function(name : String, return_type : String, args : Array(Tuple(String, String)) | Nil = nil) : Nil
@functions << {
:name => name,
:args => !args.nil? ? generate_args(args) : "",
:return_type => return_type,
}
end

# Adds a struct.
def add_struct(name : String, fields : FieldArray) : Nil
@objects << {name, :struct, fields}
end

# Adds an union.
def add_union(name : String, fields : FieldArray) : Nil
@objects << {name, :union, fields}
end

# Generates a C lib.
def generate : String
String.build do |str|
str << "lib #{@name}\n"
can_add_whitespace = false
@objects.each do |object|
str << "\n" if can_add_whitespace == true
str << " #{object[1]} #{object[0]}\n"
object[2].each do |field|
str << " #{field[0]} : #{field[1]}\n"
end
str << " end\n"
can_add_whitespace = true
end
str << "\n" if !@objects.empty? && !@functions.empty?
@functions.each do |function|
if function[:args].empty?
str << " fun #{function[:name]} : #{function[:return_type]}\n"
else
str << " fun #{function[:name]}#{function[:args]} : #{function[:return_type]}\n"
end
end
str << "end"
end
end

# Generate the args.
private def generate_args(args : Array(Tuple(String, String))) : String
String.build do |str|
str << '('
args.each_with_index do |arg, i|
str << "#{arg[0]} : #{arg[1]}"
str << ", " if i != args.size - 1
end
str << ')'
end
end
end

0 comments on commit 2669cf2

Please sign in to comment.