diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/README.TXT | 514 |
1 files changed, 0 insertions, 514 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/README.TXT b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/README.TXT deleted file mode 100644 index 3c11938..0000000 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/README.TXT +++ /dev/null | |||
@@ -1,514 +0,0 @@ | |||
1 | YPOS: YieldProlog for OpenSim | ||
2 | |||
3 | a compiler from Prolog to OpenSim compatible C# scripts | ||
4 | |||
5 | Ported by Kino Coursey and Douglas Miles at Daxtron Labs. | ||
6 | Based on Jeff Thompson Yield Prolog, http://yieldprolog.sourceforge.net/ | ||
7 | For Prolog see http://en.wikipedia.org/wiki/Prolog | ||
8 | |||
9 | |||
10 | INTRODUCTION | ||
11 | |||
12 | This folder contains code to implement a Prolog compiler using the "Yield Statement" found in C#, Javascript, and Python. | ||
13 | The original Yield Prolog system can transform Prolog programs into C# code. | ||
14 | 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"). | ||
15 | The YP code is transformed to C# and prepended to the "//CS" section, and passed as a bundel to the existing C# compiler. | ||
16 | The end result is Prolog can interface to OpenSim using the existing "//CS" functionality, and C# can call the compiled Prolog. | ||
17 | As such YP allows both declaritive and procedural programming in a 3D script enabled environment. | ||
18 | |||
19 | FEATURES | ||
20 | * Allows implementation of logic programming for objects and agents. | ||
21 | * C#/Javascript/Python as intermediate language | ||
22 | * Yield Prolog has relatively high speed of execution which is important in OpenSim. http://yieldprolog.sourceforge.net/benchmarks.html | ||
23 | * It is compatable with the existing C#/Mono based system. | ||
24 | * Yield Prolog is BSD license | ||
25 | * Calling Prolog from C# scripts | ||
26 | * Calling C# functions (with LSL and OS functions) from Prolog | ||
27 | * Prolog dynamic database | ||
28 | * Edinburgh, Cocksin & Mellish style syntax. | ||
29 | * Compiler is generated by compiling the Prolog descrition of itself into C# | ||
30 | * Same script entry interface as LSL | ||
31 | |||
32 | * Yield Prolog 1.0.1 Released : it passes all but 9 of the 421 tests in the ISO Prolog test suite (97.8%). | ||
33 | |||
34 | TODO | ||
35 | * Utilize ability to generate Javascript and Python code | ||
36 | * Integrate Prolog database with Sim | ||
37 | * Translation error reporting back to the editor | ||
38 | * Communications via message passing | ||
39 | * Interface to external inference engines | ||
40 | |||
41 | POSSIBILITIES | ||
42 | * Inworld expert systems | ||
43 | * Parallel logic programming and expert systems | ||
44 | * Ontology based processing | ||
45 | * Knowledge based alerting, accessing and business rules | ||
46 | For instance, listen on channel x, filter the events and broadcast alerts on channel y | ||
47 | or send IM, emails etc. | ||
48 | |||
49 | |||
50 | USAGE: | ||
51 | |||
52 | Add "yp" as an allowed compiler | ||
53 | |||
54 | OpenSim.ini | ||
55 | [ScriptEngine.DotNetEngine] | ||
56 | AllowedCompilers=lsl,cs,js,vb,yp | ||
57 | |||
58 | Enter scripts using the inworld editing process. Scripts have the following format. | ||
59 | The first line of a file must have "//yp". | ||
60 | |||
61 | //yp | ||
62 | <PROLOG CODE> | ||
63 | //CS | ||
64 | <CS CODE> | ||
65 | |||
66 | |||
67 | |||
68 | |||
69 | |||
70 | |||
71 | C# code calling a Prolog Predicate: | ||
72 | ----------------------------------- | ||
73 | The Prolog predicate is transformed into a C# boolean function. So the general calling format is: | ||
74 | foreach( bool var in prolog_predicate(ARGS)) {}; | ||
75 | |||
76 | I/O is via using a string reader and writer in conjunction with YP.See() and YP.Tell() | ||
77 | |||
78 | StringWriter PrologOutuput= new StringWriter(); | ||
79 | StringReader PrologInput= new StringReader(myInputString); | ||
80 | YP.see(PrologInput); | ||
81 | YP.tell(PrologOutuput); | ||
82 | <CALL PROLOG CODE HERE> | ||
83 | YP.seen(); | ||
84 | YP.told(); | ||
85 | StringBuilder builder = PrologOutput.GetStringBuilder(); | ||
86 | string finaloutput = builder.ToString(); | ||
87 | |||
88 | Any prolog reads and writes will be to the passed StringReader and StringWriter. In fact any TextReader/TextWriter class can be used. | ||
89 | |||
90 | Strings in Prolog are stored as Atom's and you need to use an Atom object to match. | ||
91 | |||
92 | \\yp | ||
93 | wanted('bob'). | ||
94 | \\cs | ||
95 | string Who="bob"; | ||
96 | foreach( bool ans in wanted(Atom.a(Who) )){}; | ||
97 | |||
98 | |||
99 | Prolog code calling a C# function: | ||
100 | ----------------------------------- | ||
101 | The prolog code uses the script_event('name_of_function',ARGS) builtin, which is transformed into the function call. | ||
102 | The C# function called uses "PrologCallback" and returns a boolean. | ||
103 | |||
104 | |||
105 | |||
106 | Dynamic database assertions: | ||
107 | ----------------------------------- | ||
108 | |||
109 | void assertdb2(string predicate, string arg1, string arg2) | ||
110 | { | ||
111 | name = Atom.a(predicate); | ||
112 | YP.assertFact(name, new object[] { arg1, arg2 }); | ||
113 | } | ||
114 | |||
115 | void retractdb2(string predicate, string arg1, string arg2) | ||
116 | { | ||
117 | name = Atom.a(predicate); | ||
118 | YP.retractFact(name, new object[] { arg1, arg2 }); | ||
119 | } | ||
120 | |||
121 | ----------- IMPORT EXTERNAL FUNCTIONS ---------- | ||
122 | Using 'import' to call a static function | ||
123 | |||
124 | Taken mostly from http://yieldprolog.sourceforge.net/tutorial4.html | ||
125 | |||
126 | If we want to call a static function but it is not defined in the Prolog code, we can simply add an import directive. | ||
127 | (In Prolog, if you start a line with :- it is a directive to the compiler. Don't forget to end with a period.): | ||
128 | |||
129 | :- import('', [parent/2]). | ||
130 | uncle(Person, Uncle):- parent(Person, Parent), brother(Parent, Uncle). | ||
131 | |||
132 | The import directive has two arguments. | ||
133 | The first argument is the module where the imported function is found, which is always ''. | ||
134 | For C#, this means the imported function is in the same class as the calling function. | ||
135 | For Javascript and Python, this means the imported function is in the global scope. | ||
136 | The second argument to import is the comma-separated list of imported functions, where each member of the list is 'name/n', where 'name' is the name of the function and 'n' is the number of arguments. | ||
137 | In this example, parent has two arguments, so we use parent/2. | ||
138 | |||
139 | Note: you can use an imported function in a dynamically defined goal, or a function in another class. | ||
140 | |||
141 | :- import('', [parent/2]). | ||
142 | uncle(Person, Uncle) :- Goal = parent(Person, Parent), Goal, brother(Parent, Uncle). | ||
143 | |||
144 | :- import('', ['OtherClass.parent'/2]). | ||
145 | uncle(Person, Uncle) :- 'OtherClass.parent'(Person, Parent), brother(Parent, Uncle). | ||
146 | |||
147 | --------- Round-about Hello Wonderful world ---------- | ||
148 | //yp | ||
149 | :-import('',[sayit/1]). | ||
150 | sayhello(X):-sayit(X). | ||
151 | |||
152 | //cs | ||
153 | public void default_event_state_entry() | ||
154 | { | ||
155 | llSay(0,"prolog hello."); | ||
156 | foreach( bool ans in sayhello(Atom.a(@"wonderful world") )){}; | ||
157 | } | ||
158 | |||
159 | PrologCallback sayit(object ans) | ||
160 | { | ||
161 | llSay(0,"sayit1"); | ||
162 | string msg = "one answer is :"+((Variable)ans).getValue(); | ||
163 | llSay(0,msg); | ||
164 | yield return false; | ||
165 | } | ||
166 | |||
167 | ------------------ UPDATES ----------------- | ||
168 | Yield Prolog 1.0 Released : It passes all but 15 of the 421 tests in the ISO Prolog test suite. | ||
169 | |||
170 | New Features: | ||
171 | * Added support for Prolog predicates read and read_term. | ||
172 | * In see, Added support for a char code list as the input. | ||
173 | Using this as the input for "fred" makes | ||
174 | set_prolog_flag(double_quotes, atom) and | ||
175 | set_prolog_flag(double_quotes, chars) pass the ISO test suite. | ||
176 | |||
177 | Fixed Bugs: | ||
178 | * In atom_chars, check for unbound tail in the char list. | ||
179 | This makes atom_chars pass the ISO test suite. | ||
180 | * In current_predicate, also check for static functions. | ||
181 | This makes current_predicate pass the ISO test suite. | ||
182 | |||
183 | Known Issues: | ||
184 | |||
185 | Here are the 9 errors of the 421 tests in the ISO test suite in | ||
186 | YieldProlog\source\prolog\isoTestSuite.P . | ||
187 | Some of these have a good excuse for why Yield Prolog produces the error. The rest will be addressed in a future maintenance release. | ||
188 | |||
189 | Goal: call((fail, 1)) | ||
190 | Expected: type_error(callable, (fail, 1)) | ||
191 | Extra Solutions found: failure | ||
192 | |||
193 | Goal: call((write(3), 1)) | ||
194 | Expected: type_error(callable, (write(3), 1)) | ||
195 | Extra Solutions found: type_error(callable, 1) | ||
196 | |||
197 | Goal: call((1; true)) | ||
198 | Expected: type_error(callable, (1 ; true)) | ||
199 | Extra Solutions found: type_error(callable, 1) | ||
200 | |||
201 | Goal: (catch(true, C, write('something')), throw(blabla)) | ||
202 | Expected: system_error | ||
203 | Extra Solutions found: unexpected_ball(blabla) | ||
204 | |||
205 | Goal: catch(number_chars(A,L), error(instantiation_error, _), fail) | ||
206 | Expected: failure | ||
207 | Extra Solutions found: instantiation_error | ||
208 | |||
209 | Goal: Goal: (X = 1 + 2, 'is'(Y, X * 3)) | ||
210 | Expected: [[X <-- (1 + 2), Y <-- 9]] | ||
211 | Extra Solutions found: type_error(evaluable, /(+, 2)) | ||
212 | |||
213 | Goal: 'is'(77, N) | ||
214 | Expected: instantiation_error | ||
215 | Extra Solutions found: N <-- 77) | ||
216 | |||
217 | Goal: \+(!, fail) | ||
218 | Expected: success | ||
219 | Extra Solutions found: failure | ||
220 | |||
221 | ((X=1;X=2), \+((!,fail))) | ||
222 | Expected: [[X <-- 1],[X <-- 2]] | ||
223 | Extra Solutions found: failure | ||
224 | |||
225 | |||
226 | |||
227 | |||
228 | |||
229 | ========================= APPENDIX A: touch test ================================ | ||
230 | |||
231 | |||
232 | =================================== | ||
233 | Input YP Code | ||
234 | =================================== | ||
235 | //yp | ||
236 | mydb('field2','field1'). | ||
237 | mydb('andy','jane'). | ||
238 | mydb('carl','dan'). | ||
239 | mydb('andy','bill'). | ||
240 | mydb('andy','betty'). | ||
241 | |||
242 | call_me(X):-mydb(X,Y) , respond(Y). | ||
243 | respond(X):- script_event('sayit',X). | ||
244 | |||
245 | //cs | ||
246 | public void default_event_touch_start(int N ) | ||
247 | { | ||
248 | llSay(0,"pstart1"); | ||
249 | foreach( bool ans in call_me(Atom.a(@"andy") )){}; | ||
250 | llSay(0,"pstop2"); | ||
251 | } | ||
252 | |||
253 | public void default_event_state_entry() | ||
254 | { | ||
255 | llSay(0,"prolog tester active."); | ||
256 | } | ||
257 | |||
258 | PrologCallback sayit(object ans) | ||
259 | { | ||
260 | llSay(0,"sayit1"); | ||
261 | string msg = "one answer is :"+((Variable)ans).getValue(); | ||
262 | llSay(0,msg); | ||
263 | yield return false; | ||
264 | } | ||
265 | |||
266 | |||
267 | =================================== | ||
268 | Generated CS Code | ||
269 | =================================== | ||
270 | using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog;using OpenSim.Region.ScriptEngine.Common; using System.Collections.Generic; | ||
271 | namespace SecondLife { public class Script : OpenSim.Region.ScriptEngine.Common.ScriptBaseClass { | ||
272 | static OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP YP=null;public Script() { YP= new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP(); } | ||
273 | //cs | ||
274 | public void default_event_touch_start(int N ) | ||
275 | { | ||
276 | llSay(0,"pstart1"); | ||
277 | foreach( bool ans in call_me(Atom.a(@"carl") )){}; | ||
278 | llSay(0,"pstop2"); | ||
279 | } | ||
280 | |||
281 | public void default_event_state_entry() | ||
282 | { | ||
283 | llSay(0,"prolog tester active."); | ||
284 | } | ||
285 | |||
286 | public IEnumerable<bool> sayit(object ans) | ||
287 | { | ||
288 | llSay(0,"sayit1"); | ||
289 | string msg = "one answer is :"+((Variable)ans).getValue(); | ||
290 | llSay(0,msg); | ||
291 | yield return false; | ||
292 | } | ||
293 | |||
294 | |||
295 | //YPEncoded | ||
296 | public IEnumerable<bool> mydb(object arg1, object arg2) { | ||
297 | { | ||
298 | foreach (bool l2 in YP.unify(arg1, Atom.a(@"carl"))) { | ||
299 | foreach (bool l3 in YP.unify(arg2, Atom.a(@"dan"))) { | ||
300 | yield return false; | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | { | ||
305 | foreach (bool l2 in YP.unify(arg1, Atom.a(@"andy"))) { | ||
306 | foreach (bool l3 in YP.unify(arg2, Atom.a(@"bill"))) { | ||
307 | yield return false; | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | { | ||
312 | foreach (bool l2 in YP.unify(arg1, Atom.a(@"andy"))) { | ||
313 | foreach (bool l3 in YP.unify(arg2, Atom.a(@"betty"))) { | ||
314 | yield return false; | ||
315 | } | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | |||
320 | public IEnumerable<bool> call_me(object X) { | ||
321 | { | ||
322 | Variable Y = new Variable(); | ||
323 | foreach (bool l2 in mydb(X, Y)) { | ||
324 | foreach (bool l3 in respond(Y)) { | ||
325 | yield return false; | ||
326 | } | ||
327 | } | ||
328 | } | ||
329 | } | ||
330 | |||
331 | public IEnumerable<bool> respond(object X) { | ||
332 | { | ||
333 | foreach (bool l2 in this.sayit( X)) { | ||
334 | yield return false; | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | |||
339 | } } | ||
340 | |||
341 | |||
342 | |||
343 | ========================= APPENDIX B:SENSOR INFORMED SCRIPT ===================== | ||
344 | |||
345 | |||
346 | =================================== | ||
347 | Input YP Code | ||
348 | =================================== | ||
349 | //yp | ||
350 | |||
351 | nop. | ||
352 | |||
353 | good('Daxxon Kinoc'). | ||
354 | good('Fluffy Kitty'). | ||
355 | |||
356 | bad('Eric Evil'). | ||
357 | bad('Spikey Plant'). | ||
358 | |||
359 | prolog_notify(X) :- good(X) , script_event('accept',X). | ||
360 | prolog_notify(X) :- bad(X) , script_event('reject',X). | ||
361 | |||
362 | |||
363 | //cs | ||
364 | |||
365 | public void default_event_state_entry() | ||
366 | { | ||
367 | llSay(0,"prolog sensor tester active."); | ||
368 | |||
369 | // Start a sensor looking for Agents | ||
370 | llSensorRepeat("","",AGENT, 10, PI,20); | ||
371 | |||
372 | } | ||
373 | |||
374 | public void default_event_sensor(int number_detected ) | ||
375 | { | ||
376 | int i; | ||
377 | for(i=0;i< number_detected ;i++) | ||
378 | { | ||
379 | string dName = llDetectedName(i); | ||
380 | string dOwner = llDetectedName(i); | ||
381 | foreach(bool response in prolog_notify(Atom.a(dName)) ){}; | ||
382 | foreach(bool response in prolog_notify(dOwner) ){}; | ||
383 | llSay(0,"Saw "+dName); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | string decodeToString(object obj) | ||
388 | { | ||
389 | if (obj is Variable) { return (string) ((Variable)obj).getValue();} | ||
390 | if (obj is Atom) { return (string) ((Atom)obj)._name;} | ||
391 | return "unknown type"; | ||
392 | } | ||
393 | |||
394 | PrologCallback accept(object ans) | ||
395 | { | ||
396 | string msg = "Welcoming :"+decodeToString(ans); | ||
397 | llSay(0,msg); | ||
398 | yield return false; | ||
399 | } | ||
400 | |||
401 | PrologCallback reject(object ans) | ||
402 | { | ||
403 | string msg = "Watching :"+decodeToString(ans); | ||
404 | llSay(0,msg); | ||
405 | yield return false; | ||
406 | } | ||
407 | |||
408 | |||
409 | =================================== | ||
410 | Generated CS Code | ||
411 | =================================== | ||
412 | |||
413 | using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog; using OpenSim.Region.ScriptEngine.Common; using System.Collections.Generic; | ||
414 | namespace SecondLife { public class Script : OpenSim.Region.ScriptEngine.Common.ScriptBaseClass { | ||
415 | static OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP YP=null; public Script() { YP= new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP(); } | ||
416 | //cs | ||
417 | |||
418 | public void default_event_state_entry() | ||
419 | { | ||
420 | llSay(0,"prolog sensor tester active."); | ||
421 | |||
422 | // Start a sensor looking for Agents | ||
423 | llSensorRepeat("","",AGENT, 10, PI,20); | ||
424 | |||
425 | } | ||
426 | |||
427 | public void default_event_sensor(int number_detected ) | ||
428 | { | ||
429 | int i; | ||
430 | for(i=0;i< number_detected ;i++) | ||
431 | { | ||
432 | string dName = llDetectedName(i); | ||
433 | string dOwner = llDetectedName(i); | ||
434 | foreach(bool response in prolog_notify(Atom.a(dName)) ){}; | ||
435 | foreach(bool response in prolog_notify(dOwner) ){}; | ||
436 | llSay(0,"Saw "+dName); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | string decodeToString(object obj) | ||
441 | { | ||
442 | if (obj is Variable) { return (string) ((Variable)obj).getValue();} | ||
443 | if (obj is Atom) { return (string) ((Atom)obj)._name;} | ||
444 | return "unknown type"; | ||
445 | } | ||
446 | |||
447 | public IEnumerable<bool> accept(object ans) | ||
448 | { | ||
449 | string msg = "Welcoming :"+decodeToString(ans); | ||
450 | llSay(0,msg); | ||
451 | yield return false; | ||
452 | } | ||
453 | |||
454 | public IEnumerable<bool> reject(object ans) | ||
455 | { | ||
456 | string msg = "Watching :"+decodeToString(ans); | ||
457 | llSay(0,msg); | ||
458 | yield return false; | ||
459 | } | ||
460 | |||
461 | |||
462 | //YPEncoded | ||
463 | public IEnumerable<bool> yp_nop_header_nop() { | ||
464 | { | ||
465 | yield return false; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | public IEnumerable<bool> good(object arg1) { | ||
470 | { | ||
471 | foreach (bool l2 in YP.unify(arg1, Atom.a(@"Daxxon Kinoc"))) { | ||
472 | yield return false; | ||
473 | } | ||
474 | } | ||
475 | { | ||
476 | foreach (bool l2 in YP.unify(arg1, Atom.a(@"Fluffy Kitty"))) { | ||
477 | yield return false; | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | |||
482 | public IEnumerable<bool> bad(object arg1) { | ||
483 | { | ||
484 | foreach (bool l2 in YP.unify(arg1, Atom.a(@"Eric Evil"))) { | ||
485 | yield return false; | ||
486 | } | ||
487 | } | ||
488 | { | ||
489 | foreach (bool l2 in YP.unify(arg1, Atom.a(@"Spikey Plant"))) { | ||
490 | yield return false; | ||
491 | } | ||
492 | } | ||
493 | } | ||
494 | |||
495 | public IEnumerable<bool> prolog_notify(object X) { | ||
496 | { | ||
497 | foreach (bool l2 in good(X)) { | ||
498 | foreach (bool l3 in this.accept( X)) { | ||
499 | yield return false; | ||
500 | } | ||
501 | } | ||
502 | } | ||
503 | { | ||
504 | foreach (bool l2 in bad(X)) { | ||
505 | foreach (bool l3 in this.reject( X)) { | ||
506 | yield return false; | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | |||
512 | } } | ||
513 | |||
514 | |||