Author Topic: LISP Result Buffer  (Read 2178 times)

0 Members and 1 Guest are viewing this topic.

jtoverka

  • Newt
  • Posts: 127
LISP Result Buffer
« on: September 28, 2020, 03:25:55 PM »
I am looking for a way to handle more complex Result Buffers such as deeply nested lists. I would like it to convert the Result Buffer to a List<object>. If someone has code they would like to share I would appreciate it. Here is what I have so far.

Code: [Select]
/// <summary>
/// Converts a <see cref="ResultBuffer"/> to <see cref="List{object}"/>. If the Lisp arguments are below the minimum or above the maximum required, an exception will be thrown.
/// </summary>
/// <param name="arguments"></param>
/// <param name="minimum"></param>
/// <param name="maximum"></param>
/// <returns><see cref="List{TypedValue}"/></returns>
/// <exception cref="System.Exception"/>
public static List<object> HandleLispArguments(ResultBuffer arguments, int minimum, int maximum)
{
    if (arguments == null)
        throw new System.Exception("too few arguments");

    TypedValue[] rawArgs = arguments.AsArray();
    List<object> Arguments = new List<object>();
           
    // List Depth
    int depth = 0;
           
    Action<List<object>, int, object> Add = null;
           
    Add = (list, depth, item) =>
    {
        if (depth == 0)
            list.Add(item);
        else
            Add((List<object>)list[list.Count - 1], --depth, item);
    };

    foreach (TypedValue item in rawArgs)
    {
        object selected = item;
        if (item.TypeCode == (short)LispDataType.ListBegin)
        {
            Add(Arguments, depth, new List<object>());
            depth++;
            selected = null;
        }
        else if(item.TypeCode == (short)LispDataType.ListEnd)
        {
            depth--;
            selected = null;
        }

        if (selected != null)
            Add(Arguments, depth, selected);
    }

    if (Arguments.Count < minimum)
        throw new System.Exception("too few arguments");
    else if (Arguments.Count > maximum)
        throw new System.Exception("too many arguments");

    return Arguments;
}

Chumplybum

  • Newt
  • Posts: 97
Re: LISP Result Buffer
« Reply #1 on: September 28, 2020, 07:10:34 PM »
have a look here: https://forums.augi.com/showthread.php?154713-NET-Return-Conversion-to-TypedValue/page2, it looks similar to what your trying to achieve


Cheers, Mark

DavidS

  • Mosquito
  • Posts: 15
Re: LISP Result Buffer
« Reply #2 on: September 29, 2020, 03:38:03 PM »
I don't know what became of it but Tony Tanzillo was testing something similar...

http://www.theswamp.org/index.php?topic=43181.msg483994#msg483994

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: LISP Result Buffer
« Reply #3 on: September 30, 2020, 01:55:16 AM »
Hi,

From the times I tried to mix LISP and .NET, here're some helpers for data exchange between LISP and .NET, some methods are also used to control the arguments validity and throw exceptions of type LispException.

