Archive for the ‘Script.NET’ Category

Using S# to generate PDF documents

Thursday, May 20th, 2010

Introduction

S# is a .NET scripting language. It is good for creating domain specific languages and embedding scripts into .NET application. Few days ago a great article revealing integration between S# and XAML in Silverlight was posted.

In this post I am going to show another useful application of S# language as an extensible markup for creating PDFs.

Obviously S# will not generate PDFs itself. There is a whole range of different components for producing PDF files. They are powerful in their functionality and may be used in .NET languages such as C# or S#.

I am going to use iText library. This is a library that allows you to generate PDF files on the fly. Here is a quote from official iText site: “Typically you won’t use it on your Desktop as you would use Acrobat or any other PDF application. Rather, you’ll build iText into your own applications so that you can automate the PDF creation and manipulation process.”

Let’s make a step further and wrap iText into S# scripting language to produce a markup language for generating PDF documents.

Goal

My aim is to get following script working and producing correct document like given on the picture below the script:

//Create document at given location
BeginDocument(“c:\\output.pdf”);//Change title in documentâ’s meta data 
ActiveDocument.AddTitle(’Sample document’);

//Create paragraphs with different alignment and color options
Paragraph(’Hello World’, ALIGN_CENTER);
Paragraph(’This is demo’, ALIGN_RIGHT, BLUE);
Paragraph(’This pdf was generated by S#’, GREEN);

//Create a list of string items
BeginList();
  ListItem(’One’);
  ListItem(’Two’);
  ListItem(’Three’);
EndList();

//Create a table with tree columns
BeginTable(3);
//Create cells for the first row
Cell(’1′);
Cell(’One’);
Cell(Paragraph(’Description of One’, RED));

//Create cells for second row
Cell(’2′);
Cell(’Two’);
Cell(’Description of Two’);
EndTable();

//Flush and close document
EndDocument();

Target PDF document:
pdfgenerator.jpg

Implementation

S# has many points for extensibility and customization. For the task purpose we will be using context customization via constants and custom functions.

Preferable pattern for such customization is to introduce a new facade over standard RuntimeHost class from S#:

public static class PdfRuntimeHost
{
  public static void Initialize()
  {
    RuntimeHost.Initialize();      
    //Make any required customization to RuntimeHost
  }
}

ScriptContext is a part Script instance. ScriptContext store run-time information about variables, functions, scopes, etc which will be used during script execution.

There are two static methods within Script class for compiling and executing code:

namespace Orbifold.SSharp
{
 public class Script : IDisposable
 {
  public static Script Compile(string code);
  public static object RunCode(string code);
 
  … 
 }

Again, preferred pattern for customization is to create a new façade class which customizes ScriptContext for those methods. So, I will introduce two new methods to PdfRuntimeHost class:

public static class PdfRuntimeHost
{
 public static void Initialize()
 {
  RuntimeHost.Initialize();
 }
 
 public static Script Compile(string code)
 {
  Script s = Script.Compile(code);
  CustomizeScriptContext(s.Context);
  return s;
 }
 
 public static object RunCode(string code)
 {
  IScriptContext context = new ScriptContext();
  CustomizeScriptContext(context);
  return Script.RunCode(code, context);
 }. . .

Context customization is quite simple itself. I am going to introduce couple of constants:

context.SetItem(“ALIGN_CENTER”“CENTER”); //iText alignment values
context.SetItem(“ALIGN_LEFT”“LEFT”);
context.SetItem(“ALIGN_RIGHT”“RIGHT”);
 
context.SetItem(“RED”new BaseColor(255, 0, 0)); //iText colors
context.SetItem(“GREEN”new BaseColor(0, 255, 0));
context.SetItem(“BLUE”new BaseColor(0, 0, 255));

There will be three variables:

context.SetItem(Functions.ActiveListVariable, null);
context.SetItem(Functions.ActiveTableVariable, null);
context.SetItem(Functions.ActiveDocumentVariable, null);

ActiveDocumentVariable – will store reference to active Document object
ActiveListVariable – will store reference to active list variable
ActiveTableVariable – will store reference to active table variable

Note that it is not possible to have nested objects, like list of lists, or table containing other table in one of cells. However, this limitation may be overcome by introducing stacks of active containers instead of single reference variable.

At the final step I will build functional structure of new language. Let’s consider Paragraph function as example (Other functions may be found in Functions.cs file in supplied solution file).

Paragraph function creates new paragraph object and automatically appends it to the document when necessary.

public static object Paragraph(IScriptContext context, object[] args)
{
 //Extract active document from context
 Document document = 
    context.GetItemAs<Document>(ActiveDocumentVariable);
 
 //Create new paragraph object. First argument – is a text
 Paragraph pf = new Paragraph((string)args[0]);
   
 //If two arguments provided, second may be either color or
 //alignment value
 if (args.Length == 2)
 {
    BaseColor color = args[1] as BaseColor;
    if (color == null)
     pf.SetAlignment((string)args[1]);
    else
     pf.Font.Color = color;
 }
 
 //If there are three arguments, second is alignment, and
 //third is a color
 if (args.Length == 3)
 {
    pf.SetAlignment((string)args[1]);
    pf.Font.Color = (BaseColor)args[2];
 }
 
 //Should we add paragraph to the document,
 //or it was generated for other container, i.e. List or Table
 if (!IsContainerScope(context))
    document.Add(pf);
 
 return pf;
}

Now, each new function should be added into ScriptContext like this:

context.SetItem(“BeginDocument”
            new FunctionWrapper(Functions.BeginDocument));

Where FunctionWrapper is class implementing S#’s IInvokable interface. It takes method delegate as a first constructor parameter and executes this delegate as a result of invoking Invoke method with supplied parameters.

Conclusion

This example gives a good example of S# language customization. With a few simple steps you may create your own domain specific language. In this example such language simulates PDF markup.

But it is not only a markup. It is also a program and experienced users may write scripts which benefits from this:

BeginList();
  for(i=0; i<10; i++)
ListItem(i.ToString());
EndList();

Downloads

S# puzzle game Cli-Q

Thursday, June 25th, 2009

Cli-Q is a space-travel puzzle game on Silverlight advertising S# language as scripting language for games.

 Cli-Q Logo

Cliq-Q exposes simple object model allowing developer easily extend functionality, create new levels and in future - new types of gaming objects.

The game field contains player object - white circle, win point - orange circle and a number of static obstacles and dynamic objects. Static obstacles simply stops player object from further movement, while dynamic objects - such as triangles may change direction of further movement:

Game field

Play Now!

On-Line calculator based on Script.NET for Silverlight 2.0

Tuesday, April 7th, 2009

As I’ve promised few weeks ago there is now Silverlight version of Script.NET. I’ve searched through Web and I think this is a first fully functional scripting engine for Silverlight. If this is wrong - please notify me at piter.protsyk@gmail.com and I will correct this information. Please also note that my understanding of scripting is quite different from those of Microsoft’s view with regards of IronPython and IronRuby. Both of these languages emits IL code and generates dynamic assemblies/method which then executed on .NET. In contrast Script.NET is a pure interpreted language which has a number of advantages.

To proof a concept of Script.NET for Silverlight I’ve created the On-Line calculator on its basis:

Silverlight 2.0 Calc

 Silverlight 2.0 Calculator Based on Script.NET

Sources & Binaries

Enjoy!

It can execute any valid Script.NET expression and has access to only one .NET type - Math.

Script.NET for Compact Framework

Tuesday, March 17th, 2009

Today I am glad to announce the first version of Script.NET which is able to run on Compact Framework (3.5).

It could be downloaded by the following link:

Script.NET for CF.

Also I would like to thank Steve Higgins without whom CF version of Script.NET most probably would not appear.

Meantime, in the nearest future I will produce a Silverlight version of Script.NET.

Script.NET 1.2 is comming!

Friday, February 20th, 2009

Today I am glad to announce a new improved version of Script.NET. It got its number 1.2. It is not yet a replacement for a previous branch, but is a more treated as public community preview version to gather your feedback.

You may find a download-able package by the link below:

Download Script.NET 1.2

This version achieved a new milestone in the continuous development and improvement of scripting engine. Now, it is even more customizable, more thread safe and more stable then previous releases.

Current version is open for functionality requests and suggestions. So please go ahead and email them: piter.protsyk@gmail.com  

Please expect official release of the renewed Script.NET in May together with a new web site containing more complete help information, new tutorials and examples.