-
Notifications
You must be signed in to change notification settings - Fork 15
/
Perl5Interpreter.cs
215 lines (174 loc) · 6.83 KB
/
Perl5Interpreter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
using Niecza;
using System.Runtime.InteropServices;
using System;
using Niecza.Serialization;
public class Perl5Interpreter : IForeignInterpreter {
[DllImport("p5embed", EntryPoint="p5embed_initialize")]
public static extern void Initialize();
[DllImport("p5embed", EntryPoint="p5embed_dispose")]
public static extern void Dispose();
[DllImport("p5embed", EntryPoint="p5embed_eval")]
public static extern IntPtr EvalPerl5(string code);
[DllImport("p5embed", EntryPoint="p5embed_SvIV")]
public static extern int SvIV(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_SvPV_nolen")]
public static extern string SvPV_nolen(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_SvPVutf8_nolen")]
public static extern IntPtr SvPVutf8_nolen(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_SvPVutf8_length")]
public static extern int SvPVutf8_length(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_SvNV")]
public static extern double SvNV(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_SvIOKp")]
public static extern int SvIOKp(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_SvNOKp")]
public static extern int SvNOKp(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_SvPOKp")]
public static extern int SvPOKp(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_SvOK")]
public static extern int SvOK(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_newSVpvn")]
public static extern IntPtr newSVpvn(IntPtr s,int length);
[DllImport("p5embed", EntryPoint="p5embed_SvUTF8_on")]
public static extern void SvUTF8_on(IntPtr sv);
[DllImport("p5embed", EntryPoint="p5embed_subcall")]
public static extern IntPtr SubCall(
int context,
IntPtr[] arguments,
int argument_n
);
// We can't use the standard char* conversion because some strings can contain nulls
public static string UnmarshalString(IntPtr sv) {
int len = SvPVutf8_length(sv);
byte[] target = new byte[len];
IntPtr data = SvPVutf8_nolen(sv);
Marshal.Copy(data, target, 0, len);
return System.Text.Encoding.UTF8.GetString(target);
}
public static Variable SVToVariable(IntPtr sv) {
if (sv == IntPtr.Zero) {
//TODO: check - cargo culted
return Kernel.NilP.mo.typeVar;
}
if (SvOK(sv) == 0) {
return Kernel.NilP.mo.typeVar;
}
if (SvIOKp(sv) != 0) {
return Builtins.MakeInt(SvIV(sv));
} else if (SvNOKp(sv) != 0) {
return Builtins.MakeFloat(SvNV(sv));
} else if (SvPOKp(sv) != 0) {
string s = UnmarshalString(sv); //SvPV_nolen(sv);
return Kernel.BoxAnyMO(s, Kernel.StrMO);
} else {
return new SVVariable(sv);
}
}
public Perl5Interpreter() {
Initialize();
}
~Perl5Interpreter() {
Dispose();
}
public Variable Eval(string code) {
IntPtr sv = EvalPerl5(code);
return SVToVariable(sv);
}
}
public class SVVariable : Variable {
public IntPtr sv;
public SVVariable(IntPtr _sv) {
sv = _sv;
}
public override P6any Fetch() {
return new SVany(sv);
}
public override void Store(P6any v) {
}
public override Variable GetVar() {
return Kernel.BoxAnyMO<Variable>(this, Kernel.ScalarMO);
}
public override void Freeze(FreezeBuffer fb) {
throw new NieczaException("Freezing perl5 SV* NYI.");
}
}
public class SVany : P6any {
[DllImport("obj/p5embed.so", EntryPoint="p5method_call")]
public static extern IntPtr MethodCall(
string name,
IntPtr[] arguments,
int argument_n
);
public override void Freeze(FreezeBuffer fb) {
throw new NieczaException("Freezing perl5 SV* NYI.");
}
// We can't use the standard char* conversion because some strings can contain nulls
public static IntPtr MarshalString(string s) {
byte[] array = System.Text.Encoding.UTF8.GetBytes(s);
int size = Marshal.SizeOf(typeof(byte)) * (array.Length + 1);
IntPtr ptr = Marshal.AllocHGlobal(size);
/* This is a hack not to crash on mono!!! */
//allocated.Add(ptr, null);
Marshal.Copy(array, 0, ptr, array.Length);
Marshal.WriteByte(ptr, array.Length, 0);
IntPtr sv = Perl5Interpreter.newSVpvn(ptr,array.Length);
Perl5Interpreter.SvUTF8_on(sv);
Marshal.FreeHGlobal(ptr);
return sv;
}
public static IntPtr VariableToSV(Variable var) {
P6any obj = var.Fetch();
if (obj is SVany) {
return ((SVany)obj).sv;
} else if (obj.Does(Kernel.StrMO)) {
string s = Kernel.UnboxAny<string>(obj);
return MarshalString(s);
} else {
throw new NieczaException("can't convert argument to p5 type");
}
}
static int Context(Variable var) {
P6any obj = var.Fetch();
string s = Kernel.UnboxAny<string>(obj);
if (s == "list") {
return 0;
} else if (s == "scalar") {
return 1;
} else if (s == "void") {
return 2;
} else {
throw new NieczaException("unknown p5 context type: "+s);
}
}
static IntPtr[] MarshalPositionals(Variable[] pos) {
IntPtr[] args = new IntPtr[pos.Length];
for (int i=0;i<pos.Length;i++) {
args[i] = VariableToSV(pos[i]);
}
return args;
}
public IntPtr sv;
public override Frame InvokeMethod(Frame caller, string name,
Variable[] pos, VarHash named) {
if (name == "postcircumfix:<( )>") {
int context = 1;
if (named != null && named["context"] != null) {
context = Context(named["context"]);
}
IntPtr[] args = MarshalPositionals(pos);
IntPtr ret = Perl5Interpreter.SubCall(context,args,args.Length);
caller.resultSlot = Perl5Interpreter.SVToVariable(ret);
return caller;
} else {
IntPtr[] args = MarshalPositionals(pos);
IntPtr ret = MethodCall(name,args,args.Length);
caller.resultSlot = Perl5Interpreter.SVToVariable(ret);
}
return caller;
}
public override string ReprName() { return "P6opaque"; }
public SVany(IntPtr _sv) {
mo = Kernel.AnyMO;
sv = _sv;
}
}