Code - C#: [Select]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using Autodesk.AutoCAD.Geometry;
  4.  
  5. using System;
  6. using System.Linq;
  7.  
  8. namespace Gile.AutoCAD.LispExtension
  9. {
  10.     /// <summary>
  11.     /// Provides properties an methods to help data exchange between LISP and .NET.
  12.     /// Some methods are also used to control the arguments validity and throw exceptions of type LispException.
  13.     /// </summary>
  14.     static class Lisp
  15.     {
  16.         #region TypedValue Constants
  17.  
  18.         /// <summary>
  19.         /// Gets the value LispDataType.Nil
  20.         /// </summary>
  21.         public static TypedValue Nil => new TypedValue(5019);
  22.  
  23.         /// <summary>
  24.         /// Gets the value LispDataType.T_atom
  25.         /// </summary>
  26.         public static TypedValue T => new TypedValue(5021);
  27.  
  28.         /// <summary>
  29.         /// Gets the value LispDataType.ListBegin
  30.         /// </summary>
  31.         public static TypedValue ListBegin => new TypedValue(5016);
  32.  
  33.         /// <summary>
  34.         /// Gets the value LispDataType.ListEnd
  35.         /// </summary>
  36.         public static TypedValue ListEnd => new TypedValue(5017);
  37.  
  38.         /// <summary>
  39.         /// Gets the value LispDataType.DottedPair
  40.         /// </summary>
  41.         public static TypedValue DottedPair => new TypedValue(5018);
  42.  
  43.         /// <summary>
  44.         /// Gets the value LispDataType.Void
  45.         /// </summary>
  46.         public static TypedValue Void => new TypedValue(5014);
  47.  
  48.         #endregion
  49.  
  50.         #region Type .NET -> TypedValue
  51.  
  52.         /// <summary>
  53.         /// Gets the value as a TypedValue.
  54.         /// </summary>
  55.         /// <param name="i">Instance of Int32 which the method applies to.</param>
  56.         /// <returns>The value as TypedValue.</returns>
  57.         public static TypedValue ToLispValue(this int i) => new TypedValue(5010, i);
  58.  
  59.         /// <summary>
  60.         /// Gets the value as a TypedValue.
  61.         /// </summary>
  62.         /// <param name="d">Instance of Double which the method applies to.</param>
  63.         /// <returns>The value as TypedValue.</returns>
  64.         public static TypedValue ToLispValue(this double d) => new TypedValue(5001, d);
  65.  
  66.         /// <summary>
  67.         /// Gets the value as a TypedValue.
  68.         /// </summary>
  69.         /// <param name="s">Instance of String which the method applies to.</param>
  70.         /// <returns>The value as TypedValue.</returns>
  71.         public static TypedValue ToLispValue(this string s) => new TypedValue(5005, s);
  72.  
  73.         /// <summary>
  74.         /// Gets the value as a TypedValue.
  75.         /// </summary>
  76.         /// <param name="id">Instance of ObjectId which the method applies to.</param>
  77.         /// <returns>The value as TypedValue.</returns>
  78.         public static TypedValue ToLispValue(this ObjectId id) => new TypedValue(5006, id);
  79.  
  80.         /// <summary>
  81.         /// Gets the value as a TypedValue.
  82.         /// </summary>
  83.         /// <param name="ss">Instance of SelectionSet which the method applies to.</param>
  84.         /// <returns>The value as TypedValue.</returns>
  85.         public static TypedValue ToLispValue(this SelectionSet ss) => new TypedValue(5007, ss);
  86.  
  87.         #endregion
  88.  
  89.         #region TypedValue -> type .NET (type validity control)
  90.  
  91.         /// <summary>
  92.         /// Gets the value as Int16.
  93.         /// </summary>
  94.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  95.         /// <returns>The value as Int16.</returns>
  96.         /// <exception cref="ArgumentTypeException">
  97.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Int16.
  98.         /// </exception>
  99.         public static short GetAsShort(this TypedValue tv)
  100.         {
  101.             if (tv.TypeCode == 5003)
  102.             {
  103.                 return (short)tv.Value;
  104.             }
  105.             else
  106.             {
  107.                 throw new ArgumentTypeException("shortp", tv);
  108.             }
  109.         }
  110.  
  111.         /// <summary>
  112.         /// Gets the value as Int32.
  113.         /// </summary>
  114.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  115.         /// <returns>The value as Int32 (Int16 type is converted).</returns>
  116.         /// <exception cref="ArgumentTypeException">
  117.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Int16 or LispDataType.Tnt32.
  118.         /// </exception>
  119.         public static int GetAsInteger(this TypedValue tv)
  120.         {
  121.             switch (tv.TypeCode)
  122.             {
  123.                 case 5003:
  124.                 case 5010:
  125.                     return Convert.ToInt32(tv.Value);
  126.                 default:
  127.                     throw new ArgumentTypeException("fixnump", tv);
  128.             }
  129.         }
  130.  
  131.         /// <summary>
  132.         /// Gets the value as Double.
  133.         /// </summary>
  134.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  135.         /// <returns>The value as Double.</returns>
  136.         /// <exception cref="ArgumentTypeException">
  137.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Double, LispDataType.Angle or LispDataType.Orientation.
  138.         /// </exception>
  139.         public static double GetAsDouble(this TypedValue tv)
  140.         {
  141.             if (tv.TypeCode == 5001 || tv.TypeCode == 5004 || tv.TypeCode == 5008)
  142.             {
  143.                 return (double)tv.Value;
  144.             }
  145.             else
  146.             {
  147.                 throw new ArgumentTypeException("shortp", tv);
  148.             }
  149.         }
  150.  
  151.  
  152.         /// <summary>
  153.         /// Gets the value as number (accepte tous les types numériques).
  154.         /// </summary>
  155.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  156.         /// <returns>The value as double (integer inputs are converted).</returns>
  157.         /// <exception cref="ArgumentTypeException">
  158.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Int16, LispDataType.Tnt32,
  159.         /// LispDataType.Double, LispDataType.Angle or LispDataType.Orientation.
  160.         /// </exception>
  161.         public static double GetAsNumber(this TypedValue tv)
  162.         {
  163.             switch (tv.TypeCode)
  164.             {
  165.                 case 5003:
  166.                 case 5010:
  167.                 case 5001:
  168.                 case 5004:
  169.                 case 5008:
  170.                     return Convert.ToDouble(tv.Value);
  171.                 default:
  172.                     throw new ArgumentTypeException("numberp", tv);
  173.             }
  174.         }
  175.  
  176.         /// <summary>
  177.         /// Gets the value as point 2d (the value may represent any list of two numbers).
  178.         /// </summary>
  179.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  180.         /// <returns>The value as Point2d.</returns>
  181.         /// <exception cref="ArgumentTypeException">
  182.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Point2d.
  183.         /// </exception>
  184.         public static Point2d GetAsPoint2d(this TypedValue tv)
  185.         {
  186.             if (tv.TypeCode != 5002)
  187.             {
  188.                 throw new ArgumentTypeException("point 2D", tv);
  189.             }
  190.  
  191.             return (Point2d)tv.Value;
  192.         }
  193.  
  194.         /// <summary>
  195.         /// Gets the value as Point3d (the value may represent any list of three numbers).
  196.         /// </summary>
  197.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  198.         /// <returns>The value as Point3d.</returns>
  199.         /// <exception cref="ArgumentTypeException">
  200.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Point3d.
  201.         /// </exception>
  202.         public static Point3d GetAsPoint3d(this TypedValue tv)
  203.         {
  204.             if (tv.TypeCode != 5009)
  205.             {
  206.                 throw new ArgumentTypeException("point 3D", tv);
  207.             }
  208.  
  209.             return (Point3d)tv.Value;
  210.         }
  211.  
  212.         /// <summary>
  213.         /// Gets the value as point (the value may represent any list of two or three numbers).
  214.         /// </summary>
  215.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  216.         /// <returns>The value as Point3d.</returns>
  217.         /// <exception cref="ArgumentTypeException">
  218.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Point3d or TypeCode.Point2d.
  219.         /// </exception>
  220.         public static Point3d GetAsPoint(this TypedValue tv)
  221.         {
  222.             switch (tv.TypeCode)
  223.             {
  224.                 case 5002:
  225.                     var pt = (Point2d)tv.Value;
  226.                     return new Point3d(pt.X, pt.Y, 0.0);
  227.                 case 5009:
  228.                     return (Point3d)tv.Value;
  229.                 default:
  230.                     throw new ArgumentTypeException("point2D/3D", tv);
  231.             }
  232.         }
  233.  
  234.         /// <summary>
  235.         /// Gets the value as String.
  236.         /// </summary>
  237.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  238.         /// <returns>The value as string</returns>
  239.         /// <exception cref="ArgumentTypeException">
  240.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Text.
  241.         /// </exception>
  242.         public static string GetAsString(this TypedValue tv)
  243.         {
  244.             if (tv.TypeCode != 5005)
  245.             {
  246.                 throw new ArgumentTypeException("stringp", tv);
  247.             }
  248.  
  249.             return (string)tv.Value;
  250.         }
  251.  
  252.         /// <summary>
  253.         /// Gets the value as ObjectId (la valeur représente un ENAME).
  254.         /// </summary>
  255.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  256.         /// <returns>The value as ObjectId</returns>
  257.         /// <exception cref="ArgumentTypeException">
  258.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.ObjectId.
  259.         /// </exception>
  260.         public static ObjectId GetAsObjectId(this TypedValue tv)
  261.         {
  262.             if (tv.TypeCode != 5006)
  263.             {
  264.                 throw new ArgumentTypeException("lentityp", tv);
  265.             }
  266.  
  267.             return (ObjectId)tv.Value;
  268.         }
  269.  
  270.         /// <summary>
  271.         /// Gets the value as SelectionSet.
  272.         /// </summary>
  273.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  274.         /// <returns>The value as SelectionSet</returns>
  275.         /// <exception cref="ArgumentTypeException">
  276.         /// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.SelectionSet.
  277.         /// </exception>
  278.         public static SelectionSet GetAsSelectionSet(this TypedValue tv)
  279.         {
  280.             if (tv.TypeCode != 5007)
  281.             {
  282.                 throw new ArgumentTypeException("lselsetp", tv);
  283.             }
  284.  
  285.             return (SelectionSet)tv.Value;
  286.         }
  287.  
  288.         /// <summary>
  289.         /// Evaluates if the value is nil.
  290.         /// </summary>
  291.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  292.         /// <returns>true, if TypeCode equals LispDataType.Nil ; false, otherwise.</returns>
  293.         public static bool IsNil(this TypedValue tv) =>
  294.             tv.TypeCode == 5019;
  295.  
  296.         /// <summary>
  297.         /// Evaluates if the value is T.
  298.         /// </summary>
  299.         /// <param name="tv">Instance of TypedValue which the method applies to.</param>
  300.         /// <returns>true, if TypeCode equals LispDataType.T_atom ; false, otherwise.</returns>
  301.         public static bool IsT(this TypedValue tv) =>
  302.             tv.TypeCode == 5021;
  303.  
  304.         #endregion
  305.  
  306.         #region TypedValue -> LISP list (type validity control)
  307.  
  308.         /// <summary>
  309.         /// Gets a list contained in a TypedValue array.
  310.         /// </summary>
  311.         /// <param name="args">TypedValue array the method applies to.</param>
  312.         /// <param name="index">Start index of the list (first parenthesis) in the array.</param>
  313.         /// <returns>A TypedValue array corresponding to the list contents.</returns>
  314.         /// <exception cref="ArgumentTypeException">
  315.         /// ArgumentTypeException is thrown if the TypeCode at specified index is not equal to ListDataType.ListBegin or ListDataType.Nil.
  316.         /// </exception>
  317.         public static TypedValue[] GetListContent(this TypedValue[] args, int index)
  318.         {
  319.             if (args[index].IsNil())
  320.                 return new TypedValue[0];
  321.  
  322.             if (args[index].TypeCode != 5016)
  323.                 throw new ArgumentTypeException("listp", args[index]);
  324.  
  325.             int cnt = 1;
  326.             return args
  327.                 .Skip(index + 1)
  328.                 .TakeWhile(tv =>
  329.                 {
  330.                     switch (tv.TypeCode)
  331.                     {
  332.                         case 5016: cnt++; break;
  333.                         case 5017: cnt--; break;
  334.                         default: break;
  335.                     }
  336.                     return cnt != 0;
  337.                 })
  338.                 .ToArray();
  339.         }
  340.  
  341.         #endregion
  342.  
  343.         #region ResultBuffer -> TypedValue[] (items number validity control)
  344.  
  345.         /// <summary>
  346.         /// Converts the ResultBuffer into TypedValue array controling the number of items.
  347.         /// </summary>
  348.         /// <param name="resbuf">Instance of ResultBuffer which the method applies to.</param>
  349.         /// <param name="length">Number of items the array is supposed to contain.</param>
  350.         /// <returns>Un table de TypedValue.</returns>
  351.         /// <exception cref="TooFewArgsException">
  352.         /// TooFewArgsException is thrown <paramref name="resbuf"/> is null or if the number of items is lower than <paramref name="length"/>.
  353.         /// </exception>
  354.         /// <exception cref="TooManyArgsException">
  355.         /// TooManyArgsException is thrown if the number of items is greater than <paramref name="length"/>.
  356.         /// </exception>
  357.         public static TypedValue[] GetAsArray(this ResultBuffer resbuf, int length)
  358.         {
  359.             return resbuf.GetAsArray(length, length);
  360.         }
  361.  
  362.         /// <summary>
  363.         /// Converts the ResultBuffer into TypedValue array controling the number of items.
  364.         /// </summary>
  365.         /// <param name="resbuf">Instance of ResultBuffer which the method applies to.</param>
  366.         /// <param name="minLength">Minimum number of items the array is supposed to contain.</param>
  367.         /// <param name="maxLength">Maximum number of items the array is supposed to contain.</param>
  368.         /// <returns>A TypedValue array.</returns>
  369.         /// <exception cref="System.ArgumentOutOfRangeException">
  370.         /// ArgumentOutOfRangeException is thrown if <paramref name="minLength"/> is lower than 0.
  371.         /// </exception>
  372.         /// <exception cref="System.ArgumentOutOfRangeException">
  373.         /// ArgumentOutOfRangeException is thrown if <paramref name="maxLength"/> is lower than <paramref name="minLength"/>.
  374.         /// </exception>
  375.         /// <exception cref="TooFewArgsException">
  376.         /// TooFewArgsException is thrown if <paramref name="resbuf"/> is null or if the number of items is lower than <paramref name="minLength"/>.
  377.         /// </exception>
  378.         /// <exception cref="TooManyArgsException">
  379.         /// TooManyArgsException is thrown if the number of items eis greater than <paramref name="length"/>.
  380.         /// </exception>
  381.         public static TypedValue[] GetAsArray(this ResultBuffer resbuf, int minLength, int maxLength)
  382.         {
  383.             if (minLength < 0)
  384.             {
  385.                 throw new ArgumentOutOfRangeException("minLength", "minLength must be lower than 0");
  386.             }
  387.  
  388.             if (maxLength < minLength)
  389.             {
  390.                 throw new ArgumentOutOfRangeException("maxLength", "maxLength must be greater than minLength");
  391.             }
  392.  
  393.             if (resbuf == null)
  394.             {
  395.                 if (minLength == 0)
  396.                 {
  397.                     return new TypedValue[0];
  398.                 }
  399.                 else
  400.                 {
  401.                     throw new TooFewArgsException();
  402.                 }
  403.             }
  404.             TypedValue[] args = resbuf.AsArray();
  405.             if (args.Length < minLength)
  406.             {
  407.                 throw new TooFewArgsException();
  408.             }
  409.  
  410.             if (args.Length > maxLength)
  411.             {
  412.                 throw new TooManyArgsException();
  413.             }
  414.  
  415.             return args;
  416.         }
  417.  
  418.         #endregion
  419.     }
  420. }
  421.  

