units

package module
v0.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2020 License: Apache-2.0 Imports: 8 Imported by: 0

README

units

Introduction

This is a PoC for a code generation tool that builds code that enforces correct units in calculations in statically type safe code.

Getting Started

To build the example configuration file :

go build ./cmd/unitsgen && ./unitsgen -c ./example/example.units -o ./example/example.go

The tool works from a configuration file that is divided into three parts :

The unit section defines the base units for the calculations and any units that can be derived from the base units by multiplication or division. The names of units must follow the naming conventions of golang identifiers. The following example defines two base units m and s and three derived units km, h and kph :

unit (
  m;
  s;
  mps = m / s;
  km = 1000 * m;
  h = s * 3600;
  kmph = km / h;
)

The quantity section defines the set of quantities that are required for the calculations along with their unit. The name of the quantity will be the exact name of the type in the resulting golang code. The following example defines threee quantities :

quantity (
  Length(km);
  Time(h);
  Speed(kmph);
)

Each quantity is represented by an interface in the golang code, and is provided with a constructor function and a few default methods like this :

type Length  interface {
  Value() float64
  Unit() units.Unit
  ...
}

func NewLength(val float64) Length

The operations section defines the the operations that are allowed to perform on the quantities, to yield other quantities. Since this part is not obvious to understand, here is an example of the operation to generate a Speed, from a Length and a Time :

Length / Time -> Speed;

In terms of the golang code, this means that The Length quantity, will be generated with a method that looks something like this :

func (q _length) DivideTime(val Time) Speed {
  return NewSpeed(q.Value() / val.Value())
}

In terms of the calling code, you work like this :

  l := NewLength(100)
  t := NewTime(50)
  s := l.DivideTime(t)
  sKmph := s.Value()
  sMps, err := s.Convert(mps)

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ParseInto

func ParseInto(out interface{}, s string) error

Types

type Converter added in v0.0.3

type Converter interface {
	Convert(float64) float64
	ConvertPtr(*float64) *float64
}

func MustConvert added in v0.0.3

func MustConvert(c Converter, err error) Converter

func NewConverter added in v0.0.3

func NewConverter(from Unit, to Unit) (Converter, error)

type Expression

type Expression struct {
	Lhs      Term        `@@`
	Operator *string     `( @( "*" | "/")`
	Rhs      *Expression `@@)?`
}

func (Expression) Unit

func (exp Expression) Unit() (Unit, error)

type ScalarTerm

type ScalarTerm struct {
	Scale float64 `(@Number)`
}

func (ScalarTerm) Unit

func (st ScalarTerm) Unit() Unit

type Term

type Term struct {
	ScalarTerm *ScalarTerm `(@@ |`
	UnitTerm   *UnitTerm   `@@)?`
}

func (Term) Unit

func (t Term) Unit() Unit

type Unit

type Unit interface {
	String() string
	IsScalar() bool
	Equal(Unit) bool
	Subs(map[string]Unit) Unit
	Validate(map[string]Unit) error
	Invert() Unit
	Multiply(Unit) Unit
	Divide(Unit) Unit
	Scale() float64
}

func MustParse added in v0.0.3

func MustParse(u Unit, err error) Unit

func NewUnit

func NewUnit(name string, dim int) Unit

func Parse

func Parse(s string) (Unit, error)

func Scalar

func Scalar(scale float64) Unit

type UnitTerm

type UnitTerm struct {
	Name     string `@Ident`
	Exponent *int   `("^" @Number)?`
}

func (UnitTerm) Unit

func (t UnitTerm) Unit() Unit

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL