Examples


...

hello.void
{   v_import("level-00/voidc_target.void");
    v_import("level-00/voidc_types.void");

    v_import("llvm-c/Core.void");
    v_import("llvm-c/TargetMachine.void");

    v_import("printf.void");
}

{   triple = LLVMGetDefaultTargetTriple();

    tr_v = v_alloca(LLVMTargetRef);

    LLVMGetTargetFromTriple(triple, tr_v, 0);

    tr = v_load(tr_v);

    cpu_name     = LLVMGetHostCPUName();
    cpu_features = LLVMGetHostCPUFeatures();

    target_machine =
        LLVMCreateTargetMachine
        (
            tr,
            triple,
            cpu_name,
            cpu_features,
            LLVMCodeGenLevelDefault,
            LLVMRelocPIC,                   //- WTF !?!
            LLVMCodeModelDefault
        );

    LLVMDisposeMessage(cpu_features);
    LLVMDisposeMessage(cpu_name);
    LLVMDisposeMessage(triple);

    //-----------------------------------------------------------------
    llvm_ctx = v_target_get_voidc_llvm_ctx();
    module = LLVMModuleCreateWithNameInContext("hello_mod", llvm_ctx);

    builder = v_target_get_voidc_builder();


    int_ = v_type_get_llvm_type(int);

    main_ft_ = LLVMFunctionType(int_, 0, 0, false);
    main_f   = LLVMAddFunction(module, "main", main_ft_);

    entry = LLVMAppendBasicBlockInContext(llvm_ctx, main_f, "entry");

    LLVMPositionBuilderAtEnd(builder, entry);


    typ_ = v_alloca(LLVMTypeRef);

    char_     = v_type_get_llvm_type(char);
    char_ptr_ = LLVMPointerType(char_, 0);

    v_store(char_ptr_, typ_);

    printf_ft_ = LLVMFunctionType(int_, typ_, 1, true);
    printf_f   = LLVMAddFunction(module, "printf", printf_ft_);

    str = LLVMBuildGlobalStringPtr(builder, "Hello world!\n", "str");

    val = v_alloca(LLVMValueRef);

    v_store(str, val);

    LLVMBuildCall2(builder, printf_ft_, printf_f, val, 1, "");


    null_ = LLVMConstNull(int_);

    LLVMBuildRet(builder, null_);


    LLVMClearInsertionPosition(builder);

    //-----------------------------------------------------------------
    msg = LLVMPrintModuleToString(module);

    printf("\n%s\n", msg);

    LLVMDisposeMessage(msg);

    //-----------------------------------------------------------------
    LLVMTargetMachineEmitToFile(target_machine,
                                module,
                                "hello.o",
                                LLVMObjectFile,
                                0);

    //-----------------------------------------------------------------
    LLVMDisposeModule(module);

    LLVMDisposeTargetMachine(target_machine);
}

{   typ = v_alloca(v_type_ptr);

    char_ptr = v_pointer_type(char, 0);

    v_store(char_ptr, typ);

    system_ft = v_function_type(int, typ, 1, false);

    v_add_symbol("system", system_ft, 0);
}

{   system("clang hello.o -o hello");

    system("bash -c ./hello");
}

...


...

macros_test.void
{   v_import("level-00");
    v_import("level-01");
    v_import("level-02");

    v_import("level-03/intrinsics_derive.void");
    v_import("level-03/local_objects.void");
    v_import("level-03/heap_objects.void");
    v_import("level-03/global_objects.void");
    v_import("level-03/coercions.void");
    v_import("level-03/namespaces.void");
    v_import("level-03/generics_etc.void");
    v_import("level-03/generating_ast.void");
    v_import("level-03/macros.void");

    v_import("printf.void");
}

{   v_enable_level_01();
    v_enable_level_02();

    voidc_enable_intrinsics_derive();
    voidc_enable_local_objects();
    voidc_enable_heap_objects();
    voidc_enable_global_objects();
    voidc_enable_coercions();
    voidc_enable_namespaces();
    voidc_enable_generics_etc();
    voidc_enable_generating_ast();
    voidc_enable_macros();
}

//---------------------------------------------------------------------
#define foo: (x, y) = x*y;

{   v = foo(6, 7);

    printf("v: %d\n", v);
}

#define bar: (v) = printf("bar: %d\n", v);

{   bar(777);
}


//---------------------------------------------------------------------
#define fact: (n) =
(
    #if (n <= 0)    1
    #else           n * fact(n-1)
    #endif
);

{   n = 7;

    printf("fact(%d): %d\n", n, fact(n));
}


//---------------------------------------------------------------------
#define fib: (n)  =
{
    #define fibb: (a, b, m)  =
    (
        #if (m > 0) fibb(b, a+b, m-1)
        #else       a
        #endif
    );

    fibb(0, 1, n)
};

{   n = 19;

    printf("fib(%d): %d\n", n, fib(n));
}


