Archive

Archive for January, 2014

Launching Quartex Pascal Website

January 31, 2014 Leave a comment

I have setup a website for all things Quartex Pascal, you can read more about my hobby project here: http://quartexpascal.wordpress.com/

CODEF for Smart Mobile Studio

January 27, 2014 Leave a comment
CodeF rocks

CodeF rocks

I never got to complete the TW3Canvas class under Smart Mobile Studio, so this post should be considered a must for SMS developers that use graphics for games or presentations. As you probably know there are some “odd” methods in TW3Canvas that is poorly documented, first and foremost drawPart and drawTile. These two methods are ported from a javascript library called CodeF – which is a super fast set of routines for writing demos and games. I wanted to implement the whole library under SMS, but sadly I never had the chance.

Patching Smart Mobile

To get this fix you have to do some “mild” patching of the file w3graphics.pas. Before you proceed make sure you make a backup of this file, just in case. Proceed at your own risk – as I take no responsibility should something go wrong (although in this case, it should be fairly safe).

  • Open up w3graphics.pas
  • Remove the methods DrawPart,DrawTo and DrawTile from the TW3Canvas class
  • Remove the implementations for above methods
  • Now create a new unit called codef.pas, save it to the RTL\libraries folder

Now copy this code into the codef.pas file:

unit codef;

{ **************************************************************************** }
{                                                                              }
{ CODEF canvas methods for Smart Mobile Studio                                 }
{ Written by Jon Lennart Aasenden                                              }
{ Copyright (c) Jon Lennart Aasenden. All rights are reserved.                 }
{                                                                              }
{ **************************************************************************** }


interface

uses 
  W3System, w3image, w3graphics, w3c.DOM, w3c.Canvas2DContext;

type

  TQTXImageHelper = Class helper for TW3Image
  public
    (* Draws the image to a context, and returns the context *)
    function  toContext(var aContext:TW3GraphicContext):Boolean;overload;
    function  toContext(var aContext:TW3GraphicContext;
              var aCanvas:TW3Canvas):Boolean;overload;
  end;

  (* CODEF implementation.
     NOTE: Midhandling of sections is not implemented yet *)
  TCodeFCanvas = class helper for TW3Canvas
  public
    Procedure   Quad(const x1,y1,x2,y2,x3,y3,x4,y4:Float;
                const aColor:TColor);overload;

    procedure   Quad(const x1,y1,x2,y2:Float;
                const aFillStyle:String);overload;

    procedure   Plot(const x1,y1,aWidth:Float;
                const aColor:TColor);

    procedure   Line(const x1,y1,x2,y2:Float;
                const aWidth:Integer;
                Const aColor:TColor);

    procedure   FastFill(const aColor:TColor);overload;

    procedure   Clear;

    procedure   Triangle(const x1,y1,x2,y2,x3,y3:Float;
                const aColor:TColor);

    procedure   DrawPart(target: TW3Canvas;
                const srcX, srcY: Integer;
                const srcWidth, srcHeight: Integer;
                const dstX, dstY: Integer); overload;

    procedure   DrawPart(target: TW3Canvas;
                const srcX, srcY: Integer;
                const srcWidth, srcHeight: Integer;
                const dstX, dstY: Integer;
                const rotation: Integer); overload;

    procedure   DrawPart(target: TW3Canvas;
                const srcX, srcY: Integer;
                const srcWidth, srcHeight: Integer;
                const dstX, dstY: Integer;
                const rotation: Integer;
                const alpha: Integer); overload;

    procedure   DrawTile(target: TW3Canvas;
                const TileID: Integer;
                const TileSize: Integer;
                const dstX, dstY: Integer); overload;

    procedure   DrawTile(target: TW3Canvas;
                const TileID: Integer;
                const TileSize: Integer;
                const dstX, dstY: Integer;
                const rotation: Integer); overload;

    procedure   DrawTile(target: TW3Canvas;
                const TileID: Integer;
                const TileSize: Integer;
                const dstX, dstY: Integer;
                const rotation: Integer;
                const alpha: Integer); overload;

    procedure   DrawTo(target: TW3Canvas;
                const dstX, dstY: Integer); overload;

    procedure   DrawTo(target: TW3Canvas;
                const dstX, dstY: Integer;
                const rotation: Integer); overload;

    procedure   DrawTo(target: TW3Canvas;
                const dstX, dstY: Integer;
                const rotation: Integer;
                const alpha: Integer); overload;
  End;