LispException type:
Code - C#: [Select]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.Runtime;
  3.  
  4. namespace Gile.AutoCAD.LispExtension
  5. {
  6.     /// <summary>
  7.     /// Base class for LISP exceptions.
  8.     /// </summary>
  9.     class LispException : System.Exception
  10.     {
  11.         /// <summary>
  12.         /// Creates a new instance.
  13.         /// </summary>
  14.         public LispException(string msg) : base(msg) { }
  15.     }
  16.  
  17.     /// <summary>
  18.     /// Exception when too few arguments.
  19.     /// </summary>
  20.     class TooFewArgsException : LispException
  21.     {
  22.         /// <summary>
  23.         /// Creates a new instance.
  24.         /// </summary>
  25.         public TooFewArgsException() : base("too few arguments") { }
  26.     }
  27.  
  28.     /// <summary>
  29.     /// Exception when too many arguments.
  30.     /// </summary>
  31.     class TooManyArgsException : LispException
  32.     {
  33.         /// <summary>
  34.         /// Creates a new instance.
  35.         /// </summary>
  36.         public TooManyArgsException() : base("too many arguments") { }
  37.     }
  38.  
  39.     /// <summary>
  40.     /// Exception when bad argument type.
  41.     /// </summary>
  42.     class ArgumentTypeException : LispException
  43.     {
  44.         /// <summary>
  45.         /// Creates a new instance.
  46.         /// </summary>
  47.         /// <param name="s">String to display in the message (fixnump, numberp, listp, consp, stringp, lentityp, lselsetp, ...).</param>
  48.         /// <param name="tv">Concerned value.</param>
  49.         public ArgumentTypeException(string s, TypedValue tv)
  50.             : base(string.Format(
  51.             "bad argument type: {0}: {1}",
  52.             s, tv.TypeCode == (int)LispDataType.Nil ? "nil" : tv.Value))
  53.         { }
  54.     }
  55. }
  56.  
Speaking English as a French Frog

jtoverka

  • Newt
  • Posts: 127
Re: LISP Result Buffer
« Reply #4 on: September 30, 2020, 07:47:28 AM »
Thanks gile!  :-)
This is a complete implementation for what I am looking for.