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(); }