diff --git a/.gitignore b/.gitignore index 8e8ca30..212173b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ dist .goreleaser.yml ell.prof +.DS_Store diff --git a/blob.go b/blob.go index 0556964..8bbd1a4 100644 --- a/blob.go +++ b/blob.go @@ -16,9 +16,9 @@ limitations under the License. package ell -import( +import ( "fmt" - + . "github.com/boynton/ell/data" ) diff --git a/cmd/ell/main.go b/cmd/ell/main.go index 41471de..dabc355 100644 --- a/cmd/ell/main.go +++ b/cmd/ell/main.go @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/code.go b/code.go index cb7c8ea..8ad5319 100644 --- a/code.go +++ b/code.go @@ -123,7 +123,6 @@ func (code1 *Code) Equals(another Value) bool { return false } - func (code *Code) signature() string { // //experimental: external annotations on the functions: *declarations* is a map from symbol to string @@ -251,19 +250,7 @@ func (code *Code) loadOps(lst *List) error { var defaults []Value var keys []Value var err error - /* if IsSymbol(funcParams) { - //legacy form, just the argc - argc, err = AsIntValue(funcParams) - if err != nil { - return err - } - if argc < 0 { - argc = -argc - 1 - defaults = make([]*Object, 0) - } - } else */ if lst, ok := funcParams.(*List); ok && lst.Length() == 4 { - // if IsList(funcParams) && ListLength(funcParams) == 4 { a := lst.Car lst = lst.Cdr name, err = AsStringValue(a) diff --git a/compiler.go b/compiler.go index 89ab37c..49d5a3c 100644 --- a/compiler.go +++ b/compiler.go @@ -16,8 +16,8 @@ limitations under the License. package ell -import( - "fmt" +import ( + "fmt" . "github.com/boynton/ell/data" ) diff --git a/ell_test.go b/ell_test.go index de2f8ba..b5a0c1d 100644 --- a/ell_test.go +++ b/ell_test.go @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -17,21 +17,23 @@ package ell import ( "testing" + + . "github.com/boynton/ell/data" ) -func testType(t *testing.T, name string, sym *Object) { +func testType(t *testing.T, name string, sym Value) { if sym != Intern(name) { t.Error("type is not ", name, ":", sym) } } -func testIdentical(t *testing.T, o1 *Object, o2 *Object) { +func testIdentical(t *testing.T, o1 Value, o2 Value) { if o1 != o2 { t.Error("objects should be identical but are not:", o1, "and", o2) } } -func testNotIdentical(t *testing.T, o1 *Object, o2 *Object) { +func testNotIdentical(t *testing.T, o1 Value, o2 Value) { if o1 == o2 { t.Error("objects should not be identical but are:", o1, "and", o2) } @@ -41,7 +43,7 @@ func TestNull(t *testing.T) { n1 := Null testIdentical(t, n1, Null) testNotIdentical(t, Null, nil) - testType(t, "", Null.Type) + testType(t, "", Null.Type()) if n1 != Null { t.Error("nil isn't Null") } @@ -50,16 +52,12 @@ func TestNull(t *testing.T) { func TestBooleans(t *testing.T) { b1 := True b2 := False - testType(t, "", True.Type) - testType(t, "", False.Type) - testIdentical(t, True.Type, False.Type) + testType(t, "", True.Type()) + testType(t, "", False.Type()) + testIdentical(t, True.Type(), False.Type()) testIdentical(t, b1, True) testIdentical(t, b2, False) testNotIdentical(t, b1, b2) - if !IsBoolean(b1) { - t.Error("boolean value isn't:", b1) - } - if !IsBoolean(b2) { - t.Error("boolean value isn't:", b2) - } + testType(t, "", b1.Type()) + testType(t, "", b2.Type()) } diff --git a/generic.go b/generic.go index f536245..dd5011d 100644 --- a/generic.go +++ b/generic.go @@ -16,7 +16,7 @@ limitations under the License. package ell -import( +import ( . "github.com/boynton/ell/data" ) diff --git a/go.mod b/go.mod index 5d5feea..5c2083f 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,11 @@ module github.com/boynton/ell -go 1.16 +go 1.19 require ( github.com/boynton/cli v0.0.0-20170122194616-c91dc790ccff github.com/boynton/repl v0.0.0-20170116235056-348863958e3e github.com/pborman/uuid v1.2.0 ) + +require github.com/google/uuid v1.0.0 // indirect diff --git a/lib/bench.ell b/lib/bench.ell index 82e8418..09c6f4a 100644 --- a/lib/bench.ell +++ b/lib/bench.ell @@ -5,6 +5,9 @@ ;; `time ell --optimize bench` ;; ;; Apple M1 (go1.16 darwin/arm64, ell v2) 2.62s +;; Apple M1 Max (go1.19.2, darwin/arm64) 2.85s +;; Apple M1 Max (go1.17.2, darwin/arm64) 3.04s +;; Apple M1 (go1.17.2, darwin/arm64) 3.07s ;; Apple M1 (go1.16 darwin/arm64) 3.31s ;; Apple M1 (go1.16 linux/aarch64, docker) 3.92s ;; Apple M1 (go1.16 darwin/amd64, rosetta 2) 5.78s @@ -15,15 +18,18 @@ ;; For reference, here are some comparable numbers for the same ;; benchmark in scheme-5.9: ;; +;; DrRacket Scheme (arm64, Apple M1 Max) 0.23 +;; DrRacket Scheme (arm64, Apple M1) 0.28 ;; Macmini9,1 (arm64, Apple M1) 0.97 ;; MacBookPro16,1 (x86-64, i9-9900K) 0.97 +;; MacbookPro18,4 (arm64, Apple M1 Max) 0.99 ;; MacBookPro14,1 (x86-64, I7-7660U) 1.27 ;; MacNookPro16,1 (x86-64, i9-9900k, rosetta2) 1.41 ;; MacPro6,1 (x86-64, xeon e5-1650) 1.73 ;; iMac11,1 (x86-64, i7-860) 1.90 ;; MacBookPro9,1 (x86-64, I7-3720QM) 1.90 ;; Macmini3,1 (x86-64, core2-duo P7350) 3.47 -;; +;; Chicken Scheme (64, Apple M1) 3.91 (use sort) (use pi) diff --git a/macro.go b/macro.go index 64e2077..9d544db 100644 --- a/macro.go +++ b/macro.go @@ -162,7 +162,9 @@ func expandUndef(expr Value) (Value, error) { } // (defn f (x) (+ 1 x)) -// -> +// +// -> +// // (def f (fn (x) (+ 1 x))) func expandDefn(expr Value) (Value, error) { exprLen := ListLength(expr) @@ -567,7 +569,7 @@ func expandQQList(lst *List) (*List, error) { result := NewList(Intern("concat")) tail := result for lst != EmptyList { - if item, ok := Car(lst).(*List); ok && item != EmptyList{ + if item, ok := Car(lst).(*List); ok && item != EmptyList { if item.Car == QuasiquoteSymbol { return nil, NewError(MacroErrorKey, "nested quasiquote not supported") } diff --git a/module.go b/module.go index 4875f18..9dd974f 100644 --- a/module.go +++ b/module.go @@ -177,8 +177,8 @@ func defMacro(sym Value, val *Function) { macroMap[sym] = NewMacro(sym, val) } -//note: unlike java, we cannot use maps or arrays as keys (they are not comparable). -//so, we will end up with duplicates, unless we do some deep compare, when putting map or array constants +// note: unlike java, we cannot use maps or arrays as keys (they are not comparable). +// so, we will end up with duplicates, unless we do some deep compare, when putting map or array constants func putConstant(val Value) int { idx, present := constantsMap[val] if !present { @@ -328,7 +328,7 @@ func compileValue(expr Value) (string, error) { return thunk.decompile(true) + "\n", nil } -//caveats: when you compile a file, you actually run it. This is so we can handle imports and macros correctly. +// caveats: when you compile a file, you actually run it. This is so we can handle imports and macros correctly. func CompileFile(name string) (Value, error) { file, err := FindModuleFile(name) if err != nil { @@ -432,7 +432,7 @@ func Main(extns ...Extension) { os.Exit(1) } interactive := len(args) == 0 - SetFlags(optimize, verbose, debug, trace, interactive) + SetFlags(optimize, verbose, debug, trace, interactive) Init(extns...) if path != "" { for _, p := range strings.Split(path, ":") { diff --git a/net.go b/net.go index 5368163..55571c1 100644 --- a/net.go +++ b/net.go @@ -209,9 +209,9 @@ var ConnectionType = Intern("") type Connection struct { Name string - In *Channel - Out *Channel - Con net.Conn + In *Channel + Out *Channel + Con net.Conn } func (c *Connection) Type() Value { @@ -232,9 +232,9 @@ func NewConnection(con net.Conn, endpoint string) Value { name := fmt.Sprintf("connection on %s", endpoint) return &Connection{ Name: name, - In: inchan, - Out: outchan, - Con: con, + In: inchan, + Out: outchan, + Con: con, } } @@ -244,7 +244,7 @@ func closeConnection(obj Value) { CloseChannel(p.In) CloseChannel(p.Out) p.Con.Close() - p.Con = nil; + p.Con = nil } } } diff --git a/notation.go b/notation.go index 4e21758..f8049c1 100644 --- a/notation.go +++ b/notation.go @@ -26,7 +26,7 @@ import ( "os" "strconv" "strings" - + . "github.com/boynton/ell/data" ) @@ -103,7 +103,7 @@ func SpitFile(path string, data string) error { func ReadFromString(s string) (Value, error) { reader := &Reader{ - Input: bufio.NewReader(strings.NewReader(s)), + Input: bufio.NewReader(strings.NewReader(s)), Position: 0, } reader.Extension = &EllReaderExtension{r: reader} @@ -112,7 +112,7 @@ func ReadFromString(s string) (Value, error) { func ReadAllFromString(s string) (*List, error) { reader := &Reader{ - Input: bufio.NewReader(strings.NewReader(s)), + Input: bufio.NewReader(strings.NewReader(s)), Position: 0, } reader.Extension = &EllReaderExtension{r: reader} diff --git a/number.go b/number.go index c551a02..f4403ad 100644 --- a/number.go +++ b/number.go @@ -182,4 +182,3 @@ func Float64Value(obj Value) float64 { } return 0 } - diff --git a/primitives.go b/primitives.go index 1c0303b..9e4fe0f 100644 --- a/primitives.go +++ b/primitives.go @@ -375,14 +375,14 @@ func numeq(n1 Value, n2 Value) bool { func numericPair(argv []Value) (float64, float64, error) { return (argv[0].(*Number)).Value, (argv[1].(*Number)).Value, nil /* f1, err := AsFloat64Value(argv[0]) - if err != nil { - return 0, 0, err - } - f2, err := AsFloat64Value(argv[1]) - if err != nil { - return 0, 0, err - } - return f1, f2, nil + if err != nil { + return 0, 0, err + } + f2, err := AsFloat64Value(argv[1]) + if err != nil { + return 0, 0, err + } + return f1, f2, nil */ } @@ -980,8 +980,8 @@ func ellSend(argv []Value) (Value, error) { ch := ChannelValue(argv[0]) if ch != nil { //not closed val := argv[1] - timeout := Float64Value(argv[2]) //FIX: timeouts in seconds, floating point - if NumberEqual(timeout, 0.0) { //non-blocking + timeout := Float64Value(argv[2]) //FIX: timeouts in seconds, floating point + if NumberEqual(timeout, 0.0) { //non-blocking select { case ch <- val: return True, nil diff --git a/repl.go b/repl.go index c926a8a..d4ce31a 100644 --- a/repl.go +++ b/repl.go @@ -25,8 +25,8 @@ import ( "sort" "strings" - "github.com/boynton/repl" . "github.com/boynton/ell/data" + "github.com/boynton/repl" ) type ellHandler struct { diff --git a/runtime.go b/runtime.go index bae0427..34d1724 100644 --- a/runtime.go +++ b/runtime.go @@ -85,7 +85,7 @@ type Continuation struct { func Closure(code *Code, frame *Frame) *Function { return &Function{ - code: code, + code: code, frame: frame, } } @@ -97,7 +97,7 @@ func NewContinuation(frame *Frame, ops []int, pc int, stack []Value) *Function { copy(cont.stack, stack) cont.pc = pc return &Function{ - frame: frame, + frame: frame, continuation: cont, } } @@ -116,10 +116,10 @@ func VM(stackSize int) *vm { var FunctionType Value = Intern("") type Function struct { - name string - code *Code - frame *Frame - primitive *Primitive + name string + code *Code + frame *Frame + primitive *Primitive continuation *Continuation } @@ -192,7 +192,6 @@ func functionSignature(f *Function) string { panic("Bad function") } - // PrimitiveFunction is the native go function signature for all Ell primitive functions type PrimitiveFunction func(argv []Value) (Value, error) @@ -202,12 +201,12 @@ type Primitive struct { // fun PrimitiveFunction signature string // idx int - argc int // -1 means the primitive itself checks the args (legacy mode) - result Value // if set the type of the result - args []Value // if set, the length must be for total args (both required and optional). The type (or ) for each - rest Value // if set, then any number of this type can follow the normal args. Mutually incompatible with defaults/keys - defaults []Value // if set, then that many optional args beyond argc have these default values - keys []Value // if set, then it must match the size of defaults, and these are the keys + argc int // -1 means the primitive itself checks the args (legacy mode) + result Value // if set the type of the result + args []Value // if set, the length must be for total args (both required and optional). The type (or ) for each + rest Value // if set, then any number of this type can follow the normal args. Mutually incompatible with defaults/keys + defaults []Value // if set, then that many optional args beyond argc have these default values + keys []Value // if set, then it must match the size of defaults, and these are the keys } func functionSignatureFromTypes(result Value, args []Value, rest Value) string { @@ -301,10 +300,10 @@ func (frame *Frame) String() string { func buildFrame(env *Frame, pc int, ops []int, fun *Function, argc int, stack []Value, sp int) (*Frame, error) { f := &Frame{ previous: env, - pc: pc, - ops: ops, - locals: fun.frame, - code: fun.code, + pc: pc, + ops: ops, + locals: fun.frame, + code: fun.code, } expectedArgc := fun.code.argc defaults := fun.code.defaults @@ -853,7 +852,7 @@ func (vm *vm) exec(code *Code, env *Frame) (Value, error) { if fun.primitive != nil { nextSp := sp + argc prim := fun.primitive - argv := stack[sp+1:nextSp+1] + argv := stack[sp+1 : nextSp+1] if prim.defaults != nil { val, err = vm.callPrimitiveWithDefaults(prim, argv) } else { @@ -923,7 +922,7 @@ func (vm *vm) exec(code *Code, env *Frame) (Value, error) { if fun.primitive != nil { nextSp := sp + argc prim := fun.primitive - argv := stack[sp+1:nextSp+1] + argv := stack[sp+1 : nextSp+1] if prim.defaults != nil { val, err = vm.callPrimitiveWithDefaults(prim, argv) } else { @@ -1238,7 +1237,7 @@ func (vm *vm) instrumentedExec(code *Code, env *Frame) (Value, error) { return stack[sp], nil } } - } else { + } else { ops, pc, sp, env, err = vm.tailcall(fun, argc, ops, stack, sp+1, env) if err != nil { return nil, err diff --git a/string.go b/string.go index 19bac29..332b364 100644 --- a/string.go +++ b/string.go @@ -22,7 +22,6 @@ import ( . "github.com/boynton/ell/data" ) - // AsStringValue - return the native string representation of the object, if possible func AsStringValue(obj Value) (string, error) { if p, ok := obj.(*String); ok { @@ -76,7 +75,7 @@ func ToString(a Value) (*String, error) { return nil, NewError(ArgumentErrorKey, "to-string: cannot convert argument to : ", a) } } - + // ToCharacter - convert object to a object, if possible func ToCharacter(c Value) (*Character, error) { switch p := c.(type) { @@ -207,4 +206,3 @@ func StringValue(obj Value) string { return p.String() } } - diff --git a/struct.go b/struct.go index 1b99cb0..c3329a4 100644 --- a/struct.go +++ b/struct.go @@ -56,7 +56,7 @@ func Put(obj Value, key Value, val Value) error { p.Put(key, val) return nil } - return NewError(ArgumentErrorKey, "Expected a argument, got a ", obj.Type()) + return NewError(ArgumentErrorKey, "Expected a argument, got a ", obj.Type()) } func Unput(obj Value, key Value) error { @@ -67,7 +67,7 @@ func Unput(obj Value, key Value) error { p.Unput(key) return nil } - return NewError(ArgumentErrorKey, "Expected a argument, got a ", obj.Type()) + return NewError(ArgumentErrorKey, "Expected a argument, got a ", obj.Type()) } func sliceContains(slice []Value, obj Value) bool { diff --git a/symbol.go b/symbol.go index 8159f5f..46c6dfc 100644 --- a/symbol.go +++ b/symbol.go @@ -16,9 +16,9 @@ limitations under the License. package ell -import( +import ( "fmt" - + . "github.com/boynton/ell/data" ) @@ -64,5 +64,5 @@ func Unkeyworded(symOrKeyword Value) (Value, error) { if kw, ok := symOrKeyword.(*Keyword); ok { return Intern(kw.Name()), nil } - return Null, NewError(ArgumentErrorKey, "Expected or , got ", symOrKeyword.Type()) + return Null, NewError(ArgumentErrorKey, "Expected or , got ", symOrKeyword.Type()) }