Skip to content

Commit eb96b8f

Browse files
authored
Merge pull request #98 from fremling/master
Problem partially solved by escaping and unescaping dollars
2 parents 5f6c5d0 + 8532e20 commit eb96b8f

File tree

2 files changed

+170
-11
lines changed

2 files changed

+170
-11
lines changed

src/eval.jl

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ wevalstr(expr) = wevalstr(Any, expr)
6565
Parse a string `str` as a Wolfram Language expression.
6666
"""
6767
function parseexpr(str::AbstractString)
68-
r = weval(W"ToExpression"(str, W"StandardForm", W"Hold"))
68+
UnescapedDollar=unescape_dollar(str)
69+
r = weval(W"ToExpression"(UnescapedDollar, W"StandardForm", W"Hold"))
6970
r.args[1]
7071
end
7172

@@ -75,8 +76,16 @@ end
7576
Parse a string `expr` as a Wolfram Language expression.
7677
"""
7778
macro W_cmd(str)
79+
#This macro takes the expresion within ` ` and feeds it to we wolfram engine using
80+
# the function parseexpr(string). The result is then back-converted to a julia MathLink expression.
7881
#quote parseexpr($(esc(Meta.parse("\"$(escape_string(str))\"")))) end
79-
string_expr = Meta.parse("\"$(escape_string(str))\"")
82+
83+
###Adding a set of string escapes for correct parsing
84+
EscapedString=escape_string(str)
85+
DollarString=escape_dollar(EscapedString)
86+
FullString="\"$(DollarString)\""
87+
##Doing the parsing!
88+
string_expr = Meta.parse(FullString)
8089
subst_dict = Dict{WSymbol,Any}()
8190
if string_expr isa String
8291
string = string_expr
@@ -97,6 +106,28 @@ macro W_cmd(str)
97106
to_julia_expr(wexpr, subst_dict)
98107
end
99108

109+
"""
110+
escape_dollar(str::AbstractString)
111+
112+
Escapes the '\$' character to create a correct string interpretation when these are present.
113+
"""
114+
function escape_dollar(str::AbstractString)
115+
####This function explicitly escapes the $ character to create a correct string interpretation when dollars are present.
116+
return replace(str,'\$'=>"\\\$")
117+
end
118+
"""
119+
unescape_dollar(str::AbstractString)
120+
121+
Un-escapes the '\$' character to create a correct string command to send to weval.
122+
"""
123+
function unescape_dollar(str::AbstractString)
124+
####This function explicitly escapes the $ character to create a correct string interpretation when dollars are present.
125+
return replace(str,"\\\$"=>'\$')
126+
end
127+
128+
129+
130+
100131
function to_julia_expr(wexpr::WExpr, subst_dict)
101132
head = to_julia_expr(wexpr.head, subst_dict)
102133
args = map(x->to_julia_expr(x, subst_dict), wexpr.args)

test/runtests.jl

Lines changed: 137 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,112 @@ using Test
44
import MathLink: WExpr, WSymbol
55

66