//---------------------------------------------------------------------
#define FOO: (x, y = 40+x)  =  x + y;

{
    printf("FOO(1, 1): %d\n", FOO(1, 1));

    printf("FOO(1): %d\n", FOO(1));
}


//---------------------------------------------------------------------
#define (_*_): (s: v_std_string_t, n) ~> v_std_string_t  =
{
    tmp: &v_std_string_t := {};

    str = v_std_string_get(&s);

    for (i: &int := 0; i < n; ++i)
    {
        v_std_string_append(&tmp, str);
    }

    tmp
};

#define (_.str): (s: *const char) ~> v_std_string_t  =
{
    tmp: &v_std_string_t := {};

    v_std_string_set(&tmp, s);

    tmp
};


//{ voidc_verify_jit_module_optimized(true); }
//{ v_debug_print_module(2); }
{   ns = ("Qwe" : *const char).str * 7;

    printf("ns: %s\n", v_std_string_get(&ns));
}


#define (_*_): (a: char[4], n) ~> v_std_string_t  =  (a: *const char).str * n;

{   ns = "Asd" * 8;

    printf("ns: %s\n", v_std_string_get(&ns));
}

#define (_.c_str): (s: &v_std_string_t) ~>       *char  =  v_std_string_get(&s);
#define (_.c_str): (s:  v_std_string_t) ~> *const char  =  v_std_string_get(&s);

{   ns = "Zxc" * 9;

    printf("ns: %s\n", ns.c_str);
}


#define (_[]): (s: &v_std_string_t, i) ~> &char  =  s.c_str[i];
#define (_[]): (s:  v_std_string_t, i) ~>  char  =  s.c_str[i];

{   ns = "Zxc" * 10;

    for (i: &int := 0; i < 10; ++i)   printf("ns[%d]: %c\n", i, ns[i]);
}


#define str: (s)  =  (s: *const char);

{
    printf("[%s]\n", (str("Qwerty").str * 5).c_str);
}


//=====================================================================
{   v_import("macros_mod_test.void"); }


//---------------------------------------------------------------------
#do (my.instantiate_list(int),
     my.instantiate_list(long))


//---------------------------------------------------------------------
{
    l: &my.list(int) := {};

    l << 5
      << 6
      << 7
      << 8
      << 9;

    for (i: &int := 0, n = l.size; i < n; ++i)
    {
        printf("l[%d]: %d\n", i, l[i]);
    }

    l0: my.list(int) = {};

    l1 = l0 << 55;

    l2 = l1 << 66 << 77;

    l3 = l2 << 88 << 99;

    ll: &my.list(int)[4] := { l0, l1, l2, l3 };

    for (i: &int := 0; i < 4; ++i)
    {
        for (j: &int := 0, n = ll[i].size; j < n; ++j)
        {
            printf("ll[%d][%d]: %d\n", i, j, ll[i][j]);
        }
    }


    l.impl;     //- WTF !?!?!?!?!?!?!
}


//---------------------------------------------------------------------
#define instantiate_list_plus: (T)
{'unit_defn_list'

    (_+_): (a: my.list(T), b: my.list(T)) ~> my.list(T)  =
    {
        tmp: &my.list(T) := a;

        for (i: &int := 0, n = b.size; i < n; ++i)
        {
            tmp << b[i];
        }

        tmp
    };

'unit_defn_list'}


#do (instantiate_list_plus(long))


//{ voidc_verify_jit_module_optimized(true); }
//{ v_debug_print_module(2); }
//---------------------------------------------------------------------
{
    a: my.list(long) = { 9, 8, 7, 6, 5 };
    b: my.list(long) = { 4, 3 };

    l = a + b +  { 2, 1, 0 };

    for (i: &int := 0, n = l.size; i < n; ++i)
    {
        printf("l[%d]: %ld\n", i, l[i]);
    }
}
macros_mod_test.void
{   v_import("level-00");
    v_import("level-01");
    v_import("level-02");

    v_import("level-03/intrinsics_derive.void");
    v_import("level-03/local_objects.void");
    v_import("level-03/heap_objects.void");
    v_import("level-03/global_objects.void");
    v_import("level-03/coercions.void");
    v_import("level-03/namespaces.void");
    v_import("level-03/generics_etc.void");
    v_import("level-03/generating_ast.void");
    v_import("level-03/macros.void");

    v_import("printf.void");
}

{   v_enable_level_01();
    v_enable_level_02();

    voidc_enable_intrinsics_derive();
    voidc_enable_local_objects();
    voidc_enable_heap_objects();
    voidc_enable_global_objects();
    voidc_enable_coercions();
    voidc_enable_namespaces();
    voidc_enable_generics_etc();
    voidc_enable_generating_ast();
    voidc_enable_macros();
}

