Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement trig. functions. #117

Merged
merged 1 commit into from
Dec 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions PRIMITIVES.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,14 @@ Things you'll find here include:
* `=`
* Numerical comparison function.
* Note that multiple arguments are supported, not just two.
* `acos`
* Trig. function.
* `arch`
* Return the operating system architecture.
* `asin`
* Trig. function.
* `atan`
* Trig. function.
* `base`
* Convert the specified integer to a string, in the given base.
* `car`
Expand All @@ -134,6 +140,10 @@ Things you'll find here include:
* Add the element to the start of the given (potentialy empty) list.
* `contains?`
* Does the specified hash contain the given key?
* `cos`
* Trig. function.
* `cosh`
* Trig. function.
* `date`
* Return details of today's date, as a list.
* Demonstrated in [time.lisp](time.lisp).
Expand Down Expand Up @@ -207,6 +217,10 @@ Things you'll find here include:
* Update the value of the specified hash-key.
* `shell`
* Run a command via the shell, and return STDOUT and STDERR it generated.
* `sin`
* Trig. function.
* `sinh`
* Trig. function.
* `sort`
* Sort the given list.
* `split`
Expand All @@ -223,6 +237,10 @@ Things you'll find here include:
* Return true if the first string is greater than the second.
* `string>=`
* Return true if the first string is greater than, or equal to the second.
* `tan`
* Trig. function.
* `tanh`
* Trig. function.
* `time`
* Return values relating to the current time, as a list.
* Demonstrated in [time.lisp](time.lisp).
Expand Down Expand Up @@ -384,6 +402,8 @@ Functions here include:
* Is the given number equal to one?
* `or`
* Logical operator, are any elements true?
* `pi`
* Return the value of PI - calculated via `atan` as per [this reference](https://en.m.wikibooks.org/wiki/Trigonometry/Calculating_Pi).
* `pos?`
* Is the given number positive?
* `range`
Expand Down
172 changes: 170 additions & 2 deletions builtins/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,20 @@ func PopulateEnvironment(env *env.Environment) {
env.Set("/=", &primitive.Procedure{F: inequalityFn, Help: helpMap["/="], Args: []primitive.Symbol{primitive.Symbol("N"), primitive.Symbol("arg1..argN")}})
env.Set("<", &primitive.Procedure{F: ltFn, Help: helpMap["<"], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}})
env.Set("=", &primitive.Procedure{F: equalsFn, Help: helpMap["="], Args: []primitive.Symbol{primitive.Symbol("arg1"), primitive.Symbol("arg2 .. argN")}})
env.Set("acos", &primitive.Procedure{F: acosFn, Help: helpMap["acos"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("arch", &primitive.Procedure{F: archFn, Help: helpMap["arch"]})
env.Set("asin", &primitive.Procedure{F: asinFn, Help: helpMap["asin"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("atan", &primitive.Procedure{F: atanFn, Help: helpMap["atan"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("base", &primitive.Procedure{F: baseFn, Help: helpMap["base"], Args: []primitive.Symbol{primitive.Symbol("number"), primitive.Symbol("base")}})
env.Set("car", &primitive.Procedure{F: carFn, Help: helpMap["car"], Args: []primitive.Symbol{primitive.Symbol("list")}})
env.Set("cdr", &primitive.Procedure{F: cdrFn, Help: helpMap["cdr"], Args: []primitive.Symbol{primitive.Symbol("list")}})
env.Set("char=", &primitive.Procedure{F: charEqualsFn, Help: helpMap["char="], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}})
env.Set("char<", &primitive.Procedure{F: charLtFn, Help: helpMap["char<"], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}})
env.Set("char=", &primitive.Procedure{F: charEqualsFn, Help: helpMap["char="], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}})
env.Set("chr", &primitive.Procedure{F: chrFn, Help: helpMap["chr"], Args: []primitive.Symbol{primitive.Symbol("num")}})
env.Set("cons", &primitive.Procedure{F: consFn, Help: helpMap["cons"], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}})
env.Set("contains?", &primitive.Procedure{F: containsFn, Help: helpMap["contains?"], Args: []primitive.Symbol{primitive.Symbol("hash"), primitive.Symbol("key")}})
env.Set("cos", &primitive.Procedure{F: cosFn, Help: helpMap["cos"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("cosh", &primitive.Procedure{F: coshFn, Help: helpMap["cosh"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("date", &primitive.Procedure{F: dateFn, Help: helpMap["date"]})
env.Set("directory:entries", &primitive.Procedure{F: directoryEntriesFn, Help: helpMap["directory:entries"]})
env.Set("directory?", &primitive.Procedure{F: directoryFn, Help: helpMap["directory?"], Args: []primitive.Symbol{primitive.Symbol("path")}})
Expand Down Expand Up @@ -141,24 +146,83 @@ func PopulateEnvironment(env *env.Environment) {
env.Set("random", &primitive.Procedure{F: randomFn, Help: helpMap["random"], Args: []primitive.Symbol{primitive.Symbol("max")}})
env.Set("set", &primitive.Procedure{F: setFn, Help: helpMap["set"], Args: []primitive.Symbol{primitive.Symbol("hash"), primitive.Symbol("key"), primitive.Symbol("val")}})
env.Set("shell", &primitive.Procedure{F: shellFn, Help: helpMap["shell"], Args: []primitive.Symbol{primitive.Symbol("list")}})
env.Set("sin", &primitive.Procedure{F: sinFn, Help: helpMap["sin"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("sinh", &primitive.Procedure{F: sinhFn, Help: helpMap["sinh"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("sort", &primitive.Procedure{F: sortFn, Help: helpMap["sort"], Args: []primitive.Symbol{primitive.Symbol("list")}})
env.Set("split", &primitive.Procedure{F: splitFn, Help: helpMap["split"], Args: []primitive.Symbol{primitive.Symbol("str"), primitive.Symbol("by")}})
env.Set("sprintf", &primitive.Procedure{F: sprintfFn, Help: helpMap["sprintf"], Args: []primitive.Symbol{primitive.Symbol("arg1..argN")}})
env.Set("str", &primitive.Procedure{F: strFn, Help: helpMap["str"], Args: []primitive.Symbol{primitive.Symbol("object")}})
env.Set("string=", &primitive.Procedure{F: stringEqualsFn, Help: helpMap["string="], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}})
env.Set("string<", &primitive.Procedure{F: stringLtFn, Help: helpMap["string<"], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}})
env.Set("string=", &primitive.Procedure{F: stringEqualsFn, Help: helpMap["string="], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}})
env.Set("tan", &primitive.Procedure{F: tanFn, Help: helpMap["tan"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("tanh", &primitive.Procedure{F: tanhFn, Help: helpMap["tanh"], Args: []primitive.Symbol{primitive.Symbol("n")}})
env.Set("time", &primitive.Procedure{F: timeFn, Help: helpMap["time"]})
env.Set("type", &primitive.Procedure{F: typeFn, Help: helpMap["type"], Args: []primitive.Symbol{primitive.Symbol("object")}})
env.Set("vals", &primitive.Procedure{F: valsFn, Help: helpMap["vals"], Args: []primitive.Symbol{primitive.Symbol("hash")}})

}

// Built in functions



// acos implements acos
func acosFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Acos(float64(n)))
}

// archFn implements (os)
func archFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {
return primitive.String(runtime.GOARCH)
}


// asin implements asin
func asinFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Asin(float64(n)))
}

// atan implements atan
func atanFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Atan(float64(n)))
}

// baseFn implements (base)
func baseFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {
if len(args) != 2 {
Expand Down Expand Up @@ -346,6 +410,40 @@ func containsFn(env *env.Environment, args []primitive.Primitive) primitive.Prim

}

// cosFn implements cos
func cosFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Cos(float64(n)))
}

// coshFn implements cosh
func coshFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Cosh(float64(n)))
}

// dateFn returns the current (Weekday, DD, MM, YYYY) as a list.
func dateFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {
var ret primitive.List
Expand Down Expand Up @@ -1465,6 +1563,41 @@ func shellFn(env *env.Environment, args []primitive.Primitive) primitive.Primiti
return ret
}


// sinFn implements sin
func sinFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Sin(float64(n)))
}

// sinhFn implements sinh
func sinhFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Sinh(float64(n)))
}

// sortFn implements (sort)
func sortFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {
// If we have only a single argument
Expand Down Expand Up @@ -1608,6 +1741,41 @@ func stringLtFn(env *env.Environment, args []primitive.Primitive) primitive.Prim
return primitive.Bool(a < b)
}


// tanFn implements tan
func tanFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Tan(float64(n)))
}

// tanhFn implements tanh
func tanhFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {

// We only need a single argument
if len(args) != 1 {
return primitive.ArityError()
}

// Which is a number
n, ok := args[0].(primitive.Number)
if !ok {
return primitive.Error("argument not a number")
}

return primitive.Number( math.Tanh(float64(n)))
}

// timeFn returns the current (HH, MM, SS) as a list.
func timeFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive {
var ret primitive.List
Expand Down
54 changes: 54 additions & 0 deletions builtins/builtins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3492,6 +3492,60 @@ func TestStringLt(t *testing.T) {
}
}

func TestTrig(t *testing.T ) {

funs := []primitive.GolangPrimitiveFn{
acosFn,
asinFn,
atanFn,
cosFn,
coshFn,
sinFn,
sinhFn,
tanFn,
tanhFn,
}

for _, fn := range(funs) {

out := fn(nil, []primitive.Primitive{} )

// Will lead to an error
e, ok := out.(primitive.Error)
if !ok {
t.Fatalf("expected error, got %v", out)
}
if !strings.Contains(string(e), "argument") {
t.Fatalf("got error, but wrong one")
}

// Argument must be an umber
out = fn(ENV, []primitive.Primitive{
primitive.String("foo"),
})

// Will lead to an error
e, ok = out.(primitive.Error)
if !ok {
t.Fatalf("expected error, got %v", out)
}
if !strings.Contains(string(e), "not a number") {
t.Fatalf("got error, but wrong one %v", out)
}

// Now a valid result
res := fn(ENV, []primitive.Primitive{
primitive.Number(3),
})

// don't care about the result
_, ok2 := res.(primitive.Number)
if !ok2 {
t.Fatalf("expected number, got %v", out)
}
}
}

func TestType(t *testing.T) {

// No arguments
Expand Down
Loading