Skip to content

Commit

Permalink
Merge pull request #179 from corywalker/corywalker
Browse files Browse the repository at this point in the history
Fixes for iwolfram.
  • Loading branch information
corywalker committed Oct 15, 2018
2 parents 6d7cc29 + 96a3dce commit c09c1bd
Show file tree
Hide file tree
Showing 23 changed files with 465 additions and 186 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -16,6 +16,7 @@ go_import_path: github.com/corywalker/expreduce

script:
- go test -v ./...
- go test -v -race ./... -run Concurrency

after_success:
- test -n "$TRAVIS_TAG" && curl -sL https://git.io/goreleaser | bash
Expand Down
32 changes: 27 additions & 5 deletions expreduce.go
Expand Up @@ -8,15 +8,18 @@ import (
"log"
"os"
"bytes"
"bufio"
"runtime/pprof"
"net/http"
_ "net/http/pprof"
)

var debug = flag.Bool("debug", false, "Debug mode. No initial definitions.")
var rawterm = flag.Bool("rawterm", false, "Do not use readline. Useful for pexpect integration.")
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var netprofile = flag.Bool("netprofile", false, "Enable live profiling at http://localhost:8080/debug/pprof/")
var scriptfile = flag.String("script", "", "script `file` to read from")
var initfile = flag.String("initfile", "", "A script to run on initialization.")



Expand All @@ -42,12 +45,25 @@ func main() {
es.ClearAll()
}

if *initfile != "" {
f, err := os.Open(*initfile)
if err != nil {
log.Fatal(err)
}
defer f.Close()

buf := new(bytes.Buffer)
buf.ReadFrom(f)
scriptText := buf.String()
expreduce.EvalInterpMany(scriptText, *initfile, es)
}