//---------------------------------------------------------------------
{   q_ref = v_reference_type(v_quark_t, 0);

    q = v_quark_ptr_from_string;

    v_add_symbol("list_q", q_ref, q("my.list"));

    v_add_symbol("q_static_type_t", q_ref, q("v_static_type_t"));
}


//=====================================================================
{   voidc_unit_begin_module("macros_mod_test_module"); }


//---------------------------------------------------------------------
export
namespace my {


//---------------------------------------------------------------------
#define list: (T: v_static_type_t) ~> v_static_type_t  =  v_generic("my.list", t(T));


//---------------------------------------------------------------------
private
list_op_braces_intrinsic: (aux: *void, vis: *voidc_visitor_t, self: *v_ast_base_t,
                           arg_ptrs: **v_ast_expr_t, arg_count: unsigned
                          ) ~> void
{
//printf("list_op_braces_intrinsic: start\n");
//defer printf("list_op_braces_intrinsic: stop\n");

    tr: &*v_type_t := v_get_result_type();

    is_reference = v_type_is_reference(tr);

    addr_sp: &unsigned := undef;

    if (is_reference)
    {
        addr_sp := v_type_refptr_get_address_space(tr);         //- Sic!
        tr      := v_type_refptr_get_element_type(tr);          //- Sic!
    }

    vr: &LLVMValueRef := v_get_result_value();

    if (vr == 0)  vr := v_make_temporary(tr, 0);

    list: &v_ast_stmt_list_t :=
    {'stmt_list'

         my_any: &v_std_any_t := {};

         #define my_step: (lst, v)
         {'stmt_list'

             v_std_any_set_value(&my_any, v);

             v_list_append(lst, lst, &my_any);

         'stmt_list'}

    'stmt_list'};

    expr: &v_ast_expr_t[2] := {};

    v_ast_make_expr_compiled(expr+0, v_pointer_type(v_util_list_t, 0), vr);

    typ = (aux: *v_type_t);

    my_step_q = v_quark_from_string("my_step");

    stmt: &v_ast_stmt_t := {};

    for (i: &int := 0; i < arg_count; ++i)
    {
        v_reset_result();

        v_set_result_type(typ);

        v_ast_accept_visitor(arg_ptrs[i], vis);

        val = v_get_result_value();

        v_ast_make_expr_compiled(expr+1, typ, val);

        v_ast_make_stmt_call(&stmt, 0, my_step_q, expr, 2);

        v_list_append(&list, &list, &stmt);
    }

    v_ast_make_stmt_block(&stmt, &list, false);

    v_reset_result();

    v_ast_accept_visitor(&stmt, vis);

    if (is_reference) v_set_result_type(v_reference_type(tr, addr_sp));
    else              v_set_result_type(tr);

    v_set_result_value(vr);
}

//---------------------------------------------------------------------
private
register_list_op_braces_intrinsic: (*void, vis: *voidc_visitor_t, self: *v_ast_base_t) ~> void
{
    args = v_ast_expr_call_get_arg_list((self: *v_ast_expr_t));

    arg0 = v_list_get_item(args, 0);        //- Element type
    arg1 = v_list_get_item(args, 1);        //- List type

    static_type_t = v_find_type_q(q_static_type_t);

    v_reset_result();

    v_set_result_type(static_type_t);

    v_ast_accept_visitor(arg0, vis);

    elt = (v_get_result_value() : *v_type_t);

    v_reset_result();

    v_set_result_type(static_type_t);

    v_ast_accept_visitor(arg1, vis);

    lst = (v_get_result_value() : *v_type_t);

    sstr: &v_std_string_t := {};

    v_std_string_set(&sstr, "my.list_op_braces-");

    voidc_internal_std_string_append_type(&sstr, elt);

    iname = v_std_string_get(&sstr);

    v_add_overload("v.op_braces", lst, iname);

    v_add_intrinsic(iname, list_op_braces_intrinsic, elt);      //- Sic!
}


//---------------------------------------------------------------------
#define instantiate_list: (T)
{'unit_defn_list'

  namespace my
  {
    #do (v_set_implementation_type(list(T), v_util_list_t))

    private
    namespace v_generic_ns(list_detail, t(T))
    {
        impl_t = v_get_implementation_type(list(T));

        alwaysinline
        (_.impl): (s: &list(T)) ~> &impl_t  =  *(&s : *impl_t);
    }

    //-------------------------------------------------------------
    inlinehint
    (v_initialize(_)): (sp: *list(T), N: size_t) ~> void
    {
        v_initialize(&sp->impl, N);

        for (i: &int := 0; i < N; ++i)
        {
            v_make_list_nil(&sp[i].impl);
        }
    }

    alwaysinline
    (v_terminate(_)): (sp: *list(T), N: size_t) ~> void
    {
        v_terminate(&sp->impl, N);
    }

    alwaysinline
    (v_copy(_)): (dst: *list(T), src: *const list(T), N: size_t) ~> void
    {
        v_copy(&dst->impl, &src->impl, N);
    }

    #do (register_list_op_braces(T, list(T)))

    //-------------------------------------------------------------
    inlinehint
    (_[]): (sp: list(T), i: size_t) ~> T
    {
        a = v_list_get_item(&sp.impl, i);
        v_assert(a);

        return  v_std_any_get_value(T, a);
    }

    inlinehint
    (_<<_): (sp: list(T), v: T) ~> list(T)
    {
        a: &v_std_any_t := {};

        v_std_any_set_value(&a, v);

        v_list_append(&v_get_return_value().impl, &sp.impl, &a);
    }

    inlinehint
    (_<<_): (sp: &list(T), v: T) ~> &list(T)  =
    {
        a: &v_std_any_t := {};

        v_std_any_set_value(&a, v);

        lst = &sp.impl;

        v_list_append(lst, lst, &a);

        sp
    };

    alwaysinline
    (_.size): (sp: list(T)) ~> size_t  =  v_list_get_size(&sp.impl);

  }   //- namespace my

'unit_defn_list'}


//---------------------------------------------------------------------
enable_list_effort: (*void) ~> void
{
    v_add_intrinsic("register_list_op_braces", register_list_op_braces_intrinsic, 0);
}


//---------------------------------------------------------------------
}   //- namespace my


