Giter Club home page Giter Club logo

zigler's Introduction

Zigler

Library test status:

Version 0.11.1 warning

Several compile-time niceties are broken, such as line and file translation and there is a compile time warning about multiple function matches. These will be addressed in the 0.12.0 release.

Installation: Elixir

Zig dependency

Prior to installing Zigler, you should install zig via mix zig.get. To do so, install the minisign and zig.get mix tasks:

mix archive.install hex minisign mix archive.install hex zig_get

And then run mix zig.get

If you're using erlang, please install zig in the following locations:

Linux

~/.cache/zigler/zig-linux-<arch>-0.11.1

Main installation

Zigler is available in Hex, and the package can be installed by adding zigler to your list of dependencies in mix.exs:

def deps do
  [
    {:zigler, "~> 0.11.0", runtime: false}
  ]
end

Installation: Erlang

Erlang is only supported via rebar3. You must enable the rebar_mix plugin and add zigler to your deps in rebar3.

Note that erlang support is highly experimental. Please submit issues if you have difficulty.

{plugins, [rebar_mix]}.

{deps, [{zigler, "0.11"}]}.

Documentation

Docs can be found at https://hexdocs.pm/zigler.

Currently supported platforms

  • Linux

  • FreeBSD (tested, but not subjected to CI)

  • MacOS

  • Nerves cross-compilation is supported out of the box.

Zig Nifs made easy

Wouldn't it be nice if you could make NIFs as easily as you can use the asm keyword in C?

This is now possible, using the magic of Zig.

defmodule ExampleZig do
  use Zig, otp_app: :zigler
  ~Z"""
  pub fn example_fun(value1: f64, value2: f64) bool {
    return value1 > value2;
  }
  """
end

test "example nifs" do
  assert ExampleZig.example_fun(0.8, -0.8)
  refute ExampleZig.example_fun(0.1, 0.4)
end

Zigler will do automatic type marshalling between Elixir code and Zig code. It will also convert trickier types into types you care about, for example:

defmodule ZigCollections do
  use Zig, otp_app: :zigler
  ~Z"""
  pub fn string_count(string: []u8) i64 {
    return @intCast(string.len);
  }

  pub fn list_sum(array: []f64) f64 {
    var sum: f64 = 0.0;
    for(array) | item | {
      sum += item;
    }
    return sum;
  }
  """
end

test "type marshalling" do
  assert 9 == ZigCollections.string_count("hello zig")
  assert 6.0 == ZigCollections.list_sum([1.0, 2.0, 3.0])
end

Memory allocation with zigler is easy! A standard BEAM allocator is provided for you, so any zig code you import will play nice with the BEAM.

defmodule Allocations do
  use Zig, otp_app: :zigler
  ~Z"""
  const beam = @import("beam");

  pub fn double_atom(env: beam.env, string: []u8) beam.term {
    var double_string = beam.allocator.alloc(u8, string.len * 2) catch {
      return beam.raise_enomem(env);
    };

    defer beam.allocator.free(double_string);

    for (string) | char, i | {
      double_string[i] = char;
      double_string[i + string.len] = char;
    }

    return beam.make_atom(env, double_string);
  }
  """
end

test "allocations" do
  assert :foofoo == Allocations.double_atom("foo")
end

It is a goal for Zigler to make using it to bind C libraries easier than using C to bind C libraries. Here is an example:

defmodule Blas do
  use Zig,     
    otp_app: :zigler
    link_lib: {:system, "blas"},

  ~Z"""
  const beam = @import("beam");
  const blas = @cImport({
    @cInclude("cblas.h");
  });

  pub fn blas_axpy(env: beam.env, a: f64, x: []f64, y: []f64) beam.term {
    if (x.len != y.len) {
      return beam.raise_function_clause_error(env);
    }

    blas.cblas_daxpy(@intCast(x.len), a, x.ptr, 1, y.ptr, 1);

    return y;
  }
  """
end

test "we can use a blas shared library" do
  # returns aX+Y
  assert [11.0, 18.0] == Blas.blas_axpy(3.0, [2.0, 4.0], [5.0, 6.0])
end

Documentation (Elixir-only)

You can document nif functions, local functions, zig structs, variables, and types. If you document a nif function, it will be a part of the module documentation, and accessible using the iex h method, etc.

Example:

