Files
argon-v3/src/factorial.go

64 lines
1.8 KiB
Go

package main
import (
"strings"
)
var factorialCompiled = makeRegex(`( *)(.|\n)+\!( *)`)
type factorial struct {
value any
code string
line int
path string
}
func parseFactorial(code UNPARSEcode, index int, codeline []UNPARSEcode) (factorial, bool, ArErr, int) {
trim := strings.TrimSpace(code.code)
trim = trim[:len(trim)-1]
val, success, err, i := translateVal(UNPARSEcode{code: trim, realcode: code.realcode, line: code.line, path: code.path}, index, codeline, 0)
if !success {
return factorial{}, false, err, i
}
return factorial{val, code.code, code.line, code.path}, success, ArErr{}, i
}
func isFactorial(code UNPARSEcode) bool {
return factorialCompiled.MatchString(code.code)
}
func fact(n number) number {
if n.Cmp(newNumber().SetInt64(1000)) >= 0 {
return infinity
} else if n.Cmp(newNumber().SetInt64(0)) == -1 {
return newNumber().SetInt64(0)
} else if n.Cmp(newNumber().SetInt64(0)) == 0 {
return newNumber().SetInt64(1)
}
result := newNumber().SetInt64(1)
for i := newNumber().SetInt64(2); i.Cmp(n) <= 0; i.Add(i, newNumber().SetInt64(1)) {
result.Mul(result, i)
}
return result
}
func runFactorial(f factorial, stack stack, stacklevel int) (any, ArErr) {
val, err := runVal(f.value, stack, stacklevel+1)
if err.EXISTS {
return nil, err
}
switch x := val.(type) {
case number:
if !x.IsInt() {
return nil, ArErr{"Runtime Error", "cannot use factorial on non-integer", f.line, f.path, f.code, true}
}
if x.Cmp(newNumber().SetInt64(0)) == -1 {
return nil, ArErr{"Runtime Error", "cannot use factorial on negative number", f.line, f.path, f.code, true}
}
return fact(x), ArErr{}
default:
return nil, ArErr{"Runtime Error", "cannot use factorial on non-number of type '" + typeof(val) + "'", f.line, f.path, f.code, true}
}
}