CGScript - Coding guideline

From Catglobe Wiki
Revision as of 05:29, 18 October 2013 by Wikicatglobe (talk | contribs)
Jump to: navigation, search

<accesscontrol>Main:MyGroup</accesscontrol>

Objects

Objects in cgscript can be created by doing following this guideline.

First an object must be created. The normal name for this is xxxCGO where xxx is the name of the object in cgscript.

This object must inherit from CgScriptObject and it must have a CgAttribute.

For example, here is the absolute minimal class:

[Cg(OBJECT_TYPE_NAME, "write the documentation for the class here")]
internal class MyObjectCGO : CgScriptObject
{
   private const string OBJECT_TYPE_NAME = "MyObject";
   public override string ObjectTypeName
   {
      get { return OBJECT_TYPE_NAME; }
   }
}

The class must be internal or public, and non-abstract, and must not play with generics. The exception is that it may inherit from a generic baseclass (which then inherits from CgScriptObject), or implement a generic interface.

Inheritance

A CgScriptObject may utilize inheritance as a normal .NET object. CgScript will not be aware of this, it just sees all inherited methods, properties, etc. as belonging to the class.

Object functions

Functions are exposed as cgscript functions by marking them with the CgAttribute and also marking all the parameters with the CgAttribute (see #Parameters).

The function must be internal or public, and non-abstract, and must not play with generics.

Overloads are supported, so the same name can be defined multiple times with different parameters. The rules for this is similar to C#s overload resolution (but not identical). If in doubt, don't use fancy parameters.

Example:

[Cg("ContainsKey", "Determines whether the dictionary contains the specified key with type is a string.")]
public bool ContainsKey([Cg("key", "Check with specific key")]string key)
{
   return _dict.ContainsKey(key);
}

A function may be static, but from inside cgscript it will be exposed as a member function.

Object properties

Properties have almost the same requirements as methods.

Example:

[Cg("Count", "Gets the number of key/value pairs contained in the dictionary.")]
public int Count
{
   get { return _dict.Count; }
}

The getter and setter may have different visibility, e.g. the getter may be public and the setter may be private. In that case, only the getter is accessible from CgScript.

However, note that this alternative marking of the getter/setter may not do what you expect:

public int Count
{
   [Cg("Count", "Gets the number of key/value pairs contained in the dictionary.")]
   get { return _dict.Count; }
}

This will register the getter as a function (ie. from cgscript you would have to call o.Count() instead of o.Count)

Object indexer

Indexers are a special construction in C# (and VB). They look a little bit like both Properties and Methods. So the syntax for registering them in CgScript is a little special.

The indexer must be marked with a CgAttribute, and the getter/setter must be marked with a CgAttribute also, the name must be get_Item/set_Item respectively in order to use it as an indexer inside CgScript. Furthermore the setter must use the very special "param:" prefix on the CgAttribute to document the value.

Example:

public IConstant this[[Cg("key", "The key used to lookup the value.")] string key]
{
   [Cg("get_Item", "Get an item based on a key.")]
   get { return _dict[key]; }
   [Cg("set_Item", "Set an item based on a key and a value.")]
   [param:Cg("value", "The value to set.")]
   set { _dict[key] = value; }
}

Parameters

CgScript objects support a number of types, that are automatically converted when calling the function and returning from the function:

  • Void (For return values only) - Constant.Empty is returned
  • string - Automatically converted to and from a StringConstant
  • double - Automatically converted to and from a NumberConstant
  • int - Automatically converted to and from a NumberConstant
  • bool - Automatically converted to and from a BooleanConstant
  • CGDateTime - Automatically converted to and from a DateTimeConstant
  • Any type that implement IConstant - No conversion is done

Example:

[Cg("Add", "Adds the specified key and value to the dictionary with type of key is a string.")]
public bool Add([Cg("key", "Add with specific key")] string key,
                [Cg("value", "Add with specific value")] IConstant constant)

There are some special parameter types, that must all NOT be marked with a CgAttribute:

  • Interpreter - If you require the interpreter to do something, you can get it by adding a Interpreter parameter. You are probably doing something wrong if you need this. If you do need it, then you should be aware that your object may be shared among several interpreters, and you should therefore NOT store the value anywhere.
  • IList<IConstant> - This is roughly equivalent to a normal C# method that takes a "params object[]". This enables you to do advanced scenarios where the parameters from cgscript cannot be predicted. For obvious reasons there can be no other parameters marked with CgAttribute.
  • other - If a parameter is not marked with a CgAttribute, it is presumed it is a IoC type that must be resolved when calling the function. This works for Constructors, Methods and Properties.

Overload resolution

To find the right overload, a score is calculated.

A function that takes an IList<IConstant> as parameter is always a match, but the lowest priority match.

A function that takes the exact type (or a type with a known conversion) will be a better match than a function that takes a very generic superclass. For example, a function x that has two overloads, one takes an IConstant and another that takes an ArrayConstant, when called with an ArrayConstant, the second overload takes precedence.

Due to the automapping some constructs may have the same overload. For example a function x that has two overloads, one takes an NumberConstant and another that takes an int. These are considered equivalent, and it is totally random which is called.

Namespace

Objects as such do not have a namespace, but we decided to simulate it by having namespace objects.

In the symbol table a variable called "Catglobe" is registered, this is an instance of GlobalNamespace.

If you want to add some global function, then implement another class in CatGlobe.Framework.Runtime.Library.GlobalFunctions. It must be a normal CgScriptObject. The class must have no member variables since the instance is shared among all interpreters, and only static getters/setters/methods (although if you forgot to mark them static they will still work).

You then register the class in the namespace you want it to appear. For instance here is the registration of Json in the GlobalNamespace:

private static readonly JsonNamespace JsonNamespace = new JsonNamespace();
[Cg("Json", "The json namespace")]
public static JsonNamespace Json { get { return JsonNamespace; } }

Now you can call the functions in this namespace:

return Catglobe.Json.Parse(Catglobe.Json.Encode({1, ""Hejsa""}));

And because they are objects, you can also do this:

object n = Catglobe.Json;
return n.Parse(n.Encode({1, ""Hejsa""}));


Functions

Normal non-object functions - Yet to be written