* WASI runtime embedding

This commit is contained in:
Michaël Van Canneyt 2021-12-24 14:02:56 +01:00
parent 6f1f064d16
commit 2626eef7c3
27 changed files with 2928 additions and 144 deletions

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="manualpromise.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="tryfetch.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="trymany.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
</Targets>
</ProjectGroup>
</CONFIG>

View File

@ -1,75 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="1">
<Targets Count="17">
<Target0 FileName="demoarea.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target0>
<Target1 FileName="demobar.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target1>
<Target2 FileName="demobubble.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target2>
<Target3 FileName="democustompoints.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target3>
<Target4 FileName="demodatalabelling.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target4>
<Target5 FileName="demodate.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target5>
<Target6 FileName="demodoughnut.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target6>
<Target7 FileName="demointeractions.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target7>
<Target8 FileName="demoline.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target8>
<Target9 FileName="demomixed.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target9>
<Target10 FileName="demopie.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target10>
<Target11 FileName="demopolararea.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target11>
<Target12 FileName="demoprogressbar.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target12>
<Target13 FileName="demoradar.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target13>
<Target14 FileName="demoscatter.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target14>
<Target15 FileName="demoscriptablebubble.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target15>
<Target16 FileName="demotime.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target16>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="demoarea.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demobar.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demobubble.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="democustompoints.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demodatalabelling.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demodate.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demodoughnut.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demointeractions.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demoline.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demomixed.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demopie.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demopolararea.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demoprogressbar.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demoradar.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demoscatter.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demoscriptablebubble.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="demotime.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
</Targets>
</ProjectGroup>
</CONFIG>

View File

@ -1,47 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="1">
<Targets Count="19">
<Target0 FileName="rtl/rtl_demos.lpg"/>
<Target1 FileName="promise/promise_demos.lpg"/>
<Target2 FileName="chartjs/chartjs_demos.lpg"/>
<Target3 FileName="webgl/webgl_demos.lpg"/>
<Target4 FileName="router/demorouter.lpi"/>
<Target5 FileName="router/demorouter2.lpi"/>
<Target6 FileName="trayicon/trayicon.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target6>
<Target7 FileName="dataabstract/sampleda.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target7>
<Target8 FileName="fcldb/demodb.lpi"/>
<Target9 FileName="fcldb/demoload.lpi"/>
<Target10 FileName="fcldb/demorest.lpi"/>
<Target11 FileName="fcldb/demorest2.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target11>
<Target12 FileName="fcldb/restserver.lpi"/>
<Target13 FileName="fpcunit/browsertest.lpi">
<BuildModes Count="1"/>
<Mode1 Name="default"/>
</Target13>
<Target14 FileName="dynload/testloader.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target14>
<Target15 FileName="hotreload/hotreload.lpi"/>
<Target16 FileName="hotreload/server.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target16>
<Target17 FileName="jquery/demoadd.lpi"/>
<Target18 FileName="jspdf/basic.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target18>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="rtl/rtl_demos.lpg"/>
<Target FileName="promise/promise_demos.lpg"/>
<Target FileName="chartjs/chartjs_demos.lpg"/>
<Target FileName="webgl/webgl_demos.lpg"/>
<Target FileName="asyncawait/asyncawaitdemos.lpg"/>
<Target FileName="wasienv/wasienvdemos.lpg"/>
<Target FileName="translate/translate_demos.lpg"/>
<Target FileName="resources/resourcedemos.lpg"/>
<Target FileName="router/demorouter.lpi">
<BuildModes>
<Mode Name="default"/>
</BuildModes>
</Target>
<Target FileName="router/demorouter2.lpi"/>
<Target FileName="dataabstract/sampleda.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="fcldb/demodb.lpi"/>
<Target FileName="fcldb/demoload.lpi"/>
<Target FileName="fcldb/demorest.lpi"/>
<Target FileName="fcldb/restserver.lpi"/>
<Target FileName="fpcunit/browsertest.lpi"/>
<Target FileName="dynload/testloader.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="hotreload/hotreload.lpi"/>
<Target FileName="hotreload/server.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="jquery/demoadd.lpi"/>
<Target FileName="jspdf/basic.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="fullcalendar/demofullcalendar.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="fullcalendar/demofullcalendar4.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="fullcalendar/demofullcalendar5.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="fpreport/reportdemo.lpi"/>
<Target FileName="jitsimeet/demojitsimeet.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="pushjs/helloworld.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="tetris/tetris.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="websockets/demowebsocket.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="webwidget/widgets/webwidgetsdemo.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="xterm/xtermdemo.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="restbridge/simple/restbridgeclient.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="opentok/demoopentok.lpi">
<BuildModes>
<Mode Name="default"/>
</BuildModes>
</Target>
<Target FileName="extend_jsclass/ExtendJSFunctionClass1.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="bootstrap/demobootstraptable.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="atom/pas2jsdemopackage.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
</Targets>
</ProjectGroup>
</CONFIG>

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="1">
<Targets Count="5">
<Target0 FileName="story.lpi"/>
<Target1 FileName="story2.lpi"/>
<Target2 FileName="story3.lpi"/>
<Target3 FileName="demoall.lpi"/>
<Target4 FileName="askmom.lpi"/>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="story.lpi"/>
<Target FileName="story2.lpi"/>
<Target FileName="story3.lpi"/>
<Target FileName="demoall.lpi"/>
<Target FileName="askmom.lpi"/>
</Targets>
</ProjectGroup>
</CONFIG>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="consoledemo.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="htmldemo.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="htmllinkdemo.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="htmlloadlinkdemo.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
</Targets>
</ProjectGroup>
</CONFIG>