implementation

//#############################################################################
// TQTXImageHelper
//#############################################################################

function  TQTXImageHelper.toContext(var aContext:TW3GraphicContext):Boolean;
var
  mCanvas:  TW3Canvas;
begin
  aContext:=NIL;
  result:=self.Ready;
  if result then
  Begin
    aContext:=TW3GraphicContext.Create(null);
    aContext.Allocate(self.Width,self.height);
    mCanvas:=TW3Canvas.Create(aContext);
    try
      mCanvas.putImageData(self.toImageData,0,0);
    finally
      mCanvas.free;
    end;
  end;
end;

function TQTXImageHelper.toContext(var aContext:TW3GraphicContext;
         var aCanvas:TW3Canvas):Boolean;
begin
  aContext:=NIL;
  aCanvas:=NIL;
  result:=self.Ready;
  if result then
  Begin
    aContext:=TW3GraphicContext.Create(null);
    aContext.Allocate(self.Width,self.height);
    aCanvas:=TW3Canvas.Create(aContext);
    aCanvas.putImageData(self.toImageData,0,0);
  end;
end;


//#############################################################################
// TCodeFCanvas
//#############################################################################

Procedure TCodeFCanvas.FastFill(const aColor:TColor);
var
  mFillStyle: String;
  mAlpha: Float;
Begin
  mFillStyle:=self.FillStyle;
  mAlpha:=self.globalAlpha;
  self.GlobalAlpha:=1;
  self.FillStyle:=ColorToWebStr(aColor);
  self.FillRectF(0,0,self.Context.Width,self.Context.Height);
  self.FillStyle:=mFillStyle;
  self.globalAlpha:=mAlpha;
end;

procedure TCodeFCanvas.Clear;
begin
  self.clearRectF(0,0,self.Context.Width,self.Context.Height);
end;

procedure TCodeFCanvas.DrawPart(target: TW3Canvas;
          const srcX, srcY: Integer;
          const srcWidth, srcHeight: Integer;
          const dstX, dstY: Integer);
begin
  if target <> nil then
  begin
    target.Handle.translate(dstX,dstY);
    target.Handle.drawImage(JElement(self.Context.handle),srcX,srcY,
      srcWidth,srcHeight,0,0,srcWidth,srcHeight);
    target.Handle.setTransform(1,0,0,1,0,0);
  end;
end;

procedure TCodeFCanvas.DrawPart(target: TW3Canvas;
          const srcX, srcY: Integer;
          const srcWidth, srcHeight: Integer;
          const dstX, dstY: Integer;
          const rotation: Integer);
begin
  if target <> nil then
  begin
    target.Handle.translate(dstX, dstY);
    target.Handle.rotate(DegToRad(rotation));
    target.Handle.drawImage(JElement(self.Context.Handle), srcX, srcY,
      srcWidth, srcHeight, 0, 0, srcWidth, srcHeight);
    target.Handle.setTransform(1, 0, 0, 1, 0, 0);
  end;
end;

procedure TCodeFCanvas.DrawPart(target: TW3Canvas;
          const srcX, srcY: Integer;
          const srcWidth, srcHeight: Integer;
          const dstX, dstY: Integer;
          const rotation: Integer;
          const alpha: Integer);
var
  mAlpha: Float;