//=====================================================================
{   voidc_unit_end_module(); }


//---------------------------------------------------------------------
{   v_export_effort(my.enable_list_effort, 0); }

...


...

geometry.void
{ voidc_import("libvoidc.void"); }
{ voidc_make_header("geometry"); }
//---------------------------------------------------------------------
{
    v_export_import("cstdio.void");
    v_export_import("type_traits.void");
}


//---------------------------------------------------------------------
double = float(64);

fabs: (double) ~> double;


//---------------------------------------------------------------------
#define (_<<_): (f: *FILE, v) ~> *FILE  =
{
    t = typeof(v);

  #if (t.is_reference)

    t = t.element_type;

  #endif

  #if ((t.is_array  ||  t.is_pointer)  &&  t.element_type == char)

    fprintf(f, "%s", v);

  #else

    v.print_to_file(f);

  #endif

    f
};


//---------------------------------------------------------------------
namespace Geometry
{


//---------------------------------------------------------------------
is_equal: (x: double, y: double) ~> bool;

alwaysinline
is_finite: (x: double) ~> bool  =  fabs(x) < 1e15;      //- ?...

infinity = 1e1000;

det_3: (v: &double[9]) ~> double;

seq_equal: (a: *const double, b: *const double, n: int) ~> bool;


//=====================================================================
//- Vector (2D)
//=====================================================================
struct Vector
{
    x: double;
    y: double;
};

(_.print_to_file()): (v: Vector, f: *FILE) ~> void;

//---------------------------------------------------------------------
alwaysinline
(_+_): (a: Vector, b: Vector) ~> Vector  =  {a.x+b.x, a.y+b.y};

alwaysinline
(_-_): (a: Vector, b: Vector) ~> Vector  =  {a.x-b.x, a.y-b.y};

alwaysinline
(+_): (a: Vector) ~> Vector  =  a;

alwaysinline
(-_): (a: Vector) ~> Vector  =  {-a.x, -a.y};

alwaysinline
(_*_): (a: Vector, k: double) ~> Vector  =  {a.x*k, a.y*k};

alwaysinline
(_*__): (k: double, a: Vector) ~> Vector  =  {k*a.x, k*a.y};

alwaysinline
(_/_): (a: Vector, k: double) ~> Vector  =  {a.x/k, a.y/k};

(_==_): (a: Vector, b: Vector) ~> bool;

alwaysinline
(_!=_): (a: Vector, b: Vector) ~> bool  =  !(a == b);

//---------------------------------------------------------------------
namespace Vector
{
    zero:     Vector = {0, 0};
    unit_x:   Vector = {1, 0};
    unit_y:   Vector = {0, 1};
    infinity: Vector = {infinity, infinity};
}

//---------------------------------------------------------------------
alwaysinline
(_.dot()): (a: Vector, b: Vector) ~> double  =  a.x*b.x + a.y*b.y;

alwaysinline
(_.crs()): (a: Vector, b: Vector) ~> double  =  a.x*b.y - a.y*b.x;

alwaysinline
(_.is_finite()): (a: Vector) ~> bool  =  is_finite(a.x)  &&  is_finite(a.y);


//=====================================================================
//- Projective point (2D)
//=====================================================================
struct Point
{
    x: double;
    y: double;
    w: double;
};

//---------------------------------------------------------------------
(_.print_to_file()): (p: Point, f: *FILE) ~> void;

//---------------------------------------------------------------------
alwaysinline
(_+_): (p: Point, v: Vector) ~> Point  =  {p.x + p.w*v.x, p.y + p.w*v.y, p.w};

#define (_-_): (a: Point, b)  =
{
    t = typeof(b);

  #if (t.is_reference)  t = t.element_type;   #endif

  #if (t == Point)

    ret: Vector = {a.x/a.w - b.x/b.w, a.y/a.w - b.y/b.w};

  #endif

  #if (t == Vector)

    ret: Point = {a.x - a.w*b.x, a.y - a.w*b.y, a.w};

  #endif

    ret
};

//---------------------------------------------------------------------
(_.norm()): (p: &Point) ~> bool;

(_.is_affine()): (p: &Point) ~> bool;

(_==_): (a: &Point, b: &Point) ~> bool;

alwaysinline
(_!=_): (a: &Point, b: &Point) ~> bool  =  !(a == b);

//---------------------------------------------------------------------
namespace Point
{
    zero:   Point = {0, 0, 1};
    unit_x: Point = {1, 0, 1};
    unit_y: Point = {0, 1, 1};
    inf_x:  Point = {1, 0, 0};
    inf_y:  Point = {0, 1, 0};
}


//=====================================================================
//- Projective line (2D)
//=====================================================================
struct Line
{
    cx: double;
    cy: double;
    cw: double;
};

//---------------------------------------------------------------------
(_.print_to_file()): (l: Line, f: *FILE) ~> void;

//---------------------------------------------------------------------
alwaysinline
(_+_): (l: Line, v: Vector) ~> Line  =  {l.cx, l.cy, l.cw - l.cx*v.x - l.cy*v.y};

alwaysinline
(_-_): (l: Line, v: Vector) ~> Line  =  {l.cx, l.cy, l.cw + l.cx*v.x + l.cy*v.y};

//---------------------------------------------------------------------
(_.norm()): (l: &Line) ~> bool;

(_.is_affine()): (l: &Line) ~> bool;

(_==_): (a: &Line, b: &Line) ~> bool;

alwaysinline
(_!=_): (a: &Line, b: &Line) ~> bool  =  !(a == b);

//---------------------------------------------------------------------
namespace Line
{
    infinity: Line = {0, 0, 1};
    abscissa: Line = {0, 1, 0};
    ordinate: Line = {1, 0, 0};
}


//=====================================================================
(_.incident()): (l: &Line, p: &Point) ~> bool;

//---------------------------------------------------------------------
alwaysinline
(_&_): (a: Point, b: Point) ~> Line  =  {a.y*b.w - a.w*b.y, a.w*b.x - a.x*b.w, a.x*b.y - a.y*b.x};

alwaysinline
(_&_): (a: Line, b: Line) ~> Point  =  {a.cy*b.cw - a.cw*b.cy, a.cw*b.cx - a.cx*b.cw, a.cx*b.cy - a.cy*b.cx};


//=====================================================================
//- Projective transformation (2D)
//=====================================================================
struct Transform
{
    double[9];
};

//---------------------------------------------------------------------
(_.print_to_file()): (t: &Transform, f: *FILE) ~> void;

//---------------------------------------------------------------------
(_.norm()): (t: &Transform) ~> bool;

(_.is_regular()): (t: &Transform) ~> bool;

(_.is_affine()): (t: &Transform) ~> bool;

(_==_): (a: &Transform, b: &Transform) ~> bool;

alwaysinline
(_!=_): (a: &Transform, b: &Transform) ~> bool  =  !(a == b);

//---------------------------------------------------------------------
alwaysinline
(_.det()): (t: &Transform) ~> double  =  det_3(t[0]);


//---------------------------------------------------------------------
#define (_()): (t: Transform, v)  =  v.transform_by(t);

//---------------------------------------------------------------------
(_.transform_by()): (v: Vector, t: Transform) ~> Vector;
(_.transform_by()): (p: Point, t: Transform) ~> Point;
(_.transform_by()): (l: Line, t: Transform) ~> Line;

//---------------------------------------------------------------------
(_+_): (t: Transform, v: Vector) ~> Transform;

alwaysinline
(_-_): (t: Transform, v: Vector) ~> Transform  =  t + -v;

(_*_): (a: Transform, b: Transform) ~> Transform;
(_*__): (k: double, t: Transform) ~> Transform;

(~_): (t: Transform) ~> Transform;

(_/_): (a: Transform, b: Transform) ~> Transform;

//---------------------------------------------------------------------
alwaysinline
(_.scaled()): (t: Transform, k: double) ~> Transform  =  k * t;

alwaysinline
(_.shifted()): (t: Transform, v: Vector) ~> Transform  =  t + v;

(_.rotated()): (t: Transform, d: double) ~> Transform;

//---------------------------------------------------------------------
namespace Transform
{
    map4: (i1: &Point, i2: &Point, i3: &Point, i4: &Point,
           o1: &Point, o2: &Point, o3: &Point, o4: &Point
          ) ~> Transform;