View File

@ -1,21 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="1">
<Targets Count="14">
<Target0 FileName="demoajax.lpi"/>
<Target1 FileName="demobrowserconsole.lpi"/>
<Target2 FileName="democanvas2d.lpi"/>
<Target3 FileName="democlasstopas.lpi"/>
<Target4 FileName="democollection.lpi"/>
<Target5 FileName="democomponents.lpi"/>
<Target6 FileName="demodatetime.lpi"/>
<Target7 FileName="demodombuttonevent.lpi"/>
<Target8 FileName="demojsarray.lpi"/>
<Target9 FileName="demorouter.lpi"/>
<Target10 FileName="demortti.lpi"/>
<Target11 FileName="demostringlist.lpi"/>
<Target12 FileName="demouncaughtexception.lpi"/>
<Target13 FileName="demoxhr.lpi"/>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="demoajax.lpi"/>
<Target FileName="demobrowserconsole.lpi"/>
<Target FileName="democanvas2d.lpi"/>
<Target FileName="democlasstopas.lpi">
<BuildModes>
<Mode Name="default"/>
</BuildModes>
</Target>
<Target FileName="democollection.lpi"/>
<Target FileName="democomponents.lpi"/>
<Target FileName="demodatetime.lpi"/>
<Target FileName="demodombuttonevent.lpi"/>
<Target FileName="demojsarray.lpi"/>
<Target FileName="demorouter.lpi"/>
<Target FileName="demortti.lpi"/>
<Target FileName="demostringlist.lpi"/>
<Target FileName="demouncaughtexception.lpi"/>
<Target FileName="demoxhr.lpi"/>
</Targets>
</ProjectGroup>
</CONFIG>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="translate_basic.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="translate_object.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="translate_url.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
</Targets>
</ProjectGroup>
</CONFIG>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="canvasdraw"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<BuildModes>
<Item Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<Units>
<Unit>
<Filename Value="canvasdraw.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="canvasdraw"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,138 @@
program canvasdraw;
{$mode objfpc}
{$h+}
uses
sysutils, webcanvas;
Type
ECanvas = class(Exception);
{ TWebCanvas }
TWebCanvas = class(TObject)
private
FCanvasID : Longint;
FHeight: Longint;
FWidth: Longint;
Protected
Procedure Check(aError : TCanvasError; const aMsg : String = '');
Public
Constructor Create(aWidth,aHeight : Longint);
Procedure moveto(X : Longint;Y : Longint);
Procedure lineto(X : Longint; Y : Longint);
Procedure stroke();
Procedure beginpath();
Procedure arc(X : Longint;Y : Longint;Radius : Longint;StartAngle : Double;EndAngle : Double);
Procedure fillrect(X : Longint; Y : Longint; Width : Longint; Height : Longint);
Procedure strokerect(X : Longint;Y : Longint; Width : Longint; Height : Longint);
Procedure clearrect(X : Longint;Y : Longint;Width : Longint; Height : Longint );
Procedure StrokeText(X : Longint;Y : Longint;S : UTF8String);
Procedure FillText(X : Longint;Y : Longint;S : UTF8String);
Property CanvasID : Integer Read FCanvasID;
Property Width : Longint Read FWidth;
Property Height : Longint Read FHeight;
end;
{ TWebCanvas }
procedure TWebCanvas.Check(aError: TCanvasError; const aMsg: String);
begin
if aError<>ECANVAS_SUCCESS then
if aMsg='' then
Raise Exception.CreateFmt('Canvas Operation failed %d',[aError])
else
Raise Exception.CreateFmt('%s : Error code %d',[aMsg,aError]);
end;
constructor TWebCanvas.Create(aWidth, aHeight: Longint);
begin
Check(__webcanvas_allocate(aWidth,aHeight,@FCanvasID),'Failed to create web canvas');
FWidth:=aWidth;
FHeight:=aHeight;
end;
procedure TWebCanvas.moveto(X: Longint; Y: Longint);
begin
Check(__webcanvas_moveto(FCanvasID,X,Y));
end;
procedure TWebCanvas.lineto(X: Longint; Y: Longint);
begin
Check(__webcanvas_lineto(FCanvasID,X,Y));
end;
procedure TWebCanvas.stroke;
begin
Check(__webcanvas_stroke(FCanvasID));
end;
procedure TWebCanvas.beginpath;
begin
Check(__webcanvas_beginpath(FCanvasID));
end;
procedure TWebCanvas.arc(X: Longint; Y: Longint; Radius: Longint;
StartAngle: Double; EndAngle: Double);
begin
Check(__webcanvas_arc(FCanvasID,X,Y,Radius,StartAngle,EndAngle));
end;
procedure TWebCanvas.fillrect(X: Longint; Y: Longint; Width: Longint;
Height: Longint);
begin
Check(__webcanvas_fillrect(FCanvasID,X,Y,Width,Height));
end;
procedure TWebCanvas.strokerect(X: Longint; Y: Longint; Width: Longint;
Height: Longint);
begin
Check(__webcanvas_strokerect(FCanvasID,X,Y,Width,Height));
end;
procedure TWebCanvas.clearrect(X: Longint; Y: Longint; Width: Longint;
Height: Longint);
begin
Check(__webcanvas_clearrect(FCanvasID,X,Y,Width,Height));
end;
procedure TWebCanvas.StrokeText(X: Longint; Y: Longint; S: UTF8String);
begin
Check(__webcanvas_stroketext(FCanvasID,X,Y,PByte(PAnsichar(S)),Length(S)));
end;
procedure TWebCanvas.FillText(X: Longint; Y: Longint; S: UTF8String);
begin
Check(__webcanvas_filltext(FCanvasID,X,Y,PByte(PAnsichar(S)),Length(S)));
end;
Var
aCanvas : TWebCanvas;
begin
aCanvas:=TWebCanvas.Create(150,150);
With aCanvas do
try
Writeln('Filling rect');
fillRect(25, 25, 100, 100);
Writeln('Clearing rect');
clearRect(45, 45, 60, 60);
Writeln('Stroking rect');
strokeRect(50, 50, 50, 50);
Writeln('Drawing cross');
BeginPath;
MoveTo(25,25);
Writeln('First line');
LineTo(125,125);
MoveTo(125,25);
Writeln('Second line');
LineTo(25,125);
Stroke;
Writeln('Writing text');
FillText(8,8,'Greetings on the WebAssembly Canvas!');
finally
Free;
end;
end.

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
<Runnable Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="demowasicanvas"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<CustomData Count="2">
<Item0 Name="MaintainHTML" Value="1"/>
<Item1 Name="PasJSWebBrowserProject" Value="1"/>
</CustomData>
<BuildModes>
<Item Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<Units>
<Unit>
<Filename Value="demowasicanvas.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="index.html"/>
<IsPartOfProject Value="True"/>
<CustomData Count="1">
<Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
</CustomData>
</Unit>
<Unit>
<Filename Value="wacanvas.pp"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target FileExt=".js">
<Filename Value="demowasicanvas"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="js"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<AllowLabel Value="False"/>
<CPPInline Value="False"/>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<TargetOS Value="browser"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
<UseLineInfoUnit Value="False"/>
</Debugging>
</Linking>
<Other>
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
<CompilerPath Value="$(pas2js)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,121 @@
program demowasicanvas;
{$mode objfpc}
uses
browserconsole, browserapp, JS, Classes, SysUtils, Web, WebAssembly, types, wasienv, wacanvas;
Type
{ TMyApplication }
TMyApplication = class(TBrowserApplication)
Private
FWasiEnv: TPas2JSWASIEnvironment;
FMemory : TJSWebAssemblyMemory; // Memory of webassembly
FTable : TJSWebAssemblyTable; // Table of exported functions
FWACanvas : TWACanvas; // canvas extension
function CreateWebAssembly(Path: string; ImportObject: TJSObject
): TJSPromise;
procedure DoWrite(Sender: TObject; const aOutput: String);
function initEnv(aValue: JSValue): JSValue;
procedure InitWebAssembly;
Public
Constructor Create(aOwner : TComponent); override;
Destructor Destroy; override;
procedure doRun; override;
end;
function TMyApplication.InitEnv(aValue: JSValue): JSValue;
Var
Module : TJSInstantiateResult absolute aValue;
exps : TWASIExports;
begin
Result:=True;
Exps := TWASIExports(TJSObject(Module.Instance.exports_));
FWasiEnv.Instance:=Module.Instance;
// console.info('got exports', exps);
Exps.Start;
end;
procedure TMyApplication.DoWrite(Sender: TObject; const aOutput: String);
begin
Writeln(aOutput);
end;
constructor TMyApplication.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FWasiEnv:=TPas2JSWASIEnvironment.Create;
FWasiEnv.OnStdErrorWrite:=@DoWrite;
FWasiEnv.OnStdOutputWrite:=@DoWrite;
FWACanvas:=TWACanvas.Create(FWasiEnv);
FWACanvas.CanvasParent:=GetHTMLElement('canvases');
end;
function TMyApplication.CreateWebAssembly(Path: string; ImportObject: TJSObject): TJSPromise;
begin
Result:=window.fetch(Path)._then(Function (res : jsValue) : JSValue
begin
Result:=TJSResponse(Res).arrayBuffer._then(Function (res2 : jsValue) : JSValue
begin
Result:=TJSWebAssembly.instantiate(TJSArrayBuffer(res2),ImportObject);
end,Nil)
end,Nil
);
end;
procedure TMyApplication.InitWebAssembly;
Var
mDesc : TJSWebAssemblyMemoryDescriptor;
tDesc: TJSWebAssemblyTableDescriptor;
ImportObj : TJSObject;
begin
// Setup memory
mDesc.initial:=256;
mDesc.maximum:=256;
FMemory:=TJSWebAssemblyMemory.New(mDesc);
// Setup table
tDesc.initial:=0;
tDesc.maximum:=0;
tDesc.element:='anyfunc';
FTable:=TJSWebAssemblyTable.New(tDesc);
// Setup ImportObject
ImportObj:=new([
'js', new([
'mem', FMemory,
'tbl', FTable
])
]);
FWasiEnv.AddImports(ImportObj);
CreateWebAssembly('canvasdraw.wasm',ImportObj)._then(@initEnv)
end;
destructor TMyApplication.Destroy;
begin
FreeAndNil(FWasiEnv);
inherited Destroy;
end;
procedure TMyApplication.doRun;
begin
// Your code here
Terminate;
InitWebAssembly;
end;
var
Application : TMyApplication;
begin
Application:=TMyApplication.Create(nil);
Application.Initialize;
Application.Run;
end.