if *scriptfile != "" {
f, err := os.Open(*scriptfile)
if err != nil {
log.Fatal(err)
}
defer f.Close()
defer f.Close()

buf := new(bytes.Buffer)
buf.ReadFrom(f)
Expand All @@ -63,8 +79,6 @@ func scriptSession(es *expreduce.EvalState, srcText string, srcPath string) {
exp := expreduce.EvalInterpMany(srcText, srcPath, es)
res := exp.Eval(es)
res = es.ProcessTopLevelResult(res, res)


}


Expand All @@ -81,8 +95,16 @@ func interactiveSession(es *expreduce.EvalState) {
fmt.Printf("Welcome to Expreduce!\n\n")
promptNum := 1
for {
rl.SetPrompt(fmt.Sprintf("In[%d]:= ", promptNum))
line, err := rl.Readline()
line := ""
var err error
if *rawterm {
reader := bufio.NewReader(os.Stdin)
fmt.Printf("In[%d]:= ", promptNum)
line, err = reader.ReadString('\n')
} else {
rl.SetPrompt(fmt.Sprintf("In[%d]:= ", promptNum))
line, err = rl.Readline()
}
if err != nil { // io.EOF, readline.ErrInterrupt
break
}
Expand Down
9 changes: 0 additions & 9 deletions expreduce/blank.go
Expand Up @@ -52,7 +52,6 @@ func IsBlankTypeCapturing(e Ex, target Ex, head Ex, pm *PDManager, cl *CASLogger
if sAsSymbolOk {
// TODO: we should handle matches with BlankSequences
// differently here.
//_, isd := es.defined[sAsSymbol.Name]
toMatch, ispd := pm.patternDefined[sAsSymbol.Name]
if !ispd {
toMatch = target
Expand All @@ -62,14 +61,6 @@ func IsBlankTypeCapturing(e Ex, target Ex, head Ex, pm *PDManager, cl *CASLogger
if !IsSameQ(toMatch, target, cl) {
return false, pm
}

/*if !isd {
//es.defined[sAsSymbol.Name] = target
es.Define(sAsSymbol.Name, sAsSymbol, target)
} else {
//return es.defined[sAsSymbol.Name].IsSameQ(target, es)
return true
}*/
}
return true, pm
}
Expand Down
29 changes: 29 additions & 0 deletions expreduce/builtin_list.go
Expand Up @@ -3,6 +3,7 @@ package expreduce
import "bytes"
import "math/big"
import "sort"
import "sync"

func (this *Expression) ToStringList(params ToStringParams) (bool, string) {
if params.form == "FullForm" {
Expand Down Expand Up @@ -203,6 +204,34 @@ func GetListDefinitions() (defs []Definition) {
return this
},
})
defs = append(defs, Definition{
Name: "ParallelTable",
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
if len(this.Parts) >= 3 {
mis, isOk := multiIterSpecFromLists(es, this.Parts[2:])
if isOk {
// Simulate evaluation within Block[]
toReturn := NewExpression([]Ex{NewSymbol("System`List")})
for mis.cont() {
toReturn.Parts = append(toReturn.Parts, ReplacePD(this.Parts[1].DeepCopy(), es, mis.currentPDManager()))
es.Debugf("%v\n", toReturn)
mis.next()
}
var wg sync.WaitGroup
for i := 1; i < len(toReturn.Parts); i++ {
wg.Add(1)
go func (idx int) {
defer wg.Done()
toReturn.Parts[idx] = toReturn.Parts[idx].Eval(es)
}(i)
}
wg.Wait()
return toReturn
}
}
return this
},
})
defs = append(defs, Definition{
Name: "MemberQ",
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
Expand Down
51 changes: 50 additions & 1 deletion expreduce/builtin_string.go
@@ -1,5 +1,10 @@
package expreduce

import (
"strings"
"encoding/base64"
)

func GetStringDefinitions() (defs []Definition) {
defs = append(defs, Definition{
Name: "ToString",
Expand All @@ -15,7 +20,7 @@ func GetStringDefinitions() (defs []Definition) {
}

// Do not implement FullForm here. It is not officially supported
if formAsSymbol.Name != "System`InputForm" && formAsSymbol.Name != "System`OutputForm" && formAsSymbol.Name != "System`FullForm" {
if formAsSymbol.Name != "System`InputForm" && formAsSymbol.Name != "System`OutputForm" && formAsSymbol.Name != "System`FullForm" && formAsSymbol.Name != "System`TeXForm" {
return this
}

Expand Down Expand Up @@ -94,5 +99,49 @@ func GetStringDefinitions() (defs []Definition) {
return NewString(asStr.Val[s : e+1])
},
})
defs = append(defs, Definition{
Name: "StringReplace",
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
if len(this.Parts) != 3 {
return this
}
asStr, isStr := this.Parts[1].(*String)
if !isStr {
return this
}
asRule, isRule := HeadAssertion(this.Parts[2], "System`Rule")
if !isRule || len(asRule.Parts) != 3 {
return this
}
bStr, bIsStr := asRule.Parts[1].(*String)
aStr, aIsStr := asRule.Parts[2].(*String)
if !bIsStr || !aIsStr {
return this
}
return NewString(strings.Replace(asStr.Val, bStr.Val, aStr.Val, -1))
},
})
defs = append(defs, Definition{
Name: "ExportString",
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
if len(this.Parts) != 3 {
return this
}
asStr, isStr := this.Parts[1].(*String)
if !isStr {
return this
}
formatAsStr, formatIsStr := this.Parts[2].(*String)
if !formatIsStr {
return this
}
format := strings.ToLower(formatAsStr.Val)
if format == "base64" {
encoded := base64.StdEncoding.EncodeToString([]byte(asStr.Val))
return NewString(encoded + "\n")
}
return NewSymbol("System`$Failed")
},
})
return
}
12 changes: 6 additions & 6 deletions expreduce/builtin_system.go
Expand Up @@ -191,7 +191,7 @@ func applyModuleFn(this *Expression, es *EvalState) (Ex, bool) {
if pl.isSet {
rhs = rhs.Eval(es)
}
es.defined[pl.uniqueName] = Def{
es.defined.Set(pl.uniqueName, Def{
downvalues: []DownValue{
DownValue{
rule: NewExpression([]Ex{
Expand All @@ -201,9 +201,9 @@ func applyModuleFn(this *Expression, es *EvalState) (Ex, bool) {
}),
},
},
}
})
} else {
es.defined[pl.uniqueName] = Def{}
es.defined.Set(pl.uniqueName, Def{})
}
pm.LazyMakeMap()
pm.patternDefined[pl.sym.Name] = NewSymbol(pl.uniqueName)
Expand Down Expand Up @@ -277,7 +277,7 @@ func GetSystemDefinitions() (defs []Definition) {
return this
}

def, isDef := es.defined[sym.Name]
def, isDef := es.defined.Get(sym.Name)
if isDef {
return def.attributes.toSymList()
}
Expand Down Expand Up @@ -333,7 +333,7 @@ func GetSystemDefinitions() (defs []Definition) {
if params.es == nil {
return true, "Definiton[<WITHOUT_CONTEXT>]"
}
def, isd := params.es.defined[sym.Name]
def, isd := params.es.defined.Get(sym.Name)
if !isd {
return true, "Null"
}
Expand All @@ -358,7 +358,7 @@ func GetSystemDefinitions() (defs []Definition) {
return this
}
res := NewExpression([]Ex{NewSymbol("System`List")})
def, isd := es.defined[sym.Name]
def, isd := es.defined.Get(sym.Name)
if !isd {
return res
}
Expand Down
23 changes: 23 additions & 0 deletions expreduce/builtin_time.go
Expand Up @@ -14,5 +14,28 @@ func GetTimeDefinitions() (defs []Definition) {
return NewInteger(big.NewInt(time.Now().UTC().Unix()))
},
})
defs = append(defs, Definition{
Name: "Pause",
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
if len(this.Parts) != 2 {
return this
}
nInt, nIsInt := this.Parts[1].(*Integer)
nFlt, nIsFlt := this.Parts[1].(*Flt)
if !nIsInt && !nIsFlt {
return this
}
var duration time.Duration
if nIsInt {
duration = time.Duration(nInt.Val.Int64() * 1000000000)
}
if nIsFlt {
asFlt, _ := nFlt.Val.Float64()
duration = time.Duration(asFlt * 1000000000)
}
time.Sleep(duration)
return NewSymbol("System`Null")
},
})
return
}
5 changes: 5 additions & 0 deletions expreduce/builtin_trig.go
Expand Up @@ -24,22 +24,27 @@ func GetTrigDefinitions() (defs []Definition) {
defs = append(defs, Definition{
Name: "Sin",
legacyEvalFn: mathFnOneParam(math.Sin),
toString: simpleTeXToString("sin"),
})
defs = append(defs, Definition{
Name: "Cos",
legacyEvalFn: mathFnOneParam(math.Cos),
toString: simpleTeXToString("cos"),
})
defs = append(defs, Definition{
Name: "Tan",
legacyEvalFn: mathFnOneParam(math.Tan),
toString: simpleTeXToString("tan"),
})
defs = append(defs, Definition{
Name: "ArcTan",
legacyEvalFn: mathFnOneParam(math.Atan),
toString: simpleTeXToString("tan^{-1}"),
})
defs = append(defs, Definition{
Name: "Cot",
legacyEvalFn: mathFnOneParam(func(x float64) float64 {return 1/math.Tan(x)}),
toString: simpleTeXToString("cot"),
})
defs = append(defs, Definition{
Name: "TrigExpand",
Expand Down
14 changes: 12 additions & 2 deletions expreduce/cas_test.go
Expand Up @@ -176,10 +176,10 @@ func TestLowLevel(t *testing.T) {
assert.Equal(t, "(a*b*c*d*e*f)", EasyRun("a * b * c *d *e *f", es))

CasAssertSame(t, es, "2", "iubjndxuier = 2")
_, containsTest := es.defined["Global`iubjndxuier"]
_, containsTest := es.defined.Get("Global`iubjndxuier")
assert.True(t, containsTest)
es.ClearAll()
_, containsTest = es.defined["Global`iubjndxuier"]
_, containsTest = es.defined.Get("Global`iubjndxuier")
assert.False(t, containsTest)

// Test raw recursion speed
Expand Down Expand Up @@ -261,4 +261,14 @@ func TestConcurrency(t *testing.T) {
}(t, i, es1)
}
wg.Wait()

// Test concurrent MarkSeen.
for i := 0; i < 1000; i++ {
wg.Add(1)
go func (t *testing.T, i int, es *EvalState) {
defer wg.Done()
es.MarkSeen("uniqueIdentifierForMarkSeen")
}(t, i, es1)
}
wg.Wait()
}
15 changes: 10 additions & 5 deletions expreduce/caslogger.go
Expand Up @@ -5,18 +5,19 @@ import (
"github.com/op/go-logging"
"os"
"runtime/debug"
"sync"
)

var format = logging.MustStringFormatter(
//`%{color}%{time:15:04:05.000} %{callpath} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}`,
`%{color}%{time:15:04:05.000} %{callpath} ▶ %{id:03x}%{color:reset} %{message}`,
)
var goLoggingMutex = &sync.Mutex{}

type CASLogger struct {
_log *logging.Logger
leveled logging.LeveledBackend
debugState bool
isProfiling bool
_log *logging.Logger
leveled logging.LeveledBackend
debugState bool
isProfiling bool
}

func (this *CASLogger) Debugf(fmt string, args ...interface{}) {
Expand Down Expand Up @@ -69,9 +70,13 @@ func (this *CASLogger) Pre() string {
}

func (this *CASLogger) SetUpLogging() {
// go-logging appears to not be thread safe, so we have a mutex when
// configuring the logging.
goLoggingMutex.Lock()
this._log = logging.MustGetLogger("example")
backend := logging.NewLogBackend(os.Stderr, "", 0)
formatter := logging.NewBackendFormatter(backend, format)
this.leveled = logging.AddModuleLevel(formatter)
logging.SetBackend(this.leveled)
goLoggingMutex.Unlock()
}

0 comments on commit c09c1bd

Please sign in to comment.