    map3: (i1: &Point, i2: &Point, i3: &Point,
           o1: &Point, o2: &Point, o3: &Point
          ) ~> Transform;

    map2: (i1: &Point, i2: &Point,
           o1: &Point, o2: &Point
          ) ~> Transform;

    map2_mirror: (i1: &Point, i2: &Point,
                  o1: &Point, o2: &Point
                 ) ~> Transform;

    //------------------------------------------------------
    identity: Transform = {{ 1, 0, 0,  0, 1, 0,  0, 0, 1 }};
    flip_x:   Transform = {{-1, 0, 0,  0, 1, 0,  0, 0, 1 }};
    flip_y:   Transform = {{ 1, 0, 0,  0,-1, 0,  0, 0, 1 }};
}

//---------------------------------------------------------------------
}   //- namespace Geometry
geometry_mod.void
{ v_import("libvoidc.void"); }
{ voidc_make_module("geometry"); }
//---------------------------------------------------------------------
{
    v_import("geometry.void");
}


//---------------------------------------------------------------------
sin: (double) ~> double;
cos: (double) ~> double;

M_PI = 3.14159265358979323846264338327950288419716939937510582;


//---------------------------------------------------------------------
namespace Geometry
{


//---------------------------------------------------------------------
EPSILON = 1e-9;

is_equal: (x: double, y: double) ~> bool
{
    if (x == y)  return true;

    size = fabs(x) + fabs(y);

    if (size <= EPSILON)  return true;

    diff = fabs(x - y);

    if (diff <= EPSILON)  return true;

    if (size > 1  &&  diff/size <= EPSILON)  return true;

    return  false;
}

det_3: (v: &double[9]) ~> double
{
    v00 = v[0]; v01 = v[1]; v02 = v[2];
    v10 = v[3]; v11 = v[4]; v12 = v[5];
    v20 = v[6]; v21 = v[7]; v22 = v[8];

    return  v00 * (v11*v22 - v12*v21)
          - v10 * (v01*v22 - v02*v21)
          + v20 * (v01*v12 - v02*v11);
}


//---------------------------------------------------------------------
seq_equal: (a: *const double, b: *const double, n: int) ~> bool
{
    ret: &bool := true;

    for (i: &int := 0; i < n; ++i)  if (!is_equal( a[i], b[i]))  { ret := false;  break; }

    if (ret)  return true;

    for (i: &int := 0; i < n; ++i)  if (!is_equal(-a[i], b[i]))  { return false; }

    return  true;
}


//=====================================================================
//- Vector (2D)
//=====================================================================
(_.print_to_file()): (v: Vector, f: *FILE) ~> void
{
    fprintf(f, "(%g, %g)", v.x, v.y);
}

(_==_): (a: Vector, b: Vector) ~> bool
{
    return  is_equal(a.x, b.x)  &&  is_equal(a.y, b.y);
}


//=====================================================================
//- Projective point (2D)
//=====================================================================
(_.print_to_file()): (p: Point, f: *FILE) ~> void
{
    fprintf(f, "(%g, %g, %g)", p.x, p.y, p.w);
}

//---------------------------------------------------------------------
(_.norm()): (p: &Point) ~> bool
{
    pa: &double[3] := {p.x, p.y, p.w};

    d: &double := 0;

    for (i: &int := 0; i < 3; ++i)
    {
        if (!is_finite(pa[i]))  return false;

        if (di = fabs(pa[i]), d < di)   d := di;
    }

    if (d == 0)  return false;
    if (d == 1)  return true;

    p.x /= d;
    p.y /= d;
    p.w /= d;

    return  true;
}

//---------------------------------------------------------------------
(_.is_affine()): (p: &Point) ~> bool
{
    if (!p.norm())  return false;

    return  fabs(p.w) > EPSILON;
}

//---------------------------------------------------------------------
(_==_): (a: &Point, b: &Point) ~> bool
{
    if (!(a.norm()  &&  b.norm()))  return false;

    sa: &double[] := {a.x, a.y, a.w};
    sb: &double[] := {b.x, b.y, b.w};

    return  seq_equal(sa, sb, 3);
}


//=====================================================================
//- Projective line (2D)
//=====================================================================
(_.print_to_file()): (l: Line, f: *FILE) ~> void
{
    fprintf(f, "(%g, %g, %g)", l.cx, l.cy, l.cw);
}

//---------------------------------------------------------------------
(_.norm()): (l: &Line) ~> bool
{
    la: &double[3] := {l.cx, l.cy, l.cw};

    d: &double := 0;

    for (i: &int := 0; i < 3; ++i)
    {
        if (!is_finite(la[i]))  return false;

        if (di = fabs(la[i]), d < di)   d := di;
    }

    if (d == 0)  return false;
    if (d == 1)  return true;

    l.cx /= d;
    l.cy /= d;
    l.cw /= d;

    return  true;
}

//---------------------------------------------------------------------
(_.is_affine()): (l: &Line) ~> bool
{
    if (!l.norm())  return false;

    return  fabs(l.cx) > EPSILON  ||  fabs(l.cy) > EPSILON;
}

//---------------------------------------------------------------------
(_==_): (a: &Line, b: &Line) ~> bool
{
    if (!(a.norm()  &&  b.norm()))  return false;

    sa: &double[] := {a.cx, a.cy, a.cw};
    sb: &double[] := {b.cx, b.cy, b.cw};

    return  seq_equal(sa, sb, 3);
}


//=====================================================================
(_.incident()): (l: &Line, p: &Point) ~> bool
{
    l.norm();
    p.norm();

    return  fabs(l.cx*p.x + l.cy*p.y + l.cw*p.w) < EPSILON;
}


//=====================================================================
//- Projective transformation (2D)
//=====================================================================
(_.print_to_file()): (t: &Transform, f: *FILE) ~> void
{
    t = t[0];

    fprintf(f, "(%g, %g, %g, %g, %g, %g, %g, %g, %g)", t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8]);
}