View File

@ -0,0 +1,51 @@
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FPC-Webassembly and Pas2JS Demo</title>
<link href="bulma.min.css" rel="stylesheet">
<script src="demowasicanvas.js"></script>
<style>
.source {
width: 730px;
margin: -45px auto;
font-size: 0.9em;
}
.source-inner {
display: flex;
justify-content: space-between;
align-items: center;
width: 482px;
}
</style>
</head>
<body>
<div class="section">
<h1 class="title is-3">Canvas</h1>
<div id="canvases"></div>
</div>
<div class="section">
<h1 class="title is-3">Console output</h1>
<div id="pasjsconsole"></div>
</div>
<hr>
<div class="section">
<div class="source">
<div class="source-inner">
<div>
<p>Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> </p>
<p>Pas2JS Sources: &nbsp; <a target="new" href="demowasicanvas.lpr">Pas2JS Program</a></p>
<p>Webassembly Sources: &nbsp; <a target="new" href="canvasdraw.lpr">FPC Program</a></p>
</div>
</div>
</div>
</div>
<script>
rtl.showUncaughtExceptions=true;
rtl.run();
</script>
</body>
</html>

View File

@ -0,0 +1,261 @@
{$mode objfpc}
{$h+}
unit wacanvas;
interface
uses js, web, webassembly, wasienv;
Const
ECANVAS_SUCCESS = 0;
ECANVAS_NOCANVAS = 1;
ECANVAS_UNSPECIFIED = -1;
Type
TCanvasError = Longint;
TCanvasID = Longint;
{ TWACanvas }
TWACanvas = class(TImportExtension)
Private
FCanvases : TJSObject;
FCurrentID : Integer;
FCanvasParent : TJSHTMLELement;
Protected
function GetCanvas(aID : TCanvasID) : TJSCanvasRenderingContext2D;
function allocate(SizeX : Longint; SizeY : Longint; aID: Longint): TCanvasError;
function moveto(aID : TCanvasID; X : Longint;Y : Longint): TCanvasError;
function lineto(aID : TCanvasID;X : Longint; Y : Longint ): TCanvasError;
function stroke(aID : TCanvasID): TCanvasError;
function beginpath(aID : TCanvasID): TCanvasError;
function arc(aID : TCanvasID;X : Longint;Y : Longint;Radius : Longint;StartAngle : Double;EndAngle : Double): TCanvasError;
function fillrect(aID : TCanvasID; X : Longint; Y : Longint; Width : Longint; Height : Longint): TCanvasError;
function strokerect(aID : TCanvasID;X : Longint;Y : Longint; Width : Longint; Height : Longint ): TCanvasError;
function clearrect(aID : TCanvasID;X : Longint;Y : Longint;Width : Longint; Height : Longint ): TCanvasError;
function StrokeText(aID : TCanvasID;X : Longint;Y : Longint; aText : Longint; aTextLen : Longint ): TCanvasError;
function FillText(aID : TCanvasID;X : Longint;Y : Longint; aText : Longint; aTextLen : Longint ): TCanvasError;
Public
Constructor Create(aEnv : TPas2JSWASIEnvironment); override;
Procedure FillImportObject(aObject : TJSObject); override;
Function ImportName : String; override;
Property CanvasParent : TJSHTMLELement Read FCanvasParent Write FCanvasParent;
end;
Implementation
uses sysutils;
constructor TWACanvas.Create(aEnv: TPas2JSWASIEnvironment);
begin
Inherited Create(aEnv);
FCanvases:=TJSObject.New();
end;
function TWACanvas.ImportName: String;
begin
Result:='web_canvas';
end;
function TWACanvas.GetCanvas(aID : TCanvasID) : TJSCanvasRenderingContext2D;
Var
JS : JSValue;
begin
JS:=FCanvases[IntTostr(AID)];
if IsObject(JS) then
Result:=TJSCanvasRenderingContext2D(JS)
else
Result:=Nil;
end;
procedure TWACanvas.FillImportObject(aObject: TJSObject);
begin
aObject['allocate']:=@allocate;
aObject['moveto']:=@moveto;
aObject['lineto']:=@LineTo;
aObject['stroke']:=@stroke;
aObject['beginpath']:=@beginpath;
aObject['arc']:=@arc;
aObject['fillrect']:=@fillrect;
aObject['strokerect']:=@strokerect;
aObject['clearrect']:=@clearrect;
aObject['stroketext']:=@StrokeText;
aObject['filltext']:=@FillText;
end;
function TWACanvas.allocate(SizeX : Longint; SizeY : Longint; aID: Longint): TCanvasError;
Var
C : TJSElement;
V : TJSDataView;
begin
C:=window.document.createElement('CANVAS');
CanvasParent.AppendChild(C);
Inc(FCurrentID);
V:=getModuleMemoryDataView;
FCanvases[IntToStr(FCurrentID)]:=TJSHTMLCanvasElement(c).getcontext('2d');
v.setUint32(aID, FCurrentID, env.IsLittleEndian);
Result:=ECANVAS_SUCCESS;
end;
function TWACanvas.moveto(aID : TCanvasID; X : Longint;Y : Longint): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
C.moveto(X,Y);
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.lineto(aID : TCanvasID;X : Longint; Y : Longint ): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
C.lineto(X,Y);
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.stroke(aID : TCanvasID): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
C.Stroke;
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.beginpath(aID : TCanvasID): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
C.beginPath;
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.arc(aID : TCanvasID;X : Longint;Y : Longint;Radius : Longint;StartAngle : Double;EndAngle : Double): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
C.arc(X,y,radius,Startangle,EndAngle);
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.fillrect(aID : TCanvasID; X : Longint; Y : Longint; Width : Longint; Height : Longint): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
C.FillRect(X,y,width,Height);
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.strokerect(aID : TCanvasID;X : Longint;Y : Longint; Width : Longint; Height : Longint ): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
C.StrokeRect(X,Y,Width,Height);
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.clearrect(aID : TCanvasID;X : Longint;Y : Longint;Width : Longint; Height : Longint ): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
C.ClearRect(X,Y,Width,Height);
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.StrokeText(aID: TCanvasID; X: Longint; Y: Longint;
aText: Longint; aTextLen: Longint): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
S : String;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
S:=Env.GetUTF8StringFromMem(aText,aTextLen);
C.StrokeText(S,X,Y);
Result:=ECANVAS_SUCCESS;
end;
end;
function TWACanvas.FillText(aID: TCanvasID; X: Longint; Y: Longint;
aText: Longint; aTextLen: Longint): TCanvasError;
Var
C : TJSCanvasRenderingContext2D;
S : String;
begin
Result:=ECANVAS_NOCANVAS;
C:=GetCanvas(aID);
if Assigned(C) then
begin
S:=Env.GetUTF8StringFromMem(aText,aTextLen);
C.FillText(S,X,Y);
Result:=ECANVAS_SUCCESS;
end;
end;
end.

