aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/README.TXT
blob: a1beeb6fb62d2a9581046686abe31912b6d32962 (plain)
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
YPOS: YieldProlog for OpenSim

 a compiler from Prolog to OpenSim compatible C# scripts

Ported by Kino Coursey and Douglas Miles at Daxtron Labs.
Based on Jeff Thompson Yield Prolog,  http://yieldprolog.sourceforge.net/
For Prolog see  http://en.wikipedia.org/wiki/Prolog


INTRODUCTION

This folder contains code to implement a Prolog compiler using the "Yield Statement" found in C#, Javascript, and Python.
The original Yield Prolog system can transform Prolog programs into C# code.
In this system we detect and extract YieldProlog code (with "//YP" as the first four characters in the script) and seperate it from any c# code ("marked by "//CS").
The YP code is transformed to C# and prepended to the "//CS" section, and passed as a bundel to the existing C# compiler.
The end result is Prolog can interface to OpenSim using the existing "//CS" functionality, and C# can call the compiled Prolog.
As such YP allows both declaritive and procedural programming in a 3D script enabled environment.

FEATURES
* Allows implementation of logic programming for objects and agents.
* C#/Javascript/Python as intermediate language
* Yield Prolog has relatively high speed of execution which is important in OpenSim.  http://yieldprolog.sourceforge.net/benchmarks.html
* It is compatable with the existing C#/Mono based system.
* Yield Prolog is BSD license
* Calling Prolog from C# scripts
* Calling C# functions (with LSL and OS functions) from Prolog
* Prolog dynamic database
* Edinburgh, Cocksin & Mellish style syntax.
* Compiler is generated by compiling the Prolog descrition of itself into C#
* Same script entry interface as LSL


TODO 
* Utilize ability to generate Javascript and Python code
* Integrate Prolog database with Sim
* Translation error reporting back to the editor
* Communications via message passing
* Interface to external inference engines

POSSIBILITIES
* Inworld expert systems
* Parallel logic programming and expert systems
* Ontology based processing
* Knowledge based alerting, accessing and business rules
   For instance, listen on channel x, filter the events and broadcast alerts on channel y
     or send IM, emails etc.


USAGE:

Add "yp" as an allowed compiler
 
OpenSim.ini 
[ScriptEngine.DotNetEngine]
AllowedCompilers=lsl,cs,js,vb,yp

Enter scripts using the inworld editing process. Scripts have the following format.
The first line of a file must have "//yp".

//yp
<PROLOG CODE>
//CS
<CS CODE>






C# code calling a Prolog Predicate:
-----------------------------------
The Prolog predicate is transformed into a C# boolean function. So the general calling format is:
	foreach( bool var in  prolog_predicate(ARGS)) {};

I/O is via using a string reader and writer in conjunction with YP.See() and YP.Tell()

            StringWriter PrologOutuput= new StringWriter();
            StringReader PrologInput= new StringReader(myInputString);
            YP.see(PrologInput);
            YP.tell(PrologOutuput);
	    <CALL PROLOG CODE HERE>
	    YP.seen();
	    YP.told();
	    StringBuilder builder = PrologOutput.GetStringBuilder();
	    string finaloutput = builder.ToString();

Any prolog reads and writes will be to the passed StringReader and StringWriter. In fact any TextReader/TextWriter class can be used.

Strings in Prolog are stored as Atom's and you need to use an Atom object to match.

\\yp
wanted('bob').
\\cs
string Who="bob";
foreach( bool ans in wanted(Atom.a(Who) )){};


Prolog code calling a C# function:
-----------------------------------
The prolog code uses the script_event('name_of_function',ARGS) builtin, which is transformed into the function call.
The C# function called uses "PrologCallback" and returns a boolean.



Dynamic database assertions:
-----------------------------------

void assertdb2(string predicate, string arg1, string arg2)
{
        name = Atom.a(predicate);
        YP.assertFact(name, new object[] { arg1, arg2 });
}

void retractdb2(string predicate, string arg1, string arg2)
{
        name = Atom.a(predicate);
        YP.retractFact(name, new object[] { arg1, arg2 });
}


========================= APPENDIX A: touch test ================================


 ===================================
Input YP Code
 ===================================
//yp
 mydb('field2','field1').
 mydb('andy','jane').
 mydb('carl','dan').
 mydb('andy','bill').
 mydb('andy','betty').
 
 call_me(X):-mydb(X,Y) , respond(Y).
 respond(X):- script_event('sayit',X).

//cs
  public void default_event_touch_start(int N ) 
  {
      llSay(0,"pstart1");
      foreach( bool ans in call_me(Atom.a(@"andy") )){};
      llSay(0,"pstop2");
  }
  
  public void default_event_state_entry()
  {
     llSay(0,"prolog tester active.");  
  }

PrologCallback sayit(object ans)
  {
      llSay(0,"sayit1");
      string msg = "one answer is :"+((Variable)ans).getValue();  
      llSay(0,msg); 
      yield return false;
  }


 ===================================
Generated CS Code
 ===================================
using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog;using OpenSim.Region.ScriptEngine.Common; using System.Collections.Generic;
namespace SecondLife { public class Script : OpenSim.Region.ScriptEngine.Common.BuiltIn_Commands_BaseClass { 
static OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP YP=null;public Script() {  YP= new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP(); } 
//cs
  public void default_event_touch_start(int N ) 
  {
      llSay(0,"pstart1");
      foreach( bool ans in call_me(Atom.a(@"carl") )){};
      llSay(0,"pstop2");
  }
  
