hexowl is a Lightweight and flexible programmer's calculator with user variables and functions support written in Go.
The main purpose of hexowl is to perform operations on numbers regardless of their base. A single expression can contain decimal, hexadecimal, and binary numbers.
- Support for operations on decimal, hexadecimal and binary numbers;
- Bitwise operators;
- Boolean operators;
- User defined variables;
- User defined functions;
- Ability to save and load the working environment.
go install github.com/dece2183/hexowl@latest
There are no dependencies, so you can simply type a build command in the cloned repository folder.
go build
If you want to disable syntax highlighting, you can add the nohighlight
tag:
go build -tags nohighlight
Operator | Syntax |
---|---|
Positive bits count | # |
Bitwise NOT | ~ |
Bitclear (AND NOT) | &~ &^ |
Bitwise XOR | ^ |
Bitwise AND | & |
Bitwise OR | | |
Right shift | >> |
Left shift | << |
Modulo | % |
Division | / |
Exponentiation | ** |
Multiplication | * |
Subtraction | - |
Addition | + |
Logical NOT | ! |
Less or equal | <= |
More or equal | >= |
Less | < |
More | > |
Not equal | != |
Equal | == |
Logical AND | && |
Logical OR | || |
Enumerate | , |
Bitwise OR and assign | |= |
Bitwise AND and assign | &= |
Divide and assign | /= |
Mutiply and assign | *= |
Add and assign | += |
Subtract and assign | -= |
Local assign | := |
Assign | = |
Sequence | ; |
Declare function | -> |
Constant | Value |
---|---|
pi |
3.141592653589793 |
e |
2.718281828459045 |
true |
1 |
false |
0 |
inf |
+Inf |
nan |
NaN |
nil |
nil |
help |
Help Message |
version |
hexowl version |
Function | Arguments | Description |
---|---|---|
acos |
(x ) |
The arccosine of the radian argument x |
asin |
(x ) |
The arcsine of the radian argument x |
atan |
(x ) |
The arctangent of the radian argument x |
ceil |
(x ) |
The least integer value greater than or equal to x |
clear |
( ) | Clear screen |
clfuncs |
( ) | Delete user defined functions |
clvars |
( ) | Delete user defined variables |
cos |
(x ) |
The cosine of the radian argument x |
envs |
( ) | List all available environments |
exit |
(code ) |
Exit with error code |
exp |
(x ) |
The base-e exponential of x |
floor |
(x ) |
The greatest integer value less than or equal to x |
funcs |
( ) | List alailable functions |
import |
(id ,unit ) |
Import unit from the working environment with id |
load |
(id ) |
Load working environment with id |
log10 |
(x ) |
The decimal logarithm of x |
log2 |
(x ) |
The binary logarithm of x |
logn |
(x ) |
The natural logarithm of x |
popcnt |
(x ) |
The number of one bits ("population count") in x |
pow |
(x ,y ) |
The base-x exponential of y |
rand |
(a ,b ) |
The random number in the range [a,b) or [0,1) if no arguments are passed |
rmfunc |
(name ) |
Delete user function with name |
rmfuncvar |
(name ,varid ) |
Delete user function name variation number varid |
rmvar |
(name ) |
Delete user variable with name |
round |
(x ) |
The nearest integer, rounding half away from zero |
save |
(envname ) |
Save working environment with envname |
sin |
(x ) |
The sine of the radian argument x |
sqrt |
(x ) |
The square root of x |
tan |
(x ) |
The tangent of the radian argument x |
vars |
( ) | List available variables |
To declare a function, you must type its name, explain the arguments in (
)
and write the body of the function after ->
operator.
It should look like this:
>: mul(a,b) -> a * b
Once declared, you can call this function as a builtin:
>: mul(2,4)
Result: 8
0x8
0b1000
Time: 0 ms
You can also create variants of functions with expressions right in the explanation of the arguments.
Let's look at a simple example of declaring a factorial function:
>: f(x == 0) -> 1
>: f(x > 0) -> x * f(x-1)
When calling such a function, the interpreter tries to find a suitable variant depending on the arguments passed, and then calls it.
You can define arrays with the enumerator operator ,
:
>: x = 1,2,3,4
All functions receive arguments as an array, so the expressions foo(x)
and foo(1,2,3,4)
are similar.
There is a single @
keyword to handle such things. If it is specified as the last argument in a function declaration, it will receive an array of the arguments passed to it. The behavior is similar to the ...
and __VA_ARGS__
preprocessor macros in C language.
An example of a function that calculates the sum of all elements of an array:
>: arrsum(a) -> a
>: arrsum(a, @) -> a+arrsum(@)
An example of a function that increments all elements of an array:
>: arrinc(v, a) -> a+v
>: arrinc(v, a, @) -> (a+v) , arrinc(v,@)
Hexowl is specially designed for use as an embeddable calculator.
An example of a minimal setup is shown below:
package main
import (
"fmt"
"github.com/dece2183/hexowl/operators"
"github.com/dece2183/hexowl/utils"
)
const expresion = "2+2"
func main() {
localVars := make(map[string]interface{})
words := utils.ParsePrompt(expresion)
operatorTree, err := operators.Generate(words, localVars))
if err != nil {
return err
}
result, err := operators.Calculate(operatorTree, localVars))
if err != nil {
return err
}
fmt.Printf("%s = %v", expresion, result);
}
For more specific designs, it is posible to provide an sdtout writer and callbacks for working with environment save files.
package main
import (
"bytes"
"fmt"
"io"
"github.com/dece2183/hexowl/builtin"
"github.com/dece2183/hexowl/builtin/types"
)
type dummyCloser bytes.Buffer
var outbuff = &bytes.Buffer{}
var envFiles map[string]*dummyCloser
func (dc *dummyCloser) Close() error {
return nil
}
func (dc *dummyCloser) Read(dest []byte) (int, error) {
b := bytes.Buffer(*dc)
return b.Read(dest)
}
func (dc *dummyCloser) Write(data []byte) (int, error) {
b := bytes.Buffer(*dc)
return b.Write(data)
}
func init() {
sysDesc := types.System{
Stdout: outbuff,
ListEnvironments: func() ([]string, error) {
return maps.Keys(envFiles), nil
},
WriteEnvironment: func(name string) (io.WriteCloser, error) {
if _, ok := envFiles[name]; !ok {
envFiles[name] = &dummyCloser{}
}
return envFiles[name], nil
},
ReadEnvironment: func(name string) (io.ReadCloser, error) {
if _, ok := envFiles[name]; !ok {
return nil, fmt.Errorf("not found")
}
return envFiles[name], nil
},
}
// Now all the additional output will be printed in outbuff.
// And environment files will be seved to and loaded from envFiles map.
builtin.SystemInit(sysDesc)
}
There are also functions for registering and manage self-written built-in functions and constants. They are described in hexowl/builtin
package.