View File

@ -0,0 +1,97 @@
unit webcanvas;
interface
// These types and constants could go in a unit shared between pas2js and webassembly !
Type
TCanvasError = longint;
TCanvasID = longint;
PCanvasID = ^TCanvasID;
Const
ECANVAS_SUCCESS = 0;
ECANVAS_NOCANVAS = 1;
ECANVAS_UNSPECIFIED = -1;
function __webcanvas_allocate(
SizeX : Longint;
SIzeY : Longint;
aID: PCanvasID
): TCanvasError; external 'web_canvas' name 'allocate';
function __webcanvas_moveto(
aID : TCanvasID;
X : Longint;
Y : Longint
): TCanvasError; external 'web_canvas' name 'moveto';
function __webcanvas_lineto(
aID : TCanvasID;
X : Longint;
Y : Longint
): TCanvasError; external 'web_canvas' name 'lineto';
function __webcanvas_stroke(
aID : TCanvasID
): TCanvasError; external 'web_canvas' name 'stroke';
function __webcanvas_beginpath(
aID : TCanvasID
): TCanvasError; external 'web_canvas' name 'beginpath';
function __webcanvas_arc(
aID : TCanvasID;
X : Longint;
Y : Longint;
Radius : Longint;
StartAngle : Double;
EndAngle : Double
): TCanvasError; external 'web_canvas' name 'arc';
function __webcanvas_fillrect(
aID : TCanvasID;
X : Longint;
Y : Longint;
Width : Longint;
Height : Longint
): TCanvasError; external 'web_canvas' name 'fillrect';
function __webcanvas_strokerect(
aID : TCanvasID;
X : Longint;
Y : Longint;
Width : Longint;
Height : Longint
): TCanvasError; external 'web_canvas' name 'strokerect';
function __webcanvas_clearrect(
aID : TCanvasID;
X : Longint;
Y : Longint;
Width : Longint;
Height : Longint
): TCanvasError; external 'web_canvas' name 'clearrect';
function __webcanvas_stroketext(
aID : TCanvasID;
X : Longint;
Y : Longint;
aText : PByte;
aTextLen : Longint
): TCanvasError; external 'web_canvas' name 'stroketext';
function __webcanvas_filltext(
aID : TCanvasID;
X : Longint;
Y : Longint;
aText : PByte;
aTextLen : Longint
): TCanvasError; external 'web_canvas' name 'filltext';
implementation
end.