begin
  if target <> nil then
  begin
    mAlpha := target.GlobalAlpha;
    target.GlobalAlpha := (1 / 255) * alpha;
    target.Handle.translate(dstX, dstY);
    target.Handle.rotate(DegToRad(rotation));
    target.Handle.drawImage(JElement(self.Context.Handle), srcX, srcY,
      srcWidth, srcHeight, 0, 0, srcWidth, srcHeight);
    target.Handle.setTransform(1, 0, 0, 1, 0, 0);
    target.GlobalAlpha := mAlpha;
  end;
end;

procedure TCodeFCanvas.Triangle(const x1,y1,x2,y2,x3,y3:Float;
          const aColor:TColor);
Begin
  self.Beginpath;
  self.moveToF(x1,y1);
  self.lineToF(x2,y2);
  self.linetoF(x3,y3);
  self.ClosePath;
  self.fillStyle:=ColorToWebStr(aColor);
  self.Fill();
end;

procedure TCodeFCanvas.Plot(const x1,y1,aWidth:Float;
          const aColor:TColor);
begin
  Quad(x1,y1,x1+awidth,y1, x1+awidth,y1+awidth,x1,y1+awidth,aColor);
end;

procedure TCodeFCanvas.Line(const x1,y1,x2,y2:Float;
          const aWidth:Integer;
          Const aColor:TColor);
var
  mTemp:  String;
Begin
  mtemp:=self.StrokeStyle;
  self.StrokeStyle:=ColorToWebStr(aColor);
  self.linewidth:=aWidth;
  self.Beginpath;
  self.moveToF(x1,y1);
  self.lineToF(x2,y2);
  self.Stroke;
  self.closepath;
  self.StrokeStyle:=mTemp;
end;

Procedure TCodeFCanvas.Quad(const x1,y1,x2,y2,x3,y3,x4,y4:Float;
          const aColor:TColor);
begin
  self.Beginpath;
  self.moveToF(x1,y1);
  self.linetoF(x2,y2);
  self.linetoF(x3,y3);
  self.linetoF(x4,y4);
  self.closepath;
  self.fillstyle:=ColorToWebStr(aColor);
  self.Fill;
end;

procedure TCodeFCanvas.Quad(const x1,y1,x2,y2:Float;
          const aFillStyle:String);
begin
  self.Beginpath;
  self.moveToF(x1,y1);
  self.linetoF(x1+x2,y1);
  self.linetoF(x1+x2,y1+y2);
  self.linetoF(x1,y1+y2);
  self.closepath;
  self.fillStyle:=aFillStyle;
  self.Fill;
end;

procedure TCodeFCanvas.DrawTile(target: TW3Canvas;
  const TileID: Integer;
  const TileSize: Integer;
  const dstX, dstY: Integer);
var
  srcX,srcY: Integer;
begin
  if target <> nil then
  begin
    srcX := TileID mod Floor(self.Context.Width / TileSize) * TileSize;
    srcY := Floor(TileID / (self.Context.Width / TileSize)) * TileSize;
    DrawPart(target, srcX, srcY, TileSize, TileSize, dstX, dstY);
  end;
end;

procedure TCodeFCanvas.DrawTile(target: TW3Canvas;
  const TileID: Integer;
  const TileSize: Integer;
  const dstX, dstY: Integer;
  const rotation: Integer);
var
  srcX, srcY: Integer;
begin
  if target <> nil then
  begin
    srcX := TileID mod Floor(self.Context.Width / TileSize) * TileSize;
    srcY := Floor(TileID / (self.Context.Width / TileSize)) * TileSize;
    DrawPart(target, srcX, srcY, TileSize, TileSize, dstX, dstY, rotation);
  end;
end;

procedure TCodeFCanvas.DrawTile(target: TW3Canvas;
  const TileID: Integer;
  const TileSize: Integer;
  const dstX, dstY: Integer;
  const rotation: Integer;
  const alpha: Integer);
