├── testdata ├── empty.txt ├── matrix.txt ├── saved ├── hello.txt ├── no_newline.txt ├── README ├── ivy.ivy ├── unary_bigrat.ivy ├── unary_rat.ivy ├── help.ivy ├── copy.ivy ├── unary_bigint.ivy ├── outer.ivy ├── unary_int.ivy ├── exec_fail.ivy ├── inner.ivy ├── debug.ivy ├── binary_complex.ivy ├── binary_bigfloat.ivy ├── scan.ivy ├── sys.ivy ├── base.ivy ├── save.ivy ├── char.ivy ├── unary_vector.ivy ├── binary_bigrat.ivy ├── reduce.ivy ├── format.ivy ├── statement.ivy └── binary_int.ivy ├── go.mod ├── ivy.jpg ├── talks ├── demo.hoc ├── images │ ├── upe.gif │ ├── aplkbd.jpg │ └── wallaby.jpg ├── script.go ├── demo.ivy └── demo2.ivy ├── exec ├── opdef.go ├── operator.go └── function.go ├── parse ├── exec │ └── opdef.go ├── helpdocs.go ├── helpgen.go └── save.go ├── run ├── time_unix.go └── run.go ├── README.md ├── scan └── type_string.go ├── lib.ivy ├── LICENSE ├── demo_test.go ├── value ├── assign.go ├── loop.go ├── sqrt.go ├── fac.go ├── asinh.go ├── char.go ├── context.go ├── value.go ├── int.go ├── log.go ├── sinh.go ├── bigfloat.go ├── bigrat.go ├── bigint.go ├── sin.go ├── expr.go ├── complex.go └── asin.go ├── mobile ├── help_gen.go ├── mobile.go └── mobile_test.go ├── demo └── demo.go ├── quorem_test.go ├── ivy.go └── ivy_test.go /testdata/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testdata/matrix.txt: -------------------------------------------------------------------------------- 1 | 1 2 3 4 2 | 5 6 7 8 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module robpike.io/ivy 2 | 3 | go 1.24.0 4 | -------------------------------------------------------------------------------- /testdata/saved: -------------------------------------------------------------------------------- 1 | x = iota 7 2 | op avg n = (+/n)/rho n 3 | -------------------------------------------------------------------------------- /ivy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rsc/ivy/master/ivy.jpg -------------------------------------------------------------------------------- /talks/demo.hoc: -------------------------------------------------------------------------------- 1 | 23 2 | 2*log(10) 3 | 1e100 4 | 2^64 5 | 0x234 6 | -------------------------------------------------------------------------------- /testdata/hello.txt: -------------------------------------------------------------------------------- 1 | hello world 2 | Καλημέρα κόσμε 3 | こんにちは 世界 4 | -------------------------------------------------------------------------------- /testdata/no_newline.txt: -------------------------------------------------------------------------------- 1 | hello world 2 | Καλημέρα κόσμε 3 | こんにちは 世界 -------------------------------------------------------------------------------- /talks/images/upe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rsc/ivy/master/talks/images/upe.gif -------------------------------------------------------------------------------- /talks/images/aplkbd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rsc/ivy/master/talks/images/aplkbd.jpg -------------------------------------------------------------------------------- /talks/images/wallaby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rsc/ivy/master/talks/images/wallaby.jpg -------------------------------------------------------------------------------- /exec/opdef.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package exec 6 | 7 | // OpDef is just a record of an op's name and arg count. 8 | // It is held in execContext.defs to control writing the 9 | // ops out in the right order during save. See comment above. 10 | type OpDef struct { 11 | Name string 12 | IsBinary bool 13 | } 14 | -------------------------------------------------------------------------------- /testdata/README: -------------------------------------------------------------------------------- 1 | Each test file is suffixed ".ivy". 2 | 3 | Each contains a list of examples separated by blank lines. 4 | Comments are discarded. 5 | 6 | Each example is one or more non-blank lines, the input, followed 7 | by one or lines indented by a tab (perhaps otherwise empty), the 8 | output. The output, trimmed of leading tab, must match the result 9 | of running ivy with the input. 10 | 11 | Example: 12 | 13 | )origin 0 14 | iota 10 15 | 0 1 2 3 4 5 6 7 8 9 16 | 17 | )origin 1 18 | iota 10 19 | 1 2 3 4 5 6 7 8 9 10 20 | -------------------------------------------------------------------------------- /parse/exec/opdef.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package exec // import "robpike.io/ivy/parse/exec" 6 | 7 | // OpDef is just a record of an op's name and arg count. 8 | // It is held in execContext.defs to control writing the 9 | // ops out in the right order during save. 10 | // See comment in parse/save.go. TODO: Move save.go here. 11 | type OpDef struct { 12 | Name string 13 | IsBinary bool 14 | } 15 | -------------------------------------------------------------------------------- /run/time_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build unix 6 | 7 | package run 8 | 9 | import ( 10 | "syscall" 11 | "time" 12 | ) 13 | 14 | func init() { 15 | cpuTime = rusageTime 16 | } 17 | 18 | func rusageTime() (user, sys time.Duration) { 19 | var rusage syscall.Rusage 20 | err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage) 21 | if err != nil { 22 | return 0, 0 23 | } 24 | return time.Duration(rusage.Utime.Nano()), time.Duration(rusage.Stime.Nano()) 25 | } 26 | -------------------------------------------------------------------------------- /testdata/ivy.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # The evaluation operator, ivy. 6 | 7 | ivy '34' 8 | 34 9 | 10 | ivy 'pi' 11 | 3.14159265359 12 | 13 | ivy '3' 14 | 3 15 | 16 | ivy 'e' 17 | 2.71828182846 18 | 19 | x='3+4' 20 | ivy x 21 | 7 22 | 23 | # Can evaluate ) commands, even without a newline. 24 | ivy ")format '%.2f'" 25 | 3 26 | # 27 | 3.00 28 | 29 | x = text 345 30 | 2 * ivy rot x 31 | 1086 32 | 33 | # Symbols and functions are shared. 34 | ivy 'x=iota 10' 35 | ivy 'op average v = (+/v)/rho v' 36 | average iota 10 37 | # 38 | 11/2 39 | 40 | # Error case, issue 66. 41 | ivy ivy '' 42 | # 43 | -------------------------------------------------------------------------------- /testdata/unary_bigrat.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Unary operations on rationals. 6 | 7 | 1.5 8 | 3/2 9 | 10 | 1e10/23 11 | 10000000000/23 12 | 13 | 75/23 14 | 75/23 15 | 16 | + 75/23 17 | 75/23 18 | 19 | +-75/23 20 | -75/23 21 | 22 | - 75/23 23 | -75/23 24 | 25 | --75/23 26 | 75/23 27 | 28 | - -75/23 29 | 75/23 30 | 31 | /75/23 32 | 23/75 33 | 34 | /-75/23 35 | -23/75 36 | 37 | sgn -1/3 38 | -1 39 | 40 | sgn 7/5 41 | 1 42 | 43 | not 1/3 44 | 0 45 | 46 | abs -75/23 47 | 75/23 48 | 49 | abs 23/75 50 | 23/75 51 | 52 | floor -123/75 53 | -2 54 | 55 | floor 123/75 56 | 1 57 | 58 | ceil -123/75 59 | -1 60 | 61 | ceil 123/75 62 | 2 63 | 64 | rho rho 1/3 65 | 0 66 | 67 | ,1/3 68 | 1/3 69 | -------------------------------------------------------------------------------- /testdata/unary_rat.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Unary operations on (big) rationals. 6 | 7 | # Inputs 8 | 9 | 1/23 10 | 1/23 11 | 12 | 1.5 13 | 3/2 14 | 15 | 0.1e-4 16 | 1/100000 17 | 18 | # Operations 19 | 20 | + 1/23 21 | 1/23 22 | 23 | +-1/23 24 | -1/23 25 | 26 | - 1/23 27 | -1/23 28 | 29 | --1/23 30 | 1/23 31 | 32 | - -1/23 33 | 1/23 34 | 35 | /1/23 36 | 23 37 | 38 | /-1/23 39 | -23 40 | 41 | sgn -1/23 42 | -1 43 | 44 | sgn 1/23 45 | 1 46 | 47 | abs -1/23 48 | 1/23 49 | 50 | abs 1/23 51 | 1/23 52 | 53 | floor -1/23 54 | -1 55 | 56 | floor 1/23 57 | 0 58 | 59 | ceil -1/23 60 | 0 61 | 62 | ceil 1/23 63 | 1 64 | 65 | rho rho 1/23 66 | 0 67 | 68 | rot 1/3 69 | 1/3 70 | 71 | flip 1/3 72 | 1/3 73 | 74 | box 1/3 75 | 1/3 76 | 77 | first 1/3 78 | 1/3 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ivy 2 | === 3 | 4 | Ivy is an interpreter for an APL-like language. It is a plaything and a work in 5 | progress. 6 | 7 | Ivy has a custom domain. Do not install using github directly. Instead, run: 8 | 9 | go install robpike.io/ivy@latest 10 | 11 | Documentation at https://pkg.go.dev/robpike.io/ivy. 12 | 13 | Try the demo: within ivy, type 14 | 15 | )demo 16 | 17 | Prototype apps for iOS and Android are available in the App store and Google Play store. 18 | (At the moment, the iOS one is unavailable but will return.) 19 | These are very old but should be updated before too long. 20 | To find them, search for "ivy bignum calculator". 21 | 22 | Slides for a talk at: https://talks.godoc.org/github.com/robpike/ivy/talks/ivy.slide 23 | Video for the talk at: https://www.youtube.com/watch?v=PXoG0WX0r_E 24 | The talk predates a lot of the features, including floating point, text, and user-defined operators. 25 | 26 | To be built, ivy requires Go 1.24. 27 | 28 | ![Ivy](ivy.jpg) 29 | -------------------------------------------------------------------------------- /testdata/help.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Help. 6 | 7 | )help rho 8 | # 9 | Unary operators: 10 | Name APL Ivy Meaning 11 | Shape ⍴B rho Vector of number of components in each dimension of B 12 | 13 | Binary operators: 14 | Name APL Ivy Meaning 15 | Reshape A⍴B rho Array of shape A with data B 16 | 17 | )help about reverse 18 | # 19 | Reversal ⌽B rot Reverse elements of B along last axis 20 | Reversal ⊖B flip Reverse elements of B along first axis 21 | Monadic transpose ⍉B transp Reverse the axes of B 22 | 23 | )help o. 24 | # 25 | Axis operators: 26 | Name APL Ivy APL Example Ivy Example Meaning (of example) 27 | Outer product ∘. o. A∘.×B A o.* B Outer product of A and B 28 | 29 | -------------------------------------------------------------------------------- /testdata/copy.ivy: -------------------------------------------------------------------------------- 1 | # Copy-on-write variable test. 2 | # Runs incredibly slowly if each recursion copies m. 3 | # Since m is never modified, runs very quickly with copy-on-write variables. 4 | m = 1000 1000 rho 1 5 | op m step2 n = n==0: m; m step2 n-1 6 | op m step1 n = n==0: m; (m step2 100) step1 n-1 7 | rho m step1 100 8 | 1000 1000 9 | 10 | # Persistent vector test. 11 | # Runs incredibly slowly and runs out of memory if each modification copies all of m 12 | # (especially because all the copies on the stack are preserved during the recursion, 13 | # so copies are never freed). 14 | # Runs quickly when only the modified subsections are copied, 15 | # so that all the live copies share most of their storage. 16 | op fibinit m = m[1] = 1; m[2] = 1; m 17 | op m fib n = n <= 2: fibinit m; m = m fib n-1; m[n] = m[n-1] + m[n-2]; m 18 | ((100000 rho 0) fib 100000)[100] 19 | 354224848179261915075 20 | 21 | # Another persistent vector test. 22 | # Checks that iterated append is efficient. 23 | op islowta n = n <= 1: 1; (islowta n-1), n 24 | rho islowta 100000 25 | 100000 26 | 27 | op mslowta n = n <= 1: 1 1 rho 1; (mslowta n-1) ,% n 28 | rho mslowta 100000 29 | 100000 1 30 | -------------------------------------------------------------------------------- /exec/operator.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package exec 6 | 7 | import "robpike.io/ivy/value" 8 | 9 | // Predefined reports whether the operator is predefined, a built-in. 10 | func Predefined(op string) bool { 11 | return value.BinaryOps[op] != nil || value.UnaryOps[op] != nil 12 | } 13 | 14 | // DefinedOp reports whether the operator is known. 15 | func (c *Context) DefinedOp(op string) bool { 16 | if c.isVariable(op) { 17 | return false 18 | } 19 | return Predefined(op) || c.BinaryFn[op] != nil || c.UnaryFn[op] != nil 20 | } 21 | 22 | // DefinedBinary reports whether the operator is a known binary. 23 | func (c *Context) DefinedBinary(op string) bool { 24 | if c.isVariable(op) { 25 | return false 26 | } 27 | return c.BinaryFn[op] != nil || value.BinaryOps[op] != nil 28 | } 29 | 30 | // DefinedUnary reports whether the operator is a known unary. 31 | func (c *Context) DefinedUnary(op string) bool { 32 | if c.isVariable(op) { 33 | return false 34 | } 35 | return c.UnaryFn[op] != nil || value.UnaryOps[op] != nil 36 | } 37 | -------------------------------------------------------------------------------- /scan/type_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type Type"; DO NOT EDIT. 2 | 3 | package scan 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[EOF-0] 12 | _ = x[Error-1] 13 | _ = x[Newline-2] 14 | _ = x[Assign-3] 15 | _ = x[Char-4] 16 | _ = x[Identifier-5] 17 | _ = x[LeftBrack-6] 18 | _ = x[LeftParen-7] 19 | _ = x[Number-8] 20 | _ = x[Operator-9] 21 | _ = x[Op-10] 22 | _ = x[OpDelete-11] 23 | _ = x[Rational-12] 24 | _ = x[Complex-13] 25 | _ = x[RightBrack-14] 26 | _ = x[RightParen-15] 27 | _ = x[Semicolon-16] 28 | _ = x[String-17] 29 | _ = x[Colon-18] 30 | } 31 | 32 | const _Type_name = "EOFErrorNewlineAssignCharIdentifierLeftBrackLeftParenNumberOperatorOpOpDeleteRationalComplexRightBrackRightParenSemicolonStringColon" 33 | 34 | var _Type_index = [...]uint8{0, 3, 8, 15, 21, 25, 35, 44, 53, 59, 67, 69, 77, 85, 92, 102, 112, 121, 127, 132} 35 | 36 | func (i Type) String() string { 37 | if i < 0 || i >= Type(len(_Type_index)-1) { 38 | return "Type(" + strconv.FormatInt(int64(i), 10) + ")" 39 | } 40 | return _Type_name[_Type_index[i]:_Type_index[i+1]] 41 | } 42 | -------------------------------------------------------------------------------- /testdata/unary_bigint.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Unary operations on big ints. 6 | 7 | )seed 0 8 | ?1e10 9 | 6568201837 10 | 11 | 1e10 12 | 10000000000 13 | 14 | + 1e10 15 | 10000000000 16 | 17 | +-1e10 18 | -10000000000 19 | 20 | - 1e10 21 | -10000000000 22 | 23 | --1e10 24 | 10000000000 25 | 26 | - -1e10 27 | 10000000000 28 | 29 | /1e10 30 | 1/10000000000 31 | 32 | /-1e10 33 | -1/10000000000 34 | 35 | sgn -10000000000 36 | -1 37 | 38 | sgn 10000000000 39 | 1 40 | 41 | ^10000000000 42 | -10000000001 43 | 44 | ^10000000000 45 | -10000000001 46 | 47 | not 10000000000 48 | 0 49 | 50 | abs 10000000000 51 | 10000000000 52 | 53 | abs -10000000000 54 | 10000000000 55 | 56 | floor -10000000000 57 | -10000000000 58 | 59 | floor 10000000000 60 | 10000000000 61 | 62 | ceil -10000000000 63 | -10000000000 64 | 65 | ceil 11000000000 66 | 11000000000 67 | 68 | rho rho 10000000000 69 | 0 70 | 71 | ,10000000000 72 | 10000000000 73 | 74 | rot 10000000000 75 | 10000000000 76 | 77 | flip 10000000000 78 | 10000000000 79 | 80 | box 10000000000 81 | 10000000000 82 | 83 | first 10000000000 84 | 10000000000 85 | -------------------------------------------------------------------------------- /testdata/outer.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Outer products. 6 | 7 | # Scalars 8 | 9 | # Test of number scanning with no spaces. 10 | 11 | 3o.*5 12 | 15 13 | 14 | 3 o.* 5 15 | 15 16 | 17 | 1/3 o.* 1/4 18 | 1/12 19 | 20 | 3e10 o.* 5e10 21 | 1500000000000000000000 22 | 23 | # Vectors 24 | 25 | 2 3 o.+ 10 11 12 26 | 12 13 14 27 | 13 14 15 28 | 29 | 2 3 4 o.* 10 11 30 | 20 22 31 | 30 33 32 | 40 44 33 | 34 | 2 3 4 o.min 10 11 35 | 2 2 36 | 3 3 37 | 4 4 38 | 39 | 2 3 o.max 10 11 12 40 | 10 11 12 41 | 10 11 12 42 | 43 | (3 2 rho iota 6) o.+ 3 3 rho iota 9 44 | [1 * * *]: 45 | ┌ ┐ 46 | │ 2 3 4│ 47 | │ 5 6 7│ 48 | │ 8 9 10│ 49 | └ ┘ 50 | ┌ ┐ 51 | │ 3 4 5│ 52 | │ 6 7 8│ 53 | │ 9 10 11│ 54 | └ ┘ 55 | 56 | [2 * * *]: 57 | ┌ ┐ 58 | │ 4 5 6│ 59 | │ 7 8 9│ 60 | │10 11 12│ 61 | └ ┘ 62 | ┌ ┐ 63 | │ 5 6 7│ 64 | │ 8 9 10│ 65 | │11 12 13│ 66 | └ ┘ 67 | 68 | [3 * * *]: 69 | ┌ ┐ 70 | │ 6 7 8│ 71 | │ 9 10 11│ 72 | │12 13 14│ 73 | └ ┘ 74 | ┌ ┐ 75 | │ 7 8 9│ 76 | │10 11 12│ 77 | │13 14 15│ 78 | └ ┘ 79 | -------------------------------------------------------------------------------- /talks/script.go: -------------------------------------------------------------------------------- 1 | package main // import "robpike.io/ivy/talks" 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "os/exec" 11 | ) 12 | 13 | func main() { 14 | flag.Parse() 15 | if flag.NArg() != 2 { 16 | log.Fatal("Usage: script program filename") 17 | } 18 | text, err := ioutil.ReadFile(flag.Arg(1)) 19 | ck(err) 20 | cmd := exec.Command(flag.Arg(0)) 21 | cmd.Stdout = os.Stdout 22 | cmd.Stderr = os.Stderr 23 | input, err := cmd.StdinPipe() 24 | ck(err) 25 | err = cmd.Start() 26 | ck(err) 27 | scan := bufio.NewScanner(os.Stdin) 28 | for scan.Scan() { 29 | // User typed something; step back across the newline. 30 | if len(scan.Bytes()) > 0 { 31 | // User typed a non-empty line of text; send that. 32 | line := []byte(fmt.Sprintf("%s\n", scan.Bytes())) 33 | _, err = input.Write(line) 34 | } else { 35 | // User typed newline; send next line of file's text. 36 | if len(text) == 0 { 37 | break 38 | } 39 | for i := 0; i < len(text); i++ { 40 | if text[i] == '\n' { 41 | os.Stdout.Write(text[:i+1]) 42 | _, err = input.Write(text[:i+1]) 43 | text = text[i+1:] 44 | break 45 | } 46 | } 47 | } 48 | ck(err) 49 | } 50 | ck(scan.Err()) 51 | } 52 | 53 | func ck(err error) { 54 | if err != nil { 55 | log.Fatal(err) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib.ivy: -------------------------------------------------------------------------------- 1 | # Average 2 | op avg x = (+/x)/rho x 3 | 4 | # Largest n in x. 5 | op n largest x = n take x[down x] 6 | 7 | # Digits of a base b. Use log to decide how many. 8 | op a base b = ((floor 1 + b log a) rho b) encode a 9 | 10 | # Count the number of appearances of each digit in x. 11 | op digitcount x = t = text x; +/(-1+iota 10) o.== (code (t in '0123456789') sel t) - code '0' 12 | 13 | # Population count. Use encode (through base) to turn the value into a string of bits. 14 | op popcount n = +/n base 2 15 | 16 | # Sum of digits. 17 | op sumdigits x = t = text x; +/(code (t in '0123456789') sel t) - code '0' 18 | 19 | # Meters to feet. 20 | op m2ft m = 0 12 encode ceil m*1000/25.4 21 | 22 | # Miles to kilometers 23 | op mi2km m = float m*1.609344 24 | 25 | # Celsius to Fahrenheit. 26 | op c2f c = float 32 + c * 9/5 27 | 28 | # Fahrenheit to Celsius. 29 | op f2c f = float 5/9 * f - 32 30 | 31 | # Kilometers to miles 32 | op km2mi m = float m/1.609344 33 | 34 | # Some crazy math. Avoid N ≳1000; these nutty routines take too long. 35 | 36 | # Primes less <= N 37 | op primes N = (not T in T o.* T) sel T = 1 drop iota N 38 | 39 | # Approximations to pi. 40 | op approxPi N = sqrt 6*+/ /(iota N)**2 41 | 42 | # A much more efficient version found by PSLQ. See Nature, Vol 590, page 69. 43 | op PSLQpiTerm N = (/16**N)* (4 / 1+8*N)-(2 / 4+8*N)+(/5+8*N)+(/6+8*N) 44 | op PSLQpi N = +/PSLQpiTerm -1 + iota N 45 | -------------------------------------------------------------------------------- /talks/demo.ivy: -------------------------------------------------------------------------------- 1 | #This is ivy. Each step in the demo is one line of input followed by some output. 2 | # Arithmetic 3 | 23 4 | 23 + 45 5 | # Rationals 6 | 1/3 7 | 1/3 + 4/5 8 | 1.2 9 | # Big numbers 10 | 1e10 # Still an integer. 11 | 1e100 # Still an integer. 12 | 2**64 13 | 2**640 14 | 2**6400 15 | # Vectors 16 | 1 2 3 17 | 1 2 3 + 4 5 6 18 | 23 + 1 2 3 19 | 1 << 1 2 3 4 5 20 | iota 10 21 | 2 ** iota 100 22 | (2 ** iota 100) == (1< demo/demo.out 24 | */ 25 | 26 | const ( 27 | demoBad = "demo.bad" 28 | demoOut = "demo/demo.out" 29 | ) 30 | 31 | func TestDemo(t *testing.T) { 32 | stdout := new(bytes.Buffer) 33 | stderr := new(bytes.Buffer) 34 | var conf config.Config 35 | conf.SetRandomSeed(0) 36 | context := exec.NewContext(&conf) 37 | scan := bufio.NewScanner(strings.NewReader(demo.Text())) 38 | for scan.Scan() { 39 | run.Ivy(context, scan.Text(), stdout, stderr) 40 | if stderr.Len() > 0 { 41 | t.Fatal(stderr.String()) 42 | } 43 | } 44 | result := stdout.String() 45 | data, err := ioutil.ReadFile(demoOut) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | if string(data) != result { 50 | err = ioutil.WriteFile(demoBad, stdout.Bytes(), 0666) 51 | if err != nil { 52 | t.Fatalf("test output differs; error writing bad output to %q: %v", demoBad, err) 53 | } 54 | t.Fatalf("test output differs; run\n\tdiff %s %s\nfor details", demoBad, demoOut) 55 | } 56 | err = os.Remove(demoBad) 57 | if err != nil { 58 | t.Logf("error removing test output file %q: %v", demoBad, err) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /testdata/unary_int.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Unary operations on small ints. 6 | 7 | )seed 0 8 | ?10 9 | 7 10 | 11 | 23 12 | 23 13 | 14 | + 23 15 | 23 16 | 17 | +-23 18 | -23 19 | 20 | - 23 21 | -23 22 | 23 | --23 24 | 23 25 | 26 | - -23 27 | 23 28 | 29 | /23 30 | 1/23 31 | 32 | /-23 33 | -1/23 34 | 35 | sgn -1 36 | -1 37 | 38 | sgn 0 39 | 0 40 | 41 | sgn 75 42 | 1 43 | 44 | !0 45 | 1 46 | 47 | !1 48 | 1 49 | 50 | !10 51 | 3628800 52 | 53 | !iota 10 54 | 1 2 6 24 120 720 5040 40320 362880 3628800 55 | 56 | ^1 57 | -2 58 | 59 | ^0x33 60 | -52 61 | 62 | not 0 63 | 1 64 | 65 | not 1 66 | 0 67 | 68 | not 3 69 | 0 70 | 71 | abs -10 72 | 10 73 | 74 | abs 0 75 | 0 76 | 77 | abs 10 78 | 10 79 | 80 | floor -1 81 | -1 82 | 83 | floor 0 84 | 0 85 | 86 | floor 1 87 | 1 88 | 89 | ceil -1 90 | -1 91 | 92 | ceil 0 93 | 0 94 | 95 | ceil 1 96 | 1 97 | 98 | # issue #41 99 | n = 1 drop iota 10; (ceil (rho n)/2) take n 100 | 2 3 4 5 6 101 | 102 | n = 1 drop iota 10; (floor (rho n)/2) take n 103 | 2 3 4 5 104 | 105 | 106 | iota 0 107 | # 108 | 109 | iota 1 110 | 1 111 | 112 | iota 10 113 | 1 2 3 4 5 6 7 8 9 10 114 | 115 | rho rho 0 116 | 0 117 | 118 | rho rho 10 119 | 0 120 | 121 | ,3 122 | 3 123 | 124 | rot 3 125 | 3 126 | 127 | flip 3 128 | 3 129 | 130 | box 3 131 | 3 132 | 133 | first 3 134 | 3 135 | 136 | print 1; print 2 137 | 1 138 | 2 139 | 140 | 141 | -------------------------------------------------------------------------------- /value/assign.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | // Code for assignment, a little intricate as there are many cases and many 8 | // validity checks. 9 | 10 | // QuietValue is an implementation of Value that is created as the result of an 11 | // assignment or print operator. It can be type-asserted to discover whether to 12 | // avoid printing the results of the expression. 13 | type QuietValue struct { 14 | Value 15 | } 16 | 17 | var scalarShape = []int{1} // The assignment shape vector for a scalar 18 | 19 | func assign(context Context, b *BinaryExpr) Value { 20 | rhs := b.Right.Eval(context).Inner() 21 | Assign(context, b.Left, b.Right, rhs) 22 | return QuietValue{Value: rhs} 23 | } 24 | 25 | func Assign(context Context, left, right Expr, rhs Value) { 26 | // We know the left is a variableExpr or index expression. 27 | // Special handling as we must not evaluate the left - it is an l-value. 28 | // But we need to process the indexing, if it is an index expression. 29 | switch lhs := left.(type) { 30 | case *VarExpr: 31 | if lhs.Local >= 1 { 32 | context.Local(lhs.Local).Assign(rhs) 33 | } else { 34 | context.AssignGlobal(lhs.Name, rhs) 35 | } 36 | return 37 | case *IndexExpr: 38 | switch lv := lhs.Left.(type) { 39 | case *VarExpr: 40 | IndexAssign(context, lhs, lhs.Left, lv, lhs.Right, right, rhs) 41 | return 42 | } 43 | case VectorExpr: 44 | // Simultaneous assignment requires evaluation of RHS before assignment. 45 | rhs, ok := rhs.(*Vector) 46 | if !ok { 47 | Errorf("rhs of assignment to (%s) not a vector", lhs.ProgString()) 48 | } 49 | if len(lhs) != rhs.Len() { 50 | Errorf("length mismatch in assignment to (%s)", lhs.ProgString()) 51 | } 52 | for i := rhs.Len() - 1; i >= 0; i-- { 53 | Assign(context, lhs[i], nil, rhs.At(i)) 54 | } 55 | return 56 | } 57 | // unexpected: parser should have caught this 58 | Errorf("internal error: cannot assign to %s", left.ProgString()) 59 | } 60 | -------------------------------------------------------------------------------- /testdata/exec_fail.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Things that should cause failures. 6 | # Comment line beginning "Expect: " is error we expect. 7 | 8 | # Expect: undefined global variable "x" 9 | x 10 | # 11 | 12 | # Expect: invalid code points in string 13 | '\x80' 14 | # 15 | 16 | # Expect: cannot index 1 (int) 17 | 1[1] 18 | # 19 | 20 | # Expect: cannot index 1/2 (rational) 21 | 1/2 [1] 22 | # 23 | 24 | # Expect: cannot index log 2 (float) 25 | (log 2)[1] 26 | # 27 | 28 | # Expect: invalid index (2) (type float) in (1 2)[1 2 (float 2)] 29 | (1 2)[1 2 (float 2)] 30 | # 31 | 32 | # Expect: zero denominator in rational 33 | 1/0 34 | # 35 | 36 | # Expect: division by zero 37 | 1 / 0 38 | # 39 | 40 | # Expect: division by zero 41 | 1 / 2 2 rho 0 42 | # 43 | 44 | # Expect: shape mismatch (4) != (2) in assignment x[1] = 1 2 45 | x = 3 4 rho iota 12; x[1]=1 2 46 | # 47 | 48 | # Expect: unexpected EOF 49 | op inc b = 50 | b + 1 51 | | 52 | # 53 | 54 | # Expect: no definition for unary foo 55 | opdelete foo x 56 | # 57 | 58 | # Expect: no definition for binary foo 59 | opdelete x foo y 60 | # 61 | 62 | # Expect: usage: sys "read" "filename" 63 | sys 'read' 64 | # 65 | 66 | # Expect: sys "abc" not defined 67 | sys 'abc' 68 | # 69 | 70 | # Expect: rot: count must be small integer 71 | 0 1 rot iota 6 72 | # 73 | 74 | # Expect: argument name "f" is function name 75 | op f (f x) = x 76 | 77 | # Expect: multiple arguments named "x" 78 | op f (x y x) = x 79 | 80 | # Expect: multiple arguments named "x" 81 | op x f x = x 82 | 83 | # Expect: multiple arguments named "x" 84 | op (x y) f (z x) = x 85 | 86 | # Issue 199: no check for reduce first of degenerate matrix. Reduce had the check. 87 | # Expect: shape for matrix is degenerate: (0 3 0) 88 | +/ (0 rho 0) o.== 1 2 3 o.== 0 rho 0 89 | 90 | # Expect: shape for matrix is degenerate: (0 3) 91 | +/% (0 rho 0) o.== 1 2 3 92 | 93 | # iota argument must be a small integer: (buggy) 94 | iota box 'buggy' 95 | 96 | -------------------------------------------------------------------------------- /testdata/inner.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Inner products. 6 | 7 | # Scalars 8 | 9 | 3 +.* 5 10 | 15 11 | 12 | 1/3 +.* 1/4 13 | 1/12 14 | 15 | 3e10 +.* 5e10 16 | 1500000000000000000000 17 | 18 | # Vectors 19 | 20 | 2 3 4 +.* 2 3 4 21 | 29 22 | 23 | 2 3 4 *.+ 2 3 4 24 | 192 25 | 26 | 2 3 4 +.min 1 3 4 27 | 8 28 | 29 | 2 3 4 min.* 1 2 3 30 | 2 31 | 32 | 2 3 4 min.max 1 2 3 33 | 2 34 | 35 | # Lexical corner case. 36 | 2 3 4 -.max 1 2 3 37 | 2 - 3 - 4 38 | 3 39 | 3 40 | 41 | # Matrices 42 | 43 | x = 3 3 rho iota 10 44 | x +.* x 45 | 30 36 42 46 | 66 81 96 47 | 102 126 150 48 | 49 | x = 3 4 rho iota 12 50 | y = 4 3 rho iota 12 51 | x+.*y 52 | 70 80 90 53 | 158 184 210 54 | 246 288 330 55 | 56 | x = 3 3 rho iota 9 57 | y= 3 5 rho iota 12 58 | x +.* y 59 | 46 52 22 28 34 60 | 100 115 58 73 88 61 | 154 178 94 118 142 62 | 63 | 1 0 1 +.* 3 3 rho iota 9 64 | 8 10 12 65 | 66 | (3 3 rho iota 9) +.* 1 0 1 67 | 4 10 16 68 | 69 | 1 1 1 -.* 1 2 3 70 | 1 - 2 - 3 71 | 2 72 | 2 73 | 74 | (2 3 rho 1 1 1 2 2 2) -.* (3 2 rho iota 6) 75 | 3 4 76 | 6 8 77 | 78 | (2 3 4 rho iota 24) +.* 1 + (4 3 2 rho iota 24) 79 | [1 * * *]: 80 | ┌ ┐ 81 | │ 140 150│ 82 | │ 160 170│ 83 | │ 180 190│ 84 | └ ┘ 85 | ┌ ┐ 86 | │ 316 342│ 87 | │ 368 394│ 88 | │ 420 446│ 89 | └ ┘ 90 | ┌ ┐ 91 | │ 492 534│ 92 | │ 576 618│ 93 | │ 660 702│ 94 | └ ┘ 95 | 96 | [2 * * *]: 97 | ┌ ┐ 98 | │ 668 726│ 99 | │ 784 842│ 100 | │ 900 958│ 101 | └ ┘ 102 | ┌ ┐ 103 | │ 844 918│ 104 | │ 992 1066│ 105 | │1140 1214│ 106 | └ ┘ 107 | ┌ ┐ 108 | │1020 1110│ 109 | │1200 1290│ 110 | │1380 1470│ 111 | └ ┘ 112 | 113 | (3 4 rho iota 12) +.* 1 + (4 3 2 rho iota 24) 114 | ┌ ┐ 115 | │140 150│ 116 | │160 170│ 117 | │180 190│ 118 | └ ┘ 119 | ┌ ┐ 120 | │316 342│ 121 | │368 394│ 122 | │420 446│ 123 | └ ┘ 124 | ┌ ┐ 125 | │492 534│ 126 | │576 618│ 127 | │660 702│ 128 | └ ┘ 129 | -------------------------------------------------------------------------------- /mobile/help_gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build ignore 6 | // +build ignore 7 | 8 | package main 9 | 10 | import ( 11 | "bytes" 12 | "fmt" 13 | "go/build" 14 | "go/doc" 15 | "go/format" 16 | "go/parser" 17 | "go/token" 18 | "log" 19 | "os" 20 | ) 21 | 22 | func main() { 23 | pkg, err := build.Import("robpike.io/ivy", "", build.ImportComment) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | fs := token.NewFileSet() 28 | pkgs, err := parser.ParseDir(fs, pkg.Dir, nil, parser.ParseComments) 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | astPkg := pkgs[pkg.Name] 33 | if astPkg == nil { 34 | log.Fatalf("failed to locate %s package", pkg.Name) 35 | } 36 | 37 | docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls) 38 | 39 | htmlBuf := new(bytes.Buffer) 40 | fmt.Fprintln(htmlBuf, ``) 41 | fmt.Fprintln(htmlBuf, head) 42 | fmt.Fprintln(htmlBuf, ``) 43 | doc.ToHTML(htmlBuf, docPkg.Doc, nil) 44 | fmt.Fprintln(htmlBuf, ``) 45 | 46 | goBuf := new(bytes.Buffer) 47 | fmt.Fprintf(goBuf, `package mobile // import "robpike.io/ivy/mobile"`+"\n\n") 48 | fmt.Fprintf(goBuf, `// Code generated by "go run help_gen.go > help.go"; DO NOT EDIT.`+"\n") 49 | fmt.Fprintf(goBuf, "const help = `%s`\n", sanitize(htmlBuf.Bytes())) 50 | 51 | buf, err := format.Source(goBuf.Bytes()) 52 | if err != nil { 53 | log.Fatalf("failed to gofmt: %v", err) 54 | } 55 | os.Stdout.Write(buf) 56 | } 57 | 58 | func sanitize(b []byte) []byte { 59 | // Replace ` with `+"`"+` 60 | return bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1) 61 | } 62 | 63 | const head = ` 64 | 65 | 85 | ` 86 | -------------------------------------------------------------------------------- /testdata/debug.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Debug printing. 6 | 7 | )debug parse 8 | 23 9 | 1 10 | 11 | 23 12 | 13 | )debug parse 14 | 3 4 rho iota 12 15 | 1 16 | (<3 4> rho (iota )) 17 | 1 2 3 4 18 | 5 6 7 8 19 | 9 10 11 12 20 | 21 | )debug parse 22 | op a base b = ((ceil b log a) rho b) encode a 23 | 1 24 | (((ceil ( log )) rho ) encode ) 25 | op a base b = (((ceil ( log )) rho ) encode ) 26 | 27 | )debug tokens 28 | 23 29 | 1 30 | :2: emit Number: "23" 31 | :3: emit Newline: "\n" 32 | 23 33 | 34 | # Fixed bugs in lexing: leading + wasn't part of a number, for example, even though - was. 35 | )debug tokens 36 | +2 37 | 1 38 | :2: emit Number: "+2" 39 | :3: emit Newline: "\n" 40 | 2 41 | 42 | )debug tokens 43 | -1/2j-5/2 44 | 1 45 | :2: emit Number: "-1/2j-5/2" 46 | :3: emit Newline: "\n" 47 | -1/2j-5/2 48 | 49 | )debug tokens 50 | op a base b = ((ceil b log a) rho b) encode a 51 | 1 52 | :2: emit Op: "op" 53 | :2: emit Identifier: "a" 54 | :2: emit Identifier: "base" 55 | :2: emit Identifier: "b" 56 | :2: emit Assign: "=" 57 | :2: emit LeftParen: "(" 58 | :2: emit LeftParen: "(" 59 | :2: emit Identifier: "ceil" 60 | :2: emit Identifier: "b" 61 | :2: emit Identifier: "log" 62 | :2: emit Identifier: "a" 63 | :2: emit RightParen: ")" 64 | :2: emit Identifier: "rho" 65 | :2: emit Identifier: "b" 66 | :2: emit RightParen: ")" 67 | :2: emit Identifier: "encode" 68 | :2: emit Identifier: "a" 69 | :3: emit Newline: "\n" 70 | 71 | )debug tokens 72 | )debug tokens 73 | 1 74 | :2: emit RightParen: ")" 75 | :2: emit Identifier: "debug" 76 | :2: emit Identifier: "tokens" 77 | :3: emit Newline: "\n" 78 | 0 79 | 80 | )debug types 81 | 23 82 | 1 83 | value.Int 84 | 23 85 | 86 | )debug types 87 | 'c' 88 | 1 89 | value.Char 90 | c 91 | 92 | )debug types 93 | 1 2 3 94 | 1 95 | *value.Vector 96 | 1 2 3 97 | 98 | )debug types 99 | sqrt 2 100 | 1 101 | value.BigFloat 102 | 1.41421356237 103 | 104 | )debug types 105 | 1.41421356237 106 | 1 107 | value.BigRat 108 | 141421356237/100000000000 109 | 110 | )debug types 111 | 2 3 rho iota 6 112 | 1 113 | *value.Matrix 114 | 1 2 3 115 | 4 5 6 116 | -------------------------------------------------------------------------------- /demo/demo.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package demo implements the I/O for running the )demo 6 | // special command. The script for the demo is in demo.ivy 7 | // in this directory. Its content is embedded in this source file. 8 | package demo 9 | 10 | import ( 11 | "bufio" 12 | "bytes" 13 | "fmt" 14 | "io" 15 | 16 | _ "embed" 17 | ) 18 | 19 | //go:embed demo.ivy 20 | var demoText []byte 21 | 22 | // Text returns the input text for the standard demo. 23 | func Text() string { 24 | return string(demoText) 25 | } 26 | 27 | // Run runs the demo. The arguments are the user's input, a Writer used to deliver 28 | // text to an ivy interpreter, and a Writer for the output. It assumes that ivy is 29 | // writing to the same output. Ivy expressions are read from a file (maintained in 30 | // demo.ivy but embedded in the package). When the user hits a blank line, the next 31 | // line from the file is delivered to ivy. If the user's input line has text, that 32 | // is delivered instead and the file does not advance. 33 | // A nil userInput ignores the user and just runs the script. 34 | func Run(userInput io.Reader, toIvy io.Writer, output io.Writer) error { 35 | text := demoText // Don't overwrite the global! 36 | var scan *bufio.Scanner 37 | if userInput != nil { 38 | scan = bufio.NewScanner(userInput) 39 | } 40 | nextLine := func() (line []byte) { 41 | nl := bytes.IndexByte(text, '\n') 42 | if nl < 0 { // EOF or incomplete line. 43 | return nil 44 | } 45 | line, text = text[:nl+1], text[nl+1:] 46 | return line 47 | } 48 | // Show first line, with instructions, before accepting user input. 49 | output.Write(nextLine()) 50 | for userInput == nil || scan.Scan() { 51 | if userInput != nil && len(scan.Bytes()) > 0 { 52 | // User typed a non-empty line of text; send that. 53 | line := []byte(fmt.Sprintf("%s\n", scan.Bytes())) 54 | // "quit" terminates. 55 | if string(bytes.TrimSpace(line)) == "quit" { 56 | break 57 | } 58 | if _, err := toIvy.Write(line); err != nil { 59 | return err 60 | } 61 | } else { 62 | // User typed newline; send next line of file's text. 63 | line := nextLine() 64 | if line == nil { 65 | break 66 | } 67 | output.Write(line) 68 | if _, err := toIvy.Write(line); err != nil { 69 | return err 70 | } 71 | } 72 | } 73 | if scan == nil { 74 | return nil 75 | } 76 | return scan.Err() 77 | } 78 | -------------------------------------------------------------------------------- /value/loop.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "math/big" 9 | 10 | "robpike.io/ivy/config" 11 | ) 12 | 13 | type loop struct { 14 | name string // The name of the function we are evaluating. 15 | i uint64 // Loop count. 16 | maxIterations uint64 // When to give up. 17 | arg *big.Float // original argument to function; only used for diagnostic. 18 | prevZ *big.Float // Result from the previous iteration. 19 | delta *big.Float // |Change| from previous iteration. 20 | } 21 | 22 | // newLoop returns a new loop checker. The arguments are the name 23 | // of the function being evaluated, the argument to the function, and 24 | // the maximum number of iterations to perform before giving up. 25 | // The last number in terms of iterations per bit, so the caller can 26 | // ignore the precision setting. 27 | func newLoop(conf *config.Config, name string, x *big.Float, itersPerBit uint) *loop { 28 | return &loop{ 29 | name: name, 30 | arg: newF(conf).Set(x), 31 | maxIterations: 10 + uint64(itersPerBit*conf.FloatPrec()), 32 | prevZ: newF(conf), 33 | delta: newF(conf), 34 | } 35 | } 36 | 37 | // done reports whether the loop is done. If it does not converge 38 | // after the maximum number of iterations, it errors out. 39 | // It will not return before doing at least 3 iterations. Some 40 | // series (such as exp(-1) hit zero along the way. 41 | func (l *loop) done(z *big.Float) bool { 42 | const minIterations = 3 43 | l.delta.Sub(l.prevZ, z) 44 | sign := l.delta.Sign() 45 | if sign == 0 && l.i >= minIterations { 46 | return true 47 | } 48 | if sign < 0 { 49 | l.delta.Neg(l.delta) 50 | } 51 | // Check if delta is no bigger than the smallest change in z that can be 52 | // represented with the given precision. 53 | var eps big.Float 54 | eps.SetMantExp(eps.SetUint64(1), z.MantExp(nil)-int(z.Prec())) 55 | if l.delta.Cmp(&eps) <= 0 && l.i >= minIterations { 56 | return true 57 | } 58 | l.i++ 59 | if l.i == l.maxIterations { 60 | // Users should never see this, but they sometimes do. 61 | // TODO: Find a better termination condition. 62 | Errorf("%s %s: did not converge after %d iterations; prev,last result %s,%s delta %s", l.name, BigFloat{l.arg}, l.maxIterations, BigFloat{z}, BigFloat{l.prevZ}, BigFloat{l.delta}) 63 | } 64 | l.prevZ.Set(z) 65 | return false 66 | } 67 | -------------------------------------------------------------------------------- /testdata/binary_complex.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Binary operations with complex numbers. 6 | 7 | 2 j 3 8 | 2j3 9 | 10 | 1 2 3 j 4 5 6 11 | 1j4 2j5 3j6 12 | 13 | 2 j 3 4 5 14 | 2j3 2j4 2j5 15 | 16 | 2j3 + 4j5 17 | 6j8 18 | 19 | 2j3 - 4j5 20 | -2j-2 21 | 22 | 2j3 * 4j5 23 | -7j22 24 | 25 | 2j3 / 4j5 26 | 23/41j2/41 27 | 28 | 1j2 == 1j1 1j2 1j3 2j2 29 | 0 1 0 0 30 | 31 | 1j2 != 1j1 1j2 1j3 2j2 32 | 1 0 1 1 33 | 34 | 1j2 === 1j2; 1j2 !== 1j2 35 | 1 0 36 | 37 | 1j2 === 1j3; 1j2 !== 1j3 38 | 0 1 39 | 40 | 0j0 and 0j0 0j1 1j0 1j1 41 | 0 0 0 0 42 | 43 | 1j1 and 0j0 0j1 1j0 1j1 44 | 0 1 1 1 45 | 46 | 0j0 or 0j0 0j1 1j0 1j1 47 | 0 1 1 1 48 | 49 | 1j1 or 0j0 0j1 1j0 1j1 50 | 1 1 1 1 51 | 52 | 0j0 xor 0j0 0j1 1j0 1j1 53 | 0 1 1 1 54 | 55 | 1j1 xor 0j0 0j1 1j0 1j1 56 | 1 0 0 0 57 | 58 | 0j0 nand 0j0 0j1 1j0 1j1 59 | 1 1 1 1 60 | 61 | 1j1 nand 0j0 0j1 1j0 1j1 62 | 1 0 0 0 63 | 64 | 0j0 nor 0j0 0j1 1j0 1j1 65 | 1 0 0 0 66 | 67 | 1j1 nor 0j0 0j1 1j0 1j1 68 | 0 0 0 0 69 | 70 | 0j1 ** -1 + iota 4 71 | 1 0j1 -1 0j-1 72 | 73 | 0j1 ** - -1 + iota 4 74 | 1 0j-1 -1 0j1 75 | 76 | 1j1 ** -1 + iota 8 77 | 1 1j1 0j2 -2j2 -4 -4j-4 0j-8 8j-8 78 | 79 | 1j1 ** - -1 + iota 8 80 | 1 1/2j-1/2 0j-1/2 -1/4j-1/4 -1/4 -1/8j1/8 0j1/8 1/16j1/16 81 | 82 | # A log B 83 | 8 1 rho 10 log 0j-1 0j1 1j-1 1j0 1j1 -1j-1 -1j0 -1j1 # no log 0j0 84 | 0j-0.682188176921 85 | 0j0.682188176921 86 | 0.150514997832j-0.34109408846 87 | 0 88 | 0.150514997832j0.34109408846 89 | 0.150514997832j-1.02328226538 90 | 0j1.36437635384 91 | 0.150514997832j1.02328226538 92 | 93 | 8 1 rho 1j1 log 0j-1 0j1 1j-1 1j0 1j1 -1j-1 -1j0 -1j1 # no log 0j0 94 | -1.67403202784j-0.738702122273 95 | 1.67403202784j0.738702122273 96 | -0.674032027837j-0.738702122273 97 | 0 98 | 1 99 | -2.34806405567j-1.47740424455 100 | 3.34806405567j1.47740424455 101 | 2.67403202784j0.738702122273 102 | 103 | # A ** B 104 | 1j1 ** 8 1 rho 0j-1 0j0 0j1 1j-1 1j0 1j1 -1j-1 -1j0 -1j1 105 | 2.06287223508j-0.74500706218 106 | 1 107 | 0.428829006294j0.154871752464 108 | 2.80787929726j1.3178651729 109 | 1j1 110 | 0.27395725383j0.583700758759 111 | 0.658932586451j-1.40393964863 112 | 1/2j-1/2 113 | 114 | -4 ** 0.5 # Uses sqrt internally for speed and precision 115 | 0j2 116 | 117 | -4 ** 0.25 118 | 1j1 119 | 120 | # Shrink complex values. Issue #216 121 | op n F ω = ω**e o.* e=-1+iota n 122 | f +.* 1/4 * conj transp f = 4 F 0j-1 123 | 1 0 0 0 124 | 0 1 0 0 125 | 0 0 1 0 126 | 0 0 0 1 127 | -------------------------------------------------------------------------------- /testdata/binary_bigfloat.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Binary operations with big floats. 6 | 7 | )format "%.16g" 8 | 1 + (sqrt 2) 9 | 2.414213562373095 10 | 11 | )format "%.16g" 12 | 1 - (sqrt 2) 13 | -0.414213562373095 14 | 15 | )format "%.16g" 16 | 2 * (sqrt 2) 17 | 2.82842712474619 18 | 19 | )format "%.16g" 20 | 1/sqrt 2 21 | 0.7071067811865475 22 | 23 | (float 3.5) mod float 2.5 24 | 1 25 | 26 | (float 3.5) mod float 2 27 | 1.5 28 | 29 | (float -3.5) mod float 2 30 | 0.5 31 | 32 | (float 3.5) mod float -2 33 | 1.5 34 | 35 | (float -3.5) mod float -2 36 | 0.5 37 | 38 | (sqrt 2) == (sqrt iota 3) 39 | 0 1 0 40 | 41 | (sqrt 2) === (sqrt 2); (sqrt 2) !== (sqrt 2) 42 | 1 0 43 | 44 | (sqrt 2) != (sqrt iota 3) 45 | 1 0 1 46 | 47 | (sqrt 2) === (sqrt 3); (sqrt 2) !== (sqrt 3) 48 | 0 1 49 | 50 | (sqrt 2) < (sqrt iota 3) 51 | 0 0 1 52 | 53 | (sqrt 2) <= (sqrt iota 3) 54 | 0 1 1 55 | 56 | (sqrt 2) > (sqrt iota 3) 57 | 1 0 0 58 | 59 | (sqrt 2) >= (sqrt iota 3) 60 | 1 1 0 61 | 62 | 2 log 2**32 63 | 32 64 | 65 | # Was bug; overwrote arguments. Issue 30. 66 | e**pi 67 | e 68 | pi 69 | 23.1406926328 70 | 2.71828182846 71 | 3.14159265359 72 | 73 | (float 0) ** 1e100 74 | 0 75 | 76 | (float 1) ** 1e100 77 | 1 78 | 79 | (sqrt 0) and sqrt 2 80 | 0 81 | 82 | (sqrt 2) and sqrt 2 83 | 1 84 | 85 | (sqrt 0) or sqrt 2 86 | 1 87 | 88 | (sqrt 2) or sqrt 2 89 | 1 90 | 91 | (sqrt 0) xor sqrt 2 92 | 1 93 | 94 | (sqrt 2) xor sqrt 2 95 | 0 96 | 97 | (sqrt 0) nor sqrt 2 98 | 0 99 | 100 | (sqrt 2) nor sqrt 2 101 | 0 102 | 103 | (sqrt 0) nand sqrt 2 104 | 1 105 | 106 | (sqrt 2) nand sqrt 2 107 | 0 108 | 109 | (sqrt 2) min sqrt 3 110 | 1.41421356237 111 | 112 | (sqrt 2) max sqrt 3 113 | 1.73205080757 114 | 115 | # High precision exponential 116 | )format '%.75f' 117 | e**2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983 118 | 10.000000000000000000000000000000000000000000000000000000000000000000000000000 119 | 120 | )format "%.16g" 121 | (sqrt 2) ** iota 10 122 | 1.414213562373095 2 2.82842712474619 4 5.65685424949238 8 11.31370849898476 16 22.62741699796952 32 123 | 124 | )format "%.16g" 125 | 1/(sqrt 2) ** -iota 10 126 | 1.414213562373095 2 2.82842712474619 4 5.65685424949238 8 11.31370849898476 16 22.62741699796952 32 127 | 128 | 129 | )format "%.16g" 130 | e**pi 131 | 23.14069263277927 132 | 133 | # Once a bug: the *. looks like the start of an operator. 134 | 3*.7 135 | 21/10 136 | -------------------------------------------------------------------------------- /parse/helpdocs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package parse 6 | 7 | import ( 8 | "strings" 9 | ) 10 | 11 | func (p *Parser) helpOverview() { 12 | p.Println("Overview:") 13 | p.Println("\t)help intro") 14 | p.Println("Unary operators:") 15 | p.Println("\t)help unary") 16 | p.Println("Binary operators:") 17 | p.Println("\t)help binary") 18 | p.Println("Axis operators:") 19 | p.Println("\t)help axis") 20 | p.Println("Types and conversions:") 21 | p.Println("\t)help types") 22 | p.Println("Constants:") 23 | p.Println("\t)help constants") 24 | p.Println("Characters:") 25 | p.Println("\t)help char") 26 | p.Println("User-defined ops:") 27 | p.Println("\t)help ops") 28 | p.Println("Special commands:") 29 | p.Println("\t)help special") 30 | p.Println("Search docs:") 31 | p.Println("\t)help about ") 32 | p.Println("Specific op:") 33 | p.Println("\t)help ") 34 | p.Println() 35 | p.Println("More at: https://pkg.go.dev/robpike.io/ivy") 36 | } 37 | 38 | func (p *Parser) printHelpBlock(start, end string) { 39 | for i, line := range helpLines { 40 | if strings.HasPrefix(line, start) { 41 | for _, line := range helpLines[i:] { 42 | if strings.HasPrefix(line, end) { 43 | return 44 | } 45 | p.Printf("%s\n", line) 46 | } 47 | } 48 | } 49 | } 50 | 51 | func (p *Parser) helpAbout(str string) { // str is already lowercase. 52 | for _, line := range helpLines { 53 | if strings.Contains(strings.ToLower(line), str) { 54 | p.Printf("%s\n", line) 55 | } 56 | } 57 | } 58 | 59 | func (p *Parser) help(str string) { 60 | unaryPair, unary := helpUnary[str] 61 | binaryPair, binary := helpBinary[str] 62 | axisPair, axis := helpAxis[str] 63 | if !unary && !binary && !axis { 64 | p.Printf("no docs for %q\n", str) 65 | return 66 | } 67 | if unary { 68 | p.Println("Unary operators:") 69 | p.Println(" Name APL Ivy Meaning") 70 | for i := unaryPair.start; i <= unaryPair.end; i++ { 71 | p.Printf("%s\n", helpLines[i]) 72 | } 73 | } 74 | if binary { 75 | if unary { 76 | p.Println() 77 | } 78 | p.Println("Binary operators:") 79 | p.Println(" Name APL Ivy Meaning") 80 | for i := binaryPair.start; i <= binaryPair.end; i++ { 81 | p.Printf("%s\n", helpLines[i]) 82 | } 83 | } 84 | if axis { 85 | if unary || binary { 86 | p.Println() 87 | } 88 | p.Println("Axis operators:") 89 | p.Println(" Name APL Ivy APL Example Ivy Example Meaning (of example)") 90 | for i := axisPair.start; i <= axisPair.end; i++ { 91 | p.Printf("%s\n", helpLines[i]) 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /testdata/scan.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Scanning. For each operation we do scan (\) and scan first (\%). 6 | 7 | # Scalars 8 | 9 | *\2 10 | 2 11 | 12 | *\%2 13 | 2 14 | 15 | +\1e10 16 | 10000000000 17 | 18 | +\%1e10 19 | 10000000000 20 | 21 | *\ 3/2 22 | 3/2 23 | 24 | *\% 3/2 25 | 3/2 26 | 27 | *\3j2 28 | 3j2 29 | 30 | *\%3j2 31 | 3j2 32 | 33 | # Vectors 34 | 35 | +\iota 10 36 | 1 3 6 10 15 21 28 36 45 55 37 | 38 | +\%iota 10 39 | 1 3 6 10 15 21 28 36 45 55 40 | 41 | -\iota 10 42 | 1 -1 2 -2 3 -3 4 -4 5 -5 43 | 44 | -\%iota 10 45 | 1 -1 2 -2 3 -3 4 -4 5 -5 46 | 47 | # associative scan should run in linear time - this takes ~10m if quadratic 48 | +/ +\ iota 100000 49 | 166671666700000 50 | +/ +\% iota 100000 51 | 166671666700000 52 | 53 | # Matrices 54 | 55 | +\3 4 rho iota 100 56 | 1 3 6 10 57 | 5 11 18 26 58 | 9 19 30 42 59 | 60 | +\%3 4 rho iota 100 61 | 1 2 3 4 62 | 6 8 10 12 63 | 15 18 21 24 64 | 65 | -\3 4 rho iota 100 66 | 1 -1 2 -2 67 | 5 -1 6 -2 68 | 9 -1 10 -2 69 | 70 | -\%3 4 rho iota 100 71 | 1 2 3 4 72 | -4 -4 -4 -4 73 | 5 6 7 8 74 | 75 | +\3 4 5 rho iota 100 76 | ┌ ┐ 77 | │ 1 3 6 10 15│ 78 | │ 6 13 21 30 40│ 79 | │ 11 23 36 50 65│ 80 | │ 16 33 51 70 90│ 81 | └ ┘ 82 | ┌ ┐ 83 | │ 21 43 66 90 115│ 84 | │ 26 53 81 110 140│ 85 | │ 31 63 96 130 165│ 86 | │ 36 73 111 150 190│ 87 | └ ┘ 88 | ┌ ┐ 89 | │ 41 83 126 170 215│ 90 | │ 46 93 141 190 240│ 91 | │ 51 103 156 210 265│ 92 | │ 56 113 171 230 290│ 93 | └ ┘ 94 | 95 | +\%3 4 5 rho iota 100 96 | ┌ ┐ 97 | │ 1 2 3 4 5│ 98 | │ 6 7 8 9 10│ 99 | │ 11 12 13 14 15│ 100 | │ 16 17 18 19 20│ 101 | └ ┘ 102 | ┌ ┐ 103 | │ 22 24 26 28 30│ 104 | │ 32 34 36 38 40│ 105 | │ 42 44 46 48 50│ 106 | │ 52 54 56 58 60│ 107 | └ ┘ 108 | ┌ ┐ 109 | │ 63 66 69 72 75│ 110 | │ 78 81 84 87 90│ 111 | │ 93 96 99 102 105│ 112 | │108 111 114 117 120│ 113 | └ ┘ 114 | 115 | # Was bug in scanner, not resetting lastWidth in peek2. 116 | ΔJ=4 117 | θ = (0 - 7) + ΔJ*(1+ΔJ*(2)) 118 | θ 119 | 29 120 | 121 | op f x = x+1 # comment 122 | f 1 123 | 2 124 | 125 | op f x = 126 | x = x+1 # increment 127 | # comment here 128 | # comment here 129 | x = x-1# decrement 130 | x 131 | 132 | f 1 133 | 1 134 | -------------------------------------------------------------------------------- /talks/demo2.ivy: -------------------------------------------------------------------------------- 1 | #This is ivy. Each step in the demo is one line of input followed by some output. 2 | # Arithmetic 3 | 23 4 | 23 + 45 5 | # Rationals 6 | 1/3 7 | 1/3 + 4/5 8 | 1.2 9 | # Big numbers 10 | 1e10 # Still an integer. 11 | 1e100 # Still an integer. 12 | 2**64 13 | 2**640 14 | 2**6400 15 | # Characters 16 | 'x' 17 | char 0x61 18 | char 0x1f4a9 19 | code '💩' 20 | # Vectors 21 | 1 2 3 22 | 1 2 3 + 4 5 6 23 | 23 + 1 2 3 24 | 1 << 1 2 3 4 5 25 | iota 10 26 | 2 ** iota 100 27 | (2 ** iota 100) == (1< conf.FloatPrec(). 69 | z.SetPrec(c.Config().FloatPrec()) 70 | z.SetMantExp(z, exp/2) 71 | 72 | // Intermediates, allocated once. 73 | zSquared := newFloat(c) 74 | num := newFloat(c) 75 | den := newFloat(c) 76 | 77 | for loop := newLoop(c.Config(), "sqrt", x, 1); ; { 78 | zSquared.Mul(z, z) 79 | num.Sub(zSquared, x) 80 | den.Mul(floatTwo, z) 81 | num.Quo(num, den) 82 | z.Sub(z, num) 83 | if loop.done(z) { 84 | break 85 | } 86 | } 87 | return z 88 | } 89 | -------------------------------------------------------------------------------- /testdata/sys.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Tests for sys operations such as time. 6 | 7 | # In alphabetical order except for the time ones, which are trickier and 8 | # done last. 9 | 10 | sys 'base' 11 | 0 0 12 | 13 | )base 16 14 | '%d' text sys 'base' 15 | 16 16 16 | 17 | )ibase 16 18 | '%d' text sys 'base' 19 | 16 0 20 | 21 | sys 'format' 22 | "" 23 | 24 | )format "%g" 25 | sys 'format' 26 | "%g" 27 | 28 | sys 'maxbits' 29 | 1000000000 30 | 31 | )maxbits 999 32 | sys 'maxbits' 33 | 999 34 | 35 | sys 'maxdigits' 36 | 10000 37 | 38 | )maxdigits 999 39 | sys 'maxdigits' 40 | 999 41 | 42 | sys 'maxstack' 43 | 100000 44 | 45 | )maxstack 999 46 | sys 'maxstack' 47 | 999 48 | 49 | )obase 16 50 | '%d' text sys 'base' 51 | 0 16 52 | 53 | sys 'origin' 54 | 1 55 | 56 | )origin 5 57 | sys 'origin' 58 | 5 59 | 60 | sys 'prompt' 61 | "" 62 | 63 | )prompt ">>" 64 | sys 'prompt' 65 | ">>" 66 | 67 | # Now the time ones. Tricky because of time moving underfoot 68 | # and discrepancies due to the local time zone. 69 | 70 | # ivy_test.go sets this to make testing independent of location. 71 | )timezone 72 | UTC 0 73 | 74 | s=sys 'sec'; (s > 1.6e9) s < 3e9 75 | 1 1 76 | 77 | rho sys 'time' 78 | 7 79 | 80 | 2023 1 1 0 0 0 -1e9<= sys 'time' 81 | 1 1 1 1 1 1 1 82 | 83 | 3000 12 31 24 60 61 1e9 >= sys 'time' 84 | 1 1 1 1 1 1 1 85 | 86 | rho 'T' encode sys 'sec' 87 | 7 88 | 89 | 'T' encode 0 90 | 1970 1 1 0 0 0 0 91 | 92 | 'T' decode 'T' encode 0 93 | 0 94 | 95 | 'T' encode 'T' decode 2023 6 15 96 | 2023 6 15 0 0 0 0 97 | 98 | # We use (big) floats, so the low bit could round off the wrong way. 99 | 1e-9 >= s- 'T' decode 'T' encode s=sys 'sec' 100 | 1 101 | 102 | )timezone "EST" 103 | 'T' text 0 104 | Wed Dec 31 19:00:00 EST 1969 105 | 106 | # Check that what sys 'date' prints is the same as 'T' text secs. 107 | # But time can shift in the interim, so we look for general agreement. 108 | # They will agree perfectly unless a second ticks mid-expression. 109 | # Unless that second is New Year's, this is fine. 110 | 25 <= +/(sys 'date') == ('T' text sys 'sec') 111 | 1 112 | 113 | # Convert an interval into days, minutes, seconds. (98 days, 14 hours, 57 minutes and 15 seconds). 114 | 0 24 60 60 encode ('T' decode 2023 9 22 3 27 25)-'T' decode 2023 6 15 12 30 10 115 | 98 14 57 15 116 | 117 | # Test a very remote time can be built. 118 | 'T' text 'T' decode -4713 11 24 12 0 0 0 119 | Mon Nov 24 12:00:00 UTC -4713 120 | 121 | box@ sys 'read' 'testdata/hello.txt' 122 | (hello world) (Καλημέρα κόσμε) (こんにちは 世界) 123 | 124 | box@ sys 'read' 'testdata/no_newline.txt' 125 | (hello world) (Καλημέρα κόσμε) (こんにちは 世界) 126 | 127 | mix ivy@ sys 'read' 'testdata/matrix.txt' 128 | 1 2 3 4 129 | 5 6 7 8 130 | 131 | rho sys 'read' 'testdata/empty.txt' 132 | 0 133 | -------------------------------------------------------------------------------- /exec/function.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package exec 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | 11 | "robpike.io/ivy/value" 12 | ) 13 | 14 | // Function represents a unary or binary user-defined operator. 15 | type Function struct { 16 | IsBinary bool 17 | Name string 18 | Left value.Expr 19 | Right value.Expr 20 | Body []value.Expr 21 | Locals []string 22 | Globals []string 23 | } 24 | 25 | // argProgString builds a string representation of arg, to be used in printing the 26 | // source to an op. If the argument is a vector, it needs special handling to get 27 | // parentheses and nesting. 28 | func argProgString(b *strings.Builder, arg value.Expr) { 29 | switch expr := arg.(type) { 30 | case *value.VarExpr: 31 | b.WriteString(expr.ProgString()) 32 | return 33 | case value.VectorExpr: 34 | b.WriteRune('(') 35 | for i, elem := range expr { 36 | if i > 0 { 37 | b.WriteRune(' ') 38 | } 39 | argProgString(b, elem) 40 | } 41 | b.WriteRune(')') 42 | default: 43 | b.WriteString(fmt.Sprintf("", arg)) 44 | } 45 | } 46 | 47 | func (fn *Function) String() string { 48 | var b strings.Builder 49 | b.WriteString("op ") 50 | if fn.IsBinary { 51 | argProgString(&b, fn.Left) 52 | b.WriteRune(' ') 53 | } 54 | b.WriteString(fn.Name) 55 | b.WriteRune(' ') 56 | argProgString(&b, fn.Right) 57 | b.WriteString(" = ") 58 | if len(fn.Body) == 1 { 59 | b.WriteString(fn.Body[0].ProgString()) 60 | } else { 61 | for _, stmt := range fn.Body { 62 | b.WriteString("\n\t") 63 | b.WriteString(stmt.ProgString()) 64 | } 65 | } 66 | return b.String() 67 | } 68 | 69 | func (fn *Function) EvalUnary(context value.Context, right value.Value) value.Value { 70 | if fn.Body == nil { 71 | value.Errorf("unary %q undefined", fn.Name) 72 | } 73 | // It's known to be an exec.Context. 74 | c := context.(*Context) 75 | if uint(len(c.frameSizes)) >= c.config.MaxStack() { 76 | value.Errorf("stack overflow calling %q", fn.Name) 77 | } 78 | c.push(fn) 79 | defer c.pop() 80 | value.Assign(context, fn.Right, right, right) 81 | v := value.EvalFunctionBody(c, fn.Name, fn.Body) 82 | if v == nil { 83 | value.Errorf("no value returned by %q", fn.Name) 84 | } 85 | return v 86 | } 87 | 88 | func (fn *Function) EvalBinary(context value.Context, left, right value.Value) value.Value { 89 | if fn.Body == nil { 90 | value.Errorf("binary %q undefined", fn.Name) 91 | } 92 | // It's known to be an exec.Context. 93 | c := context.(*Context) 94 | if uint(len(c.frameSizes)) >= c.config.MaxStack() { 95 | value.Errorf("stack overflow calling %q", fn.Name) 96 | } 97 | c.push(fn) 98 | defer c.pop() 99 | value.Assign(context, fn.Left, left, left) 100 | value.Assign(context, fn.Right, right, right) 101 | v := value.EvalFunctionBody(c, fn.Name, fn.Body) 102 | if v == nil { 103 | value.Errorf("no value returned by %q", fn.Name) 104 | } 105 | return v 106 | } 107 | -------------------------------------------------------------------------------- /value/fac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import "math/big" 8 | 9 | // Implementation of factorial using the "swinging factorial" algorithm. 10 | // from Peter Luschny, https://oeis.org/A000142/a000142.pdf. 11 | 12 | // primeGen returns a function that generates primes from 2...n on successive calls. 13 | // Used in the factorization in the swing function. (TODO: Might be fun to make available.) 14 | func primeGen(n int) func() int { 15 | marked := make([]bool, n+1) // Starts at 0 for indexing simplicity. 16 | i := 2 17 | return func() int { 18 | for ; i <= n; i++ { 19 | if marked[i] { 20 | continue 21 | } 22 | for j := i; j <= n; j += i { 23 | marked[j] = true 24 | } 25 | return i 26 | } 27 | return 0 28 | } 29 | } 30 | 31 | // swing calculates the "swinging factorial" function of n, 32 | // which is n!/⌊n/2⌋!². 33 | // Swinging factorial table for reference. 34 | // 35 | // n 0 1 2 3 4 5 6 7 8 9 10 11 36 | // n𝜎 1 1 2 6 6 30 20 140 70 630 252 2772 37 | func swing(n int) *big.Int { 38 | nextPrime := primeGen(n) 39 | factors := make([]int, 0, 100) 40 | for { 41 | prime := nextPrime() 42 | if prime == 0 { 43 | break 44 | } 45 | q := n 46 | p := 1 47 | for q != 0 { 48 | q = q / prime 49 | if q&1 == 1 { 50 | p *= prime 51 | } 52 | } 53 | if p > 1 { 54 | factors = append(factors, p) 55 | } 56 | } 57 | return product(true, factors) 58 | } 59 | 60 | // product is called by swing to multiply the elements of the list. 61 | // This recursive multiplication looks slower but is 62 | // actually faster for many large numbers, despite the allocations 63 | // required to build the list in the swing factorial calculation. 64 | func product1(f []int) *big.Int { 65 | switch len(f) { 66 | case 0: 67 | return big.NewInt(1) 68 | case 1: 69 | return big.NewInt(int64(f[0])) 70 | } 71 | n := len(f) / 2 72 | left := product1(f[:n]) 73 | right := product1(f[n:]) 74 | return left.Mul(left, right) 75 | } 76 | 77 | // product is called by swing to multiply the elements of the list. 78 | // This recursive multiplication looks slower but is 79 | // actually faster for many large numbers, despite the allocations 80 | // required to build the list in the swing factorial calculation. 81 | func product(doPar bool, f []int) *big.Int { 82 | switch len(f) { 83 | case 0: 84 | return big.NewInt(1) 85 | case 1: 86 | return big.NewInt(int64(f[0])) 87 | } 88 | n := len(f) / 2 89 | left := product1(f[:n]) 90 | right := product1(f[n:]) 91 | r := left.Mul(left, right) 92 | return r 93 | } 94 | 95 | // factorial returns factorial of n using a "swinging 96 | // factorial" for roughly 2x speedup. 97 | func factorial(n int64) *big.Int { 98 | if n < 0 { 99 | Errorf("negative value %d for factorial", n) 100 | } 101 | if n < 2 { 102 | return big.NewInt(1) 103 | } 104 | s := swing(int(n)) 105 | f2 := factorial(n / 2) 106 | f2.Mul(f2, f2) 107 | f2.Mul(f2, s) 108 | return f2 109 | } 110 | -------------------------------------------------------------------------------- /testdata/base.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Input and output bases. 6 | # The testing harness resets ibase and obase before each test. 7 | 8 | # Make sure setting a big base doesn't break seeing words as commands. 9 | )base 16 10 | )base 10 11 | )base 12 | ibase 10 13 | obase 10 14 | 15 | )ibase 16 16 | 0; 1; 10; 16; abe; 3abe; a/b; a8add6a7f6a6d; 300j200 17 | 0 1 16 22 2750 15038 10/11 2967433346247277 768j512 18 | 19 | )base 16 20 | 0; 1; 10; 16; abe; 3abe; a/b; a8add6a7f6a6d; 300j200 21 | 0 1 10 16 abe 3abe a/b a8add6a7f6a6d 300j200 22 | 23 | )ibase 8 24 | 0; 1; 10; 32; 37/41; 2367433346247277; 300j200 25 | 0 1 8 26 31/33 87380498927295 192j128 26 | 27 | )base 8 28 | 0; 1; 10; 32; 37/41; 2367433346247277; 300j200 29 | 0 1 10 32 37/41 2367433346247277 300j200 30 | 31 | )ibase 2 32 | 0; 1; 101; 101010101001; 1111/1011; 111j101 33 | 0 1 5 2729 15/11 7j5 34 | 35 | )base 2 36 | 0; 1; 101; 101010101001; 1111/1011; 111j101 37 | 0 1 101 101010101001 1111/1011 111j101 38 | 39 | )ibase 10 40 | 0; 1; 10; 32; 37/41; 2367433346247277; 3j4 41 | 0 1 10 32 37/41 2367433346247277 3j4 42 | 43 | )base 10 44 | 0; 1; 10; 32; 37/41; 2367433346247277; 3j4 45 | 0 1 10 32 37/41 2367433346247277 3j4 46 | 47 | )base 0 48 | 0; 1; 10; 32; 37/41; 2367433346247277; 0x123j0123; 0b11; 0B11; 0o11; 0O11 49 | 0 1 10 32 37/41 2367433346247277 291j83 3 3 9 9 50 | 51 | )ibase 3 52 | 0; 1; 2; 102; 101020101001; 1211/2011; 12j22 53 | 0 1 2 11 201475 49/58 5j8 54 | 55 | )base 3 56 | 0; 1; 2; 102; 101020101001; 1211/2011; 12j22 57 | 0 1 2 102 101020101001 1211/2011 12j22 58 | 59 | )ibase 10 60 | )format "%x" 61 | 1; 16; 32; 64; 128**16; 16j256 62 | 1 10 20 40 10000000000000000000000000000 10j100 63 | 64 | )ibase 16 65 | )format "%d" 66 | 1; a; aa; aaa; aaa**a; aja 67 | 1 10 170 2730 22994632358756127051836490000000000 10j10 68 | 69 | )obase 5 70 | 1; 10; 100; 1234/5678 17j22 71 | 1 20 400 4432/42324 32j42 72 | 73 | )base 10 74 | x=2*3**100 75 | )ibase 3 76 | y=20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 77 | x==y 78 | 1 79 | 80 | )base 10 81 | x=2*3**100 82 | )ibase 3 83 | y=20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 84 | y==x/x 85 | 1 86 | 87 | # Was a bug. Leading 0 in floating point switched to base 8. 88 | 0.69; 09e1 89 | 69/100 90 90 | 91 | # Was a bug. 1/f was not seen as a fraction, so it misparsed as 1/(f+1). 92 | )base 16 93 | 1/f+1 94 | 10/f 95 | 96 | # Was a bug. An all-letters number in a large base was not lexing rationals and complexes, 97 | # but returning a number, an operator, and a number. This test makes sure we get 98 | # 2 tokens, not 4. 99 | )ibase 16 100 | abc/123 234 101 | 916/97 564 102 | 103 | # Underscores, but they work only in base 0. 104 | )base 0 105 | 33_44; 0x33_44; 0o7_7; 0b11_01; 345_456.5 106 | 3344 13124 63 13 690913/2 107 | 108 | # Hexadecimal floating point 109 | 0x1.0 0x1.0p3 0x1.0p-2 0x1_2.p2 0x1p1 110 | 1 8 1/4 72 2 111 | -------------------------------------------------------------------------------- /mobile/mobile.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // The mobile package provides a very narrow interface to ivy, 6 | // suitable for wrapping in a UI for mobile applications. 7 | // It is designed to work well with the gomobile tool by exposing 8 | // only primitive types. It's also handy for testing. 9 | // 10 | // TODO: This package (and ivy itself) has global state, so only 11 | // one execution stream (Eval or Demo) can be active at a time. 12 | package mobile // import "robpike.io/ivy/mobile" 13 | 14 | //go:generate sh -c "go run help_gen.go >help.go" 15 | 16 | import ( 17 | "bufio" 18 | "bytes" 19 | "fmt" 20 | "io" 21 | "strings" 22 | 23 | "robpike.io/ivy/config" 24 | "robpike.io/ivy/exec" 25 | "robpike.io/ivy/run" 26 | "robpike.io/ivy/value" 27 | ) 28 | 29 | var ( 30 | conf config.Config 31 | context value.Context 32 | ) 33 | 34 | func init() { 35 | Reset() 36 | } 37 | 38 | // On mobile platforms, the output gets turned into HTML. 39 | // Some characters go wrong there (< and > are handled in 40 | // Objective C or Java, but not all characters), tabs don't appear 41 | // at all, and runs of spaces are collapsed. Also for some reason 42 | // backslashes are trouble. Here is the hacky fix. 43 | var escaper = strings.NewReplacer(" ", "\u00A0", "\t", " ", "\\", "\") 44 | 45 | // Eval evaluates the input string and returns its output. 46 | // The output is HTML-safe, suitable for mobile platforms. 47 | func Eval(expr string) (string, error) { 48 | stdout := new(bytes.Buffer) 49 | stderr := new(bytes.Buffer) 50 | conf.SetErrOutput(stderr) 51 | run.Ivy(context, expr, stdout, stderr) 52 | result := escaper.Replace(stdout.String()) 53 | if stderr.Len() > 0 { 54 | return result, fmt.Errorf("%s", stderr.String()) 55 | } 56 | return result, nil 57 | } 58 | 59 | // Demo represents a running line-by-line demonstration. 60 | type Demo struct { 61 | scanner *bufio.Scanner 62 | } 63 | 64 | // NewDemo returns a new Demo that will scan the input text line by line. 65 | func NewDemo(input string) *Demo { 66 | // TODO: The state being reset should be local to the demo. 67 | // but that's not worth doing until ivy itself has no global state. 68 | Reset() 69 | return &Demo{ 70 | scanner: bufio.NewScanner(strings.NewReader(input)), 71 | } 72 | } 73 | 74 | // Next returns the result (and error) produced by the next line of 75 | // input. It returns ("", io.EOF) at EOF. The output is escaped. 76 | func (d *Demo) Next() (result string, err error) { 77 | if !d.scanner.Scan() { 78 | if err := d.scanner.Err(); err != nil { 79 | return "", err 80 | } 81 | return "", io.EOF 82 | } 83 | return Eval(d.scanner.Text()) 84 | } 85 | 86 | // Reset clears all state to the initial value. 87 | func Reset() { 88 | conf.SetFormat("") 89 | conf.SetMaxBits(1e9) 90 | conf.SetMaxDigits(1e4) 91 | conf.SetOrigin(1) 92 | conf.SetPrompt("") 93 | conf.SetBase(0, 0) 94 | conf.SetRandomSeed(0) 95 | conf.SetMobile(true) 96 | context = exec.NewContext(&conf) 97 | } 98 | 99 | // Help returns the help page formatted in HTML. 100 | func Help() string { 101 | return help 102 | } 103 | -------------------------------------------------------------------------------- /mobile/mobile_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package mobile 6 | 7 | import ( 8 | "io" 9 | "io/ioutil" 10 | "os" 11 | "os/exec" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | // We know ivy works. These just test that the wrapper works. 17 | 18 | func TestEval(t *testing.T) { 19 | var tests = []struct { 20 | input string 21 | output string 22 | }{ 23 | {"", ""}, 24 | {"23", "23\n"}, 25 | {"sqrt 2", "1.41421356237\n"}, 26 | {")format '%.2f'\nsqrt 2", "1.41\n"}, 27 | } 28 | for _, test := range tests { 29 | Reset() 30 | out, err := Eval(test.input) 31 | if err != nil { 32 | t.Errorf("evaluating %q: %v", test.input, err) 33 | continue 34 | } 35 | out = escaper.Replace(out) 36 | if out != test.output { 37 | t.Errorf("%q: expected %q; got %q", test.input, test.output, out) 38 | } 39 | } 40 | } 41 | 42 | func TestEvalError(t *testing.T) { 43 | var tests = []struct { 44 | input string 45 | error string 46 | }{ 47 | {"'x", "unterminated quoted string"}, 48 | {"1/0", "zero denominator in rational"}, 49 | {"1 / 0", "division by zero"}, 50 | } 51 | for _, test := range tests { 52 | Reset() 53 | _, err := Eval(test.input) 54 | if err == nil { 55 | t.Errorf("evaluating %q: expected %q; got nothing", test.input, test.error) 56 | continue 57 | } 58 | if !strings.Contains(err.Error(), test.error) { 59 | t.Errorf("%q: expected %q; got %q", test.input, test.error, err) 60 | } 61 | } 62 | } 63 | 64 | const demoText = `# This is a demo. 65 | 23 66 | iota 10 67 | 1/0 # Cause an error. 68 | iota 10 # Keep going 69 | ` 70 | 71 | var demoOut = escaper.Replace(`23 72 | 1 2 3 4 5 6 7 8 9 10 73 | 1 2 3 4 5 6 7 8 9 10 74 | `) 75 | 76 | const demoErr = " :1: zero denominator in rational\n" 77 | 78 | func TestDemo(t *testing.T) { 79 | demo := NewDemo(demoText) 80 | results := make([]byte, 0, 100) 81 | errors := make([]byte, 0, 100) 82 | for { 83 | result, err := demo.Next() 84 | if err == io.EOF { 85 | break 86 | } 87 | results = append(results, result...) 88 | if err != nil { 89 | errors = append(errors, err.Error()...) 90 | } 91 | } 92 | if demoOut != string(results) { 93 | t.Fatalf("expected %q; got %q", demoOut, results) 94 | } 95 | if demoErr != string(errors) { 96 | t.Fatalf("expected errors %q; got %q", demoErr, errors) 97 | } 98 | } 99 | 100 | func TestHelp(t *testing.T) { 101 | // Test to make sure the document is up to date. 102 | buf, err := exec.Command("go", "run", "help_gen.go").Output() 103 | if err != nil { 104 | t.Fatalf("failed to run 'go run help_gen.go': %v", err) 105 | } 106 | f, err := ioutil.TempFile("", "mobilehelp") 107 | if err != nil { 108 | t.Fatal(err) 109 | } 110 | defer os.Remove(f.Name()) 111 | 112 | _, err = f.Write(buf) 113 | errc := f.Close() 114 | if err != nil || errc != nil { 115 | t.Fatalf("failed to write the new help.go: %v", err) 116 | } 117 | 118 | data, err := exec.Command("diff", "-u", f.Name(), "help.go").CombinedOutput() 119 | if len(data) > 0 || err != nil { 120 | t.Errorf("Help message is outdated. Run go generate: %s (diff ended with %v)", data, err) 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /value/asinh.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "math/big" 9 | ) 10 | 11 | func asinh(c Context, v Value) Value { 12 | if u, ok := v.(Complex); ok { 13 | if !isZero(u.imag) { 14 | return complexAsinh(c, u) 15 | } 16 | v = u.real 17 | } 18 | return evalFloatFunc(c, v, floatAsinh) 19 | } 20 | 21 | func acosh(c Context, v Value) Value { 22 | if u, ok := v.(Complex); ok { 23 | if !isZero(u.imag) { 24 | return complexAcosh(c, u) 25 | } 26 | v = u.real 27 | } 28 | if compare(v, 1) < 0 { 29 | return complexAcosh(c, NewComplex(v, zero)) 30 | } 31 | return evalFloatFunc(c, v, floatAcosh) 32 | } 33 | 34 | func atanh(c Context, v Value) Value { 35 | if u, ok := v.(Complex); ok { 36 | if !isZero(u.imag) { 37 | return complexAtanh(c, u) 38 | } 39 | v = u.real 40 | } 41 | if compare(v, -1) <= 0 || 0 <= compare(v, 1) { 42 | return complexAtanh(c, NewComplex(v, zero)) 43 | } 44 | return evalFloatFunc(c, v, floatAtanh) 45 | } 46 | 47 | // floatAsinh computes asinh(x) using the formula asinh(x) = log(x + sqrt(x²+1)). 48 | // The domain is the real line. 49 | func floatAsinh(c Context, x *big.Float) *big.Float { 50 | z := newFloat(c).Set(x) 51 | z.Mul(z, x) 52 | z.Add(z, floatOne) 53 | z = floatSqrt(c, z) 54 | z.Add(z, x) 55 | return floatLog(c, z) 56 | } 57 | 58 | // floatAcosh computes acosh(x) using the formula asinh(x) = log(x + sqrt(x²-1)). 59 | // The domain is the real line >= 1. 60 | func floatAcosh(c Context, x *big.Float) *big.Float { 61 | if x.Cmp(floatOne) < 0 { 62 | Errorf("real acosh out of range [1, +∞ )") 63 | } 64 | z := newFloat(c).Set(x) 65 | z.Mul(z, x) 66 | z.Sub(z, floatOne) 67 | z = floatSqrt(c, z) 68 | z.Add(z, x) 69 | return floatLog(c, z) 70 | } 71 | 72 | // floatAtanh computes atanh(x) using the formula asinh(x) = ½log((1+x)/(1-x)) 73 | // The domain is the open interval (-1, 1). 74 | func floatAtanh(c Context, x *big.Float) *big.Float { 75 | if x.Cmp(floatMinusOne) <= 0 || 0 <= x.Cmp(floatOne) { 76 | Errorf("real atanh out of range (-1, 1)") 77 | } 78 | num := newFloat(c).Add(floatOne, x) 79 | den := newFloat(c).Sub(floatOne, x) 80 | z := floatLog(c, newFloat(c).Quo(num, den)) 81 | return z.Quo(z, floatTwo) 82 | } 83 | 84 | // complexAsinh computes asinh(x) using the formula asinh(x) = log(x + sqrt(x²+1)). 85 | func complexAsinh(c Context, x Complex) Complex { 86 | z := x.mul(c, x) 87 | z = z.add(c, NewComplex(one, zero)) 88 | z = complexSqrt(c, z) 89 | z = z.add(c, x) 90 | return complexLog(c, z) 91 | } 92 | 93 | // complexAcosh computes asinh(x) using the formula asinh(x) = log(x + sqrt(x²-1)). 94 | func complexAcosh(c Context, x Complex) Complex { 95 | z := x.mul(c, x) 96 | z = z.sub(c, NewComplex(one, zero)) 97 | z = complexSqrt(c, z) 98 | z = z.add(c, x) 99 | return complexLog(c, z) 100 | } 101 | 102 | // complexAtanh computes asinh(x) using the formula asinh(x) = ½log((1+x)/(1-x)) 103 | func complexAtanh(c Context, x Complex) Complex { 104 | num := complexOne.add(c, x) 105 | den := complexOne.sub(c, x) 106 | if isZero(num) || isZero(den) { 107 | Errorf("atanh is infinite") 108 | } 109 | z := num.div(c, den) 110 | return complexLog(c, z).mul(c, complexHalf) 111 | } 112 | -------------------------------------------------------------------------------- /value/char.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | "unicode/utf8" 11 | 12 | "robpike.io/ivy/config" 13 | ) 14 | 15 | type Char rune 16 | 17 | func (c Char) String() string { 18 | return "(" + string(c) + ")" 19 | } 20 | 21 | func (c Char) Rank() int { 22 | return 0 23 | } 24 | 25 | func (c Char) shrink() Value { 26 | return c 27 | } 28 | 29 | func (c Char) Sprint(conf *config.Config) string { 30 | // We ignore the format - chars are always textual. 31 | // TODO: What about escapes? 32 | return string(c) 33 | } 34 | 35 | func (c Char) ProgString() string { 36 | return fmt.Sprintf("%q", rune(c)) 37 | } 38 | 39 | func (c Char) Eval(Context) Value { 40 | return c 41 | } 42 | 43 | func (c Char) Inner() Value { 44 | return c 45 | } 46 | 47 | func (c Char) toType(op string, conf *config.Config, which valueType) Value { 48 | switch which { 49 | case charType: 50 | return c 51 | case vectorType: 52 | return oneElemVector(c) 53 | case matrixType: 54 | return NewMatrix([]int{1}, NewVector(c)) 55 | } 56 | Errorf("%s: cannot convert char to %s", op, which) 57 | return nil 58 | } 59 | 60 | func (c Char) validate() Char { 61 | if !utf8.ValidRune(rune(c)) { 62 | Errorf("invalid char value %U\n", c) 63 | } 64 | return c 65 | } 66 | 67 | // ParseString parses a string. Single quotes and 68 | // double quotes are both allowed (but must be consistent.) 69 | // The result must contain only valid Unicode code points. 70 | func ParseString(s string) string { 71 | str, ok := unquote(s) 72 | if !ok { 73 | Errorf("invalid string syntax") 74 | } 75 | if !utf8.ValidString(str) { 76 | Errorf("invalid code points in string") 77 | } 78 | return str 79 | } 80 | 81 | // unquote is a simplified strconv.Unquote that treats ' and " equally. 82 | // Raw quotes are Go-like and bounded by ``. 83 | // The return value is the string and a boolean rather than error, which 84 | // was almost always the same anyway. 85 | func unquote(s string) (t string, ok bool) { 86 | n := len(s) 87 | if n < 2 { 88 | return 89 | } 90 | quote := s[0] 91 | if quote != s[n-1] { 92 | return 93 | } 94 | s = s[1 : n-1] 95 | 96 | if quote == '`' { 97 | if contains(s, '`') { 98 | return 99 | } 100 | return s, true 101 | } 102 | if quote != '"' && quote != '\'' { 103 | return 104 | } 105 | if contains(s, '\n') { 106 | return 107 | } 108 | 109 | // Is it trivial? Avoid allocation. 110 | if !contains(s, '\\') && !contains(s, quote) { 111 | return s, true 112 | } 113 | 114 | var runeTmp [utf8.UTFMax]byte 115 | buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. 116 | for len(s) > 0 { 117 | c, multibyte, ss, err := strconv.UnquoteChar(s, quote) 118 | if err != nil { 119 | return 120 | } 121 | s = ss 122 | if c < utf8.RuneSelf || !multibyte { 123 | buf = append(buf, byte(c)) 124 | } else { 125 | n := utf8.EncodeRune(runeTmp[:], c) 126 | buf = append(buf, runeTmp[:n]...) 127 | } 128 | } 129 | return string(buf), true 130 | } 131 | 132 | // contains reports whether the string contains the byte c. 133 | func contains(s string, c byte) bool { 134 | for i := 0; i < len(s); i++ { 135 | if s[i] == c { 136 | return true 137 | } 138 | } 139 | return false 140 | } 141 | -------------------------------------------------------------------------------- /value/context.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "fmt" 9 | 10 | "robpike.io/ivy/config" 11 | ) 12 | 13 | // Decomposable allows one to pull apart a parsed expression. 14 | // Only implemented by Expr types that need to be decomposed 15 | // in function evaluation. 16 | type Decomposable interface { 17 | // Operator returns the operator, or "" for a singleton. 18 | Operator() string 19 | 20 | // Operands returns the left and right operands, or nil if absent. 21 | // For singletons, both will be nil, but ProgString can 22 | // give the underlying name or value. 23 | Operands() (left, right Expr) 24 | } 25 | 26 | // UnaryOp is the interface implemented by a simple unary operator. 27 | type UnaryOp interface { 28 | EvalUnary(c Context, right Value) Value 29 | } 30 | 31 | // BinaryOp is the interface implemented by a simple binary operator. 32 | type BinaryOp interface { 33 | EvalBinary(c Context, right, left Value) Value 34 | } 35 | 36 | // A Var is a named variable in an Ivy execution. 37 | type Var struct { 38 | name string 39 | value Value 40 | edit *vectorEditor 41 | } 42 | 43 | // Name returns v's name. 44 | func (v *Var) Name() string { 45 | return v.name 46 | } 47 | 48 | // Value returns v's current value. 49 | func (v *Var) Value() Value { 50 | if v.edit != nil { 51 | // Flush edits back into v.value. 52 | edit := v.edit 53 | v.edit = nil 54 | switch val := v.value.(type) { 55 | default: 56 | panic(fmt.Sprintf("internal error: misuse of transient for var %s of type %T", v.name, v.value)) 57 | case *Vector: 58 | v.value = edit.Publish() 59 | case *Matrix: 60 | v.value = &Matrix{shape: val.shape, data: edit.Publish()} 61 | } 62 | } 63 | return v.value 64 | } 65 | 66 | // Assign assigns value to v. 67 | func (v *Var) Assign(value Value) { 68 | v.value = value 69 | v.edit = nil 70 | } 71 | 72 | // editor returns a vectorEditor for editing v's underlying data 73 | // (supporting an indexed assignment like v[i] = x). 74 | func (v *Var) editor() *vectorEditor { 75 | if v.edit == nil { 76 | switch val := v.value.(type) { 77 | default: 78 | panic(fmt.Sprintf("internal error: misuse of transient for var %s of type %T", v.name, v.value)) 79 | case *Vector: 80 | v.edit = val.edit() 81 | case *Matrix: 82 | v.edit = val.data.edit() 83 | } 84 | } 85 | return v.edit 86 | } 87 | 88 | // NewVar returns a new Var with the given name and value. 89 | func NewVar(name string, value Value) *Var { 90 | return &Var{name: name, value: value} 91 | } 92 | 93 | // Context is the execution context for evaluation. 94 | // The only implementation is ../exec/Context, but the interface 95 | // is defined separately, here, because of the dependence on Expr 96 | // and the import cycle that would otherwise result. 97 | type Context interface { 98 | // Config returns the configuration state for evaluation. 99 | Config() *config.Config 100 | 101 | // Local returns the i'th local variable. 102 | Local(i int) *Var 103 | 104 | // Global returns the named global variable. 105 | // It returns nil if there is no such variable. 106 | Global(name string) *Var 107 | 108 | // AssignGlobal assigns to the named global variable, 109 | // creating it if needed. 110 | AssignGlobal(name string, value Value) 111 | 112 | // Eval evaluates a list of expressions. 113 | Eval(exprs []Expr) []Value 114 | 115 | // EvalUnary evaluates a unary operator. 116 | EvalUnary(op string, right Value) Value 117 | 118 | // EvalBinary evaluates a binary operator. 119 | EvalBinary(left Value, op string, right Value) Value 120 | 121 | // UserDefined reports whether the specified op is user-defined. 122 | UserDefined(op string, isBinary bool) bool 123 | 124 | // TraceIndent returns an indentation marker showing the depth of the stack. 125 | TraceIndent() string 126 | } 127 | -------------------------------------------------------------------------------- /testdata/save.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Saving. 6 | 7 | # Initial configuration. 8 | )save "" 9 | )prec 256 10 | )maxbits 1000000000 11 | )maxdigits 10000 12 | )origin 1 13 | )prompt "" 14 | )format "" 15 | # Set base 10 for parsing numbers. 16 | )base 10 17 | e = 2.71828182845904523536028747135266249775724709369995957496696762772407663035355 18 | pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862 19 | )ibase 0 20 | )obase 0 21 | 22 | # Variables. 23 | x00 = 3 24 | x01 = 1/3 25 | x02 = sqrt 3 26 | x04 = iota 5 27 | x05 = 3 4 rho iota 12 28 | x06 = 'x' 29 | x07 = 'abc' 30 | x08 = 1 'x' 2 31 | x09 = 1j2 32 | x10 = 1 (2 3) (4 5) 33 | x11 = 3 4 rho iota 12 34 | x11[2;2] = 2 2 rho 6 35 | )save "" 36 | )prec 256 37 | )maxbits 1000000000 38 | )maxdigits 10000 39 | )origin 1 40 | )prompt "" 41 | )format "" 42 | # Set base 10 for parsing numbers. 43 | )base 10 44 | e = 2.71828182845904523536028747135266249775724709369995957496696762772407663035355 45 | pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862 46 | x00 = 3 47 | x01 = 1/3 48 | x02 = 1.7320508075688772935274463415058723669428052538103806280558069794519330169088 49 | x04 = 1 2 3 4 5 50 | x05 = 3 4 rho 1 2 3 4 5 6 7 8 9 10 11 12 51 | x06 = 'x' 52 | x07 = "abc" 53 | x08 = 1 'x' 2 54 | x09 = 1j2 55 | x10 = 1 (2 3) (4 5) 56 | x11 = 3 4 rho 1 2 3 4 5 (2 2 rho 6 6 6 6) 7 8 9 10 11 12 57 | )ibase 0 58 | )obase 0 59 | 60 | # Simple definitions. 61 | op avg x = (+/x) / rho x 62 | op roll x = x?100 63 | )save "" 64 | )prec 256 65 | )maxbits 1000000000 66 | )maxdigits 10000 67 | )origin 1 68 | )prompt "" 69 | )format "" 70 | op avg x = (+/ x) / rho x 71 | op roll x = x ? 100 72 | # Set base 10 for parsing numbers. 73 | )base 10 74 | e = 2.71828182845904523536028747135266249775724709369995957496696762772407663035355 75 | pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862 76 | )ibase 0 77 | )obase 0 78 | 79 | # Mutual recursion. 80 | op m1 n 81 | op m2 n = iota m1 n 82 | op m1 n = n 83 | )save "" 84 | )prec 256 85 | )maxbits 1000000000 86 | )maxdigits 10000 87 | )origin 1 88 | )prompt "" 89 | )format "" 90 | op m1 _ 91 | op m2 n = iota m1 n 92 | op m1 n = n 93 | # Set base 10 for parsing numbers. 94 | )base 10 95 | e = 2.71828182845904523536028747135266249775724709369995957496696762772407663035355 96 | pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862 97 | )ibase 0 98 | )obase 0 99 | 100 | # Test that we can see variables and ops created by reading from a file. 101 | )get "testdata/saved" 102 | x 103 | avg x 104 | 1 2 3 4 5 6 7 105 | 4 106 | 107 | # Indexing operations 108 | op g x = x 109 | op f x = x[1 2; g 3 4; 5 6] 110 | )save "" 111 | )prec 256 112 | )maxbits 1000000000 113 | )maxdigits 10000 114 | )origin 1 115 | )prompt "" 116 | )format "" 117 | op g x = x 118 | op f x = x[1 2; g 3 4; 5 6] 119 | # Set base 10 for parsing numbers. 120 | )base 10 121 | e = 2.71828182845904523536028747135266249775724709369995957496696762772407663035355 122 | pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862 123 | )ibase 0 124 | )obase 0 125 | 126 | # Multiline function definitions. 127 | op f x = 128 | x==1: 2 129 | x 130 | 131 | op g x = x 132 | )save "" 133 | )prec 256 134 | )maxbits 1000000000 135 | )maxdigits 10000 136 | )origin 1 137 | )prompt "" 138 | )format "" 139 | op f x = 140 | (x == 1) : 2 141 | x 142 | 143 | op g x = x 144 | # Set base 10 for parsing numbers. 145 | )base 10 146 | e = 2.71828182845904523536028747135266249775724709369995957496696762772407663035355 147 | pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862 148 | )ibase 0 149 | )obase 0 150 | -------------------------------------------------------------------------------- /quorem_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Verify that quoRem satisfies the identity 6 | // quo = x div y such that 7 | // rem = x - y*quo with 0 <= rem < |y| 8 | // See doc for math/big.Int.DivMod. 9 | 10 | package main 11 | 12 | import ( 13 | "math/big" 14 | "testing" 15 | 16 | "robpike.io/ivy/exec" 17 | "robpike.io/ivy/value" 18 | ) 19 | 20 | type pair struct { 21 | x, y int 22 | } 23 | 24 | var quoRemTests = []pair{ 25 | // We run all the tests with all four signs for 5, 3. 26 | // The correct results are: 27 | // 5,3 -> quo 1 rem 2 28 | // -5,3 -> quo -2 rem 1 29 | // 5,-3 -> quo -1 rem 2 30 | // -5,-3 -> quo 2 rem 1 31 | {5, 3}, 32 | {-5, 3}, 33 | {5, -3}, 34 | {-5, -3}, 35 | // Now check that they work with remainder 0. 36 | // 5,5 -> quo 1 rem 0 37 | // -5,5 -> quo -2 rem 0 38 | // 5,-5 -> quo -1 rem 0 39 | // -5,-5 -> quo 2 rem 0 40 | {5, 5}, 41 | {-5, 5}, 42 | {5, -5}, 43 | {-5, -5}, 44 | } 45 | 46 | func TestQuoRem(t *testing.T) { 47 | c := exec.NewContext(&testConf) 48 | for _, test := range quoRemTests { 49 | verifyQuoRemInt(t, c, test.x, test.y) 50 | verifyQuoRemBigInt(t, c, test.x, test.y) 51 | verifyQuoRemBigRat(t, c, test.x, test.y) 52 | verifyQuoRemBigFloat(t, c, test.x, test.y) 53 | } 54 | } 55 | 56 | func verifyQuoRemInt(t *testing.T, c value.Context, x, y int) { 57 | t.Helper() 58 | quoV, remV := value.QuoRem("test", c, value.Int(x), value.Int(y)) 59 | quo := int(quoV.(value.Int)) 60 | rem := int(remV.(value.Int)) 61 | absY := y 62 | if y < 0 { 63 | absY = -y 64 | } 65 | if rem < 0 || absY <= rem { 66 | t.Errorf("Int %d QuoRem %d = %d,%d (remainder out of range)", x, y, quo, rem) 67 | } 68 | expect := x - y*quo 69 | if rem != expect { 70 | t.Errorf("Int %d QuoRem %d = %d,%d yielding %d", x, y, quo, rem, expect) 71 | } 72 | } 73 | 74 | func bigInt(x int64) value.Value { 75 | return value.BigInt{Int: big.NewInt(x)} 76 | } 77 | 78 | func bigRat(x, y int64) value.Value { 79 | return value.BigRat{Rat: big.NewRat(x, y)} 80 | } 81 | 82 | func bigFloat(x float64) value.Value { 83 | return value.BigFloat{Float: big.NewFloat(x)} 84 | } 85 | 86 | func verifyQuoRemBigInt(t *testing.T, c value.Context, X, Y int) { 87 | t.Helper() 88 | x, y := int64(X), int64(Y) 89 | quoV, remV := value.QuoRem("test", c, bigInt(x), bigInt(y)) 90 | // For our tests, we get ints back. 91 | quo := int64(quoV.(value.Int)) 92 | rem := int64(remV.(value.Int)) 93 | absY := y 94 | if y < 0 { 95 | absY = -y 96 | } 97 | if rem < 0 || absY <= rem { 98 | t.Errorf("BigInt %d QuoRem %d = %d,%d (remainder out of range)", x, y, quo, rem) 99 | } 100 | expect := x - y*quo 101 | if rem != expect { 102 | t.Errorf("BigInt %d QuoRem %d = %d,%d yielding %d", x, y, quo, rem, expect) 103 | } 104 | } 105 | 106 | func verifyQuoRemBigRat(t *testing.T, c value.Context, X, Y int) { 107 | t.Helper() 108 | x, y := int64(X), int64(Y) 109 | quoV, remV := value.QuoRem("test", c, bigRat(x, 1), bigRat(y, 1)) 110 | // For our tests, we get ints back. 111 | quo := int64(quoV.(value.Int)) 112 | rem := int64(remV.(value.Int)) 113 | absY := y 114 | if y < 0 { 115 | absY = -y 116 | } 117 | if rem < 0 || absY <= rem { 118 | t.Errorf("BigRat %d QuoRem %d = %d,%d (remainder out of range)", x, y, quo, rem) 119 | } 120 | expect := x - y*quo 121 | if rem != expect { 122 | t.Errorf("BigRat %d QuoRem %d = %d,%d yielding %d", x, y, quo, rem, expect) 123 | } 124 | } 125 | 126 | func verifyQuoRemBigFloat(t *testing.T, c value.Context, X, Y int) { 127 | t.Helper() 128 | x, y := float64(X), float64(Y) 129 | quoV, remV := value.QuoRem("test", c, bigFloat(x), bigFloat(y)) 130 | // For our tests, we get ints back. 131 | quo := float64(quoV.(value.Int)) 132 | rem := float64(remV.(value.Int)) 133 | absY := y 134 | if y < 0 { 135 | absY = -y 136 | } 137 | if rem < 0 || absY <= rem { 138 | t.Errorf("BigFloat %g QuoRem %g = %g,%g (remainder out of range)", x, y, quo, rem) 139 | } 140 | expect := x - y*quo 141 | if rem != expect { 142 | t.Errorf("BigFloat %g QuoRem %g = %g,%g yielding %g", x, y, quo, rem, expect) 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /testdata/char.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Textual data. 6 | 7 | # Textual literals. 8 | 9 | 'x' 10 | x 11 | 12 | 'xyz' 13 | xyz 14 | 15 | "x" 16 | x 17 | 18 | "xyz" 19 | xyz 20 | 21 | `x` 22 | x 23 | 24 | `xyz` 25 | xyz 26 | 27 | '\'\x62\u1234\U00001234\\\'' 28 | 'bሴሴ\' 29 | 30 | "\"\x62\u1234\U00001234\\\"" 31 | "bሴሴ\" 32 | 33 | `a 34 | b 35 | c` 36 | a 37 | b 38 | c 39 | 40 | '' 41 | # 42 | 43 | "" 44 | # 45 | 46 | `` 47 | # 48 | 49 | # Comparison. 50 | 51 | '123456789' == '5' 52 | 0 0 0 0 1 0 0 0 0 53 | 54 | '123456789' != '5' 55 | 1 1 1 1 0 1 1 1 1 56 | 57 | '123456789' < '5' 58 | 1 1 1 1 0 0 0 0 0 59 | 60 | '123456789' <= '5' 61 | 1 1 1 1 1 0 0 0 0 62 | 63 | '123456789' > '5' 64 | 0 0 0 0 0 1 1 1 1 65 | 66 | '123456789' >= '5' 67 | 0 0 0 0 1 1 1 1 1 68 | 69 | '\x00\x01' or '\x00' 70 | 0 1 71 | 72 | '\x00\x01' or '\x01' 73 | 1 1 74 | 75 | '\x00\x01' and '\x00' 76 | 0 0 77 | 78 | '\x00\x01' and '\x01' 79 | 0 1 80 | 81 | '\x00\x01' nor '\x00' 82 | 1 0 83 | 84 | '\x00\x01' nor '\x01' 85 | 0 0 86 | 87 | '\x00\x01' nand '\x00' 88 | 1 1 89 | 90 | '\x00\x01' nand '\x01' 91 | 1 0 92 | 93 | '\x00\x01' xor '\x00' 94 | 0 1 95 | 96 | '\x00\x01' xor '\x01' 97 | 1 0 98 | 99 | # Min and max. 100 | 101 | 'abcd' min 'c' 102 | abcc 103 | 104 | 'abcd' max 'c' 105 | cccd 106 | 107 | # Vector and matrix ops. 108 | 109 | 10 rho 'a' 110 | aaaaaaaaaa 111 | 112 | 10 rho 'a' 'cd' 113 | a cd a cd a cd a cd a cd 114 | 115 | 10 rho 'ab' 'cd' 116 | ab cd ab cd ab cd ab cd ab cd 117 | 118 | 10 rho 'a' 'b' 119 | ababababab 120 | 121 | 10 rho 'ab' 122 | ababababab 123 | 124 | 3 4 rho 'a' 125 | aaaa 126 | aaaa 127 | aaaa 128 | 129 | 3 4 rho 'abc' 130 | abca 131 | bcab 132 | cabc 133 | 134 | 2 3 4 rho 'abcdefghijklmnopqrstuvwx' 135 | abcd 136 | efgh 137 | ijkl 138 | 139 | mnop 140 | qrst 141 | uvwx 142 | 143 | 'abc' , 'def' 144 | abcdef 145 | 146 | 'abc' 'def' 147 | abc def 148 | 149 | 3 4 rho 'a' 'bc' 150 | a bc a bc 151 | a bc a bc 152 | a bc a bc 153 | 154 | 3 4 rho 'ab' 'cd' 155 | ab cd ab cd 156 | ab cd ab cd 157 | ab cd ab cd 158 | 159 | rho '' 160 | 0 161 | 162 | rho rho 'a' 163 | 0 164 | 165 | rho 'abc' 166 | 3 167 | 168 | # Sorting and indexing. 169 | 170 | x = 'now is the time' 171 | x[up x] 172 | eehiimnosttw 173 | 174 | 175 | x = 'now is the time' 176 | x[down x] 177 | wttsonmiihee 178 | 179 | x = 'now is the time' 180 | 'e' iota x 181 | 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 182 | 183 | 3 take 'abcdef' 184 | abc 185 | 186 | 3 drop 'abcdef' 187 | def 188 | 189 | rot 'abcdef' 190 | fedcba 191 | 192 | # Unicode, or conversion between int and char. 193 | 194 | code 'a' 195 | 97 196 | 197 | char 97 198 | a 199 | 200 | )obase 16 201 | code 'ሴ' 202 | 1234 203 | 204 | char 0x1234 205 | ሴ 206 | 207 | code 'abc' 208 | 97 98 99 209 | 210 | char 97 98 99 211 | abc 212 | 213 | # Text 214 | 215 | text iota 10 216 | 1 2 3 4 5 6 7 8 9 10 217 | 218 | x=text iota 10; x[up x] 219 | 01123456789 220 | 221 | x=text iota 10; x[down x] 222 | 98765432110 223 | 224 | 6 text 1 2 3 225 | 1.000000 2.000000 3.000000 226 | 227 | 6 2 text sqrt 2 228 | 1.41 229 | 230 | 10 4 'e' text sqrt 2 231 | 1.4142e+00 232 | 233 | ".2f," text iota 3 234 | 1.00, 2.00, 3.00, 235 | 236 | 6 text sqrt iota 20 237 | 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427 3.000000 3.162278 3.316625 3.464102 3.605551 3.741657 3.872983 4.000000 4.123106 4.242641 4.358899 4.472136 238 | 239 | 5 0 text 2 3 4 rho iota 24 240 | 1 2 3 4 241 | 5 6 7 8 242 | 9 10 11 12 243 | 244 | 13 14 15 16 245 | 17 18 19 20 246 | 21 22 23 24 247 | 248 | )prec 1000 249 | 100 text 1/3 250 | )prec 256 251 | 0.3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 252 | 253 | # Issue 118 254 | "12301230" iota "1"; "12301230" iota "2"; "12301230" iota "3"; "12301230" iota "0" 255 | 1 2 3 4 256 | 257 | # Fill with spaces. 258 | -10 take 'abc' 259 | abc 260 | 261 | x=10 take 'abc'; x,'!' 262 | abc ! 263 | -------------------------------------------------------------------------------- /testdata/unary_vector.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Unary operations on vectors. 6 | 7 | 23 45 56 8 | 23 45 56 9 | 10 | 1/3 2/3 3/4 11 | 1/3 2/3 3/4 12 | 13 | 1e10 1.5 14 | 10000000000 3/2 15 | 16 | 1 (2 3) (4 5 6) 17 | 1 (2 3) (4 5 6) 18 | 19 | # A vector with expressions 20 | x = 4 21 | 1 x (x**2) (-x) 22 | 1 4 16 -4 23 | 24 | x = 4 25 | (1 x (x**2) (-x))[3] 26 | 16 27 | 28 | (3) 4 5 29 | 3 4 5 30 | 31 | )seed 0 32 | ?10 10 10 33 | 7 5 2 34 | 35 | + 23 45 56 36 | 23 45 56 37 | 38 | +-23 -45 -56 39 | -23 -45 -56 40 | 41 | + -23 -45 -56 42 | -23 -45 -56 43 | 44 | - 23 45 56 45 | -23 -45 -56 46 | 47 | --23 45 56 48 | 23 -45 -56 49 | 50 | - -23 -45 -56 51 | 23 45 56 52 | 53 | /23 45 56 54 | 1/23 1/45 1/56 55 | 56 | /-23 45 56 57 | -1/23 1/45 1/56 58 | 59 | sgn -1/3 0 3 1e10 60 | -1 0 1 1 61 | 62 | inv 1 2 3 63 | 1/14 1/7 3/14 64 | 65 | inv 1j1 2j2 3j3 66 | 1/28j-1/28 1/14j-1/14 3/28j-3/28 67 | 68 | inv inv 1 2 3 69 | 1 2 3 70 | 71 | inv inv 1j1 2j2 3j3 72 | 1j1 2j2 3j3 73 | 74 | not 0 1 2 3 75 | 1 0 0 0 76 | 77 | abs -75/23 3 4 78 | 75/23 3 4 79 | 80 | floor -75/23 3.1 4.2 81 | -4 3 4 82 | 83 | ceil -75/23 3.1 4.2 84 | -3 4 5 85 | 86 | iota 3 4 87 | (1 1) (1 2) (1 3) (1 4) 88 | (2 1) (2 2) (2 3) (2 4) 89 | (3 1) (3 2) (3 3) (3 4) 90 | 91 | )origin 0 92 | iota 3 4 93 | (0 0) (0 1) (0 2) (0 3) 94 | (1 0) (1 1) (1 2) (1 3) 95 | (2 0) (2 1) (2 2) (2 3) 96 | 97 | rho 75/23 17 28 98 | 3 99 | 100 | ,3 4 5 101 | 3 4 5 102 | 103 | up 6 5 8 10 4 1 2 5 4 7 104 | 6 7 5 9 2 8 1 10 3 4 105 | 106 | down 6 5 8 10 4 1 2 5 4 7 107 | 4 3 10 1 8 2 9 5 7 6 108 | 109 | rot iota 0 110 | # 111 | 112 | rot iota 1 113 | 1 114 | 115 | rot iota 10 116 | 10 9 8 7 6 5 4 3 2 1 117 | 118 | # rot doesn't overwrite its argument. Issue #24 119 | x=iota 10 120 | y = rot x 121 | x 122 | 1 2 3 4 5 6 7 8 9 10 123 | 124 | flip iota 0 125 | # 126 | 127 | flip iota 1 128 | 1 129 | 130 | flip iota 10 131 | 10 9 8 7 6 5 4 3 2 1 132 | 133 | unique iota 5 134 | 1 2 3 4 5 135 | 136 | unique 1 1 2 2 137 | 1 2 138 | 139 | unique 'mississippi' 140 | misp 141 | 142 | unique 1 (2 3) (4 5) (2 3) 4 143 | 1 (2 3) (4 5) 4 144 | 145 | # Choose the "lowest" type of same value 146 | unique 1j0 1 1/1 (float 1) 2/1 2j0 2 (float 2) 147 | 1 2 148 | 149 | unique 1 'a' 2 'b' 3 'a' 2 150 | 1 a 2 b 3 151 | 152 | unique iota 0 153 | # 154 | 155 | flatten 7 156 | 7 157 | 158 | flatten 3 4 159 | 3 4 160 | 161 | flatten ,\1 2 3 4 162 | 1 1 2 1 2 3 1 2 3 4 163 | 164 | # Fixed bug: don't use user-defined functions in core calculations. 165 | op rot x = 99 166 | flip 1 2 3 # Used rot internally. 167 | 3 2 1 168 | 169 | box 1 2 3 170 | (1 2 3) 171 | 172 | box iota 0 173 | () 174 | 175 | first 1 2 3 176 | 1 177 | 178 | first (1 2 3) (4 5 6) 179 | 1 2 3 180 | 181 | first iota 0 182 | 0 183 | 184 | mix 1 2 3 185 | 1 2 3 186 | 187 | mix (1 2) (3 4) 188 | 1 2 189 | 3 4 190 | 191 | mix 'ab' 'cd' 192 | ab 193 | cd 194 | 195 | mix 'ab' (2 3) 196 | a b 197 | 2 3 198 | 199 | mix 9 (3 4 rho iota 10) 200 | ┌ ┐ 201 | │ 9 0 0 0│ 202 | │ 0 0 0 0│ 203 | │ 0 0 0 0│ 204 | └ ┘ 205 | ┌ ┐ 206 | │ 1 2 3 4│ 207 | │ 5 6 7 8│ 208 | │ 9 10 1 2│ 209 | └ ┘ 210 | 211 | mix 9 (3 4 rho iota 10) (2 2 rho 9 8 7 6) # Matrices of different sizes. 212 | ┌ ┐ 213 | │ 9 0 0 0│ 214 | │ 0 0 0 0│ 215 | │ 0 0 0 0│ 216 | └ ┘ 217 | ┌ ┐ 218 | │ 1 2 3 4│ 219 | │ 5 6 7 8│ 220 | │ 9 10 1 2│ 221 | └ ┘ 222 | ┌ ┐ 223 | │ 9 8 0 0│ 224 | │ 7 6 0 0│ 225 | │ 0 0 0 0│ 226 | └ ┘ 227 | 228 | mix (2 5 rho iota 10) (3 4 rho iota 12) # Fills out to maximum on each axis. 229 | ┌ ┐ 230 | │ 1 2 3 4 5│ 231 | │ 6 7 8 9 10│ 232 | │ 0 0 0 0 0│ 233 | └ ┘ 234 | ┌ ┐ 235 | │ 1 2 3 4 0│ 236 | │ 5 6 7 8 0│ 237 | │ 9 10 11 12 0│ 238 | └ ┘ 239 | 240 | # If there is no fill, mix and split are inverses. 241 | split mix (1 2) (3 4) 242 | (1 2) (3 4) 243 | 244 | mix split 2 2 rho iota 4 245 | 1 2 246 | 3 4 247 | 248 | up mix 'ab' 'ac' 'aa' 249 | 3 1 2 250 | 251 | where 0==2 mod iota 6 252 | 1 2 253 | 254 | x[where not (x=3*iota 10) mod 5] 255 | 15 30 256 | -------------------------------------------------------------------------------- /value/value.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value // import "robpike.io/ivy/value" 6 | 7 | import ( 8 | "fmt" 9 | "math/big" 10 | "strings" 11 | 12 | "robpike.io/ivy/config" 13 | ) 14 | 15 | var debugConf = &config.Config{} // For debugging, e.g. to call a String method. 16 | 17 | type Value interface { 18 | // String is for internal debugging only. It uses default configuration 19 | // and puts parentheses around every value so it's clear when it is used. 20 | // All user output should call Sprint instead. 21 | String() string 22 | Sprint(*config.Config) string 23 | 24 | // Eval evaluates (simplifies) the Value. 25 | Eval(Context) Value 26 | 27 | // Inner retrieves the value, without evaluation. But for Assignments, 28 | // it returns the right-hand side. 29 | Inner() Value 30 | 31 | // Rank returns the rank of the value: 0 for scalar, 1 for vector, etc. 32 | Rank() int 33 | 34 | // shrink returns a simpler form of the value, such as an 35 | // integer for an integral BigFloat. For some types it is 36 | // the identity. It does not modify the receiver. 37 | shrink() Value 38 | 39 | // ProgString is like String, but suitable for program listing. 40 | // For instance, it ignores the user format for numbers and 41 | // puts quotes on chars, guaranteeing a correct representation. 42 | ProgString() string 43 | 44 | toType(string, *config.Config, valueType) Value 45 | } 46 | 47 | // Error is the type we recognize as a recoverable run-time error. 48 | type Error string 49 | 50 | func (err Error) Error() string { 51 | return string(err) 52 | } 53 | 54 | // Errorf panics with the formatted string, with type Error. 55 | func Errorf(format string, args ...interface{}) { 56 | panic(Error(fmt.Sprintf(format, args...))) 57 | } 58 | 59 | func parseTwo(conf *config.Config, s string) (Value, Value, string, error) { 60 | var elems []string 61 | var sep string 62 | var typ string 63 | if strings.ContainsRune(s, 'j') { 64 | sep = "j" 65 | typ = "complex" 66 | } else if strings.ContainsRune(s, '/') { 67 | sep = "/" 68 | typ = "rational" 69 | } else { 70 | return zero, zero, "", nil 71 | } 72 | elems = strings.Split(s, sep) 73 | if len(elems) != 2 || elems[0] == "" || elems[1] == "" { 74 | Errorf("bad %s number syntax: %q", typ, s) 75 | } 76 | v1, err := Parse(conf, elems[0]) 77 | if err != nil { 78 | return nil, nil, "", err 79 | } 80 | v2, err := Parse(conf, elems[1]) 81 | if err != nil { 82 | return nil, nil, "", err 83 | } 84 | return v1, v2, sep, err 85 | } 86 | 87 | func Parse(conf *config.Config, s string) (Value, error) { 88 | // Is it a complex or rational? 89 | v1, v2, sep, err := parseTwo(conf, s) 90 | if err != nil { 91 | return nil, err 92 | } 93 | switch sep { 94 | case "j": 95 | // A complex. 96 | return NewComplex(v1, v2).shrink(), nil 97 | case "/": 98 | // A rational. It's tricky. 99 | // Common simple case. 100 | if whichType(v1) == intType && whichType(v2) == intType { 101 | return bigRatTwoInt64s(int64(v1.(Int)), int64(v2.(Int))).shrink(), nil 102 | } 103 | // General mix-em-up. 104 | rden := v2.toType("rat", conf, bigRatType) 105 | if rden.(BigRat).Sign() == 0 { 106 | Errorf("zero denominator in rational") 107 | } 108 | return binaryBigRatOp(v1.toType("rat", conf, bigRatType), (*big.Rat).Quo, rden), nil 109 | } 110 | // Not a rational, but might be something like 1.3e-2 and therefore 111 | // become a rational. 112 | i, err := setIntString(conf, s) 113 | if err == nil { 114 | return i, nil 115 | } 116 | b, err := setBigIntString(conf, s) 117 | if err == nil { 118 | return b.shrink(), nil 119 | } 120 | r, err := setBigRatFromFloatString(s) // We know there is no slash. 121 | if err == nil { 122 | return r.shrink(), nil 123 | } 124 | return nil, err 125 | } 126 | 127 | func bigInt64(x int64) BigInt { 128 | return BigInt{big.NewInt(x)} 129 | } 130 | 131 | func bigRatInt64(x int64) BigRat { 132 | return bigRatTwoInt64s(x, 1) 133 | } 134 | 135 | func bigFloatInt64(conf *config.Config, x int64) BigFloat { 136 | return BigFloat{new(big.Float).SetPrec(conf.FloatPrec()).SetInt64(x)} 137 | } 138 | 139 | func bigRatTwoInt64s(x, y int64) BigRat { 140 | if y == 0 { 141 | Errorf("zero denominator in rational") 142 | } 143 | return BigRat{big.NewRat(x, y)} 144 | } 145 | -------------------------------------------------------------------------------- /value/int.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "fmt" 9 | "math/big" 10 | "strconv" 11 | 12 | "robpike.io/ivy/config" 13 | ) 14 | 15 | // Int is not only the simplest representation, it provides the operands that mix 16 | // types upward. That is, BigInt.Add(Int) will be done by rewriting as Int.Add(BigInt). 17 | 18 | type Int int64 19 | 20 | const ( 21 | // We use an int32 size, so multiplications will fit in int64 22 | // and can be scaled afterwards. 23 | intBits = 32 24 | minInt = -(1 << (intBits - 1)) 25 | maxInt = 1<<(intBits-1) - 1 26 | ) 27 | 28 | func setIntString(conf *config.Config, s string) (Int, error) { 29 | i, err := strconv.ParseInt(s, conf.InputBase(), intBits) 30 | return Int(i), err 31 | } 32 | 33 | func (i Int) String() string { 34 | return "(" + i.Sprint(debugConf) + ")" 35 | } 36 | 37 | func (i Int) Sprint(conf *config.Config) string { 38 | format := conf.Format() 39 | if format != "" { 40 | verb, prec, ok := conf.FloatFormat() 41 | if ok { 42 | return i.floatString(verb, prec) 43 | } 44 | return fmt.Sprintf(format, int64(i)) 45 | } 46 | base := conf.OutputBase() 47 | if base == 0 { 48 | base = 10 49 | } 50 | return strconv.FormatInt(int64(i), base) 51 | } 52 | 53 | func (i Int) ProgString() string { 54 | return strconv.FormatInt(int64(i), 10) 55 | } 56 | 57 | func (i Int) Rank() int { 58 | return 0 59 | } 60 | 61 | func (i Int) shrink() Value { 62 | return i 63 | } 64 | 65 | func (i Int) floatString(verb byte, prec int) string { 66 | switch verb { 67 | case 'f', 'F': 68 | str := strconv.FormatInt(int64(i), 10) 69 | if prec > 0 { 70 | str += "." + zeros(prec) 71 | } 72 | return str 73 | case 'e', 'E': 74 | sign := "" 75 | if i < 0 { 76 | sign = "-" 77 | i = -i 78 | } 79 | return eFormat(verb, prec, sign, strconv.FormatInt(int64(i), 10), i.eExponent()) 80 | case 'g', 'G': 81 | // Exponent is always positive so it's easy. 82 | if i.eExponent() >= prec { 83 | // Use e format. 84 | return i.floatString(verb-2, prec-1) 85 | } 86 | // Use f format, but this is just an integer. 87 | return fmt.Sprintf("%d", int64(i)) 88 | default: 89 | Errorf("can't handle verb %c for int", verb) 90 | } 91 | return "" 92 | } 93 | 94 | // eExponent returns the exponent to use to display i in 1.23e+04 format. 95 | func (i Int) eExponent() int { 96 | if i < 0 { 97 | i = -i 98 | } 99 | // The exponent will always be >= 0. 100 | exp := 0 101 | x := i 102 | for x >= 10 { 103 | exp++ 104 | x /= 10 105 | } 106 | return exp 107 | } 108 | 109 | // inverse returns 1/i 110 | func (i Int) inverse() Value { 111 | v := int64(i) 112 | if i == 0 { 113 | Errorf("inverse of zero") 114 | } 115 | return BigRat{ 116 | Rat: big.NewRat(0, 1).SetFrac64(1, v), 117 | }.shrink() 118 | } 119 | 120 | // eFormat returns the %e/%E form of the number represented by the 121 | // string str, which is a decimal integer, scaled by 10**exp. 122 | func eFormat(verb byte, prec int, sign, str string, exp int) string { 123 | if len(str)-1 < prec { 124 | // Zero pad. 125 | str += zeros(prec - len(str) + 1) 126 | } else { 127 | // Truncate. 128 | // TODO: rounding 129 | str = str[:1+prec] 130 | } 131 | period := "." 132 | if prec == 0 { 133 | period = "" 134 | } 135 | return fmt.Sprintf("%s%s%s%s%c%+.2d", sign, str[0:1], period, str[1:], verb, exp) 136 | } 137 | 138 | var manyZeros = "0000000000" 139 | 140 | func zeros(prec int) string { 141 | for len(manyZeros) < prec { 142 | manyZeros += manyZeros 143 | } 144 | return manyZeros[:prec] 145 | } 146 | 147 | func (i Int) Eval(Context) Value { 148 | return i 149 | } 150 | 151 | func (i Int) Inner() Value { 152 | return i 153 | } 154 | 155 | func (i Int) toType(op string, conf *config.Config, which valueType) Value { 156 | switch which { 157 | case intType: 158 | return i 159 | case bigIntType: 160 | return bigInt64(int64(i)) 161 | case bigRatType: 162 | return bigRatInt64(int64(i)) 163 | case bigFloatType: 164 | return bigFloatInt64(conf, int64(i)) 165 | case complexType: 166 | return NewComplex(i, zero) 167 | case vectorType: 168 | return oneElemVector(i) 169 | case matrixType: 170 | return NewMatrix([]int{1}, NewVector(i)) 171 | } 172 | Errorf("%s: cannot convert int to %s", op, which) 173 | return nil 174 | } 175 | 176 | func (i Int) ToBool() bool { 177 | return i != 0 178 | } 179 | 180 | func (i Int) maybeBig() Value { 181 | if minInt <= i && i <= maxInt { 182 | return i 183 | } 184 | return bigInt64(int64(i)) 185 | } 186 | -------------------------------------------------------------------------------- /value/log.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "math/big" 9 | ) 10 | 11 | func logn(c Context, v Value) Value { 12 | negative := isNegative(v) 13 | if negative { 14 | // Promote to complex. The Complex type is never negative. 15 | v = NewComplex(v, zero) 16 | } 17 | if u, ok := v.(Complex); ok { 18 | if isNegative(u.real) { 19 | negative = true 20 | } 21 | if !isZero(u.imag) || negative { 22 | return complexLog(c, u).shrink() 23 | } 24 | v = u.real 25 | } 26 | return evalFloatFunc(c, v, floatLog) 27 | } 28 | 29 | func logBaseU(c Context, u, v Value) Value { 30 | // Handle the integer part exactly when the arguments are exact. 31 | switch u := u.(type) { 32 | case Int: 33 | log, exact := intLog(u, v.(Int)) 34 | if exact { 35 | return Int(log) 36 | } 37 | case BigInt: 38 | log, exact := bigIntLog(u, v.(BigInt)) 39 | if exact { 40 | return log 41 | } 42 | } 43 | return c.EvalBinary(logn(c, v), "/", logn(c, u)) 44 | } 45 | 46 | // intLog returns the integer portion of the log base b of v, if it's exact. 47 | // If inexact, it returns zero. 48 | func intLog(bI, vI Int) (log uint64, exact bool) { 49 | b := uint64(bI) 50 | v := uint64(vI) 51 | if b <= 1 || v < b { 52 | return 0, false 53 | } 54 | log = 1 // The logarithm is at least 1 because v>=b. 55 | // Looping one division at a time is easy but slow. 56 | // Doesn't matter much here but can be important in bigIntLog. 57 | for v != b { 58 | quo := v / b 59 | rem := v % b 60 | if rem != 0 { 61 | return 0, false 62 | } 63 | log++ 64 | v = quo 65 | } 66 | return log, true 67 | } 68 | 69 | // bigIntLog returns the integer portion of the log base b of v, if it's exact. 70 | // If inexact, it returns zero. 71 | func bigIntLog(b, v BigInt) (log Int, exact bool) { 72 | if b.Cmp(bigIntOne.Int) <= 0 || v.Cmp(b.Int) < 0 { 73 | return 0, false 74 | } 75 | log = Int(1) // The logarithm is at least 1 because v>=b. 76 | x := new(big.Int).Set(v.Int) 77 | quo := new(big.Int) 78 | rem := new(big.Int) 79 | // Looping one division at a time is easy but slow. 80 | // TODO: Scale up faster. 81 | for x.Cmp(b.Int) != 0 { 82 | quo.DivMod(x, b.Int, rem) 83 | if rem.Sign() != 0 { 84 | return 0, false 85 | } 86 | log++ 87 | x.Set(quo) 88 | } 89 | return log, true 90 | } 91 | 92 | // floatLog computes natural log(x) using the Maclaurin series for log(1-x). 93 | func floatLog(c Context, x *big.Float) *big.Float { 94 | if x.Sign() <= 0 { 95 | Errorf("log of non-positive value") 96 | } 97 | // Convergence is imperfect at 1, so get it right. 98 | if x.Cmp(floatOne) == 0 { 99 | return newFloat(c) 100 | } 101 | // The series wants x < 1, and log 1/x == -log x, so exploit that. 102 | invert := false 103 | x = newFloat(c).Set(x) // Don't modify argument! 104 | if x.Cmp(floatOne) > 0 { 105 | invert = true 106 | x.Quo(floatOne, x) 107 | } 108 | 109 | // x = mantissa * 2**exp, and 0.5 <= mantissa < 1. 110 | // So log(x) is log(mantissa)+exp*log(2), and 1-x will be 111 | // between 0 and 0.5, so the series for 1-x will converge well. 112 | // (The series converges slowly in general.) 113 | mantissa := new(big.Float) 114 | exp2 := x.MantExp(mantissa) 115 | exp := newFloat(c).SetInt64(int64(exp2)) 116 | exp.Mul(exp, floatLog2) 117 | if invert { 118 | exp.Neg(exp) 119 | } 120 | 121 | // y = 1-x (whereupon x = 1-y and we use that in the series). 122 | y := newFloat(c).SetInt64(1) 123 | y.Sub(y, mantissa) 124 | 125 | // The Maclaurin series for log(1-y) == log(x) is: -y - y²/2 - y³/3 ... 126 | 127 | yN := newFloat(c).Set(y) 128 | term := newFloat(c) 129 | n := newFloat(c).Set(floatOne) 130 | z := newFloat(c) 131 | 132 | // This is the slowest-converging series, so we add a factor of ten to the cutoff. 133 | // Only necessary when FloatPrec is at or beyond constPrecisionInBits. 134 | 135 | for loop := newLoop(c.Config(), "log", x, 40); ; { 136 | term.Quo(yN, n.SetUint64(loop.i+1)) 137 | z.Sub(z, term) 138 | if loop.done(z) { 139 | break 140 | } 141 | // Advance y**index (multiply by y). 142 | yN.Mul(yN, y) 143 | } 144 | 145 | if invert { 146 | z.Neg(z) 147 | } 148 | z.Add(z, exp) 149 | 150 | return z 151 | } 152 | 153 | // Note: We return a Complex here, not a Value, so the caller 154 | // might want to call shrink. This is so the binary ** has a Complex 155 | // on both sides. 156 | func complexLog(c Context, v Complex) Complex { 157 | abs := v.abs(c) 158 | phase := v.phase(c) 159 | return NewComplex(logn(c, abs), phase) 160 | } 161 | -------------------------------------------------------------------------------- /ivy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main // import "robpike.io/ivy" 6 | 7 | import ( 8 | "bufio" 9 | "flag" 10 | "fmt" 11 | "io" 12 | "os" 13 | "runtime/pprof" 14 | "strings" 15 | 16 | "robpike.io/ivy/config" 17 | "robpike.io/ivy/exec" 18 | "robpike.io/ivy/parse" 19 | "robpike.io/ivy/run" 20 | "robpike.io/ivy/scan" 21 | "robpike.io/ivy/value" 22 | ) 23 | 24 | var ( 25 | execute = flag.String("e", "", "execute `argument` and quit") 26 | executeContinue = flag.String("i", "", "execute `argument` and continue") 27 | file = flag.String("f", "", "execute `file` before input") 28 | format = flag.String("format", "", "use `fmt` as format for printing numbers; empty sets default format") 29 | gformat = flag.Bool("g", false, `shorthand for -format="%.12g"`) 30 | maxbits = flag.Uint("maxbits", 1e9, "maximum size of an integer, in bits; 0 means no limit") 31 | maxdigits = flag.Uint("maxdigits", 1e4, "above this many `digits`, integers print as floating point; 0 disables") 32 | maxstack = flag.Uint("stack", 100000, "maximum call stack `depth` allowed") 33 | origin = flag.Int("origin", 1, "set index origin to `n` (must be >=0)") 34 | prompt = flag.String("prompt", "", "command `prompt`") 35 | profile = flag.String("profile", "", "write profile to `file`") 36 | debugFlag = flag.String("debug", "", "comma-separated `names` of debug settings to enable") 37 | ) 38 | 39 | var ( 40 | conf config.Config 41 | context value.Context 42 | ) 43 | 44 | func main() { 45 | flag.Usage = usage 46 | flag.Parse() 47 | 48 | if *profile != "" { 49 | f, err := os.Create(*profile) 50 | if err != nil { 51 | fmt.Fprintf(os.Stderr, "ivy: cannot create profile file: %v\n", err) 52 | os.Exit(2) 53 | } 54 | defer f.Close() 55 | err = pprof.StartCPUProfile(f) 56 | if err != nil { 57 | fmt.Fprintf(os.Stderr, "ivy: cannot start CPU profile: %v\n", err) 58 | os.Exit(2) 59 | } 60 | defer pprof.StopCPUProfile() 61 | } 62 | 63 | if *origin < 0 { 64 | fmt.Fprintf(os.Stderr, "ivy: illegal origin value %d\n", *origin) 65 | os.Exit(2) 66 | } 67 | 68 | if *gformat { 69 | *format = "%.12g" 70 | } 71 | 72 | conf.SetFormat(*format) 73 | conf.SetMaxBits(*maxbits) 74 | conf.SetMaxDigits(*maxdigits) 75 | conf.SetMaxStack(*maxstack) 76 | conf.SetOrigin(*origin) 77 | conf.SetPrompt(*prompt) 78 | 79 | if len(*debugFlag) > 0 { 80 | for _, debug := range strings.Split(*debugFlag, ",") { 81 | if !conf.SetDebug(debug, 1) { 82 | fmt.Fprintf(os.Stderr, "ivy: unknown debug flag %q\n", debug) 83 | os.Exit(2) 84 | } 85 | } 86 | } 87 | 88 | context = exec.NewContext(&conf) 89 | 90 | if *file != "" { 91 | if !runFile(context, *file) { 92 | os.Exit(1) 93 | } 94 | } 95 | 96 | if *executeContinue != "" { 97 | if !runString(context, *executeContinue) { 98 | os.Exit(1) 99 | } 100 | } 101 | 102 | if *execute != "" { 103 | if !runString(context, *execute) { 104 | os.Exit(1) 105 | } 106 | return 107 | } 108 | 109 | if flag.NArg() > 0 { 110 | for i := 0; i < flag.NArg(); i++ { 111 | if !runFile(context, flag.Arg(i)) { 112 | os.Exit(1) 113 | } 114 | } 115 | return 116 | } 117 | 118 | scanner := scan.New(context, "", bufio.NewReader(os.Stdin)) 119 | parser := parse.NewParser("", scanner, context) 120 | for !run.Run(parser, context, true) { 121 | } 122 | } 123 | 124 | // runFile executes the contents of the file as an ivy program. 125 | func runFile(context value.Context, file string) bool { 126 | var fd io.Reader 127 | var err error 128 | interactive := false 129 | if file == "-" { 130 | interactive = true 131 | fd = os.Stdin 132 | } else { 133 | interactive = false 134 | fd, err = os.Open(file) 135 | } 136 | if err != nil { 137 | fmt.Fprintf(os.Stderr, "ivy: %s\n", err) 138 | os.Exit(1) 139 | } 140 | scanner := scan.New(context, file, bufio.NewReader(fd)) 141 | parser := parse.NewParser(file, scanner, context) 142 | return run.Run(parser, context, interactive) 143 | } 144 | 145 | // runString executes the string, typically a command-line argument, as an ivy program. 146 | func runString(context value.Context, str string) bool { 147 | scanner := scan.New(context, "", strings.NewReader(str)) 148 | parser := parse.NewParser("", scanner, context) 149 | return run.Run(parser, context, false) 150 | } 151 | 152 | func usage() { 153 | fmt.Fprintf(os.Stderr, "usage: ivy [options] [file ...]\n") 154 | fmt.Fprintf(os.Stderr, "Flags:\n") 155 | flag.PrintDefaults() 156 | os.Exit(2) 157 | } 158 | -------------------------------------------------------------------------------- /value/sinh.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "math/big" 9 | ) 10 | 11 | func sinh(c Context, v Value) Value { 12 | if u, ok := v.(Complex); ok { 13 | if !isZero(u.imag) { 14 | return complexSinh(c, u) 15 | } 16 | v = u.real 17 | } 18 | return evalFloatFunc(c, v, floatSinh) 19 | } 20 | 21 | func cosh(c Context, v Value) Value { 22 | if u, ok := v.(Complex); ok { 23 | if !isZero(u.imag) { 24 | return complexCosh(c, u) 25 | } 26 | v = u.real 27 | } 28 | return evalFloatFunc(c, v, floatCosh) 29 | } 30 | 31 | func tanh(c Context, v Value) Value { 32 | if u, ok := v.(Complex); ok { 33 | if !isZero(u.imag) { 34 | return complexTanh(c, u) 35 | } 36 | v = u.real 37 | } 38 | return evalFloatFunc(c, v, floatTanh) 39 | } 40 | 41 | // floatSinh computes sinh(x) = (e**x - e**-x)/2. 42 | func floatSinh(c Context, x *big.Float) *big.Float { 43 | // The Taylor series for sinh(x) is the odd terms of exp(x): x + x³/3! + x⁵/5!... 44 | 45 | conf := c.Config() 46 | xN := newF(conf).Set(x) 47 | term := newF(conf) 48 | n := newF(conf) 49 | nFactorial := newF(conf).SetUint64(1) 50 | z := newF(conf).SetInt64(0) 51 | 52 | for loop := newLoop(conf, "sinh", x, 10); ; { // Big exponentials converge slowly. 53 | term.Set(xN) 54 | term.Quo(term, nFactorial) 55 | z.Add(z, term) 56 | 57 | if loop.done(z) { 58 | break 59 | } 60 | // Advance x**index (multiply by x). 61 | xN.Mul(xN, x) 62 | xN.Mul(xN, x) 63 | // Advance n, n!. 64 | nFactorial.Mul(nFactorial, n.SetUint64(2*loop.i)) 65 | nFactorial.Mul(nFactorial, n.SetUint64(2*loop.i+1)) 66 | } 67 | 68 | return z 69 | } 70 | 71 | // floatCosh computes sinh(x) = (e**x + e**-x)/2. 72 | func floatCosh(c Context, x *big.Float) *big.Float { 73 | // The Taylor series for cosh(x) is the even terms of exp(x): 1 + x²/2! + x⁴/4!... 74 | 75 | conf := c.Config() 76 | xN := newF(conf).Set(x) 77 | xN.Mul(xN, x) // x² 78 | term := newF(conf) 79 | n := newF(conf) 80 | nFactorial := newF(conf).SetUint64(2) 81 | z := newF(conf).SetInt64(1) 82 | 83 | for loop := newLoop(conf, "cosh", x, 10); ; { // Big exponentials converge slowly. 84 | term.Set(xN) 85 | term.Quo(term, nFactorial) 86 | z.Add(z, term) 87 | 88 | if loop.done(z) { 89 | break 90 | } 91 | // Advance x**index (multiply by x). 92 | xN.Mul(xN, x) 93 | xN.Mul(xN, x) 94 | // Advance n, n!. 95 | nFactorial.Mul(nFactorial, n.SetUint64(2*loop.i+1)) 96 | nFactorial.Mul(nFactorial, n.SetUint64(2*loop.i+2)) 97 | } 98 | 99 | return z 100 | } 101 | 102 | // floatTanh computes tanh(x) = sinh(x)/cosh(x) 103 | func floatTanh(c Context, x *big.Float) *big.Float { 104 | if x.IsInf() { 105 | Errorf("tanh of infinity") 106 | } 107 | denom := floatCosh(c, x) 108 | if denom.Cmp(floatZero) == 0 { 109 | Errorf("tanh is infinite") 110 | } 111 | num := floatSinh(c, x) 112 | return num.Quo(num, denom) 113 | } 114 | 115 | func complexSinh(c Context, v Complex) Value { 116 | // Use the formula: sinh(x+yi) = sinh(x)cos(y) + i cosh(x)sin(y) 117 | // First turn v into (a + bi) where a and b are big.Floats. 118 | x := floatSelf(c, v.real).Float 119 | y := floatSelf(c, v.imag).Float 120 | sinhX := floatSinh(c, x) 121 | cosY := floatCos(c, y) 122 | coshX := floatCosh(c, x) 123 | sinY := floatSin(c, y) 124 | lhs := sinhX.Mul(sinhX, cosY) 125 | rhs := coshX.Mul(coshX, sinY) 126 | return NewComplex(BigFloat{lhs}, BigFloat{rhs}).shrink() 127 | } 128 | 129 | func complexCosh(c Context, v Complex) Value { 130 | // Use the formula: cosh(x+yi) = cosh(x)cos(y) + i sinh(x)sin(y) 131 | // First turn v into (a + bi) where a and b are big.Floats. 132 | x := floatSelf(c, v.real).Float 133 | y := floatSelf(c, v.imag).Float 134 | coshX := floatCosh(c, x) 135 | cosY := floatCos(c, y) 136 | sinhX := floatSinh(c, x) 137 | sinY := floatSin(c, y) 138 | lhs := coshX.Mul(coshX, cosY) 139 | rhs := sinhX.Mul(sinhX, sinY) 140 | return NewComplex(BigFloat{lhs}, BigFloat{rhs}).shrink() 141 | } 142 | 143 | func complexTanh(c Context, v Complex) Value { 144 | // Use the formula: tanh(x+yi) = (sinh(2x) + i sin(2y)/(cosh(2x) + cos(2y)) 145 | // First turn v into (a + bi) where a and b are big.Floats. 146 | x := floatSelf(c, v.real).Float 147 | y := floatSelf(c, v.imag).Float 148 | // Double them - all the arguments are 2X. 149 | x.Mul(x, floatTwo) 150 | y.Mul(y, floatTwo) 151 | sinh2X := floatSinh(c, x) 152 | sin2Y := floatSin(c, y) 153 | cosh2X := floatCosh(c, x) 154 | cos2Y := floatCos(c, y) 155 | den := cosh2X.Add(cosh2X, cos2Y) 156 | if den.Sign() == 0 { 157 | Errorf("tangent is infinite") 158 | } 159 | return NewComplex(BigFloat{sinh2X.Quo(sinh2X, den)}, BigFloat{sin2Y.Quo(sin2Y, den)}).shrink() 160 | } 161 | -------------------------------------------------------------------------------- /testdata/binary_bigrat.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Binary operations with big rationals on the left. 6 | 7 | 1/3 + 5 8 | 16/3 9 | 10 | 1/3 + 1/3 11 | 2/3 12 | 13 | 1/3 + iota 3 14 | 4/3 7/3 10/3 15 | 16 | 1/3 + 2 3 rho iota 10 17 | 4/3 7/3 10/3 18 | 13/3 16/3 19/3 19 | 20 | 1/3-5 21 | -14/3 22 | 23 | 1/3 - 1e10 24 | -29999999999/3 25 | 26 | 1/3 - 2/3 27 | -1/3 28 | 29 | 1/3 - iota 3 30 | -2/3 -5/3 -8/3 31 | 32 | 1/3-2 3 rho iota 10 33 | -2/3 -5/3 -8/3 34 | -11/3 -14/3 -17/3 35 | 36 | 1/3*5 37 | 5/3 38 | 39 | 1/2*1e10 40 | 5000000000 41 | 42 | 1/3 * 1/3 43 | 1/9 44 | 45 | 1/3 * iota 3 46 | 1/3 2/3 1 47 | 48 | 1/3 * 2 3 rho iota 10 49 | 1/3 2/3 1 50 | 4/3 5/3 2 51 | 52 | 1/3 / 5 53 | 1/15 54 | 55 | 1/3 / 1e10 56 | 1/30000000000 57 | 58 | 1/3 / 2/3 59 | 1/2 60 | 61 | 1/3 / iota 3 62 | 1/3 1/6 1/9 63 | 64 | 1/3 / 2 3 rho iota 10 65 | 1/3 1/6 1/9 66 | 1/12 1/15 1/18 67 | 68 | 1 mod 2/3 69 | 1/3 70 | 71 | 1 mod 1/3 72 | 0 73 | 74 | 5/7 mod 1/3 75 | 1/21 76 | 77 | -5/7 mod 1/3 78 | 2/7 79 | 80 | 5/7 mod -1/3 81 | 1/21 82 | 83 | -5/7 mod -1/3 84 | 2/7 85 | 86 | 5/7 mod 1/3 * iota 3 87 | 1/21 1/21 5/7 88 | 89 | 5/7 mod 1/3 * 2 3 rho iota 10 90 | 1/21 1/21 5/7 91 | 5/7 5/7 5/7 92 | 93 | 1/3 ** 5 94 | 1/243 95 | 96 | 2/3 ** -2 97 | 9/4 98 | 99 | 1/3 ** -2 100 | 9 101 | 102 | 1/3 ** iota 3 103 | 1/3 1/9 1/27 104 | 105 | 1/3 ** 2 3 rho iota 4 106 | 1/3 1/9 1/27 107 | 1/81 1/3 1/9 108 | 109 | 1/3 == 5 110 | 0 111 | 112 | 1/3 == 1e10 113 | 0 114 | 115 | 1/3 == 1/3 116 | 1 117 | 118 | 1/3 == -1 + 1/3 + iota 3 119 | 1 0 0 120 | 121 | 1/3 == 2 3 rho -1 + 1/3 + iota 10 122 | 1 0 0 123 | 0 0 0 124 | 125 | 1/3 != 5 126 | 1 127 | 128 | 1/3 != 1e10 129 | 1 130 | 131 | 1/3 != 1/3 132 | 0 133 | 134 | 1/3 != -1 + 1/3 + iota 3 135 | 0 1 1 136 | 137 | 1/3 != 2 3 rho -1 + 1/3 + iota 10 138 | 0 1 1 139 | 1 1 1 140 | 141 | 1/3 < 5 142 | 1 143 | 144 | 1/3 < 3e10 145 | 1 146 | 147 | 1/3 < 1/3 148 | 0 149 | 150 | 1/3 < -1 + 1/3 + iota 3 151 | 0 1 1 152 | 153 | 1/3 < 2 3 rho -1 + 1/3 + iota 6 154 | 0 1 1 155 | 1 1 1 156 | 157 | 1/3 <= 5 158 | 1 159 | 160 | 1/3 <= 3e10 161 | 1 162 | 163 | 1/3 <= 1/3 + 1/3 164 | 1 165 | 166 | 1/3 <= 2 3 rho -1 + 1/3 + iota 10 167 | 1 1 1 168 | 1 1 1 169 | 170 | 1/3 > 5 171 | 0 172 | 173 | 1/3 > 3e10 174 | 0 175 | 176 | 1/3 > 1/3 177 | 0 178 | 179 | 1/3 > -2 + 1/3 + iota 3 180 | 1 0 0 181 | 182 | 1/3 > 2 3 rho -2 + 1/3 + iota 10 183 | 1 0 0 184 | 0 0 0 185 | 186 | 1/3 >= 5 187 | 0 188 | 189 | 1/3 >= 3e10 190 | 0 191 | 192 | 1/3 >= 1/3 193 | 1 194 | 195 | 1/3 >= -2 + 1/3 + iota 3 196 | 1 1 0 197 | 198 | 1/3 >= 2 3 rho -2 + 1/3 + iota 10 199 | 1 1 0 200 | 0 0 0 201 | 202 | 1/3 and 5 203 | 1 204 | 205 | 1/3 and 1e10 206 | 1 207 | 208 | 1/3 and 1/3 209 | 1 210 | 211 | 1/3 and iota 3 212 | 1 1 1 213 | 214 | 1/3 and 2 3 rho iota 10 215 | 1 1 1 216 | 1 1 1 217 | 218 | 1/3 or 5 219 | 1 220 | 221 | 1/3 or 1e10 222 | 1 223 | 224 | 1/3 or 1/3 225 | 1 226 | 227 | 1/3 or -2 + -2 + 1/3 + iota 3 228 | 1 1 1 229 | 230 | 0 or -2 + iota 3 231 | 1 0 1 232 | 233 | 1/3 or -2 + 2 3 rho -2 + 1/3 + iota 10 234 | 1 1 1 235 | 1 1 1 236 | 237 | 1/3 xor 3 238 | 0 239 | 240 | 1/3 xor 1e10 241 | 0 242 | 243 | 1 xor 1/3 244 | 0 245 | 246 | 1 xor -2 + iota 3 247 | 0 1 0 248 | 249 | 1 xor -2+ 2 3 rho iota 10 250 | 0 1 0 251 | 0 0 0 252 | 253 | 0 nand 0 254 | 1 255 | 256 | 0 nand 1 257 | 1 258 | 259 | 1 nand 0 260 | 1 261 | 262 | 1 nand 1 263 | 0 264 | 265 | 1/3 nand 1e10 266 | 0 267 | 268 | 1 nand 1/3 269 | 0 270 | 271 | 1 nand -2 + iota 3 272 | 0 1 0 273 | 274 | 1 nand -2 + 2 3 rho iota 10 275 | 0 1 0 276 | 0 0 0 277 | 278 | 0 nor 0 279 | 1 280 | 281 | 0 nor 1 282 | 0 283 | 284 | 1 nor 0 285 | 0 286 | 287 | 1 nor 1 288 | 0 289 | 290 | 1/3 nor 1e10 291 | 0 292 | 293 | 1 nor 1/3 294 | 0 295 | 296 | 0 nor -2 + iota 3 297 | 0 1 0 298 | 299 | 0 nor -2+ 2 3 rho iota 10 300 | 0 1 0 301 | 0 0 0 302 | 303 | 1/3 iota 1/3 3e10 4e10 304 | 1 0 0 305 | 306 | 1/3 min 5 307 | 1/3 308 | 309 | 1/3 min 1e10 310 | 1/3 311 | 312 | 1/3 min 1/3 313 | 1/3 314 | 315 | 5/3 min iota 3 316 | 1 5/3 5/3 317 | 318 | 1/3 min 2 3 rho -2 + 1/3 + iota 10 319 | -2/3 1/3 1/3 320 | 1/3 1/3 1/3 321 | 322 | 1/3 max 5 323 | 5 324 | 325 | 1/3 max 3e10 326 | 30000000000 327 | 328 | 1/3 max 2/3 329 | 2/3 330 | 331 | 1/3 max -2 + 1/3 + iota 3 332 | 1/3 1/3 4/3 333 | 334 | 1/3 max 2 3 rho -2 + 1/3 + iota 10 335 | 1/3 1/3 4/3 336 | 7/3 10/3 13/3 337 | 338 | 1/3 , 5 339 | 1/3 5 340 | 341 | 1/3 , 1e10 342 | 1/3 10000000000 343 | 344 | 1/3 , 1/3 345 | 1/3 1/3 346 | 347 | 1/3 , iota 3 348 | 1/3 1 2 3 349 | 350 | 1/3 iota 1e10 1/3 3e10 351 | 0 1 0 352 | 353 | # Issue 108 354 | -0.01 ** 6 355 | 1/1000000000000 356 | -------------------------------------------------------------------------------- /testdata/reduce.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Reduction. For each operation we do reduce (/) and reduce first (/%). 6 | 7 | # Scalars 8 | 9 | */2 10 | 2 11 | 12 | */% 2 13 | 2 14 | 15 | +/1e10 16 | 10000000000 17 | 18 | +/% 2 19 | 2 20 | 21 | */ 3/2 22 | 3/2 23 | 24 | */% 3/2 25 | 3/2 26 | 27 | */ 3j2 28 | 3j2 29 | 30 | */% 3j2 31 | 3j2 32 | 33 | # Vectors 34 | 35 | */iota 10 36 | 3628800 37 | 38 | */%iota 10 39 | 3628800 40 | 41 | -/%iota 10 42 | -5 43 | 44 | -/iota 10 45 | -5 46 | 47 | # Exponentiation is a good test for the order of operation. 48 | **/3 3 rho 0.5 * iota 9 49 | 1/2 50535.164327 3.65459038547e+278 50 | 51 | **/%3 3 rho 0.5 * iota 9 52 | 0.000392856894811 1 5.06896863197e+24 53 | 54 | # Matrices 55 | 56 | +/3 4 rho iota 100 57 | 10 26 42 58 | 59 | +/%3 4 rho iota 100 60 | 15 18 21 24 61 | 62 | -/3 4 rho iota 100 63 | -2 -2 -2 64 | 65 | -/%3 4 rho iota 100 66 | 5 6 7 8 67 | 68 | +/3 4 5 rho iota 100 69 | 15 40 65 90 70 | 115 140 165 190 71 | 215 240 265 290 72 | 73 | +/%3 4 5 rho iota 100 74 | 63 66 69 72 75 75 | 78 81 84 87 90 76 | 93 96 99 102 105 77 | 108 111 114 117 120 78 | 79 | -/3 4 5 rho iota 100 80 | 3 8 13 18 81 | 23 28 33 38 82 | 43 48 53 58 83 | 84 | -/%3 4 5 rho iota 100 85 | 21 22 23 24 25 86 | 26 27 28 29 30 87 | 31 32 33 34 35 88 | 36 37 38 39 40 89 | 90 | +/3 4 5 6 rho iota 1000 91 | ┌ ┐ 92 | │ 21 57 93 129 165│ 93 | │ 201 237 273 309 345│ 94 | │ 381 417 453 489 525│ 95 | │ 561 597 633 669 705│ 96 | └ ┘ 97 | ┌ ┐ 98 | │ 741 777 813 849 885│ 99 | │ 921 957 993 1029 1065│ 100 | │1101 1137 1173 1209 1245│ 101 | │1281 1317 1353 1389 1425│ 102 | └ ┘ 103 | ┌ ┐ 104 | │1461 1497 1533 1569 1605│ 105 | │1641 1677 1713 1749 1785│ 106 | │1821 1857 1893 1929 1965│ 107 | │2001 2037 2073 2109 2145│ 108 | └ ┘ 109 | 110 | 111 | +/%3 4 5 6 rho iota 1000 112 | ┌ ┐ 113 | │363 366 369 372 375 378│ 114 | │381 384 387 390 393 396│ 115 | │399 402 405 408 411 414│ 116 | │417 420 423 426 429 432│ 117 | │435 438 441 444 447 450│ 118 | └ ┘ 119 | ┌ ┐ 120 | │453 456 459 462 465 468│ 121 | │471 474 477 480 483 486│ 122 | │489 492 495 498 501 504│ 123 | │507 510 513 516 519 522│ 124 | │525 528 531 534 537 540│ 125 | └ ┘ 126 | ┌ ┐ 127 | │543 546 549 552 555 558│ 128 | │561 564 567 570 573 576│ 129 | │579 582 585 588 591 594│ 130 | │597 600 603 606 609 612│ 131 | │615 618 621 624 627 630│ 132 | └ ┘ 133 | ┌ ┐ 134 | │633 636 639 642 645 648│ 135 | │651 654 657 660 663 666│ 136 | │669 672 675 678 681 684│ 137 | │687 690 693 696 699 702│ 138 | │705 708 711 714 717 720│ 139 | └ ┘ 140 | 141 | op x F y = y*sqrt x 142 | floor F/3 4 5 6 rho iota 100 143 | ┌ ┐ 144 | │ 65 2825 15510 48226 113249│ 145 | │ 224692 398287 651232 1002077 1470632│ 146 | │2077885 2845948 3797997 4958225 6351805│ 147 | │8004847 19401 401 5501 23625│ 148 | └ ┘ 149 | ┌ ┐ 150 | │ 65649 144494 274831 472896 756349│ 151 | │1144171 1656569 2314915 3141681 4160385│ 152 | │5395553 6872673 8618164 974 1229│ 153 | │ 9604 34378 87149 181447 332483│ 154 | └ ┘ 155 | ┌ ┐ 156 | │ 556982 873053 1300096 1858714 2570650│ 157 | │3458732 4546817 5859757 7423354 9264327│ 158 | │ 65 2825 15510 48226 113249│ 159 | │ 224692 398287 651232 1002077 1470632│ 160 | └ ┘ 161 | 162 | op x F y = y*sqrt x 163 | floor F/%3 4 5 6 rho iota 100 164 | ┌ ┐ 165 | │ 187 278 357 431 503 574│ 166 | │ 646 718 791 866 941 1018│ 167 | │1097 1178 1260 1344 1429 1516│ 168 | │1606 1697 1789 1884 1981 2079│ 169 | │2180 2282 2386 2492 2601 2711│ 170 | └ ┘ 171 | ┌ ┐ 172 | │2823 2937 3052 3170 3290 3412│ 173 | │3536 3661 3789 3919 4050 4184│ 174 | │4319 4457 4597 4738 4882 5027│ 175 | │5175 5324 5475 5629 5784 5942│ 176 | │6101 6262 6426 6591 6758 6928│ 177 | └ ┘ 178 | ┌ ┐ 179 | │ 70 142 216 293 371 452│ 180 | │ 534 618 705 793 884 976│ 181 | │1071 1167 1266 1366 1469 1573│ 182 | │1680 1788 189 281 362 439│ 183 | │ 515 590 666 742 820 900│ 184 | └ ┘ 185 | ┌ ┐ 186 | │ 980 1063 1147 1233 1321 1410│ 187 | │1502 1596 1691 1788 187 278│ 188 | │ 357 431 503 574 646 718│ 189 | │ 791 866 941 1018 1097 1178│ 190 | │1260 1344 1429 1516 1606 1697│ 191 | └ ┘ 192 | 193 | 194 | # Some fun from tryapl.org 195 | )seed 0 196 | throws = ? 10000 rho 6 197 | +/(iota 6) o.== throws 198 | 1687 1661 1734 1587 1662 1669 199 | -------------------------------------------------------------------------------- /value/bigfloat.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "fmt" 9 | "math/big" 10 | 11 | "robpike.io/ivy/config" 12 | ) 13 | 14 | type BigFloat struct { 15 | *big.Float 16 | } 17 | 18 | // The fmt package looks for Formatter before Stringer, but we want 19 | // to use Stringer only. big.Float implements Formatter, 20 | // and we embed it in our BigFloat type. To make sure 21 | // that our String gets called rather than the inner Format, we 22 | // put a non-matching stub Format method into this interface. 23 | // This is ugly but very simple and cheap. 24 | func (f BigFloat) Format() {} 25 | 26 | func (f BigFloat) Rank() int { 27 | return 0 28 | } 29 | 30 | const fastFloatPrint = true 31 | 32 | func (f BigFloat) String() string { 33 | return "(" + f.Sprint(debugConf) + ")" 34 | } 35 | 36 | func (f BigFloat) Sprint(conf *config.Config) string { 37 | var mant big.Float 38 | exp := f.Float.MantExp(&mant) 39 | positive := 1 40 | if exp < 0 { 41 | positive = 0 42 | exp = -exp 43 | } 44 | verb, prec := byte('g'), 12 45 | format := conf.Format() 46 | if format != "" { 47 | v, p, ok := conf.FloatFormat() 48 | if ok { 49 | verb, prec = v, p 50 | } 51 | } 52 | // Printing huge floats can be very slow using 53 | // big.Float's native methods; see issue #11068. 54 | // For example 1e5000000 takes a minute of CPU time just 55 | // to print. The code below is instantaneous, by rescaling 56 | // first. It is however less feature-complete. 57 | // (Big ints are problematic too, but if you print 1e50000000 58 | // as an integer you probably won't be surprised it's slow.) 59 | if fastFloatPrint && exp > 10000 { 60 | // We always use %g to print the fraction, and it will 61 | // never have an exponent, but if the format is %E we 62 | // need to use a capital E. 63 | eChar := 'e' 64 | if verb == 'E' || verb == 'G' { 65 | eChar = 'E' 66 | } 67 | // Up to precision 10000, the result is off by 4 decimal digits. 68 | // Add at least 4×ln(10)/ln(2) bits of precision. 69 | fprec := addPrec(conf.FloatPrec(), 16) 70 | fexp := newFP(fprec).SetInt64(int64(exp)) 71 | fexp.Mul(fexp, floatLog2) 72 | fexp.Quo(fexp, floatLog10) 73 | // We now have a floating-point base 10 exponent. 74 | // Break into the integer part and the fractional part. 75 | // The integer part is what we will show. 76 | // The 10**(fractional part) will be multiplied back in. 77 | iexp, _ := fexp.Int(nil) 78 | fraction := fexp.Sub(fexp, newFP(fprec).SetInt(iexp)) 79 | // Now compute 10**(fractional part). 80 | // Fraction is in base 10. Move it to base e. 81 | fraction.Mul(fraction, floatLog10) 82 | scale := exponential(&big.Float{}, fraction) 83 | sign := "" 84 | if mant.Sign() < 0 { 85 | sign = "-" 86 | mant.Neg(&mant) 87 | } 88 | mant.SetPrec(fprec) 89 | if positive > 0 { 90 | mant.Mul(&mant, scale) 91 | } else { 92 | mant.Quo(&mant, scale) 93 | } 94 | i64exp := iexp.Int64() 95 | // If it has a leading 0 rescale. 96 | digits := mant.Text('g', prec) 97 | if digits[0] == '0' { 98 | mant.Mul(&mant, new(big.Float).SetUint64(10)) 99 | if positive > 0 { 100 | i64exp-- 101 | } else { 102 | i64exp++ 103 | } 104 | digits = mant.Text('g', prec) 105 | } 106 | // Print with the E notation for numbers far enough from one. 107 | // This should always be the case (exp must be large to get here) but just 108 | // in case, we keep this check around and fallback to big.Float.Text. 109 | if i64exp < -4 || 11 < i64exp { 110 | return fmt.Sprintf("%s%s%c%c%d", sign, digits, eChar, "-+"[positive], i64exp) 111 | } 112 | } 113 | return f.Float.Text(verb, prec) 114 | } 115 | 116 | // inverse returns 1/f 117 | func (f BigFloat) inverse() Value { 118 | if f.Sign() == 0 { 119 | Errorf("inverse of zero") 120 | } 121 | var one big.Float 122 | one.Set(floatOne) // Avoid big.Float.Copy, which appears to have a sharing bug. 123 | result := BigFloat{ 124 | Float: one.Quo(&one, f.Float), 125 | }.shrink() 126 | return result 127 | } 128 | 129 | func (f BigFloat) ProgString() string { 130 | // There is no such thing as a float literal in program listings. 131 | panic("float.ProgString - cannot happen") 132 | } 133 | 134 | func (f BigFloat) Eval(Context) Value { 135 | return f 136 | } 137 | 138 | func (f BigFloat) Inner() Value { 139 | return f 140 | } 141 | 142 | func (f BigFloat) toType(op string, conf *config.Config, which valueType) Value { 143 | switch which { 144 | case bigFloatType: 145 | return f 146 | case complexType: 147 | return NewComplex(f, zero) 148 | case vectorType: 149 | return oneElemVector(f) 150 | case matrixType: 151 | return NewMatrix([]int{1}, NewVector(f)) 152 | } 153 | Errorf("%s: cannot convert float to %s", op, which) 154 | return nil 155 | } 156 | 157 | // shrink shrinks, if possible, a BigFloat down to an integer type. 158 | func (f BigFloat) shrink() Value { 159 | exp := f.MantExp(nil) 160 | if exp <= 100 && f.IsInt() { // Huge integers are not pretty. (Exp here is power of two.) 161 | i, _ := f.Int(nil) // Result guaranteed exact. 162 | return BigInt{i}.shrink() 163 | } 164 | return f 165 | } 166 | -------------------------------------------------------------------------------- /ivy_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "io/ioutil" 11 | "os" 12 | "path/filepath" 13 | "strings" 14 | "testing" 15 | 16 | "robpike.io/ivy/config" 17 | "robpike.io/ivy/exec" 18 | "robpike.io/ivy/run" 19 | "robpike.io/ivy/value" 20 | ) 21 | 22 | const verbose = false 23 | 24 | var testConf config.Config 25 | 26 | func init() { 27 | value.MaxParallelismForTesting() 28 | } 29 | 30 | // Note: These tests share some infrastructure and cannot run in parallel. 31 | 32 | func TestAll(t *testing.T) { 33 | var err error 34 | check := func() { 35 | if err != nil { 36 | t.Fatal(err) 37 | } 38 | } 39 | dir, err := os.Open("testdata") 40 | check() 41 | names, err := dir.Readdirnames(0) 42 | check() 43 | for _, name := range names { 44 | if !strings.HasSuffix(name, ".ivy") { 45 | continue 46 | } 47 | t.Log(name) 48 | shouldFail := strings.HasSuffix(name, "_fail.ivy") 49 | var data []byte 50 | path := filepath.Join("testdata", name) 51 | data, err = ioutil.ReadFile(path) 52 | check() 53 | text := string(data) 54 | lines := strings.Split(text, "\n") 55 | // Will have a trailing empty string. 56 | if len(lines) > 0 && lines[len(lines)-1] == "" { 57 | lines = lines[:len(lines)-1] 58 | } 59 | lineNum := 1 60 | errCount := 0 61 | for len(lines) > 0 { 62 | // Assemble the input to one example. 63 | input, output, length := getText(t, path, lineNum, shouldFail, lines) 64 | if input == nil { 65 | break 66 | } 67 | if verbose { 68 | fmt.Printf("%s:%d: %s\n", path, lineNum, input) 69 | } 70 | if !runTest(t, path, lineNum, shouldFail, input, output) { 71 | errCount++ 72 | if errCount > 100 { 73 | t.Fatal("too many errors") 74 | } 75 | } 76 | lines = lines[length:] 77 | lineNum += length 78 | } 79 | } 80 | } 81 | 82 | func runTest(t *testing.T, name string, lineNum int, shouldFail bool, input, output []string) bool { 83 | reset() 84 | in := strings.Join(input, "\n") 85 | stdout := new(bytes.Buffer) 86 | stderr := new(bytes.Buffer) 87 | run.Ivy(exec.NewContext(&testConf), in, stdout, stderr) 88 | if shouldFail { 89 | if stderr.Len() == 0 { 90 | t.Fatalf("\nexpected execution failure at %s:%d:\n%s", name, lineNum, in) 91 | } 92 | expect := "" 93 | for _, s := range input { 94 | if strings.HasPrefix(s, "# Expect: ") { 95 | expect = s[len("# Expect: "):] 96 | } 97 | } 98 | if expect != "" && !strings.Contains(stderr.String(), expect) { 99 | t.Errorf("\nunexpected execution failure message at %s:%d:\n%s", name, lineNum, in) 100 | t.Errorf("got:\n\t%s", stderr) 101 | t.Fatalf("expected:\n\t%s\n", expect) 102 | } 103 | return true 104 | } 105 | if stderr.Len() != 0 { 106 | t.Fatalf("\nexecution failure (%s) at %s:%d:\n%s", stderr, name, lineNum, in) 107 | } 108 | result := strings.Split(stdout.String(), "\n") 109 | if !equal(result, output) { 110 | t.Errorf("\n%s:%d:\n\t%s\ngot:\n\t%s\nwant:\n\t%s", 111 | name, lineNum, 112 | strings.Join(input, "\n\t"), 113 | strings.Join(result, "\n\t"), 114 | strings.Join(output, "\n\t")) 115 | return false 116 | } 117 | return true 118 | } 119 | 120 | func equal(a, b []string) bool { 121 | // Split leaves an empty trailing line. 122 | if len(a) > 0 && a[len(a)-1] == "" { 123 | a = a[:len(a)-1] 124 | } 125 | if len(a) != len(b) { 126 | return false 127 | } 128 | for i, s := range a { 129 | if strings.TrimSpace(s) != strings.TrimSpace(b[i]) { 130 | return false 131 | } 132 | } 133 | return true 134 | } 135 | 136 | func getText(t *testing.T, fileName string, lineNum int, shouldFail bool, lines []string) (input, output []string, length int) { 137 | // Skip blank and initial comment lines, except keep leading comment for failure checks. 138 | if !shouldFail { 139 | for _, line := range lines { 140 | if len(line) > 0 && !strings.HasPrefix(line, "#") { 141 | break 142 | } 143 | length++ 144 | } 145 | } 146 | 147 | // Input ends at tab-indented line. 148 | for _, line := range lines[length:] { 149 | line = strings.TrimRight(line, " \t") 150 | if strings.HasPrefix(line, "\t") { 151 | break 152 | } 153 | input = append(input, line) 154 | length++ 155 | } 156 | 157 | // Output ends at non-blank, non-tab-indented line. 158 | // Indented "#" is expected blank line in output. 159 | for _, line := range lines[length:] { 160 | line = strings.TrimRight(line, " \t") 161 | if line != "" && !strings.HasPrefix(line, "\t") { 162 | break 163 | } 164 | output = append(output, strings.TrimPrefix(line, "\t")) 165 | length++ 166 | } 167 | for len(output) > 0 && output[len(output)-1] == "" { 168 | output = output[:len(output)-1] 169 | } 170 | for i, line := range output { 171 | if line == "#" { 172 | output[i] = "" 173 | } 174 | } 175 | 176 | return // Will return nil if no more tests exist. 177 | } 178 | 179 | func reset() { 180 | testConf = config.Config{} 181 | testConf.SetFloatPrec(256) 182 | testConf.SetFormat("") 183 | testConf.SetMaxBits(1e9) 184 | testConf.SetMaxDigits(1e4) 185 | testConf.SetMaxStack(100000) 186 | testConf.SetOrigin(1) 187 | testConf.SetPrompt("") 188 | testConf.SetBase(0, 0) 189 | testConf.SetRandomSeed(0) 190 | testConf.SetLocation("UTC") 191 | } 192 | -------------------------------------------------------------------------------- /value/bigrat.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "math/big" 11 | "strings" 12 | 13 | "robpike.io/ivy/config" 14 | ) 15 | 16 | type BigRat struct { 17 | *big.Rat 18 | } 19 | 20 | // The input is known to be in floating-point syntax. 21 | // If there's a slash, the parsing is done in Parse(). 22 | func setBigRatFromFloatString(s string) (br BigRat, err error) { 23 | // Be safe: Verify that it is floating-point, because otherwise 24 | // we need to honor ibase. 25 | if !strings.ContainsAny(s, ".eEpP") { 26 | // Most likely a number like "08". 27 | Errorf("bad number syntax: %s", s) 28 | } 29 | var ok bool 30 | r, ok := big.NewRat(0, 1).SetString(s) 31 | if !ok { 32 | return BigRat{}, errors.New("floating-point number syntax") 33 | } 34 | return BigRat{r}, nil 35 | } 36 | 37 | func (r BigRat) String() string { 38 | return "(" + r.Sprint(debugConf) + ")" 39 | } 40 | 41 | func (r BigRat) Rank() int { 42 | return 0 43 | } 44 | 45 | func (r BigRat) Sprint(conf *config.Config) string { 46 | format := conf.Format() 47 | if format != "" { 48 | verb, prec, ok := conf.FloatFormat() 49 | if ok { 50 | return r.floatString(verb, prec) 51 | } 52 | return fmt.Sprintf(conf.RatFormat(), r.Num(), r.Denom()) 53 | } 54 | num := BigInt{r.Num()} 55 | den := BigInt{r.Denom()} 56 | return fmt.Sprintf("%s/%s", num.Sprint(conf), den.Sprint(conf)) 57 | } 58 | 59 | func (r BigRat) ProgString() string { 60 | return fmt.Sprintf("%s/%s", r.Num(), r.Denom()) 61 | } 62 | 63 | func (r BigRat) floatString(verb byte, prec int) string { 64 | switch verb { 65 | case 'f', 'F': 66 | return r.Rat.FloatString(prec) 67 | case 'e', 'E': 68 | // The exponent will always be >= 0. 69 | sign := "" 70 | var x, t big.Rat 71 | x.Set(r.Rat) 72 | if x.Sign() < 0 { 73 | sign = "-" 74 | x.Neg(&x) 75 | } 76 | t.Set(&x) 77 | exp := ratExponent(&x) 78 | ratScale(&t, exp) 79 | str := t.FloatString(prec + 1) // +1 because first digit might be zero. 80 | // Drop the decimal. 81 | if str[0] == '0' { 82 | str = str[2:] 83 | exp-- 84 | } else if len(str) > 1 && str[1] == '.' { 85 | str = str[0:1] + str[2:] 86 | } 87 | return eFormat(verb, prec, sign, str, exp) 88 | case 'g', 'G': 89 | var x big.Rat 90 | x.Set(r.Rat) 91 | exp := ratExponent(&x) 92 | // Exponent could be positive or negative 93 | if exp < -4 || prec <= exp { 94 | // Use e format. 95 | verb -= 2 // g becomes e. 96 | return trimEZeros(verb, r.floatString(verb, prec-1)) 97 | } 98 | // Use f format. 99 | // If it's got zeros right of the decimal, they count as digits in the precision. 100 | // If it's got digits left of the decimal, they count as digits in the precision. 101 | // Both are handled by adjusting prec by exp. 102 | str := r.floatString(verb-1, prec-exp-1) // -1 for the one digit left of the decimal. 103 | // Trim trailing decimals. 104 | point := strings.IndexByte(str, '.') 105 | if point > 0 { 106 | n := len(str) 107 | for str[n-1] == '0' { 108 | n-- 109 | } 110 | str = str[:n] 111 | if str[n-1] == '.' { 112 | str = str[:n-1] 113 | } 114 | } 115 | return str 116 | default: 117 | Errorf("can't handle verb %c for rational", verb) 118 | } 119 | return "" 120 | } 121 | 122 | // ratExponent returns the power of ten that x would display in scientific notation. 123 | func ratExponent(x *big.Rat) int { 124 | if x.Sign() < 0 { 125 | x.Neg(x) 126 | } 127 | e := 0 128 | invert := false 129 | if x.Num().Cmp(x.Denom()) < 0 { 130 | invert = true 131 | x.Inv(x) 132 | e++ 133 | } 134 | for x.Cmp(bigRatBillion) >= 0 { 135 | e += 9 136 | x.Quo(x, bigRatBillion) 137 | } 138 | for x.Cmp(bigRatTen) > 0 { 139 | e++ 140 | x.Quo(x, bigRatTen) 141 | } 142 | if invert { 143 | return -e 144 | } 145 | return e 146 | } 147 | 148 | // ratScale multiplies x by 10**exp. 149 | func ratScale(x *big.Rat, exp int) { 150 | if exp < 0 { 151 | x.Inv(x) 152 | ratScale(x, -exp) 153 | x.Inv(x) 154 | return 155 | } 156 | for exp >= 9 { 157 | x.Quo(x, bigRatBillion) 158 | exp -= 9 159 | } 160 | for exp >= 1 { 161 | x.Quo(x, bigRatTen) 162 | exp-- 163 | } 164 | } 165 | 166 | // inverse returns 1/r 167 | func (r BigRat) inverse() Value { 168 | if r.Sign() == 0 { 169 | Errorf("inverse of zero") 170 | } 171 | return BigRat{ 172 | Rat: big.NewRat(0, 1).SetFrac(r.Denom(), r.Num()), 173 | }.shrink() 174 | } 175 | 176 | func (r BigRat) Eval(Context) Value { 177 | return r 178 | } 179 | 180 | func (r BigRat) Inner() Value { 181 | return r 182 | } 183 | 184 | func (r BigRat) toType(op string, conf *config.Config, which valueType) Value { 185 | switch which { 186 | case bigRatType: 187 | return r 188 | case bigFloatType: 189 | f := new(big.Float).SetPrec(conf.FloatPrec()).SetRat(r.Rat) 190 | return BigFloat{f} 191 | case complexType: 192 | return NewComplex(r, zero) 193 | case vectorType: 194 | return oneElemVector(r) 195 | case matrixType: 196 | return NewMatrix([]int{1, 1}, NewVector(r)) 197 | } 198 | Errorf("%s: cannot convert rational to %s", op, which) 199 | return nil 200 | } 201 | 202 | // shrink pulls, if possible, a BigRat down to a BigInt or Int. 203 | func (r BigRat) shrink() Value { 204 | if !r.IsInt() { 205 | return r 206 | } 207 | return BigInt{r.Num()}.shrink() 208 | } 209 | -------------------------------------------------------------------------------- /testdata/format.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Floating point formats. 6 | 7 | # %f and %F 8 | 9 | )format "%f" 10 | 1 1e25 4/3 ((sqrt 2) j (sqrt 3)) 11 | 1.000000 10000000000000000000000000.000000 1.333333 1.414214j1.732051 12 | 13 | )format "%F" 14 | -1 -1e25 -4/3 1j2 # Note: BigFloat does not understand %F. 15 | -1.000000 -10000000000000000000000000.000000 -1.333333 1.000000j2.000000 16 | 17 | )format "%.2f" 18 | 1 1e25 4/3 ((sqrt 2) j (sqrt 3)) 19 | 1.00 10000000000000000000000000.00 1.33 1.41j1.73 20 | 21 | )format "%.0f" 22 | 1 1e25 4/3 ((sqrt 2) j (sqrt 3)) 23 | 1 10000000000000000000000000 1 1j2 24 | 25 | # %e and %E 26 | 27 | )format "%.1e" 28 | 1 100 1000 1000000 -123456 ((sqrt 2) j (sqrt 3)) 29 | 1.0e+00 1.0e+02 1.0e+03 1.0e+06 -1.2e+05 1.4e+00j1.7e+00 30 | 31 | )format "%.1E" 32 | 1 100 1000 1000000 -123456 ((sqrt 2) j (sqrt 3)) 33 | 1.0E+00 1.0E+02 1.0E+03 1.0E+06 -1.2E+05 1.4E+00j1.7E+00 34 | 35 | )format "%.9e" 36 | 1 100 1000 1000000 -123456 ((sqrt 2) j (sqrt 3)) 37 | 1.000000000e+00 1.000000000e+02 1.000000000e+03 1.000000000e+06 -1.234560000e+05 1.414213562e+00j1.732050808e+00 38 | 39 | )format "%.0e" 40 | 1 100 1000 1000000 -123456 ((sqrt 2) j (sqrt 3)) 41 | 1e+00 1e+02 1e+03 1e+06 -1e+05 1e+00j2e+00 42 | 43 | )format "%.1e" 44 | 123456e100 -123456e100 ((sqrt 2) j (sqrt 3)) 45 | 1.2e+105 -1.2e+105 1.4e+00j1.7e+00 46 | 47 | )format "%.9e" 48 | 123456e100 -123456e100 ((sqrt 2) j (sqrt 3)) 49 | 1.234560000e+105 -1.234560000e+105 1.414213562e+00j1.732050808e+00 50 | 51 | )format "%.0e" 52 | 123456e100 -123456e100 ((sqrt 2) j (sqrt 3)) 53 | 1e+105 -1e+105 1e+00j2e+00 54 | 55 | # Rationals with %e. 56 | 57 | )format "%.1e" 58 | 1/3 -1/3 1/3000 10000/3 1/3j2/3 59 | 3.3e-01 -3.3e-01 3.3e-04 3.3e+03 3.3e-01j6.6e-01 60 | 61 | )format "%.0e" 62 | 1/100 1/3 -1/3 1/3000 10000/3 1/3j2/3 63 | 1e-02 3e-01 -3e-01 3e-04 3e+03 3e-01j6e-01 64 | 65 | )format "%.3e" 66 | 1/100 1/3 -1/3 1/3000 10000/3 1/3j2/3 67 | 1.000e-02 3.333e-01 -3.333e-01 3.333e-04 3.333e+03 3.333e-01j6.666e-01 68 | 69 | )format "%.9e" 70 | 1/3 -1/3 1/3000 10000/3 1/3j2/3 71 | 3.333333333e-01 -3.333333333e-01 3.333333333e-04 3.333333333e+03 3.333333333e-01j6.666666666e-01 72 | 73 | 74 | # %g and %G 75 | 76 | )format "%.1g" 77 | 1 12 -123 1234 12345 123456 1234567 12345678 123j456 78 | 1 1e+01 -1e+02 1e+03 1e+04 1e+05 1e+06 1e+07 1e+02j4e+02 79 | 80 | )format "%.3g" 81 | 1 12 -123 1234 12345 123456 1234567 12345678 123j456 82 | 1 12 -123 1.23e+03 1.23e+04 1.23e+05 1.23e+06 1.23e+07 123j456 83 | 84 | )format "%.6G" 85 | # TODO: rounding is wrong 86 | 1 12 -123 1234 12345 123456 1234567 12345678 123j456 87 | 1 12 -123 1234 12345 123456 1.23456E+06 1.23456E+07 123j456 88 | 89 | )format "%.9g" 90 | 1 12 -123 1234 12345 123456 1234567 12345678 123j456 91 | 1 12 -123 1234 12345 123456 1234567 12345678 123j456 92 | 93 | )format "%.1g" 94 | 1e20 1.2e20 -1.23e20 1.234e20 1.2345e20 1.23456e20 1.234567e20 1.2345678e20 123e20j456e20 95 | 1e+20 1e+20 -1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+22j4e+22 96 | 97 | )format "%.3g" 98 | 1e20 1.2e20 -1.23e20 1.234e20 1.2345e20 1.23456e20 1.234567e20 1.2345678e20 123e20j456e20 99 | 1e+20 1.2e+20 -1.23e+20 1.23e+20 1.23e+20 1.23e+20 1.23e+20 1.23e+20 1.23e+22j4.56e+22 100 | 101 | 102 | )format "%.6g" 103 | # TODO: rounding is wrong 104 | 1e20 -1.2e20 1.23e20 1.234e20 1.2345e20 1.23456e20 1.234567e20 1.2345678e20 123e20j456e20 105 | 1e+20 -1.2e+20 1.23e+20 1.234e+20 1.2345e+20 1.23456e+20 1.23456e+20 1.23456e+20 1.23e+22j4.56e+22 106 | 107 | )format "%.9g" 108 | 1e20 -1.2e20 1.23e20 1.234e20 1.2345e20 1.23456e20 1.234567e20 1.2345678e20 123e20j456e20 109 | 1e+20 -1.2e+20 1.23e+20 1.234e+20 1.2345e+20 1.23456e+20 1.234567e+20 1.2345678e+20 1.23e+22j4.56e+22 110 | 111 | )format "%.20g" 112 | 12345678901234567890 -123456789012345678901 1234567890123456789012 123e20j456e20 113 | 12345678901234567890 -1.234567890123456789e+20 1.234567890123456789e+21 1.23e+22j4.56e+22 114 | 115 | )format "%.1g" 116 | 1/3 1/30 -1/300 1/3000 1/30000 1/3j2/3 117 | 0.3 0.03 -0.003 0.0003 3e-05 0.3j0.7 118 | 119 | )format "%.1G" 120 | 4/3 40/3 -400/3 4000/3 1/3j2/3 121 | 1 1E+01 -1E+02 1E+03 0.3j0.7 122 | 123 | )format "%.6g" 124 | 1/3 1/30 -1/300 1/3000 1/30000 1/3j2/3 125 | 0.333333 0.0333333 -0.00333333 0.000333333 3.33333e-05 0.333333j0.666667 126 | 127 | )format "%.6g" 128 | 4/3 40/3 -400/3 4000/3 1/3j2/3 129 | 1.33333 13.3333 -133.333 1333.33 0.333333j0.666667 130 | 131 | )format "%.9g" 132 | 1/3 1/30 -1/300 1/3000 1/30000 1/3j2/3 133 | 0.333333333 0.0333333333 -0.00333333333 0.000333333333 3.33333333e-05 0.333333333j0.666666667 134 | 135 | )format "%.9g" 136 | 4/3 40/3 -400/3 4000/3 1/3j2/3 137 | 1.33333333 13.3333333 -133.333333 1333.33333 0.333333333j0.666666667 138 | 139 | # Trailing zeros and decimals (%g/%G only) 140 | 141 | # Fractional form. 142 | )format "%.20g" 143 | 1 2 3 1/2 1/4 1/8 1e10 144 | 1 2 3 0.5 0.25 0.125 10000000000 145 | 146 | # Exponential form 147 | )format "%g" 148 | 1e10 149 | 1e+10 150 | 151 | # Verify that )specials always use base 10. 152 | )base 3 153 | )base 10 154 | 1<<9 155 | 512 156 | 157 | # Big integers print as float. Configurable by )maxdigits. 158 | )maxdigits 10 159 | 1e100 160 | 1e+100 161 | 162 | # Issue 225: correct value for values > 0.5×2^10000 (fastFloatPrint). 163 | # Set prec 256, just in case the default changes 164 | )prec 256 165 | # Print with full precision 166 | )format "%.77g" 167 | float 1<<11000 168 | 2.1377273016175946639947418801095121966854178364444088402247933779652136564166e+3311 169 | -------------------------------------------------------------------------------- /value/bigint.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "math/big" 11 | "strings" 12 | 13 | "robpike.io/ivy/config" 14 | ) 15 | 16 | type BigInt struct { 17 | *big.Int 18 | } 19 | 20 | // The fmt package looks for Formatter before Stringer, but we want 21 | // to use Stringer only. big.Int and big.Rat implement Formatter, 22 | // and we embed them in our BigInt and BigRat types. To make sure 23 | // that our String gets called rather than the inner Format, we 24 | // put a non-matching stub Format method into this interface. 25 | // This is ugly but very simple and cheap. 26 | func (i BigInt) Format() {} 27 | 28 | func (i BigInt) Rank() int { 29 | return 0 30 | } 31 | 32 | func setBigIntString(conf *config.Config, s string) (BigInt, error) { 33 | i, ok := big.NewInt(0).SetString(s, conf.InputBase()) 34 | if !ok { 35 | return BigInt{}, errors.New("integer parse error") 36 | } 37 | return BigInt{i}, nil 38 | } 39 | 40 | func (i BigInt) String() string { 41 | return "(" + i.Sprint(debugConf) + ")" 42 | } 43 | 44 | func (i BigInt) Sprint(conf *config.Config) string { 45 | bitLen := i.BitLen() 46 | format := conf.Format() 47 | var maxBits = (uint64(conf.MaxDigits()) * 33222) / 10000 // log 10 / log 2 is 3.32192809489 48 | if uint64(bitLen) > maxBits && maxBits != 0 { 49 | // Print in floating point. 50 | return BigFloat{newF(conf).SetInt(i.Int)}.Sprint(conf) 51 | } 52 | if format != "" { 53 | verb, prec, ok := conf.FloatFormat() 54 | if ok { 55 | return i.floatString(verb, prec) 56 | } 57 | return fmt.Sprintf(format, i.Int) 58 | } 59 | // Is this from a rational and we could use an int? 60 | if i.BitLen() < intBits { 61 | return Int(i.Int64()).Sprint(conf) 62 | } 63 | switch conf.OutputBase() { 64 | case 0, 10: 65 | return fmt.Sprintf("%d", i.Int) 66 | case 2: 67 | return fmt.Sprintf("%b", i.Int) 68 | case 8: 69 | return fmt.Sprintf("%o", i.Int) 70 | case 16: 71 | return fmt.Sprintf("%x", i.Int) 72 | } 73 | Errorf("can't print number in base %d (yet)", conf.OutputBase()) 74 | return "" 75 | } 76 | 77 | func (i BigInt) ProgString() string { 78 | return fmt.Sprintf("%d", i.Int) 79 | } 80 | 81 | func (i BigInt) floatString(verb byte, prec int) string { 82 | switch verb { 83 | case 'f', 'F': 84 | str := fmt.Sprintf("%d", i.Int) 85 | if prec > 0 { 86 | str += "." + zeros(prec) 87 | } 88 | return str 89 | case 'e', 'E': 90 | // The exponent will always be >= 0. 91 | sign := "" 92 | var x big.Int 93 | x.Set(i.Int) 94 | if x.Sign() < 0 { 95 | sign = "-" 96 | x.Neg(&x) 97 | } 98 | return eFormat(verb, prec, sign, x.String(), eExponent(&x)) 99 | case 'g', 'G': 100 | // Exponent is always positive so it's easy. 101 | var x big.Int 102 | x.Set(i.Int) 103 | if eExponent(&x) >= prec { 104 | // Use e format. 105 | verb -= 2 // g becomes e. 106 | return trimEZeros(verb, i.floatString(verb, prec-1)) 107 | } 108 | // Use f format, but this is just an integer. 109 | return fmt.Sprintf("%d", i.Int) 110 | default: 111 | Errorf("can't handle verb %c for big int", verb) 112 | } 113 | return "" 114 | } 115 | 116 | // eExponent returns the exponent to use to display i in 1.23e+04 format. 117 | func eExponent(x *big.Int) int { 118 | if x.Sign() < 0 { 119 | x.Neg(x) 120 | } 121 | e := 0 122 | for x.Cmp(bigIntBillion) >= 0 { 123 | e += 9 124 | x.Quo(x, bigIntBillion) 125 | } 126 | for x.Cmp(bigIntTen) >= 0 { 127 | e++ 128 | x.Quo(x, bigIntTen) 129 | } 130 | return e 131 | } 132 | 133 | // inverse returns 1/i 134 | func (i BigInt) inverse() Value { 135 | if i.Sign() == 0 { 136 | Errorf("inverse of zero") 137 | } 138 | return BigRat{ 139 | Rat: big.NewRat(0, 1).SetFrac(bigIntOne.Int, i.Int), 140 | }.shrink() 141 | } 142 | 143 | func (i BigInt) Eval(Context) Value { 144 | return i 145 | } 146 | 147 | func (i BigInt) Inner() Value { 148 | return i 149 | } 150 | 151 | func (i BigInt) toType(op string, conf *config.Config, which valueType) Value { 152 | switch which { 153 | case bigIntType: 154 | return i 155 | case bigRatType: 156 | r := big.NewRat(0, 1).SetInt(i.Int) 157 | return BigRat{r} 158 | case bigFloatType: 159 | f := new(big.Float).SetPrec(conf.FloatPrec()).SetInt(i.Int) 160 | return BigFloat{f} 161 | case complexType: 162 | return NewComplex(i, zero) 163 | case vectorType: 164 | return oneElemVector(i) 165 | case matrixType: 166 | return NewMatrix([]int{1}, NewVector(i)) 167 | } 168 | Errorf("%s: cannot convert big int to %s", op, which) 169 | return nil 170 | } 171 | 172 | // trimEZeros takes an e or E format string and deletes 173 | // trailing zeros and maybe the decimal from the string. 174 | func trimEZeros(e byte, s string) string { 175 | eLoc := strings.IndexByte(s, e) 176 | if eLoc < 0 { 177 | return s 178 | } 179 | n := eLoc 180 | for s[n-1] == '0' { 181 | n-- 182 | } 183 | if s[n-1] == '.' { 184 | n-- 185 | } 186 | return s[:n] + s[eLoc:] 187 | } 188 | 189 | // shrink shrinks, if possible, a BigInt down to an Int. 190 | func (i BigInt) shrink() Value { 191 | if i.BitLen() < intBits { 192 | return Int(i.Int64()) 193 | } 194 | return i 195 | } 196 | 197 | func (i BigInt) BitLen() int64 { 198 | return int64(i.Int.BitLen()) 199 | } 200 | 201 | // mustFit errors out if n is larger than the maximum number of bits allowed. 202 | func mustFit(conf *config.Config, n int64) { 203 | max := conf.MaxBits() 204 | if max != 0 && n > int64(max) { 205 | Errorf("result too large (%d bits, max %d)", n, conf.MaxBits()) 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /testdata/statement.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Assignments, etc. 6 | 7 | x = 10 8 | x 9 | 10 10 | 11 | x = 10; x 12 | 10 13 | 14 | x = iota 10; x[2] = 100; x 15 | 1 100 3 4 5 6 7 8 9 10 16 | 17 | x = 'hello'; x[2]='☃'; x 18 | h☃llo 19 | 20 | x = 3 4 rho iota 1000; x[2] = 10*x[1]; x 21 | 1 2 3 4 22 | 10 20 30 40 23 | 9 10 11 12 24 | 25 | x = 3 4 5 rho iota 1000; x[2][3][4], x[2;3;4] 26 | 34 34 27 | 28 | x = 3 4 5 rho iota 1000; x[2; 3; 4] = 10*x[2; 3; 4]; x 29 | ┌ ┐ 30 | │ 1 2 3 4 5│ 31 | │ 6 7 8 9 10│ 32 | │ 11 12 13 14 15│ 33 | │ 16 17 18 19 20│ 34 | └ ┘ 35 | ┌ ┐ 36 | │ 21 22 23 24 25│ 37 | │ 26 27 28 29 30│ 38 | │ 31 32 33 340 35│ 39 | │ 36 37 38 39 40│ 40 | └ ┘ 41 | ┌ ┐ 42 | │ 41 42 43 44 45│ 43 | │ 46 47 48 49 50│ 44 | │ 51 52 53 54 55│ 45 | │ 56 57 58 59 60│ 46 | └ ┘ 47 | 48 | x = 3 4 5 rho iota 1000; x[2; 3] = 10*x[2; 3]; x 49 | ┌ ┐ 50 | │ 1 2 3 4 5│ 51 | │ 6 7 8 9 10│ 52 | │ 11 12 13 14 15│ 53 | │ 16 17 18 19 20│ 54 | └ ┘ 55 | ┌ ┐ 56 | │ 21 22 23 24 25│ 57 | │ 26 27 28 29 30│ 58 | │310 320 330 340 350│ 59 | │ 36 37 38 39 40│ 60 | └ ┘ 61 | ┌ ┐ 62 | │ 41 42 43 44 45│ 63 | │ 46 47 48 49 50│ 64 | │ 51 52 53 54 55│ 65 | │ 56 57 58 59 60│ 66 | └ ┘ 67 | 68 | x = 3 4 5 rho iota 1000; x[2] = 10*x[2]; x 69 | ┌ ┐ 70 | │ 1 2 3 4 5│ 71 | │ 6 7 8 9 10│ 72 | │ 11 12 13 14 15│ 73 | │ 16 17 18 19 20│ 74 | └ ┘ 75 | ┌ ┐ 76 | │210 220 230 240 250│ 77 | │260 270 280 290 300│ 78 | │310 320 330 340 350│ 79 | │360 370 380 390 400│ 80 | └ ┘ 81 | ┌ ┐ 82 | │ 41 42 43 44 45│ 83 | │ 46 47 48 49 50│ 84 | │ 51 52 53 54 55│ 85 | │ 56 57 58 59 60│ 86 | └ ┘ 87 | 88 | x = 3 4 5 rho iota 1000; x[2 3; 2 3 4; 1 2] = 0; x 89 | ┌ ┐ 90 | │ 1 2 3 4 5│ 91 | │ 6 7 8 9 10│ 92 | │11 12 13 14 15│ 93 | │16 17 18 19 20│ 94 | └ ┘ 95 | ┌ ┐ 96 | │21 22 23 24 25│ 97 | │ 0 0 28 29 30│ 98 | │ 0 0 33 34 35│ 99 | │ 0 0 38 39 40│ 100 | └ ┘ 101 | ┌ ┐ 102 | │41 42 43 44 45│ 103 | │ 0 0 48 49 50│ 104 | │ 0 0 53 54 55│ 105 | │ 0 0 58 59 60│ 106 | └ ┘ 107 | 108 | x = 4 4 rho iota 16; x[1 3; 2 4] = 2 2 rho -iota 4; x 109 | 1 -1 3 -2 110 | 5 6 7 8 111 | 9 -3 11 -4 112 | 13 14 15 16 113 | 114 | x = 4 4 rho iota 16; x[3 1; 2 4] = 2 2 rho -iota 4; x 115 | 1 -3 3 -4 116 | 5 6 7 8 117 | 9 -1 11 -2 118 | 13 14 15 16 119 | 120 | x = 4 4 rho iota 16; x[3 1; 4 2] = 2 2 rho -iota 4; x 121 | 1 -4 3 -3 122 | 5 6 7 8 123 | 9 -2 11 -1 124 | 13 14 15 16 125 | 126 | x = 5 5 rho iota 25; x[6 - iota 5; 6 - iota 5] = x; x 127 | 25 24 23 22 21 128 | 20 19 18 17 16 129 | 15 14 13 12 11 130 | 10 9 8 7 6 131 | 5 4 3 2 1 132 | 133 | x = 1 2 3; x[2] = 3 4 5; x 134 | 1 (3 4 5) 3 135 | 136 | # Test that assignment copies the data. 137 | x = 1 2 3; y = 4 5 6; x[2] = y; y[1] = 8; x 138 | 1 (4 5 6) 3 139 | 140 | # Test that assignment works with rationals, floats and big integers. 141 | x = 1 2 3; x[1] = 1/2; x[2] = float 0.5; x[3] = 10000000000; x 142 | 1/2 0.5 10000000000 143 | 144 | # Assignment is an expression. 145 | 1 + y = 100 146 | 101 147 | 148 | +/iota y = 10 149 | y 150 | 55 151 | 10 152 | 153 | 3 (x = 77); x 154 | 3 77 77 155 | 156 | 3 (x=4) rho iota 12; "\n"; x 157 | 1 2 3 4 158 | 5 6 7 8 159 | 9 10 11 12 160 | 4 161 | 162 | 'x' (y='y') 'z' 163 | xyz 164 | 165 | (x=7)/2 166 | 7/2 167 | 168 | (x = iota 3); x[2] = x[1]; x 169 | 1 1 3 170 | 171 | (x = iota 3); x[3] = (x[2] = x[1]); x 172 | 1 1 1 173 | 174 | # These odd assignments work in APL (Dyalog at least). 175 | zz = 1000; (zz=3) zz 176 | 3 1000 177 | 178 | zz = 1000; zz + zz = 2 179 | 4 180 | 181 | yy (yy=3) 182 | 3 3 183 | 184 | x = iota 3; x[1+2] = 4; x 185 | 1 2 4 186 | 187 | x = 4 4 rho 0; y = 4 4; x[y[1]; y[2]] = 3; x 188 | 0 0 0 0 189 | 0 0 0 0 190 | 0 0 0 0 191 | 0 0 0 3 192 | 193 | # Order of evaluation 194 | tags = 0 rho 0 195 | op f tag = 196 | tags = tags, tag 197 | 1 198 | 199 | op order x = 200 | x = tags 201 | tags = 0 rho 0 202 | x 203 | 204 | m = 1 1 rho 0 205 | order (f 1) + (f 2) 206 | order +/ (f 1) (f 2) 207 | order m[f 1; f 2] 208 | 2 1 209 | 2 1 210 | 2 1 211 | 212 | # Globals vs locals 213 | g = 1 214 | op f x = g = x+1; g 215 | f 10 216 | g 217 | 11 218 | 1 219 | 220 | g = 1 221 | op f x = g; g = x+1; g 222 | f 10 223 | g 224 | 11 225 | 11 226 | 227 | g = 1 228 | op f x = g = g+x; g 229 | f 100 230 | g 231 | 101 232 | 101 233 | 234 | # Assignment makes a copy. 235 | x = 1 2 3 4; y = x; y[1] = 7; x[1] y[1] 236 | 1 7 237 | 238 | x = 3 4 rho iota 12; y = x; y[1;1] = 7; +/+/x==y 239 | 11 240 | 241 | # Multiple and simultaneous assignment 242 | 243 | x y = 1 2; x y 244 | 1 2 245 | 246 | x y = 1,2; x y # 1,2 is an expression, not a vector until evaluated 247 | 1 2 248 | 249 | x y = (1 2) (3 4); x y 250 | (1 2) (3 4) 251 | 252 | z = 1 2 3; a b c = z; c b a 253 | 3 2 1 254 | 255 | x y = 'x' 'y'; x y = y x; x y 256 | yx 257 | 258 | x y = 'ab'; x y 259 | ab 260 | 261 | x y = z (z = 4); x y 262 | 4 4 263 | 264 | # Indexed values can appear in vectors; was parsing bug. 265 | 266 | x = 1 2 3 4; x[4] x[3] 7 x[1] 267 | 4 3 7 1 268 | 269 | x = 1 2 3 4; 3 4 rho x[2] x[3] 270 | 2 3 2 3 271 | 2 3 2 3 272 | 2 3 2 3 273 | -------------------------------------------------------------------------------- /run/run.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package run provides the execution control for ivy. 6 | // It is factored out of main so it can be used for tests. 7 | // This layout also helps out ivy/mobile. 8 | package run // import "robpike.io/ivy/run" 9 | 10 | import ( 11 | "bytes" 12 | "fmt" 13 | "io" 14 | "math/big" 15 | "strings" 16 | "time" 17 | 18 | "robpike.io/ivy/config" 19 | "robpike.io/ivy/parse" 20 | "robpike.io/ivy/scan" 21 | "robpike.io/ivy/value" 22 | ) 23 | 24 | func init() { 25 | value.IvyEval = IvyEval 26 | } 27 | 28 | // IvyEval is the function called by value/unaryIvy to implement the ivy (eval) operation. 29 | // It is exported but is not intended to be used outside of ivy. 30 | func IvyEval(context value.Context, str string) value.Value { 31 | scanner := scan.New(context, "", strings.NewReader(str)) 32 | parser := parse.NewParser("", scanner, context) 33 | v := eval(parser, context) 34 | if v == nil { 35 | v = value.NewIntVector() // Must return something, so make it an empty vector. 36 | } 37 | return v 38 | } 39 | 40 | // cpuTime reports user and system time. 41 | // It is replaced by system-specific files, like time_unix.go. 42 | var cpuTime = func() (user, sys time.Duration) { return 0, 0 } 43 | 44 | // Run runs the parser/evaluator until EOF or error. 45 | // The return value says whether we completed without error. If the return 46 | // value is true, it means we ran out of data (EOF) and the run was successful. 47 | // Typical execution is therefore to loop calling Run until it succeeds. 48 | // Error details are reported to the configured error output stream. 49 | func Run(p *parse.Parser, context value.Context, interactive bool) (success bool) { 50 | conf := context.Config() 51 | writer := conf.Output() 52 | defer func() { 53 | if conf.Debug("panic") > 0 { 54 | return 55 | } 56 | err := recover() 57 | if err == nil { 58 | return 59 | } 60 | _, ok := err.(value.Error) 61 | if !ok { 62 | _, ok = err.(big.ErrNaN) // Floating point error from math/big. 63 | } 64 | if ok { 65 | fmt.Fprintf(conf.ErrOutput(), "%s%s\n", p.Loc(), err) 66 | if interactive { 67 | fmt.Fprintln(writer) 68 | } 69 | success = false 70 | return 71 | } 72 | panic(err) 73 | }() 74 | for { 75 | if interactive { 76 | fmt.Fprint(writer, conf.Prompt()) 77 | } 78 | exprs, ok := p.Line() 79 | var values []value.Value 80 | if exprs != nil { 81 | start := time.Now() 82 | user, sys := cpuTime() 83 | values = context.Eval(exprs) 84 | user2, sys2 := cpuTime() 85 | conf.SetCPUTime(time.Since(start), user2-user, sys2-sys) 86 | } 87 | if printValues(conf, writer, values) { 88 | context.AssignGlobal("_", values[len(values)-1]) 89 | } 90 | if !ok { 91 | return true 92 | } 93 | if interactive { 94 | if exprs != nil && conf.Debug("cpu") > 0 { 95 | if real, _, _ := conf.CPUTime(); real != 0 { 96 | fmt.Printf("(%s)\n", conf.PrintCPUTime()) 97 | } 98 | } 99 | fmt.Fprintln(writer) 100 | } 101 | } 102 | } 103 | 104 | // eval runs until EOF or error. It prints every value but the last, and returns the last. 105 | // By last we mean the last expression of the last evaluation. 106 | // (Expressions are separated by ; in the input.) 107 | // It is always called from (somewhere below) run, so if it errors out the recover in 108 | // run will catch it. 109 | func eval(p *parse.Parser, context value.Context) value.Value { 110 | conf := context.Config() 111 | writer := conf.Output() 112 | var prevValues []value.Value 113 | for { 114 | exprs, ok := p.Line() 115 | var values []value.Value 116 | if exprs != nil { 117 | values = context.Eval(exprs) 118 | } 119 | if !ok { 120 | if len(prevValues) == 0 { 121 | return nil 122 | } 123 | printValues(conf, writer, prevValues[:len(prevValues)-1]) 124 | return prevValues[len(prevValues)-1] 125 | } 126 | printValues(conf, writer, prevValues) 127 | prevValues = values 128 | } 129 | } 130 | 131 | // printValues neatly prints the values returned from execution, followed by a newline. 132 | // It also handles the ')debug types' output. 133 | // The return value reports whether it printed anything. 134 | func printValues(conf *config.Config, writer io.Writer, values []value.Value) bool { 135 | if len(values) == 0 { 136 | return false 137 | } 138 | if conf.Debug("types") > 0 { 139 | for i, v := range values { 140 | if i > 0 { 141 | fmt.Fprint(writer, ",") 142 | } 143 | fmt.Fprintf(writer, "%T", v) 144 | } 145 | fmt.Fprintln(writer) 146 | } 147 | printed := false 148 | for _, v := range values { 149 | if _, ok := v.(value.QuietValue); ok { 150 | continue 151 | } 152 | s := v.Sprint(conf) 153 | if printed && len(s) > 0 && s[len(s)-1] != '\n' { 154 | fmt.Fprint(writer, " ") 155 | } 156 | fmt.Fprint(writer, s) 157 | printed = true 158 | } 159 | if printed { 160 | fmt.Fprintln(writer) 161 | } 162 | return printed 163 | } 164 | 165 | // Ivy evaluates the input string, appending standard output 166 | // and error output to the provided buffers, which it does by 167 | // calling context.Config.SetOutput and SetError. 168 | // If execution caused errors, they will be returned concatenated 169 | // together in the error value returned. 170 | func Ivy(context value.Context, expr string, stdout, stderr *bytes.Buffer) { 171 | if !strings.HasSuffix(expr, "\n") { 172 | expr += "\n" 173 | } 174 | reader := strings.NewReader(expr) 175 | 176 | scanner := scan.New(context, " ", reader) 177 | parser := parse.NewParser(" ", scanner, context) 178 | 179 | conf := context.Config() 180 | conf.SetOutput(stdout) 181 | conf.SetErrOutput(stderr) 182 | for !Run(parser, context, false) { 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /value/sin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "math/big" 9 | ) 10 | 11 | func sin(c Context, v Value) Value { 12 | if u, ok := v.(Complex); ok { 13 | if !isZero(u.imag) { 14 | return complexSin(c, u) 15 | } 16 | v = u.real 17 | } 18 | return evalFloatFunc(c, v, floatSin) 19 | } 20 | 21 | func cos(c Context, v Value) Value { 22 | if u, ok := v.(Complex); ok { 23 | if !isZero(u.imag) { 24 | return complexCos(c, u) 25 | } 26 | v = u.real 27 | } 28 | return evalFloatFunc(c, v, floatCos) 29 | } 30 | 31 | func tan(c Context, v Value) Value { 32 | if u, ok := v.(Complex); ok { 33 | if !isZero(u.imag) { 34 | return complexTan(c, u) 35 | } 36 | v = u.real 37 | } 38 | x := floatSelf(c, v).Float 39 | if x.IsInf() { 40 | Errorf("tangent of infinity") 41 | } 42 | negate := false 43 | if x.Sign() < 0 { 44 | x.Neg(x) 45 | negate = true 46 | } 47 | twoPiReduce(c, x) 48 | num := floatSin(c, x) 49 | den := floatCos(c, x) 50 | if den.Sign() == 0 { 51 | Errorf("tangent is infinite") 52 | } 53 | num.Quo(num, den) 54 | if negate { 55 | num.Neg(num) 56 | } 57 | return BigFloat{num}.shrink() 58 | } 59 | 60 | // floatSin computes sin(x) using argument reduction and a Taylor series. 61 | func floatSin(c Context, x *big.Float) *big.Float { 62 | if x.IsInf() { 63 | Errorf("sine of infinity") 64 | } 65 | negate := false 66 | if x.Sign() < 0 { 67 | x.Neg(x) 68 | negate = true 69 | } 70 | twoPiReduce(c, x) 71 | 72 | // sin(x) = x - x³/3! + x⁵/5! - ... 73 | // First term to compute in loop will be -x³/3! 74 | factorial := newFloat(c).SetInt64(6) 75 | 76 | result := sincos("sin", c, 3, x, newFloat(c).Set(x), 3, factorial) 77 | 78 | if negate { 79 | result.Neg(result) 80 | } 81 | 82 | return result 83 | } 84 | 85 | // floatCos computes cos(x) using argument reduction and a Taylor series. 86 | func floatCos(c Context, x *big.Float) *big.Float { 87 | if x.IsInf() { 88 | Errorf("cosine of infinity") 89 | } 90 | twoPiReduce(c, x) 91 | 92 | // cos(x) = 1 - x²/2! + x⁴/4! - ... 93 | // First term to compute in loop will be -x²/2!. 94 | factorial := newFloat(c).Set(floatTwo) 95 | 96 | return sincos("cos", c, 2, x, newFloat(c).SetInt64(1), 2, factorial) 97 | } 98 | 99 | // sincos iterates a sin or cos Taylor series. 100 | func sincos(name string, c Context, index int, x *big.Float, z *big.Float, exp uint64, factorial *big.Float) *big.Float { 101 | term := newFloat(c).Set(floatOne) 102 | for j := 0; j < index; j++ { 103 | term.Mul(term, x) 104 | } 105 | xN := newFloat(c).Set(term) 106 | x2 := newFloat(c).Mul(x, x) 107 | n := newFloat(c) 108 | 109 | for loop := newLoop(c.Config(), name, x, 4); ; { 110 | // Invariant: factorial holds -1ⁿ*exponent!. 111 | factorial.Neg(factorial) 112 | term.Quo(term, factorial) 113 | z.Add(z, term) 114 | 115 | if loop.done(z) { 116 | break 117 | } 118 | // Advance x**index (multiply by x²). 119 | term.Mul(xN, x2) 120 | xN.Set(term) 121 | // Advance factorial. 122 | factorial.Mul(factorial, n.SetUint64(exp+1)) 123 | factorial.Mul(factorial, n.SetUint64(exp+2)) 124 | exp += 2 125 | } 126 | return z 127 | } 128 | 129 | // twoPiReduce guarantees x < 2π; x is known to be >= 0 coming in. 130 | func twoPiReduce(c Context, x *big.Float) { 131 | // TODO: Is there an easy better algorithm? 132 | twoPi := newFloat(c).Set(floatTwo) 133 | twoPi.Mul(twoPi, floatPi) 134 | // Do something clever(er) if it's large. 135 | if x.Cmp(newFloat(c).SetInt64(1000)) > 0 { 136 | multiples := make([]*big.Float, 0, 100) 137 | sixteen := newFloat(c).SetInt64(16) 138 | multiple := newFloat(c).Set(twoPi) 139 | for { 140 | multiple.Mul(multiple, sixteen) 141 | if x.Cmp(multiple) < 0 { 142 | break 143 | } 144 | multiples = append(multiples, newFloat(c).Set(multiple)) 145 | } 146 | // From the right, subtract big multiples. 147 | for i := len(multiples) - 1; i >= 0; i-- { 148 | multiple := multiples[i] 149 | for x.Cmp(multiple) >= 0 { 150 | x.Sub(x, multiple) 151 | } 152 | } 153 | } 154 | for x.Cmp(twoPi) >= 0 { 155 | x.Sub(x, twoPi) 156 | } 157 | } 158 | 159 | func complexSin(c Context, v Complex) Value { 160 | // Use the formula: sin(x+yi) = sin(x)cosh(y) + i cos(x)sinh(y) 161 | x := floatSelf(c, v.real).Float 162 | y := floatSelf(c, v.imag).Float 163 | sinX := floatSin(c, x) 164 | coshY := floatCosh(c, y) 165 | cosX := floatCos(c, x) 166 | sinhY := floatSinh(c, y) 167 | lhs := sinX.Mul(sinX, coshY) 168 | rhs := cosX.Mul(cosX, sinhY) 169 | return NewComplex(BigFloat{lhs}, BigFloat{rhs}).shrink() 170 | } 171 | 172 | func complexCos(c Context, v Complex) Value { 173 | // Use the formula: cos(x+yi) = cos(x)cosh(y) + i sin(x)sinh(y) 174 | x := floatSelf(c, v.real).Float 175 | y := floatSelf(c, v.imag).Float 176 | cosX := floatCos(c, x) 177 | coshY := floatCosh(c, y) 178 | sinX := floatSin(c, x) 179 | sinhY := floatSinh(c, y) 180 | lhs := cosX.Mul(cosX, coshY) 181 | rhs := sinX.Mul(sinX, sinhY) 182 | return NewComplex(BigFloat{lhs}, BigFloat{rhs.Neg(rhs)}).shrink() 183 | } 184 | 185 | func complexTan(c Context, v Complex) Value { 186 | // Use the formula: tan(x+yi) = (sin(2x) + i sinh (2y))/(cos(2x) + cosh(2y)) 187 | x := floatSelf(c, v.real).Float 188 | y := floatSelf(c, v.imag).Float 189 | // Double them - all the arguments are 2X. 190 | x.Mul(x, floatTwo) 191 | y.Mul(y, floatTwo) 192 | sin2X := floatSin(c, x) 193 | sinh2Y := floatSinh(c, y) 194 | cos2X := floatCos(c, x) 195 | cosh2Y := floatCosh(c, y) 196 | den := cos2X.Add(cos2X, cosh2Y) 197 | if den.Sign() == 0 { 198 | Errorf("tangent is infinite") 199 | } 200 | return NewComplex(BigFloat{sin2X.Quo(sin2X, den)}, BigFloat{sinh2Y.Quo(sinh2Y, den)}).shrink() 201 | } 202 | -------------------------------------------------------------------------------- /value/expr.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // Expr is the interface for a parsed expression. 15 | // Also implemented by Value. 16 | type Expr interface { 17 | // ProgString returns the unambiguous representation of the 18 | // expression to be used in program source. 19 | ProgString() string 20 | 21 | Eval(Context) Value 22 | } 23 | 24 | type UnaryExpr struct { 25 | Op string 26 | Right Expr 27 | } 28 | 29 | func (u *UnaryExpr) ProgString() string { 30 | return fmt.Sprintf("%s %s", u.Op, u.Right.ProgString()) 31 | } 32 | 33 | func (u *UnaryExpr) Eval(context Context) Value { 34 | return context.EvalUnary(u.Op, u.Right.Eval(context).Inner()) 35 | } 36 | 37 | type BinaryExpr struct { 38 | Op string 39 | Left Expr 40 | Right Expr 41 | } 42 | 43 | func (b *BinaryExpr) ProgString() string { 44 | var left string 45 | if IsCompound(b.Left) { 46 | left = fmt.Sprintf("(%s)", b.Left.ProgString()) 47 | } else { 48 | left = b.Left.ProgString() 49 | } 50 | return fmt.Sprintf("%s %s %s", left, b.Op, b.Right.ProgString()) 51 | } 52 | 53 | func (b *BinaryExpr) Eval(context Context) Value { 54 | if b.Op == "=" { 55 | return assign(context, b) 56 | } 57 | rhs := b.Right.Eval(context).Inner() 58 | lhs := b.Left.Eval(context) 59 | return context.EvalBinary(lhs, b.Op, rhs) 60 | } 61 | 62 | // CondExpr is a CondExpr executor: expression ":" expression 63 | type CondExpr struct { 64 | Cond *BinaryExpr 65 | } 66 | 67 | func (c *CondExpr) ProgString() string { return c.Cond.ProgString() } 68 | func (c *CondExpr) Eval(context Context) Value { return c.Cond.Eval(context) } 69 | 70 | var _ = Decomposable(&CondExpr{}) 71 | 72 | func (c *CondExpr) Operator() string { 73 | return ":" 74 | } 75 | 76 | func (c *CondExpr) Operands() (left, right Expr) { 77 | return c.Cond.Left, c.Cond.Right 78 | } 79 | 80 | // VectorExpr holds a syntactic vector to be verified and evaluated. 81 | type VectorExpr []Expr 82 | 83 | func (e VectorExpr) Eval(context Context) Value { 84 | v := newVectorEditor(len(e), nil) 85 | // Evaluate right to left, as is the usual rule. 86 | // This also means things like 87 | // x=1000; x + x=2 88 | // (yielding 4) work. 89 | for i := len(e) - 1; i >= 0; i-- { 90 | v.Set(i, e[i].Eval(context)) 91 | } 92 | return v.Publish() 93 | } 94 | 95 | var charEscape = map[rune]string{ 96 | '\\': "\\\\", 97 | '\'': "\\'", 98 | '\a': "\\a", 99 | '\b': "\\b", 100 | '\f': "\\f", 101 | '\n': "\\n", 102 | '\r': "\\r", 103 | '\t': "\\t", 104 | '\v': "\\v", 105 | } 106 | 107 | func (e VectorExpr) ProgString() string { 108 | var b bytes.Buffer 109 | // If it's all Char, we can do a prettier job. 110 | if e.allChars() { 111 | b.WriteRune('\'') 112 | for _, v := range e { 113 | c := rune(v.(Char)) 114 | esc := charEscape[c] 115 | if esc != "" { 116 | b.WriteString(esc) 117 | continue 118 | } 119 | if !strconv.IsPrint(c) { 120 | if c <= 0xFFFF { 121 | fmt.Fprintf(&b, "\\u%04x", c) 122 | } else { 123 | fmt.Fprintf(&b, "\\U%08x", c) 124 | } 125 | continue 126 | } 127 | b.WriteRune(c) 128 | } 129 | b.WriteRune('\'') 130 | } else { 131 | for i, v := range e { 132 | if i > 0 { 133 | b.WriteRune(' ') 134 | } 135 | if IsCompound(v) { 136 | b.WriteString("(" + v.ProgString() + ")") 137 | } else { 138 | b.WriteString(v.ProgString()) 139 | } 140 | } 141 | } 142 | return b.String() 143 | } 144 | 145 | func (e VectorExpr) allChars() bool { 146 | for _, c := range e { 147 | if _, ok := c.(Char); !ok { 148 | return false 149 | } 150 | } 151 | return true 152 | } 153 | 154 | type IndexExpr struct { 155 | Op string 156 | Left Expr 157 | Right []Expr 158 | } 159 | 160 | func (x *IndexExpr) ProgString() string { 161 | var s strings.Builder 162 | if IsCompound(x.Left) { 163 | s.WriteString("(") 164 | s.WriteString(x.Left.ProgString()) 165 | s.WriteString(")") 166 | } else { 167 | s.WriteString(x.Left.ProgString()) 168 | } 169 | s.WriteString("[") 170 | for i, v := range x.Right { 171 | if i > 0 { 172 | s.WriteString("; ") 173 | } 174 | if v != nil { 175 | s.WriteString(v.ProgString()) 176 | } 177 | } 178 | s.WriteString("]") 179 | return s.String() 180 | } 181 | 182 | func (x *IndexExpr) Eval(context Context) Value { 183 | return Index(context, x, x.Left, x.Right) 184 | } 185 | 186 | // VarExpr identifies a variable to be looked up and evaluated. 187 | type VarExpr struct { 188 | Name string 189 | Local int // local index, or 0 for global 190 | } 191 | 192 | func NewVarExpr(name string) *VarExpr { 193 | return &VarExpr{Name: name} 194 | } 195 | 196 | func (e *VarExpr) Eval(context Context) Value { 197 | var v Value 198 | if e.Local >= 1 { 199 | v = context.Local(e.Local).Value() 200 | } else { 201 | if g := context.Global(e.Name); g != nil { 202 | v = g.Value() 203 | } 204 | } 205 | if v == nil { 206 | kind := "global" 207 | if e.Local >= 1 { 208 | kind = "local" 209 | } 210 | Errorf("undefined %s variable %q", kind, e.Name) 211 | } 212 | return v 213 | } 214 | 215 | func (e *VarExpr) ProgString() string { 216 | return e.Name 217 | } 218 | 219 | // IsCompound reports whether the item is a non-trivial expression tree, one that 220 | // may require parentheses around it when printed to maintain correct evaluation order. 221 | func IsCompound(x interface{}) bool { 222 | switch x := x.(type) { 223 | case Char, Int, BigInt, BigRat, BigFloat, Complex, *Vector, *Matrix: 224 | return false 225 | case *VarExpr: 226 | return false 227 | case VectorExpr: 228 | return true 229 | case *IndexExpr: 230 | return IsCompound(x.Left) 231 | default: 232 | return true 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /parse/helpgen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build ignore 6 | // +build ignore 7 | 8 | package main 9 | 10 | import ( 11 | "bytes" 12 | "fmt" 13 | "go/format" 14 | "io/ioutil" 15 | "log" 16 | "os" 17 | "strings" 18 | ) 19 | 20 | func main() { 21 | text, err := ioutil.ReadFile("../doc.go") 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | lines := strings.Split(string(text), "\n") 26 | 27 | // Drop text up to and including opening comment. 28 | for i, line := range lines { 29 | if strings.HasPrefix(line, "/*") { 30 | lines = lines[i+1:] 31 | break 32 | } 33 | } 34 | 35 | // Drop leading blank line(s). 36 | for lines[0] == "" { 37 | lines = lines[1:] 38 | } 39 | 40 | // Drop text starting with trailing comment. 41 | for i, line := range lines { 42 | if strings.HasPrefix(line, "*/") { 43 | lines = lines[:i] 44 | break 45 | } 46 | } 47 | 48 | // Drop trailing blank line(s). 49 | for lines[len(lines)-1] == "" { 50 | lines = lines[:len(lines)-1] 51 | } 52 | 53 | buf := new(bytes.Buffer) 54 | s := func(s string) { 55 | buf.WriteString(s) 56 | buf.WriteByte('\n') 57 | } 58 | 59 | s(`// Code generated by "go generate robpike.io/ivy/parse"; DO NOT EDIT.`) 60 | s("") 61 | s("package parse") 62 | s("") 63 | s("var helpLines = []string{") 64 | for _, line := range lines { 65 | fmt.Fprintf(buf, "%q,\n", line) 66 | } 67 | s("}") 68 | 69 | s("") 70 | s("type helpIndexPair struct {") 71 | s(" start, end int") 72 | s("}") 73 | s("") 74 | 75 | // Pull out text for all the ops. 76 | // We know the field widths in runes. 77 | // Roll ?B ? One integer selected randomly from the first B integers 78 | 79 | s("var helpUnary = map[string]helpIndexPair{") 80 | moreLines := func(i int) int { 81 | j := i 82 | // If the next few lines have no text at the left, they are a continuation. Pull them in. 83 | for ; j < len(lines); j++ { 84 | next := lines[j+1] 85 | if len(next) < 33 || next[1] != ' ' { 86 | break 87 | } 88 | } 89 | return j 90 | } 91 | var i int 92 | for i = 0; lines[i] != "Unary operators"; i++ { 93 | } 94 | for i++; i < len(lines); i++ { 95 | line := lines[i] 96 | if line == "Binary operators" { 97 | break 98 | } 99 | if len(line) < 33 { 100 | continue 101 | } 102 | if strings.Contains(line, "Name") && strings.Contains(line, "Meaning") { // It's a header. 103 | continue 104 | } 105 | // Find the op. 106 | runes := []rune(line) 107 | op := runes[25:] 108 | for i := 0; i < len(op); i++ { 109 | if op[i] == ' ' { 110 | op = op[:i] 111 | break 112 | } 113 | } 114 | if len(op) == 0 { 115 | continue 116 | } 117 | j := moreLines(i) 118 | fmt.Fprintf(buf, `%q: {%d, %d},`+"\n", string(op), i, j) 119 | i = j 120 | } 121 | 122 | // Text-converters are all unary but float is multi-line. 123 | for i = 0; lines[i] != "Type-converting operations"; i++ { 124 | } 125 | for i++; i < len(lines); i++ { 126 | line := lines[i] 127 | if line == "# Pre-defined constants" { 128 | break 129 | } 130 | if len(line) < 33 { 131 | continue 132 | } 133 | if strings.Contains(line, "Name") && strings.Contains(line, "Meaning") { // It's a header. 134 | continue 135 | } 136 | // Find the op. 137 | runes := []rune(line) 138 | op := runes[25:] 139 | for i := 0; i < len(op); i++ { 140 | if op[i] == ' ' { 141 | op = op[:i] 142 | break 143 | } 144 | } 145 | j := moreLines(i) 146 | fmt.Fprintf(buf, `%q: {%d, %d},`+"\n", string(op), i, j) 147 | i = j 148 | } 149 | 150 | s("}") 151 | s("") 152 | 153 | s("var helpBinary = map[string]helpIndexPair{") 154 | for i = 0; lines[i] != "Binary operators"; i++ { 155 | } 156 | for i++; i < len(lines); i++ { 157 | line := lines[i] 158 | if line == "Operators and axis indicator" { 159 | break 160 | } 161 | if len(line) < 33 { 162 | continue 163 | } 164 | if strings.Contains(line, "Name") && strings.Contains(line, "Meaning") { // It's a header. 165 | continue 166 | } 167 | // Find the op. 168 | runes := []rune(line) 169 | op := runes[29:] 170 | for i := 0; i < len(op); i++ { 171 | if op[i] == ' ' { 172 | op = op[:i] 173 | break 174 | } 175 | } 176 | if len(op) == 0 { 177 | continue 178 | } 179 | // Circles are unary. 180 | str := string(op) 181 | switch str { 182 | case "sin", "cos", "tan": 183 | continue 184 | } 185 | j := i 186 | // If the next few lines have no text at the left, they are a continuation. Pull them in. 187 | for ; j < len(lines); j++ { 188 | next := lines[j+1] 189 | if len(next) < 37 || next[1] != ' ' { 190 | break 191 | } 192 | } 193 | fmt.Fprintf(buf, `%q: {%d, %d},`+"\n", string(op), i, j) 194 | i = j 195 | } 196 | s("}") 197 | s("") 198 | 199 | for i = 0; lines[i] != "Operators and axis indicator"; i++ { 200 | } 201 | s("var helpAxis = map[string]helpIndexPair{") 202 | for i++; i < len(lines); i++ { 203 | line := lines[i] 204 | if line == "Type-converting operations" { 205 | break 206 | } 207 | if len(line) < 33 { 208 | continue 209 | } 210 | if strings.Contains(line, "Name") && strings.Contains(line, "Meaning") { // It's a header. 211 | continue 212 | } 213 | // Find the op. 214 | runes := []rune(line) 215 | op := runes[26:] 216 | for i := 0; i < len(op); i++ { 217 | if op[i] == ' ' { 218 | op = op[:i] 219 | break 220 | } 221 | } 222 | if len(op) == 0 { 223 | continue 224 | } 225 | fmt.Fprintf(buf, `%q: {%d, %d},`+"\n", string(op), i, i) 226 | } 227 | s("}") 228 | 229 | var formatted []byte 230 | if true { 231 | formatted, err = format.Source(buf.Bytes()) 232 | if err != nil { 233 | log.Fatal(err) 234 | } 235 | } else { 236 | formatted = buf.Bytes() 237 | } 238 | 239 | fd, err := os.Create("help.go") 240 | if err != nil { 241 | log.Fatal(err) 242 | } 243 | _, err = fd.Write(formatted) 244 | if err != nil { 245 | log.Fatal("help.go") 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /testdata/binary_int.ivy: -------------------------------------------------------------------------------- 1 | # Copyright 2014 The Go Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | # Binary operations with ints on the left. 6 | # Each operation is listed with: 7 | # 8 | # 9 | # int + int 10 | # int + bigint 11 | # int + bigrat 12 | # int + vector 13 | # int + matrix 14 | # 15 | # Ops: 16 | # 17 | # + 18 | # - 19 | # * 20 | # / 21 | # idiv 22 | # imod 23 | # div 24 | # mod 25 | # ** 26 | # ! 27 | # & 28 | # | 29 | # ^ 30 | # << 31 | # >> 32 | # == 33 | # != 34 | # < 35 | # <= 36 | # > 37 | # >= 38 | # ? 39 | # [] (Not implemented for int) 40 | # and 41 | # or 42 | # xor 43 | # nand 44 | # nor 45 | # iota 46 | # min 47 | # max 48 | # rho 49 | # , 50 | 51 | 2+5 52 | 7 53 | 54 | 2+1e10 55 | 10000000002 56 | 57 | 2+1/3 58 | 7/3 59 | 60 | 2+iota 3 61 | 3 4 5 62 | 63 | 2+2 3 rho iota 10 64 | 3 4 5 65 | 6 7 8 66 | 67 | 2-5 68 | -3 69 | 70 | 2-1e10 71 | -9999999998 72 | 73 | 2-1/3 74 | 5/3 75 | 76 | 2-iota 3 77 | 1 0 -1 78 | 79 | 2-2 3 rho iota 10 80 | 1 0 -1 81 | -2 -3 -4 82 | 83 | 2*5 84 | 10 85 | 86 | 2*1e10 87 | 20000000000 88 | 89 | 2*1/3 90 | 2/3 91 | 92 | 2*iota 3 93 | 2 4 6 94 | 95 | 2*2 3 rho iota 10 96 | 2 4 6 97 | 8 10 12 98 | 99 | 2 / 5 100 | 2/5 101 | 102 | 2 / 1e10 103 | 1/5000000000 104 | 105 | 2 / 1/3 106 | 6 107 | 108 | 2 / iota 3 109 | 2 1 2/3 110 | 111 | 2 / 2 3 rho iota 10 112 | 2 1 2/3 113 | 1/2 2/5 1/3 114 | 115 | 23 div 4 116 | 5 117 | 118 | -23 div 4 119 | -6 120 | 121 | 23 div 4 122 | 5 123 | 124 | -23 idiv 4 125 | -5 126 | 127 | 3 mod 4 128 | 3 129 | 130 | -3 mod 4 131 | 1 132 | 133 | 3 mod 4 134 | 3 135 | 136 | -3 imod 4 137 | -3 138 | 139 | 2 idiv 5 140 | 0 141 | 142 | 2 idiv 1e10 143 | 0 144 | 145 | 2 idiv iota 3 146 | 2 1 0 147 | 148 | 2 idiv 2 3 rho iota 10 149 | 2 1 0 150 | 0 0 0 151 | 152 | 2 imod 5 153 | 2 154 | 155 | 2 imod 1e10 156 | 2 157 | 158 | 2 imod iota 3 159 | 0 0 2 160 | 161 | 2 imod 2 3 rho iota 10 162 | 0 0 2 163 | 2 2 2 164 | 165 | 2 ** 5 166 | 32 167 | 168 | 2 ** -5 169 | 1/32 170 | 171 | 1 ** 1e10 172 | 1 173 | 174 | 2 ** iota 3 175 | 2 4 8 176 | 177 | 2 ** 2 3 rho iota 10 178 | 2 4 8 179 | 16 32 64 180 | 181 | 0!0 182 | 1 183 | 184 | 1!0 185 | 1 186 | 187 | -1!0 188 | 1 189 | 190 | 1e6!1e6 191 | 1 192 | 193 | 10!15 194 | 3003 195 | 196 | 15!10 197 | 0 198 | 199 | 10 11 12 ! 15 16 17 200 | 3003 4368 6188 201 | 202 | 2 & 7 203 | 2 204 | 205 | 2 & 2+1e10 206 | 2 207 | 208 | 2 & iota 3 209 | 0 2 2 210 | 211 | 2 & 2 3 rho iota 10 212 | 0 2 2 213 | 0 0 2 214 | 215 | 2 | 7 216 | 7 217 | 218 | 2 | 2+1e10 219 | 10000000002 220 | 221 | 2 | iota 3 222 | 3 2 3 223 | 224 | 2 | 2 3 rho iota 10 225 | 3 2 3 226 | 6 7 6 227 | 228 | 2 ^ 7 229 | 5 230 | 231 | 2 ^ 2+1e10 232 | 10000000000 233 | 234 | 2 ^ iota 3 235 | 3 0 1 236 | 237 | 2 ^ 2 3 rho iota 10 238 | 3 0 1 239 | 6 7 4 240 | 241 | 2 << 5 242 | 64 243 | 244 | 2 << iota 3 245 | 4 8 16 246 | 247 | 2 << 2 3 rho iota 10 248 | 4 8 16 249 | 32 64 128 250 | 251 | 222 >> 5 252 | 6 253 | 254 | 222 >> iota 3 255 | 111 55 27 256 | 257 | 222 >> 2 3 rho iota 10 258 | 111 55 27 259 | 13 6 3 260 | 261 | 2 == 5 262 | 0 263 | 264 | 2 === 2; 2 !== 2 265 | 1 0 266 | 267 | 2 === 5; 2 !== 5 268 | 0 1 269 | 270 | 2 == 1e10 271 | 0 272 | 273 | 2 == 1/3 274 | 0 275 | 276 | 2 == iota 3 277 | 0 1 0 278 | 279 | 2 == 2 3 rho iota 10 280 | 0 1 0 281 | 0 0 0 282 | 283 | 2 != 5 284 | 1 285 | 286 | 2 != 1e10 287 | 1 288 | 289 | 2 != 1/3 290 | 1 291 | 292 | 2 != iota 3 293 | 1 0 1 294 | 295 | 2 != 2 3 rho iota 10 296 | 1 0 1 297 | 1 1 1 298 | 299 | 2 < 5 300 | 1 301 | 302 | 2 < 1e10 303 | 1 304 | 305 | 2 < 1/3 306 | 0 307 | 308 | 2 < iota 3 309 | 0 0 1 310 | 311 | 2 < 2 3 rho iota 10 312 | 0 0 1 313 | 1 1 1 314 | 315 | 2 <= 5 316 | 1 317 | 318 | 2 <= 1e10 319 | 1 320 | 321 | 2 <= 1/3 322 | 0 323 | 324 | 2 <= iota 3 325 | 0 1 1 326 | 327 | 2 <= 2 3 rho iota 10 328 | 0 1 1 329 | 1 1 1 330 | 331 | 2 > 5 332 | 0 333 | 334 | 2 > 1e10 335 | 0 336 | 337 | 2 > 1/3 338 | 1 339 | 340 | 2 > iota 3 341 | 1 0 0 342 | 343 | 2 > 2 3 rho iota 10 344 | 1 0 0 345 | 0 0 0 346 | 347 | 2 >= 5 348 | 0 349 | 350 | 2 >= 1e10 351 | 0 352 | 353 | 2 >= 1/3 354 | 1 355 | 356 | 2 >= iota 3 357 | 1 1 0 358 | 359 | 2 >= 2 3 rho iota 10 360 | 1 1 0 361 | 0 0 0 362 | 363 | 2 and 5 364 | 1 365 | 366 | 2 and 1e10 367 | 1 368 | 369 | 2 and 1/3 370 | 1 371 | 372 | 2 and -1 + iota 3 373 | 0 1 1 374 | 375 | 2 and -2 + 2 3 rho iota 10 376 | 1 0 1 377 | 1 1 1 378 | 379 | 2 or 5 380 | 1 381 | 382 | 2 or 1e10 383 | 1 384 | 385 | 2 or 1/3 386 | 1 387 | 388 | 2 or -2 + iota 3 389 | 1 1 1 390 | 391 | 0 or -2 + iota 3 392 | 1 0 1 393 | 394 | 2 or -2 + 2 3 rho iota 10 395 | 1 1 1 396 | 1 1 1 397 | 398 | 0 or -2 + 2 3 rho iota 10 399 | 1 0 1 400 | 1 1 1 401 | 402 | 2 xor 3 403 | 0 404 | 405 | 2 xor 1e10 406 | 0 407 | 408 | 1 xor 1/3 409 | 0 410 | 411 | 1 xor -2 + iota 3 412 | 0 1 0 413 | 414 | 1 xor -2+ 2 3 rho iota 10 415 | 0 1 0 416 | 0 0 0 417 | 418 | 0 nand 0 419 | 1 420 | 421 | 0 nand 1 422 | 1 423 | 424 | 1 nand 0 425 | 1 426 | 427 | 1 nand 1 428 | 0 429 | 430 | 2 nand 1e10 431 | 0 432 | 433 | 1 nand 1/3 434 | 0 435 | 436 | 1 nand -2 + iota 3 437 | 0 1 0 438 | 439 | 1 nand -2+ 2 3 rho iota 10 440 | 0 1 0 441 | 0 0 0 442 | 443 | 0 nor 0 444 | 1 445 | 446 | 0 nor 1 447 | 0 448 | 449 | 1 nor 0 450 | 0 451 | 452 | 1 nor 1 453 | 0 454 | 455 | 2 nor 1e10 456 | 0 457 | 458 | 1 nor 1/3 459 | 0 460 | 461 | 0 nor -2 + iota 3 462 | 0 1 0 463 | 464 | 0 nor -2+ 2 3 rho iota 10 465 | 0 1 0 466 | 0 0 0 467 | 468 | 2 iota 1 2 3 469 | 0 1 0 470 | 471 | )origin 0 472 | 2 iota 1 2 3 473 | -1 0 -1 474 | 475 | 2 min 5 476 | 2 477 | 478 | 2 min 1e10 479 | 2 480 | 481 | 2 min 1/3 482 | 1/3 483 | 484 | 2 min iota 3 485 | 1 2 2 486 | 487 | 2 min 2 3 rho iota 10 488 | 1 2 2 489 | 2 2 2 490 | 491 | 2 max 5 492 | 5 493 | 494 | 2 max 1e10 495 | 10000000000 496 | 497 | 2 max 1/3 498 | 2 499 | 500 | 2 max iota 3 501 | 2 2 3 502 | 503 | 2 max 2 3 rho iota 10 504 | 2 2 3 505 | 4 5 6 506 | 507 | 2 rho 5 508 | 5 5 509 | 510 | 2 rho 1e10 511 | 10000000000 10000000000 512 | 513 | 2 rho iota 3 514 | 1 2 515 | 516 | 2 rho 2 3 rho iota 10 517 | 1 2 518 | 519 | )seed 0 520 | 5?10 521 | 5 1 3 10 2 522 | 523 | 2 , 5 524 | 2 5 525 | 526 | 2 , 1e10 527 | 2 10000000000 528 | 529 | 2 , 1/3 530 | 2 1/3 531 | 532 | 2 , iota 3 533 | 2 1 2 3 534 | -------------------------------------------------------------------------------- /value/complex.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "fmt" 9 | 10 | "robpike.io/ivy/config" 11 | ) 12 | 13 | type Complex struct { 14 | real Value 15 | imag Value 16 | } 17 | 18 | func NewComplex(u, v Value) Complex { 19 | if !simpleNumber(u) || !simpleNumber(v) { 20 | Errorf("bad complex construction: %v %v", u, v) 21 | } 22 | return Complex{u, v} 23 | } 24 | 25 | func (c Complex) Components() (Value, Value) { 26 | return c.real, c.imag 27 | } 28 | 29 | func simpleNumber(v Value) bool { 30 | switch v.(type) { 31 | case Int, BigInt, BigRat, BigFloat: 32 | return true 33 | } 34 | return false 35 | } 36 | 37 | func (c Complex) String() string { 38 | return "(" + c.Sprint(debugConf) + ")" 39 | } 40 | 41 | func (c Complex) Rank() int { 42 | return 0 43 | } 44 | 45 | func (c Complex) Sprint(conf *config.Config) string { 46 | return fmt.Sprintf("%sj%s", c.real.Sprint(conf), c.imag.Sprint(conf)) 47 | } 48 | 49 | func (c Complex) ProgString() string { 50 | return fmt.Sprintf("%sj%s", c.real, c.imag) 51 | } 52 | 53 | func (c Complex) Eval(Context) Value { 54 | return c 55 | } 56 | 57 | func (c Complex) Inner() Value { 58 | return c 59 | } 60 | 61 | // Signum returns: 62 | // 63 | // 0j0 if c == 0 64 | // c/abs c if c != 0 65 | func (c Complex) Signum(ctx Context) Complex { 66 | if isZero(c) { 67 | return c 68 | } 69 | return c.div(ctx, NewComplex(c.abs(ctx), zero)) 70 | } 71 | 72 | func (c Complex) toType(op string, conf *config.Config, which valueType) Value { 73 | switch which { 74 | case complexType: 75 | return c 76 | case vectorType: 77 | return oneElemVector(c) 78 | case matrixType: 79 | return NewMatrix([]int{1, 1}, NewVector(c)) 80 | } 81 | Errorf("%s: cannot convert complex to %s", op, which) 82 | return nil 83 | } 84 | 85 | func (c Complex) isReal() bool { 86 | return isZero(c.imag) 87 | } 88 | 89 | // shrink pulls, if possible, a Complex down to a scalar. 90 | // It also shrinks its components. 91 | func (c Complex) shrink() Value { 92 | sc := Complex{ 93 | c.real.shrink(), 94 | c.imag.shrink(), 95 | } 96 | if sc.isReal() { 97 | return sc.real 98 | } 99 | return sc 100 | } 101 | 102 | // Arithmetic. 103 | 104 | func (c Complex) neg(ctx Context) Complex { 105 | return NewComplex(ctx.EvalUnary("-", c.real), ctx.EvalUnary("-", c.imag)) 106 | } 107 | 108 | func (c Complex) inverse(ctx Context) Complex { 109 | if isZero(c.real) && isZero(c.imag) { 110 | Errorf("complex inverse of zero") 111 | } 112 | denom := ctx.EvalBinary(ctx.EvalBinary(c.real, "*", c.real), "+", ctx.EvalBinary(c.imag, "*", c.imag)) 113 | r := ctx.EvalBinary(c.real, "/", denom) 114 | i := ctx.EvalUnary("-", ctx.EvalBinary(c.imag, "/", denom)) 115 | return NewComplex(r, i) 116 | } 117 | 118 | func (c Complex) abs(ctx Context) Value { 119 | mag := ctx.EvalBinary(ctx.EvalBinary(c.real, "*", c.real), "+", ctx.EvalBinary(c.imag, "*", c.imag)) 120 | return sqrt(ctx, mag) 121 | } 122 | 123 | // phase returns the phase of the complex number in the range -π to π. 124 | func (c Complex) phase(ctx Context) Value { 125 | // We would use atan2 if we had it. Maybe we should. 126 | // This is fiddlier than you might suspect. 127 | if isZero(c.imag) { 128 | return realPhase(ctx, c.real) 129 | } 130 | rPos := !isNegative(c.real) 131 | rZero := isZero(c.real) 132 | iPos := !isNegative(c.imag) 133 | if rZero { 134 | if iPos { 135 | return BigFloat{floatPiBy2} 136 | } 137 | return BigFloat{floatMinusPiBy2} 138 | } 139 | atan := atan(ctx, ctx.EvalBinary(c.imag, "/", c.real)) 140 | // Correct the quadrants. We lose sign information in the division. 141 | // We want the range to be -π to π. The comments state 142 | // the value of atan from above, at 45° within the quadrant. 143 | switch { 144 | case rPos && iPos: // Upper right, π/4, OK. 145 | case rPos && !iPos: // Lower right, -π/4, OK. 146 | case !rPos && !iPos: // Lower left, π/4, subtract π. 147 | atan = ctx.EvalBinary(atan, "-", BigFloat{newFloat(ctx).Set(floatPi)}) 148 | case !rPos && iPos: // Upper left, -π/4, add π. 149 | atan = ctx.EvalBinary(atan, "+", BigFloat{newFloat(ctx).Set(floatPi)}) 150 | } 151 | return atan 152 | } 153 | 154 | func (c Complex) add(ctx Context, d Complex) Complex { 155 | return NewComplex(ctx.EvalBinary(c.real, "+", d.real), ctx.EvalBinary(c.imag, "+", d.imag)) 156 | } 157 | 158 | func (c Complex) sub(ctx Context, d Complex) Complex { 159 | return NewComplex(ctx.EvalBinary(c.real, "-", d.real), ctx.EvalBinary(c.imag, "-", d.imag)) 160 | } 161 | 162 | func (c Complex) mul(ctx Context, d Complex) Complex { 163 | r := ctx.EvalBinary(ctx.EvalBinary(c.real, "*", d.real), "-", ctx.EvalBinary(c.imag, "*", d.imag)) 164 | i := ctx.EvalBinary(ctx.EvalBinary(d.imag, "*", c.real), "+", ctx.EvalBinary(d.real, "*", c.imag)) 165 | return NewComplex(r, i) 166 | } 167 | 168 | func (c Complex) div(ctx Context, d Complex) Complex { 169 | if isZero(d.real) && isZero(d.imag) { 170 | Errorf("complex division by zero") 171 | } 172 | if d.isReal() { // A common case, like dividing by 2. 173 | denom := ctx.EvalBinary(d.real, "*", d.real) 174 | r := ctx.EvalBinary(c.real, "*", d.real) 175 | r = ctx.EvalBinary(r, "/", denom) 176 | i := ctx.EvalBinary(c.imag, "*", d.real) 177 | i = ctx.EvalBinary(i, "/", denom) 178 | return NewComplex(r, i) 179 | } 180 | denom := ctx.EvalBinary(ctx.EvalBinary(d.real, "*", d.real), "+", ctx.EvalBinary(d.imag, "*", d.imag)) 181 | r := ctx.EvalBinary(ctx.EvalBinary(c.real, "*", d.real), "+", ctx.EvalBinary(c.imag, "*", d.imag)) 182 | r = ctx.EvalBinary(r, "/", denom) 183 | i := ctx.EvalBinary(ctx.EvalBinary(c.imag, "*", d.real), "-", ctx.EvalBinary(c.real, "*", d.imag)) 184 | i = ctx.EvalBinary(i, "/", denom) 185 | return NewComplex(r, i) 186 | } 187 | 188 | // floor returns the complex floor, as defined by 189 | // McDonnell, E. E. "Complex Floor, APL Congress 73." (1973). 190 | // https://www.jsoftware.com/papers/eem/complexfloor.htm 191 | // The rough idea is to find the nearest corner of the unit square 192 | // containing the point, rounding towards the origin. 193 | func (c Complex) floor(ctx Context) Complex { 194 | r := c.real 195 | i := c.imag 196 | b := NewComplex(ctx.EvalUnary("floor", r), ctx.EvalUnary("floor", i)) 197 | x := ctx.EvalBinary(r, "mod", one) 198 | y := ctx.EvalBinary(i, "mod", one) 199 | if isTrue("floor", ctx.EvalBinary(one, ">", ctx.EvalBinary(x, "+", y))) { 200 | return b 201 | } 202 | if isTrue("floor", ctx.EvalBinary(x, ">=", y)) { 203 | return b.add(ctx, complexOne) 204 | } 205 | return b.add(ctx, NewComplex(zero, one)) 206 | } 207 | 208 | // ceil returns the complex ceiling, defined as: 209 | // 210 | // op ceil z = -(floor -z) 211 | // 212 | // See the floor method for the definition of complex floor. 213 | func (c Complex) ceil(ctx Context) Complex { 214 | return c.neg(ctx).floor(ctx).neg(ctx) 215 | } 216 | -------------------------------------------------------------------------------- /parse/save.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package parse 6 | 7 | // Saving state to a file. 8 | 9 | import ( 10 | "bufio" 11 | "fmt" 12 | "io" 13 | "os" 14 | "sort" 15 | "strings" 16 | 17 | "robpike.io/ivy/config" 18 | "robpike.io/ivy/exec" 19 | "robpike.io/ivy/value" 20 | ) 21 | 22 | /* 23 | Output is written as source text, preserving the original precision of values when 24 | possible. Configuration is also saved. 25 | 26 | Saving ops is more subtle. The root issue is inside an op definition there may be 27 | an expression like 28 | x y z 29 | that could parse as any of the following: 30 | - vector of three values (x y z) 31 | - binary operator y applied to x and z 32 | - unary operator x applied to vector (y z) 33 | - unary operator x applied to unary operator y applied to z 34 | Which of these is correct depends on which of x and y are operators, and whether 35 | they are unary or binary. Thus we need to print the source in a way that recovers 36 | the correct parse. 37 | 38 | Ivy will not allow a variable and an operator to have the same name, so it is 39 | sufficient to know when parsing an op that all the operators it depends on have 40 | already been defined. To do this, we can just print the operator definitions in 41 | the order they originally appeared: if a is an operator, the parse of a is determined 42 | only by what operators have already been defined. If none of the identifiers 43 | mentioned in the definition are operators, the parse will take them as variables, 44 | even if those variables are not yet defined. 45 | 46 | Thus we can solve the problem by printing all the operator definitions in order, 47 | and then defining all the variables. 48 | 49 | Mutually recursive functions are an extra wrinkle but easy to resolve. 50 | */ 51 | 52 | // TODO: Find a way to move this into package exec. 53 | // This would require passing the references for each function from 54 | // here to save. 55 | 56 | // save writes the state of the workspace to the named file. 57 | // The format of the output is ivy source text. 58 | func save(c *exec.Context, file string) { 59 | // "" is a special case for testing. 60 | conf := c.Config() 61 | out := conf.Output() 62 | if file != "" { 63 | fd, err := os.Create(file) 64 | if err != nil { 65 | value.Errorf("%s", err) 66 | } 67 | defer fd.Close() 68 | buf := bufio.NewWriter(fd) 69 | defer buf.Flush() 70 | out = buf 71 | } 72 | 73 | // Configuration settings. We will set the base below, 74 | // after we have printed all numbers in base 10. 75 | fmt.Fprintf(out, ")prec %d\n", conf.FloatPrec()) 76 | ibase, obase := conf.Base() 77 | fmt.Fprintf(out, ")maxbits %d\n", conf.MaxBits()) 78 | fmt.Fprintf(out, ")maxdigits %d\n", conf.MaxDigits()) 79 | fmt.Fprintf(out, ")origin %d\n", conf.Origin()) 80 | fmt.Fprintf(out, ")prompt %q\n", conf.Prompt()) 81 | fmt.Fprintf(out, ")format %q\n", conf.Format()) 82 | conf.SetBase(10, 10) 83 | 84 | // Ops. 85 | printed := make(map[exec.OpDef]bool) 86 | for _, def := range c.Defs { 87 | var fn *exec.Function 88 | if def.IsBinary { 89 | fn = c.BinaryFn[def.Name] 90 | } else { 91 | fn = c.UnaryFn[def.Name] 92 | } 93 | for _, ref := range references(c, fn.Body) { 94 | if !printed[ref] { 95 | if ref.IsBinary { 96 | fmt.Fprintf(out, "op _ %s _\n", ref.Name) 97 | } else { 98 | fmt.Fprintf(out, "op %s _\n", ref.Name) 99 | } 100 | printed[ref] = true 101 | } 102 | } 103 | printed[def] = true 104 | s := fn.String() 105 | if strings.Contains(s, "\n") { 106 | // Multiline def must end in blank line. 107 | s += "\n" 108 | } 109 | fmt.Fprintln(out, s) 110 | } 111 | 112 | // Global variables. 113 | syms := c.Globals 114 | if len(syms) > 0 { 115 | // Set the base strictly to 10 for output. 116 | fmt.Fprintf(out, "# Set base 10 for parsing numbers.\n)base 10\n") 117 | // Sort the names for consistent output. 118 | sorted := sortSyms(syms) 119 | for _, sym := range sorted { 120 | fmt.Fprintf(out, "%s = ", sym.name) 121 | put(conf, out, sym.val.Value(), false) 122 | fmt.Fprint(out, "\n") 123 | } 124 | } 125 | 126 | // Now we can set the base. 127 | fmt.Fprintf(out, ")ibase %d\n", ibase) 128 | fmt.Fprintf(out, ")obase %d\n", obase) 129 | 130 | // Restore the configuration's own base. 131 | conf.SetBase(ibase, obase) 132 | } 133 | 134 | // saveSym holds a variable's name and value so we can sort them for saving. 135 | type saveSym struct { 136 | name string 137 | val *value.Var 138 | } 139 | 140 | type sortingSyms []saveSym 141 | 142 | func (s sortingSyms) Len() int { return len(s) } 143 | func (s sortingSyms) Less(i, j int) bool { return s[i].name < s[j].name } 144 | func (s sortingSyms) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 145 | 146 | func sortSyms(syms map[string]*value.Var) []saveSym { 147 | s := make(sortingSyms, len(syms)) 148 | i := 0 149 | for k, v := range syms { 150 | s[i] = saveSym{k, v} 151 | i++ 152 | } 153 | sort.Sort(s) 154 | return s 155 | } 156 | 157 | // put writes to out a version of the value that will recreate it when parsed. 158 | func put(conf *config.Config, out io.Writer, val value.Value, withParens bool) { 159 | if withParens { 160 | fmt.Fprint(out, "(") 161 | } 162 | switch val := val.(type) { 163 | case value.Char: 164 | fmt.Fprintf(out, "%q", rune(val)) 165 | case value.Int: 166 | fmt.Fprintf(out, "%d", int(val)) 167 | case value.BigInt: 168 | fmt.Fprintf(out, "%d", val.Int) 169 | case value.BigRat: 170 | fmt.Fprintf(out, "%d/%d", val.Num(), val.Denom()) 171 | case value.BigFloat: 172 | if val.Sign() == 0 || val.IsInf() { 173 | // These have prec 0 and are easy. 174 | // They shouldn't appear anyway, but be safe. 175 | fmt.Fprintf(out, "%g", val) 176 | return 177 | } 178 | // TODO The actual value might not have the same prec as 179 | // the configuration, so we might not get this right 180 | // Probably not important but it would be nice to fix it. 181 | digits := int(float64(val.Prec()) * 0.301029995664) // 10 log 2. 182 | fmt.Fprintf(out, "%.*g", digits+1, val.Float) // Add another digit to be sure. 183 | case value.Complex: 184 | real, imag := val.Components() 185 | put(conf, out, real, false) 186 | fmt.Fprintf(out, "j") 187 | put(conf, out, imag, false) 188 | case *value.Vector: 189 | if val.AllChars() { 190 | fmt.Fprintf(out, "%q", val.Sprint(conf)) 191 | return 192 | } 193 | for i, v := range val.All() { 194 | if i > 0 { 195 | fmt.Fprint(out, " ") 196 | } 197 | put(conf, out, v, !value.IsScalarType(v)) 198 | } 199 | case *value.Matrix: 200 | put(conf, out, value.NewIntVector(val.Shape()...), false) 201 | fmt.Fprint(out, " rho ") 202 | put(conf, out, val.Data(), false) 203 | default: 204 | value.Errorf("internal error: can't save type %T", val) 205 | } 206 | if withParens { 207 | fmt.Fprint(out, ")") 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /value/asin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package value 6 | 7 | import ( 8 | "math/big" 9 | ) 10 | 11 | func asin(c Context, v Value) Value { 12 | if u, ok := v.(Complex); ok { 13 | if !isZero(u.imag) || !inArcRealDomain(u.real) { 14 | return complexAsin(c, u) 15 | } 16 | v = u.real 17 | } else if !inArcRealDomain(v) { 18 | return complexAsin(c, NewComplex(v, zero)) 19 | } 20 | return evalFloatFunc(c, v, floatAsin) 21 | } 22 | 23 | func acos(c Context, v Value) Value { 24 | if u, ok := v.(Complex); ok { 25 | if !isZero(u.imag) || !inArcRealDomain(u.real) { 26 | return complexAcos(c, u) 27 | } 28 | v = u.real 29 | } else if !inArcRealDomain(v) { 30 | return complexAcos(c, NewComplex(v, zero)) 31 | } 32 | return evalFloatFunc(c, v, floatAcos) 33 | } 34 | 35 | // inArcRealDomain reports whether the argument is between -1 and +1, 36 | // the valid domain for real arcsin and arccos. 37 | func inArcRealDomain(x Value) bool { 38 | return compare(x, -1) >= 0 && compare(x, 1) <= 0 39 | } 40 | 41 | func atan(c Context, v Value) Value { 42 | if u, ok := v.(Complex); ok { 43 | if !isZero(u.imag) { 44 | return complexAtan(c, u) 45 | } 46 | v = u.real 47 | } 48 | return evalFloatFunc(c, v, floatAtan) 49 | } 50 | 51 | // floatAsin computes asin(x) using the formula asin(x) = atan(x/sqrt(1-x²)). 52 | func floatAsin(c Context, x *big.Float) *big.Float { 53 | // The asin Taylor series converges very slowly near ±1, but our 54 | // atan implementation converges well for all values, so we use 55 | // the formula above to compute asin. But be careful when |x|=1. 56 | if x.Cmp(floatOne) == 0 { 57 | z := newFloat(c).Set(floatPi) 58 | return z.Quo(z, floatTwo) 59 | } 60 | if x.Cmp(floatMinusOne) == 0 { 61 | z := newFloat(c).Set(floatPi) 62 | z.Quo(z, floatTwo) 63 | return z.Neg(z) 64 | } 65 | z := newFloat(c) 66 | z.Mul(x, x) 67 | z.Sub(floatOne, z) 68 | z = floatSqrt(c, z) 69 | z.Quo(x, z) 70 | return floatAtan(c, z) 71 | } 72 | 73 | // floatAcos computes acos(x) as π/2 - asin(x). 74 | func floatAcos(c Context, x *big.Float) *big.Float { 75 | // acos(x) = π/2 - asin(x) 76 | z := newFloat(c).Set(floatPi) 77 | z.Quo(z, newFloat(c).SetInt64(2)) 78 | return z.Sub(z, floatAsin(c, x)) 79 | } 80 | 81 | // floatAtan computes atan(x) using a Taylor series. There are two series, 82 | // one for |x| < 1 and one for larger values. 83 | func floatAtan(c Context, x *big.Float) *big.Float { 84 | // atan(-x) == -atan(x). Do this up top to simplify the Euler crossover calculation. 85 | if x.Sign() < 0 { 86 | z := newFloat(c).Set(x) 87 | z = floatAtan(c, z.Neg(z)) 88 | return z.Neg(z) 89 | } 90 | 91 | // The series converges very slowly near 1. atan 1.00001 takes over a million 92 | // iterations at the default precision. But there is hope, an Euler identity: 93 | // atan(x) = atan(y) + atan((x-y)/(1+xy)) 94 | // Note that y is a free variable. If x is near 1, we can use this formula 95 | // to push the computation to values that converge faster. Because 96 | // tan(π/8) = √2 - 1, or equivalently atan(√2 - 1) == π/8 97 | // we choose y = √2 - 1 and then we only need to calculate one atan: 98 | // atan(x) = π/8 + atan((x-y)/(1+xy)) 99 | // Where do we cross over? This version converges significantly faster 100 | // even at 0.5, but we must be careful that (x-y)/(1+xy) never approaches 1. 101 | // At x = 0.5, (x-y)/(1+xy) is 0.07; at x=1 it is 0.414214; at x=1.5 it is 102 | // 0.66, which is as big as we dare go. With 256 bits of precision and a 103 | // crossover at 0.5, here are the number of iterations done by 104 | // atan .1*iota 20 105 | // 0.1 39, 0.2 55, 0.3 73, 0.4 96, 0.5 126, 0.6 47, 0.7 59, 0.8 71, 0.9 85, 1.0 99, 1.1 116, 1.2 38, 1.3 44, 1.4 50, 1.5 213, 1.6 183, 1.7 163, 1.8 147, 1.9 135, 2.0 125 106 | tmp := newFloat(c).Set(floatOne) 107 | tmp.Sub(tmp, x) 108 | tmp.Abs(tmp) 109 | if tmp.Cmp(newFloat(c).SetFloat64(0.5)) < 0 { 110 | z := newFloat(c).Set(floatPi) 111 | z.Quo(z, newFloat(c).SetInt64(8)) 112 | y := floatSqrt(c, floatTwo) 113 | y.Sub(y, floatOne) 114 | num := newFloat(c).Set(x) 115 | num.Sub(num, y) 116 | den := newFloat(c).Set(x) 117 | den = den.Mul(den, y) 118 | den = den.Add(den, floatOne) 119 | z = z.Add(z, floatAtan(c, num.Quo(num, den))) 120 | return z 121 | } 122 | 123 | if x.Cmp(floatOne) > 0 { 124 | return floatAtanLarge(c, x) 125 | } 126 | 127 | // This is the series for small values |x| < 1. 128 | // asin(x) = x - x³/3 + x⁵/5 - x⁷/7 + ... 129 | // First term to compute in loop will be x 130 | 131 | n := newFloat(c) 132 | term := newFloat(c) 133 | xN := newFloat(c).Set(x) 134 | xSquared := newFloat(c).Set(x) 135 | xSquared.Mul(x, x) 136 | z := newFloat(c) 137 | 138 | // n goes up by two each loop. 139 | for loop := newLoop(c.Config(), "atan", x, 4); ; { 140 | term.Set(xN) 141 | term.Quo(term, n.SetUint64(2*loop.i+1)) 142 | z.Add(z, term) 143 | xN.Neg(xN) 144 | 145 | if loop.done(z) { 146 | break 147 | } 148 | // xN *= x², becoming x**(n+2). 149 | xN.Mul(xN, xSquared) 150 | } 151 | 152 | return z 153 | } 154 | 155 | // floatAtanLarge computes atan(x) for large x using a Taylor series. 156 | // x is known to be > 1. 157 | func floatAtanLarge(c Context, x *big.Float) *big.Float { 158 | // This is the series for larger values |x| >= 1. 159 | // For x > 0, atan(x) = +π/2 - 1/x + 1/3x³ -1/5x⁵ + 1/7x⁷ - ... 160 | // First term to compute in loop will be -1/x 161 | 162 | n := newFloat(c) 163 | term := newFloat(c) 164 | xN := newFloat(c).Set(x) 165 | xSquared := newFloat(c).Set(x) 166 | xSquared.Mul(x, x) 167 | z := newFloat(c).Set(floatPi) 168 | z.Quo(z, floatTwo) 169 | 170 | // n goes up by two each loop. 171 | for loop := newLoop(c.Config(), "atan", x, 4); ; { 172 | xN.Neg(xN) 173 | term.Set(xN) 174 | term.Mul(term, n.SetUint64(2*loop.i+1)) 175 | term.Quo(floatOne, term) 176 | z.Add(z, term) 177 | 178 | if loop.done(z) { 179 | break 180 | } 181 | // xN *= x², becoming x**(n+2). 182 | xN.Mul(xN, xSquared) 183 | } 184 | 185 | return z 186 | } 187 | 188 | func complexAsin(c Context, v Complex) Complex { 189 | // Use the formula: asin(v) = -i * log(sqrt(1-v²) + i*v) 190 | x := NewComplex(one, zero) 191 | x = complexSqrt(c, x.sub(c, v.mul(c, v))) 192 | i := NewComplex(zero, one) 193 | x = x.add(c, i.mul(c, v)) 194 | x = complexLog(c, x) 195 | return NewComplex(zero, minusOne).mul(c, x) 196 | } 197 | 198 | func complexAcos(c Context, v Complex) Value { 199 | // Use the formula: acos(v) = π/2 - asin(v) 200 | piBy2 := NewComplex(BigFloat{newFloat(c).Set(floatPiBy2)}, BigFloat{floatZero}) 201 | return piBy2.sub(c, complexAsin(c, v)) 202 | } 203 | 204 | func complexAtan(c Context, v Complex) Value { 205 | // Use the formula: atan(v) = 1/2i * log((1-v)/(1+v)) 206 | i := NewComplex(zero, one) 207 | res := i.sub(c, v).div(c, i.add(c, v)) 208 | res = complexLog(c, res) 209 | return res.mul(c, minusOneOverTwoI) 210 | } 211 | --------------------------------------------------------------------------------