defmodule Documentation do
  use Zig, otp_app: :zigler
  ~Z"""
  /// a zero-arity function which returns 47.
  pub fn zero_arity() i64 {
    return 47;
  }
  """
end

Formatting (Elixir-only)

A mix format plugin is available through the zigler_format package. See the installation instructions

Erlang support

Use of Zigler with erlang is possible using parse transforms. Annotate the zig code into a zig_code attribute and pass zigler options (identical to the elixir options) into a zig_opts attribute. Zigler will then create appropriate functions matching the zig functions.

-module(erlang_zigler_module).
-compile({parse_transform, zigler}). 
-export([foo/1, foo/0]).

-zig_code("
pub fn foo() i32 {
    return 47;
}
").

-zig_opts([{otp_app, zigler}]).

foo(X) ->
    47 + X.

Zigler Principles

  1. Make being a good citizen of the BEAM easy.
  2. Use magic, but sparingly, only to prevent errors.
  3. Let the user see behind the curtain.
  4. Let the user opt out of magic.
  5. Magic shouldn't get in the way.

zigler's People

Contributors

dch avatar fhunleth avatar greenfork avatar ityonemo avatar jeremyowensboggs avatar kianmeng avatar maennchen avatar rbino avatar seomwan avatar smaximov avatar v0idpwn avatar wojtekmach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zigler's Issues

freebsd support

I think you can have FreeBSD support already:

I have the following packages installed:

# pkg install -r FreeBSD lang/zig lang/erlang-runtime22 devel/elixir-hex devel/llvm80

This gives us zig-0.5.0 and the rest should be self explanatory.

I suppressed the side-effect-only Logger https://github.com/ityonemo/zigler/blob/master/lib/zigler/compiler.ex#L24

$ export NIFTY_LLVM_VERSION=80
$ mix do deps.get --all, deps.compile, compile
$ mix zigler.get_zig 0.5.0
...
$ mix test --trace

Compiling 17 files (.ex)

13:19:58.168 [info]  compiling using command: `/repos/zigler/zig/zig-freebsd-x86_64-0.5.0/zig build-lib zig_nif.zig -dynamic --disable-gen-h --override-lib-dir /repos/zigler/zig/zig-freebsd-x86_64-0.5.0/lib/zig`

13:19:58.176 [info]  compiling using command: `/repos/zigler/zig/zig-freebsd-x86_64-0.5.0/zig build-lib zig_nif.zig -dynamic --disable-gen-h --override-lib-dir /repos/zigler/zig/zig-freebsd-x86_64-0.5.0/lib/zig`

13:20:04.925 [info]  compiling using command: `/repos/zigler/zig/zig-freebsd-x86_64-0.5.0/zig build-lib zig_nif.zig -dynamic --disable-gen-h --override-lib-dir /repos/zigler/zig/zig-freebsd-x86_64-0.5.0/lib/zig --release-safe`
Generated zigler app

ZiglerTest.CompilerErrorParserTest
  * test the compiler line parser (0.04ms)

ZiglerTest.CompilerErrorTest
  * test compiler error catches and rewrites internal error (270.6ms)
  * test compiler error catches mismatched arity (35.3ms)
  * test compiler error catches and rewrites external error (485.7ms)
  * test compiler error catches mismatched nif (7.9ms)

ZiglerTest.ParserTest
  * test the nif parser can identify nifs (0.01ms)
  * test the docstring multiline parser can identify multiline docstrings (0.05ms)
  * test the function header parser can identify bool function headers (0.07ms)
  * test the function header parser can identify one-arity function headers (0.04ms)
  * test the docstring line parser will ignore a non docline (0.00ms)
  * test the function header parser can identify zero-arity function headers (0.02ms)
  * test the docstring line parser can identify a single docline (0.02ms)
  * test the function header parser can identify two-arity function headers (0.05ms)
  * test the function header parser can identify beam.env headers (0.05ms)
  * test the docstring line parser can identify a single docline when it's got indentation (0.01ms)
  * test the function header parser can identify string function headers (0.04ms)
  * test the function header parser can identify erlnifenv headers (0.06ms)

ZiglerTest.UnitParserTest
  * test the identifier parser fails on non_identifiers (0.00ms)
  * test the test header parser can identify test headers (0.08ms)
  * test the identifier parser can correctly identify identifiers (0.01ms)
  * test the import parser leaves pub imports alone (0.02ms)
  * test the identifier parser fails on strange symbols (0.00ms)
  * test the import parser can identify import statements (0.01ms)

ZiglerTest.CodeTest
  * test when given a code multiline string the code module can return plain code with no nifs, and assign files and lines correctly (0.04ms)
  * test when given a code multiline string the code module can do the correct thing with multiple functions (0.1ms)
  * test when given a code multiline string the code module can identify more complex nif headers (0.09ms)
  * test when given a code multiline string the code module can find a nif and correctly assign it, adding line numbers (0.07ms)

ZiglerTest.Types.EmptyTest
  * test zero arity zig functions work (0.06ms)

ZiglerTest.MutationTest
  * test passing binaries across a function self-call works (0.07ms)
  * test we can mutate binaries (0.00ms)

ZigTest.TypespecTest
  * test zigler correctly creates typespecs for degenerate (2.0ms)
  * test zigler correctly creates typespecs for generic beam types (23.0ms)
  * test zigler correctly creates typespecs for floats (0.5ms)
  * test zigler correctly creates typespecs for integers (0.9ms)
  * test zigler correctly creates typespecs for bools (0.7ms)
  * test zigler correctly creates typespecs for float lists (0.4ms)
  * test zigler correctly creates typespecs for strings (0.7ms)
  * test zigler correctly creates typespecs for int lists (2.8ms)

ZiglerTest.ZigdocTest
  * test gets the docs (695.7ms)

ZiglerTest.AllocatorsTest
  * test elixir persistent memory works (0.1ms)
  * test elixir basic allocator works (0.1ms)

ZiglerTest.DoubleZigTest
  * test two zig definitions in the different sigils (0.06ms)
  * test two zig definitions in the same sigil (0.05ms)

ZiglerTest.ExternalFilesTest
  * test a recursive external file can be called (0.05ms)
  * test a relative external file can be called (0.04ms)

ZiglerTest.Types.EgressTest
  * test lists can be egressed from c_int lists (0.1ms)
  * test lists can be egressed from internal literals (0.00ms)
  * test integers can be egressed c_int (0.00ms)
  * test lists can be egressed from f16 lists (0.00ms)
  * test lists can be egressed from i32 lists (0.00ms)
  * test floats can be egressed f32 (0.00ms)
  * test floats can be egressed f64 (0.00ms)
  * test lists can be egressed from c_long lists (0.00ms)
  * test strings can be egressed from a slice (0.06ms)
  * test integers can be egressed i32 (0.00ms)
  * test integers can be egressed c_long (0.00ms)
  * test lists can be egressed from i64 lists (0.00ms)
  * test bools can be exported correctly (0.00ms)
  * test characters can be egressed correctly (0.00ms)
  * test strings can be egressed from a c_string (0.00ms)
  * test lists can be egressed from f32 lists (0.00ms)
  * test lists can be egressed from f64 lists (0.00ms)
  * test integers can be egressed i64 (0.00ms)

ZiglerTest.Types.IngressTest
  * test 32-bit integers can be ingressed and are guarded for invalid values (3.5ms)
  * test binaries can be ingressed as slices and are guarded for invalid values (0.09ms)
  * test atoms can be ingressed and are guarded for invalid values (0.02ms)
  * test f32 lists can be ingressed correctly (0.07ms)
  * test pids can be ingressed as beam.pid correctly (0.00ms)
  * test f16 lists can be ingressed and are guarded for invalid values (0.09ms)
  * test binaries can be ingressed as binary structs and are guarded for invalid values (0.01ms)
  * test pids can be ingressed as e.ErlNifPid correctly (0.00ms)
  * test binaries can be ingressed as binary structs via e.ErlNifBinary and are guarded for invalid values (0.01ms)
  * test i32 lists can be ingressed correctly (0.00ms)
  * test 16-bit floats can be ingressed and are guarded for invalid values (0.01ms)
  * test f64 lists can be ingressed even with empties (0.00ms)
  * test binaries can be ingressed as slices correctly (0.00ms)
  * test atoms can be ingressed correctly (0.00ms)
  * test 16-bit floats can be ingressed correctly (0.00ms)
  * test pids can be ingressed as beam.pid and are guarded for invalid values (0.01ms)
  * test f32 lists can be ingressed and are guarded for invalid values (0.02ms)
  * test i64 lists can be ingressed even with empties (0.00ms)
  * test i64 lists can be ingressed and are guarded for invalid values (0.02ms)
  * test binaries can be ingressed as c_strings correctly (0.00ms)
  * test usize can be ingressed correctly (0.00ms)
  * test 64-bit integers can be ingressed correctly (0.00ms)
  * test binaries can be ingressed as binary structs correctly (0.00ms)
  * test c integers can be ingressed and are guarded for invalid values (0.01ms)
  * test 32-bit integers can be ingressed correctly (0.00ms)
  * test c integers can be ingressed correctly (0.00ms)
  * test f32 lists can be ingressed even with empties (0.00ms)
  * test f16 lists can be ingressed correctly (0.00ms)
  * test binaries can be ingressed as binary structs via e.ErlNifBinary correctly (0.00ms)
  * test i32 lists can be ingressed and are guarded for invalid values (0.02ms)
  * test i32 lists can be ingressed even with empties (0.00ms)
  * test usize can be ingressed and are guarded for invalid values (0.02ms)
  * test c longs can be ingressed and are guarded for invalid values (0.02ms)
  * test 64-bit floats can be ingressed correctly (0.00ms)
  * test 64-bit integers can be ingressed and are guarded for invalid values (0.02ms)
  * test f64 lists can be ingressed correctly (0.00ms)
  * test bools can be ingressed and are guarded for invalid values (0.02ms)
  * test characters can be ingressed correctly (0.00ms)
  * test pids can be ingressed as e.ErlNifPid and are guarded for invalid values (0.01ms)
  * test f16 lists can be ingressed even with empties (0.00ms)
  * test 32-bit floats can be ingressed correctly (0.00ms)
  * test isize can be ingressed and are guarded for invalid values (0.01ms)
  * test c longs can be ingressed correctly (0.00ms)
  * test binaries can be ingressed as c_strings and are guarded for invalid values (0.01ms)
  * test f64 lists can be ingressed and are guarded for invalid values (0.02ms)
  * test 64-bit floats can be ingressed and are guarded for invalid values (0.02ms)
  * test 32-bit floats can be ingressed and are guarded for invalid values (0.01ms)
  * test characters can be ingressed and are guarded for invalid values (0.02ms)
  * test bools can be ingressed correctly (0.00ms)
  * test isize can be ingressed correctly (0.00ms)
  * test i64 lists can be ingressed correctly (0.00ms)

ZiglerTest.ReadmeTest
  * test allocations (0.1ms)
  * test example_zig (0.05ms)
  * test zig_collections (0.09ms)

ZiglerTest
  * test sigil-Z2 creates a function of the correct arity (0.05ms)
  * test sigil-Z creates a public function (0.06ms)

ZiglerTest.ZigTest
  * zigtest the truth (0.00ms)

ZiglerTest.ZigFailingTest
  * test if we have a failing test, it can be caught (5.8ms)

ZiglerTest.ZigIndirectTest
  * zigtest function one (0.00ms)

ZiglerTest.ZigDeepTest
  * zigtest function one (0.00ms)


Finished in 31.5 seconds
120 tests, 3 zigtests, 0 failures

Randomized with seed 960707

Which looks perfect to me. It would be nice if zigler knew to use the pre-installed lang/zig port, rather than needing to download stuff.

Windows support

WIndows support is likely to be extremely challenging: The erlang ABI actually has a different look to the header file. (erl_nif.h is not trivially human parsable as a result).

The correct strategy is likely to create a separate erl_nif_windows.h, and build against that.

cuter typesystem

e.ErlNifTerms and stuff are nice because they are direct c interops, but why can't we just have nice things like elixir.Term. Zig is not C.

documentation

there's no documentation right now, which is a bad situation to be in.

parser overhaul

the way the parser works now is kind of atrocious, so I should probably fix it.

zigler doesn't detect that zig has been cached in the zig directory of "deps"

results in this error:

** (CompileError) lib/zigler_test.ex:1: zig hasn't been downloaded. Run mix zigler.get_zig
expanding macro: Zigler.Compiler.before_compile/1
lib/zigler_test.ex:1: ZiglerTest (module)
(elixir) lib/kernel/parallel_compiler.ex:229: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.