|
@@ -1,3412 +0,0 @@
|
|
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
|
|
|
-<html><head>
|
|
|
|
- <title>pas2js - Translation of Pascal (Delphi/FPC) programs to JavaScript</title>
|
|
|
|
- <meta name="description" content="Translation of Pascal (Delphi/FPC) programs to JavaScript">
|
|
|
|
- <meta name="keywords" content="translation,program,Delphi,Pascal,javascript,pas2js">
|
|
|
|
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
|
|
- <style type="text/css">
|
|
|
|
- body {
|
|
|
|
- padding: 20px;
|
|
|
|
- margin-left: 20px;
|
|
|
|
- }
|
|
|
|
- table.sample th {
|
|
|
|
- background-color: #cccccc;
|
|
|
|
- font: 120% gelvetica,arial,tahoma;
|
|
|
|
- }
|
|
|
|
- table.sample pre {
|
|
|
|
- color: blue;
|
|
|
|
- }
|
|
|
|
- table.sample td {
|
|
|
|
- padding-left: 20px;
|
|
|
|
- padding-right: 20px;
|
|
|
|
- }
|
|
|
|
- .section {
|
|
|
|
- padding-bottom: 1em;
|
|
|
|
- }
|
|
|
|
- .tt {
|
|
|
|
- font-family: "Lucida Console", "Menlo", "Monaco", "Courier", monospace;
|
|
|
|
- } </style>
|
|
|
|
-</head>
|
|
|
|
-<body>
|
|
|
|
- <div id="head">
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2>Overview</h2>
|
|
|
|
- <a href="#about">About pas2js</a><br>
|
|
|
|
- <a href="#commandlineparameters">Command line parameters</a><br>
|
|
|
|
- <a href="#mode">Delphi and ObjFPC mode</a><br>
|
|
|
|
- <a href="#modules">Translating modules</a><br>
|
|
|
|
- <a href="#variables">Translating variables</a><br>
|
|
|
|
- <a href="#string">Translating string</a><br>
|
|
|
|
- <a href="#resourcestrings">Translating resourcestrings</a><br>
|
|
|
|
- <a href="#currency">Translating currency</a><br>
|
|
|
|
- <a href="#types">Translating types</a><br>
|
|
|
|
- <a href="#pointer">Translating pointer</a><br>
|
|
|
|
- <a href="#record">Translating record</a><br>
|
|
|
|
- <a href="#functions">Translating functions</a><br>
|
|
|
|
- <a href="#anonymousfunctions">Translating anonymous functions</a><br>
|
|
|
|
- <a href="#passbyref">Translating passing a parameter by reference</a><br>
|
|
|
|
- <a href="#nested functions">Translating nested functions</a><br>
|
|
|
|
- <a href="#forloop">Translating for-loop</a><br>
|
|
|
|
- <a href="#repeatuntil">Translating repeat..until</a><br>
|
|
|
|
- <a href="#whiledo">Translating while..do</a><br>
|
|
|
|
- <a href="#withdo">Translating with..do</a><br>
|
|
|
|
- <a href="#enums">Translating enums</a><br>
|
|
|
|
- <a href="#sets">Translating sets</a><br>
|
|
|
|
- <a href="#array">Translating array type</a><br>
|
|
|
|
- <a href="#class">Translating class type</a><br>
|
|
|
|
- <a href="#classof">Translating class-of type</a><br>
|
|
|
|
- <a href="#tobjectfree">Translating TObject.Free</a><br>
|
|
|
|
- <a href="#classinterfaces">Translating class interfaces</a><br>
|
|
|
|
- <a href="#helpers">Translating helpers</a><br>
|
|
|
|
- <a href="#attributes">Translating attributes</a><br>
|
|
|
|
- <a href="#tryfinally">Translating try..finally</a><br>
|
|
|
|
- <a href="#tryexcept">Translating try..except</a><br>
|
|
|
|
- <a href="#enumerators">Translating enumerators</a><br>
|
|
|
|
- <a href="#functiontype">Translating function types</a><br>
|
|
|
|
- <a href="#absolute">Translating var modifier absolute</a><br>
|
|
|
|
- <a href="#assert">Translating assert()</a><br>
|
|
|
|
- <a href="#dispatch">Dispatch messages</a><br>
|
|
|
|
- <a href="#calljavascript">Calling JavaScript from Pascal</a><br>
|
|
|
|
- <a href="#asm">The asm block</a><br>
|
|
|
|
- <a href="#assembler">The procedure modifier assembler</a><br>
|
|
|
|
- <a href="#externalproc">The procedure modifier external</a><br>
|
|
|
|
- <a href="#varargs">The procedure modifier varargs</a><br>
|
|
|
|
- <a href="#externalvar">The var modifier external</a><br>
|
|
|
|
- <a href="#externalmembers">The external modifier of class members</a><br>
|
|
|
|
- <a href="#externalclass">External classes</a><br>
|
|
|
|
- <a href="#externalclassancestor">External class as ancestor</a><br>
|
|
|
|
- <a href="#jsvalue">The JSValue type</a><br>
|
|
|
|
- <a href="#bracketaccessor">Accessing JS object properties with the bracket accessor</a><br>
|
|
|
|
- <a href="#async">Async/AWait</a><br>
|
|
|
|
- <a href="#rtti">RTTI - Run Time Type Information</a><br>
|
|
|
|
- <a href="#compilerdirectives">Compiler directives</a><br>
|
|
|
|
- <a href="#othersupportedelements">Other supported Pascal elements</a><br>
|
|
|
|
- <a href="#notsupportedelements">Not supported elements</a><br>
|
|
|
|
- <a href="#sourcemaps">Creating source maps</a><br>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="about">About pas2js</h2>
|
|
|
|
- pas2js is a compiler/transpiler to translate programs written in Pascal (subset of Delphi/ObjFPC syntax)
|
|
|
|
- to JavaScript.<br>
|
|
|
|
- The goal is to use strong typing, while still be able to use low level whenever you choose.<br>
|
|
|
|
- The compiled Pascal functions can be used in DOM events or called by JavaScript.<br>
|
|
|
|
- pas2js is written completely in FPC, runs on many platforms like Windows, Mac and Linux and more.
|
|
|
|
- It is built modular consisting of the following parts:
|
|
|
|
- <ul>
|
|
|
|
- <li>file cache - loading, caching files, converting to UTF-8</li>
|
|
|
|
- <li>file resolver - handling search paths, finding used units and include files</li>
|
|
|
|
- <li>scanner - reading tokens, handling compiler directives like $IfDef and $Include</li>
|
|
|
|
- <li>parser - reading the tokens, checking syntax, creating Pascal nodes</li>
|
|
|
|
- <li>resolver - resolving references, type checking and checking duplicate identifiers</li>
|
|
|
|
- <li>use analyzer - finding unused identifiers, emit hints and warning</li>
|
|
|
|
- <li>converter - translating Pascal nodes into JavaScript nodes</li>
|
|
|
|
- <li>compiler - handling config files, parameters, compiling recursively all used units, writes js</li>
|
|
|
|
- <li>command line interface - a small wrapper to embed the compiler into a console program</li>
|
|
|
|
- <li>library and interface - a small wrapper to embed the compiler into a library</li>
|
|
|
|
- </ul>
|
|
|
|
- Each part is tested separately and is used by other FPC tools as well. For example
|
|
|
|
- the scanner and parser are used by fpdoc too. Thus they are tested and extended by other
|
|
|
|
- programmers, reducing greatly the work for developing pas2js. Consistency is kept by
|
|
|
|
- several test suites, containing thousands of tests.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- Note: The modular structure allows to compile any parts or the whole compiler into an IDE addon (not yet started).
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="commandlineparameters">Command line parameters</h2>
|
|
|
|
- Most parameters work the same as their FPC equivalent. pas2js has some options of its own (see -J options).
|
|
|
|
-<pre>
|
|
|
|
-Usage: pas2js <your.pas>
|
|
|
|
-Options:
|
|
|
|
-Put + after a boolean switch option to enable it, - to disable it
|
|
|
|
- @<x> : Read compiler options from file <x> in addition to the default pas2js.cfg
|
|
|
|
- -B : Rebuild all
|
|
|
|
- -d<x> : Defines the symbol <x>. Optional: -d<x>:=<value>
|
|
|
|
- -i<x> : Write information and halt. <x> is a combination of the following:
|
|
|
|
- -iD : Write compiler date
|
|
|
|
- -iSO : Write compiler OS
|
|
|
|
- -iSP : Write compiler host processor
|
|
|
|
- -iTO : Write target platform
|
|
|
|
- -iTP : Write target processor
|
|
|
|
- -iV : Write short compiler version
|
|
|
|
- -iW : Write full compiler version
|
|
|
|
- -ic : Write list of supported JS processors usable by -P<x>
|
|
|
|
- -im : Write list of supported modeswitches usable by -M<x>
|
|
|
|
- -io : Write list of supported optimizations usable by -Oo<x>
|
|
|
|
- -it : Write list of supported targets usable by -T<x>
|
|
|
|
- -iJ : Write list of supported JavaScript identifiers -JoRTL-<x>
|
|
|
|
- -C<x> : Code generation options. <x> is a combination of the following letters:
|
|
|
|
- o : Overflow checking
|
|
|
|
- r : Range checking
|
|
|
|
- R : Object checks. Verify method calls and object type casts.
|
|
|
|
- -F... Set file names and paths:
|
|
|
|
- -Fe<x> : Redirect output to file <x>. UTF-8 encoded.
|
|
|
|
- -FE<x> : Set main output path to <x>
|
|
|
|
- -Fi<x> : Add <x> to include paths
|
|
|
|
- -FN<x> : add <x> to namespaces. Namespaces with trailing - are removed.
|
|
|
|
- Delphi calls this flag "unit scope names".
|
|
|
|
- -Fu<x> : Add <x> to unit paths
|
|
|
|
- -FU<x> : Set unit output path to <x>
|
|
|
|
- -I<x> : Add <x> to include paths, same as -Fi
|
|
|
|
- -J... Extra options of pas2js
|
|
|
|
- -Jc : Write all JavaScript concatenated into the output file
|
|
|
|
- -Je<x> : Encode messages as <x>.
|
|
|
|
- -Jeconsole : Console codepage. Default.
|
|
|
|
- -Jesystem : System codepage. On non Windows console and system are the same.
|
|
|
|
- -Jeutf-8 : Unicode UTF-8. Default when using -Fe.
|
|
|
|
- -JeJSON : Output compiler messages as JSON. Logo etc are outputted as-is.
|
|
|
|
- -Ji<x> : Insert JS file <x> into main JS file. E.g. -Jirtl.js. Can be given multiple times.
|
|
|
|
- -Jl : lower case identifiers
|
|
|
|
- -Jm : generate source maps
|
|
|
|
- -Jmsourceroot=<x> : use x as "sourceRoot", prefix URL for source file names.
|
|
|
|
- -Jmbasedir=<x> : write source file names relative to directory x, default is map file folder.
|
|
|
|
- -Jminclude : include Pascal sources in source map.
|
|
|
|
- -Jmabsolute: store absolute filenames, not relative.
|
|
|
|
- -Jmxssiheader : start source map with XSSI protection )]}.
|
|
|
|
- -Jm- : disable generating source maps
|
|
|
|
- -Jo<x> : Enable or disable extra option. The x is case insensitive:
|
|
|
|
- -JoSearchLikeFPC : search source files like FPC, default: search case insensitive.
|
|
|
|
- -JoUseStrict : add "use strict" to modules, default.
|
|
|
|
- -JoCheckVersion-: do not add rtl version check, default. (since 1.1)
|
|
|
|
- -JoCheckVersion=main: insert rtl version check into main. (since 1.1)
|
|
|
|
- -JoCheckVersion=system: insert rtl version check into system unit init. (since 1.1)
|
|
|
|
- -JoCheckVersion=unit: insert rtl version check into every unit init. (since 1.1)
|
|
|
|
- -JoRTL-<x>=<y>: set RTL identifier x to value y. See -iJ. (since 1.1)
|
|
|
|
- -Jpcmd<command> : Run postprocessor. For each generated js execute
|
|
|
|
- command passing the js as stdin and read the new js from stdout.
|
|
|
|
- This option can be added multiple times to call several
|
|
|
|
- postprocessors in succession.
|
|
|
|
- -Ju<x> : Add <x> to foreign unit paths. Foreign units are not compiled.
|
|
|
|
- -l : Write logo
|
|
|
|
- -M<x> : Set language mode or enable/disable a modeswitch
|
|
|
|
- -MDelphi: Delphi 7 compatibility mode
|
|
|
|
- -MObjFPC: FPC's Object Pascal compatibility mode (default)
|
|
|
|
- Each mode (as listed above) enables its default set of modeswitches.
|
|
|
|
- Other modeswitches are disabled and need to be enabled one by another.
|
|
|
|
- -NS<x> : obsolete: add <x> to namespaces. Same as -FN<x>
|
|
|
|
- -n : Do not read the default config files
|
|
|
|
- -o<x> : Change main JavaScript file to <x>, "." means stdout
|
|
|
|
- -O<x> : Optimizations:
|
|
|
|
- -O- : Disable optimizations
|
|
|
|
- -O1 : Level 1 optimizations (quick and debugger friendly)
|
|
|
|
- -O2 : Level 2 optimizations (Level 1 + not debugger friendly)
|
|
|
|
- -Oo<x> : Enable or disable optimization. The x is case insensitive:
|
|
|
|
- -OoEnumNumbers[-] : write enum values as number instead of name. Default in -O1.
|
|
|
|
- -OoRemoveNotUsedPrivates[-] : Default is enabled
|
|
|
|
- -OoRemoveNotUsedDeclarations[-] : Default enabled for programs with -Jc
|
|
|
|
- -OoRemoveNotUsedPublished[-] : Default is disabled
|
|
|
|
- -OoShortRefGlobals[-]: Insert JS local var for types, modules and static functions. Default enabled in -O2
|
|
|
|
- -P<x> : Set target processor. Case insensitive:
|
|
|
|
- -Pecmascript5 : default
|
|
|
|
- -Pecmascript6
|
|
|
|
- -S<x> : Syntax options. <x> is a combination of the following letters:
|
|
|
|
- 2 : Same as -Mobjfpc (default)
|
|
|
|
- a : Turn on assertions
|
|
|
|
- c : Support operators like C (*=,+=,/= and -=)
|
|
|
|
- d : Same as -Mdelphi
|
|
|
|
- m : Enables macro replacements
|
|
|
|
- j : Allows typed constants to be writeable (default)
|
|
|
|
- -SI<x> : Set interface style to <x>
|
|
|
|
- -SIcom : COM, reference counted interface (default)
|
|
|
|
- -SIcorba : CORBA interface
|
|
|
|
- -T<x> : Set target platform, case insensitive.
|
|
|
|
- -Tbrowser : default
|
|
|
|
- -Tnodejs : add pas.run(), includes -Jc
|
|
|
|
- -u<x> : Undefines the symbol <x>
|
|
|
|
- -v<x> : Be verbose. <x> is a combination of the following letters:
|
|
|
|
- e : Show errors (default)
|
|
|
|
- w : Show warnings
|
|
|
|
- n : Show notes
|
|
|
|
- h : Show hints
|
|
|
|
- i : Show info
|
|
|
|
- l : Show line numbers, needs -vi
|
|
|
|
- a : Show everything
|
|
|
|
- 0 : Show nothing (except errors)
|
|
|
|
- b : Show file names with full path
|
|
|
|
- c : Show conditionals
|
|
|
|
- t : Show tried/used files
|
|
|
|
- d : Show debug notes and info, enables -vni
|
|
|
|
- q : Show message numbers
|
|
|
|
- x : Show used tools
|
|
|
|
- v : Write pas2jsdebug.log with lots of debugging info
|
|
|
|
- z : Write messages to stderr, -o. still uses stdout.
|
|
|
|
- -vm<x>,<y>: Do not show messages numbered <x> and <y>.
|
|
|
|
- -? : Show this help
|
|
|
|
- -h : Show this help
|
|
|
|
-
|
|
|
|
-Environment variable PAS2JS_OPTS is parsed after default config
|
|
|
|
-and before command line parameters.
|
|
|
|
-</pre>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="mode">Delphi and ObjFPC mode</h2>
|
|
|
|
- <h3>Delphi mode</h3>
|
|
|
|
- <ul>
|
|
|
|
- <li>Defines macro <i>DELPHI</i></li>
|
|
|
|
- <li>Assigning a function to a function type variable does not require the @ operator.
|
|
|
|
- For example, you can write either <i>OnGetThing:=GetValue;</i> or <i>OnGetThing:=@GetValue;</i>.</li>
|
|
|
|
- <li>A function type variable reference without brackets is treated as a call.
|
|
|
|
- For example: If <i>OnGetThing</i> is a variable of type <i>function: integer</i>
|
|
|
|
- you can write: <i>If OnGetThing=3 then ;</i>.</li>
|
|
|
|
- <li>You must use the @@ operator to get the procedure address (i.e. JS reference) of a procedure type variable.
|
|
|
|
- For example instead of <i>If OnClick=nil then ;</i> you must use <i>if @@OnClick=nil then ;</i>.</li>
|
|
|
|
- <li>Every procedure/method overload needs the 'overload' modifier.</li>
|
|
|
|
- </ul>
|
|
|
|
- <h3>ObjFPC mode</h3>
|
|
|
|
- This the default mode of pas2js and is generally more strict than the Delphi mode, and allows some more operations.
|
|
|
|
- <ul>
|
|
|
|
- <li>Defines macro <i>OBJFPC</i></li>
|
|
|
|
- <li>Assigning a function to a function type variable requires the @ operator.
|
|
|
|
- For example: <i>OnGetThing:=@GetValue;</i>.</li>
|
|
|
|
- <li>A function type variable always needs brackets to be called.
|
|
|
|
- For example: If <i>OnGetThing</i> is a variable of type <i>function: integer</i>
|
|
|
|
- then this is allowed: <i>If OnGetThing()=3 then ;</i>.
|
|
|
|
- While this gives an error: <i>If OnGetThing=3 then ;</i>.</li>
|
|
|
|
- <li>You can compare a procedure type with <i>nil</i>.
|
|
|
|
- For example <i>If OnClick=nil then ;</i>.</li>
|
|
|
|
- <li>You can compare a procedure type with a procedure address (i.e. JS reference).
|
|
|
|
- For example <i>If OnClick=@OnFormClick then ;</i>.</li>
|
|
|
|
- <li>The procedure modifier 'overload' can be omitted when all overloads are
|
|
|
|
- in one scope, e.g. a unit or a class. And if one procedure has such modifier
|
|
|
|
- all procedures with same name and in same scope are overloads as well.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="modules">Translating modules</h2>
|
|
|
|
- A Pascal Program is translated into the following JavaScript structure:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript Structure, not code!</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program <unitname>;
|
|
|
|
-Implementation
|
|
|
|
- [implementation section]
|
|
|
|
-Begin
|
|
|
|
- [main code]
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>pas.<program>={
|
|
|
|
- [implementation section],
|
|
|
|
- $main: function() {
|
|
|
|
- [main code]
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- A Pascal Unit is translated into the following JavaScript structure:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript Structure, not code!</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit <unitname>;
|
|
|
|
-Interface
|
|
|
|
- [interface section]
|
|
|
|
-Implementation
|
|
|
|
- [implementation section]
|
|
|
|
-Initialization
|
|
|
|
- [initialization section]
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>pas.<unitname>={
|
|
|
|
- [interface section],
|
|
|
|
- $impl: {
|
|
|
|
- [implementation section],
|
|
|
|
- },
|
|
|
|
- $init: function() {
|
|
|
|
- [initialization section]
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Note: The <b>finalization</b> section is not supported by pas2js.<br>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- To create and initialize the units in topological order the compiler translates
|
|
|
|
- an Unit to the following JavaScript code:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit <unitname>;
|
|
|
|
-Interface
|
|
|
|
- [interface section]
|
|
|
|
-Implementation
|
|
|
|
- [implementation section]
|
|
|
|
-Initialization
|
|
|
|
- [initialization section]
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module('<unitname>',
|
|
|
|
- ['system',...other used units of the interface section...],
|
|
|
|
- function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- var $impl = $mod.$impl;
|
|
|
|
- [interface section]
|
|
|
|
- $mod.$implcode = function(){
|
|
|
|
- [implementation section]
|
|
|
|
- }
|
|
|
|
- $mod.$init = function(){
|
|
|
|
- [initialization section]
|
|
|
|
- };
|
|
|
|
- },
|
|
|
|
- [...used units of the implementation section]
|
|
|
|
- };
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- Here is a more detailed example to make it more clear:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Uses Sysutils;
|
|
|
|
-var
|
|
|
|
- dIntf: double;
|
|
|
|
- sIntf: string = 'abc';
|
|
|
|
-procedure MyIntfProc;
|
|
|
|
-Implementation
|
|
|
|
-Uses Classes;
|
|
|
|
-Var dImpl:double;
|
|
|
|
-Procedure MyIntfProc;
|
|
|
|
-Begin
|
|
|
|
- dImpl:=dIntf;
|
|
|
|
-End;
|
|
|
|
-Procedure MyImplProc;
|
|
|
|
-Begin
|
|
|
|
- dImpl:=dIntf;
|
|
|
|
-End;
|
|
|
|
-Initialization
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System","SysUtils"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- var $impl = $mod.$impl;
|
|
|
|
- this.dIntf = 0.0;
|
|
|
|
- this.sIntf = "abc";
|
|
|
|
- this.MyIntfProc = function(){
|
|
|
|
- $impl.dImpl = $mod.dIntf;
|
|
|
|
- };
|
|
|
|
- $mod.$implcode = function(){
|
|
|
|
- $impl.dImpl = 0.0;
|
|
|
|
- $impl.MyImplProc = function() {
|
|
|
|
- $impl.dImpl = $mod.dIntf;
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
- $mod.$init = function() {
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-["Classes"]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Unit <i>System</i> is always loaded implicitely.</li>
|
|
|
|
- <li>References to other units are translated to full path. For example
|
|
|
|
- <i>TObject</i> is translated to <i>pas.system.TObject</i></li>
|
|
|
|
- <li>References to dotted unitnames, aka units with namespaces are translated
|
|
|
|
- to <i>pas["namespace.unitname"]</i>.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="variables">Translating variables</h2>
|
|
|
|
- Variables are converted without type, because JavaScript lacks a clear type.
|
|
|
|
- They are however always initialized, which helps JavaScript engines to optimize.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Uses Classes,Forms;
|
|
|
|
-const
|
|
|
|
- c1:integer=3;
|
|
|
|
- c2 = 'abc';
|
|
|
|
- c3 = 234;
|
|
|
|
- c4 = 12.45;
|
|
|
|
- c5 = nil;
|
|
|
|
-var
|
|
|
|
- v1:string;
|
|
|
|
- v2,v3:double;
|
|
|
|
- v4:byte=0;
|
|
|
|
- v5:TForm;
|
|
|
|
- v6:TIdentMapEntry;
|
|
|
|
- v7:string='abcäöü';
|
|
|
|
- v8:char='c';
|
|
|
|
- v9:array of byte;
|
|
|
|
-Implementation
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System","Classes","Forms"],
|
|
|
|
-function(){
|
|
|
|
- this.c1 = 3;
|
|
|
|
- this.c2 = "abc";
|
|
|
|
- this.c3 = 234;
|
|
|
|
- this.c4 = 12.45;
|
|
|
|
- this.c5 = null;
|
|
|
|
- this.v1 = "";
|
|
|
|
- this.v2 = 0.0;
|
|
|
|
- this.v3 = 0.0;
|
|
|
|
- this.v4 = 0;
|
|
|
|
- this.v5 = null;
|
|
|
|
- this.v6 = new pas.Classes.TIdentMapEntry();
|
|
|
|
- this.v7 = "abcäöü";
|
|
|
|
- this.v8 = "c";
|
|
|
|
- this.v9 = [];
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Type casting a <i>boolean</i> to <i>integer</i>, gives <i>0</i> for <i>false</i> and <i>1</i> for <i>true</i>.</li>
|
|
|
|
- <li>Type casting an <i>integer</i> to <i>boolean</i>, gives <i>false</i> for <i>0</i> and <i>true</i> otherwise.</li>
|
|
|
|
- <li>A <b>char</b> is translated to a JS string, because JS lacks a native char type.</li>
|
|
|
|
- <li>A <b>char</b> is a single JS char code. An UTF-16 codepoint can contain one or two <b>char</b>.</li>
|
|
|
|
- <li><b>Integers overflows</b> at runtime differ from Delphi/FPC, due to the double format.
|
|
|
|
- For example adding <i>var i: byte = 200; ... i:=i+100;</i> will result in
|
|
|
|
- <i>i=300</i> instead of <i>i=44</i> as in Delphi/FPC.
|
|
|
|
- When range checking <i>{$R+}</i> is enabled <i>i:=300</i> will raise an ERangeError.</li>
|
|
|
|
- <li><b>type cast integer to integer</b>, e.g. <i>byte(aLongInt)</i>
|
|
|
|
- <ul>
|
|
|
|
- <li>with range checking enabled: error if outside range</li>
|
|
|
|
- <li>without range checking: emulates the FPC/Delphi behaviour:
|
|
|
|
- e.g. <i>byte(value)</i> translates to <i>value & 0xff</i>,
|
|
|
|
- <i>shortint(value)</i> translates to <i>value & 0xff <<24 >> 24.</i></li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>The <b>mod-operator</b> works 32-bit signed in JS.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="string">Translating string</h2>
|
|
|
|
- Strings are translated to JavaScript strings. They are initialized with ""
|
|
|
|
- and are never <b>null</b>.<br>
|
|
|
|
- There are no <i>ShortString, AnsiString or RawByteString</i>.
|
|
|
|
- <i>Unicodestring</i> and <i>Widestring</i> are alias of <i>String</i>.<br>
|
|
|
|
- JavaScript strings are immutable, which means
|
|
|
|
- that changing a single character in a string, creates a new string. So a <i>s[2]:='c';</i>
|
|
|
|
- is a slow operation in pas2js compared to Delphi/FPC.<br>
|
|
|
|
- Although pas2js creates .js files encoded as UTF-8 with BOM, JavaScript strings are
|
|
|
|
- UTF-16 at runtime. Keep in mind that one UTF-16 codepoint can need two <i>char</i>,
|
|
|
|
- and a visible glyph can need several codepoints. Same as in Delphi.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="resourcestrings">Translating resourcestrings</h2>
|
|
|
|
- Resourcestrings are translated to JS objects with original (org) and current value.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-resourcestring
|
|
|
|
- rsCompiler = 'pas2js';
|
|
|
|
-var
|
|
|
|
- s:string;
|
|
|
|
-Implementation
|
|
|
|
-initialization
|
|
|
|
- s:=rsCompiler;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("test1",["System"],function () {
|
|
|
|
- var $mod = this;
|
|
|
|
- this.s = "";
|
|
|
|
- $mod.$resourcestrings = {rsCompiler: {org: "pas2js"}};
|
|
|
|
- $mod.$init = function () {
|
|
|
|
- $mod.s = rtl.getResStr(pas.test1,"rsCompiler");
|
|
|
|
- };
|
|
|
|
-});
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="currency">Translating currency</h2>
|
|
|
|
- <i>Currency</i> in Delphi/FPC is an int64 with a factor of 10000. This is
|
|
|
|
- translated to a double with factor 10000 and truncated.
|
|
|
|
- <ul>
|
|
|
|
- <li><i>CurA := 1.12345</i> -> <i>CurA = 11234</i></li>
|
|
|
|
- <li><i>CurA + CurB</i> -> <i>CurA + CurB</i></li>
|
|
|
|
- <li><i>CurA * CurB</i> -> <i>CurA * CurB/10000</i></li>
|
|
|
|
- <li><i>CurA / CurB</i> -> <i>Math.floor(CurA/CurB * 10000)</i></li>
|
|
|
|
- <li><i>CurA ^^ CurB</i> -> <i>Math.floor(Math.pow(CurA/10000,CurB/10000) * 10000)</i></li>
|
|
|
|
- <li><i>Currency + Double</i> -> <i>Currency + (Double*10000)</i></li>
|
|
|
|
- <li><i>Double := Currency</i> -> <i>Double = Currency/10000</i></li>
|
|
|
|
- <li><i>Currency := Double</i> -> <i>Currency = Math.floor(Double*10000)</i></li>
|
|
|
|
- <li><i>JSValue := Currency</i> -> <i>JSValue = Currency/10000</i></li>
|
|
|
|
- <li>Keep in mind that a double has only 54 bits for the number, so calculating
|
|
|
|
- values greater than 900,719,925,474 might give a different result than in Delphi/FPC.
|
|
|
|
- See SysUtils.MinCurrency/MaxCurrency</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="types">Translating Types</h2>
|
|
|
|
- JavaScript type design has no declarative form, except for object types
|
|
|
|
- (so-called prototypes).
|
|
|
|
- That's why all the derivatives from simple Pascal types can not be translated.
|
|
|
|
- The compiler ensures type safety at compile time though, which is a big plus
|
|
|
|
- for using Pascal.<br>
|
|
|
|
- Complex Pascal types (classes, records, or arrays) are translated into
|
|
|
|
- JavaScript objects or arrays respectively.<br>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="pointer">Translating pointer</h2>
|
|
|
|
- A <i>pointer</i> is translated to a JS reference. It can be assigned a class,
|
|
|
|
- a class instance, a class-of, an array, a procedure var, a method var, a @proc address,
|
|
|
|
- a @method address, or a pointer of record.
|
|
|
|
- There is no pointer arithmetic, i.e. no p+1, and no typed pointers,
|
|
|
|
- except for pointer of record.
|
|
|
|
- You can find out its type using the functions <i>isArray</i>,
|
|
|
|
- <i>isClass</i>, <i>isClassRef</i>, <i>isCallback</i>, etc of unit <i>JS</i>.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="record">Translating record type</h2>
|
|
|
|
- A record is translated to a JavaScript object.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JS Pas2js 1.3</th>
|
|
|
|
- <th>JS Pas2js 1.2</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Type
|
|
|
|
- TMyRecord = Record
|
|
|
|
- i: integer;
|
|
|
|
- s: string;
|
|
|
|
- d: TDateTime;
|
|
|
|
- End;
|
|
|
|
-Var
|
|
|
|
- r, s: TMyRecord;
|
|
|
|
-Implementation
|
|
|
|
-Initialization
|
|
|
|
- r.i := 123;
|
|
|
|
- r:=s;
|
|
|
|
- if r=s then ;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- rtl.recNewT($mod, "TMyRecord", function() {
|
|
|
|
- this.i = 0;
|
|
|
|
- this.s = "";
|
|
|
|
- this.d = 0.0;
|
|
|
|
- this.$eq = function (b) {
|
|
|
|
- return (this.i == b.i) &&
|
|
|
|
- (this.s == b.i) && (this.d == b.d);
|
|
|
|
- };
|
|
|
|
- this.$assign = function (s) {
|
|
|
|
- this.i = s.i;
|
|
|
|
- this.s = s.s;
|
|
|
|
- this.d = s.d;
|
|
|
|
- return this;
|
|
|
|
- };
|
|
|
|
- };
|
|
|
|
- this.r = this.TMyRecord.$new();
|
|
|
|
- $mod.$init = function() {
|
|
|
|
- $mod.r.i=123;
|
|
|
|
- $mod.r.$assign($mod.s);
|
|
|
|
- if ($mod.r.$eq($mod.s)) ;
|
|
|
|
- },
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.TMyRecord = function(s) {
|
|
|
|
- if (s){
|
|
|
|
- this.i = s.i;
|
|
|
|
- this.s = s.s;
|
|
|
|
- this.d = s.d;
|
|
|
|
- } else {
|
|
|
|
- this.i = 0;
|
|
|
|
- this.s = "";
|
|
|
|
- this.d = 0.0;
|
|
|
|
- };
|
|
|
|
- this.$equal = function (b) {
|
|
|
|
- return (this.i == b.i) &&
|
|
|
|
- (this.s == b.i) && (this.d == b.d);
|
|
|
|
- };
|
|
|
|
- };
|
|
|
|
- this.r = new this.TMyRecord();
|
|
|
|
- $mod.$init = function() {
|
|
|
|
- $mod.r.i=123;
|
|
|
|
- $mod.r = new $mod.TMyRecord($mod.s);
|
|
|
|
- if ($mod.r.$equal($mod.s)) ;
|
|
|
|
- },
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- <ul>
|
|
|
|
- <li>The record variable creates a JavaScript object.</li>
|
|
|
|
- <li>Variant records are not supported.</li>
|
|
|
|
- <li>Supported: Assign, pass as argument, equal, not equal,
|
|
|
|
- array of record, pointer of record, const, default(), RTTI.</li>
|
|
|
|
- <li>Advanced record (since pas2js 1.3):
|
|
|
|
- <ul>
|
|
|
|
- <li>visibility private, strict private, public, default is public</li>
|
|
|
|
- <li>methods, class methods (must be static like in Delphi/FPC)</li>
|
|
|
|
- <li>class vars</li>
|
|
|
|
- <li>const fields</li>
|
|
|
|
- <li>property, class property, array property, default array property</li>
|
|
|
|
- <li>sub types</li>
|
|
|
|
- <li>constructor</li>
|
|
|
|
- <li>class constructor</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>Not yet implemented:
|
|
|
|
- <ul>
|
|
|
|
- <li>operator overloading</li>
|
|
|
|
- <li>reference counted interfaces as fields</li>
|
|
|
|
- <li>Interfaces as nested types</li>
|
|
|
|
- <li>default non array property</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>Until Pas2js 1.2 when assigning a record it is cloned, creating a new
|
|
|
|
- JS object. Since Pas2js 1.3 only values are copied,
|
|
|
|
- keeping the object, so pointer of record is compatible.</li>
|
|
|
|
- <li>Since record types are JS objects it is possible to typecast a record type
|
|
|
|
- to the JS Object, e.g. <i>TJSObject(TPoint)</i>.
|
|
|
|
- Note that you cannot typecast directly to a <i>TJSObject</i> descendant.
|
|
|
|
- You can use <i>TJSWindow(TJSObject(aRecord))</i>.</li>
|
|
|
|
- <li>A pointer of record is simply a reference.
|
|
|
|
- <ul>
|
|
|
|
- <li><i>p:=@r</i> translates to <i>p=r</i></li>
|
|
|
|
- <li><i>p^.x</i> becomes <i>p.x</i>.</li>
|
|
|
|
- <li><i>New(PointerOfRecord)</i> creates a new record</li>
|
|
|
|
- <li><i>Dispose(PointerOfRecord)</i> Sets the variable to null if possible.</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>Passing a record to an untyped arguments (e.g. ''TObject.Dispatch(var Msg)'')
|
|
|
|
- passes the record JS object directly, not creating a temporary reference object.</li>
|
|
|
|
- <li>Typecasting RecordType(UntypedArgument) returns the argument, i.e. no conversion.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="functions">Translating functions</h2>
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Function DoubleIt(n: integer): integer;
|
|
|
|
-Implementation
|
|
|
|
-Function DoubleIt(n: integer): integer;
|
|
|
|
-Begin
|
|
|
|
- Result:=2*n;
|
|
|
|
-End;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- this.DoubleIt = function(n){
|
|
|
|
- Result = 0;
|
|
|
|
- Result = 2*n;
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Local variables become local JavaScript variables: <i>var l = 0;</i>.</li>
|
|
|
|
- <li>Local constants become JavaScript variables in the unit/program implementation section.</li>
|
|
|
|
- <li>Local types are elevated to module.</li>
|
|
|
|
- <li>Overloaded functions are given an unique name by appending $1, $2, ...</li>
|
|
|
|
- <li>Supported: default values, const/var/out/default, FuncName:=</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="passbyref">Translating passing a parameter by reference</h2>
|
|
|
|
- JavaScript lacks passing by reference. Instead a temporary object is created
|
|
|
|
- with a <i>get</i> and <i>set</i> function.
|
|
|
|
- That means changes within the procedure are immediately visible outside, compatible with Pascal.
|
|
|
|
-
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-Procedure DoubleIt(var n: integer);
|
|
|
|
-Begin
|
|
|
|
- n:=2*n;
|
|
|
|
-End;
|
|
|
|
-Function Doubling(n: integer): integer;
|
|
|
|
-Begin
|
|
|
|
- DoubleIt(n);
|
|
|
|
- Result:=n;
|
|
|
|
-End;
|
|
|
|
-Var
|
|
|
|
- i: integer = 7;
|
|
|
|
-Begin
|
|
|
|
- Doubling(i);
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.i = 7;
|
|
|
|
- this.DoubleIt = function(n){
|
|
|
|
- n.set(2*n.get());
|
|
|
|
- };
|
|
|
|
- this.Doubling = function(n){
|
|
|
|
- var Result = 0;
|
|
|
|
- DoubleIt({
|
|
|
|
- get:function(){
|
|
|
|
- return n
|
|
|
|
- },
|
|
|
|
- set:function(v){
|
|
|
|
- n=v;
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- Result = n;
|
|
|
|
- return n;
|
|
|
|
- };
|
|
|
|
- $mod.$main = function(){
|
|
|
|
- Doubling($mod.i);
|
|
|
|
- }
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
-
|
|
|
|
- When the passed value is from another context, the context is passed too:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-Procedure DoubleIt(var n: integer);
|
|
|
|
-Begin
|
|
|
|
- n:=2*n;
|
|
|
|
-End;
|
|
|
|
-Var
|
|
|
|
- i: integer = 7;
|
|
|
|
-Begin
|
|
|
|
- DoubleIt(i);
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.i = 7;
|
|
|
|
- this.DoubleIt = function(n){
|
|
|
|
- n.set(2*n.get());
|
|
|
|
- };
|
|
|
|
- $mod.$main = function(){
|
|
|
|
- DoubleIt({
|
|
|
|
- p:$mod,
|
|
|
|
- get:function(){
|
|
|
|
- return this.p.i
|
|
|
|
- },
|
|
|
|
- set:function(v){
|
|
|
|
- this.p.i=v;
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Contrary to Delphi/FPC it is allowed to pass a property to a </i>var/out</i> parameter.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="nested functions">Translating nested functions</h2>
|
|
|
|
- A nested function is translated to a local variable.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Function SumNNumbers(n, Adder: integer): integer;
|
|
|
|
-Implementation
|
|
|
|
-Function SumNNumbers(n, Adder: integer): integer;
|
|
|
|
-
|
|
|
|
- Function Add(k: integer): integer;
|
|
|
|
- Begin
|
|
|
|
- if k=1 then
|
|
|
|
- Result:=1
|
|
|
|
- else
|
|
|
|
- Result:=Add(k-1)+Adder;
|
|
|
|
- End;
|
|
|
|
-
|
|
|
|
-Begin
|
|
|
|
- Result:=Add(n);
|
|
|
|
-End;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- this.DoubleIt = function(n,Adder){
|
|
|
|
- Result = 0;
|
|
|
|
- var Add = function(k) {
|
|
|
|
- Result = 0;
|
|
|
|
- if (k==1) {
|
|
|
|
- Result = 1;
|
|
|
|
- } else {
|
|
|
|
- Result = Add(k-1)+Adder;
|
|
|
|
- }
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
- Result = Add(n);
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Note: You can assign a nested procedure to a procedure variable. A nested
|
|
|
|
- procedure of a method can be assigned to a method variable.<br>
|
|
|
|
- JavaScript preserves the current local scope, including references to the
|
|
|
|
- local variables of parent functions. Local types and constants belong to the
|
|
|
|
- unit scope (singleton).<br>
|
|
|
|
- When a method has nested functions, the compiler adds a local var <i>Self</i>.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="forloop">Translating for-loops</h2>
|
|
|
|
- The JavaScript for-loop executes the end expression every iteration, while
|
|
|
|
- Pascal only executes it once. Therefore a local variable is introduced.
|
|
|
|
- If the loop is not entered at all, the variable is not touched. If the loop
|
|
|
|
- was entered the variable contanis the last value.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Function SumNNumbers(n: integer): integer;
|
|
|
|
-Implementation
|
|
|
|
-Function SumNNumbers(n: integer): integer;
|
|
|
|
-Var
|
|
|
|
- i, j: integer;
|
|
|
|
-Begin
|
|
|
|
- j:=0;
|
|
|
|
- For i:=1 To n Do
|
|
|
|
- Begin
|
|
|
|
- j:=j+i;
|
|
|
|
- End;
|
|
|
|
- if i<1 then j:=1;
|
|
|
|
- Result:=j;
|
|
|
|
-End;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- this.SumNNumbers=function(n){
|
|
|
|
- Result = 0;
|
|
|
|
- j = 0;
|
|
|
|
- for (var $l1 = 1, $le2 = n; $l1 <= $le2; $l1++) {
|
|
|
|
- i = $l1;
|
|
|
|
- j = j + i;
|
|
|
|
- };
|
|
|
|
- if (i<1) j=1;
|
|
|
|
- Result = j;
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Note: The after-loop decrement is only added if <i>i</i> is read after the loop.<br>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="repeatuntil">Translating repeat..until</h2>
|
|
|
|
- The <i>repeat..until</i> is translated to a <i>do{}while()</i>.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Function SumNNumbers(n: integer): integer;
|
|
|
|
-Implementation
|
|
|
|
-Function SumNNumbers(n: integer): integer;
|
|
|
|
-Var
|
|
|
|
- i, j: integer;
|
|
|
|
-Begin
|
|
|
|
- j:=0;
|
|
|
|
- i:=0;
|
|
|
|
- Repeat
|
|
|
|
- i:=i+1;
|
|
|
|
- j:=j+i;
|
|
|
|
- Until i>=n;
|
|
|
|
- Result:=j;
|
|
|
|
-End;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- this.SumNNumbers=function(n){
|
|
|
|
- Result = 0;
|
|
|
|
- j = 0;
|
|
|
|
- i = 0;
|
|
|
|
- do{
|
|
|
|
- i = (i + 1);
|
|
|
|
- j = (j + i);
|
|
|
|
- } while (!(i>=n));
|
|
|
|
- Result = j;
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="whiledo">Translating while..do</h2>
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Function SumNNumbers(n: integer): integer;
|
|
|
|
-Implementation
|
|
|
|
-Function SumNNumbers(n: integer): integer;
|
|
|
|
-Var
|
|
|
|
- i, j: integer;
|
|
|
|
-Begin
|
|
|
|
- j:=0;
|
|
|
|
- i:=0;
|
|
|
|
- While i<n Do Begin
|
|
|
|
- i:=i+1;
|
|
|
|
- j:=j+i;
|
|
|
|
- End;
|
|
|
|
- Result:=j;
|
|
|
|
-End;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- this.SumNNumbers=function(n){
|
|
|
|
- var Result = 0;
|
|
|
|
- var j = 0;
|
|
|
|
- var i = 0;
|
|
|
|
- while(i<n){
|
|
|
|
- i = (i + 1);
|
|
|
|
- j = (j + i);
|
|
|
|
- };
|
|
|
|
- Result = j;
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="casedo">Translating case..do</h2>
|
|
|
|
- Although JavaScript has something similar in form of the "switch" statement,
|
|
|
|
- it lacks ranges and is on current JS engines often slower than "if-else".
|
|
|
|
- Therefore a case..of is translated to if..else.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-Var
|
|
|
|
- i: integer;
|
|
|
|
-Begin
|
|
|
|
- case i of
|
|
|
|
- 1: ;
|
|
|
|
- 2: i:=3;
|
|
|
|
- else
|
|
|
|
- i:=4;
|
|
|
|
- end;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.i = 0;
|
|
|
|
- $mod.$main=function(n){
|
|
|
|
- $tmp1 = $mod.i;
|
|
|
|
- if ($tmp1 == 1){
|
|
|
|
- } else if ($tmp1 == 2) {
|
|
|
|
- i=3;
|
|
|
|
- } else {
|
|
|
|
- i=4;
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="withdo">Translating with..do</h2>
|
|
|
|
- JavaScript has a <b>with</b>, but it is slow and deprecated.
|
|
|
|
- Instead a temporary variable is used:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-type
|
|
|
|
- TClassA = class
|
|
|
|
- i: integer;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-procedure DoIt;
|
|
|
|
-
|
|
|
|
-Implementation
|
|
|
|
-
|
|
|
|
-procedure DoIt;
|
|
|
|
-begin
|
|
|
|
- with TClassA.Create do
|
|
|
|
- i:=3;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- rtl.createClass($mod, "TClassA", pas.System.TObject, function () {
|
|
|
|
- this.$init = function () {
|
|
|
|
- this.i = 0;
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- this.DoIt = function(){
|
|
|
|
- var $with1 = $mod.TClassA.$create("Create");
|
|
|
|
- $with1.i = 3;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Note: If the with-expression is already a local variable no new variable is
|
|
|
|
- created. This is Delphi/FPC compatible.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="enums">Translating enums</h2>
|
|
|
|
- Enum values are translated to numbers. The enum type is translated to an
|
|
|
|
- object containing a mapping from name to number and number to name.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-type
|
|
|
|
- TMyEnum = (
|
|
|
|
- Red,
|
|
|
|
- Green,
|
|
|
|
- Blue);
|
|
|
|
-var
|
|
|
|
- e: TMyEnum = Blue;
|
|
|
|
-
|
|
|
|
-procedure DoIt;
|
|
|
|
-
|
|
|
|
-Implementation
|
|
|
|
-
|
|
|
|
-procedure DoIt;
|
|
|
|
-begin
|
|
|
|
- e := Green;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.TMyEnum = {
|
|
|
|
- "0":"Red",
|
|
|
|
- Red:0,
|
|
|
|
- "1":"Green",
|
|
|
|
- Green:1,
|
|
|
|
- "2":"Blue",
|
|
|
|
- Blue:2
|
|
|
|
- };
|
|
|
|
- this.e = $mod.TMyEnum.Blue;
|
|
|
|
- this.DoIt = function(){
|
|
|
|
- $mod.e = $mod.TMyEnum.Green;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- <ul>
|
|
|
|
- <li>Supported: ord(), low(), high(), pred(), succ(), type cast number to enum.</li>
|
|
|
|
- <li>With optimization level -O1 the compiler uses numbers instead of names.</li>
|
|
|
|
- <li>Not yet implemented: custom values for enum values.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="sets">Translating sets</h2>
|
|
|
|
- A set s is translated to a JavaScript object, where for each included enum
|
|
|
|
- holds <i>s.enumvalue==true</i>.
|
|
|
|
- This allows arbitrary large sets and the <i>in</i> operator is fast.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-type
|
|
|
|
- TColor = (Red, Green, Blue);
|
|
|
|
- TColors = set of TColor;
|
|
|
|
-
|
|
|
|
-procedure DoIt;
|
|
|
|
-
|
|
|
|
-Implementation
|
|
|
|
-
|
|
|
|
-procedure DoIt;
|
|
|
|
-var
|
|
|
|
- c: TColor;
|
|
|
|
- S, T: TColors;
|
|
|
|
- b: boolean;
|
|
|
|
-begin
|
|
|
|
- S:=T;
|
|
|
|
- b:=Red in S;
|
|
|
|
- Include(S,Blue);
|
|
|
|
- Exclude(S,Blue);
|
|
|
|
- S:=S+T;
|
|
|
|
- S:=S-[Red,c];
|
|
|
|
- b:=c in [Red..Blue];
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.TColor = {
|
|
|
|
- "0":"Red",
|
|
|
|
- Red:0,
|
|
|
|
- "1":"Green",
|
|
|
|
- Green:1,
|
|
|
|
- "2":"Blue",
|
|
|
|
- Blue:2
|
|
|
|
- };
|
|
|
|
- $mod.DoIt = function(){
|
|
|
|
- var c = 0;
|
|
|
|
- var S = {};
|
|
|
|
- var T = {};
|
|
|
|
- var b = false;
|
|
|
|
- S = rtl.refSet(T);
|
|
|
|
- b = $mod.TColor.Red in S;
|
|
|
|
- S = rtl.includeSet(S,$mod.TColor.Blue);
|
|
|
|
- S = rtl.excludeSet(S,$mod.TColor.Blue);
|
|
|
|
- S = rtl.unionSet(S,T);
|
|
|
|
- S = rtl.diffSet(S,rtl.createSet($mod.TColor.Red,c));
|
|
|
|
- b = c in rtl.createSet(null,$mod.TColor.Red,$mod.TColor.Blue);
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- <ul>
|
|
|
|
- <li>Supported:
|
|
|
|
- <ul>
|
|
|
|
- <li>Include</li>
|
|
|
|
- <li>Exclude</li>
|
|
|
|
- <li>literal</li>
|
|
|
|
- <li>literal range, e.g. <i>[EnumA..EnumB], ['a'..'z']</i></li>
|
|
|
|
- <li>union +</li>
|
|
|
|
- <li>difference -</li>
|
|
|
|
- <li>intersect *</li>
|
|
|
|
- <li>symmetrical difference ><</li>
|
|
|
|
- <li>equal =</li>
|
|
|
|
- <li>unequal <></li>
|
|
|
|
- <li>subset <=</li>
|
|
|
|
- <li>superset >=</li>
|
|
|
|
- <li>set of anonymous enum type: <i>set of (enum1,enum2,...)</i></li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>Not supported: set of char, set of boolean</li>
|
|
|
|
- <li>There is no optimization yet for small sets like in Delphi/FPC.</li>
|
|
|
|
- <li>Assigning a set or passing the set as an argument only creates a
|
|
|
|
- reference and marks the set as <i>shared</i>.
|
|
|
|
- When a <i>shared</i> set is altered with Include/Exclude a new set is
|
|
|
|
- created (copy on write).</li>
|
|
|
|
- <li>Passing a set as an argument might clone the set.
|
|
|
|
- Use the <i>const</i> modifier for parameters whenever possible.</li>
|
|
|
|
- <li>Constant sets in expressions (e.g. <i>if c in ['a'..'z'] then</i>)
|
|
|
|
- are not yet optimized and created every time. Create a <i>const</i> to avoid this.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="array">Translating array type</h2>
|
|
|
|
- All arrays are translated into JavaScript arrays.<br>
|
|
|
|
- Contrary to Delphi/FPC dynamic arrays are
|
|
|
|
- not reference counted and do not copy on write. That means if you pass an
|
|
|
|
- array to a procedure and change an element, the original array is changed.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Type
|
|
|
|
- TIntArr = Array of integer;
|
|
|
|
- TObjArr = Array of TObject;
|
|
|
|
- TRec = record c: char; end;
|
|
|
|
- TRecArr = Array of TRec;
|
|
|
|
-Procedure Test;
|
|
|
|
-Implementation
|
|
|
|
-Procedure Test;
|
|
|
|
-Var
|
|
|
|
- IntArr: TIntArr = (1,2,3);
|
|
|
|
- ObjArr: TObjArr;
|
|
|
|
- RecArr: TRecArr;
|
|
|
|
-Begin
|
|
|
|
- IntArr:=nil;
|
|
|
|
- SetLength(IntArr,4);
|
|
|
|
- IntArr[2]:=2;
|
|
|
|
- IntArr[1]:=length(IntArr);
|
|
|
|
- SetLength(ObjArr,5);
|
|
|
|
- SetLength(RecArr,2,TRec);
|
|
|
|
-End;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.Test = function(){
|
|
|
|
- this.TRec = function(s){
|
|
|
|
- if (s){
|
|
|
|
- this.c = s.c;
|
|
|
|
- } else {
|
|
|
|
- this.c = "";
|
|
|
|
- };
|
|
|
|
- this.$equal = function(b){
|
|
|
|
- return (this.c == b.c);
|
|
|
|
- };
|
|
|
|
- };
|
|
|
|
- this.IntArr = [1,2,3];
|
|
|
|
- this.ObjArr = [];
|
|
|
|
- this.RecArr = [];
|
|
|
|
- this.Test = function(){
|
|
|
|
- $mod.IntArr = [];
|
|
|
|
- rtl.arraySetLength($mod.IntArr,4,0);
|
|
|
|
- $mod.IntArr[2] = 2;
|
|
|
|
- $mod.IntArr[1] = $mod.IntArr.length;
|
|
|
|
- rtl.setArrayLength($mod.ObjArr,5,null);
|
|
|
|
- rtl.setArrayLength($mod.RecArr,2,$mod.TRec);
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Supported features of dynamic arrays: SetLength(), Length(), equal/notequal nil, low(), high(),
|
|
|
|
- assigned(), concat(), copy(), insert(), delete(), multi dimensional, array of record</li>
|
|
|
|
- <li>Dynamic array constants. E.g. in mode ObjFPC <i>const a: array of byte = (1,2)</i>.
|
|
|
|
- In mode Delphi you must use square brackets, <i>... = [1,2]</i></li>
|
|
|
|
- <li>Supported features of static arrays: length(), low(), high(),
|
|
|
|
- assigned(), concat(), copy(), const, const records </li>
|
|
|
|
- <li>Open arrays are implemented as dynamic arrays.</li>
|
|
|
|
- <li>Calling <i>Concat()</i> with only one array simply returns the array
|
|
|
|
- (no cloning). Calling it with multiple arrays creates a clone.
|
|
|
|
- This is Delphi 10.1 compatible.</li>
|
|
|
|
- <li>In Delphi/FPC an empty array is <i>nil</i>. In JS it can be <i>null</i> or <i>[]</i>.
|
|
|
|
- For compatibility comparing an array with <i>nil</i> checks for <i>length(a)>0</i>.</li>
|
|
|
|
- <li><i>function Assigned(array): boolean</i> results true iff <i>length(array)>0</i>.</li>
|
|
|
|
- <li>array of const:
|
|
|
|
- <ul>
|
|
|
|
- <li>Works the same: vtInteger, vtBoolean, vtPointer, vtObject, vtClass, vtWideChar, vtInterface, vtUnicodeString</li>
|
|
|
|
- <li>''longword'' is converted to ''vtNativeInt''. Delphi/FPC converts to ''vtInteger'', changing big numbers to negative numbers.</li>
|
|
|
|
- <li>vtExtended is double, Delphi/FPC: PExtended</li>
|
|
|
|
- <li>vtCurrency is currency, Delphi/FPC: PCurrency</li>
|
|
|
|
- <li>Not supported: vtChar, vtString, vtPChar, vtPWideChar, vtAnsiString, vtVariant, vtWideString, vtInt64, vtQWord</li>
|
|
|
|
- <li>only in pas2js: vtNativeInt, vtJSValue</li>
|
|
|
|
- </ul></li>
|
|
|
|
- <li>Assignation using constant array, e.g. <i>a:=[1,1,2];</i></li>
|
|
|
|
- <li>String like operation: + operator concatenates arrays. e.g. <i>a:=[1]+[2];</i>.
|
|
|
|
- This is controlled by modeswitch arrayoperators, which is enabled in mode delphi.</li>
|
|
|
|
- <li><i>function copy(array,start=0,count=max): array</i></li>
|
|
|
|
- <li><i>procedure insert(item,var array,const position)</i></li>
|
|
|
|
- <li><i>procedure delete(var array,const start,count)</i></li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="class">Translating class type</h2>
|
|
|
|
- Classes are implemented using <i>Object.create</i> and some rtl magic.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Type
|
|
|
|
- TClassA = Class(TObject)
|
|
|
|
- Public
|
|
|
|
- i: integer;
|
|
|
|
- Procedure Add(a: integer);
|
|
|
|
- End;
|
|
|
|
-var
|
|
|
|
- ObjA: TClassA;
|
|
|
|
-Implementation
|
|
|
|
-Procedure TClassA.Add(a: integer);
|
|
|
|
-Begin
|
|
|
|
- i:=i+a;
|
|
|
|
-End;
|
|
|
|
-Initialization
|
|
|
|
- ObjA:=TClassA.Create;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- rtl.createClass($mod,"TClassA",pas.System.TObject,function(){
|
|
|
|
- this.$init = function () {
|
|
|
|
- this.i = 0;
|
|
|
|
- };
|
|
|
|
- this.Add = function(a){
|
|
|
|
- this.i = this.i + a;
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- this.ObjA = null;
|
|
|
|
- $mod.$init = function(){
|
|
|
|
- $mod.ObjA = $mod.TClassA.$create("Create");
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Each class and each instance is an JS object.</li>
|
|
|
|
- <li>Each class has a globally unique JS object, created by rtl.createClass.</li>
|
|
|
|
- <li><i>Self</i> is never <i>nil</i>.</li>
|
|
|
|
- <li>The method <i>TObject.Free</i> is using compiler magic. See <a href="#tobjectfree">Translating TObject.Free</a>.</li>
|
|
|
|
- <li><i>Class.$class</i> is a reference to the class itself.</li>
|
|
|
|
- <li><i>Class.$ancestor</i> is a reference to the ancestor class.</li>
|
|
|
|
- <li>A class has <i>c.$ancestor == Object.getPrototypeOf(c)</i>.</li>
|
|
|
|
- <li>A class instance has <i>o.$class == Object.getPrototypeOf(o)</i>.</li>
|
|
|
|
- <li><i>Class.$classname</i> is the short name. E.g. <i>TClassA.$classname == 'TClassA'</i>.</li>
|
|
|
|
- <li><i>Class.$name</i> is the long name. E.g. <i>TClassA.$name == 'MyModule.TClassA'</i>.</li>
|
|
|
|
- <li><i>Class.$unitname</i> is the unit name. E.g. <i>TClassA.$unitname == 'MyModule'</i>.</li>
|
|
|
|
- <li>The "<i>is</i>"-operator is implemented using "<i>isPrototypeOf</i>". Note that "<i>instanceof</i>" cannot be used, because classes are JS objects.</li>
|
|
|
|
- <li>The "<i>as</i>" operator is implemented as <i>rtl.as(Object,Class)</i>.</li>
|
|
|
|
- <li>Supported:
|
|
|
|
- <ul>
|
|
|
|
- <li>constructor, destructor</li>
|
|
|
|
- <li>private, protected, public, strict private, strict protected</li>
|
|
|
|
- <li>class vars, const, nested types</li>
|
|
|
|
- <li>methods, class methods, class constructor, external methods</li>
|
|
|
|
- <li>method modifiers overload, reintroduce, virtual, override, abstract,
|
|
|
|
- static, external name, message integer, message string</li>
|
|
|
|
- <li>call inherited</li>
|
|
|
|
- <li>assigned()</li>
|
|
|
|
- <li>type cast</li>
|
|
|
|
- <li>class sealed, class abstract</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>Not supported: class destructor</li>
|
|
|
|
- <li>Property:
|
|
|
|
- <ul>
|
|
|
|
- <li>References are replaced by getter/setter.</li>
|
|
|
|
- <li>Supported: argument lists, default property, class property,
|
|
|
|
- stored modifier, index modifier.</li>
|
|
|
|
- <li>Not supported: getter/setter to an array element,
|
|
|
|
- e.g. <i>property A: char read FArray[0];</i> </li>
|
|
|
|
- <li>Class property getter/setter can be static or non static. Delphi: must be static.</li>
|
|
|
|
- <li>The <i>Index</i> modifier supports any constant, e.g. a string, while
|
|
|
|
- Delphi only allows an ordinal (longint). -2147483648 is not a special
|
|
|
|
- number in pas2js. Overriding a property with an index property is allowed
|
|
|
|
- in Delphi and pas2js.</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="classof">Translating class-of type</h2>
|
|
|
|
- A class-of is a reference to a class. See above about translating class.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Type
|
|
|
|
- TBird = Class(TObject)
|
|
|
|
- Public
|
|
|
|
- Class var Count: integer;
|
|
|
|
- Class Procedure Add(a: integer); virtual;
|
|
|
|
- End;
|
|
|
|
- TBirds = class of TBird;
|
|
|
|
-
|
|
|
|
- TPigeon = Class(TBird)
|
|
|
|
- Public
|
|
|
|
- Class Procedure Add(a: integer); override;
|
|
|
|
- End;
|
|
|
|
-
|
|
|
|
-var
|
|
|
|
- BirdType: TBirds;
|
|
|
|
-Implementation
|
|
|
|
-Class Procedure TBird.Add(a: integer);
|
|
|
|
-Begin
|
|
|
|
- Count:=Count+a;
|
|
|
|
-End;
|
|
|
|
-Class Procedure TPigeon.Add(a: integer);
|
|
|
|
-Begin
|
|
|
|
- inherited Add(a+1);
|
|
|
|
-End;
|
|
|
|
-Initialization
|
|
|
|
- BirdType:=TPigeon;
|
|
|
|
- BirdType.Add(1);
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- rtl.createClass($mod,"TBird",pas.System.TObject,function () {
|
|
|
|
- this.Count = 0;
|
|
|
|
- this.Add = function (a) {
|
|
|
|
- this.Count = this.Count + a;
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- rtl.createClass($mod,"TPigeon",$mod.TBird,function () {
|
|
|
|
- this.Add = function (a) {
|
|
|
|
- $mod.TBird.Add.call(this,a + 1);
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- $mod.$init = function(){
|
|
|
|
- $mod.BirdType = $mod.TPigeon;
|
|
|
|
- $mod.BirdType.Add(1);
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Note that <i>this</i> in a class method is the class itself.<br>
|
|
|
|
- <br>
|
|
|
|
- Notes:<br>
|
|
|
|
- <ul>
|
|
|
|
- <li>Contrary to Delphi/FPC the "is" operator works with class-of.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="tobjectfree">Translating TObject.Free</h2>
|
|
|
|
- In Delphi/FPC AnObject.Free checks if Self is nil, then calls the destructor
|
|
|
|
- and frees the memory, without changing the reference.
|
|
|
|
- In JavaScript however calling a method with AnObject=nil causes a crash.
|
|
|
|
- And memory cannot be freed explicitely. Memory is only
|
|
|
|
- freed if all references are gone (e.g. set to <i>null</i>).<br>
|
|
|
|
- Therefore pas2js adds code to call the destructor and sets the variable to <i>nil</i>:<br>
|
|
|
|
- <ul>
|
|
|
|
- <li><i>Obj.Free</i> on a local variable or argument is translated to
|
|
|
|
- <i>Obj = rtl.freeLoc(Obj);</i>.</li>
|
|
|
|
- <li><i>Obj.Free</i> on a non local variable is translated to
|
|
|
|
- <i>rtl.free(this,"Obj");</i>.</li>
|
|
|
|
- <li>Not supported: Freeing a property or function result.<br>
|
|
|
|
- For example <i>List[i].Free</i> gives a compiler error. The property
|
|
|
|
- setter might create side effects, which would be incompatible to Delphi/FPC.
|
|
|
|
- </li>
|
|
|
|
- </ul>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>If the destructor raises an exception, the variable is not set to <i>nil</i>.
|
|
|
|
- This is compatible to Delphi/FPC, where the memory is not freed in this case.</li>
|
|
|
|
- <li>Alternatively you can use <i>FreeAndNil</i>, which first changes
|
|
|
|
- the variable to <i>nil</i> and then calls the destructor.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="classinterfaces">Translating class interfaces</h2>
|
|
|
|
- JavaScript has nothing like it, so they are emulated.<br>
|
|
|
|
- An interfacetype is a JS-object with some hidden properties, containing
|
|
|
|
- the GUID ($guid) and an array with the method names ($names). Here is how
|
|
|
|
- IUnknown looks like in JS:<br>
|
|
|
|
-<pre>
|
|
|
|
-{
|
|
|
|
- $module: [object Object],
|
|
|
|
- $name: "IUnknown",
|
|
|
|
- $fullname: "System.IUnknown",
|
|
|
|
- $guid: "{00000000-0000-0000-C000-000000000046}",
|
|
|
|
- $names: ["QueryInterface","_AddRef","_Release"],
|
|
|
|
- $rtti: [object Object],
|
|
|
|
- $kind: "com",
|
|
|
|
-}
|
|
|
|
-</pre>
|
|
|
|
- A class implementing interfaces has a variable <i>$intfmaps</i>, which has
|
|
|
|
- for each implemented GUID a map or delegator function. A map
|
|
|
|
- is a JS instance of the interfacetype plus a for each method name a
|
|
|
|
- function to call the class method. Here is an example map of <i>IUnknown</i> of
|
|
|
|
- <i>TInterfacedObject</i>:<br>
|
|
|
|
-<pre>
|
|
|
|
-{
|
|
|
|
- QueryInterface: function (){ return fn.apply(this.$o,arguments); },
|
|
|
|
- _AddRef: function (){ return fn.apply(this.$o,arguments); },
|
|
|
|
- _Release: function (){ return fn.apply(this.$o,arguments); },
|
|
|
|
- ...
|
|
|
|
-}
|
|
|
|
-</pre>
|
|
|
|
- When an interface is created for an object (here: a Pascal class instance),
|
|
|
|
- for example by using the <i>as</i>-operator "<i>ObjVar as IUnknown</i>",
|
|
|
|
- a JS object is created, which
|
|
|
|
- is an instance of the map object with its <i>$o</i> set to the <i>ObjVar</i>.<br>
|
|
|
|
- <br>
|
|
|
|
- Supported:
|
|
|
|
- <ul>
|
|
|
|
- <li>methods, properties, default property</li>
|
|
|
|
- <li><i>{$interfaces com|corba|default}</i><br>
|
|
|
|
- <ul>
|
|
|
|
- <li>COM is default, default ancestor is IUnknown (mode delphi: IInterface),
|
|
|
|
- managed type, i.e. automatically reference counted via _AddRef, _Release, the checks for support call QueryInterface</li>
|
|
|
|
- <li>CORBA: lightweight, no automatic reference counting,
|
|
|
|
- no default ancestor, fast support checks.</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>inheriting</li>
|
|
|
|
- <li>An interface without a GUID gets one autogenerated from its name and method names.</li>
|
|
|
|
- <li>Contrary to Delphi/FPC you can assign an interface type or var to
|
|
|
|
- the type TGuidString.</li>
|
|
|
|
- <li>a class implementing an interface must not be external</li>
|
|
|
|
- <li>a ClassType "supports" an interface, if it itself or one of its
|
|
|
|
- ancestors implements the interface.
|
|
|
|
- It does not automatically support an ancestor of the interface.</li>
|
|
|
|
- <li>method resolution, procedure IUnknown._AddRef = IncRef;</li>
|
|
|
|
- <li>delegation: property Name: interface|class read Field|Getter implements AnInterface;</li>
|
|
|
|
- <li>is-operator:</li>
|
|
|
|
- <ul>
|
|
|
|
- <li>IntfVar is IntfType - types must be releated</li>
|
|
|
|
- <li>IntfVar is ClassType - types can be unrelated, class must not be external</li>
|
|
|
|
- <li>ObjVar is IntfType - can be unrelated</li>
|
|
|
|
- </ul>
|
|
|
|
- <li>as-operator</li>
|
|
|
|
- <ul>
|
|
|
|
- <li>IntfVar as IntfType - types must be releated</li>
|
|
|
|
- <li>IntfVar as ClassType - types can be unrelated, nil returns nil,
|
|
|
|
- invalid raises EInvalidCast</li>
|
|
|
|
- <li>ObjVar as IntfType - can be unrelated, nil if not found, COM: uses _AddRef</li>
|
|
|
|
- </ul>
|
|
|
|
- <li>typecast:</li>
|
|
|
|
- <ul>
|
|
|
|
- <li>IntfType(IntfVar) - must be related</li>
|
|
|
|
- <li>ClassType(IntfVar) - can be unrelated, nil if invalid</li>
|
|
|
|
- <li>IntfType(ObjVar) - nil if not found,
|
|
|
|
- COM: if ObjVar has delegate uses _AddRef</li>
|
|
|
|
- <li>TJSObject(IntfTypeOrVar). Note that you cannot typecast directly
|
|
|
|
- to a <i>TJSObject</i> descendant. You can use <i>TJSWindow(TJSObject(IntfType))</i>.</li>
|
|
|
|
- <li>jsvalue(intfvar)</li>
|
|
|
|
- </ul>
|
|
|
|
- <li>Assign operator:</li>
|
|
|
|
- <ul>
|
|
|
|
- <li>IntfVar:=nil;</li>
|
|
|
|
- <li>IntfVar:=IntfVar2; - IntfVar2 must be same type or a descendant</li>
|
|
|
|
- <li>IntfVar:=ObjVar; - nil if unsupported</li>
|
|
|
|
- <li>jsvalue:=IntfVar;</li>
|
|
|
|
- <li>TGUIDVar:=IntfType;</li>
|
|
|
|
- <li>TGUIDVar:=IntfVar;</li>
|
|
|
|
- <li>TGUIDVar:=stringconstant;</li>
|
|
|
|
- <li>TGUIDStringVar:=IntfVar;</li>
|
|
|
|
- <li>StringVar:=GuidVar;</li>
|
|
|
|
- </ul>
|
|
|
|
- <li>Equal/Inequal operator:</li>
|
|
|
|
- <ul>
|
|
|
|
- <li>IntfVar=nil;</li>
|
|
|
|
- <li>IntfVar=IntfVar2; - must be related</li>
|
|
|
|
- <li>jsvalue=IntfVar;</li>
|
|
|
|
- <li>TGUIDVar=IntfType;</li>
|
|
|
|
- <li>TGUIDVar=IntfVar;</li>
|
|
|
|
- <li>TGUIDVar=string;</li>
|
|
|
|
- <li>TGUIDStringVar=IntfVar;</li>
|
|
|
|
- </ul>
|
|
|
|
- <li>Passing an COMIntfVar to an untyped parameter does not trigger _AddRef, _Release.</li>
|
|
|
|
- <li>Assigned(IntfVar)</li>
|
|
|
|
- <li>RTTI, typeinfo(IntfType), typeinfo(IntfVar)</li>
|
|
|
|
- </ul>
|
|
|
|
- Not yet supported: array of intferfacetype, interface as record member.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="helpers">Translating helpers</h2>
|
|
|
|
- Pas2js supports class helpers, record helpers and type helpers since 1.3.
|
|
|
|
- The extend is only virtual, the helped type is kept untouched.
|
|
|
|
- <br>
|
|
|
|
- <ul>
|
|
|
|
- <li>A <b>class helper</b> can "extend" Pascal classes and external JS classes.</li>
|
|
|
|
- <li>A <b>record helper</b> can "extend" a record type. In $mode delphi a
|
|
|
|
- record helper can extend other types as well, see <i>type helper</i></li>
|
|
|
|
- <li>A <b>type helper</b> can extend all base types like integer, string,
|
|
|
|
- char, boolean, double, currency, and user types like enumeration,
|
|
|
|
- set, range, array, class, record and interface types.
|
|
|
|
- It cannot extend helpers and procedural types.<br>
|
|
|
|
- Type helpers are enabled by default in <i>$mode delphi</i> and disabled in <i>$mode objfpc</i>.
|
|
|
|
- You can enable them with <b>{$modeswitch typehelpers}</b>.
|
|
|
|
- </li>
|
|
|
|
- <li>By default only one helper is active per type, same as in FPC/Delphi.
|
|
|
|
- If there are multiple helpers for the same type, the last helper in scope wins.<br>
|
|
|
|
- A class with ancestors can have one active helper per ancestor type, so
|
|
|
|
- multiple helpers can be active, same as FPC/Delphi.<br>
|
|
|
|
- Using <b>{$modeswitch multihelpers}</b> you can activate all helpers
|
|
|
|
- within scope.
|
|
|
|
- </li>
|
|
|
|
- <li>Nested helpers (e.g. <i>TDemo.TSub.THelper</i>) are elevated.
|
|
|
|
- Visibility is ignored. Same as FPC/Delphi.</li>
|
|
|
|
- <li>Helpers cannot be forward defined (e.g. no <i>THelper = helper;</i>).</li>
|
|
|
|
- <li>Helpers must not have fields.</li>
|
|
|
|
- <li><b>Class Var, Const, Type</b></li>
|
|
|
|
- <li><b>Visibility</b> : <i>strict private .. published</i></li>
|
|
|
|
- <li><b>Function, procedure</b>:
|
|
|
|
- In class and record helpers <i>Self</i> is the class/record instance. For other
|
|
|
|
- types Self is a reference to the passed value.
|
|
|
|
- </li>
|
|
|
|
- <li><b>Class function, class procedure</b>: Helpers for Pascal classes/records can
|
|
|
|
- add <i>static</i> and non static class functions. Helpers for external classes
|
|
|
|
- and other types can only add static class functions.</li>
|
|
|
|
- <li><b>Constructor</b>. Not for external classes. Works similar to
|
|
|
|
- construcors, i.e. <i>THelpedClass.Create</i> creates a new instance, while
|
|
|
|
- <i>AnObj.Create</i> calls the constructor function as normal method. Note that
|
|
|
|
- Delphi does not allow calling helper construcors as normal method.</li>
|
|
|
|
- <li>no destructor</li>
|
|
|
|
- <li><b>Property</b> : getters/setters can refer to members of the helper, its
|
|
|
|
- ancestors and the helped class/record.</li>
|
|
|
|
- <li><b>Class property</b> : getter can be static or non static. Delphi/FPC only allows static.</li>
|
|
|
|
- <li><b>Ancestors</b> : Helpers can have an ancestor helper, but they
|
|
|
|
- do not have a shared root class, especially not <i>TObject</i>.</li>
|
|
|
|
- <li><b>no virtual, abstract, override</b>. Delphi allows them, but 10.3 crashes when calling.</li>
|
|
|
|
- <li><b>inherited</b> :
|
|
|
|
- <i>inherited</i> inside a method of a class/record calls helper of ancestor.<br>
|
|
|
|
- <i>inherited</i> inside a helper depends on the $mode:
|
|
|
|
- <ul>
|
|
|
|
- <li> <i>$mode objfpc</i> : <i>inherited;</i> and <i>inherited Name(args);</i>
|
|
|
|
- work the same and searches first in HelperForType, then in ancestor(s).</li>
|
|
|
|
- <li><i>$mode delphi: inherited;</i> : skip ancestors and HelperForType,
|
|
|
|
- searches first in helper(s) of ancestor of HelperForType.</li>
|
|
|
|
- <li><i>$mode delphi: inherited name(args);</i> :
|
|
|
|
- same as $mode objfpc first searches in HelperForType, then Ancestor(s)</li>
|
|
|
|
- </ul>
|
|
|
|
- In any case if <i>inherited;</i> has no ancestor to call, it is silently ignored,
|
|
|
|
- while <i>inherited Name;</i> gives an error.
|
|
|
|
- </li>
|
|
|
|
- <li><b>RTTI</b>: <i>typeinfo(somehelper)</i> returns a pointer to <i>TTypeInfoHelper</i> with <i>Kind tkHelper</i>.</li>
|
|
|
|
- <li>There are some special cases when using a <b>type helper</b> function/procedure on a value:
|
|
|
|
- <ul>
|
|
|
|
- <li><i>function result</i> : using a temporary variable</li>
|
|
|
|
- <li><i>const, const argument</i> : When helper function tries to assign a value,
|
|
|
|
- pas2js raises a EPropReadOnly exception. FPC/Delphi use a temporary variable allowing the write. </li>
|
|
|
|
- <li><i>property</i> : uses only the getter, ignoring the setter.
|
|
|
|
- This breaks OOP, as it allows to change fields without calling the setter.
|
|
|
|
- This is FPC/Delphi compatible.</li>
|
|
|
|
- <li><i>with value do ;</i> : uses a temporary variable. Delphi/FPC do not support it.</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>A method with <i>external name</i> modifier is treated as an external
|
|
|
|
- method of the helped type.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="attributes">Translating attributes</h2>
|
|
|
|
- Attributes are stored in the TTypeInfo objects as streams stored in an array.
|
|
|
|
- See the function <i>GetRTTIAttributes</i> in unit <i>TypInfo</i> for details.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="tryfinally">Translating try..finally</h2>
|
|
|
|
- JavaScript has the same, so it translates straight forward.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="tryexcept">Translating try..except</h2>
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-Uses SysUtils, Math, JS;
|
|
|
|
-Function DoIt(n: integer): double;
|
|
|
|
-Implementation
|
|
|
|
-Function DoIt(n: integer): double;
|
|
|
|
-var E: Exception;
|
|
|
|
-Begin
|
|
|
|
- try
|
|
|
|
- Result:=double(7.0)/n;
|
|
|
|
- if not IsFinite(Result) then
|
|
|
|
- if n=0 then
|
|
|
|
- raise EZeroDivide.Create
|
|
|
|
- else
|
|
|
|
- raise EOverflow.Create;
|
|
|
|
- except
|
|
|
|
- on EZeroDivide do Result:=0.0;
|
|
|
|
- on E2: EOverflow do Result:=0.0;
|
|
|
|
- else
|
|
|
|
- raise EAbort.Create('Something other: '+String(JS.JSExceptObject));
|
|
|
|
- end;
|
|
|
|
-End;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System","SysUtils"],
|
|
|
|
-function(){
|
|
|
|
- this.DoIt=function(n){
|
|
|
|
- Result = 0;
|
|
|
|
- var E = null;
|
|
|
|
- try{
|
|
|
|
- Result = 7.0 / n;
|
|
|
|
- if (!IsFinite(Result)){
|
|
|
|
- if (n==0){
|
|
|
|
- throw pas.SysUtils.EZeroDivide.$create("Create");
|
|
|
|
- } else {
|
|
|
|
- throw pas.SysUtils.EOverflow.$create("Create");
|
|
|
|
- };
|
|
|
|
- };
|
|
|
|
- }catch($e){
|
|
|
|
- if (pas.SysUtils.EZeroDivide.isPrototypeOf($e)){
|
|
|
|
- Result = 0.0;
|
|
|
|
- } else if (pas.SysUtils.EOverflow.isPrototypeOf($e)){
|
|
|
|
- var E2 = $e;
|
|
|
|
- Result = 0.0;
|
|
|
|
- } else {
|
|
|
|
- throw pas.SysUtils.EAbort.$create("Create",["Something other: "+(""+$e)]);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Division by zero does not raise an exception in JavaScript. Instead it results in Infinity, except for 0/0 which results in NaN.</li>
|
|
|
|
- <li>There is no ExceptObject in SysUtils.</li>
|
|
|
|
- <li>When calling external functions keep in mind that JS allows to
|
|
|
|
- throw (raise) any value, often a string.<br>
|
|
|
|
- You can access the current except value via JSExceptValue in unit JS.<br>
|
|
|
|
- Note that this is only valid inside the catch-block. The compiler will not warn,
|
|
|
|
- if you use it outside.</li>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="enumerators">Translating enumerators</h2>
|
|
|
|
- The for..in..do supports enumerating:
|
|
|
|
- <ul>
|
|
|
|
- <li>ordinal types like char, boolean,
|
|
|
|
- byte, ..., longword, enums, custom ranges are translated to a for loop.</li>
|
|
|
|
- <li>set types are translated to a for loop, while const sets and set variables are enumerated via a for(...in...) loop.</li>
|
|
|
|
- <li>string and array variables are enumerated via for loops.</li>
|
|
|
|
- <li>for aString in ArrayOfString do ...</li>
|
|
|
|
- <li><i>for key in jsvalue do</i> translates to <i>for (key in jsvalue){}</i></li>
|
|
|
|
- <li><i>for key in ExternalClass do</i><br>
|
|
|
|
- <ul>
|
|
|
|
- <li>If the externalclass has a ''length'' and a matching default property
|
|
|
|
- it uses the enumeration of an array. For example
|
|
|
|
- <i>for value in TJSArray do</i> enumerates the values of the array, not the index.
|
|
|
|
- It checks if the array is nil.</li>
|
|
|
|
- <li>Otherwise it translates to <i>for (key in externalclass){}</i>,
|
|
|
|
- which enumerates the keys (property names) of the JS object.</li>
|
|
|
|
- </ul>
|
|
|
|
- </ul>
|
|
|
|
- The class GetEnumerator function is translated like this:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Unit MyModule;
|
|
|
|
-Interface
|
|
|
|
-
|
|
|
|
-uses Classes;
|
|
|
|
-
|
|
|
|
-procedure DoIt(List: TList);
|
|
|
|
-
|
|
|
|
-Implementation
|
|
|
|
-
|
|
|
|
-procedure DoIt(List: TList);
|
|
|
|
-var
|
|
|
|
- Item: Pointer;
|
|
|
|
-begin
|
|
|
|
- for Item in List do
|
|
|
|
- if Item<>nil then ;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("MyModule",
|
|
|
|
-["System","Classes"],
|
|
|
|
-function(){
|
|
|
|
- this.DoIt=function(List){
|
|
|
|
- var Item = null;
|
|
|
|
- var $in1 = List;
|
|
|
|
- try {
|
|
|
|
- while ($in1.MoveNext()) {
|
|
|
|
- Item = $in1.GetCurrent();
|
|
|
|
- if (Item !== null) ;
|
|
|
|
- }
|
|
|
|
- } finally {
|
|
|
|
- $in1 = rtl.freeLoc($in1)
|
|
|
|
- };
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Not supported: operator Enumerator, member modifier enumerator (i.e. custom Current and MoveNext)</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="functiontype">Translating function types</h2>
|
|
|
|
- JavaScript functions work like Delphi's "reference to function", which
|
|
|
|
- means like closures, capturing outer variables.
|
|
|
|
- Assigning a normal function or nested function to a procedural variable is
|
|
|
|
- translated to a simple assignment.
|
|
|
|
- A Pascal method needs <b>this</b> to be the class or class instance.<br>
|
|
|
|
- Note that <i>bind</i> cannot be used, because it does not support the <i>equal</i> operator.
|
|
|
|
- Instead a wrapper is created:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-type
|
|
|
|
- TMyMethod = procedure(n: integer) of object;
|
|
|
|
- TBird = class
|
|
|
|
- procedure DoIt(n: integer); virtual; abstract;
|
|
|
|
- end;
|
|
|
|
- TMyProc = procedure(n: integer);
|
|
|
|
-procedure DoSome(n: integer);
|
|
|
|
-begin
|
|
|
|
-end;
|
|
|
|
-var
|
|
|
|
- m: TMyMethod;
|
|
|
|
- Bird: TBird;
|
|
|
|
- p: TMyProc;
|
|
|
|
-Begin
|
|
|
|
- m:[email protected];
|
|
|
|
- m(3);
|
|
|
|
- p:=@DoSome;
|
|
|
|
- p(4);
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System","UnitA"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- rtl.createClass($mod,"TBird",pas.System.TObject,function(){
|
|
|
|
- this.DoIt = function (n) {
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- this.DoSome = function (n) {
|
|
|
|
- };
|
|
|
|
- this.m = null;
|
|
|
|
- this.Bird = null;
|
|
|
|
- this.p = null;
|
|
|
|
- $mod.$main = function() {
|
|
|
|
- $mod.m = rtl.createCallback($mod.Bird,"DoIt");
|
|
|
|
- $mod.m(3);
|
|
|
|
- $mod.p = $mod.DoSome;
|
|
|
|
- $mod.p(4);
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-
|
|
|
|
-rtl = {
|
|
|
|
- ...
|
|
|
|
- createCallback: function(scope, fn){
|
|
|
|
- var cb;
|
|
|
|
- if (typeof(fn)==='string'){
|
|
|
|
- cb = function(){
|
|
|
|
- return scope[fn].apply(scope,arguments);
|
|
|
|
- };
|
|
|
|
- } else {
|
|
|
|
- cb = function(){
|
|
|
|
- return fn.apply(scope,arguments);
|
|
|
|
- };
|
|
|
|
- };
|
|
|
|
- cb.scope = scope;
|
|
|
|
- cb.fn = fn;
|
|
|
|
- return cb;
|
|
|
|
- },
|
|
|
|
- ...
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>You can assign a nested procedure to procedure variable.
|
|
|
|
- You don't need and you must not add the FPC "<i>is nested</i>" modifier.</li>
|
|
|
|
- <li>In pas2js a procedural typed declared as <i>'reference to'</i> accepts procedures,
|
|
|
|
- local procedures and methods. Delphi only supports capturing procedures and methods.
|
|
|
|
- FPC 3.0.4 does not support reference-to.</li>
|
|
|
|
- <li>In pas2js the calling convention <i>safecall</i> has a special meaning:<br>
|
|
|
|
- Assigning a procedure/method, uses <i>rtl.createSafeCallback</i> instead of
|
|
|
|
- <i>createCallback</i>, enclosing a call in a <i>try..catch</i> block. When
|
|
|
|
- an exception is thrown by JS, it is caught and delegated to
|
|
|
|
- <i>rtl.handleUncaughtException(err)</i>.<br>
|
|
|
|
- For example:<br>
|
|
|
|
- <i>aButtonElement.OnClick:=@DoClick;</i> uses <i>rtl.createSafeCallback</i><br>
|
|
|
|
- <i>aButtonElement.OnClick:=SomeElement.OnClick;</i> does not.<br>
|
|
|
|
- </li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="anonymousfunctions">Translating anonymous functions</h2>
|
|
|
|
- Anonymous functions are supported since pas2js 1.1.<br>
|
|
|
|
- Note that in pas2js local procedures are closures as well. See below.<br>
|
|
|
|
- For pas2js 1.0 the next best thing are local procedures. For example:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Delphi</th>
|
|
|
|
- <th>Pas2js</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-type
|
|
|
|
- TAdder = reference to function(n: integer): integer;
|
|
|
|
-
|
|
|
|
-function CreateAdder(a: integer): TAdder;
|
|
|
|
-begin
|
|
|
|
- Result:=function(b: integer)
|
|
|
|
- begin
|
|
|
|
- Result:=a+b;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-var
|
|
|
|
- Adder: TAdder;
|
|
|
|
-Begin
|
|
|
|
- Adder:=CreateAdder(3);
|
|
|
|
- writeln(Adder(5)); // gives 8
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-type
|
|
|
|
- TAdder = reference to function(n: integer): integer;
|
|
|
|
-
|
|
|
|
-function CreateAdder(a: integer): TAdder;
|
|
|
|
- function Add(b: integer): integer;
|
|
|
|
- begin
|
|
|
|
- Result:=a+b;
|
|
|
|
- end;
|
|
|
|
-begin
|
|
|
|
- Result:=@Add;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-var
|
|
|
|
- Adder: TAdder;
|
|
|
|
-Begin
|
|
|
|
- Adder:=CreateAdder(3);
|
|
|
|
- writeln(Adder(5)); // gives 8
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="absolute">Translating var modifier absolute</h2>
|
|
|
|
- The absolute modifier works as an alias. That means it works FPC/Delphi
|
|
|
|
- compatible for related types like Pointer and TObject, and works
|
|
|
|
- incompatible for unrelated types like longword and record (e.g. <i>var r: TPoint absolute MyLongInt</i>).<br>
|
|
|
|
- The modifier is currently only supported for local variables.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="assert">Translating assert()</h2>
|
|
|
|
- The Assert(boolean[,string]) function is translated to <i>if(bool) throw x</i>.
|
|
|
|
- If unit sysutils is used, it creates an EAssertFailed exception.<br>
|
|
|
|
- Otherwise it throws a string.<br>
|
|
|
|
- <ul>
|
|
|
|
- <li>Command line enable with -Sa, disable with -Sa-</li>
|
|
|
|
- <li>In code enable with <i>{$C+}</i> or <i>{$Assertions on}</i>,
|
|
|
|
- disable with <i>{$C-}</i> or <i>{$Assertions off}</i></li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="dispatch">Dispatch messages</h2>
|
|
|
|
- The procedure modifier <b>message</b> and the <b>Dispatch</b> method works
|
|
|
|
- similar to FPC/Delphi, as it expects a record of a specific format and
|
|
|
|
- <b><i>TObject.Dispatch</i></b> calls the corresponding method with that
|
|
|
|
- message number or string.<br>
|
|
|
|
- The procedure modifier <i>message <integer></i> adds an entry to
|
|
|
|
- hidden <i>YourClass.$msgint</i> object, while the modifier
|
|
|
|
- <i>message <string></i> adds an entry to the hidden
|
|
|
|
- <i>YourClass.$msgstr</i> object.<br>
|
|
|
|
- Two new directives <b><i>{$DispatchField fieldname}</i></b> and
|
|
|
|
- <b><i>{$DispatchStrField fieldname}</i></b> were added. Insert these
|
|
|
|
- directives in front of your class declaration to let the compiler check all
|
|
|
|
- methods with message modifiers of this class and its descendants whether they
|
|
|
|
- pass a record with the required field. For example:
|
|
|
|
-<pre>
|
|
|
|
- {$DispatchField Msg} // enable checking message methods for record field name "Msg"
|
|
|
|
- {$DispatchStrField MsgStr}
|
|
|
|
- TObject = class
|
|
|
|
- procedure Dispatch(var aMessage); virtual;
|
|
|
|
- procedure DispatchStr(var aMessage); virtual;
|
|
|
|
- end;
|
|
|
|
- TMouseDownMsg = record
|
|
|
|
- Id: integer; // Id instead of Msg, works in FPC, but not in pas2js
|
|
|
|
- x,y: integer;
|
|
|
|
- end;
|
|
|
|
- TMouseUpMsg = record
|
|
|
|
- MsgStr: string;
|
|
|
|
- X,Y: integer;
|
|
|
|
- end;
|
|
|
|
- TWinControl = class
|
|
|
|
- procedure MouseDownMsg(var Msg: TMouseDownMsg); message 3; // warning: Dispatch requires record field Msg
|
|
|
|
- procedure MouseUpMsg(var Msg: TMouseUpMsg); message 'up'; // ok, record with string field name MsgStr
|
|
|
|
- end;
|
|
|
|
-</pre>
|
|
|
|
- Note that descendant classes can override the <i>$DispatchField</i> or
|
|
|
|
- disable the check using <i>{$DispatchField -}</i>.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="calljavascript">Calling JavaScript from Pascal</h2>
|
|
|
|
- Pas2js allows to write low level functions and/or access a JavaScript library
|
|
|
|
- with the following possibilities:
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="asm">The asm block</h2>
|
|
|
|
- The asm block is pure JavaScript, that is copied directly into the generated .js file.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-var
|
|
|
|
- s: string;
|
|
|
|
-Begin
|
|
|
|
- s = 'Hello World!';
|
|
|
|
- Asm
|
|
|
|
- console.log(s);
|
|
|
|
- End;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.s = '';
|
|
|
|
- $mod.$main = function(){
|
|
|
|
- $mod.s = "Hello World!";
|
|
|
|
- console.log(s);
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
-
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>The block is indented to produce more readable JS code.
|
|
|
|
- All lines are indented or unindented the same amount, i.e. sub indentation is kept.</li>
|
|
|
|
- <li>The compiler does neither parse, nor check the syntax of the JS.</li>
|
|
|
|
- <li>The compiler does not know what Pascal identifiers are used by the
|
|
|
|
- asm-block and might remove them, if no Pascal code is using them.
|
|
|
|
- To make sure that an identifier is kept, add some dummy code like
|
|
|
|
- <i>if MyVar=0 then;</i></li>
|
|
|
|
- <li>Accessing an interface, program or library identifier:<br>
|
|
|
|
- <ul>
|
|
|
|
- <li>From inside the module you can use <i>$mod.Identifier</i>.</li>
|
|
|
|
- <li>Otherwise use the fully qualified path <i>pas.Unitname.Identifier</i>.</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>Accessing an implementation identifier:<br>
|
|
|
|
- <ul>
|
|
|
|
- <li>From inside the unit you can use <i>$impl.Identifier</i>.</li>
|
|
|
|
- <li>Otherwise use the path <i>pas.Unitname.$impl.Identifier</i>.</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>Accessing a class instance member (field, procedure, function,
|
|
|
|
- constructor, destructor) from a method of the class: use <i>this.Identifier</i>.
|
|
|
|
- Inside a nested function of a method you use the <i>Self.Identifier</i>.
|
|
|
|
- </li>
|
|
|
|
- <li>Accessing a class member (class var, class procedure, class function)
|
|
|
|
- from a method of the class: for writing use <i>this.$class.Identifier</i>,
|
|
|
|
- for reading you can omit the <i>$class</i>.</li>
|
|
|
|
- <li>Accessing a class member (class var, class procedure, class function)
|
|
|
|
- from a class method of the class: use <i>this.Identifier</i>.</li>
|
|
|
|
- <li>Access to Properties must use the getter/setter.</li>
|
|
|
|
- <li>When calling a Pascal method, make sure the <b>this</b> is correct:
|
|
|
|
- <ul>
|
|
|
|
- <li>A class method (e.g. <i>class function</i>, <i>class procedure</i>)
|
|
|
|
- needs the class as <i>this</i>.<br>
|
|
|
|
- <b>Wrong</b>: <i>aCar.DoIt(params,...)</i><br>
|
|
|
|
- <b>Correct</b>: <i>aCar.$class.DoIt(params,...)</i><br>
|
|
|
|
- </li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>Calling a Pascal function from a HTML/DOM-element:
|
|
|
|
- For example to call a function when user clicks a DOM element you can
|
|
|
|
- assign a function to the <i>onclick</i> property. This will call
|
|
|
|
- the function with <i>this</i> set to the DOM element.<br>
|
|
|
|
- Pascal methods needs a wrapper to set <i>this</i> to the
|
|
|
|
- instance. Examples:
|
|
|
|
- <ul>
|
|
|
|
- <li>An unit function: <i>DOMElement.onclick = $mod.DoIt;</i></li>
|
|
|
|
- <li>An implementation function: <i>DOMElement.onclick = $impl.DoIt;</i>.</li>
|
|
|
|
- <li>A method: <i>DOMElement.onclick = this.DoIt.bind(this);</i></li>
|
|
|
|
- <li>A class function/procedure: <i>DOMElement.onclick = this.DoIt.bind(this.$class);</i></li>
|
|
|
|
- <li>A nested function: <i>DOMElement.onclick = DoIt;</i>.</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- </li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="assembler">The procedure modifier assembler</h2>
|
|
|
|
- You can write pure JavaScript functions like this:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-
|
|
|
|
-Procedure Log(const s: string); assembler;
|
|
|
|
-Asm
|
|
|
|
- console.log(s);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-Begin
|
|
|
|
- Log('Hello World!');
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.Log = function(s){
|
|
|
|
- console.log(s);
|
|
|
|
- };
|
|
|
|
- $mod.$main = function(){
|
|
|
|
- $mod.Log("Hello World!");
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
-
|
|
|
|
- See also <a href="#asm">asm</a>.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="externalproc">The procedure modifier external</h2>
|
|
|
|
- The procedure modifier <i>external</i> requires a string constant and tells the
|
|
|
|
- compiler to replace a reference with this string value. The value is not
|
|
|
|
- checked for JS syntax.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-Procedure ConsoleLog(const s: string); external name 'console.log';
|
|
|
|
-// Note: an external procedure has no begin..end block
|
|
|
|
-Begin
|
|
|
|
- ConsoleLog('Hello World!');
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- $mod.$main = function(){
|
|
|
|
- console.log("Hello World!");
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="varargs">The procedure modifier varargs</h2>
|
|
|
|
- Appending the <b>varargs</b> modifier to a procedure allows to pass arbitrary
|
|
|
|
- more parameters to a function. By default these parameters are untyped, i.e.
|
|
|
|
- any type fits. Alternatively you can use <b>varargs of aType</b> to allow
|
|
|
|
- only specific types.<br>
|
|
|
|
- To access these arguments use
|
|
|
|
- either <i>JSArguments</i> from unit JS or an <i>asm..end</i> block.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-uses JS;
|
|
|
|
-function Sum(b: boolean): longint; varargs;
|
|
|
|
-var i: longint;
|
|
|
|
-begin
|
|
|
|
- if b then
|
|
|
|
- asm
|
|
|
|
- for (var i=0; i<arguments.length; i++) Result+=arguments[i];
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- for i:=0 to JSArguments.length-1 do
|
|
|
|
- Result:=Result+longint(JSArguments[i]);
|
|
|
|
-end;
|
|
|
|
-var
|
|
|
|
- i: integer;
|
|
|
|
-Begin
|
|
|
|
- i:=Sum(true,2,4,6); // i=12
|
|
|
|
- i:=Sum(false,2,4,6); // i=12
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System","JS"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.Sum = function(b){
|
|
|
|
- var Result = 0;
|
|
|
|
- var i = 0;
|
|
|
|
- if (b){
|
|
|
|
- for (var i=0; i<arguments.length; i++) Result+=arguments[i];
|
|
|
|
- } else {
|
|
|
|
- for (var $l1 = 1, $le2 = argumens.length; $l1 <= $le2; $l1++){
|
|
|
|
- $i = $l1;
|
|
|
|
- Result = Result + arguments[i];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
- this.i = 0;
|
|
|
|
- $mod.$main = function(){
|
|
|
|
- $mod.i = $mod.Sum(true,2,4,6);
|
|
|
|
- $mod.i = $mod.Sum(false,2,4,6);
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- The above example defines a function <i>Sum</i>, that requires the first parameter to
|
|
|
|
- be a boolean and then an arbitrary number of parameters. The compiler does not
|
|
|
|
- type check the other parameters, so you can pass anything readable.
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="externalvar">The var modifier external</h2>
|
|
|
|
- The var modifier <i>external</i> allows to use a JavaScript variable or constant.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-var
|
|
|
|
- EulersNumber: Double; external name 'Math.E';
|
|
|
|
- d: double;
|
|
|
|
-Begin
|
|
|
|
- d:=EulersNumber;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- this.d = 0.0;
|
|
|
|
- $mod.$main = function(){
|
|
|
|
- $mod.d = Math.E;
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="externalmembers">The external modifier of class members</h2>
|
|
|
|
- The method modifier <i>external</i> works as the procedure modifier, except
|
|
|
|
- it uses the scope of the class or instance.<br>
|
|
|
|
- The field modifier <i>external</i> works as the var modifier, except
|
|
|
|
- it uses the scope of the class or instance.<br>
|
|
|
|
- Requires the modeswitch <b>externalclass</b>.
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-{$modeswitch externalclass}
|
|
|
|
-type
|
|
|
|
- TWrapper = class
|
|
|
|
- private
|
|
|
|
- // let's assume this object has the properties "$Handle", "$id", and "0"
|
|
|
|
- public
|
|
|
|
- Id: NativeInt; external name '$Id';
|
|
|
|
- x: NativeInt; external name '[0]';
|
|
|
|
- y: NativeInt; external name '["A B"]';
|
|
|
|
- function GetState(typ: longint): NativeInt; external name '$Handle.GetState';
|
|
|
|
- procedure DoIt;
|
|
|
|
- end;
|
|
|
|
-procedure TWrapper.DoIt;
|
|
|
|
-begin
|
|
|
|
- Id := GetState(4);
|
|
|
|
-end;
|
|
|
|
-var
|
|
|
|
- W: TWrapper;
|
|
|
|
-Begin
|
|
|
|
- W.Id := 2;
|
|
|
|
- W.x := 3;
|
|
|
|
- W.y := 4;
|
|
|
|
- W.GetState(5);
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",
|
|
|
|
-["System"],
|
|
|
|
-function(){
|
|
|
|
- var $mod = this;
|
|
|
|
- rtl.createClass($mod, "TWrapper", pas.System.TObject, function () {
|
|
|
|
- this.DoIt = function(){
|
|
|
|
- this.$Id = this.$Handle.GetState(4);
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- this.W = null;
|
|
|
|
- $mod.$main = function(){
|
|
|
|
- $mod.W.$Id = 2;
|
|
|
|
- $mod.W[0] = 3;
|
|
|
|
- $mod.W["A B"] = 4;
|
|
|
|
- $mod.W.$Handle.GetState(5);
|
|
|
|
- };
|
|
|
|
-},
|
|
|
|
-[]);
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- <ul>
|
|
|
|
- <li>Non identifiers like "0" or "A B" must be enclosed in brackets.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="externalclass">External classes</h2>
|
|
|
|
- pas2js introduces a new class modifier "<i>external name</i>", which makes
|
|
|
|
- the whole class external.
|
|
|
|
- External classes allow to easily declare Pascal wrappers for JavaScript
|
|
|
|
- objects and function objects.<br>
|
|
|
|
- They need the modeswitch <b>externalclass</b> in front of the class.<br>
|
|
|
|
- An external class is not a TObject and has none of its methods.<br>
|
|
|
|
- All members are external. If you omit the <i>external</i> modifier the
|
|
|
|
- external name is the member name. Keep in mind that JS is case sensitive.<br>
|
|
|
|
- Properties work the same as with Pascal classes, i.e. are replaced by Getter/Setter.<br>
|
|
|
|
- Destructors are not allowed.<br>
|
|
|
|
- Constructors are supported in four ways:
|
|
|
|
- <ul>
|
|
|
|
- <li><i>constructor New</i> is translated to <i>new ExtClass(params)</i>, and for nested external class: <i>new ExtParentClass.ExtClass(Params)</i></li>
|
|
|
|
- <li><i>constructor New; external name ''GlobalFunc''</i> is translated to <i>new GlobalFunc(params)</i>.</li>
|
|
|
|
- <li><i>constructor SomeName; external name </i>'{}'</i> is translated to <i>{}</i>.</li>
|
|
|
|
- <li>Otherwise it is translated to <i>new ExtClass.FuncName(params)</i>, and for nested external class: <i>new ExtParentClass.ExtClass.FuncName(params)</i>.</li>
|
|
|
|
- </ul>
|
|
|
|
-
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-{$modeswitch externalclass}
|
|
|
|
-type
|
|
|
|
- TJSDate = class external name 'Date'
|
|
|
|
- private
|
|
|
|
- function getYear: NativeInt;
|
|
|
|
- procedure setYear(const AValue: NativeInt);
|
|
|
|
- public
|
|
|
|
- constructor New;
|
|
|
|
- constructor New(const MilliSecsSince1970: NativeInt);
|
|
|
|
- class function now: NativeInt;
|
|
|
|
- property Year: NativeInt read getYear write setYear;
|
|
|
|
- end;
|
|
|
|
-var
|
|
|
|
- d: TJSDate;
|
|
|
|
-Begin
|
|
|
|
- d:=TJSDate.New;
|
|
|
|
- d.Year:=d.Year+1;
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",["System"],function () {
|
|
|
|
- var $mod = this;
|
|
|
|
- this.d = null;
|
|
|
|
- $mod.$main = function () {
|
|
|
|
- $mod.d = new Date();
|
|
|
|
- $mod.d.setYear($mod.d.getYear() + 1);
|
|
|
|
- };
|
|
|
|
-});
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Any class instance can be type casted to any root class.</li>
|
|
|
|
- <li>A Pascal class can descend from an external class.</li>
|
|
|
|
- <li>You can define a class-of external class and the <b>is</b> and <b>as</b>
|
|
|
|
- operators work similar.</li>
|
|
|
|
- <li>Class variables work as in JavaScript. That means, each descendant and each
|
|
|
|
- instance can have its own value. For example <i>TExtA.Value</i> might be
|
|
|
|
- different from <i>InstanceExtA.Value</i>. Setting <i>InstanceExtA.Value</i>
|
|
|
|
- does not change <i>TExtA.Value</i>.</li>
|
|
|
|
- <li>Const with an expression are replaced by the expression.</li>
|
|
|
|
- <li>Const without an expression are treated as a readonly variable.</li>
|
|
|
|
- <li>Class functions and class procedures are allowed, but can only be called via the class, not via an instance.<br>
|
|
|
|
- For example you can call the class function <i>TJSString.fromCharCode()</i>, but you cannot
|
|
|
|
- call <i>aJSString.fromCharCode()</i>.</li>
|
|
|
|
- <li>An external class can descend from another external class.</li>
|
|
|
|
- <li>Since class types are JS objects it is possible to typecast a class type
|
|
|
|
- to the JS Object, e.g. <i>TJSObject(TObject)</i>.
|
|
|
|
- Note that you cannot typecast directly to a <i>TJSObject</i> descendant
|
|
|
|
- in $mode objfpc. You can use <i>TJSWindow(TJSObject(ExtClassInstance))</i>.</li>
|
|
|
|
- <li>You can typecast function addresses and function references to JS
|
|
|
|
- function, e.g. <i>TJSFunction(@SomeProc)</i>, <i>TJSFunction(OnClick)</i>.
|
|
|
|
- Keep in mind that typecasting a method address creates a function wrapper
|
|
|
|
- to bind the Self argument, except when typecasting to <i>TJSFunction</i>
|
|
|
|
- (pas2js 1.5+).</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="externalclassancestor">External class as ancestor</h2>
|
|
|
|
- A Pascal class can descend from an external class - a JS object or function.<br>
|
|
|
|
- The methods <i>AfterConstruction</i> and <i>BeforeDestruction</i>
|
|
|
|
- are called if they exist.<br>
|
|
|
|
- New instances of a JS Object descendant are created by default with <i>Object.create(ancestorclass)</i>.<br>
|
|
|
|
- New instances of a JS Function descendant are created by default with <i>new DescendantFunc()</i>.<br>
|
|
|
|
- You can override this, by providing a<br>
|
|
|
|
- <b>class function NewInstance(fnname: string; const paramsarray): TPasClass; virtual;</b>.
|
|
|
|
- This method is called to create a new instance and before calling the constructor.
|
|
|
|
- The name is arbitrary, but the function must be the first non private,
|
|
|
|
- non external, virtual class function with the class as result type.<br>
|
|
|
|
-
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>
|
|
|
|
-// Example for descending a Pascal class from a JS Object
|
|
|
|
-Program MyModule;
|
|
|
|
-{$modeswitch externalclass}
|
|
|
|
-type
|
|
|
|
- TExtA = class external name 'ExtA'
|
|
|
|
- end;
|
|
|
|
- TMyB = class(TExtA)
|
|
|
|
- protected
|
|
|
|
- // optional: override default allocation
|
|
|
|
- class function NewInstance(fnname: string; const paramarray): TMyB; virtual;
|
|
|
|
- end;
|
|
|
|
-class function TMyB.NewInstance(fnname: string; const paramarray): TMyB;
|
|
|
|
-Begin
|
|
|
|
- asm
|
|
|
|
- Result = Object.create(ExtA); // that is what the rtl does
|
|
|
|
- end;
|
|
|
|
-End;
|
|
|
|
-
|
|
|
|
-Begin
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",["System"],function () {
|
|
|
|
- var $mod = this;
|
|
|
|
- rtl.createClassExt($mod, "TMyB", ExtA, "NewInstance", function () {
|
|
|
|
- this.$init = function () {
|
|
|
|
- };
|
|
|
|
- this.$final = function () {
|
|
|
|
- };
|
|
|
|
- this.NewInstance = function (fnname, paramarray) {
|
|
|
|
- var Result = null;
|
|
|
|
- Result = Object.create(ExtA);
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- $mod.$main = function () {
|
|
|
|
- };
|
|
|
|
-});
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>
|
|
|
|
-// Example for descending a Pascal class from a JS Function
|
|
|
|
-Program MyModule;
|
|
|
|
-{$modeswitch externalclass}
|
|
|
|
-uses JS;
|
|
|
|
-type
|
|
|
|
- TExternalFunc = class external name 'ExternalFunc'(TJSFunction)
|
|
|
|
- constructor New(a: word);
|
|
|
|
- end;
|
|
|
|
- TMyFunc = class(TExternalFunc)
|
|
|
|
- constructor Create(b: word);
|
|
|
|
- end;
|
|
|
|
-constructor TMyFunc.Create(b: word);
|
|
|
|
-Begin
|
|
|
|
- inherited New(b+1); // optional: call inherited constructor function
|
|
|
|
-End;
|
|
|
|
-
|
|
|
|
-var
|
|
|
|
- f: TMyFunc;
|
|
|
|
-Begin
|
|
|
|
- f:=TMyFunc.Create(3);
|
|
|
|
- writeln(jsInstanceOf(f,TExternalFunc)); // writes true, instanceof operator works as expected
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",["System","js"],function () {
|
|
|
|
- var $mod = this;
|
|
|
|
- rtl.createClassExt($mod, "TMyFunc", ExternalFunc, "", function () {
|
|
|
|
- this.$init = function () {
|
|
|
|
- };
|
|
|
|
- this.$final = function () {
|
|
|
|
- };
|
|
|
|
- this.Create$2 = function (b) {
|
|
|
|
- this.$ancestorfunc(b+1);
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- this.f = null;
|
|
|
|
- $mod.$main = function () {
|
|
|
|
- f = $mod.TMyFunc.$create("Create$2",[3]);
|
|
|
|
- pas.System.Writeln(pas.JS.jsInstanceOf(f,ExternalFunc));
|
|
|
|
- };
|
|
|
|
-});
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="jsvalue">The JSValue type</h2>
|
|
|
|
- Pas2js introduces a new type <b>JSValue</b>, which works similar to a JS variable.
|
|
|
|
- You can assign almost any value to it and it can be type casted to many types.
|
|
|
|
- JSValue is useful for JS wrappers, when a variable can have multiple types.
|
|
|
|
- And it can be used for containers storing arbitrary data, e.g. a list of JSValue.<br>
|
|
|
|
- Key features:<br>
|
|
|
|
- <ul>
|
|
|
|
- <li>A JSValue variable initial value is undefined.</li>
|
|
|
|
- <li>Operators: =, <></li>
|
|
|
|
- <li>type casting a <i>JSValue</i> to ...
|
|
|
|
- <ul>
|
|
|
|
- <li><i>Integer: Math.floor(aJSValue)</i> Note: may return <i>NaN</i></li>
|
|
|
|
- <li><i>Boolean: !(aJSValue == false)</i> Note: works for numbers too, <i>0==false</i></li>
|
|
|
|
- <li><i>Double: rtl.getNumber(aJSValue)</i> Note: <i>typeof(n)=="number"?n:NaN;</i></li>
|
|
|
|
- <li><i>String: ""+aJSValue</i></li>
|
|
|
|
- <li><i>Char: rtl.getChar(aJSValue)</i> Note: <i>((typeof(c)!="string") && (c.length==1)) ? c : ""</i></li>
|
|
|
|
- <li>class instance or class-of: <i>rtl.getObject()</i> Note: checks for type <i>"object"</i></li>
|
|
|
|
- <li>enum type</li>
|
|
|
|
- <li>pointer</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li>A JSValue in a conditional expressions <i>If aJSValue then, while aJSValue do,
|
|
|
|
- repeat until aJSValue</i> has the same meaning as in JS: the condition is
|
|
|
|
- true, if the value is not <i>undefined, false, null, NaN, 0, ''</i>.
|
|
|
|
- Note that <i>new Boolean(false)</i> is not <i>null</i> and the condition is true.
|
|
|
|
- </li>
|
|
|
|
- <li><i>function Assigned(V: jsvalue): boolean</i> returns true if<br>
|
|
|
|
- <i>(V!=undefined) && (V!=null) && (!rtl.isArray(V) || (V.length > 0))</i></li>
|
|
|
|
- <li><i>function StrictEqual(const A: jsvalue; const B): boolean</i></li>
|
|
|
|
- <li><i>function StrictInequal(const A: jsvalue; const B): boolean</i></li>
|
|
|
|
- <li>Any array can be assigned to an <i>array of jsvalue</i>.</li>
|
|
|
|
- <li>is-operator: <i>jsvalue is class-type</i>, <i>jsvalue is class-of-type</i><br>
|
|
|
|
- <li>The unit JS provides many utility functions for JSValue, like <i>hasString,
|
|
|
|
- hasValue, isBoolean, isNumber, isInteger, isObject, isClass, isClassInstance, etc..</i></li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="bracketaccessor">Accessing JS object properties with the bracket accessor</h2>
|
|
|
|
- Pas2js allows to define index properties that map directly to the JS object properties.
|
|
|
|
- For example the default property of TJSObject allows to get and set the
|
|
|
|
- properties of an object. For example <i>TJSObject(AnObject)['Name']:=Value;</i><br>
|
|
|
|
- Another example is the default property of TJSArray, that allows access via integers
|
|
|
|
- <i>aTJSArray[3]:=Value;</i><br>
|
|
|
|
- To define your own bracket accessor define a normal index property and define
|
|
|
|
- the getter/setter as <i>external name '[]'</i>.<br>
|
|
|
|
- Here is an example for a read only accessor:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-{$modeswitch externalclass}
|
|
|
|
-type
|
|
|
|
- TExtA = class external name 'ExtA'
|
|
|
|
- private
|
|
|
|
- function GetItems(Index: integer): String; external name '[]';
|
|
|
|
- public
|
|
|
|
- property Items[Index: integer]: String read GetItems; default;
|
|
|
|
- end;
|
|
|
|
-var
|
|
|
|
- Obj: TExtA;
|
|
|
|
- s: String;
|
|
|
|
-Begin
|
|
|
|
- ... get Obj from somewhere ...
|
|
|
|
- s:=Obj[2];
|
|
|
|
-End.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",["System"],function () {
|
|
|
|
- var $mod = this;
|
|
|
|
- this.Obj = undefined;
|
|
|
|
- this.s = "";
|
|
|
|
- $mod.$main = function () {
|
|
|
|
- $mod.s = Obj[2];
|
|
|
|
- };
|
|
|
|
-});
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>A property can have a mix of normal accessor and bracket accessor.
|
|
|
|
- For example a bracket accessor as getter and a normal function as setter.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="rtti">RTTI - Run Time Type Information</h2>
|
|
|
|
- The RTTI provides access to the type data of all published properties,
|
|
|
|
- fields and methods. The type data provides similar information as Delphi/FPC,
|
|
|
|
- but the internals are very different. Delphi/FPC uses pointers,
|
|
|
|
- variant records and fake static arrays, which have no equivalent in JS.
|
|
|
|
- Instead pas2js uses external classes. For example:
|
|
|
|
- <pre>
|
|
|
|
- TTypeInfo = class external name 'rtl.tTypeInfo'
|
|
|
|
- public
|
|
|
|
- Name: String external name 'name';
|
|
|
|
- Kind: TTypeKind external name 'kind';
|
|
|
|
- end;
|
|
|
|
- TTypeInfoClass = class of TTypeInfo;
|
|
|
|
-
|
|
|
|
- TTypeInfoInteger = class external name 'rtl.tTypeInfoInteger'(TTypeInfo)
|
|
|
|
- public
|
|
|
|
- MinValue: NativeInt external name 'minvalue';
|
|
|
|
- MaxValue: NativeInt external name 'maxvalue';
|
|
|
|
- OrdType : TOrdType external name 'ordtype';
|
|
|
|
- end;
|
|
|
|
- </pre>
|
|
|
|
- The <b>typeinfo</b> function works on type, var, const and property identifiers.
|
|
|
|
- By default it returns a <i>pointer</i>. If the typinfo unit is used it returns the
|
|
|
|
- appropiate <i>TTypeInfo</i>. For instance <i>typeinfo(integer)</i> returns
|
|
|
|
- a <i>TTypeInfoInteger</i>.<br>
|
|
|
|
- <i>Typeinfo</i> of a <i>var</i> or <i>const</i> returns the typeinfo of its
|
|
|
|
- type, not of its current runtime value. The exception is a class and class-of instance
|
|
|
|
- variable (e.g. <i>var o: TObject; ... typeinfo(o)</i>), which returns the
|
|
|
|
- typeinfo of the current runtime value.
|
|
|
|
- If <i>o</i> is <i>nil</i> it will give a JS error.<br>
|
|
|
|
- Local types (i.e. inside a procedure) do not have typeinfo.<br>
|
|
|
|
- Open array parameters are not yet supported.<br>
|
|
|
|
- Note that FPC <i>typeinfo(aClassVar)</i> returns the compiletime type, so it works on <i>nil</i>.<br>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="async">Async/AWait</h2>
|
|
|
|
- Pas2js supports the JS operators async and await to simplify the use of Promise.
|
|
|
|
- The await operator corresponds to three intrinsic Pas2js functions:
|
|
|
|
- <ul>
|
|
|
|
- <li><i>function await(AsyncFunctionWithResultT()): T;</i> // implicit promise, the inner () can be omitted</li>
|
|
|
|
- <li><i>function await(aType; p: TJSPromise): aType;</i> // explicit promise requires the resolved type</li>
|
|
|
|
- <li><i>function await(aType; j: jsvalue): aType;</i> // explicit promise requires the resolved type</li>
|
|
|
|
- </ul>
|
|
|
|
- The await function can only be used inside a procedure with the async modifier.<br>
|
|
|
|
- Example for the explicit promise:
|
|
|
|
- <table class="sample">
|
|
|
|
- <tbody>
|
|
|
|
- <tr>
|
|
|
|
- <th>Pascal</th>
|
|
|
|
- <th>JavaScript</th>
|
|
|
|
- </tr>
|
|
|
|
- <tr>
|
|
|
|
- <td>
|
|
|
|
-<pre>Program MyModule;
|
|
|
|
-
|
|
|
|
-uses JS, Web;
|
|
|
|
-
|
|
|
|
-function ResolveAfter2Seconds: TJSPromise;
|
|
|
|
-begin
|
|
|
|
- Result:=TJSPromise.new(procedure(resolve, reject : TJSPromiseResolver)
|
|
|
|
- begin
|
|
|
|
- window.setTimeout(procedure
|
|
|
|
- begin
|
|
|
|
- resolve('resolved');
|
|
|
|
- end,
|
|
|
|
- 2000); // wait 2 seconds
|
|
|
|
- end);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-procedure AsyncCall; async;
|
|
|
|
-var s: string;
|
|
|
|
-begin
|
|
|
|
- writeln('calling');
|
|
|
|
- s := await(string,resolveAfter2Seconds()); // does not check if result is really a string
|
|
|
|
- writeln(s); // expected output: 'resolved'
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-begin
|
|
|
|
- AsyncCall;
|
|
|
|
-end.
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- <td>
|
|
|
|
-<pre>rtl.module("program",["System","JS","Web"],function () {
|
|
|
|
- "use strict";
|
|
|
|
- var $mod = this;
|
|
|
|
- this.ResolveAfter2Seconds = function () {
|
|
|
|
- var Result = null;
|
|
|
|
- Result = new Promise(function (resolve, reject) {
|
|
|
|
- window.setTimeout(function () {
|
|
|
|
- resolve("resolved");
|
|
|
|
- },2000);
|
|
|
|
- });
|
|
|
|
- return Result;
|
|
|
|
- };
|
|
|
|
- this.AsyncCall = async function () {
|
|
|
|
- var s = "";
|
|
|
|
- pas.System.Writeln("calling");
|
|
|
|
- s = await $mod.ResolveAfter2Seconds();
|
|
|
|
- pas.System.Writeln(s);
|
|
|
|
- };
|
|
|
|
- $mod.$main = function () {
|
|
|
|
- $mod.AsyncCall();
|
|
|
|
- };
|
|
|
|
-});
|
|
|
|
-</pre>
|
|
|
|
- </td>
|
|
|
|
- </tr>
|
|
|
|
- </tbody>
|
|
|
|
- </table>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>The await function does only compile time checks, no runtime checks.</li>
|
|
|
|
- <li>Inside an async function/procedure you can pass a <i>TJSPromise</i> to the <i>exit()</i> function. For example:<br>
|
|
|
|
- <i>exit(aPromise);</i><br>
|
|
|
|
- <i>exit(inherited);</i></li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="compilerdirectives">Compiler directives</h2>
|
|
|
|
- In config files:
|
|
|
|
- <ul>
|
|
|
|
- <li>#IFDEF macroname</li>
|
|
|
|
- <li>#IFNDEF macroname</li>
|
|
|
|
- <li>#IF expression - same as $if, except only defines</li>
|
|
|
|
- <li>#ELSEIF</li>
|
|
|
|
- <li>#ELSE</li>
|
|
|
|
- <li>#ENDIF</li>
|
|
|
|
- <li>#ERROR text</li>
|
|
|
|
- </ul>
|
|
|
|
- In source files:
|
|
|
|
- <ul>
|
|
|
|
- <li><span class="tt">{$Define <i>MacroName</i>}</span>: defines macro <i>MacroName</i> with value '1'.</li>
|
|
|
|
- <li><span class="tt">{$Define <i>MacroName:=value</i>}</span>: defines macro <i>MacroName</i> with custom value.</li>
|
|
|
|
- <li><span class="tt">{$Undef <i>MacroName</i>}</span>: undefines macro <i>MacroName</i>.</li>
|
|
|
|
- <li><span class="tt">{$IfDef <i>MacroName</i>}</span>: if <i>MacroName</i> is not defined, skip to next <span class="tt">$Else</span> or <span class="tt">$EndIf</span>. Can be nested.</li>
|
|
|
|
- <li><span class="tt">{$IfNDef <i>MacroName</i>}</span>: as <span class="tt">$IfDef</span>, except negated.</li>
|
|
|
|
- <li><span class="tt">{$If <i>boolean expression</i>}</span>: if <i>expression</i> evaluates to true
|
|
|
|
- (not '0'), skip to next <span class="tt">$Else</span> or <span class="tt">$EndIf</span>. Can be nested.<br>
|
|
|
|
- Supported functions and operators:<br>
|
|
|
|
- <ul>
|
|
|
|
- <li>macro - replaced by its value, a simple define has value '1'</li>
|
|
|
|
- <li>defined(macro) - '1' if defined, '0' otherwise</li>
|
|
|
|
- <li>undefined(macro) - as <span class="tt"><i>not defined(macro)</i></span></li>
|
|
|
|
- <li>option(letter) - same as <i><span class="tt">{$IFOpt letter+}</span></i></li>
|
|
|
|
- <li><span class="tt">not</span> - first level of precedence</li>
|
|
|
|
- <li><span class="tt">*, /, div, mod, and, shl, shr</span> - second level of precedence</li>
|
|
|
|
- <li><span class="tt">+, -, or, xor</span> - third level of precedence</li>
|
|
|
|
- <li><span class="tt">=, <>, <, >, <=, >=</span> - fourth level of precedence</li>
|
|
|
|
- <li>If the operands can be converted to numbers they are combined as numbers, otherwise as strings.</li>
|
|
|
|
- </ul>
|
|
|
|
- Not supported functions and operators:<br>
|
|
|
|
- <ul>
|
|
|
|
- <li><span class="tt">defined(Pascal identifier), undefined(Pascal identifier)</span></li>
|
|
|
|
- <li><span class="tt">declared(Pascal identifier)</span></li>
|
|
|
|
- <li><span class="tt">in</span> operator</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li><span class="tt">{$IfOpt <i>Letter+,-</i>}</span>: if <i>expression</i> evaluates to true (not '0'), skip to next <span class="tt">$Else</span> or <span class="tt">$EndIf</span>. Can be nested.</li>
|
|
|
|
- <li><span class="tt">{$Else}</span>: If previous <span class="tt">$IfDef</span>, <span class="tt">$If</span> or <span class="tt">$IfOpt</span> was skipped, execute next block, otherwise skip.</li>
|
|
|
|
- <li><span class="tt">{$ElseIf <i>boolean expression</i>}</span> : As <span class="tt">$Else</span>, except with an extra expression like <span class="tt">$if</span> to test. There can be multiple <span class="tt">$elseif</span>.</li>
|
|
|
|
- <li><span class="tt">{$EndIf}</span> : ends an <span class="tt">$IfDef</span> block</li>
|
|
|
|
- <li><span class="tt">{$mode delphi} or {$mode objfpc}</span> : Same as <span class="tt">-Mdelphi</span> or <span class="tt">-Mobjfpc</span>, but only for this unit. You can use units of both modes in a program. If present must be at the top of the unit, or after the module name.</li>
|
|
|
|
- <li><span class="tt">{$modeswitch externalclass}</span> : allow declaring external classes</li>
|
|
|
|
- <li><span class="tt">{$modeswitch arrayoperators}</span> : allow + operator to concatenate arrays, default in mode delphi</li>
|
|
|
|
- <li><span class="tt">{$modeswitch OmitRTTI}</span> : treat published sections as public</li>
|
|
|
|
- <li><span class="tt">{$macro on|off}</span> enables macro replacements. Only macros with a value are replaced. Macros are never replaced inside directives.</li>
|
|
|
|
- <li><span class="tt">{$I filename} or {$include filename}</span> - insert include file</li>
|
|
|
|
- <li><span class="tt">{$I %param%}</span> :
|
|
|
|
- <ul>
|
|
|
|
- <li><span class="tt">%date%</span>: current date as string literal, '[yyyy/mm/dd]'</li>
|
|
|
|
- <li><span class="tt">%time%</span>: current time as string literal, 'hh:mm:ss'. Note that the
|
|
|
|
- inclusion of <span class="tt">%date%</span> and <span class="tt">%time%</span> will not cause the compiler to
|
|
|
|
- recompile the unit every time it is used:
|
|
|
|
- the date and time will be the date and time when the unit was last compiled.</li>
|
|
|
|
- <li><span class="tt">%file%</span>: current source filename as string literal, e.g. <i>'unit1.pas'</i></li>
|
|
|
|
- <li><span class="tt">%line%</span>: current source line number as string literal, e.g. <i>'123'</i></li>
|
|
|
|
- <li><span class="tt">%linenum%</span>: current source line number as integer, e.g. <i>123</i></li>
|
|
|
|
- <li><span class="tt">%currentroutine%</span>: name of current routine as string literal</li>
|
|
|
|
- <li><span class="tt">%pas2jstarget%, %pas2jstargetos%, %fpctarget%, %fpctargetos%</span>: target os as string literal, e.g. 'Browser'</li>
|
|
|
|
- <li><span class="tt">%pas2jstargetcpu%, %fpctargetcpu%</span>: target cpu as string literal, e.g. 'ECMAScript5'</li>
|
|
|
|
- <li><span class="tt">%pas2jsversion%, %fpcversion%</span>: compiler version as strnig literal, e.g. '1.0.2'</li>
|
|
|
|
- <li>If param is none of the above it will use the environment variable.
|
|
|
|
- Keep in mind that depending on the platform the name may be case sensitive.
|
|
|
|
- If there is no such variable an empty string <i>''</i> is inserted.</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li><span class="tt">{$Warnings on|off}</span> </li>
|
|
|
|
- <li><span class="tt">{$Notes on|off}</span> </li>
|
|
|
|
- <li><span class="tt">{$Hints on|off}</span> </li>
|
|
|
|
- <li><span class="tt">{$Error text}</span> : emit an error</li>
|
|
|
|
- <li><span class="tt">{$Warning text}</span> : emit a warning</li>
|
|
|
|
- <li><span class="tt">{$Note text}</span> : emit a note</li>
|
|
|
|
- <li><span class="tt">{$Hint text}</span> : emit a hint</li>
|
|
|
|
- <li><span class="tt">{$Message hint-text}</span> : emit a hint</li>
|
|
|
|
- <li><span class="tt">{$Message hint|note|warn|error|fatal text}</span> : emit a message</li>
|
|
|
|
- <li><span class="tt">{$Warn identifier on|off|default|error}</span> : enable or disable a specific hint.<br>
|
|
|
|
- Note, that some hints like "Parameter %s not used" are currently using the enable state at the end of the module, not the state at the hint source position.<br>
|
|
|
|
- Identifier can be a message number as written by -vq or one of the following case insensitive:<br>
|
|
|
|
- <ul>
|
|
|
|
- <li><span class="tt">CONSTRUCTING_ABSTRACT</span> : Constructing an instance of a class with abstract methods.</li>
|
|
|
|
- <li><span class="tt">IMPLICIT_VARIANTS</span> : Implicit use of the variants unit.</li>
|
|
|
|
- <li><span class="tt">NO_RETVAL</span> : Function result is not set</li>
|
|
|
|
- <li><span class="tt">SYMBOL_DEPRECATED</span> : Deprecated symbol.</li>
|
|
|
|
- <li><span class="tt">SYMBOL_EXPERIMENTAL</span> : Experimental symbol</li>
|
|
|
|
- <li><span class="tt">SYMBOL_LIBRARY</span> </li>
|
|
|
|
- <li><span class="tt">SYMBOL_PLATFORM</span> : Platform-dependent symbol.</li>
|
|
|
|
- <li><span class="tt">SYMBOL_UNIMPLEMENTED</span> : Unimplemented symbol.</li>
|
|
|
|
- <li><span class="tt">HIDDEN_VIRTUAL</span> : method hides virtual method of ancestor</li>
|
|
|
|
- <li><span class="tt">GARBAGE</span> : text after final end.</li>
|
|
|
|
- <li><span class="tt">BOUNDS_ERROR</span> : range check errors</li>
|
|
|
|
- <li><span class="tt">MESSAGE_DIRECTIVE</span> : user defined $message</li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li><span class="tt">{$M+}, {$TypeInfo on}</span> : switches default visibility for class members from public to published</li>
|
|
|
|
- <li><span class="tt">{$ScopedEnums on|off}</span> disabled(default): propagate enums to global scope, enable: needs fqn e.g. TEnumType.EnumValue.</li>
|
|
|
|
- <li><span class="tt">{$C+}</span> generate code for assertions</li>
|
|
|
|
- <li><span class="tt">{$H+}</span> , but not <span class="tt">{$H-}</span> </li>
|
|
|
|
- <li><span class="tt">{$J-}, {$WriteableConst off}</span> : Typed const become readonly. For example <i>const i:byte=3; ... i:=4</i> creates a compile time error.</li>
|
|
|
|
- <li><span class="tt">{$M+}</span> : allow published members
|
|
|
|
- <li><span class="tt">{$Q+}</span> : not yet supported, ignored
|
|
|
|
- <li><span class="tt">{$R+}, {$RangeChecks on}</span> : compile time range check hints become errors
|
|
|
|
- and add runtime range checks for assignments.</li>
|
|
|
|
- <li><span class="tt">{$ObjectChecks on|off}</span> :
|
|
|
|
- <ul>
|
|
|
|
- <li>Verify method calls, i.e. check at runtime in every method if <i>Self</i> is a descendant class.</li>
|
|
|
|
- <li>Check type casts, e.g. <i>TBird(AnObject)</i> becomes <i>AnObject as TBird</i></li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- <li><span class="tt">{$DispatchField Msg}</span> : enable checking <i>message number</i> methods for record field name "Msg"</li>
|
|
|
|
- <li><span class="tt">{$DispatchStrField MsgStr}</span> : enable checking <i>message string</i> methods for record field name "Msg"</li>
|
|
|
|
- <li><span class="tt">{$Optimization Name}</span> : same as command line option -OoName</li>
|
|
|
|
- <li><span class="tt">{$linklib filename [alias]}</span>:
|
|
|
|
- <ul>
|
|
|
|
- <li><span class="tt">filename</span> filename to import.</li>
|
|
|
|
- <li><span class="tt">alias</span> alias for this import. Must be a pascal identifier. If no alias is specified, the last part of the filename is used, all non-alphanumeric characters are converted to underscores.
|
|
|
|
- </li>
|
|
|
|
- </ul>
|
|
|
|
- </li>
|
|
|
|
- </ul>
|
|
|
|
- Defines:
|
|
|
|
- <ul>
|
|
|
|
- <li>PASJS</li>
|
|
|
|
- <li>PAS2JS_FULLVERSION - major*1000+minor*100+release, e.g. 1.2.3 = 10203</li>
|
|
|
|
- <li>Target platform: Browser, NodeJS, Pas2JSTargetOS=<value></li>
|
|
|
|
- <li>Target processor: ECMAScript5, ECMAScript6, ECMAScript=5, Pas2JSTargetCPU=<value></li>
|
|
|
|
- <li>Mode: DELPHI, OBJFPC</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="numbers">Numbers</h2>
|
|
|
|
- JavaScript only supports double. All Pascal number types and enum values
|
|
|
|
- are mapped to this. A double supports integers from<br>
|
|
|
|
- MinInteger = -$10000000000000;<br>
|
|
|
|
- MaxInteger = $fffffffffffff;<br>
|
|
|
|
- MinDouble = 5.0e-324;<br>
|
|
|
|
- MaxDouble = 1.7e+308;<br>
|
|
|
|
- <br>
|
|
|
|
- Intrinsic integer types:
|
|
|
|
- <ul>
|
|
|
|
- <li>Byte - unsigned 8-bit</li>
|
|
|
|
- <li>ShortInt - signed 8-bit</li>
|
|
|
|
- <li>Word - unsigned 16-bit</li>
|
|
|
|
- <li>SmallInt - signed 16-bit</li>
|
|
|
|
- <li>LongWord - unsigned 32-bit</li>
|
|
|
|
- <li>LongInt - signed 32-bit</li>
|
|
|
|
- <li>NativeUInt - unsigned 53-bit</li>
|
|
|
|
- <li>NativeInt - signed 54-bit</li>
|
|
|
|
- </ul>
|
|
|
|
- Notes:
|
|
|
|
- <ul>
|
|
|
|
- <li>Division by zero does not raise an exception. 0/0 results in NaN, positive/0 is Infinity, negative/0 is -Infinity.</li>
|
|
|
|
- <li>NaN<>NaN</li>
|
|
|
|
- <li>Overflows work differently. For example in Delphi adding 100 to a byte of 200 gives <i>300 and $ff = 44</i>, while in pas2js it gives 300, which is not a byte anymore.</li>
|
|
|
|
- <li>Math.isNan(double) tests for NaN. Otherwise false. isNan(Infinity)=false.</li>
|
|
|
|
- <li>Math.isFinite(double) tests if not NaN, positive or negative infinity.</li>
|
|
|
|
- <li>Math.isInfinite(double) tests if positive or negative infinity.</li>
|
|
|
|
- <li>For more functions see unit Math.</li>
|
|
|
|
- <li>To make porting easier Single is defined in the system unit as alias of
|
|
|
|
- double, but gives a warning. Since using higher precision might give
|
|
|
|
- unexpected results you should check every place.</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="othersupportedelements">Other supported Pascal elements</h2>
|
|
|
|
- <ul>
|
|
|
|
- <li><b>break</b>, <b>continue</b>, <b>exit</b>, <b>exit()</b></li>
|
|
|
|
- <li><b>chr</b>, <b>ord</b></li>
|
|
|
|
- <li>alias type and type alias type</li>
|
|
|
|
- <li>inc()/dec() to += -=</li>
|
|
|
|
- <li>Converts "a div b" to "Math.floor(a / b)"</li>
|
|
|
|
- <li>and, or, xor, not: logical and bitwise</li>
|
|
|
|
- <li>Name conflicts with JS identifiers are automatically fixed by changing case.
|
|
|
|
- For example a Pascal function "<i>apply"</i> is renamed to "<i>Apply</i>".</li>
|
|
|
|
- <li>uses unitname in 'filename'.
|
|
|
|
- In <i>$mode delphi</i> the in-filenames are only allowed in the program
|
|
|
|
- and the unitname must fit the filename,
|
|
|
|
- e.g. <i>uses unit1 in 'sub/Unit1.pas'</i>.<br>
|
|
|
|
- In <i>$mode objfpc</i> units can use in-filenames too and
|
|
|
|
- alias are allowed, e.g. <i>uses foo in 'bar.pas'</i>.</li>
|
|
|
|
- <li>The intrinsic procedure <b>str</b> works with boolean, integer, float and enumvalue.<br>
|
|
|
|
- Additionally there is <b>str</b> function, that takes an arbitrary number of
|
|
|
|
- arguments and returns a concatenated string. It supports string as parameter too.
|
|
|
|
- For example s:=str(i,' ',d:1:5).<br>
|
|
|
|
- Width and precision is supported. str(i:10) will add spaces to the left to fill up to 10 characters.</b>
|
|
|
|
- str(aDouble:1:5) returns a string in decimal format with 5 digits for the fraction.</li>
|
|
|
|
- <li>Intrinsic procedure WriteStr(out s: string; params...)</li>
|
|
|
|
- <li><i>Debugger;</i> converts to <i>debugger;</i>. If a debugger is running
|
|
|
|
- it will break on this line just like a break point.</li>
|
|
|
|
- <li><i>function concat(string1,string2,...): string</i> since 1.3</li>
|
|
|
|
- <li><i>$mode delphi: function lo|hi(integer): byte</i> since 1.3</li>
|
|
|
|
- <li><i>$mode objfpc: function lo|hi(integer): byte|word|longword</i> since 1.3</li>
|
|
|
|
- <li><i>function GetTypeKind(Type or Var): TTypeKind;</i> since 1.5</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="notsupportedelements">Not supported elements</h2>
|
|
|
|
- <ul>
|
|
|
|
- <li>Class destructor</li>
|
|
|
|
- <li>Enums with custom values</li>
|
|
|
|
- <li>Generics</li>
|
|
|
|
- <li>Global properties</li>
|
|
|
|
- <li>Futures</li>
|
|
|
|
- <li>Inline</li>
|
|
|
|
- <li>Library</li>
|
|
|
|
- <li>Objects</li>
|
|
|
|
- <li>Operator overloading</li>
|
|
|
|
- <li>Pointer arithmetic</li>
|
|
|
|
- <li>Package</li>
|
|
|
|
- <li>Resources</li>
|
|
|
|
- <li>RTTI extended, $RTTI</li>
|
|
|
|
- <li>Variant records</li>
|
|
|
|
- <li>Variants</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="targetprocessor">JavaScript Version</h2>
|
|
|
|
- Code generation depending on -P option:
|
|
|
|
- <ul>
|
|
|
|
- <li>ECMAScript5</li>
|
|
|
|
- <li>ECMAScript6: using 0b for binary literals, and 0o for octal literals</li>
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="section">
|
|
|
|
- <h2 id="sourcemaps">Creating source maps</h2>
|
|
|
|
- Source maps are files telling the browser what JavaScript comes from which
|
|
|
|
- original source (e.g. Pascal file), similar to debug information in FPC/Delphi.<br>
|
|
|
|
- In 2017 FireFox and Chrome supports source maps.<br>
|
|
|
|
- You can enable generating source map files by using the <i>-Jm</i> option.<br>
|
|
|
|
- The compiler generates one module.js.map file for every generated module.js file.
|
|
|
|
- The last line of the .js file contains the line<br>
|
|
|
|
- <i>//# sourceMappingURL=module.js.map</i><br>
|
|
|
|
- telling the browser where to find the source map.<br>
|
|
|
|
- The source map contains references to the Pascal files and included .js
|
|
|
|
- files (e.g. -Jirtl.js) relative to the location of the source map.
|
|
|
|
- Note that if the Pascal file lies in a parent directory, the relativ path
|
|
|
|
- contains '../'. You can change the base directory of the relative paths by using
|
|
|
|
- the option <i>-Jmbasedir=<x></i>. For example <i>-JmC:\www\pas</i>
|
|
|
|
- creates paths relative to C:\www\pas.<br>
|
|
|
|
- You can set the base URL, where the browser finds the Pascal sources, by passing
|
|
|
|
- the <i>-Jmsourceroot=<x></i> option. For example
|
|
|
|
- <i>-Jmsourceroot=http://www.yoursite.com/pas/</i>. The browser prepends this
|
|
|
|
- to the source map filenames when downloading the original source files
|
|
|
|
- (e.g. the .pas files).<br>
|
|
|
|
- You can include the whole Pascal sources in the source map using the option
|
|
|
|
- <i>-Jminclude</i>.<br>
|
|
|
|
- <br>
|
|
|
|
- To show the generated mapping for each line you can use the tool fpc/packages/fcl-js/examples/srcmapdump.<br>
|
|
|
|
- <li>Option -JmXSSIHeader: According to the specifications sourcemap
|
|
|
|
- should start with the XSSI (cross site script inclusion) protection header
|
|
|
|
- <i>)]}'</i>. If your browser does not support that,
|
|
|
|
- disable it with <i>-JmXSSIHeader-</i>. See here the specs:
|
|
|
|
- https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.h7yy76c5il9v
|
|
|
|
- </li>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div id="footer">
|
|
|
|
- </div>
|
|
|
|
-</body>
|
|
|
|
-</html>
|
|
|