From f8c841fa9938b0f7835984ed31ae884232d32230 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Thu, 23 Oct 2014 20:46:05 -0400 Subject: [PATCH] codegen the math library. that felt gross --- Makefile | 7 + core/Makefile | 2 + core/math.go | 669 ++++++++++++++++++++++++++++++++++++--- core/mathgen/mathgen.go | 84 +++++ core/mathgen/mathgen.tpl | 66 ++++ 5 files changed, 789 insertions(+), 39 deletions(-) create mode 100644 Makefile create mode 100644 core/Makefile create mode 100644 core/mathgen/mathgen.go create mode 100644 core/mathgen/mathgen.tpl diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3a8acf7 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +all: gen + +test: gen + go test ./... + +gen: + (cd core && make gen) diff --git a/core/Makefile b/core/Makefile new file mode 100644 index 0000000..d4f4b2b --- /dev/null +++ b/core/Makefile @@ -0,0 +1,2 @@ +gen: + go run mathgen/mathgen.go > math.go diff --git a/core/math.go b/core/math.go index 4c5c0f4..11679d4 100644 --- a/core/math.go +++ b/core/math.go @@ -16,123 +16,714 @@ func mathReduce(fn mathReduceFn, zero types.Elem, s seq.Seq) types.Elem { return seq.Reduce(reduceFn, zero, s) } + + + func plusInt(a, b types.Elem) types.Elem { - return types.GoType{Int(a) + Int(b)} + return types.GoType{ Int(a) + Int(b) } } func plusInt8(a, b types.Elem) types.Elem { - return types.GoType{Int8(a) + Int8(b)} + return types.GoType{ Int8(a) + Int8(b) } } func plusInt16(a, b types.Elem) types.Elem { - return types.GoType{Int16(a) + Int16(b)} + return types.GoType{ Int16(a) + Int16(b) } } func plusInt32(a, b types.Elem) types.Elem { - return types.GoType{Int32(a) + Int32(b)} + return types.GoType{ Int32(a) + Int32(b) } } func plusInt64(a, b types.Elem) types.Elem { - return types.GoType{Int64(a) + Int64(b)} + return types.GoType{ Int64(a) + Int64(b) } } func plusUint(a, b types.Elem) types.Elem { - return types.GoType{Uint(a) + Uint(b)} + return types.GoType{ Uint(a) + Uint(b) } } func plusUint8(a, b types.Elem) types.Elem { - return types.GoType{Uint8(a) + Uint8(b)} + return types.GoType{ Uint8(a) + Uint8(b) } } func plusUint16(a, b types.Elem) types.Elem { - return types.GoType{Uint16(a) + Uint16(b)} + return types.GoType{ Uint16(a) + Uint16(b) } } func plusUint32(a, b types.Elem) types.Elem { - return types.GoType{Uint32(a) + Uint32(b)} + return types.GoType{ Uint32(a) + Uint32(b) } } func plusUint64(a, b types.Elem) types.Elem { - return types.GoType{Uint64(a) + Uint64(b)} + return types.GoType{ Uint64(a) + Uint64(b) } } func plusFloat32(a, b types.Elem) types.Elem { - return types.GoType{Float32(a) + Float32(b)} + return types.GoType{ Float32(a) + Float32(b) } } func plusFloat64(a, b types.Elem) types.Elem { - return types.GoType{Float64(a) + Float64(b)} + return types.GoType{ Float64(a) + Float64(b) } } func plusComplex64(a, b types.Elem) types.Elem { - return types.GoType{Complex64(a) + Complex64(b)} + return types.GoType{ Complex64(a) + Complex64(b) } } func plusComplex128(a, b types.Elem) types.Elem { - return types.GoType{Complex128(a) + Complex128(b)} + return types.GoType{ Complex128(a) + Complex128(b) } } + func plusString(a, b types.Elem) types.Elem { - return types.GoType{String(a) + String(b)} + return types.GoType{ String(a) + String(b) } } func Plus(s seq.Seq) types.Elem { + var first, zero types.Elem + if seq.Empty(s) { - return types.GoType{0} + return types.GoType{ 0 } } + first, _, _ = s.FirstRest() + - first, _, _ := s.FirstRest() var fn mathReduceFn - var zero types.Elem switch first.(types.GoType).V.(type) { + case int: fn = plusInt - zero = types.GoType{int(0)} + + zero = types.GoType{ int(0) } + + case int8: fn = plusInt8 - zero = types.GoType{int8(0)} + + zero = types.GoType{ int8(0) } + + case int16: fn = plusInt16 - zero = types.GoType{int16(0)} + + zero = types.GoType{ int16(0) } + + case int32: fn = plusInt32 - zero = types.GoType{int32(0)} + + zero = types.GoType{ int32(0) } + + case int64: fn = plusInt64 - zero = types.GoType{int64(0)} + + zero = types.GoType{ int64(0) } + + case uint: - fn = plusInt - zero = types.GoType{uint(0)} + fn = plusUint + + zero = types.GoType{ uint(0) } + + case uint8: - fn = plusInt8 - zero = types.GoType{uint8(0)} + fn = plusUint8 + + zero = types.GoType{ uint8(0) } + + case uint16: - fn = plusInt16 - zero = types.GoType{uint16(0)} + fn = plusUint16 + + zero = types.GoType{ uint16(0) } + + case uint32: - fn = plusInt32 - zero = types.GoType{uint32(0)} + fn = plusUint32 + + zero = types.GoType{ uint32(0) } + + case uint64: - fn = plusInt64 - zero = types.GoType{uint64(0)} + fn = plusUint64 + + zero = types.GoType{ uint64(0) } + + case float32: fn = plusFloat32 - zero = types.GoType{float32(0)} + + zero = types.GoType{ float32(0) } + + case float64: fn = plusFloat64 - zero = types.GoType{float64(0)} + + zero = types.GoType{ float64(0) } + + case complex64: fn = plusComplex64 - zero = types.GoType{complex64(0)} + + zero = types.GoType{ complex64(0) } + + case complex128: fn = plusComplex128 - zero = types.GoType{complex128(0)} + + zero = types.GoType{ complex128(0) } + + + case string: fn = plusString - zero = types.GoType{string(0)} + zero = types.GoType{string("")} + default: - panic(fmt.Sprintf("$#v cannot have plus called on it", first)) + panic(fmt.Sprintf("$#v cannot have Plus called on it", first)) } return mathReduce(fn, zero, s) } + + + +func minusInt(a, b types.Elem) types.Elem { + return types.GoType{ Int(a) - Int(b) } +} + +func minusInt8(a, b types.Elem) types.Elem { + return types.GoType{ Int8(a) - Int8(b) } +} + +func minusInt16(a, b types.Elem) types.Elem { + return types.GoType{ Int16(a) - Int16(b) } +} + +func minusInt32(a, b types.Elem) types.Elem { + return types.GoType{ Int32(a) - Int32(b) } +} + +func minusInt64(a, b types.Elem) types.Elem { + return types.GoType{ Int64(a) - Int64(b) } +} + +func minusUint(a, b types.Elem) types.Elem { + return types.GoType{ Uint(a) - Uint(b) } +} + +func minusUint8(a, b types.Elem) types.Elem { + return types.GoType{ Uint8(a) - Uint8(b) } +} + +func minusUint16(a, b types.Elem) types.Elem { + return types.GoType{ Uint16(a) - Uint16(b) } +} + +func minusUint32(a, b types.Elem) types.Elem { + return types.GoType{ Uint32(a) - Uint32(b) } +} + +func minusUint64(a, b types.Elem) types.Elem { + return types.GoType{ Uint64(a) - Uint64(b) } +} + +func minusFloat32(a, b types.Elem) types.Elem { + return types.GoType{ Float32(a) - Float32(b) } +} + +func minusFloat64(a, b types.Elem) types.Elem { + return types.GoType{ Float64(a) - Float64(b) } +} + +func minusComplex64(a, b types.Elem) types.Elem { + return types.GoType{ Complex64(a) - Complex64(b) } +} + +func minusComplex128(a, b types.Elem) types.Elem { + return types.GoType{ Complex128(a) - Complex128(b) } +} + + +func Minus(s seq.Seq) types.Elem { + var first, zero types.Elem + + if seq.Empty(s) { + panic("Minus cannot be called with no arguments") + } + zero, s, _ = s.FirstRest() + first = zero + + + var fn mathReduceFn + switch first.(types.GoType).V.(type) { + + case int: + fn = minusInt + + + case int8: + fn = minusInt8 + + + case int16: + fn = minusInt16 + + + case int32: + fn = minusInt32 + + + case int64: + fn = minusInt64 + + + case uint: + fn = minusUint + + + case uint8: + fn = minusUint8 + + + case uint16: + fn = minusUint16 + + + case uint32: + fn = minusUint32 + + + case uint64: + fn = minusUint64 + + + case float32: + fn = minusFloat32 + + + case float64: + fn = minusFloat64 + + + case complex64: + fn = minusComplex64 + + + case complex128: + fn = minusComplex128 + + + + default: + panic(fmt.Sprintf("$#v cannot have Minus called on it", first)) + } + + return mathReduce(fn, zero, s) +} + + + +func multInt(a, b types.Elem) types.Elem { + return types.GoType{ Int(a) * Int(b) } +} + +func multInt8(a, b types.Elem) types.Elem { + return types.GoType{ Int8(a) * Int8(b) } +} + +func multInt16(a, b types.Elem) types.Elem { + return types.GoType{ Int16(a) * Int16(b) } +} + +func multInt32(a, b types.Elem) types.Elem { + return types.GoType{ Int32(a) * Int32(b) } +} + +func multInt64(a, b types.Elem) types.Elem { + return types.GoType{ Int64(a) * Int64(b) } +} + +func multUint(a, b types.Elem) types.Elem { + return types.GoType{ Uint(a) * Uint(b) } +} + +func multUint8(a, b types.Elem) types.Elem { + return types.GoType{ Uint8(a) * Uint8(b) } +} + +func multUint16(a, b types.Elem) types.Elem { + return types.GoType{ Uint16(a) * Uint16(b) } +} + +func multUint32(a, b types.Elem) types.Elem { + return types.GoType{ Uint32(a) * Uint32(b) } +} + +func multUint64(a, b types.Elem) types.Elem { + return types.GoType{ Uint64(a) * Uint64(b) } +} + +func multFloat32(a, b types.Elem) types.Elem { + return types.GoType{ Float32(a) * Float32(b) } +} + +func multFloat64(a, b types.Elem) types.Elem { + return types.GoType{ Float64(a) * Float64(b) } +} + +func multComplex64(a, b types.Elem) types.Elem { + return types.GoType{ Complex64(a) * Complex64(b) } +} + +func multComplex128(a, b types.Elem) types.Elem { + return types.GoType{ Complex128(a) * Complex128(b) } +} + + +func Mult(s seq.Seq) types.Elem { + var first, zero types.Elem + + if seq.Empty(s) { + return types.GoType{ 1 } + } + first, _, _ = s.FirstRest() + + + var fn mathReduceFn + switch first.(types.GoType).V.(type) { + + case int: + fn = multInt + + zero = types.GoType{ int(1) } + + + case int8: + fn = multInt8 + + zero = types.GoType{ int8(1) } + + + case int16: + fn = multInt16 + + zero = types.GoType{ int16(1) } + + + case int32: + fn = multInt32 + + zero = types.GoType{ int32(1) } + + + case int64: + fn = multInt64 + + zero = types.GoType{ int64(1) } + + + case uint: + fn = multUint + + zero = types.GoType{ uint(1) } + + + case uint8: + fn = multUint8 + + zero = types.GoType{ uint8(1) } + + + case uint16: + fn = multUint16 + + zero = types.GoType{ uint16(1) } + + + case uint32: + fn = multUint32 + + zero = types.GoType{ uint32(1) } + + + case uint64: + fn = multUint64 + + zero = types.GoType{ uint64(1) } + + + case float32: + fn = multFloat32 + + zero = types.GoType{ float32(1) } + + + case float64: + fn = multFloat64 + + zero = types.GoType{ float64(1) } + + + case complex64: + fn = multComplex64 + + zero = types.GoType{ complex64(1) } + + + case complex128: + fn = multComplex128 + + zero = types.GoType{ complex128(1) } + + + + default: + panic(fmt.Sprintf("$#v cannot have Mult called on it", first)) + } + + return mathReduce(fn, zero, s) +} + + + +func divInt(a, b types.Elem) types.Elem { + return types.GoType{ Int(a) / Int(b) } +} + +func divInt8(a, b types.Elem) types.Elem { + return types.GoType{ Int8(a) / Int8(b) } +} + +func divInt16(a, b types.Elem) types.Elem { + return types.GoType{ Int16(a) / Int16(b) } +} + +func divInt32(a, b types.Elem) types.Elem { + return types.GoType{ Int32(a) / Int32(b) } +} + +func divInt64(a, b types.Elem) types.Elem { + return types.GoType{ Int64(a) / Int64(b) } +} + +func divUint(a, b types.Elem) types.Elem { + return types.GoType{ Uint(a) / Uint(b) } +} + +func divUint8(a, b types.Elem) types.Elem { + return types.GoType{ Uint8(a) / Uint8(b) } +} + +func divUint16(a, b types.Elem) types.Elem { + return types.GoType{ Uint16(a) / Uint16(b) } +} + +func divUint32(a, b types.Elem) types.Elem { + return types.GoType{ Uint32(a) / Uint32(b) } +} + +func divUint64(a, b types.Elem) types.Elem { + return types.GoType{ Uint64(a) / Uint64(b) } +} + +func divFloat32(a, b types.Elem) types.Elem { + return types.GoType{ Float32(a) / Float32(b) } +} + +func divFloat64(a, b types.Elem) types.Elem { + return types.GoType{ Float64(a) / Float64(b) } +} + +func divComplex64(a, b types.Elem) types.Elem { + return types.GoType{ Complex64(a) / Complex64(b) } +} + +func divComplex128(a, b types.Elem) types.Elem { + return types.GoType{ Complex128(a) / Complex128(b) } +} + + +func Div(s seq.Seq) types.Elem { + var first, zero types.Elem + + if seq.Empty(s) { + panic("Div cannot be called with no arguments") + } + zero, s, _ = s.FirstRest() + first = zero + + + var fn mathReduceFn + switch first.(types.GoType).V.(type) { + + case int: + fn = divInt + + + case int8: + fn = divInt8 + + + case int16: + fn = divInt16 + + + case int32: + fn = divInt32 + + + case int64: + fn = divInt64 + + + case uint: + fn = divUint + + + case uint8: + fn = divUint8 + + + case uint16: + fn = divUint16 + + + case uint32: + fn = divUint32 + + + case uint64: + fn = divUint64 + + + case float32: + fn = divFloat32 + + + case float64: + fn = divFloat64 + + + case complex64: + fn = divComplex64 + + + case complex128: + fn = divComplex128 + + + + default: + panic(fmt.Sprintf("$#v cannot have Div called on it", first)) + } + + return mathReduce(fn, zero, s) +} + + + +func modInt(a, b types.Elem) types.Elem { + return types.GoType{ Int(a) % Int(b) } +} + +func modInt8(a, b types.Elem) types.Elem { + return types.GoType{ Int8(a) % Int8(b) } +} + +func modInt16(a, b types.Elem) types.Elem { + return types.GoType{ Int16(a) % Int16(b) } +} + +func modInt32(a, b types.Elem) types.Elem { + return types.GoType{ Int32(a) % Int32(b) } +} + +func modInt64(a, b types.Elem) types.Elem { + return types.GoType{ Int64(a) % Int64(b) } +} + +func modUint(a, b types.Elem) types.Elem { + return types.GoType{ Uint(a) % Uint(b) } +} + +func modUint8(a, b types.Elem) types.Elem { + return types.GoType{ Uint8(a) % Uint8(b) } +} + +func modUint16(a, b types.Elem) types.Elem { + return types.GoType{ Uint16(a) % Uint16(b) } +} + +func modUint32(a, b types.Elem) types.Elem { + return types.GoType{ Uint32(a) % Uint32(b) } +} + +func modUint64(a, b types.Elem) types.Elem { + return types.GoType{ Uint64(a) % Uint64(b) } +} + + +func Mod(s seq.Seq) types.Elem { + var first, zero types.Elem + + if seq.Empty(s) { + panic("Mod cannot be called with no arguments") + } + zero, s, _ = s.FirstRest() + first = zero + + + var fn mathReduceFn + switch first.(types.GoType).V.(type) { + + case int: + fn = modInt + + + case int8: + fn = modInt8 + + + case int16: + fn = modInt16 + + + case int32: + fn = modInt32 + + + case int64: + fn = modInt64 + + + case uint: + fn = modUint + + + case uint8: + fn = modUint8 + + + case uint16: + fn = modUint16 + + + case uint32: + fn = modUint32 + + + case uint64: + fn = modUint64 + + + + default: + panic(fmt.Sprintf("$#v cannot have Mod called on it", first)) + } + + return mathReduce(fn, zero, s) +} + diff --git a/core/mathgen/mathgen.go b/core/mathgen/mathgen.go new file mode 100644 index 0000000..38326f9 --- /dev/null +++ b/core/mathgen/mathgen.go @@ -0,0 +1,84 @@ +package main + +import ( + "os" + "text/template" +) + +// Represents a type (like int or float32) which can have a math operation +// called upon it (like + or -) +type MathOpType struct { + CastFn string + Type string +} + +// The standard types for which math operations work upon. These don't include +// byte and rune because those are aliases of int8 and int32, respectively +var MathOpTypes = []MathOpType{ + {"Int", "int"}, + {"Int8", "int8"}, + {"Int16", "int16"}, + {"Int32", "int32"}, + {"Int64", "int64"}, + {"Uint", "uint"}, + {"Uint8", "uint8"}, + {"Uint16", "uint16"}, + {"Uint32", "uint32"}, + {"Uint64", "uint64"}, + {"Float32", "float32"}, + {"Float64", "float64"}, + {"Complex64", "complex64"}, + {"Complex128", "complex128"}, +} + +var MathOpsIntOnly = []MathOpType{ + {"Int", "int"}, + {"Int8", "int8"}, + {"Int16", "int16"}, + {"Int32", "int32"}, + {"Int64", "int64"}, + {"Uint", "uint"}, + {"Uint8", "uint8"}, + {"Uint16", "uint16"}, + {"Uint32", "uint32"}, + {"Uint64", "uint64"}, +} + +// Represents a single math operation which can be performed (like + or -) +type MathOp struct { + Public string + Private string + Op string + + // Will be the first item in the reduce, and allows for the function being + // called with an empty seq. If empty string than the first item in the + // given sequence is used and an empty sequence is not allowed + Unit string + + // This is going to be the same for all ops, it's just convenient to have + // here + OpTypes []MathOpType + + // This only applies for plus, which allows for adding two strings together + IncludeString bool +} + +var MathOps = []MathOp{ + {"Plus", "plus", "+", "0", MathOpTypes, true}, + {"Minus", "minus", "-", "", MathOpTypes, false}, + + {"Mult", "mult", "*", "1", MathOpTypes, false}, + {"Div", "div", "/", "", MathOpTypes, false}, + + {"Mod", "mod", "%", "", MathOpsIntOnly, false}, +} + +func main() { + tpl, err := template.ParseFiles("mathgen/mathgen.tpl") + if err != nil { + panic(err) + } + if err := tpl.Execute(os.Stdout, MathOps); err != nil { + panic(err) + } +} diff --git a/core/mathgen/mathgen.tpl b/core/mathgen/mathgen.tpl new file mode 100644 index 0000000..f710322 --- /dev/null +++ b/core/mathgen/mathgen.tpl @@ -0,0 +1,66 @@ +package core + +import ( + "fmt" + + "github.com/mediocregopher/ginger/seq" + "github.com/mediocregopher/ginger/types" +) + +type mathReduceFn func(types.Elem, types.Elem) types.Elem + +func mathReduce(fn mathReduceFn, zero types.Elem, s seq.Seq) types.Elem { + reduceFn := func(acc, el types.Elem) (types.Elem, bool) { + return fn(acc, el), false + } + return seq.Reduce(reduceFn, zero, s) +} + +{{range .}} +{{$mathOp := .}} +{{range .OpTypes}} +func {{$mathOp.Private}}{{.CastFn}}(a, b types.Elem) types.Elem { + return types.GoType{ {{.CastFn}}(a) {{$mathOp.Op}} {{.CastFn}}(b) } +} +{{end}} +{{if $mathOp.IncludeString}} +func {{$mathOp.Private}}String(a, b types.Elem) types.Elem { + return types.GoType{ String(a) {{$mathOp.Op}} String(b) } +} +{{end}} +func {{$mathOp.Public}}(s seq.Seq) types.Elem { + var first, zero types.Elem + {{if (eq $mathOp.Unit "")}} + if seq.Empty(s) { + panic("{{$mathOp.Public}} cannot be called with no arguments") + } + zero, s, _ = s.FirstRest() + first = zero + {{else}} + if seq.Empty(s) { + return types.GoType{ {{$mathOp.Unit}} } + } + first, _, _ = s.FirstRest() + {{end}} + + var fn mathReduceFn + switch first.(types.GoType).V.(type) { + {{range .OpTypes}} + case {{.Type}}: + fn = {{$mathOp.Private}}{{.CastFn}} + {{if (ne $mathOp.Unit "")}} + zero = types.GoType{ {{.Type}}({{$mathOp.Unit}}) } + {{end}} + {{end}} + {{if $mathOp.IncludeString}} + case string: + fn = {{$mathOp.Private}}String + zero = types.GoType{string("")} + {{end}} + default: + panic(fmt.Sprintf("$#v cannot have {{$mathOp.Public}} called on it", first)) + } + + return mathReduce(fn, zero, s) +} +{{end}}