Skip to content

hikogui/hikolang

Repository files navigation

hikolang

Windows Linux MacOS Version License Coverage

  • Safe Integers

  • Unit System

  • Hidden Context Arguments

  • Universal Call Syntax.

  • elaboration phase

  • language syntax is extendable

  • inline assembler

  • compile time reflection, types are values.

  • hidden dependency injection, both functions and structs.

  • enum only has named-values, it is not an integer.

  • function overloading, on both arguments (type and non-type) and return type.

Safe integers

All operations on integers will either:

  • always result in a mathematically correct result, or
  • the operation may throws an error that must be caught locally.

The int template type automatically scales to fit the full result of an operation:

fn foo(x : int[10..=20], y : int[2..=4]) {
    // return type is infered as int[20..=80]
    return x * y
}

int is the basic integer type and the result of integer literals. The int with proper ranges are compatible with both signed and unsigned integers with C and C++.

The second integer type is long, this integer dynamically scales in size and is allocated on the heap, and includes SIO (Short Integer Optimization).

Units system

Real, rational and decimal types can be tagged with a unit, which is used for dimensional analysis.

let speed = 100.0 (km/h)
let duration = 15.0 min
let distance = speed * duration // 25.0 km

fn convert(length : real #iso.length, dpi : real #(screen.length/iso.length)) -> real #screen.length
{
    return length * dpi
}

Hidden Context Arguments

Context arguments reduces the need for global variables in many uses. It makes it easy to inject context in unit-tests as well.

fn foo(x) {
    // $y is used, which makes foo() require $y to be passed in.
    return x + $y
}

fn bar(x) {
    // $y is required by foo(), so bar requiress $y passed in.
    // $y is automatically and invisibly passed into foo()
    return foo(x)
}

fn qux(x, y) {
    // qux() does not allow $y to be passed in.
    // Pass in $y explicitly into bar.
    return bar(x, $y=y)
}

Universal call syntax

Functions and member functions may be called in two different ways:

  • foo(a, b)
  • a.foo(b)

Builtin Package Manager

The compiler will automatically clone and update git repositories that are imported with the import git statement. Repositories are cloned into the _hkdeps directory, by recursively scanning the repositories.

Directory structure within a repository is free-form; the compilation order is determined after scanning the prologue of each module (a file).

Elaboration Phase

Certain languages have a separate elaboration phase during compilation.

In this phase the compiler will fill in all:

  • type and non-type arguments of templates.
  • global variables.
  • Guaranteed full constant folding and function elimination.

The process basically does full constant folding by executing functions until no more functions can be executed.

It is a reportable error if any expression is left of which the value needs to be known for the next compilation phase.

Note: all functions by default can be executed at compile time. Note: full constant folding allows generic/templated functions without a special syntax. Note: since low level functions are written as inline-assembly, inline-assembly must be executable during compile time, possibly using an interpreter/JIT.

Extensible syntax

Custom operators

The language allows you to define custom operators. This is done by registering a a keyword or pattern-syntax, arity, precedence and associativity, and a function that will be called when the operator is used.

Custom literals

The language allows you to define custom literals. This is done by registering a suffix-keyword and a function that will be called when the suffix is used with a literal.

The literal is passed to the function as a string, and the function determines the returned value and type. Since the function is called at compile time, it can dynamically create both the value and the type.

Inline assembly

Inline assembly is supported through the llvm directive. This allows you to write low-level LLVM assembly code directly in your source code. The inline assembly may even be executed during the elaboration phase.

function foo(a : __i32__, b : __i32__) -> __i32__
{
    var c = a &+ b
    var r = 0 : __i32__

    llvm {
        %tmp = mul i32 %c, %a
        store i32 %tmp, i32* %r.addr
    }

    return r
}

Compile time reflection

The language treats types as if they are first-class values. This means types themselves are of a meta-type, recursively.

Since types are values, you can interrigate and manipulate types at compile time. This allows you to write generic code that can work with any type, and even create new types at compile time.

Meta-types are defined as built-in, by the standard library, and can be extended by the user.

Extending syntax

There is macro system that allows you to match with tokens and replace it with a different expression.

About

The hikolang a system and application programming language.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

 

Packages

No packages published