diff --git a/lang/Compiler.go b/lang/Compiler.go
index 18bdaf1..8f6a289 100644
--- a/lang/Compiler.go
+++ b/lang/Compiler.go
@@ -3,6 +3,7 @@ package lang
import (
"io"
"math/rand"
+ "golang.org/x/net/context"
)
const (
@@ -50,10 +51,18 @@ var loadNs *Symbol = InternSymbolByNsname("load-ns")
var inlineKey *Symbol = InternSymbolByNsname("inline")
// TODO: more declarations here...
-
+var KEYWORDS *Var = CreateVarFromNothing().SetDynamic()
var COMPILE_PATH *Var = InternVar(FindOrCreateNamespace(InternSymbolByNsname("clojure.core")),
InternSymbolByNsname("*compile-path*"), nil).SetDynamic()
+type ObjExpr struct {
+ name string
+ internalName string
+ thisName string
+ keywords IPersistentMap
+ constants *PersistentVector
+}
+
/*
Compiler struct and methods
*/
@@ -62,8 +71,10 @@ type compiler struct{}
var Compiler = &compiler{}
+// TODO
func (_ *compiler) CurrentNS() *Namespace {
- return CURRENT_NS.Deref().(*Namespace)
+ panic(NotYetImplementedException)
+ // return CURRENT_NS.Deref().(*Namespace)
}
func (_ *compiler) NamespaceFor(inns *Namespace, sym *Symbol) *Namespace {
@@ -90,9 +101,11 @@ func (_ *compiler) Macroexpand(form interface{}) interface{} {
func (_ *compiler) Compile(rdr *io.Reader, sourcePath string, sourceName string) interface{} {
// TODO: Do we need this? I don't know.
// #VESTIGIAL
+ /*
if COMPILE_PATH.Deref() == nil {
panic("*compile-path* not set")
}
+ */
var EOF int = rand.Int() // TODO: Sentinel value
var ret interface{}
@@ -105,31 +118,33 @@ func (_ *compiler) Compile(rdr *io.Reader, sourcePath string, sourceName string)
}
// In JVM Clojure, gen is a GeneratorAdapter. We don't have an analog for that here.
-func (_ *compiler) Compile1(gen interface{}, objx ObjExpr, form interface{}) {
+func (_ *compiler) Compile1(ctx context.Context, gen interface{}, objx ObjExpr, form interface{}) {
// TODO: some initial set-up.
- // try, catch (might want better error handling here)
+ ctx =
+ // try block begins here
form = Compiler.Macroexpand(form)
switch f := form.(type) {
case ISeq:
if Util.Equals(RT.First(form), DO) {
for s := RT.Next(form); s != nil; s = RT.Next(s) {
- Compiler.Compile1(gen, objx, RT.First(s))
+ Compiler.Compile1(ctx, gen, objx, RT.First(s))
}
}
default:
expr := Compiler.Analyze(EVAL, form)
- objx.keywords = KEYWORDS.Deref()
- objx.vars = VAR.Deref()
- objx.constants = CONSTANTS.Deref()
+ objx.keywords = KEYWORDS.Deref().(IPersistentMap)
+ objx.vars = VAR.Deref().(IPersistentMap)
+ objx.constants = CONSTANTS.Deref().(*PersistentVector)
expr.Emit(EXPRESSION, objx, gen)
expr.Eval()
}
- // TODO: Var.Pop thread bindings
}
func (_ *compiler) Eval(form interface{}, freshLoader bool) interface{} {
createdLoader := false // do we need this?
+}
-
+func (_ *compiler) Analyze(a interface{}, b interface{}) interface{} {
+ panic(NotYetImplementedException)
}
\ No newline at end of file
diff --git a/lang/Var.go b/lang/Var.go
index 0f99a89..7baa8bd 100644
--- a/lang/Var.go
+++ b/lang/Var.go
@@ -2,14 +2,11 @@ package lang
import (
"bytes"
- "sync"
-
+ "golang.org/x/net/context"
)
/*
Assorted class variables
-
-
*/
// TODO: I found this really useful: http://www.golangbootcamp.com/book/concurrency
@@ -26,18 +23,30 @@ var rev int = 0 // maybe atomic integer since this will be shared.
/*
Var
+ Extends: ARef
+
Implements: IFn, IRef, Settable
+
+ Notes: in JVM Clojure, the implementation of Vars is heavily dependent on the JVM's support
+ for thread-local storage. In the almost total absence of a simple analog here in Go, I've
+ chosen to instead use the x/net/context package instead as a way of passing explicit
+ bindings.
*/
type Var struct {
ARef
+ // AReference
_meta IPersistentMap
+
+ // ARef
+ validator IFn
+ watches *PersistentHashMap // default EMPTY
+
rev int
privateMeta IPersistentMap
root interface{}
- dyanmic bool
- threadBound bool // atomicboolean TODO
+ dynamic bool
sym *Symbol
ns *Namespace
}
@@ -63,15 +72,15 @@ func (v *Var) String() string {
func (v *Var) SetDynamic(args ...bool) *Var {
if len(args) == 0 {
- v.dyanmic = true
+ v.dynamic = true
} else {
- v.dyanmic = args[0]
+ v.dynamic = args[0]
}
return v
}
func (v *Var) IsDynamic() bool {
- return v.IsDynamic()
+ return v.dynamic
}
func InternVar(ns *Namespace, sym *Symbol, root interface{}) *Var {
@@ -112,7 +121,6 @@ func CreateVarFromNothing() *Var {
return &Var{
ns: nil,
sym: nil,
- threadBound: false, // TODOAtomicBoolean
root: VarUnbound{
v: v,
},
@@ -127,23 +135,53 @@ func CreateVarFromRoot(root interface{}) *Var {
}
}
-func (v *Var) isBound() bool {
- // TODO
- panic(NotYetImplementedException)
+// unexported type and key for var context utility functions
+type key int
+var varKey key = 0
+
+// Set the new Var root for the provided context
+func setVarBindingForContext(ctx context.Context, val interface{}) context.Context {
+ return context.WithValue(ctx, varKey, val)
}
-// TODO
-func (v *Var) Get() interface{} {
- panic(NotYetImplementedException)
+// Retrieve the new Var root from the provided context
+func getVarBindingFromContext(ctx context.Context) (*Frame, bool) {
+ r, ok := ctx.Value(varKey).(*Frame)
+ return r, ok
}
-// TODO: this is a naive and stupid implementation
-func (v *Var) Deref() interface{} {
+func (v *Var) isBound(ctx context.Context) bool {
+ r, ok := getVarBindingFromContext(ctx)
+ if ok == false {
+ panic("Stored var value wasn't an instance of *lang.Frame")
+ }
+ return v.HasRoot() || r != nil && r.bindings.ContainsKey(v)
+}
+
+func (v *Var) Get(ctx context.Context) interface{} {
+ r, ok := getVarBindingFromContext(ctx)
+ if ok == false {
+ panic("Stored var value wasn't an instance of *lang.Frame")
+ }
+ if r == nil {
+ return v.root
+ }
+ return v.Deref(ctx)
+}
+
+func (v *Var) Deref(ctx context.Context) interface{} {
+ r, ok := getVarBindingFromContext(ctx)
+ if (r != nil) {
+ return r.bindings.EntryAt(v)
+ }
return v.root
}
// TODO
func (v *Var) SetValidator(vf IFn) {
+ if v.HasRoot() {
+ v.validate()
+ }
panic(NotYetImplementedException)
}
@@ -213,35 +251,26 @@ func (v *Var) BindRoot(root interface{}) {
v.root = root
}
-func (v *Var) Fn() IFn {
- return v.Deref().(IFn)
+func (v *Var) Fn(ctx context.Context) IFn {
+ return v.Deref(ctx).(IFn)
}
-func (v *Var) Call() interface{} {
- return v.Invoke()
+func (v *Var) Call(ctx context.Context) interface{} {
+ return v.Invoke(ctx)
}
-func (v *Var) Run() {
- v.Invoke()
+func (v *Var) Run(ctx context.Context) {
+ v.Invoke(ctx)
}
-func (v *Var) Invoke(args ...interface{}) interface{} {
- return v.Fn().Invoke(args...)
+func (v *Var) Invoke(ctx context.Context, args ...interface{}) interface{} {
+ return v.Fn(ctx).Invoke(args...)
}
func (v *Var) ApplyTo(arglist ISeq) interface{} {
return AFn_ApplyToHelper(v, arglist)
}
-/*
- VarTBox [TBox]
-*/
-
-type VarTBox struct {
- val interface{}
- lock *sync.Mutex // instead of keeping track of thread
-}
-
/*
VarUnbound [Unbound]
*/
@@ -284,36 +313,9 @@ func (f *Frame) Clone() interface{} {
}
}
-/*
- VarFrameDvals
-
- This class is just a ThreadLocal in JVM Clojure with an initialValue() func.
-*/
-
-type VarFrameDvals struct {
- Frame
-
- lock *sync.Mutex
-}
-
-func (d *VarFrameDvals) InitialValue() *Frame {
- return TOP_FRAME
-}
-
-// TODO
-func getThreadBindingFrame() interface{} {
- return nil
-}
-
-// TODO
-func cloneThreadBindingFrame() interface{} {
- return nil
-}
-
-// TODO
-func resetThreadBindingFrame() interface{} {
- return nil
-}
+// In JVM Clojure, dvals is a ThreadLocal. Here we pass it around in a context.
+// First we initialize dvals to TOP_FRAME
+var dvals *Frame = TOP_FRAME
// TODO...still most of this file.
@@ -326,4 +328,4 @@ var assoc = &assocAnon{}
func (a *assocAnon) Invoke(args ...interface{}) interface{} {
m, k, v := args[0], args[1], args[2]
return RT.Assoc(m, k, v)
-}
+}
\ No newline at end of file