Skip to content

Commit

Permalink
Add support for Module.
Browse files Browse the repository at this point in the history
  • Loading branch information
corywalker committed Jul 5, 2017
1 parent 75093a8 commit 1710acd
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 2 deletions.
99 changes: 99 additions & 0 deletions expreduce/builtin_system.go
Expand Up @@ -526,5 +526,104 @@ func GetSystemDefinitions() (defs []Definition) {
return &Symbol{"$Failed"}
},
})
defs = append(defs, Definition{
Name: "Module",
Usage: "`Module[{locals}, expr]` evaluates `expr` with the local variables `locals`.",
Attributes: []string{"HoldAll"},
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
// Coarse parsing of arguments.
if len(this.Parts) != 3 {
return this
}
locals, localsIsList := HeadAssertion(this.Parts[1], "List")
if !localsIsList {
return this
}
mnExpr, mnIsDef := es.GetSymDef("$ModuleNumber")
if !mnIsDef {
return this
}
mnInteger, mnIsInt := mnExpr.(*Integer)
if !mnIsInt {
return this
}
mn := mnInteger.Val.Int64()

// Parse locals into a struct
type parsedLocal struct {
sym *Symbol
uniqueName string
setValue Ex
isSet bool
isSetDelayed bool
}
var parsedLocals []parsedLocal
for _, localEx := range locals.Parts[1:] {
pl := parsedLocal{}
symEx := localEx
localSet, localIsSet := HeadAssertion(localEx, "Set")
pl.isSet = localIsSet
localSetDelayed, localIsSetDelayed := HeadAssertion(localEx, "SetDelayed")
pl.isSetDelayed = localIsSetDelayed
if localIsSet && len(localSet.Parts) == 3 {
symEx = localSet.Parts[1]
pl.setValue = localSet.Parts[2]
}
if localIsSetDelayed && len(localSetDelayed.Parts) == 3 {
symEx = localSetDelayed.Parts[1]
pl.setValue = localSetDelayed.Parts[2]
}
localSym, localIsSym := symEx.(*Symbol)
pl.sym = localSym
if !localIsSym {
return this
}
parsedLocals = append(parsedLocals, pl)
}

// Find the next ModuleNumber to use.
tryingNew := true
for tryingNew {
tryingNew = false
for i := range parsedLocals {
parsedLocals[i].uniqueName = fmt.Sprintf("%v$%v", parsedLocals[i].sym.Name, mn)
if es.IsDef(parsedLocals[i].uniqueName) {
mn += 1
tryingNew = true
break
}
}
}
es.Define(&Symbol{"$ModuleNumber"}, &Integer{big.NewInt(mn+1)})
toReturn := this.Parts[2]
for _, pl := range parsedLocals {
if pl.isSet || pl.isSetDelayed {
rhs := pl.setValue
if pl.isSet {
rhs = rhs.Eval(es)
}
es.defined[pl.uniqueName] = Def{
downvalues: []Expression{*NewExpression([]Ex{&Symbol{"Rule"}, &Symbol{pl.uniqueName}, rhs})},
}
} else {
es.defined[pl.uniqueName] = Def{}
}
toReturn = ReplaceAll(toReturn,
NewExpression([]Ex{
&Symbol{"Rule"},
&Symbol{pl.sym.Name},
&Symbol{pl.uniqueName},
}), es, EmptyPD(), "")
}
return toReturn
},
Tests: []TestInstruction{
&SameTest{"{t$1,j$1,2}", "$ModuleNumber=1;Module[{t,j},{t,j,$ModuleNumber}]"},
&SameTest{"{t$2,j$2,3}", "$ModuleNumber=1;Module[{t,j},{t,j,$ModuleNumber}]"},
&SameTest{"{t$4,j$4,5}", "$ModuleNumber=1;t$3=test;Module[{t,j},{t,j,$ModuleNumber}]"},
&SameTest{"{t$8,2,9}", "$ModuleNumber=8;t$3=test;Module[{t,j=2},{t,j,$ModuleNumber}]"},
&SameTest{"{t$9,2,10}", "$ModuleNumber=8;t$3=test;Module[{t,j:=2},{t,j,$ModuleNumber}]"},
},
})
return
}
14 changes: 12 additions & 2 deletions expreduce/evalstate.go
Expand Up @@ -124,9 +124,13 @@ func NewEvalStateNoLog(loadAllDefs bool) *EvalState {
return &es
}

func (this *EvalState) GetDef(name string, lhs Ex) (Ex, bool, *Expression) {
func (this *EvalState) IsDef(name string) bool {
_, isd := this.defined[name]
if !isd {
return isd
}

func (this *EvalState) GetDef(name string, lhs Ex) (Ex, bool, *Expression) {
if !this.IsDef(name) {
return nil, false, nil
}
this.Debugf("Inside GetDef(\"%s\",%s)", name, lhs)
Expand Down Expand Up @@ -156,6 +160,12 @@ func (this *EvalState) GetDef(name string, lhs Ex) (Ex, bool, *Expression) {
return nil, false, nil
}

func (this *EvalState) GetSymDef(name string) (Ex, bool) {
sym := &Symbol{name}
symDef, isDef, _ := this.GetDef(name, sym)
return symDef, isDef
}

func (this *EvalState) Define(lhs Ex, rhs Ex) {
if this.IsFrozen() {
return
Expand Down
1 change: 1 addition & 0 deletions expreduce/resources/init.er
@@ -1,3 +1,4 @@
(* This file is executed upon initialization. *)
SeedRandom[UnixTime[]];
$Version = "Expreduce";
$ModuleNumber = 1;
1 change: 1 addition & 0 deletions expreduce/resources/power.er
Expand Up @@ -20,6 +20,7 @@ PolynomialQ[p_.*v_^Optional[exp_Integer], v_] :=
If[FreeQ[p, v] && Positive[exp], True, False];
PolynomialQ[p_, v_] := If[FreeQ[p, v], True, False];

(* Needs PrependTo and DeleteDuplicates and Module *)
Exponent[expr_/p_Plus,var_,head_]:=Exponent[expr,var,head];
Exponent[expr_,var_,head_]:=Module[{e=expr,v=var,h=head,theCases,toCheck},
toCheck=expr//Expand;
Expand Down

0 comments on commit 1710acd

Please sign in to comment.