From a developer’s point of view, a Push type is implemented through a class, derived from PushTypeBase, as mentioned in the previous post.
Once the type is implemented in any .NET language the system will hook it into the currently available types, will add a parser and a stack for it.
All that needs to be done is:
- Declare a class, deriving from PushTypeBase, and decorated with PushType attribute. Here the required parameter to the attribute is the name of the type:
[<PushType("FLOAT")>] type Float = inherit PushTypeBase - Define default constructor, and the constructor with one argument: the underlying type value, e.g., for a FLOAT type – a float type value:
in C#:public Float() : base() {}; public Float(double d) : base (d) {};and here is the syntax for the same in F#:
new () = {inherit PushTypeBase ()} new (f : float) = {inherit PushTypeBase(f)} - For easy access to the type name of this Push type, define a static member and instantiate it with the default constructor.
static member Me = Float() -
Implement custom parsing if required by creating a parse function and overriding the base class Parser property. Or simply override the Parser property to return Unchecked.defaultof<ExtendedTypeParser> in F#, null in C#:
// custom parsing static member parse s = let result = ref Unchecked.defaultof<float> if not (System.Double.TryParse(s, result)) then Unchecked.defaultof<PushTypeBase> else new Float(!result) :> PushTypeBase override t.Parser with get() = ExtendedTypeParser(Float.parse) - Override the base class ToString() implementation, if necessary. The base implementation will simply call the ToString() of the underlying value type if it is implemented.
- Implement type specific operations (more in the next post):
[<PushOperation("+")>] static member Add() = match processArgs2 Float.Me.MyType with | [a1; a2] -> pushResult(Float(a1.Raw<float>() + a2.Raw<float>())) | _ -> () [<PushOperation("*")>] static member Multiply() = match processArgs2 Float.Me.MyType with | [a1; a2] -> pushResult(Float(a1.Raw<float>() * a2.Raw<float>())) | _ -> ()
Here is an example of extending the language with the URL type, implemented in C#:
[PushType("URL")]
public class UrlPushType : Type.PushTypeBase
{
public UrlPushType() : base() {}
public UrlPushType(Uri url) : base(url) {}
static UrlPushType UrlParse(string url)
{
try
{
if (!url.Trim().StartsWith("http://", true, CultureInfo.InvariantCulture))
{
return null;
}
Uri uri = new Uri(url);
if (uri.HostNameType != UriHostNameType.Dns)
{
return null;
}
return new UrlPushType(uri);
}
catch (Exception)
{
return null;
}
}
public override Type.ExtendedTypeParser Parser
{
get
{
return new Type.ExtendedTypeParser(UrlParse);
}
}
[PushOperation("DOMAIN", Description="Extract domain name from the URL")]
static void ExtractDomain()
{
// pop the URL from the URL stack
var arg = TypeFactory.processArgs1("URL");
//if there is nothing there...
if (arg == null)
{
return;
}
// extract the underlying data
var uri = arg.Raw<Uri>();
//create the new URI
var newUri = new UrlPushType(new Uri(uri.Host));
// push it back to the URL stack.
TypeFactory.pushResult(newUri);
}
public override string ToString()
{
return base.ToString();
}