//---------------------------------------------------------------------
(_.norm()): (t: &Transform) ~> bool
{
    t = t[0];

    d: &double := 0;

    for (i: &int := 0; i < 9; ++i)
    {
        if (!is_finite(t[i]))  return false;

        if (di = fabs(t[i]), d < di)  d := di;
    }

    if (d == 0)  return false;
    if (d == 1)  return true;

    for (i: &int := 0; i < 9; ++i)
    {
        t[i] /= d;
    }

    return  true;
}

//---------------------------------------------------------------------
(_.is_regular()): (t: &Transform) ~> bool
{
    if (!t.norm())  return false;

    return  fabs(t.det()) > EPSILON;
}

//---------------------------------------------------------------------
(_.is_affine()): (t: &Transform) ~> bool
{
    if (!t.norm())  return false;

    t = t[0];

    return  fabs(t[6]) <= EPSILON  &&
            fabs(t[7]) <= EPSILON  &&
            fabs(t[8]) >  EPSILON;
}

//---------------------------------------------------------------------
(_==_): (a: &Transform, b: &Transform) ~> bool
{
    if (!(a.norm()  &&  b.norm()))  return false;

    return  seq_equal(a[0], b[0], 9);
}

//---------------------------------------------------------------------
(_.transform_by()): (v: Vector, t: Transform) ~> Vector
{
    t = t[0];

    x = t[0]*v.x + t[1]*v.y + t[2];
    y = t[3]*v.x + t[4]*v.y + t[5];
    w = t[6]*v.x + t[7]*v.y + t[8];

    return  { x/w, y/w };
}

