Compiler Connection! One world, one compiler!
parent
0313a1d439
commit
d8c470343e
|
@ -1,946 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSim Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Tools;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
|
|
||||||
{
|
|
||||||
public class CSCodeGenerator
|
|
||||||
{
|
|
||||||
private SYMBOL m_astRoot = null;
|
|
||||||
private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap;
|
|
||||||
private int m_indentWidth = 4; // for indentation
|
|
||||||
private int m_braceCount; // for indentation
|
|
||||||
private int m_CSharpLine; // the current line of generated C# code
|
|
||||||
private int m_CSharpCol; // the current column of generated C# code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an 'empty' CSCodeGenerator instance.
|
|
||||||
/// </summary>
|
|
||||||
public CSCodeGenerator()
|
|
||||||
{
|
|
||||||
ResetCounters();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the mapping between LSL and C# line/column number.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Dictionary\<KeyValuePair\<int, int\>, KeyValuePair\<int, int\>\>.</returns>
|
|
||||||
public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> PositionMap
|
|
||||||
{
|
|
||||||
get { return m_positionMap; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the mapping between LSL and C# line/column number.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>SYMBOL pointing to root of the abstract syntax tree.</returns>
|
|
||||||
public SYMBOL ASTRoot
|
|
||||||
{
|
|
||||||
get { return m_astRoot; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets various counters and metadata.
|
|
||||||
/// </summary>
|
|
||||||
private void ResetCounters()
|
|
||||||
{
|
|
||||||
m_braceCount = 0;
|
|
||||||
m_CSharpLine = 0;
|
|
||||||
m_CSharpCol = 1;
|
|
||||||
m_positionMap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
|
|
||||||
m_astRoot = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate the code from the AST we have.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="script">The LSL source as a string.</param>
|
|
||||||
/// <returns>String containing the generated C# code.</returns>
|
|
||||||
public string Convert(string script)
|
|
||||||
{
|
|
||||||
ResetCounters();
|
|
||||||
Parser p = new LSLSyntax(new yyLSLSyntax(), new ErrorHandler(true));
|
|
||||||
// Obviously this needs to be in a try/except block.
|
|
||||||
LSL2CSCodeTransformer codeTransformer = new LSL2CSCodeTransformer(p.Parse(script));
|
|
||||||
m_astRoot = codeTransformer.Transform();
|
|
||||||
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
// standard preamble
|
|
||||||
//retstr = GenerateLine("using OpenSim.Region.ScriptEngine.Common;");
|
|
||||||
//retstr += GenerateLine("using System.Collections.Generic;");
|
|
||||||
//retstr += GenerateLine("");
|
|
||||||
//retstr += GenerateLine("namespace SecondLife");
|
|
||||||
//retstr += GenerateLine("{");
|
|
||||||
m_braceCount++;
|
|
||||||
//retstr += GenerateIndentedLine("public class Script : OpenSim.Region.ScriptEngine.Common");
|
|
||||||
//retstr += GenerateIndentedLine("{");
|
|
||||||
m_braceCount++;
|
|
||||||
|
|
||||||
// line number
|
|
||||||
m_CSharpLine += 3;
|
|
||||||
|
|
||||||
// here's the payload
|
|
||||||
retstr += GenerateLine();
|
|
||||||
foreach (SYMBOL s in m_astRoot.kids)
|
|
||||||
retstr += GenerateNode(s);
|
|
||||||
|
|
||||||
// close braces!
|
|
||||||
m_braceCount--;
|
|
||||||
//retstr += GenerateIndentedLine("}");
|
|
||||||
m_braceCount--;
|
|
||||||
//retstr += GenerateLine("}");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recursively called to generate each type of node. Will generate this
|
|
||||||
/// node, then all it's children.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">The current node to generate code for.</param>
|
|
||||||
/// <returns>String containing C# code for SYMBOL s.</returns>
|
|
||||||
private string GenerateNode(SYMBOL s)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
// make sure to put type lower in the inheritance hierarchy first
|
|
||||||
// ie: since IdentArgument and ExpressionArgument inherit from
|
|
||||||
// Argument, put IdentArgument and ExpressionArgument before Argument
|
|
||||||
if (s is GlobalFunctionDefinition)
|
|
||||||
retstr += GenerateGlobalFunctionDefinition((GlobalFunctionDefinition) s);
|
|
||||||
else if (s is GlobalVariableDeclaration)
|
|
||||||
retstr += GenerateGlobalVariableDeclaration((GlobalVariableDeclaration) s);
|
|
||||||
else if (s is State)
|
|
||||||
retstr += GenerateState((State) s);
|
|
||||||
else if (s is CompoundStatement)
|
|
||||||
retstr += GenerateCompoundStatement((CompoundStatement) s);
|
|
||||||
else if (s is Declaration)
|
|
||||||
retstr += GenerateDeclaration((Declaration) s);
|
|
||||||
else if (s is Statement)
|
|
||||||
retstr += GenerateStatement((Statement) s);
|
|
||||||
else if (s is ReturnStatement)
|
|
||||||
retstr += GenerateReturnStatement((ReturnStatement) s);
|
|
||||||
else if (s is JumpLabel)
|
|
||||||
retstr += GenerateJumpLabel((JumpLabel) s);
|
|
||||||
else if (s is JumpStatement)
|
|
||||||
retstr += GenerateJumpStatement((JumpStatement) s);
|
|
||||||
else if (s is StateChange)
|
|
||||||
retstr += GenerateStateChange((StateChange) s);
|
|
||||||
else if (s is IfStatement)
|
|
||||||
retstr += GenerateIfStatement((IfStatement) s);
|
|
||||||
else if (s is WhileStatement)
|
|
||||||
retstr += GenerateWhileStatement((WhileStatement) s);
|
|
||||||
else if (s is DoWhileStatement)
|
|
||||||
retstr += GenerateDoWhileStatement((DoWhileStatement) s);
|
|
||||||
else if (s is ForLoop)
|
|
||||||
retstr += GenerateForLoop((ForLoop) s);
|
|
||||||
else if (s is ArgumentList)
|
|
||||||
retstr += GenerateArgumentList((ArgumentList) s);
|
|
||||||
else if (s is Assignment)
|
|
||||||
retstr += GenerateAssignment((Assignment) s);
|
|
||||||
else if (s is BinaryExpression)
|
|
||||||
retstr += GenerateBinaryExpression((BinaryExpression) s);
|
|
||||||
else if (s is ParenthesisExpression)
|
|
||||||
retstr += GenerateParenthesisExpression((ParenthesisExpression) s);
|
|
||||||
else if (s is UnaryExpression)
|
|
||||||
retstr += GenerateUnaryExpression((UnaryExpression) s);
|
|
||||||
else if (s is IncrementDecrementExpression)
|
|
||||||
retstr += GenerateIncrementDecrementExpression((IncrementDecrementExpression) s);
|
|
||||||
else if (s is TypecastExpression)
|
|
||||||
retstr += GenerateTypecastExpression((TypecastExpression) s);
|
|
||||||
else if (s is FunctionCall)
|
|
||||||
retstr += GenerateFunctionCall((FunctionCall) s);
|
|
||||||
else if (s is VectorConstant)
|
|
||||||
retstr += GenerateVectorConstant((VectorConstant) s);
|
|
||||||
else if (s is RotationConstant)
|
|
||||||
retstr += GenerateRotationConstant((RotationConstant) s);
|
|
||||||
else if (s is ListConstant)
|
|
||||||
retstr += GenerateListConstant((ListConstant) s);
|
|
||||||
else if (s is Constant)
|
|
||||||
retstr += GenerateConstant((Constant) s);
|
|
||||||
else if (s is IdentDotExpression)
|
|
||||||
retstr += Generate(((IdentDotExpression) s).Name + "." + ((IdentDotExpression) s).Member, s);
|
|
||||||
else if (s is IdentExpression)
|
|
||||||
retstr += Generate(((IdentExpression) s).Name, s);
|
|
||||||
else if (s is IDENT)
|
|
||||||
retstr += Generate(((TOKEN) s).yytext, s);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (SYMBOL kid in s.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a GlobalFunctionDefinition node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="gf">The GlobalFunctionDefinition node.</param>
|
|
||||||
/// <returns>String containing C# code for GlobalFunctionDefinition gf.</returns>
|
|
||||||
private string GenerateGlobalFunctionDefinition(GlobalFunctionDefinition gf)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
// we need to separate the argument declaration list from other kids
|
|
||||||
List<SYMBOL> argumentDeclarationListKids = new List<SYMBOL>();
|
|
||||||
List<SYMBOL> remainingKids = new List<SYMBOL>();
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in gf.kids)
|
|
||||||
if (kid is ArgumentDeclarationList)
|
|
||||||
argumentDeclarationListKids.Add(kid);
|
|
||||||
else
|
|
||||||
remainingKids.Add(kid);
|
|
||||||
|
|
||||||
retstr += GenerateIndented(String.Format("{0} {1}(", gf.ReturnType, gf.Name), gf);
|
|
||||||
|
|
||||||
// print the state arguments, if any
|
|
||||||
foreach (SYMBOL kid in argumentDeclarationListKids)
|
|
||||||
retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
|
|
||||||
|
|
||||||
retstr += GenerateLine(")");
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in remainingKids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a GlobalVariableDeclaration node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="gv">The GlobalVariableDeclaration node.</param>
|
|
||||||
/// <returns>String containing C# code for GlobalVariableDeclaration gv.</returns>
|
|
||||||
private string GenerateGlobalVariableDeclaration(GlobalVariableDeclaration gv)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
foreach (SYMBOL s in gv.kids)
|
|
||||||
{
|
|
||||||
retstr += Indent();
|
|
||||||
retstr += GenerateNode(s);
|
|
||||||
retstr += GenerateLine(";");
|
|
||||||
}
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a State node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">The State node.</param>
|
|
||||||
/// <returns>String containing C# code for State s.</returns>
|
|
||||||
private string GenerateState(State s)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in s.kids)
|
|
||||||
if (kid is StateEvent)
|
|
||||||
retstr += GenerateStateEvent((StateEvent) kid, s.Name);
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a StateEvent node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="se">The StateEvent node.</param>
|
|
||||||
/// <param name="parentStateName">The name of the parent state.</param>
|
|
||||||
/// <returns>String containing C# code for StateEvent se.</returns>
|
|
||||||
private string GenerateStateEvent(StateEvent se, string parentStateName)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
// we need to separate the argument declaration list from other kids
|
|
||||||
List<SYMBOL> argumentDeclarationListKids = new List<SYMBOL>();
|
|
||||||
List<SYMBOL> remainingKids = new List<SYMBOL>();
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in se.kids)
|
|
||||||
if (kid is ArgumentDeclarationList)
|
|
||||||
argumentDeclarationListKids.Add(kid);
|
|
||||||
else
|
|
||||||
remainingKids.Add(kid);
|
|
||||||
|
|
||||||
// "state" (function) declaration
|
|
||||||
retstr += GenerateIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name), se);
|
|
||||||
|
|
||||||
// print the state arguments, if any
|
|
||||||
foreach (SYMBOL kid in argumentDeclarationListKids)
|
|
||||||
retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
|
|
||||||
|
|
||||||
retstr += GenerateLine(")");
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in remainingKids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for an ArgumentDeclarationList node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="adl">The ArgumentDeclarationList node.</param>
|
|
||||||
/// <returns>String containing C# code for ArgumentDeclarationList adl.</returns>
|
|
||||||
private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
int comma = adl.kids.Count - 1; // tells us whether to print a comma
|
|
||||||
|
|
||||||
foreach (Declaration d in adl.kids)
|
|
||||||
{
|
|
||||||
retstr += Generate(String.Format("{0} {1}", d.Datatype, d.Id), d);
|
|
||||||
if (0 < comma--)
|
|
||||||
retstr += Generate(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for an ArgumentList node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="al">The ArgumentList node.</param>
|
|
||||||
/// <returns>String containing C# code for ArgumentList al.</returns>
|
|
||||||
private string GenerateArgumentList(ArgumentList al)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
int comma = al.kids.Count - 1; // tells us whether to print a comma
|
|
||||||
|
|
||||||
foreach (SYMBOL s in al.kids)
|
|
||||||
{
|
|
||||||
retstr += GenerateNode(s);
|
|
||||||
if (0 < comma--)
|
|
||||||
retstr += Generate(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a CompoundStatement node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cs">The CompoundStatement node.</param>
|
|
||||||
/// <returns>String containing C# code for CompoundStatement cs.</returns>
|
|
||||||
private string GenerateCompoundStatement(CompoundStatement cs)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
// opening brace
|
|
||||||
retstr += GenerateIndentedLine("{");
|
|
||||||
m_braceCount++;
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in cs.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
|
|
||||||
// closing brace
|
|
||||||
m_braceCount--;
|
|
||||||
retstr += GenerateIndentedLine("}");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a Declaration node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="d">The Declaration node.</param>
|
|
||||||
/// <returns>String containing C# code for Declaration d.</returns>
|
|
||||||
private string GenerateDeclaration(Declaration d)
|
|
||||||
{
|
|
||||||
return Generate(String.Format("{0} {1}", d.Datatype, d.Id), d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a Statement node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">The Statement node.</param>
|
|
||||||
/// <returns>String containing C# code for Statement s.</returns>
|
|
||||||
private string GenerateStatement(Statement s)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
bool printSemicolon = true;
|
|
||||||
|
|
||||||
retstr += Indent();
|
|
||||||
|
|
||||||
if (0 < s.kids.Count)
|
|
||||||
{
|
|
||||||
// Jump label prints its own colon, we don't need a semicolon.
|
|
||||||
printSemicolon = !(s.kids.Top is JumpLabel);
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in s.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (printSemicolon)
|
|
||||||
retstr += GenerateLine(";");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for an Assignment node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The Assignment node.</param>
|
|
||||||
/// <returns>String containing C# code for Assignment a.</returns>
|
|
||||||
private string GenerateAssignment(Assignment a)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += GenerateNode((SYMBOL) a.kids.Pop());
|
|
||||||
retstr += Generate(String.Format(" {0} ", a.AssignmentType), a);
|
|
||||||
foreach (SYMBOL kid in a.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a ReturnStatement node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rs">The ReturnStatement node.</param>
|
|
||||||
/// <returns>String containing C# code for ReturnStatement rs.</returns>
|
|
||||||
private string GenerateReturnStatement(ReturnStatement rs)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += Generate("return ", rs);
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in rs.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a JumpLabel node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="jl">The JumpLabel node.</param>
|
|
||||||
/// <returns>String containing C# code for JumpLabel jl.</returns>
|
|
||||||
private string GenerateJumpLabel(JumpLabel jl)
|
|
||||||
{
|
|
||||||
return Generate(String.Format("{0}:\n", jl.LabelName), jl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a JumpStatement node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="js">The JumpStatement node.</param>
|
|
||||||
/// <returns>String containing C# code for JumpStatement js.</returns>
|
|
||||||
private string GenerateJumpStatement(JumpStatement js)
|
|
||||||
{
|
|
||||||
return Generate(String.Format("goto {0}", js.TargetName), js);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for an IfStatement node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ifs">The IfStatement node.</param>
|
|
||||||
/// <returns>String containing C# code for IfStatement ifs.</returns>
|
|
||||||
private string GenerateIfStatement(IfStatement ifs)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += GenerateIndented("if (", ifs);
|
|
||||||
retstr += GenerateNode((SYMBOL) ifs.kids.Pop());
|
|
||||||
retstr += GenerateLine(")");
|
|
||||||
|
|
||||||
// CompoundStatement handles indentation itself but we need to do it
|
|
||||||
// otherwise.
|
|
||||||
bool indentHere = ifs.kids.Top is Statement;
|
|
||||||
if (indentHere) m_braceCount++;
|
|
||||||
retstr += GenerateNode((SYMBOL) ifs.kids.Pop());
|
|
||||||
if (indentHere) m_braceCount--;
|
|
||||||
|
|
||||||
if (0 < ifs.kids.Count) // do it again for an else
|
|
||||||
{
|
|
||||||
retstr += GenerateIndentedLine("else", ifs);
|
|
||||||
|
|
||||||
indentHere = ifs.kids.Top is Statement;
|
|
||||||
if (indentHere) m_braceCount++;
|
|
||||||
retstr += GenerateNode((SYMBOL) ifs.kids.Pop());
|
|
||||||
if (indentHere) m_braceCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a StateChange node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sc">The StateChange node.</param>
|
|
||||||
/// <returns>String containing C# code for StateChange sc.</returns>
|
|
||||||
private string GenerateStateChange(StateChange sc)
|
|
||||||
{
|
|
||||||
return Generate(String.Format("state(\"{0}\")", sc.NewState), sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a WhileStatement node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ws">The WhileStatement node.</param>
|
|
||||||
/// <returns>String containing C# code for WhileStatement ws.</returns>
|
|
||||||
private string GenerateWhileStatement(WhileStatement ws)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += GenerateIndented("while (", ws);
|
|
||||||
retstr += GenerateNode((SYMBOL) ws.kids.Pop());
|
|
||||||
retstr += GenerateLine(")");
|
|
||||||
|
|
||||||
// CompoundStatement handles indentation itself but we need to do it
|
|
||||||
// otherwise.
|
|
||||||
bool indentHere = ws.kids.Top is Statement;
|
|
||||||
if (indentHere) m_braceCount++;
|
|
||||||
retstr += GenerateNode((SYMBOL) ws.kids.Pop());
|
|
||||||
if (indentHere) m_braceCount--;
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a DoWhileStatement node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dws">The DoWhileStatement node.</param>
|
|
||||||
/// <returns>String containing C# code for DoWhileStatement dws.</returns>
|
|
||||||
private string GenerateDoWhileStatement(DoWhileStatement dws)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += GenerateIndentedLine("do", dws);
|
|
||||||
|
|
||||||
// CompoundStatement handles indentation itself but we need to do it
|
|
||||||
// otherwise.
|
|
||||||
bool indentHere = dws.kids.Top is Statement;
|
|
||||||
if (indentHere) m_braceCount++;
|
|
||||||
retstr += GenerateNode((SYMBOL) dws.kids.Pop());
|
|
||||||
if (indentHere) m_braceCount--;
|
|
||||||
|
|
||||||
retstr += GenerateIndented("while (", dws);
|
|
||||||
retstr += GenerateNode((SYMBOL) dws.kids.Pop());
|
|
||||||
retstr += GenerateLine(");");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a ForLoop node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fl">The ForLoop node.</param>
|
|
||||||
/// <returns>String containing C# code for ForLoop fl.</returns>
|
|
||||||
private string GenerateForLoop(ForLoop fl)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += GenerateIndented("for (", fl);
|
|
||||||
|
|
||||||
// for ( x = 0 ; x < 10 ; x++ )
|
|
||||||
// ^^^^^^^
|
|
||||||
retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop());
|
|
||||||
retstr += Generate("; ");
|
|
||||||
// for ( x = 0 ; x < 10 ; x++ )
|
|
||||||
// ^^^^^^^^
|
|
||||||
retstr += GenerateNode((SYMBOL) fl.kids.Pop());
|
|
||||||
retstr += Generate("; ");
|
|
||||||
// for ( x = 0 ; x < 10 ; x++ )
|
|
||||||
// ^^^^^
|
|
||||||
retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop());
|
|
||||||
retstr += GenerateLine(")");
|
|
||||||
|
|
||||||
// CompoundStatement handles indentation itself but we need to do it
|
|
||||||
// otherwise.
|
|
||||||
bool indentHere = fl.kids.Top is Statement;
|
|
||||||
if (indentHere) m_braceCount++;
|
|
||||||
retstr += GenerateNode((SYMBOL) fl.kids.Pop());
|
|
||||||
if (indentHere) m_braceCount--;
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a ForLoopStatement node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fls">The ForLoopStatement node.</param>
|
|
||||||
/// <returns>String containing C# code for ForLoopStatement fls.</returns>
|
|
||||||
private string GenerateForLoopStatement(ForLoopStatement fls)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
int comma = fls.kids.Count - 1; // tells us whether to print a comma
|
|
||||||
|
|
||||||
foreach (SYMBOL s in fls.kids)
|
|
||||||
{
|
|
||||||
retstr += GenerateNode(s);
|
|
||||||
if (0 < comma--)
|
|
||||||
retstr += Generate(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a BinaryExpression node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="be">The BinaryExpression node.</param>
|
|
||||||
/// <returns>String containing C# code for BinaryExpression be.</returns>
|
|
||||||
private string GenerateBinaryExpression(BinaryExpression be)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += GenerateNode((SYMBOL) be.kids.Pop());
|
|
||||||
retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be);
|
|
||||||
foreach (SYMBOL kid in be.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a UnaryExpression node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ue">The UnaryExpression node.</param>
|
|
||||||
/// <returns>String containing C# code for UnaryExpression ue.</returns>
|
|
||||||
private string GenerateUnaryExpression(UnaryExpression ue)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += Generate(ue.UnarySymbol, ue);
|
|
||||||
retstr += GenerateNode((SYMBOL) ue.kids.Pop());
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a ParenthesisExpression node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pe">The ParenthesisExpression node.</param>
|
|
||||||
/// <returns>String containing C# code for ParenthesisExpression pe.</returns>
|
|
||||||
private string GenerateParenthesisExpression(ParenthesisExpression pe)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += Generate("(");
|
|
||||||
foreach (SYMBOL kid in pe.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
retstr += Generate(")");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a IncrementDecrementExpression node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ide">The IncrementDecrementExpression node.</param>
|
|
||||||
/// <returns>String containing C# code for IncrementDecrementExpression ide.</returns>
|
|
||||||
private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
if (0 < ide.kids.Count)
|
|
||||||
{
|
|
||||||
IdentDotExpression dot = (IdentDotExpression) ide.kids.Top;
|
|
||||||
retstr += Generate(String.Format("{0}", ide.PostOperation ? dot.Name + "." + dot.Member + ide.Operation : ide.Operation + dot.Name + "." + dot.Member), ide);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
retstr += Generate(String.Format("{0}", ide.PostOperation ? ide.Name + ide.Operation : ide.Operation + ide.Name), ide);
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a TypecastExpression node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="te">The TypecastExpression node.</param>
|
|
||||||
/// <returns>String containing C# code for TypecastExpression te.</returns>
|
|
||||||
private string GenerateTypecastExpression(TypecastExpression te)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
// we wrap all typecasted statements in parentheses
|
|
||||||
retstr += Generate(String.Format("({0}) (", te.TypecastType), te);
|
|
||||||
retstr += GenerateNode((SYMBOL) te.kids.Pop());
|
|
||||||
retstr += Generate(")");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a FunctionCall node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fc">The FunctionCall node.</param>
|
|
||||||
/// <returns>String containing C# code for FunctionCall fc.</returns>
|
|
||||||
private string GenerateFunctionCall(FunctionCall fc)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += Generate(String.Format("{0}(", fc.Id), fc);
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in fc.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
|
|
||||||
retstr += Generate(")");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a Constant node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="c">The Constant node.</param>
|
|
||||||
/// <returns>String containing C# code for Constant c.</returns>
|
|
||||||
private string GenerateConstant(Constant c)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
// Supprt LSL's weird acceptance of floats with no trailing digits
|
|
||||||
// after the period. Turn float x = 10.; into float x = 10.0;
|
|
||||||
if ("LSL_Types.LSLFloat" == c.Type)
|
|
||||||
{
|
|
||||||
int dotIndex = c.Value.IndexOf('.') + 1;
|
|
||||||
if (0 < dotIndex && (dotIndex == c.Value.Length || !Char.IsDigit(c.Value[dotIndex])))
|
|
||||||
c.Value = c.Value.Insert(dotIndex, "0");
|
|
||||||
c.Value = "new LSL_Types.LSLFloat("+c.Value+")";
|
|
||||||
}
|
|
||||||
else if ("LSL_Types.LSLInteger" == c.Type)
|
|
||||||
{
|
|
||||||
c.Value = "new LSL_Types.LSLInteger("+c.Value+")";
|
|
||||||
}
|
|
||||||
else if ("LSL_Types.LSLString" == c.Type)
|
|
||||||
{
|
|
||||||
c.Value = "new LSL_Types.LSLString(\""+c.Value+"\")";
|
|
||||||
}
|
|
||||||
|
|
||||||
retstr += Generate(c.Value, c);
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a VectorConstant node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="vc">The VectorConstant node.</param>
|
|
||||||
/// <returns>String containing C# code for VectorConstant vc.</returns>
|
|
||||||
private string GenerateVectorConstant(VectorConstant vc)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += Generate(String.Format("new {0}(", vc.Type), vc);
|
|
||||||
retstr += GenerateNode((SYMBOL) vc.kids.Pop());
|
|
||||||
retstr += Generate(", ");
|
|
||||||
retstr += GenerateNode((SYMBOL) vc.kids.Pop());
|
|
||||||
retstr += Generate(", ");
|
|
||||||
retstr += GenerateNode((SYMBOL) vc.kids.Pop());
|
|
||||||
retstr += Generate(")");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a RotationConstant node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rc">The RotationConstant node.</param>
|
|
||||||
/// <returns>String containing C# code for RotationConstant rc.</returns>
|
|
||||||
private string GenerateRotationConstant(RotationConstant rc)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += Generate(String.Format("new {0}(", rc.Type), rc);
|
|
||||||
retstr += GenerateNode((SYMBOL) rc.kids.Pop());
|
|
||||||
retstr += Generate(", ");
|
|
||||||
retstr += GenerateNode((SYMBOL) rc.kids.Pop());
|
|
||||||
retstr += Generate(", ");
|
|
||||||
retstr += GenerateNode((SYMBOL) rc.kids.Pop());
|
|
||||||
retstr += Generate(", ");
|
|
||||||
retstr += GenerateNode((SYMBOL) rc.kids.Pop());
|
|
||||||
retstr += Generate(")");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the code for a ListConstant node.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lc">The ListConstant node.</param>
|
|
||||||
/// <returns>String containing C# code for ListConstant lc.</returns>
|
|
||||||
private string GenerateListConstant(ListConstant lc)
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
retstr += Generate(String.Format("new {0}(", lc.Type), lc);
|
|
||||||
|
|
||||||
foreach (SYMBOL kid in lc.kids)
|
|
||||||
retstr += GenerateNode(kid);
|
|
||||||
|
|
||||||
retstr += Generate(")");
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints a newline.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A newline.</returns>
|
|
||||||
private string GenerateLine()
|
|
||||||
{
|
|
||||||
return GenerateLine("");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints text, followed by a newline.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String of text to print.</param>
|
|
||||||
/// <returns>String s followed by newline.</returns>
|
|
||||||
private string GenerateLine(string s)
|
|
||||||
{
|
|
||||||
return GenerateLine(s, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints text, followed by a newline.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String of text to print.</param>
|
|
||||||
/// <param name="sym">Symbol being generated to extract original line
|
|
||||||
/// number and column from.</param>
|
|
||||||
/// <returns>String s followed by newline.</returns>
|
|
||||||
private string GenerateLine(string s, SYMBOL sym)
|
|
||||||
{
|
|
||||||
string retstr = Generate(s, sym) + "\n";
|
|
||||||
|
|
||||||
m_CSharpLine++;
|
|
||||||
m_CSharpCol = 1;
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints text.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String of text to print.</param>
|
|
||||||
/// <returns>String s.</returns>
|
|
||||||
private string Generate(string s)
|
|
||||||
{
|
|
||||||
return Generate(s, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints text.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String of text to print.</param>
|
|
||||||
/// <param name="sym">Symbol being generated to extract original line
|
|
||||||
/// number and column from.</param>
|
|
||||||
/// <returns>String s.</returns>
|
|
||||||
private string Generate(string s, SYMBOL sym)
|
|
||||||
{
|
|
||||||
if (null != sym)
|
|
||||||
m_positionMap.Add(new KeyValuePair<int, int>(m_CSharpLine, m_CSharpCol), new KeyValuePair<int, int>(sym.Line, sym.Position));
|
|
||||||
|
|
||||||
m_CSharpCol += s.Length;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints text correctly indented, followed by a newline.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String of text to print.</param>
|
|
||||||
/// <returns>Properly indented string s followed by newline.</returns>
|
|
||||||
private string GenerateIndentedLine(string s)
|
|
||||||
{
|
|
||||||
return GenerateIndentedLine(s, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints text correctly indented, followed by a newline.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String of text to print.</param>
|
|
||||||
/// <param name="sym">Symbol being generated to extract original line
|
|
||||||
/// number and column from.</param>
|
|
||||||
/// <returns>Properly indented string s followed by newline.</returns>
|
|
||||||
private string GenerateIndentedLine(string s, SYMBOL sym)
|
|
||||||
{
|
|
||||||
string retstr = GenerateIndented(s, sym) + "\n";
|
|
||||||
|
|
||||||
m_CSharpLine++;
|
|
||||||
m_CSharpCol = 1;
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints text correctly indented.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String of text to print.</param>
|
|
||||||
/// <returns>Properly indented string s.</returns>
|
|
||||||
//private string GenerateIndented(string s)
|
|
||||||
//{
|
|
||||||
// return GenerateIndented(s, null);
|
|
||||||
//}
|
|
||||||
// THIS FUNCTION IS COMMENTED OUT TO SUPPRESS WARNINGS
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints text correctly indented.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String of text to print.</param>
|
|
||||||
/// <param name="sym">Symbol being generated to extract original line
|
|
||||||
/// number and column from.</param>
|
|
||||||
/// <returns>Properly indented string s.</returns>
|
|
||||||
private string GenerateIndented(string s, SYMBOL sym)
|
|
||||||
{
|
|
||||||
string retstr = Indent() + s;
|
|
||||||
|
|
||||||
if (null != sym)
|
|
||||||
m_positionMap.Add(new KeyValuePair<int, int>(m_CSharpLine, m_CSharpCol), new KeyValuePair<int, int>(sym.Line, sym.Position));
|
|
||||||
|
|
||||||
m_CSharpCol += s.Length;
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints correct indentation.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Indentation based on brace count.</returns>
|
|
||||||
private string Indent()
|
|
||||||
{
|
|
||||||
string retstr = String.Empty;
|
|
||||||
|
|
||||||
for (int i = 0; i < m_braceCount; i++)
|
|
||||||
for (int j = 0; j < m_indentWidth; j++)
|
|
||||||
{
|
|
||||||
retstr += " ";
|
|
||||||
m_CSharpCol++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retstr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,509 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSim Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.CodeDom.Compiler;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using Microsoft.CSharp;
|
|
||||||
using Microsoft.JScript;
|
|
||||||
using Microsoft.VisualBasic;
|
|
||||||
using OpenSim.Region.Environment.Interfaces;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
|
|
||||||
{
|
|
||||||
public class Compiler
|
|
||||||
{
|
|
||||||
private static readonly log4net.ILog m_log
|
|
||||||
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
||||||
|
|
||||||
// * Uses "LSL2Converter" to convert LSL to C# if necessary.
|
|
||||||
// * Compiles C#-code into an assembly
|
|
||||||
// * Returns assembly name ready for AppDomain load.
|
|
||||||
//
|
|
||||||
// Assembly is compiled using LSL_BaseClass as base. Look at debug C# code file created when LSL script is compiled for full details.
|
|
||||||
//
|
|
||||||
|
|
||||||
internal enum enumCompileType
|
|
||||||
{
|
|
||||||
lsl = 0,
|
|
||||||
cs = 1,
|
|
||||||
vb = 2,
|
|
||||||
js = 3,
|
|
||||||
yp = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This contains number of lines WE use for header when compiling script. User will get error in line x-LinesToRemoveOnError when error occurs.
|
|
||||||
/// </summary>
|
|
||||||
public int LinesToRemoveOnError = 3;
|
|
||||||
private enumCompileType DefaultCompileLanguage;
|
|
||||||
private bool WriteScriptSourceToDebugFile;
|
|
||||||
private bool CompileWithDebugInformation;
|
|
||||||
// private bool CleanUpOldScriptsOnStartup;
|
|
||||||
private Dictionary<string, bool> AllowedCompilers = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
|
||||||
private Dictionary<string, enumCompileType> LanguageMapping = new Dictionary<string, enumCompileType>(StringComparer.CurrentCultureIgnoreCase);
|
|
||||||
|
|
||||||
private string FilePrefix;
|
|
||||||
private string ScriptEnginesPath = "ScriptEngines";
|
|
||||||
|
|
||||||
private static CSCodeGenerator LSL_Converter = new CSCodeGenerator();
|
|
||||||
private static Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap; // mapping between LSL and C# line/column numbers
|
|
||||||
private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider();
|
|
||||||
private static VBCodeProvider VBcodeProvider = new VBCodeProvider();
|
|
||||||
private static JScriptCodeProvider JScodeProvider = new JScriptCodeProvider();
|
|
||||||
private static CSharpCodeProvider YPcodeProvider = new CSharpCodeProvider(); // YP is translated into CSharp
|
|
||||||
private static YP2CSConverter YP_Converter = new YP2CSConverter();
|
|
||||||
|
|
||||||
private static int instanceID = new Random().Next(0, int.MaxValue); // Unique number to use on our compiled files
|
|
||||||
private static UInt64 scriptCompileCounter = 0; // And a counter
|
|
||||||
|
|
||||||
public ScriptEngine m_scriptEngine;
|
|
||||||
public Compiler(ScriptEngine scriptEngine)
|
|
||||||
{
|
|
||||||
m_scriptEngine = scriptEngine;
|
|
||||||
ReadConfig();
|
|
||||||
}
|
|
||||||
public bool in_startup = true;
|
|
||||||
public void ReadConfig()
|
|
||||||
{
|
|
||||||
|
|
||||||
// Get some config
|
|
||||||
WriteScriptSourceToDebugFile = m_scriptEngine.ScriptConfigSource.GetBoolean("WriteScriptSourceToDebugFile", true);
|
|
||||||
CompileWithDebugInformation = m_scriptEngine.ScriptConfigSource.GetBoolean("CompileWithDebugInformation", true);
|
|
||||||
// CleanUpOldScriptsOnStartup = m_scriptEngine.ScriptConfigSource.GetBoolean("CleanUpOldScriptsOnStartup", true);
|
|
||||||
|
|
||||||
// Get file prefix from scriptengine name and make it file system safe:
|
|
||||||
FilePrefix = m_scriptEngine.ScriptEngineName;
|
|
||||||
foreach (char c in Path.GetInvalidFileNameChars())
|
|
||||||
{
|
|
||||||
FilePrefix = FilePrefix.Replace(c, '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
// First time we start? Delete old files
|
|
||||||
if (in_startup)
|
|
||||||
{
|
|
||||||
in_startup = false;
|
|
||||||
DeleteOldFiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map name and enum type of our supported languages
|
|
||||||
LanguageMapping.Add(enumCompileType.cs.ToString(), enumCompileType.cs);
|
|
||||||
LanguageMapping.Add(enumCompileType.vb.ToString(), enumCompileType.vb);
|
|
||||||
LanguageMapping.Add(enumCompileType.lsl.ToString(), enumCompileType.lsl);
|
|
||||||
LanguageMapping.Add(enumCompileType.js.ToString(), enumCompileType.js);
|
|
||||||
LanguageMapping.Add(enumCompileType.yp.ToString(), enumCompileType.yp);
|
|
||||||
|
|
||||||
// Allowed compilers
|
|
||||||
string allowComp = m_scriptEngine.ScriptConfigSource.GetString("AllowedCompilers", "lsl,cs,vb,js,yp");
|
|
||||||
AllowedCompilers.Clear();
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Allowed languages: " + allowComp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
foreach (string strl in allowComp.Split(','))
|
|
||||||
{
|
|
||||||
string strlan = strl.Trim(" \t".ToCharArray()).ToLower();
|
|
||||||
if (!LanguageMapping.ContainsKey(strlan))
|
|
||||||
{
|
|
||||||
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Config error. Compiler is unable to recognize language type \"" + strlan + "\" specified in \"AllowedCompilers\".");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
//m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Config OK. Compiler recognized language type \"" + strlan + "\" specified in \"AllowedCompilers\".");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
AllowedCompilers.Add(strlan, true);
|
|
||||||
}
|
|
||||||
if (AllowedCompilers.Count == 0)
|
|
||||||
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Config error. Compiler could not recognize any language in \"AllowedCompilers\". Scripts will not be executed!");
|
|
||||||
|
|
||||||
// Default language
|
|
||||||
string defaultCompileLanguage = m_scriptEngine.ScriptConfigSource.GetString("DefaultCompileLanguage", "lsl").ToLower();
|
|
||||||
|
|
||||||
// Is this language recognized at all?
|
|
||||||
if (!LanguageMapping.ContainsKey(defaultCompileLanguage))
|
|
||||||
{
|
|
||||||
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " +
|
|
||||||
"Config error. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is not recognized as a valid language. Changing default to: \"lsl\".");
|
|
||||||
defaultCompileLanguage = "lsl";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this language in allow-list?
|
|
||||||
if (!AllowedCompilers.ContainsKey(defaultCompileLanguage))
|
|
||||||
{
|
|
||||||
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " +
|
|
||||||
"Config error. Default language \"" + defaultCompileLanguage + "\"specified in \"DefaultCompileLanguage\" is not in list of \"AllowedCompilers\". Scripts may not be executed!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
// m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: " +
|
|
||||||
// "Config OK. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is recognized as a valid language.");
|
|
||||||
#endif
|
|
||||||
// LANGUAGE IS IN ALLOW-LIST
|
|
||||||
DefaultCompileLanguage = LanguageMapping[defaultCompileLanguage];
|
|
||||||
}
|
|
||||||
|
|
||||||
// We now have an allow-list, a mapping list, and a default language
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delete old script files
|
|
||||||
/// </summary>
|
|
||||||
private void DeleteOldFiles()
|
|
||||||
{
|
|
||||||
|
|
||||||
// CREATE FOLDER IF IT DOESNT EXIST
|
|
||||||
if (!Directory.Exists(ScriptEnginesPath))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(ScriptEnginesPath);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying to create ScriptEngine directory \"" + ScriptEnginesPath + "\": " + ex.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string file in Directory.GetFiles(ScriptEnginesPath))
|
|
||||||
{
|
|
||||||
//m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: FILE FOUND: " + file);
|
|
||||||
|
|
||||||
if (file.ToLower().StartsWith(FilePrefix + "_compiled_") ||
|
|
||||||
file.ToLower().StartsWith(FilePrefix + "_source_"))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(file);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying delete old script file \"" + file + "\": " + ex.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts script from LSL to CS and calls CompileFromCSText
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Script">LSL script</param>
|
|
||||||
/// <returns>Filename to .dll assembly</returns>
|
|
||||||
public string PerformScriptCompile(string Script)
|
|
||||||
{
|
|
||||||
enumCompileType l = DefaultCompileLanguage;
|
|
||||||
|
|
||||||
|
|
||||||
if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture))
|
|
||||||
l = enumCompileType.cs;
|
|
||||||
if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture))
|
|
||||||
{
|
|
||||||
l = enumCompileType.vb;
|
|
||||||
// We need to remove //vb, it won't compile with that
|
|
||||||
|
|
||||||
Script = Script.Substring(4, Script.Length - 4);
|
|
||||||
}
|
|
||||||
if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture))
|
|
||||||
l = enumCompileType.lsl;
|
|
||||||
|
|
||||||
if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture))
|
|
||||||
l = enumCompileType.js;
|
|
||||||
|
|
||||||
if (Script.StartsWith("//yp", true, CultureInfo.InvariantCulture))
|
|
||||||
l = enumCompileType.yp;
|
|
||||||
|
|
||||||
if (!AllowedCompilers.ContainsKey(l.ToString()))
|
|
||||||
{
|
|
||||||
// Not allowed to compile to this language!
|
|
||||||
string errtext = String.Empty;
|
|
||||||
errtext += "The compiler for language \"" + l.ToString() + "\" is not in list of allowed compilers. Script will not be executed!";
|
|
||||||
throw new Exception(errtext);
|
|
||||||
}
|
|
||||||
|
|
||||||
string compileScript = Script;
|
|
||||||
|
|
||||||
if (l == enumCompileType.lsl)
|
|
||||||
{
|
|
||||||
// Its LSL, convert it to C#
|
|
||||||
compileScript = LSL_Converter.Convert(Script);
|
|
||||||
m_positionMap = LSL_Converter.PositionMap;
|
|
||||||
l = enumCompileType.cs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l == enumCompileType.yp)
|
|
||||||
{
|
|
||||||
// Its YP, convert it to C#
|
|
||||||
compileScript = YP_Converter.Convert(Script);
|
|
||||||
// We have our own processor now
|
|
||||||
//l = enumCompileType.cs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert additional assemblies here
|
|
||||||
|
|
||||||
//ADAM: Disabled for the moment until it's working right.
|
|
||||||
bool enableCommanderLSL = false;
|
|
||||||
|
|
||||||
if (enableCommanderLSL == true && ((l == enumCompileType.cs) || (l == enumCompileType.yp)))
|
|
||||||
{
|
|
||||||
foreach (KeyValuePair<string,
|
|
||||||
ICommander> com
|
|
||||||
in m_scriptEngine.World.GetCommanders())
|
|
||||||
{
|
|
||||||
compileScript = com.Value.GenerateRuntimeAPI() + compileScript;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of insert
|
|
||||||
|
|
||||||
|
|
||||||
switch (l)
|
|
||||||
{
|
|
||||||
case enumCompileType.cs:
|
|
||||||
compileScript = CreateCSCompilerScript(compileScript);
|
|
||||||
break;
|
|
||||||
case enumCompileType.vb:
|
|
||||||
compileScript = CreateVBCompilerScript(compileScript);
|
|
||||||
break;
|
|
||||||
case enumCompileType.js:
|
|
||||||
compileScript = CreateJSCompilerScript(compileScript);
|
|
||||||
break;
|
|
||||||
case enumCompileType.yp:
|
|
||||||
compileScript = CreateYPCompilerScript(compileScript);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.Debug("[ScriptEngine.DotNetEngine]: Preparing to compile the following LSL to C# translated code");
|
|
||||||
m_log.Debug("");
|
|
||||||
m_log.Debug(compileScript);
|
|
||||||
|
|
||||||
return CompileFromDotNetText(compileScript, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string CreateJSCompilerScript(string compileScript)
|
|
||||||
{
|
|
||||||
compileScript = String.Empty +
|
|
||||||
"import OpenSim.Region.ScriptEngine.Shared; import System.Collections.Generic;\r\n" +
|
|
||||||
"package SecondLife {\r\n" +
|
|
||||||
"class Script extends OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" +
|
|
||||||
compileScript +
|
|
||||||
"} }\r\n";
|
|
||||||
return compileScript;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string CreateCSCompilerScript(string compileScript)
|
|
||||||
{
|
|
||||||
compileScript = String.Empty +
|
|
||||||
"using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" +
|
|
||||||
String.Empty + "namespace SecondLife { " +
|
|
||||||
String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" +
|
|
||||||
@"public Script() { } " +
|
|
||||||
compileScript +
|
|
||||||
"} }\r\n";
|
|
||||||
return compileScript;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string CreateYPCompilerScript(string compileScript)
|
|
||||||
{
|
|
||||||
compileScript = String.Empty +
|
|
||||||
"using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog; " +
|
|
||||||
"using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" +
|
|
||||||
String.Empty + "namespace SecondLife { " +
|
|
||||||
String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" +
|
|
||||||
//@"public Script() { } " +
|
|
||||||
@"static OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP YP=null; " +
|
|
||||||
@"public Script() { YP= new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog.YP(); } "+
|
|
||||||
|
|
||||||
compileScript +
|
|
||||||
"} }\r\n";
|
|
||||||
return compileScript;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string CreateVBCompilerScript(string compileScript)
|
|
||||||
{
|
|
||||||
compileScript = String.Empty +
|
|
||||||
"Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " +
|
|
||||||
String.Empty + "NameSpace SecondLife:" +
|
|
||||||
String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass: " +
|
|
||||||
"\r\nPublic Sub New()\r\nEnd Sub: " +
|
|
||||||
compileScript +
|
|
||||||
":End Class :End Namespace\r\n";
|
|
||||||
return compileScript;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compile .NET script to .Net assembly (.dll)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Script">CS script</param>
|
|
||||||
/// <returns>Filename to .dll assembly</returns>
|
|
||||||
internal string CompileFromDotNetText(string Script, enumCompileType lang)
|
|
||||||
{
|
|
||||||
string ext = "." + lang.ToString();
|
|
||||||
|
|
||||||
// Output assembly name
|
|
||||||
scriptCompileCounter++;
|
|
||||||
string OutFile =
|
|
||||||
Path.Combine("ScriptEngines",
|
|
||||||
FilePrefix + "_compiled_" + instanceID.ToString() + "_" + scriptCompileCounter.ToString() + ".dll");
|
|
||||||
#if DEBUG
|
|
||||||
m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Starting compile of \"" + OutFile + "\".");
|
|
||||||
#endif
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(OutFile);
|
|
||||||
}
|
|
||||||
catch (Exception e) // NOTLEGIT - Should be just catching FileIOException
|
|
||||||
{
|
|
||||||
//m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString());
|
|
||||||
throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString());
|
|
||||||
}
|
|
||||||
//string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll");
|
|
||||||
|
|
||||||
// DEBUG - write source to disk
|
|
||||||
if (WriteScriptSourceToDebugFile)
|
|
||||||
{
|
|
||||||
string srcFileName = FilePrefix + "_source_" + Path.GetFileNameWithoutExtension(OutFile) + ext;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.WriteAllText(
|
|
||||||
Path.Combine("ScriptEngines", srcFileName),
|
|
||||||
Script);
|
|
||||||
}
|
|
||||||
catch (Exception ex) // NOTLEGIT - Should be just catching FileIOException
|
|
||||||
{
|
|
||||||
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception while trying to write script source to file \"" + srcFileName + "\": " + ex.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do actual compile
|
|
||||||
CompilerParameters parameters = new CompilerParameters();
|
|
||||||
|
|
||||||
parameters.IncludeDebugInformation = true;
|
|
||||||
|
|
||||||
// Add all available assemblies
|
|
||||||
// foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
|
|
||||||
// {
|
|
||||||
// Console.WriteLine("Adding assembly: " + asm.Location);
|
|
||||||
// parameters.ReferencedAssemblies.Add(asm.Location);
|
|
||||||
// }
|
|
||||||
|
|
||||||
string rootPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
|
|
||||||
string rootPathSE = Path.GetDirectoryName(GetType().Assembly.Location);
|
|
||||||
//Console.WriteLine("Assembly location: " + rootPath);
|
|
||||||
parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.dll"));
|
|
||||||
parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll"));
|
|
||||||
|
|
||||||
if (lang == enumCompileType.yp)
|
|
||||||
{
|
|
||||||
parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.YieldProlog.dll"));
|
|
||||||
}
|
|
||||||
|
|
||||||
//parameters.ReferencedAssemblies.Add("OpenSim.Region.Environment");
|
|
||||||
parameters.GenerateExecutable = false;
|
|
||||||
parameters.OutputAssembly = OutFile;
|
|
||||||
parameters.IncludeDebugInformation = CompileWithDebugInformation;
|
|
||||||
//parameters.WarningLevel = 1; // Should be 4?
|
|
||||||
parameters.TreatWarningsAsErrors = false;
|
|
||||||
|
|
||||||
CompilerResults results;
|
|
||||||
switch (lang)
|
|
||||||
{
|
|
||||||
case enumCompileType.vb:
|
|
||||||
results = VBcodeProvider.CompileAssemblyFromSource(parameters, Script);
|
|
||||||
break;
|
|
||||||
case enumCompileType.cs:
|
|
||||||
results = CScodeProvider.CompileAssemblyFromSource(parameters, Script);
|
|
||||||
break;
|
|
||||||
case enumCompileType.js:
|
|
||||||
results = JScodeProvider.CompileAssemblyFromSource(parameters, Script);
|
|
||||||
break;
|
|
||||||
case enumCompileType.yp:
|
|
||||||
results = YPcodeProvider.CompileAssemblyFromSource(parameters, Script);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception("Compiler is not able to recongnize language type \"" + lang.ToString() + "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check result
|
|
||||||
// Go through errors
|
|
||||||
|
|
||||||
//
|
|
||||||
// WARNINGS AND ERRORS
|
|
||||||
//
|
|
||||||
if (results.Errors.Count > 0)
|
|
||||||
{
|
|
||||||
string errtext = String.Empty;
|
|
||||||
foreach (CompilerError CompErr in results.Errors)
|
|
||||||
{
|
|
||||||
KeyValuePair<int, int> lslPos;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lslPos = m_positionMap[new KeyValuePair<int, int>(CompErr.Line, CompErr.Column)];
|
|
||||||
}
|
|
||||||
catch (KeyNotFoundException) // we don't have this line/column mapped
|
|
||||||
{
|
|
||||||
m_scriptEngine.Log.Debug(String.Format("[{0}]: Lookup of C# line {1}, column {2} failed.", m_scriptEngine.ScriptEngineName, CompErr.Line, CompErr.Column));
|
|
||||||
lslPos = new KeyValuePair<int, int>(-CompErr.Line, -CompErr.Column);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Second Life viewer's script editor begins
|
|
||||||
// countingn lines and columns at 0, so we subtract 1.
|
|
||||||
errtext += String.Format("Line {0}, column {1}, Error Number: {2}, '{3}'\r\n", lslPos.Key - 1, lslPos.Value - 1, CompErr.ErrorNumber, CompErr.ErrorText);
|
|
||||||
//errtext += "Line number " + (CompErr.Line - LinesToRemoveOnError) +
|
|
||||||
// ", Error Number: " + CompErr.ErrorNumber +
|
|
||||||
// ", '" + CompErr.ErrorText + "'\r\n";
|
|
||||||
}
|
|
||||||
Console.WriteLine("[COMPILER ERROR]:" + errtext);
|
|
||||||
if (!File.Exists(OutFile))
|
|
||||||
{
|
|
||||||
throw new Exception(errtext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// NO ERRORS, BUT NO COMPILED FILE
|
|
||||||
//
|
|
||||||
if (!File.Exists(OutFile))
|
|
||||||
{
|
|
||||||
string errtext = String.Empty;
|
|
||||||
errtext += "No compile error. But not able to locate compiled file.";
|
|
||||||
throw new Exception(errtext);
|
|
||||||
}
|
|
||||||
return OutFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,183 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSim Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Tools;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
|
|
||||||
{
|
|
||||||
public class LSL2CSCodeTransformer
|
|
||||||
{
|
|
||||||
private SYMBOL m_astRoot = null;
|
|
||||||
private static Dictionary<string, string> m_datatypeLSL2OpenSim = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Pass the new CodeTranformer an abstract syntax tree.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="astRoot">The root node of the AST.</param>
|
|
||||||
public LSL2CSCodeTransformer(SYMBOL astRoot)
|
|
||||||
{
|
|
||||||
m_astRoot = astRoot;
|
|
||||||
|
|
||||||
// let's populate the dictionary
|
|
||||||
if (null == m_datatypeLSL2OpenSim)
|
|
||||||
{
|
|
||||||
m_datatypeLSL2OpenSim = new Dictionary<string, string>();
|
|
||||||
m_datatypeLSL2OpenSim.Add("integer", "LSL_Types.LSLInteger");
|
|
||||||
m_datatypeLSL2OpenSim.Add("float", "LSL_Types.LSLFloat");
|
|
||||||
//m_datatypeLSL2OpenSim.Add("key", "LSL_Types.key"); // key doesn't seem to be used
|
|
||||||
m_datatypeLSL2OpenSim.Add("key", "LSL_Types.LSLString");
|
|
||||||
m_datatypeLSL2OpenSim.Add("string", "LSL_Types.LSLString");
|
|
||||||
m_datatypeLSL2OpenSim.Add("vector", "LSL_Types.Vector3");
|
|
||||||
m_datatypeLSL2OpenSim.Add("rotation", "LSL_Types.Quaternion");
|
|
||||||
m_datatypeLSL2OpenSim.Add("list", "LSL_Types.list");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Transform the code in the AST we have.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The root node of the transformed AST</returns>
|
|
||||||
public SYMBOL Transform()
|
|
||||||
{
|
|
||||||
foreach (SYMBOL s in m_astRoot.kids)
|
|
||||||
TransformNode(s);
|
|
||||||
|
|
||||||
return m_astRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recursively called to transform each type of node. Will transform this
|
|
||||||
/// node, then all it's children.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">The current node to transform.</param>
|
|
||||||
private void TransformNode(SYMBOL s)
|
|
||||||
{
|
|
||||||
// make sure to put type lower in the inheritance hierarchy first
|
|
||||||
// ie: since IdentConstant and StringConstant inherit from Constant,
|
|
||||||
// put IdentConstant and StringConstant before Constant
|
|
||||||
if (s is Declaration)
|
|
||||||
((Declaration) s).Datatype = m_datatypeLSL2OpenSim[((Declaration) s).Datatype];
|
|
||||||
else if (s is Constant)
|
|
||||||
((Constant) s).Type = m_datatypeLSL2OpenSim[((Constant) s).Type];
|
|
||||||
else if (s is TypecastExpression)
|
|
||||||
((TypecastExpression) s).TypecastType = m_datatypeLSL2OpenSim[((TypecastExpression) s).TypecastType];
|
|
||||||
else if (s is GlobalFunctionDefinition && "void" != ((GlobalFunctionDefinition) s).ReturnType) // we don't need to translate "void"
|
|
||||||
((GlobalFunctionDefinition) s).ReturnType = m_datatypeLSL2OpenSim[((GlobalFunctionDefinition) s).ReturnType];
|
|
||||||
|
|
||||||
for (int i = 0; i < s.kids.Count; i++)
|
|
||||||
{
|
|
||||||
if (!(s is Assignment || s is ArgumentDeclarationList) && s.kids[i] is Declaration)
|
|
||||||
AddImplicitInitialization(s, i);
|
|
||||||
|
|
||||||
TransformNode((SYMBOL) s.kids[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Replaces an instance of the node at s.kids[didx] with an assignment
|
|
||||||
/// node. The assignment node has the Declaration node on the left hand
|
|
||||||
/// side and a default initializer on the right hand side.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">
|
|
||||||
/// The node containing the Declaration node that needs replacing.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="didx">Index of the Declaration node to replace.</param>
|
|
||||||
private void AddImplicitInitialization(SYMBOL s, int didx)
|
|
||||||
{
|
|
||||||
// We take the kids for a while to play with them.
|
|
||||||
int sKidSize = s.kids.Count;
|
|
||||||
object [] sKids = new object[sKidSize];
|
|
||||||
for (int i = 0; i < sKidSize; i++)
|
|
||||||
sKids[i] = s.kids.Pop();
|
|
||||||
|
|
||||||
// The child to be changed.
|
|
||||||
Declaration currentDeclaration = (Declaration) sKids[didx];
|
|
||||||
|
|
||||||
// We need an assignment node.
|
|
||||||
Assignment newAssignment = new Assignment(currentDeclaration.yyps,
|
|
||||||
currentDeclaration,
|
|
||||||
GetZeroConstant(currentDeclaration.yyps, currentDeclaration.Datatype),
|
|
||||||
"=");
|
|
||||||
sKids[didx] = newAssignment;
|
|
||||||
|
|
||||||
// Put the kids back where they belong.
|
|
||||||
for (int i = 0; i < sKidSize; i++)
|
|
||||||
s.kids.Add(sKids[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the node structure required to generate a default
|
|
||||||
/// initialization.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="p">
|
|
||||||
/// Tools.Parser instance to use when instantiating nodes.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="constantType">String describing the datatype.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// A SYMBOL node conaining the appropriate structure for intializing a
|
|
||||||
/// constantType.
|
|
||||||
/// </returns>
|
|
||||||
private SYMBOL GetZeroConstant(Parser p, string constantType)
|
|
||||||
{
|
|
||||||
switch (constantType)
|
|
||||||
{
|
|
||||||
case "integer":
|
|
||||||
return new Constant(p, constantType, "0");
|
|
||||||
case "float":
|
|
||||||
return new Constant(p, constantType, "0.0");
|
|
||||||
case "string":
|
|
||||||
case "key":
|
|
||||||
return new Constant(p, constantType, "");
|
|
||||||
case "list":
|
|
||||||
ArgumentList al = new ArgumentList(p);
|
|
||||||
return new ListConstant(p, al);
|
|
||||||
case "vector":
|
|
||||||
Constant vca = new Constant(p, "float", "0.0");
|
|
||||||
Constant vcb = new Constant(p, "float", "0.0");
|
|
||||||
Constant vcc = new Constant(p, "float", "0.0");
|
|
||||||
ConstantExpression vcea = new ConstantExpression(p, vca);
|
|
||||||
ConstantExpression vceb = new ConstantExpression(p, vcb);
|
|
||||||
ConstantExpression vcec = new ConstantExpression(p, vcc);
|
|
||||||
return new VectorConstant(p, vcea, vceb, vcec);
|
|
||||||
case "rotation":
|
|
||||||
Constant rca = new Constant(p, "float", "0.0");
|
|
||||||
Constant rcb = new Constant(p, "float", "0.0");
|
|
||||||
Constant rcc = new Constant(p, "float", "0.0");
|
|
||||||
Constant rcd = new Constant(p, "float", "0.0");
|
|
||||||
ConstantExpression rcea = new ConstantExpression(p, rca);
|
|
||||||
ConstantExpression rceb = new ConstantExpression(p, rcb);
|
|
||||||
ConstantExpression rcec = new ConstantExpression(p, rcc);
|
|
||||||
ConstantExpression rced = new ConstantExpression(p, rcd);
|
|
||||||
return new RotationConstant(p, rcea, rceb, rcec, rced);
|
|
||||||
default:
|
|
||||||
return null; // this will probably break stuff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSim Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
|
|
||||||
{
|
|
||||||
public class YP2CSConverter
|
|
||||||
{
|
|
||||||
public YP2CSConverter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Convert(string Script)
|
|
||||||
{
|
|
||||||
string CS_code = GenCode(Script);
|
|
||||||
return CS_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string GenCode(string myCode)
|
|
||||||
{
|
|
||||||
Variable TermList = new Variable();
|
|
||||||
Variable FunctionCode = new Variable();
|
|
||||||
|
|
||||||
string CS_code = "";
|
|
||||||
|
|
||||||
int cs_pointer = myCode.IndexOf("\n//cs");
|
|
||||||
if (cs_pointer > 0)
|
|
||||||
{
|
|
||||||
CS_code = myCode.Substring(cs_pointer); // CS code comes after
|
|
||||||
myCode = myCode.Substring(0, cs_pointer);
|
|
||||||
}
|
|
||||||
myCode.Replace("//yp", "%YPCode");
|
|
||||||
|
|
||||||
StringWriter myCS_SW = new StringWriter();
|
|
||||||
StringReader myCode_SR = new StringReader(" yp_nop_header_nop. \n "+myCode + "\n");
|
|
||||||
|
|
||||||
YP.see(myCode_SR);
|
|
||||||
YP.tell(myCS_SW);
|
|
||||||
|
|
||||||
//Console.WriteLine("Mycode\n ===================================\n" + myCode+"\n");
|
|
||||||
// disable warning on l1, don't see how we can
|
|
||||||
// code this differently
|
|
||||||
#pragma warning disable 0168
|
|
||||||
foreach (bool l1 in Parser.parseInput(TermList))
|
|
||||||
{
|
|
||||||
foreach (bool l2 in YPCompiler.makeFunctionPseudoCode(TermList, FunctionCode))
|
|
||||||
{
|
|
||||||
// ListPair VFC = new ListPair(FunctionCode, new Variable());
|
|
||||||
//Console.WriteLine("-------------------------")
|
|
||||||
//Console.WriteLine(FunctionCode.ToString())
|
|
||||||
//Console.WriteLine("-------------------------")
|
|
||||||
YPCompiler.convertFunctionCSharp(FunctionCode);
|
|
||||||
//YPCompiler.convertStringCodesCSharp(VFC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 0168
|
|
||||||
YP.seen();
|
|
||||||
myCS_SW.Close();
|
|
||||||
YP.told();
|
|
||||||
StringBuilder bu = myCS_SW.GetStringBuilder();
|
|
||||||
string finalcode = "//YPEncoded\n" + bu.ToString();
|
|
||||||
// FIX script events (we're in the same script)
|
|
||||||
// 'YP.script_event(Atom.a(@"sayit"),' ==> 'sayit('
|
|
||||||
finalcode = Regex.Replace(finalcode,
|
|
||||||
@"YP.script_event\(Atom.a\(\@\""(.*?)""\)\,",
|
|
||||||
@"this.$1(",
|
|
||||||
RegexOptions.Compiled | RegexOptions.Singleline);
|
|
||||||
finalcode = Regex.Replace(finalcode,
|
|
||||||
@"YP.script_event\(Atom.a\(\""(.*?)""\)\,",
|
|
||||||
@"this.$1(",
|
|
||||||
RegexOptions.Compiled | RegexOptions.Singleline);
|
|
||||||
finalcode = Regex.Replace(finalcode,
|
|
||||||
@" static ",
|
|
||||||
@" ",
|
|
||||||
RegexOptions.Compiled | RegexOptions.Singleline);
|
|
||||||
|
|
||||||
finalcode = CS_code+"\n\r"+ finalcode;
|
|
||||||
finalcode = Regex.Replace(finalcode,
|
|
||||||
@"PrologCallback",
|
|
||||||
@"public IEnumerable<bool> ",
|
|
||||||
RegexOptions.Compiled | RegexOptions.Singleline);
|
|
||||||
return finalcode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,218 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
public class Atom : IUnifiable
|
|
||||||
{
|
|
||||||
private static Dictionary<string, Atom> _atomStore = new Dictionary<string, Atom>();
|
|
||||||
public readonly string _name;
|
|
||||||
public readonly Atom _module;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// You should not call this constructor, but use Atom.a instead.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="module"></param>
|
|
||||||
private Atom(string name, Atom module)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
_module = module;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return the unique Atom object for name where module is null. You should use this to create
|
|
||||||
/// an Atom instead of calling the Atom constructor.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Atom a(string name)
|
|
||||||
{
|
|
||||||
Atom atom;
|
|
||||||
if (!_atomStore.TryGetValue(name, out atom))
|
|
||||||
{
|
|
||||||
atom = new Atom(name, null);
|
|
||||||
_atomStore[name] = atom;
|
|
||||||
}
|
|
||||||
return atom;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return an Atom object with the name and module. If module is null or Atom.NIL,
|
|
||||||
/// this behaves like Atom.a(name) and returns the unique object where the module is null.
|
|
||||||
/// If module is not null or Atom.NIL, this may or may not be the same object as another Atom
|
|
||||||
/// with the same name and module.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="module"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Atom a(string name, Atom module)
|
|
||||||
{
|
|
||||||
if (module == null || module == Atom.NIL)
|
|
||||||
return a(name);
|
|
||||||
return new Atom(name, module);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If Obj is an Atom unify its _module with Module. If the Atom's _module is null, use Atom.NIL.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Atom"></param>
|
|
||||||
/// <param name="Module"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static IEnumerable<bool> module(object Obj, object Module)
|
|
||||||
{
|
|
||||||
Obj = YP.getValue(Obj);
|
|
||||||
if (Obj is Atom)
|
|
||||||
{
|
|
||||||
if (((Atom)Obj)._module == null)
|
|
||||||
return YP.unify(Module, Atom.NIL);
|
|
||||||
else
|
|
||||||
return YP.unify(Module, ((Atom)Obj)._module);
|
|
||||||
}
|
|
||||||
return YP.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly Atom NIL = Atom.a("[]");
|
|
||||||
public static readonly Atom DOT = Atom.a(".");
|
|
||||||
public static readonly Atom F = Atom.a("f");
|
|
||||||
public static readonly Atom SLASH = Atom.a("/");
|
|
||||||
public static readonly Atom HAT = Atom.a("^");
|
|
||||||
public static readonly Atom RULE = Atom.a(":-");
|
|
||||||
|
|
||||||
public IEnumerable<bool> unify(object arg)
|
|
||||||
{
|
|
||||||
arg = YP.getValue(arg);
|
|
||||||
if (arg is Atom)
|
|
||||||
return Equals(arg) ? YP.succeed() : YP.fail();
|
|
||||||
else if (arg is Variable)
|
|
||||||
return ((Variable)arg).unify(this);
|
|
||||||
else
|
|
||||||
return YP.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addUniqueVariables(List<Variable> variableSet)
|
|
||||||
{
|
|
||||||
// Atom does not contain variables.
|
|
||||||
}
|
|
||||||
|
|
||||||
public object makeCopy(Variable.CopyStore copyStore)
|
|
||||||
{
|
|
||||||
// Atom does not contain variables that need to be copied.
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool termEqual(object term)
|
|
||||||
{
|
|
||||||
return Equals(YP.getValue(term));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ground()
|
|
||||||
{
|
|
||||||
// Atom is always ground.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (obj is Atom)
|
|
||||||
{
|
|
||||||
if (_module == null && ((Atom)obj)._module == null)
|
|
||||||
// When _declaringClass is null, we always use an identical object from _atomStore.
|
|
||||||
return this == obj;
|
|
||||||
// Otherwise, ignore _declaringClass and do a normal string compare on the _name.
|
|
||||||
return _name == ((Atom)obj)._name;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
// Debug: need to check _declaringClass.
|
|
||||||
return _name.GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string toQuotedString()
|
|
||||||
{
|
|
||||||
if (_name.Length == 0)
|
|
||||||
return "''";
|
|
||||||
else if (this == Atom.NIL)
|
|
||||||
return "[]";
|
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder(_name.Length);
|
|
||||||
bool useQuotes = false;
|
|
||||||
foreach (char c in _name)
|
|
||||||
{
|
|
||||||
int cInt = (int)c;
|
|
||||||
if (c == '\'')
|
|
||||||
{
|
|
||||||
result.Append("''");
|
|
||||||
useQuotes = true;
|
|
||||||
}
|
|
||||||
else if (c == '_' || cInt >= (int)'a' && cInt <= (int)'z' ||
|
|
||||||
cInt >= (int)'A' && cInt <= (int)'Z' || cInt >= (int)'0' && cInt <= (int)'9')
|
|
||||||
result.Append(c);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Debug: Need to handle non-printable chars.
|
|
||||||
result.Append(c);
|
|
||||||
useQuotes = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!useQuotes && (int)_name[0] >= (int)'a' && (int)_name[0] <= (int)'z')
|
|
||||||
return result.ToString();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Surround in single quotes.
|
|
||||||
result.Append('\'');
|
|
||||||
return "'" + result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return true if _name is lexicographically less than atom._name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="atom"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool lessThan(Atom atom)
|
|
||||||
{
|
|
||||||
return _name.CompareTo(atom._name) < 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,239 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A BagofAnswers holds answers for bagof and setof.
|
|
||||||
/// </summary>
|
|
||||||
public class BagofAnswers
|
|
||||||
{
|
|
||||||
private object _template;
|
|
||||||
private Variable[] _freeVariables;
|
|
||||||
private Dictionary<object[], List<object>> _bagForFreeVariables;
|
|
||||||
private List<object> _findallBagArray;
|
|
||||||
private static TermArrayEqualityComparer _termArrayEqualityComparer =
|
|
||||||
new TermArrayEqualityComparer();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// To get the free variables, split off any existential qualifiers from Goal such as the X in
|
|
||||||
/// "X ^ f(Y)", get the set of unbound variables in Goal that are not qualifiers, then remove
|
|
||||||
/// the unbound variables that are qualifiers as well as the unbound variables in Template.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Template"></param>
|
|
||||||
/// <param name="Goal"></param>
|
|
||||||
public BagofAnswers(object Template, object Goal)
|
|
||||||
{
|
|
||||||
_template = Template;
|
|
||||||
|
|
||||||
// First get the set of variables that are not free variables.
|
|
||||||
List<Variable> variableSet = new List<Variable>();
|
|
||||||
YP.addUniqueVariables(Template, variableSet);
|
|
||||||
object UnqualifiedGoal = YP.getValue(Goal);
|
|
||||||
while (UnqualifiedGoal is Functor2 && ((Functor2)UnqualifiedGoal)._name == Atom.HAT)
|
|
||||||
{
|
|
||||||
YP.addUniqueVariables(((Functor2)UnqualifiedGoal)._arg1, variableSet);
|
|
||||||
UnqualifiedGoal = YP.getValue(((Functor2)UnqualifiedGoal)._arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remember how many non-free variables there are so we can find the unique free variables
|
|
||||||
// that are added.
|
|
||||||
int nNonFreeVariables = variableSet.Count;
|
|
||||||
YP.addUniqueVariables(UnqualifiedGoal, variableSet);
|
|
||||||
int nFreeVariables = variableSet.Count - nNonFreeVariables;
|
|
||||||
if (nFreeVariables == 0)
|
|
||||||
{
|
|
||||||
// There were no free variables added, so we won't waste time with _bagForFreeVariables.
|
|
||||||
_freeVariables = null;
|
|
||||||
_findallBagArray = new List<object>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Copy the free variables.
|
|
||||||
_freeVariables = new Variable[nFreeVariables];
|
|
||||||
for (int i = 0; i < nFreeVariables; ++i)
|
|
||||||
_freeVariables[i] = variableSet[i + nNonFreeVariables];
|
|
||||||
|
|
||||||
_bagForFreeVariables = new Dictionary<object[], List<object>>(_termArrayEqualityComparer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add()
|
|
||||||
{
|
|
||||||
if (_freeVariables == null)
|
|
||||||
// The goal has bound the values in _template but we don't bother with _freeVariables.
|
|
||||||
_findallBagArray.Add(YP.makeCopy(_template, new Variable.CopyStore()));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The goal has bound the values in _template and _freeVariables.
|
|
||||||
// Find the entry for this set of _freeVariables values.
|
|
||||||
object[] freeVariableValues = new object[_freeVariables.Length];
|
|
||||||
for (int i = 0; i < _freeVariables.Length; ++i)
|
|
||||||
freeVariableValues[i] = YP.getValue(_freeVariables[i]);
|
|
||||||
List<object> bagArray;
|
|
||||||
if (!_bagForFreeVariables.TryGetValue(freeVariableValues, out bagArray))
|
|
||||||
{
|
|
||||||
bagArray = new List<object>();
|
|
||||||
_bagForFreeVariables[freeVariableValues] = bagArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now copy the template and add to the bag for the freeVariables values.
|
|
||||||
bagArray.Add(YP.makeCopy(_template, new Variable.CopyStore()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable warning on l1, don't see how we can
|
|
||||||
// code this differently
|
|
||||||
#pragma warning disable 0168
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For each result, unify the _freeVariables and unify bagArrayVariable with the associated bag.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bagArrayVariable">this is unified with the List<object> of matches for template that
|
|
||||||
/// corresponds to the bindings for freeVariables. Be very careful: this does not unify with a Prolog
|
|
||||||
/// list.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<bool> resultArray(Variable bagArrayVariable)
|
|
||||||
{
|
|
||||||
if (_freeVariables == null)
|
|
||||||
{
|
|
||||||
// No unbound free variables, so we only filled one bag. If empty, bagof fails.
|
|
||||||
if (_findallBagArray.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (bool l1 in bagArrayVariable.unify(_findallBagArray))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (KeyValuePair<object[], List<object>> valuesAndBag in _bagForFreeVariables)
|
|
||||||
{
|
|
||||||
foreach (bool l1 in YP.unifyArrays(_freeVariables, valuesAndBag.Key))
|
|
||||||
{
|
|
||||||
foreach (bool l2 in bagArrayVariable.unify(valuesAndBag.Value))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
// Debug: Should we free memory of the answers already returned?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For each result, unify the _freeVariables and unify Bag with the associated bag.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Bag"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<bool> result(object Bag)
|
|
||||||
{
|
|
||||||
Variable bagArrayVariable = new Variable();
|
|
||||||
foreach (bool l1 in resultArray(bagArrayVariable))
|
|
||||||
{
|
|
||||||
foreach (bool l2 in YP.unify(Bag, ListPair.make((List<object>)bagArrayVariable.getValue())))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For each result, unify the _freeVariables and unify Bag with the associated bag which is sorted
|
|
||||||
/// with duplicates removed, as in setof.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Bag"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<bool> resultSet(object Bag)
|
|
||||||
{
|
|
||||||
Variable bagArrayVariable = new Variable();
|
|
||||||
foreach (bool l1 in resultArray(bagArrayVariable))
|
|
||||||
{
|
|
||||||
List<object> bagArray = (List<object>)bagArrayVariable.getValue();
|
|
||||||
YP.sortArray(bagArray);
|
|
||||||
foreach (bool l2 in YP.unify(Bag, ListPair.makeWithoutRepeatedTerms(bagArray)))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<bool> bagofArray
|
|
||||||
(object Template, object Goal, IEnumerable<bool> goalIterator, Variable bagArrayVariable)
|
|
||||||
{
|
|
||||||
BagofAnswers bagOfAnswers = new BagofAnswers(Template, Goal);
|
|
||||||
foreach (bool l1 in goalIterator)
|
|
||||||
bagOfAnswers.add();
|
|
||||||
return bagOfAnswers.resultArray(bagArrayVariable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<bool> bagof
|
|
||||||
(object Template, object Goal, IEnumerable<bool> goalIterator, object Bag)
|
|
||||||
{
|
|
||||||
BagofAnswers bagOfAnswers = new BagofAnswers(Template, Goal);
|
|
||||||
foreach (bool l1 in goalIterator)
|
|
||||||
bagOfAnswers.add();
|
|
||||||
return bagOfAnswers.result(Bag);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<bool> setof
|
|
||||||
(object Template, object Goal, IEnumerable<bool> goalIterator, object Bag)
|
|
||||||
{
|
|
||||||
BagofAnswers bagOfAnswers = new BagofAnswers(Template, Goal);
|
|
||||||
foreach (bool l1 in goalIterator)
|
|
||||||
bagOfAnswers.add();
|
|
||||||
return bagOfAnswers.resultSet(Bag);
|
|
||||||
}
|
|
||||||
#pragma warning restore 0168
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A TermArrayEqualityComparer implements IEqualityComparer to compare two object arrays using YP.termEqual.
|
|
||||||
/// </summary>
|
|
||||||
private class TermArrayEqualityComparer : IEqualityComparer<object[]>
|
|
||||||
{
|
|
||||||
public bool Equals(object[] array1, object[] array2)
|
|
||||||
{
|
|
||||||
if (array1.Length != array2.Length)
|
|
||||||
return false;
|
|
||||||
for (int i = 0; i < array1.Length; ++i)
|
|
||||||
{
|
|
||||||
if (!YP.termEqual(array1[i], array2[i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHashCode(object[] array)
|
|
||||||
{
|
|
||||||
int hashCode = 0;
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
hashCode ^= array[i].GetHashCode();
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A FindallAnswers holds answers for findall.
|
|
||||||
/// </summary>
|
|
||||||
public class FindallAnswers
|
|
||||||
{
|
|
||||||
private object _template;
|
|
||||||
private List<object> _bagArray;
|
|
||||||
|
|
||||||
public FindallAnswers(object Template)
|
|
||||||
{
|
|
||||||
_template = Template;
|
|
||||||
_bagArray = new List<object>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add()
|
|
||||||
{
|
|
||||||
_bagArray.Add(YP.makeCopy(_template, new Variable.CopyStore()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<object> resultArray()
|
|
||||||
{
|
|
||||||
return _bagArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unify Bag with the result. This frees the internal answers, so you can only call this once.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Bag"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<bool> result(object Bag)
|
|
||||||
{
|
|
||||||
object result = ListPair.make(_bagArray);
|
|
||||||
// Try to free the memory.
|
|
||||||
_bagArray = null;
|
|
||||||
return YP.unify(Bag, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable warning on l1, don't see how we can
|
|
||||||
// code this differently
|
|
||||||
#pragma warning disable 0168
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is a simplified findall when the goal is a single call.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Template"></param>
|
|
||||||
/// <param name="goal"></param>
|
|
||||||
/// <param name="Bag"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static IEnumerable<bool> findall(object Template, IEnumerable<bool> goal, object Bag)
|
|
||||||
{
|
|
||||||
FindallAnswers findallAnswers = new FindallAnswers(Template);
|
|
||||||
foreach (bool l1 in goal)
|
|
||||||
findallAnswers.add();
|
|
||||||
return findallAnswers.result(Bag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Like findall, except return an array of the results.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="template"></param>
|
|
||||||
/// <param name="goal"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static List<object> findallArray(object Template, IEnumerable<bool> goal)
|
|
||||||
{
|
|
||||||
FindallAnswers findallAnswers = new FindallAnswers(Template);
|
|
||||||
foreach (bool l1 in goal)
|
|
||||||
findallAnswers.add();
|
|
||||||
return findallAnswers.resultArray();
|
|
||||||
}
|
|
||||||
#pragma warning restore 0168
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
public class Functor : IUnifiable
|
|
||||||
{
|
|
||||||
public readonly Atom _name;
|
|
||||||
public readonly object[] _args;
|
|
||||||
|
|
||||||
public Functor(Atom name, object[] args)
|
|
||||||
{
|
|
||||||
if (args.Length <= 3)
|
|
||||||
{
|
|
||||||
if (args.Length == 0)
|
|
||||||
throw new Exception("For arity 0 functor, just use name as an Atom");
|
|
||||||
else if (args.Length == 1)
|
|
||||||
throw new Exception("For arity 1 functor, use Functor1");
|
|
||||||
else if (args.Length == 2)
|
|
||||||
throw new Exception("For arity 2 functor, use Functor2");
|
|
||||||
else if (args.Length == 3)
|
|
||||||
throw new Exception("For arity 3 functor, use Functor3");
|
|
||||||
else
|
|
||||||
// (This shouldn't happen, but include it for completeness.
|
|
||||||
throw new Exception("Cannot create a Functor of arity " + args.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
_name = name;
|
|
||||||
_args = args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Functor(string name, object[] args)
|
|
||||||
: this(Atom.a(name), args)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return an Atom, Functor1, Functor2, Functor3 or Functor depending on the
|
|
||||||
/// length of args.
|
|
||||||
/// Note that this is different than the Functor constructor which requires
|
|
||||||
/// the length of args to be greater than 3.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static object make(Atom name, object[] args)
|
|
||||||
{
|
|
||||||
if (args.Length <= 0)
|
|
||||||
return name;
|
|
||||||
else if (args.Length == 1)
|
|
||||||
return new Functor1(name, args[0]);
|
|
||||||
else if (args.Length == 2)
|
|
||||||
return new Functor2(name, args[0], args[1]);
|
|
||||||
else if (args.Length == 3)
|
|
||||||
return new Functor3(name, args[0], args[1], args[2]);
|
|
||||||
else
|
|
||||||
return new Functor(name, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Call the main make, first converting name to an Atom.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static object make(string name, object[] args)
|
|
||||||
{
|
|
||||||
return make(Atom.a(name), args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If arg is another Functor, then succeed (yield once) if this and arg have the
|
|
||||||
/// same name and all functor args unify, otherwise fail (don't yield).
|
|
||||||
/// If arg is a Variable, then call its unify to unify with this.
|
|
||||||
/// Otherwise fail (don't yield).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="arg"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<bool> unify(object arg)
|
|
||||||
{
|
|
||||||
arg = YP.getValue(arg);
|
|
||||||
if (arg is Functor)
|
|
||||||
{
|
|
||||||
Functor argFunctor = (Functor)arg;
|
|
||||||
if (_name.Equals(argFunctor._name))
|
|
||||||
return YP.unifyArrays(_args, argFunctor._args);
|
|
||||||
else
|
|
||||||
return YP.fail();
|
|
||||||
}
|
|
||||||
else if (arg is Variable)
|
|
||||||
return ((Variable)arg).unify(this);
|
|
||||||
else
|
|
||||||
return YP.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
string result = _name + "(" + YP.getValue(_args[0]);
|
|
||||||
for (int i = 1; i < _args.Length; ++i)
|
|
||||||
result += ", " + YP.getValue(_args[i]);
|
|
||||||
result += ")";
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool termEqual(object term)
|
|
||||||
{
|
|
||||||
term = YP.getValue(term);
|
|
||||||
if (term is Functor)
|
|
||||||
{
|
|
||||||
Functor termFunctor = (Functor)term;
|
|
||||||
if (_name.Equals(termFunctor._name) && _args.Length == termFunctor._args.Length)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _args.Length; ++i)
|
|
||||||
{
|
|
||||||
if (!YP.termEqual(_args[i], termFunctor._args[i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool lessThan(Functor functor)
|
|
||||||
{
|
|
||||||
// Do the equal check first since it is faster.
|
|
||||||
if (!_name.Equals(functor._name))
|
|
||||||
return _name.lessThan(functor._name);
|
|
||||||
|
|
||||||
if (_args.Length != functor._args.Length)
|
|
||||||
return _args.Length < functor._args.Length;
|
|
||||||
|
|
||||||
for (int i = 0; i < _args.Length; ++i)
|
|
||||||
{
|
|
||||||
if (!YP.termEqual(_args[i], functor._args[i]))
|
|
||||||
return YP.termLessThan(_args[i], functor._args[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ground()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _args.Length; ++i)
|
|
||||||
{
|
|
||||||
if (!YP.ground(_args[i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addUniqueVariables(List<Variable> variableSet)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _args.Length; ++i)
|
|
||||||
YP.addUniqueVariables(_args[i], variableSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object makeCopy(Variable.CopyStore copyStore)
|
|
||||||
{
|
|
||||||
object[] argsCopy = new object[_args.Length];
|
|
||||||
for (int i = 0; i < _args.Length; ++i)
|
|
||||||
argsCopy[i] = YP.makeCopy(_args[i], copyStore);
|
|
||||||
return new Functor(_name, argsCopy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
public class Functor1 : IUnifiable
|
|
||||||
{
|
|
||||||
public readonly Atom _name;
|
|
||||||
public readonly object _arg1;
|
|
||||||
|
|
||||||
public Functor1(Atom name, object arg1)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
_arg1 = arg1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Functor1(string name, object arg1)
|
|
||||||
: this(Atom.a(name), arg1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable warning on l1, don't see how we can
|
|
||||||
// code this differently
|
|
||||||
#pragma warning disable 0168
|
|
||||||
/// <summary>
|
|
||||||
/// If arg is another Functor1, then succeed (yield once) if this and arg have the
|
|
||||||
/// same name and the functor args unify, otherwise fail (don't yield).
|
|
||||||
/// If arg is a Variable, then call its unify to unify with this.
|
|
||||||
/// Otherwise fail (don't yield).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="arg"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<bool> unify(object arg)
|
|
||||||
{
|
|
||||||
arg = YP.getValue(arg);
|
|
||||||
if (arg is Functor1)
|
|
||||||
{
|
|
||||||
Functor1 argFunctor = (Functor1)arg;
|
|
||||||
if (_name.Equals(argFunctor._name))
|
|
||||||
{
|
|
||||||
foreach (bool l1 in YP.unify(_arg1, argFunctor._arg1))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (arg is Variable)
|
|
||||||
{
|
|
||||||
foreach (bool l1 in ((Variable)arg).unify(this))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 0168
|
|
||||||
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return _name + "(" + YP.getValue(_arg1) + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool termEqual(object term)
|
|
||||||
{
|
|
||||||
term = YP.getValue(term);
|
|
||||||
if (term is Functor1)
|
|
||||||
{
|
|
||||||
Functor1 termFunctor = (Functor1)term;
|
|
||||||
return _name.Equals(termFunctor._name) && YP.termEqual(_arg1, termFunctor._arg1);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool lessThan(Functor1 functor)
|
|
||||||
{
|
|
||||||
// Do the equal check first since it is faster.
|
|
||||||
if (!_name.Equals(functor._name))
|
|
||||||
return _name.lessThan(functor._name);
|
|
||||||
|
|
||||||
return YP.termLessThan(_arg1, functor._arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ground()
|
|
||||||
{
|
|
||||||
return YP.ground(_arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addUniqueVariables(List<Variable> variableSet)
|
|
||||||
{
|
|
||||||
YP.addUniqueVariables(_arg1, variableSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object makeCopy(Variable.CopyStore copyStore)
|
|
||||||
{
|
|
||||||
return new Functor1(_name, YP.makeCopy(_arg1, copyStore));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,163 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
public class Functor2 : IUnifiable
|
|
||||||
{
|
|
||||||
public readonly Atom _name;
|
|
||||||
public readonly object _arg1;
|
|
||||||
public readonly object _arg2;
|
|
||||||
|
|
||||||
public Functor2(Atom name, object arg1, object arg2)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
_arg1 = arg1;
|
|
||||||
_arg2 = arg2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Functor2(string name, object arg1, object arg2)
|
|
||||||
: this(Atom.a(name), arg1, arg2)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable warning on l1, don't see how we can
|
|
||||||
// code this differently
|
|
||||||
#pragma warning disable 0168
|
|
||||||
/// If arg is another Functor2, then succeed (yield once) if this and arg have the
|
|
||||||
/// same name and all functor args unify, otherwise fail (don't yield).
|
|
||||||
/// If arg is a Variable, then call its unify to unify with this.
|
|
||||||
/// Otherwise fail (don't yield).
|
|
||||||
public IEnumerable<bool> unify(object arg)
|
|
||||||
{
|
|
||||||
arg = YP.getValue(arg);
|
|
||||||
if (arg is Functor2)
|
|
||||||
{
|
|
||||||
Functor2 argFunctor = (Functor2)arg;
|
|
||||||
if (_name.Equals(argFunctor._name))
|
|
||||||
{
|
|
||||||
foreach (bool l1 in YP.unify(_arg1, argFunctor._arg1))
|
|
||||||
{
|
|
||||||
foreach (bool l2 in YP.unify(_arg2, argFunctor._arg2))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (arg is Variable)
|
|
||||||
{
|
|
||||||
foreach (bool l1 in ((Variable)arg).unify(this))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 0168
|
|
||||||
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
if (_name == Atom.DOT)
|
|
||||||
return listPairToString(this);
|
|
||||||
else
|
|
||||||
return _name + "(" + YP.getValue(_arg1) + ", " + YP.getValue(_arg2) + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool termEqual(object term)
|
|
||||||
{
|
|
||||||
term = YP.getValue(term);
|
|
||||||
if (term is Functor2)
|
|
||||||
{
|
|
||||||
Functor2 termFunctor = (Functor2)term;
|
|
||||||
return _name.Equals(termFunctor._name) && YP.termEqual(_arg1, termFunctor._arg1)
|
|
||||||
&& YP.termEqual(_arg2, termFunctor._arg2);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool lessThan(Functor2 functor)
|
|
||||||
{
|
|
||||||
// Do the equal check first since it is faster.
|
|
||||||
if (!_name.Equals(functor._name))
|
|
||||||
return _name.lessThan(functor._name);
|
|
||||||
|
|
||||||
if (!YP.termEqual(_arg1, functor._arg1))
|
|
||||||
return YP.termLessThan(_arg1, functor._arg1);
|
|
||||||
|
|
||||||
return YP.termLessThan(_arg2, functor._arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ground()
|
|
||||||
{
|
|
||||||
return YP.ground(_arg1) && YP.ground(_arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addUniqueVariables(List<Variable> variableSet)
|
|
||||||
{
|
|
||||||
YP.addUniqueVariables(_arg1, variableSet);
|
|
||||||
YP.addUniqueVariables(_arg2, variableSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object makeCopy(Variable.CopyStore copyStore)
|
|
||||||
{
|
|
||||||
return new Functor2(_name, YP.makeCopy(_arg1, copyStore),
|
|
||||||
YP.makeCopy(_arg2, copyStore));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string listPairToString(Functor2 listPair)
|
|
||||||
{
|
|
||||||
string result = "[";
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
object head = YP.getValue(listPair._arg1);
|
|
||||||
object tail = YP.getValue(listPair._arg2);
|
|
||||||
if (tail == (object)Atom.NIL)
|
|
||||||
{
|
|
||||||
result += head;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (tail is Functor2 && ((Functor2)tail)._name == Atom.DOT)
|
|
||||||
{
|
|
||||||
result += head + ", ";
|
|
||||||
listPair = (Functor2)tail;
|
|
||||||
// Loop again.
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The list is not terminated with NIL.
|
|
||||||
result += head + "|" + tail;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result += "]";
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,141 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
public class Functor3 : IUnifiable
|
|
||||||
{
|
|
||||||
public readonly Atom _name;
|
|
||||||
public readonly object _arg1;
|
|
||||||
public readonly object _arg2;
|
|
||||||
public readonly object _arg3;
|
|
||||||
|
|
||||||
public Functor3(Atom name, object arg1, object arg2, object arg3)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
_arg1 = arg1;
|
|
||||||
_arg2 = arg2;
|
|
||||||
_arg3 = arg3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Functor3(string name, object arg1, object arg2, object arg3)
|
|
||||||
: this(Atom.a(name), arg1, arg2, arg3)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable warning on l1, don't see how we can
|
|
||||||
// code this differently
|
|
||||||
#pragma warning disable 0168
|
|
||||||
/// If arg is another Functor3, then succeed (yield once) if this and arg have the
|
|
||||||
/// same name and all functor args unify, otherwise fail (don't yield).
|
|
||||||
/// If arg is a Variable, then call its unify to unify with this.
|
|
||||||
/// Otherwise fail (don't yield).
|
|
||||||
public IEnumerable<bool> unify(object arg)
|
|
||||||
{
|
|
||||||
arg = YP.getValue(arg);
|
|
||||||
if (arg is Functor3)
|
|
||||||
{
|
|
||||||
Functor3 argFunctor = (Functor3)arg;
|
|
||||||
if (_name.Equals(argFunctor._name))
|
|
||||||
{
|
|
||||||
foreach (bool l1 in YP.unify(_arg1, argFunctor._arg1))
|
|
||||||
{
|
|
||||||
foreach (bool l2 in YP.unify(_arg2, argFunctor._arg2))
|
|
||||||
{
|
|
||||||
foreach (bool l3 in YP.unify(_arg3, argFunctor._arg3))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (arg is Variable)
|
|
||||||
{
|
|
||||||
foreach (bool l1 in ((Variable)arg).unify(this))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 0168
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return _name + "(" + YP.getValue(_arg1) + ", " + YP.getValue(_arg2) + ", " +
|
|
||||||
YP.getValue(_arg3) + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool termEqual(object term)
|
|
||||||
{
|
|
||||||
term = YP.getValue(term);
|
|
||||||
if (term is Functor3)
|
|
||||||
{
|
|
||||||
Functor3 termFunctor = (Functor3)term;
|
|
||||||
return _name.Equals(termFunctor._name) && YP.termEqual(_arg1, termFunctor._arg1)
|
|
||||||
&& YP.termEqual(_arg2, termFunctor._arg2)
|
|
||||||
&& YP.termEqual(_arg3, termFunctor._arg3);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool lessThan(Functor3 functor)
|
|
||||||
{
|
|
||||||
// Do the equal check first since it is faster.
|
|
||||||
if (!_name.Equals(functor._name))
|
|
||||||
return _name.lessThan(functor._name);
|
|
||||||
|
|
||||||
if (!YP.termEqual(_arg1, functor._arg1))
|
|
||||||
return YP.termLessThan(_arg1, functor._arg1);
|
|
||||||
|
|
||||||
if (!YP.termEqual(_arg2, functor._arg2))
|
|
||||||
return YP.termLessThan(_arg2, functor._arg2);
|
|
||||||
|
|
||||||
return YP.termLessThan(_arg3, functor._arg3);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ground()
|
|
||||||
{
|
|
||||||
return YP.ground(_arg1) && YP.ground(_arg2) && YP.ground(_arg3);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addUniqueVariables(List<Variable> variableSet)
|
|
||||||
{
|
|
||||||
YP.addUniqueVariables(_arg1, variableSet);
|
|
||||||
YP.addUniqueVariables(_arg2, variableSet);
|
|
||||||
YP.addUniqueVariables(_arg3, variableSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object makeCopy(Variable.CopyStore copyStore)
|
|
||||||
{
|
|
||||||
return new Functor3(_name, YP.makeCopy(_arg1, copyStore),
|
|
||||||
YP.makeCopy(_arg2, copyStore), YP.makeCopy(_arg3, copyStore));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,385 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An IndexedAnswers holds answers to a query based on the values of index arguments.
|
|
||||||
/// </summary>
|
|
||||||
public class IndexedAnswers : YP.IClause
|
|
||||||
{
|
|
||||||
private int _arity;
|
|
||||||
// addAnswer adds the answer here and indexes it later.
|
|
||||||
private List<object[]> _allAnswers = new List<object[]>();
|
|
||||||
// The key has the arity of answers with non-null values for each indexed arg. The value
|
|
||||||
// is a list of the matching answers. The signature is implicit in the pattern on non-null index args.
|
|
||||||
private Dictionary<HashedList, List<object[]>> _indexedAnswers =
|
|
||||||
new Dictionary<HashedList, List<object[]>>();
|
|
||||||
// Keeps track of whether we have started adding entries to _indexedAnswers for the signature.
|
|
||||||
private Dictionary<int, object> _gotAnswersForSignature = new Dictionary<int, object>();
|
|
||||||
private const int MAX_INDEX_ARGS = 31;
|
|
||||||
|
|
||||||
public IndexedAnswers(int arity)
|
|
||||||
{
|
|
||||||
_arity = arity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Append the answer to the list and update the indexes, if any.
|
|
||||||
/// Elements of answer must be ground, since arguments with unbound variables make this
|
|
||||||
/// into a dynamic rule which we don't index.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="answer"></param>
|
|
||||||
public void addAnswer(object[] answer)
|
|
||||||
{
|
|
||||||
addOrPrependAnswer(answer, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prepend the answer to the list and clear the indexes so that they must be re-computed
|
|
||||||
/// on the next call to match. (Only addAnswer will maintain the indexes while adding answers.)
|
|
||||||
/// Elements of answer must be ground, since arguments with unbound variables make this
|
|
||||||
/// into a dynamic rule which we don't index.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="answer"></param>
|
|
||||||
public void prependAnswer(object[] answer)
|
|
||||||
{
|
|
||||||
addOrPrependAnswer(answer, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Do the work of addAnswer or prependAnswer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="answer"></param>
|
|
||||||
private void addOrPrependAnswer(object[] answer, bool prepend)
|
|
||||||
{
|
|
||||||
if (answer.Length != _arity)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Store a copy of the answer array.
|
|
||||||
object[] answerCopy = new object[answer.Length];
|
|
||||||
Variable.CopyStore copyStore = new Variable.CopyStore();
|
|
||||||
for (int i = 0; i < answer.Length; ++i)
|
|
||||||
answerCopy[i] = YP.makeCopy(answer[i], copyStore);
|
|
||||||
if (copyStore.getNUniqueVariables() > 0)
|
|
||||||
throw new InvalidOperationException
|
|
||||||
("Elements of answer must be ground, but found " + copyStore.getNUniqueVariables() +
|
|
||||||
" unbound variables");
|
|
||||||
|
|
||||||
if (prepend)
|
|
||||||
{
|
|
||||||
_allAnswers.Insert(0, answerCopy);
|
|
||||||
clearIndexes();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_allAnswers.Add(answerCopy);
|
|
||||||
// If match has already indexed answers for a signature, we need to add
|
|
||||||
// this to the existing indexed answers.
|
|
||||||
foreach (int signature in _gotAnswersForSignature.Keys)
|
|
||||||
indexAnswerForSignature(answerCopy, signature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void indexAnswerForSignature(object[] answer, int signature)
|
|
||||||
{
|
|
||||||
// First find out which of the answer values can be used as an index.
|
|
||||||
object[] indexValues = new object[answer.Length];
|
|
||||||
for (int i = 0; i < answer.Length; ++i)
|
|
||||||
{
|
|
||||||
// We limit the number of indexed args in a 32-bit signature.
|
|
||||||
if (i >= MAX_INDEX_ARGS)
|
|
||||||
indexValues[i] = null;
|
|
||||||
else
|
|
||||||
indexValues[i] = getIndexValue(YP.getValue(answer[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need an entry in indexArgs from indexValues for each 1 bit in signature.
|
|
||||||
HashedList indexArgs = new HashedList(indexValues.Length);
|
|
||||||
for (int i = 0; i < indexValues.Length; ++i)
|
|
||||||
{
|
|
||||||
if ((signature & (1 << i)) == 0)
|
|
||||||
indexArgs.Add(null);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (indexValues[i] == null)
|
|
||||||
// The signature wants an index value here, but we don't have one so
|
|
||||||
// we can't add it as an answer for this signature.
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
indexArgs.Add(indexValues[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the answer to the answers list for indexArgs, creating the entry if needed.
|
|
||||||
List<object[]> answers;
|
|
||||||
if (!_indexedAnswers.TryGetValue(indexArgs, out answers))
|
|
||||||
{
|
|
||||||
answers = new List<object[]>();
|
|
||||||
_indexedAnswers[indexArgs] = answers;
|
|
||||||
}
|
|
||||||
answers.Add(answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<bool> match(object[] arguments)
|
|
||||||
{
|
|
||||||
if (arguments.Length != _arity)
|
|
||||||
yield break;
|
|
||||||
|
|
||||||
// Set up indexArgs, up to arg position MAX_INDEX_ARGS. The signature has a 1 bit for
|
|
||||||
// each non-null index arg.
|
|
||||||
HashedList indexArgs = new HashedList(arguments.Length);
|
|
||||||
bool gotAllIndexArgs = true;
|
|
||||||
int signature = 0;
|
|
||||||
for (int i = 0; i < arguments.Length; ++i)
|
|
||||||
{
|
|
||||||
object indexValue = null;
|
|
||||||
if (i < MAX_INDEX_ARGS)
|
|
||||||
{
|
|
||||||
// We limit the number of args in a 32-bit signature.
|
|
||||||
indexValue = getIndexValue(YP.getValue(arguments[i]));
|
|
||||||
if (indexValue != null)
|
|
||||||
signature += (1 << i);
|
|
||||||
}
|
|
||||||
if (indexValue == null)
|
|
||||||
gotAllIndexArgs = false;
|
|
||||||
indexArgs.Add(indexValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<object[]> answers;
|
|
||||||
if (signature == 0)
|
|
||||||
// No index args, so we have to match from _allAnswers.
|
|
||||||
answers = _allAnswers;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!_gotAnswersForSignature.ContainsKey(signature))
|
|
||||||
{
|
|
||||||
// We need to create the entry in _indexedAnswers.
|
|
||||||
foreach (object[] answer in _allAnswers)
|
|
||||||
indexAnswerForSignature(answer, signature);
|
|
||||||
// Mark that we did this signature.
|
|
||||||
_gotAnswersForSignature[signature] = null;
|
|
||||||
}
|
|
||||||
if (!_indexedAnswers.TryGetValue(indexArgs, out answers))
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gotAllIndexArgs)
|
|
||||||
{
|
|
||||||
// All the arguments were already bound, so we don't need to do bindings.
|
|
||||||
yield return false;
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find matches in answers.
|
|
||||||
IEnumerator<bool>[] iterators = new IEnumerator<bool>[arguments.Length];
|
|
||||||
// Debug: If the caller asserts another answer into this same predicate during yield, the iterator
|
|
||||||
// over clauses will be corrupted. Should we take the time to copy answers?
|
|
||||||
foreach (object[] answer in answers)
|
|
||||||
{
|
|
||||||
bool gotMatch = true;
|
|
||||||
int nIterators = 0;
|
|
||||||
// Try to bind all the arguments.
|
|
||||||
for (int i = 0; i < arguments.Length; ++i)
|
|
||||||
{
|
|
||||||
if (indexArgs[i] != null)
|
|
||||||
// We already matched this argument by looking up _indexedAnswers.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
IEnumerator<bool> iterator = YP.unify(arguments[i], answer[i]).GetEnumerator();
|
|
||||||
iterators[nIterators++] = iterator;
|
|
||||||
// MoveNext() is true if YP.unify succeeds.
|
|
||||||
if (!iterator.MoveNext())
|
|
||||||
{
|
|
||||||
gotMatch = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (gotMatch)
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Manually finalize all the iterators.
|
|
||||||
for (int i = 0; i < nIterators; ++i)
|
|
||||||
iterators[i].Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<bool> clause(object Head, object Body)
|
|
||||||
{
|
|
||||||
Head = YP.getValue(Head);
|
|
||||||
if (Head is Variable)
|
|
||||||
throw new PrologException("instantiation_error", "Head is an unbound variable");
|
|
||||||
object[] arguments = YP.getFunctorArgs(Head);
|
|
||||||
|
|
||||||
// We always match Head from _allAnswers, and the Body is Atom.a("true").
|
|
||||||
#pragma warning disable 0168
|
|
||||||
foreach (bool l1 in YP.unify(Body, Atom.a("true")))
|
|
||||||
{
|
|
||||||
// The caller can assert another answer into this same predicate during yield, so we have to
|
|
||||||
// make a copy of the answers.
|
|
||||||
foreach (object[] answer in _allAnswers.ToArray())
|
|
||||||
{
|
|
||||||
foreach (bool l2 in YP.unifyArrays(arguments, answer))
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 0168
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<bool> retract(object Head, object Body)
|
|
||||||
{
|
|
||||||
Head = YP.getValue(Head);
|
|
||||||
if (Head is Variable)
|
|
||||||
throw new PrologException("instantiation_error", "Head is an unbound variable");
|
|
||||||
object[] arguments = YP.getFunctorArgs(Head);
|
|
||||||
|
|
||||||
// We always match Head from _allAnswers, and the Body is Atom.a("true").
|
|
||||||
#pragma warning disable 0168
|
|
||||||
foreach (bool l1 in YP.unify(Body, Atom.a("true")))
|
|
||||||
{
|
|
||||||
// The caller can assert another answer into this same predicate during yield, so we have to
|
|
||||||
// make a copy of the answers.
|
|
||||||
foreach (object[] answer in _allAnswers.ToArray())
|
|
||||||
{
|
|
||||||
foreach (bool l2 in YP.unifyArrays(arguments, answer))
|
|
||||||
{
|
|
||||||
_allAnswers.Remove(answer);
|
|
||||||
clearIndexes();
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 0168
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// After retracting or prepending an answer in _allAnswers, the indexes are invalid, so clear them.
|
|
||||||
/// </summary>
|
|
||||||
private void clearIndexes()
|
|
||||||
{
|
|
||||||
_indexedAnswers.Clear();
|
|
||||||
_gotAnswersForSignature.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A HashedList extends an ArrayList with methods to get a hash and to check equality
|
|
||||||
/// based on the elements of the list.
|
|
||||||
/// </summary>
|
|
||||||
public class HashedList : ArrayList
|
|
||||||
{
|
|
||||||
private bool _gotHashCode = false;
|
|
||||||
private int _hashCode;
|
|
||||||
|
|
||||||
public HashedList()
|
|
||||||
: base()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashedList(int capacity)
|
|
||||||
: base(capacity)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashedList(ICollection c)
|
|
||||||
: base(c)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug: Should override all the other methods that change this.
|
|
||||||
public override int Add(object value)
|
|
||||||
{
|
|
||||||
_gotHashCode = false;
|
|
||||||
return base.Add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
if (!_gotHashCode)
|
|
||||||
{
|
|
||||||
int hashCode = 1;
|
|
||||||
foreach (object obj in this)
|
|
||||||
hashCode = 31 * hashCode + (obj == null ? 0 : obj.GetHashCode());
|
|
||||||
_hashCode = hashCode;
|
|
||||||
_gotHashCode = true;
|
|
||||||
}
|
|
||||||
return _hashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (!(obj is ArrayList))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ArrayList objList = (ArrayList)obj;
|
|
||||||
if (objList.Count != Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = 0; i < Count; ++i)
|
|
||||||
{
|
|
||||||
object value = objList[i];
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
if (this[i] != null)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!value.Equals(this[i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If we keep an index on value, return the value, or null if we don't index it.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">the term to examine. Assume you already called YP.getValue(value)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static object getIndexValue(object value)
|
|
||||||
{
|
|
||||||
if (value is Atom || value is string || value is Int32 || value is DateTime)
|
|
||||||
return value;
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,166 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
public class ListPair : Functor2
|
|
||||||
{
|
|
||||||
public ListPair(object head, object tail) : base(Atom.DOT, head, tail)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object make(List<object> list)
|
|
||||||
{
|
|
||||||
if (list.Count <= 0)
|
|
||||||
return Atom.NIL;
|
|
||||||
|
|
||||||
object result = Atom.NIL;
|
|
||||||
// Start from the end.
|
|
||||||
for (int i = list.Count - 1; i >= 0; --i)
|
|
||||||
result = new ListPair(list[i], result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object make(object[] array)
|
|
||||||
{
|
|
||||||
if (array.Length <= 0)
|
|
||||||
return Atom.NIL;
|
|
||||||
|
|
||||||
object result = Atom.NIL;
|
|
||||||
// Start from the end.
|
|
||||||
for (int i = array.Length - 1; i >= 0; --i)
|
|
||||||
result = new ListPair(array[i], result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return a ListPair version of array, where repeated elements
|
|
||||||
/// (according to YP.termEqual) are removed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static object makeWithoutRepeatedTerms(object[] array)
|
|
||||||
{
|
|
||||||
if (array.Length <= 0)
|
|
||||||
return Atom.NIL;
|
|
||||||
|
|
||||||
// Start from the end.
|
|
||||||
object previousTerm = array[array.Length - 1];
|
|
||||||
object result = new ListPair(previousTerm, Atom.NIL);
|
|
||||||
for (int i = array.Length - 2; i >= 0; --i)
|
|
||||||
{
|
|
||||||
object term = array[i];
|
|
||||||
if (YP.termEqual(term, previousTerm))
|
|
||||||
continue;
|
|
||||||
result = new ListPair(term, result);
|
|
||||||
previousTerm = term;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return a ListPair version of array, where repeated elements
|
|
||||||
/// (according to YP.termEqual) are removed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static object makeWithoutRepeatedTerms(List<object> array)
|
|
||||||
{
|
|
||||||
if (array.Count <= 0)
|
|
||||||
return Atom.NIL;
|
|
||||||
|
|
||||||
// Start from the end.
|
|
||||||
object previousTerm = array[array.Count - 1];
|
|
||||||
object result = new ListPair(previousTerm, Atom.NIL);
|
|
||||||
for (int i = array.Count - 2; i >= 0; --i)
|
|
||||||
{
|
|
||||||
object term = array[i];
|
|
||||||
if (YP.termEqual(term, previousTerm))
|
|
||||||
continue;
|
|
||||||
result = new ListPair(term, result);
|
|
||||||
previousTerm = term;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object make(object element1)
|
|
||||||
{
|
|
||||||
return new ListPair(element1, Atom.NIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object make(object element1, object element2)
|
|
||||||
{
|
|
||||||
return new ListPair(element1, new ListPair(element2, Atom.NIL));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object make(object element1, object element2, object element3)
|
|
||||||
{
|
|
||||||
return new ListPair(element1,
|
|
||||||
new ListPair(element2, new ListPair(element3, Atom.NIL)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return an array of the elements in list or null if it is not
|
|
||||||
/// a proper list. If list is Atom.NIL, return an array of zero elements.
|
|
||||||
/// If the list or one of the tails of the list is Variable, raise an instantiation_error.
|
|
||||||
/// This does not call YP.getValue on each element.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="list"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static object[] toArray(object list)
|
|
||||||
{
|
|
||||||
list = YP.getValue(list);
|
|
||||||
if (list.Equals(Atom.NIL))
|
|
||||||
return new object[0];
|
|
||||||
|
|
||||||
List<object> result = new List<object>();
|
|
||||||
object element = list;
|
|
||||||
while (true) {
|
|
||||||
if (element == Atom.NIL)
|
|
||||||
break;
|
|
||||||
if (element is Variable)
|
|
||||||
throw new PrologException(Atom.a("instantiation_error"),
|
|
||||||
"List tail is an unbound variable");
|
|
||||||
if (!(element is Functor2 && ((Functor2)element)._name == Atom.DOT))
|
|
||||||
// Not a proper list.
|
|
||||||
return null;
|
|
||||||
result.Add(((Functor2)element)._arg1);
|
|
||||||
element = YP.getValue(((Functor2)element)._arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.Count <= 0)
|
|
||||||
return null;
|
|
||||||
return result.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,159 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A PrologException is used as the exception thrown by YP.throw(Term).
|
|
||||||
/// </summary>
|
|
||||||
public class PrologException : Exception
|
|
||||||
{
|
|
||||||
public readonly object _term;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a PrologException with the given Term. The printable exception message is the full Term.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Term">the term of the exception</param>
|
|
||||||
public PrologException(object Term)
|
|
||||||
: base(YP.getValue(Term).ToString())
|
|
||||||
{
|
|
||||||
_term = YP.makeCopy(Term, new Variable.CopyStore());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a PrologException where the Term is error(ErrorTerm, Message).
|
|
||||||
/// This uses YP.makeCopy to copy the ErrorTerm and Message so that they are valid after unbinding.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ErrorTerm">the error term of the error</param>
|
|
||||||
/// <param name="Messsage">the message term of the error. If this is a string, it is converted to an
|
|
||||||
/// Atom so it can be used by Prolog code.
|
|
||||||
/// Message, converted to a string, is use as the printable exception message.
|
|
||||||
/// </param>
|
|
||||||
public PrologException(object ErrorTerm, object Message)
|
|
||||||
: base(YP.getValue(Message).ToString())
|
|
||||||
{
|
|
||||||
if (Message is string)
|
|
||||||
Message = Atom.a((string)Message);
|
|
||||||
_term = YP.makeCopy(new Functor2(Atom.a("error"), ErrorTerm, Message), new Variable.CopyStore());
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TypeErrorInfo
|
|
||||||
{
|
|
||||||
public readonly Atom _Type;
|
|
||||||
public readonly object _Culprit;
|
|
||||||
public readonly object _Message;
|
|
||||||
|
|
||||||
public TypeErrorInfo(Atom Type, object Culprit, object Message)
|
|
||||||
{
|
|
||||||
_Type = Type;
|
|
||||||
_Culprit = Culprit;
|
|
||||||
_Message = Message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Return the TypeErrorInfo for this exception, or null if _term does not match
|
|
||||||
/// error(type_error(Type, Culprit), Message).
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public TypeErrorInfo getTypeErrorInfo()
|
|
||||||
{
|
|
||||||
if (!(_term is Functor2 && ((Functor2)_term)._name._name == "error"))
|
|
||||||
return null;
|
|
||||||
object errorTerm = ((Functor2)_term)._arg1;
|
|
||||||
if (!(errorTerm is Functor2 && ((Functor2)errorTerm)._name._name == "type_error"))
|
|
||||||
return null;
|
|
||||||
if (!(((Functor2)errorTerm)._arg1 is Atom))
|
|
||||||
return null;
|
|
||||||
return new TypeErrorInfo
|
|
||||||
((Atom)((Functor2)errorTerm)._arg1, ((Functor2)errorTerm)._arg2, ((Functor2)_term)._arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ExistenceErrorInfo
|
|
||||||
{
|
|
||||||
public readonly Atom _Type;
|
|
||||||
public readonly object _Culprit;
|
|
||||||
public readonly object _Message;
|
|
||||||
|
|
||||||
public ExistenceErrorInfo(Atom Type, object Culprit, object Message)
|
|
||||||
{
|
|
||||||
_Type = Type;
|
|
||||||
_Culprit = Culprit;
|
|
||||||
_Message = Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If _Type is procedure and _Culprit is name/artity, return the name. Otherwise return null.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object getProcedureName()
|
|
||||||
{
|
|
||||||
if (!(_Type._name == "procedure" &&
|
|
||||||
_Culprit is Functor2 && ((Functor2)_Culprit)._name == Atom.SLASH))
|
|
||||||
return null;
|
|
||||||
return ((Functor2)_Culprit)._arg1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If _Type is procedure and _Culprit is name/arity and arity is an integer, return the arity.
|
|
||||||
/// Otherwise return -1.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int getProcedureArity()
|
|
||||||
{
|
|
||||||
if (!(_Type._name == "procedure" &&
|
|
||||||
_Culprit is Functor2 && ((Functor2)_Culprit)._name == Atom.SLASH))
|
|
||||||
return -1;
|
|
||||||
if (!(((Functor2)_Culprit)._arg2 is int))
|
|
||||||
return -1;
|
|
||||||
return (int)((Functor2)_Culprit)._arg2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Return the ExistenceErrorInfo for this exception, or null if _term does not match
|
|
||||||
/// error(existence_error(Type, Culprit), Message). If the returned ExistenceErrorInfo _Culprit is
|
|
||||||
/// procedure, you can use its getProcedureName and getProcedureArity.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ExistenceErrorInfo getExistenceErrorInfo()
|
|
||||||
{
|
|
||||||
if (!(_term is Functor2 && ((Functor2)_term)._name._name == "error"))
|
|
||||||
return null;
|
|
||||||
object errorTerm = ((Functor2)_term)._arg1;
|
|
||||||
if (!(errorTerm is Functor2 && ((Functor2)errorTerm)._name._name == "existence_error"))
|
|
||||||
return null;
|
|
||||||
if (!(((Functor2)errorTerm)._arg1 is Atom))
|
|
||||||
return null;
|
|
||||||
return new ExistenceErrorInfo
|
|
||||||
((Atom)((Functor2)errorTerm)._arg1, ((Functor2)errorTerm)._arg2, ((Functor2)_term)._arg2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,514 +0,0 @@
|
||||||
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
|
|
||||||
|
|
||||||
* Yield Prolog 1.0.1 Released : it passes all but 9 of the 421 tests in the ISO Prolog test suite (97.8%).
|
|
||||||
|
|
||||||
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 });
|
|
||||||
}
|
|
||||||
|
|
||||||
----------- IMPORT EXTERNAL FUNCTIONS ----------
|
|
||||||
Using 'import' to call a static function
|
|
||||||
|
|
||||||
Taken mostly from http://yieldprolog.sourceforge.net/tutorial4.html
|
|
||||||
|
|
||||||
If we want to call a static function but it is not defined in the Prolog code, we can simply add an import directive.
|
|
||||||
(In Prolog, if you start a line with :- it is a directive to the compiler. Don't forget to end with a period.):
|
|
||||||
|
|
||||||
:- import('', [parent/2]).
|
|
||||||
uncle(Person, Uncle):- parent(Person, Parent), brother(Parent, Uncle).
|
|
||||||
|
|
||||||
The import directive has two arguments.
|
|
||||||
The first argument is the module where the imported function is found, which is always ''.
|
|
||||||
For C#, this means the imported function is in the same class as the calling function.
|
|
||||||
For Javascript and Python, this means the imported function is in the global scope.
|
|
||||||
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.
|
|
||||||
In this example, parent has two arguments, so we use parent/2.
|
|
||||||
|
|
||||||
Note: you can use an imported function in a dynamically defined goal, or a function in another class.
|
|
||||||
|
|
||||||
:- import('', [parent/2]).
|
|
||||||
uncle(Person, Uncle) :- Goal = parent(Person, Parent), Goal, brother(Parent, Uncle).
|
|
||||||
|
|
||||||
:- import('', ['OtherClass.parent'/2]).
|
|
||||||
uncle(Person, Uncle) :- 'OtherClass.parent'(Person, Parent), brother(Parent, Uncle).
|
|
||||||
|
|
||||||
--------- Round-about Hello Wonderful world ----------
|
|
||||||
//yp
|
|
||||||
:-import('',[sayit/1]).
|
|
||||||
sayhello(X):-sayit(X).
|
|
||||||
|
|
||||||
//cs
|
|
||||||
public void default_event_state_entry()
|
|
||||||
{
|
|
||||||
llSay(0,"prolog hello.");
|
|
||||||
foreach( bool ans in sayhello(Atom.a(@"wonderful world") )){};
|
|
||||||
}
|
|
||||||
|
|
||||||
PrologCallback sayit(object ans)
|
|
||||||
{
|
|
||||||
llSay(0,"sayit1");
|
|
||||||
string msg = "one answer is :"+((Variable)ans).getValue();
|
|
||||||
llSay(0,msg);
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
------------------ UPDATES -----------------
|
|
||||||
Yield Prolog 1.0 Released : It passes all but 15 of the 421 tests in the ISO Prolog test suite.
|
|
||||||
|
|
||||||
New Features:
|
|
||||||
* Added support for Prolog predicates read and read_term.
|
|
||||||
* In see, Added support for a char code list as the input.
|
|
||||||
Using this as the input for "fred" makes
|
|
||||||
set_prolog_flag(double_quotes, atom) and
|
|
||||||
set_prolog_flag(double_quotes, chars) pass the ISO test suite.
|
|
||||||
|
|
||||||
Fixed Bugs:
|
|
||||||
* In atom_chars, check for unbound tail in the char list.
|
|
||||||
This makes atom_chars pass the ISO test suite.
|
|
||||||
* In current_predicate, also check for static functions.
|
|
||||||
This makes current_predicate pass the ISO test suite.
|
|
||||||
|
|
||||||
Known Issues:
|
|
||||||
|
|
||||||
Here are the 9 errors of the 421 tests in the ISO test suite in
|
|
||||||
YieldProlog\source\prolog\isoTestSuite.P .
|
|
||||||
Some of these have a good excuse for why Yield Prolog produces the error. The rest will be addressed in a future maintenance release.
|
|
||||||
|
|
||||||
Goal: call((fail, 1))
|
|
||||||
Expected: type_error(callable, (fail, 1))
|
|
||||||
Extra Solutions found: failure
|
|
||||||
|
|
||||||
Goal: call((write(3), 1))
|
|
||||||
Expected: type_error(callable, (write(3), 1))
|
|
||||||
Extra Solutions found: type_error(callable, 1)
|
|
||||||
|
|
||||||
Goal: call((1; true))
|
|
||||||
Expected: type_error(callable, (1 ; true))
|
|
||||||
Extra Solutions found: type_error(callable, 1)
|
|
||||||
|
|
||||||
Goal: (catch(true, C, write('something')), throw(blabla))
|
|
||||||
Expected: system_error
|
|
||||||
Extra Solutions found: unexpected_ball(blabla)
|
|
||||||
|
|
||||||
Goal: catch(number_chars(A,L), error(instantiation_error, _), fail)
|
|
||||||
Expected: failure
|
|
||||||
Extra Solutions found: instantiation_error
|
|
||||||
|
|
||||||
Goal: Goal: (X = 1 + 2, 'is'(Y, X * 3))
|
|
||||||
Expected: [[X <-- (1 + 2), Y <-- 9]]
|
|
||||||
Extra Solutions found: type_error(evaluable, /(+, 2))
|
|
||||||
|
|
||||||
Goal: 'is'(77, N)
|
|
||||||
Expected: instantiation_error
|
|
||||||
Extra Solutions found: N <-- 77)
|
|
||||||
|
|
||||||
Goal: \+(!, fail)
|
|
||||||
Expected: success
|
|
||||||
Extra Solutions found: failure
|
|
||||||
|
|
||||||
((X=1;X=2), \+((!,fail)))
|
|
||||||
Expected: [[X <-- 1],[X <-- 2]]
|
|
||||||
Extra Solutions found: failure
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
========================= 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.ScriptBaseClass {
|
|
||||||
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.ScriptBaseClass {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
|
||||||
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An UndefinedPredicateException extends PrologException to create an existence_error exception.
|
|
||||||
/// </summary>
|
|
||||||
public class UndefinedPredicateException : PrologException
|
|
||||||
{
|
|
||||||
private Atom _predicateName;
|
|
||||||
private int _arity;
|
|
||||||
|
|
||||||
public UndefinedPredicateException(object message, Atom predicateName, int arity)
|
|
||||||
: base(new Functor2
|
|
||||||
(Atom.a("existence_error"), Atom.a("procedure"), new Functor2(Atom.a("/"), predicateName, arity)),
|
|
||||||
message)
|
|
||||||
{
|
|
||||||
_predicateName = predicateName;
|
|
||||||
_arity = arity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Atom PredicateName
|
|
||||||
{
|
|
||||||
get { return _predicateName; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Arity
|
|
||||||
{
|
|
||||||
get { return _arity; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,222 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008, Jeff Thompson
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
|
|
||||||
{
|
|
||||||
public interface IUnifiable
|
|
||||||
{
|
|
||||||
IEnumerable<bool> unify(object arg);
|
|
||||||
void addUniqueVariables(List<Variable> variableSet);
|
|
||||||
object makeCopy(Variable.CopyStore copyStore);
|
|
||||||
bool termEqual(object term);
|
|
||||||
bool ground();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A Variable is passed to a function so that it can be unified with
|
|
||||||
/// value or another Variable. See getValue and unify for details.
|
|
||||||
/// </summary>
|
|
||||||
public class Variable : IUnifiable
|
|
||||||
{
|
|
||||||
// Use _isBound separate from _value so that it can be bound to any value,
|
|
||||||
// including null.
|
|
||||||
private bool _isBound = false;
|
|
||||||
private object _value;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If this Variable is unbound, then just return this Variable.
|
|
||||||
/// Otherwise, if this has been bound to a value with unify, return the value.
|
|
||||||
/// If the bound value is another Variable, this follows the "variable chain"
|
|
||||||
/// to the end and returns the final value, or the final Variable if it is unbound.
|
|
||||||
/// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object getValue()
|
|
||||||
{
|
|
||||||
if (!_isBound)
|
|
||||||
return this;
|
|
||||||
|
|
||||||
object result = _value;
|
|
||||||
while (result is Variable)
|
|
||||||
{
|
|
||||||
if (!((Variable)result)._isBound)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
// Keep following the Variable chain.
|
|
||||||
result = ((Variable)result)._value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If this Variable is bound, then just call YP.unify to unify this with arg.
|
|
||||||
/// (Note that if arg is an unbound Variable, then YP.unify will bind it to
|
|
||||||
/// this Variable's value.)
|
|
||||||
/// Otherwise, bind this Variable to YP.getValue(arg) and yield once. After the
|
|
||||||
/// yield, return this Variable to the unbound state.
|
|
||||||
/// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="arg"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<bool> unify(object arg)
|
|
||||||
{
|
|
||||||
if (!_isBound)
|
|
||||||
{
|
|
||||||
_value = YP.getValue(arg);
|
|
||||||
if (_value == this)
|
|
||||||
// We are unifying this unbound variable with itself, so leave it unbound.
|
|
||||||
yield return false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_isBound = true;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
yield return false;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Remove the binding.
|
|
||||||
_isBound = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// disable warning on l1, don't see how we can
|
|
||||||
// code this differently
|
|
||||||
#pragma warning disable 0168
|
|
||||||
foreach (bool l1 in YP.unify(this, arg))
|
|
||||||
yield return false;
|
|
||||||
#pragma warning restore 0168
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
object value = getValue();
|
|
||||||
if (value == this)
|
|
||||||
return "_Variable";
|
|
||||||
else
|
|
||||||
return getValue().ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If bound, call YP.addUniqueVariables on the value. Otherwise, if this unbound
|
|
||||||
/// variable is not already in variableSet, add it.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="variableSet"></param>
|
|
||||||
public void addUniqueVariables(List<Variable> variableSet)
|
|
||||||
{
|
|
||||||
if (_isBound)
|
|
||||||
YP.addUniqueVariables(getValue(), variableSet);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (variableSet.IndexOf(this) < 0)
|
|
||||||
variableSet.Add(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If bound, return YP.makeCopy for the value, else return copyStore.getCopy(this).
|
|
||||||
/// However, if copyStore is null, just return this.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="copyStore"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object makeCopy(Variable.CopyStore copyStore)
|
|
||||||
{
|
|
||||||
if (_isBound)
|
|
||||||
return YP.makeCopy(getValue(), copyStore);
|
|
||||||
else
|
|
||||||
return copyStore == null ? this : copyStore.getCopy(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool termEqual(object term)
|
|
||||||
{
|
|
||||||
if (_isBound)
|
|
||||||
return YP.termEqual(getValue(), term);
|
|
||||||
else
|
|
||||||
return this == YP.getValue(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ground()
|
|
||||||
{
|
|
||||||
if (_isBound)
|
|
||||||
// This is usually called by YP.ground which already did getValue, so this
|
|
||||||
// should never be reached, but check anyway.
|
|
||||||
return YP.ground(getValue());
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A CopyStore is used by makeCopy to track which Variable objects have
|
|
||||||
/// been copied.
|
|
||||||
/// </summary>
|
|
||||||
public class CopyStore
|
|
||||||
{
|
|
||||||
private List<Variable> _inVariableSet = new List<Variable>();
|
|
||||||
private List<Variable> _outVariableSet = new List<Variable>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If inVariable has already been copied, return its copy. Otherwise,
|
|
||||||
/// return a fresh Variable associated with inVariable.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inVariable"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Variable getCopy(Variable inVariable)
|
|
||||||
{
|
|
||||||
int index = _inVariableSet.IndexOf(inVariable);
|
|
||||||
if (index >= 0)
|
|
||||||
return _outVariableSet[index];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Variable outVariable = new Variable();
|
|
||||||
_inVariableSet.Add(inVariable);
|
|
||||||
_outVariableSet.Add(outVariable);
|
|
||||||
return outVariable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return the number of unique variables that have been copied.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int getNUniqueVariables()
|
|
||||||
{
|
|
||||||
return _inVariableSet.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,12 +0,0 @@
|
||||||
//c#
|
|
||||||
namespace SecondLife {
|
|
||||||
public class Script : OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass
|
|
||||||
{
|
|
||||||
public Script() { }
|
|
||||||
|
|
||||||
public void default_event_state_entry( )
|
|
||||||
{
|
|
||||||
llSay(0, "testing, I've been touched");
|
|
||||||
}
|
|
||||||
|
|
||||||
}}
|
|
|
@ -39,6 +39,7 @@ using System.IO;
|
||||||
using System.Runtime.Serialization.Formatters.Binary;
|
using System.Runtime.Serialization.Formatters.Binary;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
|
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
|
||||||
|
using OpenSim.Region.ScriptEngine.Shared.CodeTools;
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
{
|
{
|
||||||
|
@ -87,13 +88,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
Unload = 2
|
Unload = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<UUID, String> scriptList =
|
|
||||||
new Dictionary<UUID, string>();
|
|
||||||
|
|
||||||
public Dictionary<uint, Dictionary<UUID, InstanceData>> Scripts =
|
public Dictionary<uint, Dictionary<UUID, InstanceData>> Scripts =
|
||||||
new Dictionary<uint, Dictionary<UUID, InstanceData>>();
|
new Dictionary<uint, Dictionary<UUID, InstanceData>>();
|
||||||
|
|
||||||
private Compiler.LSL.Compiler LSLCompiler;
|
private Compiler LSLCompiler;
|
||||||
|
|
||||||
public Scene World
|
public Scene World
|
||||||
{
|
{
|
||||||
|
@ -105,7 +103,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
// Create our compiler
|
// Create our compiler
|
||||||
LSLCompiler = new Compiler.LSL.Compiler(m_scriptEngine);
|
LSLCompiler = new Compiler(m_scriptEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void _StartScript(uint localID, UUID itemID, string Script,
|
public void _StartScript(uint localID, UUID itemID, string Script,
|
||||||
|
@ -136,23 +134,22 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
if (m_host.TaskInventory.TryGetValue(itemID, out taskInventoryItem))
|
if (m_host.TaskInventory.TryGetValue(itemID, out taskInventoryItem))
|
||||||
assetID = taskInventoryItem.AssetID;
|
assetID = taskInventoryItem.AssetID;
|
||||||
|
|
||||||
|
ScenePresence presence =
|
||||||
|
World.GetScenePresence(taskInventoryItem.OwnerID);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
|
||||||
if (scriptList.TryGetValue(assetID, out CompiledScriptFile))
|
|
||||||
{
|
|
||||||
m_log.InfoFormat("[SCRIPT]: Found existing compile of "+
|
|
||||||
"assetID {0}: {1}", assetID, CompiledScriptFile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Compile (We assume LSL)
|
// Compile (We assume LSL)
|
||||||
CompiledScriptFile =
|
CompiledScriptFile =
|
||||||
LSLCompiler.PerformScriptCompile(Script);
|
LSLCompiler.PerformScriptCompile(Script,
|
||||||
|
assetID.ToString());
|
||||||
|
|
||||||
|
if (presence != null)
|
||||||
|
presence.ControllingClient.SendAgentAlertMessage(
|
||||||
|
"Compile successful", false);
|
||||||
|
|
||||||
m_log.InfoFormat("[SCRIPT]: Compiled assetID {0}: {1}",
|
m_log.InfoFormat("[SCRIPT]: Compiled assetID {0}: {1}",
|
||||||
assetID, CompiledScriptFile);
|
assetID, CompiledScriptFile);
|
||||||
scriptList.Add(assetID, CompiledScriptFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceData id = new InstanceData();
|
InstanceData id = new InstanceData();
|
||||||
|
|
||||||
|
@ -201,6 +198,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
}
|
}
|
||||||
catch (Exception e) // LEGIT: User Scripting
|
catch (Exception e) // LEGIT: User Scripting
|
||||||
{
|
{
|
||||||
|
if (presence != null)
|
||||||
|
presence.ControllingClient.SendAgentAlertMessage(
|
||||||
|
"Script saved with errors, check debug window!",
|
||||||
|
false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// DISPLAY ERROR INWORLD
|
// DISPLAY ERROR INWORLD
|
||||||
|
|
|
@ -83,8 +83,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
|
||||||
// private static int instanceID = new Random().Next(0, int.MaxValue); // Unique number to use on our compiled files
|
// private static int instanceID = new Random().Next(0, int.MaxValue); // Unique number to use on our compiled files
|
||||||
private static UInt64 scriptCompileCounter = 0; // And a counter
|
private static UInt64 scriptCompileCounter = 0; // And a counter
|
||||||
|
|
||||||
public IScriptEngine m_scriptEngine;
|
public IEventReceiver m_scriptEngine;
|
||||||
public Compiler(IScriptEngine scriptEngine)
|
public Compiler(IEventReceiver scriptEngine)
|
||||||
{
|
{
|
||||||
m_scriptEngine = scriptEngine;
|
m_scriptEngine = scriptEngine;
|
||||||
ReadConfig();
|
ReadConfig();
|
||||||
|
|
|
@ -1957,6 +1957,7 @@
|
||||||
<Reference name="OpenSim.Region.Interfaces" />
|
<Reference name="OpenSim.Region.Interfaces" />
|
||||||
<Reference name="OpenSim.Region.ScriptEngine.Shared"/>
|
<Reference name="OpenSim.Region.ScriptEngine.Shared"/>
|
||||||
<Reference name="OpenSim.Region.ScriptEngine.Shared.Api"/>
|
<Reference name="OpenSim.Region.ScriptEngine.Shared.Api"/>
|
||||||
|
<Reference name="OpenSim.Region.ScriptEngine.Shared.CodeTools"/>
|
||||||
<Reference name="Microsoft.JScript"/>
|
<Reference name="Microsoft.JScript"/>
|
||||||
<Reference name="Nini.dll" />
|
<Reference name="Nini.dll" />
|
||||||
<Reference name="log4net.dll"/>
|
<Reference name="log4net.dll"/>
|
||||||
|
|
Loading…
Reference in New Issue