Difference between revisions of "CGScript - Coding guideline"
(→Object functions) |
|||
(7 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | = Objects | + | <accesscontrol>Main:MyGroup</accesscontrol> |
+ | = Objects = | ||
Objects in cgscript can be created by doing following this guideline. | Objects in cgscript can be created by doing following this guideline. | ||
Line 8: | Line 9: | ||
For example, here is the absolute minimal class: | For example, here is the absolute minimal class: | ||
− | + | <pre><code> | |
− | < | ||
[Cg(OBJECT_TYPE_NAME, "write the documentation for the class here")] | [Cg(OBJECT_TYPE_NAME, "write the documentation for the class here")] | ||
− | internal class MyObjectCGO : CgScriptObject | + | internal class MyObjectCGO : CgScriptObject |
{ | { | ||
private const string OBJECT_TYPE_NAME = "MyObject"; | private const string OBJECT_TYPE_NAME = "MyObject"; | ||
Line 19: | Line 19: | ||
} | } | ||
} | } | ||
− | </ | + | </code></pre> |
+ | 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 == | == Object functions == | ||
Line 33: | Line 35: | ||
Example: | Example: | ||
− | + | <pre><code> | |
− | < | ||
[Cg("ContainsKey", "Determines whether the dictionary contains the specified key with type is a string.")] | [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) | public bool ContainsKey([Cg("key", "Check with specific key")]string key) | ||
Line 40: | Line 41: | ||
return _dict.ContainsKey(key); | return _dict.ContainsKey(key); | ||
} | } | ||
− | </ | + | </code></pre> |
− | |||
A function may be static, but from inside cgscript it will be exposed as a member function. | A function may be static, but from inside cgscript it will be exposed as a member function. | ||
Line 49: | Line 49: | ||
Example: | Example: | ||
− | + | <pre><code> | |
− | < | ||
[Cg("Count", "Gets the number of key/value pairs contained in the dictionary.")] | [Cg("Count", "Gets the number of key/value pairs contained in the dictionary.")] | ||
public int Count | public int Count | ||
Line 56: | Line 55: | ||
get { return _dict.Count; } | get { return _dict.Count; } | ||
} | } | ||
− | </ | + | </code></pre> |
− | |||
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. | 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: | However, note that this alternative marking of the getter/setter may not do what you expect: | ||
− | + | <pre><code> | |
− | < | ||
public int Count | public int Count | ||
{ | { | ||
Line 68: | Line 65: | ||
get { return _dict.Count; } | get { return _dict.Count; } | ||
} | } | ||
− | </ | + | </code></pre> |
− | |||
This will register the getter as a function (ie. from cgscript you would have to call o.Count() instead of o.Count) | This will register the getter as a function (ie. from cgscript you would have to call o.Count() instead of o.Count) | ||
Line 79: | Line 75: | ||
Example: | Example: | ||
− | < | + | <pre><code> |
public IConstant this[[Cg("key", "The key used to lookup the value.")] string key] | public IConstant this[[Cg("key", "The key used to lookup the value.")] string key] | ||
{ | { | ||
Line 88: | Line 84: | ||
set { _dict[key] = value; } | set { _dict[key] = value; } | ||
} | } | ||
− | </ | + | </code></pre> |
− | |||
== Parameters == | == Parameters == | ||
CgScript objects support a number of types, that are automatically converted when calling the function and returning from the function: | 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 | + | *Void (For return values only) - Constant.Empty is returned |
− | * string - Automatically converted to and from a StringConstant | + | *string - Automatically converted to and from a StringConstant |
− | * double - Automatically converted to and from a NumberConstant | + | *double - Automatically converted to and from a NumberConstant |
− | * int - Automatically converted to and from a NumberConstant | + | *int - Automatically converted to and from a NumberConstant |
− | * bool - Automatically converted to and from a BooleanConstant | + | *bool - Automatically converted to and from a BooleanConstant |
− | * CGDateTime - Automatically converted to and from a DateTimeConstant | + | *CGDateTime - Automatically converted to and from a DateTimeConstant |
− | * Any type that implement IConstant - No conversion is done | + | *Any type that implement IConstant - No conversion is done |
Example: | Example: | ||
− | < | + | <pre><code> |
[Cg("Add", "Adds the specified key and value to the dictionary with type of key is a string.")] | [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, | public bool Add([Cg("key", "Add with specific key")] string key, | ||
[Cg("value", "Add with specific value")] IConstant constant) | [Cg("value", "Add with specific value")] IConstant constant) | ||
+ | </code></pre> | ||
+ | There are some special parameter types, that must all NOT be marked with a CgAttribute: | ||
+ | |||
+ | *<code>Interpreter</code> - 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. | ||
+ | *<code>IList<IConstant></code> - This is roughly equivalent to a normal C# method that takes a <code>"params object[]"</code>. 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 <code>IList<IConstant></code> 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 <code>CatGlobe.Framework.Runtime.Library.GlobalFunctions</code>. It must be a normal <code>CgScriptObject</code>. 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: | ||
+ | |||
+ | <code><pre> | ||
+ | private static readonly JsonNamespace JsonNamespace = new JsonNamespace(); | ||
+ | [Cg("Json", "The json namespace")] | ||
+ | public static JsonNamespace Json { get { return JsonNamespace; } } | ||
+ | </pre></code> | ||
+ | |||
+ | Now you can call the functions in this namespace: | ||
+ | |||
+ | <code><pre> | ||
+ | return Catglobe.Json.Parse(Catglobe.Json.Encode({1, ""Hejsa""})); | ||
</pre></code> | </pre></code> | ||
− | + | And because they are objects, you can also do this: | |
+ | |||
+ | <code><pre> | ||
+ | object n = Catglobe.Json; | ||
+ | return n.Parse(n.Encode({1, ""Hejsa""})); | ||
+ | </pre></code> | ||
− | |||
− | |||
− | |||
= Functions = | = Functions = |
Latest revision as of 05:45, 18 October 2013
<accesscontrol>Main:MyGroup</accesscontrol>
Contents
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:
<code> [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; } } } </code>
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:
<code> [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); } </code>
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:
<code> [Cg("Count", "Gets the number of key/value pairs contained in the dictionary.")] public int Count { get { return _dict.Count; } } </code>
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:
<code> public int Count { [Cg("Count", "Gets the number of key/value pairs contained in the dictionary.")] get { return _dict.Count; } } </code>
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:
<code> 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; } } </code>
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:
<code> [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) </code>
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