(_.transform_by()): (p: Point, t: Transform) ~> Point
{
    t = t[0];

    x = t[0]*p.x + t[1]*p.y + t[2]*p.w;
    y = t[3]*p.x + t[4]*p.y + t[5]*p.w;
    w = t[6]*p.x + t[7]*p.y + t[8]*p.w;

    return  { x, y, w };
}

(_.transform_by()): (l: Line, t: Transform) ~> Line
{
    t = t[0];

    cx = det_3({ l.cx, t[3], t[6],
                 l.cy, t[4], t[7],
                 l.cw, t[5], t[8] });

    cy = det_3({ t[0], l.cx, t[6],
                 t[1], l.cy, t[7],
                 t[2], l.cw, t[8] });

    cw = det_3({ t[0], t[3], l.cx,
                 t[1], t[4], l.cy,
                 t[2], t[5], l.cw });

    return  { cx, cy, cw };
}

//---------------------------------------------------------------------
(_+_): (t: Transform, v: Vector) ~> Transform
{
    t = t[0];

    xx = t[0] + v.x*t[6];
    xy = t[1] + v.x*t[7];
    xw = t[2] + v.x*t[8];

    yx = t[3] + v.y*t[6];
    yy = t[4] + v.y*t[7];
    yw = t[5] + v.y*t[8];

    wx = t[6];
    wy = t[7];
    ww = t[8];

    return  {{ xx, xy, xw,
               yx, yy, yw,
               wx, wy, ww }};
}

//---------------------------------------------------------------------
(_*_): (a: Transform, b: Transform) ~> Transform
{
    a = a[0];
    b = b[0];

    xx = a[0]*b[0] + a[1]*b[3] + a[2]*b[6];
    xy = a[0]*b[1] + a[1]*b[4] + a[2]*b[7];
    xw = a[0]*b[2] + a[1]*b[5] + a[2]*b[8];

    yx = a[3]*b[0] + a[4]*b[3] + a[5]*b[6];
    yy = a[3]*b[1] + a[4]*b[4] + a[5]*b[7];
    yw = a[3]*b[2] + a[4]*b[5] + a[5]*b[8];

    wx = a[6]*b[0] + a[7]*b[3] + a[8]*b[6];
    wy = a[6]*b[1] + a[7]*b[4] + a[8]*b[7];
    ww = a[6]*b[2] + a[7]*b[5] + a[8]*b[8];

    return  {{ xx, xy, xw,
               yx, yy, yw,
               wx, wy, ww }};
}