  public void default_event_state_entry()
  {
     llSay(0,"prolog tester active.");  
  }

public IEnumerable<bool>  sayit(object ans)
  {
      llSay(0,"sayit1");
      string msg = "one answer is :"+((Variable)ans).getValue();  
      llSay(0,msg); 
      yield return false;
  }


//YPEncoded
public IEnumerable<bool> mydb(object arg1, object arg2) {
  {
    foreach (bool l2 in YP.unify(arg1, Atom.a(@"carl"))) {
      foreach (bool l3 in YP.unify(arg2, Atom.a(@"dan"))) {
        yield return false;
      }
    }
  }
  {
    foreach (bool l2 in YP.unify(arg1, Atom.a(@"andy"))) {
      foreach (bool l3 in YP.unify(arg2, Atom.a(@"bill"))) {
        yield return false;
      }
    }
  }
  {
    foreach (bool l2 in YP.unify(arg1, Atom.a(@"andy"))) {
      foreach (bool l3 in YP.unify(arg2, Atom.a(@"betty"))) {
        yield return false;
      }
    }
  }
}

public IEnumerable<bool> call_me(object X) {
  {
    Variable Y = new Variable();
    foreach (bool l2 in mydb(X, Y)) {
      foreach (bool l3 in respond(Y)) {
        yield return false;
      }
    }
  }
}

public IEnumerable<bool> respond(object X) {
  {
    foreach (bool l2 in this.sayit( X)) {
      yield return false;
    }
  }
}

} }



========================= APPENDIX B:SENSOR INFORMED SCRIPT =====================


 ===================================
Input YP Code
 ===================================
//yp

nop.

good('Daxxon Kinoc').
good('Fluffy Kitty').

bad('Eric Evil').
bad('Spikey Plant').

prolog_notify(X) :- good(X) , script_event('accept',X).
prolog_notify(X) :- bad(X) , script_event('reject',X).


//cs

public void default_event_state_entry()
  {
     llSay(0,"prolog sensor tester active.");

    // Start a sensor looking for Agents
     llSensorRepeat("","",AGENT, 10, PI,20); 

  }

public void default_event_sensor(int number_detected )
{
  int i;
  for(i=0;i< number_detected ;i++)
   {
    string dName = llDetectedName(i);
    string dOwner = llDetectedName(i);
    foreach(bool response in prolog_notify(Atom.a(dName)) ){};
    foreach(bool response in prolog_notify(dOwner) ){};
    llSay(0,"Saw "+dName);
   }
}

string decodeToString(object obj)
{
    if (obj is Variable) { return (string) ((Variable)obj).getValue();}
    if (obj is Atom) { return (string) ((Atom)obj)._name;}
    return "unknown type";
}

PrologCallback accept(object ans)
  {
      string msg = "Welcoming :"+decodeToString(ans);  
      llSay(0,msg); 
      yield return false;
  }

PrologCallback reject(object ans)
  {
      string msg = "Watching :"+decodeToString(ans);  
      llSay(0,msg); 
      yield return false;
  }


 ===================================
Generated CS Code
 ===================================

using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog; using OpenSim.Region.ScriptEngine.Common; using System.Collections.Generic;
namespace SecondLife { public class Script : OpenSim.Region.ScriptEngine.Common.BuiltIn_Commands_BaseClass { 
static OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP YP=null; public Script() {  YP= new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP(); } 
//cs

public void default_event_state_entry()
  {
     llSay(0,"prolog sensor tester active.");

    // Start a sensor looking for Agents
     llSensorRepeat("","",AGENT, 10, PI,20); 

  }

public void default_event_sensor(int number_detected )
{
  int i;
  for(i=0;i< number_detected ;i++)
   {
    string dName = llDetectedName(i);
    string dOwner = llDetectedName(i);
    foreach(bool response in prolog_notify(Atom.a(dName)) ){};
    foreach(bool response in prolog_notify(dOwner) ){};
    llSay(0,"Saw "+dName);
   }
}

string decodeToString(object obj)
{
    if (obj is Variable) { return (string) ((Variable)obj).getValue();}
    if (obj is Atom) { return (string) ((Atom)obj)._name;}
    return "unknown type";
}

public IEnumerable<bool>  accept(object ans)
  {
      string msg = "Welcoming :"+decodeToString(ans);  
      llSay(0,msg); 
      yield return false;
  }

public IEnumerable<bool>  reject(object ans)
  {
      string msg = "Watching :"+decodeToString(ans);  
      llSay(0,msg); 
      yield return false;
  }


//YPEncoded
public IEnumerable<bool> yp_nop_header_nop() {
  {
    yield return false;
  }
}

public IEnumerable<bool> good(object arg1) {
  {
    foreach (bool l2 in YP.unify(arg1, Atom.a(@"Daxxon Kinoc"))) {
      yield return false;
    }
  }
  {
    foreach (bool l2 in YP.unify(arg1, Atom.a(@"Fluffy Kitty"))) {
      yield return false;
    }
  }
}

public IEnumerable<bool> bad(object arg1) {
  {
    foreach (bool l2 in YP.unify(arg1, Atom.a(@"Eric Evil"))) {
      yield return false;
    }
  }
  {
    foreach (bool l2 in YP.unify(arg1, Atom.a(@"Spikey Plant"))) {
      yield return false;
    }
  }
}

public IEnumerable<bool> prolog_notify(object X) {
  {
    foreach (bool l2 in good(X)) {
      foreach (bool l3 in this.accept( X)) {
        yield return false;
      }
    }
  }
  {
    foreach (bool l2 in bad(X)) {
      foreach (bool l3 in this.reject( X)) {
        yield return false;
      }
    }
  }
}

} }