1
demo/wasienv/simple/bulma.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
<Runnable Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="demowasienv"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<CustomData Count="2">
<Item0 Name="MaintainHTML" Value="1"/>
<Item1 Name="PasJSWebBrowserProject" Value="1"/>
</CustomData>
<BuildModes>
<Item Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<Units>
<Unit>
<Filename Value="demowasienv.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="index.html"/>
<IsPartOfProject Value="True"/>
<CustomData Count="1">
<Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
</CustomData>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target FileExt=".js">
<Filename Value="demowasienv"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="js"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<AllowLabel Value="False"/>
<CPPInline Value="False"/>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<TargetOS Value="browser"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
<UseLineInfoUnit Value="False"/>
</Debugging>
</Linking>
<Other>
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
<CompilerPath Value="$(pas2js)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,118 @@
program demowasienv;
{$mode objfpc}
uses
browserconsole, browserapp, JS, Classes, SysUtils, Web, WebAssembly, types, wasienv;
Type
{ TMyApplication }
TMyApplication = class(TBrowserApplication)
Private
FWasiEnv: TPas2JSWASIEnvironment;
FMemory : TJSWebAssemblyMemory; // Memory of webassembly
FTable : TJSWebAssemblyTable; // exported functions.
function CreateWebAssembly(Path: string; ImportObject: TJSObject
): TJSPromise;
procedure DoWrite(Sender: TObject; const aOutput: String);
function initEnv(aValue: JSValue): JSValue;
procedure InitWebAssembly;
Public
Constructor Create(aOwner : TComponent); override;
Destructor Destroy; override;
procedure doRun; override;
end;
function TMyApplication.InitEnv(aValue: JSValue): JSValue;
Var
Module : TJSInstantiateResult absolute aValue;
exps : TWASIExports;
begin
Result:=True;
Exps := TWASIExports(TJSObject(Module.Instance.exports_));
FWasiEnv.Instance:=Module.Instance;
console.info('got exports', exps);
Exps.Start;
end;
procedure TMyApplication.DoWrite(Sender: TObject; const aOutput: String);
begin
Writeln(aOutput);
end;
constructor TMyApplication.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FWasiEnv:=TPas2JSWASIEnvironment.Create;
FWasiEnv.OnStdErrorWrite:=@DoWrite;
FWasiEnv.OnStdOutputWrite:=@DoWrite;
end;
function TMyApplication.CreateWebAssembly(Path: string; ImportObject: TJSObject): TJSPromise;
begin
Result:=window.fetch(Path)._then(Function (res : jsValue) : JSValue
begin
Result:=TJSResponse(Res).arrayBuffer._then(Function (res2 : jsValue) : JSValue
begin
Result:=TJSWebAssembly.instantiate(TJSArrayBuffer(res2),ImportObject);
end,Nil)
end,Nil
);
end;
procedure TMyApplication.InitWebAssembly;
Var
mDesc : TJSWebAssemblyMemoryDescriptor;
tDesc: TJSWebAssemblyTableDescriptor;
ImportObj : TJSObject;
begin
// Setup memory
mDesc.initial:=256;
mDesc.maximum:=256;
FMemory:=TJSWebAssemblyMemory.New(mDesc);
// Setup table
tDesc.initial:=0;
tDesc.maximum:=0;
tDesc.element:='anyfunc';
FTable:=TJSWebAssemblyTable.New(tDesc);
// Setup ImportObject
ImportObj:=new([
'js', new([
'mem', FMemory,
'tbl', FTable
])
]);
FWasiEnv.AddImports(ImportObj);
CreateWebAssembly('helloworld.wasm',ImportObj)._then(@initEnv)
end;
destructor TMyApplication.Destroy;
begin
FreeAndNil(FWasiEnv);
inherited Destroy;
end;
procedure TMyApplication.doRun;
begin
// Your code here
Terminate;
InitWebAssembly;
end;
var
Application : TMyApplication;
begin
Application:=TMyApplication.Create(nil);
Application.Initialize;
Application.Run;
end.