var
  srcX, srcY: Integer;
begin
  if target <> nil then
  begin
    srcX := TileID mod Floor(self.Context.Width / TileSize) * TileSize;
    srcY := Floor(TileID / (self.Context.Width / TileSize)) * TileSize;
    DrawPart(target, srcX, srcY, TileSize, TileSize, dstX, dstY, rotation, alpha);
  end;
end;

procedure TCodeFCanvas.DrawTo(target: TW3Canvas;
  const dstX, dstY: Integer);
begin
  if target <> nil then
  target.Handle.drawImage(JElement(self.Context.Handle), dstX, dstY);
end;

procedure TCodeFCanvas.DrawTo(target: TW3Canvas;
  const dstX, dstY: Integer;
  const rotation: Integer);
begin
  if target <> nil then
  begin
    target.Handle.translate(dstX, dstY);
    target.Handle.rotate(DegToRad(rotation));
    target.Handle.drawImage(JElement(self.Context.Handle), 0, 0);
    target.Handle.setTransform(1, 0, 0, 1, 0, 0);
  end;
end;

procedure TCodeFCanvas.DrawTo(target: TW3Canvas;
  const dstX, dstY: Integer;
  const rotation: Integer;
  const alpha: Integer);
var
  mAlpha: Float;
begin
  if target <> nil then
  begin
    mAlpha := target.Handle.globalAlpha;
    target.GlobalAlpha := (1 / 255) * alpha;
    target.Handle.translate(dstX, dstY);
    target.Handle.rotate(DegToRad(rotation));
    target.Handle.drawImage(JElement(self.Context.Handle), 0, 0);
    target.Handle.setTransform(1, 0, 0, 1, 0, 0);
    target.GlobalAlpha := mAlpha;
  end;
end;


end.

Using CodeF

Whenever you want to use these new methods, simply incldude the codef.pas unit in your uses list, and the methods become a part of your normal TW3Canvas class. For inspiration, visit the CODEF demo scene and have a look what other people are making with CodeF.

Note: the above is only a port of a single library, CodeF consists of many such modules.

Smart Mobile Studio + nodeJS + Raspberry PI = awsome

January 17, 2014 Leave a comment
Smal but very fun to play with

Smal but very fun to play with

Want to test out your nodeJS business app before renting an expensive server + database hosting solution?

Well here is how you could do it with a minimalistic budget. First, order a Raspberry PI credit-card-sized computer at a whopping $25 pricetag. Follow the Raspberry PI installation guide for Linux (very simple, just download and flash the rom-card, then reboot and select the OS you want), then follow the Raspberry PI guide to setting up nodeJS on it.

So how do I code this device?

Buy Smart Mobile Studio, write your nodeJS server and Client in ordinary Object Pascal (or more precise: Smart Pascal, which is a next generation object pascal). To get your product onto the Raspberry PI, login to the device and start X (the “windows” like desktop environment) – copy the compiled nodeJS server code from your windows machine (you can access normal windows shares via the Linux filemanager).

Then open a shell (root user) and make sure read/write/execute rights is available for all users on your project folder. In short: cd to the parent folder, then type “chmod [myfolder] 7777”, replacing [myfolder] naturally with your project folder.

Then start your nodeJS project as normal on the raspberry.

Conclusion

Voila — you have a pocket size nodeJS server to test and play with. As a bonus you can also install freepascal on it (“sudo apt-get install lazarus” should do the trick). Lazarus is very slow on this device, so i suggest you write your programs on windows and just compile with FPC on the PI – which has an ARM CPU by the way).

Here is how you setup nodeJS on your machine: http://blog.rueedlinger.ch/2013/03/raspberry-pi-and-nodejs-basic-setup/

Follow the Smart Mobile Studio tutorial for creating nodeJS projects – both client and server.

Quartex pascal, foundation stone laid

January 15, 2014 Leave a comment