(_*__): (k: double, t: Transform) ~> Transform
{
    t = t[0];

    xx = k*t[0];
    xy = k*t[1];
    xw = k*t[2];

    yx = k*t[3];
    yy = k*t[4];
    yw = k*t[5];

    wx =   t[6];
    wy =   t[7];
    ww =   t[8];

    return  {{ xx, xy, xw,
               yx, yy, yw,
               wx, wy, ww }};
}

//---------------------------------------------------------------------
(~_): (t: Transform) ~> Transform
{
    t = t[0];

    xx = t[4]*t[8] - t[5]*t[7];
    xy = t[2]*t[7] - t[1]*t[8];
    xw = t[1]*t[5] - t[2]*t[4];

    yx = t[5]*t[6] - t[3]*t[8];
    yy = t[0]*t[8] - t[2]*t[6];
    yw = t[2]*t[3] - t[0]*t[5];

    wx = t[3]*t[7] - t[4]*t[6];
    wy = t[1]*t[6] - t[0]*t[7];
    ww = t[0]*t[4] - t[1]*t[3];

    r: &Transform := {{ xx,xy,xw, yx,yy,yw, wx,wy,ww }};

    if (r.det() < 0)
    {
        r = r[0];

        for (i: &int := 0; i < 9; ++i)  r[i] := -r[i];
    }

    return  r;
}

//---------------------------------------------------------------------
(_/_): (a: Transform, b: Transform) ~> Transform
{
    return  a * (~b);
}

//---------------------------------------------------------------------
(_.rotated()): (t: Transform, d: double) ~> Transform
{
    a = d * (M_PI/180);

    sa = sin(a);
    ca = cos(a);

    r: Transform = {{  ca, -sa,  0,
                       sa,  ca,  0,
                        0,   0,  1  }};

    return  r * t;
}

//---------------------------------------------------------------------
private
map4_util: (o1: &Point, o2: &Point, o3: &Point, o4: &Point) ~> Transform
{
    o1.norm();
    o2.norm();
    o3.norm();
    o4.norm();

    a1 = det_3({ o4.x, o2.x, o3.x,
                 o4.y, o2.y, o3.y,
                 o4.w, o2.w, o3.w });

    a2 = det_3({ o1.x, o4.x, o3.x,
                 o1.y, o4.y, o3.y,
                 o1.w, o4.w, o3.w });

    a3 = det_3({ o1.x, o2.x, o4.x,
                 o1.y, o2.y, o4.y,
                 o1.w, o2.w, o4.w });

    return  {{ o1.x*a1, o2.x*a2, o3.x*a3,
               o1.y*a1, o2.y*a2, o3.y*a3,
               o1.w*a1, o2.w*a2, o3.w*a3 }};
}

//---------------------------------------------------------------------
Transform.map4: (i1: &Point, i2: &Point, i3: &Point, i4: &Point,
                 o1: &Point, o2: &Point, o3: &Point, o4: &Point
                ) ~> Transform
{
    t1 = map4_util(i1, i2, i3, i4);
    t2 = map4_util(o1, o2, o3, o4);

    return  t2 / t1;
}

Transform.map3: (i1: &Point, i2: &Point, i3: &Point,
                 o1: &Point, o2: &Point, o3: &Point
                ) ~> Transform
{
    i4 = i3 + (i2 - i1);
    o4 = o3 + (o2 - o1);

    return  Transform.map4(i1, i2, i3, i4,  o1, o2, o3, o4);
}

Transform.map2: (i1: &Point, i2: &Point,
                 o1: &Point, o2: &Point
                ) ~> Transform
{
    v = i2 - i1;    v: Vector = { -v.y, v.x };

    i3 = i1 + v;

    v = o2 - o1;    v: Vector = { -v.y, v.x };

    o3 = o1 + v;

    return  Transform.map3(i1, i2, i3,  o1, o2, o3);
}

Transform.map2_mirror: (i1: &Point, i2: &Point,
                        o1: &Point, o2: &Point
                       ) ~> Transform
{
    v = i2 - i1;    v: Vector = { -v.y, v.x };

    i3 = i1 + v;

    v = o2 - o1;    v: Vector = { v.y, -v.x };

    o3 = o1 + v;

    return  Transform.map3(i1, i2, i3,  o1, o2, o3);
}

//---------------------------------------------------------------------
}   //- namespace Geometry


//---------------------------------------------------------------------
{ voidc_emit_module("geometry_mod.o"); }
//---------------------------------------------------------------------

...