View File

@ -0,0 +1,6 @@
program HelloWorld;
begin
Writeln('Hello world from FPC webassembly and Pas2JS!');
Writeln('... and a merry Christmas for all!');
end.

View File

@ -0,0 +1,47 @@
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FPC-Webassembly and Pas2JS Demo</title>
<link href="bulma.min.css" rel="stylesheet">
<script src="demowasienv.js"></script>
<style>
.source {
width: 730px;
margin: -45px auto;
font-size: 0.9em;
}
.source-inner {
display: flex;
justify-content: space-between;
align-items: center;
width: 482px;
}
</style>
</head>
<body>
<div class="section">
<h1 class="title is-4">FPC compiled wasm program console output:</h1>
<div id="pasjsconsole"></div>
</div>
<hr>
<div class="section">
<div class="source">
<div class="source-inner">
<div>
<p>Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> </p>
<p>Pas2JS Sources: &nbsp; <a target="new" href="demowasienv.lpr">Pas2JS Program</a></p>
<p>Webassembly Sources: &nbsp; <a target="new" href="helloworld.pp">FPC Program</a></p>
</div>
</div>
</div>
</div>
<script>
rtl.showUncaughtExceptions=true;
rtl.run();
</script>
</body>
</html>

1
demo/wasienv/terminal/bulma.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
<Runnable Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="demowasiterm"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<CustomData Count="2">
<Item0 Name="MaintainHTML" Value="1"/>
<Item1 Name="PasJSWebBrowserProject" Value="1"/>
</CustomData>
<BuildModes>
<Item Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<Units>
<Unit>
<Filename Value="demowasiterm.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="index.html"/>
<IsPartOfProject Value="True"/>
<CustomData Count="1">
<Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
</CustomData>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target FileExt=".js">
<Filename Value="demowasiterm"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="js"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<AllowLabel Value="False"/>
<CPPInline Value="False"/>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<TargetOS Value="browser"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
<UseLineInfoUnit Value="False"/>
</Debugging>
</Linking>
<Other>
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
<CompilerPath Value="$(pas2js)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,208 @@
program demowasiterm;
{$mode objfpc}
uses
browserapp, JS, Classes, SysUtils, Web, WebAssembly, types,
xterm, wasienv, strutils;
Type
{ TMyApplication }
TMyApplication = class(TBrowserApplication)
Private
FTerminal : TXTerm.TTerminal;
FTermEl : TJSHTMLElement;
FWasiEnv : TPas2JSWASIEnvironment;
FMemory : TJSWebAssemblyMemory; // Memory of webassembly
FTable:TJSWebAssemblyTable; // Exported functions, directly callable
FInputLine : String;
Fidx : Integer;
FinputLines : TStrings;
function CreateWebAssembly(Path: string; ImportObject: TJSObject
): TJSPromise;
procedure DoGetInputString(Sender: TObject; var AInput: string);
function DoKey(keyData: TXTerm.TOnKeyCallbackDataType): Boolean;
procedure DoWrite(Sender: TObject; const aOutput: String);
function initEnv(aValue: JSValue): JSValue;
procedure InitWebAssembly;
Public
Constructor Create(aOwner : TComponent); override;
Destructor Destroy; override;
procedure doRun; override;
end;
function TMyApplication.InitEnv(aValue: JSValue): JSValue;
Var
Module : TJSInstantiateResult absolute aValue;
exps : TWASIExports;
begin
Result:=True;
Exps := TWASIExports(TJSObject(Module.Instance.exports_));
FWasiEnv.Instance:=Module.Instance;
Exps.Start;
end;
function TMyApplication.DoKey(keyData : TXTerm.TOnKeyCallbackDataType): Boolean;
{
Experimental code to convert keystrokes to input.
Unfortunately, it does not work because the webassembly is executed in the same thread as the javascript.
Maybe using a web-worker this can be realized.
}
Var
printable : Boolean;
begin
Result:=true;
With keyData do
printable :=Not (domEvent.altKey or domEvent.metaKey or domEvent.ctrlKey or domEvent.metaKey);
if keyData.domEvent.Key=TJSKeyNames.BackSpace then
begin
if (Length(FInputLine)>0) then
begin
FInputLine:=Copy(FInputLine,1,Length(FInputLine)-1);
FTerminal.write(#8' '#8);
end;
end
else if (keyData.domEvent.Key=TJSKeyNames.Enter) then
begin
FInputLine:=FInputLine+#10;
FTerminal.writeln('');
end
else if Printable then
begin
FInputLine:=FInputLine+keyData.Key;
FTerminal.write(keyData.Key);
end;
end;
procedure TMyApplication.DoWrite(Sender: TObject; const aOutput: String);
Var
S : TStringDynArray;
L : String;
I,aLen : Integer;
begin
S:=SplitString(aOutput,#10);
aLen:=length(S)-1;
For I:=0 to aLen do
begin
L:=S[i];
FTerminal.Write(L);
if I<aLen then
FTerminal.Writeln('')
end;
end;
constructor TMyApplication.Create(aOwner: TComponent);
Var
i : Integer;
begin
inherited Create(aOwner);
FWasiEnv:=TPas2JSWASIEnvironment.Create;
FWasiEnv.OnStdErrorWrite:=@DoWrite;
FWasiEnv.OnStdOutputWrite:=@DoWrite;
FWasiEnv.OnGetConsoleInputString:=@DoGetInputString;
FTermEl:=GetHTMLElement('xterm');
FTerminal:=TXTerm.TTerminal.New;
FTerminal.OnKey(@DoKey);
FTerminal.open(FTermEl);
FinputLine:='';
FinputLines:=TStringList.Create;
Fidx:=0;
For I:=0 to 9 do
FinputLines.Add(IntToStr(Random(200)));
FinputLines.Add('-1');
end;
function TMyApplication.CreateWebAssembly(Path: string; ImportObject: TJSObject): TJSPromise;
begin
Result:=window.fetch(Path)._then(Function (res : jsValue) : JSValue
begin
Result:=TJSResponse(Res).arrayBuffer._then(Function (res2 : jsValue) : JSValue
begin
Result:=TJSWebAssembly.instantiate(TJSArrayBuffer(res2),ImportObject);
end,Nil)
end,Nil
);
end;
procedure TMyApplication.DoGetInputString(Sender: TObject; var AInput: string);
Var
S : String;
begin
{
// Experimental code for use with keyhandler.
aInput:=FInputLine;
FInputLine:='';
}
aInput:='';
If FIdx<FInputLines.Count then
begin
S:=FInputLines[FIdx];
aInput:=S+#10;
FTerminal.writeln(#27'[31m'+S+#27'[37m');
inc(FIdx);
end;
end;
procedure TMyApplication.InitWebAssembly;
Var
mDesc : TJSWebAssemblyMemoryDescriptor;
tDesc: TJSWebAssemblyTableDescriptor;
ImportObj : TJSObject;
begin
// Setup memory
mDesc.initial:=256;
mDesc.maximum:=256;
FMemory:=TJSWebAssemblyMemory.New(mDesc);
// Setup table
tDesc.initial:=0;
tDesc.maximum:=0;
tDesc.element:='anyfunc';
FTable:=TJSWebAssemblyTable.New(tDesc);
// Setup ImportObject
ImportObj:=new([
'js', new([
'mem', FMemory,
'tbl', FTable
])
]);
FWasiEnv.AddImports(ImportObj);
CreateWebAssembly('sums.wasm',ImportObj)._then(@initEnv)
end;
destructor TMyApplication.Destroy;
begin
FreeAndNil(FWasiEnv);
inherited Destroy;
end;
procedure TMyApplication.doRun;
begin
// Your code here
Terminate;
InitWebAssembly;
end;
var
Application : TMyApplication;
begin
Application:=TMyApplication.Create(nil);
Application.Initialize;
Application.Run;
end.

View File

@ -0,0 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FPC-Webassembly with Pas2JS Terminal Demo</title>
<link href="https://unpkg.com/xterm@4.16.0/css/xterm.css" rel="stylesheet">
<script src="https://unpkg.com/xterm@4.16.0/lib/xterm.js"></script>
<link href="bulma.min.css" rel="stylesheet">
<script src="demowasiterm.js"></script>
<style>
.source {
width: 730px;
margin: -45px auto;
font-size: 0.9em;
}
.source-inner {
display: flex;
justify-content: space-between;
align-items: center;
width: 482px;
}
</style>
</head>
<body>
<div class="section">
<h1 class="title is-3">FPC-Webassembly with Pas2JS Terminal Demo</h1>
<div class="block">Red color indicates (simulated) terminal input to WebAssembly program</div>
<div id="xterm" style="width: 100%; height: 60vh; background-color: black;"></div>
</div>
<hr>
<div class="section">
<div class="source">
<div class="source-inner">
<div>
<p>Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> </p>
<p>Pas2JS Sources: &nbsp; <a target="new" href="demowasiterm.lpr">Pas2JS Program</a></p>
<p>Webassembly Sources: &nbsp; <a target="new" href="sums.pp">FPC Program</a></p>
</div>
</div>
</div>
</div>
<script>
rtl.showUncaughtExceptions=true;
window.addEventListener("load", rtl.run);
</script>
</body>
</html>

View File

@ -0,0 +1,19 @@
program HelloWorld;
Var
A,B,C : Integer;
begin
Writeln('Answer -1 to end the program');
Repeat
A:=Random(100);
B:=Random(100);
Write(A,' + ',B,' = ');
Readln(C);
if (C=(A+B)) then
Writeln('Well done !')
else if (C<>-1) then
Writeln('Sorry, wrong. The correct answer is ',A+B);
Until (C=-1);
end.

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="canvas/canvasdraw.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="canvas/demowasicanvas.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="simple/demowasienv.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="terminal/demowasiterm.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
</Targets>
</ProjectGroup>
</CONFIG>

View File

@ -1,14 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectGroup FileVersion="1">
<Targets Count="4">
<Target0 FileName="Pas2JS_WebGL.lpi"/>
<Target1 FileName="Pas2JS_WebGL_Minimal.lpi"/>
<Target2 FileName="Pas2JS_WebGL_OBJ.lpi">
<BuildModes Count="1"/>
<Mode1 Name="Default"/>
</Target2>
<Target3 FileName="Pas2JS_WebGL_Terrain.lpi"/>
<ProjectGroup FileVersion="2">
<Targets>
<Target FileName="Pas2JS_WebGL.lpi"/>
<Target FileName="Pas2JS_WebGL_Minimal.lpi"/>
<Target FileName="Pas2JS_WebGL_OBJ.lpi">
<BuildModes>
<Mode Name="Default"/>
</BuildModes>
</Target>
<Target FileName="Pas2JS_WebGL_Terrain.lpi"/>
</Targets>
</ProjectGroup>
</CONFIG>

1150
packages/wasi/wasienv.pas Normal file

File diff suppressed because it is too large Load Diff