Managed to get a couple of hours work done on QPAS (quartex pascal) today, and finally I have reached the part where all the different sub-systems come together. Writing an IDE is not the same as writing  a notepad clone or simple text editor. The concept of project item types (for instance, how do you define a unit versus a textfile? Should a file ending with .res open up in a text-editor or a hex-dump?), storage mechanisms, source templates, search paths – the list goes on. Point is, it has to be abstract enough to be flexible, but rigid enough to take a punch and provide logical structure.

Meanwhile in Tønsberg, Norway

Meanwhile in Tønsberg, Norway

Today I got the time to glue the project-element templates (unit, program unit etc.) into the actual creation of a unit. I also got rid of all the initial hardcoded stuff. So when QPAS starts-up it reads all the information from files. Adding a new project type with different sub-elements (php, C#, javascript etc) is more or less a matter of writing some .inifiles which defines what the editor should do, provide a default source template (optional), and voila — the IDE has no clue about the difference between a unit and a textfile is, but it will handle both differently based on definitions now user-adaptable.

Getting there

Getting there

So in short: Yes, the IDE can be adapted for other languages (finally we can put those synEdit syntax highlighters to good use)!

But those are just the default “low level IDE stuff”, I will also need to add support for pre-defined projects. You know when you create a new delphi project, it basically just copies an already existing project from disk? This will be the next part.

Application services

In order to make this scriptable I had to add some overhead. First, everything is neatly isolated in a core class which provides access to all the sub-systems. It was very tempting to just litter the code with functions (like “getTemplateList”) rather than coding full manager classes, but I’m in no hurry – and I have a full daytime job besides. So I decided to take my time.

Here is an example from the IDE:

function TfrmMainForm.getBufferForUnit(aIdentifier:String;
         var aData:String):Boolean;
var
  mOpen:TObjectList;
  x:  Integer;
  mExt: String;
  mName:  String;
  mFound: TQTFileSourceRefList;
  mText:  TStringlist;
  mData:  TStream;
  mRef:   String;
  mAccess:  TIDEAccessManager;
begin
  (* Initialize to negative *)
  result:=False;
  mOpen:=NIL;
  setLength(aData,0);

  (* Make sure we can do this *)
  if not (csDestroying in ComponentState)
  and not (csLoading in ComponentState)
  and not application.Terminated then
  begin
    (* Request access to IDE API *)
    if getIDEAccess(mAccess) then
    begin
      mExt:=ExtractFileExt(aIdentifier);

      (* Get buffer from open tab *)
      if getOpenTabsForProject(mAccess.ProjectManager.ActiveProject,mOpen) then
      begin
        try
          for x:=0 to mOpen.Count-1 do
          begin
            (* NOTE: replace with byterage->compare later! *)
            if SameText(mopen[x].Item.Identifier,aIdentifier) then
            begin
              if (mOpen[x].Frame is TframePascal) then
              begin
                aData:=TframePascal(mOpen[x].Frame).editor.Text;
                break;
              end;
            end;
          end;
          result:=length(aData)>0;
        finally
          mOpen.Free;
        end;
      end;

      if not result then
      begin
        if length(mExt)=0 then
        mName:=aIdentifier + '.pas' else
        mName:=aIdentifier;

        if mAccess.FileSourceManager.LocateFileByName(mName,mFound) then
        begin
          try
            if mFound.Count>0 then
            begin
              mtext:=TStringlist.Create;
              try
                (* Get unit candidates, sort by priority to the project *)
                mRef:=mAccess.FileSourceManager.SortByPriority(mFound,mAccess.ProjectManager.ActiveProject).Items[0];
                WriteMessageF('using package unit [%s]',[mRef]);
                try
                  if mAccess.FileSourceManager.ObtainStreamFromRef(mRef,mData) then
                  begin
                    try
                      (* Note: Replace with streamToStr before alpha *)
                      mtext.LoadFromStream(mData);
                      aData:=mtext.Text;
                      result:=true;
                    finally
                      mData.Free;
                    end;
                  end;
                except
                  on e: exception do
                  TIDEExceptionHandler.HandleIOException(e,ehLogMessage);
                end;
              finally
                mtext.Free;
              end;
            end;
          finally
            mFound.Free;
          end;
        end;
      end;
    end;
  end;
end;

Now to get rid of the “.pas” harcoded string (query the project.template subsystem) and rename the editor frame to something more useful. Or just go bananaz and compile with packages and isolate different editors in DLL plugins (ala eclipse).

Live expression view

January 13, 2014 Leave a comment

What did i do this weekend? Well, I added a live symbolic view to the mainform. Makes it easier to see just whats going on inside DWScript. Not sure how useful it will be for others, but for me it’s very handy. It will probably need a “click to examine” feature or the list will be to large for anything practical. But it happily updates with the rest of the “auto magic” stuff so no worries.

Ye old symbolic output

Ye old symbolic output

Quartex Pascal, rolling my own

January 8, 2014 Leave a comment
Quartex is 4ever

Quartex is 4ever

No rest for the wicked. Just finished work, ran to get my daughter from daycare – then back again to the office. Homework with the kids, then finally, after arguing with my 10-year-old son that the concept of a straight angle triangle is Pythagorean in nature — I had 1 hour to play with my own stuff.

So what did I add today? What did I whip up in one hour? Well, the bridge between editor (synedit) and the filesource system is now complete. In short it can be explained as this: Whenever the compiler needs a unit an event fires. But you need a unified system so that units can be found everywhere. This is basically the same as what Delphi does with its search paths (tools -> options -> libraries -> library paths). But more importantly, the system needs to be clever and not just locate a file with a name, but rather return a list of candidates. Lets just say that TDictionary and hashed lookup tables are involved in finding files quickly. Secondly, the calling routine in question then have to make a decision on which of the resulting files is the unit you need (for example, if the file is a part of a package, then naturally a filename from that package receives a higher score than a file with the same name in another location). So this is not a walk in the park but requires a bit of thinking and infrastructure.

Also you want the IDE to be as clean and abstract as possible. So i created a class system that allows me to abstract files from the ide completely. So the IDE now happily loads and works with files no matter where they are. The RTL will not be “open” but rather stored in a sealed package.

What is the benefit of this? To change compiler target and (obviously) RTL for another language (C#, C++, Javascript or whatever) you just change the package. It also means easy component distribution and last but not least – that the IDE can support several different RTL versions for different project types (a game doesn’t really need the overhead of TComponent or TEventDelegate). In short: Easy to maintain, no dependencies, and instead of shipping a full installer for updates, I can just ship the updated RTL package (zipfile).

Some "me only" windows showing but you get the idea

Some “me only” windows showing but you get the idea

Now that I think of it, I will probably make a special “DWS only” build. You wont find a better editor for all things DWS that’s for sure. The DWS webserver deserves a good IDE and it would be fun to make different RTL/Compiler version for different tasks. But first things first: HTML5 and C#

Packages, Automation and then some

January 7, 2014 Leave a comment

Havent had much time to tinker with my pet pascal compiler, but I got in a couple of hours after work yesterday and today – and implemented support for source packages. The system is completely abstract so the IDE doesn’t really know “where” a unit is stored. When it needs a unit it simply uses a top-level api and ask for it, and the api takes care of locating it quickly.

Quartex Pascal

Quartex Pascal

Source packages

Packages are normal zipfiles (same as java uses) with some clever serial-code management. When you start the IDE a splash screen displays the loading of packages and the files are hot-plugged into the file lookup system. So the IDE actually doesn’t know the difference between a normal folder, a zipfile or something lingering on the Internet. With one exception: if your zipfile is “sealed” then you wont be able to view the units. This is a good thing for component vendors that want to ship their products without revealing their secrets. It also makes resource handling much easier (images, music, style sheets, binary data).

Storage

Also took the time to write a clever unit scanning class for dwscript. All classes and generics everywhere. Now also enumerates interfaces and class inheritance (yey!). Since DWS is so fast these days there really is no need for threading. This will by far be the best IDE for DWScript development in history.

Not much to look at yet, but getting there

Not much to look at yet, but getting there

Abstract storage is also in place, at least the basic class hierarchy. Meaning: the IDE has no idea where files are stored. It simply pertains to a storage class which takes care of the rest. Which means you don’t have to keep two buffers in memory at the same time. Much faster and requires far less code than other approaches.

Events

I have already figured out event handling, which can be a bit tricky under JavaScript/typescript/ GNU C++ (depending on the windowing toolkit), but the new RTL (QTX) will make it much easier to deal with.

Fully scriptable

And yes. DWS is bolted into the system from scratch, so once the IDE api is complete it will be fully scriptable and invokable via DWScript. Utilities etc. can be written in DWScript itself and registered in the Tools menu.

Working on the new IDE

January 4, 2014 Leave a comment

So. Creating an IDE. Sounds easy right? Just slap open a form, add some project stuff and bob’s your uncle? Sadly that is not the reality of writing a good IDE. Especially one that should be flexible, adaptable and easy to use.

Take, for example, the relationship between an open project file, a tab, and the editor reserved for an open pascal file. How do you link these 3 entities together in a meaningful way? Also, the IDE should respond fairly quickly, meaning it should be easy for you (or me in this case) to find an open unit, to locate the interface section of an open unit, to insert and modify the sourcecode – well the list of “must have” features grows on you.

quartex

Using generics this time I was able to cut through a lot of the old reinvention of the wheel, and in just 3 hours of work the basic project/unit/editor functionality is up and running. And the code is at least 40% faster than my previous product- so the IDE is snappy as hell. And yes! No skins this time 🙂

Templates

Another side of the IDE that was lacking earlier – was that of generating units. When you press “new unit”, where should the code come from? Well, I decided that templates was the way to go (just like native delphi does it) and implemented a nice and juicy based system. Took about an hour to setup, but now PASTA (yes that is the codename of the project) can already create a bunch of different projects, unit types and structures – all based on files and keywords. Much faster than my previous product and much more flexible. As a bonus: the user can now create new project types using notepad, which can only be a bonus.

Compiler

Not much to say here (or not much i want to share is more like it), but let’s just say that pipes and commandline is the way to go. Been playing around with mono C# and Gnu C++ for some time now.

RTL

This is the big one, the “meat” on the bones of any good system. Im not going to write much about this part. Let’s just say that this time — i wont let anyone touch the core. It will be abstract from the platform, portable, easy to adapt – no matter if you want to run stuff on iOS, XBox or the desktop. KISS — keep stuff simple.

Codegen

There are many ways to skin a cat. From the inside or the outside. Playing around with an intermediate bytecode structure, but brute force tend to be more efficient 😉

 

New platform, new RTL and new compiler

January 3, 2014 Leave a comment

Since airing my ideas about pascal and where it should go has led to, ahem, a rather substantial loss of intellectual property in the past – I wont divulge the inner workings of my latest platform beyond the general concepts.

So, what have I been up to the past 12 months? Well, there havent been much time to write actual code except in my spare time (which is limited) – but there has been plenty of time to think, create and play around with my ideas. Ideas that just a couple of years ago gave birth to object pascal for JavaScript (www.smartmobilestudio.com). A project I am sadly no longer involved in, but which I envisioned and realized with the help of Eric Grange (a.k.a “the stig of delphi”).

Smart mobile studio is a really kick ass system and it has been greatly expanded and perfected by Jørn, Eric and Primoz – which continue to polish the product and (to be honest) making it what Embarcadero should have done with HTML5 Builder (or Delphi for php, they keep changing the name of the product – but the product is essentially crap).

Dyson Sphere

Dyson Sphere

The missing bits

But the current architecture of OP4JS (Smart Mobile Studio) is not the complete vision. It is missing several stages which, first and foremost, is a truly universal pascal platform. This has more to do with the RTL and access to the underlying system (in this case the browser, but it could just as easily be an OS, or barebone to the kernel if need be) than actual high-level features. For those that have followed OP4JS since I first started writing about it back in 2010 – you all know the RTL has changed drastically. It has become more flexible and rich in every way (and the latest features, both in the IDE and RTL makes HTML5 Builder look like a joke), but that also means the code is more or less married to JavaScript. Which is the same mistake VCL is presently suffering – and incidentally why Firemonkey was born. Meaning.. that moving Smart Mobile Studio away from HTML5 onto “real” code is at this point impossible without a clean re-write of the entire RTL and (naturally) the codegen. The codegenerator that Eric designed is adaptable and easy to expand, so that wont be the grunt of the work (the dependencies and lingo will be more important at this point).

But, all together, the sub total undermines the entire point of the vision. Namely to create a compiler for *all* platforms, one that piggyback’s on languages rather than processor architectures; with a unified RTL that is portable in the same sense as the .net framework is portable. JavaScript was just the first stage (motivated primarily by the fact that someone said it would be “impossible”. When someone says that you just have to do it *grin*).

Architect wisely

Architect wisely

What I had in mind was, to some extent, what FPC and Lazarus started on but over time lost track of. Freepascal runs on just about everything – and the low-level units such as System and Sysutils provides a universal foundation on which the entire FCL rests upon (with some exceptions like embedded systems and mobile platforms). On top of that you have the windowing toolkit, the part which provides you with forms, buttons, listboxes and custom controls – which under lazarus is so flexible that you can actually initialize from DOS and have a fully “windows-like” system up and running without X or WinAPI taking care of the dirty bits. To sum up: Abstraction, abstraction, abstraction. The less your code depends on the OS the better.

We need a pascal that can go everywhere! A system which can quickly adapt to marked changes and new gadgets. Waiting 5 years for Embarcadero to truly support iOS is a disaster (!) The marked is saturated, every game and productivity application now already exists – and you are left with scraps. At this point you can only compete on the level of features. Thats not my idea of a living, vibrant language.

We should have been there instantly! The moment the vendor CPU specs and SDK was available – Object Pascal should have been there. Spartans forever, first in to capture the flag. Semper fidelis.

C#, C++, Javascript, Java, .net

In terms of technology Android is a curiosity, the oddball and sore thumb. It is based on java rather than C++ (although the bootstrap which is executed when your phone boots is pure C and assembler). Every other device happily runs C/++. To be more precise: GNU C++ which is the most widely used, free, C++ compiler in the world (and also the most esoteric, unix centric beast ever invented). Intel have developed their own C++ compiler which ships with their products, but most vendors simply adapt the GNU C++ toolkit to their product processor and build on that. Second through the door after C++ and Java (which in my view is not a language but an abomination) are languages like C# (via the mono project) and weird stuff like python.

Why is this? Why are these first when, to be honest, the freepascal codebase is just as easy to adapt (if not more) to a new architecture as C++?

This is where the power of the original vision comes into play. We dont compile for the CPU. We compile for whatever language is already present on the platform from the hardware vendor. So if Intel is behind the CPU, then we compile for their C++ compiler. If its a normal system then Gnu C++ or whatever fork is used. Same with iOS — we compile for Objective C and become, as the saying goes: If i have seen further, i have done so standing on the shoulders of giants.

But thats just the beginning.

And with that, I’ll leave you hanging … until my next invention is ready to make you go “holy crap thats impossible” 🙂

I am looking for investors. Proof of concept has already been given in terms of a living product.