7+
8+
@testset "interpolation" begin
9+
set_GreedyEval(false)
10+
x = exp(1)
11+
@test W`Sin[$x]` == W"Sin"(x)
12+
@test W`Cos[$(log(2))]` == W"Cos"(log(2))
13+
14+
@test W`Sin[$(1.2e19)]` == W`Sin[1.2*^19]`
15+
@test string(W`Sin[$(1.2e19)]`) == "W`Sin[1.2*^19]`"
16+
end
17+
18+
19+
function TestMeta(x)
20+
#println("M '",x,"'")
21+
return Meta.parse(x)
22+
end
23+
24+
function TestEscape(x)
25+
#println("E '",x,"'")
26+
return escape_string(x)
27+
end
28+
29+
function EscapeDollar(str::AbstractString)
30+
#println("R '",str,"'")
31+
return replace(str,'\$'=>"\\\$")
32+
end
33+
34+
@testset "Conversion of strange characters" begin
35+
a="!"
36+
println("Test with variable after")
37+
###Test with variable after
38+
@test TestMeta("\"$a\"") == "!"
39+
@test TestMeta("\"\$a\"") == :("$(a)")
40+
###Invalid escape sequence
41+
@test_throws Base.Meta.ParseError("invalid escape sequence") TestMeta("\"\\$a\"")
42+
@test TestMeta("\"\\\$a\"") == "\$a"
43+
@test TestMeta("\"\\\\$a\"") == "\\!"
44+
@test TestMeta("\"\\\\\$a\"") == :("\\$(a)")
45+
@test_throws Base.Meta.ParseError("invalid escape sequence") TestMeta("\"\\\\\\$a\"")
46+
47+
println("Test with no variable after")
48+
###Test with no variable after
49+
### TestMeta("\"$\"") ###Invalid syntax
50+
@test_throws Base.Meta.ParseError TestMeta("\"\$\"")
51+
### TestMeta("\"\\$\"") ###Invalid syntax
52+
@test TestMeta("\"\\\$\"") == "\$"
53+
### TestMeta("\"\\\\$\"") ###Invalid syntax
54+
@test_throws Base.Meta.ParseError TestMeta("\"\\\\\$\"")
55+
### TestMeta("\"\\\\\\$\"") ###Invalid syntax
56+
@test TestMeta("\"\\\\\\\$\"") == "\\\$"
57+
58+
println("Test escaped strings")
59+
### Test escaped strings
60+
@test TestEscape("\$") == "\$"
61+
@test TestEscape("\\\$") == "\\\\\$"
62+
@test TestEscape("\\\\\$") == "\\\\\\\\\$"
63+
@test TestEscape("\$\$") == "\$\$"
64+
@test TestEscape("\\\$\$") == "\\\\\$\$"
65+
@test TestEscape("\\\\\$\$") == "\\\\\\\\\$\$"
66+
67+
println("Test escaped strings")
68+
@test EscapeDollar("\$") == "\\\$"
69+
@test EscapeDollar("\\\$") == "\\\\\$"
70+
@test EscapeDollar("\\\\\$") == "\\\\\\\$"
71+
@test EscapeDollar("\$\$") == "\\\$\\\$"
72+
@test EscapeDollar("\\\$\$") == "\\\\\$\\\$"
73+
@test EscapeDollar("\\\\\$\$") == "\\\\\\\$\\\$"
74+
75+
set_GreedyEval(false)
76+
println("Test math on the symbols")
77+
@test weval(WSymbol("a")+WSymbol("a")) == weval(2*WSymbol("a"))
78+
@test weval(WSymbol("\$")+WSymbol("\$")) == weval(2*WSymbol("\$"))
79+
println("Test creating the symbol")
80+
###Test creating the symbol
81+
@test W`a` == WSymbol("a")
82+
@test W`a` == W"a"
83+
@test W`\$` == WSymbol("\$")
84+
85+
86+
println("Test creating the symbol string")
87+
###Test creating the symbol string
88+
@test W`"a"` == "a"
89+
@test W`"\$"` == "\$"
90+
91+
92+
println("Other tests")
93+
@test W`"\$"` == "\$"
94+
@test W`"a"` == "a"
95+
@test W`{a -> b}` == W"List"(W"Rule"(W"a",W"b"))
96+
@test W`{"a" -> "b"}` == W"List"(W"Rule"("a","b"))
97+
@test W`"a" -> "b"` == W"Rule"("a","b")
98+
@test W`a -> b` == W"Rule"(W"a",W"b")
99+
@test W`"b(\$)a"` == "b(\$)a"
100+
@test W`"b\\\$"` == "b\\\$"
101+
@test W`"b\$"` == "b\$"
102+
@test W`"$a"` == "\$a"
103+
@test W`"$"` == "\$"
104+
@test W`"$"` == "\$"
105+
@test W`"$" -> "b"` == W"Rule"("\$","b")
106+
@test W`{"$" -> "b"}` == W"List"(W"Rule"("\$","b"))
107+
@test W`{"a" -> "$"}` == W"List"(W"Rule"("a","\$"))
108+
@test W`{a -> "$"}` == W"List"(W"Rule"(W"a","\$"))
109+
110+
end
111+
112+
7113
@testset "W2JuliaExpr" begin
8114
###Test of a simple MathLink to Julia converter. It converts MathLink expressions to the correcsponding Julia constructions
9115
@testset "Variables" begin
@@ -196,15 +302,6 @@ end
196302
@test weval(W"Dot"(A,x)) == WExpr(W"List",A*x)
197303
end
198304

199-
@testset "interpolation" begin
200-
x = exp(1)
201-
@test W`Sin[$x]` == W"Sin"(x)
202-
@test W`Cos[$(log(2))]` == W"Cos"(log(2))
203-
204-
@test W`Sin[$(1.2e19)]` == W`Sin[1.2*^19]`
205-
@test string(W`Sin[$(1.2e19)]`) == "W`Sin[1.2*^19]`"
206-
end
207-
208305

209306

210307
@testset "README" begin
@@ -358,3 +455,34 @@ end
358455
@test !showable("text/latex",W"a"+W"b")
359456
end
360457

458+
459+
460+
461+
@testset "String conversions floats" begin
462+
###A few special tests to solve issue 94
463+
###https://github.com/JuliaInterop/MathLink.jl/issues/94
464+
465+
466+
####
467+
### weval(W"ToExpression"("17.0000000000000000000000000", W"StandardForm", W"Hold"))
468+
469+
s="17.000000000"
470+
@test MathLink.parseexpr(s) == s
471+
s="17.0000000000"
472+
@test MathLink.parseexpr(s) == s
473+
s="17.00000000000"
474+
@test MathLink.parseexpr(s) == s
475+
s="17.000000000000"
476+
@test MathLink.parseexpr(s) == s
477+
s="17.0000000000000"
478+
@test MathLink.parseexpr(s) == s
479+
s="17.00000000000000"
480+
@test MathLink.parseexpr(s) == s
481+
482+
@test W`17.000000000` == 17.0
483+
@test W`17.000000000000` == 17.0
484+
@test W`17.00000000000000000` == 17.0
485+
@test W`17.000000000000000000000` == 17.0
486+
487+
end
488+

0 commit comments

Comments
 (0)